refactor: ♻️ Refactor naming and code exports for both modules

This commit is contained in:
Jesse Wierzbinski 2024-06-19 12:21:34 -10:00
parent 8a37e7df95
commit dc352bc276
No known key found for this signature in database
29 changed files with 629 additions and 312 deletions

View file

@ -10,9 +10,9 @@ type HttpVerb =
| "OPTIONS"
| "HEAD";
const checkEvironmentSupport = async () => {
const checkEvironmentSupport = () => {
// Check if WebCrypto is supported
if (!globalThis.crypto || !globalThis.crypto.subtle) {
if (!globalThis.crypto?.subtle) {
throw new Error("WebCrypto is not supported in this environment");
}
@ -27,9 +27,9 @@ const checkEvironmentSupport = async () => {
export class SignatureValidator {
/**
* Creates a new instance of SignatureValidator.
* @param public_key The public key used for signature verification.
* @param publicKey The public key used for signature verification.
*/
constructor(private public_key: CryptoKey) {
constructor(private publicKey: CryptoKey) {
checkEvironmentSupport();
}
@ -114,9 +114,9 @@ export class SignatureValidator {
].filter(Boolean);
// Check if all headers are present
if (!signature || !date || !method || !url || !body) {
if (!(signature && date && method && url && body)) {
// Say which headers are missing
throw TypeError(
throw new TypeError(
`Headers are missing in request: ${missingHeaders.join(
", ",
)}`,
@ -124,7 +124,7 @@ export class SignatureValidator {
}
if (signature.split("signature=").length < 2) {
throw TypeError(
throw new TypeError(
"Invalid Signature header (wrong format or missing signature)",
);
}
@ -134,7 +134,7 @@ export class SignatureValidator {
.replace(/"/g, "");
if (!extractedSignature) {
throw TypeError(
throw new TypeError(
"Invalid Signature header (wrong format or missing signature)",
);
}
@ -148,8 +148,8 @@ export class SignatureValidator {
);
}
if (!date || !method || !url || !body) {
throw TypeError(
if (!(date && method && url && body)) {
throw new TypeError(
"Missing or empty required parameters: date, method, url or body",
);
}
@ -172,7 +172,7 @@ export class SignatureValidator {
// Check if signed string is valid
const isValid = await crypto.subtle.verify(
"Ed25519",
this.public_key,
this.publicKey,
Buffer.from(signature, "base64"),
new TextEncoder().encode(expectedSignedString),
);
@ -302,8 +302,8 @@ export class SignatureConstructor {
return { request, signedString };
}
if (!url || !body || !headers) {
throw TypeError(
if (!(url && body && headers)) {
throw new TypeError(
"Missing or empty required parameters: url, body or headers",
);
}

View file

@ -69,27 +69,35 @@ export class RequestParserHandler {
public async parseBody<ReturnType = void>(
callbacks: Partial<ParserCallbacks<ReturnType>>,
): Promise<ReturnType> {
if (!this.body.type) throw new Error("Missing type field in body");
if (!this.body.type) {
throw new Error("Missing type field in body");
}
switch (this.body.type) {
case "Note": {
const note = await this.validator.Note(this.body);
if (callbacks.note) return await callbacks.note(note);
if (callbacks.note) {
return await callbacks.note(note);
}
break;
}
case "Patch": {
const patch = await this.validator.Patch(this.body);
if (callbacks.patch) return await callbacks.patch(patch);
if (callbacks.patch) {
return await callbacks.patch(patch);
}
break;
}
case "Follow": {
const follow = await this.validator.Follow(this.body);
if (callbacks.follow) return await callbacks.follow(follow);
if (callbacks.follow) {
return await callbacks.follow(follow);
}
break;
}
@ -98,8 +106,9 @@ export class RequestParserHandler {
this.body,
);
if (callbacks.followAccept)
if (callbacks.followAccept) {
return await callbacks.followAccept(followAccept);
}
break;
}
@ -108,36 +117,45 @@ export class RequestParserHandler {
this.body,
);
if (callbacks.followReject)
if (callbacks.followReject) {
return await callbacks.followReject(followReject);
}
break;
}
case "User": {
const user = await this.validator.User(this.body);
if (callbacks.user) return await callbacks.user(user);
if (callbacks.user) {
return await callbacks.user(user);
}
break;
}
case "Like": {
const like = await this.validator.Like(this.body);
if (callbacks.like) return await callbacks.like(like);
if (callbacks.like) {
return await callbacks.like(like);
}
break;
}
case "Dislike": {
const dislike = await this.validator.Dislike(this.body);
if (callbacks.dislike) return await callbacks.dislike(dislike);
if (callbacks.dislike) {
return await callbacks.dislike(dislike);
}
break;
}
case "Undo": {
const undo = await this.validator.Undo(this.body);
if (callbacks.undo) return await callbacks.undo(undo);
if (callbacks.undo) {
return await callbacks.undo(undo);
}
break;
}
@ -146,16 +164,18 @@ export class RequestParserHandler {
this.body,
);
if (callbacks.serverMetadata)
if (callbacks.serverMetadata) {
return await callbacks.serverMetadata(serverMetadata);
}
break;
}
case "Extension": {
const extension = await this.validator.Extension(this.body);
if (callbacks.extension)
if (callbacks.extension) {
return await callbacks.extension(extension);
}
break;
}

View file

@ -3,6 +3,7 @@
"name": "@lysand-org/federation",
"version": "0.0.0",
"exports": {
".": "./index.ts"
".": "./index.ts",
"./types": "./schemas.ts"
}
}

View file

@ -41,6 +41,10 @@
".": {
"import": "./index.ts",
"default": "./index.ts"
},
"./types": {
"import": "./schemas.ts",
"default": "./schemas.ts"
}
},
"funding": {

51
federation/schemas.ts Normal file
View file

@ -0,0 +1,51 @@
import type { z } from "zod";
import type {
ActionSchema,
ActorPublicKeyDataSchema,
ContentFormatSchema,
CustomEmojiExtensionSchema,
DislikeSchema,
EntitySchema,
ExtensionPropertySchema,
ExtensionSchema,
FollowAcceptSchema,
FollowRejectSchema,
FollowSchema,
LikeSchema,
NoteSchema,
PatchSchema,
PublicationSchema,
ReportSchema,
ServerMetadataSchema,
UndoSchema,
UserSchema,
VanityExtensionSchema,
VisibilitySchema,
} from "./schemas/base";
// 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>;
export type Note = InferType<typeof NoteSchema>;
export type Patch = InferType<typeof PatchSchema>;
export type ActorPublicKeyData = InferType<typeof ActorPublicKeyDataSchema>;
export type ExtensionProperty = InferType<typeof ExtensionPropertySchema>;
export type VanityExtension = InferType<typeof VanityExtensionSchema>;
export type User = InferType<typeof UserSchema>;
export type Action = InferType<typeof ActionSchema>;
export type Like = InferType<typeof LikeSchema>;
export type Undo = InferType<typeof UndoSchema>;
export type Dislike = InferType<typeof DislikeSchema>;
export type Follow = InferType<typeof FollowSchema>;
export type FollowAccept = InferType<typeof FollowAcceptSchema>;
export type FollowReject = InferType<typeof FollowRejectSchema>;
export type Extension = InferType<typeof ExtensionSchema>;
export type Report = InferType<typeof ReportSchema>;
export type ServerMetadata = InferType<typeof ServerMetadataSchema>;
export type ContentFormat = InferType<typeof ContentFormatSchema>;
export type CustomEmojiExtension = InferType<typeof CustomEmojiExtensionSchema>;
export type Visibility = InferType<typeof VisibilitySchema>;
export type Publication = InferType<typeof PublicationSchema>;
export type Entity = InferType<typeof EntitySchema>;

View file

@ -1,7 +1,7 @@
import { z } from "zod";
import { ContentFormatSchema } from "./content_format";
import { ExtensionPropertySchema } from "./extensions";
import { CustomEmojiExtension } from "./extensions/custom_emojis";
import { CustomEmojiExtensionSchema } from "./extensions/custom_emojis";
import { VanityExtensionSchema } from "./extensions/vanity";
import { extensionTypeRegex } from "./regex";
@ -187,6 +187,6 @@ export {
ReportSchema,
ServerMetadataSchema,
ContentFormatSchema,
CustomEmojiExtension,
CustomEmojiExtensionSchema,
ExtensionPropertySchema,
};

View file

@ -1,6 +1,6 @@
import { z } from "zod";
import { CustomEmojiExtension } from "./extensions/custom_emojis";
import { CustomEmojiExtensionSchema } from "./extensions/custom_emojis";
export const ExtensionPropertySchema = z.object({
"org.lysand:custom_emojis": CustomEmojiExtension.optional(),
"org.lysand:custom_emojis": CustomEmojiExtensionSchema.optional(),
});

View file

@ -33,7 +33,7 @@ import { emojiRegex } from "../regex";
* // ...
* }
*/
export const CustomEmojiExtension = z.object({
export const CustomEmojiExtensionSchema = z.object({
emojis: z.array(
z.object({
name: z

View file

@ -2,7 +2,7 @@ import { describe, expect, it } from "bun:test";
import { EntityValidator } from "../index";
describe("Package testing", () => {
it("should not validate a bad Note", async () => {
it("should not validate a bad Note", () => {
const badObject = {
IamBad: "Note",
};

View file

@ -4,7 +4,7 @@ import {
ActionSchema,
ActorPublicKeyDataSchema,
ContentFormatSchema,
CustomEmojiExtension,
CustomEmojiExtensionSchema,
DislikeSchema,
EntitySchema,
ExtensionPropertySchema,
@ -54,10 +54,11 @@ type InferType<T extends AnyZod> = z.infer<T>;
* }
*
* // Types are also included for TypeScript users that don't use the extracted ones
* const noteObject: typeof EntityValidator.$Note = {
* type: "Note",
* // ...
* }
* import type { Note } from "@lysand-org/federation/types";
*
* const note: Note = {
* ...
* };
*/
export class EntityValidator {
private async validate<T extends AnyZod>(
@ -71,34 +72,6 @@ export class EntityValidator {
}
}
declare static $Note: InferType<typeof NoteSchema>;
declare static $Patch: InferType<typeof PatchSchema>;
declare static $ActorPublicKeyData: InferType<
typeof ActorPublicKeyDataSchema
>;
declare static $ExtensionProperty: InferType<
typeof ExtensionPropertySchema
>;
declare static $VanityExtension: InferType<typeof VanityExtensionSchema>;
declare static $User: InferType<typeof UserSchema>;
declare static $Action: InferType<typeof ActionSchema>;
declare static $Like: InferType<typeof LikeSchema>;
declare static $Undo: InferType<typeof UndoSchema>;
declare static $Dislike: InferType<typeof DislikeSchema>;
declare static $Follow: InferType<typeof FollowSchema>;
declare static $FollowAccept: InferType<typeof FollowAcceptSchema>;
declare static $FollowReject: InferType<typeof FollowRejectSchema>;
declare static $Extension: InferType<typeof ExtensionSchema>;
declare static $Report: InferType<typeof ReportSchema>;
declare static $ServerMetadata: InferType<typeof ServerMetadataSchema>;
declare static $ContentFormat: InferType<typeof ContentFormatSchema>;
declare static $CustomEmojiExtension: InferType<
typeof CustomEmojiExtension
>;
declare static $Visibility: InferType<typeof VisibilitySchema>;
declare static $Publication: InferType<typeof PublicationSchema>;
declare static $Entity: InferType<typeof EntitySchema>;
/**
* Validates a Note entity.
* @param data - The data to validate
@ -264,8 +237,8 @@ export class EntityValidator {
*/
public CustomEmojiExtension(
data: unknown,
): Promise<InferType<typeof CustomEmojiExtension>> {
return this.validate(CustomEmojiExtension, data);
): Promise<InferType<typeof CustomEmojiExtensionSchema>> {
return this.validate(CustomEmojiExtensionSchema, data);
}
/**