@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.
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 +695 -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 -2094
  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,173 @@
1
+ /**
2
+ * Tests for Environment Variable Validator
3
+ *
4
+ * Tests validation of required environment variables
5
+ */
6
+
7
+ const { validateEnvironmentVariables } = require('./env-validator');
8
+
9
+ describe('Environment Validator', () => {
10
+ let originalEnv;
11
+
12
+ beforeEach(() => {
13
+ originalEnv = { ...process.env };
14
+ // Clear test-related env vars
15
+ delete process.env.TEST_VAR_1;
16
+ delete process.env.TEST_VAR_2;
17
+ delete process.env.NODE_ENV;
18
+ });
19
+
20
+ afterEach(() => {
21
+ process.env = originalEnv;
22
+ });
23
+
24
+ describe('validateEnvironmentVariables()', () => {
25
+ it('should return empty results for app definition without environment', () => {
26
+ const appDefinition = {};
27
+
28
+ const result = validateEnvironmentVariables(appDefinition);
29
+
30
+ expect(result.valid).toEqual([]);
31
+ expect(result.missing).toEqual([]);
32
+ expect(result.warnings).toEqual([]);
33
+ });
34
+
35
+ it('should validate present environment variables', () => {
36
+ process.env.TEST_VAR_1 = 'value1';
37
+ process.env.TEST_VAR_2 = 'value2';
38
+
39
+ const appDefinition = {
40
+ environment: {
41
+ TEST_VAR_1: true,
42
+ TEST_VAR_2: true,
43
+ },
44
+ };
45
+
46
+ const result = validateEnvironmentVariables(appDefinition);
47
+
48
+ expect(result.valid).toEqual(['TEST_VAR_1', 'TEST_VAR_2']);
49
+ expect(result.missing).toEqual([]);
50
+ });
51
+
52
+ it('should detect missing environment variables', () => {
53
+ process.env.TEST_VAR_1 = 'value1';
54
+ // TEST_VAR_2 not set
55
+
56
+ const appDefinition = {
57
+ environment: {
58
+ TEST_VAR_1: true,
59
+ TEST_VAR_2: true,
60
+ },
61
+ };
62
+
63
+ const result = validateEnvironmentVariables(appDefinition);
64
+
65
+ expect(result.valid).toEqual(['TEST_VAR_1']);
66
+ expect(result.missing).toEqual(['TEST_VAR_2']);
67
+ });
68
+
69
+ it('should only validate variables with value true', () => {
70
+ process.env.TEST_VAR_1 = 'value1';
71
+
72
+ const appDefinition = {
73
+ environment: {
74
+ TEST_VAR_1: true,
75
+ TEST_VAR_2: false,
76
+ TEST_VAR_3: 'string-value',
77
+ },
78
+ };
79
+
80
+ const result = validateEnvironmentVariables(appDefinition);
81
+
82
+ expect(result.valid).toEqual(['TEST_VAR_1']);
83
+ expect(result.missing).toEqual([]);
84
+ });
85
+
86
+ it('should handle NODE_ENV specially with warning', () => {
87
+ // NODE_ENV not set
88
+
89
+ const appDefinition = {
90
+ environment: {
91
+ NODE_ENV: true,
92
+ },
93
+ };
94
+
95
+ const result = validateEnvironmentVariables(appDefinition);
96
+
97
+ expect(result.missing).not.toContain('NODE_ENV');
98
+ expect(result.warnings).toContain('NODE_ENV not set, defaulting to "production"');
99
+ });
100
+
101
+ it('should not warn about NODE_ENV if it is set', () => {
102
+ process.env.NODE_ENV = 'development';
103
+
104
+ const appDefinition = {
105
+ environment: {
106
+ NODE_ENV: true,
107
+ },
108
+ };
109
+
110
+ const result = validateEnvironmentVariables(appDefinition);
111
+
112
+ expect(result.valid).toContain('NODE_ENV');
113
+ expect(result.warnings).not.toContain('NODE_ENV not set, defaulting to "production"');
114
+ });
115
+
116
+ it('should warn about missing variables', () => {
117
+ const appDefinition = {
118
+ environment: {
119
+ MISSING_VAR_1: true,
120
+ MISSING_VAR_2: true,
121
+ },
122
+ };
123
+
124
+ const result = validateEnvironmentVariables(appDefinition);
125
+
126
+ expect(result.missing).toEqual(['MISSING_VAR_1', 'MISSING_VAR_2']);
127
+ expect(result.warnings.length).toBeGreaterThan(0);
128
+ });
129
+
130
+ it('should handle mixed valid and missing variables', () => {
131
+ process.env.VALID_VAR = 'value';
132
+
133
+ const appDefinition = {
134
+ environment: {
135
+ VALID_VAR: true,
136
+ MISSING_VAR: true,
137
+ },
138
+ };
139
+
140
+ const result = validateEnvironmentVariables(appDefinition);
141
+
142
+ expect(result.valid).toEqual(['VALID_VAR']);
143
+ expect(result.missing).toEqual(['MISSING_VAR']);
144
+ });
145
+
146
+ it('should handle empty environment object', () => {
147
+ const appDefinition = {
148
+ environment: {},
149
+ };
150
+
151
+ const result = validateEnvironmentVariables(appDefinition);
152
+
153
+ expect(result.valid).toEqual([]);
154
+ expect(result.missing).toEqual([]);
155
+ });
156
+
157
+ it('should handle environment variables with empty string values', () => {
158
+ process.env.TEST_VAR = '';
159
+
160
+ const appDefinition = {
161
+ environment: {
162
+ TEST_VAR: true,
163
+ },
164
+ };
165
+
166
+ const result = validateEnvironmentVariables(appDefinition);
167
+
168
+ // Empty string is still considered "present"
169
+ expect(result.valid).toContain('TEST_VAR');
170
+ });
171
+ });
172
+ });
173
+
@@ -0,0 +1,53 @@
1
+ /**
2
+ * esbuild Configuration for Frigg Lambda Functions
3
+ *
4
+ * Optimized for AWS Lambda Node.js 22.x runtime with:
5
+ * - Tree-shaking for minimal bundle size
6
+ * - AWS SDK v3 externalization (provided by Lambda)
7
+ * - Prisma client externalization (in Lambda layer)
8
+ * - Source maps for debugging
9
+ */
10
+
11
+ module.exports = {
12
+ bundle: true,
13
+ minify: true,
14
+ sourcemap: true,
15
+ target: 'node22', // AWS Lambda Node.js 22.x (latest supported)
16
+ platform: 'node',
17
+ format: 'cjs', // CommonJS for Lambda
18
+ mainFields: ['main', 'module'],
19
+
20
+ // External packages - not included in bundle
21
+ external: [
22
+ // AWS SDK v3 - provided by Lambda runtime
23
+ '@aws-sdk/*',
24
+ 'aws-sdk', // Legacy v2 SDK
25
+
26
+ // Prisma - in Lambda layer
27
+ '@prisma/client',
28
+ 'prisma',
29
+ '.prisma/*',
30
+
31
+ // Native modules
32
+ 'sharp',
33
+ 'canvas',
34
+ 'sqlite3',
35
+ 'pg-native',
36
+ ],
37
+
38
+ // Package manager
39
+ packager: 'npm',
40
+
41
+ // Additional esbuild options
42
+ keepNames: true, // Preserve function names for debugging
43
+ metafile: true, // Generate build metadata
44
+
45
+ // Exclude patterns (for serverless-esbuild plugin)
46
+ exclude: [
47
+ 'aws-sdk',
48
+ '@aws-sdk/*',
49
+ '@prisma/client',
50
+ 'prisma',
51
+ ],
52
+ };
53
+
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Infrastructure Composer
3
+ *
4
+ * Application Layer - Hexagonal Architecture
5
+ *
6
+ * Orchestrates the composition of serverless infrastructure definitions
7
+ * using domain builders and shared utilities.
8
+ */
9
+
10
+ // Domain Builders
11
+ const { BuilderOrchestrator } = require('./domains/shared/builder-orchestrator');
12
+ const { VpcBuilder } = require('./domains/networking/vpc-builder');
13
+ const { KmsBuilder } = require('./domains/security/kms-builder');
14
+ const { AuroraBuilder } = require('./domains/database/aurora-builder');
15
+ const { MigrationBuilder } = require('./domains/database/migration-builder');
16
+ const { SsmBuilder } = require('./domains/parameters/ssm-builder');
17
+ const { WebsocketBuilder } = require('./domains/integration/websocket-builder');
18
+ const { IntegrationBuilder } = require('./domains/integration/integration-builder');
19
+
20
+ // Utilities
21
+ const { modifyHandlerPaths } = require('./domains/shared/utilities/handler-path-resolver');
22
+ const { createBaseDefinition } = require('./domains/shared/utilities/base-definition-factory');
23
+ const { ensurePrismaLayerExists } = require('./domains/shared/utilities/prisma-layer-manager');
24
+
25
+ /**
26
+ * Compose serverless definition using domain builders
27
+ *
28
+ * This is the main entry point that orchestrates all infrastructure building
29
+ * using the DDD/Hexagonal architecture pattern.
30
+ */
31
+ const composeServerlessDefinition = async (AppDefinition) => {
32
+ console.log('🏗️ Composing serverless definition with domain builders...');
33
+
34
+ // Ensure Prisma layer exists (minimal, runtime only)
35
+ await ensurePrismaLayerExists(AppDefinition.database || {});
36
+
37
+ // Create orchestrator with all domain builders
38
+ const orchestrator = new BuilderOrchestrator([
39
+ new VpcBuilder(),
40
+ new KmsBuilder(),
41
+ new AuroraBuilder(),
42
+ new MigrationBuilder(), // Add migration infrastructure after Aurora
43
+ new SsmBuilder(),
44
+ new WebsocketBuilder(),
45
+ new IntegrationBuilder(),
46
+ ]);
47
+
48
+ // Build all infrastructure (orchestrator handles validation, dependencies, parallel execution)
49
+ // Builders automatically skip if shouldExecute() returns false (e.g., local mode)
50
+ const { merged, discoveredResources, appEnvironmentVars } =
51
+ await orchestrator.buildAll(AppDefinition);
52
+
53
+ // Create base definition with core functions
54
+ const definition = createBaseDefinition(
55
+ AppDefinition,
56
+ appEnvironmentVars,
57
+ discoveredResources
58
+ );
59
+
60
+ // Merge builder results into definition
61
+ Object.assign(definition.resources.Resources, merged.resources);
62
+ definition.provider.iamRoleStatements.push(...merged.iamStatements);
63
+ Object.assign(definition.provider.environment, merged.environment);
64
+ Object.assign(definition.functions, merged.functions);
65
+
66
+ if (merged.vpcConfig) {
67
+ definition.provider.vpc = merged.vpcConfig;
68
+ }
69
+
70
+ // Add unique plugins (avoid duplicates)
71
+ merged.plugins.forEach(plugin => {
72
+ if (!definition.plugins.includes(plugin)) {
73
+ definition.plugins.push(plugin);
74
+ }
75
+ });
76
+
77
+ Object.assign(definition.custom, merged.custom);
78
+
79
+ // Modify handler paths for offline mode
80
+ definition.functions = modifyHandlerPaths(definition.functions);
81
+
82
+ console.log('✅ Serverless definition composed successfully');
83
+ return definition;
84
+ };
85
+
86
+ module.exports = { composeServerlessDefinition };
87
+
@@ -1,4 +1,4 @@
1
- const { composeServerlessDefinition } = require('./serverless-template');
1
+ const { composeServerlessDefinition } = require('./infrastructure-composer');
2
2
 
3
3
  // Helper to build discovery responses with overridable fields
4
4
  const createDiscoveryResponse = (overrides = {}) => ({
@@ -7,36 +7,36 @@ const createDiscoveryResponse = (overrides = {}) => ({
7
7
  defaultSecurityGroupId: 'sg-123456',
8
8
  privateSubnetId1: 'subnet-123456',
9
9
  privateSubnetId2: 'subnet-789012',
10
- publicSubnetId: 'subnet-public',
10
+ publicSubnetId: 'subnet-public', // Keep for backward compat
11
+ publicSubnetId1: 'subnet-public-1',
12
+ publicSubnetId2: 'subnet-public-2',
11
13
  defaultRouteTableId: 'rtb-123456',
12
14
  defaultKmsKeyId:
13
15
  'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012',
14
16
  existingNatGatewayId: 'nat-default123',
17
+ auroraClusterEndpoint: 'test-cluster.cluster-abc123.us-east-1.rds.amazonaws.com',
18
+ auroraPort: 5432,
19
+ auroraEngine: 'aurora-postgresql',
15
20
  ...overrides,
16
21
  });
17
22
 
18
- // Mock AWS Discovery to prevent actual AWS calls
19
- jest.mock('./aws-discovery', () => {
23
+ // Mock resource discovery to prevent actual AWS calls
24
+ jest.mock('./domains/shared/resource-discovery', () => {
25
+ const originalModule = jest.requireActual('./domains/shared/resource-discovery');
20
26
  return {
21
- AWSDiscovery: jest.fn().mockImplementation(() => ({
22
- discoverResources: jest
23
- .fn()
24
- .mockResolvedValue(createDiscoveryResponse()),
25
- })),
27
+ ...originalModule,
28
+ gatherDiscoveredResources: jest.fn().mockResolvedValue(createDiscoveryResponse()),
26
29
  };
27
30
  });
28
31
 
29
- const { AWSDiscovery } = require('./aws-discovery');
32
+ const { gatherDiscoveredResources } = require('./domains/shared/resource-discovery');
30
33
 
31
34
  describe('composeServerlessDefinition', () => {
32
35
  let mockIntegration;
33
36
 
34
37
  beforeEach(() => {
35
- AWSDiscovery.mockImplementation(() => ({
36
- discoverResources: jest
37
- .fn()
38
- .mockResolvedValue(createDiscoveryResponse()),
39
- }));
38
+ // Reset the mock to default behavior
39
+ gatherDiscoveredResources.mockResolvedValue(createDiscoveryResponse());
40
40
 
41
41
  mockIntegration = {
42
42
  Definition: {
@@ -52,7 +52,7 @@ describe('composeServerlessDefinition', () => {
52
52
  });
53
53
 
54
54
  afterEach(() => {
55
- jest.restoreAllMocks();
55
+ jest.clearAllMocks();
56
56
  // Restore env
57
57
  delete process.env.AWS_REGION;
58
58
  delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
@@ -61,7 +61,7 @@ describe('composeServerlessDefinition', () => {
61
61
 
62
62
  describe('AWS discovery gating', () => {
63
63
  it('should skip AWS discovery when no features require it', async () => {
64
- AWSDiscovery.mockClear();
64
+ gatherDiscoveredResources.mockClear();
65
65
 
66
66
  const appDefinition = {
67
67
  integrations: [],
@@ -72,11 +72,11 @@ describe('composeServerlessDefinition', () => {
72
72
 
73
73
  await composeServerlessDefinition(appDefinition);
74
74
 
75
- expect(AWSDiscovery).not.toHaveBeenCalled();
75
+ expect(gatherDiscoveredResources).not.toHaveBeenCalled();
76
76
  });
77
77
 
78
78
  it('should run AWS discovery when VPC features are enabled', async () => {
79
- AWSDiscovery.mockClear();
79
+ gatherDiscoveredResources.mockClear();
80
80
 
81
81
  const appDefinition = {
82
82
  integrations: [],
@@ -85,11 +85,11 @@ describe('composeServerlessDefinition', () => {
85
85
 
86
86
  await composeServerlessDefinition(appDefinition);
87
87
 
88
- expect(AWSDiscovery).toHaveBeenCalledTimes(1);
88
+ expect(gatherDiscoveredResources).toHaveBeenCalledTimes(1);
89
89
  });
90
90
 
91
91
  it('should skip AWS discovery when FRIGG_SKIP_AWS_DISCOVERY is set to true', async () => {
92
- AWSDiscovery.mockClear();
92
+ gatherDiscoveredResources.mockClear();
93
93
  process.env.FRIGG_SKIP_AWS_DISCOVERY = 'true';
94
94
 
95
95
  const appDefinition = {
@@ -101,11 +101,11 @@ describe('composeServerlessDefinition', () => {
101
101
 
102
102
  await composeServerlessDefinition(appDefinition);
103
103
 
104
- expect(AWSDiscovery).not.toHaveBeenCalled();
104
+ expect(gatherDiscoveredResources).not.toHaveBeenCalled();
105
105
  });
106
106
 
107
107
  it('should run AWS discovery when FRIGG_SKIP_AWS_DISCOVERY is not set', async () => {
108
- AWSDiscovery.mockClear();
108
+ gatherDiscoveredResources.mockClear();
109
109
  delete process.env.FRIGG_SKIP_AWS_DISCOVERY;
110
110
 
111
111
  const appDefinition = {
@@ -115,7 +115,7 @@ describe('composeServerlessDefinition', () => {
115
115
 
116
116
  await composeServerlessDefinition(appDefinition);
117
117
 
118
- expect(AWSDiscovery).toHaveBeenCalledTimes(1);
118
+ expect(gatherDiscoveredResources).toHaveBeenCalledTimes(1);
119
119
  });
120
120
 
121
121
  it('should skip VPC configuration when FRIGG_SKIP_AWS_DISCOVERY is true', async () => {
@@ -1762,6 +1762,97 @@ describe('composeServerlessDefinition', () => {
1762
1762
  });
1763
1763
  });
1764
1764
 
1765
+ describe('Database Migration Lambda', () => {
1766
+ it('should include dbMigrate function in all deployments', async () => {
1767
+ const appDefinition = {
1768
+ name: 'test-app',
1769
+ integrations: []
1770
+ };
1771
+
1772
+ const result = await composeServerlessDefinition(appDefinition);
1773
+
1774
+ // Check dbMigrate function exists
1775
+ expect(result.functions.dbMigrate).toBeDefined();
1776
+ expect(result.functions.dbMigrate.handler).toBe(
1777
+ 'node_modules/@friggframework/core/handlers/workers/db-migration.handler'
1778
+ );
1779
+ });
1780
+
1781
+ it('should configure dbMigrate with correct settings', async () => {
1782
+ const appDefinition = {
1783
+ integrations: []
1784
+ };
1785
+
1786
+ const result = await composeServerlessDefinition(appDefinition);
1787
+
1788
+ const dbMigrate = result.functions.dbMigrate;
1789
+
1790
+ // Check timeout (5 minutes for long migrations)
1791
+ expect(dbMigrate.timeout).toBe(300);
1792
+
1793
+ // Check memory allocation (extra for Prisma CLI)
1794
+ expect(dbMigrate.memorySize).toBe(512);
1795
+
1796
+ // Check description
1797
+ expect(dbMigrate.description).toContain('database migrations');
1798
+ expect(dbMigrate.description).toContain('Prisma');
1799
+ });
1800
+
1801
+ it('should not have HTTP events (manual invocation only)', async () => {
1802
+ const appDefinition = {
1803
+ integrations: []
1804
+ };
1805
+
1806
+ const result = await composeServerlessDefinition(appDefinition);
1807
+
1808
+ const dbMigrate = result.functions.dbMigrate;
1809
+
1810
+ // Should have no events (manually invoked via AWS CLI)
1811
+ expect(dbMigrate.events).toBeUndefined();
1812
+ });
1813
+
1814
+ it('should include dbMigrate even with VPC enabled', async () => {
1815
+ const appDefinition = {
1816
+ vpc: {
1817
+ enable: true,
1818
+ management: 'discover'
1819
+ },
1820
+ integrations: []
1821
+ };
1822
+
1823
+ const result = await composeServerlessDefinition(appDefinition);
1824
+
1825
+ // dbMigrate should exist with VPC configuration
1826
+ expect(result.functions.dbMigrate).toBeDefined();
1827
+
1828
+ // Should have same VPC access as other functions
1829
+ expect(result.provider.vpc).toBeDefined();
1830
+ });
1831
+
1832
+ it('should include dbMigrate with database configuration', async () => {
1833
+ const appDefinition = {
1834
+ vpc: {
1835
+ enable: true,
1836
+ management: 'discover'
1837
+ },
1838
+ database: {
1839
+ postgres: {
1840
+ enable: true,
1841
+ management: 'discover'
1842
+ }
1843
+ },
1844
+ integrations: []
1845
+ };
1846
+
1847
+ const result = await composeServerlessDefinition(appDefinition);
1848
+
1849
+ // dbMigrate should exist alongside database configuration
1850
+ expect(result.functions.dbMigrate).toBeDefined();
1851
+ expect(result.provider.environment.DB_TYPE).toBe('postgresql');
1852
+ expect(result.provider.environment.DATABASE_URL).toBeDefined();
1853
+ });
1854
+ });
1855
+
1765
1856
  describe('Edge Cases', () => {
1766
1857
  it('should handle empty app definition', async () => {
1767
1858
  const appDefinition = {};