feat: improve API keys and build workflows

This commit is contained in:
2026-10-04 20:05:13 +00:00 Unverified
parent 62f2362a2e
commit e4623efe86
27 changed files with 2080 additions and 235 deletions
+16 -9
View File
@@ -36,7 +36,7 @@ export type ApiKeyRecord = {
username: string;
capabilities: Capability[];
workspace?: string;
expiresAt: string;
expiresAt?: string;
disabled?: boolean;
};
@@ -129,12 +129,14 @@ export function normalizeApiKey(key: NewApiKey): ApiKeyRecord {
) {
throw new Error("API key workspace scope is invalid");
}
const expiresAt = new Date(key.expiresAt);
if (
!Number.isFinite(expiresAt.getTime()) ||
expiresAt.toISOString() !== key.expiresAt
) {
throw new Error("API key expiration must be an ISO timestamp");
if (key.expiresAt !== undefined) {
const expiresAt = new Date(key.expiresAt);
if (
!Number.isFinite(expiresAt.getTime()) ||
expiresAt.toISOString() !== key.expiresAt
) {
throw new Error("API key expiration must be an ISO timestamp");
}
}
return {
...key,
@@ -279,7 +281,12 @@ export class MemoryAuthStore implements AuthStore {
async getApiKey(tokenHash: string): Promise<ApiKeyRecord | undefined> {
const key = this.apiKeysByTokenHash.get(tokenHash);
if (!key || key.disabled || Date.parse(key.expiresAt) <= Date.now()) return;
if (
!key ||
key.disabled ||
(key.expiresAt !== undefined && Date.parse(key.expiresAt) <= Date.now())
)
return;
const user = this.users.get(key.username);
if (!user || user.disabled) return;
return key;
@@ -309,7 +316,7 @@ export class MemoryAuthStore implements AuthStore {
async deleteExpiredApiKeys(now = Date.now()): Promise<number> {
const expired = [...this.apiKeys.values()].filter(
(key) => Date.parse(key.expiresAt) <= now,
(key) => key.expiresAt !== undefined && Date.parse(key.expiresAt) <= now,
);
for (const key of expired) this.deleteApiKey(key.id);
return expired.length;