@gugananuvem/aws-local-simulator 1.0.7 → 1.0.9

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 (37) hide show
  1. package/bin/aws-local-simulator.js +62 -1
  2. package/package.json +10 -7
  3. package/src/config/config-loader.js +113 -0
  4. package/src/config/default-config.js +65 -0
  5. package/src/config/env-loader.js +67 -0
  6. package/src/index.js +131 -1
  7. package/src/index.mjs +124 -0
  8. package/src/server.js +219 -0
  9. package/src/services/apigateway/index.js +67 -0
  10. package/src/services/apigateway/server.js +435 -0
  11. package/src/services/apigateway/simulator.js +1252 -0
  12. package/src/services/cognito/index.js +66 -0
  13. package/src/services/cognito/server.js +229 -0
  14. package/src/services/cognito/simulator.js +848 -0
  15. package/src/services/dynamodb/index.js +71 -0
  16. package/src/services/dynamodb/server.js +122 -0
  17. package/src/services/dynamodb/simulator.js +614 -0
  18. package/src/services/eventbridge/index.js +85 -0
  19. package/src/services/index.js +19 -0
  20. package/src/services/lambda/handler-loader.js +173 -0
  21. package/src/services/lambda/index.js +73 -0
  22. package/src/services/lambda/route-registry.js +275 -0
  23. package/src/services/lambda/server.js +153 -0
  24. package/src/services/lambda/simulator.js +278 -0
  25. package/src/services/s3/index.js +70 -0
  26. package/src/services/s3/server.js +239 -0
  27. package/src/services/s3/simulator.js +740 -0
  28. package/src/services/sns/index.js +76 -0
  29. package/src/services/sqs/index.js +96 -0
  30. package/src/services/sqs/server.js +274 -0
  31. package/src/services/sqs/simulator.js +660 -0
  32. package/src/template/aws-config-template.js +88 -0
  33. package/src/template/aws-config-template.mjs +91 -0
  34. package/src/template/config-template.json +165 -0
  35. package/src/utils/aws-config.js +92 -0
  36. package/src/utils/local-store.js +68 -0
  37. package/src/utils/logger.js +60 -0
