navis.js 5.4.1 → 5.5.1

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 CHANGED
@@ -171,20 +171,25 @@ navis metrics
171
171
 
172
172
  - ✅ **WebSocket support** - Real-time bidirectional communication
173
173
  - ✅ **Server-Sent Events** - One-way real-time streaming
174
- - ✅ **Database integration** - Connection pooling for PostgreSQL, MySQL, MongoDB
174
+ - ✅ **Database integration** - Connection pooling for PostgreSQL, MySQL, MongoDB, SQLite, SQL Server
175
175
 
176
176
  ### v5.3 ✅
177
177
  - ✅ **TypeScript support** - Full type definitions for all features
178
178
  - ✅ **Type-safe API** - Complete IntelliSense and type checking
179
179
  - ✅ **TypeScript examples** - Ready-to-use TypeScript examples
180
180
 
181
- ### v5.4 (Current)
181
+ ### v5.4
182
182
  - ✅ **GraphQL support** - Lightweight GraphQL server implementation
183
183
  - ✅ **GraphQL queries & mutations** - Full query and mutation support
184
184
  - ✅ **GraphQL resolvers** - Flexible resolver system with utilities
185
185
  - ✅ **GraphQL schema builder** - Schema definition helpers
186
186
  - ✅ **GraphQL middleware** - Easy integration with Navis.js routes
187
187
 
188
+ ### v5.5 (Current)
189
+ - ✅ **Extended database adapters** - SQLite and SQL Server support
190
+ - ✅ **Enhanced database pool** - Support for 5 database types (PostgreSQL, MySQL, MongoDB, SQLite, SQL Server)
191
+ - ✅ **Improved connection handling** - Better error handling and connection management
192
+
188
193
  ## API Reference
189
194
 
190
195
  ### NavisApp
@@ -545,6 +550,73 @@ curl -X POST http://localhost:3000/graphql \
545
550
 
546
551
  See `examples/graphql-demo.js` for a complete GraphQL example.
547
552
 
553
+ ### Extended Database Adapters (v5.5)
554
+
555
+ **JavaScript Example:**
556
+ ```javascript
557
+ const { NavisApp, createPool, response } = require('navis.js');
558
+
559
+ const app = new NavisApp();
560
+
561
+ // SQLite Database
562
+ app.get('/sqlite/users', async (req, res) => {
563
+ const db = createPool({
564
+ type: 'sqlite',
565
+ connectionString: ':memory:', // or path to .db file
566
+ });
567
+
568
+ await db.connect();
569
+ const users = await db.query('SELECT * FROM users');
570
+ await db.close();
571
+
572
+ response.success(res, { users });
573
+ });
574
+
575
+ // SQL Server Database
576
+ app.get('/sqlserver/users', async (req, res) => {
577
+ const db = createPool({
578
+ type: 'mssql',
579
+ connectionString: 'Server=localhost;Database=testdb;User Id=sa;Password=pass',
580
+ });
581
+
582
+ await db.connect();
583
+ const users = await db.query('SELECT TOP 10 * FROM users');
584
+ await db.close();
585
+
586
+ response.success(res, { users });
587
+ });
588
+ ```
589
+
590
+ **TypeScript Example:**
591
+ ```typescript
592
+ import { NavisApp, createPool, response, DatabasePool } from 'navis.js';
593
+
594
+ const app = new NavisApp();
595
+
596
+ // SQLite with TypeScript
597
+ app.get('/sqlite/users', async (req, res) => {
598
+ const db: DatabasePool = createPool({
599
+ type: 'sqlite',
600
+ connectionString: ':memory:',
601
+ });
602
+
603
+ await db.connect();
604
+ const users = await db.query('SELECT * FROM users') as User[];
605
+ await db.close();
606
+
607
+ response.success(res, { users });
608
+ });
609
+ ```
610
+
611
+ **Supported Databases:**
612
+ - ✅ PostgreSQL (`postgres` or `postgresql`)
613
+ - ✅ MySQL/MariaDB (`mysql` or `mariadb`)
614
+ - ✅ MongoDB (`mongodb`)
615
+ - ✅ SQLite (`sqlite` or `sqlite3`) - **NEW in v5.5**
616
+ - ✅ SQL Server (`mssql` or `sqlserver`) - **NEW in v5.5**
617
+
618
+ See `examples/database-adapters-demo.js` and `examples/database-adapters-demo.ts` for complete examples.
619
+
548
620
  ## Examples
