@friggframework/core 2.0.0--canary.684.0da024b.0 → 2.0.0--canary.679.a2bcc2f.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 (104) hide show
  1. package/CLAUDE.md +0 -2
  2. package/README.md +0 -105
  3. package/application/commands/integration-commands.js +2 -2
  4. package/application/commands/user-commands.js +5 -17
  5. package/credential/use-cases/credential-operations-for-user.js +25 -110
  6. package/credential/use-cases/reauthorize-credential-for-user.js +8 -15
  7. package/database/documentdb-utils.js +1 -6
  8. package/generated/prisma-mongodb/edge.js +4 -15
  9. package/generated/prisma-mongodb/index-browser.js +1 -12
  10. package/generated/prisma-mongodb/index.d.ts +86 -2027
  11. package/generated/prisma-mongodb/index.js +4 -15
  12. package/generated/prisma-mongodb/package.json +1 -1
  13. package/generated/prisma-mongodb/schema.prisma +0 -47
  14. package/generated/prisma-mongodb/wasm.js +4 -15
  15. package/generated/prisma-postgresql/edge.js +4 -15
  16. package/generated/prisma-postgresql/index-browser.js +1 -12
  17. package/generated/prisma-postgresql/index.d.ts +63 -2162
  18. package/generated/prisma-postgresql/index.js +4 -15
  19. package/generated/prisma-postgresql/package.json +1 -1
  20. package/generated/prisma-postgresql/schema.prisma +0 -44
  21. package/generated/prisma-postgresql/wasm.js +4 -15
  22. package/handlers/app-definition-loader.js +1 -15
  23. package/index.js +0 -18
  24. package/integrations/integration-router.js +73 -115
  25. package/integrations/repositories/integration-repository-documentdb.js +3 -35
  26. package/integrations/repositories/integration-repository-interface.js +1 -17
  27. package/integrations/repositories/integration-repository-mongo.js +76 -59
  28. package/integrations/repositories/integration-repository-postgres.js +76 -62
  29. package/integrations/tests/doubles/test-integration-repository.js +1 -12
  30. package/integrations/use-cases/create-integration.js +20 -55
  31. package/integrations/use-cases/get-integrations-for-user.js +40 -80
  32. package/integrations/use-cases/index.js +1 -5
  33. package/integrations/use-cases/integration-operations-for-user.js +24 -55
  34. package/management-api/management-api-config.js +0 -3
  35. package/management-api/openapi/components.js +0 -40
  36. package/management-api/openapi/v2-operations.js +1 -13
  37. package/management-api/v2/dependencies.js +15 -40
  38. package/management-api/v2/dto.js +0 -20
  39. package/management-api/v2/handlers/authorization.js +0 -1
  40. package/management-api/v2/handlers/credentials.js +2 -6
  41. package/management-api/v2/handlers/entities.js +7 -10
  42. package/management-api/v2/handlers/integrations.js +3 -6
  43. package/management-api/v2/request.js +1 -32
  44. package/modules/index.js +0 -8
  45. package/modules/repositories/module-repository-documentdb.js +4 -48
  46. package/modules/repositories/module-repository-interface.js +2 -19
  47. package/modules/repositories/module-repository-mongo.js +73 -65
  48. package/modules/repositories/module-repository-postgres.js +73 -64
  49. package/modules/use-cases/entity-operations-for-user.js +13 -50
  50. package/modules/use-cases/entity-types.js +7 -31
  51. package/modules/use-cases/execute-entity-proxy-request.js +0 -15
  52. package/modules/use-cases/get-entities-for-user.js +5 -16
  53. package/modules/use-cases/get-entity-module-for-user.js +3 -23
  54. package/modules/use-cases/get-entity-options-by-id.js +3 -9
  55. package/modules/use-cases/get-module.js +3 -9
  56. package/modules/use-cases/multi-step-authorization.js +12 -39
  57. package/modules/use-cases/process-authorization-callback.js +18 -52
  58. package/modules/use-cases/refresh-entity-options.js +3 -9
  59. package/modules/use-cases/test-module-auth.js +3 -9
  60. package/package.json +5 -6
  61. package/prisma-mongodb/schema.prisma +0 -47
  62. package/prisma-postgresql/schema.prisma +0 -44
  63. package/types/index.d.ts +0 -1
  64. package/types/modules/index.d.ts +0 -87
  65. package/user/repositories/user-repository-documentdb.js +2 -27
  66. package/user/repositories/user-repository-interface.js +0 -18
  67. package/user/repositories/user-repository-mongo.js +0 -24
  68. package/user/repositories/user-repository-postgres.js +0 -18
  69. package/user/use-cases/authenticate-user.js +1 -7
  70. package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
  71. package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
  72. package/user/user.js +1 -64
  73. package/database/organization-where.js +0 -18
  74. package/database/unique-violation.js +0 -25
  75. package/integrations/repositories/integration-not-found.js +0 -14
  76. package/integrations/use-cases/resolve-integration-ownership.js +0 -177
  77. package/modules/entity-scope.js +0 -15
  78. package/modules/scope-config.js +0 -192
  79. package/modules/scope-policy.js +0 -112
  80. package/modules/scope-resolution.js +0 -288
  81. package/modules/scope-visibility.js +0 -239
  82. package/modules/tests/doubles/ownership-matching.js +0 -18
  83. package/modules/use-cases/authorize-entity-for-user.js +0 -61
  84. package/modules/use-cases/create-entity-from-credential.js +0 -113
  85. package/modules/use-cases/manage-access.js +0 -21
  86. package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
  87. package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
  88. package/types/user/index.d.ts +0 -134
  89. package/user/adopter-jwt-config.js +0 -177
  90. package/user/adopter-jwt-errors.js +0 -59
  91. package/user/adopter-token-verifier.js +0 -122
  92. package/user/app-user-helpers.js +0 -97
  93. package/user/create-user-authentication.js +0 -64
  94. package/user/membership.js +0 -51
  95. package/user/repositories/organization-membership-record.js +0 -19
  96. package/user/repositories/organization-membership-repository-documentdb.js +0 -106
  97. package/user/repositories/organization-membership-repository-factory.js +0 -42
  98. package/user/repositories/organization-membership-repository-interface.js +0 -57
  99. package/user/repositories/organization-membership-repository-mongo.js +0 -13
  100. package/user/repositories/organization-membership-repository-postgres.js +0 -29
  101. package/user/repositories/organization-membership-repository-prisma.js +0 -81
  102. package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
  103. package/user/use-cases/ensure-organization-membership.js +0 -92
  104. package/user/use-cases/find-individual-users-by-organization.js +0 -54
