'use strict';

var StytchSSRProxy = require('../StytchSSRProxy-D0nfqCWX.js');
var idpHelpers = require('../idpHelpers-hKje8C-l.js');
var dev = require('../dev-DaCGDI6V.js');
var logger = require('../logger-CvOATP4R.js');

class HeadlessB2BDiscoveryClient {
    _networkClient;
    _subscriptionService;
    organizations;
    intermediateSessions;
    constructor(_networkClient, _subscriptionService){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
        this.organizations = {
            list: async ()=>this._networkClient.fetchSDK({
                    url: '/b2b/discovery/organizations',
                    body: {
                        intermediate_session_token: await this._subscriptionService.getIntermediateSessionToken() || undefined
                    },
                    method: 'POST'
                }),
            create: this._subscriptionService.withUpdateSession(async (data)=>{
                dev.validateInDev('stytch.discovery.organizations.create', data, {
                    session_duration_minutes: 'number',
                    organization_name: 'optionalString',
                    organization_slug: 'optionalString',
                    organization_logo_url: 'optionalString',
                    sso_jit_provisioning: 'optionalString',
                    email_allowed_domains: 'optionalStringArray',
                    email_invites: 'optionalString',
                    auth_methods: 'optionalString',
                    allowed_auth_methods: 'optionalStringArray',
                    mfa_policy: 'optionalString'
                });
                const requestBody = {
                    ...data,
                    intermediate_session_token: await this._subscriptionService.getIntermediateSessionToken() || undefined
                };
                return this._networkClient.fetchSDK({
                    url: '/b2b/discovery/organizations/create',
                    body: requestBody,
                    method: 'POST'
                });
            })
        };
        this.intermediateSessions = {
            exchange: this._subscriptionService.withUpdateSession(async (data)=>{
                dev.validateInDev('stytch.discovery.intermediateSessions.exchange', data, {
                    organization_id: 'string',
                    session_duration_minutes: 'number',
                    locale: 'optionalString'
                });
                const requestBody = {
                    ...data,
                    intermediate_session_token: this._subscriptionService.getIntermediateSessionToken() || undefined
                };
                return this._networkClient.fetchSDK({
                    url: '/b2b/discovery/intermediate_sessions/exchange',
                    body: requestBody,
                    method: 'POST'
                });
            })
        };
    }
}

class HeadlessB2BIDPClient {
    _networkClient;
    constructor(_networkClient){
        this._networkClient = _networkClient;
    }
    /**
   * Initiates a request for authorization of a Connected App to access a Member's account.
   *
   * Call this endpoint using the query parameters from an OAuth Authorization request. This endpoint validates various fields (scope, client_id, redirect_uri, prompt, etc...) are correct and returns relevant information for rendering an OAuth Consent Screen.
   *
   * @example
   * const response = await stytch.idp.oauthAuthorizeStart({
   *   client_id: 'client_123',
   *   redirect_uri: 'https://example.com/callback',
   *   scope: 'openid email profile',
   * });
   */ oauthAuthorizeStart = async (data)=>this._networkClient.fetchSDK({
            url: '/idp/b2b/oauth/authorize/start',
            method: 'POST',
            body: data
        });
    /**
   * Completes a request for authorization of a Connected App to access a Member's account.
   *
   * Call this endpoint using the query parameters from an OAuth Authorization request, after previously validating those parameters using the Preflight Check API. Note that this endpoint takes in a few additional parameters the preflight check does not- state, nonce, and code_challenge.
   *
   * If the authorization was successful, the redirect_uri will contain a valid authorization_code embedded as a query parameter. If the authorization was unsuccessful, the redirect_uri will contain an OAuth2.1 error_code. In both cases, redirect the Member to the location for the response to be consumed by the Connected App.
   *
   * Exactly one of the following must be provided to identify the Member granting authorization:
   * organization_id + member_id
   * session_token
   * session_jwt
   *
   * If a session_token or session_jwt is passed, the OAuth Authorization will be linked to the Member's session for tracking purposes. One of these fields must be used if the Connected App intends to complete the Exchange Access Token flow.
   *
   * @example
   * const response = await stytch.idp.oauthAuthorizeSubmit({
   *   client_id: 'client_123',
   *   redirect_uri: 'https://example.com/callback',
   *   scope: 'openid email profile',
   * });
   */ oauthAuthorizeSubmit = async (data)=>this._networkClient.fetchSDK({
            url: '/idp/b2b/oauth/authorize/submit',
            method: 'POST',
            body: data
        });
    oauthLogoutStart = async (data)=>this._networkClient.fetchSDK({
            url: `/b2b/oauth/logout/start`,
            method: 'POST',
            body: data
        });
}

class HeadlessB2BImpersonationClient {
    _networkClient;
    _subscriptionService;
    dfpProtectedAuth;
    authenticate;
    constructor(_networkClient, _subscriptionService, dfpProtectedAuth){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
        this.dfpProtectedAuth = dfpProtectedAuth;
        this.authenticate = this._subscriptionService.withUpdateSession(async (data)=>{
            dev.validateInDev('stytch.impersonation.authenticate', data, {
                impersonation_token: 'string'
            });
            const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
            return this._networkClient.retriableFetchSDK({
                url: '/b2b/impersonation/authenticate',
                body: {
                    ...data,
                    dfp_telemetry_id,
                    captcha_token
                },
                method: 'POST',
                retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
            });
        });
    }
}

