@friggframework/core 2.0.0-next.5 → 2.0.0-next.51

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 (267) hide show
  1. package/CLAUDE.md +693 -0
  2. package/README.md +959 -50
  3. package/application/commands/README.md +421 -0
  4. package/application/commands/credential-commands.js +224 -0
  5. package/application/commands/entity-commands.js +315 -0
  6. package/application/commands/integration-commands.js +179 -0
  7. package/application/commands/user-commands.js +213 -0
  8. package/application/index.js +69 -0
  9. package/core/CLAUDE.md +690 -0
  10. package/core/Worker.js +8 -21
  11. package/core/create-handler.js +2 -7
  12. package/credential/repositories/credential-repository-factory.js +47 -0
  13. package/credential/repositories/credential-repository-interface.js +98 -0
  14. package/credential/repositories/credential-repository-mongo.js +307 -0
  15. package/credential/repositories/credential-repository-postgres.js +313 -0
  16. package/credential/repositories/credential-repository.js +302 -0
  17. package/credential/use-cases/get-credential-for-user.js +21 -0
  18. package/credential/use-cases/update-authentication-status.js +15 -0
  19. package/database/MONGODB_TRANSACTION_FIX.md +198 -0
  20. package/database/adapters/lambda-invoker.js +97 -0
  21. package/database/config.js +154 -0
  22. package/database/encryption/README.md +684 -0
  23. package/database/encryption/encryption-schema-registry.js +141 -0
  24. package/database/encryption/field-encryption-service.js +226 -0
  25. package/database/encryption/logger.js +79 -0
  26. package/database/encryption/prisma-encryption-extension.js +222 -0
  27. package/database/index.js +25 -12
  28. package/database/models/WebsocketConnection.js +16 -10
  29. package/database/models/readme.md +1 -0
  30. package/database/prisma.js +222 -0
  31. package/database/repositories/health-check-repository-factory.js +43 -0
  32. package/database/repositories/health-check-repository-interface.js +87 -0
  33. package/database/repositories/health-check-repository-mongodb.js +91 -0
  34. package/database/repositories/health-check-repository-postgres.js +82 -0
  35. package/database/repositories/health-check-repository.js +108 -0
  36. package/database/repositories/migration-status-repository-s3.js +137 -0
  37. package/database/use-cases/check-database-health-use-case.js +29 -0
  38. package/database/use-cases/check-database-state-use-case.js +81 -0
  39. package/database/use-cases/check-encryption-health-use-case.js +83 -0
  40. package/database/use-cases/get-database-state-via-worker-use-case.js +61 -0
  41. package/database/use-cases/get-migration-status-use-case.js +93 -0
  42. package/database/use-cases/run-database-migration-use-case.js +137 -0
  43. package/database/use-cases/test-encryption-use-case.js +253 -0
  44. package/database/use-cases/trigger-database-migration-use-case.js +157 -0
  45. package/database/utils/mongodb-collection-utils.js +91 -0
  46. package/database/utils/mongodb-schema-init.js +106 -0
  47. package/database/utils/prisma-runner.js +400 -0
  48. package/database/utils/prisma-schema-parser.js +182 -0
  49. package/docs/PROCESS_MANAGEMENT_QUEUE_SPEC.md +517 -0
  50. package/encrypt/Cryptor.js +34 -168
  51. package/encrypt/index.js +1 -2
  52. package/encrypt/test-encrypt.js +0 -2
  53. package/generated/prisma-mongodb/client.d.ts +1 -0
  54. package/generated/prisma-mongodb/client.js +4 -0
  55. package/generated/prisma-mongodb/default.d.ts +1 -0
  56. package/generated/prisma-mongodb/default.js +4 -0
  57. package/generated/prisma-mongodb/edge.d.ts +1 -0
  58. package/generated/prisma-mongodb/edge.js +334 -0
  59. package/generated/prisma-mongodb/index-browser.js +316 -0
  60. package/generated/prisma-mongodb/index.d.ts +22898 -0
  61. package/generated/prisma-mongodb/index.js +359 -0
  62. package/generated/prisma-mongodb/package.json +183 -0
  63. package/generated/prisma-mongodb/query-engine-debian-openssl-3.0.x +0 -0
  64. package/generated/prisma-mongodb/query-engine-rhel-openssl-3.0.x +0 -0
  65. package/generated/prisma-mongodb/runtime/binary.d.ts +1 -0
  66. package/generated/prisma-mongodb/runtime/binary.js +289 -0
  67. package/generated/prisma-mongodb/runtime/edge-esm.js +34 -0
  68. package/generated/prisma-mongodb/runtime/edge.js +34 -0
  69. package/generated/prisma-mongodb/runtime/index-browser.d.ts +370 -0
  70. package/generated/prisma-mongodb/runtime/index-browser.js +16 -0
  71. package/generated/prisma-mongodb/runtime/library.d.ts +3982 -0
  72. package/generated/prisma-mongodb/runtime/react-native.js +83 -0
  73. package/generated/prisma-mongodb/runtime/wasm-compiler-edge.js +84 -0
  74. package/generated/prisma-mongodb/runtime/wasm-engine-edge.js +36 -0
  75. package/generated/prisma-mongodb/schema.prisma +362 -0
  76. package/generated/prisma-mongodb/wasm-edge-light-loader.mjs +4 -0
  77. package/generated/prisma-mongodb/wasm-worker-loader.mjs +4 -0
  78. package/generated/prisma-mongodb/wasm.d.ts +1 -0
  79. package/generated/prisma-mongodb/wasm.js +341 -0
  80. package/generated/prisma-postgresql/client.d.ts +1 -0
  81. package/generated/prisma-postgresql/client.js +4 -0
  82. package/generated/prisma-postgresql/default.d.ts +1 -0
  83. package/generated/prisma-postgresql/default.js +4 -0
  84. package/generated/prisma-postgresql/edge.d.ts +1 -0
  85. package/generated/prisma-postgresql/edge.js +356 -0
  86. package/generated/prisma-postgresql/index-browser.js +338 -0
  87. package/generated/prisma-postgresql/index.d.ts +25072 -0
  88. package/generated/prisma-postgresql/index.js +381 -0
  89. package/generated/prisma-postgresql/package.json +183 -0
  90. package/generated/prisma-postgresql/query-engine-debian-openssl-3.0.x +0 -0
  91. package/generated/prisma-postgresql/query-engine-rhel-openssl-3.0.x +0 -0
  92. package/generated/prisma-postgresql/query_engine_bg.js +2 -0
  93. package/generated/prisma-postgresql/query_engine_bg.wasm +0 -0
  94. package/generated/prisma-postgresql/runtime/binary.d.ts +1 -0
  95. package/generated/prisma-postgresql/runtime/binary.js +289 -0
  96. package/generated/prisma-postgresql/runtime/edge-esm.js +34 -0
  97. package/generated/prisma-postgresql/runtime/edge.js +34 -0
  98. package/generated/prisma-postgresql/runtime/index-browser.d.ts +370 -0
  99. package/generated/prisma-postgresql/runtime/index-browser.js +16 -0
  100. package/generated/prisma-postgresql/runtime/library.d.ts +3982 -0
  101. package/generated/prisma-postgresql/runtime/react-native.js +83 -0
  102. package/generated/prisma-postgresql/runtime/wasm-compiler-edge.js +84 -0
  103. package/generated/prisma-postgresql/runtime/wasm-engine-edge.js +36 -0
  104. package/generated/prisma-postgresql/schema.prisma +345 -0
  105. package/generated/prisma-postgresql/wasm-edge-light-loader.mjs +4 -0
  106. package/generated/prisma-postgresql/wasm-worker-loader.mjs +4 -0
  107. package/generated/prisma-postgresql/wasm.d.ts +1 -0
  108. package/generated/prisma-postgresql/wasm.js +363 -0
  109. package/handlers/WEBHOOKS.md +653 -0
  110. package/handlers/app-definition-loader.js +38 -0
  111. package/handlers/app-handler-helpers.js +56 -0
  112. package/handlers/backend-utils.js +180 -0
  113. package/handlers/database-migration-handler.js +227 -0
  114. package/handlers/integration-event-dispatcher.js +54 -0
  115. package/handlers/routers/HEALTHCHECK.md +342 -0
  116. package/handlers/routers/auth.js +15 -0
  117. package/handlers/routers/db-migration.handler.js +29 -0
  118. package/handlers/routers/db-migration.js +256 -0
  119. package/handlers/routers/health.js +519 -0
  120. package/handlers/routers/integration-defined-routers.js +45 -0
  121. package/handlers/routers/integration-webhook-routers.js +67 -0
  122. package/handlers/routers/user.js +63 -0
  123. package/handlers/routers/websocket.js +57 -0
  124. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  125. package/handlers/use-cases/check-integrations-health-use-case.js +44 -0
  126. package/handlers/workers/db-migration.js +352 -0
  127. package/handlers/workers/integration-defined-workers.js +27 -0
  128. package/index.js +77 -22
  129. package/integrations/WEBHOOK-QUICKSTART.md +151 -0
  130. package/integrations/index.js +12 -10
  131. package/integrations/integration-base.js +296 -54
  132. package/integrations/integration-router.js +381 -182
  133. package/integrations/options.js +1 -1
  134. package/integrations/repositories/integration-mapping-repository-factory.js +50 -0
  135. package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
  136. package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
  137. package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
  138. package/integrations/repositories/integration-mapping-repository.js +156 -0
  139. package/integrations/repositories/integration-repository-factory.js +44 -0
  140. package/integrations/repositories/integration-repository-interface.js +127 -0
  141. package/integrations/repositories/integration-repository-mongo.js +303 -0
  142. package/integrations/repositories/integration-repository-postgres.js +352 -0
  143. package/integrations/repositories/process-repository-factory.js +46 -0
  144. package/integrations/repositories/process-repository-interface.js +90 -0
  145. package/integrations/repositories/process-repository-mongo.js +190 -0
  146. package/integrations/repositories/process-repository-postgres.js +217 -0
  147. package/integrations/tests/doubles/dummy-integration-class.js +83 -0
  148. package/integrations/tests/doubles/test-integration-repository.js +99 -0
  149. package/integrations/use-cases/create-integration.js +83 -0
  150. package/integrations/use-cases/create-process.js +128 -0
  151. package/integrations/use-cases/delete-integration-for-user.js +101 -0
  152. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
  153. package/integrations/use-cases/get-integration-for-user.js +78 -0
  154. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  155. package/integrations/use-cases/get-integration-instance.js +83 -0
  156. package/integrations/use-cases/get-integrations-for-user.js +88 -0
  157. package/integrations/use-cases/get-possible-integrations.js +27 -0
  158. package/integrations/use-cases/get-process.js +87 -0
  159. package/integrations/use-cases/index.js +19 -0
  160. package/integrations/use-cases/load-integration-context.js +71 -0
  161. package/integrations/use-cases/update-integration-messages.js +44 -0
  162. package/integrations/use-cases/update-integration-status.js +32 -0
  163. package/integrations/use-cases/update-integration.js +93 -0
  164. package/integrations/use-cases/update-process-metrics.js +201 -0
  165. package/integrations/use-cases/update-process-state.js +119 -0
  166. package/integrations/utils/map-integration-dto.js +37 -0
  167. package/jest-global-setup-noop.js +3 -0
  168. package/jest-global-teardown-noop.js +3 -0
  169. package/logs/logger.js +0 -4
  170. package/{module-plugin → modules}/entity.js +1 -1
  171. package/{module-plugin → modules}/index.js +0 -8
  172. package/modules/module-factory.js +56 -0
  173. package/modules/module.js +221 -0
  174. package/modules/repositories/module-repository-factory.js +33 -0
  175. package/modules/repositories/module-repository-interface.js +129 -0
  176. package/modules/repositories/module-repository-mongo.js +377 -0
  177. package/modules/repositories/module-repository-postgres.js +426 -0
  178. package/modules/repositories/module-repository.js +316 -0
  179. package/{module-plugin → modules}/requester/requester.js +1 -0
  180. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  181. package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
  182. package/modules/tests/doubles/test-module-factory.js +16 -0
  183. package/modules/tests/doubles/test-module-repository.js +39 -0
  184. package/modules/use-cases/get-entities-for-user.js +32 -0
  185. package/modules/use-cases/get-entity-options-by-id.js +59 -0
  186. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  187. package/modules/use-cases/get-module-instance-from-type.js +31 -0
  188. package/modules/use-cases/get-module.js +55 -0
  189. package/modules/use-cases/process-authorization-callback.js +122 -0
  190. package/modules/use-cases/refresh-entity-options.js +59 -0
  191. package/modules/use-cases/test-module-auth.js +55 -0
  192. package/modules/utils/map-module-dto.js +18 -0
  193. package/package.json +82 -50
  194. package/prisma-mongodb/schema.prisma +362 -0
  195. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  196. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  197. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  198. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  199. package/prisma-postgresql/schema.prisma +345 -0
  200. package/queues/queuer-util.js +28 -15
  201. package/syncs/manager.js +468 -443
  202. package/syncs/repositories/sync-repository-factory.js +38 -0
  203. package/syncs/repositories/sync-repository-interface.js +109 -0
  204. package/syncs/repositories/sync-repository-mongo.js +239 -0
  205. package/syncs/repositories/sync-repository-postgres.js +319 -0
  206. package/syncs/sync.js +0 -1
  207. package/token/repositories/token-repository-factory.js +33 -0
  208. package/token/repositories/token-repository-interface.js +131 -0
  209. package/token/repositories/token-repository-mongo.js +212 -0
  210. package/token/repositories/token-repository-postgres.js +257 -0
  211. package/token/repositories/token-repository.js +219 -0
  212. package/types/core/index.d.ts +2 -2
  213. package/types/integrations/index.d.ts +2 -6
  214. package/types/module-plugin/index.d.ts +5 -59
  215. package/types/syncs/index.d.ts +0 -2
  216. package/user/repositories/user-repository-factory.js +46 -0
  217. package/user/repositories/user-repository-interface.js +198 -0
  218. package/user/repositories/user-repository-mongo.js +291 -0
  219. package/user/repositories/user-repository-postgres.js +350 -0
  220. package/user/tests/doubles/test-user-repository.js +72 -0
  221. package/user/use-cases/authenticate-user.js +127 -0
  222. package/user/use-cases/authenticate-with-shared-secret.js +48 -0
  223. package/user/use-cases/create-individual-user.js +61 -0
  224. package/user/use-cases/create-organization-user.js +47 -0
  225. package/user/use-cases/create-token-for-user-id.js +30 -0
  226. package/user/use-cases/get-user-from-adopter-jwt.js +149 -0
  227. package/user/use-cases/get-user-from-bearer-token.js +77 -0
  228. package/user/use-cases/get-user-from-x-frigg-headers.js +106 -0
  229. package/user/use-cases/login-user.js +122 -0
  230. package/user/user.js +93 -0
  231. package/utils/backend-path.js +38 -0
  232. package/utils/index.js +6 -0
  233. package/websocket/repositories/websocket-connection-repository-factory.js +37 -0
  234. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  235. package/websocket/repositories/websocket-connection-repository-mongo.js +156 -0
  236. package/websocket/repositories/websocket-connection-repository-postgres.js +196 -0
  237. package/websocket/repositories/websocket-connection-repository.js +161 -0
  238. package/database/models/State.js +0 -9
  239. package/database/models/Token.js +0 -70
  240. package/database/mongo.js +0 -45
  241. package/encrypt/Cryptor.test.js +0 -32
  242. package/encrypt/encrypt.js +0 -132
  243. package/encrypt/encrypt.test.js +0 -1069
  244. package/errors/base-error.test.js +0 -32
  245. package/errors/fetch-error.test.js +0 -79
  246. package/errors/halt-error.test.js +0 -11
  247. package/errors/validation-errors.test.js +0 -120
  248. package/integrations/create-frigg-backend.js +0 -31
  249. package/integrations/integration-factory.js +0 -251
  250. package/integrations/integration-mapping.js +0 -43
  251. package/integrations/integration-model.js +0 -46
  252. package/integrations/integration-user.js +0 -144
  253. package/integrations/test/integration-base.test.js +0 -144
  254. package/lambda/TimeoutCatcher.test.js +0 -68
  255. package/logs/logger.test.js +0 -76
  256. package/module-plugin/auther.js +0 -393
  257. package/module-plugin/credential.js +0 -22
  258. package/module-plugin/entity-manager.js +0 -70
  259. package/module-plugin/manager.js +0 -169
  260. package/module-plugin/module-factory.js +0 -61
  261. package/module-plugin/requester/requester.test.js +0 -28
  262. package/module-plugin/test/auther.test.js +0 -97
  263. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  264. /package/{module-plugin → modules}/requester/api-key.js +0 -0
  265. /package/{module-plugin → modules}/requester/basic.js +0 -0
  266. /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
  267. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -0,0 +1,377 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const { ModuleRepositoryInterface } = require('./module-repository-interface');
