@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
@@ -2,17 +2,9 @@
2
2
  const {
3
3
  mapIntegrationClassToIntegrationDTO,
4
4
  } = require('../utils/map-integration-dto');
5
- const {
6
- describeRecord,
7
- visibilityClauses,
8
- matchesListFilters,
9
- } = require('../../modules/scope-visibility');
10
- const { DEFAULT_SCOPE_POLICY } = require('../../modules/scope-policy');
11
5
 
12
6
  /**
13
- * Use case for retrieving the integrations a caller may see: the ones they own
14
- * or their active organization owns, created in that organization (ADR-056
15
- * §3.6), each with `tenancy` ({scope, owner, organizationId, access}).
7
+ * Use case for retrieving all integrations for a specific user.
16
8
  * @class GetIntegrationsForUser
17
9
  */
18
10
  class GetIntegrationsForUser {
@@ -23,16 +15,13 @@ class GetIntegrationsForUser {
23
15
  * @param {Array<import('../integration').Integration>} params.integrationClasses - Array of available integration classes.
24
16
  * @param {import('../../modules/module-factory').ModuleFactory} params.moduleFactory - Service for module instantiation and management.
25
17
  * @param {import('../../modules/repositories/module-repository-interface').ModuleRepositoryInterface} params.moduleRepository - Repository for module and entity data operations.
26
- * @param {Object} [params.scopePolicy] - from createScopePolicy
27
18
  */
28
19
  constructor({
29
20
  integrationRepository,
30
21
  integrationClasses,
31
22
  moduleFactory,
32
23
  moduleRepository,
33
- scopePolicy,
34
24
  }) {
35
- this.scopePolicy = scopePolicy || DEFAULT_SCOPE_POLICY;
36
25
  /**
37
26
  * @type {import('../repositories/integration-repository-interface').IntegrationRepositoryInterface}
38
27
  */
@@ -43,86 +32,57 @@ class GetIntegrationsForUser {
43
32
  }
44
33
 
45
34
  /**
35
+ * Executes the retrieval of all integrations for a user.
46
36
  * @async
47
- * @param {Object} user - authenticated User
48
- * @param {{scope?: string, owner?: string}} [filters] - `?scope=` and `?owner=`
49
- * @returns {Promise<Object[]>} Array of integration DTOs.
37
+ * @param {string} userId - ID of the user whose integrations to retrieve.
38
+ * @returns {Promise<Object[]>} Array of integration DTOs for the specified user.
50
39
  */
51
- async execute(user, filters = {}) {
52
- const ctx = this.scopePolicy.accessContext(user);
53
- const records = await this.integrationRepository.findIntegrationsByOwnership(
54
- visibilityClauses(ctx, 'integration')
55
- );
40
+ async execute(userId) {
41
+ const integrationRecords =
42
+ await this.integrationRepository.findIntegrationsByUserId(userId);
56
43
 
57
44
  const integrations = [];
58
- for (const record of records) {
59
- // The query is the filter; the same rule again means a repository
60
- // that returns too much cannot widen the list.
61
- const tenancy = describeRecord(record, ctx, 'integration');
62
- if (!tenancy || !matchesListFilters(tenancy, filters)) continue;
63
- integrations.push({ ...(await this.toDto(record)), tenancy });
64
- }
65
- return integrations;
66
- }
67
45
 
68
- /** Hydrates one stored integration record into its DTO. */
69
- async toDto(integrationRecord) {
70
- const entities = await this.moduleRepository.findEntitiesByIds(
71
- integrationRecord.entitiesIds
72
- );
73
-
74
- const integrationClass = this.integrationClasses.find(
75
- (integrationClass) =>
76
- integrationClass.Definition.name ===
77
- integrationRecord.config.type
78
- );
46
+ for (const integrationRecord of integrationRecords) {
47
+ const entities = await this.moduleRepository.findEntitiesByIds(
48
+ integrationRecord.entitiesIds
49
+ );
79
50
 
80
- const modules = [];
81
- for (const entity of entities) {
82
- const moduleInstance = await this.moduleFactory.getModuleInstance(
83
- entity.id,
84
- integrationRecord.userId
51
+ const integrationClass = this.integrationClasses.find(
52
+ (integrationClass) =>
53
+ integrationClass.Definition.name ===
54
+ integrationRecord.config.type
85
55
  );
86
- modules.push(moduleInstance);
87
- }
88
56
 
89
- return mapIntegrationClassToIntegrationDTO({
90
- id: integrationRecord.id,
91
- userId: integrationRecord.userId,
92
- entities: entities,
93
- config: integrationRecord.config,
94
- status: integrationRecord.status,
95
- version: integrationRecord.version,
96
- messages: integrationRecord.messages || { errors: [], warnings: [] },
97
- modules,
98
- options: integrationClass.getOptionDetails(),
99
- });
100
- }
101
- }
57
+ const modules = [];
58
+ for (const entity of entities) {
59
+ const moduleInstance =
60
+ await this.moduleFactory.getModuleInstance(
61
+ entity.id,
62
+ integrationRecord.userId
63
+ );
64
+ modules.push(moduleInstance);
65
+ }
102
66
 
103
- /**
104
- * Every integration one user id owns, with no organization rules: the lookup
105
- * behind the app-level `friggCommands.findIntegrationsByUserId`, which has a
106
- * user id and no request.
107
- */
108
- class GetIntegrationsByUserId {
109
- /** @param {ConstructorParameters<typeof GetIntegrationsForUser>[0]} params */
110
- constructor(params) {
111
- this.integrationRepository = params.integrationRepository;
112
- this.hydrator = new GetIntegrationsForUser(params);
113
- }
67
+ const integrationData = {
68
+ id: integrationRecord.id,
69
+ userId: integrationRecord.userId,
70
+ entities: entities,
71
+ config: integrationRecord.config,
72
+ status: integrationRecord.status,
73
+ version: integrationRecord.version,
74
+ messages: integrationRecord.messages || { errors: [], warnings: [] },
75
+ modules,
76
+ options: integrationClass.getOptionDetails(),
77
+ };
114
78
 
115
- /** @param {string} userId */
116
- async execute(userId) {
117
- const records = await this.integrationRepository.findIntegrationsByUserId(
118
- userId
119
- );
120
- const integrations = [];
121
- for (const record of records) {
122
- integrations.push(await this.hydrator.toDto(record));
79
+ integrations.push(
80
+ mapIntegrationClassToIntegrationDTO(integrationData)
81
+ );
123
82
  }
83
+
124
84
  return integrations;
125
85
  }
126
86
  }
127
87
 
128
- module.exports = { GetIntegrationsForUser, GetIntegrationsByUserId };
88
+ module.exports = { GetIntegrationsForUser };
@@ -1,7 +1,4 @@
1
- const {
2
- GetIntegrationsForUser,
3
- GetIntegrationsByUserId,
4
- } = require('./get-integrations-for-user');
1
+ const { GetIntegrationsForUser } = require('./get-integrations-for-user');
5
2
  const { DeleteIntegrationForUser } = require('./delete-integration-for-user');
6
3
  const { CreateIntegration } = require('./create-integration');
7
4
  const { GetIntegration } = require('./get-integration');
@@ -9,11 +6,9 @@ const { CreateProcess } = require('./create-process');
9
6
  const { UpdateProcessState } = require('./update-process-state');
10
7
  const { UpdateProcessMetrics } = require('./update-process-metrics');
11
8
  const { GetProcess } = require('./get-process');
12
- const { DispatchOngoingSyncs } = require('./dispatch-ongoing-syncs');
13
9
 
14
10
  module.exports = {
15
11
  GetIntegrationsForUser,
16
- GetIntegrationsByUserId,
17
12
  DeleteIntegrationForUser,
18
13
  CreateIntegration,
19
14
  GetIntegration,
@@ -21,5 +16,4 @@ module.exports = {
21
16
  UpdateProcessState,
22
17
  UpdateProcessMetrics,
23
18
  GetProcess,
24
- DispatchOngoingSyncs,
25
19
  };
@@ -19,48 +19,19 @@ function mapIntegrationClassToIntegrationDTO(integration) {
19
19
  };
20
20
  }
21
21
 
22
- let deprecationLogged = false;
23
22
 
24
- /**
25
- * @deprecated Since ADR-059. Read `entityTypeRegistry` / `moduleDefinitions`
26
- * from `loadAppDefinition()`, or call `getEntityTypeRegistry(appDefinition)`
27
- * and read each entry's `definition`.
28
- *
29
- * Kept as a wrapper over the entity type registry so callers that imported it
30
- * keep working. It returns the registry's definitions, so it follows the
31
- * registry's rules: one definition per entity type name (the first wins when
32
- * two integrations bind different definitions under one name, as
33
- * ModuleFactory already picked), and, when `entities` is passed, registry-only
34
- * types are included and conflicts throw `EntityRegistryError`.
35
- *
36
- * @param {Array<Function>} integrationClasses - integration classes
37
- * @param {Object} [entities] - `appDefinition.entities` (ADR-059)
38
- * @returns {Array<Object>} API module definitions
39
- */
40
- function getModulesDefinitionFromIntegrationClasses(
41
- integrationClasses,
42
- entities
43
- ) {
44
- // Required here, not at the top: modules/ must not load at require time
45
- // of every integration use case that only wants the DTO mapper.
46
- const {
47
- getEntityTypeRegistry,
48
- getEntityTypeDefinitions,
49
- } = require('../../modules/entity-type-registry');
50
- if (!deprecationLogged) {
51
- deprecationLogged = true;
52
- const { getLogger } = require('../../logs');
53
- getLogger('frigg.integrations').warn(
54
- 'getModulesDefinitionFromIntegrationClasses is deprecated; use getEntityTypeRegistry (ADR-059)',
55
- { eventName: 'frigg.integrations.deprecated_module_definitions' }
56
- );
57
- }
58
- return getEntityTypeDefinitions(
59
- getEntityTypeRegistry({ integrations: integrationClasses, entities })
60
- );
61
- }
62
-
63
- module.exports = {
64
- mapIntegrationClassToIntegrationDTO,
65
- getModulesDefinitionFromIntegrationClasses,
23
+ const getModulesDefinitionFromIntegrationClasses = (integrationClasses) => {
24
+ return [
25
+ ...new Set(
26
+ integrationClasses
27
+ .map((integration) =>
28
+ Object.values(integration.Definition.modules).map(
29
+ (module) => module.definition
30
+ )
31
+ )
32
+ .flat()
33
+ ),
34
+ ];
66
35
  };
36
+
37
+ module.exports = { mapIntegrationClassToIntegrationDTO, getModulesDefinitionFromIntegrationClasses };
package/modules/index.js CHANGED
@@ -4,15 +4,6 @@ const { OAuth2Requester } = require('./requester/oauth-2');
4
4
  const { Requester } = require('./requester/requester');
5
5
  const { ModuleConstants } = require('./ModuleConstants');
6
6
  const { ModuleFactory } = require('./module-factory');
7
- const {
8
- getEntityTypeRegistry,
9
- EntityRegistryError,
10
- } = require('./entity-type-registry');
11
- const {
12
- resolveScope,
13
- listBindingScopes,
14
- OwnershipConfigError,
15
- } = require('./entity-scope');
16
7
 
17
8
  module.exports = {
18
9
  ApiKeyRequester,
@@ -21,9 +12,4 @@ module.exports = {
21
12
  Requester,
22
13
  ModuleConstants,
23
14
  ModuleFactory,
24
- getEntityTypeRegistry,
25
- EntityRegistryError,
26
- resolveScope,
27
- listBindingScopes,
28
- OwnershipConfigError,
29
15
  };
@@ -45,18 +45,6 @@ class ModuleFactory {
45
45
  );
46
46
  }
47
47
 
48
- // definition.env may be an async function (e.g. the db-credentials
49
- // extension's bootstrap loads OAuth app credentials from the
50
- // database); resolve it first. A static env keeps the plain
51
- // constructor, exactly as before.
52
- if (typeof moduleDefinition.env === 'function') {
53
- return await Module.create({
54
- userId,
55
- entity,
56
- definition: moduleDefinition,
57
- });
58
- }
59
-
60
48
  return new Module({
61
49
  userId,
62
50
  entity,
package/modules/module.js CHANGED
@@ -21,17 +21,8 @@ class Module extends Delegate {
21
21
  * @param {string} params.userId The user id
22
22
  * @param {Object} params.entity The entity record from the database
23
23
  * @param {string} [params.state] Optional OAuth state value forwarded to the API client (round-trips through the OAuth provider).
24
- * @param {Object} [params.resolvedEnv] definition.env as Module.create() resolved it (may be undefined).
25
- * @param {boolean} [params.envResolved=false] true when resolvedEnv carries the resolved env, even an undefined one; otherwise the static definition.env is used.
26
24
  */
27
- constructor({
28
- definition,
29
- userId = null,
30
- entity: entityObj = null,
31
- state = null,
32
- resolvedEnv,
33
- envResolved = false,
34
- }) {
25
+ constructor({ definition, userId = null, entity: entityObj = null, state = null }) {
35
26
  super({ definition, userId, entity: entityObj });
36
27
 
37
28
  this.validateDefinition(definition);
@@ -63,23 +54,8 @@ class Module extends Delegate {
63
54
 
64
55
  Object.assign(this, this.definition.requiredAuthMethods);
65
56
 
66
- // A pre-resolved env (Module.create()) supports definition.env as an
67
- // async function, e.g. OAuth app credentials loaded from the database
68
- // by the db-credentials extension; otherwise the static object.
69
- // "Resolved" is an explicit flag, not a non-null value: a function env
70
- // may legitimately resolve to undefined (no static env, no DB row),
71
- // and falling back to definition.env would then read the function.
72
- const envValues = envResolved ? resolvedEnv : this.definition.env;
73
- if (typeof envValues === 'function') {
74
- // Spreading a function yields no keys, so the API client would
75
- // silently get no client_id / client_secret.
76
- throw new TypeError(
77
- `Module ${this.name}: definition.env is a function; build the module with await Module.create(...)`
78
- );
79
- }
80
-
81
57
  const apiParams = {
82
- ...envValues,
58
+ ...this.definition.env,
83
59
  delegate: this,
84
60
  logger: this.logger,
85
61
  ...(state ? { state } : {}),
@@ -91,33 +67,6 @@ class Module extends Delegate {
91
67
  this.api = new this.apiClass(apiParams);
92
68
  }
93
69
 
94
- /**
95
- * Resolves definition.env, supporting both a static object and a
96
- * (possibly async) function.
97
- *
98
- * @param {Object} definition - Module definition
99
- * @returns {Promise<Object|undefined>} Resolved env values
100
- */
101
- static async resolveEnv(definition) {
102
- if (typeof definition.env === 'function') {
103
- return await definition.env();
104
- }
105
- return definition.env;
106
- }
107
-
108
- /**
109
- * Async factory that resolves definition.env first, so a module whose
110
- * env is a function gets its values. Prefer it over `new Module(...)`
111
- * wherever the call site can await.
112
- *
113
- * @param {Object} params - same as the constructor, minus resolvedEnv
114
- * @returns {Promise<Module>}
115
- */
116
- static async create({ definition, userId = null, entity = null, state = null }) {
117
- const resolvedEnv = await Module.resolveEnv(definition);
118
- return new Module({ definition, userId, entity, state, resolvedEnv, envResolved: true });
119
- }
120
-
121
70
  getName() {
122
71
  return this.name;
123
72
  }
@@ -3,14 +3,12 @@ const {
3
3
  toObjectId,
4
4
  fromObjectId,
5
5
  findMany,
6
- findManyDrained,
7
6
  findOne,
8
7
  insertOne,
9
8
  updateOne,
10
9
  deleteOne,
11
10
  } = require('../../database/documentdb-utils');
12
11
  const { ModuleRepositoryInterface } = require('./module-repository-interface');
13
- const { entityNotFoundError } = require('./entity-not-found');
14
12
  const { DocumentDBEncryptionService } = require('../../database/documentdb-encryption-service');
15
13
 
16
14
  /**
@@ -35,11 +33,11 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
35
33
  async findEntityById(entityId) {
36
34
  const objectId = toObjectId(entityId);
37
35
  if (!objectId) {
38
- throw entityNotFoundError(entityId);
36
+ throw new Error(`Entity ${entityId} not found`);
39
37
  }
40
38
  const doc = await findOne(this.prisma, 'Entity', { _id: objectId });
41
39
  if (!doc) {
42
- throw entityNotFoundError(entityId);
40
+ throw new Error(`Entity ${entityId} not found`);
43
41
  }
44
42
  const credential = await this._fetchCredential(doc.credentialId);
45
43
  return this._mapEntity(doc, credential);
@@ -78,29 +76,6 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
78
76
  return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
79
77
  }
80
78
 
81
- /**
82
- * Find entities matching any of the owner/organization pairs, in one query.
83
- * `organizationId: null` matches rows with no organization (a raw MongoDB
84
- * `null` also matches a missing field). The caller (a use case) decides
85
- * which pairs; this only runs them.
86
- *
87
- * @param {Array<{userId: string, organizationId: (string|null)}>} clauses
88
- * @returns {Promise<Array>}
89
- */
90
- async findEntitiesByOwnership(clauses) {
91
- if (!Array.isArray(clauses) || clauses.length === 0) return [];
92
- // Drained: a list can hold more than the first cursor batch (~101).
93
- const docs = await findManyDrained(this.prisma, 'Entity', {
94
- $or: clauses.map(({ userId, organizationId }) => ({
95
- userId: toObjectId(userId),
96
- organizationId:
97
- organizationId === null ? null : toObjectId(organizationId),
98
- })),
99
- });
100
- const credentialMap = await this._fetchCredentialsBulk(docs.map((doc) => doc.credentialId));
101
- return docs.map((doc) => this._mapEntity(doc, credentialMap.get(fromObjectId(doc.credentialId)) || null));
102
- }
103
-
104
79
  async unsetCredential(entityId) {
105
80
  const objectId = toObjectId(entityId);
106
81
  if (!objectId) return false;
@@ -140,14 +115,7 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
140
115
  );
141
116
  }
142
117
 
143
- /**
144
- * @param {Object} entityData
145
- * @param {{organizationId?: (string|null)}} [tenancy] - the organization the entity
146
- * belongs to (ADR-056 §3.6). A separate argument, not a field of `entityData`,
147
- * because `entityData` carries provider fields and one named `organizationId`
148
- * must not be taken for ours.
149
- */
150
- async createEntity(entityData, tenancy = {}) {
118
+ async createEntity(entityData) {
151
119
  const {
152
120
  user,
153
121
  userId,
@@ -165,7 +133,6 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
165
133
  name: name ?? null,
166
134
  moduleName: moduleName ?? null,
167
135
  externalId: externalId ?? null,
168
- organizationId: toObjectId(tenancy.organizationId) || null,
169
136
  data: dynamicData,
170
137
  };
171
138
  const insertedId = await insertOne(this.prisma, 'Entity', document);
@@ -280,9 +247,8 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
280
247
  const objectIds = ids.map(id => toObjectId(id)).filter(Boolean);
281
248
  if (objectIds.length === 0) return new Map();
282
249
 
283
- // Raw read to bypass the Prisma encryption extension. Drained:
284
- // more ids than the first cursor batch must all come back.
285
- const rawCredentials = await findManyDrained(this.prisma, 'Credential', {
250
+ // Use raw findMany to bypass Prisma encryption extension
251
+ const rawCredentials = await findMany(this.prisma, 'Credential', {
286
252
  _id: { $in: objectIds }
287
253
  });
288
254
 
@@ -363,30 +329,19 @@ class ModuleRepositoryDocumentDB extends ModuleRepositoryInterface {
363
329
  if (filter.name) query.name = filter.name;
364
330
  if (filter.moduleName) query.moduleName = filter.moduleName;
365
331
  if (filter.externalId) query.externalId = filter.externalId;
366
- // `null` means "no organization"; absent means "any". A raw MongoDB
367
- // `{ field: null }` matches both a null value and a missing field.
368
- if (filter.organizationId !== undefined) {
369
- query.organizationId =
370
- filter.organizationId === null
371
- ? null
372
- : toObjectId(filter.organizationId);
373
- }
374
332
  return query;
375
333
  }
376
334
 
377
335
  _mapEntity(doc, credential) {
378
336
  const dynamicData = doc?.data || {};
379
337
  return {
380
- // First, so no stored provider field can replace a column below
381
- // (identity, owner or organization decide who sees the entity).
382
- ...dynamicData,
383
338
  id: fromObjectId(doc?._id),
384
339
  credential,
385
340
  userId: fromObjectId(doc?.userId),
386
341
  name: doc?.name ?? null,
387
342
  externalId: doc?.externalId ?? null,
388
343
  moduleName: doc?.moduleName ?? null,
389
- organizationId: fromObjectId(doc?.organizationId) ?? null,
344
+ ...dynamicData,
390
345
  };
391
346
  }
392
347
  }
@@ -67,21 +67,6 @@ class ModuleRepositoryInterface {
67
67
  );
68
68
  }
69
69
 
70
- /**
71
- * Find entities matching any of the owner/organization pairs, in one query
72
- * (ADR-056 §3.6). `organizationId: null` matches rows with no organization.
73
- * Which pairs is decided by the caller (modules/entity-scope.js), not here.
74
- *
75
- * @param {Array<{userId: string|number, organizationId: (string|number|null)}>} clauses
76
- * @returns {Promise<Array>} Array of entity objects
77
- * @abstract
78
- */
79
- async findEntitiesByOwnership(clauses) {
80
- throw new Error(
81
- 'Method findEntitiesByOwnership must be implemented by subclass'
82
- );
83
- }
84
-
85
70
  /**
86
71
  * Unset credential from entity
87
72
  *
@@ -125,13 +110,11 @@ class ModuleRepositoryInterface {
125
110
  /**
126
111
  * Create a new entity
127
112
  *
128
- * @param {Object} entityData - Entity data (provider fields included)
129
- * @param {{organizationId?: (string|number|null)}} [tenancy] - the organization
130
- * the entity belongs to (ADR-056 §3.6), kept apart from `entityData`
113
+ * @param {Object} entityData - Entity data
131
114
  * @returns {Promise<Object>} Created entity object
132
115
  * @abstract
133
116
  */
134
- async createEntity(entityData, tenancy) {
117
+ async createEntity(entityData) {
135
118
  throw new Error('Method createEntity must be implemented by subclass');
136
119
  }
137
120