create-phoenixjs 0.1.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/index.ts +196 -0
- package/package.json +31 -0
- package/template/README.md +62 -0
- package/template/app/controllers/ExampleController.ts +61 -0
- package/template/artisan +2 -0
- package/template/bootstrap/app.ts +44 -0
- package/template/bunfig.toml +7 -0
- package/template/config/database.ts +25 -0
- package/template/config/plugins.ts +7 -0
- package/template/config/security.ts +158 -0
- package/template/framework/cli/Command.ts +17 -0
- package/template/framework/cli/ConsoleApplication.ts +55 -0
- package/template/framework/cli/artisan.ts +16 -0
- package/template/framework/cli/commands/MakeControllerCommand.ts +41 -0
- package/template/framework/cli/commands/MakeMiddlewareCommand.ts +41 -0
- package/template/framework/cli/commands/MakeModelCommand.ts +36 -0
- package/template/framework/cli/commands/MakeValidatorCommand.ts +42 -0
- package/template/framework/controller/Controller.ts +222 -0
- package/template/framework/core/Application.ts +208 -0
- package/template/framework/core/Container.ts +100 -0
- package/template/framework/core/Kernel.ts +297 -0
- package/template/framework/database/DatabaseAdapter.ts +18 -0
- package/template/framework/database/PrismaAdapter.ts +65 -0
- package/template/framework/database/SqlAdapter.ts +117 -0
- package/template/framework/gateway/Gateway.ts +109 -0
- package/template/framework/gateway/GatewayManager.ts +150 -0
- package/template/framework/gateway/WebSocketAdapter.ts +159 -0
- package/template/framework/gateway/WebSocketGateway.ts +182 -0
- package/template/framework/http/Request.ts +608 -0
- package/template/framework/http/Response.ts +525 -0
- package/template/framework/http/Server.ts +161 -0
- package/template/framework/http/UploadedFile.ts +145 -0
- package/template/framework/middleware/Middleware.ts +50 -0
- package/template/framework/middleware/Pipeline.ts +89 -0
- package/template/framework/plugin/Plugin.ts +26 -0
- package/template/framework/plugin/PluginManager.ts +61 -0
- package/template/framework/routing/RouteRegistry.ts +185 -0
- package/template/framework/routing/Router.ts +280 -0
- package/template/framework/security/CorsMiddleware.ts +151 -0
- package/template/framework/security/CsrfMiddleware.ts +121 -0
- package/template/framework/security/HelmetMiddleware.ts +138 -0
- package/template/framework/security/InputSanitizerMiddleware.ts +134 -0
- package/template/framework/security/RateLimiterMiddleware.ts +189 -0
- package/template/framework/security/SecurityManager.ts +128 -0
- package/template/framework/validation/Validator.ts +482 -0
- package/template/package.json +24 -0
- package/template/routes/api.ts +56 -0
- package/template/server.ts +29 -0
- package/template/tsconfig.json +49 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhoenixJS - GatewayManager
|
|
3
|
+
*
|
|
4
|
+
* Manages gateway registration, transport adapters, and lifecycle.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Application } from '@framework/core/Application';
|
|
8
|
+
import type { Gateway, GatewayTransport, TransportAdapter } from './Gateway';
|
|
9
|
+
|
|
10
|
+
export class GatewayManager {
|
|
11
|
+
private app: Application;
|
|
12
|
+
private gateways: Map<string, Gateway> = new Map();
|
|
13
|
+
private adapters: Map<GatewayTransport, TransportAdapter> = new Map();
|
|
14
|
+
private booted = false;
|
|
15
|
+
|
|
16
|
+
constructor(app: Application) {
|
|
17
|
+
this.app = app;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register a gateway
|
|
22
|
+
*/
|
|
23
|
+
register(gateway: Gateway): this {
|
|
24
|
+
if (this.gateways.has(gateway.name)) {
|
|
25
|
+
throw new Error(`Gateway "${gateway.name}" is already registered`);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
this.gateways.set(gateway.name, gateway);
|
|
29
|
+
gateway.register(this.app);
|
|
30
|
+
|
|
31
|
+
// If already booted, boot the gateway immediately
|
|
32
|
+
if (this.booted && gateway.boot) {
|
|
33
|
+
gateway.boot(this.app);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Register a transport adapter
|
|
41
|
+
*/
|
|
42
|
+
registerAdapter(adapter: TransportAdapter): this {
|
|
43
|
+
if (this.adapters.has(adapter.transport)) {
|
|
44
|
+
throw new Error(`Transport adapter for "${adapter.transport}" is already registered`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.adapters.set(adapter.transport, adapter);
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Get a gateway by name
|
|
53
|
+
*/
|
|
54
|
+
get(name: string): Gateway | undefined {
|
|
55
|
+
return this.gateways.get(name);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Get a transport adapter
|
|
60
|
+
*/
|
|
61
|
+
getAdapter(transport: GatewayTransport): TransportAdapter | undefined {
|
|
62
|
+
return this.adapters.get(transport);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Check if a gateway exists
|
|
67
|
+
*/
|
|
68
|
+
has(name: string): boolean {
|
|
69
|
+
return this.gateways.has(name);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Get all registered gateways
|
|
74
|
+
*/
|
|
75
|
+
all(): Gateway[] {
|
|
76
|
+
return Array.from(this.gateways.values());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get gateways by transport type
|
|
81
|
+
*/
|
|
82
|
+
getByTransport(transport: GatewayTransport): Gateway[] {
|
|
83
|
+
return this.all().filter(g => g.transport === transport);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Find a gateway by path
|
|
88
|
+
*/
|
|
89
|
+
findByPath(path: string): Gateway | undefined {
|
|
90
|
+
return this.all().find(g => g.path === path);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Boot all gateways
|
|
95
|
+
*/
|
|
96
|
+
boot(): void {
|
|
97
|
+
if (this.booted) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
for (const gateway of this.gateways.values()) {
|
|
102
|
+
if (gateway.boot) {
|
|
103
|
+
gateway.boot(this.app);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.booted = true;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Start all transport adapters
|
|
112
|
+
*/
|
|
113
|
+
start(): void {
|
|
114
|
+
// Group gateways by transport
|
|
115
|
+
const transports = new Set(this.all().map(g => g.transport));
|
|
116
|
+
|
|
117
|
+
for (const transport of transports) {
|
|
118
|
+
const adapter = this.adapters.get(transport);
|
|
119
|
+
if (adapter) {
|
|
120
|
+
const gateways = this.getByTransport(transport);
|
|
121
|
+
adapter.start(gateways);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Stop all transport adapters
|
|
128
|
+
*/
|
|
129
|
+
stop(): void {
|
|
130
|
+
for (const adapter of this.adapters.values()) {
|
|
131
|
+
if (adapter.isRunning()) {
|
|
132
|
+
adapter.stop();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Check if manager is booted
|
|
139
|
+
*/
|
|
140
|
+
isBooted(): boolean {
|
|
141
|
+
return this.booted;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get gateway count
|
|
146
|
+
*/
|
|
147
|
+
count(): number {
|
|
148
|
+
return this.gateways.size;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhoenixJS - WebSocketAdapter
|
|
3
|
+
*
|
|
4
|
+
* Built-in transport adapter for Bun's native WebSocket support.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ServerWebSocket } from 'bun';
|
|
8
|
+
import type {
|
|
9
|
+
Gateway,
|
|
10
|
+
TransportAdapter,
|
|
11
|
+
WebSocketGatewayInterface,
|
|
12
|
+
WebSocketData,
|
|
13
|
+
GatewayOptions
|
|
14
|
+
} from './Gateway';
|
|
15
|
+
|
|
16
|
+
// Type for Bun server
|
|
17
|
+
type BunServer = ReturnType<typeof Bun.serve>;
|
|
18
|
+
|
|
19
|
+
export class WebSocketAdapter implements TransportAdapter {
|
|
20
|
+
readonly name = 'websocket';
|
|
21
|
+
readonly transport = 'websocket' as const;
|
|
22
|
+
|
|
23
|
+
private gateways: WebSocketGatewayInterface[] = [];
|
|
24
|
+
private server: BunServer | null = null;
|
|
25
|
+
private options: GatewayOptions;
|
|
26
|
+
|
|
27
|
+
constructor(options: GatewayOptions = {}) {
|
|
28
|
+
this.options = {
|
|
29
|
+
idleTimeout: options.idleTimeout ?? 120,
|
|
30
|
+
maxPayloadLength: options.maxPayloadLength ?? 1024 * 1024, // 1MB
|
|
31
|
+
perMessageDeflate: options.perMessageDeflate ?? false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Start the WebSocket adapter
|
|
37
|
+
*/
|
|
38
|
+
start(gateways: Gateway[]): void {
|
|
39
|
+
this.gateways = gateways.filter(
|
|
40
|
+
(g): g is WebSocketGatewayInterface => g.transport === 'websocket'
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Stop the WebSocket adapter
|
|
46
|
+
*/
|
|
47
|
+
stop(): void {
|
|
48
|
+
this.gateways = [];
|
|
49
|
+
this.server = null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Check if adapter is running
|
|
54
|
+
*/
|
|
55
|
+
isRunning(): boolean {
|
|
56
|
+
return this.server !== null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Set the server reference
|
|
61
|
+
*/
|
|
62
|
+
setServer(server: BunServer): void {
|
|
63
|
+
this.server = server;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get the Bun websocket handlers configuration
|
|
68
|
+
*/
|
|
69
|
+
getWebSocketConfig() {
|
|
70
|
+
const self = this;
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
idleTimeout: this.options.idleTimeout,
|
|
74
|
+
maxPayloadLength: this.options.maxPayloadLength,
|
|
75
|
+
perMessageDeflate: this.options.perMessageDeflate,
|
|
76
|
+
|
|
77
|
+
open(ws: ServerWebSocket<WebSocketData>) {
|
|
78
|
+
const gateway = self.findGateway(ws.data.gateway);
|
|
79
|
+
if (gateway?.onOpen) {
|
|
80
|
+
gateway.onOpen(ws);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
message(ws: ServerWebSocket<WebSocketData>, message: string | Buffer) {
|
|
85
|
+
const gateway = self.findGateway(ws.data.gateway);
|
|
86
|
+
if (gateway?.onMessage) {
|
|
87
|
+
gateway.onMessage(ws, message);
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
close(ws: ServerWebSocket<WebSocketData>, code: number, reason: string) {
|
|
92
|
+
const gateway = self.findGateway(ws.data.gateway);
|
|
93
|
+
if (gateway?.onClose) {
|
|
94
|
+
gateway.onClose(ws, code, reason);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
|
|
98
|
+
drain(ws: ServerWebSocket<WebSocketData>) {
|
|
99
|
+
const gateway = self.findGateway(ws.data.gateway);
|
|
100
|
+
if (gateway?.onDrain) {
|
|
101
|
+
gateway.onDrain(ws);
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Handle WebSocket upgrade request
|
|
109
|
+
*/
|
|
110
|
+
handleUpgrade(
|
|
111
|
+
request: Request,
|
|
112
|
+
server: BunServer,
|
|
113
|
+
customData?: Record<string, unknown>
|
|
114
|
+
): boolean {
|
|
115
|
+
const url = new URL(request.url);
|
|
116
|
+
const gateway = this.findGatewayByPath(url.pathname);
|
|
117
|
+
|
|
118
|
+
if (!gateway) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const data: WebSocketData = {
|
|
123
|
+
gateway: gateway.name,
|
|
124
|
+
connectionId: crypto.randomUUID(),
|
|
125
|
+
connectedAt: Date.now(),
|
|
126
|
+
...customData,
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
return server.upgrade(request, { data });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Find a gateway by name
|
|
134
|
+
*/
|
|
135
|
+
findGateway(name: string): WebSocketGatewayInterface | undefined {
|
|
136
|
+
return this.gateways.find(g => g.name === name);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Find a gateway by path
|
|
141
|
+
*/
|
|
142
|
+
findGatewayByPath(path: string): WebSocketGatewayInterface | undefined {
|
|
143
|
+
return this.gateways.find(g => g.path === path);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get all registered gateways
|
|
148
|
+
*/
|
|
149
|
+
getGateways(): WebSocketGatewayInterface[] {
|
|
150
|
+
return this.gateways;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Check if a path has a registered gateway
|
|
155
|
+
*/
|
|
156
|
+
hasGatewayForPath(path: string): boolean {
|
|
157
|
+
return this.findGatewayByPath(path) !== undefined;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PhoenixJS - WebSocketGateway
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for WebSocket gateways with pub/sub support.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ServerWebSocket } from 'bun';
|
|
8
|
+
import type { Application } from '@framework/core/Application';
|
|
9
|
+
import type { WebSocketGatewayInterface, WebSocketData, GatewayOptions } from './Gateway';
|
|
10
|
+
|
|
11
|
+
export abstract class WebSocketGateway implements WebSocketGatewayInterface {
|
|
12
|
+
readonly transport = 'websocket' as const;
|
|
13
|
+
|
|
14
|
+
/** Gateway name - must be unique */
|
|
15
|
+
abstract readonly name: string;
|
|
16
|
+
|
|
17
|
+
/** Gateway path (e.g., '/ws', '/chat') */
|
|
18
|
+
abstract readonly path: string;
|
|
19
|
+
|
|
20
|
+
/** Application instance */
|
|
21
|
+
protected app!: Application;
|
|
22
|
+
|
|
23
|
+
/** Active connections */
|
|
24
|
+
protected connections: Map<string, ServerWebSocket<WebSocketData>> = new Map();
|
|
25
|
+
|
|
26
|
+
/** Gateway options */
|
|
27
|
+
protected options: GatewayOptions = {};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Called when gateway is registered
|
|
31
|
+
*/
|
|
32
|
+
register(app: Application): void {
|
|
33
|
+
this.app = app;
|
|
34
|
+
this.onRegister();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Called after all gateways are registered
|
|
39
|
+
*/
|
|
40
|
+
boot(app: Application): void {
|
|
41
|
+
this.onBoot();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Override to perform actions during registration
|
|
46
|
+
*/
|
|
47
|
+
protected onRegister(): void { }
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Override to perform actions during boot
|
|
51
|
+
*/
|
|
52
|
+
protected onBoot(): void { }
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Called when a connection is opened
|
|
56
|
+
*/
|
|
57
|
+
onOpen(ws: ServerWebSocket<WebSocketData>): void {
|
|
58
|
+
this.connections.set(ws.data.connectionId, ws);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Called when a message is received - override in subclass
|
|
63
|
+
*/
|
|
64
|
+
onMessage(ws: ServerWebSocket<WebSocketData>, message: string | Buffer): void {
|
|
65
|
+
// Override in subclass
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Called when a connection is closed
|
|
70
|
+
*/
|
|
71
|
+
onClose(ws: ServerWebSocket<WebSocketData>, code: number, reason: string): void {
|
|
72
|
+
this.connections.delete(ws.data.connectionId);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Called when an error occurs
|
|
77
|
+
*/
|
|
78
|
+
onError(ws: ServerWebSocket<WebSocketData>, error: Error): void {
|
|
79
|
+
console.error(`[${this.name}] WebSocket error:`, error);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Called when the socket is ready to receive more data
|
|
84
|
+
*/
|
|
85
|
+
onDrain(ws: ServerWebSocket<WebSocketData>): void {
|
|
86
|
+
// Override if needed
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Send a message to a specific connection
|
|
91
|
+
*/
|
|
92
|
+
protected send(ws: ServerWebSocket<WebSocketData>, data: string | Uint8Array): number {
|
|
93
|
+
return ws.send(data as string);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Send JSON data to a connection
|
|
98
|
+
*/
|
|
99
|
+
protected sendJson(ws: ServerWebSocket<WebSocketData>, data: unknown): number {
|
|
100
|
+
return ws.send(JSON.stringify(data));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Subscribe a connection to a topic
|
|
105
|
+
*/
|
|
106
|
+
protected subscribe(ws: ServerWebSocket<WebSocketData>, topic: string): void {
|
|
107
|
+
ws.subscribe(topic);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Unsubscribe a connection from a topic
|
|
112
|
+
*/
|
|
113
|
+
protected unsubscribe(ws: ServerWebSocket<WebSocketData>, topic: string): void {
|
|
114
|
+
ws.unsubscribe(topic);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Publish a message to a topic
|
|
119
|
+
*/
|
|
120
|
+
protected publish(topic: string, data: string | Uint8Array, compress?: boolean): void {
|
|
121
|
+
for (const ws of this.connections.values()) {
|
|
122
|
+
ws.publish(topic, data as string, compress);
|
|
123
|
+
return; // Only need to publish once
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Broadcast a message to all connected clients
|
|
129
|
+
*/
|
|
130
|
+
protected broadcast(data: string | Uint8Array, exclude?: ServerWebSocket<WebSocketData>): void {
|
|
131
|
+
for (const ws of this.connections.values()) {
|
|
132
|
+
if (ws !== exclude) {
|
|
133
|
+
ws.send(data as string);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Broadcast JSON data to all connected clients
|
|
140
|
+
*/
|
|
141
|
+
protected broadcastJson(data: unknown, exclude?: ServerWebSocket<WebSocketData>): void {
|
|
142
|
+
this.broadcast(JSON.stringify(data), exclude);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get all active connections
|
|
147
|
+
*/
|
|
148
|
+
protected getConnections(): ServerWebSocket<WebSocketData>[] {
|
|
149
|
+
return Array.from(this.connections.values());
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Get connection count
|
|
154
|
+
*/
|
|
155
|
+
protected getConnectionCount(): number {
|
|
156
|
+
return this.connections.size;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get a connection by ID
|
|
161
|
+
*/
|
|
162
|
+
protected getConnection(connectionId: string): ServerWebSocket<WebSocketData> | undefined {
|
|
163
|
+
return this.connections.get(connectionId);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Close a connection
|
|
168
|
+
*/
|
|
169
|
+
protected closeConnection(ws: ServerWebSocket<WebSocketData>, code?: number, reason?: string): void {
|
|
170
|
+
ws.close(code, reason);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Close all connections
|
|
175
|
+
*/
|
|
176
|
+
protected closeAll(code?: number, reason?: string): void {
|
|
177
|
+
for (const ws of this.connections.values()) {
|
|
178
|
+
ws.close(code, reason);
|
|
179
|
+
}
|
|
180
|
+
this.connections.clear();
|
|
181
|
+
}
|
|
182
|
+
}
|