@krisanalfa/bunest-adapter 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1089 @@
1
+ // @bun
2
+ var __legacyDecorateClassTS = function(decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
5
+ r = Reflect.decorate(decorators, target, key, desc);
6
+ else
7
+ for (var i = decorators.length - 1;i >= 0; i--)
8
+ if (d = decorators[i])
9
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
10
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
11
+ };
12
+ var __legacyMetadataTS = (k, v) => {
13
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
14
+ return Reflect.metadata(k, v);
15
+ };
16
+
17
+ // lib/bun.adapter.ts
18
+ import {
19
+ Logger
20
+ } from "@nestjs/common";
21
+ var {randomUUIDv7 } = globalThis.Bun;
22
+ import { AbstractHttpAdapter } from "@nestjs/core";
23
+
24
+ // lib/bun.body-parser.middleware.ts
25
+ var GET_CODE = 71;
26
+ var HEAD_CODE = 72;
27
+ var DELETE_CODE = 68;
28
+ var OPTIONS_CODE = 79;
29
+
30
+ class BunBodyParserMiddleware {
31
+ prefix;
32
+ rawBody;
33
+ prefixLen;
34
+ constructor(options) {
35
+ this.prefix = options?.prefix ?? null;
36
+ this.prefixLen = this.prefix?.length ?? 0;
37
+ this.rawBody = options?.rawBody ?? false;
38
+ }
39
+ async run(req, res, next) {
40
+ const methodFirstChar = req.method.charCodeAt(0);
41
+ if (methodFirstChar === GET_CODE || methodFirstChar === HEAD_CODE || methodFirstChar === DELETE_CODE || methodFirstChar === OPTIONS_CODE) {
42
+ next?.();
43
+ return;
44
+ }
45
+ if (this.prefix !== null) {
46
+ const pathname = req.pathname;
47
+ if (pathname.length < this.prefixLen || !pathname.startsWith(this.prefix)) {
48
+ next?.();
49
+ return;
50
+ }
51
+ }
52
+ if (this.rawBody) {
53
+ req.setRawBody(await req.arrayBuffer());
54
+ }
55
+ await this.parseRequestBody(req);
56
+ next?.();
57
+ }
58
+ async parseRequestBody(req) {
59
+ const contentType = req.headers.get("content-type");
60
+ if (!contentType) {
61
+ return;
62
+ }
63
+ if (contentType.includes("application/json")) {
64
+ req.setBody(await req.json());
65
+ return;
66
+ }
67
+ if (contentType.includes("text/") || contentType.includes("application/text")) {
68
+ req.setBody(await req.text());
69
+ return;
70
+ }
71
+ if (contentType.includes("form")) {
72
+ await this.parseFormData(req);
73
+ }
74
+ }
75
+ async parseFormData(req) {
76
+ const formData = await req.formData();
77
+ const body = Object.create(null);
78
+ let files = null;
79
+ let firstFile = null;
80
+ for (const [key, value] of formData.entries()) {
81
+ body[key] = value;
82
+ if (this.isFile(value)) {
83
+ if (firstFile === null) {
84
+ firstFile = value;
85
+ files = [value];
86
+ } else {
87
+ files?.push(value);
88
+ }
89
+ }
90
+ }
91
+ req.setBody(body);
92
+ if (firstFile !== null) {
93
+ req.setFile(firstFile);
94
+ }
95
+ if (files !== null) {
96
+ req.setFiles(files);
97
+ }
98
+ }
99
+ isFile(value) {
100
+ return typeof value === "object" && value !== null && "size" in value && "name" in value && "type" in value;
101
+ }
102
+ }
103
+
104
+ // lib/bun.cors.middleware.ts
105
+ import cors from "cors";
106
+
107
+ class BunCorsMiddleware {
108
+ options;
109
+ prefix;
110
+ constructor(options) {
111
+ this.options = options?.corsOptions;
112
+ this.prefix = options?.prefix;
113
+ }
114
+ async run(req, res, next) {
115
+ const nextFn = next;
116
+ if (this.prefix && !req.pathname.startsWith(this.prefix)) {
117
+ return nextFn?.();
118
+ }
119
+ const corsOptions = await this.resolveCorsOptions(req);
120
+ const { nodeReq, nodeRes, isEnded } = this.createNodeAdapters(req, res);
121
+ cors(corsOptions)(nodeReq, nodeRes, (err) => {
122
+ if (err)
123
+ return nextFn?.(err);
124
+ if (!isEnded())
125
+ nextFn?.();
126
+ });
127
+ }
128
+ async resolveCorsOptions(req) {
129
+ const options = this.options;
130
+ if (typeof options === "function") {
131
+ return new Promise((resolve, reject) => {
132
+ options(req, (err, opts) => {
133
+ if (err)
134
+ reject(err);
135
+ else
136
+ resolve(opts);
137
+ });
138
+ });
139
+ }
140
+ if (!options)
141
+ return;
142
+ return {
143
+ origin: options.origin,
144
+ methods: options.methods,
145
+ allowedHeaders: options.allowedHeaders,
146
+ exposedHeaders: options.exposedHeaders,
147
+ credentials: options.credentials,
148
+ maxAge: options.maxAge,
149
+ preflightContinue: options.preflightContinue,
150
+ optionsSuccessStatus: options.optionsSuccessStatus
151
+ };
152
+ }
153
+ createNodeAdapters(req, res) {
154
+ const nodeReq = {
155
+ method: req.method,
156
+ headers: req.headers,
157
+ url: req.pathname
158
+ };
159
+ const nodeRes = {
160
+ get statusCode() {
161
+ return res.getStatus();
162
+ },
163
+ set statusCode(code) {
164
+ res.setStatus(code);
165
+ },
166
+ setHeader: (key, value) => {
167
+ res.setHeader(key, value);
168
+ },
169
+ end: (data) => {
170
+ res.end(data);
171
+ },
172
+ getHeader: (name) => res.getHeader(name),
173
+ removeHeader: (name) => {
174
+ res.removeHeader(name);
175
+ }
176
+ };
177
+ return { nodeReq, nodeRes, isEnded: () => res.isEnded() };
178
+ }
179
+ }
180
+
181
+ // lib/bun.middleware-engine.ts
182
+ var EMPTY_HANDLERS = new Array(0);
183
+ var noop = () => {};
184
+
185
+ class BunMiddlewareEngine {
186
+ globalMiddlewares = [];
187
+ routeMiddleware = new Map;
188
+ routeMiddlewareByMethod = new Map;
189
+ wildcardMiddleware = new Map;
190
+ middlewareCache = new Map;
191
+ errorHandler = null;
192
+ notFoundHandler = null;
193
+ useGlobal(middleware) {
194
+ this.globalMiddlewares.push(middleware);
195
+ }
196
+ useRoute(method, path, middleware) {
197
+ const key = `${method}:${path}`;
198
+ (this.routeMiddleware.get(key) ?? this.routeMiddleware.set(key, []).get(key)).push(middleware);
199
+ (this.routeMiddlewareByMethod.get(method) ?? this.routeMiddlewareByMethod.set(method, new Map).get(method)).set(path, this.routeMiddlewareByMethod.get(method)?.get(path) ?? []).get(path).push(middleware);
200
+ }
201
+ useWildcard(method, middleware) {
202
+ (this.wildcardMiddleware.get(method) ?? this.wildcardMiddleware.set(method, []).get(method)).push(middleware);
203
+ }
204
+ useErrorHandler(handler) {
205
+ this.errorHandler = handler;
206
+ }
207
+ useNotFoundHandler(handler) {
208
+ this.notFoundHandler = handler;
209
+ }
210
+ async run(options) {
211
+ try {
212
+ const middlewares = this.getMiddlewareChain(options.method, options.path);
213
+ await this.executeChain(middlewares, options.requestHandler, options.req, options.res);
214
+ return options.res;
215
+ } catch (error) {
216
+ return this.handleError(error, options.req, options.res);
217
+ }
218
+ }
219
+ getMiddlewareChain(method, path) {
220
+ const cacheKey = `${method}:${path}`;
221
+ let cached = this.middlewareCache.get(cacheKey);
222
+ if (cached !== undefined)
223
+ return cached;
224
+ cached = this.buildMiddlewareChain(method, path, cacheKey);
225
+ this.middlewareCache.set(cacheKey, cached);
226
+ return cached;
227
+ }
228
+ buildMiddlewareChain(method, path, cacheKey) {
229
+ const global = this.globalMiddlewares;
230
+ const globalLen = global.length;
231
+ const wildcardAll = this.wildcardMiddleware.get("ALL");
232
+ const wildcardMethod = this.wildcardMiddleware.get(method);
233
+ const routeMiddleware = this.findRouteMiddleware(method, path, cacheKey);
234
+ const wildcardAllLen = wildcardAll?.length ?? 0;
235
+ const wildcardMethodLen = wildcardMethod?.length ?? 0;
236
+ const routeLen = routeMiddleware.length;
237
+ const totalLen = globalLen + wildcardAllLen + wildcardMethodLen + routeLen;
238
+ if (totalLen === 0)
239
+ return EMPTY_HANDLERS;
240
+ const chain = new Array(totalLen);
241
+ let idx = 0;
242
+ for (let i = 0;i < globalLen; i++)
243
+ chain[idx++] = global[i];
244
+ if (wildcardAll)
245
+ for (let i = 0;i < wildcardAllLen; i++)
246
+ chain[idx++] = wildcardAll[i];
247
+ if (wildcardMethod)
248
+ for (let i = 0;i < wildcardMethodLen; i++)
249
+ chain[idx++] = wildcardMethod[i];
250
+ for (let i = 0;i < routeLen; i++)
251
+ chain[idx++] = routeMiddleware[i];
252
+ return chain;
253
+ }
254
+ findRouteMiddleware(method, path, cacheKey) {
255
+ const exactMiddleware = this.routeMiddleware.get(cacheKey);
256
+ if (exactMiddleware !== undefined)
257
+ return exactMiddleware;
258
+ return this.findBestPrefixMatch(method, path);
259
+ }
260
+ findBestPrefixMatch(method, path) {
261
+ const methodMap = this.routeMiddlewareByMethod.get(method);
262
+ if (!methodMap)
263
+ return EMPTY_HANDLERS;
264
+ let bestMatch = null;
265
+ let bestMatchLength = 0;
266
+ const pathLen = path.length;
267
+ for (const [keyPath, middleware] of methodMap) {
268
+ const keyPathLen = keyPath.length;
269
+ if (keyPathLen <= bestMatchLength || middleware.length === 0)
270
+ continue;
271
+ if (path === keyPath || pathLen > keyPathLen && path.charCodeAt(keyPathLen) === 47 && path.startsWith(keyPath)) {
272
+ bestMatch = middleware;
273
+ bestMatchLength = keyPathLen;
274
+ }
275
+ }
276
+ return bestMatch ?? EMPTY_HANDLERS;
277
+ }
278
+ async executeChain(chain, requestHandler, req, res) {
279
+ const chainLength = chain.length;
280
+ let index = 0;
281
+ const next = async (err) => {
282
+ if (err)
283
+ throw err;
284
+ if (index < chainLength) {
285
+ const handler = chain[index++];
286
+ const result = handler(req, res, next);
287
+ if (result instanceof Promise)
288
+ await result;
289
+ return;
290
+ }
291
+ if (index === chainLength) {
292
+ index++;
293
+ const result = requestHandler(req, res, next);
294
+ if (result instanceof Promise)
295
+ await result;
296
+ if (index > chainLength) {
297
+ const result2 = this.notFoundHandler?.(req, res, noop);
298
+ if (result2 instanceof Promise)
299
+ await result2;
300
+ }
301
+ }
302
+ };
303
+ await next();
304
+ }
305
+ async handleError(error, req, res) {
306
+ if (this.errorHandler !== null) {
307
+ const result = this.errorHandler(error, req, res, noop);
308
+ if (result instanceof Promise)
309
+ await result;
310
+ return res;
311
+ }
312
+ throw error;
313
+ }
314
+ }
315
+
316
+ // lib/bun.request.ts
317
+ import { parse } from "qs";
318
+ var NULL_PROTO = Object.getPrototypeOf(Object.create(null));
319
+
320
+ class BunRequest {
321
+ nativeRequest;
322
+ _nativeHeaders;
323
+ _headers = null;
324
+ _hostname = null;
325
+ _pathname = null;
326
+ _query = null;
327
+ _body = null;
328
+ _rawBody = null;
329
+ _file = null;
330
+ _files = null;
331
+ _settings = null;
332
+ _url;
333
+ _parsedUrl;
334
+ method;
335
+ params;
336
+ constructor(nativeRequest) {
337
+ this.nativeRequest = nativeRequest;
338
+ this._url = nativeRequest.url;
339
+ this._parsedUrl = new URL(this._url);
340
+ this._nativeHeaders = nativeRequest.headers;
341
+ this.method = nativeRequest.method;
342
+ this.params = nativeRequest.params;
343
+ }
344
+ get url() {
345
+ return this._url;
346
+ }
347
+ get pathname() {
348
+ return this._pathname ??= this._parsedUrl.pathname;
349
+ }
350
+ get hostname() {
351
+ return this._hostname ??= this.headers.get("x-forwarded-host") ?? this._parsedUrl.hostname;
352
+ }
353
+ get headers() {
354
+ if (this._headers !== null)
355
+ return this._headers;
356
+ const native = this._nativeHeaders;
357
+ const proxy = Object.create(NULL_PROTO);
358
+ native.forEach((value, key) => {
359
+ proxy[key.toLowerCase()] = value;
360
+ });
361
+ proxy.get = (key) => native.get(key);
362
+ return this._headers = proxy;
363
+ }
364
+ get query() {
365
+ return this._query ??= parse(this._parsedUrl.searchParams.toString());
366
+ }
367
+ get body() {
368
+ return this._body;
369
+ }
370
+ setBody(body) {
371
+ this._body = body;
372
+ }
373
+ get rawBody() {
374
+ return this._rawBody;
375
+ }
376
+ setRawBody(rawBody) {
377
+ this._rawBody = rawBody;
378
+ }
379
+ get file() {
380
+ return this._file;
381
+ }
382
+ setFile(file) {
383
+ this._file = file;
384
+ }
385
+ get files() {
386
+ return this._files;
387
+ }
388
+ setFiles(files) {
389
+ this._files = files;
390
+ }
391
+ get(key) {
392
+ return this._settings?.get(key);
393
+ }
394
+ set(key, value) {
395
+ (this._settings ??= new Map).set(key, value);
396
+ }
397
+ get signal() {
398
+ return this.nativeRequest.signal;
399
+ }
400
+ get cookies() {
401
+ return this.nativeRequest.cookies;
402
+ }
403
+ json() {
404
+ return this.nativeRequest.json();
405
+ }
406
+ text() {
407
+ return this.nativeRequest.text();
408
+ }
409
+ formData() {
410
+ return this.nativeRequest.formData();
411
+ }
412
+ arrayBuffer() {
413
+ return this.nativeRequest.arrayBuffer();
414
+ }
415
+ blob() {
416
+ return this.nativeRequest.blob();
417
+ }
418
+ bytes() {
419
+ return this.nativeRequest.bytes();
420
+ }
421
+ clone() {
422
+ const cloned = new BunRequest(this.nativeRequest.clone());
423
+ cloned._pathname = this._pathname;
424
+ cloned._body = this._body;
425
+ cloned._rawBody = this._rawBody;
426
+ cloned._file = this._file;
427
+ cloned._files = this._files;
428
+ cloned._headers = this._headers;
429
+ cloned._query = this._query;
430
+ cloned._settings = this._settings;
431
+ return cloned;
432
+ }
433
+ }
434
+
435
+ // lib/bun.response.ts
436
+ var {CookieMap } = globalThis.Bun;
437
+ import { StreamableFile } from "@nestjs/common";
438
+ var JSON_CONTENT_TYPE = "application/json";
439
+
440
+ class BunResponse {
441
+ resolve;
442
+ response;
443
+ cookieMap = new CookieMap;
444
+ _headers = null;
445
+ statusCode = 200;
446
+ ended = false;
447
+ _cookieHeaderCache = null;
448
+ constructor() {
449
+ this.response = new Promise((r) => {
450
+ this.resolve = r;
451
+ });
452
+ }
453
+ get headersMap() {
454
+ return this._headers ??= new Map;
455
+ }
456
+ cookie(...args) {
457
+ this._cookieHeaderCache = null;
458
+ if (args.length === 1) {
459
+ this.cookieMap.set(args[0]);
460
+ } else {
461
+ this.cookieMap.set(args[0], args[1]);
462
+ }
463
+ }
464
+ deleteCookie(optionsOrName, options) {
465
+ if (typeof optionsOrName === "string") {
466
+ this.cookieMap.delete(optionsOrName, options);
467
+ } else {
468
+ this.cookieMap.delete(optionsOrName);
469
+ }
470
+ }
471
+ redirect(url, statusCode = 302) {
472
+ if (this.ended)
473
+ return;
474
+ this.ended = true;
475
+ this.resolve(Response.redirect(url, statusCode));
476
+ }
477
+ end(body) {
478
+ if (this.ended)
479
+ return;
480
+ this.ended = true;
481
+ this._cookieHeaderCache ??= this.cookieMap.toSetCookieHeaders().join("; ");
482
+ if (this._cookieHeaderCache.length > 0) {
483
+ this.setHeader("set-cookie", this._cookieHeaderCache);
484
+ }
485
+ if (body !== null && typeof body === "object") {
486
+ if (body instanceof Uint8Array || body instanceof Blob) {
487
+ this.resolve(this.createResponse(body));
488
+ return;
489
+ }
490
+ if (body instanceof StreamableFile) {
491
+ this.resolve(this.buildStreamableResponse(body));
492
+ return;
493
+ }
494
+ this.resolve(this.buildJsonResponse(body));
495
+ return;
496
+ }
497
+ if (!body) {
498
+ this.resolve(this.createResponse(null));
499
+ return;
500
+ }
501
+ this.resolve(this.buildJsonResponse(body));
502
+ }
503
+ setHeader(name, value) {
504
+ this.headersMap.set(name.toLowerCase(), value);
505
+ }
506
+ getHeader(name) {
507
+ return this._headers?.get(name.toLowerCase()) ?? null;
508
+ }
509
+ appendHeader(name, value) {
510
+ const key = name.toLowerCase();
511
+ const headers = this.headersMap;
512
+ const existing = headers.get(key);
513
+ headers.set(key, existing ? `${existing}, ${value}` : value);
514
+ }
515
+ removeHeader(name) {
516
+ this._headers?.delete(name.toLowerCase());
517
+ }
518
+ setStatus(code) {
519
+ this.statusCode = code;
520
+ }
521
+ getStatus() {
522
+ return this.statusCode;
523
+ }
524
+ res() {
525
+ return this.response;
526
+ }
527
+ isEnded() {
528
+ return this.ended;
529
+ }
530
+ buildStreamableResponse(body) {
531
+ const streamHeaders = body.getHeaders();
532
+ const headers = this.headersMap;
533
+ if (streamHeaders.type && !headers.has("content-type")) {
534
+ headers.set("content-type", streamHeaders.type);
535
+ }
536
+ if (streamHeaders.disposition && !headers.has("content-disposition")) {
537
+ headers.set("content-disposition", streamHeaders.disposition);
538
+ }
539
+ if (streamHeaders.length !== undefined && !headers.has("content-length")) {
540
+ headers.set("content-length", String(streamHeaders.length));
541
+ }
542
+ return this.createResponse(body.getStream());
543
+ }
544
+ buildJsonResponse(body) {
545
+ const headers = this._headers;
546
+ if (headers === null || headers.size === 0) {
547
+ return Response.json(body, { status: this.statusCode });
548
+ }
549
+ if (!headers.has("content-type")) {
550
+ headers.set("content-type", JSON_CONTENT_TYPE);
551
+ }
552
+ return Response.json(body, {
553
+ status: this.statusCode,
554
+ headers: Object.fromEntries(headers)
555
+ });
556
+ }
557
+ createResponse(body) {
558
+ const headers = this._headers;
559
+ if (headers === null || headers.size === 0) {
560
+ return new Response(body, { status: this.statusCode });
561
+ }
562
+ return new Response(body, {
563
+ status: this.statusCode,
564
+ headers: Object.fromEntries(headers)
565
+ });
566
+ }
567
+ }
568
+
569
+ // lib/bun.version-filter.middleware.ts
570
+ import { VERSION_NEUTRAL, VersioningType } from "@nestjs/common";
571
+ async function executeHandler(handler, req, res, next) {
572
+ const result = handler(req, res, next);
573
+ return result instanceof Promise ? await result : result;
574
+ }
575
+ function callNext(next) {
576
+ return next();
577
+ }
578
+
579
+ class BunVersionFilterMiddleware {
580
+ static createFilter(handler, version, versioningOptions) {
581
+ if (version === VERSION_NEUTRAL || versioningOptions.type === VersioningType.URI) {
582
+ return handler;
583
+ }
584
+ switch (versioningOptions.type) {
585
+ case VersioningType.CUSTOM:
586
+ return this.createCustomVersionFilter(handler, version, versioningOptions);
587
+ case VersioningType.MEDIA_TYPE:
588
+ return this.createMediaTypeVersionFilter(handler, version, versioningOptions);
589
+ case VersioningType.HEADER:
590
+ return this.createHeaderVersionFilter(handler, version, versioningOptions);
591
+ default:
592
+ throw new Error("Unsupported versioning options");
593
+ }
594
+ }
595
+ static createVersionMatcher(handlerVersion) {
596
+ if (Array.isArray(handlerVersion)) {
597
+ const versionSet = new Set(handlerVersion);
598
+ return (requestedVersion) => requestedVersion !== undefined && versionSet.has(requestedVersion);
599
+ }
600
+ return (requestedVersion) => requestedVersion == handlerVersion;
601
+ }
602
+ static computeAcceptsNeutral(version) {
603
+ return version === VERSION_NEUTRAL || Array.isArray(version) && version.includes(VERSION_NEUTRAL);
604
+ }
605
+ static getHeader(req, name) {
606
+ return req.headers.get(name) ?? undefined;
607
+ }
608
+ static createCustomVersionFilter(handler, version, options) {
609
+ const isVersionArray = Array.isArray(version);
610
+ const versionSet = isVersionArray ? new Set(version) : null;
611
+ const singleVersion = isVersionArray ? null : version;
612
+ return async (req, res, next) => {
613
+ const extracted = options.extractor(req);
614
+ const reqMeta = req;
615
+ reqMeta._customVersioningPhase ??= "discovery";
616
+ reqMeta._customVersioningCandidates ??= new Map;
617
+ const isDiscovery = reqMeta._customVersioningPhase === "discovery";
618
+ const extractedIsArray = Array.isArray(extracted);
619
+ const extractedVersions = extractedIsArray ? extracted : [extracted];
620
+ let match;
621
+ let matchIndex = -1;
622
+ for (let i = 0;i < extractedVersions.length; i++) {
623
+ const extractedVersion = extractedVersions[i];
624
+ if (versionSet ? versionSet.has(extractedVersion) : extractedVersion === singleVersion) {
625
+ match = extractedVersion;
626
+ matchIndex = i;
627
+ break;
628
+ }
629
+ }
630
+ if (match) {
631
+ if (isDiscovery) {
632
+ reqMeta._customVersioningCandidates.set(match, {
633
+ priority: matchIndex,
634
+ execute: () => handler(req, res, next)
635
+ });
636
+ return callNext(next);
637
+ }
638
+ if (reqMeta._customVersioningBestCandidate === match) {
639
+ return executeHandler(handler, req, res, next);
640
+ }
641
+ }
642
+ return callNext(next);
643
+ };
644
+ }
645
+ static createMediaTypeVersionFilter(handler, version, options) {
646
+ const acceptsNeutral = this.computeAcceptsNeutral(version);
647
+ const versionMatches = this.createVersionMatcher(version);
648
+ const keyLength = options.key.length;
649
+ return async (req, res, next) => {
650
+ const acceptHeader = this.getHeader(req, "accept");
651
+ if (acceptHeader) {
652
+ const semiIndex = acceptHeader.indexOf(";");
653
+ if (semiIndex !== -1) {
654
+ const versionPart = acceptHeader.substring(semiIndex + 1).trim();
655
+ const keyIndex = versionPart.indexOf(options.key);
656
+ if (keyIndex !== -1) {
657
+ const headerVersion = versionPart.substring(keyIndex + keyLength);
658
+ if (versionMatches(headerVersion)) {
659
+ return executeHandler(handler, req, res, next);
660
+ }
661
+ return callNext(next);
662
+ }
663
+ }
664
+ }
665
+ if (acceptsNeutral) {
666
+ return executeHandler(handler, req, res, next);
667
+ }
668
+ return callNext(next);
669
+ };
670
+ }
671
+ static createHeaderVersionFilter(handler, version, options) {
672
+ const acceptsNeutral = this.computeAcceptsNeutral(version);
673
+ const versionMatches = this.createVersionMatcher(version);
674
+ const defaultVersion = options.defaultVersion;
675
+ const hasNeutralDefault = defaultVersion === VERSION_NEUTRAL;
676
+ const resolvedDefault = this.resolveDefaultVersion(version, defaultVersion);
677
+ const headerName = options.header;
678
+ return async (req, res, next) => {
679
+ let headerVersion = this.getHeader(req, headerName)?.trim();
680
+ if (headerVersion === "")
681
+ headerVersion = undefined;
682
+ headerVersion ??= resolvedDefault;
683
+ if (!headerVersion) {
684
+ if ((hasNeutralDefault || !defaultVersion) && acceptsNeutral) {
685
+ return executeHandler(handler, req, res, next);
686
+ }
687
+ return callNext(next);
688
+ }
689
+ if (versionMatches(headerVersion)) {
690
+ return executeHandler(handler, req, res, next);
691
+ }
692
+ return callNext(next);
693
+ };
694
+ }
695
+ static resolveDefaultVersion(handlerVersion, defaultVersion) {
696
+ if (defaultVersion === undefined || defaultVersion === VERSION_NEUTRAL) {
697
+ return;
698
+ }
699
+ const handlerVersions = Array.isArray(handlerVersion) ? handlerVersion : [handlerVersion];
700
+ if (typeof defaultVersion === "string") {
701
+ return handlerVersions.includes(defaultVersion) ? defaultVersion : undefined;
702
+ }
703
+ if (Array.isArray(defaultVersion)) {
704
+ return defaultVersion.find((dv) => typeof dv === "string" && handlerVersions.includes(dv));
705
+ }
706
+ return;
707
+ }
708
+ static selectBestCustomVersionCandidate(req) {
709
+ const { _customVersioningPhase: phase, _customVersioningCandidates: candidates } = req;
710
+ if (phase !== "discovery" || !candidates?.size)
711
+ return null;
712
+ let bestVersion = null;
713
+ let bestPriority = Infinity;
714
+ for (const [version, { priority }] of candidates) {
715
+ if (priority < bestPriority) {
716
+ bestPriority = priority;
717
+ bestVersion = version;
718
+ }
719
+ }
720
+ return bestVersion;
721
+ }
722
+ static setCustomVersioningExecutionPhase(req, bestVersion) {
723
+ const reqMeta = req;
724
+ reqMeta._customVersioningPhase = "execution";
725
+ reqMeta._customVersioningBestCandidate = bestVersion;
726
+ }
727
+ static hasCustomVersioningCandidates(req) {
728
+ const { _customVersioningPhase: phase, _customVersioningCandidates: candidates } = req;
729
+ return phase === "discovery" && !!candidates?.size;
730
+ }
731
+ }
732
+
733
+ // lib/bun.adapter.ts
734
+ var REQUEST_METHOD_STRINGS = [
735
+ "GET",
736
+ "POST",
737
+ "PUT",
738
+ "DELETE",
739
+ "PATCH",
740
+ "ALL",
741
+ "OPTIONS",
742
+ "HEAD",
743
+ "SEARCH",
744
+ "PROPFIND",
745
+ "PROPPATCH",
746
+ "MKCOL",
747
+ "COPY",
748
+ "MOVE",
749
+ "LOCK",
750
+ "UNLOCK"
751
+ ];
752
+
753
+ class BunAdapter extends AbstractHttpAdapter {
754
+ bunServeOptions;
755
+ logger = new Logger("BunAdapter", { timestamp: true });
756
+ middlewareEngine = new BunMiddlewareEngine;
757
+ useVersioning = false;
758
+ routes = Object.create(null);
759
+ routeHandlers = new Map;
760
+ notFoundHandler = (req, res) => {
761
+ res.setStatus(404);
762
+ res.end({ message: "Not Found" });
763
+ };
764
+ constructor(bunServeOptions = {
765
+ development: false,
766
+ id: randomUUIDv7()
767
+ }) {
768
+ super();
769
+ this.bunServeOptions = bunServeOptions;
770
+ }
771
+ use(middleware) {
772
+ this.middlewareEngine.useGlobal(middleware);
773
+ }
774
+ get(pathOrHandler, maybeHandler) {
775
+ const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
776
+ this.delegateRouteHandler("GET", path, handler);
777
+ }
778
+ post(pathOrHandler, maybeHandler) {
779
+ const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
780
+ this.delegateRouteHandler("POST", path, handler);
781
+ }
782
+ put(pathOrHandler, maybeHandler) {
783
+ const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
784
+ this.delegateRouteHandler("PUT", path, handler);
785
+ }
786
+ patch(pathOrHandler, maybeHandler) {
787
+ const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
788
+ this.delegateRouteHandler("PATCH", path, handler);
789
+ }
790
+ delete(pathOrHandler, maybeHandler) {
791
+ const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
792
+ this.delegateRouteHandler("DELETE", path, handler);
793
+ }
794
+ head(pathOrHandler, maybeHandler) {
795
+ const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
796
+ this.delegateRouteHandler("HEAD", path, handler);
797
+ }
798
+ options(pathOrHandler, maybeHandler) {
799
+ const { path, handler } = this.parseRouteHandler(pathOrHandler, maybeHandler);
800
+ this.delegateRouteHandler("OPTIONS", path, handler);
801
+ }
802
+ all(pathOrHandler, maybeHandler) {
803
+ throw new Error("Not supported.");
804
+ }
805
+ propfind(pathOrHandler, maybeHandler) {
806
+ throw new Error("Not supported.");
807
+ }
808
+ proppatch(pathOrHandler, maybeHandler) {
809
+ throw new Error("Not supported.");
810
+ }
811
+ mkcol(pathOrHandler, maybeHandler) {
812
+ throw new Error("Not supported.");
813
+ }
814
+ copy(pathOrHandler, maybeHandler) {
815
+ throw new Error("Not supported.");
816
+ }
817
+ move(pathOrHandler, maybeHandler) {
818
+ throw new Error("Not supported.");
819
+ }
820
+ lock(pathOrHandler, maybeHandler) {
821
+ throw new Error("Not supported.");
822
+ }
823
+ unlock(pathOrHandler, maybeHandler) {
824
+ throw new Error("Not supported.");
825
+ }
826
+ search(pathOrHandler, maybeHandler) {
827
+ throw new Error("Not supported.");
828
+ }
829
+ useStaticAssets(...args) {
830
+ throw new Error("Not supported.");
831
+ }
832
+ setViewEngine(engine) {
833
+ throw new Error("Not supported.");
834
+ }
835
+ render(response, view, options) {
836
+ throw new Error("Not supported.");
837
+ }
838
+ async close() {
839
+ await this.httpServer.stop();
840
+ }
841
+ initHttpServer(options) {
842
+ this.setHttpServer({
843
+ once: () => {},
844
+ address: () => ({ address: "0.0.0.0", port: 0 }),
845
+ removeListener: () => {},
846
+ stop: () => {}
847
+ });
848
+ if (options.httpsOptions) {
849
+ this.bunServeOptions.tls = {
850
+ key: options.httpsOptions.key,
851
+ cert: options.httpsOptions.cert,
852
+ passphrase: options.httpsOptions.passphrase,
853
+ ca: options.httpsOptions.ca,
854
+ ciphers: options.httpsOptions.ciphers,
855
+ secureOptions: options.httpsOptions.secureOptions,
856
+ rejectUnauthorized: options.httpsOptions.rejectUnauthorized,
857
+ requestCert: options.httpsOptions.requestCert
858
+ };
859
+ }
860
+ }
861
+ getRequestHostname(request) {
862
+ return request.hostname;
863
+ }
864
+ getRequestMethod(request) {
865
+ return request.method;
866
+ }
867
+ getRequestUrl(request) {
868
+ return request.pathname;
869
+ }
870
+ status(response, statusCode) {
871
+ response.setStatus(statusCode);
872
+ }
873
+ reply(response, body, statusCode) {
874
+ if (statusCode) {
875
+ response.setStatus(statusCode);
876
+ }
877
+ response.end(body);
878
+ }
879
+ end(response, message) {
880
+ response.end(message);
881
+ }
882
+ redirect(response, statusCode, url) {
883
+ response.redirect(url, statusCode);
884
+ }
885
+ setErrorHandler(handler, prefix) {
886
+ this.middlewareEngine.useErrorHandler(handler);
887
+ }
888
+ setNotFoundHandler(handler, prefix) {
889
+ this.notFoundHandler = handler;
890
+ this.middlewareEngine.useNotFoundHandler(handler);
891
+ }
892
+ isHeadersSent(response) {
893
+ return response.isEnded();
894
+ }
895
+ getHeader(response, name) {
896
+ return response.getHeader(name);
897
+ }
898
+ setHeader(response, name, value) {
899
+ response.setHeader(name, value);
900
+ }
901
+ appendHeader(response, name, value) {
902
+ response.appendHeader(name, value);
903
+ }
904
+ registerParserMiddleware(prefix, rawBody) {
905
+ this.logger.log(`Registering Body Parser Middleware with prefix: ${prefix || "/"} and rawBody: ${rawBody ? "true" : "false"}`);
906
+ const bodyParser = new BunBodyParserMiddleware({ prefix, rawBody });
907
+ this.middlewareEngine.useGlobal(bodyParser.run.bind(bodyParser));
908
+ }
909
+ enableCors(options, prefix) {
910
+ this.logger.log(`Enabling CORS Middleware with prefix: ${prefix ?? "/"}`);
911
+ const corsMiddleware = new BunCorsMiddleware({ corsOptions: options, prefix });
912
+ this.middlewareEngine.useGlobal(corsMiddleware.run.bind(corsMiddleware));
913
+ }
914
+ createMiddlewareFactory(requestMethod) {
915
+ return (path, callback) => {
916
+ const methodName = this.mapRequestMethodToString(requestMethod);
917
+ if (path === "*" || path === "/*") {
918
+ this.middlewareEngine.useWildcard(methodName, callback);
919
+ return;
920
+ }
921
+ const normalizedPath = path === "/" ? path : path.replace(/\/$/, "");
922
+ this.middlewareEngine.useRoute(methodName, normalizedPath, callback);
923
+ };
924
+ }
925
+ getType() {
926
+ return "bun";
927
+ }
928
+ applyVersionFilter(handler, version, versioningOptions) {
929
+ this.logger.log(`Applying Version Filter Middleware for version: ${JSON.stringify(version)}`);
930
+ this.useVersioning = true;
931
+ return BunVersionFilterMiddleware.createFilter(handler, version, versioningOptions);
932
+ }
933
+ listen(port, hostnameOrCallback, maybeCallback) {
934
+ const hostname = typeof hostnameOrCallback === "string" ? hostnameOrCallback : "localhost";
935
+ const callback = typeof hostnameOrCallback === "function" ? hostnameOrCallback : maybeCallback;
936
+ const middlewareEngine = this.middlewareEngine;
937
+ const notFoundHandler = this.notFoundHandler;
938
+ const fetch = async (request) => {
939
+ const bunRequest = new BunRequest(request);
940
+ const bunResponse = new BunResponse;
941
+ await middlewareEngine.run({
942
+ req: bunRequest,
943
+ res: bunResponse,
944
+ method: bunRequest.method,
945
+ path: bunRequest.pathname,
946
+ requestHandler: notFoundHandler
947
+ });
948
+ return bunResponse.res();
949
+ };
950
+ const omit = (obj, ...keys) => {
951
+ const result = { ...obj };
952
+ for (const key of keys) {
953
+ Reflect.deleteProperty(result, key);
954
+ }
955
+ return result;
956
+ };
957
+ const server = typeof port === "number" || !isNaN(Number(port)) ? Bun.serve({
958
+ ...this.bunServeOptions,
959
+ hostname,
960
+ port,
961
+ routes: this.routes,
962
+ fetch
963
+ }) : Bun.serve({
964
+ ...omit(this.bunServeOptions, "idleTimeout"),
965
+ unix: port,
966
+ routes: this.routes,
967
+ fetch
968
+ });
969
+ if (typeof port === "string" && isNaN(Number(port))) {
970
+ this.logger.log(`Bun server listening on unix socket: ${port}`);
971
+ }
972
+ callback?.();
973
+ Object.defineProperty(server, "address", {
974
+ configurable: true,
975
+ enumerable: true,
976
+ get: () => ({ address: server.hostname, port: server.port })
977
+ });
978
+ this.setHttpServer(server);
979
+ }
980
+ delegateRouteHandler(method, path, handler) {
981
+ if (!(path in this.routes)) {
982
+ this.routes[path] = Object.create(null);
983
+ }
984
+ const requestHandler = !this.useVersioning ? handler : this.createChainedHandlerForVersioningResolution(this.createVersioningHandlers(method, path, handler), this.notFoundHandler);
985
+ this.routes[path][method] = async (request) => {
986
+ const bunRequest = new BunRequest(request);
987
+ const bunResponse = new BunResponse;
988
+ await this.middlewareEngine.run({
989
+ req: bunRequest,
990
+ res: bunResponse,
991
+ method,
992
+ path,
993
+ requestHandler
994
+ });
995
+ return bunResponse.res();
996
+ };
997
+ }
998
+ createVersioningHandlers(method, path, handler) {
999
+ const routeKey = `${method}:${path}`;
1000
+ let versioningHandlers = this.routeHandlers.get(routeKey);
1001
+ if (!versioningHandlers) {
1002
+ versioningHandlers = [];
1003
+ this.routeHandlers.set(routeKey, versioningHandlers);
1004
+ }
1005
+ versioningHandlers.push(handler);
1006
+ return versioningHandlers;
1007
+ }
1008
+ async executeHandlerChain(handlers, req, res) {
1009
+ const handlersLength = handlers.length;
1010
+ let index = 0;
1011
+ let shouldContinue = true;
1012
+ while (shouldContinue && index < handlersLength && !res.isEnded()) {
1013
+ shouldContinue = false;
1014
+ const currentIndex = index++;
1015
+ const result = handlers[currentIndex](req, res, () => {
1016
+ shouldContinue = true;
1017
+ });
1018
+ if (result instanceof Promise)
1019
+ await result;
1020
+ }
1021
+ }
1022
+ createChainedHandlerForVersioningResolution(handlers, notFoundHandler) {
1023
+ return async (req, res, next) => {
1024
+ await this.executeHandlerChain(handlers, req, res);
1025
+ if (!res.isEnded() && BunVersionFilterMiddleware.hasCustomVersioningCandidates(req)) {
1026
+ const bestVersion = BunVersionFilterMiddleware.selectBestCustomVersionCandidate(req);
1027
+ if (bestVersion) {
1028
+ BunVersionFilterMiddleware.setCustomVersioningExecutionPhase(req, bestVersion);
1029
+ await this.executeHandlerChain(handlers, req, res);
1030
+ }
1031
+ }
1032
+ if (!res.isEnded()) {
1033
+ notFoundHandler(req, res, next);
1034
+ }
1035
+ };
1036
+ }
1037
+ mapRequestMethodToString(requestMethod) {
1038
+ return REQUEST_METHOD_STRINGS[requestMethod] ?? "ALL";
1039
+ }
1040
+ parseRouteHandler(pathOrHandler, maybeHandler) {
1041
+ const path = typeof pathOrHandler === "string" ? pathOrHandler : "/";
1042
+ const handler = typeof pathOrHandler === "function" ? pathOrHandler : maybeHandler;
1043
+ return { path, handler };
1044
+ }
1045
+ }
1046
+ // lib/bun.file.interceptor.ts
1047
+ import { Injectable } from "@nestjs/common";
1048
+ import { basename, join } from "path";
1049
+ import { HttpAdapterHost } from "@nestjs/core";
1050
+ var {randomUUIDv7: randomUUIDv72 } = globalThis.Bun;
1051
+ import { tmpdir } from "os";
1052
+ class BunFileInterceptor {
1053
+ adapter;
1054
+ uploadDir = Bun.env.BUN_UPLOAD_DIR;
1055
+ constructor(adapter) {
1056
+ this.adapter = adapter;
1057
+ const httpAdapter = this.adapter.httpAdapter;
1058
+ this.uploadDir ??= join(tmpdir(), "uploads", httpAdapter.getHttpServer().id, randomUUIDv72());
1059
+ }
1060
+ async intercept(context, next) {
1061
+ const request = context.switchToHttp().getRequest();
1062
+ if (!request.files?.length) {
1063
+ return next.handle();
1064
+ }
1065
+ const files = await Promise.all(request.files.map(async (file) => {
1066
+ const destPath = join(this.uploadDir, basename(file.name));
1067
+ await Bun.write(destPath, file);
1068
+ return Bun.file(destPath);
1069
+ }));
1070
+ request.setFile(files[0]);
1071
+ request.setFiles(files);
1072
+ return next.handle();
1073
+ }
1074
+ }
1075
+ BunFileInterceptor = __legacyDecorateClassTS([
1076
+ Injectable(),
1077
+ __legacyMetadataTS("design:paramtypes", [
1078
+ typeof HttpAdapterHost === "undefined" ? Object : HttpAdapterHost
1079
+ ])
1080
+ ], BunFileInterceptor);
1081
+ export {
1082
+ BunResponse,
1083
+ BunRequest,
1084
+ BunFileInterceptor,
1085
+ BunAdapter
1086
+ };
1087
+
1088
+ //# debugId=E15070B5DB09928264756E2164756E21
1089
+ //# sourceMappingURL=index.js.map