@friggframework/core 2.0.0--canary.686.df38e8e.0 → 2.0.0--canary.710.9045bbc.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 (217) hide show
  1. package/CHANGELOG.md +0 -16
  2. package/CLAUDE.md +41 -29
  3. package/README.md +0 -105
  4. package/application/commands/README.md +17 -11
  5. package/application/commands/entity-commands.js +18 -60
  6. package/application/commands/integration-commands.js +73 -20
  7. package/application/commands/scheduler-commands.js +7 -11
  8. package/application/commands/user-commands.js +5 -17
  9. package/application/index.js +2 -6
  10. package/core/Worker.js +7 -31
  11. package/core/create-handler.js +0 -9
  12. package/credential/repositories/credential-repository-documentdb.js +0 -34
  13. package/credential/repositories/credential-repository-interface.js +0 -15
  14. package/credential/repositories/credential-repository-mongo.js +0 -23
  15. package/credential/repositories/credential-repository-postgres.js +0 -28
  16. package/database/config.js +24 -48
  17. package/database/documentdb-encryption-service.js +22 -9
  18. package/database/documentdb-utils.js +0 -2
  19. package/database/encryption/README.md +17 -81
  20. package/database/encryption/documentdb-encryption-service.md +1 -78
  21. package/database/encryption/encryption-schema-registry.js +46 -123
  22. package/database/encryption/field-encryption-service.js +5 -69
  23. package/database/encryption/integration-mapping-encryption.js +1 -1
  24. package/database/prisma.js +38 -15
  25. package/database/use-cases/check-encryption-health-use-case.js +52 -43
  26. package/errors/index.js +4 -0
  27. package/errors/mapping-already-exists-error.js +14 -0
  28. package/generated/prisma-mongodb/edge.js +4 -43
  29. package/generated/prisma-mongodb/index-browser.js +1 -40
  30. package/generated/prisma-mongodb/index.d.ts +111 -4739
  31. package/generated/prisma-mongodb/index.js +4 -43
  32. package/generated/prisma-mongodb/package.json +1 -1
  33. package/generated/prisma-mongodb/schema.prisma +0 -92
  34. package/generated/prisma-mongodb/wasm.js +4 -43
  35. package/generated/prisma-postgresql/edge.js +4 -43
  36. package/generated/prisma-postgresql/index-browser.js +1 -40
  37. package/generated/prisma-postgresql/index.d.ts +33 -4966
  38. package/generated/prisma-postgresql/index.js +4 -43
  39. package/generated/prisma-postgresql/package.json +1 -1
  40. package/generated/prisma-postgresql/schema.prisma +0 -87
  41. package/generated/prisma-postgresql/wasm.js +4 -43
  42. package/handlers/WEBHOOKS.md +29 -0
  43. package/handlers/app-definition-loader.js +19 -121
  44. package/handlers/app-handler-helpers.js +3 -25
  45. package/handlers/backend-utils.js +25 -31
  46. package/handlers/middleware/admin-auth.js +1 -14
  47. package/handlers/routers/auth.js +10 -46
  48. package/handlers/routers/health.js +4 -13
  49. package/handlers/routers/integration-defined-routers.js +92 -144
  50. package/handlers/routers/integration-webhook-routers.js +64 -102
  51. package/handlers/workers/integration-defined-workers.js +2 -5
  52. package/index.js +3 -65
  53. package/infrastructure/scheduler/eventbridge-scheduler-adapter.js +67 -13
  54. package/infrastructure/scheduler/index.js +6 -19
  55. package/infrastructure/scheduler/scheduler-service-factory.js +7 -55
  56. package/integrations/index.js +0 -1
  57. package/integrations/integration-base.js +29 -0
  58. package/integrations/integration-router.js +96 -131
  59. package/integrations/repositories/integration-mapping-repository-documentdb.js +50 -0
  60. package/integrations/repositories/integration-mapping-repository-interface.js +15 -0
  61. package/integrations/repositories/integration-mapping-repository-mongo.js +29 -0
  62. package/integrations/repositories/integration-mapping-repository-postgres.js +30 -0
  63. package/integrations/repositories/integration-mapping-repository.js +29 -0
  64. package/integrations/repositories/integration-repository-documentdb.js +35 -35
  65. package/integrations/repositories/integration-repository-interface.js +31 -17
  66. package/integrations/repositories/integration-repository-mongo.js +129 -60
  67. package/integrations/repositories/integration-repository-postgres.js +134 -62
  68. package/integrations/repositories/process-repository-mongo.js +1 -1
  69. package/integrations/tests/doubles/test-integration-repository.js +1 -12
  70. package/integrations/use-cases/add-entities-to-integration.js +92 -0
  71. package/integrations/use-cases/create-integration.js +75 -72
  72. package/integrations/use-cases/get-integrations-for-user.js +40 -80
  73. package/integrations/use-cases/index.js +1 -7
  74. package/integrations/use-cases/remove-entities-from-integration.js +70 -0
  75. package/integrations/utils/assert-entity-ids-input.js +42 -0
  76. package/integrations/utils/map-integration-dto.js +14 -43
  77. package/jest-setup.js +13 -2
  78. package/jest-teardown.js +5 -2
  79. package/jest.config.js +4 -0
  80. package/jest.db.config.js +23 -0
  81. package/modules/index.js +0 -14
  82. package/modules/module-factory.js +0 -12
  83. package/modules/module.js +2 -53
  84. package/modules/repositories/module-repository-documentdb.js +6 -51
  85. package/modules/repositories/module-repository-interface.js +2 -19
  86. package/modules/repositories/module-repository-mongo.js +74 -67
  87. package/modules/repositories/module-repository-postgres.js +74 -66
  88. package/modules/repositories/module-repository.js +1 -2
  89. package/modules/requester/requester.js +2 -27
  90. package/modules/use-cases/get-entities-for-user.js +13 -26
  91. package/modules/use-cases/get-entity-options-by-id.js +4 -10
  92. package/modules/use-cases/get-entity-options-by-type.js +1 -1
  93. package/modules/use-cases/get-module-instance-from-type.js +1 -1
  94. package/modules/use-cases/get-module.js +4 -10
  95. package/modules/use-cases/process-authorization-callback.js +19 -53
  96. package/modules/use-cases/refresh-entity-options.js +4 -10
  97. package/modules/use-cases/test-module-auth.js +4 -10
  98. package/modules/utils/map-module-dto.js +5 -3
  99. package/modules/utils/to-credential-id.js +14 -0
  100. package/package.json +7 -6
  101. package/prisma-mongodb/schema.prisma +0 -92
  102. package/prisma-postgresql/schema.prisma +0 -87
  103. package/queues/index.js +0 -25
  104. package/queues/queuer-util.js +6 -5
  105. package/types/index.d.ts +0 -2
  106. package/user/repositories/user-repository-documentdb.js +2 -27
  107. package/user/repositories/user-repository-interface.js +0 -18
  108. package/user/repositories/user-repository-mongo.js +0 -24
  109. package/user/repositories/user-repository-postgres.js +0 -18
  110. package/user/tests/doubles/test-user-repository.js +1 -1
  111. package/user/use-cases/authenticate-user.js +1 -7
  112. package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
  113. package/user/use-cases/get-user-from-bearer-token.js +7 -2
  114. package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
  115. package/user/user.js +1 -64
  116. package/credential/use-cases/credential-operations-for-user.js +0 -202
  117. package/credential/use-cases/reauthorize-credential-for-user.js +0 -73
  118. package/database/encryption/encryption-config.js +0 -219
  119. package/database/encryption/test-support/fake-ciphertext.js +0 -15
  120. package/database/organization-where.js +0 -18
  121. package/database/unique-violation.js +0 -25
  122. package/extensions/bootstrap-runner.js +0 -43
  123. package/extensions/extension-loader.js +0 -187
  124. package/extensions/index.js +0 -41
  125. package/extensions/initialize-app.js +0 -123
  126. package/extensions/route-mounter.js +0 -103
  127. package/extensions/schema-composer.js +0 -188
  128. package/infrastructure/scheduler/netlify-scheduler-adapter.js +0 -220
  129. package/infrastructure/scheduler/scheduled-job-repository.js +0 -118
  130. package/integrations/repositories/integration-not-found.js +0 -14
  131. package/integrations/schedule-config.js +0 -80
  132. package/integrations/use-cases/dispatch-ongoing-syncs.js +0 -100
  133. package/integrations/use-cases/integration-operations-for-user.js +0 -256
  134. package/integrations/use-cases/resolve-integration-ownership.js +0 -177
  135. package/management-api/create-management-api-router.js +0 -49
  136. package/management-api/error-response.js +0 -116
  137. package/management-api/management-api-config.js +0 -151
  138. package/management-api/meta-router.js +0 -76
  139. package/management-api/openapi/build-openapi.js +0 -144
  140. package/management-api/openapi/components.js +0 -408
  141. package/management-api/openapi/v1-operations.js +0 -83
  142. package/management-api/openapi/v2-operations.js +0 -264
  143. package/management-api/route-registry.js +0 -411
  144. package/management-api/test-support/http-client.js +0 -39
  145. package/management-api/use-cases/get-management-api-meta.js +0 -57
  146. package/management-api/v1-deprecation.js +0 -120
  147. package/management-api/v2/create-v2-router.js +0 -85
  148. package/management-api/v2/dependencies.js +0 -281
  149. package/management-api/v2/dto.js +0 -143
  150. package/management-api/v2/handlers/authorization.js +0 -94
  151. package/management-api/v2/handlers/credentials.js +0 -33
  152. package/management-api/v2/handlers/entities.js +0 -77
  153. package/management-api/v2/handlers/integrations.js +0 -128
  154. package/management-api/v2/handlers/proxy.js +0 -34
  155. package/management-api/v2/request.js +0 -85
  156. package/management-api/v2/test-support/fake-dependencies.js +0 -103
  157. package/modules/domain/authorization-session.js +0 -144
  158. package/modules/entity-scope.js +0 -15
  159. package/modules/entity-type-registry.js +0 -311
  160. package/modules/proxy/proxy-errors.js +0 -20
  161. package/modules/proxy/proxy-path.js +0 -179
  162. package/modules/proxy/proxy-policy.js +0 -248
  163. package/modules/repositories/authorization-session-repository-documentdb.js +0 -112
  164. package/modules/repositories/authorization-session-repository-factory.js +0 -31
  165. package/modules/repositories/authorization-session-repository-interface.js +0 -47
  166. package/modules/repositories/authorization-session-repository-prisma.js +0 -87
  167. package/modules/repositories/entity-not-found.js +0 -18
  168. package/modules/requester/proxy-request.js +0 -244
  169. package/modules/scope-config.js +0 -192
  170. package/modules/scope-policy.js +0 -112
  171. package/modules/scope-resolution.js +0 -288
  172. package/modules/scope-visibility.js +0 -247
  173. package/modules/tests/doubles/in-memory-authorization-session-repository.js +0 -45
  174. package/modules/tests/doubles/ownership-matching.js +0 -18
  175. package/modules/use-cases/authorize-entity-for-user.js +0 -61
  176. package/modules/use-cases/create-entity-from-credential.js +0 -113
  177. package/modules/use-cases/entity-operations-for-user.js +0 -162
  178. package/modules/use-cases/entity-types.js +0 -139
  179. package/modules/use-cases/execute-entity-proxy-request.js +0 -286
  180. package/modules/use-cases/get-authorization-requirements.js +0 -100
  181. package/modules/use-cases/get-entity-module-for-user.js +0 -113
  182. package/modules/use-cases/manage-access.js +0 -21
  183. package/modules/use-cases/multi-step-authorization.js +0 -329
  184. package/prisma-postgresql/migrations/20261003000000_add_authorization_session/migration.sql +0 -28
  185. package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
  186. package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
  187. package/prisma-postgresql/migrations/20261017000000_add_scheduled_job/migration.sql +0 -28
  188. package/providers/index.js +0 -23
  189. package/providers/resolve-provider.js +0 -93
  190. package/providers/runtime-detection.js +0 -124
  191. package/queues/providers/index.js +0 -11
  192. package/queues/providers/netlify-background-provider.js +0 -187
  193. package/queues/providers/qstash-queue-provider.js +0 -219
  194. package/queues/providers/sqs-queue-provider.js +0 -70
  195. package/queues/queue-client-interface.js +0 -55
  196. package/queues/queue-message-auth.js +0 -193
  197. package/queues/queue-provider-factory.js +0 -101
  198. package/queues/queue-provider.js +0 -65
  199. package/queues/sqs-queue-client.js +0 -81
  200. package/types/modules/index.d.ts +0 -197
  201. package/types/user/index.d.ts +0 -134
  202. package/user/adopter-jwt-config.js +0 -177
  203. package/user/adopter-jwt-errors.js +0 -59
  204. package/user/adopter-token-verifier.js +0 -122
  205. package/user/app-user-helpers.js +0 -97
  206. package/user/create-user-authentication.js +0 -64
  207. package/user/membership.js +0 -51
  208. package/user/repositories/organization-membership-record.js +0 -19
  209. package/user/repositories/organization-membership-repository-documentdb.js +0 -106
  210. package/user/repositories/organization-membership-repository-factory.js +0 -42
  211. package/user/repositories/organization-membership-repository-interface.js +0 -57
  212. package/user/repositories/organization-membership-repository-mongo.js +0 -13
  213. package/user/repositories/organization-membership-repository-postgres.js +0 -29
  214. package/user/repositories/organization-membership-repository-prisma.js +0 -81
  215. package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
  216. package/user/use-cases/ensure-organization-membership.js +0 -92
  217. package/user/use-cases/find-individual-users-by-organization.js +0 -54
