@friggframework/core 2.0.0--canary.686.3e27a92.0 → 2.0.0--canary.663.8de669c.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (184) hide show
  1. package/CLAUDE.md +0 -28
  2. package/README.md +0 -105
  3. package/application/commands/integration-commands.js +10 -20
  4. package/application/commands/scheduler-commands.js +7 -11
  5. package/application/commands/user-commands.js +5 -17
  6. package/application/index.js +2 -6
  7. package/core/Worker.js +7 -31
  8. package/core/create-handler.js +0 -9
  9. package/credential/repositories/credential-repository-documentdb.js +0 -34
  10. package/credential/repositories/credential-repository-interface.js +0 -15
  11. package/credential/repositories/credential-repository-mongo.js +0 -23
  12. package/credential/repositories/credential-repository-postgres.js +0 -28
  13. package/database/config.js +24 -48
  14. package/database/documentdb-utils.js +1 -6
  15. package/database/encryption/encryption-config.js +31 -10
  16. package/database/encryption/encryption-schema-registry.js +12 -93
  17. package/database/prisma.js +2 -4
  18. package/generated/prisma-mongodb/edge.js +4 -43
  19. package/generated/prisma-mongodb/index-browser.js +1 -40
  20. package/generated/prisma-mongodb/index.d.ts +111 -4739
  21. package/generated/prisma-mongodb/index.js +4 -43
  22. package/generated/prisma-mongodb/package.json +1 -1
  23. package/generated/prisma-mongodb/schema.prisma +0 -92
  24. package/generated/prisma-mongodb/wasm.js +4 -43
  25. package/generated/prisma-postgresql/edge.js +4 -43
  26. package/generated/prisma-postgresql/index-browser.js +1 -40
  27. package/generated/prisma-postgresql/index.d.ts +33 -4966
  28. package/generated/prisma-postgresql/index.js +4 -43
  29. package/generated/prisma-postgresql/package.json +1 -1
  30. package/generated/prisma-postgresql/schema.prisma +0 -87
  31. package/generated/prisma-postgresql/wasm.js +4 -43
  32. package/handlers/app-definition-loader.js +19 -121
  33. package/handlers/app-handler-helpers.js +3 -25
  34. package/handlers/backend-utils.js +25 -31
  35. package/handlers/middleware/admin-auth.js +1 -14
  36. package/handlers/routers/auth.js +10 -46
  37. package/handlers/routers/health.js +4 -13
  38. package/handlers/routers/integration-defined-routers.js +92 -144
  39. package/handlers/routers/integration-webhook-routers.js +64 -102
  40. package/handlers/workers/integration-defined-workers.js +2 -5
  41. package/index.js +1 -65
  42. package/infrastructure/scheduler/index.js +6 -19
  43. package/infrastructure/scheduler/scheduler-service-factory.js +7 -55
  44. package/integrations/index.js +0 -1
  45. package/integrations/integration-router.js +96 -131
  46. package/integrations/repositories/integration-repository-documentdb.js +3 -35
  47. package/integrations/repositories/integration-repository-interface.js +1 -17
  48. package/integrations/repositories/integration-repository-mongo.js +76 -59
  49. package/integrations/repositories/integration-repository-postgres.js +76 -62
  50. package/integrations/tests/doubles/test-integration-repository.js +1 -12
  51. package/integrations/use-cases/create-integration.js +20 -55
  52. package/integrations/use-cases/get-integrations-for-user.js +40 -80
  53. package/integrations/use-cases/index.js +1 -7
  54. package/integrations/utils/map-integration-dto.js +14 -43
  55. package/modules/index.js +0 -14
  56. package/modules/module-factory.js +0 -12
  57. package/modules/module.js +2 -53
  58. package/modules/repositories/module-repository-documentdb.js +6 -51
  59. package/modules/repositories/module-repository-interface.js +2 -19
  60. package/modules/repositories/module-repository-mongo.js +74 -67
  61. package/modules/repositories/module-repository-postgres.js +74 -66
  62. package/modules/repositories/module-repository.js +1 -2
  63. package/modules/requester/requester.js +2 -27
  64. package/modules/use-cases/get-entities-for-user.js +13 -26
  65. package/modules/use-cases/get-entity-options-by-id.js +4 -10
  66. package/modules/use-cases/get-entity-options-by-type.js +1 -1
  67. package/modules/use-cases/get-module-instance-from-type.js +1 -1
  68. package/modules/use-cases/get-module.js +4 -10
  69. package/modules/use-cases/process-authorization-callback.js +19 -53
  70. package/modules/use-cases/refresh-entity-options.js +4 -10
  71. package/modules/use-cases/test-module-auth.js +4 -10
  72. package/package.json +5 -6
  73. package/prisma-mongodb/schema.prisma +0 -92
  74. package/prisma-postgresql/schema.prisma +0 -87
  75. package/queues/index.js +0 -25
  76. package/types/index.d.ts +0 -2
  77. package/user/repositories/user-repository-documentdb.js +2 -27
  78. package/user/repositories/user-repository-interface.js +0 -18
  79. package/user/repositories/user-repository-mongo.js +0 -24
  80. package/user/repositories/user-repository-postgres.js +0 -18
  81. package/user/use-cases/authenticate-user.js +1 -7
  82. package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
  83. package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
  84. package/user/user.js +1 -64
  85. package/credential/use-cases/credential-operations-for-user.js +0 -202
  86. package/credential/use-cases/reauthorize-credential-for-user.js +0 -73
  87. package/database/organization-where.js +0 -18
  88. package/database/unique-violation.js +0 -25
  89. package/extensions/bootstrap-runner.js +0 -43
  90. package/extensions/extension-loader.js +0 -187
  91. package/extensions/index.js +0 -41
  92. package/extensions/initialize-app.js +0 -123
  93. package/extensions/route-mounter.js +0 -103
  94. package/extensions/schema-composer.js +0 -188
  95. package/infrastructure/scheduler/netlify-scheduler-adapter.js +0 -216
  96. package/infrastructure/scheduler/scheduled-job-repository.js +0 -118
  97. package/integrations/repositories/integration-not-found.js +0 -14
  98. package/integrations/schedule-config.js +0 -80
  99. package/integrations/use-cases/dispatch-ongoing-syncs.js +0 -100
  100. package/integrations/use-cases/integration-operations-for-user.js +0 -256
  101. package/integrations/use-cases/resolve-integration-ownership.js +0 -177
  102. package/management-api/create-management-api-router.js +0 -49
  103. package/management-api/error-response.js +0 -116
  104. package/management-api/management-api-config.js +0 -151
  105. package/management-api/meta-router.js +0 -76
  106. package/management-api/openapi/build-openapi.js +0 -144
  107. package/management-api/openapi/components.js +0 -408
  108. package/management-api/openapi/v1-operations.js +0 -83
  109. package/management-api/openapi/v2-operations.js +0 -264
  110. package/management-api/route-registry.js +0 -411
  111. package/management-api/test-support/http-client.js +0 -39
  112. package/management-api/use-cases/get-management-api-meta.js +0 -57
  113. package/management-api/v1-deprecation.js +0 -120
  114. package/management-api/v2/create-v2-router.js +0 -85
  115. package/management-api/v2/dependencies.js +0 -281
  116. package/management-api/v2/dto.js +0 -143
  117. package/management-api/v2/handlers/authorization.js +0 -94
  118. package/management-api/v2/handlers/credentials.js +0 -33
  119. package/management-api/v2/handlers/entities.js +0 -77
  120. package/management-api/v2/handlers/integrations.js +0 -128
  121. package/management-api/v2/handlers/proxy.js +0 -34
  122. package/management-api/v2/request.js +0 -85
  123. package/management-api/v2/test-support/fake-dependencies.js +0 -103
  124. package/modules/domain/authorization-session.js +0 -144
  125. package/modules/entity-scope.js +0 -15
  126. package/modules/entity-type-registry.js +0 -311
  127. package/modules/proxy/proxy-errors.js +0 -20
  128. package/modules/proxy/proxy-path.js +0 -179
  129. package/modules/proxy/proxy-policy.js +0 -248
  130. package/modules/repositories/authorization-session-repository-documentdb.js +0 -112
  131. package/modules/repositories/authorization-session-repository-factory.js +0 -31
  132. package/modules/repositories/authorization-session-repository-interface.js +0 -47
  133. package/modules/repositories/authorization-session-repository-prisma.js +0 -87
  134. package/modules/repositories/entity-not-found.js +0 -18
  135. package/modules/requester/proxy-request.js +0 -244
  136. package/modules/scope-config.js +0 -192
  137. package/modules/scope-policy.js +0 -112
  138. package/modules/scope-resolution.js +0 -288
  139. package/modules/scope-visibility.js +0 -247
  140. package/modules/tests/doubles/in-memory-authorization-session-repository.js +0 -45
  141. package/modules/tests/doubles/ownership-matching.js +0 -18
  142. package/modules/use-cases/authorize-entity-for-user.js +0 -61
  143. package/modules/use-cases/create-entity-from-credential.js +0 -113
  144. package/modules/use-cases/entity-operations-for-user.js +0 -162
  145. package/modules/use-cases/entity-types.js +0 -139
  146. package/modules/use-cases/execute-entity-proxy-request.js +0 -286
  147. package/modules/use-cases/get-authorization-requirements.js +0 -100
  148. package/modules/use-cases/get-entity-module-for-user.js +0 -113
  149. package/modules/use-cases/manage-access.js +0 -21
  150. package/modules/use-cases/multi-step-authorization.js +0 -329
  151. package/prisma-postgresql/migrations/20261003000000_add_authorization_session/migration.sql +0 -28
  152. package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
  153. package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
  154. package/prisma-postgresql/migrations/20261017000000_add_scheduled_job/migration.sql +0 -28
  155. package/providers/index.js +0 -23
  156. package/providers/resolve-provider.js +0 -93
  157. package/providers/runtime-detection.js +0 -124
  158. package/queues/providers/index.js +0 -11
  159. package/queues/providers/netlify-background-provider.js +0 -150
  160. package/queues/providers/qstash-queue-provider.js +0 -219
  161. package/queues/providers/sqs-queue-provider.js +0 -70
  162. package/queues/queue-client-interface.js +0 -55
  163. package/queues/queue-message-auth.js +0 -193
  164. package/queues/queue-provider-factory.js +0 -101
  165. package/queues/queue-provider.js +0 -65
  166. package/queues/sqs-queue-client.js +0 -81
  167. package/types/modules/index.d.ts +0 -197
  168. package/types/user/index.d.ts +0 -134
  169. package/user/adopter-jwt-config.js +0 -177
  170. package/user/adopter-jwt-errors.js +0 -59
  171. package/user/adopter-token-verifier.js +0 -122
  172. package/user/app-user-helpers.js +0 -97
  173. package/user/create-user-authentication.js +0 -64
  174. package/user/membership.js +0 -51
  175. package/user/repositories/organization-membership-record.js +0 -19
  176. package/user/repositories/organization-membership-repository-documentdb.js +0 -106
  177. package/user/repositories/organization-membership-repository-factory.js +0 -42
  178. package/user/repositories/organization-membership-repository-interface.js +0 -57
  179. package/user/repositories/organization-membership-repository-mongo.js +0 -13
  180. package/user/repositories/organization-membership-repository-postgres.js +0 -29
  181. package/user/repositories/organization-membership-repository-prisma.js +0 -81
  182. package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
  183. package/user/use-cases/ensure-organization-membership.js +0 -92
  184. package/user/use-cases/find-individual-users-by-organization.js +0 -54
