@grest-ts/websocket 0.0.22 → 0.0.24
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/README.md +150 -40
- package/dist/src/adapter/NodeSocketAdapter.d.ts +2 -0
- package/dist/src/adapter/NodeSocketAdapter.d.ts.map +1 -1
- package/dist/src/adapter/NodeSocketAdapter.js +6 -0
- package/dist/src/adapter/NodeSocketAdapter.js.map +1 -1
- package/dist/src/client/GGSocketPool.d.ts +21 -0
- package/dist/src/client/GGSocketPool.d.ts.map +1 -1
- package/dist/src/client/GGSocketPool.js +82 -63
- package/dist/src/client/GGSocketPool.js.map +1 -1
- package/dist/src/client/GGWebSocketSchema.createClient.d.ts +154 -0
- package/dist/src/client/GGWebSocketSchema.createClient.d.ts.map +1 -0
- package/dist/src/client/GGWebSocketSchema.createClient.js +345 -0
- package/dist/src/client/GGWebSocketSchema.createClient.js.map +1 -0
- package/dist/src/index-browser.d.ts +2 -1
- package/dist/src/index-browser.d.ts.map +1 -1
- package/dist/src/index-browser.js +3 -1
- package/dist/src/index-browser.js.map +1 -1
- package/dist/src/index-node.d.ts +2 -1
- package/dist/src/index-node.d.ts.map +1 -1
- package/dist/src/index-node.js +2 -1
- package/dist/src/index-node.js.map +1 -1
- package/dist/src/schema/GGWebSocketMiddleware.d.ts +12 -0
- package/dist/src/schema/GGWebSocketMiddleware.d.ts.map +1 -1
- package/dist/src/schema/GGWebSocketMiddleware.js +0 -4
- package/dist/src/schema/GGWebSocketMiddleware.js.map +1 -1
- package/dist/src/schema/GGWebSocketSchema.d.ts +4 -3
- package/dist/src/schema/GGWebSocketSchema.d.ts.map +1 -1
- package/dist/src/schema/GGWebSocketSchema.js +3 -1
- package/dist/src/schema/GGWebSocketSchema.js.map +1 -1
- package/dist/src/schema/webSocketSchema.d.ts +12 -6
- package/dist/src/schema/webSocketSchema.d.ts.map +1 -1
- package/dist/src/schema/webSocketSchema.js +9 -2
- package/dist/src/schema/webSocketSchema.js.map +1 -1
- package/dist/src/server/GGSocketServer.d.ts.map +1 -1
- package/dist/src/server/GGSocketServer.js +36 -2
- package/dist/src/server/GGSocketServer.js.map +1 -1
- package/dist/src/server/GGWebSocketSchema.startServer.d.ts +5 -3
- package/dist/src/server/GGWebSocketSchema.startServer.d.ts.map +1 -1
- package/dist/src/server/GGWebSocketSchema.startServer.js +7 -5
- package/dist/src/server/GGWebSocketSchema.startServer.js.map +1 -1
- package/dist/src/socket/GGSocket.d.ts +13 -1
- package/dist/src/socket/GGSocket.d.ts.map +1 -1
- package/dist/src/socket/GGSocket.js +52 -2
- package/dist/src/socket/GGSocket.js.map +1 -1
- package/dist/src/socket/SocketAdapter.d.ts +11 -0
- package/dist/src/socket/SocketAdapter.d.ts.map +1 -1
- package/dist/testkit/client/GGWebSocketSchema.callOn.d.ts +1 -1
- package/dist/testkit/client/GGWebSocketSchema.callOn.d.ts.map +1 -1
- package/dist/tsconfig.publish.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/src/adapter/NodeSocketAdapter.ts +8 -0
- package/src/client/GGSocketPool.ts +90 -73
- package/src/client/GGWebSocketSchema.createClient.ts +534 -0
- package/src/index-browser.ts +5 -2
- package/src/index-node.ts +2 -1
- package/src/schema/GGWebSocketMiddleware.ts +14 -0
- package/src/schema/GGWebSocketSchema.ts +7 -3
- package/src/schema/webSocketSchema.ts +18 -8
- package/src/server/GGSocketServer.ts +51 -2
- package/src/server/GGWebSocketSchema.startServer.ts +14 -10
- package/src/socket/GGSocket.ts +56 -2
- package/src/socket/SocketAdapter.ts +13 -0
- package/dist/src/client/GGSocketClient.d.ts +0 -10
- package/dist/src/client/GGSocketClient.d.ts.map +0 -1
- package/dist/src/client/GGSocketClient.js +0 -17
- package/dist/src/client/GGSocketClient.js.map +0 -1
- package/src/client/GGSocketClient.ts +0 -25
|
@@ -29,6 +29,53 @@ export interface GGSocketServerConfig<TContext, Query> {
|
|
|
29
29
|
middlewares: readonly GGWebSocketMiddleware[];
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
/**
|
|
33
|
+
* Shared path-dispatching upgrade registry per http.Server.
|
|
34
|
+
*
|
|
35
|
+
* The `ws` library's `{server, path}` mode aborts the HTTP handshake with 400
|
|
36
|
+
* whenever the upgrade path doesn't match — so attaching two WebSocketServer
|
|
37
|
+
* instances to the same http.Server causes whichever one fires first to reject
|
|
38
|
+
* requests meant for the other. We install a single shared 'upgrade' listener
|
|
39
|
+
* on each http.Server and dispatch by path instead.
|
|
40
|
+
*/
|
|
41
|
+
interface WsRegistry {
|
|
42
|
+
readonly wssByPath: Map<string, WebSocketServer>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const wsRegistryByHttpServer = new WeakMap<http.Server, WsRegistry>();
|
|
46
|
+
|
|
47
|
+
function attachUpgradeDispatch(httpServer: http.Server, path: string, wss: WebSocketServer): void {
|
|
48
|
+
let registry = wsRegistryByHttpServer.get(httpServer);
|
|
49
|
+
if (!registry) {
|
|
50
|
+
registry = {wssByPath: new Map()};
|
|
51
|
+
wsRegistryByHttpServer.set(httpServer, registry);
|
|
52
|
+
const captured = registry;
|
|
53
|
+
httpServer.on('upgrade', (req, socket, head) => {
|
|
54
|
+
const pathname = (req.url ?? '').split('?')[0];
|
|
55
|
+
const matched = captured.wssByPath.get(pathname);
|
|
56
|
+
if (matched) {
|
|
57
|
+
matched.handleUpgrade(req, socket, head, (ws) => {
|
|
58
|
+
matched.emit('connection', ws, req);
|
|
59
|
+
});
|
|
60
|
+
} else {
|
|
61
|
+
socket.write('HTTP/1.1 404 Not Found\r\nConnection: close\r\n\r\n');
|
|
62
|
+
socket.destroy();
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
if (registry.wssByPath.has(path)) {
|
|
67
|
+
throw new Error(`WebSocket path "${path}" is already registered on this HTTP server.`);
|
|
68
|
+
}
|
|
69
|
+
registry.wssByPath.set(path, wss);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function detachUpgradeDispatch(httpServer: http.Server, path: string): void {
|
|
73
|
+
const registry = wsRegistryByHttpServer.get(httpServer);
|
|
74
|
+
if (registry) {
|
|
75
|
+
registry.wssByPath.delete(path);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
32
79
|
export class GGSocketServer<TContext, Query> {
|
|
33
80
|
|
|
34
81
|
private readonly wss: WebSocketServer;
|
|
@@ -50,8 +97,9 @@ export class GGSocketServer<TContext, Query> {
|
|
|
50
97
|
this.apiName = config.apiName;
|
|
51
98
|
this.middlewares = config.middlewares;
|
|
52
99
|
this.queryValidator = config.queryValidator;
|
|
53
|
-
this.wss = new WebSocketServer({
|
|
100
|
+
this.wss = new WebSocketServer({noServer: true});
|
|
54
101
|
this.wss.on('connection', this.scope.wrapWithEnter(this._onConnection));
|
|
102
|
+
attachUpgradeDispatch(http.httpServer, this.path, this.wss);
|
|
55
103
|
this.http = http
|
|
56
104
|
.onStart(() => {
|
|
57
105
|
GGLog.info(this, "WebSocket server started", {api: config.apiName, path: config.path});
|
|
@@ -68,7 +116,8 @@ export class GGSocketServer<TContext, Query> {
|
|
|
68
116
|
.onTeardown(async () => {
|
|
69
117
|
GGLog.info(this, "WebSocket server closing");
|
|
70
118
|
try {
|
|
71
|
-
|
|
119
|
+
detachUpgradeDispatch(http.httpServer, this.path);
|
|
120
|
+
this.wss.close();
|
|
72
121
|
} catch (error) {
|
|
73
122
|
GGLog.error(this, error);
|
|
74
123
|
}
|
|
@@ -24,12 +24,14 @@ export interface WebSocketSchemaConfig {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
declare module "../schema/GGWebSocketSchema" {
|
|
27
|
-
interface GGWebSocketSchema<TClientToServer, TServerToClient, TContext = {}, TQuery = undefined, TClientToServerImpl = TClientToServer> {
|
|
27
|
+
interface GGWebSocketSchema<TClientToServer, TServerToClient, TContext = {}, TQuery = undefined, TClientToServerImpl = TClientToServer, TServerToClientImpl = TServerToClient> {
|
|
28
28
|
/**
|
|
29
29
|
* Start the WebSocket server for this API.
|
|
30
|
+
* The onConnection handler receives validated query parameters as its 3rd argument
|
|
31
|
+
* (only populated when the schema declares `queryOnConnect(validator)`).
|
|
30
32
|
*/
|
|
31
33
|
startServer(
|
|
32
|
-
onConnection: (incoming: WebSocketIncoming<TClientToServerImpl>, outgoing: WebSocketOutgoing<TServerToClient
|
|
34
|
+
onConnection: (incoming: WebSocketIncoming<TClientToServerImpl>, outgoing: WebSocketOutgoing<TServerToClient>, query: TQuery) => void,
|
|
33
35
|
config: WebSocketSchemaConfig
|
|
34
36
|
): GGSocketServer<TContext, TQuery>
|
|
35
37
|
|
|
@@ -38,14 +40,14 @@ declare module "../schema/GGWebSocketSchema" {
|
|
|
38
40
|
* Uses GGHttpServerAdapter from locator if not explicitly provided.
|
|
39
41
|
*/
|
|
40
42
|
register(
|
|
41
|
-
onConnection: (incoming: WebSocketIncoming<TClientToServerImpl>, outgoing: WebSocketOutgoing<TServerToClient
|
|
43
|
+
onConnection: (incoming: WebSocketIncoming<TClientToServerImpl>, outgoing: WebSocketOutgoing<TServerToClient>, query: TQuery) => void,
|
|
42
44
|
config?: WebSocketSchemaConfig
|
|
43
45
|
): void
|
|
44
46
|
}
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
GGWebSocketSchema.prototype.startServer = function (
|
|
48
|
-
this: GGWebSocketSchema<any, any, any, any>,
|
|
50
|
+
this: GGWebSocketSchema<any, any, any, any, any, any>,
|
|
49
51
|
onConnection: any,
|
|
50
52
|
config: WebSocketSchemaConfig
|
|
51
53
|
): GGSocketServer<any, any> {
|
|
@@ -57,15 +59,17 @@ GGWebSocketSchema.prototype.startServer = function (
|
|
|
57
59
|
const normalizedPath = this.path.startsWith('/') ? this.path : '/' + this.path
|
|
58
60
|
const schemaName = this.name
|
|
59
61
|
const http = config.http ?? GGLocator.getScope().get(GG_HTTP_SERVER);
|
|
62
|
+
http._registerWebSocketSchema(this as any);
|
|
60
63
|
|
|
61
64
|
// @TODO We might want some lookup here based on path/middlewares etc. If I use same socket for multiple paths, we need to reuse also same GGSocketServer.
|
|
62
65
|
const socketServer = new GGSocketServer(http, {
|
|
63
66
|
apiName: schemaName,
|
|
64
67
|
path: normalizedPath,
|
|
65
|
-
middlewares: [...this.middlewares, ...(config?.middlewares ?? [])]
|
|
68
|
+
middlewares: [...this.middlewares, ...(config?.middlewares ?? [])],
|
|
69
|
+
queryValidator: this.queryValidator,
|
|
66
70
|
});
|
|
67
71
|
|
|
68
|
-
socketServer.onConnection((socket: GGSocket) => {
|
|
72
|
+
socketServer.onConnection((socket: GGSocket, queryArgs: any) => {
|
|
69
73
|
const clientToServerContract = contract.clientToServer
|
|
70
74
|
const serverToClientContract = contract.serverToClient
|
|
71
75
|
|
|
@@ -86,7 +90,7 @@ GGWebSocketSchema.prototype.startServer = function (
|
|
|
86
90
|
};
|
|
87
91
|
}
|
|
88
92
|
|
|
89
|
-
const incomingInstance = clientToServerContract.implement(impl);
|
|
93
|
+
const incomingInstance = clientToServerContract.implement(impl, {skipLocatorRegistration: true});
|
|
90
94
|
|
|
91
95
|
for (const methodName of Object.keys(clientToServerContract.methods)) {
|
|
92
96
|
socket.registerHandler({
|
|
@@ -106,18 +110,18 @@ GGWebSocketSchema.prototype.startServer = function (
|
|
|
106
110
|
};
|
|
107
111
|
}
|
|
108
112
|
|
|
109
|
-
const outgoingInstance = serverToClientContract.implement(impl);
|
|
113
|
+
const outgoingInstance = serverToClientContract.implement(impl, {skipLocatorRegistration: true});
|
|
110
114
|
(outgoingInstance as any).onClose = (callback: () => void) => {
|
|
111
115
|
socket.onClose(callback)
|
|
112
116
|
}
|
|
113
|
-
onConnection(incoming, outgoingInstance)
|
|
117
|
+
onConnection(incoming, outgoingInstance, queryArgs)
|
|
114
118
|
});
|
|
115
119
|
|
|
116
120
|
return socketServer;
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
GGWebSocketSchema.prototype.register = function (
|
|
120
|
-
this: GGWebSocketSchema<any, any, any, any>,
|
|
124
|
+
this: GGWebSocketSchema<any, any, any, any, any, any>,
|
|
121
125
|
onConnection: any,
|
|
122
126
|
config?: WebSocketSchemaConfig
|
|
123
127
|
): void {
|
package/src/socket/GGSocket.ts
CHANGED
|
@@ -232,11 +232,13 @@ export class GGSocket {
|
|
|
232
232
|
* @param path - The message path/route
|
|
233
233
|
* @param body - The message data (already validated)
|
|
234
234
|
* @param expectsResponse - Whether to wait for a response
|
|
235
|
+
* @param timeoutMs - Timeout for req/res in ms. Ignored for fire-and-forget. Defaults to 30_000.
|
|
235
236
|
*/
|
|
236
237
|
public async send(
|
|
237
238
|
path: string,
|
|
238
239
|
body: any,
|
|
239
|
-
expectsResponse: boolean
|
|
240
|
+
expectsResponse: boolean,
|
|
241
|
+
timeoutMs: number = 30000
|
|
240
242
|
): Promise<any> {
|
|
241
243
|
const labels: MetricLabels = {api: this.apiName, path: this.socketPath, method: path};
|
|
242
244
|
const startTime = performance.now();
|
|
@@ -247,7 +249,7 @@ export class GGSocket {
|
|
|
247
249
|
}
|
|
248
250
|
|
|
249
251
|
if (expectsResponse) {
|
|
250
|
-
return this.pendingRequests.create(path,
|
|
252
|
+
return this.pendingRequests.create(path, timeoutMs, async (id, waitForResponse) => {
|
|
251
253
|
this.socket.send(Message.create(MessageType.REQ, path, id, body));
|
|
252
254
|
const result = await waitForResponse;
|
|
253
255
|
const resultType = result?.success === true ? 'OK' : (result?.type ?? 'SERVER_ERROR');
|
|
@@ -307,6 +309,58 @@ export class GGSocket {
|
|
|
307
309
|
return this;
|
|
308
310
|
}
|
|
309
311
|
|
|
312
|
+
// --------------------------------------------------------------------------------------
|
|
313
|
+
// Heartbeat (PING/PONG) — dead-connection detection
|
|
314
|
+
// --------------------------------------------------------------------------------------
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Start a heartbeat loop that sends protocol-level PINGs and closes the socket
|
|
318
|
+
* if no PONG comes back within `intervalMs + timeoutMs`. Returns a stop function.
|
|
319
|
+
*
|
|
320
|
+
* No-op (returns an empty stop fn) if the underlying adapter does not support
|
|
321
|
+
* ping/pong — e.g. the browser WebSocket API cannot initiate pings.
|
|
322
|
+
*/
|
|
323
|
+
public startHeartbeat(config: {intervalMs: number; timeoutMs: number}): () => void {
|
|
324
|
+
// Adapter doesn't support ping/pong (e.g. browser WebSocket) — no-op.
|
|
325
|
+
if (!this.socket.ping || !this.socket.onPong) {
|
|
326
|
+
return () => {};
|
|
327
|
+
}
|
|
328
|
+
// Socket is already closed — starting heartbeat would leak intervals
|
|
329
|
+
// because the onCloseCallbacks push below won't fire (isCleanedUp guard).
|
|
330
|
+
if (!this.isActive) {
|
|
331
|
+
return () => {};
|
|
332
|
+
}
|
|
333
|
+
let lastActivity = Date.now();
|
|
334
|
+
const onPong = () => { lastActivity = Date.now(); };
|
|
335
|
+
this.socket.onPong(onPong);
|
|
336
|
+
|
|
337
|
+
const sender = setInterval(() => {
|
|
338
|
+
if (!this.isActive) return;
|
|
339
|
+
try {
|
|
340
|
+
this.socket.ping!();
|
|
341
|
+
} catch (_) { /* adapter may throw if socket already closing */ }
|
|
342
|
+
}, config.intervalMs);
|
|
343
|
+
|
|
344
|
+
const watchdog = setInterval(() => {
|
|
345
|
+
if (!this.isActive) return;
|
|
346
|
+
if (Date.now() - lastActivity > config.intervalMs + config.timeoutMs) {
|
|
347
|
+
this.log.warn(this, 'Heartbeat timeout — no PONG received; closing socket');
|
|
348
|
+
clearInterval(sender);
|
|
349
|
+
clearInterval(watchdog);
|
|
350
|
+
this.close();
|
|
351
|
+
}
|
|
352
|
+
}, config.timeoutMs);
|
|
353
|
+
|
|
354
|
+
// Auto-cleanup on close
|
|
355
|
+
const cleanup = () => {
|
|
356
|
+
clearInterval(sender);
|
|
357
|
+
clearInterval(watchdog);
|
|
358
|
+
};
|
|
359
|
+
this.onCloseCallbacks.push(cleanup);
|
|
360
|
+
|
|
361
|
+
return cleanup;
|
|
362
|
+
}
|
|
363
|
+
|
|
310
364
|
// --------------------------------------------------------------------------------------
|
|
311
365
|
// Teardown
|
|
312
366
|
// --------------------------------------------------------------------------------------
|
|
@@ -18,4 +18,17 @@ export interface SocketAdapter {
|
|
|
18
18
|
offClose(handler: () => void): void;
|
|
19
19
|
|
|
20
20
|
offError(handler: (error: Error) => void): void;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Send a protocol-level PING frame. The peer auto-responds with a PONG.
|
|
24
|
+
* Optional: browsers cannot initiate pings (the native WebSocket API does not expose it).
|
|
25
|
+
* Node can; use this for dead-connection detection.
|
|
26
|
+
*/
|
|
27
|
+
ping?(): void;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Register a handler for PONG frames received from the peer.
|
|
31
|
+
* Paired with `ping()` — only supported by adapters that also support ping.
|
|
32
|
+
*/
|
|
33
|
+
onPong?(handler: () => void): void;
|
|
21
34
|
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { GGSocket } from "../socket/GGSocket";
|
|
2
|
-
import { GGContractMethod } from "@grest-ts/schema";
|
|
3
|
-
export declare abstract class GGSocketClient {
|
|
4
|
-
readonly socket: GGSocket;
|
|
5
|
-
constructor(socket: GGSocket);
|
|
6
|
-
onClose(onClose: () => void): this;
|
|
7
|
-
close(): void;
|
|
8
|
-
__defineApi<T extends Record<string, GGContractMethod<any, any, any>>>(api: T): T;
|
|
9
|
-
}
|
|
10
|
-
//# sourceMappingURL=GGSocketClient.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GGSocketClient.d.ts","sourceRoot":"","sources":["../../../src/client/GGSocketClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,QAAQ,EAAC,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAElD,8BAAsB,cAAc;IAEhC,SAAgB,MAAM,EAAE,QAAQ,CAAA;gBAEpB,MAAM,EAAE,QAAQ;IAIrB,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI;IAK3B,KAAK,IAAI,IAAI;IAIb,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC;CAI3F"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
export class GGSocketClient {
|
|
2
|
-
socket;
|
|
3
|
-
constructor(socket) {
|
|
4
|
-
this.socket = socket;
|
|
5
|
-
}
|
|
6
|
-
onClose(onClose) {
|
|
7
|
-
this.socket.onClose(onClose);
|
|
8
|
-
return this;
|
|
9
|
-
}
|
|
10
|
-
close() {
|
|
11
|
-
this.socket.close();
|
|
12
|
-
}
|
|
13
|
-
__defineApi(api) {
|
|
14
|
-
return api;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
//# sourceMappingURL=GGSocketClient.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"GGSocketClient.js","sourceRoot":"","sources":["../../../src/client/GGSocketClient.ts"],"names":[],"mappings":"AAGA,MAAM,OAAgB,cAAc;IAEhB,MAAM,CAAU;IAEhC,YAAY,MAAgB;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACzB,CAAC;IAEM,OAAO,CAAC,OAAmB;QAC9B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;QAC5B,OAAO,IAAI,CAAA;IACf,CAAC;IAEM,KAAK;QACR,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;IACvB,CAAC;IAEM,WAAW,CAA4D,GAAM;QAChF,OAAO,GAAG,CAAC;IACf,CAAC;CAEJ"}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import {GGSocket} from "../socket/GGSocket";
|
|
2
|
-
import {GGContractMethod} from "@grest-ts/schema";
|
|
3
|
-
|
|
4
|
-
export abstract class GGSocketClient {
|
|
5
|
-
|
|
6
|
-
public readonly socket: GGSocket
|
|
7
|
-
|
|
8
|
-
constructor(socket: GGSocket) {
|
|
9
|
-
this.socket = socket;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
public onClose(onClose: () => void) {
|
|
13
|
-
this.socket.onClose(onClose)
|
|
14
|
-
return this
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
public close(): void {
|
|
18
|
-
this.socket.close()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
public __defineApi<T extends Record<string, GGContractMethod<any, any, any>>>(api: T): T {
|
|
22
|
-
return api;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
}
|