/*
Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
Copyright (C) 2025 Spacebar and Spacebar Contributors
This program 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.
This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { ConnectedAccountSchema, Snowflake, UserSettingsSchema } from "@spacebar/schemas";
import { BitField } from "@spacebar/util/util";
import { Relationship, Session } from "@spacebar/util/entities";
interface UserEntityPleaseRewriteThankYou {
id: Snowflake;
username: string;
discriminator: string;
avatar?: string;
accent_color?: number;
banner?: string;
theme_colors?: number[];
pronouns?: string;
phone?: string;
desktop: boolean;
mobile: boolean;
premium: boolean;
premium_type: number;
bot: boolean;
bio: string;
system: boolean;
nsfw_allowed: boolean;
mfa_enabled: boolean;
webauthn_enabled: boolean;
created_at: Date;
premium_since: Date;
verified: boolean;
disabled: boolean;
deleted: boolean;
email?: string;
flags: number;
public_flags: number;
purchased_flags: number;
premium_usage_flags: number;
rights: string;
sessions: Session[];
relationships: Relationship[];
connected_accounts: ConnectedAccountSchema[];
fingerprints: string[];
settings?: UserSettingsSchema;
extended_settings: string;
badge_ids?: string[];
}
export interface PartialUser {
id: Snowflake;
username: string;
discriminator: string;
global_name?: string | null;
avatar: string | null;
avatar_decoration_data?: AvatarDecorationData | null;
collectibles?: Collectibles | null;
display_name_styles?: DisplayNameStyle | null;
primary_guild?: PrimaryGuild | null;
bot?: boolean;
system?: boolean;
banner?: string | null;
accent_color?: number | null;
public_flags?: number;
}
export interface AvatarDecorationData {
asset: string;
sku_id: Snowflake;
expires_at: string | null;
}
export interface Collectibles {
nameplate: NameplateData | null;
}
export interface NameplateData {
asset: string;
sku_id: Snowflake;
label: string;
palette: string;
expires_at: number | null;
}
export interface DisplayNameStyle {
font_id: number;
effect_id: number;
colors: number;
}
export interface PrimaryGuild {
identity_enabled: boolean | null;
identity_guild_id: Snowflake | null;
tag: string | null;
badge: string | null;
}
export enum PublicUserEnum {
username,
discriminator,
id,
public_flags,
avatar,
accent_color,
banner,
bio,
bot,
premium_since,
premium_type,
theme_colors,
pronouns,
badge_ids,
}
export type PublicUserKeys = keyof typeof PublicUserEnum;
export enum PrivateUserEnum {
flags,
mfa_enabled,
email,
phone,
verified,
nsfw_allowed,
premium,
premium_type,
purchased_flags,
premium_usage_flags,
disabled,
settings,
// locale
}
export type PrivateUserKeys = keyof typeof PrivateUserEnum | PublicUserKeys;
export const PublicUserProjection = Object.values(PublicUserEnum).filter((x) => typeof x === "string") as PublicUserKeys[];
export const PrivateUserProjection = [...PublicUserProjection, ...Object.values(PrivateUserEnum).filter((x) => typeof x === "string")] as PrivateUserKeys[];
// Private user data that should never get sent to the client
export type PublicUser = Pick<UserEntityPleaseRewriteThankYou, PublicUserKeys>;
export type PrivateUser = Pick<UserEntityPleaseRewriteThankYou, PrivateUserKeys>;
export interface UserPrivate extends Pick<UserEntityPleaseRewriteThankYou, PrivateUserKeys> {
locale: string;
}
// This causes a failure in openapi.js...?
export class UserFlags extends BitField {
static FLAGS = {
DISCORD_EMPLOYEE: 1n << 0n,
PARTNERED_SERVER_OWNER: 1n << 1n,
HYPESQUAD_EVENTS: 1n << 2n,
BUGHUNTER_LEVEL_1: 1n << 3n,
MFA_SMS: 1n << 4n,
PREMIUM_PROMO_DISMISSED: 1n << 5n,
HOUSE_BRAVERY: 1n << 6n,
HOUSE_BRILLIANCE: 1n << 7n,
HOUSE_BALANCE: 1n << 8n,
EARLY_SUPPORTER: 1n << 9n,
TEAM_USER: 1n << 10n,
TRUST_AND_SAFETY: 1n << 11n,
SYSTEM: 1n << 12n,
HAS_UNREAD_URGENT_MESSAGES: 1n << 13n,
BUGHUNTER_LEVEL_2: 1n << 14n,
UNDERAGE_DELETED: 1n << 15n,
VERIFIED_BOT: 1n << 16n,
EARLY_VERIFIED_BOT_DEVELOPER: 1n << 17n,
CERTIFIED_MODERATOR: 1n << 18n,
BOT_HTTP_INTERACTIONS: 1n << 19n,
SPAMMER: 1n << 20n,
// @deprecated
DISABLE_PREMIUM: 1n << 21n,
ACTIVE_DEVELOPER: 1n << 22n,
PROVISIONAL_ACCOUNT: 1n << 23n,
// Where did 24-32 go???
HIGH_GLOBAL_RATE_LIMIT: 1n << 33n,
DELETED: 1n << 34n,
DISABLED_SUSPICIOUS_ACCOUNT: 1n << 35n,
SELF_DELETED: 1n << 36n,
PREMIUM_DISCIRMINATOR: 1n << 37n,
USED_DESKTOP_CLIENT: 1n << 38n,
USED_WEB_CLIENT: 1n << 39n,
USED_MOBILE_CLIENT: 1n << 40n,
DISABLED: 1n << 41n,
// 42 is unknown...
HAS_SESSION_STARTED: 1n << 43n,
QUARANTINED: 1n << 44n,
// 45 and 46 are unknown...
PREMIUM_ELEGIBLE_FOR_UNIQUE_USERNAME: 1n << 47n,
// 48 and 49 are unknown...
COLLABORATOR: 1n << 50n,
RESTRICTED_COLLABORATOR: 1n << 51n,
};
}