@pegasusheavy/nestjs-platform-deno 0.1.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/dist/index.js ADDED
@@ -0,0 +1,1673 @@
1
+ // src/adapters/deno-adapter.ts
2
+ import { AbstractHttpAdapter } from "@nestjs/core";
3
+ import { HttpStatus } from "@nestjs/common";
4
+
5
+ // src/compat/express-compat.ts
6
+ var STATUS_MESSAGES = {
7
+ 100: "Continue",
8
+ 101: "Switching Protocols",
9
+ 102: "Processing",
10
+ 200: "OK",
11
+ 201: "Created",
12
+ 202: "Accepted",
13
+ 204: "No Content",
14
+ 206: "Partial Content",
15
+ 301: "Moved Permanently",
16
+ 302: "Found",
17
+ 303: "See Other",
18
+ 304: "Not Modified",
19
+ 307: "Temporary Redirect",
20
+ 308: "Permanent Redirect",
21
+ 400: "Bad Request",
22
+ 401: "Unauthorized",
23
+ 403: "Forbidden",
24
+ 404: "Not Found",
25
+ 405: "Method Not Allowed",
26
+ 406: "Not Acceptable",
27
+ 408: "Request Timeout",
28
+ 409: "Conflict",
29
+ 410: "Gone",
30
+ 413: "Payload Too Large",
31
+ 415: "Unsupported Media Type",
32
+ 422: "Unprocessable Entity",
33
+ 429: "Too Many Requests",
34
+ 500: "Internal Server Error",
35
+ 501: "Not Implemented",
36
+ 502: "Bad Gateway",
37
+ 503: "Service Unavailable",
38
+ 504: "Gateway Timeout"
39
+ };
40
+ function headersToObject(headers) {
41
+ const result = {};
42
+ headers.forEach((value, key) => {
43
+ const existing = result[key.toLowerCase()];
44
+ if (existing) {
45
+ if (Array.isArray(existing)) {
46
+ existing.push(value);
47
+ } else {
48
+ result[key.toLowerCase()] = [existing, value];
49
+ }
50
+ } else {
51
+ result[key.toLowerCase()] = value;
52
+ }
53
+ });
54
+ return result;
55
+ }
56
+ function parseAccept(acceptHeader, types) {
57
+ if (!acceptHeader || types.length === 0) return false;
58
+ const accepts = acceptHeader.split(",").map((part) => {
59
+ const [type, ...params] = part.trim().split(";");
60
+ let q = 1;
61
+ params.forEach((p) => {
62
+ const [key, value] = p.trim().split("=");
63
+ if (key === "q") q = parseFloat(value) || 1;
64
+ });
65
+ return { type: type.trim(), q };
66
+ }).sort((a, b) => b.q - a.q);
67
+ for (const accept of accepts) {
68
+ for (const type of types) {
69
+ if (accept.type === "*/*" || accept.type === type || accept.type.endsWith("/*") && type.startsWith(accept.type.slice(0, -1))) {
70
+ return type;
71
+ }
72
+ }
73
+ }
74
+ return false;
75
+ }
76
+ function serializeCookie(name, value, options = {}) {
77
+ let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
78
+ if (options.maxAge !== void 0) {
79
+ cookie += `; Max-Age=${options.maxAge}`;
80
+ }
81
+ if (options.domain) {
82
+ cookie += `; Domain=${options.domain}`;
83
+ }
84
+ if (options.path) {
85
+ cookie += `; Path=${options.path}`;
86
+ } else {
87
+ cookie += "; Path=/";
88
+ }
89
+ if (options.expires) {
90
+ cookie += `; Expires=${options.expires.toUTCString()}`;
91
+ }
92
+ if (options.httpOnly) {
93
+ cookie += "; HttpOnly";
94
+ }
95
+ if (options.secure) {
96
+ cookie += "; Secure";
97
+ }
98
+ if (options.sameSite) {
99
+ if (options.sameSite === true) {
100
+ cookie += "; SameSite=Strict";
101
+ } else {
102
+ cookie += `; SameSite=${options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)}`;
103
+ }
104
+ }
105
+ return cookie;
106
+ }
107
+ function createExpressRequest(denoReq) {
108
+ const headersObj = headersToObject(denoReq.headers);
109
+ const cookieHeader = denoReq.headers.get("cookie") || "";
110
+ const cookies = {};
111
+ cookieHeader.split(";").forEach((cookie) => {
112
+ const [name, ...valueParts] = cookie.trim().split("=");
113
+ if (name) {
114
+ cookies[decodeURIComponent(name.trim())] = decodeURIComponent(valueParts.join("="));
115
+ }
116
+ });
117
+ const req = {
118
+ // Core properties
119
+ method: denoReq.method,
120
+ url: denoReq.originalUrl || denoReq.path || "/",
121
+ originalUrl: denoReq.originalUrl || denoReq.path || "/",
122
+ baseUrl: denoReq.baseUrl || "",
123
+ path: denoReq.path || "/",
124
+ hostname: denoReq.hostname || "",
125
+ ip: denoReq.ip,
126
+ protocol: denoReq.protocol || "http",
127
+ secure: denoReq.secure || false,
128
+ headers: headersObj,
129
+ // Parsed data
130
+ params: denoReq.params,
131
+ query: denoReq.query,
132
+ body: denoReq.body,
133
+ // Raw access
134
+ raw: denoReq.raw,
135
+ // Cookies
136
+ cookies,
137
+ signedCookies: {},
138
+ // Computed properties
139
+ xhr: denoReq.headers.get("x-requested-with")?.toLowerCase() === "xmlhttprequest",
140
+ subdomains: denoReq.hostname?.split(".").slice(0, -2).reverse() || [],
141
+ // Methods
142
+ get(name) {
143
+ const key = name.toLowerCase();
144
+ const value = headersObj[key];
145
+ return Array.isArray(value) ? value[0] : value;
146
+ },
147
+ header(name) {
148
+ return this.get(name);
149
+ },
150
+ is(type) {
151
+ const contentType = denoReq.headers.get("content-type");
152
+ if (!contentType) return null;
153
+ const types = Array.isArray(type) ? type : [type];
154
+ for (const t of types) {
155
+ if (contentType.includes(t) || contentType.includes(t.replace("/", ""))) {
156
+ return t;
157
+ }
158
+ }
159
+ return false;
160
+ },
161
+ accepts(...types) {
162
+ return parseAccept(denoReq.headers.get("accept") || void 0, types);
163
+ },
164
+ acceptsEncodings(...encodings) {
165
+ return parseAccept(denoReq.headers.get("accept-encoding") || void 0, encodings);
166
+ },
167
+ acceptsCharsets(...charsets) {
168
+ return parseAccept(denoReq.headers.get("accept-charset") || void 0, charsets);
169
+ },
170
+ acceptsLanguages(...langs) {
171
+ return parseAccept(denoReq.headers.get("accept-language") || void 0, langs);
172
+ }
173
+ };
174
+ const modifiedSince = denoReq.headers.get("if-modified-since");
175
+ const noneMatch = denoReq.headers.get("if-none-match");
176
+ req.fresh = !!(modifiedSince || noneMatch);
177
+ req.stale = !req.fresh;
178
+ return req;
179
+ }
180
+ function createExpressResponse(denoRes) {
181
+ let statusMessage = "OK";
182
+ const cookies = [];
183
+ const res = {
184
+ // Properties
185
+ get statusCode() {
186
+ return denoRes.statusCode;
187
+ },
188
+ set statusCode(code) {
189
+ denoRes.statusCode = code;
190
+ statusMessage = STATUS_MESSAGES[code] || "Unknown";
191
+ },
192
+ get statusMessage() {
193
+ return statusMessage;
194
+ },
195
+ set statusMessage(msg) {
196
+ statusMessage = msg;
197
+ },
198
+ get headersSent() {
199
+ return denoRes.headersSent;
200
+ },
201
+ // Status methods
202
+ status(code) {
203
+ denoRes.status(code);
204
+ statusMessage = STATUS_MESSAGES[code] || "Unknown";
205
+ return this;
206
+ },
207
+ sendStatus(code) {
208
+ this.status(code);
209
+ denoRes.send(STATUS_MESSAGES[code] || String(code));
210
+ return this;
211
+ },
212
+ // Header methods
213
+ set(field, value) {
214
+ if (typeof field === "object") {
215
+ Object.entries(field).forEach(([key, val]) => {
216
+ if (Array.isArray(val)) {
217
+ val.forEach((v) => denoRes.headers.append(key, v));
218
+ } else {
219
+ denoRes.setHeader(key, val);
220
+ }
221
+ });
222
+ } else if (value !== void 0) {
223
+ if (Array.isArray(value)) {
224
+ value.forEach((v) => denoRes.headers.append(field, v));
225
+ } else {
226
+ denoRes.setHeader(field, value);
227
+ }
228
+ }
229
+ return this;
230
+ },
231
+ header(field, value) {
232
+ if (value === void 0) {
233
+ return denoRes.getHeader(field) || void 0;
234
+ }
235
+ return this.set(field, value);
236
+ },
237
+ get(field) {
238
+ return denoRes.getHeader(field) || void 0;
239
+ },
240
+ append(field, value) {
241
+ if (Array.isArray(value)) {
242
+ value.forEach((v) => denoRes.headers.append(field, v));
243
+ } else {
244
+ denoRes.headers.append(field, value);
245
+ }
246
+ return this;
247
+ },
248
+ // Body methods
249
+ send(body) {
250
+ if (body === void 0) {
251
+ denoRes.end();
252
+ } else if (typeof body === "string") {
253
+ if (!denoRes.getHeader("Content-Type")) {
254
+ denoRes.setHeader("Content-Type", "text/html; charset=utf-8");
255
+ }
256
+ denoRes.send(body);
257
+ } else if (Buffer.isBuffer(body)) {
258
+ if (!denoRes.getHeader("Content-Type")) {
259
+ denoRes.setHeader("Content-Type", "application/octet-stream");
260
+ }
261
+ denoRes.send(body);
262
+ } else if (typeof body === "object") {
263
+ return this.json(body);
264
+ } else {
265
+ denoRes.send(String(body));
266
+ }
267
+ return this;
268
+ },
269
+ json(body) {
270
+ denoRes.json(body);
271
+ return this;
272
+ },
273
+ jsonp(body) {
274
+ denoRes.json(body);
275
+ return this;
276
+ },
277
+ end(data) {
278
+ if (data !== void 0) {
279
+ denoRes.end(typeof data === "string" ? data : JSON.stringify(data));
280
+ } else {
281
+ denoRes.end();
282
+ }
283
+ return this;
284
+ },
285
+ // Redirect
286
+ redirect(statusOrUrl, url) {
287
+ if (typeof statusOrUrl === "number" && url) {
288
+ denoRes.redirect(url, statusOrUrl);
289
+ } else if (typeof statusOrUrl === "string") {
290
+ denoRes.redirect(statusOrUrl, 302);
291
+ }
292
+ },
293
+ // Content type
294
+ type(type) {
295
+ const mimeTypes = {
296
+ html: "text/html",
297
+ json: "application/json",
298
+ xml: "application/xml",
299
+ text: "text/plain",
300
+ js: "application/javascript",
301
+ css: "text/css"
302
+ };
303
+ const contentType = mimeTypes[type] || type;
304
+ denoRes.setHeader("Content-Type", contentType);
305
+ return this;
306
+ },
307
+ contentType(type) {
308
+ return this.type(type);
309
+ },
310
+ // Cookies
311
+ cookie(name, value, options = {}) {
312
+ const cookieStr = serializeCookie(name, value, options);
313
+ cookies.push(cookieStr);
314
+ denoRes.headers.append("Set-Cookie", cookieStr);
315
+ return this;
316
+ },
317
+ clearCookie(name, options = {}) {
318
+ const clearOptions = { ...options, expires: /* @__PURE__ */ new Date(0), maxAge: 0 };
319
+ return this.cookie(name, "", clearOptions);
320
+ },
321
+ // Other methods
322
+ location(url) {
323
+ denoRes.setHeader("Location", url);
324
+ return this;
325
+ },
326
+ links(links) {
327
+ const linkHeader = Object.entries(links).map(([rel, href]) => `<${href}>; rel="${rel}"`).join(", ");
328
+ denoRes.setHeader("Link", linkHeader);
329
+ return this;
330
+ },
331
+ vary(field) {
332
+ const existing = denoRes.getHeader("Vary");
333
+ if (existing) {
334
+ denoRes.setHeader("Vary", `${existing}, ${field}`);
335
+ } else {
336
+ denoRes.setHeader("Vary", field);
337
+ }
338
+ return this;
339
+ },
340
+ format(obj) {
341
+ const accept = denoRes.headers.get?.("Accept") || "*/*";
342
+ const types = Object.keys(obj);
343
+ const matched = parseAccept(accept, types);
344
+ if (matched && obj[matched]) {
345
+ obj[matched]();
346
+ } else if (obj.default) {
347
+ obj.default();
348
+ }
349
+ return this;
350
+ }
351
+ };
352
+ return res;
353
+ }
354
+ function wrapExpressMiddleware(middleware) {
355
+ return async (denoReq, denoRes, next) => {
356
+ const expressReq = createExpressRequest(denoReq);
357
+ const expressRes = createExpressResponse(denoRes);
358
+ return new Promise((resolve, reject) => {
359
+ const expressNext = (err) => {
360
+ if (err) {
361
+ if (middleware.length === 4) {
362
+ try {
363
+ const result = middleware(err, expressReq, expressRes, expressNext);
364
+ if (result instanceof Promise) {
365
+ result.catch(reject);
366
+ }
367
+ } catch (e) {
368
+ reject(e);
369
+ }
370
+ } else {
371
+ reject(err);
372
+ }
373
+ } else {
374
+ next().then(resolve).catch(reject);
375
+ }
376
+ };
377
+ try {
378
+ const result = middleware(expressReq, expressRes, expressNext);
379
+ if (result instanceof Promise) {
380
+ result.catch(reject);
381
+ }
382
+ } catch (err) {
383
+ reject(err);
384
+ }
385
+ });
386
+ };
387
+ }
388
+
389
+ // src/compat/fastify-compat.ts
390
+ var requestIdCounter = 0;
391
+ function generateRequestId() {
392
+ return `req-${Date.now()}-${++requestIdCounter}`;
393
+ }
394
+ function headersToObject2(headers) {
395
+ const result = {};
396
+ headers.forEach((value, key) => {
397
+ const lowerKey = key.toLowerCase();
398
+ const existing = result[lowerKey];
399
+ if (existing) {
400
+ if (Array.isArray(existing)) {
401
+ existing.push(value);
402
+ } else {
403
+ result[lowerKey] = [existing, value];
404
+ }
405
+ } else {
406
+ result[lowerKey] = value;
407
+ }
408
+ });
409
+ return result;
410
+ }
411
+ function createFastifyRequest(denoReq) {
412
+ const headersObj = headersToObject2(denoReq.headers);
413
+ const req = {
414
+ id: generateRequestId(),
415
+ params: denoReq.params,
416
+ query: denoReq.query,
417
+ body: denoReq.body,
418
+ headers: headersObj,
419
+ raw: denoReq.raw,
420
+ url: denoReq.originalUrl || denoReq.path || "/",
421
+ originalUrl: denoReq.originalUrl || denoReq.path || "/",
422
+ method: denoReq.method,
423
+ hostname: denoReq.hostname || "",
424
+ ip: denoReq.ip,
425
+ protocol: denoReq.secure ? "https" : "http",
426
+ routerPath: denoReq.path,
427
+ routerMethod: denoReq.method
428
+ };
429
+ return req;
430
+ }
431
+ function createFastifyReply(denoRes) {
432
+ let serializer = JSON.stringify;
433
+ const startTime = Date.now();
434
+ const reply = {
435
+ get statusCode() {
436
+ return denoRes.statusCode;
437
+ },
438
+ set statusCode(code) {
439
+ denoRes.statusCode = code;
440
+ },
441
+ get sent() {
442
+ return denoRes.headersSent;
443
+ },
444
+ raw: denoRes,
445
+ code(statusCode) {
446
+ denoRes.status(statusCode);
447
+ return this;
448
+ },
449
+ status(statusCode) {
450
+ return this.code(statusCode);
451
+ },
452
+ header(key, value) {
453
+ denoRes.setHeader(key, String(value));
454
+ return this;
455
+ },
456
+ headers(headers) {
457
+ Object.entries(headers).forEach(([key, value]) => {
458
+ denoRes.setHeader(key, String(value));
459
+ });
460
+ return this;
461
+ },
462
+ getHeader(key) {
463
+ return denoRes.getHeader(key) || void 0;
464
+ },
465
+ getHeaders() {
466
+ const result = {};
467
+ denoRes.headers.forEach((value, key) => {
468
+ result[key] = value;
469
+ });
470
+ return result;
471
+ },
472
+ removeHeader(key) {
473
+ denoRes.removeHeader(key);
474
+ return this;
475
+ },
476
+ hasHeader(key) {
477
+ return denoRes.getHeader(key) !== null;
478
+ },
479
+ send(payload) {
480
+ if (payload === void 0) {
481
+ denoRes.end();
482
+ } else if (typeof payload === "string") {
483
+ if (!denoRes.getHeader("Content-Type")) {
484
+ denoRes.setHeader("Content-Type", "text/plain; charset=utf-8");
485
+ }
486
+ denoRes.send(payload);
487
+ } else if (payload instanceof Uint8Array || payload instanceof ArrayBuffer) {
488
+ if (!denoRes.getHeader("Content-Type")) {
489
+ denoRes.setHeader("Content-Type", "application/octet-stream");
490
+ }
491
+ denoRes.send(payload);
492
+ } else if (typeof payload === "object") {
493
+ if (!denoRes.getHeader("Content-Type")) {
494
+ denoRes.setHeader("Content-Type", "application/json; charset=utf-8");
495
+ }
496
+ denoRes.send(serializer(payload));
497
+ } else {
498
+ denoRes.send(String(payload));
499
+ }
500
+ return this;
501
+ },
502
+ serialize(payload) {
503
+ return serializer(payload);
504
+ },
505
+ serializer(fn) {
506
+ serializer = fn;
507
+ return this;
508
+ },
509
+ type(contentType) {
510
+ denoRes.setHeader("Content-Type", contentType);
511
+ return this;
512
+ },
513
+ redirect(statusCodeOrUrl, url) {
514
+ if (typeof statusCodeOrUrl === "number" && url) {
515
+ denoRes.redirect(url, statusCodeOrUrl);
516
+ } else if (typeof statusCodeOrUrl === "string") {
517
+ denoRes.redirect(statusCodeOrUrl, 302);
518
+ }
519
+ return this;
520
+ },
521
+ callNotFound() {
522
+ denoRes.status(404).json({
523
+ statusCode: 404,
524
+ error: "Not Found",
525
+ message: "Route not found"
526
+ });
527
+ },
528
+ getResponseTime() {
529
+ return Date.now() - startTime;
530
+ }
531
+ };
532
+ return reply;
533
+ }
534
+ function isAsyncHook(hook) {
535
+ return hook.length <= 2;
536
+ }
537
+ function wrapFastifyHook(hook) {
538
+ return async (denoReq, denoRes, next) => {
539
+ const fastifyReq = createFastifyRequest(denoReq);
540
+ const fastifyReply = createFastifyReply(denoRes);
541
+ if (isAsyncHook(hook)) {
542
+ await hook(fastifyReq, fastifyReply);
543
+ if (!fastifyReply.sent) {
544
+ await next();
545
+ }
546
+ } else {
547
+ return new Promise((resolve, reject) => {
548
+ const done = (err) => {
549
+ if (err) {
550
+ reject(err);
551
+ } else if (!fastifyReply.sent) {
552
+ next().then(resolve).catch(reject);
553
+ } else {
554
+ resolve();
555
+ }
556
+ };
557
+ try {
558
+ hook(fastifyReq, fastifyReply, done);
559
+ } catch (err) {
560
+ reject(err);
561
+ }
562
+ });
563
+ }
564
+ };
565
+ }
566
+ function wrapFastifyPlugin(plugin, instance, opts = {}) {
567
+ return new Promise((resolve, reject) => {
568
+ if (plugin.length <= 2) {
569
+ const result = plugin(instance, opts);
570
+ if (result instanceof Promise) {
571
+ result.then(resolve).catch(reject);
572
+ } else {
573
+ resolve();
574
+ }
575
+ } else {
576
+ try {
577
+ plugin(instance, opts, (err) => {
578
+ if (err) {
579
+ reject(err);
580
+ } else {
581
+ resolve();
582
+ }
583
+ });
584
+ } catch (err) {
585
+ reject(err);
586
+ }
587
+ }
588
+ });
589
+ }
590
+ function createFastifyLogger() {
591
+ const createLogFn = (level) => (msg, ...args) => {
592
+ console.log(`[${level.toUpperCase()}] ${msg}`, ...args);
593
+ };
594
+ return {
595
+ info: createLogFn("info"),
596
+ error: createLogFn("error"),
597
+ debug: createLogFn("debug"),
598
+ warn: createLogFn("warn"),
599
+ trace: createLogFn("trace"),
600
+ fatal: createLogFn("fatal"),
601
+ child(bindings) {
602
+ const prefix = Object.entries(bindings).map(([k, v]) => `${k}=${v}`).join(" ");
603
+ const childLog = createFastifyLogger();
604
+ const wrap = (fn) => (msg, ...args) => fn(`[${prefix}] ${msg}`, ...args);
605
+ return {
606
+ ...childLog,
607
+ info: wrap(childLog.info),
608
+ error: wrap(childLog.error),
609
+ debug: wrap(childLog.debug),
610
+ warn: wrap(childLog.warn),
611
+ trace: wrap(childLog.trace),
612
+ fatal: wrap(childLog.fatal)
613
+ };
614
+ }
615
+ };
616
+ }
617
+
618
+ // src/adapters/deno-adapter.ts
619
+ var DenoAdapter = class _DenoAdapter extends AbstractHttpAdapter {
620
+ routes = [];
621
+ middlewares = [];
622
+ server;
623
+ abortController;
624
+ corsOptions;
625
+ errorHandler;
626
+ notFoundHandler;
627
+ staticAssetsPath;
628
+ staticAssetsOptions;
629
+ constructor(instance) {
630
+ super(instance || {});
631
+ }
632
+ /**
633
+ * Create a new DenoAdapter instance
634
+ */
635
+ static create() {
636
+ return new _DenoAdapter();
637
+ }
638
+ async listen(port, hostnameOrCallback, callback) {
639
+ const portNum = typeof port === "string" ? parseInt(port, 10) : port;
640
+ const hostname = typeof hostnameOrCallback === "string" ? hostnameOrCallback : "0.0.0.0";
641
+ const cb = typeof hostnameOrCallback === "function" ? hostnameOrCallback : callback;
642
+ this.abortController = new AbortController();
643
+ const serveOptions = {
644
+ port: portNum,
645
+ hostname,
646
+ signal: this.abortController.signal,
647
+ onListen: () => {
648
+ cb?.();
649
+ }
650
+ };
651
+ this.server = Deno.serve(
652
+ serveOptions,
653
+ this.handleRequest.bind(this)
654
+ );
655
+ }
656
+ /**
657
+ * Handle incoming HTTP requests
658
+ */
659
+ async handleRequest(request) {
660
+ const url = new URL(request.url);
661
+ const path = url.pathname;
662
+ const method = request.method.toUpperCase();
663
+ const req = await this.createRequest(request, url);
664
+ const res = this.createResponse();
665
+ try {
666
+ if (this.corsOptions && method === "OPTIONS") {
667
+ this.handleCors(req, res);
668
+ return this.buildResponse(res);
669
+ }
670
+ if (this.corsOptions) {
671
+ this.applyCorsHeaders(req, res);
672
+ }
673
+ if (this.staticAssetsPath && path.startsWith(this.staticAssetsOptions?.prefix || "/")) {
674
+ const staticResponse = await this.serveStaticAsset(path);
675
+ if (staticResponse) {
676
+ return staticResponse;
677
+ }
678
+ }
679
+ await this.runMiddlewares(req, res, path);
680
+ if (res.headersSent) {
681
+ return this.buildResponse(res);
682
+ }
683
+ const route = this.findRoute(path, method);
684
+ if (route) {
685
+ req.params = this.extractParams(route, path);
686
+ await route.handler(req, res);
687
+ } else if (this.notFoundHandler) {
688
+ this.notFoundHandler(req, res);
689
+ } else {
690
+ res.status(HttpStatus.NOT_FOUND).json({
691
+ statusCode: HttpStatus.NOT_FOUND,
692
+ message: "Cannot " + method + " " + path,
693
+ error: "Not Found"
694
+ });
695
+ }
696
+ return this.buildResponse(res);
697
+ } catch (error) {
698
+ if (this.errorHandler) {
699
+ this.errorHandler(error, req, res);
700
+ return this.buildResponse(res);
701
+ }
702
+ res.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
703
+ statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
704
+ message: error.message || "Internal Server Error",
705
+ error: "Internal Server Error"
706
+ });
707
+ return this.buildResponse(res);
708
+ }
709
+ }
710
+ /**
711
+ * Create a DenoRequest object from a native Request
712
+ */
713
+ async createRequest(request, url) {
714
+ let body = void 0;
715
+ if (["POST", "PUT", "PATCH", "DELETE"].includes(request.method.toUpperCase())) {
716
+ const contentType = request.headers.get("content-type") || "";
717
+ if (contentType.includes("application/json")) {
718
+ try {
719
+ body = await request.json();
720
+ } catch {
721
+ body = void 0;
722
+ }
723
+ } else if (contentType.includes("application/x-www-form-urlencoded")) {
724
+ try {
725
+ const formData = await request.formData();
726
+ const entries = {};
727
+ formData.forEach((value, key) => {
728
+ entries[key] = value;
729
+ });
730
+ body = entries;
731
+ } catch {
732
+ body = void 0;
733
+ }
734
+ } else if (contentType.includes("text/")) {
735
+ try {
736
+ body = await request.text();
737
+ } catch {
738
+ body = void 0;
739
+ }
740
+ } else if (contentType.includes("multipart/form-data")) {
741
+ try {
742
+ body = await request.formData();
743
+ } catch {
744
+ body = void 0;
745
+ }
746
+ }
747
+ }
748
+ const query = {};
749
+ url.searchParams.forEach((value, key) => {
750
+ query[key] = value;
751
+ });
752
+ return {
753
+ raw: request,
754
+ url: request.url,
755
+ method: request.method,
756
+ headers: request.headers,
757
+ params: {},
758
+ query,
759
+ body,
760
+ ip: void 0,
761
+ // Deno doesn't expose client IP in the same way
762
+ hostname: url.hostname,
763
+ protocol: url.protocol.replace(":", ""),
764
+ secure: url.protocol === "https:",
765
+ originalUrl: url.pathname + url.search,
766
+ baseUrl: "",
767
+ path: url.pathname
768
+ };
769
+ }
770
+ /**
771
+ * Create a DenoResponse object
772
+ */
773
+ createResponse() {
774
+ const headers = new Headers();
775
+ let statusCode = 200;
776
+ let body = null;
777
+ let headersSent = false;
778
+ const res = {
779
+ get statusCode() {
780
+ return statusCode;
781
+ },
782
+ set statusCode(code) {
783
+ statusCode = code;
784
+ },
785
+ headers,
786
+ get body() {
787
+ return body;
788
+ },
789
+ set body(b) {
790
+ body = b ?? null;
791
+ },
792
+ get headersSent() {
793
+ return headersSent;
794
+ },
795
+ set headersSent(sent) {
796
+ headersSent = sent;
797
+ },
798
+ status(code) {
799
+ statusCode = code;
800
+ return this;
801
+ },
802
+ setHeader(name, value) {
803
+ headers.set(name, value);
804
+ return this;
805
+ },
806
+ getHeader(name) {
807
+ return headers.get(name);
808
+ },
809
+ removeHeader(name) {
810
+ headers.delete(name);
811
+ return this;
812
+ },
813
+ send(responseBody) {
814
+ headersSent = true;
815
+ if (responseBody === void 0 || responseBody === null) {
816
+ body = null;
817
+ } else if (typeof responseBody === "object" && !(responseBody instanceof Blob) && !(responseBody instanceof ReadableStream) && !(responseBody instanceof FormData) && !(responseBody instanceof URLSearchParams) && !(responseBody instanceof ArrayBuffer)) {
818
+ headers.set("Content-Type", "application/json");
819
+ body = JSON.stringify(responseBody);
820
+ } else {
821
+ body = responseBody;
822
+ }
823
+ },
824
+ json(responseBody) {
825
+ headersSent = true;
826
+ headers.set("Content-Type", "application/json");
827
+ body = JSON.stringify(responseBody);
828
+ },
829
+ redirect(url, code = 302) {
830
+ headersSent = true;
831
+ statusCode = code;
832
+ headers.set("Location", url);
833
+ body = null;
834
+ },
835
+ end(responseBody) {
836
+ headersSent = true;
837
+ body = responseBody ?? null;
838
+ }
839
+ };
840
+ return res;
841
+ }
842
+ /**
843
+ * Build a Response object from DenoResponse
844
+ */
845
+ buildResponse(res) {
846
+ return new Response(res.body, {
847
+ status: res.statusCode,
848
+ headers: res.headers
849
+ });
850
+ }
851
+ /**
852
+ * Run all matching middlewares
853
+ */
854
+ async runMiddlewares(req, res, path) {
855
+ const matchingMiddlewares = this.middlewares.filter(
856
+ (m) => path.startsWith(m.path) || m.path === "*" || m.path === "/"
857
+ );
858
+ let index = 0;
859
+ const next = async () => {
860
+ if (index < matchingMiddlewares.length && !res.headersSent) {
861
+ const middleware = matchingMiddlewares[index++];
862
+ await middleware.handler(req, res, next);
863
+ }
864
+ };
865
+ await next();
866
+ }
867
+ /**
868
+ * Find a matching route
869
+ */
870
+ findRoute(path, method) {
871
+ return this.routes.find((route) => {
872
+ const methodMatch = route.method === method || route.method === "ALL";
873
+ if (typeof route.path === "string") {
874
+ const pattern = this.pathToRegex(route.path);
875
+ return methodMatch && pattern.test(path);
876
+ }
877
+ return methodMatch && route.path.test(path);
878
+ });
879
+ }
880
+ /**
881
+ * Extract route parameters from path
882
+ */
883
+ extractParams(route, path) {
884
+ const params = {};
885
+ if (typeof route.path === "string") {
886
+ const pattern = this.pathToRegex(route.path);
887
+ const match = path.match(pattern);
888
+ if (match) {
889
+ route.keys.forEach((key, index) => {
890
+ params[key] = match[index + 1] || "";
891
+ });
892
+ }
893
+ }
894
+ return params;
895
+ }
896
+ /**
897
+ * Convert a path pattern to a RegExp
898
+ */
899
+ pathToRegex(path) {
900
+ const escaped = path.replace(/([.+?^${}()|[\]\\])/g, "\\$1").replace(/:(\w+)/g, "([^/]+)").replace(/\*/g, ".*");
901
+ return new RegExp(`^${escaped}$`);
902
+ }
903
+ /**
904
+ * Extract parameter keys from path pattern
905
+ */
906
+ extractKeys(path) {
907
+ const keys = [];
908
+ const regex = /:(\w+)/g;
909
+ let match;
910
+ while ((match = regex.exec(path)) !== null) {
911
+ keys.push(match[1]);
912
+ }
913
+ return keys;
914
+ }
915
+ /**
916
+ * Register a route handler
917
+ */
918
+ registerRoute(method, path, handler) {
919
+ this.routes.push({
920
+ path,
921
+ method,
922
+ handler,
923
+ keys: this.extractKeys(path)
924
+ });
925
+ }
926
+ get(pathOrHandler, handler) {
927
+ if (typeof pathOrHandler === "function") {
928
+ this.registerRoute("GET", "/", pathOrHandler);
929
+ } else if (handler) {
930
+ this.registerRoute("GET", pathOrHandler, handler);
931
+ }
932
+ }
933
+ post(pathOrHandler, handler) {
934
+ if (typeof pathOrHandler === "function") {
935
+ this.registerRoute("POST", "/", pathOrHandler);
936
+ } else if (handler) {
937
+ this.registerRoute("POST", pathOrHandler, handler);
938
+ }
939
+ }
940
+ put(pathOrHandler, handler) {
941
+ if (typeof pathOrHandler === "function") {
942
+ this.registerRoute("PUT", "/", pathOrHandler);
943
+ } else if (handler) {
944
+ this.registerRoute("PUT", pathOrHandler, handler);
945
+ }
946
+ }
947
+ delete(pathOrHandler, handler) {
948
+ if (typeof pathOrHandler === "function") {
949
+ this.registerRoute("DELETE", "/", pathOrHandler);
950
+ } else if (handler) {
951
+ this.registerRoute("DELETE", pathOrHandler, handler);
952
+ }
953
+ }
954
+ patch(pathOrHandler, handler) {
955
+ if (typeof pathOrHandler === "function") {
956
+ this.registerRoute("PATCH", "/", pathOrHandler);
957
+ } else if (handler) {
958
+ this.registerRoute("PATCH", pathOrHandler, handler);
959
+ }
960
+ }
961
+ options(pathOrHandler, handler) {
962
+ if (typeof pathOrHandler === "function") {
963
+ this.registerRoute("OPTIONS", "/", pathOrHandler);
964
+ } else if (handler) {
965
+ this.registerRoute("OPTIONS", pathOrHandler, handler);
966
+ }
967
+ }
968
+ head(pathOrHandler, handler) {
969
+ if (typeof pathOrHandler === "function") {
970
+ this.registerRoute("HEAD", "/", pathOrHandler);
971
+ } else if (handler) {
972
+ this.registerRoute("HEAD", pathOrHandler, handler);
973
+ }
974
+ }
975
+ all(pathOrHandler, handler) {
976
+ if (typeof pathOrHandler === "function") {
977
+ this.registerRoute("ALL", "/", pathOrHandler);
978
+ } else if (handler) {
979
+ this.registerRoute("ALL", pathOrHandler, handler);
980
+ }
981
+ }
982
+ use(pathOrHandler, handler) {
983
+ if (typeof pathOrHandler === "function") {
984
+ this.middlewares.push({
985
+ path: "*",
986
+ handler: pathOrHandler
987
+ });
988
+ } else if (handler) {
989
+ this.middlewares.push({
990
+ path: pathOrHandler,
991
+ handler
992
+ });
993
+ }
994
+ }
995
+ useExpressMiddleware(pathOrMiddleware, middleware) {
996
+ if (typeof pathOrMiddleware === "function") {
997
+ const wrappedMiddleware = wrapExpressMiddleware(pathOrMiddleware);
998
+ this.middlewares.push({
999
+ path: "*",
1000
+ handler: wrappedMiddleware
1001
+ });
1002
+ } else if (middleware) {
1003
+ const wrappedMiddleware = wrapExpressMiddleware(middleware);
1004
+ this.middlewares.push({
1005
+ path: pathOrMiddleware,
1006
+ handler: wrappedMiddleware
1007
+ });
1008
+ }
1009
+ }
1010
+ /**
1011
+ * Create an Express-like app instance for middleware that requires app.use()
1012
+ *
1013
+ * Some Express middleware (like express-session) require an Express app instance.
1014
+ * This creates a compatible shim that routes middleware through the Deno adapter.
1015
+ *
1016
+ * @example
1017
+ * ```typescript
1018
+ * import session from 'express-session';
1019
+ *
1020
+ * const adapter = new DenoAdapter();
1021
+ * const expressApp = adapter.getExpressApp();
1022
+ *
1023
+ * expressApp.use(session({ secret: 'keyboard cat' }));
1024
+ * ```
1025
+ */
1026
+ getExpressApp() {
1027
+ const self = this;
1028
+ const settings = {};
1029
+ const app = {
1030
+ locals: {},
1031
+ settings,
1032
+ use(...args) {
1033
+ if (args.length === 1 && typeof args[0] === "function") {
1034
+ self.useExpressMiddleware(args[0]);
1035
+ } else if (args.length === 2 && typeof args[0] === "string" && typeof args[1] === "function") {
1036
+ self.useExpressMiddleware(args[0], args[1]);
1037
+ } else if (args.length >= 2) {
1038
+ const path = typeof args[0] === "string" ? args[0] : "*";
1039
+ const handlers = typeof args[0] === "string" ? args.slice(1) : args;
1040
+ handlers.forEach((handler) => {
1041
+ if (typeof handler === "function") {
1042
+ self.useExpressMiddleware(path, handler);
1043
+ }
1044
+ });
1045
+ }
1046
+ },
1047
+ get(path, ...handlers) {
1048
+ handlers.forEach((handler) => {
1049
+ self.get(path, async (req, res) => {
1050
+ const expressReq = createExpressRequest(req);
1051
+ const expressRes = createExpressResponse(res);
1052
+ await handler(expressReq, expressRes, () => {
1053
+ });
1054
+ });
1055
+ });
1056
+ },
1057
+ post(path, ...handlers) {
1058
+ handlers.forEach((handler) => {
1059
+ self.post(path, async (req, res) => {
1060
+ const expressReq = createExpressRequest(req);
1061
+ const expressRes = createExpressResponse(res);
1062
+ await handler(expressReq, expressRes, () => {
1063
+ });
1064
+ });
1065
+ });
1066
+ },
1067
+ put(path, ...handlers) {
1068
+ handlers.forEach((handler) => {
1069
+ self.put(path, async (req, res) => {
1070
+ const expressReq = createExpressRequest(req);
1071
+ const expressRes = createExpressResponse(res);
1072
+ await handler(expressReq, expressRes, () => {
1073
+ });
1074
+ });
1075
+ });
1076
+ },
1077
+ delete(path, ...handlers) {
1078
+ handlers.forEach((handler) => {
1079
+ self.delete(path, async (req, res) => {
1080
+ const expressReq = createExpressRequest(req);
1081
+ const expressRes = createExpressResponse(res);
1082
+ await handler(expressReq, expressRes, () => {
1083
+ });
1084
+ });
1085
+ });
1086
+ },
1087
+ patch(path, ...handlers) {
1088
+ handlers.forEach((handler) => {
1089
+ self.patch(path, async (req, res) => {
1090
+ const expressReq = createExpressRequest(req);
1091
+ const expressRes = createExpressResponse(res);
1092
+ await handler(expressReq, expressRes, () => {
1093
+ });
1094
+ });
1095
+ });
1096
+ },
1097
+ options(path, ...handlers) {
1098
+ handlers.forEach((handler) => {
1099
+ self.options(path, async (req, res) => {
1100
+ const expressReq = createExpressRequest(req);
1101
+ const expressRes = createExpressResponse(res);
1102
+ await handler(expressReq, expressRes, () => {
1103
+ });
1104
+ });
1105
+ });
1106
+ },
1107
+ head(path, ...handlers) {
1108
+ handlers.forEach((handler) => {
1109
+ self.head(path, async (req, res) => {
1110
+ const expressReq = createExpressRequest(req);
1111
+ const expressRes = createExpressResponse(res);
1112
+ await handler(expressReq, expressRes, () => {
1113
+ });
1114
+ });
1115
+ });
1116
+ },
1117
+ all(path, ...handlers) {
1118
+ handlers.forEach((handler) => {
1119
+ self.all(path, async (req, res) => {
1120
+ const expressReq = createExpressRequest(req);
1121
+ const expressRes = createExpressResponse(res);
1122
+ await handler(expressReq, expressRes, () => {
1123
+ });
1124
+ });
1125
+ });
1126
+ },
1127
+ set(key, value) {
1128
+ settings[key] = value;
1129
+ },
1130
+ enable(key) {
1131
+ settings[key] = true;
1132
+ },
1133
+ disable(key) {
1134
+ settings[key] = false;
1135
+ },
1136
+ enabled(key) {
1137
+ return Boolean(settings[key]);
1138
+ },
1139
+ disabled(key) {
1140
+ return !settings[key];
1141
+ }
1142
+ };
1143
+ return app;
1144
+ }
1145
+ /**
1146
+ * Use Fastify middleware/hooks with the Deno adapter
1147
+ *
1148
+ * This method wraps Fastify hooks to be compatible with the Deno adapter,
1149
+ * allowing you to use Fastify-style middleware.
1150
+ *
1151
+ * @example
1152
+ * ```typescript
1153
+ * const adapter = new DenoAdapter();
1154
+ *
1155
+ * // Use a Fastify hook
1156
+ * adapter.useFastifyHook('onRequest', async (request, reply) => {
1157
+ * console.log('Request received:', request.url);
1158
+ * });
1159
+ *
1160
+ * // Use with callback style
1161
+ * adapter.useFastifyHook('preHandler', (request, reply, done) => {
1162
+ * // Do something
1163
+ * done();
1164
+ * });
1165
+ * ```
1166
+ */
1167
+ useFastifyHook(_name, hook) {
1168
+ const wrappedHook = wrapFastifyHook(hook);
1169
+ this.middlewares.push({
1170
+ path: "*",
1171
+ handler: wrappedHook
1172
+ });
1173
+ }
1174
+ /**
1175
+ * Register a Fastify plugin with the Deno adapter
1176
+ *
1177
+ * This allows using Fastify plugins that add hooks, decorators, or routes.
1178
+ *
1179
+ * @example
1180
+ * ```typescript
1181
+ * import fastifyCors from '@fastify/cors';
1182
+ * import fastifyHelmet from '@fastify/helmet';
1183
+ *
1184
+ * const adapter = new DenoAdapter();
1185
+ * const fastify = adapter.getFastifyInstance();
1186
+ *
1187
+ * // Register plugins
1188
+ * await adapter.registerFastifyPlugin(fastifyCors, { origin: '*' });
1189
+ * await adapter.registerFastifyPlugin(fastifyHelmet);
1190
+ * ```
1191
+ */
1192
+ async registerFastifyPlugin(plugin, opts) {
1193
+ const instance = this.getFastifyInstance();
1194
+ await wrapFastifyPlugin(plugin, instance, opts);
1195
+ }
1196
+ /**
1197
+ * Get a Fastify-like instance for plugins that require it
1198
+ *
1199
+ * This creates a Fastify-compatible interface that routes hooks and routes
1200
+ * through the Deno adapter.
1201
+ *
1202
+ * @example
1203
+ * ```typescript
1204
+ * const adapter = new DenoAdapter();
1205
+ * const fastify = adapter.getFastifyInstance();
1206
+ *
1207
+ * // Add hooks
1208
+ * fastify.addHook('onRequest', async (request, reply) => {
1209
+ * console.log('Request:', request.method, request.url);
1210
+ * });
1211
+ *
1212
+ * // Add decorators
1213
+ * fastify.decorateRequest('user', null);
1214
+ * ```
1215
+ */
1216
+ getFastifyInstance() {
1217
+ const self = this;
1218
+ const decorators = {};
1219
+ const requestDecorators = {};
1220
+ const replyDecorators = {};
1221
+ const instance = {
1222
+ log: createFastifyLogger(),
1223
+ prefix: "",
1224
+ // Decorators
1225
+ decorate(name, value) {
1226
+ decorators[name] = value;
1227
+ return this;
1228
+ },
1229
+ decorateRequest(name, value) {
1230
+ requestDecorators[name] = value;
1231
+ return this;
1232
+ },
1233
+ decorateReply(name, value) {
1234
+ replyDecorators[name] = value;
1235
+ return this;
1236
+ },
1237
+ hasDecorator(name) {
1238
+ return name in decorators;
1239
+ },
1240
+ hasRequestDecorator(name) {
1241
+ return name in requestDecorators;
1242
+ },
1243
+ hasReplyDecorator(name) {
1244
+ return name in replyDecorators;
1245
+ },
1246
+ // Hooks
1247
+ addHook(name, hook) {
1248
+ if (["onRequest", "preParsing", "preValidation", "preHandler", "onResponse"].includes(name)) {
1249
+ self.useFastifyHook(name, hook);
1250
+ }
1251
+ return this;
1252
+ },
1253
+ // Plugin registration
1254
+ register(plugin, opts) {
1255
+ wrapFastifyPlugin(plugin, this, opts).catch(console.error);
1256
+ return this;
1257
+ },
1258
+ // Routes
1259
+ route(opts) {
1260
+ const methods = Array.isArray(opts.method) ? opts.method : [opts.method];
1261
+ methods.forEach((method) => {
1262
+ const handler = async (req, res) => {
1263
+ const fastifyReq = createFastifyRequest(req);
1264
+ const fastifyReply = createFastifyReply(res);
1265
+ Object.entries(requestDecorators).forEach(([key, value]) => {
1266
+ fastifyReq[key] = typeof value === "function" ? value() : value;
1267
+ });
1268
+ Object.entries(replyDecorators).forEach(([key, value]) => {
1269
+ fastifyReply[key] = typeof value === "function" ? value() : value;
1270
+ });
1271
+ const hooks = [
1272
+ ...opts.onRequest ? Array.isArray(opts.onRequest) ? opts.onRequest : [opts.onRequest] : [],
1273
+ ...opts.preValidation ? Array.isArray(opts.preValidation) ? opts.preValidation : [opts.preValidation] : [],
1274
+ ...opts.preHandler ? Array.isArray(opts.preHandler) ? opts.preHandler : [opts.preHandler] : []
1275
+ ];
1276
+ for (const hook of hooks) {
1277
+ if (fastifyReply.sent) break;
1278
+ await new Promise((resolve, reject) => {
1279
+ if (hook.length <= 2) {
1280
+ hook(fastifyReq, fastifyReply).then(resolve).catch(reject);
1281
+ } else {
1282
+ hook(
1283
+ fastifyReq,
1284
+ fastifyReply,
1285
+ (err) => err ? reject(err) : resolve()
1286
+ );
1287
+ }
1288
+ });
1289
+ }
1290
+ if (!fastifyReply.sent) {
1291
+ const result = await opts.handler(fastifyReq, fastifyReply);
1292
+ if (result !== void 0 && !fastifyReply.sent) {
1293
+ fastifyReply.send(result);
1294
+ }
1295
+ }
1296
+ };
1297
+ switch (method.toUpperCase()) {
1298
+ case "GET":
1299
+ self.get(opts.url, handler);
1300
+ break;
1301
+ case "POST":
1302
+ self.post(opts.url, handler);
1303
+ break;
1304
+ case "PUT":
1305
+ self.put(opts.url, handler);
1306
+ break;
1307
+ case "DELETE":
1308
+ self.delete(opts.url, handler);
1309
+ break;
1310
+ case "PATCH":
1311
+ self.patch(opts.url, handler);
1312
+ break;
1313
+ case "OPTIONS":
1314
+ self.options(opts.url, handler);
1315
+ break;
1316
+ case "HEAD":
1317
+ self.head(opts.url, handler);
1318
+ break;
1319
+ default:
1320
+ self.all(opts.url, handler);
1321
+ }
1322
+ });
1323
+ return this;
1324
+ },
1325
+ // HTTP method shortcuts
1326
+ get(path, optsOrHandler, handler) {
1327
+ const h = typeof optsOrHandler === "function" ? optsOrHandler : handler;
1328
+ const opts = typeof optsOrHandler === "object" ? optsOrHandler : {};
1329
+ return this.route({ ...opts, method: "GET", url: path, handler: h });
1330
+ },
1331
+ post(path, optsOrHandler, handler) {
1332
+ const h = typeof optsOrHandler === "function" ? optsOrHandler : handler;
1333
+ const opts = typeof optsOrHandler === "object" ? optsOrHandler : {};
1334
+ return this.route({ ...opts, method: "POST", url: path, handler: h });
1335
+ },
1336
+ put(path, optsOrHandler, handler) {
1337
+ const h = typeof optsOrHandler === "function" ? optsOrHandler : handler;
1338
+ const opts = typeof optsOrHandler === "object" ? optsOrHandler : {};
1339
+ return this.route({ ...opts, method: "PUT", url: path, handler: h });
1340
+ },
1341
+ delete(path, optsOrHandler, handler) {
1342
+ const h = typeof optsOrHandler === "function" ? optsOrHandler : handler;
1343
+ const opts = typeof optsOrHandler === "object" ? optsOrHandler : {};
1344
+ return this.route({ ...opts, method: "DELETE", url: path, handler: h });
1345
+ },
1346
+ patch(path, optsOrHandler, handler) {
1347
+ const h = typeof optsOrHandler === "function" ? optsOrHandler : handler;
1348
+ const opts = typeof optsOrHandler === "object" ? optsOrHandler : {};
1349
+ return this.route({ ...opts, method: "PATCH", url: path, handler: h });
1350
+ },
1351
+ options(path, optsOrHandler, handler) {
1352
+ const h = typeof optsOrHandler === "function" ? optsOrHandler : handler;
1353
+ const opts = typeof optsOrHandler === "object" ? optsOrHandler : {};
1354
+ return this.route({ ...opts, method: "OPTIONS", url: path, handler: h });
1355
+ },
1356
+ head(path, optsOrHandler, handler) {
1357
+ const h = typeof optsOrHandler === "function" ? optsOrHandler : handler;
1358
+ const opts = typeof optsOrHandler === "object" ? optsOrHandler : {};
1359
+ return this.route({ ...opts, method: "HEAD", url: path, handler: h });
1360
+ },
1361
+ all(path, optsOrHandler, handler) {
1362
+ const h = typeof optsOrHandler === "function" ? optsOrHandler : handler;
1363
+ const opts = typeof optsOrHandler === "object" ? optsOrHandler : {};
1364
+ return this.route({ ...opts, method: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"], url: path, handler: h });
1365
+ }
1366
+ };
1367
+ return instance;
1368
+ }
1369
+ /**
1370
+ * Get the underlying HTTP server
1371
+ */
1372
+ getHttpServer() {
1373
+ return this.server;
1374
+ }
1375
+ /**
1376
+ * Set the HTTP server instance
1377
+ */
1378
+ setHttpServer(server) {
1379
+ this.server = server;
1380
+ }
1381
+ /**
1382
+ * Close the server
1383
+ */
1384
+ async close() {
1385
+ if (this.abortController) {
1386
+ this.abortController.abort();
1387
+ await this.server?.finished;
1388
+ }
1389
+ }
1390
+ /**
1391
+ * Set error handler
1392
+ */
1393
+ setErrorHandler(handler) {
1394
+ this.errorHandler = handler;
1395
+ }
1396
+ /**
1397
+ * Set 404 handler
1398
+ */
1399
+ setNotFoundHandler(handler) {
1400
+ this.notFoundHandler = handler;
1401
+ }
1402
+ /**
1403
+ * Enable CORS
1404
+ */
1405
+ enableCors(options) {
1406
+ this.corsOptions = options || {
1407
+ origin: "*",
1408
+ methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
1409
+ credentials: false
1410
+ };
1411
+ }
1412
+ /**
1413
+ * Handle CORS preflight requests
1414
+ */
1415
+ handleCors(req, res) {
1416
+ this.applyCorsHeaders(req, res);
1417
+ res.status(this.corsOptions?.optionsSuccessStatus || 204).end();
1418
+ }
1419
+ /**
1420
+ * Apply CORS headers to response
1421
+ */
1422
+ applyCorsHeaders(req, res) {
1423
+ if (!this.corsOptions) return;
1424
+ const origin = req.headers.get("origin") || "*";
1425
+ let allowOrigin = "*";
1426
+ if (typeof this.corsOptions.origin === "string") {
1427
+ allowOrigin = this.corsOptions.origin;
1428
+ } else if (typeof this.corsOptions.origin === "boolean") {
1429
+ allowOrigin = this.corsOptions.origin ? origin : "";
1430
+ } else if (Array.isArray(this.corsOptions.origin)) {
1431
+ allowOrigin = this.corsOptions.origin.includes(origin) ? origin : "";
1432
+ } else if (typeof this.corsOptions.origin === "function") {
1433
+ const result = this.corsOptions.origin(origin);
1434
+ allowOrigin = typeof result === "string" ? result : result ? origin : "";
1435
+ }
1436
+ res.setHeader("Access-Control-Allow-Origin", allowOrigin);
1437
+ if (this.corsOptions.credentials) {
1438
+ res.setHeader("Access-Control-Allow-Credentials", "true");
1439
+ }
1440
+ const methods = Array.isArray(this.corsOptions.methods) ? this.corsOptions.methods.join(",") : this.corsOptions.methods || "GET,HEAD,PUT,PATCH,POST,DELETE";
1441
+ res.setHeader("Access-Control-Allow-Methods", methods);
1442
+ if (this.corsOptions.allowedHeaders) {
1443
+ const headers = Array.isArray(this.corsOptions.allowedHeaders) ? this.corsOptions.allowedHeaders.join(",") : this.corsOptions.allowedHeaders;
1444
+ res.setHeader("Access-Control-Allow-Headers", headers);
1445
+ } else {
1446
+ const requestHeaders = req.headers.get("access-control-request-headers");
1447
+ if (requestHeaders) {
1448
+ res.setHeader("Access-Control-Allow-Headers", requestHeaders);
1449
+ }
1450
+ }
1451
+ if (this.corsOptions.exposedHeaders) {
1452
+ const exposed = Array.isArray(this.corsOptions.exposedHeaders) ? this.corsOptions.exposedHeaders.join(",") : this.corsOptions.exposedHeaders;
1453
+ res.setHeader("Access-Control-Expose-Headers", exposed);
1454
+ }
1455
+ if (this.corsOptions.maxAge) {
1456
+ res.setHeader("Access-Control-Max-Age", String(this.corsOptions.maxAge));
1457
+ }
1458
+ }
1459
+ /**
1460
+ * Use static assets
1461
+ */
1462
+ useStaticAssets(path, options) {
1463
+ this.staticAssetsPath = path;
1464
+ this.staticAssetsOptions = options;
1465
+ }
1466
+ /**
1467
+ * Serve static asset
1468
+ */
1469
+ async serveStaticAsset(urlPath) {
1470
+ if (!this.staticAssetsPath) return null;
1471
+ const prefix = this.staticAssetsOptions?.prefix || "/";
1472
+ const relativePath = urlPath.replace(prefix, "").replace(/^\//, "");
1473
+ const filePath = `${this.staticAssetsPath}/${relativePath}`;
1474
+ try {
1475
+ const file = await Deno.open(filePath, { read: true });
1476
+ const stat = await file.stat();
1477
+ if (stat.isDirectory) {
1478
+ file.close();
1479
+ if (this.staticAssetsOptions?.index !== false) {
1480
+ const indexFile = typeof this.staticAssetsOptions?.index === "string" ? this.staticAssetsOptions.index : "index.html";
1481
+ return this.serveStaticAsset(`${urlPath}/${indexFile}`);
1482
+ }
1483
+ return null;
1484
+ }
1485
+ const headers = new Headers();
1486
+ const ext = filePath.split(".").pop()?.toLowerCase();
1487
+ const mimeTypes = {
1488
+ html: "text/html",
1489
+ css: "text/css",
1490
+ js: "application/javascript",
1491
+ json: "application/json",
1492
+ png: "image/png",
1493
+ jpg: "image/jpeg",
1494
+ jpeg: "image/jpeg",
1495
+ gif: "image/gif",
1496
+ svg: "image/svg+xml",
1497
+ ico: "image/x-icon",
1498
+ woff: "font/woff",
1499
+ woff2: "font/woff2",
1500
+ ttf: "font/ttf",
1501
+ eot: "application/vnd.ms-fontobject",
1502
+ txt: "text/plain",
1503
+ xml: "application/xml",
1504
+ pdf: "application/pdf",
1505
+ mp4: "video/mp4",
1506
+ webm: "video/webm",
1507
+ mp3: "audio/mpeg",
1508
+ wav: "audio/wav"
1509
+ };
1510
+ headers.set("Content-Type", mimeTypes[ext || ""] || "application/octet-stream");
1511
+ if (this.staticAssetsOptions?.etag !== false) {
1512
+ headers.set("ETag", `"${stat.size}-${stat.mtime?.getTime() || 0}"`);
1513
+ }
1514
+ if (this.staticAssetsOptions?.lastModified !== false && stat.mtime) {
1515
+ headers.set("Last-Modified", stat.mtime.toUTCString());
1516
+ }
1517
+ if (this.staticAssetsOptions?.maxAge) {
1518
+ let cacheControl = `max-age=${this.staticAssetsOptions.maxAge}`;
1519
+ if (this.staticAssetsOptions.immutable) {
1520
+ cacheControl += ", immutable";
1521
+ }
1522
+ headers.set("Cache-Control", cacheControl);
1523
+ }
1524
+ return new Response(file.readable, {
1525
+ status: 200,
1526
+ headers
1527
+ });
1528
+ } catch (error) {
1529
+ if (error.name === "NotFound") {
1530
+ return null;
1531
+ }
1532
+ throw error;
1533
+ }
1534
+ }
1535
+ /**
1536
+ * Set view engine (not implemented for base adapter)
1537
+ */
1538
+ setViewEngine(_engine) {
1539
+ console.warn("View engine is not supported in the base Deno adapter");
1540
+ }
1541
+ /**
1542
+ * Render view (not implemented for base adapter)
1543
+ */
1544
+ render(_response, _view, _options) {
1545
+ console.warn("Render is not supported in the base Deno adapter");
1546
+ }
1547
+ /**
1548
+ * Get request hostname
1549
+ */
1550
+ getRequestHostname(request) {
1551
+ return request.hostname || request.headers.get("host") || "";
1552
+ }
1553
+ /**
1554
+ * Get request method
1555
+ */
1556
+ getRequestMethod(request) {
1557
+ return request.method;
1558
+ }
1559
+ /**
1560
+ * Get request URL
1561
+ */
1562
+ getRequestUrl(request) {
1563
+ return request.path || new URL(request.url).pathname;
1564
+ }
1565
+ /**
1566
+ * Send a reply
1567
+ */
1568
+ reply(response, body, statusCode) {
1569
+ if (statusCode) {
1570
+ response.status(statusCode);
1571
+ }
1572
+ if (body === void 0 || body === null) {
1573
+ response.end();
1574
+ } else if (typeof body === "object") {
1575
+ response.json(body);
1576
+ } else {
1577
+ response.send(String(body));
1578
+ }
1579
+ }
1580
+ /**
1581
+ * Set response status
1582
+ */
1583
+ status(response, statusCode) {
1584
+ response.status(statusCode);
1585
+ }
1586
+ /**
1587
+ * Redirect response
1588
+ */
1589
+ redirect(response, statusCode, url) {
1590
+ response.redirect(url, statusCode);
1591
+ }
1592
+ /**
1593
+ * Set response header
1594
+ */
1595
+ setHeader(response, name, value) {
1596
+ response.setHeader(name, value);
1597
+ }
1598
+ /**
1599
+ * Get response header
1600
+ */
1601
+ getHeader(response, name) {
1602
+ return response.getHeader(name);
1603
+ }
1604
+ /**
1605
+ * Append value to header
1606
+ */
1607
+ appendHeader(response, name, value) {
1608
+ const existing = response.getHeader(name);
1609
+ if (existing) {
1610
+ response.setHeader(name, `${existing}, ${value}`);
1611
+ } else {
1612
+ response.setHeader(name, value);
1613
+ }
1614
+ }
1615
+ /**
1616
+ * End response
1617
+ */
1618
+ end(response, message) {
1619
+ response.end(message);
1620
+ }
1621
+ /**
1622
+ * Check if headers have been sent
1623
+ */
1624
+ isHeadersSent(response) {
1625
+ return response.headersSent;
1626
+ }
1627
+ /**
1628
+ * Register body parser middleware
1629
+ */
1630
+ registerParserMiddleware() {
1631
+ }
1632
+ /**
1633
+ * Create middleware factory
1634
+ */
1635
+ createMiddlewareFactory(_requestMethod) {
1636
+ return (path, callback) => {
1637
+ this.use(path, async (req, res, next) => {
1638
+ await callback(req, res, next);
1639
+ });
1640
+ };
1641
+ }
1642
+ /**
1643
+ * Initialize the adapter
1644
+ */
1645
+ initHttpServer() {
1646
+ }
1647
+ /**
1648
+ * Get the adapter type
1649
+ */
1650
+ getType() {
1651
+ return "deno";
1652
+ }
1653
+ /**
1654
+ * Apply version filter
1655
+ */
1656
+ applyVersionFilter(handler, _version, _versioningOptions) {
1657
+ return (_req, _res, _next) => {
1658
+ return handler;
1659
+ };
1660
+ }
1661
+ };
1662
+ export {
1663
+ DenoAdapter,
1664
+ createExpressRequest,
1665
+ createExpressResponse,
1666
+ createFastifyLogger,
1667
+ createFastifyReply,
1668
+ createFastifyRequest,
1669
+ wrapExpressMiddleware,
1670
+ wrapFastifyHook,
1671
+ wrapFastifyPlugin
1672
+ };
1673
+ //# sourceMappingURL=index.js.map