@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
@@ -2,27 +2,21 @@ const { findNearestBackendPackageJson } = require('@friggframework/core/utils');
2
2
  const path = require('node:path');
3
3
  const fs = require('fs-extra');
4
4
  const { resolveTelemetryConfig } = require('../telemetry/telemetry-config');
5
- const { assertAdopterJwtConfig } = require('../user/adopter-jwt-config');
6
5
  const { registerDeniedKeys } = require('../logs/denied-keys');
7
6
  const {
8
7
  extractCredentialFieldsFromModules,
9
8
  } = require('../database/encryption/encryption-schema-registry');
10
9
  const {
11
- getEntityTypeRegistry,
12
- getEntityTypeDefinitions,
13
- } = require('../modules/entity-type-registry');
14
- const { resolveOwnershipConfig } = require('../modules/entity-scope');
15
- const { assertProxyConfig } = require('../modules/proxy/proxy-bases');
16
- const {
17
- resolveManagementApiConfig,
18
- } = require('../management-api/management-api-config');
19
- const { resolveScheduleConfig } = require('../integrations/schedule-config');
10
+ getModulesDefinitionFromIntegrationClasses,
11
+ } = require('../integrations/utils/map-integration-dto');
20
12
 
21
13
  // Handlers without a database never load the encryption registry, so the
22
14
  // credential leaf keys are registered for redaction here too.
