@friggframework/core 2.0.0-next.41 → 2.0.0-next.43

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 (197) hide show
  1. package/CLAUDE.md +693 -0
  2. package/README.md +931 -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 +160 -0
  7. package/application/commands/integration-commands.test.js +123 -0
  8. package/application/commands/user-commands.js +213 -0
  9. package/application/index.js +69 -0
  10. package/core/CLAUDE.md +690 -0
  11. package/core/create-handler.js +0 -6
  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 +301 -0
  15. package/credential/repositories/credential-repository-postgres.js +307 -0
  16. package/credential/repositories/credential-repository.js +307 -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/config.js +117 -0
  20. package/database/encryption/README.md +683 -0
  21. package/database/encryption/encryption-integration.test.js +553 -0
  22. package/database/encryption/encryption-schema-registry.js +141 -0
  23. package/database/encryption/encryption-schema-registry.test.js +392 -0
  24. package/database/encryption/field-encryption-service.js +226 -0
  25. package/database/encryption/field-encryption-service.test.js +525 -0
  26. package/database/encryption/logger.js +79 -0
  27. package/database/encryption/mongo-decryption-fix-verification.test.js +348 -0
  28. package/database/encryption/postgres-decryption-fix-verification.test.js +371 -0
  29. package/database/encryption/postgres-relation-decryption.test.js +245 -0
  30. package/database/encryption/prisma-encryption-extension.js +222 -0
  31. package/database/encryption/prisma-encryption-extension.test.js +439 -0
  32. package/database/index.js +25 -12
  33. package/database/models/readme.md +1 -0
  34. package/database/prisma.js +162 -0
  35. package/database/repositories/health-check-repository-factory.js +38 -0
  36. package/database/repositories/health-check-repository-interface.js +86 -0
  37. package/database/repositories/health-check-repository-mongodb.js +72 -0
  38. package/database/repositories/health-check-repository-postgres.js +75 -0
  39. package/database/repositories/health-check-repository.js +108 -0
  40. package/database/use-cases/check-database-health-use-case.js +34 -0
  41. package/database/use-cases/check-encryption-health-use-case.js +82 -0
  42. package/database/use-cases/test-encryption-use-case.js +252 -0
  43. package/encrypt/Cryptor.js +20 -152
  44. package/encrypt/index.js +1 -2
  45. package/encrypt/test-encrypt.js +0 -2
  46. package/handlers/app-definition-loader.js +38 -0
  47. package/handlers/app-handler-helpers.js +0 -3
  48. package/handlers/auth-flow.integration.test.js +147 -0
  49. package/handlers/backend-utils.js +25 -45
  50. package/handlers/integration-event-dispatcher.js +54 -0
  51. package/handlers/integration-event-dispatcher.test.js +141 -0
  52. package/handlers/routers/HEALTHCHECK.md +103 -1
  53. package/handlers/routers/auth.js +3 -14
  54. package/handlers/routers/health.js +63 -424
  55. package/handlers/routers/health.test.js +7 -0
  56. package/handlers/routers/integration-defined-routers.js +8 -5
  57. package/handlers/routers/user.js +27 -5
  58. package/handlers/routers/websocket.js +5 -3
  59. package/handlers/use-cases/check-external-apis-health-use-case.js +81 -0
  60. package/handlers/use-cases/check-integrations-health-use-case.js +32 -0
  61. package/handlers/workers/integration-defined-workers.js +6 -3
  62. package/index.js +45 -22
  63. package/integrations/index.js +12 -10
  64. package/integrations/integration-base.js +224 -53
  65. package/integrations/integration-router.js +386 -178
  66. package/integrations/options.js +1 -1
  67. package/integrations/repositories/integration-mapping-repository-factory.js +50 -0
  68. package/integrations/repositories/integration-mapping-repository-interface.js +106 -0
  69. package/integrations/repositories/integration-mapping-repository-mongo.js +161 -0
  70. package/integrations/repositories/integration-mapping-repository-postgres.js +227 -0
  71. package/integrations/repositories/integration-mapping-repository.js +156 -0
  72. package/integrations/repositories/integration-repository-factory.js +44 -0
  73. package/integrations/repositories/integration-repository-interface.js +115 -0
  74. package/integrations/repositories/integration-repository-mongo.js +271 -0
  75. package/integrations/repositories/integration-repository-postgres.js +319 -0
  76. package/integrations/tests/doubles/dummy-integration-class.js +90 -0
  77. package/integrations/tests/doubles/test-integration-repository.js +99 -0
  78. package/integrations/tests/use-cases/create-integration.test.js +131 -0
  79. package/integrations/tests/use-cases/delete-integration-for-user.test.js +150 -0
  80. package/integrations/tests/use-cases/find-integration-context-by-external-entity-id.test.js +92 -0
  81. package/integrations/tests/use-cases/get-integration-for-user.test.js +150 -0
  82. package/integrations/tests/use-cases/get-integration-instance.test.js +176 -0
  83. package/integrations/tests/use-cases/get-integrations-for-user.test.js +176 -0
  84. package/integrations/tests/use-cases/get-possible-integrations.test.js +188 -0
  85. package/integrations/tests/use-cases/update-integration-messages.test.js +142 -0
  86. package/integrations/tests/use-cases/update-integration-status.test.js +103 -0
  87. package/integrations/tests/use-cases/update-integration.test.js +141 -0
  88. package/integrations/use-cases/create-integration.js +83 -0
  89. package/integrations/use-cases/delete-integration-for-user.js +73 -0
  90. package/integrations/use-cases/find-integration-context-by-external-entity-id.js +72 -0
  91. package/integrations/use-cases/get-integration-for-user.js +78 -0
  92. package/integrations/use-cases/get-integration-instance-by-definition.js +67 -0
  93. package/integrations/use-cases/get-integration-instance.js +83 -0
  94. package/integrations/use-cases/get-integrations-for-user.js +87 -0
  95. package/integrations/use-cases/get-possible-integrations.js +27 -0
  96. package/integrations/use-cases/index.js +11 -0
  97. package/integrations/use-cases/load-integration-context-full.test.js +329 -0
  98. package/integrations/use-cases/load-integration-context.js +71 -0
  99. package/integrations/use-cases/load-integration-context.test.js +114 -0
  100. package/integrations/use-cases/update-integration-messages.js +44 -0
  101. package/integrations/use-cases/update-integration-status.js +32 -0
  102. package/integrations/use-cases/update-integration.js +93 -0
  103. package/integrations/utils/map-integration-dto.js +36 -0
  104. package/jest-global-setup-noop.js +3 -0
  105. package/jest-global-teardown-noop.js +3 -0
  106. package/{module-plugin → modules}/entity.js +1 -0
  107. package/{module-plugin → modules}/index.js +0 -8
  108. package/modules/module-factory.js +56 -0
  109. package/modules/module-hydration.test.js +205 -0
  110. package/modules/module.js +221 -0
  111. package/modules/repositories/module-repository-factory.js +33 -0
  112. package/modules/repositories/module-repository-interface.js +129 -0
  113. package/modules/repositories/module-repository-mongo.js +386 -0
  114. package/modules/repositories/module-repository-postgres.js +437 -0
  115. package/modules/repositories/module-repository.js +327 -0
  116. package/{module-plugin → modules}/test/mock-api/api.js +8 -3
  117. package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
  118. package/modules/tests/doubles/test-module-factory.js +16 -0
  119. package/modules/tests/doubles/test-module-repository.js +39 -0
  120. package/modules/use-cases/get-entities-for-user.js +32 -0
  121. package/modules/use-cases/get-entity-options-by-id.js +59 -0
  122. package/modules/use-cases/get-entity-options-by-type.js +34 -0
  123. package/modules/use-cases/get-module-instance-from-type.js +31 -0
  124. package/modules/use-cases/get-module.js +56 -0
  125. package/modules/use-cases/process-authorization-callback.js +122 -0
  126. package/modules/use-cases/refresh-entity-options.js +59 -0
  127. package/modules/use-cases/test-module-auth.js +55 -0
  128. package/modules/utils/map-module-dto.js +18 -0
  129. package/package.json +14 -6
  130. package/prisma-mongodb/schema.prisma +318 -0
  131. package/prisma-postgresql/migrations/20250930193005_init/migration.sql +315 -0
  132. package/prisma-postgresql/migrations/20251006135218_init/migration.sql +9 -0
  133. package/prisma-postgresql/migrations/20251010000000_remove_unused_entity_reference_map/migration.sql +3 -0
  134. package/prisma-postgresql/migrations/migration_lock.toml +3 -0
  135. package/prisma-postgresql/schema.prisma +300 -0
  136. package/syncs/manager.js +468 -443
  137. package/syncs/repositories/sync-repository-factory.js +38 -0
  138. package/syncs/repositories/sync-repository-interface.js +109 -0
  139. package/syncs/repositories/sync-repository-mongo.js +239 -0
  140. package/syncs/repositories/sync-repository-postgres.js +319 -0
  141. package/syncs/sync.js +0 -1
  142. package/token/repositories/token-repository-factory.js +33 -0
  143. package/token/repositories/token-repository-interface.js +131 -0
  144. package/token/repositories/token-repository-mongo.js +212 -0
  145. package/token/repositories/token-repository-postgres.js +257 -0
  146. package/token/repositories/token-repository.js +219 -0
  147. package/types/integrations/index.d.ts +2 -6
  148. package/types/module-plugin/index.d.ts +5 -57
  149. package/types/syncs/index.d.ts +0 -2
  150. package/user/repositories/user-repository-factory.js +46 -0
  151. package/user/repositories/user-repository-interface.js +198 -0
  152. package/user/repositories/user-repository-mongo.js +250 -0
  153. package/user/repositories/user-repository-postgres.js +311 -0
  154. package/user/tests/doubles/test-user-repository.js +72 -0
  155. package/user/tests/use-cases/create-individual-user.test.js +24 -0
  156. package/user/tests/use-cases/create-organization-user.test.js +28 -0
  157. package/user/tests/use-cases/create-token-for-user-id.test.js +19 -0
  158. package/user/tests/use-cases/get-user-from-bearer-token.test.js +64 -0
  159. package/user/tests/use-cases/login-user.test.js +140 -0
  160. package/user/use-cases/create-individual-user.js +61 -0
  161. package/user/use-cases/create-organization-user.js +47 -0
  162. package/user/use-cases/create-token-for-user-id.js +30 -0
  163. package/user/use-cases/get-user-from-bearer-token.js +77 -0
  164. package/user/use-cases/login-user.js +122 -0
  165. package/user/user.js +77 -0
  166. package/websocket/repositories/websocket-connection-repository-factory.js +37 -0
  167. package/websocket/repositories/websocket-connection-repository-interface.js +106 -0
  168. package/websocket/repositories/websocket-connection-repository-mongo.js +155 -0
  169. package/websocket/repositories/websocket-connection-repository-postgres.js +195 -0
  170. package/websocket/repositories/websocket-connection-repository.js +160 -0
  171. package/database/models/State.js +0 -9
  172. package/database/models/Token.js +0 -70
  173. package/database/mongo.js +0 -171
  174. package/encrypt/Cryptor.test.js +0 -32
  175. package/encrypt/encrypt.js +0 -104
  176. package/encrypt/encrypt.test.js +0 -1069
  177. package/handlers/routers/middleware/loadUser.js +0 -15
  178. package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
  179. package/integrations/create-frigg-backend.js +0 -31
  180. package/integrations/integration-factory.js +0 -251
  181. package/integrations/integration-mapping.js +0 -43
  182. package/integrations/integration-model.js +0 -46
  183. package/integrations/integration-user.js +0 -144
  184. package/integrations/test/integration-base.test.js +0 -144
  185. package/module-plugin/auther.js +0 -393
  186. package/module-plugin/credential.js +0 -22
  187. package/module-plugin/entity-manager.js +0 -70
  188. package/module-plugin/manager.js +0 -169
  189. package/module-plugin/module-factory.js +0 -61
  190. package/module-plugin/test/auther.test.js +0 -97
  191. /package/{module-plugin → modules}/ModuleConstants.js +0 -0
  192. /package/{module-plugin → modules}/requester/api-key.js +0 -0
  193. /package/{module-plugin → modules}/requester/basic.js +0 -0
  194. /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
  195. /package/{module-plugin → modules}/requester/requester.js +0 -0
  196. /package/{module-plugin → modules}/requester/requester.test.js +0 -0
  197. /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
