Files
Termix/src/backend/database/repositories/opkssh-token-repository.ts
T

127 lines
3.1 KiB
TypeScript
Raw Normal View History

+8
2026-07-19 12:29:52 -05:00
import { and, eq } from "drizzle-orm";
import { opksshTokens } from "../db/schema.js";
import type { DatabaseContext } from "./database-context.js";
+3
2026-08-06 14:41:39 -05:00
import { rowsAffected } from "./mutation-result.js";
import { upsert } from "./returning.js";
+8
2026-07-19 12:29:52 -05:00
export type OpksshTokenRecord = typeof opksshTokens.$inferSelect;
export interface OpksshTokenUpsertInput {
userId: string;
hostId: number;
sshCert: string;
privateKey: string;
email?: string | null;
sub?: string | null;
issuer?: string | null;
audience?: string | null;
expiresAt: string;
createdAt?: string;
}
export class OpksshTokenRepository {
constructor(
private readonly context: DatabaseContext,
private readonly onWrite?: () => void | Promise<void>,
) {}
async upsert(input: OpksshTokenUpsertInput): Promise<void> {
const createdAt = input.createdAt ?? new Date().toISOString();
+3
2026-08-06 14:41:39 -05:00
await upsert(
this.context,
opksshTokens,
{
+8
2026-07-19 12:29:52 -05:00
userId: input.userId,
hostId: input.hostId,
sshCert: input.sshCert,
privateKey: input.privateKey,
email: input.email,
sub: input.sub,
issuer: input.issuer,
audience: input.audience,
expiresAt: input.expiresAt,
+3
2026-08-06 14:41:39 -05:00
},
{
+8
2026-07-19 12:29:52 -05:00
target: [opksshTokens.userId, opksshTokens.hostId],
set: {
sshCert: input.sshCert,
privateKey: input.privateKey,
email: input.email,
sub: input.sub,
issuer: input.issuer,
audience: input.audience,
expiresAt: input.expiresAt,
createdAt,
},
+3
2026-08-06 14:41:39 -05:00
},
);
+8
2026-07-19 12:29:52 -05:00
await this.afterWrite();
}
async findByUserAndHost(
userId: string,
hostId: number,
): Promise<OpksshTokenRecord | null> {
const rows = await this.context.drizzle
.select()
.from(opksshTokens)
.where(
and(eq(opksshTokens.userId, userId), eq(opksshTokens.hostId, hostId)),
)
.limit(1);
return rows[0] ?? null;
}
async updateLastUsed(
userId: string,
hostId: number,
lastUsed = new Date().toISOString(),
): Promise<boolean> {
+3
2026-08-06 14:41:39 -05:00
const result = await this.context.drizzle
+8
2026-07-19 12:29:52 -05:00
.update(opksshTokens)
.set({ lastUsed })
.where(
and(eq(opksshTokens.userId, userId), eq(opksshTokens.hostId, hostId)),
+3
2026-08-06 14:41:39 -05:00
);
+8
2026-07-19 12:29:52 -05:00
+3
2026-08-06 14:41:39 -05:00
if (rowsAffected(result) > 0) {
+8
2026-07-19 12:29:52 -05:00
await this.afterWrite();
}
+3
2026-08-06 14:41:39 -05:00
return rowsAffected(result) > 0;
+8
2026-07-19 12:29:52 -05:00
}
async deleteByUserAndHost(userId: string, hostId: number): Promise<boolean> {
+3
2026-08-06 14:41:39 -05:00
const result = await this.context.drizzle
+8
2026-07-19 12:29:52 -05:00
.delete(opksshTokens)
.where(
and(eq(opksshTokens.userId, userId), eq(opksshTokens.hostId, hostId)),
+3
2026-08-06 14:41:39 -05:00
);
+8
2026-07-19 12:29:52 -05:00
+3
2026-08-06 14:41:39 -05:00
if (rowsAffected(result) > 0) {
+8
2026-07-19 12:29:52 -05:00
await this.afterWrite();
}
+3
2026-08-06 14:41:39 -05:00
return rowsAffected(result) > 0;
+8
2026-07-19 12:29:52 -05:00
}
async deleteByUserId(userId: string): Promise<number> {
+3
2026-08-06 14:41:39 -05:00
const result = await this.context.drizzle
+8
2026-07-19 12:29:52 -05:00
.delete(opksshTokens)
+3
2026-08-06 14:41:39 -05:00
.where(eq(opksshTokens.userId, userId));
+8
2026-07-19 12:29:52 -05:00
+3
2026-08-06 14:41:39 -05:00
if (rowsAffected(result) > 0) {
+8
2026-07-19 12:29:52 -05:00
await this.afterWrite();
}
+3
2026-08-06 14:41:39 -05:00
return rowsAffected(result);
+8
2026-07-19 12:29:52 -05:00
}
private async afterWrite(): Promise<void> {
await this.onWrite?.();
}
}