Files
zerobyte/app/server/modules/api-keys/api-keys.service.ts
Nico 283de054ec feat(authentication): api key (#966)
* feat(authentication): api key

Keeps selected UX pieces from b487b096.

Co-authored-by: Nguyen Quy Hy <nguyenquyhy@live.com.sg>

* refactor: pr feedbacks

* chore: bump @better-auth/api-key

* refactor: global limit of 50 api key instead of 10 per org

---------

Co-authored-by: Nguyen Quy Hy <nguyenquyhy@live.com.sg>
2026-06-12 20:14:21 +02:00

63 lines
1.8 KiB
TypeScript

import { db } from "~/server/db/db";
import { parseApiKeyOrganizationId } from "./api-key-metadata";
export const MAX_API_KEYS_PER_USER = 50;
export const listApiKeys = async (userId: string, organizationId: string) => {
const rows = await db.query.apikey.findMany({
where: {
AND: [
{ referenceId: userId },
{ OR: [{ enabled: true }, { enabled: { isNull: true } }] },
{ OR: [{ expiresAt: { isNull: true } }, { expiresAt: { gt: new Date() } }] },
],
},
orderBy: (table, { desc }) => [desc(table.createdAt)],
});
return rows
.filter((row) => parseApiKeyOrganizationId(row.metadata) === organizationId)
.map((row) => ({
id: row.id,
name: row.name,
createdAt: row.createdAt.toISOString(),
expiresAt: row.expiresAt?.toISOString() ?? null,
lastRequestAt: row.lastRequest?.toISOString() ?? null,
}));
};
export const countActiveApiKeys = async (userId: string) => {
const rows = await db.query.apikey.findMany({
where: {
AND: [
{ referenceId: userId },
{ OR: [{ enabled: true }, { enabled: { isNull: true } }] },
{ OR: [{ expiresAt: { isNull: true } }, { expiresAt: { gt: new Date() } }] },
],
},
columns: { id: true },
});
return rows.length;
};
export const hasApiKey = async (userId: string, organizationId: string, apiKeyId: string) => {
const row = await db.query.apikey.findFirst({
where: {
AND: [{ id: apiKeyId }, { referenceId: userId }],
},
columns: { metadata: true },
});
return parseApiKeyOrganizationId(row?.metadata ?? null) === organizationId;
};
export const getApiKeyOrganizationId = async (apiKeyId: string) => {
const apiKeyRecord = await db.query.apikey.findFirst({
where: { id: apiKeyId },
columns: { metadata: true },
});
return parseApiKeyOrganizationId(apiKeyRecord?.metadata);
};