@orion-js/mongodb 4.0.18 → 4.0.20
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/index.cjs +310 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +73 -7
- package/dist/index.d.ts +73 -7
- package/dist/index.js +306 -86
- package/dist/index.js.map +1 -1
- package/package.json +12 -11
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as MongoDB from 'mongodb';
|
|
2
|
-
import { MongoClient, Db, EnhancedOmit } from 'mongodb';
|
|
2
|
+
import { MongoClient, Db, MongoClientOptions, EnhancedOmit, KMSProviders, AWSEncryptionKeyOptions, UUID } from 'mongodb';
|
|
3
3
|
export { MongoDB };
|
|
4
4
|
import { SchemaInAnyOrionForm, Schema, StrictInferSchemaType, TypedSchemaOnSchema, InferSchemaType, FieldType } from '@orion-js/schema';
|
|
5
5
|
|
|
@@ -8,14 +8,51 @@ interface OrionMongoClient {
|
|
|
8
8
|
db: Db;
|
|
9
9
|
uri: string;
|
|
10
10
|
dbName: string;
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Use startConnection() instead. This property is not guaranteed to be resolved if the connection is not started.
|
|
13
|
+
* When using async calls startConnection or connectionPromise is no longer needed. Orion will automatically start the connection if it is not already started.
|
|
14
|
+
* Kept for backwards compatibility. startConnection does not re-start the connection if it is already started, so it is safe to use.
|
|
15
|
+
*/
|
|
11
16
|
connectionPromise: Promise<MongoClient>;
|
|
12
17
|
connectionName: string;
|
|
18
|
+
encrypted: {
|
|
19
|
+
client: MongoClient;
|
|
20
|
+
db: Db;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Starts the connection if it is not already started.
|
|
24
|
+
* If the connection is already started, it resolves immediately.
|
|
25
|
+
*/
|
|
13
26
|
startConnection: () => Promise<MongoClient>;
|
|
27
|
+
closeConnection: () => Promise<void>;
|
|
14
28
|
}
|
|
15
|
-
|
|
16
|
-
|
|
29
|
+
declare class OrionMongoDatabaseWrapper implements OrionMongoClient {
|
|
30
|
+
uri: string;
|
|
31
|
+
dbName: string;
|
|
32
|
+
connectionName: string;
|
|
33
|
+
connectionPromise: Promise<MongoClient>;
|
|
34
|
+
private mongoOptions;
|
|
35
|
+
private connectionEvent;
|
|
36
|
+
private state;
|
|
37
|
+
client: MongoClient;
|
|
38
|
+
db: Db;
|
|
39
|
+
configured: boolean;
|
|
40
|
+
readonly encrypted: {
|
|
41
|
+
client: MongoClient;
|
|
42
|
+
db: Db;
|
|
43
|
+
};
|
|
44
|
+
readonly configTimeout: NodeJS.Timeout;
|
|
45
|
+
constructor(connectionName: string);
|
|
46
|
+
config(mongoURL: string, mongoOptions: MongoClientOptions): void;
|
|
47
|
+
awaitConnection(): Promise<this>;
|
|
48
|
+
connectWithRetry(client: MongoClient): any;
|
|
49
|
+
startConnection(): Promise<MongoClient>;
|
|
50
|
+
closeConnection(): Promise<void>;
|
|
17
51
|
}
|
|
18
|
-
declare
|
|
52
|
+
declare function configureConnection(connectionName: string, mongoOptions: MongoClientOptions): Promise<OrionMongoDatabaseWrapper>;
|
|
53
|
+
declare const connections: {
|
|
54
|
+
[key: string]: OrionMongoDatabaseWrapper;
|
|
55
|
+
};
|
|
19
56
|
|
|
20
57
|
declare const allConnectionPromises: any[];
|
|
21
58
|
interface MongoConnectOptions {
|
|
@@ -141,16 +178,19 @@ type CreateCollectionOptionsWithTypedSchema<T extends TypedSchemaOnSchema & {
|
|
|
141
178
|
}> = {
|
|
142
179
|
schema: T;
|
|
143
180
|
} & Omit<CreateCollectionOptions<InferSchemaType<T>>, 'schema'>;
|
|
144
|
-
declare class
|
|
181
|
+
declare class BaseCollection<ModelClass extends ModelClassBase = ModelClassBase> {
|
|
145
182
|
name: string;
|
|
146
183
|
connectionName?: string;
|
|
147
184
|
schema?: Schema;
|
|
148
|
-
indexes: Array<CollectionIndex>;
|
|
149
185
|
generateId: () => ModelClass['_id'];
|
|
150
186
|
getSchema: () => Schema;
|
|
151
187
|
db: MongoDB.Db;
|
|
152
188
|
client: OrionMongoClient;
|
|
189
|
+
/**
|
|
190
|
+
* @deprecated Use getRawCollection() instead. This property is not guaranteed to be defined if the connection has not been started.
|
|
191
|
+
*/
|
|
153
192
|
rawCollection: MongoDB.Collection<ModelClass>;
|
|
193
|
+
getRawCollection: () => Promise<MongoDB.Collection<ModelClass>>;
|
|
154
194
|
findOne: FindOne<ModelClass>;
|
|
155
195
|
find: Find<ModelClass>;
|
|
156
196
|
insertOne: InsertOne<ModelClass>;
|
|
@@ -182,9 +222,18 @@ declare class Collection<ModelClass extends ModelClassBase = ModelClassBase> {
|
|
|
182
222
|
*/
|
|
183
223
|
createIndexes: () => Promise<string[]>;
|
|
184
224
|
createIndexesPromise: Promise<string[]>;
|
|
225
|
+
/**
|
|
226
|
+
* @deprecated Use startConnection() instead. This property is not guaranteed to be resolved if the connection is not started.
|
|
227
|
+
* When using async calls startConnection or connectionPromise is no longer needed. Orion will automatically start the connection if it is not already started.
|
|
228
|
+
* Kept for backwards compatibility. startConnection does not re-start the connection if it is already started, so it is safe to use.
|
|
229
|
+
*/
|
|
185
230
|
connectionPromise: Promise<MongoDB.MongoClient>;
|
|
186
231
|
startConnection: () => Promise<MongoDB.MongoClient>;
|
|
187
232
|
}
|
|
233
|
+
declare class Collection<ModelClass extends ModelClassBase = ModelClassBase> extends BaseCollection<ModelClass> {
|
|
234
|
+
indexes: Array<CollectionIndex>;
|
|
235
|
+
encrypted?: BaseCollection<ModelClass>;
|
|
236
|
+
}
|
|
188
237
|
type DistinctDocumentId<DistinctId extends string> = string & {
|
|
189
238
|
__TYPE__: `DistinctDocumentId<${DistinctId}>`;
|
|
190
239
|
};
|
|
@@ -219,4 +268,21 @@ declare function createCollection<T extends TypedSchemaOnSchema & {
|
|
|
219
268
|
}>(options: CreateCollectionOptionsWithTypedSchema<T>): Collection<InferSchemaType<T>>;
|
|
220
269
|
declare function createCollection<T extends ModelClassBase>(options: CreateCollectionOptions<T>): Collection<T>;
|
|
221
270
|
|
|
222
|
-
|
|
271
|
+
declare function getOrCreateEncryptionKey({ keyAltName, kmsProvider, masterKey, connectionName, keyVaultDatabase, keyVaultCollection, kmsProviders, }: {
|
|
272
|
+
keyAltName: string;
|
|
273
|
+
kmsProvider: keyof KMSProviders;
|
|
274
|
+
masterKey?: AWSEncryptionKeyOptions;
|
|
275
|
+
connectionName?: string;
|
|
276
|
+
keyVaultDatabase?: string;
|
|
277
|
+
keyVaultCollection?: string;
|
|
278
|
+
kmsProviders: KMSProviders;
|
|
279
|
+
}): Promise<{
|
|
280
|
+
key: UUID;
|
|
281
|
+
keyVaultNamespace: string;
|
|
282
|
+
}>;
|
|
283
|
+
declare const ENCRYPTION_ALGORITHMS: {
|
|
284
|
+
DETERMINISTIC: string;
|
|
285
|
+
RANDOM: string;
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
export { BaseCollection, Collection, type CollectionIndex, type CountDocuments, type CreateCollectionOptions, type CreateCollectionOptionsWithSchemaType, type CreateCollectionOptionsWithTypedSchema, DataLoader, type DeleteMany, type DeleteOne, type DistinctDocumentId, type DocumentWithId, ENCRYPTION_ALGORITHMS, type EstimatedDocumentCount, type Find, type FindCursor, type FindOne, type FindOneAndUpdate, type FindOneAndUpdateUpdateOptions, type InferIdType, type InferSchemaTypeWithId, type InitItem, type InsertAndFind, type InsertMany, type InsertOne, type InsertOptions, type ModelClassBase, type ModelToMongoSelector, MongoCollection, type MongoFilter, type MongoSelector, type OptionalId, Repository, type SchemaWithRequiredId, type TypedId, type UpdateAndFind, type UpdateItem, type UpdateMany, type UpdateOne, type UpdateOptions, type Upsert, allConnectionPromises, configureConnection, connections, createCollection, createIndexesPromises, getMongoConnection, getOrCreateEncryptionKey, typedId };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
// src/connect/connections.ts
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
// src/connect/getMongoConnection.ts
|
|
2
|
+
import { EventEmitter } from "events";
|
|
5
3
|
import { MongoClient } from "mongodb";
|
|
6
4
|
|
|
7
5
|
// src/connect/getDBName.ts
|
|
@@ -24,10 +22,14 @@ function getDBName(url) {
|
|
|
24
22
|
return dbName;
|
|
25
23
|
}
|
|
26
24
|
|
|
25
|
+
// src/connect/connections.ts
|
|
26
|
+
import { nextTick } from "process";
|
|
27
|
+
import { logger } from "@orion-js/logger";
|
|
28
|
+
import { sleep } from "@orion-js/helpers";
|
|
29
|
+
|
|
27
30
|
// src/connect/getMongoURLFromEnv.ts
|
|
28
31
|
import { internalGetEnv } from "@orion-js/env";
|
|
29
32
|
var getMongoURLFromEnv = (connectionName) => {
|
|
30
|
-
var _a;
|
|
31
33
|
if (connectionName === "main") {
|
|
32
34
|
if (!internalGetEnv("mongo_url", "MONGO_URL")) {
|
|
33
35
|
throw new Error("MONGO_URL is required");
|
|
@@ -36,7 +38,7 @@ var getMongoURLFromEnv = (connectionName) => {
|
|
|
36
38
|
}
|
|
37
39
|
const envName = `mongo_url_${connectionName.toLowerCase()}`;
|
|
38
40
|
const processEnvName = `MONGO_URL_${connectionName.toUpperCase()}`;
|
|
39
|
-
const uri =
|
|
41
|
+
const uri = internalGetEnv(envName, processEnvName);
|
|
40
42
|
if (!uri) {
|
|
41
43
|
throw new Error(
|
|
42
44
|
`To use the connection "${connectionName}" you must initialize it first calling getMongoConnection({name: "${connectionName}", uri: "MONGOURI"}) or setting the environment variable ${processEnvName}.`
|
|
@@ -44,56 +46,156 @@ var getMongoURLFromEnv = (connectionName) => {
|
|
|
44
46
|
}
|
|
45
47
|
return uri;
|
|
46
48
|
};
|
|
49
|
+
var requiresExplicitSetup = (connectionName) => {
|
|
50
|
+
if (connectionName === "main") {
|
|
51
|
+
const value2 = internalGetEnv("mongo_explicit_setup", "MONGO_EXPLICIT_SETUP");
|
|
52
|
+
return typeof value2 === "boolean" ? value2 : value2 === "true";
|
|
53
|
+
}
|
|
54
|
+
const envName = `mongo_explicit_setup_${connectionName.toLowerCase()}`;
|
|
55
|
+
const processEnvName = `MONGO_EXPLICIT_SETUP_${connectionName.toUpperCase()}`;
|
|
56
|
+
const value = internalGetEnv(envName, processEnvName);
|
|
57
|
+
return typeof value === "boolean" ? value : value === "true";
|
|
58
|
+
};
|
|
47
59
|
|
|
48
|
-
// src/connect/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
// src/connect/connections.ts
|
|
61
|
+
var connectionWrappers = {};
|
|
62
|
+
var OrionMongoDatabaseWrapper = class {
|
|
63
|
+
uri;
|
|
64
|
+
dbName;
|
|
65
|
+
connectionName;
|
|
66
|
+
connectionPromise;
|
|
67
|
+
mongoOptions;
|
|
68
|
+
connectionEvent = new EventEmitter();
|
|
69
|
+
state = "disconnected";
|
|
70
|
+
client;
|
|
71
|
+
db;
|
|
72
|
+
configured = false;
|
|
73
|
+
encrypted = { client: null, db: null };
|
|
74
|
+
configTimeout;
|
|
75
|
+
constructor(connectionName) {
|
|
76
|
+
this.connectionName = connectionName;
|
|
77
|
+
logger.info("New connection requested", {
|
|
78
|
+
connectionName
|
|
79
|
+
});
|
|
80
|
+
this.connectionEvent.setMaxListeners(Number.POSITIVE_INFINITY);
|
|
81
|
+
this.connectionPromise = new Promise((resolve, reject) => {
|
|
82
|
+
if (this.state === "connected") {
|
|
83
|
+
resolve(this.client);
|
|
84
|
+
}
|
|
85
|
+
this.connectionEvent.once("connected", resolve);
|
|
86
|
+
this.connectionEvent.once("error", reject);
|
|
87
|
+
});
|
|
88
|
+
this.configTimeout = setTimeout(() => {
|
|
89
|
+
logger.error(
|
|
90
|
+
"Connection was required but never configured, call configureConnection() or unset the env variable MONGO_EXPLICIT_SETUP",
|
|
91
|
+
{
|
|
92
|
+
connectionName
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
this.connectionEvent.emit("error", new Error("Connection was required but never configured"));
|
|
96
|
+
}, 30 * 1e3);
|
|
97
|
+
}
|
|
98
|
+
config(mongoURL, mongoOptions) {
|
|
99
|
+
var _a;
|
|
100
|
+
this.uri = mongoURL;
|
|
101
|
+
this.mongoOptions = mongoOptions;
|
|
102
|
+
this.configured = true;
|
|
103
|
+
if ((_a = this.mongoOptions) == null ? void 0 : _a.autoEncryption) {
|
|
104
|
+
this.encrypted.client = new MongoClient(mongoURL, {
|
|
105
|
+
retryReads: true,
|
|
106
|
+
...this.mongoOptions
|
|
107
|
+
});
|
|
108
|
+
this.encrypted.db = this.encrypted.client.db(getDBName(this.uri));
|
|
109
|
+
}
|
|
110
|
+
this.client = new MongoClient(mongoURL, {
|
|
111
|
+
retryReads: true,
|
|
112
|
+
...this.mongoOptions,
|
|
113
|
+
autoEncryption: null
|
|
114
|
+
});
|
|
115
|
+
this.db = this.client.db(getDBName(this.uri));
|
|
116
|
+
clearTimeout(this.configTimeout);
|
|
117
|
+
}
|
|
118
|
+
async awaitConnection() {
|
|
119
|
+
if (this.state === "connected") return this;
|
|
120
|
+
if (this.state === "connecting" || !this.configured) {
|
|
121
|
+
await this.connectionPromise;
|
|
122
|
+
return this;
|
|
123
|
+
}
|
|
124
|
+
this.state = "connecting";
|
|
125
|
+
const censoredURI = this.uri.replace(/\/\/.*:.*@/, "//");
|
|
126
|
+
logger.info("Connecting to mongo", {
|
|
127
|
+
uri: censoredURI,
|
|
128
|
+
connectionName: this.connectionName
|
|
129
|
+
});
|
|
130
|
+
if (this.encrypted.client) {
|
|
131
|
+
await this.connectWithRetry(this.encrypted.client);
|
|
132
|
+
logger.info("Successfully connected to encrypted mongo", {
|
|
133
|
+
uri: censoredURI,
|
|
134
|
+
connectionName: this.connectionName
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
await this.connectWithRetry(this.client);
|
|
138
|
+
this.state = "connected";
|
|
139
|
+
this.connectionEvent.emit("connected", this.client);
|
|
140
|
+
logger.info("Successfully connected to mongo", {
|
|
141
|
+
uri: censoredURI,
|
|
142
|
+
connectionName: this.connectionName
|
|
143
|
+
});
|
|
144
|
+
nextTick(() => {
|
|
145
|
+
this.connectionEvent.removeAllListeners();
|
|
146
|
+
this.connectionEvent = null;
|
|
147
|
+
});
|
|
148
|
+
return this;
|
|
149
|
+
}
|
|
150
|
+
async connectWithRetry(client) {
|
|
151
|
+
try {
|
|
152
|
+
return await client.connect();
|
|
153
|
+
} catch (error) {
|
|
154
|
+
logger.error("Error connecting to mongo. Will retry in 5s", {
|
|
155
|
+
error,
|
|
156
|
+
connectionName: this.connectionName
|
|
157
|
+
});
|
|
158
|
+
await sleep(5e3);
|
|
159
|
+
return this.connectWithRetry(client);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async startConnection() {
|
|
163
|
+
return this.awaitConnection().then(() => this.client);
|
|
60
164
|
}
|
|
165
|
+
async closeConnection() {
|
|
166
|
+
var _a, _b, _c;
|
|
167
|
+
if (this.state === "disconnected" || this.state === "disconnecting") return;
|
|
168
|
+
this.state = "disconnecting";
|
|
169
|
+
await ((_a = this.client) == null ? void 0 : _a.close());
|
|
170
|
+
await ((_c = (_b = this.encrypted) == null ? void 0 : _b.client) == null ? void 0 : _c.close());
|
|
171
|
+
this.state = "disconnected";
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
function configureConnection(connectionName, mongoOptions) {
|
|
175
|
+
connectionWrappers[connectionName] = connectionWrappers[connectionName] || new OrionMongoDatabaseWrapper(connectionName);
|
|
176
|
+
const connectionWrapper = connectionWrappers[connectionName];
|
|
177
|
+
if (connectionWrapper.configured) {
|
|
178
|
+
throw new Error("Connection already configured");
|
|
179
|
+
}
|
|
180
|
+
connectionWrapper.config(getMongoURLFromEnv(connectionName), mongoOptions);
|
|
181
|
+
return connectionWrapper.awaitConnection();
|
|
61
182
|
}
|
|
183
|
+
function getExistingConnection(connectionName) {
|
|
184
|
+
connectionWrappers[connectionName] = connectionWrappers[connectionName] || new OrionMongoDatabaseWrapper(connectionName);
|
|
185
|
+
return connectionWrappers[connectionName];
|
|
186
|
+
}
|
|
187
|
+
var connections = connectionWrappers;
|
|
188
|
+
|
|
189
|
+
// src/connect/getMongoConnection.ts
|
|
190
|
+
var allConnectionPromises = [];
|
|
62
191
|
var getMongoConnection = ({ name, uri }) => {
|
|
63
192
|
uri = uri || getMongoURLFromEnv(name);
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
resolveConnected = resolve;
|
|
71
|
-
});
|
|
72
|
-
let internalConnectionPromise;
|
|
73
|
-
const startConnection = async () => {
|
|
74
|
-
if (internalConnectionPromise) {
|
|
75
|
-
return await internalConnectionPromise;
|
|
76
|
-
}
|
|
77
|
-
internalConnectionPromise = connect(client);
|
|
78
|
-
allConnectionPromises.push(internalConnectionPromise);
|
|
79
|
-
internalConnectionPromise.then((client2) => {
|
|
80
|
-
resolveConnected(client2);
|
|
81
|
-
});
|
|
82
|
-
return await internalConnectionPromise;
|
|
83
|
-
};
|
|
84
|
-
const dbName = getDBName(uri);
|
|
85
|
-
const db = client.db(dbName);
|
|
86
|
-
const mongoClient = {
|
|
87
|
-
uri,
|
|
88
|
-
client,
|
|
89
|
-
connectionPromise,
|
|
90
|
-
startConnection,
|
|
91
|
-
dbName,
|
|
92
|
-
db,
|
|
93
|
-
connectionName: name
|
|
94
|
-
};
|
|
95
|
-
connections[name] = mongoClient;
|
|
96
|
-
return mongoClient;
|
|
193
|
+
const connection = getExistingConnection(name);
|
|
194
|
+
if (!connection.configured && !requiresExplicitSetup(name)) {
|
|
195
|
+
connection.config(uri, {});
|
|
196
|
+
}
|
|
197
|
+
allConnectionPromises.push(connection.connectionPromise);
|
|
198
|
+
return connection;
|
|
97
199
|
};
|
|
98
200
|
|
|
99
201
|
// src/types/index.ts
|
|
@@ -101,16 +203,19 @@ import * as MongoDB from "mongodb";
|
|
|
101
203
|
import {
|
|
102
204
|
fieldTypes
|
|
103
205
|
} from "@orion-js/schema";
|
|
104
|
-
var
|
|
206
|
+
var BaseCollection = class {
|
|
105
207
|
name;
|
|
106
208
|
connectionName;
|
|
107
209
|
schema;
|
|
108
|
-
indexes;
|
|
109
210
|
generateId;
|
|
110
211
|
getSchema;
|
|
111
212
|
db;
|
|
112
213
|
client;
|
|
214
|
+
/**
|
|
215
|
+
* @deprecated Use getRawCollection() instead. This property is not guaranteed to be defined if the connection has not been started.
|
|
216
|
+
*/
|
|
113
217
|
rawCollection;
|
|
218
|
+
getRawCollection;
|
|
114
219
|
findOne;
|
|
115
220
|
find;
|
|
116
221
|
insertOne;
|
|
@@ -142,9 +247,18 @@ var Collection = class {
|
|
|
142
247
|
*/
|
|
143
248
|
createIndexes;
|
|
144
249
|
createIndexesPromise;
|
|
250
|
+
/**
|
|
251
|
+
* @deprecated Use startConnection() instead. This property is not guaranteed to be resolved if the connection is not started.
|
|
252
|
+
* When using async calls startConnection or connectionPromise is no longer needed. Orion will automatically start the connection if it is not already started.
|
|
253
|
+
* Kept for backwards compatibility. startConnection does not re-start the connection if it is already started, so it is safe to use.
|
|
254
|
+
*/
|
|
145
255
|
connectionPromise;
|
|
146
256
|
startConnection;
|
|
147
257
|
};
|
|
258
|
+
var Collection = class extends BaseCollection {
|
|
259
|
+
indexes;
|
|
260
|
+
encrypted;
|
|
261
|
+
};
|
|
148
262
|
function typedId(prefix) {
|
|
149
263
|
return {
|
|
150
264
|
...fieldTypes.string,
|
|
@@ -1115,6 +1229,7 @@ function getSchema(options) {
|
|
|
1115
1229
|
}
|
|
1116
1230
|
|
|
1117
1231
|
// src/createCollection/wrapMethods.ts
|
|
1232
|
+
import { logger as logger2 } from "@orion-js/logger";
|
|
1118
1233
|
function wrapMethods(collection) {
|
|
1119
1234
|
const methodsWithPromises = [
|
|
1120
1235
|
"findOne",
|
|
@@ -1149,6 +1264,14 @@ function wrapMethods(collection) {
|
|
|
1149
1264
|
if (typeof collection[methodName2] === "function") {
|
|
1150
1265
|
collection[methodName2] = (...args) => {
|
|
1151
1266
|
collection.startConnection();
|
|
1267
|
+
if (!collection.rawCollection) {
|
|
1268
|
+
logger2.error("Method called before connection was initialized", {
|
|
1269
|
+
collectionName: collection.name,
|
|
1270
|
+
connectionName: collection.connectionName,
|
|
1271
|
+
methodName: methodName2
|
|
1272
|
+
});
|
|
1273
|
+
throw new Error("Method called before connection was initialized");
|
|
1274
|
+
}
|
|
1152
1275
|
return originalMethods[methodName2](...args);
|
|
1153
1276
|
};
|
|
1154
1277
|
}
|
|
@@ -1164,56 +1287,91 @@ function createCollection(options) {
|
|
|
1164
1287
|
if (!orionConnection) {
|
|
1165
1288
|
throw new Error(`The connection to MongoDB "${connectionName}" was not found`);
|
|
1166
1289
|
}
|
|
1167
|
-
const db = orionConnection.db;
|
|
1168
|
-
const rawCollection = db.collection(options.name);
|
|
1169
1290
|
const schema = getSchema(options);
|
|
1170
|
-
|
|
1291
|
+
let resolveCollectionPromise;
|
|
1292
|
+
const collectionPromise = new Promise((resolve) => {
|
|
1293
|
+
resolveCollectionPromise = resolve;
|
|
1294
|
+
});
|
|
1295
|
+
const baseCollection = {
|
|
1171
1296
|
name: options.name,
|
|
1172
1297
|
connectionName,
|
|
1173
1298
|
schema,
|
|
1174
1299
|
indexes: options.indexes || [],
|
|
1175
|
-
db,
|
|
1176
1300
|
client: orionConnection,
|
|
1177
|
-
connectionPromise:
|
|
1178
|
-
startConnection: orionConnection.startConnection,
|
|
1179
|
-
rawCollection,
|
|
1301
|
+
connectionPromise: collectionPromise,
|
|
1302
|
+
startConnection: () => orionConnection.startConnection(),
|
|
1180
1303
|
generateId: generateId_default(options),
|
|
1304
|
+
getRawCollection: async () => {
|
|
1305
|
+
await orionConnection.startConnection();
|
|
1306
|
+
return orionConnection.db.collection(options.name);
|
|
1307
|
+
},
|
|
1181
1308
|
getSchema: () => schema
|
|
1182
1309
|
};
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1310
|
+
const encryptedCollection = {
|
|
1311
|
+
...baseCollection,
|
|
1312
|
+
getRawCollection: async () => {
|
|
1313
|
+
await orionConnection.startConnection();
|
|
1314
|
+
return orionConnection.encrypted.db.collection(options.name);
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
1317
|
+
const mainCollection = {
|
|
1318
|
+
...baseCollection,
|
|
1319
|
+
encrypted: encryptedCollection
|
|
1320
|
+
};
|
|
1321
|
+
const defineCollectionProperties = () => {
|
|
1322
|
+
if (orionConnection.db) {
|
|
1323
|
+
mainCollection.db = orionConnection.db;
|
|
1324
|
+
mainCollection.rawCollection = orionConnection.db.collection(options.name);
|
|
1325
|
+
}
|
|
1326
|
+
if (orionConnection.encrypted.db) {
|
|
1327
|
+
encryptedCollection.db = orionConnection.encrypted.db;
|
|
1328
|
+
encryptedCollection.rawCollection = orionConnection.encrypted.db.collection(options.name);
|
|
1329
|
+
}
|
|
1330
|
+
};
|
|
1331
|
+
defineCollectionProperties();
|
|
1332
|
+
orionConnection.connectionPromise.then(() => {
|
|
1333
|
+
defineCollectionProperties();
|
|
1334
|
+
resolveCollectionPromise(orionConnection.client);
|
|
1335
|
+
});
|
|
1336
|
+
const collections = [mainCollection, encryptedCollection];
|
|
1337
|
+
for (const collection of collections) {
|
|
1338
|
+
collection.findOne = findOne_default(collection);
|
|
1339
|
+
collection.find = find_default(collection);
|
|
1340
|
+
collection.findOneAndUpdate = findOneAndUpdate_default(collection);
|
|
1341
|
+
collection.insertOne = insertOne_default(collection);
|
|
1342
|
+
collection.insertMany = insertMany_default(collection);
|
|
1343
|
+
collection.insertAndFind = insertAndFind_default(collection);
|
|
1344
|
+
collection.updateOne = updateOne_default(collection);
|
|
1345
|
+
collection.updateMany = updateMany_default(collection);
|
|
1346
|
+
collection.deleteMany = deleteMany_default(collection);
|
|
1347
|
+
collection.deleteOne = deleteOne_default(collection);
|
|
1348
|
+
collection.upsert = upsert_default(collection);
|
|
1349
|
+
collection.estimatedDocumentCount = estimatedDocumentCount_default(collection);
|
|
1350
|
+
collection.countDocuments = countDocuments_default(collection);
|
|
1351
|
+
collection.updateAndFind = updateAndFind_default(collection);
|
|
1352
|
+
collection.updateItem = updateItem_default(collection);
|
|
1353
|
+
collection.aggregate = (pipeline, options2) => collection.rawCollection.aggregate(pipeline, options2);
|
|
1354
|
+
collection.watch = (pipeline, options2) => collection.rawCollection.watch(pipeline, options2);
|
|
1355
|
+
collection.loadData = loadData_default(collection);
|
|
1356
|
+
collection.loadById = loadById_default(collection);
|
|
1357
|
+
collection.loadOne = loadOne_default(collection);
|
|
1358
|
+
collection.loadMany = loadMany_default(collection);
|
|
1359
|
+
collection.createIndexes = async () => [];
|
|
1360
|
+
}
|
|
1204
1361
|
const createIndexes = async () => {
|
|
1205
|
-
await orionConnection.
|
|
1206
|
-
const createIndexPromise = loadIndexes(
|
|
1362
|
+
await orionConnection.startConnection();
|
|
1363
|
+
const createIndexPromise = loadIndexes(mainCollection);
|
|
1207
1364
|
createIndexesPromises.push(createIndexPromise);
|
|
1208
|
-
|
|
1365
|
+
mainCollection.createIndexesPromise = createIndexPromise;
|
|
1209
1366
|
return createIndexPromise;
|
|
1210
1367
|
};
|
|
1211
|
-
|
|
1368
|
+
mainCollection.createIndexes = createIndexes;
|
|
1212
1369
|
if (!process.env.DONT_CREATE_INDEXES_AUTOMATICALLY) {
|
|
1213
1370
|
createIndexes();
|
|
1214
1371
|
}
|
|
1215
|
-
wrapMethods(
|
|
1216
|
-
|
|
1372
|
+
wrapMethods(mainCollection);
|
|
1373
|
+
wrapMethods(encryptedCollection);
|
|
1374
|
+
return mainCollection;
|
|
1217
1375
|
}
|
|
1218
1376
|
|
|
1219
1377
|
// src/service/index.ts
|
|
@@ -1241,16 +1399,78 @@ function MongoCollection(options) {
|
|
|
1241
1399
|
});
|
|
1242
1400
|
};
|
|
1243
1401
|
}
|
|
1402
|
+
|
|
1403
|
+
// src/encrypted/getOrCreateEncryptionKey.ts
|
|
1404
|
+
import { logger as logger3 } from "@orion-js/logger";
|
|
1405
|
+
import { ClientEncryption, MongoClient as MongoClient2 } from "mongodb";
|
|
1406
|
+
async function getOrCreateEncryptionKey({
|
|
1407
|
+
keyAltName,
|
|
1408
|
+
kmsProvider,
|
|
1409
|
+
masterKey,
|
|
1410
|
+
connectionName = "main",
|
|
1411
|
+
keyVaultDatabase = "encryption",
|
|
1412
|
+
keyVaultCollection = "__keyVault",
|
|
1413
|
+
kmsProviders
|
|
1414
|
+
}) {
|
|
1415
|
+
const keyVaultNamespace = `${keyVaultDatabase}.${keyVaultCollection}`;
|
|
1416
|
+
logger3.info("Connecting to database to get or create the encryption key", {
|
|
1417
|
+
keyVaultNamespace,
|
|
1418
|
+
keyAltName
|
|
1419
|
+
});
|
|
1420
|
+
const client = new MongoClient2(getMongoURLFromEnv(connectionName));
|
|
1421
|
+
await client.connect();
|
|
1422
|
+
const db = client.db(keyVaultDatabase);
|
|
1423
|
+
const collection = db.collection(keyVaultCollection);
|
|
1424
|
+
await collection.createIndex(
|
|
1425
|
+
{ keyAltName: 1 },
|
|
1426
|
+
{ unique: true, partialFilterExpression: { keyAltName: { $exists: true } } }
|
|
1427
|
+
);
|
|
1428
|
+
const clientEncryption = new ClientEncryption(client, {
|
|
1429
|
+
keyVaultNamespace,
|
|
1430
|
+
kmsProviders
|
|
1431
|
+
});
|
|
1432
|
+
const key = await clientEncryption.getKeyByAltName(keyAltName);
|
|
1433
|
+
if (key) {
|
|
1434
|
+
logger3.info("Key found on the key vault", {
|
|
1435
|
+
keyVaultNamespace,
|
|
1436
|
+
keyAltName,
|
|
1437
|
+
UUID: key._id
|
|
1438
|
+
});
|
|
1439
|
+
return { key: key._id, keyVaultNamespace };
|
|
1440
|
+
}
|
|
1441
|
+
logger3.info("Key not found on the key vault, creating a new one", {
|
|
1442
|
+
keyVaultNamespace,
|
|
1443
|
+
keyAltName
|
|
1444
|
+
});
|
|
1445
|
+
const newKey = await clientEncryption.createDataKey(kmsProvider, {
|
|
1446
|
+
keyAltNames: [keyAltName],
|
|
1447
|
+
...masterKey ? { masterKey } : {}
|
|
1448
|
+
});
|
|
1449
|
+
logger3.info("New encryption key created", {
|
|
1450
|
+
keyVaultNamespace,
|
|
1451
|
+
keyAltName,
|
|
1452
|
+
UUID: newKey
|
|
1453
|
+
});
|
|
1454
|
+
return { key: newKey, keyVaultNamespace };
|
|
1455
|
+
}
|
|
1456
|
+
var ENCRYPTION_ALGORITHMS = {
|
|
1457
|
+
DETERMINISTIC: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
|
|
1458
|
+
RANDOM: "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
|
|
1459
|
+
};
|
|
1244
1460
|
export {
|
|
1461
|
+
BaseCollection,
|
|
1245
1462
|
Collection,
|
|
1463
|
+
ENCRYPTION_ALGORITHMS,
|
|
1246
1464
|
MongoCollection,
|
|
1247
1465
|
MongoDB,
|
|
1248
1466
|
Repository,
|
|
1249
1467
|
allConnectionPromises,
|
|
1468
|
+
configureConnection,
|
|
1250
1469
|
connections,
|
|
1251
1470
|
createCollection,
|
|
1252
1471
|
createIndexesPromises,
|
|
1253
1472
|
getMongoConnection,
|
|
1473
|
+
getOrCreateEncryptionKey,
|
|
1254
1474
|
typedId
|
|
1255
1475
|
};
|
|
1256
1476
|
//# sourceMappingURL=index.js.map
|