@flowerforce/flowerbase 1.7.6-beta.0 → 1.7.6-beta.10

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.
Files changed (122) hide show
  1. package/README.md +125 -1
  2. package/dist/auth/providers/anon-user/controller.d.ts.map +1 -1
  3. package/dist/auth/providers/anon-user/controller.js +1 -0
  4. package/dist/auth/providers/custom-function/controller.d.ts.map +1 -1
  5. package/dist/auth/providers/custom-function/controller.js +6 -9
  6. package/dist/auth/providers/local-userpass/controller.d.ts.map +1 -1
  7. package/dist/auth/providers/local-userpass/controller.js +58 -18
  8. package/dist/auth/providers/local-userpass/dtos.d.ts +5 -1
  9. package/dist/auth/providers/local-userpass/dtos.d.ts.map +1 -1
  10. package/dist/auth/utils.d.ts +1 -0
  11. package/dist/auth/utils.d.ts.map +1 -1
  12. package/dist/auth/utils.js +1 -0
  13. package/dist/constants.d.ts +10 -0
  14. package/dist/constants.d.ts.map +1 -1
  15. package/dist/constants.js +11 -1
  16. package/dist/features/encryption/interface.d.ts +36 -0
  17. package/dist/features/encryption/interface.d.ts.map +1 -0
  18. package/dist/features/encryption/interface.js +2 -0
  19. package/dist/features/encryption/utils.d.ts +9 -0
  20. package/dist/features/encryption/utils.d.ts.map +1 -0
  21. package/dist/features/encryption/utils.js +34 -0
  22. package/dist/features/endpoints/utils.d.ts.map +1 -1
  23. package/dist/features/endpoints/utils.js +3 -0
  24. package/dist/features/functions/controller.d.ts +2 -0
  25. package/dist/features/functions/controller.d.ts.map +1 -1
  26. package/dist/features/functions/controller.js +7 -1
  27. package/dist/features/rules/interface.d.ts +6 -5
  28. package/dist/features/rules/interface.d.ts.map +1 -1
  29. package/dist/features/rules/utils.d.ts.map +1 -1
  30. package/dist/features/rules/utils.js +1 -11
  31. package/dist/features/triggers/index.d.ts.map +1 -1
  32. package/dist/features/triggers/index.js +4 -0
  33. package/dist/features/triggers/interface.d.ts +1 -1
  34. package/dist/features/triggers/interface.d.ts.map +1 -1
  35. package/dist/features/triggers/utils.d.ts.map +1 -1
  36. package/dist/features/triggers/utils.js +85 -33
  37. package/dist/index.d.ts +3 -1
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +9 -4
  40. package/dist/monitoring/plugin.d.ts.map +1 -1
  41. package/dist/monitoring/plugin.js +31 -0
  42. package/dist/services/mongodb-atlas/index.d.ts +3 -0
  43. package/dist/services/mongodb-atlas/index.d.ts.map +1 -1
  44. package/dist/services/mongodb-atlas/index.js +136 -43
  45. package/dist/services/mongodb-atlas/model.d.ts +2 -1
  46. package/dist/services/mongodb-atlas/model.d.ts.map +1 -1
  47. package/dist/utils/context/helpers.d.ts.map +1 -1
  48. package/dist/utils/context/helpers.js +3 -2
  49. package/dist/utils/context/index.d.ts.map +1 -1
  50. package/dist/utils/context/index.js +4 -2
  51. package/dist/utils/index.d.ts +1 -0
  52. package/dist/utils/index.d.ts.map +1 -1
  53. package/dist/utils/index.js +14 -3
  54. package/dist/utils/initializer/mongodbCSFLE.d.ts +69 -0
  55. package/dist/utils/initializer/mongodbCSFLE.d.ts.map +1 -0
  56. package/dist/utils/initializer/mongodbCSFLE.js +131 -0
  57. package/dist/utils/initializer/registerPlugins.d.ts +5 -1
  58. package/dist/utils/initializer/registerPlugins.d.ts.map +1 -1
  59. package/dist/utils/initializer/registerPlugins.js +27 -5
  60. package/dist/utils/roles/helpers.d.ts.map +1 -1
  61. package/dist/utils/roles/helpers.js +6 -3
  62. package/dist/utils/roles/machines/fieldPermissions.d.ts.map +1 -1
  63. package/dist/utils/roles/machines/fieldPermissions.js +19 -10
  64. package/dist/utils/rules-matcher/interface.d.ts +2 -0
  65. package/dist/utils/rules-matcher/interface.d.ts.map +1 -1
  66. package/dist/utils/rules-matcher/interface.js +1 -0
  67. package/dist/utils/rules-matcher/utils.d.ts.map +1 -1
  68. package/dist/utils/rules-matcher/utils.js +23 -6
  69. package/package.json +4 -2
  70. package/src/auth/providers/anon-user/controller.ts +1 -0
  71. package/src/auth/providers/custom-function/controller.ts +10 -11
  72. package/src/auth/providers/local-userpass/__tests__/controller.test.ts +200 -0
  73. package/src/auth/providers/local-userpass/controller.ts +87 -34
  74. package/src/auth/providers/local-userpass/dtos.ts +6 -1
  75. package/src/auth/utils.ts +1 -0
  76. package/src/constants.ts +11 -2
  77. package/src/features/encryption/interface.ts +46 -0
  78. package/src/features/encryption/utils.ts +22 -0
  79. package/src/features/endpoints/__tests__/utils.test.ts +65 -0
  80. package/src/features/endpoints/utils.ts +3 -0
  81. package/src/features/functions/__tests__/watch-filter.test.ts +11 -1
  82. package/src/features/functions/controller.ts +8 -0
  83. package/src/features/rules/interface.ts +18 -17
  84. package/src/features/rules/utils.ts +1 -11
  85. package/src/features/triggers/__tests__/index.test.ts +6 -4
  86. package/src/features/triggers/index.ts +5 -1
  87. package/src/features/triggers/interface.ts +1 -1
  88. package/src/features/triggers/utils.ts +86 -37
  89. package/src/index.ts +10 -2
  90. package/src/monitoring/plugin.ts +33 -0
  91. package/src/monitoring/ui.collections.js +7 -10
  92. package/src/monitoring/ui.css +378 -0
  93. package/src/monitoring/ui.endpoints.js +5 -10
  94. package/src/monitoring/ui.events.js +3 -5
  95. package/src/monitoring/ui.functions.js +64 -71
  96. package/src/monitoring/ui.html +8 -0
  97. package/src/monitoring/ui.js +189 -0
  98. package/src/monitoring/ui.shared.js +237 -2
  99. package/src/monitoring/ui.triggers.js +2 -3
  100. package/src/monitoring/ui.users.js +5 -9
  101. package/src/services/mongodb-atlas/__tests__/realmCompatibility.test.ts +205 -7
  102. package/src/services/mongodb-atlas/__tests__/utils.test.ts +27 -0
  103. package/src/services/mongodb-atlas/__tests__/watch-filter.test.ts +78 -0
  104. package/src/services/mongodb-atlas/index.ts +379 -182
  105. package/src/services/mongodb-atlas/model.ts +3 -1
  106. package/src/types/fastify-raw-body.d.ts +0 -9
  107. package/src/utils/__tests__/checkIsValidFieldNameFn.test.ts +74 -5
  108. package/src/utils/__tests__/contextExecuteCompatibility.test.ts +27 -1
  109. package/src/utils/__tests__/evaluateExpression.test.ts +33 -0
  110. package/src/utils/__tests__/generateContextData.test.ts +5 -1
  111. package/src/utils/__tests__/mongodbCSFLE.test.ts +105 -0
  112. package/src/utils/__tests__/rule.test.ts +38 -0
  113. package/src/utils/context/helpers.ts +3 -2
  114. package/src/utils/context/index.ts +4 -3
  115. package/src/utils/index.ts +12 -1
  116. package/src/utils/initializer/mongodbCSFLE.ts +224 -0
  117. package/src/utils/initializer/registerPlugins.ts +45 -10
  118. package/src/utils/roles/helpers.ts +10 -5
  119. package/src/utils/roles/machines/fieldPermissions.ts +17 -8
  120. package/src/utils/rules-matcher/interface.ts +2 -0
  121. package/src/utils/rules-matcher/utils.ts +33 -17
  122. package/src/utils/__tests__/readFileContent.test.ts +0 -35
package/README.md CHANGED
@@ -265,8 +265,132 @@ Example
265
265
  ```
266
266
  If you're configuring the project from scratch, you can skip ahead to the [Build](#build) step.
267
267
 
268
- --------
268
+ ## 🔐 7 Client-Side Field Level Encryption (CSFLE)
269
269
 
270
+ Flowerbase supports MongoDB Client-Side Field Level Encryption. When enabled, sensitive fields are encrypted by the MongoDB driver before writing to MongoDB and decrypted automatically when reading.
271
+
272
+ What Flowerbase does for you:
273
+
274
+ - Loads all `encryption.json` files under `data_sources/mongodb-atlas/**`.
275
+ - Builds the MongoDB `schemaMap` automatically from those files.
276
+ - Resolves each `keyAlias` in your schemas to a real Data Encryption Key (DEK) `keyId`.
277
+ - Ensures DEKs exist in the key vault (creates them if missing).
278
+ - Configures Fastify MongoDB plugin `autoEncryption` with the generated `schemaMap`.
279
+
280
+ ### 1. Install encryption drivers
281
+
282
+ Refer to the official MongoDB documentation for CSFLE installation requirements: https://www.mongodb.com/docs/manual/core/csfle/install.
283
+
284
+ It is recommended to use the [**Automatic Encryption Shared Library**](https://www.mongodb.com/docs/manual/core/csfle/reference/install-library/?encryption-component=crypt_shared#std-label-csfle-reference-shared-library-download) instead of mongocryptd.
285
+
286
+ Note that the project should also install [mongodb-client-encryption](https://www.npmjs.com/package/mongodb-client-encryption), matching the mongodb driver version.
287
+
288
+ ### 2. Add encryption schema files
289
+
290
+ Create one `encryption.json` per collection you want to encrypt:
291
+
292
+ Path example:
293
+
294
+ ```text
295
+ src/data_sources/mongodb-atlas/<database>/<collection>/encryption.json
296
+ ```
297
+
298
+ Example:
299
+
300
+ ```json
301
+ {
302
+ "database": "appDb",
303
+ "collection": "records",
304
+ "schema": {
305
+ "bsonType": "object",
306
+ "encryptMetadata": {
307
+ "keyAlias": "root-key"
308
+ },
309
+ "properties": {
310
+ "protectedField1": {
311
+ "encrypt": {
312
+ "bsonType": "string",
313
+ "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Random"
314
+ }
315
+ },
316
+ "protectedField2": {
317
+ "encrypt": {
318
+ "bsonType": "string",
319
+ "algorithm": "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
320
+ "keyAlias": "deep-key"
321
+ }
322
+ }
323
+ }
324
+ }
325
+ }
326
+ ```
327
+
328
+ Notes:
329
+
330
+ - `encryptMetadata.keyAlias` applies as default key for that object level.
331
+ - `encrypt.keyAlias` overrides key selection for a specific field.
332
+ - If a field has `encrypt` but no `keyAlias`, MongoDB uses nearest `encryptMetadata`.
333
+
334
+ ### 3. Pass `mongodbEncryptionConfig` to `initialize()`
335
+
336
+ `initialize()` accepts `mongodbEncryptionConfig` to configure KMS providers and key vault settings.
337
+
338
+ #### Local KMS provider example (development)
339
+
340
+ ```ts
341
+ import { initialize } from "@flowerforce/flowerbase";
342
+
343
+ await initialize({
344
+ projectId: "my-project-id",
345
+ mongodbUrl: process.env.MONGODB_URL,
346
+ jwtSecret: process.env.JWT_SECRET,
347
+ mongodbEncryptionConfig: {
348
+ kmsProviders: [
349
+ {
350
+ provider: "local",
351
+ keyAlias: "root-key",
352
+ config: {
353
+ // 96-byte local master key encoded as base64
354
+ key: process.env.LOCAL_MASTER_KEY_BASE64,
355
+ },
356
+ },
357
+ {
358
+ provider: "local",
359
+ keyAlias: "deep-key",
360
+ config: { key: process.env.LOCAL_MASTER_KEY_BASE64 },
361
+ },
362
+ ],
363
+ keyVaultDb: "encryption",
364
+ keyVaultCollection: "__keyVault",
365
+ extraOptions: {
366
+ // Optional: path to crypt shared library
367
+ // cryptSharedLibPath: '/opt/mongo_crypt_v1/lib/mongo_crypt_v1.so'
368
+ },
369
+ },
370
+ });
371
+ ```
372
+
373
+ #### AWS KMS provider example
374
+
375
+ ```ts
376
+ mongodbEncryptionConfig: {
377
+ kmsProviders: [
378
+ {
379
+ provider: "aws",
380
+ keyAlias: "root-key",
381
+ config: {
382
+ accessKeyId: process.env.AWS_ACCESS_KEY_ID,
383
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
384
+ },
385
+ masterKey: {
386
+ key: process.env.AWS_KMS_KEY_ARN,
387
+ region: process.env.AWS_REGION,
388
+ },
389
+ },
390
+ ];
391
+ }
392
+ ```
393
+ ---
270
394
 
271
395
  <a id="migration"></a>
272
396
  ## 🔄 [Migration Guide](#migration) - Migrating Your Realm Project
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/anon-user/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,eAAe,iBAwE5D"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/anon-user/controller.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAOzC;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,eAAe,iBAyE5D"}
@@ -54,6 +54,7 @@ function anonUserController(app) {
54
54
  email: anonEmail,
55
55
  status: 'confirmed',
56
56
  createdAt: now,
57
+ lastLoginAt: now,
57
58
  custom_data: {},
58
59
  identities: [
59
60
  {
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/custom-function/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAUzC;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,eAAe,iBA2IlE"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/custom-function/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAUzC;;;;GAIG;AACH,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,eAAe,iBA0IlE"}
@@ -38,10 +38,7 @@ function customFunctionController(app) {
38
38
  * @returns {Promise<Object>} A promise resolving with access and refresh tokens.
39
39
  */
40
40
  app.post(utils_1.AUTH_ENDPOINTS.LOGIN, {
41
- schema: schema_1.LOGIN_SCHEMA,
42
- errorHandler: (_error, _request, reply) => {
43
- reply.code(500).send({ message: 'Internal Server Error' });
44
- }
41
+ schema: schema_1.LOGIN_SCHEMA
45
42
  }, function (req, reply) {
46
43
  return __awaiter(this, void 0, void 0, function* () {
47
44
  var _a, _b, _c;
@@ -114,23 +111,23 @@ function customFunctionController(app) {
114
111
  user_data: Object.assign(Object.assign({}, (user || {})), { id: authUser._id.toString(), email: authUser.email }),
115
112
  custom_data: Object.assign({}, (user || {}))
116
113
  };
114
+ const now = new Date();
117
115
  const refreshToken = this.createRefreshToken(currentUserData);
118
116
  const refreshTokenHash = (0, crypto_1.hashToken)(refreshToken);
119
117
  yield authDb.collection(refreshTokensCollection).insertOne({
120
118
  userId: authUser._id,
121
119
  tokenHash: refreshTokenHash,
122
- createdAt: new Date(),
120
+ createdAt: now,
123
121
  expiresAt: new Date(Date.now() + refreshTokenTtlMs),
124
122
  revokedAt: null
125
123
  });
126
- const accessToken = this.createAccessToken(currentUserData);
127
- const responsePayload = {
128
- access_token: accessToken,
124
+ yield authDb.collection(authCollection).updateOne({ _id: authUser._id }, { $set: { lastLoginAt: now } });
125
+ return {
126
+ access_token: this.createAccessToken(currentUserData),
129
127
  refresh_token: refreshToken,
130
128
  device_id: '',
131
129
  user_id: authUser._id.toString()
132
130
  };
133
- reply.code(200).send(responsePayload);
134
131
  });
135
132
  });
136
133
  });
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AAqCzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBAqXjE"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA;AA4CzC;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,eAAe,iBAmajE"}
@@ -49,14 +49,22 @@ function localUserPassController(app) {
49
49
  const resetMaxAttempts = constants_1.DEFAULT_CONFIG.AUTH_RESET_MAX_ATTEMPTS;
50
50
  const refreshTokenTtlMs = constants_1.DEFAULT_CONFIG.REFRESH_TOKEN_TTL_DAYS * 24 * 60 * 60 * 1000;
51
51
  const resolveLocalUserpassProvider = () => { var _a; return (_a = constants_1.AUTH_CONFIG.authProviders) === null || _a === void 0 ? void 0 : _a['local-userpass']; };
52
+ const invalidPasswordError = {
53
+ error: 'unauthorized',
54
+ error_code: 'InvalidPassword'
55
+ };
52
56
  try {
53
- yield authDb.collection(resetPasswordCollection).createIndex({ createdAt: 1 }, { expireAfterSeconds: resetPasswordTtlSeconds });
57
+ yield authDb
58
+ .collection(resetPasswordCollection)
59
+ .createIndex({ createdAt: 1 }, { expireAfterSeconds: resetPasswordTtlSeconds });
54
60
  }
55
61
  catch (error) {
56
62
  console.error('Failed to ensure reset password TTL index', error);
57
63
  }
58
64
  try {
59
- yield authDb.collection(refreshTokensCollection).createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
65
+ yield authDb
66
+ .collection(refreshTokensCollection)
67
+ .createIndex({ expiresAt: 1 }, { expireAfterSeconds: 0 });
60
68
  }
61
69
  catch (error) {
62
70
  console.error('Failed to ensure refresh token TTL index', error);
@@ -80,8 +88,10 @@ function localUserPassController(app) {
80
88
  const services = state_1.StateManager.select('services');
81
89
  const currentFunction = functionsList[resetPasswordConfig.resetFunctionName];
82
90
  const baseArgs = { token, tokenId, email, password, username: email };
83
- const args = Array.isArray(extraArguments) ? [baseArgs, ...extraArguments] : [baseArgs];
84
- yield (0, context_1.GenerateContext)({
91
+ const args = Array.isArray(extraArguments)
92
+ ? [baseArgs, ...extraArguments]
93
+ : [baseArgs];
94
+ const response = (yield (0, context_1.GenerateContext)({
85
95
  args,
86
96
  app,
87
97
  rules: {},
@@ -89,10 +99,32 @@ function localUserPassController(app) {
89
99
  currentFunction,
90
100
  functionName: resetPasswordConfig.resetFunctionName,
91
101
  functionsList,
92
- services
93
- });
94
- return;
102
+ services,
103
+ runAsSystem: true
104
+ }));
105
+ const resetStatus = response === null || response === void 0 ? void 0 : response.status;
106
+ if (resetStatus === 'success') {
107
+ if (!password) {
108
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_RESET_FUNCTION_RESPONSE);
109
+ }
110
+ const hashedPassword = yield (0, crypto_1.hashPassword)(password);
111
+ yield authDb.collection(authCollection).updateOne({ email }, {
112
+ $set: {
113
+ password: hashedPassword
114
+ }
115
+ });
116
+ yield (authDb === null || authDb === void 0 ? void 0 : authDb.collection(resetPasswordCollection).deleteOne({ email }));
117
+ return { status: 'success' };
118
+ }
119
+ if (resetStatus === 'pending') {
120
+ return { status: 'pending' };
121
+ }
122
+ if (resetStatus === 'fail') {
123
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_RESET_PARAMS);
124
+ }
125
+ throw new Error(utils_1.AUTH_ERRORS.INVALID_RESET_FUNCTION_RESPONSE);
95
126
  }
127
+ return { status: 'pending' };
96
128
  });
97
129
  /**
98
130
  * Endpoint for user registration.
@@ -116,13 +148,17 @@ function localUserPassController(app) {
116
148
  }
117
149
  let result;
118
150
  try {
119
- result = yield (0, handleUserRegistration_1.default)(app, { run_as_system: true, provider: handleUserRegistration_model_1.PROVIDER.LOCAL_USERPASS })({
151
+ result = yield (0, handleUserRegistration_1.default)(app, {
152
+ run_as_system: true,
153
+ provider: handleUserRegistration_model_1.PROVIDER.LOCAL_USERPASS
154
+ })({
120
155
  email: req.body.email.toLowerCase(),
121
156
  password: req.body.password
122
157
  });
123
158
  }
124
159
  catch (error) {
125
- if (error instanceof Error && error.message === 'This email address is already used') {
160
+ if (error instanceof Error &&
161
+ error.message === 'This email address is already used') {
126
162
  res.status(409).send({
127
163
  error: 'name already in use',
128
164
  error_code: 'AccountNameInUse'
@@ -157,10 +193,10 @@ function localUserPassController(app) {
157
193
  res.status(429).send({ message: 'Too many requests' });
158
194
  return;
159
195
  }
160
- const existing = yield authDb.collection(authCollection).findOne({
196
+ const existing = (yield authDb.collection(authCollection).findOne({
161
197
  confirmationToken: req.body.token,
162
198
  confirmationTokenId: req.body.tokenId
163
- });
199
+ }));
164
200
  if (!existing) {
165
201
  res.status(500);
166
202
  throw new Error(utils_1.AUTH_ERRORS.INVALID_TOKEN);
@@ -198,11 +234,13 @@ function localUserPassController(app) {
198
234
  email: req.body.username
199
235
  });
200
236
  if (!authUser) {
201
- throw new Error(utils_1.AUTH_ERRORS.INVALID_CREDENTIALS);
237
+ res.status(401);
238
+ return invalidPasswordError;
202
239
  }
203
240
  const passwordMatches = yield (0, crypto_1.comparePassword)(req.body.password, authUser.password);
204
241
  if (!passwordMatches) {
205
- throw new Error(utils_1.AUTH_ERRORS.INVALID_CREDENTIALS);
242
+ res.status(401);
243
+ return invalidPasswordError;
206
244
  }
207
245
  const user = user_id_field && userCollection
208
246
  ? yield customUserDb
@@ -214,15 +252,19 @@ function localUserPassController(app) {
214
252
  if (authUser && authUser.status !== 'confirmed') {
215
253
  throw new Error(utils_1.AUTH_ERRORS.USER_NOT_CONFIRMED);
216
254
  }
255
+ const now = new Date();
217
256
  const refreshToken = this.createRefreshToken(userWithCustomData);
218
257
  const refreshTokenHash = (0, crypto_1.hashToken)(refreshToken);
219
258
  yield authDb.collection(refreshTokensCollection).insertOne({
220
259
  userId: authUser._id,
221
260
  tokenHash: refreshTokenHash,
222
- createdAt: new Date(),
261
+ createdAt: now,
223
262
  expiresAt: new Date(Date.now() + refreshTokenTtlMs),
224
263
  revokedAt: null
225
264
  });
265
+ yield authDb
266
+ .collection(authCollection)
267
+ .updateOne({ _id: authUser._id }, { $set: { lastLoginAt: now } });
226
268
  return {
227
269
  access_token: this.createAccessToken(userWithCustomData),
228
270
  refresh_token: refreshToken,
@@ -271,11 +313,9 @@ function localUserPassController(app) {
271
313
  res.status(429);
272
314
  return { message: 'Too many requests' };
273
315
  }
274
- yield handleResetPasswordRequest(req.body.email, req.body.password, req.body.arguments);
316
+ const result = yield handleResetPasswordRequest(req.body.email, req.body.password, req.body.arguments);
275
317
  res.status(202);
276
- return {
277
- status: 'ok'
278
- };
318
+ return result;
279
319
  });
280
320
  });
281
321
  /**
@@ -15,12 +15,16 @@ export type LoginSuccessDto = {
15
15
  export type ErrorResponseDto = {
16
16
  message: string;
17
17
  };
18
+ export type InvalidPasswordResponseDto = {
19
+ error: 'unauthorized';
20
+ error_code: 'InvalidPassword';
21
+ };
18
22
  export interface RegistrationDto {
19
23
  Body: RegisterUserDto;
20
24
  }
21
25
  export interface LoginDto {
22
26
  Body: LoginUserDto;
23
- Reply: LoginSuccessDto | ErrorResponseDto;
27
+ Reply: LoginSuccessDto | ErrorResponseDto | InvalidPasswordResponseDto;
24
28
  }
25
29
  export interface ResetPasswordSendDto {
26
30
  Body: {
@@ -1 +1 @@
1
- {"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/dtos.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAAA;CAC1C;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAA;KACtB,CAAA;CACF;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF"}
1
+ {"version":3,"file":"dtos.d.ts","sourceRoot":"","sources":["../../../../src/auth/providers/local-userpass/dtos.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,0BAA0B,GAAG;IACvC,KAAK,EAAE,cAAc,CAAA;IACrB,UAAU,EAAE,iBAAiB,CAAA;CAC9B,CAAA;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,eAAe,CAAA;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,YAAY,CAAA;IAClB,KAAK,EAAE,eAAe,GAAG,gBAAgB,GAAG,0BAA0B,CAAA;CACvE;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,OAAO,EAAE,CAAA;KACtB,CAAA;CACF;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,OAAO,EAAE,MAAM,CAAA;KAChB,CAAA;CACF"}
@@ -146,6 +146,7 @@ export declare enum AUTH_ERRORS {
146
146
  INVALID_TOKEN = "Invalid refresh token provided",
147
147
  INVALID_RESET_PARAMS = "Invalid token or tokenId provided",
148
148
  MISSING_RESET_FUNCTION = "Missing reset function",
149
+ INVALID_RESET_FUNCTION_RESPONSE = "Invalid reset function response",
149
150
  USER_NOT_CONFIRMED = "User not confirmed"
150
151
  }
151
152
  export interface AuthConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/auth/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc;;;CAA4C,CAAC;AACxE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;CAexB,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;CAc7B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;CAgB7B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;CAWhC,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAU/B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAAoB,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;CAe/B,CAAA;AAED,oBAAY,cAAc;IACxB,KAAK,WAAW;IAChB,YAAY,cAAc;IAC1B,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,KAAK,gBAAgB;IACrB,UAAU,gBAAgB;IAC1B,aAAa,WAAW;IACxB,UAAU,sBAAsB;CACjC;AAED,oBAAY,WAAW;IACrB,mBAAmB,wBAAwB;IAC3C,aAAa,mCAAmC;IAChD,oBAAoB,sCAAsC;IAC1D,sBAAsB,2BAA2B;IACjD,kBAAkB,uBAAuB;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;IAC/B,iBAAiB,EAAE,cAAc,CAAA;IACjC,WAAW,CAAC,EAAE,QAAQ,CAAA;CACvB;AAED,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AACD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACN,kBAAkB,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,iBAAiB,EAAE,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,uBAAuB,EAAE,OAAO,CAAA;IAChC,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,8BAA8B,EAAE,MAAM,CAAA;CACvC;AAMD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,UAuCjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAarC,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,eAAW,WAG3C,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/auth/utils.ts"],"names":[],"mappings":"AAMA,eAAO,MAAM,cAAc;;;CAA4C,CAAC;AACxE,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;CAexB,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;CAc7B,CAAA;AAED,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;CAgB7B,CAAA;AAED,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;;;;CAWhC,CAAA;AAED,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;CAU/B,CAAA;AAED,eAAO,MAAM,YAAY;;;;;;;;;;;;;;CAAoB,CAAA;AAE7C,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;CAe/B,CAAA;AAED,oBAAY,cAAc;IACxB,KAAK,WAAW;IAChB,YAAY,cAAc;IAC1B,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,OAAO,aAAa;IACpB,KAAK,gBAAgB;IACrB,UAAU,gBAAgB;IAC1B,aAAa,WAAW;IACxB,UAAU,sBAAsB;CACjC;AAED,oBAAY,WAAW;IACrB,mBAAmB,wBAAwB;IAC3C,aAAa,mCAAmC;IAChD,oBAAoB,sCAAsC;IAC1D,sBAAsB,2BAA2B;IACjD,+BAA+B,oCAAoC;IACnE,kBAAkB,uBAAuB;CAC1C;AAED,MAAM,WAAW,UAAU;IACzB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,EAAE,aAAa,CAAA;IAC/B,iBAAiB,EAAE,cAAc,CAAA;IACjC,WAAW,CAAC,EAAE,QAAQ,CAAA;CACvB;AAED,UAAU,MAAM;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;CAClB;AACD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;CACf;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,iBAAiB,CAAC;IACxB,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE;QACN,kBAAkB,EAAE,MAAM,CAAA;KAC3B,CAAA;CACF;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,WAAW,CAAA;IACjB,IAAI,EAAE,WAAW,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,MAAM;IACrB,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,iBAAiB,EAAE,MAAM,CAAA;IACzB,gBAAgB,EAAE,MAAM,CAAA;IACxB,uBAAuB,EAAE,OAAO,CAAA;IAChC,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,8BAA8B,EAAE,MAAM,CAAA;CACvC;AAMD;;;GAGG;AACH,eAAO,MAAM,cAAc,QAAO,UAuCjC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,oBAarC,CAAA;AAED,eAAO,MAAM,gBAAgB,GAAI,eAAW,WAG3C,CAAA"}
@@ -115,6 +115,7 @@ var AUTH_ERRORS;
115
115
  AUTH_ERRORS["INVALID_TOKEN"] = "Invalid refresh token provided";
116
116
  AUTH_ERRORS["INVALID_RESET_PARAMS"] = "Invalid token or tokenId provided";
117
117
  AUTH_ERRORS["MISSING_RESET_FUNCTION"] = "Missing reset function";
118
+ AUTH_ERRORS["INVALID_RESET_FUNCTION_RESPONSE"] = "Invalid reset function response";
118
119
  AUTH_ERRORS["USER_NOT_CONFIRMED"] = "User not confirmed";
119
120
  })(AUTH_ERRORS || (exports.AUTH_ERRORS = AUTH_ERRORS = {}));
120
121
  const resolveAppPath = () => { var _a, _b, _c; return (_c = (_a = process.env.FLOWERBASE_APP_PATH) !== null && _a !== void 0 ? _a : (_b = require.main) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : process.cwd(); };
@@ -33,6 +33,10 @@ export declare const DEFAULT_CONFIG: {
33
33
  origin: string;
34
34
  methods: ALLOWED_METHODS[];
35
35
  };
36
+ MONGODB_ENCRYPTION_CONFIG: {
37
+ keyVaultDb: string;
38
+ keyVaultCollection: string;
39
+ };
36
40
  };
37
41
  export declare const API_VERSION: string;
38
42
  export declare const HTTPS_SCHEMA: string;
@@ -63,5 +67,11 @@ export declare const S3_CONFIG: {
63
67
  ACCESS_KEY_ID: string | undefined;
64
68
  SECRET_ACCESS_KEY: string | undefined;
65
69
  };
70
+ /**
71
+ * Name of the MongoDB client to use for change streams.
72
+ * This may be a separate instance because streams do not work
73
+ * when the main client has auto encryption enabled.
74
+ */
75
+ export declare const CHANGESTREAM = "changestream";
66
76
  export {};
67
77
  //# sourceMappingURL=constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AAsBpC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCsB,eAAe,EAAE;;CAEjE,CAAA;AACD,eAAO,MAAM,WAAW,QAA8C,CAAA;AACtE,eAAO,MAAM,YAAY,QAA8B,CAAA;AACvD,eAAO,MAAM,OAAO,QAAgB,CAAA;AACpC,eAAO,MAAM,YAAY,QAAiC,CAAA;AAE1D,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAA;AAE7E,eAAO,MAAM,WAAW;;;;;;;mBAOqB,aAAa;;;;;;;;;CAOzD,CAAA;AAID,eAAO,MAAM,SAAS;;;CAGrB,CAAA"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,IAAI,CAAA;AAsBpC,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCsB,eAAe,EAAE;;;;;;CAMjE,CAAA;AACD,eAAO,MAAM,WAAW,QAA8C,CAAA;AACtE,eAAO,MAAM,YAAY,QAA8B,CAAA;AACvD,eAAO,MAAM,OAAO,QAAgB,CAAA;AACpC,eAAO,MAAM,YAAY,QAAiC,CAAA;AAE1D,KAAK,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,CAAA;AAE7E,eAAO,MAAM,WAAW;;;;;;;mBAOqB,aAAa;;;;;;;;;CAOzD,CAAA;AAED,eAAO,MAAM,SAAS;;;CAGrB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,iBAAiB,CAAA"}