let HeadlessB2BOAuthClient$1 = class HeadlessB2BOAuthClient {
    _networkClient;
    _subscriptionService;
    _pkceManager;
    _dynamicConfig;
    _config;
    dfpProtectedAuth;
    authenticate;
    discovery;
    google;
    microsoft;
    hubspot;
    slack;
    github;
    constructor(_networkClient, _subscriptionService, _pkceManager, _dynamicConfig, _config, dfpProtectedAuth){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
        this._pkceManager = _pkceManager;
        this._dynamicConfig = _dynamicConfig;
        this._config = _config;
        this.dfpProtectedAuth = dfpProtectedAuth;
        this.authenticate = this._subscriptionService.withUpdateSession(async (options)=>{
            dev.validateInDev('stytch.oauth.authenticate', options, {
                oauth_token: 'string',
                session_duration_minutes: 'number',
                locale: 'optionalString'
            });
            const keyPair = await this._pkceManager.getPKPair();
            if (!keyPair) {
                logger.logger.warn('No code verifier found in local storage for OAuth flow.\n' + 'Consider using stytch.oauth.$provider.start() to add PKCE to your OAuth flows for added security.\n' + 'See https://stytch.com/docs/oauth#guides_pkce for more information.');
            }
            const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
            const resp = await this._networkClient.retriableFetchSDK({
                url: '/b2b/oauth/authenticate',
                method: 'POST',
                body: {
                    pkce_code_verifier: keyPair?.code_verifier,
                    dfp_telemetry_id,
                    captcha_token,
                    intermediate_session_token: await this._subscriptionService.getIntermediateSessionToken() || undefined,
                    ...options
                },
                retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
            });
            this._pkceManager.clearPKPair();
            return resp;
        });
        this.discovery = {
            authenticate: this._subscriptionService.withUpdateSession(async (data)=>{
                dev.validateInDev('stytch.oauth.discovery.authenticate', data, {
                    discovery_oauth_token: 'string'
                });
                const pkPair = await this._pkceManager.getPKPair();
                const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
                const requestBody = {
                    pkce_code_verifier: pkPair?.code_verifier,
                    dfp_telemetry_id,
                    captcha_token,
                    ...data
                };
                const resp = await this._networkClient.retriableFetchSDK({
                    url: '/b2b/oauth/discovery/authenticate',
                    body: requestBody,
                    method: 'POST',
                    retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
                });
                this._pkceManager.clearPKPair();
                return resp;
            })
        };
        this.google = {
            start: this.startOAuthFlow(StytchSSRProxy.B2BOAuthProviders.Google),
            discovery: {
                start: this.startDiscoveryOAuthFlow(StytchSSRProxy.B2BOAuthProviders.Google)
            }
        };
        this.microsoft = {
            start: this.startOAuthFlow(StytchSSRProxy.B2BOAuthProviders.Microsoft),
            discovery: {
                start: this.startDiscoveryOAuthFlow(StytchSSRProxy.B2BOAuthProviders.Microsoft)
            }
        };
        this.hubspot = {
            start: this.startOAuthFlow(StytchSSRProxy.B2BOAuthProviders.HubSpot),
            discovery: {
                start: this.startDiscoveryOAuthFlow(StytchSSRProxy.B2BOAuthProviders.HubSpot)
            }
        };
        this.slack = {
            start: this.startOAuthFlow(StytchSSRProxy.B2BOAuthProviders.Slack),
            discovery: {
                start: this.startDiscoveryOAuthFlow(StytchSSRProxy.B2BOAuthProviders.Slack)
            }
        };
        this.github = {
            start: this.startOAuthFlow(StytchSSRProxy.B2BOAuthProviders.GitHub),
            discovery: {
                start: this.startDiscoveryOAuthFlow(StytchSSRProxy.B2BOAuthProviders.GitHub)
            }
        };
    }
    async getBaseApiUrl() {
        const { cnameDomain } = await this._dynamicConfig;
        if (cnameDomain) {
            // The API returns cname domains without a protocol - assume HTTPS
            return `https://${cnameDomain}`;
        }
        // Our TestAPIURL and LiveAPIURL should have the HTTPS protocol already attached
        // Don't add it twice!
        if (idpHelpers.isTestPublicToken(this._config.publicToken)) {
            return this._config.testAPIURL;
        }
        return this._config.liveAPIURL;
    }
    startOAuthFlow(providerType) {
        return async (options)=>{
            const { organization_id, organization_slug, login_redirect_url, signup_redirect_url, custom_scopes, provider_params } = options;
            const { pkceRequiredForOAuth } = await this._dynamicConfig;
            const baseURL = await this.getBaseApiUrl();
            const startUrl = new URL(`${baseURL}/v1/b2b/public/oauth/${providerType}/start`);
            startUrl.searchParams.set('public_token', this._config.publicToken);
            if (organization_id && organization_id != '') {
                startUrl.searchParams.set('organization_id', organization_id);
            }
            if (organization_slug && organization_slug != '') {
                startUrl.searchParams.set('slug', organization_slug);
            }
            if (custom_scopes) {
                dev.validateInDev('startOAuthFlow', {
                    custom_scopes
                }, {
                    custom_scopes: 'stringArray'
                });
                startUrl.searchParams.set('custom_scopes', custom_scopes.join(' '));
            }
            if (provider_params) {
                dev.validateInDev('startOAuthFlow', {
                    provider_params
                }, {
                    provider_params: 'optionalObject'
                });
                for(const key in provider_params){
                    startUrl.searchParams.set('provider_' + key, provider_params[key]);
                }
            }
            if (pkceRequiredForOAuth) {
                const keyPair = await this._pkceManager.startPKCETransaction();
                startUrl.searchParams.set('pkce_code_challenge', keyPair.code_challenge);
            } else {
                this._pkceManager.clearPKPair();
            }
            if (login_redirect_url) startUrl.searchParams.set('login_redirect_url', login_redirect_url);
            if (signup_redirect_url) startUrl.searchParams.set('signup_redirect_url', signup_redirect_url);
            this.navigate(startUrl);
        };
    }
    startDiscoveryOAuthFlow(providerType) {
        return async (options)=>{
            const { discovery_redirect_url, custom_scopes, provider_params } = options;
            const { pkceRequiredForOAuth } = await this._dynamicConfig;
            const baseURL = await this.getBaseApiUrl();
            const startUrl = new URL(`${baseURL}/v1/b2b/public/oauth/${providerType}/discovery/start`);
            startUrl.searchParams.set('public_token', this._config.publicToken);
            if (custom_scopes) {
                dev.validateInDev('startOAuthFlow', {
                    custom_scopes
                }, {
                    custom_scopes: 'stringArray'
                });
                startUrl.searchParams.set('custom_scopes', custom_scopes.join(' '));
            }
            if (provider_params) {
                dev.validateInDev('startOAuthFlow', {
                    provider_params
                }, {
                    provider_params: 'optionalObject'
                });
                for(const key in provider_params){
                    startUrl.searchParams.set('provider_' + key, provider_params[key]);
                }
            }
            if (pkceRequiredForOAuth) {
                const keyPair = await this._pkceManager.startPKCETransaction();
                startUrl.searchParams.set('pkce_code_challenge', keyPair.code_challenge);
            } else {
                this._pkceManager.clearPKPair();
            }
            if (discovery_redirect_url) {
                startUrl.searchParams.set('discovery_redirect_url', discovery_redirect_url);
            }
            this.navigate(startUrl);
        };
    }
    // Public so it can be mocked in tests
    navigate(url) {
        window.location.href = url.toString();
    }
};

class HeadlessB2BOrganizationClient {
    _networkClient;
    _apiNetworkClient;
    _subscriptionService;
    constructor(_networkClient, _apiNetworkClient, _subscriptionService){
        this._networkClient = _networkClient;
        this._apiNetworkClient = _apiNetworkClient;
        this._subscriptionService = _subscriptionService;
    }
    get = async ()=>{
        const resp = await this._networkClient.fetchSDK({
            url: `/b2b/organizations/me`,
            method: 'GET'
        });
        this._subscriptionService.updateOrganization(resp.organization);
        return resp.organization;
    };
    getSync = ()=>{
        return this._subscriptionService.getOrganization();
    };
    getInfo = ()=>({
            organization: this.getSync(),
            fromCache: this._subscriptionService.getFromCache()
        });
    onChange = (callback)=>{
        return this._subscriptionService.subscribeToState((state)=>callback(state?.organization ?? null));
    };
    update = async (data)=>{
        const resp = await this._networkClient.fetchSDK({
            url: `/b2b/organizations/me`,
            method: 'PUT',
            body: data
        });
        this._subscriptionService.updateOrganization(resp.organization);
        return resp;
    };
    delete = async ()=>{
        const resp = await this._networkClient.fetchSDK({
            url: `/b2b/organizations/me`,
            method: 'DELETE'
        });
        this._subscriptionService.destroyState();
        return resp;
    };
    getBySlug = async (data)=>{
        dev.validateInDev('stytch.organization.getBySlug', data, {
            organization_slug: 'string'
        });
        return this._networkClient.fetchSDK({
            url: `/b2b/organizations/search`,
            method: 'POST',
            body: data
        });
    };
    getConnectedApps = async ()=>{
        return this._networkClient.fetchSDK({
            url: '/b2b/organizations/connected_apps',
            method: 'GET'
        });
    };
    getConnectedApp = async (data)=>{
        return this._networkClient.fetchSDK({
            url: `/b2b/organizations/connected_apps/${data.connected_app_id}`,
            method: 'GET'
        });
    };
    members = {
        create: async (data)=>{
            return this._networkClient.fetchSDK({
                url: `/b2b/organizations/members`,
                method: 'POST',
                body: data
            });
        },
        search: async (data)=>{
            return this._networkClient.fetchSDK({
                url: `/b2b/organizations/me/members/search`,
                method: 'POST',
                body: data
            });
        },
        update: async (data)=>{
            const response = await this._networkClient.fetchSDK({
                url: `/b2b/organizations/members/${data.member_id}`,
                method: 'PUT',
                body: data
            });
            this.updateMemberIfSelf(response);
            return response;
        },
        deletePassword: async (passwordId)=>{
            const response = await this._networkClient.fetchSDK({
                url: `/b2b/organizations/members/passwords/${passwordId}`,
                method: 'DELETE'
            });
            this.updateMemberIfSelf(response);
            return response;
        },
        deleteMFAPhoneNumber: async (memberId)=>{
            const response = await this._networkClient.fetchSDK({
                url: `/b2b/organizations/members/mfa_phone_numbers/${memberId}`,
                method: 'DELETE'
            });
            this.updateMemberIfSelf(response);
            return response;
        },
        deleteMFATOTP: async (memberId)=>{
            const response = await this._networkClient.fetchSDK({
                url: `/b2b/organizations/members/totp/${memberId}`,
                method: 'DELETE'
            });
            this.updateMemberIfSelf(response);
            return response;
        },
        delete: async (memberId)=>{
            const response = await this._networkClient.fetchSDK({
                url: `/b2b/organizations/members/${memberId}`,
                method: 'DELETE'
            });
            if (memberId === this._subscriptionService.getMember()?.member_id) {
                this._subscriptionService.destroyState();
            }
            return response;
        },
        reactivate: async (memberId)=>{
            return this._networkClient.fetchSDK({
                url: `/b2b/organizations/members/${memberId}/reactivate`,
                method: 'PUT'
            });
        },
        unlinkRetiredEmail: async (data)=>{
            const { member_id, ...body } = data;
            const response = await this._apiNetworkClient.fetchSDK({
                url: `/b2b/organizations/members/${member_id}/unlink_retired_email`,
                method: 'POST',
                body
            });
            this.updateMemberIfSelf(response);
            return response;
        },
        startEmailUpdate: async (data)=>{
            const { member_id, ...body } = data;
            const response = await this._apiNetworkClient.fetchSDK({
                url: `/b2b/organizations/members/${member_id}/start_email_update`,
                method: 'POST',
                body
            });
            this.updateMemberIfSelf(response);
            return response;
        },
        getConnectedApps: async (data)=>{
            return this._networkClient.fetchSDK({
                url: `b2b/organizations/members/${data.member_id}/connected_apps`,
                method: 'GET'
            });
        },
        revokeConnectedApp: async (data)=>{
            return this._networkClient.fetchSDK({
                url: `/b2b/organizations/members/${data.member_id}/connected_apps/${data.connected_app_id}/revoke`,
                method: 'POST'
            });
        }
    };
    updateMemberIfSelf = (response)=>{
        if (response.member_id === this._subscriptionService.getMember()?.member_id) {
            this._subscriptionService.updateMember(response.member);
        }
    };
}

