@vercube/ws 0.0.19
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 +21 -0
- package/README.md +29 -0
- package/dist/index.d.mts +219 -0
- package/dist/index.mjs +554 -0
- package/package.json +33 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-present - Vercube
|
|
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,29 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://vercube.dev/"><img src="https://github.com/OskarLebuda/vue-lazy-hydration/raw/main/.github/assets/logo.png?raw=true" alt="Vite logo" width="200"></a>
|
|
3
|
+
<br>
|
|
4
|
+
<br>
|
|
5
|
+
|
|
6
|
+
# Vercube
|
|
7
|
+
|
|
8
|
+
Next generation HTTP framework
|
|
9
|
+
|
|
10
|
+
<a href="https://www.npmjs.com/package/@vercube/auth">
|
|
11
|
+
<img src="https://img.shields.io/npm/v/%40vercube%2Fauth?style=for-the-badge&logo=npm&color=%23767eff" alt="npm"/>
|
|
12
|
+
</a>
|
|
13
|
+
<a href="https://www.npmjs.com/package/@vercube/auth">
|
|
14
|
+
<img src="https://img.shields.io/npm/dm/%40vercube%2Fauth?style=for-the-badge&logo=npm&color=%23767eff" alt="npm"/>
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://github.com/vercube/vercube/blob/main/LICENSE" target="_blank">
|
|
17
|
+
<img src="https://img.shields.io/npm/l/%40vercube%2Fauth?style=for-the-badge&color=%23767eff" alt="License"/>
|
|
18
|
+
</a>
|
|
19
|
+
<br/>
|
|
20
|
+
<br/>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
An ultra-efficient JavaScript server framework that runs anywhere - Node.js, Bun, or Deno - with unmatched flexibility and complete configurability for developers who refuse to sacrifice speed or control.
|
|
24
|
+
|
|
25
|
+
## <a name="module">Websocket module</a>
|
|
26
|
+
The Websocket module enables you to set up websocket connections on your application. It offers a collection of decorators that enable you to listen to incoming messages, emit/broadcast messages and more. It works based on namespaces.
|
|
27
|
+
|
|
28
|
+
## <a name="documentation">📖 Documentation</a>
|
|
29
|
+
Comprehensive documentation is available at [vercube.dev](https://vercube.dev). There you'll find detailed module descriptions, project information, guides, and everything else you need to know about Vercube.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { App, BasePlugin, ValidationTypes } from "@vercube/core";
|
|
2
|
+
import { Peer } from "crossws";
|
|
3
|
+
|
|
4
|
+
//#region src/Decorators/Namespace.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A decorator function for defining a websocket namespace and accepting websocket connections.
|
|
8
|
+
*
|
|
9
|
+
* This function attaches namespace metadata to the decorated class, which is used to group websocket events under a
|
|
10
|
+
* specific namespace.
|
|
11
|
+
*
|
|
12
|
+
* @param {string} path - The namespace path for websocket connections.
|
|
13
|
+
* @returns {Function} - The decorator function.
|
|
14
|
+
*/
|
|
15
|
+
declare function Namespace(path: string): Function;
|
|
16
|
+
//#endregion
|
|
17
|
+
//#region src/Decorators/Message.d.ts
|
|
18
|
+
interface MessageDecoratorOptions {
|
|
19
|
+
event: string;
|
|
20
|
+
validationSchema?: ValidationTypes.Schema;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A decorator function for listening to websocket messages under a specific event.
|
|
24
|
+
*
|
|
25
|
+
* This function creates an instance of the MessageDecorator class and registers a handler for websocket messages under
|
|
26
|
+
* the specified event and optional validation schema.
|
|
27
|
+
*
|
|
28
|
+
* @param {MessageDecoratorOptions} params - The options for the message handler, including event and optional validation schema.
|
|
29
|
+
* @returns {Function} - The decorator function.
|
|
30
|
+
*/
|
|
31
|
+
declare function Message(params: MessageDecoratorOptions): Function;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region src/Decorators/Emit.d.ts
|
|
34
|
+
/**
|
|
35
|
+
* A decorator function for emitting websocket messages to the peer.
|
|
36
|
+
*
|
|
37
|
+
* This function creates an instance of the EmitDecorator class and emits the result of the decorated method as a
|
|
38
|
+
* websocket message to the peer under the specified event.
|
|
39
|
+
*
|
|
40
|
+
* @param {string} event - The event name for the emitted websocket message.
|
|
41
|
+
* @returns {Function} - The decorator function.
|
|
42
|
+
*/
|
|
43
|
+
declare function Emit(event: string): Function;
|
|
44
|
+
//#endregion
|
|
45
|
+
//#region src/Decorators/Broadcast.d.ts
|
|
46
|
+
/**
|
|
47
|
+
* A decorator function for broadcasting websocket messages to everyone on the namespace (including the peer).
|
|
48
|
+
*
|
|
49
|
+
* This function creates an instance of the BroadcastDecorator class and emits the result of the decorated method as a
|
|
50
|
+
* websocket message to everyone on the namespace under the specified event.
|
|
51
|
+
*
|
|
52
|
+
* @param {string} event - The event name for the broadcasted websocket message.
|
|
53
|
+
* @returns {Function} - The decorator function.
|
|
54
|
+
*/
|
|
55
|
+
declare function Broadcast(event: string): Function;
|
|
56
|
+
//#endregion
|
|
57
|
+
//#region src/Decorators/BroadcastOthers.d.ts
|
|
58
|
+
/**
|
|
59
|
+
* A decorator function for broadcasting websocket messages to everyone on the namespace (except the peer).
|
|
60
|
+
*
|
|
61
|
+
* This function creates an instance of the BroadcastOthersDecorator class and emits the result of the decorated method
|
|
62
|
+
* as a websocket message to everyone on the namespace (except the peer) under the specified event.
|
|
63
|
+
*
|
|
64
|
+
* @param {string} event - The event name for the broadcasted websocket message.
|
|
65
|
+
* @returns {Function} - The decorator function.
|
|
66
|
+
*/
|
|
67
|
+
declare function BroadcastOthers(event: string): Function;
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/Decorators/OnConnectionAttempt.d.ts
|
|
70
|
+
/**
|
|
71
|
+
* A decorator function for handling websocket connection attempts to a namespace.
|
|
72
|
+
*
|
|
73
|
+
* This function creates an instance of the OnConnectionAttemptDecorator class and registers a handler for websocket
|
|
74
|
+
* connection attempts under the namespace. If the decorated function throws or returns false, the connection will not
|
|
75
|
+
* be accepted.
|
|
76
|
+
*
|
|
77
|
+
* The decorated function will receive the following parameters:
|
|
78
|
+
* - params: {Record<string, unknown>} The connection query parameters.
|
|
79
|
+
* - request: {Request} The original HTTP request.
|
|
80
|
+
*
|
|
81
|
+
* @returns {Function} - The decorator function.
|
|
82
|
+
*/
|
|
83
|
+
declare function OnConnectionAttempt(): Function;
|
|
84
|
+
//#endregion
|
|
85
|
+
//#region src/Plugins/WebsocketPlugin.d.ts
|
|
86
|
+
/**
|
|
87
|
+
* Websocket Plugin for Vercube framework
|
|
88
|
+
*
|
|
89
|
+
* Enables websocket connections and use of decorators related
|
|
90
|
+
* to the Websocket package.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```ts
|
|
94
|
+
* import { createApp } from '@vercube/core';
|
|
95
|
+
* import { WebsocketPlugin } from '@vercube/ws';
|
|
96
|
+
*
|
|
97
|
+
* const app = createApp({
|
|
98
|
+
* setup: async (app) => {
|
|
99
|
+
* app.addPlugin(WebsocketPlugin);
|
|
100
|
+
* }
|
|
101
|
+
* });
|
|
102
|
+
* ```
|
|
103
|
+
*
|
|
104
|
+
* @see {@link https://vercube.dev} for full documentation
|
|
105
|
+
*/
|
|
106
|
+
declare class WebsocketPlugin<T = unknown> extends BasePlugin<T> {
|
|
107
|
+
/**
|
|
108
|
+
* The name of the plugin.
|
|
109
|
+
* @override
|
|
110
|
+
*/
|
|
111
|
+
name: string;
|
|
112
|
+
/**
|
|
113
|
+
* Method to use the plugin with the given app.
|
|
114
|
+
* @param {App} app - The application instance.
|
|
115
|
+
* @returns {void | Promise<void>}
|
|
116
|
+
* @override
|
|
117
|
+
*/
|
|
118
|
+
use(app: App, options: T): void | Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
//#endregion
|
|
121
|
+
//#region src/Types/WebsocketTypes.d.ts
|
|
122
|
+
declare namespace WebsocketTypes {
|
|
123
|
+
enum HandlerAction {
|
|
124
|
+
CONNECTION = "connection",
|
|
125
|
+
MESSAGE = "message",
|
|
126
|
+
}
|
|
127
|
+
type HandlerAttributes = {
|
|
128
|
+
callback: Function;
|
|
129
|
+
event?: string;
|
|
130
|
+
schema?: ValidationTypes.Schema;
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region src/Services/WebsocketService.d.ts
|
|
135
|
+
/**
|
|
136
|
+
* WebsocketService class responsible for dealing with Websocket connections.
|
|
137
|
+
*
|
|
138
|
+
* This class is responsible for:
|
|
139
|
+
* - Registering namespaces and accepting websocket connections for them
|
|
140
|
+
* - Registering event handlers and handling them
|
|
141
|
+
*/
|
|
142
|
+
declare class WebsocketService {
|
|
143
|
+
/**
|
|
144
|
+
* Http Server for injecting the server plugin
|
|
145
|
+
*/
|
|
146
|
+
private readonly gHttpServer;
|
|
147
|
+
/**
|
|
148
|
+
* Validation provider for running the schema validation
|
|
149
|
+
*/
|
|
150
|
+
private readonly gValidationProvider;
|
|
151
|
+
private readonly gLogger;
|
|
152
|
+
/**
|
|
153
|
+
* Internal namespace registry
|
|
154
|
+
*/
|
|
155
|
+
private fNamespaces;
|
|
156
|
+
/**
|
|
157
|
+
* Internal handlers registry
|
|
158
|
+
*/
|
|
159
|
+
private fHandlers;
|
|
160
|
+
/**
|
|
161
|
+
* Register a new namespace.
|
|
162
|
+
*
|
|
163
|
+
* @param {string} path - The namespace path to register.
|
|
164
|
+
* @returns {void}
|
|
165
|
+
*/
|
|
166
|
+
registerNamespace(path: string): void;
|
|
167
|
+
/**
|
|
168
|
+
* Register a new handler for a namespace or event.
|
|
169
|
+
*
|
|
170
|
+
* @param {WebsocketTypes.HandlerAction} action - The handler action type.
|
|
171
|
+
* @param {string} namespace - The namespace to register the handler for.
|
|
172
|
+
* @param {WebsocketTypes.HandlerAttributes} handler - The handler attributes.
|
|
173
|
+
* @returns {void}
|
|
174
|
+
*/
|
|
175
|
+
registerHandler(action: WebsocketTypes.HandlerAction, namespace: string, handler: WebsocketTypes.HandlerAttributes): void;
|
|
176
|
+
/**
|
|
177
|
+
* Broadcast a message to all peers in the same namespace (including the sender).
|
|
178
|
+
*
|
|
179
|
+
* @param {Peer} peer - The sender peer (used to determine the namespace).
|
|
180
|
+
* @param {unknown} message - The message to broadcast.
|
|
181
|
+
* @returns {void}
|
|
182
|
+
*/
|
|
183
|
+
broadcast(peer: Peer, message: unknown): void;
|
|
184
|
+
/**
|
|
185
|
+
* Emit a message to a single peer.
|
|
186
|
+
*
|
|
187
|
+
* @param {Peer} peer - The peer to send the message to.
|
|
188
|
+
* @param {unknown} message - The message to send.
|
|
189
|
+
* @returns {void}
|
|
190
|
+
*/
|
|
191
|
+
emit(peer: Peer, message: unknown): void;
|
|
192
|
+
/**
|
|
193
|
+
* Broadcast a message to all peers in the same namespace except the sender.
|
|
194
|
+
*
|
|
195
|
+
* @param {Peer} peer - The sender peer (used to determine the namespace).
|
|
196
|
+
* @param {unknown} message - The message to broadcast.
|
|
197
|
+
* @returns {void}
|
|
198
|
+
*/
|
|
199
|
+
broadcastOthers(peer: Peer, message: unknown): void;
|
|
200
|
+
/**
|
|
201
|
+
* Initialize the websocket service and attach the server plugin.
|
|
202
|
+
*
|
|
203
|
+
* @returns {void}
|
|
204
|
+
*/
|
|
205
|
+
initialize(): void;
|
|
206
|
+
/**
|
|
207
|
+
* Handle an incoming websocket message for a peer.
|
|
208
|
+
*
|
|
209
|
+
* @param {Peer} peer - The peer receiving the message.
|
|
210
|
+
* @param {Message} rawMessage - The raw websocket message.
|
|
211
|
+
* @returns {Promise<void>}
|
|
212
|
+
*/
|
|
213
|
+
private handleMessage;
|
|
214
|
+
}
|
|
215
|
+
//#endregion
|
|
216
|
+
//#region src/Symbols/WebsocketSymbols.d.ts
|
|
217
|
+
declare const $WebsocketService: symbol;
|
|
218
|
+
//#endregion
|
|
219
|
+
export { $WebsocketService, Broadcast, BroadcastOthers, Emit, Message, Namespace, OnConnectionAttempt, WebsocketPlugin, WebsocketService, WebsocketTypes };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import "node:module";
|
|
2
|
+
import { BadRequestError, BasePlugin, HttpServer, ValidationProvider, initializeMetadata, initializeMetadataMethod } from "@vercube/core";
|
|
3
|
+
import { BaseDecorator, Identity, Inject, InjectOptional, createDecorator } from "@vercube/di";
|
|
4
|
+
import { plugin } from "crossws/server";
|
|
5
|
+
import { defineHooks } from "crossws";
|
|
6
|
+
import { Logger } from "@vercube/logger";
|
|
7
|
+
|
|
8
|
+
//#region rolldown:runtime
|
|
9
|
+
var __create = Object.create;
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
12
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
13
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
14
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
15
|
+
var __commonJS = (cb, mod) => function() {
|
|
16
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
20
|
+
key = keys[i];
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
22
|
+
get: ((k) => from[k]).bind(null, key),
|
|
23
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
29
|
+
value: mod,
|
|
30
|
+
enumerable: true
|
|
31
|
+
}) : target, mod));
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/Decorators/Namespace.ts
|
|
35
|
+
/**
|
|
36
|
+
* A decorator function for defining a websocket namespace and accepting websocket connections.
|
|
37
|
+
*
|
|
38
|
+
* This function attaches namespace metadata to the decorated class, which is used to group websocket events under a
|
|
39
|
+
* specific namespace.
|
|
40
|
+
*
|
|
41
|
+
* @param {string} path - The namespace path for websocket connections.
|
|
42
|
+
* @returns {Function} - The decorator function.
|
|
43
|
+
*/
|
|
44
|
+
function Namespace(path) {
|
|
45
|
+
return function internalDecorator(target) {
|
|
46
|
+
const meta = initializeMetadata(target.prototype);
|
|
47
|
+
meta.__meta = {
|
|
48
|
+
...meta?.__meta,
|
|
49
|
+
namespace: path
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/Types/WebsocketTypes.ts
|
|
56
|
+
let WebsocketTypes;
|
|
57
|
+
(function(_WebsocketTypes) {
|
|
58
|
+
let HandlerAction = /* @__PURE__ */ function(HandlerAction$1) {
|
|
59
|
+
HandlerAction$1["CONNECTION"] = "connection";
|
|
60
|
+
HandlerAction$1["MESSAGE"] = "message";
|
|
61
|
+
return HandlerAction$1;
|
|
62
|
+
}({});
|
|
63
|
+
_WebsocketTypes.HandlerAction = HandlerAction;
|
|
64
|
+
})(WebsocketTypes || (WebsocketTypes = {}));
|
|
65
|
+
|
|
66
|
+
//#endregion
|
|
67
|
+
//#region src/Symbols/WebsocketSymbols.ts
|
|
68
|
+
const $WebsocketService = Identity("WebsocketService");
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
//#region ../../node_modules/.pnpm/@oxc-project+runtime@0.77.3/node_modules/@oxc-project/runtime/src/helpers/decorate.js
|
|
72
|
+
var require_decorate = __commonJS({ "../../node_modules/.pnpm/@oxc-project+runtime@0.77.3/node_modules/@oxc-project/runtime/src/helpers/decorate.js"(exports, module) {
|
|
73
|
+
function __decorate(decorators, target, key, desc) {
|
|
74
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
75
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
76
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
77
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
78
|
+
}
|
|
79
|
+
module.exports = __decorate, module.exports.__esModule = true, module.exports["default"] = module.exports;
|
|
80
|
+
} });
|
|
81
|
+
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/Decorators/Message.ts
|
|
84
|
+
var import_decorate$5 = __toESM(require_decorate(), 1);
|
|
85
|
+
/**
|
|
86
|
+
* A decorator class for listening to websocket messages under
|
|
87
|
+
* a specific event.
|
|
88
|
+
*
|
|
89
|
+
* This class extends the BaseDecorator and is used to listen
|
|
90
|
+
* to websocket messages under a specific event.
|
|
91
|
+
*
|
|
92
|
+
* @extends {BaseDecorator<MessageDecoratorOptions>}
|
|
93
|
+
*/
|
|
94
|
+
var MessageDecorator = class extends BaseDecorator {
|
|
95
|
+
gWebsocketService;
|
|
96
|
+
created() {
|
|
97
|
+
if (!this.gWebsocketService) {
|
|
98
|
+
console.warn("MessageDecorator::WebsocketService is not registered");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const meta = initializeMetadata(this.prototype);
|
|
102
|
+
const method = initializeMetadataMethod(this.prototype, this.propertyName);
|
|
103
|
+
const namespace = meta?.__meta?.namespace;
|
|
104
|
+
if (!namespace) {
|
|
105
|
+
console.warn("MessageDecorator::Unable to find namespace. Did you use @Namespace()?");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
method.meta = {
|
|
109
|
+
...method.meta,
|
|
110
|
+
event: this.options.event
|
|
111
|
+
};
|
|
112
|
+
const originalMethod = this.instance[this.propertyName].bind(this.instance);
|
|
113
|
+
this.gWebsocketService.registerHandler(WebsocketTypes.HandlerAction.MESSAGE, namespace, {
|
|
114
|
+
callback: originalMethod,
|
|
115
|
+
event: this.options.event,
|
|
116
|
+
schema: this.options.validationSchema
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
(0, import_decorate$5.default)([InjectOptional($WebsocketService)], MessageDecorator.prototype, "gWebsocketService", void 0);
|
|
121
|
+
/**
|
|
122
|
+
* A decorator function for listening to websocket messages under a specific event.
|
|
123
|
+
*
|
|
124
|
+
* This function creates an instance of the MessageDecorator class and registers a handler for websocket messages under
|
|
125
|
+
* the specified event and optional validation schema.
|
|
126
|
+
*
|
|
127
|
+
* @param {MessageDecoratorOptions} params - The options for the message handler, including event and optional validation schema.
|
|
128
|
+
* @returns {Function} - The decorator function.
|
|
129
|
+
*/
|
|
130
|
+
function Message(params) {
|
|
131
|
+
return createDecorator(MessageDecorator, params);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/Decorators/Emit.ts
|
|
136
|
+
var import_decorate$4 = __toESM(require_decorate(), 1);
|
|
137
|
+
/**
|
|
138
|
+
* A decorator class for emitting websocket messages to the peer.
|
|
139
|
+
*
|
|
140
|
+
* This class extends the BaseDecorator and is used to emit the result of
|
|
141
|
+
* your function as a websocket message to the peer.
|
|
142
|
+
*
|
|
143
|
+
* @extends {BaseDecorator<EmitDecoratorOptions>}
|
|
144
|
+
*/
|
|
145
|
+
var EmitDecorator = class extends BaseDecorator {
|
|
146
|
+
gWebsocketService;
|
|
147
|
+
created() {
|
|
148
|
+
if (!this.gWebsocketService) {
|
|
149
|
+
console.warn("EmitDecorator::WebsocketService is not registered");
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
initializeMetadata(this.prototype);
|
|
153
|
+
initializeMetadataMethod(this.prototype, this.propertyName);
|
|
154
|
+
const originalMethod = this.instance[this.propertyName];
|
|
155
|
+
this.instance[this.propertyName] = async (incomingMessage, peer) => {
|
|
156
|
+
const result = await originalMethod.call(this.instance, incomingMessage, peer);
|
|
157
|
+
this.gWebsocketService.emit(peer, {
|
|
158
|
+
event: this.options.event,
|
|
159
|
+
data: result
|
|
160
|
+
});
|
|
161
|
+
return result;
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
(0, import_decorate$4.default)([InjectOptional($WebsocketService)], EmitDecorator.prototype, "gWebsocketService", void 0);
|
|
166
|
+
/**
|
|
167
|
+
* A decorator function for emitting websocket messages to the peer.
|
|
168
|
+
*
|
|
169
|
+
* This function creates an instance of the EmitDecorator class and emits the result of the decorated method as a
|
|
170
|
+
* websocket message to the peer under the specified event.
|
|
171
|
+
*
|
|
172
|
+
* @param {string} event - The event name for the emitted websocket message.
|
|
173
|
+
* @returns {Function} - The decorator function.
|
|
174
|
+
*/
|
|
175
|
+
function Emit(event) {
|
|
176
|
+
return createDecorator(EmitDecorator, { event });
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
//#endregion
|
|
180
|
+
//#region src/Decorators/Broadcast.ts
|
|
181
|
+
var import_decorate$3 = __toESM(require_decorate(), 1);
|
|
182
|
+
/**
|
|
183
|
+
* A decorator class for broadcasting websocket messages to everyone
|
|
184
|
+
* on the namespace (including the peer).
|
|
185
|
+
*
|
|
186
|
+
* This class extends the BaseDecorator and is used to emit the result of
|
|
187
|
+
* your function as a websocket message to everyone on the namespace.
|
|
188
|
+
*
|
|
189
|
+
* @extends {BaseDecorator<BroadcastDecoratorOptions>}
|
|
190
|
+
*/
|
|
191
|
+
var BroadcastDecorator = class extends BaseDecorator {
|
|
192
|
+
gWebsocketService;
|
|
193
|
+
created() {
|
|
194
|
+
if (!this.gWebsocketService) {
|
|
195
|
+
console.warn("BroadcastDecorator::WebsocketService is not registered");
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
initializeMetadata(this.prototype);
|
|
199
|
+
initializeMetadataMethod(this.prototype, this.propertyName);
|
|
200
|
+
const originalMethod = this.instance[this.propertyName];
|
|
201
|
+
this.instance[this.propertyName] = async (incomingMessage, peer) => {
|
|
202
|
+
const result = await originalMethod.call(this.instance, incomingMessage, peer);
|
|
203
|
+
this.gWebsocketService.broadcast(peer, {
|
|
204
|
+
event: this.options.event,
|
|
205
|
+
data: result
|
|
206
|
+
});
|
|
207
|
+
return result;
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
(0, import_decorate$3.default)([InjectOptional($WebsocketService)], BroadcastDecorator.prototype, "gWebsocketService", void 0);
|
|
212
|
+
/**
|
|
213
|
+
* A decorator function for broadcasting websocket messages to everyone on the namespace (including the peer).
|
|
214
|
+
*
|
|
215
|
+
* This function creates an instance of the BroadcastDecorator class and emits the result of the decorated method as a
|
|
216
|
+
* websocket message to everyone on the namespace under the specified event.
|
|
217
|
+
*
|
|
218
|
+
* @param {string} event - The event name for the broadcasted websocket message.
|
|
219
|
+
* @returns {Function} - The decorator function.
|
|
220
|
+
*/
|
|
221
|
+
function Broadcast(event) {
|
|
222
|
+
return createDecorator(BroadcastDecorator, { event });
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/Decorators/BroadcastOthers.ts
|
|
227
|
+
var import_decorate$2 = __toESM(require_decorate(), 1);
|
|
228
|
+
/**
|
|
229
|
+
* A decorator class for broadcasting websocket messages to everyone
|
|
230
|
+
* on the namespace (except the peer).
|
|
231
|
+
*
|
|
232
|
+
* This class extends the BaseDecorator and is used to emit the result of
|
|
233
|
+
* your function as a websocket message to everyone on the namespace
|
|
234
|
+
* (except the peer).
|
|
235
|
+
*
|
|
236
|
+
* @extends {BaseDecorator<BroadcastOthersDecoratorOptions>}
|
|
237
|
+
*/
|
|
238
|
+
var BroadcastOthersDecorator = class extends BaseDecorator {
|
|
239
|
+
gWebsocketService;
|
|
240
|
+
created() {
|
|
241
|
+
if (!this.gWebsocketService) {
|
|
242
|
+
console.warn("BroadcastOthersDecorator::WebsocketService is not registered");
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
initializeMetadata(this.prototype);
|
|
246
|
+
initializeMetadataMethod(this.prototype, this.propertyName);
|
|
247
|
+
const originalMethod = this.instance[this.propertyName];
|
|
248
|
+
this.instance[this.propertyName] = async (incomingMessage, peer) => {
|
|
249
|
+
const result = await originalMethod.call(this.instance, incomingMessage, peer);
|
|
250
|
+
this.gWebsocketService.broadcastOthers(peer, {
|
|
251
|
+
event: this.options.event,
|
|
252
|
+
data: result
|
|
253
|
+
});
|
|
254
|
+
return result;
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
};
|
|
258
|
+
(0, import_decorate$2.default)([InjectOptional($WebsocketService)], BroadcastOthersDecorator.prototype, "gWebsocketService", void 0);
|
|
259
|
+
/**
|
|
260
|
+
* A decorator function for broadcasting websocket messages to everyone on the namespace (except the peer).
|
|
261
|
+
*
|
|
262
|
+
* This function creates an instance of the BroadcastOthersDecorator class and emits the result of the decorated method
|
|
263
|
+
* as a websocket message to everyone on the namespace (except the peer) under the specified event.
|
|
264
|
+
*
|
|
265
|
+
* @param {string} event - The event name for the broadcasted websocket message.
|
|
266
|
+
* @returns {Function} - The decorator function.
|
|
267
|
+
*/
|
|
268
|
+
function BroadcastOthers(event) {
|
|
269
|
+
return createDecorator(BroadcastOthersDecorator, { event });
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
//#endregion
|
|
273
|
+
//#region src/Decorators/OnConnectionAttempt.ts
|
|
274
|
+
var import_decorate$1 = __toESM(require_decorate(), 1);
|
|
275
|
+
/**
|
|
276
|
+
* A decorator class for handling websocket connection attempts.
|
|
277
|
+
*
|
|
278
|
+
* This class extends the BaseDecorator and is used to handle a
|
|
279
|
+
* websocket connection attempt to a namespace.
|
|
280
|
+
*
|
|
281
|
+
* If your function throws, or returns false, the connection
|
|
282
|
+
* will not be accepted.
|
|
283
|
+
*
|
|
284
|
+
* The decorated function will receive the following parameters:
|
|
285
|
+
*
|
|
286
|
+
* @param {Record<string, unknown>} params - The connection query parameters.
|
|
287
|
+
* @param {Request} request - The original HTTP request.
|
|
288
|
+
*
|
|
289
|
+
* @extends {BaseDecorator}
|
|
290
|
+
*/
|
|
291
|
+
var OnConnectionAttemptDecorator = class extends BaseDecorator {
|
|
292
|
+
gWebsocketService;
|
|
293
|
+
created() {
|
|
294
|
+
if (!this.gWebsocketService) {
|
|
295
|
+
console.warn("OnConnectionAttemptDecorator::WebsocketService is not registered");
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
const meta = initializeMetadata(this.prototype);
|
|
299
|
+
initializeMetadataMethod(this.prototype, this.propertyName);
|
|
300
|
+
const namespace = meta?.__meta?.namespace;
|
|
301
|
+
if (!namespace) {
|
|
302
|
+
console.warn("OnConnectionAttemptDecorator::Unable to find namespace. Did you use @Namespace()?");
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const originalMethod = this.instance[this.propertyName].bind(this.instance);
|
|
306
|
+
this.gWebsocketService.registerHandler(WebsocketTypes.HandlerAction.CONNECTION, namespace, { callback: originalMethod });
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
(0, import_decorate$1.default)([InjectOptional($WebsocketService)], OnConnectionAttemptDecorator.prototype, "gWebsocketService", void 0);
|
|
310
|
+
/**
|
|
311
|
+
* A decorator function for handling websocket connection attempts to a namespace.
|
|
312
|
+
*
|
|
313
|
+
* This function creates an instance of the OnConnectionAttemptDecorator class and registers a handler for websocket
|
|
314
|
+
* connection attempts under the namespace. If the decorated function throws or returns false, the connection will not
|
|
315
|
+
* be accepted.
|
|
316
|
+
*
|
|
317
|
+
* The decorated function will receive the following parameters:
|
|
318
|
+
* - params: {Record<string, unknown>} The connection query parameters.
|
|
319
|
+
* - request: {Request} The original HTTP request.
|
|
320
|
+
*
|
|
321
|
+
* @returns {Function} - The decorator function.
|
|
322
|
+
*/
|
|
323
|
+
function OnConnectionAttempt() {
|
|
324
|
+
return createDecorator(OnConnectionAttemptDecorator, void 0);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/Services/WebsocketService.ts
|
|
329
|
+
var import_decorate = __toESM(require_decorate(), 1);
|
|
330
|
+
/**
|
|
331
|
+
* WebsocketService class responsible for dealing with Websocket connections.
|
|
332
|
+
*
|
|
333
|
+
* This class is responsible for:
|
|
334
|
+
* - Registering namespaces and accepting websocket connections for them
|
|
335
|
+
* - Registering event handlers and handling them
|
|
336
|
+
*/
|
|
337
|
+
var WebsocketService = class {
|
|
338
|
+
/**
|
|
339
|
+
* Http Server for injecting the server plugin
|
|
340
|
+
*/
|
|
341
|
+
gHttpServer;
|
|
342
|
+
/**
|
|
343
|
+
* Validation provider for running the schema validation
|
|
344
|
+
*/
|
|
345
|
+
gValidationProvider;
|
|
346
|
+
gLogger;
|
|
347
|
+
/**
|
|
348
|
+
* Internal namespace registry
|
|
349
|
+
*/
|
|
350
|
+
fNamespaces = {};
|
|
351
|
+
/**
|
|
352
|
+
* Internal handlers registry
|
|
353
|
+
*/
|
|
354
|
+
fHandlers = {
|
|
355
|
+
[WebsocketTypes.HandlerAction.CONNECTION]: {},
|
|
356
|
+
[WebsocketTypes.HandlerAction.MESSAGE]: {}
|
|
357
|
+
};
|
|
358
|
+
/**
|
|
359
|
+
* Register a new namespace.
|
|
360
|
+
*
|
|
361
|
+
* @param {string} path - The namespace path to register.
|
|
362
|
+
* @returns {void}
|
|
363
|
+
*/
|
|
364
|
+
registerNamespace(path) {
|
|
365
|
+
if (!this?.fNamespaces?.[path.toLowerCase()]) this.fNamespaces[path.toLowerCase()] = [];
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Register a new handler for a namespace or event.
|
|
369
|
+
*
|
|
370
|
+
* @param {WebsocketTypes.HandlerAction} action - The handler action type.
|
|
371
|
+
* @param {string} namespace - The namespace to register the handler for.
|
|
372
|
+
* @param {WebsocketTypes.HandlerAttributes} handler - The handler attributes.
|
|
373
|
+
* @returns {void}
|
|
374
|
+
*/
|
|
375
|
+
registerHandler(action, namespace, handler) {
|
|
376
|
+
const normalizedNamespace = namespace.toLowerCase();
|
|
377
|
+
if (action === WebsocketTypes.HandlerAction.CONNECTION) this.fHandlers[action][normalizedNamespace] = handler;
|
|
378
|
+
if (action === WebsocketTypes.HandlerAction.MESSAGE) {
|
|
379
|
+
const event = handler.event;
|
|
380
|
+
if (!event) {
|
|
381
|
+
this.gLogger?.warn("WebsocketService::registerHandler", `Cannot register message handler without an event name for namespace "${normalizedNamespace}".`);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (!this.fHandlers[action][normalizedNamespace]) this.fHandlers[action][normalizedNamespace] = {};
|
|
385
|
+
this.fHandlers[action][normalizedNamespace][event] = handler;
|
|
386
|
+
}
|
|
387
|
+
this.registerNamespace(normalizedNamespace);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Broadcast a message to all peers in the same namespace (including the sender).
|
|
391
|
+
*
|
|
392
|
+
* @param {Peer} peer - The sender peer (used to determine the namespace).
|
|
393
|
+
* @param {unknown} message - The message to broadcast.
|
|
394
|
+
* @returns {void}
|
|
395
|
+
*/
|
|
396
|
+
broadcast(peer, message) {
|
|
397
|
+
const namespace = peer.namespace?.toLowerCase();
|
|
398
|
+
if (!namespace) return;
|
|
399
|
+
const peers = this.fNamespaces[namespace];
|
|
400
|
+
if (!peers || peers.length === 0) return;
|
|
401
|
+
for (const p of peers) p.send(message);
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Emit a message to a single peer.
|
|
405
|
+
*
|
|
406
|
+
* @param {Peer} peer - The peer to send the message to.
|
|
407
|
+
* @param {unknown} message - The message to send.
|
|
408
|
+
* @returns {void}
|
|
409
|
+
*/
|
|
410
|
+
emit(peer, message) {
|
|
411
|
+
peer.send(message);
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Broadcast a message to all peers in the same namespace except the sender.
|
|
415
|
+
*
|
|
416
|
+
* @param {Peer} peer - The sender peer (used to determine the namespace).
|
|
417
|
+
* @param {unknown} message - The message to broadcast.
|
|
418
|
+
* @returns {void}
|
|
419
|
+
*/
|
|
420
|
+
broadcastOthers(peer, message) {
|
|
421
|
+
const namespace = peer.namespace?.toLowerCase();
|
|
422
|
+
if (!namespace) return;
|
|
423
|
+
const peers = this.fNamespaces[namespace];
|
|
424
|
+
if (!peers || peers.length === 0) return;
|
|
425
|
+
for (const p of peers) if (p.id !== peer.id) p.send(message);
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Initialize the websocket service and attach the server plugin.
|
|
429
|
+
*
|
|
430
|
+
* @returns {void}
|
|
431
|
+
*/
|
|
432
|
+
initialize() {
|
|
433
|
+
const hooks = defineHooks({
|
|
434
|
+
upgrade: async (request) => {
|
|
435
|
+
const url = new URL(request.url);
|
|
436
|
+
const namespace = url.pathname;
|
|
437
|
+
const parameters = Object.fromEntries(url.searchParams.entries());
|
|
438
|
+
const isNamespaceRegistered = !!this.fNamespaces?.[namespace?.toLowerCase()];
|
|
439
|
+
if (!isNamespaceRegistered) {
|
|
440
|
+
this.gLogger?.warn("WebsocketService::initialize", `Namespace "${namespace}" is not registered. Connection rejected.`);
|
|
441
|
+
return new Response("Namespace not registered", { status: 403 });
|
|
442
|
+
}
|
|
443
|
+
const handler = this.fHandlers[WebsocketTypes.HandlerAction.CONNECTION]?.[namespace];
|
|
444
|
+
if (handler) try {
|
|
445
|
+
const result = await handler.callback(parameters, request);
|
|
446
|
+
if (result === false) return new Response("Unauthorized", { status: 403 });
|
|
447
|
+
} catch (error) {
|
|
448
|
+
if (error instanceof Error) return new Response(error.message, { status: 403 });
|
|
449
|
+
return new Response("Unknown error", { status: 403 });
|
|
450
|
+
}
|
|
451
|
+
return {
|
|
452
|
+
namespace,
|
|
453
|
+
headers: {}
|
|
454
|
+
};
|
|
455
|
+
},
|
|
456
|
+
open: async (peer) => {
|
|
457
|
+
const namespace = peer.namespace?.toLowerCase();
|
|
458
|
+
if (namespace && this.fNamespaces[namespace]) this.fNamespaces[namespace].push(peer);
|
|
459
|
+
},
|
|
460
|
+
message: async (peer, message) => {
|
|
461
|
+
await this.handleMessage(peer, message);
|
|
462
|
+
},
|
|
463
|
+
close: async (peer) => {
|
|
464
|
+
const namespace = peer.namespace?.toLowerCase();
|
|
465
|
+
if (namespace && this.fNamespaces[namespace]) {
|
|
466
|
+
const peers = this.fNamespaces[namespace];
|
|
467
|
+
this.fNamespaces[namespace] = peers.filter((p) => p.id !== peer.id);
|
|
468
|
+
}
|
|
469
|
+
},
|
|
470
|
+
error: async (peer, error) => {
|
|
471
|
+
this.gLogger?.error("WebsocketService::initialize", `Error: ${error.message}`, { peer });
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
const serverPlugin = plugin(hooks);
|
|
475
|
+
this.gHttpServer.addPlugin(serverPlugin);
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Handle an incoming websocket message for a peer.
|
|
479
|
+
*
|
|
480
|
+
* @param {Peer} peer - The peer receiving the message.
|
|
481
|
+
* @param {Message} rawMessage - The raw websocket message.
|
|
482
|
+
* @returns {Promise<void>}
|
|
483
|
+
*/
|
|
484
|
+
async handleMessage(peer, rawMessage) {
|
|
485
|
+
try {
|
|
486
|
+
const msg = JSON.parse(rawMessage.text());
|
|
487
|
+
const namespace = peer.namespace?.toLowerCase();
|
|
488
|
+
const event = msg.event;
|
|
489
|
+
const data = msg.data;
|
|
490
|
+
const handler = this.fHandlers[WebsocketTypes.HandlerAction.MESSAGE]?.[namespace]?.[event];
|
|
491
|
+
if (!handler) {
|
|
492
|
+
this.gLogger?.warn("WebsocketService::handleMessage", `No message handler for event "${event}" in namespace "${namespace}"`);
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (handler.schema) {
|
|
496
|
+
if (!this.gValidationProvider) {
|
|
497
|
+
this.gLogger?.warn("WebsocketService::handleMessage", "ValidationProvider is not registered");
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
const result = await this.gValidationProvider.validate(handler.schema, data);
|
|
501
|
+
if (result?.issues?.length) throw new BadRequestError("Websocket message validation error", result.issues);
|
|
502
|
+
}
|
|
503
|
+
await handler.callback(data, peer);
|
|
504
|
+
} catch (error) {
|
|
505
|
+
this.gLogger?.error("WebsocketService::handleMessage", `Failed to process message: ${error}`);
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
(0, import_decorate.default)([Inject(HttpServer)], WebsocketService.prototype, "gHttpServer", void 0);
|
|
510
|
+
(0, import_decorate.default)([InjectOptional(ValidationProvider)], WebsocketService.prototype, "gValidationProvider", void 0);
|
|
511
|
+
(0, import_decorate.default)([InjectOptional(Logger)], WebsocketService.prototype, "gLogger", void 0);
|
|
512
|
+
|
|
513
|
+
//#endregion
|
|
514
|
+
//#region src/Plugins/WebsocketPlugin.ts
|
|
515
|
+
/**
|
|
516
|
+
* Websocket Plugin for Vercube framework
|
|
517
|
+
*
|
|
518
|
+
* Enables websocket connections and use of decorators related
|
|
519
|
+
* to the Websocket package.
|
|
520
|
+
*
|
|
521
|
+
* @example
|
|
522
|
+
* ```ts
|
|
523
|
+
* import { createApp } from '@vercube/core';
|
|
524
|
+
* import { WebsocketPlugin } from '@vercube/ws';
|
|
525
|
+
*
|
|
526
|
+
* const app = createApp({
|
|
527
|
+
* setup: async (app) => {
|
|
528
|
+
* app.addPlugin(WebsocketPlugin);
|
|
529
|
+
* }
|
|
530
|
+
* });
|
|
531
|
+
* ```
|
|
532
|
+
*
|
|
533
|
+
* @see {@link https://vercube.dev} for full documentation
|
|
534
|
+
*/
|
|
535
|
+
var WebsocketPlugin = class extends BasePlugin {
|
|
536
|
+
/**
|
|
537
|
+
* The name of the plugin.
|
|
538
|
+
* @override
|
|
539
|
+
*/
|
|
540
|
+
name = "WebsocketPlugin";
|
|
541
|
+
/**
|
|
542
|
+
* Method to use the plugin with the given app.
|
|
543
|
+
* @param {App} app - The application instance.
|
|
544
|
+
* @returns {void | Promise<void>}
|
|
545
|
+
* @override
|
|
546
|
+
*/
|
|
547
|
+
use(app, options) {
|
|
548
|
+
app.container.bind($WebsocketService, WebsocketService);
|
|
549
|
+
app.container.get($WebsocketService).initialize();
|
|
550
|
+
}
|
|
551
|
+
};
|
|
552
|
+
|
|
553
|
+
//#endregion
|
|
554
|
+
export { $WebsocketService, Broadcast, BroadcastOthers, Emit, Message, Namespace, OnConnectionAttempt, WebsocketPlugin, WebsocketService, WebsocketTypes };
|
package/package.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vercube/ws",
|
|
3
|
+
"version": "0.0.19",
|
|
4
|
+
"description": "Websocket module for Vercube framework",
|
|
5
|
+
"repository": "@vercube/ws",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.mjs",
|
|
10
|
+
"module": "./dist/index.mjs",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": "./dist/index.mjs",
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"types": "./dist/index.d.mts",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"zod": "4.0.10"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"crossws": "0.4.1",
|
|
25
|
+
"srvx": "0.8.2",
|
|
26
|
+
"@vercube/core": "0.0.19",
|
|
27
|
+
"@vercube/logger": "0.0.19",
|
|
28
|
+
"@vercube/di": "0.0.19"
|
|
29
|
+
},
|
|
30
|
+
"publishConfig": {
|
|
31
|
+
"access": "public"
|
|
32
|
+
}
|
|
33
|
+
}
|