@vezlo/assistant-server 2.10.0 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/database-schema.sql +44 -0
- package/dist/src/bootstrap/initializeServices.d.ts +5 -0
- package/dist/src/bootstrap/initializeServices.d.ts.map +1 -1
- package/dist/src/bootstrap/initializeServices.js +20 -4
- package/dist/src/bootstrap/initializeServices.js.map +1 -1
- package/dist/src/controllers/ChatController.d.ts +3 -0
- package/dist/src/controllers/ChatController.d.ts.map +1 -1
- package/dist/src/controllers/ChatController.js +75 -15
- package/dist/src/controllers/ChatController.js.map +1 -1
- package/dist/src/controllers/DatabaseToolConfigController.d.ts +81 -0
- package/dist/src/controllers/DatabaseToolConfigController.d.ts.map +1 -0
- package/dist/src/controllers/DatabaseToolConfigController.js +524 -0
- package/dist/src/controllers/DatabaseToolConfigController.js.map +1 -0
- package/dist/src/controllers/KnowledgeController.js +4 -4
- package/dist/src/controllers/KnowledgeController.js.map +1 -1
- package/dist/src/migrations/011_create_database_tool_configs.d.ts +4 -0
- package/dist/src/migrations/011_create_database_tool_configs.d.ts.map +1 -0
- package/dist/src/migrations/011_create_database_tool_configs.js +49 -0
- package/dist/src/migrations/011_create_database_tool_configs.js.map +1 -0
- package/dist/src/server.js +399 -0
- package/dist/src/server.js.map +1 -1
- package/dist/src/services/AIService.d.ts +3 -0
- package/dist/src/services/AIService.d.ts.map +1 -1
- package/dist/src/services/AIService.js +5 -0
- package/dist/src/services/AIService.js.map +1 -1
- package/dist/src/services/DatabaseToolConfigService.d.ts +133 -0
- package/dist/src/services/DatabaseToolConfigService.d.ts.map +1 -0
- package/dist/src/services/DatabaseToolConfigService.js +442 -0
- package/dist/src/services/DatabaseToolConfigService.js.map +1 -0
- package/dist/src/services/DatabaseToolService.d.ts +75 -0
- package/dist/src/services/DatabaseToolService.d.ts.map +1 -0
- package/dist/src/services/DatabaseToolService.js +299 -0
- package/dist/src/services/DatabaseToolService.js.map +1 -0
- package/dist/src/services/IntentService.d.ts +12 -1
- package/dist/src/services/IntentService.d.ts.map +1 -1
- package/dist/src/services/IntentService.js +35 -5
- package/dist/src/services/IntentService.js.map +1 -1
- package/dist/src/services/ResponseGenerationService.d.ts +5 -3
- package/dist/src/services/ResponseGenerationService.d.ts.map +1 -1
- package/dist/src/services/ResponseGenerationService.js +29 -4
- package/dist/src/services/ResponseGenerationService.js.map +1 -1
- package/package.json +1 -1
|
@@ -23,6 +23,10 @@ class AIService {
|
|
|
23
23
|
this.knowledgeBaseService = service;
|
|
24
24
|
this.systemPrompt = this.buildSystemPrompt();
|
|
25
25
|
}
|
|
26
|
+
setDatabaseToolService(service) {
|
|
27
|
+
this.databaseToolService = service;
|
|
28
|
+
logger_1.default.info('🔌 Database tool service attached to AI Service');
|
|
29
|
+
}
|
|
26
30
|
buildSystemPrompt() {
|
|
27
31
|
const orgName = this.config.organizationName || 'Your Organization';
|
|
28
32
|
const assistantName = this.config.assistantName || `${orgName} AI Assistant`;
|
|
@@ -171,6 +175,7 @@ The knowledge base contains curated content ingested through the src-to-kb pipel
|
|
|
171
175
|
*/
|
|
172
176
|
async *generateResponseStream(message, context) {
|
|
173
177
|
try {
|
|
178
|
+
// Note: Database tools are handled separately in ChatController before streaming
|
|
174
179
|
let knowledgeResults = '';
|
|
175
180
|
let hasKnowledgeContext = false;
|
|
176
181
|
// Check if knowledge results are already provided in context
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIService.js","sourceRoot":"","sources":["../../../src/services/AIService.ts"],"names":[],"mappings":";;;;;;AAAA,oDAA4B;
|
|
1
|
+
{"version":3,"file":"AIService.js","sourceRoot":"","sources":["../../../src/services/AIService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DatabaseToolConfigService
|
|
3
|
+
*
|
|
4
|
+
* Manages external database tool configurations for companies
|
|
5
|
+
* Handles CRUD operations, encryption, and schema introspection
|
|
6
|
+
*/
|
|
7
|
+
import { SupabaseClient } from '@supabase/supabase-js';
|
|
8
|
+
export interface DatabaseToolConfig {
|
|
9
|
+
id?: string;
|
|
10
|
+
company_id: number;
|
|
11
|
+
db_url_encrypted: string;
|
|
12
|
+
db_key_encrypted: string;
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
created_at?: Date;
|
|
15
|
+
updated_at?: Date;
|
|
16
|
+
}
|
|
17
|
+
export interface DatabaseTool {
|
|
18
|
+
id?: string;
|
|
19
|
+
config_id: string;
|
|
20
|
+
table_name: string;
|
|
21
|
+
tool_name: string;
|
|
22
|
+
tool_description: string;
|
|
23
|
+
columns: string[];
|
|
24
|
+
id_column: string;
|
|
25
|
+
id_column_type: 'integer' | 'uuid' | 'string';
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
requires_user_context?: boolean;
|
|
28
|
+
user_filter_column?: string | null;
|
|
29
|
+
user_filter_type?: 'uuid' | 'integer' | 'string' | null;
|
|
30
|
+
user_context_key?: string | null;
|
|
31
|
+
created_at?: Date;
|
|
32
|
+
updated_at?: Date;
|
|
33
|
+
}
|
|
34
|
+
export interface TableSchema {
|
|
35
|
+
table_name: string;
|
|
36
|
+
columns: Array<{
|
|
37
|
+
column_name: string;
|
|
38
|
+
data_type: string;
|
|
39
|
+
is_nullable: string;
|
|
40
|
+
}>;
|
|
41
|
+
}
|
|
42
|
+
export declare class DatabaseToolConfigService {
|
|
43
|
+
private supabase;
|
|
44
|
+
private encryptionKey;
|
|
45
|
+
private algorithm;
|
|
46
|
+
constructor(supabase: SupabaseClient);
|
|
47
|
+
/**
|
|
48
|
+
* Encrypt sensitive data
|
|
49
|
+
*/
|
|
50
|
+
private encrypt;
|
|
51
|
+
/**
|
|
52
|
+
* Decrypt sensitive data
|
|
53
|
+
*/
|
|
54
|
+
private decrypt;
|
|
55
|
+
/**
|
|
56
|
+
* Create a new database tool configuration
|
|
57
|
+
*/
|
|
58
|
+
createConfig(companyId: number, dbUrl: string, dbKey: string): Promise<DatabaseToolConfig>;
|
|
59
|
+
/**
|
|
60
|
+
* Get configuration by company ID
|
|
61
|
+
*/
|
|
62
|
+
getConfigByCompany(companyId: number): Promise<DatabaseToolConfig | null>;
|
|
63
|
+
/**
|
|
64
|
+
* Get decrypted credentials for a company
|
|
65
|
+
*/
|
|
66
|
+
getDecryptedCredentials(companyId: number): Promise<{
|
|
67
|
+
url: string;
|
|
68
|
+
key: string;
|
|
69
|
+
} | null>;
|
|
70
|
+
/**
|
|
71
|
+
* Get decrypted credentials by config ID
|
|
72
|
+
*/
|
|
73
|
+
getDecryptedCredentialsByConfigId(configId: string): Promise<{
|
|
74
|
+
url: string;
|
|
75
|
+
key: string;
|
|
76
|
+
} | null>;
|
|
77
|
+
/**
|
|
78
|
+
* Update configuration
|
|
79
|
+
*/
|
|
80
|
+
updateConfig(configId: string, dbUrl?: string, dbKey?: string, enabled?: boolean): Promise<DatabaseToolConfig>;
|
|
81
|
+
/**
|
|
82
|
+
* Delete configuration
|
|
83
|
+
*/
|
|
84
|
+
deleteConfig(configId: string): Promise<void>;
|
|
85
|
+
/**
|
|
86
|
+
* Validate database connection and credentials (READ-ONLY)
|
|
87
|
+
*/
|
|
88
|
+
validateConnection(dbUrl: string, dbKey: string): Promise<{
|
|
89
|
+
valid: boolean;
|
|
90
|
+
error?: string;
|
|
91
|
+
tables?: string[];
|
|
92
|
+
}>;
|
|
93
|
+
/**
|
|
94
|
+
* Introspect database schema - get all tables (READ-ONLY, no database writes required)
|
|
95
|
+
*/
|
|
96
|
+
introspectTables(dbUrl: string, dbKey: string): Promise<string[]>;
|
|
97
|
+
/**
|
|
98
|
+
* Introspect table schema - get columns and types (READ-ONLY, no database writes required)
|
|
99
|
+
*/
|
|
100
|
+
introspectTableColumns(dbUrl: string, dbKey: string, tableName: string): Promise<TableSchema>;
|
|
101
|
+
/**
|
|
102
|
+
* Create a tool for a specific table
|
|
103
|
+
*/
|
|
104
|
+
createTool(configId: string, tableName: string, toolName: string, toolDescription: string, columns: string[], idColumn: string, idColumnType: 'integer' | 'uuid' | 'string', requiresUserContext?: boolean, userFilterColumn?: string, userFilterType?: 'uuid' | 'integer' | 'string', userContextKey?: string): Promise<DatabaseTool>;
|
|
105
|
+
/**
|
|
106
|
+
* Get all tools for a configuration
|
|
107
|
+
*/
|
|
108
|
+
getToolsByConfig(configId: string): Promise<DatabaseTool[]>;
|
|
109
|
+
/**
|
|
110
|
+
* Get all enabled tools for a company
|
|
111
|
+
*/
|
|
112
|
+
getEnabledToolsByCompany(companyId: number): Promise<DatabaseTool[]>;
|
|
113
|
+
/**
|
|
114
|
+
* Update a tool
|
|
115
|
+
*/
|
|
116
|
+
updateTool(toolId: string, updates: {
|
|
117
|
+
tool_name?: string;
|
|
118
|
+
tool_description?: string;
|
|
119
|
+
columns?: string[];
|
|
120
|
+
id_column?: string;
|
|
121
|
+
id_column_type?: 'integer' | 'uuid' | 'string';
|
|
122
|
+
enabled?: boolean;
|
|
123
|
+
requires_user_context?: boolean;
|
|
124
|
+
user_filter_column?: string;
|
|
125
|
+
user_filter_type?: 'uuid' | 'integer' | 'string';
|
|
126
|
+
user_context_key?: string;
|
|
127
|
+
}): Promise<DatabaseTool>;
|
|
128
|
+
/**
|
|
129
|
+
* Delete a tool
|
|
130
|
+
*/
|
|
131
|
+
deleteTool(toolId: string): Promise<void>;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=DatabaseToolConfigService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DatabaseToolConfigService.d.ts","sourceRoot":"","sources":["../../../src/services/DatabaseToolConfigService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DatabaseToolConfigService
|
|
4
|
+
*
|
|
5
|
+
* Manages external database tool configurations for companies
|
|
6
|
+
* Handles CRUD operations, encryption, and schema introspection
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DatabaseToolConfigService = void 0;
|
|
13
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
14
|
+
const logger_1 = __importDefault(require("../config/logger"));
|
|
15
|
+
class DatabaseToolConfigService {
|
|
16
|
+
constructor(supabase) {
|
|
17
|
+
this.algorithm = 'aes-256-cbc';
|
|
18
|
+
this.supabase = supabase;
|
|
19
|
+
// Use JWT_SECRET for encryption
|
|
20
|
+
const key = process.env.JWT_SECRET || 'default-encryption-key-change-this';
|
|
21
|
+
// Ensure key is 32 bytes for aes-256-cbc
|
|
22
|
+
this.encryptionKey = crypto_1.default.createHash('sha256').update(key).digest('hex').substring(0, 32);
|
|
23
|
+
if (!process.env.JWT_SECRET) {
|
|
24
|
+
logger_1.default.warn('⚠️ No JWT_SECRET found - using default (insecure for production)');
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Encrypt sensitive data
|
|
29
|
+
*/
|
|
30
|
+
encrypt(text) {
|
|
31
|
+
const iv = crypto_1.default.randomBytes(16);
|
|
32
|
+
const cipher = crypto_1.default.createCipheriv(this.algorithm, this.encryptionKey, iv);
|
|
33
|
+
let encrypted = cipher.update(text, 'utf8', 'hex');
|
|
34
|
+
encrypted += cipher.final('hex');
|
|
35
|
+
return iv.toString('hex') + ':' + encrypted;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Decrypt sensitive data
|
|
39
|
+
*/
|
|
40
|
+
decrypt(text) {
|
|
41
|
+
const parts = text.split(':');
|
|
42
|
+
const iv = Buffer.from(parts[0], 'hex');
|
|
43
|
+
const encryptedText = parts[1];
|
|
44
|
+
const decipher = crypto_1.default.createDecipheriv(this.algorithm, this.encryptionKey, iv);
|
|
45
|
+
let decrypted = decipher.update(encryptedText, 'hex', 'utf8');
|
|
46
|
+
decrypted += decipher.final('utf8');
|
|
47
|
+
return decrypted;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Create a new database tool configuration
|
|
51
|
+
*/
|
|
52
|
+
async createConfig(companyId, dbUrl, dbKey) {
|
|
53
|
+
const encryptedUrl = this.encrypt(dbUrl);
|
|
54
|
+
const encryptedKey = this.encrypt(dbKey);
|
|
55
|
+
const { data, error } = await this.supabase
|
|
56
|
+
.from('vezlo_database_tool_configs')
|
|
57
|
+
.insert({
|
|
58
|
+
company_id: companyId,
|
|
59
|
+
db_url_encrypted: encryptedUrl,
|
|
60
|
+
db_key_encrypted: encryptedKey,
|
|
61
|
+
enabled: true
|
|
62
|
+
})
|
|
63
|
+
.select()
|
|
64
|
+
.single();
|
|
65
|
+
if (error) {
|
|
66
|
+
logger_1.default.error('Failed to create database tool config:', error);
|
|
67
|
+
throw new Error(`Failed to create config: ${error.message}`);
|
|
68
|
+
}
|
|
69
|
+
logger_1.default.info(`✅ Created database tool config for company ${companyId}`);
|
|
70
|
+
return data;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get configuration by company ID
|
|
74
|
+
*/
|
|
75
|
+
async getConfigByCompany(companyId) {
|
|
76
|
+
const { data, error } = await this.supabase
|
|
77
|
+
.from('vezlo_database_tool_configs')
|
|
78
|
+
.select('*')
|
|
79
|
+
.eq('company_id', companyId)
|
|
80
|
+
.eq('enabled', true)
|
|
81
|
+
.single();
|
|
82
|
+
if (error && error.code !== 'PGRST116') { // PGRST116 = not found
|
|
83
|
+
logger_1.default.error('Failed to get database tool config:', error);
|
|
84
|
+
throw new Error(`Failed to get config: ${error.message}`);
|
|
85
|
+
}
|
|
86
|
+
return data || null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get decrypted credentials for a company
|
|
90
|
+
*/
|
|
91
|
+
async getDecryptedCredentials(companyId) {
|
|
92
|
+
const config = await this.getConfigByCompany(companyId);
|
|
93
|
+
if (!config) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
try {
|
|
97
|
+
const url = this.decrypt(config.db_url_encrypted);
|
|
98
|
+
const key = this.decrypt(config.db_key_encrypted);
|
|
99
|
+
return { url, key };
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
logger_1.default.error('Failed to decrypt credentials:', error);
|
|
103
|
+
throw new Error('Failed to decrypt database credentials');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get decrypted credentials by config ID
|
|
108
|
+
*/
|
|
109
|
+
async getDecryptedCredentialsByConfigId(configId) {
|
|
110
|
+
const { data: config, error } = await this.supabase
|
|
111
|
+
.from('vezlo_database_tool_configs')
|
|
112
|
+
.select('*')
|
|
113
|
+
.eq('id', configId)
|
|
114
|
+
.single();
|
|
115
|
+
if (error || !config) {
|
|
116
|
+
logger_1.default.error('Failed to get config by ID:', error);
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const url = this.decrypt(config.db_url_encrypted);
|
|
121
|
+
const key = this.decrypt(config.db_key_encrypted);
|
|
122
|
+
return { url, key };
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
logger_1.default.error('Failed to decrypt credentials:', error);
|
|
126
|
+
throw new Error('Failed to decrypt database credentials');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Update configuration
|
|
131
|
+
*/
|
|
132
|
+
async updateConfig(configId, dbUrl, dbKey, enabled) {
|
|
133
|
+
const updates = {};
|
|
134
|
+
if (dbUrl) {
|
|
135
|
+
updates.db_url_encrypted = this.encrypt(dbUrl);
|
|
136
|
+
}
|
|
137
|
+
if (dbKey) {
|
|
138
|
+
updates.db_key_encrypted = this.encrypt(dbKey);
|
|
139
|
+
}
|
|
140
|
+
if (enabled !== undefined) {
|
|
141
|
+
updates.enabled = enabled;
|
|
142
|
+
}
|
|
143
|
+
updates.updated_at = new Date().toISOString();
|
|
144
|
+
const { data, error } = await this.supabase
|
|
145
|
+
.from('vezlo_database_tool_configs')
|
|
146
|
+
.update(updates)
|
|
147
|
+
.eq('id', configId)
|
|
148
|
+
.select()
|
|
149
|
+
.single();
|
|
150
|
+
if (error) {
|
|
151
|
+
logger_1.default.error('Failed to update database tool config:', error);
|
|
152
|
+
throw new Error(`Failed to update config: ${error.message}`);
|
|
153
|
+
}
|
|
154
|
+
logger_1.default.info(`✅ Updated database tool config ${configId}`);
|
|
155
|
+
return data;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Delete configuration
|
|
159
|
+
*/
|
|
160
|
+
async deleteConfig(configId) {
|
|
161
|
+
const { error } = await this.supabase
|
|
162
|
+
.from('vezlo_database_tool_configs')
|
|
163
|
+
.delete()
|
|
164
|
+
.eq('id', configId);
|
|
165
|
+
if (error) {
|
|
166
|
+
logger_1.default.error('Failed to delete database tool config:', error);
|
|
167
|
+
throw new Error(`Failed to delete config: ${error.message}`);
|
|
168
|
+
}
|
|
169
|
+
logger_1.default.info(`✅ Deleted database tool config ${configId}`);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Validate database connection and credentials (READ-ONLY)
|
|
173
|
+
*/
|
|
174
|
+
async validateConnection(dbUrl, dbKey) {
|
|
175
|
+
try {
|
|
176
|
+
// Use Supabase REST API to get OpenAPI schema (read-only operation)
|
|
177
|
+
// This doesn't require any functions to be created in the database
|
|
178
|
+
const response = await fetch(`${dbUrl}/rest/v1/`, {
|
|
179
|
+
method: 'GET',
|
|
180
|
+
headers: {
|
|
181
|
+
'apikey': dbKey,
|
|
182
|
+
'Authorization': `Bearer ${dbKey}`
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
if (!response.ok) {
|
|
186
|
+
return { valid: false, error: `Connection failed: ${response.statusText}` };
|
|
187
|
+
}
|
|
188
|
+
const openApiSpec = await response.json();
|
|
189
|
+
// Extract table names from OpenAPI spec paths
|
|
190
|
+
const tables = [];
|
|
191
|
+
if (openApiSpec.paths) {
|
|
192
|
+
logger_1.default.info(`📋 Found ${Object.keys(openApiSpec.paths).length} paths in OpenAPI spec`);
|
|
193
|
+
for (const path of Object.keys(openApiSpec.paths)) {
|
|
194
|
+
// Paths are like "/table_name" - extract table name
|
|
195
|
+
const match = path.match(/^\/([^\/\?]+)/);
|
|
196
|
+
if (match && match[1] && !match[1].startsWith('rpc')) {
|
|
197
|
+
tables.push(match[1]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
logger_1.default.warn('⚠️ No paths found in OpenAPI spec - check if tables are exposed to REST API');
|
|
203
|
+
}
|
|
204
|
+
const uniqueTables = [...new Set(tables)];
|
|
205
|
+
logger_1.default.info(`✅ Found ${uniqueTables.length} tables available via REST API`);
|
|
206
|
+
return { valid: true, tables: uniqueTables };
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
return { valid: false, error: error.message || 'Connection failed' };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Introspect database schema - get all tables (READ-ONLY, no database writes required)
|
|
214
|
+
*/
|
|
215
|
+
async introspectTables(dbUrl, dbKey) {
|
|
216
|
+
try {
|
|
217
|
+
// Use Supabase REST API OpenAPI endpoint (read-only, no setup required)
|
|
218
|
+
const response = await fetch(`${dbUrl}/rest/v1/`, {
|
|
219
|
+
method: 'GET',
|
|
220
|
+
headers: {
|
|
221
|
+
'apikey': dbKey,
|
|
222
|
+
'Authorization': `Bearer ${dbKey}`,
|
|
223
|
+
'Accept': 'application/json'
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
if (!response.ok) {
|
|
227
|
+
throw new Error(`Failed to fetch database schema: ${response.statusText}`);
|
|
228
|
+
}
|
|
229
|
+
const openApiSpec = await response.json();
|
|
230
|
+
// Extract table names from OpenAPI spec
|
|
231
|
+
const tables = [];
|
|
232
|
+
if (openApiSpec.paths) {
|
|
233
|
+
logger_1.default.info(`📋 Found ${Object.keys(openApiSpec.paths).length} paths in OpenAPI spec`);
|
|
234
|
+
for (const path of Object.keys(openApiSpec.paths)) {
|
|
235
|
+
// Paths are like "/table_name" - extract table name
|
|
236
|
+
const match = path.match(/^\/([^\/\?]+)/);
|
|
237
|
+
if (match && match[1] && !match[1].startsWith('rpc')) {
|
|
238
|
+
tables.push(match[1]);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
logger_1.default.warn('⚠️ No paths found in OpenAPI spec - tables may not be exposed to REST API');
|
|
244
|
+
}
|
|
245
|
+
const uniqueTables = [...new Set(tables)].sort();
|
|
246
|
+
logger_1.default.info(`✅ Successfully introspected ${uniqueTables.length} tables available via REST API`);
|
|
247
|
+
if (uniqueTables.length === 0) {
|
|
248
|
+
logger_1.default.warn('⚠️ No tables found. Possible reasons:');
|
|
249
|
+
logger_1.default.warn(' 1. Database has no tables');
|
|
250
|
+
logger_1.default.warn(' 2. Tables are not exposed to Supabase REST API');
|
|
251
|
+
logger_1.default.warn(' 3. Check Supabase Dashboard > API Settings > API Docs to see available tables');
|
|
252
|
+
}
|
|
253
|
+
return uniqueTables;
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
logger_1.default.error('Failed to introspect tables:', error);
|
|
257
|
+
throw new Error(`Failed to introspect tables: ${error.message}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Introspect table schema - get columns and types (READ-ONLY, no database writes required)
|
|
262
|
+
*/
|
|
263
|
+
async introspectTableColumns(dbUrl, dbKey, tableName) {
|
|
264
|
+
try {
|
|
265
|
+
// Use Supabase REST API OpenAPI endpoint (read-only, no setup required)
|
|
266
|
+
const response = await fetch(`${dbUrl}/rest/v1/`, {
|
|
267
|
+
method: 'GET',
|
|
268
|
+
headers: {
|
|
269
|
+
'apikey': dbKey,
|
|
270
|
+
'Authorization': `Bearer ${dbKey}`,
|
|
271
|
+
'Accept': 'application/json'
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
if (!response.ok) {
|
|
275
|
+
throw new Error(`Failed to fetch database schema: ${response.statusText}`);
|
|
276
|
+
}
|
|
277
|
+
const openApiSpec = await response.json();
|
|
278
|
+
// Find the schema definition for this table
|
|
279
|
+
const tableDefinition = openApiSpec.definitions?.[tableName];
|
|
280
|
+
if (!tableDefinition || !tableDefinition.properties) {
|
|
281
|
+
throw new Error(`Table "${tableName}" not found or has no accessible columns`);
|
|
282
|
+
}
|
|
283
|
+
// Extract column information
|
|
284
|
+
const columns = [];
|
|
285
|
+
for (const [columnName, columnSchema] of Object.entries(tableDefinition.properties)) {
|
|
286
|
+
const schema = columnSchema;
|
|
287
|
+
let dataType = schema.type || 'unknown';
|
|
288
|
+
// Map OpenAPI types to PostgreSQL types
|
|
289
|
+
if (schema.format === 'uuid')
|
|
290
|
+
dataType = 'uuid';
|
|
291
|
+
else if (schema.format === 'date-time')
|
|
292
|
+
dataType = 'timestamp';
|
|
293
|
+
else if (schema.format === 'date')
|
|
294
|
+
dataType = 'date';
|
|
295
|
+
else if (schema.type === 'integer')
|
|
296
|
+
dataType = 'integer';
|
|
297
|
+
else if (schema.type === 'number')
|
|
298
|
+
dataType = 'numeric';
|
|
299
|
+
else if (schema.type === 'boolean')
|
|
300
|
+
dataType = 'boolean';
|
|
301
|
+
else if (schema.type === 'string')
|
|
302
|
+
dataType = 'text';
|
|
303
|
+
else if (schema.type === 'array')
|
|
304
|
+
dataType = 'array';
|
|
305
|
+
const isNullable = tableDefinition.required?.includes(columnName) ? 'NO' : 'YES';
|
|
306
|
+
columns.push({
|
|
307
|
+
column_name: columnName,
|
|
308
|
+
data_type: dataType,
|
|
309
|
+
is_nullable: isNullable
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
logger_1.default.info(`✅ Successfully introspected ${columns.length} columns for table "${tableName}"`);
|
|
313
|
+
return {
|
|
314
|
+
table_name: tableName,
|
|
315
|
+
columns: columns.sort((a, b) => a.column_name.localeCompare(b.column_name))
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
catch (error) {
|
|
319
|
+
logger_1.default.error('Failed to introspect table columns:', error);
|
|
320
|
+
throw new Error(`Failed to introspect columns for table "${tableName}": ${error.message}`);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Create a tool for a specific table
|
|
325
|
+
*/
|
|
326
|
+
async createTool(configId, tableName, toolName, toolDescription, columns, idColumn, idColumnType, requiresUserContext, userFilterColumn, userFilterType, userContextKey) {
|
|
327
|
+
// Ensure columns is an array before stringifying
|
|
328
|
+
const columnsArray = Array.isArray(columns) ? columns :
|
|
329
|
+
(typeof columns === 'string' ? JSON.parse(columns) : columns);
|
|
330
|
+
const { data, error } = await this.supabase
|
|
331
|
+
.from('vezlo_database_tools')
|
|
332
|
+
.insert({
|
|
333
|
+
config_id: configId,
|
|
334
|
+
table_name: tableName,
|
|
335
|
+
tool_name: toolName,
|
|
336
|
+
tool_description: toolDescription,
|
|
337
|
+
columns: JSON.stringify(columnsArray),
|
|
338
|
+
id_column: idColumn,
|
|
339
|
+
id_column_type: idColumnType,
|
|
340
|
+
enabled: true,
|
|
341
|
+
requires_user_context: requiresUserContext || false,
|
|
342
|
+
user_filter_column: userFilterColumn || null,
|
|
343
|
+
user_filter_type: userFilterType || null,
|
|
344
|
+
user_context_key: userContextKey || null
|
|
345
|
+
})
|
|
346
|
+
.select()
|
|
347
|
+
.single();
|
|
348
|
+
if (error) {
|
|
349
|
+
logger_1.default.error('Failed to create database tool:', error);
|
|
350
|
+
throw new Error(`Failed to create tool: ${error.message}`);
|
|
351
|
+
}
|
|
352
|
+
logger_1.default.info(`✅ Created tool ${toolName} for table ${tableName}`);
|
|
353
|
+
// Parse columns before returning
|
|
354
|
+
return {
|
|
355
|
+
...data,
|
|
356
|
+
columns: typeof data.columns === 'string' ? JSON.parse(data.columns) : data.columns
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Get all tools for a configuration
|
|
361
|
+
*/
|
|
362
|
+
async getToolsByConfig(configId) {
|
|
363
|
+
const { data, error } = await this.supabase
|
|
364
|
+
.from('vezlo_database_tools')
|
|
365
|
+
.select('*')
|
|
366
|
+
.eq('config_id', configId)
|
|
367
|
+
.order('table_name');
|
|
368
|
+
if (error) {
|
|
369
|
+
logger_1.default.error('Failed to get database tools:', error);
|
|
370
|
+
throw new Error(`Failed to get tools: ${error.message}`);
|
|
371
|
+
}
|
|
372
|
+
// Parse columns JSONB field
|
|
373
|
+
return (data || []).map(tool => ({
|
|
374
|
+
...tool,
|
|
375
|
+
columns: typeof tool.columns === 'string' ? JSON.parse(tool.columns) : tool.columns
|
|
376
|
+
}));
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Get all enabled tools for a company
|
|
380
|
+
*/
|
|
381
|
+
async getEnabledToolsByCompany(companyId) {
|
|
382
|
+
const { data, error } = await this.supabase
|
|
383
|
+
.from('vezlo_database_tools')
|
|
384
|
+
.select('*, vezlo_database_tool_configs!inner(company_id, enabled)')
|
|
385
|
+
.eq('vezlo_database_tool_configs.company_id', companyId)
|
|
386
|
+
.eq('vezlo_database_tool_configs.enabled', true)
|
|
387
|
+
.eq('enabled', true);
|
|
388
|
+
if (error) {
|
|
389
|
+
logger_1.default.error('Failed to get enabled database tools:', error);
|
|
390
|
+
throw new Error(`Failed to get enabled tools: ${error.message}`);
|
|
391
|
+
}
|
|
392
|
+
// Parse columns JSONB field
|
|
393
|
+
return (data || []).map(tool => ({
|
|
394
|
+
...tool,
|
|
395
|
+
columns: typeof tool.columns === 'string' ? JSON.parse(tool.columns) : tool.columns
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Update a tool
|
|
400
|
+
*/
|
|
401
|
+
async updateTool(toolId, updates) {
|
|
402
|
+
const updateData = { ...updates, updated_at: new Date().toISOString() };
|
|
403
|
+
if (updates.columns) {
|
|
404
|
+
// Ensure columns is an array before stringifying
|
|
405
|
+
const columnsArray = Array.isArray(updates.columns) ? updates.columns :
|
|
406
|
+
(typeof updates.columns === 'string' ? JSON.parse(updates.columns) : updates.columns);
|
|
407
|
+
updateData.columns = JSON.stringify(columnsArray);
|
|
408
|
+
}
|
|
409
|
+
const { data, error } = await this.supabase
|
|
410
|
+
.from('vezlo_database_tools')
|
|
411
|
+
.update(updateData)
|
|
412
|
+
.eq('id', toolId)
|
|
413
|
+
.select()
|
|
414
|
+
.single();
|
|
415
|
+
if (error) {
|
|
416
|
+
logger_1.default.error('Failed to update database tool:', error);
|
|
417
|
+
throw new Error(`Failed to update tool: ${error.message}`);
|
|
418
|
+
}
|
|
419
|
+
logger_1.default.info(`✅ Updated tool ${toolId}`);
|
|
420
|
+
// Parse columns before returning
|
|
421
|
+
return {
|
|
422
|
+
...data,
|
|
423
|
+
columns: typeof data.columns === 'string' ? JSON.parse(data.columns) : data.columns
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Delete a tool
|
|
428
|
+
*/
|
|
429
|
+
async deleteTool(toolId) {
|
|
430
|
+
const { error } = await this.supabase
|
|
431
|
+
.from('vezlo_database_tools')
|
|
432
|
+
.delete()
|
|
433
|
+
.eq('id', toolId);
|
|
434
|
+
if (error) {
|
|
435
|
+
logger_1.default.error('Failed to delete database tool:', error);
|
|
436
|
+
throw new Error(`Failed to delete tool: ${error.message}`);
|
|
437
|
+
}
|
|
438
|
+
logger_1.default.info(`✅ Deleted tool ${toolId}`);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
exports.DatabaseToolConfigService = DatabaseToolConfigService;
|
|
442
|
+
//# sourceMappingURL=DatabaseToolConfigService.js.map
|