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, MainWeaponId, ModeShort, StageId, } from "~/modules/in-game-lists/types"; import type { JSONColumnTypeNullable } from "~/utils/kysely.server"; type Generated = T extends ColumnType ? ColumnType : ColumnType; export type MemberRole = (typeof TEAM_MEMBER_ROLES)[number]; /** In SQLite booleans are presented as 0 (false) and 1 (true) */ export type DBBoolean = number; export interface Team { avatarImgId: number | null; bannerImgId: number | null; bio: string | null; createdAt: Generated; css: JSONColumnTypeNullable>; customUrl: string; deletedAt: number | null; id: GeneratedAlways; inviteCode: string; name: string; bsky: string | null; /** 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; isOwner: Generated; isManager: Generated; leftAt: number | null; role: MemberRole | null; teamId: number; userId: number; isMainTeam: DBBoolean; } export interface Art { authorId: number; createdAt: Generated; description: string | null; id: GeneratedAlways; imgId: number; isShowcase: Generated; } export interface ArtTag { authorId: number; createdAt: Generated; id: GeneratedAlways; name: string; } export interface ArtUserMetadata { artId: number; userId: number; } export interface TaggedArt { artId: number; tagId: number; } export interface Badge { id: GeneratedAlways; 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; /** 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; }; export interface Build { clothesGearSplId: number; description: string | null; headGearSplId: number; id: GeneratedAlways; modes: JSONColumnTypeNullable; ownerId: number; private: DBBoolean | null; shoesGearSplId: number; title: string; updatedAt: Generated; } export type GearType = "HEAD" | "CLOTHES" | "SHOES"; export interface BuildAbility { ability: Ability; buildId: number; gearType: GearType; slotIndex: number; /** 10 if main ability, 3 if sub */ abilityPoints: GeneratedAlways; } export interface BuildWeapon { buildId: number; weaponSplId: MainWeaponId; /** Has the owner of this build reached top 500 of X Rank with this weapon? Denormalized for performance reasons. */ isTop500: Generated; /** Plus tier or 4 if none. Denormalized for performance reasons. */ tier: Generated; /** Last time the build was updated. Denormalized for performance reasons. */ updatedAt: Generated; } export type CalendarEventTag = keyof typeof tags; export interface CalendarEvent { authorId: number; bracketUrl: string; description: string | null; discordInviteCode: string | null; id: GeneratedAlways; discordUrl: GeneratedAlways; name: string; participantCount: number | null; tags: string | null; hidden: Generated; tournamentId: number | null; organizationId: number | null; avatarImgId: number | null; } export interface CalendarEventBadge { badgeId: number; eventId: number; } export interface CalendarEventDate { eventId: number; id: GeneratedAlways; startTime: number; } export interface CalendarEventResultPlayer { name: string | null; teamId: number; userId: number | null; } export interface CalendarEventResultTeam { eventId: number; id: GeneratedAlways; name: string; placement: number; } export interface FreshPlusTier { tier: number | null; userId: number; } export interface Group { chatCode: string | null; createdAt: Generated; id: GeneratedAlways; inviteCode: string; latestActionAt: Generated; status: "PREPARING" | "ACTIVE" | "INACTIVE"; teamId: number | null; } export interface GroupLike { createdAt: Generated; 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; } | 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> >; /** mapPreferences of season 2 */ mapPreferences?: Array<{ userId: number; preference?: Preference }[]>; pools: Array<{ userId: number; pool: UserMapModePreferences["pool"] }>; }; export interface GroupMatch { alphaGroupId: number; bravoGroupId: number; chatCode: string | null; createdAt: Generated; id: GeneratedAlways; memento: JSONColumnTypeNullable; reportedAt: number | null; reportedByUserId: number | null; } export interface GroupMatchMap { id: GeneratedAlways; index: number; matchId: number; mode: ModeShort; source: string; stageId: StageId; winnerGroupId: number | null; } export interface GroupMember { createdAt: Generated; 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; } /** 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; type: LFGType; text: string; /** e.g. Europe/Helsinki */ timezone: string; authorId: number; teamId: number | null; plusTierVisibility: number | null; languages: string | null; updatedAt: Generated; createdAt: GeneratedAlways; } 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; id: GeneratedAlways; 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; passedVoting: DBBoolean; } export interface ReportedWeapon { groupMatchMapId: number | null; userId: number; weaponSplId: MainWeaponId; } export interface Skill { groupMatchId: number | null; id: GeneratedAlways; 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; 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; } export interface CastedMatchesInfo { /** Array for match ID's that are locked because they are pending to be casted */ lockedMatches: number[]; /** What matches are streamed currently & where */ castedMatches: { twitchAccount: string; matchId: number }[]; } export interface Tournament { settings: JSONColumnType; id: GeneratedAlways; 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; castedMatchesInfo: JSONColumnTypeNullable; 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; /** Snapshot of teams and rosters when seeds were last saved. Used to detect NEW teams/players. */ seedingSnapshot: JSONColumnTypeNullable; /** 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; } export interface SeedingSnapshot { savedAt: number; teams: Array<{ teamId: number; members: Array<{ userId: number; username: string }>; }>; } export interface PreparedMaps { authorId: number; createdAt: number; maps: Array; eliminationTeamCount?: number; } export interface TournamentBadgeOwner { badgeId: number; userId: number; tournamentId: number | null; } /** 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; 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; opponentOne: JSONColumnType; opponentTwo: JSONColumnType; 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"; stageId: StageId; mode: ModeShort; matchId: number; authorId: number; number: number; createdAt: GeneratedAlways; } export interface TournamentMatchGameResult { createdAt: Generated; id: GeneratedAlways; 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; 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; /** 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; } /** * 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; stageId: number; maps: JSONColumnType; } // when updating this also update `defaultBracketSettings` in tournament-utils.ts export interface TournamentStageSettings { // SE thirdPlaceMatch?: boolean; // RR teamsPerGroup?: number; // 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; 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; message: string | null; okWeapons: string | null; tournamentId: number; userId: number; visibility: "+1" | "+2" | "+3" | "ALL"; } export interface TournamentStaff { tournamentId: number; userId: number; role: "ORGANIZER" | "STREAMER"; } export interface TournamentTeam { createdAt: Generated; id: GeneratedAlways; inviteCode: string; name: string; prefersNotToHost: Generated; droppedOut: Generated; seed: number | null; /** For formats that have many starting brackets, where should the team start? */ startingBracketIdx: number | null; activeRosterUserIds: JSONColumnTypeNullable; tournamentId: number; teamId: number | null; avatarImgId: 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; } export interface TournamentTeamMember { createdAt: Generated; isOwner: Generated; inGameName: string | null; tournamentTeamId: number; userId: number; } export interface TournamentOrganization { id: GeneratedAlways; name: string; slug: string; description: string | null; socials: JSONColumnTypeNullable; avatarImgId: number | null; isEstablished: Generated; } 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; organizationId: number; name: string; description: string | null; substringMatches: JSONColumnType; showLeaderboard: Generated; tierHistory: JSONColumnTypeNullable; } export interface TournamentBracketProgressionOverride { sourceBracketIdx: number; destinationBracketIdx: number; tournamentTeamId: number; tournamentId: number; } export interface TournamentOrganizationBannedUser { organizationId: number; userId: number; privateNote: string | null; updatedAt: Generated; 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; } export interface UnvalidatedUserSubmittedImage { id: GeneratedAlways; 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; 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; } 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; bannedReason: string | null; bio: string | null; commissionsOpen: Generated; commissionsOpenedAt: number | null; commissionText: string | null; country: string | null; css: JSONColumnTypeNullable>; customUrl: string | null; discordAvatar: string | null; discordId: string; discordName: string; customName: string | null; /** coalesce(customName, discordName) */ username: ColumnType; 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; id: GeneratedAlways; inGameName: string | null; isArtist: Generated; isVideoAdder: Generated; isTournamentOrganizer: Generated; isApiAccesser: Generated; languages: string | null; motionSens: number | null; pronouns: JSONColumnTypeNullable; patronSince: number | null; patronTier: number | null; patronTill: number | null; showDiscordUniqueName: Generated; stickSens: number | null; twitch: string | null; bsky: string | null; battlefy: string | null; vc: Generated<"YES" | "NO" | "LISTEN_ONLY">; youtubeId: string | null; mapModePreferences: JSONColumnTypeNullable; qWeaponPool: JSONColumnTypeNullable; plusSkippedForSeasonNth: number | null; noScreen: Generated; buildSorting: JSONColumnTypeNullable; preferences: JSONColumnTypeNullable; /** User creation date. Can be null because we did not always save this. */ createdAt: 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; submitterUserId: number | null; url: string; validatedAt: number | null; } export interface UserWeapon { createdAt: Generated; isFavorite: Generated; order: number; userId: number; weaponSplId: MainWeaponId; } export interface UserFriendCode { friendCode: string; userId: number; submitterUserId: number; createdAt: GeneratedAlways; } export interface UserWidget { userId: number; index: number; widget: JSONColumnType; } export type ApiTokenType = "read" | "write"; export interface ApiToken { id: GeneratedAlways; userId: number; token: string; type: Generated; createdAt: GeneratedAlways; } export interface LiveStream { id: GeneratedAlways; userId: number | null; viewerCount: number; thumbnailUrl: string; twitch: string | null; } export interface BanLog { id: GeneratedAlways; userId: number; banned: number | null; bannedReason: string | null; bannedByUserId: number; createdAt: GeneratedAlways; } export interface ModNote { id: GeneratedAlways; userId: number; authorId: number; text: string; createdAt: GeneratedAlways; isDeleted: Generated; } export interface Video { eventId: number | null; id: GeneratedAlways; submitterUserId: number; title: string; type: "SCRIM" | "TOURNAMENT" | "MATCHMAKING" | "CAST" | "SENDOUQ"; validatedAt: number | null; youtubeDate: number; youtubeId: string; } export interface VideoMatch { id: GeneratedAlways; 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; 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; /** 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; /** 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; /** 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; updatedAt: Generated; } export interface ScrimPostUser { scrimPostId: number; userId: number; /** User is the author of the post */ isOwner: number; } export interface ScrimPostRequest { id: GeneratedAlways; scrimPostId: number; teamId: number | null; message: string | null; /** Specific time selected by requester (required when post has rangeEnd) */ at: number | null; isAccepted: Generated; createdAt: GeneratedAlways; } export interface ScrimPostRequestUser { scrimPostRequestId: number; /** User that made the request */ userId: number; isOwner: DBBoolean; } export interface Association { id: GeneratedAlways; name: string; inviteCode: string; createdAt: GeneratedAlways; } export interface AssociationMember { userId: number; associationId: number; role: "MEMBER" | "ADMIN"; } export interface Notification { id: GeneratedAlways; type: NotificationValue["type"]; meta: JSONColumnTypeNullable>; pictureUrl: string | null; createdAt: GeneratedAlways; } export interface NotificationUser { notificationId: number; userId: number; seen: Generated; } 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; userId: number; subscription: JSONColumnType; } export type Tables = { [P in keyof DB]: Selectable }; export type TablesInsertable = { [P in keyof DB]: Insertable }; export type TablesUpdatable = { [P in keyof DB]: Updateable }; 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; BuildAbility: BuildAbility; BuildWeapon: BuildWeapon; CalendarEvent: CalendarEvent; CalendarEventBadge: CalendarEventBadge; CalendarEventDate: CalendarEventDate; CalendarEventResultPlayer: CalendarEventResultPlayer; CalendarEventResultTeam: CalendarEventResultTeam; FreshPlusTier: FreshPlusTier; Group: Group; GroupLike: GroupLike; GroupMatch: GroupMatch; GroupMatchMap: GroupMatchMap; GroupMember: GroupMember; PrivateUserNote: PrivateUserNote; LogInLink: LogInLink; LFGPost: LFGPost; MapPoolMap: MapPoolMap; MapResult: MapResult; PlayerResult: PlayerResult; PlusSuggestion: PlusSuggestion; PlusTier: PlusTier; PlusVote: PlusVote; PlusVotingResult: PlusVotingResult; ReportedWeapon: ReportedWeapon; Skill: Skill; SkillTeamUser: SkillTeamUser; SeedingSkill: SeedingSkill; SplatoonPlayer: SplatoonPlayer; Team: Team; TeamMember: TeamMember; TeamMemberWithSecondary: TeamMember; Tournament: Tournament; TournamentStaff: TournamentStaff; TournamentGroup: TournamentGroup; 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; TrustRelationship: TrustRelationship; 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; }