3
+
4
+ /**
5
+ * MongoDB Module Repository Adapter
6
+ * Handles Entity model operations for external service entities with MongoDB
7
+ *
8
+ * MongoDB-specific characteristics:
9
+ * - Uses String IDs (ObjectId)
10
+ * - No ID conversion needed (IDs are already strings)
11
+ *
12
+ * Prisma Migration Notes:
13
+ * - Mongoose discriminator (__t) → moduleName field (module type: salesforce, hubspot, etc.)
14
+ */
15
+ class ModuleRepositoryMongo extends ModuleRepositoryInterface {
16
+ constructor() {
17
+ super();
18
+ this.prisma = prisma;
19
+ }
20
+
21
+ /**
22
+ * Convert any value to string (handles null/undefined)
23
+ * @private
24
+ * @param {*} value - Value to convert
25
+ * @returns {string|null|undefined} String value or null/undefined
26
+ */
27
+ _toString(value) {
28
+ if (value === null || value === undefined) return value;
29
+ return String(value);
30
+ }
31
+
32
+ /**
33
+ * Fetch credential by ID separately to ensure encryption extension processes it
34
+ * This fixes the bug where credentials fetched via include bypass decryption
35
+ * @private
36
+ * @param {string|null|undefined} credentialId - Credential ID
37
+ * @returns {Promise<Object|null>} Decrypted credential or null
38
+ */
39
+ async _fetchCredential(credentialId) {
40
+ if (!credentialId) return null;
41
+
42
+ const credential = await this.prisma.credential.findUnique({
43
+ where: { id: credentialId },
44
+ });
45
+
46
+ return credential;
47
+ }
48
+
49
+ /**
50
+ * Fetch multiple credentials in bulk separately to ensure decryption
51
+ * More efficient than fetching one-by-one for arrays of entities
52
+ * @private
53
+ * @param {Array<string>} credentialIds - Array of credential IDs
54
+ * @returns {Promise<Map<string, Object>>} Map of credentialId -> credential object
55
+ */
56
+ async _fetchCredentialsBulk(credentialIds) {
57
+ if (!credentialIds || credentialIds.length === 0) {
58
+ return new Map();
59
+ }
60
+
61
+ const validIds = credentialIds.filter(id => id !== null && id !== undefined);
62
+
63
+ if (validIds.length === 0) {
64
+ return new Map();
65
+ }
66
+
67
+ const credentials = await this.prisma.credential.findMany({
68
+ where: { id: { in: validIds } },
69
+ });
70
+
71
+ const credentialMap = new Map();
72
+ for (const credential of credentials) {
73
+ credentialMap.set(credential.id, credential);
74
+ }
75
+
76
+ return credentialMap;
77
+ }
78
+
79
+ /**
80
+ * Find entity by ID with credential
81
+ * Replaces: Entity.findById(entityId).populate('credential')
82
+ *
83
+ * @param {string} entityId - Entity ID
84
+ * @returns {Promise<Object>} Entity object with string IDs
85
+ * @throws {Error} If entity not found
86
+ */
87
+ async findEntityById(entityId) {
88
+ const entity = await this.prisma.entity.findUnique({
89
+ where: { id: entityId },
90
+ });
91
+
92
+ if (!entity) {
93
+ throw new Error(`Entity ${entityId} not found`);
94
+ }
95
+
96
+ const credential = await this._fetchCredential(entity.credentialId);
97
+
98
+ return {
99
+ id: entity.id,
100
+ accountId: entity.accountId,
101
+ credential,
102
+ userId: entity.userId,
103
+ name: entity.name,
104
+ externalId: entity.externalId,
105
+ moduleName: entity.moduleName,
106
+ };
107
+ }
108
+
109
+ /**
110
+ * Find all entities for a user
111
+ * Replaces: Entity.find({ user: userId }).populate('credential')
112
+ *
113
+ * @param {string} userId - User ID
114
+ * @returns {Promise<Array>} Array of entity objects with string IDs
115
+ */
116
+ async findEntitiesByUserId(userId) {
117
+ const entities = await this.prisma.entity.findMany({
118
+ where: { userId },
119
+ });
120
+
121
+ const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
122
+ const credentialMap = await this._fetchCredentialsBulk(credentialIds);
123
+
124
+ return entities.map((e) => ({
125
+ id: e.id,
126
+ accountId: e.accountId,
127
+ credential: credentialMap.get(e.credentialId) || null,
128
+ userId: e.userId,
129
+ name: e.name,
130
+ externalId: e.externalId,
131
+ moduleName: e.moduleName,
132
+ }));
133
+ }
134
+
135
+ /**
136
+ * Find entities by array of IDs
137
+ * Replaces: Entity.find({ _id: { $in: entitiesIds } }).populate('credential')
138
+ *
139
+ * @param {Array<string>} entitiesIds - Array of entity IDs
140
+ * @returns {Promise<Array>} Array of entity objects with string IDs
141
+ */
142
+ async findEntitiesByIds(entitiesIds) {
143
+ const entities = await this.prisma.entity.findMany({
144
+ where: { id: { in: entitiesIds } },
145
+ });
146
+
147
+ const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
148
+ const credentialMap = await this._fetchCredentialsBulk(credentialIds);
149
+
150
+ return entities.map((e) => ({
151
+ id: e.id,
152
+ accountId: e.accountId,
153
+ credential: credentialMap.get(e.credentialId) || null,
154
+ userId: e.userId,
155
+ name: e.name,
156
+ externalId: e.externalId,
157
+ moduleName: e.moduleName,
158
+ }));
159
+ }
160
+
161
+ /**
162
+ * Find entities by user ID and module name
163
+ * Replaces: Entity.find({ user: userId, moduleName: moduleName }).populate('credential')
164
+ *
165
+ * @param {string} userId - User ID
166
+ * @param {string} moduleName - Module name
167
+ * @returns {Promise<Array>} Array of entity objects with string IDs
168
+ */
169
+ async findEntitiesByUserIdAndModuleName(userId, moduleName) {
170
+ const entities = await this.prisma.entity.findMany({
171
+ where: {
172
+ userId,
173
+ moduleName,
174
+ },
175
+ });
176
+
177
+ const credentialIds = entities.map(e => e.credentialId).filter(Boolean);
178
+ const credentialMap = await this._fetchCredentialsBulk(credentialIds);
179
+
180
+ return entities.map((e) => ({
181
+ id: e.id,
182
+ accountId: e.accountId,
183
+ credential: credentialMap.get(e.credentialId) || null,
184
+ userId: e.userId,
185
+ name: e.name,
186
+ externalId: e.externalId,
187
+ moduleName: e.moduleName,
188
+ }));
189
+ }
190
+
191
+ /**
192
+ * Remove credential reference from entity
193
+ * Replaces: Entity.updateOne({ _id: entityId }, { $unset: { credential: "" } })
194
+ *
195
+ * @param {string} entityId - Entity ID
196
+ * @returns {Promise<boolean>} Success indicator
197
+ */
198
+ async unsetCredential(entityId) {
199
+ await this.prisma.entity.update({
200
+ where: { id: entityId },
201
+ data: { credentialId: null },
202
+ });
203
+
204
+ return true;
205
+ }
206
+
207
+ /**
208
+ * Find entity by filter criteria
209
+ * Replaces: Entity.findOne(filter).populate('credential')
210
+ *
211
+ * @param {Object} filter - Filter criteria
212
+ * @returns {Promise<Object|null>} Entity object with string IDs or null
213
+ */
214
+ async findEntity(filter) {
215
+ const where = this._convertFilterToWhere(filter);
216
+ const entity = await this.prisma.entity.findFirst({
217
+ where,
218
+ });
219
+
220
+ if (!entity) {
221
+ return null;
222
+ }
223
+
224
+ const credential = await this._fetchCredential(entity.credentialId);
225
+
226
+ return {
227
+ id: entity.id,
228
+ accountId: entity.accountId,
229
+ credential,
230
+ userId: entity.userId,
231
+ name: entity.name,
232
+ externalId: entity.externalId,
233
+ moduleName: entity.moduleName,
234
+ };
235
+ }
236
+
237
+ /**
238
+ * Create a new entity
239
+ * Replaces: Entity.create(entityData)
240
+ *
241
+ * @param {Object} entityData - Entity data
242
+ * @returns {Promise<Object>} Created entity object with string IDs
243
+ */
244
+ async createEntity(entityData) {
245
+ const data = {
246
+ userId: entityData.user || entityData.userId,
247
+ credentialId: entityData.credential || entityData.credentialId,
248
+ name: entityData.name,
249
+ moduleName: entityData.moduleName,
250
+ externalId: entityData.externalId,
251
+ accountId: entityData.accountId,
252
+ };
253
+
254
+ const entity = await this.prisma.entity.create({
255
+ data,
256
+ });
257
+
258
+ const credential = await this._fetchCredential(entity.credentialId);
259
+
260
+ return {
261
+ id: entity.id,
262
+ accountId: entity.accountId,
263
+ credential,
264
+ userId: entity.userId,
265
+ name: entity.name,
266
+ externalId: entity.externalId,
267
+ moduleName: entity.moduleName,
268
+ };
269
+ }
270
+
271
+ /**
272
+ * Update an entity by ID
273
+ * Replaces: Entity.findByIdAndUpdate(entityId, updates, { new: true })
274
+ *
275
+ * @param {string} entityId - Entity ID to update
276
+ * @param {Object} updates - Fields to update
277
+ * @returns {Promise<Object|null>} Updated entity object with string IDs or null if not found
278
+ */
279
+ async updateEntity(entityId, updates) {
280
+ const data = {};
281
+ if (updates.user !== undefined) data.userId = updates.user;
282
+ if (updates.userId !== undefined) data.userId = updates.userId;
283
+ if (updates.credential !== undefined)
284
+ data.credentialId = updates.credential;
285
+ if (updates.credentialId !== undefined)
286
+ data.credentialId = updates.credentialId;
287
+ if (updates.name !== undefined) data.name = updates.name;
288
+ if (updates.moduleName !== undefined)
289
+ data.moduleName = updates.moduleName;
290
+ if (updates.externalId !== undefined)
291
+ data.externalId = updates.externalId;
292
+ if (updates.accountId !== undefined) data.accountId = updates.accountId;
293
+
294
+ try {
295
+ const entity = await this.prisma.entity.update({
296
+ where: { id: entityId },
297
+ data,
298
+ });
299
+
300
+ const credential = await this._fetchCredential(entity.credentialId);
301
+
302
+ return {
303
+ id: entity.id,
304
+ accountId: entity.accountId,
305
+ credential,
306
+ userId: entity.userId,
307
+ name: entity.name,
308
+ externalId: entity.externalId,
309
+ moduleName: entity.moduleName,
310
+ };
311
+ } catch (error) {
312
+ if (error.code === 'P2025') {
313
+ return null;
314
+ }
315
+ throw error;
316
+ }
317
+ }
318
+
319
+ /**
320
+ * Delete an entity by ID
321
+ * Replaces: Entity.deleteOne({ _id: entityId })
322
+ *
323
+ * @param {string} entityId - Entity ID to delete
324
+ * @returns {Promise<boolean>} True if deleted successfully
325
+ */
326
+ async deleteEntity(entityId) {
327
+ try {
328
+ await this.prisma.entity.delete({
329
+ where: { id: entityId },
330
+ });
331
+ return true;
332
+ } catch (error) {
333
+ if (error.code === 'P2025') {
334
+ // Record not found
335
+ return false;
336
+ }
337
+ throw error;
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Convert Mongoose-style filter to Prisma where clause
343
+ * @private
344
+ * @param {Object} filter - Mongoose filter
345
+ * @returns {Object} Prisma where clause
346
+ */
347
+ _convertFilterToWhere(filter) {
348
+ const where = {};
349
+
350
+ // Handle _id field (Mongoose uses _id, Prisma uses id)
351
+ if (filter._id) {
352
+ where.id = filter._id;
353
+ }
354
+
355
+ // Handle user field (Mongoose uses user, Prisma uses userId)
356
+ if (filter.user) {
357
+ where.userId = filter.user;
358
+ }
359
+
360
+ // Handle credential field (Mongoose uses credential, Prisma uses credentialId)
361
+ if (filter.credential) {
362
+ where.credentialId = filter.credential;
363
+ }
364
+
365
+ // Copy other fields directly
366
+ if (filter.id) where.id = filter.id;
367
+ if (filter.userId) where.userId = filter.userId;
368
+ if (filter.credentialId) where.credentialId = filter.credentialId;
369
+ if (filter.name) where.name = filter.name;
370
+ if (filter.moduleName) where.moduleName = filter.moduleName;
371
+ if (filter.externalId) where.externalId = this._toString(filter.externalId);
372
+
373
+ return where;
374
+ }
375
+ }
376
+
377
+ module.exports = { ModuleRepositoryMongo };