class HeadlessB2BOTPsClient {
    _networkClient;
    _subscriptionService;
    dfpProtectedAuth;
    sms;
    email;
    constructor(_networkClient, _subscriptionService, dfpProtectedAuth){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
        this.dfpProtectedAuth = dfpProtectedAuth;
        this.sms = {
            send: async (data)=>{
                dev.validateInDev('stytch.otps.sms.send', data, {
                    organization_id: 'string',
                    member_id: 'string',
                    mfa_phone_number: 'optionalString',
                    locale: 'optionalString'
                });
                const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
                return this._networkClient.retriableFetchSDK({
                    url: '/b2b/otps/sms/send',
                    body: {
                        ...data,
                        dfp_telemetry_id,
                        captcha_token,
                        intermediate_session_token: this._subscriptionService.getIntermediateSessionToken() || undefined
                    },
                    method: 'POST',
                    retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
                });
            },
            authenticate: this._subscriptionService.withUpdateSession(async (data)=>{
                dev.validateInDev('stytch.otps.sms.authenticate', data, {
                    session_duration_minutes: 'number',
                    organization_id: 'string',
                    member_id: 'string',
                    code: 'string',
                    set_mfa_enrollment: 'optionalString'
                });
                const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
                const requestBody = {
                    ...data,
                    dfp_telemetry_id,
                    captcha_token,
                    intermediate_session_token: this._subscriptionService.getIntermediateSessionToken() || undefined
                };
                return this._networkClient.retriableFetchSDK({
                    url: '/b2b/otps/sms/authenticate',
                    body: requestBody,
                    method: 'POST',
                    retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
                });
            })
        };
        this.email = {
            loginOrSignup: async (data)=>{
                dev.validateInDev('stytch.otps.email.loginOrSignup', data, {
                    organization_id: 'string',
                    email_address: 'string',
                    login_template_id: 'optionalString',
                    signup_template_id: 'optionalString',
                    locale: 'optionalString',
                    login_expiration_minutes: 'optionalNumber',
                    signup_expiration_minutes: 'optionalNumber'
                });
                const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
                return this._networkClient.retriableFetchSDK({
                    url: '/b2b/otps/email/login_or_signup',
                    body: {
                        ...data,
                        dfp_telemetry_id,
                        captcha_token
                    },
                    method: 'POST',
                    retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
                });
            },
            authenticate: this._subscriptionService.withUpdateSession(async (data)=>{
                dev.validateInDev('stytch.otps.email.authenticate', data, {
                    code: 'string',
                    email_address: 'string',
                    organization_id: 'string',
                    session_duration_minutes: 'number',
                    locale: 'optionalString'
                });
                const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
                return this._networkClient.retriableFetchSDK({
                    url: '/b2b/otps/email/authenticate',
                    body: {
                        ...data,
                        intermediate_session_token: this._subscriptionService.getIntermediateSessionToken() || undefined,
                        dfp_telemetry_id,
                        captcha_token
                    },
                    method: 'POST',
                    retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
                });
            }),
            discovery: {
                send: async (data)=>{
                    dev.validateInDev('stytch.otps.email.discovery.send', data, {
                        email_address: 'string',
                        login_template_id: 'optionalString',
                        locale: 'optionalString',
                        discovery_expiration_minutes: 'optionalNumber'
                    });
                    const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
                    const requestBody = {
                        ...data,
                        dfp_telemetry_id,
                        captcha_token
                    };
                    return this._networkClient.retriableFetchSDK({
                        url: '/b2b/otps/email/discovery/send',
                        body: requestBody,
                        method: 'POST',
                        retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
                    });
                },
                authenticate: this._subscriptionService.withUpdateSession(async (data)=>{
                    dev.validateInDev('stytch.otps.email.discovery.authenticate', data, {
                        code: 'string',
                        email_address: 'string'
                    });
                    const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
                    const requestBody = {
                        dfp_telemetry_id,
                        captcha_token,
                        ...data
                    };
                    return this._networkClient.retriableFetchSDK({
                        url: '/b2b/otps/email/discovery/authenticate',
                        body: requestBody,
                        method: 'POST',
                        retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
                    });
                })
            }
        };
    }
}

class HeadlessB2BRBACClient {
    _subscriptionService;
    cachedPolicy;
    policyPromise;
    constructor(cachedConfig, dynamicConfig, _subscriptionService){
        this._subscriptionService = _subscriptionService;
        this.cachedPolicy = cachedConfig.rbacPolicy ? idpHelpers.RBACPolicy.fromJSON(cachedConfig.rbacPolicy) : null;
        this.policyPromise = dynamicConfig.then((data)=>{
            if (!data.rbacPolicy) {
                logger.logger.error('Unable to retrieve RBAC policy from servers. Assuming caller has no permissions.');
                return new idpHelpers.RBACPolicy([], []);
            }
            // Update the existing policy too, so isAuthorizedSync will be up-to-date
            this.cachedPolicy = idpHelpers.RBACPolicy.fromJSON(data.rbacPolicy);
            return this.cachedPolicy;
        });
    }
    /**
   * Gets the effective policy for the current session by merging project policy with org custom roles
   */ async getEffectivePolicy() {
        const projectPolicy = await this.policyPromise;
        const organization = this._subscriptionService.getOrganization();
        // If no org or no custom roles, just return project policy
        if (!organization?.custom_roles?.length) {
            return projectPolicy;
        }
        return projectPolicy.mergeWithCustomRoles(organization.custom_roles);
    }
    /**
   * Gets the effective policy synchronously for the current session
   * Uses cached policies only
   */ getEffectivePolicySync() {
        if (!this.cachedPolicy) {
            return null;
        }
        const organization = this._subscriptionService.getOrganization();
        // If no custom roles, just return project policy
        if (!organization?.custom_roles?.length) {
            return this.cachedPolicy;
        }
        return this.cachedPolicy.mergeWithCustomRoles(organization.custom_roles);
    }
    allPermissions() {
        return this.getEffectivePolicy().then((policy)=>policy.allPermissionsForCaller(this.roleIds()));
    }
    isAuthorizedSync = (resourceId, action)=>{
        const effectivePolicy = this.getEffectivePolicySync();
        return !!effectivePolicy?.callerIsAuthorized(this.roleIds(), resourceId, action);
    };
    isAuthorized = (resourceId, action)=>{
        return this.getEffectivePolicy().then((policy)=>policy.callerIsAuthorized(this.roleIds(), resourceId, action));
    };
    roleIds() {
        const session = this._subscriptionService.getSession();
        if (!session) {
            return [];
        }
        // Although session.roles is guaranteed to exist for fresh data, there is a minuscule chance
        // that the member session stored in localstorage clientside comes from before roles were added to
        // the API response - in which case session.roles will be undefined and this will crash
        // TODO: [AUTH-2294] We can safely remove this ~3mos after RBAC is released
        return session.roles ?? [];
    }
}

