@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
package/core/Worker.js CHANGED
@@ -1,8 +1,4 @@
1
- const {
2
- SQSClient,
3
- GetQueueUrlCommand,
4
- SendMessageCommand,
5
- } = require('@aws-sdk/client-sqs');
1
+ const { SQSClient, GetQueueUrlCommand, SendMessageCommand } = require('@aws-sdk/client-sqs');
6
2
  const _ = require('lodash');
7
3
  const { RequiredPropertyError } = require('../errors');
8
4
  const { get } = require('../assertions');
@@ -3,7 +3,6 @@ const {
3
3
  toObjectId,
4
4
  fromObjectId,
5
5
  findOne,
6
- findMany,
7
6
  insertOne,
8
7
  updateOne,
9
8
  deleteOne,
@@ -107,10 +106,7 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
107
106
  const updateDocument = {
108
107
  userId: existing.userId,
109
108
  externalId: existing.externalId,
110
- authIsValid:
111
- authIsValid !== undefined
112
- ? authIsValid
113
- : existing.authIsValid,
109
+ authIsValid: authIsValid !== undefined ? authIsValid : existing.authIsValid,
114
110
  data: mergedData,
115
111
  updatedAt: now,
116
112
  };
@@ -176,50 +172,8 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
176
172
  return this._mapCredential(decryptedCredential);
177
173
  }
178
174
 
179
- /**
180
- * Find credential(s) by filter criteria
181
- *
182
- * When filter includes only userId, returns an array of all credentials for that user
183
- * When filter includes credentialId or externalId, returns a single credential or null
184
- *
185
- * @param {Object} filter
186
- * @param {string} [filter.userId] - User ID
187
- * @param {string} [filter.externalId] - External ID
188
- * @param {string} [filter.credentialId] - Credential ID
189
- * @returns {Promise<Array|Object|null>} Credential array, single credential, or null
190
- */
191
175
  async findCredential(filter) {
192
176
  const query = this._buildFilter(filter);
193
-
194
- // If filtering by userId only, return all credentials for that user
195
- const hasOnlyUserId =
196
- filter.userId &&
197
- !filter.credentialId &&
198
- !filter.externalId &&
199
- !filter.id;
200
-
201
- if (hasOnlyUserId) {
202
- const credentials = await findMany(
203
- this.prisma,
204
- 'Credential',
205
- query
206
- );
207
-
208
- const decryptedCredentials = await Promise.all(
209
- credentials.map(async (credential) => {
210
- const decrypted =
211
- await this.encryptionService.decryptFields(
212
- 'Credential',
213
- credential
214
- );
215
- return this._mapCredentialWithMetadata(decrypted);
216
- })
217
- );
218
-
219
- return decryptedCredentials;
220
- }
221
-
222
- // Otherwise, find single credential
223
177
  const credential = await findOne(this.prisma, 'Credential', query);
224
178
  if (!credential) return null;
225
179
 
@@ -345,30 +299,6 @@ class CredentialRepositoryDocumentDB extends CredentialRepositoryInterface {
345
299
  ...data,
346
300
  };
347
301
  }
348
-
349
- /**
350
- * Map credential document with metadata (for list views)
351
- * Includes timestamps and additional fields needed by API
352
- * @private
353
- */
354
- _mapCredentialWithMetadata(doc) {
355
- const data = doc?.data || {};
356
- const id = fromObjectId(doc?._id);
357
- const userId = doc?.userId;
358
- return {
359
- id,
360
- type: doc?.type,
361
- userId,
362
- externalId: doc?.externalId ?? null,
363
- authIsValid: doc?.authIsValid ?? null,
364
- entityCount: doc?.entityCount,
365
- createdAt: doc?.createdAt,
366
- updatedAt: doc?.updatedAt,
367
- access_token: data.access_token,
368
- refresh_token: data.refresh_token,
369
- ...data,
370
- };
371
- }
372
302
  }
373
303
 
374
304
  module.exports = { CredentialRepositoryDocumentDB };
