@friggframework/devtools 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.
|
@@ -348,8 +348,7 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
348
348
|
}
|
|
349
349
|
|
|
350
350
|
// Create HTTP API handler for integration (catch-all route AFTER
|
|
351
|
-
// webhooks).
|
|
352
|
-
// binding gets its own function below so it can have its own DB infra.
|
|
351
|
+
// webhooks). Extension routes get their own functions below.
|
|
353
352
|
result.functions[integrationName] = {
|
|
354
353
|
handler: `node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.${integrationName}.handler`,
|
|
355
354
|
skipEsbuild: true, // Nested exports in node_modules - skip esbuild bundling
|
|
@@ -366,13 +365,8 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
366
365
|
};
|
|
367
366
|
console.log(` ✓ HTTP handler function defined`);
|
|
368
367
|
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
// hubspot + clockwork webhooks) never collide on the same path. The
|
|
372
|
-
// Prisma layer is attached only when the extension/binding declares
|
|
373
|
-
// useDatabase: true (default false → DB-free receiver, faster cold
|
|
374
|
-
// start). Route shape mirrors core's getExtensionRoutes; read directly
|
|
375
|
-
// to avoid coupling the build-time generator to a core runtime import.
|
|
368
|
+
// One serverless function per extension binding, namespaced under
|
|
369
|
+
// /{bindingKey}. Prisma layer attached only when useDatabase is true.
|
|
376
370
|
const sanitizeBindingKey = (name) =>
|
|
377
371
|
String(name).replace(/[^A-Za-z0-9]/g, '');
|
|
378
372
|
const extensionEntries = Object.entries(
|
|
@@ -386,9 +380,21 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
386
380
|
binding.useDatabase ??
|
|
387
381
|
(extension && extension.useDatabase) ??
|
|
388
382
|
false;
|
|
383
|
+
// Wire contract: core's integration-defined-routers derives the
|
|
384
|
+
// identical handler key. Keep both in sync.
|
|
389
385
|
const fnName = `${integrationName}__${sanitizeBindingKey(
|
|
390
386
|
bindingKey
|
|
391
387
|
)}`;
|
|
388
|
+
// Distinct binding keys can sanitize to the same fnName — fail loud rather than overwrite.
|
|
389
|
+
if (
|
|
390
|
+
Object.prototype.hasOwnProperty.call(result.functions, fnName)
|
|
391
|
+
) {
|
|
392
|
+
throw new Error(
|
|
393
|
+
`Integration "${integrationName}" extension function conflict: ` +
|
|
394
|
+
`binding "${bindingKey}" sanitizes to "${fnName}", which is already taken. ` +
|
|
395
|
+
`Use binding keys that are distinct after stripping non-alphanumeric characters.`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
392
398
|
result.functions[fnName] = {
|
|
393
399
|
handler: `node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.${fnName}.handler`,
|
|
394
400
|
skipEsbuild: true,
|
|
@@ -668,6 +668,30 @@ describe('IntegrationBuilder', () => {
|
|
|
668
668
|
expect(withoutDb.functions.hs__wh.layers).toBeUndefined();
|
|
669
669
|
});
|
|
670
670
|
|
|
671
|
+
it('throws when two binding keys sanitize to the same function name', async () => {
|
|
672
|
+
const mkExt = (name, event) => ({
|
|
673
|
+
name,
|
|
674
|
+
routes: [{ path: '/w', method: 'POST', event }],
|
|
675
|
+
events: { [event]: { handler: () => {} } },
|
|
676
|
+
});
|
|
677
|
+
const appDefinition = {
|
|
678
|
+
integrations: [
|
|
679
|
+
{
|
|
680
|
+
Definition: {
|
|
681
|
+
name: 'hs',
|
|
682
|
+
extensions: {
|
|
683
|
+
'hub-spot': { extension: mkExt('a', 'A') }, // → hs__hubspot
|
|
684
|
+
hubspot: { extension: mkExt('b', 'B') }, // → hs__hubspot
|
|
685
|
+
},
|
|
686
|
+
},
|
|
687
|
+
},
|
|
688
|
+
],
|
|
689
|
+
};
|
|
690
|
+
await expect(
|
|
691
|
+
integrationBuilder.build(appDefinition, {})
|
|
692
|
+
).rejects.toThrow(/extension function conflict.*hs__hubspot/);
|
|
693
|
+
});
|
|
694
|
+
|
|
671
695
|
it('should only have the catch-all proxy route when no extensions are declared', async () => {
|
|
672
696
|
const appDefinition = {
|
|
673
697
|
integrations: [{ Definition: { name: 'plain' } }],
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.596.
|
|
4
|
+
"version": "2.0.0--canary.596.fc8739c.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"frigg": "./frigg-cli/index.js"
|
|
7
7
|
},
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"@babel/eslint-parser": "^7.18.9",
|
|
26
26
|
"@babel/parser": "^7.25.3",
|
|
27
27
|
"@babel/traverse": "^7.25.3",
|
|
28
|
-
"@friggframework/core": "2.0.0--canary.596.
|
|
29
|
-
"@friggframework/schemas": "2.0.0--canary.596.
|
|
30
|
-
"@friggframework/test": "2.0.0--canary.596.
|
|
28
|
+
"@friggframework/core": "2.0.0--canary.596.fc8739c.0",
|
|
29
|
+
"@friggframework/schemas": "2.0.0--canary.596.fc8739c.0",
|
|
30
|
+
"@friggframework/test": "2.0.0--canary.596.fc8739c.0",
|
|
31
31
|
"@hapi/boom": "^10.0.1",
|
|
32
32
|
"@inquirer/prompts": "^5.3.8",
|
|
33
33
|
"axios": "^1.7.2",
|
|
@@ -55,8 +55,8 @@
|
|
|
55
55
|
"validate-npm-package-name": "^5.0.0"
|
|
56
56
|
},
|
|
57
57
|
"devDependencies": {
|
|
58
|
-
"@friggframework/eslint-config": "2.0.0--canary.596.
|
|
59
|
-
"@friggframework/prettier-config": "2.0.0--canary.596.
|
|
58
|
+
"@friggframework/eslint-config": "2.0.0--canary.596.fc8739c.0",
|
|
59
|
+
"@friggframework/prettier-config": "2.0.0--canary.596.fc8739c.0",
|
|
60
60
|
"aws-sdk-client-mock": "^4.1.0",
|
|
61
61
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
62
62
|
"jest": "^30.1.3",
|
|
@@ -88,5 +88,5 @@
|
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"access": "public"
|
|
90
90
|
},
|
|
91
|
-
"gitHead": "
|
|
91
|
+
"gitHead": "fc8739c1c49a9731b8465e0d5e864c71db20c581"
|
|
92
92
|
}
|