549
621
 
550
622
  See the `examples/` directory:
@@ -563,6 +635,8 @@ See the `examples/` directory:
563
635
  - `v5.2-features-demo.js` - v5.2 features demonstration (WebSocket, SSE, database)
564
636
  - `graphql-demo.js` - GraphQL server example with queries and mutations (v5.4) - JavaScript
565
637
  - `graphql-demo.ts` - GraphQL server example with TypeScript types (v5.4) - TypeScript
638
+ - `database-adapters-demo.js` - Extended database adapters example (v5.5) - JavaScript
639
+ - `database-adapters-demo.ts` - Extended database adapters example (v5.5) - TypeScript
566
640
  - `service-client-demo.js` - ServiceClient usage example
567
641
 
568
642
  ## Roadmap
@@ -591,15 +665,18 @@ Real-time features: WebSocket, Server-Sent Events, database integration
591
665
  ### v5.3 ✅
592
666
  TypeScript support: Full type definitions, type-safe API, IntelliSense
593
667
 
594
- ### v5.4 ✅ (Current)
668
+ ### v5.4 ✅
595
669
  GraphQL support: Lightweight GraphQL server, queries, mutations, resolvers, schema builder
596
670
 
671
+ ### v5.5 ✅ (Current)
672
+ Extended database adapters: SQLite and SQL Server support, enhanced connection pooling
673
+
597
674
  ## What's Next?
598
675
 
599
676
  Future versions may include:
600
677
  - gRPC integration
601
678
  - Advanced caching strategies
602
- - More database adapters
679
+ - Advanced query builders
603
680
  - Enhanced monitoring and alerting
604
681
 
605
682
  ## Documentation
