Skip to content

Commit

Permalink
General improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
TTTaevas committed Mar 21, 2024
1 parent 84304fb commit 26f2885
Show file tree
Hide file tree
Showing 11 changed files with 112 additions and 124 deletions.
20 changes: 10 additions & 10 deletions lib/beatmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export namespace Beatmap {
export interface WithFailtimesMaxcombo extends WithFailtimes, WithMaxcombo {}

/** @obtainableFrom {@link API.getBeatmap} */
export interface WithFailtimesBeatmapsetextended extends WithFailtimesMaxcombo {
export interface WithFailtimesBeatmapset extends WithFailtimesMaxcombo {
beatmapset: Beatmapset.Extended
}
}
Expand All @@ -94,11 +94,7 @@ export namespace Beatmap {
beatmapset: Beatmapset
}

/**
* @obtainableFrom
* {@link API.getBeatmapPack} /
* {@link API.getBeatmapPacks}
*/
/** @obtainableFrom {@link API.getBeatmapPacks} */
export interface Pack {
author: User["username"]
date: Date
Expand All @@ -108,16 +104,20 @@ export namespace Beatmap {
ruleset_id: Rulesets | null,
tag: string,
url: string,
beatmapsets?: Beatmapset.Extended[],
user_completion_data?:{
/** IDs of beatmapsets completed by the user (according to the requirements of the pack) */
beatmapset_ids: Beatmapset["id"][],
/** Whether all beatmapsets are completed by the user or not */
completed: boolean
}
}

export namespace Pack {
/** @obtainableFrom {@link API.getBeatmapPack} */
export interface WithBeatmapset extends Pack {
beatmapsets: Beatmapset.Extended[]
}

/**
* Get data about a Beatmap.Pack using its tag!
* @param pack The Pack or the pack tag of the Pack you're trying to get
Expand Down Expand Up @@ -269,15 +269,15 @@ export namespace Beatmap {
* @param query What to specify in order to find the right beatmap
*/
export async function lookup(this: API, query: {checksum?: Beatmap.WithChecksum["checksum"], filename?: string, id?: Beatmap["id"]}):
Promise<Extended.WithFailtimesBeatmapsetextended> {
Promise<Extended.WithFailtimesBeatmapset> {
return await this.request("get", `beatmaps/lookup`, {checksum: query.checksum, filename: query.filename, id: query.id ? String(query.id) : undefined})
}

/**
* Get extensive beatmap data about whichever beatmap you want!
* @param beatmap An object with the id of the beatmap you're trying to get
*/
export async function getOne(this: API, beatmap: Beatmap["id"] | Beatmap): Promise<Extended.WithFailtimesBeatmapsetextended> {
export async function getOne(this: API, beatmap: Beatmap["id"] | Beatmap): Promise<Extended.WithFailtimesBeatmapset> {
return await this.request("get", `beatmaps/${getId(beatmap)}`)
}

Expand Down
6 changes: 3 additions & 3 deletions lib/beatmapset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,11 @@ export namespace Beatmapset {

export namespace Extended {
/** @obtainableFrom {@link API.getUserBeatmaps} */
export interface WithBeatmapExtended extends Extended {
export interface WithBeatmap extends Extended {
beatmaps: Beatmap.Extended[]
}

export interface WithBeatmapExtendedPacktags extends Extended {
export interface WithBeatmapPacktags extends Extended {
beatmaps: Beatmap.Extended.WithMaxcombo[]
pack_tags: string[]
}
Expand Down Expand Up @@ -304,7 +304,7 @@ export namespace Beatmapset {
/** The thing you've got from a previous request to get another page of results! */
cursor_string?: string
}):
Promise<{beatmapsets: Beatmapset.Extended.WithBeatmapExtendedPacktags[], recommended_difficulty: number | null, total: number, error: any | null,
Promise<{beatmapsets: Beatmapset.Extended.WithBeatmapPacktags[], recommended_difficulty: number | null, total: number, error: any | null,
cursor_string: string | null}> {
const sort = query?.sort ? (query.sort.by + "_" + query.sort.in) : undefined
const c = query?.general ? query.general.map((general_value) => {
Expand Down
85 changes: 47 additions & 38 deletions lib/chat.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { API } from "./index.js";
import { getId } from "./misc.js";
import { User } from "./user.js";

export namespace Chat {
/** @obtainableFrom {@link API.keepChatAlive} */
export interface UserSilence {
id: number
user_id: number
user_id: User["id"]
}

/**
Expand Down Expand Up @@ -38,14 +39,14 @@ export namespace Chat {
*/
can_message_error: string | null
/** @remarks Is null if no message has been read (I think) */
last_read_id: number | null
last_read_id: Message["message_id"] | null
}
last_message_id: number
last_message_id: Message["message_id"]
/**
* The ids of the users that are in the channel
* @remarks Is empty for public channels
*/
users: number[]
users: User["id"][]
}

/**
Expand All @@ -54,16 +55,16 @@ export namespace Chat {
* @remarks Will 404 if the user has not joined the channel (use `joinChatChannel` for that)
* @param channel The channel in question
*/
export async function getOne(this: API, channel: {channel_id: number} | Chat.Channel): Promise<Chat.Channel.WithDetails> {
const response = await this.request("get", `chat/channels/${channel.channel_id}`)
export async function getOne(this: API, channel: Channel["channel_id"] | Channel): Promise<Channel.WithDetails> {
const response = await this.request("get", `chat/channels/${getId(channel, "channel_id")}`)
return response.channel
}

/**
* Get a list of all publicly joinable channels!
* @scope {@link Scope"chat.read"}
*/
export async function getAll(this: API): Promise<Chat.Channel[]> {
export async function getAll(this: API): Promise<Channel[]> {
return await this.request("get", "chat/channels")
}

Expand All @@ -73,9 +74,10 @@ export namespace Chat {
* @param channel The channel in question
* @param message You're marking this and all the messages before it as read!
*/
export async function markAsRead(this: API, channel: {channel_id: number} | Chat.Channel, message: {message_id: number} | Chat.Message): Promise<void> {
return await this.request("put",
`chat/channels/${channel.channel_id}/mark-as-read/${message.message_id}`, {channel_id: channel.channel_id, message: message.message_id})
export async function markAsRead(this: API, channel: Channel["channel_id"] | Channel, message: Message["message_id"] | Message): Promise<void> {
const channel_id = getId(channel, "channel_id")
const message_id = getId(message, "message_id")
return await this.request("put", `chat/channels/${channel_id}/mark-as-read/${message_id}`, {channel_id, message_id})
}

/**
Expand All @@ -84,8 +86,8 @@ export namespace Chat {
* @param user_target The other user able to read and send messages in this channel
* @returns The newly created channel!
*/
export async function createPrivate(this: API, user_target: {id: number} | User): Promise<Chat.Channel> {
return await this.request("post", "chat/channels", {type: "PM", target_id: user_target.id})
export async function createPrivate(this: API, user_target: User["id"] | User): Promise<Channel> {
return await this.request("post", "chat/channels", {type: "PM", target_id: getId(user_target)})
}

/**
Expand All @@ -97,30 +99,32 @@ export namespace Chat {
* @param message The message to send with the announcement
* @returns The newly created channel!
*/
export async function createAnnouncement(this: API, channel: {name: string, description: string}, user_targets: Array<{id: number} | User>, message: string):
Promise<Chat.Channel> {
const target_ids = user_targets.map((u) => u.id)
export async function createAnnouncement(this: API, channel: {name: string, description: string}, user_targets: Array<User["id"] | User>, message: string):
Promise<Channel> {
const target_ids = user_targets.map((u) => getId(u))
return await this.request("post", "chat/channels", {type: "ANNOUNCE", channel, target_ids, message})
}

/**
* Join a public or multiplayer ChatChannel, allowing you to interact with it!
* @scope {@link Scope"chat.write_manage"}
* @param channel The channel you wanna join
* @param user (defaults to the presumed authorized user) The user joining the channel
* @param user The user joining the channel (defaults to the **presumed authorized user** (api.user))
*/
export async function joinOne(this: API, channel: {channel_id: number} | Chat.Channel, user?: {id: number} | User): Promise<Chat.Channel.WithDetails> {
return await this.request("put", `chat/channels/${channel.channel_id}/users/${user?.id || this.user}`)
export async function joinOne(this: API, channel: Channel["channel_id"] | Channel, user?: User["id"] | User): Promise<Channel.WithDetails> {
const user_id = user ? getId(user) : this.user ? this.user : ""
return await this.request("put", `chat/channels/${getId(channel, "channel_id")}/users/${user_id}`)
}

/**
* Leave/Close a public ChatChannel!
* @scope {@link Scope"chat.write_manage"}
* @param channel The channel you wanna join
* @param user (defaults to the presumed authorized user) The user joining the channel
* @param channel The channel you wanna leave/close
* @param user The user leaving/closing the channel (defaults to the **presumed authorized user** (api.user))
*/
export async function leaveOne(this: API, channel: {channel_id: number} | Chat.Channel, user?: {id: number} | User): Promise<void> {
return await this.request("delete", `chat/channels/${channel.channel_id}/users/${user?.id || this.user}`)
export async function leaveOne(this: API, channel: Channel["channel_id"] | Channel, user?: User["id"] | User): Promise<void> {
const user_id = user ? getId(user) : this.user ? this.user : ""
return await this.request("delete", `chat/channels/${getId(channel, "channel_id")}/users/${user_id}`)
}
}

Expand All @@ -131,42 +135,44 @@ export namespace Chat {
* {@link API.getChatMessages}
*/
export interface Message {
channel_id: number
channel_id: Channel["channel_id"]
content: string
is_action: boolean
message_id: number
sender_id: number
sender_id: User["id"]
timestamp: Date
/** Like "action", "markdown", "plain" */
type: string
uuid?: string | null
sender: User
uuid?: string | null
}

export namespace Message {
/**
* Get the recent messages of a specific ChatChannel!
* @scope {@link Scope"chat.read"}
* @param channel The Channel you wanna get the messages from
* @param limit (defaults to 20, max 50) The maximum amount of messages you want to get!
* @param limit The maximum amount of messages you want to get, up to 50! (defaults to **20**)
* @param since Get the messages sent after this message
* @param until Get the messages sent up to but not including this message
*/
export async function getMultiple(this: API, channel: {channel_id: number} | Chat.Channel, limit: number = 20,
since?: {message_id: number} | Chat.Message, until?: {message_id: number} | Chat.Message): Promise<Chat.Message[]> {
return await this.request("get", `chat/channels/${channel.channel_id}/messages`, {limit, since: since?.message_id, until: until?.message_id})
export async function getMultiple(this: API, channel: Channel["channel_id"] | Channel, limit: number = 20,
since?: Message["message_id"] | Message, until?: Message["message_id"] | Message): Promise<Message[]> {
since = since ? getId(since, "message_id") : undefined
until = until ? getId(until, "message_id") : undefined
return await this.request("get", `chat/channels/${getId(channel, "channel_id")}/messages`, {limit, since, until})
}

/**
* Send a message in a ChatChannel!
* @scope {@link Scope"chat.write"}
* @param channel The channel in which you want to send your message
* @param message The message you wanna send
* @param is_action (defaults to false) Is it a command? Like `/me dances`
* @param is_action Is it a command? Like `/me dances` (defaults to **false**)
* @returns The newly sent ChatMessage!
*/
export async function send(this: API, channel: {channel_id: number} | Chat.Channel, message: string, is_action: boolean = false): Promise<Chat.Message> {
return await this.request("post", `chat/channels/${channel.channel_id}/messages`, {message, is_action})
export async function send(this: API, channel: Channel["channel_id"] | Channel, message: string, is_action: boolean = false): Promise<Message> {
return await this.request("post", `chat/channels/${getId(channel, "channel_id")}/messages`, {message, is_action})
}

/**
Expand All @@ -175,13 +181,13 @@ export namespace Chat {
* @remarks You don't need to use `createChatPrivateChannel` before sending a message
* @param user_target The User you wanna send your message to!
* @param message The message you wanna send
* @param is_action (defaults to false) Is it a command? Like `/me dances`
* @param is_action Is it a command? Like `/me dances` (defaults to **false**)
* @param uuid A client-side message identifier
* @returns The message you sent
*/
export async function sendPrivate(this: API, user_target: {id: number} | User, message: string, is_action: boolean = false, uuid?: string):
Promise<{channel: Chat.Channel, message: Chat.Message}> {
return await this.request("post", "chat/new", {target_id: user_target.id, message, is_action, uuid})
export async function sendPrivate(this: API, user_target: User["id"] | User, message: string, is_action: boolean = false, uuid?: string):
Promise<{channel: Channel, message: Message}> {
return await this.request("post", "chat/new", {target_id: getId(user_target), message, is_action, uuid})
}
}

Expand All @@ -192,7 +198,10 @@ export namespace Chat {
* @returns A list of recent silences
* @remarks Every 30 seconds is a good idea
*/
export async function keepAlive(this: API, since?: {user_silence?: {id: number} | Chat.UserSilence, message?: {message_id: number} | Chat.Message}): Promise<Chat.UserSilence[]> {
return await this.request("post", "chat/ack", {history_since: since?.user_silence?.id, since: since?.message?.message_id})
export async function keepAlive(this: API, since?: {user_silence?: UserSilence["id"]| UserSilence, message?: Message["message_id"] | Message}):
Promise<UserSilence[]> {
const history_since = since?.user_silence ? getId(since.user_silence) : undefined
const message_since = since?.message ? getId(since.message, "message_id") : undefined
return await this.request("post", "chat/ack", {history_since, since: message_since})
}
}
13 changes: 7 additions & 6 deletions lib/comment.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { API } from "./index.js"
import { getId } from "./misc.js"
import { User } from "./user.js"

export interface Comment {
Expand Down Expand Up @@ -77,8 +78,8 @@ export namespace Comment {
* Get a specific comment by using its id!
* @param comment The comment in question
*/
export async function getOne(this: API, comment: Comment | {id: number}): Promise<Comment.Bundle> {
let bundle = await this.request("get", `comments/${comment.id}`)
export async function getOne(this: API, comment: Comment["id"] | Comment): Promise<Comment.Bundle> {
let bundle = await this.request("get", `comments/${getId(comment)}`)
const commentable_meta = bundle.commentable_meta.filter((c: any) => c.id)
bundle.deleted_commentable_meta = bundle.commentable_meta.length - commentable_meta.length
bundle.commentable_meta = commentable_meta
Expand All @@ -92,10 +93,10 @@ export namespace Comment {
* @param parent The comments are replying to which comment? Make the id 0 to filter out replies (and only get top level comments)
* @param sort Should the comments be sorted by votes? Should they be from after a certain date? Maybe you can give a cursor?
*/
export async function getMultiple(this: API, from?: {type: Comment["commentable_type"], id: number}, parent?: Comment | {id: number | 0},
sort?: {type?: Comment.Bundle["sort"], after?: Comment | {id: number}, cursor?: Comment.Bundle["cursor"]}): Promise<Comment.Bundle.WithTotalToplevelcount> {
const after = sort?.after?.id ? String(sort.after.id) : undefined
const parent_id = parent?.id ? String(parent.id) : undefined
export async function getMultiple(this: API, from?: {type: Comment["commentable_type"], id: number}, parent?: Comment["id"] | Comment,
sort?: {type?: Comment.Bundle["sort"], after?: Comment["id"] | Comment, cursor?: Comment.Bundle["cursor"]}): Promise<Comment.Bundle.WithTotalToplevelcount> {
const after = sort?.after ? String(getId(sort.after)) : undefined
const parent_id = parent ? String(getId(parent)) : undefined

let bundle = await this.request("get", "comments", {
after, commentable_type: from?.type, commentable_id: from?.id,
Expand Down
3 changes: 2 additions & 1 deletion lib/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ export namespace Event {
* @param sort (defaults to "id_desc") "id_asc" to have the oldest recent event first, "id_desc" to have the newest instead
* @param cursor_string Use a response's `cursor_string` with the same parameters to get the next "page" of results, so `posts` in this instance!
*/
export async function getMultiple(this: API, sort: "id_desc" | "id_asc" = "id_desc", cursor_string?: string): Promise<{events: Event.Any[], cursor_string: string}> {
export async function getMultiple(this: API, sort: "id_desc" | "id_asc" = "id_desc", cursor_string?: string):
Promise<{events: Event.Any[], cursor_string: string}> {
return await this.request("get", "events", {sort, cursor_string})
}
}
31 changes: 7 additions & 24 deletions lib/home.ts
Original file line number Diff line number Diff line change
@@ -1,44 +1,27 @@
import { API } from "./index.js"
import { User as UserInterface } from "./user.js"
import { User } from "./user.js"
import { WikiPage } from "./wiki.js"

export namespace Home {
interface Search {
/** How many results there are across all pages */
total: number
}

export namespace Search {
/** @obtainableFrom {@link API.searchUser} */
export interface User extends Search {
/** The Users that have been found */
data: UserInterface[]
}

/** @obtainableFrom {@link API.searchWiki} */
export interface Wiki extends Search {
/** The WikiPages that have been found */
data: WikiPage[]
}

/**
* Look for a user like you would on the website!
* @param query What you would put in the searchbar
* @param page (defaults to 1) You normally get the first 20 results, but if page is 2, you'd get results 21 to 40 instead for example!
* @param page You normally get the first **20 results**, but if page is 2, you'd get results 21 to 40 instead for example! (defaults to **1**)
*/
export async function getUsers(this: API, query: string, page: number = 1): Promise<User> {
export async function getUsers(this: API, query: string, page: number = 1): Promise<{data: User[], total: number}> {
const response = await this.request("get", "search", {mode: "user", query, page})
return response.user
return response.user // It's the only property
}

/**
* Look for a wiki page like you would on the website!
* @param query What you would put in the searchbar
* @param page (defaults to 1) You normally get the first 50 results, but if page is 2, you'd get results 51 to 100 instead for example!
* @param page You normally get the first **50 results**, but if page is 2, you'd get results 51 to 100 instead for example! (defaults to **1**)
*/
export async function getWikiPages(this: API, query: string, page: number = 1): Promise<Wiki> {
export async function getWikiPages(this: API, query: string, page: number = 1): Promise<{data: WikiPage[], total: number}> {
const response = await this.request("get", "search", {mode: "wiki_page", query, page})
return response.wiki_page
return response.wiki_page // It's the only property
}
}
}
4 changes: 2 additions & 2 deletions lib/misc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,6 @@ export namespace Spotlight {
* @param arg The id or the object with the id
* @returns The id
*/
export function getId(arg: number | {id: number}): number {
return typeof arg === "number" ? arg : arg.id
export function getId(arg: number | {[key: string]: any}, property_name: string = "id"): number {
return typeof arg === "number" ? arg : arg[property_name]
}
Loading

0 comments on commit 26f2885

Please sign in to comment.