@payez/next-mvp 4.1.21 → 4.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/POST-INSTALL.md +408 -0
  2. package/README.md +7 -0
  3. package/dist/api-handlers/account/recovery/initiate.js +35 -2
  4. package/dist/api-handlers/account/recovery/send-code.d.ts +0 -33
  5. package/dist/api-handlers/account/recovery/send-code.js +35 -2
  6. package/dist/api-handlers/account/recovery/verify-code.d.ts +0 -33
  7. package/dist/api-handlers/account/recovery/verify-code.js +35 -2
  8. package/dist/api-handlers/account/reset-password.js +35 -2
  9. package/dist/api-handlers/account/validate-password.js +21 -3
  10. package/dist/api-handlers/admin/analytics.js +2 -1
  11. package/dist/api-handlers/admin/audit.js +2 -1
  12. package/dist/api-handlers/admin/sessions.js +2 -1
  13. package/dist/api-handlers/admin/stats.js +2 -1
  14. package/dist/api-handlers/admin/users.js +2 -1
  15. package/dist/api-handlers/admin/vibe-data.js +2 -1
  16. package/dist/api-handlers/auth/jwks.js +10 -0
  17. package/dist/api-handlers/auth/login.js +5 -2
  18. package/dist/api-handlers/auth/passkey-signin.js +16 -1
  19. package/dist/api-handlers/auth/refresh.d.ts +23 -3
  20. package/dist/api-handlers/auth/refresh.js +107 -16
  21. package/dist/api-handlers/auth/signout.js +3 -2
  22. package/dist/api-handlers/auth/verify-code.js +5 -2
  23. package/dist/api-handlers/session/viability.js +27 -1
  24. package/dist/api-handlers/test/force-expire.d.ts +29 -15
  25. package/dist/api-handlers/test/force-expire.js +109 -14
  26. package/dist/auth/better-auth.d.ts +263 -6
  27. package/dist/auth/better-auth.js +437 -59
  28. package/dist/auth/utils/idp-client.js +1 -1
  29. package/dist/client/AuthContext.js +49 -17
  30. package/dist/client/better-auth-client.d.ts +62 -62
  31. package/dist/components/account/UserAvatarMenu.js +12 -0
  32. package/dist/components/auth/ModeAwareLoginPage.js +10 -8
  33. package/dist/components/auth/ModeAwareSignupPage.js +5 -2
  34. package/dist/components/auth/TraditionalAuthSection.js +5 -1
  35. package/dist/hooks/useAuthSettings.js +14 -2
  36. package/dist/hooks/usePublicAuthSettings.d.ts +2 -2
  37. package/dist/hooks/usePublicAuthSettings.js +28 -14
  38. package/dist/lib/client-key.d.ts +61 -0
  39. package/dist/lib/client-key.js +72 -0
  40. package/dist/lib/demo-mode.js +2 -1
  41. package/dist/lib/ensure-fresh-access-token.js +5 -1
  42. package/dist/lib/idp-client-config.d.ts +25 -2
  43. package/dist/lib/idp-client-config.js +381 -36
  44. package/dist/lib/idp-fetch.d.ts +2 -0
  45. package/dist/lib/idp-fetch.js +31 -1
  46. package/dist/lib/idp-url-guard.d.ts +29 -0
  47. package/dist/lib/idp-url-guard.js +38 -0
  48. package/dist/lib/redis.js +77 -5
  49. package/dist/lib/session-cookie-shape.d.ts +69 -0
  50. package/dist/lib/session-cookie-shape.js +126 -0
  51. package/dist/lib/session-store.d.ts +35 -2
  52. package/dist/lib/session-store.js +135 -4
  53. package/dist/lib/single-flight.d.ts +35 -0
  54. package/dist/lib/single-flight.js +30 -0
  55. package/dist/lib/token-lifecycle.js +12 -0
  56. package/dist/middleware/create-middleware.js +12 -0
  57. package/dist/models/SessionModel.d.ts +41 -0
  58. package/dist/models/SessionModel.js +9 -0
  59. package/dist/pages/admin-login/page.d.ts +1 -1
  60. package/dist/pages/admin-login/page.js +5 -41
  61. package/dist/pages/security/EnhancedSecurityPage.d.ts +35 -1
  62. package/dist/pages/security/EnhancedSecurityPage.js +42 -2
  63. package/dist/pages/security/index.d.ts +1 -0
  64. package/dist/pages/security/index.js +3 -0
  65. package/dist/pages/test-env/EmergencyLogoutPage.d.ts +17 -5
  66. package/dist/pages/test-env/EmergencyLogoutPage.js +17 -5
  67. package/dist/pages/test-env/JwtInspectPage.d.ts +30 -5
  68. package/dist/pages/test-env/JwtInspectPage.js +166 -7
  69. package/dist/pages/test-env/RefreshTokenPage.d.ts +22 -6
  70. package/dist/pages/test-env/RefreshTokenPage.js +22 -6
  71. package/dist/pages/test-env/TestEnvPage.d.ts +16 -4
  72. package/dist/pages/test-env/TestEnvPage.js +16 -4
  73. package/dist/pages/test-env/guarded.d.ts +4 -0
  74. package/dist/pages/test-env/guarded.js +86 -0
  75. package/dist/pages/test-env/index.d.ts +50 -7
  76. package/dist/pages/test-env/index.js +58 -12
  77. package/dist/routes/auth/logout.js +3 -2
  78. package/dist/routes/auth/refresh.js +27 -1
  79. package/dist/routes/auth/session.d.ts +12 -3
  80. package/dist/routes/auth/session.js +92 -9
  81. package/dist/routes/auth/settings.d.ts +34 -4
  82. package/dist/routes/auth/settings.js +87 -33
  83. package/dist/routes/auth/viability.d.ts +1 -1
  84. package/dist/routes/auth/viability.js +122 -11
  85. package/dist/server/auth-guard.js +22 -15
  86. package/dist/server/auth.d.ts +177 -20
  87. package/dist/server/auth.js +34 -75
  88. package/dist/server/decode-session.js +84 -10
  89. package/dist/types/auth.d.ts +18 -0
  90. package/package.json +969 -958
  91. package/scripts/check-internal-url-usage.sh +73 -73
  92. package/scripts/check-publish-health.mjs +120 -0
  93. package/scripts/dev-broker.ps1 +71 -6
  94. package/scripts/print-client-config.mjs +162 -0
  95. package/scripts/server-only-stub.cjs +4 -0
  96. package/src/api-handlers/account/recovery/initiate.ts +35 -2
  97. package/src/api-handlers/account/recovery/send-code.ts +36 -2
  98. package/src/api-handlers/account/recovery/verify-code.ts +36 -2
  99. package/src/api-handlers/account/reset-password.ts +35 -2
  100. package/src/api-handlers/account/validate-password.ts +22 -3
  101. package/src/api-handlers/admin/analytics.ts +2 -1
  102. package/src/api-handlers/admin/audit.ts +2 -1
  103. package/src/api-handlers/admin/sessions.ts +2 -1
  104. package/src/api-handlers/admin/stats.ts +2 -1
  105. package/src/api-handlers/admin/users.ts +2 -1
  106. package/src/api-handlers/admin/vibe-data.ts +2 -1
  107. package/src/api-handlers/auth/jwks.ts +10 -0
  108. package/src/api-handlers/auth/login.ts +5 -2
  109. package/src/api-handlers/auth/passkey-signin.ts +112 -98
  110. package/src/api-handlers/auth/refresh.ts +112 -15
  111. package/src/api-handlers/auth/signout.ts +4 -3
  112. package/src/api-handlers/auth/verify-code.ts +5 -2
  113. package/src/api-handlers/mfa/backup-code-verify.ts +175 -175
  114. package/src/api-handlers/mfa/backup-codes.ts +41 -41
  115. package/src/api-handlers/mfa/methods.ts +46 -46
  116. package/src/api-handlers/mfa/totp-confirm.ts +42 -42
  117. package/src/api-handlers/mfa/totp-enroll.ts +42 -42
  118. package/src/api-handlers/passkeys/list.ts +31 -31
  119. package/src/api-handlers/passkeys/manage.ts +54 -54
  120. package/src/api-handlers/passkeys/register-options.ts +42 -42
  121. package/src/api-handlers/passkeys/register-verify.ts +41 -41
  122. package/src/api-handlers/session/viability.ts +29 -1
  123. package/src/api-handlers/test/force-expire.ts +118 -13
  124. package/src/auth/better-auth.ts +486 -51
  125. package/src/auth/utils/idp-client.ts +1 -1
  126. package/src/client/AuthContext.tsx +55 -19
  127. package/src/components/account/UserAvatarMenu.tsx +11 -0
  128. package/src/components/auth/ModeAwareLoginPage.tsx +40 -49
  129. package/src/components/auth/ModeAwareSignupPage.tsx +5 -2
  130. package/src/components/auth/TraditionalAuthSection.tsx +5 -1
  131. package/src/hooks/useAuthSettings.ts +14 -2
  132. package/src/hooks/usePublicAuthSettings.ts +38 -16
  133. package/src/lib/client-key.ts +88 -0
  134. package/src/lib/demo-mode.ts +2 -1
  135. package/src/lib/ensure-fresh-access-token.ts +5 -1
  136. package/src/lib/idp-client-config.ts +399 -36
  137. package/src/lib/idp-fetch.ts +36 -1
  138. package/src/lib/idp-url-guard.ts +37 -0
  139. package/src/lib/redis.ts +84 -6
  140. package/src/lib/session-cookie-shape.ts +184 -0
  141. package/src/lib/session-store.ts +152 -6
  142. package/src/lib/single-flight.ts +64 -0
  143. package/src/lib/token-lifecycle.ts +12 -0
  144. package/src/middleware/create-middleware.ts +11 -0
  145. package/src/models/SessionModel.ts +49 -0
  146. package/src/pages/admin-login/page.tsx +17 -127
  147. package/src/pages/security/EnhancedSecurityPage.tsx +95 -9
  148. package/src/pages/security/index.ts +3 -0
  149. package/src/pages/test-env/EmergencyLogoutPage.tsx +17 -5
  150. package/src/pages/test-env/JwtInspectPage.tsx +235 -20
  151. package/src/pages/test-env/RefreshTokenPage.tsx +22 -6
  152. package/src/pages/test-env/TestEnvPage.tsx +16 -4
  153. package/src/pages/test-env/guarded.tsx +81 -0
  154. package/src/pages/test-env/index.ts +59 -7
  155. package/src/routes/auth/logout.ts +4 -3
  156. package/src/routes/auth/passkey-signin.ts +13 -13
  157. package/src/routes/auth/refresh.ts +30 -1
  158. package/src/routes/auth/session.ts +98 -9
  159. package/src/routes/auth/settings.ts +144 -42
  160. package/src/routes/auth/viability.ts +129 -11
  161. package/src/routes/mfa/backup-code-verify.ts +1 -1
  162. package/src/routes/mfa/backup-codes.ts +10 -10
  163. package/src/routes/mfa/methods.ts +22 -22
  164. package/src/routes/mfa/totp-confirm.ts +10 -10
  165. package/src/routes/mfa/totp-enroll.ts +10 -10
  166. package/src/routes/mfa/totp-verify.ts +14 -14
  167. package/src/routes/passkeys/list.ts +10 -10
  168. package/src/routes/passkeys/manage.ts +23 -23
  169. package/src/routes/passkeys/register-options.ts +10 -10
  170. package/src/routes/passkeys/register-verify.ts +10 -10
  171. package/src/server/auth-guard.ts +24 -17
  172. package/src/server/auth.ts +37 -73
  173. package/src/server/decode-session.ts +95 -11
  174. package/src/templates/instrumentation.ts +21 -2
  175. package/src/types/auth.ts +20 -0
  176. package/dist/lib/auth-secret.d.ts +0 -17
  177. package/dist/lib/auth-secret.js +0 -116
  178. package/src/lib/auth-secret.ts +0 -137
