@gftdcojp/gftd-orm
Version:
Enterprise-grade real-time data platform with ksqlDB, inspired by Supabase architecture
194 lines • 6.32 kB
JavaScript
/**
* Supabase風クライアント - 匿名キーベースの統合クライアント
*/
import { rls, executePullQuery, executePushQuery, AuditLogManager, AuditEventType, AuditLogLevel } from './types';
import { RealtimeClient } from './realtime-client';
import { log } from './utils/logger';
/**
* キーの種類
*/
export var KeyType;
(function (KeyType) {
KeyType["ANON"] = "anon";
KeyType["SERVICE_ROLE"] = "service_role";
})(KeyType || (KeyType = {}));
/**
* 最小限のキー認証システム(内部実装)
* @deprecated anon-key-systemから移行
*/
class SimpleKeyAuth {
constructor() {
this.validKeys = new Set();
// デフォルトキーを設定(開発用)
this.validKeys.add('gftd_anon_mock_key');
this.validKeys.add('gftd_service_mock_key');
}
static getInstance() {
if (!SimpleKeyAuth.instance) {
SimpleKeyAuth.instance = new SimpleKeyAuth();
}
return SimpleKeyAuth.instance;
}
authenticateWithKey(key, userId) {
if (!this.validKeys.has(key)) {
return { success: false, error: 'Invalid key' };
}
const isServiceKey = key.includes('service');
const user = {
sub: userId || `mock-${Date.now()}`,
role: isServiceKey ? 'service_role' : 'anon',
tenant_id: 'default',
metadata: {
keyType: isServiceKey ? KeyType.SERVICE_ROLE : KeyType.ANON,
},
app_metadata: {
provider: 'key',
keyId: key,
},
user_metadata: {},
};
return { success: true, user, token: 'mock-token' };
}
}
/**
* 最小限のキーシステムヘルパー
*/
const simpleKeySystem = {
manager: () => SimpleKeyAuth.getInstance(),
};
/**
* Supabase風クライアント
*/
export class GftdClient {
constructor(config) {
this.config = config;
this.authState = {
user: null,
session: null,
isAuthenticated: false,
isAnonymous: false,
};
this.initializeClient();
}
/**
* クライアントを初期化
*/
async initializeClient() {
// キーベース認証を実行
const authResult = simpleKeySystem.manager().authenticateWithKey(this.config.key);
if (authResult.success && authResult.user) {
this.authState = {
user: authResult.user,
session: {
accessToken: authResult.token || '',
user: authResult.user,
expiresAt: Math.floor(Date.now() / 1000) + 3600, // 1時間
expiresIn: 3600, // 1時間(秒)
tokenType: 'Bearer',
},
isAuthenticated: true,
isAnonymous: authResult.user.role === 'anon',
};
log.info(`GFTD Client initialized with ${authResult.user.role} key`);
// リアルタイムクライアントを初期化
if (this.config.options?.realtime) {
this.realtimeClient = new RealtimeClient({
url: this.config.options.realtime.url || this.config.url.replace('http', 'ws'),
autoReconnect: this.config.options.realtime.autoReconnect,
});
}
}
else {
throw new Error(`Authentication failed: ${authResult.error}`);
}
}
/**
* 認証状態を取得
*/
get auth() {
return this.authState;
}
/**
* 直接SQLクエリを実行
*/
async query(sql, options) {
try {
if (!this.authState.user) {
throw new Error('Not authenticated');
}
// RLSを適用
const modifiedSQL = rls.applyToQuery(sql, this.authState.user);
// クエリを実行
const result = await executePullQuery(modifiedSQL, options);
AuditLogManager.log({
level: AuditLogLevel.INFO,
eventType: AuditEventType.DATA_READ,
userId: this.authState.user.sub,
tenantId: this.authState.user.tenant_id,
result: 'SUCCESS',
message: `Query executed successfully`,
details: { sql: modifiedSQL },
});
return {
data: result.data,
error: null,
};
}
catch (error) {
log.error(`Query execution failed: ${error}`);
if (this.authState.user) {
AuditLogManager.log({
level: AuditLogLevel.ERROR,
eventType: AuditEventType.DATA_READ,
userId: this.authState.user.sub,
tenantId: this.authState.user.tenant_id,
result: 'FAILURE',
message: `Query execution failed: ${error}`,
details: { sql, error: String(error) },
});
}
return {
data: [],
error: error,
};
}
}
/**
* プッシュクエリを実行(ストリーミング)
*/
async stream(sql, onData, onError) {
if (!this.authState.user) {
throw new Error('Not authenticated');
}
// RLSを適用
const modifiedSQL = rls.applyToQuery(sql, this.authState.user);
return executePushQuery(modifiedSQL, onData, onError);
}
/**
* 接続をクリーンアップ
*/
dispose() {
if (this.tokenRefreshInterval) {
clearInterval(this.tokenRefreshInterval);
}
if (this.realtimeClient) {
this.realtimeClient.disconnect();
}
}
/**
* 公開キーを取得(互換性のため)
*/
getKeys() {
return {
anonKey: 'gftd_anon_mock_key',
serviceRoleKey: null, // サービスロールキーは公開しない
};
}
}
/**
* Supabase風クライアント作成関数
*/
export function createClient(url, key, options) {
return new GftdClient({ url, key, options });
}
//# sourceMappingURL=supabase-like-client.js.map