@gugananuvem/aws-local-simulator 1.0.8 → 1.0.10

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 (41) hide show
  1. package/README.md +2 -1
  2. package/bin/aws-local-simulator.js +62 -1
  3. package/package.json +10 -7
  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 +69 -0
  7. package/src/index.js +131 -1
  8. package/src/index.mjs +124 -0
  9. package/src/server.js +222 -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/ecs/index.js +66 -0
  20. package/src/services/ecs/server.js +234 -0
  21. package/src/services/ecs/simulator.js +845 -0
  22. package/src/services/eventbridge/index.js +85 -0
  23. package/src/services/index.js +19 -0
  24. package/src/services/lambda/handler-loader.js +173 -0
  25. package/src/services/lambda/index.js +73 -0
  26. package/src/services/lambda/route-registry.js +275 -0
  27. package/src/services/lambda/server.js +153 -0
  28. package/src/services/lambda/simulator.js +285 -0
  29. package/src/services/s3/index.js +70 -0
  30. package/src/services/s3/server.js +239 -0
  31. package/src/services/s3/simulator.js +740 -0
  32. package/src/services/sns/index.js +76 -0
  33. package/src/services/sqs/index.js +96 -0
  34. package/src/services/sqs/server.js +274 -0
  35. package/src/services/sqs/simulator.js +660 -0
  36. package/src/template/aws-config-template.js +88 -0
  37. package/src/template/aws-config-template.mjs +91 -0
  38. package/src/template/config-template.json +203 -0
  39. package/src/utils/aws-config.js +92 -0
  40. package/src/utils/local-store.js +68 -0
  41. package/src/utils/logger.js +60 -0