@@ -0,0 +1,435 @@
1
+ /**
2
+ * API Gateway Server - Servidor HTTP para API Gateway
3
+ */
4
+
5
+ const express = require('express');
6
+ const cors = require('cors');
7
+ const logger = require('../../utils/logger');
8
+
9
+ class APIGatewayServer {
10
+ constructor(port, config) {
11
+ this.port = port;
12
+ this.config = config;
13
+ this.app = express();
14
+ this.simulator = null;
15
+ this.server = null;
16
+ this.setupMiddlewares();
17
+ }
18
+
19
+ setupMiddlewares() {
20
+ this.app.use(express.json({ limit: '10mb' }));
21
+ this.app.use(express.urlencoded({ extended: true, limit: '10mb' }));
22
+ this.app.use(cors());
23
+
24
+ if (logger.currentLogLevel === 'verboso') {
25
+ this.app.use((req, res, next) => {
26
+ const start = Date.now();
27
+ res.on('finish', () => {
28
+ const duration = Date.now() - start;
29
+ logger.verboso(`API Gateway: ${req.method} ${req.path} - ${duration}ms`);
30
+ });
31
+ next();
32
+ });
33
+ }
34
+ }
35
+
36
+ async initialize() {
37
+ this.setupRoutes();
38
+ this.setupProxyRoutes();
39
+ logger.debug('API Gateway Server inicializado');
40
+ }
41
+
42
+ setupRoutes() {
43
+ // Health check
44
+ this.app.get('/health', (req, res) => {
45
+ res.json({
46
+ status: 'healthy',
47
+ service: 'apigateway-simulator',
48
+ version: '1.0.0'
49
+ });
50
+ });
51
+
52
+ // Control Plane - REST API
53
+ this.app.post('/restapis', async (req, res) => {
54
+ try {
55
+ const result = this.simulator.createRestApi(req.body);
56
+ res.json(result);
57
+ } catch (error) {
58
+ res.status(400).json({ error: error.message });
59
+ }
60
+ });
61
+
62
+ this.app.get('/restapis', (req, res) => {
63
+ const result = this.simulator.getRestApis();
64
+ res.json(result);
65
+ });
66
+
67
+ this.app.get('/restapis/:apiId', (req, res) => {
68
+ try {
69
+ const result = this.simulator.getRestApi({ restApiId: req.params.apiId });
70
+ res.json(result);
71
+ } catch (error) {
72
+ res.status(404).json({ error: error.message });
73
+ }
74
+ });
75
+
76
+ this.app.delete('/restapis/:apiId', (req, res) => {
77
+ try {
78
+ this.simulator.deleteRestApi({ restApiId: req.params.apiId });
79
+ res.json({});
80
+ } catch (error) {
81
+ res.status(404).json({ error: error.message });
82
+ }
83
+ });
84
+
85
+ // Resources
86
+ this.app.get('/restapis/:apiId/resources', (req, res) => {
87
+ try {
88
+ const result = this.simulator.getResources({ restApiId: req.params.apiId });
89
+ res.json(result);
90
+ } catch (error) {
91
+ res.status(404).json({ error: error.message });
92
+ }
93
+ });
94
+
95
+ this.app.post('/restapis/:apiId/resources', (req, res) => {
96
+ try {
97
+ const result = this.simulator.createResource({
98
+ ...req.body,
99
+ restApiId: req.params.apiId
100
+ });
101
+ res.json(result);
102
+ } catch (error) {
103
+ res.status(400).json({ error: error.message });
104
+ }
105
+ });
106
+
107
+ this.app.delete('/restapis/:apiId/resources/:resourceId', (req, res) => {
108
+ try {
109
+ this.simulator.deleteResource({
110
+ restApiId: req.params.apiId,
111
+ resourceId: req.params.resourceId
112
+ });
113
+ res.json({});
114
+ } catch (error) {
115
+ res.status(400).json({ error: error.message });
116
+ }
117
+ });
118
+
119
+ // Methods
120
+ this.app.put('/restapis/:apiId/resources/:resourceId/methods/:method', (req, res) => {
121
+ try {
122
+ const result = this.simulator.putMethod({
123
+ ...req.body,
124
+ restApiId: req.params.apiId,
125
+ resourceId: req.params.resourceId,
126
+ httpMethod: req.params.method
127
+ });
128
+ res.json(result);
129
+ } catch (error) {
130
+ res.status(400).json({ error: error.message });
131
+ }
132
+ });
133
+
134
+ this.app.get('/restapis/:apiId/resources/:resourceId/methods/:method', (req, res) => {
135
+ try {
136
+ const result = this.simulator.getMethod({
137
+ restApiId: req.params.apiId,
138
+ resourceId: req.params.resourceId,
139
+ httpMethod: req.params.method
140
+ });
141
+ res.json(result);
142
+ } catch (error) {
143
+ res.status(404).json({ error: error.message });
144
+ }
145
+ });
146
+
147
+ this.app.delete('/restapis/:apiId/resources/:resourceId/methods/:method', (req, res) => {
148
+ try {
149
+ this.simulator.deleteMethod({
150
+ restApiId: req.params.apiId,
151
+ resourceId: req.params.resourceId,
152
+ httpMethod: req.params.method
153
+ });
154
+ res.json({});
155
+ } catch (error) {
156
+ res.status(404).json({ error: error.message });
157
+ }
158
+ });
159
+
160
+ // Integrations
161
+ this.app.put('/restapis/:apiId/resources/:resourceId/methods/:method/integration', (req, res) => {
162
+ try {
163
+ const result = this.simulator.putIntegration({
164
+ ...req.body,
165
+ restApiId: req.params.apiId,
166
+ resourceId: req.params.resourceId,
167
+ httpMethod: req.params.method
168
+ });
169
+ res.json(result);
170
+ } catch (error) {
171
+ res.status(400).json({ error: error.message });
172
+ }
173
+ });
174
+
175
+ this.app.get('/restapis/:apiId/resources/:resourceId/methods/:method/integration', (req, res) => {
176
+ try {
177
+ const result = this.simulator.getIntegration({
178
+ restApiId: req.params.apiId,
179
+ resourceId: req.params.resourceId,
180
+ httpMethod: req.params.method
181
+ });
182
+ res.json(result);
183
+ } catch (error) {
184
+ res.status(404).json({ error: error.message });
185
+ }
186
+ });
187
+
188
+ this.app.delete('/restapis/:apiId/resources/:resourceId/methods/:method/integration', (req, res) => {
189
+ try {
190
+ this.simulator.deleteIntegration({
191
+ restApiId: req.params.apiId,
192
+ resourceId: req.params.resourceId,
193
+ httpMethod: req.params.method
194
+ });
195
+ res.json({});
196
+ } catch (error) {
197
+ res.status(404).json({ error: error.message });
198
+ }
199
+ });
200
+
201
+ // Deployments
202
+ this.app.post('/restapis/:apiId/deployments', (req, res) => {
203
+ try {
204
+ const result = this.simulator.createDeployment({
205
+ ...req.body,
206
+ restApiId: req.params.apiId
207
+ });
208
+ res.json(result);
209
+ } catch (error) {
210
+ res.status(400).json({ error: error.message });
211
+ }
212
+ });
213
+
214
+ // Stages
215
+ this.app.post('/restapis/:apiId/stages', (req, res) => {
216
+ try {
217
+ const result = this.simulator.createStage({
218
+ ...req.body,
219
+ restApiId: req.params.apiId
220
+ });
221
+ res.json(result);
222
+ } catch (error) {
223
+ res.status(400).json({ error: error.message });
224
+ }
225
+ });
226
+
227
+ this.app.get('/restapis/:apiId/stages/:stageName', (req, res) => {
228
+ try {
229
+ const result = this.simulator.getStage({
230
+ restApiId: req.params.apiId,
231
+ stageName: req.params.stageName
232
+ });
233
+ res.json(result);
234
+ } catch (error) {
235
+ res.status(404).json({ error: error.message });
236
+ }
237
+ });
238
+
239
+ this.app.patch('/restapis/:apiId/stages/:stageName', (req, res) => {
240
+ try {
241
+ const result = this.simulator.updateStage({
242
+ ...req.body,
243
+ restApiId: req.params.apiId,
244
+ stageName: req.params.stageName
245
+ });
246
+ res.json(result);
247
+ } catch (error) {
248
+ res.status(400).json({ error: error.message });
249
+ }
250
+ });
251
+
252
+ this.app.delete('/restapis/:apiId/stages/:stageName', (req, res) => {
253
+ try {
254
+ this.simulator.deleteStage({
255
+ restApiId: req.params.apiId,
256
+ stageName: req.params.stageName
257
+ });
258
+ res.json({});
259
+ } catch (error) {
260
+ res.status(404).json({ error: error.message });
261
+ }
262
+ });
263
+
264
+ // API Keys
265
+ this.app.post('/apikeys', (req, res) => {
266
+ try {
267
+ const result = this.simulator.createApiKey(req.body);
268
+ res.json(result);
269
+ } catch (error) {
270
+ res.status(400).json({ error: error.message });
271
+ }
272
+ });
273
+
274
+ this.app.get('/apikeys', (req, res) => {
275
+ const result = this.simulator.getApiKeys(req.query);
276
+ res.json(result);
277
+ });
278
+
279
+ // Usage Plans
280
+ this.app.post('/usageplans', (req, res) => {
281
+ try {
282
+ const result = this.simulator.createUsagePlan(req.body);
283
+ res.json(result);
284
+ } catch (error) {
285
+ res.status(400).json({ error: error.message });
286
+ }
287
+ });
288
+
289
+ // HTTP APIs
290
+ this.app.post('/httpapis', (req, res) => {
291
+ try {
292
+ const result = this.simulator.createHttpApi(req.body);
293
+ res.json(result);
294
+ } catch (error) {
295
+ res.status(400).json({ error: error.message });
296
+ }
297
+ });
298
+
299
+ this.app.post('/httpapis/:apiId/routes', (req, res) => {
300
+ try {
301
+ const result = this.simulator.createRoute({
302
+ ...req.body,
303
+ apiId: req.params.apiId
304
+ });
305
+ res.json(result);
306
+ } catch (error) {
307
+ res.status(400).json({ error: error.message });
308
+ }
309
+ });
310
+
311
+ // Admin endpoints
312
+ this.setupAdminRoutes();
313
+ }
314
+
315
+ setupProxyRoutes() {
316
+ // Proxy para execução das APIs
317
+ this.app.all('/:apiId/:stageName/*', async (req, res) => {
318
+ const apiId = req.params.apiId;
319
+ const stageName = req.params.stageName;
320
+ const path = '/' + (req.params[0] || '');
321
+
322
+ logger.debug(`🌐 Executando: ${req.method} ${path} (${apiId}/${stageName})`);
323
+
324
+ try {
325
+ const result = await this.simulator.executeRequest(
326
+ apiId,
327
+ stageName,
328
+ req.method,
329
+ path,
330
+ req.headers,
331
+ req.body,
332
+ req.query
333
+ );
334
+
335
+ res.status(result.statusCode);
336
+
337
+ if (result.headers) {
338
+ Object.entries(result.headers).forEach(([key, value]) => {
339
+ res.set(key, value);
340
+ });
341
+ }
342
+
343
+ res.send(result.body);
344
+ } catch (error) {
345
+ logger.error('Error executing request:', error);
346
+ res.status(500).json({ error: error.message });
347
+ }
348
+ });
349
+ }
350
+
351
+ setupAdminRoutes() {
352
+ this.app.get('/__admin/apis', (req, res) => {
353
+ res.json({
354
+ totalApis: this.simulator.getAPIsCount(),
355
+ totalDeployments: this.simulator.getDeploymentsCount(),
356
+ totalStages: this.simulator.getStagesCount(),
357
+ totalResources: this.simulator.getResourcesCount()
358
+ });
359
+ });
360
+
361
+ this.app.get('/__admin/apis/:apiId', (req, res) => {
362
+ const api = this.simulator.apis.get(req.params.apiId);
363
+ if (api) {
364
+ res.json({
365
+ id: api.id,
366
+ name: api.name,
367
+ resources: Array.from(api.resources.keys()),
368
+ stages: Array.from(api.stages.keys()),
369
+ deployments: Array.from(api.deployments.keys())
370
+ });
371
+ } else {
372
+ res.status(404).json({ error: 'API not found' });
373
+ }
374
+ });
375
+
376
+ this.app.get('/__admin/apikeys', (req, res) => {
377
+ const keys = Array.from(this.simulator.apiKeys.values()).map(k => ({
378
+ id: k.id,
379
+ name: k.name,
380
+ enabled: k.enabled,
381
+ createdDate: k.createdDate
382
+ }));
383
+ res.json(keys);
384
+ });
385
+
386
+ this.app.get('/__admin/usageplans', (req, res) => {
387
+ const plans = Array.from(this.simulator.usagePlans.values());
388
+ res.json(plans);
389
+ });
390
+ }
391
+
392
+ start() {
393
+ return new Promise((resolve) => {
394
+ this.server = this.app.listen(this.port, () => {
395
+ logger.info(`🌐 API Gateway rodando em http://localhost:${this.port}`);
396
+ this.printInfo();
397
+ resolve();
398
+ });
399
+ });
400
+ }
401
+
402
+ printInfo() {
403
+ logger.info('\n📡 API Gateway Endpoints:');
404
+ logger.info(` Control Plane: http://localhost:${this.port}/restapis`);
405
+ logger.info(` Execute APIs: http://localhost:${this.port}/{apiId}/{stageName}/{path}`);
406
+ logger.info('\n📚 Admin Endpoints:');
407
+ logger.info(` GET http://localhost:${this.port}/__admin/apis`);
408
+ logger.info(` GET http://localhost:${this.port}/__admin/apikeys`);
409
+ logger.info(` GET http://localhost:${this.port}/__admin/usageplans`);
410
+ }
411
+
412
+ stop() {
413
+ return new Promise((resolve) => {
414
+ if (this.server) {
415
+ this.server.close(() => resolve());
416
+ } else {
417
+ resolve();
418
+ }
419
+ });
420
+ }
421
+
422
+ getStatus() {
423
+ return {
424
+ running: !!this.server,
425
+ port: this.port,
426
+ endpoint: `http://localhost:${this.port}`,
427
+ apisCount: this.simulator?.getAPIsCount() || 0,
428
+ deploymentsCount: this.simulator?.getDeploymentsCount() || 0,
429
+ stagesCount: this.simulator?.getStagesCount() || 0,
430
+ resourcesCount: this.simulator?.getResourcesCount() || 0
431
+ };
432
+ }
433
+ }
434
+
435
+ module.exports = APIGatewayServer;