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

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 +87 -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 +36 -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,316 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const { ModuleRepositoryInterface } = require('./module-repository-interface');
3
+
4
+ /**
5
+ * Prisma-based Module Repository
6
+ * Handles Entity model operations for external service entities
7
+ *
8
+ * Works identically for both MongoDB and PostgreSQL:
9
+ * - MongoDB: String IDs with @db.ObjectId
10
+ * - PostgreSQL: Integer IDs with auto-increment
11
+ * - Both use same query patterns (no many-to-many differences)
12
+ *
13
+ * Migration from Mongoose:
14
+ * - Constructor injection of Prisma client
15
+ * - populate('credential') → include: { credential: true }
16
+ * - Mongoose discriminator (__t) → moduleName field (module type: salesforce, hubspot, etc.)
17
+ * - _id → id conversion automatic in Prisma
18
+ */
19
+ class ModuleRepository extends ModuleRepositoryInterface {
20
+ constructor(prismaClient = prisma) {
21
+ super();
22
+ this.prisma = prismaClient; // Allow injection for testing
23
+ }
24
+
25
+ /**
26
+ * Find entity by ID with credential
27
+ * Replaces: Entity.findById(entityId).populate('credential')
28
+ *
29
+ * @param {string} entityId - Entity ID
30
+ * @returns {Promise<Object>} Entity object
31
+ * @throws {Error} If entity not found
32
+ */
33
+ async findEntityById(entityId) {
34
+ const entity = await this.prisma.entity.findUnique({
35
+ where: { id: entityId },
36
+ include: { credential: true },
37
+ });
38
+
39
+ if (!entity) {
40
+ throw new Error(`Entity ${entityId} not found`);
41
+ }
42
+
43
+ return {
44
+ id: entity.id,
45
+ accountId: entity.accountId,
46
+ credential: entity.credential,
47
+ userId: entity.userId,
48
+ name: entity.name,
49
+ externalId: entity.externalId,
50
+ moduleName: entity.moduleName,
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Find all entities for a user
56
+ * Replaces: Entity.find({ user: userId }).populate('credential')
57
+ *
58
+ * @param {string} userId - User ID
59
+ * @returns {Promise<Array>} Array of entity objects
60
+ */
61
+ async findEntitiesByUserId(userId) {
62
+ const entities = await this.prisma.entity.findMany({
63
+ where: { userId },
64
+ include: { credential: true },
65
+ });
66
+
67
+ return entities.map((e) => ({
68
+ id: e.id,
69
+ accountId: e.accountId,
70
+ credential: e.credential,
71
+ userId: e.userId,
72
+ name: e.name,
73
+ externalId: e.externalId,
74
+ moduleName: e.moduleName,
75
+ }));
76
+ }
77
+
78
+ /**
79
+ * Find entities by array of IDs
80
+ * Replaces: Entity.find({ _id: { $in: entitiesIds } }).populate('credential')
81
+ *
82
+ * @param {Array<string>} entitiesIds - Array of entity IDs
83
+ * @returns {Promise<Array>} Array of entity objects
84
+ */
85
+ async findEntitiesByIds(entitiesIds) {
86
+ const entities = await this.prisma.entity.findMany({
87
+ where: { id: { in: entitiesIds } },
88
+ include: { credential: true },
89
+ });
90
+
91
+ return entities.map((e) => ({
92
+ id: e.id,
93
+ accountId: e.accountId,
94
+ credential: e.credential,
95
+ userId: e.userId,
96
+ name: e.name,
97
+ externalId: e.externalId,
98
+ moduleName: e.moduleName,
99
+ }));
100
+ }
101
+
102
+ /**
103
+ * Find entities by user ID and module name
104
+ * Replaces: Entity.find({ user: userId, moduleName: moduleName }).populate('credential')
105
+ *
106
+ * @param {string} userId - User ID
107
+ * @param {string} moduleName - Module name
108
+ * @returns {Promise<Array>} Array of entity objects
109
+ */
110
+ async findEntitiesByUserIdAndModuleName(userId, moduleName) {
111
+ const entities = await this.prisma.entity.findMany({
112
+ where: {
113
+ userId,
114
+ moduleName,
115
+ },
116
+ include: { credential: true },
117
+ });
118
+
119
+ return entities.map((e) => ({
120
+ id: e.id,
121
+ accountId: e.accountId,
122
+ credential: e.credential,
123
+ userId: e.userId,
124
+ name: e.name,
125
+ externalId: e.externalId,
126
+ moduleName: e.moduleName,
127
+ }));
128
+ }
129
+
130
+ /**
131
+ * Remove credential reference from entity
132
+ * Replaces: Entity.updateOne({ _id: entityId }, { $unset: { credential: "" } })
133
+ *
134
+ * @param {string} entityId - Entity ID
135
+ * @returns {Promise<boolean>} Success indicator
136
+ */
137
+ async unsetCredential(entityId) {
138
+ await this.prisma.entity.update({
139
+ where: { id: entityId },
140
+ data: { credentialId: null },
141
+ });
142
+
143
+ return true;
144
+ }
145
+
146
+ /**
147
+ * Find entity by filter criteria
148
+ * Replaces: Entity.findOne(filter).populate('credential')
149
+ *
150
+ * @param {Object} filter - Filter criteria
151
+ * @returns {Promise<Object|null>} Entity object or null
152
+ */
153
+ async findEntity(filter) {
154
+ const where = this._convertFilterToWhere(filter);
155
+ const entity = await this.prisma.entity.findFirst({
156
+ where,
157
+ include: { credential: true },
158
+ });
159
+
160
+ if (!entity) {
161
+ return null;
162
+ }
163
+
164
+ return {
165
+ id: entity.id,
166
+ accountId: entity.accountId,
167
+ credential: entity.credential,
168
+ userId: entity.userId,
169
+ name: entity.name,
170
+ externalId: entity.externalId,
171
+ moduleName: entity.moduleName,
172
+ };
173
+ }
174
+
175
+ /**
176
+ * Create a new entity
177
+ * Replaces: Entity.create(entityData)
178
+ *
179
+ * @param {Object} entityData - Entity data
180
+ * @returns {Promise<Object>} Created entity object
181
+ */
182
+ async createEntity(entityData) {
183
+ // Convert Mongoose-style fields to Prisma
184
+ const data = {
185
+ userId: entityData.user || entityData.userId,
186
+ credentialId: entityData.credential || entityData.credentialId,
187
+ name: entityData.name,
188
+ moduleName: entityData.moduleName,
189
+ externalId: entityData.externalId,
190
+ accountId: entityData.accountId,
191
+ };
192
+
193
+ const entity = await this.prisma.entity.create({
194
+ data,
195
+ include: { credential: true },
196
+ });
197
+
198
+ return {
199
+ id: entity.id,
200
+ accountId: entity.accountId,
201
+ credential: entity.credential,
202
+ userId: entity.userId,
203
+ name: entity.name,
204
+ externalId: entity.externalId,
205
+ moduleName: entity.moduleName,
206
+ };
207
+ }
208
+
209
+ /**
210
+ * Update an entity by ID
211
+ * Replaces: Entity.findByIdAndUpdate(entityId, updates, { new: true })
212
+ *
213
+ * @param {string} entityId - Entity ID to update
214
+ * @param {Object} updates - Fields to update
215
+ * @returns {Promise<Object|null>} Updated entity object or null if not found
216
+ */
217
+ async updateEntity(entityId, updates) {
218
+ // Convert Mongoose-style fields to Prisma
219
+ const data = {};
220
+ if (updates.user !== undefined) data.userId = updates.user;
221
+ if (updates.userId !== undefined) data.userId = updates.userId;
222
+ if (updates.credential !== undefined)
223
+ data.credentialId = updates.credential;
224
+ if (updates.credentialId !== undefined)
225
+ data.credentialId = updates.credentialId;
226
+ if (updates.name !== undefined) data.name = updates.name;
227
+ if (updates.moduleName !== undefined)
228
+ data.moduleName = updates.moduleName;
229
+ if (updates.externalId !== undefined)
230
+ data.externalId = updates.externalId;
231
+ if (updates.accountId !== undefined) data.accountId = updates.accountId;
232
+
233
+ try {
234
+ const entity = await this.prisma.entity.update({
235
+ where: { id: entityId },
236
+ data,
237
+ include: { credential: true },
238
+ });
239
+
240
+ return {
241
+ id: entity.id,
242
+ accountId: entity.accountId,
243
+ credential: entity.credential,
244
+ userId: entity.userId,
245
+ name: entity.name,
246
+ externalId: entity.externalId,
247
+ moduleName: entity.moduleName,
248
+ };
249
+ } catch (error) {
250
+ if (error.code === 'P2025') {
251
+ // Record not found
252
+ return null;
253
+ }
254
+ throw error;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Delete an entity by ID
260
+ * Replaces: Entity.deleteOne({ _id: entityId })
261
+ *
262
+ * @param {string} entityId - Entity ID to delete
263
+ * @returns {Promise<boolean>} True if deleted successfully
264
+ */
265
+ async deleteEntity(entityId) {
266
+ try {
267
+ await this.prisma.entity.delete({
268
+ where: { id: entityId },
269
+ });
270
+ return true;
271
+ } catch (error) {
272
+ if (error.code === 'P2025') {
273
+ // Record not found
274
+ return false;
275
+ }
276
+ throw error;
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Convert Mongoose-style filter to Prisma where clause
282
+ * @private
283
+ * @param {Object} filter - Mongoose filter
284
+ * @returns {Object} Prisma where clause
285
+ */
286
+ _convertFilterToWhere(filter) {
287
+ const where = {};
288
+
289
+ // Handle _id field (Mongoose uses _id, Prisma uses id)
290
+ if (filter._id) {
291
+ where.id = filter._id;
292
+ }
293
+
294
+ // Handle user field (Mongoose uses user, Prisma uses userId)
295
+ if (filter.user) {
296
+ where.userId = filter.user;
297
+ }
298
+
299
+ // Handle credential field (Mongoose uses credential, Prisma uses credentialId)
300
+ if (filter.credential) {
301
+ where.credentialId = filter.credential;
302
+ }
303
+
304
+ // Copy other fields directly
305
+ if (filter.id) where.id = filter.id;
306
+ if (filter.userId) where.userId = filter.userId;
307
+ if (filter.credentialId) where.credentialId = filter.credentialId;
308
+ if (filter.name) where.name = filter.name;
309
+ if (filter.moduleName) where.moduleName = filter.moduleName;
310
+ if (filter.externalId) where.externalId = filter.externalId;
311
+
312
+ return where;
313
+ }
314
+ }
315
+
316
+ module.exports = { ModuleRepository };
@@ -108,6 +108,7 @@ class Requester extends Delegate {
108
108
  }
109
109
 
110
110
  async _post(options, stringify = true) {
111
+ console.log('options', options);
111
112
  const fetchOptions = {
112
113
  method: 'POST',
113
114
  credentials: 'include',
@@ -1,5 +1,5 @@
1
- const { get } = require('../../assertions');
2
- const { OAuth2Requester } = require('../../module-plugin');
1
+ const { get } = require('../../../assertions');
2
+ const { OAuth2Requester } = require('../..');
3
3
 
4
4
  class Api extends OAuth2Requester {
5
5
  constructor(params) {
@@ -23,7 +23,12 @@ class Api extends OAuth2Requester {
23
23
  return this.authorizationUri;
24
24
  }
25
25
 
26
-
26
+ getAuthorizationRequirements() {
27
+ return {
28
+ url: this.getAuthUri(),
29
+ type: 'oauth2',
30
+ };
31
+ }
27
32
  }
28
33
 
29
34
  module.exports = { Api };
@@ -1,19 +1,23 @@
1
1
  require('dotenv').config();
2
- const {Api} = require('./api');
3
- const {get} = require('../../assertions');
4
- const config = {name: 'anapi'}
2
+ const { Api } = require('./api');
3
+ const { get } = require('../../../assertions');
4
+ const config = { name: 'anapi' }
5
5
 
6
6
  const Definition = {
7
7
  API: Api,
8
- getName: function() {return config.name},
8
+ getAuthorizationRequirements: () => ({
9
+ url: 'http://localhost:3000/redirect/anapi',
10
+ type: 'oauth2',
11
+ }),
12
+ getName: function () { return config.name },
9
13
  moduleName: config.name,
10
14
  modelName: 'AnApi',
11
15
  requiredAuthMethods: {
12
- getToken: async function(api, params){
16
+ getToken: async function (api, params) {
13
17
  const code = get(params.data, 'code');
14
18
  return api.getTokenFromCode(code);
15
19
  },
16
- getEntityDetails: async function(api, callbackParams, tokenResponse, userId) {
20
+ getEntityDetails: async function (api, callbackParams, tokenResponse, userId) {
17
21
  const userDetails = await api.getUserDetails();
18
22
  return {
19
23
  identifiers: { externalId: userDetails.portalId, user: userId },
@@ -26,14 +30,14 @@ const Definition = {
26
30
  ],
27
31
  entity: [],
28
32
  },
29
- getCredentialDetails: async function(api, userId) {
33
+ getCredentialDetails: async function (api, userId) {
30
34
  const userDetails = await api.getUserDetails();
31
35
  return {
32
36
  identifiers: { externalId: userDetails.portalId, user: userId },
33
37
  details: {}
34
38
  };
35
39
  },
36
- testAuthRequest: async function(api){
40
+ testAuthRequest: async function (api) {
37
41
  return api.getUserDetails()
38
42
  },
39
43
  },
@@ -0,0 +1,16 @@
1
+ class TestModuleFactory {
2
+ constructor() { }
3
+
4
+ async getModuleInstance(entityId, userId) {
5
+ // return minimal stub module with getName and api property
6
+ return {
7
+ getName() { return 'stubModule'; },
8
+ api: {},
9
+ entityId,
10
+ userId,
11
+ testAuth: async () => true,
12
+ };
13
+ }
14
+ }
15
+
16
+ module.exports = { TestModuleFactory };
@@ -0,0 +1,39 @@
1
+ class TestModuleRepository {
2
+ constructor() {
3
+ this.entities = new Map();
4
+ }
5
+
6
+ addEntity(entity) {
7
+ this.entities.set(entity.id, entity);
8
+ }
9
+
10
+ async findEntityById(id) {
11
+ return this.entities.get(id);
12
+ }
13
+
14
+ async findEntitiesByIds(ids) {
15
+ return ids.map((id) => this.entities.get(id));
16
+ }
17
+
18
+ async findEntity(filter) {
19
+ if (!filter || typeof filter !== 'object') {
20
+ return null;
21
+ }
22
+
23
+ if (filter.id && this.entities.has(filter.id)) {
24
+ return this.entities.get(filter.id);
25
+ }
26
+
27
+ if (filter.externalId) {
28
+ for (const entity of this.entities.values()) {
29
+ if (entity.externalId === filter.externalId) {
30
+ return entity;
31
+ }
32
+ }
33
+ }
34
+
35
+ return null;
36
+ }
37
+ }
38
+
39
+ module.exports = { TestModuleRepository };
@@ -0,0 +1,32 @@
1
+ const { Module } = require('../module');
2
+ const { mapModuleClassToModuleDTO } = require('../utils/map-module-dto');
3
+
4
+ class GetEntitiesForUser {
5
+ constructor({ moduleRepository, moduleDefinitions }) {
6
+ this.moduleRepository = moduleRepository;
7
+
8
+ this.definitionMap = new Map();
9
+ for (const definition of moduleDefinitions) {
10
+ this.definitionMap.set(definition.moduleName, definition);
11
+ }
12
+ }
13
+
14
+ async execute(userId) {
15
+ const entities = await this.moduleRepository.findEntitiesByUserId(
16
+ userId
17
+ );
18
+
19
+ return entities.map((entity) => {
20
+ const definition = this.definitionMap.get(entity.moduleName);
21
+
22
+ const moduleInstance = new Module({
23
+ userId,
24
+ definition: definition,
25
+ entity: entity,
26
+ });
27
+ return mapModuleClassToModuleDTO(moduleInstance);
28
+ });
29
+ }
30
+ }
31
+
32
+ module.exports = { GetEntitiesForUser };
@@ -0,0 +1,59 @@
1
+ const { Module } = require('../module');
2
+
3
+ class GetEntityOptionsById {
4
+ /**
5
+ * @param {Object} params
6
+ * @param {import('../repositories/module-repository-interface').ModuleRepositoryInterface} params.moduleRepository
7
+ * @param {} params.moduleDefinitions
8
+ */
9
+ constructor({ moduleRepository, moduleDefinitions }) {
10
+ this.moduleRepository = moduleRepository;
11
+ this.moduleDefinitions = moduleDefinitions;
12
+ }
13
+
14
+ /**
15
+ * Retrieve a Module instance for a given user and entity/module type.
16
+ * @param {string} userId
17
+ * @param {string} entityId
18
+ */
19
+ async execute(entityId, userId) {
20
+ const entity = await this.moduleRepository.findEntityById(
21
+ entityId,
22
+ userId
23
+ );
24
+
25
+ if (!entity) {
26
+ throw new Error(`Entity ${entityId} not found`);
27
+ }
28
+
29
+ if (entity.userId !== userId) {
30
+ throw new Error(
31
+ `Entity ${entityId} does not belong to user ${userId}`
32
+ );
33
+ }
34
+
35
+ const entityType = entity.moduleName;
36
+ const moduleDefinition = this.moduleDefinitions.find((def) => {
37
+ const modelName =
38
+ Module.getEntityModelFromDefinition(def).modelName;
39
+ return entityType === modelName;
40
+ });
41
+
42
+ if (!moduleDefinition) {
43
+ throw new Error(
44
+ `Module definition not found for entity type: ${entityType}`
45
+ );
46
+ }
47
+
48
+ const module = new Module({
49
+ userId,
50
+ entity,
51
+ definition: moduleDefinition,
52
+ });
53
+
54
+ const entityOptions = await module.getEntityOptions();
55
+ return entityOptions;
56
+ }
57
+ }
58
+
59
+ module.exports = { GetEntityOptionsById };
@@ -0,0 +1,34 @@
1
+ const { Module } = require('../module');
2
+
3
+ class GetEntityOptionsByType {
4
+ /**
5
+ * @param {Object} params
6
+ * @param {} params.moduleDefinitions
7
+ */
8
+ constructor({ moduleDefinitions }) {
9
+ this.moduleDefinitions = moduleDefinitions;
10
+ }
11
+
12
+ /**
13
+ * Retrieve a Module instance for a given user and entity/module type.
14
+ * @param {string} userId
15
+ * @param {string} type – human-readable module/entity type (e.g. "Hubspot")
16
+ */
17
+ async execute(userId, type) {
18
+ const moduleDefinition = this.moduleDefinitions.find(
19
+ (def) => def.getName() === type
20
+ );
21
+ if (!moduleDefinition) {
22
+ throw new Error(`Module definition not found for type: ${type}`);
23
+ }
24
+ const moduleInstance = new Module({
25
+ userId,
26
+ definition: moduleDefinition,
27
+ });
28
+
29
+ const entityOptions = await moduleInstance.getEntityOptions();
30
+ return entityOptions;
31
+ }
32
+ }
33
+
34
+ module.exports = { GetEntityOptionsByType };
@@ -0,0 +1,31 @@
1
+ const { Module } = require('../module');
2
+
3
+ class GetModuleInstanceFromType {
4
+ /**
5
+ * @param {Object} params
6
+ * @param {} params.moduleDefinitions
7
+ */
8
+ constructor({ moduleDefinitions }) {
9
+ this.moduleDefinitions = moduleDefinitions;
10
+ }
11
+
12
+ /**
13
+ * Retrieve a Module instance for a given user and entity/module type.
14
+ * @param {string} userId
15
+ * @param {string} type – human-readable module/entity type (e.g. "Hubspot")
16
+ */
17
+ async execute(userId, type) {
18
+ const moduleDefinition = this.moduleDefinitions.find(
19
+ (def) => def.getName() === type
20
+ );
21
+ if (!moduleDefinition) {
22
+ throw new Error(`Module definition not found for type: ${type}`);
23
+ }
24
+ return new Module({
25
+ userId,
26
+ definition: moduleDefinition,
27
+ });
28
+ }
29
+ }
30
+
31
+ module.exports = { GetModuleInstanceFromType };
@@ -0,0 +1,55 @@
1
+ const { Module } = require('../module');
2
+
3
+ class GetModule {
4
+ constructor({ moduleRepository, moduleDefinitions }) {
5
+ this.moduleRepository = moduleRepository;
6
+ this.moduleDefinitions = moduleDefinitions;
7
+ }
8
+
9
+ async execute(entityId, userId) {
10
+ const entity = await this.moduleRepository.findEntityById(
11
+ entityId,
12
+ userId
13
+ );
14
+
15
+ if (!entity) {
16
+ throw new Error(`Entity ${entityId} not found`);
17
+ }
18
+
19
+ if (entity.userId !== userId) {
20
+ throw new Error(
21
+ `Entity ${entityId} does not belong to user ${userId}`
22
+ );
23
+ }
24
+
25
+ const entityType = entity.moduleName;
26
+ const moduleDefinition = this.moduleDefinitions.find((def) => {
27
+ const modelName = Module.getEntityModelFromDefinition(def).modelName;
28
+ return entityType === modelName;
29
+ });
30
+
31
+ if (!moduleDefinition) {
32
+ throw new Error(
33
+ `Module definition not found for entity type: ${entityType}`
34
+ );
35
+ }
36
+
37
+ const module = new Module({
38
+ userId,
39
+ entity,
40
+ definition: moduleDefinition,
41
+ });
42
+
43
+ // todo: this properties should be methods in the Module class
44
+ return {
45
+ id: module.entity.id,
46
+ name: module.entity.name,
47
+ moduleName: module.entity.moduleName,
48
+ credential: module.credential,
49
+ externalId: module.entity.externalId,
50
+ userId: module.entity.user.toString(),
51
+ }
52
+ }
53
+ }
54
+
55
+ module.exports = { GetModule };