@lossless.org/client 0.1.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/.smartconfig.json +37 -0
- package/dist_ts/00_commitinfo_data.d.ts +8 -0
- package/dist_ts/00_commitinfo_data.js +9 -0
- package/dist_ts/classes.losslessorgclient.d.ts +32 -0
- package/dist_ts/classes.losslessorgclient.js +103 -0
- package/dist_ts/core/classes.error.d.ts +16 -0
- package/dist_ts/core/classes.error.js +29 -0
- package/dist_ts/core/classes.operation.d.ts +17 -0
- package/dist_ts/core/classes.operation.js +70 -0
- package/dist_ts/core/interfaces.d.ts +18 -0
- package/dist_ts/core/interfaces.js +2 -0
- package/dist_ts/index.d.ts +4 -0
- package/dist_ts/index.js +3 -0
- package/dist_ts/nosqldb/classes.atomicdelete.d.ts +26 -0
- package/dist_ts/nosqldb/classes.atomicdelete.js +44 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.d.ts +27 -0
- package/dist_ts/nosqldb/classes.atomicfindoneandupdate.js +86 -0
- package/dist_ts/nosqldb/classes.atomicupdate.d.ts +26 -0
- package/dist_ts/nosqldb/classes.atomicupdate.js +55 -0
- package/dist_ts/nosqldb/classes.bootstraprecord.d.ts +14 -0
- package/dist_ts/nosqldb/classes.bootstraprecord.js +80 -0
- package/dist_ts/nosqldb/classes.bsonassertion.d.ts +2 -0
- package/dist_ts/nosqldb/classes.bsonassertion.js +29 -0
- package/dist_ts/nosqldb/classes.bsonobjectid.d.ts +2 -0
- package/dist_ts/nosqldb/classes.bsonobjectid.js +50 -0
- package/dist_ts/nosqldb/classes.bsonsnapshot.d.ts +3 -0
- package/dist_ts/nosqldb/classes.bsonsnapshot.js +126 -0
- package/dist_ts/nosqldb/classes.cached-document.d.ts +27 -0
- package/dist_ts/nosqldb/classes.cached-document.js +112 -0
- package/dist_ts/nosqldb/classes.collection.d.ts +302 -0
- package/dist_ts/nosqldb/classes.collection.js +1568 -0
- package/dist_ts/nosqldb/classes.collectionfactory.d.ts +30 -0
- package/dist_ts/nosqldb/classes.collectionfactory.js +65 -0
- package/dist_ts/nosqldb/classes.collectionlifecycle.d.ts +4 -0
- package/dist_ts/nosqldb/classes.collectionlifecycle.js +15 -0
- package/dist_ts/nosqldb/classes.collectionpreparation.d.ts +34 -0
- package/dist_ts/nosqldb/classes.collectionpreparation.js +134 -0
- package/dist_ts/nosqldb/classes.collectiontopology.d.ts +47 -0
- package/dist_ts/nosqldb/classes.collectiontopology.js +388 -0
- package/dist_ts/nosqldb/classes.connection.d.ts +18 -0
- package/dist_ts/nosqldb/classes.connection.js +23 -0
- package/dist_ts/nosqldb/classes.convenience.d.ts +1 -0
- package/dist_ts/nosqldb/classes.convenience.js +5 -0
- package/dist_ts/nosqldb/classes.cursor.d.ts +15 -0
- package/dist_ts/nosqldb/classes.cursor.js +82 -0
- package/dist_ts/nosqldb/classes.cursoroperation.d.ts +7 -0
- package/dist_ts/nosqldb/classes.cursoroperation.js +36 -0
- package/dist_ts/nosqldb/classes.db.d.ts +98 -0
- package/dist_ts/nosqldb/classes.db.js +434 -0
- package/dist_ts/nosqldb/classes.distributedcoordinator.d.ts +52 -0
- package/dist_ts/nosqldb/classes.distributedcoordinator.js +314 -0
- package/dist_ts/nosqldb/classes.doc.d.ts +722 -0
- package/dist_ts/nosqldb/classes.doc.js +2976 -0
- package/dist_ts/nosqldb/classes.easystore.d.ts +42 -0
- package/dist_ts/nosqldb/classes.easystore.js +199 -0
- package/dist_ts/nosqldb/classes.exactpersistence.d.ts +141 -0
- package/dist_ts/nosqldb/classes.exactpersistence.js +1110 -0
- package/dist_ts/nosqldb/classes.lucene.adapter.d.ts +173 -0
- package/dist_ts/nosqldb/classes.lucene.adapter.js +623 -0
- package/dist_ts/nosqldb/classes.mongoadministration.d.ts +73 -0
- package/dist_ts/nosqldb/classes.mongoadministration.js +497 -0
- package/dist_ts/nosqldb/classes.namespaceinspection.d.ts +42 -0
- package/dist_ts/nosqldb/classes.namespaceinspection.js +138 -0
- package/dist_ts/nosqldb/classes.operationbudget.d.ts +22 -0
- package/dist_ts/nosqldb/classes.operationbudget.js +65 -0
- package/dist_ts/nosqldb/classes.ordinarypersistence.d.ts +18 -0
- package/dist_ts/nosqldb/classes.ordinarypersistence.js +71 -0
- package/dist_ts/nosqldb/classes.persistence.d.ts +14 -0
- package/dist_ts/nosqldb/classes.persistence.js +34 -0
- package/dist_ts/nosqldb/classes.session.d.ts +28 -0
- package/dist_ts/nosqldb/classes.session.js +246 -0
- package/dist_ts/nosqldb/classes.storedinspection.d.ts +44 -0
- package/dist_ts/nosqldb/classes.storedinspection.js +100 -0
- package/dist_ts/nosqldb/classes.testdatabase.d.ts +56 -0
- package/dist_ts/nosqldb/classes.testdatabase.js +250 -0
- package/dist_ts/nosqldb/classes.watcher.d.ts +37 -0
- package/dist_ts/nosqldb/classes.watcher.js +98 -0
- package/dist_ts/nosqldb/index.d.ts +27 -0
- package/dist_ts/nosqldb/index.js +18 -0
- package/dist_ts/nosqldb/logging.d.ts +2 -0
- package/dist_ts/nosqldb/logging.js +3 -0
- package/dist_ts/nosqldb/plugins.d.ts +17 -0
- package/dist_ts/nosqldb/plugins.js +20 -0
- package/dist_ts/nosqldb/shim.d.ts +1 -0
- package/dist_ts/nosqldb/shim.js +8 -0
- package/dist_ts/nosqldb/testsupport.d.ts +3 -0
- package/dist_ts/nosqldb/testsupport.js +3 -0
- package/dist_ts/objectstorage/classes.bucket.d.ts +227 -0
- package/dist_ts/objectstorage/classes.bucket.js +939 -0
- package/dist_ts/objectstorage/classes.connection.d.ts +21 -0
- package/dist_ts/objectstorage/classes.connection.js +27 -0
- package/dist_ts/objectstorage/classes.directory.d.ts +124 -0
- package/dist_ts/objectstorage/classes.directory.js +335 -0
- package/dist_ts/objectstorage/classes.exactpathpurgeerror.d.ts +5 -0
- package/dist_ts/objectstorage/classes.exactpathpurgeerror.js +18 -0
- package/dist_ts/objectstorage/classes.exactuploaderror.d.ts +5 -0
- package/dist_ts/objectstorage/classes.exactuploaderror.js +19 -0
- package/dist_ts/objectstorage/classes.file.d.ts +91 -0
- package/dist_ts/objectstorage/classes.file.js +255 -0
- package/dist_ts/objectstorage/classes.listcursor.d.ts +41 -0
- package/dist_ts/objectstorage/classes.listcursor.js +67 -0
- package/dist_ts/objectstorage/classes.metadata.d.ts +57 -0
- package/dist_ts/objectstorage/classes.metadata.js +113 -0
- package/dist_ts/objectstorage/classes.smartbucket.d.ts +57 -0
- package/dist_ts/objectstorage/classes.smartbucket.js +357 -0
- package/dist_ts/objectstorage/classes.trash.d.ts +11 -0
- package/dist_ts/objectstorage/classes.trash.js +22 -0
- package/dist_ts/objectstorage/classes.watcher.d.ts +79 -0
- package/dist_ts/objectstorage/classes.watcher.js +249 -0
- package/dist_ts/objectstorage/helpers.d.ts +25 -0
- package/dist_ts/objectstorage/helpers.js +215 -0
- package/dist_ts/objectstorage/index.d.ts +13 -0
- package/dist_ts/objectstorage/index.js +13 -0
- package/dist_ts/objectstorage/interfaces.d.ts +276 -0
- package/dist_ts/objectstorage/interfaces.js +2 -0
- package/dist_ts/objectstorage/internal.exactpathpurge.operations.d.ts +11 -0
- package/dist_ts/objectstorage/internal.exactpathpurge.operations.js +1069 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.d.ts +40 -0
- package/dist_ts/objectstorage/internal.exactupload.capability.js +382 -0
- package/dist_ts/objectstorage/internal.exactupload.operations.d.ts +11 -0
- package/dist_ts/objectstorage/internal.exactupload.operations.js +1104 -0
- package/dist_ts/objectstorage/internal.multipart.planner.d.ts +8 -0
- package/dist_ts/objectstorage/internal.multipart.planner.js +63 -0
- package/dist_ts/objectstorage/internal.multipart.stream.d.ts +17 -0
- package/dist_ts/objectstorage/internal.multipart.stream.js +440 -0
- package/dist_ts/objectstorage/internal.multipart.types.d.ts +82 -0
- package/dist_ts/objectstorage/internal.multipart.types.js +2 -0
- package/dist_ts/objectstorage/plugins.d.ts +17 -0
- package/dist_ts/objectstorage/plugins.js +23 -0
- package/dist_ts/plugins.d.ts +4 -0
- package/dist_ts/plugins.js +5 -0
- package/dist_ts/sqldb/classes.clickhouseconnection.d.ts +39 -0
- package/dist_ts/sqldb/classes.clickhouseconnection.js +225 -0
- package/dist_ts/sqldb/classes.sqlconnection.d.ts +50 -0
- package/dist_ts/sqldb/classes.sqlconnection.js +376 -0
- package/dist_ts/sqldb/classes.sqltable.d.ts +29 -0
- package/dist_ts/sqldb/classes.sqltable.js +70 -0
- package/dist_ts/sqldb/clickhouse/classes.metricwriter.d.ts +27 -0
- package/dist_ts/sqldb/clickhouse/classes.metricwriter.js +89 -0
- package/dist_ts/sqldb/clickhouse/index.d.ts +9 -0
- package/dist_ts/sqldb/clickhouse/index.js +13 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.d.ts +88 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.js +304 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.d.ts +28 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.js +46 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.d.ts +43 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.js +155 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.d.ts +13 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.resultset.js +36 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.d.ts +49 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.js +106 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.d.ts +51 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.js +96 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.d.ts +5 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.plugins.js +6 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.types.d.ts +53 -0
- package/dist_ts/sqldb/clickhouse/smartclickhouse.types.js +41 -0
- package/dist_ts/sqldb/index.d.ts +6 -0
- package/dist_ts/sqldb/index.js +6 -0
- package/dist_ts/sqldb/interfaces.d.ts +53 -0
- package/dist_ts/sqldb/interfaces.js +19 -0
- package/dist_ts/sqldb/internal.sqlpool.d.ts +51 -0
- package/dist_ts/sqldb/internal.sqlpool.js +214 -0
- package/dist_ts/sqldb/plugins.clickhouse.d.ts +4 -0
- package/dist_ts/sqldb/plugins.clickhouse.js +5 -0
- package/dist_ts/sqldb/plugins.mariadb.d.ts +4 -0
- package/dist_ts/sqldb/plugins.mariadb.js +5 -0
- package/docs/source/smartbucket/license.md +19 -0
- package/docs/source/smartclickhouse/license.md +19 -0
- package/license.md +21 -0
- package/package.json +101 -0
- package/readme.md +157 -0
- package/ts/00_commitinfo_data.ts +8 -0
- package/ts/classes.losslessorgclient.ts +104 -0
- package/ts/core/classes.error.ts +31 -0
- package/ts/core/classes.operation.ts +60 -0
- package/ts/core/interfaces.ts +24 -0
- package/ts/index.ts +4 -0
- package/ts/nosqldb/classes.atomicdelete.ts +81 -0
- package/ts/nosqldb/classes.atomicfindoneandupdate.ts +152 -0
- package/ts/nosqldb/classes.atomicupdate.ts +99 -0
- package/ts/nosqldb/classes.bootstraprecord.ts +107 -0
- package/ts/nosqldb/classes.bsonassertion.ts +25 -0
- package/ts/nosqldb/classes.bsonobjectid.ts +45 -0
- package/ts/nosqldb/classes.bsonsnapshot.ts +105 -0
- package/ts/nosqldb/classes.cached-document.ts +67 -0
- package/ts/nosqldb/classes.collection.ts +2399 -0
- package/ts/nosqldb/classes.collectionfactory.ts +87 -0
- package/ts/nosqldb/classes.collectionlifecycle.ts +24 -0
- package/ts/nosqldb/classes.collectionpreparation.ts +164 -0
- package/ts/nosqldb/classes.collectiontopology.ts +645 -0
- package/ts/nosqldb/classes.connection.ts +31 -0
- package/ts/nosqldb/classes.convenience.ts +5 -0
- package/ts/nosqldb/classes.cursor.ts +88 -0
- package/ts/nosqldb/classes.cursoroperation.ts +38 -0
- package/ts/nosqldb/classes.db.ts +637 -0
- package/ts/nosqldb/classes.distributedcoordinator.ts +305 -0
- package/ts/nosqldb/classes.doc.ts +4928 -0
- package/ts/nosqldb/classes.easystore.ts +154 -0
- package/ts/nosqldb/classes.exactpersistence.ts +1974 -0
- package/ts/nosqldb/classes.lucene.adapter.ts +780 -0
- package/ts/nosqldb/classes.mongoadministration.ts +867 -0
- package/ts/nosqldb/classes.namespaceinspection.ts +199 -0
- package/ts/nosqldb/classes.operationbudget.ts +75 -0
- package/ts/nosqldb/classes.ordinarypersistence.ts +84 -0
- package/ts/nosqldb/classes.persistence.ts +62 -0
- package/ts/nosqldb/classes.session.ts +389 -0
- package/ts/nosqldb/classes.storedinspection.ts +151 -0
- package/ts/nosqldb/classes.testdatabase.ts +272 -0
- package/ts/nosqldb/classes.watcher.ts +96 -0
- package/ts/nosqldb/index.ts +51 -0
- package/ts/nosqldb/logging.ts +3 -0
- package/ts/nosqldb/plugins.ts +37 -0
- package/ts/nosqldb/shim.ts +6 -0
- package/ts/nosqldb/testsupport.ts +13 -0
- package/ts/objectstorage/classes.bucket.ts +1114 -0
- package/ts/objectstorage/classes.connection.ts +36 -0
- package/ts/objectstorage/classes.directory.ts +425 -0
- package/ts/objectstorage/classes.exactpathpurgeerror.ts +24 -0
- package/ts/objectstorage/classes.exactuploaderror.ts +25 -0
- package/ts/objectstorage/classes.file.ts +303 -0
- package/ts/objectstorage/classes.listcursor.ts +89 -0
- package/ts/objectstorage/classes.metadata.ts +134 -0
- package/ts/objectstorage/classes.smartbucket.ts +445 -0
- package/ts/objectstorage/classes.trash.ts +30 -0
- package/ts/objectstorage/classes.watcher.ts +289 -0
- package/ts/objectstorage/helpers.ts +254 -0
- package/ts/objectstorage/index.ts +13 -0
- package/ts/objectstorage/interfaces.ts +389 -0
- package/ts/objectstorage/internal.exactpathpurge.operations.ts +1936 -0
- package/ts/objectstorage/internal.exactupload.capability.ts +580 -0
- package/ts/objectstorage/internal.exactupload.operations.ts +1715 -0
- package/ts/objectstorage/internal.multipart.planner.ts +90 -0
- package/ts/objectstorage/internal.multipart.stream.ts +606 -0
- package/ts/objectstorage/internal.multipart.types.ts +106 -0
- package/ts/objectstorage/plugins.ts +35 -0
- package/ts/plugins.ts +4 -0
- package/ts/sqldb/classes.clickhouseconnection.ts +189 -0
- package/ts/sqldb/classes.sqlconnection.ts +350 -0
- package/ts/sqldb/classes.sqltable.ts +70 -0
- package/ts/sqldb/clickhouse/classes.metricwriter.ts +72 -0
- package/ts/sqldb/clickhouse/index.ts +16 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.clickhousetable.ts +372 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.httpclient.ts +52 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.querybuilder.ts +120 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.resultset.ts +44 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.smartclickhouse.ts +123 -0
- package/ts/sqldb/clickhouse/smartclickhouse.classes.timedatatable.ts +114 -0
- package/ts/sqldb/clickhouse/smartclickhouse.plugins.ts +5 -0
- package/ts/sqldb/clickhouse/smartclickhouse.types.ts +134 -0
- package/ts/sqldb/index.ts +6 -0
- package/ts/sqldb/interfaces.ts +61 -0
- package/ts/sqldb/internal.sqlpool.ts +179 -0
- package/ts/sqldb/plugins.clickhouse.ts +4 -0
- package/ts/sqldb/plugins.mariadb.ts +4 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { SmartdataDb } from './classes.db.js';
|
|
2
|
+
export interface ISmartdataMongoOperationOptions {
|
|
3
|
+
timeoutMs?: number;
|
|
4
|
+
signal?: AbortSignal;
|
|
5
|
+
}
|
|
6
|
+
export interface ISmartdataMongoReplicaSetExpectation extends ISmartdataMongoOperationOptions {
|
|
7
|
+
expectedSetName: string;
|
|
8
|
+
expectedMemberHost: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ISmartdataMongoReplicaSetMember {
|
|
11
|
+
host: string;
|
|
12
|
+
health: number;
|
|
13
|
+
state: string;
|
|
14
|
+
}
|
|
15
|
+
export type TSmartdataMongoReplicaSetState = 'replication_disabled' | 'uninitialized' | 'exact_primary' | 'exact_non_primary' | 'divergent' | 'unavailable';
|
|
16
|
+
export interface ISmartdataMongoReplicaSetInspection {
|
|
17
|
+
state: TSmartdataMongoReplicaSetState;
|
|
18
|
+
durationMs: number;
|
|
19
|
+
observedSetName?: string;
|
|
20
|
+
observedMembers?: ISmartdataMongoReplicaSetMember[];
|
|
21
|
+
}
|
|
22
|
+
export interface ISmartdataMongoReplicaSetInitializationResult {
|
|
23
|
+
status: 'initiated' | 'already_configured';
|
|
24
|
+
topology: ISmartdataMongoReplicaSetInspection;
|
|
25
|
+
}
|
|
26
|
+
export type TSmartdataMongoTransactionReadinessFailureReason = 'aborted' | 'timeout' | 'unsupported_topology' | 'unavailable' | 'cleanup_failed';
|
|
27
|
+
export type TSmartdataMongoTransactionReadinessResult = {
|
|
28
|
+
ready: true;
|
|
29
|
+
status: 'ready';
|
|
30
|
+
durationMs: number;
|
|
31
|
+
} | {
|
|
32
|
+
ready: false;
|
|
33
|
+
status: 'unavailable';
|
|
34
|
+
reason: TSmartdataMongoTransactionReadinessFailureReason;
|
|
35
|
+
durationMs: number;
|
|
36
|
+
};
|
|
37
|
+
export interface ISmartdataMongoDatabaseUserOptions extends ISmartdataMongoOperationOptions {
|
|
38
|
+
expectedDatabaseName: string;
|
|
39
|
+
username: string;
|
|
40
|
+
password: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ISmartdataMongoDatabaseUserRemovalOptions extends ISmartdataMongoOperationOptions {
|
|
43
|
+
expectedDatabaseName: string;
|
|
44
|
+
username: string;
|
|
45
|
+
}
|
|
46
|
+
export interface ISmartdataMongoDatabaseDropOptions extends ISmartdataMongoOperationOptions {
|
|
47
|
+
expectedDatabaseName: string;
|
|
48
|
+
confirmationDatabaseName: string;
|
|
49
|
+
}
|
|
50
|
+
export declare class SmartdataMongoAdministration {
|
|
51
|
+
private readonly owner;
|
|
52
|
+
private readonly expectedMongoDb;
|
|
53
|
+
private readonly expectedMongoDbClient;
|
|
54
|
+
constructor(ownerArg: SmartdataDb);
|
|
55
|
+
inspectReplicaSet(optionsArg: ISmartdataMongoReplicaSetExpectation): Promise<ISmartdataMongoReplicaSetInspection>;
|
|
56
|
+
initializeSingleMemberReplicaSet(optionsArg: ISmartdataMongoReplicaSetExpectation): Promise<ISmartdataMongoReplicaSetInitializationResult>;
|
|
57
|
+
checkTransactionReadiness(optionsArg?: ISmartdataMongoOperationOptions): Promise<TSmartdataMongoTransactionReadinessResult>;
|
|
58
|
+
ensureReadWriteDatabaseUser(optionsArg: ISmartdataMongoDatabaseUserOptions): Promise<{
|
|
59
|
+
status: 'created' | 'updated';
|
|
60
|
+
}>;
|
|
61
|
+
removeDatabaseUser(optionsArg: ISmartdataMongoDatabaseUserRemovalOptions): Promise<{
|
|
62
|
+
removed: boolean;
|
|
63
|
+
}>;
|
|
64
|
+
dropDatabase(optionsArg: ISmartdataMongoDatabaseDropOptions): Promise<{
|
|
65
|
+
dropped: boolean;
|
|
66
|
+
}>;
|
|
67
|
+
private getConnectedContext;
|
|
68
|
+
private contextIsCurrent;
|
|
69
|
+
private createTopologyResult;
|
|
70
|
+
private assertDatabaseUserOptions;
|
|
71
|
+
private runAdministrationCommand;
|
|
72
|
+
private executeAdministrationCommand;
|
|
73
|
+
}
|
|
@@ -0,0 +1,497 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { SmartdataPersistenceError } from './classes.persistence.js';
|
|
3
|
+
const mongoAdministrationDefaultTimeoutMs = 5_000;
|
|
4
|
+
const mongoAdministrationMaximumTimeoutMs = 30_000;
|
|
5
|
+
const transactionCapabilityCollectionName = '__smartdata_transaction_capability';
|
|
6
|
+
const replicaSetNameRegex = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
7
|
+
const replicaSetMemberRegex = /^([A-Za-z0-9][A-Za-z0-9.-]{0,252}):([0-9]{1,5})$/;
|
|
8
|
+
const databaseNameRegex = /^[^/\\.\s"$*<>:|?\u0000]{1,63}$/;
|
|
9
|
+
const databaseUsernameRegex = /^[^\u0000\r\n]{1,128}$/;
|
|
10
|
+
const assertExactDataObject = (valueArg, expectedKeysArg, descriptionArg) => {
|
|
11
|
+
if (valueArg === null
|
|
12
|
+
|| typeof valueArg !== 'object'
|
|
13
|
+
|| Array.isArray(valueArg)
|
|
14
|
+
|| Object.getPrototypeOf(valueArg) !== Object.prototype) {
|
|
15
|
+
throw new SmartdataPersistenceError('invalid_argument', `${descriptionArg} must be a plain object.`);
|
|
16
|
+
}
|
|
17
|
+
const keys = Reflect.ownKeys(valueArg);
|
|
18
|
+
if (keys.some((keyArg) => (typeof keyArg !== 'string' || !expectedKeysArg.includes(keyArg)))) {
|
|
19
|
+
throw new SmartdataPersistenceError('invalid_argument', `${descriptionArg} has an invalid shape.`);
|
|
20
|
+
}
|
|
21
|
+
for (const key of keys) {
|
|
22
|
+
const descriptor = Object.getOwnPropertyDescriptor(valueArg, key);
|
|
23
|
+
if (!descriptor || !('value' in descriptor)) {
|
|
24
|
+
throw new SmartdataPersistenceError('invalid_argument', `${descriptionArg} must contain data properties only.`);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return valueArg;
|
|
28
|
+
};
|
|
29
|
+
const isAbortSignal = (valueArg) => (valueArg !== null
|
|
30
|
+
&& typeof valueArg === 'object'
|
|
31
|
+
&& typeof valueArg.aborted === 'boolean'
|
|
32
|
+
&& typeof valueArg.addEventListener === 'function');
|
|
33
|
+
const assertOperationOptions = (optionsArg) => {
|
|
34
|
+
const timeoutMs = optionsArg.timeoutMs ?? mongoAdministrationDefaultTimeoutMs;
|
|
35
|
+
if (!Number.isSafeInteger(timeoutMs)
|
|
36
|
+
|| timeoutMs <= 0
|
|
37
|
+
|| timeoutMs > mongoAdministrationMaximumTimeoutMs) {
|
|
38
|
+
throw new SmartdataPersistenceError('invalid_argument', `Mongo administration timeoutMs must be a positive safe integer no greater than ${mongoAdministrationMaximumTimeoutMs}.`);
|
|
39
|
+
}
|
|
40
|
+
if (optionsArg.signal !== undefined && !isAbortSignal(optionsArg.signal)) {
|
|
41
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo administration signal must be an AbortSignal.');
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
timeoutMs: timeoutMs,
|
|
45
|
+
signal: optionsArg.signal,
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
const assertReplicaSetExpectation = (optionsArg) => {
|
|
49
|
+
const options = assertExactDataObject(optionsArg, ['expectedSetName', 'expectedMemberHost', 'timeoutMs', 'signal'], 'Mongo replica-set expectation');
|
|
50
|
+
if (typeof options.expectedSetName !== 'string'
|
|
51
|
+
|| !replicaSetNameRegex.test(options.expectedSetName)) {
|
|
52
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo expectedSetName must be a canonical replica-set name.');
|
|
53
|
+
}
|
|
54
|
+
if (typeof options.expectedMemberHost !== 'string') {
|
|
55
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo expectedMemberHost must be a canonical hostname and port.');
|
|
56
|
+
}
|
|
57
|
+
const memberMatch = replicaSetMemberRegex.exec(options.expectedMemberHost);
|
|
58
|
+
const port = memberMatch ? Number(memberMatch[2]) : 0;
|
|
59
|
+
if (!memberMatch || port < 1 || port > 65_535) {
|
|
60
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo expectedMemberHost must be a canonical hostname and port.');
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
expectedSetName: options.expectedSetName,
|
|
64
|
+
expectedMemberHost: options.expectedMemberHost,
|
|
65
|
+
...assertOperationOptions(options),
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
const isMongoServerError = (errorArg, codeArg, codeNameArg) => errorArg instanceof plugins.mongodb.MongoServerError
|
|
69
|
+
&& (errorArg.code === codeArg || errorArg.codeName === codeNameArg);
|
|
70
|
+
const isMongoTimeoutError = (errorArg) => (errorArg instanceof plugins.mongodb.MongoOperationTimeoutError);
|
|
71
|
+
const isUnsupportedTransactionTopologyError = (errorArg) => (isMongoServerError(errorArg, 20, 'IllegalOperation')
|
|
72
|
+
|| isMongoServerError(errorArg, 263, 'OperationNotSupportedInTransaction'));
|
|
73
|
+
const isUserAlreadyExistsError = (errorArg) => (isMongoServerError(errorArg, 51_003, 'UserAlreadyExists')
|
|
74
|
+
|| isMongoServerError(errorArg, 51_003, 'Location51003'));
|
|
75
|
+
const isUserNotFoundError = (errorArg) => (isMongoServerError(errorArg, 11, 'UserNotFound'));
|
|
76
|
+
export class SmartdataMongoAdministration {
|
|
77
|
+
owner;
|
|
78
|
+
expectedMongoDb;
|
|
79
|
+
expectedMongoDbClient;
|
|
80
|
+
constructor(ownerArg) {
|
|
81
|
+
if (ownerArg.status !== 'connected'
|
|
82
|
+
|| !ownerArg.mongoDb
|
|
83
|
+
|| !ownerArg.mongoDbClient
|
|
84
|
+
|| ownerArg.mongoDb.client !== ownerArg.mongoDbClient) {
|
|
85
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo administration requires a connected SmartData database.');
|
|
86
|
+
}
|
|
87
|
+
this.owner = ownerArg;
|
|
88
|
+
this.expectedMongoDb = ownerArg.mongoDb;
|
|
89
|
+
this.expectedMongoDbClient = ownerArg.mongoDbClient;
|
|
90
|
+
}
|
|
91
|
+
async inspectReplicaSet(optionsArg) {
|
|
92
|
+
const options = assertReplicaSetExpectation(optionsArg);
|
|
93
|
+
const startedAt = performance.now();
|
|
94
|
+
const context = this.getConnectedContext();
|
|
95
|
+
if (options.signal?.aborted) {
|
|
96
|
+
return {
|
|
97
|
+
state: 'unavailable',
|
|
98
|
+
durationMs: performance.now() - startedAt,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
let status;
|
|
102
|
+
try {
|
|
103
|
+
status = await context.mongoDb.admin().command({ replSetGetStatus: 1 }, {
|
|
104
|
+
timeoutMS: options.timeoutMs,
|
|
105
|
+
signal: options.signal,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (errorArg) {
|
|
109
|
+
if (!this.contextIsCurrent(context)) {
|
|
110
|
+
return this.createTopologyResult('unavailable', startedAt);
|
|
111
|
+
}
|
|
112
|
+
if (isMongoServerError(errorArg, 76, 'NoReplicationEnabled')) {
|
|
113
|
+
return this.createTopologyResult('replication_disabled', startedAt);
|
|
114
|
+
}
|
|
115
|
+
if (isMongoServerError(errorArg, 94, 'NotYetInitialized')) {
|
|
116
|
+
return this.createTopologyResult('uninitialized', startedAt);
|
|
117
|
+
}
|
|
118
|
+
return this.createTopologyResult('unavailable', startedAt);
|
|
119
|
+
}
|
|
120
|
+
if (!this.contextIsCurrent(context)) {
|
|
121
|
+
return this.createTopologyResult('unavailable', startedAt);
|
|
122
|
+
}
|
|
123
|
+
const observedSetName = typeof status.set === 'string' ? status.set : undefined;
|
|
124
|
+
const rawMembers = Array.isArray(status.members) ? status.members : [];
|
|
125
|
+
const observedMembers = [];
|
|
126
|
+
let membersWellFormed = Array.isArray(status.members);
|
|
127
|
+
for (const memberArg of rawMembers) {
|
|
128
|
+
if (!memberArg || typeof memberArg !== 'object' || Array.isArray(memberArg)) {
|
|
129
|
+
membersWellFormed = false;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const member = memberArg;
|
|
133
|
+
if (typeof member.name !== 'string'
|
|
134
|
+
|| typeof member.stateStr !== 'string'
|
|
135
|
+
|| typeof member.health !== 'number'
|
|
136
|
+
|| !Number.isFinite(member.health)) {
|
|
137
|
+
membersWellFormed = false;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
observedMembers.push({
|
|
141
|
+
host: member.name,
|
|
142
|
+
health: member.health,
|
|
143
|
+
state: member.stateStr,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const exactConfiguration = membersWellFormed
|
|
147
|
+
&& rawMembers.length === observedMembers.length
|
|
148
|
+
&& observedSetName === options.expectedSetName
|
|
149
|
+
&& observedMembers.length === 1
|
|
150
|
+
&& observedMembers[0].host === options.expectedMemberHost;
|
|
151
|
+
if (!exactConfiguration) {
|
|
152
|
+
return {
|
|
153
|
+
state: 'divergent',
|
|
154
|
+
observedSetName,
|
|
155
|
+
observedMembers,
|
|
156
|
+
durationMs: performance.now() - startedAt,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const exactPrimary = status.myState === 1
|
|
160
|
+
&& observedMembers[0].state === 'PRIMARY'
|
|
161
|
+
&& observedMembers[0].health === 1;
|
|
162
|
+
return {
|
|
163
|
+
state: exactPrimary ? 'exact_primary' : 'exact_non_primary',
|
|
164
|
+
observedSetName,
|
|
165
|
+
observedMembers,
|
|
166
|
+
durationMs: performance.now() - startedAt,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
async initializeSingleMemberReplicaSet(optionsArg) {
|
|
170
|
+
const options = assertReplicaSetExpectation(optionsArg);
|
|
171
|
+
const topology = await this.inspectReplicaSet(options);
|
|
172
|
+
if (topology.state === 'exact_primary' || topology.state === 'exact_non_primary') {
|
|
173
|
+
return {
|
|
174
|
+
status: 'already_configured',
|
|
175
|
+
topology,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
if (topology.state === 'divergent') {
|
|
179
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Mongo replica-set configuration differs from the exact expected topology.');
|
|
180
|
+
}
|
|
181
|
+
if (topology.state === 'replication_disabled') {
|
|
182
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Mongo replication must be enabled before replica-set initialization.');
|
|
183
|
+
}
|
|
184
|
+
if (topology.state !== 'uninitialized') {
|
|
185
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo replica-set topology is unavailable for initialization.');
|
|
186
|
+
}
|
|
187
|
+
const context = this.getConnectedContext();
|
|
188
|
+
let initializationStatus = 'initiated';
|
|
189
|
+
try {
|
|
190
|
+
const response = await context.mongoDb.admin().command({
|
|
191
|
+
replSetInitiate: {
|
|
192
|
+
_id: options.expectedSetName,
|
|
193
|
+
members: [{
|
|
194
|
+
_id: 0,
|
|
195
|
+
host: options.expectedMemberHost,
|
|
196
|
+
}],
|
|
197
|
+
},
|
|
198
|
+
}, {
|
|
199
|
+
timeoutMS: options.timeoutMs,
|
|
200
|
+
signal: options.signal,
|
|
201
|
+
});
|
|
202
|
+
if (response.ok !== 1 || !this.contextIsCurrent(context)) {
|
|
203
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo did not acknowledge replica-set initialization.');
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (errorArg) {
|
|
207
|
+
if (isMongoServerError(errorArg, 23, 'AlreadyInitialized')) {
|
|
208
|
+
initializationStatus = 'already_configured';
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
if (errorArg instanceof SmartdataPersistenceError)
|
|
212
|
+
throw errorArg;
|
|
213
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo replica-set initialization failed.');
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const initializedTopology = await this.inspectReplicaSet(options);
|
|
217
|
+
if (initializedTopology.state === 'divergent') {
|
|
218
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Mongo initialized a replica-set topology that differs from the expectation.');
|
|
219
|
+
}
|
|
220
|
+
if (initializedTopology.state !== 'exact_primary'
|
|
221
|
+
&& initializedTopology.state !== 'exact_non_primary') {
|
|
222
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo replica-set initialization could not prove the exact expected topology.');
|
|
223
|
+
}
|
|
224
|
+
return {
|
|
225
|
+
status: initializationStatus,
|
|
226
|
+
topology: initializedTopology,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
async checkTransactionReadiness(optionsArg = {}) {
|
|
230
|
+
const options = assertExactDataObject(optionsArg, ['timeoutMs', 'signal'], 'Mongo transaction-readiness options');
|
|
231
|
+
const boundedOptions = assertOperationOptions(options);
|
|
232
|
+
const startedAt = performance.now();
|
|
233
|
+
const context = this.getConnectedContext();
|
|
234
|
+
const probeId = globalThis.crypto.randomUUID();
|
|
235
|
+
const collection = context.mongoDb.collection(transactionCapabilityCollectionName);
|
|
236
|
+
let session;
|
|
237
|
+
let failure;
|
|
238
|
+
let cleanupFailed = false;
|
|
239
|
+
try {
|
|
240
|
+
try {
|
|
241
|
+
await context.mongoDb.command({ create: transactionCapabilityCollectionName }, {
|
|
242
|
+
timeoutMS: boundedOptions.timeoutMs,
|
|
243
|
+
signal: boundedOptions.signal,
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
catch (errorArg) {
|
|
247
|
+
if (!isMongoServerError(errorArg, 48, 'NamespaceExists'))
|
|
248
|
+
throw errorArg;
|
|
249
|
+
}
|
|
250
|
+
session = context.mongoDbClient.startSession();
|
|
251
|
+
session.startTransaction({
|
|
252
|
+
readConcern: { level: 'snapshot' },
|
|
253
|
+
writeConcern: { w: 'majority' },
|
|
254
|
+
});
|
|
255
|
+
const insertResponse = await context.mongoDb.command({
|
|
256
|
+
insert: transactionCapabilityCollectionName,
|
|
257
|
+
documents: [
|
|
258
|
+
{ _id: `${probeId}:1`, probeId, part: 1 },
|
|
259
|
+
{ _id: `${probeId}:2`, probeId, part: 2 },
|
|
260
|
+
],
|
|
261
|
+
ordered: true,
|
|
262
|
+
}, {
|
|
263
|
+
session,
|
|
264
|
+
timeoutMS: boundedOptions.timeoutMs,
|
|
265
|
+
signal: boundedOptions.signal,
|
|
266
|
+
});
|
|
267
|
+
if (insertResponse.ok !== 1 || insertResponse.n !== 2) {
|
|
268
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo transaction probe did not acknowledge both writes.');
|
|
269
|
+
}
|
|
270
|
+
const abortResponse = await context.mongoDb.admin().command({
|
|
271
|
+
abortTransaction: 1,
|
|
272
|
+
writeConcern: {
|
|
273
|
+
w: 'majority',
|
|
274
|
+
wtimeout: boundedOptions.timeoutMs,
|
|
275
|
+
},
|
|
276
|
+
}, {
|
|
277
|
+
session,
|
|
278
|
+
timeoutMS: boundedOptions.timeoutMs,
|
|
279
|
+
signal: boundedOptions.signal,
|
|
280
|
+
});
|
|
281
|
+
if (abortResponse.ok !== 1 || !this.contextIsCurrent(context)) {
|
|
282
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo transaction probe did not acknowledge its abort.');
|
|
283
|
+
}
|
|
284
|
+
// The acknowledged raw command proves the server-side abort. Calling the
|
|
285
|
+
// public driver method afterwards advances its local transaction state;
|
|
286
|
+
// that method intentionally ignores most server-side abort errors.
|
|
287
|
+
await session.abortTransaction({ timeoutMS: boundedOptions.timeoutMs });
|
|
288
|
+
const remainingCount = await collection.countDocuments({ probeId }, {
|
|
289
|
+
limit: 2,
|
|
290
|
+
timeoutMS: boundedOptions.timeoutMs,
|
|
291
|
+
signal: boundedOptions.signal,
|
|
292
|
+
});
|
|
293
|
+
if (remainingCount !== 0 || !this.contextIsCurrent(context)) {
|
|
294
|
+
cleanupFailed = remainingCount !== 0;
|
|
295
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo transaction probe did not abort cleanly.');
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
ready: true,
|
|
299
|
+
status: 'ready',
|
|
300
|
+
durationMs: performance.now() - startedAt,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
catch (errorArg) {
|
|
304
|
+
failure = errorArg;
|
|
305
|
+
if (session?.inTransaction()) {
|
|
306
|
+
try {
|
|
307
|
+
await session.abortTransaction({ timeoutMS: boundedOptions.timeoutMs });
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
cleanupFailed = true;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
try {
|
|
314
|
+
await collection.deleteMany({ probeId }, { timeoutMS: boundedOptions.timeoutMs });
|
|
315
|
+
}
|
|
316
|
+
catch {
|
|
317
|
+
cleanupFailed = true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
finally {
|
|
321
|
+
await session?.endSession().catch(() => undefined);
|
|
322
|
+
}
|
|
323
|
+
let reason;
|
|
324
|
+
if (cleanupFailed) {
|
|
325
|
+
reason = 'cleanup_failed';
|
|
326
|
+
}
|
|
327
|
+
else if (boundedOptions.signal?.aborted) {
|
|
328
|
+
reason = 'aborted';
|
|
329
|
+
}
|
|
330
|
+
else if (isMongoTimeoutError(failure)) {
|
|
331
|
+
reason = 'timeout';
|
|
332
|
+
}
|
|
333
|
+
else if (isUnsupportedTransactionTopologyError(failure)) {
|
|
334
|
+
reason = 'unsupported_topology';
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
reason = 'unavailable';
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
ready: false,
|
|
341
|
+
status: 'unavailable',
|
|
342
|
+
reason,
|
|
343
|
+
durationMs: performance.now() - startedAt,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
async ensureReadWriteDatabaseUser(optionsArg) {
|
|
347
|
+
const options = this.assertDatabaseUserOptions(optionsArg, true);
|
|
348
|
+
const context = this.getConnectedContext(options.expectedDatabaseName);
|
|
349
|
+
const usersInfo = await this.runAdministrationCommand(context, {
|
|
350
|
+
usersInfo: {
|
|
351
|
+
user: options.username,
|
|
352
|
+
db: options.expectedDatabaseName,
|
|
353
|
+
},
|
|
354
|
+
}, options, 'Mongo database-user inspection failed.');
|
|
355
|
+
if (!Array.isArray(usersInfo.users) || usersInfo.users.length > 1) {
|
|
356
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo database-user inspection returned an invalid result.');
|
|
357
|
+
}
|
|
358
|
+
const updateCommand = {
|
|
359
|
+
updateUser: options.username,
|
|
360
|
+
pwd: options.password,
|
|
361
|
+
roles: [{ role: 'readWrite', db: options.expectedDatabaseName }],
|
|
362
|
+
};
|
|
363
|
+
if (usersInfo.users.length === 1) {
|
|
364
|
+
await this.runAdministrationCommand(context, updateCommand, options, 'Mongo database-user reconciliation failed.');
|
|
365
|
+
return { status: 'updated' };
|
|
366
|
+
}
|
|
367
|
+
try {
|
|
368
|
+
await this.executeAdministrationCommand(context, {
|
|
369
|
+
createUser: options.username,
|
|
370
|
+
pwd: options.password,
|
|
371
|
+
roles: [{ role: 'readWrite', db: options.expectedDatabaseName }],
|
|
372
|
+
}, options);
|
|
373
|
+
return { status: 'created' };
|
|
374
|
+
}
|
|
375
|
+
catch (errorArg) {
|
|
376
|
+
if (!isUserAlreadyExistsError(errorArg)) {
|
|
377
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo database-user reconciliation failed.');
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
await this.runAdministrationCommand(context, updateCommand, options, 'Mongo database-user reconciliation failed.');
|
|
381
|
+
return { status: 'updated' };
|
|
382
|
+
}
|
|
383
|
+
async removeDatabaseUser(optionsArg) {
|
|
384
|
+
const options = this.assertDatabaseUserOptions(optionsArg, false);
|
|
385
|
+
const context = this.getConnectedContext(options.expectedDatabaseName);
|
|
386
|
+
const usersInfo = await this.runAdministrationCommand(context, {
|
|
387
|
+
usersInfo: {
|
|
388
|
+
user: options.username,
|
|
389
|
+
db: options.expectedDatabaseName,
|
|
390
|
+
},
|
|
391
|
+
}, options, 'Mongo database-user inspection failed.');
|
|
392
|
+
if (!Array.isArray(usersInfo.users) || usersInfo.users.length > 1) {
|
|
393
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo database-user inspection returned an invalid result.');
|
|
394
|
+
}
|
|
395
|
+
if (usersInfo.users.length === 0)
|
|
396
|
+
return { removed: false };
|
|
397
|
+
try {
|
|
398
|
+
await this.executeAdministrationCommand(context, { dropUser: options.username }, options);
|
|
399
|
+
}
|
|
400
|
+
catch (errorArg) {
|
|
401
|
+
if (isUserNotFoundError(errorArg))
|
|
402
|
+
return { removed: false };
|
|
403
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo database-user removal failed.');
|
|
404
|
+
}
|
|
405
|
+
return { removed: true };
|
|
406
|
+
}
|
|
407
|
+
async dropDatabase(optionsArg) {
|
|
408
|
+
const options = assertExactDataObject(optionsArg, ['expectedDatabaseName', 'confirmationDatabaseName', 'timeoutMs', 'signal'], 'Mongo database-drop options');
|
|
409
|
+
if (typeof options.expectedDatabaseName !== 'string'
|
|
410
|
+
|| !databaseNameRegex.test(options.expectedDatabaseName)) {
|
|
411
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo expectedDatabaseName must be a canonical database name.');
|
|
412
|
+
}
|
|
413
|
+
if (options.confirmationDatabaseName !== options.expectedDatabaseName
|
|
414
|
+
|| ['admin', 'config', 'local'].includes(options.expectedDatabaseName)) {
|
|
415
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo database-drop confirmation must exactly match a non-system database.');
|
|
416
|
+
}
|
|
417
|
+
const context = this.getConnectedContext(options.expectedDatabaseName);
|
|
418
|
+
await this.runAdministrationCommand(context, { dropDatabase: 1 }, assertOperationOptions(options), 'Mongo database removal failed.');
|
|
419
|
+
return { dropped: true };
|
|
420
|
+
}
|
|
421
|
+
getConnectedContext(expectedDatabaseNameArg) {
|
|
422
|
+
if (this.owner.status !== 'connected'
|
|
423
|
+
|| !this.owner.mongoDb
|
|
424
|
+
|| !this.owner.mongoDbClient
|
|
425
|
+
|| this.owner.mongoDb.client !== this.owner.mongoDbClient
|
|
426
|
+
|| this.owner.mongoDb !== this.expectedMongoDb
|
|
427
|
+
|| this.owner.mongoDbClient !== this.expectedMongoDbClient) {
|
|
428
|
+
throw new SmartdataPersistenceError('unsupported_operation', 'Mongo administration requires a connected SmartData database.');
|
|
429
|
+
}
|
|
430
|
+
if (expectedDatabaseNameArg !== undefined
|
|
431
|
+
&& (this.owner.mongoDb.databaseName !== expectedDatabaseNameArg
|
|
432
|
+
|| this.owner.smartdataOptions.mongoDbName !== expectedDatabaseNameArg)) {
|
|
433
|
+
throw new SmartdataPersistenceError('invalid_configuration', 'Mongo expectedDatabaseName does not match the connected database.');
|
|
434
|
+
}
|
|
435
|
+
return {
|
|
436
|
+
mongoDb: this.owner.mongoDb,
|
|
437
|
+
mongoDbClient: this.owner.mongoDbClient,
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
contextIsCurrent(contextArg) {
|
|
441
|
+
return this.owner.status === 'connected'
|
|
442
|
+
&& this.owner.mongoDb === contextArg.mongoDb
|
|
443
|
+
&& this.owner.mongoDbClient === contextArg.mongoDbClient;
|
|
444
|
+
}
|
|
445
|
+
createTopologyResult(stateArg, startedAtArg) {
|
|
446
|
+
return {
|
|
447
|
+
state: stateArg,
|
|
448
|
+
durationMs: performance.now() - startedAtArg,
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
assertDatabaseUserOptions(optionsArg, hasPasswordArg) {
|
|
452
|
+
const allowedKeys = hasPasswordArg
|
|
453
|
+
? ['expectedDatabaseName', 'username', 'password', 'timeoutMs', 'signal']
|
|
454
|
+
: ['expectedDatabaseName', 'username', 'timeoutMs', 'signal'];
|
|
455
|
+
const options = assertExactDataObject(optionsArg, allowedKeys, 'Mongo database-user options');
|
|
456
|
+
if (typeof options.expectedDatabaseName !== 'string'
|
|
457
|
+
|| !databaseNameRegex.test(options.expectedDatabaseName)) {
|
|
458
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo expectedDatabaseName must be a canonical database name.');
|
|
459
|
+
}
|
|
460
|
+
if (typeof options.username !== 'string'
|
|
461
|
+
|| !databaseUsernameRegex.test(options.username)) {
|
|
462
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo database username must be a bounded string without control characters.');
|
|
463
|
+
}
|
|
464
|
+
if (hasPasswordArg
|
|
465
|
+
&& (typeof options.password !== 'string'
|
|
466
|
+
|| options.password.length < 16
|
|
467
|
+
|| options.password.length > 1024
|
|
468
|
+
|| /[\u0000\r\n]/.test(options.password))) {
|
|
469
|
+
throw new SmartdataPersistenceError('invalid_argument', 'Mongo database-user password must be a bounded nonempty secret without control characters.');
|
|
470
|
+
}
|
|
471
|
+
return {
|
|
472
|
+
expectedDatabaseName: options.expectedDatabaseName,
|
|
473
|
+
username: options.username,
|
|
474
|
+
password: (hasPasswordArg ? options.password : undefined),
|
|
475
|
+
...assertOperationOptions(options),
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
async runAdministrationCommand(contextArg, commandArg, optionsArg, failureMessageArg) {
|
|
479
|
+
try {
|
|
480
|
+
return await this.executeAdministrationCommand(contextArg, commandArg, optionsArg);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
throw new SmartdataPersistenceError('unsupported_operation', failureMessageArg);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
async executeAdministrationCommand(contextArg, commandArg, optionsArg) {
|
|
487
|
+
const response = await contextArg.mongoDb.command(commandArg, {
|
|
488
|
+
timeoutMS: optionsArg.timeoutMs,
|
|
489
|
+
signal: optionsArg.signal,
|
|
490
|
+
});
|
|
491
|
+
if (response.ok !== 1 || !this.contextIsCurrent(contextArg)) {
|
|
492
|
+
throw new Error('Mongo administration acknowledgement was unavailable.');
|
|
493
|
+
}
|
|
494
|
+
return response;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5tb25nb2FkbWluaXN0cmF0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvbm9zcWxkYi9jbGFzc2VzLm1vbmdvYWRtaW5pc3RyYXRpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFHeEMsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUE4RXJFLE1BQU0sbUNBQW1DLEdBQUcsS0FBSyxDQUFDO0FBQ2xELE1BQU0sbUNBQW1DLEdBQUcsTUFBTSxDQUFDO0FBQ25ELE1BQU0sbUNBQW1DLEdBQUcsb0NBQW9DLENBQUM7QUFRakYsTUFBTSxtQkFBbUIsR0FBRyxvQ0FBb0MsQ0FBQztBQUNqRSxNQUFNLHFCQUFxQixHQUFHLGtEQUFrRCxDQUFDO0FBQ2pGLE1BQU0saUJBQWlCLEdBQUcsaUNBQWlDLENBQUM7QUFDNUQsTUFBTSxxQkFBcUIsR0FBRyx3QkFBd0IsQ0FBQztBQUV2RCxNQUFNLHFCQUFxQixHQUFHLENBQzVCLFFBQWlCLEVBQ2pCLGVBQWtDLEVBQ2xDLGNBQXNCLEVBQ0csRUFBRTtJQUMzQixJQUNFLFFBQVEsS0FBSyxJQUFJO1dBQ2QsT0FBTyxRQUFRLEtBQUssUUFBUTtXQUM1QixLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQztXQUN2QixNQUFNLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxTQUFTLEVBQ3ZELENBQUM7UUFDRCxNQUFNLElBQUkseUJBQXlCLENBQ2pDLGtCQUFrQixFQUNsQixHQUFHLGNBQWMsMEJBQTBCLENBQzVDLENBQUM7SUFDSixDQUFDO0lBQ0QsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUN2QyxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLENBQ3hCLE9BQU8s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
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import type { SmartdataDb } from './classes.db.js';
|
|
3
|
+
import { SmartdataSession } from './classes.session.js';
|
|
4
|
+
import { type ISmartdataCollectionTopologyIndex, type TSmartdataCollectionTopologyReasonCode } from './classes.collectiontopology.js';
|
|
5
|
+
export interface ISmartdataNamespaceInspectionOptions {
|
|
6
|
+
/** Default 256, maximum 1024. Overflow fails the entire observation. */
|
|
7
|
+
maxCollections?: number;
|
|
8
|
+
/** Default bounded. Exact counts scan the collection within the shared deadline. */
|
|
9
|
+
documentCountMode?: 'bounded' | 'exact';
|
|
10
|
+
/** Default 1, maximum 10000. Read one additional document to detect overflow. */
|
|
11
|
+
documentCountUpTo?: number;
|
|
12
|
+
/** Cumulative deadline. Default 5000ms, maximum 120000ms. */
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
signal?: AbortSignal;
|
|
15
|
+
/** Owned session for sequential observation; active transactions are unsupported. */
|
|
16
|
+
session?: SmartdataSession;
|
|
17
|
+
}
|
|
18
|
+
export type TSmartdataObservedDocumentCount = {
|
|
19
|
+
readonly kind: 'exact';
|
|
20
|
+
readonly value: number;
|
|
21
|
+
} | {
|
|
22
|
+
readonly kind: 'at_least';
|
|
23
|
+
readonly value: number;
|
|
24
|
+
};
|
|
25
|
+
export interface ISmartdataObservedCollection {
|
|
26
|
+
readonly collectionName: string;
|
|
27
|
+
readonly namespaceType: 'collection' | 'view' | 'other';
|
|
28
|
+
readonly reasonCodes: readonly TSmartdataCollectionTopologyReasonCode[];
|
|
29
|
+
readonly actualIndexes: readonly ISmartdataCollectionTopologyIndex[];
|
|
30
|
+
readonly documentCount: TSmartdataObservedDocumentCount | null;
|
|
31
|
+
}
|
|
32
|
+
export interface ISmartdataNamespaceInspection {
|
|
33
|
+
/** Explicitly observational: catalog and data reads are not an atomic snapshot. */
|
|
34
|
+
readonly consistency: 'observational';
|
|
35
|
+
readonly collections: readonly ISmartdataObservedCollection[];
|
|
36
|
+
}
|
|
37
|
+
/** @internal Bounded catalog reading shared with collection preparation. */
|
|
38
|
+
export declare const readBoundedInspectionCursor: <T>(cursorArg: plugins.mongodb.AbstractCursor<T>, maximumArg: number, signalArg: AbortSignal, closeOptionsArg?: () => {
|
|
39
|
+
timeoutMS: number;
|
|
40
|
+
}) => Promise<T[]>;
|
|
41
|
+
/** @internal Entry point exposed through SmartdataDb.inspectNamespace(). */
|
|
42
|
+
export declare const inspectSmartdataNamespace: (dbArg: SmartdataDb, opts?: ISmartdataNamespaceInspectionOptions) => Promise<ISmartdataNamespaceInspection>;
|