/* eslint-disable lingui/no-unlocalized-strings -- user-facing strings in this file can be overridden using different APIs */ const OPENID_CONSENT_ITEM = {
    text: 'Verify your identity',
    details: [
        'View information stored within your account'
    ]
};
// Full Access didn't really make the cut
// const FULL_ACCESS_CONSENT_ITEM: IDPConsentItem = {
//   text: 'Act on behalf of you',
//   details: [],
// };
const PROFILE_CONSENT_ITEM = {
    text: 'View your personal profile information'};
const OFFLINE_ACCESS_CONSENT_ITEM = {
    text: "Maintain access to your data even when you're not actively using the app",
    details: [
        'Access your data even when you are offline.',
        'Synchronize data and process background tasks on your behalf.'
    ]
};
const OPENID_SCOPE = 'openid';
const PROFILE_SCOPE = 'profile';
const EMAIL_SCOPE = 'email';
const PHONE_SCOPE = 'phone';
const FULL_ACCESS_SCOPE = 'full_access';
const OFFLINE_ACCESS_SCOPE = 'offline_access';
const DEFAULT_SCOPES = new Set([
    OPENID_SCOPE,
    PROFILE_SCOPE,
    EMAIL_SCOPE,
    PHONE_SCOPE,
    FULL_ACCESS_SCOPE,
    OFFLINE_ACCESS_SCOPE
]);
// Scope is an optional param in OAuth2.1
// When no scope is present, this is what we default to
const FALLBACK_SCOPES = [
    OPENID_SCOPE,
    EMAIL_SCOPE,
    PROFILE_SCOPE
];
const containsCustomScopes = (scope)=>{
    // set.difference is not in ES2015
    return scope.split(' ').some((sc)=>!DEFAULT_SCOPES.has(sc));
};
const createBuiltinScopeDescriptions = (scopes)=>{
    const descriptions = [];
    if (scopes.includes(OPENID_SCOPE)) {
        descriptions.push(OPENID_CONSENT_ITEM);
    }
    if (scopes.includes(EMAIL_SCOPE) || scopes.includes(PROFILE_SCOPE) || scopes.includes(PHONE_SCOPE)) {
        descriptions.push(createProfileScopeDescription({
            containsEmail: scopes.includes(EMAIL_SCOPE),
            containsPhoneNumber: scopes.includes(PHONE_SCOPE),
            containsProfile: scopes.includes(PROFILE_SCOPE)
        }));
    }
    // if (scopes.has(FULL_ACCESS_SCOPE)) {
    //   descriptions.push();
    // }
    if (scopes.includes(OFFLINE_ACCESS_SCOPE)) {
        descriptions.push(OFFLINE_ACCESS_CONSENT_ITEM);
    }
    return descriptions;
};
const createProfileScopeDescription = ({ containsProfile, containsEmail, containsPhoneNumber })=>{
    const details = [];
    if (containsProfile) {
        details.push('Your name, profile picture, and language preferences');
    }
    if (containsEmail) {
        details.push('Your email address');
    }
    if (containsPhoneNumber) {
        details.push('Your phone number');
    }
    return {
        text: PROFILE_CONSENT_ITEM.text,
        details: details
    };
};
const createCustomScopeDescriptions = (scopes, rbacPolicy)=>{
    if (!rbacPolicy) return [];
    const descriptions = [];
    for (const scope of scopes){
        if (DEFAULT_SCOPES.has(scope)) continue;
        const found = rbacPolicy.scopes.find((policyScope)=>policyScope.scope === scope);
        if (found && found.description) {
            descriptions.push(found.description);
        } else {
            descriptions.push(`Use the ${scope} scope`);
        }
    }
    return descriptions;
};
const fallbackConsentManifestGenerator = ({ scopes, clientName, rbacPolicy })=>{
    return [
        {
            header: `${clientName} is requesting to:`,
            items: createBuiltinScopeDescriptions(scopes).concat(createCustomScopeDescriptions(scopes, rbacPolicy))
        }
    ];
};
/**
 * Parse the OAuth Authorize params from the URL search parameters to pass in to subsequent OAuthAuthorize calls.
 *
 * @param params - The URL search parameters to parse.
 * @returns The parsed OAuth Authorize parameters.
 */ const parseOAuthAuthorizeParams = (params)=>{
    const authorizeParams = {
        client_id: '',
        redirect_uri: '',
        // As of writing, ChatGPT isn't sending `response_type` when making calls to our
        // authorization endpoint, even though it's technically a required field in the spec.
        // We default it to 'code' here and server-side.
        // See: https://stytchio.slack.com/archives/C07U0MHAH7G/p1749075544763149.
        response_type: 'code',
        // Default to this initial set of scopes when the client does not provide this param
        scopes: [
            ...FALLBACK_SCOPES
        ]
    };
    const requiredFields = [
        'client_id',
        'redirect_uri'
    ];
    for (const field of requiredFields){
        const value = params.get(field);
        if (!value) {
            return {
                error: `Required parameter is missing: ${field}. Please reach out to the application developer.`,
                result: authorizeParams
            };
        }
        authorizeParams[field] = value;
    }
    const optionalStringFields = [
        'response_type',
        'scope',
        'code_challenge',
        'state',
        'nonce',
        'prompt'
    ];
    for (const field of optionalStringFields){
        const value = params.get(field);
        if (value) {
            if (field === 'scope') {
                authorizeParams.scopes = value.split(' ').filter(Boolean);
            } else {
                authorizeParams[field] = value;
            }
        }
    }
    if (params.has('resource')) {
        authorizeParams.resources = params.getAll('resource');
    }
    return {
        error: null,
        result: authorizeParams
    };
};
const parseOAuthLogoutParams = (params)=>{
    const logoutParams = {
        client_id: '',
        post_logout_redirect_uri: ''
    };
    const requiredFields = [
        'client_id',
        'post_logout_redirect_uri'
    ];
    for (const field of requiredFields){
        const value = params.get(field);
        if (!value) {
            return {
                error: `Required parameter is missing: ${field}. Please reach out to the application developer.`,
                result: logoutParams
            };
        }
        logoutParams[field] = value;
    }
    logoutParams.id_token_hint = params.get('id_token_hint') || undefined;
    logoutParams.state = params.get('state') || undefined;
    return {
        error: null,
        result: logoutParams
    };
};
/**
 * Parse generic IDP parameters and determine if it is an Authorize or Logout request.
 */ const parseIDPParams = (searchParams)=>{
    const params = new URLSearchParams(searchParams);
    // Check if `post_logout_redirect_uri` exists to determine if it's a Logout request.
    if (params.has('post_logout_redirect_uri')) {
        const logoutResult = parseOAuthLogoutParams(params);
        return {
            error: logoutResult.error,
            flow: {
                type: 'Logout',
                params: logoutResult.result
            }
        };
    }
    // Otherwise, assume it's an Authorize request.
    const authorizeResult = parseOAuthAuthorizeParams(params);
    return {
        error: authorizeResult.error,
        flow: {
            type: 'Authorize',
            params: authorizeResult.result
        }
    };
};

export { containsCustomScopes, createBuiltinScopeDescriptions, createCustomScopeDescriptions, fallbackConsentManifestGenerator, parseIDPParams, parseOAuthAuthorizeParams, parseOAuthLogoutParams };
//# sourceMappingURL=idpHelpers.mjs.map