class HeadlessB2BRecoveryCodesClient {
    _networkClient;
    _subscriptionService;
    dfpProtectedAuth;
    recover;
    constructor(_networkClient, _subscriptionService, dfpProtectedAuth){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
        this.dfpProtectedAuth = dfpProtectedAuth;
        this.recover = this._subscriptionService.withUpdateSession(async (data)=>{
            dev.validateInDev('stytch.recoveryCodes.recover', data, {
                organization_id: 'string',
                member_id: 'string',
                recovery_code: 'string',
                session_duration_minutes: 'number'
            });
            const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
            const requestBody = {
                ...data,
                dfp_telemetry_id,
                captcha_token,
                intermediate_session_token: this._subscriptionService.getIntermediateSessionToken() || undefined
            };
            return this._networkClient.retriableFetchSDK({
                url: '/b2b/recovery_codes/recover',
                body: requestBody,
                method: 'POST',
                retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
            });
        });
    }
    async rotate() {
        const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
        return this._networkClient.retriableFetchSDK({
            url: '/b2b/recovery_codes/rotate',
            body: {
                dfp_telemetry_id,
                captcha_token
            },
            method: 'POST',
            retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
        });
    }
    async get() {
        return this._networkClient.fetchSDK({
            url: '/b2b/recovery_codes',
            method: 'GET'
        });
    }
}

class HeadlessB2BSCIMClient {
    _networkClient;
    _subscriptionService;
    constructor(_networkClient, _subscriptionService){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
    }
    async createConnection(data) {
        dev.validateInDev('stytch.scim.createConnection', data, {
            display_name: 'optionalString',
            identity_provider: 'optionalString'
        });
        return await this._networkClient.fetchSDK({
            url: '/b2b/scim',
            method: 'POST',
            body: data
        });
    }
    async updateConnection(data) {
        dev.validateInDev('stytch.scim.updateConnection', data, {
            connection_id: 'string',
            display_name: 'optionalString',
            identity_provider: 'optionalString'
        });
        return await this._networkClient.fetchSDK({
            url: `/b2b/scim/${data.connection_id}`,
            method: 'PUT',
            body: data
        });
    }
    async deleteConnection(connectionId) {
        dev.validateInDev('stytch.scim.deleteConnection', {
            connection_id: connectionId
        }, {
            connection_id: 'string'
        });
        return await this._networkClient.fetchSDK({
            url: `/b2b/scim/${connectionId}`,
            method: 'DELETE'
        });
    }
    async getConnection() {
        return await this._networkClient.fetchSDK({
            url: '/b2b/scim',
            method: 'GET'
        });
    }
    async getConnectionGroups(data) {
        dev.validateInDev('stytch.scim.getConnectionGroups', data, {
            limit: 'optionalNumber',
            cursor: 'optionalString'
        });
        return await this._networkClient.fetchSDK({
            url: '/b2b/scim/groups',
            method: 'POST',
            body: data
        });
    }
    async rotateStart(connectionId) {
        dev.validateInDev('stytch.scim.rotateStart', {
            connectionId
        }, {
            connectionId: 'string'
        });
        return await this._networkClient.fetchSDK({
            url: `/b2b/scim/rotate/start`,
            method: 'POST',
            body: {
                connection_id: connectionId
            }
        });
    }
    async rotateComplete(connectionId) {
        dev.validateInDev('stytch.scim.rotateComplete', {
            connectionId
        }, {
            connectionId: 'string'
        });
        return await this._networkClient.fetchSDK({
            url: `/b2b/scim/rotate/complete`,
            method: 'POST',
            body: {
                connection_id: connectionId
            }
        });
    }
    async rotateCancel(connectionId) {
        dev.validateInDev('stytch.scim.rotateCancel', {
            connectionId
        }, {
            connectionId: 'string'
        });
        return await this._networkClient.fetchSDK({
            url: `/b2b/scim/rotate/cancel`,
            method: 'POST',
            body: {
                connection_id: connectionId
            }
        });
    }
}

class HeadlessB2BSelfClient {
    _networkClient;
    _apiNetworkClient;
    _subscriptionService;
    constructor(_networkClient, _apiNetworkClient, _subscriptionService){
        this._networkClient = _networkClient;
        this._apiNetworkClient = _apiNetworkClient;
        this._subscriptionService = _subscriptionService;
    }
    get = async ()=>{
        const resp = await this._networkClient.fetchSDK({
            url: `/b2b/organizations/members/me`,
            method: 'GET'
        });
        this._subscriptionService.updateMember(resp.member);
        return resp.member;
    };
    getSync = ()=>{
        return this._subscriptionService.getMember();
    };
    getInfo = ()=>({
            member: this.getSync(),
            fromCache: this._subscriptionService.getFromCache()
        });
    onChange = (callback)=>{
        return this._subscriptionService.subscribeToState((state)=>callback(state?.member ?? null));
    };
    update = async (data)=>{
        dev.validateInDev('stytch.self.update', data, {
            name: 'optionalString',
            untrusted_metadata: 'optionalObject',
            mfa_enrolled: 'optionalBoolean',
            mfa_phone_number: 'optionalString',
            default_mfa_method: 'optionalString'
        });
        const resp = await this._networkClient.fetchSDK({
            url: '/b2b/organizations/members/update',
            body: data,
            method: 'PUT'
        });
        this._subscriptionService.updateMember(resp.member);
        return resp;
    };
    deleteMFAPhoneNumber = async ()=>{
        const resp = await this._networkClient.fetchSDK({
            url: '/b2b/organizations/members/deletePhoneNumber',
            method: 'DELETE'
        });
        this._subscriptionService.updateMember(resp.member);
        return resp;
    };
    deleteMFATOTP = async ()=>{
        const resp = await this._networkClient.fetchSDK({
            url: `/b2b/organizations/members/deleteTOTP`,
            method: 'DELETE'
        });
        this._subscriptionService.updateMember(resp.member);
        return resp;
    };
    deletePassword = async (passwordId)=>{
        const resp = await this._networkClient.fetchSDK({
            url: `/b2b/organizations/members/passwords/${passwordId}`,
            method: 'DELETE'
        });
        this._subscriptionService.updateMember(resp.member);
        return resp;
    };
    unlinkRetiredEmail = async (data)=>{
        const resp = await this._apiNetworkClient.fetchSDK({
            url: '/b2b/organizations/members/unlink_retired_email',
            method: 'POST',
            body: data
        });
        this._subscriptionService.updateMember(resp.member);
        return resp;
    };
    startEmailUpdate = async (data)=>{
        const resp = await this._apiNetworkClient.fetchSDK({
            url: '/b2b/organizations/members/start_email_update',
            method: 'POST',
            body: data
        });
        this._subscriptionService.updateMember(resp.member);
        return resp;
    };
    getConnectedApps = async ()=>{
        return this._networkClient.fetchSDK({
            url: '/b2b/organizations/members/connected_apps',
            method: 'GET'
        });
    };
    revokeConnectedApp = async (data)=>{
        return this._networkClient.fetchSDK({
            url: `/b2b/organizations/members/connected_apps/${data.connected_app_id}/revoke`,
            method: 'POST'
        });
    };
}

