@friggframework/core 2.0.0--canary.690.08cd07e.0 → 2.0.0--canary.693.d8859c2.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 (261) 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 +0 -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/index.js +3 -65
  44. package/infrastructure/scheduler/index.js +6 -19
  45. package/infrastructure/scheduler/scheduler-service-factory.js +7 -55
  46. package/integrations/data-defined/README.md +169 -0
  47. package/integrations/data-defined/canonical.js +11 -0
  48. package/integrations/data-defined/capabilities/acmeerp.capabilities.json +608 -0
  49. package/integrations/data-defined/capabilities/asana.capabilities.json +265 -0
  50. package/integrations/data-defined/capabilities/calendly.capabilities.json +385 -0
  51. package/integrations/data-defined/capabilities/docusign.capabilities.json +314 -0
  52. package/integrations/data-defined/capabilities/fathom.capabilities.json +228 -0
  53. package/integrations/data-defined/capabilities/github.capabilities.json +563 -0
  54. package/integrations/data-defined/capabilities/hubspot.capabilities.json +715 -0
  55. package/integrations/data-defined/capabilities/jira.capabilities.json +376 -0
  56. package/integrations/data-defined/capabilities/klaviyo.capabilities.json +475 -0
  57. package/integrations/data-defined/capabilities/linear.capabilities.json +324 -0
  58. package/integrations/data-defined/capabilities/netsuite.capabilities.json +491 -0
  59. package/integrations/data-defined/capabilities/notion.capabilities.json +208 -0
  60. package/integrations/data-defined/capabilities/phone.capabilities.json +470 -0
  61. package/integrations/data-defined/capabilities/pipedrive.capabilities.json +388 -0
  62. package/integrations/data-defined/capabilities/quickbooks.capabilities.json +615 -0
  63. package/integrations/data-defined/capabilities/salesforce.capabilities.json +507 -0
  64. package/integrations/data-defined/capabilities/shopify.capabilities.json +1082 -0
  65. package/integrations/data-defined/capabilities/slack.capabilities.json +363 -0
  66. package/integrations/data-defined/capabilities/stripe.capabilities.json +580 -0
  67. package/integrations/data-defined/capabilities/webflow.capabilities.json +196 -0
  68. package/integrations/data-defined/capabilities/zendesk.capabilities.json +409 -0
  69. package/integrations/data-defined/compile.js +77 -0
  70. package/integrations/data-defined/config-form.js +110 -0
  71. package/integrations/data-defined/data-defined-integration.js +366 -0
  72. package/integrations/data-defined/examples/acme-erp-quickbooks.definition.json +467 -0
  73. package/integrations/data-defined/examples/asana-slack.definition.json +220 -0
  74. package/integrations/data-defined/examples/calendly-salesforce.definition.json +459 -0
  75. package/integrations/data-defined/examples/docusign-salesforce.definition.json +305 -0
  76. package/integrations/data-defined/examples/fathom-hubspot-notion.definition.json +575 -0
  77. package/integrations/data-defined/examples/github-linear.definition.json +316 -0
  78. package/integrations/data-defined/examples/hubspot-slack.definition.json +409 -0
  79. package/integrations/data-defined/examples/klaviyo-hubspot.definition.json +339 -0
  80. package/integrations/data-defined/examples/phone-hubspot.definition.json +637 -0
  81. package/integrations/data-defined/examples/pipedrive-hubspot.definition.json +136 -0
  82. package/integrations/data-defined/examples/pipedrive-phone.definition.json +340 -0
  83. package/integrations/data-defined/examples/records/phone-hubspot.definition-version.json +652 -0
  84. package/integrations/data-defined/examples/records/phone-hubspot.integration.json +86 -0
  85. package/integrations/data-defined/examples/records/phone-hubspot.mappings.json +39 -0
  86. package/integrations/data-defined/examples/records/phone-hubspot.workflow-run.json +62 -0
  87. package/integrations/data-defined/examples/shopify-klaviyo.definition.json +488 -0
  88. package/integrations/data-defined/examples/shopify-netsuite.definition.json +622 -0
  89. package/integrations/data-defined/examples/stripe-quickbooks.definition.json +476 -0
  90. package/integrations/data-defined/examples/webflow-hubspot-slack.definition.json +262 -0
  91. package/integrations/data-defined/examples/zendesk-jira.definition.json +604 -0
  92. package/integrations/data-defined/expressions.js +225 -0
  93. package/integrations/data-defined/index.js +39 -0
  94. package/integrations/data-defined/interpreter.js +89 -0
  95. package/integrations/data-defined/manifests.js +125 -0
  96. package/integrations/data-defined/repositories/definition-version-repository.js +67 -0
  97. package/integrations/data-defined/repositories/workflow-run-repository.js +59 -0
  98. package/integrations/data-defined/router.js +97 -0
  99. package/integrations/data-defined/runtime.js +208 -0
  100. package/integrations/data-defined/schema/capability-manifest.v0.1.schema.json +377 -0
  101. package/integrations/data-defined/schema/installation.v0.1.schema.json +83 -0
  102. package/integrations/data-defined/schema/integration-definition.v0.1.schema.json +848 -0
  103. package/integrations/data-defined/schema/records.md +98 -0
  104. package/integrations/data-defined/schema-check.js +58 -0
  105. package/integrations/data-defined/scripts/validate.js +66 -0
  106. package/integrations/data-defined/steps.js +89 -0
  107. package/integrations/data-defined/transforms.js +91 -0
  108. package/integrations/data-defined/use-cases/definition-use-cases.js +187 -0
  109. package/integrations/data-defined/validate.js +370 -0
  110. package/integrations/data-defined/versioning.js +161 -0
  111. package/integrations/data-defined/webhooks.js +119 -0
  112. package/integrations/index.js +0 -1
  113. package/integrations/integration-base.js +29 -0
  114. package/integrations/integration-router.js +101 -131
  115. package/integrations/repositories/integration-mapping-repository-documentdb.js +50 -0
  116. package/integrations/repositories/integration-mapping-repository-interface.js +15 -0
  117. package/integrations/repositories/integration-mapping-repository-mongo.js +29 -0
  118. package/integrations/repositories/integration-mapping-repository-postgres.js +30 -0
  119. package/integrations/repositories/integration-mapping-repository.js +29 -0
  120. package/integrations/repositories/integration-repository-documentdb.js +3 -35
  121. package/integrations/repositories/integration-repository-interface.js +1 -17
  122. package/integrations/repositories/integration-repository-mongo.js +77 -60
  123. package/integrations/repositories/integration-repository-postgres.js +76 -62
  124. package/integrations/repositories/process-repository-mongo.js +1 -1
  125. package/integrations/tests/doubles/test-integration-repository.js +1 -12
  126. package/integrations/use-cases/create-integration.js +20 -55
  127. package/integrations/use-cases/get-integrations-for-user.js +40 -80
  128. package/integrations/use-cases/index.js +1 -7
  129. package/integrations/utils/map-integration-dto.js +14 -43
  130. package/modules/index.js +0 -14
  131. package/modules/module-factory.js +0 -12
  132. package/modules/module.js +2 -53
  133. package/modules/repositories/module-repository-documentdb.js +6 -51
  134. package/modules/repositories/module-repository-interface.js +2 -19
  135. package/modules/repositories/module-repository-mongo.js +74 -67
  136. package/modules/repositories/module-repository-postgres.js +74 -66
  137. package/modules/repositories/module-repository.js +1 -2
  138. package/modules/requester/requester.js +5 -35
  139. package/modules/use-cases/get-entities-for-user.js +13 -26
  140. package/modules/use-cases/get-entity-options-by-id.js +4 -10
  141. package/modules/use-cases/get-entity-options-by-type.js +1 -1
  142. package/modules/use-cases/get-module-instance-from-type.js +1 -1
  143. package/modules/use-cases/get-module.js +4 -10
  144. package/modules/use-cases/process-authorization-callback.js +19 -53
  145. package/modules/use-cases/refresh-entity-options.js +4 -10
  146. package/modules/use-cases/test-module-auth.js +4 -10
  147. package/package.json +6 -6
  148. package/prisma-mongodb/schema.prisma +50 -86
  149. package/prisma-postgresql/migrations/20261018000000_add_data_defined_integrations/migration.sql +66 -0
  150. package/prisma-postgresql/schema.prisma +48 -81
  151. package/queues/index.js +0 -25
  152. package/types/index.d.ts +0 -2
  153. package/user/repositories/user-repository-documentdb.js +2 -27
  154. package/user/repositories/user-repository-interface.js +0 -18
  155. package/user/repositories/user-repository-mongo.js +0 -24
  156. package/user/repositories/user-repository-postgres.js +0 -18
  157. package/user/use-cases/authenticate-user.js +1 -7
  158. package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
  159. package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
  160. package/user/user.js +1 -64
  161. package/credential/use-cases/credential-operations-for-user.js +0 -202
  162. package/credential/use-cases/reauthorize-credential-for-user.js +0 -73
  163. package/database/organization-where.js +0 -18
  164. package/database/unique-violation.js +0 -25
  165. package/extensions/bootstrap-runner.js +0 -43
  166. package/extensions/extension-loader.js +0 -187
  167. package/extensions/index.js +0 -41
  168. package/extensions/initialize-app.js +0 -123
  169. package/extensions/route-mounter.js +0 -103
  170. package/extensions/schema-composer.js +0 -188
  171. package/infrastructure/scheduler/netlify-scheduler-adapter.js +0 -216
  172. package/infrastructure/scheduler/scheduled-job-repository.js +0 -118
  173. package/integrations/repositories/integration-not-found.js +0 -14
  174. package/integrations/schedule-config.js +0 -80
  175. package/integrations/use-cases/dispatch-ongoing-syncs.js +0 -100
  176. package/integrations/use-cases/integration-operations-for-user.js +0 -256
  177. package/integrations/use-cases/resolve-integration-ownership.js +0 -177
  178. package/management-api/create-management-api-router.js +0 -49
  179. package/management-api/error-response.js +0 -116
  180. package/management-api/management-api-config.js +0 -151
  181. package/management-api/meta-router.js +0 -76
  182. package/management-api/openapi/build-openapi.js +0 -144
  183. package/management-api/openapi/components.js +0 -415
  184. package/management-api/openapi/v1-operations.js +0 -83
  185. package/management-api/openapi/v2-operations.js +0 -264
  186. package/management-api/route-registry.js +0 -411
  187. package/management-api/test-support/http-client.js +0 -39
  188. package/management-api/use-cases/get-management-api-meta.js +0 -57
  189. package/management-api/v1-deprecation.js +0 -120
  190. package/management-api/v2/create-v2-router.js +0 -85
  191. package/management-api/v2/dependencies.js +0 -281
  192. package/management-api/v2/dto.js +0 -143
  193. package/management-api/v2/handlers/authorization.js +0 -94
  194. package/management-api/v2/handlers/credentials.js +0 -33
  195. package/management-api/v2/handlers/entities.js +0 -77
  196. package/management-api/v2/handlers/integrations.js +0 -128
  197. package/management-api/v2/handlers/proxy.js +0 -34
  198. package/management-api/v2/request.js +0 -85
  199. package/management-api/v2/test-support/fake-dependencies.js +0 -103
  200. package/modules/domain/authorization-session.js +0 -144
  201. package/modules/entity-scope.js +0 -15
  202. package/modules/entity-type-registry.js +0 -311
  203. package/modules/proxy/proxy-bases.js +0 -169
  204. package/modules/proxy/proxy-errors.js +0 -31
  205. package/modules/proxy/proxy-path.js +0 -183
  206. package/modules/proxy/proxy-policy.js +0 -277
  207. package/modules/repositories/authorization-session-repository-documentdb.js +0 -112
  208. package/modules/repositories/authorization-session-repository-factory.js +0 -31
  209. package/modules/repositories/authorization-session-repository-interface.js +0 -47
  210. package/modules/repositories/authorization-session-repository-prisma.js +0 -87
  211. package/modules/repositories/entity-not-found.js +0 -18
  212. package/modules/requester/proxy-request.js +0 -245
  213. package/modules/scope-config.js +0 -192
  214. package/modules/scope-policy.js +0 -112
  215. package/modules/scope-resolution.js +0 -288
  216. package/modules/scope-visibility.js +0 -247
  217. package/modules/tests/doubles/in-memory-authorization-session-repository.js +0 -45
  218. package/modules/tests/doubles/ownership-matching.js +0 -18
  219. package/modules/use-cases/authorize-entity-for-user.js +0 -61
  220. package/modules/use-cases/create-entity-from-credential.js +0 -113
  221. package/modules/use-cases/entity-operations-for-user.js +0 -162
  222. package/modules/use-cases/entity-types.js +0 -139
  223. package/modules/use-cases/execute-entity-proxy-request.js +0 -331
  224. package/modules/use-cases/get-authorization-requirements.js +0 -100
  225. package/modules/use-cases/get-entity-module-for-user.js +0 -113
  226. package/modules/use-cases/manage-access.js +0 -21
  227. package/modules/use-cases/multi-step-authorization.js +0 -329
  228. package/prisma-postgresql/migrations/20261003000000_add_authorization_session/migration.sql +0 -28
  229. package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
  230. package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
  231. package/prisma-postgresql/migrations/20261017000000_add_scheduled_job/migration.sql +0 -28
  232. package/providers/index.js +0 -23
  233. package/providers/resolve-provider.js +0 -93
  234. package/providers/runtime-detection.js +0 -124
  235. package/queues/providers/index.js +0 -11
  236. package/queues/providers/netlify-background-provider.js +0 -150
  237. package/queues/providers/qstash-queue-provider.js +0 -219
  238. package/queues/providers/sqs-queue-provider.js +0 -70
  239. package/queues/queue-client-interface.js +0 -55
  240. package/queues/queue-message-auth.js +0 -193
  241. package/queues/queue-provider-factory.js +0 -101
  242. package/queues/queue-provider.js +0 -65
  243. package/queues/sqs-queue-client.js +0 -81
  244. package/types/modules/index.d.ts +0 -214
  245. package/types/user/index.d.ts +0 -134
  246. package/user/adopter-jwt-config.js +0 -177
  247. package/user/adopter-jwt-errors.js +0 -59
  248. package/user/adopter-token-verifier.js +0 -122
  249. package/user/app-user-helpers.js +0 -97
  250. package/user/create-user-authentication.js +0 -64
  251. package/user/membership.js +0 -51
  252. package/user/repositories/organization-membership-record.js +0 -19
  253. package/user/repositories/organization-membership-repository-documentdb.js +0 -106
  254. package/user/repositories/organization-membership-repository-factory.js +0 -42
  255. package/user/repositories/organization-membership-repository-interface.js +0 -57
  256. package/user/repositories/organization-membership-repository-mongo.js +0 -13
  257. package/user/repositories/organization-membership-repository-postgres.js +0 -29
  258. package/user/repositories/organization-membership-repository-prisma.js +0 -81
  259. package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
  260. package/user/use-cases/ensure-organization-membership.js +0 -92
  261. package/user/use-cases/find-individual-users-by-organization.js +0 -54
