@krisanalfa/bunest-adapter 0.3.0 → 0.5.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 +156 -18
- package/dist/bun.adapter.d.ts +8 -67
- package/dist/bun.internal.types.d.ts +53 -0
- package/dist/bun.preflight-http-server.d.ts +8 -26
- package/dist/bun.request.d.ts +56 -7
- package/dist/bun.response.d.ts +35 -0
- package/dist/bun.server-instance.d.ts +137 -0
- package/dist/bun.ws-adapter.d.ts +1 -11
- package/dist/index.d.ts +2 -1
- package/dist/index.js +517 -324
- package/dist/index.js.map +11 -10
- package/package.json +17 -7
- package/dist/internal.types.d.ts +0 -8
package/dist/index.js
CHANGED
|
@@ -15,12 +15,52 @@ var __legacyMetadataTS = (k, v) => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
// lib/bun.adapter.ts
|
|
18
|
-
var {randomUUIDv7 } = globalThis.Bun;
|
|
19
18
|
import {
|
|
20
|
-
Logger
|
|
19
|
+
Logger as Logger2
|
|
21
20
|
} from "@nestjs/common";
|
|
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
|
+
import { join } from "path";
|
|
62
|
+
import { readdir } from "fs/promises";
|
|
63
|
+
|
|
24
64
|
// lib/bun.body-parser.middleware.ts
|
|
25
65
|
var GET_CODE = 71;
|
|
26
66
|
var HEAD_CODE = 72;
|
|
@@ -179,6 +219,7 @@ class BunCorsMiddleware {
|
|
|
179
219
|
}
|
|
180
220
|
|
|
181
221
|
// lib/bun.middleware-engine.ts
|
|
222
|
+
var {peek } = globalThis.Bun;
|
|
182
223
|
var EMPTY_HANDLERS = new Array(0);
|
|
183
224
|
var noop = () => {};
|
|
184
225
|
|
|
@@ -258,6 +299,17 @@ class BunMiddlewareEngine {
|
|
|
258
299
|
const keyPathLen = keyPath.length;
|
|
259
300
|
return path === keyPath || pathLen > keyPathLen && path.charCodeAt(keyPathLen) === 47 && path.startsWith(keyPath);
|
|
260
301
|
}
|
|
302
|
+
async executeHandler(handler, req, res, next) {
|
|
303
|
+
if (!handler)
|
|
304
|
+
return;
|
|
305
|
+
const result = handler(req, res, next);
|
|
306
|
+
if (result instanceof Promise) {
|
|
307
|
+
const peeked = peek(result);
|
|
308
|
+
if (peeked !== result)
|
|
309
|
+
return;
|
|
310
|
+
await result;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
261
313
|
async run(options) {
|
|
262
314
|
try {
|
|
263
315
|
const middlewares = this.getMiddlewareChain(options.method, options.path);
|
|
@@ -333,25 +385,18 @@ class BunMiddlewareEngine {
|
|
|
333
385
|
if (err)
|
|
334
386
|
throw err;
|
|
335
387
|
if (index < chainLength) {
|
|
336
|
-
|
|
337
|
-
const result = handler(req, res, next);
|
|
338
|
-
if (result instanceof Promise)
|
|
339
|
-
await result;
|
|
388
|
+
await this.executeHandler(chain[index++], req, res, next);
|
|
340
389
|
return;
|
|
341
390
|
}
|
|
342
391
|
if (index === chainLength) {
|
|
343
392
|
index++;
|
|
344
393
|
if (!res.isEnded()) {
|
|
345
|
-
|
|
346
|
-
if (result instanceof Promise)
|
|
347
|
-
await result;
|
|
394
|
+
await this.executeHandler(requestHandler, req, res, next);
|
|
348
395
|
}
|
|
349
396
|
return;
|
|
350
397
|
}
|
|
351
|
-
if (
|
|
352
|
-
|
|
353
|
-
if (result instanceof Promise)
|
|
354
|
-
await result;
|
|
398
|
+
if (!res.isEnded()) {
|
|
399
|
+
await this.executeHandler(this.notFoundHandler ?? undefined, req, res, () => Promise.resolve());
|
|
355
400
|
}
|
|
356
401
|
};
|
|
357
402
|
await next();
|
|
@@ -359,67 +404,17 @@ class BunMiddlewareEngine {
|
|
|
359
404
|
async handleError(error, req, res) {
|
|
360
405
|
if (this.errorHandler !== null) {
|
|
361
406
|
const result = this.errorHandler(error, req, res, noop);
|
|
362
|
-
if (result instanceof Promise)
|
|
363
|
-
|
|
407
|
+
if (result instanceof Promise) {
|
|
408
|
+
const peeked = peek(result);
|
|
409
|
+
if (peeked === result)
|
|
410
|
+
await result;
|
|
411
|
+
}
|
|
364
412
|
return res;
|
|
365
413
|
}
|
|
366
414
|
throw error;
|
|
367
415
|
}
|
|
368
416
|
}
|
|
369
417
|
|
|
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
|
-
|
|
423
418
|
// lib/bun.request.ts
|
|
424
419
|
import { parse } from "qs";
|
|
425
420
|
var NULL_PROTO = Object.getPrototypeOf(Object.create(null));
|
|
@@ -436,25 +431,34 @@ class BunRequest {
|
|
|
436
431
|
_file = null;
|
|
437
432
|
_files = null;
|
|
438
433
|
_settings = null;
|
|
439
|
-
|
|
434
|
+
_connection = null;
|
|
435
|
+
_socket = null;
|
|
436
|
+
_url = null;
|
|
440
437
|
_parsedUrl;
|
|
441
438
|
method;
|
|
442
439
|
params;
|
|
443
440
|
constructor(nativeRequest) {
|
|
444
441
|
this.nativeRequest = nativeRequest;
|
|
445
|
-
this.
|
|
446
|
-
this._parsedUrl = new URL(this._url);
|
|
442
|
+
this._parsedUrl = new URL(nativeRequest.url);
|
|
447
443
|
this._nativeHeaders = nativeRequest.headers;
|
|
448
444
|
this.method = nativeRequest.method;
|
|
449
445
|
this.params = nativeRequest.params;
|
|
450
446
|
}
|
|
447
|
+
get connection() {
|
|
448
|
+
return this._connection ??= {
|
|
449
|
+
encrypted: this._parsedUrl.protocol === "https:" || this.nativeRequest.url.startsWith("https://")
|
|
450
|
+
};
|
|
451
|
+
}
|
|
451
452
|
get socket() {
|
|
452
|
-
return {
|
|
453
|
-
encrypted: this._parsedUrl.protocol === "https:"
|
|
453
|
+
return this._socket ??= {
|
|
454
|
+
encrypted: this._parsedUrl.protocol === "https:" || this.nativeRequest.url.startsWith("https://"),
|
|
455
|
+
setKeepAlive: () => {},
|
|
456
|
+
setNoDelay: () => {},
|
|
457
|
+
setTimeout: () => {}
|
|
454
458
|
};
|
|
455
459
|
}
|
|
456
460
|
get url() {
|
|
457
|
-
return this._parsedUrl.pathname + this._parsedUrl.search;
|
|
461
|
+
return this._url ??= this._parsedUrl.pathname + this._parsedUrl.search;
|
|
458
462
|
}
|
|
459
463
|
original() {
|
|
460
464
|
return this.nativeRequest;
|
|
@@ -535,16 +539,32 @@ class BunRequest {
|
|
|
535
539
|
}
|
|
536
540
|
clone() {
|
|
537
541
|
const cloned = new BunRequest(this.nativeRequest.clone());
|
|
542
|
+
cloned._hostname = this._hostname;
|
|
538
543
|
cloned._pathname = this._pathname;
|
|
544
|
+
cloned._query = this._query;
|
|
539
545
|
cloned._body = this._body;
|
|
540
546
|
cloned._rawBody = this._rawBody;
|
|
541
547
|
cloned._file = this._file;
|
|
542
548
|
cloned._files = this._files;
|
|
543
549
|
cloned._headers = this._headers;
|
|
544
|
-
cloned._query = this._query;
|
|
545
550
|
cloned._settings = this._settings;
|
|
551
|
+
cloned._connection = this._connection;
|
|
552
|
+
cloned._socket = this._socket;
|
|
553
|
+
cloned._url = this._url;
|
|
546
554
|
return cloned;
|
|
547
555
|
}
|
|
556
|
+
on(event, listener) {
|
|
557
|
+
return this;
|
|
558
|
+
}
|
|
559
|
+
once(event, listener) {
|
|
560
|
+
return this;
|
|
561
|
+
}
|
|
562
|
+
off(event, listener) {
|
|
563
|
+
return this;
|
|
564
|
+
}
|
|
565
|
+
emit(event, ...args) {
|
|
566
|
+
return true;
|
|
567
|
+
}
|
|
548
568
|
}
|
|
549
569
|
|
|
550
570
|
// lib/bun.response.ts
|
|
@@ -557,11 +577,14 @@ class BunResponse {
|
|
|
557
577
|
response;
|
|
558
578
|
cookieMap = new CookieMap;
|
|
559
579
|
static textDecoder = new TextDecoder;
|
|
580
|
+
writable = true;
|
|
560
581
|
headers = null;
|
|
561
582
|
statusCode = 200;
|
|
562
583
|
ended = false;
|
|
563
584
|
cookieHeaders = null;
|
|
564
585
|
chunks = [];
|
|
586
|
+
streamWriter = null;
|
|
587
|
+
textEncoder = new TextEncoder;
|
|
565
588
|
constructor() {
|
|
566
589
|
this.response = new Promise((r) => {
|
|
567
590
|
this.resolve = r;
|
|
@@ -595,6 +618,16 @@ class BunResponse {
|
|
|
595
618
|
if (this.ended)
|
|
596
619
|
return;
|
|
597
620
|
this.ended = true;
|
|
621
|
+
if (this.streamWriter) {
|
|
622
|
+
try {
|
|
623
|
+
if (body) {
|
|
624
|
+
const bytes = typeof body === "string" ? this.textEncoder.encode(body) : body instanceof Uint8Array ? body : this.textEncoder.encode(JSON.stringify(body));
|
|
625
|
+
this.streamWriter.write(bytes);
|
|
626
|
+
}
|
|
627
|
+
this.streamWriter.close();
|
|
628
|
+
} catch {}
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
598
631
|
this.applyCookieHeaders();
|
|
599
632
|
if (this.chunks.length > 0) {
|
|
600
633
|
const finalBody = this.combineChunks(body);
|
|
@@ -604,14 +637,19 @@ class BunResponse {
|
|
|
604
637
|
this.sendResponse(body);
|
|
605
638
|
}
|
|
606
639
|
applyCookieHeaders() {
|
|
640
|
+
if (this.cookieMap.size === 0)
|
|
641
|
+
return;
|
|
607
642
|
this.cookieHeaders ??= this.cookieMap.toSetCookieHeaders();
|
|
608
|
-
|
|
609
|
-
this.setHeader("set-cookie", this.cookieHeaders.join(`
|
|
643
|
+
this.setHeader("set-cookie", this.cookieHeaders.join(`
|
|
610
644
|
`));
|
|
611
|
-
}
|
|
612
645
|
}
|
|
613
646
|
sendResponse(body) {
|
|
614
647
|
if (body !== null && typeof body === "object") {
|
|
648
|
+
const ctor = body.constructor;
|
|
649
|
+
if (ctor === Object || ctor === Array) {
|
|
650
|
+
this.resolve(this.buildJsonResponse(body));
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
615
653
|
if (body instanceof Uint8Array || body instanceof Blob) {
|
|
616
654
|
this.resolve(this.createResponse(body));
|
|
617
655
|
return;
|
|
@@ -695,10 +733,30 @@ class BunResponse {
|
|
|
695
733
|
once(event, listener) {
|
|
696
734
|
return this;
|
|
697
735
|
}
|
|
736
|
+
emit(event, ...args) {
|
|
737
|
+
return true;
|
|
738
|
+
}
|
|
739
|
+
get writableEnded() {
|
|
740
|
+
return this.ended;
|
|
741
|
+
}
|
|
698
742
|
write(chunk) {
|
|
699
743
|
if (this.ended) {
|
|
700
744
|
return false;
|
|
701
745
|
}
|
|
746
|
+
const contentType = this.headers?.get("content-type") ?? "";
|
|
747
|
+
const isStreamingResponse = contentType.includes("text/event-stream") || contentType.includes("application/octet-stream");
|
|
748
|
+
if (isStreamingResponse && !this.streamWriter) {
|
|
749
|
+
this.initializeStreamingMode();
|
|
750
|
+
}
|
|
751
|
+
if (this.streamWriter) {
|
|
752
|
+
try {
|
|
753
|
+
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));
|
|
754
|
+
this.streamWriter.write(bytes);
|
|
755
|
+
return true;
|
|
756
|
+
} catch {
|
|
757
|
+
return false;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
702
760
|
if (typeof chunk === "string") {
|
|
703
761
|
this.chunks.push(chunk);
|
|
704
762
|
return true;
|
|
@@ -721,6 +779,12 @@ class BunResponse {
|
|
|
721
779
|
}
|
|
722
780
|
return true;
|
|
723
781
|
}
|
|
782
|
+
initializeStreamingMode() {
|
|
783
|
+
const { readable, writable } = new TransformStream;
|
|
784
|
+
this.streamWriter = writable.getWriter();
|
|
785
|
+
this.applyCookieHeaders();
|
|
786
|
+
this.resolve(this.createResponse(readable));
|
|
787
|
+
}
|
|
724
788
|
getHeader(name) {
|
|
725
789
|
return this.headers?.get(name.toLowerCase()) ?? null;
|
|
726
790
|
}
|
|
@@ -745,6 +809,9 @@ class BunResponse {
|
|
|
745
809
|
isEnded() {
|
|
746
810
|
return this.ended;
|
|
747
811
|
}
|
|
812
|
+
_implicitHeader() {
|
|
813
|
+
this.writeHead(this.statusCode, {});
|
|
814
|
+
}
|
|
748
815
|
buildStreamableResponse(body) {
|
|
749
816
|
const streamHeaders = body.getHeaders();
|
|
750
817
|
const headers = this.headersMap;
|
|
@@ -764,9 +831,7 @@ class BunResponse {
|
|
|
764
831
|
if (headers === null || headers.size === 0) {
|
|
765
832
|
return Response.json(body, { status: this.statusCode });
|
|
766
833
|
}
|
|
767
|
-
|
|
768
|
-
headers.set("content-type", JSON_CONTENT_TYPE);
|
|
769
|
-
}
|
|
834
|
+
headers.set("content-type", JSON_CONTENT_TYPE);
|
|
770
835
|
return Response.json(body, {
|
|
771
836
|
status: this.statusCode,
|
|
772
837
|
headers: Object.fromEntries(headers)
|
|
@@ -786,13 +851,9 @@ class BunResponse {
|
|
|
786
851
|
|
|
787
852
|
// lib/bun.version-filter.middleware.ts
|
|
788
853
|
import { VERSION_NEUTRAL, VersioningType } from "@nestjs/common";
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
}
|
|
793
|
-
function callNext(next) {
|
|
794
|
-
return next();
|
|
795
|
-
}
|
|
854
|
+
var CUSTOM_VERSIONING_PHASE_KEY = "_cvp";
|
|
855
|
+
var CUSTOM_VERSIONING_CANDIDATES_KEY = "_cvc";
|
|
856
|
+
var CUSTOM_VERSIONING_BEST_CANDIDATE_KEY = "_cvb";
|
|
796
857
|
|
|
797
858
|
class BunVersionFilterMiddleware {
|
|
798
859
|
static createFilter(handler, version, versioningOptions) {
|
|
@@ -820,24 +881,26 @@ class BunVersionFilterMiddleware {
|
|
|
820
881
|
static computeAcceptsNeutral(version) {
|
|
821
882
|
return version === VERSION_NEUTRAL || Array.isArray(version) && version.includes(VERSION_NEUTRAL);
|
|
822
883
|
}
|
|
823
|
-
static getHeader(req, name) {
|
|
824
|
-
return req.headers.get(name) ?? undefined;
|
|
825
|
-
}
|
|
826
884
|
static createCustomVersionFilter(handler, version, options) {
|
|
827
885
|
const isVersionArray = Array.isArray(version);
|
|
828
886
|
const versionSet = isVersionArray ? new Set(version) : null;
|
|
829
887
|
const singleVersion = isVersionArray ? null : version;
|
|
830
|
-
return
|
|
888
|
+
return (req, res, next) => {
|
|
831
889
|
const extracted = options.extractor(req);
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
890
|
+
let phase = req.get(CUSTOM_VERSIONING_PHASE_KEY);
|
|
891
|
+
if (phase === undefined) {
|
|
892
|
+
phase = 0;
|
|
893
|
+
req.set(CUSTOM_VERSIONING_PHASE_KEY, phase);
|
|
894
|
+
}
|
|
895
|
+
let candidates = req.get(CUSTOM_VERSIONING_CANDIDATES_KEY);
|
|
896
|
+
if (!candidates) {
|
|
897
|
+
candidates = new Map;
|
|
898
|
+
req.set(CUSTOM_VERSIONING_CANDIDATES_KEY, candidates);
|
|
899
|
+
}
|
|
900
|
+
const extractedVersions = Array.isArray(extracted) ? extracted : [extracted];
|
|
838
901
|
let match;
|
|
839
902
|
let matchIndex = -1;
|
|
840
|
-
for (let i = 0
|
|
903
|
+
for (let i = 0, len = extractedVersions.length;i < len; i++) {
|
|
841
904
|
const extractedVersion = extractedVersions[i];
|
|
842
905
|
if (versionSet ? versionSet.has(extractedVersion) : extractedVersion === singleVersion) {
|
|
843
906
|
match = extractedVersion;
|
|
@@ -846,44 +909,44 @@ class BunVersionFilterMiddleware {
|
|
|
846
909
|
}
|
|
847
910
|
}
|
|
848
911
|
if (match) {
|
|
849
|
-
if (
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
});
|
|
854
|
-
return callNext(next);
|
|
912
|
+
if (phase === 0) {
|
|
913
|
+
candidates.set(match, matchIndex);
|
|
914
|
+
next();
|
|
915
|
+
return;
|
|
855
916
|
}
|
|
856
|
-
if (
|
|
857
|
-
return
|
|
917
|
+
if (req.get(CUSTOM_VERSIONING_BEST_CANDIDATE_KEY) === match) {
|
|
918
|
+
return handler(req, res, next);
|
|
858
919
|
}
|
|
859
920
|
}
|
|
860
|
-
|
|
921
|
+
next();
|
|
861
922
|
};
|
|
862
923
|
}
|
|
863
924
|
static createMediaTypeVersionFilter(handler, version, options) {
|
|
864
925
|
const acceptsNeutral = this.computeAcceptsNeutral(version);
|
|
865
926
|
const versionMatches = this.createVersionMatcher(version);
|
|
866
|
-
const
|
|
867
|
-
|
|
868
|
-
|
|
927
|
+
const key = options.key;
|
|
928
|
+
const keyLength = key.length;
|
|
929
|
+
return (req, res, next) => {
|
|
930
|
+
const acceptHeader = req.headers.get("accept");
|
|
869
931
|
if (acceptHeader) {
|
|
870
932
|
const semiIndex = acceptHeader.indexOf(";");
|
|
871
933
|
if (semiIndex !== -1) {
|
|
872
934
|
const versionPart = acceptHeader.substring(semiIndex + 1).trim();
|
|
873
|
-
const keyIndex = versionPart.indexOf(
|
|
935
|
+
const keyIndex = versionPart.indexOf(key);
|
|
874
936
|
if (keyIndex !== -1) {
|
|
875
937
|
const headerVersion = versionPart.substring(keyIndex + keyLength);
|
|
876
938
|
if (versionMatches(headerVersion)) {
|
|
877
|
-
return
|
|
939
|
+
return handler(req, res, next);
|
|
878
940
|
}
|
|
879
|
-
|
|
941
|
+
next();
|
|
942
|
+
return;
|
|
880
943
|
}
|
|
881
944
|
}
|
|
882
945
|
}
|
|
883
946
|
if (acceptsNeutral) {
|
|
884
|
-
return
|
|
947
|
+
return handler(req, res, next);
|
|
885
948
|
}
|
|
886
|
-
|
|
949
|
+
next();
|
|
887
950
|
};
|
|
888
951
|
}
|
|
889
952
|
static createHeaderVersionFilter(handler, version, options) {
|
|
@@ -893,21 +956,25 @@ class BunVersionFilterMiddleware {
|
|
|
893
956
|
const hasNeutralDefault = defaultVersion === VERSION_NEUTRAL;
|
|
894
957
|
const resolvedDefault = this.resolveDefaultVersion(version, defaultVersion);
|
|
895
958
|
const headerName = options.header;
|
|
896
|
-
return
|
|
897
|
-
let headerVersion =
|
|
898
|
-
if (headerVersion
|
|
899
|
-
headerVersion =
|
|
959
|
+
return (req, res, next) => {
|
|
960
|
+
let headerVersion = req.headers.get(headerName) ?? undefined;
|
|
961
|
+
if (headerVersion) {
|
|
962
|
+
headerVersion = headerVersion.trim();
|
|
963
|
+
if (headerVersion === "")
|
|
964
|
+
headerVersion = undefined;
|
|
965
|
+
}
|
|
900
966
|
headerVersion ??= resolvedDefault;
|
|
901
967
|
if (!headerVersion) {
|
|
902
968
|
if ((hasNeutralDefault || !defaultVersion) && acceptsNeutral) {
|
|
903
|
-
return
|
|
969
|
+
return handler(req, res, next);
|
|
904
970
|
}
|
|
905
|
-
|
|
971
|
+
next();
|
|
972
|
+
return;
|
|
906
973
|
}
|
|
907
974
|
if (versionMatches(headerVersion)) {
|
|
908
|
-
return
|
|
975
|
+
return handler(req, res, next);
|
|
909
976
|
}
|
|
910
|
-
|
|
977
|
+
next();
|
|
911
978
|
};
|
|
912
979
|
}
|
|
913
980
|
static resolveDefaultVersion(handlerVersion, defaultVersion) {
|
|
@@ -924,12 +991,15 @@ class BunVersionFilterMiddleware {
|
|
|
924
991
|
return;
|
|
925
992
|
}
|
|
926
993
|
static selectBestCustomVersionCandidate(req) {
|
|
927
|
-
const
|
|
928
|
-
if (phase !==
|
|
994
|
+
const phase = req.get(CUSTOM_VERSIONING_PHASE_KEY);
|
|
995
|
+
if (phase !== 0)
|
|
996
|
+
return null;
|
|
997
|
+
const candidates = req.get(CUSTOM_VERSIONING_CANDIDATES_KEY);
|
|
998
|
+
if (!candidates?.size)
|
|
929
999
|
return null;
|
|
930
1000
|
let bestVersion = null;
|
|
931
1001
|
let bestPriority = Infinity;
|
|
932
|
-
for (const [version,
|
|
1002
|
+
for (const [version, priority] of candidates) {
|
|
933
1003
|
if (priority < bestPriority) {
|
|
934
1004
|
bestPriority = priority;
|
|
935
1005
|
bestVersion = version;
|
|
@@ -938,17 +1008,19 @@ class BunVersionFilterMiddleware {
|
|
|
938
1008
|
return bestVersion;
|
|
939
1009
|
}
|
|
940
1010
|
static setCustomVersioningExecutionPhase(req, bestVersion) {
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
reqMeta._customVersioningBestCandidate = bestVersion;
|
|
1011
|
+
req.set(CUSTOM_VERSIONING_PHASE_KEY, 1);
|
|
1012
|
+
req.set(CUSTOM_VERSIONING_BEST_CANDIDATE_KEY, bestVersion);
|
|
944
1013
|
}
|
|
945
1014
|
static hasCustomVersioningCandidates(req) {
|
|
946
|
-
const
|
|
947
|
-
|
|
1015
|
+
const phase = req.get(CUSTOM_VERSIONING_PHASE_KEY);
|
|
1016
|
+
if (phase !== 0)
|
|
1017
|
+
return false;
|
|
1018
|
+
const candidates = req.get(CUSTOM_VERSIONING_CANDIDATES_KEY);
|
|
1019
|
+
return !!candidates?.size;
|
|
948
1020
|
}
|
|
949
1021
|
}
|
|
950
1022
|
|
|
951
|
-
// lib/bun.
|
|
1023
|
+
// lib/bun.server-instance.ts
|
|
952
1024
|
var REQUEST_METHOD_STRINGS = [
|
|
953
1025
|
"GET",
|
|
954
1026
|
"POST",
|
|
@@ -968,9 +1040,9 @@ var REQUEST_METHOD_STRINGS = [
|
|
|
968
1040
|
"UNLOCK"
|
|
969
1041
|
];
|
|
970
1042
|
|
|
971
|
-
class
|
|
1043
|
+
class BunServerInstance {
|
|
972
1044
|
bunServeOptions;
|
|
973
|
-
logger = new Logger("
|
|
1045
|
+
logger = new Logger("BunServerInstance", { timestamp: true });
|
|
974
1046
|
middlewareEngine = new BunMiddlewareEngine;
|
|
975
1047
|
useVersioning = false;
|
|
976
1048
|
routes = Object.create(null);
|
|
@@ -988,35 +1060,27 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
988
1060
|
wsOptions = {};
|
|
989
1061
|
useWs = false;
|
|
990
1062
|
useWsCors = false;
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
id: randomUUIDv7()
|
|
995
|
-
}) {
|
|
996
|
-
super();
|
|
1063
|
+
staticAssetsOptions = null;
|
|
1064
|
+
httpServer = null;
|
|
1065
|
+
constructor(bunServeOptions) {
|
|
997
1066
|
this.bunServeOptions = bunServeOptions;
|
|
998
|
-
this.setInstance({
|
|
999
|
-
use: (maybePath, maybeHandler) => {
|
|
1000
|
-
if (typeof maybePath === "string") {
|
|
1001
|
-
let path = maybePath;
|
|
1002
|
-
const handler = maybeHandler;
|
|
1003
|
-
if (!handler) {
|
|
1004
|
-
throw new Error("Handler must be provided when path is a string.");
|
|
1005
|
-
}
|
|
1006
|
-
if (path.includes("/*")) {
|
|
1007
|
-
path = path.substring(0, path.indexOf("/*"));
|
|
1008
|
-
}
|
|
1009
|
-
this.logger.log(`Registering middleware for path: ${path}`);
|
|
1010
|
-
this.middlewareEngine.useRoute("ALL", path, handler);
|
|
1011
|
-
} else {
|
|
1012
|
-
const handler = maybePath;
|
|
1013
|
-
this.middlewareEngine.useGlobal(handler);
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
});
|
|
1017
1067
|
}
|
|
1018
|
-
use(
|
|
1019
|
-
|
|
1068
|
+
use(maybePath, maybeHandler) {
|
|
1069
|
+
if (typeof maybePath === "string") {
|
|
1070
|
+
let path = maybePath;
|
|
1071
|
+
const handler = maybeHandler;
|
|
1072
|
+
if (!handler) {
|
|
1073
|
+
throw new Error("Handler must be provided when path is a string.");
|
|
1074
|
+
}
|
|
1075
|
+
if (path.includes("/*")) {
|
|
1076
|
+
path = path.substring(0, path.indexOf("/*"));
|
|
1077
|
+
}
|
|
1078
|
+
this.logger.log(`Registering middleware for path: ${path}`);
|
|
1079
|
+
this.middlewareEngine.useRoute("ALL", path, handler);
|
|
1080
|
+
} else {
|
|
1081
|
+
const handler = maybePath;
|
|
1082
|
+
this.middlewareEngine.useGlobal(handler);
|
|
1083
|
+
}
|
|
1020
1084
|
}
|
|
1021
1085
|
createHttpMethodHandler(httpMethod) {
|
|
1022
1086
|
return (pathOrHandler, maybeHandler) => {
|
|
@@ -1077,95 +1141,88 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1077
1141
|
search(pathOrHandler, maybeHandler) {
|
|
1078
1142
|
this.createUnsupportedMethod()(pathOrHandler, maybeHandler);
|
|
1079
1143
|
}
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1144
|
+
async listen(port, hostnameOrCallback, maybeCallback) {
|
|
1145
|
+
const hostname = typeof hostnameOrCallback === "string" ? hostnameOrCallback : this.bunServeOptions.hostname ?? "127.0.0.1";
|
|
1146
|
+
const callback = typeof hostnameOrCallback === "function" ? hostnameOrCallback : maybeCallback;
|
|
1147
|
+
const middlewareEngine = this.middlewareEngine;
|
|
1148
|
+
const notFoundHandler = this.notFoundHandler;
|
|
1149
|
+
const wsHandlers = this.wsHandlers;
|
|
1150
|
+
const bunServeOptions = this.bunServeOptions;
|
|
1151
|
+
await this.setupStaticAssetsIfNeeded();
|
|
1152
|
+
this.setupWebSocketIfNeeded(wsHandlers, bunServeOptions);
|
|
1153
|
+
const fetch = async (request, server) => {
|
|
1154
|
+
const bunRequest = new BunRequest(request);
|
|
1155
|
+
if (await this.upgradeWebSocket(request, bunRequest, server)) {
|
|
1156
|
+
return;
|
|
1157
|
+
}
|
|
1158
|
+
const routeHandler = middlewareEngine.findRouteHandler(bunRequest.method, bunRequest.pathname) ?? notFoundHandler;
|
|
1159
|
+
const bunResponse = await middlewareEngine.run({
|
|
1160
|
+
req: bunRequest,
|
|
1161
|
+
res: new BunResponse,
|
|
1162
|
+
method: bunRequest.method,
|
|
1163
|
+
path: bunRequest.pathname,
|
|
1164
|
+
requestHandler: routeHandler
|
|
1165
|
+
});
|
|
1166
|
+
return bunResponse.res();
|
|
1167
|
+
};
|
|
1168
|
+
this.httpServer = this.createServer(port, hostname, bunServeOptions, fetch);
|
|
1169
|
+
callback?.();
|
|
1170
|
+
return this.httpServer;
|
|
1088
1171
|
}
|
|
1089
|
-
async
|
|
1090
|
-
|
|
1172
|
+
async stop(force) {
|
|
1173
|
+
const server = this.httpServer;
|
|
1174
|
+
if (!server) {
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
await server.stop(force);
|
|
1091
1178
|
}
|
|
1092
|
-
|
|
1093
|
-
const
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
});
|
|
1101
|
-
this.setHttpServer(preflightServer);
|
|
1102
|
-
if (options.httpsOptions) {
|
|
1103
|
-
this.bunServeOptions.tls = {
|
|
1104
|
-
key: options.httpsOptions.key,
|
|
1105
|
-
cert: options.httpsOptions.cert,
|
|
1106
|
-
passphrase: options.httpsOptions.passphrase,
|
|
1107
|
-
ca: options.httpsOptions.ca,
|
|
1108
|
-
ciphers: options.httpsOptions.ciphers,
|
|
1109
|
-
secureOptions: options.httpsOptions.secureOptions,
|
|
1110
|
-
rejectUnauthorized: options.httpsOptions.rejectUnauthorized,
|
|
1111
|
-
requestCert: options.httpsOptions.requestCert
|
|
1179
|
+
address() {
|
|
1180
|
+
const server = this.httpServer;
|
|
1181
|
+
if (!server) {
|
|
1182
|
+
const hostname = this.bunServeOptions.hostname;
|
|
1183
|
+
const port = this.bunServeOptions.port;
|
|
1184
|
+
return {
|
|
1185
|
+
address: typeof hostname === "string" ? hostname : "127.0.0.1",
|
|
1186
|
+
port: typeof port === "number" ? port : 3000
|
|
1112
1187
|
};
|
|
1113
1188
|
}
|
|
1114
|
-
return
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1189
|
+
return {
|
|
1190
|
+
address: server.hostname ?? "127.0.0.1",
|
|
1191
|
+
port: server.port ?? 3000
|
|
1192
|
+
};
|
|
1118
1193
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1194
|
+
setWsOptions(options) {
|
|
1195
|
+
this.wsOptions = options;
|
|
1121
1196
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1197
|
+
registerWsOpenHandler(handler) {
|
|
1198
|
+
this.wsHandlers.onOpen = handler;
|
|
1124
1199
|
}
|
|
1125
|
-
|
|
1126
|
-
|
|
1200
|
+
registerWsMessageHandler(handler) {
|
|
1201
|
+
this.wsHandlers.onMessage = handler;
|
|
1127
1202
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
response.setStatus(statusCode);
|
|
1131
|
-
}
|
|
1132
|
-
response.end(body);
|
|
1203
|
+
registerWsCloseHandler(handler) {
|
|
1204
|
+
this.wsHandlers.onClose = handler;
|
|
1133
1205
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1206
|
+
getBunServer() {
|
|
1207
|
+
return this.httpServer;
|
|
1136
1208
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1209
|
+
async close() {
|
|
1210
|
+
await this.stop(true);
|
|
1139
1211
|
}
|
|
1140
|
-
|
|
1141
|
-
this.middlewareEngine
|
|
1212
|
+
getMiddlewareEngine() {
|
|
1213
|
+
return this.middlewareEngine;
|
|
1142
1214
|
}
|
|
1143
|
-
setNotFoundHandler(handler
|
|
1215
|
+
setNotFoundHandler(handler) {
|
|
1144
1216
|
this.notFoundHandler = handler;
|
|
1145
|
-
this.middlewareEngine.useNotFoundHandler(handler);
|
|
1146
|
-
}
|
|
1147
|
-
isHeadersSent(response) {
|
|
1148
|
-
return response.isEnded();
|
|
1149
|
-
}
|
|
1150
|
-
getHeader(response, name) {
|
|
1151
|
-
return response.getHeader(name);
|
|
1152
|
-
}
|
|
1153
|
-
setHeader(response, name, value) {
|
|
1154
|
-
response.setHeader(name, value);
|
|
1155
1217
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1218
|
+
setUseVersioning(value) {
|
|
1219
|
+
this.useVersioning = value;
|
|
1158
1220
|
}
|
|
1159
1221
|
registerParserMiddleware(prefix, rawBody) {
|
|
1160
1222
|
this.logger.log(`Registering Body Parser Middleware with prefix: ${prefix || "/"} and rawBody: ${rawBody ? "true" : "false"}`);
|
|
1161
1223
|
const bodyParser = new BunBodyParserMiddleware({ prefix, rawBody });
|
|
1162
1224
|
this.middlewareEngine.useGlobal(bodyParser.run.bind(bodyParser));
|
|
1163
1225
|
}
|
|
1164
|
-
enableCors(options, prefix) {
|
|
1165
|
-
this.logger.log(`Enabling CORS Middleware with prefix: ${prefix ?? "/"}`);
|
|
1166
|
-
const corsMiddleware = new BunCorsMiddleware({ corsOptions: options, prefix });
|
|
1167
|
-
this.middlewareEngine.useGlobal(corsMiddleware.run.bind(corsMiddleware));
|
|
1168
|
-
}
|
|
1169
1226
|
createMiddlewareFactory(requestMethod) {
|
|
1170
1227
|
return (path, callback) => {
|
|
1171
1228
|
const methodName = this.mapRequestMethodToString(requestMethod);
|
|
@@ -1177,41 +1234,14 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1177
1234
|
this.middlewareEngine.useRoute(methodName, normalizedPath, callback);
|
|
1178
1235
|
};
|
|
1179
1236
|
}
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
this.logger.log(`Applying Version Filter Middleware for version: ${JSON.stringify(version)}`);
|
|
1185
|
-
this.useVersioning = true;
|
|
1186
|
-
return BunVersionFilterMiddleware.createFilter(handler, version, versioningOptions);
|
|
1237
|
+
enableCors(corsOptions, prefix) {
|
|
1238
|
+
this.logger.log(`Enabling CORS Middleware with prefix: ${prefix ?? "/"}`);
|
|
1239
|
+
const corsMiddleware = new BunCorsMiddleware({ corsOptions, prefix });
|
|
1240
|
+
this.middlewareEngine.useGlobal(corsMiddleware.run.bind(corsMiddleware));
|
|
1187
1241
|
}
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
const middlewareEngine = this.middlewareEngine;
|
|
1192
|
-
const notFoundHandler = this.notFoundHandler;
|
|
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
|
-
}
|
|
1200
|
-
const bunRequest = new BunRequest(request);
|
|
1201
|
-
const bunResponse = new BunResponse;
|
|
1202
|
-
const routeHandler = middlewareEngine.findRouteHandler(bunRequest.method, bunRequest.pathname) ?? notFoundHandler;
|
|
1203
|
-
await middlewareEngine.run({
|
|
1204
|
-
req: bunRequest,
|
|
1205
|
-
res: bunResponse,
|
|
1206
|
-
method: bunRequest.method,
|
|
1207
|
-
path: bunRequest.pathname,
|
|
1208
|
-
requestHandler: routeHandler
|
|
1209
|
-
});
|
|
1210
|
-
return bunResponse.res();
|
|
1211
|
-
};
|
|
1212
|
-
const server = this.createServer(port, hostname, bunServeOptions, fetch);
|
|
1213
|
-
callback?.();
|
|
1214
|
-
this.setHttpServer(server);
|
|
1242
|
+
useStaticAssets(path, options) {
|
|
1243
|
+
this.logger.log(`Configuring static assets serving from path: ${path} with options: ${JSON.stringify(options)}`);
|
|
1244
|
+
this.staticAssetsOptions = { path, options };
|
|
1215
1245
|
}
|
|
1216
1246
|
static isNumericPort(value) {
|
|
1217
1247
|
return typeof value === "number" || !isNaN(Number(value));
|
|
@@ -1228,11 +1258,7 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1228
1258
|
const connectionHeader = request.headers.get("connection");
|
|
1229
1259
|
return !!(upgradeHeader?.toLowerCase() === "websocket" && connectionHeader?.toLowerCase().includes("upgrade"));
|
|
1230
1260
|
}
|
|
1231
|
-
async
|
|
1232
|
-
if (this.wsCorsHeaders) {
|
|
1233
|
-
return this.wsCorsHeaders;
|
|
1234
|
-
}
|
|
1235
|
-
const bunRequest = new BunRequest(request);
|
|
1261
|
+
async provideCorsHeaders(bunRequest) {
|
|
1236
1262
|
const bunResponse = new BunResponse;
|
|
1237
1263
|
await this.wsMiddlewareEngine.run({
|
|
1238
1264
|
req: bunRequest,
|
|
@@ -1244,66 +1270,124 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1244
1270
|
}
|
|
1245
1271
|
});
|
|
1246
1272
|
const response = await bunResponse.res();
|
|
1247
|
-
|
|
1248
|
-
return this.wsCorsHeaders;
|
|
1273
|
+
return response.headers;
|
|
1249
1274
|
}
|
|
1250
|
-
async upgradeWebSocket(request, server) {
|
|
1275
|
+
async upgradeWebSocket(request, bunRequest, server) {
|
|
1251
1276
|
if (!this.useWs || !this.isWebSocketUpgradeRequest(request)) {
|
|
1252
1277
|
return false;
|
|
1253
1278
|
}
|
|
1254
|
-
|
|
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);
|
|
1279
|
+
const headers = this.useWsCors ? await this.provideCorsHeaders(bunRequest) : undefined;
|
|
1260
1280
|
return server.upgrade(request, {
|
|
1261
1281
|
headers,
|
|
1262
|
-
data:
|
|
1282
|
+
data: await this.wsOptions.clientDataFactory?.(bunRequest) ?? {}
|
|
1263
1283
|
});
|
|
1264
1284
|
}
|
|
1285
|
+
async setupStaticAssetsIfNeeded() {
|
|
1286
|
+
if (!this.staticAssetsOptions)
|
|
1287
|
+
return;
|
|
1288
|
+
const { path, options } = this.staticAssetsOptions;
|
|
1289
|
+
const files = await readdir(path, { withFileTypes: true, recursive: true });
|
|
1290
|
+
const flattenFiles = files.flat(Infinity);
|
|
1291
|
+
if (flattenFiles.length === 0)
|
|
1292
|
+
return;
|
|
1293
|
+
const useStatic = options?.useStatic ?? false;
|
|
1294
|
+
for (const file of flattenFiles) {
|
|
1295
|
+
if (!file.isFile())
|
|
1296
|
+
continue;
|
|
1297
|
+
const relativePath = file.parentPath.replace(path, "");
|
|
1298
|
+
const routePath = relativePath.startsWith("/") ? [relativePath, file.name].join("/") : `/${file.name}`;
|
|
1299
|
+
if (useStatic) {
|
|
1300
|
+
const bunFile = Bun.file(join(file.parentPath, file.name));
|
|
1301
|
+
this.routes[routePath] = {
|
|
1302
|
+
GET: new Response(await bunFile.bytes(), {
|
|
1303
|
+
headers: {
|
|
1304
|
+
"Content-Type": bunFile.type
|
|
1305
|
+
}
|
|
1306
|
+
})
|
|
1307
|
+
};
|
|
1308
|
+
} else {
|
|
1309
|
+
this.delegateRouteHandler("GET", routePath, async (req, res) => {
|
|
1310
|
+
const bunFile = Bun.file(join(file.parentPath, file.name));
|
|
1311
|
+
if (!await bunFile.exists()) {
|
|
1312
|
+
this.notFoundHandler(req, res);
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
const ifModifiedSince = req.headers.get("if-modified-since");
|
|
1316
|
+
if (ifModifiedSince) {
|
|
1317
|
+
const lastModified = bunFile.lastModified;
|
|
1318
|
+
if (new Date(ifModifiedSince).getTime() >= lastModified) {
|
|
1319
|
+
res.setStatus(304);
|
|
1320
|
+
res.end();
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
const range = req.headers.get("range");
|
|
1325
|
+
if (range) {
|
|
1326
|
+
const fileSize = bunFile.size;
|
|
1327
|
+
const match = /bytes=(\d*)-(\d*)/.exec(range);
|
|
1328
|
+
if (match) {
|
|
1329
|
+
const start = parseInt(match[1], 10) || 0;
|
|
1330
|
+
const end = parseInt(match[2], 10) || fileSize - 1;
|
|
1331
|
+
if (start >= 0 && end < fileSize && start <= end) {
|
|
1332
|
+
res.setStatus(206);
|
|
1333
|
+
res.setHeader("Content-Range", `bytes ${start.toString()}-${end.toString()}/${fileSize.toString()}`);
|
|
1334
|
+
res.end(bunFile.slice(start, end + 1));
|
|
1335
|
+
return;
|
|
1336
|
+
} else {
|
|
1337
|
+
res.setStatus(416);
|
|
1338
|
+
res.setHeader("Content-Range", `bytes */${fileSize.toString()}`);
|
|
1339
|
+
res.end();
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
res.end(bunFile);
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1265
1349
|
setupWebSocketIfNeeded(wsHandlers, bunServeOptions) {
|
|
1266
1350
|
const useWs = !!wsHandlers.onOpen && !!wsHandlers.onMessage && !!wsHandlers.onClose;
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
}
|
|
1288
|
-
}
|
|
1351
|
+
if (!useWs)
|
|
1352
|
+
return;
|
|
1353
|
+
this.useWs = true;
|
|
1354
|
+
const getServer = () => this.getBunServer();
|
|
1355
|
+
const onMessage = wsHandlers.onMessage;
|
|
1356
|
+
const onOpen = wsHandlers.onOpen;
|
|
1357
|
+
const onClose = wsHandlers.onClose;
|
|
1358
|
+
bunServeOptions.websocket = {
|
|
1359
|
+
...this.wsOptions,
|
|
1360
|
+
message: (ws, message) => {
|
|
1361
|
+
ws.data.onMessageInternal?.(message);
|
|
1362
|
+
onMessage?.(ws, message, getServer());
|
|
1363
|
+
},
|
|
1364
|
+
open: (ws) => {
|
|
1365
|
+
onOpen?.(ws);
|
|
1366
|
+
},
|
|
1367
|
+
close: (ws, code, reason) => {
|
|
1368
|
+
ws.data.onCloseInternal?.();
|
|
1369
|
+
ws.data.onDisconnect?.(ws);
|
|
1370
|
+
onClose?.(ws, code, reason);
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1289
1373
|
const useWsCors = typeof this.wsOptions.cors !== "undefined";
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1374
|
+
if (!useWsCors)
|
|
1375
|
+
return;
|
|
1376
|
+
this.useWsCors = true;
|
|
1377
|
+
const corsMiddleware = new BunCorsMiddleware({
|
|
1378
|
+
corsOptions: this.wsOptions.cors === true ? undefined : this.wsOptions.cors
|
|
1379
|
+
});
|
|
1380
|
+
this.wsMiddlewareEngine.useGlobal(corsMiddleware.run.bind(corsMiddleware));
|
|
1297
1381
|
}
|
|
1298
1382
|
createServer(port, hostname, bunServeOptions, fetch) {
|
|
1299
|
-
return
|
|
1383
|
+
return BunServerInstance.isNumericPort(port) ? Bun.serve({
|
|
1300
1384
|
...bunServeOptions,
|
|
1301
1385
|
hostname,
|
|
1302
1386
|
port,
|
|
1303
1387
|
routes: this.routes,
|
|
1304
1388
|
fetch
|
|
1305
1389
|
}) : Bun.serve({
|
|
1306
|
-
...
|
|
1390
|
+
...BunServerInstance.omitKeys(bunServeOptions, "idleTimeout", "port", "hostname"),
|
|
1307
1391
|
unix: port,
|
|
1308
1392
|
routes: this.routes,
|
|
1309
1393
|
fetch
|
|
@@ -1320,21 +1404,19 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1320
1404
|
}
|
|
1321
1405
|
}
|
|
1322
1406
|
prepareRequestHandler(method, path, handler) {
|
|
1323
|
-
if (!this.useVersioning)
|
|
1407
|
+
if (!this.useVersioning)
|
|
1324
1408
|
return handler;
|
|
1325
|
-
}
|
|
1326
1409
|
return this.createChainedHandlerForVersioningResolution(this.createVersioningHandlers(method, path, handler), this.notFoundHandler);
|
|
1327
1410
|
}
|
|
1328
1411
|
createRouteFetchHandler(path, method, requestHandler) {
|
|
1329
1412
|
return async (request, server) => {
|
|
1330
|
-
|
|
1413
|
+
const bunRequest = new BunRequest(request);
|
|
1414
|
+
if (path === "/" && await this.upgradeWebSocket(request, bunRequest, server)) {
|
|
1331
1415
|
return;
|
|
1332
1416
|
}
|
|
1333
|
-
const
|
|
1334
|
-
const bunResponse = new BunResponse;
|
|
1335
|
-
await this.middlewareEngine.run({
|
|
1417
|
+
const bunResponse = await this.middlewareEngine.run({
|
|
1336
1418
|
req: bunRequest,
|
|
1337
|
-
res:
|
|
1419
|
+
res: new BunResponse,
|
|
1338
1420
|
method,
|
|
1339
1421
|
path,
|
|
1340
1422
|
requestHandler
|
|
@@ -1390,9 +1472,119 @@ class BunAdapter extends AbstractHttpAdapter {
|
|
|
1390
1472
|
return { path, handler };
|
|
1391
1473
|
}
|
|
1392
1474
|
}
|
|
1475
|
+
|
|
1476
|
+
// lib/bun.adapter.ts
|
|
1477
|
+
class BunAdapter extends AbstractHttpAdapter {
|
|
1478
|
+
bunServeOptions;
|
|
1479
|
+
logger = new Logger2("BunAdapter", { timestamp: true });
|
|
1480
|
+
constructor(bunServeOptions = {
|
|
1481
|
+
development: false,
|
|
1482
|
+
id: randomUUIDv7()
|
|
1483
|
+
}) {
|
|
1484
|
+
super(new BunServerInstance(bunServeOptions));
|
|
1485
|
+
this.bunServeOptions = bunServeOptions;
|
|
1486
|
+
}
|
|
1487
|
+
useStaticAssets(path, options) {
|
|
1488
|
+
this.instance.useStaticAssets(path, options);
|
|
1489
|
+
}
|
|
1490
|
+
setViewEngine(engine) {
|
|
1491
|
+
throw new Error("Not supported.");
|
|
1492
|
+
}
|
|
1493
|
+
render(response, view, options) {
|
|
1494
|
+
throw new Error("Not supported.");
|
|
1495
|
+
}
|
|
1496
|
+
async close() {
|
|
1497
|
+
await this.instance.close();
|
|
1498
|
+
}
|
|
1499
|
+
initHttpServer(options) {
|
|
1500
|
+
this.configureTls(options);
|
|
1501
|
+
const preflightServer = new BunPreflightHttpServer(this.instance);
|
|
1502
|
+
this.setHttpServer(preflightServer);
|
|
1503
|
+
return preflightServer;
|
|
1504
|
+
}
|
|
1505
|
+
getRequestHostname(request) {
|
|
1506
|
+
return request.hostname;
|
|
1507
|
+
}
|
|
1508
|
+
getRequestMethod(request) {
|
|
1509
|
+
return request.method;
|
|
1510
|
+
}
|
|
1511
|
+
getRequestUrl(request) {
|
|
1512
|
+
return request.pathname;
|
|
1513
|
+
}
|
|
1514
|
+
status(response, statusCode) {
|
|
1515
|
+
response.setStatus(statusCode);
|
|
1516
|
+
}
|
|
1517
|
+
reply(response, body, statusCode) {
|
|
1518
|
+
if (statusCode) {
|
|
1519
|
+
response.setStatus(statusCode);
|
|
1520
|
+
}
|
|
1521
|
+
response.end(body);
|
|
1522
|
+
}
|
|
1523
|
+
end(response, message) {
|
|
1524
|
+
response.end(message);
|
|
1525
|
+
}
|
|
1526
|
+
redirect(response, statusCode, url) {
|
|
1527
|
+
response.redirect(url, statusCode);
|
|
1528
|
+
}
|
|
1529
|
+
setErrorHandler(handler, prefix) {
|
|
1530
|
+
this.instance.getMiddlewareEngine().useErrorHandler(handler);
|
|
1531
|
+
}
|
|
1532
|
+
setNotFoundHandler(handler, prefix) {
|
|
1533
|
+
this.instance.setNotFoundHandler(handler);
|
|
1534
|
+
this.instance.getMiddlewareEngine().useNotFoundHandler(handler);
|
|
1535
|
+
}
|
|
1536
|
+
isHeadersSent(response) {
|
|
1537
|
+
return response.isEnded();
|
|
1538
|
+
}
|
|
1539
|
+
getHeader(response, name) {
|
|
1540
|
+
return response.getHeader(name);
|
|
1541
|
+
}
|
|
1542
|
+
setHeader(response, name, value) {
|
|
1543
|
+
response.setHeader(name, value);
|
|
1544
|
+
}
|
|
1545
|
+
appendHeader(response, name, value) {
|
|
1546
|
+
response.appendHeader(name, value);
|
|
1547
|
+
}
|
|
1548
|
+
registerParserMiddleware(prefix, rawBody) {
|
|
1549
|
+
this.instance.registerParserMiddleware(prefix, rawBody);
|
|
1550
|
+
}
|
|
1551
|
+
enableCors(options, prefix) {
|
|
1552
|
+
this.instance.enableCors(options, prefix);
|
|
1553
|
+
}
|
|
1554
|
+
createMiddlewareFactory(requestMethod) {
|
|
1555
|
+
return this.instance.createMiddlewareFactory(requestMethod);
|
|
1556
|
+
}
|
|
1557
|
+
getType() {
|
|
1558
|
+
return "bun";
|
|
1559
|
+
}
|
|
1560
|
+
applyVersionFilter(handler, version, versioningOptions) {
|
|
1561
|
+
this.logger.log(`Applying Version Filter Middleware for version: ${JSON.stringify(version)}`);
|
|
1562
|
+
this.instance.setUseVersioning(true);
|
|
1563
|
+
return BunVersionFilterMiddleware.createFilter(handler, version, versioningOptions);
|
|
1564
|
+
}
|
|
1565
|
+
listen(port, hostnameOrCallback, maybeCallback) {
|
|
1566
|
+
this.instance.listen(port, hostnameOrCallback, maybeCallback).then((server) => {
|
|
1567
|
+
this.setHttpServer(server);
|
|
1568
|
+
});
|
|
1569
|
+
}
|
|
1570
|
+
configureTls(options) {
|
|
1571
|
+
if (options.httpsOptions) {
|
|
1572
|
+
this.bunServeOptions.tls = {
|
|
1573
|
+
key: options.httpsOptions.key,
|
|
1574
|
+
cert: options.httpsOptions.cert,
|
|
1575
|
+
passphrase: options.httpsOptions.passphrase,
|
|
1576
|
+
ca: options.httpsOptions.ca,
|
|
1577
|
+
ciphers: options.httpsOptions.ciphers,
|
|
1578
|
+
secureOptions: options.httpsOptions.secureOptions,
|
|
1579
|
+
rejectUnauthorized: options.httpsOptions.rejectUnauthorized,
|
|
1580
|
+
requestCert: options.httpsOptions.requestCert
|
|
1581
|
+
};
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1393
1585
|
// lib/bun.file.interceptor.ts
|
|
1394
1586
|
import { Injectable } from "@nestjs/common";
|
|
1395
|
-
import { basename, join } from "path";
|
|
1587
|
+
import { basename, join as join2 } from "path";
|
|
1396
1588
|
import { HttpAdapterHost } from "@nestjs/core";
|
|
1397
1589
|
var {randomUUIDv7: randomUUIDv72 } = globalThis.Bun;
|
|
1398
1590
|
import { tmpdir } from "os";
|
|
@@ -1402,7 +1594,7 @@ class BunFileInterceptor {
|
|
|
1402
1594
|
constructor(adapter) {
|
|
1403
1595
|
this.adapter = adapter;
|
|
1404
1596
|
const httpAdapter = this.adapter.httpAdapter;
|
|
1405
|
-
this.uploadDir ??=
|
|
1597
|
+
this.uploadDir ??= join2(tmpdir(), "uploads", httpAdapter.getHttpServer().id, randomUUIDv72());
|
|
1406
1598
|
}
|
|
1407
1599
|
async intercept(context, next) {
|
|
1408
1600
|
const request = context.switchToHttp().getRequest();
|
|
@@ -1410,7 +1602,7 @@ class BunFileInterceptor {
|
|
|
1410
1602
|
return next.handle();
|
|
1411
1603
|
}
|
|
1412
1604
|
const files = await Promise.all(request.files.map(async (file) => {
|
|
1413
|
-
const destPath =
|
|
1605
|
+
const destPath = join2(this.uploadDir, basename(file.name));
|
|
1414
1606
|
await Bun.write(destPath, file);
|
|
1415
1607
|
return Bun.file(destPath);
|
|
1416
1608
|
}));
|
|
@@ -1430,7 +1622,7 @@ import {
|
|
|
1430
1622
|
AbstractWsAdapter
|
|
1431
1623
|
} from "@nestjs/websockets";
|
|
1432
1624
|
import { EMPTY, Subject, mergeMap } from "rxjs";
|
|
1433
|
-
import { Logger as
|
|
1625
|
+
import { Logger as Logger3 } from "@nestjs/common";
|
|
1434
1626
|
import { isNil } from "@nestjs/common/utils/shared.utils.js";
|
|
1435
1627
|
var WS_READY_STATE_OPEN = 1;
|
|
1436
1628
|
var defaultMessageParser = (data) => {
|
|
@@ -1447,7 +1639,7 @@ var defaultMessageParser = (data) => {
|
|
|
1447
1639
|
};
|
|
1448
1640
|
|
|
1449
1641
|
class BunWsAdapter extends AbstractWsAdapter {
|
|
1450
|
-
logger = new
|
|
1642
|
+
logger = new Logger3(BunWsAdapter.name);
|
|
1451
1643
|
nestApp;
|
|
1452
1644
|
messageParser = defaultMessageParser;
|
|
1453
1645
|
onOpenHandler;
|
|
@@ -1572,6 +1764,7 @@ class BunWsAdapter extends AbstractWsAdapter {
|
|
|
1572
1764
|
}
|
|
1573
1765
|
export {
|
|
1574
1766
|
BunWsAdapter,
|
|
1767
|
+
BunServerInstance,
|
|
1575
1768
|
BunResponse,
|
|
1576
1769
|
BunRequest,
|
|
1577
1770
|
BunPreflightHttpServer,
|
|
@@ -1579,5 +1772,5 @@ export {
|
|
|
1579
1772
|
BunAdapter
|
|
1580
1773
|
};
|
|
1581
1774
|
|
|
1582
|
-
//# debugId=
|
|
1775
|
+
//# debugId=B2EFFD14F95E510364756E2164756E21
|
|
1583
1776
|
//# sourceMappingURL=index.js.map
|