2025-03-22 02:34:03 +01:00
|
|
|
import type {
|
|
|
|
|
Application as ApplicationSchema,
|
|
|
|
|
CredentialApplication,
|
2025-03-22 18:04:47 +01:00
|
|
|
} from "@versia/client/schemas";
|
2024-10-23 17:56:47 +02:00
|
|
|
import {
|
|
|
|
|
desc,
|
|
|
|
|
eq,
|
2025-04-10 19:15:31 +02:00
|
|
|
type InferInsertModel,
|
|
|
|
|
type InferSelectModel,
|
2024-10-23 17:56:47 +02:00
|
|
|
inArray,
|
2025-04-10 19:15:31 +02:00
|
|
|
type SQL,
|
2024-10-23 17:56:47 +02:00
|
|
|
} from "drizzle-orm";
|
2025-07-07 03:42:35 +02:00
|
|
|
import type { z } from "zod/v4";
|
2025-07-04 06:29:43 +02:00
|
|
|
import { db } from "../tables/db.ts";
|
2025-08-21 00:45:58 +02:00
|
|
|
import { Clients } from "../tables/schema.ts";
|
2024-10-23 17:56:47 +02:00
|
|
|
import { BaseInterface } from "./base.ts";
|
2025-07-04 06:29:43 +02:00
|
|
|
import { Token } from "./token.ts";
|
2024-10-23 17:56:47 +02:00
|
|
|
|
2025-08-21 00:45:58 +02:00
|
|
|
type ApplicationType = InferSelectModel<typeof Clients>;
|
2024-10-23 17:56:47 +02:00
|
|
|
|
2025-08-21 00:45:58 +02:00
|
|
|
export class Application extends BaseInterface<typeof Clients> {
|
2024-11-04 14:58:17 +01:00
|
|
|
public static $type: ApplicationType;
|
|
|
|
|
|
2024-11-01 21:20:12 +01:00
|
|
|
public async reload(): Promise<void> {
|
2024-10-23 17:56:47 +02:00
|
|
|
const reloaded = await Application.fromId(this.data.id);
|
|
|
|
|
|
|
|
|
|
if (!reloaded) {
|
|
|
|
|
throw new Error("Failed to reload application");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.data = reloaded.data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async fromId(id: string | null): Promise<Application | null> {
|
|
|
|
|
if (!id) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-21 00:45:58 +02:00
|
|
|
return await Application.fromSql(eq(Clients.id, id));
|
2024-10-23 17:56:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async fromIds(ids: string[]): Promise<Application[]> {
|
2025-08-21 00:45:58 +02:00
|
|
|
return await Application.manyFromSql(inArray(Clients.id, ids));
|
2024-10-23 17:56:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async fromSql(
|
|
|
|
|
sql: SQL<unknown> | undefined,
|
2025-08-21 00:45:58 +02:00
|
|
|
orderBy: SQL<unknown> | undefined = desc(Clients.id),
|
2024-10-23 17:56:47 +02:00
|
|
|
): Promise<Application | null> {
|
2025-08-21 00:45:58 +02:00
|
|
|
const found = await db.query.Clients.findFirst({
|
2024-10-23 17:56:47 +02:00
|
|
|
where: sql,
|
|
|
|
|
orderBy,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!found) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return new Application(found);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async manyFromSql(
|
|
|
|
|
sql: SQL<unknown> | undefined,
|
2025-08-21 00:45:58 +02:00
|
|
|
orderBy: SQL<unknown> | undefined = desc(Clients.id),
|
2024-10-23 17:56:47 +02:00
|
|
|
limit?: number,
|
|
|
|
|
offset?: number,
|
2025-08-21 00:45:58 +02:00
|
|
|
extra?: Parameters<typeof db.query.Clients.findMany>[0],
|
2024-10-23 17:56:47 +02:00
|
|
|
): Promise<Application[]> {
|
2025-08-21 00:45:58 +02:00
|
|
|
const found = await db.query.Clients.findMany({
|
2024-10-23 17:56:47 +02:00
|
|
|
where: sql,
|
|
|
|
|
orderBy,
|
|
|
|
|
limit,
|
|
|
|
|
offset,
|
|
|
|
|
with: extra?.with,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return found.map((s) => new Application(s));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async getFromToken(
|
|
|
|
|
token: string,
|
|
|
|
|
): Promise<Application | null> {
|
2024-11-03 17:45:21 +01:00
|
|
|
const result = await Token.fromAccessToken(token);
|
2024-10-23 17:56:47 +02:00
|
|
|
|
2025-08-21 00:45:58 +02:00
|
|
|
return result?.data.client ? new Application(result.data.client) : null;
|
2024-10-23 17:56:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static fromClientId(clientId: string): Promise<Application | null> {
|
2025-08-21 00:45:58 +02:00
|
|
|
return Application.fromSql(eq(Clients.id, clientId));
|
2024-10-23 17:56:47 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-01 21:20:12 +01:00
|
|
|
public async update(
|
2024-10-23 17:56:47 +02:00
|
|
|
newApplication: Partial<ApplicationType>,
|
|
|
|
|
): Promise<ApplicationType> {
|
|
|
|
|
await db
|
2025-08-21 00:45:58 +02:00
|
|
|
.update(Clients)
|
2024-10-23 17:56:47 +02:00
|
|
|
.set(newApplication)
|
2025-08-21 00:45:58 +02:00
|
|
|
.where(eq(Clients.id, this.id));
|
2024-10-23 17:56:47 +02:00
|
|
|
|
|
|
|
|
const updated = await Application.fromId(this.data.id);
|
|
|
|
|
|
|
|
|
|
if (!updated) {
|
|
|
|
|
throw new Error("Failed to update application");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.data = updated.data;
|
|
|
|
|
return updated.data;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-01 21:20:12 +01:00
|
|
|
public save(): Promise<ApplicationType> {
|
2024-10-23 17:56:47 +02:00
|
|
|
return this.update(this.data);
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-01 21:20:12 +01:00
|
|
|
public async delete(ids?: string[]): Promise<void> {
|
2024-10-23 17:56:47 +02:00
|
|
|
if (Array.isArray(ids)) {
|
2025-08-21 00:45:58 +02:00
|
|
|
await db.delete(Clients).where(inArray(Clients.id, ids));
|
2024-10-23 17:56:47 +02:00
|
|
|
} else {
|
2025-08-21 00:45:58 +02:00
|
|
|
await db.delete(Clients).where(eq(Clients.id, this.id));
|
2024-10-23 17:56:47 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async insert(
|
2025-08-21 00:45:58 +02:00
|
|
|
data: InferInsertModel<typeof Clients>,
|
2024-10-23 17:56:47 +02:00
|
|
|
): Promise<Application> {
|
2025-08-21 00:45:58 +02:00
|
|
|
const inserted = (await db.insert(Clients).values(data).returning())[0];
|
2024-10-23 17:56:47 +02:00
|
|
|
|
|
|
|
|
const application = await Application.fromId(inserted.id);
|
|
|
|
|
|
|
|
|
|
if (!application) {
|
|
|
|
|
throw new Error("Failed to insert application");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return application;
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-02 00:43:33 +01:00
|
|
|
public get id(): string {
|
2024-10-23 17:56:47 +02:00
|
|
|
return this.data.id;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-05 22:49:07 +01:00
|
|
|
public toApi(): z.infer<typeof ApplicationSchema> {
|
|
|
|
|
return {
|
|
|
|
|
name: this.data.name,
|
|
|
|
|
website: this.data.website,
|
2025-08-21 00:45:58 +02:00
|
|
|
scopes: this.data.scopes,
|
|
|
|
|
redirect_uri: this.data.redirectUris.join(" "),
|
|
|
|
|
redirect_uris: this.data.redirectUris,
|
2025-02-05 22:49:07 +01:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public toApiCredential(): z.infer<typeof CredentialApplication> {
|
2024-10-23 17:56:47 +02:00
|
|
|
return {
|
|
|
|
|
name: this.data.name,
|
|
|
|
|
website: this.data.website,
|
2025-08-21 00:45:58 +02:00
|
|
|
client_id: this.data.id,
|
2025-02-05 22:49:07 +01:00
|
|
|
client_secret: this.data.secret,
|
|
|
|
|
client_secret_expires_at: "0",
|
2025-08-21 00:45:58 +02:00
|
|
|
scopes: this.data.scopes,
|
|
|
|
|
redirect_uri: this.data.redirectUris.join(" "),
|
|
|
|
|
redirect_uris: this.data.redirectUris,
|
2024-10-23 17:56:47 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|