Files
onebox/ts/database/repositories/registry.repository.ts

124 lines
4.0 KiB
TypeScript
Raw Normal View History

/**
* Registry Repository
* Handles CRUD operations for registries and registry_tokens tables
*/
import { BaseRepository } from '../base.repository.ts';
import type { IRegistry, IRegistryToken } from '../../types.ts';
export class RegistryRepository extends BaseRepository {
// ============ Registries ============
async createRegistry(registry: Omit<IRegistry, 'id'>): Promise<IRegistry> {
const now = Date.now();
this.query(
'INSERT INTO registries (url, username, password_encrypted, created_at) VALUES (?, ?, ?, ?)',
[registry.url, registry.username, registry.passwordEncrypted, now]
);
return this.getRegistryByURL(registry.url)!;
}
getRegistryByURL(url: string): IRegistry | null {
const rows = this.query('SELECT * FROM registries WHERE url = ?', [url]);
return rows.length > 0 ? this.rowToRegistry(rows[0]) : null;
}
getAllRegistries(): IRegistry[] {
const rows = this.query('SELECT * FROM registries ORDER BY created_at DESC');
return rows.map((row) => this.rowToRegistry(row));
}
deleteRegistry(url: string): void {
this.query('DELETE FROM registries WHERE url = ?', [url]);
}
private rowToRegistry(row: any): IRegistry {
return {
id: Number(row.id || row[0]),
url: String(row.url || row[1]),
username: String(row.username || row[2]),
passwordEncrypted: String(row.password_encrypted || row[3]),
createdAt: Number(row.created_at || row[4]),
};
}
// ============ Registry Tokens ============
createToken(token: Omit<IRegistryToken, 'id'>): IRegistryToken {
const scopeJson = Array.isArray(token.scope) ? JSON.stringify(token.scope) : token.scope;
this.query(
`INSERT INTO registry_tokens (name, token_hash, token_type, scope, expires_at, created_at, last_used_at, created_by)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
[
token.name,
token.tokenHash,
token.type,
scopeJson,
token.expiresAt,
token.createdAt,
token.lastUsedAt,
token.createdBy,
]
);
const rows = this.query('SELECT * FROM registry_tokens WHERE id = last_insert_rowid()');
return this.rowToToken(rows[0]);
}
getTokenById(id: number): IRegistryToken | null {
const rows = this.query('SELECT * FROM registry_tokens WHERE id = ?', [id]);
return rows.length > 0 ? this.rowToToken(rows[0]) : null;
}
getTokenByHash(tokenHash: string): IRegistryToken | null {
const rows = this.query('SELECT * FROM registry_tokens WHERE token_hash = ?', [tokenHash]);
return rows.length > 0 ? this.rowToToken(rows[0]) : null;
}
getAllTokens(): IRegistryToken[] {
const rows = this.query('SELECT * FROM registry_tokens ORDER BY created_at DESC');
return rows.map((row) => this.rowToToken(row));
}
getTokensByType(type: 'global' | 'ci'): IRegistryToken[] {
const rows = this.query('SELECT * FROM registry_tokens WHERE token_type = ? ORDER BY created_at DESC', [type]);
return rows.map((row) => this.rowToToken(row));
}
updateTokenLastUsed(id: number): void {
this.query('UPDATE registry_tokens SET last_used_at = ? WHERE id = ?', [Date.now(), id]);
}
deleteToken(id: number): void {
this.query('DELETE FROM registry_tokens WHERE id = ?', [id]);
}
private rowToToken(row: any): IRegistryToken {
let scope: 'all' | string[];
const scopeRaw = row.scope || row[4];
if (scopeRaw === 'all') {
scope = 'all';
} else {
try {
scope = JSON.parse(String(scopeRaw));
} catch {
scope = 'all';
}
}
return {
id: Number(row.id || row[0]),
name: String(row.name || row[1]),
tokenHash: String(row.token_hash || row[2]),
type: String(row.token_type || row[3]) as IRegistryToken['type'],
scope,
expiresAt: row.expires_at || row[5] ? Number(row.expires_at || row[5]) : null,
createdAt: Number(row.created_at || row[6]),
lastUsedAt: row.last_used_at || row[7] ? Number(row.last_used_at || row[7]) : null,
createdBy: String(row.created_by || row[8]),
};
}
}