@@ -31,6 +31,9 @@ const {
31
31
  GetIntegrationInstance,
32
32
  } = require('./use-cases/get-integration-instance');
33
33
  const { UpdateIntegration } = require('./use-cases/update-integration');
34
+ const {
35
+ getModulesDefinitionFromIntegrationClasses,
36
+ } = require('./utils/map-integration-dto');
34
37
  const {
35
38
  GetModuleInstanceFromType,
36
39
  } = require('../modules/use-cases/get-module-instance-from-type');
@@ -51,51 +54,47 @@ const {
51
54
  const {
52
55
  createUserRepository,
53
56
  } = require('../user/repositories/user-repository-factory');
57
+ const {
58
+ GetUserFromBearerToken,
59
+ } = require('../user/use-cases/get-user-from-bearer-token');
60
+ const {
61
+ GetUserFromXFriggHeaders,
62
+ } = require('../user/use-cases/get-user-from-x-frigg-headers');
63
+ const {
64
+ GetUserFromAdopterJwt,
65
+ } = require('../user/use-cases/get-user-from-adopter-jwt');
54
66
  const {
55
67
  AuthenticateWithSharedSecret,
56
68
  } = require('../user/use-cases/authenticate-with-shared-secret');
57
69
  const { AuthenticateUser } = require('../user/use-cases/authenticate-user');
58
- const {
59
- buildUserAuthentication,
60
- } = require('../user/create-user-authentication');
61
70
  const {
62
71
  ProcessAuthorizationCallback,
63
72
  } = require('../modules/use-cases/process-authorization-callback');
64
- const { createScopePolicy } = require('../modules/scope-policy');
65
- const {
66
- AuthorizeEntityForUser,
67
- } = require('../modules/use-cases/authorize-entity-for-user');
68
- const {
69
- CreateEntityFromCredential,
70
- } = require('../modules/use-cases/create-entity-from-credential');
71
- const {
72
- ResolveIntegrationOwnership,
73
- } = require('./use-cases/resolve-integration-ownership');
74
- const { GetOwnedIntegrationRecord } = require('./use-cases/integration-operations-for-user');
75
73
 
76
74
  const log = getLogger('frigg.integrations');
77
75
 
78
76
  function createIntegrationRouter() {
79
- // moduleDefinitions is the app registry's definitions (ADR-059), so
80
- // /api/authorize and friends accept a type no integration binds.
81
- const {
82
- integrations: integrationClasses,
83
- userConfig,
84
- moduleDefinitions,
85
- ownership,
86
- entityTypeRegistry,
87
- } = loadAppDefinition();
88
- // Ownership by scope (ADR-056 §3): one object every use case asks.
89
- const scopePolicy = createScopePolicy({ ownership, entityTypeRegistry });
77
+ const { integrations: integrationClasses, userConfig } =
78
+ loadAppDefinition();
90
79
  const moduleRepository = createModuleRepository();
91
80
  const integrationRepository = createIntegrationRepository();
92
81
  const credentialRepository = createCredentialRepository();
93
82
  const userRepository = createUserRepository();
94
- const {
95
- getUserFromBearerToken,
96
- getUserFromXFriggHeaders,
97
- getUserFromAdopterJwt,
98
- } = buildUserAuthentication({ userConfig, userRepository });
83
+
84
+ const getUserFromBearerToken = new GetUserFromBearerToken({
85
+ userRepository,
86
+ userConfig,
87
+ });
88
+
89
+ const getUserFromXFriggHeaders = new GetUserFromXFriggHeaders({
90
+ userRepository,
91
+ userConfig,
92
+ });
93
+
94
+ const getUserFromAdopterJwt = new GetUserFromAdopterJwt({
95
+ userRepository,
96
+ userConfig,
97
+ });
99
98
 
100
99
  const authenticateWithSharedSecret = new AuthenticateWithSharedSecret();
101
100
 
@@ -109,7 +108,8 @@ function createIntegrationRouter() {
109
108
 
110
109
  const moduleFactory = new ModuleFactory({
111
110
  moduleRepository,
112
- moduleDefinitions,
111
+ moduleDefinitions:
112
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
113
113
  });
114
114
  const deleteIntegrationForUser = new DeleteIntegrationForUser({
115
115
  integrationRepository,
@@ -122,19 +122,6 @@ function createIntegrationRouter() {
122
122
  integrationClasses,
123
123
  moduleFactory,
124
124
  moduleRepository,
125
- scopePolicy,
126
- });
127
-
128
- // Decides who owns a new integration and which entities the caller may bind
129
- // (the v1 create used to check neither), and who may reach an existing one.
130
- const resolveIntegrationOwnership = new ResolveIntegrationOwnership({
131
- moduleRepository,
132
- integrationClasses,
133
- scopePolicy,
134
- });
135
- const getOwnedIntegrationRecord = new GetOwnedIntegrationRecord({
136
- integrationRepository,
137
- scopePolicy,
138
125
  });
139
126
 
140
127
  const getCredentialForUser = new GetCredentialForUser({
@@ -149,8 +136,8 @@ function createIntegrationRouter() {
149
136
 
150
137
  const getEntitiesForUser = new GetEntitiesForUser({
151
138
  moduleRepository,
152
- moduleDefinitions,
153
- scopePolicy,
139
+ moduleDefinitions:
140
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
154
141
  });
155
142
 
156
143
  const getIntegrationInstance = new GetIntegrationInstance({
@@ -166,65 +153,54 @@ function createIntegrationRouter() {
166
153
  });
167
154
 
168
155
  const getModuleInstanceFromType = new GetModuleInstanceFromType({
169
- moduleDefinitions,
156
+ moduleDefinitions:
157
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
170
158
  });
171
159
 
172
160
  const getEntityOptionsByType = new GetEntityOptionsByType({
173
- moduleDefinitions,
161
+ moduleDefinitions:
162
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
174
163
  });
175
164
 
176
165
  const testModuleAuth = new TestModuleAuth({
177
166
  moduleRepository,
178
- moduleDefinitions,
179
- scopePolicy,
167
+ moduleDefinitions:
168
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
180
169
  });
181
170
 
182
171
  const getModule = new GetModule({
183
172
  moduleRepository,
184
- moduleDefinitions,
185
- scopePolicy,
173
+ moduleDefinitions:
174
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
186
175
  });
187
176
 
188
177
  const getEntityOptionsById = new GetEntityOptionsById({
189
178
  moduleRepository,
190
- moduleDefinitions,
191
- scopePolicy,
179
+ moduleDefinitions:
180
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
192
181
  });
193
182
 
194
183
  const refreshEntityOptions = new RefreshEntityOptions({
195
184
  moduleRepository,
196
- moduleDefinitions,
197
- scopePolicy,
185
+ moduleDefinitions:
186
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
198
187
  });
199
188
 
200
189
  const getPossibleIntegrations = new GetPossibleIntegrations({
201
190
  integrationClasses,
202
191
  });
203
192
 
204
- // The owner of what an authorization creates follows its scope (ADR-056 §3.2).
205
193
  const processAuthorizationCallback = new ProcessAuthorizationCallback({
206
194
  moduleRepository,
207
195
  credentialRepository,
208
196
  integrationRepository,
209
- moduleDefinitions,
210
- });
211
- const authorizeEntityForUser = new AuthorizeEntityForUser({
212
- scopePolicy,
213
- processAuthorizationCallback,
214
- });
215
- // v1 POST /api/entity: same owner resolution as /api/authorize.
216
- const createEntityFromCredential = new CreateEntityFromCredential({
217
- authorizeEntityForUser,
218
- processAuthorizationCallback,
219
- credentialRepository,
220
- moduleDefinitions,
197
+ moduleDefinitions:
198
+ getModulesDefinitionFromIntegrationClasses(integrationClasses),
221
199
  });
222
200
 
223
201
  const router = express();
224
202
 
225
203
  setIntegrationRoutes(router, authenticateUser, {
226
- resolveIntegrationOwnership,
227
- getOwnedIntegrationRecord,
228
204
  createIntegration,
229
205
  deleteIntegrationForUser,
230
206
  getIntegrationsForUser,
@@ -241,8 +217,7 @@ function createIntegrationRouter() {
241
217
  getModule,
242
218
  getEntityOptionsById,
243
219
  refreshEntityOptions,
244
- authorizeEntityForUser,
245
- createEntityFromCredential,
220
+ processAuthorizationCallback,
246
221
  });
247
222
  return router;
248
223
  }
@@ -279,8 +254,6 @@ function checkRequiredParams(params, requiredKeys) {
279
254
  */
280
255
  function setIntegrationRoutes(router, authenticateUser, useCases) {
281
256
  const {
282
- resolveIntegrationOwnership,
283
- getOwnedIntegrationRecord,
284
257
  createIntegration,
285
258
  deleteIntegrationForUser,
286
259
  getIntegrationsForUser,
@@ -289,22 +262,15 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
289
262
  updateIntegration,
290
263
  getPossibleIntegrations,
291
264
  } = useCases;
292
-
293
- // The owner of an integration the caller may reach (404 otherwise), which is
294
- // what the id-and-owner use cases below expect. `manage: true` is for
295
- // changing or deleting: an organization's integration needs an admin (403).
296
- const ownerOf = async (integrationId, user, options) =>
297
- (await getOwnedIntegrationRecord.execute(integrationId, user, options))
298
- .userId;
299
-
300
265
  router.route('/api/integrations').get(
301
266
  catchAsyncError(async (req, res) => {
302
267
  const user = await authenticateUser.execute(req);
303
- const integrations = await getIntegrationsForUser.execute(user);
268
+ const userId = user.getId();
269
+ const integrations = await getIntegrationsForUser.execute(userId);
304
270
  const results = {
305
271
  entities: {
306
272
  options: await getPossibleIntegrations.execute(),
307
- authorized: await getEntitiesForUser.execute(user),
273
+ authorized: await getEntitiesForUser.execute(userId),
308
274
  },
309
275
  integrations: integrations,
310
276
  };
@@ -316,6 +282,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
316
282
  router.route('/api/integrations').post(
317
283
  catchAsyncError(async (req, res) => {
318
284
  const user = await authenticateUser.execute(req);
285
+ const userId = user.getId();
319
286
  const params = checkRequiredParams(req.body, [
320
287
  'entities',
321
288
  'config',
@@ -323,17 +290,10 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
323
290
 
324
291
  get(params.config, 'type');
325
292
 
326
- const { ownerId, organizationId, adoptUnscoped } =
327
- await resolveIntegrationOwnership.execute({
328
- entityIds: params.entities,
329
- config: params.config,
330
- user,
331
- });
332
293
  const integration = await createIntegration.execute(
333
294
  params.entities,
334
- ownerId,
335
- params.config,
336
- { organizationId, adoptUnscoped }
295
+ userId,
296
+ params.config
337
297
  );
338
298
 
339
299
  res.status(201).json(integration);
@@ -343,11 +303,12 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
343
303
  router.route('/api/integrations/:integrationId').patch(
344
304
  catchAsyncError(async (req, res) => {
345
305
  const user = await authenticateUser.execute(req);
306
+ const userId = user.getId();
346
307
  const params = checkRequiredParams(req.body, ['config']);
347
308
 
348
309
  const integration = await updateIntegration.execute(
349
310
  req.params.integrationId,
350
- await ownerOf(req.params.integrationId, user, { manage: true }),
311
+ userId,
351
312
  params.config
352
313
  );
353
314
  res.json(integration);
@@ -360,7 +321,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
360
321
  const params = checkRequiredParams(req.params, ['integrationId']);
361
322
  await deleteIntegrationForUser.execute(
362
323
  params.integrationId,
363
- await ownerOf(params.integrationId, user, { manage: true })
324
+ user.getId()
364
325
  );
365
326
  res.status(204).json({});
366
327
  })
@@ -372,7 +333,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
372
333
  const params = checkRequiredParams(req.params, ['integrationId']);
373
334
  const integration = await getIntegrationInstance.execute(
374
335
  params.integrationId,
375
- await ownerOf(params.integrationId, user)
336
+ user.getId()
376
337
  );
377
338
  res.json(await integration.send('GET_CONFIG_OPTIONS'));
378
339
  })
@@ -388,7 +349,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
388
349
  ]);
389
350
  const integration = await getIntegrationInstance.execute(
390
351
  params.integrationId,
391
- await ownerOf(params.integrationId, user)
352
+ user.getId()
392
353
  );
393
354
 
394
355
  res.json(
@@ -402,7 +363,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
402
363
  const params = checkRequiredParams(req.params, ['integrationId']);
403
364
  const integration = await getIntegrationInstance.execute(
404
365
  params.integrationId,
405
- await ownerOf(params.integrationId, user)
366
+ user.getId()
406
367
  );
407
368
  res.json(await integration.send('GET_USER_ACTIONS', req.body));
408
369
  })
@@ -419,7 +380,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
419
380
  ]);
420
381
  const integration = await getIntegrationInstance.execute(
421
382
  params.integrationId,
422
- await ownerOf(params.integrationId, user)
383
+ user.getId()
423
384
  );
424
385
 
425
386
  res.json(
@@ -444,7 +405,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
444
405
  ]);
445
406
  const integration = await getIntegrationInstance.execute(
446
407
  params.integrationId,
447
- await ownerOf(params.integrationId, user)
408
+ user.getId()
448
409
  );
449
410
 
450
411
  res.json(
@@ -465,7 +426,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
465
426
  ]);
466
427
  const integration = await getIntegrationInstance.execute(
467
428
  params.integrationId,
468
- await ownerOf(params.integrationId, user)
429
+ user.getId()
469
430
  );
470
431
  res.json(await integration.send(params.actionId, req.body));
471
432
  })
@@ -482,7 +443,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
482
443
  const params = checkRequiredParams(req.params, ['integrationId']);
483
444
  const integration = await getIntegrationInstance.execute(
484
445
  params.integrationId,
485
- await ownerOf(params.integrationId, user)
446
+ user.getId()
486
447
  );
487
448
 
488
449
  // We could perhaps augment router with dynamic options? Haven't decided yet, but here may be the place
@@ -502,7 +463,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
502
463
  const params = checkRequiredParams(req.params, ['integrationId']);
503
464
  const instance = await getIntegrationInstance.execute(
504
465
  params.integrationId,
505
- await ownerOf(params.integrationId, user)
466
+ user.getId()
506
467
  );
507
468
 
508
469
  if (!instance) {
@@ -540,21 +501,16 @@ function setEntityRoutes(router, authenticateUser, useCases) {
540
501
  getModule,
541
502
  getEntityOptionsById,
542
503
  refreshEntityOptions,
543
- authorizeEntityForUser,
544
- createEntityFromCredential,
504
+ processAuthorizationCallback,
545
505
  } = useCases;
546
506
 
547
507
  router.route('/api/authorize').get(
548
508
  catchAsyncError(async (req, res) => {
549
509
  const user = await authenticateUser.execute(req);
510
+ const userId = user.getId();
550
511
  const params = checkRequiredParams(req.query, ['entityType']);
551
- // The owner POST stores under, so GET and POST describe one connection.
552
- const { ownerId } = authorizeEntityForUser.resolveOwnership({
553
- user,
554
- entityType: params.entityType,
555
- });
556
512
  const module = await getModuleInstanceFromType.execute(
557
- ownerId,
513
+ userId,
558
514
  params.entityType,
559
515
  { state: req.query.state }
560
516
  );
@@ -573,15 +529,11 @@ function setEntityRoutes(router, authenticateUser, useCases) {
573
529
  router.route('/api/authorize').post(
574
530
  catchAsyncError(async (req, res) => {
575
531
  const user = await authenticateUser.execute(req);
532
+ const userId = user.getId();
576
533
  const params = checkRequiredParams(req.body, [
577
534
  'entityType',
578
535
  'data',
579
536
  ]);
580
- const ownership = authorizeEntityForUser.resolveOwnership({
581
- user,
582
- entityType: params.entityType,
583
- });
584
- const userId = ownership.ownerId;
585
537
 
586
538
  const dataKeys =
587
539
  params.data && typeof params.data === 'object'
@@ -593,13 +545,11 @@ function setEntityRoutes(router, authenticateUser, useCases) {
593
545
  dataKeys,
594
546
  });
595
547
 
596
- const { result: entityDetails } =
597
- await authorizeEntityForUser.execute({
598
- user,
599
- entityType: params.entityType,
600
- data: params.data,
601
- ownership,
602
- });
548
+ const entityDetails = await processAuthorizationCallback.execute(
549
+ userId,
550
+ params.entityType,
551
+ params.data
552
+ );
603
553
 
604
554
  log.info('Entity authorized', {
605
555
  eventName: 'frigg.integrations.authorized',
@@ -616,20 +566,35 @@ function setEntityRoutes(router, authenticateUser, useCases) {
616
566
  router.route('/api/entity').post(
617
567
  catchAsyncError(async (req, res) => {
618
568
  const user = await authenticateUser.execute(req);
569
+ const userId = user.getId();
619
570
  const params = checkRequiredParams(req.body, [
620
571
  'entityType',
621
572
  'data',
622
573
  ]);
623
574
  checkRequiredParams(req.body.data, ['credential_id']);
624
575
 
625
- // The owner follows the entity type's scope, as /api/authorize.
626
- res.json(
627
- await createEntityFromCredential.execute({
628
- user,
629
- entityType: params.entityType,
630
- credentialId: params.data.credential_id,
631
- })
576
+ // May want to pass along the user ID as well so credential ID's can't be fished???
577
+ const credential = await getCredentialForUser.execute(
578
+ params.data.credential_id,
579
+ userId
632
580
  );
581
+
582
+ if (!credential) {
583
+ throw Boom.badRequest('Invalid credential ID');
584
+ }
585
+
586
+ const module = await getModuleInstanceFromType.execute(
587
+ userId,
588
+ params.entityType
589
+ );
590
+ const entityDetails = await module.getEntityDetails(
591
+ module.api,
592
+ null,
593
+ null,
594
+ userId
595
+ );
596
+
597
+ res.json(await module.findOrCreateEntity(entityDetails));
633
598
  })
634
599
  );
635
600
 
@@ -14,7 +14,6 @@ const {
14
14
  IntegrationRepositoryInterface,
15
15
  } = require('./integration-repository-interface');
16
16
  const { validateConfigPatch } = require('./config-patch-shared');
17
- const { integrationNotFoundError } = require('./integration-not-found');
18
17
 
19
18
  class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
20
19
  constructor() {
@@ -29,28 +28,6 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
29
28
  return records.map((doc) => this._mapIntegration(doc));
30
29
  }
31
30
 
32
- /**
33
- * Find integrations matching any of the owner/organization pairs, in one
34
- * query. `organizationId: null` matches rows with no organization (a raw
35
- * MongoDB `null` also matches a missing field). The caller (a use case)
36
- * decides which pairs; this only runs them.
37
- *
38
- * @param {Array<{userId: string, organizationId: (string|null)}>} clauses
39
- * @returns {Promise<Array>}
40
- */
41
- async findIntegrationsByOwnership(clauses) {
42
- if (!Array.isArray(clauses) || clauses.length === 0) return [];
43
- // Drained: a list can hold more than the first cursor batch (~101).
44
- const records = await findManyDrained(this.prisma, 'Integration', {
45
- $or: clauses.map(({ userId, organizationId }) => ({
46
- userId: toObjectId(userId),
47
- organizationId:
48
- organizationId === null ? null : toObjectId(organizationId),
49
- })),
50
- });
51
- return records.map((doc) => this._mapIntegration(doc));
52
- }
53
-
54
31
  async findIntegrations({ type, status } = {}) {
55
32
  const filter = {};
56
33
  if (type) {
@@ -91,11 +68,11 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
91
68
  async findIntegrationById(id) {
92
69
  const objectId = toObjectId(id);
93
70
  if (!objectId) {
94
- throw integrationNotFoundError(id);
71
+ throw new Error(`Integration with id ${id} not found`);
95
72
  }
96
73
  const doc = await findOne(this.prisma, 'Integration', { _id: objectId });
97
74
  if (!doc) {
98
- throw integrationNotFoundError(id);
75
+ throw new Error(`Integration with id ${id} not found`);
99
76
  }
100
77
  return this._mapIntegration(doc);
101
78
  }
@@ -155,18 +132,10 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
155
132
  return true;
156
133
  }
157
134
 
158
- /**
159
- * @param {Array<string>} entities - entity ids
160
- * @param {string} userId - owner (the person, or the organization's user)
161
- * @param {Object} config - Integration configuration
162
- * @param {{organizationId?: (string|null)}} [tenancy] - the organization the
163
- * integration is created in (ADR-056 §3.6)
164
- */
165
- async createIntegration(entities, userId, config, tenancy = {}) {
135
+ async createIntegration(entities, userId, config) {
166
136
  const now = new Date();
167
137
  const document = {
168
138
  userId: toObjectId(userId) || null,
169
- organizationId: toObjectId(tenancy.organizationId) || null,
170
139
  config,
171
140
  version: '0.0.0',
172
141
  status: 'IN_CREATION',
@@ -329,7 +298,6 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
329
298
  id: fromObjectId(doc?._id),
330
299
  entitiesIds: (doc?.entityIds || []).map((value) => fromObjectId(value)),
331
300
  userId: fromObjectId(doc?.userId),
332
- organizationId: fromObjectId(doc?.organizationId) ?? null,
333
301
  config: doc?.config ?? null,
334
302
  version: doc?.version ?? null,
335
303
  status: doc?.status ?? null,
@@ -10,20 +10,6 @@
10
10
  * @abstract
11
11
  */
12
12
  class IntegrationRepositoryInterface {
13
- /**
14
- * Find integrations matching any of the owner/organization pairs, in one
15
- * query (ADR-056 §3.6). `organizationId: null` matches rows with no
16
- * organization. Which pairs is decided by the caller
17
- * (modules/entity-scope.js), not here.
18
- *
19
- * @param {Array<{userId: string|number, organizationId: (string|number|null)}>} clauses
20
- * @returns {Promise<Array>} Array of integration objects
21
- * @abstract
22
- */
23
- async findIntegrationsByOwnership(clauses) {
24
- throw new Error('Method findIntegrationsByOwnership must be implemented by subclass');
25
- }
26
-
27
13
  /**
28
14
  * Find all integrations for a user
29
15
  *
@@ -137,12 +123,10 @@ class IntegrationRepositoryInterface {
137
123
  * @param {Array<string|number>} entities - Array of entity IDs
138
124
  * @param {string|number} userId - User ID
139
125
  * @param {Object} config - Integration configuration
140
- * @param {{organizationId?: (string|number|null)}} [tenancy] - the organization the
141
- * integration is created in (ADR-056 §3.6)
142
126
  * @returns {Promise<Object>} Created integration object
143
127
  * @abstract
144
128
  */
145
- async createIntegration(entities, userId, config, tenancy) {
129
+ async createIntegration(entities, userId, config) {
146
130
  throw new Error('Method createIntegration must be implemented by subclass');
147
131
  }
148
132