import {z} from 'zod' export type PasswordType = string; export type WebAuthnAuthenticationResponse = {id: string, rawId: string, type: 'public-key', authenticatorAttachment?: ('cross-platform' | 'platform') | undefined, clientExtensionResults: {appid?: boolean | undefined, credProps?: ({rk?: boolean | undefined} | {[key: string]: unknown}) | undefined, hmacCreateSecret?: boolean | undefined} | {[key: string]: unknown}, response: {clientDataJSON: string, authenticatorData: string, signature: string, userHandle?: string | undefined} | {[key: string]: unknown}} | {[key: string]: unknown}; export type WebAuthnTwoFactorRequest = {enabled: boolean, password?: PasswordType | undefined, mfa_method?: ('totp' | 'webauthn' | 'email_code') | undefined, mfa_code?: string | undefined, email_code_ticket?: string | undefined, email_code?: string | undefined, webauthn_response?: WebAuthnAuthenticationResponse | undefined, webauthn_challenge?: string | undefined}; export type UpdateApiUsersMeMfaWebauthnTwoFactorArgs = {body: WebAuthnTwoFactorRequest}; export type UpdateApiUsersMeMfaWebauthnTwoFactorOptions = {baseUrl?: string | undefined, sessionToken?: string | undefined, fetch?: typeof fetch | undefined}; export const snowflakeStringType = z.string(); export const int32Type = z.number().int().gte(0).lte(2147483647); export const publicUserFlags = z.number().int().gte(0).lte(2147483647); export const mentionReplyPreferences = z.union([z.literal(0), z.literal(1), z.literal(2)]); export const profileFieldPrivacyFlags = z.number().int().gte(0).lte(2147483647); export const userAuthenticatorTypes = z.union([z.literal(0), z.literal(2)]); export const userPremiumTypes = z.union([z.literal(0), z.literal(1), z.literal(2)]); export const accountTierSchema = z.enum(["unclaimed", "unverified", "verified"]); export const accountVerificationNeedSchema = z.enum(["add_email", "confirm_email", "password"]); export const userPrivateResponse = z.object({id: snowflakeStringType, username: z.string(), discriminator: z.string(), global_name: z.string().nullable(), avatar: z.string().nullable(), avatar_color: int32Type.nullable(), bot: z.boolean().optional(), system: z.boolean().optional(), flags: publicUserFlags, mention_flags: mentionReplyPreferences.optional(), is_staff: z.boolean(), acls: z.array(z.string()), traits: z.array(z.string()), email: z.string().nullable(), email_bounced: z.boolean().optional(), has_verified_phone: z.boolean(), bio: z.string().nullable(), pronouns: z.string().nullable(), accent_color: int32Type.nullable(), timezone: z.string().nullable().optional(), timezone_privacy_flags: profileFieldPrivacyFlags.optional(), banner: z.string().nullable(), banner_color: int32Type.nullable(), mfa_enabled: z.boolean(), authenticator_types: z.array(userAuthenticatorTypes).optional(), verified: z.boolean(), account_limited: z.boolean().optional(), premium_type: userPremiumTypes.nullable(), premium_since: z.string().nullable(), premium_until: z.string().nullable(), premium_will_cancel: z.boolean(), premium_billing_cycle: z.string().nullable(), premium_lifetime_sequence: int32Type.nullable(), premium_grace_ends_at: z.string().nullable(), premium_discriminator: z.boolean(), hidden_profile_badges: z.array(z.string()), premium_badge_hidden: z.boolean(), premium_badge_masked: z.boolean(), premium_badge_timestamp_hidden: z.boolean(), premium_badge_sequence_hidden: z.boolean(), premium_purchase_disabled: z.boolean(), premium_enabled_override: z.boolean(), premium_perks_disabled: z.boolean(), operator_pass_badge_hidden: z.boolean().optional(), operator_pass_badge_timestamp_hidden: z.boolean().optional(), operator_pass_badge_count_hidden: z.boolean().optional(), operator_pass_since: z.string().nullable().optional(), password_last_changed_at: z.string().nullable(), last_voice_activity_sharing_change_at: z.string().nullable(), required_actions: z.array(z.string()), nsfw_allowed: z.boolean(), has_dismissed_premium_onboarding: z.boolean(), has_ever_purchased: z.boolean(), has_unread_gift_inventory: z.boolean(), unread_gift_inventory_count: int32Type, pending_bulk_message_deletion: z.object({scheduled_at: z.string(), channel_count: int32Type, message_count: int32Type}).nullable(), mature_content_unlocked: z.boolean().optional(), terms_agreed_at: z.string().nullable(), privacy_agreed_at: z.string().nullable(), claimed: z.boolean().optional(), account_tier: accountTierSchema.optional(), verification_need: accountVerificationNeedSchema.nullable().optional(), has_password: z.boolean().optional(), date_of_birth_required: z.boolean().optional(), has_age_range: z.boolean().optional(), profile_restricted: z.boolean().optional()}); export const webAuthnTwoFactorResponse = z.object({user: userPrivateResponse, backup_codes: z.array(z.object({code: z.string(), consumed: z.boolean()})).nullable()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Set WebAuthn two-factor authentication * * PUT /users/@me/mfa/webauthn/two-factor */ export const updateApiUsersMeMfaWebauthnTwoFactor = async (args: UpdateApiUsersMeMfaWebauthnTwoFactorArgs, options?: UpdateApiUsersMeMfaWebauthnTwoFactorOptions) => { const {baseUrl = "https://web.fluxer.app/api/v1", fetch: fetchFn = fetch, sessionToken} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (sessionToken !== undefined) headers.set("Authorization", sessionToken) const url = `${baseUrl.replace(/\/+$/, '')}/users/@me/mfa/webauthn/two-factor${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "PUT", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(webAuthnTwoFactorResponse, await res.json()) };