outlet-orm 6.5.0 → 9.0.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.
Files changed (58) hide show
  1. package/README.md +130 -2
  2. package/bin/init.js +122 -0
  3. package/bin/mcp.js +78 -0
  4. package/bin/migrate.js +25 -0
  5. package/docs/skills/outlet-orm/ADVANCED.md +575 -0
  6. package/docs/skills/outlet-orm/AI.md +220 -0
  7. package/docs/skills/outlet-orm/API.md +522 -0
  8. package/docs/skills/outlet-orm/BACKUP.md +150 -0
  9. package/docs/skills/outlet-orm/MIGRATIONS.md +605 -0
  10. package/docs/skills/outlet-orm/MODELS.md +427 -0
  11. package/docs/skills/outlet-orm/QUERIES.md +345 -0
  12. package/docs/skills/outlet-orm/RELATIONS.md +555 -0
  13. package/docs/skills/outlet-orm/SECURITY.md +386 -0
  14. package/docs/skills/outlet-orm/SEEDS.md +98 -0
  15. package/docs/skills/outlet-orm/SKILL.md +205 -0
  16. package/docs/skills/outlet-orm/TYPESCRIPT.md +480 -0
  17. package/package.json +7 -3
  18. package/src/AI/AIPromptEnhancer.js +170 -0
  19. package/src/AI/AIQueryBuilder.js +234 -0
  20. package/src/AI/AIQueryOptimizer.js +185 -0
  21. package/src/AI/AISafetyGuardrails.js +146 -0
  22. package/src/AI/AISeeder.js +181 -0
  23. package/src/AI/AiBridgeManager.js +287 -0
  24. package/src/AI/Builders/TextBuilder.js +170 -0
  25. package/src/AI/Contracts/AudioProviderContract.js +29 -0
  26. package/src/AI/Contracts/ChatProviderContract.js +38 -0
  27. package/src/AI/Contracts/EmbeddingsProviderContract.js +19 -0
  28. package/src/AI/Contracts/ImageProviderContract.js +19 -0
  29. package/src/AI/Contracts/ModelsProviderContract.js +26 -0
  30. package/src/AI/Contracts/ToolContract.js +25 -0
  31. package/src/AI/Facades/AiBridge.js +79 -0
  32. package/src/AI/MCPServer.js +798 -0
  33. package/src/AI/PromptGenerator.js +318 -0
  34. package/src/AI/Providers/ClaudeProvider.js +64 -0
  35. package/src/AI/Providers/CustomOpenAIProvider.js +238 -0
  36. package/src/AI/Providers/GeminiProvider.js +68 -0
  37. package/src/AI/Providers/GrokProvider.js +46 -0
  38. package/src/AI/Providers/MistralProvider.js +21 -0
  39. package/src/AI/Providers/OllamaProvider.js +249 -0
  40. package/src/AI/Providers/OllamaTurboProvider.js +32 -0
  41. package/src/AI/Providers/OnnProvider.js +46 -0
  42. package/src/AI/Providers/OpenAIProvider.js +471 -0
  43. package/src/AI/Support/AudioNormalizer.js +37 -0
  44. package/src/AI/Support/ChatNormalizer.js +42 -0
  45. package/src/AI/Support/Document.js +77 -0
  46. package/src/AI/Support/DocumentAttachmentMapper.js +101 -0
  47. package/src/AI/Support/EmbeddingsNormalizer.js +30 -0
  48. package/src/AI/Support/Exceptions/ProviderError.js +22 -0
  49. package/src/AI/Support/FileSecurity.js +56 -0
  50. package/src/AI/Support/ImageNormalizer.js +62 -0
  51. package/src/AI/Support/JsonSchemaValidator.js +73 -0
  52. package/src/AI/Support/Message.js +40 -0
  53. package/src/AI/Support/StreamChunk.js +45 -0
  54. package/src/AI/Support/ToolChatRunner.js +160 -0
  55. package/src/AI/Support/ToolRegistry.js +62 -0
  56. package/src/AI/Tools/SystemInfoTool.js +25 -0
  57. package/src/index.js +77 -1
  58. package/types/index.d.ts +432 -0
