@friggframework/devtools 2.0.0-next.45 → 2.0.0-next.47
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/infrastructure/ARCHITECTURE.md +487 -0
- package/infrastructure/HEALTH.md +468 -0
- package/infrastructure/README.md +51 -0
- package/infrastructure/__tests__/postgres-config.test.js +914 -0
- package/infrastructure/__tests__/template-generation.test.js +687 -0
- package/infrastructure/create-frigg-infrastructure.js +1 -1
- package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
- package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
- package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
- package/infrastructure/domains/database/aurora-builder.js +809 -0
- package/infrastructure/domains/database/aurora-builder.test.js +950 -0
- package/infrastructure/domains/database/aurora-discovery.js +87 -0
- package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
- package/infrastructure/domains/database/aurora-resolver.js +210 -0
- package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
- package/infrastructure/domains/database/migration-builder.js +695 -0
- package/infrastructure/domains/database/migration-builder.test.js +294 -0
- package/infrastructure/domains/database/migration-resolver.js +163 -0
- package/infrastructure/domains/database/migration-resolver.test.js +337 -0
- package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
- package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
- package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
- package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
- package/infrastructure/domains/health/application/ports/index.js +26 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
- package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
- package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
- package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
- package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
- package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
- package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
- package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
- package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
- package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
- package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
- package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
- package/infrastructure/domains/health/domain/entities/issue.js +299 -0
- package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
- package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
- package/infrastructure/domains/health/domain/entities/resource.js +159 -0
- package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
- package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
- package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
- package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
- package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
- package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
- package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
- package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
- package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
- package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
- package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
- package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
- package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
- package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
- package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
- package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
- package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
- package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
- package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
- package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
- package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
- package/infrastructure/domains/integration/integration-builder.js +397 -0
- package/infrastructure/domains/integration/integration-builder.test.js +593 -0
- package/infrastructure/domains/integration/integration-resolver.js +170 -0
- package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
- package/infrastructure/domains/integration/websocket-builder.js +69 -0
- package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
- package/infrastructure/domains/networking/vpc-builder.js +1829 -0
- package/infrastructure/domains/networking/vpc-builder.test.js +1262 -0
- package/infrastructure/domains/networking/vpc-discovery.js +177 -0
- package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
- package/infrastructure/domains/networking/vpc-resolver.js +324 -0
- package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
- package/infrastructure/domains/parameters/ssm-builder.js +79 -0
- package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
- package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
- package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
- package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
- package/infrastructure/domains/security/kms-builder.js +366 -0
- package/infrastructure/domains/security/kms-builder.test.js +374 -0
- package/infrastructure/domains/security/kms-discovery.js +80 -0
- package/infrastructure/domains/security/kms-discovery.test.js +177 -0
- package/infrastructure/domains/security/kms-resolver.js +96 -0
- package/infrastructure/domains/security/kms-resolver.test.js +216 -0
- package/infrastructure/domains/shared/base-builder.js +112 -0
- package/infrastructure/domains/shared/base-resolver.js +186 -0
- package/infrastructure/domains/shared/base-resolver.test.js +305 -0
- package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
- package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
- package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
- package/infrastructure/domains/shared/cloudformation-discovery.js +375 -0
- package/infrastructure/domains/shared/cloudformation-discovery.test.js +590 -0
- package/infrastructure/domains/shared/environment-builder.js +119 -0
- package/infrastructure/domains/shared/environment-builder.test.js +247 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.js +544 -0
- package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +377 -0
- package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
- package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
- package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
- package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
- package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
- package/infrastructure/domains/shared/resource-discovery.js +192 -0
- package/infrastructure/domains/shared/resource-discovery.test.js +552 -0
- package/infrastructure/domains/shared/types/app-definition.js +205 -0
- package/infrastructure/domains/shared/types/discovery-result.js +106 -0
- package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
- package/infrastructure/domains/shared/types/index.js +46 -0
- package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
- package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js +380 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
- package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
- package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
- package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +138 -0
- package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +2 -1
- package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
- package/infrastructure/esbuild.config.js +53 -0
- package/infrastructure/infrastructure-composer.js +87 -0
- package/infrastructure/{serverless-template.test.js → infrastructure-composer.test.js} +115 -24
- package/infrastructure/scripts/build-prisma-layer.js +553 -0
- package/infrastructure/scripts/build-prisma-layer.test.js +102 -0
- package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +80 -48
- package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
- package/layers/prisma/nodejs/package.json +8 -0
- package/management-ui/server/utils/cliIntegration.js +1 -1
- package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
- package/package.json +11 -11
- package/frigg-cli/.eslintrc.js +0 -141
- package/frigg-cli/__tests__/unit/commands/build.test.js +0 -251
- package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
- package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
- package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
- package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
- package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
- package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +0 -486
- package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
- package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
- package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
- package/frigg-cli/__tests__/utils/test-setup.js +0 -287
- package/frigg-cli/build-command/index.js +0 -65
- package/frigg-cli/db-setup-command/index.js +0 -193
- package/frigg-cli/deploy-command/index.js +0 -175
- package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
- package/frigg-cli/generate-command/azure-generator.js +0 -43
- package/frigg-cli/generate-command/gcp-generator.js +0 -47
- package/frigg-cli/generate-command/index.js +0 -332
- package/frigg-cli/generate-command/terraform-generator.js +0 -555
- package/frigg-cli/generate-iam-command.js +0 -118
- package/frigg-cli/index.js +0 -75
- package/frigg-cli/index.test.js +0 -158
- package/frigg-cli/init-command/backend-first-handler.js +0 -756
- package/frigg-cli/init-command/index.js +0 -93
- package/frigg-cli/init-command/template-handler.js +0 -143
- package/frigg-cli/install-command/backend-js.js +0 -33
- package/frigg-cli/install-command/commit-changes.js +0 -16
- package/frigg-cli/install-command/environment-variables.js +0 -127
- package/frigg-cli/install-command/environment-variables.test.js +0 -136
- package/frigg-cli/install-command/index.js +0 -54
- package/frigg-cli/install-command/install-package.js +0 -13
- package/frigg-cli/install-command/integration-file.js +0 -30
- package/frigg-cli/install-command/logger.js +0 -12
- package/frigg-cli/install-command/template.js +0 -90
- package/frigg-cli/install-command/validate-package.js +0 -75
- package/frigg-cli/jest.config.js +0 -124
- package/frigg-cli/package.json +0 -54
- package/frigg-cli/start-command/index.js +0 -149
- package/frigg-cli/start-command/start-command.test.js +0 -297
- package/frigg-cli/test/init-command.test.js +0 -180
- package/frigg-cli/test/npm-registry.test.js +0 -319
- package/frigg-cli/ui-command/index.js +0 -154
- package/frigg-cli/utils/app-resolver.js +0 -319
- package/frigg-cli/utils/backend-path.js +0 -25
- package/frigg-cli/utils/database-validator.js +0 -161
- package/frigg-cli/utils/error-messages.js +0 -257
- package/frigg-cli/utils/npm-registry.js +0 -167
- package/frigg-cli/utils/prisma-runner.js +0 -280
- package/frigg-cli/utils/process-manager.js +0 -199
- package/frigg-cli/utils/repo-detection.js +0 -405
- package/infrastructure/aws-discovery.js +0 -1176
- package/infrastructure/aws-discovery.test.js +0 -1220
- package/infrastructure/serverless-template.js +0 -2094
- /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
- /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
- /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
- /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
- /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
- /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
- /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
|
@@ -0,0 +1,593 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Integration Builder
|
|
3
|
+
*
|
|
4
|
+
* Tests integration-specific Lambda functions and SQS queues
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { IntegrationBuilder } = require('./integration-builder');
|
|
8
|
+
const { ValidationResult } = require('../shared/base-builder');
|
|
9
|
+
|
|
10
|
+
describe('IntegrationBuilder', () => {
|
|
11
|
+
let integrationBuilder;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
integrationBuilder = new IntegrationBuilder();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('shouldExecute()', () => {
|
|
18
|
+
it('should return true when integrations array has items', () => {
|
|
19
|
+
const appDefinition = {
|
|
20
|
+
integrations: [
|
|
21
|
+
{ Definition: { name: 'test' } },
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
expect(integrationBuilder.shouldExecute(appDefinition)).toBe(true);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('should return false when integrations array is empty', () => {
|
|
29
|
+
const appDefinition = {
|
|
30
|
+
integrations: [],
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
expect(integrationBuilder.shouldExecute(appDefinition)).toBe(false);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('should return false when integrations is not defined', () => {
|
|
37
|
+
const appDefinition = {};
|
|
38
|
+
|
|
39
|
+
expect(integrationBuilder.shouldExecute(appDefinition)).toBe(false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should return false when integrations is not an array', () => {
|
|
43
|
+
const appDefinition = {
|
|
44
|
+
integrations: { name: 'test' },
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
expect(integrationBuilder.shouldExecute(appDefinition)).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('validate()', () => {
|
|
52
|
+
it('should pass validation for valid integrations', () => {
|
|
53
|
+
const appDefinition = {
|
|
54
|
+
integrations: [
|
|
55
|
+
{ Definition: { name: 'hubspot' } },
|
|
56
|
+
{ Definition: { name: 'salesforce' } },
|
|
57
|
+
],
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const result = integrationBuilder.validate(appDefinition);
|
|
61
|
+
|
|
62
|
+
expect(result).toBeInstanceOf(ValidationResult);
|
|
63
|
+
expect(result.valid).toBe(true);
|
|
64
|
+
expect(result.errors).toEqual([]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should pass when integrations is undefined', () => {
|
|
68
|
+
const appDefinition = {};
|
|
69
|
+
|
|
70
|
+
const result = integrationBuilder.validate(appDefinition);
|
|
71
|
+
|
|
72
|
+
expect(result.valid).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('should error when integrations is not an array', () => {
|
|
76
|
+
const appDefinition = {
|
|
77
|
+
integrations: 'invalid',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const result = integrationBuilder.validate(appDefinition);
|
|
81
|
+
|
|
82
|
+
expect(result.valid).toBe(false);
|
|
83
|
+
expect(result.errors).toContain('integrations must be an array');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should error when integration is missing Definition', () => {
|
|
87
|
+
const appDefinition = {
|
|
88
|
+
integrations: [
|
|
89
|
+
{ someOtherField: 'value' },
|
|
90
|
+
],
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const result = integrationBuilder.validate(appDefinition);
|
|
94
|
+
|
|
95
|
+
expect(result.valid).toBe(false);
|
|
96
|
+
expect(result.errors).toContain(
|
|
97
|
+
'Integration at index 0 is missing Definition or name'
|
|
98
|
+
);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('should error when integration Definition is missing name', () => {
|
|
102
|
+
const appDefinition = {
|
|
103
|
+
integrations: [
|
|
104
|
+
{ Definition: {} },
|
|
105
|
+
],
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const result = integrationBuilder.validate(appDefinition);
|
|
109
|
+
|
|
110
|
+
expect(result.valid).toBe(false);
|
|
111
|
+
expect(result.errors).toContain(
|
|
112
|
+
'Integration at index 0 is missing Definition or name'
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should validate all integrations', () => {
|
|
117
|
+
const appDefinition = {
|
|
118
|
+
integrations: [
|
|
119
|
+
{ Definition: { name: 'valid' } },
|
|
120
|
+
{ Definition: {} }, // Invalid - no name
|
|
121
|
+
{ someField: 'value' }, // Invalid - no Definition
|
|
122
|
+
],
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const result = integrationBuilder.validate(appDefinition);
|
|
126
|
+
|
|
127
|
+
expect(result.valid).toBe(false);
|
|
128
|
+
expect(result.errors).toHaveLength(2);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe('build()', () => {
|
|
133
|
+
it('should create HTTP handler for integration', async () => {
|
|
134
|
+
const appDefinition = {
|
|
135
|
+
integrations: [
|
|
136
|
+
{ Definition: { name: 'hubspot' } },
|
|
137
|
+
],
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
141
|
+
|
|
142
|
+
expect(result.functions.hubspot).toBeDefined();
|
|
143
|
+
expect(result.functions.hubspot.handler).toBe(
|
|
144
|
+
'node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.hubspot.handler'
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('should configure HTTP API event for integration', async () => {
|
|
149
|
+
const appDefinition = {
|
|
150
|
+
integrations: [
|
|
151
|
+
{ Definition: { name: 'salesforce' } },
|
|
152
|
+
],
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
156
|
+
|
|
157
|
+
expect(result.functions.salesforce.events).toEqual([
|
|
158
|
+
{
|
|
159
|
+
httpApi: {
|
|
160
|
+
path: '/api/salesforce-integration/{proxy+}',
|
|
161
|
+
method: 'ANY',
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
]);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should create SQS queue for integration', async () => {
|
|
168
|
+
const appDefinition = {
|
|
169
|
+
integrations: [
|
|
170
|
+
{ Definition: { name: 'slack' } },
|
|
171
|
+
],
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
175
|
+
|
|
176
|
+
expect(result.resources.SlackQueue).toBeDefined();
|
|
177
|
+
expect(result.resources.SlackQueue.Type).toBe('AWS::SQS::Queue');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it('should configure queue with correct retention and visibility timeout', async () => {
|
|
181
|
+
const appDefinition = {
|
|
182
|
+
integrations: [
|
|
183
|
+
{ Definition: { name: 'test' } },
|
|
184
|
+
],
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
188
|
+
|
|
189
|
+
expect(result.resources.TestQueue.Properties.MessageRetentionPeriod).toBe(60);
|
|
190
|
+
expect(result.resources.TestQueue.Properties.VisibilityTimeout).toBe(1800);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should configure redrive policy to internal error queue', async () => {
|
|
194
|
+
const appDefinition = {
|
|
195
|
+
integrations: [
|
|
196
|
+
{ Definition: { name: 'test' } },
|
|
197
|
+
],
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
201
|
+
|
|
202
|
+
expect(result.resources.TestQueue.Properties.RedrivePolicy).toEqual({
|
|
203
|
+
maxReceiveCount: 1,
|
|
204
|
+
deadLetterTargetArn: {
|
|
205
|
+
'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('should create queue worker function', async () => {
|
|
211
|
+
const appDefinition = {
|
|
212
|
+
integrations: [
|
|
213
|
+
{ Definition: { name: 'hubspot' } },
|
|
214
|
+
],
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
218
|
+
|
|
219
|
+
expect(result.functions.hubspotQueueWorker).toBeDefined();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('should configure queue worker with SQS event', async () => {
|
|
223
|
+
const appDefinition = {
|
|
224
|
+
integrations: [
|
|
225
|
+
{ Definition: { name: 'test' } },
|
|
226
|
+
],
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
230
|
+
|
|
231
|
+
expect(result.functions.testQueueWorker.events).toEqual([
|
|
232
|
+
{
|
|
233
|
+
sqs: {
|
|
234
|
+
arn: { 'Fn::GetAtt': ['TestQueue', 'Arn'] },
|
|
235
|
+
batchSize: 1,
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
]);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it('should set queue worker timeout to 600 seconds', async () => {
|
|
242
|
+
const appDefinition = {
|
|
243
|
+
integrations: [
|
|
244
|
+
{ Definition: { name: 'test' } },
|
|
245
|
+
],
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
249
|
+
|
|
250
|
+
expect(result.functions.testQueueWorker.timeout).toBe(900); // 15 minutes (Lambda max)
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('should set queue worker reserved concurrency', async () => {
|
|
254
|
+
const appDefinition = {
|
|
255
|
+
integrations: [
|
|
256
|
+
{ Definition: { name: 'test' } },
|
|
257
|
+
],
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
261
|
+
|
|
262
|
+
expect(result.functions.testQueueWorker.reservedConcurrency).toBe(5);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('should add queue URL to environment variables', async () => {
|
|
266
|
+
const appDefinition = {
|
|
267
|
+
integrations: [
|
|
268
|
+
{ Definition: { name: 'slack' } },
|
|
269
|
+
],
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
273
|
+
|
|
274
|
+
expect(result.environment.SLACK_QUEUE_URL).toEqual({
|
|
275
|
+
Ref: 'SlackQueue',
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('should add queue name to custom variables', async () => {
|
|
280
|
+
const appDefinition = {
|
|
281
|
+
integrations: [
|
|
282
|
+
{ Definition: { name: 'stripe' } },
|
|
283
|
+
],
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
287
|
+
|
|
288
|
+
expect(result.custom.StripeQueue).toBe('${self:service}--${self:provider.stage}-StripeQueue');
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it('should handle multiple integrations', async () => {
|
|
292
|
+
const appDefinition = {
|
|
293
|
+
integrations: [
|
|
294
|
+
{ Definition: { name: 'hubspot' } },
|
|
295
|
+
{ Definition: { name: 'salesforce' } },
|
|
296
|
+
{ Definition: { name: 'slack' } },
|
|
297
|
+
],
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
301
|
+
|
|
302
|
+
// Check functions
|
|
303
|
+
expect(result.functions.hubspot).toBeDefined();
|
|
304
|
+
expect(result.functions.salesforce).toBeDefined();
|
|
305
|
+
expect(result.functions.slack).toBeDefined();
|
|
306
|
+
expect(result.functions.hubspotQueueWorker).toBeDefined();
|
|
307
|
+
expect(result.functions.salesforceQueueWorker).toBeDefined();
|
|
308
|
+
expect(result.functions.slackQueueWorker).toBeDefined();
|
|
309
|
+
|
|
310
|
+
// Check queues
|
|
311
|
+
expect(result.resources.HubspotQueue).toBeDefined();
|
|
312
|
+
expect(result.resources.SalesforceQueue).toBeDefined();
|
|
313
|
+
expect(result.resources.SlackQueue).toBeDefined();
|
|
314
|
+
|
|
315
|
+
// Check environment vars
|
|
316
|
+
expect(result.environment.HUBSPOT_QUEUE_URL).toBeDefined();
|
|
317
|
+
expect(result.environment.SALESFORCE_QUEUE_URL).toBeDefined();
|
|
318
|
+
expect(result.environment.SLACK_QUEUE_URL).toBeDefined();
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it('should capitalize integration name for queue reference', async () => {
|
|
322
|
+
const appDefinition = {
|
|
323
|
+
integrations: [
|
|
324
|
+
{ Definition: { name: 'myIntegration' } },
|
|
325
|
+
],
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
329
|
+
|
|
330
|
+
// Queue name should start with capital letter
|
|
331
|
+
expect(result.resources.MyIntegrationQueue).toBeDefined();
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('should handle integration names with hyphens', async () => {
|
|
335
|
+
const appDefinition = {
|
|
336
|
+
integrations: [
|
|
337
|
+
{ Definition: { name: 'my-integration' } },
|
|
338
|
+
],
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
342
|
+
|
|
343
|
+
expect(result.functions['my-integration']).toBeDefined();
|
|
344
|
+
expect(result.functions['my-integrationQueueWorker']).toBeDefined();
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
describe('getDependencies()', () => {
|
|
349
|
+
it('should have no dependencies', () => {
|
|
350
|
+
const deps = integrationBuilder.getDependencies();
|
|
351
|
+
|
|
352
|
+
expect(deps).toEqual([]);
|
|
353
|
+
});
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
describe('getName()', () => {
|
|
357
|
+
it('should return IntegrationBuilder', () => {
|
|
358
|
+
expect(integrationBuilder.getName()).toBe('IntegrationBuilder');
|
|
359
|
+
});
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
describe('Webhook Handler Configuration', () => {
|
|
363
|
+
it('should create webhook handler when webhooks enabled with boolean true', async () => {
|
|
364
|
+
const appDefinition = {
|
|
365
|
+
integrations: [
|
|
366
|
+
{
|
|
367
|
+
Definition: {
|
|
368
|
+
name: 'hubspot',
|
|
369
|
+
webhooks: true,
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
376
|
+
|
|
377
|
+
expect(result.functions.hubspotWebhook).toBeDefined();
|
|
378
|
+
expect(result.functions.hubspotWebhook.handler).toBe(
|
|
379
|
+
'node_modules/@friggframework/core/handlers/routers/integration-webhook-routers.handlers.hubspotWebhook.handler'
|
|
380
|
+
);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('should create webhook handler when webhooks enabled with object', async () => {
|
|
384
|
+
const appDefinition = {
|
|
385
|
+
integrations: [
|
|
386
|
+
{
|
|
387
|
+
Definition: {
|
|
388
|
+
name: 'salesforce',
|
|
389
|
+
webhooks: { enabled: true },
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
],
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
396
|
+
|
|
397
|
+
expect(result.functions.salesforceWebhook).toBeDefined();
|
|
398
|
+
});
|
|
399
|
+
|
|
400
|
+
it('should NOT create webhook handler when webhooks disabled', async () => {
|
|
401
|
+
const appDefinition = {
|
|
402
|
+
integrations: [
|
|
403
|
+
{
|
|
404
|
+
Definition: {
|
|
405
|
+
name: 'slack',
|
|
406
|
+
webhooks: false,
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
],
|
|
410
|
+
};
|
|
411
|
+
|
|
412
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
413
|
+
|
|
414
|
+
expect(result.functions.slackWebhook).toBeUndefined();
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
it('should NOT create webhook handler when webhooks explicitly disabled in object', async () => {
|
|
418
|
+
const appDefinition = {
|
|
419
|
+
integrations: [
|
|
420
|
+
{
|
|
421
|
+
Definition: {
|
|
422
|
+
name: 'test',
|
|
423
|
+
webhooks: { enabled: false },
|
|
424
|
+
}
|
|
425
|
+
},
|
|
426
|
+
],
|
|
427
|
+
};
|
|
428
|
+
|
|
429
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
430
|
+
|
|
431
|
+
expect(result.functions.testWebhook).toBeUndefined();
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
it('should configure webhook with both base and ID-specific routes', async () => {
|
|
435
|
+
const appDefinition = {
|
|
436
|
+
integrations: [
|
|
437
|
+
{
|
|
438
|
+
Definition: {
|
|
439
|
+
name: 'stripe',
|
|
440
|
+
webhooks: true,
|
|
441
|
+
}
|
|
442
|
+
},
|
|
443
|
+
],
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
447
|
+
|
|
448
|
+
expect(result.functions.stripeWebhook.events).toEqual([
|
|
449
|
+
{
|
|
450
|
+
httpApi: {
|
|
451
|
+
path: '/api/stripe-integration/webhooks',
|
|
452
|
+
method: 'POST',
|
|
453
|
+
},
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
httpApi: {
|
|
457
|
+
path: '/api/stripe-integration/webhooks/{integrationId}',
|
|
458
|
+
method: 'POST',
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
]);
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
it('should define webhook handler BEFORE catch-all proxy route (ordering bug fix)', async () => {
|
|
465
|
+
const appDefinition = {
|
|
466
|
+
integrations: [
|
|
467
|
+
{
|
|
468
|
+
Definition: {
|
|
469
|
+
name: 'asana',
|
|
470
|
+
webhooks: true,
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
],
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
477
|
+
|
|
478
|
+
// Get the keys (function names) in the order they were added
|
|
479
|
+
const functionKeys = Object.keys(result.functions);
|
|
480
|
+
|
|
481
|
+
// Webhook handler should be defined before the main integration handler
|
|
482
|
+
const webhookIndex = functionKeys.indexOf('asanaWebhook');
|
|
483
|
+
const integrationIndex = functionKeys.indexOf('asana');
|
|
484
|
+
|
|
485
|
+
expect(webhookIndex).toBeGreaterThanOrEqual(0);
|
|
486
|
+
expect(integrationIndex).toBeGreaterThan(0);
|
|
487
|
+
expect(webhookIndex).toBeLessThan(integrationIndex);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
it('should maintain correct function order: webhook, integration, queue worker', async () => {
|
|
491
|
+
const appDefinition = {
|
|
492
|
+
integrations: [
|
|
493
|
+
{
|
|
494
|
+
Definition: {
|
|
495
|
+
name: 'test',
|
|
496
|
+
webhooks: true,
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
],
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
503
|
+
|
|
504
|
+
const functionKeys = Object.keys(result.functions);
|
|
505
|
+
|
|
506
|
+
// Expected order: webhook, integration, queueWorker
|
|
507
|
+
expect(functionKeys).toEqual([
|
|
508
|
+
'testWebhook',
|
|
509
|
+
'test',
|
|
510
|
+
'testQueueWorker',
|
|
511
|
+
]);
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
it('should handle multiple integrations with mixed webhook configurations', async () => {
|
|
515
|
+
const appDefinition = {
|
|
516
|
+
integrations: [
|
|
517
|
+
{
|
|
518
|
+
Definition: {
|
|
519
|
+
name: 'hubspot',
|
|
520
|
+
webhooks: true,
|
|
521
|
+
}
|
|
522
|
+
},
|
|
523
|
+
{
|
|
524
|
+
Definition: {
|
|
525
|
+
name: 'salesforce',
|
|
526
|
+
webhooks: false,
|
|
527
|
+
}
|
|
528
|
+
},
|
|
529
|
+
{
|
|
530
|
+
Definition: {
|
|
531
|
+
name: 'slack',
|
|
532
|
+
webhooks: { enabled: true },
|
|
533
|
+
}
|
|
534
|
+
},
|
|
535
|
+
],
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
539
|
+
|
|
540
|
+
// Hubspot: webhook enabled
|
|
541
|
+
expect(result.functions.hubspotWebhook).toBeDefined();
|
|
542
|
+
expect(result.functions.hubspot).toBeDefined();
|
|
543
|
+
expect(result.functions.hubspotQueueWorker).toBeDefined();
|
|
544
|
+
|
|
545
|
+
// Salesforce: webhook disabled
|
|
546
|
+
expect(result.functions.salesforceWebhook).toBeUndefined();
|
|
547
|
+
expect(result.functions.salesforce).toBeDefined();
|
|
548
|
+
expect(result.functions.salesforceQueueWorker).toBeDefined();
|
|
549
|
+
|
|
550
|
+
// Slack: webhook enabled via object
|
|
551
|
+
expect(result.functions.slackWebhook).toBeDefined();
|
|
552
|
+
expect(result.functions.slack).toBeDefined();
|
|
553
|
+
expect(result.functions.slackQueueWorker).toBeDefined();
|
|
554
|
+
});
|
|
555
|
+
|
|
556
|
+
it('should use skipEsbuild for webhook handlers', async () => {
|
|
557
|
+
const appDefinition = {
|
|
558
|
+
integrations: [
|
|
559
|
+
{
|
|
560
|
+
Definition: {
|
|
561
|
+
name: 'test',
|
|
562
|
+
webhooks: true,
|
|
563
|
+
}
|
|
564
|
+
},
|
|
565
|
+
],
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
569
|
+
|
|
570
|
+
expect(result.functions.testWebhook.skipEsbuild).toBe(true);
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
it('should apply package configuration to webhook handlers', async () => {
|
|
574
|
+
const appDefinition = {
|
|
575
|
+
integrations: [
|
|
576
|
+
{
|
|
577
|
+
Definition: {
|
|
578
|
+
name: 'test',
|
|
579
|
+
webhooks: true,
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
],
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
const result = await integrationBuilder.build(appDefinition, {});
|
|
586
|
+
|
|
587
|
+
expect(result.functions.testWebhook.package).toBeDefined();
|
|
588
|
+
expect(result.functions.testWebhook.package.exclude).toContain('node_modules/aws-sdk/**');
|
|
589
|
+
expect(result.functions.testWebhook.package.exclude).toContain('node_modules/@prisma/**');
|
|
590
|
+
});
|
|
591
|
+
});
|
|
592
|
+
});
|
|
593
|
+
|