refactor(federation): ⬆️ Use @lysand-org/federation v2.0.0

This commit is contained in:
Jesse Wierzbinski 2024-06-19 13:21:02 -10:00
parent 47ce60494a
commit 70cd00cfa8
No known key found for this signature in database
17 changed files with 56 additions and 60 deletions

BIN
bun.lockb

Binary file not shown.

View file

@ -1,8 +1,6 @@
import { debugRequest } from "@/api";
import {
type EntityValidator,
SignatureConstructor,
} from "@lysand-org/federation";
import { SignatureConstructor } from "@lysand-org/federation";
import type { Entity, Undo } from "@lysand-org/federation/types";
import { config } from "config-manager";
import type { User } from "~/packages/database-interface/user";
import { LogLevel, LogManager } from "~/packages/log-manager";
@ -11,7 +9,7 @@ export const localObjectUri = (id: string) =>
new URL(`/objects/${id}`, config.http.base_url).toString();
export const objectToInboxRequest = async (
object: typeof EntityValidator.$Entity,
object: Entity,
author: User,
userToSendTo: User,
): Promise<Request> => {
@ -68,10 +66,7 @@ export const objectToInboxRequest = async (
return signed;
};
export const undoFederationRequest = (
undoer: User,
uri: string,
): typeof EntityValidator.$Undo => {
export const undoFederationRequest = (undoer: User, uri: string): Undo => {
const id = crypto.randomUUID();
return {
type: "Undo",

View file

@ -1,4 +1,4 @@
import type { EntityValidator } from "@lysand-org/federation";
import type { ServerMetadata } from "@lysand-org/federation/types";
import { db } from "~/drizzle/db";
import { Instances } from "~/drizzle/schema";
@ -26,7 +26,7 @@ export const addInstanceIfNotExists = async (url: string) => {
// Fetch the instance configuration
const metadata = (await fetch(new URL("/.well-known/lysand", origin)).then(
(res) => res.json(),
)) as typeof EntityValidator.$ServerMetadata;
)) as ServerMetadata;
if (metadata.type !== "ServerMetadata") {
throw new Error("Invalid instance metadata (wrong type)");

View file

@ -1,4 +1,4 @@
import type { EntityValidator } from "@lysand-org/federation";
import type { Like } from "@lysand-org/federation/types";
import { config } from "config-manager";
import { type InferSelectModel, and, eq } from "drizzle-orm";
import { db } from "~/drizzle/db";
@ -6,12 +6,12 @@ import { Likes, Notifications } from "~/drizzle/schema";
import type { Note } from "~/packages/database-interface/note";
import type { User } from "~/packages/database-interface/user";
export type Like = InferSelectModel<typeof Likes>;
export type LikeType = InferSelectModel<typeof Likes>;
/**
* Represents a Like entity in the database.
*/
export const likeToLysand = (like: Like): typeof EntityValidator.$Like => {
export const likeToLysand = (like: LikeType): Like => {
return {
id: like.id,
// biome-ignore lint/suspicious/noExplicitAny: to be rewritten

View file

@ -2,7 +2,7 @@ import { mentionValidator } from "@/api";
import { dualLogger } from "@/loggers";
import { sanitizeHtml, sanitizeHtmlInline } from "@/sanitization";
import markdownItTaskLists from "@hackmd/markdown-it-task-lists";
import type { EntityValidator } from "@lysand-org/federation";
import type { ContentFormat } from "@lysand-org/federation/types";
import { config } from "config-manager";
import {
type InferSelectModel,
@ -373,7 +373,7 @@ export const replaceTextMentions = (text: string, mentions: User[]) => {
};
export const contentToHtml = async (
content: typeof EntityValidator.$ContentFormat,
content: ContentFormat,
mentions: User[] = [],
inline = false,
): Promise<string> => {

View file

@ -1,5 +1,9 @@
import { dualLogger } from "@/loggers";
import type { EntityValidator } from "@lysand-org/federation";
import type {
Follow,
FollowAccept,
FollowReject,
} from "@lysand-org/federation/types";
import { config } from "config-manager";
import { type InferSelectModel, and, eq, sql } from "drizzle-orm";
import { db } from "~/drizzle/db";
@ -505,7 +509,7 @@ export const getRelationshipToOtherUser = async (
export const followRequestToLysand = (
follower: User,
followee: User,
): typeof EntityValidator.$Follow => {
): Follow => {
if (follower.isRemote()) {
throw new Error("Follower must be a local user");
}
@ -533,7 +537,7 @@ export const followRequestToLysand = (
export const followAcceptToLysand = (
follower: User,
followee: User,
): typeof EntityValidator.$FollowAccept => {
): FollowAccept => {
if (!follower.isRemote()) {
throw new Error("Follower must be a remote user");
}
@ -561,7 +565,7 @@ export const followAcceptToLysand = (
export const followRejectToLysand = (
follower: User,
followee: User,
): typeof EntityValidator.$FollowReject => {
): FollowReject => {
return {
...followAcceptToLysand(follower, followee),
type: "FollowReject",

View file

@ -1,4 +1,4 @@
import type { EntityValidator } from "@lysand-org/federation";
import type { ContentFormat } from "@lysand-org/federation/types";
import type { Challenge } from "altcha-lib/types";
import { relations, sql } from "drizzle-orm";
import {
@ -375,8 +375,8 @@ export const Users = pgTable(
passwordResetToken: text("password_reset_token"),
fields: jsonb("fields").notNull().default("[]").$type<
{
key: typeof EntityValidator.$ContentFormat;
value: typeof EntityValidator.$ContentFormat;
key: ContentFormat;
value: ContentFormat;
}[]
>(),
endpoints: jsonb("endpoints").$type<Partial<{

View file

@ -100,7 +100,7 @@
"@inquirer/confirm": "^3.1.10",
"@inquirer/input": "^2.1.10",
"@json2csv/plainjs": "^7.0.6",
"@lysand-org/federation": "^1.2.0",
"@lysand-org/federation": "^2.0.0",
"@oclif/core": "^4.0.6",
"@tufjs/canonical-json": "^2.0.0",
"altcha-lib": "^0.3.0",

View file

@ -1,5 +1,5 @@
import { proxyUrl } from "@/response";
import type { EntityValidator } from "@lysand-org/federation";
import type { ContentFormat } from "@lysand-org/federation/types";
import {
type InferInsertModel,
type InferSelectModel,
@ -183,7 +183,7 @@ export class Attachment extends BaseInterface<typeof Attachments> {
};
}
public toLysand(): typeof EntityValidator.$ContentFormat {
public toLysand(): ContentFormat {
return {
[this.data.mimeType]: {
content: this.data.url,
@ -204,7 +204,7 @@ export class Attachment extends BaseInterface<typeof Attachments> {
}
public static fromLysand(
attachmentToConvert: typeof EntityValidator.$ContentFormat,
attachmentToConvert: ContentFormat,
): Promise<Attachment> {
const key = Object.keys(attachmentToConvert)[0];
const value = attachmentToConvert[key];

View file

@ -1,5 +1,5 @@
import { proxyUrl } from "@/response";
import type { EntityValidator } from "@lysand-org/federation";
import type { CustomEmojiExtension } from "@lysand-org/federation/types";
import {
type InferInsertModel,
type SQL,
@ -118,7 +118,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
}
public static async fetchFromRemote(
emojiToFetch: (typeof EntityValidator.$CustomEmojiExtension)["emojis"][0],
emojiToFetch: CustomEmojiExtension["emojis"][0],
host?: string,
): Promise<Emoji> {
const existingEmoji = await db
@ -164,7 +164,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
};
}
public toLysand(): (typeof EntityValidator.$CustomEmojiExtension)["emojis"][0] {
public toLysand(): CustomEmojiExtension["emojis"][0] {
return {
name: this.data.shortcode,
url: {
@ -177,7 +177,7 @@ export class Emoji extends BaseInterface<typeof Emojis, EmojiWithInstance> {
}
public static fromLysand(
emoji: (typeof EntityValidator.$CustomEmojiExtension)["emojis"][0],
emoji: CustomEmojiExtension["emojis"][0],
instanceId: string | null,
): Promise<Emoji> {
return Emoji.insert({

View file

@ -3,6 +3,10 @@ import { dualLogger } from "@/loggers";
import { proxyUrl } from "@/response";
import { sanitizedHtmlStrip } from "@/sanitization";
import { EntityValidator } from "@lysand-org/federation";
import type {
ContentFormat,
Note as LysandNote,
} from "@lysand-org/federation/types";
import {
type InferInsertModel,
type SQL,
@ -302,7 +306,7 @@ export class Note extends BaseInterface<typeof Notes, StatusWithRelations> {
*/
static async fromData(data: {
author: User;
content: typeof EntityValidator.$ContentFormat;
content: ContentFormat;
visibility: APIStatus["visibility"];
isSensitive: boolean;
spoilerText: string;
@ -392,7 +396,7 @@ export class Note extends BaseInterface<typeof Notes, StatusWithRelations> {
*/
async updateFromData(data: {
author?: User;
content?: typeof EntityValidator.$ContentFormat;
content?: ContentFormat;
visibility?: APIStatus["visibility"];
isSensitive?: boolean;
spoilerText?: string;
@ -579,7 +583,7 @@ export class Note extends BaseInterface<typeof Notes, StatusWithRelations> {
* @returns The saved note, or null if the note could not be fetched
*/
static async saveFromRemote(uri: string): Promise<Note | null> {
let note: typeof EntityValidator.$Note | null = null;
let note: LysandNote | null = null;
if (uri) {
if (!URL.canParse(uri)) {
@ -615,10 +619,7 @@ export class Note extends BaseInterface<typeof Notes, StatusWithRelations> {
* @param author Author of the note
* @returns The saved note
*/
static async fromLysand(
note: typeof EntityValidator.$Note,
author: User,
): Promise<Note> {
static async fromLysand(note: LysandNote, author: User): Promise<Note> {
const emojis: Emoji[] = [];
for (const emoji of note.extensions?.["org.lysand:custom_emojis"]
@ -878,7 +879,7 @@ export class Note extends BaseInterface<typeof Notes, StatusWithRelations> {
* Convert a note to the Lysand format
* @returns The note in the Lysand format
*/
toLysand(): typeof EntityValidator.$Note {
toLysand(): LysandNote {
const status = this.data;
return {
type: "Note",

View file

@ -4,6 +4,7 @@ import { randomString } from "@/math";
import { addUserToMeilisearch } from "@/meilisearch";
import { proxyUrl } from "@/response";
import { EntityValidator } from "@lysand-org/federation";
import type { Entity, User as LysandUser } from "@lysand-org/federation/types";
import {
type InferInsertModel,
type InferSelectModel,
@ -254,9 +255,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
},
});
const json = (await response.json()) as Partial<
typeof EntityValidator.$User
>;
const json = (await response.json()) as Partial<LysandUser>;
const validator = new EntityValidator();
@ -299,7 +298,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
}
static async fromLysand(
user: typeof EntityValidator.$User,
user: LysandUser,
instance: InferSelectModel<typeof Instances>,
): Promise<User> {
const data = {
@ -535,7 +534,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
return updated.data;
}
async federateToFollowers(object: typeof EntityValidator.$Entity) {
async federateToFollowers(object: Entity) {
// Get followers
const followers = await User.manyFromSql(
and(
@ -625,7 +624,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
};
}
toLysand(): typeof EntityValidator.$User {
toLysand(): LysandUser {
if (this.isRemote()) {
throw new Error("Cannot convert remote user to Lysand format");
}

View file

@ -1,11 +1,11 @@
import { applyConfig, handleZodError } from "@/api";
import { errorResponse, jsonResponse } from "@/response";
import { zValidator } from "@hono/zod-validator";
import type { EntityValidator } from "@lysand-org/federation";
import type { Entity } from "@lysand-org/federation/types";
import { and, eq, inArray, sql } from "drizzle-orm";
import type { Hono } from "hono";
import { z } from "zod";
import { type Like, likeToLysand } from "~/database/entities/like";
import { type LikeType, likeToLysand } from "~/database/entities/like";
import { db } from "~/drizzle/db";
import { Notes } from "~/drizzle/schema";
import { Note } from "~/packages/database-interface/note";
@ -36,8 +36,8 @@ export default (app: Hono) =>
async (context) => {
const { id } = context.req.valid("param");
let foundObject: Note | Like | null = null;
let apiObject: typeof EntityValidator.$Entity | null = null;
let foundObject: Note | LikeType | null = null;
let apiObject: Entity | null = null;
foundObject = await Note.fromSql(
and(

View file

@ -7,6 +7,7 @@ import {
RequestParserHandler,
SignatureValidator,
} from "@lysand-org/federation";
import type { Entity } from "@lysand-org/federation/types";
import type { SocketAddress } from "bun";
import { and, eq } from "drizzle-orm";
import type { Hono } from "hono";
@ -72,8 +73,7 @@ export default (app: Hono) =>
return response(null, 201);
}
const body: typeof EntityValidator.$Entity =
await context.req.valid("json");
const body: Entity = await context.req.valid("json");
if (config.debug.federation) {
// Debug request

View file

@ -1,7 +1,7 @@
import { applyConfig } from "@/api";
import { urlToContentFormat } from "@/content_types";
import { jsonResponse } from "@/response";
import type { EntityValidator } from "@lysand-org/federation";
import type { ServerMetadata } from "@lysand-org/federation/types";
import type { Hono } from "hono";
import pkg from "~/package.json";
import { config } from "~/packages/config-manager";
@ -29,5 +29,5 @@ export default (app: Hono) =>
banner: urlToContentFormat(config.instance.banner) ?? undefined,
supported_extensions: ["org.lysand:custom_emojis"],
website: "https://lysand.org",
} satisfies typeof EntityValidator.$ServerMetadata);
} satisfies ServerMetadata);
});

View file

@ -28,6 +28,7 @@
},
"noUnusedLocals": true
},
"exclude": ["node_modules"],
"include": [
"*.ts",
"*.d.ts",

View file

@ -1,9 +1,7 @@
import type { EntityValidator } from "@lysand-org/federation";
import type { ContentFormat } from "@lysand-org/federation/types";
import { lookup } from "mime-types";
export const getBestContentType = (
content?: typeof EntityValidator.$ContentFormat,
) => {
export const getBestContentType = (content?: ContentFormat) => {
if (!content) {
return { content: "", format: "text/plain" };
}
@ -24,9 +22,7 @@ export const getBestContentType = (
return { content: "", format: "text/plain" };
};
export const urlToContentFormat = (
url?: string,
): typeof EntityValidator.$ContentFormat | null => {
export const urlToContentFormat = (url?: string): ContentFormat | null => {
if (!url) {
return null;
}