@gugananuvem/aws-local-simulator 1.0.11 → 1.0.12
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.
- package/README.md +122 -69
- package/package.json +2 -2
- package/src/config/config-loader.js +2 -0
- package/src/config/default-config.js +2 -0
- package/src/server.js +3 -1
- package/src/services/apigateway/index.js +5 -3
- package/src/services/apigateway/server.js +53 -0
- package/src/services/cognito/server.js +54 -3
- package/src/services/cognito/simulator.js +269 -2
- package/src/services/lambda/handler-loader.js +13 -2
- package/src/services/lambda/index.js +2 -1
- package/src/services/lambda/server.js +32 -39
- package/src/services/lambda/simulator.js +44 -157
- package/src/services/sqs/server.js +88 -16
- package/src/services/sqs/simulator.js +79 -298
- package/src/services/sts/index.js +37 -0
- package/src/services/sts/server.js +142 -0
- package/src/services/sts/simulator.js +69 -0
|
@@ -3,42 +3,40 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const HandlerLoader = require('./handler-loader');
|
|
6
|
-
const RouteRegistry = require('./route-registry');
|
|
7
6
|
const logger = require('../../utils/logger');
|
|
8
7
|
|
|
9
8
|
class LambdaSimulator {
|
|
10
9
|
constructor(config) {
|
|
11
10
|
this.config = config;
|
|
12
|
-
this.
|
|
13
|
-
this.lambdas = new Map();
|
|
11
|
+
this.lambdas = new Map(); // functionName -> { handler, env, config }
|
|
14
12
|
this.environment = { ...process.env };
|
|
15
13
|
}
|
|
16
14
|
|
|
17
15
|
async initialize() {
|
|
18
16
|
logger.debug('Inicializando Lambda Simulator...');
|
|
19
|
-
|
|
17
|
+
|
|
20
18
|
if (this.config.lambdas && this.config.lambdas.length > 0) {
|
|
21
19
|
for (const lambdaConfig of this.config.lambdas) {
|
|
22
20
|
await this.registerLambda(lambdaConfig);
|
|
23
21
|
}
|
|
24
22
|
}
|
|
25
|
-
|
|
23
|
+
|
|
26
24
|
logger.debug(`✅ ${this.lambdas.size} Lambdas registradas`);
|
|
27
25
|
}
|
|
28
26
|
|
|
29
27
|
async registerLambda(lambdaConfig) {
|
|
30
28
|
try {
|
|
31
|
-
const {
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
const { name, handler: handlerPath, env = {}, type = 'auto' } = lambdaConfig;
|
|
30
|
+
|
|
31
|
+
if (!name) {
|
|
32
|
+
logger.warn(`Lambda sem nome ignorada: ${JSON.stringify(lambdaConfig)}`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
34
36
|
const handler = await HandlerLoader.load(handlerPath, type);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
// Armazena metadata
|
|
40
|
-
this.lambdas.set(path, {
|
|
41
|
-
path,
|
|
37
|
+
|
|
38
|
+
this.lambdas.set(name, {
|
|
39
|
+
name,
|
|
42
40
|
handler,
|
|
43
41
|
handlerPath,
|
|
44
42
|
handlerName: handler.name || 'anonymous',
|
|
@@ -46,84 +44,33 @@ class LambdaSimulator {
|
|
|
46
44
|
type,
|
|
47
45
|
registeredAt: new Date().toISOString()
|
|
48
46
|
});
|
|
49
|
-
|
|
50
|
-
logger.debug(`✅ Lambda registrada: ${
|
|
51
|
-
|
|
47
|
+
|
|
48
|
+
logger.debug(`✅ Lambda registrada: ${name} -> ${handlerPath}`);
|
|
52
49
|
} catch (error) {
|
|
53
|
-
logger.error(`❌ Erro ao registrar Lambda ${lambdaConfig.
|
|
50
|
+
logger.error(`❌ Erro ao registrar Lambda ${lambdaConfig.name}:`, error);
|
|
54
51
|
throw error;
|
|
55
52
|
}
|
|
56
53
|
}
|
|
57
54
|
|
|
58
|
-
async
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
if (!
|
|
62
|
-
|
|
63
|
-
error: {
|
|
64
|
-
statusCode: 404,
|
|
65
|
-
message: `Route not found: ${req.path}`,
|
|
66
|
-
availableRoutes: this.listRoutes()
|
|
67
|
-
},
|
|
68
|
-
status: 404
|
|
69
|
-
};
|
|
55
|
+
async invoke(functionName, event, invocationType = 'RequestResponse') {
|
|
56
|
+
const lambda = this.lambdas.get(functionName);
|
|
57
|
+
|
|
58
|
+
if (!lambda) {
|
|
59
|
+
throw new Error(`Function not found: ${functionName}`);
|
|
70
60
|
}
|
|
71
|
-
|
|
72
|
-
// Aplica variáveis de ambiente específicas da rota
|
|
73
|
-
this.applyEnvironment(matchedRoute.env);
|
|
74
|
-
|
|
75
|
-
// Prepara evento Lambda
|
|
76
|
-
const event = this.toLambdaEvent(req, matchedRoute.params);
|
|
77
|
-
|
|
78
|
-
logger.debug(`🎯 Executando: ${matchedRoute.path} -> ${matchedRoute.handler.name || 'anonymous'}`);
|
|
79
|
-
|
|
80
|
-
// Executa middlewares
|
|
81
|
-
const middlewares = this.routeRegistry.getMiddlewares(matchedRoute);
|
|
82
|
-
let handled = false;
|
|
83
|
-
let result = null;
|
|
84
|
-
|
|
85
|
-
const runMiddlewares = async (index) => {
|
|
86
|
-
if (index >= middlewares.length) {
|
|
87
|
-
// Executa handler
|
|
88
61
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const middleware = middlewares[index];
|
|
101
|
-
await new Promise((resolve, reject) => {
|
|
102
|
-
middleware(event, {
|
|
103
|
-
status: (code) => ({ json: (data) => {
|
|
104
|
-
result = { statusCode: code, body: data };
|
|
105
|
-
handled = true;
|
|
106
|
-
resolve();
|
|
107
|
-
}}),
|
|
108
|
-
send: (data) => {
|
|
109
|
-
result = { statusCode: 200, body: data };
|
|
110
|
-
handled = true;
|
|
111
|
-
resolve();
|
|
112
|
-
},
|
|
113
|
-
next: () => {
|
|
114
|
-
runMiddlewares(index + 1).then(resolve).catch(reject);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
});
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
await runMiddlewares(0);
|
|
121
|
-
|
|
122
|
-
if (!handled && result) {
|
|
123
|
-
return this.formatResponse(result);
|
|
62
|
+
this.applyEnvironment(lambda.env);
|
|
63
|
+
logger.debug(`🎯 Invocando Lambda: ${functionName}`);
|
|
64
|
+
|
|
65
|
+
if (invocationType === 'Event') {
|
|
66
|
+
this.executeHandler(lambda.handler, event).catch(err =>
|
|
67
|
+
logger.error(`❌ Async Lambda error (${functionName}):`, err)
|
|
68
|
+
);
|
|
69
|
+
return { StatusCode: 202 };
|
|
124
70
|
}
|
|
125
71
|
|
|
126
|
-
|
|
72
|
+
const result = await this.executeHandler(lambda.handler, event);
|
|
73
|
+
return { StatusCode: result.statusCode || 200, Payload: result };
|
|
127
74
|
}
|
|
128
75
|
|
|
129
76
|
async executeHandler(handler, event) {
|
|
@@ -135,57 +82,17 @@ class LambdaSimulator {
|
|
|
135
82
|
logger.error('❌ Erro no handler:', error);
|
|
136
83
|
return {
|
|
137
84
|
statusCode: 500,
|
|
138
|
-
body: {
|
|
139
|
-
error: 'Internal Server Error',
|
|
140
|
-
message: error.message,
|
|
141
|
-
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
|
|
142
|
-
}
|
|
85
|
+
body: JSON.stringify({ error: 'Internal Server Error', message: error.message })
|
|
143
86
|
};
|
|
144
87
|
}
|
|
145
88
|
}
|
|
146
89
|
|
|
147
|
-
toLambdaEvent(req, params = {}) {
|
|
148
|
-
return {
|
|
149
|
-
httpMethod: req.method,
|
|
150
|
-
path: req.path,
|
|
151
|
-
headers: req.headers,
|
|
152
|
-
queryStringParameters: req.query,
|
|
153
|
-
pathParameters: params,
|
|
154
|
-
body: req.body ? (typeof req.body === 'string' ? req.body : JSON.stringify(req.body)) : null,
|
|
155
|
-
isBase64Encoded: false,
|
|
156
|
-
requestContext: {
|
|
157
|
-
path: req.path,
|
|
158
|
-
stage: process.env.STAGE_NAME || 'dev',
|
|
159
|
-
requestId: Math.random().toString(36).substring(7),
|
|
160
|
-
identity: {
|
|
161
|
-
sourceIp: req.ip,
|
|
162
|
-
userAgent: req.headers['user-agent']
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
stageVariables: {},
|
|
166
|
-
resource: req.path
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
formatResponse(result) {
|
|
171
|
-
const statusCode = result.statusCode || 200;
|
|
172
|
-
const body = result.body;
|
|
173
|
-
const headers = result.headers || { 'Content-Type': 'application/json' };
|
|
174
|
-
|
|
175
|
-
return {
|
|
176
|
-
statusCode,
|
|
177
|
-
headers,
|
|
178
|
-
body: typeof body === 'string' ? body : JSON.stringify(body),
|
|
179
|
-
isBase64Encoded: false
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
90
|
createContext() {
|
|
184
91
|
return {
|
|
185
92
|
awsRequestId: Math.random().toString(36).substring(7),
|
|
186
93
|
functionName: 'local-lambda',
|
|
187
94
|
functionVersion: '$LATEST',
|
|
188
|
-
invokedFunctionArn: 'arn:aws:lambda:local:function',
|
|
95
|
+
invokedFunctionArn: 'arn:aws:lambda:local:000000000000:function:local-lambda',
|
|
189
96
|
memoryLimitInMB: '1024',
|
|
190
97
|
logGroupName: '/aws/lambda/local-lambda',
|
|
191
98
|
logStreamName: 'local-stream',
|
|
@@ -214,7 +121,7 @@ class LambdaSimulator {
|
|
|
214
121
|
|
|
215
122
|
listLambdas() {
|
|
216
123
|
return Array.from(this.lambdas.values()).map(l => ({
|
|
217
|
-
|
|
124
|
+
name: l.name,
|
|
218
125
|
handlerName: l.handlerName,
|
|
219
126
|
handlerPath: l.handlerPath,
|
|
220
127
|
type: l.type,
|
|
@@ -223,12 +130,8 @@ class LambdaSimulator {
|
|
|
223
130
|
}));
|
|
224
131
|
}
|
|
225
132
|
|
|
226
|
-
getLambda(
|
|
227
|
-
return this.lambdas.get(
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
listRoutes() {
|
|
231
|
-
return this.routeRegistry.list();
|
|
133
|
+
getLambda(name) {
|
|
134
|
+
return this.lambdas.get(name);
|
|
232
135
|
}
|
|
233
136
|
|
|
234
137
|
getLambdasCount() {
|
|
@@ -237,49 +140,33 @@ class LambdaSimulator {
|
|
|
237
140
|
|
|
238
141
|
async reloadLambdas() {
|
|
239
142
|
logger.info('🔄 Recarregando Lambdas...');
|
|
240
|
-
|
|
241
|
-
for (const [
|
|
143
|
+
|
|
144
|
+
for (const [name, lambda] of this.lambdas.entries()) {
|
|
242
145
|
try {
|
|
243
146
|
const newHandler = await HandlerLoader.reload(lambda.handlerPath, lambda.type);
|
|
244
|
-
this.routeRegistry.register(path, newHandler, lambda.env);
|
|
245
147
|
lambda.handler = newHandler;
|
|
246
148
|
lambda.handlerName = newHandler.name || 'anonymous';
|
|
247
|
-
logger.debug(`✅ Lambda recarregada: ${
|
|
149
|
+
logger.debug(`✅ Lambda recarregada: ${name}`);
|
|
248
150
|
} catch (error) {
|
|
249
|
-
logger.error(`❌ Erro ao recarregar Lambda ${
|
|
151
|
+
logger.error(`❌ Erro ao recarregar Lambda ${name}:`, error);
|
|
250
152
|
}
|
|
251
153
|
}
|
|
252
|
-
|
|
154
|
+
|
|
253
155
|
logger.info(`✅ ${this.lambdas.size} Lambdas recarregadas`);
|
|
254
156
|
}
|
|
255
157
|
|
|
256
158
|
getStats() {
|
|
257
|
-
const lambdas = this.listLambdas();
|
|
258
159
|
return {
|
|
259
|
-
totalLambdas: lambdas.
|
|
260
|
-
lambdas:
|
|
261
|
-
path: l.path,
|
|
262
|
-
handler: l.handlerName
|
|
263
|
-
})),
|
|
264
|
-
routes: this.routeRegistry.getStats(),
|
|
265
|
-
environment: Object.keys(this.environment).length
|
|
160
|
+
totalLambdas: this.lambdas.size,
|
|
161
|
+
lambdas: this.listLambdas().map(l => ({ name: l.name, handler: l.handlerName }))
|
|
266
162
|
};
|
|
267
163
|
}
|
|
268
164
|
|
|
269
165
|
async reset() {
|
|
270
|
-
// Recarrega Lambdas
|
|
271
166
|
await this.reloadLambdas();
|
|
272
|
-
|
|
273
|
-
// Limpa variáveis de ambiente customizadas
|
|
274
|
-
for (const key of Object.keys(this.environment)) {
|
|
275
|
-
if (!process.env.hasOwnProperty(key) || key.startsWith('AWS_LOCAL_SIMULATOR_')) {
|
|
276
|
-
delete process.env[key];
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
167
|
this.environment = { ...process.env };
|
|
281
168
|
logger.debug('Lambda: Estado resetado');
|
|
282
169
|
}
|
|
283
170
|
}
|
|
284
171
|
|
|
285
|
-
module.exports = LambdaSimulator;
|
|
172
|
+
module.exports = LambdaSimulator;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const express = require('express');
|
|
6
|
+
const crypto = require('crypto');
|
|
6
7
|
const SQSSimulator = require('./simulator');
|
|
7
8
|
const logger = require('../../utils/logger');
|
|
8
9
|
|
|
@@ -18,8 +19,23 @@ class SQSServer {
|
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
setupMiddlewares() {
|
|
21
|
-
this.app.use(express.
|
|
22
|
-
this.app.use(
|
|
22
|
+
this.app.use(express.raw({ type: '*/*', limit: '10mb' }));
|
|
23
|
+
this.app.use((req, res, next) => {
|
|
24
|
+
if (req.body && Buffer.isBuffer(req.body)) {
|
|
25
|
+
const str = req.body.toString('utf8');
|
|
26
|
+
const contentType = req.headers['content-type'] || '';
|
|
27
|
+
if (contentType.includes('application/x-amz-json-1.0') || contentType.includes('application/json')) {
|
|
28
|
+
try { req.body = JSON.parse(str); } catch (e) { req.body = {}; }
|
|
29
|
+
} else if (contentType.includes('application/x-www-form-urlencoded')) {
|
|
30
|
+
req.body = Object.fromEntries(new URLSearchParams(str));
|
|
31
|
+
} else {
|
|
32
|
+
try { req.body = JSON.parse(str); } catch (e) { req.body = {}; }
|
|
33
|
+
}
|
|
34
|
+
} else if (!req.body) {
|
|
35
|
+
req.body = {};
|
|
36
|
+
}
|
|
37
|
+
next();
|
|
38
|
+
});
|
|
23
39
|
|
|
24
40
|
// Logging de requisições
|
|
25
41
|
if (logger.currentLogLevel === 'verboso') {
|
|
@@ -42,16 +58,35 @@ class SQSServer {
|
|
|
42
58
|
|
|
43
59
|
setupRoutes() {
|
|
44
60
|
// Endpoint principal
|
|
61
|
+
this.app.use((req, res, next) => {
|
|
62
|
+
logger.info(`SQS incoming: ${req.method} ${req.path} headers=${JSON.stringify(req.headers)} query=${JSON.stringify(req.query)} body=${JSON.stringify(req.body)}`);
|
|
63
|
+
next();
|
|
64
|
+
});
|
|
65
|
+
|
|
45
66
|
this.app.post('/', (req, res) => {
|
|
46
|
-
const action = req.query.Action || req.body.Action
|
|
67
|
+
const action = req.query.Action || req.body.Action ||
|
|
68
|
+
(req.headers['x-amz-target'] && req.headers['x-amz-target'].split('.')[1]);
|
|
69
|
+
logger.info(`SQS action resolved: ${action}`);
|
|
47
70
|
const result = this.simulator.handleRequest(action, req, res);
|
|
48
|
-
|
|
71
|
+
const isJsonProtocol = req.headers['content-type'] && req.headers['content-type'].includes('application/x-amz-json-1.0');
|
|
72
|
+
|
|
49
73
|
if (result && result.error) {
|
|
50
|
-
|
|
74
|
+
const isJsonProtocol = req.headers['content-type'] && req.headers['content-type'].includes('application/x-amz-json-1.0');
|
|
75
|
+
if (isJsonProtocol) {
|
|
76
|
+
res.status(result.status).json({ __type: result.error.code, message: result.error.message });
|
|
77
|
+
} else {
|
|
78
|
+
res.status(result.status).send(this.simulator.generateErrorResponse(result.error.code, result.error.message));
|
|
79
|
+
}
|
|
51
80
|
} else if (result) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
81
|
+
if (isJsonProtocol) {
|
|
82
|
+
res.set('Content-Type', 'application/x-amz-json-1.0');
|
|
83
|
+
res.json(this.generateJsonResponse(action, result));
|
|
84
|
+
} else {
|
|
85
|
+
const xml = this.generateResponse(action, result);
|
|
86
|
+
logger.info(`SQS response for ${action}: ${xml}`);
|
|
87
|
+
res.set('Content-Type', 'application/xml');
|
|
88
|
+
res.send(xml);
|
|
89
|
+
}
|
|
55
90
|
}
|
|
56
91
|
});
|
|
57
92
|
|
|
@@ -105,6 +140,37 @@ class SQSServer {
|
|
|
105
140
|
});
|
|
106
141
|
}
|
|
107
142
|
|
|
143
|
+
generateJsonResponse(action, result) {
|
|
144
|
+
switch (action) {
|
|
145
|
+
case 'CreateQueue':
|
|
146
|
+
return { QueueUrl: result.queueUrl };
|
|
147
|
+
case 'SendMessage':
|
|
148
|
+
return { MD5OfMessageBody: result.md5, MessageId: result.messageId };
|
|
149
|
+
case 'SendMessageBatch':
|
|
150
|
+
return {
|
|
151
|
+
Successful: (result.successful || []).map(s => ({ Id: s.Id, MessageId: s.MessageId, MD5OfMessageBody: s.MD5OfMessageBody })),
|
|
152
|
+
Failed: result.failed || []
|
|
153
|
+
};
|
|
154
|
+
case 'ReceiveMessage':
|
|
155
|
+
return {
|
|
156
|
+
Messages: (result.messages || []).map(m => ({
|
|
157
|
+
MessageId: m.MessageId,
|
|
158
|
+
ReceiptHandle: m.ReceiptHandle,
|
|
159
|
+
MD5OfBody: m.MD5OfBody,
|
|
160
|
+
Body: m.Body
|
|
161
|
+
}))
|
|
162
|
+
};
|
|
163
|
+
case 'DeleteMessage':
|
|
164
|
+
return {};
|
|
165
|
+
case 'GetQueueUrl':
|
|
166
|
+
return { QueueUrl: result.queueUrl };
|
|
167
|
+
case 'ListQueues':
|
|
168
|
+
return { QueueUrls: (result.queues || []).map(q => q.url) };
|
|
169
|
+
default:
|
|
170
|
+
return result;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
108
174
|
generateResponse(action, result) {
|
|
109
175
|
switch(action) {
|
|
110
176
|
case 'CreateQueue':
|
|
@@ -128,26 +194,28 @@ class SQSServer {
|
|
|
128
194
|
|
|
129
195
|
generateCreateQueueResponse(queueUrl) {
|
|
130
196
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
131
|
-
<CreateQueueResponse>
|
|
197
|
+
<CreateQueueResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
|
132
198
|
<CreateQueueResult>
|
|
133
199
|
<QueueUrl>${queueUrl}</QueueUrl>
|
|
134
200
|
</CreateQueueResult>
|
|
201
|
+
<ResponseMetadata><RequestId>${crypto.randomUUID()}</RequestId></ResponseMetadata>
|
|
135
202
|
</CreateQueueResponse>`;
|
|
136
203
|
}
|
|
137
204
|
|
|
138
205
|
generateSendMessageResponse(messageId, md5) {
|
|
139
206
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
140
|
-
<SendMessageResponse>
|
|
207
|
+
<SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
|
141
208
|
<SendMessageResult>
|
|
142
209
|
<MD5OfMessageBody>${md5}</MD5OfMessageBody>
|
|
143
210
|
<MessageId>${messageId}</MessageId>
|
|
144
211
|
</SendMessageResult>
|
|
212
|
+
<ResponseMetadata><RequestId>${crypto.randomUUID()}</RequestId></ResponseMetadata>
|
|
145
213
|
</SendMessageResponse>`;
|
|
146
214
|
}
|
|
147
215
|
|
|
148
216
|
generateSendMessageBatchResponse(successful, failed) {
|
|
149
217
|
let xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
150
|
-
<SendMessageBatchResponse>
|
|
218
|
+
<SendMessageBatchResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
|
151
219
|
<SendMessageBatchResult>`;
|
|
152
220
|
|
|
153
221
|
for (const s of successful) {
|
|
@@ -170,6 +238,7 @@ class SQSServer {
|
|
|
170
238
|
|
|
171
239
|
xml += `
|
|
172
240
|
</SendMessageBatchResult>
|
|
241
|
+
<ResponseMetadata><RequestId>${crypto.randomUUID()}</RequestId></ResponseMetadata>
|
|
173
242
|
</SendMessageBatchResponse>`;
|
|
174
243
|
|
|
175
244
|
return xml;
|
|
@@ -177,7 +246,7 @@ class SQSServer {
|
|
|
177
246
|
|
|
178
247
|
generateReceiveMessageResponse(messages) {
|
|
179
248
|
let xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
180
|
-
<ReceiveMessageResponse>
|
|
249
|
+
<ReceiveMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
|
181
250
|
<ReceiveMessageResult>`;
|
|
182
251
|
|
|
183
252
|
for (const msg of messages) {
|
|
@@ -192,6 +261,7 @@ class SQSServer {
|
|
|
192
261
|
|
|
193
262
|
xml += `
|
|
194
263
|
</ReceiveMessageResult>
|
|
264
|
+
<ResponseMetadata><RequestId>${crypto.randomUUID()}</RequestId></ResponseMetadata>
|
|
195
265
|
</ReceiveMessageResponse>`;
|
|
196
266
|
|
|
197
267
|
return xml;
|
|
@@ -199,25 +269,26 @@ class SQSServer {
|
|
|
199
269
|
|
|
200
270
|
generateDeleteMessageResponse() {
|
|
201
271
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
202
|
-
<DeleteMessageResponse>
|
|
272
|
+
<DeleteMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
|
203
273
|
<ResponseMetadata>
|
|
204
|
-
<RequestId>${
|
|
274
|
+
<RequestId>${crypto.randomUUID()}</RequestId>
|
|
205
275
|
</ResponseMetadata>
|
|
206
276
|
</DeleteMessageResponse>`;
|
|
207
277
|
}
|
|
208
278
|
|
|
209
279
|
generateGetQueueUrlResponse(queueUrl) {
|
|
210
280
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
211
|
-
<GetQueueUrlResponse>
|
|
281
|
+
<GetQueueUrlResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
|
212
282
|
<GetQueueUrlResult>
|
|
213
283
|
<QueueUrl>${queueUrl}</QueueUrl>
|
|
214
284
|
</GetQueueUrlResult>
|
|
285
|
+
<ResponseMetadata><RequestId>${crypto.randomUUID()}</RequestId></ResponseMetadata>
|
|
215
286
|
</GetQueueUrlResponse>`;
|
|
216
287
|
}
|
|
217
288
|
|
|
218
289
|
generateListQueuesResponse(queues) {
|
|
219
290
|
let xml = `<?xml version="1.0" encoding="UTF-8"?>
|
|
220
|
-
<ListQueuesResponse>
|
|
291
|
+
<ListQueuesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
|
|
221
292
|
<ListQueuesResult>`;
|
|
222
293
|
|
|
223
294
|
for (const queue of queues) {
|
|
@@ -226,6 +297,7 @@ class SQSServer {
|
|
|
226
297
|
|
|
227
298
|
xml += `
|
|
228
299
|
</ListQueuesResult>
|
|
300
|
+
<ResponseMetadata><RequestId>${crypto.randomUUID()}</RequestId></ResponseMetadata>
|
|
229
301
|
</ListQueuesResponse>`;
|
|
230
302
|
|
|
231
303
|
return xml;
|