json-api-mocker 2.3.0 → 2.3.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/CONFIG.md CHANGED
@@ -302,3 +302,41 @@ You can configure file upload endpoints in your `data.json`:
302
302
  }
303
303
  }
304
304
  ```
305
+
306
+ ### WebSocket Configuration
307
+
308
+ | Field | Type | Required | Description |
309
+ |-------|------|----------|-------------|
310
+ | enabled | boolean | Yes | Enable/disable WebSocket support |
311
+ | path | string | Yes | WebSocket endpoint path |
312
+ | events | object | No | Event configurations |
313
+
314
+ #### Event Configuration
315
+
316
+ | Field | Type | Required | Description |
317
+ |-------|------|----------|-------------|
318
+ | mock.enabled | boolean | Yes | Enable/disable mock data for this event |
319
+ | mock.interval | number | No | Interval (ms) for automatic data sending |
320
+ | mock.template | object | Yes | Mock.js template for response data |
321
+
322
+ Example:
323
+ ```json
324
+ {
325
+ "websocket": {
326
+ "enabled": true,
327
+ "path": "/ws",
328
+ "events": {
329
+ "event-name": {
330
+ "mock": {
331
+ "enabled": true,
332
+ "interval": 5000,
333
+ "template": {
334
+ "field1": "@value",
335
+ "field2|1-100": 1
336
+ }
337
+ }
338
+ }
339
+ }
340
+ }
341
+ }
342
+ ```
package/README.ch.md CHANGED
@@ -17,6 +17,7 @@
17
17
  - 🛠 可自定义响应结构
18
18
  - 🎭 集成 Mock.js 实现强大的数据模拟
19
19
  - 📤 支持文件上传
20
+ - 🔌 支持 WebSocket 实时通信
20
21
  - 💡 TypeScript 支持
21
22
 
22
23
  ## 📦 安装
@@ -296,6 +297,89 @@ curl http://localhost:8080/api/users?page=2&pageSize=10
296
297
  }
297
298
  ```
298
299
 
300
+ ### WebSocket 支持
301
+
302
+ 你可以在 `data.json` 中配置 WebSocket 接口:
303
+
304
+ ```json
305
+ {
306
+ "websocket": {
307
+ "enabled": true,
308
+ "path": "/ws",
309
+ "events": {
310
+ "realtime-data": {
311
+ "mock": {
312
+ "enabled": true,
313
+ "interval": 5000, // 每5秒发送一次数据
314
+ "template": {
315
+ "timestamp": "@datetime",
316
+ "value|1-100": 1,
317
+ "status|1": ["normal", "warning", "error"]
318
+ }
319
+ }
320
+ },
321
+ "user-status": {
322
+ "mock": {
323
+ "enabled": true,
324
+ "template": {
325
+ "userId|+1": 1,
326
+ "status|1": ["online", "offline", "away"],
327
+ "lastActive": "@datetime"
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+ ```
335
+
336
+ #### 客户端使用示例:
337
+
338
+ ```javascript
339
+ // 连接 WebSocket 服务器
340
+ const ws = new WebSocket('ws://localhost:8080/ws');
341
+
342
+ // 处理连接打开
343
+ ws.onopen = () => {
344
+ console.log('已连接到 WebSocket 服务器');
345
+
346
+ // 请求实时数据
347
+ ws.send(JSON.stringify({
348
+ event: 'realtime-data'
349
+ }));
350
+ };
351
+
352
+ // 处理接收到的消息
353
+ ws.onmessage = (event) => {
354
+ const data = JSON.parse(event.data);
355
+ console.log('收到数据:', data);
356
+ // {
357
+ // event: 'realtime-data',
358
+ // data: {
359
+ // timestamp: '2024-01-01 12:00:00',
360
+ // value: 75,
361
+ // status: 'normal'
362
+ // }
363
+ // }
364
+ };
365
+
366
+ // 处理错误
367
+ ws.onerror = (error) => {
368
+ console.error('WebSocket 错误:', error);
369
+ };
370
+
371
+ // 处理连接关闭
372
+ ws.onclose = () => {
373
+ console.log('与 WebSocket 服务器断开连接');
374
+ };
375
+ ```
376
+
377
+ #### 特性:
378
+ - 基于事件的通信
379
+ - 支持指定间隔自动发送数据
380
+ - 支持 Mock.js 模板生成动态数据
381
+ - 支持多个事件处理器
382
+
299
383
  ## 🤝 贡献指南
