整理代码结构

This commit is contained in:
Baobhan Sith
2025-06-01 15:31:06 +08:00
parent 3d16613194
commit 33422a215c
39 changed files with 37 additions and 37 deletions
@@ -0,0 +1,154 @@
import { getDbInstance, runDb, getDb, allDb } from '../database/connection';
export interface Passkey {
id: number;
user_id: number;
credential_id: string;
public_key: string;
counter: number;
transports: string | null; // JSON string
name: string | null;
backed_up: boolean; // SQLite stores booleans as 0 or 1
last_used_at: number | null;
created_at: number;
updated_at: number;
}
export interface NewPasskey {
user_id: number;
credential_id: string;
public_key: string;
counter: number;
transports?: string | null; // JSON string
name?: string | null;
backed_up?: boolean;
}
// Helper to convert DB result (0/1) to boolean for backed_up field
function mapPasskeyResult(dbResult: any): Passkey | null {
if (!dbResult) return null;
return {
...dbResult,
backed_up: !!dbResult.backed_up, // Ensure boolean
transports: dbResult.transports, // Already string or null
created_at: typeof dbResult.created_at === 'string' ? parseInt(dbResult.created_at, 10) : dbResult.created_at,
last_used_at: dbResult.last_used_at && typeof dbResult.last_used_at === 'string' ? parseInt(dbResult.last_used_at, 10) : dbResult.last_used_at,
updated_at: typeof dbResult.updated_at === 'string' ? parseInt(dbResult.updated_at, 10) : dbResult.updated_at,
};
}
function mapPasskeyResults(dbResults: any[]): Passkey[] {
return dbResults.map(row => ({
...row,
backed_up: !!row.backed_up,
transports: row.transports,
created_at: typeof row.created_at === 'string' ? parseInt(row.created_at, 10) : row.created_at,
last_used_at: row.last_used_at && typeof row.last_used_at === 'string' ? parseInt(row.last_used_at, 10) : row.last_used_at,
updated_at: typeof row.updated_at === 'string' ? parseInt(row.updated_at, 10) : row.updated_at,
}));
}
export class PasskeyRepository {
async createPasskey(passkeyData: NewPasskey): Promise<Passkey> {
const db = await getDbInstance();
const sql = `
INSERT INTO passkeys (user_id, credential_id, public_key, counter, transports, name, backed_up, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, strftime('%s', 'now'), strftime('%s', 'now'))
RETURNING *
`;
// Note: RETURNING * might not work as expected with the 'sqlite3' package's run method.
// We'll do a SELECT after INSERT if needed, or rely on lastID and then select.
// For simplicity with 'sqlite3', we'll insert then select.
const insertSql = `
INSERT INTO passkeys (user_id, credential_id, public_key, counter, transports, name, backed_up, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, strftime('%s', 'now'), strftime('%s', 'now'))
`;
const params = [
passkeyData.user_id,
passkeyData.credential_id,
passkeyData.public_key,
passkeyData.counter,
passkeyData.transports ?? null,
passkeyData.name ?? null,
passkeyData.backed_up ? 1 : 0, // Store boolean as 0 or 1
];
const { lastID } = await runDb(db, insertSql, params);
// Fetch the inserted row
const newPasskey = await this.getPasskeyById(lastID);
if (!newPasskey) {
throw new Error('Failed to create or retrieve passkey after insert.');
}
return newPasskey;
}
async getPasskeyById(id: number): Promise<Passkey | null> {
const db = await getDbInstance();
const sql = 'SELECT * FROM passkeys WHERE id = ?';
const result = await getDb<any>(db, sql, [id]);
return mapPasskeyResult(result);
}
async getPasskeyByCredentialId(credentialId: string): Promise<Passkey | null> {
const db = await getDbInstance();
const sql = 'SELECT * FROM passkeys WHERE credential_id = ?';
const result = await getDb<any>(db, sql, [credentialId]);
return mapPasskeyResult(result);
}
async getPasskeysByUserId(userId: number): Promise<Passkey[]> {
const db = await getDbInstance();
const sql = 'SELECT * FROM passkeys WHERE user_id = ? ORDER BY created_at DESC';
const results = await allDb<any>(db, sql, [userId]);
// Log the raw results from the database before mapping
// console.log(`[PasskeyRepository] Raw passkeys for user ${userId}:`, JSON.stringify(results, null, 2));
return mapPasskeyResults(results);
}
async updatePasskeyCounter(credentialId: string, newCounter: number): Promise<boolean> {
const db = await getDbInstance();
const sql = "UPDATE passkeys SET counter = ?, updated_at = strftime('%s', 'now') WHERE credential_id = ?";
const { changes } = await runDb(db, sql, [newCounter, credentialId]);
return changes > 0;
}
async updatePasskeyLastUsedAt(credentialId: string): Promise<boolean> {
const db = await getDbInstance();
const sql = "UPDATE passkeys SET last_used_at = strftime('%s', 'now'), updated_at = strftime('%s', 'now') WHERE credential_id = ?";
const { changes } = await runDb(db, sql, [credentialId]);
return changes > 0;
}
async deletePasskey(credentialId: string): Promise<boolean> {
const db = await getDbInstance();
const sql = 'DELETE FROM passkeys WHERE credential_id = ?';
const { changes } = await runDb(db, sql, [credentialId]);
return changes > 0;
}
async deletePasskeysByUserId(userId: number): Promise<boolean> {
const db = await getDbInstance();
const sql = 'DELETE FROM passkeys WHERE user_id = ?';
const { changes } = await runDb(db, sql, [userId]);
return changes > 0;
}
async updatePasskeyName(credentialId: string, name: string): Promise<boolean> {
const db = await getDbInstance();
const sql = "UPDATE passkeys SET name = ?, updated_at = strftime('%s', 'now') WHERE credential_id = ?";
const { changes } = await runDb(db, sql, [name, credentialId]);
return changes > 0;
}
async getFirstPasskey(): Promise<Passkey | null> {
const db = await getDbInstance();
const sql = 'SELECT * FROM passkeys LIMIT 1';
const result = await getDb<any>(db, sql);
return mapPasskeyResult(result);
}
}
export const passkeyRepository = new PasskeyRepository();