initial commit

This commit is contained in:
Hampus Kraft
2026-01-01 20:42:59 +00:00
commit 2f557eda8c
9029 changed files with 1490197 additions and 0 deletions

File diff suppressed because it is too large Load Diff

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 * from '~/database/types/AdminArchiveTypes';
export * from '~/database/types/AuthTypes';
export * from '~/database/types/ChannelTypes';
export * from '~/database/types/Common';
export * from '~/database/types/GuildTypes';
export * from '~/database/types/InstanceConfigTypes';
export * from '~/database/types/MessageTypes';
export * from '~/database/types/OAuth2Types';
export * from '~/database/types/PaymentTypes';
export * from '~/database/types/ReportTypes';
export * from '~/database/types/UserTypes';
export * from '~/database/types/VoiceTypes';

View File

@@ -0,0 +1,108 @@
/*
* 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 interface AdminArchiveRow {
subject_type: 'user' | 'guild';
subject_id: bigint;
archive_id: bigint;
requested_by: bigint;
requested_at: Date;
started_at: Date | null;
completed_at: Date | null;
failed_at: Date | null;
storage_key: string | null;
file_size: bigint | null;
progress_percent: number;
progress_step: string | null;
error_message: string | null;
download_url_expires_at: Date | null;
expires_at: Date | null;
}
export const ADMIN_ARCHIVE_COLUMNS = [
'subject_type',
'subject_id',
'archive_id',
'requested_by',
'requested_at',
'started_at',
'completed_at',
'failed_at',
'storage_key',
'file_size',
'progress_percent',
'progress_step',
'error_message',
'download_url_expires_at',
'expires_at',
] as const satisfies ReadonlyArray<keyof AdminArchiveRow>;
export interface AdminAuditLogRow {
log_id: bigint;
admin_user_id: bigint;
target_type: string;
target_id: bigint;
action: string;
audit_log_reason: string | null;
metadata: Map<string, string>;
created_at: Date;
}
export const ADMIN_AUDIT_LOG_COLUMNS = [
'log_id',
'admin_user_id',
'target_type',
'target_id',
'action',
'audit_log_reason',
'metadata',
'created_at',
] as const satisfies ReadonlyArray<keyof AdminAuditLogRow>;
export interface BannedIpRow {
ip: string;
}
export const BANNED_IP_COLUMNS = ['ip'] as const satisfies ReadonlyArray<keyof BannedIpRow>;
export interface BannedEmailRow {
email_lower: string;
}
export const BANNED_EMAIL_COLUMNS = ['email_lower'] as const satisfies ReadonlyArray<keyof BannedEmailRow>;
export interface BannedPhoneRow {
phone: string;
}
export const BANNED_PHONE_COLUMNS = ['phone'] as const satisfies ReadonlyArray<keyof BannedPhoneRow>;
export interface PendingVerificationRow {
user_id: bigint;
created_at: Date;
version: number;
metadata: Map<string, string> | null;
}
export const PENDING_VERIFICATION_COLUMNS = [
'user_id',
'created_at',
'version',
'metadata',
] as const satisfies ReadonlyArray<keyof PendingVerificationRow>;

View File

@@ -0,0 +1,226 @@
/*
* 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 {
BetaCode,
EmailRevertToken,
EmailVerificationToken,
IpAuthorizationToken,
MfaBackupCode,
PasswordResetToken,
UserID,
} from '~/BrandedTypes';
type Nullish<T> = T | null;
export interface AuthSessionRow {
user_id: UserID;
session_id_hash: Buffer;
created_at: Date;
approx_last_used_at: Date;
client_ip: string;
client_os: string;
client_platform: string;
client_country: Nullish<string>;
client_location: Nullish<string>;
version: number;
}
export interface MfaBackupCodeRow {
user_id: UserID;
code: MfaBackupCode;
consumed: boolean;
}
export interface EmailVerificationTokenRow {
token_: EmailVerificationToken;
user_id: UserID;
email: string;
}
export interface PasswordResetTokenRow {
token_: PasswordResetToken;
user_id: UserID;
email: string;
}
export interface EmailRevertTokenRow {
token_: EmailRevertToken;
user_id: UserID;
email: string;
}
export interface IpAuthorizationTokenRow {
token_: IpAuthorizationToken;
user_id: UserID;
email: string;
}
export interface BetaCodeRow {
code: BetaCode;
creator_id: UserID;
created_at: Date;
redeemer_id: Nullish<UserID>;
redeemed_at: Nullish<Date>;
version: number;
}
export interface BetaCodeByCodeRow {
code: BetaCode;
creator_id: UserID;
}
export interface AuthorizedIpRow {
user_id: UserID;
ip: string;
}
export interface WebAuthnCredentialRow {
user_id: UserID;
credential_id: string;
public_key: Buffer;
counter: bigint;
transports: Nullish<Set<string>>;
name: string;
created_at: Date;
last_used_at: Nullish<Date>;
version: number;
}
export interface PhoneTokenRow {
token_: string;
phone: string;
user_id: Nullish<UserID>;
}
export interface EmailChangeTicketRow {
ticket: string;
user_id: UserID;
require_original: boolean;
original_email: Nullish<string>;
original_verified: boolean;
original_proof: Nullish<string>;
original_code: Nullish<string>;
original_code_sent_at: Nullish<Date>;
original_code_expires_at: Nullish<Date>;
new_email: Nullish<string>;
new_code: Nullish<string>;
new_code_sent_at: Nullish<Date>;
new_code_expires_at: Nullish<Date>;
status: string;
created_at: Date;
updated_at: Date;
}
export interface EmailChangeTokenRow {
token_: string;
user_id: UserID;
new_email: string;
expires_at: Date;
created_at: Date;
}
export const AUTH_SESSION_COLUMNS = [
'user_id',
'session_id_hash',
'created_at',
'approx_last_used_at',
'client_ip',
'client_os',
'client_platform',
'client_country',
'client_location',
'version',
] as const satisfies ReadonlyArray<keyof AuthSessionRow>;
export const MFA_BACKUP_CODE_COLUMNS = ['user_id', 'code', 'consumed'] as const satisfies ReadonlyArray<
keyof MfaBackupCodeRow
>;
export const EMAIL_VERIFICATION_TOKEN_COLUMNS = ['token_', 'user_id', 'email'] as const satisfies ReadonlyArray<
keyof EmailVerificationTokenRow
>;
export const PASSWORD_RESET_TOKEN_COLUMNS = ['token_', 'user_id', 'email'] as const satisfies ReadonlyArray<
keyof PasswordResetTokenRow
>;
export const EMAIL_REVERT_TOKEN_COLUMNS = ['token_', 'user_id', 'email'] as const satisfies ReadonlyArray<
keyof EmailRevertTokenRow
>;
export const IP_AUTHORIZATION_TOKEN_COLUMNS = ['token_', 'user_id', 'email'] as const satisfies ReadonlyArray<
keyof IpAuthorizationTokenRow
>;
export const AUTHORIZED_IP_COLUMNS = ['user_id', 'ip'] as const satisfies ReadonlyArray<keyof AuthorizedIpRow>;
export const WEBAUTHN_CREDENTIAL_COLUMNS = [
'user_id',
'credential_id',
'public_key',
'counter',
'transports',
'name',
'created_at',
'last_used_at',
'version',
] as const satisfies ReadonlyArray<keyof WebAuthnCredentialRow>;
export const PHONE_TOKEN_COLUMNS = ['token_', 'phone', 'user_id'] as const satisfies ReadonlyArray<keyof PhoneTokenRow>;
export const EMAIL_CHANGE_TICKET_COLUMNS = [
'ticket',
'user_id',
'require_original',
'original_email',
'original_verified',
'original_proof',
'original_code',
'original_code_sent_at',
'original_code_expires_at',
'new_email',
'new_code',
'new_code_sent_at',
'new_code_expires_at',
'status',
'created_at',
'updated_at',
] as const satisfies ReadonlyArray<keyof EmailChangeTicketRow>;
export const EMAIL_CHANGE_TOKEN_COLUMNS = [
'token_',
'user_id',
'new_email',
'expires_at',
'created_at',
] as const satisfies ReadonlyArray<keyof EmailChangeTokenRow>;
export const BETA_CODE_COLUMNS = [
'creator_id',
'code',
'created_at',
'redeemer_id',
'redeemed_at',
'version',
] as const satisfies ReadonlyArray<keyof BetaCodeRow>;
export const BETA_CODE_BY_CODE_COLUMNS = ['code', 'creator_id'] as const satisfies ReadonlyArray<
keyof BetaCodeByCodeRow
>;

View File

@@ -0,0 +1,177 @@
/*
* 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 {ChannelID, GuildID, InviteCode, MessageID, RoleID, UserID, WebhookID, WebhookToken} from '~/BrandedTypes';
type Nullish<T> = T | null;
export interface PermissionOverwrite {
type: number;
allow_: Nullish<bigint>;
deny_: Nullish<bigint>;
}
export interface ChannelRow {
channel_id: ChannelID;
guild_id: Nullish<GuildID>;
type: number;
name: Nullish<string>;
topic: Nullish<string>;
icon_hash: Nullish<string>;
url: Nullish<string>;
parent_id: Nullish<ChannelID>;
position: Nullish<number>;
owner_id: Nullish<UserID>;
recipient_ids: Nullish<Set<UserID>>;
nsfw: Nullish<boolean>;
rate_limit_per_user: Nullish<number>;
bitrate: Nullish<number>;
user_limit: Nullish<number>;
rtc_region: Nullish<string>;
last_message_id: Nullish<MessageID>;
last_pin_timestamp: Nullish<Date>;
permission_overwrites: Nullish<Map<RoleID | UserID, PermissionOverwrite>>;
nicks: Nullish<Map<string, string>>;
soft_deleted: boolean;
indexed_at: Nullish<Date>;
version: number;
}
export interface InviteRow {
code: InviteCode;
type: number;
guild_id: Nullish<GuildID>;
channel_id: Nullish<ChannelID>;
inviter_id: Nullish<UserID>;
created_at: Date;
uses: number;
max_uses: number;
max_age: number;
temporary: Nullish<boolean>;
version: number;
}
export interface WebhookRow {
webhook_id: WebhookID;
webhook_token: WebhookToken;
type: number;
guild_id: Nullish<GuildID>;
channel_id: Nullish<ChannelID>;
creator_id: Nullish<UserID>;
name: string;
avatar_hash: Nullish<string>;
version: number;
}
export interface PrivateChannelRow {
user_id: UserID;
channel_id: ChannelID;
is_gdm: boolean;
}
export interface DmStateRow {
hi_user_id: UserID;
lo_user_id: UserID;
channel_id: ChannelID;
}
export interface ReadStateRow {
user_id: UserID;
channel_id: ChannelID;
message_id: Nullish<MessageID>;
mention_count: number;
last_pin_timestamp: Nullish<Date>;
}
export const CHANNEL_COLUMNS = [
'channel_id',
'guild_id',
'type',
'name',
'topic',
'icon_hash',
'url',
'parent_id',
'position',
'owner_id',
'recipient_ids',
'nsfw',
'rate_limit_per_user',
'bitrate',
'user_limit',
'rtc_region',
'last_message_id',
'last_pin_timestamp',
'permission_overwrites',
'nicks',
'soft_deleted',
'indexed_at',
'version',
] as const satisfies ReadonlyArray<keyof ChannelRow>;
export interface ChannelsByGuildRow {
guild_id: GuildID;
channel_id: ChannelID;
}
export const CHANNELS_BY_GUILD_COLUMNS = ['guild_id', 'channel_id'] as const satisfies ReadonlyArray<
keyof ChannelsByGuildRow
>;
export const INVITE_COLUMNS = [
'code',
'type',
'guild_id',
'channel_id',
'inviter_id',
'created_at',
'uses',
'max_uses',
'max_age',
'temporary',
'version',
] as const satisfies ReadonlyArray<keyof InviteRow>;
export const WEBHOOK_COLUMNS = [
'webhook_id',
'webhook_token',
'type',
'guild_id',
'channel_id',
'creator_id',
'name',
'avatar_hash',
'version',
] as const satisfies ReadonlyArray<keyof WebhookRow>;
export const READ_STATE_COLUMNS = [
'user_id',
'channel_id',
'message_id',
'mention_count',
'last_pin_timestamp',
] as const satisfies ReadonlyArray<keyof ReadStateRow>;
export const PRIVATE_CHANNEL_COLUMNS = ['user_id', 'channel_id', 'is_gdm'] as const satisfies ReadonlyArray<
keyof PrivateChannelRow
>;
export const DM_STATE_COLUMNS = ['hi_user_id', 'lo_user_id', 'channel_id'] as const satisfies ReadonlyArray<
keyof DmStateRow
>;

View File

@@ -0,0 +1,21 @@
/*
* 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 PartialRowUpdate<TRow, TExtraFields = Record<string, unknown>> = Partial<Pick<TRow, keyof TRow>> &
TExtraFields;

View File

@@ -0,0 +1,284 @@
/*
* 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 {ChannelID, EmojiID, GuildID, InviteCode, RoleID, StickerID, UserID, VanityURLCode} from '~/BrandedTypes';
import type {AuditLogActionType} from '~/constants/AuditLogActionType';
import type {GuildSplashCardAlignmentValue} from '~/constants/Guild';
type Nullish<T> = T | null;
export interface GuildRow {
guild_id: GuildID;
owner_id: UserID;
name: string;
vanity_url_code: Nullish<VanityURLCode>;
icon_hash: Nullish<string>;
banner_hash: Nullish<string>;
banner_width: Nullish<number>;
banner_height: Nullish<number>;
splash_hash: Nullish<string>;
splash_width: Nullish<number>;
splash_height: Nullish<number>;
splash_card_alignment: Nullish<GuildSplashCardAlignmentValue>;
embed_splash_hash: Nullish<string>;
embed_splash_width: Nullish<number>;
embed_splash_height: Nullish<number>;
features: Nullish<Set<string>>;
verification_level: number;
mfa_level: number;
nsfw_level: number;
explicit_content_filter: number;
default_message_notifications: number;
system_channel_id: Nullish<ChannelID>;
system_channel_flags: number;
rules_channel_id: Nullish<ChannelID>;
afk_channel_id: Nullish<ChannelID>;
afk_timeout: number;
disabled_operations: number;
member_count: number;
audit_logs_indexed_at: Nullish<Date>;
version: number;
}
export const GUILD_COLUMNS = [
'guild_id',
'owner_id',
'name',
'vanity_url_code',
'icon_hash',
'banner_hash',
'banner_width',
'banner_height',
'splash_hash',
'splash_width',
'splash_height',
'splash_card_alignment',
'embed_splash_hash',
'embed_splash_width',
'embed_splash_height',
'features',
'verification_level',
'mfa_level',
'nsfw_level',
'explicit_content_filter',
'default_message_notifications',
'system_channel_id',
'system_channel_flags',
'rules_channel_id',
'afk_channel_id',
'afk_timeout',
'disabled_operations',
'member_count',
'audit_logs_indexed_at',
'version',
] as const satisfies ReadonlyArray<keyof GuildRow>;
export interface GuildMemberRow {
guild_id: GuildID;
user_id: UserID;
joined_at: Date;
nick: Nullish<string>;
avatar_hash: Nullish<string>;
banner_hash: Nullish<string>;
bio: Nullish<string>;
pronouns: Nullish<string>;
accent_color: Nullish<number>;
join_source_type: Nullish<number>;
source_invite_code: Nullish<InviteCode>;
inviter_id: Nullish<UserID>;
deaf: boolean;
mute: boolean;
communication_disabled_until: Nullish<Date>;
role_ids: Nullish<Set<RoleID>>;
is_premium_sanitized: Nullish<boolean>;
temporary: Nullish<boolean>;
profile_flags: Nullish<number>;
version: number;
}
export const GUILD_MEMBER_COLUMNS = [
'guild_id',
'user_id',
'joined_at',
'nick',
'avatar_hash',
'banner_hash',
'bio',
'pronouns',
'accent_color',
'join_source_type',
'source_invite_code',
'inviter_id',
'deaf',
'mute',
'communication_disabled_until',
'role_ids',
'is_premium_sanitized',
'temporary',
'profile_flags',
'version',
] as const satisfies ReadonlyArray<keyof GuildMemberRow>;
export interface GuildAuditLogRow {
guild_id: GuildID;
log_id: bigint;
user_id: UserID;
target_id: Nullish<string>;
action_type: AuditLogActionType;
reason: Nullish<string>;
options: Nullish<Map<string, string>>;
changes: Nullish<string>;
}
export const GUILD_AUDIT_LOG_COLUMNS = [
'guild_id',
'log_id',
'user_id',
'target_id',
'action_type',
'reason',
'options',
'changes',
] as const satisfies ReadonlyArray<keyof GuildAuditLogRow>;
export interface GuildRoleRow {
guild_id: GuildID;
role_id: RoleID;
name: string;
permissions: bigint;
position: number;
hoist_position: Nullish<number>;
color: number;
icon_hash: Nullish<string>;
unicode_emoji: Nullish<string>;
hoist: boolean;
mentionable: boolean;
version: number;
}
export const GUILD_ROLE_COLUMNS = [
'guild_id',
'role_id',
'name',
'permissions',
'position',
'hoist_position',
'color',
'icon_hash',
'unicode_emoji',
'hoist',
'mentionable',
'version',
] as const satisfies ReadonlyArray<keyof GuildRoleRow>;
export interface GuildBanRow {
guild_id: GuildID;
user_id: UserID;
moderator_id: UserID;
banned_at: Date;
expires_at: Nullish<Date>;
reason: Nullish<string>;
ip: Nullish<string>;
}
export const GUILD_BAN_COLUMNS = [
'guild_id',
'user_id',
'moderator_id',
'banned_at',
'expires_at',
'reason',
'ip',
] as const satisfies ReadonlyArray<keyof GuildBanRow>;
export interface GuildEmojiRow {
guild_id: GuildID;
emoji_id: EmojiID;
name: string;
creator_id: UserID;
animated: boolean;
version: number;
}
export const GUILD_EMOJI_COLUMNS = [
'guild_id',
'emoji_id',
'name',
'creator_id',
'animated',
'version',
] as const satisfies ReadonlyArray<keyof GuildEmojiRow>;
export const GUILD_EMOJI_BY_EMOJI_ID_COLUMNS = [
'guild_id',
'emoji_id',
'name',
'creator_id',
'animated',
] as const satisfies ReadonlyArray<keyof GuildEmojiRow>;
export interface GuildStickerRow {
guild_id: GuildID;
sticker_id: StickerID;
name: string;
description: Nullish<string>;
format_type: number;
tags: Nullish<Array<string>>;
creator_id: UserID;
version: number;
}
export const GUILD_STICKER_COLUMNS = [
'guild_id',
'sticker_id',
'name',
'description',
'format_type',
'tags',
'creator_id',
'version',
] as const satisfies ReadonlyArray<keyof GuildStickerRow>;
export const GUILD_STICKER_BY_STICKER_ID_COLUMNS = [
'guild_id',
'sticker_id',
'name',
'description',
'format_type',
'tags',
'creator_id',
] as const satisfies ReadonlyArray<keyof GuildStickerRow>;
export interface GuildMemberByUserIdRow {
user_id: UserID;
guild_id: GuildID;
}
export const GUILD_MEMBER_BY_USER_ID_COLUMNS = ['user_id', 'guild_id'] as const satisfies ReadonlyArray<
keyof GuildMemberByUserIdRow
>;
export interface GuildByOwnerIdRow {
owner_id: UserID;
guild_id: GuildID;
}
export const GUILD_BY_OWNER_ID_COLUMNS = ['owner_id', 'guild_id'] as const satisfies ReadonlyArray<
keyof GuildByOwnerIdRow
>;

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 interface InstanceConfigurationRow {
key: string;
value: string | null;
updated_at: Date | null;
}
export const INSTANCE_CONFIGURATION_COLUMNS = ['key', 'value', 'updated_at'] as const satisfies ReadonlyArray<
keyof InstanceConfigurationRow
>;

View File

@@ -0,0 +1,277 @@
/*
* 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 {
AttachmentID,
ChannelID,
EmojiID,
GuildID,
MessageID,
RoleID,
StickerID,
UserID,
WebhookID,
} from '~/BrandedTypes';
type Nullish<T> = T | null;
export interface MessageAttachment {
attachment_id: AttachmentID;
filename: string;
size: bigint;
title: Nullish<string>;
description: Nullish<string>;
width: Nullish<number>;
height: Nullish<number>;
content_type: string;
content_hash: Nullish<string>;
placeholder: Nullish<string>;
flags: number;
duration: Nullish<number>;
nsfw: Nullish<boolean>;
}
export interface MessageEmbedAuthor {
name: Nullish<string>;
url: Nullish<string>;
icon_url: Nullish<string>;
}
export interface MessageEmbedProvider {
name: Nullish<string>;
url: Nullish<string>;
}
export interface MessageEmbedFooter {
text: Nullish<string>;
icon_url: Nullish<string>;
}
export interface MessageEmbedMedia {
url: Nullish<string>;
width: Nullish<number>;
height: Nullish<number>;
description: Nullish<string>;
content_type: Nullish<string>;
content_hash: Nullish<string>;
placeholder: Nullish<string>;
flags: number;
duration: Nullish<number>;
}
export interface MessageEmbedField {
name: Nullish<string>;
value: Nullish<string>;
inline: boolean;
}
export interface MessageEmbed {
type: Nullish<string>;
title: Nullish<string>;
description: Nullish<string>;
url: Nullish<string>;
timestamp: Nullish<Date>;
color: Nullish<number>;
author: Nullish<MessageEmbedAuthor>;
provider: Nullish<MessageEmbedProvider>;
thumbnail: Nullish<MessageEmbedMedia>;
image: Nullish<MessageEmbedMedia>;
video: Nullish<MessageEmbedMedia>;
footer: Nullish<MessageEmbedFooter>;
fields: Nullish<Array<MessageEmbedField>>;
nsfw: Nullish<boolean>;
}
export interface MessageStickerItem {
sticker_id: StickerID;
name: string;
format_type: number;
}
export interface MessageReference {
channel_id: ChannelID;
message_id: MessageID;
guild_id: Nullish<GuildID>;
type: number;
}
export interface MessageSnapshot {
content: Nullish<string>;
timestamp: Date;
edited_timestamp: Nullish<Date>;
mention_users: Nullish<Set<UserID>>;
mention_roles: Nullish<Set<RoleID>>;
mention_channels: Nullish<Set<ChannelID>>;
attachments: Nullish<Array<MessageAttachment>>;
embeds: Nullish<Array<MessageEmbed>>;
sticker_items: Nullish<Array<MessageStickerItem>>;
type: number;
flags: number;
}
export interface MessageCall {
participant_ids: Nullish<Set<UserID>>;
ended_timestamp: Nullish<Date>;
}
export interface MessageRow {
channel_id: ChannelID;
bucket: number;
message_id: MessageID;
author_id: Nullish<UserID>;
type: number;
webhook_id: Nullish<WebhookID>;
webhook_name: Nullish<string>;
webhook_avatar_hash: Nullish<string>;
content: Nullish<string>;
edited_timestamp: Nullish<Date>;
pinned_timestamp: Nullish<Date>;
flags: number;
mention_everyone: boolean;
mention_users: Nullish<Set<UserID>>;
mention_roles: Nullish<Set<RoleID>>;
mention_channels: Nullish<Set<ChannelID>>;
attachments: Nullish<Array<MessageAttachment>>;
embeds: Nullish<Array<MessageEmbed>>;
sticker_items: Nullish<Array<MessageStickerItem>>;
message_reference: Nullish<MessageReference>;
message_snapshots: Nullish<Array<MessageSnapshot>>;
call: Nullish<MessageCall>;
has_reaction: Nullish<boolean>;
version: number;
}
export const MESSAGE_COLUMNS = [
'channel_id',
'bucket',
'message_id',
'author_id',
'type',
'webhook_id',
'webhook_name',
'webhook_avatar_hash',
'content',
'edited_timestamp',
'pinned_timestamp',
'flags',
'mention_everyone',
'mention_users',
'mention_roles',
'mention_channels',
'attachments',
'embeds',
'sticker_items',
'message_reference',
'message_snapshots',
'call',
'has_reaction',
'version',
] as const satisfies ReadonlyArray<keyof MessageRow>;
export interface ChannelPinRow {
channel_id: ChannelID;
message_id: MessageID;
pinned_timestamp: Date;
}
export interface MessageReactionRow {
channel_id: ChannelID;
bucket: number;
message_id: MessageID;
user_id: UserID;
emoji_id: EmojiID;
emoji_name: string;
emoji_animated: boolean;
}
export interface AttachmentLookupRow {
channel_id: ChannelID;
attachment_id: AttachmentID;
filename: string;
message_id: MessageID;
}
export const ATTACHMENT_LOOKUP_COLUMNS = [
'channel_id',
'attachment_id',
'filename',
'message_id',
] as const satisfies ReadonlyArray<keyof AttachmentLookupRow>;
export const CHANNEL_PIN_COLUMNS = ['channel_id', 'message_id', 'pinned_timestamp'] as const satisfies ReadonlyArray<
keyof ChannelPinRow
>;
export const MESSAGE_REACTION_COLUMNS = [
'channel_id',
'bucket',
'message_id',
'user_id',
'emoji_id',
'emoji_name',
'emoji_animated',
] as const satisfies ReadonlyArray<keyof MessageReactionRow>;
export interface MessageByAuthorRow {
author_id: UserID;
channel_id: ChannelID;
message_id: MessageID;
}
export const MESSAGE_BY_AUTHOR_COLUMNS = ['author_id', 'channel_id', 'message_id'] as const satisfies ReadonlyArray<
keyof MessageByAuthorRow
>;
export interface ChannelStateRow {
channel_id: ChannelID;
created_bucket: number;
has_messages: boolean;
last_message_id: Nullish<MessageID>;
last_message_bucket: Nullish<number>;
updated_at: Date;
}
export const CHANNEL_STATE_COLUMNS = [
'channel_id',
'created_bucket',
'has_messages',
'last_message_id',
'last_message_bucket',
'updated_at',
] as const satisfies ReadonlyArray<keyof ChannelStateRow>;
export interface ChannelMessageBucketRow {
channel_id: ChannelID;
bucket: number;
updated_at: Date;
}
export const CHANNEL_MESSAGE_BUCKET_COLUMNS = ['channel_id', 'bucket', 'updated_at'] as const satisfies ReadonlyArray<
keyof ChannelMessageBucketRow
>;
export interface ChannelEmptyBucketRow {
channel_id: ChannelID;
bucket: number;
updated_at: Date;
}
export const CHANNEL_EMPTY_BUCKET_COLUMNS = ['channel_id', 'bucket', 'updated_at'] as const satisfies ReadonlyArray<
keyof ChannelEmptyBucketRow
>;

View File

@@ -0,0 +1,117 @@
/*
* 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 {ApplicationID, UserID} from '~/BrandedTypes';
export interface ApplicationRow {
application_id: ApplicationID;
owner_user_id: UserID;
name: string;
bot_user_id: UserID | null;
bot_is_public: boolean | null;
oauth2_redirect_uris: Set<string>;
client_secret_hash: string | null;
bot_token_hash: string | null;
bot_token_preview: string | null;
bot_token_created_at: Date | null;
client_secret_created_at: Date | null;
version?: number | null;
}
export interface ApplicationByOwnerRow {
owner_user_id: UserID;
application_id: ApplicationID;
}
export interface OAuth2AuthorizationCodeRow {
code: string;
application_id: ApplicationID;
user_id: UserID;
redirect_uri: string;
scope: Set<string>;
nonce: string | null;
created_at: Date;
}
export interface OAuth2AccessTokenRow {
token_: string;
application_id: ApplicationID;
user_id: UserID | null;
scope: Set<string>;
created_at: Date;
}
export interface OAuth2AccessTokenByUserRow {
user_id: UserID;
token_: string;
}
export interface OAuth2RefreshTokenRow {
token_: string;
application_id: ApplicationID;
user_id: UserID;
scope: Set<string>;
created_at: Date;
}
export interface OAuth2RefreshTokenByUserRow {
user_id: UserID;
token_: string;
}
export const APPLICATION_COLUMNS = [
'application_id',
'owner_user_id',
'name',
'bot_user_id',
'bot_is_public',
'oauth2_redirect_uris',
'client_secret_hash',
'bot_token_hash',
'bot_token_preview',
'bot_token_created_at',
'client_secret_created_at',
'version',
] as const satisfies ReadonlyArray<keyof ApplicationRow>;
export const OAUTH2_AUTHORIZATION_CODE_COLUMNS = [
'code',
'application_id',
'user_id',
'redirect_uri',
'scope',
'nonce',
'created_at',
] as const satisfies ReadonlyArray<keyof OAuth2AuthorizationCodeRow>;
export const OAUTH2_ACCESS_TOKEN_COLUMNS = [
'token_',
'application_id',
'user_id',
'scope',
'created_at',
] as const satisfies ReadonlyArray<keyof OAuth2AccessTokenRow>;
export const OAUTH2_REFRESH_TOKEN_COLUMNS = [
'token_',
'application_id',
'user_id',
'scope',
'created_at',
] as const satisfies ReadonlyArray<keyof OAuth2RefreshTokenRow>;

View File

@@ -0,0 +1,145 @@
/*
* 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 {UserID} from '~/BrandedTypes';
type Nullish<T> = T | null;
export interface GiftCodeRow {
code: string;
duration_months: number;
created_at: Date;
created_by_user_id: UserID;
redeemed_at: Nullish<Date>;
redeemed_by_user_id: Nullish<UserID>;
stripe_payment_intent_id: Nullish<string>;
visionary_sequence_number: Nullish<number>;
checkout_session_id: Nullish<string>;
version: number;
}
export interface PaymentRow {
checkout_session_id: string;
user_id: UserID;
stripe_customer_id: Nullish<string>;
payment_intent_id: Nullish<string>;
subscription_id: Nullish<string>;
invoice_id: Nullish<string>;
price_id: Nullish<string>;
product_type: Nullish<string>;
amount_cents: number;
currency: string;
status: string;
is_gift: boolean;
gift_code: Nullish<string>;
created_at: Date;
completed_at: Nullish<Date>;
version: number;
}
export interface PaymentBySubscriptionRow {
subscription_id: string;
checkout_session_id: string;
user_id: UserID;
price_id: string;
product_type: string;
}
export interface VisionarySlotRow {
slot_index: number;
user_id: UserID | null;
}
export const PAYMENT_COLUMNS = [
'checkout_session_id',
'user_id',
'stripe_customer_id',
'payment_intent_id',
'subscription_id',
'invoice_id',
'price_id',
'product_type',
'amount_cents',
'currency',
'status',
'is_gift',
'gift_code',
'created_at',
'completed_at',
'version',
] as const;
export const PAYMENT_BY_SUBSCRIPTION_COLUMNS = [
'subscription_id',
'checkout_session_id',
'user_id',
'price_id',
'product_type',
] as const;
export const PAYMENT_BY_PAYMENT_INTENT_COLUMNS = ['payment_intent_id', 'checkout_session_id'] as const;
export const PAYMENT_BY_USER_COLUMNS = ['user_id', 'created_at', 'checkout_session_id'] as const;
export const GIFT_CODE_COLUMNS = [
'code',
'duration_months',
'created_at',
'created_by_user_id',
'redeemed_at',
'redeemed_by_user_id',
'stripe_payment_intent_id',
'visionary_sequence_number',
'checkout_session_id',
'version',
] as const;
export const GIFT_CODE_BY_CREATOR_COLUMNS = ['created_by_user_id', 'code'] as const;
export const GIFT_CODE_BY_PAYMENT_INTENT_COLUMNS = ['stripe_payment_intent_id', 'code'] as const;
export const GIFT_CODE_BY_REDEEMER_COLUMNS = ['redeemed_by_user_id', 'code'] as const;
export const VISIONARY_SLOT_COLUMNS = ['slot_index', 'user_id'] as const;
export interface PaymentByPaymentIntentRow {
payment_intent_id: string;
checkout_session_id: string;
}
export interface PaymentByUserRow {
user_id: UserID;
created_at: Date;
checkout_session_id: string;
}
export interface GiftCodeByCreatorRow {
created_by_user_id: UserID;
code: string;
}
export interface GiftCodeByPaymentIntentRow {
stripe_payment_intent_id: string;
code: string;
}
export interface GiftCodeByRedeemerRow {
redeemed_by_user_id: UserID;
code: string;
}

View File

@@ -0,0 +1,129 @@
/*
* 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 {MessageAttachment, MessageEmbed, MessageStickerItem} from './MessageTypes';
export type {MessageAttachment};
type MentionCollection = ReadonlyArray<bigint> | Set<bigint> | null | undefined;
export interface IARMessageContextRow {
message_id: bigint;
channel_id: bigint | null;
author_id: bigint;
author_username: string;
author_discriminator: number;
author_avatar_hash: string | null;
content: string | null;
timestamp: Date;
edited_timestamp: Date | null;
type: number;
flags: number;
mention_everyone: boolean;
mention_users: MentionCollection;
mention_roles: MentionCollection;
mention_channels: MentionCollection;
attachments: Array<MessageAttachment> | null;
embeds: Array<MessageEmbed> | null;
sticker_items: Array<MessageStickerItem> | null;
}
export interface IARSubmissionRow {
report_id: bigint;
reporter_id: bigint | null;
reporter_email: string | null;
reporter_full_legal_name: string | null;
reporter_country_of_residence: string | null;
reported_at: Date;
status: number;
report_type: number;
category: string;
additional_info: string | null;
reported_user_id: bigint | null;
reported_user_avatar_hash: string | null;
reported_guild_id: bigint | null;
reported_guild_name: string | null;
reported_guild_icon_hash: string | null;
reported_message_id: bigint | null;
reported_channel_id: bigint | null;
reported_channel_name: string | null;
message_context: Array<IARMessageContextRow> | null;
guild_context_id: bigint | null;
resolved_at: Date | null;
resolved_by_admin_id: bigint | null;
public_comment: string | null;
audit_log_reason: string | null;
reported_guild_invite_code: string | null;
}
export interface DSAReportEmailVerificationRow {
email_lower: string;
code_hash: string;
expires_at: Date;
last_sent_at: Date;
}
export interface DSAReportTicketRow {
ticket: string;
email_lower: string;
expires_at: Date;
created_at: Date;
}
export const IAR_SUBMISSION_COLUMNS = [
'report_id',
'reporter_id',
'reporter_email',
'reporter_full_legal_name',
'reporter_country_of_residence',
'reported_at',
'status',
'report_type',
'category',
'additional_info',
'reported_user_id',
'reported_user_avatar_hash',
'reported_guild_id',
'reported_guild_name',
'reported_guild_icon_hash',
'reported_message_id',
'reported_channel_id',
'reported_channel_name',
'message_context',
'guild_context_id',
'resolved_at',
'resolved_by_admin_id',
'public_comment',
'audit_log_reason',
'reported_guild_invite_code',
] as const satisfies ReadonlyArray<keyof IARSubmissionRow>;
export const DSA_REPORT_EMAIL_VERIFICATION_COLUMNS = [
'email_lower',
'code_hash',
'expires_at',
'last_sent_at',
] as const satisfies ReadonlyArray<keyof DSAReportEmailVerificationRow>;
export const DSA_REPORT_TICKET_COLUMNS = [
'ticket',
'email_lower',
'expires_at',
'created_at',
] as const satisfies ReadonlyArray<keyof DSAReportTicketRow>;

View File

@@ -0,0 +1,594 @@
/*
* 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 {types} from 'cassandra-driver';
import type {AttachmentID, ChannelID, EmojiID, GuildID, MemeID, MessageID, UserID} from '~/BrandedTypes';
type Nullish<T> = T | null;
export interface UserRow {
user_id: UserID;
username: string;
discriminator: number;
global_name: Nullish<string>;
bot: Nullish<boolean>;
system: Nullish<boolean>;
email: Nullish<string>;
email_verified: Nullish<boolean>;
email_bounced: Nullish<boolean>;
phone: Nullish<string>;
password_hash: Nullish<string>;
password_last_changed_at: Nullish<Date>;
totp_secret: Nullish<string>;
authenticator_types: Nullish<Set<number>>;
avatar_hash: Nullish<string>;
avatar_color: Nullish<number>;
banner_hash: Nullish<string>;
banner_color: Nullish<number>;
bio: Nullish<string>;
pronouns: Nullish<string>;
accent_color: Nullish<number>;
date_of_birth: Nullish<types.LocalDate>;
locale: Nullish<string>;
flags: Nullish<bigint>;
premium_type: Nullish<number>;
premium_since: Nullish<Date>;
premium_until: Nullish<Date>;
premium_will_cancel: Nullish<boolean>;
premium_billing_cycle: Nullish<string>;
premium_lifetime_sequence: Nullish<number>;
stripe_subscription_id: Nullish<string>;
stripe_customer_id: Nullish<string>;
has_ever_purchased: Nullish<boolean>;
suspicious_activity_flags: Nullish<number>;
terms_agreed_at: Nullish<Date>;
privacy_agreed_at: Nullish<Date>;
last_active_at: Nullish<Date>;
last_active_ip: Nullish<string>;
temp_banned_until: Nullish<Date>;
pending_bulk_message_deletion_at: Nullish<Date>;
pending_bulk_message_deletion_channel_count: Nullish<number>;
pending_bulk_message_deletion_message_count: Nullish<number>;
pending_deletion_at: Nullish<Date>;
deletion_reason_code: Nullish<number>;
deletion_public_reason: Nullish<string>;
deletion_audit_log_reason: Nullish<string>;
acls: Nullish<Set<string>>;
first_refund_at: Nullish<Date>;
beta_code_allowance: Nullish<number>;
beta_code_last_reset_at: Nullish<Date>;
gift_inventory_server_seq: Nullish<number>;
gift_inventory_client_seq: Nullish<number>;
premium_onboarding_dismissed_at: Nullish<Date>;
version: number;
}
export const USER_COLUMNS = [
'user_id',
'username',
'discriminator',
'global_name',
'bot',
'system',
'email',
'email_verified',
'email_bounced',
'phone',
'password_hash',
'password_last_changed_at',
'totp_secret',
'authenticator_types',
'avatar_hash',
'avatar_color',
'banner_hash',
'banner_color',
'bio',
'pronouns',
'accent_color',
'date_of_birth',
'locale',
'flags',
'premium_type',
'premium_since',
'premium_until',
'premium_will_cancel',
'premium_billing_cycle',
'premium_lifetime_sequence',
'stripe_subscription_id',
'stripe_customer_id',
'has_ever_purchased',
'suspicious_activity_flags',
'terms_agreed_at',
'privacy_agreed_at',
'last_active_at',
'last_active_ip',
'temp_banned_until',
'pending_bulk_message_deletion_at',
'pending_bulk_message_deletion_channel_count',
'pending_bulk_message_deletion_message_count',
'pending_deletion_at',
'deletion_reason_code',
'deletion_public_reason',
'deletion_audit_log_reason',
'acls',
'first_refund_at',
'beta_code_allowance',
'beta_code_last_reset_at',
'gift_inventory_server_seq',
'gift_inventory_client_seq',
'premium_onboarding_dismissed_at',
'version',
] as const satisfies ReadonlyArray<keyof UserRow>;
export const EMPTY_USER_ROW: UserRow = {
user_id: -1n as UserID,
username: '',
discriminator: 0,
global_name: null,
bot: null,
system: null,
email: null,
email_verified: null,
email_bounced: null,
phone: null,
password_hash: null,
password_last_changed_at: null,
totp_secret: null,
authenticator_types: null,
avatar_hash: null,
avatar_color: null,
banner_hash: null,
banner_color: null,
bio: null,
pronouns: null,
accent_color: null,
date_of_birth: null,
locale: null,
flags: null,
premium_type: null,
premium_since: null,
premium_until: null,
premium_will_cancel: null,
premium_billing_cycle: null,
premium_lifetime_sequence: null,
stripe_subscription_id: null,
stripe_customer_id: null,
has_ever_purchased: null,
suspicious_activity_flags: null,
terms_agreed_at: null,
privacy_agreed_at: null,
last_active_at: null,
last_active_ip: null,
temp_banned_until: null,
pending_bulk_message_deletion_at: null,
pending_bulk_message_deletion_channel_count: null,
pending_bulk_message_deletion_message_count: null,
pending_deletion_at: null,
deletion_reason_code: null,
deletion_public_reason: null,
deletion_audit_log_reason: null,
acls: null,
first_refund_at: null,
beta_code_allowance: null,
beta_code_last_reset_at: null,
gift_inventory_server_seq: null,
gift_inventory_client_seq: null,
premium_onboarding_dismissed_at: null,
version: 1,
};
export interface CustomStatus {
text: Nullish<string>;
emoji_id: Nullish<EmojiID>;
emoji_name: Nullish<string>;
emoji_animated: boolean;
expires_at: Nullish<Date>;
}
export interface GuildFolder {
folder_id: number;
name: Nullish<string>;
color: Nullish<number>;
guild_ids: Nullish<Array<GuildID>>;
}
export interface UserSettingsRow {
user_id: UserID;
locale: string;
theme: string;
status: string;
status_resets_at: Nullish<Date>;
status_resets_to: Nullish<string>;
custom_status: Nullish<CustomStatus>;
developer_mode: boolean;
message_display_compact: boolean;
animate_emoji: boolean;
animate_stickers: number;
gif_auto_play: boolean;
render_embeds: boolean;
render_reactions: boolean;
render_spoilers: number;
inline_attachment_media: boolean;
inline_embed_media: boolean;
explicit_content_filter: number;
friend_source_flags: number;
incoming_call_flags: number;
group_dm_add_permission_flags: number;
default_guilds_restricted: boolean;
restricted_guilds: Nullish<Set<GuildID>>;
guild_positions: Nullish<Array<GuildID>>;
guild_folders: Nullish<Array<GuildFolder>>;
afk_timeout: Nullish<number>;
time_format: Nullish<number>;
version: number;
}
export interface RelationshipRow {
source_user_id: UserID;
target_user_id: UserID;
type: number;
nickname: Nullish<string>;
since: Nullish<Date>;
version: number;
}
export interface NoteRow {
source_user_id: UserID;
target_user_id: UserID;
note: string;
version: number;
}
export interface MuteConfig {
end_time: Nullish<Date>;
selected_time_window: Nullish<number>;
}
export interface ChannelOverride {
collapsed: boolean;
message_notifications: Nullish<number>;
muted: boolean;
mute_config: Nullish<MuteConfig>;
}
export interface UserGuildSettingsRow {
user_id: UserID;
guild_id: GuildID;
message_notifications: Nullish<number>;
muted: boolean;
mute_config: Nullish<MuteConfig>;
mobile_push: boolean;
suppress_everyone: boolean;
suppress_roles: boolean;
hide_muted_channels: boolean;
channel_overrides: Nullish<Map<ChannelID, ChannelOverride>>;
version: number;
}
export interface ExpressionPackRow {
pack_id: GuildID;
pack_type: string;
creator_id: UserID;
name: string;
description: Nullish<string>;
created_at: Date;
updated_at: Date;
version: number;
}
export interface PackInstallationRow {
user_id: UserID;
pack_id: GuildID;
pack_type: string;
installed_at: Date;
}
export interface SavedMessageRow {
user_id: UserID;
channel_id: ChannelID;
message_id: MessageID;
saved_at: Date;
}
export const SAVED_MESSAGE_COLUMNS = [
'user_id',
'channel_id',
'message_id',
'saved_at',
] as const satisfies ReadonlyArray<keyof SavedMessageRow>;
export interface ScheduledMessageRow {
user_id: UserID;
scheduled_message_id: MessageID;
channel_id: ChannelID;
payload: string;
scheduled_at: Date;
scheduled_local_at: string;
timezone: string;
status: string;
status_reason: string | null;
created_at: Date;
invalidated_at: Date | null;
}
export const SCHEDULED_MESSAGE_COLUMNS = [
'user_id',
'scheduled_message_id',
'channel_id',
'payload',
'scheduled_at',
'scheduled_local_at',
'timezone',
'status',
'status_reason',
'created_at',
'invalidated_at',
] as const satisfies ReadonlyArray<keyof ScheduledMessageRow>;
export interface FavoriteMemeRow {
user_id: UserID;
meme_id: MemeID;
name: string;
alt_text: Nullish<string>;
tags: Nullish<Array<string>>;
attachment_id: AttachmentID;
filename: string;
content_type: string;
content_hash: Nullish<string>;
size: bigint;
width: Nullish<number>;
height: Nullish<number>;
duration: Nullish<number>;
is_gifv: boolean;
tenor_id_str: Nullish<string>;
version: number;
}
export const FAVORITE_MEME_COLUMNS = [
'user_id',
'meme_id',
'name',
'alt_text',
'tags',
'attachment_id',
'filename',
'content_type',
'content_hash',
'size',
'width',
'height',
'duration',
'is_gifv',
'tenor_id_str',
'version',
] as const satisfies ReadonlyArray<keyof FavoriteMemeRow>;
export interface RecentMentionRow {
user_id: UserID;
channel_id: ChannelID;
message_id: MessageID;
guild_id: GuildID;
is_everyone: boolean;
is_role: boolean;
}
export const RECENT_MENTION_COLUMNS = [
'user_id',
'channel_id',
'message_id',
'guild_id',
'is_everyone',
'is_role',
] as const satisfies ReadonlyArray<keyof RecentMentionRow>;
export interface UserHarvestRow {
user_id: UserID;
harvest_id: bigint;
requested_at: Date;
started_at: Nullish<Date>;
completed_at: Nullish<Date>;
failed_at: Nullish<Date>;
storage_key: Nullish<string>;
file_size: Nullish<bigint>;
progress_percent: number;
progress_step: Nullish<string>;
error_message: Nullish<string>;
download_url_expires_at: Nullish<Date>;
}
export const USER_HARVEST_COLUMNS = [
'user_id',
'harvest_id',
'requested_at',
'started_at',
'completed_at',
'failed_at',
'storage_key',
'file_size',
'progress_percent',
'progress_step',
'error_message',
'download_url_expires_at',
] as const satisfies ReadonlyArray<keyof UserHarvestRow>;
export interface PushSubscriptionRow {
user_id: UserID;
subscription_id: string;
endpoint: string;
p256dh_key: string;
auth_key: string;
user_agent: Nullish<string>;
}
export const PUSH_SUBSCRIPTION_COLUMNS = [
'user_id',
'subscription_id',
'endpoint',
'p256dh_key',
'auth_key',
'user_agent',
] as const satisfies ReadonlyArray<keyof PushSubscriptionRow>;
export interface UserContactChangeLogRow {
user_id: UserID;
event_id: types.TimeUuid;
field: string;
old_value: Nullish<string>;
new_value: Nullish<string>;
reason: string;
actor_user_id: Nullish<UserID>;
event_at: Date;
}
export const USER_SETTINGS_COLUMNS = [
'user_id',
'locale',
'theme',
'status',
'status_resets_at',
'status_resets_to',
'custom_status',
'developer_mode',
'message_display_compact',
'animate_emoji',
'animate_stickers',
'gif_auto_play',
'render_embeds',
'render_reactions',
'render_spoilers',
'inline_attachment_media',
'inline_embed_media',
'explicit_content_filter',
'friend_source_flags',
'incoming_call_flags',
'group_dm_add_permission_flags',
'default_guilds_restricted',
'restricted_guilds',
'guild_positions',
'guild_folders',
'afk_timeout',
'time_format',
'version',
] as const satisfies ReadonlyArray<keyof UserSettingsRow>;
export const EXPRESSION_PACK_COLUMNS = [
'pack_id',
'pack_type',
'creator_id',
'name',
'description',
'created_at',
'updated_at',
'version',
] as const satisfies ReadonlyArray<keyof ExpressionPackRow>;
export const USER_GUILD_SETTINGS_COLUMNS = [
'user_id',
'guild_id',
'message_notifications',
'muted',
'mute_config',
'mobile_push',
'suppress_everyone',
'suppress_roles',
'hide_muted_channels',
'channel_overrides',
'version',
] as const satisfies ReadonlyArray<keyof UserGuildSettingsRow>;
export const RELATIONSHIP_COLUMNS = [
'source_user_id',
'target_user_id',
'type',
'nickname',
'since',
'version',
] as const satisfies ReadonlyArray<keyof RelationshipRow>;
export const NOTE_COLUMNS = ['source_user_id', 'target_user_id', 'note', 'version'] as const satisfies ReadonlyArray<
keyof NoteRow
>;
export const USER_CONTACT_CHANGE_LOG_COLUMNS = [
'user_id',
'event_id',
'field',
'old_value',
'new_value',
'reason',
'actor_user_id',
'event_at',
] as const satisfies ReadonlyArray<keyof UserContactChangeLogRow>;
export interface UserByUsernameRow {
username: string;
discriminator: number;
user_id: UserID;
}
export interface UserByEmailRow {
email_lower: string;
user_id: UserID;
}
export interface UserByPhoneRow {
phone: string;
user_id: UserID;
}
export interface UserByStripeCustomerIdRow {
stripe_customer_id: string;
user_id: UserID;
}
export interface UserByStripeSubscriptionIdRow {
stripe_subscription_id: string;
user_id: UserID;
}
export const USER_BY_USERNAME_COLUMNS = ['username', 'discriminator', 'user_id'] as const satisfies ReadonlyArray<
keyof UserByUsernameRow
>;
export const USER_BY_EMAIL_COLUMNS = ['email_lower', 'user_id'] as const satisfies ReadonlyArray<keyof UserByEmailRow>;
export const USER_BY_PHONE_COLUMNS = ['phone', 'user_id'] as const satisfies ReadonlyArray<keyof UserByPhoneRow>;
export const USER_BY_STRIPE_CUSTOMER_ID_COLUMNS = ['stripe_customer_id', 'user_id'] as const satisfies ReadonlyArray<
keyof UserByStripeCustomerIdRow
>;
export const USER_BY_STRIPE_SUBSCRIPTION_ID_COLUMNS = [
'stripe_subscription_id',
'user_id',
] as const satisfies ReadonlyArray<keyof UserByStripeSubscriptionIdRow>;
export interface UsersPendingDeletionRow {
deletion_date: string;
pending_deletion_at: Date;
user_id: UserID;
deletion_reason_code: number;
}
export const USERS_PENDING_DELETION_COLUMNS = [
'deletion_date',
'pending_deletion_at',
'user_id',
'deletion_reason_code',
] as const satisfies ReadonlyArray<keyof UsersPendingDeletionRow>;

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 interface VoiceRegionRow {
id: string;
name: string;
emoji: string;
latitude: number;
longitude: number;
is_default: boolean | null;
vip_only: boolean | null;
required_guild_features: Set<string> | null;
allowed_guild_ids: Set<bigint> | null;
allowed_user_ids: Set<bigint> | null;
created_at: Date | null;
updated_at: Date | null;
}
export const VOICE_REGION_COLUMNS = [
'id',
'name',
'emoji',
'latitude',
'longitude',
'is_default',
'vip_only',
'required_guild_features',
'allowed_guild_ids',
'allowed_user_ids',
'created_at',
'updated_at',
] as const satisfies ReadonlyArray<keyof VoiceRegionRow>;
export interface VoiceServerRow {
region_id: string;
server_id: string;
endpoint: string;
api_key: string;
api_secret: string;
is_active: boolean | null;
vip_only: boolean | null;
required_guild_features: Set<string> | null;
allowed_guild_ids: Set<bigint> | null;
allowed_user_ids: Set<bigint> | null;
created_at: Date | null;
updated_at: Date | null;
}
export const VOICE_SERVER_COLUMNS = [
'region_id',
'server_id',
'endpoint',
'api_key',
'api_secret',
'is_active',
'vip_only',
'required_guild_features',
'allowed_guild_ids',
'allowed_user_ids',
'created_at',
'updated_at',
] as const satisfies ReadonlyArray<keyof VoiceServerRow>;