2024-07-23 00:11:05 +02:00
|
|
|
import type { z } from "zod";
|
|
|
|
|
import { fromError } from "zod-validation-error";
|
2024-08-25 16:10:38 +02:00
|
|
|
import type {
|
|
|
|
|
ContentFormat,
|
|
|
|
|
CustomEmojiExtension,
|
|
|
|
|
Delete,
|
|
|
|
|
DislikeExtension,
|
|
|
|
|
Entity,
|
|
|
|
|
EntityExtensionProperty,
|
|
|
|
|
Follow,
|
|
|
|
|
FollowAccept,
|
|
|
|
|
FollowReject,
|
|
|
|
|
Group,
|
|
|
|
|
InstanceMetadata,
|
|
|
|
|
LikeExtension,
|
|
|
|
|
Note,
|
|
|
|
|
PollVoteExtension,
|
|
|
|
|
ReactionExtension,
|
|
|
|
|
ShareExtension,
|
|
|
|
|
Unfollow,
|
|
|
|
|
User,
|
|
|
|
|
VanityExtension,
|
|
|
|
|
} from "./schemas";
|
2024-05-29 01:38:47 +02:00
|
|
|
import {
|
2024-08-25 16:01:06 +02:00
|
|
|
DeleteSchema,
|
2024-05-29 01:38:47 +02:00
|
|
|
EntitySchema,
|
|
|
|
|
FollowAcceptSchema,
|
|
|
|
|
FollowRejectSchema,
|
|
|
|
|
FollowSchema,
|
2024-08-25 16:01:06 +02:00
|
|
|
GroupSchema,
|
|
|
|
|
InstanceMetadataSchema,
|
2024-05-29 01:38:47 +02:00
|
|
|
NoteSchema,
|
2024-08-25 16:01:06 +02:00
|
|
|
UnfollowSchema,
|
2024-05-29 01:38:47 +02:00
|
|
|
UserSchema,
|
2024-07-26 17:49:36 +02:00
|
|
|
} from "./schemas/base";
|
2024-08-24 15:05:11 +02:00
|
|
|
import { ContentFormatSchema } from "./schemas/content_format";
|
|
|
|
|
import { ExtensionPropertySchema } from "./schemas/extensions";
|
|
|
|
|
import { CustomEmojiExtensionSchema } from "./schemas/extensions/custom_emojis";
|
2024-08-25 16:01:06 +02:00
|
|
|
import { LikeSchema } from "./schemas/extensions/likes";
|
|
|
|
|
import { VoteSchema } from "./schemas/extensions/polls";
|
|
|
|
|
import { ReactionSchema } from "./schemas/extensions/reactions";
|
|
|
|
|
import { ShareSchema } from "./schemas/extensions/share";
|
2024-08-24 15:05:11 +02:00
|
|
|
import { VanityExtensionSchema } from "./schemas/extensions/vanity";
|
2024-05-29 01:38:47 +02:00
|
|
|
|
|
|
|
|
// biome-ignore lint/suspicious/noExplicitAny: Used only as a base type
|
|
|
|
|
type AnyZod = z.ZodType<any, any, any>;
|
|
|
|
|
|
|
|
|
|
type InferType<T extends AnyZod> = z.infer<T>;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates entities against their respective schemas.
|
|
|
|
|
* @module federation/validator
|
|
|
|
|
* @see module:federation/schemas/base
|
|
|
|
|
* @example
|
2024-08-24 14:58:50 +02:00
|
|
|
* import { EntityValidator, type ValidationError } from "@versia/federation";
|
2024-05-29 01:38:47 +02:00
|
|
|
* const validator = new EntityValidator();
|
|
|
|
|
*
|
|
|
|
|
* // Will throw a special ValidationError with a human-friendly error message
|
|
|
|
|
* // and a machine-friendly error object if the data is invalid.
|
|
|
|
|
* const note = await validator.Note({
|
|
|
|
|
* type: "Note",
|
|
|
|
|
* content: "Hello, world!",
|
|
|
|
|
* });
|
|
|
|
|
*
|
|
|
|
|
* try {
|
|
|
|
|
* await validator.Note({
|
|
|
|
|
* type: "Note",
|
|
|
|
|
* content: 123,
|
|
|
|
|
* });
|
|
|
|
|
* } catch (error) {
|
|
|
|
|
* sendUser((error as ValidationError).toString());
|
|
|
|
|
* }
|
|
|
|
|
*
|
|
|
|
|
* // Types are also included for TypeScript users that don't use the extracted ones
|
2024-08-24 14:58:50 +02:00
|
|
|
* import type { Note } from "@versia/federation/types";
|
2024-06-20 00:21:34 +02:00
|
|
|
*
|
|
|
|
|
* const note: Note = {
|
|
|
|
|
* ...
|
|
|
|
|
* };
|
2024-05-29 01:38:47 +02:00
|
|
|
*/
|
|
|
|
|
export class EntityValidator {
|
|
|
|
|
private async validate<T extends AnyZod>(
|
|
|
|
|
schema: T,
|
|
|
|
|
data: unknown,
|
|
|
|
|
): Promise<InferType<T>> {
|
|
|
|
|
try {
|
|
|
|
|
return (await schema.parseAsync(data)) as InferType<T>;
|
|
|
|
|
} catch (error) {
|
|
|
|
|
throw fromError(error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Note entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public Note(data: unknown): Promise<Note> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(NoteSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a VanityExtension entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public VanityExtension(data: unknown): Promise<VanityExtension> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(VanityExtensionSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a User entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public User(data: unknown): Promise<User> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(UserSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Follow entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public Follow(data: unknown): Promise<Follow> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(FollowSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a FollowAccept entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public FollowAccept(data: unknown): Promise<FollowAccept> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(FollowAcceptSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a FollowReject entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public FollowReject(data: unknown): Promise<FollowReject> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(FollowRejectSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a ContentFormat entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public ContentFormat(data: unknown): Promise<ContentFormat> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(ContentFormatSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a CustomEmojiExtension entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public CustomEmojiExtension(data: unknown): Promise<CustomEmojiExtension> {
|
2024-06-20 00:21:34 +02:00
|
|
|
return this.validate(CustomEmojiExtensionSchema, data);
|
2024-05-29 01:38:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates an Entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public Entity(data: unknown): Promise<Entity> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(EntitySchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates an ExtensionProperty.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public EntityExtensionProperty(
|
2024-05-29 01:38:47 +02:00
|
|
|
data: unknown,
|
2024-08-25 16:10:38 +02:00
|
|
|
): Promise<EntityExtensionProperty> {
|
2024-05-29 01:38:47 +02:00
|
|
|
return this.validate(ExtensionPropertySchema, data);
|
|
|
|
|
}
|
2024-08-25 16:01:06 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Delete entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public Delete(data: unknown): Promise<Delete> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(DeleteSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Group entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public Group(data: unknown): Promise<Group> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(GroupSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates an InstanceMetadata entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public InstanceMetadata(data: unknown): Promise<InstanceMetadata> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(InstanceMetadataSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates an Unfollow entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public Unfollow(data: unknown): Promise<Unfollow> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(UnfollowSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Like entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public LikeExtension(data: unknown): Promise<LikeExtension> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(LikeSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Dislike entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public DislikeExtension(data: unknown): Promise<DislikeExtension> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(LikeSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Vote entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public PollVoteExtension(data: unknown): Promise<PollVoteExtension> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(VoteSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Reaction entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public ReactionExtension(data: unknown): Promise<ReactionExtension> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(ReactionSchema, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Validates a Share entity.
|
|
|
|
|
* @param data - The data to validate
|
|
|
|
|
* @returns A promise that resolves to the validated data.
|
|
|
|
|
*/
|
2024-08-25 16:10:38 +02:00
|
|
|
public ShareExtension(data: unknown): Promise<ShareExtension> {
|
2024-08-25 16:01:06 +02:00
|
|
|
return this.validate(ShareSchema, data);
|
|
|
|
|
}
|
2024-05-29 01:38:47 +02:00
|
|
|
}
|