@friggframework/core 2.0.0-next.53 → 2.0.0-next.54
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/CLAUDE.md +2 -1
- package/application/commands/integration-commands.js +1 -1
- package/application/index.js +1 -1
- package/credential/repositories/credential-repository-documentdb.js +300 -0
- package/credential/repositories/credential-repository-factory.js +8 -1
- package/database/config.js +4 -4
- package/database/documentdb-encryption-service.js +330 -0
- package/database/documentdb-utils.js +136 -0
- package/database/encryption/README.md +50 -0
- package/database/encryption/documentdb-encryption-service.md +3270 -0
- package/database/encryption/encryption-schema-registry.js +46 -0
- package/database/prisma.js +7 -47
- package/database/repositories/health-check-repository-documentdb.js +134 -0
- package/database/repositories/health-check-repository-factory.js +6 -1
- package/database/repositories/health-check-repository-interface.js +29 -34
- package/database/repositories/health-check-repository-mongodb.js +1 -3
- package/database/use-cases/check-database-state-use-case.js +3 -3
- package/database/use-cases/run-database-migration-use-case.js +6 -4
- package/database/use-cases/trigger-database-migration-use-case.js +2 -2
- package/database/utils/mongodb-schema-init.js +5 -5
- package/database/utils/prisma-runner.js +15 -9
- package/generated/prisma-mongodb/edge.js +3 -3
- package/generated/prisma-mongodb/index.d.ts +10 -4
- package/generated/prisma-mongodb/index.js +3 -3
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +1 -3
- package/generated/prisma-mongodb/wasm.js +2 -2
- package/generated/prisma-postgresql/edge.js +3 -3
- package/generated/prisma-postgresql/index.d.ts +10 -4
- package/generated/prisma-postgresql/index.js +3 -3
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +1 -3
- package/generated/prisma-postgresql/wasm.js +2 -2
- package/handlers/routers/db-migration.js +2 -3
- package/handlers/routers/health.js +0 -3
- package/handlers/workers/db-migration.js +8 -8
- package/integrations/repositories/integration-mapping-repository-documentdb.js +135 -0
- package/integrations/repositories/integration-mapping-repository-factory.js +8 -1
- package/integrations/repositories/integration-repository-documentdb.js +189 -0
- package/integrations/repositories/integration-repository-factory.js +8 -1
- package/integrations/repositories/process-repository-documentdb.js +141 -0
- package/integrations/repositories/process-repository-factory.js +8 -1
- package/modules/repositories/module-repository-documentdb.js +307 -0
- package/modules/repositories/module-repository-factory.js +8 -1
- package/package.json +5 -5
- package/prisma-mongodb/schema.prisma +1 -3
- package/prisma-postgresql/migrations/20251112195422_update_user_unique_constraints/migration.sql +69 -0
- package/prisma-postgresql/schema.prisma +1 -3
- package/syncs/repositories/sync-repository-documentdb.js +240 -0
- package/syncs/repositories/sync-repository-factory.js +6 -1
- package/token/repositories/token-repository-documentdb.js +125 -0
- package/token/repositories/token-repository-factory.js +8 -1
- package/user/repositories/user-repository-documentdb.js +292 -0
- package/user/repositories/user-repository-factory.js +6 -1
- package/websocket/repositories/websocket-connection-repository-documentdb.js +119 -0
- package/websocket/repositories/websocket-connection-repository-factory.js +8 -1
package/CLAUDE.md
CHANGED
|
@@ -27,7 +27,7 @@ This file provides guidance to Claude Code when working with the Frigg Framework
|
|
|
27
27
|
`@friggframework/core` is the foundational package of the Frigg Framework, providing:
|
|
28
28
|
|
|
29
29
|
- **IntegrationBase**: Base class all integrations extend
|
|
30
|
-
- **Database Layer**: Multi-database support (MongoDB, PostgreSQL) with Prisma ORM
|
|
30
|
+
- **Database Layer**: Multi-database support (MongoDB, DocumentDB, PostgreSQL) with Prisma ORM
|
|
31
31
|
- **Encryption**: Transparent field-level encryption with AWS KMS or AES
|
|
32
32
|
- **User Management**: Individual and organizational user support
|
|
33
33
|
- **Module System**: API module loading and credential management
|
|
@@ -256,6 +256,7 @@ class MyIntegration extends IntegrationBase {
|
|
|
256
256
|
- `health-check-repository.js` - Database health monitoring
|
|
257
257
|
- `token-repository.js` - Authentication tokens
|
|
258
258
|
- `websocket-connection-repository.js` - WebSocket connections
|
|
259
|
+
- DocumentDB-enabled adapters mirror the MongoDB APIs but execute raw commands (`$runCommandRaw`, `$aggregateRaw`) for compatibility; encrypted models (e.g., credentials) still delegate reads to Prisma so the encryption extension can decrypt secrets transparently.
|
|
259
260
|
|
|
260
261
|
**Use Cases**:
|
|
261
262
|
- `check-database-health-use-case.js` - Database health checks
|
|
@@ -38,7 +38,7 @@ function mapErrorToResponse(error) {
|
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function createIntegrationCommands({ integrationClass }
|
|
41
|
+
function createIntegrationCommands({ integrationClass }) {
|
|
42
42
|
if (!integrationClass) {
|
|
43
43
|
throw new Error('integrationClass is required');
|
|
44
44
|
}
|
package/application/index.js
CHANGED
|
@@ -23,7 +23,7 @@ const {
|
|
|
23
23
|
* const user = await commands.createUser({ username: 'user@example.com' });
|
|
24
24
|
* const credential = await commands.createCredential({ userId: user.id, ... });
|
|
25
25
|
*/
|
|
26
|
-
function createFriggCommands({ integrationClass }
|
|
26
|
+
function createFriggCommands({ integrationClass }) {
|
|
27
27
|
// All commands use Frigg's default repositories and use cases
|
|
28
28
|
const integrationCommands = createIntegrationCommands({ integrationClass });
|
|
29
29
|
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
const { prisma } = require('../../database/prisma');
|
|
2
|
+
const {
|
|
3
|
+
toObjectId,
|
|
4
|
+
fromObjectId,
|
|
5
|
+
findOne,
|
|
6
|
+
insertOne,
|
|
7
|
+
updateOne,
|
|
8
|
+
deleteOne,
|
|
9
|
+
} = require('../../database/documentdb-utils');
|
|
10
|
+
const {
|
|
11
|
+
CredentialRepositoryInterface,
|
|
12
|
+
} = require('./credential-repository-interface');
|
|
13
|
+
const { DocumentDBEncryptionService } = require('../../database/documentdb-encryption-service');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Credential repository for DocumentDB.
|
|
17
|
+
* Uses DocumentDBEncryptionService for field-level encryption.
|
|
18
|
+
*
|
|
19
|
+
* Encrypted fields:
|
|
20
|
+
* - Credential.data.access_token
|
|
21
|
+
* - Credential.data.refresh_token
|
|
22
|
+
* - Credential.data.id_token
|
|
23
|
+
* - Credential.data.domain
|
|
24
|
+
*
|
|
25
|
+
* SECURITY CRITICAL: All OAuth credentials must be encrypted at rest.
|
|
26
|
+
*
|
|
27
|
+
* @see DocumentDBEncryptionService
|
|
28
|
+
* @see encryption-schema-registry.js
|
|
29
|
+
*/
|
|
30
|
+
class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
|
|
31
|
+
constructor() {
|
|
32
|
+
super();
|
|
33
|
+
this.prisma = prisma;
|
|
34
|
+
this.encryptionService = new DocumentDBEncryptionService();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async findCredentialById(id) {
|
|
38
|
+
const objectId = toObjectId(id);
|
|
39
|
+
if (!objectId) return null;
|
|
40
|
+
const doc = await findOne(this.prisma, 'Credential', { _id: objectId });
|
|
41
|
+
if (!doc) return null;
|
|
42
|
+
|
|
43
|
+
// Decrypt sensitive fields using service
|
|
44
|
+
const decryptedCredential = await this.encryptionService.decryptFields('Credential', doc);
|
|
45
|
+
return this._mapCredentialById(decryptedCredential);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async updateAuthenticationStatus(credentialId, authIsValid) {
|
|
49
|
+
const objectId = toObjectId(credentialId);
|
|
50
|
+
if (!objectId) return { acknowledged: false, modifiedCount: 0 };
|
|
51
|
+
const result = await updateOne(
|
|
52
|
+
this.prisma,
|
|
53
|
+
'Credential',
|
|
54
|
+
{ _id: objectId },
|
|
55
|
+
{
|
|
56
|
+
$set: { authIsValid, updatedAt: new Date() },
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
const modified = result?.nModified ?? result?.n ?? 0;
|
|
60
|
+
return { acknowledged: true, modifiedCount: modified };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async deleteCredentialById(credentialId) {
|
|
64
|
+
const objectId = toObjectId(credentialId);
|
|
65
|
+
if (!objectId) return { acknowledged: true, deletedCount: 0 };
|
|
66
|
+
const result = await deleteOne(this.prisma, 'Credential', { _id: objectId });
|
|
67
|
+
const deleted = result?.n ?? 0;
|
|
68
|
+
return { acknowledged: true, deletedCount: deleted };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async upsertCredential(credentialDetails) {
|
|
72
|
+
const { identifiers, details } = credentialDetails;
|
|
73
|
+
if (!identifiers) throw new Error('identifiers required to upsert credential');
|
|
74
|
+
if (!identifiers.user && !identifiers.userId) {
|
|
75
|
+
throw new Error('user or userId required in identifiers');
|
|
76
|
+
}
|
|
77
|
+
if (!identifiers.externalId) {
|
|
78
|
+
throw new Error(
|
|
79
|
+
'externalId required in identifiers to prevent credential collision. When multiple credentials exist for the same user, both userId and externalId are needed to uniquely identify which credential to update.'
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const filter = this._buildIdentifierFilter(identifiers);
|
|
84
|
+
const existing = await findOne(this.prisma, 'Credential', filter);
|
|
85
|
+
|
|
86
|
+
const {
|
|
87
|
+
user,
|
|
88
|
+
userId,
|
|
89
|
+
authIsValid,
|
|
90
|
+
externalId,
|
|
91
|
+
...oauthData
|
|
92
|
+
} = details || {};
|
|
93
|
+
|
|
94
|
+
const now = new Date();
|
|
95
|
+
|
|
96
|
+
if (existing) {
|
|
97
|
+
// Decrypt existing credential data first
|
|
98
|
+
const decryptedExisting = await this.encryptionService.decryptFields('Credential', existing);
|
|
99
|
+
const mergedData = { ...(decryptedExisting.data || {}), ...oauthData };
|
|
100
|
+
|
|
101
|
+
// Build update document
|
|
102
|
+
const updateDocument = {
|
|
103
|
+
userId: toObjectId(userId || user) || existing.userId || null,
|
|
104
|
+
externalId: externalId !== undefined ? externalId : existing.externalId,
|
|
105
|
+
authIsValid: authIsValid !== undefined ? authIsValid : existing.authIsValid,
|
|
106
|
+
data: mergedData,
|
|
107
|
+
updatedAt: now,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Encrypt before storing
|
|
111
|
+
const encryptedUpdate = await this.encryptionService.encryptFields(
|
|
112
|
+
'Credential',
|
|
113
|
+
{ data: updateDocument.data }
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
await updateOne(
|
|
117
|
+
this.prisma,
|
|
118
|
+
'Credential',
|
|
119
|
+
{ _id: existing._id },
|
|
120
|
+
{
|
|
121
|
+
$set: {
|
|
122
|
+
userId: updateDocument.userId,
|
|
123
|
+
externalId: updateDocument.externalId,
|
|
124
|
+
authIsValid: updateDocument.authIsValid,
|
|
125
|
+
data: encryptedUpdate.data,
|
|
126
|
+
updatedAt: updateDocument.updatedAt,
|
|
127
|
+
},
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// Read back and decrypt
|
|
132
|
+
const updated = await findOne(this.prisma, 'Credential', { _id: existing._id });
|
|
133
|
+
const decryptedCredential = await this.encryptionService.decryptFields('Credential', updated);
|
|
134
|
+
return this._mapCredential(decryptedCredential);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Build plain text document
|
|
138
|
+
const plainDocument = {
|
|
139
|
+
userId: toObjectId(userId || user || identifiers.user),
|
|
140
|
+
externalId: externalId !== undefined ? externalId : identifiers.externalId,
|
|
141
|
+
authIsValid: authIsValid ?? null,
|
|
142
|
+
data: oauthData,
|
|
143
|
+
createdAt: now,
|
|
144
|
+
updatedAt: now,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Encrypt before storing
|
|
148
|
+
const encryptedDocument = await this.encryptionService.encryptFields(
|
|
149
|
+
'Credential',
|
|
150
|
+
plainDocument
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
const insertedId = await insertOne(this.prisma, 'Credential', encryptedDocument);
|
|
154
|
+
|
|
155
|
+
// Read back and decrypt
|
|
156
|
+
const created = await findOne(this.prisma, 'Credential', { _id: insertedId });
|
|
157
|
+
const decryptedCredential = await this.encryptionService.decryptFields('Credential', created);
|
|
158
|
+
return this._mapCredential(decryptedCredential);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async findCredential(filter) {
|
|
162
|
+
const query = this._buildFilter(filter);
|
|
163
|
+
const credential = await findOne(this.prisma, 'Credential', query);
|
|
164
|
+
if (!credential) return null;
|
|
165
|
+
|
|
166
|
+
// Decrypt sensitive fields using service
|
|
167
|
+
const decryptedCredential = await this.encryptionService.decryptFields('Credential', credential);
|
|
168
|
+
return this._mapCredential(decryptedCredential);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
async updateCredential(credentialId, updates) {
|
|
172
|
+
const objectId = toObjectId(credentialId);
|
|
173
|
+
if (!objectId) return null;
|
|
174
|
+
const existing = await findOne(this.prisma, 'Credential', { _id: objectId });
|
|
175
|
+
if (!existing) return null;
|
|
176
|
+
|
|
177
|
+
const {
|
|
178
|
+
user,
|
|
179
|
+
userId,
|
|
180
|
+
authIsValid,
|
|
181
|
+
externalId,
|
|
182
|
+
...oauthData
|
|
183
|
+
} = updates || {};
|
|
184
|
+
|
|
185
|
+
// Decrypt existing credential data first
|
|
186
|
+
const decryptedExisting = await this.encryptionService.decryptFields('Credential', existing);
|
|
187
|
+
const mergedData = { ...(decryptedExisting.data || {}), ...oauthData };
|
|
188
|
+
|
|
189
|
+
// Build update document
|
|
190
|
+
const updateDocument = {
|
|
191
|
+
userId: toObjectId(userId || user) || existing.userId || null,
|
|
192
|
+
externalId: externalId !== undefined ? externalId : existing.externalId,
|
|
193
|
+
authIsValid: authIsValid !== undefined ? authIsValid : existing.authIsValid,
|
|
194
|
+
data: mergedData,
|
|
195
|
+
updatedAt: new Date(),
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Encrypt before storing
|
|
199
|
+
const encryptedUpdate = await this.encryptionService.encryptFields(
|
|
200
|
+
'Credential',
|
|
201
|
+
{ data: updateDocument.data }
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
await updateOne(
|
|
205
|
+
this.prisma,
|
|
206
|
+
'Credential',
|
|
207
|
+
{ _id: objectId },
|
|
208
|
+
{
|
|
209
|
+
$set: {
|
|
210
|
+
userId: updateDocument.userId,
|
|
211
|
+
externalId: updateDocument.externalId,
|
|
212
|
+
authIsValid: updateDocument.authIsValid,
|
|
213
|
+
data: encryptedUpdate.data,
|
|
214
|
+
updatedAt: updateDocument.updatedAt,
|
|
215
|
+
},
|
|
216
|
+
}
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
// Read back and decrypt
|
|
220
|
+
const updated = await findOne(this.prisma, 'Credential', { _id: objectId });
|
|
221
|
+
const decryptedCredential = await this.encryptionService.decryptFields('Credential', updated);
|
|
222
|
+
return this._mapCredential(decryptedCredential);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
_buildIdentifierFilter(identifiers) {
|
|
226
|
+
const filter = {};
|
|
227
|
+
if (identifiers._id || identifiers.id) {
|
|
228
|
+
const idObj = toObjectId(identifiers._id || identifiers.id);
|
|
229
|
+
if (idObj) filter._id = idObj;
|
|
230
|
+
}
|
|
231
|
+
if (identifiers.user || identifiers.userId) {
|
|
232
|
+
const userObj = toObjectId(identifiers.user || identifiers.userId);
|
|
233
|
+
if (userObj) filter.userId = userObj;
|
|
234
|
+
}
|
|
235
|
+
if (identifiers.externalId !== undefined) {
|
|
236
|
+
filter.externalId = identifiers.externalId;
|
|
237
|
+
}
|
|
238
|
+
return filter;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
_buildFilter(filter) {
|
|
242
|
+
const query = {};
|
|
243
|
+
if (!filter) return query;
|
|
244
|
+
if (filter.credentialId || filter.id) {
|
|
245
|
+
const idObj = toObjectId(filter.credentialId || filter.id);
|
|
246
|
+
if (idObj) query._id = idObj;
|
|
247
|
+
}
|
|
248
|
+
if (filter.user || filter.userId) {
|
|
249
|
+
const userObj = toObjectId(filter.user || filter.userId);
|
|
250
|
+
if (userObj) query.userId = userObj;
|
|
251
|
+
}
|
|
252
|
+
if (filter.externalId !== undefined) {
|
|
253
|
+
query.externalId = filter.externalId;
|
|
254
|
+
}
|
|
255
|
+
return query;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Map credential document to application format (without legacy fields)
|
|
260
|
+
* Used by findCredential, upsertCredential, updateCredential
|
|
261
|
+
* Matches MongoDB repository format
|
|
262
|
+
* @private
|
|
263
|
+
*/
|
|
264
|
+
_mapCredential(doc) {
|
|
265
|
+
const data = doc?.data || {};
|
|
266
|
+
const id = fromObjectId(doc?._id);
|
|
267
|
+
const userId = fromObjectId(doc?.userId);
|
|
268
|
+
return {
|
|
269
|
+
id,
|
|
270
|
+
userId,
|
|
271
|
+
externalId: doc?.externalId ?? null,
|
|
272
|
+
authIsValid: doc?.authIsValid ?? null,
|
|
273
|
+
...data,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Map credential document with legacy fields for findCredentialById
|
|
279
|
+
* Includes _id and user fields for backward compatibility
|
|
280
|
+
* Matches MongoDB repository format
|
|
281
|
+
* @private
|
|
282
|
+
*/
|
|
283
|
+
_mapCredentialById(doc) {
|
|
284
|
+
const data = doc?.data || {};
|
|
285
|
+
const id = fromObjectId(doc?._id);
|
|
286
|
+
const userId = fromObjectId(doc?.userId);
|
|
287
|
+
return {
|
|
288
|
+
_id: id,
|
|
289
|
+
id,
|
|
290
|
+
user: userId,
|
|
291
|
+
userId,
|
|
292
|
+
externalId: doc?.externalId ?? null,
|
|
293
|
+
authIsValid: doc?.authIsValid ?? null,
|
|
294
|
+
...data,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
module.exports = { CredentialRepositoryDocumentDB };
|
|
300
|
+
|
|
@@ -2,6 +2,9 @@ const { CredentialRepositoryMongo } = require('./credential-repository-mongo');
|
|
|
2
2
|
const {
|
|
3
3
|
CredentialRepositoryPostgres,
|
|
4
4
|
} = require('./credential-repository-postgres');
|
|
5
|
+
const {
|
|
6
|
+
CredentialRepositoryDocumentDB,
|
|
7
|
+
} = require('./credential-repository-documentdb');
|
|
5
8
|
const config = require('../../database/config');
|
|
6
9
|
|
|
7
10
|
/**
|
|
@@ -32,9 +35,12 @@ function createCredentialRepository() {
|
|
|
32
35
|
case 'postgresql':
|
|
33
36
|
return new CredentialRepositoryPostgres();
|
|
34
37
|
|
|
38
|
+
case 'documentdb':
|
|
39
|
+
return new CredentialRepositoryDocumentDB();
|
|
40
|
+
|
|
35
41
|
default:
|
|
36
42
|
throw new Error(
|
|
37
|
-
`Unsupported database type: ${dbType}. Supported values: 'mongodb', 'postgresql'`
|
|
43
|
+
`Unsupported database type: ${dbType}. Supported values: 'mongodb', 'documentdb', 'postgresql'`
|
|
38
44
|
);
|
|
39
45
|
}
|
|
40
46
|
}
|
|
@@ -44,4 +50,5 @@ module.exports = {
|
|
|
44
50
|
// Export adapters for direct testing
|
|
45
51
|
CredentialRepositoryMongo,
|
|
46
52
|
CredentialRepositoryPostgres,
|
|
53
|
+
CredentialRepositoryDocumentDB,
|
|
47
54
|
};
|
package/database/config.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* 1. DB_TYPE environment variable (set for migration handlers)
|
|
11
11
|
* 2. App definition (backend/index.js Definition.database configuration)
|
|
12
12
|
*
|
|
13
|
-
* @returns {'mongodb'|'postgresql'} Database type
|
|
13
|
+
* @returns {'mongodb'|'postgresql'|'documentdb'} Database type
|
|
14
14
|
* @throws {Error} If database type cannot be determined or app definition missing
|
|
15
15
|
*/
|
|
16
16
|
function getDatabaseType() {
|
|
@@ -93,7 +93,7 @@ function getDatabaseType() {
|
|
|
93
93
|
return 'mongodb';
|
|
94
94
|
}
|
|
95
95
|
if (database.documentDB?.enable === true) {
|
|
96
|
-
return '
|
|
96
|
+
return 'documentdb';
|
|
97
97
|
}
|
|
98
98
|
|
|
99
99
|
throw new Error(
|
|
@@ -114,7 +114,7 @@ function getDatabaseType() {
|
|
|
114
114
|
|
|
115
115
|
/**
|
|
116
116
|
* Cached database type (lazy evaluation)
|
|
117
|
-
* @type {'mongodb'|'postgresql'|null}
|
|
117
|
+
* @type {'mongodb'|'postgresql'|'documentdb'|null}
|
|
118
118
|
*/
|
|
119
119
|
let cachedDbType = null;
|
|
120
120
|
|
|
@@ -140,7 +140,7 @@ module.exports = {
|
|
|
140
140
|
/**
|
|
141
141
|
* Lazy-evaluated database type determined from app definition
|
|
142
142
|
* Only evaluates when accessed, preventing module load failures in test environments
|
|
143
|
-
* @type {'mongodb'|'postgresql'}
|
|
143
|
+
* @type {'mongodb'|'postgresql'|'documentdb'}
|
|
144
144
|
*/
|
|
145
145
|
Object.defineProperty(module.exports, 'DB_TYPE', {
|
|
146
146
|
get() {
|