mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
refactor(database): 🚚 Rename Application to Client everywhere
This commit is contained in:
parent
6f97903f3b
commit
1a0a27bee1
|
|
@ -1,4 +1,4 @@
|
||||||
import { Application, Token } from "@versia-server/kit/db";
|
import { Client, Token } from "@versia-server/kit/db";
|
||||||
import { randomUUIDv7 } from "bun";
|
import { randomUUIDv7 } from "bun";
|
||||||
import chalk from "chalk";
|
import chalk from "chalk";
|
||||||
// @ts-expect-error - Root import is required or the Clec type definitions won't work
|
// @ts-expect-error - Root import is required or the Clec type definitions won't work
|
||||||
|
|
@ -22,7 +22,7 @@ export const generateTokenCommand = defineCommand(
|
||||||
throw new Error(`User ${chalk.gray(username)} not found.`);
|
throw new Error(`User ${chalk.gray(username)} not found.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const application = await Application.insert({
|
const application = await Client.insert({
|
||||||
id:
|
id:
|
||||||
user.id +
|
user.id +
|
||||||
Buffer.from(
|
Buffer.from(
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
//import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import type { Config } from "drizzle-kit";
|
import type { Config } from "drizzle-kit";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -10,16 +10,16 @@ export default {
|
||||||
out: "./packages/kit/tables/migrations",
|
out: "./packages/kit/tables/migrations",
|
||||||
schema: "./packages/kit/tables/schema.ts",
|
schema: "./packages/kit/tables/schema.ts",
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
host: "localhost",
|
/* host: "localhost",
|
||||||
port: 40000,
|
port: 40000,
|
||||||
user: "lysand",
|
user: "lysand",
|
||||||
password: "lysand",
|
password: "lysand",
|
||||||
database: "lysand",
|
database: "lysand", */
|
||||||
/* host: config.postgres.host,
|
host: config.postgres.host,
|
||||||
port: config.postgres.port,
|
port: config.postgres.port,
|
||||||
user: config.postgres.username,
|
user: config.postgres.username,
|
||||||
password: config.postgres.password,
|
password: config.postgres.password,
|
||||||
database: config.postgres.database, */
|
database: config.postgres.database,
|
||||||
},
|
},
|
||||||
// Print all statements
|
// Print all statements
|
||||||
verbose: true,
|
verbose: true,
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
import { afterAll, describe, expect, test } from "bun:test";
|
import { afterAll, describe, expect, test } from "bun:test";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { Application } from "@versia-server/kit/db";
|
import { Client } from "@versia-server/kit/db";
|
||||||
import { fakeRequest, getTestUsers } from "@versia-server/tests";
|
import { fakeRequest, getTestUsers } from "@versia-server/tests";
|
||||||
import { randomString } from "@/math";
|
import { randomString } from "@/math";
|
||||||
|
|
||||||
const { users, deleteUsers, passwords } = await getTestUsers(1);
|
const { users, deleteUsers, passwords } = await getTestUsers(1);
|
||||||
|
|
||||||
// Create application
|
// Create application
|
||||||
const application = await Application.insert({
|
const application = await Client.insert({
|
||||||
id: randomString(32, "hex"),
|
id: randomString(32, "hex"),
|
||||||
name: "Test Application",
|
name: "Test Client",
|
||||||
secret: "test",
|
secret: "test",
|
||||||
redirectUris: ["https://example.com"],
|
redirectUris: ["https://example.com"],
|
||||||
scopes: ["read", "write"],
|
scopes: ["read", "write"],
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
import { apiRoute, handleZodError } from "@versia-server/kit/api";
|
import { apiRoute, handleZodError } from "@versia-server/kit/api";
|
||||||
import { Application, User } from "@versia-server/kit/db";
|
import { Client, User } from "@versia-server/kit/db";
|
||||||
import { Users } from "@versia-server/kit/tables";
|
import { Users } from "@versia-server/kit/tables";
|
||||||
import { password as bunPassword } from "bun";
|
import { password as bunPassword } from "bun";
|
||||||
import { eq, or } from "drizzle-orm";
|
import { eq, or } from "drizzle-orm";
|
||||||
|
|
@ -156,7 +156,7 @@ export default apiRoute((app) =>
|
||||||
config.authentication.key,
|
config.authentication.key,
|
||||||
);
|
);
|
||||||
|
|
||||||
const application = await Application.fromClientId(client_id);
|
const application = await Client.fromClientId(client_id);
|
||||||
|
|
||||||
if (!application) {
|
if (!application) {
|
||||||
throw new ApiError(400, "Invalid application");
|
throw new ApiError(400, "Invalid application");
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import {
|
||||||
} from "@versia/client/schemas";
|
} from "@versia/client/schemas";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
import { apiRoute, handleZodError, jsonOrForm } from "@versia-server/kit/api";
|
import { apiRoute, handleZodError, jsonOrForm } from "@versia-server/kit/api";
|
||||||
import { Application } from "@versia-server/kit/db";
|
import { Client } from "@versia-server/kit/db";
|
||||||
import { describeRoute, resolver, validator } from "hono-openapi";
|
import { describeRoute, resolver, validator } from "hono-openapi";
|
||||||
import { z } from "zod/v4";
|
import { z } from "zod/v4";
|
||||||
import { randomString } from "@/math";
|
import { randomString } from "@/math";
|
||||||
|
|
@ -62,7 +62,7 @@ export default apiRoute((app) =>
|
||||||
const { client_name, redirect_uris, scopes, website } =
|
const { client_name, redirect_uris, scopes, website } =
|
||||||
context.req.valid("json");
|
context.req.valid("json");
|
||||||
|
|
||||||
const app = await Application.insert({
|
const app = await Client.insert({
|
||||||
id: randomString(32, "base64url"),
|
id: randomString(32, "base64url"),
|
||||||
name: client_name,
|
name: client_name,
|
||||||
redirectUris: Array.isArray(redirect_uris)
|
redirectUris: Array.isArray(redirect_uris)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import {
|
||||||
} from "@versia/client/schemas";
|
} from "@versia/client/schemas";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
import { apiRoute, auth } from "@versia-server/kit/api";
|
import { apiRoute, auth } from "@versia-server/kit/api";
|
||||||
import { Application } from "@versia-server/kit/db";
|
import { Client } from "@versia-server/kit/db";
|
||||||
import { describeRoute, resolver } from "hono-openapi";
|
import { describeRoute, resolver } from "hono-openapi";
|
||||||
|
|
||||||
export default apiRoute((app) =>
|
export default apiRoute((app) =>
|
||||||
|
|
@ -38,7 +38,7 @@ export default apiRoute((app) =>
|
||||||
async (context) => {
|
async (context) => {
|
||||||
const { token } = context.get("auth");
|
const { token } = context.get("auth");
|
||||||
|
|
||||||
const application = await Application.getFromToken(
|
const application = await Client.getFromToken(
|
||||||
token.data.accessToken,
|
token.data.accessToken,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { RolePermission } from "@versia/client/schemas";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
import { apiRoute, auth, handleZodError } from "@versia-server/kit/api";
|
import { apiRoute, auth, handleZodError } from "@versia-server/kit/api";
|
||||||
import { Application, db } from "@versia-server/kit/db";
|
import { Client, db } from "@versia-server/kit/db";
|
||||||
import { OpenIdLoginFlows } from "@versia-server/kit/tables";
|
import { OpenIdLoginFlows } from "@versia-server/kit/tables";
|
||||||
import { randomUUIDv7 } from "bun";
|
import { randomUUIDv7 } from "bun";
|
||||||
import { describeRoute, resolver, validator } from "hono-openapi";
|
import { describeRoute, resolver, validator } from "hono-openapi";
|
||||||
|
|
@ -123,7 +123,7 @@ export default apiRoute((app) => {
|
||||||
issuerId,
|
issuerId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const application = await Application.insert({
|
const application = await Client.insert({
|
||||||
id:
|
id:
|
||||||
user.id +
|
user.id +
|
||||||
Buffer.from(
|
Buffer.from(
|
||||||
|
|
@ -144,7 +144,7 @@ export default apiRoute((app) => {
|
||||||
codeVerifier,
|
codeVerifier,
|
||||||
state: parameters.state,
|
state: parameters.state,
|
||||||
issuerId,
|
issuerId,
|
||||||
applicationId: application.id,
|
clientId: application.id,
|
||||||
})
|
})
|
||||||
.returning()
|
.returning()
|
||||||
)[0];
|
)[0];
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ export default apiRoute((app) =>
|
||||||
spoilerText: sanitizedSpoilerText,
|
spoilerText: sanitizedSpoilerText,
|
||||||
replyId: in_reply_to_id ?? undefined,
|
replyId: in_reply_to_id ?? undefined,
|
||||||
quotingId: quote_id ?? undefined,
|
quotingId: quote_id ?? undefined,
|
||||||
applicationId: application?.id,
|
clientId: application?.id,
|
||||||
contentSource: status,
|
contentSource: status,
|
||||||
contentType: content_type,
|
contentType: content_type,
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,10 @@ afterAll(async () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Login flow", () => {
|
describe("Login flow", () => {
|
||||||
test("should create an application", async () => {
|
test("should create a client", async () => {
|
||||||
const client = await generateClient(users[0]);
|
const client = await generateClient(users[0]);
|
||||||
|
|
||||||
const { ok, data } = await client.createApp("Test Application", {
|
const { ok, data } = await client.createApp("Test Client", {
|
||||||
redirect_uris: "https://example.com",
|
redirect_uris: "https://example.com",
|
||||||
website: "https://example.com",
|
website: "https://example.com",
|
||||||
scopes: ["read", "write"],
|
scopes: ["read", "write"],
|
||||||
|
|
@ -24,7 +24,7 @@ describe("Login flow", () => {
|
||||||
|
|
||||||
expect(ok).toBe(true);
|
expect(ok).toBe(true);
|
||||||
expect(data).toEqual({
|
expect(data).toEqual({
|
||||||
name: "Test Application",
|
name: "Test Client",
|
||||||
website: "https://example.com",
|
website: "https://example.com",
|
||||||
client_id: expect.any(String),
|
client_id: expect.any(String),
|
||||||
client_secret: expect.any(String),
|
client_secret: expect.any(String),
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { afterAll, describe, expect, test } from "bun:test";
|
import { afterAll, describe, expect, test } from "bun:test";
|
||||||
import { Application, Token } from "@versia-server/kit/db";
|
import { Client, Token } from "@versia-server/kit/db";
|
||||||
import { fakeRequest, getTestUsers } from "@versia-server/tests";
|
import { fakeRequest, getTestUsers } from "@versia-server/tests";
|
||||||
import { randomUUIDv7 } from "bun";
|
import { randomUUIDv7 } from "bun";
|
||||||
|
|
||||||
const { deleteUsers, users } = await getTestUsers(1);
|
const { deleteUsers, users } = await getTestUsers(1);
|
||||||
|
|
||||||
const application = await Application.insert({
|
const application = await Client.insert({
|
||||||
id: randomUUIDv7(),
|
id: randomUUIDv7(),
|
||||||
redirectUris: ["https://example.com/callback"],
|
redirectUris: ["https://example.com/callback"],
|
||||||
scopes: ["openid", "profile", "email"],
|
scopes: ["openid", "profile", "email"],
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ export default apiRoute((app) => {
|
||||||
const flow = await db.query.OpenIdLoginFlows.findFirst({
|
const flow = await db.query.OpenIdLoginFlows.findFirst({
|
||||||
where: (flow): SQL | undefined => eq(flow.id, flowId),
|
where: (flow): SQL | undefined => eq(flow.id, flowId),
|
||||||
with: {
|
with: {
|
||||||
application: true,
|
client: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -129,11 +129,11 @@ export default apiRoute((app) => {
|
||||||
// If linking account
|
// If linking account
|
||||||
if (link && user_id) {
|
if (link && user_id) {
|
||||||
// Check if userId is equal to application.clientId
|
// Check if userId is equal to application.clientId
|
||||||
if (!flow.application?.id.startsWith(user_id)) {
|
if (!flow.client?.id.startsWith(user_id)) {
|
||||||
return redirectWithMessage(
|
return redirectWithMessage(
|
||||||
{
|
{
|
||||||
oidc_account_linking_error: "Account linking error",
|
oidc_account_linking_error: "Account linking error",
|
||||||
oidc_account_linking_error_message: `User ID does not match application client ID (${user_id} != ${flow.application?.id})`,
|
oidc_account_linking_error_message: `User ID does not match application client ID (${user_id} != ${flow.client?.id})`,
|
||||||
},
|
},
|
||||||
config.frontend.routes.home,
|
config.frontend.routes.home,
|
||||||
);
|
);
|
||||||
|
|
@ -262,14 +262,14 @@ export default apiRoute((app) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!flow.application) {
|
if (!flow.client) {
|
||||||
throw new ApiError(500, "Application not found");
|
throw new ApiError(500, "Application not found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const code = randomString(32, "hex");
|
const code = randomString(32, "hex");
|
||||||
|
|
||||||
await db.insert(AuthorizationCodes).values({
|
await db.insert(AuthorizationCodes).values({
|
||||||
clientId: flow.application.id,
|
clientId: flow.client.id,
|
||||||
code,
|
code,
|
||||||
expiresAt: new Date(Date.now() + 60 * 1000).toISOString(), // 1 minute
|
expiresAt: new Date(Date.now() + 60 * 1000).toISOString(), // 1 minute
|
||||||
redirectUri: flow.clientRedirectUri ?? undefined,
|
redirectUri: flow.clientRedirectUri ?? undefined,
|
||||||
|
|
@ -281,7 +281,7 @@ export default apiRoute((app) => {
|
||||||
{
|
{
|
||||||
sub: user.id,
|
sub: user.id,
|
||||||
iss: new URL(context.get("config").http.base_url).origin,
|
iss: new URL(context.get("config").http.base_url).origin,
|
||||||
aud: flow.application.id,
|
aud: flow.client.id,
|
||||||
exp: Math.floor(Date.now() / 1000) + 60 * 60,
|
exp: Math.floor(Date.now() / 1000) + 60 * 60,
|
||||||
iat: Math.floor(Date.now() / 1000),
|
iat: Math.floor(Date.now() / 1000),
|
||||||
nbf: Math.floor(Date.now() / 1000),
|
nbf: Math.floor(Date.now() / 1000),
|
||||||
|
|
@ -303,9 +303,9 @@ export default apiRoute((app) => {
|
||||||
{
|
{
|
||||||
redirect_uri: flow.clientRedirectUri ?? undefined,
|
redirect_uri: flow.clientRedirectUri ?? undefined,
|
||||||
code,
|
code,
|
||||||
client_id: flow.application.id,
|
client_id: flow.client.id,
|
||||||
application: flow.application.name,
|
application: flow.client.name,
|
||||||
website: flow.application.website ?? "",
|
website: flow.client.website ?? "",
|
||||||
scope: flow.clientScopes?.join(" "),
|
scope: flow.clientScopes?.join(" "),
|
||||||
state: flow.clientState ?? undefined,
|
state: flow.clientState ?? undefined,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import { ApiError } from "@versia-server/kit";
|
import { ApiError } from "@versia-server/kit";
|
||||||
import { apiRoute, handleZodError } from "@versia-server/kit/api";
|
import { apiRoute, handleZodError } from "@versia-server/kit/api";
|
||||||
import { Application, db } from "@versia-server/kit/db";
|
import { Client, db } from "@versia-server/kit/db";
|
||||||
import { OpenIdLoginFlows } from "@versia-server/kit/tables";
|
import { OpenIdLoginFlows } from "@versia-server/kit/tables";
|
||||||
import { randomUUIDv7 } from "bun";
|
import { randomUUIDv7 } from "bun";
|
||||||
import { describeRoute, validator } from "hono-openapi";
|
import { describeRoute, validator } from "hono-openapi";
|
||||||
|
|
@ -54,7 +54,7 @@ export default apiRoute((app) => {
|
||||||
throw new ApiError(422, "Unknown or invalid issuer");
|
throw new ApiError(422, "Unknown or invalid issuer");
|
||||||
}
|
}
|
||||||
|
|
||||||
const application = await Application.fromClientId(client_id);
|
const application = await Client.fromClientId(client_id);
|
||||||
|
|
||||||
if (!application) {
|
if (!application) {
|
||||||
throw new ApiError(422, "Unknown or invalid client_id");
|
throw new ApiError(422, "Unknown or invalid client_id");
|
||||||
|
|
@ -98,7 +98,7 @@ export default apiRoute((app) => {
|
||||||
clientState: state,
|
clientState: state,
|
||||||
clientRedirectUri: redirect_uri,
|
clientRedirectUri: redirect_uri,
|
||||||
clientScopes: scopes,
|
clientScopes: scopes,
|
||||||
applicationId: application.id,
|
clientId: application.id,
|
||||||
issuerId,
|
issuerId,
|
||||||
})
|
})
|
||||||
.returning()
|
.returning()
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { afterAll, describe, expect, test } from "bun:test";
|
import { afterAll, describe, expect, test } from "bun:test";
|
||||||
import { Application, db } from "@versia-server/kit/db";
|
import { Client, db } from "@versia-server/kit/db";
|
||||||
import { fakeRequest, getTestUsers } from "@versia-server/tests";
|
import { fakeRequest, getTestUsers } from "@versia-server/tests";
|
||||||
import { randomUUIDv7 } from "bun";
|
import { randomUUIDv7 } from "bun";
|
||||||
import { eq } from "drizzle-orm";
|
import { eq } from "drizzle-orm";
|
||||||
|
|
@ -8,7 +8,7 @@ import { AuthorizationCodes } from "~/packages/kit/tables/schema";
|
||||||
|
|
||||||
const { deleteUsers, users } = await getTestUsers(1);
|
const { deleteUsers, users } = await getTestUsers(1);
|
||||||
|
|
||||||
const application = await Application.insert({
|
const application = await Client.insert({
|
||||||
id: randomUUIDv7(),
|
id: randomUUIDv7(),
|
||||||
redirectUris: ["https://example.com/callback"],
|
redirectUris: ["https://example.com/callback"],
|
||||||
scopes: ["openid", "profile", "email"],
|
scopes: ["openid", "profile", "email"],
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Token as TokenSchema } from "@versia/client/schemas";
|
import { Token as TokenSchema } from "@versia/client/schemas";
|
||||||
import { apiRoute, handleZodError, jsonOrForm } from "@versia-server/kit/api";
|
import { apiRoute, handleZodError, jsonOrForm } from "@versia-server/kit/api";
|
||||||
import { Application, db, Token } from "@versia-server/kit/db";
|
import { Client, db, Token } from "@versia-server/kit/db";
|
||||||
import { AuthorizationCodes } from "@versia-server/kit/tables";
|
import { AuthorizationCodes } from "@versia-server/kit/tables";
|
||||||
import { randomUUIDv7 } from "bun";
|
import { randomUUIDv7 } from "bun";
|
||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
|
|
@ -77,7 +77,7 @@ export default apiRoute((app) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the client_secret
|
// Verify the client_secret
|
||||||
const client = await Application.fromClientId(client_id);
|
const client = await Client.fromClientId(client_id);
|
||||||
|
|
||||||
if (!client || client.data.secret !== client_secret) {
|
if (!client || client.data.secret !== client_secret) {
|
||||||
return context.json(
|
return context.json(
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import { type ZodAny, ZodError, z } from "zod/v4";
|
||||||
import { fromZodError } from "zod-validation-error";
|
import { fromZodError } from "zod-validation-error";
|
||||||
import type { AuthData, HonoEnv } from "~/types/api";
|
import type { AuthData, HonoEnv } from "~/types/api";
|
||||||
import { ApiError } from "./api-error.ts";
|
import { ApiError } from "./api-error.ts";
|
||||||
import { Application } from "./db/application.ts";
|
import { Client } from "./db/application.ts";
|
||||||
import { Emoji } from "./db/emoji.ts";
|
import { Emoji } from "./db/emoji.ts";
|
||||||
import { Note } from "./db/note.ts";
|
import { Note } from "./db/note.ts";
|
||||||
import { Token } from "./db/token.ts";
|
import { Token } from "./db/token.ts";
|
||||||
|
|
@ -170,7 +170,7 @@ export const auth = <AuthRequired extends boolean>(options: {
|
||||||
const auth: AuthData = {
|
const auth: AuthData = {
|
||||||
token,
|
token,
|
||||||
application: token?.data.client
|
application: token?.data.client
|
||||||
? new Application(token?.data.client)
|
? new Client(token?.data.client)
|
||||||
: null,
|
: null,
|
||||||
user: (await token?.getUser()) ?? null,
|
user: (await token?.getUser()) ?? null,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -16,37 +16,37 @@ import { Clients } from "../tables/schema.ts";
|
||||||
import { BaseInterface } from "./base.ts";
|
import { BaseInterface } from "./base.ts";
|
||||||
import { Token } from "./token.ts";
|
import { Token } from "./token.ts";
|
||||||
|
|
||||||
type ApplicationType = InferSelectModel<typeof Clients>;
|
type ClientType = InferSelectModel<typeof Clients>;
|
||||||
|
|
||||||
export class Application extends BaseInterface<typeof Clients> {
|
export class Client extends BaseInterface<typeof Clients> {
|
||||||
public static $type: ApplicationType;
|
public static $type: ClientType;
|
||||||
|
|
||||||
public async reload(): Promise<void> {
|
public async reload(): Promise<void> {
|
||||||
const reloaded = await Application.fromId(this.data.id);
|
const reloaded = await Client.fromId(this.data.id);
|
||||||
|
|
||||||
if (!reloaded) {
|
if (!reloaded) {
|
||||||
throw new Error("Failed to reload application");
|
throw new Error("Failed to reload client");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.data = reloaded.data;
|
this.data = reloaded.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async fromId(id: string | null): Promise<Application | null> {
|
public static async fromId(id: string | null): Promise<Client | null> {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return await Application.fromSql(eq(Clients.id, id));
|
return await Client.fromSql(eq(Clients.id, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async fromIds(ids: string[]): Promise<Application[]> {
|
public static async fromIds(ids: string[]): Promise<Client[]> {
|
||||||
return await Application.manyFromSql(inArray(Clients.id, ids));
|
return await Client.manyFromSql(inArray(Clients.id, ids));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async fromSql(
|
public static async fromSql(
|
||||||
sql: SQL<unknown> | undefined,
|
sql: SQL<unknown> | undefined,
|
||||||
orderBy: SQL<unknown> | undefined = desc(Clients.id),
|
orderBy: SQL<unknown> | undefined = desc(Clients.id),
|
||||||
): Promise<Application | null> {
|
): Promise<Client | null> {
|
||||||
const found = await db.query.Clients.findFirst({
|
const found = await db.query.Clients.findFirst({
|
||||||
where: sql,
|
where: sql,
|
||||||
orderBy,
|
orderBy,
|
||||||
|
|
@ -55,7 +55,7 @@ export class Application extends BaseInterface<typeof Clients> {
|
||||||
if (!found) {
|
if (!found) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new Application(found);
|
return new Client(found);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async manyFromSql(
|
public static async manyFromSql(
|
||||||
|
|
@ -64,7 +64,7 @@ export class Application extends BaseInterface<typeof Clients> {
|
||||||
limit?: number,
|
limit?: number,
|
||||||
offset?: number,
|
offset?: number,
|
||||||
extra?: Parameters<typeof db.query.Clients.findMany>[0],
|
extra?: Parameters<typeof db.query.Clients.findMany>[0],
|
||||||
): Promise<Application[]> {
|
): Promise<Client[]> {
|
||||||
const found = await db.query.Clients.findMany({
|
const found = await db.query.Clients.findMany({
|
||||||
where: sql,
|
where: sql,
|
||||||
orderBy,
|
orderBy,
|
||||||
|
|
@ -73,30 +73,28 @@ export class Application extends BaseInterface<typeof Clients> {
|
||||||
with: extra?.with,
|
with: extra?.with,
|
||||||
});
|
});
|
||||||
|
|
||||||
return found.map((s) => new Application(s));
|
return found.map((s) => new Client(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async getFromToken(
|
public static async getFromToken(token: string): Promise<Client | null> {
|
||||||
token: string,
|
|
||||||
): Promise<Application | null> {
|
|
||||||
const result = await Token.fromAccessToken(token);
|
const result = await Token.fromAccessToken(token);
|
||||||
|
|
||||||
return result?.data.client ? new Application(result.data.client) : null;
|
return result?.data.client ? new Client(result.data.client) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromClientId(clientId: string): Promise<Application | null> {
|
public static fromClientId(clientId: string): Promise<Client | null> {
|
||||||
return Application.fromSql(eq(Clients.id, clientId));
|
return Client.fromSql(eq(Clients.id, clientId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async update(
|
public async update(
|
||||||
newApplication: Partial<ApplicationType>,
|
newApplication: Partial<ClientType>,
|
||||||
): Promise<ApplicationType> {
|
): Promise<ClientType> {
|
||||||
await db
|
await db
|
||||||
.update(Clients)
|
.update(Clients)
|
||||||
.set(newApplication)
|
.set(newApplication)
|
||||||
.where(eq(Clients.id, this.id));
|
.where(eq(Clients.id, this.id));
|
||||||
|
|
||||||
const updated = await Application.fromId(this.data.id);
|
const updated = await Client.fromId(this.data.id);
|
||||||
|
|
||||||
if (!updated) {
|
if (!updated) {
|
||||||
throw new Error("Failed to update application");
|
throw new Error("Failed to update application");
|
||||||
|
|
@ -106,7 +104,7 @@ export class Application extends BaseInterface<typeof Clients> {
|
||||||
return updated.data;
|
return updated.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public save(): Promise<ApplicationType> {
|
public save(): Promise<ClientType> {
|
||||||
return this.update(this.data);
|
return this.update(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,10 +118,10 @@ export class Application extends BaseInterface<typeof Clients> {
|
||||||
|
|
||||||
public static async insert(
|
public static async insert(
|
||||||
data: InferInsertModel<typeof Clients>,
|
data: InferInsertModel<typeof Clients>,
|
||||||
): Promise<Application> {
|
): Promise<Client> {
|
||||||
const inserted = (await db.insert(Clients).values(data).returning())[0];
|
const inserted = (await db.insert(Clients).values(data).returning())[0];
|
||||||
|
|
||||||
const application = await Application.fromId(inserted.id);
|
const application = await Client.fromId(inserted.id);
|
||||||
|
|
||||||
if (!application) {
|
if (!application) {
|
||||||
throw new Error("Failed to insert application");
|
throw new Error("Failed to insert application");
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
export { db, setupDatabase } from "../tables/db.ts";
|
export { db, setupDatabase } from "../tables/db.ts";
|
||||||
export { Application } from "./application.ts";
|
export { Client } from "./application.ts";
|
||||||
export { Emoji } from "./emoji.ts";
|
export { Emoji } from "./emoji.ts";
|
||||||
export { Instance } from "./instance.ts";
|
export { Instance } from "./instance.ts";
|
||||||
export { Like } from "./like.ts";
|
export { Like } from "./like.ts";
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ import {
|
||||||
Notifications,
|
Notifications,
|
||||||
Users,
|
Users,
|
||||||
} from "../tables/schema.ts";
|
} from "../tables/schema.ts";
|
||||||
import { Application } from "./application.ts";
|
import { Client } from "./application.ts";
|
||||||
import { BaseInterface } from "./base.ts";
|
import { BaseInterface } from "./base.ts";
|
||||||
import { Emoji } from "./emoji.ts";
|
import { Emoji } from "./emoji.ts";
|
||||||
import { Instance } from "./instance.ts";
|
import { Instance } from "./instance.ts";
|
||||||
|
|
@ -129,7 +129,7 @@ const findManyNotes = async (
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
likes: true,
|
likes: true,
|
||||||
application: true,
|
client: true,
|
||||||
mentions: {
|
mentions: {
|
||||||
with: {
|
with: {
|
||||||
user: {
|
user: {
|
||||||
|
|
@ -238,7 +238,7 @@ type NoteTypeWithRelations = NoteType & {
|
||||||
emojis: (typeof Emoji.$type)[];
|
emojis: (typeof Emoji.$type)[];
|
||||||
reply: NoteType | null;
|
reply: NoteType | null;
|
||||||
quote: NoteType | null;
|
quote: NoteType | null;
|
||||||
application: typeof Application.$type | null;
|
client: typeof Client.$type | null;
|
||||||
pinned: boolean;
|
pinned: boolean;
|
||||||
reblogged: boolean;
|
reblogged: boolean;
|
||||||
muted: boolean;
|
muted: boolean;
|
||||||
|
|
@ -514,7 +514,7 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
|
||||||
visibility,
|
visibility,
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
applicationId: null,
|
clientId: null,
|
||||||
uri: uri?.href,
|
uri: uri?.href,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -1162,8 +1162,8 @@ export class Note extends BaseInterface<typeof Notes, NoteTypeWithRelations> {
|
||||||
in_reply_to_account_id: data.reply?.authorId || null,
|
in_reply_to_account_id: data.reply?.authorId || null,
|
||||||
account: this.author.toApi(userFetching?.id === data.authorId),
|
account: this.author.toApi(userFetching?.id === data.authorId),
|
||||||
created_at: new Date(data.createdAt).toISOString(),
|
created_at: new Date(data.createdAt).toISOString(),
|
||||||
application: data.application
|
application: data.client
|
||||||
? new Application(data.application).toApi()
|
? new Client(data.client).toApi()
|
||||||
: undefined,
|
: undefined,
|
||||||
card: null,
|
card: null,
|
||||||
content: replacedContent,
|
content: replacedContent,
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,12 @@ import {
|
||||||
import type { z } from "zod/v4";
|
import type { z } from "zod/v4";
|
||||||
import { db } from "../tables/db.ts";
|
import { db } from "../tables/db.ts";
|
||||||
import { Tokens } from "../tables/schema.ts";
|
import { Tokens } from "../tables/schema.ts";
|
||||||
import type { Application } from "./application.ts";
|
import type { Client } from "./application.ts";
|
||||||
import { BaseInterface } from "./base.ts";
|
import { BaseInterface } from "./base.ts";
|
||||||
import { User } from "./user.ts";
|
import { User } from "./user.ts";
|
||||||
|
|
||||||
type TokenType = InferSelectModel<typeof Tokens> & {
|
type TokenType = InferSelectModel<typeof Tokens> & {
|
||||||
client: typeof Application.$type;
|
client: typeof Client.$type;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class Token extends BaseInterface<typeof Tokens, TokenType> {
|
export class Token extends BaseInterface<typeof Tokens, TokenType> {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
ALTER TABLE "Applications" RENAME TO "Clients";--> statement-breakpoint
|
||||||
|
ALTER TABLE "Notes" RENAME COLUMN "applicationId" TO "clientId";--> statement-breakpoint
|
||||||
|
ALTER TABLE "OpenIdLoginFlows" RENAME COLUMN "applicationId" TO "clientId";--> statement-breakpoint
|
||||||
|
ALTER TABLE "AuthorizationCodes" DROP CONSTRAINT "AuthorizationCodes_clientId_Applications_client_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "Notes" DROP CONSTRAINT "Notes_applicationId_Applications_client_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "OpenIdLoginFlows" DROP CONSTRAINT "OpenIdLoginFlows_applicationId_Applications_client_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "Tokens" DROP CONSTRAINT "Tokens_clientId_Applications_client_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "AuthorizationCodes" ADD CONSTRAINT "AuthorizationCodes_clientId_Clients_client_id_fk" FOREIGN KEY ("clientId") REFERENCES "public"."Clients"("client_id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||||
|
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_clientId_Clients_client_id_fk" FOREIGN KEY ("clientId") REFERENCES "public"."Clients"("client_id") ON DELETE set null ON UPDATE cascade;--> statement-breakpoint
|
||||||
|
ALTER TABLE "OpenIdLoginFlows" ADD CONSTRAINT "OpenIdLoginFlows_clientId_Clients_client_id_fk" FOREIGN KEY ("clientId") REFERENCES "public"."Clients"("client_id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||||
|
ALTER TABLE "Tokens" ADD CONSTRAINT "Tokens_clientId_Clients_client_id_fk" FOREIGN KEY ("clientId") REFERENCES "public"."Clients"("client_id") ON DELETE cascade ON UPDATE cascade;
|
||||||
2439
packages/kit/tables/migrations/meta/0052_snapshot.json
Normal file
2439
packages/kit/tables/migrations/meta/0052_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -365,6 +365,13 @@
|
||||||
"when": 1755729662013,
|
"when": 1755729662013,
|
||||||
"tag": "0051_stiff_morbius",
|
"tag": "0051_stiff_morbius",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 52,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1755732000165,
|
||||||
|
"tag": "0052_complete_hellfire_club",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,7 @@ export const RelationshipsRelations = relations(Relationships, ({ one }) => ({
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const Clients = pgTable("Applications", {
|
export const Clients = pgTable("Clients", {
|
||||||
id: text("client_id").primaryKey(),
|
id: text("client_id").primaryKey(),
|
||||||
secret: text("secret").notNull(),
|
secret: text("secret").notNull(),
|
||||||
redirectUris: text("redirect_uris")
|
redirectUris: text("redirect_uris")
|
||||||
|
|
@ -494,7 +494,7 @@ export const Notes = pgTable("Notes", {
|
||||||
}),
|
}),
|
||||||
sensitive: boolean("sensitive").notNull().default(false),
|
sensitive: boolean("sensitive").notNull().default(false),
|
||||||
spoilerText: text("spoiler_text").default("").notNull(),
|
spoilerText: text("spoiler_text").default("").notNull(),
|
||||||
applicationId: text("applicationId").references(() => Clients.id, {
|
clientId: text("clientId").references(() => Clients.id, {
|
||||||
onDelete: "set null",
|
onDelete: "set null",
|
||||||
onUpdate: "cascade",
|
onUpdate: "cascade",
|
||||||
}),
|
}),
|
||||||
|
|
@ -528,8 +528,8 @@ export const NotesRelations = relations(Notes, ({ many, one }) => ({
|
||||||
references: [Notes.id],
|
references: [Notes.id],
|
||||||
relationName: "NoteToQuotes",
|
relationName: "NoteToQuotes",
|
||||||
}),
|
}),
|
||||||
application: one(Clients, {
|
client: one(Clients, {
|
||||||
fields: [Notes.applicationId],
|
fields: [Notes.clientId],
|
||||||
references: [Clients.id],
|
references: [Clients.id],
|
||||||
}),
|
}),
|
||||||
quotes: many(Notes, {
|
quotes: many(Notes, {
|
||||||
|
|
@ -703,7 +703,7 @@ export const OpenIdLoginFlows = pgTable("OpenIdLoginFlows", {
|
||||||
clientState: text("client_state"),
|
clientState: text("client_state"),
|
||||||
clientRedirectUri: text("client_redirect_uri"),
|
clientRedirectUri: text("client_redirect_uri"),
|
||||||
clientScopes: text("client_scopes").array(),
|
clientScopes: text("client_scopes").array(),
|
||||||
applicationId: text("applicationId").references(() => Clients.id, {
|
clientId: text("clientId").references(() => Clients.id, {
|
||||||
onDelete: "cascade",
|
onDelete: "cascade",
|
||||||
onUpdate: "cascade",
|
onUpdate: "cascade",
|
||||||
}),
|
}),
|
||||||
|
|
@ -713,8 +713,8 @@ export const OpenIdLoginFlows = pgTable("OpenIdLoginFlows", {
|
||||||
export const OpenIdLoginFlowsRelations = relations(
|
export const OpenIdLoginFlowsRelations = relations(
|
||||||
OpenIdLoginFlows,
|
OpenIdLoginFlows,
|
||||||
({ one }) => ({
|
({ one }) => ({
|
||||||
application: one(Clients, {
|
client: one(Clients, {
|
||||||
fields: [OpenIdLoginFlows.applicationId],
|
fields: [OpenIdLoginFlows.clientId],
|
||||||
references: [Clients.id],
|
references: [Clients.id],
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { mock } from "bun:test";
|
||||||
import { Client as VersiaClient } from "@versia/client";
|
import { Client as VersiaClient } from "@versia/client";
|
||||||
import { config } from "@versia-server/config";
|
import { config } from "@versia-server/config";
|
||||||
import {
|
import {
|
||||||
Application,
|
Client,
|
||||||
db,
|
db,
|
||||||
Note,
|
Note,
|
||||||
setupDatabase,
|
setupDatabase,
|
||||||
|
|
@ -50,7 +50,7 @@ export const generateClient = async (
|
||||||
dbToken: Token;
|
dbToken: Token;
|
||||||
}
|
}
|
||||||
> => {
|
> => {
|
||||||
const application = await Application.insert({
|
const application = await Client.insert({
|
||||||
id: randomUUIDv7(),
|
id: randomUUIDv7(),
|
||||||
name: "Versia",
|
name: "Versia",
|
||||||
redirectUris: [],
|
redirectUris: [],
|
||||||
|
|
@ -111,7 +111,7 @@ export const getTestUsers = async (
|
||||||
const users: User[] = [];
|
const users: User[] = [];
|
||||||
const passwords: string[] = [];
|
const passwords: string[] = [];
|
||||||
|
|
||||||
const application = await Application.insert({
|
const application = await Client.insert({
|
||||||
id: randomUUIDv7(),
|
id: randomUUIDv7(),
|
||||||
name: "Versia",
|
name: "Versia",
|
||||||
redirectUris: [],
|
redirectUris: [],
|
||||||
|
|
@ -182,7 +182,7 @@ export const getTestStatuses = async (
|
||||||
sensitive: false,
|
sensitive: false,
|
||||||
updatedAt: new Date().toISOString(),
|
updatedAt: new Date().toISOString(),
|
||||||
visibility: "public",
|
visibility: "public",
|
||||||
applicationId: null,
|
clientId: null,
|
||||||
...partial,
|
...partial,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type * as VersiaEntities from "@versia/sdk/entities";
|
import type * as VersiaEntities from "@versia/sdk/entities";
|
||||||
import type { ConfigSchema } from "@versia-server/config";
|
import type { ConfigSchema } from "@versia-server/config";
|
||||||
import type { Application, Token, User } from "@versia-server/kit/db";
|
import type { Client, Token, User } from "@versia-server/kit/db";
|
||||||
import type { SocketAddress } from "bun";
|
import type { SocketAddress } from "bun";
|
||||||
import type { Hono } from "hono";
|
import type { Hono } from "hono";
|
||||||
import type { RouterRoute } from "hono/types";
|
import type { RouterRoute } from "hono/types";
|
||||||
|
|
@ -11,7 +11,7 @@ export type HttpVerb = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
||||||
export interface AuthData {
|
export interface AuthData {
|
||||||
user: User | null;
|
user: User | null;
|
||||||
token: Token | null;
|
token: Token | null;
|
||||||
application: Application | null;
|
application: Client | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HonoEnv = {
|
export type HonoEnv = {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue