@friggframework/core 2.0.0--canary.522.cbd3d5a.0 → 2.0.0--canary.517.35ee143.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.
Files changed (225) hide show
  1. package/CHANGELOG.md +67 -66
  2. package/CLAUDE.md +124 -148
  3. package/README.md +130 -165
  4. package/admin-scripts/index.js +16 -30
  5. package/admin-scripts/repositories/{admin-api-key-repository-documentdb.js → admin-process-repository-documentdb.js} +5 -5
  6. package/admin-scripts/repositories/{admin-api-key-repository-factory.js → admin-process-repository-factory.js} +15 -19
  7. package/admin-scripts/repositories/admin-process-repository-interface.js +150 -0
  8. package/admin-scripts/repositories/admin-process-repository-mongo.js +213 -0
  9. package/admin-scripts/repositories/admin-process-repository-postgres.js +251 -0
  10. package/admin-scripts/repositories/script-schedule-repository-factory.js +2 -6
  11. package/admin-scripts/repositories/script-schedule-repository-interface.js +14 -36
  12. package/admin-scripts/repositories/script-schedule-repository-mongo.js +13 -25
  13. package/admin-scripts/repositories/script-schedule-repository-postgres.js +13 -25
  14. package/application/commands/admin-script-commands.js +102 -266
  15. package/application/commands/integration-commands.js +6 -12
  16. package/application/index.js +3 -1
  17. package/assertions/get.js +4 -1
  18. package/associations/association.js +57 -59
  19. package/associations/model.js +41 -41
  20. package/core/CLAUDE.md +156 -222
  21. package/core/Worker.js +1 -5
  22. package/credential/repositories/credential-repository-documentdb.js +1 -71
  23. package/credential/repositories/credential-repository-interface.js +2 -8
  24. package/credential/repositories/credential-repository-mongo.js +4 -45
  25. package/credential/repositories/credential-repository-postgres.js +3 -44
  26. package/credential/repositories/credential-repository.js +4 -6
  27. package/credential/use-cases/get-credential-for-user.js +3 -21
  28. package/credential/use-cases/update-authentication-status.js +2 -5
  29. package/database/MONGODB_TRANSACTION_FIX.md +52 -72
  30. package/database/adapters/lambda-invoker.js +7 -8
  31. package/database/config.js +13 -15
  32. package/database/documentdb-encryption-service.js +13 -29
  33. package/database/documentdb-utils.js +12 -21
  34. package/database/encryption/README.md +36 -53
  35. package/database/encryption/encryption-schema-registry.js +9 -21
  36. package/database/encryption/field-encryption-service.js +4 -15
  37. package/database/encryption/logger.js +2 -3
  38. package/database/encryption/prisma-encryption-extension.js +8 -5
  39. package/database/index.js +2 -4
  40. package/database/models/IndividualUser.js +15 -15
  41. package/database/models/OrganizationUser.js +4 -6
  42. package/database/models/UserModel.js +2 -2
  43. package/database/models/WebsocketConnection.js +1 -4
  44. package/database/mongoose.js +2 -2
  45. package/database/prisma.js +14 -22
  46. package/database/repositories/health-check-repository-documentdb.js +7 -22
  47. package/database/repositories/health-check-repository-factory.js +3 -9
  48. package/database/repositories/health-check-repository-interface.js +5 -15
  49. package/database/repositories/health-check-repository-mongodb.js +6 -9
  50. package/database/repositories/health-check-repository-postgres.js +1 -1
  51. package/database/repositories/migration-status-repository-s3.js +5 -10
  52. package/database/use-cases/check-database-health-use-case.js +2 -3
  53. package/database/use-cases/check-database-state-use-case.js +7 -9
  54. package/database/use-cases/get-database-state-via-worker-use-case.js +12 -15
  55. package/database/use-cases/get-migration-status-use-case.js +2 -4
  56. package/database/use-cases/run-database-migration-use-case.js +9 -41
  57. package/database/use-cases/test-encryption-use-case.js +5 -4
  58. package/database/use-cases/trigger-database-migration-use-case.js +8 -9
  59. package/database/utils/mongodb-collection-utils.js +3 -11
  60. package/database/utils/mongodb-schema-init.js +4 -10
  61. package/database/utils/prisma-runner.js +74 -144
  62. package/database/utils/prisma-schema-parser.js +2 -2
  63. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +80 -135
  64. package/encrypt/Cryptor.js +2 -8
  65. package/errors/fetch-error.js +1 -1
  66. package/generated/prisma-mongodb/edge.js +16 -59
  67. package/generated/prisma-mongodb/index-browser.js +12 -62
  68. package/generated/prisma-mongodb/index.d.ts +4850 -8136
  69. package/generated/prisma-mongodb/index.js +16 -59
  70. package/generated/prisma-mongodb/package.json +1 -1
  71. package/generated/prisma-mongodb/schema.prisma +33 -75
  72. package/generated/prisma-mongodb/wasm.js +16 -59
  73. package/generated/prisma-postgresql/edge.js +15 -59
  74. package/generated/prisma-postgresql/index-browser.js +11 -62
  75. package/generated/prisma-postgresql/index.d.ts +5963 -8930
  76. package/generated/prisma-postgresql/index.js +15 -59
  77. package/generated/prisma-postgresql/package.json +1 -1
  78. package/generated/prisma-postgresql/schema.prisma +33 -73
  79. package/generated/prisma-postgresql/wasm.js +15 -59
  80. package/handlers/WEBHOOKS.md +81 -104
  81. package/handlers/app-definition-loader.js +1 -1
  82. package/handlers/app-handler-helpers.js +2 -14
  83. package/handlers/backend-utils.js +1 -0
  84. package/handlers/database-migration-handler.js +45 -64
  85. package/handlers/middleware/admin-auth.js +53 -0
  86. package/handlers/routers/HEALTHCHECK.md +135 -170
  87. package/handlers/routers/auth.js +2 -23
  88. package/handlers/routers/db-migration.handler.js +3 -2
  89. package/handlers/routers/db-migration.js +33 -69
  90. package/handlers/routers/health.js +8 -23
  91. package/handlers/routers/integration-defined-routers.js +4 -4
  92. package/handlers/routers/integration-webhook-routers.js +7 -17
  93. package/handlers/routers/websocket.js +3 -9
  94. package/handlers/use-cases/check-integrations-health-use-case.js +6 -13
  95. package/handlers/workers/db-migration.js +26 -54
  96. package/index.js +9 -5
  97. package/integrations/WEBHOOK-QUICKSTART.md +14 -21
  98. package/integrations/index.js +0 -4
  99. package/integrations/integration-base.js +6 -9
  100. package/integrations/integration-router.js +146 -1817
  101. package/integrations/options.js +20 -47
  102. package/integrations/repositories/integration-repository-documentdb.js +24 -53
  103. package/integrations/repositories/integration-repository-factory.js +2 -6
  104. package/integrations/repositories/integration-repository-interface.js +9 -27
  105. package/integrations/repositories/integration-repository-postgres.js +3 -3
  106. package/integrations/repositories/process-repository-factory.js +1 -0
  107. package/integrations/repositories/process-repository-interface.js +5 -9
  108. package/integrations/repositories/process-repository-mongo.js +3 -7
  109. package/integrations/repositories/process-repository-postgres.js +2 -2
  110. package/integrations/tests/doubles/config-capturing-integration.js +8 -9
  111. package/integrations/tests/doubles/dummy-integration-class.js +8 -81
  112. package/integrations/tests/doubles/test-integration-repository.js +11 -51
  113. package/integrations/use-cases/create-integration.js +32 -36
  114. package/integrations/use-cases/create-process.js +9 -20
  115. package/integrations/use-cases/delete-integration-for-user.js +4 -5
  116. package/integrations/use-cases/get-integration-for-user.js +10 -25
  117. package/integrations/use-cases/get-integration-instance-by-definition.js +7 -13
  118. package/integrations/use-cases/get-integrations-for-user.js +1 -4
  119. package/integrations/use-cases/get-possible-integrations.js +1 -1
  120. package/integrations/use-cases/get-process.js +6 -5
  121. package/integrations/use-cases/index.js +1 -3
  122. package/integrations/use-cases/load-integration-context.js +5 -1
  123. package/integrations/use-cases/update-process-state.js +8 -10
  124. package/integrations/utils/map-integration-dto.js +3 -9
  125. package/jest-setup.js +1 -1
  126. package/jest-teardown.js +1 -1
  127. package/lambda/TimeoutCatcher.js +30 -32
  128. package/lambda/index.js +1 -1
  129. package/logs/index.js +3 -3
  130. package/modules/module.js +1 -3
  131. package/modules/repositories/module-repository-documentdb.js +48 -114
  132. package/modules/repositories/module-repository-interface.js +0 -13
  133. package/modules/repositories/module-repository-mongo.js +6 -46
  134. package/modules/repositories/module-repository-postgres.js +6 -48
  135. package/modules/repositories/module-repository.js +1 -34
  136. package/modules/requester/api-key.js +2 -0
  137. package/modules/requester/basic.js +1 -0
  138. package/modules/requester/oauth-2.js +2 -3
  139. package/modules/test/mock-api/definition.js +10 -15
  140. package/modules/test/mock-api/mocks/hubspot.js +36 -36
  141. package/modules/tests/doubles/test-module-factory.js +4 -10
  142. package/modules/tests/doubles/test-module-repository.js +1 -1
  143. package/modules/use-cases/get-entities-for-user.js +1 -1
  144. package/modules/use-cases/get-entity-options-by-id.js +6 -8
  145. package/modules/use-cases/get-module.js +9 -12
  146. package/modules/use-cases/process-authorization-callback.js +6 -12
  147. package/modules/use-cases/refresh-entity-options.js +6 -8
  148. package/modules/use-cases/test-module-auth.js +6 -8
  149. package/modules/utils/map-module-dto.js +2 -2
  150. package/package.json +5 -7
  151. package/prisma-mongodb/schema.prisma +33 -75
  152. package/prisma-postgresql/schema.prisma +33 -73
  153. package/queues/queuer-util.js +1 -5
  154. package/syncs/model.js +51 -51
  155. package/syncs/repositories/sync-repository-documentdb.js +19 -39
  156. package/syncs/repositories/sync-repository-interface.js +2 -6
  157. package/syncs/repositories/sync-repository-postgres.js +13 -19
  158. package/syncs/sync.js +100 -104
  159. package/token/repositories/token-repository-factory.js +3 -1
  160. package/types/assertions/index.d.ts +72 -72
  161. package/types/associations/index.d.ts +57 -57
  162. package/types/core/index.d.ts +53 -59
  163. package/types/database/index.d.ts +2 -2
  164. package/types/encrypt/index.d.ts +3 -3
  165. package/types/errors/index.d.ts +54 -61
  166. package/types/eslint-config/index.d.ts +40 -40
  167. package/types/integrations/index.d.ts +183 -185
  168. package/types/lambda/index.d.ts +26 -26
  169. package/types/logs/index.d.ts +4 -4
  170. package/types/module-plugin/index.d.ts +237 -239
  171. package/types/prettier-config/index.d.ts +5 -5
  172. package/types/syncs/index.d.ts +108 -102
  173. package/types/test-environment/index.d.ts +14 -14
  174. package/types/tsconfig.json +93 -95
  175. package/user/tests/doubles/test-user-repository.js +2 -5
  176. package/user/use-cases/authenticate-user.js +4 -2
  177. package/user/use-cases/authenticate-with-shared-secret.js +1 -1
  178. package/user/use-cases/create-individual-user.js +7 -8
  179. package/user/use-cases/create-organization-user.js +1 -1
  180. package/user/use-cases/create-token-for-user-id.js +1 -1
  181. package/user/use-cases/get-user-from-adopter-jwt.js +2 -0
  182. package/user/use-cases/get-user-from-bearer-token.js +3 -7
  183. package/user/use-cases/get-user-from-x-frigg-headers.js +11 -14
  184. package/user/use-cases/login-user.js +8 -8
  185. package/user/user.js +4 -18
  186. package/utils/backend-path.js +2 -2
  187. package/utils/index.js +1 -4
  188. package/websocket/repositories/websocket-connection-repository-documentdb.js +8 -21
  189. package/websocket/repositories/websocket-connection-repository-mongo.js +4 -8
  190. package/websocket/repositories/websocket-connection-repository-postgres.js +4 -8
  191. package/websocket/repositories/websocket-connection-repository.js +4 -8
  192. package/admin-scripts/repositories/admin-api-key-repository-interface.js +0 -121
  193. package/admin-scripts/repositories/admin-api-key-repository-mongo.js +0 -155
  194. package/admin-scripts/repositories/admin-api-key-repository-postgres.js +0 -189
  195. package/admin-scripts/repositories/script-execution-repository-documentdb.js +0 -21
  196. package/admin-scripts/repositories/script-execution-repository-factory.js +0 -55
  197. package/admin-scripts/repositories/script-execution-repository-interface.js +0 -193
  198. package/admin-scripts/repositories/script-execution-repository-mongo.js +0 -278
  199. package/admin-scripts/repositories/script-execution-repository-postgres.js +0 -320
  200. package/credential/credential-router.js +0 -262
  201. package/credential/use-cases/delete-credential-for-user.js +0 -50
  202. package/credential/use-cases/list-credentials-for-user.js +0 -31
  203. package/credential/use-cases/reauthorize-credential.js +0 -103
  204. package/handlers/routers/admin.js +0 -450
  205. package/handlers/routers/docs.js +0 -180
  206. package/handlers/routers/middleware/loadUser.js +0 -39
  207. package/handlers/routers/middleware/requireAdmin.js +0 -41
  208. package/handlers/routers/middleware/requireLoggedInUser.js +0 -19
  209. package/integrations/use-cases/execute-proxy-request.js +0 -564
  210. package/modules/domain/entities/AuthorizationSession.js +0 -131
  211. package/modules/domain/entities/index.js +0 -10
  212. package/modules/repositories/authorization-session-repository-factory.js +0 -55
  213. package/modules/repositories/authorization-session-repository-interface.js +0 -75
  214. package/modules/repositories/authorization-session-repository-mongo.js +0 -169
  215. package/modules/repositories/authorization-session-repository-postgres.js +0 -170
  216. package/modules/use-cases/delete-module-entity.js +0 -23
  217. package/modules/use-cases/get-authorization-requirements.js +0 -110
  218. package/modules/use-cases/get-module-entity-by-id.js +0 -16
  219. package/modules/use-cases/process-authorization-step.js +0 -160
  220. package/modules/use-cases/start-authorization-session.js +0 -86
  221. package/modules/use-cases/update-module-entity.js +0 -27
  222. package/openapi/openapi-spec-generator.js +0 -370
  223. package/openapi/openapi-v1.yaml +0 -1360
  224. package/openapi/openapi-v2.yaml +0 -1535
  225. package/user/use-cases/delete-user.js +0 -47