@@ -68,16 +68,10 @@ class CredentialRepositoryInterface {
68
68
  }
69
69
 
70
70
  /**
71
- * Find credential(s) by filter criteria
72
- *
73
- * When filter includes only userId, returns an array of all credentials for that user
74
- * When filter includes credentialId or externalId, returns a single credential or null
71
+ * Find a credential by filter criteria
75
72
  *
76
73
  * @param {Object} filter - Filter criteria
77
- * @param {string} [filter.userId] - User ID
78
- * @param {string} [filter.externalId] - External ID
79
- * @param {string} [filter.credentialId] - Credential ID
80
- * @returns {Promise<Array|Object|null>} Credential array, single credential, or null
74
+ * @returns {Promise<Object|null>} Credential object or null if not found
81
75
  * @abstract
82
76
  */
83
77
  async findCredential(filter) {
@@ -121,10 +121,7 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
121
121
  data: {
122
122
  userId: existing.userId,
123
123
  externalId: existing.externalId,
124
- authIsValid:
125
- authIsValid !== undefined
126
- ? authIsValid
127
- : existing.authIsValid,
124
+ authIsValid: authIsValid !== undefined ? authIsValid : existing.authIsValid,
128
125
  data: mergedData,
129
126
  },
130
127
  });
@@ -157,52 +154,18 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
157
154
  }
158
155
 
159
156
  /**
160
- * Find credential(s) by filter criteria
161
- * Replaces: Credential.find(query) or Credential.findOne(query)
162
- *
163
- * When filter includes only userId, returns an array of all credentials for that user
164
- * When filter includes credentialId or externalId, returns a single credential or null
157
+ * Find a credential by filter criteria
158
+ * Replaces: Credential.findOne(query)
165
159
  *
166
160
  * @param {Object} filter
167
161
  * @param {string} [filter.userId] - User ID
168
162
  * @param {string} [filter.externalId] - External ID
169
163
  * @param {string} [filter.credentialId] - Credential ID
170
- * @returns {Promise<Array|Object|null>} Credential array, single credential, or null
164
+ * @returns {Promise<Object|null>} Credential object or null if not found
171
165
  */
172
166
  async findCredential(filter) {
173
167
  const where = this._convertFilterToWhere(filter);
174
168
 
175
- // If filtering by userId only, return all credentials for that user
176
- const hasOnlyUserId =
177
- filter.userId &&
178
- !filter.credentialId &&
179
- !filter.externalId &&
180
- !filter.id;
181
-
182
- if (hasOnlyUserId) {
183
- const credentials = await this.prisma.credential.findMany({
184
- where,
185
- });
186
-
187
- return credentials.map((credential) => {
188
- const data = credential.data || {};
189
- return {
190
- id: credential.id,
191
- type: credential.type,
192
- userId: credential.userId,
193
- externalId: credential.externalId,
194
- authIsValid: credential.authIsValid,
195
- entityCount: credential.entityCount,
196
- createdAt: credential.createdAt,
197
- updatedAt: credential.updatedAt,
198
- access_token: data.access_token,
199
- refresh_token: data.refresh_token,
200
- ...data,
201
- };
202
- });
203
- }
204
-
205
- // Otherwise, find single credential
206
169
  const credential = await this.prisma.credential.findFirst({
207
170
  where,
208
171
  });
@@ -215,13 +178,9 @@ class CredentialRepositoryMongo extends CredentialRepositoryInterface {
215
178
 
216
179
  return {
217
180
  id: credential.id,
218
- type: credential.type,
219
181
  userId: credential.userId,
220
182
  externalId: credential.externalId,
221
183
  authIsValid: credential.authIsValid,
222
- entityCount: credential.entityCount,
223
- createdAt: credential.createdAt,
224
- updatedAt: credential.updatedAt,
225
184
  access_token: data.access_token,
226
185
  refresh_token: data.refresh_token,
227
186
  ...data,
@@ -139,10 +139,7 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
139
139
  data: {
140
140
  userId: this._convertId(existing.userId),
141
141
  externalId: existing.externalId,
142
- authIsValid:
143
- authIsValid !== undefined
144
- ? authIsValid
145
- : existing.authIsValid,
142
+ authIsValid: authIsValid !== undefined ? authIsValid : existing.authIsValid,
146
143
  data: mergedData,
147
144
  },
148
145
  });
@@ -176,51 +173,17 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
176
173
  }
