@vercube/ws 1.2.1 → 1.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/dist/index.d.mts +21 -18
- package/dist/index.mjs +53 -3
- package/package.json +8 -7
package/dist/index.d.mts
CHANGED
|
@@ -10,7 +10,7 @@ import { Message as Message$1, Peer, WSError } from "crossws";
|
|
|
10
10
|
* @param {string} path - The namespace path for websocket connections.
|
|
11
11
|
* @returns {Function} - The decorator function.
|
|
12
12
|
*/
|
|
13
|
-
declare function Namespace(path: string): Function;
|
|
13
|
+
export declare function Namespace(path: string): Function;
|
|
14
14
|
//#endregion
|
|
15
15
|
//#region src/Decorators/Message.d.ts
|
|
16
16
|
interface MessageDecoratorOptions {
|
|
@@ -26,7 +26,7 @@ interface MessageDecoratorOptions {
|
|
|
26
26
|
* @param {MessageDecoratorOptions} params - The options for the message handler, including event and optional validation schema.
|
|
27
27
|
* @returns {Function} - The decorator function.
|
|
28
28
|
*/
|
|
29
|
-
declare function Message(params: MessageDecoratorOptions): Function;
|
|
29
|
+
export declare function Message(params: MessageDecoratorOptions): Function;
|
|
30
30
|
//#endregion
|
|
31
31
|
//#region src/Decorators/Emit.d.ts
|
|
32
32
|
/**
|
|
@@ -38,7 +38,7 @@ declare function Message(params: MessageDecoratorOptions): Function;
|
|
|
38
38
|
* @param {string} event - The event name for the emitted websocket message.
|
|
39
39
|
* @returns {Function} - The decorator function.
|
|
40
40
|
*/
|
|
41
|
-
declare function Emit(event: string): Function;
|
|
41
|
+
export declare function Emit(event: string): Function;
|
|
42
42
|
//#endregion
|
|
43
43
|
//#region src/Decorators/Broadcast.d.ts
|
|
44
44
|
/**
|
|
@@ -50,7 +50,7 @@ declare function Emit(event: string): Function;
|
|
|
50
50
|
* @param {string} event - The event name for the broadcasted websocket message.
|
|
51
51
|
* @returns {Function} - The decorator function.
|
|
52
52
|
*/
|
|
53
|
-
declare function Broadcast(event: string): Function;
|
|
53
|
+
export declare function Broadcast(event: string): Function;
|
|
54
54
|
//#endregion
|
|
55
55
|
//#region src/Decorators/BroadcastOthers.d.ts
|
|
56
56
|
/**
|
|
@@ -62,7 +62,7 @@ declare function Broadcast(event: string): Function;
|
|
|
62
62
|
* @param {string} event - The event name for the broadcasted websocket message.
|
|
63
63
|
* @returns {Function} - The decorator function.
|
|
64
64
|
*/
|
|
65
|
-
declare function BroadcastOthers(event: string): Function;
|
|
65
|
+
export declare function BroadcastOthers(event: string): Function;
|
|
66
66
|
//#endregion
|
|
67
67
|
//#region src/Decorators/OnConnectionAttempt.d.ts
|
|
68
68
|
/**
|
|
@@ -78,7 +78,7 @@ declare function BroadcastOthers(event: string): Function;
|
|
|
78
78
|
*
|
|
79
79
|
* @returns {Function} - The decorator function.
|
|
80
80
|
*/
|
|
81
|
-
declare function OnConnectionAttempt(): Function;
|
|
81
|
+
export declare function OnConnectionAttempt(): Function;
|
|
82
82
|
//#endregion
|
|
83
83
|
//#region src/Plugins/WebsocketPlugin.d.ts
|
|
84
84
|
/**
|
|
@@ -101,7 +101,7 @@ declare function OnConnectionAttempt(): Function;
|
|
|
101
101
|
*
|
|
102
102
|
* @see {@link https://vercube.dev} for full documentation
|
|
103
103
|
*/
|
|
104
|
-
declare class WebsocketPlugin<T = unknown> extends BasePlugin<T> {
|
|
104
|
+
export declare class WebsocketPlugin<T = unknown> extends BasePlugin<T> {
|
|
105
105
|
/**
|
|
106
106
|
* The name of the plugin.
|
|
107
107
|
* @override
|
|
@@ -117,7 +117,7 @@ declare class WebsocketPlugin<T = unknown> extends BasePlugin<T> {
|
|
|
117
117
|
}
|
|
118
118
|
//#endregion
|
|
119
119
|
//#region src/Types/WebsocketTypes.d.ts
|
|
120
|
-
declare namespace WebsocketTypes {
|
|
120
|
+
export declare namespace WebsocketTypes {
|
|
121
121
|
enum HandlerAction {
|
|
122
122
|
CONNECTION = "connection",
|
|
123
123
|
MESSAGE = "message"
|
|
@@ -130,14 +130,7 @@ declare namespace WebsocketTypes {
|
|
|
130
130
|
}
|
|
131
131
|
//#endregion
|
|
132
132
|
//#region src/Services/WebsocketService.d.ts
|
|
133
|
-
|
|
134
|
-
* WebsocketService class responsible for dealing with Websocket connections.
|
|
135
|
-
*
|
|
136
|
-
* This class is responsible for:
|
|
137
|
-
* - Registering namespaces and accepting websocket connections for them
|
|
138
|
-
* - Registering event handlers and handling them
|
|
139
|
-
*/
|
|
140
|
-
declare class WebsocketService {
|
|
133
|
+
export declare class WebsocketService {
|
|
141
134
|
/**
|
|
142
135
|
* Http Server for injecting the server plugin
|
|
143
136
|
*/
|
|
@@ -213,9 +206,19 @@ declare class WebsocketService {
|
|
|
213
206
|
* @returns {Promise<void>}
|
|
214
207
|
*/
|
|
215
208
|
private handleMessage;
|
|
209
|
+
/**
|
|
210
|
+
* Dispatches one websocket message to its handler.
|
|
211
|
+
*
|
|
212
|
+
* @param {WSPeer} peer - The peer the message came from
|
|
213
|
+
* @param {WSMessage} rawMessage - The raw message
|
|
214
|
+
* @param {Span} span - The span covering this message
|
|
215
|
+
* @returns {Promise<void>} Resolves once the handler has run
|
|
216
|
+
* @private
|
|
217
|
+
*/
|
|
218
|
+
private internalHandleMessage;
|
|
216
219
|
}
|
|
217
220
|
//#endregion
|
|
218
221
|
//#region src/Symbols/WebsocketSymbols.d.ts
|
|
219
|
-
declare const $WebsocketService: symbol;
|
|
222
|
+
export declare const $WebsocketService: symbol;
|
|
220
223
|
//#endregion
|
|
221
|
-
export {
|
|
224
|
+
export type { WSError, Message$1 as WSMessage, Peer as WSPeer };
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BadRequestError, BasePlugin, HttpServer, ValidationProvider, initializeMetadata, initializeMetadataMethod, safeJsonParse, sanitizeObject } from "@vercube/core";
|
|
2
2
|
import { BaseDecorator, Identity, Inject, InjectOptional, createDecorator } from "@vercube/di";
|
|
3
3
|
import { Logger } from "@vercube/logger";
|
|
4
|
+
import { SpanKind, ValueType, createInstrument } from "@vercube/telemetry/instrument";
|
|
4
5
|
import { defineHooks } from "crossws";
|
|
5
6
|
import { plugin } from "crossws/server";
|
|
6
7
|
//#region src/Decorators/Namespace.ts
|
|
@@ -33,7 +34,7 @@ let WebsocketTypes;
|
|
|
33
34
|
}({});
|
|
34
35
|
})(WebsocketTypes || (WebsocketTypes = {}));
|
|
35
36
|
//#endregion
|
|
36
|
-
//#region \0@oxc-project+runtime@0.
|
|
37
|
+
//#region \0@oxc-project+runtime@0.150.0/helpers/esm/decorate.js
|
|
37
38
|
function __decorate(decorators, target, key, desc) {
|
|
38
39
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
39
40
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -49,6 +50,33 @@ function __decorate(decorators, target, key, desc) {
|
|
|
49
50
|
* - Registering namespaces and accepting websocket connections for them
|
|
50
51
|
* - Registering event handlers and handling them
|
|
51
52
|
*/
|
|
53
|
+
/**
|
|
54
|
+
* Records websocket signals.
|
|
55
|
+
*
|
|
56
|
+
* The toolkit comes from `@vercube/telemetry/instrument`, which is the only
|
|
57
|
+
* place in the framework that speaks to OpenTelemetry directly.
|
|
58
|
+
*/
|
|
59
|
+
const instrument = createInstrument("@vercube/ws");
|
|
60
|
+
/** Attribute naming the namespace a peer or message belongs to. */
|
|
61
|
+
const WS_NAMESPACE = "vercube.ws.namespace";
|
|
62
|
+
/**
|
|
63
|
+
* Records a change in the number of connected peers.
|
|
64
|
+
*
|
|
65
|
+
* An up/down counter rather than a gauge: connects and disconnects are events
|
|
66
|
+
* the service already sees, and counting them is exact, where sampling a peer
|
|
67
|
+
* list on a timer would miss everything that happened between two samples.
|
|
68
|
+
*
|
|
69
|
+
* @param {number} delta - `1` on connect, `-1` on disconnect
|
|
70
|
+
* @param {string} namespace - The namespace the peer belongs to
|
|
71
|
+
* @returns {void}
|
|
72
|
+
*/
|
|
73
|
+
function countConnection(delta, namespace) {
|
|
74
|
+
instrument.upDownCounter("vercube.ws.connections", {
|
|
75
|
+
description: "Currently connected websocket peers.",
|
|
76
|
+
unit: "{connection}",
|
|
77
|
+
valueType: ValueType.INT
|
|
78
|
+
}).add(delta, { [WS_NAMESPACE]: namespace });
|
|
79
|
+
}
|
|
52
80
|
var WebsocketService = class {
|
|
53
81
|
/**
|
|
54
82
|
* Http Server for injecting the server plugin
|
|
@@ -153,7 +181,8 @@ var WebsocketService = class {
|
|
|
153
181
|
upgrade: async (request) => {
|
|
154
182
|
const url = new URL(request.url);
|
|
155
183
|
const namespace = url.pathname;
|
|
156
|
-
const
|
|
184
|
+
const unsafeParameters = Object.fromEntries(url.searchParams);
|
|
185
|
+
const parameters = sanitizeObject(unsafeParameters);
|
|
157
186
|
if (!!!this.fNamespaces?.[namespace?.toLowerCase()]) {
|
|
158
187
|
this.gLogger?.warn("WebsocketService::initialize", `Namespace "${namespace}" is not registered. Connection rejected.`);
|
|
159
188
|
return new Response("Namespace not registered", { status: 403 });
|
|
@@ -172,7 +201,10 @@ var WebsocketService = class {
|
|
|
172
201
|
},
|
|
173
202
|
open: async (peer) => {
|
|
174
203
|
const namespace = peer.namespace?.toLowerCase();
|
|
175
|
-
if (namespace && this.fNamespaces[namespace])
|
|
204
|
+
if (namespace && this.fNamespaces[namespace]) {
|
|
205
|
+
this.fNamespaces[namespace].push(peer);
|
|
206
|
+
countConnection(1, namespace);
|
|
207
|
+
}
|
|
176
208
|
},
|
|
177
209
|
message: async (peer, message) => {
|
|
178
210
|
await this.handleMessage(peer, message);
|
|
@@ -182,6 +214,7 @@ var WebsocketService = class {
|
|
|
182
214
|
if (namespace && this.fNamespaces[namespace]) {
|
|
183
215
|
const peers = this.fNamespaces[namespace];
|
|
184
216
|
this.fNamespaces[namespace] = peers.filter((p) => p.id !== peer.id);
|
|
217
|
+
countConnection(-1, namespace);
|
|
185
218
|
}
|
|
186
219
|
},
|
|
187
220
|
error: async (peer, error) => {
|
|
@@ -203,11 +236,28 @@ var WebsocketService = class {
|
|
|
203
236
|
* @returns {Promise<void>}
|
|
204
237
|
*/
|
|
205
238
|
async handleMessage(peer, rawMessage) {
|
|
239
|
+
await instrument.span("ws.message", {
|
|
240
|
+
kind: SpanKind.CONSUMER,
|
|
241
|
+
attributes: { [WS_NAMESPACE]: peer.namespace ?? "" }
|
|
242
|
+
}, (span) => this.internalHandleMessage(peer, rawMessage, span));
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Dispatches one websocket message to its handler.
|
|
246
|
+
*
|
|
247
|
+
* @param {WSPeer} peer - The peer the message came from
|
|
248
|
+
* @param {WSMessage} rawMessage - The raw message
|
|
249
|
+
* @param {Span} span - The span covering this message
|
|
250
|
+
* @returns {Promise<void>} Resolves once the handler has run
|
|
251
|
+
* @private
|
|
252
|
+
*/
|
|
253
|
+
async internalHandleMessage(peer, rawMessage, span) {
|
|
206
254
|
try {
|
|
207
255
|
const msg = safeJsonParse(rawMessage.text());
|
|
208
256
|
const namespace = peer.namespace?.toLowerCase();
|
|
209
257
|
const event = msg.event;
|
|
210
258
|
const data = msg.data;
|
|
259
|
+
span.updateName(`ws.message ${String(event)}`);
|
|
260
|
+
span.setAttribute("vercube.ws.event", String(event));
|
|
211
261
|
const handler = this.fHandlers[WebsocketTypes.HandlerAction.MESSAGE]?.[namespace]?.[event];
|
|
212
262
|
if (!handler) {
|
|
213
263
|
this.gLogger?.warn("WebsocketService::handleMessage", `No message handler for event "${event}" in namespace "${namespace}"`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vercube/ws",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Websocket module for Vercube framework",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,14 +22,15 @@
|
|
|
22
22
|
"README.md"
|
|
23
23
|
],
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"zod": "4.
|
|
25
|
+
"zod": "4.6.5"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"@vercube/
|
|
31
|
-
"@vercube/
|
|
32
|
-
"
|
|
28
|
+
"@vercube/core": "1.3.1",
|
|
29
|
+
"@vercube/di": "1.3.1",
|
|
30
|
+
"@vercube/logger": "1.3.1",
|
|
31
|
+
"@vercube/telemetry": "1.3.1",
|
|
32
|
+
"crossws": "0.4.12",
|
|
33
|
+
"srvx": "1.0.5"
|
|
33
34
|
},
|
|
34
35
|
"publishConfig": {
|
|
35
36
|
"access": "public"
|