@friggframework/core 2.0.0--canary.596.6355e72.0 → 2.0.0--canary.596.fc8739c.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.
package/core/create-handler.js
CHANGED
|
@@ -80,10 +80,7 @@ const createHandler = (optionByName = {}) => {
|
|
|
80
80
|
// If enabled (i.e. if SECRET_ARN is set in process.env) Fetch secrets from AWS Secrets Manager, and set them as environment variables.
|
|
81
81
|
await secretsToEnv();
|
|
82
82
|
|
|
83
|
-
//
|
|
84
|
-
// Lazy-required so DB-free handlers (e.g. extension webhook
|
|
85
|
-
// receivers with useDatabase:false) never load the Prisma client.
|
|
86
|
-
// $connect is idempotent, so this safely reuses a warm connection.
|
|
83
|
+
// Lazy-required so DB-free handlers never load the Prisma client.
|
|
87
84
|
if (shouldUseDatabase) {
|
|
88
85
|
const { connectPrisma } = require('../database/prisma');
|
|
89
86
|
await connectPrisma();
|
|
@@ -511,6 +511,8 @@ router.get('/health/ready', async (_req, res) => {
|
|
|
511
511
|
});
|
|
512
512
|
});
|
|
513
513
|
|
|
514
|
-
|
|
514
|
+
// DB-free: /health/ready probes the DB itself and degrades to 503. Eager-connect
|
|
515
|
+
// here would turn a DB outage into a 500, killing otherwise-healthy containers.
|
|
516
|
+
const handler = createAppHandler('HTTP Event: Health', router, false);
|
|
515
517
|
|
|
516
518
|
module.exports = { handler, router };
|
|
@@ -56,11 +56,8 @@ for (const IntegrationClass of integrationClasses) {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
// can declare the same relative path (e.g. two /webhooks) without colliding.
|
|
62
|
-
// Each per-binding handler carries its own shouldUseDatabase (resolved from
|
|
63
|
-
// the extension/binding `useDatabase`, default false → DB-free receiver).
|
|
59
|
+
// Each extension binding gets its own namespaced handler (/{bindingName}),
|
|
60
|
+
// so two modules' extensions can share a path like /webhooks without colliding.
|
|
64
61
|
const bindingGroups = new Map();
|
|
65
62
|
for (const extRoute of getExtensionRoutes(IntegrationClass)) {
|
|
66
63
|
const namespacedPath = `/${extRoute.bindingName}${extRoute.path}`;
|
|
@@ -94,9 +91,19 @@ for (const IntegrationClass of integrationClasses) {
|
|
|
94
91
|
};
|
|
95
92
|
|
|
96
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.
|
|
97
96
|
const fnKey = `${IntegrationClass.Definition.name}__${sanitizeBindingKey(
|
|
98
97
|
bindingName
|
|
99
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
|
+
}
|
|
100
107
|
handlers[fnKey] = {
|
|
101
108
|
handler: createAppHandler(
|
|
102
109
|
`HTTP Event: ${IntegrationClass.Definition.name} extension ${bindingName}`,
|
|
@@ -55,6 +55,8 @@ Each extension binding is mounted under its **binding key**, on its own dedicate
|
|
|
55
55
|
|
|
56
56
|
So the full URL is `/api/{integration-name}-integration/{bindingKey}{route.path}`. Register that URL with the upstream provider (e.g. paste it into your HubSpot app's webhook settings). Hit it and the bound method (`onHubSpotEvent`) fires on the resolved per-account integration instance.
|
|
57
57
|
|
|
58
|
+
> **⚠️ Breaking:** extension routes used to mount un-namespaced (`/api/{x}-integration/webhooks`). They are now namespaced under the binding key. Any provider webhook already registered against the old path must be re-pointed at the new `/{bindingKey}` URL — and for signature schemes that sign the full URL (e.g. HubSpot v3), the old registration will also fail verification until updated.
|
|
59
|
+
|
|
58
60
|
## `useDatabase` — does the receiver open a DB connection?
|
|
59
61
|
|
|
60
62
|
Each extension declares whether its route handler should open a database connection:
|
|
@@ -72,6 +74,7 @@ module.exports = {
|
|
|
72
74
|
- **Default is `false`** — a webhook receiver that only verifies a signature and enqueues should not pay for a DB connection (faster cold start; at build time its Lambda doesn't get the Prisma layer).
|
|
73
75
|
- Set `useDatabase: true` at the **extension level** if the receiver itself needs the DB. A binding may override it locally (`extensions: { x: { extension, useDatabase: true } }`), though that's rarely needed.
|
|
74
76
|
- Resolution order: `binding.useDatabase ?? extension.useDatabase ?? false`.
|
|
77
|
+
- Scope note: `false` is the default **for extension routes**. `createHandler` itself still defaults `shouldUseDatabase: true` for the integration's own catch-all handler and the legacy `Definition.webhooks: true` path — those connect as before. The `false` default applies only to the per-binding extension handler.
|
|
75
78
|
|
|
76
79
|
If `useDatabase` is `false`, the receiver must not touch the database. Work that needs the DB (e.g. resolving `portalId → integrationId`) belongs in the queue worker that processes the dispatched event, not in the receiver.
|
|
77
80
|
|
|
@@ -199,8 +199,6 @@ function getExtensionRoutes(IntegrationClass) {
|
|
|
199
199
|
integrationName,
|
|
200
200
|
binding
|
|
201
201
|
);
|
|
202
|
-
// useDatabase is resolved at the binding level, falling back to the
|
|
203
|
-
// extension's declared value, then to false (DB-free by default).
|
|
204
202
|
const useDatabase =
|
|
205
203
|
binding.useDatabase ?? binding.extension.useDatabase ?? false;
|
|
206
204
|
const routes = binding.extension.routes || [];
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.596.
|
|
4
|
+
"version": "2.0.0--canary.596.fc8739c.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.588.0",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@friggframework/eslint-config": "2.0.0--canary.596.
|
|
42
|
-
"@friggframework/prettier-config": "2.0.0--canary.596.
|
|
43
|
-
"@friggframework/test": "2.0.0--canary.596.
|
|
41
|
+
"@friggframework/eslint-config": "2.0.0--canary.596.fc8739c.0",
|
|
42
|
+
"@friggframework/prettier-config": "2.0.0--canary.596.fc8739c.0",
|
|
43
|
+
"@friggframework/test": "2.0.0--canary.596.fc8739c.0",
|
|
44
44
|
"@prisma/client": "^6.17.0",
|
|
45
45
|
"@types/lodash": "4.17.15",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "fc8739c1c49a9731b8465e0d5e864c71db20c581"
|
|
84
84
|
}
|