@fluojs/websockets 1.0.0-beta.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/LICENSE +21 -0
- package/README.ko.md +133 -0
- package/README.md +133 -0
- package/dist/bun/bun-module.d.ts +15 -0
- package/dist/bun/bun-module.d.ts.map +1 -0
- package/dist/bun/bun-module.js +27 -0
- package/dist/bun/bun-service.d.ts +63 -0
- package/dist/bun/bun-service.d.ts.map +1 -0
- package/dist/bun/bun-service.js +558 -0
- package/dist/bun/bun-types.d.ts +58 -0
- package/dist/bun/bun-types.d.ts.map +1 -0
- package/dist/bun/bun-types.js +1 -0
- package/dist/bun/bun.d.ts +4 -0
- package/dist/bun/bun.d.ts.map +1 -0
- package/dist/bun/bun.js +3 -0
- package/dist/bun.d.ts +2 -0
- package/dist/bun.d.ts.map +1 -0
- package/dist/bun.js +1 -0
- package/dist/cloudflare-workers/cloudflare-workers-module.d.ts +15 -0
- package/dist/cloudflare-workers/cloudflare-workers-module.d.ts.map +1 -0
- package/dist/cloudflare-workers/cloudflare-workers-module.js +27 -0
- package/dist/cloudflare-workers/cloudflare-workers-service.d.ts +61 -0
- package/dist/cloudflare-workers/cloudflare-workers-service.d.ts.map +1 -0
- package/dist/cloudflare-workers/cloudflare-workers-service.js +538 -0
- package/dist/cloudflare-workers/cloudflare-workers-types.d.ts +30 -0
- package/dist/cloudflare-workers/cloudflare-workers-types.d.ts.map +1 -0
- package/dist/cloudflare-workers/cloudflare-workers-types.js +1 -0
- package/dist/cloudflare-workers/cloudflare-workers.d.ts +4 -0
- package/dist/cloudflare-workers/cloudflare-workers.d.ts.map +1 -0
- package/dist/cloudflare-workers/cloudflare-workers.js +3 -0
- package/dist/cloudflare-workers.d.ts +2 -0
- package/dist/cloudflare-workers.d.ts.map +1 -0
- package/dist/cloudflare-workers.js +1 -0
- package/dist/decorators.d.ts +56 -0
- package/dist/decorators.d.ts.map +1 -0
- package/dist/decorators.js +115 -0
- package/dist/deno/deno-module.d.ts +15 -0
- package/dist/deno/deno-module.d.ts.map +1 -0
- package/dist/deno/deno-module.js +27 -0
- package/dist/deno/deno-service.d.ts +61 -0
- package/dist/deno/deno-service.d.ts.map +1 -0
- package/dist/deno/deno-service.js +533 -0
- package/dist/deno/deno-types.d.ts +25 -0
- package/dist/deno/deno-types.d.ts.map +1 -0
- package/dist/deno/deno-types.js +1 -0
- package/dist/deno/deno.d.ts +4 -0
- package/dist/deno/deno.d.ts.map +1 -0
- package/dist/deno/deno.js +3 -0
- package/dist/deno.d.ts +2 -0
- package/dist/deno.d.ts.map +1 -0
- package/dist/deno.js +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/internal/shared.d.ts +28 -0
- package/dist/internal/shared.d.ts.map +1 -0
- package/dist/internal/shared.js +188 -0
- package/dist/metadata.d.ts +13 -0
- package/dist/metadata.d.ts.map +1 -0
- package/dist/metadata.js +81 -0
- package/dist/module.d.ts +26 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +26 -0
- package/dist/node/node-module.d.ts +15 -0
- package/dist/node/node-module.d.ts.map +1 -0
- package/dist/node/node-module.js +27 -0
- package/dist/node/node-service.d.ts +129 -0
- package/dist/node/node-service.d.ts.map +1 -0
- package/dist/node/node-service.js +892 -0
- package/dist/node/node-types.d.ts +81 -0
- package/dist/node/node-types.d.ts.map +1 -0
- package/dist/node/node-types.js +1 -0
- package/dist/node/node.d.ts +4 -0
- package/dist/node/node.d.ts.map +1 -0
- package/dist/node/node.js +3 -0
- package/dist/node.d.ts +2 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +1 -0
- package/dist/options-token.internal.d.ts +7 -0
- package/dist/options-token.internal.d.ts.map +1 -0
- package/dist/options-token.internal.js +4 -0
- package/dist/service.d.ts +9 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +8 -0
- package/dist/types.d.ts +133 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +91 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
let _initClass;
|
|
2
|
+
function _applyDecs(e, t, n, r, o, i) { var a, c, u, s, f, l, p, d = Symbol.metadata || Symbol.for("Symbol.metadata"), m = Object.defineProperty, h = Object.create, y = [h(null), h(null)], v = t.length; function g(t, n, r) { return function (o, i) { n && (i = o, o = e); for (var a = 0; a < t.length; a++) i = t[a].apply(o, r ? [i] : []); return r ? i : o; }; } function b(e, t, n, r) { if ("function" != typeof e && (r || void 0 !== e)) throw new TypeError(t + " must " + (n || "be") + " a function" + (r ? "" : " or undefined")); return e; } function applyDec(e, t, n, r, o, i, u, s, f, l, p) { function d(e) { if (!p(e)) throw new TypeError("Attempted to access private element on non-instance"); } var h = [].concat(t[0]), v = t[3], w = !u, D = 1 === o, S = 3 === o, j = 4 === o, E = 2 === o; function I(t, n, r) { return function (o, i) { return n && (i = o, o = e), r && r(o), P[t].call(o, i); }; } if (!w) { var P = {}, k = [], F = S ? "get" : j || D ? "set" : "value"; if (f ? (l || D ? P = { get: _setFunctionName(function () { return v(this); }, r, "get"), set: function (e) { t[4](this, e); } } : P[F] = v, l || _setFunctionName(P[F], r, E ? "" : F)) : l || (P = Object.getOwnPropertyDescriptor(e, r)), !l && !f) { if ((c = y[+s][r]) && 7 !== (c ^ o)) throw Error("Decorating two elements with the same name (" + P[F].name + ") is not supported yet"); y[+s][r] = o < 3 ? 1 : o; } } for (var N = e, O = h.length - 1; O >= 0; O -= n ? 2 : 1) { var T = b(h[O], "A decorator", "be", !0), z = n ? h[O - 1] : void 0, A = {}, H = { kind: ["field", "accessor", "method", "getter", "setter", "class"][o], name: r, metadata: a, addInitializer: function (e, t) { if (e.v) throw new TypeError("attempted to call addInitializer after decoration was finished"); b(t, "An initializer", "be", !0), i.push(t); }.bind(null, A) }; if (w) c = T.call(z, N, H), A.v = 1, b(c, "class decorators", "return") && (N = c);else if (H.static = s, H.private = f, c = H.access = { has: f ? p.bind() : function (e) { return r in e; } }, j || (c.get = f ? E ? function (e) { return d(e), P.value; } : I("get", 0, d) : function (e) { return e[r]; }), E || S || (c.set = f ? I("set", 0, d) : function (e, t) { e[r] = t; }), N = T.call(z, D ? { get: P.get, set: P.set } : P[F], H), A.v = 1, D) { if ("object" == typeof N && N) (c = b(N.get, "accessor.get")) && (P.get = c), (c = b(N.set, "accessor.set")) && (P.set = c), (c = b(N.init, "accessor.init")) && k.unshift(c);else if (void 0 !== N) throw new TypeError("accessor decorators must return an object with get, set, or init properties or undefined"); } else b(N, (l ? "field" : "method") + " decorators", "return") && (l ? k.unshift(N) : P[F] = N); } return o < 2 && u.push(g(k, s, 1), g(i, s, 0)), l || w || (f ? D ? u.splice(-1, 0, I("get", s), I("set", s)) : u.push(E ? P[F] : b.call.bind(P[F])) : m(e, r, P)), N; } function w(e) { return m(e, d, { configurable: !0, enumerable: !0, value: a }); } return void 0 !== i && (a = i[d]), a = h(null == a ? null : a), f = [], l = function (e) { e && f.push(g(e)); }, p = function (t, r) { for (var i = 0; i < n.length; i++) { var a = n[i], c = a[1], l = 7 & c; if ((8 & c) == t && !l == r) { var p = a[2], d = !!a[3], m = 16 & c; applyDec(t ? e : e.prototype, a, m, d ? "#" + p : _toPropertyKey(p), l, l < 2 ? [] : t ? s = s || [] : u = u || [], f, !!t, d, r, t && d ? function (t) { return _checkInRHS(t) === e; } : o); } } }, p(8, 0), p(0, 0), p(8, 1), p(0, 1), l(u), l(s), c = f, v || w(e), { e: c, get c() { var n = []; return v && [w(e = applyDec(e, [t], r, e.name, 5, n)), g(n, 1)]; } }; }
|
|
3
|
+
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
4
|
+
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
5
|
+
function _setFunctionName(e, t, n) { "symbol" == typeof t && (t = (t = t.description) ? "[" + t + "]" : ""); try { Object.defineProperty(e, "name", { configurable: !0, value: n ? n + " " + t : t }); } catch (e) {} return e; }
|
|
6
|
+
function _checkInRHS(e) { if (Object(e) !== e) throw TypeError("right-hand side of 'in' should be an object, got " + (null !== e ? typeof e : "null")); return e; }
|
|
7
|
+
import { Inject } from '@fluojs/core';
|
|
8
|
+
import { APPLICATION_LOGGER, COMPILED_MODULES, HTTP_APPLICATION_ADAPTER, RUNTIME_CONTAINER } from '@fluojs/runtime/internal';
|
|
9
|
+
import { dispatchGatewayDisconnect, dispatchGatewayMessage, discoverGatewayDescriptors, isFinitePositiveInteger, normalizeGatewayPath, resolveGatewayInstance, runGatewayHandlers } from '../internal/shared.js';
|
|
10
|
+
import { WEBSOCKET_OPTIONS_INTERNAL } from '../options-token.internal.js';
|
|
11
|
+
const DEFAULT_MAX_PENDING_MESSAGES_PER_SOCKET = 256;
|
|
12
|
+
const DEFAULT_MAX_WEBSOCKET_CONNECTIONS = 1_000;
|
|
13
|
+
const DEFAULT_MAX_WEBSOCKET_PAYLOAD_BYTES = 1_048_576;
|
|
14
|
+
const LIFECYCLE_LOG_CONTEXT = 'WebSocketGatewayLifecycleService';
|
|
15
|
+
const WEBSOCKET_OPEN_READY_STATE = 1;
|
|
16
|
+
function hasDenoWebSocketBindingHost(adapter) {
|
|
17
|
+
return 'configureWebSocketBinding' in adapter && typeof adapter.configureWebSocketBinding === 'function';
|
|
18
|
+
}
|
|
19
|
+
function resolveSupportedFetchStyleRealtimeCapability(adapter) {
|
|
20
|
+
if (typeof adapter.getRealtimeCapability !== 'function') {
|
|
21
|
+
throw new Error('Deno WebSocket gateway bootstrap requires an HTTP adapter with getRealtimeCapability(). Use @fluojs/platform-deno together with @fluojs/websockets/deno.');
|
|
22
|
+
}
|
|
23
|
+
const capability = adapter.getRealtimeCapability();
|
|
24
|
+
if (capability.kind !== 'fetch-style' || capability.contract !== 'raw-websocket-expansion') {
|
|
25
|
+
throw new Error('Deno WebSocket gateway bootstrap requires a fetch-style raw-websocket-expansion realtime capability from the selected HTTP adapter.');
|
|
26
|
+
}
|
|
27
|
+
if (capability.support !== 'supported') {
|
|
28
|
+
throw new Error(`Deno WebSocket gateway bootstrap requires supported fetch-style websocket hosting. ${capability.reason}`);
|
|
29
|
+
}
|
|
30
|
+
return capability;
|
|
31
|
+
}
|
|
32
|
+
function isWebSocketUpgradeRequest(request) {
|
|
33
|
+
return request.headers.get('upgrade')?.toLowerCase() === 'websocket';
|
|
34
|
+
}
|
|
35
|
+
function isHttpExceptionLike(error) {
|
|
36
|
+
return typeof error === 'object' && error !== null && 'message' in error && 'status' in error;
|
|
37
|
+
}
|
|
38
|
+
function resolveMessageByteLength(message) {
|
|
39
|
+
if (typeof message === 'string') {
|
|
40
|
+
return Buffer.byteLength(message);
|
|
41
|
+
}
|
|
42
|
+
return message.size;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Boots Deno-backed websocket gateways and manages their room lifecycle state.
|
|
47
|
+
*/
|
|
48
|
+
let _DenoWebSocketGateway;
|
|
49
|
+
class DenoWebSocketGatewayLifecycleService {
|
|
50
|
+
static {
|
|
51
|
+
[_DenoWebSocketGateway, _initClass] = _applyDecs(this, [Inject(RUNTIME_CONTAINER, COMPILED_MODULES, APPLICATION_LOGGER, HTTP_APPLICATION_ADAPTER, WEBSOCKET_OPTIONS_INTERNAL)], []).c;
|
|
52
|
+
}
|
|
53
|
+
pendingUpgradeReservations = 0;
|
|
54
|
+
roomSockets = new Map();
|
|
55
|
+
shutdownPromise;
|
|
56
|
+
socketRegistry = new Map();
|
|
57
|
+
socketRooms = new Map();
|
|
58
|
+
constructor(runtimeContainer, compiledModules, logger, adapter, moduleOptions) {
|
|
59
|
+
this.runtimeContainer = runtimeContainer;
|
|
60
|
+
this.compiledModules = compiledModules;
|
|
61
|
+
this.logger = logger;
|
|
62
|
+
this.adapter = adapter;
|
|
63
|
+
this.moduleOptions = moduleOptions;
|
|
64
|
+
}
|
|
65
|
+
async onApplicationBootstrap() {
|
|
66
|
+
const descriptors = discoverGatewayDescriptors(this.compiledModules, this.logger, LIFECYCLE_LOG_CONTEXT);
|
|
67
|
+
if (descriptors.length === 0) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
this.assertNoServerBackedGatewayOptIn(descriptors);
|
|
71
|
+
resolveSupportedFetchStyleRealtimeCapability(this.adapter);
|
|
72
|
+
if (!hasDenoWebSocketBindingHost(this.adapter)) {
|
|
73
|
+
throw new Error('Deno WebSocket gateway bootstrap requires the selected adapter to expose Deno websocket binding configuration. Use @fluojs/platform-deno with @fluojs/websockets/deno.');
|
|
74
|
+
}
|
|
75
|
+
this.adapter.configureWebSocketBinding(this.createBinding(descriptors));
|
|
76
|
+
}
|
|
77
|
+
assertNoServerBackedGatewayOptIn(descriptors) {
|
|
78
|
+
const descriptor = descriptors.find(entry => entry.serverBacked !== undefined);
|
|
79
|
+
if (!descriptor) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
throw new Error(`@WebSocketGateway({ serverBacked }) is not supported on @fluojs/websockets/deno. Gateway path ${descriptor.path} must use the default fetch-style request-upgrade host instead.`);
|
|
83
|
+
}
|
|
84
|
+
async onApplicationShutdown() {
|
|
85
|
+
await this.shutdown();
|
|
86
|
+
}
|
|
87
|
+
async onModuleDestroy() {
|
|
88
|
+
await this.shutdown();
|
|
89
|
+
}
|
|
90
|
+
createBinding(descriptors) {
|
|
91
|
+
const descriptorsByPath = this.groupDescriptorsByPath(descriptors);
|
|
92
|
+
return {
|
|
93
|
+
fetch: async (request, host) => {
|
|
94
|
+
if (!isWebSocketUpgradeRequest(request)) {
|
|
95
|
+
return new Response(null, {
|
|
96
|
+
status: 426
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
let targetPath;
|
|
100
|
+
try {
|
|
101
|
+
targetPath = normalizeGatewayPath(new URL(request.url).pathname);
|
|
102
|
+
} catch {
|
|
103
|
+
return new Response(null, {
|
|
104
|
+
status: 400
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const descriptors = descriptorsByPath.get(targetPath);
|
|
108
|
+
if (!descriptors) {
|
|
109
|
+
return new Response(null, {
|
|
110
|
+
status: 404
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
const rejection = await this.resolveUpgradeRejection(request, targetPath);
|
|
114
|
+
if (rejection) {
|
|
115
|
+
return new Response(rejection.body ?? null, {
|
|
116
|
+
headers: rejection.headers,
|
|
117
|
+
status: rejection.status
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
let response;
|
|
121
|
+
let socket;
|
|
122
|
+
try {
|
|
123
|
+
({
|
|
124
|
+
response,
|
|
125
|
+
socket
|
|
126
|
+
} = host.upgrade(request));
|
|
127
|
+
} catch (error) {
|
|
128
|
+
this.releaseUpgradeReservation();
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
void this.bindConnectionHandlers(socket, request, descriptors).catch(error => {
|
|
132
|
+
this.unregisterSocket(this.findSocketId(socket));
|
|
133
|
+
this.logger.error('WebSocket gateway open lifecycle failed.', error, LIFECYCLE_LOG_CONTEXT);
|
|
134
|
+
socket.close(1011, 'Internal server error');
|
|
135
|
+
});
|
|
136
|
+
return response;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
groupDescriptorsByPath(descriptors) {
|
|
141
|
+
const descriptorsByPath = new Map();
|
|
142
|
+
for (const descriptor of descriptors) {
|
|
143
|
+
const current = descriptorsByPath.get(descriptor.path);
|
|
144
|
+
if (current) {
|
|
145
|
+
current.push(descriptor);
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
descriptorsByPath.set(descriptor.path, [descriptor]);
|
|
149
|
+
}
|
|
150
|
+
return descriptorsByPath;
|
|
151
|
+
}
|
|
152
|
+
async bindConnectionHandlers(socket, request, descriptors) {
|
|
153
|
+
const state = this.createConnectionHandlerState(request, descriptors);
|
|
154
|
+
this.releaseUpgradeReservation();
|
|
155
|
+
this.socketRegistry.set(state.socketId, socket);
|
|
156
|
+
this.attachConnectionListeners(state, socket, request);
|
|
157
|
+
await this.resolveConnectionGateways(state);
|
|
158
|
+
await this.runConnectHandlers(state, socket);
|
|
159
|
+
await this.finalizeConnectionBinding(state, socket, request);
|
|
160
|
+
}
|
|
161
|
+
createConnectionHandlerState(request, descriptors) {
|
|
162
|
+
return {
|
|
163
|
+
bufferedDisconnect: undefined,
|
|
164
|
+
bufferedMessages: [],
|
|
165
|
+
bufferedMessagesStartIndex: 0,
|
|
166
|
+
descriptors,
|
|
167
|
+
enqueuedMessageCount: 0,
|
|
168
|
+
handlerQueue: Promise.resolve(),
|
|
169
|
+
handlersReady: false,
|
|
170
|
+
processingMessageQueue: false,
|
|
171
|
+
queuedMessages: [],
|
|
172
|
+
queuedMessagesStartIndex: 0,
|
|
173
|
+
request,
|
|
174
|
+
resolved: [],
|
|
175
|
+
socketId: crypto.randomUUID()
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
attachConnectionListeners(state, socket, request) {
|
|
179
|
+
socket.addEventListener('message', event => {
|
|
180
|
+
if (this.closeOversizedPayload(state.socketId, socket, event.data)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!state.handlersReady) {
|
|
184
|
+
this.bufferIncomingMessage(state, socket, event.data);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
this.enqueueMessageDispatch(state, socket, request, event.data);
|
|
188
|
+
});
|
|
189
|
+
socket.addEventListener('error', event => {
|
|
190
|
+
this.unregisterSocket(state.socketId);
|
|
191
|
+
this.logger.error('WebSocket gateway socket emitted an error.', event, LIFECYCLE_LOG_CONTEXT);
|
|
192
|
+
});
|
|
193
|
+
socket.addEventListener('close', event => {
|
|
194
|
+
this.unregisterSocket(state.socketId);
|
|
195
|
+
const disconnectEvent = {
|
|
196
|
+
code: event.code,
|
|
197
|
+
reason: event.reason
|
|
198
|
+
};
|
|
199
|
+
if (!state.handlersReady) {
|
|
200
|
+
state.bufferedDisconnect = disconnectEvent;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
this.enqueueDisconnectDispatch(state, socket, disconnectEvent);
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
getBufferedMessageCount(state) {
|
|
207
|
+
return state.bufferedMessages.length - state.bufferedMessagesStartIndex;
|
|
208
|
+
}
|
|
209
|
+
getQueuedMessageCount(state) {
|
|
210
|
+
return state.queuedMessages.length - state.queuedMessagesStartIndex;
|
|
211
|
+
}
|
|
212
|
+
maybeCompactBufferedMessages(state) {
|
|
213
|
+
if (state.bufferedMessagesStartIndex === 0 || state.bufferedMessagesStartIndex < state.bufferedMessages.length / 2) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
state.bufferedMessages = state.bufferedMessages.slice(state.bufferedMessagesStartIndex);
|
|
217
|
+
state.bufferedMessagesStartIndex = 0;
|
|
218
|
+
}
|
|
219
|
+
clearBufferedMessages(state) {
|
|
220
|
+
state.bufferedMessages = [];
|
|
221
|
+
state.bufferedMessagesStartIndex = 0;
|
|
222
|
+
}
|
|
223
|
+
maybeCompactQueuedMessages(state) {
|
|
224
|
+
if (state.queuedMessagesStartIndex === 0 || state.queuedMessagesStartIndex < state.queuedMessages.length / 2) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
state.queuedMessages = state.queuedMessages.slice(state.queuedMessagesStartIndex);
|
|
228
|
+
state.queuedMessagesStartIndex = 0;
|
|
229
|
+
}
|
|
230
|
+
clearQueuedMessages(state) {
|
|
231
|
+
state.queuedMessages = [];
|
|
232
|
+
state.queuedMessagesStartIndex = 0;
|
|
233
|
+
state.enqueuedMessageCount = 0;
|
|
234
|
+
}
|
|
235
|
+
bufferIncomingMessage(state, socket, message) {
|
|
236
|
+
const limit = isFinitePositiveInteger(this.moduleOptions.buffer?.maxPendingMessagesPerSocket) ? this.moduleOptions.buffer.maxPendingMessagesPerSocket : DEFAULT_MAX_PENDING_MESSAGES_PER_SOCKET;
|
|
237
|
+
const policy = this.moduleOptions.buffer?.overflowPolicy ?? 'drop-oldest';
|
|
238
|
+
if (this.getBufferedMessageCount(state) < limit) {
|
|
239
|
+
state.bufferedMessages.push(message);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (policy === 'close') {
|
|
243
|
+
socket.close(1013, 'Pending message buffer limit exceeded');
|
|
244
|
+
this.clearBufferedMessages(state);
|
|
245
|
+
this.logger.warn(`WebSocket connection ${state.socketId} exceeded pending message buffer limit (${String(limit)}). Connection closed.`, LIFECYCLE_LOG_CONTEXT);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (policy === 'drop-newest') {
|
|
249
|
+
this.logger.warn(`WebSocket connection ${state.socketId} dropped an incoming message due to pending buffer limit (${String(limit)}).`, LIFECYCLE_LOG_CONTEXT);
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
state.bufferedMessagesStartIndex += 1;
|
|
253
|
+
this.maybeCompactBufferedMessages(state);
|
|
254
|
+
state.bufferedMessages.push(message);
|
|
255
|
+
this.logger.warn(`WebSocket connection ${state.socketId} dropped the oldest pending message due to buffer limit (${String(limit)}).`, LIFECYCLE_LOG_CONTEXT);
|
|
256
|
+
}
|
|
257
|
+
enqueueMessageDispatch(state, socket, request, message) {
|
|
258
|
+
const limit = isFinitePositiveInteger(this.moduleOptions.buffer?.maxPendingMessagesPerSocket) ? this.moduleOptions.buffer.maxPendingMessagesPerSocket : DEFAULT_MAX_PENDING_MESSAGES_PER_SOCKET;
|
|
259
|
+
const policy = this.moduleOptions.buffer?.overflowPolicy ?? 'drop-oldest';
|
|
260
|
+
if (this.getQueuedMessageCount(state) >= limit) {
|
|
261
|
+
if (policy === 'close') {
|
|
262
|
+
socket.close(1013, 'Ready-state message queue limit exceeded');
|
|
263
|
+
this.clearQueuedMessages(state);
|
|
264
|
+
this.unregisterSocket(state.socketId);
|
|
265
|
+
this.logger.warn(`WebSocket connection ${state.socketId} exceeded ready-state message queue limit (${String(limit)}). Connection closed.`, LIFECYCLE_LOG_CONTEXT);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (policy === 'drop-oldest') {
|
|
269
|
+
state.queuedMessagesStartIndex += 1;
|
|
270
|
+
this.maybeCompactQueuedMessages(state);
|
|
271
|
+
this.logger.warn(`WebSocket connection ${state.socketId} dropped the oldest ready-state message because queue limit (${String(limit)}) was reached.`, LIFECYCLE_LOG_CONTEXT);
|
|
272
|
+
} else {
|
|
273
|
+
this.logger.warn(`WebSocket connection ${state.socketId} dropped a ready-state message because queue limit (${String(limit)}) was reached.`, LIFECYCLE_LOG_CONTEXT);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
state.queuedMessages.push(message);
|
|
278
|
+
state.enqueuedMessageCount = this.getQueuedMessageCount(state);
|
|
279
|
+
if (state.processingMessageQueue) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
state.processingMessageQueue = true;
|
|
283
|
+
state.handlerQueue = this.drainMessageQueue(state, socket, request).finally(() => {
|
|
284
|
+
state.processingMessageQueue = false;
|
|
285
|
+
state.enqueuedMessageCount = this.getQueuedMessageCount(state);
|
|
286
|
+
}).catch(error => {
|
|
287
|
+
this.logger.error('WebSocket gateway message dispatch failed.', error, LIFECYCLE_LOG_CONTEXT);
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
async drainMessageQueue(state, socket, request) {
|
|
291
|
+
while (state.queuedMessagesStartIndex < state.queuedMessages.length) {
|
|
292
|
+
const nextMessage = state.queuedMessages[state.queuedMessagesStartIndex];
|
|
293
|
+
state.queuedMessagesStartIndex += 1;
|
|
294
|
+
state.enqueuedMessageCount = this.getQueuedMessageCount(state);
|
|
295
|
+
if (nextMessage === undefined) {
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
const normalizedMessage = await this.normalizeMessage(nextMessage);
|
|
299
|
+
await dispatchGatewayMessage(state.resolved, socket, request, normalizedMessage, this.logger, LIFECYCLE_LOG_CONTEXT);
|
|
300
|
+
}
|
|
301
|
+
this.clearQueuedMessages(state);
|
|
302
|
+
}
|
|
303
|
+
async normalizeMessage(message) {
|
|
304
|
+
if (typeof message === 'string') {
|
|
305
|
+
return message;
|
|
306
|
+
}
|
|
307
|
+
return await message.arrayBuffer();
|
|
308
|
+
}
|
|
309
|
+
enqueueDisconnectDispatch(state, socket, disconnectEvent) {
|
|
310
|
+
state.handlerQueue = state.handlerQueue.then(async () => {
|
|
311
|
+
await dispatchGatewayDisconnect(state.resolved, socket, disconnectEvent.code, disconnectEvent.reason, state.socketId, this.logger, LIFECYCLE_LOG_CONTEXT);
|
|
312
|
+
}).catch(error => {
|
|
313
|
+
this.logger.error('WebSocket gateway disconnect dispatch failed.', error, LIFECYCLE_LOG_CONTEXT);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
async resolveConnectionGateways(state) {
|
|
317
|
+
const resolved = [];
|
|
318
|
+
for (const descriptor of state.descriptors) {
|
|
319
|
+
const instance = await resolveGatewayInstance(this.runtimeContainer, descriptor, this.logger, LIFECYCLE_LOG_CONTEXT);
|
|
320
|
+
if (instance !== undefined) {
|
|
321
|
+
resolved.push({
|
|
322
|
+
descriptor,
|
|
323
|
+
instance
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
state.resolved = resolved;
|
|
328
|
+
}
|
|
329
|
+
async runConnectHandlers(state, socket) {
|
|
330
|
+
for (const {
|
|
331
|
+
descriptor,
|
|
332
|
+
instance
|
|
333
|
+
} of state.resolved) {
|
|
334
|
+
await runGatewayHandlers(instance, descriptor, 'connect', [socket, state.request, state.socketId], this.logger, LIFECYCLE_LOG_CONTEXT);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async finalizeConnectionBinding(state, socket, request) {
|
|
338
|
+
state.handlersReady = true;
|
|
339
|
+
await this.replayBufferedConnectionEvents(state, socket, request);
|
|
340
|
+
await state.handlerQueue;
|
|
341
|
+
}
|
|
342
|
+
async replayBufferedConnectionEvents(state, socket, request) {
|
|
343
|
+
for (let index = state.bufferedMessagesStartIndex; index < state.bufferedMessages.length; index += 1) {
|
|
344
|
+
const message = state.bufferedMessages[index];
|
|
345
|
+
if (message !== undefined) {
|
|
346
|
+
this.enqueueMessageDispatch(state, socket, request, message);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (state.bufferedDisconnect) {
|
|
350
|
+
this.enqueueDisconnectDispatch(state, socket, state.bufferedDisconnect);
|
|
351
|
+
state.bufferedDisconnect = undefined;
|
|
352
|
+
}
|
|
353
|
+
this.clearBufferedMessages(state);
|
|
354
|
+
}
|
|
355
|
+
findSocketId(target) {
|
|
356
|
+
for (const [socketId, socket] of this.socketRegistry) {
|
|
357
|
+
if (socket === target) {
|
|
358
|
+
return socketId;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return '';
|
|
362
|
+
}
|
|
363
|
+
async resolveUpgradeRejection(request, path) {
|
|
364
|
+
if (!this.tryReserveUpgradeSlot()) {
|
|
365
|
+
return {
|
|
366
|
+
body: 'WebSocket connection limit exceeded.',
|
|
367
|
+
status: 429
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
const guard = this.moduleOptions.upgrade?.guard;
|
|
371
|
+
if (!guard) {
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
try {
|
|
375
|
+
const result = await guard(request, {
|
|
376
|
+
activeConnectionCount: this.resolveReservedConnectionCount() - 1,
|
|
377
|
+
path
|
|
378
|
+
});
|
|
379
|
+
if (result === false) {
|
|
380
|
+
this.releaseUpgradeReservation();
|
|
381
|
+
return {
|
|
382
|
+
body: 'WebSocket upgrade rejected.',
|
|
383
|
+
status: 403
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (typeof result === 'object' && result !== null && 'status' in result) {
|
|
387
|
+
this.releaseUpgradeReservation();
|
|
388
|
+
return result;
|
|
389
|
+
}
|
|
390
|
+
return undefined;
|
|
391
|
+
} catch (error) {
|
|
392
|
+
this.releaseUpgradeReservation();
|
|
393
|
+
if (isHttpExceptionLike(error)) {
|
|
394
|
+
return {
|
|
395
|
+
body: error.message,
|
|
396
|
+
status: error.status
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
throw error;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
closeOversizedPayload(socketId, socket, message) {
|
|
403
|
+
const maxPayloadBytes = this.resolveMaxPayloadBytes();
|
|
404
|
+
if (resolveMessageByteLength(message) <= maxPayloadBytes) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
socket.close(1009, 'Payload too large');
|
|
408
|
+
this.logger.warn(`WebSocket connection ${socketId} exceeded payload limit (${String(maxPayloadBytes)} bytes). Connection closed.`, LIFECYCLE_LOG_CONTEXT);
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
resolveMaxConnectionCount() {
|
|
412
|
+
const configured = this.moduleOptions.limits?.maxConnections;
|
|
413
|
+
if (!isFinitePositiveInteger(configured)) {
|
|
414
|
+
return DEFAULT_MAX_WEBSOCKET_CONNECTIONS;
|
|
415
|
+
}
|
|
416
|
+
return configured;
|
|
417
|
+
}
|
|
418
|
+
resolveReservedConnectionCount() {
|
|
419
|
+
return this.socketRegistry.size + this.pendingUpgradeReservations;
|
|
420
|
+
}
|
|
421
|
+
tryReserveUpgradeSlot() {
|
|
422
|
+
if (this.resolveReservedConnectionCount() >= this.resolveMaxConnectionCount()) {
|
|
423
|
+
return false;
|
|
424
|
+
}
|
|
425
|
+
this.pendingUpgradeReservations += 1;
|
|
426
|
+
return true;
|
|
427
|
+
}
|
|
428
|
+
releaseUpgradeReservation() {
|
|
429
|
+
if (this.pendingUpgradeReservations > 0) {
|
|
430
|
+
this.pendingUpgradeReservations -= 1;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
resolveMaxPayloadBytes() {
|
|
434
|
+
const configured = this.moduleOptions.limits?.maxPayloadBytes;
|
|
435
|
+
if (!isFinitePositiveInteger(configured)) {
|
|
436
|
+
return DEFAULT_MAX_WEBSOCKET_PAYLOAD_BYTES;
|
|
437
|
+
}
|
|
438
|
+
return configured;
|
|
439
|
+
}
|
|
440
|
+
async shutdown() {
|
|
441
|
+
if (this.shutdownPromise) {
|
|
442
|
+
await this.shutdownPromise;
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
this.shutdownPromise = this.runShutdownLifecycle();
|
|
446
|
+
await this.shutdownPromise;
|
|
447
|
+
}
|
|
448
|
+
async runShutdownLifecycle() {
|
|
449
|
+
if (hasDenoWebSocketBindingHost(this.adapter)) {
|
|
450
|
+
this.adapter.configureWebSocketBinding(undefined);
|
|
451
|
+
}
|
|
452
|
+
this.pendingUpgradeReservations = 0;
|
|
453
|
+
this.socketRegistry.clear();
|
|
454
|
+
this.socketRooms.clear();
|
|
455
|
+
this.roomSockets.clear();
|
|
456
|
+
}
|
|
457
|
+
joinRoom(socketId, room) {
|
|
458
|
+
let rooms = this.socketRooms.get(socketId);
|
|
459
|
+
if (!rooms) {
|
|
460
|
+
rooms = new Set();
|
|
461
|
+
this.socketRooms.set(socketId, rooms);
|
|
462
|
+
}
|
|
463
|
+
rooms.add(room);
|
|
464
|
+
let sockets = this.roomSockets.get(room);
|
|
465
|
+
if (!sockets) {
|
|
466
|
+
sockets = new Set();
|
|
467
|
+
this.roomSockets.set(room, sockets);
|
|
468
|
+
}
|
|
469
|
+
sockets.add(socketId);
|
|
470
|
+
}
|
|
471
|
+
leaveRoom(socketId, room) {
|
|
472
|
+
const rooms = this.socketRooms.get(socketId);
|
|
473
|
+
rooms?.delete(room);
|
|
474
|
+
if (rooms && rooms.size === 0) {
|
|
475
|
+
this.socketRooms.delete(socketId);
|
|
476
|
+
}
|
|
477
|
+
const sockets = this.roomSockets.get(room);
|
|
478
|
+
sockets?.delete(socketId);
|
|
479
|
+
if (sockets && sockets.size === 0) {
|
|
480
|
+
this.roomSockets.delete(room);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
broadcastToRoom(room, event, data) {
|
|
484
|
+
const socketIds = this.roomSockets.get(room);
|
|
485
|
+
if (!socketIds) {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const message = JSON.stringify({
|
|
489
|
+
data,
|
|
490
|
+
event
|
|
491
|
+
});
|
|
492
|
+
for (const socketId of socketIds) {
|
|
493
|
+
const socket = this.socketRegistry.get(socketId);
|
|
494
|
+
if (!socket || socket.readyState !== WEBSOCKET_OPEN_READY_STATE) {
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
try {
|
|
498
|
+
socket.send(message);
|
|
499
|
+
} catch (error) {
|
|
500
|
+
this.unregisterSocket(socketId);
|
|
501
|
+
this.logger.warn(`WebSocket connection ${socketId} failed to send a room broadcast and was removed. ${error instanceof Error ? error.message : 'Unknown error.'}`, LIFECYCLE_LOG_CONTEXT);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
getRooms(socketId) {
|
|
506
|
+
const rooms = this.socketRooms.get(socketId);
|
|
507
|
+
if (!rooms) {
|
|
508
|
+
return new Set();
|
|
509
|
+
}
|
|
510
|
+
return new Set(rooms);
|
|
511
|
+
}
|
|
512
|
+
unregisterSocket(socketId) {
|
|
513
|
+
if (!socketId) {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
this.socketRegistry.delete(socketId);
|
|
517
|
+
const rooms = this.socketRooms.get(socketId);
|
|
518
|
+
if (rooms) {
|
|
519
|
+
for (const room of rooms) {
|
|
520
|
+
const sockets = this.roomSockets.get(room);
|
|
521
|
+
sockets?.delete(socketId);
|
|
522
|
+
if (sockets && sockets.size === 0) {
|
|
523
|
+
this.roomSockets.delete(room);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
this.socketRooms.delete(socketId);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
static {
|
|
530
|
+
_initClass();
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
export { _DenoWebSocketGateway as DenoWebSocketGatewayLifecycleService };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { WebSocketModuleOptions as SharedWebSocketModuleOptions } from '../types.js';
|
|
2
|
+
export type DenoWebSocketMessage = Blob | string;
|
|
3
|
+
export interface DenoServerWebSocket extends Pick<WebSocket, 'addEventListener' | 'close' | 'removeEventListener' | 'send'> {
|
|
4
|
+
readonly readyState: number;
|
|
5
|
+
}
|
|
6
|
+
export interface DenoWebSocketUpgradeResult<TSocket extends DenoServerWebSocket = DenoServerWebSocket> {
|
|
7
|
+
response: Response;
|
|
8
|
+
socket: TSocket;
|
|
9
|
+
}
|
|
10
|
+
export interface DenoWebSocketUpgradeHost<TSocket extends DenoServerWebSocket = DenoServerWebSocket> {
|
|
11
|
+
upgrade(request: Request): DenoWebSocketUpgradeResult<TSocket>;
|
|
12
|
+
}
|
|
13
|
+
export interface DenoWebSocketBinding<TSocket extends DenoServerWebSocket = DenoServerWebSocket> {
|
|
14
|
+
fetch(request: Request, host: DenoWebSocketUpgradeHost<TSocket>): Response | Promise<Response>;
|
|
15
|
+
}
|
|
16
|
+
export interface DenoWebSocketBindingHost<TSocket extends DenoServerWebSocket = DenoServerWebSocket> {
|
|
17
|
+
configureWebSocketBinding(binding: DenoWebSocketBinding<TSocket> | undefined): void;
|
|
18
|
+
}
|
|
19
|
+
export type TypedOnMessageHandler<TEvents extends Record<string, unknown>, K extends keyof TEvents> = (payload: TEvents[K], socket: DenoServerWebSocket, request: Request) => void | Promise<void>;
|
|
20
|
+
export interface WebSocketGatewayContext {
|
|
21
|
+
request: Request;
|
|
22
|
+
socket: DenoServerWebSocket;
|
|
23
|
+
}
|
|
24
|
+
export type WebSocketModuleOptions = SharedWebSocketModuleOptions;
|
|
25
|
+
//# sourceMappingURL=deno-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deno-types.d.ts","sourceRoot":"","sources":["../../src/deno/deno-types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,IAAI,4BAA4B,EAAE,MAAM,aAAa,CAAC;AAE1F,MAAM,MAAM,oBAAoB,GAAG,IAAI,GAAG,MAAM,CAAC;AAEjD,MAAM,WAAW,mBAAoB,SAAQ,IAAI,CAAC,SAAS,EAAE,kBAAkB,GAAG,OAAO,GAAG,qBAAqB,GAAG,MAAM,CAAC;IACzH,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,0BAA0B,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB;IACnG,QAAQ,EAAE,QAAQ,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,wBAAwB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB;IACjG,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;CAChE;AAED,MAAM,WAAW,oBAAoB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB;IAC7F,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,wBAAwB,CAAC,OAAO,CAAC,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CAChG;AAED,MAAM,WAAW,wBAAwB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB;IACjG,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,IAAI,CAAC;CACrF;AAED,MAAM,MAAM,qBAAqB,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,SAAS,MAAM,OAAO,IAAI,CACpG,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE,OAAO,KACb,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAE1B,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,MAAM,sBAAsB,GAAG,4BAA4B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../../src/deno/deno.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC"}
|
package/dist/deno.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deno.d.ts","sourceRoot":"","sources":["../src/deno.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC"}
|
package/dist/deno.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './deno/deno.js';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Token } from '@fluojs/core';
|
|
2
|
+
import type { Container } from '@fluojs/di';
|
|
3
|
+
import type { ApplicationLogger, CompiledModule } from '@fluojs/runtime';
|
|
4
|
+
import type { WebSocketGatewayDescriptor, WebSocketGatewayHandlerDescriptor } from '../types.js';
|
|
5
|
+
export interface DiscoveryCandidate {
|
|
6
|
+
moduleName: string;
|
|
7
|
+
scope: 'request' | 'singleton' | 'transient';
|
|
8
|
+
targetType: Function;
|
|
9
|
+
token: Token;
|
|
10
|
+
}
|
|
11
|
+
export interface ResolvedGatewayInstance {
|
|
12
|
+
descriptor: WebSocketGatewayDescriptor;
|
|
13
|
+
instance: unknown;
|
|
14
|
+
}
|
|
15
|
+
export type ParsedWebSocketMessage = {
|
|
16
|
+
event?: string;
|
|
17
|
+
payload: unknown;
|
|
18
|
+
};
|
|
19
|
+
export type SharedWebSocketIncomingMessage = ArrayBuffer | ArrayBufferView | Uint8Array[] | string;
|
|
20
|
+
export declare function isFinitePositiveInteger(value: unknown): value is number;
|
|
21
|
+
export declare function normalizeGatewayPath(path: string): string;
|
|
22
|
+
export declare function parseIncomingMessage(data: SharedWebSocketIncomingMessage): ParsedWebSocketMessage;
|
|
23
|
+
export declare function discoverGatewayDescriptors(compiledModules: readonly CompiledModule[], logger: ApplicationLogger, loggerContext: string): WebSocketGatewayDescriptor[];
|
|
24
|
+
export declare function resolveGatewayInstance(runtimeContainer: Container, descriptor: WebSocketGatewayDescriptor, logger: ApplicationLogger, loggerContext: string): Promise<unknown | undefined>;
|
|
25
|
+
export declare function dispatchGatewayMessage<TSocket, TRequest>(resolved: readonly ResolvedGatewayInstance[], socket: TSocket, request: TRequest, data: SharedWebSocketIncomingMessage, logger: ApplicationLogger, loggerContext: string): Promise<void>;
|
|
26
|
+
export declare function dispatchGatewayDisconnect<TSocket>(resolved: readonly ResolvedGatewayInstance[], socket: TSocket, code: number, reason: string, socketId: string, logger: ApplicationLogger, loggerContext: string): Promise<void>;
|
|
27
|
+
export declare function runGatewayHandlers(instance: unknown, descriptor: WebSocketGatewayDescriptor, type: WebSocketGatewayHandlerDescriptor['type'], args: unknown[], logger: ApplicationLogger, loggerContext: string): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/internal/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAuB,KAAK,EAAE,MAAM,cAAc,CAAC;AAE/D,OAAO,KAAK,EAAY,SAAS,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGzE,OAAO,KAAK,EACV,0BAA0B,EAC1B,iCAAiC,EAClC,MAAM,aAAa,CAAC;AAIrB,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,WAAW,CAAC;IAC7C,UAAU,EAAE,QAAQ,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;CACd;AAQD,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,0BAA0B,CAAC;IACvC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,8BAA8B,GACtC,WAAW,GACX,eAAe,GACf,UAAU,EAAE,GACZ,MAAM,CAAC;AAEX,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAEvE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQzD;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,8BAA8B,GAAG,sBAAsB,CA4CjG;AAED,wBAAgB,0BAA0B,CACxC,eAAe,EAAE,SAAS,cAAc,EAAE,EAC1C,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,MAAM,GACpB,0BAA0B,EAAE,CA4B9B;AAED,wBAAsB,sBAAsB,CAC1C,gBAAgB,EAAE,SAAS,EAC3B,UAAU,EAAE,0BAA0B,EACtC,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,CAW9B;AAED,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAC5D,QAAQ,EAAE,SAAS,uBAAuB,EAAE,EAC5C,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,QAAQ,EACjB,IAAI,EAAE,8BAA8B,EACpC,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,wBAAsB,yBAAyB,CAAC,OAAO,EACrD,QAAQ,EAAE,SAAS,uBAAuB,EAAE,EAC5C,MAAM,EAAE,OAAO,EACf,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,OAAO,EACjB,UAAU,EAAE,0BAA0B,EACtC,IAAI,EAAE,iCAAiC,CAAC,MAAM,CAAC,EAC/C,IAAI,EAAE,OAAO,EAAE,EACf,MAAM,EAAE,iBAAiB,EACzB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAMf"}
|