@@ -0,0 +1,239 @@
1
+ /**
2
+ * S3 Server - Servidor HTTP para S3
3
+ */
4
+
5
+ const express = require('express');
6
+ const S3Simulator = require('./simulator');
7
+ const logger = require('../../utils/logger');
8
+
9
+ class S3Server {
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: '100mb' }));
21
+ this.app.use(express.raw({ type: 'application/octet-stream', limit: '100mb' }));
22
+ this.app.use(express.text({ limit: '100mb' }));
23
+
24
+ // Logging de requisições
25
+ if (logger.currentLogLevel === 'verboso') {
26
+ this.app.use((req, res, next) => {
27
+ const start = Date.now();
28
+ res.on('finish', () => {
29
+ const duration = Date.now() - start;
30
+ logger.verboso(`S3: ${req.method} ${req.path} - ${duration}ms`);
31
+ });
32
+ next();
33
+ });
34
+ }
35
+ }
36
+
37
+ async initialize() {
38
+ this.simulator = new S3Simulator(this.config);
39
+ await this.simulator.initialize();
40
+ this.setupRoutes();
41
+ }
42
+
43
+ setupRoutes() {
44
+ // Listar buckets
45
+ this.app.get('/', (req, res) => {
46
+ const buckets = this.simulator.listBuckets();
47
+ res.set('Content-Type', 'application/xml');
48
+ res.send(this.simulator.generateListBucketsResponse(buckets));
49
+ });
50
+
51
+ // Criar bucket
52
+ this.app.put('/:bucket', (req, res) => {
53
+ const result = this.simulator.createBucket(req.params.bucket);
54
+ if (result.error) {
55
+ res.status(result.status).send(this.simulator.generateErrorResponse(result.error.code, result.error.message));
56
+ } else {
57
+ res.status(200).send();
58
+ }
59
+ });
60
+
61
+ // Deletar bucket
62
+ this.app.delete('/:bucket', (req, res) => {
63
+ const result = this.simulator.deleteBucket(req.params.bucket);
64
+ if (result.error) {
65
+ res.status(result.status).send(this.simulator.generateErrorResponse(result.error.code, result.error.message));
66
+ } else {
67
+ res.status(204).send();
68
+ }
69
+ });
70
+
71
+ // Head bucket
72
+ this.app.head('/:bucket', (req, res) => {
73
+ const bucket = this.simulator.getBucket(req.params.bucket);
74
+ if (!bucket) {
75
+ res.status(404).send();
76
+ } else {
77
+ res.status(200).send();
78
+ }
79
+ });
80
+
81
+ // Upload object
82
+ this.app.put('/:bucket/*', (req, res) => {
83
+ const bucket = req.params.bucket;
84
+ const key = req.params[0];
85
+ const result = this.simulator.putObject(bucket, key, req.body, req.headers);
86
+
87
+ if (result.error) {
88
+ res.status(result.status).send(this.simulator.generateErrorResponse(result.error.code, result.error.message));
89
+ } else {
90
+ res.set('ETag', `"${result.etag}"`);
91
+ res.status(200).send();
92
+ }
93
+ });
94
+
95
+ // Get object
96
+ this.app.get('/:bucket/*', (req, res) => {
97
+ const bucket = req.params.bucket;
98
+ const key = req.params[0];
99
+ const result = this.simulator.getObject(bucket, key, req.headers);
100
+
101
+ if (result.error) {
102
+ res.status(result.status).send(this.simulator.generateErrorResponse(result.error.code, result.error.message));
103
+ } else {
104
+ res.set('ETag', `"${result.etag}"`);
105
+ res.set('Last-Modified', result.lastModified);
106
+ res.set('Content-Type', result.contentType);
107
+ res.set('Content-Length', result.size);
108
+
109
+ if (result.metadata) {
110
+ Object.entries(result.metadata).forEach(([k, v]) => {
111
+ res.set(`x-amz-meta-${k}`, v);
112
+ });
113
+ }
114
+
115
+ res.send(result.content);
116
+ }
117
+ });
118
+
119
+ // Head object
120
+ this.app.head('/:bucket/*', (req, res) => {
121
+ const bucket = req.params.bucket;
122
+ const key = req.params[0];
123
+ const result = this.simulator.headObject(bucket, key);
124
+
125
+ if (result.error) {
126
+ res.status(result.status).send();
127
+ } else {
128
+ res.set('ETag', `"${result.etag}"`);
129
+ res.set('Last-Modified', result.lastModified);
130
+ res.set('Content-Type', result.contentType);
131
+ res.set('Content-Length', result.size);
132
+ res.status(200).send();
133
+ }
134
+ });
135
+
136
+ // Delete object
137
+ this.app.delete('/:bucket/*', (req, res) => {
138
+ const bucket = req.params.bucket;
139
+ const key = req.params[0];
140
+ const result = this.simulator.deleteObject(bucket, key);
141
+
142
+ if (result.error) {
143
+ res.status(result.status).send(this.simulator.generateErrorResponse(result.error.code, result.error.message));
144
+ } else {
145
+ res.status(204).send();
146
+ }
147
+ });
148
+
149
+ // List objects
150
+ this.app.get('/:bucket', (req, res) => {
151
+ const bucket = req.params.bucket;
152
+ const prefix = req.query.prefix || '';
153
+ const delimiter = req.query.delimiter;
154
+ const maxKeys = parseInt(req.query['max-keys']) || 1000;
155
+ const listType = req.query['list-type'];
156
+
157
+ const result = this.simulator.listObjects(bucket, { prefix, delimiter, maxKeys });
158
+
159
+ if (result.error) {
160
+ res.status(result.status).send(this.simulator.generateErrorResponse(result.error.code, result.error.message));
161
+ } else {
162
+ res.set('Content-Type', 'application/xml');
163
+ if (listType === '2') {
164
+ res.send(this.simulator.generateListObjectsV2Response(result));
165
+ } else {
166
+ res.send(this.simulator.generateListObjectsResponse(result));
167
+ }
168
+ }
169
+ });
170
+
171
+ // Admin endpoints
172
+ this.setupAdminRoutes();
173
+ }
174
+
175
+ setupAdminRoutes() {
176
+ this.app.get('/__admin/buckets', (req, res) => {
177
+ res.json(this.simulator.getBucketsInfo());
178
+ });
179
+
180
+ this.app.get('/__admin/buckets/:bucket', (req, res) => {
181
+ const info = this.simulator.getBucketInfo(req.params.bucket);
182
+ if (info.error) {
183
+ res.status(404).json(info.error);
184
+ } else {
185
+ res.json(info);
186
+ }
187
+ });
188
+
189
+ this.app.get('/__admin/buckets/:bucket/objects', (req, res) => {
190
+ const objects = this.simulator.listAllObjects(req.params.bucket);
191
+ res.json(objects);
192
+ });
193
+
194
+ this.app.delete('/__admin/buckets/:bucket', (req, res) => {
195
+ this.simulator.clearBucket(req.params.bucket);
196
+ res.json({ message: `Bucket ${req.params.bucket} cleared` });
197
+ });
198
+
199
+ this.app.delete('/__admin/buckets/:bucket/objects/:key', (req, res) => {
200
+ this.simulator.deleteObject(req.params.bucket, req.params.key);
201
+ res.json({ message: 'Object deleted' });
202
+ });
203
+
204
+ this.app.get('/__admin/stats', (req, res) => {
205
+ res.json(this.simulator.getStats());
206
+ });
207
+ }
208
+
209
+ start() {
210
+ return new Promise((resolve) => {
211
+ this.server = this.app.listen(this.port, () => {
212
+ logger.info(`🗄️ S3 rodando em http://localhost:${this.port}`);
213
+ resolve();
214
+ });
215
+ });
216
+ }
217
+
218
+ stop() {
219
+ return new Promise((resolve) => {
220
+ if (this.server) {
221
+ this.server.close(() => resolve());
222
+ } else {
223
+ resolve();
224
+ }
225
+ });
226
+ }
227
+
228
+ getStatus() {
229
+ return {
230
+ running: !!this.server,
231
+ port: this.port,
232
+ endpoint: `http://localhost:${this.port}`,
233
+ bucketsCount: this.simulator?.getBucketsCount() || 0,
234
+ objectsCount: this.simulator?.getTotalObjectsCount() || 0
235
+ };
236
+ }
237
+ }
238
+
239
+ module.exports = S3Server;