refactor(database): Remove unused columns and rename baseUrl to domain

This commit is contained in:
Jesse Wierzbinski 2026-04-03 12:47:37 +02:00
parent 35d285bb2a
commit df2a5ce260
No known key found for this signature in database
16 changed files with 2448 additions and 59 deletions

View file

@ -18,18 +18,18 @@ export const refetchInstanceCommand = defineCommand(
? new URL(url_or_host).host ? new URL(url_or_host).host
: url_or_host; : url_or_host;
const instance = await Instance.fromSql(eq(Instances.baseUrl, host)); const instance = await Instance.fromSql(eq(Instances.domain, host));
if (!instance) { if (!instance) {
throw new Error(`Instance ${chalk.gray(host)} not found.`); throw new Error(`Instance ${chalk.gray(host)} not found.`);
} }
await fetchQueue.add(FetchJobType.Instance, { await fetchQueue.add(FetchJobType.Instance, {
uri: new URL(`https://${instance.data.baseUrl}`).origin, uri: new URL(`https://${instance.data.domain}`).origin,
}); });
console.info( console.info(
`Refresh job enqueued for ${chalk.gray(instance.data.baseUrl)}.`, `Refresh job enqueued for ${chalk.gray(instance.data.domain)}.`,
); );
}, },
); );

View file

