refactor(database): move db into typescript

- Implemented githubTokensDb for managing GitHub tokens with CRUD operations.
- Created
otificationPreferencesDb to handle user notification preferences.
- Added projectsDb for project path management and related operations.
- Introduced pushSubscriptionsDb for managing browser push subscriptions.
- Developed scanStateDb to track the last scanned timestamp.
- Established sessionsDb for session management with CRUD functionalities.
- Created userDb for user management, including authentication and onboarding.
- Implemented apidKeysDb for storing and managing VAPID keys.

feat(database): define schema for new database tables

- Added SQL schema definitions for users, API keys, user credentials, notification preferences, VAPID keys, push subscriptions, projects, sessions, scan state, and app configuration.
- Included necessary indexes for performance optimization.

refactor(shared): enhance type definitions and utility functions

- Updated shared types and interfaces for improved clarity and consistency.
- Added new types for credential management and provider-specific operations.
- Refined utility functions for better error handling and message normalization.
This commit is contained in:
Haileyesus
2026-04-23 16:59:45 +03:00
parent 2e326214e1
commit 7b75ed0b72
18 changed files with 1879 additions and 42 deletions

View File

@@ -9,6 +9,7 @@ import type {
UpsertProviderMcpServerInput,
} from '@/shared/types.js';
//----------------- PROVIDER CONTRACT INTERFACES ------------
/**
* Main provider contract for CLI and SDK integrations.
*
@@ -22,9 +23,13 @@ export interface IProvider {
readonly sessions: IProviderSessions;
}
// ---------------------------
//----------------- PROVIDER AUTH INTERFACE ------------
/**
* Auth contract for one provider.
*
* Implementations should return a complete installation/authentication status
* without throwing for normal "not installed" or "not authenticated" states.
*/
export interface IProviderAuth {
/**
@@ -33,8 +38,13 @@ export interface IProviderAuth {
getStatus(): Promise<ProviderAuthStatus>;
}
// ---------------------------
//----------------- PROVIDER MCP INTERFACE ------------
/**
* MCP contract for one provider.
*
* Implementations must map provider-native MCP config formats to shared
* `ProviderMcpServer` records used by routes and frontend state.
*/
export interface IProviderMcp {
listServers(options?: { workspacePath?: string }): Promise<Record<McpScope, ProviderMcpServer[]>>;
@@ -45,8 +55,13 @@ export interface IProviderMcp {
): Promise<{ removed: boolean; provider: LLMProvider; name: string; scope: McpScope }>;
}
// ---------------------------
//----------------- PROVIDER SESSION INTERFACE ------------
/**
* Session/history contract for one provider.
*
* Implementations normalize provider-specific events and message history into
* shared transport shapes consumed by API routes and realtime streams.
*/
export interface IProviderSessions {
normalizeMessage(raw: unknown, sessionId: string | null): NormalizedMessage[];

View File

@@ -1,18 +1,38 @@
// -------------- HTTP API response shapes for the server, shared across modules --------------
//----------------- HTTP RESPONSE SHAPES ------------
/**
* Canonical success envelope used by backend APIs that return a structured payload.
*
* Use this for route handlers that need a stable `success/data` shape so frontend
* consumers can parse responses consistently across endpoints.
*/
export type ApiSuccessShape<TData = unknown> = {
success: true;
data: TData;
};
/**
* Generic plain-object record used when parsing loosely typed JSON payloads.
*
* Use this only after runtime shape checks, not as a replacement for validated
* domain models.
*/
export type AnyRecord = Record<string, any>;
// ---------------------------------------------------------------------------------------------
// ---------------------------
//----------------- PROVIDER MESSAGE MODEL ------------
/**
* Providers supported by the unified server runtime.
*
* Use this as the source of truth whenever a function or payload needs to identify
* a specific LLM integration.
*/
export type LLMProvider = 'claude' | 'codex' | 'gemini' | 'cursor';
// ---------------------------------------------------------------------------------------------
/**
* Message/event variants emitted by provider adapters and normalized transports.
*
* Keep this union in sync with event kinds produced by provider session adapters.
*/
export type MessageKind =
| 'text'
| 'tool_use'
@@ -30,11 +50,10 @@ export type MessageKind =
| 'task_notification';
/**
* Provider-neutral message event emitted over REST and realtime transports.
* Provider-neutral message envelope used in REST responses and realtime channels.
*
* Providers all produce their own native SDK/CLI event shapes, so this type keeps
* the common envelope strict while allowing provider-specific details to ride
* along as optional properties.
* Every provider-specific message must be converted into this shape before being
* emitted outside provider-specific modules.
*/
export type NormalizedMessage = {
id: string;
@@ -73,21 +92,22 @@ export type NormalizedMessage = {
};
/**
* Pagination and provider lookup options for reading persisted session history.
* Shared options used to fetch historical provider messages.
*
* Consumers should pass provider-specific lookup hints (`projectName`, `projectPath`)
* only when the selected provider requires them.
*/
export type FetchHistoryOptions = {
/** Claude project folder name. Required by Claude history lookup. */
projectName?: string;
/** Absolute workspace path. Required by Cursor to compute its chat hash. */
projectPath?: string;
/** Page size. `null` means all messages. */
limit?: number | null;
/** Pagination offset from the newest messages. */
offset?: number;
};
/**
* Provider-neutral history result returned by the unified messages endpoint.
* Standardized response payload returned from provider history readers.
*
* Use this as the contract for APIs that return paginated conversation history.
*/
export type FetchHistoryResult = {
messages: NormalizedMessage[];
@@ -98,21 +118,40 @@ export type FetchHistoryResult = {
tokenUsage?: unknown;
};
// ---------------------------------------------------------------------------------------------
// ---------------------------
//----------------- SHARED ERROR TYPES ------------
/**
* Optional metadata used when constructing application-level errors.
*
* `statusCode` should reflect the HTTP response status, while `code` identifies
* the stable machine-readable error category.
*/
export type AppErrorOptions = {
code?: string;
statusCode?: number;
details?: unknown;
};
// -------------------- MCP related shared types --------------------
// ---------------------------
//----------------- MCP TYPES ------------
/**
* Scope where an MCP server definition is stored and resolved.
*
* `user` is global for a user account, `local` is provider-local, and `project`
* is tied to a specific project path.
*/
export type McpScope = 'user' | 'local' | 'project';
/**
* Transport protocol used by an MCP server definition.
*/
export type McpTransport = 'stdio' | 'http' | 'sse';
/**
* Provider MCP server descriptor normalized for frontend consumption.
* Normalized MCP server model exposed to frontend and route handlers.
*
* Provider adapters should map provider-native config to this structure before
* returning results.
*/
export type ProviderMcpServer = {
provider: LLMProvider;
@@ -131,7 +170,10 @@ export type ProviderMcpServer = {
};
/**
* Shared payload shape for MCP server create/update operations.
* Payload for create/update MCP server operations.
*
* Routes and services should accept this type, validate it, and then persist it
* through provider-specific MCP repositories.
*/
export type UpsertProviderMcpServerInput = {
name: string;
@@ -149,18 +191,13 @@ export type UpsertProviderMcpServerInput = {
envHttpHeaders?: Record<string, string>;
};
// ---------------------------------------------------------------------------------------------
// -------------------- Provider auth status types --------------------
// ---------------------------
//----------------- PROVIDER AUTH TYPES ------------
/**
* Result of a provider status check (installation + authentication).
* Authentication status result returned by provider health checks.
*
* installed - Whether the provider's CLI/SDK is available
* provider - Provider id the status belongs to
* authenticated - Whether valid credentials exist
* email - User email or auth method identifier
* method - Auth method (e.g. 'api_key', 'credentials_file')
* [error] - Error message if not installed or not authenticated
* This shape is consumed by settings/status endpoints to report installation and
* credential state for each provider.
*/
export type ProviderAuthStatus = {
installed: boolean;
@@ -170,3 +207,32 @@ export type ProviderAuthStatus = {
method: string | null;
error?: string;
};
// ---------------------------
//----------------- SHARED DATABASE CREDENTIAL TYPES ------------
/**
* Safe credential view returned by credential listing APIs.
*
* This intentionally excludes the raw credential secret while still exposing
* metadata needed for UI rendering and management operations.
*/
export type CredentialPublicRow = {
id: number;
credential_name: string;
credential_type: string;
description: string | null;
created_at: string;
is_active: number;
};
/**
* Result returned after creating a credential record.
*
* Use this return shape when callers need the created id and display metadata,
* but must never receive the stored secret value.
*/
export type CreateCredentialResult = {
id: number | bigint;
credentialName: string;
credentialType: string;
};

View File

@@ -1,4 +1,3 @@
import { randomUUID } from 'node:crypto';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import path from 'node:path';
@@ -12,6 +11,14 @@ import type {
NormalizedMessage,
} from '@/shared/types.js';
//----------------- NORMALIZED MESSAGE HELPER INPUT TYPES ------------
/**
* Input payload accepted by `createNormalizedMessage`.
*
* Callers provide provider-specific fields plus the required `kind/provider`
* pair; this helper fills missing envelope fields (`id`, `sessionId`,
* `timestamp`) in a consistent way.
*/
type NormalizedMessageInput =
{
kind: NormalizedMessage['kind'];
@@ -21,6 +28,14 @@ type NormalizedMessageInput =
timestamp?: string | null;
} & Record<string, unknown>;
// ---------------------------
//----------------- HTTP HANDLER UTILITIES ------------
/**
* Wraps arbitrary data in the standard API success envelope.
*
* Use this helper in route handlers to keep successful JSON responses consistent
* across endpoints.
*/
export function createApiSuccessResponse<TData>(
data: TData,
): ApiSuccessShape<TData> {
@@ -30,6 +45,12 @@ export function createApiSuccessResponse<TData>(
};
}
/**
* Converts an async Express handler into a standard `RequestHandler` and routes
* rejected promises to Express error middleware.
*
* Use this to avoid repeating `try/catch(next)` in every async route.
*/
export function asyncHandler(
handler: (req: Request, res: Response, next: NextFunction) => Promise<unknown>
): RequestHandler {
@@ -38,7 +59,14 @@ export function asyncHandler(
};
}
// --------- Global app error class for consistent error handling across the server ---------
// ---------------------------
//----------------- SHARED ERROR UTILITIES ------------
/**
* Shared application error with HTTP status and machine-readable code metadata.
*
* Throw this from service/route layers when the caller should receive a
* controlled error response rather than a generic 500.
*/
export class AppError extends Error {
readonly code: string;
readonly statusCode: number;
@@ -53,9 +81,8 @@ export class AppError extends Error {
}
}
// -------------------------------------------------------------------------------------------
// ------------------------ Normalized provider message helpers ------------------------
// ---------------------------
//----------------- NORMALIZED PROVIDER MESSAGE UTILITIES ------------
/**
* Generates a stable unique id for normalized provider messages.
*/
@@ -80,9 +107,8 @@ export function createNormalizedMessage(fields: NormalizedMessageInput): Normali
};
}
// -------------------------------------------------------------------------------------------
// ------------------------ The following are mainly for provider MCP runtimes ------------------------
// ---------------------------
//----------------- MCP CONFIG PARSING UTILITIES ------------
/**
* Safely narrows an unknown value to a plain object record.
*
@@ -189,5 +215,3 @@ export const writeJsonConfig = async (filePath: string, data: Record<string, unk
await writeFile(filePath, `${JSON.stringify(data, null, 2)}\n`, 'utf8');
};
// -------------------------------------------------------------------------------------------