mm_websocket_server 0.0.0-stage → 2.0.0

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,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Admin
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,119 @@
1
- # Temporary Holding Version
1
+ # mm_websocket_server
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 最薄的 WebSocket 服务器入站适配器。继承 `mm_mod` 的 `Mod`,把 `ws` 的每条消息直接交给 `mm_event` 的事件管理器处理,不做路由表、不做插件、不加载脚本。
4
+
5
+ - 入口:`index.js`(CommonJS)
6
+ - 导出:`WebSocketServer`、`admin`、`websocketServerAdmin`
7
+ - 运行时依赖:`mm_mod`、`mm_event`、`mm_corejs`、`ws`
8
+
9
+ ## 消息路径
10
+
11
+ ```
12
+ WebSocket.Server → connection → ctx = { client_id, path, ws }
13
+ → eventManager.run(path, params, ctx, options)
14
+ → 结果非空时回发来源连接
15
+ ```
16
+
17
+ 事件 `target` 取握手请求路径(第一个 `?` 之前)。`params` 为 `{ client_id, data }`,`data` 在 `json: true` 时尝试 `JSON.parse`(失败回落原文)。
18
+
19
+ ## 快速开始
20
+
21
+ ```js
22
+ 'use strict';
23
+
24
+ const { WebSocketServer } = require('mm_websocket_server');
25
+
26
+ const websocket = new WebSocketServer({ name: 'websocket', host: '127.0.0.1', port: 8090 });
27
+ const events = websocket.getEventManager();
28
+
29
+ events.add({ name: 'echo', target: '/echo', end: true }).main = async (params, ctx) => ({
30
+ client_id: ctx.client_id,
31
+ data: params.data
32
+ });
33
+
34
+ await websocket.init();
35
+ await websocket.start();
36
+
37
+ console.log(websocket.getAddress());
38
+ ```
39
+
40
+ ## 服务器配置
41
+
42
+ | 字段 | 类型 | 默认值 | 说明 |
43
+ | --- | --- | --- | --- |
44
+ | `name` | string | `'os'` | 模块名称(必填) |
45
+ | `title` | string | `'WebSocket服务器模块'` | 模块标题 |
46
+ | `description` | string | — | 模块描述 |
47
+ | `version` | string | `'2.0.0'` | 版本号 |
48
+ | `host` | string | `'0.0.0.0'` | 监听地址 |
49
+ | `port` | number | `8090` | 监听端口 |
50
+ | `json` | boolean | `true` | 入站尝试 JSON 解析,出站对象自动序列化 |
51
+ | `params` | object | `{ action }` | `main` 的参数约定 |
52
+
53
+ 不限制升级路径,任何路径都可连接,路径即事件 `target`。
54
+
55
+ ## API
56
+
57
+ | 成员 | 说明 |
58
+ | --- | --- |
59
+ | `init()` / `start()` / `stop()` / `dispose()` | `Mod` 生命周期模板方法 |
60
+ | `onInit()` / `onStart()` / `onStop()` / `onDispose()` | 生命周期钩子,子类可覆盖 |
61
+ | `getEventManager()` | 获取 `mm_event` 的 `websocket` 作用域事件管理器(与其他实例共享),用于注册事件 |
62
+ | `setEventManager(manager)` | 注入外部事件管理器,需提供 `run()` |
63
+ | `getAddress()` | 实际监听地址,未启动为 `null` |
64
+ | `run(params, ctx, options)` | 主动操作入口,`params.action` 派发 `send` / `broadcast` / `close` / `list` |
65
+ | `send(client_id, data)` | 向指定连接发送数据,返回是否成功 |
66
+ | `broadcast(data)` | 向全部在线连接广播,返回送达数 |
67
+ | `closeClient(client_id)` | 关闭指定连接,返回是否发起 |
68
+ | `listClients()` | 在线连接列表 `{ id, path, address }` |
69
+ | `hasClient(client_id)` | 是否在线 |
70
+ | `setClientOptions(client_id, options)` | 绑定连接级选项,随入站消息作为 `options` 透传(`null` 清空) |
71
+
72
+ ## 请求上下文(ctx)
73
+
74
+ | 字段 | 说明 |
75
+ | --- | --- |
76
+ | `client_id` | 连接编号,形如 `ws_1` |
77
+ | `path` | 握手请求路径,`?` 之后已截断 |
78
+ | `ws` | 原生 ws 连接,事件可直接写出 |
79
+
80
+ ## 事件处理函数
81
+
82
+ 签名固定为 `(params, ctx, options)`:
83
+
84
+ ```js
85
+ events.add({ name: 'echo', target: '/echo', end: true }).main = async (params, ctx, options) => {
86
+ return { data: params.data };
87
+ };
88
+ ```
89
+
90
+ 返回非 `undefined` / `null` 的结果会按 `json` 配置编码后回发来源连接;返回 `undefined` 则不回发。事件也可直接用 `ctx.ws` 写出。
91
+
92
+ ## 主动操作
93
+
94
+ ```js
95
+ await websocket.run({ action: 'send', client_id: 'ws_1', data: 'hi' });
96
+ await websocket.run({ action: 'broadcast', data: { type: 'notice' } });
97
+ await websocket.run({ action: 'close', client_id: 'ws_1' });
98
+ await websocket.run({ action: 'list' });
99
+ ```
100
+
101
+ ## 生命周期
102
+
103
+ `onStart` 创建并监听 `WebSocket.Server`,`onStop` 断开全部连接并关闭服务器。事件管理器取自 `mm_event` 的 `websocket` 作用域,由全局 `Admin` 共享,停止时不清理。端口被占用时 `start()` 抛错,模块进入 `error` 状态,可 `dispose()` 释放。
104
+
105
+ ## 示例
106
+
107
+ ```bash
108
+ npm run demo # 启动演示服务器(127.0.0.1:8090),见 example/demo.js
109
+ ```
110
+
111
+ ## 测试
112
+
113
+ ```bash
114
+ npm test # node --test
115
+ ```
116
+
117
+ ## 许可证
118
+
119
+ ISC
@@ -0,0 +1,51 @@
1
+ 'use strict';
2
+
3
+ const { WebSocketServer } = require('..');
4
+
5
+ /** 演示监听端口 */
6
+ const DEMO_PORT = 8090;
7
+
8
+ /**
9
+ * 注册演示事件:握手路径即事件 target
10
+ * @param {Object} events 事件管理器
11
+ * @returns {void}
12
+ */
13
+ function bindEvents(events) {
14
+ events.add({ name: 'echo', target: '/echo', end: true }).main = async (params, ctx) => ({
15
+ type: 'echo',
16
+ client_id: ctx.client_id,
17
+ data: params.data
18
+ });
19
+
20
+ events.add({ name: 'time', target: '/time', end: true }).main = async () => ({
21
+ time: new Date().toISOString()
22
+ });
23
+
24
+ events.add({ name: 'error', target: '/error', end: true }).main = async () => {
25
+ throw new Error('boom');
26
+ };
27
+ }
28
+
29
+ /**
30
+ * 演示入口:启动服务器并打印监听地址
31
+ * @returns {Promise<void>} 无返回值
32
+ */
33
+ async function main() {
34
+ const websocket = new WebSocketServer({ name: 'demo', host: '127.0.0.1', port: DEMO_PORT });
35
+
36
+ bindEvents(websocket.getEventManager());
37
+ websocket.on('error', (err) => console.error(`[demo] 错误: ${err.message}`));
38
+
39
+ await websocket.init();
40
+ await websocket.start();
41
+
42
+ const address = websocket.getAddress();
43
+ console.log(`ws://127.0.0.1:${address.port}/echo`);
44
+ console.log(`ws://127.0.0.1:${address.port}/time`);
45
+ console.log('连接后发送任意内容,结果由事件返回并自动回发');
46
+ }
47
+
48
+ main().catch((err) => {
49
+ console.error(err);
50
+ process.exit(1);
51
+ });
package/index.js ADDED
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ const WebSocketServer = require('./lib/websocket');
4
+ const Admin = require('mm_corejs').Admin;
5
+
6
+ let admin = new Admin();
7
+ admin.setClass(WebSocketServer);
8
+
9
+ module.exports = {
10
+ WebSocketServer,
11
+ admin,
12
+ /**
13
+ * 获取指定作用域的 WebSocket 服务器
14
+ * @param {string} [scope='os'] 作用域名称
15
+ * @param {object} [config] 配置参数
16
+ * @returns {WebSocketServer} WebSocket 服务器实例
17
+ */
18
+ websocketServerAdmin(scope, config) {
19
+ if (!scope) {
20
+ scope = 'os';
21
+ }
22
+ return admin.get(scope, config);
23
+ }
24
+ };
@@ -0,0 +1,434 @@
1
+ 'use strict';
2
+
3
+ const WebSocket = require('ws');
4
+ const { Mod } = require('mm_mod');
5
+ const { eventAdmin } = require('mm_event');
6
+
7
+ /**
8
+ * 获取请求路径(在 ? 处截断,不解析查询串)
9
+ * @param {string} url 原始请求地址
10
+ * @returns {string} 请求路径
11
+ */
12
+ function getPath(url) {
13
+ const index = url.indexOf('?');
14
+ return index === -1 ? url : url.slice(0, index);
15
+ }
16
+
17
+ /**
18
+ * WebSocketServer —— 最薄的 WebSocket 传输层(入站适配器模块)。
19
+ *
20
+ * 只做三件事:
21
+ * 1. 生命周期:由 Mod 的 init / start / stop 驱动 WebSocket.Server;
22
+ * 2. 消息转交:以握手请求路径为 target,直接调用
23
+ * EventManager.run(path, params, ctx, options),不做路由、不做插件;
24
+ * 3. 结果回发:事件返回非空结果时回发来源客户端,事件也可用 ctx.ws 自行写出。
25
+ *
26
+ * 用法:
27
+ * const wss = new WebSocketServer({ name: 'websocket', port: 8090 });
28
+ * wss.getEventManager().add({ name: 'echo', target: '*' }).main = async (params) => params.data;
29
+ * await wss.init();
30
+ * await wss.start();
31
+ */
32
+ class WebSocketServer extends Mod {
33
+ /**
34
+ * 模块默认配置
35
+ */
36
+ static config = {
37
+ name: 'os',
38
+ title: 'WebSocket服务器模块',
39
+ description: 'WebSocket 传输层:消息直达事件管理器,不做路由与插件',
40
+ version: '2.0.0',
41
+ host: '0.0.0.0',
42
+ port: 8090,
43
+ json: true,
44
+ params: {
45
+ type: 'object',
46
+ required: ['action'],
47
+ properties: {
48
+ action: { type: 'string', enum: ['send', 'broadcast', 'close', 'list'] },
49
+ client_id: { type: 'string', min_length: 1 },
50
+ data: {}
51
+ }
52
+ }
53
+ };
54
+
55
+ /**
56
+ * ws 服务器实例
57
+ */
58
+ #wss = null;
59
+
60
+ /**
61
+ * 事件管理器(取自 mm_event 的 websocket 作用域,与其他实例共享)
62
+ */
63
+ #events = null;
64
+
65
+ /**
66
+ * 在线连接表:client_id -> 连接信息
67
+ */
68
+ #clients = new Map();
69
+
70
+ /**
71
+ * 客户端编号自增计数器
72
+ */
73
+ #counter = 0;
74
+
75
+ /**
76
+ * 构造函数
77
+ * @param {Object} config 模块配置
78
+ * @param {Object} server 框架实例
79
+ */
80
+ constructor(config, server) {
81
+ super(config, server);
82
+ this.#events = eventAdmin('websocket');
83
+ }
84
+
85
+ // ---------- 生命周期钩子 ----------
86
+ /**
87
+ * 启动钩子:创建 ws 服务器并开始监听
88
+ * @returns {Promise<void>} 无返回值
89
+ */
90
+ async onStart() {
91
+ const wss = new WebSocket.Server({
92
+ host: this.config.host,
93
+ port: this.config.port
94
+ });
95
+ this.#wss = wss;
96
+ await this._listen(wss);
97
+ wss.on('error', (err) => this._emitError(err));
98
+ wss.on('connection', (ws, req) => this._handleConnection(ws, req));
99
+ }
100
+
101
+ /**
102
+ * 停止钩子:断开全部连接并关闭服务器(事件管理器与其他实例共享,不清理)
103
+ * @returns {Promise<void>} 无返回值
104
+ */
105
+ async onStop() {
106
+ this._closeAllClients();
107
+ await this._closeServer();
108
+ }
109
+
110
+ // ---------- 执行入口 ----------
111
+ /**
112
+ * 模块主逻辑:按 action 派发操作
113
+ * @param {Object} params 调用参数,含 action 及操作所需字段
114
+ * @param {Object} ctx 执行上下文
115
+ * @param {Object} options 合并后的选项
116
+ * @returns {Promise<Object>} 操作结果
117
+ */
118
+ async main(params, ctx, options) {
119
+ const action = params.action;
120
+ if (action === 'send') return this._actionSend(params);
121
+ if (action === 'broadcast') return this._actionBroadcast(params);
122
+ if (action === 'close') return this._actionClose(params);
123
+ return this._actionList();
124
+ }
125
+
126
+ /**
127
+ * 执行发送操作
128
+ * @param {Object} params 调用参数,含 client_id 与 data
129
+ * @returns {Object} 操作结果
130
+ */
131
+ _actionSend(params) {
132
+ this._requireClientId(params);
133
+ const success = this.send(params.client_id, params.data);
134
+ return { action: 'send', client_id: params.client_id, success };
135
+ }
136
+
137
+ /**
138
+ * 执行广播操作
139
+ * @param {Object} params 调用参数,含 data
140
+ * @returns {Object} 操作结果,count 为送达连接数
141
+ */
142
+ _actionBroadcast(params) {
143
+ const count = this.broadcast(params.data);
144
+ return { action: 'broadcast', count };
145
+ }
146
+
147
+ /**
148
+ * 执行关闭连接操作
149
+ * @param {Object} params 调用参数,含 client_id
150
+ * @returns {Object} 操作结果
151
+ */
152
+ _actionClose(params) {
153
+ this._requireClientId(params);
154
+ const success = this.closeClient(params.client_id);
155
+ return { action: 'close', client_id: params.client_id, success };
156
+ }
157
+
158
+ /**
159
+ * 执行列出连接操作
160
+ * @returns {Object} 操作结果,clients 为在线连接列表
161
+ */
162
+ _actionList() {
163
+ return { action: 'list', clients: this.listClients() };
164
+ }
165
+
166
+ // ---------- 事件管理器 ----------
167
+ /**
168
+ * 获取事件管理器,用于注册事件
169
+ * @returns {Object} 事件管理器实例
170
+ */
171
+ getEventManager() {
172
+ return this.#events;
173
+ }
174
+
175
+ /**
176
+ * 注入外部事件管理器
177
+ * @param {Object} manager 事件管理器实例
178
+ * @returns {WebSocketServer} 当前实例
179
+ * @throws {TypeError} manager 不具备 run 方法时
180
+ */
181
+ setEventManager(manager) {
182
+ if (!manager || typeof manager.run !== 'function') {
183
+ throw new TypeError(`${this._label()} manager must provide run()`);
184
+ }
185
+ this.#events = manager;
186
+ return this;
187
+ }
188
+
189
+ /**
190
+ * 获取实际监听地址
191
+ * @returns {Object|null} 监听地址信息,未启动时为 null
192
+ */
193
+ getAddress() {
194
+ const wss = this.#wss;
195
+ return wss ? wss.address() : null;
196
+ }
197
+
198
+ // ---------- 公开操作 ----------
199
+ /**
200
+ * 向指定连接发送数据
201
+ * @param {string} client_id 客户端 ID
202
+ * @param {string|Object} data 待发送数据
203
+ * @returns {boolean} 是否发送成功
204
+ */
205
+ send(client_id, data) {
206
+ const client = this.#clients.get(client_id);
207
+ if (!client) return false;
208
+ return this._sendToClient(client, this._encodeData(data));
209
+ }
210
+
211
+ /**
212
+ * 向全部在线连接广播数据
213
+ * @param {string|Object} data 待广播数据
214
+ * @returns {number} 送达的连接数量
215
+ */
216
+ broadcast(data) {
217
+ const payload = this._encodeData(data);
218
+ let count = 0;
219
+ for (const client of this.#clients.values()) {
220
+ if (this._sendToClient(client, payload)) count += 1;
221
+ }
222
+ return count;
223
+ }
224
+
225
+ /**
226
+ * 关闭指定连接(连接表由关闭回调清理)
227
+ * @param {string} client_id 客户端 ID
228
+ * @returns {boolean} 是否发起关闭
229
+ */
230
+ closeClient(client_id) {
231
+ const client = this.#clients.get(client_id);
232
+ if (!client) return false;
233
+ client.ws.close();
234
+ return true;
235
+ }
236
+
237
+ /**
238
+ * 列出在线连接
239
+ * @returns {Array<Object>} 连接信息列表,含 id、path 与 address
240
+ */
241
+ listClients() {
242
+ const list = [];
243
+ for (const client of this.#clients.values()) {
244
+ list.push({ id: client.id, path: client.path, address: client.address });
245
+ }
246
+ return list;
247
+ }
248
+
249
+ /**
250
+ * 判断连接是否在线
251
+ * @param {string} client_id 客户端 ID
252
+ * @returns {boolean} 是否在线
253
+ */
254
+ hasClient(client_id) {
255
+ return this.#clients.has(client_id);
256
+ }
257
+
258
+ /**
259
+ * 绑定连接级选项,入站消息将作为 options 透传给事件
260
+ * @param {string} client_id 客户端 ID
261
+ * @param {Object|null} options 选项对象,null 时清空
262
+ * @returns {boolean} 是否设置成功(连接不在线时失败)
263
+ */
264
+ setClientOptions(client_id, options) {
265
+ const client = this.#clients.get(client_id);
266
+ if (!client) return false;
267
+ client.options = options || null;
268
+ return true;
269
+ }
270
+
271
+ // ---------- 连接处理 ----------
272
+ /**
273
+ * 登记新的连接并绑定回调
274
+ * @param {Object} ws ws 连接实例
275
+ * @param {Object} req 握手请求对象
276
+ */
277
+ _handleConnection(ws, req) {
278
+ this.#counter += 1;
279
+ const client_id = `ws_${this.#counter}`;
280
+ const client = {
281
+ id: client_id,
282
+ path: getPath(req.url || '/'),
283
+ address: this._remoteAddress(req),
284
+ ws,
285
+ options: null
286
+ };
287
+ this.#clients.set(client_id, client);
288
+ ws.on('message', (buf) => this._handleMessage(client_id, buf));
289
+ ws.on('close', () => this.#clients.delete(client_id));
290
+ ws.on('error', (err) => this._emitError(err));
291
+ }
292
+
293
+ /**
294
+ * 处理入站消息:解码后交给事件管理器,返回非空结果时回发来源连接
295
+ * @param {string} client_id 客户端 ID
296
+ * @param {Object} buf 数据缓冲区
297
+ * @returns {Promise<void>} 无返回值
298
+ */
299
+ async _handleMessage(client_id, buf) {
300
+ const client = this.#clients.get(client_id);
301
+ if (!client) return;
302
+ const params = { client_id, data: this._decodeData(buf) };
303
+ const ctx = { client_id, path: client.path, ws: client.ws };
304
+ const options = this._clientOptions(client);
305
+ try {
306
+ const result = await this.#events.run(client.path, params, ctx, options);
307
+ const error = ctx.error || options.error;
308
+ if (error) this._emitError(error);
309
+ if (result !== undefined && result !== null) this.send(client_id, result);
310
+ } catch (err) {
311
+ this._emitError(err);
312
+ }
313
+ }
314
+
315
+ /**
316
+ * 获取连接级选项(复制一份,避免事件管理器回写)
317
+ * @param {Object} client 连接信息
318
+ * @returns {Object} 选项对象
319
+ */
320
+ _clientOptions(client) {
321
+ if (!client.options) return {};
322
+ return { ...client.options };
323
+ }
324
+
325
+ /**
326
+ * 获取远端地址字符串
327
+ * @param {Object} req 握手请求对象
328
+ * @returns {string} 形如 ip:port 的地址
329
+ */
330
+ _remoteAddress(req) {
331
+ return `${req.socket.remoteAddress}:${req.socket.remotePort}`;
332
+ }
333
+
334
+ // ---------- 数据编解码 ----------
335
+ /**
336
+ * 编码待发送数据
337
+ * @param {string|Object} data 待编码数据
338
+ * @returns {string} 编码后的字符串
339
+ */
340
+ _encodeData(data) {
341
+ if (this.config.json) return JSON.stringify(data);
342
+ if (typeof data === 'string') return data;
343
+ return String(data);
344
+ }
345
+
346
+ /**
347
+ * 解码收到的数据
348
+ * @param {Object} buf 数据缓冲区
349
+ * @returns {string|Object} 解码后的数据,json 模式下解析失败时返回原文
350
+ */
351
+ _decodeData(buf) {
352
+ const text = buf.toString('utf8');
353
+ if (!this.config.json) return text;
354
+ return this._parseJson(text);
355
+ }
356
+
357
+ /**
358
+ * 尝试将文本解析为 JSON
359
+ * @param {string} text 文本内容
360
+ * @returns {Object|string} 解析结果,失败时返回原文
361
+ */
362
+ _parseJson(text) {
363
+ try {
364
+ return JSON.parse(text);
365
+ } catch {
366
+ return text;
367
+ }
368
+ }
369
+
370
+ // ---------- 发送与清理 ----------
371
+ /**
372
+ * 向单个连接发送已编码数据
373
+ * @param {Object} client 连接信息
374
+ * @param {string} payload 已编码数据
375
+ * @returns {boolean} 是否发送成功
376
+ */
377
+ _sendToClient(client, payload) {
378
+ if (client.ws.readyState !== WebSocket.OPEN) return false;
379
+ client.ws.send(payload);
380
+ return true;
381
+ }
382
+
383
+ /**
384
+ * 断开全部连接并清空连接表
385
+ */
386
+ _closeAllClients() {
387
+ for (const client of this.#clients.values()) {
388
+ client.ws.terminate();
389
+ }
390
+ this.#clients.clear();
391
+ }
392
+
393
+ /**
394
+ * 等待 ws 服务器监听成功
395
+ * @param {Object} wss WebSocket.Server 实例
396
+ * @returns {Promise<void>} 无返回值
397
+ */
398
+ _listen(wss) {
399
+ return new Promise((resolve, reject) => {
400
+ wss.once('error', reject);
401
+ wss.once('listening', () => {
402
+ wss.removeListener('error', reject);
403
+ resolve();
404
+ });
405
+ });
406
+ }
407
+
408
+ /**
409
+ * 关闭 ws 服务器(连接已在之前全部终止)
410
+ * @returns {Promise<void>} 无返回值
411
+ */
412
+ _closeServer() {
413
+ const wss = this.#wss;
414
+ this.#wss = null;
415
+ if (!wss) return Promise.resolve();
416
+ return new Promise((resolve) => {
417
+ wss.close(() => resolve());
418
+ });
419
+ }
420
+
421
+ // ---------- 校验辅助 ----------
422
+ /**
423
+ * 断言调用参数含 client_id
424
+ * @param {Object} params 调用参数
425
+ * @throws {Error} 缺少 client_id 时
426
+ */
427
+ _requireClientId(params) {
428
+ if (!params.client_id) {
429
+ throw new Error(`${this._label()} params.client_id required`);
430
+ }
431
+ }
432
+ }
433
+
434
+ module.exports = WebSocketServer;
package/package.json CHANGED
@@ -1,6 +1,49 @@
1
1
  {
2
2
  "name": "mm_websocket_server",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "2.0.0",
4
+ "description": "最薄的 WebSocket 服务器入站适配器:消息直达 mm_event 事件管理器,不做路由与插件。",
5
+ "keywords": [
6
+ "超级美眉",
7
+ "入站适配器",
8
+ "mm_mod",
9
+ "mm_adapter",
10
+ "mm_in_adapter",
11
+ "mm_receiver",
12
+ "websocket",
13
+ "ws",
14
+ "server"
15
+ ],
16
+ "layer": "adapter",
17
+ "group": "in_adapter",
18
+ "license": "ISC",
19
+ "author": "qww",
20
+ "type": "commonjs",
21
+ "main": "index.js",
22
+ "files": [
23
+ "index.js",
24
+ "lib",
25
+ "example"
26
+ ],
27
+ "engines": {
28
+ "node": ">=22.5.0"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://gitee.com/qiuwenwu91/mm_websocket_server.git"
33
+ },
34
+ "homepage": "https://gitee.com/qiuwenwu91/mm_websocket_server",
35
+ "bugs": {
36
+ "url": "https://gitee.com/qiuwenwu91/mm_websocket_server/issues"
37
+ },
38
+ "scripts": {
39
+ "start": "node example/demo.js",
40
+ "demo": "node example/demo.js",
41
+ "test": "node --test \"test/*.test.js\""
42
+ },
43
+ "dependencies": {
44
+ "mm_corejs": "^1.1.4",
45
+ "mm_event": "^2.2.2",
46
+ "mm_mod": "^1.0.1",
47
+ "ws": "^8.22.0"
48
+ }
49
+ }