@ -38,7 +38,7 @@ export const deleteUserCommand = defineCommand(
`Created At: ${chalk.blue(user.data.createdAt.toISOString())}`, `Created At: ${chalk.blue(user.data.createdAt.toISOString())}`,
); );
console.info( console.info(
`Instance: ${chalk.blue(user.data.instance?.baseUrl || "Local")}`, `Instance: ${chalk.blue(user.data.instance?.domain || "Local")}`,
); );
if (confirmFlag) { if (confirmFlag) {

View file

@ -166,7 +166,7 @@ export default apiRoute((app) =>
and( and(
eq(Users.username, username), eq(Users.username, username),
domain domain
? eq(Instances.baseUrl, domain) ? eq(Instances.domain, domain)
: isNull(Users.instanceId), : isNull(Users.instanceId),
), ),
) )

View file

@ -274,7 +274,7 @@ export class Instance extends BaseInterface<typeof Instances> {
public static async resolve(domain: string): Promise<Instance> { public static async resolve(domain: string): Promise<Instance> {
const existingInstance = await Instance.fromSql( const existingInstance = await Instance.fromSql(
eq(Instances.baseUrl, domain), eq(Instances.domain, domain),
); );
if (existingInstance) { if (existingInstance) {
@ -287,7 +287,7 @@ export class Instance extends BaseInterface<typeof Instances> {
return Instance.insert({ return Instance.insert({
id: randomUUIDv7(), id: randomUUIDv7(),
baseUrl: domain, domain,
name: metadata.data.name, name: metadata.data.name,
version: metadata.data.software.version, version: metadata.data.software.version,
logo: metadata.data.logo, logo: metadata.data.logo,
@ -298,11 +298,11 @@ export class Instance extends BaseInterface<typeof Instances> {
} }
public async updateFromRemote(): Promise<Instance> { public async updateFromRemote(): Promise<Instance> {
const output = await Instance.fetchMetadata(this.data.baseUrl); const output = await Instance.fetchMetadata(this.data.domain);
if (!output) { if (!output) {
federationResolversLogger.error`Failed to update instance ${chalk.bold( federationResolversLogger.error`Failed to update instance ${chalk.bold(
this.data.baseUrl, this.data.domain,
)}`; )}`;
throw new Error("Failed to update instance"); throw new Error("Failed to update instance");
} }
@ -353,7 +353,7 @@ export class Instance extends BaseInterface<typeof Instances> {
!this.data.extensions?.["pub.versia:instance_messaging"]?.endpoint !this.data.extensions?.["pub.versia:instance_messaging"]?.endpoint
) { ) {
federationMessagingLogger.info`Instance ${chalk.gray( federationMessagingLogger.info`Instance ${chalk.gray(
this.data.baseUrl, this.data.domain,
)} does not support Instance Messaging, skipping message`; )} does not support Instance Messaging, skipping message`;
return; return;

View file

@ -1,5 +1,4 @@
import * as VersiaEntities from "@versia/sdk/entities"; import * as VersiaEntities from "@versia/sdk/entities";
import { config } from "@versia-server/config";
import { import {
and, and,
desc, desc,
@ -161,15 +160,11 @@ export class Like extends BaseInterface<typeof Likes, LikeType> {
); );
} }
public getUri(): URL {
return new URL(`/likes/${this.data.id}`, config.http.base_url);
}
public toVersia(): VersiaEntities.Like { public toVersia(): VersiaEntities.Like {
let likedReference = this.data.liked.id; let likedReference = this.data.liked.id;
if (this.data.liked.author.instance) { if (this.data.liked.author.instance) {
likedReference = `${this.data.liked.author.instance.baseUrl}:${this.data.liked.remoteId}`; likedReference = `${this.data.liked.author.instance.domain}:${this.data.liked.remoteId}`;
} }
return new VersiaEntities.Like({ return new VersiaEntities.Like({

View file

@ -427,7 +427,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
public get reference(): VersiaEntities.Reference { public get reference(): VersiaEntities.Reference {
if (this.remote) { if (this.remote) {
const instanceUrl = new URL( const instanceUrl = new URL(
this.author.data.instance?.baseUrl || "", this.author.data.instance?.domain || "",
); );
return new VersiaEntities.Reference(this.id, instanceUrl.hostname); return new VersiaEntities.Reference(this.id, instanceUrl.hostname);
} }
@ -978,7 +978,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
? reference ? reference
: new VersiaEntities.Reference( : new VersiaEntities.Reference(
reference.id, reference.id,
instance.data.baseUrl, instance.data.domain,
), ),
); );
} }
@ -1232,11 +1232,11 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
acct: User.getAcct( acct: User.getAcct(
mention.instanceId === null, mention.instanceId === null,
mention.username, mention.username,
mention.instance?.baseUrl, mention.instance?.domain,
), ),
url: new URL( url: new URL(
`/@${mention.username}${ `/@${mention.username}${
mention.instance ? `@${mention.instance.baseUrl}` : "" mention.instance ? `@${mention.instance.domain}` : ""
}`, }`,
config.http.base_url, config.http.base_url,
).toString(), ).toString(),
@ -1274,8 +1274,8 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
} }
public getUri(): URL { public getUri(): URL {
const domain = this.author.data.instance?.baseUrl const domain = this.author.data.instance?.domain
? new URL(`https://${this.author.data.instance.baseUrl}`) ? new URL(`https://${this.author.data.instance.domain}`)
: config.http.base_url; : config.http.base_url;
return new URL( return new URL(
@ -1315,13 +1315,13 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
let quoteReference = status.quote?.id ?? null; let quoteReference = status.quote?.id ?? null;
if (quoteReference && status.quote?.author.instance) { if (quoteReference && status.quote?.author.instance) {
quoteReference = `${status.quote.author.instance.baseUrl}:${status.quote.remoteId}`; quoteReference = `${status.quote.author.instance.domain}:${status.quote.remoteId}`;
} }
let replyReference = status.reply?.id ?? null; let replyReference = status.reply?.id ?? null;
if (replyReference && status.reply?.author.instance) { if (replyReference && status.reply?.author.instance) {
replyReference = `${status.reply.author.instance.baseUrl}:${status.reply.remoteId}`; replyReference = `${status.reply.author.instance.domain}:${status.reply.remoteId}`;
} }
return new VersiaEntities.Note({ return new VersiaEntities.Note({
@ -1349,7 +1349,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
is_sensitive: status.sensitive, is_sensitive: status.sensitive,
mentions: status.mentions.map((mention) => mentions: status.mentions.map((mention) =>
mention.instance mention.instance
? `${mention.instance.baseUrl}:${mention.id}` ? `${mention.instance.domain}:${mention.id}`
: mention.id, : mention.id,
), ),
quotes: quoteReference, quotes: quoteReference,
@ -1379,7 +1379,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
id: this.id, id: this.id,
created_at: new Date().toISOString(), created_at: new Date().toISOString(),
shared: this.data.reblog.author.instance shared: this.data.reblog.author.instance
? `${this.data.reblog.author.instance.baseUrl}:${this.data.reblog.id}` ? `${this.data.reblog.author.instance.domain}:${this.data.reblog.id}`
: this.data.reblog.id, : this.data.reblog.id,
}); });
} }
@ -1499,7 +1499,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
} else if (reaction.emoji?.instance === null) { } else if (reaction.emoji?.instance === null) {
emojiName = `:${reaction.emoji.shortcode}:`; emojiName = `:${reaction.emoji.shortcode}:`;
} else if (reaction.emoji?.instance) { } else if (reaction.emoji?.instance) {
emojiName = `:${reaction.emoji.shortcode}@${reaction.emoji.instance.baseUrl}:`; emojiName = `:${reaction.emoji.shortcode}@${reaction.emoji.instance.domain}:`;
} else { } else {
continue; // Skip invalid reactions continue; // Skip invalid reactions
} }

View file

@ -1,4 +1,5 @@
import * as VersiaEntities from "@versia/sdk/entities"; import * as VersiaEntities from "@versia/sdk/entities";
import { config } from "@versia-server/config";
import { randomUUIDv7 } from "bun"; import { randomUUIDv7 } from "bun";
import { import {
and, and,
@ -212,13 +213,17 @@ export class Reaction extends BaseInterface<typeof Reactions, ReactionType> {
); );
} }
public getUri(baseUrl: URL): URL { public getUri(): URL {
return this.data.uri const domain = this.data.note.author.instance?.domain
? new URL(this.data.uri) ? new URL(`https://${this.data.note.author.instance.domain}`)
: new URL( : config.http.base_url;
`/notes/${this.data.noteId}/reactions/${this.id}`,
baseUrl, return new URL(
); `/.versia/v0.6/entities/${encodeURIComponent(
"pub.versia:reactions/Reaction",
)}/${this.id}`,
domain,
);
} }
public get local(): boolean { public get local(): boolean {
@ -237,7 +242,7 @@ export class Reaction extends BaseInterface<typeof Reactions, ReactionType> {
let noteReference = this.data.note.id; let noteReference = this.data.note.id;
if (this.data.note.author.instance) { if (this.data.note.author.instance) {
noteReference = `${this.data.note.author.instance.baseUrl}:${this.data.note.remoteId}`; noteReference = `${this.data.note.author.instance.domain}:${this.data.note.remoteId}`;
} }
return new VersiaEntities.Reaction({ return new VersiaEntities.Reaction({

View file

@ -229,13 +229,13 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
return new VersiaEntities.Reference( return new VersiaEntities.Reference(
this.data.remoteId as string, this.data.remoteId as string,
(this.data.instance as typeof Instance.$type).baseUrl, (this.data.instance as typeof Instance.$type).domain,
); );
} }
public get uri(): URL { public get uri(): URL {
const domain = this.data.instance?.baseUrl const domain = this.data.instance?.domain
? new URL(`https://${this.data.instance.baseUrl}`) ? new URL(`https://${this.data.instance.domain}`)
: config.http.base_url; : config.http.base_url;
return new URL( return new URL(
@ -335,7 +335,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
author: this.id, author: this.id,
created_at: new Date().toISOString(), created_at: new Date().toISOString(),
followee: followee.data.instance followee: followee.data.instance
? `${followee.data.instance.baseUrl}:${followee.id}` ? `${followee.data.instance.domain}:${followee.id}`
: followee.id, : followee.id,
}); });
} }
@ -357,7 +357,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
author: this.id, author: this.id,
created_at: new Date().toISOString(), created_at: new Date().toISOString(),
follower: follower.data.instance follower: follower.data.instance
? `${follower.data.instance.baseUrl}:${follower.id}` ? `${follower.data.instance.domain}:${follower.id}`
: follower.id, : follower.id,
}); });
@ -382,7 +382,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
author: this.id, author: this.id,
created_at: new Date().toISOString(), created_at: new Date().toISOString(),
follower: follower.data.instance follower: follower.data.instance
? `${follower.data.instance.baseUrl}:${follower.id}` ? `${follower.data.instance.domain}:${follower.id}`
: follower.id, : follower.id,
}); });
@ -840,7 +840,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
? reference ? reference
: new VersiaEntities.Reference( : new VersiaEntities.Reference(
reference.id, reference.id,
instance.data.baseUrl, instance.data.domain,
), ),
); );
} }
@ -910,7 +910,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
public getAcct(): string { public getAcct(): string {
return this.local return this.local
? this.data.username ? this.data.username
: `${this.data.username}@${this.data.instance?.baseUrl}`; : `${this.data.username}@${this.data.instance?.domain}`;
} }
public static getAcct( public static getAcct(
@ -1008,7 +1008,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
try { try {
await Instance.federationRequester.postEntity( await Instance.federationRequester.postEntity(
user.data.instance.baseUrl, user.data.instance.domain,
entity, entity,
); );
} catch (e) { } catch (e) {
@ -1034,7 +1034,7 @@ export class User extends BaseInterface<typeof Users, UserWithRelations> {
uri: this.uri.href, uri: this.uri.href,
url: new URL( url: new URL(
`/@${user.username}${ `/@${user.username}${
user.instanceId ? `@${user.instance?.baseUrl}` : "" user.instanceId ? `@${user.instance?.domain}` : ""
}`, }`,
config.http.base_url, config.http.base_url,
).href, ).href,

View file

@ -154,7 +154,7 @@ export class InboxProcessor {
!this.sender && !this.sender &&
federationInboxLogger.debug`Processing request from potential bridge`; federationInboxLogger.debug`Processing request from potential bridge`;
if (this.sender && isDefederated(this.sender.instance.data.baseUrl)) { if (this.sender && isDefederated(this.sender.instance.data.domain)) {
// Return 201 to avoid // Return 201 to avoid
// 1. Leaking defederated instance information // 1. Leaking defederated instance information
// 2. Preventing the sender from thinking the message was not delivered and retrying // 2. Preventing the sender from thinking the message was not delivered and retrying
@ -162,7 +162,7 @@ export class InboxProcessor {
} }
federationInboxLogger.debug`Instance ${chalk.gray( federationInboxLogger.debug`Instance ${chalk.gray(
this.sender?.instance.data.baseUrl, this.sender?.instance.data.domain,
)} is not defederated`; )} is not defederated`;
const shouldCheckSignature = this.shouldCheckSignature(); const shouldCheckSignature = this.shouldCheckSignature();

View file

@ -39,7 +39,7 @@ export const parseMentionsFromText = async (text: string): Promise<User[]> => {
.select({ .select({
id: Users.id, id: Users.id,
username: Users.username, username: Users.username,
baseUrl: Instances.baseUrl, baseUrl: Instances.domain,
}) })
.from(Users) .from(Users)
.leftJoin(Instances, eq(Users.instanceId, Instances.id)) .leftJoin(Instances, eq(Users.instanceId, Instances.id))
@ -50,7 +50,7 @@ export const parseMentionsFromText = async (text: string): Promise<User[]> => {
eq(Users.username, person[1] ?? ""), eq(Users.username, person[1] ?? ""),
isLocal(person[2]) isLocal(person[2])
? isNull(Users.instanceId) ? isNull(Users.instanceId)
: eq(Instances.baseUrl, person[2] ?? ""), : eq(Instances.domain, person[2] ?? ""),
), ),
), ),
), ),
@ -110,8 +110,8 @@ export const linkifyUserMentions = (text: string, mentions: User[]): string => {
if (mention.remote) { if (mention.remote) {
return finalText.replaceAll( return finalText.replaceAll(
`@${username}@${instance?.baseUrl}`, `@${username}@${instance?.domain}`,
linkTemplate(`@${username}@${instance?.baseUrl}`), linkTemplate(`@${username}@${instance?.domain}`),
); );
} }

View file

@ -20,7 +20,7 @@ export const getFetchWorker = (): Worker<FetchJobData, void, FetchJobType> =>
const host = new URL(uri).hostname; const host = new URL(uri).hostname;
const existingInstance = await Instance.fromSql( const existingInstance = await Instance.fromSql(
eq(Instances.baseUrl, host), eq(Instances.domain, host),
); );
if (existingInstance) { if (existingInstance) {

View file

@ -82,12 +82,12 @@ export const getInboxWorker = (): Worker<InboxJobData, void, InboxJobType> =>
} }
await job.log( await job.log(
`Entity [${data.id}] is from remote instance [${sender.data.baseUrl}]`, `Entity [${data.id}] is from remote instance [${sender.data.domain}]`,
); );
if (!sender.data.publicKey?.key) { if (!sender.data.publicKey?.key) {
throw new Error( throw new Error(
`Instance ${sender.data.baseUrl} has no public key stored in database`, `Instance ${sender.data.domain} has no public key stored in database`,
); );
} }
@ -124,7 +124,7 @@ export const getInboxWorker = (): Worker<InboxJobData, void, InboxJobType> =>
); );
await job.log( await job.log(
`Sending error message to instance [${sender.data.baseUrl}]`, `Sending error message to instance [${sender.data.domain}]`,
); );
await sender.sendMessage( await sender.sendMessage(

View file

@ -0,0 +1,3 @@
ALTER TABLE "Instances" RENAME COLUMN "base_url" TO "domain";--> statement-breakpoint
ALTER TABLE "Reaction" DROP CONSTRAINT "Reaction_uri_unique";--> statement-breakpoint
ALTER TABLE "Reaction" DROP COLUMN "uri";

File diff suppressed because it is too large Load diff

View file

@ -386,6 +386,13 @@
"when": 1771983340896, "when": 1771983340896,
"tag": "0054_good_madelyne_pryor", "tag": "0054_good_madelyne_pryor",
"breakpoints": true "breakpoints": true
},
{
"idx": 55,
"version": "7",
"when": 1775213166172,
"tag": "0055_yielding_harry_osborn",
"breakpoints": true
} }
] ]
} }

View file

@ -37,8 +37,6 @@ const updatedAt = () =>
.defaultNow() .defaultNow()
.notNull(); .notNull();
const uri = () => text("uri").unique();
const id = () => uuid("id").primaryKey(); const id = () => uuid("id").primaryKey();
export const Challenges = pgTable("Challenges", { export const Challenges = pgTable("Challenges", {
@ -136,7 +134,6 @@ export const PushSubscriptionsRelations = relations(
export const Reactions = pgTable("Reaction", { export const Reactions = pgTable("Reaction", {
id: id(), id: id(),
uri: uri(),
remoteId: text("remote_id"), remoteId: text("remote_id"),
// Emoji ID is nullable, in which case it is a text emoji, and the emojiText field is used // Emoji ID is nullable, in which case it is a text emoji, and the emojiText field is used
emojiId: uuid("emojiId").references(() => Emojis.id, { emojiId: uuid("emojiId").references(() => Emojis.id, {
@ -560,7 +557,7 @@ export const NotesRelations = relations(Notes, ({ many, one }) => ({
export const Instances = pgTable("Instances", { export const Instances = pgTable("Instances", {
id: id(), id: id(),
baseUrl: text("base_url").notNull(), domain: text("domain").notNull(),
name: text("name").notNull(), name: text("name").notNull(),
version: text("version").notNull(), version: text("version").notNull(),
logo: jsonb("logo").$type<typeof NonTextContentFormatSchema._input>(), logo: jsonb("logo").$type<typeof NonTextContentFormatSchema._input>(),