refactor progress

This commit is contained in:
Hampus Kraft
2026-02-17 12:22:36 +00:00
parent cb31608523
commit d5abd1a7e4
8257 changed files with 1190207 additions and 761040 deletions

View File

@@ -0,0 +1,113 @@
/*
* 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/>.
*/
export const AdminACLs = {
WILDCARD: '*',
ACL_SET_USER: 'acl:set:user',
ADMIN_API_KEY_MANAGE: 'admin_api_key:manage',
ARCHIVE_TRIGGER_GUILD: 'archive:trigger:guild',
ARCHIVE_TRIGGER_USER: 'archive:trigger:user',
ARCHIVE_VIEW_ALL: 'archive:view_all',
ASSET_PURGE: 'asset:purge',
AUDIT_LOG_VIEW: 'audit_log:view',
AUTHENTICATE: 'admin:authenticate',
BAN_EMAIL_ADD: 'ban:email:add',
BAN_EMAIL_CHECK: 'ban:email:check',
BAN_EMAIL_REMOVE: 'ban:email:remove',
BAN_IP_ADD: 'ban:ip:add',
BAN_IP_CHECK: 'ban:ip:check',
BAN_IP_REMOVE: 'ban:ip:remove',
BAN_PHONE_ADD: 'ban:phone:add',
BAN_PHONE_CHECK: 'ban:phone:check',
BAN_PHONE_REMOVE: 'ban:phone:remove',
BULK_ADD_GUILD_MEMBERS: 'bulk:add:guild_members',
BULK_DELETE_USERS: 'bulk:delete:users',
BULK_UPDATE_GUILD_FEATURES: 'bulk:update:guild_features',
BULK_UPDATE_USER_FLAGS: 'bulk:update:user_flags',
CSAM_SUBMIT_NCMEC: 'csam:submit_ncmec',
DISCOVERY_REMOVE: 'discovery:remove',
DISCOVERY_REVIEW: 'discovery:review',
GATEWAY_MEMORY_STATS: 'gateway:memory_stats',
GATEWAY_RELOAD_ALL: 'gateway:reload_all',
GIFT_CODES_GENERATE: 'gift_codes:generate',
GUILD_BAN_MEMBER: 'guild:ban_member',
GUILD_DELETE: 'guild:delete',
GUILD_FORCE_ADD_MEMBER: 'guild:force_add_member',
GUILD_KICK_MEMBER: 'guild:kick_member',
GUILD_LIST_MEMBERS: 'guild:list:members',
GUILD_LOOKUP: 'guild:lookup',
GUILD_RELOAD: 'guild:reload',
GUILD_SHUTDOWN: 'guild:shutdown',
GUILD_TRANSFER_OWNERSHIP: 'guild:transfer_ownership',
GUILD_UPDATE_BANNER: 'guild:update:banner',
GUILD_UPDATE_FEATURES: 'guild:update:features',
GUILD_UPDATE_ICON: 'guild:update:icon',
GUILD_UPDATE_NAME: 'guild:update:name',
GUILD_UPDATE_SETTINGS: 'guild:update:settings',
GUILD_UPDATE_SPLASH: 'guild:update:splash',
GUILD_UPDATE_VANITY: 'guild:update:vanity',
INSTANCE_CONFIG_UPDATE: 'instance:config:update',
INSTANCE_CONFIG_VIEW: 'instance:config:view',
INSTANCE_LIMIT_CONFIG_UPDATE: 'instance:limit_config:update',
INSTANCE_LIMIT_CONFIG_VIEW: 'instance:limit_config:view',
INSTANCE_SNOWFLAKE_RESERVATION_MANAGE: 'instance:snowflake_reservation:manage',
INSTANCE_SNOWFLAKE_RESERVATION_VIEW: 'instance:snowflake_reservation:view',
MESSAGE_DELETE_ALL: 'message:delete_all',
MESSAGE_DELETE: 'message:delete',
MESSAGE_LOOKUP: 'message:lookup',
MESSAGE_SHRED: 'message:shred',
METRICS_VIEW: 'metrics:view',
REPORT_RESOLVE: 'report:resolve',
REPORT_VIEW: 'report:view',
SYSTEM_DM_SEND: 'system_dm:send',
USER_CANCEL_BULK_MESSAGE_DELETION: 'user:cancel:bulk_message_deletion',
USER_DELETE: 'user:delete',
USER_DISABLE_SUSPICIOUS: 'user:disable:suspicious',
USER_LIST_DM_CHANNELS: 'user:list:dm_channels',
USER_LIST_GUILDS: 'user:list:guilds',
USER_LIST_SESSIONS: 'user:list:sessions',
USER_LOOKUP: 'user:lookup',
USER_TEMP_BAN: 'user:temp_ban',
USER_TERMINATE_SESSIONS: 'user:terminate_sessions',
USER_UPDATE_AVATAR: 'user:update:avatar',
USER_UPDATE_BANNER: 'user:update:banner',
USER_UPDATE_BOT_STATUS: 'user:update:bot_status',
USER_UPDATE_DOB: 'user:update:dob',
USER_UPDATE_EMAIL: 'user:update:email',
USER_UPDATE_FLAGS: 'user:update:flags',
USER_UPDATE_MFA: 'user:update:mfa',
USER_UPDATE_PHONE: 'user:update:phone',
USER_UPDATE_PROFILE: 'user:update:profile',
USER_UPDATE_SUSPICIOUS_ACTIVITY: 'user:update:suspicious_activity',
USER_UPDATE_TRAITS: 'user:update:traits',
USER_UPDATE_USERNAME: 'user:update:username',
VISIONARY_SLOT_EXPAND: 'visionary_slot:expand',
VISIONARY_SLOT_RESERVE: 'visionary_slot:reserve',
VISIONARY_SLOT_SWAP: 'visionary_slot:swap',
VISIONARY_SLOT_SHRINK: 'visionary_slot:shrink',
VISIONARY_SLOT_VIEW: 'visionary_slot:view',
VOICE_REGION_CREATE: 'voice:region:create',
VOICE_REGION_DELETE: 'voice:region:delete',
VOICE_REGION_LIST: 'voice:region:list',
VOICE_REGION_UPDATE: 'voice:region:update',
VOICE_SERVER_CREATE: 'voice:server:create',
VOICE_SERVER_DELETE: 'voice:server:delete',
VOICE_SERVER_LIST: 'voice:server:list',
VOICE_SERVER_UPDATE: 'voice:server:update',
} as const;

View File

@@ -0,0 +1,305 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const APIErrorCodes = {
ACCESS_DENIED: 'ACCESS_DENIED',
ACCOUNT_DISABLED: 'ACCOUNT_DISABLED',
BAD_GATEWAY: 'BAD_GATEWAY',
BAD_REQUEST: 'BAD_REQUEST',
BLUESKY_OAUTH_CALLBACK_FAILED: 'BLUESKY_OAUTH_CALLBACK_FAILED',
BLUESKY_OAUTH_NOT_ENABLED: 'BLUESKY_OAUTH_NOT_ENABLED',
BLUESKY_OAUTH_SESSION_EXPIRED: 'BLUESKY_OAUTH_SESSION_EXPIRED',
BLUESKY_OAUTH_STATE_INVALID: 'BLUESKY_OAUTH_STATE_INVALID',
ACCOUNT_SCHEDULED_FOR_DELETION: 'ACCOUNT_SCHEDULED_FOR_DELETION',
ACCOUNT_SUSPENDED_PERMANENTLY: 'ACCOUNT_SUSPENDED_PERMANENTLY',
ACCOUNT_SUSPENDED_TEMPORARILY: 'ACCOUNT_SUSPENDED_TEMPORARILY',
ACCOUNT_SUSPICIOUS_ACTIVITY: 'ACCOUNT_SUSPICIOUS_ACTIVITY',
ACCOUNT_TOO_NEW_FOR_GUILD: 'ACCOUNT_TOO_NEW_FOR_GUILD',
ACLS_MUST_BE_NON_EMPTY: 'ACLS_MUST_BE_NON_EMPTY',
ADMIN_API_KEY_NOT_FOUND: 'ADMIN_API_KEY_NOT_FOUND',
APPLICATION_NOT_FOUND: 'APPLICATION_NOT_FOUND',
APPLICATION_NOT_OWNED: 'APPLICATION_NOT_OWNED',
ALREADY_FRIENDS: 'ALREADY_FRIENDS',
AUDIT_LOG_INDEXING: 'AUDIT_LOG_INDEXING',
BOTS_CANNOT_SEND_FRIEND_REQUESTS: 'BOTS_CANNOT_SEND_FRIEND_REQUESTS',
BOT_ALREADY_IN_GUILD: 'BOT_ALREADY_IN_GUILD',
BOT_APPLICATION_NOT_FOUND: 'BOT_APPLICATION_NOT_FOUND',
BOT_IS_PRIVATE: 'BOT_IS_PRIVATE',
BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED: 'BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED',
BOT_USER_AUTH_SESSION_CREATION_DENIED: 'BOT_USER_AUTH_SESSION_CREATION_DENIED',
BOT_USER_GENERATION_FAILED: 'BOT_USER_GENERATION_FAILED',
BOT_USER_NOT_FOUND: 'BOT_USER_NOT_FOUND',
CALL_ALREADY_EXISTS: 'CALL_ALREADY_EXISTS',
CANNOT_EDIT_OTHER_USER_MESSAGE: 'CANNOT_EDIT_OTHER_USER_MESSAGE',
CANNOT_EXECUTE_ON_DM: 'CANNOT_EXECUTE_ON_DM',
CANNOT_MODIFY_SYSTEM_WEBHOOK: 'CANNOT_MODIFY_SYSTEM_WEBHOOK',
CANNOT_MODIFY_VOICE_STATE: 'CANNOT_MODIFY_VOICE_STATE',
CANNOT_REDEEM_PLUTONIUM_WITH_VISIONARY: 'CANNOT_REDEEM_PLUTONIUM_WITH_VISIONARY',
CANNOT_REPORT_OWN_GUILD: 'CANNOT_REPORT_OWN_GUILD',
CANNOT_REPORT_OWN_MESSAGE: 'CANNOT_REPORT_OWN_MESSAGE',
CANNOT_REPORT_YOURSELF: 'CANNOT_REPORT_YOURSELF',
CANNOT_SEND_EMPTY_MESSAGE: 'CANNOT_SEND_EMPTY_MESSAGE',
CANNOT_SEND_FRIEND_REQUEST_TO_BLOCKED_USER: 'CANNOT_SEND_FRIEND_REQUEST_TO_BLOCKED_USER',
CANNOT_SEND_FRIEND_REQUEST_TO_SELF: 'CANNOT_SEND_FRIEND_REQUEST_TO_SELF',
CANNOT_SEND_MESSAGES_IN_NON_TEXT_CHANNEL: 'CANNOT_SEND_MESSAGES_IN_NON_TEXT_CHANNEL',
CANNOT_SEND_MESSAGES_TO_USER: 'CANNOT_SEND_MESSAGES_TO_USER',
CANNOT_TRANSFER_OWNERSHIP_TO_BOT: 'CANNOT_TRANSFER_OWNERSHIP_TO_BOT',
CANNOT_SHRINK_RESERVED_SLOTS: 'CANNOT_SHRINK_RESERVED_SLOTS',
CAPTCHA_REQUIRED: 'CAPTCHA_REQUIRED',
CHANNEL_INDEXING: 'CHANNEL_INDEXING',
COMMUNICATION_DISABLED: 'COMMUNICATION_DISABLED',
CONNECTION_ALREADY_EXISTS: 'CONNECTION_ALREADY_EXISTS',
CONNECTION_INITIATION_TOKEN_INVALID: 'CONNECTION_INITIATION_TOKEN_INVALID',
CONNECTION_INVALID_IDENTIFIER: 'CONNECTION_INVALID_IDENTIFIER',
CONNECTION_INVALID_TYPE: 'CONNECTION_INVALID_TYPE',
CONNECTION_LIMIT_REACHED: 'CONNECTION_LIMIT_REACHED',
CONNECTION_NOT_FOUND: 'CONNECTION_NOT_FOUND',
CONNECTION_VERIFICATION_FAILED: 'CONNECTION_VERIFICATION_FAILED',
CONFLICT: 'CONFLICT',
CONTENT_BLOCKED: 'CONTENT_BLOCKED',
CREATION_FAILED: 'CREATION_FAILED',
CSAM_SCAN_FAILED: 'CSAM_SCAN_FAILED',
CSAM_SCAN_PARSE_ERROR: 'CSAM_SCAN_PARSE_ERROR',
CSAM_SCAN_SUBSCRIPTION_ERROR: 'CSAM_SCAN_SUBSCRIPTION_ERROR',
CSAM_SCAN_TIMEOUT: 'CSAM_SCAN_TIMEOUT',
DECRYPTION_FAILED: 'DECRYPTION_FAILED',
DELETION_FAILED: 'DELETION_FAILED',
DISCOVERY_ALREADY_APPLIED: 'DISCOVERY_ALREADY_APPLIED',
DISCOVERY_APPLICATION_ALREADY_REVIEWED: 'DISCOVERY_APPLICATION_ALREADY_REVIEWED',
DISCOVERY_APPLICATION_NOT_FOUND: 'DISCOVERY_APPLICATION_NOT_FOUND',
DISCOVERY_DESCRIPTION_REQUIRED: 'DISCOVERY_DESCRIPTION_REQUIRED',
DISCOVERY_INSUFFICIENT_MEMBERS: 'DISCOVERY_INSUFFICIENT_MEMBERS',
DISCOVERY_INVALID_CATEGORY: 'DISCOVERY_INVALID_CATEGORY',
DISCOVERY_NOT_DISCOVERABLE: 'DISCOVERY_NOT_DISCOVERABLE',
DISCRIMINATOR_REQUIRED: 'DISCRIMINATOR_REQUIRED',
EMAIL_SERVICE_NOT_TESTABLE: 'EMAIL_SERVICE_NOT_TESTABLE',
EMAIL_VERIFICATION_REQUIRED: 'EMAIL_VERIFICATION_REQUIRED',
EMPTY_ENCRYPTED_BODY: 'EMPTY_ENCRYPTED_BODY',
ENCRYPTION_FAILED: 'ENCRYPTION_FAILED',
EXPLICIT_CONTENT_CANNOT_BE_SENT: 'EXPLICIT_CONTENT_CANNOT_BE_SENT',
FEATURE_NOT_AVAILABLE_SELF_HOSTED: 'FEATURE_NOT_AVAILABLE_SELF_HOSTED',
FEATURE_TEMPORARILY_DISABLED: 'FEATURE_TEMPORARILY_DISABLED',
FILE_SIZE_TOO_LARGE: 'FILE_SIZE_TOO_LARGE',
FORBIDDEN: 'FORBIDDEN',
FRIEND_REQUEST_BLOCKED: 'FRIEND_REQUEST_BLOCKED',
GATEWAY_TIMEOUT: 'GATEWAY_TIMEOUT',
GENERAL_ERROR: 'GENERAL_ERROR',
GONE: 'GONE',
GIFT_CODE_ALREADY_REDEEMED: 'GIFT_CODE_ALREADY_REDEEMED',
GUILD_PHONE_VERIFICATION_REQUIRED: 'GUILD_PHONE_VERIFICATION_REQUIRED',
GUILD_VERIFICATION_REQUIRED: 'GUILD_VERIFICATION_REQUIRED',
HANDOFF_CODE_EXPIRED: 'HANDOFF_CODE_EXPIRED',
HARVEST_EXPIRED: 'HARVEST_EXPIRED',
HARVEST_FAILED: 'HARVEST_FAILED',
HARVEST_NOT_READY: 'HARVEST_NOT_READY',
HARVEST_ON_COOLDOWN: 'HARVEST_ON_COOLDOWN',
HTTP_GET_AUTHORIZE_NOT_SUPPORTED: 'HTTP_GET_AUTHORIZE_NOT_SUPPORTED',
INSTANCE_VERSION_MISMATCH: 'INSTANCE_VERSION_MISMATCH',
INTERNAL_SERVER_ERROR: 'INTERNAL_SERVER_ERROR',
INVALID_ACLS_FORMAT: 'INVALID_ACLS_FORMAT',
INVALID_API_ORIGIN: 'INVALID_API_ORIGIN',
INVALID_AUTH_TOKEN: 'INVALID_AUTH_TOKEN',
INVALID_BOT_FLAG: 'INVALID_BOT_FLAG',
INVALID_CAPTCHA: 'INVALID_CAPTCHA',
INVALID_CHANNEL_TYPE_FOR_CALL: 'INVALID_CHANNEL_TYPE_FOR_CALL',
INVALID_CHANNEL_TYPE: 'INVALID_CHANNEL_TYPE',
INVALID_CLIENT: 'INVALID_CLIENT',
INVALID_CLIENT_SECRET: 'INVALID_CLIENT_SECRET',
INVALID_DSA_REPORT_TARGET: 'INVALID_DSA_REPORT_TARGET',
INVALID_DSA_TICKET: 'INVALID_DSA_TICKET',
INVALID_DSA_VERIFICATION_CODE: 'INVALID_DSA_VERIFICATION_CODE',
INVALID_DECRYPTED_JSON: 'INVALID_DECRYPTED_JSON',
INVALID_EPHEMERAL_KEY: 'INVALID_EPHEMERAL_KEY',
INVALID_FLAGS_FORMAT: 'INVALID_FLAGS_FORMAT',
INVALID_IV: 'INVALID_IV',
INVALID_FORM_BODY: 'INVALID_FORM_BODY',
INVALID_GRANT: 'INVALID_GRANT',
INVALID_HANDOFF_CODE: 'INVALID_HANDOFF_CODE',
INVALID_PACK_TYPE: 'INVALID_PACK_TYPE',
INVALID_PERMISSIONS_INTEGER: 'INVALID_PERMISSIONS_INTEGER',
INVALID_PERMISSIONS_NEGATIVE: 'INVALID_PERMISSIONS_NEGATIVE',
INVALID_PHONE_NUMBER: 'INVALID_PHONE_NUMBER',
INVALID_PHONE_VERIFICATION_CODE: 'INVALID_PHONE_VERIFICATION_CODE',
INVALID_REDIRECT_URI: 'INVALID_REDIRECT_URI',
INVALID_REQUEST: 'INVALID_REQUEST',
INVALID_RESPONSE_TYPE_FOR_NON_BOT: 'INVALID_RESPONSE_TYPE_FOR_NON_BOT',
INVALID_SCOPE: 'INVALID_SCOPE',
INVALID_STREAM_KEY_FORMAT: 'INVALID_STREAM_KEY_FORMAT',
INVALID_STREAM_THUMBNAIL_PAYLOAD: 'INVALID_STREAM_THUMBNAIL_PAYLOAD',
INVALID_SUDO_TOKEN: 'INVALID_SUDO_TOKEN',
INVALID_SUSPICIOUS_FLAGS_FORMAT: 'INVALID_SUSPICIOUS_FLAGS_FORMAT',
INVALID_SYSTEM_FLAG: 'INVALID_SYSTEM_FLAG',
INVALID_TIMESTAMP: 'INVALID_TIMESTAMP',
INVALID_TOKEN: 'INVALID_TOKEN',
INVALID_WEBAUTHN_AUTHENTICATION_COUNTER: 'INVALID_WEBAUTHN_AUTHENTICATION_COUNTER',
INVALID_WEBAUTHN_CREDENTIAL_COUNTER: 'INVALID_WEBAUTHN_CREDENTIAL_COUNTER',
INVALID_WEBAUTHN_CREDENTIAL: 'INVALID_WEBAUTHN_CREDENTIAL',
INVALID_WEBAUTHN_PUBLIC_KEY_FORMAT: 'INVALID_WEBAUTHN_PUBLIC_KEY_FORMAT',
INVITES_DISABLED: 'INVITES_DISABLED',
IP_AUTHORIZATION_REQUIRED: 'IP_AUTHORIZATION_REQUIRED',
IP_AUTHORIZATION_RESEND_COOLDOWN: 'IP_AUTHORIZATION_RESEND_COOLDOWN',
IP_AUTHORIZATION_RESEND_LIMIT_EXCEEDED: 'IP_AUTHORIZATION_RESEND_LIMIT_EXCEEDED',
IP_BANNED: 'IP_BANNED',
MAX_ANIMATED_EMOJIS: 'MAX_ANIMATED_EMOJIS',
MAX_BOOKMARKS: 'MAX_BOOKMARKS',
MAX_CATEGORY_CHANNELS: 'MAX_CATEGORY_CHANNELS',
MAX_EMOJIS: 'MAX_EMOJIS',
MAX_FAVORITE_MEMES: 'MAX_FAVORITE_MEMES',
MAX_FRIENDS: 'MAX_FRIENDS',
MAX_GROUP_DM_RECIPIENTS: 'MAX_GROUP_DM_RECIPIENTS',
MAX_GROUP_DMS: 'MAX_GROUP_DMS',
MAX_GUILD_CHANNELS: 'MAX_GUILD_CHANNELS',
MAX_GUILD_MEMBERS: 'MAX_GUILD_MEMBERS',
MAX_GUILD_ROLES: 'MAX_GUILD_ROLES',
MAX_GUILDS: 'MAX_GUILDS',
MAX_INVITES: 'MAX_INVITES',
MAX_PACK_EXPRESSIONS: 'MAX_PACK_EXPRESSIONS',
MAX_PACKS: 'MAX_PACKS',
MAX_PINS_PER_CHANNEL: 'MAX_PINS_PER_CHANNEL',
MESSAGE_TOTAL_ATTACHMENT_SIZE_TOO_LARGE: 'MESSAGE_TOTAL_ATTACHMENT_SIZE_TOO_LARGE',
MAX_REACTIONS: 'MAX_REACTIONS',
MAX_STICKERS: 'MAX_STICKERS',
MAX_WEBHOOKS_PER_CHANNEL: 'MAX_WEBHOOKS_PER_CHANNEL',
MAX_WEBHOOKS_PER_GUILD: 'MAX_WEBHOOKS_PER_GUILD',
MAX_WEBHOOKS: 'MAX_WEBHOOKS',
NCMEC_ALREADY_SUBMITTED: 'NCMEC_ALREADY_SUBMITTED',
NCMEC_SUBMISSION_FAILED: 'NCMEC_SUBMISSION_FAILED',
MEDIA_METADATA_ERROR: 'MEDIA_METADATA_ERROR',
METHOD_NOT_ALLOWED: 'METHOD_NOT_ALLOWED',
MISSING_ACCESS: 'MISSING_ACCESS',
MISSING_ACL: 'MISSING_ACL',
MISSING_AUTHORIZATION: 'MISSING_AUTHORIZATION',
MISSING_CLIENT_SECRET: 'MISSING_CLIENT_SECRET',
MISSING_EPHEMERAL_KEY: 'MISSING_EPHEMERAL_KEY',
MISSING_IV: 'MISSING_IV',
MISSING_OAUTH_ADMIN_SCOPE: 'MISSING_OAUTH_ADMIN_SCOPE',
MISSING_OAUTH_FIELDS: 'MISSING_OAUTH_FIELDS',
MISSING_OAUTH_SCOPE: 'MISSING_OAUTH_SCOPE',
MISSING_PERMISSIONS: 'MISSING_PERMISSIONS',
MISSING_REDIRECT_URI: 'MISSING_REDIRECT_URI',
NO_ACTIVE_CALL: 'NO_ACTIVE_CALL',
NO_ACTIVE_SUBSCRIPTION: 'NO_ACTIVE_SUBSCRIPTION',
NOT_FOUND: 'NOT_FOUND',
NOT_IMPLEMENTED: 'NOT_IMPLEMENTED',
NO_PASSKEYS_REGISTERED: 'NO_PASSKEYS_REGISTERED',
NO_PENDING_DELETION: 'NO_PENDING_DELETION',
NO_USERS_WITH_FLUXERTAG_EXIST: 'NO_USERS_WITH_FLUXERTAG_EXIST',
NO_VISIONARY_SLOTS_AVAILABLE: 'NO_VISIONARY_SLOTS_AVAILABLE',
NOT_A_BOT_APPLICATION: 'NOT_A_BOT_APPLICATION',
NOT_FRIENDS_WITH_USER: 'NOT_FRIENDS_WITH_USER',
NOT_OWNER_OF_ADMIN_API_KEY: 'NOT_OWNER_OF_ADMIN_API_KEY',
NSFW_CONTENT_AGE_RESTRICTED: 'NSFW_CONTENT_AGE_RESTRICTED',
PACK_ACCESS_DENIED: 'PACK_ACCESS_DENIED',
PASSKEY_AUTHENTICATION_FAILED: 'PASSKEY_AUTHENTICATION_FAILED',
PASSKEYS_DISABLED: 'PASSKEYS_DISABLED',
PHONE_ALREADY_USED: 'PHONE_ALREADY_USED',
PHONE_RATE_LIMIT_EXCEEDED: 'PHONE_RATE_LIMIT_EXCEEDED',
PHONE_REQUIRED_FOR_SMS_MFA: 'PHONE_REQUIRED_FOR_SMS_MFA',
PHONE_VERIFICATION_REQUIRED: 'PHONE_VERIFICATION_REQUIRED',
PREMIUM_PURCHASE_BLOCKED: 'PREMIUM_PURCHASE_BLOCKED',
PREVIEW_MUST_BE_JPEG: 'PREVIEW_MUST_BE_JPEG',
PROCESSING_FAILED: 'PROCESSING_FAILED',
RATE_LIMITED: 'RATE_LIMITED',
REDIRECT_URI_REQUIRED_FOR_NON_BOT: 'REDIRECT_URI_REQUIRED_FOR_NON_BOT',
REPORT_ALREADY_RESOLVED: 'REPORT_ALREADY_RESOLVED',
REPORT_BANNED: 'REPORT_BANNED',
RESPONSE_VALIDATION_ERROR: 'RESPONSE_VALIDATION_ERROR',
SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
SESSION_TOKEN_MISMATCH: 'SESSION_TOKEN_MISMATCH',
SLOWMODE_RATE_LIMITED: 'SLOWMODE_RATE_LIMITED',
SMS_MFA_NOT_ENABLED: 'SMS_MFA_NOT_ENABLED',
SMS_MFA_REQUIRES_TOTP: 'SMS_MFA_REQUIRES_TOTP',
SMS_VERIFICATION_UNAVAILABLE: 'SMS_VERIFICATION_UNAVAILABLE',
SSO_REQUIRED: 'SSO_REQUIRED',
STREAM_KEY_CHANNEL_MISMATCH: 'STREAM_KEY_CHANNEL_MISMATCH',
STREAM_KEY_SCOPE_MISMATCH: 'STREAM_KEY_SCOPE_MISMATCH',
STREAM_THUMBNAIL_PAYLOAD_EMPTY: 'STREAM_THUMBNAIL_PAYLOAD_EMPTY',
STRIPE_ERROR: 'STRIPE_ERROR',
STRIPE_GIFT_REDEMPTION_IN_PROGRESS: 'STRIPE_GIFT_REDEMPTION_IN_PROGRESS',
STRIPE_INVALID_PRODUCT: 'STRIPE_INVALID_PRODUCT',
STRIPE_INVALID_PRODUCT_CONFIGURATION: 'STRIPE_INVALID_PRODUCT_CONFIGURATION',
STRIPE_NO_ACTIVE_SUBSCRIPTION: 'STRIPE_NO_ACTIVE_SUBSCRIPTION',
STRIPE_NO_PURCHASE_HISTORY: 'STRIPE_NO_PURCHASE_HISTORY',
STRIPE_NO_SUBSCRIPTION: 'STRIPE_NO_SUBSCRIPTION',
STRIPE_PAYMENT_NOT_AVAILABLE: 'STRIPE_PAYMENT_NOT_AVAILABLE',
STRIPE_SUBSCRIPTION_ALREADY_CANCELING: 'STRIPE_SUBSCRIPTION_ALREADY_CANCELING',
STRIPE_SUBSCRIPTION_NOT_CANCELING: 'STRIPE_SUBSCRIPTION_NOT_CANCELING',
STRIPE_SUBSCRIPTION_PERIOD_END_MISSING: 'STRIPE_SUBSCRIPTION_PERIOD_END_MISSING',
STRIPE_WEBHOOK_NOT_AVAILABLE: 'STRIPE_WEBHOOK_NOT_AVAILABLE',
STRIPE_WEBHOOK_SIGNATURE_INVALID: 'STRIPE_WEBHOOK_SIGNATURE_INVALID',
STRIPE_WEBHOOK_SIGNATURE_MISSING: 'STRIPE_WEBHOOK_SIGNATURE_MISSING',
DONATION_AMOUNT_INVALID: 'DONATION_AMOUNT_INVALID',
DONATION_MAGIC_LINK_EXPIRED: 'DONATION_MAGIC_LINK_EXPIRED',
DONATION_MAGIC_LINK_INVALID: 'DONATION_MAGIC_LINK_INVALID',
DONATION_MAGIC_LINK_USED: 'DONATION_MAGIC_LINK_USED',
DONOR_NOT_FOUND: 'DONOR_NOT_FOUND',
SUDO_MODE_REQUIRED: 'SUDO_MODE_REQUIRED',
TAG_ALREADY_TAKEN: 'TAG_ALREADY_TAKEN',
TEMPORARY_INVITE_REQUIRES_PRESENCE: 'TEMPORARY_INVITE_REQUIRES_PRESENCE',
TEST_HARNESS_DISABLED: 'TEST_HARNESS_DISABLED',
TEST_HARNESS_FORBIDDEN: 'TEST_HARNESS_FORBIDDEN',
TWO_FA_NOT_ENABLED: 'TWO_FA_NOT_ENABLED',
TWO_FACTOR_REQUIRED: 'TWO_FACTOR_REQUIRED',
UNAUTHORIZED: 'UNAUTHORIZED',
UNCLAIMED_ACCOUNT_CANNOT_ACCEPT_FRIEND_REQUESTS: 'UNCLAIMED_ACCOUNT_CANNOT_ACCEPT_FRIEND_REQUESTS',
UNCLAIMED_ACCOUNT_CANNOT_ADD_REACTIONS: 'UNCLAIMED_ACCOUNT_CANNOT_ADD_REACTIONS',
UNCLAIMED_ACCOUNT_CANNOT_CREATE_APPLICATIONS: 'UNCLAIMED_ACCOUNT_CANNOT_CREATE_APPLICATIONS',
UNCLAIMED_ACCOUNT_CANNOT_JOIN_GROUP_DMS: 'UNCLAIMED_ACCOUNT_CANNOT_JOIN_GROUP_DMS',
UNCLAIMED_ACCOUNT_CANNOT_JOIN_ONE_ON_ONE_VOICE_CALLS: 'UNCLAIMED_ACCOUNT_CANNOT_JOIN_ONE_ON_ONE_VOICE_CALLS',
UNCLAIMED_ACCOUNT_CANNOT_JOIN_VOICE_CHANNELS: 'UNCLAIMED_ACCOUNT_CANNOT_JOIN_VOICE_CHANNELS',
UNCLAIMED_ACCOUNT_CANNOT_MAKE_PURCHASES: 'UNCLAIMED_ACCOUNT_CANNOT_MAKE_PURCHASES',
UNCLAIMED_ACCOUNT_CANNOT_SEND_DIRECT_MESSAGES: 'UNCLAIMED_ACCOUNT_CANNOT_SEND_DIRECT_MESSAGES',
UNCLAIMED_ACCOUNT_CANNOT_SEND_FRIEND_REQUESTS: 'UNCLAIMED_ACCOUNT_CANNOT_SEND_FRIEND_REQUESTS',
UNCLAIMED_ACCOUNT_CANNOT_SEND_MESSAGES: 'UNCLAIMED_ACCOUNT_CANNOT_SEND_MESSAGES',
UNKNOWN_CHANNEL: 'UNKNOWN_CHANNEL',
UNKNOWN_EMOJI: 'UNKNOWN_EMOJI',
UNKNOWN_FAVORITE_MEME: 'UNKNOWN_FAVORITE_MEME',
UNKNOWN_GIFT_CODE: 'UNKNOWN_GIFT_CODE',
UNKNOWN_GUILD: 'UNKNOWN_GUILD',
UNKNOWN_HARVEST: 'UNKNOWN_HARVEST',
UNKNOWN_INVITE: 'UNKNOWN_INVITE',
UNKNOWN_MEMBER: 'UNKNOWN_MEMBER',
UNKNOWN_MESSAGE: 'UNKNOWN_MESSAGE',
UNKNOWN_PACK: 'UNKNOWN_PACK',
UNKNOWN_REPORT: 'UNKNOWN_REPORT',
UNKNOWN_ROLE: 'UNKNOWN_ROLE',
UNKNOWN_STICKER: 'UNKNOWN_STICKER',
UNKNOWN_SUSPICIOUS_FLAG: 'UNKNOWN_SUSPICIOUS_FLAG',
UNKNOWN_USER_FLAG: 'UNKNOWN_USER_FLAG',
UNKNOWN_USER: 'UNKNOWN_USER',
UNKNOWN_VOICE_REGION: 'UNKNOWN_VOICE_REGION',
UNKNOWN_VOICE_SERVER: 'UNKNOWN_VOICE_SERVER',
UNKNOWN_WEBAUTHN_CREDENTIAL: 'UNKNOWN_WEBAUTHN_CREDENTIAL',
UNKNOWN_APPLICATION: 'UNKNOWN_APPLICATION',
UNKNOWN_WEBHOOK: 'UNKNOWN_WEBHOOK',
UNSUPPORTED_RESPONSE_TYPE: 'UNSUPPORTED_RESPONSE_TYPE',
USERNAME_NOT_AVAILABLE: 'USERNAME_NOT_AVAILABLE',
UPDATE_FAILED: 'UPDATE_FAILED',
USER_BANNED_FROM_GUILD: 'USER_BANNED_FROM_GUILD',
USER_IP_BANNED_FROM_GUILD: 'USER_IP_BANNED_FROM_GUILD',
USER_NOT_IN_VOICE: 'USER_NOT_IN_VOICE',
USER_OWNS_GUILDS: 'USER_OWNS_GUILDS',
VALIDATION_ERROR: 'VALIDATION_ERROR',
VOICE_CHANNEL_FULL: 'VOICE_CHANNEL_FULL',
WEBAUTHN_CREDENTIAL_LIMIT_REACHED: 'WEBAUTHN_CREDENTIAL_LIMIT_REACHED',
} as const;
export type APIErrorCode = ValueOf<typeof APIErrorCodes>;