@@ -5,7 +5,7 @@
5
5
 
6
6
  /**
7
7
  * Determines database type from environment or app definition
8
- *
8
+ *
9
9
  * Detection order:
10
10
  * 1. DB_TYPE environment variable (set for migration handlers)
11
11
  * 2. App definition (backend/index.js Definition.database configuration)
@@ -32,7 +32,7 @@ function getDatabaseType() {
32
32
  if (!backendPackagePath) {
33
33
  throw new Error(
34
34
  '[Frigg] Cannot find backend package.json. ' +
35
- 'Ensure backend/package.json exists in your project.'
35
+ 'Ensure backend/package.json exists in your project.'
36
36
  );
37
37
  }
38
38
 
@@ -42,7 +42,7 @@ function getDatabaseType() {
42
42
  if (!fs.existsSync(backendIndexPath)) {
43
43
  throw new Error(
44
44
  `[Frigg] Backend index.js not found at ${backendIndexPath}. ` +
45
- 'Ensure backend/index.js exists with a Definition export.'
45
+ 'Ensure backend/index.js exists with a Definition export.'
46
46
  );
47
47
  }
48
48
 
@@ -57,9 +57,7 @@ function getDatabaseType() {
57
57
 
58
58
  for (const line of stackLines) {
59
59
  // Match file paths in stack trace, excluding node:internal
60
- const match =
61
- line.match(/\(([^)]+\.js):\d+:\d+\)/) ||
62
- line.match(/at ([^(]+\.js):\d+:\d+/);
60
+ const match = line.match(/\(([^)]+\.js):\d+:\d+\)/) || line.match(/at ([^(]+\.js):\d+:\d+/);
63
61
  if (match && match[1] && !match[1].includes('node:internal')) {
64
62
  errorFile = match[1];
65
63
  break;
@@ -69,11 +67,11 @@ function getDatabaseType() {
69
67
  // Provide better error context for syntax/runtime errors
70
68
  throw new Error(
71
69
  `[Frigg] Failed to load app definition from ${backendIndexPath}\n` +
72
- `Error: ${requireError.message}\n` +
73
- `File with error: ${errorFile}\n` +
74
- `\nFull stack trace:\n${requireError.stack}\n\n` +
75
- 'This error occurred while loading your app definition or its dependencies. ' +
76
- 'Check the file listed above for syntax errors (trailing commas, missing brackets, etc.)'
70
+ `Error: ${requireError.message}\n` +
71
+ `File with error: ${errorFile}\n` +
72
+ `\nFull stack trace:\n${requireError.stack}\n\n` +
73
+ 'This error occurred while loading your app definition or its dependencies. ' +
74
+ 'Check the file listed above for syntax errors (trailing commas, missing brackets, etc.)'
77
75
  );
78
76
  }
79
77
 
@@ -82,7 +80,7 @@ function getDatabaseType() {
82
80
  if (!database) {
83
81
  throw new Error(
84
82
  '[Frigg] App definition missing database configuration. ' +
85
- `Add database: { postgres: { enable: true } } (or mongoDB/documentDB) to ${backendIndexPath}`
83
+ `Add database: { postgres: { enable: true } } (or mongoDB/documentDB) to ${backendIndexPath}`
86
84
  );
87
85
  }
88
86
 
@@ -100,7 +98,7 @@ function getDatabaseType() {
100
98
 
101
99
  throw new Error(
102
100
  '[Frigg] No database enabled in app definition. ' +
103
- 'Set one of: database.postgres.enable, database.mongoDB.enable, or database.documentDB.enable to true'
101
+ 'Set one of: database.postgres.enable, database.mongoDB.enable, or database.documentDB.enable to true'
104
102
  );
105
103
  } catch (error) {
106
104
  // Re-throw with context if it's our error
@@ -152,5 +150,5 @@ Object.defineProperty(module.exports, 'DB_TYPE', {
152
150
  return cachedDbType;
153
151
  },
154
152
  enumerable: true,
155
- configurable: true,
156
- });
153
+ configurable: true
154
+ });
@@ -1,8 +1,5 @@
1
1
  const { Cryptor } = require('../encrypt/Cryptor');
2
- const {
3
- getEncryptedFields,
4
- loadCustomEncryptionSchema,
5
- } = require('./encryption/encryption-schema-registry');
2
+ const { getEncryptedFields, loadCustomEncryptionSchema } = require('./encryption/encryption-schema-registry');
6
3
 
7
4
  /**
8
5
  * Encryption service specifically for DocumentDB repositories
@@ -54,11 +51,8 @@ class DocumentDBEncryptionService {
54
51
  loadCustomEncryptionSchema();
55
52
 
56
53
  // Match logic from packages/core/database/prisma.js
57
- const stage =
58
- process.env.STAGE || process.env.NODE_ENV || 'development';
59
- const bypassEncryption = ['dev', 'test', 'local'].includes(
60
- stage.toLowerCase()
61
- );
54
+ const stage = process.env.STAGE || process.env.NODE_ENV || 'development';
55
+ const bypassEncryption = ['dev', 'test', 'local'].includes(stage.toLowerCase());
62
56
 
63
57
  if (bypassEncryption) {
64
58
  this.cryptor = null;
@@ -67,17 +61,11 @@ class DocumentDBEncryptionService {
67
61
  }
68
62
 
69
63
  // Determine encryption method (ensure boolean values)
70
- const hasKMS = !!(
71
- process.env.KMS_KEY_ARN && process.env.KMS_KEY_ARN.trim() !== ''
72
- );
73
- const hasAES = !!(
74
- process.env.AES_KEY_ID && process.env.AES_KEY_ID.trim() !== ''
75
- );
64
+ const hasKMS = !!(process.env.KMS_KEY_ARN && process.env.KMS_KEY_ARN.trim() !== '');
65
+ const hasAES = !!(process.env.AES_KEY_ID && process.env.AES_KEY_ID.trim() !== '');
76
66
 
77
67
  if (!hasKMS && !hasAES) {
78
- console.warn(
79
- '[DocumentDBEncryptionService] No encryption keys configured. Encryption disabled.'
80
- );
68
+ console.warn('[DocumentDBEncryptionService] No encryption keys configured. Encryption disabled.');
81
69
  this.cryptor = null;
82
70
  this.enabled = false;
83
71
  return;
@@ -214,16 +202,14 @@ class DocumentDBEncryptionService {
214
202
 
215
203
  try {
216
204
  // Convert to string if needed
217
- const stringValue =
218
- typeof value === 'string' ? value : JSON.stringify(value);
205
+ const stringValue = typeof value === 'string'
206
+ ? value
207
+ : JSON.stringify(value);
219
208
 
220
209
  // Encrypt using Cryptor
221
210
  current[fieldName] = await this.cryptor.encrypt(stringValue);
222
211
  } catch (error) {
223
- console.error(
224
- `[DocumentDBEncryptionService] Failed to encrypt ${modelName}.${fieldPath}:`,
225
- error.message
226
- );
212
+ console.error(`[DocumentDBEncryptionService] Failed to encrypt ${modelName}.${fieldPath}:`, error.message);
227
213
  throw error;
228
214
  }
229
215
  }
@@ -275,7 +261,7 @@ class DocumentDBEncryptionService {
275
261
  modelName,
276
262
  fieldPath,
277
263
  encryptedValuePrefix: encryptedValue.substring(0, 20),
278
- errorMessage: error.message,
264
+ errorMessage: error.message
279
265
  };
280
266
 
281
267
  console.error(
@@ -284,9 +270,7 @@ class DocumentDBEncryptionService {
284
270
  );
285
271
 
286
272
  // Throw error to fail fast - don't silently corrupt data
287
- throw new Error(
288
- `Decryption failed for ${modelName}.${fieldPath}: ${error.message}`
289
- );
273
+ throw new Error(`Decryption failed for ${modelName}.${fieldPath}: ${error.message}`);
290
274
  }
291
275
  }
292
276
 
@@ -323,7 +307,7 @@ class DocumentDBEncryptionService {
323
307
  const base64Pattern = /^[A-Za-z0-9+/=]+$/;
324
308
 
325
309
  // All parts should be base64-encoded
326
- if (!parts.every((part) => base64Pattern.test(part))) {
310
+ if (!parts.every(part => base64Pattern.test(part))) {
327
311
  return false;
328
312
  }
329
313
 
@@ -3,10 +3,8 @@ const { ObjectId } = require('mongodb');
3
3
  function toObjectId(value) {
4
4
  if (value === null || value === undefined || value === '') return undefined;
5
5
  if (value instanceof ObjectId) return value;
6
- if (typeof value === 'object' && value.$oid)
7
- return new ObjectId(value.$oid);
8
- if (typeof value === 'string')
9
- return ObjectId.isValid(value) ? new ObjectId(value) : undefined;
6
+ if (typeof value === 'object' && value.$oid) return new ObjectId(value.$oid);
7
+ if (typeof value === 'string') return ObjectId.isValid(value) ? new ObjectId(value) : undefined;
10
8
  return undefined;
11
9
  }
12
10
 
@@ -17,8 +15,7 @@ function toObjectIdArray(values) {
17
15
 
18
16
  function fromObjectId(value) {
19
17
  if (value instanceof ObjectId) return value.toHexString();
20
- if (typeof value === 'object' && value !== null && value.$oid)
21
- return value.$oid;
18
+ if (typeof value === 'object' && value !== null && value.$oid) return value.$oid;
22
19
  if (typeof value === 'string') return value;
23
20
  return value === undefined || value === null ? value : String(value);
24
21
  }
@@ -33,10 +30,7 @@ async function findMany(client, collection, filter = {}, options = {}) {
33
30
  }
34
31
 
35
32
  async function findOne(client, collection, filter = {}, options = {}) {
36
- const docs = await findMany(client, collection, filter, {
37
- ...options,
38
- limit: 1,
39
- });
33
+ const docs = await findMany(client, collection, filter, { ...options, limit: 1 });
40
34
  return docs[0] || null;
41
35
  }
42
36
 
@@ -53,9 +47,7 @@ async function insertOne(client, collection, document) {
53
47
  // Validate insert succeeded
54
48
  if (result.ok !== 1) {
55
49
  throw new Error(
56
- `Insert command failed for collection '${collection}': ${JSON.stringify(
57
- result
58
- )}`
50
+ `Insert command failed for collection '${collection}': ${JSON.stringify(result)}`
59
51
  );
60
52
  }
61
53
 
@@ -75,7 +67,7 @@ async function insertOne(client, collection, document) {
75
67
  if (result.n !== 1) {
76
68
  throw new Error(
77
69
  `Expected to insert 1 document into '${collection}', but inserted ${result.n}. ` +
78
- `Result: ${JSON.stringify(result)}`
70
+ `Result: ${JSON.stringify(result)}`
79
71
  );
80
72
  }
81
73
 
@@ -83,13 +75,11 @@ async function insertOne(client, collection, document) {
83
75
  }
84
76
 
85
77
  async function updateOne(client, collection, filter, update, options = {}) {
86
- const updates = [
87
- {
88
- q: filter,
89
- u: update,
90
- upsert: Boolean(options.upsert),
91
- },
92
- ];
78
+ const updates = [{
79
+ q: filter,
80
+ u: update,
81
+ upsert: Boolean(options.upsert),
82
+ }];
93
83
  if (options.arrayFilters) updates[0].arrayFilters = options.arrayFilters;
94
84
  const result = await client.$runCommandRaw({
95
85
  update: collection,
@@ -143,3 +133,4 @@ module.exports = {
143
133
  deleteMany,
144
134
  aggregate,
145
135
  };
136
+
@@ -125,11 +125,10 @@ Or simply don't configure any encryption keys. In Production field level encrypt
125
125
  Core and custom encrypted fields are defined in `encryption-schema-registry.js`. See that file for the current list of encrypted fields.
126
126
 
127
127
  **Core fields include**:
128
-
129
- - OAuth tokens: `access_token`, `refresh_token`, `id_token`
130
- - API keys: `api_key`, `apiKey`, `API_KEY_VALUE`
131
- - Basic auth: `password`
132
- - OAuth client credentials: `client_secret`
128
+ - OAuth tokens: `access_token`, `refresh_token`, `id_token`
129
+ - API keys: `api_key`, `apiKey`, `API_KEY_VALUE`
130
+ - Basic auth: `password`
131
+ - OAuth client credentials: `client_secret`
133
132
 
134
133
  **Note**: API modules should use `api_key` (snake_case) in their `apiPropertiesToPersist.credential` arrays for consistency with OAuth2Requester and BasicAuthRequester conventions.
135
134
 
@@ -138,36 +137,34 @@ Core and custom encrypted fields are defined in `encryption-schema-registry.js`.
138
137
  When creating API module definitions, use **snake_case** for credential property names to ensure automatic encryption:
139
138
 
140
139
  **✅ Recommended (automatically encrypted):**
141
-
142
140
  ```javascript
143
141
  // API Module Definition
144
142
  const Definition = {
145
143
  requiredAuthMethods: {
146
144
  apiPropertiesToPersist: {
147
145
  // For API key authentication
148
- credential: ['api_key'], // ✅ Automatically encrypted
146
+ credential: ['api_key'], // ✅ Automatically encrypted
149
147
  // or for OAuth authentication
150
- credential: ['access_token', 'refresh_token'], // ✅ OAuth - encrypted
148
+ credential: ['access_token', 'refresh_token'], // ✅ OAuth - encrypted
151
149
  // or for Basic authentication
152
- credential: ['username', 'password'], // ✅ Basic auth - encrypted
153
- },
154
- },
150
+ credential: ['username', 'password'], // ✅ Basic auth - encrypted
151
+ }
152
+ }
155
153
  };
156
154
 
157
155
  // API class (extends ApiKeyRequester)
158
156
  class MyApi extends ApiKeyRequester {
159
157
  constructor(params) {
160
158
  super(params);
161
- this.api_key = params.api_key; // ✅ snake_case convention
159
+ this.api_key = params.api_key; // ✅ snake_case convention
162
160
  }
163
161
  }
164
162
  ```
165
163
 
166
164
  **❌ Avoid (requires manual encryption schema):**
167
-
168
165
  ```javascript
169
166
  apiPropertiesToPersist: {
170
- credential: ['customToken', 'proprietaryKey']; // ❌ Not in core schema
167
+ credential: ['customToken', 'proprietaryKey'] // ❌ Not in core schema
171
168
  }
172
169
  ```
173
170
 
@@ -187,61 +184,57 @@ const Definition = {
187
184
 
188
185
  // Declare which credential fields need encryption
189
186
  encryption: {
190
- credentialFields: ['api_key', 'webhook_secret'],
187
+ credentialFields: ['api_key', 'webhook_secret']
191
188
  },
192
189
 
193
190
  requiredAuthMethods: {
194
191
  apiPropertiesToPersist: {
195
- credential: ['api_key', 'webhook_secret'], // These will be auto-encrypted
196
- entity: [],
192
+ credential: ['api_key', 'webhook_secret'], // These will be auto-encrypted
193
+ entity: []
197
194
  },
198
195
  // ... other methods
199
- },
196
+ }
200
197
  };
201
198
  ```
202
199
 
203
200
  **How it works**:
204
-
205
201
  1. Module declares `encryption.credentialFields` array
206
202
  2. Framework automatically adds `data.` prefix: `['api_key']` → `['data.api_key']`
207
203
  3. Fields are merged with core encryption schema on app startup
208
204
  4. All modules across all integrations are scanned and combined
209
205
 
210
206
  **Benefits**:
211
-
212
- - ✅ Module authors control their own security requirements
213
- - ✅ No need to modify core framework or app configuration
214
- - ✅ Automatic encryption for API key-based integrations
215
- - ✅ Works seamlessly with `apiPropertiesToPersist`
207
+ - ✅ Module authors control their own security requirements
208
+ - ✅ No need to modify core framework or app configuration
209
+ - ✅ Automatic encryption for API key-based integrations
210
+ - ✅ Works seamlessly with `apiPropertiesToPersist`
216
211
 
217
212
  **Example - API Key Module**:
218
-
219
213
  ```javascript
220
214
  // API Module Definition
221
215
  const Definition = {
222
216
  moduleName: 'axiscare',
223
217
  API: AxisCareApi,
224
218
  encryption: {
225
- credentialFields: ['api_key'], // Auto-encrypted as 'data.api_key'
219
+ credentialFields: ['api_key'] // Auto-encrypted as 'data.api_key'
226
220
  },
227
221
  requiredAuthMethods: {
228
222
  apiPropertiesToPersist: {
229
- credential: ['api_key'], // Will be encrypted automatically
230
- },
231
- },
223
+ credential: ['api_key'] // Will be encrypted automatically
224
+ }
225
+ }
232
226
  };
233
227
 
234
228
  // API Class (extends ApiKeyRequester)
235
229
  class AxisCareApi extends ApiKeyRequester {
236
230
  constructor(params) {
237
231
  super(params);
238
- this.api_key = params.api_key; // snake_case convention
232
+ this.api_key = params.api_key; // snake_case convention
239
233
  }
240
234
  }
241
235
  ```
242
236
 
243
237
  **Example - Custom Authentication**:
244
-
245
238
  ```javascript
246
239
  const Definition = {
247
240
  moduleName: 'customService',
@@ -249,17 +242,16 @@ const Definition = {
249
242
  credentialFields: [
250
243
  'signing_key',
251
244
  'webhook_secret',
252
- 'data.custom_nested_field', // Can specify data. prefix explicitly
253
- ],
254
- },
245
+ 'data.custom_nested_field' // Can specify data. prefix explicitly
246
+ ]
247
+ }
255
248
  };
256
249
  ```
257
250
 
258
251
  **Limitations**:
259
-
260
- - Only supports Credential model fields (stored in `credential.data`)
261
- - Cannot encrypt entity fields or custom models (use app-level schema for those)
262
- - Applied globally once - module schemas loaded at app startup
252
+ - Only supports Credential model fields (stored in `credential.data`)
253
+ - Cannot encrypt entity fields or custom models (use app-level schema for those)
254
+ - Applied globally once - module schemas loaded at app startup
263
255
 
264
256
  #### Option 2: App-Level Custom Schema (Integration Developers)
265
257
 
@@ -537,9 +529,7 @@ For DocumentDB repositories, use `DocumentDBEncryptionService` to manually encry
537
529
  #### Usage Example
538
530
 
539
531
  ```javascript
540
- const {
541
- DocumentDBEncryptionService,
542
- } = require('../documentdb-encryption-service');
532
+ const { DocumentDBEncryptionService } = require('../documentdb-encryption-service');
543
533
  const { insertOne, findOne } = require('../documentdb-utils');
544
534
 
545
535
  class MyRepositoryDocumentDB {
@@ -549,18 +539,12 @@ class MyRepositoryDocumentDB {
549
539
 
550
540
  async create(data) {
551
541
  // Encrypt before write
552
- const encrypted = await this.encryptionService.encryptFields(
553
- 'ModelName',
554
- data
555
- );
542
+ const encrypted = await this.encryptionService.encryptFields('ModelName', data);
556
543
  const id = await insertOne(this.prisma, 'CollectionName', encrypted);
557
544
 
558
545
  // Decrypt after read
559
546
  const doc = await findOne(this.prisma, 'CollectionName', { _id: id });
560
- const decrypted = await this.encryptionService.decryptFields(
561
- 'ModelName',
562
- doc
563
- );
547
+ const decrypted = await this.encryptionService.decryptFields('ModelName', doc);
564
548
 
565
549
  return decrypted;
566
550
  }
@@ -570,10 +554,9 @@ class MyRepositoryDocumentDB {
570
554
  #### Configuration
571
555
 
572
556
  Uses the same environment variables and Cryptor as the Prisma Extension:
573
-
574
- - `STAGE`: Bypasses encryption for dev/test/local
575
- - `KMS_KEY_ARN`: AWS KMS encryption (production)
576
- - `AES_KEY_ID` + `AES_KEY`: AES encryption (fallback)
557
+ - `STAGE`: Bypasses encryption for dev/test/local
558
+ - `KMS_KEY_ARN`: AWS KMS encryption (production)
559
+ - `AES_KEY_ID` + `AES_KEY`: AES encryption (fallback)
577
560
 
578
561
  ## Usage Examples
579
562
 
@@ -72,9 +72,7 @@ function validateCustomSchema(schema) {
72
72
 
73
73
  for (const fieldPath of config.fields) {
74
74
  if (typeof fieldPath !== 'string' || !fieldPath) {
75
- errors.push(
76
- `Model "${modelName}" has invalid field path: ${fieldPath}`
77
- );
75
+ errors.push(`Model "${modelName}" has invalid field path: ${fieldPath}`);
78
76
  }
79
77
 
80
78
  // Check if trying to override core fields
@@ -106,17 +104,13 @@ function registerCustomSchema(schema) {
106
104
  const validation = validateCustomSchema(schema);
107
105
  if (!validation.valid) {
108
106
  throw new Error(
109
- `Invalid custom encryption schema:\n- ${validation.errors.join(
110
- '\n- '
111
- )}`
107
+ `Invalid custom encryption schema:\n- ${validation.errors.join('\n- ')}`
112
108
  );
113
109
  }
114
110
 
115
111
  customSchema = { ...schema };
116
112
  logger.info(
117
- `Registered custom encryption schema for models: ${Object.keys(
118
- customSchema
119
- ).join(', ')}`
113
+ `Registered custom encryption schema for models: ${Object.keys(customSchema).join(', ')}`
120
114
  );
121
115
  }
122
116
 
@@ -139,9 +133,7 @@ function extractCredentialFieldsFromModules(moduleDefinitions) {
139
133
  }
140
134
 
141
135
  for (const field of credentialFields) {
142
- const prefixedField = field.startsWith('data.')
143
- ? field
144
- : `data.${field}`;
136
+ const prefixedField = field.startsWith('data.') ? field : `data.${field}`;
145
137
  fields.push(prefixedField);
146
138
  }
147
139
  }
@@ -168,14 +160,10 @@ function loadModuleEncryptionSchemas(integrations) {
168
160
  return;
169
161
  }
170
162
 
171
- const {
172
- getModulesDefinitionFromIntegrationClasses,
173
- } = require('../integrations/utils/map-integration-dto');
163
+ const { getModulesDefinitionFromIntegrationClasses } = require('../integrations/utils/map-integration-dto');
174
164
 
175
- const moduleDefinitions =
176
- getModulesDefinitionFromIntegrationClasses(integrations);
177
- const credentialFields =
178
- extractCredentialFieldsFromModules(moduleDefinitions);
165
+ const moduleDefinitions = getModulesDefinitionFromIntegrationClasses(integrations);
166
+ const credentialFields = extractCredentialFieldsFromModules(moduleDefinitions);
179
167
 
180
168
  if (credentialFields.length === 0) {
181
169
  return;
@@ -183,8 +171,8 @@ function loadModuleEncryptionSchemas(integrations) {
183
171
 
184
172
  const moduleSchema = {
185
173
  Credential: {
186
- fields: credentialFields,
187
- },
174
+ fields: credentialFields
175
+ }
188
176
  };
189
177
 
190
178
  logger.info(
@@ -35,9 +35,7 @@ class FieldEncryptionService {
35
35
 
36
36
  if (this._shouldEncrypt(value)) {
37
37
  const serializedValue = this._serializeForEncryption(value);
38
- const encryptedValue = await this.cryptor.encrypt(
39
- serializedValue
40
- );
38
+ const encryptedValue = await this.cryptor.encrypt(serializedValue);
41
39
  return { fieldPath, encryptedValue };
42
40
  }
43
41
  return null;
@@ -48,11 +46,7 @@ class FieldEncryptionService {
48
46
  // Apply encrypted values
49
47
  for (const result of results) {
50
48
  if (result) {
51
- this._setNestedValue(
52
- encrypted,
53
- result.fieldPath,
54
- result.encryptedValue
55
- );
49
+ this._setNestedValue(encrypted, result.fieldPath, result.encryptedValue);
56
50
  }
57
51
  }
58
52
 
@@ -77,8 +71,7 @@ class FieldEncryptionService {
77
71
 
78
72
  if (this._isEncrypted(value)) {
79
73
  const decryptedValue = await this.cryptor.decrypt(value);
80
- const deserializedValue =
81
- this._deserializeAfterDecryption(decryptedValue);
74
+ const deserializedValue = this._deserializeAfterDecryption(decryptedValue);
82
75
  return { fieldPath, decryptedValue: deserializedValue };
83
76
  }
84
77
  return null;
@@ -89,11 +82,7 @@ class FieldEncryptionService {
89
82
  // Apply decrypted values
90
83
  for (const result of results) {
91
84
  if (result) {
92
- this._setNestedValue(
93
- decrypted,
94
- result.fieldPath,
95
- result.decryptedValue
96
- );
85
+ this._setNestedValue(decrypted, result.fieldPath, result.decryptedValue);
97
86
  }
98
87
  }
99
88
 
@@ -30,9 +30,8 @@ class EncryptionLogger {
30
30
  // Remove potential key material or encrypted data from logs
31
31
  if (typeof message === 'string') {
32
32
  // Truncate long base64 strings that might be keys or encrypted data
33
- return message.replace(
34
- /([A-Za-z0-9+/=]{50,})/g,
35
- (match) => `${match.substring(0, 10)}...[${match.length} chars]`
33
+ return message.replace(/([A-Za-z0-9+/=]{50,})/g, (match) =>
34
+ `${match.substring(0, 10)}...[${match.length} chars]`
36
35
  );
37
36
  }
38
37
  return message;
@@ -12,7 +12,9 @@ function createEncryptionExtension({ cryptor, enabled = true }) {
12
12
  }
13
13
 
14
14
  if (!cryptor) {
15
- throw new Error('Cryptor instance required for encryption extension');
15
+ throw new Error(
16
+ 'Cryptor instance required for encryption extension'
17
+ );
16
18
  }
17
19
 
18
20
  const encryptionService = new FieldEncryptionService({
@@ -46,10 +48,11 @@ function createEncryptionExtension({ cryptor, enabled = true }) {
46
48
 
47
49
  async createMany({ model, args, query }) {
48
50
  if (args.data && Array.isArray(args.data)) {
49
- args.data = await encryptionService.encryptFieldsInBulk(
50
- model,
51
- args.data
52
- );
51
+ args.data =
52
+ await encryptionService.encryptFieldsInBulk(
53
+ model,
54
+ args.data
55
+ );
53
56
  } else if (args.data) {
54
57
  args.data = await encryptionService.encryptFields(
55
58
  model,
package/database/index.js CHANGED
@@ -42,8 +42,7 @@ module.exports = {
42
42
  },
43
43
  get OrganizationUser() {
44
44
  if (!_OrganizationUser) {
45
- _OrganizationUser =
46
- require('./models/OrganizationUser').OrganizationUser;
45
+ _OrganizationUser = require('./models/OrganizationUser').OrganizationUser;
47
46
  }
48
47
  return _OrganizationUser;
49
48
  },
@@ -55,8 +54,7 @@ module.exports = {
55
54
  },
56
55
  get WebsocketConnection() {
57
56
  if (!_WebsocketConnection) {
58
- _WebsocketConnection =
59
- require('./models/WebsocketConnection').WebsocketConnection;
57
+ _WebsocketConnection = require('./models/WebsocketConnection').WebsocketConnection;
60
58
  }
61
59
  return _WebsocketConnection;
62
60
  },