@gugananuvem/aws-local-simulator 1.0.0 → 1.0.1

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 (38) hide show
  1. package/README.md +192 -192
  2. package/bin/aws-local-simulator.js +62 -62
  3. package/package.json +8 -5
  4. package/src/config/config-loader.js +113 -0
  5. package/src/config/default-config.js +65 -0
  6. package/src/config/env-loader.js +67 -0
  7. package/src/index.js +130 -130
  8. package/src/index.mjs +124 -0
  9. package/src/server.js +219 -0
  10. package/src/services/apigateway/index.js +67 -0
  11. package/src/services/apigateway/server.js +435 -0
  12. package/src/services/apigateway/simulator.js +1252 -0
  13. package/src/services/cognito/index.js +66 -0
  14. package/src/services/cognito/server.js +229 -0
  15. package/src/services/cognito/simulator.js +848 -0
  16. package/src/services/dynamodb/index.js +71 -0
  17. package/src/services/dynamodb/server.js +122 -0
  18. package/src/services/dynamodb/simulator.js +614 -0
  19. package/src/services/eventbridge/index.js +85 -0
  20. package/src/services/index.js +19 -0
  21. package/src/services/lambda/handler-loader.js +173 -0
  22. package/src/services/lambda/index.js +73 -0
  23. package/src/services/lambda/route-registry.js +275 -0
  24. package/src/services/lambda/server.js +153 -0
  25. package/src/services/lambda/simulator.js +278 -0
  26. package/src/services/s3/index.js +70 -0
  27. package/src/services/s3/server.js +239 -0
  28. package/src/services/s3/simulator.js +740 -0
  29. package/src/services/sns/index.js +76 -0
  30. package/src/services/sqs/index.js +96 -0
  31. package/src/services/sqs/server.js +274 -0
  32. package/src/services/sqs/simulator.js +660 -0
  33. package/src/template/aws-config-template.js +88 -0
  34. package/src/template/aws-config-template.mjs +91 -0
  35. package/src/template/config-template.json +165 -0
  36. package/src/utils/aws-config.js +92 -0
  37. package/src/utils/local-store.js +68 -0
  38. 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;