@gugananuvem/aws-local-simulator 1.0.15 → 1.0.16
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 +789 -594
- package/bin/aws-local-simulator.js +63 -63
- package/package.json +2 -2
- package/src/config/config-loader.js +114 -114
- package/src/config/default-config.js +68 -68
- package/src/config/env-loader.js +68 -68
- package/src/index.js +146 -146
- package/src/index.mjs +123 -123
- package/src/server.js +227 -227
- package/src/services/apigateway/index.js +75 -73
- package/src/services/apigateway/server.js +570 -507
- package/src/services/apigateway/simulator.js +1261 -1261
- package/src/services/athena/index.js +75 -75
- package/src/services/athena/server.js +101 -101
- package/src/services/athena/simulador.js +998 -998
- package/src/services/athena/simulator.js +346 -346
- package/src/services/cloudformation/index.js +106 -106
- package/src/services/cloudformation/server.js +417 -417
- package/src/services/cloudformation/simulador.js +1045 -1045
- package/src/services/cloudtrail/index.js +84 -84
- package/src/services/cloudtrail/server.js +235 -235
- package/src/services/cloudtrail/simulador.js +719 -719
- package/src/services/cloudwatch/index.js +84 -84
- package/src/services/cloudwatch/server.js +366 -366
- package/src/services/cloudwatch/simulador.js +1173 -1173
- package/src/services/cognito/index.js +79 -79
- package/src/services/cognito/server.js +301 -301
- package/src/services/cognito/simulator.js +1655 -1655
- package/src/services/config/index.js +96 -96
- package/src/services/config/server.js +215 -215
- package/src/services/config/simulador.js +1260 -1260
- package/src/services/dynamodb/index.js +74 -74
- package/src/services/dynamodb/server.js +125 -125
- package/src/services/dynamodb/simulator.js +630 -630
- package/src/services/ecs/index.js +65 -65
- package/src/services/ecs/server.js +235 -235
- package/src/services/ecs/simulator.js +844 -844
- package/src/services/eventbridge/index.js +89 -89
- package/src/services/eventbridge/server.js +209 -209
- package/src/services/eventbridge/simulator.js +684 -684
- package/src/services/index.js +45 -45
- package/src/services/kms/index.js +75 -75
- package/src/services/kms/server.js +67 -67
- package/src/services/kms/simulator.js +324 -324
- package/src/services/lambda/handler-loader.js +183 -183
- package/src/services/lambda/index.js +78 -78
- package/src/services/lambda/route-registry.js +274 -274
- package/src/services/lambda/server.js +145 -145
- package/src/services/lambda/simulator.js +199 -199
- package/src/services/parameter-store/index.js +80 -80
- package/src/services/parameter-store/server.js +50 -50
- package/src/services/parameter-store/simulator.js +201 -201
- package/src/services/s3/index.js +73 -73
- package/src/services/s3/server.js +329 -329
- package/src/services/s3/simulator.js +565 -565
- package/src/services/secret-manager/index.js +80 -80
- package/src/services/secret-manager/server.js +50 -50
- package/src/services/secret-manager/simulator.js +171 -171
- package/src/services/sns/index.js +89 -89
- package/src/services/sns/server.js +580 -580
- package/src/services/sns/simulator.js +1482 -1482
- package/src/services/sqs/index.js +98 -93
- package/src/services/sqs/server.js +349 -349
- package/src/services/sqs/simulator.js +441 -441
- package/src/services/sts/index.js +37 -37
- package/src/services/sts/server.js +144 -144
- package/src/services/sts/simulator.js +69 -69
- package/src/services/xray/index.js +83 -83
- package/src/services/xray/server.js +308 -308
- package/src/services/xray/simulador.js +994 -994
- package/src/template/aws-config-template.js +87 -87
- package/src/template/aws-config-template.mjs +90 -90
- package/src/template/config-template.json +203 -203
- package/src/utils/aws-config.js +91 -91
- package/src/utils/cloudtrail-audit.js +129 -129
- package/src/utils/local-store.js +83 -83
- package/src/utils/logger.js +59 -59
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @fileoverview EventBridge Service — entry point
|
|
5
|
-
* Porta padrão: 4010
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
const http = require('http');
|
|
9
|
-
const path = require('path');
|
|
10
|
-
const { EventBridgeSimulator } = require('./simulator');
|
|
11
|
-
const { createEventBridgeServer } = require('./server');
|
|
12
|
-
const LocalStore = require('../../utils/local-store');
|
|
13
|
-
|
|
14
|
-
class EventBridgeService {
|
|
15
|
-
constructor(config) {
|
|
16
|
-
this.config = config;
|
|
17
|
-
this.logger = require('../../utils/logger');
|
|
18
|
-
this.name = 'eventbridge';
|
|
19
|
-
this.port = config?.ports?.eventbridge || config?.services?.eventbridge?.port || 4010;
|
|
20
|
-
this.store = null;
|
|
21
|
-
this.simulator = null;
|
|
22
|
-
this.app = null;
|
|
23
|
-
this.server = null;
|
|
24
|
-
this.isRunning = false;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async initialize() {
|
|
28
|
-
this.logger.debug(`Inicializando EventBridge Service na porta ${this.port}...`);
|
|
29
|
-
const dataDir = process.env.AWS_LOCAL_SIMULATOR_DATA_DIR;
|
|
30
|
-
this.store = new LocalStore(path.join(dataDir, 'eventbridge'));
|
|
31
|
-
this.simulator = new EventBridgeSimulator(this.config, this.store, this.logger);
|
|
32
|
-
this.app = createEventBridgeServer(this.simulator, this.config, this.logger);
|
|
33
|
-
this.logger.debug('EventBridge Service inicializado');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
injectDependencies(server) {
|
|
37
|
-
if (!server) return;
|
|
38
|
-
const lambda = server.getService('lambda');
|
|
39
|
-
if (lambda) this.simulator.setLambdaService(lambda);
|
|
40
|
-
const sqs = server.getService('sqs');
|
|
41
|
-
if (sqs) this.simulator.setSqsService(sqs);
|
|
42
|
-
const sns = server.getService('sns');
|
|
43
|
-
if (sns) this.simulator.setSnsService(sns);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
async start() {
|
|
47
|
-
if (this.isRunning) return;
|
|
48
|
-
await this.store.ensureDir();
|
|
49
|
-
await this.simulator.load();
|
|
50
|
-
return new Promise((resolve, reject) => {
|
|
51
|
-
this.server = http.createServer(this.app);
|
|
52
|
-
this.server.on('error', reject);
|
|
53
|
-
this.server.listen(this.port, () => {
|
|
54
|
-
this.isRunning = true;
|
|
55
|
-
this.logger.debug(`EventBridge rodando na porta ${this.port}`);
|
|
56
|
-
resolve();
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async stop() {
|
|
62
|
-
if (!this.isRunning || !this.server) return;
|
|
63
|
-
return new Promise((resolve, reject) => {
|
|
64
|
-
this.server.close((err) => {
|
|
65
|
-
if (err) return reject(err);
|
|
66
|
-
this.isRunning = false;
|
|
67
|
-
resolve();
|
|
68
|
-
});
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async reset() {
|
|
73
|
-
await this.simulator.reset();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
getStatus() {
|
|
77
|
-
return {
|
|
78
|
-
running: this.isRunning,
|
|
79
|
-
port: this.port,
|
|
80
|
-
endpoint: `http://localhost:${this.port}`,
|
|
81
|
-
buses: this.simulator?.buses.size || 0,
|
|
82
|
-
rules: this.simulator?.rules.size || 0,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
getSimulator() { return this.simulator; }
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
module.exports = { EventBridgeService };
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @fileoverview EventBridge Service — entry point
|
|
5
|
+
* Porta padrão: 4010
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const http = require('http');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const { EventBridgeSimulator } = require('./simulator');
|
|
11
|
+
const { createEventBridgeServer } = require('./server');
|
|
12
|
+
const LocalStore = require('../../utils/local-store');
|
|
13
|
+
|
|
14
|
+
class EventBridgeService {
|
|
15
|
+
constructor(config) {
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.logger = require('../../utils/logger');
|
|
18
|
+
this.name = 'eventbridge';
|
|
19
|
+
this.port = config?.ports?.eventbridge || config?.services?.eventbridge?.port || 4010;
|
|
20
|
+
this.store = null;
|
|
21
|
+
this.simulator = null;
|
|
22
|
+
this.app = null;
|
|
23
|
+
this.server = null;
|
|
24
|
+
this.isRunning = false;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async initialize() {
|
|
28
|
+
this.logger.debug(`Inicializando EventBridge Service na porta ${this.port}...`);
|
|
29
|
+
const dataDir = process.env.AWS_LOCAL_SIMULATOR_DATA_DIR;
|
|
30
|
+
this.store = new LocalStore(path.join(dataDir, 'eventbridge'));
|
|
31
|
+
this.simulator = new EventBridgeSimulator(this.config, this.store, this.logger);
|
|
32
|
+
this.app = createEventBridgeServer(this.simulator, this.config, this.logger);
|
|
33
|
+
this.logger.debug('EventBridge Service inicializado');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
injectDependencies(server) {
|
|
37
|
+
if (!server) return;
|
|
38
|
+
const lambda = server.getService('lambda');
|
|
39
|
+
if (lambda) this.simulator.setLambdaService(lambda);
|
|
40
|
+
const sqs = server.getService('sqs');
|
|
41
|
+
if (sqs) this.simulator.setSqsService(sqs);
|
|
42
|
+
const sns = server.getService('sns');
|
|
43
|
+
if (sns) this.simulator.setSnsService(sns);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async start() {
|
|
47
|
+
if (this.isRunning) return;
|
|
48
|
+
await this.store.ensureDir();
|
|
49
|
+
await this.simulator.load();
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
this.server = http.createServer(this.app);
|
|
52
|
+
this.server.on('error', reject);
|
|
53
|
+
this.server.listen(this.port, () => {
|
|
54
|
+
this.isRunning = true;
|
|
55
|
+
this.logger.debug(`EventBridge rodando na porta ${this.port}`);
|
|
56
|
+
resolve();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async stop() {
|
|
62
|
+
if (!this.isRunning || !this.server) return;
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
this.server.close((err) => {
|
|
65
|
+
if (err) return reject(err);
|
|
66
|
+
this.isRunning = false;
|
|
67
|
+
resolve();
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async reset() {
|
|
73
|
+
await this.simulator.reset();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getStatus() {
|
|
77
|
+
return {
|
|
78
|
+
running: this.isRunning,
|
|
79
|
+
port: this.port,
|
|
80
|
+
endpoint: `http://localhost:${this.port}`,
|
|
81
|
+
buses: this.simulator?.buses.size || 0,
|
|
82
|
+
rules: this.simulator?.rules.size || 0,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
getSimulator() { return this.simulator; }
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = { EventBridgeService };
|
|
@@ -1,209 +1,209 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @fileoverview EventBridge HTTP Server
|
|
3
|
-
* Express server compatível com AWS EventBridge REST API (JSON)
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
'use strict';
|
|
7
|
-
|
|
8
|
-
const express = require('express');
|
|
9
|
-
const cors = require('cors');
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Create EventBridge Express application
|
|
13
|
-
* @param {Object} simulator - EventBridgeSimulator instance
|
|
14
|
-
* @param {Object} config - Service configuration
|
|
15
|
-
* @param {Object} logger - Logger instance
|
|
16
|
-
* @returns {express.Application}
|
|
17
|
-
*/
|
|
18
|
-
function createEventBridgeServer(simulator, config, logger) {
|
|
19
|
-
const app = express();
|
|
20
|
-
|
|
21
|
-
if (config.cors?.enabled !== false) {
|
|
22
|
-
app.use(cors({ origin: config.cors?.origin || '*' }));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
app.use(express.json({ limit: '10mb' }));
|
|
26
|
-
|
|
27
|
-
app.use((req, _res, next) => {
|
|
28
|
-
logger.debug('EventBridge', `${req.method} ${req.path}`);
|
|
29
|
-
next();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
// ==================== Event Buses ====================
|
|
33
|
-
|
|
34
|
-
app.post('/event-buses', async (req, res) => {
|
|
35
|
-
try {
|
|
36
|
-
const result = await simulator.createEventBus(req.body);
|
|
37
|
-
res.status(201).json(result);
|
|
38
|
-
} catch (err) { sendError(res, err); }
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
app.delete('/event-buses/:name', async (req, res) => {
|
|
42
|
-
try {
|
|
43
|
-
await simulator.deleteEventBus({ Name: req.params.name });
|
|
44
|
-
res.status(200).json({});
|
|
45
|
-
} catch (err) { sendError(res, err); }
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
app.get('/event-buses', (_req, res) => {
|
|
49
|
-
try {
|
|
50
|
-
const result = simulator.listEventBuses();
|
|
51
|
-
res.json(result);
|
|
52
|
-
} catch (err) { sendError(res, err); }
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
app.get('/event-buses/:name', (req, res) => {
|
|
56
|
-
try {
|
|
57
|
-
const result = simulator.describeEventBus({ Name: req.params.name });
|
|
58
|
-
res.json(result);
|
|
59
|
-
} catch (err) { sendError(res, err); }
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// ==================== Rules ====================
|
|
63
|
-
|
|
64
|
-
app.put('/rules', async (req, res) => {
|
|
65
|
-
try {
|
|
66
|
-
const result = await simulator.putRule(req.body);
|
|
67
|
-
res.json(result);
|
|
68
|
-
} catch (err) { sendError(res, err); }
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
app.delete('/rules/:name', async (req, res) => {
|
|
72
|
-
try {
|
|
73
|
-
await simulator.deleteRule({ Name: req.params.name, EventBusName: req.query.eventBusName });
|
|
74
|
-
res.status(200).json({});
|
|
75
|
-
} catch (err) { sendError(res, err); }
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
app.get('/rules', (req, res) => {
|
|
79
|
-
try {
|
|
80
|
-
const result = simulator.listRules({
|
|
81
|
-
EventBusName: req.query.EventBusName || 'default',
|
|
82
|
-
NamePrefix: req.query.NamePrefix,
|
|
83
|
-
Limit: req.query.Limit ? parseInt(req.query.Limit) : undefined
|
|
84
|
-
});
|
|
85
|
-
res.json(result);
|
|
86
|
-
} catch (err) { sendError(res, err); }
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
app.get('/rules/:name', (req, res) => {
|
|
90
|
-
try {
|
|
91
|
-
const result = simulator.describeRule({
|
|
92
|
-
Name: req.params.name,
|
|
93
|
-
EventBusName: req.query.EventBusName || 'default'
|
|
94
|
-
});
|
|
95
|
-
res.json(result);
|
|
96
|
-
} catch (err) { sendError(res, err); }
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
app.patch('/rules/:name/enable', async (req, res) => {
|
|
100
|
-
try {
|
|
101
|
-
await simulator.enableRule({ Name: req.params.name, EventBusName: req.query.EventBusName || 'default' });
|
|
102
|
-
res.json({ message: 'Rule enabled' });
|
|
103
|
-
} catch (err) { sendError(res, err); }
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
app.patch('/rules/:name/disable', async (req, res) => {
|
|
107
|
-
try {
|
|
108
|
-
await simulator.disableRule({ Name: req.params.name, EventBusName: req.query.EventBusName || 'default' });
|
|
109
|
-
res.json({ message: 'Rule disabled' });
|
|
110
|
-
} catch (err) { sendError(res, err); }
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// ==================== Targets ====================
|
|
114
|
-
|
|
115
|
-
app.put('/rules/:name/targets', async (req, res) => {
|
|
116
|
-
try {
|
|
117
|
-
const result = await simulator.putTargets({
|
|
118
|
-
Rule: req.params.name,
|
|
119
|
-
EventBusName: req.body.EventBusName || 'default',
|
|
120
|
-
Targets: req.body.Targets
|
|
121
|
-
});
|
|
122
|
-
res.json(result);
|
|
123
|
-
} catch (err) { sendError(res, err); }
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
app.delete('/rules/:name/targets', async (req, res) => {
|
|
127
|
-
try {
|
|
128
|
-
const result = await simulator.removeTargets({
|
|
129
|
-
Rule: req.params.name,
|
|
130
|
-
EventBusName: req.query.EventBusName || 'default',
|
|
131
|
-
Ids: req.body.Ids || []
|
|
132
|
-
});
|
|
133
|
-
res.json(result);
|
|
134
|
-
} catch (err) { sendError(res, err); }
|
|
135
|
-
});
|
|
136
|
-
|
|
137
|
-
app.get('/rules/:name/targets', (req, res) => {
|
|
138
|
-
try {
|
|
139
|
-
const result = simulator.listTargetsByRule({
|
|
140
|
-
Rule: req.params.name,
|
|
141
|
-
EventBusName: req.query.EventBusName || 'default'
|
|
142
|
-
});
|
|
143
|
-
res.json(result);
|
|
144
|
-
} catch (err) { sendError(res, err); }
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// ==================== PutEvents ====================
|
|
148
|
-
|
|
149
|
-
app.post('/events', async (req, res) => {
|
|
150
|
-
try {
|
|
151
|
-
const result = await simulator.putEvents(req.body);
|
|
152
|
-
res.json(result);
|
|
153
|
-
} catch (err) { sendError(res, err); }
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
// ==================== Admin ====================
|
|
157
|
-
|
|
158
|
-
app.get('/__admin/health', (_req, res) => {
|
|
159
|
-
res.json({
|
|
160
|
-
status: 'healthy',
|
|
161
|
-
service: 'eventbridge',
|
|
162
|
-
buses: simulator.buses.size,
|
|
163
|
-
rules: simulator.rules.size,
|
|
164
|
-
recentEvents: simulator.eventArchive.length,
|
|
165
|
-
timestamp: new Date().toISOString()
|
|
166
|
-
});
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
app.get('/__admin/buses', (_req, res) => {
|
|
170
|
-
res.json({ buses: Array.from(simulator.buses.values()) });
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
app.get('/__admin/rules', (_req, res) => {
|
|
174
|
-
res.json({ rules: Array.from(simulator.rules.values()) });
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
app.get('/__admin/events', (req, res) => {
|
|
178
|
-
const limit = parseInt(req.query.limit) || 50;
|
|
179
|
-
const events = simulator.eventArchive.slice(-limit);
|
|
180
|
-
res.json({ events, total: simulator.eventArchive.length });
|
|
181
|
-
});
|
|
182
|
-
|
|
183
|
-
app.post('/__admin/reset', async (_req, res) => {
|
|
184
|
-
await simulator.reset();
|
|
185
|
-
res.json({ message: 'EventBridge data reset' });
|
|
186
|
-
});
|
|
187
|
-
|
|
188
|
-
app.use((_req, res) => res.status(404).json({ message: 'Not Found' }));
|
|
189
|
-
|
|
190
|
-
return app;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Send error response
|
|
195
|
-
* @param {express.Response} res
|
|
196
|
-
* @param {Error} err
|
|
197
|
-
*/
|
|
198
|
-
function sendError(res, err) {
|
|
199
|
-
const statusMap = {
|
|
200
|
-
ValidationException: 400,
|
|
201
|
-
ResourceNotFoundException: 404,
|
|
202
|
-
ResourceAlreadyExistsException: 409,
|
|
203
|
-
InvalidEventPatternException: 400
|
|
204
|
-
};
|
|
205
|
-
const status = statusMap[err.code] || statusMap[err.__type] || 500;
|
|
206
|
-
res.status(status).json({ message: err.message, __type: err.__type || err.code });
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
module.exports = { createEventBridgeServer };
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview EventBridge HTTP Server
|
|
3
|
+
* Express server compatível com AWS EventBridge REST API (JSON)
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
const express = require('express');
|
|
9
|
+
const cors = require('cors');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Create EventBridge Express application
|
|
13
|
+
* @param {Object} simulator - EventBridgeSimulator instance
|
|
14
|
+
* @param {Object} config - Service configuration
|
|
15
|
+
* @param {Object} logger - Logger instance
|
|
16
|
+
* @returns {express.Application}
|
|
17
|
+
*/
|
|
18
|
+
function createEventBridgeServer(simulator, config, logger) {
|
|
19
|
+
const app = express();
|
|
20
|
+
|
|
21
|
+
if (config.cors?.enabled !== false) {
|
|
22
|
+
app.use(cors({ origin: config.cors?.origin || '*' }));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
app.use(express.json({ limit: '10mb' }));
|
|
26
|
+
|
|
27
|
+
app.use((req, _res, next) => {
|
|
28
|
+
logger.debug('EventBridge', `${req.method} ${req.path}`);
|
|
29
|
+
next();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// ==================== Event Buses ====================
|
|
33
|
+
|
|
34
|
+
app.post('/event-buses', async (req, res) => {
|
|
35
|
+
try {
|
|
36
|
+
const result = await simulator.createEventBus(req.body);
|
|
37
|
+
res.status(201).json(result);
|
|
38
|
+
} catch (err) { sendError(res, err); }
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
app.delete('/event-buses/:name', async (req, res) => {
|
|
42
|
+
try {
|
|
43
|
+
await simulator.deleteEventBus({ Name: req.params.name });
|
|
44
|
+
res.status(200).json({});
|
|
45
|
+
} catch (err) { sendError(res, err); }
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
app.get('/event-buses', (_req, res) => {
|
|
49
|
+
try {
|
|
50
|
+
const result = simulator.listEventBuses();
|
|
51
|
+
res.json(result);
|
|
52
|
+
} catch (err) { sendError(res, err); }
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
app.get('/event-buses/:name', (req, res) => {
|
|
56
|
+
try {
|
|
57
|
+
const result = simulator.describeEventBus({ Name: req.params.name });
|
|
58
|
+
res.json(result);
|
|
59
|
+
} catch (err) { sendError(res, err); }
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// ==================== Rules ====================
|
|
63
|
+
|
|
64
|
+
app.put('/rules', async (req, res) => {
|
|
65
|
+
try {
|
|
66
|
+
const result = await simulator.putRule(req.body);
|
|
67
|
+
res.json(result);
|
|
68
|
+
} catch (err) { sendError(res, err); }
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
app.delete('/rules/:name', async (req, res) => {
|
|
72
|
+
try {
|
|
73
|
+
await simulator.deleteRule({ Name: req.params.name, EventBusName: req.query.eventBusName });
|
|
74
|
+
res.status(200).json({});
|
|
75
|
+
} catch (err) { sendError(res, err); }
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
app.get('/rules', (req, res) => {
|
|
79
|
+
try {
|
|
80
|
+
const result = simulator.listRules({
|
|
81
|
+
EventBusName: req.query.EventBusName || 'default',
|
|
82
|
+
NamePrefix: req.query.NamePrefix,
|
|
83
|
+
Limit: req.query.Limit ? parseInt(req.query.Limit) : undefined
|
|
84
|
+
});
|
|
85
|
+
res.json(result);
|
|
86
|
+
} catch (err) { sendError(res, err); }
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
app.get('/rules/:name', (req, res) => {
|
|
90
|
+
try {
|
|
91
|
+
const result = simulator.describeRule({
|
|
92
|
+
Name: req.params.name,
|
|
93
|
+
EventBusName: req.query.EventBusName || 'default'
|
|
94
|
+
});
|
|
95
|
+
res.json(result);
|
|
96
|
+
} catch (err) { sendError(res, err); }
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
app.patch('/rules/:name/enable', async (req, res) => {
|
|
100
|
+
try {
|
|
101
|
+
await simulator.enableRule({ Name: req.params.name, EventBusName: req.query.EventBusName || 'default' });
|
|
102
|
+
res.json({ message: 'Rule enabled' });
|
|
103
|
+
} catch (err) { sendError(res, err); }
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
app.patch('/rules/:name/disable', async (req, res) => {
|
|
107
|
+
try {
|
|
108
|
+
await simulator.disableRule({ Name: req.params.name, EventBusName: req.query.EventBusName || 'default' });
|
|
109
|
+
res.json({ message: 'Rule disabled' });
|
|
110
|
+
} catch (err) { sendError(res, err); }
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// ==================== Targets ====================
|
|
114
|
+
|
|
115
|
+
app.put('/rules/:name/targets', async (req, res) => {
|
|
116
|
+
try {
|
|
117
|
+
const result = await simulator.putTargets({
|
|
118
|
+
Rule: req.params.name,
|
|
119
|
+
EventBusName: req.body.EventBusName || 'default',
|
|
120
|
+
Targets: req.body.Targets
|
|
121
|
+
});
|
|
122
|
+
res.json(result);
|
|
123
|
+
} catch (err) { sendError(res, err); }
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
app.delete('/rules/:name/targets', async (req, res) => {
|
|
127
|
+
try {
|
|
128
|
+
const result = await simulator.removeTargets({
|
|
129
|
+
Rule: req.params.name,
|
|
130
|
+
EventBusName: req.query.EventBusName || 'default',
|
|
131
|
+
Ids: req.body.Ids || []
|
|
132
|
+
});
|
|
133
|
+
res.json(result);
|
|
134
|
+
} catch (err) { sendError(res, err); }
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
app.get('/rules/:name/targets', (req, res) => {
|
|
138
|
+
try {
|
|
139
|
+
const result = simulator.listTargetsByRule({
|
|
140
|
+
Rule: req.params.name,
|
|
141
|
+
EventBusName: req.query.EventBusName || 'default'
|
|
142
|
+
});
|
|
143
|
+
res.json(result);
|
|
144
|
+
} catch (err) { sendError(res, err); }
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// ==================== PutEvents ====================
|
|
148
|
+
|
|
149
|
+
app.post('/events', async (req, res) => {
|
|
150
|
+
try {
|
|
151
|
+
const result = await simulator.putEvents(req.body);
|
|
152
|
+
res.json(result);
|
|
153
|
+
} catch (err) { sendError(res, err); }
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// ==================== Admin ====================
|
|
157
|
+
|
|
158
|
+
app.get('/__admin/health', (_req, res) => {
|
|
159
|
+
res.json({
|
|
160
|
+
status: 'healthy',
|
|
161
|
+
service: 'eventbridge',
|
|
162
|
+
buses: simulator.buses.size,
|
|
163
|
+
rules: simulator.rules.size,
|
|
164
|
+
recentEvents: simulator.eventArchive.length,
|
|
165
|
+
timestamp: new Date().toISOString()
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
app.get('/__admin/buses', (_req, res) => {
|
|
170
|
+
res.json({ buses: Array.from(simulator.buses.values()) });
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
app.get('/__admin/rules', (_req, res) => {
|
|
174
|
+
res.json({ rules: Array.from(simulator.rules.values()) });
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
app.get('/__admin/events', (req, res) => {
|
|
178
|
+
const limit = parseInt(req.query.limit) || 50;
|
|
179
|
+
const events = simulator.eventArchive.slice(-limit);
|
|
180
|
+
res.json({ events, total: simulator.eventArchive.length });
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
app.post('/__admin/reset', async (_req, res) => {
|
|
184
|
+
await simulator.reset();
|
|
185
|
+
res.json({ message: 'EventBridge data reset' });
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
app.use((_req, res) => res.status(404).json({ message: 'Not Found' }));
|
|
189
|
+
|
|
190
|
+
return app;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Send error response
|
|
195
|
+
* @param {express.Response} res
|
|
196
|
+
* @param {Error} err
|
|
197
|
+
*/
|
|
198
|
+
function sendError(res, err) {
|
|
199
|
+
const statusMap = {
|
|
200
|
+
ValidationException: 400,
|
|
201
|
+
ResourceNotFoundException: 404,
|
|
202
|
+
ResourceAlreadyExistsException: 409,
|
|
203
|
+
InvalidEventPatternException: 400
|
|
204
|
+
};
|
|
205
|
+
const status = statusMap[err.code] || statusMap[err.__type] || 500;
|
|
206
|
+
res.status(status).json({ message: err.message, __type: err.__type || err.code });
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = { createEventBridgeServer };
|