@friggframework/core 2.0.0--canary.707.df80bfd.0 → 2.0.0--canary.680.d670696.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 (161) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/CLAUDE.md +0 -28
  3. package/README.md +0 -105
  4. package/application/commands/integration-commands.js +2 -2
  5. package/application/commands/scheduler-commands.js +7 -11
  6. package/application/commands/user-commands.js +5 -17
  7. package/core/Worker.js +7 -31
  8. package/core/create-handler.js +0 -9
  9. package/credential/use-cases/credential-operations-for-user.js +25 -110
  10. package/credential/use-cases/reauthorize-credential-for-user.js +8 -15
  11. package/database/config.js +24 -48
  12. package/database/documentdb-encryption-service.js +0 -1
  13. package/database/documentdb-utils.js +1 -6
  14. package/database/encryption/encryption-config.js +44 -13
  15. package/database/encryption/encryption-schema-registry.js +31 -88
  16. package/database/prisma.js +2 -4
  17. package/generated/prisma-mongodb/edge.js +4 -27
  18. package/generated/prisma-mongodb/index-browser.js +1 -24
  19. package/generated/prisma-mongodb/index.d.ts +48 -3228
  20. package/generated/prisma-mongodb/index.js +4 -27
  21. package/generated/prisma-mongodb/package.json +1 -1
  22. package/generated/prisma-mongodb/schema.prisma +0 -65
  23. package/generated/prisma-mongodb/wasm.js +4 -27
  24. package/generated/prisma-postgresql/edge.js +4 -27
  25. package/generated/prisma-postgresql/index-browser.js +1 -24
  26. package/generated/prisma-postgresql/index.d.ts +51 -3503
  27. package/generated/prisma-postgresql/index.js +4 -27
  28. package/generated/prisma-postgresql/package.json +1 -1
  29. package/generated/prisma-postgresql/schema.prisma +0 -61
  30. package/generated/prisma-postgresql/wasm.js +4 -27
  31. package/handlers/app-definition-loader.js +12 -110
  32. package/handlers/routers/auth.js +12 -40
  33. package/handlers/routers/health.js +2 -4
  34. package/handlers/routers/integration-defined-routers.js +92 -144
  35. package/handlers/routers/integration-webhook-routers.js +64 -102
  36. package/index.js +1 -64
  37. package/infrastructure/scheduler/index.js +6 -19
  38. package/infrastructure/scheduler/scheduler-service-factory.js +7 -55
  39. package/integrations/index.js +0 -5
  40. package/integrations/integration-router.js +73 -115
  41. package/integrations/repositories/integration-repository-documentdb.js +3 -35
  42. package/integrations/repositories/integration-repository-interface.js +1 -17
  43. package/integrations/repositories/integration-repository-mongo.js +76 -59
  44. package/integrations/repositories/integration-repository-postgres.js +76 -62
  45. package/integrations/tests/doubles/test-integration-repository.js +1 -12
  46. package/integrations/use-cases/create-integration.js +20 -55
  47. package/integrations/use-cases/get-integrations-for-user.js +40 -80
  48. package/integrations/use-cases/index.js +1 -7
  49. package/integrations/use-cases/integration-operations-for-user.js +24 -55
  50. package/integrations/utils/map-integration-dto.js +1 -44
  51. package/management-api/management-api-config.js +2 -71
  52. package/management-api/meta-router.js +2 -21
  53. package/management-api/openapi/components.js +3 -50
  54. package/management-api/openapi/v2-operations.js +5 -17
  55. package/management-api/route-registry.js +6 -123
  56. package/management-api/v2/dependencies.js +15 -40
  57. package/management-api/v2/dto.js +0 -20
  58. package/management-api/v2/handlers/authorization.js +0 -1
  59. package/management-api/v2/handlers/credentials.js +2 -6
  60. package/management-api/v2/handlers/entities.js +7 -10
  61. package/management-api/v2/handlers/integrations.js +3 -6
  62. package/management-api/v2/request.js +1 -32
  63. package/modules/index.js +0 -8
  64. package/modules/module-factory.js +0 -12
  65. package/modules/module.js +2 -53
  66. package/modules/proxy/proxy-errors.js +1 -12
  67. package/modules/proxy/proxy-path.js +3 -7
  68. package/modules/proxy/proxy-policy.js +5 -34
  69. package/modules/repositories/module-repository-documentdb.js +6 -51
  70. package/modules/repositories/module-repository-interface.js +2 -19
  71. package/modules/repositories/module-repository-mongo.js +74 -67
  72. package/modules/repositories/module-repository-postgres.js +74 -66
  73. package/modules/repositories/module-repository.js +1 -2
  74. package/modules/requester/proxy-request.js +1 -2
  75. package/modules/requester/requester.js +3 -8
  76. package/modules/use-cases/entity-operations-for-user.js +13 -50
  77. package/modules/use-cases/entity-types.js +7 -31
  78. package/modules/use-cases/execute-entity-proxy-request.js +15 -107
  79. package/modules/use-cases/get-authorization-requirements.js +2 -2
  80. package/modules/use-cases/get-entities-for-user.js +13 -26
  81. package/modules/use-cases/get-entity-module-for-user.js +7 -34
  82. package/modules/use-cases/get-entity-options-by-id.js +4 -10
  83. package/modules/use-cases/get-entity-options-by-type.js +1 -1
  84. package/modules/use-cases/get-module-instance-from-type.js +1 -1
  85. package/modules/use-cases/get-module.js +4 -10
  86. package/modules/use-cases/multi-step-authorization.js +13 -40
  87. package/modules/use-cases/process-authorization-callback.js +19 -53
  88. package/modules/use-cases/refresh-entity-options.js +4 -10
  89. package/modules/use-cases/test-module-auth.js +4 -10
  90. package/package.json +5 -6
  91. package/prisma-mongodb/schema.prisma +0 -65
  92. package/prisma-postgresql/schema.prisma +0 -61
  93. package/queues/index.js +0 -25
  94. package/types/index.d.ts +0 -1
  95. package/types/modules/index.d.ts +1 -157
  96. package/user/repositories/user-repository-documentdb.js +2 -27
  97. package/user/repositories/user-repository-interface.js +0 -18
  98. package/user/repositories/user-repository-mongo.js +0 -24
  99. package/user/repositories/user-repository-postgres.js +0 -18
  100. package/user/use-cases/authenticate-user.js +1 -7
  101. package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
  102. package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
  103. package/user/user.js +1 -64
  104. package/database/organization-where.js +0 -18
  105. package/database/unique-violation.js +0 -25
  106. package/extensions/bootstrap-runner.js +0 -43
  107. package/extensions/extension-loader.js +0 -230
  108. package/extensions/index.js +0 -44
  109. package/extensions/initialize-app.js +0 -123
  110. package/extensions/prisma-composer.js +0 -270
  111. package/extensions/route-mounter.js +0 -103
  112. package/extensions/schema-composer.js +0 -188
  113. package/infrastructure/scheduler/netlify-scheduler-adapter.js +0 -216
  114. package/infrastructure/scheduler/scheduled-job-repository.js +0 -118
  115. package/integrations/repositories/integration-not-found.js +0 -14
  116. package/integrations/schedule-config.js +0 -80
  117. package/integrations/use-cases/dispatch-ongoing-syncs.js +0 -100
  118. package/integrations/use-cases/resolve-integration-ownership.js +0 -177
  119. package/modules/entity-scope.js +0 -15
  120. package/modules/proxy/proxy-bases.js +0 -169
  121. package/modules/repositories/entity-not-found.js +0 -18
  122. package/modules/scope-config.js +0 -192
  123. package/modules/scope-policy.js +0 -112
  124. package/modules/scope-resolution.js +0 -288
  125. package/modules/scope-visibility.js +0 -247
  126. package/modules/tests/doubles/ownership-matching.js +0 -18
  127. package/modules/use-cases/authorize-entity-for-user.js +0 -61
  128. package/modules/use-cases/create-entity-from-credential.js +0 -113
  129. package/modules/use-cases/manage-access.js +0 -21
  130. package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
  131. package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
  132. package/prisma-postgresql/migrations/20261017000000_add_scheduled_job/migration.sql +0 -28
  133. package/providers/index.js +0 -23
  134. package/providers/resolve-provider.js +0 -93
  135. package/providers/runtime-detection.js +0 -124
  136. package/queues/providers/index.js +0 -11
  137. package/queues/providers/netlify-background-provider.js +0 -150
  138. package/queues/providers/qstash-queue-provider.js +0 -219
  139. package/queues/providers/sqs-queue-provider.js +0 -70
  140. package/queues/queue-client-interface.js +0 -55
  141. package/queues/queue-message-auth.js +0 -193
  142. package/queues/queue-provider-factory.js +0 -101
  143. package/queues/queue-provider.js +0 -65
  144. package/queues/sqs-queue-client.js +0 -81
  145. package/types/user/index.d.ts +0 -134
  146. package/user/adopter-jwt-config.js +0 -177
  147. package/user/adopter-jwt-errors.js +0 -59
  148. package/user/adopter-token-verifier.js +0 -122
  149. package/user/app-user-helpers.js +0 -97
  150. package/user/create-user-authentication.js +0 -64
  151. package/user/membership.js +0 -51
  152. package/user/repositories/organization-membership-record.js +0 -19
  153. package/user/repositories/organization-membership-repository-documentdb.js +0 -106
  154. package/user/repositories/organization-membership-repository-factory.js +0 -42
  155. package/user/repositories/organization-membership-repository-interface.js +0 -57
  156. package/user/repositories/organization-membership-repository-mongo.js +0 -13
  157. package/user/repositories/organization-membership-repository-postgres.js +0 -29
  158. package/user/repositories/organization-membership-repository-prisma.js +0 -81
  159. package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
  160. package/user/use-cases/ensure-organization-membership.js +0 -92
  161. package/user/use-cases/find-individual-users-by-organization.js +0 -54