300
384
 
301
385
  1. Fork 本仓库
package/README.md CHANGED
@@ -17,6 +17,7 @@ A lightweight and flexible mock server that uses JSON configuration to quickly c
17
17
  - 🛠 Customizable response schemas
18
18
  - 🎭 Integration with Mock.js for powerful data mocking
19
19
  - 📤 File upload support
20
+ - 🔌 Real-time communication with WebSocket
20
21
  - 💡 TypeScript support
21
22
 
22
23
  ## 📦 Installation
@@ -296,6 +297,89 @@ Add schema validation for POST/PUT requests:
296
297
  }
297
298
  ```
298
299
 
300
+ ### WebSocket Support
301
+
302
+ You can configure WebSocket endpoints in your `data.json`:
303
+
304
+ ```json
305
+ {
306
+ "websocket": {
307
+ "enabled": true,
308
+ "path": "/ws",
309
+ "events": {
310
+ "realtime-data": {
311
+ "mock": {
312
+ "enabled": true,
313
+ "interval": 5000, // Send data every 5 seconds
314
+ "template": {
315
+ "timestamp": "@datetime",
316
+ "value|1-100": 1,
317
+ "status|1": ["normal", "warning", "error"]
318
+ }
319
+ }
320
+ },
321
+ "user-status": {
322
+ "mock": {
323
+ "enabled": true,
324
+ "template": {
325
+ "userId|+1": 1,
326
+ "status|1": ["online", "offline", "away"],
327
+ "lastActive": "@datetime"
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ }
334
+ ```
335
+
336
+ #### Client Usage Example:
337
+
338
+ ```javascript
339
+ // Connect to WebSocket server
340
+ const ws = new WebSocket('ws://localhost:8080/ws');
341
+
342
+ // Handle connection open
343
+ ws.onopen = () => {
344
+ console.log('Connected to WebSocket server');
345
+
346
+ // Request real-time data
347
+ ws.send(JSON.stringify({
348
+ event: 'realtime-data'
349
+ }));
350
+ };
351
+
352
+ // Handle incoming messages
353
+ ws.onmessage = (event) => {
354
+ const data = JSON.parse(event.data);
355
+ console.log('Received:', data);
356
+ // {
357
+ // event: 'realtime-data',
358
+ // data: {
359
+ // timestamp: '2024-01-01 12:00:00',
360
+ // value: 75,
361
+ // status: 'normal'
362
+ // }
363
+ // }
364
+ };
365
+
366
+ // Handle errors
367
+ ws.onerror = (error) => {
368
+ console.error('WebSocket error:', error);
369
+ };
370
+
371
+ // Handle connection close
372
+ ws.onclose = () => {
373
+ console.log('Disconnected from WebSocket server');
374
+ };
375
+ ```
376
+
377
+ #### Features:
378
+ - Event-based communication
379
+ - Automatic data sending at specified intervals
380
+ - Mock.js template support for dynamic data
381
+ - Multiple event handlers
382
+
299
383
  ## 🤝 Contributing
300
384
 
301
385
  1. Fork the repository
package/dist/cli.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- #!/usr/bin/env node
2
- export {};
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js CHANGED
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- Object.defineProperty(exports, "__esModule", { value: true });
4
- const index_1 = require("./index");
5
- const configPath = process.argv[2] || 'data.json';
6
- (0, index_1.startServer)(configPath);
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const index_1 = require("./index");
5
+ const configPath = process.argv[2] || 'data.json';
6
+ (0, index_1.startServer)(configPath);
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export declare function startServer(configPath?: string): void;
2
- export { MockServer } from './server';
3
- export * from './types';
1
+ export declare function startServer(configPath?: string): void;
2
+ export { MockServer } from './server';
3
+ export * from './types';
package/dist/index.js CHANGED
@@ -1,43 +1,43 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- var __importDefault = (this && this.__importDefault) || function (mod) {
17
- return (mod && mod.__esModule) ? mod : { "default": mod };
18
- };
19
- Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.MockServer = exports.startServer = void 0;
21
- const fs_1 = __importDefault(require("fs"));
22
- const path_1 = __importDefault(require("path"));
23
- const server_1 = require("./server");
24
- function startServer(configPath = 'data.json') {
25
- const fullPath = path_1.default.resolve(process.cwd(), configPath);
26
- try {
27
- const configContent = fs_1.default.readFileSync(fullPath, 'utf-8');
28
- const config = JSON.parse(configContent);
29
- const server = new server_1.MockServer(config, configPath);
30
- server.start();
31
- }
32
- catch (error) {
33
- console.error('Failed to start server:', error);
34
- process.exit(1);
35
- }
36
- }
37
- exports.startServer = startServer;
38
- if (require.main === module) {
39
- startServer();
40
- }
41
- var server_2 = require("./server");
42
- Object.defineProperty(exports, "MockServer", { enumerable: true, get: function () { return server_2.MockServer; } });
43
- __exportStar(require("./types"), exports);
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ var __importDefault = (this && this.__importDefault) || function (mod) {
17
+ return (mod && mod.__esModule) ? mod : { "default": mod };
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.MockServer = void 0;
21
+ exports.startServer = startServer;
22
+ const fs_1 = __importDefault(require("fs"));
23
+ const path_1 = __importDefault(require("path"));
24
+ const server_1 = require("./server");
25
+ function startServer(configPath = 'data.json') {
26
+ const fullPath = path_1.default.resolve(process.cwd(), configPath);
27
+ try {
28
+ const configContent = fs_1.default.readFileSync(fullPath, 'utf-8');
29
+ const config = JSON.parse(configContent);
30
+ const server = new server_1.MockServer(config, configPath);
31
+ server.start();
32
+ }
33
+ catch (error) {
34
+ console.error('Failed to start server:', error);
35
+ process.exit(1);
36
+ }
37
+ }
38
+ if (require.main === module) {
39
+ startServer();
40
+ }
41
+ var server_2 = require("./server");
42
+ Object.defineProperty(exports, "MockServer", { enumerable: true, get: function () { return server_2.MockServer; } });
43
+ __exportStar(require("./types"), exports);
package/dist/server.d.ts CHANGED
@@ -1,18 +1,22 @@
1
- import { Express } from 'express';
2
- import { Config } from './types';
3
- export declare class MockServer {
4
- private app;
5
- private config;
6
- private configPath;
7
- constructor(config: Config, configPath?: string);
8
- getApp(): Express;
9
- private setupMiddleware;
10
- private logRequest;
11
- private generateMockData;
12
- private handleRequest;
13
- private setupRoutes;
14
- private createRoute;
15
- private findRouteConfig;
16
- private generateMockResponse;
17
- start(): void;
18
- }
1
+ import { Express } from 'express';
2
+ import { Config } from './types';
3
+ export declare class MockServer {
4
+ private app;
5
+ private server;
6
+ private wss;
7
+ private config;
8
+ private configPath;
9
+ constructor(config: Config, configPath?: string);
10
+ getApp(): Express;
11
+ private setupMiddleware;
12
+ private logRequest;
13
+ private generateMockData;
14
+ private handleRequest;
15
+ private setupRoutes;
16
+ private createRoute;
17
+ private findRouteConfig;
18
+ private generateMockResponse;
19
+ private setupWebSocket;
20
+ start(): void;
21
+ close(): void;
22
+ }
package/dist/server.js CHANGED
@@ -1,138 +1,205 @@
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.MockServer = void 0;
7
- const mockjs_1 = __importDefault(require("mockjs"));
8
- const express_1 = __importDefault(require("express"));
9
- const cors_1 = __importDefault(require("cors"));
10
- class MockServer {
11
- constructor(config, configPath = 'data.json') {
12
- this.app = (0, express_1.default)();
13
- this.logRequest = (req, res, next) => {
14
- const startTime = Date.now();
15
- const requestId = Math.random().toString(36).substring(7);
16
- console.log(`[${new Date().toISOString()}] Request ${requestId}:`);
17
- console.log(` Method: ${req.method}`);
18
- console.log(` URL: ${req.url}`);
19
- console.log(` Query Params: ${JSON.stringify(req.query)}`);
20
- console.log(` Body: ${JSON.stringify(req.body)}`);
21
- res.on('finish', () => {
22
- const duration = Date.now() - startTime;
23
- console.log(`[${new Date().toISOString()}] Response ${requestId}:`);
24
- console.log(` Status: ${res.statusCode}`);
25
- console.log(` Duration: ${duration}ms`);
26
- console.log('----------------------------------------');
27
- });
28
- next();
29
- };
30
- this.config = config;
31
- this.configPath = configPath;
32
- this.setupMiddleware();
33
- this.setupRoutes();
34
- }
35
- getApp() {
36
- return this.app;
37
- }
38
- setupMiddleware() {
39
- this.app.use((0, cors_1.default)());
40
- this.app.use(express_1.default.json());
41
- this.app.use('/uploads', express_1.default.static('uploads'));
42
- this.app.use(this.logRequest);
43
- }
44
- generateMockData(config) {
45
- try {
46
- if (config.mock?.enabled && config.mock.template) {
47
- const { total, template } = config.mock;
48
- return mockjs_1.default.mock({
49
- [`data|${total}`]: [template]
50
- }).data;
51
- }
52
- return config.response;
53
- }
54
- catch (error) {
55
- console.error('Error generating mock data:', error);
56
- return config.response;
57
- }
58
- }
59
- handleRequest(config) {
60
- return (req, res) => {
61
- try {
62
- let responseData = this.generateMockData(config);
63
- if (config.pagination?.enabled && Array.isArray(responseData)) {
64
- const page = parseInt(req.query.page) || 1;
65
- const pageSize = parseInt(req.query.pageSize) || config.pagination.pageSize;
66
- const startIndex = (page - 1) * pageSize;
67
- const endIndex = startIndex + pageSize;
68
- const paginatedData = responseData.slice(startIndex, endIndex);
69
- res.header('X-Total-Count', responseData.length.toString());
70
- responseData = paginatedData;
71
- }
72
- res.json(responseData);
73
- }
74
- catch (error) {
75
- console.error('Error handling request:', error);
76
- res.status(500).json({ error: 'Internal server error' });
77
- }
78
- };
79
- }
80
- setupRoutes() {
81
- this.config.routes.forEach((route) => {
82
- Object.entries(route.methods).forEach(([method, methodConfig]) => {
83
- this.createRoute(route.path, method, methodConfig);
84
- });
85
- });
86
- }
87
- createRoute(path, method, config) {
88
- const fullPath = `${this.config.server.baseProxy}${path}`;
89
- console.log(`创建路由: ${method.toUpperCase()} ${fullPath}`);
90
- switch (method.toLowerCase()) {
91
- case 'get':
92
- this.app.get(fullPath, this.handleRequest(config));
93
- break;
94
- case 'post':
95
- if (path === '/upload/avatar') {
96
- // 对于文件上传路由,使用特殊处理
97
- this.app.post(fullPath, (req, res) => {
98
- const mockResponse = this.generateMockData(config);
99
- res.json(mockResponse);
100
- });
101
- }
102
- else {
103
- this.app.post(fullPath, this.handleRequest(config));
104
- }
105
- break;
106
- case 'put':
107
- this.app.put(`${fullPath}/:id`, this.handleRequest(config));
108
- break;
109
- case 'delete':
110
- this.app.delete(`${fullPath}/:id`, this.handleRequest(config));
111
- break;
112
- }
113
- }
114
- findRouteConfig(path, method) {
115
- const route = this.config.routes.find(r => r.path === path);
116
- return route?.methods[method] || null;
117
- }
118
- generateMockResponse(config) {
119
- if (config.mock?.enabled && config.mock.template) {
120
- return mockjs_1.default.mock(config.mock.template);
121
- }
122
- return config.response;
123
- }
124
- start() {
125
- this.app.listen(this.config.server.port, () => {
126
- console.log(`Mock 服务器已启动:`);
127
- console.log(`- 地址: http://localhost:${this.config.server.port}`);
128
- console.log(`- 基础路径: ${this.config.server.baseProxy}`);
129
- console.log('可用的接口:');
130
- this.config.routes.forEach(route => {
131
- Object.keys(route.methods).forEach(method => {
132
- console.log(` ${method.toUpperCase()} http://localhost:${this.config.server.port}${this.config.server.baseProxy}${route.path}`);
133
- });
134
- });
135
- });
136
- }
137
- }
138
- exports.MockServer = MockServer;
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.MockServer = void 0;
7
+ const mockjs_1 = __importDefault(require("mockjs"));
8
+ const express_1 = __importDefault(require("express"));
9
+ const cors_1 = __importDefault(require("cors"));
10
+ const ws_1 = require("ws");
11
+ const http_1 = __importDefault(require("http"));
12
+ class MockServer {
13
+ constructor(config, configPath = 'data.json') {
14
+ this.app = (0, express_1.default)();
15
+ this.wss = null;
16
+ this.logRequest = (req, res, next) => {
17
+ const startTime = Date.now();
18
+ const requestId = Math.random().toString(36).substring(7);
19
+ console.log(`[${new Date().toISOString()}] Request ${requestId}:`);
20
+ console.log(` Method: ${req.method}`);
21
+ console.log(` URL: ${req.url}`);
22
+ console.log(` Query Params: ${JSON.stringify(req.query)}`);
23
+ console.log(` Body: ${JSON.stringify(req.body)}`);
24
+ res.on('finish', () => {
25
+ const duration = Date.now() - startTime;
26
+ console.log(`[${new Date().toISOString()}] Response ${requestId}:`);
27
+ console.log(` Status: ${res.statusCode}`);
28
+ console.log(` Duration: ${duration}ms`);
29
+ console.log('----------------------------------------');
30
+ });
31
+ next();
32
+ };
33
+ this.config = config;
34
+ this.configPath = configPath;
35
+ this.server = http_1.default.createServer(this.app);
36
+ this.setupMiddleware();
37
+ this.setupRoutes();
38
+ if (config.websocket?.enabled) {
39
+ this.setupWebSocket();
40
+ }
41
+ }
42
+ getApp() {
43
+ return this.app;
44
+ }
45
+ setupMiddleware() {
46
+ this.app.use((0, cors_1.default)());
47
+ this.app.use(express_1.default.json());
48
+ this.app.use('/uploads', express_1.default.static('uploads'));
49
+ this.app.use(this.logRequest);
50
+ }
51
+ generateMockData(config) {
52
+ try {
53
+ if (config.mock?.enabled && config.mock.template) {
54
+ const { total, template } = config.mock;
55
+ return mockjs_1.default.mock({
56
+ [`data|${total}`]: [template]
57
+ }).data;
58
+ }
59
+ return config.response;
60
+ }
61
+ catch (error) {
62
+ console.error('Error generating mock data:', error);
63
+ return config.response;
64
+ }
65
+ }
66
+ handleRequest(config) {
67
+ return (req, res) => {
68
+ try {
69
+ let responseData = this.generateMockData(config);
70
+ if (config.pagination?.enabled && Array.isArray(responseData)) {
71
+ const page = parseInt(req.query.page) || 1;
72
+ const pageSize = parseInt(req.query.pageSize) || config.pagination.pageSize;
73
+ const startIndex = (page - 1) * pageSize;
74
+ const endIndex = startIndex + pageSize;
75
+ const paginatedData = responseData.slice(startIndex, endIndex);
76
+ res.header('X-Total-Count', responseData.length.toString());
77
+ responseData = paginatedData;
78
+ }
79
+ res.json(responseData);
80
+ }
81
+ catch (error) {
82
+ console.error('Error handling request:', error);
83
+ res.status(500).json({ error: 'Internal server error' });
84
+ }
85
+ };
86
+ }
87
+ setupRoutes() {
88
+ this.config.routes.forEach((route) => {
89
+ Object.entries(route.methods).forEach(([method, methodConfig]) => {
90
+ this.createRoute(route.path, method, methodConfig);
91
+ });
92
+ });
93
+ }
94
+ createRoute(path, method, config) {
95
+ const fullPath = `${this.config.server.baseProxy}${path}`;
96
+ console.log(`创建路由: ${method.toUpperCase()} ${fullPath}`);
97
+ switch (method.toLowerCase()) {
98
+ case 'get':
99
+ this.app.get(fullPath, this.handleRequest(config));
100
+ break;
101
+ case 'post':
102
+ if (path === '/upload/avatar') {
103
+ // 对于文件上传路由,使用特殊处理
104
+ this.app.post(fullPath, (req, res) => {
105
+ const mockResponse = this.generateMockData(config);
106
+ res.json(mockResponse);
107
+ });
108
+ }
109
+ else {
110
+ this.app.post(fullPath, this.handleRequest(config));
111
+ }
112
+ break;
113
+ case 'put':
114
+ this.app.put(`${fullPath}/:id`, this.handleRequest(config));
115
+ break;
116
+ case 'delete':
117
+ this.app.delete(`${fullPath}/:id`, this.handleRequest(config));
118
+ break;
119
+ }
120
+ }
121
+ findRouteConfig(path, method) {
122
+ const route = this.config.routes.find(r => r.path === path);
123
+ return route?.methods[method] || null;
124
+ }
125
+ generateMockResponse(config) {
126
+ if (config.mock?.enabled && config.mock.template) {
127
+ return mockjs_1.default.mock(config.mock.template);
128
+ }
129
+ return config.response;
130
+ }
131
+ setupWebSocket() {
132
+ if (!this.config.websocket)
133
+ return;
134
+ this.wss = new ws_1.Server({
135
+ server: this.server,
136
+ path: this.config.websocket.path
137
+ });
138
+ this.wss.on('connection', (ws) => {
139
+ console.log('WebSocket client connected');
140
+ // 处理客户端消息
141
+ ws.on('message', (message) => {
142
+ try {
143
+ const data = JSON.parse(message.toString());
144
+ const eventConfig = this.config.websocket?.events?.[data.event];
145
+ if (eventConfig?.mock.enabled) {
146
+ const response = mockjs_1.default.mock(eventConfig.mock.template);
147
+ ws.send(JSON.stringify({
148
+ event: data.event,
149
+ data: response
150
+ }));
151
+ }
152
+ }
153
+ catch (error) {
154
+ console.error('Error handling WebSocket message:', error);
155
+ }
156
+ });
157
+ // 设置自动发送数据的定时器
158
+ if (this.config.websocket && this.config.websocket.events) {
159
+ Object.entries(this.config.websocket.events).forEach(([event, config]) => {
160
+ if (config.mock.interval) {
161
+ setInterval(() => {
162
+ const response = mockjs_1.default.mock(config.mock.template);
163
+ ws.send(JSON.stringify({
164
+ event,
165
+ data: response
166
+ }));
167
+ }, config.mock.interval);
168
+ }
169
+ });
170
+ }
171
+ ws.on('close', () => {
172
+ // 移除日志,避免测试完成后的日志输出
173
+ // console.log('WebSocket client disconnected');
174
+ });
175
+ });
176
+ }
177
+ start() {
178
+ this.server.listen(this.config.server.port, () => {
179
+ console.log(`Mock 服务器已启动:`);
180
+ console.log(`- HTTP 地址: http://localhost:${this.config.server.port}`);
181
+ if (this.config.websocket?.enabled) {
182
+ console.log(`- WebSocket 地址: ws://localhost:${this.config.server.port}${this.config.websocket.path}`);
183
+ }
184
+ console.log(`- 基础路径: ${this.config.server.baseProxy}`);
185
+ console.log('可用的接口:');
186
+ this.config.routes.forEach(route => {
187
+ Object.keys(route.methods).forEach(method => {
188
+ console.log(` ${method.toUpperCase()} http://localhost:${this.config.server.port}${this.config.server.baseProxy}${route.path}`);
189
+ });
190
+ });
191
+ });
192
+ }
193
+ close() {
194
+ // 关闭所有 WebSocket 连接
195
+ if (this.wss) {
196
+ this.wss.clients.forEach(client => {
197
+ client.close();
198
+ });
199
+ this.wss.close();
200
+ }
201
+ // 关闭 HTTP 服务器
202
+ this.server.close();
203
+ }
204
+ }
205
+ exports.MockServer = MockServer;
package/dist/types.d.ts CHANGED
@@ -1,31 +1,45 @@
1
- export interface ServerConfig {
2
- port: number;
3
- baseProxy: string;
4
- }
5
- export interface PaginationConfig {
6
- enabled: boolean;
7
- pageSize: number;
8
- totalCount: number;
9
- }
10
- export interface MockConfig {
11
- enabled: boolean;
12
- total?: number;
13
- template: Record<string, any>;
14
- }
15
- export interface MethodConfig {
16
- type?: 'array' | 'object';
17
- response?: any;
18
- mock?: MockConfig;
19
- pagination?: PaginationConfig;
20
- requestSchema?: Record<string, string>;
21
- }
22
- export interface RouteConfig {
23
- path: string;
24
- methods: {
25
- [key: string]: MethodConfig;
26
- };
27
- }
28
- export interface Config {
29
- server: ServerConfig;
30
- routes: RouteConfig[];
31
- }
1
+ export interface ServerConfig {
2
+ port: number;
3
+ baseProxy: string;
4
+ }
5
+ export interface PaginationConfig {
6
+ enabled: boolean;
7
+ pageSize: number;
8
+ totalCount: number;
9
+ }
10
+ export interface MockConfig {
11
+ enabled: boolean;
12
+ total?: number;
13
+ template: Record<string, any>;
14
+ }
15
+ export interface MethodConfig {
16
+ type?: 'array' | 'object';
17
+ response?: any;
18
+ mock?: MockConfig;
19
+ pagination?: PaginationConfig;
20
+ requestSchema?: Record<string, string>;
21
+ }
22
+ export interface RouteConfig {
23
+ path: string;
24
+ methods: {
25
+ [key: string]: MethodConfig;
26
+ };
27
+ }
28
+ export interface WebSocketConfig {
29
+ enabled: boolean;
30
+ path: string;
31
+ events?: {
32
+ [key: string]: {
33
+ mock: {
34
+ enabled: boolean;
35
+ template: Record<string, any>;
36
+ interval?: number;
37
+ };
38
+ };
39
+ };
40
+ }
41
+ export interface Config {
42
+ server: ServerConfig;
43
+ routes: RouteConfig[];
44
+ websocket?: WebSocketConfig;
45
+ }
package/dist/types.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-api-mocker",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "A mock server based on JSON configuration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -47,7 +47,8 @@
47
47
  "cors": "^2.8.5",
48
48
  "express": "^4.17.1",
49
49
  "mockjs": "^1.1.0",
50
- "multer": "^1.4.5-lts.1"
50
+ "multer": "^1.4.5-lts.1",
51
+ "ws": "^8.18.0"
51
52
  },
52
53
  "devDependencies": {
53
54
  "@types/cors": "^2.8.13",
@@ -57,6 +58,7 @@
57
58
  "@types/multer": "^1.4.12",
58
59
  "@types/node": "^16.18.0",
59
60
  "@types/supertest": "^6.0.2",
61
+ "@types/ws": "^8.5.13",
60
62
  "jest": "^27.5.1",
61
63
  "nodemon": "^2.0.22",
62
64
  "supertest": "^7.0.0",