mirror of
https://github.com/versia-pub/server.git
synced 2026-03-13 05:49:16 +01:00
refactor(api): ♻️ Refactor test code to use new client
This commit is contained in:
parent
232ce83e4d
commit
84b9fc3719
23 changed files with 717 additions and 962 deletions
|
|
@ -34,6 +34,6 @@ export { Status, Mention, StatusSource } from "./schemas/status.ts";
|
|||
export { Tag } from "./schemas/tag.ts";
|
||||
export { Token } from "./schemas/token.ts";
|
||||
export { TermsOfService } from "./schemas/tos.ts";
|
||||
export { Role, NoteReaction, SSOConfig } from "./schemas/versia.ts";
|
||||
export { Role, NoteReaction, SSOConfig, Challenge } from "./schemas/versia.ts";
|
||||
|
||||
export { Id, iso631, zBoolean } from "./schemas/common.ts";
|
||||
|
|
|
|||
|
|
@ -105,3 +105,35 @@ export const SSOConfig = z.object({
|
|||
"An array of external OpenID Connect providers that users can link their accounts to.",
|
||||
}),
|
||||
});
|
||||
|
||||
/* Versia Server API extension */
|
||||
export const Challenge = z
|
||||
.object({
|
||||
id: Id.openapi({}).openapi({
|
||||
description: "Challenge ID in the database.",
|
||||
example: "b4a7e0f0-8f6a-479b-910b-9265c070d5bd",
|
||||
}),
|
||||
algorithm: z.enum(["SHA-1", "SHA-256", "SHA-512"]).openapi({
|
||||
description: "Algorithm used to generate the challenge.",
|
||||
example: "SHA-1",
|
||||
}),
|
||||
challenge: z.string().openapi({
|
||||
description: "Challenge to solve.",
|
||||
example: "1234567890",
|
||||
}),
|
||||
maxnumber: z.number().int().nonnegative().optional().openapi({
|
||||
description: "Maximum number to solve the challenge.",
|
||||
example: 100,
|
||||
}),
|
||||
salt: z.string().openapi({
|
||||
description: "Salt used to generate the challenge.",
|
||||
example: "1234567890",
|
||||
}),
|
||||
signature: z.string().openapi({
|
||||
description: "Signature of the challenge.",
|
||||
example: "1234567890",
|
||||
}),
|
||||
})
|
||||
.openapi({
|
||||
description: "A cryptographic challenge to solve. Used for Captchas.",
|
||||
});
|
||||
|
|
|
|||
|
|
@ -91,9 +91,10 @@ export class BaseClient {
|
|||
public constructor(
|
||||
protected baseUrl: URL,
|
||||
private accessToken?: string,
|
||||
public globalCatch: (error: ResponseError) => void = () => {
|
||||
// Do nothing by default
|
||||
},
|
||||
private options: {
|
||||
globalCatch?: (error: ResponseError) => void;
|
||||
throwOnError?: boolean;
|
||||
} = {},
|
||||
) {}
|
||||
|
||||
public get url(): URL {
|
||||
|
|
@ -104,16 +105,21 @@ export class BaseClient {
|
|||
return this.accessToken;
|
||||
}
|
||||
|
||||
/** Overridable by testing */
|
||||
private fetch = fetch;
|
||||
|
||||
private async request<ReturnType>(
|
||||
request: Request,
|
||||
): Promise<Output<ReturnType>> {
|
||||
const result = await fetch(request);
|
||||
const result = await this.fetch(request);
|
||||
const isJson = result.headers
|
||||
.get("Content-Type")
|
||||
?.includes("application/json");
|
||||
|
||||
if (!result.ok) {
|
||||
const error = isJson ? await result.json() : await result.text();
|
||||
if (!result.ok && this.options.throwOnError) {
|
||||
const error = isJson
|
||||
? await result.clone().json()
|
||||
: await result.clone().text();
|
||||
throw new ResponseError(
|
||||
{
|
||||
data: error,
|
||||
|
|
@ -127,8 +133,10 @@ export class BaseClient {
|
|||
}
|
||||
|
||||
return {
|
||||
data: isJson ? await result.json() : (await result.text()) || null,
|
||||
ok: true,
|
||||
data: isJson
|
||||
? await result.clone().json()
|
||||
: (await result.clone().text()) || null,
|
||||
ok: result.ok,
|
||||
raw: result,
|
||||
};
|
||||
}
|
||||
|
|
@ -168,19 +176,19 @@ export class BaseClient {
|
|||
});
|
||||
}
|
||||
|
||||
public get<ReturnType>(
|
||||
public get<ReturnType = void>(
|
||||
path: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<ReturnType>> {
|
||||
return this.request<ReturnType>(
|
||||
this.constructRequest(path, "GET", undefined, extra),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
public post<ReturnType>(
|
||||
public post<ReturnType = void>(
|
||||
path: string,
|
||||
body?: object,
|
||||
extra?: RequestInit,
|
||||
|
|
@ -188,12 +196,12 @@ export class BaseClient {
|
|||
return this.request<ReturnType>(
|
||||
this.constructRequest(path, "POST", body, extra),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
public postForm<ReturnType>(
|
||||
public postForm<ReturnType = void>(
|
||||
path: string,
|
||||
body: FormData | ConvertibleObject,
|
||||
extra?: RequestInit,
|
||||
|
|
@ -206,12 +214,12 @@ export class BaseClient {
|
|||
extra,
|
||||
),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
public put<ReturnType>(
|
||||
public put<ReturnType = void>(
|
||||
path: string,
|
||||
body?: object,
|
||||
extra?: RequestInit,
|
||||
|
|
@ -219,12 +227,12 @@ export class BaseClient {
|
|||
return this.request<ReturnType>(
|
||||
this.constructRequest(path, "PUT", body, extra),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
public putForm<ReturnType>(
|
||||
public putForm<ReturnType = void>(
|
||||
path: string,
|
||||
body: FormData | ConvertibleObject,
|
||||
extra?: RequestInit,
|
||||
|
|
@ -237,12 +245,12 @@ export class BaseClient {
|
|||
extra,
|
||||
),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
public patch<ReturnType>(
|
||||
public patch<ReturnType = void>(
|
||||
path: string,
|
||||
body?: object,
|
||||
extra?: RequestInit,
|
||||
|
|
@ -250,12 +258,12 @@ export class BaseClient {
|
|||
return this.request<ReturnType>(
|
||||
this.constructRequest(path, "PATCH", body, extra),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
public patchForm<ReturnType>(
|
||||
public patchForm<ReturnType = void>(
|
||||
path: string,
|
||||
body: FormData | ConvertibleObject,
|
||||
extra?: RequestInit,
|
||||
|
|
@ -268,12 +276,12 @@ export class BaseClient {
|
|||
extra,
|
||||
),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
public delete<ReturnType>(
|
||||
public delete<ReturnType = void>(
|
||||
path: string,
|
||||
body?: object,
|
||||
extra?: RequestInit,
|
||||
|
|
@ -281,12 +289,12 @@ export class BaseClient {
|
|||
return this.request<ReturnType>(
|
||||
this.constructRequest(path, "DELETE", body, extra),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
||||
public deleteForm<ReturnType>(
|
||||
public deleteForm<ReturnType = void>(
|
||||
path: string,
|
||||
body: FormData | ConvertibleObject,
|
||||
extra?: RequestInit,
|
||||
|
|
@ -299,7 +307,7 @@ export class BaseClient {
|
|||
extra,
|
||||
),
|
||||
).catch((e) => {
|
||||
this.globalCatch(e);
|
||||
this.options.globalCatch?.(e);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import type { Attachment } from "../schemas/attachment.ts";
|
|||
import type { Context } from "../schemas/context.ts";
|
||||
import type { CustomEmoji } from "../schemas/emoji.ts";
|
||||
import type { ExtendedDescription } from "../schemas/extended-description.ts";
|
||||
import type { FamiliarFollowers } from "../schemas/familiar-followers.ts";
|
||||
import type { Instance } from "../schemas/instance.ts";
|
||||
import type { Marker } from "../schemas/marker.ts";
|
||||
import type { Notification } from "../schemas/notification.ts";
|
||||
|
|
@ -21,7 +22,7 @@ import type { Status, StatusSource } from "../schemas/status.ts";
|
|||
import type { Tag } from "../schemas/tag.ts";
|
||||
import type { Token } from "../schemas/token.ts";
|
||||
import type { TermsOfService } from "../schemas/tos.ts";
|
||||
import type { Role } from "../schemas/versia.ts";
|
||||
import type { Challenge, Role } from "../schemas/versia.ts";
|
||||
import { BaseClient, type Output } from "./base.ts";
|
||||
import { DEFAULT_SCOPE, NO_REDIRECT } from "./constants.ts";
|
||||
|
||||
|
|
@ -71,7 +72,7 @@ export class Client extends BaseClient {
|
|||
account_ids: string[],
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.post<void>(
|
||||
return this.post(
|
||||
`/api/v1/lists/${id}/accounts`,
|
||||
{ account_ids },
|
||||
extra,
|
||||
|
|
@ -89,7 +90,7 @@ export class Client extends BaseClient {
|
|||
name: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.put<void>(
|
||||
return this.put(
|
||||
`/api/v1/announcements/${id}/reactions/${name}`,
|
||||
undefined,
|
||||
extra,
|
||||
|
|
@ -108,7 +109,7 @@ export class Client extends BaseClient {
|
|||
role_id: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.post<void>(
|
||||
return this.post(
|
||||
`/api/v1/accounts/${account_id}/roles/${role_id}`,
|
||||
undefined,
|
||||
extra,
|
||||
|
|
@ -141,7 +142,7 @@ export class Client extends BaseClient {
|
|||
domain: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.post<void>("/api/v1/domain_blocks", { domain }, extra);
|
||||
return this.post("/api/v1/domain_blocks", { domain }, extra);
|
||||
}
|
||||
|
||||
public bookmarkStatus(
|
||||
|
|
@ -164,7 +165,7 @@ export class Client extends BaseClient {
|
|||
id: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.delete<void>(
|
||||
return this.delete(
|
||||
`/api/v1/scheduled_statuses/${id}/cancel`,
|
||||
undefined,
|
||||
extra,
|
||||
|
|
@ -287,7 +288,7 @@ export class Client extends BaseClient {
|
|||
account_ids: string[],
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.delete<void>(
|
||||
return this.delete(
|
||||
`/api/v1/lists/${id}/accounts`,
|
||||
{ account_ids },
|
||||
extra,
|
||||
|
|
@ -303,11 +304,7 @@ export class Client extends BaseClient {
|
|||
id: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.delete<void>(
|
||||
`/api/v1/conversations/${id}`,
|
||||
undefined,
|
||||
extra,
|
||||
);
|
||||
return this.delete(`/api/v1/conversations/${id}`, undefined, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -318,7 +315,7 @@ export class Client extends BaseClient {
|
|||
* @return Empty.
|
||||
*/
|
||||
public deleteEmoji(id: string, extra?: RequestInit): Promise<Output<void>> {
|
||||
return this.delete<void>(`/api/v1/emojis/${id}`, undefined, extra);
|
||||
return this.delete(`/api/v1/emojis/${id}`, undefined, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -350,11 +347,7 @@ export class Client extends BaseClient {
|
|||
id: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.delete<void>(
|
||||
`/api/v1/featured_tags/${id}`,
|
||||
undefined,
|
||||
extra,
|
||||
);
|
||||
return this.delete(`/api/v1/featured_tags/${id}`, undefined, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -363,14 +356,14 @@ export class Client extends BaseClient {
|
|||
* @param id Target list ID.
|
||||
*/
|
||||
public deleteList(id: string, extra?: RequestInit): Promise<Output<void>> {
|
||||
return this.delete<void>(`/api/v1/lists/${id}`, undefined, extra);
|
||||
return this.delete(`/api/v1/lists/${id}`, undefined, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE /api/v1/push/subscription
|
||||
*/
|
||||
public deletePushSubscription(extra?: RequestInit): Promise<Output<void>> {
|
||||
return this.delete<void>("/api/v1/push/subscription", undefined, extra);
|
||||
return this.delete("/api/v1/push/subscription", undefined, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -381,7 +374,7 @@ export class Client extends BaseClient {
|
|||
* @return Empty.
|
||||
*/
|
||||
public deleteRole(id: string, extra?: RequestInit): Promise<Output<void>> {
|
||||
return this.delete<void>(`/api/v1/roles/${id}`, undefined, extra);
|
||||
return this.delete(`/api/v1/roles/${id}`, undefined, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -412,7 +405,7 @@ export class Client extends BaseClient {
|
|||
id: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.post<void>(
|
||||
return this.post(
|
||||
`/api/v1/instance/announcements/${id}/dismiss`,
|
||||
undefined,
|
||||
extra,
|
||||
|
|
@ -428,7 +421,7 @@ export class Client extends BaseClient {
|
|||
id: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.post<void>(
|
||||
return this.post(
|
||||
`/api/v1/notifications/${id}/dismiss`,
|
||||
undefined,
|
||||
extra,
|
||||
|
|
@ -439,7 +432,7 @@ export class Client extends BaseClient {
|
|||
* POST /api/v1/notifications/clear
|
||||
*/
|
||||
public dismissNotifications(extra?: RequestInit): Promise<Output<void>> {
|
||||
return this.post<void>("/api/v1/notifications/clear", undefined, extra);
|
||||
return this.post("/api/v1/notifications/clear", undefined, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -600,6 +593,22 @@ export class Client extends BaseClient {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /api/v1/challenges
|
||||
*
|
||||
* Generates a new Captcha to solve.
|
||||
* @returns A challenge.
|
||||
*/
|
||||
public getChallenge(
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<z.infer<typeof Challenge>>> {
|
||||
return this.post<z.infer<typeof Challenge>>(
|
||||
"/api/v1/challenges",
|
||||
undefined,
|
||||
extra,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/accounts/:id
|
||||
*
|
||||
|
|
@ -1047,6 +1056,28 @@ export class Client extends BaseClient {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/accounts/familiar_followers
|
||||
*
|
||||
* @param ids Array of account IDs.
|
||||
* @return Array of familiar followers.
|
||||
*/
|
||||
public getFamiliarFollowers(
|
||||
ids: string[],
|
||||
): Promise<Output<z.infer<typeof FamiliarFollowers>[]>> {
|
||||
const params = new URLSearchParams();
|
||||
|
||||
if (ids) {
|
||||
for (const id of ids) {
|
||||
params.append("id[]", id);
|
||||
}
|
||||
}
|
||||
|
||||
return this.get<z.infer<typeof FamiliarFollowers>[]>(
|
||||
`/api/v1/accounts/familiar_followers?${params}`,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* GET /api/v1/favourites
|
||||
*
|
||||
|
|
@ -2354,7 +2385,7 @@ export class Client extends BaseClient {
|
|||
role_id: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.delete<void>(`/api/v1/roles/${role_id}`, undefined, extra);
|
||||
return this.delete(`/api/v1/roles/${role_id}`, undefined, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2400,7 +2431,7 @@ export class Client extends BaseClient {
|
|||
token: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.post<void>(
|
||||
return this.post(
|
||||
"/oauth/revoke",
|
||||
{ client_id, client_secret, token },
|
||||
extra,
|
||||
|
|
@ -2534,7 +2565,7 @@ export class Client extends BaseClient {
|
|||
*/
|
||||
public searchAccount(
|
||||
q: string,
|
||||
options: Partial<{
|
||||
options?: Partial<{
|
||||
following: boolean;
|
||||
limit: number;
|
||||
max_id: string;
|
||||
|
|
@ -2547,22 +2578,20 @@ export class Client extends BaseClient {
|
|||
|
||||
params.set("q", q);
|
||||
|
||||
if (options) {
|
||||
if (options.following) {
|
||||
params.set("following", "true");
|
||||
}
|
||||
if (options.limit) {
|
||||
params.set("limit", options.limit.toString());
|
||||
}
|
||||
if (options.max_id) {
|
||||
params.set("max_id", options.max_id);
|
||||
}
|
||||
if (options.resolve) {
|
||||
params.set("resolve", "true");
|
||||
}
|
||||
if (options.since_id) {
|
||||
params.set("since_id", options.since_id);
|
||||
}
|
||||
if (options?.following) {
|
||||
params.set("following", "true");
|
||||
}
|
||||
if (options?.limit) {
|
||||
params.set("limit", options.limit.toString());
|
||||
}
|
||||
if (options?.max_id) {
|
||||
params.set("max_id", options.max_id);
|
||||
}
|
||||
if (options?.resolve) {
|
||||
params.set("resolve", "true");
|
||||
}
|
||||
if (options?.since_id) {
|
||||
params.set("since_id", options.since_id);
|
||||
}
|
||||
|
||||
return this.get<z.infer<typeof Account>[]>(
|
||||
|
|
@ -2639,7 +2668,7 @@ export class Client extends BaseClient {
|
|||
role_id: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.delete<void>(
|
||||
return this.delete(
|
||||
`/api/v1/accounts/${account_id}/roles/${role_id}`,
|
||||
undefined,
|
||||
extra,
|
||||
|
|
@ -2672,7 +2701,7 @@ export class Client extends BaseClient {
|
|||
domain: string,
|
||||
extra?: RequestInit,
|
||||
): Promise<Output<void>> {
|
||||
return this.delete<void>("/api/v1/domain_blocks", { domain }, extra);
|
||||
return this.delete("/api/v1/domain_blocks", { domain }, extra);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue