@friggframework/devtools 2.0.0-next.44 → 2.0.0-next.46

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 (212) hide show
  1. package/infrastructure/ARCHITECTURE.md +487 -0
  2. package/infrastructure/HEALTH.md +468 -0
  3. package/infrastructure/README.md +51 -0
  4. package/infrastructure/__tests__/postgres-config.test.js +914 -0
  5. package/infrastructure/__tests__/template-generation.test.js +687 -0
  6. package/infrastructure/create-frigg-infrastructure.js +1 -1
  7. package/infrastructure/docs/POSTGRES-CONFIGURATION.md +630 -0
  8. package/infrastructure/{DEPLOYMENT-INSTRUCTIONS.md → docs/deployment-instructions.md} +3 -3
  9. package/infrastructure/{IAM-POLICY-TEMPLATES.md → docs/iam-policy-templates.md} +9 -10
  10. package/infrastructure/domains/database/aurora-builder.js +809 -0
  11. package/infrastructure/domains/database/aurora-builder.test.js +950 -0
  12. package/infrastructure/domains/database/aurora-discovery.js +87 -0
  13. package/infrastructure/domains/database/aurora-discovery.test.js +188 -0
  14. package/infrastructure/domains/database/aurora-resolver.js +210 -0
  15. package/infrastructure/domains/database/aurora-resolver.test.js +347 -0
  16. package/infrastructure/domains/database/migration-builder.js +633 -0
  17. package/infrastructure/domains/database/migration-builder.test.js +294 -0
  18. package/infrastructure/domains/database/migration-resolver.js +163 -0
  19. package/infrastructure/domains/database/migration-resolver.test.js +337 -0
  20. package/infrastructure/domains/health/application/ports/IPropertyReconciler.js +164 -0
  21. package/infrastructure/domains/health/application/ports/IResourceDetector.js +129 -0
  22. package/infrastructure/domains/health/application/ports/IResourceImporter.js +142 -0
  23. package/infrastructure/domains/health/application/ports/IStackRepository.js +131 -0
  24. package/infrastructure/domains/health/application/ports/index.js +26 -0
  25. package/infrastructure/domains/health/application/use-cases/__tests__/execute-resource-import-use-case.test.js +679 -0
  26. package/infrastructure/domains/health/application/use-cases/__tests__/mismatch-analyzer-method-name.test.js +167 -0
  27. package/infrastructure/domains/health/application/use-cases/__tests__/repair-via-import-use-case.test.js +1130 -0
  28. package/infrastructure/domains/health/application/use-cases/execute-resource-import-use-case.js +221 -0
  29. package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.js +152 -0
  30. package/infrastructure/domains/health/application/use-cases/reconcile-properties-use-case.test.js +343 -0
  31. package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.js +535 -0
  32. package/infrastructure/domains/health/application/use-cases/repair-via-import-use-case.test.js +376 -0
  33. package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.js +213 -0
  34. package/infrastructure/domains/health/application/use-cases/run-health-check-use-case.test.js +441 -0
  35. package/infrastructure/domains/health/docs/ACME-DEV-DRIFT-ANALYSIS.md +267 -0
  36. package/infrastructure/domains/health/docs/BUILD-VS-DEPLOYED-TEMPLATE-ANALYSIS.md +324 -0
  37. package/infrastructure/domains/health/docs/ORPHAN-DETECTION-ANALYSIS.md +386 -0
  38. package/infrastructure/domains/health/docs/SPEC-CLEANUP-COMMAND.md +1419 -0
  39. package/infrastructure/domains/health/docs/TDD-IMPLEMENTATION-SUMMARY.md +391 -0
  40. package/infrastructure/domains/health/docs/TEMPLATE-COMPARISON-IMPLEMENTATION.md +551 -0
  41. package/infrastructure/domains/health/domain/entities/issue.js +299 -0
  42. package/infrastructure/domains/health/domain/entities/issue.test.js +528 -0
  43. package/infrastructure/domains/health/domain/entities/property-mismatch.js +108 -0
  44. package/infrastructure/domains/health/domain/entities/property-mismatch.test.js +275 -0
  45. package/infrastructure/domains/health/domain/entities/resource.js +159 -0
  46. package/infrastructure/domains/health/domain/entities/resource.test.js +432 -0
  47. package/infrastructure/domains/health/domain/entities/stack-health-report.js +306 -0
  48. package/infrastructure/domains/health/domain/entities/stack-health-report.test.js +601 -0
  49. package/infrastructure/domains/health/domain/services/__tests__/health-score-percentage-based.test.js +380 -0
  50. package/infrastructure/domains/health/domain/services/__tests__/import-progress-monitor.test.js +971 -0
  51. package/infrastructure/domains/health/domain/services/__tests__/import-template-generator.test.js +1150 -0
  52. package/infrastructure/domains/health/domain/services/__tests__/logical-id-mapper.test.js +672 -0
  53. package/infrastructure/domains/health/domain/services/__tests__/template-parser.test.js +496 -0
  54. package/infrastructure/domains/health/domain/services/__tests__/update-progress-monitor.test.js +419 -0
  55. package/infrastructure/domains/health/domain/services/health-score-calculator.js +248 -0
  56. package/infrastructure/domains/health/domain/services/health-score-calculator.test.js +504 -0
  57. package/infrastructure/domains/health/domain/services/import-progress-monitor.js +195 -0
  58. package/infrastructure/domains/health/domain/services/import-template-generator.js +435 -0
  59. package/infrastructure/domains/health/domain/services/logical-id-mapper.js +345 -0
  60. package/infrastructure/domains/health/domain/services/mismatch-analyzer.js +234 -0
  61. package/infrastructure/domains/health/domain/services/mismatch-analyzer.test.js +431 -0
  62. package/infrastructure/domains/health/domain/services/property-mutability-config.js +382 -0
  63. package/infrastructure/domains/health/domain/services/template-parser.js +245 -0
  64. package/infrastructure/domains/health/domain/services/update-progress-monitor.js +192 -0
  65. package/infrastructure/domains/health/domain/value-objects/health-score.js +138 -0
  66. package/infrastructure/domains/health/domain/value-objects/health-score.test.js +267 -0
  67. package/infrastructure/domains/health/domain/value-objects/property-mutability.js +161 -0
  68. package/infrastructure/domains/health/domain/value-objects/property-mutability.test.js +198 -0
  69. package/infrastructure/domains/health/domain/value-objects/resource-state.js +167 -0
  70. package/infrastructure/domains/health/domain/value-objects/resource-state.test.js +196 -0
  71. package/infrastructure/domains/health/domain/value-objects/stack-identifier.js +192 -0
  72. package/infrastructure/domains/health/domain/value-objects/stack-identifier.test.js +262 -0
  73. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-cfn-tagged.test.js +312 -0
  74. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-multi-stack.test.js +367 -0
  75. package/infrastructure/domains/health/infrastructure/adapters/__tests__/orphan-detection-relationship-analysis.test.js +432 -0
  76. package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.js +784 -0
  77. package/infrastructure/domains/health/infrastructure/adapters/aws-property-reconciler.test.js +1133 -0
  78. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.js +565 -0
  79. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-detector.test.js +554 -0
  80. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.js +318 -0
  81. package/infrastructure/domains/health/infrastructure/adapters/aws-resource-importer.test.js +398 -0
  82. package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.js +777 -0
  83. package/infrastructure/domains/health/infrastructure/adapters/aws-stack-repository.test.js +580 -0
  84. package/infrastructure/domains/integration/integration-builder.js +397 -0
  85. package/infrastructure/domains/integration/integration-builder.test.js +593 -0
  86. package/infrastructure/domains/integration/integration-resolver.js +170 -0
  87. package/infrastructure/domains/integration/integration-resolver.test.js +369 -0
  88. package/infrastructure/domains/integration/websocket-builder.js +69 -0
  89. package/infrastructure/domains/integration/websocket-builder.test.js +195 -0
  90. package/infrastructure/domains/networking/vpc-builder.js +1829 -0
  91. package/infrastructure/domains/networking/vpc-builder.test.js +1262 -0
  92. package/infrastructure/domains/networking/vpc-discovery.js +177 -0
  93. package/infrastructure/domains/networking/vpc-discovery.test.js +350 -0
  94. package/infrastructure/domains/networking/vpc-resolver.js +324 -0
  95. package/infrastructure/domains/networking/vpc-resolver.test.js +501 -0
  96. package/infrastructure/domains/parameters/ssm-builder.js +79 -0
  97. package/infrastructure/domains/parameters/ssm-builder.test.js +189 -0
  98. package/infrastructure/domains/parameters/ssm-discovery.js +84 -0
  99. package/infrastructure/domains/parameters/ssm-discovery.test.js +210 -0
  100. package/infrastructure/{iam-generator.js → domains/security/iam-generator.js} +2 -2
  101. package/infrastructure/domains/security/kms-builder.js +366 -0
  102. package/infrastructure/domains/security/kms-builder.test.js +374 -0
  103. package/infrastructure/domains/security/kms-discovery.js +80 -0
  104. package/infrastructure/domains/security/kms-discovery.test.js +177 -0
  105. package/infrastructure/domains/security/kms-resolver.js +96 -0
  106. package/infrastructure/domains/security/kms-resolver.test.js +216 -0
  107. package/infrastructure/domains/shared/base-builder.js +112 -0
  108. package/infrastructure/domains/shared/base-resolver.js +186 -0
  109. package/infrastructure/domains/shared/base-resolver.test.js +305 -0
  110. package/infrastructure/domains/shared/builder-orchestrator.js +212 -0
  111. package/infrastructure/domains/shared/builder-orchestrator.test.js +213 -0
  112. package/infrastructure/domains/shared/cloudformation-discovery-v2.js +334 -0
  113. package/infrastructure/domains/shared/cloudformation-discovery.js +375 -0
  114. package/infrastructure/domains/shared/cloudformation-discovery.test.js +590 -0
  115. package/infrastructure/domains/shared/environment-builder.js +119 -0
  116. package/infrastructure/domains/shared/environment-builder.test.js +247 -0
  117. package/infrastructure/domains/shared/providers/aws-provider-adapter.js +544 -0
  118. package/infrastructure/domains/shared/providers/aws-provider-adapter.test.js +377 -0
  119. package/infrastructure/domains/shared/providers/azure-provider-adapter.stub.js +93 -0
  120. package/infrastructure/domains/shared/providers/cloud-provider-adapter.js +136 -0
  121. package/infrastructure/domains/shared/providers/gcp-provider-adapter.stub.js +82 -0
  122. package/infrastructure/domains/shared/providers/provider-factory.js +108 -0
  123. package/infrastructure/domains/shared/providers/provider-factory.test.js +170 -0
  124. package/infrastructure/domains/shared/resource-discovery.js +192 -0
  125. package/infrastructure/domains/shared/resource-discovery.test.js +552 -0
  126. package/infrastructure/domains/shared/types/app-definition.js +205 -0
  127. package/infrastructure/domains/shared/types/discovery-result.js +106 -0
  128. package/infrastructure/domains/shared/types/discovery-result.test.js +258 -0
  129. package/infrastructure/domains/shared/types/index.js +46 -0
  130. package/infrastructure/domains/shared/types/resource-ownership.js +108 -0
  131. package/infrastructure/domains/shared/types/resource-ownership.test.js +101 -0
  132. package/infrastructure/domains/shared/utilities/base-definition-factory.js +380 -0
  133. package/infrastructure/domains/shared/utilities/base-definition-factory.js.bak +338 -0
  134. package/infrastructure/domains/shared/utilities/base-definition-factory.test.js +248 -0
  135. package/infrastructure/domains/shared/utilities/handler-path-resolver.js +134 -0
  136. package/infrastructure/domains/shared/utilities/handler-path-resolver.test.js +268 -0
  137. package/infrastructure/domains/shared/utilities/prisma-layer-manager.js +55 -0
  138. package/infrastructure/domains/shared/utilities/prisma-layer-manager.test.js +138 -0
  139. package/infrastructure/{env-validator.js → domains/shared/validation/env-validator.js} +2 -1
  140. package/infrastructure/domains/shared/validation/env-validator.test.js +173 -0
  141. package/infrastructure/esbuild.config.js +53 -0
  142. package/infrastructure/infrastructure-composer.js +87 -0
  143. package/infrastructure/{serverless-template.test.js → infrastructure-composer.test.js} +115 -24
  144. package/infrastructure/scripts/build-prisma-layer.js +553 -0
  145. package/infrastructure/scripts/build-prisma-layer.test.js +102 -0
  146. package/infrastructure/{build-time-discovery.js → scripts/build-time-discovery.js} +80 -48
  147. package/infrastructure/{build-time-discovery.test.js → scripts/build-time-discovery.test.js} +5 -4
  148. package/layers/prisma/nodejs/package.json +8 -0
  149. package/management-ui/server/utils/cliIntegration.js +1 -1
  150. package/management-ui/server/utils/environment/awsParameterStore.js +29 -18
  151. package/package.json +11 -11
  152. package/frigg-cli/.eslintrc.js +0 -141
  153. package/frigg-cli/__tests__/unit/commands/build.test.js +0 -251
  154. package/frigg-cli/__tests__/unit/commands/db-setup.test.js +0 -548
  155. package/frigg-cli/__tests__/unit/commands/install.test.js +0 -400
  156. package/frigg-cli/__tests__/unit/commands/ui.test.js +0 -346
  157. package/frigg-cli/__tests__/unit/utils/database-validator.test.js +0 -366
  158. package/frigg-cli/__tests__/unit/utils/error-messages.test.js +0 -304
  159. package/frigg-cli/__tests__/unit/utils/prisma-runner.test.js +0 -486
  160. package/frigg-cli/__tests__/utils/mock-factory.js +0 -270
  161. package/frigg-cli/__tests__/utils/prisma-mock.js +0 -194
  162. package/frigg-cli/__tests__/utils/test-fixtures.js +0 -463
  163. package/frigg-cli/__tests__/utils/test-setup.js +0 -287
  164. package/frigg-cli/build-command/index.js +0 -65
  165. package/frigg-cli/db-setup-command/index.js +0 -193
  166. package/frigg-cli/deploy-command/index.js +0 -175
  167. package/frigg-cli/generate-command/__tests__/generate-command.test.js +0 -301
  168. package/frigg-cli/generate-command/azure-generator.js +0 -43
  169. package/frigg-cli/generate-command/gcp-generator.js +0 -47
  170. package/frigg-cli/generate-command/index.js +0 -332
  171. package/frigg-cli/generate-command/terraform-generator.js +0 -555
  172. package/frigg-cli/generate-iam-command.js +0 -118
  173. package/frigg-cli/index.js +0 -75
  174. package/frigg-cli/index.test.js +0 -158
  175. package/frigg-cli/init-command/backend-first-handler.js +0 -756
  176. package/frigg-cli/init-command/index.js +0 -93
  177. package/frigg-cli/init-command/template-handler.js +0 -143
  178. package/frigg-cli/install-command/backend-js.js +0 -33
  179. package/frigg-cli/install-command/commit-changes.js +0 -16
  180. package/frigg-cli/install-command/environment-variables.js +0 -127
  181. package/frigg-cli/install-command/environment-variables.test.js +0 -136
  182. package/frigg-cli/install-command/index.js +0 -54
  183. package/frigg-cli/install-command/install-package.js +0 -13
  184. package/frigg-cli/install-command/integration-file.js +0 -30
  185. package/frigg-cli/install-command/logger.js +0 -12
  186. package/frigg-cli/install-command/template.js +0 -90
  187. package/frigg-cli/install-command/validate-package.js +0 -75
  188. package/frigg-cli/jest.config.js +0 -124
  189. package/frigg-cli/package.json +0 -54
  190. package/frigg-cli/start-command/index.js +0 -149
  191. package/frigg-cli/start-command/start-command.test.js +0 -297
  192. package/frigg-cli/test/init-command.test.js +0 -180
  193. package/frigg-cli/test/npm-registry.test.js +0 -319
  194. package/frigg-cli/ui-command/index.js +0 -154
  195. package/frigg-cli/utils/app-resolver.js +0 -319
  196. package/frigg-cli/utils/backend-path.js +0 -25
  197. package/frigg-cli/utils/database-validator.js +0 -161
  198. package/frigg-cli/utils/error-messages.js +0 -257
  199. package/frigg-cli/utils/npm-registry.js +0 -167
  200. package/frigg-cli/utils/prisma-runner.js +0 -280
  201. package/frigg-cli/utils/process-manager.js +0 -199
  202. package/frigg-cli/utils/repo-detection.js +0 -405
  203. package/infrastructure/aws-discovery.js +0 -1176
  204. package/infrastructure/aws-discovery.test.js +0 -1220
  205. package/infrastructure/serverless-template.js +0 -2074
  206. /package/infrastructure/{WEBSOCKET-CONFIGURATION.md → docs/WEBSOCKET-CONFIGURATION.md} +0 -0
  207. /package/infrastructure/{GENERATE-IAM-DOCS.md → docs/generate-iam-command.md} +0 -0
  208. /package/infrastructure/{iam-generator.test.js → domains/security/iam-generator.test.js} +0 -0
  209. /package/infrastructure/{frigg-deployment-iam-stack.yaml → domains/security/templates/frigg-deployment-iam-stack.yaml} +0 -0
  210. /package/infrastructure/{iam-policy-basic.json → domains/security/templates/iam-policy-basic.json} +0 -0
  211. /package/infrastructure/{iam-policy-full.json → domains/security/templates/iam-policy-full.json} +0 -0
  212. /package/infrastructure/{run-discovery.js → scripts/run-discovery.js} +0 -0
