@depup/h3 2.0.1-depup.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.
Files changed (73) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +25 -0
  3. package/bin/h3.mjs +36 -0
  4. package/changes.json +5 -0
  5. package/dist/THIRD-PARTY-LICENSES.md +70 -0
  6. package/dist/_entries/bun.d.mts +6 -0
  7. package/dist/_entries/bun.mjs +16 -0
  8. package/dist/_entries/cloudflare.d.mts +6 -0
  9. package/dist/_entries/cloudflare.mjs +16 -0
  10. package/dist/_entries/deno.d.mts +6 -0
  11. package/dist/_entries/deno.mjs +16 -0
  12. package/dist/_entries/generic.d.mts +6 -0
  13. package/dist/_entries/generic.mjs +16 -0
  14. package/dist/_entries/node.d.mts +10 -0
  15. package/dist/_entries/node.mjs +19 -0
  16. package/dist/_entries/service-worker.d.mts +6 -0
  17. package/dist/_entries/service-worker.mjs +16 -0
  18. package/dist/_utils.mjs +240 -0
  19. package/dist/cache.mjs +599 -0
  20. package/dist/cache2.mjs +50 -0
  21. package/dist/cors.mjs +292 -0
  22. package/dist/docs/0.guide/0.index/index.md +117 -0
  23. package/dist/docs/0.guide/1.basics/0.lifecycle.md +68 -0
  24. package/dist/docs/0.guide/1.basics/1.routing.md +167 -0
  25. package/dist/docs/0.guide/1.basics/2.middleware.md +97 -0
  26. package/dist/docs/0.guide/1.basics/3.handler.md +165 -0
  27. package/dist/docs/0.guide/1.basics/4.response.md +171 -0
  28. package/dist/docs/0.guide/1.basics/5.error.md +117 -0
  29. package/dist/docs/0.guide/1.basics/6.nested-apps.md +57 -0
  30. package/dist/docs/0.guide/2.rules.md +698 -0
  31. package/dist/docs/0.guide/3.api/0.h3.md +144 -0
  32. package/dist/docs/0.guide/3.api/1.h3event.md +160 -0
  33. package/dist/docs/0.guide/4.advanced/0.plugins.md +50 -0
  34. package/dist/docs/0.guide/4.advanced/1.websocket.md +176 -0
  35. package/dist/docs/0.guide/4.advanced/2.nightly.md +13 -0
  36. package/dist/docs/1.utils/0.index/index.md +46 -0
  37. package/dist/docs/1.utils/1.request.md +447 -0
  38. package/dist/docs/1.utils/2.response.md +172 -0
  39. package/dist/docs/1.utils/3.cookie.md +33 -0
  40. package/dist/docs/1.utils/4.security.md +175 -0
  41. package/dist/docs/1.utils/5.proxy.md +57 -0
  42. package/dist/docs/1.utils/6.mcp.md +75 -0
  43. package/dist/docs/1.utils/7.more.md +117 -0
  44. package/dist/docs/1.utils/8.community.md +48 -0
  45. package/dist/docs/2.examples/0.index/index.md +17 -0
  46. package/dist/docs/2.examples/1.handle-cookie.md +67 -0
  47. package/dist/docs/2.examples/2.handle-query.md +76 -0
  48. package/dist/docs/2.examples/3.handle-session.md +210 -0
  49. package/dist/docs/2.examples/4.serve-static-assets.md +66 -0
  50. package/dist/docs/2.examples/5.stream-response.md +76 -0
  51. package/dist/docs/2.examples/6.validate-data.md +193 -0
  52. package/dist/docs/3.migration/0.index/index.md +204 -0
  53. package/dist/docs/README.md +37 -0
  54. package/dist/h3.d.mts +1669 -0
  55. package/dist/h3.mjs +1809 -0
  56. package/dist/index.d.mts +1634 -0
  57. package/dist/match.d.mts +123 -0
  58. package/dist/middleware.mjs +123 -0
  59. package/dist/normalize.mjs +645 -0
  60. package/dist/path.mjs +42 -0
  61. package/dist/proxy.mjs +254 -0
  62. package/dist/response.mjs +465 -0
  63. package/dist/rules/cache.d.mts +29 -0
  64. package/dist/rules/cache.mjs +163 -0
  65. package/dist/rules/compiler.d.mts +94 -0
  66. package/dist/rules/compiler.mjs +173 -0
  67. package/dist/rules/index.d.mts +77 -0
  68. package/dist/rules/index.mjs +34 -0
  69. package/dist/rules/proxy.d.mts +3 -0
  70. package/dist/rules/proxy.mjs +14 -0
  71. package/dist/tracing.d.mts +33 -0
  72. package/dist/tracing.mjs +89 -0
  73. package/package.json +148 -0