177
174
 
178
175
  /**
179
- * Find credential(s) by filter criteria
180
- *
181
- * When filter includes only userId, returns an array of all credentials for that user
182
- * When filter includes credentialId or externalId, returns a single credential or null
176
+ * Find a credential by filter criteria
183
177
  *
184
178
  * @param {Object} filter
185
179
  * @param {string} [filter.userId] - User ID (string from application layer)
186
180
  * @param {string} [filter.externalId] - External ID
187
181
  * @param {string} [filter.credentialId] - Credential ID (string from application layer)
188
- * @returns {Promise<Array|Object|null>} Credential array, single credential with string IDs, or null
182
+ * @returns {Promise<Object|null>} Credential object with string IDs or null if not found
189
183
  */
190
184
  async findCredential(filter) {
191
185
  const where = this._convertFilterToWhere(filter);
192
186
 
193
- // If filtering by userId only, return all credentials for that user
194
- const hasOnlyUserId =
195
- filter.userId &&
196
- !filter.credentialId &&
197
- !filter.externalId &&
198
- !filter.id;
199
-
200
- if (hasOnlyUserId) {
201
- const credentials = await this.prisma.credential.findMany({
202
- where,
203
- });
204
-
205
- return credentials.map((credential) => {
206
- const data = credential.data || {};
207
- return {
208
- id: credential.id.toString(),
209
- type: credential.type,
210
- userId: credential.userId?.toString(),
211
- externalId: credential.externalId,
212
- authIsValid: credential.authIsValid,
213
- entityCount: credential.entityCount,
214
- createdAt: credential.createdAt,
215
- updatedAt: credential.updatedAt,
216
- access_token: data.access_token,
217
- refresh_token: data.refresh_token,
218
- ...data,
219
- };
220
- });
221
- }
222
-
223
- // Otherwise, find single credential
224
187
  const credential = await this.prisma.credential.findFirst({
225
188
  where,
226
189
  });
@@ -233,13 +196,9 @@ class CredentialRepositoryPostgres extends CredentialRepositoryInterface {
233
196
 
234
197
  return {
235
198
  id: credential.id.toString(),
236
- type: credential.type,
237
199
  userId: credential.userId?.toString(),
238
200
  externalId: credential.externalId,
239
201
  authIsValid: credential.authIsValid,
240
- entityCount: credential.entityCount,
241
- createdAt: credential.createdAt,
242
- updatedAt: credential.updatedAt,
243
202
  access_token: data.access_token,
244
203
  refresh_token: data.refresh_token,
245
204
  ...data,
@@ -114,7 +114,7 @@ class CredentialRepository extends CredentialRepositoryInterface {
114
114
  userId,
115
115
  externalId,
116
116
  authIsValid,
117
-
117
+
118
118
  ...oauthData
119
119
  } = details;
120
120
 
@@ -156,7 +156,7 @@ class CredentialRepository extends CredentialRepositoryInterface {
156
156
  userId: userId || user,
157
157
  externalId,
158
158
  authIsValid: authIsValid,
159
-
159
+
160
160
  data: oauthData,
161
161
  },
162
162
  });
@@ -229,7 +229,7 @@ class CredentialRepository extends CredentialRepositoryInterface {
229
229
  userId,
230
230
  externalId,
231
231
  authIsValid,
232
-
232
+
233
233
  ...oauthData
234
234
  } = updates;
235
235
 
@@ -243,9 +243,7 @@ class CredentialRepository extends CredentialRepositoryInterface {
243
243
  externalId:
244
244
  externalId !== undefined ? externalId : existing.externalId,
245
245
  authIsValid:
246
- authIsValid !== undefined
247
- ? authIsValid
248
- : existing.authIsValid,
246
+ authIsValid !== undefined ? authIsValid : existing.authIsValid,
249
247
  data: mergedData,
250
248
  },
251
249
  });