class HeadlessB2BSessionClient {
    _networkClient;
    _subscriptionService;
    getSync = ()=>{
        return this._subscriptionService.getSession();
    };
    getInfo = ()=>({
            session: this.getSync(),
            fromCache: this._subscriptionService.getFromCache()
        });
    onChange = (callback)=>{
        return this._subscriptionService.subscribeToState((state)=>callback(state?.session ?? null));
    };
    revoke = async (options)=>{
        /**
     * Revoke destroys the local state if the API request is successful
     * or if we return an unrecoverable error (user is unauthenticated)
     * or if the developer passes in a forceClear option.
     * If the API request returns a recoverable error (the user is offline),
     * we do not destroy the local state to let the developer manually add retry
     * logic to call revoke again.
     */ try {
            const resp = await this._networkClient.fetchSDK({
                url: `/b2b/sessions/revoke`,
                method: 'POST'
            });
            this._subscriptionService.destroyState();
            return resp;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        } catch (error) {
            if (options?.forceClear) {
                this._subscriptionService.destroyState();
            } else if (dev.UNRECOVERABLE_ERROR_TYPES.includes(error.error_type)) {
                this._subscriptionService.destroyState();
            }
            throw error;
        }
    };
    revokeForMember = async (options)=>{
        dev.validateInDev('stytch.session.revokeForMember', options, {
            member_id: 'string'
        });
        return await this._networkClient.fetchSDK({
            url: `/b2b/sessions/revoke/${options.member_id}`,
            method: 'POST'
        });
    };
    _authenticate = async (options)=>{
        const initialSession = this._subscriptionService.getSession();
        const isSessionStale = ()=>initialSession?.member_session_id !== this._subscriptionService.getSession()?.member_session_id;
        try {
            const requestBody = {
                session_duration_minutes: options?.session_duration_minutes
            };
            const resp = await this._networkClient.fetchSDK({
                url: '/b2b/sessions/authenticate',
                body: requestBody,
                method: 'POST'
            });
            if (isSessionStale()) {
                // [SDK-1336] The session was updated out from under us while the
                // request was in flight; discard the response and retry
                return this._authenticate(options);
            }
            return resp;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        } catch (error) {
            if (isSessionStale()) {
                // [SDK-1336] The session was updated out from under us while the
                // request was in flight; discard the response and retry
                return this._authenticate(options);
            }
            if (dev.UNRECOVERABLE_ERROR_TYPES.includes(error.error_type)) {
                this._subscriptionService.destroySession();
            }
            throw error;
        }
    };
    authenticate;
    exchange;
    exchangeAccessToken;
    attest;
    constructor(_networkClient, _subscriptionService){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
        this.authenticate = this._subscriptionService.withUpdateSession(this._authenticate);
        this.exchange = this._subscriptionService.withUpdateSession(async (data)=>{
            dev.validateInDev('stytch.session.exchange', data, {
                organization_id: 'string',
                session_duration_minutes: 'number',
                locale: 'optionalString'
            });
            return this._networkClient.fetchSDK({
                url: '/b2b/sessions/exchange',
                body: data,
                method: 'POST'
            });
        });
        this.exchangeAccessToken = this._subscriptionService.withUpdateSession(async (data)=>{
            dev.validateInDev('stytch.session.exchange', data, {
                access_token: 'string',
                session_duration_minutes: 'number'
            });
            return this._networkClient.fetchSDK({
                url: '/b2b/sessions/exchange_access_token',
                body: data,
                method: 'POST'
            });
        });
        this.attest = this._subscriptionService.withUpdateSession(async (data)=>{
            dev.validateInDev('stytch.session.attest', data, {
                organization_id: 'optionalString',
                profile_id: 'string',
                token: 'string',
                session_duration_minutes: 'optionalNumber'
            });
            return this._networkClient.fetchSDK({
                url: '/b2b/sessions/attest',
                body: data,
                method: 'POST'
            });
        });
    }
    getTokens() {
        return this._subscriptionService.getTokens();
    }
    updateSession(tokens) {
        dev.validateInDev('stytch.session.updateSession', tokens, {
            session_token: 'string',
            session_jwt: 'optionalString'
        });
        this._subscriptionService.updateTokens(tokens);
    }
}

class HeadlessB2BSSOClient {
    _networkClient;
    _subscriptionService;
    _pkceManager;
    _dynamicConfig;
    _config;
    dfpProtectedAuth;
    authenticate;
    constructor(_networkClient, _subscriptionService, _pkceManager, _dynamicConfig, _config, dfpProtectedAuth){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
        this._pkceManager = _pkceManager;
        this._dynamicConfig = _dynamicConfig;
        this._config = _config;
        this.dfpProtectedAuth = dfpProtectedAuth;
        this.authenticate = this._subscriptionService.withUpdateSession(async (options)=>{
            dev.validateInDev('stytch.sso.authenticate', options, {
                sso_token: 'string',
                session_duration_minutes: 'number',
                locale: 'optionalString'
            });
            const keyPair = await this._pkceManager.getPKPair();
            if (!keyPair) {
                logger.logger.warn('No code verifier found in local storage for SSO flow.\n' + 'Consider using stytch.sso.start() to add PKCE to your SSO flows for added security.\n' + 'See https://stytch.com/docs/oauth#guides_pkce for more information.');
            }
            const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
            const resp = await this._networkClient.retriableFetchSDK({
                url: '/b2b/sso/authenticate',
                method: 'POST',
                body: {
                    pkce_code_verifier: keyPair?.code_verifier,
                    ...options,
                    dfp_telemetry_id,
                    captcha_token,
                    intermediate_session_token: this._subscriptionService.getIntermediateSessionToken() || undefined
                },
                retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
            });
            this._pkceManager.clearPKPair();
            return resp;
        });
    }
    async getBaseApiUrl() {
        // Our TestAPIURL and LiveAPIURL should have the HTTPS protocol already attached
        // Don't add it twice!
        if (idpHelpers.isTestPublicToken(this._config.publicToken)) {
            return this._config.testAPIURL;
        }
        return this._config.liveAPIURL;
    }
    async start({ connection_id, login_redirect_url, signup_redirect_url }) {
        const { pkceRequiredForSso } = await this._dynamicConfig;
        const baseURL = await this.getBaseApiUrl();
        const startUrl = new URL(`${baseURL}/v1/public/sso/start`);
        startUrl.searchParams.set('public_token', this._config.publicToken);
        startUrl.searchParams.set('connection_id', connection_id);
        if (pkceRequiredForSso) {
            const keyPair = await this._pkceManager.startPKCETransaction();
            startUrl.searchParams.set('pkce_code_challenge', keyPair.code_challenge);
        } else {
            this._pkceManager.clearPKPair();
        }
        if (login_redirect_url) startUrl.searchParams.set('login_redirect_url', login_redirect_url);
        if (signup_redirect_url) startUrl.searchParams.set('signup_redirect_url', signup_redirect_url);
        this.navigate(startUrl);
    }
    // Public so it can be mocked in tests
    navigate(url) {
        window.location.href = url.toString();
    }
    async getConnections() {
        return await this._networkClient.fetchSDK({
            url: '/b2b/sso',
            method: 'GET'
        });
    }
    async discoverConnections(emailAddress) {
        return await this._networkClient.fetchSDK({
            url: `/b2b/sso/discovery/connections?email_address=${encodeURIComponent(emailAddress)}`,
            method: 'GET'
        });
    }
    async deleteConnection(connectionId) {
        return this._networkClient.fetchSDK({
            url: `/b2b/sso/${connectionId}`,
            method: 'DELETE'
        });
    }
    saml = {
        createConnection: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: '/b2b/sso/saml',
                method: 'POST',
                body: data
            });
        },
        updateConnection: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: `/b2b/sso/saml/${data.connection_id}`,
                method: 'PUT',
                body: data
            });
        },
        updateConnectionByURL: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: `/b2b/sso/saml/${data.connection_id}/url`,
                method: 'PUT',
                body: data
            });
        },
        deleteVerificationCertificate: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: `/b2b/sso/saml/${data.connection_id}/verification_certificates/${data.certificate_id}`,
                method: 'DELETE'
            });
        },
        deleteEncryptionPrivateKey: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: `/b2b/sso/saml/${data.connection_id}/encryption_private_key/${data.private_key_id}`,
                method: 'DELETE'
            });
        }
    };
    oidc = {
        createConnection: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: '/b2b/sso/oidc',
                method: 'POST',
                body: data
            });
        },
        updateConnection: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: `/b2b/sso/oidc/${data.connection_id}`,
                method: 'PUT',
                body: data
            });
        }
    };
    external = {
        createConnection: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: '/b2b/sso/external',
                method: 'POST',
                body: data
            });
        },
        updateConnection: async (data)=>{
            return await this._networkClient.fetchSDK({
                url: `/b2b/sso/external/${data.connection_id}`,
                method: 'PUT',
                body: data
            });
        }
    };
}