@@ -36,7 +36,7 @@ function getIdpUrl() {
36
36
  * Get client ID for this application.
37
37
  */
38
38
  function getClientId() {
39
- const clientId = process.env.CLIENT_ID || process.env.NEXT_PUBLIC_CLIENT_ID;
39
+ const clientId = process.env.CLIENT_ID;
40
40
  if (!clientId) {
41
41
  throw new Error('[IDP_CLIENT] FATAL: CLIENT_ID environment variable is REQUIRED');
42
42
  }
@@ -32,6 +32,8 @@ const OAUTH_PROVIDER_IDS = ['google', 'apple', 'facebook', 'github', 'azure-ad',
32
32
  function AuthProvider({ children, config, useDynamicProviders = true }) {
33
33
  const [dynamicProviders, setDynamicProviders] = (0, react_1.useState)([]);
34
34
  const [providersLoaded, setProvidersLoaded] = (0, react_1.useState)(!useDynamicProviders);
35
+ // What the IDP says this client offers. null until /api/auth/settings answers.
36
+ const [serverSettings, setServerSettings] = (0, react_1.useState)(null);
35
37
  // Create QueryClient instance for React Query - used internally by MVP hooks
36
38
  const [queryClient] = (0, react_1.useState)(() => new react_query_1.QueryClient({
37
39
  defaultOptions: {
@@ -49,24 +51,45 @@ function AuthProvider({ children, config, useDynamicProviders = true }) {
49
51
  let mounted = true;
50
52
  async function fetchDynamicProviders() {
51
53
  try {
52
- // Better Auth doesn't have a getProviders equivalent.
53
- // Use static provider map based on configured social providers.
54
- const result = {
55
- google: { id: 'google', name: 'Google' },
56
- };
57
- if (!mounted)
54
+ // READ THE IDP. This used to be a hardcoded literal:
55
+ // const result = { google: { id: 'google', name: 'Google' } };
56
+ // sitting under a comment saying providers were loaded dynamically. It returned
57
+ // Google for every client regardless of what the tenant actually had enabled -
58
+ // a config-shaped constant, which is the one thing configuration must never be.
59
+ //
60
+ // /api/auth/settings already serves the real answer (enabledProviders,
61
+ // allowFederatedLogin, enablePasswordReset) and nothing consumed it.
62
+ const response = await fetch('/api/auth/settings');
63
+ if (!response.ok) {
64
+ // No silent substitution. Absent settings means we do not know what this
65
+ // client offers, and inventing a provider list is how a tenant ends up with a
66
+ // sign-in button their IDP will refuse.
67
+ console.error('[AuthProvider] /api/auth/settings returned ' + response.status +
68
+ ' - provider list unknown. Mount ./routes/auth/settings.');
58
69
  return;
59
- if (result) {
60
- // Filter to OAuth providers only and map to FederatedProvider type
61
- const oauthProviders = Object.keys(result)
62
- .filter(id => OAUTH_PROVIDER_IDS.includes(id))
63
- .map(id => PROVIDER_MAP[id])
64
- .filter((p) => p !== undefined);
65
- setDynamicProviders(oauthProviders);
66
70
  }
71
+ const body = await response.json();
72
+ const settings = body?.data ?? body;
73
+ if (!mounted)
74
+ return;
75
+ const ids = Array.isArray(settings?.enabledProviders)
76
+ ? settings.enabledProviders
77
+ : [];
78
+ const oauthProviders = ids
79
+ .filter(id => OAUTH_PROVIDER_IDS.includes(id))
80
+ .map(id => PROVIDER_MAP[id])
81
+ .filter((p) => p !== undefined);
82
+ setDynamicProviders(oauthProviders);
83
+ setServerSettings({
84
+ allowFederatedLogin: settings?.allowFederatedLogin !== false,
85
+ // TRADITIONAL DEFAULTS ON. The IDP does not carry an explicit flag for it yet;
86
+ // until it does, username/password is available unless a site opts out. An
87
+ // OAuth-only client is a deliberate choice, not the default.
88
+ allowTraditionalLogin: settings?.allowTraditionalLogin !== false,
89
+ });
67
90
  }
68
91
  catch (err) {
69
- // Fall back to static config providers on error
92
+ console.error('[AuthProvider] could not read /api/auth/settings:', err);
70
93
  }
71
94
  finally {
72
95
  if (mounted) {
@@ -86,7 +109,12 @@ function AuthProvider({ children, config, useDynamicProviders = true }) {
86
109
  const authConfig = {
87
110
  ...defaultConfig,
88
111
  ...config,
89
- providers, // Override with dynamic providers if enabled
112
+ providers, // from the IDP when useDynamicProviders is on
113
+ // THE SERVER DECIDES, THE SITE MAY OVERRIDE. A site that passes an explicit value
114
+ // still wins; absent that, what the tenant's IDP reports is what renders. A client
115
+ // hardcoding its own auth mode is how a sign-in screen and its IDP disagree.
116
+ allowFederatedLogin: config?.allowFederatedLogin ?? serverSettings?.allowFederatedLogin ?? true,
117
+ allowTraditionalLogin: config?.allowTraditionalLogin ?? serverSettings?.allowTraditionalLogin ?? true,
90
118
  };
91
119
  return ((0, jsx_runtime_1.jsx)(react_query_1.QueryClientProvider, { client: queryClient, children: (0, jsx_runtime_1.jsx)(AuthContext.Provider, { value: authConfig, children: children }) }));
92
120
  }
@@ -107,9 +135,13 @@ function useFederatedProviders() {
107
135
  }
108
136
  function useFederatedAuthEnabled() {
109
137
  const config = useAuthConfig();
110
- return config.mode === 'federated' && config.providers.length > 0;
138
+ // Was `config.mode === 'federated'`, which made the two mutually exclusive and let a
139
+ // site's hardcoded mode silently hide what the IDP offers.
140
+ return config.allowFederatedLogin !== false && config.providers.length > 0;
111
141
  }
112
142
  function useTraditionalAuthEnabled() {
113
143
  const config = useAuthConfig();
114
- return config.mode === 'traditional';
144
+ // Was `config.mode === 'traditional'`. Both can be on at once - that is the normal
145
+ // case, and OAuth-only is the exception a client opts into.
146
+ return config.allowTraditionalLogin !== false;
115
147
  }
@@ -24,7 +24,7 @@ export declare const authClient: {
24
24
  metadata?: Record<string, any> | undefined;
25
25
  } & {
26
26
  fetchOptions?: FetchOptions | undefined;
27
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
27
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
28
28
  status: boolean;
29
29
  }, {
30
30
  code?: string | undefined;
@@ -46,7 +46,7 @@ export declare const authClient: {
46
46
  newUserCallbackURL?: string | undefined;
47
47
  };
48
48
  fetchOptions?: FetchOptions | undefined;
49
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<Omit<{
49
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<Omit<{
50
50
  token: string;
51
51
  user: {
52
52
  id: string;
@@ -124,7 +124,7 @@ export declare const authClient: {
124
124
  additionalData?: Record<string, any> | undefined;
125
125
  } & {
126
126
  fetchOptions?: FetchOptions | undefined;
127
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
127
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
128
128
  redirect: boolean;
129
129
  url: string;
130
130
  } | (Omit<{
@@ -159,7 +159,7 @@ export declare const authClient: {
159
159
  signOut: <FetchOptions extends import("@better-auth/core").ClientFetchOption<never, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0?: import("better-auth/react").Prettify<{
160
160
  query?: Record<string, any> | undefined;
161
161
  fetchOptions?: FetchOptions | undefined;
162
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
162
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
163
163
  success: boolean;
164
164
  }, {
165
165
  code?: string | undefined;
@@ -181,7 +181,7 @@ export declare const authClient: {
181
181
  image?: string | undefined;
182
182
  callbackURL?: string | undefined;
183
183
  fetchOptions?: FetchOptions | undefined;
184
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<(Omit<{
184
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<(Omit<{
185
185
  token: null;
186
186
  user: {
187
187
  id: string;
@@ -242,7 +242,7 @@ export declare const authClient: {
242
242
  rememberMe?: boolean | undefined;
243
243
  } & {
244
244
  fetchOptions?: FetchOptions | undefined;
245
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<Omit<{
245
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<Omit<{
246
246
  redirect: boolean;
247
247
  token: string;
248
248
  url?: string | undefined;
@@ -281,7 +281,7 @@ export declare const authClient: {
281
281
  token?: string | undefined;
282
282
  } & {
283
283
  fetchOptions?: FetchOptions | undefined;
284
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
284
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
285
285
  status: boolean;
286
286
  }, {
287
287
  code?: string | undefined;
@@ -297,7 +297,7 @@ export declare const authClient: {
297
297
  callbackURL?: string | undefined;
298
298
  };
299
299
  fetchOptions?: FetchOptions | undefined;
300
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<NonNullable<void | {
300
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<NonNullable<void | {
301
301
  status: boolean;
302
302
  }>, {
303
303
  code?: string | undefined;
@@ -312,7 +312,7 @@ export declare const authClient: {
312
312
  callbackURL?: string | undefined;
313
313
  } & {
314
314
  fetchOptions?: FetchOptions | undefined;
315
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
315
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
316
316
  status: boolean;
317
317
  }, {
318
318
  code?: string | undefined;
@@ -327,7 +327,7 @@ export declare const authClient: {
327
327
  callbackURL?: string | undefined;
328
328
  } & {
329
329
  fetchOptions?: FetchOptions | undefined;
330
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
330
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
331
331
  status: boolean;
332
332
  }, {
333
333
  code?: string | undefined;
@@ -344,7 +344,7 @@ export declare const authClient: {
344
344
  revokeOtherSessions?: boolean | undefined;
345
345
  } & {
346
346
  fetchOptions?: FetchOptions | undefined;
347
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<Omit<{
347
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<Omit<{
348
348
  token: string | null;
349
349
  user: {
350
350
  id: string;
@@ -380,7 +380,7 @@ export declare const authClient: {
380
380
  } & {
381
381
  updateSession: <FetchOptions extends import("@better-auth/core").ClientFetchOption<Partial<Partial<{}>> & Record<string, any>, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0?: import("better-auth/react").Prettify<Partial<{}> & {
382
382
  fetchOptions?: FetchOptions | undefined;
383
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
383
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
384
384
  session: {
385
385
  id: string;
386
386
  createdAt: Date;
@@ -405,16 +405,16 @@ export declare const authClient: {
405
405
  $InferServerPlugin: ReturnType<(options: import("better-auth/plugins/magic-link").MagicLinkOptions) => {
406
406
  id: "magic-link";
407
407
  endpoints: {
408
- signInMagicLink: import("better-auth/*").StrictEndpoint<"/sign-in/magic-link", {
408
+ signInMagicLink: import("better-call").StrictEndpoint<"/sign-in/magic-link", {
409
409
  method: "POST";
410
410
  requireHeaders: true;
411
- body: import("better-auth/*").ZodObject<{
412
- email: import("better-auth/*").ZodEmail;
413
- name: import("better-auth/*").ZodOptional<import("better-auth/*").ZodString>;
414
- callbackURL: import("better-auth/*").ZodOptional<import("better-auth/*").ZodString>;
415
- newUserCallbackURL: import("better-auth/*").ZodOptional<import("better-auth/*").ZodString>;
416
- errorCallbackURL: import("better-auth/*").ZodOptional<import("better-auth/*").ZodString>;
417
- metadata: import("better-auth/*").ZodOptional<import("better-auth/*").ZodRecord<import("better-auth/*").ZodString, import("better-auth/*").ZodAny>>;
411
+ body: import("zod").ZodObject<{
412
+ email: import("zod").ZodEmail;
413
+ name: import("zod").ZodOptional<import("zod").ZodString>;
414
+ callbackURL: import("zod").ZodOptional<import("zod").ZodString>;
415
+ newUserCallbackURL: import("zod").ZodOptional<import("zod").ZodString>;
416
+ errorCallbackURL: import("zod").ZodOptional<import("zod").ZodString>;
417
+ metadata: import("zod").ZodOptional<import("zod").ZodRecord<import("zod").ZodString, import("zod").ZodAny>>;
418
418
  }, import("better-auth/*").$strip>;
419
419
  metadata: {
420
420
  openapi: {
@@ -442,15 +442,15 @@ export declare const authClient: {
442
442
  }, {
443
443
  status: boolean;
444
444
  }>;
445
- magicLinkVerify: import("better-auth/*").StrictEndpoint<"/magic-link/verify", {
445
+ magicLinkVerify: import("better-call").StrictEndpoint<"/magic-link/verify", {
446
446
  method: "GET";
447
- query: import("better-auth/*").ZodObject<{
448
- token: import("better-auth/*").ZodString;
449
- callbackURL: import("better-auth/*").ZodOptional<import("better-auth/*").ZodString>;
450
- errorCallbackURL: import("better-auth/*").ZodOptional<import("better-auth/*").ZodString>;
451
- newUserCallbackURL: import("better-auth/*").ZodOptional<import("better-auth/*").ZodString>;
447
+ query: import("zod").ZodObject<{
448
+ token: import("zod").ZodString;
449
+ callbackURL: import("zod").ZodOptional<import("zod").ZodString>;
450
+ errorCallbackURL: import("zod").ZodOptional<import("zod").ZodString>;
451
+ newUserCallbackURL: import("zod").ZodOptional<import("zod").ZodString>;
452
452
  }, import("better-auth/*").$strip>;
453
- use: ((inputContext: import("better-auth/*").MiddlewareInputContext<import("better-auth/*").MiddlewareOptions>) => Promise<void>)[];
453
+ use: ((inputContext: import("better-call").MiddlewareInputContext<import("better-call").MiddlewareOptions>) => Promise<void>)[];
454
454
  requireHeaders: true;
455
455
  metadata: {
456
456
  openapi: {
@@ -499,7 +499,7 @@ export declare const authClient: {
499
499
  options: import("better-auth/plugins/magic-link").MagicLinkOptions;
500
500
  }>;
501
501
  }[];
502
- }, FetchOptions>> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
502
+ }, FetchOptions>> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
503
503
  status: boolean;
504
504
  }, {
505
505
  code?: string | undefined;
@@ -516,7 +516,7 @@ export declare const authClient: {
516
516
  token?: string | undefined;
517
517
  } & {
518
518
  fetchOptions?: FetchOptions | undefined;
519
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
519
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
520
520
  success: boolean;
521
521
  message: string;
522
522
  }, {
@@ -532,7 +532,7 @@ export declare const authClient: {
532
532
  redirectTo?: string | undefined;
533
533
  } & {
534
534
  fetchOptions?: FetchOptions | undefined;
535
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
535
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
536
536
  status: boolean;
537
537
  message: string;
538
538
  }, {
@@ -550,7 +550,7 @@ export declare const authClient: {
550
550
  callbackURL: string;
551
551
  };
552
552
  fetchOptions?: FetchOptions | undefined;
553
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<never, {
553
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<never, {
554
554
  code?: string | undefined;
555
555
  message?: string | undefined;
556
556
  }, FetchOptions["throw"] extends true ? true : false>>;
@@ -559,7 +559,7 @@ export declare const authClient: {
559
559
  listSessions: <FetchOptions extends import("@better-auth/core").ClientFetchOption<never, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0?: import("better-auth/react").Prettify<{
560
560
  query?: Record<string, any> | undefined;
561
561
  fetchOptions?: FetchOptions | undefined;
562
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<import("better-auth/react").Prettify<{
562
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<import("better-auth/react").Prettify<{
563
563
  id: string;
564
564
  createdAt: Date;
565
565
  updatedAt: Date;
@@ -579,7 +579,7 @@ export declare const authClient: {
579
579
  token: string;
580
580
  } & {
581
581
  fetchOptions?: FetchOptions | undefined;
582
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
582
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
583
583
  status: boolean;
584
584
  }, {
585
585
  code?: string | undefined;
@@ -589,7 +589,7 @@ export declare const authClient: {
589
589
  revokeSessions: <FetchOptions extends import("@better-auth/core").ClientFetchOption<never, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0?: import("better-auth/react").Prettify<{
590
590
  query?: Record<string, any> | undefined;
591
591
  fetchOptions?: FetchOptions | undefined;
592
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
592
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
593
593
  status: boolean;
594
594
  }, {
595
595
  code?: string | undefined;
@@ -599,7 +599,7 @@ export declare const authClient: {
599
599
  revokeOtherSessions: <FetchOptions extends import("@better-auth/core").ClientFetchOption<never, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0?: import("better-auth/react").Prettify<{
600
600
  query?: Record<string, any> | undefined;
601
601
  fetchOptions?: FetchOptions | undefined;
602
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
602
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
603
603
  status: boolean;
604
604
  }, {
605
605
  code?: string | undefined;
@@ -638,7 +638,7 @@ export declare const authClient: {
638
638
  additionalData?: Record<string, any> | undefined;
639
639
  } & {
640
640
  fetchOptions?: FetchOptions | undefined;
641
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
641
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
642
642
  url: string;
643
643
  redirect: boolean;
644
644
  }, {
@@ -649,7 +649,7 @@ export declare const authClient: {
649
649
  listAccounts: <FetchOptions extends import("@better-auth/core").ClientFetchOption<never, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0?: import("better-auth/react").Prettify<{
650
650
  query?: Record<string, any> | undefined;
651
651
  fetchOptions?: FetchOptions | undefined;
652
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
652
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
653
653
  scopes: string[];
654
654
  id: string;
655
655
  createdAt: Date;
@@ -672,7 +672,7 @@ export declare const authClient: {
672
672
  callbackURL?: string | undefined;
673
673
  };
674
674
  fetchOptions?: FetchOptions | undefined;
675
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
675
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
676
676
  success: boolean;
677
677
  message: string;
678
678
  }, {
@@ -689,7 +689,7 @@ export declare const authClient: {
689
689
  accountId?: string | undefined;
690
690
  } & {
691
691
  fetchOptions?: FetchOptions | undefined;
692
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
692
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
693
693
  status: boolean;
694
694
  }, {
695
695
  code?: string | undefined;
@@ -706,7 +706,7 @@ export declare const authClient: {
706
706
  userId?: string | undefined;
707
707
  } & {
708
708
  fetchOptions?: FetchOptions | undefined;
709
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
709
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
710
710
  accessToken: string | undefined;
711
711
  refreshToken: string;
712
712
  accessTokenExpiresAt: Date | undefined;
@@ -730,7 +730,7 @@ export declare const authClient: {
730
730
  userId?: string | undefined;
731
731
  } & {
732
732
  fetchOptions?: FetchOptions | undefined;
733
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
733
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
734
734
  accessToken: string;
735
735
  accessTokenExpiresAt: Date | undefined;
736
736
  scopes: string[];
@@ -747,7 +747,7 @@ export declare const authClient: {
747
747
  accountId?: string | undefined;
748
748
  } | undefined;
749
749
  fetchOptions?: FetchOptions | undefined;
750
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
750
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
751
751
  user: import("better-auth/*").OAuth2UserInfo;
752
752
  data: Record<string, any>;
753
753
  }, {
@@ -764,7 +764,7 @@ export declare const authClient: {
764
764
  disableRefresh?: unknown;
765
765
  } | undefined;
766
766
  fetchOptions?: FetchOptions | undefined;
767
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
767
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
768
768
  user: import("better-auth/react").StripEmptyObjects<{
769
769
  id: string;
770
770
  createdAt: Date;
@@ -813,7 +813,7 @@ export declare const authClient: {
813
813
  } | null;
814
814
  isPending: boolean;
815
815
  isRefetching: boolean;
816
- error: import("better-auth/react").BetterFetchError | null;
816
+ error: import("@better-fetch/fetch").BetterFetchError | null;
817
817
  refetch: (queryParams
818
818
  /**
819
819
  * NextAuth-compatible signOut wrapper.
@@ -847,21 +847,21 @@ export declare const authClient: {
847
847
  }>;
848
848
  };
849
849
  };
850
- $fetch: import("better-auth/react").BetterFetch<{
851
- plugins: (import("better-auth/react").BetterFetchPlugin<Record<string, any>> | {
850
+ $fetch: import("@better-fetch/fetch").BetterFetch<{
851
+ plugins: (import("@better-fetch/fetch").BetterFetchPlugin<Record<string, any>> | {
852
852
  id: string;
853
853
  name: string;
854
854
  hooks: {
855
- onSuccess(context: import("better-auth/react").SuccessContext<any>): void;
855
+ onSuccess(context: import("@better-fetch/fetch").SuccessContext<any>): void;
856
856
  };
857
857
  } | {
858
858
  id: string;
859
859
  name: string;
860
860
  hooks: {
861
- onSuccess: ((context: import("better-auth/react").SuccessContext<any>) => Promise<void> | void) | undefined;
862
- onError: ((context: import("better-auth/react").ErrorContext) => Promise<void> | void) | undefined;
863
- onRequest: (<T extends Record<string, any>>(context: import("better-auth/react").RequestContext<T>) => Promise<import("better-auth/react").RequestContext | void> | import("better-auth/react").RequestContext | void) | undefined;
864
- onResponse: ((context: import("better-auth/react").ResponseContext) => Promise<Response | void | import("better-auth/react").ResponseContext> | Response | import("better-auth/react").ResponseContext | void) | undefined;
861
+ onSuccess: ((context: import("@better-fetch/fetch").SuccessContext<any>) => Promise<void> | void) | undefined;
862
+ onError: ((context: import("@better-fetch/fetch").ErrorContext) => Promise<void> | void) | undefined;
863
+ onRequest: (<T extends Record<string, any>>(context: import("@better-fetch/fetch").RequestContext<T>) => Promise<import("@better-fetch/fetch").RequestContext | void> | import("@better-fetch/fetch").RequestContext | void) | undefined;
864
+ onResponse: ((context: import("@better-fetch/fetch").ResponseContext) => Promise<Response | void | import("@better-fetch/fetch").ResponseContext> | Response | import("@better-fetch/fetch").ResponseContext | void) | undefined;
865
865
  };
866
866
  })[];
867
867
  cache?: RequestCache | undefined;
@@ -881,12 +881,12 @@ export declare const authClient: {
881
881
  referrerPolicy?: ReferrerPolicy | undefined;
882
882
  signal?: (AbortSignal | null) | undefined;
883
883
  window?: null | undefined;
884
- onRetry?: ((response: import("better-auth/react").ResponseContext) => Promise<void> | void) | undefined;
884
+ onRetry?: ((response: import("@better-fetch/fetch").ResponseContext) => Promise<void> | void) | undefined;
885
885
  hookOptions?: {
886
886
  cloneResponse?: boolean;
887
887
  } | undefined;
888
888
  timeout?: number | undefined;
889
- customFetchImpl: import("better-auth/react").FetchEsque;
889
+ customFetchImpl: import("@better-fetch/fetch").FetchEsque;
890
890
  baseURL: string;
891
891
  throw?: boolean | undefined;
892
892
  auth?: ({
@@ -906,17 +906,17 @@ export declare const authClient: {
906
906
  params?: any;
907
907
  duplex?: "full" | "half" | undefined;
908
908
  jsonParser: (text: string) => Promise<any> | any;
909
- retry?: import("better-auth/react").RetryOptions | undefined;
909
+ retry?: import("@better-fetch/fetch").RetryOptions | undefined;
910
910
  retryAttempt?: number | undefined;
911
- output?: (import("better-auth/react").StandardSchemaV1 | typeof Blob | typeof File) | undefined;
912
- errorSchema?: import("better-auth/react").StandardSchemaV1 | undefined;
911
+ output?: (import("@better-fetch/fetch").StandardSchemaV1 | typeof Blob | typeof File) | undefined;
912
+ errorSchema?: import("@better-fetch/fetch").StandardSchemaV1 | undefined;
913
913
  disableValidation?: boolean | undefined;
914
914
  disableSignal?: boolean | undefined;
915
915
  }, unknown, unknown, {}>;
916
916
  $store: {
917
917
  notify: (signal?: (Omit<string, "$sessionSignal"> | "$sessionSignal") | undefined) => void;
918
918
  listen: (signal: Omit<string, "$sessionSignal"> | "$sessionSignal", listener: (value: boolean, oldValue?: boolean | undefined) => void) => void;
919
- atoms: Record<string, import("better-auth/react").WritableAtom<any>>;
919
+ atoms: Record<string, import("nanostores/atom").WritableAtom<any>>;
920
920
  };
921
921
  $ERROR_CODES: {
922
922
  USER_NOT_FOUND: import("better-auth/*").RawError<"USER_NOT_FOUND">;
@@ -993,7 +993,7 @@ export declare const useSession: () => {
993
993
  } | null;
994
994
  isPending: boolean;
995
995
  isRefetching: boolean;
996
- error: import("better-auth/react").BetterFetchError | null;
996
+ error: import("@better-fetch/fetch").BetterFetchError | null;
997
997
  refetch: (queryParams
998
998
  /**
999
999
  * NextAuth-compatible signOut wrapper.
@@ -1020,7 +1020,7 @@ export declare const useSession: () => {
1020
1020
  metadata?: Record<string, any> | undefined;
1021
1021
  } & {
1022
1022
  fetchOptions?: FetchOptions | undefined;
1023
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
1023
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
1024
1024
  status: boolean;
1025
1025
  }, {
1026
1026
  code?: string | undefined;
@@ -1077,7 +1077,7 @@ export declare const useSession: () => {
1077
1077
  additionalData?: Record<string, any> | undefined;
1078
1078
  } & {
1079
1079
  fetchOptions?: FetchOptions | undefined;
1080
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
1080
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
1081
1081
  redirect: boolean;
1082
1082
  url: string;
1083
1083
  } | (Omit<{
@@ -1120,7 +1120,7 @@ export declare const useSession: () => {
1120
1120
  rememberMe?: boolean | undefined;
1121
1121
  } & {
1122
1122
  fetchOptions?: FetchOptions | undefined;
1123
- }>, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<Omit<{
1123
+ }>, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<Omit<{
1124
1124
  redirect: boolean;
1125
1125
  token: string;
1126
1126
  url?: string | undefined;
@@ -1150,7 +1150,7 @@ export declare const useSession: () => {
1150
1150
  }, signOut: <FetchOptions extends import("@better-auth/core").ClientFetchOption<never, Partial<Record<string, any>> & Record<string, any>, Record<string, any> | undefined>>(data_0?: import("better-auth/react").Prettify<{
1151
1151
  query?: Record<string, any> | undefined;
1152
1152
  fetchOptions?: FetchOptions | undefined;
1153
- }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("better-auth/react").BetterFetchResponse<{
1153
+ }> | undefined, data_1?: FetchOptions | undefined) => Promise<import("@better-fetch/fetch").BetterFetchResponse<{
1154
1154
  success: boolean;
1155
1155
  }, {
1156
1156
  code?: string | undefined;
@@ -67,6 +67,18 @@ function UserAvatarMenu({ basePath = '', showProfile = true, showSettings = true
67
67
  else {
68
68
  // Use NEXT_PUBLIC env var or default to root
69
69
  const logoutUrl = process.env.NEXT_PUBLIC_LOGOUT_REDIRECT_URL || '/';
70
+ // 272068: revoke server-side BEFORE the better-auth client sign-out clears
71
+ // the cookie jar. authClient.signOut() ALONE leaves the server-side sess
72
+ // record alive - a copied pre-signout cookie still authenticates. The
73
+ // logout route (routes/auth/logout) runs deleteSessionEverywhere and
74
+ // clears the __Secure- twin; it must still see the cookie, so it goes
75
+ // first. Best-effort: a failed revoke must not trap the user on the page.
76
+ try {
77
+ await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' });
78
+ }
79
+ catch {
80
+ // sign-out continues regardless
81
+ }
70
82
  await better_auth_client_1.authClient.signOut();
71
83
  window.location.href = logoutUrl;
72
84
  }
@@ -27,16 +27,18 @@ function ModeAwareLoginPage({ onFederatedSignIn, onTraditionalSignIn, onForgotPa
27
27
  setLocalLoading(false);
28
28
  }
29
29
  };
30
- const isFederated = config.mode === 'federated';
31
- const isTraditional = config.mode === 'traditional';
30
+ // READ THE FLAGS, NOT `mode`. A single mode made these mutually exclusive, so a site
31
+ // could only ever show ONE of OAuth or username/password. Both are normal together;
32
+ // OAuth-only is the exception a client opts into. Source is the IDP
33
+ // (/api/auth/settings) unless the site deliberately overrides.
34
+ const isFederated = config.allowFederatedLogin !== false && config.providers.length > 0;
35
+ const isTraditional = config.allowTraditionalLogin !== false;
32
36
  const totalLoading = isLoading || localLoading;
33
37
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [error && ((0, jsx_runtime_1.jsx)("div", { className: "mb-6 px-4 py-3 rounded-lg", style: {
34
38
  background: 'var(--color-error, #ef4444)',
35
39
  color: 'white',
36
- }, children: error })), isFederated && ((0, jsx_runtime_1.jsx)(FederatedAuthSection_1.FederatedAuthSection, { providers: config.providers, onProviderClick: handleFederatedClick, isLoading: totalLoading })), isTraditional && ((0, jsx_runtime_1.jsx)(TraditionalAuthSection_1.TraditionalAuthSection, { email: email, password: password, onEmailChange: setEmail, onPasswordChange: setPassword, onSubmit: handleTraditionalSubmit, isLoading: totalLoading, buttonText: "Sign In", showForgotPassword: config.enableRecovery, onForgotPassword: onForgotPassword })), isFederated === false && isTraditional === false && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(FederatedAuthSection_1.FederatedAuthSection, { providers: config.providers, onProviderClick: handleFederatedClick, isLoading: totalLoading }), config.providers.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "relative my-6", children: [(0, jsx_runtime_1.jsx)("div", { className: "absolute inset-0 flex items-center", children: (0, jsx_runtime_1.jsx)("div", { className: "w-full", style: {
37
- borderTop: '1px solid var(--border-default)',
38
- } }) }), (0, jsx_runtime_1.jsx)("div", { className: "relative flex justify-center text-sm", children: (0, jsx_runtime_1.jsx)("span", { className: "px-2", style: {
39
- background: 'var(--bg-card)',
40
- color: 'var(--text-secondary)',
41
- }, children: "Or sign in with email" }) })] })), (0, jsx_runtime_1.jsx)(TraditionalAuthSection_1.TraditionalAuthSection, { email: email, password: password, onEmailChange: setEmail, onPasswordChange: setPassword, onSubmit: handleTraditionalSubmit, isLoading: totalLoading, buttonText: "Sign In", showForgotPassword: config.enableRecovery, onForgotPassword: onForgotPassword })] }))] }));
40
+ }, children: error })), isFederated && ((0, jsx_runtime_1.jsx)(FederatedAuthSection_1.FederatedAuthSection, { providers: config.providers, onProviderClick: handleFederatedClick, isLoading: totalLoading })), isFederated && isTraditional && ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center gap-3 my-6", "aria-hidden": "true", children: [(0, jsx_runtime_1.jsx)("span", { className: "h-px flex-1", style: { background: 'var(--border-default, #e5e7eb)' } }), (0, jsx_runtime_1.jsx)("span", { className: "text-xs uppercase tracking-wide", style: { color: 'var(--text-muted, #6b7280)' }, children: "or" }), (0, jsx_runtime_1.jsx)("span", { className: "h-px flex-1", style: { background: 'var(--border-default, #e5e7eb)' } })] })), isTraditional && ((0, jsx_runtime_1.jsx)(TraditionalAuthSection_1.TraditionalAuthSection, { email: email, password: password, onEmailChange: setEmail, onPasswordChange: setPassword, onSubmit: handleTraditionalSubmit, isLoading: totalLoading, buttonText: "Sign In", showForgotPassword: config.enableRecovery, onForgotPassword: onForgotPassword })), !isFederated && !isTraditional && ((0, jsx_runtime_1.jsxs)("div", { role: "alert", className: "px-4 py-3 rounded-lg text-sm text-left", style: {
41
+ border: '1px solid var(--border-default, #e5e7eb)',
42
+ color: 'var(--text-primary, #111827)',
43
+ }, children: [(0, jsx_runtime_1.jsx)("p", { className: "font-semibold", children: "Sign-in is not available for this application." }), (0, jsx_runtime_1.jsx)("p", { className: "mt-1", children: "No sign-in method is enabled for this client. An administrator needs to enable a federated provider or username and password sign-in." })] }))] }));
42
44
  }
@@ -31,8 +31,11 @@ function ModeAwareSignupPage({ onFederatedSignUp, onTraditionalSignUp, isLoading
31
31
  setLocalLoading(false);
32
32
  }
33
33
  };
34
- const isFederated = config.mode === 'federated';
35
- const isTraditional = config.mode === 'traditional';
34
+ // Same change as ModeAwareLoginPage: read the independent flags, not the single mode.
35
+ // Leaving signup on `mode` would have made sign-in and sign-up disagree about what the
36
+ // client offers - the worse half of a half-migration.
37
+ const isFederated = config.allowFederatedLogin !== false && config.providers.length > 0;
38
+ const isTraditional = config.allowTraditionalLogin !== false;
36
39
  const totalLoading = isLoading || localLoading;
37
40
  return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [error && ((0, jsx_runtime_1.jsx)("div", { className: "mb-6 px-4 py-3 rounded-lg", style: {
38
41
  background: 'var(--color-error, #ef4444)',
@@ -4,7 +4,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.TraditionalAuthSection = TraditionalAuthSection;
5
5
  const jsx_runtime_1 = require("react/jsx-runtime");
6
6
  function TraditionalAuthSection({ email, password, onEmailChange, onPasswordChange, onSubmit, isLoading, buttonText = 'Sign In', showForgotPassword = true, onForgotPassword, }) {
7
- return ((0, jsx_runtime_1.jsxs)("form", { onSubmit: onSubmit, className: "space-y-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "block text-sm font-medium mb-2", style: { color: 'var(--text-primary)' }, children: "Email Address" }), (0, jsx_runtime_1.jsx)("input", { type: "email", value: email, onChange: (e) => onEmailChange(e.target.value), placeholder: "you@example.com", disabled: isLoading, required: true, className: "w-full px-4 py-3 rounded-lg border transition-colors focus:outline-none focus:ring-2 disabled:opacity-50", style: {
7
+ // text-left is DELIBERATE and load-bearing: a host card with text-align:center made the
8
+ // Email label render CENTRED while Password stayed left, because Password sits in a flex
9
+ // row (for the forgot link) that ignores inherited alignment and Email did not. A shared
10
+ // component must not inherit its alignment from whatever wraps it.
11
+ return ((0, jsx_runtime_1.jsxs)("form", { onSubmit: onSubmit, className: "space-y-4 text-left", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("label", { className: "block text-sm font-medium mb-2", style: { color: 'var(--text-primary)' }, children: "Email Address" }), (0, jsx_runtime_1.jsx)("input", { type: "email", value: email, onChange: (e) => onEmailChange(e.target.value), placeholder: "you@example.com", disabled: isLoading, required: true, className: "w-full px-4 py-3 rounded-lg border transition-colors focus:outline-none focus:ring-2 disabled:opacity-50", style: {
8
12
  border: '1px solid var(--border-default)',
9
13
  color: 'var(--text-primary)',
10
14
  background: 'var(--bg-default)',