@@ -1,38 +1,20 @@
1
- const Boom = require('@hapi/boom');
2
-
3
- /**
4
- * Get Credential For User Use Case
5
- * Retrieves a single credential after verifying ownership
6
- *
7
- * Business Logic:
8
- * - Verify credential exists
9
- * - Verify credential belongs to user (authorization)
10
- * - Return credential
11
- */
12
1
  class GetCredentialForUser {
13
2
  constructor({ credentialRepository }) {
14
3
  this.credentialRepository = credentialRepository;
15
4
  }
16
5
 
17
- /**
18
- * Execute the use case
19
- * @param {string} credentialId - Credential ID
20
- * @param {string} userId - User ID (for ownership verification)
21
- * @returns {Promise<Object>} Credential object
22
- */
23
6
  async execute(credentialId, userId) {
24
7
  const credential = await this.credentialRepository.findCredentialById(
25
8
  credentialId
26
9
  );
27
10
 
28
11
  if (!credential) {
29
- throw Boom.notFound(`Credential ${credentialId} not found`);
12
+ throw new Error(`Credential with id ${credentialId} not found`);
30
13
  }
31
14
 
32
- // Verify ownership - compare as strings to handle both MongoDB and PostgreSQL
33
15
  if (credential.userId.toString() !== userId.toString()) {
34
- throw Boom.forbidden(
35
- 'You do not have permission to access this credential'
16
+ throw new Error(
17
+ `Credential ${credentialId} does not belong to user ${userId}`
36
18
  );
37
19
  }
38
20
 
@@ -8,11 +8,8 @@ class UpdateAuthenticationStatus {
8
8
  * @param {boolean} authIsValid
9
9
  */
10
10
  async execute(credentialId, authIsValid) {
11
- await this.credentialRepository.updateAuthenticationStatus(
12
- credentialId,
13
- authIsValid
14
- );
11
+ await this.credentialRepository.updateAuthenticationStatus(credentialId, authIsValid);
15
12
  }
16
13
  }
17
14
 
18
- module.exports = { UpdateAuthenticationStatus };
15
+ module.exports = { UpdateAuthenticationStatus };
@@ -15,9 +15,9 @@ MongoDB does not allow creating collections (namespaces) inside multi-document t
15
15
 
16
16
  ### Technical Details
17
17
 
18
- - **MongoDB Constraint**: Collections must exist before being used in multi-document transactions
19
- - **Prisma Behavior**: Prisma may implicitly use transactions for certain operations
20
- - **Impact**: Health checks fail on fresh databases or when collections haven't been created yet
18
+ - **MongoDB Constraint**: Collections must exist before being used in multi-document transactions
19
+ - **Prisma Behavior**: Prisma may implicitly use transactions for certain operations
20
+ - **Impact**: Health checks fail on fresh databases or when collections haven't been created yet
21
21
 
22
22
  ## Solution
23
23
 
@@ -37,34 +37,30 @@ This follows the **"fail fast"** principle and ensures consistent state across a
37
37
  ### Changes Made
38
38
 
39
39
  1. **Created MongoDB Schema Initialization** (`packages/core/database/utils/mongodb-schema-init.js`)
40
-
41
- - `initializeMongoDBSchema()` - Ensures all Prisma collections exist at startup
42
- - `getPrismaCollections()` - Returns list of all Prisma collection names
43
- - `PRISMA_COLLECTIONS` - Constant array of all 13 Prisma collections
44
- - Only runs for MongoDB (skips PostgreSQL)
45
- - Fails fast if database not connected
40
+ - `initializeMongoDBSchema()` - Ensures all Prisma collections exist at startup
41
+ - `getPrismaCollections()` - Returns list of all Prisma collection names
42
+ - `PRISMA_COLLECTIONS` - Constant array of all 13 Prisma collections
43
+ - Only runs for MongoDB (skips PostgreSQL)
44
+ - Fails fast if database not connected
46
45
 
47
46
  2. **Created MongoDB Collection Utilities** (`packages/core/database/utils/mongodb-collection-utils.js`)
48
-
49
- - `ensureCollectionExists(collectionName)` - Ensures a single collection exists
50
- - `ensureCollectionsExist(collectionNames)` - Batch creates multiple collections
51
- - `collectionExists(collectionName)` - Checks if a collection exists
52
- - Handles race conditions gracefully (NamespaceExists errors)
47
+ - `ensureCollectionExists(collectionName)` - Ensures a single collection exists
48
+ - `ensureCollectionsExist(collectionNames)` - Batch creates multiple collections
49
+ - `collectionExists(collectionName)` - Checks if a collection exists
50
+ - Handles race conditions gracefully (NamespaceExists errors)
53
51
 
54
52
  3. **Integrated into Database Connection** (`packages/core/database/prisma.js`)
55
-
56
- - Modified `connectPrisma()` to call `initializeMongoDBSchema()` after connection
57
- - Ensures all collections exist before application handles requests
53
+ - Modified `connectPrisma()` to call `initializeMongoDBSchema()` after connection
54
+ - Ensures all collections exist before application handles requests
58
55
 
59
56
  4. **Updated Health Check Repository** (`packages/core/database/repositories/health-check-repository-mongodb.js`)
60
-
61
- - Removed per-operation collection existence checks
62
- - Added documentation noting schema is initialized at startup
57
+ - Removed per-operation collection existence checks
58
+ - Added documentation noting schema is initialized at startup
63
59
 
64
60
  5. **Added Comprehensive Tests**
65
- - `mongodb-schema-init.test.js` - Tests schema initialization system
66
- - `mongodb-collection-utils.test.js` - Tests collection utility functions
67
- - Tests error handling, race conditions, and edge cases
61
+ - `mongodb-schema-init.test.js` - Tests schema initialization system
62
+ - `mongodb-collection-utils.test.js` - Tests collection utility functions
63
+ - Tests error handling, race conditions, and edge cases
68
64
 
69
65
  ### Implementation Flow
70
66
 
@@ -97,26 +93,23 @@ await prisma.credential.create({ data: {...} }); // Works without namespace erro
97
93
  ## Benefits
98
94
 
99
95
  ### Immediate Benefits
100
-
101
- - ✅ Fixes encryption health check failures on fresh databases
102
- - ✅ Prevents transaction namespace errors across **all** Prisma operations
103
- - ✅ No per-operation overhead - collections created once at startup
104
- - ✅ Fail fast - database issues discovered immediately at startup
105
- - ✅ Idempotent - safe to run multiple times and across multiple instances
96
+ - ✅ Fixes encryption health check failures on fresh databases
97
+ - ✅ Prevents transaction namespace errors across **all** Prisma operations
98
+ - ✅ No per-operation overhead - collections created once at startup
99
+ - ✅ Fail fast - database issues discovered immediately at startup
100
+ - ✅ Idempotent - safe to run multiple times and across multiple instances
106
101
 
107
102
  ### Architectural Benefits
108
-
109
- - ✅ **Clean separation of concerns**: Schema initialization is infrastructure concern, handled at startup
110
- - ✅ **Follows DDD/Hexagonal Architecture**: Infrastructure layer handles database setup, repositories focus on business operations
111
- - ✅ **Consistent across all environments**: Dev, test, staging, production all follow same pattern
112
- - ✅ **No repository-level checks needed**: All repositories benefit automatically
113
- - ✅ **Well-tested and documented**: Comprehensive test coverage and documentation
103
+ - ✅ **Clean separation of concerns**: Schema initialization is infrastructure concern, handled at startup
104
+ - ✅ **Follows DDD/Hexagonal Architecture**: Infrastructure layer handles database setup, repositories focus on business operations
105
+ - ✅ **Consistent across all environments**: Dev, test, staging, production all follow same pattern
106
+ - ✅ **No repository-level checks needed**: All repositories benefit automatically
107
+ - ✅ **Well-tested and documented**: Comprehensive test coverage and documentation
114
108
 
115
109
  ### Operational Benefits
116
-
117
- - ✅ **Predictable startup**: Clear logging of schema initialization
118
- - ✅ **Zero runtime overhead**: Collections created once, not on every operation
119
- - ✅ **Production-ready**: Handles race conditions, errors, and edge cases gracefully
110
+ - ✅ **Predictable startup**: Clear logging of schema initialization
111
+ - ✅ **Zero runtime overhead**: Collections created once, not on every operation
112
+ - ✅ **Production-ready**: Handles race conditions, errors, and edge cases gracefully
120
113
 
121
114
  ## Design Decisions
122
115
 
@@ -125,19 +118,16 @@ await prisma.credential.create({ data: {...} }); // Works without namespace erro
125
118
  We considered two approaches:
126
119
 
127
120
  **❌ Per-Operation Checks (Initial approach)**
128
-
129
121
  ```javascript
130
122
  async createCredential(data) {
131
123
  await ensureCollectionExists('Credential'); // Check every time
132
124
  return await prisma.credential.create({ data });
133
125
  }
134
126
  ```
135
-
136
- - Pros: Guarantees collection exists before each operation
137
- - Cons: Runtime overhead, repeated checks, scattered logic
127
+ - Pros: Guarantees collection exists before each operation
128
+ - Cons: Runtime overhead, repeated checks, scattered logic
138
129
 
139
130
  **✅ Startup Initialization (Final approach)**
140
-
141
131
  ```javascript
142
132
  // Once at startup
143
133
  await connectPrisma(); // Initializes all collections
@@ -147,9 +137,8 @@ async createCredential(data) {
147
137
  return await prisma.credential.create({ data }); // No checks needed
148
138
  }
149
139
  ```
150
-
151
- - Pros: Zero runtime overhead, centralized logic, fail fast, consistent
152
- - Cons: Requires database connection at startup (already required)
140
+ - Pros: Zero runtime overhead, centralized logic, fail fast, consistent
141
+ - Cons: Requires database connection at startup (already required)
153
142
 
154
143
  ### Benefits of Startup Approach
155
144
 
@@ -170,7 +159,6 @@ MongoDB schema initialization complete - 13 collections verified (45ms)
170
159
  ```
171
160
 
172
161
  On subsequent startups (collections already exist):
173
-
174
162
  ```
175
163
  Initializing MongoDB schema - ensuring all collections exist...
176
164
  MongoDB schema initialization complete - 13 collections verified (12ms)
@@ -178,41 +166,33 @@ MongoDB schema initialization complete - 13 collections verified (12ms)
178
166
 
179
167
  ## References
180
168
 
181
- - [Prisma Issue #8305](https://github.com/prisma/prisma/issues/8305) - MongoDB "Cannot create namespace" error
182
- - [Mongoose Issue #6699](https://github.com/Automattic/mongoose/issues/6699) - Similar issue in Mongoose
183
- - [MongoDB Transactions Documentation](https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-operations) - Operations allowed in transactions
184
- - [Prisma MongoDB Guide](https://www.prisma.io/docs/guides/database/mongodb) - Using Prisma with MongoDB
169
+ - [Prisma Issue #8305](https://github.com/prisma/prisma/issues/8305) - MongoDB "Cannot create namespace" error
170
+ - [Mongoose Issue #6699](https://github.com/Automattic/mongoose/issues/6699) - Similar issue in Mongoose
171
+ - [MongoDB Transactions Documentation](https://www.mongodb.com/docs/manual/core/transactions/#transactions-and-operations) - Operations allowed in transactions
172
+ - [Prisma MongoDB Guide](https://www.prisma.io/docs/guides/database/mongodb) - Using Prisma with MongoDB
185
173
 
186
174
  ## Future Considerations
187
175
 
188
176
  ### Automatic Schema Sync
189
-
190
177
  Consider enhancing the system to:
191
-
192
- - Parse Prisma schema file dynamically to extract collection names
193
- - Auto-detect schema changes and create new collections
194
- - Provide CLI command for manual schema initialization
178
+ - Parse Prisma schema file dynamically to extract collection names
179
+ - Auto-detect schema changes and create new collections
180
+ - Provide CLI command for manual schema initialization
195
181
 
196
182
  ### Migration Support
197
-
198
183
  For production deployments with existing data:
199
-
200
- - Document migration procedures for new collections
201
- - Consider pre-migration scripts for blue-green deployments
202
- - Add health check for schema initialization status
184
+ - Document migration procedures for new collections
185
+ - Consider pre-migration scripts for blue-green deployments
186
+ - Add health check for schema initialization status
203
187
 
204
188
  ### Multi-Database Support
205
-
206
189
  The system already handles:
207
-
208
- - ✅ MongoDB - Full schema initialization
209
- - ✅ PostgreSQL - Skips initialization (uses Prisma migrations)
210
- - Consider adding explicit migration support for DocumentDB-specific features
190
+ - ✅ MongoDB - Full schema initialization
191
+ - ✅ PostgreSQL - Skips initialization (uses Prisma migrations)
192
+ - Consider adding explicit migration support for DocumentDB-specific features
211
193
 
212
194
  ### Index Creation
213
-
214
195
  Future enhancement could also create indexes at startup:
215
-
216
- - Parse Prisma schema for `@@index` directives
217
- - Create indexes if they don't exist
218
- - Provide index health checks
196
+ - Parse Prisma schema for `@@index` directives
197
+ - Create indexes if they don't exist
198
+ - Provide index health checks
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Lambda Invoker Adapter
3
3
  * Infrastructure layer - handles AWS Lambda function invocations
4
- *
4
+ *
5
5
  * Part of Hexagonal Architecture:
6
6
  * - Infrastructure Layer adapter for AWS SDK
7
7
  * - Used by Domain Layer use cases
@@ -25,7 +25,7 @@ class LambdaInvocationError extends Error {
25
25
 
26
26
  /**
27
27
  * Adapter for invoking AWS Lambda functions
28
- *
28
+ *
29
29
  * Infrastructure layer - handles AWS SDK communication
30
30
  * Converts AWS SDK responses to domain-friendly formats
31
31
  */
@@ -39,7 +39,7 @@ class LambdaInvoker {
39
39
 
40
40
  /**
41
41
  * Invoke Lambda function synchronously
42
- *
42
+ *
43
43
  * @param {string} functionName - Lambda function name or ARN
44
44
  * @param {Object} payload - Event payload to send to Lambda
45
45
  * @returns {Promise<Object>} Parsed response body
@@ -74,8 +74,7 @@ class LambdaInvoker {
74
74
  }
75
75
 
76
76
  // Lambda returned error status
77
- const errorMessage =
78
- result.body?.error || 'Lambda invocation failed';
77
+ const errorMessage = result.body?.error || 'Lambda invocation failed';
79
78
  throw new LambdaInvocationError(
80
79
  `Lambda ${functionName} returned error: ${errorMessage}`,
81
80
  functionName,
@@ -88,11 +87,11 @@ class LambdaInvoker {
88
87
  }
89
88
 
90
89
  // Wrap AWS SDK errors
91
- throw new Error(
92
- `Failed to invoke Lambda ${functionName}: ${error.message}`
93
- );
90
+ throw new Error(`Failed to invoke Lambda ${functionName}: ${error.message}`);
94
91
  }
95
92
  }
96
93
  }
97
94
 
98
95
  module.exports = { LambdaInvoker, LambdaInvocationError };
96
+
97
+