class HeadlessB2BTOTPsClient {
    _networkClient;
    _subscriptionService;
    dfpProtectedAuth;
    authenticate;
    constructor(_networkClient, _subscriptionService, dfpProtectedAuth){
        this._networkClient = _networkClient;
        this._subscriptionService = _subscriptionService;
        this.dfpProtectedAuth = dfpProtectedAuth;
        this.authenticate = this._subscriptionService.withUpdateSession(async (data)=>{
            dev.validateInDev('stytch.totp.authenticate', data, {
                organization_id: 'string',
                member_id: 'string',
                code: 'string',
                session_duration_minutes: 'number',
                set_mfa_enrollment: 'optionalString',
                set_default_mfa: 'optionalBoolean'
            });
            const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
            const requestBody = {
                ...data,
                dfp_telemetry_id,
                captcha_token,
                intermediate_session_token: this._subscriptionService.getIntermediateSessionToken() || undefined
            };
            return this._networkClient.retriableFetchSDK({
                url: '/b2b/totp/authenticate',
                body: requestBody,
                method: 'POST',
                retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
            });
        });
    }
    async create(data) {
        dev.validateInDev('stytch.totp.create', data, {
            organization_id: 'string',
            member_id: 'string',
            expiration_minutes: 'optionalNumber'
        });
        const { dfp_telemetry_id, captcha_token } = await this.dfpProtectedAuth.getDFPTelemetryIDAndCaptcha();
        const response = await this._networkClient.retriableFetchSDK({
            url: '/b2b/totp',
            body: {
                ...data,
                dfp_telemetry_id,
                captcha_token,
                intermediate_session_token: await this._subscriptionService.getIntermediateSessionToken() || undefined
            },
            method: 'POST',
            retryCallback: this.dfpProtectedAuth.retryWithCaptchaAndDFP
        });
        if (response.member_id === this._subscriptionService.getMember()?.member_id) {
            this._subscriptionService.updateMember(response.member);
        }
        return response;
    }
}

class HeadlessB2BOAuthClient extends HeadlessB2BOAuthClient$1 {
    _oneTap;
    constructor(_networkClient, _subscriptionService, _pkceManager, _dynamicConfig, _config, _dfpProtectedAuth = idpHelpers.DisabledDFPProtectedAuthProvider(), _oneTap){
        super(_networkClient, _subscriptionService, _pkceManager, _dynamicConfig, _config, _dfpProtectedAuth), this._oneTap = _oneTap;
    }
    startOneTapDiscovery = async (options)=>{
        const clientResult = await this._oneTap.createOneTapClient();
        if (!clientResult.success) {
            throw new Error(`One Tap could not load: ${clientResult.reason}`);
        }
        const { client } = clientResult;
        const onSuccessCallback = this._oneTap.createOnDiscoverySuccessHandler({
            discoveryRedirectUrl: options.discovery_redirect_url,
            onSuccess: this._oneTap.redirectOnSuccess
        });
        return client.render({
            style: {
                position: StytchSSRProxy.OneTapPositions.floating
            },
            callback: onSuccessCallback,
            cancelOnTapOutside: options.cancel_on_tap_outside
        });
    };
    startOneTap = async (options)=>{
        if (!options.organization_id) {
            throw new dev.StytchSDKUsageError('stytch.oauth.googleOneTap.start', 'organization_id is a required argument');
        }
        const clientResult = await this._oneTap.createOneTapClient();
        if (!clientResult.success) {
            throw new Error(`One Tap could not load: ${clientResult.reason}`);
        }
        const { client } = clientResult;
        const onSuccessCallback = this._oneTap.createOnSuccessHandler({
            organizationId: options.organization_id,
            signupRedirectUrl: options.signup_redirect_url,
            loginRedirectUrl: options.login_redirect_url,
            onSuccess: this._oneTap.redirectOnSuccess
        });
        return client.render({
            style: {
                position: StytchSSRProxy.OneTapPositions.floating
            },
            callback: onSuccessCallback,
            cancelOnTapOutside: options.cancel_on_tap_outside
        });
    };
    googleOneTap = {
        discovery: {
            start: this.startOneTapDiscovery
        },
        start: this.startOneTap
    };
}

const DefaultDynamicConfig = Promise.resolve({
    pkceRequiredForOAuth: false
});
/**
 * Handles loading One Tap config from Stytch API and initializing {@link GoogleOneTapClient}
 */ class B2BOneTapProvider {
    _networkClient;
    _pkceManager;
    _config;
    googleClientID;
    constructor(_networkClient, _pkceManager, _config = DefaultDynamicConfig){
        this._networkClient = _networkClient;
        this._pkceManager = _pkceManager;
        this._config = _config;
    }
    async fetchGoogleStart() {
        if (this.googleClientID) {
            return this.googleClientID;
        }
        const oneTapStartResp = await this._networkClient.fetchSDK({
            url: '/b2b/oauth/google/onetap/start',
            method: 'GET'
        });
        this.googleClientID = oneTapStartResp.google_client_id;
        return this.googleClientID;
    }
    async submitGoogleOneTapTokenDiscovery({ credential, discoveryRedirectUrl }) {
        let codeChallenge = undefined;
        const { pkceRequiredForOAuth } = await this._config;
        if (pkceRequiredForOAuth) {
            const keyPair = await this._pkceManager.startPKCETransaction();
            codeChallenge = keyPair.code_challenge;
        } else {
            this._pkceManager.clearPKPair();
        }
        return await this._networkClient.fetchSDK({
            url: '/b2b/oauth/google/onetap/discovery/submit',
            method: 'POST',
            body: {
                id_token: credential,
                discovery_redirect_url: discoveryRedirectUrl,
                pkce_code_challenge: codeChallenge
            }
        });
    }
    async submitGoogleOneTapToken({ credential, organizationId, signupRedirectUrl, loginRedirectUrl }) {
        let codeChallenge = undefined;
        const { pkceRequiredForOAuth } = await this._config;
        if (pkceRequiredForOAuth) {
            const keyPair = await this._pkceManager.startPKCETransaction();
            codeChallenge = keyPair.code_challenge;
        } else {
            this._pkceManager.clearPKPair();
        }
        return await this._networkClient.fetchSDK({
            url: '/b2b/oauth/google/onetap/submit',
            method: 'POST',
            body: {
                id_token: credential,
                organization_id: organizationId,
                signup_redirect_url: signupRedirectUrl,
                login_redirect_url: loginRedirectUrl,
                pkce_code_challenge: codeChallenge
            }
        });
    }
    async createOneTapClient() {
        let googleClientId;
        try {
            googleClientId = await this.fetchGoogleStart();
        } catch (e) {
            const err = dev.StytchAPIError.from(e);
            return {
                success: false,
                reason: err.error_type
            };
        }
        if (googleClientId === '') {
            return {
                success: false,
                reason: 'oauth_config_not_found'
            };
        }
        const client = new idpHelpers.GoogleOneTapClient(await idpHelpers.loadGoogleOneTapClient(), googleClientId);
        return {
            success: true,
            client
        };
    }
    createOnDiscoverySuccessHandler = ({ discoveryRedirectUrl, onSuccess, onError })=>async (response)=>{
            const { credential } = response;
            let submitPromise = this.submitGoogleOneTapTokenDiscovery({
                credential,
                discoveryRedirectUrl
            }).then((result)=>onSuccess(result.redirect_url));
            if (onError) {
                submitPromise = submitPromise.catch((error)=>onError(error));
            }
            await submitPromise;
        };
    createOnSuccessHandler = ({ organizationId, signupRedirectUrl, loginRedirectUrl, onSuccess, onError })=>async (response)=>{
            const { credential } = response;
            let submitPromise = this.submitGoogleOneTapToken({
                credential,
                organizationId,
                signupRedirectUrl,
                loginRedirectUrl
            }).then((result)=>onSuccess(result.redirect_url));
            if (onError) {
                submitPromise = submitPromise.catch((error)=>onError(error));
            }
            await submitPromise;
        };
    redirectOnSuccess = (redirect_url)=>{
        window.location.href = redirect_url;
    };
}

