@friggframework/core 2.0.0--canary.690.08cd07e.0 → 2.0.0--canary.694.f66a64a.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 (267) 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 +2 -2
  15. package/database/encryption/encryption-schema-registry.js +12 -93
  16. package/database/prisma.js +2 -4
  17. package/errors/index.js +4 -0
  18. package/errors/mapping-already-exists-error.js +14 -0
  19. package/generated/prisma-mongodb/edge.js +38 -33
  20. package/generated/prisma-mongodb/index-browser.js +35 -30
  21. package/generated/prisma-mongodb/index.d.ts +1880 -3191
  22. package/generated/prisma-mongodb/index.js +38 -33
  23. package/generated/prisma-mongodb/package.json +1 -1
  24. package/generated/prisma-mongodb/schema.prisma +50 -86
  25. package/generated/prisma-mongodb/wasm.js +38 -33
  26. package/generated/prisma-postgresql/edge.js +38 -33
  27. package/generated/prisma-postgresql/index-browser.js +35 -30
  28. package/generated/prisma-postgresql/index.d.ts +2050 -3390
  29. package/generated/prisma-postgresql/index.js +38 -33
  30. package/generated/prisma-postgresql/package.json +1 -1
  31. package/generated/prisma-postgresql/schema.prisma +48 -81
  32. package/generated/prisma-postgresql/wasm.js +38 -33
  33. package/handlers/WEBHOOKS.md +29 -0
  34. package/handlers/app-definition-loader.js +19 -128
  35. package/handlers/app-handler-helpers.js +3 -25
  36. package/handlers/backend-utils.js +25 -31
  37. package/handlers/middleware/admin-auth.js +1 -14
  38. package/handlers/routers/auth.js +10 -46
  39. package/handlers/routers/health.js +4 -13
  40. package/handlers/routers/integration-defined-routers.js +92 -144
  41. package/handlers/routers/integration-webhook-routers.js +64 -102
  42. package/handlers/workers/integration-defined-workers.js +2 -5
  43. package/handlers/workers/integration-triggers.js +25 -0
  44. package/index.js +3 -65
  45. package/infrastructure/scheduler/index.js +6 -19
  46. package/infrastructure/scheduler/recurrence.js +204 -0
  47. package/infrastructure/scheduler/scheduler-service-factory.js +7 -55
  48. package/integrations/data-defined/README.md +185 -0
  49. package/integrations/data-defined/canonical.js +11 -0
  50. package/integrations/data-defined/capabilities/acmeerp.capabilities.json +608 -0
  51. package/integrations/data-defined/capabilities/asana.capabilities.json +265 -0
  52. package/integrations/data-defined/capabilities/calendly.capabilities.json +385 -0
  53. package/integrations/data-defined/capabilities/docusign.capabilities.json +314 -0
  54. package/integrations/data-defined/capabilities/fathom.capabilities.json +228 -0
  55. package/integrations/data-defined/capabilities/github.capabilities.json +563 -0
  56. package/integrations/data-defined/capabilities/hubspot.capabilities.json +715 -0
  57. package/integrations/data-defined/capabilities/jira.capabilities.json +376 -0
  58. package/integrations/data-defined/capabilities/klaviyo.capabilities.json +475 -0
  59. package/integrations/data-defined/capabilities/linear.capabilities.json +324 -0
  60. package/integrations/data-defined/capabilities/netsuite.capabilities.json +491 -0
  61. package/integrations/data-defined/capabilities/notion.capabilities.json +208 -0
  62. package/integrations/data-defined/capabilities/phone.capabilities.json +470 -0
  63. package/integrations/data-defined/capabilities/pipedrive.capabilities.json +388 -0
  64. package/integrations/data-defined/capabilities/quickbooks.capabilities.json +615 -0
  65. package/integrations/data-defined/capabilities/salesforce.capabilities.json +507 -0
  66. package/integrations/data-defined/capabilities/shopify.capabilities.json +1082 -0
  67. package/integrations/data-defined/capabilities/slack.capabilities.json +363 -0
  68. package/integrations/data-defined/capabilities/stripe.capabilities.json +580 -0
  69. package/integrations/data-defined/capabilities/webflow.capabilities.json +196 -0
  70. package/integrations/data-defined/capabilities/zendesk.capabilities.json +409 -0
  71. package/integrations/data-defined/compile.js +80 -0
  72. package/integrations/data-defined/config-form.js +137 -0
  73. package/integrations/data-defined/data-defined-integration.js +417 -0
  74. package/integrations/data-defined/examples/acme-erp-quickbooks.definition.json +467 -0
  75. package/integrations/data-defined/examples/asana-slack.definition.json +220 -0
  76. package/integrations/data-defined/examples/calendly-salesforce.definition.json +459 -0
  77. package/integrations/data-defined/examples/docusign-salesforce.definition.json +305 -0
  78. package/integrations/data-defined/examples/fathom-hubspot-notion.definition.json +575 -0
  79. package/integrations/data-defined/examples/github-linear.definition.json +316 -0
  80. package/integrations/data-defined/examples/hubspot-slack.definition.json +409 -0
  81. package/integrations/data-defined/examples/klaviyo-hubspot.definition.json +339 -0
  82. package/integrations/data-defined/examples/phone-hubspot.definition.json +637 -0
  83. package/integrations/data-defined/examples/pipedrive-hubspot.definition.json +136 -0
  84. package/integrations/data-defined/examples/pipedrive-phone.definition.json +340 -0
  85. package/integrations/data-defined/examples/records/phone-hubspot.definition-version.json +652 -0
  86. package/integrations/data-defined/examples/records/phone-hubspot.integration.json +86 -0
  87. package/integrations/data-defined/examples/records/phone-hubspot.mappings.json +39 -0
  88. package/integrations/data-defined/examples/records/phone-hubspot.workflow-run.json +62 -0
  89. package/integrations/data-defined/examples/shopify-klaviyo.definition.json +488 -0
  90. package/integrations/data-defined/examples/shopify-netsuite.definition.json +622 -0
  91. package/integrations/data-defined/examples/stripe-quickbooks.definition.json +476 -0
  92. package/integrations/data-defined/examples/webflow-hubspot-slack.definition.json +262 -0
  93. package/integrations/data-defined/examples/zendesk-jira.definition.json +604 -0
  94. package/integrations/data-defined/expressions.js +225 -0
  95. package/integrations/data-defined/index.js +39 -0
  96. package/integrations/data-defined/interpreter.js +89 -0
  97. package/integrations/data-defined/manifests.js +125 -0
  98. package/integrations/data-defined/repositories/definition-version-repository.js +67 -0
  99. package/integrations/data-defined/repositories/workflow-run-repository.js +59 -0
  100. package/integrations/data-defined/router.js +97 -0
  101. package/integrations/data-defined/runtime.js +208 -0
  102. package/integrations/data-defined/schema/capability-manifest.v0.1.schema.json +377 -0
  103. package/integrations/data-defined/schema/installation.v0.1.schema.json +130 -0
  104. package/integrations/data-defined/schema/integration-definition.v0.1.schema.json +902 -0
  105. package/integrations/data-defined/schema/records.md +98 -0
  106. package/integrations/data-defined/schema-check.js +58 -0
  107. package/integrations/data-defined/scripts/validate.js +66 -0
  108. package/integrations/data-defined/steps.js +89 -0
  109. package/integrations/data-defined/transforms.js +91 -0
  110. package/integrations/data-defined/use-cases/definition-use-cases.js +187 -0
  111. package/integrations/data-defined/validate.js +384 -0
  112. package/integrations/data-defined/versioning.js +176 -0
  113. package/integrations/data-defined/webhooks.js +119 -0
  114. package/integrations/index.js +0 -1
  115. package/integrations/integration-base.js +117 -0
  116. package/integrations/integration-router.js +101 -131
  117. package/integrations/repositories/integration-mapping-repository-documentdb.js +50 -0
  118. package/integrations/repositories/integration-mapping-repository-interface.js +15 -0
  119. package/integrations/repositories/integration-mapping-repository-mongo.js +29 -0
  120. package/integrations/repositories/integration-mapping-repository-postgres.js +30 -0
  121. package/integrations/repositories/integration-mapping-repository.js +29 -0
  122. package/integrations/repositories/integration-repository-documentdb.js +9 -37
  123. package/integrations/repositories/integration-repository-interface.js +4 -17
  124. package/integrations/repositories/integration-repository-mongo.js +96 -64
  125. package/integrations/repositories/integration-repository-postgres.js +81 -63
  126. package/integrations/repositories/process-repository-mongo.js +1 -1
  127. package/integrations/tests/doubles/test-integration-repository.js +1 -12
  128. package/integrations/triggers.js +244 -0
  129. package/integrations/use-cases/create-integration.js +20 -55
  130. package/integrations/use-cases/get-integrations-for-user.js +40 -80
  131. package/integrations/use-cases/index.js +1 -7
  132. package/integrations/use-cases/run-trigger-tick.js +132 -0
  133. package/integrations/use-cases/run-trigger.js +77 -0
  134. package/integrations/utils/map-integration-dto.js +14 -43
  135. package/modules/index.js +0 -14
  136. package/modules/module-factory.js +0 -12
  137. package/modules/module.js +2 -53
  138. package/modules/repositories/module-repository-documentdb.js +6 -51
  139. package/modules/repositories/module-repository-interface.js +2 -19
  140. package/modules/repositories/module-repository-mongo.js +74 -67
  141. package/modules/repositories/module-repository-postgres.js +74 -66
  142. package/modules/repositories/module-repository.js +1 -2
  143. package/modules/requester/requester.js +5 -35
  144. package/modules/use-cases/get-entities-for-user.js +13 -26
  145. package/modules/use-cases/get-entity-options-by-id.js +4 -10
  146. package/modules/use-cases/get-entity-options-by-type.js +1 -1
  147. package/modules/use-cases/get-module-instance-from-type.js +1 -1
  148. package/modules/use-cases/get-module.js +4 -10
  149. package/modules/use-cases/process-authorization-callback.js +19 -53
  150. package/modules/use-cases/refresh-entity-options.js +4 -10
  151. package/modules/use-cases/test-module-auth.js +4 -10
  152. package/package.json +6 -6
  153. package/prisma-mongodb/schema.prisma +50 -86
  154. package/prisma-postgresql/migrations/20261018000000_add_data_defined_integrations/migration.sql +66 -0
  155. package/prisma-postgresql/schema.prisma +48 -81
  156. package/queues/index.js +0 -25
  157. package/queues/queuer-util.js +9 -2
  158. package/types/index.d.ts +0 -2
  159. package/user/repositories/user-repository-documentdb.js +2 -27
  160. package/user/repositories/user-repository-interface.js +0 -18
  161. package/user/repositories/user-repository-mongo.js +0 -24
  162. package/user/repositories/user-repository-postgres.js +0 -18
  163. package/user/use-cases/authenticate-user.js +1 -7
  164. package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
  165. package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
  166. package/user/user.js +1 -64
  167. package/credential/use-cases/credential-operations-for-user.js +0 -202
  168. package/credential/use-cases/reauthorize-credential-for-user.js +0 -73
  169. package/database/organization-where.js +0 -18
  170. package/database/unique-violation.js +0 -25
  171. package/extensions/bootstrap-runner.js +0 -43
  172. package/extensions/extension-loader.js +0 -187
  173. package/extensions/index.js +0 -41
  174. package/extensions/initialize-app.js +0 -123
  175. package/extensions/route-mounter.js +0 -103
  176. package/extensions/schema-composer.js +0 -188
  177. package/infrastructure/scheduler/netlify-scheduler-adapter.js +0 -216
  178. package/infrastructure/scheduler/scheduled-job-repository.js +0 -118
  179. package/integrations/repositories/integration-not-found.js +0 -14
  180. package/integrations/schedule-config.js +0 -80
  181. package/integrations/use-cases/dispatch-ongoing-syncs.js +0 -100
  182. package/integrations/use-cases/integration-operations-for-user.js +0 -256
  183. package/integrations/use-cases/resolve-integration-ownership.js +0 -177
  184. package/management-api/create-management-api-router.js +0 -49
  185. package/management-api/error-response.js +0 -116
  186. package/management-api/management-api-config.js +0 -151
  187. package/management-api/meta-router.js +0 -76
  188. package/management-api/openapi/build-openapi.js +0 -144
  189. package/management-api/openapi/components.js +0 -415
  190. package/management-api/openapi/v1-operations.js +0 -83
  191. package/management-api/openapi/v2-operations.js +0 -264
  192. package/management-api/route-registry.js +0 -411
  193. package/management-api/test-support/http-client.js +0 -39
  194. package/management-api/use-cases/get-management-api-meta.js +0 -57
  195. package/management-api/v1-deprecation.js +0 -120
  196. package/management-api/v2/create-v2-router.js +0 -85
  197. package/management-api/v2/dependencies.js +0 -281
  198. package/management-api/v2/dto.js +0 -143
  199. package/management-api/v2/handlers/authorization.js +0 -94
  200. package/management-api/v2/handlers/credentials.js +0 -33
  201. package/management-api/v2/handlers/entities.js +0 -77
  202. package/management-api/v2/handlers/integrations.js +0 -128
  203. package/management-api/v2/handlers/proxy.js +0 -34
  204. package/management-api/v2/request.js +0 -85
  205. package/management-api/v2/test-support/fake-dependencies.js +0 -103
  206. package/modules/domain/authorization-session.js +0 -144
  207. package/modules/entity-scope.js +0 -15
  208. package/modules/entity-type-registry.js +0 -311
  209. package/modules/proxy/proxy-bases.js +0 -169
  210. package/modules/proxy/proxy-errors.js +0 -31
  211. package/modules/proxy/proxy-path.js +0 -183
  212. package/modules/proxy/proxy-policy.js +0 -277
  213. package/modules/repositories/authorization-session-repository-documentdb.js +0 -112
  214. package/modules/repositories/authorization-session-repository-factory.js +0 -31
  215. package/modules/repositories/authorization-session-repository-interface.js +0 -47
  216. package/modules/repositories/authorization-session-repository-prisma.js +0 -87
  217. package/modules/repositories/entity-not-found.js +0 -18
  218. package/modules/requester/proxy-request.js +0 -245
  219. package/modules/scope-config.js +0 -192
  220. package/modules/scope-policy.js +0 -112
  221. package/modules/scope-resolution.js +0 -288
  222. package/modules/scope-visibility.js +0 -247
  223. package/modules/tests/doubles/in-memory-authorization-session-repository.js +0 -45
  224. package/modules/tests/doubles/ownership-matching.js +0 -18
  225. package/modules/use-cases/authorize-entity-for-user.js +0 -61
  226. package/modules/use-cases/create-entity-from-credential.js +0 -113
  227. package/modules/use-cases/entity-operations-for-user.js +0 -162
  228. package/modules/use-cases/entity-types.js +0 -139
  229. package/modules/use-cases/execute-entity-proxy-request.js +0 -331
  230. package/modules/use-cases/get-authorization-requirements.js +0 -100
  231. package/modules/use-cases/get-entity-module-for-user.js +0 -113
  232. package/modules/use-cases/manage-access.js +0 -21
  233. package/modules/use-cases/multi-step-authorization.js +0 -329
  234. package/prisma-postgresql/migrations/20261003000000_add_authorization_session/migration.sql +0 -28
  235. package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
  236. package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
  237. package/prisma-postgresql/migrations/20261017000000_add_scheduled_job/migration.sql +0 -28
  238. package/providers/index.js +0 -23
  239. package/providers/resolve-provider.js +0 -93
  240. package/providers/runtime-detection.js +0 -124
  241. package/queues/providers/index.js +0 -11
  242. package/queues/providers/netlify-background-provider.js +0 -150
  243. package/queues/providers/qstash-queue-provider.js +0 -219
  244. package/queues/providers/sqs-queue-provider.js +0 -70
  245. package/queues/queue-client-interface.js +0 -55
  246. package/queues/queue-message-auth.js +0 -193
  247. package/queues/queue-provider-factory.js +0 -101
  248. package/queues/queue-provider.js +0 -65
  249. package/queues/sqs-queue-client.js +0 -81
  250. package/types/modules/index.d.ts +0 -214
  251. package/types/user/index.d.ts +0 -134
  252. package/user/adopter-jwt-config.js +0 -177
  253. package/user/adopter-jwt-errors.js +0 -59
  254. package/user/adopter-token-verifier.js +0 -122
  255. package/user/app-user-helpers.js +0 -97
  256. package/user/create-user-authentication.js +0 -64
  257. package/user/membership.js +0 -51
  258. package/user/repositories/organization-membership-record.js +0 -19
  259. package/user/repositories/organization-membership-repository-documentdb.js +0 -106
  260. package/user/repositories/organization-membership-repository-factory.js +0 -42
  261. package/user/repositories/organization-membership-repository-interface.js +0 -57
  262. package/user/repositories/organization-membership-repository-mongo.js +0 -13
  263. package/user/repositories/organization-membership-repository-postgres.js +0 -29
  264. package/user/repositories/organization-membership-repository-prisma.js +0 -81
  265. package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
  266. package/user/use-cases/ensure-organization-membership.js +0 -92
  267. package/user/use-cases/find-individual-users-by-organization.js +0 -54
