@gugananuvem/aws-local-simulator 1.0.34 → 1.0.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gugananuvem/aws-local-simulator",
3
- "version": "1.0.34",
3
+ "version": "1.0.35",
4
4
  "description": "Simulador local completo para serviços AWS",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -10,7 +10,6 @@
10
10
  "start": "node bin/aws-local-simulator.js start"
11
11
  },
12
12
  "dependencies": {
13
- "better-sqlite3": "^11.0.0",
14
13
  "@aws-sdk/client-api-gateway": "^3.0.0",
15
14
  "@aws-sdk/client-cognito-identity-provider": "^3.0.0",
16
15
  "@aws-sdk/client-dynamodb": "^3.0.0",
@@ -19,6 +18,7 @@
19
18
  "@aws-sdk/client-s3": "^3.0.0",
20
19
  "@aws-sdk/client-sqs": "^3.0.0",
21
20
  "@aws-sdk/lib-dynamodb": "^3.0.0",
21
+ "better-sqlite3": "11.10.0",
22
22
  "child_process": "1.0.2",
23
23
  "cors": "^2.8.5",
24
24
  "crypto": "1.0.1",
@@ -67,6 +67,6 @@
67
67
  "publishConfig": {
68
68
  "directory": "dist"
69
69
  },
70
- "buildDate": "2026-06-23T12:54:20.022Z",
70
+ "buildDate": "2026-06-26T03:40:01.988Z",
71
71
  "published": true
72
72
  }