/**
 * A headless client used for invoking Stytch's B2B APIs.
 * The Stytch Headless Client can be used as a drop-in solution for authentication and session management.
 * Full documentation can be found {@link https://stytch.com/docs/b2b/sdks/javascript-sdk online}.
 *
 * @example
 * const stytch = new StytchB2BClient('public-token-<find yours in the stytch dashboard>');
 * stytch.magicLinks.email.loginOrCreate({
 *   email: 'sandbox@stytch.com',
 *   organization_id: 'organization-test-123',
 * });
 */ class StytchB2BClient {
    _subscriptionService;
    _sessionManager;
    _networkClient;
    _dataLayer;
    _stateChangeClient;
    // External API Clients
    magicLinks;
    session;
    /** @deprecated Please use client.self instead. This will be removed in a future release. */ member;
    self;
    organization;
    oauth;
    sso;
    discovery;
    passwords;
    otps;
    totp;
    recoveryCodes;
    rbac;
    scim;
    impersonation;
    idp;
    // External methods
    /**
   * Register a callback function to be invoked whenever certain state changes
   * occur, like a member or session object being updated.
   *
   * This is an alternative to more specific methods like `self.onChange` and
   * `session.onChange`. It can be helpful if you want to be notified of related
   * changes to different parts of state at once.
   *
   * If you are only interested in specific state changes, consider using more
   * specific methods like `self.onChange` and `session.onChange` instead.
   */ onStateChange;
    /**
   * Extracts token and token type from the current page URL's query parameters.
   * If the current URL do not have the required query params, this will return null.
   * Otherwise, returns an object { handled: boolean, tokenType: string, token: string }
   */ parseAuthenticateUrl;
    /**
   * Call this method to authenticate the user when the user has been redirected
   * to this page with a token in the query parameters, such as after OAuth
   * or through an email magic link. This method currently supports
   *
   * - Magic links
   * - OAuth
   * - SSO
   * - Impersonation
   *
   * If the current URL do not have the required query params, the promise returned will resolve to null.
   * If the token type is not supported (e.g. reset_password), the promise returned will resolve to this
   * object allowing you to handle the token.
   * {
   *   handled: false,
   *   tokenType: 'token_type',
   *   token: '<token>'
   * }
   */ authenticateByUrl;
    constructor(rawPublicToken, options){
        idpHelpers.checkB2BNotSSR();
        // Intentionally check the raw public token so that we can log a correct error message,
        // but then coalesce to an empty string so that the UI components don't fail to render.
        idpHelpers.checkPublicToken(rawPublicToken);
        const _PUBLIC_TOKEN = rawPublicToken ?? '';
        // Not casting to InternalStytchClientOptions since InternalStytchClientOptions is currently a superset
        const config = idpHelpers.buildFinalConfig(this.constructor.name, options);
        const usingCustomApiEndpoint = idpHelpers.hasCustomApiEndpoint(_PUBLIC_TOKEN, options);
        this._dataLayer = idpHelpers.getB2BDataLayer(_PUBLIC_TOKEN, config);
        this._subscriptionService = new idpHelpers.B2BSubscriptionService(_PUBLIC_TOKEN, this._dataLayer, {
            usingCustomApiEndpoint
        });
        this._stateChangeClient = new idpHelpers.StateChangeClient(this._subscriptionService, {});
        this.onStateChange = (...args)=>this._stateChangeClient.onStateChange(...args);
        const additionalTelemetryDataFn = ()=>({
                stytch_member_id: this._dataLayer.state?.member?.member_id,
                stytch_member_session_id: this._dataLayer.state?.session?.member_session_id
            });
        const passwordsPKCEManager = new idpHelpers.PKCEManager(this._dataLayer, 'passwords');
        const networkClient = new idpHelpers.NetworkClient(_PUBLIC_TOKEN, this._dataLayer, config.endpoints.liveAPIURL, config.endpoints.testAPIURL, additionalTelemetryDataFn);
        this._networkClient = networkClient;
        const bootstrap = new idpHelpers.BootstrapDataManager(_PUBLIC_TOKEN, networkClient, this._dataLayer);
        const captcha = new idpHelpers.CaptchaProvider(bootstrap.getAsync());
        const dfpProtectedAuth = new idpHelpers.DFPProtectedAuthProvider(_PUBLIC_TOKEN, config.endpoints.dfpBackendURL, config.endpoints.dfpCdnURL, bootstrap.getAsync(), captcha.executeRecaptcha);
        const clientsideServices = new idpHelpers.ClientsideServicesProvider(config.endpoints.clientsideServicesIframeURL);
        const pkceManagerForOAuth = new idpHelpers.PKCEManager(this._dataLayer, 'oauth');
        const oneTap = new B2BOneTapProvider(networkClient, pkceManagerForOAuth, bootstrap.getAsync());
        this.organization = new HeadlessB2BOrganizationClient(networkClient, networkClient, this._subscriptionService);
        this.member = new HeadlessB2BSelfClient(networkClient, networkClient, this._subscriptionService);
        this.self = new HeadlessB2BSelfClient(networkClient, networkClient, this._subscriptionService);
        this.session = new HeadlessB2BSessionClient(networkClient, this._subscriptionService);
        this.magicLinks = new idpHelpers.HeadlessB2BMagicLinksClient(networkClient, this._subscriptionService, new idpHelpers.PKCEManager(this._dataLayer, 'magic_links'), passwordsPKCEManager, bootstrap.getAsync(), dfpProtectedAuth);
        this.oauth = new HeadlessB2BOAuthClient(networkClient, this._subscriptionService, pkceManagerForOAuth, bootstrap.getAsync(), {
            publicToken: _PUBLIC_TOKEN,
            testAPIURL: config.endpoints.testAPIURL,
            liveAPIURL: config.endpoints.liveAPIURL
        }, dfpProtectedAuth, oneTap);
        this.sso = new HeadlessB2BSSOClient(networkClient, this._subscriptionService, new idpHelpers.PKCEManager(this._dataLayer, 'sso'), bootstrap.getAsync(), {
            publicToken: _PUBLIC_TOKEN,
            testAPIURL: config.endpoints.testAPIURL,
            liveAPIURL: config.endpoints.liveAPIURL
        }, dfpProtectedAuth);
        this.discovery = new HeadlessB2BDiscoveryClient(networkClient, this._subscriptionService);
        this.passwords = new idpHelpers.HeadlessB2BPasswordsClient(networkClient, this._subscriptionService, passwordsPKCEManager, bootstrap.getAsync(), dfpProtectedAuth);
        this.otps = new HeadlessB2BOTPsClient(networkClient, this._subscriptionService, dfpProtectedAuth);
        this.totp = new HeadlessB2BTOTPsClient(networkClient, this._subscriptionService, dfpProtectedAuth);
        this.recoveryCodes = new HeadlessB2BRecoveryCodesClient(networkClient, this._subscriptionService, dfpProtectedAuth);
        this.rbac = new HeadlessB2BRBACClient(bootstrap.getSync(), bootstrap.getAsync(), this._subscriptionService);
        this.scim = new HeadlessB2BSCIMClient(this._networkClient, this._subscriptionService);
        this.impersonation = new HeadlessB2BImpersonationClient(this._networkClient, this._subscriptionService, dfpProtectedAuth);
        this.idp = new HeadlessB2BIDPClient(networkClient);
        this._sessionManager = new idpHelpers.SessionManager(this._subscriptionService, this.session, _PUBLIC_TOKEN, {
            keepSessionAlive: config.keepSessionAlive
        });
        const searchManager = new idpHelpers.SearchDataManager(networkClient, dfpProtectedAuth);
        // If the session does not exist in localstorage (like if we are in an iframe)
        // then the cookie might still be set and we can retrieve the session via an API call.
        // If a custom API endpoint is being used, the session may be being managed by
        // HttpOnly cookies, which we can't detect.
        if (usingCustomApiEndpoint || this._dataLayer.readSessionCookie().session_token) {
            this._sessionManager.performBackgroundRefresh();
        }
        const { authenticateByUrl, parseAuthenticateUrl } = idpHelpers.createAuthUrlHandler({
            discovery: (token)=>this.magicLinks.discovery.authenticate({
                    discovery_magic_links_token: token
                }),
            discovery_oauth: (token)=>this.oauth.discovery.authenticate({
                    discovery_oauth_token: token
                }),
            oauth: (token, options)=>this.oauth.authenticate({
                    oauth_token: token,
                    ...options
                }),
            sso: (token, options)=>this.sso.authenticate({
                    sso_token: token,
                    ...options
                }),
            multi_tenant_magic_links: (token, options)=>this.magicLinks.authenticate({
                    magic_links_token: token,
                    ...options
                }),
            multi_tenant_impersonation: (token)=>this.impersonation.authenticate({
                    impersonation_token: token
                })
        });
        this.authenticateByUrl = authenticateByUrl;
        this.parseAuthenticateUrl = parseAuthenticateUrl;
        networkClient.logEvent({
            name: 'b2b_sdk_instance_instantiated',
            details: {
                event_callback_registered: false,
                error_callback_registered: false,
                success_callback_registered: false
            }
        });
        bootstrap.getAsync().then((bootstrapData)=>{
            if (bootstrapData.vertical === idpHelpers.VERTICAL_CONSUMER) {
                logger.logger.error('This application is using a Stytch client for B2B projects, but the public token is for a Stytch Consumer project. Use a Consumer Stytch client instead, or verify that the public token is correct.');
            }
        });
        const internals = {
            bootstrap,
            clientsideServices,
            publicToken: _PUBLIC_TOKEN,
            searchManager,
            dataLayer: this._dataLayer,
            networkClient: networkClient,
            oneTap
        };
        StytchSSRProxy.writeB2BInternals(this, internals);
    }
}