@@ -0,0 +1,397 @@
1
+ /**
2
+ * Integration Builder
3
+ *
4
+ * Domain Layer - Hexagonal Architecture
5
+ *
6
+ * Responsible for:
7
+ * - Creating SQS queues for each integration (CloudFormation resources)
8
+ * - Creating InternalErrorQueue (dead letter queue)
9
+ * - Creating Lambda function definitions (serverless template code)
10
+ * - Creating queue worker Lambda functions
11
+ * - Creating webhook handler functions
12
+ * - Configuring integration-specific routes and handlers
13
+ *
14
+ * Uses ownership-based architecture to support both stack-managed
15
+ * and externally-provided SQS queues.
16
+ */
17
+
18
+ const { InfrastructureBuilder, ValidationResult } = require('../shared/base-builder');
19
+ const IntegrationResourceResolver = require('./integration-resolver');
20
+ const { createEmptyDiscoveryResult, ResourceOwnership } = require('../shared/types');
21
+
22
+ class IntegrationBuilder extends InfrastructureBuilder {
23
+ constructor() {
24
+ super();
25
+ this.name = 'IntegrationBuilder';
26
+ }
27
+
28
+ shouldExecute(appDefinition) {
29
+ return Array.isArray(appDefinition.integrations) && appDefinition.integrations.length > 0;
30
+ }
31
+
32
+ getDependencies() {
33
+ return []; // No dependencies - integrations can run independently
34
+ }
35
+
36
+ validate(appDefinition) {
37
+ const result = new ValidationResult();
38
+
39
+ if (!appDefinition.integrations) {
40
+ return result; // Not an error, just no integrations
41
+ }
42
+
43
+ if (!Array.isArray(appDefinition.integrations)) {
44
+ result.addError('integrations must be an array');
45
+ return result;
46
+ }
47
+
48
+ // Validate each integration
49
+ appDefinition.integrations.forEach((integration, index) => {
50
+ if (!integration?.Definition?.name) {
51
+ result.addError(`Integration at index ${index} is missing Definition or name`);
52
+ }
53
+ });
54
+
55
+ return result;
56
+ }
57
+
58
+ /**
59
+ * Build integration infrastructure using ownership-based architecture
60
+ */
61
+ async build(appDefinition, discoveredResources) {
62
+ console.log(`\n[${this.name}] Configuring integrations...`);
63
+ console.log(` Processing ${appDefinition.integrations.length} integrations...`);
64
+
65
+ const result = {
66
+ functions: {},
67
+ resources: {},
68
+ environment: {},
69
+ custom: {},
70
+ iamStatements: [],
71
+ };
72
+
73
+ // Get structured discovery result
74
+ const discovery = discoveredResources._structured || this.convertFlatDiscoveryToStructured(discoveredResources);
75
+
76
+ // Use IntegrationResourceResolver to make ownership decisions
77
+ const resolver = new IntegrationResourceResolver();
78
+ const decisions = resolver.resolveAll(appDefinition, discovery);
79
+
80
+ console.log('\n 📋 Resource Ownership Decisions:');
81
+ console.log(` InternalErrorQueue: ${decisions.internalErrorQueue.ownership} - ${decisions.internalErrorQueue.reason}`);
82
+
83
+ // Log per-integration decisions
84
+ Object.keys(decisions.integrations).forEach(integrationName => {
85
+ const queueDecision = decisions.integrations[integrationName].queue;
86
+ console.log(` ${integrationName}Queue: ${queueDecision.ownership} - ${queueDecision.reason}`);
87
+ });
88
+
89
+ // Build resources based on ownership decisions
90
+ await this.buildFromDecisions(decisions, appDefinition, result);
91
+
92
+ console.log(`[${this.name}] ✅ Integration configuration completed`);
93
+ return result;
94
+ }
95
+
96
+ /**
97
+ * Convert flat discovery to structured discovery
98
+ * Provides backwards compatibility
99
+ */
100
+ convertFlatDiscoveryToStructured(flatDiscovery) {
101
+ const discovery = createEmptyDiscoveryResult();
102
+
103
+ if (!flatDiscovery) {
104
+ return discovery;
105
+ }
106
+
107
+ // Check if resources are from CloudFormation stack
108
+ if (flatDiscovery.fromCloudFormationStack) {
109
+ discovery.fromCloudFormation = true;
110
+ discovery.stackName = flatDiscovery.stackName || 'assumed-stack';
111
+
112
+ // Add stack-managed resources from existingLogicalIds
113
+ const existingLogicalIds = flatDiscovery.existingLogicalIds || [];
114
+ existingLogicalIds.forEach(logicalId => {
115
+ let resourceType = '';
116
+ let physicalId = '';
117
+
118
+ // Determine resource type and physical ID
119
+ if (logicalId === 'InternalErrorQueue') {
120
+ resourceType = 'AWS::SQS::Queue';
121
+ physicalId = flatDiscovery.internalErrorQueueUrl;
122
+ } else if (logicalId.endsWith('Queue')) {
123
+ // Integration-specific queue (e.g., SlackQueue, HubspotQueue)
124
+ resourceType = 'AWS::SQS::Queue';
125
+ const integrationName = logicalId.replace('Queue', '').toLowerCase();
126
+ physicalId = flatDiscovery[`${integrationName}QueueUrl`];
127
+ }
128
+
129
+ if (physicalId && typeof physicalId === 'string') {
130
+ discovery.stackManaged.push({
131
+ logicalId,
132
+ physicalId,
133
+ resourceType
134
+ });
135
+ }
136
+ });
137
+ }
138
+
139
+ return discovery;
140
+ }
141
+
142
+ /**
143
+ * Build integration resources based on ownership decisions
144
+ */
145
+ async buildFromDecisions(decisions, appDefinition, result) {
146
+ // Create InternalErrorQueue if ownership = STACK
147
+ const shouldCreateInternalErrorQueue = decisions.internalErrorQueue.ownership === ResourceOwnership.STACK;
148
+
149
+ if (shouldCreateInternalErrorQueue) {
150
+ console.log(' → Creating InternalErrorQueue in stack');
151
+ this.createInternalErrorQueue(result);
152
+ } else {
153
+ console.log(' → Using external InternalErrorQueue');
154
+ this.useExternalInternalErrorQueue(decisions.internalErrorQueue, result);
155
+ }
156
+
157
+ // Create Lambda function definitions and queue resources for each integration
158
+ const functionPackageConfig = this.createFunctionPackageConfig();
159
+
160
+ for (const integration of appDefinition.integrations) {
161
+ const integrationName = integration.Definition.name;
162
+ const queueDecision = decisions.integrations[integrationName].queue;
163
+
164
+ console.log(`\n Adding integration: ${integrationName}`);
165
+
166
+ // Create Lambda function definitions (serverless template code)
167
+ await this.createFunctionDefinitions(integration, functionPackageConfig, result);
168
+
169
+ // Create or reference SQS queue based on ownership decision
170
+ const shouldCreateQueue = queueDecision.ownership === ResourceOwnership.STACK;
171
+
172
+ if (shouldCreateQueue) {
173
+ console.log(` ✓ Creating ${integrationName}Queue in stack`);
174
+ this.createIntegrationQueue(integrationName, result);
175
+ } else {
176
+ console.log(` ✓ Using external ${integrationName}Queue`);
177
+ this.useExternalIntegrationQueue(integrationName, queueDecision, result);
178
+ }
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Create function package exclusion configuration
184
+ */
185
+ createFunctionPackageConfig() {
186
+ return {
187
+ exclude: [
188
+ // Exclude AWS SDK (provided by Lambda runtime)
189
+ 'node_modules/aws-sdk/**',
190
+ 'node_modules/@aws-sdk/**',
191
+
192
+ // Exclude Prisma (provided via Lambda Layer)
193
+ 'node_modules/@prisma/**',
194
+ 'node_modules/.prisma/**',
195
+ 'node_modules/prisma/**',
196
+ 'node_modules/@friggframework/core/generated/**',
197
+
198
+ // Exclude ALL nested node_modules
199
+ 'node_modules/**/node_modules/**',
200
+
201
+ // Exclude build tools (not needed at runtime)
202
+ 'node_modules/esbuild/**',
203
+ 'node_modules/@esbuild/**',
204
+ 'node_modules/typescript/**',
205
+ 'node_modules/webpack/**',
206
+ 'node_modules/osls/**',
207
+ 'node_modules/serverless-esbuild/**',
208
+ 'node_modules/serverless-jetpack/**',
209
+ 'node_modules/serverless-offline/**',
210
+ 'node_modules/serverless-offline-sqs/**',
211
+ 'node_modules/serverless-dotenv-plugin/**',
212
+ 'node_modules/serverless-kms-grants/**',
213
+ // Note: DO NOT exclude serverless-http - it's a runtime dependency!
214
+
215
+ // Exclude dev/test dependencies
216
+ 'node_modules/@friggframework/test/**',
217
+ 'node_modules/@friggframework/eslint-config/**',
218
+ 'node_modules/@friggframework/prettier-config/**',
219
+ 'node_modules/jest/**',
220
+ 'node_modules/prettier/**',
221
+ 'node_modules/eslint/**',
222
+
223
+ // Exclude local dev files
224
+ 'deploy.log',
225
+ '.env.backup',
226
+ 'docker-compose.yml',
227
+ 'jest.config.js',
228
+ 'jest.unit.config.js',
229
+ '.eslintrc.json',
230
+ '.prettierrc',
231
+ '.prettierignore',
232
+ '.markdownlintignore',
233
+ 'package-lock.json',
234
+
235
+ // Exclude development/test files (keep src/ - needed for integrations and api-modules)
236
+ 'coverage/**',
237
+ 'test/**',
238
+ 'layers/**',
239
+ // Note: DO NOT exclude src/** - handlers need src/integrations and src/api-modules at runtime
240
+ '**/*.test.js',
241
+ '**/*.spec.js',
242
+ '**/.claude-flow/**',
243
+ '**/.swarm/**',
244
+ ],
245
+ };
246
+ }
247
+
248
+ /**
249
+ * Create Lambda function definitions for an integration
250
+ * These are serverless framework template function definitions
251
+ */
252
+ async createFunctionDefinitions(integration, functionPackageConfig, result) {
253
+ const integrationName = integration.Definition.name;
254
+
255
+ // Add webhook handler if enabled (BEFORE catch-all proxy route)
256
+ // CRITICAL: Webhook routes must be defined before the catch-all {proxy+} route
257
+ // to ensure proper route matching in AWS API Gateway/HTTP API
258
+ const webhookConfig = integration.Definition.webhooks;
259
+ if (webhookConfig && (webhookConfig === true || webhookConfig.enabled === true)) {
260
+ const webhookFunctionName = `${integrationName}Webhook`;
261
+
262
+ result.functions[webhookFunctionName] = {
263
+ handler: `node_modules/@friggframework/core/handlers/routers/integration-webhook-routers.handlers.${integrationName}Webhook.handler`,
264
+ skipEsbuild: true, // Nested exports in node_modules - skip esbuild bundling
265
+ package: functionPackageConfig,
266
+ events: [
267
+ {
268
+ httpApi: {
269
+ path: `/api/${integrationName}-integration/webhooks`,
270
+ method: 'POST',
271
+ },
272
+ },
273
+ {
274
+ httpApi: {
275
+ path: `/api/${integrationName}-integration/webhooks/{integrationId}`,
276
+ method: 'POST',
277
+ },
278
+ },
279
+ ],
280
+ };
281
+ console.log(` ✓ Webhook handler function defined`);
282
+ }
283
+
284
+ // Create HTTP API handler for integration (catch-all route AFTER webhooks)
285
+ result.functions[integrationName] = {
286
+ handler: `node_modules/@friggframework/core/handlers/routers/integration-defined-routers.handlers.${integrationName}.handler`,
287
+ skipEsbuild: true, // Nested exports in node_modules - skip esbuild bundling
288
+ package: functionPackageConfig,
289
+ events: [
290
+ {
291
+ httpApi: {
292
+ path: `/api/${integrationName}-integration/{proxy+}`,
293
+ method: 'ANY',
294
+ },
295
+ },
296
+ ],
297
+ };
298
+ console.log(` ✓ HTTP handler function defined`);
299
+
300
+ // Create Queue Worker function
301
+ const queueWorkerName = `${integrationName}QueueWorker`;
302
+ result.functions[queueWorkerName] = {
303
+ handler: `node_modules/@friggframework/core/handlers/workers/integration-defined-workers.handlers.${integrationName}.queueWorker`,
304
+ skipEsbuild: true, // Nested exports in node_modules - skip esbuild bundling
305
+ package: functionPackageConfig,
306
+ reservedConcurrency: 5,
307
+ events: [
308
+ {
309
+ sqs: {
310
+ arn: { 'Fn::GetAtt': [`${this.capitalizeFirst(integrationName)}Queue`, 'Arn'] },
311
+ batchSize: 1,
312
+ },
313
+ },
314
+ ],
315
+ timeout: 900, // 15 minutes max for queue workers (Lambda maximum)
316
+ };
317
+ console.log(` ✓ Queue worker function defined`);
318
+ }
319
+
320
+ /**
321
+ * Create InternalErrorQueue CloudFormation resource
322
+ */
323
+ createInternalErrorQueue(result) {
324
+ result.resources.InternalErrorQueue = {
325
+ Type: 'AWS::SQS::Queue',
326
+ Properties: {
327
+ QueueName: '${self:service}-${self:provider.stage}-InternalErrorQueue',
328
+ MessageRetentionPeriod: 1209600, // 14 days
329
+ VisibilityTimeout: 300, // 5 minutes for error processing
330
+ },
331
+ };
332
+
333
+ console.log(' ✓ Created InternalErrorQueue resource');
334
+ }
335
+
336
+ /**
337
+ * Use external InternalErrorQueue
338
+ */
339
+ useExternalInternalErrorQueue(decision, result) {
340
+ // Add ARN to environment for Lambda functions
341
+ result.environment.INTERNAL_ERROR_QUEUE_ARN = decision.physicalId;
342
+
343
+ console.log(` ✓ Using external InternalErrorQueue: ${decision.physicalId}`);
344
+ }
345
+
346
+ /**
347
+ * Create integration-specific SQS queue CloudFormation resource
348
+ */
349
+ createIntegrationQueue(integrationName, result) {
350
+ const queueReference = `${this.capitalizeFirst(integrationName)}Queue`;
351
+ const queueName = `\${self:service}--\${self:provider.stage}-${queueReference}`;
352
+
353
+ result.resources[queueReference] = {
354
+ Type: 'AWS::SQS::Queue',
355
+ Properties: {
356
+ QueueName: `\${self:custom.${queueReference}}`,
357
+ MessageRetentionPeriod: 60,
358
+ VisibilityTimeout: 1800,
359
+ RedrivePolicy: {
360
+ maxReceiveCount: 1,
361
+ deadLetterTargetArn: {
362
+ 'Fn::GetAtt': ['InternalErrorQueue', 'Arn'],
363
+ },
364
+ },
365
+ },
366
+ };
367
+
368
+ // Add queue URL to environment
369
+ result.environment[`${integrationName.toUpperCase()}_QUEUE_URL`] = {
370
+ Ref: queueReference,
371
+ };
372
+
373
+ // Add queue name to custom section
374
+ result.custom[queueReference] = queueName;
375
+
376
+ console.log(` ✓ Created ${queueReference} resource`);
377
+ }
378
+
379
+ /**
380
+ * Use external integration queue
381
+ */
382
+ useExternalIntegrationQueue(integrationName, decision, result) {
383
+ // Add queue URL to environment for Lambda functions
384
+ result.environment[`${integrationName.toUpperCase()}_QUEUE_URL`] = decision.physicalId;
385
+
386
+ console.log(` ✓ Using external queue: ${decision.physicalId}`);
387
+ }
388
+
389
+ /**
390
+ * Capitalize first letter of string (e.g., 'slack' -> 'Slack')
391
+ */
392
+ capitalizeFirst(str) {
393
+ return str.charAt(0).toUpperCase() + str.slice(1);
394
+ }
395
+ }
396
+
397
+ module.exports = { IntegrationBuilder };