@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,435 @@
1
+ /**
2
+ * ImportTemplateGenerator - Generate CloudFormation import templates
3
+ *
4
+ * Purpose: Generate CloudFormation templates for importing existing resources
5
+ * by resolving intrinsic functions (!Ref, !Sub, !GetAtt) with actual AWS values
6
+ * and merging with current stack template.
7
+ *
8
+ * Domain Layer - Service
9
+ */
10
+
11
+ class ImportTemplateGenerator {
12
+ /**
13
+ * Create ImportTemplateGenerator instance
14
+ * @param {object} dependencies - Service dependencies
15
+ * @param {object} dependencies.templateParser - Template parsing service
16
+ * @param {object} dependencies.resourceDetector - AWS resource detection service
17
+ * @param {object} dependencies.stackRepository - CloudFormation stack repository
18
+ */
19
+ constructor({ templateParser, resourceDetector, stackRepository }) {
20
+ this.templateParser = templateParser;
21
+ this.resourceDetector = resourceDetector;
22
+ this.stackRepository = stackRepository;
23
+ }
24
+
25
+ /**
26
+ * Generate import template by merging build template with AWS state
27
+ *
28
+ * Process:
29
+ * 1. Parse build template to get resource definitions with Refs
30
+ * 2. Get current stack template (if exists)
31
+ * 3. For each resource to import:
32
+ * - Get AWS resource properties via resourceDetector
33
+ * - Generate resource definition with resolved intrinsics
34
+ * - Create resource identifier for import operation
35
+ * 4. Merge with current template (preserve existing resources)
36
+ *
37
+ * @param {object} params - Generation parameters
38
+ * @param {Array} params.resourcesToImport - Resources to import
39
+ * @param {string} params.buildTemplatePath - Path to build template
40
+ * @param {object} params.stackIdentifier - Target stack identifier
41
+ * @returns {Promise<object>} Import template and resource identifiers
42
+ */
43
+ async generateImportTemplate({
44
+ resourcesToImport,
45
+ buildTemplatePath,
46
+ stackIdentifier,
47
+ }) {
48
+ // 1. Parse build template
49
+ const buildTemplate = this.templateParser.parseTemplate(buildTemplatePath);
50
+
51
+ // 2. Get current stack template (if exists)
52
+ let currentTemplate;
53
+ try {
54
+ currentTemplate = await this.stackRepository.getTemplate(stackIdentifier);
55
+ } catch (error) {
56
+ // Stack might not exist yet
57
+ currentTemplate = { Resources: {} };
58
+ }
59
+
60
+ // 3. For each resource to import, get AWS properties
61
+ const resourceDefinitions = {};
62
+ const resourceIdentifiers = [];
63
+
64
+ for (const resource of resourcesToImport) {
65
+ const { logicalId, physicalId, resourceType } = resource;
66
+
67
+ // Get current resource state from AWS
68
+ const awsResourceDetails =
69
+ await this.resourceDetector.getResourceDetails({
70
+ resourceType,
71
+ physicalId,
72
+ region: stackIdentifier.region,
73
+ });
74
+
75
+ // Generate CloudFormation resource definition
76
+ const resourceDef = this._generateResourceDefinition({
77
+ logicalId,
78
+ resourceType,
79
+ physicalId,
80
+ buildTemplate,
81
+ awsResourceDetails,
82
+ });
83
+
84
+ resourceDefinitions[logicalId] = resourceDef;
85
+
86
+ // Generate resource identifier for import
87
+ resourceIdentifiers.push({
88
+ ResourceType: resourceType,
89
+ LogicalResourceId: logicalId,
90
+ ResourceIdentifier: this._getResourceIdentifier(
91
+ resourceType,
92
+ physicalId
93
+ ),
94
+ });
95
+ }
96
+
97
+ // 4. Merge with current template (keep existing resources)
98
+ const importTemplate = {
99
+ ...currentTemplate,
100
+ Resources: {
101
+ ...currentTemplate.Resources,
102
+ ...resourceDefinitions,
103
+ },
104
+ };
105
+
106
+ // DEBUG: Write template to file for inspection
107
+ if (process.env.DEBUG_IMPORT_TEMPLATE === 'true') {
108
+ const fs = require('fs');
109
+ const path = require('path');
110
+ const debugDir = path.join(__dirname, '../../debug');
111
+
112
+ // Ensure debug directory exists
113
+ if (!fs.existsSync(debugDir)) {
114
+ fs.mkdirSync(debugDir, { recursive: true });
115
+ }
116
+
117
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
118
+ const debugFile = path.join(debugDir, `import-template-${timestamp}.json`);
119
+
120
+ const debugData = {
121
+ stackIdentifier,
122
+ resourcesToImport,
123
+ resourceIdentifiers,
124
+ template: importTemplate,
125
+ templateSize: JSON.stringify(importTemplate).length,
126
+ resourceCount: Object.keys(importTemplate.Resources || {}).length,
127
+ };
128
+
129
+ fs.writeFileSync(debugFile, JSON.stringify(debugData, null, 2));
130
+ console.log(`[DEBUG] Template written to: ${debugFile}`);
131
+ }
132
+
133
+ return {
134
+ template: importTemplate,
135
+ resourceIdentifiers,
136
+ };
137
+ }
138
+
139
+ /**
140
+ * Generate CloudFormation resource definition from AWS state
141
+ *
142
+ * Takes build template definition and resolves all intrinsics
143
+ * with actual AWS values to create import-ready definition.
144
+ *
145
+ * @private
146
+ * @param {object} params - Generation parameters
147
+ * @param {string} params.logicalId - CloudFormation logical ID
148
+ * @param {string} params.resourceType - AWS resource type
149
+ * @param {string} params.physicalId - AWS physical resource ID
150
+ * @param {object} params.buildTemplate - Build template with Refs
151
+ * @param {object} params.awsResourceDetails - Current AWS resource state
152
+ * @returns {object} CloudFormation resource definition
153
+ * @throws {Error} If logical ID not found in build template
154
+ */
155
+ _generateResourceDefinition({
156
+ logicalId,
157
+ resourceType,
158
+ physicalId,
159
+ buildTemplate,
160
+ awsResourceDetails,
161
+ }) {
162
+ // Start with build template definition if available
163
+ const buildResource = buildTemplate.resources?.[logicalId];
164
+
165
+ if (!buildResource) {
166
+ throw new Error(
167
+ `Logical ID ${logicalId} not found in build template. ` +
168
+ `Cannot generate import definition without template reference.`
169
+ );
170
+ }
171
+
172
+ // Resolve intrinsics with actual AWS values
173
+ const resolvedProperties = this._resolveIntrinsics({
174
+ properties: buildResource.Properties,
175
+ awsResourceDetails,
176
+ resourceType,
177
+ });
178
+
179
+ return {
180
+ Type: resourceType,
181
+ Properties: resolvedProperties,
182
+ DeletionPolicy: 'Retain', // Required for CloudFormation IMPORT operations
183
+ UpdateReplacePolicy: 'Retain', // Protects old resources during stack updates
184
+ };
185
+ }
186
+
187
+ /**
188
+ * Resolve CloudFormation intrinsics in properties
189
+ *
190
+ * Processes all properties and resolves intrinsic functions
191
+ * (!Ref, !Sub, !GetAtt) with actual AWS values.
192
+ *
193
+ * @private
194
+ * @param {object} params - Resolution parameters
195
+ * @param {object} params.properties - CloudFormation properties
196
+ * @param {object} params.awsResourceDetails - AWS resource state
197
+ * @param {string} params.resourceType - AWS resource type
198
+ * @returns {object} Resolved properties
199
+ */
200
+ _resolveIntrinsics({ properties, awsResourceDetails, resourceType }) {
201
+ const resolved = {};
202
+
203
+ for (const [key, value] of Object.entries(properties)) {
204
+ resolved[key] = this._resolveValue(
205
+ value,
206
+ awsResourceDetails,
207
+ resourceType
208
+ );
209
+ }
210
+
211
+ return resolved;
212
+ }
213
+
214
+ /**
215
+ * Recursively resolve a property value
216
+ *
217
+ * Handles:
218
+ * - Intrinsic functions (!Ref, !Sub, !GetAtt)
219
+ * - Nested objects
220
+ * - Arrays
221
+ * - Literal values
222
+ *
223
+ * @private
224
+ * @param {*} value - Property value to resolve
225
+ * @param {object} awsResourceDetails - AWS resource state
226
+ * @param {string} resourceType - AWS resource type
227
+ * @returns {*} Resolved value
228
+ */
229
+ _resolveValue(value, awsResourceDetails, resourceType) {
230
+ // Handle intrinsic functions
231
+ if (typeof value === 'object' && value !== null) {
232
+ // !Ref
233
+ if (value.Ref) {
234
+ return this._resolveRef(value.Ref, awsResourceDetails, resourceType);
235
+ }
236
+
237
+ // !Sub
238
+ if (value['Fn::Sub']) {
239
+ return this._resolveSub(value['Fn::Sub'], awsResourceDetails);
240
+ }
241
+
242
+ // !GetAtt
243
+ if (value['Fn::GetAtt']) {
244
+ return this._resolveGetAtt(value['Fn::GetAtt'], awsResourceDetails);
245
+ }
246
+
247
+ // Recursively process nested objects
248
+ if (Array.isArray(value)) {
249
+ return value.map((v) =>
250
+ this._resolveValue(v, awsResourceDetails, resourceType)
251
+ );
252
+ }
253
+
254
+ // Recursively process object properties
255
+ const resolved = {};
256
+ for (const [k, v] of Object.entries(value)) {
257
+ resolved[k] = this._resolveValue(v, awsResourceDetails, resourceType);
258
+ }
259
+ return resolved;
260
+ }
261
+
262
+ // Literal value
263
+ return value;
264
+ }
265
+
266
+ /**
267
+ * Resolve !Ref to actual AWS value
268
+ *
269
+ * Maps common parameter names and resource references to AWS property values.
270
+ * Supports:
271
+ * - Parameter names (VpcCidr, VpcId, etc.)
272
+ * - Resource logical IDs (FriggVPC, FriggLambdaSecurityGroup, etc.)
273
+ * - Direct property references (Subnet1, Subnet2, etc.)
274
+ *
275
+ * @private
276
+ * @param {string} refName - Reference name
277
+ * @param {object} awsResourceDetails - AWS resource state
278
+ * @param {string} resourceType - AWS resource type
279
+ * @returns {*} Resolved value
280
+ */
281
+ _resolveRef(refName, awsResourceDetails, resourceType) {
282
+ // Map common parameters to AWS properties
283
+ const refMap = {
284
+ VpcCidr: awsResourceDetails.properties?.CidrBlock,
285
+ VpcId: awsResourceDetails.properties?.VpcId,
286
+ };
287
+
288
+ if (refMap[refName] !== undefined) {
289
+ return refMap[refName];
290
+ }
291
+
292
+ // First, try direct property lookup
293
+ // This handles cases like { Ref: 'Subnet1' } where properties.Subnet1 = 'subnet-111'
294
+ const directValue = awsResourceDetails.properties?.[refName];
295
+ if (directValue !== undefined) {
296
+ return directValue;
297
+ }
298
+
299
+ // Check if refName is a resource logical ID that references another resource
300
+ // In this case, the AWS properties will already have the resolved value
301
+ // For example: { Ref: 'FriggVPC' } should resolve to VpcId from properties
302
+ // For example: { Ref: 'FriggLambdaSecurityGroup' } should resolve to GroupId from properties
303
+ if (refName.includes('VPC') && !refName.includes('Endpoint')) {
304
+ // VPC resource reference
305
+ return awsResourceDetails.properties?.VpcId || refName;
306
+ } else if (refName.includes('Subnet')) {
307
+ // Subnet resource reference
308
+ return awsResourceDetails.properties?.SubnetId || refName;
309
+ } else if (refName.includes('SecurityGroup')) {
310
+ // Security Group resource reference
311
+ return awsResourceDetails.properties?.GroupId || refName;
312
+ }
313
+
314
+ // Fallback: return the ref name itself if not found
315
+ return refName;
316
+ }
317
+
318
+ /**
319
+ * Resolve !Sub to actual string
320
+ *
321
+ * Replaces CloudFormation pseudo parameters and variables
322
+ * with actual values from AWS resource state.
323
+ *
324
+ * Supports:
325
+ * - ${AWS::StackName}
326
+ * - Custom variables from tags
327
+ *
328
+ * @private
329
+ * @param {string|object} subValue - Sub expression
330
+ * @param {object} awsResourceDetails - AWS resource state
331
+ * @returns {string|object} Resolved value
332
+ */
333
+ _resolveSub(subValue, awsResourceDetails) {
334
+ if (typeof subValue !== 'string') {
335
+ return subValue;
336
+ }
337
+
338
+ // Replace ${AWS::StackName} with actual stack name
339
+ let resolved = subValue.replace(
340
+ /\$\{AWS::StackName\}/g,
341
+ awsResourceDetails.stackName || ''
342
+ );
343
+
344
+ // Replace other variables if present in tags
345
+ if (awsResourceDetails.tags) {
346
+ for (const [key, value] of Object.entries(awsResourceDetails.tags)) {
347
+ resolved = resolved.replace(new RegExp(`\\$\\{${key}\\}`, 'g'), value);
348
+ }
349
+ }
350
+
351
+ return resolved;
352
+ }
353
+
354
+ /**
355
+ * Resolve !GetAtt to actual attribute value
356
+ *
357
+ * Gets attribute value from AWS resource properties.
358
+ * When the attribute refers to a different resource's property
359
+ * (e.g., FriggVPC.CidrBlock from a Subnet), we need to look at
360
+ * the actual AWS values in the current resource's properties.
361
+ *
362
+ * The AWS resource details from the detector already contain
363
+ * resolved values. For example, a Subnet may have Tags that
364
+ * include the VPC's CIDR, or properties that include the VPC ID.
365
+ *
366
+ * @private
367
+ * @param {Array} getAttValue - GetAtt expression [ResourceName, AttributeName]
368
+ * @param {object} awsResourceDetails - AWS resource state
369
+ * @returns {*} Attribute value or null
370
+ */
371
+ _resolveGetAtt([resourceName, attributeName], awsResourceDetails) {
372
+ // First try to get directly from properties
373
+ const directValue = awsResourceDetails.properties?.[attributeName];
374
+ if (directValue !== undefined && directValue !== null) {
375
+ // Check if this is the actual value we want
376
+ // For cross-resource references, we need to be more careful
377
+ // If resourceName refers to a different resource (e.g., FriggVPC from a Subnet),
378
+ // the property might not be the right one
379
+
380
+ // If getting VPC.CidrBlock, but we have Subnet.CidrBlock,
381
+ // we need to look elsewhere
382
+ if (resourceName.includes('VPC') && attributeName === 'CidrBlock') {
383
+ // Check if this is actually a subnet's CIDR (starts with same first two octets + .X.0/24 pattern)
384
+ // If so, we need to look at Tags for VpcCidr
385
+ const tags = awsResourceDetails.properties?.Tags;
386
+ if (Array.isArray(tags)) {
387
+ const vpcCidrTag = tags.find(t => t.Key === 'VpcCidr');
388
+ if (vpcCidrTag) {
389
+ return vpcCidrTag.Value;
390
+ }
391
+ }
392
+ }
393
+
394
+ return directValue;
395
+ }
396
+
397
+ // Check Tags as fallback
398
+ const tags = awsResourceDetails.properties?.Tags;
399
+ if (Array.isArray(tags)) {
400
+ const tag = tags.find(t => t.Key === attributeName || t.Key === `${resourceName}${attributeName}`);
401
+ if (tag) {
402
+ return tag.Value;
403
+ }
404
+ }
405
+
406
+ return null;
407
+ }
408
+
409
+ /**
410
+ * Get resource identifier for import operation
411
+ *
412
+ * Maps resource type to CloudFormation import identifier format.
413
+ * Each AWS resource type has a specific identifier property.
414
+ *
415
+ * @private
416
+ * @param {string} resourceType - AWS resource type
417
+ * @param {string} physicalId - AWS physical resource ID
418
+ * @returns {object} Resource identifier for import
419
+ */
420
+ _getResourceIdentifier(resourceType, physicalId) {
421
+ const identifierMap = {
422
+ 'AWS::EC2::VPC': { VpcId: physicalId },
423
+ 'AWS::EC2::Subnet': { SubnetId: physicalId },
424
+ 'AWS::EC2::SecurityGroup': { Id: physicalId },
425
+ 'AWS::EC2::InternetGateway': { InternetGatewayId: physicalId },
426
+ 'AWS::EC2::NatGateway': { NatGatewayId: physicalId },
427
+ 'AWS::EC2::RouteTable': { RouteTableId: physicalId },
428
+ 'AWS::EC2::VPCEndpoint': { VpcEndpointId: physicalId },
429
+ };
430
+
431
+ return identifierMap[resourceType] || { Id: physicalId };
432
+ }
433
+ }
434
+
435
+ module.exports = { ImportTemplateGenerator };