mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 05:25:40 +09:00
refactor progress
This commit is contained in:
8257 files changed
+1190205
-761038
No files matched your search
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
createNamedStringLiteralUnion,
|
||||
createStringType,
|
||||
SnowflakeStringType,
|
||||
withOpenApiType,
|
||||
} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const HarvestStatusEnum = withOpenApiType(
|
||||
createNamedStringLiteralUnion(
|
||||
[
|
||||
['pending', 'pending', 'The harvest job is waiting to be processed'],
|
||||
['processing', 'processing', 'The harvest job is currently being processed'],
|
||||
['completed', 'completed', 'The harvest job has finished successfully'],
|
||||
['failed', 'failed', 'The harvest job encountered an error and could not complete'],
|
||||
],
|
||||
'Current status of the harvest request',
|
||||
),
|
||||
'HarvestStatus',
|
||||
);
|
||||
|
||||
export const HarvestCreationResponseSchema = z.object({
|
||||
harvest_id: SnowflakeStringType.describe('Unique identifier for the harvest request'),
|
||||
status: HarvestStatusEnum,
|
||||
created_at: z.string().describe('ISO 8601 timestamp when the harvest request was created'),
|
||||
});
|
||||
|
||||
export const HarvestStatusResponseSchema = HarvestCreationResponseSchema.extend({
|
||||
started_at: z.string().nullable().describe('ISO 8601 timestamp when the harvest started, or null if pending'),
|
||||
completed_at: z.string().nullable().describe('ISO 8601 timestamp when the harvest completed, or null otherwise'),
|
||||
failed_at: z.string().nullable().describe('ISO 8601 timestamp when the harvest failed, or null otherwise'),
|
||||
file_size: z
|
||||
.string()
|
||||
.nullable()
|
||||
.describe('Final file size of the downloaded data, expressed as a string, or null if not available'),
|
||||
progress_percent: z.number().describe('Harvest progress as a percentage value between 0 and 100'),
|
||||
progress_step: z.string().nullable().describe('Textual description of the current harvest step, if available'),
|
||||
error_message: z.string().nullable().describe('Error message when the harvest fails, or null otherwise'),
|
||||
download_url_expires_at: z
|
||||
.string()
|
||||
.nullable()
|
||||
.describe('ISO 8601 timestamp when the download URL expires, or null if unavailable'),
|
||||
expires_at: z
|
||||
.string()
|
||||
.nullable()
|
||||
.describe('ISO 8601 timestamp when the harvest download expires, or null if unavailable'),
|
||||
});
|
||||
|
||||
export type HarvestCreationResponse = z.infer<typeof HarvestCreationResponseSchema>;
|
||||
export type HarvestStatusResponse = z.infer<typeof HarvestStatusResponseSchema>;
|
||||
|
||||
export const HarvestStatusResponseSchemaNullable = HarvestStatusResponseSchema.nullable();
|
||||
|
||||
export const HarvestDownloadUrlResponse = z.object({
|
||||
download_url: createStringType(1, 2048).describe('The presigned URL to download the harvest archive'),
|
||||
expires_at: z.string().describe('ISO 8601 timestamp when the harvest download expires'),
|
||||
});
|
||||
export type HarvestDownloadUrlResponse = z.infer<typeof HarvestDownloadUrlResponse>;
|
||||
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {AVATAR_MAX_SIZE} from '@fluxer/constants/src/LimitConstants';
|
||||
import {StatusTypes} from '@fluxer/constants/src/StatusConstants';
|
||||
import {
|
||||
DEFAULT_GUILD_FOLDER_ICON,
|
||||
FriendSourceFlags,
|
||||
FriendSourceFlagsDescriptions,
|
||||
GroupDmAddPermissionFlags,
|
||||
GroupDmAddPermissionFlagsDescriptions,
|
||||
GuildFolderFlags,
|
||||
GuildFolderFlagsDescriptions,
|
||||
GuildFolderIcons,
|
||||
IncomingCallFlags,
|
||||
IncomingCallFlagsDescriptions,
|
||||
ThemeTypes,
|
||||
} from '@fluxer/constants/src/UserConstants';
|
||||
import {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
|
||||
import {SudoVerificationSchema} from '@fluxer/schema/src/domains/auth/AuthSchemas';
|
||||
import {isValidSingleUnicodeEmoji} from '@fluxer/schema/src/primitives/EmojiValidators';
|
||||
import {createBase64StringType} from '@fluxer/schema/src/primitives/FileValidators';
|
||||
import {LocaleSchema} from '@fluxer/schema/src/primitives/LocaleSchema';
|
||||
import {createQueryIntegerType, DateTimeType, QueryBooleanType} from '@fluxer/schema/src/primitives/QueryValidators';
|
||||
import {
|
||||
ColorType,
|
||||
createBitflagInt32Type,
|
||||
createNamedStringLiteralUnion,
|
||||
createStringType,
|
||||
Int32Type,
|
||||
SignedInt32Type,
|
||||
SnowflakeStringType,
|
||||
SnowflakeType,
|
||||
withFieldDescription,
|
||||
withOpenApiType,
|
||||
} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {URLType} from '@fluxer/schema/src/primitives/UrlValidators';
|
||||
import {
|
||||
RelationshipTypesSchema,
|
||||
RenderSpoilersSchema,
|
||||
StickerAnimationOptionsSchema,
|
||||
TimeFormatTypesSchema,
|
||||
UserNotificationSettingsSchema,
|
||||
} from '@fluxer/schema/src/primitives/UserSettingsValidators';
|
||||
import {
|
||||
DiscriminatorType,
|
||||
EmailType,
|
||||
GlobalNameType,
|
||||
PasswordType,
|
||||
UsernameType,
|
||||
} from '@fluxer/schema/src/primitives/UserValidators';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const UserUpdateRequest = z
|
||||
.object({
|
||||
username: UsernameType.describe('The username for the account (1-32 characters)'),
|
||||
discriminator: DiscriminatorType.describe('The 4-digit discriminator tag'),
|
||||
global_name: GlobalNameType.nullish().describe('The display name shown to other users'),
|
||||
email: EmailType.describe('The email address for the account'),
|
||||
new_password: PasswordType.describe('The new password to set'),
|
||||
password: PasswordType.describe('The current password for verification'),
|
||||
avatar: createBase64StringType(1, AVATAR_MAX_SIZE * 1.33)
|
||||
.nullish()
|
||||
.describe('Base64-encoded avatar image'),
|
||||
banner: createBase64StringType(1, AVATAR_MAX_SIZE * 1.33)
|
||||
.nullish()
|
||||
.describe('Base64-encoded profile banner image'),
|
||||
bio: createStringType(1, 320).nullish().describe('User biography text (max 320 characters)'),
|
||||
pronouns: createStringType(1, 40).nullish().describe('User pronouns (max 40 characters)'),
|
||||
accent_color: ColorType.nullish().describe('Profile accent color as integer'),
|
||||
premium_badge_hidden: z.boolean().describe('Whether to hide the premium badge'),
|
||||
premium_badge_masked: z.boolean().describe('Whether to mask the premium badge'),
|
||||
premium_badge_timestamp_hidden: z.boolean().describe('Whether to hide premium badge timestamp'),
|
||||
premium_badge_sequence_hidden: z.boolean().describe('Whether to hide premium badge sequence'),
|
||||
premium_enabled_override: z.boolean().describe('Override premium enabled state'),
|
||||
has_dismissed_premium_onboarding: z.boolean().describe('Whether user dismissed premium onboarding'),
|
||||
has_unread_gift_inventory: z.boolean().describe('Whether user has unread gifts'),
|
||||
used_mobile_client: z.boolean().describe('Whether user has used mobile client'),
|
||||
})
|
||||
.partial();
|
||||
|
||||
export type UserUpdateRequest = z.infer<typeof UserUpdateRequest>;
|
||||
|
||||
const EmailTokenType = createStringType(1, 256);
|
||||
|
||||
export const UserUpdateWithVerificationRequest = UserUpdateRequest.merge(
|
||||
z.object({
|
||||
email_token: EmailTokenType.optional().describe('Email change token for updating email'),
|
||||
}),
|
||||
)
|
||||
.merge(SudoVerificationSchema)
|
||||
.superRefine((data, ctx) => {
|
||||
if (data.email !== undefined) {
|
||||
ctx.addIssue({
|
||||
code: 'custom',
|
||||
message: ValidationErrorCodes.EMAIL_MUST_BE_CHANGED_VIA_TOKEN,
|
||||
path: ['email'],
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export type UserUpdateWithVerificationRequest = z.infer<typeof UserUpdateWithVerificationRequest>;
|
||||
|
||||
export const EmailChangeTicketRequest = z.object({
|
||||
ticket: createStringType().describe('Email change ticket identifier'),
|
||||
});
|
||||
|
||||
export type EmailChangeTicketRequest = z.infer<typeof EmailChangeTicketRequest>;
|
||||
|
||||
export const EmailChangeVerifyOriginalRequest = EmailChangeTicketRequest.extend({
|
||||
code: createStringType().describe('Verification code sent to the original email address'),
|
||||
});
|
||||
|
||||
export type EmailChangeVerifyOriginalRequest = z.infer<typeof EmailChangeVerifyOriginalRequest>;
|
||||
|
||||
export const EmailChangeRequestNewRequest = EmailChangeTicketRequest.extend({
|
||||
new_email: EmailType.describe('New email address to switch to'),
|
||||
original_proof: createStringType().describe('Proof token obtained from verifying the original email'),
|
||||
});
|
||||
|
||||
export type EmailChangeRequestNewRequest = z.infer<typeof EmailChangeRequestNewRequest>;
|
||||
|
||||
export const EmailChangeVerifyNewRequest = EmailChangeVerifyOriginalRequest.extend({
|
||||
original_proof: createStringType().describe('Proof token obtained from verifying the original email'),
|
||||
});
|
||||
|
||||
export type EmailChangeVerifyNewRequest = z.infer<typeof EmailChangeVerifyNewRequest>;
|
||||
|
||||
export const EmailChangeBouncedRequestNewRequest = z.object({
|
||||
new_email: EmailType.describe('Replacement email address used when the current email has bounced'),
|
||||
});
|
||||
|
||||
export type EmailChangeBouncedRequestNewRequest = z.infer<typeof EmailChangeBouncedRequestNewRequest>;
|
||||
|
||||
export const EmailChangeBouncedVerifyNewRequest = EmailChangeTicketRequest.extend({
|
||||
code: createStringType().describe('Verification code sent to the replacement email address'),
|
||||
});
|
||||
|
||||
export type EmailChangeBouncedVerifyNewRequest = z.infer<typeof EmailChangeBouncedVerifyNewRequest>;
|
||||
|
||||
export const PasswordChangeTicketRequest = z.object({
|
||||
ticket: createStringType().describe('Password change ticket identifier'),
|
||||
});
|
||||
|
||||
export type PasswordChangeTicketRequest = z.infer<typeof PasswordChangeTicketRequest>;
|
||||
|
||||
export const PasswordChangeVerifyRequest = PasswordChangeTicketRequest.extend({
|
||||
code: createStringType().describe('Verification code sent to the email address'),
|
||||
});
|
||||
|
||||
export type PasswordChangeVerifyRequest = z.infer<typeof PasswordChangeVerifyRequest>;
|
||||
|
||||
export const PasswordChangeCompleteRequest = PasswordChangeTicketRequest.extend({
|
||||
verification_proof: createStringType().describe('Proof token obtained from verifying the email code'),
|
||||
new_password: PasswordType.describe('The new password to set'),
|
||||
});
|
||||
|
||||
export type PasswordChangeCompleteRequest = z.infer<typeof PasswordChangeCompleteRequest>;
|
||||
|
||||
export const FriendRequestByTagRequest = z.object({
|
||||
username: UsernameType.describe('Username of the user to send friend request'),
|
||||
discriminator: DiscriminatorType.describe('Discriminator tag of the user'),
|
||||
});
|
||||
|
||||
export type FriendRequestByTagRequest = z.infer<typeof FriendRequestByTagRequest>;
|
||||
|
||||
export const RelationshipNicknameUpdateRequest = z.object({
|
||||
nickname: createStringType(0, 256).nullable().describe('Custom nickname for this friend (max 256 characters)'),
|
||||
});
|
||||
|
||||
export type RelationshipNicknameUpdateRequest = z.infer<typeof RelationshipNicknameUpdateRequest>;
|
||||
|
||||
export const RelationshipTypePutRequest = z
|
||||
.object({
|
||||
type: withFieldDescription(RelationshipTypesSchema, 'Type of relationship to create').optional(),
|
||||
})
|
||||
.optional();
|
||||
|
||||
export type RelationshipTypePutRequest = z.infer<typeof RelationshipTypePutRequest>;
|
||||
|
||||
export const CustomStatusPayload = z
|
||||
.object({
|
||||
text: createStringType(1, 128).nullish().describe('Custom status text (max 128 characters)'),
|
||||
expires_at: DateTimeType.nullish().describe('When the custom status expires'),
|
||||
emoji_id: SnowflakeType.nullish().describe('ID of custom emoji to display'),
|
||||
emoji_name: createStringType(2, 32).nullish().describe('Unicode emoji or custom emoji name'),
|
||||
})
|
||||
.transform((value) => {
|
||||
if (value.emoji_id != null) {
|
||||
return {...value, emoji_name: undefined};
|
||||
}
|
||||
return value;
|
||||
})
|
||||
.refine((value) => value.emoji_name == null || isValidSingleUnicodeEmoji(value.emoji_name), {
|
||||
message: 'Emoji name must be a valid Unicode emoji',
|
||||
path: ['emoji_name'],
|
||||
})
|
||||
.refine((value) => value.expires_at == null || value.expires_at.getTime() > Date.now(), {
|
||||
message: 'expires_at must be in the future',
|
||||
path: ['expires_at'],
|
||||
});
|
||||
|
||||
export type CustomStatusPayload = z.infer<typeof CustomStatusPayload>;
|
||||
|
||||
const GuildFolderIconSchema = withOpenApiType(
|
||||
createNamedStringLiteralUnion(
|
||||
[
|
||||
[GuildFolderIcons.FOLDER, 'FOLDER', 'Classic folder icon'],
|
||||
[GuildFolderIcons.STAR, 'STAR', 'Star icon'],
|
||||
[GuildFolderIcons.HEART, 'HEART', 'Heart icon'],
|
||||
[GuildFolderIcons.BOOKMARK, 'BOOKMARK', 'Bookmark icon'],
|
||||
[GuildFolderIcons.GAME_CONTROLLER, 'GAME_CONTROLLER', 'Game controller icon'],
|
||||
[GuildFolderIcons.SHIELD, 'SHIELD', 'Shield icon'],
|
||||
[GuildFolderIcons.MUSIC_NOTE, 'MUSIC_NOTE', 'Music note icon'],
|
||||
] as const,
|
||||
'Guild folder icon',
|
||||
),
|
||||
'GuildFolderIconType',
|
||||
);
|
||||
|
||||
export const CreatePrivateChannelRequest = z
|
||||
.object({
|
||||
recipient_id: SnowflakeType.optional().describe('User ID for creating a DM channel'),
|
||||
recipients: z.array(SnowflakeType).max(9).optional().describe('Array of user IDs for creating a group DM (max 9)'),
|
||||
})
|
||||
.refine((data) => (data.recipient_id && !data.recipients) || (!data.recipient_id && data.recipients), {
|
||||
message: 'Either recipient_id or recipients must be provided, but not both',
|
||||
});
|
||||
|
||||
export type CreatePrivateChannelRequest = z.infer<typeof CreatePrivateChannelRequest>;
|
||||
|
||||
const GuildFolderSchema = z.object({
|
||||
id: SignedInt32Type.describe('Unique identifier for the folder (-1 for uncategorized)'),
|
||||
name: createStringType(0, 100).nullish().describe('Display name of the folder'),
|
||||
color: Int32Type.nullish().describe('Color of the folder as integer'),
|
||||
flags: createBitflagInt32Type(
|
||||
GuildFolderFlags,
|
||||
GuildFolderFlagsDescriptions,
|
||||
'Bitfield for guild folder display behaviour',
|
||||
'GuildFolderFlags',
|
||||
)
|
||||
.default(0)
|
||||
.describe('Bitfield for guild folder display behaviour'),
|
||||
icon: GuildFolderIconSchema.default(DEFAULT_GUILD_FOLDER_ICON).describe('Selected icon for the guild folder'),
|
||||
guild_ids: z.array(SnowflakeType).max(200).describe('Guild IDs in this folder'),
|
||||
});
|
||||
|
||||
export const UserStatusType = withOpenApiType(
|
||||
createNamedStringLiteralUnion(
|
||||
[
|
||||
[StatusTypes.ONLINE, 'ONLINE', 'User is online and available'],
|
||||
[StatusTypes.DND, 'DND', 'Do not disturb – notifications are suppressed'],
|
||||
[StatusTypes.IDLE, 'IDLE', 'User is away or inactive'],
|
||||
[StatusTypes.INVISIBLE, 'INVISIBLE', 'User appears offline but can still receive messages'],
|
||||
] as const,
|
||||
'User online status',
|
||||
),
|
||||
'UserStatusType',
|
||||
);
|
||||
|
||||
export const UserThemeType = withOpenApiType(
|
||||
createNamedStringLiteralUnion(
|
||||
[
|
||||
[ThemeTypes.DARK, 'DARK', 'Dark colour theme'],
|
||||
[ThemeTypes.COAL, 'COAL', 'Coal/darker colour theme'],
|
||||
[ThemeTypes.LIGHT, 'LIGHT', 'Light colour theme'],
|
||||
[ThemeTypes.SYSTEM, 'SYSTEM', 'Follow system colour preference'],
|
||||
] as const,
|
||||
'UI theme preference',
|
||||
),
|
||||
'UserThemeType',
|
||||
);
|
||||
|
||||
export const UserSettingsUpdateRequest = z
|
||||
.object({
|
||||
flags: createBitflagInt32Type(
|
||||
FriendSourceFlags,
|
||||
FriendSourceFlagsDescriptions,
|
||||
'Friend source flags',
|
||||
'FriendSourceFlags',
|
||||
),
|
||||
status: UserStatusType,
|
||||
status_resets_at: DateTimeType.nullish().describe('When status resets'),
|
||||
status_resets_to: UserStatusType.nullish(),
|
||||
theme: UserThemeType,
|
||||
locale: LocaleSchema,
|
||||
restricted_guilds: z.array(SnowflakeType).max(200).describe('Guilds with DM restrictions'),
|
||||
bot_restricted_guilds: z.array(SnowflakeType).max(200).describe('Guilds with bot DM restrictions'),
|
||||
default_guilds_restricted: z.boolean().describe('Default DM restriction for new guilds'),
|
||||
bot_default_guilds_restricted: z.boolean().describe('Default bot DM restriction for new guilds'),
|
||||
inline_attachment_media: z.boolean().describe('Display attachments inline'),
|
||||
inline_embed_media: z.boolean().describe('Display embed media inline'),
|
||||
gif_auto_play: z.boolean().describe('Auto-play GIFs'),
|
||||
render_embeds: z.boolean().describe('Render message embeds'),
|
||||
render_reactions: z.boolean().describe('Display reactions'),
|
||||
animate_emoji: z.boolean().describe('Animate custom emoji'),
|
||||
animate_stickers: withFieldDescription(StickerAnimationOptionsSchema, 'Sticker animation preference'),
|
||||
render_spoilers: withFieldDescription(RenderSpoilersSchema, 'Spoiler rendering preference'),
|
||||
message_display_compact: z.boolean().describe('Compact message display'),
|
||||
friend_source_flags: createBitflagInt32Type(
|
||||
FriendSourceFlags,
|
||||
FriendSourceFlagsDescriptions,
|
||||
'Friend request source permissions',
|
||||
'FriendSourceFlags',
|
||||
),
|
||||
incoming_call_flags: createBitflagInt32Type(
|
||||
IncomingCallFlags,
|
||||
IncomingCallFlagsDescriptions,
|
||||
'Incoming call settings',
|
||||
'IncomingCallFlags',
|
||||
),
|
||||
group_dm_add_permission_flags: createBitflagInt32Type(
|
||||
GroupDmAddPermissionFlags,
|
||||
GroupDmAddPermissionFlagsDescriptions,
|
||||
'Group DM add permissions',
|
||||
'GroupDmAddPermissionFlags',
|
||||
),
|
||||
guild_folders: z.array(GuildFolderSchema).max(200).describe('Guild folder organization'),
|
||||
custom_status: CustomStatusPayload.nullish().describe('Custom status'),
|
||||
afk_timeout: z.number().int().describe('AFK timeout in seconds'),
|
||||
time_format: withFieldDescription(TimeFormatTypesSchema, 'Time format preference'),
|
||||
developer_mode: z.boolean().describe('Developer mode enabled'),
|
||||
trusted_domains: z
|
||||
.array(z.string().min(1).max(253))
|
||||
.max(1000)
|
||||
.describe('Trusted external link domains. Use "*" to trust all domains.'),
|
||||
default_hide_muted_channels: z.boolean().describe('Hide muted channels by default in new guilds'),
|
||||
})
|
||||
.partial();
|
||||
|
||||
export type UserSettingsUpdateRequest = z.infer<typeof UserSettingsUpdateRequest>;
|
||||
|
||||
const MuteConfigSchema = z
|
||||
.object({
|
||||
end_time: DateTimeType.nullish().describe('When the mute expires'),
|
||||
selected_time_window: z.number().int().describe('Selected mute duration'),
|
||||
})
|
||||
.nullish();
|
||||
|
||||
const ChannelOverrideSchema = z.object({
|
||||
collapsed: z.boolean().describe('Channel category collapsed'),
|
||||
message_notifications: withFieldDescription(UserNotificationSettingsSchema, 'Channel notification level'),
|
||||
muted: z.boolean().describe('Channel muted'),
|
||||
mute_config: MuteConfigSchema.describe('Channel mute configuration'),
|
||||
});
|
||||
|
||||
export const UserGuildSettingsUpdateRequest = z
|
||||
.object({
|
||||
message_notifications: withFieldDescription(UserNotificationSettingsSchema, 'Default guild notification level'),
|
||||
muted: z.boolean().describe('Guild muted'),
|
||||
mute_config: MuteConfigSchema.describe('Guild mute configuration'),
|
||||
mobile_push: z.boolean().describe('Mobile push notifications enabled'),
|
||||
suppress_everyone: z.boolean().describe('Suppress @everyone mentions'),
|
||||
suppress_roles: z.boolean().describe('Suppress role mentions'),
|
||||
hide_muted_channels: z.boolean().describe('Hide muted channels'),
|
||||
channel_overrides: z
|
||||
.record(SnowflakeStringType, ChannelOverrideSchema)
|
||||
.nullable()
|
||||
.describe('Per-channel overrides'),
|
||||
})
|
||||
.partial();
|
||||
|
||||
export type UserGuildSettingsUpdateRequest = z.infer<typeof UserGuildSettingsUpdateRequest>;
|
||||
|
||||
export const EmptyBodyRequest = z.object({}).optional();
|
||||
export type EmptyBodyRequest = z.infer<typeof EmptyBodyRequest>;
|
||||
|
||||
export const UserTagCheckQueryRequest = z.object({
|
||||
username: UsernameType.describe('The username to check'),
|
||||
discriminator: DiscriminatorType.describe('The discriminator to check'),
|
||||
});
|
||||
export type UserTagCheckQueryRequest = z.infer<typeof UserTagCheckQueryRequest>;
|
||||
|
||||
export const UserProfileQueryRequest = z.object({
|
||||
guild_id: SnowflakeType.optional().describe('Optional guild ID for guild-specific profile'),
|
||||
with_mutual_friends: QueryBooleanType.describe('Whether to include mutual friends'),
|
||||
with_mutual_guilds: QueryBooleanType.describe('Whether to include mutual guilds'),
|
||||
});
|
||||
export type UserProfileQueryRequest = z.infer<typeof UserProfileQueryRequest>;
|
||||
|
||||
export const UserNoteUpdateRequest = z.object({
|
||||
note: createStringType(1, 256).nullish().describe('The note text (max 256 characters)'),
|
||||
});
|
||||
export type UserNoteUpdateRequest = z.infer<typeof UserNoteUpdateRequest>;
|
||||
|
||||
export const PushSubscribeRequest = z.object({
|
||||
endpoint: URLType.describe('The push subscription endpoint URL'),
|
||||
keys: z.object({
|
||||
p256dh: createStringType(1, 1024).describe('The P-256 ECDH public key'),
|
||||
auth: createStringType(1, 1024).describe('The authentication secret'),
|
||||
}),
|
||||
user_agent: createStringType(1, 1024).optional().describe('The user agent string'),
|
||||
});
|
||||
export type PushSubscribeRequest = z.infer<typeof PushSubscribeRequest>;
|
||||
|
||||
export const SubscriptionIdParam = z.object({
|
||||
subscription_id: createStringType(1, 256).describe('The ID of the push subscription'),
|
||||
});
|
||||
export type SubscriptionIdParam = z.infer<typeof SubscriptionIdParam>;
|
||||
|
||||
export const PreloadMessagesRequest = z.object({
|
||||
channels: z.array(SnowflakeType).max(100).describe('Array of channel IDs to preload messages from (max 100)'),
|
||||
});
|
||||
export type PreloadMessagesRequest = z.infer<typeof PreloadMessagesRequest>;
|
||||
|
||||
export const UserMentionsQueryRequest = z.object({
|
||||
limit: createQueryIntegerType({minValue: 1, maxValue: 100, defaultValue: 25}).describe(
|
||||
'Maximum number of mentions to return (1-100, default 25)',
|
||||
),
|
||||
roles: QueryBooleanType.optional().default(true).describe('Whether to include role mentions'),
|
||||
everyone: QueryBooleanType.optional().default(true).describe('Whether to include @everyone mentions'),
|
||||
guilds: QueryBooleanType.optional().default(true).describe('Whether to include guild mentions'),
|
||||
before: SnowflakeType.optional().describe('Get mentions before this message ID'),
|
||||
});
|
||||
export type UserMentionsQueryRequest = z.infer<typeof UserMentionsQueryRequest>;
|
||||
|
||||
export const UserSavedMessagesQueryRequest = z.object({
|
||||
limit: createQueryIntegerType({minValue: 1, maxValue: 100, defaultValue: 25}).describe(
|
||||
'Maximum number of saved messages to return (1-100, default 25)',
|
||||
),
|
||||
});
|
||||
export type UserSavedMessagesQueryRequest = z.infer<typeof UserSavedMessagesQueryRequest>;
|
||||
|
||||
export const SaveMessageRequest = z.object({
|
||||
channel_id: SnowflakeType.describe('The ID of the channel containing the message'),
|
||||
message_id: SnowflakeType.describe('The ID of the message to save'),
|
||||
});
|
||||
export type SaveMessageRequest = z.infer<typeof SaveMessageRequest>;
|
||||
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* Copyright (C) 2026 Fluxer Contributors
|
||||
*
|
||||
* This file is part of Fluxer.
|
||||
*
|
||||
* Fluxer is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Fluxer is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with Fluxer. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
DEFAULT_GUILD_FOLDER_ICON,
|
||||
FriendSourceFlags,
|
||||
FriendSourceFlagsDescriptions,
|
||||
GroupDmAddPermissionFlags,
|
||||
GroupDmAddPermissionFlagsDescriptions,
|
||||
GuildFolderFlags,
|
||||
GuildFolderFlagsDescriptions,
|
||||
GuildFolderIcons,
|
||||
IncomingCallFlags,
|
||||
IncomingCallFlagsDescriptions,
|
||||
PublicUserFlags,
|
||||
PublicUserFlagsDescriptions,
|
||||
} from '@fluxer/constants/src/UserConstants';
|
||||
import {ConnectionResponse} from '@fluxer/schema/src/domains/connection/ConnectionSchemas';
|
||||
import {GuildMemberResponse} from '@fluxer/schema/src/domains/guild/GuildMemberSchemas';
|
||||
import {MessageResponseSchema} from '@fluxer/schema/src/domains/message/MessageResponseSchemas';
|
||||
import {LocaleSchema} from '@fluxer/schema/src/primitives/LocaleSchema';
|
||||
import {
|
||||
createBitflagInt32Type,
|
||||
createNamedStringLiteralUnion,
|
||||
createStringType,
|
||||
HexString32Type,
|
||||
Int32Type,
|
||||
SignedInt32Type,
|
||||
SnowflakeStringType,
|
||||
withFieldDescription,
|
||||
withOpenApiType,
|
||||
} from '@fluxer/schema/src/primitives/SchemaPrimitives';
|
||||
import {
|
||||
RelationshipTypesSchema,
|
||||
RenderSpoilersSchema,
|
||||
StickerAnimationOptionsSchema,
|
||||
TimeFormatTypesSchema,
|
||||
UserAuthenticatorTypesSchema,
|
||||
UserNotificationSettingsSchema,
|
||||
UserPremiumTypesSchema,
|
||||
} from '@fluxer/schema/src/primitives/UserSettingsValidators';
|
||||
import {z} from 'zod';
|
||||
|
||||
export const UserPartialResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier (snowflake) for this user'),
|
||||
username: z.string().describe('The username of the user, not unique across the platform'),
|
||||
discriminator: z.string().describe('The four-digit discriminator tag of the user'),
|
||||
global_name: z.string().nullable().describe('The display name of the user, if set'),
|
||||
avatar: z.string().nullable().describe('The hash of the user avatar image'),
|
||||
avatar_color: Int32Type.nullable().describe('The dominant avatar color of the user as an integer'),
|
||||
bot: z.boolean().optional().describe('Whether the user is a bot account'),
|
||||
system: z.boolean().optional().describe('Whether the user is an official system user'),
|
||||
flags: createBitflagInt32Type(
|
||||
PublicUserFlags,
|
||||
PublicUserFlagsDescriptions,
|
||||
'The public flags on the user account',
|
||||
'PublicUserFlags',
|
||||
),
|
||||
});
|
||||
|
||||
export type UserPartialResponse = z.infer<typeof UserPartialResponse>;
|
||||
|
||||
export const UserPrivateResponse = UserPartialResponse.extend({
|
||||
is_staff: z.boolean().describe('Whether the user has staff permissions'),
|
||||
acls: z.array(z.string()).max(100).describe('Access control list entries for the user'),
|
||||
traits: z.array(z.string()).max(100).describe('Special traits assigned to the user account'),
|
||||
email: z.string().nullable().describe('The email address associated with the account'),
|
||||
email_bounced: z
|
||||
.boolean()
|
||||
.optional()
|
||||
.describe('Whether the current email address is marked as bounced by the mail provider'),
|
||||
phone: z.string().nullable().describe('The phone number associated with the account'),
|
||||
bio: z.string().nullable().describe('The user biography text'),
|
||||
pronouns: z.string().nullable().describe('The preferred pronouns of the user'),
|
||||
accent_color: Int32Type.nullable().describe('The user-selected accent color as an integer'),
|
||||
banner: z.string().nullable().describe('The hash of the user profile banner image'),
|
||||
banner_color: Int32Type.nullable().describe('The default banner color if no custom banner is set'),
|
||||
mfa_enabled: z.boolean().describe('Whether multi-factor authentication is enabled'),
|
||||
authenticator_types: z
|
||||
.array(UserAuthenticatorTypesSchema)
|
||||
.max(10)
|
||||
.optional()
|
||||
.describe('The types of authenticators configured for MFA'),
|
||||
verified: z.boolean().describe('Whether the email address has been verified'),
|
||||
premium_type: withFieldDescription(UserPremiumTypesSchema, 'The type of premium subscription').nullable(),
|
||||
premium_since: z.string().nullable().describe('ISO8601 timestamp of when premium was first activated'),
|
||||
premium_until: z.string().nullable().describe('ISO8601 timestamp of when the current premium period ends'),
|
||||
premium_will_cancel: z.boolean().describe('Whether premium is set to cancel at the end of the billing period'),
|
||||
premium_billing_cycle: z.string().nullable().describe('The billing cycle for the premium subscription'),
|
||||
premium_lifetime_sequence: Int32Type.nullable().describe('The sequence number for lifetime premium subscribers'),
|
||||
premium_badge_hidden: z.boolean().describe('Whether the premium badge is hidden on the profile'),
|
||||
premium_badge_masked: z.boolean().describe('Whether the premium badge shows a masked appearance'),
|
||||
premium_badge_timestamp_hidden: z.boolean().describe('Whether the premium start timestamp is hidden'),
|
||||
premium_badge_sequence_hidden: z.boolean().describe('Whether the lifetime sequence number is hidden'),
|
||||
premium_purchase_disabled: z.boolean().describe('Whether premium purchases are disabled for this account'),
|
||||
premium_enabled_override: z.boolean().describe('Whether premium features are enabled via override'),
|
||||
password_last_changed_at: z.string().nullable().describe('ISO8601 timestamp of the last password change'),
|
||||
required_actions: z
|
||||
.array(z.string())
|
||||
.max(20)
|
||||
.nullable()
|
||||
.describe('Actions the user must complete before full access'),
|
||||
nsfw_allowed: z.boolean().describe('Whether the user is allowed to view NSFW content'),
|
||||
has_dismissed_premium_onboarding: z.boolean().describe('Whether the user has dismissed the premium onboarding flow'),
|
||||
has_ever_purchased: z.boolean().describe('Whether the user has ever made a purchase'),
|
||||
has_unread_gift_inventory: z.boolean().describe('Whether there are unread items in the gift inventory'),
|
||||
unread_gift_inventory_count: Int32Type.describe('The number of unread gift inventory items'),
|
||||
used_mobile_client: z.boolean().describe('Whether the user has ever used the mobile client'),
|
||||
pending_bulk_message_deletion: z
|
||||
.object({
|
||||
scheduled_at: z.string().describe('ISO8601 timestamp of when the deletion was scheduled'),
|
||||
channel_count: Int32Type.describe('The number of channels with messages to delete'),
|
||||
message_count: Int32Type.describe('The total number of messages to delete'),
|
||||
})
|
||||
.nullable()
|
||||
.describe('Information about a pending bulk message deletion request'),
|
||||
});
|
||||
|
||||
export type UserPrivateResponse = z.infer<typeof UserPrivateResponse>;
|
||||
|
||||
export const EmailChangeStartResponse = z.object({
|
||||
ticket: z.string().describe('Ticket returned for email change actions'),
|
||||
require_original: z.boolean().describe('Whether verification of the original email is required'),
|
||||
original_email: z.string().nullable().describe('The original email address on record'),
|
||||
original_proof: z
|
||||
.string()
|
||||
.nullable()
|
||||
.describe('Proof token generated when original email verification is not required'),
|
||||
original_code_expires_at: z
|
||||
.string()
|
||||
.nullable()
|
||||
.describe('ISO8601 timestamp when the original verification code expires'),
|
||||
resend_available_at: z
|
||||
.string()
|
||||
.nullable()
|
||||
.describe('ISO8601 timestamp when the original verification code can be resent'),
|
||||
});
|
||||
export type EmailChangeStartResponse = z.infer<typeof EmailChangeStartResponse>;
|
||||
|
||||
export const EmailChangeVerifyOriginalResponse = z.object({
|
||||
original_proof: z.string().describe('Proof token issued after verifying the original email'),
|
||||
});
|
||||
export type EmailChangeVerifyOriginalResponse = z.infer<typeof EmailChangeVerifyOriginalResponse>;
|
||||
|
||||
export const EmailChangeRequestNewResponse = z.object({
|
||||
ticket: z.string().describe('Ticket associated with the email change attempt'),
|
||||
new_email: z.string().describe('The new email address the user wants to verify'),
|
||||
new_code_expires_at: z.string().describe('ISO8601 timestamp when the new email code expires'),
|
||||
resend_available_at: z.string().nullable().describe('ISO8601 timestamp when the new email code can be resent'),
|
||||
});
|
||||
export type EmailChangeRequestNewResponse = z.infer<typeof EmailChangeRequestNewResponse>;
|
||||
|
||||
export const PasswordChangeStartResponse = z.object({
|
||||
ticket: z.string().describe('Ticket for password change actions'),
|
||||
code_expires_at: z.string().describe('ISO8601 timestamp when the verification code expires'),
|
||||
resend_available_at: z.string().nullable().describe('ISO8601 timestamp when the code can be resent'),
|
||||
});
|
||||
export type PasswordChangeStartResponse = z.infer<typeof PasswordChangeStartResponse>;
|
||||
|
||||
export const PasswordChangeVerifyResponse = z.object({
|
||||
verification_proof: z.string().describe('Proof token issued after verifying the email code'),
|
||||
});
|
||||
export type PasswordChangeVerifyResponse = z.infer<typeof PasswordChangeVerifyResponse>;
|
||||
|
||||
export interface UserProfileResponse {
|
||||
bio: string | null;
|
||||
pronouns: string | null;
|
||||
banner: string | null;
|
||||
banner_color?: number | null;
|
||||
accent_color: number | null;
|
||||
}
|
||||
|
||||
export const CustomStatusResponse = z.object({
|
||||
text: z.string().nullish().describe('The custom status message text'),
|
||||
expires_at: z.iso.datetime().nullish().describe('ISO8601 timestamp of when the custom status expires'),
|
||||
emoji_id: SnowflakeStringType.nullish().describe('The ID of the custom emoji used in the status'),
|
||||
emoji_name: z.string().nullish().describe('The name of the emoji used in the status'),
|
||||
emoji_animated: z.boolean().describe('Whether the status emoji is animated'),
|
||||
});
|
||||
|
||||
export type CustomStatusResponse = z.infer<typeof CustomStatusResponse>;
|
||||
|
||||
const GuildFolderIconSchema = withOpenApiType(
|
||||
createNamedStringLiteralUnion(
|
||||
[
|
||||
[GuildFolderIcons.FOLDER, 'FOLDER', 'Classic folder icon'],
|
||||
[GuildFolderIcons.STAR, 'STAR', 'Star icon'],
|
||||
[GuildFolderIcons.HEART, 'HEART', 'Heart icon'],
|
||||
[GuildFolderIcons.BOOKMARK, 'BOOKMARK', 'Bookmark icon'],
|
||||
[GuildFolderIcons.GAME_CONTROLLER, 'GAME_CONTROLLER', 'Game controller icon'],
|
||||
[GuildFolderIcons.SHIELD, 'SHIELD', 'Shield icon'],
|
||||
[GuildFolderIcons.MUSIC_NOTE, 'MUSIC_NOTE', 'Music note icon'],
|
||||
] as const,
|
||||
'Guild folder icon',
|
||||
),
|
||||
'GuildFolderIconType',
|
||||
);
|
||||
|
||||
export const UserSettingsResponse = z.object({
|
||||
status: z.string().describe('The current online status of the user'),
|
||||
status_resets_at: z.iso.datetime().nullish().describe('ISO8601 timestamp of when the status will reset'),
|
||||
status_resets_to: z.string().nullish().describe('The status to reset to after the scheduled reset'),
|
||||
theme: z.string().describe('The UI theme preference'),
|
||||
locale: LocaleSchema,
|
||||
restricted_guilds: z.array(SnowflakeStringType).max(200).describe('Guild IDs where direct messages are restricted'),
|
||||
bot_restricted_guilds: z
|
||||
.array(SnowflakeStringType)
|
||||
.max(200)
|
||||
.describe('Guild IDs where bot direct messages are restricted'),
|
||||
default_guilds_restricted: z.boolean().describe('Whether new guilds have DM restrictions by default'),
|
||||
bot_default_guilds_restricted: z.boolean().describe('Whether new guilds have bot DM restrictions by default'),
|
||||
inline_attachment_media: z.boolean().describe('Whether to display attachments inline in chat'),
|
||||
inline_embed_media: z.boolean().describe('Whether to display embed media inline in chat'),
|
||||
gif_auto_play: z.boolean().describe('Whether GIFs auto-play in chat'),
|
||||
render_embeds: z.boolean().describe('Whether to render message embeds'),
|
||||
render_reactions: z.boolean().describe('Whether to display reactions on messages'),
|
||||
animate_emoji: z.boolean().describe('Whether to animate custom emoji'),
|
||||
animate_stickers: withFieldDescription(StickerAnimationOptionsSchema, 'Sticker animation preference setting'),
|
||||
render_spoilers: withFieldDescription(RenderSpoilersSchema, 'Spoiler rendering preference setting'),
|
||||
message_display_compact: z.boolean().describe('Whether to use compact message display mode'),
|
||||
friend_source_flags: createBitflagInt32Type(
|
||||
FriendSourceFlags,
|
||||
FriendSourceFlagsDescriptions,
|
||||
'Bitfield for friend request source permissions',
|
||||
'FriendSourceFlags',
|
||||
),
|
||||
incoming_call_flags: createBitflagInt32Type(
|
||||
IncomingCallFlags,
|
||||
IncomingCallFlagsDescriptions,
|
||||
'Bitfield for incoming call notification settings',
|
||||
'IncomingCallFlags',
|
||||
),
|
||||
group_dm_add_permission_flags: createBitflagInt32Type(
|
||||
GroupDmAddPermissionFlags,
|
||||
GroupDmAddPermissionFlagsDescriptions,
|
||||
'Bitfield for group DM add permissions',
|
||||
'GroupDmAddPermissionFlags',
|
||||
),
|
||||
guild_folders: z
|
||||
.array(
|
||||
z.object({
|
||||
id: SignedInt32Type.nullish().describe('The unique identifier for the folder (-1 for uncategorized)'),
|
||||
name: z.string().nullish().describe('The display name of the folder'),
|
||||
color: Int32Type.nullish().describe('The color of the folder as an integer'),
|
||||
flags: createBitflagInt32Type(
|
||||
GuildFolderFlags,
|
||||
GuildFolderFlagsDescriptions,
|
||||
'Bitfield for guild folder display behaviour',
|
||||
'GuildFolderFlags',
|
||||
)
|
||||
.default(0)
|
||||
.describe('Bitfield for guild folder display behaviour'),
|
||||
icon: GuildFolderIconSchema.default(DEFAULT_GUILD_FOLDER_ICON).describe('Selected icon for the guild folder'),
|
||||
guild_ids: z.array(SnowflakeStringType).max(200).describe('The IDs of guilds contained in this folder'),
|
||||
}),
|
||||
)
|
||||
.max(200)
|
||||
.describe('The folder structure for organizing guilds in the sidebar'),
|
||||
custom_status: CustomStatusResponse.nullable().describe('The custom status set by the user'),
|
||||
afk_timeout: Int32Type.describe('The idle timeout in seconds before going AFK'),
|
||||
time_format: withFieldDescription(TimeFormatTypesSchema, 'The preferred time format setting'),
|
||||
developer_mode: z.boolean().describe('Whether developer mode is enabled'),
|
||||
trusted_domains: z.array(z.string()).max(1000).describe('List of trusted external link domains'),
|
||||
default_hide_muted_channels: z.boolean().describe('Whether muted channels are hidden by default in new guilds'),
|
||||
});
|
||||
|
||||
export type UserSettingsResponse = z.infer<typeof UserSettingsResponse>;
|
||||
|
||||
const UserGuildMuteConfig = z
|
||||
.object({
|
||||
end_time: z.string().nullable().describe('ISO8601 timestamp of when the mute expires'),
|
||||
selected_time_window: Int32Type.describe('The selected mute duration in seconds'),
|
||||
})
|
||||
.nullable();
|
||||
|
||||
const UserGuildChannelOverride = z.object({
|
||||
collapsed: z.boolean().describe('Whether the channel category is collapsed in the sidebar'),
|
||||
message_notifications: withFieldDescription(
|
||||
UserNotificationSettingsSchema,
|
||||
'The notification level override for this channel',
|
||||
),
|
||||
muted: z.boolean().describe('Whether notifications are muted for this channel'),
|
||||
mute_config: UserGuildMuteConfig.describe('The mute configuration for this channel'),
|
||||
});
|
||||
|
||||
export const UserGuildSettingsResponse = z.object({
|
||||
guild_id: SnowflakeStringType.nullable().describe('The ID of the guild these settings apply to'),
|
||||
message_notifications: withFieldDescription(
|
||||
UserNotificationSettingsSchema,
|
||||
'The default notification level for the guild',
|
||||
),
|
||||
muted: z.boolean().describe('Whether the guild is muted'),
|
||||
mute_config: UserGuildMuteConfig.describe('The mute configuration for the guild'),
|
||||
mobile_push: z.boolean().describe('Whether mobile push notifications are enabled'),
|
||||
suppress_everyone: z.boolean().describe('Whether @everyone mentions are suppressed'),
|
||||
suppress_roles: z.boolean().describe('Whether role mentions are suppressed'),
|
||||
hide_muted_channels: z.boolean().describe('Whether muted channels are hidden in the sidebar'),
|
||||
channel_overrides: z
|
||||
.record(SnowflakeStringType, UserGuildChannelOverride)
|
||||
.nullable()
|
||||
.describe('Per-channel notification overrides'),
|
||||
version: Int32Type.describe('The version number of these settings for sync'),
|
||||
});
|
||||
|
||||
export type UserGuildSettingsResponse = z.infer<typeof UserGuildSettingsResponse>;
|
||||
|
||||
export const RelationshipResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The unique identifier for the relationship'),
|
||||
type: withFieldDescription(RelationshipTypesSchema, 'The type of relationship (friend, blocked, pending, etc.)'),
|
||||
user: z.lazy(() => UserPartialResponse).describe('The user involved in this relationship'),
|
||||
since: z.iso.datetime().optional().describe('ISO8601 timestamp of when the relationship was established'),
|
||||
nickname: z.string().nullable().describe('A custom nickname set for the related user'),
|
||||
});
|
||||
|
||||
export type RelationshipResponse = z.infer<typeof RelationshipResponse>;
|
||||
|
||||
export const RelationshipListResponse = z
|
||||
.array(RelationshipResponse)
|
||||
.max(10000)
|
||||
.describe('A list of user relationships');
|
||||
export type RelationshipListResponse = z.infer<typeof RelationshipListResponse>;
|
||||
|
||||
export type RequiredAction =
|
||||
| 'REQUIRE_VERIFIED_EMAIL'
|
||||
| 'REQUIRE_REVERIFIED_EMAIL'
|
||||
| 'REQUIRE_VERIFIED_PHONE'
|
||||
| 'REQUIRE_REVERIFIED_PHONE'
|
||||
| 'REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE'
|
||||
| 'REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE'
|
||||
| 'REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE'
|
||||
| 'REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE';
|
||||
|
||||
export interface BackupCode {
|
||||
readonly code: string;
|
||||
readonly consumed: boolean;
|
||||
}
|
||||
|
||||
export interface PendingBulkMessageDeletion {
|
||||
readonly scheduled_at: string;
|
||||
readonly channel_count: number;
|
||||
readonly message_count: number;
|
||||
}
|
||||
|
||||
export interface UserProfile {
|
||||
readonly bio: string | null;
|
||||
readonly banner: string | null;
|
||||
readonly banner_color?: number | null;
|
||||
readonly pronouns: string | null;
|
||||
readonly accent_color: number | null;
|
||||
}
|
||||
|
||||
export interface UserPartial {
|
||||
readonly id: string;
|
||||
readonly username: string;
|
||||
readonly discriminator: string;
|
||||
readonly global_name: string | null;
|
||||
readonly avatar: string | null;
|
||||
readonly avatar_color: number | null;
|
||||
readonly bot?: boolean;
|
||||
readonly system?: boolean;
|
||||
readonly flags: number;
|
||||
}
|
||||
|
||||
export interface UserPrivate extends UserPartial, UserProfile {
|
||||
readonly is_staff: boolean;
|
||||
readonly email: string | null;
|
||||
readonly email_bounced?: boolean;
|
||||
readonly mfa_enabled: boolean;
|
||||
readonly phone: string | null;
|
||||
readonly authenticator_types: ReadonlyArray<number>;
|
||||
readonly verified: boolean;
|
||||
readonly premium_type: number | null;
|
||||
readonly premium_since: string | null;
|
||||
readonly premium_until: string | null;
|
||||
readonly premium_will_cancel: boolean;
|
||||
readonly premium_billing_cycle: string | null;
|
||||
readonly premium_lifetime_sequence: number | null;
|
||||
readonly premium_badge_hidden: boolean;
|
||||
readonly premium_badge_masked: boolean;
|
||||
readonly premium_badge_timestamp_hidden: boolean;
|
||||
readonly premium_badge_sequence_hidden: boolean;
|
||||
readonly premium_purchase_disabled: boolean;
|
||||
readonly premium_enabled_override: boolean;
|
||||
readonly password_last_changed_at: string | null;
|
||||
readonly required_actions: ReadonlyArray<RequiredAction> | null;
|
||||
readonly nsfw_allowed: boolean;
|
||||
readonly pending_bulk_message_deletion: PendingBulkMessageDeletion | null;
|
||||
readonly has_dismissed_premium_onboarding: boolean;
|
||||
readonly has_ever_purchased: boolean;
|
||||
readonly has_unread_gift_inventory: boolean;
|
||||
readonly unread_gift_inventory_count: number;
|
||||
readonly used_mobile_client: boolean;
|
||||
readonly traits: ReadonlyArray<string>;
|
||||
}
|
||||
|
||||
export type User = UserPartial & Partial<UserPrivate>;
|
||||
|
||||
export const SavedMessageStatusSchema = withOpenApiType(
|
||||
createNamedStringLiteralUnion(
|
||||
[
|
||||
['available', 'Available', 'The saved message is available and can be retrieved'],
|
||||
['missing_permissions', 'Missing Permissions', 'The user no longer has permission to view the message'],
|
||||
],
|
||||
'Availability status of a saved message',
|
||||
),
|
||||
'SavedMessageStatus',
|
||||
);
|
||||
export type SavedMessageStatus = z.infer<typeof SavedMessageStatusSchema>;
|
||||
|
||||
export const SavedMessageEntryResponse = z.object({
|
||||
id: SnowflakeStringType.describe('Unique identifier for the saved message entry'),
|
||||
channel_id: SnowflakeStringType.describe('ID of the channel containing the message'),
|
||||
message_id: SnowflakeStringType.describe('ID of the saved message'),
|
||||
status: SavedMessageStatusSchema.describe('Availability status of the saved message'),
|
||||
message: MessageResponseSchema.nullable().describe('The message content if available'),
|
||||
});
|
||||
|
||||
export type SavedMessageEntryResponse = z.infer<typeof SavedMessageEntryResponse>;
|
||||
|
||||
export const SavedMessageEntryListResponse = z.array(SavedMessageEntryResponse);
|
||||
export type SavedMessageEntryListResponse = z.infer<typeof SavedMessageEntryListResponse>;
|
||||
|
||||
export const EmailTokenResponse = z.object({
|
||||
email_token: createStringType(1, 256).describe('The email change token to use for updating email'),
|
||||
});
|
||||
export type EmailTokenResponse = z.infer<typeof EmailTokenResponse>;
|
||||
|
||||
export const UserTagCheckResponse = z.object({
|
||||
taken: z.boolean().describe('Whether the username/discriminator combination is already taken'),
|
||||
});
|
||||
export type UserTagCheckResponse = z.infer<typeof UserTagCheckResponse>;
|
||||
|
||||
export const UserProfileDataResponse = z.object({
|
||||
bio: z.string().nullable().describe('User biography text'),
|
||||
pronouns: z.string().nullable().describe('User pronouns'),
|
||||
banner: z.string().nullable().describe('Hash of the profile banner image'),
|
||||
banner_color: Int32Type.nullable().optional().describe('Default banner color if no custom banner'),
|
||||
accent_color: Int32Type.nullable().describe('User-selected accent color'),
|
||||
});
|
||||
export type UserProfileDataResponse = z.infer<typeof UserProfileDataResponse>;
|
||||
|
||||
export const GuildMemberProfileDataResponse = z
|
||||
.object({
|
||||
bio: z.string().nullable().describe('Guild-specific biography text'),
|
||||
pronouns: z.string().nullable().describe('Guild-specific pronouns'),
|
||||
banner: z.string().nullable().describe('Hash of the guild-specific banner image'),
|
||||
accent_color: Int32Type.nullable().describe('Guild-specific accent color'),
|
||||
})
|
||||
.nullable()
|
||||
.optional();
|
||||
export type GuildMemberProfileDataResponse = z.infer<typeof GuildMemberProfileDataResponse>;
|
||||
|
||||
export const MutualGuildResponse = z.object({
|
||||
id: SnowflakeStringType.describe('The ID of the mutual guild'),
|
||||
nick: z.string().nullable().describe('The nickname of the target user in this guild'),
|
||||
});
|
||||
export type MutualGuildResponse = z.infer<typeof MutualGuildResponse>;
|
||||
|
||||
export const UserProfileFullResponse = z.object({
|
||||
user: UserPartialResponse.describe('The user object'),
|
||||
user_profile: UserProfileDataResponse.describe('The user profile data'),
|
||||
guild_member: z
|
||||
.lazy(() => GuildMemberResponse)
|
||||
.optional()
|
||||
.describe('The guild member data if guild_id was provided'),
|
||||
guild_member_profile: GuildMemberProfileDataResponse.describe('Guild-specific profile data'),
|
||||
premium_type: withFieldDescription(UserPremiumTypesSchema, 'The type of premium subscription').optional(),
|
||||
premium_since: z.string().optional().describe('ISO8601 timestamp of when premium was activated'),
|
||||
premium_lifetime_sequence: Int32Type.optional().describe('Sequence number for lifetime premium'),
|
||||
mutual_friends: z.array(UserPartialResponse).optional().describe('Array of mutual friends'),
|
||||
mutual_guilds: z.array(MutualGuildResponse).optional().describe('Array of mutual guilds'),
|
||||
connected_accounts: z.array(ConnectionResponse).optional().describe('Array of verified external connections'),
|
||||
});
|
||||
export type UserProfileFullResponse = z.infer<typeof UserProfileFullResponse>;
|
||||
|
||||
export const UserNotesRecordResponse = z
|
||||
.record(SnowflakeStringType, z.string())
|
||||
.describe('A map of user IDs to note text');
|
||||
export type UserNotesRecordResponse = z.infer<typeof UserNotesRecordResponse>;
|
||||
|
||||
export const UserNoteResponse = z.object({
|
||||
note: z.string().describe('The note text for this user'),
|
||||
});
|
||||
export type UserNoteResponse = z.infer<typeof UserNoteResponse>;
|
||||
|
||||
export const PushSubscribeResponse = z.object({
|
||||
subscription_id: HexString32Type.describe('The unique identifier for the push subscription'),
|
||||
});
|
||||
export type PushSubscribeResponse = z.infer<typeof PushSubscribeResponse>;
|
||||
|
||||
export const PushSubscriptionItemResponse = z.object({
|
||||
subscription_id: HexString32Type.describe('The unique identifier for the push subscription'),
|
||||
user_agent: z.string().nullable().describe('The user agent that registered this subscription'),
|
||||
});
|
||||
export type PushSubscriptionItemResponse = z.infer<typeof PushSubscriptionItemResponse>;
|
||||
|
||||
export const PushSubscriptionsListResponse = z.object({
|
||||
subscriptions: z.array(PushSubscriptionItemResponse).describe('Array of push subscriptions'),
|
||||
});
|
||||
export type PushSubscriptionsListResponse = z.infer<typeof PushSubscriptionsListResponse>;
|
||||
|
||||
export const PreloadMessagesResponse = z
|
||||
.record(SnowflakeStringType, MessageResponseSchema.nullable())
|
||||
.describe('A map of channel IDs to the latest message in each channel');
|
||||
export type PreloadMessagesResponse = z.infer<typeof PreloadMessagesResponse>;
|
||||
Reference in new issue
Block a user