@@ -51,27 +51,22 @@ const {
51
51
  const {
52
52
  createUserRepository,
53
53
  } = require('../user/repositories/user-repository-factory');
54
+ const {
55
+ GetUserFromBearerToken,
56
+ } = require('../user/use-cases/get-user-from-bearer-token');
57
+ const {
58
+ GetUserFromXFriggHeaders,
59
+ } = require('../user/use-cases/get-user-from-x-frigg-headers');
60
+ const {
61
+ GetUserFromAdopterJwt,
62
+ } = require('../user/use-cases/get-user-from-adopter-jwt');
54
63
  const {
55
64
  AuthenticateWithSharedSecret,
56
65
  } = require('../user/use-cases/authenticate-with-shared-secret');
57
66
  const { AuthenticateUser } = require('../user/use-cases/authenticate-user');
58
- const {
59
- buildUserAuthentication,
60
- } = require('../user/create-user-authentication');
61
67
  const {
62
68
  ProcessAuthorizationCallback,
63
69
  } = 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
70
 
76
71
  const log = getLogger('frigg.integrations');
77
72
 
@@ -82,20 +77,26 @@ function createIntegrationRouter() {
82
77
  integrations: integrationClasses,
83
78
  userConfig,
84
79
  moduleDefinitions,
85
- ownership,
86
- entityTypeRegistry,
87
80
  } = loadAppDefinition();
88
- // Ownership by scope (ADR-056 §3): one object every use case asks.
89
- const scopePolicy = createScopePolicy({ ownership, entityTypeRegistry });
90
81
  const moduleRepository = createModuleRepository();
91
82
  const integrationRepository = createIntegrationRepository();
92
83
  const credentialRepository = createCredentialRepository();
93
84
  const userRepository = createUserRepository();
94
- const {
95
- getUserFromBearerToken,
96
- getUserFromXFriggHeaders,
97
- getUserFromAdopterJwt,
98
- } = buildUserAuthentication({ userConfig, userRepository });
85
+
86
+ const getUserFromBearerToken = new GetUserFromBearerToken({
87
+ userRepository,
88
+ userConfig,
89
+ });
90
+
91
+ const getUserFromXFriggHeaders = new GetUserFromXFriggHeaders({
92
+ userRepository,
93
+ userConfig,
94
+ });
95
+
96
+ const getUserFromAdopterJwt = new GetUserFromAdopterJwt({
97
+ userRepository,
98
+ userConfig,
99
+ });
99
100
 
100
101
  const authenticateWithSharedSecret = new AuthenticateWithSharedSecret();
101
102
 
@@ -122,19 +123,6 @@ function createIntegrationRouter() {
122
123
  integrationClasses,
123
124
  moduleFactory,
124
125
  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
126
  });