@@ -1,169 +1,117 @@
1
1
  const { createAppHandler } = require('./../app-handler-helpers');
2
- const { loadAppDefinition } = require('../app-definition-loader');
2
+ const {
3
+ loadAppDefinition,
4
+ } = require('../app-definition-loader');
3
5
  const express = require('express');
4
6
  const { Router } = express;
5
7
  const { loadRouterFromObject } = require('../backend-utils');
6
8
  const { getExtensionRoutes } = require('../../integrations/extension');
7
9
 
10
+ const handlers = {};
11
+ const { integrations: integrationClasses } = loadAppDefinition();
12
+
8
13
  const routeKey = (method, path) => `${(method || 'ANY').toUpperCase()} ${path}`;
9
14
 
10
15
  // Serverless function keys must be alphanumeric; binding keys are developer-chosen.
11
16
  const sanitizeBindingKey = (name) => String(name).replace(/[^A-Za-z0-9]/g, '');
12
17
 
13
- /**
14
- * Builds the Express routers for every integration's Definition.routes and
15
- * extension bindings. Pure: no handler wrapping, so the AWS handlers below
16
- * and other hosts (provider-netlify's integration-routes function) mount the
17
- * very same routers.
18
- *
19
- * @param {Array<Function>} integrationClasses
20
- * @returns {Array<{ key: string, eventName: string, router: import('express').Router, useDatabase: boolean }>}
21
- * One entry per integration, then one per extension binding (key
22
- * `${name}__${binding}`), in declaration order.
23
- */
24
- function buildIntegrationRouters(integrationClasses) {
25
- const entries = [];
26
- const keys = new Set();
27
- //todo: this should be in a use case class
28
- for (const IntegrationClass of integrationClasses) {
29
- const router = Router();
30
- const basePath = `/api/${IntegrationClass.Definition.name}-integration`;
31
- // Track (method, path) tuples to fail fast on conflicts between Definition.routes,
32
- // extension routes, or two extensions claiming the same path.
33
- const claimedRoutes = new Map();
34
- const claim = (method, path, source) => {
35
- const key = routeKey(method, path);
36
- if (claimedRoutes.has(key)) {
37
- const prev = claimedRoutes.get(key);
38
- throw new Error(
39
- `Integration "${IntegrationClass.Definition.name}" route conflict: ` +
40
- `${key} declared by ${prev} and ${source}`
41
- );
42
- }
43
- claimedRoutes.set(key, source);
44
- };
45
-
46
- console.log(
47
- `\n│ Configuring routes for ${IntegrationClass.Definition.name} Integration:`
48
- );
49
-
50
- const routes = IntegrationClass.Definition.routes || [];
51
- for (const routeDef of routes) {
52
- if (typeof routeDef === 'function') {
53
- router.use(basePath, routeDef(IntegrationClass));
54
- console.log(`│ ANY ${basePath}/* (function handler)`);
55
- } else if (routeDef instanceof express.Router) {
56
- router.use(basePath, routeDef);
57
- console.log(`│ ANY ${basePath}/* (express router)`);
58
- } else if (typeof routeDef === 'object') {
59
- claim(routeDef.method, routeDef.path, 'Definition.routes');
60
- router.use(
61
- basePath,
62
- loadRouterFromObject(IntegrationClass, routeDef)
63
- );
64
- const method = (routeDef.method || 'ANY').toUpperCase();
65
- const fullPath = `${basePath}${routeDef.path}`;
66
- console.log(`│ ${method} ${fullPath}`);
67
- }
68
- }
69
-
70
- // Each extension binding gets its own namespaced handler (/{bindingName}),
71
- // so two modules' extensions can share a path like /webhooks without colliding.
72
- const bindingGroups = new Map();
73
- for (const extRoute of getExtensionRoutes(IntegrationClass)) {
74
- const namespacedPath = `/${extRoute.bindingName}${extRoute.path}`;
75
- claim(
76
- extRoute.method,
77
- namespacedPath,
78
- `extension "${extRoute.extensionName}" (binding "${extRoute.bindingName}")`
79
- );
80
- if (!bindingGroups.has(extRoute.bindingName)) {
81
- bindingGroups.set(extRoute.bindingName, {
82
- router: Router(),
83
- useDatabase: extRoute.useDatabase,
84
- });
85
- }
86
- const group = bindingGroups.get(extRoute.bindingName);
87
- group.router.use(
88
- `${basePath}/${extRoute.bindingName}`,
89
- loadRouterFromObject(IntegrationClass, extRoute)
90
- );
91
- console.log(
92
- `│ ${extRoute.method.toUpperCase()} ${basePath}/${
93
- extRoute.bindingName
94
- }${extRoute.path} (extension: ${
95
- extRoute.extensionName
96
- }, useDatabase: ${extRoute.useDatabase})`
18
+ //todo: this should be in a use case class
19
+ for (const IntegrationClass of integrationClasses) {
20
+ const router = Router();
21
+ const basePath = `/api/${IntegrationClass.Definition.name}-integration`;
22
+ // Track (method, path) tuples to fail fast on conflicts between Definition.routes,
23
+ // extension routes, or two extensions claiming the same path.
24
+ const claimedRoutes = new Map();
25
+ const claim = (method, path, source) => {
26
+ const key = routeKey(method, path);
27
+ if (claimedRoutes.has(key)) {
28
+ const prev = claimedRoutes.get(key);
29
+ throw new Error(
30
+ `Integration "${IntegrationClass.Definition.name}" route conflict: ` +
31
+ `${key} declared by ${prev} and ${source}`
97
32
  );
98
33
  }
99
- console.log('│');
34
+ claimedRoutes.set(key, source);
35
+ };
100
36
 
101
- entries.push({
102
- key: `${IntegrationClass.Definition.name}`,
103
- eventName: `HTTP Event: ${IntegrationClass.Definition.name}`,
104
- router,
105
- useDatabase: true,
106
- });
107
- keys.add(`${IntegrationClass.Definition.name}`);
37
+ console.log(`\n│ Configuring routes for ${IntegrationClass.Definition.name} Integration:`);
108
38
 
109
- for (const [bindingName, group] of bindingGroups) {
110
- // Wire contract: integration-builder.js (devtools) derives the identical
111
- // function key for the serverless config. Keep both in sync.
112
- const fnKey = `${
113
- IntegrationClass.Definition.name
114
- }__${sanitizeBindingKey(bindingName)}`;
115
- // Distinct binding keys can sanitize to the same fnKey — fail loud rather than overwrite.
116
- if (keys.has(fnKey)) {
117
- throw new Error(
118
- `Integration "${IntegrationClass.Definition.name}" extension handler conflict: ` +
119
- `binding "${bindingName}" sanitizes to "${fnKey}", which is already taken. ` +
120
- `Use binding keys that are distinct after stripping non-alphanumeric characters.`
121
- );
122
- }
123
- entries.push({
124
- key: fnKey,
125
- eventName: `HTTP Event: ${IntegrationClass.Definition.name} extension ${bindingName}`,
126
- router: group.router,
127
- useDatabase: group.useDatabase,
128
- });
129
- keys.add(fnKey);
39
+ const routes = IntegrationClass.Definition.routes || [];
40
+ for (const routeDef of routes) {
41
+ if (typeof routeDef === 'function') {
42
+ router.use(basePath, routeDef(IntegrationClass));
43
+ console.log(`│ ANY ${basePath}/* (function handler)`);
44
+ } else if (routeDef instanceof express.Router) {
45
+ router.use(basePath, routeDef);
46
+ console.log(`│ ANY ${basePath}/* (express router)`);
47
+ } else if (typeof routeDef === 'object') {
48
+ claim(routeDef.method, routeDef.path, 'Definition.routes');
49
+ router.use(
50
+ basePath,
51
+ loadRouterFromObject(IntegrationClass, routeDef)
52
+ );
53
+ const method = (routeDef.method || 'ANY').toUpperCase();
54
+ const fullPath = `${basePath}${routeDef.path}`;
55
+ console.log(`│ ${method} ${fullPath}`);
130
56
  }
131
57
  }
132
- return entries;
133
- }
134
58
 
135
- /**
136
- * One router serving every integration-defined route and extension binding,
137
- * for hosts that run them all in one function (provider-netlify).
138
- *
139
- * @param {Array<Function>} [integrationClasses] - defaults to the app's.
140
- * @returns {import('express').Router}
141
- */
142
- function createIntegrationDefinedRouter(integrationClasses) {
143
- const classes = integrationClasses || loadAppDefinition().integrations;
144
- const combined = Router();
145
- for (const entry of buildIntegrationRouters(classes)) {
146
- combined.use(entry.router);
59
+ // Each extension binding gets its own namespaced handler (/{bindingName}),
60
+ // so two modules' extensions can share a path like /webhooks without colliding.
61
+ const bindingGroups = new Map();
62
+ for (const extRoute of getExtensionRoutes(IntegrationClass)) {
63
+ const namespacedPath = `/${extRoute.bindingName}${extRoute.path}`;
64
+ claim(
65
+ extRoute.method,
66
+ namespacedPath,
67
+ `extension "${extRoute.extensionName}" (binding "${extRoute.bindingName}")`
68
+ );
69
+ if (!bindingGroups.has(extRoute.bindingName)) {
70
+ bindingGroups.set(extRoute.bindingName, {
71
+ router: Router(),
72
+ useDatabase: extRoute.useDatabase,
73
+ });
74
+ }
75
+ const group = bindingGroups.get(extRoute.bindingName);
76
+ group.router.use(
77
+ `${basePath}/${extRoute.bindingName}`,
78
+ loadRouterFromObject(IntegrationClass, extRoute)
79
+ );
80
+ console.log(
81
+ `│ ${extRoute.method.toUpperCase()} ${basePath}/${extRoute.bindingName}${extRoute.path} (extension: ${extRoute.extensionName}, useDatabase: ${extRoute.useDatabase})`
82
+ );
147
83
  }
148
- return combined;
149
- }
84
+ console.log('│');
150
85
 
151
- // The AWS handlers (one Lambda per integration and per extension binding,
152
- // see devtools integration-builder). Built at require time on purpose: a
153
- // route conflict fails the cold start, not the first request.
154
- const handlers = {};
155
- for (const entry of buildIntegrationRouters(loadAppDefinition().integrations)) {
156
- handlers[entry.key] = {
86
+ handlers[`${IntegrationClass.Definition.name}`] = {
157
87
  handler: createAppHandler(
158
- entry.eventName,
159
- entry.router,
160
- entry.useDatabase
88
+ `HTTP Event: ${IntegrationClass.Definition.name}`,
89
+ router
161
90
  ),
162
91
  };
92
+
93
+ for (const [bindingName, group] of bindingGroups) {
94
+ // Wire contract: integration-builder.js (devtools) derives the identical
95
+ // function key for the serverless config. Keep both in sync.
96
+ const fnKey = `${IntegrationClass.Definition.name}__${sanitizeBindingKey(
97
+ bindingName
98
+ )}`;
99
+ // Distinct binding keys can sanitize to the same fnKey — fail loud rather than overwrite.
100
+ if (Object.prototype.hasOwnProperty.call(handlers, fnKey)) {
101
+ throw new Error(
102
+ `Integration "${IntegrationClass.Definition.name}" extension handler conflict: ` +
103
+ `binding "${bindingName}" sanitizes to "${fnKey}", which is already taken. ` +
104
+ `Use binding keys that are distinct after stripping non-alphanumeric characters.`
105
+ );
106
+ }
107
+ handlers[fnKey] = {
108
+ handler: createAppHandler(
109
+ `HTTP Event: ${IntegrationClass.Definition.name} extension ${bindingName}`,
110
+ group.router,
111
+ group.useDatabase
112
+ ),
113
+ };
114
+ }
163
115
  }
164
116
 
165
- module.exports = {
166
- handlers,
167
- buildIntegrationRouters,
168
- createIntegrationDefinedRouter,
169
- };
117
+ module.exports = { handlers };
@@ -6,120 +6,82 @@ const {
6
6
  IntegrationEventDispatcher,
7
7
  } = require('../integration-event-dispatcher');
8
8
 
9
+ const handlers = {};
10
+ const { integrations: integrationClasses } = loadAppDefinition();
11
+
9
12
  // `webhooks.received` is counted at the DB-connected ON_WEBHOOK dispatch (see
10
13
  // usage-rollup-subscriber), not in this DB-free receipt handler.
11
14
 
12
- /**
13
- * Builds the webhook receiver router for every integration with webhooks
14
- * enabled. Pure: no handler wrapping, so the AWS handlers below and other
15
- * hosts (provider-netlify's webhooks function) mount the same routers.
16
- *
17
- * @param {Array<Function>} integrationClasses
18
- * @returns {Array<{ key: string, eventName: string, router: import('express').Router }>}
19
- */
20
- function buildWebhookRouters(integrationClasses) {
21
- const entries = [];
22
- for (const IntegrationClass of integrationClasses) {
23
- const webhookConfig = IntegrationClass.Definition.webhooks;
24
-
25
- // Skip if webhooks not enabled
26
- if (
27
- !webhookConfig ||
28
- (typeof webhookConfig === 'object' && !webhookConfig.enabled)
29
- ) {
30
- continue;
31
- }
32
-
33
- const router = Router();
34
- const basePath = `/api/${IntegrationClass.Definition.name}-integration/webhooks`;
15
+ for (const IntegrationClass of integrationClasses) {
16
+ const webhookConfig = IntegrationClass.Definition.webhooks;
35
17
 
36
- console.log(
37
- `\n│ Configuring webhook routes for ${IntegrationClass.Definition.name}:`
38
- );
18
+ // Skip if webhooks not enabled
19
+ if (
20
+ !webhookConfig ||
21
+ (typeof webhookConfig === 'object' && !webhookConfig.enabled)
22
+ ) {
23
+ continue;
24
+ }
39
25
 
40
- // General webhook route (no integration ID)
41
- router.post(basePath, async (req, res, next) => {
42
- try {
43
- const integrationInstance = new IntegrationClass();
44
- const dispatcher = new IntegrationEventDispatcher(
45
- integrationInstance
46
- );
47
- await dispatcher.dispatchHttp({
48
- event: 'WEBHOOK_RECEIVED',
49
- req,
50
- res,
51
- next,
52
- });
53
- } catch (error) {
54
- next(error);
55
- }
56
- });
57
- console.log(`│ POST ${basePath}`);
26
+ const router = Router();
27
+ const basePath = `/api/${IntegrationClass.Definition.name}-integration/webhooks`;
58
28
 
59
- // Integration-specific webhook route (with integration ID)
60
- router.post(`${basePath}/:integrationId`, async (req, res, next) => {
61
- try {
62
- const integrationInstance = new IntegrationClass();
63
- const dispatcher = new IntegrationEventDispatcher(
64
- integrationInstance
65
- );
66
- // Logs only: the id comes from an unauthenticated URL, so it must
67
- // not reach the telemetry context that drives usage attribution.
68
- await runInContext(
69
- {
70
- [LOGGER_SCOPE_KEY]: {
71
- integrationId: req.params.integrationId,
72
- },
73
- },
74
- () =>
75
- dispatcher.dispatchHttp({
76
- event: 'WEBHOOK_RECEIVED',
77
- req,
78
- res,
79
- next,
80
- })
81
- );
82
- } catch (error) {
83
- next(error);
84
- }
85
- });
86
- console.log(`│ POST ${basePath}/:integrationId`);
87
- console.log('│');
29
+ console.log(
30
+ `\n│ Configuring webhook routes for ${IntegrationClass.Definition.name}:`
31
+ );
88
32
 
89
- entries.push({
90
- key: `${IntegrationClass.Definition.name}Webhook`,
91
- eventName: `HTTP Event: ${IntegrationClass.Definition.name} Webhook`,
92
- router,
93
- });
94
- }
95
- return entries;
96
- }
33
+ // General webhook route (no integration ID)
34
+ router.post(basePath, async (req, res, next) => {
35
+ try {
36
+ const integrationInstance = new IntegrationClass();
37
+ const dispatcher = new IntegrationEventDispatcher(
38
+ integrationInstance
39
+ );
40
+ await dispatcher.dispatchHttp({
41
+ event: 'WEBHOOK_RECEIVED',
42
+ req,
43
+ res,
44
+ next,
45
+ });
46
+ } catch (error) {
47
+ next(error);
48
+ }
49
+ });
50
+ console.log(`│ POST ${basePath}`);
97
51
 
98
- /**
99
- * One router serving every integration's webhook routes, for hosts that run
100
- * them all in one function (provider-netlify).
101
- *
102
- * @param {Array<Function>} [integrationClasses] - defaults to the app's.
103
- * @returns {import('express').Router}
104
- */
105
- function createWebhookRouter(integrationClasses) {
106
- const classes = integrationClasses || loadAppDefinition().integrations;
107
- const combined = Router();
108
- for (const entry of buildWebhookRouters(classes)) {
109
- combined.use(entry.router);
110
- }
111
- return combined;
112
- }
52
+ // Integration-specific webhook route (with integration ID)
53
+ router.post(`${basePath}/:integrationId`, async (req, res, next) => {
54
+ try {
55
+ const integrationInstance = new IntegrationClass();
56
+ const dispatcher = new IntegrationEventDispatcher(
57
+ integrationInstance
58
+ );
59
+ // Logs only: the id comes from an unauthenticated URL, so it must
60
+ // not reach the telemetry context that drives usage attribution.
61
+ await runInContext(
62
+ { [LOGGER_SCOPE_KEY]: { integrationId: req.params.integrationId } },
63
+ () =>
64
+ dispatcher.dispatchHttp({
65
+ event: 'WEBHOOK_RECEIVED',
66
+ req,
67
+ res,
68
+ next,
69
+ })
70
+ );
71
+ } catch (error) {
72
+ next(error);
73
+ }
74
+ });
75
+ console.log(`│ POST ${basePath}/:integrationId`);
76
+ console.log('│');
113
77
 
114
- const handlers = {};
115
- for (const entry of buildWebhookRouters(loadAppDefinition().integrations)) {
116
- handlers[entry.key] = {
78
+ handlers[`${IntegrationClass.Definition.name}Webhook`] = {
117
79
  handler: createAppHandler(
118
- entry.eventName,
119
- entry.router,
80
+ `HTTP Event: ${IntegrationClass.Definition.name} Webhook`,
81
+ router,
120
82
  false // shouldUseDatabase = false
121
83
  ),
122
84
  };
123
85
  }
124
86
 
125
- module.exports = { handlers, buildWebhookRouters, createWebhookRouter };
87
+ module.exports = { handlers };
package/index.js CHANGED
@@ -25,14 +25,6 @@ const {
25
25
  UserRepositoryMongo,
26
26
  UserRepositoryPostgres,
27
27
  } = require('./user/repositories/user-repository-factory');
28
- const {
29
- createOrganizationMembershipRepository,
30
- OrganizationMembershipRepositoryMongo,
31
- OrganizationMembershipRepositoryPostgres,
32
- } = require('./user/repositories/organization-membership-repository-factory');
33
- const {
34
- EnsureOrganizationMembership,
35
- } = require('./user/use-cases/ensure-organization-membership');
36
28
  const {
37
29
  GetUserFromXFriggHeaders,
38
30
  } = require('./user/use-cases/get-user-from-x-frigg-headers');
@@ -71,7 +63,6 @@ const {
71
63
  Options,
72
64
  createIntegrationRouter,
73
65
  checkRequiredParams,
74
- getModulesDefinitionFromIntegrationClasses,
75
66
  LoadIntegrationContextUseCase,
76
67
  } = require('./integrations/index');
77
68
  const {
@@ -109,34 +100,11 @@ const {
109
100
  ModuleFactory,
110
101
  getEntityTypeRegistry,
111
102
  EntityRegistryError,
112
- resolveScope,
113
- listBindingScopes,
114
- OwnershipConfigError,
115
103
  } = require('./modules/index');
116
- const {
117
- ManagementApiConfigError,
118
- } = require('./management-api/management-api-config');
119
104
  const application = require('./application');
120
105
  const utils = require('./utils');
121
106
 
122
- const {
123
- QueuerUtil,
124
- QueueProvider,
125
- QueueClientInterface,
126
- createQueueProvider,
127
- QUEUE_PROVIDERS,
128
- } = require('./queues');
129
- const {
130
- resolveProvider,
131
- determineProviderName,
132
- providerPackageName,
133
- KNOWN_PROVIDERS,
134
- isDeployedRuntime,
135
- } = require('./providers');
136
-
137
- // App-level core extensions (appDefinition.coreExtensions): Prisma models, encrypted
138
- // fields, admin routes and bootstrap hooks (friggframework/frigg#545).
139
- const extensions = require('./extensions');
107
+ const { QueuerUtil } = require('./queues');
140
108
 
141
109
  module.exports = {
142
110
  // assertions
@@ -163,10 +131,6 @@ module.exports = {
163
131
  createUserRepository,
164
132
  UserRepositoryMongo,
165
133
  UserRepositoryPostgres,
166
- createOrganizationMembershipRepository,
167
- OrganizationMembershipRepositoryMongo,
168
- OrganizationMembershipRepositoryPostgres,
169
- EnsureOrganizationMembership,
170
134
  GetUserFromXFriggHeaders,
171
135
  GetUserFromAdopterJwt,
172
136
  AuthenticateUser,
@@ -187,8 +151,6 @@ module.exports = {
187
151
  Options,
188
152
  checkRequiredParams,
189
153
  createIntegrationRouter,
190
- // Deprecated (ADR-059): use getEntityTypeRegistry.
191
- getModulesDefinitionFromIntegrationClasses,
192
154
  LoadIntegrationContextUseCase,
193
155
  CreateProcess,
194
156
  UpdateProcessState,
@@ -246,33 +208,8 @@ module.exports = {
246
208
  ModuleFactory,
247
209
  getEntityTypeRegistry,
248
210
  EntityRegistryError,
249
- resolveScope,
250
- listBindingScopes,
251
- OwnershipConfigError,
252
- ManagementApiConfigError,
253
211
  // queues
254
212
  QueuerUtil,
255
- QueueProvider,
256
- QueueClientInterface,
257
- createQueueProvider,
258
- QUEUE_PROVIDERS,
259
-
260
- // provider plugins (appDefinition.provider)
261
- resolveProvider,
262
- determineProviderName,
263
- providerPackageName,
264
- KNOWN_PROVIDERS,
265
- isDeployedRuntime,
266
-
267
- // app-level extensions
268
- extensions,
269
- loadExtensions: extensions.loadExtensions,
270
- composeSchemas: extensions.composeSchemas,
271
- composeExtensionPrisma: extensions.composeExtensionPrisma,
272
- mountExtensionRoutes: extensions.mountExtensionRoutes,
273
- createExtensionRoutesRouter: extensions.createExtensionRoutesRouter,
274
- runExtensionBootstraps: extensions.runExtensionBootstraps,
275
- initializeApp: extensions.initializeApp,
276
213
 
277
214
  // utils
278
215
  ...utils,
@@ -5,19 +5,13 @@
5
5
  * Follows hexagonal architecture with interface + adapters pattern.
6
6
  *
7
7
  * Providers:
8
- * - eventbridge: AWS EventBridge Scheduler (production on AWS)
9
- * - netlify: poll-and-dispatch from a Netlify scheduled function
8
+ * - eventbridge: AWS EventBridge Scheduler (production)
10
9
  * - mock: In-memory mock scheduler (local development)
11
- *
12
- * Adapters are lazy getters (friggframework/frigg#545, 1176a004): the
13
- * EventBridge adapter requires @aws-sdk/client-scheduler, which is not a
14
- * core dependency, and core/index -> application -> scheduler-commands ->
15
- * this barrel runs on every require('@friggframework/core'). An eager
16
- * require crashed any deployment without that SDK (e.g. a pruned Netlify
17
- * function bundle).
18
10
  */
19
11
 
20
12
  const { SchedulerServiceInterface } = require('./scheduler-service-interface');
13
+ const { EventBridgeSchedulerAdapter } = require('./eventbridge-scheduler-adapter');
14
+ const { MockSchedulerAdapter } = require('./mock-scheduler-adapter');
21
15
  const {
22
16
  createSchedulerService,
23
17
  SCHEDULER_PROVIDERS,
@@ -28,16 +22,9 @@ module.exports = {
28
22
  // Interface (Port)
29
23
  SchedulerServiceInterface,
30
24
 
31
- // Adapters (loaded on access)
32
- get EventBridgeSchedulerAdapter() {
33
- return require('./eventbridge-scheduler-adapter').EventBridgeSchedulerAdapter;
34
- },
35
- get MockSchedulerAdapter() {
36
- return require('./mock-scheduler-adapter').MockSchedulerAdapter;
37
- },
38
- get NetlifySchedulerAdapter() {
39
- return require('./netlify-scheduler-adapter').NetlifySchedulerAdapter;
40
- },
25
+ // Adapters
26
+ EventBridgeSchedulerAdapter,
27
+ MockSchedulerAdapter,
41
28
 
42
29
  // Factory
43
30
  createSchedulerService,