@push.rocks/smartdb 2.7.1 → 2.9.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/dist_rust/rustdb_linux_amd64 +0 -0
- package/dist_rust/rustdb_linux_arm64 +0 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/index.d.ts +1 -1
- package/dist_ts/ts_smartdb/index.d.ts +1 -1
- package/dist_ts/ts_smartdb/rust-db-bridge.d.ts +74 -0
- package/dist_ts/ts_smartdb/rust-db-bridge.js +27 -2
- package/dist_ts/ts_smartdb/server/SmartdbServer.d.ts +40 -1
- package/dist_ts/ts_smartdb/server/SmartdbServer.js +80 -1
- package/dist_ts_debugserver/bundled.js +1 -1
- package/package.json +1 -1
- package/readme.md +8 -4
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/index.ts +10 -0
- package/ts/ts_smartdb/index.ts +10 -0
- package/ts/ts_smartdb/rust-db-bridge.ts +143 -1
- package/ts/ts_smartdb/server/SmartdbServer.ts +110 -0
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -290,10 +290,12 @@ await client.connect();
|
|
|
290
290
|
|
|
291
291
|
TLS is available for TCP listeners. `getConnectionUri()` includes `?tls=true` when TLS is enabled; pass the trusted CA to the MongoDB driver with `tlsCAFile`, `ca`, or `secureContext`.
|
|
292
292
|
|
|
293
|
-
Authentication verifies SCRAM credentials, denies unauthenticated commands, and enforces command-level built-in roles for supported operations.
|
|
293
|
+
Authentication verifies SCRAM credentials, denies unauthenticated commands, and enforces command-level built-in roles for supported operations. `connectionStatus` reports the authenticated users and roles for the current socket.
|
|
294
294
|
|
|
295
295
|
Supported built-in role names are `root`, `read`, `readWrite`, `dbAdmin`, `userAdmin`, `clusterMonitor`, plus `readAnyDatabase`, `readWriteAnyDatabase`, `dbAdminAnyDatabase`, and `userAdminAnyDatabase`. When `usersPath` is set, SmartDB persists SCRAM credential material atomically and does not store plaintext passwords.
|
|
296
296
|
|
|
297
|
+
Single-node transactions are supported through official MongoDB driver sessions. Writes with `startTransaction` and `autocommit: false` are buffered per logical session, reads inside the transaction see the buffered overlay, `commitTransaction` applies the write set with conflict checks, and `abortTransaction` discards it.
|
|
298
|
+
|
|
297
299
|
Basic user management commands are available for authenticated users with `root` or `userAdmin` privileges:
|
|
298
300
|
|
|
299
301
|
```typescript
|
|
@@ -317,7 +319,7 @@ await client.db('admin').command({ usersInfo: 'reader' });
|
|
|
317
319
|
| `port` | `number` | Configured port (TCP mode) |
|
|
318
320
|
| `host` | `string` | Configured host (TCP mode) |
|
|
319
321
|
| `socketPath` | `string \| undefined` | Socket path (socket mode) |
|
|
320
|
-
| `getMetrics()` | `Promise<ISmartDbMetrics>` | Server metrics (db/collection counts, uptime) |
|
|
322
|
+
| `getMetrics()` | `Promise<ISmartDbMetrics>` | Server metrics (db/collection counts, sessions, transactions, auth, uptime) |
|
|
321
323
|
| `getOpLog(params?)` | `Promise<IOpLogResult>` | Query oplog entries with optional filters |
|
|
322
324
|
| `getOpLogStats()` | `Promise<IOpLogStats>` | Aggregate oplog statistics |
|
|
323
325
|
| `revertToSeq(seq, dryRun?)` | `Promise<IRevertResult>` | Revert to a specific oplog sequence |
|
|
@@ -531,7 +533,7 @@ const names = await collection.distinct('name');
|
|
|
531
533
|
| **Aggregation** | `aggregate`, `count`, `distinct` |
|
|
532
534
|
| **Indexes** | `createIndexes`, `dropIndexes`, `listIndexes` |
|
|
533
535
|
| **Sessions** | `startSession`, `endSessions` |
|
|
534
|
-
| **Transactions** | `commitTransaction`, `abortTransaction` |
|
|
536
|
+
| **Transactions** | `startTransaction`, `commitTransaction`, `abortTransaction` through driver sessions |
|
|
535
537
|
| **Admin** | `ping`, `listDatabases`, `listCollections`, `drop`, `dropDatabase`, `create`, `serverStatus`, `buildInfo`, `dbStats`, `collStats`, `connectionStatus`, `currentOp`, `renameCollection` |
|
|
536
538
|
|
|
537
539
|
Compatible with wire protocol versions 0–21 (driver versions 3.6 through 7.0).
|
|
@@ -540,7 +542,7 @@ Compatible with wire protocol versions 0–21 (driver versions 3.6 through 7.0).
|
|
|
540
542
|
|
|
541
543
|
## Rust Crate Architecture 🦀
|
|
542
544
|
|
|
543
|
-
The Rust engine is organized as a Cargo workspace with
|
|
545
|
+
The Rust engine is organized as a Cargo workspace with 9 focused crates:
|
|
544
546
|
|
|
545
547
|
| Crate | Purpose |
|
|
546
548
|
|---|---|
|
|
@@ -551,6 +553,7 @@ The Rust engine is organized as a Cargo workspace with 8 focused crates:
|
|
|
551
553
|
| `rustdb-storage` | Storage backends (memory, file), OpLog with point-in-time replay |
|
|
552
554
|
| `rustdb-index` | B-tree/hash indexes, query planner (IXSCAN/COLLSCAN) |
|
|
553
555
|
| `rustdb-txn` | Transaction + session management with snapshot isolation |
|
|
556
|
+
| `rustdb-auth` | SCRAM-SHA-256 credential handling, user metadata persistence, RBAC checks |
|
|
554
557
|
| `rustdb-commands` | 40+ command handlers wiring everything together |
|
|
555
558
|
|
|
556
559
|
Cross-compiled for `linux_amd64` and `linux_arm64` via [@git.zone/tsrust](https://www.npmjs.com/package/@git.zone/tsrust).
|
|
@@ -563,6 +566,7 @@ The Bitcask-style file storage engine includes several reliability features:
|
|
|
563
566
|
- **CRC32 checksums** — every record is integrity-checked on read
|
|
564
567
|
- **Automatic compaction** — dead records are reclaimed when they exceed 50% of file size, runs on startup and after every write
|
|
565
568
|
- **Hint file staleness detection** — the hint file records the data file size at write time; if data.rdb changed since (e.g. crash after a delete), the engine falls back to a full scan to ensure tombstones are not lost
|
|
569
|
+
- **Torn-tail repair** — startup scans `data.rdb` to the last valid record, truncates invalid trailing bytes, and preserves all verified records after interrupted writes
|
|
566
570
|
- **Stale socket cleanup** — orphaned `/tmp/smartdb-*.sock` files from crashed instances are automatically cleaned up on startup
|
|
567
571
|
|
|
568
572
|
### Data Integrity CLI 🔍
|
package/ts/00_commitinfo_data.ts
CHANGED
package/ts/index.ts
CHANGED
|
@@ -22,4 +22,14 @@ export type {
|
|
|
22
22
|
ICollectionInfo,
|
|
23
23
|
IDocumentsResult,
|
|
24
24
|
ISmartDbMetrics,
|
|
25
|
+
ISmartDbHealth,
|
|
26
|
+
ISmartDbDatabaseTenantInput,
|
|
27
|
+
ISmartDbDeleteDatabaseTenantInput,
|
|
28
|
+
ISmartDbRotateDatabaseTenantPasswordInput,
|
|
29
|
+
ISmartDbDatabaseTenantDescriptor,
|
|
30
|
+
ISmartDbDeleteDatabaseTenantResult,
|
|
31
|
+
ISmartDbDatabaseExportCollection,
|
|
32
|
+
ISmartDbDatabaseExport,
|
|
33
|
+
ISmartDbImportDatabaseInput,
|
|
34
|
+
ISmartDbImportDatabaseResult,
|
|
25
35
|
} from './ts_smartdb/index.js';
|
package/ts/ts_smartdb/index.ts
CHANGED
|
@@ -21,4 +21,14 @@ export type {
|
|
|
21
21
|
ICollectionInfo,
|
|
22
22
|
IDocumentsResult,
|
|
23
23
|
ISmartDbMetrics,
|
|
24
|
+
ISmartDbHealth,
|
|
25
|
+
ISmartDbDatabaseTenantInput,
|
|
26
|
+
ISmartDbDeleteDatabaseTenantInput,
|
|
27
|
+
ISmartDbRotateDatabaseTenantPasswordInput,
|
|
28
|
+
ISmartDbDatabaseTenantDescriptor,
|
|
29
|
+
ISmartDbDeleteDatabaseTenantResult,
|
|
30
|
+
ISmartDbDatabaseExportCollection,
|
|
31
|
+
ISmartDbDatabaseExport,
|
|
32
|
+
ISmartDbImportDatabaseInput,
|
|
33
|
+
ISmartDbImportDatabaseResult,
|
|
24
34
|
} from './rust-db-bridge.js';
|
|
@@ -76,9 +76,80 @@ export interface ISmartDbMetrics {
|
|
|
76
76
|
collections: number;
|
|
77
77
|
oplogEntries: number;
|
|
78
78
|
oplogCurrentSeq: number;
|
|
79
|
+
sessions: number;
|
|
80
|
+
activeTransactions: number;
|
|
81
|
+
authEnabled: boolean;
|
|
82
|
+
authUsers: number;
|
|
79
83
|
uptimeSeconds: number;
|
|
80
84
|
}
|
|
81
85
|
|
|
86
|
+
export interface ISmartDbHealth {
|
|
87
|
+
running: boolean;
|
|
88
|
+
storage?: 'memory' | 'file';
|
|
89
|
+
storagePath?: string;
|
|
90
|
+
authEnabled?: boolean;
|
|
91
|
+
authUsers?: number;
|
|
92
|
+
usersPathConfigured?: boolean;
|
|
93
|
+
databaseCount: number;
|
|
94
|
+
collectionCount: number;
|
|
95
|
+
uptimeSeconds?: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export interface ISmartDbDatabaseTenantInput {
|
|
99
|
+
databaseName: string;
|
|
100
|
+
username: string;
|
|
101
|
+
password: string;
|
|
102
|
+
roles?: string[];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export interface ISmartDbDeleteDatabaseTenantInput {
|
|
106
|
+
databaseName: string;
|
|
107
|
+
username?: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface ISmartDbRotateDatabaseTenantPasswordInput {
|
|
111
|
+
username: string;
|
|
112
|
+
password: string;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface ISmartDbDatabaseTenantDescriptor {
|
|
116
|
+
databaseName: string;
|
|
117
|
+
username: string;
|
|
118
|
+
roles: string[];
|
|
119
|
+
authSource: string;
|
|
120
|
+
mongodbUri?: string;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export interface ISmartDbDeleteDatabaseTenantResult {
|
|
124
|
+
databaseName: string;
|
|
125
|
+
deletedUsers: number;
|
|
126
|
+
databaseDropped: boolean;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export interface ISmartDbDatabaseExportCollection {
|
|
130
|
+
name: string;
|
|
131
|
+
documents: Record<string, any>[];
|
|
132
|
+
indexes: Record<string, any>[];
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface ISmartDbDatabaseExport {
|
|
136
|
+
format: 'smartdb.database.export.v1';
|
|
137
|
+
databaseName: string;
|
|
138
|
+
exportedAtMs: number;
|
|
139
|
+
collections: ISmartDbDatabaseExportCollection[];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export interface ISmartDbImportDatabaseInput {
|
|
143
|
+
databaseName: string;
|
|
144
|
+
source: ISmartDbDatabaseExport;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface ISmartDbImportDatabaseResult {
|
|
148
|
+
databaseName: string;
|
|
149
|
+
collections: number;
|
|
150
|
+
documents: number;
|
|
151
|
+
}
|
|
152
|
+
|
|
82
153
|
/**
|
|
83
154
|
* Type-safe command definitions for the RustDb IPC protocol.
|
|
84
155
|
*/
|
|
@@ -86,7 +157,36 @@ type TSmartDbCommands = {
|
|
|
86
157
|
start: { params: { config: ISmartDbRustConfig }; result: { connectionUri: string } };
|
|
87
158
|
stop: { params: Record<string, never>; result: void };
|
|
88
159
|
getStatus: { params: Record<string, never>; result: { running: boolean } };
|
|
160
|
+
getHealth: { params: Record<string, never>; result: ISmartDbHealth };
|
|
89
161
|
getMetrics: { params: Record<string, never>; result: ISmartDbMetrics };
|
|
162
|
+
createDatabaseTenant: {
|
|
163
|
+
params: ISmartDbDatabaseTenantInput;
|
|
164
|
+
result: ISmartDbDatabaseTenantDescriptor;
|
|
165
|
+
};
|
|
166
|
+
deleteDatabaseTenant: {
|
|
167
|
+
params: ISmartDbDeleteDatabaseTenantInput;
|
|
168
|
+
result: ISmartDbDeleteDatabaseTenantResult;
|
|
169
|
+
};
|
|
170
|
+
rotateDatabaseTenantPassword: {
|
|
171
|
+
params: ISmartDbRotateDatabaseTenantPasswordInput;
|
|
172
|
+
result: ISmartDbDatabaseTenantDescriptor;
|
|
173
|
+
};
|
|
174
|
+
listDatabaseTenants: {
|
|
175
|
+
params: Record<string, never>;
|
|
176
|
+
result: { tenants: ISmartDbDatabaseTenantDescriptor[] };
|
|
177
|
+
};
|
|
178
|
+
getDatabaseTenantDescriptor: {
|
|
179
|
+
params: { databaseName: string; username: string };
|
|
180
|
+
result: ISmartDbDatabaseTenantDescriptor;
|
|
181
|
+
};
|
|
182
|
+
exportDatabase: {
|
|
183
|
+
params: { databaseName: string };
|
|
184
|
+
result: ISmartDbDatabaseExport;
|
|
185
|
+
};
|
|
186
|
+
importDatabase: {
|
|
187
|
+
params: ISmartDbImportDatabaseInput;
|
|
188
|
+
result: ISmartDbImportDatabaseResult;
|
|
189
|
+
};
|
|
90
190
|
getOpLog: {
|
|
91
191
|
params: { sinceSeq?: number; limit?: number; db?: string; collection?: string };
|
|
92
192
|
result: IOpLogResult;
|
|
@@ -198,7 +298,7 @@ export class RustDbBridge extends EventEmitter {
|
|
|
198
298
|
envVarName: 'SMARTDB_RUST_BINARY',
|
|
199
299
|
platformPackagePrefix: '@push.rocks/smartdb',
|
|
200
300
|
localPaths: buildLocalPaths(),
|
|
201
|
-
maxPayloadSize:
|
|
301
|
+
maxPayloadSize: 100 * 1024 * 1024, // database exports/imports can be larger than command replies
|
|
202
302
|
});
|
|
203
303
|
|
|
204
304
|
// Forward events from the inner bridge
|
|
@@ -247,6 +347,48 @@ export class RustDbBridge extends EventEmitter {
|
|
|
247
347
|
return this.bridge.sendCommand('getMetrics', {} as Record<string, never>) as Promise<ISmartDbMetrics>;
|
|
248
348
|
}
|
|
249
349
|
|
|
350
|
+
public async getHealth(): Promise<ISmartDbHealth> {
|
|
351
|
+
return this.bridge.sendCommand('getHealth', {} as Record<string, never>) as Promise<ISmartDbHealth>;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
public async createDatabaseTenant(
|
|
355
|
+
params: ISmartDbDatabaseTenantInput,
|
|
356
|
+
): Promise<ISmartDbDatabaseTenantDescriptor> {
|
|
357
|
+
return this.bridge.sendCommand('createDatabaseTenant', params) as Promise<ISmartDbDatabaseTenantDescriptor>;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
public async deleteDatabaseTenant(
|
|
361
|
+
params: ISmartDbDeleteDatabaseTenantInput,
|
|
362
|
+
): Promise<ISmartDbDeleteDatabaseTenantResult> {
|
|
363
|
+
return this.bridge.sendCommand('deleteDatabaseTenant', params) as Promise<ISmartDbDeleteDatabaseTenantResult>;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
public async rotateDatabaseTenantPassword(
|
|
367
|
+
params: ISmartDbRotateDatabaseTenantPasswordInput,
|
|
368
|
+
): Promise<ISmartDbDatabaseTenantDescriptor> {
|
|
369
|
+
return this.bridge.sendCommand('rotateDatabaseTenantPassword', params) as Promise<ISmartDbDatabaseTenantDescriptor>;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
public async listDatabaseTenants(): Promise<ISmartDbDatabaseTenantDescriptor[]> {
|
|
373
|
+
const result = await this.bridge.sendCommand('listDatabaseTenants', {} as Record<string, never>) as { tenants: ISmartDbDatabaseTenantDescriptor[] };
|
|
374
|
+
return result.tenants;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
public async getDatabaseTenantDescriptor(params: {
|
|
378
|
+
databaseName: string;
|
|
379
|
+
username: string;
|
|
380
|
+
}): Promise<ISmartDbDatabaseTenantDescriptor> {
|
|
381
|
+
return this.bridge.sendCommand('getDatabaseTenantDescriptor', params) as Promise<ISmartDbDatabaseTenantDescriptor>;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
public async exportDatabase(params: { databaseName: string }): Promise<ISmartDbDatabaseExport> {
|
|
385
|
+
return this.bridge.sendCommand('exportDatabase', params) as Promise<ISmartDbDatabaseExport>;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
public async importDatabase(params: ISmartDbImportDatabaseInput): Promise<ISmartDbImportDatabaseResult> {
|
|
389
|
+
return this.bridge.sendCommand('importDatabase', params) as Promise<ISmartDbImportDatabaseResult>;
|
|
390
|
+
}
|
|
391
|
+
|
|
250
392
|
public async getOpLog(params: {
|
|
251
393
|
sinceSeq?: number;
|
|
252
394
|
limit?: number;
|
|
@@ -8,6 +8,15 @@ import type {
|
|
|
8
8
|
ICollectionInfo,
|
|
9
9
|
IDocumentsResult,
|
|
10
10
|
ISmartDbMetrics,
|
|
11
|
+
ISmartDbHealth,
|
|
12
|
+
ISmartDbDatabaseTenantInput,
|
|
13
|
+
ISmartDbDeleteDatabaseTenantInput,
|
|
14
|
+
ISmartDbRotateDatabaseTenantPasswordInput,
|
|
15
|
+
ISmartDbDatabaseTenantDescriptor,
|
|
16
|
+
ISmartDbDeleteDatabaseTenantResult,
|
|
17
|
+
ISmartDbDatabaseExport,
|
|
18
|
+
ISmartDbImportDatabaseInput,
|
|
19
|
+
ISmartDbImportDatabaseResult,
|
|
11
20
|
} from '../rust-db-bridge.js';
|
|
12
21
|
|
|
13
22
|
/**
|
|
@@ -204,6 +213,85 @@ export class SmartdbServer {
|
|
|
204
213
|
return this.options.host ?? '127.0.0.1';
|
|
205
214
|
}
|
|
206
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Create an isolated database/user pair for an application tenant.
|
|
218
|
+
*/
|
|
219
|
+
async createDatabaseTenant(
|
|
220
|
+
params: ISmartDbDatabaseTenantInput,
|
|
221
|
+
): Promise<ISmartDbDatabaseTenantDescriptor> {
|
|
222
|
+
const descriptor = await this.bridge.createDatabaseTenant(params);
|
|
223
|
+
return this.withTenantMongoUri(descriptor, params.password);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Delete a tenant database and its tenant user(s).
|
|
228
|
+
*/
|
|
229
|
+
async deleteDatabaseTenant(
|
|
230
|
+
params: ISmartDbDeleteDatabaseTenantInput,
|
|
231
|
+
): Promise<ISmartDbDeleteDatabaseTenantResult> {
|
|
232
|
+
return this.bridge.deleteDatabaseTenant(params);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Rotate a tenant user's password without restarting the server.
|
|
237
|
+
*/
|
|
238
|
+
async rotateDatabaseTenantPassword(
|
|
239
|
+
params: ISmartDbRotateDatabaseTenantPasswordInput,
|
|
240
|
+
): Promise<ISmartDbDatabaseTenantDescriptor> {
|
|
241
|
+
const descriptor = await this.bridge.rotateDatabaseTenantPassword(params);
|
|
242
|
+
return this.withTenantMongoUri(descriptor, params.password);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* List known database tenants.
|
|
247
|
+
*/
|
|
248
|
+
async listDatabaseTenants(): Promise<ISmartDbDatabaseTenantDescriptor[]> {
|
|
249
|
+
return this.bridge.listDatabaseTenants();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Get a tenant descriptor without exposing a password.
|
|
254
|
+
*/
|
|
255
|
+
async getDatabaseTenantDescriptor(params: {
|
|
256
|
+
databaseName: string;
|
|
257
|
+
username: string;
|
|
258
|
+
}): Promise<ISmartDbDatabaseTenantDescriptor> {
|
|
259
|
+
return this.bridge.getDatabaseTenantDescriptor(params);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Export one database as an Extended JSON snapshot.
|
|
264
|
+
*/
|
|
265
|
+
async exportDatabase(params: { databaseName: string }): Promise<ISmartDbDatabaseExport> {
|
|
266
|
+
return this.bridge.exportDatabase(params);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Replace one database with a previously exported snapshot.
|
|
271
|
+
*/
|
|
272
|
+
async importDatabase(params: ISmartDbImportDatabaseInput): Promise<ISmartDbImportDatabaseResult> {
|
|
273
|
+
return this.bridge.importDatabase(params);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Get readiness/health details for long-running service use.
|
|
278
|
+
*/
|
|
279
|
+
async getHealth(): Promise<ISmartDbHealth> {
|
|
280
|
+
if (!this.isRunning) {
|
|
281
|
+
return {
|
|
282
|
+
running: false,
|
|
283
|
+
storage: this.options.storage,
|
|
284
|
+
storagePath: this.options.storage === 'file' ? this.options.storagePath : this.options.persistPath,
|
|
285
|
+
authEnabled: Boolean(this.options.auth?.enabled),
|
|
286
|
+
authUsers: this.options.auth?.users?.length ?? 0,
|
|
287
|
+
usersPathConfigured: Boolean(this.options.auth?.usersPath),
|
|
288
|
+
databaseCount: 0,
|
|
289
|
+
collectionCount: 0,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
return this.bridge.getHealth();
|
|
293
|
+
}
|
|
294
|
+
|
|
207
295
|
// --- OpLog / Debug API ---
|
|
208
296
|
|
|
209
297
|
/**
|
|
@@ -258,4 +346,26 @@ export class SmartdbServer {
|
|
|
258
346
|
async getMetrics(): Promise<ISmartDbMetrics> {
|
|
259
347
|
return this.bridge.getMetrics();
|
|
260
348
|
}
|
|
349
|
+
|
|
350
|
+
private withTenantMongoUri(
|
|
351
|
+
descriptor: ISmartDbDatabaseTenantDescriptor,
|
|
352
|
+
password: string,
|
|
353
|
+
): ISmartDbDatabaseTenantDescriptor {
|
|
354
|
+
return {
|
|
355
|
+
...descriptor,
|
|
356
|
+
mongodbUri: this.buildTenantMongoUri(descriptor.databaseName, descriptor.username, password),
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
private buildTenantMongoUri(databaseName: string, username: string, password: string): string {
|
|
361
|
+
const host = this.options.socketPath
|
|
362
|
+
? encodeURIComponent(this.options.socketPath)
|
|
363
|
+
: `${this.options.host ?? '127.0.0.1'}:${this.options.port ?? 27017}`;
|
|
364
|
+
const auth = `${encodeURIComponent(username)}:${encodeURIComponent(password)}@`;
|
|
365
|
+
const query = new URLSearchParams({ authSource: databaseName });
|
|
366
|
+
if (this.options.tls?.enabled) {
|
|
367
|
+
query.set('tls', 'true');
|
|
368
|
+
}
|
|
369
|
+
return `mongodb://${auth}${host}/${encodeURIComponent(databaseName)}?${query.toString()}`;
|
|
370
|
+
}
|
|
261
371
|
}
|