osu-web.js
Version:
osu.js is an unofficial Javascript and Typescript SDK for the browser-facing portion of osu! with type safety in mind
1,722 lines (1,710 loc) • 89.4 kB
TypeScript
import polyfillFetch, { Response as Response$1 } from 'node-fetch';
declare class Base$1 {
protected clientId: number;
protected clientSecret: string;
protected redirectUri: string;
protected oauthUrl: string;
protected fetch: typeof fetch | typeof polyfillFetch;
constructor(clientId: number, clientSecret: string, redirectUri: string, options?: {
polyfillFetch?: typeof polyfillFetch;
});
}
declare const isOsuJSErrorSymbol: unique symbol;
/**
* Documentation: {@link https://osujs.mario564.com/extras/error-handling}
*/
declare class OsuJSGeneralError extends Error {
readonly _: {
[isOsuJSErrorSymbol]: boolean;
};
type: 'invalid_json_syntax' | 'network_error' | 'undefined_fetch';
constructor(type: 'invalid_json_syntax' | 'network_error' | 'undefined_fetch');
}
/**
* Documentation: {@link https://osujs.mario564.com/extras/error-handling}
*/
declare class OsuJSUnexpectedResponseError extends Error {
readonly _: {
[isOsuJSErrorSymbol]: boolean;
};
type: "unexpected_response";
private response1;
constructor(response: Response | Response$1);
response<T extends boolean | undefined = undefined>(polyfill?: T): T extends true ? Response$1 : Response;
}
/**
* Documentation: {@link https://osujs.mario564.com/references/modes-enum}
*/
declare enum ModesEnum {
osu = 0,
taiko = 1,
fruits = 2,
mania = 3
}
/**
* Documentation: {@link https://osujs.mario564.com/references/status-enum}
*/
declare enum StatusEnum {
graveyard = -2,
wip = -1,
pending = 0,
ranked = 1,
approved = 2,
qualified = 3,
loved = 4
}
/**
* Documentation: {@link https://osujs.mario564.com/references/genres-enum}
*/
declare enum GenresEnum {
Any = 0,
Unspecified = 1,
'Video Game' = 2,
Anime = 3,
Rock = 4,
Pop = 5,
Other = 6,
Novelty = 7,
'Hip Hop' = 9,
Electronic = 10,
Metal = 11,
Classical = 12,
Folk = 13,
Jazz = 14
}
/**
* Documentation: {@link https://osujs.mario564.com/references/languages-enum}
*/
declare enum LanguagesEnum {
Any = 0,
Unspecified = 1,
English = 2,
Japanese = 3,
Chinese = 4,
Instrumental = 5,
Korean = 6,
French = 7,
German = 8,
Swedish = 9,
Spanish = 10,
Italian = 11,
Russian = 12,
Polish = 13,
Other = 14
}
/**
* Documentation: {@link https://osujs.mario564.com/references/mods-enum}
*/
declare enum ModsEnum {
NF = 1,
EZ = 2,
TD = 4,
HD = 8,
HR = 16,
SD = 32,
DT = 64,
RX = 128,
HT = 256,
NC = 512,
FL = 1024,
AT = 2048,
SO = 4096,
AP = 8192,
PF = 16384,
'4K' = 32768,
'5K' = 65536,
'6K' = 131072,
'7K' = 262144,
'8K' = 524288,
FI = 1048576,
RD = 2097152,
CN = 4194304,
TP = 8388608,
K9 = 16777216,
KC = 33554432,
'1K' = 67108864,
'3K' = 134217728,
'2K' = 268435456,
SV2 = 536870912,
MR = 1073741824
}
/**
* Documentation: {@link https://osujs.mario564.com/references/scoring-type-enum}
*/
declare enum ScoringTypeEnum {
Score = 0,
Accuracy = 1,
Combo = 2,
'Score V2' = 3
}
/**
* Documentation: {@link https://osujs.mario564.com/references/team-type-enum}
*/
declare enum TeamTypeEnum {
'Head To Head' = 0,
'Tag Co-Op' = 1,
'Team VS' = 2,
'Tag Team VS' = 3
}
/**
* Documentation: {@link https://osujs.mario564.com/references/team-color-enum}
*/
declare enum TeamColorEnum {
Blue = 1,
Red = 2
}
type BaseMod<TAcronym extends string, TSettings extends Record<string, any> | undefined = undefined> = TSettings extends undefined ? {
acronym: TAcronym;
} : {
acronym: TAcronym;
settings?: TSettings;
};
type EasyMod = BaseMod<'EZ', {
retries: number;
}>;
type NoFailMod = BaseMod<'NF'>;
type HalfTimeMod = BaseMod<'HT', {
speed_change: number;
adjust_pitch: boolean;
}>;
type DaycoreMod = BaseMod<'DC', {
speed_change: number;
}>;
type HardRockMod = BaseMod<'HR'>;
type SuddenDeathMod = BaseMod<'SD', {
restart: boolean;
}>;
type PerfectMod = BaseMod<'PF', {
restart: boolean;
}>;
type DoubleTimeMod = BaseMod<'DT', {
speed_change: number;
adjust_pitch: boolean;
}>;
type NightcoreMod = BaseMod<'NC', {
speed_change: number;
}>;
type HiddenMod = BaseMod<'HD', {
only_fade_approach_circles: boolean;
}>;
type FlaslightMod = BaseMod<'FL', {
follow_delay: number;
size_multiplier: number;
combo_based_size: boolean;
}>;
type BlindsMod = BaseMod<'BL'>;
type StrictTrackingMod = BaseMod<'ST'>;
type AccuracyChallengeMod = BaseMod<'AC', {
minimum_accuracy: number;
accuracy_judge_mode: string;
restart: boolean;
}>;
type TargetPracticeMod = BaseMod<'TP', {
seed: number;
metronome: boolean;
}>;
type DifficultyAdjustMod = BaseMod<'DA', {
circle_size: number;
approach_rate: number;
drain_rate: number;
overall_difficulty: number;
extended_limits: boolean;
}>;
type ClassicMod = BaseMod<'CL', {
no_slider_head_accuracy: boolean;
classic_note_lock: boolean;
always_play_tail_sample: boolean;
fade_hit_circle_early: boolean;
classic_health: boolean;
}>;
type RandomMod = BaseMod<'RD', {
angle_sharpness: number;
seed: number;
}>;
type MirrorMod = BaseMod<'MR', {
reflection: string;
}>;
type AlternateMod = BaseMod<'AL'>;
type SingleTapMod = BaseMod<'SG'>;
type AutoplayMod = BaseMod<'AT'>;
type CinemaMod = BaseMod<'CN'>;
type RelaxMod = BaseMod<'RX'>;
type AutopilotMod = BaseMod<'AP'>;
type SpunOutMod = BaseMod<'SO'>;
type TransformMod = BaseMod<'TR'>;
type WiggleMod = BaseMod<'WG', {
strength: number;
}>;
type SpinInMod = BaseMod<'SI'>;
type GrowMod = BaseMod<'GR', {
start_scale: number;
}>;
type DeflateMod = BaseMod<'DF', {
start_scale: number;
}>;
type WindUpMod = BaseMod<'WU', {
initial_rate: number;
final_rate: number;
adjust_pitch: boolean;
}>;
type WindDownMod = BaseMod<'WD', {
initial_rate: number;
final_rate: number;
adjust_pitch: boolean;
}>;
type TraceableMod = BaseMod<'TC'>;
type BarrelRollMod = BaseMod<'BR', {
spin_speed: number;
direction: string;
}>;
type ApproachDifferentMod = BaseMod<'AD', {
scale: number;
style: string;
}>;
type MutedMod = BaseMod<'MU', {
inverse_muting: boolean;
enable_metronome: boolean;
mute_combo_count: number;
affects_hit_sounds: boolean;
}>;
type NoScopeMod = BaseMod<'NS', {
hidden_combo_count: number;
}>;
type MagnetisedMod = BaseMod<'MG', {
attraction_strength: number;
}>;
type RepelMod = BaseMod<'RP', {
repulsion_strength: number;
}>;
type AdaptiveSpeedMod = BaseMod<'AS', {
initial_rate: number;
adjust_pitch: boolean;
}>;
type FreezeFrameMod = BaseMod<'FR'>;
type BubblesMod = BaseMod<'BU'>;
type SynesthesiaMod = BaseMod<'SY'>;
type DepthMod = BaseMod<'DP', {
max_depth: number;
show_approach_circles: boolean;
}>;
type TouchDeviceMod = BaseMod<'TD'>;
type ScoreV2Mod = BaseMod<'SV2'>;
type SwapMod = BaseMod<'SW'>;
type FloatingFruitsMod = BaseMod<'FF'>;
type FadeInMod = BaseMod<'FI', {
coverage: number;
}>;
type DualStagesMod = BaseMod<'DS'>;
type InvertMod = BaseMod<'IN'>;
type ConstantSpeedMod = BaseMod<'CS'>;
type HoldOffMod = BaseMod<'HO'>;
type Key1Mod = BaseMod<'1K'>;
type Key2Mod = BaseMod<'2K'>;
type Key3Mod = BaseMod<'3K'>;
type Key4Mod = BaseMod<'4K'>;
type Key5Mod = BaseMod<'5K'>;
type Key6Mod = BaseMod<'6K'>;
type Key7Mod = BaseMod<'7K'>;
type Key8Mod = BaseMod<'8K'>;
type Key9Mod = BaseMod<'9K'>;
type Key10Mod = BaseMod<'10K'>;
type ModSettings = EasyMod | NoFailMod | HalfTimeMod | DaycoreMod | HardRockMod | SuddenDeathMod | PerfectMod | DoubleTimeMod | NightcoreMod | HiddenMod | FlaslightMod | BlindsMod | StrictTrackingMod | AccuracyChallengeMod | TargetPracticeMod | DifficultyAdjustMod | ClassicMod | RandomMod | MirrorMod | AlternateMod | SingleTapMod | AutoplayMod | CinemaMod | RelaxMod | AutopilotMod | SpunOutMod | TransformMod | WiggleMod | SpinInMod | GrowMod | DeflateMod | WindUpMod | WindDownMod | TraceableMod | BarrelRollMod | ApproachDifferentMod | MutedMod | NoScopeMod | MagnetisedMod | RepelMod | AdaptiveSpeedMod | FreezeFrameMod | BubblesMod | SynesthesiaMod | DepthMod | TouchDeviceMod | ScoreV2Mod | SwapMod | FloatingFruitsMod | FadeInMod | DualStagesMod | InvertMod | ConstantSpeedMod | HoldOffMod | Key1Mod | Key2Mod | Key3Mod | Key4Mod | Key5Mod | Key6Mod | Key7Mod | Key8Mod | Key9Mod | Key10Mod;
/**
* Timestamp string in ISO 8601 format
*/
type ISOTimestamp = string;
/**
* Documentation: {@link https://osujs.mario564.com/extras/error-handling}
*/
type OsuJSError = OsuJSGeneralError | OsuJSUnexpectedResponseError;
type Cursor = string | null;
type SafeParse<TData, TUsePolyfillResponse extends boolean = false> = {
success: true;
data: TData;
} | {
success: false;
response: TUsePolyfillResponse extends true ? Response$1 : Response;
};
type Mod = keyof typeof ModsEnum | 'DC' | 'BL' | 'ST' | 'AC' | 'DA' | 'CL' | 'AL' | 'SG' | 'TR' | 'WG' | 'SI' | 'GR' | 'DF' | 'WU' | 'WD' | 'TC' | 'BR' | 'AD' | 'MU' | 'NS' | 'MG' | 'RP' | 'AS' | 'FR' | 'BU' | 'SY' | 'DP' | 'SW' | 'FF' | 'DS' | 'IN' | 'CS' | 'HO' | '9K' | '10K';
type RankStatus = keyof typeof StatusEnum;
type GameMode = 'fruits' | 'mania' | 'osu' | 'taiko';
type UserBeatmapsType = 'favourite' | 'graveyard' | 'guest' | 'loved' | 'most_played' | 'nominated' | 'pending' | 'ranked';
type CommentableType = 'beatmapset' | 'news_post' | 'build';
type CommentSort = 'new' | 'old' | 'top';
type MultiplayerScoresSort = 'score_asc' | 'score_desc';
type RankingType = 'charts' | 'country' | 'performance' | 'score';
type UserScoreType = 'best' | 'firsts' | 'recent';
type ChangelogStream = 'stable40' | 'beta40' | 'cuttingedge' | 'lazer' | 'web';
type DiscussionMessageType = 'suggestion' | 'problem' | 'mapper_note' | 'praise' | 'hype' | 'review';
type Playstyle = 'mouse' | 'keyboard' | 'tablet' | 'touch';
type Scope = 'chat.read' | 'chat.write' | 'chat.write_manage' | 'delegate' | 'forum.write' | 'friends.read' | 'identify' | 'public';
type ProfilePageSection = 'me' | 'recent_activity' | 'beatmaps' | 'historical' | 'kudosu' | 'top_ranks' | 'medals';
type UserAccountHistoryType = 'note' | 'restriction' | 'silence';
type KudosuAction = 'give' | 'vote.give' | 'reset' | 'vote.reset' | 'revoke' | 'vote.revoke';
type Rank = 'SS' | 'SSH' | 'S' | 'SH' | 'A' | 'B' | 'C' | 'D' | 'F';
type UserEventType = 'achievement' | 'beatmapPlaycount' | 'beatmapsetApprove' | 'beatmapsetDelete' | 'beatmapsetRevive' | 'beatmapsetUpdate' | 'beatmapsetUpload' | 'rank' | 'rankLost' | 'userSupportAgain' | 'userSupportFirst' | 'userSupportGift' | 'usernameChange';
type AchievementGrouping = 'Skill' | 'Hush-Hush' | 'Dedication' | 'Mod Introduction';
type EventBeatmapsetApprovedType = 'ranked' | 'approved' | 'qualified' | 'loved';
type SpotlightType = 'monthly' | 'spotlight' | 'theme' | 'special' | 'bestof';
type ChannelType = 'PUBLIC' | 'PRIVATE' | 'MULTIPLAYER' | 'SPECTATOR' | 'TEMPORARY' | 'PM' | 'GROUP' | 'ANNOUNCE';
type ChatMessageType = 'action' | 'markdown' | 'plain';
type ForumTopicType = 'normal' | 'sticky' | 'announcement';
interface Token {
token_type: string;
expires_in: number;
access_token: string;
refresh_token: string;
}
type GuestToken = Omit<Token, 'refresh_token'>;
interface UserCompact {
avatar_url: string;
country_code: string;
default_group: string;
id: number;
is_active: boolean;
is_bot: boolean;
is_deleted: boolean;
is_online: boolean;
is_supporter: boolean;
last_visit: string;
pm_friends_only: boolean;
profile_colour: string | null;
username: string;
}
interface Country {
code: string;
name: string;
}
interface Cover {
custom_url: string | null;
url: string;
id: string | null;
}
interface UserKudosu {
available: number;
total: number;
}
interface User extends UserCompact {
country: Country;
cover: Cover;
discord: string | null;
has_supported: boolean;
interests: string | null;
join_date: ISOTimestamp;
kudosu: UserKudosu;
location: string | null;
max_blocks: number;
max_friends: number;
occupation: string | null;
playmode: GameMode;
playstyle: Playstyle[];
post_count: number;
profile_order: ProfilePageSection[];
title: string | null;
title_url: string | null;
twitter: string | null;
website: string | null;
}
interface UserAccountHistory {
description: string | null;
id: number;
length: number;
permanent: boolean;
timestamp: string;
type: UserAccountHistoryType;
}
interface UserActiveTournamentBanner {
id: number;
tournament_id: number;
image: string | null;
'image@2x': string | null;
}
interface UserBadge {
awarded_at: ISOTimestamp;
description: string;
image_url: string;
'image@2x_url': string;
url: string;
}
interface Page {
html: string;
raw: string;
}
interface Group {
colour: string | null;
has_listing: boolean;
has_playmodes: boolean;
id: number;
identifier: string;
is_probationary: boolean;
name: string;
short_name: string;
}
interface UserGroup extends Group {
playmodes: GameMode[] | null;
}
interface MonthlyPlaycount {
start_date: ISOTimestamp;
count: number;
}
interface RankHighest {
rank: number;
updated_at: ISOTimestamp;
}
interface RankHistory {
mode: GameMode;
data: number[];
}
interface GradeCounts {
a: number;
s: number;
sh: number;
ss: number;
ssh: number;
}
interface UserLevel {
current: number;
progress: number;
}
interface UserStatisticsVariant {
mode: GameMode;
variant: string;
country_rank: number;
global_rank: number;
pp: number;
}
interface UserStatistics {
count_100: number;
count_300: number;
count_50: number;
count_miss: number;
grade_counts: GradeCounts;
hit_accuracy: number;
is_ranked: boolean;
level: UserLevel;
maximum_combo: number;
play_count: number;
play_time: number;
pp: number;
pp_exp: number;
global_rank: number | null;
global_rank_exp: number | null;
ranked_score: number;
replays_watched_by_others: number;
total_hits: number;
total_score: number;
country_rank: number | null;
variants?: UserStatisticsVariant[];
}
interface UserAchievement {
achieved_at: ISOTimestamp;
achievement_id: number;
}
interface UserExtended extends User {
account_history: UserAccountHistory[];
active_tournament_banners: UserActiveTournamentBanner[];
active_tournament_banner: UserActiveTournamentBanner | null;
badges: UserBadge[];
beatmap_playcounts_count: number;
favourite_beatmapset_count: number;
follower_count: number;
graveyard_beatmapset_count: number;
groups: UserGroup[];
loved_beatmapset_count: number;
mapping_follower_count: number;
monthly_playcounts: MonthlyPlaycount[];
page: Page;
pending_beatmapset_count: number;
previous_usernames: string[];
rank_highest: RankHighest | null;
rank_history: RankHistory;
ranked_beatmapset_count: number;
replays_watched_counts: MonthlyPlaycount[];
scores_best_count: number;
scores_first_count: number;
scores_recent_count: number;
statistics: UserStatistics;
support_level: number;
user_achievements: UserAchievement[];
}
interface Giver {
url: string;
username: string;
}
interface Post {
url: string | null;
title: string;
}
interface UserKudosuHistory {
id: number;
action: KudosuAction;
amount: number;
model: string;
created_at: ISOTimestamp;
giver: Giver | null;
post: Post;
}
type StatisticsRulesets = Record<GameMode, UserStatistics | undefined>;
interface BeatmapCompact {
beatmapset_id: number;
difficulty_rating: number;
id: number;
mode: GameMode;
status: RankStatus;
total_length: number;
user_id: number;
version: string;
}
interface ScoreStatistics {
count_50: number;
count_100: number;
count_300: number;
count_geki: number | null;
count_katu: number | null;
count_miss: number;
}
interface Score {
id: number;
best_id: number;
user_id: number;
accuracy: number;
mods: Mod[];
score: number;
max_combo: number;
perfect: boolean;
statistics: ScoreStatistics;
passed: boolean;
pp: number;
rank: Rank;
created_at: ISOTimestamp;
mode: GameMode;
mode_int: number;
replay: boolean;
}
interface ScoreV2 {
accuracy: number;
beatmap_id: number;
best_id: number | null;
build_id: number | null;
classic_total_score: number | null;
ended_at: ISOTimestamp;
has_replay: boolean;
id: number;
is_perfect_combo: boolean;
legacy_perfect: boolean;
legacy_score_id: number | null;
legacy_total_score: number;
max_combo: number;
maximum_statistics: ScoreStatistics;
mods: ModSettings[];
passed: boolean;
playlist_item_id: number | null;
pp: number | null;
preserve: boolean | null;
processed: boolean | null;
rank: Rank;
room_id: number | null;
ruleset_id: number;
started_at: ISOTimestamp | null;
statistics: ScoreStatistics;
total_score: number;
type: string;
user_id: number;
}
interface Covers {
cover: string;
'cover@2x': string;
card: string;
'card@2x': string;
list: string;
'list@2x': string;
slimcover: string;
'slimcover@2x': string;
}
interface BeatmapsetCompact {
artist: string;
artist_unicode: string;
covers: Covers;
creator: string;
favourite_count: number;
id: number;
nsfw: boolean;
play_count: number;
preview_url: string;
source: string;
status: RankStatus;
title: string;
title_unicode: string;
user_id: string;
video: boolean;
}
interface UserScore extends Score {
beatmap: BeatmapCompact & {
checksum: string | null;
};
beatmapset: BeatmapsetCompact;
user: UserCompact;
}
interface UserScoreV2 extends Pick<UserScore, 'beatmap' | 'beatmapset' | 'user'>, ScoreV2 {
}
interface Weight {
percentage: number;
pp: number;
}
interface UserBestScore extends UserScore, Score {
weight: Weight;
}
interface UserBestScoreV2 extends UserScoreV2, ScoreV2 {
weight: Weight;
}
interface BeatmapsetAvailability {
download_disabled: boolean;
more_information: string | null;
}
interface BeatmapsetHype {
current: number;
required: number;
}
interface Beatmapset extends BeatmapsetCompact {
availability: BeatmapsetAvailability;
bpm: number;
can_be_hyped: boolean;
creator: string;
discussion_locked: boolean;
hype: BeatmapsetHype | null;
is_scoreable: boolean;
last_updated: ISOTimestamp;
legacy_thread_url: string | null;
nominations_summary: BeatmapsetHype;
ranked: number;
ranked_date: ISOTimestamp | null;
source: string;
storyboard: boolean;
submitted_date: ISOTimestamp | null;
tags: string;
}
interface Beatmap extends BeatmapCompact {
accuracy: number;
ar: number;
beatmapset_id: number;
bpm: number | null;
convert: boolean;
count_circles: number;
count_sliders: number;
count_spinners: number;
cs: number;
deleted_at: ISOTimestamp | null;
drain: number;
hit_length: number;
is_scoreable: boolean;
last_updated: ISOTimestamp;
mode_int: number;
passcount: number;
playcount: number;
ranked: number;
url: string;
}
interface BeatmapPlaycount {
beatmap_id: number;
beatmap: BeatmapCompact | null;
beatmapset: BeatmapsetCompact | null;
count: number;
}
interface EventAchievement {
icon_url: string;
id: number;
name: string;
grouping: AchievementGrouping;
ordering: number;
slug: string;
description: string;
mode: GameMode | null;
instructions: string;
}
interface EventUser {
username: string;
url: string;
}
interface EventBeatmap {
title: string;
url: string;
}
interface BaseUserEvent {
created_at: ISOTimestamp;
id: number;
type: UserEventType;
}
interface UserEventAchievement extends BaseUserEvent {
type: 'achievement';
achievement: EventAchievement;
user: EventUser;
}
interface UserEventBeatmapPlaycount extends BaseUserEvent {
type: 'beatmapPlaycount';
beatmap: EventBeatmap;
count: number;
}
interface UserEventBeatmapsetApprove extends BaseUserEvent {
type: 'beatmapsetApprove';
approval: EventBeatmapsetApprovedType;
beatmapset: EventBeatmap;
}
interface UserEventBeatmapsetDelete extends BaseUserEvent {
type: 'beatmapsetDelete';
beatmapset: EventBeatmap;
}
interface UserEventBeatmapsetUpdate extends BaseUserEvent {
type: 'beatmapsetRevive' | 'beatmapsetUpdate' | 'beatmapsetUpload';
beatmapset: EventBeatmap;
user: EventUser;
}
interface UserEventRank extends BaseUserEvent {
mode: GameMode;
beatmap: EventBeatmap;
user: EventUser;
}
interface UserEventRankAchieved extends BaseUserEvent, UserEventRank {
type: 'rank';
scoreRank: Rank;
}
interface UserEventRankLost extends BaseUserEvent, UserEventRank {
type: 'rankLost';
}
interface UserEventUserUpdate extends BaseUserEvent {
type: 'userSupportAgain' | 'userSupportFirst' | 'userSupportGift';
user: EventUser;
}
interface UserEventUsernameUpdate extends BaseUserEvent {
type: 'usernameChange';
user: EventUser & {
previousUsername: string | null;
};
}
type UserEvent = UserEventAchievement | UserEventBeatmapPlaycount | UserEventBeatmapsetApprove | UserEventBeatmapsetDelete | UserEventBeatmapsetUpdate | UserEventRankAchieved | UserEventRankLost | UserEventUserUpdate | UserEventUsernameUpdate;
interface WikiPage {
available_locales: string[];
layout: string;
locale: string;
markdown: string;
path: string;
subtitle: string | null;
tags: string[];
title: string;
}
type SearchResult<T> = {
data: T[];
total: number;
};
interface SearchResults {
user: SearchResult<UserCompact> | null;
wiki_page: SearchResult<WikiPage> | null;
}
interface CommentableMetadata {
id: number;
title: string;
type: string;
url: string;
}
interface Comment {
commentable_id: number;
commentable_type: CommentableType;
created_at: ISOTimestamp;
deleted_at: ISOTimestamp | null;
edited_at: ISOTimestamp | null;
edited_by_id: number | null;
id: number;
legacy_name: string | null;
message: string | null;
message_html: string | null;
parent_id: number | null;
pinned: boolean;
replies_count: number;
updated_at: ISOTimestamp;
user_id: number;
votes_count: number;
}
interface CommentBundle {
commentable_meta: CommentableMetadata[];
comments: Comment[];
has_more: boolean;
has_more_id: number | null;
included_comments: Comment[];
pinned_commnets: Comment[] | null;
sort: CommentSort;
top_level_count: number | null;
total: number | null;
user_follow: boolean;
user_votes: number[];
users: UserCompact[];
}
interface MultiplayerScoresParams {
limit: number;
sort: MultiplayerScoresSort;
}
interface MultiplayerScoreMod {
acronym: Mod;
}
interface MultiplayerScoreStatistics {
Ok: number;
Meh: number;
Good: number;
Miss: number;
None: number;
Great: number;
Perfect: number;
IgnoreHit: number;
IgnoreMiss: number;
LargeBonus: number;
SmallBonus: number;
LargeTickHit: number;
SmallTickHit: number;
LargeTickMiss: number;
SmallTickMiss: number;
}
interface MultiplayerScore {
id: number;
user_id: number;
room_id: number;
playlist_item_id: number;
beatmap_id: number;
rank: Rank;
total_score: number;
accuracy: number;
max_combo: number;
mods: MultiplayerScoreMod[];
statistics: MultiplayerScoreStatistics;
passed: boolean;
position: number | null;
user: UserCompact & {
country: Country;
cover: Cover;
};
}
interface MultiplayerScores {
cursor_string: Cursor;
params: MultiplayerScoresParams;
scores: MultiplayerScore[];
total: number | null;
user_score: MultiplayerScore | null;
}
interface Spotlight {
end_date: ISOTimestamp;
id: number;
mode_specific: boolean;
participant_count: number | null;
name: string;
start_date: ISOTimestamp;
type: SpotlightType;
}
interface Rankings {
beatmapsets: Beatmapset[] | null;
ranking: (UserStatistics & {
user: UserCompact & {
country: Country;
cover: Cover;
};
})[];
spotlight: Spotlight | null;
total: number;
}
interface NewsPost {
author: string;
edit_url: string;
first_image: string | null;
id: number;
published_at: ISOTimestamp;
slug: string;
title: string;
updated_at: ISOTimestamp;
}
interface NewsSidebar {
current_year: number;
news_posts: NewsPost;
years: number[];
}
interface NewsSearch {
limit: number;
sort: 'published_desc';
}
interface NewsListing {
cursor_string: Cursor;
news_posts: NewsPost & {
preview: string;
};
news_sidebar: NewsSidebar;
search: NewsSearch;
}
interface NewsNavigation {
newer: NewsPost | null;
older: NewsPost | null;
}
interface Fails {
exit: number[] | null;
fail: number[] | null;
}
interface BeatmapUserScore {
position: number;
score: Score & {
beatmap: Beatmap & {
checksum: string | null;
};
user: UserCompact & {
country: Country;
cover: Cover;
};
};
}
interface BeatmapUserScoreV2 {
position: number;
score: ScoreV2 & {
beatmap: Beatmap & {
checksum: string | null;
};
user: UserCompact & {
country: Country;
cover: Cover;
};
};
}
interface BeatmapDifficultyAttributes {
max_combo: number;
star_rating: number;
gamemode: GameMode;
}
interface OsuBeatmapDifficultyAttributes extends BeatmapDifficultyAttributes {
gamemode: 'osu';
aim_difficulty: number;
approach_rate: number;
flashlight_difficulty: number;
overall_difficulty: number;
slider_factor: number;
speed_difficulty: number;
}
interface TaikoBeatmapDifficultyAttributes extends BeatmapDifficultyAttributes {
gamemode: 'taiko';
stamina_difficulty: number;
rhythm_difficulty: number;
colour_difficulty: number;
approach_rate: number;
great_hit_window: number;
}
interface FruitsBeatmapDifficultyAttributes extends BeatmapDifficultyAttributes {
gamemode: 'fruits';
approach_rate: number;
}
interface ManiaBeatmapDifficultyAttributes extends BeatmapDifficultyAttributes {
gamemode: 'mania';
great_hit_window: number;
score_multiplier: number;
}
interface UpdateStream {
display_name: string | null;
id: number;
is_featured: boolean;
name: string;
}
interface Build {
created_at: ISOTimestamp;
display_version: string;
id: number;
update_stream: UpdateStream | null;
users: number;
version: string | null;
}
interface BuildVersions {
next: Build | null;
previous: Build | null;
}
interface ChangelogEntry {
category: string;
created_at: ISOTimestamp | null;
github_pull_request_id: number | null;
github_url: string | null;
id: number | null;
major: boolean;
repository: string | null;
title: string | null;
type: string;
url: string | null;
}
interface GithubUser {
display_name: string;
github_url: string | null;
id: number | null;
osu_username: string | null;
user_id: number | null;
user_url: string | null;
}
interface Channel {
channel_id: number;
name: string;
description: string | null;
icon: string | null;
type: ChannelType;
moderated: boolean;
uuid: string | null;
}
interface ChatMessage {
channel_id: number;
content: string;
is_action: boolean;
message_id: number;
sender_id: number;
timestamp: ISOTimestamp;
type: ChatMessageType;
uuid: string | null;
}
interface ForumPost {
created_at: ISOTimestamp;
deleted_at: ISOTimestamp | null;
edited_at: ISOTimestamp | null;
edited_by_id: number | null;
forum_id: number;
id: number;
topic_id: number;
user_id: number;
}
interface ForumPostBody {
html: string;
raw: string;
}
interface ForumTopic {
created_at: ISOTimestamp;
deleted_at: ISOTimestamp | null;
first_post_id: number;
forum_id: number;
id: number;
is_locked: boolean;
last_post_id: number;
poll: ForumPoll | null;
post_count: number;
title: string;
type: ForumTopicType;
updated_at: ISOTimestamp;
user_id: number;
}
interface ForumPoll {
allow_vote_change: boolean;
ended_at: ISOTimestamp | null;
hide_incomplete_results: boolean;
last_vote_at: ISOTimestamp | null;
max_votes: number;
options: ForumPollOptions[];
started_at: ISOTimestamp;
title: {
bbcode: string;
html: string;
};
total_vote_count: number;
}
interface ForumPollOptions {
id: number;
text: {
bbcode: string;
html: string;
};
vote_count: number | null;
}
interface BeatmapsetDiscussion {
beatmap_id: number | null;
beatmapset_id: number | null;
can_be_resolved: boolean;
can_grant_kudosu: boolean;
created_at: ISOTimestamp;
deleted_at: ISOTimestamp | null;
deleted_by_id: number | null;
id: number;
kudosu_denied: boolean;
last_post_at: ISOTimestamp;
message_type: DiscussionMessageType;
parent_id: number | null;
resolved: boolean;
timestamp: number | null;
updated_at: ISOTimestamp;
user_id: number;
}
interface DiscussionPost {
beatmapset_discussion_id: number;
created_at: ISOTimestamp;
deleted_at: ISOTimestamp | null;
deleted_by_id: number | null;
id: number;
last_editor_id: number | null;
message: string;
system: boolean;
updated_at: ISOTimestamp;
user_id: number;
}
interface DiscussionVote {
beatmapset_discussion_id: number;
created_at: ISOTimestamp;
id: number;
score: number;
updated_at: ISOTimestamp;
user_id: number;
}
/**
* Class that handles auth code grant flow related actions
*
* Documentation: {@link https://osujs.mario564.com/oauth/authorization-code-grant}
*/
declare class AuthCodeGrant extends Base$1 {
private scopes;
/**
* @param clientId OAuth client ID
* @param clientSecret OAuth client secret
* @param redirectUri OAuth redirect URI
* @param scopes An array of OAuth scopes
* @param options.polyfillFetch In case developing with a Node.js version prior to 18, you need to pass a polyfill for the fetch API. Install `node-fetch`
*/
constructor(clientId: number, clientSecret: string, redirectUri: string, scopes: Scope[], options?: {
polyfillFetch?: typeof polyfillFetch;
});
/**
* Gets a token
*
* Documentation: {@link https://osujs.mario564.com/oauth/authorization-code-grant}
* @param code The string received after a user authorizes the app
* @returns An API token
*/
requestToken(code: string): Promise<Token>;
/**
* Refreshes a token
*
* Documentation: {@link https://osujs.mario564.com/oauth/authorization-code-grant}
* @param refreshToken The token used to refresh
* @returns An API token
*/
refreshToken(refreshToken: string): Promise<Token>;
}
/**
* Class that wraps all OAuth related endpoints
*
* Documentation: {@link https://osujs.mario564.com/oauth}
*/
declare class Auth extends Base$1 {
/**
* @param clientId OAuth client ID
* @param clientSecret OAuth client secret
* @param redirectUri OAuth redirect URI
* @param options.polyfillFetch In case developing with a Node.js version prior to 18, you need to pass a polyfill for the fetch API. Install `node-fetch`
*/
constructor(clientId: number, clientSecret: string, redirectUri: string, options?: {
polyfillFetch?: typeof polyfillFetch;
});
/**
* @param scopes An array of scopes
*
* Documentation: {@link https://osujs.mario564.com/oauth/authorization-code-grant}
*/
authorizationCodeGrant(scopes?: Scope[]): AuthCodeGrant;
/**
* Gets a token
*
* Documentation: {@link https://osujs.mario564.com/oauth/client-credentials-grant}
* @param scopes An array of scopes
* @returns An API token
*/
clientCredentialsGrant(scopes?: Scope[]): Promise<GuestToken>;
/**
* Revokes a token
*
* Documentation: {@link https://osujs.mario564.com/oauth/revoke-token}
* @param accessToken Access token to revoke
*/
revokeToken(accessToken: string): Promise<void>;
}
interface Options {
query?: Record<string, any>;
body?: Record<string, any> | string;
}
interface LookupBeatmapOptions {
query?: {
/** A beatmap checksum */
checksum?: string;
/** A beatmap file name */
filename?: string;
/** ID of a beatmap */
id?: number;
};
}
interface GetBeatmapScoresOptions {
query?: {
/** Gamemode of the scores to return */
mode?: GameMode;
};
}
interface GetBeatmapTopNonLegacyScoresOptions {
query?: {
/** Set to true to only return legacy scores */
legacy_only?: boolean;
/** Gamemode of the scores to return */
mode?: GameMode;
};
}
interface GetBeatmapsOptions {
query?: {
/** An array of beatmap IDs (can only take up to 50 IDs) */
ids?: number[];
};
}
interface GetBeatmapAttributesOptions {
body?: {
/** Mods to apply (can be either the bitwise representation or an array of acronyms) */
mods?: number | Mod[];
/** Ruleset of the difficulty attributes. Only valid if it's the beatmap ruleset or the beatmap can be converted to the specified ruleset. Defaults to ruleset of the specified beatmap */
ruleset?: GameMode;
/** The same as `ruleset` but in integer form */
ruleset_id?: number;
};
}
interface GetDiscussionBaseQuery {
/** Max. number of results */
limit?: number;
/** Search result page number */
page?: number;
/** Sort posts by newest (`id_desc`) or oldest (`id_desc`) */
sort?: 'id_desc' | 'id_asc';
}
interface GetDiscussionPostsOptions {
query?: GetDiscussionBaseQuery & {
/** ID of the beatmapset discussion */
beatmapset_discussion_id?: number;
/** Post types */
types?: ('first' | 'reply' | 'system')[];
/** ID of the user to get posts from */
user?: number;
};
}
interface GetDiscussionVotesOptions {
query?: GetDiscussionBaseQuery & {
/** ID of the beatmapset discussion */
beatmapset_discussion_id?: number;
/** ID of the user receiving the votes */
receiver?: number;
/** `1` for up vote, `-1` for down vote */
score?: 1 | -1;
/** ID of the user giving votes */
user?: number;
};
}
interface GetDiscussionsOptions {
query?: GetDiscussionBaseQuery & {
/** ID of the beatmap to get discussions from */
beatmap_id?: number;
/** ID of the beatmapset to get discussions from */
beatmapset_id?: number;
/** Specify beatmapset status */
beatmapset_status?: 'all' | 'ranked' | 'qualified' | 'disqualified' | 'never_qualified';
/** Specify message types, (unset for all) */
message_types?: DiscussionMessageType[];
/** Show only resolved issues? */
only_unresolved?: boolean;
/** ID of the user (documentation doesn't specify about what) */
user?: number;
};
}
interface GetChangelogListingOptions {
query?: {
/** Minimum build version */
from?: string;
/** Maximum build ID */
max_id?: number;
/** Stream name to return builds from */
stream?: ChangelogStream;
/** Maximum build version */
to?: string;
/** Changelog entry format (returns both by default) */
message_formats?: ('html' | 'markdown')[];
};
}
interface LookupChangelogBuildOptions {
query?: {
/** Unset to query by build version or stream name, or id to query by build ID */
key?: 'id';
/** Changelog entry format (returns both by default) */
message_formats?: ('html' | 'markdown')[];
};
}
interface CreatePMOptions {
body: {
/** ID of the user to send a PM */
target_id: number;
/** Message to send */
message: string;
/** Is the message an action? */
is_action: boolean;
/** Client side message identifier which will be sent back in response and websocket JSON */
uuid?: string;
};
}
interface CreatePMChannelOptions {
body: {
/** Message to send */
message?: string;
/** Channel details */
channel?: {
/** Channel name */
name?: string;
/** Channel description */
description?: string;
};
/** Target user ID */
target_id: number;
};
}
interface CreateAnnounceChannelOptions {
body: {
/** Message to send with the announcement */
message: string;
/** Channel details */
channel: {
/** Channel name */
name: string;
/** Channel description */
description: string;
};
/** Target user IDs */
target_ids: number[];
};
}
interface GetCommentsOptions {
query?: {
/** Resource to get comments for */
commentable?: {
/** Type of the resource */
type?: CommentableType;
/** ID of the resource */
id?: number;
};
/** Get replies of a specific comment ID */
parent_id?: number;
/** Sort option */
sort?: CommentSort;
};
}
interface ReplyToTopicOptions {
body: {
/** Content of the reply */
body: string;
};
}
interface CreateTopicOptions {
body: {
/** Content of the topic */
body: string;
/** ID of the forum to create the topic in */
forum_id: number;
/** Title of the topic */
title: string;
/** Create a poll with the topic? */
with_poll?: boolean;
/** Poll details */
forum_topic_poll?: {
/** Hide result (until voting period ends)? (Default: false) */
hide_results?: boolean;
/** Length of the voting period in days. 0 means that the voting will never end (default: 0). This parameter is required if `hide_results` option is enabled */
length_days?: number;
/** Max. number of votes each user can cast (default: 1) */
max_options?: number;
/** Newline-separated list of voting options. BBCode is supported */
options: string;
/** Title of the poll */
title: string;
/** Can a user change their votes? (Default: false) */
vote_change?: boolean;
};
};
}
interface GetTopicOptions {
query?: {
/** Pagination cursor */
cursor_string?: string;
/** Sort posts by */
sort?: 'id_asc' | 'id_desc';
/** Max. number of posts to be returned (caps at 50) */
limit?: number;
/** First post ID to be returned with `sort` set to `id_asc`. This parameter is ignored if `cursor_string` is specified */
start?: number;
/** First post ID to be returned with `sort` set to `id_desc`. This parameter is ignored if `cursor_string` is specified */
end?: number;
};
}
interface UpdateTopicOptions {
body?: {
/** Forum topic details */
forum_topic?: {
/** Title of the topic */
topic_title?: string;
};
};
}
interface UpdatePostOptions {
body: {
/** Content of the post in BBCode format */
body: string;
};
}
interface SearchOptions {
query?: {
/** Search only users, only wiki pages or both */
mode?: 'all' | 'user' | 'wiki_page';
/** Query string to search */
query?: string;
/** Page number */
page?: number;
};
}
interface GetPlaylistScoresOptions {
query?: {
/** Limit number of results */
limit?: number;
/** Sort option */
sort?: MultiplayerScoresSort;
/** Pagination cursor */
cursor_string?: string;
};
}
interface GetNewsListingOptions {
query?: {
/** Limit number of results */
limit?: number;
/** Filter news posts by a specific year */
year?: number;
/** Pagination cursor */
cursor_string?: string;
};
}
interface GetNewsPostOptions {
query?: {
/** Specify whether the query must be done with a news post ID (`id`) or a slug (unset value) */
key?: 'id';
};
}
interface GetRankingOptions {
query?: {
/** Filter by country code (only available for type `performance`) */
country?: string;
/** Show all users or friend ranking */
filter?: 'all' | 'friends';
/** ID of the spotlight (if type is `charts`) */
spotlight?: number;
/** Filter ranking by specified mode variant (only available for type `performance`) */
variant?: string;
};
}
interface GetSelfOptions {
urlParams?: {
/** Gamemode of the profile to return */
mode: GameMode;
};
}
interface GetUserKodosuOptions {
query?: {
/** Limit number of results */
limit?: number;
/** Pagination offset */
offset?: number;
};
}
interface GetUserScoresOptions {
query?: {
/** Limit number of results */
limit?: number;
/** Pagination offset */
offset?: number;
/** Gamemode of the scores to return */
mode?: GameMode;
};
}
interface GetUserRecentScoresOptions {
query?: {
/** Limit number of results */
limit?: number;
/** Pagination offset */
offset?: number;
/** Gamemode of the scores to return */
mode?: GameMode;
/** Include failed scores? */
include_fails?: boolean | number;
};
}
interface GetUserBeatmapsOptions {
query?: {
/** Limit number of results */
limit?: number;
/** Pagination offset */
offset?: number;
};
}
interface GetUserRecentActivityOptions {
query?: {
/** Limit number of results */
limit?: number;
/** Pagination offset */
offset?: number;
};
}
interface GetUserOptions {
urlParams?: {
/** Gamemode of the profile to return */
mode?: GameMode;
};
query?: {
/** Specify if the `user` param is an `id` or a `username` */
key: 'id' | 'username';
};
}
interface GetUsersOptions {
query?: {
/** An array of user IDs (can only take up to 50 IDs) */
ids?: number[];
/** Include `statistics_rulesets.variants`? */
include_variant_statistics?: boolean;
};
}
declare class Base<TPolyfillFetch extends typeof polyfillFetch | undefined = undefined> {
protected accessToken: string;
private fetch;
private usingPolyfillFetch;
constructor(accessToken: string, options?: {
polyfillFetch?: TPolyfillFetch;
});
protected request<T>(endpoint: string, method: 'POST' | 'GET' | 'PATCH' | 'DELETE', options?: Options & {
returnNullOn404?: boolean;
dontParseResp?: boolean;
apiVersion?: string;
}): Promise<T>;
/**
* Prevents a request done to the current API to throw an `OsuJSUnexpectedResponseError` error.
*
* Documentation: {@link https://osujs.mario564.com/current/safe-parse}
*/
safeParse<T extends Promise<any>>(request: T): Promise<SafeParse<Awaited<T>, TPolyfillFetch extends typeof polyfillFetch ? true : false>>;
/**
* Set a new access token to be used by the current client.
*
* Documentation: {@link https://osujs.mario564.com/current/set-access-token}
*/
setAccessToken(accessToken: string): void;
}
/**
* Class that wraps all user related endpoints
*/
declare class Users<TPolyfillFetch extends typeof polyfillFetch | undefined = undefined> extends Base<TPolyfillFetch> {
/**
* @param accessToken OAuth access token
* @param options.polyfillFetch In case developing with a Node.js version prior to 18, you need to pass a polyfill for the fetch API. Install `node-fetch`
*/
constructor(accessToken: string, options?: {
polyfillFetch?: TPolyfillFetch;
});
/**
* Makes a GET request to the `me` endpoint (requires the `identify` scope)
*
* Documentation: {@link https://osujs.mario564.com/current/get-self}
* @returns The user corresponding to the access token provided in the constructor of this class
*/
getSelf(options?: GetSelfOptions): Promise<UserExtended & {
is_restricted: boolean;
session_verified: boolean;
statistics_rulesets: StatisticsRulesets;
}>;
/**
* Makes a GET request to the `/users/{user}/kudosu` endpoint
*
* Documentation: {@link https://osujs.mario564.com/current/get-user-kudosu}
* @param user ID of the user to get kudosu from
* @param options
* @returns An array containing the specified user's kudosu history
*/
getUserKudosu(user: number, options?: GetUserKodosuOptions): Promise<UserKudosuHistory[]>;
/**
* Makes a GET request to the `/users/{user}/recent_activity` endpoint
*
* Documentation: {@link https://osujs.mario564.com/current/get-user-recent-activity}
* @param user ID of the user to get their recent activity from
* @param options
* @returns An array containing the specified user's recent activity (each event is a union, to discriminate, use the `type` key)
*/
getUserRecentActivity(user: number, options?: GetUserRecentActivityOptions): Promise<UserEvent[]>;
private getUserScoresBase;
/**
* Makes a GET request to the `/users/{user}/scores/{type}` endpoint
*
* Documentation: {@link https://osujs.mario564.com/current/get-user-scores}
* @param user ID of the user to get their scores
* @param type Score type
* @param options
* @returns An array of the specified user's scores
*/
getUserScores: <T extends UserScoreType>(user: number, type: T, options?: (T extends "recent" ? GetUserRecentScoresOptions : GetUserScoresOptions) | undefined) => Promise<T extends "best" ? UserBestScore[] : UserScore[]>;
/**
* Makes a GET request to the `/users/{user}/scores/{type}` endpoint with the `x-api-version` header set to `20220705`
*
* Documentation: {@link https://osujs.mario564.com/current/get-user-scores}
* @param user ID of the user to get their scores
* @param type Score type
* @param options
* @returns An array of the specified user's scores
*/
getUserScoresV2: <T extends UserScoreType>(user: number, type: T, options?: (T extends "recent" ? GetUserRecentScoresOptions : GetUserScoresOptions) | undefined) => Promise<T extends "best" ? UserBestScoreV2[] : UserScoreV2[]>;
/**
* Makes a GET request to the `/users/{user}/beatmapsets/{type}` endpoint
*
* Documentation: {@link https://osujs.mario564.com/current/get-user-beatmaps}
* @param user ID of the user to get their beatmapsets
* @param type Type of beatmapsets to return
* @param options
* @returns An array of a user's beatmapsets
*/
getUserBeatmaps<T extends UserBeatmapsType>(user: number, type: T, options?: GetUserBeatmapsOptions): Promise<T extends 'most_played' ? BeatmapPlaycount[] : (Beatmapset & {
beatmaps: (Beatmap & {
checksum: string | null;
})[];
})[]>;
/**
* Makes a GET request to the `/users/{user}/{mode?}` endpoint
*
* Documentation: {@link https://osujs.mario564.com/current/get-user}
* @param user ID or username of the user to get
* @param options
* @returns A user
*/
getUser(user: number | string, options?: GetUserOptions): Promise<UserExtended>;
/**
* Makes a GET request to the `/users` endpoint
*
* Documentation: {@link https://osujs.mario564.com/current/get-users}
* @returns An array of users
*/
getUsers(options?: GetUsersOptions): Promise<(UserCompact & {
country: Country;
cover: Cover;
groups: UserGroup[];
statistics_rulesets: StatisticsRulesets;
})[]>;
}
/**
* Class that wraps all wiki related endpoints
*/
declare class Wiki<TPolyfillFetch extends typeof polyfillFetch | undefined = undefined> extends Base<TPolyfillFetch> {
/**
* @param accessToken OAuth access token
* @param options.polyfillFetch In case developing with a Node.js version prior to 18, you need to pass a polyfill for the fetch API. Install `node-fetch`
*/
constructor(accessToken: string, options?: {
polyfillFetch?: TPolyfillFetch;
});
/**
* Makes a GET request to the `/wiki/{locale}/{path}` endpoint
*
* Documentation: {@link https://osujs.mario564.com/current/get-wiki-page}
* @param locale Two-letter language code of the wiki page
* @param path Path to the wiki page
* @returns The wiki page
*/
getWikiPage(locale: string, path: string): Promise<WikiPage>;
}
/**
* Class that wraps all comment related en