139
127
 
140
128
  const getCredentialForUser = new GetCredentialForUser({
@@ -150,7 +138,6 @@ function createIntegrationRouter() {
150
138
  const getEntitiesForUser = new GetEntitiesForUser({
151
139
  moduleRepository,
152
140
  moduleDefinitions,
153
- scopePolicy,
154
141
  });
155
142
 
156
143
  const getIntegrationInstance = new GetIntegrationInstance({
@@ -176,55 +163,37 @@ function createIntegrationRouter() {
176
163
  const testModuleAuth = new TestModuleAuth({
177
164
  moduleRepository,
178
165
  moduleDefinitions,
179
- scopePolicy,
180
166
  });
181
167
 
182
168
  const getModule = new GetModule({
183
169
  moduleRepository,
184
170
  moduleDefinitions,
185
- scopePolicy,
186
171
  });
187
172
 
188
173
  const getEntityOptionsById = new GetEntityOptionsById({
189
174
  moduleRepository,
190
175
  moduleDefinitions,
191
- scopePolicy,
192
176
  });
193
177
 
194
178
  const refreshEntityOptions = new RefreshEntityOptions({
195
179
  moduleRepository,
196
180
  moduleDefinitions,
197
- scopePolicy,
198
181
  });
199
182
 
200
183
  const getPossibleIntegrations = new GetPossibleIntegrations({
201
184
  integrationClasses,
202
185
  });
203
186
 
204
- // The owner of what an authorization creates follows its scope (ADR-056 §3.2).
205
187
  const processAuthorizationCallback = new ProcessAuthorizationCallback({
206
188
  moduleRepository,
207
189
  credentialRepository,
208
190
  integrationRepository,
209
191
  moduleDefinitions,
210
192
  });
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,
221
- });
222
193
 
223
194
  const router = express();
224
195
 
225
196
  setIntegrationRoutes(router, authenticateUser, {
226
- resolveIntegrationOwnership,
227
- getOwnedIntegrationRecord,
228
197
  createIntegration,
229
198
  deleteIntegrationForUser,
230
199
  getIntegrationsForUser,
@@ -241,8 +210,7 @@ function createIntegrationRouter() {
241
210
  getModule,
242
211
  getEntityOptionsById,
243
212
  refreshEntityOptions,
244
- authorizeEntityForUser,
245
- createEntityFromCredential,
213
+ processAuthorizationCallback,
246
214
  });
247
215
  return router;
248
216
  }
@@ -279,8 +247,6 @@ function checkRequiredParams(params, requiredKeys) {
279
247
  */
280
248
  function setIntegrationRoutes(router, authenticateUser, useCases) {
281
249
  const {
282
- resolveIntegrationOwnership,
283
- getOwnedIntegrationRecord,
284
250
  createIntegration,
285
251
  deleteIntegrationForUser,
286
252
  getIntegrationsForUser,
@@ -289,22 +255,15 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
289
255
  updateIntegration,
290
256
  getPossibleIntegrations,
291
257
  } = 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
258
  router.route('/api/integrations').get(
301
259
  catchAsyncError(async (req, res) => {
302
260
  const user = await authenticateUser.execute(req);
303
- const integrations = await getIntegrationsForUser.execute(user);
261
+ const userId = user.getId();
262
+ const integrations = await getIntegrationsForUser.execute(userId);
304
263
  const results = {
305
264
  entities: {
306
265
  options: await getPossibleIntegrations.execute(),
307
- authorized: await getEntitiesForUser.execute(user),
266
+ authorized: await getEntitiesForUser.execute(userId),
308
267
  },
309
268
  integrations: integrations,
310
269
  };
@@ -316,6 +275,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
316
275
  router.route('/api/integrations').post(
317
276
  catchAsyncError(async (req, res) => {
318
277
  const user = await authenticateUser.execute(req);
278
+ const userId = user.getId();
319
279
  const params = checkRequiredParams(req.body, [
320
280
  'entities',
321
281
  'config',
@@ -323,17 +283,10 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
323
283
 
324
284
  get(params.config, 'type');
325
285
 
326
- const { ownerId, organizationId, adoptUnscoped } =
327
- await resolveIntegrationOwnership.execute({
328
- entityIds: params.entities,
329
- config: params.config,
330
- user,
331
- });
332
286
  const integration = await createIntegration.execute(
333
287
  params.entities,
334
- ownerId,
335
- params.config,
336
- { organizationId, adoptUnscoped }
288
+ userId,
289
+ params.config
337
290
  );
338
291
 
339
292
  res.status(201).json(integration);
@@ -343,11 +296,12 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
343
296
  router.route('/api/integrations/:integrationId').patch(
344
297
  catchAsyncError(async (req, res) => {
345
298
  const user = await authenticateUser.execute(req);
299
+ const userId = user.getId();
346
300
  const params = checkRequiredParams(req.body, ['config']);
347
301
 
348
302
  const integration = await updateIntegration.execute(
349
303
  req.params.integrationId,
350
- await ownerOf(req.params.integrationId, user, { manage: true }),
304
+ userId,
351
305
  params.config
352
306
  );
353
307
  res.json(integration);
@@ -360,7 +314,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
360
314
  const params = checkRequiredParams(req.params, ['integrationId']);
361
315
  await deleteIntegrationForUser.execute(
362
316
  params.integrationId,
363
- await ownerOf(params.integrationId, user, { manage: true })
317
+ user.getId()
364
318
  );
365
319
  res.status(204).json({});
366
320
  })
@@ -372,7 +326,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
372
326
  const params = checkRequiredParams(req.params, ['integrationId']);
373
327
  const integration = await getIntegrationInstance.execute(
374
328
  params.integrationId,
375
- await ownerOf(params.integrationId, user)
329
+ user.getId()
376
330
  );
377
331
  res.json(await integration.send('GET_CONFIG_OPTIONS'));
378
332
  })
@@ -388,7 +342,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
388
342
  ]);
389
343
  const integration = await getIntegrationInstance.execute(
390
344
  params.integrationId,
391
- await ownerOf(params.integrationId, user)
345
+ user.getId()
392
346
  );
393
347
 
394
348
  res.json(
@@ -402,7 +356,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
402
356
  const params = checkRequiredParams(req.params, ['integrationId']);
403
357
  const integration = await getIntegrationInstance.execute(
404
358
  params.integrationId,
405
- await ownerOf(params.integrationId, user)
359
+ user.getId()
406
360
  );
407
361
  res.json(await integration.send('GET_USER_ACTIONS', req.body));
408
362
  })
@@ -419,7 +373,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
419
373
  ]);
420
374
  const integration = await getIntegrationInstance.execute(
421
375
  params.integrationId,
422
- await ownerOf(params.integrationId, user)
376
+ user.getId()
423
377
  );
424
378
 
425
379
  res.json(
@@ -444,7 +398,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
444
398
  ]);
445
399
  const integration = await getIntegrationInstance.execute(
446
400
  params.integrationId,
447
- await ownerOf(params.integrationId, user)
401
+ user.getId()
448
402
  );
449
403
 
450
404
  res.json(
@@ -465,7 +419,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
465
419
  ]);
466
420
  const integration = await getIntegrationInstance.execute(
467
421
  params.integrationId,
468
- await ownerOf(params.integrationId, user)
422
+ user.getId()
469
423
  );
470
424
  res.json(await integration.send(params.actionId, req.body));
471
425
  })
@@ -482,7 +436,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
482
436
  const params = checkRequiredParams(req.params, ['integrationId']);
483
437
  const integration = await getIntegrationInstance.execute(
484
438
  params.integrationId,
485
- await ownerOf(params.integrationId, user)
439
+ user.getId()
486
440
  );
487
441
 
488
442
  // We could perhaps augment router with dynamic options? Haven't decided yet, but here may be the place
@@ -502,7 +456,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
502
456
  const params = checkRequiredParams(req.params, ['integrationId']);
503
457
  const instance = await getIntegrationInstance.execute(
504
458
  params.integrationId,
505
- await ownerOf(params.integrationId, user)
459
+ user.getId()
506
460
  );
507
461
 
508
462
  if (!instance) {
@@ -540,21 +494,16 @@ function setEntityRoutes(router, authenticateUser, useCases) {
540
494
  getModule,
541
495
  getEntityOptionsById,
542
496
  refreshEntityOptions,
543
- authorizeEntityForUser,
544
- createEntityFromCredential,
497
+ processAuthorizationCallback,
545
498
  } = useCases;
546
499
 
547
500
  router.route('/api/authorize').get(
548
501
  catchAsyncError(async (req, res) => {
549
502
  const user = await authenticateUser.execute(req);
503
+ const userId = user.getId();
550
504
  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
505
  const module = await getModuleInstanceFromType.execute(
557
- ownerId,
506
+ userId,
558
507
  params.entityType,
559
508
  { state: req.query.state }
560
509
  );
@@ -573,15 +522,11 @@ function setEntityRoutes(router, authenticateUser, useCases) {
573
522
  router.route('/api/authorize').post(
574
523
  catchAsyncError(async (req, res) => {
575
524
  const user = await authenticateUser.execute(req);
525
+ const userId = user.getId();
576
526
  const params = checkRequiredParams(req.body, [
577
527
  'entityType',
578
528
  'data',
579
529
  ]);
580
- const ownership = authorizeEntityForUser.resolveOwnership({
581
- user,
582
- entityType: params.entityType,
583
- });
584
- const userId = ownership.ownerId;
585
530
 
586
531
  const dataKeys =
587
532
  params.data && typeof params.data === 'object'
@@ -593,13 +538,11 @@ function setEntityRoutes(router, authenticateUser, useCases) {
593
538
  dataKeys,
594
539
  });
595
540
 
596
- const { result: entityDetails } =
597
- await authorizeEntityForUser.execute({
598
- user,
599
- entityType: params.entityType,
600
- data: params.data,
601
- ownership,
602
- });
541
+ const entityDetails = await processAuthorizationCallback.execute(
542
+ userId,
543
+ params.entityType,
544
+ params.data
545
+ );
603
546
 
604
547
  log.info('Entity authorized', {
605
548
  eventName: 'frigg.integrations.authorized',
@@ -616,20 +559,35 @@ function setEntityRoutes(router, authenticateUser, useCases) {
616
559
  router.route('/api/entity').post(
617
560
  catchAsyncError(async (req, res) => {
618
561
  const user = await authenticateUser.execute(req);
562
+ const userId = user.getId();
619
563
  const params = checkRequiredParams(req.body, [
620
564
  'entityType',
621
565
  'data',
622
566
  ]);
623
567
  checkRequiredParams(req.body.data, ['credential_id']);
624
568
 
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
- })
569
+ // May want to pass along the user ID as well so credential ID's can't be fished???
570
+ const credential = await getCredentialForUser.execute(
571
+ params.data.credential_id,
572
+ userId
573
+ );
574
+
575
+ if (!credential) {
576
+ throw Boom.badRequest('Invalid credential ID');
577
+ }
578
+
579
+ const module = await getModuleInstanceFromType.execute(
580
+ userId,
581
+ params.entityType
582
+ );
583
+ const entityDetails = await module.getEntityDetails(
584
+ module.api,
585
+ null,
586
+ null,
587
+ userId
632
588
  );
589
+
590
+ res.json(await module.findOrCreateEntity(entityDetails));
633
591
  })
634
592
  );
635
593
 
@@ -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