h3 0.8.5 → 0.8.6

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 CHANGED
@@ -136,6 +136,7 @@ H3 has concept of compasable utilities that accept `event` (from `eventHandler((
136
136
  - `isMethod(event, expected, allowHead?)`
137
137
  - `assertMethod(event, expected, allowHead?)`
138
138
  - `createError({ statusCode, statusMessage, data? })`
139
+ - `sendProxy(event, { target, headers?, fetchOptions?, fetch?, sendStream? })`
139
140
 
140
141
  👉 You can learn more about usage in [JSDocs Documentation](https://www.jsdocs.io/package/h3#package-functions).
141
142
 
package/dist/index.cjs CHANGED
@@ -25,6 +25,19 @@ class H3Error extends Error {
25
25
  this.unhandled = false;
26
26
  this.statusMessage = void 0;
27
27
  }
28
+ toJSON() {
29
+ const obj = {
30
+ message: this.message,
31
+ statusCode: this.statusCode
32
+ };
33
+ if (this.statusMessage) {
34
+ obj.statusMessage = this.statusMessage;
35
+ }
36
+ if (this.data !== void 0) {
37
+ obj.data = this.data;
38
+ }
39
+ return obj;
40
+ }
28
41
  }
29
42
  H3Error.__h3_error__ = true;
30
43
  function createError(input) {
@@ -47,14 +60,18 @@ function createError(input) {
47
60
  }
48
61
  }
49
62
  }
63
+ if (input.data) {
64
+ err.data = input.data;
65
+ }
50
66
  if (input.statusCode) {
51
67
  err.statusCode = input.statusCode;
68
+ } else if (input.status) {
69
+ err.statusCode = input.status;
52
70
  }
53
71
  if (input.statusMessage) {
54
72
  err.statusMessage = input.statusMessage;
55
- }
56
- if (input.data) {
57
- err.data = input.data;
73
+ } else if (input.statusText) {
74
+ err.statusMessage = input.statusText;
58
75
  }
59
76
  if (input.fatal !== void 0) {
60
77
  err.fatal = input.fatal;
@@ -349,6 +366,44 @@ function deleteCookie(event, name, serializeOptions) {
349
366
  });
350
367
  }
351
368
 
369
+ async function sendProxy(event, target, opts = {}) {
370
+ const _fetch = opts.fetch || globalThis.fetch;
371
+ if (!_fetch) {
372
+ throw new Error("fetch is not available. Try importing `node-fetch-native/polyfill` for Node.js.");
373
+ }
374
+ const response = await _fetch(target, {
375
+ headers: opts.headers,
376
+ ...opts.fetchOptions
377
+ });
378
+ event.res.statusCode = response.status;
379
+ event.res.statusMessage = response.statusText;
380
+ for (const [key, value] of response.headers.entries()) {
381
+ if (key === "content-encoding") {
382
+ continue;
383
+ }
384
+ if (key === "content-length") {
385
+ continue;
386
+ }
387
+ event.res.setHeader(key, value);
388
+ }
389
+ try {
390
+ if (response.body) {
391
+ if (opts.sendStream === false) {
392
+ const data = new Uint8Array(await response.arrayBuffer());
393
+ event.res.end(data);
394
+ } else {
395
+ for await (const chunk of response.body) {
396
+ event.res.write(chunk);
397
+ }
398
+ event.res.end();
399
+ }
400
+ }
401
+ } catch (err) {
402
+ event.res.end();
403
+ throw err;
404
+ }
405
+ }
406
+
352
407
  class H3Headers {
353
408
  constructor(init) {
354
409
  if (!init) {
@@ -361,6 +416,18 @@ class H3Headers {
361
416
  this._headers = Object.fromEntries(Object.entries(init).map(([key, value]) => [key.toLowerCase(), value]));
362
417
  }
363
418
  }
419
+ [Symbol.iterator]() {
420
+ return this.entries();
421
+ }
422
+ entries() {
423
+ throw Object.entries(this._headers)[Symbol.iterator]();
424
+ }
425
+ keys() {
426
+ return Object.keys(this._headers)[Symbol.iterator]();
427
+ }
428
+ values() {
429
+ throw Object.values(this._headers)[Symbol.iterator]();
430
+ }
364
431
  append(name, value) {
365
432
  const _name = name.toLowerCase();
366
433
  this.set(_name, [this.get(_name), value].filter(Boolean).join(", "));
@@ -700,7 +767,11 @@ function createRouter(opts = {}) {
700
767
  router[method] = (path, handle) => router.add(path, handle, method);
701
768
  }
702
769
  router.handler = eventHandler((event) => {
703
- const path = new URL(event.req.url || "/", "http://localhost").pathname;
770
+ let path = event.req.url || "/";
771
+ const qIndex = path.indexOf("?");
772
+ if (qIndex !== -1) {
773
+ path = path.substring(0, qIndex);
774
+ }
704
775
  const matched = _router.lookup(path);
705
776
  if (!matched) {
706
777
  if (opts.preemtive) {
@@ -778,6 +849,7 @@ exports.readBody = readBody;
778
849
  exports.readRawBody = readRawBody;
779
850
  exports.send = send;
780
851
  exports.sendError = sendError;
852
+ exports.sendProxy = sendProxy;
781
853
  exports.sendRedirect = sendRedirect;
782
854
  exports.sendStream = sendStream;
783
855
  exports.setCookie = setCookie;
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { IncomingMessage, ServerResponse, OutgoingMessage } from 'http';
2
2
  export { IncomingMessage as NodeIncomingMessage, ServerResponse as NodeServerResponse } from 'http';
3
3
  import { CookieSerializeOptions } from 'cookie-es';
4
+ import { RequestHeaders as RequestHeaders$1 } from 'src/types';
4
5
  import * as ufo from 'ufo';
5
6
 
6
7
  declare type HTTPMethod = 'GET' | 'HEAD' | 'PATCH' | 'POST' | 'PUT' | 'DELETE' | 'CONNECT' | 'OPTIONS' | 'TRACE';
@@ -30,6 +31,10 @@ declare function callNodeListener(handler: NodeMiddleware, req: IncomingMessage,
30
31
  declare class H3Headers implements Headers {
31
32
  _headers: Record<string, string>;
32
33
  constructor(init?: HeadersInit);
34
+ [Symbol.iterator](): IterableIterator<[string, string]>;
35
+ entries(): IterableIterator<[string, string]>;
36
+ keys(): IterableIterator<string>;
37
+ values(): IterableIterator<string>;
33
38
  append(name: string, value: string): void;
34
39
  delete(name: string): void;
35
40
  get(name: string): string | null;
@@ -127,6 +132,7 @@ declare function createAppEventHandler(stack: Stack, options: AppOptions): Event
127
132
  */
128
133
  declare class H3Error extends Error {
129
134
  static __h3_error__: boolean;
135
+ toJSON(): Pick<H3Error, "statusCode" | "statusMessage" | "data" | "message">;
130
136
  statusCode: number;
131
137
  fatal: boolean;
132
138
  unhandled: boolean;
@@ -139,7 +145,10 @@ declare class H3Error extends Error {
139
145
  * @param input {Partial<H3Error>}
140
146
  * @return {H3Error} An instance of the H3Error
141
147
  */
142
- declare function createError(input: string | Partial<H3Error>): H3Error;
148
+ declare function createError(input: string | Partial<H3Error> & {
149
+ status?: number;
150
+ statusText?: string;
151
+ }): H3Error;
143
152
  /**
144
153
  * Receive an error and return the corresponding response.<br>
145
154
  * H3 internally uses this function to handle unhandled errors.<br>
@@ -243,6 +252,14 @@ declare function setCookie(event: H3Event, name: string, value: string, serializ
243
252
  */
244
253
  declare function deleteCookie(event: H3Event, name: string, serializeOptions?: CookieSerializeOptions): void;
245
254
 
255
+ interface SendProxyOptions {
256
+ headers?: RequestHeaders$1 | HeadersInit;
257
+ fetchOptions?: RequestInit;
258
+ fetch?: typeof fetch;
259
+ sendStream?: boolean;
260
+ }
261
+ declare function sendProxy(event: H3Event, target: string, opts?: SendProxyOptions): Promise<void>;
262
+
246
263
  declare function getQuery(event: H3Event): ufo.QueryObject;
247
264
  /** @deprecated Use `h3.getQuery` */
248
265
  declare const useQuery: typeof getQuery;
@@ -288,4 +305,4 @@ interface CreateRouterOptions {
288
305
  }
289
306
  declare function createRouter(opts?: CreateRouterOptions): Router;
290
307
 
291
- export { AddRouteShortcuts, App, AppOptions, AppUse, CacheConditions, CreateRouterOptions, DynamicEventHandler, Encoding, EventHandler, EventHandlerResponse, H3Error, H3Event, H3EventContext, H3Headers, H3Response, HTTPMethod, InputLayer, InputStack, Layer, LazyEventHandler, MIMES, Matcher, NodeListener, NodeMiddleware, NodePromisifiedHandler, RequestHeaders, Router, RouterMethod, RouterUse, Stack, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fromNodeMiddleware, getCookie, getHeader, getHeaders, getMethod, getQuery, getRequestHeader, getRequestHeaders, getResponseHeader, getResponseHeaders, getRouterParam, getRouterParams, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, parseCookies, promisifyNodeListener, readBody, readRawBody, send, sendError, sendRedirect, sendStream, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, toEventHandler, toNodeListener, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody, writeEarlyHints };
308
+ export { AddRouteShortcuts, App, AppOptions, AppUse, CacheConditions, CreateRouterOptions, DynamicEventHandler, Encoding, EventHandler, EventHandlerResponse, H3Error, H3Event, H3EventContext, H3Headers, H3Response, HTTPMethod, InputLayer, InputStack, Layer, LazyEventHandler, MIMES, Matcher, NodeListener, NodeMiddleware, NodePromisifiedHandler, RequestHeaders, Router, RouterMethod, RouterUse, SendProxyOptions, Stack, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fromNodeMiddleware, getCookie, getHeader, getHeaders, getMethod, getQuery, getRequestHeader, getRequestHeaders, getResponseHeader, getResponseHeaders, getRouterParam, getRouterParams, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, parseCookies, promisifyNodeListener, readBody, readRawBody, send, sendError, sendProxy, sendRedirect, sendStream, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, toEventHandler, toNodeListener, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody, writeEarlyHints };
package/dist/index.mjs CHANGED
@@ -23,6 +23,19 @@ class H3Error extends Error {
23
23
  this.unhandled = false;
24
24
  this.statusMessage = void 0;
25
25
  }
26
+ toJSON() {
27
+ const obj = {
28
+ message: this.message,
29
+ statusCode: this.statusCode
30
+ };
31
+ if (this.statusMessage) {
32
+ obj.statusMessage = this.statusMessage;
33
+ }
34
+ if (this.data !== void 0) {
35
+ obj.data = this.data;
36
+ }
37
+ return obj;
38
+ }
26
39
  }
27
40
  H3Error.__h3_error__ = true;
28
41
  function createError(input) {
@@ -45,14 +58,18 @@ function createError(input) {
45
58
  }
46
59
  }
47
60
  }
61
+ if (input.data) {
62
+ err.data = input.data;
63
+ }
48
64
  if (input.statusCode) {
49
65
  err.statusCode = input.statusCode;
66
+ } else if (input.status) {
67
+ err.statusCode = input.status;
50
68
  }
51
69
  if (input.statusMessage) {
52
70
  err.statusMessage = input.statusMessage;
53
- }
54
- if (input.data) {
55
- err.data = input.data;
71
+ } else if (input.statusText) {
72
+ err.statusMessage = input.statusText;
56
73
  }
57
74
  if (input.fatal !== void 0) {
58
75
  err.fatal = input.fatal;
@@ -347,6 +364,44 @@ function deleteCookie(event, name, serializeOptions) {
347
364
  });
348
365
  }
349
366
 
367
+ async function sendProxy(event, target, opts = {}) {
368
+ const _fetch = opts.fetch || globalThis.fetch;
369
+ if (!_fetch) {
370
+ throw new Error("fetch is not available. Try importing `node-fetch-native/polyfill` for Node.js.");
371
+ }
372
+ const response = await _fetch(target, {
373
+ headers: opts.headers,
374
+ ...opts.fetchOptions
375
+ });
376
+ event.res.statusCode = response.status;
377
+ event.res.statusMessage = response.statusText;
378
+ for (const [key, value] of response.headers.entries()) {
379
+ if (key === "content-encoding") {
380
+ continue;
381
+ }
382
+ if (key === "content-length") {
383
+ continue;
384
+ }
385
+ event.res.setHeader(key, value);
386
+ }
387
+ try {
388
+ if (response.body) {
389
+ if (opts.sendStream === false) {
390
+ const data = new Uint8Array(await response.arrayBuffer());
391
+ event.res.end(data);
392
+ } else {
393
+ for await (const chunk of response.body) {
394
+ event.res.write(chunk);
395
+ }
396
+ event.res.end();
397
+ }
398
+ }
399
+ } catch (err) {
400
+ event.res.end();
401
+ throw err;
402
+ }
403
+ }
404
+
350
405
  class H3Headers {
351
406
  constructor(init) {
352
407
  if (!init) {
@@ -359,6 +414,18 @@ class H3Headers {
359
414
  this._headers = Object.fromEntries(Object.entries(init).map(([key, value]) => [key.toLowerCase(), value]));
360
415
  }
361
416
  }
417
+ [Symbol.iterator]() {
418
+ return this.entries();
419
+ }
420
+ entries() {
421
+ throw Object.entries(this._headers)[Symbol.iterator]();
422
+ }
423
+ keys() {
424
+ return Object.keys(this._headers)[Symbol.iterator]();
425
+ }
426
+ values() {
427
+ throw Object.values(this._headers)[Symbol.iterator]();
428
+ }
362
429
  append(name, value) {
363
430
  const _name = name.toLowerCase();
364
431
  this.set(_name, [this.get(_name), value].filter(Boolean).join(", "));
@@ -698,7 +765,11 @@ function createRouter(opts = {}) {
698
765
  router[method] = (path, handle) => router.add(path, handle, method);
699
766
  }
700
767
  router.handler = eventHandler((event) => {
701
- const path = new URL(event.req.url || "/", "http://localhost").pathname;
768
+ let path = event.req.url || "/";
769
+ const qIndex = path.indexOf("?");
770
+ if (qIndex !== -1) {
771
+ path = path.substring(0, qIndex);
772
+ }
702
773
  const matched = _router.lookup(path);
703
774
  if (!matched) {
704
775
  if (opts.preemtive) {
@@ -727,4 +798,4 @@ function createRouter(opts = {}) {
727
798
  return router;
728
799
  }
729
800
 
730
- export { H3Error, H3Event, H3Headers, H3Response, MIMES, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fromNodeMiddleware, getCookie, getHeader, getHeaders, getMethod, getQuery, getRequestHeader, getRequestHeaders, getResponseHeader, getResponseHeaders, getRouterParam, getRouterParams, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, parseCookies, promisifyNodeListener, readBody, readRawBody, send, sendError, sendRedirect, sendStream, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, toEventHandler, toNodeListener, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody, writeEarlyHints };
801
+ export { H3Error, H3Event, H3Headers, H3Response, MIMES, appendHeader, appendHeaders, appendResponseHeader, appendResponseHeaders, assertMethod, callNodeListener, createApp, createAppEventHandler, createError, createEvent, createRouter, defaultContentType, defineEventHandler, defineLazyEventHandler, defineNodeListener, defineNodeMiddleware, deleteCookie, dynamicEventHandler, eventHandler, fromNodeMiddleware, getCookie, getHeader, getHeaders, getMethod, getQuery, getRequestHeader, getRequestHeaders, getResponseHeader, getResponseHeaders, getRouterParam, getRouterParams, handleCacheHeaders, isError, isEvent, isEventHandler, isMethod, isStream, lazyEventHandler, parseCookies, promisifyNodeListener, readBody, readRawBody, send, sendError, sendProxy, sendRedirect, sendStream, setCookie, setHeader, setHeaders, setResponseHeader, setResponseHeaders, toEventHandler, toNodeListener, use, useBase, useBody, useCookie, useCookies, useMethod, useQuery, useRawBody, writeEarlyHints };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "h3",
3
- "version": "0.8.5",
3
+ "version": "0.8.6",
4
4
  "description": "Tiny JavaScript Server",
5
5
  "repository": "unjs/h3",
6
6
  "license": "MIT",
@@ -29,23 +29,24 @@
29
29
  "0x": "^5.4.1",
30
30
  "@nuxtjs/eslint-config-typescript": "^11.0.0",
31
31
  "@types/express": "^4.17.14",
32
- "@types/node": "^18.11.0",
32
+ "@types/node": "^18.11.7",
33
33
  "@types/supertest": "^2.0.12",
34
34
  "@vitest/coverage-c8": "^0.24.3",
35
35
  "autocannon": "^7.10.0",
36
36
  "changelogen": "^0.3.5",
37
37
  "connect": "^3.7.0",
38
- "eslint": "^8.25.0",
38
+ "eslint": "^8.26.0",
39
39
  "express": "^4.18.2",
40
40
  "get-port": "^6.1.2",
41
41
  "jiti": "^1.16.0",
42
42
  "listhen": "^0.3.4",
43
- "supertest": "^6.3.0",
43
+ "node-fetch-native": "^0.1.8",
44
+ "supertest": "^6.3.1",
44
45
  "typescript": "^4.8.4",
45
46
  "unbuild": "^0.9.4",
46
47
  "vitest": "^0.24.3"
47
48
  },
48
- "packageManager": "pnpm@7.13.5",
49
+ "packageManager": "pnpm@7.14.0",
49
50
  "scripts": {
50
51
  "build": "unbuild",
51
52
  "dev": "vitest",