@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,219 @@
1
+ const { prisma } = require('../../database/prisma');
2
+ const bcrypt = require('bcryptjs');
3
+ const { TokenRepositoryInterface } = require('./token-repository-interface');
4
+
5
+ const BCRYPT_ROUNDS = 10;
6
+
7
+ /**
8
+ * Prisma-based Token Repository
9
+ * Handles persistence of authentication tokens with bcrypt hashing
10
+ *
11
+ * Works identically for both MongoDB and PostgreSQL:
12
+ * - MongoDB: String IDs with @db.ObjectId
13
+ * - PostgreSQL: Integer IDs with auto-increment
14
+ * - Both use same query patterns (no many-to-many differences)
15
+ *
16
+ * Migration from Mongoose:
17
+ * - Constructor injection of Prisma client
18
+ * - Static methods → Instance methods
19
+ * - Token.createTokenWithExpire() → createTokenWithExpire()
20
+ * - Token.validateAndGetTokenFromJSONToken() → validateAndGetToken()
21
+ * - Bcrypt hashing handled in repository layer
22
+ */
23
+ class TokenRepository extends TokenRepositoryInterface {
24
+ constructor(prismaClient = prisma) {
25
+ super();
26
+ this.prisma = prismaClient; // Allow injection for testing
27
+ }
28
+
29
+ /**
30
+ * Create a token with expiration
31
+ * Replaces: Token.createTokenWithExpire(userId, rawToken, minutes)
32
+ *
33
+ * @param {string} userId - The user ID
34
+ * @param {string} rawToken - The raw (unhashed) token string
35
+ * @param {number} minutes - Minutes until expiration
36
+ * @returns {Promise<Object>} The created token record
37
+ */
38
+ async createTokenWithExpire(userId, rawToken, minutes) {
39
+ // Hash the token with bcrypt
40
+ const tokenHash = await bcrypt.hash(rawToken, BCRYPT_ROUNDS);
41
+
42
+ // Calculate expiration time
43
+ const expires = new Date(Date.now() + minutes * 60000);
44
+
45
+ return await this.prisma.token.create({
46
+ data: {
47
+ token: tokenHash,
48
+ expires,
49
+ userId,
50
+ },
51
+ });
52
+ }
53
+
54
+ /**
55
+ * Validate and retrieve token from JSON token object
56
+ * Replaces: Token.validateAndGetTokenFromJSONToken(tokenObj)
57
+ *
58
+ * @param {Object} tokenObj - Object with id and token properties
59
+ * @returns {Promise<Object>} The validated token record
60
+ * @throws {Error} If token is invalid, expired, or doesn't exist
61
+ */
62
+ async validateAndGetToken(tokenObj) {
63
+ const sessionToken = await this.prisma.token.findUnique({
64
+ where: { id: tokenObj.id },
65
+ });
66
+
67
+ if (!sessionToken) {
68
+ throw new Error('Invalid Token: Token does not exist');
69
+ }
70
+
71
+ // Verify token hash matches
72
+ const isValid = await bcrypt.compare(
73
+ tokenObj.token,
74
+ sessionToken.token
75
+ );
76
+ if (!isValid) {
77
+ throw new Error('Invalid Token: Token does not match');
78
+ }
79
+
80
+ // Check if token is expired
81
+ if (
82
+ sessionToken.expires &&
83
+ new Date(sessionToken.expires) < new Date()
84
+ ) {
85
+ throw new Error('Invalid Token: Token is expired');
86
+ }
87
+
88
+ return sessionToken;
89
+ }
90
+
91
+ /**
92
+ * Find a token by ID
93
+ * Replaces: Token.findById(tokenId)
94
+ *
95
+ * @param {string} tokenId - The token ID
96
+ * @returns {Promise<Object|null>} The token record or null
97
+ */
98
+ async findTokenById(tokenId) {
99
+ return await this.prisma.token.findUnique({
100
+ where: { id: tokenId },
101
+ });
102
+ }
103
+
104
+ /**
105
+ * Find tokens by user ID
106
+ * Replaces: Token.find({ user: userId })
107
+ *
108
+ * @param {string} userId - The user ID
109
+ * @returns {Promise<Array>} Array of token records
110
+ */
111
+ async findTokensByUserId(userId) {
112
+ return await this.prisma.token.findMany({
113
+ where: { userId },
114
+ });
115
+ }
116
+
117
+ /**
118
+ * Delete a token by ID
119
+ * Replaces: Token.deleteOne({ _id: tokenId })
120
+ *
121
+ * @param {string} tokenId - The token ID
122
+ * @returns {Promise<Object>} The deletion result
123
+ */
124
+ async deleteToken(tokenId) {
125
+ try {
126
+ await this.prisma.token.delete({
127
+ where: { id: tokenId },
128
+ });
129
+ return { acknowledged: true, deletedCount: 1 };
130
+ } catch (error) {
131
+ if (error.code === 'P2025') {
132
+ // Record not found
133
+ return { acknowledged: true, deletedCount: 0 };
134
+ }
135
+ throw error;
136
+ }
137
+ }
138
+
139
+ /**
140
+ * Delete expired tokens
141
+ * Replaces: Token.deleteMany({ expires: { $lt: new Date() } })
142
+ *
143
+ * @returns {Promise<Object>} The deletion result with count
144
+ */
145
+ async deleteExpiredTokens() {
146
+ const result = await this.prisma.token.deleteMany({
147
+ where: {
148
+ expires: {
149
+ lt: new Date(),
150
+ },
151
+ },
152
+ });
153
+
154
+ return {
155
+ acknowledged: true,
156
+ deletedCount: result.count,
157
+ };
158
+ }
159
+
160
+ /**
161
+ * Delete all tokens for a user
162
+ * Replaces: Token.deleteMany({ user: userId })
163
+ *
164
+ * @param {string} userId - The user ID
165
+ * @returns {Promise<Object>} The deletion result
166
+ */
167
+ async deleteTokensByUserId(userId) {
168
+ const result = await this.prisma.token.deleteMany({
169
+ where: { userId },
170
+ });
171
+
172
+ return {
173
+ acknowledged: true,
174
+ deletedCount: result.count,
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Create JSON token string from token object and raw token
180
+ * Replaces: Token.createJSONToken(token, rawToken)
181
+ *
182
+ * @param {Object} token - The token record
183
+ * @param {string} rawToken - The raw token string
184
+ * @returns {string} JSON string with id and token
185
+ */
186
+ createJSONToken(token, rawToken) {
187
+ return JSON.stringify({
188
+ id: token.id,
189
+ token: rawToken,
190
+ });
191
+ }
192
+
193
+ /**
194
+ * Create base64 encoded buffer token
195
+ * Replaces: Token.createBase64BufferToken(token, rawToken)
196
+ *
197
+ * @param {Object} token - The token record
198
+ * @param {string} rawToken - The raw token string
199
+ * @returns {string} Base64 encoded token
200
+ */
201
+ createBase64BufferToken(token, rawToken) {
202
+ const jsonVal = this.createJSONToken(token, rawToken);
203
+ return Buffer.from(jsonVal).toString('base64');
204
+ }
205
+
206
+ /**
207
+ * Parse JSON token from base64 buffer
208
+ * Replaces: Token.getJSONTokenFromBase64BufferToken(buffer)
209
+ *
210
+ * @param {string} buffer - Base64 encoded token string
211
+ * @returns {Object} Parsed token object with id and token
212
+ */
213
+ getJSONTokenFromBase64BufferToken(buffer) {
214
+ const tokenStr = Buffer.from(buffer.trim(), 'base64').toString('ascii');
215
+ return JSON.parse(tokenStr);
216
+ }
217
+ }
218
+
219
+ module.exports = { TokenRepository };
@@ -1,5 +1,5 @@
1
1
  declare module "@friggframework/core" {
2
- import { SQS } from "aws-sdk";
2
+ import type { SendMessageCommandInput } from "@aws-sdk/client-sqs";
3
3
 
4
4
  export class Delegate implements IFriggDelegate {
5
5
  delegate: any;
@@ -50,5 +50,5 @@ declare module "@friggframework/core" {
50
50
  QueueOwnerAWSAccountId?: string;
51
51
  };
52
52
 
53
- type SendSQSMessageParams = SQS.SendMessageRequest;
53
+ type SendSQSMessageParams = SendMessageCommandInput;
54
54
  }
@@ -1,7 +1,6 @@
1
1
  declare module "@friggframework/integrations" {
2
2
  import { Delegate, IFriggDelegate } from "@friggframework/core";
3
3
  import { Model } from "mongoose";
4
- import { EntityManager } from "@friggframework/module-plugin";
5
4
 
6
5
  export class Integration extends Model {
7
6
  entities: any[];
@@ -19,8 +18,7 @@ declare module "@friggframework/integrations" {
19
18
 
20
19
  export class IntegrationManager
21
20
  extends Delegate
22
- implements IFriggIntegrationManager
23
- {
21
+ implements IFriggIntegrationManager {
24
22
  integration: Integration;
25
23
  primaryInstance: any;
26
24
  targetInstance: any;
@@ -56,7 +54,6 @@ declare module "@friggframework/integrations" {
56
54
  entities: { id: string; user: any },
57
55
  userId: string,
58
56
  config: any,
59
- EntityManager: EntityManager
60
57
  ): Promise<any>;
61
58
 
62
59
  static getFormattedIntegration(
@@ -116,8 +113,7 @@ declare module "@friggframework/integrations" {
116
113
  }
117
114
 
118
115
  export class IntegrationConfigManager
119
- implements IFriggIntegrationConfigManager
120
- {
116
+ implements IFriggIntegrationConfigManager {
121
117
  options: IntegrationOptions[];
122
118
  primary: any;
123
119
 
@@ -4,72 +4,21 @@ declare module "@friggframework/module-plugin" {
4
4
 
5
5
  export class Credential extends Model {
6
6
  userId: string;
7
- auth_is_valid: boolean;
8
- subType: string;
7
+ authIsValid: boolean;
9
8
  externalId: string;
10
9
  }
11
10
 
12
- export class EntityManager implements IFriggEntityManager {
13
- static primaryEntityClass: any;
14
- static entityManagerClasses: any[];
15
- static entityTypes: string[];
16
- static getEntitiesForUser(userId: string): Promise<any[]>;
17
- static checkIsValidType(entityType: string): boolean;
18
- static getEntityManagerClass(entityType?: string): any;
19
-
20
- static getEntityManagerInstanceFromEntityId(
21
- entityId: string,
22
- userId: string
23
- ): Promise<any>;
24
- }
25
-
26
- interface IFriggEntityManager {}
11
+ interface IFriggEntityManager { }
27
12
 
28
13
  export class Entity extends Model {
29
14
  credentialId: string;
30
- subType: string;
31
15
  userId: string;
32
16
  name: string;
33
17
  externalId: string;
34
18
  }
35
19
 
36
20
  export type MappedEntity = Entity & { id: string; type: any };
37
- export class ModuleManager extends Delegate implements IFriggModuleManager {
38
- static Entity: Entity;
39
- static Credential: Credential;
40
-
41
- constructor(params: { userId: string });
42
21
 
43
- static getName(): any;
44
- static getInstance(params: any): Promise<any>;
45
- static getEntitiesForUserId(userId: string): Promise<MappedEntity[]>;
46
-
47
- batchCreateSyncObjects(syncObjects: any, syncManager: any): Promise<any>;
48
- batchUpdateSyncObjects(syncObjects: any, syncManager: any): Promise<any>;
49
- findOrCreateEntity(params: any): Promise<any>;
50
- getAllSyncObjects(SyncClass: any): Promise<any>;
51
- getAuthorizationRequirements(params: any): Promise<any>;
52
- getEntityId(): Promise<string>;
53
- getEntityOptions(): Promise<any>;
54
- markCredentialsInvalid(): Promise<Credential>;
55
- processAuthorizationCallback(params: any): Promise<any>;
56
- testAuth(params: any): Promise<any>;
57
- validateAuthorizationRequirements(): Promise<boolean>;
58
- }
59
-
60
- interface IFriggModuleManager extends IFriggDelegate {
61
- getEntityId(): Promise<string>;
62
- validateAuthorizationRequirements(): Promise<boolean>;
63
- getAuthorizationRequirements(params: any): Promise<any>;
64
- testAuth(params: any): Promise<any>;
65
- processAuthorizationCallback(params: any): Promise<any>;
66
- getEntityOptions(): Promise<any>;
67
- findOrCreateEntity(params: any): Promise<any>;
68
- getAllSyncObjects(SyncClass: any): Promise<any>;
69
- batchCreateSyncObjects(syncObjects: any, syncManager: any): Promise<any>;
70
- batchUpdateSyncObjects(syncObjects: any, syncManager: any): Promise<any>;
71
- markCredentialsInvalid(): Promise<Credential>;
72
- }
73
22
 
74
23
  export class Requester implements IFriggRequester {
75
24
  DLGT_INVALID_AUTH: string;
@@ -138,8 +87,7 @@ declare module "@friggframework/module-plugin" {
138
87
 
139
88
  export class ApiKeyRequester
140
89
  extends Requester
141
- implements IFriggApiKeyRequester
142
- {
90
+ implements IFriggApiKeyRequester {
143
91
  API_KEY_NAME: string;
144
92
  API_KEY_VALUE: any;
145
93
 
@@ -160,8 +108,7 @@ declare module "@friggframework/module-plugin" {
160
108
 
161
109
  export class BasicAuthRequester
162
110
  extends Requester
163
- implements IFriggBasicAuthRequester
164
- {
111
+ implements IFriggBasicAuthRequester {
165
112
  password: string;
166
113
  username: string;
167
114
 
@@ -189,8 +136,7 @@ declare module "@friggframework/module-plugin" {
189
136
 
190
137
  export class OAuth2Requester
191
138
  extends Requester
192
- implements IFriggOAuth2Requester
193
- {
139
+ implements IFriggOAuth2Requester {
194
140
  DLGT_TOKEN_DEAUTHORIZED: string;
195
141
  DLGT_TOKEN_UPDATE: string;
196
142
  accessTokenExpire: any;
@@ -28,7 +28,6 @@ declare module "@friggframework/syncs/manager" {
28
28
  confirmCreate(
29
29
  syncObj: Sync,
30
30
  createdId: string,
31
- moduleManager: any
32
31
  ): Promise<any>;
33
32
  confirmUpdate(syncObj: Sync): Promise<any>;
34
33
  createSyncDBObject(objArr: any[], entities: any[]): Promise<any>;
@@ -50,7 +49,6 @@ declare module "@friggframework/syncs/manager" {
50
49
  confirmCreate(
51
50
  syncObj: Sync,
52
51
  createdId: string,
53
- moduleManager: any
54
52
  ): Promise<any>;
55
53
  confirmUpdate(syncObj: Sync): Promise<any>;
56
54
  }
@@ -0,0 +1,46 @@
1
+ const { UserRepositoryMongo } = require('./user-repository-mongo');
2
+ const { UserRepositoryPostgres } = require('./user-repository-postgres');
3
+ const databaseConfig = require('../../database/config');
4
+
5
+ /**
6
+ * User Repository Factory
7
+ * Creates the appropriate repository adapter based on database type
8
+ *
9
+ * Database-specific implementations:
10
+ * - MongoDB: Uses String IDs (ObjectId), no conversion needed
11
+ * - PostgreSQL: Uses Int IDs, converts String ↔ Int
12
+ *
13
+ * All repository methods return String IDs regardless of database type,
14
+ * ensuring application layer consistency.
15
+ *
16
+ * Usage:
17
+ * ```javascript
18
+ * const repository = createUserRepository();
19
+ * const user = await repository.findUserById(id); // ID is string
20
+ * ```
21
+ *
22
+ * @returns {UserRepositoryInterface} Configured repository adapter
23
+ */
24
+ function createUserRepository() {
25
+ const dbType = databaseConfig.DB_TYPE;
26
+
27
+ switch (dbType) {
28
+ case 'mongodb':
29
+ return new UserRepositoryMongo();
30
+
31
+ case 'postgresql':
32
+ return new UserRepositoryPostgres();
33
+
34
+ default:
35
+ throw new Error(
36
+ `Unsupported DB_TYPE: ${dbType}. Supported values: 'mongodb', 'postgresql'`
37
+ );
38
+ }
39
+ }
40
+
41
+ module.exports = {
42
+ createUserRepository,
43
+ // Export adapters for direct testing
44
+ UserRepositoryMongo,
45
+ UserRepositoryPostgres,
46
+ };
@@ -0,0 +1,198 @@
1
+ /**
2
+ * User Repository Interface
3
+ * Abstract base class defining the contract for user persistence adapters
4
+ *
5
+ * This follows the Port in Hexagonal Architecture:
6
+ * - Domain layer depends on this abstraction
7
+ * - Concrete adapters implement this interface
8
+ * - Use cases receive repositories via dependency injection
9
+ *
10
+ * Note: Currently, User model has identical structure across MongoDB and PostgreSQL,
11
+ * so UserRepository serves both. This interface exists for consistency and
12
+ * future-proofing if database-specific implementations become needed.
13
+ *
14
+ * @abstract
15
+ */
16
+ class UserRepositoryInterface {
17
+ /**
18
+ * Get session token from base64 buffer token
19
+ *
20
+ * @param {string} token - Base64 buffer token
21
+ * @returns {Promise<Object>} Session token object
22
+ * @abstract
23
+ */
24
+ async getSessionToken(token) {
25
+ throw new Error(
26
+ 'Method getSessionToken must be implemented by subclass'
27
+ );
28
+ }
29
+
30
+ /**
31
+ * Find organization user by ID
32
+ *
33
+ * @param {string|number} userId - User ID
34
+ * @returns {Promise<Object|null>} User object or null
35
+ * @abstract
36
+ */
37
+ async findOrganizationUserById(userId) {
38
+ throw new Error(
39
+ 'Method findOrganizationUserById must be implemented by subclass'
40
+ );
41
+ }
42
+
43
+ /**
44
+ * Find individual user by ID
45
+ *
46
+ * @param {string|number} userId - User ID
47
+ * @returns {Promise<Object|null>} User object or null
48
+ * @abstract
49
+ */
50
+ async findIndividualUserById(userId) {
51
+ throw new Error(
52
+ 'Method findIndividualUserById must be implemented by subclass'
53
+ );
54
+ }
55
+
56
+ /**
57
+ * Create token with expiration
58
+ *
59
+ * @param {string|number} userId - User ID
60
+ * @param {string} rawToken - Raw unhashed token
61
+ * @param {number} minutes - Minutes until expiration (default 120)
62
+ * @returns {Promise<string>} Base64 buffer token
63
+ * @abstract
64
+ */
65
+ async createToken(userId, rawToken, minutes = 120) {
66
+ throw new Error('Method createToken must be implemented by subclass');
67
+ }
68
+
69
+ /**
70
+ * Create individual user
71
+ *
72
+ * @param {Object} params - User creation parameters
73
+ * @returns {Promise<Object>} Created user object
74
+ * @abstract
75
+ */
76
+ async createIndividualUser(params) {
77
+ throw new Error(
78
+ 'Method createIndividualUser must be implemented by subclass'
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Create organization user
84
+ *
85
+ * @param {Object} params - Organization creation parameters
86
+ * @returns {Promise<Object>} Created organization object
87
+ * @abstract
88
+ */
89
+ async createOrganizationUser(params) {
90
+ throw new Error(
91
+ 'Method createOrganizationUser must be implemented by subclass'
92
+ );
93
+ }
94
+
95
+ /**
96
+ * Find individual user by username
97
+ *
98
+ * @param {string} username - Username to search for
99
+ * @returns {Promise<Object|null>} User object or null
100
+ * @abstract
101
+ */
102
+ async findIndividualUserByUsername(username) {
103
+ throw new Error(
104
+ 'Method findIndividualUserByUsername must be implemented by subclass'
105
+ );
106
+ }
107
+
108
+ /**
109
+ * Find individual user by app user ID
110
+ *
111
+ * @param {string} appUserId - App user ID to search for
112
+ * @returns {Promise<Object|null>} User object or null
113
+ * @abstract
114
+ */
115
+ async findIndividualUserByAppUserId(appUserId) {
116
+ throw new Error(
117
+ 'Method findIndividualUserByAppUserId must be implemented by subclass'
118
+ );
119
+ }
120
+
121
+ /**
122
+ * Find organization user by app org ID
123
+ *
124
+ * @param {string} appOrgId - App organization ID to search for
125
+ * @returns {Promise<Object|null>} User object or null
126
+ * @abstract
127
+ */
128
+ async findOrganizationUserByAppOrgId(appOrgId) {
129
+ throw new Error(
130
+ 'Method findOrganizationUserByAppOrgId must be implemented by subclass'
131
+ );
132
+ }
133
+
134
+ /**
135
+ * Find user by ID (any type)
136
+ *
137
+ * @param {string|number} userId - User ID
138
+ * @returns {Promise<Object|null>} User object or null
139
+ * @abstract
140
+ */
141
+ async findUserById(userId) {
142
+ throw new Error('Method findUserById must be implemented by subclass');
143
+ }
144
+
145
+ /**
146
+ * Find individual user by email
147
+ *
148
+ * @param {string} email - Email to search for
149
+ * @returns {Promise<Object|null>} User object or null
150
+ * @abstract
151
+ */
152
+ async findIndividualUserByEmail(email) {
153
+ throw new Error(
154
+ 'Method findIndividualUserByEmail must be implemented by subclass'
155
+ );
156
+ }
157
+
158
+ /**
159
+ * Update individual user
160
+ *
161
+ * @param {string|number} userId - User ID
162
+ * @param {Object} updates - Fields to update
163
+ * @returns {Promise<Object>} Updated user object
164
+ * @abstract
165
+ */
166
+ async updateIndividualUser(userId, updates) {
167
+ throw new Error(
168
+ 'Method updateIndividualUser must be implemented by subclass'
169
+ );
170
+ }
171
+
172
+ /**
173
+ * Update organization user
174
+ *
175
+ * @param {string|number} userId - User ID
176
+ * @param {Object} updates - Fields to update
177
+ * @returns {Promise<Object>} Updated user object
178
+ * @abstract
179
+ */
180
+ async updateOrganizationUser(userId, updates) {
181
+ throw new Error(
182
+ 'Method updateOrganizationUser must be implemented by subclass'
183
+ );
184
+ }
185
+
186
+ /**
187
+ * Delete user by ID
188
+ *
189
+ * @param {string|number} userId - User ID to delete
190
+ * @returns {Promise<boolean>} True if deleted successfully
191
+ * @abstract
192
+ */
193
+ async deleteUser(userId) {
194
+ throw new Error('Method deleteUser must be implemented by subclass');
195
+ }
196
+ }
197
+
198
+ module.exports = { UserRepositoryInterface };