diff --git a/lib/beatmap.ts b/lib/beatmap.ts index 35c1414..3ecc674 100644 --- a/lib/beatmap.ts +++ b/lib/beatmap.ts @@ -39,6 +39,10 @@ export namespace Beatmap { } export interface WithBeatmapsetChecksumMaxcombo extends WithBeatmapset, WithChecksum { + /** + * @privateRemarks I had a single instance of this being null, on beatmap 2124608, specifically on the dev server (it's okay on osu server) + * For the sake of convenience, I cross my fingers that I won't regret not marking this as potentially null + */ max_combo: number } diff --git a/lib/comment.ts b/lib/comment.ts index 09e829e..9c13175 100644 --- a/lib/comment.ts +++ b/lib/comment.ts @@ -1,10 +1,22 @@ import { API, Beatmapset, Changelog, NewsPost, User } from "./index.js" import { getId } from "./misc.js" +/** Remove so-called "Deleted Items" / items that lack an id, add a "deleted_commentable_meta" and make it the number of removed objects */ +function removeDeletedItems(bundle: T): T { + const commentable_meta = bundle.commentable_meta.filter((c) => c.id) + bundle.deleted_commentable_meta = bundle.commentable_meta.length - commentable_meta.length + bundle.commentable_meta = commentable_meta + return bundle +} + export interface Comment { id: number parent_id: number | null - user_id: User["id"] + /** + * @remarks Is null if the author of the comment from the old comment system has no associated osu! user, presumably + * @privateRemarks Example is comment 178966 from beatmapset 349238 + */ + user_id: User["id"] | null pinned: boolean replies_count: number votes_count: number @@ -79,13 +91,7 @@ export namespace Comment { * @param comment The comment in question */ export async function getOne(this: API, comment: Comment["id"] | Comment): Promise { - const bundle = await this.request("get", `comments/${getId(comment)}`) as Bundle - // Remove so-called "Deleted Items" / items that lack an id, add a "deleted_commentable_meta" and make it the number of removed objects - const commentable_meta = bundle.commentable_meta.filter((c) => c.id) - bundle.deleted_commentable_meta = bundle.commentable_meta.length - commentable_meta.length - bundle.commentable_meta = commentable_meta - - return bundle + return removeDeletedItems(await this.request("get", `comments/${getId(comment)}`)) } /** @@ -99,15 +105,9 @@ export namespace Comment { const after = sort?.after ? String(getId(sort.after)) : undefined const parent_id = parent ? String(getId(parent)) : undefined - const bundle = await this.request("get", "comments", { + return removeDeletedItems(await this.request("get", "comments", { after, commentable_type: from?.type, commentable_id: from?.id, cursor: sort?.cursor, parent_id, sort: sort?.type - }) - // Remove so-called "Deleted Items" / items that lack an id, add a "deleted_commentable_meta" and make it the number of removed objects - 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 - - return bundle + })) } } diff --git a/lib/event.ts b/lib/event.ts index 1fb7f26..504201f 100644 --- a/lib/event.ts +++ b/lib/event.ts @@ -135,7 +135,7 @@ export namespace Event { /** * Get everything note-worthy that happened on osu! recently! * @param sort "id_asc" to have the oldest recent event first, "id_desc" to have the newest instead (defaults to **id_desc**) - * @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! + * @param cursor_string Use a response's `cursor_string` with the same parameters to get the next "page" of results, so `events` 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 | null}> { diff --git a/lib/index.ts b/lib/index.ts index 0c8ba70..6443f02 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -114,6 +114,7 @@ export class APIError { export class API { // ACCESS TOKEN STUFF + /** The key that allows you to talk with the API */ access_token: string = "" /** Should always be "Bearer" */ @@ -145,11 +146,14 @@ export class API { this.updateRefreshTimeout() // because the refresh token may be specified last } - /** If true, upon failing a request due to a 401, it will use the `refresh_token` if it exists (defaults to **true**) */ + /** If true, upon failing a request due to a 401, it will use the {@link API.refresh_token} if it exists (defaults to **true**) */ refresh_on_401: boolean = true private _refresh_on_expires: boolean = true - /** If true, the application will silently use the `refresh_token` right before the `access_token` expires, as determined by `expires` (defaults to **true**) */ + /** + * If true, the application will silently use the {@link API.refresh_token} right before the {@link API.access_token} expires, + * as determined by {@link API.expires} (defaults to **true**) + */ get refresh_on_expires(): boolean { return this._refresh_on_expires } @@ -163,7 +167,7 @@ export class API { return this._refresh_timeout } set refresh_timeout(timeout: NodeJS.Timeout) { - // if a previous refresh_timeout already exists, clear it + // if a previous one already exists, clear it if (this._refresh_timeout) { clearTimeout(this._refresh_timeout) } @@ -186,7 +190,7 @@ export class API { server: string = "https://osu.ppy.sh" /** The osu! user id of the user who went through the Authorization Code Grant */ user?: User["id"] - /** The scopes your application have, assuming it acts as a user */ + /** The {@link Scope}s your application has, assuming it acts as a user */ scopes?: Scope[] @@ -209,9 +213,9 @@ export class API { delay: number /** How many retries maximum before throwing an {@link APIError} (defaults to **5**) */ maximum_amount: number - /** Should it retry a request upon successfully refreshing the token due to `refresh_on_401` being `true`? (defaults to **true**) */ + /** Should it retry a request upon successfully refreshing the token due to {@link API.refresh_on_401} being `true`? (defaults to **true**) */ on_automatic_refresh: boolean - /** Should it retry a request if that request failed because it has been aborted by the `timeout`? (defaults to **false**) */ + /** Should it retry a request if that request failed because it has been aborted by the {@link API.timeout}? (defaults to **false**) */ on_timeout: boolean /** Upon failing a request and receiving a response, because of which received status code should the request be retried? (defaults to **[429]**) */ on_status_codes: number[] @@ -226,7 +230,7 @@ export class API { /** - * **Please use {@link API.createAsync} instead of the default constructor** if you don't have at least an `access_token`! + * **Please use {@link API.createAsync} instead of the default constructor** if you don't have at least an {@link API.access_token}! * An API object without an `access_token` is pretty much useless! */ constructor(properties: Partial) { @@ -250,7 +254,7 @@ export class API { user?: { /** The Application Callback URL; Where the User has been redirected to after saying "okay" to your application doing stuff */ redirect_uri: string, - /** The code that appeared as a GET argument when they got redirected to the Application Callback URl (`redirect_url`) */ + /** The code that appeared as a GET argument when they got redirected to the Application Callback URL (`redirect_uri`) */ code: string }, verbose?: "none" | "errors" | "all", @@ -274,7 +278,7 @@ export class API { /** * Get a websocket to get WebSocket events from! * @param server Where the "notification websocket/server" is - * (defaults to **the api's `server`'s protocol and a maximum of 1 subdomain being replaced by "wss://notify."** (so usually `wss://notify.ppy.sh`)) + * (defaults to **the {@link API.server}'s protocol and a maximum of 1 subdomain being replaced by "wss://notify."** (so usually `wss://notify.ppy.sh`)) */ public generateWebSocket(server: string = `${this.server.replace(/^\w*:\/\/(?:[A-Za-z0-9]+[.](?=[A-Za-z0-9]+[.]([A-Za-z0-9]+)$))?/g, "wss://notify.")}`): WebSocket {