@@ -0,0 +1,138 @@
1
+ /**
2
+ * Database Adapters Demo - Navis.js
3
+ * Demonstrates extended database adapter support (SQLite, SQL Server)
4
+ */
5
+
6
+ const { NavisApp, createPool, response } = require('../src/index');
7
+
8
+ const app = new NavisApp();
9
+
10
+ // Example: SQLite Database
11
+ app.get('/sqlite/users', async (req, res) => {
12
+ try {
13
+ const db = createPool({
14
+ type: 'sqlite',
15
+ connectionString: ':memory:', // In-memory database for demo
16
+ });
17
+
18
+ await db.connect();
19
+
20
+ // Create table (if not exists)
21
+ await db.query(`
22
+ CREATE TABLE IF NOT EXISTS users (
23
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
24
+ name TEXT NOT NULL,
25
+ email TEXT NOT NULL
26
+ )
27
+ `);
28
+
29
+ // Insert sample data
30
+ await db.query('INSERT INTO users (name, email) VALUES (?, ?)', ['Alice', 'alice@example.com']);
31
+ await db.query('INSERT INTO users (name, email) VALUES (?, ?)', ['Bob', 'bob@example.com']);
32
+
33
+ // Query users
34
+ const users = await db.query('SELECT * FROM users');
35
+
36
+ await db.close();
37
+
38
+ response.success(res, {
39
+ database: 'SQLite',
40
+ users,
41
+ });
42
+ } catch (error) {
43
+ response.error(res, `SQLite error: ${error.message}`, 500);
44
+ }
45
+ });
46
+
47
+ // Example: SQL Server Database
48
+ app.get('/sqlserver/users', async (req, res) => {
49
+ try {
50
+ const db = createPool({
51
+ type: 'mssql',
52
+ connectionString: process.env.SQL_SERVER_CONNECTION_STRING || 'Server=localhost;Database=testdb;User Id=sa;Password=YourPassword123',
53
+ });
54
+
55
+ await db.connect();
56
+
57
+ // Query users (assuming table exists)
58
+ const users = await db.query('SELECT TOP 10 * FROM users');
59
+
60
+ await db.close();
61
+
62
+ response.success(res, {
63
+ database: 'SQL Server',
64
+ users,
65
+ });
66
+ } catch (error) {
67
+ response.error(res, `SQL Server error: ${error.message}`, 500);
68
+ }
69
+ });
70
+
71
+ // Example: PostgreSQL (existing)
72
+ app.get('/postgres/users', async (req, res) => {
73
+ try {
74
+ const db = createPool({
75
+ type: 'postgres',
76
+ connectionString: process.env.DATABASE_URL || 'postgresql://user:password@localhost:5432/mydb',
77
+ });
78
+
79
+ await db.connect();
80
+ const users = await db.query('SELECT * FROM users LIMIT 10');
81
+ await db.close();
82
+
83
+ response.success(res, {
84
+ database: 'PostgreSQL',
85
+ users,
86
+ });
87
+ } catch (error) {
88
+ response.error(res, `PostgreSQL error: ${error.message}`, 500);
89
+ }
90
+ });
91
+
92
+ // Example: MySQL (existing)
93
+ app.get('/mysql/users', async (req, res) => {
94
+ try {
95
+ const db = createPool({
96
+ type: 'mysql',
97
+ connectionString: process.env.MYSQL_URL || 'mysql://user:password@localhost:3306/mydb',
98
+ });
99
+
100
+ await db.connect();
101
+ const users = await db.query('SELECT * FROM users LIMIT 10');
102
+ await db.close();
103
+
104
+ response.success(res, {
105
+ database: 'MySQL',
106
+ users,
107
+ });
108
+ } catch (error) {
109
+ response.error(res, `MySQL error: ${error.message}`, 500);
110
+ }
111
+ });
112
+
113
+ // Health check
114
+ app.get('/health', (req, res) => {
115
+ response.success(res, {
116
+ status: 'ok',
117
+ databases: ['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite', 'SQL Server'],
118
+ });
119
+ });
120
+
121
+ // Start server
122
+ const PORT = process.env.PORT || 3000;
123
+ app.listen(PORT, () => {
124
+ console.log(`🚀 Navis.js Database Adapters Demo running on http://localhost:${PORT}`);
125
+ console.log('\n📊 Available endpoints:');
126
+ console.log(` GET http://localhost:${PORT}/sqlite/users - SQLite example`);
127
+ console.log(` GET http://localhost:${PORT}/sqlserver/users - SQL Server example`);
128
+ console.log(` GET http://localhost:${PORT}/postgres/users - PostgreSQL example`);
129
+ console.log(` GET http://localhost:${PORT}/mysql/users - MySQL example`);
130
+ console.log(` GET http://localhost:${PORT}/health - Health check`);
131
+ console.log('\n💡 Note: Make sure to install the required database drivers:');
132
+ console.log(' - SQLite: npm install better-sqlite3 (or sqlite3 sqlite)');
133
+ console.log(' - SQL Server: npm install mssql');
134
+ console.log(' - PostgreSQL: npm install pg');
135
+ console.log(' - MySQL: npm install mysql2');
136
+ console.log(' - MongoDB: npm install mongodb');
137
+ });
138
+
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Database Adapters Demo - Navis.js (TypeScript)
3
+ * Demonstrates extended database adapter support with TypeScript types
4
+ */
5
+
6
+ import { NavisApp, createPool, response, DatabasePool } from '../src/index';
7
+
8
+ const app = new NavisApp();
9
+
10
+ interface User {
11
+ id: number;
12
+ name: string;
13
+ email: string;
14
+ }
15
+
16
+ // Example: SQLite Database
17
+ app.get('/sqlite/users', async (req, res) => {
18
+ try {
19
+ const db: DatabasePool = createPool({
20
+ type: 'sqlite',
21
+ connectionString: ':memory:', // In-memory database for demo
22
+ });
23
+
24
+ await db.connect();
25
+
26
+ // Create table (if not exists)
27
+ await db.query(`
28
+ CREATE TABLE IF NOT EXISTS users (
29
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
30
+ name TEXT NOT NULL,
31
+ email TEXT NOT NULL
32
+ )
33
+ `);
34
+
35
+ // Insert sample data
36
+ await db.query('INSERT INTO users (name, email) VALUES (?, ?)', ['Alice', 'alice@example.com']);
37
+ await db.query('INSERT INTO users (name, email) VALUES (?, ?)', ['Bob', 'bob@example.com']);
38
+
39
+ // Query users
40
+ const users = await db.query('SELECT * FROM users') as User[];
41
+
42
+ await db.close();
43
+
44
+ response.success(res, {
45
+ database: 'SQLite',
46
+ users,
47
+ });
48
+ } catch (error) {
49
+ response.error(res, `SQLite error: ${(error as Error).message}`, 500);
50
+ }
51
+ });
52
+
53
+ // Example: SQL Server Database
54
+ app.get('/sqlserver/users', async (req, res) => {
55
+ try {
56
+ const db: DatabasePool = createPool({
57
+ type: 'mssql',
58
+ connectionString: process.env.SQL_SERVER_CONNECTION_STRING || 'Server=localhost;Database=testdb;User Id=sa;Password=YourPassword123',
59
+ });
60
+
61
+ await db.connect();
62
+
63
+ // Query users (assuming table exists)
64
+ const users = await db.query('SELECT TOP 10 * FROM users') as User[];
65
+
66
+ await db.close();
67
+
68
+ response.success(res, {
69
+ database: 'SQL Server',
70
+ users,
71
+ });
72
+ } catch (error) {
73
+ response.error(res, `SQL Server error: ${(error as Error).message}`, 500);
74
+ }
75
+ });
76
+
77
+ // Example: PostgreSQL (existing)
78
+ app.get('/postgres/users', async (req, res) => {
79
+ try {
80
+ const db: DatabasePool = createPool({
81
+ type: 'postgres',
82
+ connectionString: process.env.DATABASE_URL || 'postgresql://user:password@localhost:5432/mydb',
83
+ });
84
+
85
+ await db.connect();
86
+ const users = await db.query('SELECT * FROM users LIMIT 10') as User[];
87
+ await db.close();
88
+
89
+ response.success(res, {
90
+ database: 'PostgreSQL',
91
+ users,
92
+ });
93
+ } catch (error) {
94
+ response.error(res, `PostgreSQL error: ${(error as Error).message}`, 500);
95
+ }
96
+ });
97
+
98
+ // Example: MySQL (existing)
99
+ app.get('/mysql/users', async (req, res) => {
100
+ try {
101
+ const db: DatabasePool = createPool({
102
+ type: 'mysql',
103
+ connectionString: process.env.MYSQL_URL || 'mysql://user:password@localhost:3306/mydb',
104
+ });
105
+
106
+ await db.connect();
107
+ const users = await db.query('SELECT * FROM users LIMIT 10') as User[];
108
+ await db.close();
109
+
110
+ response.success(res, {
111
+ database: 'MySQL',
112
+ users,
113
+ });
114
+ } catch (error) {
115
+ response.error(res, `MySQL error: ${(error as Error).message}`, 500);
116
+ }
117
+ });
118
+
119
+ // Health check
120
+ app.get('/health', (req, res) => {
121
+ response.success(res, {
122
+ status: 'ok',
123
+ databases: ['PostgreSQL', 'MySQL', 'MongoDB', 'SQLite', 'SQL Server'],
124
+ typescript: true,
125
+ });
126
+ });
127
+
128
+ // Start server
129
+ const PORT = process.env.PORT || 3000;
130
+ app.listen(PORT, () => {
131
+ console.log(`🚀 Navis.js Database Adapters Demo (TypeScript) running on http://localhost:${PORT}`);
132
+ console.log('\n📊 Available endpoints:');
133
+ console.log(` GET http://localhost:${PORT}/sqlite/users - SQLite example`);
134
+ console.log(` GET http://localhost:${PORT}/sqlserver/users - SQL Server example`);
135
+ console.log(` GET http://localhost:${PORT}/postgres/users - PostgreSQL example`);
136
+ console.log(` GET http://localhost:${PORT}/mysql/users - MySQL example`);
137
+ console.log(` GET http://localhost:${PORT}/health - Health check`);
138
+ console.log('\n💡 Note: Make sure to install the required database drivers:');
139
+ console.log(' - SQLite: npm install better-sqlite3 (or sqlite3 sqlite)');
140
+ console.log(' - SQL Server: npm install mssql');
141
+ console.log(' - PostgreSQL: npm install pg');
142
+ console.log(' - MySQL: npm install mysql2');
143
+ console.log(' - MongoDB: npm install mongodb');
144
+ });
145
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "navis.js",
3
- "version": "5.4.1",
3
+ "version": "5.5.1",
4
4
  "description": "A lightweight, serverless-first, microservice API framework designed for AWS Lambda and Node.js",
