diff --git a/frontends/nextjs/next.config.ts b/frontends/nextjs/next.config.ts index 3a4fa55d7..6dffda30e 100644 --- a/frontends/nextjs/next.config.ts +++ b/frontends/nextjs/next.config.ts @@ -85,7 +85,7 @@ const nextConfig: NextConfig = { webpack(config) { config.resolve.alias = { ...config.resolve.alias, - '@/dbal': path.resolve(__dirname, '..', 'dbal', 'ts', 'src'), + '@/dbal': path.resolve(__dirname, '../../dbal/development/src'), } return config }, diff --git a/frontends/nextjs/src/lib/database-lib/dbal-stub.ts b/frontends/nextjs/src/lib/database-lib/dbal-stub.ts deleted file mode 100644 index ceda09793..000000000 --- a/frontends/nextjs/src/lib/database-lib/dbal-stub.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../dbal/dbal-stub/index' diff --git a/frontends/nextjs/src/lib/dbal/core/client/dbal-client.ts b/frontends/nextjs/src/lib/dbal/core/client/dbal-client.ts index c51824ade..a4504b2f1 100644 --- a/frontends/nextjs/src/lib/dbal/core/client/dbal-client.ts +++ b/frontends/nextjs/src/lib/dbal/core/client/dbal-client.ts @@ -2,5 +2,5 @@ export { createDBALClient } from './dbal-client/create-dbal-client' export { getDBALClient } from './dbal-client/get-dbal-client' export { migrateToDBAL } from './dbal-client/migrate-to-dbal' -export { DBALClient } from '@/lib/dbal-stub' -export type { DBALUser } from '@/lib/dbal-stub' +export { DBALClient } from '@/dbal' +export type { DBALUser } from '@/dbal/core/entities/operations/core/user-operations' diff --git a/frontends/nextjs/src/lib/dbal/core/client/dbal-integration.ts b/frontends/nextjs/src/lib/dbal/core/client/dbal-integration.ts index f33ca0632..22cd89e51 100644 --- a/frontends/nextjs/src/lib/dbal/core/client/dbal-integration.ts +++ b/frontends/nextjs/src/lib/dbal/core/client/dbal-integration.ts @@ -1,12 +1,12 @@ /** - * DBAL Integration Layer (Stub Version) + * DBAL Integration Layer * - * This module provides a simplified DBAL integration when the full DBAL - * module is not available. It provides in-memory implementations of - * tenant management, KV store, and blob storage. + * This module provides DBAL integration using the real DBAL client + * from dbal/development for development mode and WebSocket connection + * for production mode. */ -import { DBALClient, type DBALConfig } from '@/lib/dbal-stub' +import { DBALClient, type DBALConfig } from '@/dbal' /* eslint-disable @typescript-eslint/no-explicit-any */ diff --git a/frontends/nextjs/src/lib/dbal/core/client/index.ts b/frontends/nextjs/src/lib/dbal/core/client/index.ts index 64dabd752..d7a6219d4 100644 --- a/frontends/nextjs/src/lib/dbal/core/client/index.ts +++ b/frontends/nextjs/src/lib/dbal/core/client/index.ts @@ -1,5 +1,5 @@ // DBAL (Database Abstraction Layer) exports export { DBALClient, createDBALClient } from './dbal-client' export { DBALIntegration, dbal } from './dbal-integration' -export { default as DBALStub } from './dbal-stub' -export type { DBALConfig, DBALUser, ListResult } from './dbal-stub' +export { DBALClient as DBALRealClient } from '@/dbal' +export type { DBALConfig } from '@/dbal/runtime/config' diff --git a/frontends/nextjs/src/lib/dbal/core/stub/dbal-stub.test.ts b/frontends/nextjs/src/lib/dbal/core/stub/dbal-stub.test.ts deleted file mode 100644 index f55b1deb4..000000000 --- a/frontends/nextjs/src/lib/dbal/core/stub/dbal-stub.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { beforeEach, describe, expect, it } from 'vitest' -import { DBALClient, resetDBALStubState } from '@/lib/dbal-stub' - -describe('dbal-stub users', () => { - beforeEach(() => { - resetDBALStubState() - }) - - it('lists seeded users', async () => { - const client = new DBALClient({ adapter: 'stub' }) - const result = await client.users.list() - - expect(result.data.length).toBeGreaterThanOrEqual(2) - const emails = result.data.map((user) => user.email) - expect(emails).toContain('admin@example.com') - expect(emails).toContain('user@example.com') - }) - - it('creates, updates, and deletes a user', async () => { - const client = new DBALClient({ adapter: 'stub' }) - - const created = await client.users.create({ - username: 'newuser', - email: 'newuser@example.com', - role: 'admin', - bio: 'hello', - }) - - expect(created.id).toBeDefined() - expect(created.bio).toBe('hello') - - const fetched = await client.users.get(created.id) - expect(fetched?.email).toBe('newuser@example.com') - - const updated = await client.users.update(created.id, { - email: 'updated@example.com', - profilePicture: 'https://example.com/avatar.png', - }) - expect(updated.email).toBe('updated@example.com') - expect(updated.profilePicture).toBe('https://example.com/avatar.png') - - const deleted = await client.users.delete(created.id) - expect(deleted).toBe(true) - - const afterDelete = await client.users.get(created.id) - expect(afterDelete).toBeNull() - }) -}) diff --git a/frontends/nextjs/src/lib/dbal/core/stub/dbal-stub.ts b/frontends/nextjs/src/lib/dbal/core/stub/dbal-stub.ts deleted file mode 100644 index 438b31468..000000000 --- a/frontends/nextjs/src/lib/dbal/core/stub/dbal-stub.ts +++ /dev/null @@ -1,160 +0,0 @@ -/** - * DBAL Stub Implementation - * - * Provides a mock implementation of DBAL when the full DBAL module is not available. - * This allows the frontend to build and function in development without the full DBAL. - * - * In production, replace this with the actual DBAL module connection. - */ - - - - -// Error codes for DBAL operations -export enum DBALErrorCode { - UNKNOWN = 'UNKNOWN', - NOT_FOUND = 'NOT_FOUND', - VALIDATION = 'VALIDATION', - PERMISSION = 'PERMISSION', - CONNECTION = 'CONNECTION', - TIMEOUT = 'TIMEOUT', - DUPLICATE = 'DUPLICATE', -} - -// Custom error class for DBAL operations -export class DBALError extends Error { - code: DBALErrorCode - - constructor(message: string, code: DBALErrorCode = DBALErrorCode.UNKNOWN) { - super(message) - this.name = 'DBALError' - this.code = code - } -} - -export interface DBALConfig { - mode?: 'development' | 'production' - adapter?: string - database?: { - url?: string - } - security?: { - sandbox?: 'strict' | 'permissive' - enableAuditLog?: boolean - } -} - -export interface DBALUser { - id: string - email: string - username?: string - name?: string - role?: string - level?: number - tenantId?: string - profilePicture?: string - bio?: string - isInstanceOwner?: boolean - createdAt?: number | Date - updatedAt?: number | Date -} - -export interface ListResult { - data: T[] - total?: number -} - -// In-memory store for development -const defaultUsers: DBALUser[] = [ - { id: '1', email: 'admin@example.com', username: 'admin', role: 'admin', level: 4 }, - { id: '2', email: 'user@example.com', username: 'user', role: 'user', level: 1 }, -] - -const userStore = new Map( - defaultUsers.map((user) => [user.id, { ...user }]) -) - -let nextId = defaultUsers.length + 1 - -export function resetDBALStubState(): void { - userStore.clear() - defaultUsers.forEach((user) => userStore.set(user.id, { ...user })) - nextId = defaultUsers.length + 1 -} - -export class DBALClient { - private config: DBALConfig - - constructor(config: DBALConfig) { - this.config = config - } - - users = { - async list(): Promise> { - return { - data: Array.from(userStore.values()), - total: userStore.size, - } - }, - - async create(data: Partial): Promise { - const id = String(nextId++) - const user: DBALUser = { - id, - email: data.email || '', - username: data.username, - name: data.name, - role: data.role || 'user', - level: data.level || 1, - tenantId: data.tenantId, - profilePicture: data.profilePicture, - bio: data.bio, - isInstanceOwner: data.isInstanceOwner, - createdAt: Date.now(), - updatedAt: Date.now(), - } - userStore.set(id, user) - return user - }, - - async update(id: string, data: Partial): Promise { - const existing = userStore.get(id) - if (!existing) { - throw new Error(`User not found: ${id}`) - } - const updated: DBALUser = { - ...existing, - ...data, - id, - updatedAt: Date.now(), - } - userStore.set(id, updated) - return updated - }, - - async delete(id: string): Promise { - return userStore.delete(id) - }, - - async get(id: string): Promise { - return userStore.get(id) || null - }, - } - - async connect(): Promise { - console.log('[DBAL Stub] Connected (mock mode)') - } - - async disconnect(): Promise { - console.log('[DBAL Stub] Disconnected (mock mode)') - } - - async capabilities(): Promise<{ adapter: string; features: string[] }> { - return { - adapter: this.config.adapter || 'stub', - features: ['users', 'crud', 'mock'], - } - } -} - -export default DBALClient diff --git a/frontends/nextjs/src/lib/dbal/database-dbal/core/dbal-state.server.ts b/frontends/nextjs/src/lib/dbal/database-dbal/core/dbal-state.server.ts index f01ec40f7..9b9e704b7 100644 --- a/frontends/nextjs/src/lib/dbal/database-dbal/core/dbal-state.server.ts +++ b/frontends/nextjs/src/lib/dbal/database-dbal/core/dbal-state.server.ts @@ -1,8 +1,7 @@ -import type { DBALClient as StubDBALClient } from '@/lib/dbal-stub' -import type { DBALClient as RealDBALClient } from '@/dbal/development/src' +import type { DBALClient } from '@/dbal' export const dbalState: { - client: StubDBALClient | RealDBALClient | null + client: DBALClient | null initialized: boolean } = { client: null, diff --git a/frontends/nextjs/src/lib/dbal/database-dbal/core/get-dbal.server.ts b/frontends/nextjs/src/lib/dbal/database-dbal/core/get-dbal.server.ts index f68af0c82..ac30f4f57 100644 --- a/frontends/nextjs/src/lib/dbal/database-dbal/core/get-dbal.server.ts +++ b/frontends/nextjs/src/lib/dbal/database-dbal/core/get-dbal.server.ts @@ -1,6 +1,6 @@ import 'server-only' -import type { DBALClient } from '@/lib/dbal-stub' +import type { DBALClient } from '@/dbal' import { dbalState } from './dbal-state.server' import { initializeDBAL } from './initialize-dbal.server' diff --git a/frontends/nextjs/src/lib/dbal/database-dbal/core/initialize-dbal.server.ts b/frontends/nextjs/src/lib/dbal/database-dbal/core/initialize-dbal.server.ts index 2b29a625c..614417c62 100644 --- a/frontends/nextjs/src/lib/dbal/database-dbal/core/initialize-dbal.server.ts +++ b/frontends/nextjs/src/lib/dbal/database-dbal/core/initialize-dbal.server.ts @@ -1,13 +1,12 @@ import 'server-only' -import { DBALClient as StubDBALClient } from '@/lib/dbal/dbal-stub' -import type { DBALConfig as StubDBALConfig } from '@/lib/dbal/dbal-stub' -import { DBALClient as RealDBALClient } from '@/dbal' -import type { DBALConfig as RealDBALConfig } from '@/dbal/runtime/config' +import { DBALClient } from '@/dbal' +import type { DBALConfig } from '@/dbal/runtime/config' import { dbalState } from './dbal-state.server' /** * Initialize DBAL client for database operations + * Supports both development (TypeScript) and production (C++ daemon) modes */ export async function initializeDBAL(): Promise { if (dbalState.initialized) { @@ -20,7 +19,7 @@ export async function initializeDBAL(): Promise { const engine = process.env.DBAL_SQL_ENGINE?.toLowerCase() === 'mysql' ? 'mysql' : 'postgres' const auth = process.env.DBAL_API_KEY ? { apiKey: process.env.DBAL_API_KEY } : undefined - const config: RealDBALConfig = { + const config: DBALConfig = { mode, adapter: endpoint ? 'prisma' : engine, endpoint: endpoint ?? undefined, @@ -34,25 +33,7 @@ export async function initializeDBAL(): Promise { }, } - try { - dbalState.client = new RealDBALClient(config) - dbalState.initialized = true - console.log('Real DBAL client initialized successfully') - } catch (error) { - console.warn('Falling back to stub DBAL client:', error) - const stubConfig: StubDBALConfig = { - mode, - adapter: engine, - auth, - database: { - url: databaseUrl, - }, - security: { - sandbox: 'permissive', - enableAuditLog: false, - }, - } - dbalState.client = new StubDBALClient(stubConfig) - dbalState.initialized = true - } + dbalState.client = new DBALClient(config) + dbalState.initialized = true + console.log(`DBAL client initialized in ${mode} mode${endpoint ? ' with WebSocket endpoint' : ''}`) } diff --git a/frontends/nextjs/src/lib/dbal/dbal-client/create-dbal-client.ts b/frontends/nextjs/src/lib/dbal/dbal-client/create-dbal-client.ts index d61b57cea..b9c1976dc 100644 --- a/frontends/nextjs/src/lib/dbal/dbal-client/create-dbal-client.ts +++ b/frontends/nextjs/src/lib/dbal/dbal-client/create-dbal-client.ts @@ -1,5 +1,5 @@ -import { DBALClient } from '@/lib/dbal-stub' -import type { DBALConfig } from '@/lib/dbal-stub' +import { DBALClient } from '@/dbal' +import type { DBALConfig } from '@/dbal' import type { User } from '../../types/level-types' import { dbalClientState } from './dbal-client-state' diff --git a/frontends/nextjs/src/lib/dbal/dbal-client/dbal-client-state.ts b/frontends/nextjs/src/lib/dbal/dbal-client/dbal-client-state.ts index 0508d416d..4ac9831bd 100644 --- a/frontends/nextjs/src/lib/dbal/dbal-client/dbal-client-state.ts +++ b/frontends/nextjs/src/lib/dbal/dbal-client/dbal-client-state.ts @@ -1,4 +1,4 @@ -import type { DBALClient } from '@/lib/dbal-stub' +import type { DBALClient } from '@/dbal' export const dbalClientState: { instance: DBALClient | null } = { instance: null, diff --git a/frontends/nextjs/src/lib/dbal/dbal-stub/blob/index.ts b/frontends/nextjs/src/lib/dbal/dbal-stub/blob/index.ts deleted file mode 100644 index f8d3690d2..000000000 --- a/frontends/nextjs/src/lib/dbal/dbal-stub/blob/index.ts +++ /dev/null @@ -1,82 +0,0 @@ -/** - * DBAL Blob Storage Stub - */ - -/* eslint-disable @typescript-eslint/no-explicit-any */ - - -export interface BlobStorageConfig { - type: 'filesystem' | 'memory' | 's3' - basePath?: string -} - -export interface BlobMetadata { - contentType?: string - size?: number - lastModified?: Date - [key: string]: any -} - -export interface BlobListItem { - key: string - [key: string]: any -} - -export interface BlobListResult { - items: BlobListItem[] -} - -export interface BlobStorage { - upload(key: string, data: Buffer | string, metadata?: BlobMetadata): Promise - download(key: string): Promise - delete(key: string): Promise - exists(key: string): Promise - list(options?: { prefix?: string }): Promise - getMetadata(key: string): Promise -} - -class InMemoryBlobStorage implements BlobStorage { - private store = new Map() - - async upload(key: string, data: Buffer | string, metadata?: BlobMetadata): Promise { - const buffer = typeof data === 'string' ? Buffer.from(data) : data - this.store.set(key, { - data: buffer, - metadata: { ...metadata, size: buffer.length, lastModified: new Date() }, - }) - return key - } - - async download(key: string): Promise { - const item = this.store.get(key) - if (!item) throw new Error(`Blob not found: ${key}`) - return item.data - } - - async delete(key: string): Promise { - this.store.delete(key) - } - - async exists(key: string): Promise { - return this.store.has(key) - } - - async list(options?: { prefix?: string }): Promise { - const items: BlobListItem[] = [] - for (const key of this.store.keys()) { - if (!options?.prefix || key.startsWith(options.prefix)) { - items.push({ key }) - } - } - return { items } - } - - async getMetadata(key: string): Promise { - const item = this.store.get(key) - return item?.metadata ?? null - } -} - -export function createBlobStorage(_config: BlobStorageConfig): BlobStorage { - return new InMemoryBlobStorage() -} diff --git a/frontends/nextjs/src/lib/dbal/dbal-stub/blob/tenant-aware-storage.ts b/frontends/nextjs/src/lib/dbal/dbal-stub/blob/tenant-aware-storage.ts deleted file mode 100644 index 3702c23ce..000000000 --- a/frontends/nextjs/src/lib/dbal/dbal-stub/blob/tenant-aware-storage.ts +++ /dev/null @@ -1,40 +0,0 @@ -/** - * DBAL Tenant-Aware Blob Storage Stub - */ - -/* eslint-disable @typescript-eslint/no-explicit-any */ - - -import type { BlobStorage, BlobMetadata, BlobListResult } from './index' - -export class TenantAwareBlobStorage implements BlobStorage { - constructor( - private storage: BlobStorage, - _tenantManager: any, - ..._args: any[] - ) {} - - async upload(key: string, data: Buffer | string, metadata?: BlobMetadata): Promise { - return this.storage.upload(key, data, metadata) - } - - async download(key: string): Promise { - return this.storage.download(key) - } - - async delete(key: string): Promise { - return this.storage.delete(key) - } - - async exists(key: string): Promise { - return this.storage.exists(key) - } - - async list(options?: { prefix?: string }): Promise { - return this.storage.list(options) - } - - async getMetadata(key: string): Promise { - return this.storage.getMetadata(key) - } -} diff --git a/frontends/nextjs/src/lib/dbal/dbal-stub/core/kv-store.ts b/frontends/nextjs/src/lib/dbal/dbal-stub/core/kv-store.ts deleted file mode 100644 index ac13a610d..000000000 --- a/frontends/nextjs/src/lib/dbal/dbal-stub/core/kv-store.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * DBAL KV Store Stub - */ - -/* eslint-disable @typescript-eslint/no-explicit-any */ - - -import type { TenantContext } from './tenant-context' - -export class InMemoryKVStore { - private store = new Map() - - async get(key: string, _context?: TenantContext): Promise { - return this.store.get(key) ?? null - } - - async set(key: string, value: T, _context?: TenantContext, _ttl?: number): Promise { - this.store.set(key, value) - } - - async delete(key: string, _context?: TenantContext): Promise { - return this.store.delete(key) - } - - async listAdd(key: string, items: any[], _context?: TenantContext): Promise { - const existing = this.store.get(key) || [] - this.store.set(key, [...existing, ...items]) - } - - async listGet(key: string, _context?: TenantContext, start = 0, end = -1): Promise { - const list = this.store.get(key) || [] - return end === -1 ? list.slice(start) : list.slice(start, end) - } -} diff --git a/frontends/nextjs/src/lib/dbal/dbal-stub/core/tenant-context.ts b/frontends/nextjs/src/lib/dbal/dbal-stub/core/tenant-context.ts deleted file mode 100644 index 83fb613ae..000000000 --- a/frontends/nextjs/src/lib/dbal/dbal-stub/core/tenant-context.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * DBAL Tenant Context Stub - */ - -/* eslint-disable @typescript-eslint/no-explicit-any */ - - -export interface TenantContext { - tenantId: string - userId?: string -} - -export class InMemoryTenantManager { - private currentTenant: string | null = null - - setCurrentTenant(tenantId: string): void { - this.currentTenant = tenantId - } - - getCurrentTenant(): string | null { - return this.currentTenant - } - - async createTenant(_id: string, _metadata: Record, ..._args: any[]): Promise { - // Stub implementation - } - - async getTenantContext(tenantId: string, userId?: string): Promise { - return { tenantId, userId } - } -} diff --git a/frontends/nextjs/src/lib/dbal/dbal-stub/core/types.ts b/frontends/nextjs/src/lib/dbal/dbal-stub/core/types.ts deleted file mode 100644 index 93362d5c1..000000000 --- a/frontends/nextjs/src/lib/dbal/dbal-stub/core/types.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * DBAL Core Types Stub - */ - -export interface User { - id: string - email: string - name?: string - level: number - tenantId: string -} diff --git a/frontends/nextjs/src/lib/dbal/dbal-stub/index.ts b/frontends/nextjs/src/lib/dbal/dbal-stub/index.ts deleted file mode 100644 index f2a03896b..000000000 --- a/frontends/nextjs/src/lib/dbal/dbal-stub/index.ts +++ /dev/null @@ -1,94 +0,0 @@ -/** - * DBAL Stub Module - * This provides runtime stubs for the DBAL when the full module is not available. - * Used in the frontend when DBAL is not fully configured. - */ - -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export interface DBALConfig { - mode?: 'development' | 'production' - adapter?: string - auth?: any - database?: { - url?: string - } - security?: { - sandbox?: 'strict' | 'permissive' | 'disabled' - enableAuditLog?: boolean - } - [key: string]: any -} - -export interface DBALUser { - id: string - email: string - name?: string - username?: string - level?: number - role?: string - tenantId?: string - createdAt?: number | string | Date - [key: string]: any -} - -export interface ListResult { - data: T[] - total?: number -} - -export interface UsersAPI { - list(): Promise> - create(data: Partial): Promise - update(id: string, data: Partial): Promise - delete(id: string): Promise -} - -export class DBALClient { - users: UsersAPI - - constructor(_config: DBALConfig) { - // Stub users API - this.users = { - list: async () => ({ data: [], total: 0 }), - create: async (data) => ({ id: 'stub', email: data.email || '', ...data }), - update: async (id, data) => ({ id, email: '', ...data }), - delete: async () => true, - } - } - - async query(_sql: string, _params?: unknown[]): Promise { - console.warn('DBAL stub: query not implemented') - return [] - } - - async execute(_sql: string, _params?: unknown[]): Promise { - console.warn('DBAL stub: execute not implemented') - } - - async capabilities(): Promise> { - return { - users: true, - tenants: false, - kv: false, - blob: false, - } - } -} - -export class DBALError extends Error { - code: DBALErrorCode - - constructor(message: string, code: DBALErrorCode) { - super(message) - this.code = code - this.name = 'DBALError' - } -} - -export enum DBALErrorCode { - UNKNOWN = 'UNKNOWN', - CONNECTION_ERROR = 'CONNECTION_ERROR', - QUERY_ERROR = 'QUERY_ERROR', - VALIDATION_ERROR = 'VALIDATION_ERROR', -} diff --git a/frontends/nextjs/tsconfig.json b/frontends/nextjs/tsconfig.json index 1f554ba40..944f670d9 100644 --- a/frontends/nextjs/tsconfig.json +++ b/frontends/nextjs/tsconfig.json @@ -29,11 +29,14 @@ "@/*": [ "./src/*" ], + "@/dbal": [ + "../../dbal/development/src" + ], "@/dbal/*": [ - "../dbal/development/src/*" + "../../dbal/development/src/*" ], "@dbal-ui/*": [ - "../dbal/src/*" + "../../dbal/src/*" ] }, "plugins": [