package/README.md CHANGED
@@ -197,7 +197,14 @@ async store(req, res) {
197
197
  - **Raw queries**: `executeRawQuery()` and `execute()` (native driver results)
198
198
  - **Complete Migrations** (create/alter/drop, index, foreign keys, batch tracking)
199
199
  - **Database Backup** (v6.0.0): full/partial/journal backups, recurring scheduler, AES-256-GCM encryption, TCP daemon + remote client, automatic restore
200
- - **Handy CLI tools**: `outlet-init`, `outlet-migrate`, `outlet-convert`
200
+ - **šŸ¤– AiBridge** (v8.0.0): Multi-provider LLM abstraction — chat, stream, embeddings, images, TTS, STT with 9+ providers
201
+ - **šŸ¤– AI Query Builder** (v8.0.0): Natural language → SQL with schema introspection
202
+ - **šŸ¤– AI Seeder** (v8.0.0): LLM-powered realistic, domain-specific data generation
203
+ - **šŸ¤– AI Query Optimizer** (v8.0.0): SQL analysis, optimization, and index recommendations
204
+ - **šŸ¤– AI Prompt Enhancer** (v8.0.0): Schema/model/migration generation from natural language
205
+ - **šŸ¤– MCP Server** (v7.0.0): Model Context Protocol for AI agent integration (13 tools)
206
+ - **šŸ¤– AI Safety Guardrails** (v7.0.0): Automatic AI agent detection + destructive operation protection
207
+ - **Handy CLI tools**: `outlet-init`, `outlet-migrate`, `outlet-convert`, `outlet-mcp`
201
208
  - **`.env` configuration** (loaded automatically)
202
209
  - **Multi-database**: MySQL, PostgreSQL, and SQLite
203
210
  - **Complete TypeScript types** with Generic Model and typed Schema Builder (v4.0.0+)
@@ -1220,6 +1227,126 @@ outlet-convert
1220
1227
  - āœ… Automatic timestamps support
1221
1228
  - āœ… Class names converted to PascalCase
1222
1229
 
1230
+ ## šŸ¤– AI Integration
1231
+
1232
+ Outlet ORM includes a complete AI subsystem with multi-provider LLM support and ORM-specific AI features.
1233
+
1234
+ šŸ“š **[Complete AI documentation available in `/docs`](./docs/AI_BRIDGE.md)**
1235
+
1236
+ ### AiBridge — Multi-Provider LLM Abstraction
1237
+
1238
+ ```javascript
1239
+ const { AiBridgeManager } = require('outlet-orm');
1240
+
1241
+ const ai = new AiBridgeManager({
1242
+ providers: {
1243
+ openai: { api_key: process.env.OPENAI_API_KEY, model: 'gpt-4o' },
1244
+ claude: { api_key: process.env.ANTHROPIC_API_KEY, model: 'claude-sonnet-4-20250514' },
1245
+ ollama: { endpoint: 'http://localhost:11434', model: 'llama3' }
1246
+ }
1247
+ });
1248
+
1249
+ // Chat with any provider
1250
+ const response = await ai.chat('openai', [
1251
+ { role: 'user', content: 'What is Node.js?' }
1252
+ ]);
1253
+
1254
+ // Fluent TextBuilder
1255
+ const { text } = await ai.text()
1256
+ .using('openai', 'gpt-4o')
1257
+ .withSystemPrompt('You are a helpful assistant.')
1258
+ .withPrompt('Explain closures in JavaScript.')
1259
+ .asText();
1260
+
1261
+ // Stream responses
1262
+ for await (const chunk of ai.stream('claude', messages)) {
1263
+ process.stdout.write(chunk.text || '');
1264
+ }
1265
+
1266
+ // Embeddings, images, TTS, STT
1267
+ const embeddings = await ai.embeddings('openai', ['Hello world']);
1268
+ const image = await ai.image('openai', 'A sunset over mountains');
1269
+ ```
1270
+
1271
+ **Supported providers**: OpenAI, Claude, Gemini, Ollama, Grok, Mistral, ONN, Custom OpenAI, OpenRouter
1272
+
1273
+ ### AI Query Builder — Natural Language → SQL
1274
+
1275
+ ```javascript
1276
+ const { AIQueryBuilder } = require('outlet-orm');
1277
+
1278
+ const qb = new AIQueryBuilder(ai, db);
1279
+
1280
+ // Ask in natural language, get SQL + results
1281
+ const result = await qb.query('How many users signed up last month?');
1282
+ console.log(result.sql); // SELECT COUNT(*) FROM users WHERE ...
1283
+ console.log(result.results); // [{ count: 42 }]
1284
+
1285
+ // Generate SQL without executing
1286
+ const { sql } = await qb.toSql('Show me the top 5 users by post count');
1287
+ ```
1288
+
1289
+ ### AI Seeder — Realistic Data Generation
1290
+
1291
+ ```javascript
1292
+ const { AISeeder } = require('outlet-orm');
1293
+
1294
+ const seeder = new AISeeder(ai, db);
1295
+
1296
+ // Generate and insert realistic data
1297
+ await seeder.seed('products', 20, {
1298
+ domain: 'e-commerce',
1299
+ locale: 'fr_FR',
1300
+ description: 'Fashion store for young adults'
1301
+ });
1302
+ ```
1303
+
1304
+ ### AI Query Optimizer
1305
+
1306
+ ```javascript
1307
+ const { AIQueryOptimizer } = require('outlet-orm');
1308
+
1309
+ const optimizer = new AIQueryOptimizer(ai, db);
1310
+ const result = await optimizer.optimize(
1311
+ 'SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE status = "active")'
1312
+ );
1313
+
1314
+ console.log(result.optimized); // Rewritten SQL
1315
+ console.log(result.suggestions); // [{ type: 'index', impact: 'high', ... }]
1316
+ console.log(result.indexes); // ['CREATE INDEX idx_...']
1317
+ ```
1318
+
1319
+ ### MCP Server — AI Agent Integration
1320
+
1321
+ ```bash
1322
+ # Start MCP server for AI editors
1323
+ npx outlet-mcp
1324
+ ```
1325
+
1326
+ Configure your AI editor:
1327
+
1328
+ ```json
1329
+ {
1330
+ "mcpServers": {
1331
+ "outlet-orm": {
1332
+ "command": "npx",
1333
+ "args": ["outlet-mcp"]
1334
+ }
1335
+ }
1336
+ }
1337
+ ```
1338
+
1339
+ **13 MCP tools**: migrations, schema introspection, queries, seeds, backups, AI query, query optimization
1340
+
1341
+ šŸ“– Full documentation:
1342
+ - [AiBridge Manager](docs/AI_BRIDGE.md) — Multi-provider LLM abstraction
1343
+ - [AI Query Builder](docs/AI_QUERY.md) — Natural language to SQL
1344
+ - [AI Seeder](docs/AI_SEEDER.md) — Realistic data generation
1345
+ - [AI Query Optimizer](docs/AI_OPTIMIZER.md) — SQL optimization
1346
+ - [AI Prompt Enhancer](docs/AI_PROMPT.md) — Schema/code generation
1347
+ - [MCP Server](docs/MCP.md) — AI agent integration
1348
+ - [AI Safety Guardrails](docs/AI_SAFETY.md) — Destructive operation protection
1349
+
1223
1350
  ## šŸ“š Documentation
1224
1351
 
1225
1352
  - [Migrations Guide](docs/MIGRATIONS.md)
@@ -1227,7 +1354,8 @@ outlet-convert
1227
1354
  - [Relation Detection](docs/RELATIONS_DETECTION.md)
1228
1355
  - [Quick Start Guide](docs/QUICKSTART.md)
1229
1356
  - [Architecture](docs/ARCHITECTURE.md)
1230
- - [**TypeScript (complet)**](docs/TYPESCRIPT.md)
1357
+ - [**TypeScript (complete)**](docs/TYPESCRIPT.md)
1358
+ - [**AI Integration (complete)**](docs/AI_BRIDGE.md)
1231
1359
 
1232
1360
  ## šŸ“˜ TypeScript Support
1233
1361
 
package/bin/init.js CHANGED
@@ -16,7 +16,129 @@ const rl = readline.createInterface({
16
16
 
17
17
  const question = (query) => new Promise((resolve) => rl.question(query, resolve));
18
18
 
19
+ // ─── Parse CLI flags ─────────────────────────────────────────────
20
+
21
+ function parseInitFlags(argv) {
22
+ const flags = {};
23
+ for (let i = 0; i < argv.length; i++) {
24
+ const arg = argv[i];
25
+ if (arg === '--prompt' || arg === '-P') {
26
+ flags.prompt = argv[++i];
27
+ } else if (arg === '--driver' || arg === '-d') {
28
+ flags.driver = argv[++i];
29
+ }
30
+ }
31
+ return flags;
32
+ }
33
+
34
+ // ─── Prompt-based init (v7.0.0) ─────────────────────────────────
35
+
36
+ async function initFromPrompt(promptText, driverName) {
37
+ const PromptGenerator = require('../src/AI/PromptGenerator');
38
+
39
+ console.log('\nšŸ¤– Outlet ORM — Prompt-based Initialization\n');
40
+ console.log(` Prompt: "${promptText}"`);
41
+
42
+ const blueprint = PromptGenerator.parse(promptText);
43
+ console.log(` Domain detected: ${blueprint.domain} (score: ${blueprint.score})`);
44
+ console.log(` Tables: ${Object.keys(blueprint.tables).join(', ')}\n`);
45
+
46
+ // Determine the driver
47
+ const driver = driverName || 'sqlite';
48
+ const driverConfig = {
49
+ mysql: { package: 'mysql2', port: 3306 },
50
+ postgres: { package: 'pg', port: 5432 },
51
+ sqlite: { package: 'sqlite3', port: null }
52
+ };
53
+
54
+ if (!driverConfig[driver]) {
55
+ console.error(`āŒ Unknown driver: ${driver}. Use mysql, postgres, or sqlite.`);
56
+ process.exit(1);
57
+ }
58
+
59
+ const cwd = process.cwd();
60
+
61
+ // Create directory structure
62
+ const directories = ['database/migrations', 'database/seeds', 'models', 'config'];
63
+ for (const dir of directories) {
64
+ const dirPath = path.join(cwd, dir);
65
+ if (!fs.existsSync(dirPath)) {
66
+ fs.mkdirSync(dirPath, { recursive: true });
67
+ console.log(` šŸ“ ${dir}/`);
68
+ }
69
+ }
70
+
71
+ // Generate database config
72
+ let config;
73
+ if (driver === 'sqlite') {
74
+ config = { driver: 'sqlite', database: './database.sqlite' };
75
+ } else {
76
+ config = {
77
+ driver,
78
+ host: 'localhost',
79
+ port: driverConfig[driver].port,
80
+ database: 'my_app',
81
+ user: 'root',
82
+ password: ''
83
+ };
84
+ }
85
+
86
+ const configContent = `const { DatabaseConnection } = require('outlet-orm');\n\nconst db = new DatabaseConnection(${JSON.stringify(config, null, 2)});\n\nmodule.exports = db;\n`;
87
+ const configPath = path.join(cwd, 'database', 'config.js');
88
+ if (!fs.existsSync(configPath)) {
89
+ fs.writeFileSync(configPath, configContent);
90
+ console.log(' āœ… database/config.js');
91
+ }
92
+
93
+ // Generate .env
94
+ const envPath = path.join(cwd, '.env');
95
+ if (!fs.existsSync(envPath)) {
96
+ const envLines = [`DB_DRIVER=${config.driver}`];
97
+ if (driver !== 'sqlite') {
98
+ envLines.push(`DB_HOST=${config.host}`, `DB_PORT=${config.port}`, `DB_USER=${config.user}`, `DB_PASSWORD=${config.password}`, `DB_DATABASE=${config.database}`);
99
+ } else {
100
+ envLines.push(`DB_FILE=${config.database}`);
101
+ }
102
+ fs.writeFileSync(envPath, envLines.join('\n') + '\n');
103
+ console.log(' āœ… .env');
104
+ }
105
+
106
+ // Generate models
107
+ console.log('\nšŸ“Š Generating models...');
108
+ const modelFiles = PromptGenerator.generateModels(blueprint, path.join(cwd, 'models'));
109
+ for (const f of modelFiles) {
110
+ console.log(` āœ… ${path.relative(cwd, f)}`);
111
+ }
112
+
113
+ // Generate migrations
114
+ console.log('\nšŸ“¦ Generating migrations...');
115
+ const migrationFiles = PromptGenerator.generateMigrations(blueprint, path.join(cwd, 'database', 'migrations'));
116
+ for (const f of migrationFiles) {
117
+ console.log(` āœ… ${path.relative(cwd, f)}`);
118
+ }
119
+
120
+ // Generate seeder
121
+ console.log('\n🌱 Generating seeder...');
122
+ const seederFile = PromptGenerator.generateSeeder(blueprint, path.join(cwd, 'database', 'seeds'));
123
+ console.log(` āœ… ${path.relative(cwd, seederFile)}`);
124
+
125
+ console.log('\n✨ Project generated from prompt!\n');
126
+ console.log('Next steps:');
127
+ console.log(' 1. Review generated models in models/');
128
+ console.log(' 2. Review migrations in database/migrations/');
129
+ console.log(' 3. Run migrations: outlet-migrate migrate');
130
+ console.log(` 4. Install driver: npm install ${driverConfig[driver].package}`);
131
+ }
132
+
19
133
  async function init() {
134
+ // Check for --prompt flag
135
+ const flags = parseInitFlags(process.argv.slice(2));
136
+ if (flags.prompt) {
137
+ await initFromPrompt(flags.prompt, flags.driver);
138
+ rl.close();
139
+ return;
140
+ }
141
+
20
142
  console.log('\nšŸš€ Bienvenue dans l\'assistant de configuration Outlet ORM!\n');
21
143
 
22
144
  try {
package/bin/mcp.js ADDED
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * outlet-mcp — MCP Server CLI entry point
5
+ * Starts the Outlet ORM MCP server on stdio for AI agent integration.
6
+ *
7
+ * Usage:
8
+ * npx outlet-mcp # Start the MCP server
9
+ * npx outlet-mcp --project /path # Start with custom project directory
10
+ * npx outlet-mcp --no-safety # Disable AI safety guardrails
11
+ *
12
+ * @since 7.0.0
13
+ */
14
+
15
+ const MCPServer = require('../src/AI/MCPServer');
16
+
17
+ // ─── Parse CLI flags ─────────────────────────────────────────────
18
+
19
+ const args = process.argv.slice(2);
20
+ const options = {};
21
+
22
+ for (let i = 0; i < args.length; i++) {
23
+ const arg = args[i];
24
+ if (arg === '--project' || arg === '-p') {
25
+ options.projectDir = args[++i];
26
+ } else if (arg === '--no-safety') {
27
+ options.safetyGuardrails = false;
28
+ } else if (arg === '--help' || arg === '-h') {
29
+ console.error(`
30
+ outlet-mcp — Outlet ORM MCP Server
31
+
32
+ Usage:
33
+ outlet-mcp [options]
34
+
35
+ Options:
36
+ --project, -p <path> Project root directory (default: cwd)
37
+ --no-safety Disable AI safety guardrails
38
+ --help, -h Show this help message
39
+
40
+ The server communicates over stdio using the Model Context Protocol (MCP).
41
+ It exposes tools for migrations, schema introspection, queries, seeds, and backups.
42
+
43
+ Documentation: https://github.com/omgbwa-yasse/outlet-orm/blob/main/docs/MCP.md
44
+ `);
45
+ process.exit(0);
46
+ }
47
+ }
48
+
49
+ // ─── Start ───────────────────────────────────────────────────────
50
+
51
+ const server = new MCPServer(options);
52
+
53
+ server.on('started', () => {
54
+ process.stderr.write('[outlet-mcp] MCP server started on stdio\n');
55
+ });
56
+
57
+ server.on('initialized', () => {
58
+ process.stderr.write('[outlet-mcp] Client connected and initialized\n');
59
+ });
60
+
61
+ server.on('close', async () => {
62
+ process.stderr.write('[outlet-mcp] Shutting down...\n');
63
+ await server.close();
64
+ process.exit(0);
65
+ });
66
+
67
+ // Graceful shutdown
68
+ process.on('SIGINT', async () => {
69
+ await server.close();
70
+ process.exit(0);
71
+ });
72
+
73
+ process.on('SIGTERM', async () => {
74
+ await server.close();
75
+ process.exit(0);
76
+ });
77
+
78
+ server.start();
package/bin/migrate.js CHANGED
@@ -8,6 +8,7 @@
8
8
  const readline = require('readline');
9
9
  const fs = require('fs').promises;
10
10
  const path = require('path');
11
+ const AISafetyGuardrails = require('../src/AI/AISafetyGuardrails');
11
12
 
12
13
  const rl = readline.createInterface({
13
14
  input: process.stdin,
@@ -367,6 +368,14 @@ async function runNonInteractive(cmd, flags) {
367
368
  }
368
369
 
369
370
  case 'reset': {
371
+ // AI Safety Guardrails check (v7.0.0)
372
+ if (AISafetyGuardrails.isDestructiveCommand('reset')) {
373
+ const check = AISafetyGuardrails.validateDestructiveAction('reset', flags);
374
+ if (!check.allowed) {
375
+ console.error(check.message);
376
+ return;
377
+ }
378
+ }
370
379
  if (flags.yes || flags.force) {
371
380
  await manager.reset();
372
381
  } else {
@@ -376,6 +385,14 @@ async function runNonInteractive(cmd, flags) {
376
385
  }
377
386
 
378
387
  case 'refresh': {
388
+ // AI Safety Guardrails check (v7.0.0)
389
+ if (AISafetyGuardrails.isDestructiveCommand('fresh')) {
390
+ const check = AISafetyGuardrails.validateDestructiveAction('refresh', flags);
391
+ if (!check.allowed) {
392
+ console.error(check.message);
393
+ return;
394
+ }
395
+ }
379
396
  if (flags.yes || flags.force) {
380
397
  await manager.refresh();
381
398
  } else {
@@ -385,6 +402,14 @@ async function runNonInteractive(cmd, flags) {
385
402
  }
386
403
 
387
404
  case 'fresh': {
405
+ // AI Safety Guardrails check (v7.0.0)
406
+ if (AISafetyGuardrails.isDestructiveCommand('fresh')) {
407
+ const check = AISafetyGuardrails.validateDestructiveAction('fresh', flags);
408
+ if (!check.allowed) {
409
+ console.error(check.message);
410
+ return;
411
+ }
412
+ }
388
413
  if (flags.yes || flags.force) {
389
414
  await manager.fresh();
390
415
  } else {