package/dist/constants.js CHANGED
@@ -12,7 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
12
12
  };
13
13
  var _a, _b, _c, _d, _e, _f, _g, _h;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.S3_CONFIG = exports.AUTH_CONFIG = exports.AUTH_DB_NAME = exports.DB_NAME = exports.HTTPS_SCHEMA = exports.API_VERSION = exports.DEFAULT_CONFIG = void 0;
15
+ exports.CHANGESTREAM = exports.S3_CONFIG = exports.AUTH_CONFIG = exports.AUTH_DB_NAME = exports.DB_NAME = exports.HTTPS_SCHEMA = exports.API_VERSION = exports.DEFAULT_CONFIG = void 0;
16
16
  const utils_1 = require("./auth/utils");
17
17
  const parseBoolean = (value) => {
18
18
  if (!value)
@@ -63,6 +63,10 @@ exports.DEFAULT_CONFIG = {
63
63
  CORS_OPTIONS: {
64
64
  origin: "*",
65
65
  methods: ["GET", "POST", "PUT", "DELETE"]
66
+ },
67
+ MONGODB_ENCRYPTION_CONFIG: {
68
+ keyVaultDb: "encryption",
69
+ keyVaultCollection: "__keyVault"
66
70
  }
67
71
  };
68
72
  exports.API_VERSION = `/api/client/${exports.DEFAULT_CONFIG.API_VERSION}`;
@@ -89,3 +93,9 @@ exports.S3_CONFIG = {
89
93
  ACCESS_KEY_ID: process.env.S3_ACCESS_KEY_ID,
90
94
  SECRET_ACCESS_KEY: process.env.S3_SECRET_ACCESS_KEY
91
95
  };
96
+ /**
97
+ * Name of the MongoDB client to use for change streams.
98
+ * This may be a separate instance because streams do not work
99
+ * when the main client has auto encryption enabled.
100
+ */
101
+ exports.CHANGESTREAM = "changestream";
@@ -0,0 +1,36 @@
1
+ import type { UUID } from "mongodb";
2
+ export type EncryptionSchemaProperty = EncryptionSchema | {
3
+ encrypt: {
4
+ algorithm: string;
5
+ bsonType: string;
6
+ keyAlias?: string;
7
+ };
8
+ };
9
+ export type EncryptionSchema = {
10
+ bsonType: "object";
11
+ properties: Record<string, EncryptionSchemaProperty>;
12
+ encryptMetadata?: {
13
+ keyAlias: string;
14
+ };
15
+ };
16
+ export type MappedEncryptionSchemaProperty = MappedEncryptionSchema | {
17
+ encrypt: {
18
+ algorithm: string;
19
+ bsonType: string;
20
+ keyId?: [UUID];
21
+ };
22
+ };
23
+ export type MappedEncryptionSchema = {
24
+ bsonType: "object";
25
+ properties: Record<string, MappedEncryptionSchemaProperty>;
26
+ encryptMetadata?: {
27
+ keyId: [UUID];
28
+ };
29
+ };
30
+ export type EncryptionSchemaFile = {
31
+ database: string;
32
+ collection: string;
33
+ schema: EncryptionSchema;
34
+ };
35
+ export type EncryptionSchemas = Record<string, EncryptionSchema>;
36
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../../src/features/encryption/interface.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAA;AAEnC,MAAM,MAAM,wBAAwB,GAChC,gBAAgB,GAChB;IACA,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,CAAA;CACF,CAAA;AAEH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,QAAQ,CAAA;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;IACpD,eAAe,CAAC,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAC;CACH,CAAA;AAGD,MAAM,MAAM,8BAA8B,GACtC,sBAAsB,GACtB;IACA,OAAO,EAAE;QACP,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;QAChB,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,CAAA;KACf,CAAA;CACF,CAAA;AAEH,MAAM,MAAM,sBAAsB,GAAG;IACnC,QAAQ,EAAE,QAAQ,CAAA;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAA;IAC1D,eAAe,CAAC,EAAE;QAChB,KAAK,EAAE,CAAC,IAAI,CAAC,CAAA;KACd,CAAC;CACH,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,EAAE,gBAAgB,CAAA;CACzB,CAAA;AAED,MAAM,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ import { EncryptionSchemas } from "./interface";
2
+ /**
3
+ * @experimental
4
+ * Schemas used for Client-Side Level Encryption configuration.
5
+ *
6
+ * **Important:** These schemas do not perform JSON validation.
7
+ */
8
+ export declare const loadEncryptionSchemas: (rootDir?: string) => Promise<EncryptionSchemas>;
9
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/encryption/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwB,iBAAiB,EAAE,MAAM,aAAa,CAAA;AAErE;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,GAAU,gBAAuB,KAAG,OAAO,CAAC,iBAAiB,CAW9F,CAAA"}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.loadEncryptionSchemas = void 0;
16
+ const node_path_1 = __importDefault(require("node:path"));
17
+ const utils_1 = require("../../utils");
18
+ /**
19
+ * @experimental
20
+ * Schemas used for Client-Side Level Encryption configuration.
21
+ *
22
+ * **Important:** These schemas do not perform JSON validation.
23
+ */
24
+ const loadEncryptionSchemas = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (rootDir = process.cwd()) {
25
+ const schemasRoot = node_path_1.default.join(rootDir, 'data_sources', 'mongodb-atlas');
26
+ const files = (0, utils_1.recursivelyCollectFiles)(schemasRoot);
27
+ const schemaFiles = files.filter((x) => x.endsWith('encryption.json'));
28
+ return schemaFiles.reduce((acc, filePath) => {
29
+ const { collection, database, schema } = (0, utils_1.readJsonContent)(filePath);
30
+ acc[`${database}.${collection}`] = schema;
31
+ return acc;
32
+ }, {});
33
+ });
34
+ exports.loadEncryptionSchemas = loadEncryptionSchemas;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/endpoints/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAKvE,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAU,gBAAuB,KAAG,OAAO,CAAC,SAAS,CA+B9E,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,KAAK,eAAe,EACpB,SAAS,UAAU,CAAC,OAAO,eAAe,CAAC,EAC3C,UAAU,MAAM;;;;;;;CAkDhB,CAAA;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,kEAM7B,qBAAqB,MACR,KAAK,cAAc,EAAE,KAAK,YAAY,gBA6CrD,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/features/endpoints/utils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAKvE,OAAO,EAAE,SAAS,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AAE9D;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAU,gBAAuB,KAAG,OAAO,CAAC,SAAS,CA+B9E,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,GAC3B,KAAK,eAAe,EACpB,SAAS,UAAU,CAAC,OAAO,eAAe,CAAC,EAC3C,UAAU,MAAM;;;;;;;CAkDhB,CAAA;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,kEAM7B,qBAAqB,MACR,KAAK,cAAc,EAAE,KAAK,YAAY,gBAgDrD,CAAA"}
@@ -135,6 +135,9 @@ const generateHandler = ({ app, currentFunction, functionName, functionsList, ru
135
135
  setStatusCode: (code) => {
136
136
  res.status(code);
137
137
  },
138
+ setHeader: (name, value) => {
139
+ res.header(name, value);
140
+ },
138
141
  setBody: (body) => {
139
142
  customResponseBody.data = body;
140
143
  }
@@ -1,6 +1,8 @@
1
+ import type { Document } from 'mongodb';
1
2
  import { FunctionController } from './interface';
2
3
  export declare const mapWatchFilterToChangeStreamMatch: (value: unknown) => unknown;
3
4
  export declare const mapWatchFilterToDocumentQuery: (value: unknown) => unknown;
5
+ export declare const shouldSkipReadabilityLookupForChange: (change: Document) => boolean;
4
6
  /**
5
7
  * > Creates a pre handler for every query
6
8
  * @param app -> the fastify instance
@@ -1 +1 @@
1
- {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/features/functions/controller.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAmHhD,eAAO,MAAM,iCAAiC,GAAI,OAAO,OAAO,KAAG,OA0BlE,CAAA;AAID,eAAO,MAAM,6BAA6B,GAAI,OAAO,OAAO,KAAG,OAgD9D,CAAA;AAqHD;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,kBAoRjC,CAAA"}
1
+ {"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/features/functions/controller.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAIvC,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AAmHhD,eAAO,MAAM,iCAAiC,GAAI,OAAO,OAAO,KAAG,OA0BlE,CAAA;AAID,eAAO,MAAM,6BAA6B,GAAI,OAAO,OAAO,KAAG,OAgD9D,CAAA;AAqHD,eAAO,MAAM,oCAAoC,GAAI,QAAQ,QAAQ,YAClC,CAAA;AAEnC;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,EAAE,kBAyRjC,CAAA"}
@@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) {
20
20
  return t;
21
21
  };
22
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.functionsController = exports.mapWatchFilterToDocumentQuery = exports.mapWatchFilterToChangeStreamMatch = void 0;
23
+ exports.functionsController = exports.shouldSkipReadabilityLookupForChange = exports.mapWatchFilterToDocumentQuery = exports.mapWatchFilterToChangeStreamMatch = void 0;
24
24
  const bson_1 = require("bson");
25
25
  const services_1 = require("../../services");
26
26
  const context_1 = require("../../utils/context");
@@ -262,6 +262,8 @@ const isReadableDocumentResult = (value) => !!value &&
262
262
  typeof value === 'object' &&
263
263
  !Array.isArray(value) &&
264
264
  Object.keys(value).length > 0;
265
+ const shouldSkipReadabilityLookupForChange = (change) => change.operationType === 'delete';
266
+ exports.shouldSkipReadabilityLookupForChange = shouldSkipReadabilityLookupForChange;
265
267
  /**
266
268
  * > Creates a pre handler for every query
267
269
  * @param app -> the fastify instance
@@ -431,6 +433,10 @@ const functionsController = (app_1, _a) => __awaiter(void 0, [app_1, _a], void 0
431
433
  const docId = (_b = (_a = change === null || change === void 0 ? void 0 : change.documentKey) === null || _a === void 0 ? void 0 : _a._id) !== null && _b !== void 0 ? _b : (_c = change === null || change === void 0 ? void 0 : change.fullDocument) === null || _c === void 0 ? void 0 : _c._id;
432
434
  if (typeof docId === 'undefined')
433
435
  return;
436
+ if ((0, exports.shouldSkipReadabilityLookupForChange)(change)) {
437
+ subscriberRes.write(`data: ${serializeEjson(change)}\n\n`);
438
+ return;
439
+ }
434
440
  const readQuery = subscriber.documentFilter
435
441
  ? { $and: [subscriber.documentFilter, { _id: docId }] }
436
442
  : { _id: docId };