View File

@@ -0,0 +1,303 @@
/*
* 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 type {APIErrorCodes} from '@fluxer/constants/src/ApiErrorCodes';
export const APIErrorCodesDescriptions: Record<keyof typeof APIErrorCodes, string> = {
ACCESS_DENIED: 'Access to this resource is denied',
ACCOUNT_DISABLED: 'This account has been disabled',
APPLICATION_NOT_FOUND: 'Application not found',
APPLICATION_NOT_OWNED: 'You do not own this application',
BAD_GATEWAY: 'Bad gateway',
BAD_REQUEST: 'Bad request',
BLUESKY_OAUTH_CALLBACK_FAILED: 'The Bluesky OAuth callback could not be processed',
BLUESKY_OAUTH_NOT_ENABLED: 'Bluesky OAuth connections are not enabled on this instance',
BLUESKY_OAUTH_SESSION_EXPIRED: 'The Bluesky OAuth session has expired or been revoked',
BLUESKY_OAUTH_STATE_INVALID: 'The OAuth state parameter is invalid or expired',
ACCOUNT_SCHEDULED_FOR_DELETION: 'This account is scheduled for deletion',
ACCOUNT_SUSPENDED_PERMANENTLY: 'This account has been permanently suspended',
ACCOUNT_SUSPENDED_TEMPORARILY: 'This account has been temporarily suspended',
ACCOUNT_SUSPICIOUS_ACTIVITY: 'Suspicious activity detected on this account',
ACCOUNT_TOO_NEW_FOR_GUILD: 'Account is too new to join this guild',
ACLS_MUST_BE_NON_EMPTY: 'Access control list must not be empty',
ADMIN_API_KEY_NOT_FOUND: 'Admin API key was not found',
ALREADY_FRIENDS: 'You are already friends with this user',
AUDIT_LOG_INDEXING: 'Audit log is currently being indexed',
BOTS_CANNOT_SEND_FRIEND_REQUESTS: 'Bots cannot send friend requests',
BOT_ALREADY_IN_GUILD: 'Bot is already in this guild',
BOT_APPLICATION_NOT_FOUND: 'Bot application not found',
BOT_IS_PRIVATE: 'This bot is private and can only be invited by the owner',
BOT_USER_AUTH_ENDPOINT_ACCESS_DENIED: 'Bot users cannot access this authentication endpoint',
BOT_USER_AUTH_SESSION_CREATION_DENIED: 'Bot users cannot create authentication sessions',
BOT_USER_NOT_FOUND: 'Bot user not found',
BOT_USER_GENERATION_FAILED: 'Failed to generate bot user',
CALL_ALREADY_EXISTS: 'A call already exists in this channel',
CANNOT_EDIT_OTHER_USER_MESSAGE: 'You cannot edit another user message',
CANNOT_EXECUTE_ON_DM: 'This action cannot be executed on a DM channel',
CANNOT_MODIFY_SYSTEM_WEBHOOK: 'System webhooks cannot be modified',
CANNOT_MODIFY_VOICE_STATE: 'Cannot modify voice state',
CANNOT_REDEEM_PLUTONIUM_WITH_VISIONARY: 'Cannot redeem plutonium while having Visionary subscription',
CANNOT_REPORT_OWN_GUILD: 'You cannot report your own guild',
CANNOT_REPORT_OWN_MESSAGE: 'You cannot report your own message',
CANNOT_REPORT_YOURSELF: 'You cannot report yourself',
CANNOT_SEND_EMPTY_MESSAGE: 'Cannot send an empty message',
CANNOT_SEND_FRIEND_REQUEST_TO_BLOCKED_USER: 'Cannot send friend request to a blocked user',
CANNOT_SEND_FRIEND_REQUEST_TO_SELF: 'Cannot send friend request to yourself',
CANNOT_SEND_MESSAGES_IN_NON_TEXT_CHANNEL: 'Cannot send messages in a non-text channel',
CANNOT_SEND_MESSAGES_TO_USER: 'Cannot send messages to this user',
CANNOT_TRANSFER_OWNERSHIP_TO_BOT: 'Guild ownership cannot be transferred to a bot',
CANNOT_SHRINK_RESERVED_SLOTS: 'Cannot shrink reserved slots',
CAPTCHA_REQUIRED: 'Captcha verification is required',
CHANNEL_INDEXING: 'Channel is currently being indexed',
COMMUNICATION_DISABLED: 'You are timed out in this guild',
CONNECTION_ALREADY_EXISTS: 'A connection of this type with this identifier already exists',
CONNECTION_INITIATION_TOKEN_INVALID: 'The connection initiation token is invalid or has expired',
CONNECTION_INVALID_IDENTIFIER: 'The connection identifier is invalid',
CONNECTION_INVALID_TYPE: 'The connection type is not supported',
CONNECTION_LIMIT_REACHED: 'Maximum number of connections reached',
CONNECTION_NOT_FOUND: 'Unknown connection',
CONNECTION_VERIFICATION_FAILED: 'Connection verification failed',
CONFLICT: 'Resource conflict',
CONTENT_BLOCKED: 'Content was blocked',
CREATION_FAILED: 'Resource creation failed',
CSAM_SCAN_FAILED: 'CSAM scan service error',
CSAM_SCAN_PARSE_ERROR: 'Failed to parse CSAM scan result',
CSAM_SCAN_SUBSCRIPTION_ERROR: 'CSAM scan subscription error',
CSAM_SCAN_TIMEOUT: 'CSAM scan request timed out',
DECRYPTION_FAILED: 'Failed to decrypt data',
DELETION_FAILED: 'Resource deletion failed',
DISCOVERY_ALREADY_APPLIED: 'This community has already applied for discovery',
DISCOVERY_APPLICATION_ALREADY_REVIEWED: 'This discovery application has already been reviewed',
DISCOVERY_APPLICATION_NOT_FOUND: 'Discovery application not found',
DISCOVERY_DESCRIPTION_REQUIRED: 'A description is required for discovery',
DISCOVERY_INSUFFICIENT_MEMBERS: 'Community does not meet the minimum member count for discovery',
DISCOVERY_INVALID_CATEGORY: 'Invalid discovery category',
DISCOVERY_NOT_DISCOVERABLE: 'This community is not listed in discovery',
DISCRIMINATOR_REQUIRED: 'A discriminator is required',
DONATION_AMOUNT_INVALID: 'Invalid donation amount',
DONATION_MAGIC_LINK_EXPIRED: 'Donation magic link has expired',
DONATION_MAGIC_LINK_INVALID: 'Invalid donation magic link',
DONATION_MAGIC_LINK_USED: 'Donation magic link has already been used',
DONOR_NOT_FOUND: 'Donor was not found',
EMPTY_ENCRYPTED_BODY: 'Encrypted body is empty',
ENCRYPTION_FAILED: 'Failed to encrypt data',
EMAIL_SERVICE_NOT_TESTABLE: 'Email service is not in testable mode',
EMAIL_VERIFICATION_REQUIRED: 'Email verification is required',
EXPLICIT_CONTENT_CANNOT_BE_SENT: 'Explicit content cannot be sent in this channel',
FEATURE_NOT_AVAILABLE_SELF_HOSTED: 'This feature is not available on self-hosted instances',
FEATURE_TEMPORARILY_DISABLED: 'This feature is temporarily disabled',
FILE_SIZE_TOO_LARGE: 'File size exceeds the maximum allowed',
FORBIDDEN: 'Access forbidden',
FRIEND_REQUEST_BLOCKED: 'Friend request was blocked',
GATEWAY_TIMEOUT: 'Gateway timeout',
GENERAL_ERROR: 'A general error occurred',
GONE: 'Resource no longer exists',
GIFT_CODE_ALREADY_REDEEMED: 'This gift code has already been redeemed',
GUILD_PHONE_VERIFICATION_REQUIRED: 'Phone verification is required to join this guild',
GUILD_VERIFICATION_REQUIRED: 'Account verification is required to interact in this guild',
HANDOFF_CODE_EXPIRED: 'Handoff code has expired',
HARVEST_EXPIRED: 'Data harvest request has expired',
HARVEST_FAILED: 'Data harvest failed',
HARVEST_NOT_READY: 'Data harvest is not yet ready',
HARVEST_ON_COOLDOWN: 'Data harvest is on cooldown',
HTTP_GET_AUTHORIZE_NOT_SUPPORTED: 'HTTP GET authorize is not supported',
INSTANCE_VERSION_MISMATCH: 'Instance version mismatch',
INTERNAL_SERVER_ERROR: 'Internal server error',
INVALID_ACLS_FORMAT: 'Invalid access control list format',
INVALID_API_ORIGIN: 'Invalid API origin',
INVALID_AUTH_TOKEN: 'Invalid authentication token',
INVALID_BOT_FLAG: 'Invalid bot flag',
INVALID_CAPTCHA: 'Invalid captcha response',
INVALID_CHANNEL_TYPE_FOR_CALL: 'Invalid channel type for call',
INVALID_CHANNEL_TYPE: 'Invalid channel type',
INVALID_CLIENT: 'Invalid OAuth2 client',
INVALID_CLIENT_SECRET: 'Invalid client secret',
INVALID_DSA_REPORT_TARGET: 'Invalid DSA report target',
INVALID_DSA_TICKET: 'Invalid DSA ticket',
INVALID_DSA_VERIFICATION_CODE: 'Invalid DSA verification code',
INVALID_DECRYPTED_JSON: 'Invalid JSON in decrypted data',
INVALID_EPHEMERAL_KEY: 'Invalid ephemeral key',
INVALID_FLAGS_FORMAT: 'Invalid flags format',
INVALID_FORM_BODY: 'Invalid request body format',
INVALID_IV: 'Invalid initialization vector',
INVALID_GRANT: 'Invalid OAuth2 grant',
INVALID_HANDOFF_CODE: 'Invalid handoff code',
INVALID_PACK_TYPE: 'Invalid pack type',
INVALID_PERMISSIONS_INTEGER: 'Invalid permissions value',
INVALID_PERMISSIONS_NEGATIVE: 'Permissions value cannot be negative',
INVALID_PHONE_NUMBER: 'Invalid phone number',
INVALID_PHONE_VERIFICATION_CODE: 'Invalid phone verification code',
INVALID_REDIRECT_URI: 'Invalid redirect URI',
INVALID_REQUEST: 'Invalid request',
INVALID_RESPONSE_TYPE_FOR_NON_BOT: 'Invalid response type for non-bot application',
INVALID_SCOPE: 'Invalid OAuth2 scope',
INVALID_STREAM_KEY_FORMAT: 'Invalid stream key format',
INVALID_STREAM_THUMBNAIL_PAYLOAD: 'Invalid stream thumbnail payload',
INVALID_SUDO_TOKEN: 'Invalid sudo token',
INVALID_SUSPICIOUS_FLAGS_FORMAT: 'Invalid suspicious flags format',
INVALID_SYSTEM_FLAG: 'Invalid system flag',
INVALID_TIMESTAMP: 'Invalid timestamp',
INVALID_TOKEN: 'Invalid token',
INVALID_WEBAUTHN_AUTHENTICATION_COUNTER: 'Invalid WebAuthn authentication counter',
INVALID_WEBAUTHN_CREDENTIAL_COUNTER: 'Invalid WebAuthn credential counter',
INVALID_WEBAUTHN_CREDENTIAL: 'Invalid WebAuthn credential',
INVALID_WEBAUTHN_PUBLIC_KEY_FORMAT: 'Invalid WebAuthn public key format',
INVITES_DISABLED: 'Invites are disabled for this guild',
IP_AUTHORIZATION_REQUIRED: 'IP address authorization is required',
IP_AUTHORIZATION_RESEND_COOLDOWN: 'IP authorization email resend is on cooldown',
IP_AUTHORIZATION_RESEND_LIMIT_EXCEEDED: 'IP authorization email resend limit exceeded',
IP_BANNED: 'This IP address has been banned',
MAX_ANIMATED_EMOJIS: 'Maximum animated emojis limit reached',
MAX_BOOKMARKS: 'Maximum bookmarks limit reached',
MAX_CATEGORY_CHANNELS: 'Maximum category channels limit reached',
MAX_EMOJIS: 'Maximum emojis limit reached',
MAX_FAVORITE_MEMES: 'Maximum favourite memes limit reached',
MAX_FRIENDS: 'Maximum friends limit reached',
MAX_GROUP_DM_RECIPIENTS: 'Maximum group DM recipients limit reached',
MAX_GROUP_DMS: 'Maximum group DMs limit reached',
MAX_GUILD_CHANNELS: 'Maximum guild channels limit reached',
MAX_GUILD_MEMBERS: 'Maximum guild members limit reached',
MAX_GUILD_ROLES: 'Maximum guild roles limit reached',
MAX_GUILDS: 'Maximum guilds limit reached',
MAX_INVITES: 'Maximum invites limit reached',
MAX_PACK_EXPRESSIONS: 'Maximum pack expressions limit reached',
MAX_PACKS: 'Maximum packs limit reached',
MAX_PINS_PER_CHANNEL: 'Maximum pins per channel limit reached',
MESSAGE_TOTAL_ATTACHMENT_SIZE_TOO_LARGE: 'Total attachment size per message is too large',
MAX_REACTIONS: 'Maximum reactions limit reached',
MAX_STICKERS: 'Maximum stickers limit reached',
MAX_WEBHOOKS_PER_CHANNEL: 'Maximum webhooks per channel limit reached',
MAX_WEBHOOKS_PER_GUILD: 'Maximum webhooks per guild limit reached',
MAX_WEBHOOKS: 'Maximum webhooks limit reached',
NCMEC_ALREADY_SUBMITTED: 'NCMEC report has already been submitted',
NCMEC_SUBMISSION_FAILED: 'NCMEC report submission failed',
MEDIA_METADATA_ERROR: 'Error processing media metadata',
METHOD_NOT_ALLOWED: 'Method not allowed',
MISSING_ACCESS: 'Missing access to this resource',
MISSING_ACL: 'Missing access control list entry',
MISSING_AUTHORIZATION: 'Missing authorization header',
MISSING_CLIENT_SECRET: 'Missing client secret',
MISSING_EPHEMERAL_KEY: 'Missing ephemeral key',
MISSING_IV: 'Missing initialization vector',
MISSING_OAUTH_ADMIN_SCOPE: 'Missing OAuth admin scope',
MISSING_OAUTH_FIELDS: 'Missing required OAuth fields',
MISSING_OAUTH_SCOPE: 'Missing required OAuth scope',
MISSING_PERMISSIONS: 'Missing required permissions',
MISSING_REDIRECT_URI: 'Missing redirect URI',
NO_ACTIVE_CALL: 'No active call in this channel',
NO_ACTIVE_SUBSCRIPTION: 'No active subscription',
NOT_A_BOT_APPLICATION: 'Application is not a bot',
NOT_FOUND: 'Resource not found',
NOT_IMPLEMENTED: 'Feature not implemented',
NO_PASSKEYS_REGISTERED: 'No passkeys registered for this account',
NO_PENDING_DELETION: 'No pending deletion for this account',
NO_USERS_WITH_FLUXERTAG_EXIST: 'No users with this Fluxertag exist',
NO_VISIONARY_SLOTS_AVAILABLE: 'No Visionary slots available',
NOT_FRIENDS_WITH_USER: 'You are not friends with this user',
NOT_OWNER_OF_ADMIN_API_KEY: 'You are not the owner of this admin API key',
NSFW_CONTENT_AGE_RESTRICTED: 'NSFW content is age restricted',
PACK_ACCESS_DENIED: 'Access to this pack is denied',
PASSKEY_AUTHENTICATION_FAILED: 'Passkey authentication failed',
PASSKEYS_DISABLED: 'Passkeys are disabled',
PHONE_ALREADY_USED: 'This phone number is already in use',
PHONE_RATE_LIMIT_EXCEEDED: 'Phone verification rate limit exceeded',
PHONE_REQUIRED_FOR_SMS_MFA: 'Phone number required for SMS MFA',
PHONE_VERIFICATION_REQUIRED: 'Phone verification is required',
PREMIUM_PURCHASE_BLOCKED: 'Premium purchase is blocked',
PREVIEW_MUST_BE_JPEG: 'Preview image must be JPEG format',
PROCESSING_FAILED: 'Processing failed',
RATE_LIMITED: 'You are being rate limited',
REDIRECT_URI_REQUIRED_FOR_NON_BOT: 'Redirect URI required for non-bot application',
REPORT_ALREADY_RESOLVED: 'This report has already been resolved',
REPORT_BANNED: 'You are banned from submitting reports',
RESPONSE_VALIDATION_ERROR: 'Response validation error',
SERVICE_UNAVAILABLE: 'Service temporarily unavailable',
SESSION_TOKEN_MISMATCH: 'Session token mismatch',
SLOWMODE_RATE_LIMITED: 'You are being rate limited by slowmode',
SMS_MFA_NOT_ENABLED: 'SMS MFA is not enabled',
SMS_MFA_REQUIRES_TOTP: 'SMS MFA requires TOTP to be enabled first',
SMS_VERIFICATION_UNAVAILABLE: 'SMS verification is unavailable',
SSO_REQUIRED: 'Single sign-on is required',
STREAM_KEY_CHANNEL_MISMATCH: 'Stream key does not match channel',
STREAM_KEY_SCOPE_MISMATCH: 'Stream key scope mismatch',
STREAM_THUMBNAIL_PAYLOAD_EMPTY: 'Stream thumbnail payload is empty',
STRIPE_ERROR: 'Stripe payment error',
STRIPE_GIFT_REDEMPTION_IN_PROGRESS: 'Gift redemption already in progress',
STRIPE_INVALID_PRODUCT: 'Invalid Stripe product',
STRIPE_INVALID_PRODUCT_CONFIGURATION: 'Invalid Stripe product configuration',
STRIPE_NO_ACTIVE_SUBSCRIPTION: 'No active Stripe subscription',
STRIPE_NO_PURCHASE_HISTORY: 'No Stripe purchase history',
STRIPE_NO_SUBSCRIPTION: 'No Stripe subscription',
STRIPE_PAYMENT_NOT_AVAILABLE: 'Stripe payment not available',
STRIPE_SUBSCRIPTION_ALREADY_CANCELING: 'Subscription is already being cancelled',
STRIPE_SUBSCRIPTION_NOT_CANCELING: 'Subscription is not being cancelled',
STRIPE_SUBSCRIPTION_PERIOD_END_MISSING: 'Subscription period end date is missing',
STRIPE_WEBHOOK_NOT_AVAILABLE: 'Stripe webhook not available',
STRIPE_WEBHOOK_SIGNATURE_INVALID: 'Invalid Stripe webhook signature',
STRIPE_WEBHOOK_SIGNATURE_MISSING: 'Missing Stripe webhook signature',
SUDO_MODE_REQUIRED: 'Sudo mode is required for this action',
TAG_ALREADY_TAKEN: 'This tag is already taken',
TEMPORARY_INVITE_REQUIRES_PRESENCE: 'Temporary invite requires presence tracking',
TEST_HARNESS_DISABLED: 'Test harness is disabled',
TEST_HARNESS_FORBIDDEN: 'Test harness access is forbidden',
TWO_FA_NOT_ENABLED: 'Two-factor authentication is not enabled',
TWO_FACTOR_REQUIRED: 'Two-factor authentication is required',
UNAUTHORIZED: 'Unauthorized',
UNCLAIMED_ACCOUNT_CANNOT_ACCEPT_FRIEND_REQUESTS: 'Unclaimed accounts cannot accept friend requests',
UNCLAIMED_ACCOUNT_CANNOT_ADD_REACTIONS: 'Unclaimed accounts cannot add reactions',
UNCLAIMED_ACCOUNT_CANNOT_CREATE_APPLICATIONS: 'Unclaimed accounts cannot create applications',
UNCLAIMED_ACCOUNT_CANNOT_JOIN_GROUP_DMS: 'Unclaimed accounts cannot join group DMs',
UNCLAIMED_ACCOUNT_CANNOT_JOIN_ONE_ON_ONE_VOICE_CALLS: 'Unclaimed accounts cannot join one-on-one voice calls',
UNCLAIMED_ACCOUNT_CANNOT_JOIN_VOICE_CHANNELS: 'Unclaimed accounts cannot join voice channels',
UNCLAIMED_ACCOUNT_CANNOT_MAKE_PURCHASES: 'Unclaimed accounts cannot make purchases',
UNCLAIMED_ACCOUNT_CANNOT_SEND_DIRECT_MESSAGES: 'Unclaimed accounts cannot send direct messages',
UNCLAIMED_ACCOUNT_CANNOT_SEND_FRIEND_REQUESTS: 'Unclaimed accounts cannot send friend requests',
UNCLAIMED_ACCOUNT_CANNOT_SEND_MESSAGES: 'Unclaimed accounts cannot send messages',
UNKNOWN_CHANNEL: 'Unknown channel',
UNKNOWN_EMOJI: 'Unknown emoji',
UNKNOWN_FAVORITE_MEME: 'Unknown favourite meme',
UNKNOWN_GIFT_CODE: 'Unknown gift code',
UNKNOWN_GUILD: 'Unknown guild',
UNKNOWN_HARVEST: 'Unknown data harvest',
UNKNOWN_INVITE: 'Unknown invite',
UNKNOWN_MEMBER: 'Unknown member',
UNKNOWN_MESSAGE: 'Unknown message',
UNKNOWN_PACK: 'Unknown pack',
UNKNOWN_REPORT: 'Unknown report',
UNKNOWN_ROLE: 'Unknown role',
UNKNOWN_STICKER: 'Unknown sticker',
UNKNOWN_SUSPICIOUS_FLAG: 'Unknown suspicious flag',
UNKNOWN_USER_FLAG: 'Unknown user flag',
UNKNOWN_USER: 'Unknown user',
UNKNOWN_VOICE_REGION: 'Unknown voice region',
UNKNOWN_VOICE_SERVER: 'Unknown voice server',
UNKNOWN_WEBAUTHN_CREDENTIAL: 'Unknown WebAuthn credential',
UNKNOWN_APPLICATION: 'Unknown application',
UNKNOWN_WEBHOOK: 'Unknown webhook',
UNSUPPORTED_RESPONSE_TYPE: 'Unsupported response type',
UPDATE_FAILED: 'Resource update failed',
USER_BANNED_FROM_GUILD: 'User is banned from this guild',
USER_IP_BANNED_FROM_GUILD: 'User IP is banned from this guild',
USER_NOT_IN_VOICE: 'User is not in a voice channel',
USER_OWNS_GUILDS: 'User owns guilds and cannot perform this action',
USERNAME_NOT_AVAILABLE: 'Username is not available',
VALIDATION_ERROR: 'Validation error',
VOICE_CHANNEL_FULL: 'Voice channel is full',
WEBAUTHN_CREDENTIAL_LIMIT_REACHED: 'WebAuthn credential limit reached',
};

View File

@@ -0,0 +1,25 @@
/*
* 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/>.
*/
export const API_CODE_VERSION = 1;
export const DEFAULT_API_VERSION = 1;
export const FLUXERBOT_ID = '0';
export const ME = '@me';
export const FAVORITES_GUILD_ID = '@favorites';
export const DEFAULT_ACCENT_COLOR = '#4641D9';