@@ -1,144 +0,0 @@
1
- const {
2
- MANAGEMENT_API_VERSIONS,
3
- V1_ROUTES,
4
- META_ROUTES,
5
- V1_MIGRATION_DOCS_URL,
6
- listV2Routes,
7
- toGatewayPath,
8
- } = require('../route-registry');
9
- const { SCHEMAS, RESPONSES, SECURITY_SCHEMES } = require('./components');
10
- const { V2_OPERATIONS, META_OPERATIONS } = require('./v2-operations');
11
- const { V1_OPERATIONS } = require('./v1-operations');
12
- const { version: coreVersion } = require('../../package.json');
13
-
14
- const COMPATIBILITY_RULES = `
15
- Compatibility (ADR-053): within a major, changes are additive only. Clients
16
- must ignore response fields and enum values they do not know. Operations
17
- marked \`x-frigg-stability: beta\` may still change in a core minor.
18
-
19
- Errors: \`{ "error": { "code", "message", "details"? } }\`. Every response
20
- carries \`Frigg-API-Version: 2\`.`;
21
-
22
- const DESCRIPTIONS = {
23
- 1: `The original, unprefixed Management API. Deprecated (ADR-053): every response carries
24
- \`Deprecation\` and \`Link: <${V1_MIGRATION_DOCS_URL}>; rel="deprecation"\`. It is frozen,
25
- and \`managementApi.v1: false\` turns it off. Use v2.`,
26
- 2: `Integrations, entities, credentials, multi-step authorization and the entity proxy, under
27
- \`/api/v2\`. Discover what a deployment serves with \`GET /api/meta\`.
28
- ${COMPATIBILITY_RULES}`,
29
- };
30
-
31
- const TAGS = [
32
- { name: 'Integrations', description: 'Integrations between connected entities' },
33
- { name: 'Entities', description: 'Connected accounts, entity types and the entity proxy' },
34
- { name: 'Credentials', description: 'Stored credentials (always masked) and re-authorization' },
35
- { name: 'Authorization', description: 'Single- and multi-step authorization' },
36
- { name: 'Meta', description: 'Version-neutral discovery' },
37
- ];
38
-
39
- /** Path parameters, derived from the Express path. */
40
- function pathParameters(expressPath) {
41
- return [...expressPath.matchAll(/:([A-Za-z0-9_]+)/g)].map(([, name]) => ({
42
- name,
43
- in: 'path',
44
- required: true,
45
- schema: { type: 'string' },
46
- }));
47
- }
48
-
49
- function operationFor(route, docs, extra = {}) {
50
- if (!docs) {
51
- throw new Error(
52
- `No OpenAPI documentation for ${route.method} ${route.path} (${route.operationId || 'v1'})`
53
- );
54
- }
55
- const parameters = [...pathParameters(route.path), ...(docs.parameters || [])];
56
- return {
57
- operationId: route.operationId,
58
- ...(route.tag && { tags: [route.tag] }),
59
- ...docs,
60
- ...(parameters.length && { parameters }),
61
- ...(route.stability && { 'x-frigg-stability': route.stability }),
62
- ...extra,
63
- };
64
- }
65
-
66
- function addOperation(paths, route, operation) {
67
- const path = toGatewayPath(route.path);
68
- paths[path] = paths[path] || {};
69
- // An ANY route (router.all in v1) is documented as GET and POST, the two
70
- // methods callers use.
71
- const methods = route.method === 'ANY' ? ['get', 'post'] : [route.method.toLowerCase()];
72
- for (const method of methods) {
73
- paths[path][method] = {
74
- ...operation,
75
- ...(methods.length > 1 && {
76
- operationId: `${operation.operationId}${method === 'get' ? '' : 'Post'}`,
77
- }),
78
- };
79
- }
80
- }
81
-
82
- /**
83
- * Builds the OpenAPI 3 document for one Management API major from the route
84
- * registry (ADR-053 §5).
85
- *
86
- * @param {string} major - '1' or '2'
87
- * @param {Object} [options]
88
- * @param {boolean} [options.proxy=true] - include the entity proxy (served
89
- * documents follow managementApi.proxy.enable)
90
- * @returns {Object}
91
- */
92
- function buildOpenApiDocument(major, { proxy = true } = {}) {
93
- const info = MANAGEMENT_API_VERSIONS[major];
94
- if (!info) throw new Error(`Unknown Management API version: ${major}`);
95
-
96
- const paths = {};
97
- if (major === '1') {
98
- for (const route of V1_ROUTES) {
99
- const key = `${route.method} ${route.path}`;
100
- addOperation(
101
- paths,
102
- route,
103
- operationFor({ ...route, operationId: V1_OPERATIONS[key]?.operationId }, V1_OPERATIONS[key], {
104
- deprecated: true,
105
- })
106
- );
107
- }
108
- } else {
109
- for (const route of listV2Routes({ proxy })) {
110
- addOperation(paths, route, operationFor(route, V2_OPERATIONS[route.operationId]));
111
- }
112
- }
113
- for (const route of META_ROUTES) {
114
- addOperation(
115
- paths,
116
- route,
117
- operationFor({ ...route, tag: 'Meta' }, META_OPERATIONS[route.operationId])
118
- );
119
- }
120
-
121
- return {
122
- openapi: '3.0.3',
123
- info: {
124
- title: `Frigg Management API v${major}`,
125
- version: coreVersion,
126
- description: DESCRIPTIONS[major],
127
- license: { name: 'MIT' },
128
- },
129
- 'x-frigg-api-version': major,
130
- 'x-frigg-api-status': info.status,
131
- ...(info.deprecatedAt && { 'x-frigg-deprecated-at': info.deprecatedAt }),
132
- servers: [{ url: '/', description: 'This Frigg deployment' }],
133
- security: [{ bearerAuth: [] }, { friggApiKey: [] }],
134
- tags: TAGS,
135
- paths,
136
- components: {
137
- schemas: SCHEMAS,
138
- responses: RESPONSES,
139
- securitySchemes: SECURITY_SCHEMES,
140
- },
141
- };
142
- }
143
-
144
- module.exports = { buildOpenApiDocument };
@@ -1,415 +0,0 @@
1
- /**
2
- * OpenAPI components for the Management API documents. The shapes match what
3
- * the v2 handlers return (management-api/v2/dto.js) and are reconciled with
4
- * packages/schemas/schemas/api-*.schema.json (a test checks the two agree).
5
- */
6
-
7
- const ref = (name) => ({ $ref: `#/components/schemas/${name}` });
8
-
9
- const nullable = (schema) => ({ ...schema, nullable: true });
10
-
11
- // Whose a record is and what the caller may do with it (ADR-056 §3.4). Added to
12
- // entities, credentials and integrations by the list and get use cases.
13
- const tenancyProperties = {
14
- scope: { type: 'string', enum: ['individual', 'organization'], description: 'Whose it is. `global` records are not shown to tenants.' },
15
- owner: {
16
- type: 'object',
17
- properties: { type: { type: 'string', enum: ['individual', 'organization'] }, id: { type: 'string' } },
18
- description: "The user that owns it: the person, or the organization's user",
19
- },
20
- organizationId: nullable({
21
- type: 'string',
22
- description:
23
- 'The organization it belongs to. Null for an individual entity connected outside an organization, or under ownership.individualAcross "all".',
24
- }),
25
- access: {
26
- type: 'string',
27
- enum: ['manage', 'use', 'view'],
28
- description: 'manage (create, reauthorize, delete), use (bind it, proxy through it) or view (metadata only)',
29
- },
30
- };
31
-
32
- const errorBody = {
33
- type: 'object',
34
- required: ['error'],
35
- properties: {
36
- error: {
37
- type: 'object',
38
- required: ['code', 'message'],
39
- properties: {
40
- code: {
41
- type: 'string',
42
- description:
43
- 'Machine-readable code, e.g. VALIDATION_ERROR, NOT_FOUND, ENTITY_NOT_FOUND, AUTHORIZATION_SESSION_NOT_FOUND, PROXY_NOT_ALLOWED, PROXY_UNKNOWN_BASE. New codes may be added.',
44
- },
45
- message: { type: 'string' },
46
- details: { description: 'Optional structured details' },
47
- },
48
- },
49
- },
50
- };
51
-
52
- const authorizationRequirements = {
53
- type: 'object',
54
- required: ['type', 'data', 'step', 'totalSteps', 'isMultiStep'],
55
- properties: {
56
- type: {
57
- type: 'string',
58
- description: 'oauth2, api-key, basic, form, or a module-specific step type (e.g. email, otp)',
59
- },
60
- data: {
61
- type: 'object',
62
- description:
63
- 'Step data: { url } for OAuth2, { jsonSchema, uiSchema } for forms',
64
- additionalProperties: true,
65
- },
66
- step: { type: 'integer', minimum: 1 },
67
- totalSteps: { type: 'integer', minimum: 1 },
68
- isMultiStep: { type: 'boolean' },
69
- sessionId: {
70
- type: 'string',
71
- description: 'Present for multi-step flows; send it with every later step',
72
- },
73
- },
74
- };
75
-
76
- const SCHEMAS = {
77
- Error: errorBody,
78
-
79
- Integration: {
80
- type: 'object',
81
- required: ['id', 'entities', 'status', 'config'],
82
- properties: {
83
- id: { type: 'string' },
84
- entities: {
85
- type: 'array',
86
- items: {},
87
- description: 'Entity ids (or entity summaries) the integration connects',
88
- },
89
- status: nullable({ type: 'string', description: 'e.g. ENABLED, DISABLED, ERROR, NEEDS_CONFIG' }),
90
- config: { type: 'object', additionalProperties: true },
91
- version: nullable({ type: 'string' }),
92
- messages: { type: 'object', additionalProperties: true },
93
- ...tenancyProperties,
94
- },
95
- },
96
- ListIntegrationsResponse: {
97
- type: 'object',
98
- required: ['integrations'],
99
- properties: { integrations: { type: 'array', items: ref('Integration') } },
100
- },
101
- ListIntegrationOptionsResponse: {
102
- type: 'object',
103
- required: ['integrations'],
104
- properties: {
105
- integrations: {
106
- type: 'array',
107
- items: { type: 'object', additionalProperties: true },
108
- description: 'Integration types this app offers (each integration Definition option details)',
109
- },
110
- },
111
- },
112
- CreateIntegrationRequest: {
113
- type: 'object',
114
- required: ['entities', 'config'],
115
- properties: {
116
- entities: {
117
- type: 'array',
118
- items: { type: 'string' },
119
- description: 'Ids of entities the caller owns',
120
- },
121
- config: {
122
- type: 'object',
123
- required: ['type'],
124
- properties: { type: { type: 'string', description: 'Integration name' } },
125
- additionalProperties: true,
126
- },
127
- },
128
- },
129
- UpdateIntegrationRequest: {
130
- type: 'object',
131
- required: ['config'],
132
- properties: { config: { type: 'object', additionalProperties: true } },
133
- },
134
- AuthTestResult: {
135
- type: 'object',
136
- required: ['status'],
137
- properties: {
138
- status: { type: 'string', enum: ['ok', 'failed'] },
139
- errors: { type: 'array', items: { type: 'object', additionalProperties: true } },
140
- },
141
- },
142
-
143
- Entity: {
144
- type: 'object',
145
- required: ['id', 'type', 'userId'],
146
- properties: {
147
- id: { type: 'string' },
148
- type: nullable({ type: 'string', description: 'Module name' }),
149
- name: nullable({ type: 'string' }),
150
- externalId: nullable({ type: 'string' }),
151
- credentialId: nullable({ type: 'string' }),
152
- userId: nullable({ type: 'string' }),
153
- authIsValid: nullable({ type: 'boolean' }),
154
- ...tenancyProperties,
155
- },
156
- },
157
- ListEntitiesResponse: {
158
- type: 'object',
159
- required: ['entities'],
160
- properties: { entities: { type: 'array', items: ref('Entity') } },
161
- },
162
- EntityType: {
163
- type: 'object',
164
- required: ['type', 'name', 'authType', 'isMultiStep', 'stepCount', 'usedBy'],
165
- properties: {
166
- type: { type: 'string' },
167
- name: { type: 'string' },
168
- description: { type: 'string' },
169
- usedBy: {
170
- type: 'array',
171
- items: { type: 'string' },
172
- description:
173
- 'Names of the integrations that bind this entity type. Empty for a type registered only in appDefinition.entities.',
174
- },
175
- authType: { type: 'string', description: 'oauth2, oauth1, api-key, basic or custom' },
176
- isMultiStep: { type: 'boolean' },
177
- stepCount: { type: 'integer', minimum: 1 },
178
- capabilities: {},
179
- scope: {
180
- type: 'object',
181
- description:
182
- 'The scope a new connection of this type gets and the scopes a request may choose (ADR-056 §3.1). `global` is never offered.',
183
- properties: {
184
- default: { type: 'string', enum: ['individual', 'organization', 'global'] },
185
- allow: { type: 'array', items: { type: 'string', enum: ['individual', 'organization'] } },
186
- source: { type: 'string', enum: ['binding', 'integration', 'entityType', 'app', 'default'] },
187
- },
188
- },
189
- },
190
- },
191
- ListEntityTypesResponse: {
192
- type: 'object',
193
- required: ['types'],
194
- properties: { types: { type: 'array', items: ref('EntityType') } },
195
- },
196
-
197
- Credential: {
198
- type: 'object',
199
- required: ['id', 'type', 'userId', 'authIsValid'],
200
- description: 'Every provider field in data is masked; values never leave the server.',
201
- properties: {
202
- id: { type: 'string' },
203
- type: nullable({ type: 'string', description: 'Module name, from the entities using it' }),
204
- externalId: nullable({ type: 'string' }),
205
- userId: nullable({ type: 'string' }),
206
- authIsValid: nullable({ type: 'boolean' }),
207
- entityIds: { type: 'array', items: { type: 'string' } },
208
- entityCount: { type: 'integer', minimum: 0 },
209
- ...tenancyProperties,
210
- createdAt: nullable({ type: 'string', format: 'date-time' }),
211
- updatedAt: nullable({ type: 'string', format: 'date-time' }),
212
- data: {
213
- type: 'object',
214
- additionalProperties: true,
215
- description: 'Masked provider fields, e.g. { "access_token": "****WXYZ" }',
216
- },
217
- },
218
- },
219
- ListCredentialsResponse: {
220
- type: 'object',
221
- required: ['credentials'],
222
- properties: { credentials: { type: 'array', items: ref('Credential') } },
223
- },
224
-
225
- AuthorizationRequirements: authorizationRequirements,
226
- AuthorizeRequest: {
227
- type: 'object',
228
- required: ['entityType', 'data'],
229
- properties: {
230
- entityType: { type: 'string', description: 'Module name' },
231
- data: { type: 'object', additionalProperties: true, description: 'OAuth callback params or step form data' },
232
- step: { type: 'integer', minimum: 1, default: 1 },
233
- sessionId: { type: 'string', description: 'Required for step 2 and later' },
234
- scope: {
235
- type: 'string',
236
- enum: ['individual', 'organization'],
237
- description:
238
- "The scope to connect at, from the entity type's allow list (ADR-056 §3.1). Omit to take the type's default. `global` is refused (403).",
239
- },
240
- },
241
- },
242
- ReauthorizeRequest: {
243
- type: 'object',
244
- required: ['data'],
245
- properties: {
246
- data: { type: 'object', additionalProperties: true },
247
- step: { type: 'integer', minimum: 1, default: 1 },
248
- sessionId: { type: 'string' },
249
- },
250
- },
251
- AuthorizeComplete: {
252
- type: 'object',
253
- required: ['status', 'entity', 'credential'],
254
- properties: {
255
- status: { type: 'string', enum: ['complete'] },
256
- entity: ref('Entity'),
257
- credential: ref('Credential'),
258
- previousCredentialId: {
259
- type: 'string',
260
- description: 'Re-authorization only: the credential being renewed, when the provider account changed and a new credential was stored',
261
- },
262
- },
263
- },
264
- AuthorizePending: {
265
- type: 'object',
266
- required: ['status', 'step', 'totalSteps', 'sessionId', 'requirements'],
267
- properties: {
268
- status: { type: 'string', enum: ['pending'] },
269
- step: { type: 'integer', minimum: 2 },
270
- totalSteps: { type: 'integer', minimum: 2 },
271
- sessionId: { type: 'string' },
272
- requirements: ref('AuthorizationRequirements'),
273
- message: { type: 'string', description: 'e.g. "Code sent to your email"' },
274
- },
275
- },
276
- AuthorizeResponse: {
277
- oneOf: [ref('AuthorizeComplete'), ref('AuthorizePending')],
278
- discriminator: { propertyName: 'status' },
279
- },
280
-
281
- ProxyRequest: {
282
- type: 'object',
283
- required: ['method', 'path'],
284
- properties: {
285
- method: { type: 'string', enum: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'] },
286
- path: {
287
- type: 'string',
288
- pattern: '^/',
289
- description:
290
- "Path relative to the module's base URL (the one named by `base`). No //, backslashes, ? or #, dot segments, encoded separators or double encoding. The host always comes from the module.",
291
- },
292
- base: {
293
- type: 'string',
294
- pattern: '^[a-z][a-z0-9-]*$',
295
- description:
296
- "Name of one of the module's base URLs (ADR-052 amendment); default when omitted. A name the module declares, never a URL or host. An unknown name is 400 PROXY_UNKNOWN_BASE.",
297
- },
298
- query: {
299
- type: 'object',
300
- additionalProperties: {
301
- oneOf: [
302
- { type: 'string' },
303
- { type: 'number' },
304
- { type: 'boolean' },
305
- { type: 'array', items: { type: 'string' } },
306
- ],
307
- },
308
- description:
309
- 'Array values are sent comma-separated (`ids: ["1","2"]` → `ids=1,2`), except under a key ending in `[]`, which is sent once per value (`"fields[]": ["a","b"]` → `fields%5B%5D=a&fields%5B%5D=b`; an empty array sends nothing).',
310
- },
311
- headers: {
312
- type: 'object',
313
- additionalProperties: { type: 'string' },
314
- description:
315
- 'Only accept, content-type, accept-language, if-match, if-none-match and module-listed headers are forwarded. Credential, Host and forwarding headers are refused.',
316
- },
317
- body: { description: 'JSON value or string; POST, PUT, PATCH and DELETE only' },
318
- },
319
- },
320
- ProxyResponse: {
321
- type: 'object',
322
- required: ['success', 'status', 'headers', 'data'],
323
- properties: {
324
- success: { type: 'boolean', description: 'False for relayed upstream 4xx' },
325
- status: { type: 'integer', description: 'Upstream status; also the HTTP status of this response' },
326
- headers: { type: 'object', additionalProperties: { type: 'string' } },
327
- data: { description: 'Parsed JSON, text, or base64 when dataEncoding is set' },
328
- dataEncoding: { type: 'string', enum: ['base64'] },
329
- },
330
- },
331
- ProxyError: {
332
- type: 'object',
333
- required: ['success', 'status', 'error'],
334
- properties: {
335
- success: { type: 'boolean', enum: [false] },
336
- status: { type: 'integer' },
337
- error: errorBody.properties.error,
338
- },
339
- },
340
-
341
- ApiMeta: {
342
- type: 'object',
343
- required: ['api', 'capabilities'],
344
- properties: {
345
- api: {
346
- type: 'object',
347
- required: ['versions', 'preferred'],
348
- properties: {
349
- versions: {
350
- type: 'object',
351
- additionalProperties: {
352
- type: 'object',
353
- required: ['status', 'openapi'],
354
- properties: {
355
- status: { type: 'string', enum: ['stable', 'beta', 'deprecated', 'disabled'] },
356
- deprecatedAt: { type: 'string', format: 'date' },
357
- sunset: nullable({ type: 'string', format: 'date' }),
358
- openapi: { type: 'string' },
359
- },
360
- },
361
- },
362
- preferred: { type: 'string' },
363
- },
364
- },
365
- capabilities: {
366
- type: 'array',
367
- items: { type: 'string' },
368
- description: 'Stable feature flags, e.g. credentials, multiStepAuthorize, entityProxy',
369
- },
370
- frigg: {
371
- type: 'object',
372
- description: 'Only for callers with x-frigg-admin-api-key',
373
- properties: { coreVersion: { type: 'string' } },
374
- },
375
- },
376
- },
377
- };
378
-
379
- const errorResponse = (description) => ({
380
- description,
381
- content: { 'application/json': { schema: ref('Error') } },
382
- });
383
-
384
- const RESPONSES = {
385
- BadRequest: errorResponse('Invalid request (VALIDATION_ERROR, INVALID_JSON, INVALID_STEP, ...)'),
386
- Unauthorized: errorResponse('Missing or invalid authentication'),
387
- Forbidden: errorResponse('Not allowed'),
388
- NotFound: errorResponse('Not found, or not owned by the caller'),
389
- Conflict: errorResponse('Conflicts with the current state'),
390
- Gone: errorResponse('This API version is disabled for the app'),
391
- BadGateway: errorResponse('The provider failed'),
392
- };
393
-
394
- const SECURITY_SCHEMES = {
395
- bearerAuth: {
396
- type: 'http',
397
- scheme: 'bearer',
398
- description: 'Frigg user token (POST /user/login) or, when enabled, an adopter JWT',
399
- },
400
- friggApiKey: {
401
- type: 'apiKey',
402
- in: 'header',
403
- name: 'x-frigg-api-key',
404
- description:
405
- 'Backend-to-backend shared secret. Send x-frigg-appuserid (and x-frigg-apporgid for organisation users) to act for a user.',
406
- },
407
- adminApiKey: {
408
- type: 'apiKey',
409
- in: 'header',
410
- name: 'x-frigg-admin-api-key',
411
- description: 'Admin key; on /api/meta it only adds the core version',
412
- },
413
- };
414
-
415
- module.exports = { SCHEMAS, RESPONSES, SECURITY_SCHEMES, ref };
@@ -1,83 +0,0 @@
1
- /**
2
- * Documentation for the frozen Management API v1 routes, keyed by
3
- * "METHOD path" as in the route registry. Each names its v2 replacement
4
- * (docs/reference/api-reference.md has the full migration table).
5
- */
6
-
7
- const any = { description: 'Response body as returned by v1' };
8
- const v1 = (operationId, summary, replacement, extra = {}) => ({
9
- operationId,
10
- summary,
11
- description: replacement ? `Deprecated. Use ${replacement}.` : 'Deprecated.',
12
- responses: { 200: any },
13
- ...extra,
14
- });
15
-
16
- const V1_OPERATIONS = {
17
- 'GET /api/integrations': v1(
18
- 'v1ListIntegrations',
19
- 'List integrations, integration options and authorized entities in one response',
20
- 'GET /api/v2/integrations, GET /api/v2/integrations/options and GET /api/v2/entities'
21
- ),
22
- 'POST /api/integrations': v1('v1CreateIntegration', 'Create an integration', 'POST /api/v2/integrations', {
23
- responses: { 201: any },
24
- }),
25
- 'PATCH /api/integrations/:integrationId': v1('v1UpdateIntegration', 'Update an integration', 'PATCH /api/v2/integrations/{integrationId}'),
26
- 'DELETE /api/integrations/:integrationId': v1('v1DeleteIntegration', 'Delete an integration', 'DELETE /api/v2/integrations/{integrationId}', {
27
- responses: { 204: any },
28
- }),
29
- 'GET /api/integrations/:integrationId/config/options': v1(
30
- 'v1GetIntegrationConfigOptions',
31
- 'Get config options',
32
- 'GET /api/v2/integrations/{integrationId}/config/options'
33
- ),
34
- 'POST /api/integrations/:integrationId/config/options/refresh': v1(
35
- 'v1RefreshIntegrationConfigOptions',
36
- 'Refresh config options',
37
- 'POST /api/v2/integrations/{integrationId}/config/options/refresh'
38
- ),
39
- 'ANY /api/integrations/:integrationId/actions': v1(
40
- 'v1ListIntegrationActions',
41
- 'List user actions (any method)',
42
- 'GET /api/v2/integrations/{integrationId}/actions'
43
- ),
44
- 'ANY /api/integrations/:integrationId/actions/:actionId/options': v1(
45
- 'v1GetIntegrationActionOptions',
46
- 'Get user action options (any method)',
47
- 'POST /api/v2/integrations/{integrationId}/actions/{actionId}/options'
48
- ),
49
- 'POST /api/integrations/:integrationId/actions/:actionId/options/refresh': v1(
50
- 'v1RefreshIntegrationActionOptions',
51
- 'Refresh user action options',
52
- 'POST /api/v2/integrations/{integrationId}/actions/{actionId}/options/refresh'
53
- ),
54
- 'POST /api/integrations/:integrationId/actions/:actionId': v1(
55
- 'v1RunIntegrationAction',
56
- 'Run an integration event',
57
- 'POST /api/v2/integrations/{integrationId}/actions/{actionId} (user actions only)'
58
- ),
59
- 'GET /api/integrations/:integrationId': v1('v1GetIntegration', 'Get an integration', 'GET /api/v2/integrations/{integrationId}'),
60
- 'GET /api/integrations/:integrationId/test-auth': v1(
61
- 'v1TestIntegrationAuth',
62
- 'Test integration auth',
63
- 'GET /api/v2/integrations/{integrationId}/test-auth'
64
- ),
65
- 'GET /api/authorize': v1('v1GetAuthorizeRequirements', 'Get authorization requirements', 'GET /api/v2/authorize'),
66
- 'POST /api/authorize': v1('v1Authorize', 'Authorize an entity', 'POST /api/v2/authorize'),
67
- 'POST /api/entity': v1('v1CreateEntity', 'Create an entity from a credential', 'POST /api/v2/authorize (authorization creates the entity)'),
68
- 'GET /api/entity/options/:credentialId': v1(
69
- 'v1GetEntityOptionsByCredential',
70
- 'Get entity options for a credential',
71
- 'GET /api/v2/entities/{entityId}/options'
72
- ),
73
- 'GET /api/entities/:entityId/test-auth': v1('v1TestEntityAuth', 'Test entity auth', 'GET /api/v2/entities/{entityId}/test-auth'),
74
- 'GET /api/entities/:entityId': v1('v1GetEntity', 'Get an entity', 'GET /api/v2/entities/{entityId}'),
75
- 'POST /api/entities/:entityId/options': v1('v1GetEntityOptions', 'Get entity options', 'GET /api/v2/entities/{entityId}/options'),
76
- 'POST /api/entities/:entityId/options/refresh': v1(
77
- 'v1RefreshEntityOptions',
78
- 'Refresh entity options',
79
- 'POST /api/v2/entities/{entityId}/options/refresh'
80
- ),
81
- };
82
-
83
- module.exports = { V1_OPERATIONS };