@@ -1,39 +0,0 @@
1
- /**
2
- * Test helper: send one real HTTP request to an Express app on an ephemeral
3
- * port and return { status, headers, body }. Real HTTP (not a mocked req/res)
4
- * so body parsing, the error boundary and headers behave as in Lambda.
5
- */
6
- async function request(app, { method = 'GET', path, headers = {}, body, rawBody } = {}) {
7
- const server = await new Promise((resolve) => {
8
- const s = app.listen(0, '127.0.0.1', () => resolve(s));
9
- });
10
- try {
11
- const init = { method, headers: { ...headers } };
12
- if (rawBody !== undefined) {
13
- init.body = rawBody;
14
- } else if (body !== undefined) {
15
- init.body = JSON.stringify(body);
16
- init.headers['content-type'] = 'application/json';
17
- }
18
- const res = await fetch(
19
- `http://127.0.0.1:${server.address().port}${path}`,
20
- init
21
- );
22
- const text = await res.text();
23
- let parsed = text;
24
- try {
25
- parsed = text ? JSON.parse(text) : undefined;
26
- } catch {
27
- // not JSON; keep the text
28
- }
29
- return {
30
- status: res.status,
31
- headers: Object.fromEntries(res.headers.entries()),
32
- body: parsed,
33
- };
34
- } finally {
35
- await new Promise((resolve) => server.close(resolve));
36
- }
37
- }
38
-
39
- module.exports = { request };
@@ -1,57 +0,0 @@
1
- const {
2
- MANAGEMENT_API_VERSIONS,
3
- PREFERRED_API_VERSION,
4
- listV2Routes,
5
- } = require('../route-registry');
6
-
7
- /**
8
- * Builds the GET /api/meta document (ADR-053 §4): the API majors this
9
- * deployment serves, their status and OpenAPI links, and the capability flags
10
- * clients feature-detect with. Reads configuration only: no database, no
11
- * network.
12
- */
13
- class GetManagementApiMeta {
14
- /**
15
- * @param {Object} params
16
- * @param {ReturnType<import('../management-api-config').resolveManagementApiConfig>} params.config
17
- * @param {string} params.coreVersion - @friggframework/core version, admin-only.
18
- */
19
- constructor({ config, coreVersion }) {
20
- this.config = config;
21
- this.coreVersion = coreVersion;
22
- }
23
-
24
- /**
25
- * @param {Object} [options]
26
- * @param {boolean} [options.isAdmin=false] - caller presented the admin key.
27
- */
28
- execute({ isAdmin = false } = {}) {
29
- const versions = {};
30
- for (const [major, info] of Object.entries(MANAGEMENT_API_VERSIONS)) {
31
- const disabled = major === '1' && !this.config.v1;
32
- versions[major] = {
33
- ...info,
34
- ...(disabled && { status: 'disabled' }),
35
- openapi: `/api/meta/openapi/v${major}.json`,
36
- };
37
- }
38
-
39
- // Capabilities come from the routes the app actually serves, so a flag
40
- // can never advertise a route that is not mounted.
41
- const capabilities = [
42
- ...new Set(
43
- listV2Routes({ proxy: this.config.proxy.enable })
44
- .map((r) => r.capability)
45
- .filter(Boolean)
46
- ),
47
- ].sort();
48
-
49
- return {
50
- api: { versions, preferred: PREFERRED_API_VERSION },
51
- capabilities,
52
- ...(isAdmin && { frigg: { coreVersion: this.coreVersion } }),
53
- };
54
- }
55
- }
56
-
57
- module.exports = { GetManagementApiMeta };
@@ -1,120 +0,0 @@
1
- const { Router } = require('express');
2
- const Boom = require('@hapi/boom');
3
- const { getLogger } = require('../logs');
4
- const { getTelemetry } = require('../telemetry/telemetry-runtime');
5
- const {
6
- MANAGEMENT_API_VERSIONS,
7
- V1_MIGRATION_DOCS_URL,
8
- V1_ROUTES,
9
- } = require('./route-registry');
10
-
11
- const log = getLogger('frigg.api');
12
-
13
- const V1_LINK_HEADER = `<${V1_MIGRATION_DOCS_URL}>; rel="deprecation"; type="text/html"`;
14
-
15
- /**
16
- * RFC 9745 `Deprecation` value: an RFC 9651 structured-field date, i.e. `@`
17
- * followed by seconds since the epoch.
18
- * @param {string} isoDate - YYYY-MM-DD
19
- */
20
- function deprecationHeaderValue(isoDate) {
21
- return `@${Math.floor(Date.parse(`${isoDate}T00:00:00Z`) / 1000)}`;
22
- }
23
-
24
- const registerOn = (router, { method, path }, handler) => {
25
- const verb = method === 'ANY' ? 'all' : method.toLowerCase();
26
- router[verb](path, handler);
27
- };
28
-
29
- function setDeprecationHeaders(res) {
30
- const { deprecatedAt, sunset } = MANAGEMENT_API_VERSIONS['1'];
31
- res.set('Deprecation', deprecationHeaderValue(deprecatedAt));
32
- if (sunset) {
33
- // RFC 8594: an HTTP-date.
34
- res.set('Sunset', new Date(`${sunset}T00:00:00Z`).toUTCString());
35
- }
36
- res.append('Link', V1_LINK_HEADER);
37
- }
38
-
39
- /**
40
- * Marks every v1 response as deprecated and records the call (ADR-053 §6):
41
- * `Deprecation` + `Link: rel="deprecation"` headers, one ADR-048 log record
42
- * and one ADR-011 counter increment per call. Mounted ahead of the frozen v1
43
- * router; it calls `next()` so the v1 handler answers unchanged.
44
- *
45
- * @param {Object} [params]
46
- * @param {Object} [params.telemetry] - defaults to the process telemetry.
47
- */
48
- function createV1DeprecationRouter({ telemetry } = {}) {
49
- const router = Router();
50
-
51
- for (const route of V1_ROUTES) {
52
- registerOn(router, route, (req, res, next) => {
53
- // One signal per request, even if two v1 patterns match it.
54
- if (res.locals.friggV1Deprecated) return next();
55
- res.locals.friggV1Deprecated = true;
56
- setDeprecationHeaders(res);
57
- const method = req.method;
58
- log.info('Deprecated Management API v1 route called', {
59
- eventName: 'frigg.api.deprecated_route',
60
- route: route.path,
61
- method,
62
- client: req.get('Frigg-Client'),
63
- });
64
- try {
65
- (telemetry || getTelemetry()).count('frigg.api.v1.requests', 1, {
66
- route: route.path,
67
- method,
68
- });
69
- } catch {
70
- // Telemetry must never break a request.
71
- }
72
- next();
73
- });
74
- }
75
-
76
- return router;
77
- }
78
-
79
- /**
80
- * Answers the v1 routes with 410 Gone when the app sets
81
- * `managementApi.v1: false`. Only the registry's v1 routes are claimed, so
82
- * the OAuth redirect and adopter routes keep working.
83
- */
84
- function createV1DisabledRouter() {
85
- const router = Router();
86
- for (const route of V1_ROUTES) {
87
- registerOn(router, route, (_req, res, next) => {
88
- res.append('Link', V1_LINK_HEADER);
89
- next(
90
- Boom.resourceGone(
91
- 'Management API v1 is disabled for this app. Use /api/v2; see the migration guide.',
92
- {
93
- code: 'API_VERSION_DISABLED',
94
- details: { migrationGuide: V1_MIGRATION_DOCS_URL },
95
- }
96
- )
97
- );
98
- });
99
- }
100
- // A disabled v1 answers in the v2 error shape: there is no v1 contract
101
- // left to honour, and the body should point at the replacement.
102
- router.use((err, req, res, next) => {
103
- if (err?.data?.code !== 'API_VERSION_DISABLED') return next(err);
104
- res.status(410).json({
105
- error: {
106
- code: 'API_VERSION_DISABLED',
107
- message: err.message,
108
- details: err.data.details,
109
- },
110
- });
111
- });
112
- return router;
113
- }
114
-
115
- module.exports = {
116
- createV1DeprecationRouter,
117
- createV1DisabledRouter,
118
- deprecationHeaderValue,
119
- V1_LINK_HEADER,
120
- };
@@ -1,85 +0,0 @@
1
- const express = require('express');
2
- const Boom = require('@hapi/boom');
3
- const catchAsyncError = require('express-async-handler');
4
- const { API_VERSION_HEADER } = require('../error-response');
5
- const { listV2Routes } = require('../route-registry');
6
- const { resolveManagementApiConfig } = require('../management-api-config');
7
- const { createIntegrationHandlers } = require('./handlers/integrations');
8
- const { createEntityHandlers } = require('./handlers/entities');
9
- const { createCredentialHandlers } = require('./handlers/credentials');
10
- const { createAuthorizationHandlers } = require('./handlers/authorization');
11
- const { createProxyHandlers } = require('./handlers/proxy');
12
-
13
- /** Every v2 handler, keyed by the registry's operationId. */
14
- function createV2Handlers(dependencies) {
15
- return {
16
- ...createIntegrationHandlers(dependencies),
17
- ...createEntityHandlers(dependencies),
18
- ...createCredentialHandlers(dependencies),
19
- ...createAuthorizationHandlers(dependencies),
20
- ...(dependencies.executeEntityProxyRequest
21
- ? createProxyHandlers(dependencies)
22
- : {}),
23
- };
24
- }
25
-
26
- /**
27
- * Management API v2 router (ADR-053). Routes come from the registry, in
28
- * registry order; each authenticates the caller with the same
29
- * AuthenticateUser as v1 (bearer token, x-frigg headers, adopter JWT) and then
30
- * runs the handler for its operationId. Every response under /api/v2 carries
31
- * `Frigg-API-Version: 2`; an unknown /api/v2 path is a v2 404.
32
- *
33
- * @param {Object} [params]
34
- * @param {Object} [params.appDefinition]
35
- * @param {Object} [params.config] - resolveManagementApiConfig() output.
36
- * @param {Object} [params.dependencies] - use cases and authenticateUser;
37
- * built from the app definition when omitted.
38
- */
39
- function createManagementApiV2Router({
40
- appDefinition = {},
41
- config,
42
- dependencies,
43
- } = {}) {
44
- const resolvedConfig =
45
- config || resolveManagementApiConfig(appDefinition.managementApi);
46
- const deps =
47
- dependencies ||
48
- require('./dependencies').buildV2Dependencies({
49
- appDefinition,
50
- config: resolvedConfig,
51
- });
52
- const handlers = createV2Handlers(deps);
53
-
54
- const router = express.Router();
55
-
56
- router.use('/api/v2', (_req, res, next) => {
57
- res.set(API_VERSION_HEADER, '2');
58
- next();
59
- });
60
-
61
- for (const route of listV2Routes({ proxy: resolvedConfig.proxy.enable })) {
62
- const handler = handlers[route.operationId];
63
- if (!handler) continue;
64
- router[route.method.toLowerCase()](
65
- route.path,
66
- catchAsyncError(async (req, res) => {
67
- const user = await deps.authenticateUser.execute(req);
68
- if (!user) throw Boom.unauthorized('Authentication required');
69
- await handler(req, res, user);
70
- })
71
- );
72
- }
73
-
74
- router.use('/api/v2', (req, _res, next) => {
75
- next(
76
- Boom.notFound(
77
- `No Management API v2 route for ${req.method} ${req.baseUrl}${req.path}`
78
- )
79
- );
80
- });
81
-
82
- return router;
83
- }
84
-
85
- module.exports = { createManagementApiV2Router, createV2Handlers };
@@ -1,281 +0,0 @@
1
- /**
2
- * Wires the repositories and use cases behind Management API v2. Kept apart
3
- * from the router so tests can hand the router doubles instead.
4
- */
5
- /**
6
- * @param {Object} params
7
- * @param {Object} params.appDefinition - the loaded app definition. Its
8
- * `entityTypeRegistry` (built once by loadAppDefinition) is used.
9
- * @param {Object} params.config
10
- * @param {Map} [params.entityTypeRegistry] - overrides the registry on the
11
- * app definition. When neither exists (a raw definition in a test), it is
12
- * built here from the definition.
13
- */
14
- function buildV2Dependencies({ appDefinition, config, entityTypeRegistry }) {
15
- const {
16
- createIntegrationRepository,
17
- } = require('../../integrations/repositories/integration-repository-factory');
18
- const {
19
- createCredentialRepository,
20
- } = require('../../credential/repositories/credential-repository-factory');
21
- const {
22
- createModuleRepository,
23
- } = require('../../modules/repositories/module-repository-factory');
24
- const {
25
- createUserRepository,
26
- } = require('../../user/repositories/user-repository-factory');
27
- const { ModuleFactory } = require('../../modules/module-factory');
28
- const {
29
- getEntityTypeRegistry,
30
- getEntityTypeDefinitions,
31
- } = require('../../modules/entity-type-registry');
32
- const { createScopePolicy } = require('../../modules/scope-policy');
33
- const {
34
- AuthorizeEntityForUser,
35
- } = require('../../modules/use-cases/authorize-entity-for-user');
36
- const {
37
- ResolveIntegrationOwnership,
38
- } = require('../../integrations/use-cases/resolve-integration-ownership');
39
- const {
40
- AuthenticateWithSharedSecret,
41
- } = require('../../user/use-cases/authenticate-with-shared-secret');
42
- const { AuthenticateUser } = require('../../user/use-cases/authenticate-user');
43
- const { buildUserAuthentication } = require('../../user/create-user-authentication');
44
- const { CreateIntegration } = require('../../integrations/use-cases/create-integration');
45
- const { UpdateIntegration } = require('../../integrations/use-cases/update-integration');
46
- const {
47
- DeleteIntegrationForUser,
48
- } = require('../../integrations/use-cases/delete-integration-for-user');
49
- const {
50
- GetIntegrationsForUser,
51
- } = require('../../integrations/use-cases/get-integrations-for-user');
52
- const {
53
- GetIntegrationInstance,
54
- } = require('../../integrations/use-cases/get-integration-instance');
55
- const {
56
- GetPossibleIntegrations,
57
- } = require('../../integrations/use-cases/get-possible-integrations');
58
- const integrationOps = require('../../integrations/use-cases/integration-operations-for-user');
59
- const {
60
- GetEntityModuleForUser,
61
- } = require('../../modules/use-cases/get-entity-module-for-user');
62
- const entityOps = require('../../modules/use-cases/entity-operations-for-user');
63
- const { ListEntityTypes, GetEntityType } = require('../../modules/use-cases/entity-types');
64
- const credentialOps = require('../../credential/use-cases/credential-operations-for-user');
65
- const {
66
- GetCredentialReauthorization,
67
- ReauthorizeCredentialForUser,
68
- } = require('../../credential/use-cases/reauthorize-credential-for-user');
69
- const {
70
- GetAuthorizationStep,
71
- SubmitAuthorizationStep,
72
- } = require('../../modules/use-cases/multi-step-authorization');
73
- const {
74
- ProcessAuthorizationCallback,
75
- } = require('../../modules/use-cases/process-authorization-callback');
76
- const {
77
- ExecuteEntityProxyRequest,
78
- } = require('../../modules/use-cases/execute-entity-proxy-request');
79
- const {
80
- createAuthorizationSessionRepository,
81
- } = require('../../modules/repositories/authorization-session-repository-factory');
82
- const {
83
- GetAuthorizationRequirements,
84
- } = require('../../modules/use-cases/get-authorization-requirements');
85
-
86
- const integrationClasses = appDefinition.integrations || [];
87
- const userConfig = appDefinition.userConfig || {};
88
- // The registry holds entity types registered on the app as well as those
89
- // integrations bind (ADR-059), so v2 authorize/entities accept both.
90
- const registry =
91
- entityTypeRegistry ??
92
- appDefinition.entityTypeRegistry ??
93
- getEntityTypeRegistry(appDefinition);
94
- const moduleDefinitions = getEntityTypeDefinitions(registry);
95
- // Ownership by scope (ADR-056 §3): one object every use case asks.
96
- const scopePolicy = createScopePolicy({
97
- ownership: appDefinition.ownership,
98
- entityTypeRegistry: registry,
99
- });
100
-
101
- const moduleRepository = createModuleRepository();
102
- const integrationRepository = createIntegrationRepository();
103
- const credentialRepository = createCredentialRepository();
104
- const userRepository = createUserRepository();
105
- const authorizationSessionRepository = createAuthorizationSessionRepository();
106
-
107
- const authenticateUser = new AuthenticateUser({
108
- ...buildUserAuthentication({ userConfig, userRepository }),
109
- authenticateWithSharedSecret: new AuthenticateWithSharedSecret(),
110
- userConfig,
111
- });
112
-
113
- const moduleFactory = new ModuleFactory({ moduleRepository, moduleDefinitions });
114
- const getIntegrationInstance = new GetIntegrationInstance({
115
- integrationRepository,
116
- integrationClasses,
117
- moduleFactory,
118
- });
119
- const getEntityModuleForUser = new GetEntityModuleForUser({
120
- moduleRepository,
121
- moduleDefinitions,
122
- scopePolicy,
123
- });
124
- const getCredentialForUser = new credentialOps.GetCredentialForUserV2({
125
- credentialRepository,
126
- moduleRepository,
127
- scopePolicy,
128
- });
129
- const getAuthorizationRequirements = new GetAuthorizationRequirements({
130
- moduleDefinitions,
131
- });
132
- const getAuthorizationStep = new GetAuthorizationStep({
133
- moduleDefinitions,
134
- getAuthorizationRequirements,
135
- authorizationSessionRepository,
136
- });
137
- const submitAuthorizationStep = new SubmitAuthorizationStep({
138
- moduleDefinitions,
139
- getAuthorizationRequirements,
140
- authorizationSessionRepository,
141
- authorizeEntityForUser: new AuthorizeEntityForUser({
142
- scopePolicy,
143
- processAuthorizationCallback: new ProcessAuthorizationCallback({
144
- moduleRepository,
145
- credentialRepository,
146
- integrationRepository,
147
- moduleDefinitions,
148
- }),
149
- }),
150
- moduleRepository,
151
- credentialRepository,
152
- scopePolicy,
153
- });
154
- const getOwnedIntegrationRecord = new integrationOps.GetOwnedIntegrationRecord({
155
- integrationRepository,
156
- scopePolicy,
157
- });
158
- const getIntegrationInstanceForUser = new integrationOps.GetIntegrationInstanceForUser({
159
- getOwnedIntegrationRecord,
160
- getIntegrationInstance,
161
- });
162
-
163
- return {
164
- config,
165
- moduleDefinitions,
166
- scopePolicy,
167
- repositories: {
168
- moduleRepository,
169
- integrationRepository,
170
- credentialRepository,
171
- userRepository,
172
- authorizationSessionRepository,
173
- },
174
- authenticateUser,
175
-
176
- // Integrations
177
- getIntegrationsForUser: new GetIntegrationsForUser({
178
- integrationRepository,
179
- integrationClasses,
180
- moduleFactory,
181
- moduleRepository,
182
- scopePolicy,
183
- }),
184
- getPossibleIntegrations: new GetPossibleIntegrations({ integrationClasses }),
185
- createIntegrationForUser: new integrationOps.CreateIntegrationForUser({
186
- createIntegration: new CreateIntegration({
187
- integrationRepository,
188
- integrationClasses,
189
- moduleFactory,
190
- }),
191
- resolveIntegrationOwnership: new ResolveIntegrationOwnership({
192
- moduleRepository,
193
- integrationClasses,
194
- scopePolicy,
195
- }),
196
- integrationClasses,
197
- }),
198
- getIntegrationInstanceForUser,
199
- updateIntegrationForUser: new integrationOps.UpdateIntegrationForUser({
200
- getOwnedIntegrationRecord,
201
- updateIntegration: new UpdateIntegration({
202
- integrationRepository,
203
- integrationClasses,
204
- moduleFactory,
205
- }),
206
- }),
207
- removeIntegrationForUser: new integrationOps.RemoveIntegrationForUser({
208
- getOwnedIntegrationRecord,
209
- deleteIntegrationForUser: new DeleteIntegrationForUser({
210
- integrationRepository,
211
- integrationClasses,
212
- moduleFactory,
213
- }),
214
- }),
215
- sendIntegrationEventForUser: new integrationOps.SendIntegrationEventForUser({
216
- getIntegrationInstanceForUser,
217
- }),
218
- runIntegrationActionForUser: new integrationOps.RunIntegrationActionForUser({
219
- getIntegrationInstanceForUser,
220
- }),
221
- testIntegrationAuthForUser: new integrationOps.TestIntegrationAuthForUser({
222
- getIntegrationInstanceForUser,
223
- }),
224
-
225
- // Entities
226
- getEntityModuleForUser,
227
- listEntitiesForUser: new entityOps.ListEntitiesForUser({
228
- moduleRepository,
229
- scopePolicy,
230
- }),
231
- getEntityForUser: new entityOps.GetEntityForUser({ getEntityModuleForUser }),
232
- deleteEntityForUser: new entityOps.DeleteEntityForUser({
233
- getEntityModuleForUser,
234
- moduleRepository,
235
- integrationRepository,
236
- }),
237
- testEntityAuthForUser: new entityOps.TestEntityAuthForUser({ getEntityModuleForUser }),
238
- getEntityOptionsForUser: new entityOps.GetEntityOptionsForUser({ getEntityModuleForUser }),
239
- refreshEntityOptionsForUser: new entityOps.RefreshEntityOptionsForUser({
240
- getEntityModuleForUser,
241
- }),
242
- listEntityTypes: new ListEntityTypes({ entityTypeRegistry: registry, scopePolicy }),
243
- getEntityType: new GetEntityType({ entityTypeRegistry: registry, scopePolicy }),
244
- getAuthorizationRequirements,
245
-
246
- // Credentials
247
- listCredentialsForUser: new credentialOps.ListCredentialsForUser({
248
- credentialRepository,
249
- moduleRepository,
250
- scopePolicy,
251
- }),
252
- getCredentialForUser,
253
- deleteCredentialForUser: new credentialOps.DeleteCredentialForUser({
254
- credentialRepository,
255
- moduleRepository,
256
- getCredentialForUser,
257
- }),
258
- getCredentialReauthorization: new GetCredentialReauthorization({
259
- getCredentialForUser,
260
- getAuthorizationStep,
261
- }),
262
- reauthorizeCredentialForUser: new ReauthorizeCredentialForUser({
263
- getCredentialForUser,
264
- submitAuthorizationStep,
265
- }),
266
-
267
- // Authorization (multi-step)
268
- getAuthorizationStep,
269
- submitAuthorizationStep,
270
-
271
- // Entity proxy (ADR-052): only built when the app enables it.
272
- ...(config.proxy.enable && {
273
- executeEntityProxyRequest: new ExecuteEntityProxyRequest({
274
- getEntityModuleForUser,
275
- proxyConfig: config.proxy,
276
- }),
277
- }),
278
- };
279
- }
280
-
281
- module.exports = { buildV2Dependencies };