@gugananuvem/aws-local-simulator 1.0.34 → 1.0.39
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 +662 -658
- package/package.json +11 -4
- package/src/config/default-config.js +71 -0
- package/src/config/env-loader.js +4 -2
- package/src/middleware/authorization.js +271 -0
- package/src/middleware/cloudtrail-logger.js +333 -0
- package/src/middleware/error-handler.js +138 -0
- package/src/middleware/index.js +79 -0
- package/src/middleware/policy-enforcement.js +407 -0
- package/src/server.js +74 -4
- package/src/services/acm/index.js +66 -0
- package/src/services/acm/models/certificate.js +202 -0
- package/src/services/acm/server.js +224 -0
- package/src/services/acm/simulator.js +293 -0
- package/src/services/alb/index.js +104 -0
- package/src/services/alb/models/loadBalancer.js +88 -0
- package/src/services/alb/models/targetGroup.js +128 -0
- package/src/services/alb/server.js +160 -0
- package/src/services/alb/simulator.js +262 -0
- package/src/services/apigateway/index.js +22 -0
- package/src/services/apigateway/server.js +247 -35
- package/src/services/apigateway/simulator.js +780 -26
- package/src/services/asg/index.js +100 -0
- package/src/services/asg/models/autoScalingGroup.js +110 -0
- package/src/services/asg/models/launchTemplate.js +41 -0
- package/src/services/asg/models/scalingPolicy.js +51 -0
- package/src/services/asg/server.js +236 -0
- package/src/services/asg/simulator.js +410 -0
- package/src/services/aurora/cluster-manager.js +731 -0
- package/src/services/aurora/data-api.js +514 -0
- package/src/services/aurora/db-engine.js +270 -0
- package/src/services/aurora/index.js +159 -0
- package/src/services/aurora/rds-api.js +189 -0
- package/src/services/aurora/server.js +213 -0
- package/src/services/aurora/sql-translator.js +334 -0
- package/src/services/cloudformation/index.js +2 -2
- package/src/services/cloudformation/server.js +1 -0
- package/src/services/cloudfront/cache-engine.js +225 -0
- package/src/services/cloudfront/geo-restrictions.js +377 -0
- package/src/services/cloudfront/index.js +220 -0
- package/src/services/cloudfront/models/behavior.js +158 -0
- package/src/services/cloudfront/models/distribution.js +284 -0
- package/src/services/cloudfront/models/index.js +99 -0
- package/src/services/cloudfront/models/invalidation.js +109 -0
- package/src/services/cloudfront/models/origin.js +155 -0
- package/src/services/cloudfront/origin-router.js +552 -0
- package/src/services/cloudfront/origin-validator.js +398 -0
- package/src/services/cloudfront/server.js +512 -0
- package/src/services/cloudfront/signed-url-generator.js +377 -0
- package/src/services/cloudfront/simulator.js +425 -0
- package/src/services/cloudfront/store.js +326 -0
- package/src/services/cloudshell/env-builder.js +27 -0
- package/src/services/cloudshell/index.js +48 -0
- package/src/services/cloudshell/routes.js +60 -0
- package/src/services/cloudshell/session-manager.js +226 -0
- package/src/services/cloudshell/static/.gitkeep +0 -0
- package/src/services/cloudshell/static/index.html +406 -0
- package/src/services/cloudshell/websocket-handler.js +107 -0
- package/src/services/cloudtrail/index.js +2 -3
- package/src/services/cloudtrail/server.js +68 -0
- package/src/services/cognito/server.js +4 -1
- package/src/services/dynamodb/server.js +4 -1
- package/src/services/dynamodb/simulator.js +2 -1
- package/src/services/ec2/index.js +101 -0
- package/src/services/ec2/instanceServer.js +311 -0
- package/src/services/ec2/models/ami.js +39 -0
- package/src/services/ec2/models/instance.js +98 -0
- package/src/services/ec2/models/networkInterface.js +74 -0
- package/src/services/ec2/models/securityGroup.js +71 -0
- package/src/services/ec2/server.js +350 -0
- package/src/services/ec2/simulator.js +436 -0
- package/src/services/eventbridge/server.js +36 -0
- package/src/services/eventbridge/simulator.js +230 -45
- package/src/services/iam/index.js +65 -0
- package/src/services/iam/middleware.js +99 -0
- package/src/services/iam/server.js +331 -0
- package/src/services/iam/simulator.js +1432 -0
- package/src/services/index.js +28 -0
- package/src/services/kinesis-analytics/index.js +105 -0
- package/src/services/kinesis-analytics/models/application.js +325 -0
- package/src/services/kinesis-analytics/models/index.js +12 -0
- package/src/services/kinesis-analytics/server.js +250 -0
- package/src/services/kinesis-analytics/simulator.js +407 -0
- package/src/services/kinesis-analytics/store.js +176 -0
- package/src/services/kinesis-data-streams/index.js +106 -0
- package/src/services/kinesis-data-streams/models/index.js +12 -0
- package/src/services/kinesis-data-streams/models/record.js +70 -0
- package/src/services/kinesis-data-streams/models/stream.js +280 -0
- package/src/services/kinesis-data-streams/server.js +255 -0
- package/src/services/kinesis-data-streams/simulator.js +514 -0
- package/src/services/kinesis-data-streams/store.js +163 -0
- package/src/services/kinesis-firehose/index.js +106 -0
- package/src/services/kinesis-firehose/models/delivery-stream.js +265 -0
- package/src/services/kinesis-firehose/models/index.js +10 -0
- package/src/services/kinesis-firehose/server.js +215 -0
- package/src/services/kinesis-firehose/simulator.js +388 -0
- package/src/services/kinesis-firehose/store.js +163 -0
- package/src/services/kms/server.js +4 -1
- package/src/services/lambda/handler-loader.js +50 -5
- package/src/services/lambda/index.js +26 -0
- package/src/services/lambda/server.js +18 -12
- package/src/services/lambda/simulator.js +73 -17
- package/src/services/opensearch/index.js +105 -0
- package/src/services/opensearch/models/document.js +115 -0
- package/src/services/opensearch/models/index.js +73 -0
- package/src/services/opensearch/server.js +310 -0
- package/src/services/opensearch/simulator.js +605 -0
- package/src/services/opensearch/store.js +162 -0
- package/src/services/organizations/control-tower-simulator.js +321 -0
- package/src/services/organizations/control-tower-store.js +182 -0
- package/src/services/organizations/iam-integration.js +413 -0
- package/src/services/organizations/index.js +172 -0
- package/src/services/organizations/models/index.js +13 -0
- package/src/services/organizations/models/invitation.js +48 -0
- package/src/services/organizations/models/organization.js +566 -0
- package/src/services/organizations/models/role.js +244 -0
- package/src/services/organizations/models/scp.js +131 -0
- package/src/services/organizations/server.js +736 -0
- package/src/services/organizations/simulator.js +593 -0
- package/src/services/organizations/store.js +235 -0
- package/src/services/organizations/vpc-integration.js +453 -0
- package/src/services/route53/index.js +67 -0
- package/src/services/route53/models/healthCheck.js +101 -0
- package/src/services/route53/models/hostedZone.js +37 -0
- package/src/services/route53/models/resourceRecord.js +106 -0
- package/src/services/route53/server.js +841 -0
- package/src/services/route53/simulator.js +350 -0
- package/src/services/s3/index.js +62 -0
- package/src/services/s3/presigned-url-generator.js +337 -0
- package/src/services/s3/server.js +231 -0
- package/src/services/s3/simulator.js +551 -4
- package/src/services/sns/index.js +31 -0
- package/src/services/sns/server.js +9 -0
- package/src/services/sqs/index.js +38 -0
- package/src/services/sqs/server.js +57 -4
- package/src/services/sqs/simulator.js +423 -33
- package/src/services/sts/simulator.js +209 -17
- package/src/services/vpc/README.md +459 -0
- package/src/services/vpc/ec2ResponseFormatter.js +431 -0
- package/src/services/vpc/index.js +90 -0
- package/src/services/vpc/models/internetGateway.js +71 -0
- package/src/services/vpc/models/routeTable.js +160 -0
- package/src/services/vpc/models/subnet.js +48 -0
- package/src/services/vpc/models/vpc.js +37 -0
- package/src/services/vpc/models/vpcEndpoint.js +100 -0
- package/src/services/vpc/models/vpcGateway.js +134 -0
- package/src/services/vpc/server.js +836 -0
- package/src/services/vpc/simulator.js +613 -0
- package/src/utils/policy-cache.js +215 -0
- package/aws-config +0 -154
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const { setupServiceMiddleware } = require('../../middleware');
|
|
1
2
|
/**
|
|
2
3
|
* Lambda Server - Servidor HTTP para Lambda (API Gateway style)
|
|
3
4
|
*/
|
|
@@ -8,7 +9,9 @@ const LambdaSimulator = require('./simulator');
|
|
|
8
9
|
const logger = require('../../utils/logger');
|
|
9
10
|
|
|
10
11
|
class LambdaServer {
|
|
11
|
-
constructor(port, config) {
|
|
12
|
+
constructor(port, config) {
|
|
13
|
+
this.organizationsService = null;
|
|
14
|
+
this.stsService = null;
|
|
12
15
|
this.port = port;
|
|
13
16
|
this.config = config;
|
|
14
17
|
this.app = express();
|
|
@@ -18,6 +21,7 @@ class LambdaServer {
|
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
setupMiddlewares() {
|
|
24
|
+
this.app.use(express.json()); // Adiciona suporte para JSON
|
|
21
25
|
this.app.use(express.urlencoded({ extended: true }));
|
|
22
26
|
this.app.use(cors());
|
|
23
27
|
|
|
@@ -41,6 +45,14 @@ class LambdaServer {
|
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
setupRoutes() {
|
|
48
|
+
// IAM enforcement (conditionally applied)
|
|
49
|
+
this.app.use((req, res, next) => {
|
|
50
|
+
if (this.iamMiddleware && !req.path.startsWith('/__admin') && !req.path.startsWith('/health')) {
|
|
51
|
+
return this.iamMiddleware(req, res, next);
|
|
52
|
+
}
|
|
53
|
+
next();
|
|
54
|
+
});
|
|
55
|
+
|
|
44
56
|
// Health check
|
|
45
57
|
this.app.get('/health', (req, res) => {
|
|
46
58
|
res.json({ status: 'healthy', lambdas: this.simulator.getLambdasCount() });
|
|
@@ -91,20 +103,13 @@ class LambdaServer {
|
|
|
91
103
|
}
|
|
92
104
|
|
|
93
105
|
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
106
|
this.app.get('/__admin/functions', (req, res) => {
|
|
103
107
|
res.json(this.simulator.listLambdas());
|
|
104
108
|
});
|
|
105
109
|
|
|
106
|
-
this.app.post('/__admin/functions',
|
|
110
|
+
this.app.post('/__admin/functions', async (req, res) => {
|
|
107
111
|
try {
|
|
112
|
+
logger.debug(`📥 POST /__admin/functions:`, req.body);
|
|
108
113
|
const lambda = await this.simulator.createFunction(req.body);
|
|
109
114
|
res.status(201).json(lambda);
|
|
110
115
|
} catch (err) {
|
|
@@ -112,8 +117,9 @@ class LambdaServer {
|
|
|
112
117
|
}
|
|
113
118
|
});
|
|
114
119
|
|
|
115
|
-
this.app.put('/__admin/functions/:name',
|
|
120
|
+
this.app.put('/__admin/functions/:name', async (req, res) => {
|
|
116
121
|
try {
|
|
122
|
+
logger.debug(`📥 PUT /__admin/functions/${req.params.name}:`, req.body);
|
|
117
123
|
const lambda = await this.simulator.updateFunction(req.params.name, req.body);
|
|
118
124
|
res.json(lambda);
|
|
119
125
|
} catch (err) {
|
|
@@ -132,7 +138,7 @@ class LambdaServer {
|
|
|
132
138
|
res.json({ message: 'Lambdas recarregadas', count: this.simulator.getLambdasCount() });
|
|
133
139
|
});
|
|
134
140
|
|
|
135
|
-
this.app.post('/__admin/env',
|
|
141
|
+
this.app.post('/__admin/env', (req, res) => {
|
|
136
142
|
const { key, value } = req.body;
|
|
137
143
|
if (key && value !== undefined) {
|
|
138
144
|
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} -> ${
|
|
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);
|
|
@@ -129,6 +141,10 @@ class LambdaSimulator {
|
|
|
129
141
|
return { StatusCode: result.statusCode || 200, Payload: result };
|
|
130
142
|
}
|
|
131
143
|
|
|
144
|
+
async invokeFunction(functionName, event) {
|
|
145
|
+
return this.invoke(functionName, event, "Event");
|
|
146
|
+
}
|
|
147
|
+
|
|
132
148
|
async executeHandler(lambda, functionName, event) {
|
|
133
149
|
const requestId = Math.random().toString(36).substring(2, 10) + Math.random().toString(36).substring(2, 10);
|
|
134
150
|
const capturedLogs = [];
|
|
@@ -222,6 +238,7 @@ class LambdaSimulator {
|
|
|
222
238
|
|
|
223
239
|
return {
|
|
224
240
|
name: l.name,
|
|
241
|
+
runtime: l.runtime,
|
|
225
242
|
handlerName: l.handlerName,
|
|
226
243
|
handlerPath: l.handlerPath,
|
|
227
244
|
type: l.type,
|
|
@@ -297,25 +314,64 @@ class LambdaSimulator {
|
|
|
297
314
|
const lambda = this.lambdas.get(name);
|
|
298
315
|
if (!lambda) throw new Error(`Function not found: ${name}`);
|
|
299
316
|
|
|
300
|
-
|
|
317
|
+
// Normaliza 'environment' para 'env' se necessário
|
|
318
|
+
const config = {
|
|
319
|
+
...lambdaConfig,
|
|
320
|
+
env: lambdaConfig.environment || lambdaConfig.env
|
|
321
|
+
};
|
|
322
|
+
delete config.environment; // Remove para evitar confusão
|
|
323
|
+
|
|
324
|
+
const { code, runtime, handler, timeout, memorySize, env } = config;
|
|
325
|
+
|
|
326
|
+
logger.debug(`📝 Updating function ${name}:`, {
|
|
327
|
+
hasCode: !!code,
|
|
328
|
+
code: code ? `(${code.length} chars)` : 'NULL/UNDEFINED',
|
|
329
|
+
codeLength: code?.length,
|
|
330
|
+
runtime,
|
|
331
|
+
timeout,
|
|
332
|
+
memorySize,
|
|
333
|
+
handlerPath: lambda.handlerPath,
|
|
334
|
+
configKeys: Object.keys(config)
|
|
335
|
+
});
|
|
301
336
|
|
|
302
337
|
// Se houver código novo, sobrescreve o arquivo
|
|
303
|
-
if (code !== undefined) {
|
|
304
|
-
|
|
338
|
+
if (code !== undefined && code !== null && code.trim() !== '') {
|
|
339
|
+
logger.debug(`💾 Escrevendo código no arquivo: ${lambda.handlerPath}`);
|
|
340
|
+
try {
|
|
341
|
+
fs.writeFileSync(lambda.handlerPath, code, 'utf8');
|
|
342
|
+
logger.debug(`✅ Arquivo atualizado com sucesso`);
|
|
343
|
+
} catch (err) {
|
|
344
|
+
logger.error(`❌ Erro ao escrever arquivo:`, err);
|
|
345
|
+
throw err;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Reload the handler from the updated file
|
|
349
|
+
try {
|
|
350
|
+
const newHandler = await HandlerLoader.reload(lambda.handlerPath, lambda.type);
|
|
351
|
+
lambda.handler = newHandler;
|
|
352
|
+
lambda.handlerName = newHandler.name || "anonymous";
|
|
353
|
+
|
|
354
|
+
// Update code size
|
|
355
|
+
try {
|
|
356
|
+
const info = await HandlerLoader.getInfo(lambda.handlerPath);
|
|
357
|
+
lambda.codeSize = info.size;
|
|
358
|
+
} catch (err) {
|
|
359
|
+
// Ignore size errors
|
|
360
|
+
}
|
|
361
|
+
} catch (error) {
|
|
362
|
+
logger.error(`❌ Erro ao recarregar Lambda ${name}:`, error);
|
|
363
|
+
throw error;
|
|
364
|
+
}
|
|
365
|
+
} else {
|
|
366
|
+
logger.warn(`⚠️ Nenhum código fornecido para atualização. code=${JSON.stringify(code)}`);
|
|
305
367
|
}
|
|
306
368
|
|
|
307
|
-
// Atualiza
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
timeout: timeout || lambda.timeout,
|
|
313
|
-
memorySize: memorySize || lambda.memorySize,
|
|
314
|
-
env: environment || lambda.env,
|
|
315
|
-
type: lambda.type
|
|
316
|
-
};
|
|
369
|
+
// Atualiza outras configurações
|
|
370
|
+
if (runtime !== undefined) lambda.runtime = runtime;
|
|
371
|
+
if (timeout !== undefined) lambda.timeout = timeout;
|
|
372
|
+
if (memorySize !== undefined) lambda.memorySize = memorySize;
|
|
373
|
+
if (env !== undefined) lambda.env = env;
|
|
317
374
|
|
|
318
|
-
await this.registerLambda(updatedConfig);
|
|
319
375
|
this.persistLambdas();
|
|
320
376
|
|
|
321
377
|
return this.lambdas.get(name);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenSearch Service - Ponto de entrada
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const OpenSearchServer = require('./server');
|
|
6
|
+
const OpenSearchSimulator = require('./simulator');
|
|
7
|
+
|
|
8
|
+
class OpenSearchService {
|
|
9
|
+
constructor(config) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.name = 'opensearch';
|
|
12
|
+
this.port = config.ports.opensearch || 9200;
|
|
13
|
+
this.server = null;
|
|
14
|
+
this.simulator = null;
|
|
15
|
+
this.isRunning = false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async initialize() {
|
|
19
|
+
const logger = require('../../utils/logger');
|
|
20
|
+
logger.debug(`Inicializando OpenSearch Service na porta ${this.port}...`);
|
|
21
|
+
|
|
22
|
+
this.simulator = new OpenSearchSimulator(this.config);
|
|
23
|
+
await this.simulator.initialize();
|
|
24
|
+
|
|
25
|
+
this.server = new OpenSearchServer(this.port, this.config);
|
|
26
|
+
this.server.simulator = this.simulator;
|
|
27
|
+
|
|
28
|
+
await this.server.initialize();
|
|
29
|
+
|
|
30
|
+
logger.debug('OpenSearch Service inicializado');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
injectDependencies(server) {
|
|
34
|
+
// Aqui você pode injetar dependências de outros serviços se necessário
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async start() {
|
|
38
|
+
const logger = require('../../utils/logger');
|
|
39
|
+
|
|
40
|
+
if (this.isRunning) {
|
|
41
|
+
logger.warn('OpenSearch Service já está em execução');
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
await this.server.start();
|
|
47
|
+
this.isRunning = true;
|
|
48
|
+
logger.info('OpenSearch Service iniciado com sucesso');
|
|
49
|
+
} catch (error) {
|
|
50
|
+
logger.error(`Erro ao iniciar OpenSearch Service: ${error.message}`);
|
|
51
|
+
throw error;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async stop() {
|
|
56
|
+
const logger = require('../../utils/logger');
|
|
57
|
+
|
|
58
|
+
if (!this.isRunning) {
|
|
59
|
+
logger.warn('OpenSearch Service não está em execução');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
await this.server.stop();
|
|
65
|
+
this.isRunning = false;
|
|
66
|
+
logger.info('OpenSearch Service parado com sucesso');
|
|
67
|
+
} catch (error) {
|
|
68
|
+
logger.error(`Erro ao parar OpenSearch Service: ${error.message}`);
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async reset() {
|
|
74
|
+
const logger = require('../../utils/logger');
|
|
75
|
+
try {
|
|
76
|
+
await this.simulator.reset();
|
|
77
|
+
logger.info('OpenSearch Service resetado');
|
|
78
|
+
} catch (error) {
|
|
79
|
+
logger.error(`Erro ao resetar OpenSearch Service: ${error.message}`);
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
getSimulator() {
|
|
85
|
+
return this.simulator;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
getStatus() {
|
|
89
|
+
const stats = this.simulator?.getClusterStats() || { indices: 0, docs: 0, size_mb: 0 };
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
name: this.name,
|
|
93
|
+
running: this.isRunning,
|
|
94
|
+
port: this.port,
|
|
95
|
+
endpoint: `http://localhost:${this.port}`,
|
|
96
|
+
resources: {
|
|
97
|
+
indicesCount: stats.indices,
|
|
98
|
+
docsCount: stats.docs,
|
|
99
|
+
sizeMb: stats.size_mb
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
module.exports = OpenSearchService;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenSearch Document Model - Equivalente ao Item no DynamoDB
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { v4: uuidv4 } = require('uuid');
|
|
6
|
+
|
|
7
|
+
class Document {
|
|
8
|
+
constructor(data = {}, config = {}) {
|
|
9
|
+
this._id = config._id || uuidv4();
|
|
10
|
+
this._type = config._type || '_doc';
|
|
11
|
+
this._index = config._index || null;
|
|
12
|
+
this._version = config._version || 1;
|
|
13
|
+
this._seq_no = config._seq_no || 0;
|
|
14
|
+
this._primary_term = config._primary_term || 1;
|
|
15
|
+
this._score = config._score || null;
|
|
16
|
+
|
|
17
|
+
// Metadados
|
|
18
|
+
this._createdAt = config._createdAt || new Date().toISOString();
|
|
19
|
+
this._updatedAt = config._updatedAt || new Date().toISOString();
|
|
20
|
+
|
|
21
|
+
// Source - dados do documento
|
|
22
|
+
this._source = data;
|
|
23
|
+
|
|
24
|
+
// Highlights - para busca
|
|
25
|
+
this.highlight = {};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Atualiza documento
|
|
30
|
+
*/
|
|
31
|
+
update(data = {}) {
|
|
32
|
+
this._source = { ...this._source, ...data };
|
|
33
|
+
this._version++;
|
|
34
|
+
this._updatedAt = new Date().toISOString();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Incrementa version
|
|
39
|
+
*/
|
|
40
|
+
incrementVersion() {
|
|
41
|
+
this._version++;
|
|
42
|
+
this._updatedAt = new Date().toISOString();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Retorna documento em formato Elasticsearch
|
|
47
|
+
*/
|
|
48
|
+
toJSON() {
|
|
49
|
+
return {
|
|
50
|
+
_id: this._id,
|
|
51
|
+
_type: this._type,
|
|
52
|
+
_index: this._index,
|
|
53
|
+
_version: this._version,
|
|
54
|
+
_seq_no: this._seq_no,
|
|
55
|
+
_primary_term: this._primary_term,
|
|
56
|
+
_score: this._score,
|
|
57
|
+
_source: this._source,
|
|
58
|
+
highlight: Object.keys(this.highlight).length > 0 ? this.highlight : undefined
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Retorna apenas _source
|
|
64
|
+
*/
|
|
65
|
+
getSource() {
|
|
66
|
+
return this._source;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Retorna tamanho em bytes (aproximado)
|
|
71
|
+
*/
|
|
72
|
+
getSize() {
|
|
73
|
+
return JSON.stringify(this._source).length;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Verifica se documento match em busca simples
|
|
78
|
+
*/
|
|
79
|
+
matchesQuery(query = {}) {
|
|
80
|
+
if (Object.keys(query).length === 0) return true;
|
|
81
|
+
|
|
82
|
+
for (const [key, value] of Object.entries(query)) {
|
|
83
|
+
if (key === '_id' && this._id !== value) return false;
|
|
84
|
+
if (key === '_type' && this._type !== value) return false;
|
|
85
|
+
if (!(key in this._source)) return false;
|
|
86
|
+
|
|
87
|
+
const fieldValue = this._source[key];
|
|
88
|
+
if (typeof fieldValue === 'string') {
|
|
89
|
+
if (!fieldValue.toLowerCase().includes(String(value).toLowerCase())) return false;
|
|
90
|
+
} else if (fieldValue !== value) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Busca full-text simples
|
|
100
|
+
*/
|
|
101
|
+
matchesFullText(text = '') {
|
|
102
|
+
if (!text) return true;
|
|
103
|
+
|
|
104
|
+
const searchText = text.toLowerCase();
|
|
105
|
+
for (const value of Object.values(this._source)) {
|
|
106
|
+
if (typeof value === 'string' && value.toLowerCase().includes(searchText)) {
|
|
107
|
+
return true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = Document;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenSearch Index Model - Equivalente à Table no DynamoDB
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
const { v4: uuidv4 } = require('uuid');
|
|
6
|
+
|
|
7
|
+
class Index {
|
|
8
|
+
constructor(name, config = {}) {
|
|
9
|
+
this.name = name;
|
|
10
|
+
this.settings = {
|
|
11
|
+
number_of_shards: config.number_of_shards || 1,
|
|
12
|
+
number_of_replicas: config.number_of_replicas || 1,
|
|
13
|
+
analysis: config.analysis || {
|
|
14
|
+
analyzer: {
|
|
15
|
+
default: {
|
|
16
|
+
type: 'standard'
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Mappings - Define tipos de campos
|
|
23
|
+
this.mappings = {
|
|
24
|
+
properties: config.properties || {
|
|
25
|
+
_id: { type: 'keyword' },
|
|
26
|
+
_type: { type: 'keyword' },
|
|
27
|
+
_source: { type: 'text' }
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
this.aliases = config.aliases || {};
|
|
32
|
+
this.createdAt = new Date().toISOString();
|
|
33
|
+
this.status = 'open';
|
|
34
|
+
this.docsCount = 0;
|
|
35
|
+
this.storeSize = 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
toJSON() {
|
|
39
|
+
return {
|
|
40
|
+
name: this.name,
|
|
41
|
+
settings: this.settings,
|
|
42
|
+
mappings: this.mappings,
|
|
43
|
+
aliases: this.aliases,
|
|
44
|
+
status: this.status,
|
|
45
|
+
createdAt: this.createdAt,
|
|
46
|
+
docsCount: this.docsCount,
|
|
47
|
+
storeSize: this.storeSize
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Adiciona documento - incrementa contador
|
|
53
|
+
*/
|
|
54
|
+
addDocument() {
|
|
55
|
+
this.docsCount++;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Remove documento - decrementa contador
|
|
60
|
+
*/
|
|
61
|
+
removeDocument() {
|
|
62
|
+
if (this.docsCount > 0) this.docsCount--;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Atualiza tamanho do índice
|
|
67
|
+
*/
|
|
68
|
+
updateSize(totalSize) {
|
|
69
|
+
this.storeSize = totalSize;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = Index;
|