package/dist/proxy.mjs ADDED
@@ -0,0 +1,254 @@
1
+ import { EmptyObject, HTTPError, HTTPResponse } from "./response.mjs";
2
+ const ignoredHeaders = /* @__PURE__ */ new Set([
3
+ "transfer-encoding",
4
+ "accept-encoding",
5
+ "connection",
6
+ "keep-alive",
7
+ "upgrade",
8
+ "expect",
9
+ "te",
10
+ "trailer",
11
+ "host",
12
+ "proxy-authorization",
13
+ "proxy-connection"
14
+ ]);
15
+ const framingHeaders = /* @__PURE__ */ new Set([
16
+ "connection",
17
+ "keep-alive",
18
+ "transfer-encoding",
19
+ "te",
20
+ "trailer",
21
+ "upgrade",
22
+ "proxy-authorization",
23
+ "proxy-connection"
24
+ ]);
25
+ function connectionTokens(connection) {
26
+ return new Set((connection || "").toLowerCase().split(",").map((name) => name.trim()).filter(Boolean));
27
+ }
28
+ const ignoredResponseHeaders = /* @__PURE__ */ new Set([
29
+ "content-encoding",
30
+ "content-length",
31
+ "transfer-encoding",
32
+ "connection",
33
+ "keep-alive",
34
+ "proxy-authenticate",
35
+ "proxy-connection",
36
+ "upgrade",
37
+ "trailer",
38
+ "te"
39
+ ]);
40
+ function rewriteCookieProperty(header, map, property) {
41
+ const _map = typeof map === "string" ? { "*": map } : map;
42
+ return header.replace(new RegExp(`(;\\s*${property}=)([^;]+)`, "gi"), (match, prefix, previousValue) => {
43
+ let newValue;
44
+ if (Object.hasOwn(_map, previousValue)) newValue = _map[previousValue];
45
+ else if (Object.hasOwn(_map, "*")) newValue = _map["*"];
46
+ else return match;
47
+ return newValue ? prefix + newValue : "";
48
+ });
49
+ }
50
+ function applyXForwardedHeaders(headers, event) {
51
+ const merged = headers instanceof Headers ? headers : new Headers(headers);
52
+ const ip = event.req.ip;
53
+ if (ip) {
54
+ const forwardedFor = merged.get("x-forwarded-for");
55
+ merged.set("x-forwarded-for", forwardedFor ? `${forwardedFor}, ${ip}` : ip);
56
+ }
57
+ const proto = event.url.protocol.slice(0, -1);
58
+ merged.set("x-forwarded-proto", proto);
59
+ merged.set("x-forwarded-host", event.url.host);
60
+ merged.set("x-forwarded-port", event.url.port || (proto === "https" ? "443" : "80"));
61
+ return merged;
62
+ }
63
+ function rewriteLocationHeaders(headers, rewrite, targetOrigin, requestOrigin) {
64
+ const rewriteValue = (value) => rewrite === true ? rewriteOrigin(value, targetOrigin, requestOrigin) : rewritePrefix(value, rewrite);
65
+ const location = headers.get("location");
66
+ if (location) {
67
+ const rewritten = rewriteValue(location);
68
+ if (rewritten) headers.set("location", rewritten);
69
+ }
70
+ const refresh = headers.get("refresh");
71
+ if (refresh) {
72
+ const match = refresh.match(/^(\s*(?:[\d.]+\s*[;,]\s*)?url\s*=\s*)(['"]?)(.*?)\2(\s*)$/i);
73
+ const rewritten = match && rewriteValue(match[3]);
74
+ if (rewritten) headers.set("refresh", match[1] + match[2] + rewritten + match[2] + match[4]);
75
+ }
76
+ }
77
+ function rewriteOrigin(value, targetOrigin, requestOrigin) {
78
+ if (!targetOrigin || targetOrigin === requestOrigin) return;
79
+ const url = value.startsWith("//") ? URL.canParse(value, targetOrigin) ? new URL(value, targetOrigin) : void 0 : URL.canParse(value) ? new URL(value) : void 0;
80
+ if (!url || url.origin !== targetOrigin) return;
81
+ return requestOrigin + url.pathname + url.search + url.hash;
82
+ }
83
+ function rewritePrefix(value, map) {
84
+ for (const prefix of Object.keys(map)) if (value.startsWith(prefix)) return map[prefix] + value.slice(prefix.length);
85
+ }
86
+ function abortable(run, signal) {
87
+ if (signal.aborted) return Promise.reject(signal.reason);
88
+ return new Promise((resolve, reject) => {
89
+ const onAbort = () => reject(signal.reason);
90
+ signal.addEventListener("abort", onAbort, { once: true });
91
+ Promise.resolve(run()).then((value) => {
92
+ signal.removeEventListener("abort", onAbort);
93
+ resolve(value);
94
+ }, (error) => {
95
+ signal.removeEventListener("abort", onAbort);
96
+ reject(error);
97
+ });
98
+ });
99
+ }
100
+ function mergeHeaders(defaults, ...inputs) {
101
+ const _inputs = inputs.filter(Boolean);
102
+ if (_inputs.length === 0) return defaults;
103
+ const merged = new Headers(defaults);
104
+ for (const input of _inputs) {
105
+ const entries = Array.isArray(input) ? input : typeof input.entries === "function" ? input.entries() : Object.entries(input);
106
+ for (const [key, value] of entries) if (value !== void 0) merged.set(key, value);
107
+ }
108
+ return merged;
109
+ }
110
+ async function proxyRequest(event, target, opts = {}) {
111
+ const method = opts.fetchOptions?.method || event.req.method;
112
+ const methodUpper = method.toUpperCase();
113
+ const incomingBody = event.req.body;
114
+ const requestBody = incomingBody != null && methodUpper !== "GET" && methodUpper !== "HEAD" ? incomingBody : void 0;
115
+ const proxyHeaders = getProxyRequestHeaders(event, {
116
+ host: target.startsWith("/"),
117
+ forwardHeaders: opts.forwardHeaders,
118
+ filterHeaders: opts.filterHeaders
119
+ });
120
+ const fetchHeaders = mergeHeaders(opts.xfwd ? applyXForwardedHeaders(proxyHeaders, event) : proxyHeaders, opts.fetchOptions?.headers, opts.headers);
121
+ if (opts.fetchOptions && "body" in opts.fetchOptions || incomingBody && !requestBody) {
122
+ if (fetchHeaders instanceof Headers) fetchHeaders.delete("content-length");
123
+ else if (!Array.isArray(fetchHeaders)) delete fetchHeaders["content-length"];
124
+ }
125
+ const fetchBody = opts.fetchOptions?.body ?? requestBody;
126
+ return proxy(event, target, {
127
+ ...opts,
128
+ fetchOptions: {
129
+ method,
130
+ body: requestBody,
131
+ ...opts.fetchOptions,
132
+ duplex: opts.fetchOptions?.duplex ?? (fetchBody != null ? "half" : void 0),
133
+ headers: fetchHeaders
134
+ }
135
+ });
136
+ }
137
+ async function proxy(event, target, opts = {}) {
138
+ const signals = [event.req.signal];
139
+ if (opts.fetchOptions?.signal) signals.push(opts.fetchOptions.signal);
140
+ let timeoutId;
141
+ if (opts.timeout > 0 && Number.isFinite(opts.timeout)) {
142
+ const timeoutController = new AbortController();
143
+ timeoutId = setTimeout(() => timeoutController.abort(new DOMException("Proxy request timed out", "TimeoutError")), Math.min(Math.max(Math.trunc(opts.timeout), 1), 2147483647));
144
+ signals.push(timeoutController.signal);
145
+ }
146
+ const signal = signals.length > 1 ? AbortSignal.any(signals) : signals[0];
147
+ const fetchOptions = {
148
+ headers: opts.headers,
149
+ ...opts.fetchOptions,
150
+ redirect: opts.fetchOptions?.redirect ?? "manual",
151
+ signal
152
+ };
153
+ let response;
154
+ try {
155
+ response = target[0] === "/" ? await abortable(() => event.app.fetch(createSubRequest(event, target, fetchOptions)), signal) : await fetch(target, fetchOptions);
156
+ } catch (error) {
157
+ if ((signal.aborted ? signal.reason : void 0)?.name === "TimeoutError" || error?.name === "TimeoutError") throw new HTTPError({
158
+ status: 504,
159
+ statusText: "Gateway Timeout",
160
+ cause: error
161
+ });
162
+ if (signal.aborted || error?.name === "AbortError") {
163
+ if (opts.propagateAbortError) throw error;
164
+ if (event.req.signal.aborted) return new HTTPResponse(null, {
165
+ status: 499,
166
+ statusText: "Client Closed Request"
167
+ });
168
+ }
169
+ throw new HTTPError("Bad Gateway", {
170
+ status: 502,
171
+ statusText: "Bad Gateway",
172
+ cause: error
173
+ });
174
+ } finally {
175
+ if (timeoutId !== void 0) clearTimeout(timeoutId);
176
+ }
177
+ if (response.type === "opaqueredirect") throw new HTTPError({
178
+ status: 502,
179
+ message: "Cannot relay an opaque redirect response on this runtime. Set `fetchOptions: { redirect: \"follow\" }` to follow upstream redirects instead."
180
+ });
181
+ if (response.type === "opaque" || response.type === "error" || response.status === 0) throw new HTTPError({
182
+ status: 502,
183
+ message: "Cannot relay an opaque or errored upstream response (status 0), typically caused by a `no-cors` request mode on browser/service-worker runtimes."
184
+ });
185
+ const headers = new Headers();
186
+ const connectionNominated = connectionTokens(response.headers.get("connection"));
187
+ for (const [key, value] of response.headers.entries()) {
188
+ if (ignoredResponseHeaders.has(key) || connectionNominated.has(key) || key === "set-cookie") continue;
189
+ headers.append(key, value);
190
+ }
191
+ const cookies = response.headers.getSetCookie();
192
+ if (cookies.length > 0) {
193
+ const _cookies = cookies.map((cookie) => {
194
+ if (opts.cookieDomainRewrite) cookie = rewriteCookieProperty(cookie, opts.cookieDomainRewrite, "domain");
195
+ if (opts.cookiePathRewrite) cookie = rewriteCookieProperty(cookie, opts.cookiePathRewrite, "path");
196
+ return cookie;
197
+ });
198
+ for (const cookie of _cookies) headers.append("set-cookie", cookie);
199
+ }
200
+ const locationRewrite = opts.locationRewrite ?? true;
201
+ if (locationRewrite !== false && (locationRewrite !== true || target[0] !== "/")) rewriteLocationHeaders(headers, locationRewrite, target[0] === "/" ? void 0 : new URL(target).origin, event.url.origin);
202
+ if (opts.onResponse) await opts.onResponse(event, response);
203
+ return new HTTPResponse(response.body, {
204
+ status: response.status,
205
+ statusText: response.statusText,
206
+ headers
207
+ });
208
+ }
209
+ function getProxyRequestHeaders(event, opts) {
210
+ const headers = new EmptyObject();
211
+ const filterHeaders = opts?.filterHeaders?.map((h) => h.toLowerCase());
212
+ const forwardHeaders = opts?.forwardHeaders?.map((h) => h.toLowerCase());
213
+ const connectionNominated = connectionTokens(event.req.headers.get("connection"));
214
+ for (const [name, value] of event.req.headers.entries()) {
215
+ if (filterHeaders?.includes(name)) continue;
216
+ if (forwardHeaders?.includes(name) && !framingHeaders.has(name) && !connectionNominated.has(name)) {
217
+ headers[name] = value;
218
+ continue;
219
+ }
220
+ if (connectionNominated.has(name)) continue;
221
+ if (!ignoredHeaders.has(name) || name === "host" && opts?.host) {
222
+ headers[name] = value;
223
+ continue;
224
+ }
225
+ }
226
+ return headers;
227
+ }
228
+ async function fetchWithEvent(event, url, init) {
229
+ if (url[0] !== "/") {
230
+ if (init?.body != null && init.duplex === void 0) init = {
231
+ ...init,
232
+ duplex: "half"
233
+ };
234
+ return fetch(url, init);
235
+ }
236
+ return event.app.fetch(createSubRequest(event, url, {
237
+ ...init,
238
+ headers: mergeHeaders(getProxyRequestHeaders(event, { host: true }), init?.headers)
239
+ }));
240
+ }
241
+ function createSubRequest(event, path, init) {
242
+ const url = new URL(path.replace(LEADING_SEPARATOR_RUN_RE, "/"), event.url);
243
+ if (init.body != null && init.duplex === void 0) init = {
244
+ ...init,
245
+ duplex: "half"
246
+ };
247
+ const req = new Request(url, init);
248
+ req.runtime = event.req.runtime;
249
+ req.waitUntil = event.req.waitUntil;
250
+ req.ip = event.req.ip;
251
+ return req;
252
+ }
253
+ const LEADING_SEPARATOR_RUN_RE = /^(?:[/\\]|[\t\n\r])+/;
254
+ export { fetchWithEvent, getProxyRequestHeaders, proxy, proxyRequest };