@@ -0,0 +1,213 @@
1
+ const {
2
+ createUserRepository,
3
+ } = require('../../user/repositories/user-repository-factory');
4
+
5
+ const ERROR_CODE_MAP = {
6
+ USER_NOT_FOUND: 404,
7
+ USER_ALREADY_EXISTS: 409,
8
+ INVALID_USER_DATA: 400,
9
+ };
10
+
11
+ function mapErrorToResponse(error) {
12
+ const status = ERROR_CODE_MAP[error?.code] || 500;
13
+ return {
14
+ error: status,
15
+ reason: error?.message,
16
+ code: error?.code,
17
+ };
18
+ }
19
+
20
+ /**
21
+ * Create user command factory
22
+ *
23
+ * NOTE: This is an internal API. Integration developers should use createFriggCommands() instead.
24
+ *
25
+ * @returns {Object} User command object with CRUD operations
26
+ */
27
+ function createUserCommands() {
28
+ const userRepository = createUserRepository();
29
+
30
+ return {
31
+ /**
32
+ * Create a new individual user
33
+ * @param {Object} params
34
+ * @param {string} params.username - Username (usually email)
35
+ * @param {string} [params.email] - Email address
36
+ * @param {string} [params.appUserId] - External application user ID
37
+ * @param {string} [params.password] - Password (optional)
38
+ * @returns {Promise<Object>} Created user object
39
+ */
40
+ async createUser({ username, email, appUserId, password } = {}) {
41
+ try {
42
+ if (!username) {
43
+ const error = new Error('username is required');
44
+ error.code = 'INVALID_USER_DATA';
45
+ throw error;
46
+ }
47
+
48
+ const userData = { username };
49
+ if (email) userData.email = email;
50
+ if (appUserId) userData.appUserId = appUserId;
51
+ if (password) userData.password = password;
52
+
53
+ const user = await userRepository.createIndividualUser(
54
+ userData
55
+ );
56
+
57
+ return {
58
+ id: user.id,
59
+ username: user.username,
60
+ email: user.email,
61
+ appUserId: user.appUserId,
62
+ };
63
+ } catch (error) {
64
+ if (error.code === 11000) {
65
+ // Duplicate key error
66
+ const duplicateError = new Error(
67
+ `User with username '${username}' already exists`
68
+ );
69
+ duplicateError.code = 'USER_ALREADY_EXISTS';
70
+ return mapErrorToResponse(duplicateError);
71
+ }
72
+ return mapErrorToResponse(error);
73
+ }
74
+ },
75
+
76
+ /**
77
+ * Find a user by their application user ID
78
+ * @param {string} appUserId - External application user ID
79
+ * @returns {Promise<Object|null>} User object or null if not found
80
+ */
81
+ async findUserByAppUserId(appUserId) {
82
+ try {
83
+ if (!appUserId) {
84
+ const error = new Error('appUserId is required');
85
+ error.code = 'INVALID_USER_DATA';
86
+ throw error;
87
+ }
88
+
89
+ const user = await userRepository.findIndividualUserByAppUserId(
90
+ appUserId
91
+ );
92
+
93
+ if (!user) {
94
+ return null;
95
+ }
96
+
97
+ return {
98
+ id: user.id,
99
+ username: user.username,
100
+ email: user.email,
101
+ appUserId: user.appUserId,
102
+ };
103
+ } catch (error) {
104
+ return mapErrorToResponse(error);
105
+ }
106
+ },
107
+
108
+ /**
109
+ * Find a user by their username
110
+ * @param {string} username - Username to search for
111
+ * @returns {Promise<Object|null>} User object or null if not found
112
+ */
113
+ async findUserByUsername(username) {
114
+ try {
115
+ if (!username) {
116
+ const error = new Error('username is required');
117
+ error.code = 'INVALID_USER_DATA';
118
+ throw error;
119
+ }
120
+
121
+ const user = await userRepository.findIndividualUserByUsername(
122
+ username
123
+ );
124
+
125
+ if (!user) {
126
+ return null;
127
+ }
128
+
129
+ return {
130
+ id: user.id,
131
+ username: user.username,
132
+ email: user.email,
133
+ appUserId: user.appUserId,
134
+ };
135
+ } catch (error) {
136
+ return mapErrorToResponse(error);
137
+ }
138
+ },
139
+
140
+ /**
141
+ * Find a user by their ID
142
+ * @param {string} userId - User ID to search for
143
+ * @returns {Promise<Object|null>} User object or null if not found
144
+ */
145
+ async findUserById(userId) {
146
+ try {
147
+ if (!userId) {
148
+ const error = new Error('userId is required');
149
+ error.code = 'INVALID_USER_DATA';
150
+ throw error;
151
+ }
152
+
153
+ const user = await userRepository.findIndividualUserById(
154
+ userId
155
+ );
156
+
157
+ if (!user) {
158
+ return null;
159
+ }
160
+
161
+ return {
162
+ id: user._id.toString(),
163
+ username: user.username,
164
+ email: user.email,
165
+ appUserId: user.appUserId,
166
+ };
167
+ } catch (error) {
168
+ return mapErrorToResponse(error);
169
+ }
170
+ },
171
+
172
+ /**
173
+ * Update a user by ID
174
+ * @param {string} userId - User ID to update
175
+ * @param {Object} updates - Fields to update
176
+ * @returns {Promise<Object>} Updated user object
177
+ */
178
+ async updateUser(userId, updates) {
179
+ try {
180
+ if (!userId) {
181
+ const error = new Error('userId is required');
182
+ error.code = 'INVALID_USER_DATA';
183
+ throw error;
184
+ }
185
+
186
+ const user = await userRepository.IndividualUser.update(
187
+ userId,
188
+ updates
189
+ );
190
+
191
+ if (!user) {
192
+ const error = new Error(`User ${userId} not found`);
193
+ error.code = 'USER_NOT_FOUND';
194
+ throw error;
195
+ }
196
+
197
+ return {
198
+ id: user._id.toString(),
199
+ username: user.username,
200
+ email: user.email,
201
+ appUserId: user.appUserId,
202
+ };
203
+ } catch (error) {
204
+ return mapErrorToResponse(error);
205
+ }
206
+ },
207
+ };
208
+ }
209
+
210
+ module.exports = {
211
+ createUserCommands,
212
+ ERROR_CODE_MAP,
213
+ };
@@ -0,0 +1,69 @@
1
+ const {
2
+ createIntegrationCommands,
3
+ findIntegrationContextByExternalEntityId,
4
+ } = require('./commands/integration-commands');
5
+ const { createUserCommands } = require('./commands/user-commands');
6
+ const { createEntityCommands } = require('./commands/entity-commands');
7
+ const {
8
+ createCredentialCommands,
9
+ } = require('./commands/credential-commands');
10
+
11
+ /**
12
+ * Create a unified command factory with all CRUD operations
13
+ *
14
+ * This is the main entry point for integration developers to access all
15
+ * database operations without directly touching Mongoose models.
16
+ *
17
+ * @param {Object} params
18
+ * @param {Object} params.integrationClass - Integration class (required)
19
+ * @returns {Object} Unified commands object with all CRUD operations
20
+ *
21
+ * @example
22
+ * const commands = createFriggCommands({ integrationClass: MyIntegration });
23
+ * const user = await commands.createUser({ username: 'user@example.com' });
24
+ * const credential = await commands.createCredential({ userId: user.id, ... });
25
+ */
26
+ function createFriggCommands({ integrationClass } = {}) {
27
+ // All commands use Frigg's default repositories and use cases
28
+ const integrationCommands = createIntegrationCommands({ integrationClass });
29
+
30
+ const userCommands = createUserCommands();
31
+
32
+ const entityCommands = createEntityCommands();
33
+
34
+ const credentialCommands = createCredentialCommands();
35
+
36
+ return {
37
+ // Integration commands
38
+ ...integrationCommands,
39
+
40
+ // User commands
41
+ ...userCommands,
42
+
43
+ // Entity commands
44
+ ...entityCommands,
45
+
46
+ // Credential commands
47
+ ...credentialCommands,
48
+ };
49
+ }
50
+
51
+ module.exports = {
52
+ // Unified factory
53
+ createFriggCommands,
54
+
55
+ // Individual factories
56
+ createIntegrationCommands,
57
+ createUserCommands,
58
+ createEntityCommands,
59
+ createCredentialCommands,
60
+
61
+ // Legacy standalone function
62
+ findIntegrationContextByExternalEntityId,
63
+
64
+ // Deprecated - use createFriggCommands instead
65
+ integrationCommands: {
66
+ create: createIntegrationCommands,
67
+ findIntegrationContextByExternalEntityId,
68
+ },
69
+ };