aws-apigw-ws-emulator 0.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 m1heng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,287 @@
1
+ # AWS WebSocket Gateway Local
2
+
3
+ A lightweight local emulator for **AWS API Gateway WebSocket** with HTTP integration support.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/aws-apigw-ws-emulator.svg)](https://www.npmjs.com/package/aws-apigw-ws-emulator)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## Why?
9
+
10
+ AWS API Gateway WebSocket supports HTTP integration, allowing you to route WebSocket events to your HTTP backend. However, there's no good open-source solution for local development:
11
+
12
+ - **LocalStack**: WebSocket support requires Pro (paid) version
13
+ - **serverless-offline**: Only supports Lambda integration, not HTTP
14
+
15
+ This tool fills that gap - a simple, standalone emulator that:
16
+ - Accepts WebSocket connections from your frontend
17
+ - Forwards `$connect`, `$disconnect`, `$default` events to your HTTP backend
18
+ - Provides `/@connections/{connectionId}` endpoint for `postToConnection`
19
+
20
+ ## Quick Start
21
+
22
+ ### Using npx (no installation)
23
+
24
+ ```bash
25
+ npx aws-apigw-ws-emulator --backend http://localhost:8080
26
+ ```
27
+
28
+ ### Using npm
29
+
30
+ ```bash
31
+ npm install -g aws-apigw-ws-emulator
32
+ aws-apigw-ws-emulator --backend http://localhost:8080
33
+ ```
34
+
35
+ ### Using Docker
36
+
37
+ ```bash
38
+ docker run -p 3001:3001 ghcr.io/m1heng/aws-apigw-ws-emulator
39
+ ```
40
+
41
+ ## Architecture
42
+
43
+ ```
44
+ ┌──────────────┐ WebSocket ┌─────────────────────┐ HTTP POST ┌──────────────────┐
45
+ │ Frontend │◄──────────────────►│ aws-ws-gateway- │───────────────────►│ Your Backend │
46
+ │ │ ws://localhost │ local (:3001) │ │ (:8080) │
47
+ │ │ :3001?token=... │ │ /api/.../connect │ │
48
+ └──────────────┘ └──────────┬──────────┘ /api/.../default └────────┬─────────┘
49
+ ▲ │ /api/.../disconnect │
50
+ │ │ │
51
+ │ │◄───────────────────────────────────────┘
52
+ │ │ POST /@connections/{connectionId}
53
+ └───────────────────────────────────────┘ (postToConnection)
54
+ ```
55
+
56
+ ## Usage
57
+
58
+ ### CLI Options
59
+
60
+ ```bash
61
+ aws-apigw-ws-emulator [options]
62
+
63
+ Options:
64
+ -p, --port <port> WebSocket server port (default: 3001)
65
+ -s, --stage <stage> API stage name (default: local)
66
+ --idle-timeout <seconds> Idle timeout in seconds (default: 600)
67
+ --hard-timeout <seconds> Hard timeout in seconds (default: 7200)
68
+ -c, --config <file> Config file (YAML or JSON)
69
+ -v, --verbose Enable verbose logging
70
+ -h, --help Display help
71
+ ```
72
+
73
+ ### Config File
74
+
75
+ Create `gateway.config.yaml`:
76
+
77
+ ```yaml
78
+ port: 3001
79
+ stage: local
80
+
81
+ routes:
82
+ $connect:
83
+ uri: http://localhost:8080/ws/connect
84
+ $disconnect:
85
+ uri: http://localhost:8080/ws/disconnect
86
+ $default:
87
+ uri: http://localhost:8080/ws/default
88
+
89
+ idleTimeout: 600
90
+ hardTimeout: 7200
91
+ verbose: false
92
+ ```
93
+
94
+ Run with config:
95
+
96
+ ```bash
97
+ aws-apigw-ws-emulator -c gateway.config.yaml
98
+ ```
99
+
100
+ ## Integration Guide
101
+
102
+ ### Backend Requirements
103
+
104
+ Your backend receives AWS Lambda-style WebSocket events via HTTP POST:
105
+
106
+ ```typescript
107
+ interface AWSWebSocketEvent {
108
+ requestContext: {
109
+ routeKey: '$connect' | '$disconnect' | '$default' | string;
110
+ eventType: 'CONNECT' | 'DISCONNECT' | 'MESSAGE';
111
+ connectionId: string;
112
+ connectedAt: number;
113
+ domainName: string;
114
+ stage: string;
115
+ apiId: string;
116
+ requestId: string;
117
+ identity: { sourceIp: string; userAgent?: string };
118
+ // MESSAGE only
119
+ messageId?: string;
120
+ // DISCONNECT only
121
+ disconnectStatusCode?: number;
122
+ disconnectReason?: string;
123
+ };
124
+ headers?: Record<string, string>;
125
+ queryStringParameters?: Record<string, string> | null;
126
+ body: string | null;
127
+ isBase64Encoded: boolean;
128
+ }
129
+ ```
130
+
131
+ Example request to your `$connect` endpoint:
132
+
133
+ ```json
134
+ {
135
+ "requestContext": {
136
+ "routeKey": "$connect",
137
+ "eventType": "CONNECT",
138
+ "connectionId": "abc123xyz456=",
139
+ "connectedAt": 1704067200000,
140
+ "domainName": "localhost:3001",
141
+ "stage": "local",
142
+ "apiId": "local",
143
+ "requestId": "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",
144
+ "identity": { "sourceIp": "127.0.0.1", "userAgent": "..." }
145
+ },
146
+ "headers": { "origin": "http://localhost:3000", ... },
147
+ "queryStringParameters": { "token": "xxx", "conversationId": "123" },
148
+ "body": null,
149
+ "isBase64Encoded": false
150
+ }
151
+ ```
152
+
153
+ ### Sending Messages to Clients (postToConnection)
154
+
155
+ Use the Management API to send messages back to clients:
156
+
157
+ ```bash
158
+ # Using curl
159
+ curl -X POST http://localhost:3001/@connections/{connectionId} \
160
+ -H "Content-Type: application/json" \
161
+ -d '{"type": "message", "data": "Hello!"}'
162
+ ```
163
+
164
+ ```java
165
+ // Using AWS SDK (Java)
166
+ ApiGatewayManagementApiClient client = ApiGatewayManagementApiClient.builder()
167
+ .endpointOverride(URI.create("http://localhost:3001"))
168
+ .region(Region.US_WEST_1)
169
+ .credentialsProvider(StaticCredentialsProvider.create(
170
+ AwsBasicCredentials.create("test", "test")))
171
+ .build();
172
+
173
+ client.postToConnection(PostToConnectionRequest.builder()
174
+ .connectionId(connectionId)
175
+ .data(SdkBytes.fromUtf8String("{\"message\": \"Hello!\"}"))
176
+ .build());
177
+ ```
178
+
179
+ ```javascript
180
+ // Using AWS SDK (JavaScript)
181
+ const client = new ApiGatewayManagementApiClient({
182
+ endpoint: 'http://localhost:3001',
183
+ region: 'us-west-1',
184
+ credentials: { accessKeyId: 'test', secretAccessKey: 'test' },
185
+ });
186
+
187
+ await client.send(new PostToConnectionCommand({
188
+ ConnectionId: connectionId,
189
+ Data: Buffer.from(JSON.stringify({ message: 'Hello!' })),
190
+ }));
191
+ ```
192
+
193
+ ### Frontend Connection
194
+
195
+ ```javascript
196
+ // Same code works for both local and production!
197
+ const wsUrl = process.env.NEXT_PUBLIC_WS_URL; // ws://localhost:3001 or wss://xxx.amazonaws.com
198
+
199
+ const ws = new WebSocket(`${wsUrl}?token=${token}&conversationId=${conversationId}`);
200
+
201
+ ws.onmessage = (event) => {
202
+ console.log('Received:', event.data);
203
+ };
204
+ ```
205
+
206
+ ### Environment Configuration
207
+
208
+ Use the same codebase for local and production:
209
+
210
+ ```yaml
211
+ # application.yml (Spring Boot)
212
+ aws:
213
+ apigateway:
214
+ callback: ${AWS_APIGATEWAY_CALLBACK:https://xxx.execute-api.us-west-1.amazonaws.com/prod}
215
+ ```
216
+
217
+ ```bash
218
+ # Local development
219
+ AWS_APIGATEWAY_CALLBACK=http://localhost:3001 ./mvnw spring-boot:run
220
+
221
+ # Production
222
+ AWS_APIGATEWAY_CALLBACK=https://xxx.execute-api.us-west-1.amazonaws.com/prod java -jar app.jar
223
+ ```
224
+
225
+ ## API Reference
226
+
227
+ ### Management API
228
+
229
+ | Method | Path | Description |
230
+ |--------|------|-------------|
231
+ | POST | `/@connections/{connectionId}` | Send message to connection (postToConnection) |
232
+ | GET | `/@connections/{connectionId}` | Get connection info |
233
+ | DELETE | `/@connections/{connectionId}` | Close connection |
234
+ | GET | `/health` | Health check |
235
+
236
+ ### Health Check Response
237
+
238
+ ```json
239
+ {
240
+ "status": "ok",
241
+ "connections": 5,
242
+ "uptime": 3600.123
243
+ }
244
+ ```
245
+
246
+ ## Comparison with Alternatives
247
+
248
+ | Feature | aws-apigw-ws-emulator | LocalStack | serverless-offline |
249
+ |---------|---------------------|------------|-------------------|
250
+ | HTTP Integration | ✅ | ✅ (Pro only) | ❌ |
251
+ | Lambda Integration | ❌ | ✅ | ✅ |
252
+ | Free | ✅ | ❌ ($35/mo) | ✅ |
253
+ | Standalone | ✅ | ✅ | ❌ (needs SF) |
254
+ | postToConnection | ✅ | ✅ | ✅ |
255
+ | Easy Setup | ✅ One command | ⚠️ Complex | ⚠️ Complex |
256
+
257
+ ## Programmatic Usage
258
+
259
+ ```typescript
260
+ import { AWSWebSocketGateway } from 'aws-apigw-ws-emulator';
261
+
262
+ const gateway = new AWSWebSocketGateway({
263
+ port: 3001,
264
+ routes: {
265
+ $connect: { uri: 'http://localhost:8080/ws/connect' },
266
+ $disconnect: { uri: 'http://localhost:8080/ws/disconnect' },
267
+ $default: { uri: 'http://localhost:8080/ws/default' },
268
+ },
269
+ verbose: true,
270
+ });
271
+
272
+ await gateway.start();
273
+
274
+ // Get connection count
275
+ console.log(`Active connections: ${gateway.getConnectionCount()}`);
276
+
277
+ // Graceful shutdown
278
+ await gateway.stop();
279
+ ```
280
+
281
+ ## Contributing
282
+
283
+ Contributions are welcome! Please feel free to submit a Pull Request.
284
+
285
+ ## License
286
+
287
+ MIT License - see [LICENSE](LICENSE) for details.
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const yaml_1 = require("yaml");
8
+ const server_1 = require("./server");
9
+ const types_1 = require("./types");
10
+ const logger_1 = require("./logger");
11
+ const packageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, '../package.json'), 'utf-8'));
12
+ const program = new commander_1.Command();
13
+ program
14
+ .name('aws-apigw-ws-emulator')
15
+ .description('Local emulator for AWS API Gateway WebSocket with HTTP integration')
16
+ .version(packageJson.version)
17
+ .option('-p, --port <port>', 'WebSocket server port', String(types_1.DEFAULT_CONFIG.port))
18
+ .option('-s, --stage <stage>', 'API stage name', types_1.DEFAULT_CONFIG.stage)
19
+ .option('--idle-timeout <seconds>', 'Idle timeout in seconds', String(types_1.DEFAULT_CONFIG.idleTimeout))
20
+ .option('--hard-timeout <seconds>', 'Hard timeout in seconds', String(types_1.DEFAULT_CONFIG.hardTimeout))
21
+ .option('-c, --config <file>', 'Config file (YAML or JSON)')
22
+ .option('-v, --verbose', 'Enable verbose logging', false)
23
+ .action(async (options) => {
24
+ let fileConfig = {};
25
+ // Load config file if specified
26
+ if (options.config && (0, fs_1.existsSync)(options.config)) {
27
+ try {
28
+ const content = (0, fs_1.readFileSync)(options.config, 'utf-8');
29
+ if (options.config.endsWith('.yaml') || options.config.endsWith('.yml')) {
30
+ fileConfig = (0, yaml_1.parse)(content);
31
+ }
32
+ else {
33
+ fileConfig = JSON.parse(content);
34
+ }
35
+ logger_1.logger.info(`Loaded config from ${options.config}`);
36
+ }
37
+ catch (error) {
38
+ logger_1.logger.error(`Failed to load config file: ${error.message}`);
39
+ process.exit(1);
40
+ }
41
+ }
42
+ // Build final config: defaults <- file <- CLI
43
+ const finalConfig = {
44
+ ...types_1.DEFAULT_CONFIG,
45
+ ...fileConfig,
46
+ };
47
+ // CLI overrides (only if explicitly provided)
48
+ if (options.port !== String(types_1.DEFAULT_CONFIG.port)) {
49
+ finalConfig.port = parseInt(options.port, 10);
50
+ }
51
+ if (options.stage !== types_1.DEFAULT_CONFIG.stage) {
52
+ finalConfig.stage = options.stage;
53
+ }
54
+ if (options.idleTimeout !== String(types_1.DEFAULT_CONFIG.idleTimeout)) {
55
+ finalConfig.idleTimeout = parseInt(options.idleTimeout, 10);
56
+ }
57
+ if (options.hardTimeout !== String(types_1.DEFAULT_CONFIG.hardTimeout)) {
58
+ finalConfig.hardTimeout = parseInt(options.hardTimeout, 10);
59
+ }
60
+ if (options.verbose) {
61
+ finalConfig.verbose = true;
62
+ }
63
+ const gateway = new server_1.AWSWebSocketGateway(finalConfig);
64
+ // Graceful shutdown
65
+ const shutdown = async () => {
66
+ logger_1.logger.info('Shutting down...');
67
+ await gateway.stop();
68
+ process.exit(0);
69
+ };
70
+ process.on('SIGINT', shutdown);
71
+ process.on('SIGTERM', shutdown);
72
+ try {
73
+ await gateway.start();
74
+ }
75
+ catch (error) {
76
+ logger_1.logger.error(`Failed to start server: ${error.message}`);
77
+ process.exit(1);
78
+ }
79
+ });
80
+ program.parse();
81
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export { AWSWebSocketGateway } from './server';
2
+ export { GatewayConfig, Connection, RouteIntegration, AWSWebSocketEvent, AWSRequestContext, AWSIdentity, DEFAULT_CONFIG, } from './types';
3
+ export { logger, Logger } from './logger';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,EACL,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Logger = exports.logger = exports.DEFAULT_CONFIG = exports.AWSWebSocketGateway = void 0;
4
+ // Main exports for programmatic usage
5
+ var server_1 = require("./server");
6
+ Object.defineProperty(exports, "AWSWebSocketGateway", { enumerable: true, get: function () { return server_1.AWSWebSocketGateway; } });
7
+ var types_1 = require("./types");
8
+ Object.defineProperty(exports, "DEFAULT_CONFIG", { enumerable: true, get: function () { return types_1.DEFAULT_CONFIG; } });
9
+ var logger_1 = require("./logger");
10
+ Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return logger_1.logger; } });
11
+ Object.defineProperty(exports, "Logger", { enumerable: true, get: function () { return logger_1.Logger; } });
12
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,sCAAsC;AACtC,mCAA+C;AAAtC,6GAAA,mBAAmB,OAAA;AAC5B,iCAQiB;AADf,uGAAA,cAAc,OAAA;AAEhB,mCAA0C;AAAjC,gGAAA,MAAM,OAAA;AAAE,gGAAA,MAAM,OAAA"}
@@ -0,0 +1,18 @@
1
+ export declare class Logger {
2
+ private verbose;
3
+ constructor(verbose?: boolean);
4
+ setVerbose(verbose: boolean): void;
5
+ info(message: string, ...args: unknown[]): void;
6
+ success(message: string, ...args: unknown[]): void;
7
+ warn(message: string, ...args: unknown[]): void;
8
+ error(message: string, ...args: unknown[]): void;
9
+ debug(message: string, ...args: unknown[]): void;
10
+ ws(action: string, connectionId: string, detail?: string): void;
11
+ http(method: string, path: string, status: number): void;
12
+ banner(config: {
13
+ port: number;
14
+ stage: string;
15
+ }): void;
16
+ }
17
+ export declare const logger: Logger;
18
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAEA,qBAAa,MAAM;IACjB,OAAO,CAAC,OAAO,CAAU;gBAEb,OAAO,UAAQ;IAI3B,UAAU,CAAC,OAAO,EAAE,OAAO;IAI3B,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE;IAIxC,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE;IAI3C,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE;IAIxC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE;IAIzC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE;IAMzC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAUxD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IASjD,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE;CAa/C;AAED,eAAO,MAAM,MAAM,QAAe,CAAC"}
package/dist/logger.js ADDED
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.logger = exports.Logger = void 0;
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ class Logger {
9
+ verbose;
10
+ constructor(verbose = false) {
11
+ this.verbose = verbose;
12
+ }
13
+ setVerbose(verbose) {
14
+ this.verbose = verbose;
15
+ }
16
+ info(message, ...args) {
17
+ console.log(chalk_1.default.blue('[INFO]'), message, ...args);
18
+ }
19
+ success(message, ...args) {
20
+ console.log(chalk_1.default.green('[OK]'), message, ...args);
21
+ }
22
+ warn(message, ...args) {
23
+ console.log(chalk_1.default.yellow('[WARN]'), message, ...args);
24
+ }
25
+ error(message, ...args) {
26
+ console.log(chalk_1.default.red('[ERROR]'), message, ...args);
27
+ }
28
+ debug(message, ...args) {
29
+ if (this.verbose) {
30
+ console.log(chalk_1.default.gray('[DEBUG]'), message, ...args);
31
+ }
32
+ }
33
+ ws(action, connectionId, detail) {
34
+ const id = chalk_1.default.cyan(connectionId.slice(0, 12));
35
+ const act = chalk_1.default.magenta(`[${action}]`);
36
+ if (detail) {
37
+ console.log(act, id, chalk_1.default.gray(detail));
38
+ }
39
+ else {
40
+ console.log(act, id);
41
+ }
42
+ }
43
+ http(method, path, status) {
44
+ const statusColor = status < 400 ? chalk_1.default.green : chalk_1.default.red;
45
+ console.log(chalk_1.default.yellow(`[${method}]`), path, statusColor(status));
46
+ }
47
+ banner(config) {
48
+ console.log('');
49
+ console.log(chalk_1.default.bold.cyan('╔══════════════════════════════════════════════════════════════╗'));
50
+ console.log(chalk_1.default.bold.cyan('║') + chalk_1.default.bold.white(' AWS API Gateway WebSocket - Local Emulator ') + chalk_1.default.bold.cyan('║'));
51
+ console.log(chalk_1.default.bold.cyan('╠══════════════════════════════════════════════════════════════╣'));
52
+ console.log(chalk_1.default.bold.cyan('║') + ` WebSocket: ${chalk_1.default.green(`ws://localhost:${config.port}`)} ` + chalk_1.default.bold.cyan('║'));
53
+ console.log(chalk_1.default.bold.cyan('║') + ` Management: ${chalk_1.default.green(`http://localhost:${config.port}/@connections/{id}`)} ` + chalk_1.default.bold.cyan('║'));
54
+ console.log(chalk_1.default.bold.cyan('║') + ` Stage: ${chalk_1.default.yellow(config.stage)} ` + chalk_1.default.bold.cyan('║'));
55
+ console.log(chalk_1.default.bold.cyan('╠══════════════════════════════════════════════════════════════╣'));
56
+ console.log(chalk_1.default.bold.cyan('║') + chalk_1.default.gray(' Connect: ws://localhost:' + config.port + '?token=xxx') + ' ' + chalk_1.default.bold.cyan('║'));
57
+ console.log(chalk_1.default.bold.cyan('╚══════════════════════════════════════════════════════════════╝'));
58
+ console.log('');
59
+ }
60
+ }
61
+ exports.Logger = Logger;
62
+ exports.logger = new Logger();
63
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import { GatewayConfig } from './types';
2
+ export declare class AWSWebSocketGateway {
3
+ private config;
4
+ private httpServer;
5
+ private wss;
6
+ private connections;
7
+ private timeoutTimers;
8
+ constructor(config?: Partial<GatewayConfig>);
9
+ private handleHttpRequest;
10
+ private handleManagementApi;
11
+ private handleConnection;
12
+ private selectRoute;
13
+ private buildRequestContext;
14
+ private buildMultiValueHeaders;
15
+ private buildLambdaEvent;
16
+ private formatRequestTime;
17
+ private callBackend;
18
+ private getEventType;
19
+ private setupTimeouts;
20
+ private resetIdleTimeout;
21
+ private clearTimeouts;
22
+ private generateConnectionId;
23
+ private generateRequestId;
24
+ private generateMessageId;
25
+ start(): Promise<void>;
26
+ stop(): Promise<void>;
27
+ getConnectionCount(): number;
28
+ }
29
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,aAAa,EAKd,MAAM,SAAS,CAAC;AAQjB,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,GAAG,CAAkB;IAC7B,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAA0C;gBAEnD,MAAM,GAAE,OAAO,CAAC,aAAa,CAAM;IAiB/C,OAAO,CAAC,iBAAiB;IA+BzB,OAAO,CAAC,mBAAmB;IAyE3B,OAAO,CAAC,gBAAgB;IAyFxB,OAAO,CAAC,WAAW;IAiCnB,OAAO,CAAC,mBAAmB;IA0C3B,OAAO,CAAC,sBAAsB;IAQ9B,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,iBAAiB;YA2BX,WAAW;IA0CzB,OAAO,CAAC,YAAY;IAepB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,gBAAgB;IAkBxB,OAAO,CAAC,aAAa;IAarB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,iBAAiB;IAQzB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAYtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBrB,kBAAkB,IAAI,MAAM;CAG7B"}
package/dist/server.js ADDED
@@ -0,0 +1,425 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.AWSWebSocketGateway = void 0;
7
+ const http_1 = __importDefault(require("http"));
8
+ const url_1 = require("url");
9
+ const ws_1 = require("ws");
10
+ const types_1 = require("./types");
11
+ const logger_1 = require("./logger");
12
+ class AWSWebSocketGateway {
13
+ config;
14
+ httpServer;
15
+ wss;
16
+ connections = new Map();
17
+ timeoutTimers = new Map();
18
+ constructor(config = {}) {
19
+ this.config = { ...types_1.DEFAULT_CONFIG, ...config };
20
+ // Set domainName if not specified
21
+ if (!this.config.domainName) {
22
+ this.config.domainName = `localhost:${this.config.port}`;
23
+ }
24
+ logger_1.logger.setVerbose(this.config.verbose);
25
+ this.httpServer = http_1.default.createServer(this.handleHttpRequest.bind(this));
26
+ this.wss = new ws_1.WebSocketServer({ server: this.httpServer });
27
+ this.wss.on('connection', this.handleConnection.bind(this));
28
+ }
29
+ // ============================================================================
30
+ // HTTP Request Handling (Management API)
31
+ // ============================================================================
32
+ handleHttpRequest(req, res) {
33
+ const url = new url_1.URL(req.url || '/', `http://localhost:${this.config.port}`);
34
+ const method = req.method || 'GET';
35
+ // Health check
36
+ if (method === 'GET' && url.pathname === '/health') {
37
+ res.writeHead(200, { 'Content-Type': 'application/json' });
38
+ res.end(JSON.stringify({
39
+ status: 'ok',
40
+ connections: this.connections.size,
41
+ uptime: process.uptime(),
42
+ }));
43
+ logger_1.logger.http('GET', '/health', 200);
44
+ return;
45
+ }
46
+ // Management API: /@connections/{connectionId}
47
+ const match = url.pathname.match(/^\/@connections\/(.+)$/);
48
+ if (match) {
49
+ const connectionId = decodeURIComponent(match[1]);
50
+ this.handleManagementApi(method, connectionId, req, res);
51
+ return;
52
+ }
53
+ res.writeHead(404, { 'Content-Type': 'application/json' });
54
+ res.end(JSON.stringify({ message: 'Not Found' }));
55
+ logger_1.logger.http(method, url.pathname, 404);
56
+ }
57
+ handleManagementApi(method, connectionId, req, res) {
58
+ const connection = this.connections.get(connectionId);
59
+ // GET - Get connection info
60
+ if (method === 'GET') {
61
+ if (connection) {
62
+ res.writeHead(200, { 'Content-Type': 'application/json' });
63
+ res.end(JSON.stringify({
64
+ connectionId,
65
+ connectedAt: connection.connectedAt.toISOString(),
66
+ lastActiveAt: connection.lastActivityAt.toISOString(),
67
+ }));
68
+ logger_1.logger.http('GET', `/@connections/${connectionId}`, 200);
69
+ }
70
+ else {
71
+ res.writeHead(410, { 'Content-Type': 'application/json' });
72
+ res.end(JSON.stringify({ message: 'Gone', connectionId }));
73
+ logger_1.logger.http('GET', `/@connections/${connectionId}`, 410);
74
+ }
75
+ return;
76
+ }
77
+ // DELETE - Close connection
78
+ if (method === 'DELETE') {
79
+ if (connection && connection.ws.readyState === ws_1.WebSocket.OPEN) {
80
+ connection.ws.close(1000, 'Closed by management API');
81
+ res.writeHead(204);
82
+ res.end();
83
+ logger_1.logger.http('DELETE', `/@connections/${connectionId}`, 204);
84
+ }
85
+ else {
86
+ res.writeHead(410, { 'Content-Type': 'application/json' });
87
+ res.end(JSON.stringify({ message: 'Gone', connectionId }));
88
+ logger_1.logger.http('DELETE', `/@connections/${connectionId}`, 410);
89
+ }
90
+ return;
91
+ }
92
+ // POST - Send message (postToConnection)
93
+ if (method === 'POST') {
94
+ let body = '';
95
+ req.on('data', (chunk) => (body += chunk));
96
+ req.on('end', () => {
97
+ if (connection && connection.ws.readyState === ws_1.WebSocket.OPEN) {
98
+ connection.ws.send(body);
99
+ connection.lastActivityAt = new Date();
100
+ res.writeHead(200);
101
+ res.end();
102
+ logger_1.logger.http('POST', `/@connections/${connectionId}`, 200);
103
+ logger_1.logger.debug(`Sent ${body.length} bytes to ${connectionId}`);
104
+ }
105
+ else {
106
+ res.writeHead(410, { 'Content-Type': 'application/json' });
107
+ res.end(JSON.stringify({ message: 'Gone', connectionId }));
108
+ logger_1.logger.http('POST', `/@connections/${connectionId}`, 410);
109
+ }
110
+ });
111
+ return;
112
+ }
113
+ res.writeHead(405, { 'Content-Type': 'application/json' });
114
+ res.end(JSON.stringify({ message: 'Method Not Allowed' }));
115
+ logger_1.logger.http(method, `/@connections/${connectionId}`, 405);
116
+ }
117
+ // ============================================================================
118
+ // WebSocket Connection Handling
119
+ // ============================================================================
120
+ handleConnection(ws, req) {
121
+ const url = new url_1.URL(req.url || '/', `http://localhost:${this.config.port}`);
122
+ const connectionId = this.generateConnectionId();
123
+ // Parse query parameters
124
+ const queryParams = {};
125
+ url.searchParams.forEach((value, key) => {
126
+ queryParams[key] = value;
127
+ });
128
+ // Parse headers
129
+ const headers = {};
130
+ for (const [key, value] of Object.entries(req.headers)) {
131
+ if (typeof value === 'string') {
132
+ headers[key.toLowerCase()] = value;
133
+ }
134
+ else if (Array.isArray(value)) {
135
+ headers[key.toLowerCase()] = value[0];
136
+ }
137
+ }
138
+ // Extract client info
139
+ const sourceIp = (req.socket.remoteAddress || '127.0.0.1').replace('::ffff:', '');
140
+ const userAgent = req.headers['user-agent'] || '';
141
+ const connection = {
142
+ id: connectionId,
143
+ ws,
144
+ connectedAt: new Date(),
145
+ lastActivityAt: new Date(),
146
+ queryParams,
147
+ headers,
148
+ sourceIp,
149
+ userAgent,
150
+ };
151
+ this.connections.set(connectionId, connection);
152
+ this.setupTimeouts(connectionId);
153
+ logger_1.logger.ws('CONNECT', connectionId, `ip: ${sourceIp}`);
154
+ // Call $connect route
155
+ this.callBackend('$connect', connection, null).then((success) => {
156
+ if (!success) {
157
+ logger_1.logger.warn(`$connect callback failed for ${connectionId}, closing connection`);
158
+ ws.close(1011, 'Backend connect failed');
159
+ }
160
+ });
161
+ // Handle messages
162
+ ws.on('message', (data) => {
163
+ const message = data.toString();
164
+ connection.lastActivityAt = new Date();
165
+ this.resetIdleTimeout(connectionId);
166
+ logger_1.logger.ws('MESSAGE', connectionId, `${message.substring(0, 50)}${message.length > 50 ? '...' : ''}`);
167
+ // Route selection (P2: custom routes)
168
+ const routeKey = this.selectRoute(message);
169
+ this.callBackend(routeKey, connection, message);
170
+ });
171
+ // Handle close
172
+ ws.on('close', (code, reason) => {
173
+ const reasonStr = reason.toString();
174
+ logger_1.logger.ws('DISCONNECT', connectionId, `code: ${code}`);
175
+ this.callBackend('$disconnect', connection, null, {
176
+ disconnectStatusCode: code,
177
+ disconnectReason: reasonStr,
178
+ });
179
+ this.clearTimeouts(connectionId);
180
+ this.connections.delete(connectionId);
181
+ });
182
+ // Handle error
183
+ ws.on('error', (error) => {
184
+ logger_1.logger.error(`WebSocket error for ${connectionId}:`, error.message);
185
+ });
186
+ }
187
+ // ============================================================================
188
+ // Route Selection (P2)
189
+ // ============================================================================
190
+ selectRoute(message) {
191
+ if (!this.config.routeSelectionExpression) {
192
+ return '$default';
193
+ }
194
+ try {
195
+ const parsed = JSON.parse(message);
196
+ const match = this.config.routeSelectionExpression.match(/^\$request\.body\.(.+)$/);
197
+ if (match) {
198
+ const path = match[1].split('.');
199
+ let value = parsed;
200
+ for (const key of path) {
201
+ if (value && typeof value === 'object' && key in value) {
202
+ value = value[key];
203
+ }
204
+ else {
205
+ return '$default';
206
+ }
207
+ }
208
+ if (typeof value === 'string' && this.config.routes[value]) {
209
+ return value;
210
+ }
211
+ }
212
+ }
213
+ catch {
214
+ // Non-JSON message, use $default
215
+ }
216
+ return '$default';
217
+ }
218
+ // ============================================================================
219
+ // AWS Event Building
220
+ // ============================================================================
221
+ buildRequestContext(connection, routeKey, eventType, options) {
222
+ const now = new Date();
223
+ const requestId = this.generateRequestId();
224
+ const context = {
225
+ routeKey,
226
+ eventType,
227
+ extendedRequestId: requestId,
228
+ requestTime: this.formatRequestTime(now),
229
+ messageDirection: 'IN',
230
+ stage: this.config.stage,
231
+ connectedAt: connection.connectedAt.getTime(),
232
+ requestTimeEpoch: now.getTime(),
233
+ identity: {
234
+ sourceIp: connection.sourceIp,
235
+ userAgent: connection.userAgent,
236
+ },
237
+ requestId,
238
+ domainName: this.config.domainName,
239
+ connectionId: connection.id,
240
+ apiId: this.config.apiId,
241
+ };
242
+ // MESSAGE-specific fields
243
+ if (eventType === 'MESSAGE') {
244
+ context.messageId = options?.messageId || this.generateMessageId();
245
+ }
246
+ // DISCONNECT-specific fields
247
+ if (eventType === 'DISCONNECT' && options) {
248
+ context.disconnectStatusCode = options.disconnectStatusCode;
249
+ context.disconnectReason = options.disconnectReason;
250
+ }
251
+ return context;
252
+ }
253
+ buildMultiValueHeaders(headers) {
254
+ const result = {};
255
+ for (const [key, value] of Object.entries(headers)) {
256
+ result[key] = [value];
257
+ }
258
+ return result;
259
+ }
260
+ buildLambdaEvent(connection, routeKey, eventType, body, options) {
261
+ return {
262
+ requestContext: this.buildRequestContext(connection, routeKey, eventType, options),
263
+ headers: connection.headers,
264
+ multiValueHeaders: this.buildMultiValueHeaders(connection.headers),
265
+ queryStringParameters: Object.keys(connection.queryParams).length > 0 ? connection.queryParams : null,
266
+ body,
267
+ isBase64Encoded: false,
268
+ };
269
+ }
270
+ formatRequestTime(date) {
271
+ const pad = (n) => n.toString().padStart(2, '0');
272
+ const months = [
273
+ 'Jan',
274
+ 'Feb',
275
+ 'Mar',
276
+ 'Apr',
277
+ 'May',
278
+ 'Jun',
279
+ 'Jul',
280
+ 'Aug',
281
+ 'Sep',
282
+ 'Oct',
283
+ 'Nov',
284
+ 'Dec',
285
+ ];
286
+ return (`${pad(date.getUTCDate())}/${months[date.getUTCMonth()]}/${date.getUTCFullYear()}:` +
287
+ `${pad(date.getUTCHours())}:${pad(date.getUTCMinutes())}:${pad(date.getUTCSeconds())} +0000`);
288
+ }
289
+ // ============================================================================
290
+ // Backend Communication
291
+ // ============================================================================
292
+ async callBackend(routeKey, connection, body, disconnectOptions) {
293
+ // Get event type from route key
294
+ const eventType = this.getEventType(routeKey);
295
+ // Get route integration
296
+ const integration = this.config.routes[routeKey] || this.config.routes['$default'];
297
+ if (!integration) {
298
+ logger_1.logger.warn(`No integration found for route: ${routeKey}`);
299
+ return false;
300
+ }
301
+ // Build AWS Lambda event
302
+ const event = this.buildLambdaEvent(connection, routeKey, eventType, body, disconnectOptions);
303
+ try {
304
+ const response = await fetch(integration.uri, {
305
+ method: 'POST',
306
+ headers: {
307
+ 'Content-Type': 'application/json',
308
+ },
309
+ body: JSON.stringify(event),
310
+ });
311
+ logger_1.logger.debug(`${routeKey} callback: ${response.status}`);
312
+ return response.ok;
313
+ }
314
+ catch (error) {
315
+ logger_1.logger.error(`${routeKey} callback failed:`, error.message);
316
+ return false;
317
+ }
318
+ }
319
+ getEventType(routeKey) {
320
+ switch (routeKey) {
321
+ case '$connect':
322
+ return 'CONNECT';
323
+ case '$disconnect':
324
+ return 'DISCONNECT';
325
+ default:
326
+ return 'MESSAGE';
327
+ }
328
+ }
329
+ // ============================================================================
330
+ // Timeout Management
331
+ // ============================================================================
332
+ setupTimeouts(connectionId) {
333
+ this.resetIdleTimeout(connectionId);
334
+ // Hard timeout
335
+ const hardTimer = setTimeout(() => {
336
+ const connection = this.connections.get(connectionId);
337
+ if (connection) {
338
+ logger_1.logger.warn(`Hard timeout reached for ${connectionId}`);
339
+ connection.ws.close(1001, 'Hard timeout');
340
+ }
341
+ }, this.config.hardTimeout * 1000);
342
+ this.timeoutTimers.set(`${connectionId}:hard`, hardTimer);
343
+ }
344
+ resetIdleTimeout(connectionId) {
345
+ const idleKey = `${connectionId}:idle`;
346
+ const existingTimer = this.timeoutTimers.get(idleKey);
347
+ if (existingTimer) {
348
+ clearTimeout(existingTimer);
349
+ }
350
+ const idleTimer = setTimeout(() => {
351
+ const connection = this.connections.get(connectionId);
352
+ if (connection) {
353
+ logger_1.logger.warn(`Idle timeout reached for ${connectionId}`);
354
+ connection.ws.close(1001, 'Idle timeout');
355
+ }
356
+ }, this.config.idleTimeout * 1000);
357
+ this.timeoutTimers.set(idleKey, idleTimer);
358
+ }
359
+ clearTimeouts(connectionId) {
360
+ const idleTimer = this.timeoutTimers.get(`${connectionId}:idle`);
361
+ const hardTimer = this.timeoutTimers.get(`${connectionId}:hard`);
362
+ if (idleTimer)
363
+ clearTimeout(idleTimer);
364
+ if (hardTimer)
365
+ clearTimeout(hardTimer);
366
+ this.timeoutTimers.delete(`${connectionId}:idle`);
367
+ this.timeoutTimers.delete(`${connectionId}:hard`);
368
+ }
369
+ // ============================================================================
370
+ // ID Generation
371
+ // ============================================================================
372
+ generateConnectionId() {
373
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
374
+ let result = '';
375
+ for (let i = 0; i < 12; i++) {
376
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
377
+ }
378
+ return result + '=';
379
+ }
380
+ generateRequestId() {
381
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
382
+ const r = (Math.random() * 16) | 0;
383
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
384
+ return v.toString(16);
385
+ });
386
+ }
387
+ generateMessageId() {
388
+ return this.generateConnectionId();
389
+ }
390
+ // ============================================================================
391
+ // Server Lifecycle
392
+ // ============================================================================
393
+ start() {
394
+ return new Promise((resolve) => {
395
+ this.httpServer.listen(this.config.port, () => {
396
+ logger_1.logger.banner({
397
+ port: this.config.port,
398
+ stage: this.config.stage,
399
+ });
400
+ resolve();
401
+ });
402
+ });
403
+ }
404
+ stop() {
405
+ return new Promise((resolve) => {
406
+ this.connections.forEach((connection) => {
407
+ connection.ws.close(1001, 'Server shutting down');
408
+ });
409
+ this.connections.clear();
410
+ this.timeoutTimers.forEach((timer) => clearTimeout(timer));
411
+ this.timeoutTimers.clear();
412
+ this.wss.close(() => {
413
+ this.httpServer.close(() => {
414
+ logger_1.logger.info('Server stopped');
415
+ resolve();
416
+ });
417
+ });
418
+ });
419
+ }
420
+ getConnectionCount() {
421
+ return this.connections.size;
422
+ }
423
+ }
424
+ exports.AWSWebSocketGateway = AWSWebSocketGateway;
425
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import { WebSocket } from 'ws';
2
+ export interface AWSIdentity {
3
+ sourceIp: string;
4
+ userAgent?: string;
5
+ }
6
+ export interface AWSRequestContext {
7
+ routeKey: string;
8
+ eventType: 'CONNECT' | 'DISCONNECT' | 'MESSAGE';
9
+ extendedRequestId: string;
10
+ requestTime: string;
11
+ messageDirection: 'IN';
12
+ stage: string;
13
+ connectedAt: number;
14
+ requestTimeEpoch: number;
15
+ identity: AWSIdentity;
16
+ requestId: string;
17
+ domainName: string;
18
+ connectionId: string;
19
+ apiId: string;
20
+ messageId?: string;
21
+ disconnectStatusCode?: number;
22
+ disconnectReason?: string;
23
+ }
24
+ export interface AWSWebSocketEvent {
25
+ requestContext: AWSRequestContext;
26
+ headers: Record<string, string>;
27
+ multiValueHeaders: Record<string, string[]>;
28
+ queryStringParameters: Record<string, string> | null;
29
+ body: string | null;
30
+ isBase64Encoded: boolean;
31
+ }
32
+ export interface RouteIntegration {
33
+ uri: string;
34
+ }
35
+ export interface GatewayConfig {
36
+ port: number;
37
+ stage: string;
38
+ apiId: string;
39
+ domainName: string;
40
+ routeSelectionExpression?: string;
41
+ routes: Record<string, RouteIntegration>;
42
+ idleTimeout: number;
43
+ hardTimeout: number;
44
+ verbose: boolean;
45
+ }
46
+ export declare const DEFAULT_CONFIG: GatewayConfig;
47
+ export interface Connection {
48
+ id: string;
49
+ ws: WebSocket;
50
+ connectedAt: Date;
51
+ lastActivityAt: Date;
52
+ queryParams: Record<string, string>;
53
+ headers: Record<string, string>;
54
+ sourceIp: string;
55
+ userAgent: string;
56
+ }
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAM/B,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;IAChD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,IAAI,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IAEd,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,iBAAiB,CAAC;IAClC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5C,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAAC;IACrD,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAMD,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,cAAc,EAAE,aAa5B,CAAC;AAMF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,SAAS,CAAC;IACd,WAAW,EAAE,IAAI,CAAC;IAClB,cAAc,EAAE,IAAI,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_CONFIG = void 0;
4
+ exports.DEFAULT_CONFIG = {
5
+ port: 3001,
6
+ stage: 'local',
7
+ apiId: 'local',
8
+ domainName: '',
9
+ routes: {
10
+ $connect: { uri: 'http://localhost:8080/ws/connect' },
11
+ $disconnect: { uri: 'http://localhost:8080/ws/disconnect' },
12
+ $default: { uri: 'http://localhost:8080/ws/default' },
13
+ },
14
+ idleTimeout: 600,
15
+ hardTimeout: 7200,
16
+ verbose: false,
17
+ };
18
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AA6Da,QAAA,cAAc,GAAkB;IAC3C,IAAI,EAAE,IAAI;IACV,KAAK,EAAE,OAAO;IACd,KAAK,EAAE,OAAO;IACd,UAAU,EAAE,EAAE;IACd,MAAM,EAAE;QACN,QAAQ,EAAE,EAAE,GAAG,EAAE,kCAAkC,EAAE;QACrD,WAAW,EAAE,EAAE,GAAG,EAAE,qCAAqC,EAAE;QAC3D,QAAQ,EAAE,EAAE,GAAG,EAAE,kCAAkC,EAAE;KACtD;IACD,WAAW,EAAE,GAAG;IAChB,WAAW,EAAE,IAAI;IACjB,OAAO,EAAE,KAAK;CACf,CAAC"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "aws-apigw-ws-emulator",
3
+ "version": "0.0.1",
4
+ "description": "Local emulator for AWS API Gateway WebSocket with HTTP integration support",
5
+ "keywords": [
6
+ "aws",
7
+ "api-gateway",
8
+ "websocket",
9
+ "local",
10
+ "emulator",
11
+ "mock",
12
+ "development",
13
+ "serverless"
14
+ ],
15
+ "author": "m1heng",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/m1heng/aws-apigw-ws-emulator"
20
+ },
21
+ "main": "dist/index.js",
22
+ "types": "dist/index.d.ts",
23
+ "bin": {
24
+ "aws-apigw-ws-emulator": "./dist/cli.js"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "dependencies": {
32
+ "chalk": "^4.1.2",
33
+ "commander": "^11.1.0",
34
+ "ws": "^8.16.0",
35
+ "yaml": "^2.3.4"
36
+ },
37
+ "devDependencies": {
38
+ "@types/node": "^20.10.0",
39
+ "@types/ws": "^8.5.10",
40
+ "ts-node": "^10.9.2",
41
+ "typescript": "^5.3.0",
42
+ "vitest": "^3.0.0"
43
+ },
44
+ "engines": {
45
+ "node": ">=18.0.0"
46
+ },
47
+ "scripts": {
48
+ "build": "tsc",
49
+ "dev": "ts-node src/cli.ts",
50
+ "start": "node dist/cli.js",
51
+ "test": "vitest run",
52
+ "test:watch": "vitest"
53
+ }
54
+ }