2024-12-30 18:00:23 +01:00
|
|
|
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
|
|
|
|
import type { JSONObject } from "hono/utils/types";
|
2025-04-10 19:15:31 +02:00
|
|
|
import type { DescribeRouteOptions } from "hono-openapi";
|
|
|
|
|
import { resolver } from "hono-openapi/zod";
|
2025-03-29 03:30:06 +01:00
|
|
|
import { z } from "zod";
|
2024-12-30 18:00:23 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* API Error
|
|
|
|
|
*
|
|
|
|
|
* Custom error class used to throw errors in the API. Includes a status code, a message and an optional description.
|
|
|
|
|
* @extends Error
|
|
|
|
|
*/
|
|
|
|
|
export class ApiError extends Error {
|
|
|
|
|
/**
|
2025-03-24 14:42:09 +01:00
|
|
|
* @param {ContentfulStatusCode} status - The status code of the error
|
2024-12-30 18:00:23 +01:00
|
|
|
* @param {string} message - The message of the error
|
|
|
|
|
* @param {string | JSONObject} [details] - The description of the error
|
|
|
|
|
*/
|
|
|
|
|
public constructor(
|
|
|
|
|
public status: ContentfulStatusCode,
|
|
|
|
|
public message: string,
|
|
|
|
|
public details?: string | JSONObject,
|
|
|
|
|
) {
|
|
|
|
|
super(message);
|
|
|
|
|
this.name = "ApiError";
|
|
|
|
|
}
|
2025-03-24 14:42:09 +01:00
|
|
|
|
|
|
|
|
public static zodSchema = z.object({
|
|
|
|
|
error: z.string(),
|
2025-03-27 20:12:00 +01:00
|
|
|
details: z
|
|
|
|
|
.string()
|
|
|
|
|
.or(z.record(z.string(), z.string().or(z.number())))
|
|
|
|
|
.optional(),
|
2025-03-24 14:42:09 +01:00
|
|
|
});
|
|
|
|
|
|
2025-03-29 03:30:06 +01:00
|
|
|
public get schema(): DescribeRouteOptions["responses"] {
|
2025-03-24 14:42:09 +01:00
|
|
|
return {
|
|
|
|
|
description: this.message,
|
|
|
|
|
content: {
|
|
|
|
|
"application/json": {
|
2025-03-29 03:30:06 +01:00
|
|
|
schema: resolver(ApiError.zodSchema),
|
2025-03-24 14:42:09 +01:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static missingAuthentication(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
401,
|
|
|
|
|
"Missing authentication",
|
|
|
|
|
"The Authorization header is missing or could not be parsed.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static forbidden(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
403,
|
|
|
|
|
"Missing permissions",
|
|
|
|
|
"You do not have permission to access or modify this resource.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static notFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Not found",
|
|
|
|
|
"The requested resource could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static noteNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Note not found",
|
|
|
|
|
"The requested note could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static accountNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Account not found",
|
|
|
|
|
"The requested account could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static roleNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Role not found",
|
|
|
|
|
"The requested role could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static instanceNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Instance not found",
|
|
|
|
|
"The requested instance could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-28 22:06:42 +01:00
|
|
|
public static likeNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Like not found",
|
|
|
|
|
"The requested like could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-24 14:42:09 +01:00
|
|
|
public static pushSubscriptionNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Push subscription not found",
|
|
|
|
|
"No push subscription associated with this access token",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static tokenNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Token not found",
|
|
|
|
|
"The requested token could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static mediaNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Media not found",
|
|
|
|
|
"The requested media could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static applicationNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Application not found",
|
|
|
|
|
"The requested application could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static emojiNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Emoji not found",
|
|
|
|
|
"The requested emoji could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static notificationNotFound(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
404,
|
|
|
|
|
"Notification not found",
|
|
|
|
|
"The requested notification could not be found.",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static validationFailed(): ApiError {
|
|
|
|
|
return new ApiError(422, "Invalid values in request");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static internalServerError(): ApiError {
|
|
|
|
|
return new ApiError(
|
|
|
|
|
500,
|
|
|
|
|
"Internal server error. This is likely a bug.",
|
|
|
|
|
);
|
|
|
|
|
}
|
2024-12-30 18:00:23 +01:00
|
|
|
}
|