View File

@@ -0,0 +1,102 @@
/*
* 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/>.
*/
export enum AuditLogActionType {
GUILD_UPDATE = 1,
CHANNEL_CREATE = 10,
CHANNEL_UPDATE = 11,
CHANNEL_DELETE = 12,
CHANNEL_OVERWRITE_CREATE = 13,
CHANNEL_OVERWRITE_UPDATE = 14,
CHANNEL_OVERWRITE_DELETE = 15,
MEMBER_KICK = 20,
MEMBER_PRUNE = 21,
MEMBER_BAN_ADD = 22,
MEMBER_BAN_REMOVE = 23,
MEMBER_UPDATE = 24,
MEMBER_ROLE_UPDATE = 25,
MEMBER_MOVE = 26,
MEMBER_DISCONNECT = 27,
BOT_ADD = 28,
ROLE_CREATE = 30,
ROLE_UPDATE = 31,
ROLE_DELETE = 32,
INVITE_CREATE = 40,
INVITE_UPDATE = 41,
INVITE_DELETE = 42,
WEBHOOK_CREATE = 50,
WEBHOOK_UPDATE = 51,
WEBHOOK_DELETE = 52,
EMOJI_CREATE = 60,
EMOJI_UPDATE = 61,
EMOJI_DELETE = 62,
STICKER_CREATE = 90,
STICKER_UPDATE = 91,
STICKER_DELETE = 92,
MESSAGE_DELETE = 72,
MESSAGE_BULK_DELETE = 73,
MESSAGE_PIN = 74,
MESSAGE_UNPIN = 75,
}
export const ALL_AUDIT_LOG_ACTION_TYPES: ReadonlyArray<AuditLogActionType> = [
AuditLogActionType.GUILD_UPDATE,
AuditLogActionType.CHANNEL_CREATE,
AuditLogActionType.CHANNEL_UPDATE,
AuditLogActionType.CHANNEL_DELETE,
AuditLogActionType.CHANNEL_OVERWRITE_CREATE,
AuditLogActionType.CHANNEL_OVERWRITE_UPDATE,
AuditLogActionType.CHANNEL_OVERWRITE_DELETE,
AuditLogActionType.MEMBER_KICK,
AuditLogActionType.MEMBER_PRUNE,
AuditLogActionType.MEMBER_BAN_ADD,
AuditLogActionType.MEMBER_BAN_REMOVE,
AuditLogActionType.MEMBER_UPDATE,
AuditLogActionType.MEMBER_ROLE_UPDATE,
AuditLogActionType.MEMBER_MOVE,
AuditLogActionType.MEMBER_DISCONNECT,
AuditLogActionType.BOT_ADD,
AuditLogActionType.ROLE_CREATE,
AuditLogActionType.ROLE_UPDATE,
AuditLogActionType.ROLE_DELETE,
AuditLogActionType.INVITE_CREATE,
AuditLogActionType.INVITE_UPDATE,
AuditLogActionType.INVITE_DELETE,
AuditLogActionType.WEBHOOK_CREATE,
AuditLogActionType.WEBHOOK_UPDATE,
AuditLogActionType.WEBHOOK_DELETE,
AuditLogActionType.EMOJI_CREATE,
AuditLogActionType.EMOJI_UPDATE,
AuditLogActionType.EMOJI_DELETE,
AuditLogActionType.STICKER_CREATE,
AuditLogActionType.STICKER_UPDATE,
AuditLogActionType.STICKER_DELETE,
AuditLogActionType.MESSAGE_DELETE,
AuditLogActionType.MESSAGE_BULK_DELETE,
AuditLogActionType.MESSAGE_PIN,
AuditLogActionType.MESSAGE_UNPIN,
];

View File

@@ -0,0 +1,23 @@
/*
* 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/>.
*/
export const SESSION_MAX_AGE_SECONDS = 60 * 60 * 24 * 7;
export const CSRF_TOKEN_LENGTH = 32;
export const CSRF_TOKEN_MAX_AGE_SECONDS = 60 * 60 * 24;
export const SUDO_MODE_MAX_AGE_SECONDS = 60 * 5;

View File

@@ -0,0 +1,32 @@
/*
* 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 {PublicUserFlags} from '@fluxer/constants/src/UserConstants';
export const ApplicationFlags = {} as const;
export const BotFlags = {
FRIENDLY_BOT: PublicUserFlags.FRIENDLY_BOT,
FRIENDLY_BOT_MANUAL_APPROVAL: PublicUserFlags.FRIENDLY_BOT_MANUAL_APPROVAL,
} as const;
export const BotFlagsDescriptions: Record<keyof typeof BotFlags, string> = {
FRIENDLY_BOT: 'Bot accepts friend requests from users',
FRIENDLY_BOT_MANUAL_APPROVAL: 'Bot requires manual approval for friend requests',
};

View File

@@ -0,0 +1,22 @@
/*
* 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/>.
*/
export const CACHE_IMMUTABLE = 'public, max-age=31536000, immutable';
export const CACHE_NO_STORE = 'no-cache, no-store, must-revalidate';
export const CACHE_NO_CACHE = 'no-cache';

View File

@@ -0,0 +1,23 @@
/*
* 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/>.
*/
export const CdnEndpoints = {
STATIC: 'https://fluxerstatic.com',
STATIC_HOST: 'fluxerstatic.com',
} as const;

View File

@@ -0,0 +1,299 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const ChannelTypes = {
GUILD_TEXT: 0,
DM: 1,
GUILD_VOICE: 2,
GROUP_DM: 3,
GUILD_CATEGORY: 4,
GUILD_LINK: 998,
DM_PERSONAL_NOTES: 999,
} as const;
export type ChannelType = ValueOf<typeof ChannelTypes>;
export const TEXT_BASED_CHANNEL_TYPES = new Set<number>([
ChannelTypes.GUILD_TEXT,
ChannelTypes.DM,
ChannelTypes.DM_PERSONAL_NOTES,
ChannelTypes.GROUP_DM,
]);
export const ChannelOverwriteTypes = {
ROLE: 0,
MEMBER: 1,
} as const;
export const ChannelOverwriteTypesDescriptions: Record<keyof typeof ChannelOverwriteTypes, string> = {
ROLE: 'Overwrite applies to a role',
MEMBER: 'Overwrite applies to a member',
};
export const InviteTypes = {
GUILD: 0,
GROUP_DM: 1,
EMOJI_PACK: 2,
STICKER_PACK: 3,
} as const;
export const MessageTypes = {
DEFAULT: 0,
RECIPIENT_ADD: 1,
RECIPIENT_REMOVE: 2,
CALL: 3,
CHANNEL_NAME_CHANGE: 4,
CHANNEL_ICON_CHANGE: 5,
CHANNEL_PINNED_MESSAGE: 6,
USER_JOIN: 7,
REPLY: 19,
CLIENT_SYSTEM: 99,
} as const;
export const MessageTypesDescriptions: Record<keyof typeof MessageTypes, string> = {
DEFAULT: 'A regular message',
RECIPIENT_ADD: 'A system message indicating a user was added to the conversation',
RECIPIENT_REMOVE: 'A system message indicating a user was removed from the conversation',
CALL: 'A message representing a call',
CHANNEL_NAME_CHANGE: 'A system message indicating the channel name changed',
CHANNEL_ICON_CHANGE: 'A system message indicating the channel icon changed',
CHANNEL_PINNED_MESSAGE: 'A system message indicating a message was pinned',
USER_JOIN: 'A system message indicating a user joined',
REPLY: 'A reply message',
CLIENT_SYSTEM: 'A client-side system message',
};
export type MessageTypeValue = ValueOf<typeof MessageTypes>;
export const MESSAGE_TYPE_DELETABLE = {
[MessageTypes.DEFAULT]: true,
[MessageTypes.REPLY]: true,
[MessageTypes.CHANNEL_PINNED_MESSAGE]: true,
[MessageTypes.USER_JOIN]: true,
[MessageTypes.RECIPIENT_ADD]: false,
[MessageTypes.RECIPIENT_REMOVE]: false,
[MessageTypes.CALL]: false,
[MessageTypes.CHANNEL_NAME_CHANGE]: false,
[MessageTypes.CHANNEL_ICON_CHANGE]: false,
[MessageTypes.CLIENT_SYSTEM]: false,
} as const satisfies Record<MessageTypeValue, boolean>;
export function isMessageTypeDeletable(type: number): boolean {
return type in MESSAGE_TYPE_DELETABLE ? MESSAGE_TYPE_DELETABLE[type as MessageTypeValue] : false;
}
export const MessageReferenceTypes = {
DEFAULT: 0,
FORWARD: 1,
} as const;
export const MessageReferenceTypesDescriptions: Record<keyof typeof MessageReferenceTypes, string> = {
DEFAULT: 'Default reference (reply)',
FORWARD: 'Forwarded message reference',
};
export const AllowedMentionParseTypes = {
USERS: 'users',
ROLES: 'roles',
EVERYONE: 'everyone',
} as const;
export const AllowedMentionParseTypesDescriptions: Record<keyof typeof AllowedMentionParseTypes, string> = {
USERS: 'Parse user mentions from the message content',
ROLES: 'Parse role mentions from the message content',
EVERYONE: 'Parse @everyone and @here mentions from the message content',
};
export const MessageFlags = {
SUPPRESS_EMBEDS: 1 << 2,
SUPPRESS_NOTIFICATIONS: 1 << 12,
VOICE_MESSAGE: 1 << 13,
COMPACT_ATTACHMENTS: 1 << 17,
} as const;
export const MessageFlagsDescriptions: Record<keyof typeof MessageFlags, string> = {
SUPPRESS_EMBEDS: 'Do not include embeds when serialising this message',
SUPPRESS_NOTIFICATIONS: 'This message will not trigger push or desktop notifications',
VOICE_MESSAGE: 'This message is a voice message',
COMPACT_ATTACHMENTS: 'Display attachments in a compact format',
};
export const SENDABLE_MESSAGE_FLAGS =
MessageFlags.SUPPRESS_EMBEDS |
MessageFlags.SUPPRESS_NOTIFICATIONS |
MessageFlags.COMPACT_ATTACHMENTS |
MessageFlags.VOICE_MESSAGE;
export const MessageAttachmentFlags = {
IS_SPOILER: 1 << 3,
CONTAINS_EXPLICIT_MEDIA: 1 << 4,
IS_ANIMATED: 1 << 5,
} as const;
export const MessageAttachmentFlagsDescriptions: Record<keyof typeof MessageAttachmentFlags, string> = {
IS_SPOILER: 'Attachment is marked as a spoiler',
CONTAINS_EXPLICIT_MEDIA: 'Attachment contains explicit media content',
IS_ANIMATED: 'Attachment is animated',
};
export const EmbedMediaFlags = {
CONTAINS_EXPLICIT_MEDIA: 1 << 4,
IS_ANIMATED: 1 << 5,
} as const;
export const EmbedMediaFlagsDescriptions: Record<keyof typeof EmbedMediaFlags, string> = {
CONTAINS_EXPLICIT_MEDIA: 'Embed media contains explicit content',
IS_ANIMATED: 'Embed media is animated',
};
export const MessageEmbedTypes = {
RICH: 'rich',
ARTICLE: 'article',
LINK: 'link',
IMAGE: 'image',
VIDEO: 'video',
AUDIO: 'audio',
GIFV: 'gifv',
BLUESKY: 'bluesky',
} as const;
export const MessageStates = {
SENT: 'SENT',
SENDING: 'SENDING',
EDITING: 'EDITING',
FAILED: 'FAILED',
} as const;
export const MessagePreviewContext = {
SETTINGS: 'SETTINGS',
LIST_POPOUT: 'LIST_POPOUT',
} as const;
export const Permissions = {
CREATE_INSTANT_INVITE: 1n << 0n,
KICK_MEMBERS: 1n << 1n,
BAN_MEMBERS: 1n << 2n,
ADMINISTRATOR: 1n << 3n,
MANAGE_CHANNELS: 1n << 4n,
MANAGE_GUILD: 1n << 5n,
ADD_REACTIONS: 1n << 6n,
VIEW_AUDIT_LOG: 1n << 7n,
PRIORITY_SPEAKER: 1n << 8n,
STREAM: 1n << 9n,
VIEW_CHANNEL: 1n << 10n,
SEND_MESSAGES: 1n << 11n,
SEND_TTS_MESSAGES: 1n << 12n,
MANAGE_MESSAGES: 1n << 13n,
EMBED_LINKS: 1n << 14n,
ATTACH_FILES: 1n << 15n,
READ_MESSAGE_HISTORY: 1n << 16n,
MENTION_EVERYONE: 1n << 17n,
USE_EXTERNAL_EMOJIS: 1n << 18n,
CONNECT: 1n << 20n,
SPEAK: 1n << 21n,
MUTE_MEMBERS: 1n << 22n,
DEAFEN_MEMBERS: 1n << 23n,
MOVE_MEMBERS: 1n << 24n,
USE_VAD: 1n << 25n,
CHANGE_NICKNAME: 1n << 26n,
MANAGE_NICKNAMES: 1n << 27n,
MANAGE_ROLES: 1n << 28n,
MANAGE_WEBHOOKS: 1n << 29n,
MANAGE_EXPRESSIONS: 1n << 30n,
USE_EXTERNAL_STICKERS: 1n << 37n,
MODERATE_MEMBERS: 1n << 40n,
CREATE_EXPRESSIONS: 1n << 43n,
PIN_MESSAGES: 1n << 51n,
BYPASS_SLOWMODE: 1n << 52n,
UPDATE_RTC_REGION: 1n << 53n,
} as const;
export const PermissionsDescriptions: Record<keyof typeof Permissions, string> = {
CREATE_INSTANT_INVITE: 'Allows creation of instant invites',
KICK_MEMBERS: 'Allows kicking members from the guild',
BAN_MEMBERS: 'Allows banning members from the guild',
ADMINISTRATOR: 'Grants all permissions and bypasses channel permission overwrites',
MANAGE_CHANNELS: 'Allows management and editing of channels',
MANAGE_GUILD: 'Allows management and editing of the guild',
ADD_REACTIONS: 'Allows adding reactions to messages',
VIEW_AUDIT_LOG: 'Allows viewing of the audit log',
PRIORITY_SPEAKER: 'Allows using priority speaker in a voice channel',
STREAM: 'Allows the user to go live',
VIEW_CHANNEL: 'Allows viewing a channel',
SEND_MESSAGES: 'Allows sending messages in a channel',
SEND_TTS_MESSAGES: 'Allows sending text-to-speech messages',
MANAGE_MESSAGES: 'Allows for deleting and pinning messages',
EMBED_LINKS: 'Links sent will have an embed automatically',
ATTACH_FILES: 'Allows uploading files',
READ_MESSAGE_HISTORY: 'Allows reading message history',
MENTION_EVERYONE: 'Allows using @everyone and @here mentions',
USE_EXTERNAL_EMOJIS: 'Allows using emojis from other guilds',
CONNECT: 'Allows connecting to a voice channel',
SPEAK: 'Allows speaking in a voice channel',
MUTE_MEMBERS: 'Allows muting members in voice channels',
DEAFEN_MEMBERS: 'Allows deafening members in voice channels',
MOVE_MEMBERS: 'Allows moving members between voice channels',
USE_VAD: 'Allows using voice activity detection',
CHANGE_NICKNAME: 'Allows changing own nickname',
MANAGE_NICKNAMES: 'Allows changing other members nicknames',
MANAGE_ROLES: 'Allows management and editing of roles',
MANAGE_WEBHOOKS: 'Allows management and editing of webhooks',
MANAGE_EXPRESSIONS: 'Allows management of guild expressions',
USE_EXTERNAL_STICKERS: 'Allows using stickers from other guilds',
MODERATE_MEMBERS: 'Allows timing out users',
CREATE_EXPRESSIONS: 'Allows creating guild expressions',
PIN_MESSAGES: 'Allows pinning messages',
BYPASS_SLOWMODE: 'Allows bypassing slowmode',
UPDATE_RTC_REGION: 'Allows updating the voice region',
};
export const ALL_PERMISSIONS = Object.values(Permissions).reduce((acc, p) => acc | p, 0n);
export const DEFAULT_PERMISSIONS =
Permissions.CREATE_INSTANT_INVITE |
Permissions.ADD_REACTIONS |
Permissions.STREAM |
Permissions.VIEW_CHANNEL |
Permissions.SEND_MESSAGES |
Permissions.EMBED_LINKS |
Permissions.ATTACH_FILES |
Permissions.READ_MESSAGE_HISTORY |
Permissions.USE_EXTERNAL_EMOJIS |
Permissions.CONNECT |
Permissions.SPEAK |
Permissions.USE_VAD |
Permissions.CHANGE_NICKNAME |
Permissions.USE_EXTERNAL_STICKERS |
Permissions.CREATE_EXPRESSIONS;
export const ElevatedPermissions =
Permissions.KICK_MEMBERS |
Permissions.BAN_MEMBERS |
Permissions.ADMINISTRATOR |
Permissions.MANAGE_CHANNELS |
Permissions.MANAGE_GUILD |
Permissions.MANAGE_ROLES |
Permissions.MANAGE_MESSAGES |
Permissions.MANAGE_WEBHOOKS |
Permissions.MANAGE_EXPRESSIONS |
Permissions.MODERATE_MEMBERS;
export const CHANNEL_REINDEX_AFTER_TIMESTAMP = 1769813072;

View File

@@ -0,0 +1,54 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const ConnectionTypes = {
BLUESKY: 'bsky',
DOMAIN: 'domain',
} as const;
export type ConnectionType = ValueOf<typeof ConnectionTypes>;
export const ConnectionTypesDescriptions: Record<keyof typeof ConnectionTypes, string> = {
BLUESKY: 'Bluesky social account connection',
DOMAIN: 'Custom domain ownership connection',
};
export const ConnectionVisibilityFlags = {
EVERYONE: 1 << 0,
FRIENDS: 1 << 1,
MUTUAL_GUILDS: 1 << 2,
} as const;
export type ConnectionVisibilityFlag = ValueOf<typeof ConnectionVisibilityFlags>;
export const ConnectionVisibilityFlagsDescriptions: Record<keyof typeof ConnectionVisibilityFlags, string> = {
EVERYONE: 'Allow anyone to see this connection',
FRIENDS: 'Allow friends to see this connection',
MUTUAL_GUILDS: 'Allow members from mutual guilds to see this connection',
};
export const MAX_CONNECTIONS_PER_USER = 20;
export const CONNECTION_VERIFICATION_TOKEN_LENGTH = 32;
export const CONNECTION_REVALIDATION_INTERVAL_HOURS = 24;
export const CONNECTION_INITIATION_TOKEN_EXPIRY_MS = 30 * 60 * 1000;

View File

@@ -0,0 +1,24 @@
/*
* 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/>.
*/
export const CSRF_COOKIE_NAME = 'csrf_token';
export const CSRF_HEADER_NAME = 'x-csrf-token';
export const CSRF_FORM_FIELD = '_csrf';
export const FLASH_COOKIE_NAME = 'flash';
export const SESSION_COOKIE_NAME = 'session';

View File

