@krisanalfa/bunest-adapter 0.1.0 → 0.4.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 +515 -12
- package/dist/bun.adapter.d.ts +9 -48
- package/dist/bun.internal.types.d.ts +22 -0
- package/dist/bun.preflight-http-server.d.ts +44 -0
- package/dist/bun.request.d.ts +41 -1
- package/dist/bun.response.d.ts +28 -0
- package/dist/bun.server-instance.d.ts +131 -0
- package/dist/bun.ws-adapter.d.ts +38 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +652 -237
- package/dist/index.js.map +12 -9
- package/package.json +16 -7
package/dist/index.js
CHANGED
|
@@ -16,11 +16,49 @@ var __legacyMetadataTS = (k, v) => {
|
|
|
16
16
|
|
|
17
17
|
// lib/bun.adapter.ts
|
|
18
18
|
import {
|
|
19
|
-
Logger
|
|
19
|
+
Logger as Logger2
|
|
20
20
|
} from "@nestjs/common";
|
|
21
21
|
var {randomUUIDv7 } = globalThis.Bun;
|
|
22
22
|
import { AbstractHttpAdapter } from "@nestjs/core";
|
|
23
23
|
|
|
24
|
+
// lib/bun.preflight-http-server.ts
|
|
25
|
+
class BunPreflightHttpServer {
|
|
26
|
+
serverInstance;
|
|
27
|
+
constructor(serverInstance) {
|
|
28
|
+
this.serverInstance = serverInstance;
|
|
29
|
+
}
|
|
30
|
+
on(event, callback) {}
|
|
31
|
+
once() {}
|
|
32
|
+
removeListener() {}
|
|
33
|
+
async stop(force) {
|
|
34
|
+
await this.serverInstance.stop(force);
|
|
35
|
+
}
|
|
36
|
+
address() {
|
|
37
|
+
return this.serverInstance.address();
|
|
38
|
+
}
|
|
39
|
+
setWsOptions(options) {
|
|
40
|
+
this.serverInstance.setWsOptions(options);
|
|
41
|
+
}
|
|
42
|
+
registerWsOpenHandler(handler) {
|
|
43
|
+
this.serverInstance.registerWsOpenHandler(handler);
|
|
44
|
+
}
|
|
45
|
+
registerWsMessageHandler(handler) {
|
|
46
|
+
this.serverInstance.registerWsMessageHandler(handler);
|
|
47
|
+
}
|
|
48
|
+
registerWsCloseHandler(handler) {
|
|
49
|
+
this.serverInstance.registerWsCloseHandler(handler);
|
|
50
|
+
}
|
|
51
|
+
getBunServer() {
|
|
52
|
+
return this.serverInstance.getBunServer();
|
|
53
|
+
}
|
|
54
|
+
async close() {
|
|
55
|
+
await this.serverInstance.close();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// lib/bun.server-instance.ts
|
|
60
|
+
import { Logger } from "@nestjs/common";
|
|
61
|
+
|
|
24
62
|
// lib/bun.body-parser.middleware.ts
|
|
25
63
|
var GET_CODE = 71;
|
|
26
64
|
var HEAD_CODE = 72;
|
|
@@ -179,6 +217,7 @@ class BunCorsMiddleware {
|
|
|
179
217
|
}
|
|
180
218
|
|
|
181
219
|
// lib/bun.middleware-engine.ts
|
|
220
|
+
var {peek } = globalThis.Bun;
|
|
182
221
|
var EMPTY_HANDLERS = new Array(0);
|
|
183
222
|
var noop = () => {};
|
|
184
223
|
|
|
@@ -258,6 +297,17 @@ class BunMiddlewareEngine {
|
|
|
258
297
|
const keyPathLen = keyPath.length;
|
|
259
298
|
return path === keyPath || pathLen > keyPathLen && path.charCodeAt(keyPathLen) === 47 && path.startsWith(keyPath);
|
|
260
299
|
}
|
|
300
|
+
async executeHandler(handler, req, res, next) {
|
|
301
|
+
if (!handler)
|
|
302
|
+
return;
|
|
303
|
+
const result = handler(req, res, next);
|
|
304
|
+
if (result instanceof Promise) {
|
|
305
|
+
const peeked = peek(result);
|
|
306
|
+
if (peeked !== result)
|
|
307
|
+
return;
|
|
308
|
+
await result;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
261
311
|
async run(options) {
|
|
262
312
|
try {
|
|
263
313
|
const middlewares = this.getMiddlewareChain(options.method, options.path);
|
|
@@ -333,25 +383,18 @@ class BunMiddlewareEngine {
|
|
|
333
383
|
if (err)
|
|
334
384
|
throw err;
|
|
335
385
|
if (index < chainLength) {
|
|
336
|
-
|
|
337
|
-
const result = handler(req, res, next);
|
|
338
|
-
if (result instanceof Promise)
|
|
339
|
-
await result;
|
|
386
|
+
await this.executeHandler(chain[index++], req, res, next);
|
|
340
387
|
return;
|
|
341
388
|
}
|
|
342
389
|
if (index === chainLength) {
|
|
343
390
|
index++;
|
|
344
391
|
if (!res.isEnded()) {
|
|
345
|
-
|
|
346
|
-
if (result instanceof Promise)
|
|
347
|
-
await result;
|
|
392
|
+
await this.executeHandler(requestHandler, req, res, next);
|
|
348
393
|
}
|
|
349
394
|
return;
|
|
350
395
|
}
|
|
351
|
-
if (
|
|
352
|
-
|
|
353
|
-
if (result instanceof Promise)
|
|
354
|
-
await result;
|
|
396
|
+
if (!res.isEnded()) {
|
|
397
|
+
await this.executeHandler(this.notFoundHandler ?? undefined, req, res, () => Promise.resolve());
|
|
355
398
|
}
|
|
356
399
|
};
|
|
357
400
|
await next();
|
|
@@ -359,8 +402,11 @@ class BunMiddlewareEngine {
|
|
|
359
402
|
async handleError(error, req, res) {
|
|
360
403
|
if (this.errorHandler !== null) {
|
|
361
404
|
const result = this.errorHandler(error, req, res, noop);
|
|
362
|
-
if (result instanceof Promise)
|
|
363
|
-
|
|
405
|
+
if (result instanceof Promise) {
|
|
406
|
+
const peeked = peek(result);
|
|
407
|
+
if (peeked === result)
|
|
408
|
+
await result;
|
|
409
|
+
}
|
|
364
410
|
return res;
|
|
365
411
|
}
|
|
366
412
|
throw error;
|
|
@@ -397,7 +443,10 @@ class BunRequest {
|
|
|
397
443
|
}
|
|
398
444
|
get socket() {
|
|
399
445
|
return {
|
|
400
|
-
encrypted: this._parsedUrl.protocol === "https:"
|
|
446
|
+
encrypted: this._parsedUrl.protocol === "https:",
|
|
447
|
+
setKeepAlive: () => {},
|
|
448
|
+
setNoDelay: () => {},
|
|
449
|
+
setTimeout: () => {}
|
|
401
450
|
};
|
|
402
451
|
}
|
|
403
452
|
get url() {
|
|
@@ -492,6 +541,18 @@ class BunRequest {
|
|
|
492
541
|
cloned._settings = this._settings;
|
|
493
542
|
return cloned;
|
|
494
543
|
}
|
|
544
|
+
on(event, listener) {
|
|
545
|
+
return this;
|
|
546
|
+
}
|
|
547
|
+
once(event, listener) {
|
|
548
|
+
return this;
|
|
549
|
+
}
|
|
550
|
+
off(event, listener) {
|
|
551
|
+
return this;
|
|
552
|
+
}
|
|
553
|
+
emit(event, ...args) {
|
|
554
|
+
return true;
|
|
555
|
+
}
|
|
495
556
|
}
|
|
496
557
|
|
|
497
558
|
// lib/bun.response.ts
|
|
@@ -504,11 +565,14 @@ class BunResponse {
|
|
|
504
565
|
response;
|
|
505
566
|
cookieMap = new CookieMap;
|
|
506
567
|
static textDecoder = new TextDecoder;
|
|
568
|
+
writable = true;
|
|
507
569
|
headers = null;
|
|
508
570
|
statusCode = 200;
|
|
509
571
|
ended = false;
|
|
510
572
|
cookieHeaders = null;
|
|
511
573
|
chunks = [];
|
|
574
|
+
streamWriter = null;
|
|
575
|
+
textEncoder = new TextEncoder;
|
|
512
576
|
constructor() {
|
|
513
577
|
this.response = new Promise((r) => {
|
|
514
578
|
this.resolve = r;
|
|
@@ -542,6 +606,16 @@ class BunResponse {
|
|
|
542
606
|
if (this.ended)
|
|
543
607
|
return;
|
|
544
608
|
this.ended = true;
|
|
609
|
+
if (this.streamWriter) {
|
|
610
|
+
try {
|
|
611
|
+
if (body) {
|
|
612
|
+
const bytes = typeof body === "string" ? this.textEncoder.encode(body) : body instanceof Uint8Array ? body : this.textEncoder.encode(JSON.stringify(body));
|
|
613
|
+
this.streamWriter.write(bytes);
|
|
614
|
+
}
|
|
615
|
+
this.streamWriter.close();
|
|
616
|
+
} catch {}
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
545
619
|
this.applyCookieHeaders();
|
|
546
620
|
if (this.chunks.length > 0) {
|
|
547
621
|
const finalBody = this.combineChunks(body);
|
|
@@ -551,14 +625,19 @@ class BunResponse {
|
|
|
551
625
|
this.sendResponse(body);
|
|
552
626
|
}
|
|
553
627
|
applyCookieHeaders() {
|
|
628
|
+
if (this.cookieMap.size === 0)
|
|
629
|
+
return;
|
|
554
630
|
this.cookieHeaders ??= this.cookieMap.toSetCookieHeaders();
|
|
555
|
-
|
|
556
|
-
this.setHeader("set-cookie", this.cookieHeaders.join(`
|
|
631
|
+
this.setHeader("set-cookie", this.cookieHeaders.join(`
|
|
557
632
|
`));
|
|
558
|
-
}
|
|
559
633
|
}
|
|
560
634
|
sendResponse(body) {
|
|
561
635
|
if (body !== null && typeof body === "object") {
|
|
636
|
+
const ctor = body.constructor;
|
|
637
|
+
if (ctor === Object || ctor === Array) {
|
|
638
|
+
this.resolve(this.buildJsonResponse(body));
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
562
641
|
if (body instanceof Uint8Array || body instanceof Blob) {
|
|
563
642
|
this.resolve(this.createResponse(body));
|
|
564
643
|
return;
|
|
@@ -642,10 +721,30 @@ class BunResponse {
|
|
|
642
721
|
once(event, listener) {
|
|
643
722
|
return this;
|
|
644
723
|
}
|
|
724
|
+
emit(event, ...args) {
|
|
725
|
+
return true;
|
|
726
|
+
}
|
|
727
|
+
get writableEnded() {
|
|
728
|
+
return this.ended;
|
|
729
|
+
}
|
|
645
730
|
write(chunk) {
|
|
646
731
|
if (this.ended) {
|
|
647
732
|
return false;
|
|
648
733
|
}
|
|
734
|
+
const contentType = this.headers?.get("content-type") ?? "";
|
|
735
|
+
const isStreamingResponse = contentType.includes("text/event-stream") || contentType.includes("application/octet-stream");
|
|
736
|
+
if (isStreamingResponse && !this.streamWriter) {
|
|
737
|
+
this.initializeStreamingMode();
|
|
738
|
+
}
|
|
739
|
+
if (this.streamWriter) {
|
|
740
|
+
try {
|
|
741
|
+
const bytes = typeof chunk === "string" ? this.textEncoder.encode(chunk) : chunk instanceof Uint8Array ? chunk : chunk instanceof Buffer ? new Uint8Array(chunk) : this.textEncoder.encode(JSON.stringify(chunk));
|
|
742
|
+
this.streamWriter.write(bytes);
|
|
743
|
+
return true;
|
|
744
|
+
} catch {
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
}
|
|
649
748
|
if (typeof chunk === "string") {
|
|
650
749
|
this.chunks.push(chunk);
|
|
651
750
|
return true;
|
|
@@ -668,6 +767,12 @@ class BunResponse {
|
|
|
668
767
|
}
|
|
669
768
|
return true;
|
|
670
769
|
}
|
|
770
|
+
initializeStreamingMode() {
|
|
771
|
+
const { readable, writable } = new TransformStream;
|
|
772
|
+
this.streamWriter = writable.getWriter();
|
|
773
|
+
this.applyCookieHeaders();
|
|
774
|
+
this.resolve(this.createResponse(readable));
|
|
775
|
+
}
|
|
671
776
|
getHeader(name) {
|
|
672
777
|
return this.headers?.get(name.toLowerCase()) ?? null;
|
|
673
778
|
}
|
|
@@ -711,9 +816,7 @@ class BunResponse {
|
|
|
711
816
|
if (headers === null || headers.size === 0) {
|
|
712
817
|
return Response.json(body, { status: this.statusCode });
|
|
713
818
|
}
|
|
714
|
-
|
|
715
|
-
headers.set("content-type", JSON_CONTENT_TYPE);
|
|
716
|
-
}
|
|
819
|
+
headers.set("content-type", JSON_CONTENT_TYPE);
|
|
717
820
|
return Response.json(body, {
|
|
718
821
|
status: this.statusCode,
|
|
719
822
|
headers: Object.fromEntries(headers)
|
|
@@ -733,13 +836,9 @@ class BunResponse {
|
|
|
733
836
|
|
|
734
837
|
// lib/bun.version-filter.middleware.ts
|
|
735
838
|
import { VERSION_NEUTRAL, VersioningType } from "@nestjs/common";
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
}
|
|
740
|
-
function callNext(next) {
|
|
741
|
-
return next();
|
|
742
|
-
}
|
|
839
|
+
var CUSTOM_VERSIONING_PHASE_KEY = "_cvp";
|
|
840
|
+
var CUSTOM_VERSIONING_CANDIDATES_KEY = "_cvc";
|
|
841
|
+
var CUSTOM_VERSIONING_BEST_CANDIDATE_KEY = "_cvb";
|
|
743
842
|
|
|
744
843
|
class BunVersionFilterMiddleware {
|
|
745
844
|
static createFilter(handler, version, versioningOptions) {
|
|
@@ -767,24 +866,26 @@ class BunVersionFilterMiddleware {
|
|
|
767
866
|
static computeAcceptsNeutral(version) {
|
|
768
867
|
return version === VERSION_NEUTRAL || Array.isArray(version) && version.includes(VERSION_NEUTRAL);
|
|
769
868
|
}
|
|
770
|
-
static getHeader(req, name) {
|
|
771
|
-
return req.headers.get(name) ?? undefined;
|
|
772
|
-
}
|
|
773
869
|
static createCustomVersionFilter(handler, version, options) {
|
|
774
870
|
const isVersionArray = Array.isArray(version);
|
|
775
871
|
const versionSet = isVersionArray ? new Set(version) : null;
|
|
776
872
|
const singleVersion = isVersionArray ? null : version;
|
|
777
|
-
return
|
|
873
|
+
return (req, res, next) => {
|
|
778
874
|
const extracted = options.extractor(req);
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
875
|
+
let phase = req.get(CUSTOM_VERSIONING_PHASE_KEY);
|
|
876
|
+
if (phase === undefined) {
|
|
877
|
+
phase = 0;
|
|
878
|
+
req.set(CUSTOM_VERSIONING_PHASE_KEY, phase);
|
|
879
|
+
}
|
|
880
|
+
let candidates = req.get(CUSTOM_VERSIONING_CANDIDATES_KEY);
|
|
881
|
+
if (!candidates) {
|
|
882
|
+
candidates = new Map;
|
|
883
|
+
req.set(CUSTOM_VERSIONING_CANDIDATES_KEY, candidates);
|
|
884
|
+
}
|
|
885
|
+
const extractedVersions = Array.isArray(extracted) ? extracted : [extracted];
|
|
785
886
|
let match;
|
|
786
887
|
let matchIndex = -1;
|
|
787
|
-
for (let i = 0
|
|
888
|
+
for (let i = 0, len = extractedVersions.length;i < len; i++) {
|
|
788
889
|
const extractedVersion = extractedVersions[i];
|
|
789
890
|
if (versionSet ? versionSet.has(extractedVersion) : extractedVersion === singleVersion) {
|
|
790
891
|
match = extractedVersion;
|
|
@@ -793,44 +894,44 @@ class BunVersionFilterMiddleware {
|
|
|
793
894
|
}
|
|
794
895
|
}
|
|
795
896
|
if (match) {
|
|
796
|
-
if (
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
});
|
|
801
|
-
return callNext(next);
|
|
897
|
+
if (phase === 0) {
|
|
898
|
+
candidates.set(match, matchIndex);
|
|
899
|
+
next();
|
|
900
|
+
return;
|
|
802
901
|
}
|
|
803
|
-
if (
|
|
804
|
-
return
|
|
902
|
+
if (req.get(CUSTOM_VERSIONING_BEST_CANDIDATE_KEY) === match) {
|
|
903
|
+
return handler(req, res, next);
|
|
805
904
|
}
|
|
806
905
|
}
|
|
807
|
-
|
|
906
|
+
next();
|
|
808
907
|
};
|
|
809
908
|
}
|
|
810
909
|
static createMediaTypeVersionFilter(handler, version, options) {
|
|
811
910
|
const acceptsNeutral = this.computeAcceptsNeutral(version);
|
|
812
911
|
const versionMatches = this.createVersionMatcher(version);
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
912
|
+
const key = options.key;
|
|
913
|
+
const keyLength = key.length;
|
|
914
|
+
return (req, res, next) => {
|
|
915
|
+
const acceptHeader = req.headers.get("accept");
|
|
816
916
|
if (acceptHeader) {
|
|
817
917
|
const semiIndex = acceptHeader.indexOf(";");
|
|
818
918
|
if (semiIndex !== -1) {
|
|
819
919
|
const versionPart = acceptHeader.substring(semiIndex + 1).trim();
|
|
820
|
-
const keyIndex = versionPart.indexOf(
|
|
920
|
+
const keyIndex = versionPart.indexOf(key);
|
|
821
921
|
if (keyIndex !== -1) {
|
|
822
922
|
const headerVersion = versionPart.substring(keyIndex + keyLength);
|
|
823
923
|
if (versionMatches(headerVersion)) {
|
|
824
|
-
return
|
|
924
|
+
return handler(req, res, next);
|
|
825
925
|
}
|
|
826
|
-
|
|
926
|
+
next();
|
|
927
|
+
return;
|
|
827
928
|
}
|
|
828
929
|
}
|
|
829
930
|
}
|
|
830
931
|
if (acceptsNeutral) {
|
|
831
|
-
return
|
|
932
|
+
return handler(req, res, next);
|
|
832
933
|
}
|
|
833
|
-
|
|
934
|
+
next();
|
|
834
935
|
};
|
|
835
936
|
}
|
|
836
937
|
static createHeaderVersionFilter(handler, version, options) {
|
|
@@ -840,21 +941,25 @@ class BunVersionFilterMiddleware {
|
|
|
840
941
|
const hasNeutralDefault = defaultVersion === VERSION_NEUTRAL;
|
|
841
942
|
const resolvedDefault = this.resolveDefaultVersion(version, defaultVersion);
|
|
842
943
|
const headerName = options.header;
|
|
843
|
-
return
|
|
844
|
-
let headerVersion =
|
|
845
|
-
if (headerVersion
|
|
846
|
-
headerVersion =
|
|
944
|
+
return (req, res, next) => {
|
|
945
|
+
let headerVersion = req.headers.get(headerName) ?? undefined;
|
|
946
|
+
if (headerVersion) {
|
|
947
|
+
headerVersion = headerVersion.trim();
|
|
948
|
+
if (headerVersion === "")
|
|
949
|
+
headerVersion = undefined;
|
|
950
|
+
}
|
|
847
951
|
headerVersion ??= resolvedDefault;
|
|
848
952
|
if (!headerVersion) {
|
|
849
953
|
if ((hasNeutralDefault || !defaultVersion) && acceptsNeutral) {
|
|
850
|
-
return
|
|
954
|
+
return handler(req, res, next);
|
|
851
955
|
}
|
|
852
|
-
|
|
956
|
+
next();
|
|
957
|
+
return;
|
|
853
958
|
}
|
|
854
959
|
if (versionMatches(headerVersion)) {
|
|
855
|
-
return
|
|
960
|
+
return handler(req, res, next);
|
|
856
961
|
}
|
|
857
|
-
|
|
962
|
+
next();
|
|
858
963
|
};
|
|
859
964
|
}
|
|
860
965
|
static resolveDefaultVersion(handlerVersion, defaultVersion) {
|
|
@@ -871,12 +976,15 @@ class BunVersionFilterMiddleware {
|
|
|
871
976
|
return;
|
|
872
977
|
}
|
|
873
978
|
static selectBestCustomVersionCandidate(req) {
|
|
874
|
-
const
|
|
875
|
-
if (phase !==
|
|
979
|
+
const phase = req.get(CUSTOM_VERSIONING_PHASE_KEY);
|
|
980
|
+
if (phase !== 0)
|
|
981
|
+
return null;
|
|
982
|
+
const candidates = req.get(CUSTOM_VERSIONING_CANDIDATES_KEY);
|
|
983
|
+
if (!candidates?.size)
|
|
876
984
|
return null;
|
|
877
985
|
let bestVersion = null;
|
|
878
986
|
let bestPriority = Infinity;
|
|
879
|
-
for (const [version,
|
|
987
|
+
for (const [version, priority] of candidates) {
|
|
880
988
|
if (priority < bestPriority) {
|
|
881
989
|
bestPriority = priority;
|
|
882
990
|
bestVersion = version;
|
|
@@ -885,17 +993,19 @@ class BunVersionFilterMiddleware {
|
|
|
885
993
|
return bestVersion;
|
|
886
994
|
}
|
|
887
995
|
static setCustomVersioningExecutionPhase(req, bestVersion) {
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
reqMeta._customVersioningBestCandidate = bestVersion;
|
|
996
|
+
req.set(CUSTOM_VERSIONING_PHASE_KEY, 1);
|
|
997
|
+
req.set(CUSTOM_VERSIONING_BEST_CANDIDATE_KEY, bestVersion);
|
|
891
998
|
}
|
|
892
999
|
static hasCustomVersioningCandidates(req) {
|
|
893
|
-
const
|
|
894
|
-
|
|
1000
|
+
const phase = req.get(CUSTOM_VERSIONING_PHASE_KEY);
|
|
1001
|
+
if (phase !== 0)
|
|
1002
|
+
return false;
|
|
1003
|
+
const candidates = req.get(CUSTOM_VERSIONING_CANDIDATES_KEY);
|
|
1004
|
+
return !!candidates?.size;
|
|
895
1005
|
}
|
|
896
1006
|
}
|
|
897
1007
|
|
|
898
|
-
// lib/bun.
|
|
1008
|
+
// lib/bun.server-instance.ts
|
|
899
1009
|
var REQUEST_METHOD_STRINGS = [
|
|
900
1010
|
"GET",
|
|
901
1011
|
"POST",
|
|
@@ -915,9 +1025,9 @@ var REQUEST_METHOD_STRINGS = [
|
|
|
915
1025
|
"UNLOCK"
|
|
916
1026
|
];
|
|
917
1027
|
|
|
918
|
-
class
|
|
1028
|
+
class BunServerInstance {
|
|
919
1029
|
bunServeOptions;
|
|
920
|
-
logger = new Logger("
|
|
1030
|
+
logger = new Logger("BunServerInstance", { timestamp: true });
|
|
921
1031
|
middlewareEngine = new BunMiddlewareEngine;
|
|
922
1032
|
useVersioning = false;
|
|
923
1033
|
routes = Object.create(null);
|
|
@@ -926,175 +1036,176 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
926
1036
|
res.setStatus(404);
|
|
927
1037
|
res.end({ message: "Not Found" });
|
|
928
1038
|
};
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
1039
|
+
wsHandlers = {
|
|
1040
|
+
onOpen: undefined,
|
|
1041
|
+
onMessage: undefined,
|
|
1042
|
+
onClose: undefined
|
|
1043
|
+
};
|
|
1044
|
+
wsMiddlewareEngine = new BunMiddlewareEngine;
|
|
1045
|
+
wsOptions = {};
|
|
1046
|
+
useWs = false;
|
|
1047
|
+
useWsCors = false;
|
|
1048
|
+
httpServer = null;
|
|
1049
|
+
constructor(bunServeOptions) {
|
|
934
1050
|
this.bunServeOptions = bunServeOptions;
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
}
|
|
943
|
-
if (path.includes("/*")) {
|
|
944
|
-
path = path.substring(0, path.indexOf("/*"));
|
|
945
|
-
}
|
|
946
|
-
this.logger.log(`Registering middleware for path: ${path}`);
|
|
947
|
-
this.middlewareEngine.useRoute("ALL", path, handler);
|
|
948
|
-
} else {
|
|
949
|
-
const handler = maybePath;
|
|
950
|
-
this.middlewareEngine.useGlobal(handler);
|
|
951
|
-
}
|
|
1051
|
+
}
|
|
1052
|
+
use(maybePath, maybeHandler) {
|
|
1053
|
+
if (typeof maybePath === "string") {
|
|
1054
|
+
let path = maybePath;
|
|
1055
|
+
const handler = maybeHandler;
|
|
1056
|
+
if (!handler) {
|
|
1057
|
+
throw new Error("Handler must be provided when path is a string.");
|
|
952
1058
|
}
|
|
953
|
-
|
|
1059
|
+
if (path.includes("/*")) {
|
|
1060
|
+
path = path.substring(0, path.indexOf("/*"));
|
|
1061
|
+
}
|
|
1062
|
+
this.logger.log(`Registering middleware for path: ${path}`);
|
|
1063
|
+
this.middlewareEngine.useRoute("ALL", path, handler);
|
|
1064
|
+
} else {
|
|
1065
|
+
const handler = maybePath;
|
|
1066
|
+
this.middlewareEngine.useGlobal(handler);
|
|
1067
|
+
}
|
|
954
1068
|
}
|
|
955
|
-
|
|
956
|
-
|
|
1069
|
+
createHttpMethodHandler(httpMethod) {
|
|
1070
|
+
return (pathOrHandler, maybeHandler) => {
|
|
1071
|
+
const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
|
|
1072
|
+
this.delegateRouteHandler(httpMethod, path, handler);
|
|
1073
|
+
};
|
|
957
1074
|
}
|
|
958
1075
|
get(pathOrHandler, maybeHandler) {
|
|
959
|
-
|
|
960
|
-
this.delegateRouteHandler("GET", path, handler);
|
|
1076
|
+
this.createHttpMethodHandler("GET")(pathOrHandler, maybeHandler);
|
|
961
1077
|
}
|
|
962
1078
|
post(pathOrHandler, maybeHandler) {
|
|
963
|
-
|
|
964
|
-
this.delegateRouteHandler("POST", path, handler);
|
|
1079
|
+
this.createHttpMethodHandler("POST")(pathOrHandler, maybeHandler);
|
|
965
1080
|
}
|
|
966
1081
|
put(pathOrHandler, maybeHandler) {
|
|
967
|
-
|
|
968
|
-
this.delegateRouteHandler("PUT", path, handler);
|
|
1082
|
+
this.createHttpMethodHandler("PUT")(pathOrHandler, maybeHandler);
|
|
969
1083
|
}
|
|
970
1084
|
patch(pathOrHandler, maybeHandler) {
|
|
971
|
-
|
|
972
|
-
this.delegateRouteHandler("PATCH", path, handler);
|
|
1085
|
+
this.createHttpMethodHandler("PATCH")(pathOrHandler, maybeHandler);
|
|
973
1086
|
}
|
|
974
1087
|
delete(pathOrHandler, maybeHandler) {
|
|
975
|
-
|
|
976
|
-
this.delegateRouteHandler("DELETE", path, handler);
|
|
1088
|
+
this.createHttpMethodHandler("DELETE")(pathOrHandler, maybeHandler);
|
|
977
1089
|
}
|
|
978
1090
|
head(pathOrHandler, maybeHandler) {
|
|
979
|
-
|
|
980
|
-
this.delegateRouteHandler("HEAD", path, handler);
|
|
1091
|
+
this.createHttpMethodHandler("HEAD")(pathOrHandler, maybeHandler);
|
|
981
1092
|
}
|
|
982
1093
|
options(pathOrHandler, maybeHandler) {
|
|
983
|
-
|
|
984
|
-
|
|
1094
|
+
this.createHttpMethodHandler("OPTIONS")(pathOrHandler, maybeHandler);
|
|
1095
|
+
}
|
|
1096
|
+
createUnsupportedMethod() {
|
|
1097
|
+
return (pathOrHandler, maybeHandler) => {
|
|
1098
|
+
throw new Error("Not supported.");
|
|
1099
|
+
};
|
|
985
1100
|
}
|
|
986
1101
|
all(pathOrHandler, maybeHandler) {
|
|
987
|
-
|
|
1102
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
988
1103
|
}
|
|
989
1104
|
propfind(pathOrHandler, maybeHandler) {
|
|
990
|
-
|
|
1105
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
991
1106
|
}
|
|
992
1107
|
proppatch(pathOrHandler, maybeHandler) {
|
|
993
|
-
|
|
1108
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
994
1109
|
}
|
|
995
1110
|
mkcol(pathOrHandler, maybeHandler) {
|
|
996
|
-
|
|
1111
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
997
1112
|
}
|
|
998
1113
|
copy(pathOrHandler, maybeHandler) {
|
|
999
|
-
|
|
1114
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1000
1115
|
}
|
|
1001
1116
|
move(pathOrHandler, maybeHandler) {
|
|
1002
|
-
|
|
1117
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1003
1118
|
}
|
|
1004
1119
|
lock(pathOrHandler, maybeHandler) {
|
|
1005
|
-
|
|
1120
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1006
1121
|
}
|
|
1007
1122
|
unlock(pathOrHandler, maybeHandler) {
|
|
1008
|
-
|
|
1123
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1009
1124
|
}
|
|
1010
1125
|
search(pathOrHandler, maybeHandler) {
|
|
1011
|
-
|
|
1012
|
-
}
|
|
1013
|
-
useStaticAssets(...args) {
|
|
1014
|
-
throw new Error("Not supported.");
|
|
1015
|
-
}
|
|
1016
|
-
setViewEngine(engine) {
|
|
1017
|
-
throw new Error("Not supported.");
|
|
1126
|
+
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1018
1127
|
}
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1128
|
+
listen(port, hostnameOrCallback, maybeCallback) {
|
|
1129
|
+
const hostname = typeof hostnameOrCallback === "string" ? hostnameOrCallback : this.bunServeOptions.hostname ?? "127.0.0.1";
|
|
1130
|
+
const callback = typeof hostnameOrCallback === "function" ? hostnameOrCallback : maybeCallback;
|
|
1131
|
+
const middlewareEngine = this.middlewareEngine;
|
|
1132
|
+
const notFoundHandler = this.notFoundHandler;
|
|
1133
|
+
const wsHandlers = this.wsHandlers;
|
|
1134
|
+
const bunServeOptions = this.bunServeOptions;
|
|
1135
|
+
this.setupWebSocketIfNeeded(wsHandlers, bunServeOptions);
|
|
1136
|
+
const fetch = async (request, server) => {
|
|
1137
|
+
const bunRequest = new BunRequest(request);
|
|
1138
|
+
if (await this.upgradeWebSocket(request, bunRequest, server)) {
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
const routeHandler = middlewareEngine.findRouteHandler(bunRequest.method, bunRequest.pathname) ?? notFoundHandler;
|
|
1142
|
+
const bunResponse = await middlewareEngine.run({
|
|
1143
|
+
req: bunRequest,
|
|
1144
|
+
res: new BunResponse,
|
|
1145
|
+
method: bunRequest.method,
|
|
1146
|
+
path: bunRequest.pathname,
|
|
1147
|
+
requestHandler: routeHandler
|
|
1148
|
+
});
|
|
1149
|
+
return bunResponse.res();
|
|
1150
|
+
};
|
|
1151
|
+
this.httpServer = this.createServer(port, hostname, bunServeOptions, fetch);
|
|
1152
|
+
callback?.();
|
|
1153
|
+
return this.httpServer;
|
|
1024
1154
|
}
|
|
1025
|
-
|
|
1026
|
-
this.
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
rejectUnauthorized: options.httpsOptions.rejectUnauthorized,
|
|
1041
|
-
requestCert: options.httpsOptions.requestCert
|
|
1155
|
+
async stop(force) {
|
|
1156
|
+
const server = this.httpServer;
|
|
1157
|
+
if (!server) {
|
|
1158
|
+
return;
|
|
1159
|
+
}
|
|
1160
|
+
await server.stop(force);
|
|
1161
|
+
}
|
|
1162
|
+
address() {
|
|
1163
|
+
const server = this.httpServer;
|
|
1164
|
+
if (!server) {
|
|
1165
|
+
const hostname = this.bunServeOptions.hostname;
|
|
1166
|
+
const port = this.bunServeOptions.port;
|
|
1167
|
+
return {
|
|
1168
|
+
address: typeof hostname === "string" ? hostname : "127.0.0.1",
|
|
1169
|
+
port: typeof port === "number" ? port : 3000
|
|
1042
1170
|
};
|
|
1043
1171
|
}
|
|
1172
|
+
return {
|
|
1173
|
+
address: server.hostname ?? "127.0.0.1",
|
|
1174
|
+
port: server.port ?? 3000
|
|
1175
|
+
};
|
|
1044
1176
|
}
|
|
1045
|
-
|
|
1046
|
-
|
|
1177
|
+
setWsOptions(options) {
|
|
1178
|
+
this.wsOptions = options;
|
|
1047
1179
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1180
|
+
registerWsOpenHandler(handler) {
|
|
1181
|
+
this.wsHandlers.onOpen = handler;
|
|
1050
1182
|
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1183
|
+
registerWsMessageHandler(handler) {
|
|
1184
|
+
this.wsHandlers.onMessage = handler;
|
|
1053
1185
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1186
|
+
registerWsCloseHandler(handler) {
|
|
1187
|
+
this.wsHandlers.onClose = handler;
|
|
1056
1188
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
response.setStatus(statusCode);
|
|
1060
|
-
}
|
|
1061
|
-
response.end(body);
|
|
1189
|
+
getBunServer() {
|
|
1190
|
+
return this.httpServer;
|
|
1062
1191
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1192
|
+
async close() {
|
|
1193
|
+
await this.stop(true);
|
|
1065
1194
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1195
|
+
getMiddlewareEngine() {
|
|
1196
|
+
return this.middlewareEngine;
|
|
1068
1197
|
}
|
|
1069
|
-
|
|
1070
|
-
this.middlewareEngine.useErrorHandler(handler);
|
|
1071
|
-
}
|
|
1072
|
-
setNotFoundHandler(handler, prefix) {
|
|
1198
|
+
setNotFoundHandler(handler) {
|
|
1073
1199
|
this.notFoundHandler = handler;
|
|
1074
|
-
this.middlewareEngine.useNotFoundHandler(handler);
|
|
1075
1200
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1079
|
-
getHeader(response, name) {
|
|
1080
|
-
return response.getHeader(name);
|
|
1081
|
-
}
|
|
1082
|
-
setHeader(response, name, value) {
|
|
1083
|
-
response.setHeader(name, value);
|
|
1084
|
-
}
|
|
1085
|
-
appendHeader(response, name, value) {
|
|
1086
|
-
response.appendHeader(name, value);
|
|
1201
|
+
setUseVersioning(value) {
|
|
1202
|
+
this.useVersioning = value;
|
|
1087
1203
|
}
|
|
1088
1204
|
registerParserMiddleware(prefix, rawBody) {
|
|
1089
1205
|
this.logger.log(`Registering Body Parser Middleware with prefix: ${prefix || "/"} and rawBody: ${rawBody ? "true" : "false"}`);
|
|
1090
1206
|
const bodyParser = new BunBodyParserMiddleware({ prefix, rawBody });
|
|
1091
1207
|
this.middlewareEngine.useGlobal(bodyParser.run.bind(bodyParser));
|
|
1092
1208
|
}
|
|
1093
|
-
enableCors(options, prefix) {
|
|
1094
|
-
this.logger.log(`Enabling CORS Middleware with prefix: ${prefix ?? "/"}`);
|
|
1095
|
-
const corsMiddleware = new BunCorsMiddleware({ corsOptions: options, prefix });
|
|
1096
|
-
this.middlewareEngine.useGlobal(corsMiddleware.run.bind(corsMiddleware));
|
|
1097
|
-
}
|
|
1098
1209
|
createMiddlewareFactory(requestMethod) {
|
|
1099
1210
|
return (path, callback) => {
|
|
1100
1211
|
const methodName = this.mapRequestMethodToString(requestMethod);
|
|
@@ -1106,73 +1217,121 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1106
1217
|
this.middlewareEngine.useRoute(methodName, normalizedPath, callback);
|
|
1107
1218
|
};
|
|
1108
1219
|
}
|
|
1109
|
-
|
|
1110
|
-
|
|
1220
|
+
enableCors(corsOptions, prefix) {
|
|
1221
|
+
this.logger.log(`Enabling CORS Middleware with prefix: ${prefix ?? "/"}`);
|
|
1222
|
+
const corsMiddleware = new BunCorsMiddleware({ corsOptions, prefix });
|
|
1223
|
+
this.middlewareEngine.useGlobal(corsMiddleware.run.bind(corsMiddleware));
|
|
1111
1224
|
}
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
this.useVersioning = true;
|
|
1115
|
-
return BunVersionFilterMiddleware.createFilter(handler, version, versioningOptions);
|
|
1225
|
+
static isNumericPort(value) {
|
|
1226
|
+
return typeof value === "number" || !isNaN(Number(value));
|
|
1116
1227
|
}
|
|
1117
|
-
|
|
1118
|
-
const
|
|
1119
|
-
const
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1228
|
+
static omitKeys(obj, ...keys) {
|
|
1229
|
+
const result = { ...obj };
|
|
1230
|
+
for (const key of keys) {
|
|
1231
|
+
Reflect.deleteProperty(result, key);
|
|
1232
|
+
}
|
|
1233
|
+
return result;
|
|
1234
|
+
}
|
|
1235
|
+
isWebSocketUpgradeRequest(request) {
|
|
1236
|
+
const upgradeHeader = request.headers.get("upgrade");
|
|
1237
|
+
const connectionHeader = request.headers.get("connection");
|
|
1238
|
+
return !!(upgradeHeader?.toLowerCase() === "websocket" && connectionHeader?.toLowerCase().includes("upgrade"));
|
|
1239
|
+
}
|
|
1240
|
+
async provideCorsHeaders(bunRequest) {
|
|
1241
|
+
const bunResponse = new BunResponse;
|
|
1242
|
+
await this.wsMiddlewareEngine.run({
|
|
1243
|
+
req: bunRequest,
|
|
1244
|
+
res: bunResponse,
|
|
1245
|
+
method: bunRequest.method,
|
|
1246
|
+
path: bunRequest.pathname,
|
|
1247
|
+
requestHandler: (req, res) => {
|
|
1248
|
+
res.end();
|
|
1249
|
+
}
|
|
1250
|
+
});
|
|
1251
|
+
const response = await bunResponse.res();
|
|
1252
|
+
return response.headers;
|
|
1253
|
+
}
|
|
1254
|
+
async upgradeWebSocket(request, bunRequest, server) {
|
|
1255
|
+
if (!this.useWs || !this.isWebSocketUpgradeRequest(request)) {
|
|
1256
|
+
return false;
|
|
1257
|
+
}
|
|
1258
|
+
const headers = this.useWsCors ? await this.provideCorsHeaders(bunRequest) : undefined;
|
|
1259
|
+
return server.upgrade(request, {
|
|
1260
|
+
headers,
|
|
1261
|
+
data: await this.wsOptions.clientDataFactory?.(bunRequest) ?? {}
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
setupWebSocketIfNeeded(wsHandlers, bunServeOptions) {
|
|
1265
|
+
const useWs = !!wsHandlers.onOpen && !!wsHandlers.onMessage && !!wsHandlers.onClose;
|
|
1266
|
+
if (!useWs)
|
|
1267
|
+
return;
|
|
1268
|
+
this.useWs = true;
|
|
1269
|
+
const getServer = () => this.getBunServer();
|
|
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);
|
|
1139
1286
|
}
|
|
1140
|
-
return result;
|
|
1141
1287
|
};
|
|
1142
|
-
const
|
|
1143
|
-
|
|
1288
|
+
const useWsCors = typeof this.wsOptions.cors !== "undefined";
|
|
1289
|
+
if (!useWsCors)
|
|
1290
|
+
return;
|
|
1291
|
+
this.useWsCors = true;
|
|
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
|
+
createServer(port, hostname, bunServeOptions, fetch) {
|
|
1298
|
+
return BunServerInstance.isNumericPort(port) ? Bun.serve({
|
|
1299
|
+
...bunServeOptions,
|
|
1144
1300
|
hostname,
|
|
1145
1301
|
port,
|
|
1146
1302
|
routes: this.routes,
|
|
1147
1303
|
fetch
|
|
1148
1304
|
}) : Bun.serve({
|
|
1149
|
-
...
|
|
1305
|
+
...BunServerInstance.omitKeys(bunServeOptions, "idleTimeout", "port", "hostname"),
|
|
1150
1306
|
unix: port,
|
|
1151
1307
|
routes: this.routes,
|
|
1152
1308
|
fetch
|
|
1153
1309
|
});
|
|
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
1310
|
}
|
|
1165
1311
|
delegateRouteHandler(method, path, handler) {
|
|
1312
|
+
this.ensureRouteExists(path);
|
|
1313
|
+
const requestHandler = this.prepareRequestHandler(method, path, handler);
|
|
1314
|
+
this.routes[path][method] = this.createRouteFetchHandler(path, method, requestHandler);
|
|
1315
|
+
}
|
|
1316
|
+
ensureRouteExists(path) {
|
|
1166
1317
|
if (!(path in this.routes)) {
|
|
1167
1318
|
this.routes[path] = Object.create(null);
|
|
1168
1319
|
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1320
|
+
}
|
|
1321
|
+
prepareRequestHandler(method, path, handler) {
|
|
1322
|
+
if (!this.useVersioning)
|
|
1323
|
+
return handler;
|
|
1324
|
+
return this.createChainedHandlerForVersioningResolution(this.createVersioningHandlers(method, path, handler), this.notFoundHandler);
|
|
1325
|
+
}
|
|
1326
|
+
createRouteFetchHandler(path, method, requestHandler) {
|
|
1327
|
+
return async (request, server) => {
|
|
1171
1328
|
const bunRequest = new BunRequest(request);
|
|
1172
|
-
|
|
1173
|
-
|
|
1329
|
+
if (path === "/" && await this.upgradeWebSocket(request, bunRequest, server)) {
|
|
1330
|
+
return;
|
|
1331
|
+
}
|
|
1332
|
+
const bunResponse = await this.middlewareEngine.run({
|
|
1174
1333
|
req: bunRequest,
|
|
1175
|
-
res:
|
|
1334
|
+
res: new BunResponse,
|
|
1176
1335
|
method,
|
|
1177
1336
|
path,
|
|
1178
1337
|
requestHandler
|
|
@@ -1228,6 +1387,114 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1228
1387
|
return { path, handler };
|
|
1229
1388
|
}
|
|
1230
1389
|
}
|
|
1390
|
+
|
|
1391
|
+
// lib/bun.adapter.ts
|
|
1392
|
+
class BunAdapter extends AbstractHttpAdapter {
|
|
1393
|
+
bunServeOptions;
|
|
1394
|
+
logger = new Logger2("BunAdapter", { timestamp: true });
|
|
1395
|
+
constructor(bunServeOptions = {
|
|
1396
|
+
development: false,
|
|
1397
|
+
id: randomUUIDv7()
|
|
1398
|
+
}) {
|
|
1399
|
+
super(new BunServerInstance(bunServeOptions));
|
|
1400
|
+
this.bunServeOptions = bunServeOptions;
|
|
1401
|
+
}
|
|
1402
|
+
useStaticAssets(...args) {
|
|
1403
|
+
throw new Error("Not supported.");
|
|
1404
|
+
}
|
|
1405
|
+
setViewEngine(engine) {
|
|
1406
|
+
throw new Error("Not supported.");
|
|
1407
|
+
}
|
|
1408
|
+
render(response, view, options) {
|
|
1409
|
+
throw new Error("Not supported.");
|
|
1410
|
+
}
|
|
1411
|
+
async close() {
|
|
1412
|
+
await this.instance.close();
|
|
1413
|
+
}
|
|
1414
|
+
initHttpServer(options) {
|
|
1415
|
+
this.configureTls(options);
|
|
1416
|
+
const preflightServer = new BunPreflightHttpServer(this.instance);
|
|
1417
|
+
this.setHttpServer(preflightServer);
|
|
1418
|
+
return preflightServer;
|
|
1419
|
+
}
|
|
1420
|
+
getRequestHostname(request) {
|
|
1421
|
+
return request.hostname;
|
|
1422
|
+
}
|
|
1423
|
+
getRequestMethod(request) {
|
|
1424
|
+
return request.method;
|
|
1425
|
+
}
|
|
1426
|
+
getRequestUrl(request) {
|
|
1427
|
+
return request.pathname;
|
|
1428
|
+
}
|
|
1429
|
+
status(response, statusCode) {
|
|
1430
|
+
response.setStatus(statusCode);
|
|
1431
|
+
}
|
|
1432
|
+
reply(response, body, statusCode) {
|
|
1433
|
+
if (statusCode) {
|
|
1434
|
+
response.setStatus(statusCode);
|
|
1435
|
+
}
|
|
1436
|
+
response.end(body);
|
|
1437
|
+
}
|
|
1438
|
+
end(response, message) {
|
|
1439
|
+
response.end(message);
|
|
1440
|
+
}
|
|
1441
|
+
redirect(response, statusCode, url) {
|
|
1442
|
+
response.redirect(url, statusCode);
|
|
1443
|
+
}
|
|
1444
|
+
setErrorHandler(handler, prefix) {
|
|
1445
|
+
this.instance.getMiddlewareEngine().useErrorHandler(handler);
|
|
1446
|
+
}
|
|
1447
|
+
setNotFoundHandler(handler, prefix) {
|
|
1448
|
+
this.instance.setNotFoundHandler(handler);
|
|
1449
|
+
this.instance.getMiddlewareEngine().useNotFoundHandler(handler);
|
|
1450
|
+
}
|
|
1451
|
+
isHeadersSent(response) {
|
|
1452
|
+
return response.isEnded();
|
|
1453
|
+
}
|
|
1454
|
+
getHeader(response, name) {
|
|
1455
|
+
return response.getHeader(name);
|
|
1456
|
+
}
|
|
1457
|
+
setHeader(response, name, value) {
|
|
1458
|
+
response.setHeader(name, value);
|
|
1459
|
+
}
|
|
1460
|
+
appendHeader(response, name, value) {
|
|
1461
|
+
response.appendHeader(name, value);
|
|
1462
|
+
}
|
|
1463
|
+
registerParserMiddleware(prefix, rawBody) {
|
|
1464
|
+
this.instance.registerParserMiddleware(prefix, rawBody);
|
|
1465
|
+
}
|
|
1466
|
+
enableCors(options, prefix) {
|
|
1467
|
+
this.instance.enableCors(options, prefix);
|
|
1468
|
+
}
|
|
1469
|
+
createMiddlewareFactory(requestMethod) {
|
|
1470
|
+
return this.instance.createMiddlewareFactory(requestMethod);
|
|
1471
|
+
}
|
|
1472
|
+
getType() {
|
|
1473
|
+
return "bun";
|
|
1474
|
+
}
|
|
1475
|
+
applyVersionFilter(handler, version, versioningOptions) {
|
|
1476
|
+
this.logger.log(`Applying Version Filter Middleware for version: ${JSON.stringify(version)}`);
|
|
1477
|
+
this.instance.setUseVersioning(true);
|
|
1478
|
+
return BunVersionFilterMiddleware.createFilter(handler, version, versioningOptions);
|
|
1479
|
+
}
|
|
1480
|
+
listen(port, hostnameOrCallback, maybeCallback) {
|
|
1481
|
+
this.setHttpServer(this.instance.listen(port, hostnameOrCallback, maybeCallback));
|
|
1482
|
+
}
|
|
1483
|
+
configureTls(options) {
|
|
1484
|
+
if (options.httpsOptions) {
|
|
1485
|
+
this.bunServeOptions.tls = {
|
|
1486
|
+
key: options.httpsOptions.key,
|
|
1487
|
+
cert: options.httpsOptions.cert,
|
|
1488
|
+
passphrase: options.httpsOptions.passphrase,
|
|
1489
|
+
ca: options.httpsOptions.ca,
|
|
1490
|
+
ciphers: options.httpsOptions.ciphers,
|
|
1491
|
+
secureOptions: options.httpsOptions.secureOptions,
|
|
1492
|
+
rejectUnauthorized: options.httpsOptions.rejectUnauthorized,
|
|
1493
|
+
requestCert: options.httpsOptions.requestCert
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1231
1498
|
// lib/bun.file.interceptor.ts
|
|
1232
1499
|
import { Injectable } from "@nestjs/common";
|
|
1233
1500
|
import { basename, join } from "path";
|
|
@@ -1263,12 +1530,160 @@ BunFileInterceptor = __legacyDecorateClassTS([
|
|
|
1263
1530
|
typeof HttpAdapterHost === "undefined" ? Object : HttpAdapterHost
|
|
1264
1531
|
])
|
|
1265
1532
|
], BunFileInterceptor);
|
|
1533
|
+
// lib/bun.ws-adapter.ts
|
|
1534
|
+
import {
|
|
1535
|
+
AbstractWsAdapter
|
|
1536
|
+
} from "@nestjs/websockets";
|
|
1537
|
+
import { EMPTY, Subject, mergeMap } from "rxjs";
|
|
1538
|
+
import { Logger as Logger3 } from "@nestjs/common";
|
|
1539
|
+
import { isNil } from "@nestjs/common/utils/shared.utils.js";
|
|
1540
|
+
var WS_READY_STATE_OPEN = 1;
|
|
1541
|
+
var defaultMessageParser = (data) => {
|
|
1542
|
+
if (typeof data === "string") {
|
|
1543
|
+
return JSON.parse(data);
|
|
1544
|
+
}
|
|
1545
|
+
if (data instanceof ArrayBuffer) {
|
|
1546
|
+
return JSON.parse(new TextDecoder().decode(data));
|
|
1547
|
+
}
|
|
1548
|
+
if (Buffer.isBuffer(data)) {
|
|
1549
|
+
return JSON.parse(data.toString("utf8"));
|
|
1550
|
+
}
|
|
1551
|
+
return JSON.parse(Buffer.concat(data).toString("utf8"));
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
class BunWsAdapter extends AbstractWsAdapter {
|
|
1555
|
+
logger = new Logger3(BunWsAdapter.name);
|
|
1556
|
+
nestApp;
|
|
1557
|
+
messageParser = defaultMessageParser;
|
|
1558
|
+
onOpenHandler;
|
|
1559
|
+
globalHandlersInitialized = false;
|
|
1560
|
+
constructor(appOrHttpServer) {
|
|
1561
|
+
super(appOrHttpServer);
|
|
1562
|
+
if (!appOrHttpServer || !("getHttpAdapter" in appOrHttpServer)) {
|
|
1563
|
+
throw new Error("BunWsAdapter requires a NestApplication instance in the constructor.");
|
|
1564
|
+
}
|
|
1565
|
+
this.nestApp = appOrHttpServer;
|
|
1566
|
+
}
|
|
1567
|
+
create(_port, options) {
|
|
1568
|
+
if (options?.messageParser) {
|
|
1569
|
+
this.messageParser = options.messageParser;
|
|
1570
|
+
}
|
|
1571
|
+
const server = this.nestApp.getHttpAdapter().getHttpServer();
|
|
1572
|
+
const wsOptions = this.extractWsOptions(options);
|
|
1573
|
+
server.setWsOptions(wsOptions);
|
|
1574
|
+
this.initializeGlobalHandlers(server);
|
|
1575
|
+
return server;
|
|
1576
|
+
}
|
|
1577
|
+
extractWsOptions(options) {
|
|
1578
|
+
if (!options) {
|
|
1579
|
+
return {};
|
|
1580
|
+
}
|
|
1581
|
+
const wsOptions = { ...options };
|
|
1582
|
+
delete wsOptions.messageParser;
|
|
1583
|
+
return wsOptions;
|
|
1584
|
+
}
|
|
1585
|
+
async close(server) {
|
|
1586
|
+
await server.close();
|
|
1587
|
+
}
|
|
1588
|
+
bindClientConnect(server, callback) {
|
|
1589
|
+
this.onOpenHandler = callback;
|
|
1590
|
+
}
|
|
1591
|
+
bindClientDisconnect(client, callback) {
|
|
1592
|
+
const existingHandler = client.data.onDisconnect;
|
|
1593
|
+
client.data.onDisconnect = (ws) => {
|
|
1594
|
+
existingHandler?.(ws);
|
|
1595
|
+
callback(client);
|
|
1596
|
+
};
|
|
1597
|
+
}
|
|
1598
|
+
bindMessageHandlers(client, handlers, transform) {
|
|
1599
|
+
const handlerMap = this.buildHandlerMap(handlers);
|
|
1600
|
+
const message$ = new Subject;
|
|
1601
|
+
let isActive = true;
|
|
1602
|
+
const existingOnMessage = client.data.onMessageInternal;
|
|
1603
|
+
client.data.onMessageInternal = (data) => {
|
|
1604
|
+
existingOnMessage?.(data);
|
|
1605
|
+
if (isActive) {
|
|
1606
|
+
message$.next(data);
|
|
1607
|
+
}
|
|
1608
|
+
};
|
|
1609
|
+
const subscription = message$.pipe(mergeMap((data) => this.processMessage(data, handlerMap, transform))).subscribe({
|
|
1610
|
+
next: (response) => {
|
|
1611
|
+
this.sendResponse(client, response, isActive);
|
|
1612
|
+
},
|
|
1613
|
+
error: (err) => {
|
|
1614
|
+
this.logger.error("Message processing error", err instanceof Error ? err.stack : err);
|
|
1615
|
+
}
|
|
1616
|
+
});
|
|
1617
|
+
const existingOnClose = client.data.onCloseInternal;
|
|
1618
|
+
client.data.onCloseInternal = () => {
|
|
1619
|
+
existingOnClose?.();
|
|
1620
|
+
isActive = false;
|
|
1621
|
+
this.cleanupClient(message$, subscription);
|
|
1622
|
+
};
|
|
1623
|
+
}
|
|
1624
|
+
initializeGlobalHandlers(server) {
|
|
1625
|
+
if (this.globalHandlersInitialized) {
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
this.globalHandlersInitialized = true;
|
|
1629
|
+
server.registerWsOpenHandler((ws) => {
|
|
1630
|
+
this.onOpenHandler?.(ws);
|
|
1631
|
+
});
|
|
1632
|
+
server.registerWsMessageHandler(() => {});
|
|
1633
|
+
server.registerWsCloseHandler(() => {});
|
|
1634
|
+
}
|
|
1635
|
+
buildHandlerMap(handlers) {
|
|
1636
|
+
const map = new Map;
|
|
1637
|
+
for (const handler of handlers) {
|
|
1638
|
+
map.set(handler.message, handler);
|
|
1639
|
+
}
|
|
1640
|
+
return map;
|
|
1641
|
+
}
|
|
1642
|
+
processMessage(data, handlerMap, transform) {
|
|
1643
|
+
try {
|
|
1644
|
+
const parsed = this.messageParser(data);
|
|
1645
|
+
if (typeof parsed.event !== "string") {
|
|
1646
|
+
return EMPTY;
|
|
1647
|
+
}
|
|
1648
|
+
const handler = handlerMap.get(parsed.event);
|
|
1649
|
+
if (!handler) {
|
|
1650
|
+
return EMPTY;
|
|
1651
|
+
}
|
|
1652
|
+
const result = handler.callback(parsed.data, parsed.event);
|
|
1653
|
+
return transform(result).pipe(mergeMap((value) => isNil(value) ? EMPTY : [value]));
|
|
1654
|
+
} catch (error) {
|
|
1655
|
+
this.logger.warn("Failed to parse WebSocket message", error instanceof Error ? error.message : String(error));
|
|
1656
|
+
return EMPTY;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
sendResponse(client, response, isActive) {
|
|
1660
|
+
if (!isActive || client.readyState !== WS_READY_STATE_OPEN) {
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
if (response instanceof ArrayBuffer) {
|
|
1664
|
+
client.send(response);
|
|
1665
|
+
return;
|
|
1666
|
+
}
|
|
1667
|
+
if (ArrayBuffer.isView(response)) {
|
|
1668
|
+
client.send(response.buffer);
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
client.send(JSON.stringify(response));
|
|
1672
|
+
}
|
|
1673
|
+
cleanupClient(message$, subscription) {
|
|
1674
|
+
message$.complete();
|
|
1675
|
+
subscription.unsubscribe();
|
|
1676
|
+
}
|
|
1677
|
+
}
|
|
1266
1678
|
export {
|
|
1679
|
+
BunWsAdapter,
|
|
1680
|
+
BunServerInstance,
|
|
1267
1681
|
BunResponse,
|
|
1268
1682
|
BunRequest,
|
|
1683
|
+
BunPreflightHttpServer,
|
|
1269
1684
|
BunFileInterceptor,
|
|
1270
1685
|
BunAdapter
|
|
1271
1686
|
};
|
|
1272
1687
|
|
|
1273
|
-
//# debugId=
|
|
1688
|
+
//# debugId=813882D1C572F1EC64756E2164756E21
|
|
1274
1689
|
//# sourceMappingURL=index.js.map
|