5
5
  "main": "src/index.js",
6
6
  "types": "types/index.d.ts",
package/src/db/db-pool.js CHANGED
@@ -33,6 +33,14 @@ class DatabasePool {
33
33
  case 'mongodb':
34
34
  await this._connectMongoDB();
35
35
  break;
36
+ case 'sqlite':
37
+ case 'sqlite3':
38
+ await this._connectSQLite();
39
+ break;
40
+ case 'mssql':
41
+ case 'sqlserver':
42
+ await this._connectSQLServer();
43
+ break;
36
44
  default:
37
45
  throw new Error(`Unsupported database type: ${this.type}`);
38
46
  }
@@ -90,6 +98,111 @@ class DatabasePool {
90
98
  }
91
99
  }
92
100
 
101
+ /**
102
+ * Connect to SQLite
103
+ * @private
104
+ */
105
+ async _connectSQLite() {
106
+ try {
107
+ const sqlite3 = require('better-sqlite3');
108
+ // SQLite connection string is a file path
109
+ const dbPath = this.connectionString || ':memory:';
110
+ this.pool = sqlite3(dbPath, {
111
+ timeout: this.idleTimeout,
112
+ });
113
+ // SQLite doesn't use connection pooling, but we store the db instance
114
+ this.db = this.pool;
115
+ } catch (error) {
116
+ // Fallback to sqlite3 if better-sqlite3 is not available
117
+ try {
118
+ const sqlite3 = require('sqlite3');
119
+ const { open } = require('sqlite');
120
+ const dbPath = this.connectionString || ':memory:';
121
+ this.pool = await open({
122
+ filename: dbPath,
123
+ driver: sqlite3.Database,
124
+ });
125
+ this.db = this.pool;
126
+ } catch (fallbackError) {
127
+ throw new Error('SQLite package not installed. Install with: npm install better-sqlite3 or npm install sqlite3 sqlite');
128
+ }
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Connect to SQL Server
134
+ * @private
135
+ */
136
+ async _connectSQLServer() {
137
+ try {
138
+ const sql = require('mssql');
139
+ const config = this._parseSQLServerConfig(this.connectionString);
140
+ this.pool = await sql.connect(config);
141
+ this.db = this.pool;
142
+ } catch (error) {
143
+ throw new Error('mssql package not installed. Install with: npm install mssql');
144
+ }
145
+ }
146
+
147
+ /**
148
+ * Parse SQL Server connection string to config object
149
+ * @private
150
+ */
151
+ _parseSQLServerConfig(connectionString) {
152
+ if (!connectionString) {
153
+ throw new Error('SQL Server connection string is required');
154
+ }
155
+
156
+ // If it's already an object, return it
157
+ if (typeof connectionString === 'object') {
158
+ return {
159
+ ...connectionString,
160
+ pool: {
161
+ max: this.maxConnections,
162
+ min: this.minConnections,
163
+ idleTimeoutMillis: this.idleTimeout,
164
+ },
165
+ };
166
+ }
167
+
168
+ // Parse connection string format: Server=host;Database=db;User Id=user;Password=pass
169
+ const config = {};
170
+ connectionString.split(';').forEach(part => {
171
+ const [key, value] = part.split('=');
172
+ if (key && value) {
173
+ const normalizedKey = key.trim().toLowerCase();
174
+ switch (normalizedKey) {
175
+ case 'server':
176
+ config.server = value.trim();
177
+ break;
178
+ case 'database':
179
+ config.database = value.trim();
180
+ break;
181
+ case 'user id':
182
+ case 'userid':
183
+ case 'uid':
184
+ config.user = value.trim();
185
+ break;
186
+ case 'password':
187
+ case 'pwd':
188
+ config.password = value.trim();
189
+ break;
190
+ case 'port':
191
+ config.port = parseInt(value.trim(), 10);
192
+ break;
193
+ }
194
+ }
195
+ });
196
+
197
+ config.pool = {
198
+ max: this.maxConnections,
199
+ min: this.minConnections,
200
+ idleTimeoutMillis: this.idleTimeout,
201
+ };
202
+
203
+ return config;
204
+ }
205
+
93
206
  /**
94
207
  * Execute a query
95
208
  * @param {string} query - SQL query or MongoDB operation
@@ -113,6 +226,36 @@ class DatabasePool {
113
226
  // MongoDB uses different query syntax
114
227
  // This is a placeholder - implement based on your needs
115
228
  return await this.db.collection(query).find(params[0] || {}).toArray();
229
+ case 'sqlite':
230
+ case 'sqlite3':
231
+ // SQLite with better-sqlite3 (synchronous) or sqlite (async)
232
+ if (this.pool.prepare) {
233
+ // better-sqlite3
234
+ const stmt = this.pool.prepare(query);
235
+ return stmt.all(...params);
236
+ } else {
237
+ // sqlite (async)
238
+ return await this.pool.all(query, params);
239
+ }
240
+ case 'mssql':
241
+ case 'sqlserver':
242
+ const sql = require('mssql');
243
+ const request = this.pool.request();
244
+ // For parameterized queries, use proper SQL Server parameter syntax
245
+ // If params is an array, bind them as @p0, @p1, etc.
246
+ if (Array.isArray(params) && params.length > 0) {
247
+ params.forEach((param, index) => {
248
+ request.input(`p${index}`, param);
249
+ });
250
+ // Replace ? with @p0, @p1, etc. in query
251
+ let paramIndex = 0;
252
+ const modifiedQuery = query.replace(/\?/g, () => `@p${paramIndex++}`);
253
+ const result = await request.query(modifiedQuery);
254
+ return result.recordset;
255
+ } else {
256
+ const result = await request.query(query);
257
+ return result.recordset;
258
+ }
116
259
  default:
117
260
  throw new Error(`Unsupported database type: ${this.type}`);
118
261
  }
@@ -127,7 +270,11 @@ class DatabasePool {
127
270
  await this.connect();
128
271
  }
129
272
 
130
- if (this.type === 'mongodb') {
273
+ if (this.type === 'mongodb' || this.type === 'sqlite' || this.type === 'sqlite3') {
274
+ return this.pool;
275
+ }
276
+
277
+ if (this.type === 'mssql' || this.type === 'sqlserver') {
131
278
  return this.pool;
132
279
  }
133
280
 
@@ -143,6 +290,9 @@ class DatabasePool {
143
290
  await this.pool.end();
144
291
  } else if (this.pool.close) {
145
292
  await this.pool.close();
293
+ } else if (typeof this.pool.close === 'function') {
294
+ // SQLite better-sqlite3
295
+ this.pool.close();
146
296
  }
147
297
  this.pool = null;
148
298
  }
@@ -170,6 +320,19 @@ class DatabasePool {
170
320
  case 'mongodb':
171
321
  await this.db.admin().ping();
172
322
  return true;
323
+ case 'sqlite':
324
+ case 'sqlite3':
325
+ // SQLite ping - just check if database is accessible
326
+ if (this.pool.prepare) {
327
+ this.pool.prepare('SELECT 1').get();
328
+ } else {
329
+ await this.pool.get('SELECT 1');
330
+ }
331
+ return true;
332
+ case 'mssql':
333
+ case 'sqlserver':
334
+ await this.pool.request().query('SELECT 1');
335
+ return true;
173
336
  default:
174
337
  return false;
175
338
  }
package/types/index.d.ts CHANGED
@@ -537,7 +537,7 @@ export interface SSEServer {
537
537
  }
538
538
 
539
539
  export interface DatabasePoolOptions {
540
- type?: 'postgres' | 'postgresql' | 'mysql' | 'mariadb' | 'mongodb';
540
+ type?: 'postgres' | 'postgresql' | 'mysql' | 'mariadb' | 'mongodb' | 'sqlite' | 'sqlite3' | 'mssql' | 'sqlserver';
541
541
  connectionString?: string;
542
542
  maxConnections?: number;
543
543
  minConnections?: number;