@@ -0,0 +1,52 @@
/*
* 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/>.
*/
export const FLUXER_EPOCH = 1420070400000;
export const FLUXER_USER_AGENT = 'Mozilla/5.0 (compatible; Fluxerbot/1.0; +https://fluxer.app)';
export const ADMIN_OAUTH2_APPLICATION_ID = 1234567890123456789n;
export const USER_MENTION_REGEX = /<@!?(?<userId>\d+)>/g;
export const ROLE_MENTION_REGEX = /<@&(?<roleId>\d+)>/g;
export const URL_REGEX = /https?:\/\/[^\s/$.?#].[^\s]*/g;
export const DeletionReasons = {
USER_REQUESTED: 1,
OTHER: 2,
SPAM: 3,
CHEATING_OR_EXPLOITATION: 4,
COORDINATED_RAIDING: 5,
AUTOMATION_OR_SELFBOT: 6,
NONCONSENSUAL_SEXUAL_CONTENT: 7,
SCAM_OR_SOCIAL_ENGINEERING: 8,
CHILD_SEXUAL_CONTENT: 9,
PRIVACY_VIOLATION_OR_DOXXING: 10,
HARASSMENT_OR_BULLYING: 11,
PAYMENT_FRAUD: 12,
CHILD_SAFETY_VIOLATION: 13,
BILLING_DISPUTE_OR_ABUSE: 14,
UNSOLICITED_EXPLICIT_CONTENT: 15,
GRAPHIC_VIOLENCE: 16,
BAN_EVASION: 17,
TOKEN_OR_CREDENTIAL_SCAM: 18,
INACTIVITY: 19,
HATE_SPEECH_OR_EXTREMIST_CONTENT: 20,
MALICIOUS_LINKS_OR_MALWARE: 21,
IMPERSONATION_OR_FAKE_IDENTITY: 22,
} as const;

View File

@@ -0,0 +1,60 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const DiscoveryCategories = {
GAMING: 0,
MUSIC: 1,
ENTERTAINMENT: 2,
EDUCATION: 3,
SCIENCE_AND_TECHNOLOGY: 4,
CONTENT_CREATOR: 5,
ANIME_AND_MANGA: 6,
MOVIES_AND_TV: 7,
OTHER: 8,
} as const;
export type DiscoveryCategory = ValueOf<typeof DiscoveryCategories>;
export const DiscoveryCategoryLabels: Record<DiscoveryCategory, string> = {
0: 'Gaming',
1: 'Music',
2: 'Entertainment',
3: 'Education',
4: 'Science & Technology',
5: 'Content Creator',
6: 'Anime & Manga',
7: 'Movies & TV',
8: 'Other',
};
export const DiscoveryApplicationStatus = {
PENDING: 'pending',
APPROVED: 'approved',
REJECTED: 'rejected',
REMOVED: 'removed',
} as const;
export type DiscoveryApplicationStatusValue = ValueOf<typeof DiscoveryApplicationStatus>;
export const DISCOVERY_MIN_MEMBER_COUNT = 50;
export const DISCOVERY_MIN_MEMBER_COUNT_DEV = 1;
export const DISCOVERY_DESCRIPTION_MIN_LENGTH = 10;
export const DISCOVERY_DESCRIPTION_MAX_LENGTH = 300;

View File

@@ -0,0 +1,24 @@
/*
* 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/>.
*/
export const NON_SELF_HOSTED_RESERVED_DISCRIMINATORS = new Set<number>([
1, 2, 3, 4, 5, 6, 7, 8, 9, 67, 69, 404, 420, 666, 911, 1000, 1111, 1234, 1337, 2000, 2025, 2026, 2027, 2222, 2345,
3000, 3333, 3456, 4000, 4321, 4444, 4567, 5000, 5432, 5555, 5678, 6000, 6543, 6666, 6789, 6969, 7000, 7654, 7777,
7890, 8000, 8008, 8055, 8080, 8765, 8888, 9000, 9001, 9876, 9999,
]);

View File

@@ -0,0 +1,20 @@
/*
* 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/>.
*/
export const DONATION_MAGIC_LINK_EXPIRY_MS = 15 * 60 * 1000;

View File

@@ -0,0 +1,20 @@
/*
* 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/>.
*/
export const SKIN_TONE_SURROGATES = ['🏻', '🏼', '🏽', '🏾', '🏿'];

View File

@@ -0,0 +1,73 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const CommonErrorCode = {
INTERNAL_ERROR: 'InternalError',
INVALID_ARGUMENT: 'InvalidArgument',
INVALID_REQUEST: 'InvalidRequest',
INVALID_OPERATION: 'InvalidOperation',
ACCESS_DENIED: 'AccessDenied',
UNAUTHORIZED: 'Unauthorized',
FORBIDDEN: 'Forbidden',
INVALID_TOKEN: 'InvalidToken',
NOT_FOUND: 'NotFound',
KEY_NOT_FOUND: 'KeyNotFound',
RESOURCE_NOT_FOUND: 'ResourceNotFound',
ALREADY_EXISTS: 'AlreadyExists',
CONFLICT: 'Conflict',
TYPE_MISMATCH: 'TypeMismatch',
VALIDATION_ERROR: 'ValidationError',
RATE_LIMITED: 'RateLimited',
TOO_MANY_REQUESTS: 'TooManyRequests',
SERVICE_UNAVAILABLE: 'ServiceUnavailable',
NOT_IMPLEMENTED: 'NotImplemented',
TIMEOUT: 'Timeout',
} as const;
export type CommonErrorCodeValue = ValueOf<typeof CommonErrorCode>;
export const ErrorCodeToStatus: Record<CommonErrorCodeValue, number> = {
[CommonErrorCode.INTERNAL_ERROR]: 500,
[CommonErrorCode.INVALID_ARGUMENT]: 400,
[CommonErrorCode.INVALID_REQUEST]: 400,
[CommonErrorCode.INVALID_OPERATION]: 400,
[CommonErrorCode.ACCESS_DENIED]: 403,
[CommonErrorCode.UNAUTHORIZED]: 401,
[CommonErrorCode.FORBIDDEN]: 403,
[CommonErrorCode.INVALID_TOKEN]: 401,
[CommonErrorCode.NOT_FOUND]: 404,
[CommonErrorCode.KEY_NOT_FOUND]: 404,
[CommonErrorCode.RESOURCE_NOT_FOUND]: 404,
[CommonErrorCode.ALREADY_EXISTS]: 409,
[CommonErrorCode.CONFLICT]: 409,
[CommonErrorCode.TYPE_MISMATCH]: 400,
[CommonErrorCode.VALIDATION_ERROR]: 400,
[CommonErrorCode.RATE_LIMITED]: 429,
[CommonErrorCode.TOO_MANY_REQUESTS]: 429,
[CommonErrorCode.SERVICE_UNAVAILABLE]: 503,
[CommonErrorCode.NOT_IMPLEMENTED]: 501,
[CommonErrorCode.TIMEOUT]: 408,
};

View File

@@ -0,0 +1,20 @@
/*
* 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/>.
*/
export const FEDERATION_PROTOCOL_VERSION = 1;

View File

@@ -0,0 +1,85 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const GatewayOpcodes = {
DISPATCH: 0,
HEARTBEAT: 1,
IDENTIFY: 2,
PRESENCE_UPDATE: 3,
VOICE_STATE_UPDATE: 4,
VOICE_SERVER_PING: 5,
RESUME: 6,
RECONNECT: 7,
REQUEST_GUILD_MEMBERS: 8,
INVALID_SESSION: 9,
HELLO: 10,
HEARTBEAT_ACK: 11,
GATEWAY_ERROR: 12,
LAZY_REQUEST: 14,
} as const;
export const LARGE_GUILD_THRESHOLD = 250;
export const MEMBER_CHUNK_SIZE = 1000;
export const GatewayIdentifyFlags = {
USE_CANARY_API: 1 << 0,
DEBOUNCE_MESSAGE_REACTIONS: 1 << 1,
} as const;
export const GatewayCloseCodes = {
UNKNOWN_ERROR: 4000,
UNKNOWN_OPCODE: 4001,
DECODE_ERROR: 4002,
NOT_AUTHENTICATED: 4003,
AUTHENTICATION_FAILED: 4004,
ALREADY_AUTHENTICATED: 4005,
INVALID_SEQ: 4007,
RATE_LIMITED: 4008,
SESSION_TIMEOUT: 4009,
INVALID_SHARD: 4010,
SHARDING_REQUIRED: 4011,
INVALID_API_VERSION: 4012,
} as const;
export const GatewayErrorCodes = {
DM_INVALID_CHANNEL_TYPE: 'DM_INVALID_CHANNEL_TYPE',
DM_NOT_RECIPIENT: 'DM_NOT_RECIPIENT',
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
VOICE_CHANNEL_FULL: 'VOICE_CHANNEL_FULL',
VOICE_CHANNEL_NOT_FOUND: 'VOICE_CHANNEL_NOT_FOUND',
VOICE_CONNECTION_NOT_FOUND: 'VOICE_CONNECTION_NOT_FOUND',
VOICE_GUILD_ID_MISSING: 'VOICE_GUILD_ID_MISSING',
VOICE_GUILD_NOT_FOUND: 'VOICE_GUILD_NOT_FOUND',
VOICE_INVALID_CHANNEL_ID: 'VOICE_INVALID_CHANNEL_ID',
VOICE_INVALID_CHANNEL_TYPE: 'VOICE_INVALID_CHANNEL_TYPE',
VOICE_INVALID_GUILD_ID: 'VOICE_INVALID_GUILD_ID',
VOICE_INVALID_STATE: 'VOICE_INVALID_STATE',
VOICE_INVALID_USER_ID: 'VOICE_INVALID_USER_ID',
VOICE_MEMBER_NOT_FOUND: 'VOICE_MEMBER_NOT_FOUND',
VOICE_MEMBER_TIMED_OUT: 'VOICE_MEMBER_TIMED_OUT',
VOICE_MISSING_CONNECTION_ID: 'VOICE_MISSING_CONNECTION_ID',
VOICE_PERMISSION_DENIED: 'VOICE_PERMISSION_DENIED',
VOICE_TOKEN_FAILED: 'VOICE_TOKEN_FAILED',
VOICE_UNCLAIMED_ACCOUNT: 'VOICE_UNCLAIMED_ACCOUNT',
VOICE_USER_MISMATCH: 'VOICE_USER_MISMATCH',
VOICE_USER_NOT_IN_VOICE: 'VOICE_USER_NOT_IN_VOICE',
} as const;
export type GatewayErrorCode = ValueOf<typeof GatewayErrorCodes>;

View File

@@ -0,0 +1,150 @@
/*
* 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 {ManagedTraits} from '@fluxer/constants/src/ManagedTraits';
import type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const GuildVerificationLevel = {
NONE: 0,
LOW: 1,
MEDIUM: 2,
HIGH: 3,
VERY_HIGH: 4,
} as const;
export const GuildMFALevel = {
NONE: 0,
ELEVATED: 1,
} as const;
export const GuildSplashCardAlignment = {
CENTER: 0,
LEFT: 1,
RIGHT: 2,
} as const;
export type GuildSplashCardAlignmentValue = ValueOf<typeof GuildSplashCardAlignment>;
export const SystemChannelFlags = {
SUPPRESS_JOIN_NOTIFICATIONS: 1 << 0,
} as const;
export const SystemChannelFlagsDescriptions: Record<keyof typeof SystemChannelFlags, string> = {
SUPPRESS_JOIN_NOTIFICATIONS: 'Suppress member join notifications in system channel',
};
export const GuildOperations = {
PUSH_NOTIFICATIONS: 1 << 0,
EVERYONE_MENTIONS: 1 << 1,
TYPING_EVENTS: 1 << 2,
INSTANT_INVITES: 1 << 3,
SEND_MESSAGE: 1 << 4,
REACTIONS: 1 << 5,
MEMBER_LIST_UPDATES: 1 << 6,
} as const;
export const GuildOperationsDescriptions: Record<keyof typeof GuildOperations, string> = {
PUSH_NOTIFICATIONS: 'Allow push notifications for this guild',
EVERYONE_MENTIONS: 'Allow @everyone mentions in this guild',
TYPING_EVENTS: 'Enable typing indicator events',
INSTANT_INVITES: 'Allow creation of instant invites',
SEND_MESSAGE: 'Allow sending messages in the guild',
REACTIONS: 'Allow adding reactions to messages',
MEMBER_LIST_UPDATES: 'Enable member list update events',
};
export const GuildMemberProfileFlags = {
AVATAR_UNSET: 1 << 0,
BANNER_UNSET: 1 << 1,
} as const;
export const GuildMemberProfileFlagsDescriptions: Record<keyof typeof GuildMemberProfileFlags, string> = {
AVATAR_UNSET: 'Guild member avatar is unset',
BANNER_UNSET: 'Guild member banner is unset',
};
export const GuildExplicitContentFilterTypes = {
DISABLED: 0,
MEMBERS_WITHOUT_ROLES: 1,
ALL_MEMBERS: 2,
} as const;
export const GuildNSFWLevel = {
DEFAULT: 0,
EXPLICIT: 1,
SAFE: 2,
AGE_RESTRICTED: 3,
} as const;
export const GuildNSFWLevelDescriptions: Record<keyof typeof GuildNSFWLevel, string> = {
DEFAULT: 'Default NSFW level',
EXPLICIT: 'Guild contains explicit content',
SAFE: 'Guild is safe for all ages',
AGE_RESTRICTED: 'Guild is age-restricted',
};
export const GuildFeatures = {
ANIMATED_ICON: 'ANIMATED_ICON',
ANIMATED_BANNER: 'ANIMATED_BANNER',
BANNER: 'BANNER',
DETACHED_BANNER: 'DETACHED_BANNER',
INVITE_SPLASH: 'INVITE_SPLASH',
INVITES_DISABLED: 'INVITES_DISABLED',
TEXT_CHANNEL_FLEXIBLE_NAMES: 'TEXT_CHANNEL_FLEXIBLE_NAMES',
MORE_EMOJI: 'MORE_EMOJI',
MORE_STICKERS: 'MORE_STICKERS',
UNLIMITED_EMOJI: 'UNLIMITED_EMOJI',
UNLIMITED_STICKERS: 'UNLIMITED_STICKERS',
EXPRESSION_PURGE_ALLOWED: 'EXPRESSION_PURGE_ALLOWED',
VANITY_URL: 'VANITY_URL',
DISCOVERABLE: 'DISCOVERABLE',
PARTNERED: 'PARTNERED',
VERIFIED: 'VERIFIED',
VIP_VOICE: 'VIP_VOICE',
UNAVAILABLE_FOR_EVERYONE: 'UNAVAILABLE_FOR_EVERYONE',
UNAVAILABLE_FOR_EVERYONE_BUT_STAFF: 'UNAVAILABLE_FOR_EVERYONE_BUT_STAFF',
VISIONARY: 'VISIONARY',
OPERATOR: 'OPERATOR',
LARGE_GUILD_OVERRIDE: 'LARGE_GUILD_OVERRIDE',
VERY_LARGE_GUILD: 'VERY_LARGE_GUILD',
MANAGED_MESSAGE_SCHEDULING: ManagedTraits.MESSAGE_SCHEDULING,
MANAGED_EXPRESSION_PACKS: ManagedTraits.EXPRESSION_PACKS,
} as const;
export type GuildFeature = ValueOf<typeof GuildFeatures>;
export const JoinSourceTypes = {
CREATOR: 0,
INSTANT_INVITE: 1,
VANITY_URL: 2,
BOT_INVITE: 3,
ADMIN_FORCE_ADD: 4,
} as const;
export const DEFAULT_RULE_COUNT = 0;
export const MAX_RULE_COUNT = 100;
export const MemberSortType = {
JOIN_DATE_DESC: 1,
JOIN_DATE_ASC: 2,
} as const;
export type MemberSortTypeValue = ValueOf<typeof MemberSortType>;
export const GUILD_MEMBERS_REINDEX_AFTER_TIMESTAMP = 1769813072;

View File

@@ -0,0 +1,72 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const Headers = {
CONTENT_TYPE: 'Content-Type',
CONTENT_LENGTH: 'Content-Length',
CONTENT_DISPOSITION: 'Content-Disposition',
AUTHORIZATION: 'Authorization',
ACCEPT: 'Accept',
CACHE_CONTROL: 'Cache-Control',
USER_AGENT: 'User-Agent',
X_FORWARDED_FOR: 'X-Forwarded-For',
X_FORWARDED_PROTO: 'X-Forwarded-Proto',
X_FORWARDED_HOST: 'X-Forwarded-Host',
X_REQUEST_ID: 'X-Request-ID',
X_RATELIMIT_LIMIT: 'X-RateLimit-Limit',
X_RATELIMIT_REMAINING: 'X-RateLimit-Remaining',
X_RATELIMIT_RESET: 'X-RateLimit-Reset',
X_CONTENT_TYPE_OPTIONS: 'X-Content-Type-Options',
X_FRAME_OPTIONS: 'X-Frame-Options',
X_XSS_PROTECTION: 'X-XSS-Protection',
X_FLUXER_SUDO_MODE_JWT: 'X-Fluxer-Sudo-Mode-JWT',
X_AUDIT_LOG_REASON: 'X-Audit-Log-Reason',
X_INTERNAL_API_KEY: 'X-Internal-API-Key',
X_AMZ_REQUEST_ID: 'x-amz-request-id',
X_AMZ_ID_2: 'x-amz-id-2',
X_ACCEL_BUFFERING: 'X-Accel-Buffering',
} as const;
export type HeaderName = ValueOf<typeof Headers>;
export const HeaderValues = {
NOSNIFF: 'nosniff',
ATTACHMENT: 'attachment',
DENY: 'DENY',
SAMEORIGIN: 'SAMEORIGIN',
NO: 'no',
NO_CACHE: 'no-cache',
NO_STORE: 'no-store',
PUBLIC: 'public',
PRIVATE: 'private',
} as const;
export type HeaderValue = ValueOf<typeof HeaderValues>;

View File

@@ -0,0 +1,115 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const HttpStatus = {
OK: 200,
CREATED: 201,
ACCEPTED: 202,
NO_CONTENT: 204,
PARTIAL_CONTENT: 206,
MOVED_PERMANENTLY: 301,
FOUND: 302,
SEE_OTHER: 303,
NOT_MODIFIED: 304,
TEMPORARY_REDIRECT: 307,
PERMANENT_REDIRECT: 308,
BAD_REQUEST: 400,
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
METHOD_NOT_ALLOWED: 405,
NOT_ACCEPTABLE: 406,
REQUEST_TIMEOUT: 408,
CONFLICT: 409,
GONE: 410,
LENGTH_REQUIRED: 411,
PRECONDITION_FAILED: 412,
PAYLOAD_TOO_LARGE: 413,
URI_TOO_LONG: 414,
UNSUPPORTED_MEDIA_TYPE: 415,
RANGE_NOT_SATISFIABLE: 416,
TOO_MANY_REQUESTS: 429,
INTERNAL_SERVER_ERROR: 500,
NOT_IMPLEMENTED: 501,
BAD_GATEWAY: 502,
SERVICE_UNAVAILABLE: 503,
GATEWAY_TIMEOUT: 504,
} as const;
export type HttpStatusCode = ValueOf<typeof HttpStatus>;
export const MimeType = {
JSON: 'application/json',
XML: 'application/xml',
FORM_URLENCODED: 'application/x-www-form-urlencoded',
OCTET_STREAM: 'application/octet-stream',
PDF: 'application/pdf',
PLAIN: 'text/plain',
HTML: 'text/html',
CSS: 'text/css',
JAVASCRIPT: 'text/javascript',
CSV: 'text/csv',
PNG: 'image/png',
JPEG: 'image/jpeg',
GIF: 'image/gif',
WEBP: 'image/webp',
SVG: 'image/svg+xml',
ICO: 'image/x-icon',
MP3: 'audio/mpeg',
WAV: 'audio/wav',
OGG_AUDIO: 'audio/ogg',
MP4: 'video/mp4',
WEBM: 'video/webm',
OGG_VIDEO: 'video/ogg',
MULTIPART_FORM_DATA: 'multipart/form-data',
} as const;
export type MimeTypeValue = ValueOf<typeof MimeType>;
export const HttpMethod = {
GET: 'GET',
POST: 'POST',
PUT: 'PUT',
PATCH: 'PATCH',
DELETE: 'DELETE',
HEAD: 'HEAD',
OPTIONS: 'OPTIONS',
} as const;
export type HttpMethodValue = ValueOf<typeof HttpMethod>;
export const REDIRECT_STATUS_CODES = [
HttpStatus.MOVED_PERMANENTLY,
HttpStatus.FOUND,
HttpStatus.SEE_OTHER,
HttpStatus.TEMPORARY_REDIRECT,
HttpStatus.PERMANENT_REDIRECT,
] as const;
export type RedirectStatusCode = (typeof REDIRECT_STATUS_CODES)[number];

View File

@@ -0,0 +1,27 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const JumpTypes = {
ANIMATED: 'ANIMATED',
INSTANT: 'INSTANT',
NONE: 'NONE',
} as const;
export type JumpType = ValueOf<typeof JumpTypes>;

View File

@@ -0,0 +1,69 @@
/*
* 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 type {LimitKey} from '@fluxer/constants/src/LimitConfigMetadata';
import {MAX_GUILD_MEMBERS_VERY_LARGE_GUILD} from '@fluxer/constants/src/LimitConstants';
export const LIMIT_KEY_BOUNDS: Record<LimitKey, {min: number; max: number}> = {
avatar_max_size: {min: 1024, max: 10_485_760},
emoji_max_size: {min: 1024, max: 393_216},
feature_animated_avatar: {min: 0, max: 1},
feature_animated_banner: {min: 0, max: 1},
feature_custom_discriminator: {min: 0, max: 1},
feature_custom_notification_sounds: {min: 0, max: 1},
feature_early_access: {min: 0, max: 1},
feature_global_expressions: {min: 0, max: 1},
feature_higher_video_quality: {min: 0, max: 1},
feature_per_guild_profiles: {min: 0, max: 1},
feature_voice_entrance_sounds: {min: 0, max: 1},
max_attachment_file_size: {min: 0, max: 500 * 1024 * 1024},
max_attachments_per_message: {min: 1, max: 10},
max_bio_length: {min: 1, max: 320},
max_bookmarks: {min: 0, max: 300},
max_channels_per_category: {min: 1, max: 50},
max_created_packs: {min: 0, max: 50},
max_custom_backgrounds: {min: 0, max: 15},
max_embeds_per_message: {min: 0, max: 10},
max_favorite_meme_tags: {min: 1, max: 10},
max_favorite_memes: {min: 0, max: 500},
max_group_dm_recipients: {min: 2, max: 25},
max_group_dms_per_user: {min: 0, max: 150},
max_guild_channels: {min: 1, max: 500},
max_guild_emojis_animated_more: {min: 0, max: 250},
max_guild_emojis_animated: {min: 0, max: 50},
max_guild_emojis_static_more: {min: 0, max: 250},
max_guild_emojis_static: {min: 0, max: 50},
max_guild_invites: {min: 0, max: 1000},
max_guild_members: {min: 1, max: MAX_GUILD_MEMBERS_VERY_LARGE_GUILD},
max_guild_roles: {min: 1, max: 250},
max_guild_stickers_more: {min: 0, max: 250},
max_guild_stickers: {min: 0, max: 50},
max_guilds: {min: 1, max: 200},
max_installed_packs: {min: 0, max: 50},
max_message_length: {min: 1, max: 4000},
max_pack_expressions: {min: 1, max: 200},
max_private_channels_per_user: {min: 1, max: 250},
max_reactions_per_message: {min: 0, max: 30},
max_relationships: {min: 0, max: 1000},
max_users_per_message_reaction: {min: 1, max: 5000},
max_voice_message_duration: {min: 1, max: 1200},
max_webhooks_per_channel: {min: 0, max: 15},
max_webhooks_per_guild: {min: 0, max: 1000},
sticker_max_size: {min: 1024, max: 524_288},
};

View File

@@ -0,0 +1,547 @@
/*
* 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/>.
*/
export const LIMIT_KEYS = [
'avatar_max_size',
'emoji_max_size',
'feature_animated_avatar',
'feature_animated_banner',
'feature_custom_discriminator',
'feature_custom_notification_sounds',
'feature_early_access',
'feature_global_expressions',
'feature_higher_video_quality',
'feature_per_guild_profiles',
'feature_voice_entrance_sounds',
'max_attachments_per_message',
'max_bio_length',
'max_bookmarks',
'max_channels_per_category',
'max_created_packs',
'max_custom_backgrounds',
'max_embeds_per_message',
'max_favorite_meme_tags',
'max_favorite_memes',
'max_group_dm_recipients',
'max_group_dms_per_user',
'max_guild_channels',
'max_guild_emojis_animated_more',
'max_guild_emojis_animated',
'max_guild_emojis_static_more',
'max_guild_emojis_static',
'max_guild_invites',
'max_guild_members',
'max_guild_roles',
'max_guild_stickers_more',
'max_guild_stickers',
'max_guilds',
'max_installed_packs',
'max_attachment_file_size',
'max_message_length',
'max_pack_expressions',
'max_private_channels_per_user',
'max_reactions_per_message',
'max_relationships',
'max_users_per_message_reaction',
'max_voice_message_duration',
'max_webhooks_per_channel',
'max_webhooks_per_guild',
'sticker_max_size',
] as const;
export type LimitKey = (typeof LIMIT_KEYS)[number];
export type LimitScope = 'user' | 'guild' | 'both';
export const LIMIT_KEY_SCOPES: Record<LimitKey, LimitScope> = {
avatar_max_size: 'user',
emoji_max_size: 'guild',
feature_animated_avatar: 'user',
feature_animated_banner: 'user',
feature_custom_discriminator: 'user',
feature_custom_notification_sounds: 'user',
feature_early_access: 'user',
feature_global_expressions: 'user',
feature_higher_video_quality: 'user',
feature_per_guild_profiles: 'user',
feature_voice_entrance_sounds: 'user',
max_attachments_per_message: 'both',
max_bio_length: 'user',
max_bookmarks: 'user',
max_channels_per_category: 'guild',
max_created_packs: 'user',
max_custom_backgrounds: 'user',
max_embeds_per_message: 'both',
max_favorite_meme_tags: 'user',
max_favorite_memes: 'user',
max_group_dm_recipients: 'user',
max_group_dms_per_user: 'user',
max_guild_channels: 'guild',
max_guild_emojis_animated_more: 'guild',
max_guild_emojis_animated: 'guild',
max_guild_emojis_static_more: 'guild',
max_guild_emojis_static: 'guild',
max_guild_invites: 'guild',
max_guild_members: 'guild',
max_guild_roles: 'guild',
max_guild_stickers_more: 'guild',
max_guild_stickers: 'guild',
max_guilds: 'user',
max_installed_packs: 'user',
max_attachment_file_size: 'both',
max_message_length: 'both',
max_pack_expressions: 'guild',
max_private_channels_per_user: 'user',
max_reactions_per_message: 'guild',
max_relationships: 'user',
max_users_per_message_reaction: 'guild',
max_voice_message_duration: 'both',
max_webhooks_per_channel: 'guild',
max_webhooks_per_guild: 'guild',
sticker_max_size: 'guild',
};
export type LimitCategory = 'messages' | 'guilds' | 'channels' | 'expressions' | 'files' | 'social' | 'features';
export interface LimitKeyMetadata {
key: LimitKey;
label: string;
description: string;
category: LimitCategory;
scope: LimitScope;
isToggle: boolean;
unit?: 'bytes' | 'count';
min?: number;
max?: number;
}
export const LIMIT_CATEGORY_LABELS: Record<LimitCategory, string> = {
messages: 'Messages',
guilds: 'Guilds',
channels: 'Channels',
expressions: 'Expressions & Stickers',
files: 'Files & Attachments',
social: 'Social & Private',
features: 'Premium Features',
};
export const LIMIT_KEY_METADATA: Record<LimitKey, LimitKeyMetadata> = {
max_message_length: {
key: 'max_message_length',
label: 'Max Message Length',
description: 'Maximum number of characters per message',
category: 'messages',
scope: 'both',
isToggle: false,
unit: 'count',
},
max_attachments_per_message: {
key: 'max_attachments_per_message',
label: 'Max Attachments per Message',
description: 'Maximum number of file attachments per message',
category: 'messages',
scope: 'both',
isToggle: false,
unit: 'count',
},
max_embeds_per_message: {
key: 'max_embeds_per_message',
label: 'Max Embeds per Message',
description: 'Maximum number of embeds per message',
category: 'messages',
scope: 'both',
isToggle: false,
unit: 'count',
},
max_reactions_per_message: {
key: 'max_reactions_per_message',
label: 'Max Reactions per Message',
description: 'Maximum distinct reactions per message',
category: 'messages',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_users_per_message_reaction: {
key: 'max_users_per_message_reaction',
label: 'Max Users per Reaction',
description: 'Maximum users who can use the same reaction on a message',
category: 'messages',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_voice_message_duration: {
key: 'max_voice_message_duration',
label: 'Max Voice Message Duration',
description: 'Maximum duration in seconds for voice message recordings',
category: 'messages',
scope: 'both',
isToggle: false,
unit: 'count',
},
max_guilds: {
key: 'max_guilds',
label: 'Max Guilds',
description: 'Maximum number of guilds a user can join',
category: 'guilds',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_guild_members: {
key: 'max_guild_members',
label: 'Max Guild Members',
description: 'Maximum members per guild',
category: 'guilds',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_roles: {
key: 'max_guild_roles',
label: 'Max Guild Roles',
description: 'Maximum roles per guild',
category: 'guilds',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_invites: {
key: 'max_guild_invites',
label: 'Max Guild Invites',
description: 'Maximum active invites per guild',
category: 'guilds',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_channels: {
key: 'max_guild_channels',
label: 'Max Guild Channels',
description: 'Maximum channels per guild',
category: 'channels',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_channels_per_category: {
key: 'max_channels_per_category',
label: 'Max Channels per Category',
description: 'Maximum channels per category',
category: 'channels',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_webhooks_per_channel: {
key: 'max_webhooks_per_channel',
label: 'Max Webhooks per Channel',
description: 'Maximum webhooks per channel',
category: 'channels',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_webhooks_per_guild: {
key: 'max_webhooks_per_guild',
label: 'Max Webhooks per Guild',
description: 'Maximum webhooks per guild',
category: 'channels',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_emojis_static: {
key: 'max_guild_emojis_static',
label: 'Max Static Emojis',
description: 'Maximum static emojis per guild',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_emojis_animated: {
key: 'max_guild_emojis_animated',
label: 'Max Animated Emojis',
description: 'Maximum animated emojis per guild',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_emojis_static_more: {
key: 'max_guild_emojis_static_more',
label: 'Max Static Emojis (More Emoji)',
description: 'Maximum static emojis with MORE_EMOJI feature',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_emojis_animated_more: {
key: 'max_guild_emojis_animated_more',
label: 'Max Animated Emojis (More Emoji)',
description: 'Maximum animated emojis with MORE_EMOJI feature',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_stickers: {
key: 'max_guild_stickers',
label: 'Max Stickers',
description: 'Maximum stickers per guild',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_guild_stickers_more: {
key: 'max_guild_stickers_more',
label: 'Max Stickers (More Stickers)',
description: 'Maximum stickers with MORE_STICKERS feature',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'count',
},
emoji_max_size: {
key: 'emoji_max_size',
label: 'Emoji Max Size',
description: 'Maximum file size for emoji uploads',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'bytes',
},
sticker_max_size: {
key: 'sticker_max_size',
label: 'Sticker Max Size',
description: 'Maximum file size for sticker uploads',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'bytes',
},
max_pack_expressions: {
key: 'max_pack_expressions',
label: 'Max Pack Expressions',
description: 'Maximum expressions per pack',
category: 'expressions',
scope: 'guild',
isToggle: false,
unit: 'count',
},
max_created_packs: {
key: 'max_created_packs',
label: 'Max Created Packs',
description: 'Maximum expression packs a user can create',
category: 'expressions',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_installed_packs: {
key: 'max_installed_packs',
label: 'Max Installed Packs',
description: 'Maximum expression packs a user can install',
category: 'expressions',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_attachment_file_size: {
key: 'max_attachment_file_size',
label: 'Max Attachment File Size',
description: 'Maximum size of each attachment file',
category: 'files',
scope: 'both',
isToggle: false,
unit: 'bytes',
},
avatar_max_size: {
key: 'avatar_max_size',
label: 'Avatar Max Size',
description: 'Maximum file size for avatar uploads',
category: 'files',
scope: 'user',
isToggle: false,
unit: 'bytes',
},
max_custom_backgrounds: {
key: 'max_custom_backgrounds',
label: 'Max Custom Backgrounds',
description: 'Maximum custom profile backgrounds',
category: 'files',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_relationships: {
key: 'max_relationships',
label: 'Max Relationships',
description: 'Maximum friends/blocked users',
category: 'social',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_private_channels_per_user: {
key: 'max_private_channels_per_user',
label: 'Max Private Channels',
description: 'Maximum DM channels per user',
category: 'social',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_group_dms_per_user: {
key: 'max_group_dms_per_user',
label: 'Max Group DMs',
description: 'Maximum group DMs a user can own',
category: 'social',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_group_dm_recipients: {
key: 'max_group_dm_recipients',
label: 'Max Group DM Recipients',
description: 'Maximum users per group DM',
category: 'social',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_bio_length: {
key: 'max_bio_length',
label: 'Max Bio Length',
description: 'Maximum characters in user bio',
category: 'social',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_bookmarks: {
key: 'max_bookmarks',
label: 'Max Bookmarks',
description: 'Maximum bookmarked messages',
category: 'social',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_favorite_memes: {
key: 'max_favorite_memes',
label: 'Max Favorite Memes',
description: 'Maximum favorited memes',
category: 'social',
scope: 'user',
isToggle: false,
unit: 'count',
},
max_favorite_meme_tags: {
key: 'max_favorite_meme_tags',
label: 'Max Favorite Meme Tags',
description: 'Maximum meme tags to track',
category: 'social',
scope: 'user',
isToggle: false,
unit: 'count',
},
feature_animated_avatar: {
key: 'feature_animated_avatar',
label: 'Animated Avatar',
description: 'Allow animated avatar uploads',
category: 'features',
scope: 'user',
isToggle: true,
},
feature_animated_banner: {
key: 'feature_animated_banner',
label: 'Animated Banner',
description: 'Allow animated banner uploads',
category: 'features',
scope: 'user',
isToggle: true,
},
feature_custom_discriminator: {
key: 'feature_custom_discriminator',
label: 'Custom Discriminator',
description: 'Allow custom discriminator selection',
category: 'features',
scope: 'user',
isToggle: true,
},
feature_custom_notification_sounds: {
key: 'feature_custom_notification_sounds',
label: 'Custom Notification Sounds',
description: 'Allow custom notification sounds',
category: 'features',
scope: 'user',
isToggle: true,
},
feature_early_access: {
key: 'feature_early_access',
label: 'Early Access',
description: 'Access to beta features',
category: 'features',
scope: 'user',
isToggle: true,
},
feature_global_expressions: {
key: 'feature_global_expressions',
label: 'Global Expressions',
description: 'Use expressions across all guilds',
category: 'features',
scope: 'user',
isToggle: true,
},
feature_higher_video_quality: {
key: 'feature_higher_video_quality',
label: 'Higher Video Quality',
description: 'Access to higher video streaming quality',
category: 'features',
scope: 'user',
isToggle: true,
},
feature_per_guild_profiles: {
key: 'feature_per_guild_profiles',
label: 'Per-Guild Profiles',
description: 'Different profile per guild',
category: 'features',
scope: 'user',
isToggle: true,
},
feature_voice_entrance_sounds: {
key: 'feature_voice_entrance_sounds',
label: 'Voice Entrance Sounds',
description: 'Play sound when joining voice',
category: 'features',
scope: 'user',
isToggle: true,
},
};

View File

@@ -0,0 +1,109 @@
/*
* 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/>.
*/
export const MAX_GUILDS_PREMIUM = 200;
export const MAX_GUILDS_NON_PREMIUM = 100;
export const MAX_GUILD_CHANNELS = 500;
export const MAX_CHANNELS_PER_CATEGORY = 50;
export const VOICE_CHANNEL_BITRATE_MIN = 8000;
export const VOICE_CHANNEL_BITRATE_MAX = 320000;
export const VOICE_CHANNEL_USER_LIMIT_MIN = 0;
export const VOICE_CHANNEL_USER_LIMIT_MAX = 99;
export const VOICE_CHANNEL_CAMERA_USER_LIMIT = 25;
export const CHANNEL_RATE_LIMIT_PER_USER_MIN = 0;
export const CHANNEL_RATE_LIMIT_PER_USER_MAX = 21600;
export const CHANNEL_TOPIC_MIN_LENGTH = 1;
export const CHANNEL_TOPIC_MAX_LENGTH = 1024;
export const RTC_REGION_ID_MIN_LENGTH = 1;
export const RTC_REGION_ID_MAX_LENGTH = 64;
export const MAX_CHANNEL_PERMISSION_OVERWRITES = 500;
export const MAX_DM_RECIPIENTS = 10;
export const MAX_GUILD_EMOJIS_ANIMATED = 50;
export const MAX_GUILD_EMOJIS_STATIC = 50;
export const MAX_GUILD_EMOJIS_ANIMATED_MORE_EMOJI = 250;
export const MAX_GUILD_EMOJIS_STATIC_MORE_EMOJI = 250;
export const MAX_GUILD_STICKERS = 50;
export const MAX_GUILD_STICKERS_MORE_STICKERS = 250;
export const MAX_GUILD_EXPRESSION_SLOTS_UNLIMITED = 999_999;
export const MAX_GUILD_INVITES = 1000;
export const MAX_GUILD_MEMBERS = 1_000_000;
export const MAX_GUILD_MEMBERS_VERY_LARGE_GUILD = 10_000_000;
export const MAX_INVITE_USES = 100;
export const MAX_INVITE_AGE_SECONDS = 604800;
export const MAX_GUILD_ROLES = 250;
export const MAX_WEBHOOKS_PER_CHANNEL = 15;
export const MAX_WEBHOOKS_PER_GUILD = 1000;
export const MAX_MESSAGE_LENGTH_PREMIUM = 4000;
export const MAX_MESSAGE_LENGTH_NON_PREMIUM = 2000;
export const MAX_ATTACHMENTS_PER_MESSAGE = 10;
export const MAX_EMBEDS_PER_MESSAGE = 10;
export const MAX_REACTIONS_PER_MESSAGE = 30;
export const MAX_USERS_PER_MESSAGE_REACTION = 5000;
export const MAX_READ_STATES_BULK_ACK = 100;
export const MIN_READ_STATES_BULK_ACK = 1;
export const MAX_ATTACHMENT_ALT_TEXT_LENGTH = 4096;
export const MAX_BIO_LENGTH = 320;
export const AVATAR_MAX_SIZE = 10 * 1024 * 1024;
export const AVATAR_EXTENSIONS = new Set(['jpeg', 'png', 'apng', 'webp', 'gif', 'avif']);
export const MAX_RELATIONSHIPS = 1000;
export const MAX_GROUP_DM_RECIPIENTS = 25;
export const MAX_PRIVATE_CHANNELS_PER_USER = 250;
export const MAX_PRIVATE_CHANNELS_PER_USER_ALTERNATE = 200;
export const MAX_GROUP_DMS_PER_USER = 150;
export const MAX_BOOKMARKS_PREMIUM = 300;
export const MAX_BOOKMARKS_NON_PREMIUM = 50;
export const MAX_FAVORITE_MEMES_PREMIUM = 500;
export const MAX_FAVORITE_MEMES_NON_PREMIUM = 50;
export const MAX_FAVORITE_MEME_TAGS = 10;
export const MAX_PACK_EXPRESSIONS = 200;
export const MAX_CREATED_PACKS_NON_PREMIUM = 0;
export const MAX_CREATED_PACKS_PREMIUM = 50;
export const MAX_INSTALLED_PACKS_NON_PREMIUM = 0;
export const MAX_INSTALLED_PACKS_PREMIUM = 50;
export const MAX_VOICE_MESSAGE_DURATION = 1200;
export const EMOJI_MAX_SIZE = 384 * 1024;
export const EMOJI_EXTENSIONS = new Set(['jpeg', 'png', 'apng', 'webp', 'gif', 'avif']);
export const STICKER_MAX_SIZE = 512 * 1024;
export const STICKER_EXTENSIONS = new Set(['png', 'gif', 'apng', 'webp', 'avif']);
export const ATTACHMENT_MAX_SIZE_PREMIUM = 500 * 1024 * 1024;
export const ATTACHMENT_MAX_SIZE_NON_PREMIUM = 25 * 1024 * 1024;
export const MAX_MESSAGES_PER_CHANNEL = 30;
export const MAX_LOADED_MESSAGES = MAX_MESSAGES_PER_CHANNEL * 4;
export const TRUNCATED_MESSAGE_VIEW_SIZE = MAX_LOADED_MESSAGES * 0.5;
export const MAX_MESSAGE_CACHE_SIZE = MAX_MESSAGES_PER_CHANNEL * 5;
export const NEW_MESSAGES_BAR_BUFFER = 32;
export const VALID_TEMP_BAN_DURATIONS: ReadonlySet<number> = new Set([
1 * 3600,
12 * 3600,
24 * 3600,
72 * 3600,
120 * 3600,
168 * 3600,
336 * 3600,
720 * 3600,
]);

View File

@@ -0,0 +1,61 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const Locales = {
AR: 'ar',
BG: 'bg',
CS: 'cs',
DA: 'da',
DE: 'de',
EL: 'el',
EN_GB: 'en-GB',
EN_US: 'en-US',
ES_ES: 'es-ES',
ES_419: 'es-419',
FI: 'fi',
FR: 'fr',
HE: 'he',
HI: 'hi',
HR: 'hr',
HU: 'hu',
ID: 'id',
IT: 'it',
JA: 'ja',
KO: 'ko',
LT: 'lt',
NL: 'nl',
NO: 'no',
PL: 'pl',
PT_BR: 'pt-BR',
RO: 'ro',
RU: 'ru',
SV_SE: 'sv-SE',
TH: 'th',
TR: 'tr',
UK: 'uk',
VI: 'vi',
ZH_CN: 'zh-CN',
ZH_TW: 'zh-TW',
} as const;
export type LocaleCode = ValueOf<typeof Locales>;
export const AllLocales: ReadonlyArray<LocaleCode> = Object.values(Locales);

View File

@@ -0,0 +1,35 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const MANAGED_TRAIT_PREFIX = 'MT_';
export const ManagedTraits = {
MESSAGE_SCHEDULING: 'MT_MESSAGE_SCHEDULING',
EXPRESSION_PACKS: 'MT_EXPRESSION_PACKS',
} as const;
export type ManagedTrait = ValueOf<typeof ManagedTraits>;
export const ALL_MANAGED_TRAITS: Array<ManagedTrait> = Object.values(ManagedTraits);
export function isManagedTrait(value: string): value is ManagedTrait {
return value.startsWith(MANAGED_TRAIT_PREFIX);
}

View File

@@ -0,0 +1,32 @@
/*
* 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 type {MediaProxyImageSize} from '@fluxer/constants/src/MediaProxyImageSizes';
export const MEDIA_PROXY_AVATAR_SIZE_DEFAULT: MediaProxyImageSize = 160;
export const MEDIA_PROXY_AVATAR_SIZE_PROFILE: MediaProxyImageSize = 240;
export const MEDIA_PROXY_ICON_SIZE_DEFAULT: MediaProxyImageSize = 160;
export const MEDIA_PROXY_PROFILE_BANNER_SIZE_POPOUT: MediaProxyImageSize = 600;
export const MEDIA_PROXY_PROFILE_BANNER_SIZE_MODAL: MediaProxyImageSize = 1024;
export const MEDIA_PROXY_GUILD_BANNER_SIZE_DEFAULT: MediaProxyImageSize = 1024;
export const MEDIA_PROXY_GUILD_SPLASH_SIZE_DEFAULT: MediaProxyImageSize = 1024;
export const MEDIA_PROXY_GUILD_EMBED_SPLASH_SIZE_DEFAULT: MediaProxyImageSize = 1024;

View File

@@ -0,0 +1,64 @@
/*
* 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/>.
*/
export const MEDIA_PROXY_IMAGE_SIZE_QUERY_VALUES = [
'16',
'20',
'22',
'24',
'28',
'32',
'40',
'44',
'48',
'56',
'60',
'64',
'80',
'96',
'100',
'128',
'160',
'240',
'256',
'300',
'320',
'480',
'512',
'600',
'640',
'1024',
'1280',
'1536',
'2048',
'3072',
'4096',
] as const;
export const DEFAULT_MEDIA_PROXY_IMAGE_SIZE_QUERY_VALUE = '128' as const;
export type MediaProxyImageSizeQueryValue = (typeof MEDIA_PROXY_IMAGE_SIZE_QUERY_VALUES)[number];
type ParseNumericLiteral<T extends string> = T extends `${infer N extends number}` ? N : never;
export type MediaProxyImageSize = ParseNumericLiteral<MediaProxyImageSizeQueryValue>;
export const MEDIA_PROXY_IMAGE_SIZE_VALUES: ReadonlyArray<MediaProxyImageSize> =
MEDIA_PROXY_IMAGE_SIZE_QUERY_VALUES.map((value) => Number(value) as MediaProxyImageSize);
export const DEFAULT_MEDIA_PROXY_IMAGE_SIZE = 128 as MediaProxyImageSize;

View File

@@ -0,0 +1,26 @@
/*
* 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/>.
*/
export const MessageNotifications = {
NULL: -1,
ALL_MESSAGES: 0,
ONLY_MENTIONS: 1,
NO_MESSAGES: 2,
INHERIT: 3,
} as const;

View File

@@ -0,0 +1,28 @@
/*
* 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/>.
*/
export type OAuth2Scope = 'identify' | 'email' | 'guilds' | 'connections' | 'bot' | 'admin';
export const OAuth2Scopes: ReadonlyArray<OAuth2Scope> = [
'identify',
'email',
'guilds',
'connections',
'bot',
'admin',
] as const;

View File

@@ -0,0 +1,22 @@
/*
* 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/>.
*/
export const DEFAULT_PAGE_SIZE = 25;
export const MAX_PAGE_SIZE = 100;
export const MIN_PAGE_SIZE = 1;

View File

@@ -0,0 +1,247 @@
/*
* 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 type {LimitKey} from '@fluxer/constants/src/LimitConfigMetadata';
export type PerkStatus = 'available' | 'coming_soon' | 'beta';
export type PerkType = 'boolean' | 'numeric' | 'text';
interface BasePerk {
id: string;
type: PerkType;
status: PerkStatus;
i18nKey: string;
}
export interface BooleanPerk extends BasePerk {
type: 'boolean';
freeValue: boolean;
plutoniumValue: boolean;
}
export interface NumericPerk extends BasePerk {
type: 'numeric';
freeValue: number;
plutoniumValue: number;
limitKey?: LimitKey;
unit?: 'count' | 'bytes' | 'characters';
}
export interface TextPerk extends BasePerk {
type: 'text';
freeValueI18nKey: string;
plutoniumValueI18nKey: string;
}
export type PlutoniumPerk = BooleanPerk | NumericPerk | TextPerk;
export function isBooleanPerk(perk: PlutoniumPerk): perk is BooleanPerk {
return perk.type === 'boolean';
}
export function isNumericPerk(perk: PlutoniumPerk): perk is NumericPerk {
return perk.type === 'numeric';
}
export function isTextPerk(perk: PlutoniumPerk): perk is TextPerk {
return perk.type === 'text';
}
export const PLUTONIUM_PERKS: ReadonlyArray<PlutoniumPerk> = [
{
id: 'custom_discriminator',
type: 'boolean',
status: 'available',
i18nKey: 'custom_4_digit_username_tag',
freeValue: false,
plutoniumValue: true,
},
{
id: 'per_guild_profiles',
type: 'boolean',
status: 'available',
i18nKey: 'per_community_profiles',
freeValue: false,
plutoniumValue: true,
},
{
id: 'message_scheduling',
type: 'boolean',
status: 'coming_soon',
i18nKey: 'message_scheduling',
freeValue: false,
plutoniumValue: true,
},
{
id: 'profile_badge',
type: 'boolean',
status: 'available',
i18nKey: 'profile_badge',
freeValue: false,
plutoniumValue: true,
},
{
id: 'custom_video_backgrounds',
type: 'numeric',
status: 'beta',
i18nKey: 'custom_video_backgrounds',
freeValue: 1,
plutoniumValue: 15,
limitKey: 'max_custom_backgrounds',
unit: 'count',
},
{
id: 'entrance_sounds',
type: 'boolean',
status: 'beta',
i18nKey: 'entrance_sounds',
freeValue: false,
plutoniumValue: true,
},
{
id: 'notification_sounds',
type: 'boolean',
status: 'beta',
i18nKey: 'notification_sounds',
freeValue: false,
plutoniumValue: true,
},
{
id: 'max_guilds',
type: 'numeric',
status: 'available',
i18nKey: 'communities',
freeValue: 100,
plutoniumValue: 200,
limitKey: 'max_guilds',
unit: 'count',
},
{
id: 'max_message_length',
type: 'numeric',
status: 'available',
i18nKey: 'message_character_limit',
freeValue: 2000,
plutoniumValue: 4000,
limitKey: 'max_message_length',
unit: 'characters',
},
{
id: 'max_bookmarks',
type: 'numeric',
status: 'available',
i18nKey: 'bookmarked_messages',
freeValue: 50,
plutoniumValue: 300,
limitKey: 'max_bookmarks',
unit: 'count',
},
{
id: 'max_attachment_file_size',
type: 'numeric',
status: 'available',
i18nKey: 'file_upload_size',
freeValue: 25 * 1024 * 1024,
plutoniumValue: 500 * 1024 * 1024,
limitKey: 'max_attachment_file_size',
unit: 'bytes',
},
{
id: 'emoji_sticker_packs',
type: 'boolean',
status: 'coming_soon',
i18nKey: 'emoji_sticker_packs',
freeValue: false,
plutoniumValue: true,
},
{
id: 'max_favorite_memes',
type: 'numeric',
status: 'beta',
i18nKey: 'saved_media',
freeValue: 50,
plutoniumValue: 500,
limitKey: 'max_favorite_memes',
unit: 'count',
},
{
id: 'use_animated_emojis',
type: 'boolean',
status: 'available',
i18nKey: 'use_animated_emojis',
freeValue: true,
plutoniumValue: true,
},
{
id: 'global_expressions',
type: 'boolean',
status: 'available',
i18nKey: 'global_emoji_sticker_access',
freeValue: false,
plutoniumValue: true,
},
{
id: 'video_quality',
type: 'text',
status: 'available',
i18nKey: 'video_quality',
freeValueI18nKey: 'video_quality_free',
plutoniumValueI18nKey: 'video_quality_premium',
},
{
id: 'animated_profile',
type: 'boolean',
status: 'available',
i18nKey: 'animated_avatars_and_banners',
freeValue: false,
plutoniumValue: true,
},
{
id: 'early_access',
type: 'boolean',
status: 'available',
i18nKey: 'early_access',
freeValue: false,
plutoniumValue: true,
},
{
id: 'custom_themes',
type: 'boolean',
status: 'available',
i18nKey: 'custom_themes',
freeValue: true,
plutoniumValue: true,
},
] as const;
export function getPerksByStatus(status: PerkStatus): ReadonlyArray<PlutoniumPerk> {
return PLUTONIUM_PERKS.filter((perk) => perk.status === status);
}
export function getAvailablePerks(): ReadonlyArray<PlutoniumPerk> {
return getPerksByStatus('available');
}
export function getBetaPerks(): ReadonlyArray<PlutoniumPerk> {
return getPerksByStatus('beta');
}
export function getComingSoonPerks(): ReadonlyArray<PlutoniumPerk> {
return getPerksByStatus('coming_soon');
}

View File

@@ -0,0 +1,74 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const PressAssetIds = {
LOGO_WHITE: 'logo-white',
LOGO_BLACK: 'logo-black',
LOGO_COLOR: 'logo-color',
SYMBOL_WHITE: 'symbol-white',
SYMBOL_BLACK: 'symbol-black',
SYMBOL_COLOR: 'symbol-color',
} as const;
export type PressAssetId = ValueOf<typeof PressAssetIds>;
export interface PressAssetDefinition {
id: PressAssetId;
path: string;
filename: string;
}
export const PressAssets: Record<PressAssetId, PressAssetDefinition> = {
[PressAssetIds.LOGO_WHITE]: {
id: PressAssetIds.LOGO_WHITE,
path: '/marketing/branding/logo-white.svg',
filename: 'fluxer-logo-white.svg',
},
[PressAssetIds.LOGO_BLACK]: {
id: PressAssetIds.LOGO_BLACK,
path: '/marketing/branding/logo-black.svg',
filename: 'fluxer-logo-black.svg',
},
[PressAssetIds.LOGO_COLOR]: {
id: PressAssetIds.LOGO_COLOR,
path: '/marketing/branding/logo-color.svg',
filename: 'fluxer-logo-color.svg',
},
[PressAssetIds.SYMBOL_WHITE]: {
id: PressAssetIds.SYMBOL_WHITE,
path: '/marketing/branding/symbol-white.svg',
filename: 'fluxer-symbol-white.svg',
},
[PressAssetIds.SYMBOL_BLACK]: {
id: PressAssetIds.SYMBOL_BLACK,
path: '/marketing/branding/symbol-black.svg',
filename: 'fluxer-symbol-black.svg',
},
[PressAssetIds.SYMBOL_COLOR]: {
id: PressAssetIds.SYMBOL_COLOR,
path: '/marketing/branding/symbol-color.svg',
filename: 'fluxer-symbol-color.svg',
},
};
export function isPressAssetId(value: string): value is PressAssetId {
return Object.hasOwn(PressAssets, value);
}

View File

@@ -0,0 +1,35 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const QuickSwitcherResultTypes = {
HEADER: 'header',
USER: 'user',
GROUP_DM: 'group_dm',
TEXT_CHANNEL: 'text_channel',
VOICE_CHANNEL: 'voice_channel',
GUILD: 'guild',
VIRTUAL_GUILD: 'virtual_guild',
SETTINGS: 'settings',
QUICK_ACTION: 'quick_action',
LINK: 'link',
} as const;
export type QuickSwitcherResultType = ValueOf<typeof QuickSwitcherResultTypes>;

View File

@@ -0,0 +1,78 @@
/*
* 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/>.
*/
export const CATEGORY_HARASSMENT = 'harassment' as const;
export const CATEGORY_HATE_SPEECH = 'hate_speech' as const;
export const CATEGORY_SPAM = 'spam' as const;
export const CATEGORY_ILLEGAL_ACTIVITY = 'illegal_activity' as const;
export const CATEGORY_IMPERSONATION = 'impersonation' as const;
export const CATEGORY_CHILD_SAFETY = 'child_safety' as const;
export const CATEGORY_OTHER = 'other' as const;
export const CATEGORY_VIOLENT_CONTENT = 'violent_content' as const;
export const CATEGORY_NSFW_VIOLATION = 'nsfw_violation' as const;
export const CATEGORY_DOXXING = 'doxxing' as const;
export const CATEGORY_SELF_HARM = 'self_harm' as const;
export const CATEGORY_MALICIOUS_LINKS = 'malicious_links' as const;
export const CATEGORY_SPAM_ACCOUNT = 'spam_account' as const;
export const CATEGORY_UNDERAGE_USER = 'underage_user' as const;
export const CATEGORY_INAPPROPRIATE_PROFILE = 'inappropriate_profile' as const;
export const CATEGORY_RAID_COORDINATION = 'raid_coordination' as const;
export const CATEGORY_MALWARE_DISTRIBUTION = 'malware_distribution' as const;
export const CATEGORY_EXTREMIST_COMMUNITY = 'extremist_community' as const;
const REPORT_CATEGORY_GROUPS = {
message: [
CATEGORY_HARASSMENT,
CATEGORY_HATE_SPEECH,
CATEGORY_VIOLENT_CONTENT,
CATEGORY_SPAM,
CATEGORY_NSFW_VIOLATION,
CATEGORY_ILLEGAL_ACTIVITY,
CATEGORY_DOXXING,
CATEGORY_SELF_HARM,
CATEGORY_CHILD_SAFETY,
CATEGORY_MALICIOUS_LINKS,
CATEGORY_IMPERSONATION,
CATEGORY_OTHER,
] as const,
user: [
CATEGORY_HARASSMENT,
CATEGORY_HATE_SPEECH,
CATEGORY_SPAM_ACCOUNT,
CATEGORY_IMPERSONATION,
CATEGORY_UNDERAGE_USER,
CATEGORY_INAPPROPRIATE_PROFILE,
CATEGORY_OTHER,
] as const,
guild: [
CATEGORY_HARASSMENT,
CATEGORY_HATE_SPEECH,
CATEGORY_EXTREMIST_COMMUNITY,
CATEGORY_ILLEGAL_ACTIVITY,
CATEGORY_CHILD_SAFETY,
CATEGORY_RAID_COORDINATION,
CATEGORY_SPAM,
CATEGORY_MALWARE_DISTRIBUTION,
CATEGORY_OTHER,
] as const,
} as const;
export const MESSAGE_REPORT_CATEGORIES = REPORT_CATEGORY_GROUPS.message;
export const USER_REPORT_CATEGORIES = REPORT_CATEGORY_GROUPS.user;
export const GUILD_REPORT_CATEGORIES = REPORT_CATEGORY_GROUPS.guild;

View File

@@ -0,0 +1,46 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const ServiceName = {
API: 'fluxer-api',
KV: 'fluxer-kv',
S3: 'fluxer-s3',
QUEUE: 'fluxer-queue',
MEDIA_PROXY: 'fluxer-media-proxy',
APP_PROXY: 'fluxer-app-proxy',
ADMIN: 'fluxer-admin',
GATEWAY: 'fluxer-gateway',
} as const;
export type ServiceNameValue = ValueOf<typeof ServiceName>;
export const DefaultPort = {
API: 3000,
KV: 3001,
S3: 3002,
QUEUE: 3003,
MEDIA_PROXY: 3004,
APP_PROXY: 3005,
ADMIN: 3006,
GATEWAY: 4000,
} as const;
export type DefaultPortValue = ValueOf<typeof DefaultPort>;

View File

@@ -0,0 +1,27 @@
/*
* 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/>.
*/
export const SMS_VERIFICATION_CODE_LENGTH = 6;
export const SMS_VERIFICATION_TTL_SECONDS = 600;
export const SMS_VERIFICATION_CACHE_PREFIX = 'sms:verification:';
export const SMS_VERIFICATION_MESSAGE_TEMPLATE =
'Your Fluxer verification code is {code}. It expires in {minutes} minutes.';
export const SMS_TWILIO_DEFAULT_VERIFY_API_URL = 'https://verify.twilio.com/v2';
export const SMS_MASK_VISIBLE_PREFIX_LENGTH = 6;
export const SMS_TEST_VERIFICATION_CODE = '123456';

View File

@@ -0,0 +1,49 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const StatusTypes = {
ONLINE: 'online',
DND: 'dnd',
IDLE: 'idle',
INVISIBLE: 'invisible',
OFFLINE: 'offline',
} as const;
export type StatusType = ValueOf<typeof StatusTypes>;
const STATUS_VALUES = Object.values(StatusTypes) as Array<StatusType>;
const STATUS_SET = new Set<StatusType>(STATUS_VALUES);
export function isStatusType(value: unknown): value is StatusType {
return typeof value === 'string' && STATUS_SET.has(value as StatusType);
}
export function normalizeStatus(value: unknown): StatusType {
return isStatusType(value) ? value : StatusTypes.OFFLINE;
}
export const OFFLINE_STATUS_TYPES: Set<StatusType> = new Set([StatusTypes.OFFLINE, StatusTypes.INVISIBLE]);
export function isOfflineStatus(
status: StatusType,
): status is typeof StatusTypes.OFFLINE | typeof StatusTypes.INVISIBLE {
return status === StatusTypes.OFFLINE || status === StatusTypes.INVISIBLE;
}

View File

@@ -0,0 +1,23 @@
/*
* 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/>.
*/
export const DIRECT_S3_EXPIRATION_DB_FILENAME = 'direct_s3_metadata.db';
export const DIRECT_S3_EXPIRATION_TABLE = 'direct_s3_object_expirations';
export const DIRECT_S3_EXPIRATION_RETRY_DELAY_MS = 60000;
export const DIRECT_S3_EXPIRATION_TIMER_MAX_DELAY_MS = 2147483647;

View File

@@ -0,0 +1,37 @@
/*
* 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/>.
*/
export const STREAM_PREVIEW_MAX_BYTES = 1_000_000;
export const STREAM_PREVIEW_MAX_DIMENSION_PX = 640;
export const STREAM_PREVIEW_MIN_DIMENSION_PX = 160;
export const STREAM_PREVIEW_INITIAL_UPLOAD_INTERVAL_MS = 1000;
export const STREAM_PREVIEW_INITIAL_UPLOAD_MAX_ATTEMPTS = 10;
export const STREAM_PREVIEW_UPLOAD_INTERVAL_MS = 4 * 60 * 1000;
export const STREAM_PREVIEW_UPLOAD_JITTER_MS = 60 * 1000;
export const STREAM_PREVIEW_REFRESH_INTERVAL_MS = 5000;
export const STREAM_PREVIEW_CONTENT_TYPE_JPEG = 'image/jpeg';
export const STREAM_PREVIEW_JPEG_DATA_URL_PREFIX = 'data:image/jpeg;base64,';
export const STREAM_PREVIEW_JPEG_QUALITY_START = 0.7;
export const STREAM_PREVIEW_JPEG_QUALITY_MIN = 0.4;
export const STREAM_PREVIEW_JPEG_QUALITY_STEP = 0.15;
export const STREAM_PREVIEW_DIMENSION_SCALE_STEP = 0.8;
export const STREAM_PREVIEW_ENCODE_ATTEMPTS = 6;
export const STREAM_AUDIO_PREFS_TTL_MS = 6 * 60 * 60 * 1000;
export const STREAM_AUDIO_PREFS_PRUNE_INTERVAL_MS = 10 * 60 * 1000;
export const STREAM_AUDIO_PREFS_TOUCH_INTERVAL_MS = 5 * 60 * 1000;

View File

@@ -0,0 +1,31 @@
/*
* 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/>.
*/
export const DEFAULT_KV_TIMEOUT_MS = 5000;
export const DEFAULT_EXPORT_TIMEOUT_MS = 30000;
export const DEFAULT_SENTRY_FLUSH_TIMEOUT_MS = 2000;
export const DEFAULT_QUEUE_VISIBILITY_TIMEOUT_MS = 30000;
export const DEFAULT_HTTP_WORKER_TIMEOUT_MS = 30000;
export const DEFAULT_SEARCH_CLIENT_TIMEOUT_MS = 30000;
export const DEFAULT_CSAM_SCAN_TIMEOUT_MS = 30000;
export const DEFAULT_FFPROBE_TIMEOUT_MS = 30000;
export const DEFAULT_THUMBNAIL_TIMEOUT_MS = 30000;
export const DEFAULT_FRAME_EXTRACTION_TIMEOUT_MS = 60000;
export const QUEUE_SNAPSHOT_INTERVAL_MS = 2000;
export const QUEUE_SNAPSHOT_AFTER_OPS = 50000;

View File

@@ -0,0 +1,313 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const UNCATEGORIZED_FOLDER_ID = -1;
export const GuildFolderFlags = {
SHOW_ICON_WHEN_COLLAPSED: 1 << 0,
} as const;
export const GuildFolderFlagsDescriptions: Record<keyof typeof GuildFolderFlags, string> = {
SHOW_ICON_WHEN_COLLAPSED: 'Show the selected icon instead of guild previews when the folder is collapsed',
};
export const GuildFolderIcons = {
FOLDER: 'folder',
STAR: 'star',
HEART: 'heart',
BOOKMARK: 'bookmark',
GAME_CONTROLLER: 'game_controller',
SHIELD: 'shield',
MUSIC_NOTE: 'music_note',
} as const;
export type GuildFolderIcon = ValueOf<typeof GuildFolderIcons>;
export const DEFAULT_GUILD_FOLDER_ICON: GuildFolderIcon = GuildFolderIcons.FOLDER;
export const UserAuthenticatorTypes = {
TOTP: 0,
SMS: 1,
WEBAUTHN: 2,
} as const;
export const UserAuthenticatorTypesDescriptions: Record<keyof typeof UserAuthenticatorTypes, string> = {
TOTP: 'Time-based one-time password authenticator',
SMS: 'SMS-based authenticator',
WEBAUTHN: 'WebAuthn authenticator',
};
export const UserPremiumTypes = {
NONE: 0,
SUBSCRIPTION: 1,
LIFETIME: 2,
} as const;
export const UserPremiumTypesDescriptions: Record<keyof typeof UserPremiumTypes, string> = {
NONE: 'No premium subscription',
SUBSCRIPTION: 'Active premium subscription',
LIFETIME: 'Lifetime premium subscription',
};
export const UserFlags = {
STAFF: 1n << 0n,
CTP_MEMBER: 1n << 1n,
PARTNER: 1n << 2n,
BUG_HUNTER: 1n << 3n,
HIGH_GLOBAL_RATE_LIMIT: 1n << 33n,
FRIENDLY_BOT: 1n << 4n,
FRIENDLY_BOT_MANUAL_APPROVAL: 1n << 5n,
DELETED: 1n << 34n,
DISABLED_SUSPICIOUS_ACTIVITY: 1n << 35n,
SELF_DELETED: 1n << 36n,
PREMIUM_DISCRIMINATOR: 1n << 37n,
DISABLED: 1n << 38n,
HAS_SESSION_STARTED: 1n << 39n,
PREMIUM_BADGE_HIDDEN: 1n << 40n,
PREMIUM_BADGE_MASKED: 1n << 41n,
PREMIUM_BADGE_TIMESTAMP_HIDDEN: 1n << 42n,
PREMIUM_BADGE_SEQUENCE_HIDDEN: 1n << 43n,
PREMIUM_PERKS_SANITIZED: 1n << 44n,
PREMIUM_PURCHASE_DISABLED: 1n << 45n,
PREMIUM_ENABLED_OVERRIDE: 1n << 46n,
RATE_LIMIT_BYPASS: 1n << 47n,
REPORT_BANNED: 1n << 48n,
VERIFIED_NOT_UNDERAGE: 1n << 49n,
HAS_DISMISSED_PREMIUM_ONBOARDING: 1n << 51n,
USED_MOBILE_CLIENT: 1n << 52n,
APP_STORE_REVIEWER: 1n << 53n,
DM_HISTORY_BACKFILLED: 1n << 54n,
HAS_RELATIONSHIPS_INDEXED: 1n << 55n,
MESSAGES_BY_AUTHOR_BACKFILLED: 1n << 56n,
STAFF_HIDDEN: 1n << 57n,
BOT_SANITIZED: 1n << 58n,
} as const;
export const UserFlagsDescriptions: Record<keyof typeof UserFlags, string> = {
STAFF: 'User is a staff member',
CTP_MEMBER: 'User is a community test program member',
PARTNER: 'User is a partner',
BUG_HUNTER: 'User is a bug hunter',
HIGH_GLOBAL_RATE_LIMIT: 'User has elevated global rate limits',
FRIENDLY_BOT: 'Bot accepts friend requests from users',
FRIENDLY_BOT_MANUAL_APPROVAL: 'Bot requires manual approval for friend requests',
DELETED: 'User account has been deleted',
DISABLED_SUSPICIOUS_ACTIVITY: 'User account disabled due to suspicious activity',
SELF_DELETED: 'User account was self-deleted',
PREMIUM_DISCRIMINATOR: 'User has a premium discriminator',
DISABLED: 'User account is disabled',
HAS_SESSION_STARTED: 'User has started a session',
PREMIUM_BADGE_HIDDEN: 'User has hidden their premium badge',
PREMIUM_BADGE_MASKED: 'User has masked their premium badge',
PREMIUM_BADGE_TIMESTAMP_HIDDEN: 'User has hidden their premium badge timestamp',
PREMIUM_BADGE_SEQUENCE_HIDDEN: 'User has hidden their premium badge sequence',
PREMIUM_PERKS_SANITIZED: 'User premium perks are sanitized',
PREMIUM_PURCHASE_DISABLED: 'Premium purchase is disabled for this user',
PREMIUM_ENABLED_OVERRIDE: 'Premium status is enabled via override',
RATE_LIMIT_BYPASS: 'User can bypass rate limits',
REPORT_BANNED: 'User is banned from reporting',
VERIFIED_NOT_UNDERAGE: 'User is verified as not underage',
HAS_DISMISSED_PREMIUM_ONBOARDING: 'User has dismissed premium onboarding',
USED_MOBILE_CLIENT: 'User has used a mobile client',
APP_STORE_REVIEWER: 'User is an app store reviewer',
DM_HISTORY_BACKFILLED: 'User DM history has been backfilled',
HAS_RELATIONSHIPS_INDEXED: 'User relationships have been indexed',
MESSAGES_BY_AUTHOR_BACKFILLED: 'Messages by this author have been backfilled',
STAFF_HIDDEN: 'User staff status is hidden from public flags',
BOT_SANITIZED: "User's owned bot discriminators have been sanitized",
};
export const PUBLIC_USER_FLAGS =
UserFlags.STAFF |
UserFlags.CTP_MEMBER |
UserFlags.PARTNER |
UserFlags.BUG_HUNTER |
UserFlags.FRIENDLY_BOT |
UserFlags.FRIENDLY_BOT_MANUAL_APPROVAL;
export const DELETED_USER_USERNAME = 'DeletedUser';
export const DELETED_USER_GLOBAL_NAME = 'Deleted User';
export const DELETED_USER_DISCRIMINATOR = 0;
export const PublicUserFlags = {
STAFF: Number(UserFlags.STAFF),
CTP_MEMBER: Number(UserFlags.CTP_MEMBER),
PARTNER: Number(UserFlags.PARTNER),
BUG_HUNTER: Number(UserFlags.BUG_HUNTER),
FRIENDLY_BOT: Number(UserFlags.FRIENDLY_BOT),
FRIENDLY_BOT_MANUAL_APPROVAL: Number(UserFlags.FRIENDLY_BOT_MANUAL_APPROVAL),
} as const;
export const PublicUserFlagsDescriptions: Record<keyof typeof PublicUserFlags, string> = {
STAFF: 'User is a staff member',
CTP_MEMBER: 'User is a community test program member',
PARTNER: 'User is a partner',
BUG_HUNTER: 'User is a bug hunter',
FRIENDLY_BOT: 'Bot accepts friend requests from users',
FRIENDLY_BOT_MANUAL_APPROVAL: 'Bot requires manual approval for friend requests',
};
export const SuspiciousActivityFlags = {
REQUIRE_VERIFIED_EMAIL: 1 << 0,
REQUIRE_REVERIFIED_EMAIL: 1 << 1,
REQUIRE_VERIFIED_PHONE: 1 << 2,
REQUIRE_REVERIFIED_PHONE: 1 << 3,
REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE: 1 << 4,
REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE: 1 << 5,
REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE: 1 << 6,
REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE: 1 << 7,
} as const;
export const SuspiciousActivityFlagsDescriptions: Record<keyof typeof SuspiciousActivityFlags, string> = {
REQUIRE_VERIFIED_EMAIL: 'Requires verified email address',
REQUIRE_REVERIFIED_EMAIL: 'Requires re-verified email address',
REQUIRE_VERIFIED_PHONE: 'Requires verified phone number',
REQUIRE_REVERIFIED_PHONE: 'Requires re-verified phone number',
REQUIRE_VERIFIED_EMAIL_OR_VERIFIED_PHONE: 'Requires verified email or verified phone',
REQUIRE_REVERIFIED_EMAIL_OR_VERIFIED_PHONE: 'Requires re-verified email or re-verified phone',
REQUIRE_VERIFIED_EMAIL_OR_REVERIFIED_PHONE: 'Requires verified email or re-verified phone',
REQUIRE_REVERIFIED_EMAIL_OR_REVERIFIED_PHONE: 'Requires re-verified email or re-verified phone',
};
export const ThemeTypes = {
DARK: 'dark',
COAL: 'coal',
LIGHT: 'light',
SYSTEM: 'system',
} as const;
export type ThemeType = ValueOf<typeof ThemeTypes>;
export const TimeFormatTypes = {
AUTO: 0,
TWELVE_HOUR: 1,
TWENTY_FOUR_HOUR: 2,
} as const;
export const TimeFormatTypesDescriptions: Record<keyof typeof TimeFormatTypes, string> = {
AUTO: 'Automatically detect time format based on locale',
TWELVE_HOUR: 'Use 12-hour time format (AM/PM)',
TWENTY_FOUR_HOUR: 'Use 24-hour time format',
};
export const StickerAnimationOptions = {
ALWAYS_ANIMATE: 0,
ANIMATE_ON_INTERACTION: 1,
NEVER_ANIMATE: 2,
} as const;
export const StickerAnimationOptionsDescriptions: Record<keyof typeof StickerAnimationOptions, string> = {
ALWAYS_ANIMATE: 'Always animate stickers',
ANIMATE_ON_INTERACTION: 'Animate stickers on hover/interaction',
NEVER_ANIMATE: 'Never animate stickers',
};
export const RenderSpoilers = {
ALWAYS: 0,
ON_CLICK: 1,
IF_MODERATOR: 2,
} as const;
export const RenderSpoilersDescriptions: Record<keyof typeof RenderSpoilers, string> = {
ALWAYS: 'Always reveal spoiler content',
ON_CLICK: 'Reveal spoiler content on click',
IF_MODERATOR: 'Reveal spoiler content if moderator',
};
export const UserExplicitContentFilterTypes = {
DISABLED: 0,
NON_FRIENDS: 1,
FRIENDS_AND_NON_FRIENDS: 2,
} as const;
export const FriendSourceFlags = {
MUTUAL_FRIENDS: 1 << 0,
MUTUAL_GUILDS: 1 << 1,
NO_RELATION: 1 << 2,
} as const;
export const FriendSourceFlagsDescriptions: Record<keyof typeof FriendSourceFlags, string> = {
MUTUAL_FRIENDS: 'Allow friend requests from users who share mutual friends',
MUTUAL_GUILDS: 'Allow friend requests from users in mutual guilds',
NO_RELATION: 'Allow friend requests from users with no existing relation',
};
export const IncomingCallFlags = {
FRIENDS_OF_FRIENDS: 1 << 0,
GUILD_MEMBERS: 1 << 1,
EVERYONE: 1 << 2,
FRIENDS_ONLY: 1 << 3,
NOBODY: 1 << 4,
SILENT_EVERYONE: 1 << 5,
} as const;
export const IncomingCallFlagsDescriptions: Record<keyof typeof IncomingCallFlags, string> = {
FRIENDS_OF_FRIENDS: 'Allow incoming calls from friends of friends',
GUILD_MEMBERS: 'Allow incoming calls from guild members',
EVERYONE: 'Allow incoming calls from everyone',
FRIENDS_ONLY: 'Allow incoming calls only from friends',
NOBODY: 'Block all incoming calls',
SILENT_EVERYONE: 'Allow calls from everyone but receive them silently',
};
export const GroupDmAddPermissionFlags = {
FRIENDS_OF_FRIENDS: 1 << 0,
GUILD_MEMBERS: 1 << 1,
EVERYONE: 1 << 2,
FRIENDS_ONLY: 1 << 3,
NOBODY: 1 << 4,
} as const;
export const GroupDmAddPermissionFlagsDescriptions: Record<keyof typeof GroupDmAddPermissionFlags, string> = {
FRIENDS_OF_FRIENDS: 'Allow friends of friends to add user to group DMs',
GUILD_MEMBERS: 'Allow guild members to add user to group DMs',
EVERYONE: 'Allow everyone to add user to group DMs',
FRIENDS_ONLY: 'Allow only friends to add user to group DMs',
NOBODY: 'Block everyone from adding user to group DMs',
};
export const UserNotificationSettings = {
ALL_MESSAGES: 0,
ONLY_MENTIONS: 1,
NO_MESSAGES: 2,
INHERIT: 3,
} as const;
export const UserNotificationSettingsDescriptions: Record<keyof typeof UserNotificationSettings, string> = {
ALL_MESSAGES: 'Receive notifications for all messages',
ONLY_MENTIONS: 'Only receive notifications for mentions',
NO_MESSAGES: 'Do not receive any notifications',
INHERIT: 'Inherit notification settings from parent',
};
export const RelationshipTypes = {
FRIEND: 1,
BLOCKED: 2,
INCOMING_REQUEST: 3,
OUTGOING_REQUEST: 4,
} as const;
export const RelationshipTypesDescriptions: Record<keyof typeof RelationshipTypes, string> = {
FRIEND: 'User is a friend',
BLOCKED: 'User is blocked',
INCOMING_REQUEST: 'Pending incoming friend request',
OUTGOING_REQUEST: 'Pending outgoing friend request',
};

View File

@@ -0,0 +1,257 @@
/*
* 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 type {ValueOf} from '@fluxer/constants/src/ValueOf';
export const ValidationErrorCodes = {
ACCENT_COLOR_CHANGED_TOO_MANY_TIMES: 'ACCENT_COLOR_CHANGED_TOO_MANY_TIMES',
ACCOUNT_ALREADY_VERIFIED: 'ACCOUNT_ALREADY_VERIFIED',
AFK_CHANNEL_MUST_BE_IN_GUILD: 'AFK_CHANNEL_MUST_BE_IN_GUILD',
AFK_CHANNEL_MUST_BE_VOICE: 'AFK_CHANNEL_MUST_BE_VOICE',
ALL_CHANNELS_MUST_BELONG_TO_GUILD: 'ALL_CHANNELS_MUST_BELONG_TO_GUILD',
ANIMATED_AVATARS_REQUIRE_PREMIUM: 'ANIMATED_AVATARS_REQUIRE_PREMIUM',
ANIMATED_GUILD_BANNER_REQUIRES_FEATURE: 'ANIMATED_GUILD_BANNER_REQUIRES_FEATURE',
AT_LEAST_ONE_ENTRY_IS_REQUIRED: 'AT_LEAST_ONE_ENTRY_IS_REQUIRED',
AT_LEAST_ONE_RECIPIENT_REQUIRED: 'AT_LEAST_ONE_RECIPIENT_REQUIRED',
ATTACHMENT_FIELDS_REQUIRED: 'ATTACHMENT_FIELDS_REQUIRED',
ATTACHMENT_ID_NOT_FOUND_IN_MESSAGE: 'ATTACHMENT_ID_NOT_FOUND_IN_MESSAGE',
ATTACHMENT_IDS_MUST_BE_VALID_INTEGERS: 'ATTACHMENT_IDS_MUST_BE_VALID_INTEGERS',
ATTACHMENT_METADATA_WITHOUT_FILES: 'ATTACHMENT_METADATA_WITHOUT_FILES',
ATTACHMENT_MUST_BE_IMAGE: 'ATTACHMENT_MUST_BE_IMAGE',
ATTACHMENTS_METADATA_REQUIRED_WHEN_UPLOADING: 'ATTACHMENTS_METADATA_REQUIRED_WHEN_UPLOADING',
ATTACHMENTS_NOT_ALLOWED_FOR_MESSAGE: 'ATTACHMENTS_NOT_ALLOWED_FOR_MESSAGE',
AVATAR_CHANGED_TOO_MANY_TIMES: 'AVATAR_CHANGED_TOO_MANY_TIMES',
BANNER_CHANGED_TOO_MANY_TIMES: 'BANNER_CHANGED_TOO_MANY_TIMES',
BANNERS_REQUIRE_PREMIUM: 'BANNERS_REQUIRE_PREMIUM',
BASE64_LENGTH_INVALID: 'BASE64_LENGTH_INVALID',
BIO_CHANGED_TOO_MANY_TIMES: 'BIO_CHANGED_TOO_MANY_TIMES',
BUCKET_IS_REQUIRED: 'BUCKET_IS_REQUIRED',
CANNOT_ADD_YOURSELF_TO_GROUP_DM: 'CANNOT_ADD_YOURSELF_TO_GROUP_DM',
CANNOT_DELETE_MORE_THAN_100_MESSAGES: 'CANNOT_DELETE_MORE_THAN_100_MESSAGES',
CANNOT_DM_YOURSELF: 'CANNOT_DM_YOURSELF',
CANNOT_EDIT_ATTACHMENT_METADATA: 'CANNOT_EDIT_ATTACHMENT_METADATA',
CANNOT_LEAVE_GUILD_AS_OWNER: 'CANNOT_LEAVE_GUILD_AS_OWNER',
CANNOT_POSITION_CHANNEL_RELATIVE_TO_ITSELF: 'CANNOT_POSITION_CHANNEL_RELATIVE_TO_ITSELF',
CANNOT_PRELOAD_MORE_THAN_100_CHANNELS: 'CANNOT_PRELOAD_MORE_THAN_100_CHANNELS',
CANNOT_REFERENCE_ATTACHMENTS_WITHOUT_ATTACHMENTS: 'CANNOT_REFERENCE_ATTACHMENTS_WITHOUT_ATTACHMENTS',
CANNOT_REORDER_EVERYONE_ROLE: 'CANNOT_REORDER_EVERYONE_ROLE',
CANNOT_REPLY_TO_SYSTEM_MESSAGE: 'CANNOT_REPLY_TO_SYSTEM_MESSAGE',
CANNOT_SET_HOIST_FOR_EVERYONE_ROLE: 'CANNOT_SET_HOIST_FOR_EVERYONE_ROLE',
CANNOT_SPECIFY_BOTH_BEFORE_AND_AFTER: 'CANNOT_SPECIFY_BOTH_BEFORE_AND_AFTER',
CANNOT_USE_SAME_ROLE_AS_PRECEDING: 'CANNOT_USE_SAME_ROLE_AS_PRECEDING',
CATEGORIES_CANNOT_HAVE_PARENT_CHANNEL: 'CATEGORIES_CANNOT_HAVE_PARENT_CHANNEL',
CATEGORIES_CANNOT_HAVE_PARENTS: 'CATEGORIES_CANNOT_HAVE_PARENTS',
CHANGING_DISCRIMINATOR_REQUIRES_PREMIUM: 'CHANGING_DISCRIMINATOR_REQUIRES_PREMIUM',
CHANNEL_DOES_NOT_EXIST: 'CHANNEL_DOES_NOT_EXIST',
CHANNEL_ID_IS_REQUIRED: 'CHANNEL_ID_IS_REQUIRED',
CHANNEL_MUST_BE_DM_OR_GROUP_DM: 'CHANNEL_MUST_BE_DM_OR_GROUP_DM',
CHANNEL_MUST_BE_VOICE: 'CHANNEL_MUST_BE_VOICE',
CHANNEL_NAME_EMPTY_AFTER_NORMALIZATION: 'CHANNEL_NAME_EMPTY_AFTER_NORMALIZATION',
CHANNEL_NOT_FOUND: 'CHANNEL_NOT_FOUND',
COLOR_VALUE_TOO_HIGH: 'COLOR_VALUE_TOO_HIGH',
COLOR_VALUE_TOO_LOW: 'COLOR_VALUE_TOO_LOW',
CONTENT_EXCEEDS_MAX_LENGTH: 'CONTENT_EXCEEDS_MAX_LENGTH',
CONTEXT_CHANNEL_OR_GUILD_ID_REQUIRED: 'CONTEXT_CHANNEL_OR_GUILD_ID_REQUIRED',
CUSTOM_EMOJI_NOT_FOUND: 'CUSTOM_EMOJI_NOT_FOUND',
CUSTOM_EMOJIS_REQUIRE_PREMIUM_OUTSIDE_SOURCE: 'CUSTOM_EMOJIS_REQUIRE_PREMIUM_OUTSIDE_SOURCE',
CUSTOM_STICKER_NOT_FOUND: 'CUSTOM_STICKER_NOT_FOUND',
CUSTOM_STICKERS_IN_DMS_REQUIRE_PREMIUM: 'CUSTOM_STICKERS_IN_DMS_REQUIRE_PREMIUM',
CUSTOM_STICKERS_REQUIRE_PREMIUM_OUTSIDE_SOURCE: 'CUSTOM_STICKERS_REQUIRE_PREMIUM_OUTSIDE_SOURCE',
DISCRIMINATOR_INVALID_FORMAT: 'DISCRIMINATOR_INVALID_FORMAT',
DISCRIMINATOR_OUT_OF_RANGE: 'DISCRIMINATOR_OUT_OF_RANGE',
DUPLICATE_ATTACHMENT_IDS_NOT_ALLOWED: 'DUPLICATE_ATTACHMENT_IDS_NOT_ALLOWED',
DUPLICATE_FILE_INDEX: 'DUPLICATE_FILE_INDEX',
DUPLICATE_RECIPIENTS_NOT_ALLOWED: 'DUPLICATE_RECIPIENTS_NOT_ALLOWED',
VOICE_MESSAGES_ATTACHMENT_MUST_BE_AUDIO: 'VOICE_MESSAGES_ATTACHMENT_MUST_BE_AUDIO',
VOICE_MESSAGES_ATTACHMENT_WAVEFORM_REQUIRED: 'VOICE_MESSAGES_ATTACHMENT_WAVEFORM_REQUIRED',
VOICE_MESSAGES_ATTACHMENT_DURATION_REQUIRED: 'VOICE_MESSAGES_ATTACHMENT_DURATION_REQUIRED',
VOICE_MESSAGES_CANNOT_HAVE_CONTENT: 'VOICE_MESSAGES_CANNOT_HAVE_CONTENT',
VOICE_MESSAGES_CANNOT_HAVE_EMBEDS: 'VOICE_MESSAGES_CANNOT_HAVE_EMBEDS',
VOICE_MESSAGES_CANNOT_HAVE_FAVORITE_MEMES: 'VOICE_MESSAGES_CANNOT_HAVE_FAVORITE_MEMES',
VOICE_MESSAGES_CANNOT_HAVE_STICKERS: 'VOICE_MESSAGES_CANNOT_HAVE_STICKERS',
VOICE_MESSAGES_DURATION_EXCEEDS_LIMIT: 'VOICE_MESSAGES_DURATION_EXCEEDS_LIMIT',
VOICE_MESSAGES_REQUIRE_SINGLE_ATTACHMENT: 'VOICE_MESSAGES_REQUIRE_SINGLE_ATTACHMENT',
EMAIL_ALREADY_IN_USE: 'EMAIL_ALREADY_IN_USE',
EMAIL_IS_REQUIRED: 'EMAIL_IS_REQUIRED',
EMAIL_LENGTH_INVALID: 'EMAIL_LENGTH_INVALID',
EMAIL_MUST_BE_CHANGED_VIA_TOKEN: 'EMAIL_MUST_BE_CHANGED_VIA_TOKEN',
EMAIL_TOKEN_EXPIRED: 'EMAIL_TOKEN_EXPIRED',
EMBED_INDEX_OUT_OF_BOUNDS: 'EMBED_INDEX_OUT_OF_BOUNDS',
EMBED_SPLASH_REQUIRES_FEATURE: 'EMBED_SPLASH_REQUIRES_FEATURE',
EMBEDS_EXCEED_MAX_CHARACTERS: 'EMBEDS_EXCEED_MAX_CHARACTERS',
EMOJI_REQUIRES_GUILD_OR_PACK_ACCESS: 'EMOJI_REQUIRES_GUILD_OR_PACK_ACCESS',
FAILED_TO_PARSE_MULTIPART_FORM_DATA: 'FAILED_TO_PARSE_MULTIPART_FORM_DATA',
FAILED_TO_PARSE_MULTIPART_PAYLOAD: 'FAILED_TO_PARSE_MULTIPART_PAYLOAD',
FAILED_TO_UPLOAD_IMAGE: 'FAILED_TO_UPLOAD_IMAGE',
FAVORITE_MEME_NAME_REQUIRED: 'FAVORITE_MEME_NAME_REQUIRED',
FAVORITE_MEME_NOT_FOUND: 'FAVORITE_MEME_NOT_FOUND',
FILE_INDEX_EXCEEDS_MAXIMUM: 'FILE_INDEX_EXCEEDS_MAXIMUM',
FILE_NOT_FOUND_FOR_SCANNING: 'FILE_NOT_FOUND_FOR_SCANNING',
FILE_NOT_FOUND: 'FILE_NOT_FOUND',
FILENAME_EMPTY_AFTER_NORMALIZATION: 'FILENAME_EMPTY_AFTER_NORMALIZATION',
FILENAME_INVALID_CHARACTERS: 'FILENAME_INVALID_CHARACTERS',
FILENAME_LENGTH_INVALID: 'FILENAME_LENGTH_INVALID',
FILENAME_MISMATCH_FOR_ATTACHMENT: 'FILENAME_MISMATCH_FOR_ATTACHMENT',
FORWARD_MESSAGES_CANNOT_CONTAIN_CONTENT: 'FORWARD_MESSAGES_CANNOT_CONTAIN_CONTENT',
FORWARD_REFERENCE_REQUIRES_CHANNEL_AND_MESSAGE: 'FORWARD_REFERENCE_REQUIRES_CHANNEL_AND_MESSAGE',
GLOBAL_NAME_CANNOT_CONTAIN_RESERVED_TERMS: 'GLOBAL_NAME_CANNOT_CONTAIN_RESERVED_TERMS',
GLOBAL_NAME_LENGTH_INVALID: 'GLOBAL_NAME_LENGTH_INVALID',
GLOBAL_NAME_RESERVED_VALUE: 'GLOBAL_NAME_RESERVED_VALUE',
GUILD_BANNER_REQUIRES_FEATURE: 'GUILD_BANNER_REQUIRES_FEATURE',
GUILD_ID_MUST_MATCH_REFERENCED_MESSAGE: 'GUILD_ID_MUST_MATCH_REFERENCED_MESSAGE',
IMAGE_SIZE_EXCEEDS_LIMIT: 'IMAGE_SIZE_EXCEEDS_LIMIT',
INTEGER_OUT_OF_INT64_RANGE: 'INTEGER_OUT_OF_INT64_RANGE',
SNOWFLAKE_OUT_OF_RANGE: 'SNOWFLAKE_OUT_OF_RANGE',
INVALID_AUDIT_LOG_REASON: 'INVALID_AUDIT_LOG_REASON',
INVALID_BASE64_FORMAT: 'INVALID_BASE64_FORMAT',
INVALID_CHANNEL_ID: 'INVALID_CHANNEL_ID',
INVALID_CHANNEL: 'INVALID_CHANNEL',
INVALID_CODE: 'INVALID_CODE',
INVALID_CURRENT_PASSWORD: 'INVALID_CURRENT_PASSWORD',
INVALID_DATE_OF_BIRTH_FORMAT: 'INVALID_DATE_OF_BIRTH_FORMAT',
INVALID_DATETIME_FOR_SCHEDULED_SEND: 'INVALID_DATETIME_FOR_SCHEDULED_SEND',
INVALID_EMAIL_ADDRESS: 'INVALID_EMAIL_ADDRESS',
INVALID_EMAIL_FORMAT: 'INVALID_EMAIL_FORMAT',
INVALID_EMAIL_LOCAL_PART: 'INVALID_EMAIL_LOCAL_PART',
INVALID_EMAIL_OR_PASSWORD: 'INVALID_EMAIL_OR_PASSWORD',
INVALID_EMAIL_TOKEN: 'INVALID_EMAIL_TOKEN',
INVALID_FILE_FIELD_NAME: 'INVALID_FILE_FIELD_NAME',
INVALID_FORMAT: 'INVALID_FORMAT',
INVALID_IMAGE_DATA: 'INVALID_IMAGE_DATA',
INVALID_IMAGE_FORMAT: 'INVALID_IMAGE_FORMAT',
INVALID_INTEGER_FORMAT: 'INVALID_INTEGER_FORMAT',
INVALID_SNOWFLAKE_FORMAT: 'INVALID_SNOWFLAKE_FORMAT',
INVALID_ISO_TIMESTAMP: 'INVALID_ISO_TIMESTAMP',
INVALID_JOB_ID: 'INVALID_JOB_ID',
INVALID_JSON_IN_PAYLOAD_JSON: 'INVALID_JSON_IN_PAYLOAD_JSON',
INVALID_MESSAGE_DATA: 'INVALID_MESSAGE_DATA',
INVALID_MFA_CODE: 'INVALID_MFA_CODE',
INVALID_OR_EXPIRED_AUTHORIZATION_TICKET: 'INVALID_OR_EXPIRED_AUTHORIZATION_TICKET',
INVALID_OR_EXPIRED_AUTHORIZATION_TOKEN: 'INVALID_OR_EXPIRED_AUTHORIZATION_TOKEN',
INVALID_OR_EXPIRED_RESET_TOKEN: 'INVALID_OR_EXPIRED_RESET_TOKEN',
INVALID_OR_EXPIRED_REVERT_TOKEN: 'INVALID_OR_EXPIRED_REVERT_TOKEN',
INVALID_OR_EXPIRED_TICKET: 'INVALID_OR_EXPIRED_TICKET',
INVALID_OR_EXPIRED_VERIFICATION_TOKEN: 'INVALID_OR_EXPIRED_VERIFICATION_TOKEN',
INVALID_OR_RESTRICTED_RTC_REGION: 'INVALID_OR_RESTRICTED_RTC_REGION',
INVALID_PARENT_CHANNEL: 'INVALID_PARENT_CHANNEL',
INVALID_PASSWORD: 'INVALID_PASSWORD',
INVALID_PROOF_TOKEN: 'INVALID_PROOF_TOKEN',
INVALID_ROLE_ID: 'INVALID_ROLE_ID',
INVALID_RTC_REGION: 'INVALID_RTC_REGION',
INVALID_SCHEDULED_MESSAGE_PAYLOAD: 'INVALID_SCHEDULED_MESSAGE_PAYLOAD',
INVALID_SNOWFLAKE: 'INVALID_SNOWFLAKE',
INVALID_TIMEOUT_VALUE: 'INVALID_TIMEOUT_VALUE',
INVALID_TIMEZONE_IDENTIFIER: 'INVALID_TIMEZONE_IDENTIFIER',
INVALID_URL_FORMAT: 'INVALID_URL_FORMAT',
INVALID_URL_OR_ATTACHMENT_FORMAT: 'INVALID_URL_OR_ATTACHMENT_FORMAT',
INVALID_VERIFICATION_CODE: 'INVALID_VERIFICATION_CODE',
INVITE_SPLASH_REQUIRES_FEATURE: 'INVITE_SPLASH_REQUIRES_FEATURE',
JOB_ID_IS_REQUIRED: 'JOB_ID_IS_REQUIRED',
JOB_IS_ALREADY_PROCESSED: 'JOB_IS_ALREADY_PROCESSED',
JOB_NOT_FOUND: 'JOB_NOT_FOUND',
MEDIA_ALREADY_IN_FAVORITE_MEMES: 'MEDIA_ALREADY_IN_FAVORITE_MEMES',
MESSAGE_HISTORY_CUTOFF_BEFORE_GUILD_CREATION: 'MESSAGE_HISTORY_CUTOFF_BEFORE_GUILD_CREATION',
MESSAGE_HISTORY_CUTOFF_IN_FUTURE: 'MESSAGE_HISTORY_CUTOFF_IN_FUTURE',
MESSAGE_IDS_CANNOT_BE_EMPTY: 'MESSAGE_IDS_CANNOT_BE_EMPTY',
MESSAGES_ARRAY_REQUIRED_AND_NOT_EMPTY: 'MESSAGES_ARRAY_REQUIRED_AND_NOT_EMPTY',
MESSAGES_WITH_SNAPSHOTS_CANNOT_BE_EDITED: 'MESSAGES_WITH_SNAPSHOTS_CANNOT_BE_EDITED',
MESSAGE_TOTAL_ATTACHMENT_SIZE_TOO_LARGE: 'MESSAGE_TOTAL_ATTACHMENT_SIZE_TOO_LARGE',
MULTIPLE_FILES_FOR_INDEX_NOT_ALLOWED: 'MULTIPLE_FILES_FOR_INDEX_NOT_ALLOWED',
MUST_AGREE_TO_TOS_AND_PRIVACY_POLICY: 'MUST_AGREE_TO_TOS_AND_PRIVACY_POLICY',
MUST_BE_MINIMUM_AGE: 'MUST_BE_MINIMUM_AGE',
MUST_ENABLE_2FA_BEFORE_REQUIRING_FOR_MODS: 'MUST_ENABLE_2FA_BEFORE_REQUIRING_FOR_MODS',
MUST_HAVE_EMAIL_TO_CHANGE_IT: 'MUST_HAVE_EMAIL_TO_CHANGE_IT',
MUST_START_SESSION_BEFORE_SENDING: 'MUST_START_SESSION_BEFORE_SENDING',
NAME_EMPTY_AFTER_NORMALIZATION: 'NAME_EMPTY_AFTER_NORMALIZATION',
NEW_EMAIL_MUST_BE_DIFFERENT: 'NEW_EMAIL_MUST_BE_DIFFERENT',
NO_FILE_FOR_ATTACHMENT_METADATA: 'NO_FILE_FOR_ATTACHMENT_METADATA',
NO_FILE_FOR_ATTACHMENT: 'NO_FILE_FOR_ATTACHMENT',
NO_METADATA_FOR_FILE: 'NO_METADATA_FOR_FILE',
NO_NEW_EMAIL_REQUESTED: 'NO_NEW_EMAIL_REQUESTED',
NO_ORIGINAL_EMAIL_ON_RECORD: 'NO_ORIGINAL_EMAIL_ON_RECORD',
NO_VALID_MEDIA_IN_MESSAGE: 'NO_VALID_MEDIA_IN_MESSAGE',
NOT_A_VALID_UNICODE_EMOJI: 'NOT_A_VALID_UNICODE_EMOJI',
ORIGINAL_EMAIL_ALREADY_VERIFIED: 'ORIGINAL_EMAIL_ALREADY_VERIFIED',
ORIGINAL_EMAIL_MUST_BE_VERIFIED_FIRST: 'ORIGINAL_EMAIL_MUST_BE_VERIFIED_FIRST',
ORIGINAL_VERIFICATION_NOT_REQUIRED: 'ORIGINAL_VERIFICATION_NOT_REQUIRED',
PARENT_CHANNEL_NOT_IN_GUILD: 'PARENT_CHANNEL_NOT_IN_GUILD',
PARENT_MUST_BE_CATEGORY: 'PARENT_MUST_BE_CATEGORY',
PARSE_AND_USERS_OR_ROLES_CANNOT_BE_USED_TOGETHER: 'PARSE_AND_USERS_OR_ROLES_CANNOT_BE_USED_TOGETHER',
PASSWORD_IS_TOO_COMMON: 'PASSWORD_IS_TOO_COMMON',
PASSWORD_LENGTH_INVALID: 'PASSWORD_LENGTH_INVALID',
PASSWORD_NOT_SET: 'PASSWORD_NOT_SET',
PAYLOAD_JSON_REQUIRED_FOR_MULTIPART: 'PAYLOAD_JSON_REQUIRED_FOR_MULTIPART',
PHONE_NUMBER_INVALID_FORMAT: 'PHONE_NUMBER_INVALID_FORMAT',
PRECEDING_CHANNEL_MUST_SHARE_PARENT: 'PRECEDING_CHANNEL_MUST_SHARE_PARENT',
PRECEDING_CHANNEL_NOT_IN_GUILD: 'PRECEDING_CHANNEL_NOT_IN_GUILD',
PRECEDING_ROLE_NOT_IN_GUILD: 'PRECEDING_ROLE_NOT_IN_GUILD',
PREMIUM_REQUIRED_FOR_CUSTOM_EMOJI: 'PREMIUM_REQUIRED_FOR_CUSTOM_EMOJI',
PRONOUNS_CHANGED_TOO_MANY_TIMES: 'PRONOUNS_CHANGED_TOO_MANY_TIMES',
RECIPIENT_IDS_CANNOT_BE_EMPTY: 'RECIPIENT_IDS_CANNOT_BE_EMPTY',
RECIPIENT_IDS_MUST_BE_STRINGS: 'RECIPIENT_IDS_MUST_BE_STRINGS',
RECIPIENT_IDS_MUST_BE_VALID_SNOWFLAKES: 'RECIPIENT_IDS_MUST_BE_VALID_SNOWFLAKES',
REFERENCED_ATTACHMENT_NOT_FOUND: 'REFERENCED_ATTACHMENT_NOT_FOUND',
ROWS_IS_REQUIRED: 'ROWS_IS_REQUIRED',
SCHEDULED_MESSAGES_MAX_30_DAYS: 'SCHEDULED_MESSAGES_MAX_30_DAYS',
SCHEDULED_TIME_MUST_BE_FUTURE: 'SCHEDULED_TIME_MUST_BE_FUTURE',
SESSION_TIMEOUT: 'SESSION_TIMEOUT',
SIZE_BYTES_MUST_BE_VALID_INTEGER: 'SIZE_BYTES_MUST_BE_VALID_INTEGER',
STRING_LENGTH_EXACT: 'STRING_LENGTH_EXACT',
STRING_LENGTH_INVALID: 'STRING_LENGTH_INVALID',
SYSTEM_CHANNEL_MUST_BE_IN_GUILD: 'SYSTEM_CHANNEL_MUST_BE_IN_GUILD',
SYSTEM_CHANNEL_MUST_BE_TEXT: 'SYSTEM_CHANNEL_MUST_BE_TEXT',
TAG_ALREADY_TAKEN: 'TAG_ALREADY_TAKEN',
THIS_VANITY_URL_IS_ALREADY_TAKEN: 'THIS_VANITY_URL_IS_ALREADY_TAKEN',
TICKET_ALREADY_COMPLETED: 'TICKET_ALREADY_COMPLETED',
TIMEOUT_CANNOT_EXCEED_365_DAYS: 'TIMEOUT_CANNOT_EXCEED_365_DAYS',
TOO_MANY_EMBEDS: 'TOO_MANY_EMBEDS',
TOO_MANY_FILES: 'TOO_MANY_FILES',
TOO_MANY_USERS_WITH_THIS_USERNAME: 'TOO_MANY_USERS_WITH_THIS_USERNAME',
TOO_MANY_USERS_WITH_USERNAME_TRY_DIFFERENT: 'TOO_MANY_USERS_WITH_USERNAME_TRY_DIFFERENT',
UNCLAIMED_ACCOUNTS_CAN_ONLY_SET_EMAIL_VIA_TOKEN: 'UNCLAIMED_ACCOUNTS_CAN_ONLY_SET_EMAIL_VIA_TOKEN',
UNKNOWN_IMAGE_FORMAT: 'UNKNOWN_IMAGE_FORMAT',
UNRESOLVED_ATTACHMENT_URL: 'UNRESOLVED_ATTACHMENT_URL',
UPLOADED_ATTACHMENT_NOT_FOUND: 'UPLOADED_ATTACHMENT_NOT_FOUND',
URL_LENGTH_INVALID: 'URL_LENGTH_INVALID',
USER_DOES_NOT_HAVE_AN_EMAIL_ADDRESS: 'USER_DOES_NOT_HAVE_AN_EMAIL_ADDRESS',
USER_IS_NOT_BANNED: 'USER_IS_NOT_BANNED',
USER_MUST_BE_A_BOT_TO_BE_MARKED_AS_A_SYSTEM_USER: 'USER_MUST_BE_A_BOT_TO_BE_MARKED_AS_A_SYSTEM_USER',
USER_NOT_IN_CHANNEL: 'USER_NOT_IN_CHANNEL',
USERNAME_CANNOT_CONTAIN_RESERVED_TERMS: 'USERNAME_CANNOT_CONTAIN_RESERVED_TERMS',
USERNAME_CHANGED_TOO_MANY_TIMES: 'USERNAME_CHANGED_TOO_MANY_TIMES',
USERNAME_INVALID_CHARACTERS: 'USERNAME_INVALID_CHARACTERS',
USERNAME_LENGTH_INVALID: 'USERNAME_LENGTH_INVALID',
USERNAME_RESERVED_VALUE: 'USERNAME_RESERVED_VALUE',
VALUE_MUST_BE_INTEGER_IN_RANGE: 'VALUE_MUST_BE_INTEGER_IN_RANGE',
VALUE_TOO_SMALL: 'VALUE_TOO_SMALL',
VANITY_URL_CODE_ALREADY_TAKEN: 'VANITY_URL_CODE_ALREADY_TAKEN',
VANITY_URL_CODE_CANNOT_CONTAIN_FLUXER: 'VANITY_URL_CODE_CANNOT_CONTAIN_FLUXER',
VANITY_URL_CODE_LENGTH_INVALID: 'VANITY_URL_CODE_LENGTH_INVALID',
VANITY_URL_INVALID_CHARACTERS: 'VANITY_URL_INVALID_CHARACTERS',
VANITY_URL_REQUIRES_FEATURE: 'VANITY_URL_REQUIRES_FEATURE',
VERIFICATION_CODE_EXPIRED: 'VERIFICATION_CODE_EXPIRED',
VERIFICATION_CODE_NOT_ISSUED: 'VERIFICATION_CODE_NOT_ISSUED',
VISIONARY_REQUIRED_FOR_BOT_DISCRIMINATOR: 'VISIONARY_REQUIRED_FOR_BOT_DISCRIMINATOR',
VISIONARY_REQUIRED_FOR_DISCRIMINATOR: 'VISIONARY_REQUIRED_FOR_DISCRIMINATOR',
BOT_DISCRIMINATOR_CANNOT_BE_CHANGED: 'BOT_DISCRIMINATOR_CANNOT_BE_CHANGED',
VOICE_CHANNELS_CANNOT_BE_ABOVE_TEXT_CHANNELS: 'VOICE_CHANNELS_CANNOT_BE_ABOVE_TEXT_CHANNELS',
WEBHOOK_NAME_LENGTH_INVALID: 'WEBHOOK_NAME_LENGTH_INVALID',
} as const;
export type ValidationErrorCode = ValueOf<typeof ValidationErrorCodes>;

View File

@@ -0,0 +1,256 @@
/*
* 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 type {ValidationErrorCodes} from '@fluxer/constants/src/ValidationErrorCodes';
export const ValidationErrorCodesDescriptions: Record<keyof typeof ValidationErrorCodes, string> = {
ACCENT_COLOR_CHANGED_TOO_MANY_TIMES: 'Accent colour has been changed too many times recently',
ACCOUNT_ALREADY_VERIFIED: 'Account is already verified',
AFK_CHANNEL_MUST_BE_IN_GUILD: 'AFK channel must be in the same guild',
AFK_CHANNEL_MUST_BE_VOICE: 'AFK channel must be a voice channel',
ALL_CHANNELS_MUST_BELONG_TO_GUILD: 'All channels must belong to the same guild',
ANIMATED_AVATARS_REQUIRE_PREMIUM: 'Animated avatars require premium',
ANIMATED_GUILD_BANNER_REQUIRES_FEATURE: 'Animated guild banners require the feature to be enabled',
AT_LEAST_ONE_ENTRY_IS_REQUIRED: 'At least one entry is required',
AT_LEAST_ONE_RECIPIENT_REQUIRED: 'At least one recipient is required',
ATTACHMENT_FIELDS_REQUIRED: 'Attachment fields are required',
ATTACHMENT_ID_NOT_FOUND_IN_MESSAGE: 'Attachment ID was not found in the message',
ATTACHMENT_IDS_MUST_BE_VALID_INTEGERS: 'Attachment IDs must be valid integers',
ATTACHMENT_METADATA_WITHOUT_FILES: 'Attachment metadata provided without files',
ATTACHMENT_MUST_BE_IMAGE: 'Attachment must be an image',
ATTACHMENTS_METADATA_REQUIRED_WHEN_UPLOADING: 'Attachments metadata is required when uploading files',
ATTACHMENTS_NOT_ALLOWED_FOR_MESSAGE: 'Attachments are not allowed for this message type',
AVATAR_CHANGED_TOO_MANY_TIMES: 'Avatar has been changed too many times recently',
BANNER_CHANGED_TOO_MANY_TIMES: 'Banner has been changed too many times recently',
BANNERS_REQUIRE_PREMIUM: 'Banners require premium',
BASE64_LENGTH_INVALID: 'Invalid base64 length',
BIO_CHANGED_TOO_MANY_TIMES: 'Bio has been changed too many times recently',
BUCKET_IS_REQUIRED: 'Bucket is required',
CANNOT_ADD_YOURSELF_TO_GROUP_DM: 'Cannot add yourself to a group DM',
CANNOT_DELETE_MORE_THAN_100_MESSAGES: 'Cannot delete more than 100 messages at once',
CANNOT_DM_YOURSELF: 'Cannot send a direct message to yourself',
CANNOT_EDIT_ATTACHMENT_METADATA:
'Users with MANAGE_MESSAGES can only edit attachment descriptions, not other metadata',
CANNOT_LEAVE_GUILD_AS_OWNER: 'Cannot leave guild as the owner',
CANNOT_POSITION_CHANNEL_RELATIVE_TO_ITSELF: 'Cannot position channel relative to itself',
CANNOT_PRELOAD_MORE_THAN_100_CHANNELS: 'Cannot preload more than 100 channels',
CANNOT_REFERENCE_ATTACHMENTS_WITHOUT_ATTACHMENTS: 'Cannot reference attachments without providing attachments',
CANNOT_REORDER_EVERYONE_ROLE: 'Cannot reorder the everyone role',
CANNOT_REPLY_TO_SYSTEM_MESSAGE: 'Cannot reply to a system message',
CANNOT_SET_HOIST_FOR_EVERYONE_ROLE: 'Cannot set hoist for the everyone role',
CANNOT_SPECIFY_BOTH_BEFORE_AND_AFTER: 'Cannot specify both before and after parameters',
CANNOT_USE_SAME_ROLE_AS_PRECEDING: 'Cannot use the same role as preceding',
CATEGORIES_CANNOT_HAVE_PARENT_CHANNEL: 'Categories cannot have a parent channel',
CATEGORIES_CANNOT_HAVE_PARENTS: 'Categories cannot have parents',
CHANGING_DISCRIMINATOR_REQUIRES_PREMIUM: 'Changing discriminator requires premium',
CHANNEL_DOES_NOT_EXIST: 'Channel does not exist',
CHANNEL_ID_IS_REQUIRED: 'Channel ID is required',
CHANNEL_MUST_BE_DM_OR_GROUP_DM: 'Channel must be a DM or group DM',
CHANNEL_MUST_BE_VOICE: 'Channel must be a voice channel',
CHANNEL_NAME_EMPTY_AFTER_NORMALIZATION: 'Channel name is empty after normalisation',
CHANNEL_NOT_FOUND: 'Channel was not found',
COLOR_VALUE_TOO_HIGH: 'Colour value is too high',
COLOR_VALUE_TOO_LOW: 'Colour value is too low',
CONTENT_EXCEEDS_MAX_LENGTH: 'Content exceeds maximum length',
CONTEXT_CHANNEL_OR_GUILD_ID_REQUIRED: 'Context channel or guild ID is required',
CUSTOM_EMOJI_NOT_FOUND: 'Custom emoji was not found',
CUSTOM_EMOJIS_REQUIRE_PREMIUM_OUTSIDE_SOURCE: 'Custom emojis require premium when used outside their source',
CUSTOM_STICKER_NOT_FOUND: 'Custom sticker was not found',
CUSTOM_STICKERS_IN_DMS_REQUIRE_PREMIUM: 'Custom stickers in DMs require premium',
CUSTOM_STICKERS_REQUIRE_PREMIUM_OUTSIDE_SOURCE: 'Custom stickers require premium when used outside their source',
DISCRIMINATOR_INVALID_FORMAT: 'Discriminator has an invalid format',
DISCRIMINATOR_OUT_OF_RANGE: 'Discriminator is out of valid range',
DUPLICATE_ATTACHMENT_IDS_NOT_ALLOWED: 'Duplicate attachment IDs are not allowed',
DUPLICATE_FILE_INDEX: 'Duplicate file index',
DUPLICATE_RECIPIENTS_NOT_ALLOWED: 'Duplicate recipients are not allowed',
VOICE_MESSAGES_ATTACHMENT_MUST_BE_AUDIO: 'Voice message attachment must be audio',
VOICE_MESSAGES_ATTACHMENT_WAVEFORM_REQUIRED: 'Voice message attachment waveform is required',
VOICE_MESSAGES_ATTACHMENT_DURATION_REQUIRED: 'Voice message attachment duration is required',
VOICE_MESSAGES_CANNOT_HAVE_CONTENT: 'Voice messages cannot have content',
VOICE_MESSAGES_CANNOT_HAVE_EMBEDS: 'Voice messages cannot have embeds',
VOICE_MESSAGES_CANNOT_HAVE_FAVORITE_MEMES: 'Voice messages cannot have favourite memes',
VOICE_MESSAGES_CANNOT_HAVE_STICKERS: 'Voice messages cannot have stickers',
VOICE_MESSAGES_DURATION_EXCEEDS_LIMIT: 'Voice message duration exceeds limit',
VOICE_MESSAGES_REQUIRE_SINGLE_ATTACHMENT: 'Voice messages require a single attachment',
EMAIL_ALREADY_IN_USE: 'Email address is already in use',
EMAIL_IS_REQUIRED: 'Email address is required',
EMAIL_LENGTH_INVALID: 'Email address length is invalid',
EMAIL_MUST_BE_CHANGED_VIA_TOKEN: 'Email must be changed via verification token',
EMAIL_TOKEN_EXPIRED: 'Email verification token has expired',
EMBED_INDEX_OUT_OF_BOUNDS: 'Embed index is out of bounds',
EMBED_SPLASH_REQUIRES_FEATURE: 'Embed splash requires the feature to be enabled',
EMBEDS_EXCEED_MAX_CHARACTERS: 'Embeds exceed maximum character count',
EMOJI_REQUIRES_GUILD_OR_PACK_ACCESS: 'Emoji requires guild or pack access',
FAILED_TO_PARSE_MULTIPART_FORM_DATA: 'Failed to parse multipart form data',
FAILED_TO_PARSE_MULTIPART_PAYLOAD: 'Failed to parse multipart payload',
FAILED_TO_UPLOAD_IMAGE: 'Failed to upload image',
FAVORITE_MEME_NAME_REQUIRED: 'Favourite meme name is required',
FAVORITE_MEME_NOT_FOUND: 'Favourite meme was not found',
FILE_INDEX_EXCEEDS_MAXIMUM: 'File index exceeds maximum',
FILE_NOT_FOUND_FOR_SCANNING: 'File not found for scanning',
FILE_NOT_FOUND: 'File was not found',
FILENAME_EMPTY_AFTER_NORMALIZATION: 'Filename is empty after normalisation',
FILENAME_INVALID_CHARACTERS: 'Filename contains invalid characters',
FILENAME_LENGTH_INVALID: 'Filename length is invalid',
FILENAME_MISMATCH_FOR_ATTACHMENT: 'Filename mismatch for attachment',
FORWARD_MESSAGES_CANNOT_CONTAIN_CONTENT: 'Forward messages cannot contain content',
FORWARD_REFERENCE_REQUIRES_CHANNEL_AND_MESSAGE: 'Forward reference requires channel and message',
GLOBAL_NAME_CANNOT_CONTAIN_RESERVED_TERMS: 'Display name cannot contain reserved terms',
GLOBAL_NAME_LENGTH_INVALID: 'Display name length is invalid',
GLOBAL_NAME_RESERVED_VALUE: 'Display name is a reserved value',
GUILD_BANNER_REQUIRES_FEATURE: 'Guild banner requires the feature to be enabled',
GUILD_ID_MUST_MATCH_REFERENCED_MESSAGE: 'Guild ID must match referenced message',
IMAGE_SIZE_EXCEEDS_LIMIT: 'Image size exceeds limit',
INTEGER_OUT_OF_INT64_RANGE: 'Integer is out of 64-bit range',
SNOWFLAKE_OUT_OF_RANGE: 'Snowflake is out of valid range',
INVALID_AUDIT_LOG_REASON: 'Invalid audit log reason',
INVALID_BASE64_FORMAT: 'Invalid base64 format',
INVALID_CHANNEL_ID: 'Invalid channel ID',
INVALID_CHANNEL: 'Invalid channel',
INVALID_CODE: 'Invalid code',
INVALID_CURRENT_PASSWORD: 'Invalid current password',
INVALID_DATE_OF_BIRTH_FORMAT: 'Invalid date of birth format',
INVALID_DATETIME_FOR_SCHEDULED_SEND: 'Invalid datetime for scheduled send',
INVALID_EMAIL_ADDRESS: 'Invalid email address',
INVALID_EMAIL_FORMAT: 'Invalid email format',
INVALID_EMAIL_LOCAL_PART: 'Invalid email local part',
INVALID_EMAIL_OR_PASSWORD: 'Invalid email or password',
INVALID_EMAIL_TOKEN: 'Invalid email verification token',
INVALID_FILE_FIELD_NAME: 'Invalid file field name',
INVALID_FORMAT: 'Invalid format',
INVALID_IMAGE_DATA: 'Invalid image data',
INVALID_IMAGE_FORMAT: 'Invalid image format',
INVALID_INTEGER_FORMAT: 'Invalid integer format',
INVALID_SNOWFLAKE_FORMAT: 'Invalid snowflake format',
INVALID_ISO_TIMESTAMP: 'Invalid ISO timestamp',
INVALID_JOB_ID: 'Invalid job ID',
INVALID_JSON_IN_PAYLOAD_JSON: 'Invalid JSON in payload_json field',
INVALID_MESSAGE_DATA: 'Invalid message data',
INVALID_MFA_CODE: 'Invalid MFA code',
INVALID_OR_EXPIRED_AUTHORIZATION_TICKET: 'Invalid or expired authorisation ticket',
INVALID_OR_EXPIRED_AUTHORIZATION_TOKEN: 'Invalid or expired authorisation token',
INVALID_OR_EXPIRED_RESET_TOKEN: 'Invalid or expired password reset token',
INVALID_OR_EXPIRED_REVERT_TOKEN: 'Invalid or expired revert token',
INVALID_OR_EXPIRED_TICKET: 'Invalid or expired ticket',
INVALID_OR_EXPIRED_VERIFICATION_TOKEN: 'Invalid or expired verification token',
INVALID_OR_RESTRICTED_RTC_REGION: 'Invalid or restricted RTC region',
INVALID_PARENT_CHANNEL: 'Invalid parent channel',
INVALID_PASSWORD: 'Invalid password',
INVALID_PROOF_TOKEN: 'Invalid proof token',
INVALID_ROLE_ID: 'Invalid role ID',
INVALID_RTC_REGION: 'Invalid RTC region',
INVALID_SCHEDULED_MESSAGE_PAYLOAD: 'Invalid scheduled message payload',
INVALID_SNOWFLAKE: 'Invalid snowflake',
INVALID_TIMEOUT_VALUE: 'Invalid timeout value',
INVALID_TIMEZONE_IDENTIFIER: 'Invalid timezone identifier',
INVALID_URL_FORMAT: 'Invalid URL format',
INVALID_URL_OR_ATTACHMENT_FORMAT: 'Invalid URL or attachment format',
INVALID_VERIFICATION_CODE: 'Invalid verification code',
INVITE_SPLASH_REQUIRES_FEATURE: 'Invite splash requires the feature to be enabled',
JOB_ID_IS_REQUIRED: 'Job ID is required',
JOB_IS_ALREADY_PROCESSED: 'Job has already been processed',
JOB_NOT_FOUND: 'Job was not found',
MEDIA_ALREADY_IN_FAVORITE_MEMES: 'Media is already in favourite memes',
MESSAGE_HISTORY_CUTOFF_BEFORE_GUILD_CREATION: 'Message history cutoff cannot be before the guild was created',
MESSAGE_HISTORY_CUTOFF_IN_FUTURE: 'Message history cutoff cannot be in the future',
MESSAGE_IDS_CANNOT_BE_EMPTY: 'Message IDs cannot be empty',
MESSAGE_TOTAL_ATTACHMENT_SIZE_TOO_LARGE: 'Total attachment size exceeds the maximum allowed',
MESSAGES_ARRAY_REQUIRED_AND_NOT_EMPTY: 'Messages array is required and cannot be empty',
MESSAGES_WITH_SNAPSHOTS_CANNOT_BE_EDITED: 'Messages with snapshots cannot be edited',
MULTIPLE_FILES_FOR_INDEX_NOT_ALLOWED: 'Multiple files for the same index are not allowed',
MUST_AGREE_TO_TOS_AND_PRIVACY_POLICY: 'Must agree to terms of service and privacy policy',
MUST_BE_MINIMUM_AGE: 'Must be minimum age to use this service',
MUST_ENABLE_2FA_BEFORE_REQUIRING_FOR_MODS: 'Must enable 2FA before requiring it for moderators',
MUST_HAVE_EMAIL_TO_CHANGE_IT: 'Must have an email to change it',
MUST_START_SESSION_BEFORE_SENDING: 'Must start session before sending',
NAME_EMPTY_AFTER_NORMALIZATION: 'Name is empty after normalisation',
NEW_EMAIL_MUST_BE_DIFFERENT: 'New email must be different from current email',
NO_FILE_FOR_ATTACHMENT_METADATA: 'No file provided for attachment metadata',
NO_FILE_FOR_ATTACHMENT: 'No file provided for attachment',
NO_METADATA_FOR_FILE: 'No metadata provided for file',
NO_NEW_EMAIL_REQUESTED: 'No new email has been requested',
NO_ORIGINAL_EMAIL_ON_RECORD: 'No original email on record',
NO_VALID_MEDIA_IN_MESSAGE: 'No valid media in message',
NOT_A_VALID_UNICODE_EMOJI: 'Not a valid Unicode emoji',
ORIGINAL_EMAIL_ALREADY_VERIFIED: 'Original email is already verified',
ORIGINAL_EMAIL_MUST_BE_VERIFIED_FIRST: 'Original email must be verified first',
ORIGINAL_VERIFICATION_NOT_REQUIRED: 'Original verification is not required',
PARENT_CHANNEL_NOT_IN_GUILD: 'Parent channel is not in the guild',
PARENT_MUST_BE_CATEGORY: 'Parent channel must be a category',
PARSE_AND_USERS_OR_ROLES_CANNOT_BE_USED_TOGETHER: 'Parse and users/roles cannot be used together',
PASSWORD_IS_TOO_COMMON: 'Password is too common',
PASSWORD_LENGTH_INVALID: 'Password length is invalid',
PASSWORD_NOT_SET: 'Password is not set',
PAYLOAD_JSON_REQUIRED_FOR_MULTIPART: 'payload_json is required for multipart requests',
PHONE_NUMBER_INVALID_FORMAT: 'Phone number has an invalid format',
PRECEDING_CHANNEL_MUST_SHARE_PARENT: 'Preceding channel must share the same parent',
PRECEDING_CHANNEL_NOT_IN_GUILD: 'Preceding channel is not in the guild',
PRECEDING_ROLE_NOT_IN_GUILD: 'Preceding role is not in the guild',
PREMIUM_REQUIRED_FOR_CUSTOM_EMOJI: 'Premium is required for custom emoji',
PRONOUNS_CHANGED_TOO_MANY_TIMES: 'Pronouns have been changed too many times recently',
RECIPIENT_IDS_CANNOT_BE_EMPTY: 'Recipient IDs cannot be empty',
RECIPIENT_IDS_MUST_BE_STRINGS: 'Recipient IDs must be strings',
RECIPIENT_IDS_MUST_BE_VALID_SNOWFLAKES: 'Recipient IDs must be valid snowflakes',
REFERENCED_ATTACHMENT_NOT_FOUND: 'Referenced attachment was not found',
ROWS_IS_REQUIRED: 'Rows field is required',
SCHEDULED_MESSAGES_MAX_30_DAYS: 'Scheduled messages must be within 30 days',
SCHEDULED_TIME_MUST_BE_FUTURE: 'Scheduled time must be in the future',
SESSION_TIMEOUT: 'Session has timed out',
SIZE_BYTES_MUST_BE_VALID_INTEGER: 'Size in bytes must be a valid integer',
STRING_LENGTH_EXACT: 'String must be exactly the required length',
STRING_LENGTH_INVALID: 'String length is invalid',
SYSTEM_CHANNEL_MUST_BE_IN_GUILD: 'System channel must be in the guild',
SYSTEM_CHANNEL_MUST_BE_TEXT: 'System channel must be a text channel',
TAG_ALREADY_TAKEN: 'Tag is already taken',
THIS_VANITY_URL_IS_ALREADY_TAKEN: 'This vanity URL is already taken',
TICKET_ALREADY_COMPLETED: 'Ticket has already been completed',
TIMEOUT_CANNOT_EXCEED_365_DAYS: 'Timeout cannot exceed 365 days',
TOO_MANY_EMBEDS: 'Too many embeds',
TOO_MANY_FILES: 'Too many files',
TOO_MANY_USERS_WITH_THIS_USERNAME: 'Too many users with this username',
TOO_MANY_USERS_WITH_USERNAME_TRY_DIFFERENT: 'Too many users with this username, try a different one',
UNCLAIMED_ACCOUNTS_CAN_ONLY_SET_EMAIL_VIA_TOKEN: 'Unclaimed accounts can only set email via verification token',
UNKNOWN_IMAGE_FORMAT: 'Unknown image format',
UNRESOLVED_ATTACHMENT_URL: 'Unresolved attachment URL',
UPLOADED_ATTACHMENT_NOT_FOUND: 'Uploaded attachment was not found',
URL_LENGTH_INVALID: 'URL length is invalid',
USER_DOES_NOT_HAVE_AN_EMAIL_ADDRESS: 'User does not have an email address',
USER_IS_NOT_BANNED: 'User is not banned',
USER_MUST_BE_A_BOT_TO_BE_MARKED_AS_A_SYSTEM_USER: 'User must be a bot to be marked as a system user',
USER_NOT_IN_CHANNEL: 'User is not in the channel',
USERNAME_CANNOT_CONTAIN_RESERVED_TERMS: 'Username cannot contain reserved terms',
USERNAME_CHANGED_TOO_MANY_TIMES: 'Username has been changed too many times recently',
USERNAME_INVALID_CHARACTERS: 'Username contains invalid characters',
USERNAME_LENGTH_INVALID: 'Username length is invalid',
USERNAME_RESERVED_VALUE: 'Username is a reserved value',
VALUE_MUST_BE_INTEGER_IN_RANGE: 'Value must be an integer in the valid range',
VALUE_TOO_SMALL: 'Value is too small',
VANITY_URL_CODE_ALREADY_TAKEN: 'Vanity URL code is already taken',
VANITY_URL_CODE_CANNOT_CONTAIN_FLUXER: 'Vanity URL code cannot contain fluxer',
VANITY_URL_CODE_LENGTH_INVALID: 'Vanity URL code length is invalid',
VANITY_URL_INVALID_CHARACTERS: 'Vanity URL contains invalid characters',
VANITY_URL_REQUIRES_FEATURE: 'Vanity URL requires the feature to be enabled',
VERIFICATION_CODE_EXPIRED: 'Verification code has expired',
VERIFICATION_CODE_NOT_ISSUED: 'Verification code was not issued',
VISIONARY_REQUIRED_FOR_BOT_DISCRIMINATOR: 'Visionary subscription required for bot discriminator',
VISIONARY_REQUIRED_FOR_DISCRIMINATOR: 'Visionary subscription required for discriminator',
BOT_DISCRIMINATOR_CANNOT_BE_CHANGED: 'Bot discriminator cannot be changed',
VOICE_CHANNELS_CANNOT_BE_ABOVE_TEXT_CHANNELS: 'Voice channels cannot be positioned above text channels',
WEBHOOK_NAME_LENGTH_INVALID: 'Webhook name length is invalid',
};

View File

@@ -0,0 +1,20 @@
/*
* 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/>.
*/
export type ValueOf<T> = T[keyof T];

View File

@@ -0,0 +1,26 @@
/*
* 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/>.
*/
export const VOICE_MESSAGE_HOLD_TOOLTIP_DURATION_MS = 2000;
export const VOICE_MESSAGE_MIN_SEND_DURATION_MS = 500;
export const VOICE_MESSAGE_RECORDING_TICK_MS = 120;
export const VOICE_MESSAGE_WAVEFORM_BAR_COUNT = 24;
export const VOICE_MESSAGE_WAVEFORM_UPDATE_INTERVAL_MS = 70;
export const VOICE_MESSAGE_LOCK_DRAG_MIN_VERTICAL_DELTA_PX = 52;
export const VOICE_MESSAGE_LOCK_DRAG_MAX_HORIZONTAL_DELTA_PX = 96;