@friggframework/devtools 2.0.0-next.45 → 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 -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,318 @@
1
+ /**
2
+ * AWSResourceImporter - AWS CloudFormation Resource Import Adapter
3
+ *
4
+ * Infrastructure Adapter - Hexagonal Architecture
5
+ *
6
+ * Implements IResourceImporter port for AWS CloudFormation.
7
+ * Handles resource import operations using CloudFormation change sets.
8
+ *
9
+ * Lazy-loads AWS SDK to minimize cold start time and memory usage.
10
+ */
11
+
12
+ const IResourceImporter = require('../../application/ports/IResourceImporter');
13
+
14
+ // Lazy-loaded AWS SDK CloudFormation client
15
+ let CloudFormationClient,
16
+ CreateChangeSetCommand,
17
+ DescribeChangeSetCommand,
18
+ ExecuteChangeSetCommand,
19
+ GetTemplateCommand;
20
+
21
+ /**
22
+ * Lazy load CloudFormation SDK
23
+ */
24
+ function loadCloudFormation() {
25
+ if (!CloudFormationClient) {
26
+ const cfModule = require('@aws-sdk/client-cloudformation');
27
+ CloudFormationClient = cfModule.CloudFormationClient;
28
+ CreateChangeSetCommand = cfModule.CreateChangeSetCommand;
29
+ DescribeChangeSetCommand = cfModule.DescribeChangeSetCommand;
30
+ ExecuteChangeSetCommand = cfModule.ExecuteChangeSetCommand;
31
+ GetTemplateCommand = cfModule.GetTemplateCommand;
32
+ }
33
+ }
34
+
35
+ class AWSResourceImporter extends IResourceImporter {
36
+ /**
37
+ * Resource types that support import
38
+ * Maps CloudFormation resource type to identifier property
39
+ * @private
40
+ */
41
+ static IMPORTABLE_TYPES = {
42
+ 'AWS::EC2::VPC': 'VpcId',
43
+ 'AWS::EC2::Subnet': 'SubnetId',
44
+ 'AWS::EC2::SecurityGroup': 'GroupId',
45
+ 'AWS::EC2::RouteTable': 'RouteTableId',
46
+ 'AWS::RDS::DBCluster': 'DBClusterIdentifier',
47
+ 'AWS::KMS::Key': 'KeyId',
48
+ };
49
+
50
+ /**
51
+ * Create AWS Resource Importer
52
+ *
53
+ * @param {Object} [config={}]
54
+ * @param {string} [config.region] - AWS region (defaults to AWS_REGION env var)
55
+ */
56
+ constructor(config = {}) {
57
+ super();
58
+ this.region = config.region || process.env.AWS_REGION || 'us-east-1';
59
+ this.client = null;
60
+ }
61
+
62
+ /**
63
+ * Get or create CloudFormation client
64
+ * @private
65
+ */
66
+ _getClient() {
67
+ if (!this.client) {
68
+ loadCloudFormation();
69
+ this.client = new CloudFormationClient({ region: this.region });
70
+ }
71
+ return this.client;
72
+ }
73
+
74
+ /**
75
+ * Check if a resource type supports import
76
+ */
77
+ async supportsImport(resourceType) {
78
+ return resourceType in AWSResourceImporter.IMPORTABLE_TYPES;
79
+ }
80
+
81
+ /**
82
+ * Get the identifier property for a resource type
83
+ */
84
+ async getIdentifierProperty(resourceType) {
85
+ if (!(await this.supportsImport(resourceType))) {
86
+ throw new Error(`Resource type ${resourceType} does not support import`);
87
+ }
88
+
89
+ return AWSResourceImporter.IMPORTABLE_TYPES[resourceType];
90
+ }
91
+
92
+ /**
93
+ * Validate that a resource can be imported
94
+ */
95
+ async validateImport({ resourceType, physicalId, region }) {
96
+ const canImport = await this.supportsImport(resourceType);
97
+
98
+ if (!canImport) {
99
+ return {
100
+ canImport: false,
101
+ reason: `Resource type ${resourceType} is not supported for import`,
102
+ warnings: [],
103
+ };
104
+ }
105
+
106
+ // Add resource-specific warnings
107
+ const warnings = [];
108
+ if (resourceType === 'AWS::RDS::DBCluster') {
109
+ warnings.push(
110
+ 'Ensure DBCluster has required properties (Engine, MasterUsername, etc.)'
111
+ );
112
+ }
113
+
114
+ return {
115
+ canImport: true,
116
+ reason: '',
117
+ warnings,
118
+ };
119
+ }
120
+
121
+ /**
122
+ * Import a single resource into a stack
123
+ */
124
+ async importResource({ stackIdentifier, logicalId, resourceType, physicalId, properties }) {
125
+ // Validate resource type
126
+ if (!(await this.supportsImport(resourceType))) {
127
+ throw new Error(`Resource type ${resourceType} does not support import`);
128
+ }
129
+
130
+ const client = this._getClient();
131
+
132
+ // Get identifier property
133
+ const identifierProperty = await this.getIdentifierProperty(resourceType);
134
+
135
+ // Create change set for import
136
+ const changeSetName = `import-${logicalId}-${Date.now()}`;
137
+
138
+ const createChangeSetCommand = new CreateChangeSetCommand({
139
+ StackName: stackIdentifier.stackName,
140
+ ChangeSetName: changeSetName,
141
+ ChangeSetType: 'IMPORT',
142
+ ResourcesToImport: [
143
+ {
144
+ ResourceType: resourceType,
145
+ LogicalResourceId: logicalId,
146
+ ResourceIdentifier: {
147
+ [identifierProperty]: physicalId,
148
+ },
149
+ },
150
+ ],
151
+ TemplateBody: JSON.stringify({
152
+ Resources: {
153
+ [logicalId]: {
154
+ Type: resourceType,
155
+ Properties: properties,
156
+ },
157
+ },
158
+ }),
159
+ });
160
+
161
+ const createResponse = await client.send(createChangeSetCommand);
162
+
163
+ // Execute the change set
164
+ const executeCommand = new ExecuteChangeSetCommand({
165
+ ChangeSetName: changeSetName,
166
+ StackName: stackIdentifier.stackName,
167
+ });
168
+
169
+ await client.send(executeCommand);
170
+
171
+ return {
172
+ operationId: createResponse.Id,
173
+ status: 'IN_PROGRESS',
174
+ message: `Resource import initiated via change set ${createResponse.Id}`,
175
+ };
176
+ }
177
+
178
+ /**
179
+ * Import multiple resources into a stack in a single operation
180
+ */
181
+ async importMultipleResources({ stackIdentifier, resources }) {
182
+ const client = this._getClient();
183
+
184
+ // Filter to only supported resources
185
+ const supportedResources = [];
186
+ const unsupportedResources = [];
187
+
188
+ for (const resource of resources) {
189
+ if (await this.supportsImport(resource.resourceType)) {
190
+ supportedResources.push(resource);
191
+ } else {
192
+ unsupportedResources.push(resource);
193
+ }
194
+ }
195
+
196
+ if (supportedResources.length === 0) {
197
+ return {
198
+ operationId: null,
199
+ status: 'FAILED',
200
+ importedCount: 0,
201
+ failedCount: resources.length,
202
+ message: 'No supported resources to import',
203
+ details: [],
204
+ };
205
+ }
206
+
207
+ // Build resources to import
208
+ const resourcesToImport = [];
209
+ const templateResources = {};
210
+
211
+ for (const resource of supportedResources) {
212
+ const identifierProperty = await this.getIdentifierProperty(resource.resourceType);
213
+
214
+ resourcesToImport.push({
215
+ ResourceType: resource.resourceType,
216
+ LogicalResourceId: resource.logicalId,
217
+ ResourceIdentifier: {
218
+ [identifierProperty]: resource.physicalId,
219
+ },
220
+ });
221
+
222
+ templateResources[resource.logicalId] = {
223
+ Type: resource.resourceType,
224
+ Properties: resource.properties,
225
+ };
226
+ }
227
+
228
+ // Create change set for import
229
+ const changeSetName = `import-multi-${Date.now()}`;
230
+
231
+ const createChangeSetCommand = new CreateChangeSetCommand({
232
+ StackName: stackIdentifier.stackName,
233
+ ChangeSetName: changeSetName,
234
+ ChangeSetType: 'IMPORT',
235
+ ResourcesToImport: resourcesToImport,
236
+ TemplateBody: JSON.stringify({
237
+ Resources: templateResources,
238
+ }),
239
+ });
240
+
241
+ const createResponse = await client.send(createChangeSetCommand);
242
+
243
+ // Execute the change set
244
+ const executeCommand = new ExecuteChangeSetCommand({
245
+ ChangeSetName: changeSetName,
246
+ StackName: stackIdentifier.stackName,
247
+ });
248
+
249
+ await client.send(executeCommand);
250
+
251
+ return {
252
+ operationId: createResponse.Id,
253
+ status: 'IN_PROGRESS',
254
+ importedCount: supportedResources.length,
255
+ failedCount: unsupportedResources.length,
256
+ message: `Import operation initiated for ${supportedResources.length} resources`,
257
+ details: [],
258
+ };
259
+ }
260
+
261
+ /**
262
+ * Get status of an import operation
263
+ */
264
+ async getImportStatus(operationId) {
265
+ const client = this._getClient();
266
+
267
+ const command = new DescribeChangeSetCommand({
268
+ ChangeSetName: operationId,
269
+ });
270
+
271
+ const response = await client.send(command);
272
+
273
+ // Map CloudFormation status to our status
274
+ let status = 'IN_PROGRESS';
275
+ let progress = 0;
276
+
277
+ if (response.ExecutionStatus === 'EXECUTE_COMPLETE') {
278
+ status = 'COMPLETE';
279
+ progress = 100;
280
+ } else if (response.Status === 'FAILED' || response.ExecutionStatus === 'EXECUTE_FAILED') {
281
+ status = 'FAILED';
282
+ progress = 0;
283
+ } else if (response.Status === 'CREATE_COMPLETE') {
284
+ status = 'IN_PROGRESS';
285
+ progress = 50;
286
+ } else if (response.Status === 'CREATE_PENDING') {
287
+ status = 'IN_PROGRESS';
288
+ progress = 25;
289
+ }
290
+
291
+ return {
292
+ operationId,
293
+ status,
294
+ progress,
295
+ message: response.StatusReason || '',
296
+ completedTime: status === 'COMPLETE' ? response.CreationTime : null,
297
+ };
298
+ }
299
+
300
+ /**
301
+ * Generate CloudFormation template snippet for an imported resource
302
+ */
303
+ async generateTemplateSnippet({ logicalId, resourceType, properties }) {
304
+ // Validate resource type
305
+ if (!(await this.supportsImport(resourceType))) {
306
+ throw new Error(`Resource type ${resourceType} does not support import`);
307
+ }
308
+
309
+ return {
310
+ [logicalId]: {
311
+ Type: resourceType,
312
+ Properties: properties,
313
+ },
314
+ };
315
+ }
316
+ }
317
+
318
+ module.exports = AWSResourceImporter;