23
- function registerCredentialLogKeys(appDefinition, moduleDefinitions) {
15
+ function registerCredentialLogKeys(appDefinition, integrations) {
24
16
  try {
25
- extractCredentialFieldsFromModules(moduleDefinitions);
17
+ extractCredentialFieldsFromModules(
18
+ getModulesDefinitionFromIntegrationClasses(integrations)
19
+ );
26
20
  } catch {
27
21
  // An odd integration shape must not stop the app from loading.
28
22
  }
@@ -35,53 +29,18 @@ function registerCredentialLogKeys(appDefinition, moduleDefinitions) {
35
29
  }
36
30
 
37
31
  /**
38
- * The definition handed to setAppDefinition(), or null when the backend is
39
- * discovered from process.cwd().
40
- */
41
- let presetDefinition = null;
42
-
43
- /**
44
- * Pre-set the app definition so loadAppDefinition() does not discover the
45
- * backend through process.cwd().
46
- *
47
- * Platforms such as Netlify need this: the function bundler (nft/esbuild)
48
- * only traces static require() calls, and at runtime process.cwd() is the
49
- * function root, not the backend. A generated function entry point therefore
50
- * requires the backend's index.js statically and passes its Definition here.
51
- *
52
- * The preset definition is validated and derived exactly like a discovered
53
- * one: adopter-JWT config, the entity registry, ownership and the Management
54
- * API config all apply, so a Netlify function and an AWS Lambda load the
55
- * same app the same way. Pass null to clear it.
56
- *
57
- * @param {Object|null} definition - the backend's `Definition` export
58
- */
59
- function setAppDefinition(definition) {
60
- if (
61
- definition !== null &&
62
- (typeof definition !== 'object' || Array.isArray(definition))
63
- ) {
64
- throw new TypeError(
65
- 'setAppDefinition expects the app Definition object (or null)'
66
- );
67
- }
68
- presetDefinition = definition;
69
- }
70
-
71
- /**
72
- * The definition preset with setAppDefinition(), unvalidated, or null.
73
- *
74
- * For low-level readers that only need one raw field before the app is
75
- * fully loaded (the database type, the custom encryption schema) and keep
76
- * their own process.cwd() discovery as the fallback.
77
- *
78
- * @returns {Object|null}
32
+ * Loads the App definition from the nearest backend package
33
+ * @function loadAppDefinition
34
+ * @description Searches for the nearest backend package.json, loads the corresponding index.js file,
35
+ * and extracts the application definition containing integrations and user configuration.
36
+ * @returns {{integrations: Array<object>, userConfig: object | null, adminScripts: Array<object>, reports: Array<object>, admin: object, telemetry: object, logging: object | null}} An object containing the application definition.
37
+ * @throws {Error} Throws error if backend package.json cannot be found.
38
+ * @throws {Error} Throws error if index.js file cannot be found in the backend directory.
39
+ * @example
40
+ * const { integrations, userConfig, telemetry } = loadAppDefinition();
41
+ * console.log(`Found ${integrations.length} integrations`);
79
42
  */
80
- function getPresetAppDefinition() {
81
- return presetDefinition;
82
- }
83
-
84
- function discoverAppDefinition() {
43
+ function loadAppDefinition() {
85
44
  const backendPath = findNearestBackendPackageJson();
86
45
  if (!backendPath) {
87
46
  throw new Error('Could not find backend package.json');
@@ -94,78 +53,18 @@ function discoverAppDefinition() {
94
53
  }
95
54
 
96
55
  const backendJsFile = require(backendFilePath);
97
- return backendJsFile.Definition;
98
- }
56
+ const appDefinition = backendJsFile.Definition;
99
57
 
100
- /**
101
- * Loads the App definition: the one preset with setAppDefinition(), or the
102
- * nearest backend package's index.js.
103
- * @function loadAppDefinition
104
- * @description Uses the definition preset by setAppDefinition() when there is one; otherwise searches for the nearest backend package.json, loads the corresponding index.js file,
105
- * and extracts the application definition containing integrations and user configuration.
106
- * @returns {{appDefinition: object, integrations: Array<object>, entities: object | null, entityTypeRegistry: Map<string, object>, moduleDefinitions: Array<object>, ownership: {scope: ({default: string, allow: string[]}|null), individualAcross: string}, userConfig: object | null, adminScripts: Array<object>, reports: Array<object>, admin: object, telemetry: object, logging: object | null, managementApi: object}} An object containing the application definition. `appDefinition` is the raw Definition object.
107
- * @throws {Error} Throws error if backend package.json cannot be found.
108
- * @throws {Error} Throws error if index.js file cannot be found in the backend directory.
109
- * @throws {Error} Throws error if user.authModes.adopterJwt is enabled without a usable user.jwtConfig.
110
- * @throws {OwnershipConfigError} Throws if an ownership or scope setting is invalid (ADR-056 §3.1).
111
- * @throws {ManagementApiConfigError} Throws if `managementApi.proxy.scopes` is invalid (ADR-056 §3.5).
112
- * @throws {ProxyConfigError} Throws if a module's `proxy.baseUrls` or an allow rule's `base` is invalid (ADR-052).
113
- * @throws {ScheduleConfigError} Throws if an integration's `Definition.schedule` is invalid.
114
- * @example
115
- * const { integrations, userConfig, telemetry } = loadAppDefinition();
116
- * console.log(`Found ${integrations.length} integrations`);
117
- */
118
- function loadAppDefinition() {
119
- const appDefinition = presetDefinition || discoverAppDefinition();
120
- return resolveAppDefinition(appDefinition);
121
- }
122
-
123
- function resolveAppDefinition(appDefinition) {
124
58
  const {
125
59
  integrations = [],
126
- entities = null,
127
60
  user: userConfig = null,
128
61
  adminScripts = [],
129
62
  reports = [],
130
63
  admin = {},
131
64
  logging = null,
132
- managementApi = {},
133
65
  } = appDefinition;
134
66
 
135
- // Fail at load, not on the first request: an adopter-token mode with no
136
- // key source would otherwise start cleanly and answer every login with 500.
137
- assertAdopterJwtConfig(userConfig);
138
-
139
- // Fail fast: a bad `entities` registry (key/name mismatch, conflicting
140
- // definitions, `$infer: false` with an unregistered module) must stop the
141
- // app at load, not on the first request that needs a module.
142
- const entityTypeRegistry = getEntityTypeRegistry(appDefinition);
143
- const moduleDefinitions = getEntityTypeDefinitions(entityTypeRegistry);
144
-
145
- // Same reason for entity scopes (ADR-056 §3.1): a mistyped scope, an unknown
146
- // `individualAcross`, or an organization-owned integration that binds an
147
- // individual entity stops the app at load.
148
- const ownership = resolveOwnershipConfig(appDefinition, entityTypeRegistry);
149
-
150
- // And for the Management API: `managementApi.proxy.scopes` decides whose
151
- // credentials the entity proxy may act through (ADR-056 §3.5), so an
152
- // unknown scope stops the app here rather than being read as a default.
153
- const managementApiConfig = resolveManagementApiConfig(managementApi);
154
-
155
- // Named proxy bases (ADR-052 amendment): a module that declares both
156
- // `baseUrl` and `baseUrls`, a bad base URL or name, or an allow rule for a
157
- // base the module lacks, stops the app here.
158
- assertProxyConfig(moduleDefinitions, managementApiConfig.proxy);
159
-
160
- // And for each integration's `Definition.schedule`: a mistyped scope would
161
- // otherwise tick ONGOING_SYNC per class when per installation was meant.
162
- for (const IntegrationClass of integrations) {
163
- if (IntegrationClass?.Definition) {
164
- resolveScheduleConfig(IntegrationClass.Definition);
165
- }
166
- }
167
-
168
- registerCredentialLogKeys(appDefinition, moduleDefinitions);
67
+ registerCredentialLogKeys(appDefinition, integrations);
169
68
 
170
69
  // Degrade consistently: an invalid telemetry block must never take down a
171
70
  // router bundle that loads the app definition at module scope (telemetry is
@@ -189,24 +88,16 @@ function resolveAppDefinition(appDefinition) {
189
88
  }
190
89
 
191
90
  return {
192
- appDefinition,
193
91
  integrations,
194
- entities,
195
- entityTypeRegistry,
196
- moduleDefinitions,
197
- ownership,
198
92
  userConfig,
199
93
  adminScripts,
200
94
  reports,
201
95
  admin,
202
96
  telemetry,
203
97
  logging,
204
- managementApi,
205
98
  };
206
99
  }
207
100
 
208
101
  module.exports = {
209
102
  loadAppDefinition,
210
- setAppDefinition,
211
- getPresetAppDefinition,
212
103
  };
@@ -6,12 +6,6 @@ const bodyParser = require('body-parser');
6
6
  const cors = require('cors');
7
7
  const Boom = require('@hapi/boom');
8
8
  const serverlessHttp = require('serverless-http');
9
- const {
10
- API_VERSION_HEADER,
11
- isVersionedManagementApiPath,
12
- toBoom,
13
- toV2ErrorBody,
14
- } = require('../management-api/error-response');
15
9
 
16
10
  const log = getLogger('frigg.http');
17
11
 
@@ -32,15 +26,11 @@ const createApp = (applyMiddleware) => {
32
26
  if (applyMiddleware) applyMiddleware(app);
33
27
 
34
28
  // The express boundary: send the error response and log it one time.
35
- // A Boom error keeps its status; other errors keep theirs only when they
36
- // mark a 4xx safe to expose (body-parser's 400/413 via http-errors), so a
37
- // malformed body is a 400, not a 500.
38
29
  app.use((err, req, res, next) => {
39
- const boomError = toBoom(err);
30
+ const boomError = err.isBoom ? err : Boom.boomify(err);
40
31
  const {
41
32
  output: { statusCode = 500 },
42
33
  } = boomError;
43
- const versioned = isVersionedManagementApiPath(req.path);
44
34
 
45
35
  if (statusCode >= 500) {
46
36
  log.error('Request failed', {
@@ -49,6 +39,7 @@ const createApp = (applyMiddleware) => {
49
39
  invocation: summarizeExpressRequest(req),
50
40
  error: boomError,
51
41
  });
42
+ res.status(statusCode).json({ error: 'Internal Server Error' });
52
43
  } else {
53
44
  // A client error needs no stack; the logger scrubs the reason.
54
45
  log.warn('Request rejected', {
@@ -56,21 +47,8 @@ const createApp = (applyMiddleware) => {
56
47
  statusCode,
57
48
  reason: boomError.message,
58
49
  });
50
+ res.status(statusCode).json({ error: err.message });
59
51
  }
60
-
61
- if (versioned) {
62
- // Management API v2 / meta: { error: { code, message, details? } }.
63
- if (req.path.startsWith('/api/v2')) {
64
- res.set(API_VERSION_HEADER, '2');
65
- }
66
- return res.status(statusCode).json(toV2ErrorBody(boomError));
67
- }
68
-
69
- // v1 and other routes keep their historical body.
70
- if (statusCode >= 500) {
71
- return res.status(statusCode).json({ error: 'Internal Server Error' });
72
- }
73
- return res.status(statusCode).json({ error: err.message });
74
52
  });
75
53
 
76
54
  return app;
@@ -18,9 +18,8 @@ const {
18
18
  createModuleRepository,
19
19
  } = require('../modules/repositories/module-repository-factory');
20
20
  const {
21
- getEntityTypeRegistry,
22
- getEntityTypeDefinitions,
23
- } = require('../modules/entity-type-registry');
21
+ getModulesDefinitionFromIntegrationClasses,
22
+ } = require('../integrations/utils/map-integration-dto');
24
23
  const { processNotFound } = require('../integrations/use-cases/process-errors');
25
24
 
26
25
  const loadRouterFromObject = (IntegrationClass, routerObject) => {
@@ -62,18 +61,30 @@ const initializeRepositories = () => {
62
61
  return { processRepository, integrationRepository, moduleRepository };
63
62
  };
64
63
 
64
+ const createModuleFactoryWithDefinitions = (
65
+ moduleRepository,
66
+ integrationClasses
67
+ ) => {
68
+ const moduleDefinitions =
69
+ getModulesDefinitionFromIntegrationClasses(integrationClasses);
70
+
71
+ return new ModuleFactory({
72
+ moduleRepository,
73
+ moduleDefinitions,
74
+ });
75
+ };
76
+
65
77
  const loadIntegrationForWebhook = async (integrationId) => {
66
78
  const { loadAppDefinition } = require('./app-definition-loader');
67
- const { integrations: integrationClasses, moduleDefinitions } =
68
- loadAppDefinition();
79
+ const { integrations: integrationClasses } = loadAppDefinition();
69
80
 
70
81
  const { integrationRepository, moduleRepository } =
71
82
  initializeRepositories();
72
83
 
73
- const moduleFactory = new ModuleFactory({
84
+ const moduleFactory = createModuleFactoryWithDefinitions(
74
85
  moduleRepository,
75
- moduleDefinitions,
76
- });
86
+ integrationClasses
87
+ );
77
88
 
78
89
  const getIntegrationInstance = new GetIntegrationInstance({
79
90
  integrationRepository,
@@ -118,23 +129,13 @@ const integrationExists = async (integrationId) => {
118
129
  }
119
130
  };
120
131
 
121
- const loadIntegrationForProcess = async (
122
- processId,
123
- integrationClass,
124
- moduleDefinitions
125
- ) => {
132
+ const loadIntegrationForProcess = async (processId, integrationClass) => {
126
133
  const { processRepository, integrationRepository, moduleRepository } =
127
134
  initializeRepositories();
128
135
 
129
- const moduleFactory = new ModuleFactory({
130
- moduleRepository,
131
- moduleDefinitions:
132
- moduleDefinitions ??
133
- // No app definition handed in: this integration's own modules only.
134
- getEntityTypeDefinitions(
135
- getEntityTypeRegistry({ integrations: [integrationClass] })
136
- ),
137
- });
136
+ const moduleFactory = createModuleFactoryWithDefinitions(moduleRepository, [
137
+ integrationClass,
138
+ ]);
138
139
 
139
140
  const getIntegrationInstance = new GetIntegrationInstance({
140
141
  integrationRepository,
@@ -160,13 +161,7 @@ const loadIntegrationForProcess = async (
160
161
  return instance;
161
162
  };
162
163
 
163
- /**
164
- * @param {Function} integrationClass
165
- * @param {{moduleDefinitions?: Array<object>}} [options] - the app's offered
166
- * module definitions (`loadAppDefinition().moduleDefinitions`). When omitted
167
- * the worker hydrates with this integration's own modules only.
168
- */
169
- const createQueueWorker = (integrationClass, { moduleDefinitions } = {}) => {
164
+ const createQueueWorker = (integrationClass) => {
170
165
  const integrationName = integrationClass.Definition.name;
171
166
 
172
167
  class QueueWorker extends Worker {
@@ -188,8 +183,7 @@ const createQueueWorker = (integrationClass, { moduleDefinitions } = {}) => {
188
183
  console.log(`[QueueWorker] hydrating by processId`, logCtx);
189
184
  integrationInstance = await loadIntegrationForProcess(
190
185
  params.data.processId,
191
- integrationClass,
192
- moduleDefinitions
186
+ integrationClass
193
187
  );
194
188
  console.log(`[QueueWorker] hydrated`, {
195
189
  ...logCtx,
@@ -29,19 +29,6 @@ function secretsMatch(provided, expected) {
29
29
  return crypto.timingSafeEqual(providedHash, expectedHash);
30
30
  }
31
31
 
32
- /**
33
- * True when `provided` matches the configured ADMIN_API_KEY. False when no
34
- * key is configured or none was provided. For callers that change a response
35
- * for admins rather than reject everyone else (GET /api/meta).
36
- * @param {string|undefined} provided
37
- * @returns {boolean}
38
- */
39
- function isValidAdminApiKey(provided) {
40
- const expectedKey = process.env.ADMIN_API_KEY;
41
- if (!expectedKey || !provided) return false;
42
- return secretsMatch(provided, expectedKey);
43
- }
44
-
45
32
  /**
46
33
  * Validate admin API key from request header
47
34
  * @param {import('express').Request} req
@@ -83,4 +70,4 @@ function validateAdminApiKey(req, res, next) {
83
70
  next();
84
71
  }
85
72
 
86
- module.exports = { validateAdminApiKey, isValidAdminApiKey };
73
+ module.exports = { validateAdminApiKey };
@@ -1,51 +1,15 @@
1
- const express = require('express');
2
- const {
3
- createManagementApiRouter,
4
- } = require('../../management-api/create-management-api-router');
5
- const {
6
- createExtensionRoutesRouter,
7
- } = require('../../extensions/route-mounter');
1
+ const { createIntegrationRouter } = require('@friggframework/core');
8
2
  const { createAppHandler } = require('./../app-handler-helpers');
9
3
 
10
- // The Management API (ADR-053): v2 under /api/v2, the deprecated v1 at the
11
- // unprefixed paths (or 410 when managementApi.v1 is false).
12
- //
13
- // Built on first access, not at require time (friggframework/frigg#545,
14
- // c40eca49): a host that presets the app definition (setAppDefinition, as
15
- // provider-netlify's function entry points do) can require this module
16
- // before or after doing so.
17
- let router;
18
- let handler;
4
+ const router = createIntegrationRouter();
19
5
 
20
- function buildRouter() {
21
- const built = express.Router();
22
- built.use(createManagementApiRouter());
6
+ router.route('/api/integrations/redirect/:appId').get((req, res) => {
7
+ res.redirect(
8
+ `${process.env.FRONTEND_URI}/redirect/${req.params.appId
9
+ }?${new URLSearchParams(req.query)}`
10
+ );
11
+ });
23
12
 
24
- // The OAuth provider's redirect target. Unversioned: it is neither part
25
- // of v1 nor v2, so it is never deprecated or disabled.
26
- built.route('/api/integrations/redirect/:appId').get((req, res) => {
27
- res.redirect(
28
- `${process.env.FRONTEND_URI}/redirect/${req.params.appId
29
- }?${new URLSearchParams(req.query)}`
30
- );
31
- });
13
+ const handler = createAppHandler('HTTP Event: Auth', router);
32
14
 
33
- // Core extension routes (appDefinition.coreExtensions[].routes), each
34
- // behind the admin API key.
35
- built.use(createExtensionRoutesRouter());
36
-
37
- return built;
38
- }
39
-
40
- module.exports = {
41
- get router() {
42
- if (!router) router = buildRouter();
43
- return router;
44
- },
45
- get handler() {
46
- if (!handler) {
47
- handler = createAppHandler('HTTP Event: Auth', module.exports.router);
48
- }
49
- return handler;
50
- },
51
- };
15
+ module.exports = { handler };
@@ -2,6 +2,9 @@ const { Router } = require('express');
2
2
  const { createAppHandler } = require('./../app-handler-helpers');
3
3
  const { loadAppDefinition } = require('./../app-definition-loader');
4
4
  const { ModuleFactory } = require('../../modules/module-factory');
5
+ const {
6
+ getModulesDefinitionFromIntegrationClasses,
7
+ } = require('../../integrations/utils/map-integration-dto');
5
8
  const {
6
9
  createModuleRepository,
7
10
  } = require('../../modules/repositories/module-repository-factory');
@@ -25,25 +28,18 @@ const {
25
28
  CheckIntegrationsHealthUseCase,
26
29
  } = require('../use-cases/check-integrations-health-use-case');
27
30
 
28
- const {
29
- createManagementApiMetaRouter,
30
- createDocsRedirectRouter,
31
- } = require('../../management-api/meta-router');
32
-
33
31
  const router = Router();
34
32
  const healthCheckRepository = createHealthCheckRepository({ prismaClient: prisma });
35
33
 
36
34
  // Load integrations and create factories just like auth router does
37
35
  // This verifies the system can properly load integrations
38
36
  let moduleFactory, integrationClasses;
39
- let appDefinition = {};
40
37
  try {
41
38
  const appDef = loadAppDefinition();
42
- appDefinition = appDef;
43
39
  integrationClasses = appDef.integrations || [];
44
40
 
45
41
  const moduleRepository = createModuleRepository();
46
- const { moduleDefinitions } = appDef;
42
+ const moduleDefinitions = getModulesDefinitionFromIntegrationClasses(integrationClasses);
47
43
 
48
44
  moduleFactory = new ModuleFactory({
49
45
  moduleRepository,
@@ -89,11 +85,6 @@ const validateApiKey = (req, res, next) => {
89
85
  next();
90
86
  };
91
87
 
92
- // Management API discovery (ADR-053 §4) and the /api/docs redirect to it are
93
- // public and DB-free, so they are mounted ahead of the health API key check.
94
- router.use(createManagementApiMetaRouter({ appDefinition }));
95
- router.use(createDocsRedirectRouter());
96
-
97
88
  router.use(validateApiKey);
98
89
 
99
90
  // Helper to detect VPC configuration