/**
 * Creates a Headless Stytch client object to call the stytch B2B APIs.
 * The Stytch client is not available serverside.
 * @example
 * const stytch = createStytchB2BClient('public-token-<find yours in the stytch dashboard>')
 *
 * return (
 *   <StytchB2BProvider stytch={stytch}>
 *     <App />
 *   </StytchB2BProvider>
 * )
 * @returns A {@link StytchB2BClient}
 */ const createStytchB2BClient = StytchSSRProxy.ssrSafeClientFactory(StytchB2BClient);
/**
 * @deprecated Use {createStytchB2BClient()} instead
 */ const createStytchB2BHeadlessClient = createStytchB2BClient;
/**
 * @deprecated Use {StytchB2BClient()} instead
 */ const StytchB2BHeadlessClient = StytchB2BClient;

exports.AuthFlowType = StytchSSRProxy.AuthFlowType;
exports.B2BMFAProducts = StytchSSRProxy.B2BMFAProducts;
exports.B2BOAuthProviders = StytchSSRProxy.B2BOAuthProviders;
exports.OAuthProviders = StytchSSRProxy.OAuthProviders;
exports.OTPMethods = StytchSSRProxy.OTPMethods;
exports.OneTapPositions = StytchSSRProxy.OneTapPositions;
exports.RNUIProducts = StytchSSRProxy.RNUIProducts;
exports.RedirectURLType = StytchSSRProxy.RedirectURLType;
exports.StytchEventType = StytchSSRProxy.StytchEventType;
exports.Wallets = StytchSSRProxy.Wallets;
exports.parseOAuthAuthorizeParams = idpHelpers.parseOAuthAuthorizeParams;
exports.parseOAuthLogoutParams = idpHelpers.parseOAuthLogoutParams;
exports.BiometricRegistrationIdIsNullOrBlank = dev.BiometricRegistrationIdIsNullOrBlank;
exports.BiometricsAlreadyEnrolledError = dev.BiometricsAlreadyEnrolledError;
exports.BiometricsFailedError = dev.BiometricsFailedError;
exports.BiometricsUnavailableError = dev.BiometricsUnavailableError;
exports.ChallengeSigningFailedError = dev.ChallengeSigningFailedError;
exports.DFPNotConfigured = dev.DFPNotConfigured;
exports.DeviceCredentialsNotAllowedError = dev.DeviceCredentialsNotAllowedError;
exports.FailedCodeChallengeError = dev.FailedCodeChallengeError;
exports.FailedToDecryptDataError = dev.FailedToDecryptDataError;
exports.IDPOAuthFlowMissingParamError = dev.IDPOAuthFlowMissingParamError;
exports.InternalError = dev.InternalError;
exports.InvalidAuthorizationCredentialError = dev.InvalidAuthorizationCredentialError;
exports.InvalidCredentialTypeError = dev.InvalidCredentialTypeError;
exports.InvalidPrivateKeyLength = dev.InvalidPrivateKeyLength;
exports.InvalidRedirectSchemeError = dev.InvalidRedirectSchemeError;
exports.InvalidStartUrlError = dev.InvalidStartUrlError;
exports.JSONDataNotConvertibleToStringError = dev.JSONDataNotConvertibleToStringError;
exports.KeyInvalidatedError = dev.KeyInvalidatedError;
exports.KeystoreUnavailableError = dev.KeystoreUnavailableError;
exports.MissingAttestationObjectError = dev.MissingAttestationObjectError;
exports.MissingAuthorizationCredentialIDTokenError = dev.MissingAuthorizationCredentialIDTokenError;
exports.MissingCipherIv = dev.MissingCipherIv;
exports.MissingGoogleClientIDError = dev.MissingGoogleClientIDError;
exports.MissingPKCEError = dev.MissingPKCEError;
exports.MissingPublicKeyError = dev.MissingPublicKeyError;
exports.MissingUrlError = dev.MissingUrlError;
exports.NoBiometricsEnrolledError = dev.NoBiometricsEnrolledError;
exports.NoBiometricsRegistrationError = dev.NoBiometricsRegistrationError;
exports.NoCredentialsPresentError = dev.NoCredentialsPresentError;
exports.NoCurrentSessionError = dev.NoCurrentSessionError;
exports.PasskeysInvalidEncoding = dev.PasskeysInvalidEncoding;
exports.PasskeysMisconfigured = dev.PasskeysMisconfigured;
exports.PasskeysUnsupportedError = dev.PasskeysUnsupportedError;
exports.RandomNumberGenerationFailed = dev.RandomNumberGenerationFailed;
exports.SDKAPIUnreachableError = dev.SDKAPIUnreachableError;
exports.SDKNotConfiguredError = dev.SDKNotConfiguredError;
exports.SignInWithAppleMisconfigured = dev.SignInWithAppleMisconfigured;
exports.StytchAPIError = dev.StytchAPIError;
exports.StytchAPISchemaError = dev.StytchAPISchemaError;
exports.StytchAPIUnreachableError = dev.StytchAPIUnreachableError;
exports.StytchError = dev.StytchError;
exports.StytchSDKAPIError = dev.StytchSDKAPIError;
exports.StytchSDKError = dev.StytchSDKError;
exports.StytchSDKSchemaError = dev.StytchSDKSchemaError;
exports.StytchSDKUsageError = dev.StytchSDKUsageError;
exports.UNRECOVERABLE_ERROR_TYPES = dev.UNRECOVERABLE_ERROR_TYPES;
exports.UserCancellationError = dev.UserCancellationError;
exports.UserLockedOutError = dev.UserLockedOutError;
exports.errorToStytchError = dev.errorToStytchError;
exports.StytchB2BClient = StytchB2BClient;
exports.StytchB2BHeadlessClient = StytchB2BHeadlessClient;
exports.createStytchB2BClient = createStytchB2BClient;
exports.createStytchB2BHeadlessClient = createStytchB2BHeadlessClient;
//# sourceMappingURL=index.headless.cjs.map
