UNPKG

@gftdcojp/gftd-orm

Version:

Enterprise-grade real-time data platform with ksqlDB, inspired by Supabase architecture

269 lines 8.72 kB
/** * Next.js環境のブラウザ専用クライアント * Client ComponentsやPages Routerのクライアントサイドで使用 */ // Mock DatabaseClient implementation // @todo [P2] Replace with actual DatabaseClient implementation class DatabaseClient { constructor(config) { console.log('[MOCK] DatabaseClient created:', config); } async initialize() { console.log('[MOCK] DatabaseClient initialized'); } from(table) { return { select: () => ({ eq: () => ({ execute: () => Promise.resolve({ data: [], error: null }) }) }), insert: (data) => Promise.resolve({ data: [], error: null }), update: (data) => Promise.resolve({ data: [], error: null }), delete: () => Promise.resolve({ data: [], error: null }), execute: () => Promise.resolve({ data: [], error: null }) }; } async sql(query, params) { return { data: [], queryId: 'mock-query' }; } async health() { return { status: 'ok' }; } } import { RealtimeClient } from '../realtime-client'; import { isBrowser } from '../utils/env'; import { log } from '../utils/logger'; /** * ブラウザ専用のGFTD-ORMクライアント */ export class BrowserClient { constructor(config) { this._database = null; this._realtime = null; this.initialized = false; this._isConnected = false; this.validateBrowserEnvironment(); this.config = config; } /** * ブラウザ環境の検証 */ validateBrowserEnvironment() { if (!isBrowser()) { throw new Error('BrowserClient can only be used in browser environment. ' + 'Use ServerClient for server-side rendering or API routes.'); } } /** * データベースクライアントを取得 */ get database() { if (!this._database) { throw new Error('Database not initialized. Call initialize() first.'); } return this._database; } /** * リアルタイムクライアントを取得 */ get realtime() { if (!this._realtime) { throw new Error('Realtime not initialized or not configured.'); } return this._realtime; } /** * クライアントを初期化 */ async initialize() { if (this.initialized) { return; } try { log.info('Initializing browser client...'); // Database初期化(ブラウザ版) this._database = new DatabaseClient({ ksql: { url: this.config.database.ksql.url, apiKey: this.config.database.ksql.apiKey, headers: { 'User-Agent': 'gftd-orm-browser-client', 'X-Client-Type': 'browser', ...this.config.database.ksql.headers, }, }, schemaRegistry: { url: this.config.database.schemaRegistry.url, apiKey: this.config.database.schemaRegistry.apiKey, }, }); await this._database.initialize(); // Realtime初期化(ブラウザ版) if (this.config.realtime) { this._realtime = new RealtimeClient({ url: this.config.realtime.url, apiKey: this.config.realtime.apiKey, autoReconnect: this.config.realtime.autoReconnect ?? true, reconnectInterval: this.config.realtime.reconnectInterval ?? 3000, maxReconnectAttempts: this.config.realtime.maxReconnectAttempts ?? 5, }); } this.initialized = true; this._isConnected = true; log.info('Browser client initialized successfully'); } catch (error) { log.error(`Failed to initialize browser client: ${error}`); this._isConnected = false; throw error; } } /** * Supabaseライクなテーブルアクセス */ from(table) { return this.database.from(table); } /** * SQL クエリを実行 */ async query(sql, params) { try { const startTime = Date.now(); const result = await this.database.sql(sql, params); const executionTime = Date.now() - startTime; return { data: result.data, error: null, metadata: { rowCount: result.data.length, executionTime, queryId: result.queryId, }, }; } catch (error) { log.error(`Query execution failed: ${error}`); return { data: [], error: error, }; } } /** * ストリーミングクエリを実行 */ async stream(sql, onData, onError) { try { // TODO: DatabaseClientのstream機能が実装されるまでの暫定実装 const mockTerminate = () => { log.info('Stream terminated'); }; // 実際の実装では、this.database.stream(sql, onData, onError) を使用 // const { terminate } = await this.database.stream(sql, onData, onError); return { terminate: mockTerminate, pause: () => { // ブラウザクライアントでは一時停止機能は制限的 log.warn('Pause functionality is limited in browser client'); }, resume: () => { // ブラウザクライアントでは再開機能は制限的 log.warn('Resume functionality is limited in browser client'); }, isActive: () => true, // 基本的なステータス管理 }; } catch (error) { log.error(`Stream execution failed: ${error}`); throw error; } } /** * リアルタイムチャンネル */ channel(name) { if (!this._realtime) { throw new Error('Realtime not configured. Please provide realtime config when creating the client.'); } return this._realtime.channel(name); } /** * ヘルスチェック */ async health() { const connections = { ksqldb: this._database ? 'connected' : 'disconnected', schemaRegistry: this._database ? 'connected' : 'disconnected', realtime: this._realtime ? 'connected' : 'disconnected', }; const features = [ 'database', ...(this._realtime ? ['realtime'] : []), 'rate-limit', ]; try { // データベースの健康状態をチェック if (this._database) { await this._database.health(); } return { status: 'ok', version: '25.07.6', features, connections, environment: 'browser', }; } catch (error) { log.error(`Health check failed: ${error}`); return { status: 'error', version: '25.07.6', features, connections: { ...connections, ksqldb: 'error', }, environment: 'browser', }; } } /** * 接続状態を確認 */ isConnected() { return this._isConnected && this.initialized; } /** * すべての接続を閉じる */ async disconnect() { try { if (this._realtime) { this._realtime.disconnect(); } this._isConnected = false; this.initialized = false; log.info('Browser client disconnected'); } catch (error) { log.error(`Error during disconnect: ${error}`); throw error; } } } /** * ブラウザ専用クライアント作成関数 */ export function createBrowserClient(config) { return new BrowserClient(config); } /** * Next.js Client Components用のクライアント作成関数 */ export function createNextBrowserClient(config) { return createBrowserClient(config); } //# sourceMappingURL=browser.js.map