@friggframework/devtools 2.0.0--canary.593.8eb6309.0 → 2.0.0--canary.596.6355e72.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.
|
@@ -347,7 +347,9 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
347
347
|
console.log(` ✓ Webhook handler function defined`);
|
|
348
348
|
}
|
|
349
349
|
|
|
350
|
-
// Create HTTP API handler for integration (catch-all route AFTER
|
|
350
|
+
// Create HTTP API handler for integration (catch-all route AFTER
|
|
351
|
+
// webhooks). Tier 3 extension routes are NOT folded in here — each
|
|
352
|
+
// binding gets its own function below so it can have its own DB infra.
|
|
351
353
|
result.functions[integrationName] = {
|
|
352
354
|
handler: `node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.${integrationName}.handler`,
|
|
353
355
|
skipEsbuild: true, // Nested exports in node_modules - skip esbuild bundling
|
|
@@ -364,6 +366,47 @@ class IntegrationBuilder extends InfrastructureBuilder {
|
|
|
364
366
|
};
|
|
365
367
|
console.log(` ✓ HTTP handler function defined`);
|
|
366
368
|
|
|
369
|
+
// Tier 3 Integration Extensions — one dedicated function per binding,
|
|
370
|
+
// namespaced under /{bindingKey} so multiple modules' extensions (e.g.
|
|
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.
|
|
376
|
+
const sanitizeBindingKey = (name) =>
|
|
377
|
+
String(name).replace(/[^A-Za-z0-9]/g, '');
|
|
378
|
+
const extensionEntries = Object.entries(
|
|
379
|
+
integration.Definition.extensions || {}
|
|
380
|
+
);
|
|
381
|
+
for (const [bindingKey, binding] of extensionEntries) {
|
|
382
|
+
const extension = binding && binding.extension;
|
|
383
|
+
const routes = (extension && extension.routes) || [];
|
|
384
|
+
if (routes.length === 0) continue;
|
|
385
|
+
const useDatabase =
|
|
386
|
+
binding.useDatabase ??
|
|
387
|
+
(extension && extension.useDatabase) ??
|
|
388
|
+
false;
|
|
389
|
+
const fnName = `${integrationName}__${sanitizeBindingKey(
|
|
390
|
+
bindingKey
|
|
391
|
+
)}`;
|
|
392
|
+
result.functions[fnName] = {
|
|
393
|
+
handler: `node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.${fnName}.handler`,
|
|
394
|
+
skipEsbuild: true,
|
|
395
|
+
package: functionPackageConfig,
|
|
396
|
+
...(usePrismaLayer &&
|
|
397
|
+
useDatabase && { layers: [{ Ref: 'PrismaLambdaLayer' }] }),
|
|
398
|
+
events: routes.map((route) => ({
|
|
399
|
+
httpApi: {
|
|
400
|
+
path: `/api/${integrationName}-integration/${bindingKey}${route.path}`,
|
|
401
|
+
method: route.method,
|
|
402
|
+
},
|
|
403
|
+
})),
|
|
404
|
+
};
|
|
405
|
+
console.log(
|
|
406
|
+
` ✓ Extension handler function defined: ${fnName} (useDatabase: ${useDatabase})`
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
367
410
|
// Create Queue Worker function
|
|
368
411
|
const queueWorkerName = `${integrationName}QueueWorker`;
|
|
369
412
|
result.functions[queueWorkerName] = {
|
|
@@ -568,6 +568,123 @@ describe('IntegrationBuilder', () => {
|
|
|
568
568
|
]);
|
|
569
569
|
});
|
|
570
570
|
|
|
571
|
+
it('emits a dedicated per-binding function (namespaced) for Tier 3 extension routes; the main handler keeps only {proxy+}', async () => {
|
|
572
|
+
const appDefinition = {
|
|
573
|
+
integrations: [
|
|
574
|
+
{
|
|
575
|
+
Definition: {
|
|
576
|
+
name: 'hubspot',
|
|
577
|
+
extensions: {
|
|
578
|
+
hubspotWebhooks: {
|
|
579
|
+
extension: {
|
|
580
|
+
name: 'hubspot-webhooks',
|
|
581
|
+
routes: [
|
|
582
|
+
{
|
|
583
|
+
path: '/webhooks',
|
|
584
|
+
method: 'POST',
|
|
585
|
+
event: 'HUBSPOT_WEBHOOK_RECEIVED',
|
|
586
|
+
},
|
|
587
|
+
],
|
|
588
|
+
events: {
|
|
589
|
+
HUBSPOT_WEBHOOK_RECEIVED: {
|
|
590
|
+
type: 'LIFE_CYCLE_EVENT',
|
|
591
|
+
handler: () => {},
|
|
592
|
+
},
|
|
593
|
+
},
|
|
594
|
+
},
|
|
595
|
+
handlers: {},
|
|
596
|
+
},
|
|
597
|
+
},
|
|
598
|
+
},
|
|
599
|
+
},
|
|
600
|
+
],
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
604
|
+
|
|
605
|
+
// Dedicated per-binding function, namespaced under the binding key,
|
|
606
|
+
// pointing at its own handler export.
|
|
607
|
+
const fn = result.functions.hubspot__hubspotWebhooks;
|
|
608
|
+
expect(fn).toBeDefined();
|
|
609
|
+
expect(fn.handler).toBe(
|
|
610
|
+
'node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.hubspot__hubspotWebhooks.handler'
|
|
611
|
+
);
|
|
612
|
+
expect(fn.events).toEqual([
|
|
613
|
+
{
|
|
614
|
+
httpApi: {
|
|
615
|
+
path: '/api/hubspot-integration/hubspotWebhooks/webhooks',
|
|
616
|
+
method: 'POST',
|
|
617
|
+
},
|
|
618
|
+
},
|
|
619
|
+
]);
|
|
620
|
+
|
|
621
|
+
// The main integration handler keeps only the catch-all.
|
|
622
|
+
expect(result.functions.hubspot.events).toEqual([
|
|
623
|
+
{
|
|
624
|
+
httpApi: {
|
|
625
|
+
path: '/api/hubspot-integration/{proxy+}',
|
|
626
|
+
method: 'ANY',
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
]);
|
|
630
|
+
|
|
631
|
+
// useDatabase defaults to false → no Prisma layer on the receiver.
|
|
632
|
+
expect(fn.layers).toBeUndefined();
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
it('attaches the Prisma layer to a per-binding function only when useDatabase is true', async () => {
|
|
636
|
+
const mkDef = (useDatabase) => ({
|
|
637
|
+
integrations: [
|
|
638
|
+
{
|
|
639
|
+
Definition: {
|
|
640
|
+
name: 'hs',
|
|
641
|
+
extensions: {
|
|
642
|
+
wh: {
|
|
643
|
+
extension: {
|
|
644
|
+
name: 'wh-ext',
|
|
645
|
+
useDatabase,
|
|
646
|
+
routes: [
|
|
647
|
+
{
|
|
648
|
+
path: '/webhooks',
|
|
649
|
+
method: 'POST',
|
|
650
|
+
event: 'E',
|
|
651
|
+
},
|
|
652
|
+
],
|
|
653
|
+
events: { E: { handler: () => {} } },
|
|
654
|
+
},
|
|
655
|
+
},
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
},
|
|
659
|
+
],
|
|
660
|
+
});
|
|
661
|
+
|
|
662
|
+
const withDb = await integrationBuilder.build(mkDef(true), {});
|
|
663
|
+
expect(withDb.functions.hs__wh.layers).toEqual([
|
|
664
|
+
{ Ref: 'PrismaLambdaLayer' },
|
|
665
|
+
]);
|
|
666
|
+
|
|
667
|
+
const withoutDb = await integrationBuilder.build(mkDef(false), {});
|
|
668
|
+
expect(withoutDb.functions.hs__wh.layers).toBeUndefined();
|
|
669
|
+
});
|
|
670
|
+
|
|
671
|
+
it('should only have the catch-all proxy route when no extensions are declared', async () => {
|
|
672
|
+
const appDefinition = {
|
|
673
|
+
integrations: [{ Definition: { name: 'plain' } }],
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
677
|
+
|
|
678
|
+
expect(result.functions.plain.events).toEqual([
|
|
679
|
+
{
|
|
680
|
+
httpApi: {
|
|
681
|
+
path: '/api/plain-integration/{proxy+}',
|
|
682
|
+
method: 'ANY',
|
|
683
|
+
},
|
|
684
|
+
},
|
|
685
|
+
]);
|
|
686
|
+
});
|
|
687
|
+
|
|
571
688
|
it('should define webhook handler BEFORE catch-all proxy route (ordering bug fix)', async () => {
|
|
572
689
|
const appDefinition = {
|
|
573
690
|
integrations: [
|
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.
|
|
4
|
+
"version": "2.0.0--canary.596.6355e72.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.
|
|
29
|
-
"@friggframework/schemas": "2.0.0--canary.
|
|
30
|
-
"@friggframework/test": "2.0.0--canary.
|
|
28
|
+
"@friggframework/core": "2.0.0--canary.596.6355e72.0",
|
|
29
|
+
"@friggframework/schemas": "2.0.0--canary.596.6355e72.0",
|
|
30
|
+
"@friggframework/test": "2.0.0--canary.596.6355e72.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.
|
|
59
|
-
"@friggframework/prettier-config": "2.0.0--canary.
|
|
58
|
+
"@friggframework/eslint-config": "2.0.0--canary.596.6355e72.0",
|
|
59
|
+
"@friggframework/prettier-config": "2.0.0--canary.596.6355e72.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": "6355e7230ef1f29f10e5336c88d4ddd257dffe18"
|
|
92
92
|
}
|