@krisanalfa/bunest-adapter 0.1.0 → 0.3.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/README.md +435 -11
- package/dist/bun.adapter.d.ts +24 -4
- package/dist/bun.preflight-http-server.d.ts +62 -0
- package/dist/bun.ws-adapter.d.ts +48 -0
- package/dist/index.d.ts +7 -4
- package/dist/index.js +362 -53
- package/dist/index.js.map +7 -5
- package/dist/internal.types.d.ts +8 -0
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -15,10 +15,10 @@ var __legacyMetadataTS = (k, v) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
// lib/bun.adapter.ts
|
|
18
|
+
var {randomUUIDv7 } = globalThis.Bun;
|
|
18
19
|
import {
|
|
19
20
|
Logger
|
|
20
21
|
} from "@nestjs/common";
|
|
21
|
-
var {randomUUIDv7 } = globalThis.Bun;
|
|
22
22
|
import { AbstractHttpAdapter } from "@nestjs/core";
|
|
23
23
|
|
|
24
24
|
// lib/bun.body-parser.middleware.ts
|
|
@@ -367,6 +367,59 @@ class BunMiddlewareEngine {
|
|
|
367
367
|
}
|
|
368
368
|
}
|
|
369
369
|
|
|
370
|
+
// lib/bun.preflight-http-server.ts
|
|
371
|
+
class BunPreflightHttpServer {
|
|
372
|
+
adapter;
|
|
373
|
+
constructor(adapter) {
|
|
374
|
+
this.adapter = adapter;
|
|
375
|
+
}
|
|
376
|
+
on(event, callback) {}
|
|
377
|
+
once() {}
|
|
378
|
+
removeListener() {}
|
|
379
|
+
async stop(force) {
|
|
380
|
+
const server = this.adapter.getBunHttpServerInstance();
|
|
381
|
+
if (server instanceof BunPreflightHttpServer) {
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
await server.stop(force);
|
|
385
|
+
}
|
|
386
|
+
address() {
|
|
387
|
+
const server = this.adapter.getBunHttpServerInstance();
|
|
388
|
+
if (server instanceof BunPreflightHttpServer) {
|
|
389
|
+
const options = this.adapter.getBunServerOptions();
|
|
390
|
+
return {
|
|
391
|
+
address: options.hostname ?? "127.0.0.1",
|
|
392
|
+
port: options.port ?? 3000
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
return {
|
|
396
|
+
address: server.hostname,
|
|
397
|
+
port: server.port
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
setWsOptions(options) {
|
|
401
|
+
this.adapter.setWsOptions(options);
|
|
402
|
+
}
|
|
403
|
+
registerWsOpenHandler(handler) {
|
|
404
|
+
this.adapter.getWsHandlers().onOpen = handler;
|
|
405
|
+
}
|
|
406
|
+
registerWsMessageHandler(handler) {
|
|
407
|
+
this.adapter.getWsHandlers().onMessage = handler;
|
|
408
|
+
}
|
|
409
|
+
registerWsCloseHandler(handler) {
|
|
410
|
+
this.adapter.getWsHandlers().onClose = handler;
|
|
411
|
+
}
|
|
412
|
+
getWsHandlers() {
|
|
413
|
+
return this.adapter.getWsHandlers();
|
|
414
|
+
}
|
|
415
|
+
getBunServer() {
|
|
416
|
+
return this.adapter.getBunHttpServerInstance();
|
|
417
|
+
}
|
|
418
|
+
async close() {
|
|
419
|
+
await this.stop(true);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
370
423
|
// lib/bun.request.ts
|
|
371
424
|
import { parse } from "qs";
|
|
372
425
|
var NULL_PROTO = Object.getPrototypeOf(Object.create(null));
|
|
@@ -926,6 +979,16 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
926
979
|
res.setStatus(404);
|
|
927
980
|
res.end({ message: "Not Found" });
|
|
928
981
|
};
|
|
982
|
+
wsHandlers = {
|
|
983
|
+
onOpen: undefined,
|
|
984
|
+
onMessage: undefined,
|
|
985
|
+
onClose: undefined
|
|
986
|
+
};
|
|
987
|
+
wsMiddlewareEngine = new BunMiddlewareEngine;
|
|
988
|
+
wsOptions = {};
|
|
989
|
+
useWs = false;
|
|
990
|
+
useWsCors = false;
|
|
991
|
+
wsCorsHeaders;
|
|
929
992
|
constructor(bunServeOptions = {
|
|
930
993
|
development: false,
|
|
931
994
|
id: randomUUIDv7()
|
|
@@ -955,60 +1018,64 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
955
1018
|
use(middleware) {
|
|
956
1019
|
this.middlewareEngine.useGlobal(middleware);
|
|
957
1020
|
}
|
|
1021
|
+
createHttpMethodHandler(httpMethod) {
|
|
1022
|
+
return (pathOrHandler, maybeHandler) => {
|
|
1023
|
+
const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
|
|
1024
|
+
this.delegateRouteHandler(httpMethod, path, handler);
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
958
1027
|
get(pathOrHandler, maybeHandler) {
|
|
959
|
-
|
|
960
|
-
this.delegateRouteHandler("GET", path, handler);
|
|
1028
|
+
this.createHttpMethodHandler("GET")(pathOrHandler, maybeHandler);
|
|
961
1029
|
}
|
|
962
1030
|
post(pathOrHandler, maybeHandler) {
|
|
963
|
-
|
|
964
|
-
this.delegateRouteHandler("POST", path, handler);
|
|
1031
|
+
this.createHttpMethodHandler("POST")(pathOrHandler, maybeHandler);
|
|
965
1032
|
}
|
|
966
1033
|
put(pathOrHandler, maybeHandler) {
|
|
967
|
-
|
|
968
|
-
this.delegateRouteHandler("PUT", path, handler);
|
|
1034
|
+
this.createHttpMethodHandler("PUT")(pathOrHandler, maybeHandler);
|
|
969
1035
|
}
|
|
970
1036
|
patch(pathOrHandler, maybeHandler) {
|
|
971
|
-
|
|
972
|
-
this.delegateRouteHandler("PATCH", path, handler);
|
|
1037
|
+
this.createHttpMethodHandler("PATCH")(pathOrHandler, maybeHandler);
|
|
973
1038
|
}
|
|
974
1039
|
delete(pathOrHandler, maybeHandler) {
|
|
975
|
-
|
|
976
|
-
this.delegateRouteHandler("DELETE", path, handler);
|
|
1040
|
+
this.createHttpMethodHandler("DELETE")(pathOrHandler, maybeHandler);
|
|
977
1041
|
}
|
|
978
1042
|
head(pathOrHandler, maybeHandler) {
|
|
979
|
-
|
|
980
|
-
this.delegateRouteHandler("HEAD", path, handler);
|
|
1043
|
+
this.createHttpMethodHandler("HEAD")(pathOrHandler, maybeHandler);
|
|
981
1044
|
}
|
|
982
1045
|
options(pathOrHandler, maybeHandler) {
|
|
983
|
-
|
|
984
|
-
|
|
1046
|
+
this.createHttpMethodHandler("OPTIONS")(pathOrHandler, maybeHandler);
|
|
1047
|
+
}
|
|
1048
|
+
createUnsupportedMethod() {
|
|
1049
|
+
return (pathOrHandler, maybeHandler) => {
|
|
1050
|
+
throw new Error("Not supported.");
|
|
1051
|
+
};
|
|
985
1052
|
}
|
|
986
1053
|
all(pathOrHandler, maybeHandler) {
|
|
987
|
-
|
|
1054
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
988
1055
|
}
|
|
989
1056
|
propfind(pathOrHandler, maybeHandler) {
|
|
990
|
-
|
|
1057
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
991
1058
|
}
|
|
992
1059
|
proppatch(pathOrHandler, maybeHandler) {
|
|
993
|
-
|
|
1060
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
994
1061
|
}
|
|
995
1062
|
mkcol(pathOrHandler, maybeHandler) {
|
|
996
|
-
|
|
1063
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
997
1064
|
}
|
|
998
1065
|
copy(pathOrHandler, maybeHandler) {
|
|
999
|
-
|
|
1066
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1000
1067
|
}
|
|
1001
1068
|
move(pathOrHandler, maybeHandler) {
|
|
1002
|
-
|
|
1069
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1003
1070
|
}
|
|
1004
1071
|
lock(pathOrHandler, maybeHandler) {
|
|
1005
|
-
|
|
1072
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1006
1073
|
}
|
|
1007
1074
|
unlock(pathOrHandler, maybeHandler) {
|
|
1008
|
-
|
|
1075
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1009
1076
|
}
|
|
1010
1077
|
search(pathOrHandler, maybeHandler) {
|
|
1011
|
-
|
|
1078
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1012
1079
|
}
|
|
1013
1080
|
useStaticAssets(...args) {
|
|
1014
1081
|
throw new Error("Not supported.");
|
|
@@ -1023,12 +1090,15 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1023
1090
|
await this.httpServer.stop();
|
|
1024
1091
|
}
|
|
1025
1092
|
initHttpServer(options) {
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1093
|
+
const preflightServer = new BunPreflightHttpServer({
|
|
1094
|
+
getBunHttpServerInstance: () => this.getHttpServer(),
|
|
1095
|
+
getBunServerOptions: () => this.bunServeOptions,
|
|
1096
|
+
getWsHandlers: () => this.wsHandlers,
|
|
1097
|
+
setWsOptions: (wsOptions) => {
|
|
1098
|
+
this.wsOptions = wsOptions;
|
|
1099
|
+
}
|
|
1031
1100
|
});
|
|
1101
|
+
this.setHttpServer(preflightServer);
|
|
1032
1102
|
if (options.httpsOptions) {
|
|
1033
1103
|
this.bunServeOptions.tls = {
|
|
1034
1104
|
key: options.httpsOptions.key,
|
|
@@ -1041,6 +1111,7 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1041
1111
|
requestCert: options.httpsOptions.requestCert
|
|
1042
1112
|
};
|
|
1043
1113
|
}
|
|
1114
|
+
return preflightServer;
|
|
1044
1115
|
}
|
|
1045
1116
|
getRequestHostname(request) {
|
|
1046
1117
|
return request.hostname;
|
|
@@ -1115,11 +1186,17 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1115
1186
|
return BunVersionFilterMiddleware.createFilter(handler, version, versioningOptions);
|
|
1116
1187
|
}
|
|
1117
1188
|
listen(port, hostnameOrCallback, maybeCallback) {
|
|
1118
|
-
const hostname = typeof hostnameOrCallback === "string" ? hostnameOrCallback : "
|
|
1189
|
+
const hostname = typeof hostnameOrCallback === "string" ? hostnameOrCallback : this.bunServeOptions.hostname ?? "127.0.0.1";
|
|
1119
1190
|
const callback = typeof hostnameOrCallback === "function" ? hostnameOrCallback : maybeCallback;
|
|
1120
1191
|
const middlewareEngine = this.middlewareEngine;
|
|
1121
1192
|
const notFoundHandler = this.notFoundHandler;
|
|
1122
|
-
const
|
|
1193
|
+
const wsHandlers = this.wsHandlers;
|
|
1194
|
+
const bunServeOptions = this.bunServeOptions;
|
|
1195
|
+
this.setupWebSocketIfNeeded(wsHandlers, bunServeOptions);
|
|
1196
|
+
const fetch = async (request, server2) => {
|
|
1197
|
+
if (await this.upgradeWebSocket(request, server2)) {
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1123
1200
|
const bunRequest = new BunRequest(request);
|
|
1124
1201
|
const bunResponse = new BunResponse;
|
|
1125
1202
|
const routeHandler = middlewareEngine.findRouteHandler(bunRequest.method, bunRequest.pathname) ?? notFoundHandler;
|
|
@@ -1132,42 +1209,127 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1132
1209
|
});
|
|
1133
1210
|
return bunResponse.res();
|
|
1134
1211
|
};
|
|
1135
|
-
const
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1212
|
+
const server = this.createServer(port, hostname, bunServeOptions, fetch);
|
|
1213
|
+
callback?.();
|
|
1214
|
+
this.setHttpServer(server);
|
|
1215
|
+
}
|
|
1216
|
+
static isNumericPort(value) {
|
|
1217
|
+
return typeof value === "number" || !isNaN(Number(value));
|
|
1218
|
+
}
|
|
1219
|
+
static omitKeys(obj, ...keys) {
|
|
1220
|
+
const result = { ...obj };
|
|
1221
|
+
for (const key of keys) {
|
|
1222
|
+
Reflect.deleteProperty(result, key);
|
|
1223
|
+
}
|
|
1224
|
+
return result;
|
|
1225
|
+
}
|
|
1226
|
+
isWebSocketUpgradeRequest(request) {
|
|
1227
|
+
const upgradeHeader = request.headers.get("upgrade");
|
|
1228
|
+
const connectionHeader = request.headers.get("connection");
|
|
1229
|
+
return !!(upgradeHeader?.toLowerCase() === "websocket" && connectionHeader?.toLowerCase().includes("upgrade"));
|
|
1230
|
+
}
|
|
1231
|
+
async handleWebSocketCors(request) {
|
|
1232
|
+
if (this.wsCorsHeaders) {
|
|
1233
|
+
return this.wsCorsHeaders;
|
|
1234
|
+
}
|
|
1235
|
+
const bunRequest = new BunRequest(request);
|
|
1236
|
+
const bunResponse = new BunResponse;
|
|
1237
|
+
await this.wsMiddlewareEngine.run({
|
|
1238
|
+
req: bunRequest,
|
|
1239
|
+
res: bunResponse,
|
|
1240
|
+
method: bunRequest.method,
|
|
1241
|
+
path: bunRequest.pathname,
|
|
1242
|
+
requestHandler: (req, res) => {
|
|
1243
|
+
res.end();
|
|
1139
1244
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1245
|
+
});
|
|
1246
|
+
const response = await bunResponse.res();
|
|
1247
|
+
this.wsCorsHeaders = response.headers;
|
|
1248
|
+
return this.wsCorsHeaders;
|
|
1249
|
+
}
|
|
1250
|
+
async upgradeWebSocket(request, server) {
|
|
1251
|
+
if (!this.useWs || !this.isWebSocketUpgradeRequest(request)) {
|
|
1252
|
+
return false;
|
|
1253
|
+
}
|
|
1254
|
+
if (!this.useWsCors) {
|
|
1255
|
+
return server.upgrade(request, {
|
|
1256
|
+
data: this.wsOptions.clientDataFactory ? this.wsOptions.clientDataFactory(new BunRequest(request)) : {}
|
|
1257
|
+
});
|
|
1258
|
+
}
|
|
1259
|
+
const headers = await this.handleWebSocketCors(request);
|
|
1260
|
+
return server.upgrade(request, {
|
|
1261
|
+
headers,
|
|
1262
|
+
data: this.wsOptions.clientDataFactory ? this.wsOptions.clientDataFactory(new BunRequest(request)) : {}
|
|
1263
|
+
});
|
|
1264
|
+
}
|
|
1265
|
+
setupWebSocketIfNeeded(wsHandlers, bunServeOptions) {
|
|
1266
|
+
const useWs = !!wsHandlers.onOpen && !!wsHandlers.onMessage && !!wsHandlers.onClose;
|
|
1267
|
+
this.useWs = useWs;
|
|
1268
|
+
if (useWs) {
|
|
1269
|
+
const getServer = this.getHttpServer.bind(this);
|
|
1270
|
+
const onMessage = wsHandlers.onMessage;
|
|
1271
|
+
const onOpen = wsHandlers.onOpen;
|
|
1272
|
+
const onClose = wsHandlers.onClose;
|
|
1273
|
+
bunServeOptions.websocket = {
|
|
1274
|
+
...this.wsOptions,
|
|
1275
|
+
message: (ws, message) => {
|
|
1276
|
+
ws.data.onMessageInternal?.(message);
|
|
1277
|
+
onMessage?.(ws, message, getServer());
|
|
1278
|
+
},
|
|
1279
|
+
open: (ws) => {
|
|
1280
|
+
onOpen?.(ws);
|
|
1281
|
+
},
|
|
1282
|
+
close: (ws, code, reason) => {
|
|
1283
|
+
ws.data.onCloseInternal?.();
|
|
1284
|
+
ws.data.onDisconnect?.(ws);
|
|
1285
|
+
onClose?.(ws, code, reason);
|
|
1286
|
+
}
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
const useWsCors = typeof this.wsOptions.cors !== "undefined";
|
|
1290
|
+
this.useWsCors = useWsCors;
|
|
1291
|
+
if (useWsCors) {
|
|
1292
|
+
const corsMiddleware = new BunCorsMiddleware({
|
|
1293
|
+
corsOptions: this.wsOptions.cors === true ? undefined : this.wsOptions.cors
|
|
1294
|
+
});
|
|
1295
|
+
this.wsMiddlewareEngine.useGlobal(corsMiddleware.run.bind(corsMiddleware));
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
createServer(port, hostname, bunServeOptions, fetch) {
|
|
1299
|
+
return BunAdapter.isNumericPort(port) ? Bun.serve({
|
|
1300
|
+
...bunServeOptions,
|
|
1144
1301
|
hostname,
|
|
1145
1302
|
port,
|
|
1146
1303
|
routes: this.routes,
|
|
1147
1304
|
fetch
|
|
1148
1305
|
}) : Bun.serve({
|
|
1149
|
-
...
|
|
1306
|
+
...BunAdapter.omitKeys(bunServeOptions, "idleTimeout", "port", "hostname"),
|
|
1150
1307
|
unix: port,
|
|
1151
1308
|
routes: this.routes,
|
|
1152
1309
|
fetch
|
|
1153
1310
|
});
|
|
1154
|
-
if (typeof port === "string" && isNaN(Number(port))) {
|
|
1155
|
-
this.logger.log(`Bun server listening on unix socket: ${port}`);
|
|
1156
|
-
}
|
|
1157
|
-
callback?.();
|
|
1158
|
-
Object.defineProperty(server, "address", {
|
|
1159
|
-
configurable: true,
|
|
1160
|
-
enumerable: true,
|
|
1161
|
-
get: () => ({ address: server.hostname, port: server.port })
|
|
1162
|
-
});
|
|
1163
|
-
this.setHttpServer(server);
|
|
1164
1311
|
}
|
|
1165
1312
|
delegateRouteHandler(method, path, handler) {
|
|
1313
|
+
this.ensureRouteExists(path);
|
|
1314
|
+
const requestHandler = this.prepareRequestHandler(method, path, handler);
|
|
1315
|
+
this.routes[path][method] = this.createRouteFetchHandler(path, method, requestHandler);
|
|
1316
|
+
}
|
|
1317
|
+
ensureRouteExists(path) {
|
|
1166
1318
|
if (!(path in this.routes)) {
|
|
1167
1319
|
this.routes[path] = Object.create(null);
|
|
1168
1320
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1321
|
+
}
|
|
1322
|
+
prepareRequestHandler(method, path, handler) {
|
|
1323
|
+
if (!this.useVersioning) {
|
|
1324
|
+
return handler;
|
|
1325
|
+
}
|
|
1326
|
+
return this.createChainedHandlerForVersioningResolution(this.createVersioningHandlers(method, path, handler), this.notFoundHandler);
|
|
1327
|
+
}
|
|
1328
|
+
createRouteFetchHandler(path, method, requestHandler) {
|
|
1329
|
+
return async (request, server) => {
|
|
1330
|
+
if (path === "/" && await this.upgradeWebSocket(request, server)) {
|
|
1331
|
+
return;
|
|
1332
|
+
}
|
|
1171
1333
|
const bunRequest = new BunRequest(request);
|
|
1172
1334
|
const bunResponse = new BunResponse;
|
|
1173
1335
|
await this.middlewareEngine.run({
|
|
@@ -1263,12 +1425,159 @@ BunFileInterceptor = __legacyDecorateClassTS([
|
|
|
1263
1425
|
typeof HttpAdapterHost === "undefined" ? Object : HttpAdapterHost
|
|
1264
1426
|
])
|
|
1265
1427
|
], BunFileInterceptor);
|
|
1428
|
+
// lib/bun.ws-adapter.ts
|
|
1429
|
+
import {
|
|
1430
|
+
AbstractWsAdapter
|
|
1431
|
+
} from "@nestjs/websockets";
|
|
1432
|
+
import { EMPTY, Subject, mergeMap } from "rxjs";
|
|
1433
|
+
import { Logger as Logger2 } from "@nestjs/common";
|
|
1434
|
+
import { isNil } from "@nestjs/common/utils/shared.utils.js";
|
|
1435
|
+
var WS_READY_STATE_OPEN = 1;
|
|
1436
|
+
var defaultMessageParser = (data) => {
|
|
1437
|
+
if (typeof data === "string") {
|
|
1438
|
+
return JSON.parse(data);
|
|
1439
|
+
}
|
|
1440
|
+
if (data instanceof ArrayBuffer) {
|
|
1441
|
+
return JSON.parse(new TextDecoder().decode(data));
|
|
1442
|
+
}
|
|
1443
|
+
if (Buffer.isBuffer(data)) {
|
|
1444
|
+
return JSON.parse(data.toString("utf8"));
|
|
1445
|
+
}
|
|
1446
|
+
return JSON.parse(Buffer.concat(data).toString("utf8"));
|
|
1447
|
+
};
|
|
1448
|
+
|
|
1449
|
+
class BunWsAdapter extends AbstractWsAdapter {
|
|
1450
|
+
logger = new Logger2(BunWsAdapter.name);
|
|
1451
|
+
nestApp;
|
|
1452
|
+
messageParser = defaultMessageParser;
|
|
1453
|
+
onOpenHandler;
|
|
1454
|
+
globalHandlersInitialized = false;
|
|
1455
|
+
constructor(appOrHttpServer) {
|
|
1456
|
+
super(appOrHttpServer);
|
|
1457
|
+
if (!appOrHttpServer || !("getHttpAdapter" in appOrHttpServer)) {
|
|
1458
|
+
throw new Error("BunWsAdapter requires a NestApplication instance in the constructor.");
|
|
1459
|
+
}
|
|
1460
|
+
this.nestApp = appOrHttpServer;
|
|
1461
|
+
}
|
|
1462
|
+
create(_port, options) {
|
|
1463
|
+
if (options?.messageParser) {
|
|
1464
|
+
this.messageParser = options.messageParser;
|
|
1465
|
+
}
|
|
1466
|
+
const server = this.nestApp.getHttpAdapter().getHttpServer();
|
|
1467
|
+
const wsOptions = this.extractWsOptions(options);
|
|
1468
|
+
server.setWsOptions(wsOptions);
|
|
1469
|
+
this.initializeGlobalHandlers(server);
|
|
1470
|
+
return server;
|
|
1471
|
+
}
|
|
1472
|
+
extractWsOptions(options) {
|
|
1473
|
+
if (!options) {
|
|
1474
|
+
return {};
|
|
1475
|
+
}
|
|
1476
|
+
const wsOptions = { ...options };
|
|
1477
|
+
delete wsOptions.messageParser;
|
|
1478
|
+
return wsOptions;
|
|
1479
|
+
}
|
|
1480
|
+
async close(server) {
|
|
1481
|
+
await server.close();
|
|
1482
|
+
}
|
|
1483
|
+
bindClientConnect(server, callback) {
|
|
1484
|
+
this.onOpenHandler = callback;
|
|
1485
|
+
}
|
|
1486
|
+
bindClientDisconnect(client, callback) {
|
|
1487
|
+
const existingHandler = client.data.onDisconnect;
|
|
1488
|
+
client.data.onDisconnect = (ws) => {
|
|
1489
|
+
existingHandler?.(ws);
|
|
1490
|
+
callback(client);
|
|
1491
|
+
};
|
|
1492
|
+
}
|
|
1493
|
+
bindMessageHandlers(client, handlers, transform) {
|
|
1494
|
+
const handlerMap = this.buildHandlerMap(handlers);
|
|
1495
|
+
const message$ = new Subject;
|
|
1496
|
+
let isActive = true;
|
|
1497
|
+
const existingOnMessage = client.data.onMessageInternal;
|
|
1498
|
+
client.data.onMessageInternal = (data) => {
|
|
1499
|
+
existingOnMessage?.(data);
|
|
1500
|
+
if (isActive) {
|
|
1501
|
+
message$.next(data);
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
const subscription = message$.pipe(mergeMap((data) => this.processMessage(data, handlerMap, transform))).subscribe({
|
|
1505
|
+
next: (response) => {
|
|
1506
|
+
this.sendResponse(client, response, isActive);
|
|
1507
|
+
},
|
|
1508
|
+
error: (err) => {
|
|
1509
|
+
this.logger.error("Message processing error", err instanceof Error ? err.stack : err);
|
|
1510
|
+
}
|
|
1511
|
+
});
|
|
1512
|
+
const existingOnClose = client.data.onCloseInternal;
|
|
1513
|
+
client.data.onCloseInternal = () => {
|
|
1514
|
+
existingOnClose?.();
|
|
1515
|
+
isActive = false;
|
|
1516
|
+
this.cleanupClient(message$, subscription);
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
initializeGlobalHandlers(server) {
|
|
1520
|
+
if (this.globalHandlersInitialized) {
|
|
1521
|
+
return;
|
|
1522
|
+
}
|
|
1523
|
+
this.globalHandlersInitialized = true;
|
|
1524
|
+
server.registerWsOpenHandler((ws) => {
|
|
1525
|
+
this.onOpenHandler?.(ws);
|
|
1526
|
+
});
|
|
1527
|
+
server.registerWsMessageHandler(() => {});
|
|
1528
|
+
server.registerWsCloseHandler(() => {});
|
|
1529
|
+
}
|
|
1530
|
+
buildHandlerMap(handlers) {
|
|
1531
|
+
const map = new Map;
|
|
1532
|
+
for (const handler of handlers) {
|
|
1533
|
+
map.set(handler.message, handler);
|
|
1534
|
+
}
|
|
1535
|
+
return map;
|
|
1536
|
+
}
|
|
1537
|
+
processMessage(data, handlerMap, transform) {
|
|
1538
|
+
try {
|
|
1539
|
+
const parsed = this.messageParser(data);
|
|
1540
|
+
if (typeof parsed.event !== "string") {
|
|
1541
|
+
return EMPTY;
|
|
1542
|
+
}
|
|
1543
|
+
const handler = handlerMap.get(parsed.event);
|
|
1544
|
+
if (!handler) {
|
|
1545
|
+
return EMPTY;
|
|
1546
|
+
}
|
|
1547
|
+
const result = handler.callback(parsed.data, parsed.event);
|
|
1548
|
+
return transform(result).pipe(mergeMap((value) => isNil(value) ? EMPTY : [value]));
|
|
1549
|
+
} catch (error) {
|
|
1550
|
+
this.logger.warn("Failed to parse WebSocket message", error instanceof Error ? error.message : String(error));
|
|
1551
|
+
return EMPTY;
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
sendResponse(client, response, isActive) {
|
|
1555
|
+
if (!isActive || client.readyState !== WS_READY_STATE_OPEN) {
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
if (response instanceof ArrayBuffer) {
|
|
1559
|
+
client.send(response);
|
|
1560
|
+
return;
|
|
1561
|
+
}
|
|
1562
|
+
if (ArrayBuffer.isView(response)) {
|
|
1563
|
+
client.send(response.buffer);
|
|
1564
|
+
return;
|
|
1565
|
+
}
|
|
1566
|
+
client.send(JSON.stringify(response));
|
|
1567
|
+
}
|
|
1568
|
+
cleanupClient(message$, subscription) {
|
|
1569
|
+
message$.complete();
|
|
1570
|
+
subscription.unsubscribe();
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1266
1573
|
export {
|
|
1574
|
+
BunWsAdapter,
|
|
1267
1575
|
BunResponse,
|
|
1268
1576
|
BunRequest,
|
|
1577
|
+
BunPreflightHttpServer,
|
|
1269
1578
|
BunFileInterceptor,
|
|
1270
1579
|
BunAdapter
|
|
1271
1580
|
};
|
|
1272
1581
|
|
|
1273
|
-
//# debugId=
|
|
1582
|
+
//# debugId=1BD5D75380392B3E64756E2164756E21
|
|
1274
1583
|
//# sourceMappingURL=index.js.map
|