@@ -146,9 +146,25 @@ class HandlerLoader {
146
146
  * Recarrega um handler (útil para hot reload)
147
147
  */
148
148
  static async reload(handlerPath, type = 'auto') {
149
- // Limpa cache
150
- const fullPath = path.resolve(process.cwd(), handlerPath);
151
- delete require.cache[require.resolve(fullPath)];
149
+ // Resolve path: try cwd first, then data dir (same logic as load())
150
+ let fullPath = path.resolve(process.cwd(), handlerPath);
151
+
152
+ if (!fs.existsSync(fullPath)) {
153
+ const dataDir = process.env.AWS_LOCAL_SIMULATOR_DATA_DIR;
154
+ if (dataDir) {
155
+ const dataPath = path.resolve(dataDir, 'lambda', handlerPath.replace(/^\.\//, ''));
156
+ if (fs.existsSync(dataPath)) {
157
+ fullPath = dataPath;
158
+ }
159
+ }
160
+ }
161
+
162
+ if (!fs.existsSync(fullPath)) {
163
+ throw new Error(`Handler não encontrado: ${fullPath}`);
164
+ }
165
+
166
+ // Limpa cache do require
167
+ delete require.cache[fullPath];
152
168
 
153
169
  // Recarrega
154
170
  return this.load(handlerPath, type);
@@ -158,7 +174,20 @@ class HandlerLoader {
158
174
  * Valida se um caminho de handler é válido
159
175
  */
160
176
  static isValid(handlerPath) {
161
- const fullPath = path.resolve(process.cwd(), handlerPath);
177
+ // Tenta resolver de cwd primeiro
178
+ let fullPath = path.resolve(process.cwd(), handlerPath);
179
+
180
+ if (!fs.existsSync(fullPath)) {
181
+ // Tenta resolver do data dir
182
+ const dataDir = process.env.AWS_LOCAL_SIMULATOR_DATA_DIR;
183
+ if (dataDir) {
184
+ const dataPath = path.resolve(dataDir, 'lambda', handlerPath.replace(/^\.\//, ''));
185
+ if (fs.existsSync(dataPath)) {
186
+ return true;
187
+ }
188
+ }
189
+ }
190
+
162
191
  return fs.existsSync(fullPath);
163
192
  }
164
193
 
@@ -166,7 +195,23 @@ class HandlerLoader {
166
195
  * Retorna informações sobre o handler
167
196
  */
168
197
  static async getInfo(handlerPath) {
169
- const fullPath = path.resolve(process.cwd(), handlerPath);
198
+ // Resolve path: try cwd first, then data dir (same logic as load())
199
+ let fullPath = path.resolve(process.cwd(), handlerPath);
200
+
201
+ if (!fs.existsSync(fullPath)) {
202
+ const dataDir = process.env.AWS_LOCAL_SIMULATOR_DATA_DIR;
203
+ if (dataDir) {
204
+ const dataPath = path.resolve(dataDir, 'lambda', handlerPath.replace(/^\.\//, ''));
205
+ if (fs.existsSync(dataPath)) {
206
+ fullPath = dataPath;
207
+ }
208
+ }
209
+ }
210
+
211
+ if (!fs.existsSync(fullPath)) {
212
+ throw new Error(`Handler não encontrado: ${fullPath}`);
213
+ }
214
+
170
215
  const type = this.detectType(fullPath);
171
216
  const stats = fs.statSync(fullPath);
172
217
 
@@ -18,6 +18,7 @@ class LambdaServer {
18
18
  }
19
19
 
20
20
  setupMiddlewares() {
21
+ this.app.use(express.json()); // Adiciona suporte para JSON
21
22
  this.app.use(express.urlencoded({ extended: true }));
22
23
  this.app.use(cors());
23
24
 
@@ -91,20 +92,13 @@ class LambdaServer {
91
92
  }
92
93
 
93
94
  setupAdminRoutes() {
94
- // Helper: parse Buffer body as JSON for admin routes
95
- const parseJson = (req, res, next) => {
96
- if (Buffer.isBuffer(req.body) && req.body.length > 0) {
97
- try { req.body = JSON.parse(req.body.toString('utf8')); } catch { req.body = {}; }
98
- }
99
- next();
100
- };
101
-
102
95
  this.app.get('/__admin/functions', (req, res) => {
103
96
  res.json(this.simulator.listLambdas());
104
97
  });
105
98
 
106
- this.app.post('/__admin/functions', parseJson, async (req, res) => {
99
+ this.app.post('/__admin/functions', async (req, res) => {
107
100
  try {
101
+ logger.debug(`📥 POST /__admin/functions:`, req.body);
108
102
  const lambda = await this.simulator.createFunction(req.body);
109
103
  res.status(201).json(lambda);
110
104
  } catch (err) {
@@ -112,8 +106,9 @@ class LambdaServer {
112
106
  }
113
107
  });
114
108
 
115
- this.app.put('/__admin/functions/:name', parseJson, async (req, res) => {
109
+ this.app.put('/__admin/functions/:name', async (req, res) => {
116
110
  try {
111
+ logger.debug(`📥 PUT /__admin/functions/${req.params.name}:`, req.body);
117
112
  const lambda = await this.simulator.updateFunction(req.params.name, req.body);
118
113
  res.json(lambda);
119
114
  } catch (err) {
@@ -132,7 +127,7 @@ class LambdaServer {
132
127
  res.json({ message: 'Lambdas recarregadas', count: this.simulator.getLambdasCount() });
133
128
  });
134
129
 
135
- this.app.post('/__admin/env', parseJson, (req, res) => {
130
+ this.app.post('/__admin/env', (req, res) => {
136
131
  const { key, value } = req.body;
137
132
  if (key && value !== undefined) {
138
133
  this.simulator.setEnvironmentVariable(key, value);
@@ -48,13 +48,24 @@ class LambdaSimulator {
48
48
 
49
49
  async registerLambda(lambdaConfig) {
50
50
  try {
51
- const { name, handler: handlerPath, type = "auto" } = lambdaConfig;
51
+ const { name, handler: handlerPath, type = "auto", runtime = "nodejs18.x" } = lambdaConfig;
52
52
 
53
53
  if (!name) {
54
54
  logger.warn(`Lambda sem nome ignorada: ${JSON.stringify(lambdaConfig)}`);
55
55
  return;
56
56
  }
57
57
 
58
+ // Resolve the handler path to absolute path
59
+ let resolvedHandlerPath = path.resolve(process.cwd(), handlerPath);
60
+
61
+ // Se não existir no cwd, tenta no data dir
62
+ if (!fs.existsSync(resolvedHandlerPath)) {
63
+ const dataPath = path.resolve(this.dataDir, handlerPath.replace(/^\.\//, ''));
64
+ if (fs.existsSync(dataPath)) {
65
+ resolvedHandlerPath = dataPath;
66
+ }
67
+ }
68
+
58
69
  // Merge: global env as base, lambda-specific env overrides
59
70
  const env = {
60
71
  ...(this.globalEnv || {}),
@@ -76,8 +87,9 @@ class LambdaSimulator {
76
87
  if (handler != undefined) {
77
88
  this.lambdas.set(name, {
78
89
  name,
90
+ runtime,
79
91
  handler,
80
- handlerPath,
92
+ handlerPath: resolvedHandlerPath,
81
93
  handlerName: handler.name || "anonymous",
82
94
  env,
83
95
  timeout,
@@ -87,7 +99,7 @@ class LambdaSimulator {
87
99
  registeredAt: new Date().toISOString(),
88
100
  });
89
101
  }
90
- logger.debug(`✅ Lambda registrada: ${name} -> ${handlerPath}`);
102
+ logger.debug(`✅ Lambda registrada: ${name} -> ${resolvedHandlerPath}`);
91
103
  } catch (error) {
92
104
  if (error.message.indexOf("Handler não encontrado") == -1){
93
105
  logger.error(`Erro ao registrar Lambda ${lambdaConfig.name}:`, error);
@@ -222,6 +234,7 @@ class LambdaSimulator {
222
234
 
223
235
  return {
224
236
  name: l.name,
237
+ runtime: l.runtime,
225
238
  handlerName: l.handlerName,
226
239
  handlerPath: l.handlerPath,
227
240
  type: l.type,
@@ -297,25 +310,64 @@ class LambdaSimulator {
297
310
  const lambda = this.lambdas.get(name);
298
311
  if (!lambda) throw new Error(`Function not found: ${name}`);
299
312
 
300
- const { code, runtime, handler, timeout, memorySize, environment } = lambdaConfig;
313
+ // Normaliza 'environment' para 'env' se necessário
314
+ const config = {
315
+ ...lambdaConfig,
316
+ env: lambdaConfig.environment || lambdaConfig.env
317
+ };
318
+ delete config.environment; // Remove para evitar confusão
319
+
320
+ const { code, runtime, handler, timeout, memorySize, env } = config;
321
+
322
+ logger.debug(`📝 Updating function ${name}:`, {
323
+ hasCode: !!code,
324
+ code: code ? `(${code.length} chars)` : 'NULL/UNDEFINED',
325
+ codeLength: code?.length,
326
+ runtime,
327
+ timeout,
328
+ memorySize,
329
+ handlerPath: lambda.handlerPath,
330
+ configKeys: Object.keys(config)
331
+ });
301
332
 
302
333
  // Se houver código novo, sobrescreve o arquivo
303
- if (code !== undefined) {
304
- fs.writeFileSync(lambda.handlerPath, code);
334
+ if (code !== undefined && code !== null && code.trim() !== '') {
335
+ logger.debug(`💾 Escrevendo código no arquivo: ${lambda.handlerPath}`);
336
+ try {
337
+ fs.writeFileSync(lambda.handlerPath, code, 'utf8');
338
+ logger.debug(`✅ Arquivo atualizado com sucesso`);
339
+ } catch (err) {
340
+ logger.error(`❌ Erro ao escrever arquivo:`, err);
341
+ throw err;
342
+ }
343
+
344
+ // Reload the handler from the updated file
345
+ try {
346
+ const newHandler = await HandlerLoader.reload(lambda.handlerPath, lambda.type);
347
+ lambda.handler = newHandler;
348
+ lambda.handlerName = newHandler.name || "anonymous";
349
+
350
+ // Update code size
351
+ try {
352
+ const info = await HandlerLoader.getInfo(lambda.handlerPath);
353
+ lambda.codeSize = info.size;
354
+ } catch (err) {
355
+ // Ignore size errors
356
+ }
357
+ } catch (error) {
358
+ logger.error(`❌ Erro ao recarregar Lambda ${name}:`, error);
359
+ throw error;
360
+ }
361
+ } else {
362
+ logger.warn(`⚠️ Nenhum código fornecido para atualização. code=${JSON.stringify(code)}`);
305
363
  }
306
364
 
307
- // Atualiza a configuração
308
- const updatedConfig = {
309
- name,
310
- handler: lambda.handlerPath,
311
- runtime: runtime || lambda.runtime,
312
- timeout: timeout || lambda.timeout,
313
- memorySize: memorySize || lambda.memorySize,
314
- env: environment || lambda.env,
315
- type: lambda.type
316
- };
365
+ // Atualiza outras configurações
366
+ if (runtime !== undefined) lambda.runtime = runtime;
367
+ if (timeout !== undefined) lambda.timeout = timeout;
368
+ if (memorySize !== undefined) lambda.memorySize = memorySize;
369
+ if (env !== undefined) lambda.env = env;
317
370
 
318
- await this.registerLambda(updatedConfig);
319
371
  this.persistLambdas();
320
372
 
321
373
  return this.lambdas.get(name);