@seamless-auth/react 0.4.0 → 0.6.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.
- package/CHANGELOG.md +144 -0
- package/LICENSE.md +2 -2
- package/README.md +333 -63
- package/dist/AuthProvider.d.ts +20 -19
- package/dist/client/createSeamlessAuthClient.d.ts +83 -60
- package/dist/client/errors.d.ts +15 -0
- package/dist/client/result.d.ts +36 -0
- package/dist/client/webauthnSupport.d.ts +10 -0
- package/dist/components/AuthFallbackOptions.d.ts +1 -1
- package/dist/hooks/useAuthClient.d.ts +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/routes.d.ts +21 -0
- package/package.json +7 -4
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Credential, Organization, OrganizationMembership, User } from '../types';
|
|
2
|
+
import { type SeamlessAuthResult } from './result';
|
|
2
3
|
import { PasskeyPrfInput, PasskeyPrfResult } from './webauthnPrf';
|
|
3
4
|
export interface SeamlessAuthClientOptions {
|
|
4
5
|
apiHost: string;
|
|
@@ -15,8 +16,7 @@ export interface LoginStartResult {
|
|
|
15
16
|
}
|
|
16
17
|
export interface RegisterInput {
|
|
17
18
|
email: string;
|
|
18
|
-
phone
|
|
19
|
-
bootstrapToken?: string | null;
|
|
19
|
+
phone?: string | null;
|
|
20
20
|
}
|
|
21
21
|
export interface PasskeyMetadata {
|
|
22
22
|
friendlyName: string;
|
|
@@ -61,6 +61,20 @@ export interface OrganizationMembersResult {
|
|
|
61
61
|
members: OrganizationMembership[];
|
|
62
62
|
total: number;
|
|
63
63
|
}
|
|
64
|
+
/** Response body for a single membership mutation. */
|
|
65
|
+
export interface OrganizationMembershipResult {
|
|
66
|
+
membership: OrganizationMembership;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Response body when the active organization changes. The server also returns
|
|
70
|
+
* session material here, which this SDK deliberately does not surface: sessions
|
|
71
|
+
* are carried by cookies, so adopters have no reason to handle raw tokens.
|
|
72
|
+
*/
|
|
73
|
+
export interface OrganizationSwitchResult {
|
|
74
|
+
message: string;
|
|
75
|
+
organizationId: string;
|
|
76
|
+
organization: Organization;
|
|
77
|
+
}
|
|
64
78
|
export interface OAuthProvider {
|
|
65
79
|
id: string;
|
|
66
80
|
name: string;
|
|
@@ -84,16 +98,23 @@ export interface FinishOAuthLoginInput {
|
|
|
84
98
|
code: string;
|
|
85
99
|
state: string;
|
|
86
100
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
mfaRequired: boolean;
|
|
101
|
+
/** Response body for endpoints that only acknowledge the request. */
|
|
102
|
+
export interface MessageResult {
|
|
90
103
|
message: string;
|
|
91
104
|
}
|
|
92
|
-
|
|
93
|
-
|
|
105
|
+
/** Payload returned by a completed passkey login. */
|
|
106
|
+
export interface PasskeyLoginData {
|
|
107
|
+
prf?: PasskeyPrfResult;
|
|
108
|
+
}
|
|
109
|
+
/** Payload returned by a completed passkey registration. */
|
|
110
|
+
export interface PasskeyRegistrationData {
|
|
111
|
+
credentialId: string;
|
|
112
|
+
prfCapable: boolean;
|
|
113
|
+
}
|
|
114
|
+
/** Response body returned when credential metadata is updated. */
|
|
115
|
+
export interface CredentialUpdateResult {
|
|
94
116
|
message: string;
|
|
95
|
-
|
|
96
|
-
prfCapable?: boolean;
|
|
117
|
+
credential: Credential;
|
|
97
118
|
}
|
|
98
119
|
export interface RegisterPasskeyOptions {
|
|
99
120
|
metadata: PasskeyMetadata;
|
|
@@ -123,69 +144,71 @@ export interface StepUpStatus {
|
|
|
123
144
|
expiresAt: string | null;
|
|
124
145
|
maxAgeSeconds: number;
|
|
125
146
|
}
|
|
126
|
-
export interface StepUpVerificationResult extends StepUpStatus {
|
|
127
|
-
success: boolean;
|
|
128
|
-
message: string;
|
|
129
|
-
}
|
|
130
147
|
export interface PasskeyLoginOptions {
|
|
131
148
|
prf?: PasskeyPrfInput;
|
|
132
149
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
credentialId: string | null;
|
|
138
|
-
prf: PasskeyPrfResult | null;
|
|
150
|
+
/** Step-up payload that also carries the PRF output for the caller. */
|
|
151
|
+
export interface StepUpPrfData extends StepUpStatus {
|
|
152
|
+
credentialId: string;
|
|
153
|
+
prf: PasskeyPrfResult;
|
|
139
154
|
}
|
|
140
155
|
export type LogoutScope = 'current_session' | 'all_sessions';
|
|
141
156
|
export interface LogoutOptions {
|
|
142
157
|
scope?: LogoutScope;
|
|
143
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* Headless auth client.
|
|
161
|
+
*
|
|
162
|
+
* Every request resolves to a `SeamlessAuthResult`: check `error` first, then
|
|
163
|
+
* read `data`. Nothing here throws for an HTTP or transport failure.
|
|
164
|
+
* `isPasskeyPrfSupported` is the one exception, since it is a local capability
|
|
165
|
+
* check rather than a request.
|
|
166
|
+
*/
|
|
144
167
|
export interface SeamlessAuthClient {
|
|
145
|
-
getCurrentUser: () => Promise<
|
|
146
|
-
login: (input: LoginInput) => Promise<
|
|
147
|
-
loginWithPasskey: (options?: PasskeyLoginOptions) => Promise<
|
|
148
|
-
logout: (options?: LogoutOptions) => Promise<
|
|
149
|
-
logoutAllSessions: () => Promise<
|
|
150
|
-
deleteUser: () => Promise<
|
|
151
|
-
register: (input: RegisterInput) => Promise<
|
|
152
|
-
requestPhoneOtp: () => Promise<
|
|
153
|
-
verifyPhoneOtp: (verificationToken: string) => Promise<
|
|
154
|
-
requestLoginPhoneOtp: () => Promise<
|
|
155
|
-
verifyLoginPhoneOtp: (verificationToken: string) => Promise<
|
|
156
|
-
requestEmailOtp: () => Promise<
|
|
157
|
-
verifyEmailOtp: (verificationToken: string) => Promise<
|
|
158
|
-
requestLoginEmailOtp: () => Promise<
|
|
159
|
-
verifyLoginEmailOtp: (verificationToken: string) => Promise<
|
|
160
|
-
requestMagicLink: () => Promise<
|
|
161
|
-
checkMagicLink: () => Promise<
|
|
162
|
-
verifyMagicLink: (token: string) => Promise<
|
|
163
|
-
listOAuthProviders: () => Promise<OAuthProvidersResult
|
|
164
|
-
startOAuthLogin: (input: StartOAuthLoginInput) => Promise<StartOAuthLoginResult
|
|
165
|
-
finishOAuthLogin: (input: FinishOAuthLoginInput) => Promise<
|
|
166
|
-
registerPasskey: (input: PasskeyMetadata | RegisterPasskeyOptions) => Promise<
|
|
168
|
+
getCurrentUser: () => Promise<SeamlessAuthResult<CurrentUserResult>>;
|
|
169
|
+
login: (input: LoginInput) => Promise<SeamlessAuthResult<LoginStartResult>>;
|
|
170
|
+
loginWithPasskey: (options?: PasskeyLoginOptions) => Promise<SeamlessAuthResult<PasskeyLoginData>>;
|
|
171
|
+
logout: (options?: LogoutOptions) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
172
|
+
logoutAllSessions: () => Promise<SeamlessAuthResult<MessageResult>>;
|
|
173
|
+
deleteUser: () => Promise<SeamlessAuthResult<MessageResult>>;
|
|
174
|
+
register: (input: RegisterInput) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
175
|
+
requestPhoneOtp: () => Promise<SeamlessAuthResult<MessageResult>>;
|
|
176
|
+
verifyPhoneOtp: (verificationToken: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
177
|
+
requestLoginPhoneOtp: () => Promise<SeamlessAuthResult<MessageResult>>;
|
|
178
|
+
verifyLoginPhoneOtp: (verificationToken: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
179
|
+
requestEmailOtp: () => Promise<SeamlessAuthResult<MessageResult>>;
|
|
180
|
+
verifyEmailOtp: (verificationToken: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
181
|
+
requestLoginEmailOtp: () => Promise<SeamlessAuthResult<MessageResult>>;
|
|
182
|
+
verifyLoginEmailOtp: (verificationToken: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
183
|
+
requestMagicLink: () => Promise<SeamlessAuthResult<MessageResult>>;
|
|
184
|
+
checkMagicLink: () => Promise<SeamlessAuthResult<MessageResult>>;
|
|
185
|
+
verifyMagicLink: (token: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
186
|
+
listOAuthProviders: () => Promise<SeamlessAuthResult<OAuthProvidersResult>>;
|
|
187
|
+
startOAuthLogin: (input: StartOAuthLoginInput) => Promise<SeamlessAuthResult<StartOAuthLoginResult>>;
|
|
188
|
+
finishOAuthLogin: (input: FinishOAuthLoginInput) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
189
|
+
registerPasskey: (input: PasskeyMetadata | RegisterPasskeyOptions) => Promise<SeamlessAuthResult<PasskeyRegistrationData>>;
|
|
167
190
|
isPasskeyPrfSupported: () => Promise<boolean>;
|
|
168
|
-
getStepUpStatus: () => Promise<
|
|
169
|
-
verifyStepUpWithPasskey: () => Promise<
|
|
170
|
-
verifyStepUpWithPasskeyPrf: (input: PasskeyPrfInput) => Promise<
|
|
171
|
-
getTotpStatus: () => Promise<
|
|
172
|
-
startTotpEnrollment: () => Promise<
|
|
173
|
-
verifyTotpEnrollment: (code: string) => Promise<
|
|
174
|
-
disableTotp: (code: string) => Promise<
|
|
175
|
-
verifyStepUpWithTotp: (code: string) => Promise<
|
|
191
|
+
getStepUpStatus: () => Promise<SeamlessAuthResult<StepUpStatus>>;
|
|
192
|
+
verifyStepUpWithPasskey: () => Promise<SeamlessAuthResult<StepUpStatus>>;
|
|
193
|
+
verifyStepUpWithPasskeyPrf: (input: PasskeyPrfInput) => Promise<SeamlessAuthResult<StepUpPrfData>>;
|
|
194
|
+
getTotpStatus: () => Promise<SeamlessAuthResult<TotpStatus>>;
|
|
195
|
+
startTotpEnrollment: () => Promise<SeamlessAuthResult<TotpEnrollmentStartResult>>;
|
|
196
|
+
verifyTotpEnrollment: (code: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
197
|
+
disableTotp: (code: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
198
|
+
verifyStepUpWithTotp: (code: string) => Promise<SeamlessAuthResult<StepUpStatus>>;
|
|
176
199
|
updateCredential: (input: {
|
|
177
200
|
id: string;
|
|
178
201
|
friendlyName: string | null;
|
|
179
|
-
}) => Promise<
|
|
180
|
-
deleteCredential: (id: string) => Promise<
|
|
181
|
-
listOrganizations: () => Promise<
|
|
182
|
-
createOrganization: (input: CreateOrganizationInput) => Promise<
|
|
183
|
-
getOrganization: (organizationId: string) => Promise<
|
|
184
|
-
updateOrganization: (organizationId: string, input: UpdateOrganizationInput) => Promise<
|
|
185
|
-
switchOrganization: (organizationId: string) => Promise<
|
|
186
|
-
listOrganizationMembers: (organizationId: string) => Promise<
|
|
187
|
-
addOrganizationMember: (organizationId: string, input: OrganizationMemberInput) => Promise<
|
|
188
|
-
updateOrganizationMember: (organizationId: string, userId: string, input: OrganizationMemberUpdateInput) => Promise<
|
|
189
|
-
removeOrganizationMember: (organizationId: string, userId: string) => Promise<
|
|
202
|
+
}) => Promise<SeamlessAuthResult<CredentialUpdateResult>>;
|
|
203
|
+
deleteCredential: (id: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
204
|
+
listOrganizations: () => Promise<SeamlessAuthResult<OrganizationsResult>>;
|
|
205
|
+
createOrganization: (input: CreateOrganizationInput) => Promise<SeamlessAuthResult<OrganizationResult>>;
|
|
206
|
+
getOrganization: (organizationId: string) => Promise<SeamlessAuthResult<OrganizationResult>>;
|
|
207
|
+
updateOrganization: (organizationId: string, input: UpdateOrganizationInput) => Promise<SeamlessAuthResult<OrganizationResult>>;
|
|
208
|
+
switchOrganization: (organizationId: string) => Promise<SeamlessAuthResult<OrganizationSwitchResult>>;
|
|
209
|
+
listOrganizationMembers: (organizationId: string) => Promise<SeamlessAuthResult<OrganizationMembersResult>>;
|
|
210
|
+
addOrganizationMember: (organizationId: string, input: OrganizationMemberInput) => Promise<SeamlessAuthResult<OrganizationMembershipResult>>;
|
|
211
|
+
updateOrganizationMember: (organizationId: string, userId: string, input: OrganizationMemberUpdateInput) => Promise<SeamlessAuthResult<OrganizationMembershipResult>>;
|
|
212
|
+
removeOrganizationMember: (organizationId: string, userId: string) => Promise<SeamlessAuthResult<MessageResult>>;
|
|
190
213
|
}
|
|
191
214
|
export declare const createSeamlessAuthClient: (opts: SeamlessAuthClientOptions) => SeamlessAuthClient;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error carrying the auth server's response detail, so callers can map known
|
|
3
|
+
* failures to their own messaging instead of only seeing a generic string.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SeamlessAuthError extends Error {
|
|
6
|
+
readonly status: number;
|
|
7
|
+
readonly body: unknown;
|
|
8
|
+
constructor(message: string, status: number, body?: unknown);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Build a `SeamlessAuthError` from a failed response, preserving the status and
|
|
12
|
+
* the parsed body. The body may be empty or non-JSON, which is not treated as a
|
|
13
|
+
* failure: the fallback message is used instead.
|
|
14
|
+
*/
|
|
15
|
+
export declare function toSeamlessAuthError(response: Response, fallbackMessage: string): Promise<SeamlessAuthError>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { SeamlessAuthError } from './errors';
|
|
2
|
+
/**
|
|
3
|
+
* Outcome of an auth request.
|
|
4
|
+
*
|
|
5
|
+
* Auth failures are expected outcomes rather than exceptions: a wrong OTP, an
|
|
6
|
+
* expired magic link, or a disabled provider all map directly to UI state. So
|
|
7
|
+
* requests resolve to a result instead of throwing, and `data` is only readable
|
|
8
|
+
* once `error` has been checked.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const { data, error } = await authClient.getCurrentUser();
|
|
12
|
+
* if (error) {
|
|
13
|
+
* setMessage(error.message);
|
|
14
|
+
* return;
|
|
15
|
+
* }
|
|
16
|
+
* setUser(data.user);
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export type SeamlessAuthResult<T> = {
|
|
20
|
+
data: T;
|
|
21
|
+
error: null;
|
|
22
|
+
} | {
|
|
23
|
+
data: null;
|
|
24
|
+
error: SeamlessAuthError;
|
|
25
|
+
};
|
|
26
|
+
/** Status used when the request never reached the server. */
|
|
27
|
+
export declare const NETWORK_ERROR_STATUS = 0;
|
|
28
|
+
/**
|
|
29
|
+
* Run a request and convert it into a result. Never throws for HTTP outcomes,
|
|
30
|
+
* and also absorbs transport failures so callers only handle one shape.
|
|
31
|
+
*/
|
|
32
|
+
export declare function requestResult<T>(request: Promise<Response>, fallbackMessage: string): Promise<SeamlessAuthResult<T>>;
|
|
33
|
+
/** Wrap an already-derived value as a successful result. */
|
|
34
|
+
export declare function resultOf<T>(data: T): SeamlessAuthResult<T>;
|
|
35
|
+
/** Wrap a failure as a result. */
|
|
36
|
+
export declare function resultError<T>(message: string, status?: number, body?: unknown): SeamlessAuthResult<T>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True when the browser exposes a usable WebAuthn API in a secure context.
|
|
3
|
+
* This is the coarse gate for any passkey flow, including PRF assertions.
|
|
4
|
+
*/
|
|
5
|
+
export declare function isWebAuthnAvailable(): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* True when a user-verifying platform authenticator (Touch ID, Windows Hello,
|
|
8
|
+
* and similar) can be used on this device.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isPlatformAuthenticatorAvailable(): Promise<boolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const useAuthClient: () => import("
|
|
1
|
+
export declare const useAuthClient: () => import("../client/createSeamlessAuthClient").SeamlessAuthClient;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { AuthContextType, AuthProvider, useAuth } from '
|
|
2
|
-
import { AuthRoutes } from '
|
|
3
|
-
import { createSeamlessAuthClient, CreateOrganizationInput, CurrentUserResult, FinishOAuthLoginInput, LoginInput, LoginMethod, LoginStartResult, OAuthProvider, OAuthProvidersResult, OrganizationMemberInput, OrganizationMemberUpdateInput, OrganizationMembersResult, OrganizationResult,
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { AuthContextType, AuthProvider, useAuth } from './AuthProvider';
|
|
2
|
+
import { AuthRoutes } from './AuthRoutes';
|
|
3
|
+
import { createSeamlessAuthClient, CredentialUpdateResult, CreateOrganizationInput, CurrentUserResult, FinishOAuthLoginInput, LoginInput, LoginMethod, LoginStartResult, MessageResult, OAuthProvider, OAuthProvidersResult, OrganizationMemberInput, OrganizationMemberUpdateInput, OrganizationMembersResult, OrganizationMembershipResult, OrganizationResult, OrganizationSwitchResult, OrganizationsResult, PasskeyLoginData, PasskeyMetadata, PasskeyRegistrationData, RegisterInput, RegisterPasskeyOptions, SeamlessAuthClient, SeamlessAuthClientOptions, StartOAuthLoginInput, StartOAuthLoginResult, StepUpMethod, StepUpStatus, StepUpPrfData, TotpEnrollmentStartResult, TotpStatus, UpdateOrganizationInput } from './client/createSeamlessAuthClient';
|
|
4
|
+
import { SeamlessAuthError } from './client/errors';
|
|
5
|
+
import type { SeamlessAuthResult } from './client/result';
|
|
6
|
+
import { encodePrfSalt, extractPasskeyPrfResult, isPasskeyPrfSupported, PasskeyPrfInput, PasskeyPrfResult } from './client/webauthnPrf';
|
|
7
|
+
import { useAuthClient } from './hooks/useAuthClient';
|
|
8
|
+
import { usePasskeySupport } from './hooks/usePasskeySupport';
|
|
9
|
+
import { hasScopedRole, roleGrantsAccess } from './scopedRoles';
|
|
10
|
+
import { Credential, Organization, OrganizationMembership, User } from './types';
|
|
11
|
+
export { AuthProvider, AuthRoutes, createSeamlessAuthClient, encodePrfSalt, extractPasskeyPrfResult, hasScopedRole, isPasskeyPrfSupported, roleGrantsAccess, SeamlessAuthError, useAuth, useAuthClient, usePasskeySupport, };
|
|
12
|
+
export type { CredentialUpdateResult, AuthContextType, Credential, CreateOrganizationInput, CurrentUserResult, FinishOAuthLoginInput, LoginInput, LoginMethod, LoginStartResult, MessageResult, OAuthProvider, OAuthProvidersResult, Organization, OrganizationMemberInput, OrganizationMembership, OrganizationMemberUpdateInput, OrganizationMembersResult, OrganizationMembershipResult, OrganizationResult, OrganizationSwitchResult, OrganizationsResult, PasskeyLoginData, PasskeyMetadata, PasskeyPrfInput, PasskeyPrfResult, PasskeyRegistrationData, RegisterInput, RegisterPasskeyOptions, SeamlessAuthClient, SeamlessAuthClientOptions, SeamlessAuthResult, StartOAuthLoginInput, StartOAuthLoginResult, StepUpMethod, StepUpStatus, StepUpPrfData, TotpEnrollmentStartResult, TotpStatus, UpdateOrganizationInput, User, };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{jsx as e,jsxs as t,Fragment as o}from"react/jsx-runtime";import{bufferToBase64URLString as n,browserSupportsWebAuthn as i,base64URLStringToBuffer as r,startAuthentication as a,startRegistration as s,WebAuthnError as l}from"@simplewebauthn/browser";import{useState as d,useEffect as c,createContext as u,useMemo as _,useCallback as m,useContext as p,useRef as g}from"react";import{useNavigate as h,useLocation as f,useSearchParams as y,Routes as b,Route as k,Navigate as v}from"react-router-dom";import w,{AsYouType as x,parsePhoneNumberFromString as P}from"libphonenumber-js";function S(e){if(e instanceof ArrayBuffer)return e;const t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),o=new Uint8Array(t.byteLength);return o.set(t),o.buffer}function N(e){return"string"==typeof e?e:n(S(e))}function O(e){return"string"==typeof e?r(e):e}function T(e){return{...e.credentialId?{credentialId:e.credentialId}:{},prf:{salt:N(e.salt),...e.secondSalt?{secondSalt:N(e.secondSalt)}:{}}}}async function C(){return!!i()&&(("undefined"==typeof window||!1!==window.isSecureContext)&&(void 0!==globalThis.PublicKeyCredential&&"undefined"!=typeof navigator&&"function"==typeof navigator.credentials?.get))}function A(e){const t=e,o=t.extensions?.prf?.eval;return o?{...t,extensions:{...t.extensions,prf:{...t.extensions?.prf,eval:{...o,...o.first?{first:O(o.first)}:{},...o.second?{second:O(o.second)}:{}}}}}:e}function M(e){const t=e.clientExtensionResults,o=t?.prf?.results?.first;if(!o)return null;const i=(r=o)instanceof ArrayBuffer?new Uint8Array(r):new Uint8Array(r.buffer,r.byteOffset,r.byteLength);var r;return{credentialId:e.id,output:i,outputBase64url:n(S(i))}}function I(e){const t=e.clientExtensionResults;return t?.prf?.results?{...e,clientExtensionResults:{...e.clientExtensionResults,prf:{...t.prf,results:void 0}}}:e}function E(e){const t=e.clientExtensionResults;return!0===t?.prf?.enabled}const z=e=>({success:!1,fresh:!1,method:null,verifiedAt:null,expiresAt:null,maxAgeSeconds:0,message:e}),L=e=>({...z(e),credentialId:null,prf:null});function j(e){return e?{method:"POST",body:JSON.stringify(T(e))}:{method:"POST"}}const U=e=>{const t=(e=>{const{authHost:t}=e;return async function(e,o){const n=`${t?.replace(/\/+$/,"")??""}/auth${e.startsWith("/")?e:`/${e}`}`,i={...o,credentials:"include",headers:{"Content-Type":"application/json",...o?.headers}},r=await fetch(n,i);return r.ok||console.warn("Auth fetch failed:",r.status),r}})({authHost:e.apiHost});return{getCurrentUser:()=>t("users/me",{method:"GET"}),login:e=>t("/login",{method:"POST",body:JSON.stringify(e)}),loginWithPasskey:async e=>{const o=await t("/webAuthn/login/start",{...j(e?.prf)});if(!o.ok)return{success:!1,mfaRequired:!1,message:"Failed to start passkey login."};try{const e=await o.json(),n=await a({optionsJSON:A(e)}),i=M(n),r=I(n),s=await t("/webAuthn/login/finish",{method:"POST",body:JSON.stringify({assertionResponse:r})});if(!s.ok)return{success:!1,mfaRequired:!1,message:"Failed to verify passkey."};const l=await s.json();return"Success"===l.message?{success:!l.mfaLogin,mfaRequired:Boolean(l.mfaLogin),message:l.mfaLogin?"Passkey login requires MFA.":"Passkey login succeeded.",...i?{prf:i}:{}}:{success:!1,mfaRequired:!1,message:l.message??"Passkey login failed."}}catch{return console.error("Passkey login error."),{success:!1,mfaRequired:!1,message:"Passkey login failed."}}},logout:(e={})=>t("all_sessions"===e.scope?"/logout/all":"/logout",{method:"DELETE"}),logoutAllSessions:()=>t("/logout/all",{method:"DELETE"}),deleteUser:()=>t("/users/delete",{method:"DELETE"}),register:e=>t("/registration/register",{method:"POST",body:JSON.stringify({email:e.email,phone:e.phone,...e.bootstrapToken?{bootstrapToken:e.bootstrapToken}:{}})}),requestPhoneOtp:()=>t("/otp/generate-phone-otp",{method:"GET"}),verifyPhoneOtp:e=>t("/otp/verify-phone-otp",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({verificationToken:e}),credentials:"include"}),requestLoginPhoneOtp:()=>t("/otp/generate-login-phone-otp",{method:"GET"}),verifyLoginPhoneOtp:e=>t("/otp/verify-login-phone-otp",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({verificationToken:e}),credentials:"include"}),requestEmailOtp:()=>t("/otp/generate-email-otp",{method:"GET",headers:{"Content-Type":"application/json"}}),verifyEmailOtp:e=>t("/otp/verify-email-otp",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({verificationToken:e}),credentials:"include"}),requestLoginEmailOtp:()=>t("/otp/generate-login-email-otp",{method:"GET",headers:{"Content-Type":"application/json"}}),verifyLoginEmailOtp:e=>t("/otp/verify-login-email-otp",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({verificationToken:e}),credentials:"include"}),requestMagicLink:()=>t("/magic-link",{method:"GET"}),checkMagicLink:()=>t("/magic-link/check",{method:"GET",headers:{"Content-Type":"application/json"}}),verifyMagicLink:e=>t(`/magic-link/verify/${e}`,{method:"GET",headers:{"Content-Type":"application/json"}}),listOAuthProviders:async()=>{const e=await t("/oauth/providers",{method:"GET"});if(!e.ok)throw new Error("Failed to list OAuth providers.");return e.json()},startOAuthLogin:async e=>{const o=await t(`/oauth/${encodeURIComponent(e.providerId)}/start`,{method:"POST",body:JSON.stringify({...e.redirectUri?{redirectUri:e.redirectUri}:{},...e.returnTo?{returnTo:e.returnTo}:{}})});if(!o.ok)throw new Error("Failed to start OAuth login.");return o.json()},finishOAuthLogin:e=>t(`/oauth/${encodeURIComponent(e.providerId)}/callback`,{method:"POST",body:JSON.stringify({code:e.code,state:e.state})}),registerPasskey:async e=>{const o=function(e){return"metadata"in e?e:{metadata:e}}(e),n=await t(function(e){const t=new URLSearchParams;e.requirePrf?t.set("requirePrf","true"):e.requestPrf&&t.set("requestPrf","true");const o=t.toString();return"/webAuthn/register/start"+(o?`?${o}`:"")}(o),{method:"GET",headers:{"Content-Type":"application/json"},credentials:"include"});if(!n.ok)return{success:!1,message:"Failed to fetch passkey registration challenge."};const i=await n.json();let r;try{r=await s({optionsJSON:i})}catch(e){return e instanceof l?{success:!1,message:e.name}:(console.error("Passkey registration error."),{success:!1,message:"Passkey registration failed."})}return(await t("/webAuthn/register/finish",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({attestationResponse:r,metadata:{...o.metadata,prfCapable:E(r)}}),credentials:"include"})).ok?{success:!0,message:"Passkey registered successfully.",credentialId:r.id,prfCapable:E(r)}:{success:!1,message:"Verification failed."}},isPasskeyPrfSupported:C,getStepUpStatus:()=>t("/step-up/status",{method:"GET"}),verifyStepUpWithPasskey:async()=>{const e=await t("/step-up/webauthn/start",{method:"POST"});if(!e.ok)return z("Failed to start step-up authentication.");try{const o=await e.json(),n=I(await a({optionsJSON:A(o)})),i=await t("/step-up/webauthn/finish",{method:"POST",body:JSON.stringify({assertionResponse:n})});if(!i.ok)return z("Failed to verify step-up authentication.");const r=await i.json(),s="webauthn"===r.method?r.method:null,l="Success"===r.message&&!0===r.fresh&&"webauthn"===s;return{success:l,fresh:Boolean(r.fresh),method:s,verifiedAt:r.verifiedAt??null,expiresAt:r.expiresAt??null,maxAgeSeconds:r.maxAgeSeconds??0,message:l?"Step-up authentication succeeded.":r.message??"Step-up authentication failed."}}catch{return console.error("Step-up authentication error."),z("Step-up authentication failed.")}},verifyStepUpWithPasskeyPrf:async e=>{const o=await t("/step-up/webauthn/start",{...j(e)});if(!o.ok)return L("Failed to start step-up authentication.");try{const e=await o.json(),n=await a({optionsJSON:A(e)}),i=M(n),r=I(n);if(!i)return L("Passkey did not return PRF output.");const s=await t("/step-up/webauthn/finish",{method:"POST",body:JSON.stringify({assertionResponse:r})});if(!s.ok)return L("Failed to verify step-up authentication.");const l=await s.json(),d="webauthn"===l.method?l.method:null,c="Success"===l.message&&!0===l.fresh&&"webauthn"===d;return{success:c,fresh:Boolean(l.fresh),method:d,verifiedAt:l.verifiedAt??null,expiresAt:l.expiresAt??null,maxAgeSeconds:l.maxAgeSeconds??0,message:c?"Step-up authentication succeeded.":l.message??"Step-up authentication failed.",credentialId:i.credentialId,prf:i}}catch{return console.error("Step-up authentication error."),L("Step-up authentication failed.")}},getTotpStatus:()=>t("/totp/status",{method:"GET"}),startTotpEnrollment:()=>t("/totp/enroll/start",{method:"POST"}),verifyTotpEnrollment:e=>t("/totp/enroll/verify",{method:"POST",body:JSON.stringify({code:e})}),disableTotp:e=>t("/totp/disable",{method:"POST",body:JSON.stringify({code:e})}),verifyStepUpWithTotp:async e=>{const o=await t("/totp/verify-mfa",{method:"POST",body:JSON.stringify({code:e})});if(!o.ok)return z("Failed to verify step-up authentication.");try{const e=await o.json(),t="totp"===e.method?e.method:null,n="Success"===e.message&&!0===e.fresh&&"totp"===t;return{success:n,fresh:Boolean(e.fresh),method:t,verifiedAt:e.verifiedAt??null,expiresAt:e.expiresAt??null,maxAgeSeconds:e.maxAgeSeconds??0,message:n?"Step-up authentication succeeded.":e.message??"Step-up authentication failed."}}catch{return console.error("Step-up authentication error."),z("Step-up authentication failed.")}},updateCredential:e=>t("users/credentials",{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}),deleteCredential:e=>t("users/credentials",{method:"DELETE",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify({id:e})}),listOrganizations:()=>t("/organizations",{method:"GET"}),createOrganization:e=>t("/organizations",{method:"POST",body:JSON.stringify(e)}),getOrganization:e=>t(`/organizations/${encodeURIComponent(e)}`,{method:"GET"}),updateOrganization:(e,o)=>t(`/organizations/${encodeURIComponent(e)}`,{method:"PATCH",body:JSON.stringify(o)}),switchOrganization:e=>t(`/organizations/${encodeURIComponent(e)}/switch`,{method:"POST"}),listOrganizationMembers:e=>t(`/organizations/${encodeURIComponent(e)}/members`,{method:"GET"}),addOrganizationMember:(e,o)=>t(`/organizations/${encodeURIComponent(e)}/members`,{method:"POST",body:JSON.stringify(o)}),updateOrganizationMember:(e,o,n)=>t(`/organizations/${encodeURIComponent(e)}/members/${encodeURIComponent(o)}`,{method:"PATCH",body:JSON.stringify(n)}),removeOrganizationMember:(e,o)=>t(`/organizations/${encodeURIComponent(e)}/members/${encodeURIComponent(o)}`,{method:"DELETE"})}};function F(e,t){const o=e.trim(),n=t.trim();if(!o||!n)return!1;if(o===n)return!0;if(o.endsWith(":*")){const e=o.slice(0,-2);return n===e||n.startsWith(`${e}:`)}if(!n.includes(":"))return!1;if(!o.includes(":"))return n.startsWith(`${o}:`);const i=o.split(":"),r=n.split(":"),a=i[i.length-1],s=r[r.length-1],l=i.slice(0,-1),d=r.slice(0,-1);return"write"===a&&"read"===s&&l.length===d.length&&l.every((e,t)=>e===d[t])}function B(e,t){if(!Array.isArray(e))return!1;const o=e.filter(e=>"string"==typeof e);return(Array.isArray(t)?t:[t]).some(e=>o.some(t=>F(t,e)))}const R=u(void 0),q=()=>{const e=p(R);if(!e)throw new Error("useAuth must be used within an AuthProvider");return e},G=({children:t,apiHost:o,autoDetectPreviousSignin:n=!0})=>{const[i,r]=d(null),[a,s]=d([]),[l,u]=d([]),[p,g]=d(null),[h,f]=d(null),[y,b]=d(!1),[k,v]=d(!0),{hasSignedInBefore:w,markSignedIn:x}=function(e="seamlessauth_seen"){const[t,o]=d(!1);return c(()=>{try{"true"===localStorage.getItem(e)&&o(!0)}catch{}},[e]),{hasSignedInBefore:t,markSignedIn:()=>{try{localStorage.setItem(e,"true"),o(!0)}catch{}}}}(),P=_(()=>U({apiHost:o}),[o]),S=m(()=>{b(!1),r(null),s([]),u([]),g(null),f(null)},[]),N=m(async()=>{try{await P.logout()}catch{console.error("Error during logout")}finally{S()}},[P,S]),O=m(async()=>{try{await P.logoutAllSessions()}catch{console.error("Error during logout")}finally{S()}},[P,S]),T=m(async()=>{v(!0);try{const e=await P.getCurrentUser();if(e.ok){const{user:t,credentials:o,organizations:n,activeOrganization:i}=await e.json();r(t),s(o??[]),u(n??[]),g(i??null),b(!0)}else await N()}catch{await N()}finally{v(!1)}},[P,N]),C=m(async()=>{const e=await P.getStepUpStatus();if(!e.ok)return f(null),null;const t=await e.json();return f(t),t},[P]),A=m(async()=>{const e=await P.verifyStepUpWithPasskey();return e.success&&f({fresh:e.fresh,method:e.method,verifiedAt:e.verifiedAt,expiresAt:e.expiresAt,maxAgeSeconds:e.maxAgeSeconds}),e},[P]),M=m(async e=>{const t=await P.verifyStepUpWithPasskeyPrf(e);return t.success&&f({fresh:t.fresh,method:t.method,verifiedAt:t.verifiedAt,expiresAt:t.expiresAt,maxAgeSeconds:t.maxAgeSeconds}),t},[P]),I=m(async e=>{const t=await P.verifyStepUpWithTotp(e);return t.success&&f({fresh:t.fresh,method:t.method,verifiedAt:t.verifiedAt,expiresAt:t.expiresAt,maxAgeSeconds:t.maxAgeSeconds}),t},[P]);return c(()=>{T()},[T]),c(()=>{i&&y&&x()},[i,y,x]),e(R.Provider,{value:{user:i,logout:N,logoutAllSessions:O,refreshSession:T,loading:k,deleteUser:async()=>{try{if((await P.deleteUser()).ok)return r(null),b(!1),s([]),u([]),g(null),void f(null);throw new Error("Could not delete user.")}catch{throw console.error("Something went wrong deleting user."),new Error("Could not delete user.")}},isAuthenticated:y,hasRole:e=>i?.roles?.includes(e),hasScopedRole:e=>i?B(i.roles,e):void 0,apiHost:o,markSignedIn:x,hasSignedInBefore:!!n&&w,credentials:a,organizations:l,activeOrganization:p,switchOrganization:async e=>{if(!(await P.switchOrganization(e)).ok)throw new Error("Failed to switch organization");await T()},listOAuthProviders:()=>P.listOAuthProviders(),startOAuthLogin:e=>P.startOAuthLogin(e),finishOAuthLogin:async e=>{if(!(await P.finishOAuthLogin(e)).ok)throw new Error("Failed to finish OAuth login");await T()},stepUpStatus:h,updateCredential:async e=>{const t=await P.updateCredential({friendlyName:e.friendlyName,id:e.id});if(t.ok){const e=await t.json(),o=e.credential??e;return s(e=>e.map(e=>e.id===o.id?{...e,...o}:e)),e}throw new Error("Failed to update credential")},deleteCredential:async e=>{const t=await P.deleteCredential(e);if(t.ok){const o=await t.json();return s(t=>t.filter(t=>t.id!==e)),o}throw new Error("Failed to delete credential")},login:async(e,t)=>P.login({identifier:e,passkeyAvailable:t}),handlePasskeyLogin:async()=>{const e=await P.loginWithPasskey();return e.mfaRequired?(console.warn("Passkey login requested MFA, but the built-in MFA route is not currently available."),!1):e.success?(await T(),!0):(console.error("Passkey login failed."),!1)},refreshStepUpStatus:C,verifyStepUpWithPasskey:A,verifyStepUpWithPasskeyPrf:M,verifyStepUpWithTotp:I},children:t})};function J(e,t){void 0===t&&(t={});var o=t.insertAt;if(e&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],i=document.createElement("style");i.type="text/css","top"===o&&n.firstChild?n.insertBefore(i,n.firstChild):n.appendChild(i),i.styleSheet?i.styleSheet.cssText=e:i.appendChild(document.createTextNode(e))}}var D="login-module__container___YggDx",W="login-module__card___Ub-Py",V="login-module__heading___neEqb",$="login-module__inputGroup___P6qgS",K="login-module__label___mx5vu",H="login-module__input___U07lW",Y="login-module__helperText___kDQ4-",Z="login-module__error___40zxh",Q="login-module__button___0kFBs",X="login-module__toggle___1JiG1",ee="login-module__underline___gs-RS",te="login-module__phoneRow___oeNtq",oe="login-module__select___rRV1O",ne="login-module__phoneInput___2MPQC",ie="login-module__fallbackCard___HdIk-",re="login-module__fallbackHeader___-il2v",ae="login-module__fallbackDescription___ea5EB",se="login-module__fallbackActions___AD3ni",le="login-module__fallbackActionButton___lFgWf",de="login-module__actionTitle___ycrMp",ce="login-module__actionSubtext___opaIV",ue="login-module__linkButton___5lsoe";J(".login-module__container___YggDx{align-items:center;color:#fff;display:flex;justify-content:center}.login-module__card___Ub-Py{background-color:#1f2937;border-radius:.5rem;box-shadow:0 4px 6px rgba(0,0,0,.1);max-width:28rem;padding:2rem;width:100%}.login-module__heading___neEqb{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1.5rem;text-align:center}.login-module__message___qSejT{color:#68d391;text-align:center}.login-module__inputGroup___P6qgS{margin-bottom:1rem}.login-module__label___mx5vu{color:#d1d5db;display:block}.login-module__input___U07lW{background-color:#4b5563;border:1px solid #d1d5db;border-radius:.375rem;margin-top:.25rem;padding:.5rem;width:100%}.login-module__input___U07lW:focus{box-shadow:0 0 0 2px #3b82f6;outline:none}.login-module__helperText___kDQ4-{color:#9ca3af;font-size:.75rem;margin-top:.5rem}.login-module__error___40zxh{color:#f87171;font-size:.875rem}.login-module__button___0kFBs{background-color:#2563eb;border-radius:.375rem;color:#fff;cursor:pointer;margin-top:1rem;padding:.5rem;transition:background-color .3s;width:100%}.login-module__button___0kFBs:hover{background-color:#1d4ed8}.login-module__button___0kFBs:disabled{background-color:#9ca3af;cursor:not-allowed}.login-module__toggle___1JiG1{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.875rem;margin-top:1.5rem;text-align:center;width:100%}.login-module__underline___gs-RS{text-decoration:underline}.login-module__phoneRow___oeNtq{display:grid;gap:.5rem;grid-template-columns:1fr 3fr;margin-top:.25rem}.login-module__phoneInput___2MPQC,.login-module__select___rRV1O{background-color:#4b5563;border:1px solid #d1d5db;border-radius:.375rem;padding:.5rem;width:100%}@media (max-width:500px){.login-module__phoneRow___oeNtq{grid-template-columns:1fr}}.login-module__fallbackCard___HdIk-{background:hsla(0,0%,100%,.04);border:1px solid hsla(0,0%,100%,.08);border-radius:12px;display:flex;flex-direction:column;gap:14px;margin-top:18px;padding:18px}.login-module__fallbackHeader___-il2v{color:#f3f4f6;font-size:.95rem;font-weight:600}.login-module__fallbackDescription___ea5EB{color:#9ca3af;font-size:.85rem;line-height:1.4}.login-module__fallbackActions___AD3ni{display:flex;flex-direction:column;gap:10px}.login-module__fallbackActionButton___lFgWf{background:rgba(0,0,0,.25);border:1px solid hsla(0,0%,100%,.08);border-radius:8px;cursor:pointer;display:flex;flex-direction:column;padding:12px 14px;text-align:left;transition:all .15s ease}.login-module__fallbackActionButton___lFgWf:hover{background:hsla(0,0%,100%,.06);border-color:hsla(0,0%,100%,.15)}.login-module__actionTitle___ycrMp{color:#f9fafb;font-size:.9rem;font-weight:500}.login-module__actionSubtext___opaIV{color:#9ca3af;font-size:.75rem;margin-top:2px}.login-module__linkButton___5lsoe{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.8rem;margin-top:6px}.login-module__linkButton___5lsoe:hover{text-decoration:underline}");var _e="termsModal-module__overlay___-j6r5",me="termsModal-module__modal___4PxZV",pe="termsModal-module__header___B7wxb",ge="termsModal-module__title___Sucwt",he="termsModal-module__closeBtn___evIs5",fe="termsModal-module__content___5BDhN",ye="termsModal-module__link___oPZrU";J(".termsModal-module__overlay___-j6r5{align-items:center;background-color:rgba(0,0,0,.7);display:flex;inset:0;justify-content:center;position:fixed;z-index:999}.termsModal-module__modal___4PxZV{background-color:#1a1a1a;border-radius:8px;box-shadow:0 10px 25px rgba(0,0,0,.4);color:#fff;max-height:80vh;max-width:640px;outline:none;overflow-y:auto;padding:24px;width:100%}.termsModal-module__header___B7wxb{align-items:center;display:flex;justify-content:space-between;margin-bottom:16px}.termsModal-module__title___Sucwt{color:#60a5fa;font-size:1.25rem;font-weight:700}.termsModal-module__closeBtn___evIs5{background:none;border:none;color:#ccc;cursor:pointer;font-size:1.75rem}.termsModal-module__closeBtn___evIs5:hover{color:#fff}.termsModal-module__content___5BDhN{color:#d1d5db;font-size:.9rem;line-height:1.6}.termsModal-module__link___oPZrU{color:#60a5fa;text-decoration:underline}.termsModal-module__link___oPZrU:hover{text-decoration:none}");const be=({isOpen:o,onClose:n})=>{const i=g(null);return c(()=>{const e=e=>{"Escape"===e.key&&n()};return o&&(document.addEventListener("keydown",e),i.current?.focus()),()=>{document.removeEventListener("keydown",e)}},[o,n]),o?e("div",{className:_e,role:"dialog","aria-modal":"true","aria-labelledby":"terms-title",children:t("div",{className:me,tabIndex:-1,ref:i,children:[t("div",{className:pe,children:[e("h2",{id:"terms-title",className:ge,children:"SMS Terms & Conditions"}),e("button",{onClick:n,className:he,children:"×"})]}),t("div",{className:fe,children:[t("p",{children:[e("strong",{children:"Effective Date:"})," June 01, 2025"]}),e("p",{children:"By providing your phone number to SeamlessAuth, a Fells Code LLC product, you agree to receive SMS messages for identity verification, authentication, and account security."}),t("p",{children:[e("strong",{children:"1. Purpose:"})," SMS is used only for account security (OTP, MFA). No marketing messages."]}),t("p",{children:[e("strong",{children:"2. Frequency:"})," Based on login and account activity."]}),t("p",{children:[e("strong",{children:"3. Opt-Out:"})," Contact support@seamlessauth.com to opt out."]}),t("p",{children:[e("strong",{children:"4. Fees:"})," Message and data rates may apply."]}),t("p",{children:[e("strong",{children:"5. Supported Carriers:"})," Most major providers supported, delivery not guaranteed."]}),t("p",{children:[e("strong",{children:"6. Privacy:"})," Your phone number is not shared or sold. See our Privacy Policy."]}),t("p",{children:[e("strong",{children:"7. Changes:"})," Terms may be updated with notice on this page."]}),t("p",{children:["Questions? Email us at"," ",e("a",{className:ye,href:"mailto:support@seamlessauth.com",children:"support@seamlessauth.com"}),"."]})]})]})}):null},ke=[{code:"US",name:"United States",dialCode:"+1",flag:"🇺🇸"},{code:"CA",name:"Canada",dialCode:"+1",flag:"🇨🇦"},{code:"GB",name:"United Kingdom",dialCode:"+44",flag:"🇬🇧"},{code:"IN",name:"India",dialCode:"+91",flag:"🇮🇳"},{code:"AU",name:"Australia",dialCode:"+61",flag:"🇦🇺"}];function ve({phone:o,setPhone:n,phoneError:i,setPhoneError:r}){const[a,s]=d(!1),[l,u]=d(ke[0]);c(()=>{const e=function(){try{const e=Intl.DateTimeFormat().resolvedOptions().locale||"en-US",t=e.split("-")[1]?.toUpperCase()||"US";return ke.find(e=>e.code===t)||ke[0]}catch{return ke[0]}}();u(e)},[]);return t("div",{className:$,children:[e("label",{id:"phone",className:K,children:"Phone Number"}),t("div",{className:te,children:[e("select",{value:l.code,onChange:e=>{const t=ke.find(t=>t.code===e.target.value);if(t){u(t);const e=o.replace(/^\+\d+/,""),i=(new x).input(t.dialCode+e);n(i)}},className:oe,children:ke.map(e=>t("option",{value:e.code,children:[e.flag," (",e.dialCode,")"]},e.code))}),e("input",{"aria-labelledby":"phone",type:"tel",value:o,onChange:e=>{const t=e.target.value,o=t.startsWith(l.dialCode)?t:l.dialCode+t,a=(new x).input(o);n(a),i&&r("")},onBlur:()=>{if(o){const e=P(o),t=e?.isValid();r(t?"":"Please enter a valid phone number.")}},autoComplete:"off",placeholder:"(555) 123-4567",className:ne})]}),t("p",{className:Y,children:["By signing up, you agree to our"," ",e("button",{onClick:()=>s(!0),className:ee,children:"SMS Terms & Conditions"}),"."]}),i&&e("p",{className:Z,children:i}),e(be,{isOpen:a,onClose:()=>s(!1)})]})}const we=()=>{const{apiHost:e}=q();return _(()=>U({apiHost:e}),[e])},xe=e=>{if("string"!=typeof e)return!1;const t=e.trim();if(t.length<3||t.length>320)return!1;const o=t.split("@");if(2!==o.length)return!1;const[n,i]=o;return!(!/^[A-Za-z0-9._%+-]+$/.test(n)||n.startsWith(".")||n.endsWith(".")||n.includes(".."))&&!(!/^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(i)||i.startsWith("-")||i.endsWith("-")||i.startsWith(".")||i.endsWith(".")||i.includes(".."))},Pe=e=>{const t=w(e);return t?.isValid()||!1};const Se=()=>{const[e,t]=d(!1),[o,n]=d(!0);return c(()=>{let e=!0;return(async()=>{try{const o=await async function(){if(window.PublicKeyCredential&&"function"==typeof window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable)try{return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return console.error("Error checking passkey support."),!1}return!1}();e&&t(o)}catch{e&&t(!1)}finally{e&&n(!1)}})(),()=>{e=!1}},[]),{passkeySupported:e,loading:o}},Ne=({identifier:o,onMagicLink:n,onEmailOtp:i,onPhoneOtp:r,onPasskeyRetry:a,loginMethods:s})=>{const l=new Set(s??["passkey","magic_link","phone_otp"]),d=l.has("magic_link")&&xe(o),c=l.has("email_otp")&&Boolean(i)&&xe(o),u=l.has("phone_otp")&&Pe(o),_=l.has("passkey")&&Boolean(a);return d||c||u||_?t("div",{className:ie,children:[e("div",{className:re,children:"Choose a sign-in method"}),e("p",{className:ae,children:"Choose another secure sign-in method."}),t("div",{className:se,children:[d&&t("button",{type:"button",className:le,onClick:n,children:[e("span",{className:de,children:"Email Magic Link"}),e("span",{className:ce,children:"Send a secure sign-in link to your email"})]}),c&&t("button",{type:"button",className:le,onClick:i,children:[e("span",{className:de,children:"Email Code"}),e("span",{className:ce,children:"Receive a one-time code by email"})]}),u&&t("button",{type:"button",className:le,onClick:r,children:[e("span",{className:de,children:"Text Message Code"}),e("span",{className:ce,children:"Receive a one-time code via SMS"})]})]}),_&&e("button",{type:"button",className:ue,onClick:a,children:"Try passkey anyway"})]}):null},Oe="seamless:oauth:provider",Te=()=>{const{listOAuthProviders:o,startOAuthLogin:n}=q(),[i,r]=d([]),[a,s]=d("");if(c(()=>{let e=!0;return o().then(t=>{e&&r(t.providers??[])}).catch(()=>{e&&r([])}),()=>{e=!1}},[o]),0===i.length)return null;return t("div",{className:se,children:[i.map(o=>e("button",{type:"button",className:le,onClick:()=>(async e=>{s("");try{sessionStorage.setItem(Oe,e);const{authorizationUrl:t}=await n({providerId:e,redirectUri:`${window.location.origin}/oauth/callback`});window.location.assign(t)}catch{s("Could not start sign-in with this provider.")}})(o.id),children:t("span",{className:de,children:["Continue with ",o.name]})},o.id)),a&&e("p",{className:Z,children:a})]})},Ce=["passkey","magic_link","phone_otp"],Ae=()=>{const n=h(),{hasSignedInBefore:i,login:r,handlePasskeyLogin:a}=q(),s=we(),{passkeySupported:l}=Se(),[u,_]=d(""),[m,p]=d(""),[g,f]=d("register"),[y,b]=d(""),[k,v]=d(""),[w,x]=d(""),[P,S]=d(""),[N,O]=d(""),[T,C]=d(!1),[A,M]=d(Ce),[I,E]=d(null);c(()=>{i&&f("login");const e=new URLSearchParams(window.location.search).get("bootstrapToken");e&&e.length>10&&E(e)},[i]);return e("div",{className:D,children:t("div",{className:W,children:[e("h2",{className:V,children:"login"===g?"Sign In":"Create Account"}),t(o,{children:[t("form",{onSubmit:async e=>{e.preventDefault(),v(""),C(!1);try{if("login"===g){const e=await r(u,l),t=await(async e=>{if(!e||"function"!=typeof e.json)return null;try{return await e.json()}catch{return null}})(e),o=t?.loginMethods?.length?t.loginMethods:Ce;if(M(o),e?.ok&&l&&o.includes("passkey")){return await a()?void n("/"):(C(!0),void v("Passkey sign-in could not be completed. Choose another sign-in method."))}return e?.ok?void C(!0):void v("Failed to start sign-in. Please try again.")}"register"===g&&await(async()=>{v("");try{const e=await s.register({email:m,phone:y,bootstrapToken:I});if(!e.ok)return void v("Failed to register. Please try again.");if("Success"===(await e.json()).message)return void n("/verifyEmailOTP");v("An unexpected error occurred. Try again. If the problem persists, contact support.")}catch{console.error("Unexpected login error."),v("An unexpected error occurred. Try again. If the problem persists, contact support.")}})()}catch{console.error("Failed to continue sign-in."),v("Failed to continue sign-in. Please try again.")}},children:["login"===g&&t("div",{className:$,children:[e("label",{htmlFor:"identifier",className:K,children:"Email Address / Phone Number"}),e("input",{id:"identifier",type:"text",value:u,onChange:e=>{const t=e.target.value;_(t)},autoComplete:"off",placeholder:"Email or Phone Number",className:H,onBlur:()=>{if(u){const e=xe(u)||Pe(u);O(e?"":"Please enter a valid email or phone number")}},required:!0}),e("p",{className:Y,children:"Phone numbers must include a country code e.g. +1"}),T&&e(Ne,{identifier:u,onMagicLink:async()=>{try{if(!(await s.requestMagicLink()).ok)return void v("Failed to send magic link.");n("/magiclinks-sent",{state:{identifier:u}})}catch{console.error("Failed to send magic link."),v("Failed to send magic link.")}},onEmailOtp:async()=>{try{if(!(await s.requestLoginEmailOtp()).ok)return void v("Failed to send email code.");n("/verifyEmailOTP",{state:{flow:"login"}})}catch{console.error("Failed to send email OTP."),v("Failed to send email code.")}},onPhoneOtp:async()=>{try{if(!(await s.requestLoginPhoneOtp()).ok)return void v("Failed to send OTP.");n("/verifyPhoneOTP",{state:{flow:"login"}})}catch{console.error("Failed to send phone OTP."),v("Failed to send OTP.")}},onPasskeyRetry:l?a:void 0,loginMethods:A}),N&&e("p",{className:Z,children:N})]}),"register"===g&&t(o,{children:[t("div",{className:$,children:[e("label",{htmlFor:"email",className:K,children:"Email Address"}),e("input",{id:"email",type:"email",value:m,onChange:e=>{const t=e.target.value;p(t)},autoComplete:"off",className:H,onBlur:()=>{if(m){const e=xe(m);S(e?"":"Please enter a valid email")}},required:!0}),P&&e("p",{className:Z,children:P})]}),e(ve,{phone:y,setPhone:b,phoneError:w,setPhoneError:x})]}),e("button",{type:"submit",className:Q,disabled:!("login"===g&&u?xe(u)||Pe(u):xe(m)&&(!y||Pe(y))),children:"login"===g?"Login":"Register"}),k&&e("p",{className:Z,children:k}),e("button",{type:"button",onClick:()=>f("login"===g?"register":"login"),className:X,children:"login"===g?"Don't have an account? Create one":"Already have an account? Sign in"})]}),e(Te,{})]})]})})};var Me={container:"passKeyLogin-module__container___IUKxF",card:"passKeyLogin-module__card___2sKM1",title:"passKeyLogin-module__title___HZxvc",button:"passKeyLogin-module__button___FvR4I"};J(".passKeyLogin-module__container___IUKxF{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.passKeyLogin-module__card___2sKM1{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;flex-direction:column;gap:1.5rem;max-width:400px;padding:2rem;width:100%}.passKeyLogin-module__title___HZxvc{color:#fff;font-size:1.5rem;font-weight:600;text-align:center}.passKeyLogin-module__button___FvR4I{background-color:#2563eb;border:1px solid #3b82f6;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;text-align:center;transition:background-color .2s ease;width:100%}.passKeyLogin-module__button___FvR4I:hover{background-color:#1d4ed8}@media (max-width:480px){.passKeyLogin-module__card___2sKM1{padding:1.25rem}.passKeyLogin-module__button___FvR4I{font-size:1rem}}");const Ie=()=>{const o=h(),{handlePasskeyLogin:n}=q(),[i,r]=d("");return e("div",{className:Me.container,children:t("div",{className:Me.card,children:[e("h2",{className:Me.title,children:"Login with Passkey"}),e("button",{onClick:async()=>{r("");await n()?o("/"):r("Passkey sign-in could not be completed. Try another sign-in method.")},className:Me.button,children:"Use Passkey"}),i&&e("p",{className:Me.error,children:i})]})})};var Ee="registerPasskey-module__container___jqEh8",ze="registerPasskey-module__card___MJAyC",Le="registerPasskey-module__loading___Q4i1x",je="registerPasskey-module__spinner___V1nhd",Ue="registerPasskey-module__supported___ihTih",Fe="registerPasskey-module__title___vn2Qu",Be="registerPasskey-module__description___AWmO-",Re="registerPasskey-module__button___D3b4B",qe="registerPasskey-module__message___RiOw-",Ge="registerPasskey-module__success___HP5aX",Je="registerPasskey-module__error___hGiqE";J(".registerPasskey-module__container___jqEh8{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.registerPasskey-module__card___MJAyC{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);max-width:400px;padding:1.5rem;width:100%}.registerPasskey-module__loading___Q4i1x{align-items:center;background-color:#f9fafb;border-radius:.75rem;box-shadow:0 2px 8px rgba(0,0,0,.1);color:#374151;display:flex;font-weight:500;gap:.75rem;justify-content:center;padding:1.5rem}.registerPasskey-module__spinner___V1nhd{animation:registerPasskey-module__spin___oYcsC 1s linear infinite;border-color:#3b82f6 transparent;border-radius:9999px;border-style:solid;border-width:2px;height:1.5rem;width:1.5rem}@keyframes registerPasskey-module__spin___oYcsC{to{transform:rotate(1turn)}}.registerPasskey-module__supported___ihTih{background-color:#ecfdf5;border-radius:.75rem;box-shadow:0 2px 12px rgba(0,0,0,.1);color:#065f46;padding:1.25rem}.registerPasskey-module__title___vn2Qu{font-size:1.125rem;font-weight:600;margin-bottom:.5rem}.registerPasskey-module__description___AWmO-{margin-bottom:1rem}.registerPasskey-module__button___D3b4B{background-color:#059669;border:none;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;transition:background-color .2s ease;width:100%}.registerPasskey-module__button___D3b4B:hover{background-color:#047857}.registerPasskey-module__message___RiOw-{font-size:.875rem;margin-top:1rem}.registerPasskey-module__success___HP5aX{color:#6ee7b7}.registerPasskey-module__error___hGiqE{color:#f87171}");var De="deviceNameModal-module__overlay___fmdPd",We="deviceNameModal-module__modal___uoEda",Ve="deviceNameModal-module__description___-HMTA",$e="deviceNameModal-module__input___4vQMI",Ke="deviceNameModal-module__actions___KXw7b",He="deviceNameModal-module__primary___9Ozlk",Ye="deviceNameModal-module__secondary___HILhc";J(".deviceNameModal-module__overlay___fmdPd{align-items:center;background:rgba(0,0,0,.45);display:flex;inset:0;justify-content:center;position:fixed;z-index:1000}.deviceNameModal-module__modal___uoEda{background:#1f2937;border-radius:12px;box-shadow:0 20px 40px rgba(0,0,0,.15);color:#fff;max-width:420px;padding:24px;width:100%}.deviceNameModal-module__description___-HMTA{color:#fff;font-size:14px;margin-bottom:16px}.deviceNameModal-module__input___4vQMI{border:1px solid #ddd;border-radius:8px;font-size:14px;margin-bottom:20px;padding:10px 12px;width:100%}.deviceNameModal-module__actions___KXw7b{display:flex;gap:10px;justify-content:flex-end}.deviceNameModal-module__primary___9Ozlk{background:#2563eb;border:none;border-radius:8px;color:#fff;cursor:pointer;padding:8px 14px}.deviceNameModal-module__secondary___HILhc{background:transparent;border:1px solid #ccc;border-radius:8px;cursor:pointer;padding:8px 14px}");const Ze=({isOpen:o,onCancel:n,onConfirm:i})=>{const[r,a]=d("");return o?e("div",{className:De,children:t("div",{className:We,children:[e("h3",{children:"Name This Device"}),e("p",{className:Ve,children:"Give this passkey a friendly name so you can recognize it later."}),e("input",{type:"text",placeholder:"e.g., MacBook Pro, iPhone, YubiKey",value:r,onChange:e=>a(e.target.value),className:$e,autoFocus:!0}),t("div",{className:Ke,children:[e("button",{onClick:n,className:Ye,children:"Cancel"}),e("button",{onClick:()=>i(r.trim()),disabled:!r.trim(),className:He,children:"Continue"})]})]})}):null},Qe=()=>{const{refreshSession:n}=q(),i=we(),{passkeySupported:r,loading:a}=Se(),s=h(),[l,c]=d("idle"),[u,_]=d(""),[m,p]=d(!1),[g,f]=d(null);return t(o,{children:[e("div",{className:Ee,children:e("div",{className:ze,children:t("div",a||!r?{className:Le,children:[e("div",{className:je}),e("span",{children:a?"Checking for Passkey Support...":"Passkeys are not supported on this device."})]}:{className:Ue,children:[e("h2",{className:Fe,children:"Secure Your Account with a Passkey"}),e("p",{className:Be,children:"Your device supports passkeys! Register one to skip passwords forever."}),e("button",{onClick:()=>{const{platform:e,browser:t,deviceInfo:o}=function(){const e=navigator.userAgent.toLowerCase();let t="unknown",o="unknown";return/iphone|ipad|ipod/.test(e)?t="ios":/android/.test(e)?t="android":/mac os/.test(e)?t="mac":/windows/.test(e)?t="windows":/linux/.test(e)&&(t="linux"),/chrome/.test(e)&&(o="chrome"),/safari/.test(e)&&!/chrome/.test(e)&&(o="safari"),/firefox/.test(e)&&(o="firefox"),/edg/.test(e)&&(o="edge"),{platform:t,browser:o,deviceInfo:`${t} • ${o}`}}();f({platform:e,browser:t,deviceInfo:o}),p(!0)},disabled:"loading"===l,className:Re,children:"loading"===l?"Registering...":"Register Passkey"}),u&&e("p",{className:`${qe} ${"success"===l?Ge:Je}`,children:u})]})})}),e(Ze,{isOpen:m,onCancel:()=>{p(!1),f(null)},onConfirm:async e=>{if(!g)return;const t={friendlyName:e,...g};c("loading");try{const e=await i.registerPasskey(t);if(!e.success)throw new Error(e.message);await n(),c("success"),_(e.message),s("/")}catch{console.error("Passkey registration failed."),c("error"),_("Error registering passkey.")}finally{p(!1),f(null)}}})]})};var Xe="verifyOTP-module__container___wgoDE",et="verifyOTP-module__card___3cs2p",tt="verifyOTP-module__title___fZ-1d",ot="verifyOTP-module__subtitle___dGSu3",nt="verifyOTP-module__error___GEtlG",it="verifyOTP-module__success___46TjG",rt="verifyOTP-module__form___jiGG-",at="verifyOTP-module__label___Zq5Mi",st="verifyOTP-module__timer___smq-a",lt="verifyOTP-module__resend___PlmkG",dt="verifyOTP-module__button___8pIuO",ct="verifyOTP-module__toggle___wbzVa";J(".verifyOTP-module__container___wgoDE{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.verifyOTP-module__card___3cs2p{background-color:#1f2937;border-radius:.5rem;box-shadow:0 0 10px rgba(0,0,0,.3);max-width:28rem;padding:1.5rem;width:100%}.verifyOTP-module__title___fZ-1d{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1rem;text-align:center}.verifyOTP-module__subtitle___dGSu3{color:#9ca3af;font-size:.875rem;margin-bottom:1.5rem;text-align:center}.verifyOTP-module__error___GEtlG{color:#f87171;margin-bottom:1rem;text-align:center}.verifyOTP-module__success___46TjG{color:#34d399;margin-bottom:.75rem;text-align:center}.verifyOTP-module__form___jiGG-{display:flex;flex-direction:column;gap:1rem}.verifyOTP-module__label___Zq5Mi{color:#d1d5db;display:block;font-size:.875rem;margin-bottom:.25rem}.verifyOTP-module__timer___smq-a{color:#facc15;font-size:.875rem}.verifyOTP-module__input___yqIXM{background-color:#374151;border:1px solid #4b5563;border-radius:.375rem;color:#fff;outline:none;padding:.5rem;width:100%}.verifyOTP-module__input___yqIXM:focus{box-shadow:0 0 0 2px #3b82f6}.verifyOTP-module__resend___PlmkG{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.75rem;margin-top:.25rem;text-decoration:underline}.verifyOTP-module__resend___PlmkG:hover{color:#3b82f6}.verifyOTP-module__button___8pIuO{background-color:#2563eb;border:none;border-radius:.375rem;color:#fff;cursor:pointer;padding:.5rem;transition:background-color .2s;width:100%}.verifyOTP-module__button___8pIuO:hover{background-color:#1d4ed8}.verifyOTP-module__toggle___wbzVa{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.875rem;margin-top:1.5rem;text-align:center;width:100%}");var ut="otpInput-module__otpContainer___MUjby",_t="otpInput-module__otpInput___3YMVm";J(".otpInput-module__otpContainer___MUjby{display:flex;gap:8px;justify-content:center;margin-top:8px}.otpInput-module__otpInput___3YMVm{background:#374151;border:1px solid #4b5563;border-radius:8px;color:#fff;font-size:1.2rem;height:48px;text-align:center;transition:border-color .15s ease,box-shadow .15s ease;width:42px}.otpInput-module__otpInput___3YMVm:focus{border-color:#60a5fa;box-shadow:0 0 0 2px rgba(96,165,250,.25);outline:none}");const mt=({length:t=6,value:o,inputMode:n="numeric",onChange:i,name:r="otp"})=>{const a=g([]),s=o.split("").concat(Array(t).fill("")).slice(0,t),l=(e,t)=>{var o;if(t.length>1)d(e,t);else if(!t||(o=t,"numeric"===n?/^\d$/.test(o):/^[a-zA-Z]$/.test(o))){const o=[...s];o[e]=t;const n=o.join("");i(n),t&&a.current[e+1]&&a.current[e+1]?.focus()}},d=(e,o)=>{let r=o;r="numeric"===n?o.replace(/\D/g,""):o.replace(/[^a-zA-Z]/g,"");const l=r.slice(0,t).split(""),d=[...s];l.forEach((o,n)=>{e+n<t&&(d[e+n]=o)}),i(d.join("")),a.current[Math.min(e+l.length,t-1)]?.focus()};return e("div",{className:ut,role:"group","aria-label":"One-time password input",onPaste:e=>{e.preventDefault(),d(0,e.clipboardData.getData("text"))},children:s.map((o,d)=>e("input",{ref:e=>a.current[d]=e,type:"text",inputMode:"numeric"===n?"numeric":"text",autoComplete:"one-time-code",name:`${r}-${d}`,maxLength:1,value:o,className:_t,onChange:e=>l(d,e.target.value),onKeyDown:e=>((e,o)=>{if("Backspace"===o.key){o.preventDefault();const t=[...s];s[e]?(t[e]="",i(t.join(""))):e>0&&(t[e-1]="",i(t.join("")),a.current[e-1]?.focus())}"ArrowLeft"===o.key&&e>0&&a.current[e-1]?.focus(),"ArrowRight"===o.key&&e<t-1&&a.current[e+1]?.focus()})(d,e),"aria-label":`Digit ${d+1}`},d))})},pt=()=>{const o=h(),n=f(),{refreshSession:i}=q(),r="login"===n.state?.flow,[a,s]=d(""),[l,u]=d(null),[_,m]=d(""),[p,g]=d(!1),[y,b]=d(""),[k,v]=d(300),w=we(),x=async()=>{g(!0);try{if(!l){if((r?await w.verifyLoginPhoneOtp(a):await w.verifyPhoneOtp(a)).ok){if(r)return await i(),void o("/");u(!0)}else m("Verification failed.")}}catch{console.error("Phone OTP verification failed."),m("Verification failed.")}g(!1)},P=async()=>{b(""),await(async()=>{m(""),(r?await w.requestLoginPhoneOtp():await w.requestPhoneOtp()).ok?b("Verification SMS has been resent."):m("Failed to send SMS code. If this persists, refresh the page and try again.")})(),b("Verification SMS has been resent.")};return c(()=>{const e=setInterval(()=>{v(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),c(()=>{l&&!r&&(async()=>{(await w.requestEmailOtp()).ok?o("/verifyEmailOTP"):m("Failed to send Email code. If this persists, refresh the page and try registering again.")})()},[l,r,o,w]),e("div",{className:Xe,children:t("div",{className:et,children:[e("h2",{className:tt,children:"Verify Your Phone Number"}),e("p",{className:ot,children:"Enter the code sent to your phone number."}),_&&e("p",{className:nt,children:_}),y&&e("p",{className:it,children:y}),t("form",{onSubmit:async e=>{if(e.preventDefault(),m(""),6===a.length){g(!0);try{await x()}catch{m("Unexpected error occurred.")}finally{g(!1)}}else m("Please enter a valid code.")},className:rt,children:[t("div",{children:[t("label",{htmlFor:"phoneCode",className:at,children:["Phone Verification Code ",(N=l,!0===N?e("span",{className:"text-green-400 ml-2",children:"✅"}):!1===N?e("span",{className:"text-red-400 ml-2",children:"❌"}):null)," -"," ",t("span",{className:st,children:["Code expires in: ",(S=k,`${Math.floor(S/60).toString().padStart(2,"0")}:${(S%60).toString().padStart(2,"0")}`)]})]}),e(mt,{length:6,value:a,onChange:s}),e("button",{type:"button",onClick:()=>P(),className:lt,children:"Resend code to phone"})]}),e("button",{type:"submit",className:dt,children:p?"Verifying...":"Verify & Continue"}),e("button",{type:"button",onClick:()=>o("/login"),className:ct,children:"Back to login"})]})]})});var S,N},gt=()=>{const o=h(),n=f(),{refreshSession:i}=q(),r=we(),{passkeySupported:a}=Se(),s="login"===n.state?.flow,[l,u]=d(!1),[_,m]=d(""),[p,g]=d(300),[y,b]=d(""),[k,v]=d("");return c(()=>{const e=setInterval(()=>{g(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),e("div",{className:Xe,children:t("div",{className:et,children:[e("h2",{className:tt,children:"Verify Your Email"}),e("p",{className:ot,children:"We sent you a verification email. Enter the code below."}),y&&e("p",{className:nt,children:y}),k&&e("p",{className:it,children:k}),t("form",{onSubmit:async e=>{if(e.preventDefault(),b(""),6===_.length){u(!0);try{if(!(s?await r.verifyLoginEmailOtp(_):await r.verifyEmailOtp(_)).ok)return void b("Verification failed.");if(s)return await i(),void o("/");a?o("/registerPasskey"):(await i(),o("/"))}catch{console.error("Email OTP verification failed."),b("Verification failed.")}finally{u(!1)}}else b("Please enter a valid code.")},className:rt,children:[t("div",{children:[t("label",{htmlFor:"emailCode",className:at,children:["Email Verification Code",t("span",{className:st,children:[" ","— Code expires in ",(w=p,`${Math.floor(w/60).toString().padStart(2,"0")}:${(w%60).toString().padStart(2,"0")}`)]})]}),e(mt,{length:6,value:_,onChange:m,inputMode:"text"}),e("button",{type:"button",onClick:async()=>{b(""),v("");(s?await r.requestLoginEmailOtp():await r.requestEmailOtp()).ok?v("Verification email has been resent."):b("Failed to send Email code. If this persists, refresh the page and try again.")},className:lt,children:"Resend code to email"})]}),e("button",{type:"submit",className:dt,disabled:l,children:l?"Verifying...":"Verify & Continue"}),e("button",{type:"button",onClick:()=>o("/login"),className:ct,children:"Back to login"})]})]})});var w};var ht={container:"verifyMagiclink-module__container___qrSXf",card:"verifyMagiclink-module__card___niKgr",title:"verifyMagiclink-module__title___SumxD",verificationContent:"verifyMagiclink-module__verificationContent___NdsS0",spinner:"verifyMagiclink-module__spinner___lnW1k",successIcon:"verifyMagiclink-module__successIcon___XjFEM",checkIcon:"verifyMagiclink-module__checkIcon___I0JOP",successText:"verifyMagiclink-module__successText___lO5Qq"};J(".verifyMagiclink-module__container___qrSXf{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.verifyMagiclink-module__card___niKgr{background-color:#1f2937;border-radius:.5rem;box-shadow:0 0 10px rgba(0,0,0,.3);max-width:28rem;padding:1.5rem;width:100%}.verifyMagiclink-module__title___SumxD{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1rem;text-align:center}.verifyMagiclink-module__verificationContent___NdsS0{align-items:center;display:flex;flex-direction:column;gap:14px;margin:20px 0}.verifyMagiclink-module__spinner___lnW1k{animation:verifyMagiclink-module__spin___2lGzj .9s linear infinite;border:3px solid hsla(0,0%,100%,.15);border-radius:50%;border-top-color:#60a5fa;height:28px;width:28px}.verifyMagiclink-module__successIcon___XjFEM{align-items:center;background:rgba(16,185,129,.15);border-radius:50%;display:flex;height:36px;justify-content:center;width:36px}.verifyMagiclink-module__checkIcon___I0JOP{animation:verifyMagiclink-module__checkPop___-3qJu .25s ease-out;color:#34d399;height:22px;width:22px}.verifyMagiclink-module__successText___lO5Qq{color:#34d399;font-size:.9rem}@keyframes verifyMagiclink-module__checkPop___-3qJu{0%{opacity:0;transform:scale(.6)}80%{transform:scale(1.15)}to{opacity:1;transform:scale(1)}}@keyframes verifyMagiclink-module__spin___2lGzj{to{transform:rotate(1turn)}}");const ft=()=>{const[o]=y(),n=h(),i=o.get("token"),[r,a]=d(""),[s,l]=d(""),u=we();return c(()=>{let e=!0,t=null,o=null;return(async()=>{if(!i)return e&&a("Missing token for verification."),void console.error("No magic-link token found.");try{if(!(await u.verifyMagicLink(i)).ok)return console.error("Failed to verify token"),void(e&&a("Failed to verify token"))}catch{console.error("Failed to verify magic-link token.")}e&&(t=new BroadcastChannel("seamless-auth"),t.postMessage({type:"MAGIC_LINK_AUTH_SUCCESS"}),l("You have been verified on the device and browser that initiated this request"),o=setTimeout(()=>{e&&n("/")},900))})(),()=>{e=!1,t?.close(),o&&clearTimeout(o)}},[i,u,n]),e("div",{className:ht.container,children:t("div",{className:ht.card,children:[e("h1",{className:ht.title,children:"Verifying your login"}),t("div",{className:ht.verificationContent,children:[!s&&!r&&e("div",{className:ht.spinner}),s&&e("div",{className:ht.successIcon,children:e("svg",{viewBox:"0 0 24 24",className:ht.checkIcon,fill:"none",stroke:"currentColor",strokeWidth:"2",children:e("path",{d:"M5 13l4 4L19 7"})})}),!s&&!r&&e("p",{className:ht.helperText,children:"Please wait while we securely verify your sign-in link."}),s&&e("p",{className:ht.successText,children:"Login verified. Redirecting…"}),r&&e("p",{className:ht.error,children:r})]})]})})},yt=()=>{const{finishOAuthLogin:n}=q(),i=h(),[r]=y(),[a,s]=d(""),l=g(!1);return c(()=>{if(l.current)return;l.current=!0;const e=r.get("code"),t=r.get("state"),o=sessionStorage.getItem(Oe);e&&t&&o?n({providerId:o,code:e,state:t}).then(()=>{sessionStorage.removeItem(Oe),i("/")}).catch(()=>{s("We could not complete sign-in. Please try again.")}):s("This sign-in link is missing required information.")},[n,i,r]),t("div",{className:ht.container,children:[e("h2",{className:ht.title,children:a?"Sign-in failed":"Completing sign-in..."}),a&&t(o,{children:[e("p",{children:a}),e("button",{type:"button",onClick:()=>i("/login"),children:"Back to login"})]})]})};var bt="magiclink-module__container___45zcA",kt="magiclink-module__card___Au9oN",vt="magiclink-module__iconWrapper___k5ndr",wt="magiclink-module__mailIcon___Pwb7q",xt="magiclink-module__iconRing___bdLvf",Pt="magiclink-module__heading___b9cre",St="magiclink-module__message___kiVFj",Nt="magiclink-module__identifier___JtcFM",Ot="magiclink-module__helperText___7Mlfh",Tt="magiclink-module__actions___64I-3",Ct="magiclink-module__secondaryButton___BntAI",At="magiclink-module__cooldown___Ib4rm",Mt="magiclink-module__linkButton___maJiv";J(".magiclink-module__container___45zcA{align-items:center;color:#fff;display:flex;justify-content:center}.magiclink-module__card___Au9oN{background-color:#1f2937;border-radius:.75rem;box-shadow:0 10px 25px rgba(0,0,0,.25);max-width:420px;padding:2.5rem 2rem;text-align:center;width:100%}.magiclink-module__iconWrapper___k5ndr{display:flex;justify-content:center;margin-bottom:1.25rem;position:relative}.magiclink-module__mailIcon___Pwb7q{color:#a5b4fc;height:38px;width:38px;z-index:2}.magiclink-module__iconRing___bdLvf{animation:magiclink-module__pulse___YGm-I 2s infinite;background:rgba(99,102,241,.15);border-radius:50%;height:72px;position:absolute;width:72px}@keyframes magiclink-module__pulse___YGm-I{0%{opacity:.8;transform:scale(.6)}70%{opacity:0;transform:scale(1.4)}to{opacity:0}}.magiclink-module__heading___b9cre{font-size:1.55rem;font-weight:600;margin-bottom:.75rem}.magiclink-module__message___kiVFj{color:#d1d5db;font-size:.95rem;line-height:1.4;margin-bottom:1rem}.magiclink-module__identifier___JtcFM{background:hsla(0,0%,100%,.05);border-radius:6px;display:inline-block;font-size:1rem;font-weight:600;margin-bottom:1rem;padding:.45rem .6rem}.magiclink-module__helperText___7Mlfh{color:#9ca3af;font-size:.85rem;line-height:1.4;margin-bottom:.6rem}.magiclink-module__actions___64I-3{display:flex;flex-direction:column;gap:.6rem;margin-top:1.6rem}.magiclink-module__secondaryButton___BntAI{background:#111827;border:1px solid #374151;border-radius:8px;color:#fff;cursor:pointer;font-weight:500;padding:.65rem}.magiclink-module__secondaryButton___BntAI:hover:not(:disabled){background:#1f2937}.magiclink-module__secondaryButton___BntAI:disabled{cursor:not-allowed;opacity:.5}.magiclink-module__cooldown___Ib4rm{color:#9ca3af;font-size:.8rem}.magiclink-module__linkButton___maJiv{background:none;border:none;color:#a5b4fc;cursor:pointer;font-size:.85rem;margin-top:.4rem}.magiclink-module__linkButton___maJiv:hover{text-decoration:underline}");const It=()=>{const{refreshSession:o}=q(),n=h(),i=f(),r=we(),a=i.state?.identifier,[s,l]=d(30);c(()=>{const e=setInterval(()=>{l(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]);return c(()=>{const e=new BroadcastChannel("seamless-auth");return e.onmessage=async e=>{if("MAGIC_LINK_AUTH_SUCCESS"===e.data?.type){200===(await r.checkMagicLink()).status&&(await o(),n("/"))}},()=>{e.close()}},[r,n,o]),c(()=>{const e=setInterval(async()=>{try{200===(await r.checkMagicLink()).status&&(await o(),n("/"))}catch{}},5e3);return()=>clearInterval(e)},[r,o,n]),e("div",{className:bt,children:t("div",{className:kt,children:[t("div",{className:vt,children:[e("div",{className:xt}),t("svg",{className:wt,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.8",children:[e("path",{d:"M4 6h16v12H4z"}),e("path",{d:"m4 6 8 6 8-6"})]})]}),e("h2",{className:Pt,children:"Check your email"}),e("p",{className:St,children:"If an account exists for this address, we sent a secure sign-in link."}),a&&e("div",{className:Nt,children:a}),e("p",{className:Ot,children:"Open the email and click the link to finish signing in."}),e("p",{className:Ot,children:"Didn’t receive anything? Check your spam folder or try creating a new account."}),t("div",{className:Tt,children:[e("button",{className:Ct,disabled:s>0,onClick:async()=>{s>0||(await r.requestMagicLink(),l(30))},children:"Resend link"}),s>0&&t("div",{className:At,children:["Available in ",s,"s"]}),e("button",{className:Mt,onClick:()=>n("/login"),children:"Change email or phone"})]})]})})},Et=()=>t(b,{children:[e(k,{path:"/login",element:e(Ae,{})}),e(k,{path:"/passKeyLogin",element:e(Ie,{})}),e(k,{path:"/verifyPhoneOTP",element:e(pt,{})}),e(k,{path:"/verifyEmailOTP",element:e(gt,{})}),e(k,{path:"/verify-magiclink",element:e(ft,{})}),e(k,{path:"/oauth/callback",element:e(yt,{})}),e(k,{path:"/registerPasskey",element:e(Qe,{})}),e(k,{path:"/magiclinks-sent",element:e(It,{})}),e(k,{path:"*",element:e(v,{to:"/login",replace:!0})})]});export{G as AuthProvider,Et as AuthRoutes,U as createSeamlessAuthClient,N as encodePrfSalt,M as extractPasskeyPrfResult,B as hasScopedRole,C as isPasskeyPrfSupported,F as roleGrantsAccess,q as useAuth,we as useAuthClient,Se as usePasskeySupport};
|
|
1
|
+
import{jsx as e,jsxs as t,Fragment as i}from"react/jsx-runtime";import{browserSupportsWebAuthn as o,bufferToBase64URLString as r,base64URLStringToBuffer as n,startAuthentication as a,startRegistration as s,WebAuthnError as l}from"@simplewebauthn/browser";import{useState as d,useEffect as c,createContext as u,useMemo as _,useCallback as m,useContext as g,useRef as p}from"react";import{useHref as f,useNavigate as h,useLocation as y,useSearchParams as b,Routes as v,Route as k,Navigate as w}from"react-router-dom";import x from"libphonenumber-js";class P extends Error{constructor(e,t,i){super(e),this.name="SeamlessAuthError",this.status=t,this.body=i}}async function S(e,t){let i;try{i=await e.json()}catch{i=void 0}return new P(function(e){if("object"!=typeof e||null===e)return;const{error:t,message:i}=e;return"string"==typeof t&&t?t:"string"==typeof i&&i?i:void 0}(i)??t,e.status,i)}async function N(e){try{return await e.json()}catch{return}}async function O(e,t){let i;try{i=await e}catch{return{data:null,error:new P(t,0)}}return i.ok?{data:await N(i),error:null}:{data:null,error:await S(i,t)}}function T(e){return{data:e,error:null}}function C(e,t=0,i){return{data:null,error:new P(e,t,i)}}function I(e){if(e instanceof ArrayBuffer)return e;const t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),i=new Uint8Array(t.byteLength);return i.set(t),i.buffer}function M(e){return"string"==typeof e?e:r(I(e))}function A(e){return"string"==typeof e?n(e):e}function z(e){return{...e.credentialId?{credentialId:e.credentialId}:{},prf:{salt:M(e.salt),...e.secondSalt?{secondSalt:M(e.secondSalt)}:{}}}}async function E(){return!!o()&&("undefined"==typeof window||!1!==window.isSecureContext)&&void 0!==globalThis.PublicKeyCredential&&"undefined"!=typeof navigator&&"function"==typeof navigator.credentials?.get}function F(e){const t=e,i=t.extensions?.prf?.eval;return i?{...t,extensions:{...t.extensions,prf:{...t.extensions?.prf,eval:{...i,...i.first?{first:A(i.first)}:{},...i.second?{second:A(i.second)}:{}}}}}:e}function L(e){const t=e.clientExtensionResults,i=t?.prf?.results?.first;if(!i)return null;const o=(n=i)instanceof ArrayBuffer?new Uint8Array(n):new Uint8Array(n.buffer,n.byteOffset,n.byteLength);var n;return{credentialId:e.id,output:o,outputBase64url:r(I(o))}}function U(e){const t=e.clientExtensionResults;return t?.prf?.results?{...e,clientExtensionResults:{...e.clientExtensionResults,prf:{...t.prf,results:void 0}}}:e}function R(e,t){const i=e.method===t?e.method:null;return"Success"===e.message&&!0===e.fresh&&null!==i?T({fresh:!0,method:i,verifiedAt:e.verifiedAt??null,expiresAt:e.expiresAt??null,maxAgeSeconds:e.maxAgeSeconds??0}):C(e.message??"Step-up authentication failed.")}function B(e){return e?{method:"POST",body:JSON.stringify(z(e))}:{method:"POST"}}const q=e=>{const t=(e=>{const{authHost:t}=e;return async function(e,i){const o=`${t?.replace(/\/+$/,"")??""}/auth${e.startsWith("/")?e:`/${e}`}`,r=null!=i?.body,n={...i,credentials:"include",headers:{...r?{"Content-Type":"application/json"}:{},...i?.headers}};return fetch(o,n)}})({authHost:e.apiHost});return{getCurrentUser:()=>O(t("users/me",{method:"GET"}),"Failed to load the current user."),login:e=>O(t("/login",{method:"POST",body:JSON.stringify(e)}),"Failed to start sign-in."),loginWithPasskey:async e=>{const i=await O(t("/webAuthn/login/start",{...B(e?.prf)}),"Failed to start passkey login.");if(i.error)return i;let o,r;try{const e=await a({optionsJSON:F(i.data)});o=L(e),r=U(e)}catch{return console.error("Passkey login error."),C("Passkey login failed.")}const n=await O(t("/webAuthn/login/finish",{method:"POST",body:JSON.stringify({assertionResponse:r})}),"Failed to verify passkey.");return n.error?n:"Success"!==n.data?.message?C(n.data?.message??"Passkey login failed."):T(o?{prf:o}:{})},logout:(e={})=>O(t("all_sessions"===e.scope?"/logout/all":"/logout",{method:"DELETE"}),"Failed to sign out."),logoutAllSessions:()=>O(t("/logout/all",{method:"DELETE"}),"Failed to sign out of all sessions."),deleteUser:()=>O(t("/users/delete",{method:"DELETE"}),"Failed to delete the account."),register:e=>O(t("/registration/register",{method:"POST",body:JSON.stringify({email:e.email,...e.phone?{phone:e.phone}:{}})}),"Failed to register."),requestPhoneOtp:()=>O(t("/otp/generate-phone-otp",{method:"POST",body:JSON.stringify({})}),"Failed to send the SMS code."),verifyPhoneOtp:e=>O(t("/otp/verify-phone-otp",{method:"POST",body:JSON.stringify({verificationToken:e})}),"Failed to verify the SMS code."),requestLoginPhoneOtp:()=>O(t("/otp/generate-login-phone-otp",{method:"POST",body:JSON.stringify({})}),"Failed to send the SMS code."),verifyLoginPhoneOtp:e=>O(t("/otp/verify-login-phone-otp",{method:"POST",body:JSON.stringify({verificationToken:e})}),"Failed to verify the SMS code."),requestEmailOtp:()=>O(t("/otp/generate-email-otp",{method:"POST",body:JSON.stringify({})}),"Failed to send the email code."),verifyEmailOtp:e=>O(t("/otp/verify-email-otp",{method:"POST",body:JSON.stringify({verificationToken:e})}),"Failed to verify the email code."),requestLoginEmailOtp:()=>O(t("/otp/generate-login-email-otp",{method:"POST",body:JSON.stringify({})}),"Failed to send the email code."),verifyLoginEmailOtp:e=>O(t("/otp/verify-login-email-otp",{method:"POST",body:JSON.stringify({verificationToken:e})}),"Failed to verify the email code."),requestMagicLink:()=>O(t("/magic-link",{method:"POST",body:JSON.stringify({})}),"Failed to send the magic link."),checkMagicLink:()=>O(t("/magic-link/check",{method:"GET"}),"Failed to check the magic link."),verifyMagicLink:e=>O(t(`/magic-link/verify/${encodeURIComponent(e)}`,{method:"GET"}),"Failed to verify the magic link."),listOAuthProviders:()=>O(t("/oauth/providers",{method:"GET"}),"Failed to list OAuth providers."),startOAuthLogin:e=>O(t(`/oauth/${encodeURIComponent(e.providerId)}/start`,{method:"POST",body:JSON.stringify({...e.redirectUri?{redirectUri:e.redirectUri}:{},...e.returnTo?{returnTo:e.returnTo}:{}})}),"Failed to start OAuth login."),finishOAuthLogin:e=>O(t(`/oauth/${encodeURIComponent(e.providerId)}/callback`,{method:"POST",body:JSON.stringify({code:e.code,state:e.state})}),"Failed to finish OAuth login."),registerPasskey:async e=>{const i=function(e){return"metadata"in e?e:{metadata:e}}(e),o=await O(t(function(e){const t=new URLSearchParams;e.requirePrf?t.set("requirePrf","true"):e.requestPrf&&t.set("requestPrf","true");const i=t.toString();return"/webAuthn/register/start"+(i?`?${i}`:"")}(i),{method:"GET"}),"Failed to fetch passkey registration challenge.");if(o.error)return o;let r;try{r=await s({optionsJSON:o.data})}catch(e){return e instanceof l?C(e.name):(console.error("Passkey registration error."),C("Passkey registration failed."))}const n=function(e){const t=e.clientExtensionResults;return!0===t?.prf?.enabled}(r),a=await O(t("/webAuthn/register/finish",{method:"POST",body:JSON.stringify({attestationResponse:r,metadata:{...i.metadata,prfCapable:n}})}),"Verification failed.");return a.error?a:T({credentialId:r.id,prfCapable:n})},isPasskeyPrfSupported:E,getStepUpStatus:()=>O(t("/step-up/status",{method:"GET"}),"Failed to load step-up status."),verifyStepUpWithPasskey:async()=>{const e=await O(t("/step-up/webauthn/start",{method:"POST"}),"Failed to start step-up authentication.");if(e.error)return e;let i;try{i=U(await a({optionsJSON:F(e.data)}))}catch{return console.error("Step-up authentication error."),C("Step-up authentication failed.")}const o=await O(t("/step-up/webauthn/finish",{method:"POST",body:JSON.stringify({assertionResponse:i})}),"Failed to verify step-up authentication.");return o.error?o:R(o.data??{},"webauthn")},verifyStepUpWithPasskeyPrf:async e=>{const i=await O(t("/step-up/webauthn/start",{...B(e)}),"Failed to start step-up authentication.");if(i.error)return i;let o,r;try{const e=await a({optionsJSON:F(i.data)});o=L(e),r=U(e)}catch{return console.error("Step-up authentication error."),C("Step-up authentication failed.")}if(!o)return C("Passkey did not return PRF output.");const n=await O(t("/step-up/webauthn/finish",{method:"POST",body:JSON.stringify({assertionResponse:r})}),"Failed to verify step-up authentication.");if(n.error)return n;const s=R(n.data??{},"webauthn");return s.error?s:T({...s.data,credentialId:o.credentialId,prf:o})},getTotpStatus:()=>O(t("/totp/status",{method:"GET"}),"Failed to load authenticator status."),startTotpEnrollment:()=>O(t("/totp/enroll/start",{method:"POST"}),"Failed to start authenticator enrollment."),verifyTotpEnrollment:e=>O(t("/totp/enroll/verify",{method:"POST",body:JSON.stringify({code:e})}),"Failed to verify the authenticator code."),disableTotp:e=>O(t("/totp/disable",{method:"POST",body:JSON.stringify({code:e})}),"Failed to disable the authenticator."),verifyStepUpWithTotp:async e=>{const i=await O(t("/totp/verify-mfa",{method:"POST",body:JSON.stringify({code:e})}),"Failed to verify step-up authentication.");return i.error?i:R(i.data??{},"totp")},updateCredential:e=>O(t("users/credentials",{method:"POST",body:JSON.stringify(e)}),"Failed to update credential."),deleteCredential:e=>O(t("users/credentials",{method:"DELETE",body:JSON.stringify({id:e})}),"Failed to delete credential."),listOrganizations:()=>O(t("/organizations",{method:"GET"}),"Failed to list organizations."),createOrganization:e=>O(t("/organizations",{method:"POST",body:JSON.stringify(e)}),"Failed to create organization."),getOrganization:e=>O(t(`/organizations/${encodeURIComponent(e)}`,{method:"GET"}),"Failed to load organization."),updateOrganization:(e,i)=>O(t(`/organizations/${encodeURIComponent(e)}`,{method:"PATCH",body:JSON.stringify(i)}),"Failed to update organization."),switchOrganization:e=>O(t(`/organizations/${encodeURIComponent(e)}/switch`,{method:"POST"}),"Failed to switch organization."),listOrganizationMembers:e=>O(t(`/organizations/${encodeURIComponent(e)}/members`,{method:"GET"}),"Failed to list organization members."),addOrganizationMember:(e,i)=>O(t(`/organizations/${encodeURIComponent(e)}/members`,{method:"POST",body:JSON.stringify(i)}),"Failed to add organization member."),updateOrganizationMember:(e,i,o)=>O(t(`/organizations/${encodeURIComponent(e)}/members/${encodeURIComponent(i)}`,{method:"PATCH",body:JSON.stringify(o)}),"Failed to update organization member."),removeOrganizationMember:(e,i)=>O(t(`/organizations/${encodeURIComponent(e)}/members/${encodeURIComponent(i)}`,{method:"DELETE"}),"Failed to remove organization member.")}};function J(e,t){const i=e.trim(),o=t.trim();if(!i||!o)return!1;if(i===o)return!0;if(i.endsWith(":*")){const e=i.slice(0,-2);return o===e||o.startsWith(`${e}:`)}if(!o.includes(":"))return!1;if(!i.includes(":"))return o.startsWith(`${i}:`);const r=i.split(":"),n=o.split(":"),a=r[r.length-1],s=n[n.length-1],l=r.slice(0,-1),d=n.slice(0,-1);return"write"===a&&"read"===s&&l.length===d.length&&l.every((e,t)=>e===d[t])}function G(e,t){if(!Array.isArray(e))return!1;const i=e.filter(e=>"string"==typeof e);return(Array.isArray(t)?t:[t]).some(e=>i.some(t=>J(t,e)))}const j=u(void 0),W=()=>{const e=g(j);if(!e)throw new Error("useAuth must be used within an AuthProvider");return e},D=({children:t,apiHost:i,autoDetectPreviousSignin:o=!0})=>{const[r,n]=d(null),[a,s]=d([]),[l,u]=d([]),[g,p]=d(null),[f,h]=d(null),[y,b]=d(!1),[v,k]=d(!0),{hasSignedInBefore:w,markSignedIn:x}=function(e="seamlessauth_seen"){const[t,i]=d(!1);return c(()=>{try{"true"===localStorage.getItem(e)&&i(!0)}catch{}},[e]),{hasSignedInBefore:t,markSignedIn:()=>{try{localStorage.setItem(e,"true"),i(!0)}catch{}}}}(),P=_(()=>q({apiHost:i}),[i]),S=m(()=>{b(!1),n(null),s([]),u([]),p(null),h(null)},[]),N=m(async()=>{try{return await P.logout()}finally{S()}},[P,S]),O=m(async()=>{try{return await P.logoutAllSessions()}finally{S()}},[P,S]),T=m(async()=>{k(!0);const e=await P.getCurrentUser();return e.error?(await N(),k(!1),e):(n(e.data.user),s(e.data.credentials??[]),u(e.data.organizations??[]),p(e.data.activeOrganization??null),b(!0),k(!1),e)},[P,N]),C=m(async()=>{const e=await P.getStepUpStatus();return h(e.error?null:e.data),e},[P]),I=m(async()=>{const e=await P.verifyStepUpWithPasskey();return e.error||h(e.data),e},[P]),M=m(async e=>{const t=await P.verifyStepUpWithPasskeyPrf(e);return t.error||h({fresh:t.data.fresh,method:t.data.method,verifiedAt:t.data.verifiedAt,expiresAt:t.data.expiresAt,maxAgeSeconds:t.data.maxAgeSeconds}),t},[P]),A=m(async e=>{const t=await P.verifyStepUpWithTotp(e);return t.error||h(t.data),t},[P]);return c(()=>{T()},[T]),c(()=>{r&&y&&x()},[r,y,x]),e(j.Provider,{value:{user:r,logout:N,logoutAllSessions:O,refreshSession:T,loading:v,deleteUser:async()=>{const e=await P.deleteUser();return e.error||S(),e},isAuthenticated:y,hasRole:e=>r?.roles?.includes(e),hasScopedRole:e=>r?G(r.roles,e):void 0,apiHost:i,markSignedIn:x,hasSignedInBefore:!!o&&w,credentials:a,organizations:l,activeOrganization:g,switchOrganization:async e=>{const t=await P.switchOrganization(e);return t.error||await T(),t},listOAuthProviders:()=>P.listOAuthProviders(),startOAuthLogin:e=>P.startOAuthLogin(e),finishOAuthLogin:async e=>{const t=await P.finishOAuthLogin(e);return t.error||await T(),t},stepUpStatus:f,updateCredential:async e=>{const{data:t,error:i}=await P.updateCredential({friendlyName:e.friendlyName,id:e.id});if(i)return{data:null,error:i};const o=t.credential;return s(e=>e.map(e=>e.id===o.id?{...e,...o}:e)),{data:o,error:null}},deleteCredential:async e=>{const t=await P.deleteCredential(e);return t.error||s(t=>t.filter(t=>t.id!==e)),t},login:(e,t)=>P.login({identifier:e,passkeyAvailable:t}),handlePasskeyLogin:async()=>{const e=await P.loginWithPasskey();return e.error||await T(),e},refreshStepUpStatus:C,verifyStepUpWithPasskey:I,verifyStepUpWithPasskeyPrf:M,verifyStepUpWithTotp:A},children:t})},$=()=>{const{apiHost:e}=W();return _(()=>q({apiHost:e}),[e])},V=e=>{if("string"!=typeof e)return!1;const t=e.trim();if(t.length<3||t.length>320)return!1;const i=t.split("@");if(2!==i.length)return!1;const[o,r]=i;return!(!/^[A-Za-z0-9._%+-]+$/.test(o)||o.startsWith(".")||o.endsWith(".")||o.includes(".."))&&!(!/^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/.test(r)||r.startsWith("-")||r.endsWith("-")||r.startsWith(".")||r.endsWith(".")||r.includes(".."))},K=e=>{const t=x(e);return t?.isValid()||!1};async function H(){return async function(){if("undefined"==typeof window)return!1;if(window.PublicKeyCredential&&"function"==typeof window.PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable)try{return await PublicKeyCredential.isUserVerifyingPlatformAuthenticatorAvailable()}catch{return console.error("Error checking passkey support."),!1}return!1}()}const Y=()=>{const[e,t]=d(!1),[i,o]=d(!0);return c(()=>{let e=!0;return(async()=>{try{const i=await H();e&&t(i)}catch{e&&t(!1)}finally{e&&o(!1)}})(),()=>{e=!1}},[]),{passkeySupported:e,loading:i}},Q="/login",Z="/passkey-login",X="/verify-phone-otp",ee="/verify-email-otp",te="/verify-magiclink",ie="/oauth/callback",oe="/register-passkey",re="/magic-link-sent";function ne(e,t){void 0===t&&(t={});var i=t.insertAt;if(e&&"undefined"!=typeof document){var o=document.head||document.getElementsByTagName("head")[0],r=document.createElement("style");r.type="text/css","top"===i&&o.firstChild?o.insertBefore(r,o.firstChild):o.appendChild(r),r.styleSheet?r.styleSheet.cssText=e:r.appendChild(document.createTextNode(e))}}var ae="login-module__container___YggDx",se="login-module__card___Ub-Py",le="login-module__heading___neEqb",de="login-module__inputGroup___P6qgS",ce="login-module__label___mx5vu",ue="login-module__input___U07lW",_e="login-module__helperText___kDQ4-",me="login-module__error___40zxh",ge="login-module__button___0kFBs",pe="login-module__toggle___1JiG1",fe="login-module__fallbackCard___HdIk-",he="login-module__fallbackHeader___-il2v",ye="login-module__fallbackDescription___ea5EB",be="login-module__fallbackActions___AD3ni",ve="login-module__fallbackActionButton___lFgWf",ke="login-module__actionTitle___ycrMp",we="login-module__actionSubtext___opaIV",xe="login-module__linkButton___5lsoe";ne(".login-module__container___YggDx{align-items:center;color:#fff;display:flex;justify-content:center}.login-module__card___Ub-Py{background-color:#1f2937;border-radius:.5rem;box-shadow:0 4px 6px rgba(0,0,0,.1);max-width:28rem;padding:2rem;width:100%}.login-module__heading___neEqb{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1.5rem;text-align:center}.login-module__message___qSejT{color:#68d391;text-align:center}.login-module__inputGroup___P6qgS{margin-bottom:1rem}.login-module__label___mx5vu{color:#d1d5db;display:block}.login-module__input___U07lW{background-color:#4b5563;border:1px solid #d1d5db;border-radius:.375rem;margin-top:.25rem;padding:.5rem;width:100%}.login-module__input___U07lW:focus{box-shadow:0 0 0 2px #3b82f6;outline:none}.login-module__helperText___kDQ4-{color:#9ca3af;font-size:.75rem;margin-top:.5rem}.login-module__error___40zxh{color:#f87171;font-size:.875rem}.login-module__button___0kFBs{background-color:#2563eb;border-radius:.375rem;color:#fff;cursor:pointer;margin-top:1rem;padding:.5rem;transition:background-color .3s;width:100%}.login-module__button___0kFBs:hover{background-color:#1d4ed8}.login-module__button___0kFBs:disabled{background-color:#9ca3af;cursor:not-allowed}.login-module__toggle___1JiG1{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.875rem;margin-top:1.5rem;text-align:center;width:100%}.login-module__underline___gs-RS{text-decoration:underline}.login-module__phoneRow___oeNtq{display:grid;gap:.5rem;grid-template-columns:1fr 3fr;margin-top:.25rem}.login-module__phoneInput___2MPQC,.login-module__select___rRV1O{background-color:#4b5563;border:1px solid #d1d5db;border-radius:.375rem;padding:.5rem;width:100%}@media (max-width:500px){.login-module__phoneRow___oeNtq{grid-template-columns:1fr}}.login-module__fallbackCard___HdIk-{background:hsla(0,0%,100%,.04);border:1px solid hsla(0,0%,100%,.08);border-radius:12px;display:flex;flex-direction:column;gap:14px;margin-top:18px;padding:18px}.login-module__fallbackHeader___-il2v{color:#f3f4f6;font-size:.95rem;font-weight:600}.login-module__fallbackDescription___ea5EB{color:#9ca3af;font-size:.85rem;line-height:1.4}.login-module__fallbackActions___AD3ni{display:flex;flex-direction:column;gap:10px}.login-module__fallbackActionButton___lFgWf{background:rgba(0,0,0,.25);border:1px solid hsla(0,0%,100%,.08);border-radius:8px;cursor:pointer;display:flex;flex-direction:column;padding:12px 14px;text-align:left;transition:all .15s ease}.login-module__fallbackActionButton___lFgWf:hover{background:hsla(0,0%,100%,.06);border-color:hsla(0,0%,100%,.15)}.login-module__actionTitle___ycrMp{color:#f9fafb;font-size:.9rem;font-weight:500}.login-module__actionSubtext___opaIV{color:#9ca3af;font-size:.75rem;margin-top:2px}.login-module__linkButton___5lsoe{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.8rem;margin-top:6px}.login-module__linkButton___5lsoe:hover{text-decoration:underline}");const Pe=({identifier:i,onMagicLink:o,onEmailOtp:r,onPhoneOtp:n,onPasskeyRetry:a,loginMethods:s})=>{const l=new Set(s??["passkey","magic_link","phone_otp"]),d=l.has("magic_link")&&V(i),c=l.has("email_otp")&&Boolean(r)&&V(i),u=l.has("phone_otp")&&K(i),_=l.has("passkey")&&Boolean(a);return d||c||u||_?t("div",{className:fe,children:[e("div",{className:he,children:"Choose a sign-in method"}),e("p",{className:ye,children:"Choose another secure sign-in method."}),t("div",{className:be,children:[d&&t("button",{type:"button",className:ve,onClick:o,children:[e("span",{className:ke,children:"Email Magic Link"}),e("span",{className:we,children:"Send a secure sign-in link to your email"})]}),c&&t("button",{type:"button",className:ve,onClick:r,children:[e("span",{className:ke,children:"Email Code"}),e("span",{className:we,children:"Receive a one-time code by email"})]}),u&&t("button",{type:"button",className:ve,onClick:n,children:[e("span",{className:ke,children:"Text Message Code"}),e("span",{className:we,children:"Receive a one-time code via SMS"})]})]}),_&&e("button",{type:"button",className:xe,onClick:a,children:"Try passkey anyway"})]}):null},Se="seamless:oauth:provider",Ne=()=>{const{listOAuthProviders:i,startOAuthLogin:o}=W(),r=f("/oauth/callback"),[n,a]=d([]),[s,l]=d("");if(c(()=>{let e=!0;return i().then(({data:t})=>{e&&a(t?.providers??[])}),()=>{e=!1}},[i]),0===n.length)return null;return t("div",{className:be,children:[n.map(i=>e("button",{type:"button",className:ve,onClick:()=>(async e=>{l(""),sessionStorage.setItem(Se,e);const{data:t,error:i}=await o({providerId:e,redirectUri:new URL(r,window.location.origin).toString()});i?l("Could not start sign-in with this provider."):window.location.assign(t.authorizationUrl)})(i.id),children:t("span",{className:ke,children:["Continue with ",i.name]})},i.id)),s&&e("p",{className:me,children:s})]})},Oe=["passkey","magic_link","phone_otp"],Te=()=>{const o=h(),{hasSignedInBefore:r,login:n,handlePasskeyLogin:a}=W(),s=$(),{passkeySupported:l}=Y(),[u,_]=d(""),[m,g]=d(""),[p,f]=d("register"),[y,b]=d(""),[v,k]=d(""),[w,x]=d(""),[P,S]=d(!1),[N,O]=d(Oe);c(()=>{r&&f("login")},[r]);return e("div",{className:ae,children:t("div",{className:se,children:[e("h2",{className:le,children:"login"===p?"Sign In":"Create Account"}),t(i,{children:[t("form",{onSubmit:async e=>{e.preventDefault(),b(""),S(!1);try{if("login"===p){const{data:e,error:t}=await n(u,l);if(t)return void b("Failed to start sign-in. Please try again.");const i=e?.loginMethods?.length?e.loginMethods:Oe;if(O(i),l&&i.includes("passkey")){const{error:e}=await a();return e?(S(!0),void b("Passkey sign-in could not be completed. Choose another sign-in method.")):void o("/")}return void S(!0)}"register"===p&&await(async()=>{b("");const{data:e,error:t}=await s.register({email:m});t?b("Failed to register. Please try again."):"Success"===e.message?o(ee):b("An unexpected error occurred. Try again. If the problem persists, contact support.")})()}catch{console.error("Failed to continue sign-in."),b("Failed to continue sign-in. Please try again.")}},children:["login"===p&&t("div",{className:de,children:[e("label",{htmlFor:"identifier",className:ce,children:"Email Address / Phone Number"}),e("input",{id:"identifier",type:"text",value:u,onChange:e=>{const t=e.target.value;_(t)},autoComplete:"off",placeholder:"Email or Phone Number",className:ue,onBlur:()=>{if(u){const e=V(u)||K(u);x(e?"":"Please enter a valid email or phone number")}},required:!0}),e("p",{className:_e,children:"Phone numbers must include a country code e.g. +1"}),P&&e(Pe,{identifier:u,onMagicLink:async()=>{const{error:e}=await s.requestMagicLink();e?b("Failed to send magic link."):o(re,{state:{identifier:u}})},onEmailOtp:async()=>{const{error:e}=await s.requestLoginEmailOtp();e?b("Failed to send email code."):o(ee,{state:{flow:"login"}})},onPhoneOtp:async()=>{const{error:e}=await s.requestLoginPhoneOtp();e?b("Failed to send OTP."):o(X,{state:{flow:"login"}})},onPasskeyRetry:l?a:void 0,loginMethods:N}),w&&e("p",{className:me,children:w})]}),"register"===p&&t("div",{className:de,children:[e("label",{htmlFor:"email",className:ce,children:"Email Address"}),e("input",{id:"email",type:"email",value:m,onChange:e=>{const t=e.target.value;g(t)},autoComplete:"off",className:ue,onBlur:()=>{if(m){const e=V(m);k(e?"":"Please enter a valid email")}},required:!0}),v&&e("p",{className:me,children:v})]}),e("button",{type:"submit",className:ge,disabled:!("login"===p&&u?V(u)||K(u):V(m)),children:"login"===p?"Login":"Register"}),y&&e("p",{className:me,children:y}),e("button",{type:"button",onClick:()=>f("login"===p?"register":"login"),className:pe,children:"login"===p?"Don't have an account? Create one":"Already have an account? Sign in"})]}),e(Ne,{})]})]})})};var Ce={container:"passKeyLogin-module__container___IUKxF",card:"passKeyLogin-module__card___2sKM1",title:"passKeyLogin-module__title___HZxvc",button:"passKeyLogin-module__button___FvR4I"};ne(".passKeyLogin-module__container___IUKxF{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.passKeyLogin-module__card___2sKM1{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);display:flex;flex-direction:column;gap:1.5rem;max-width:400px;padding:2rem;width:100%}.passKeyLogin-module__title___HZxvc{color:#fff;font-size:1.5rem;font-weight:600;text-align:center}.passKeyLogin-module__button___FvR4I{background-color:#2563eb;border:1px solid #3b82f6;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;text-align:center;transition:background-color .2s ease;width:100%}.passKeyLogin-module__button___FvR4I:hover{background-color:#1d4ed8}@media (max-width:480px){.passKeyLogin-module__card___2sKM1{padding:1.25rem}.passKeyLogin-module__button___FvR4I{font-size:1rem}}");const Ie=()=>{const i=h(),{handlePasskeyLogin:o}=W(),[r,n]=d("");return e("div",{className:Ce.container,children:t("div",{className:Ce.card,children:[e("h2",{className:Ce.title,children:"Login with Passkey"}),e("button",{onClick:async()=>{n("");const{error:e}=await o();e?n("Passkey sign-in could not be completed. Try another sign-in method."):i("/")},className:Ce.button,children:"Use Passkey"}),r&&e("p",{className:Ce.error,children:r})]})})};var Me="registerPasskey-module__container___jqEh8",Ae="registerPasskey-module__card___MJAyC",ze="registerPasskey-module__loading___Q4i1x",Ee="registerPasskey-module__spinner___V1nhd",Fe="registerPasskey-module__supported___ihTih",Le="registerPasskey-module__title___vn2Qu",Ue="registerPasskey-module__description___AWmO-",Re="registerPasskey-module__button___D3b4B",Be="registerPasskey-module__message___RiOw-",qe="registerPasskey-module__success___HP5aX",Je="registerPasskey-module__error___hGiqE";ne(".registerPasskey-module__container___jqEh8{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.registerPasskey-module__card___MJAyC{background-color:#1f2937;border-radius:1rem;box-shadow:0 4px 20px rgba(0,0,0,.4);max-width:400px;padding:1.5rem;width:100%}.registerPasskey-module__loading___Q4i1x{align-items:center;background-color:#f9fafb;border-radius:.75rem;box-shadow:0 2px 8px rgba(0,0,0,.1);color:#374151;display:flex;font-weight:500;gap:.75rem;justify-content:center;padding:1.5rem}.registerPasskey-module__spinner___V1nhd{animation:registerPasskey-module__spin___oYcsC 1s linear infinite;border-color:#3b82f6 transparent;border-radius:9999px;border-style:solid;border-width:2px;height:1.5rem;width:1.5rem}@keyframes registerPasskey-module__spin___oYcsC{to{transform:rotate(1turn)}}.registerPasskey-module__supported___ihTih{background-color:#ecfdf5;border-radius:.75rem;box-shadow:0 2px 12px rgba(0,0,0,.1);color:#065f46;padding:1.25rem}.registerPasskey-module__title___vn2Qu{font-size:1.125rem;font-weight:600;margin-bottom:.5rem}.registerPasskey-module__description___AWmO-{margin-bottom:1rem}.registerPasskey-module__button___D3b4B{background-color:#059669;border:none;border-radius:.5rem;color:#fff;cursor:pointer;font-weight:500;padding:.75rem 1rem;transition:background-color .2s ease;width:100%}.registerPasskey-module__button___D3b4B:hover{background-color:#047857}.registerPasskey-module__message___RiOw-{font-size:.875rem;margin-top:1rem}.registerPasskey-module__success___HP5aX{color:#6ee7b7}.registerPasskey-module__error___hGiqE{color:#f87171}");var Ge="deviceNameModal-module__overlay___fmdPd",je="deviceNameModal-module__modal___uoEda",We="deviceNameModal-module__description___-HMTA",De="deviceNameModal-module__input___4vQMI",$e="deviceNameModal-module__actions___KXw7b",Ve="deviceNameModal-module__primary___9Ozlk",Ke="deviceNameModal-module__secondary___HILhc";ne(".deviceNameModal-module__overlay___fmdPd{align-items:center;background:rgba(0,0,0,.45);display:flex;inset:0;justify-content:center;position:fixed;z-index:1000}.deviceNameModal-module__modal___uoEda{background:#1f2937;border-radius:12px;box-shadow:0 20px 40px rgba(0,0,0,.15);color:#fff;max-width:420px;padding:24px;width:100%}.deviceNameModal-module__description___-HMTA{color:#fff;font-size:14px;margin-bottom:16px}.deviceNameModal-module__input___4vQMI{border:1px solid #ddd;border-radius:8px;font-size:14px;margin-bottom:20px;padding:10px 12px;width:100%}.deviceNameModal-module__actions___KXw7b{display:flex;gap:10px;justify-content:flex-end}.deviceNameModal-module__primary___9Ozlk{background:#2563eb;border:none;border-radius:8px;color:#fff;cursor:pointer;padding:8px 14px}.deviceNameModal-module__secondary___HILhc{background:transparent;border:1px solid #ccc;border-radius:8px;cursor:pointer;padding:8px 14px}");const He=({isOpen:i,onCancel:o,onConfirm:r})=>{const[n,a]=d("");return i?e("div",{className:Ge,children:t("div",{className:je,children:[e("h3",{children:"Name This Device"}),e("p",{className:We,children:"Give this passkey a friendly name so you can recognize it later."}),e("input",{type:"text",placeholder:"e.g., MacBook Pro, iPhone, YubiKey",value:n,onChange:e=>a(e.target.value),className:De,autoFocus:!0}),t("div",{className:$e,children:[e("button",{onClick:o,className:Ke,children:"Cancel"}),e("button",{onClick:()=>r(n.trim()),disabled:!n.trim(),className:Ve,children:"Continue"})]})]})}):null},Ye=()=>{const{refreshSession:o}=W(),r=$(),{passkeySupported:n,loading:a}=Y(),s=h(),[l,c]=d("idle"),[u,_]=d(""),[m,g]=d(!1),[p,f]=d(null);return t(i,{children:[e("div",{className:Me,children:e("div",{className:Ae,children:t("div",a||!n?{className:ze,children:[e("div",{className:Ee}),e("span",{children:a?"Checking for Passkey Support...":"Passkeys are not supported on this device."})]}:{className:Fe,children:[e("h2",{className:Le,children:"Secure Your Account with a Passkey"}),e("p",{className:Ue,children:"Your device supports passkeys! Register one to skip passwords forever."}),e("button",{onClick:()=>{const{platform:e,browser:t,deviceInfo:i}=function(){const e=navigator.userAgent.toLowerCase();let t="unknown",i="unknown";return/iphone|ipad|ipod/.test(e)?t="ios":/android/.test(e)?t="android":/mac os/.test(e)?t="mac":/windows/.test(e)?t="windows":/linux/.test(e)&&(t="linux"),navigator.brave?i="brave":/edg\/|edgios/.test(e)?i="edge":/opr\/|opt\/|opera/.test(e)?i="opera":/vivaldi/.test(e)?i="vivaldi":/samsungbrowser/.test(e)?i="samsung":/firefox|fxios/.test(e)?i="firefox":/chrome|crios/.test(e)?i="chrome":/safari/.test(e)&&(i="safari"),{platform:t,browser:i,deviceInfo:`${t} • ${i}`}}();f({platform:e,browser:t,deviceInfo:i}),g(!0)},disabled:"loading"===l,className:Re,children:"loading"===l?"Registering...":"Register Passkey"}),u&&e("p",{className:`${Be} ${"success"===l?qe:Je}`,children:u})]})})}),e(He,{isOpen:m,onCancel:()=>{g(!1),f(null)},onConfirm:async e=>{if(!p)return;const t={friendlyName:e,...p};c("loading");try{const{error:e}=await r.registerPasskey(t);if(e)throw e;await o(),c("success"),_("Passkey registered successfully."),s("/")}catch{console.error("Passkey registration failed."),c("error"),_("Error registering passkey.")}finally{g(!1),f(null)}}})]})};var Qe="verifyOTP-module__container___wgoDE",Ze="verifyOTP-module__card___3cs2p",Xe="verifyOTP-module__title___fZ-1d",et="verifyOTP-module__subtitle___dGSu3",tt="verifyOTP-module__error___GEtlG",it="verifyOTP-module__success___46TjG",ot="verifyOTP-module__form___jiGG-",rt="verifyOTP-module__label___Zq5Mi",nt="verifyOTP-module__timer___smq-a",at="verifyOTP-module__resend___PlmkG",st="verifyOTP-module__button___8pIuO",lt="verifyOTP-module__toggle___wbzVa";ne(".verifyOTP-module__container___wgoDE{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.verifyOTP-module__card___3cs2p{background-color:#1f2937;border-radius:.5rem;box-shadow:0 0 10px rgba(0,0,0,.3);max-width:28rem;padding:1.5rem;width:100%}.verifyOTP-module__title___fZ-1d{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1rem;text-align:center}.verifyOTP-module__subtitle___dGSu3{color:#9ca3af;font-size:.875rem;margin-bottom:1.5rem;text-align:center}.verifyOTP-module__error___GEtlG{color:#f87171;margin-bottom:1rem;text-align:center}.verifyOTP-module__success___46TjG{color:#34d399;margin-bottom:.75rem;text-align:center}.verifyOTP-module__form___jiGG-{display:flex;flex-direction:column;gap:1rem}.verifyOTP-module__label___Zq5Mi{color:#d1d5db;display:block;font-size:.875rem;margin-bottom:.25rem}.verifyOTP-module__timer___smq-a{color:#facc15;font-size:.875rem}.verifyOTP-module__input___yqIXM{background-color:#374151;border:1px solid #4b5563;border-radius:.375rem;color:#fff;outline:none;padding:.5rem;width:100%}.verifyOTP-module__input___yqIXM:focus{box-shadow:0 0 0 2px #3b82f6}.verifyOTP-module__resend___PlmkG{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.75rem;margin-top:.25rem;text-decoration:underline}.verifyOTP-module__resend___PlmkG:hover{color:#3b82f6}.verifyOTP-module__button___8pIuO{background-color:#2563eb;border:none;border-radius:.375rem;color:#fff;cursor:pointer;padding:.5rem;transition:background-color .2s;width:100%}.verifyOTP-module__button___8pIuO:hover{background-color:#1d4ed8}.verifyOTP-module__toggle___wbzVa{background:none;border:none;color:#60a5fa;cursor:pointer;font-size:.875rem;margin-top:1.5rem;text-align:center;width:100%}");var dt="otpInput-module__otpContainer___MUjby",ct="otpInput-module__otpInput___3YMVm";ne(".otpInput-module__otpContainer___MUjby{display:flex;gap:8px;justify-content:center;margin-top:8px}.otpInput-module__otpInput___3YMVm{background:#374151;border:1px solid #4b5563;border-radius:8px;color:#fff;font-size:1.2rem;height:48px;text-align:center;transition:border-color .15s ease,box-shadow .15s ease;width:42px}.otpInput-module__otpInput___3YMVm:focus{border-color:#60a5fa;box-shadow:0 0 0 2px rgba(96,165,250,.25);outline:none}");const ut=({length:t=6,value:i,inputMode:o="numeric",onChange:r,name:n="otp"})=>{const a=p([]),s=i.split("").concat(Array(t).fill("")).slice(0,t),l=(e,t)=>{var i;if(t.length>1)d(e,t);else if(!t||(i=t,"numeric"===o?/^\d$/.test(i):/^[a-zA-Z]$/.test(i))){const i=[...s];i[e]=t;const o=i.join("");r(o),t&&a.current[e+1]&&a.current[e+1]?.focus()}},d=(e,i)=>{let n=i;n="numeric"===o?i.replace(/\D/g,""):i.replace(/[^a-zA-Z]/g,"");const l=n.slice(0,t).split(""),d=[...s];l.forEach((i,o)=>{e+o<t&&(d[e+o]=i)}),r(d.join("")),a.current[Math.min(e+l.length,t-1)]?.focus()};return e("div",{className:dt,role:"group","aria-label":"One-time password input",onPaste:e=>{e.preventDefault(),d(0,e.clipboardData.getData("text"))},children:s.map((i,d)=>e("input",{ref:e=>a.current[d]=e,type:"text",inputMode:"numeric"===o?"numeric":"text",autoComplete:"one-time-code",name:`${n}-${d}`,maxLength:1,value:i,className:ct,onChange:e=>l(d,e.target.value),onKeyDown:e=>((e,i)=>{if("Backspace"===i.key){i.preventDefault();const t=[...s];s[e]?(t[e]="",r(t.join(""))):e>0&&(t[e-1]="",r(t.join("")),a.current[e-1]?.focus())}"ArrowLeft"===i.key&&e>0&&a.current[e-1]?.focus(),"ArrowRight"===i.key&&e<t-1&&a.current[e+1]?.focus()})(d,e),"aria-label":`Digit ${d+1}`},d))})},_t=()=>{const i=h(),o=y(),{refreshSession:r}=W(),n="login"===o.state?.flow,[a,s]=d(""),[l,u]=d(null),[_,m]=d(""),[g,p]=d(!1),[f,b]=d(""),[v,k]=d(300),w=$(),x=async()=>{if(p(!0),!l){const{error:e}=n?await w.verifyLoginPhoneOtp(a):await w.verifyPhoneOtp(a);if(e)m("Verification failed.");else{if(n)return await r(),void i("/");u(!0)}}p(!1)},P=async()=>{b(""),await(async()=>{m("");const{error:e}=n?await w.requestLoginPhoneOtp():await w.requestPhoneOtp();e?m("Failed to send SMS code. If this persists, refresh the page and try again."):b("Verification SMS has been resent.")})(),b("Verification SMS has been resent.")};return c(()=>{const e=setInterval(()=>{k(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),c(()=>{l&&!n&&(async()=>{const{error:e}=await w.requestEmailOtp();e?m("Failed to send Email code. If this persists, refresh the page and try registering again."):i(ee)})()},[l,n,i,w]),e("div",{className:Qe,children:t("div",{className:Ze,children:[e("h2",{className:Xe,children:"Verify Your Phone Number"}),e("p",{className:et,children:"Enter the code sent to your phone number."}),_&&e("p",{className:tt,children:_}),f&&e("p",{className:it,children:f}),t("form",{onSubmit:async e=>{if(e.preventDefault(),m(""),6===a.length){p(!0);try{await x()}catch{m("Unexpected error occurred.")}finally{p(!1)}}else m("Please enter a valid code.")},className:ot,children:[t("div",{children:[t("label",{htmlFor:"phoneCode",className:rt,children:["Phone Verification Code ",(N=l,!0===N?e("span",{className:"text-green-400 ml-2",children:"✅"}):!1===N?e("span",{className:"text-red-400 ml-2",children:"❌"}):null)," -"," ",t("span",{className:nt,children:["Code expires in: ",(S=v,`${Math.floor(S/60).toString().padStart(2,"0")}:${(S%60).toString().padStart(2,"0")}`)]})]}),e(ut,{length:6,value:a,onChange:s}),e("button",{type:"button",onClick:()=>P(),className:at,children:"Resend code to phone"})]}),e("button",{type:"submit",className:st,children:g?"Verifying...":"Verify & Continue"}),e("button",{type:"button",onClick:()=>i("/login"),className:lt,children:"Back to login"})]})]})});var S,N},mt=()=>{const i=h(),o=y(),{refreshSession:r}=W(),n=$(),{passkeySupported:a}=Y(),s="login"===o.state?.flow,[l,u]=d(!1),[_,m]=d(""),[g,p]=d(300),[f,b]=d(""),[v,k]=d("");return c(()=>{const e=setInterval(()=>{p(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]),e("div",{className:Qe,children:t("div",{className:Ze,children:[e("h2",{className:Xe,children:"Verify Your Email"}),e("p",{className:et,children:"We sent you a verification email. Enter the code below."}),f&&e("p",{className:tt,children:f}),v&&e("p",{className:it,children:v}),t("form",{onSubmit:async e=>{if(e.preventDefault(),b(""),6===_.length){u(!0);try{const{error:e}=s?await n.verifyLoginEmailOtp(_):await n.verifyEmailOtp(_);if(e)return void b("Verification failed.");if(s)return await r(),void i("/");a?i(oe):(await r(),i("/"))}catch{console.error("Email OTP verification failed."),b("Verification failed.")}finally{u(!1)}}else b("Please enter a valid code.")},className:ot,children:[t("div",{children:[t("label",{htmlFor:"emailCode",className:rt,children:["Email Verification Code",t("span",{className:nt,children:[" ","— Code expires in ",(w=g,`${Math.floor(w/60).toString().padStart(2,"0")}:${(w%60).toString().padStart(2,"0")}`)]})]}),e(ut,{length:6,value:_,onChange:m,inputMode:"text"}),e("button",{type:"button",onClick:async()=>{b(""),k("");const{error:e}=s?await n.requestLoginEmailOtp():await n.requestEmailOtp();e?b("Failed to send Email code. If this persists, refresh the page and try again."):k("Verification email has been resent.")},className:at,children:"Resend code to email"})]}),e("button",{type:"submit",className:st,disabled:l,children:l?"Verifying...":"Verify & Continue"}),e("button",{type:"button",onClick:()=>i("/login"),className:lt,children:"Back to login"})]})]})});var w};var gt={container:"verifyMagiclink-module__container___qrSXf",card:"verifyMagiclink-module__card___niKgr",title:"verifyMagiclink-module__title___SumxD",verificationContent:"verifyMagiclink-module__verificationContent___NdsS0",spinner:"verifyMagiclink-module__spinner___lnW1k",successIcon:"verifyMagiclink-module__successIcon___XjFEM",checkIcon:"verifyMagiclink-module__checkIcon___I0JOP",successText:"verifyMagiclink-module__successText___lO5Qq"};ne(".verifyMagiclink-module__container___qrSXf{align-items:center;color:#fff;display:flex;justify-content:center;padding:1rem}.verifyMagiclink-module__card___niKgr{background-color:#1f2937;border-radius:.5rem;box-shadow:0 0 10px rgba(0,0,0,.3);max-width:28rem;padding:1.5rem;width:100%}.verifyMagiclink-module__title___SumxD{color:#fff;font-size:1.5rem;font-weight:700;margin-bottom:1rem;text-align:center}.verifyMagiclink-module__verificationContent___NdsS0{align-items:center;display:flex;flex-direction:column;gap:14px;margin:20px 0}.verifyMagiclink-module__spinner___lnW1k{animation:verifyMagiclink-module__spin___2lGzj .9s linear infinite;border:3px solid hsla(0,0%,100%,.15);border-radius:50%;border-top-color:#60a5fa;height:28px;width:28px}.verifyMagiclink-module__successIcon___XjFEM{align-items:center;background:rgba(16,185,129,.15);border-radius:50%;display:flex;height:36px;justify-content:center;width:36px}.verifyMagiclink-module__checkIcon___I0JOP{animation:verifyMagiclink-module__checkPop___-3qJu .25s ease-out;color:#34d399;height:22px;width:22px}.verifyMagiclink-module__successText___lO5Qq{color:#34d399;font-size:.9rem}@keyframes verifyMagiclink-module__checkPop___-3qJu{0%{opacity:0;transform:scale(.6)}80%{transform:scale(1.15)}to{opacity:1;transform:scale(1)}}@keyframes verifyMagiclink-module__spin___2lGzj{to{transform:rotate(1turn)}}");const pt=()=>{const[i]=b(),o=h(),r=i.get("token"),[n,a]=d(""),[s,l]=d(""),u=$(),{refreshSession:_}=W();return c(()=>{let e=!0,t=null,i=null;return(async()=>{if(!r)return e&&a("Missing token for verification."),void console.error("No magic-link token found.");const{error:n}=await u.verifyMagicLink(r);if(n)return console.error("Failed to verify token"),void(e&&a("Failed to verify token"));await _(),e&&(t=new BroadcastChannel("seamless-auth"),t.postMessage({type:"MAGIC_LINK_AUTH_SUCCESS"}),l("You have been verified on the device and browser that initiated this request"),i=setTimeout(()=>{e&&o("/")},900))})(),()=>{e=!1,t?.close(),i&&clearTimeout(i)}},[r,u,o,_]),e("div",{className:gt.container,children:t("div",{className:gt.card,children:[e("h1",{className:gt.title,children:"Verifying your login"}),t("div",{className:gt.verificationContent,children:[!s&&!n&&e("div",{className:gt.spinner}),s&&e("div",{className:gt.successIcon,children:e("svg",{viewBox:"0 0 24 24",className:gt.checkIcon,fill:"none",stroke:"currentColor",strokeWidth:"2",children:e("path",{d:"M5 13l4 4L19 7"})})}),!s&&!n&&e("p",{className:gt.helperText,children:"Please wait while we securely verify your sign-in link."}),s&&e("p",{className:gt.successText,children:"Login verified. Redirecting…"}),n&&e("p",{className:gt.error,children:n})]})]})})},ft=()=>{const{finishOAuthLogin:o}=W(),r=h(),[n]=b(),[a,s]=d(""),l=p(!1);return c(()=>{if(l.current)return;l.current=!0;const e=n.get("code"),t=n.get("state"),i=sessionStorage.getItem(Se);e&&t&&i?o({providerId:i,code:e,state:t}).then(({error:e})=>{e?s("We could not complete sign-in. Please try again."):(sessionStorage.removeItem(Se),r("/"))}):s("This sign-in link is missing required information.")},[o,r,n]),t("div",{className:gt.container,children:[e("h2",{className:gt.title,children:a?"Sign-in failed":"Completing sign-in..."}),a&&t(i,{children:[e("p",{children:a}),e("button",{type:"button",onClick:()=>r("/login"),children:"Back to login"})]})]})};var ht="magiclink-module__container___45zcA",yt="magiclink-module__card___Au9oN",bt="magiclink-module__iconWrapper___k5ndr",vt="magiclink-module__mailIcon___Pwb7q",kt="magiclink-module__iconRing___bdLvf",wt="magiclink-module__heading___b9cre",xt="magiclink-module__message___kiVFj",Pt="magiclink-module__identifier___JtcFM",St="magiclink-module__helperText___7Mlfh",Nt="magiclink-module__actions___64I-3",Ot="magiclink-module__secondaryButton___BntAI",Tt="magiclink-module__cooldown___Ib4rm",Ct="magiclink-module__linkButton___maJiv";ne(".magiclink-module__container___45zcA{align-items:center;color:#fff;display:flex;justify-content:center}.magiclink-module__card___Au9oN{background-color:#1f2937;border-radius:.75rem;box-shadow:0 10px 25px rgba(0,0,0,.25);max-width:420px;padding:2.5rem 2rem;text-align:center;width:100%}.magiclink-module__iconWrapper___k5ndr{display:flex;justify-content:center;margin-bottom:1.25rem;position:relative}.magiclink-module__mailIcon___Pwb7q{color:#a5b4fc;height:38px;width:38px;z-index:2}.magiclink-module__iconRing___bdLvf{animation:magiclink-module__pulse___YGm-I 2s infinite;background:rgba(99,102,241,.15);border-radius:50%;height:72px;position:absolute;width:72px}@keyframes magiclink-module__pulse___YGm-I{0%{opacity:.8;transform:scale(.6)}70%{opacity:0;transform:scale(1.4)}to{opacity:0}}.magiclink-module__heading___b9cre{font-size:1.55rem;font-weight:600;margin-bottom:.75rem}.magiclink-module__message___kiVFj{color:#d1d5db;font-size:.95rem;line-height:1.4;margin-bottom:1rem}.magiclink-module__identifier___JtcFM{background:hsla(0,0%,100%,.05);border-radius:6px;display:inline-block;font-size:1rem;font-weight:600;margin-bottom:1rem;padding:.45rem .6rem}.magiclink-module__helperText___7Mlfh{color:#9ca3af;font-size:.85rem;line-height:1.4;margin-bottom:.6rem}.magiclink-module__actions___64I-3{display:flex;flex-direction:column;gap:.6rem;margin-top:1.6rem}.magiclink-module__secondaryButton___BntAI{background:#111827;border:1px solid #374151;border-radius:8px;color:#fff;cursor:pointer;font-weight:500;padding:.65rem}.magiclink-module__secondaryButton___BntAI:hover:not(:disabled){background:#1f2937}.magiclink-module__secondaryButton___BntAI:disabled{cursor:not-allowed;opacity:.5}.magiclink-module__cooldown___Ib4rm{color:#9ca3af;font-size:.8rem}.magiclink-module__linkButton___maJiv{background:none;border:none;color:#a5b4fc;cursor:pointer;font-size:.85rem;margin-top:.4rem}.magiclink-module__linkButton___maJiv:hover{text-decoration:underline}");const It=()=>{const{refreshSession:i}=W(),o=h(),r=y(),n=$(),a=r.state?.identifier,[s,l]=d(30);c(()=>{const e=setInterval(()=>{l(e=>e>0?e-1:0)},1e3);return()=>clearInterval(e)},[]);const u=m(async()=>{const{data:e,error:t}=await n.checkMagicLink();return!t&&"Success"===e?.message},[n]);return c(()=>{const e=new BroadcastChannel("seamless-auth");return e.onmessage=async e=>{"MAGIC_LINK_AUTH_SUCCESS"===e.data?.type&&await u()&&(await i(),o("/"))},()=>{e.close()}},[u,o,i]),c(()=>{const e=setInterval(async()=>{try{await u()&&(await i(),o("/"))}catch{}},5e3);return()=>clearInterval(e)},[u,i,o]),e("div",{className:ht,children:t("div",{className:yt,children:[t("div",{className:bt,children:[e("div",{className:kt}),t("svg",{className:vt,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"1.8",children:[e("path",{d:"M4 6h16v12H4z"}),e("path",{d:"m4 6 8 6 8-6"})]})]}),e("h2",{className:wt,children:"Check your email"}),e("p",{className:xt,children:"If an account exists for this address, we sent a secure sign-in link."}),a&&e("div",{className:Pt,children:a}),e("p",{className:St,children:"Open the email and click the link to finish signing in."}),e("p",{className:St,children:"Didn’t receive anything? Check your spam folder or try creating a new account."}),t("div",{className:Nt,children:[e("button",{className:Ot,disabled:s>0,onClick:async()=>{s>0||(await n.requestMagicLink(),l(30))},children:"Resend link"}),s>0&&t("div",{className:Tt,children:["Available in ",s,"s"]}),e("button",{className:Ct,onClick:()=>o("/login"),children:"Change email or phone"})]})]})})},Mt=()=>t(v,{children:[e(k,{path:Q,element:e(Te,{})}),e(k,{path:Z,element:e(Ie,{})}),e(k,{path:X,element:e(_t,{})}),e(k,{path:ee,element:e(mt,{})}),e(k,{path:te,element:e(pt,{})}),e(k,{path:ie,element:e(ft,{})}),e(k,{path:oe,element:e(Ye,{})}),e(k,{path:re,element:e(It,{})}),e(k,{path:"*",element:e(w,{to:Q,replace:!0})})]});export{D as AuthProvider,Mt as AuthRoutes,P as SeamlessAuthError,q as createSeamlessAuthClient,M as encodePrfSalt,L as extractPasskeyPrfResult,G as hasScopedRole,E as isPasskeyPrfSupported,J as roleGrantsAccess,W as useAuth,$ as useAuthClient,Y as usePasskeySupport};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|