mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-05-26 05:24:03 -05:00
1453 lines
38 KiB
TypeScript
1453 lines
38 KiB
TypeScript
import type {
|
||
ColumnType,
|
||
GeneratedAlways,
|
||
Insertable,
|
||
JSONColumnType,
|
||
Selectable,
|
||
Updateable,
|
||
} from "kysely";
|
||
import type { AssociationVisibility } from "~/features/associations/associations-types";
|
||
import type { tags } from "~/features/calendar/calendar-constants";
|
||
import type { CalendarFilters } from "~/features/calendar/calendar-types";
|
||
import type { TieredSkill } from "~/features/mmr/tiered.server";
|
||
import type { Notification as NotificationValue } from "~/features/notifications/notifications-types";
|
||
import type { ScrimFilters } from "~/features/scrims/scrims-types";
|
||
import type { TEAM_MEMBER_ROLES } from "~/features/team/team-constants";
|
||
import type { TournamentTierNumber } from "~/features/tournament/core/tiering";
|
||
import type * as PickBan from "~/features/tournament-bracket/core/PickBan";
|
||
import type * as Progression from "~/features/tournament-bracket/core/Progression";
|
||
import type { StoredWidget } from "~/features/user-page/core/widgets/types";
|
||
import type { ParticipantResult } from "~/modules/brackets-model";
|
||
import type {
|
||
Ability,
|
||
BuildAbilitiesTuple,
|
||
MainWeaponId,
|
||
ModeShort,
|
||
StageId,
|
||
} from "~/modules/in-game-lists/types";
|
||
import type { JSONColumnTypeNullable } from "~/utils/kysely.server";
|
||
|
||
type Generated<T> =
|
||
T extends ColumnType<infer S, infer I, infer U>
|
||
? ColumnType<S, I | undefined, U>
|
||
: ColumnType<T, T | undefined, T>;
|
||
|
||
export type MemberRole = (typeof TEAM_MEMBER_ROLES)[number];
|
||
|
||
/** In SQLite booleans are presented as 0 (false) and 1 (true) */
|
||
export type DBBoolean = number;
|
||
|
||
export const CUSTOM_THEME_VARS = [
|
||
"--_base-h",
|
||
"--_base-c-0",
|
||
"--_base-c-1",
|
||
"--_base-c-2",
|
||
"--_base-c-3",
|
||
"--_base-c-4",
|
||
"--_base-c-5",
|
||
"--_base-c-6",
|
||
"--_base-c-7",
|
||
"--_acc-h",
|
||
"--_acc-c-0",
|
||
"--_acc-c-1",
|
||
"--_acc-c-2",
|
||
"--_acc-c-3",
|
||
"--_acc-c-4",
|
||
"--_acc-c-5",
|
||
"--_second-h",
|
||
"--_second-c-0",
|
||
"--_second-c-1",
|
||
"--_second-c-2",
|
||
"--_second-c-3",
|
||
"--_second-c-4",
|
||
"--_second-c-5",
|
||
"--_chat-h",
|
||
"--_radius-box",
|
||
"--_radius-field",
|
||
"--_radius-selector",
|
||
"--_border-width",
|
||
"--_size-field",
|
||
"--_size-selector",
|
||
"--_size-spacing",
|
||
] as const;
|
||
export type CustomThemeVar = (typeof CUSTOM_THEME_VARS)[number];
|
||
export type CustomTheme = Omit<Record<CustomThemeVar, number>, "--_chat-h"> & {
|
||
"--_chat-h": number | null;
|
||
};
|
||
|
||
export interface Team {
|
||
avatarImgId: number | null;
|
||
bannerImgId: number | null;
|
||
bio: string | null;
|
||
createdAt: Generated<number>;
|
||
customUrl: string;
|
||
customTheme: JSONColumnTypeNullable<CustomTheme>;
|
||
deletedAt: number | null;
|
||
id: GeneratedAlways<number>;
|
||
inviteCode: string;
|
||
name: string;
|
||
bsky: string | null;
|
||
mapModePreferences: JSONColumnTypeNullable<UserMapModePreferences>;
|
||
/** Team's tag, typically used in-game in front of users' names to indicate they are a member of the team. */
|
||
tag: string | null;
|
||
}
|
||
|
||
export interface TeamMember {
|
||
createdAt: Generated<number>;
|
||
isOwner: Generated<number>;
|
||
isManager: Generated<number>;
|
||
leftAt: number | null;
|
||
role: MemberRole | null;
|
||
teamId: number;
|
||
userId: number;
|
||
isMainTeam: DBBoolean;
|
||
}
|
||
|
||
export interface Art {
|
||
authorId: number;
|
||
createdAt: Generated<number>;
|
||
description: string | null;
|
||
id: GeneratedAlways<number>;
|
||
imgId: number;
|
||
isShowcase: Generated<DBBoolean>;
|
||
}
|
||
|
||
export interface ArtTag {
|
||
authorId: number;
|
||
createdAt: Generated<number>;
|
||
id: GeneratedAlways<number>;
|
||
name: string;
|
||
}
|
||
|
||
export interface ArtUserMetadata {
|
||
artId: number;
|
||
userId: number;
|
||
}
|
||
|
||
export interface TaggedArt {
|
||
artId: number;
|
||
tagId: number;
|
||
}
|
||
|
||
export interface Badge {
|
||
id: GeneratedAlways<number>;
|
||
code: string;
|
||
displayName: string;
|
||
hue: number | null;
|
||
/** Who made the badge? If null, a legacy badge. */
|
||
authorId: number | null;
|
||
}
|
||
|
||
export interface BadgeManager {
|
||
badgeId: number;
|
||
userId: number;
|
||
}
|
||
|
||
export type BadgeOwner = {
|
||
badgeId: number;
|
||
userId: number;
|
||
count: number;
|
||
};
|
||
|
||
export interface Build {
|
||
clothesGearSplId: number | null;
|
||
description: string | null;
|
||
headGearSplId: number | null;
|
||
id: GeneratedAlways<number>;
|
||
modes: JSONColumnTypeNullable<ModeShort[]>;
|
||
ownerId: number;
|
||
private: DBBoolean | null;
|
||
shoesGearSplId: number | null;
|
||
title: string;
|
||
updatedAt: Generated<number>;
|
||
/** 3x4 ability tuple (head/clothes/shoes × main + 3 subs). */
|
||
abilities: JSONColumnTypeNullable<BuildAbilitiesTuple>;
|
||
/** Serialized ability+AP combo (e.g. `SSU_30,ISS_10`) used to group identical builds for the popular builds view. */
|
||
abilitiesSignature: string | null;
|
||
}
|
||
|
||
export type GearType = "HEAD" | "CLOTHES" | "SHOES";
|
||
|
||
export interface BuildWeapon {
|
||
buildId: number;
|
||
weaponSplId: MainWeaponId;
|
||
/** Alt skins collapse to their base weapon (e.g. Hero Shot Replica `45` → Splattershot `40`). Indexed for the builds-by-weapon, popular, and stats queries so they can filter `= ?` against a covering index instead of `IN (alt skins…)`. */
|
||
canonicalWeaponSplId: MainWeaponId;
|
||
/** Mirror of `Build.updatedAt`. Denormalized so the `(canonicalWeaponSplId, sortValue, updatedAt, buildId)` covering index serves the builds-by-weapon list. */
|
||
updatedAt: Generated<number>;
|
||
/** Per-weapon sort priority: `plusTier * 2 + (this weapon is top500 ? 0 : 1)` for public builds, NULL for private. */
|
||
sortValue: number | null;
|
||
}
|
||
|
||
/** Per-build ability point sums across all gear slots. Used to compute global `abilityPointAverages`. */
|
||
export interface BuildAbilitySum {
|
||
buildId: number;
|
||
ability: Ability;
|
||
abilityPoints: number;
|
||
}
|
||
|
||
/** Per-weapon, per-build ability point sums. Used to compute per-weapon `abilityPointAverages`. One row per canonical weapon × build × ability with non-zero AP. */
|
||
export interface BuildWeaponAbility {
|
||
canonicalWeaponSplId: MainWeaponId;
|
||
buildId: number;
|
||
ability: Ability;
|
||
abilityPoints: number;
|
||
}
|
||
|
||
export type CalendarEventTag = keyof typeof tags;
|
||
|
||
export interface CalendarEvent {
|
||
authorId: number;
|
||
bracketUrl: string;
|
||
description: string | null;
|
||
discordInviteCode: string | null;
|
||
id: GeneratedAlways<number>;
|
||
discordUrl: GeneratedAlways<string | null>;
|
||
name: string;
|
||
participantCount: number | null;
|
||
tags: string | null;
|
||
hidden: Generated<DBBoolean>;
|
||
tournamentId: number | null;
|
||
organizationId: number | null;
|
||
avatarImgId: number | null;
|
||
}
|
||
|
||
export interface CalendarEventBadge {
|
||
badgeId: number;
|
||
eventId: number;
|
||
}
|
||
|
||
export interface CalendarEventDate {
|
||
eventId: number;
|
||
id: GeneratedAlways<number>;
|
||
startTime: number;
|
||
}
|
||
|
||
export interface CalendarEventResultPlayer {
|
||
name: string | null;
|
||
teamId: number;
|
||
userId: number | null;
|
||
}
|
||
|
||
export interface CalendarEventResultTeam {
|
||
eventId: number;
|
||
id: GeneratedAlways<number>;
|
||
name: string;
|
||
placement: number;
|
||
}
|
||
|
||
export interface Group {
|
||
chatCode: string | null;
|
||
createdAt: Generated<number>;
|
||
id: GeneratedAlways<number>;
|
||
inviteCode: string;
|
||
latestActionAt: Generated<number>;
|
||
/** If truthy, group was at least partly made in the matchmaking UI (/q/looking) */
|
||
matchmade: Generated<DBBoolean>;
|
||
status: "PREPARING" | "ACTIVE" | "INACTIVE";
|
||
teamId: number | null;
|
||
}
|
||
|
||
export interface GroupLike {
|
||
createdAt: Generated<number>;
|
||
likerGroupId: number;
|
||
targetGroupId: number;
|
||
isRechallenge: DBBoolean | null;
|
||
}
|
||
|
||
type CalculatingSkill = {
|
||
calculated: false;
|
||
matchesCount: number;
|
||
matchesCountNeeded: number;
|
||
/** Freshly calculated skill */
|
||
newSp?: number;
|
||
};
|
||
export type UserSkillDifference =
|
||
| {
|
||
calculated: true;
|
||
spDiff: number;
|
||
oldSp?: number;
|
||
newSp?: number;
|
||
}
|
||
| CalculatingSkill;
|
||
export type GroupSkillDifference =
|
||
| {
|
||
calculated: true;
|
||
oldSp: number;
|
||
newSp: number;
|
||
}
|
||
| CalculatingSkill;
|
||
|
||
export type ParsedMemento = {
|
||
users: Record<
|
||
number,
|
||
{
|
||
plusTier?: PlusTier["tier"];
|
||
skill?: TieredSkill | "CALCULATING";
|
||
skillDifference?: UserSkillDifference;
|
||
}
|
||
>;
|
||
groups: Record<
|
||
number,
|
||
{
|
||
tier?: TieredSkill["tier"];
|
||
skillDifference?: GroupSkillDifference;
|
||
}
|
||
>;
|
||
modePreferences?: Partial<
|
||
Record<ModeShort, Array<{ userId: number; preference?: Preference }>>
|
||
>;
|
||
/** mapPreferences of season 2 */
|
||
mapPreferences?: Array<{ userId: number; preference?: Preference }[]>;
|
||
pools: Array<{
|
||
userId: number;
|
||
pool: UserMapModePreferences["pool"];
|
||
teamName?: string;
|
||
}>;
|
||
};
|
||
|
||
export interface GroupMatch {
|
||
alphaGroupId: number;
|
||
bravoGroupId: number;
|
||
chatCode: string | null;
|
||
confirmedAt: number | null;
|
||
confirmedByUserId: number | null;
|
||
createdAt: Generated<number>;
|
||
id: GeneratedAlways<number>;
|
||
memento: JSONColumnTypeNullable<ParsedMemento>;
|
||
cancelRequestedByUserId: number | null;
|
||
cancelAcceptedByUserId: number | null;
|
||
}
|
||
|
||
export interface GroupMatchContinueVote {
|
||
id: GeneratedAlways<number>;
|
||
groupId: number;
|
||
userId: number;
|
||
isContinuing: DBBoolean;
|
||
votedAt: Generated<number>;
|
||
}
|
||
|
||
export interface GroupMatchMap {
|
||
id: GeneratedAlways<number>;
|
||
index: number;
|
||
matchId: number;
|
||
mode: ModeShort;
|
||
reportedAt: number | null;
|
||
reportedByUserId: number | null;
|
||
source: string;
|
||
stageId: StageId;
|
||
winnerGroupId: number | null;
|
||
}
|
||
|
||
export interface GroupMember {
|
||
createdAt: Generated<number>;
|
||
groupId: number;
|
||
note: string | null;
|
||
role: "OWNER" | "MANAGER" | "REGULAR";
|
||
userId: number;
|
||
}
|
||
|
||
export interface PrivateUserNote {
|
||
authorId: number;
|
||
targetId: number;
|
||
text: string | null;
|
||
sentiment: "POSITIVE" | "NEUTRAL" | "NEGATIVE";
|
||
updatedAt: Generated<number>;
|
||
}
|
||
|
||
/** Log-in links generated via the Lohi Discord bot commands. */
|
||
export interface LogInLink {
|
||
code: string;
|
||
expiresAt: number;
|
||
userId: number;
|
||
}
|
||
|
||
export type LFGType =
|
||
| "PLAYER_FOR_TEAM"
|
||
| "PLAYER_FOR_COACH"
|
||
| "TEAM_FOR_PLAYER"
|
||
| "TEAM_FOR_COACH"
|
||
| "TEAM_FOR_SCRIM"
|
||
| "COACH_FOR_TEAM";
|
||
|
||
export const LFG_TYPES = [
|
||
"PLAYER_FOR_TEAM",
|
||
"PLAYER_FOR_COACH",
|
||
"TEAM_FOR_PLAYER",
|
||
"TEAM_FOR_COACH",
|
||
"TEAM_FOR_SCRIM",
|
||
"COACH_FOR_TEAM",
|
||
] as const;
|
||
|
||
export interface LFGPost {
|
||
id: GeneratedAlways<number>;
|
||
type: LFGType;
|
||
text: string;
|
||
/** e.g. Europe/Helsinki */
|
||
timezone: string;
|
||
authorId: number;
|
||
teamId: number | null;
|
||
plusTierVisibility: number | null;
|
||
languages: string | null;
|
||
updatedAt: Generated<number>;
|
||
createdAt: GeneratedAlways<number>;
|
||
}
|
||
|
||
export interface MapPoolMap {
|
||
calendarEventId: number | null;
|
||
mode: ModeShort;
|
||
stageId: StageId;
|
||
tieBreakerCalendarEventId: number | null;
|
||
tournamentTeamId: number | null;
|
||
}
|
||
|
||
export interface MapResult {
|
||
losses: number;
|
||
mode: ModeShort;
|
||
season: number;
|
||
stageId: StageId;
|
||
userId: number;
|
||
wins: number;
|
||
}
|
||
|
||
export interface PlayerResult {
|
||
mapLosses: number;
|
||
mapWins: number;
|
||
otherUserId: number;
|
||
ownerUserId: number;
|
||
season: number;
|
||
setLosses: number;
|
||
setWins: number;
|
||
type: string;
|
||
}
|
||
|
||
export interface PlusSuggestion {
|
||
authorId: number;
|
||
createdAt: GeneratedAlways<number>;
|
||
id: GeneratedAlways<number>;
|
||
month: number;
|
||
suggestedId: number;
|
||
text: string;
|
||
tier: number;
|
||
updatedAt: number | null;
|
||
year: number;
|
||
}
|
||
|
||
export interface PlusTier {
|
||
tier: number;
|
||
userId: number;
|
||
}
|
||
|
||
export interface PlusVote {
|
||
authorId: number;
|
||
month: number;
|
||
score: number;
|
||
tier: number;
|
||
validAfter: number;
|
||
votedId: number;
|
||
year: number;
|
||
}
|
||
|
||
export interface PlusVotingResult {
|
||
votedId: number;
|
||
tier: number;
|
||
score: number;
|
||
month: number;
|
||
year: number;
|
||
wasSuggested: DBBoolean;
|
||
}
|
||
|
||
export interface ReportedWeapon {
|
||
groupMatchId: number | null;
|
||
tournamentMatchId: number | null;
|
||
mapIndex: number;
|
||
userId: number;
|
||
weaponSplId: MainWeaponId;
|
||
createdAt: Generated<number>;
|
||
}
|
||
|
||
export interface Skill {
|
||
groupMatchId: number | null;
|
||
id: GeneratedAlways<number>;
|
||
identifier: string | null;
|
||
matchesCount: number;
|
||
mu: number;
|
||
ordinal: number;
|
||
sigma: number;
|
||
season: number;
|
||
tournamentId: number | null;
|
||
userId: number | null;
|
||
createdAt: number | null;
|
||
}
|
||
|
||
export interface SkillTeamUser {
|
||
skillId: number;
|
||
userId: number;
|
||
}
|
||
|
||
/** Used for tournament auto-seeding. Calculates off tournament matches same as SP but does not have seasonal resets. */
|
||
export interface SeedingSkill {
|
||
mu: number;
|
||
ordinal: number;
|
||
sigma: number;
|
||
userId: number;
|
||
type: "RANKED" | "UNRANKED";
|
||
}
|
||
|
||
export interface SplatoonPlayer {
|
||
id: GeneratedAlways<number>;
|
||
splId: string;
|
||
userId: number | null;
|
||
/** Players best XP across both divisions. Denormalized for performance. */
|
||
peakXp: number | null;
|
||
}
|
||
|
||
export interface TaggedArt {
|
||
artId: number;
|
||
tagId: number;
|
||
}
|
||
|
||
// AUTO = style where teams pick their map pool ahead of time and the map lists are automatically made for each round
|
||
// could also have the traditional style where TO picks the maps later
|
||
type TournamentMapPickingStyle =
|
||
| "TO"
|
||
| "AUTO_ALL"
|
||
| "AUTO_SZ"
|
||
| "AUTO_TC"
|
||
| "AUTO_RM"
|
||
| "AUTO_CB";
|
||
|
||
export interface TournamentSettings {
|
||
bracketProgression: Progression.ParsedBracket[];
|
||
/** @deprecated use bracketProgression instead */
|
||
teamsPerGroup?: number;
|
||
/** @deprecated use bracketProgression instead */
|
||
thirdPlaceMatch?: boolean;
|
||
isRanked?: boolean;
|
||
enableNoScreenToggle?: boolean;
|
||
/** Enable the subs tab, default true */
|
||
enableSubs?: boolean;
|
||
requireInGameNames?: boolean;
|
||
isInvitational?: boolean;
|
||
/** Can teams add subs on their own while tournament is in progress? */
|
||
autonomousSubs?: boolean;
|
||
/** Timestamp (SQLite format) when reg closes, if missing then means closes at start time */
|
||
regClosesAt?: number;
|
||
/** @deprecated use bracketProgression instead */
|
||
swiss?: {
|
||
groupCount: number;
|
||
roundCount: number;
|
||
};
|
||
minMembersPerTeam?: number;
|
||
/** Maximum number of team members that can be registered (only applies to 4v4 tournaments) */
|
||
maxMembersPerTeam?: number;
|
||
isTest?: boolean;
|
||
isDraft?: boolean;
|
||
requireSendouQParticipation?: boolean;
|
||
}
|
||
|
||
export interface CastedMatchesInfo {
|
||
/** Array for matches that are locked because they are pending to be casted */
|
||
lockedMatches: Array<{ twitchAccount: string; matchId: number }>;
|
||
/** What matches are streamed currently & where */
|
||
castedMatches: { twitchAccount: string; matchId: number }[];
|
||
castedMatchHistory?: Array<{
|
||
twitchAccount: string;
|
||
matchId: number;
|
||
timestamp: number;
|
||
}>;
|
||
}
|
||
|
||
export interface Tournament {
|
||
settings: JSONColumnType<TournamentSettings>;
|
||
id: GeneratedAlways<number>;
|
||
mapPickingStyle: TournamentMapPickingStyle;
|
||
/** Maps prepared ahead of time for rounds. Follows settings.bracketProgression order. Null in the spot if not defined yet for that bracket. */
|
||
preparedMaps: JSONColumnTypeNullable<(PreparedMaps | null)[]>;
|
||
castTwitchAccounts: JSONColumnTypeNullable<string[]>;
|
||
castedMatchesInfo: JSONColumnTypeNullable<CastedMatchesInfo>;
|
||
rules: string | null;
|
||
/** Related "parent tournament", the tournament that contains the original sign-ups (for leagues) */
|
||
parentTournamentId: number | null;
|
||
/** Is the tournament finalized meaning all the matches are played and TO has locked it making it read-only */
|
||
isFinalized: Generated<DBBoolean>;
|
||
/** Snapshot of teams and rosters when seeds were last saved. Used to detect NEW teams/players. */
|
||
seedingSnapshot: JSONColumnTypeNullable<SeedingSnapshot>;
|
||
/** Tournament tier based on top teams' skill. 1=X, 2=S+, 3=S, 4=A+, 5=A, 6=B+, 7=B, 8=C+, 9=C */
|
||
tier: TournamentTierNumber | null;
|
||
vodsLastSyncAt: Generated<number | null>;
|
||
/** How many times vods have been synced (automatic process that happens when tournament has concluded). */
|
||
vodsSyncCount: Generated<number>;
|
||
}
|
||
|
||
export interface SeedingSnapshot {
|
||
savedAt: number;
|
||
teams: Array<{
|
||
teamId: number;
|
||
members: Array<{ userId: number; username: string }>;
|
||
}>;
|
||
}
|
||
|
||
export interface PreparedMaps {
|
||
authorId: number;
|
||
createdAt: number;
|
||
maps: Array<TournamentRoundMaps & { roundId: number; groupId: number }>;
|
||
eliminationTeamCount?: number;
|
||
}
|
||
|
||
export interface SavedCalendarEvent {
|
||
id: GeneratedAlways<number>;
|
||
userId: number;
|
||
calendarEventId: number;
|
||
createdAt: Generated<number>;
|
||
}
|
||
|
||
export interface TournamentBadgeOwner {
|
||
badgeId: number;
|
||
userId: number;
|
||
/** Which tournament the badge is from, if null was added manually by a badge manager as opposed to once a tournament was finalized. */
|
||
tournamentId: number | null;
|
||
/** How many times this badge was awarded to this user from this source. Tournament rows are always 1; manual grants aggregate repeat awards here. */
|
||
count: Generated<number>;
|
||
}
|
||
|
||
/** A group is a logical structure used to group multiple rounds together.
|
||
|
||
- In round-robin stages, a group is a pool.
|
||
- In swiss, a group is also a pool (can have one or multiple groups)
|
||
- In elimination stages, a group is a bracket.
|
||
- A single elimination stage can have one or two groups:
|
||
- The unique bracket.
|
||
- If enabled, the Consolation Final.
|
||
- A double elimination stage can have two or three groups:
|
||
- Upper and lower brackets.
|
||
- If enabled, the Grand Final.
|
||
*/
|
||
export interface TournamentGroup {
|
||
id: GeneratedAlways<number>;
|
||
number: number;
|
||
stageId: number;
|
||
}
|
||
|
||
export const TournamentMatchStatus = {
|
||
/** The two matches leading to this one are not completed yet. */
|
||
Locked: 0,
|
||
|
||
/** One participant is ready and waiting for the other one. */
|
||
Waiting: 1,
|
||
|
||
/** Both participants are ready to start. */
|
||
Ready: 2,
|
||
|
||
/** The match is running. */
|
||
Running: 3,
|
||
|
||
/** The match is completed. */
|
||
Completed: 4,
|
||
};
|
||
|
||
export interface TournamentMatch {
|
||
chatCode: string | null;
|
||
groupId: number;
|
||
id: GeneratedAlways<number>;
|
||
number: number;
|
||
opponentOne: JSONColumnType<ParticipantResult>;
|
||
opponentTwo: JSONColumnType<ParticipantResult>;
|
||
roundId: number;
|
||
stageId: number;
|
||
status: (typeof TournamentMatchStatus)[keyof typeof TournamentMatchStatus];
|
||
// set when match becomes ongoing (both teams ready and no earlier matches for either team)
|
||
// for swiss: set at creation time
|
||
startedAt: number | null;
|
||
}
|
||
|
||
/** Represents one decision, pick or ban, during tournaments pick/ban (counterpick, ban 2) phase. */
|
||
export interface TournamentMatchPickBanEvent {
|
||
type: "PICK" | "BAN" | "ROLL" | "MODE_PICK" | "MODE_BAN";
|
||
stageId: StageId | null;
|
||
mode: ModeShort | null;
|
||
matchId: number;
|
||
authorId: number | null;
|
||
number: number;
|
||
createdAt: GeneratedAlways<number>;
|
||
}
|
||
|
||
export interface TournamentMatchGameResult {
|
||
createdAt: Generated<number>;
|
||
id: GeneratedAlways<number>;
|
||
matchId: number;
|
||
mode: ModeShort;
|
||
number: number;
|
||
reporterId: number;
|
||
source: string;
|
||
stageId: StageId;
|
||
winnerTeamId: number;
|
||
opponentOnePoints: number | null;
|
||
opponentTwoPoints: number | null;
|
||
}
|
||
|
||
export interface TournamentMatchGameResultParticipant {
|
||
matchGameResultId: number;
|
||
userId: number;
|
||
tournamentTeamId: number;
|
||
}
|
||
|
||
export type WinLossParticipationArray = Array<"W" | "L" | null>;
|
||
|
||
export interface TournamentResult {
|
||
isHighlight: Generated<DBBoolean>;
|
||
participantCount: number;
|
||
placement: number;
|
||
tournamentId: number;
|
||
tournamentTeamId: number;
|
||
/**
|
||
* The result of sets in the tournament.
|
||
* E.g. ["W", "L", null] would mean the user won the first set, lost the second and did not play the third.
|
||
* */
|
||
setResults: JSONColumnType<WinLossParticipationArray>;
|
||
/** The SP change in total after the finalization of a ranked tournament. */
|
||
spDiff: number | null;
|
||
userId: number;
|
||
/** Division label for tournaments with multiple starting brackets (e.g., "D1", "D2") */
|
||
div: string | null;
|
||
}
|
||
|
||
export interface TournamentRoundMaps {
|
||
list?: Array<{ mode: ModeShort; stageId: StageId }> | null;
|
||
count: number;
|
||
type: "BEST_OF" | "PLAY_ALL";
|
||
pickBan?: PickBan.Type | null;
|
||
customFlow?: CustomPickBanFlow | null;
|
||
}
|
||
|
||
export const WHO_SIDES = [
|
||
"ALPHA",
|
||
"BRAVO",
|
||
"HIGHER_SEED",
|
||
"LOWER_SEED",
|
||
"WINNER",
|
||
"LOSER",
|
||
] as const;
|
||
export type WhoSide = (typeof WHO_SIDES)[number];
|
||
|
||
export const ACTION_TYPES = [
|
||
"ROLL",
|
||
"PICK",
|
||
"BAN",
|
||
"MODE_PICK",
|
||
"MODE_BAN",
|
||
] as const;
|
||
export type ActionType = (typeof ACTION_TYPES)[number];
|
||
|
||
export interface CustomPickBanStep {
|
||
action: ActionType;
|
||
side?: WhoSide;
|
||
}
|
||
|
||
export interface CustomPickBanFlow {
|
||
preSet: CustomPickBanStep[];
|
||
postGame: CustomPickBanStep[];
|
||
}
|
||
|
||
/**
|
||
* A round is a logical structure used to group multiple matches together.
|
||
|
||
- In round-robin stages, a round can be viewed as a list of matches that can be played at the same time.
|
||
- In swiss, a round is a list of matches that are played at the same time.
|
||
- In elimination stages, a round is a round of a bracket, e.g. 8th finals, semi-finals, etc.
|
||
*/
|
||
export interface TournamentRound {
|
||
groupId: number;
|
||
id: GeneratedAlways<number>;
|
||
number: number;
|
||
stageId: number;
|
||
maps: JSONColumnType<TournamentRoundMaps>;
|
||
}
|
||
|
||
// when updating this also update `defaultBracketSettings` in tournament-utils.ts
|
||
export interface TournamentStageSettings {
|
||
// SE
|
||
thirdPlaceMatch?: boolean;
|
||
// RR
|
||
teamsPerGroup?: number;
|
||
/** (RR only) When true, teams are split into A and B divisions and matches only pair A-vs-B. Only valid on starting brackets. */
|
||
hasAbDivisions?: boolean;
|
||
// SWISS
|
||
groupCount?: number;
|
||
// SWISS
|
||
roundCount?: number;
|
||
/** (Swiss only) Number of wins required for a team to advance early. When set, teams advance at this win count and are eliminated at (roundCount - advanceThreshold + 1) losses. */
|
||
advanceThreshold?: number;
|
||
}
|
||
|
||
export const TOURNAMENT_STAGE_TYPES = [
|
||
"single_elimination",
|
||
"double_elimination",
|
||
"round_robin",
|
||
"swiss",
|
||
] as const;
|
||
|
||
/** A stage is an intermediate phase in a tournament. In essence a bracket. */
|
||
export interface TournamentStage {
|
||
id: GeneratedAlways<number>;
|
||
name: string;
|
||
number: number;
|
||
settings: string;
|
||
tournamentId: number;
|
||
type: (typeof TOURNAMENT_STAGE_TYPES)[number];
|
||
// not Generated<> because SQLite doesn't allow altering tables to add columns with default values :(
|
||
createdAt: number | null;
|
||
}
|
||
|
||
/** Tournament sub post, shown in a list of subs available for teams to pick from. */
|
||
export interface TournamentSub {
|
||
bestWeapons: string;
|
||
/** 0 = no, 1 = yes, 2 = listen only */
|
||
canVc: number;
|
||
createdAt: Generated<number>;
|
||
message: string | null;
|
||
okWeapons: string | null;
|
||
tournamentId: number;
|
||
userId: number;
|
||
visibility: "+1" | "+2" | "+3" | "ALL";
|
||
}
|
||
|
||
export interface TournamentLFGLike {
|
||
likerTeamId: number;
|
||
targetTeamId: number;
|
||
createdAt: Generated<number>;
|
||
}
|
||
|
||
export interface TournamentStaff {
|
||
tournamentId: number;
|
||
userId: number;
|
||
role: "ORGANIZER" | "STREAMER";
|
||
}
|
||
|
||
export interface TournamentTeam {
|
||
createdAt: Generated<number>;
|
||
id: GeneratedAlways<number>;
|
||
inviteCode: string;
|
||
name: string;
|
||
prefersNotToHost: Generated<DBBoolean>;
|
||
droppedOut: Generated<DBBoolean>;
|
||
seed: number | null;
|
||
/** For formats that have many starting brackets, where should the team start? */
|
||
startingBracketIdx: number | null;
|
||
activeRosterUserIds: JSONColumnTypeNullable<number[]>;
|
||
tournamentId: number;
|
||
teamId: number | null;
|
||
avatarImgId: number | null;
|
||
isLooking: Generated<DBBoolean>;
|
||
isPlaceholder: Generated<DBBoolean>;
|
||
lfgNote: string | null;
|
||
chatCode: Generated<string | null>;
|
||
/** A/B division assignment for bipartite round robin brackets. `0` = A, `1` = B, `null` = unassigned. */
|
||
abDivision: number | null;
|
||
}
|
||
|
||
export interface TournamentTeamCheckIn {
|
||
checkedInAt: number;
|
||
/** Which bracket checked in for. If missing is check in for the whole event. */
|
||
bracketIdx: number | null;
|
||
tournamentTeamId: number;
|
||
/** Indicates that this bracket defaults to checked in and this team has been explicitly checked out from it */
|
||
isCheckOut: Generated<number>;
|
||
}
|
||
|
||
export interface TournamentTeamMember {
|
||
createdAt: Generated<number>;
|
||
inGameName: string | null;
|
||
tournamentTeamId: number;
|
||
userId: number;
|
||
role: Generated<"OWNER" | "MANAGER" | "REGULAR">;
|
||
isStayAsSub: Generated<DBBoolean>;
|
||
// denormalized from TournamentTeam.isLooking
|
||
isLooking: Generated<DBBoolean>;
|
||
}
|
||
|
||
export interface TournamentOrganization {
|
||
id: GeneratedAlways<number>;
|
||
name: string;
|
||
slug: string;
|
||
description: string | null;
|
||
socials: JSONColumnTypeNullable<string[]>;
|
||
avatarImgId: number | null;
|
||
isEstablished: Generated<DBBoolean>;
|
||
}
|
||
|
||
export const TOURNAMENT_ORGANIZATION_ROLES = [
|
||
"ADMIN",
|
||
"MEMBER",
|
||
"ORGANIZER",
|
||
"STREAMER",
|
||
] as const;
|
||
type TournamentOrganizationRole =
|
||
(typeof TOURNAMENT_ORGANIZATION_ROLES)[number];
|
||
|
||
export interface TournamentOrganizationMember {
|
||
organizationId: number;
|
||
userId: number;
|
||
role: TournamentOrganizationRole;
|
||
roleDisplayName: string | null;
|
||
}
|
||
|
||
export interface TournamentOrganizationBadge {
|
||
organizationId: number;
|
||
badgeId: number;
|
||
}
|
||
|
||
export interface TournamentOrganizationSeries {
|
||
id: GeneratedAlways<number>;
|
||
organizationId: number;
|
||
name: string;
|
||
description: string | null;
|
||
substringMatches: JSONColumnType<string[]>;
|
||
showLeaderboard: Generated<number>;
|
||
tierHistory: JSONColumnTypeNullable<TournamentTierNumber[]>;
|
||
}
|
||
|
||
export interface TournamentBracketProgressionOverride {
|
||
sourceBracketIdx: number;
|
||
destinationBracketIdx: number;
|
||
tournamentTeamId: number;
|
||
tournamentId: number;
|
||
}
|
||
|
||
export interface TournamentOrganizationBannedUser {
|
||
organizationId: number;
|
||
userId: number;
|
||
privateNote: string | null;
|
||
updatedAt: Generated<number>;
|
||
expiresAt: number | null;
|
||
}
|
||
|
||
/** Indicates a user trusts another. Allows direct adding to groups/teams without invite links. */
|
||
export interface TrustRelationship {
|
||
trustGiverUserId: number;
|
||
trustReceiverUserId: number;
|
||
lastUsedAt: number;
|
||
}
|
||
|
||
/** Mutual friendship between two users. Invariant: userOneId < userTwoId. */
|
||
export interface Friendship {
|
||
id: GeneratedAlways<number>;
|
||
userOneId: number;
|
||
userTwoId: number;
|
||
createdAt: Generated<number>;
|
||
}
|
||
|
||
/** Pending friend request from one user to another. */
|
||
export interface FriendRequest {
|
||
id: GeneratedAlways<number>;
|
||
senderId: number;
|
||
receiverId: number;
|
||
createdAt: Generated<number>;
|
||
}
|
||
|
||
export interface UnvalidatedUserSubmittedImage {
|
||
id: GeneratedAlways<number>;
|
||
submitterUserId: number;
|
||
url: string;
|
||
/** When was the image validated? If `null` should be hidden from other users. */
|
||
validatedAt: number | null;
|
||
}
|
||
|
||
export interface UnvalidatedVideo {
|
||
eventId: number | null;
|
||
id: GeneratedAlways<number>;
|
||
submitterUserId: number;
|
||
title: string;
|
||
type: string;
|
||
validatedAt: number | null;
|
||
youtubeDate: number;
|
||
youtubeId: string;
|
||
}
|
||
|
||
// missing means "neutral"
|
||
export type Preference = "AVOID" | "PREFER";
|
||
export interface UserMapModePreferences {
|
||
modes: Array<{
|
||
mode: ModeShort;
|
||
/** Users opinion on the mode, `undefined` means neutral */
|
||
preference?: Preference;
|
||
}>;
|
||
pool: Array<{
|
||
mode: ModeShort;
|
||
stages: StageId[];
|
||
}>;
|
||
}
|
||
|
||
export interface QWeaponPool {
|
||
weaponSplId: MainWeaponId;
|
||
isFavorite: number;
|
||
}
|
||
|
||
export const BUILD_SORT_IDENTIFIERS = [
|
||
"UPDATED_AT",
|
||
"TOP_500",
|
||
"WEAPON_POOL",
|
||
"WEAPON_IN_GAME_ORDER",
|
||
"ALPHABETICAL_TITLE",
|
||
"MODE",
|
||
"HEADGEAR_ID",
|
||
"CLOTHES_ID",
|
||
"SHOES_ID",
|
||
"PUBLIC_BUILD",
|
||
"PRIVATE_BUILD",
|
||
] as const;
|
||
|
||
export type BuildSort = (typeof BUILD_SORT_IDENTIFIERS)[number];
|
||
|
||
export interface UserPreferences {
|
||
disableBuildAbilitySorting?: boolean;
|
||
disallowScrimPickupsFromUntrusted?: boolean;
|
||
defaultCalendarFilters?: CalendarFilters;
|
||
defaultScrimsFilters?: ScrimFilters;
|
||
/**
|
||
* What time format the user prefers?
|
||
*
|
||
* "auto" = use browser default (default value)
|
||
* "24h" = 24 hour format (e.g. 14:00)
|
||
* "12h" = 12 hour format (e.g. 2:00 PM)
|
||
* */
|
||
clockFormat?: "24h" | "12h" | "auto";
|
||
/** Is the new widget based user page enabled? (Supporter early preview) */
|
||
newProfileEnabled?: boolean;
|
||
/** Is spoiler-free mode enabled? Hides recent tournament results and scores until the user chooses to reveal them. */
|
||
spoilerFreeMode?: boolean;
|
||
weaponReportDefaultOpen?: boolean;
|
||
}
|
||
|
||
export const SUBJECT_PRONOUNS = ["he", "she", "they", "it", "any"] as const;
|
||
export const OBJECT_PRONOUNS = [
|
||
"him",
|
||
"her",
|
||
"them",
|
||
"its",
|
||
"all",
|
||
...SUBJECT_PRONOUNS,
|
||
] as const;
|
||
|
||
export type Pronouns = {
|
||
subject: (typeof SUBJECT_PRONOUNS)[number];
|
||
object: (typeof OBJECT_PRONOUNS)[number];
|
||
};
|
||
|
||
export interface User {
|
||
/** 1 = permabanned, timestamp = ban active till then */
|
||
banned: Generated<number | null>;
|
||
bannedReason: string | null;
|
||
bio: string | null;
|
||
commissionsOpen: Generated<number | null>;
|
||
commissionsOpenedAt: number | null;
|
||
commissionText: string | null;
|
||
country: string | null;
|
||
customTheme: JSONColumnTypeNullable<CustomTheme>;
|
||
customUrl: string | null;
|
||
discordAvatar: string | null;
|
||
discordId: string;
|
||
discordName: string;
|
||
customName: string | null;
|
||
/** coalesce(customName, discordName) */
|
||
username: ColumnType<string, never, never>;
|
||
discordUniqueName: string | null;
|
||
/** User's favorite badges they want to show on the front page of the badge display. Index = 0 big badge. */
|
||
favoriteBadgeIds: ColumnType<number[] | null, string | null, string | null>;
|
||
id: GeneratedAlways<number>;
|
||
inGameName: string | null;
|
||
isArtist: Generated<DBBoolean | null>;
|
||
isVideoAdder: Generated<DBBoolean | null>;
|
||
isTournamentOrganizer: Generated<DBBoolean | null>;
|
||
isApiAccesser: Generated<DBBoolean | null>;
|
||
languages: string | null;
|
||
motionSens: number | null;
|
||
pronouns: JSONColumnTypeNullable<Pronouns>;
|
||
patronSince: number | null;
|
||
patronTier: number | null;
|
||
patronTill: number | null;
|
||
showDiscordUniqueName: Generated<DBBoolean>;
|
||
stickSens: number | null;
|
||
twitch: string | null;
|
||
bsky: string | null;
|
||
battlefy: string | null;
|
||
vc: Generated<"YES" | "NO" | "LISTEN_ONLY">;
|
||
youtubeId: string | null;
|
||
mapModePreferences: JSONColumnTypeNullable<UserMapModePreferences>;
|
||
qWeaponPool: JSONColumnTypeNullable<QWeaponPool[]>;
|
||
plusSkippedForSeasonNth: number | null;
|
||
noScreen: Generated<DBBoolean>;
|
||
/** User doesn't have access to SplatNet 3 to join rooms made by others */
|
||
noSplatnet: Generated<DBBoolean>;
|
||
buildSorting: JSONColumnTypeNullable<BuildSort[]>;
|
||
preferences: JSONColumnTypeNullable<UserPreferences>;
|
||
/** User creation date. Can be null because we did not always save this. */
|
||
createdAt: number | null;
|
||
joinOrder: number | null;
|
||
/** Last message used when creating a tournament sub post */
|
||
lastSubMessage: string | null;
|
||
}
|
||
|
||
/** Represents User joined with PlusTier table */
|
||
export type UserWithPlusTier = Tables["User"] & {
|
||
plusTier: PlusTier["tier"] | null;
|
||
};
|
||
|
||
export interface UserResultHighlight {
|
||
teamId: number;
|
||
userId: number;
|
||
}
|
||
|
||
export interface UserSubmittedImage {
|
||
id: GeneratedAlways<number>;
|
||
submitterUserId: number | null;
|
||
url: string;
|
||
validatedAt: number | null;
|
||
}
|
||
|
||
export interface UserWeapon {
|
||
createdAt: Generated<number>;
|
||
isFavorite: Generated<DBBoolean>;
|
||
order: number;
|
||
userId: number;
|
||
weaponSplId: MainWeaponId;
|
||
}
|
||
|
||
export interface UserFriendCode {
|
||
friendCode: string;
|
||
userId: number;
|
||
submitterUserId: number;
|
||
createdAt: GeneratedAlways<number>;
|
||
}
|
||
|
||
export interface UserWidget {
|
||
userId: number;
|
||
index: number;
|
||
widget: JSONColumnType<StoredWidget>;
|
||
}
|
||
export type ApiTokenType = "read" | "write";
|
||
|
||
export interface ApiToken {
|
||
id: GeneratedAlways<number>;
|
||
userId: number;
|
||
token: string;
|
||
type: Generated<ApiTokenType>;
|
||
createdAt: GeneratedAlways<number>;
|
||
}
|
||
|
||
export interface LiveStream {
|
||
id: GeneratedAlways<number>;
|
||
userId: number | null;
|
||
viewerCount: number;
|
||
thumbnailUrl: string;
|
||
twitch: string | null;
|
||
}
|
||
|
||
export interface TournamentStreamer {
|
||
id: GeneratedAlways<number>;
|
||
userId: number | null;
|
||
tournamentId: number;
|
||
twitchAccount: string;
|
||
}
|
||
|
||
export interface TournamentMatchVod {
|
||
id: GeneratedAlways<number>;
|
||
matchId: number;
|
||
userId: number | null;
|
||
platform: string;
|
||
account: string;
|
||
platformVideoId: string;
|
||
timestampSeconds: number;
|
||
viewCount: number;
|
||
}
|
||
|
||
export interface BanLog {
|
||
id: GeneratedAlways<number>;
|
||
userId: number;
|
||
banned: number | null;
|
||
bannedReason: string | null;
|
||
bannedByUserId: number;
|
||
createdAt: GeneratedAlways<number>;
|
||
}
|
||
|
||
export interface ModNote {
|
||
id: GeneratedAlways<number>;
|
||
userId: number;
|
||
authorId: number;
|
||
text: string;
|
||
createdAt: GeneratedAlways<number>;
|
||
isDeleted: Generated<DBBoolean>;
|
||
}
|
||
|
||
export interface Video {
|
||
eventId: number | null;
|
||
id: GeneratedAlways<number>;
|
||
submitterUserId: number;
|
||
title: string;
|
||
type: "SCRIM" | "TOURNAMENT" | "MATCHMAKING" | "CAST" | "SENDOUQ";
|
||
validatedAt: number | null;
|
||
youtubeDate: number;
|
||
youtubeId: string;
|
||
}
|
||
|
||
export interface VideoMatch {
|
||
id: GeneratedAlways<number>;
|
||
mode: ModeShort;
|
||
stageId: StageId;
|
||
startsAt: number;
|
||
videoId: number;
|
||
}
|
||
|
||
export interface VideoMatchPlayer {
|
||
player: number;
|
||
playerName: string | null;
|
||
playerUserId: number | null;
|
||
videoMatchId: number;
|
||
weaponSplId: number;
|
||
}
|
||
|
||
export interface XRankPlacement {
|
||
badges: string;
|
||
bannerSplId: number;
|
||
id: GeneratedAlways<number>;
|
||
mode: ModeShort;
|
||
month: number;
|
||
name: string;
|
||
nameDiscriminator: string;
|
||
playerId: number;
|
||
power: number;
|
||
rank: number;
|
||
region: "WEST" | "JPN";
|
||
title: string;
|
||
weaponSplId: MainWeaponId;
|
||
year: number;
|
||
}
|
||
|
||
export interface ScrimPost {
|
||
id: GeneratedAlways<number>;
|
||
/** When is the scrim scheduled to happen */
|
||
at: number;
|
||
/** Optional end of time range indicating team accepts scrims starting between at and rangeEnd */
|
||
rangeEnd: number | null;
|
||
/** Highest LUTI div accepted */
|
||
maxDiv: number | null;
|
||
/** Lowest LUTI div accepted */
|
||
minDiv: number | null;
|
||
/** Who sees the post */
|
||
visibility: JSONColumnTypeNullable<AssociationVisibility>;
|
||
/** Any additional info */
|
||
text: string | null;
|
||
/** The key to access the scrim chat, used after scrim is scheduled with another team */
|
||
chatCode: string;
|
||
/** Refers to the team looking for the team (can also be a pick-up) */
|
||
teamId: number | null;
|
||
/** Indicates if anyone in the post can manage it */
|
||
managedByAnyone: DBBoolean;
|
||
/** When the scrim was canceled */
|
||
canceledAt: number | null;
|
||
/** User id who canceled the scrim */
|
||
canceledByUserId: number | null;
|
||
/** Reason for canceling the scrim */
|
||
cancelReason: string | null;
|
||
/** When the post was made was it scheduled for a future time slot (as opposed to looking now) */
|
||
isScheduledForFuture: Generated<DBBoolean>;
|
||
/** Maps/modes the scrim is available for. If null means no preference unless "mapsTournamentId" is set */
|
||
maps: "SZ" | "ALL" | "RANKED" | null;
|
||
/** If set, specifies the maps of a tournament to play */
|
||
mapsTournamentId: number | null;
|
||
createdAt: GeneratedAlways<number>;
|
||
updatedAt: Generated<number>;
|
||
}
|
||
|
||
export interface ScrimPostUser {
|
||
scrimPostId: number;
|
||
userId: number;
|
||
/** User is the author of the post */
|
||
isOwner: number;
|
||
}
|
||
|
||
export interface ScrimPostRequest {
|
||
id: GeneratedAlways<number>;
|
||
scrimPostId: number;
|
||
teamId: number | null;
|
||
message: string | null;
|
||
/** Specific time selected by requester (required when post has rangeEnd) */
|
||
at: number | null;
|
||
isAccepted: Generated<DBBoolean>;
|
||
createdAt: GeneratedAlways<number>;
|
||
}
|
||
|
||
export interface ScrimPostRequestUser {
|
||
scrimPostRequestId: number;
|
||
/** User that made the request */
|
||
userId: number;
|
||
isOwner: DBBoolean;
|
||
}
|
||
|
||
export interface Association {
|
||
id: GeneratedAlways<number>;
|
||
name: string;
|
||
inviteCode: string;
|
||
createdAt: GeneratedAlways<number>;
|
||
}
|
||
|
||
export interface AssociationMember {
|
||
userId: number;
|
||
associationId: number;
|
||
role: "MEMBER" | "ADMIN";
|
||
}
|
||
|
||
export interface Notification {
|
||
id: GeneratedAlways<number>;
|
||
type: NotificationValue["type"];
|
||
meta: JSONColumnTypeNullable<Record<string, number | string>>;
|
||
pictureUrl: string | null;
|
||
createdAt: GeneratedAlways<number>;
|
||
}
|
||
|
||
export interface NotificationUser {
|
||
notificationId: number;
|
||
userId: number;
|
||
seen: Generated<DBBoolean>;
|
||
}
|
||
|
||
export interface NotificationSubscription {
|
||
endpoint: string;
|
||
keys: {
|
||
auth: string;
|
||
p256dh: string;
|
||
};
|
||
}
|
||
|
||
/** A subscription of user's browser indicating where push notifications can be sent to. */
|
||
export interface NotificationUserSubscription {
|
||
id: GeneratedAlways<number>;
|
||
userId: number;
|
||
subscription: JSONColumnType<NotificationSubscription>;
|
||
}
|
||
|
||
export interface RoomLink {
|
||
userId: number;
|
||
url: string;
|
||
createdAt: Generated<number>;
|
||
refreshedAt: Generated<number>;
|
||
}
|
||
|
||
export const SPLATOON_ROTATION_TYPES = ["SERIES", "OPEN", "X"] as const;
|
||
export type SplatoonRotationType = (typeof SPLATOON_ROTATION_TYPES)[number];
|
||
|
||
export interface SplatoonRotation {
|
||
id: GeneratedAlways<number>;
|
||
type: SplatoonRotationType;
|
||
mode: string;
|
||
stageId1: number;
|
||
stageId2: number;
|
||
startTime: number;
|
||
endTime: number;
|
||
}
|
||
|
||
export type Tables = { [P in keyof DB]: Selectable<DB[P]> };
|
||
export type TablesInsertable = { [P in keyof DB]: Insertable<DB[P]> };
|
||
export type TablesUpdatable = { [P in keyof DB]: Updateable<DB[P]> };
|
||
|
||
export interface DB {
|
||
AllTeam: Team;
|
||
AllTeamMember: TeamMember;
|
||
ApiToken: ApiToken;
|
||
Art: Art;
|
||
LiveStream: LiveStream;
|
||
ArtTag: ArtTag;
|
||
ArtUserMetadata: ArtUserMetadata;
|
||
TaggedArt: TaggedArt;
|
||
Badge: Badge;
|
||
BadgeManager: BadgeManager;
|
||
BadgeOwner: BadgeOwner;
|
||
TournamentBadgeOwner: TournamentBadgeOwner;
|
||
BanLog: BanLog;
|
||
ModNote: ModNote;
|
||
Build: Build;
|
||
BuildAbilitySum: BuildAbilitySum;
|
||
BuildWeapon: BuildWeapon;
|
||
BuildWeaponAbility: BuildWeaponAbility;
|
||
CalendarEvent: CalendarEvent;
|
||
CalendarEventBadge: CalendarEventBadge;
|
||
CalendarEventDate: CalendarEventDate;
|
||
CalendarEventResultPlayer: CalendarEventResultPlayer;
|
||
CalendarEventResultTeam: CalendarEventResultTeam;
|
||
|
||
Group: Group;
|
||
GroupLike: GroupLike;
|
||
GroupMatch: GroupMatch;
|
||
GroupMatchContinueVote: GroupMatchContinueVote;
|
||
GroupMatchMap: GroupMatchMap;
|
||
GroupMember: GroupMember;
|
||
PrivateUserNote: PrivateUserNote;
|
||
LogInLink: LogInLink;
|
||
LFGPost: LFGPost;
|
||
MapPoolMap: MapPoolMap;
|
||
MapResult: MapResult;
|
||
PlayerResult: PlayerResult;
|
||
PlusSuggestion: PlusSuggestion;
|
||
PlusTier: PlusTier;
|
||
PlusVote: PlusVote;
|
||
PlusVotingResult: PlusVotingResult;
|
||
RoomLink: RoomLink;
|
||
ReportedWeapon: ReportedWeapon;
|
||
Skill: Skill;
|
||
SkillTeamUser: SkillTeamUser;
|
||
SeedingSkill: SeedingSkill;
|
||
SplatoonPlayer: SplatoonPlayer;
|
||
Team: Team;
|
||
TeamMember: TeamMember;
|
||
TeamMemberWithSecondary: TeamMember;
|
||
Tournament: Tournament;
|
||
TournamentStaff: TournamentStaff;
|
||
TournamentGroup: TournamentGroup;
|
||
TournamentLFGLike: TournamentLFGLike;
|
||
TournamentMatch: TournamentMatch;
|
||
TournamentMatchPickBanEvent: TournamentMatchPickBanEvent;
|
||
TournamentMatchGameResult: TournamentMatchGameResult;
|
||
TournamentMatchGameResultParticipant: TournamentMatchGameResultParticipant;
|
||
TournamentResult: TournamentResult;
|
||
TournamentRound: TournamentRound;
|
||
TournamentStage: TournamentStage;
|
||
TournamentSub: TournamentSub;
|
||
TournamentTeam: TournamentTeam;
|
||
TournamentTeamCheckIn: TournamentTeamCheckIn;
|
||
TournamentTeamMember: TournamentTeamMember;
|
||
TournamentOrganization: TournamentOrganization;
|
||
TournamentOrganizationMember: TournamentOrganizationMember;
|
||
TournamentOrganizationBadge: TournamentOrganizationBadge;
|
||
TournamentOrganizationSeries: TournamentOrganizationSeries;
|
||
TournamentBracketProgressionOverride: TournamentBracketProgressionOverride;
|
||
TournamentOrganizationBannedUser: TournamentOrganizationBannedUser;
|
||
TournamentStreamer: TournamentStreamer;
|
||
TournamentMatchVod: TournamentMatchVod;
|
||
TrustRelationship: TrustRelationship;
|
||
Friendship: Friendship;
|
||
FriendRequest: FriendRequest;
|
||
UnvalidatedUserSubmittedImage: UnvalidatedUserSubmittedImage;
|
||
UnvalidatedVideo: UnvalidatedVideo;
|
||
User: User;
|
||
UserResultHighlight: UserResultHighlight;
|
||
UserSubmittedImage: UserSubmittedImage;
|
||
UserWeapon: UserWeapon;
|
||
UserFriendCode: UserFriendCode;
|
||
UserWidget: UserWidget;
|
||
Video: Video;
|
||
VideoMatch: VideoMatch;
|
||
VideoMatchPlayer: VideoMatchPlayer;
|
||
XRankPlacement: XRankPlacement;
|
||
ScrimPost: ScrimPost;
|
||
ScrimPostUser: ScrimPostUser;
|
||
ScrimPostRequest: ScrimPostRequest;
|
||
ScrimPostRequestUser: ScrimPostRequestUser;
|
||
Association: Association;
|
||
AssociationMember: AssociationMember;
|
||
Notification: Notification;
|
||
NotificationUser: NotificationUser;
|
||
NotificationUserSubscription: NotificationUserSubscription;
|
||
SavedCalendarEvent: SavedCalendarEvent;
|
||
SplatoonRotation: SplatoonRotation;
|
||
}
|