@@ -1,143 +0,0 @@
1
- /**
2
- * Response shapes for Management API v2. Use cases return domain records;
3
- * these functions decide what leaves the server. Credential material never
4
- * does (see maskCredential).
5
- */
6
-
7
- const idOf = (value) => {
8
- if (value === undefined || value === null) return null;
9
- if (typeof value === 'object') {
10
- const id = value.id ?? value._id;
11
- return id === undefined || id === null ? null : String(id);
12
- }
13
- return String(value);
14
- };
15
-
16
- /**
17
- * `{ scope, owner, organizationId, access }` (ADR-056 §3.4): whose a record is
18
- * and what the caller may do with it. Empty when the use case did not say.
19
- */
20
- function tenancyFields(tenancy) {
21
- if (!tenancy) return {};
22
- return {
23
- scope: tenancy.scope,
24
- owner: tenancy.owner,
25
- organizationId: tenancy.organizationId ?? null,
26
- access: tenancy.access,
27
- };
28
- }
29
-
30
- /** An entity (connected account). */
31
- function toEntityDto(entity) {
32
- const credential =
33
- entity.credential && typeof entity.credential === 'object'
34
- ? entity.credential
35
- : null;
36
- return {
37
- id: String(entity.id),
38
- type: entity.moduleName ?? null,
39
- name: entity.name ?? null,
40
- externalId: entity.externalId ?? null,
41
- credentialId: idOf(entity.credential ?? entity.credentialId),
42
- userId: idOf(entity.userId ?? entity.user),
43
- authIsValid:
44
- typeof credential?.authIsValid === 'boolean'
45
- ? credential.authIsValid
46
- : null,
47
- ...tenancyFields(entity.tenancy),
48
- };
49
- }
50
-
51
- /** An integration, from a hydrated instance or a stored DTO. */
52
- function toIntegrationDto(integration) {
53
- return {
54
- id: String(integration.id),
55
- entities: integration.entities ?? [],
56
- status: integration.status ?? null,
57
- config: integration.config ?? {},
58
- version: integration.version ?? null,
59
- messages: integration.messages ?? {},
60
- ...tenancyFields(integration.tenancy),
61
- };
62
- }
63
-
64
- // Fields every repository adds around the stored data; everything else on a
65
- // credential record came from the provider and is treated as secret.
66
- const CREDENTIAL_METADATA = new Set([
67
- 'id',
68
- '_id',
69
- 'userId',
70
- 'user',
71
- 'externalId',
72
- 'authIsValid',
73
- 'createdAt',
74
- 'updatedAt',
75
- 'type',
76
- 'entityIds',
77
- 'status',
78
- // Added by the credential use cases (ADR-056 §3.4); never provider data.
79
- 'tenancy',
80
- ]);
81
-
82
- /**
83
- * Masks one stored credential value. Strings keep at most their last four
84
- * characters, and only when long enough that four characters reveal nothing
85
- * useful; objects and arrays are hidden whole. Numbers, booleans and null
86
- * (expiry times, flags) are not secret and pass through.
87
- */
88
- function maskValue(value) {
89
- if (value === null || typeof value === 'number' || typeof value === 'boolean') {
90
- return value;
91
- }
92
- if (typeof value === 'string') {
93
- return value.length >= 16 ? `****${value.slice(-4)}` : '****';
94
- }
95
- return '****';
96
- }
97
-
98
- const toIso = (value) => {
99
- if (!value) return null;
100
- const date = value instanceof Date ? value : new Date(value);
101
- return Number.isNaN(date.getTime()) ? null : date.toISOString();
102
- };
103
-
104
- /**
105
- * A credential with every provider field masked. The keys stay visible so a
106
- * client can tell an OAuth credential from an API-key one; the values never
107
- * leave the server.
108
- */
109
- function maskCredential(credential) {
110
- const data = {};
111
- for (const [key, value] of Object.entries(credential)) {
112
- if (CREDENTIAL_METADATA.has(key) || value === undefined) continue;
113
- data[key] = maskValue(value);
114
- }
115
- const entityIds = Array.isArray(credential.entityIds)
116
- ? credential.entityIds.map(String)
117
- : [];
118
- return {
119
- id: String(credential.id),
120
- type: credential.type ?? null,
121
- externalId: credential.externalId ?? null,
122
- userId: idOf(credential.userId),
123
- authIsValid:
124
- typeof credential.authIsValid === 'boolean'
125
- ? credential.authIsValid
126
- : null,
127
- entityIds,
128
- entityCount: entityIds.length,
129
- createdAt: toIso(credential.createdAt),
130
- updatedAt: toIso(credential.updatedAt),
131
- ...tenancyFields(credential.tenancy),
132
- data,
133
- };
134
- }
135
-
136
- module.exports = {
137
- tenancyFields,
138
- toEntityDto,
139
- toIntegrationDto,
140
- maskCredential,
141
- maskValue,
142
- idOf,
143
- };
@@ -1,94 +0,0 @@
1
- const { toEntityDto, maskCredential } = require('../dto');
2
- const { objectBody, requireFields, parseStep, optionalString } = require('../request');
3
-
4
- /** The v2 body for a submitted step: masked records when complete. */
5
- function toAuthorizationResponse(result) {
6
- if (result.status !== 'complete') return result;
7
- return {
8
- status: 'complete',
9
- entity: result.entity ? toEntityDto(result.entity) : null,
10
- credential: result.credential ? maskCredential(result.credential) : null,
11
- ...(result.previousCredentialId && {
12
- previousCredentialId: result.previousCredentialId,
13
- }),
14
- };
15
- }
16
-
17
- /**
18
- * Management API v2 authorization handlers (multi-step authorize and
19
- * credential re-authorization), keyed by operationId.
20
- */
21
- function createAuthorizationHandlers(useCases) {
22
- const {
23
- getAuthorizationStep,
24
- submitAuthorizationStep,
25
- getCredentialReauthorization,
26
- reauthorizeCredentialForUser,
27
- } = useCases;
28
-
29
- const stepQuery = (req) => ({
30
- step: parseStep(req.query.step),
31
- sessionId: optionalString(req.query.sessionId, 'sessionId'),
32
- state: optionalString(req.query.state, 'state'),
33
- });
34
-
35
- const stepBody = (req) => {
36
- const body = objectBody(req);
37
- return {
38
- body,
39
- step: parseStep(body.step),
40
- sessionId: optionalString(body.sessionId, 'sessionId'),
41
- };
42
- };
43
-
44
- return {
45
- async getAuthorizationRequirements(req, res, user) {
46
- const entityType = optionalString(req.query.entityType, 'entityType');
47
- requireFields({ entityType }, ['entityType']);
48
- res.json(
49
- await getAuthorizationStep.execute({
50
- user,
51
- entityType,
52
- ...stepQuery(req),
53
- })
54
- );
55
- },
56
-
57
- async authorize(req, res, user) {
58
- const { body, step, sessionId } = stepBody(req);
59
- requireFields(body, ['entityType', 'data']);
60
- const result = await submitAuthorizationStep.execute({
61
- user,
62
- entityType: optionalString(body.entityType, 'entityType'),
63
- data: body.data,
64
- step,
65
- sessionId,
66
- scope: optionalString(body.scope, 'scope'),
67
- });
68
- res.json(toAuthorizationResponse(result));
69
- },
70
-
71
- async getCredentialReauthorizeRequirements(req, res, user) {
72
- res.json(
73
- await getCredentialReauthorization.execute(
74
- req.params.credentialId,
75
- user,
76
- stepQuery(req)
77
- )
78
- );
79
- },
80
-
81
- async reauthorizeCredential(req, res, user) {
82
- const { body, step, sessionId } = stepBody(req);
83
- requireFields(body, ['data']);
84
- const result = await reauthorizeCredentialForUser.execute(
85
- req.params.credentialId,
86
- user,
87
- { data: body.data, step, sessionId }
88
- );
89
- res.json(toAuthorizationResponse(result));
90
- },
91
- };
92
- }
93
-
94
- module.exports = { createAuthorizationHandlers, toAuthorizationResponse };
@@ -1,33 +0,0 @@
1
- const { maskCredential } = require('../dto');
2
- const { parseListFilters } = require('../request');
3
-
4
- /** Management API v2 credential handlers, keyed by operationId. */
5
- function createCredentialHandlers(useCases) {
6
- const { listCredentialsForUser, getCredentialForUser, deleteCredentialForUser } =
7
- useCases;
8
-
9
- return {
10
- async listCredentials(req, res, user) {
11
- const credentials = await listCredentialsForUser.execute(
12
- user,
13
- parseListFilters(req.query)
14
- );
15
- res.json({ credentials: credentials.map(maskCredential) });
16
- },
17
-
18
- async getCredential(req, res, user) {
19
- res.json(
20
- maskCredential(
21
- await getCredentialForUser.execute(req.params.credentialId, user)
22
- )
23
- );
24
- },
25
-
26
- async deleteCredential(req, res, user) {
27
- await deleteCredentialForUser.execute(req.params.credentialId, user);
28
- res.status(204).end();
29
- },
30
- };
31
- }
32
-
33
- module.exports = { createCredentialHandlers };
@@ -1,77 +0,0 @@
1
- const { toEntityDto } = require('../dto');
2
- const { objectBody, parseStep, parseListFilters } = require('../request');
3
-
4
- /** Management API v2 entity and entity-type handlers, keyed by operationId. */
5
- function createEntityHandlers(useCases) {
6
- const {
7
- listEntitiesForUser,
8
- getEntityForUser,
9
- deleteEntityForUser,
10
- testEntityAuthForUser,
11
- getEntityOptionsForUser,
12
- refreshEntityOptionsForUser,
13
- listEntityTypes,
14
- getEntityType,
15
- getAuthorizationRequirements,
16
- } = useCases;
17
-
18
- return {
19
- async listEntities(req, res, user) {
20
- const entities = await listEntitiesForUser.execute(
21
- user,
22
- parseListFilters(req.query)
23
- );
24
- res.json({ entities: entities.map(toEntityDto) });
25
- },
26
-
27
- async listEntityTypes(_req, res, user) {
28
- res.json({ types: await listEntityTypes.execute({ user }) });
29
- },
30
-
31
- async getEntityType(req, res, user) {
32
- res.json(await getEntityType.execute(req.params.entityType, { user }));
33
- },
34
-
35
- // Describes a step's requirements without starting an authorization
36
- // session; GET /api/v2/authorize starts one.
37
- async getEntityTypeRequirements(req, res, user) {
38
- res.json(
39
- await getAuthorizationRequirements.execute({
40
- entityType: req.params.entityType,
41
- step: parseStep(req.query.step),
42
- userId: user.getId(),
43
- })
44
- );
45
- },
46
-
47
- async getEntity(req, res, user) {
48
- res.json(toEntityDto(await getEntityForUser.execute(req.params.entityId, user)));
49
- },
50
-
51
- async deleteEntity(req, res, user) {
52
- await deleteEntityForUser.execute(req.params.entityId, user);
53
- res.status(204).end();
54
- },
55
-
56
- async testEntityAuth(req, res, user) {
57
- const ok = await testEntityAuthForUser.execute(req.params.entityId, user);
58
- res.json({ status: ok ? 'ok' : 'failed' });
59
- },
60
-
61
- async getEntityOptions(req, res, user) {
62
- res.json(await getEntityOptionsForUser.execute(req.params.entityId, user));
63
- },
64
-
65
- async refreshEntityOptions(req, res, user) {
66
- res.json(
67
- await refreshEntityOptionsForUser.execute(
68
- req.params.entityId,
69
- user,
70
- objectBody(req)
71
- )
72
- );
73
- },
74
- };
75
- }
76
-
77
- module.exports = { createEntityHandlers };
@@ -1,128 +0,0 @@
1
- const { toIntegrationDto } = require('../dto');
2
- const { objectBody, optionalString, parseListFilters } = require('../request');
3
-
4
- /**
5
- * Management API v2 integration handlers, keyed by registry operationId.
6
- * Each takes (req, res, user) after authentication and only calls use cases.
7
- */
8
- function createIntegrationHandlers(useCases) {
9
- const {
10
- getIntegrationsForUser,
11
- getPossibleIntegrations,
12
- createIntegrationForUser,
13
- getIntegrationInstanceForUser,
14
- updateIntegrationForUser,
15
- removeIntegrationForUser,
16
- sendIntegrationEventForUser,
17
- runIntegrationActionForUser,
18
- testIntegrationAuthForUser,
19
- } = useCases;
20
-
21
- const send = (req, user, event, payload) =>
22
- sendIntegrationEventForUser.execute(
23
- req.params.integrationId,
24
- user,
25
- event,
26
- payload
27
- );
28
-
29
- return {
30
- async listIntegrations(req, res, user) {
31
- const integrations = await getIntegrationsForUser.execute(
32
- user,
33
- parseListFilters(req.query)
34
- );
35
- res.json({ integrations: integrations.map(toIntegrationDto) });
36
- },
37
-
38
- async listIntegrationOptions(_req, res) {
39
- res.json({ integrations: await getPossibleIntegrations.execute() });
40
- },
41
-
42
- async createIntegration(req, res, user) {
43
- const { entities, config } = objectBody(req);
44
- const integration = await createIntegrationForUser.execute(
45
- { entities, config },
46
- user
47
- );
48
- res.status(201).json(toIntegrationDto(integration));
49
- },
50
-
51
- async getIntegration(req, res, user) {
52
- const instance = await getIntegrationInstanceForUser.execute(
53
- req.params.integrationId,
54
- user
55
- );
56
- res.json(toIntegrationDto(instance));
57
- },
58
-
59
- async updateIntegration(req, res, user) {
60
- const { config } = objectBody(req);
61
- const integration = await updateIntegrationForUser.execute(
62
- req.params.integrationId,
63
- user,
64
- config
65
- );
66
- res.json(toIntegrationDto(integration));
67
- },
68
-
69
- async deleteIntegration(req, res, user) {
70
- await removeIntegrationForUser.execute(req.params.integrationId, user);
71
- res.status(204).end();
72
- },
73
-
74
- async getIntegrationConfigOptions(req, res, user) {
75
- res.json(await send(req, user, 'GET_CONFIG_OPTIONS'));
76
- },
77
-
78
- async refreshIntegrationConfigOptions(req, res, user) {
79
- res.json(await send(req, user, 'REFRESH_CONFIG_OPTIONS', objectBody(req)));
80
- },
81
-
82
- async listIntegrationActions(req, res, user) {
83
- const actionType = optionalString(req.query.actionType, 'actionType');
84
- res.json(
85
- await send(req, user, 'GET_USER_ACTIONS', actionType ? { actionType } : {})
86
- );
87
- },
88
-
89
- async getIntegrationActionOptions(req, res, user) {
90
- res.json(
91
- await send(req, user, 'GET_USER_ACTION_OPTIONS', {
92
- actionId: req.params.actionId,
93
- data: objectBody(req),
94
- })
95
- );
96
- },
97
-
98
- async refreshIntegrationActionOptions(req, res, user) {
99
- res.json(
100
- await send(req, user, 'REFRESH_USER_ACTION_OPTIONS', {
101
- actionId: req.params.actionId,
102
- data: objectBody(req),
103
- })
104
- );
105
- },
106
-
107
- async runIntegrationAction(req, res, user) {
108
- res.json(
109
- await runIntegrationActionForUser.execute(
110
- req.params.integrationId,
111
- user,
112
- req.params.actionId,
113
- objectBody(req)
114
- )
115
- );
116
- },
117
-
118
- async testIntegrationAuth(req, res, user) {
119
- const { ok, errors } = await testIntegrationAuthForUser.execute(
120
- req.params.integrationId,
121
- user
122
- );
123
- res.json(ok ? { status: 'ok' } : { status: 'failed', errors });
124
- },
125
- };
126
- }
127
-
128
- module.exports = { createIntegrationHandlers };
@@ -1,34 +0,0 @@
1
- const { toV2ErrorBody } = require('../../error-response');
2
-
3
- /**
4
- * POST /api/v2/entities/:entityId/proxy (ADR-052). The HTTP status follows the
5
- * upstream status. Proxy failures answer in the api-proxy.schema.json error
6
- * shape, which is also the v2 error shape plus `success` and `status`.
7
- */
8
- function createProxyHandlers({ executeEntityProxyRequest }) {
9
- return {
10
- async proxyEntityRequest(req, res, user) {
11
- try {
12
- const result = await executeEntityProxyRequest.execute(
13
- req.params.entityId,
14
- user,
15
- req.body
16
- );
17
- res.status(result.status).json(result.body);
18
- } catch (error) {
19
- if (!error?.isBoom || !error.data?.proxy) throw error;
20
- const status = error.output.statusCode;
21
- if (error.data.retryAfter) {
22
- res.set('Retry-After', String(error.data.retryAfter));
23
- }
24
- res.status(status).json({
25
- success: false,
26
- status,
27
- ...toV2ErrorBody(error),
28
- });
29
- }
30
- },
31
- };
32
- }
33
-
34
- module.exports = { createProxyHandlers };
@@ -1,85 +0,0 @@
1
- const Boom = require('@hapi/boom');
2
- const { LIST_OWNERS } = require('../../modules/scope-visibility');
3
-
4
- /** The JSON body as an object, or a 400 VALIDATION_ERROR. */
5
- function objectBody(req) {
6
- const body = req.body;
7
- if (body === undefined || body === null || body === '') return {};
8
- if (typeof body !== 'object' || Array.isArray(body)) {
9
- throw Boom.badRequest('Request body must be a JSON object', {
10
- code: 'VALIDATION_ERROR',
11
- });
12
- }
13
- return body;
14
- }
15
-
16
- /** Fields that must be present (non-empty) in the body. */
17
- function requireFields(body, fields) {
18
- const missing = fields.filter(
19
- (field) =>
20
- body[field] === undefined || body[field] === null || body[field] === ''
21
- );
22
- if (missing.length) {
23
- throw Boom.badRequest(
24
- `Missing required field${missing.length > 1 ? 's' : ''}: ${missing.join(', ')}`,
25
- { code: 'VALIDATION_ERROR', details: { missing } }
26
- );
27
- }
28
- return body;
29
- }
30
-
31
- /** A 1-based step number from a query or body value; 1 when absent. */
32
- function parseStep(value) {
33
- if (value === undefined || value === null || value === '') return 1;
34
- const step = Number(value);
35
- if (!Number.isInteger(step) || step < 1) {
36
- throw Boom.badRequest('step must be a positive integer', {
37
- code: 'INVALID_STEP',
38
- });
39
- }
40
- return step;
41
- }
42
-
43
- /** An optional string query/body value. */
44
- function optionalString(value, name) {
45
- if (value === undefined || value === null || value === '') return undefined;
46
- if (typeof value !== 'string') {
47
- throw Boom.badRequest(`${name} must be a string`, {
48
- code: 'VALIDATION_ERROR',
49
- details: { field: name },
50
- });
51
- }
52
- return value;
53
- }
54
-
55
- const LIST_SCOPES = ['individual', 'organization'];
56
-
57
- /**
58
- * `?scope=individual|organization` and `?owner=me|org` on a list (ADR-056
59
- * §3.4). Anything else is a 400.
60
- */
61
- function parseListFilters(query = {}) {
62
- const scope = optionalString(query.scope, 'scope');
63
- const owner = optionalString(query.owner, 'owner');
64
- if (scope !== undefined && !LIST_SCOPES.includes(scope)) {
65
- throw Boom.badRequest(`scope must be one of ${LIST_SCOPES.join(', ')}`, {
66
- code: 'VALIDATION_ERROR',
67
- details: { field: 'scope' },
68
- });
69
- }
70
- if (owner !== undefined && !Object.hasOwn(LIST_OWNERS, owner)) {
71
- throw Boom.badRequest('owner must be me or org', {
72
- code: 'VALIDATION_ERROR',
73
- details: { field: 'owner' },
74
- });
75
- }
76
- return { scope, owner };
77
- }
78
-
79
- module.exports = {
80
- objectBody,
81
- requireFields,
82
- parseStep,
83
- optionalString,
84
- parseListFilters,
85
- };