@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
@@ -0,0 +1,94 @@
1
+ import { RouteRuleConfig } from "../h3.mjs";
2
+ import { MatcherMemoizeOptions } from "../match.mjs";
3
+
4
+ export declare const DEFAULT_RUNTIME_RULES: Readonly<Record<string, RuntimeRuleImport>>;
5
+ /** Module and optional named export for a generated rule-handler import. */
6
+ type RuntimeRuleImport = string | RuntimeRuleImportSpec;
7
+ interface RuntimeRuleImportSpec {
8
+ source: string;
9
+ /**
10
+ * Named export within `source`; must be a valid JS identifier (becomes an
11
+ * import binding in generated code).
12
+ * @default the rule key
13
+ */
14
+ export?: string;
15
+ }
16
+ interface CompileRouteRulesOptions {
17
+ /** Base URL prefix for all rule patterns (trailing slash trimmed). */
18
+ baseURL?: string;
19
+ /**
20
+ * Identifier prefix for imported handlers in generated code (handler `name`
21
+ * binds as `<prefix>$<name>`).
22
+ * @default "__ruleHandlers__"
23
+ */
24
+ handlersImportName?: string;
25
+ /**
26
+ * Runtime rules keyed by rule name, merged **over** `DEFAULT_RUNTIME_RULES`
27
+ * (list only additions/overrides). Keys bind as JS identifiers in generated
28
+ * code.
29
+ * @default DEFAULT_RUNTIME_RULES
30
+ */
31
+ runtimeRules?: Record<string, RuntimeRuleImport>;
32
+ /**
33
+ * Pre-merge each pattern's subsumption chain at compile time (exact, but
34
+ * requires a **chain-clean** rule set). Unlike the runtime matcher, the
35
+ * compiler is fail-safe: a non-chain-clean set emits a `console.warn` and
36
+ * falls back to plain compilation instead of throwing.
37
+ */
38
+ preMerge?: boolean;
39
+ }
40
+ /**
41
+ * Optional generated matcher export. A string sets its name; object form can
42
+ * also enable memoization.
43
+ */
44
+ type MatcherExport = boolean | string | {
45
+ name?: string;
46
+ memoize?: boolean | MatcherMemoizeOptions;
47
+ };
48
+ /** Options for compiling a complete route-rules module. */
49
+ interface CompileModuleOptions extends CompileRouteRulesOptions {
50
+ /**
51
+ * Also emit a ready-to-use matcher export. See {@link MatcherExport}.
52
+ * @default false
53
+ */
54
+ matcher?: MatcherExport;
55
+ }
56
+ /** Compiled module source, also split into composable imports and body. */
57
+ interface CompiledRouteRules {
58
+ /**
59
+ * Handler import statements ({@link compileHandlersImport} output); empty
60
+ * for a data-only rule set. Includes the matcher infra import when one is
61
+ * requested.
62
+ */
63
+ imports: string;
64
+ /**
65
+ * `findRouteRules` export declaration (no imports), plus the matcher
66
+ * declaration when requested. References bindings {@link imports} brings
67
+ * into scope.
68
+ */
69
+ body: string;
70
+ /** The complete module source — {@link imports} then {@link body}. Same as `toString()`. */
71
+ code: string;
72
+ /** The complete module source ({@link code}), so the result interpolates as a string. */
73
+ toString(): string;
74
+ }
75
+ /**
76
+ * Compile a rule set into a complete ESM module exporting `findRouteRules`
77
+ * (and, with `matcher`, a ready-to-use matcher). Input is normalized
78
+ * internally — pass authored config or already-normalized rules.
79
+ */
80
+ export declare function compileRouteRules(config: Record<string, RouteRuleConfig>, opts?: CompileModuleOptions): CompiledRouteRules;
81
+ /**
82
+ * Compile a rule set into the source of a `findRouteRules(method, pathname)`
83
+ * function expression. Entries reference handler constructors as
84
+ * `<handlersImportName>$<name>` bindings — pair with
85
+ * {@link compileHandlersImport} (which imports exactly those names).
86
+ */
87
+ export declare function compileFindRouteRules(config: Record<string, RouteRuleConfig>, opts?: CompileRouteRulesOptions): string;
88
+ /**
89
+ * Import statement for exactly the handlers the rule set references (empty
90
+ * string if none), keeping unused handlers' deps (e.g. ocache) tree-shakeable.
91
+ * Input is normalized internally, so e.g. an `swr` shortcut counts as `cache`.
92
+ */
93
+ export declare function compileHandlersImport(config: Record<string, RouteRuleConfig>, opts?: CompileRouteRulesOptions): string;
94
+ export type { CompileModuleOptions, CompileRouteRulesOptions, CompiledRouteRules, MatcherExport, RuntimeRuleImport, RuntimeRuleImportSpec };
@@ -0,0 +1,173 @@
1
+ import { createRulesRouter, normalizeRouteRules, parseRouteKey } from "../normalize.mjs";
2
+ import { compareRoutes } from "rou3";
3
+ import { compileRouterToString } from "rou3/compiler";
4
+ const DEFAULT_RUNTIME_RULES = Object.freeze({
5
+ headers: "h3/rules",
6
+ redirect: "h3/rules",
7
+ proxy: "h3/rules/proxy",
8
+ cache: "h3/rules/cache",
9
+ cors: "h3/rules"
10
+ });
11
+ function resolveRuntimeRules(runtimeRules) {
12
+ return runtimeRules ? {
13
+ ...DEFAULT_RUNTIME_RULES,
14
+ ...runtimeRules
15
+ } : DEFAULT_RUNTIME_RULES;
16
+ }
17
+ function isRuntimeRule(name, runtimeRules) {
18
+ return Object.hasOwn(runtimeRules, name);
19
+ }
20
+ function resolveRuntimeRule(name, runtimeRules) {
21
+ const entry = runtimeRules[name];
22
+ return typeof entry === "string" ? {
23
+ source: entry,
24
+ export: name
25
+ } : {
26
+ source: entry.source,
27
+ export: entry.export ?? name
28
+ };
29
+ }
30
+ function serializePreMergedRouteRules(data, ns, runtimeRules) {
31
+ const resets = data.resets?.length ? `,resets:${JSON.stringify(data.resets)}` : "";
32
+ return `{route:${JSON.stringify(data.route)},rank:${data.rank}${resets},rules:${serializeRouteRuleEntries(data.rules, ns, runtimeRules)}}`;
33
+ }
34
+ function serializeRouteRuleEntries(entries, ns, runtimeRules) {
35
+ return `[${entries.map((entry) => {
36
+ const runtime = isRuntimeRule(entry.name, runtimeRules);
37
+ if (runtime) assertHandlerBinding(entry.name, "runtime rule name");
38
+ assertSerializableOptions(entry.options, entry, "options");
39
+ return [
40
+ `name:${JSON.stringify(entry.name)}`,
41
+ `route:${JSON.stringify(entry.route)}`,
42
+ runtime && `handler:${ns}$${entry.name}`,
43
+ `options:${JSON.stringify(entry.options)}`,
44
+ entry.rank && `rank:${entry.rank}`,
45
+ entry.paramRoutes && `paramRoutes:${JSON.stringify(entry.paramRoutes)}`
46
+ ].filter(Boolean).join(",");
47
+ }).map((fields) => `{${fields}}`).join(",")}]`;
48
+ }
49
+ const DEFAULT_MATCHER_EXPORT_NAME = "matcher";
50
+ function compileMatcherExport(matcher, overridePredicate) {
51
+ if (!matcher) return null;
52
+ const spec = typeof matcher === "string" ? { name: matcher } : matcher === true ? {} : matcher;
53
+ const name = spec.name || DEFAULT_MATCHER_EXPORT_NAME;
54
+ assertHandlerBinding(name, "matcher export name");
55
+ const { memoize } = spec;
56
+ let expr = `createMatcherFromFind(findRouteRules, ${overridePredicate})`;
57
+ if (memoize) {
58
+ const max = memoize === true ? void 0 : memoize.max;
59
+ expr = max === void 0 ? `memoizeRouteRulesMatcher(${expr})` : `memoizeRouteRulesMatcher(${expr}, { max: ${JSON.stringify(max)} })`;
60
+ }
61
+ return {
62
+ imports: `import { createMatcherFromFind${memoize ? ", memoizeRouteRulesMatcher" : ""} } from "h3/rules";`,
63
+ body: `export const ${name} = ${expr};\n`
64
+ };
65
+ }
66
+ function compileOverridePredicate(routes) {
67
+ const sorted = [...routes].sort();
68
+ const allowed = /* @__PURE__ */ new Map();
69
+ for (const current of sorted) for (const incoming of sorted) {
70
+ if (current === incoming) continue;
71
+ const rel = compareRoutes(current, incoming);
72
+ if (rel === "superset" || rel === "equal") {
73
+ let list = allowed.get(current);
74
+ if (!list) allowed.set(current, list = []);
75
+ list.push(incoming);
76
+ }
77
+ }
78
+ if (allowed.size === 0) return "(a, b) => a === b";
79
+ return `/* @__PURE__ */ (() => { const t = new Map([${[...allowed].map(([current, list]) => `[${JSON.stringify(current)}, new Set(${JSON.stringify(list)})]`).join(", ")}]); return (a, b) => a === b || (t.get(a)?.has(b) ?? false); })()`;
80
+ }
81
+ function assertHandlerBinding(name, what) {
82
+ if (!JS_IDENTIFIER_RE.test(name)) throw new Error(`[h3] rules: compiler: ${what} \`${name}\` is not a valid JS identifier — it is used as a binding in generated code`);
83
+ }
84
+ const JS_IDENTIFIER_RE = /^[A-Za-z_$][\w$]*$/;
85
+ function assertSerializableOptions(value, entry, path) {
86
+ if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number" && Number.isFinite(value)) return;
87
+ if (Array.isArray(value)) {
88
+ for (const [i, item] of value.entries()) assertSerializableOptions(item, entry, `${path}[${i}]`);
89
+ return;
90
+ }
91
+ const proto = typeof value === "object" ? Object.getPrototypeOf(value) : void 0;
92
+ if (proto === Object.prototype || proto === null) {
93
+ for (const [key, item] of Object.entries(value)) {
94
+ if (key === "__proto__") throw new Error(`[h3] rules: compiler: \`${entry.name}\` rule for \`${entry.route}\` has a \`__proto__\` key at \`${path}\` — it cannot be embedded as a JS object literal without changing the object's prototype (its JSON.stringify output would diverge from the runtime matcher); rename or remove it`);
95
+ assertSerializableOptions(item, entry, `${path}.${key}`);
96
+ }
97
+ return;
98
+ }
99
+ const kind = typeof value === "object" ? value.constructor?.name || "object" : typeof value;
100
+ throw new Error(`[h3] rules: compiler: \`${entry.name}\` rule for \`${entry.route}\` has a non-JSON-serializable value at \`${path}\` (${kind}) — compiled rule options must survive a JSON round-trip`);
101
+ }
102
+ function compileRouteRules(config, opts = {}) {
103
+ const ctx = resolveCompileCtx(config, opts);
104
+ const handlerImports = emitHandlersImport(ctx);
105
+ const matcherExport = opts.matcher ? compileMatcherExport(opts.matcher, compileOverridePredicate(collectRoutes(ctx))) : null;
106
+ const imports = [handlerImports, matcherExport?.imports].filter(Boolean).join("\n");
107
+ const find = `export const findRouteRules = ${emitFindRouteRules(ctx)};\n`;
108
+ const body = matcherExport ? find + matcherExport.body : find;
109
+ const code = `${imports ? imports + "\n" : ""}${body}`;
110
+ return {
111
+ imports,
112
+ body,
113
+ code,
114
+ toString: () => code
115
+ };
116
+ }
117
+ function compileFindRouteRules(config, opts = {}) {
118
+ return emitFindRouteRules(resolveCompileCtx(config, opts));
119
+ }
120
+ function compileHandlersImport(config, opts = {}) {
121
+ return emitHandlersImport(resolveCompileCtx(config, opts));
122
+ }
123
+ function resolveCompileCtx(config, opts) {
124
+ const rules = normalizeRouteRules(config);
125
+ const ns = opts.handlersImportName || "__ruleHandlers__";
126
+ assertHandlerBinding(ns, "handlersImportName");
127
+ const ctx = {
128
+ rules,
129
+ preMerge: false,
130
+ runtimeRules: resolveRuntimeRules(opts.runtimeRules),
131
+ ns,
132
+ baseURL: opts.baseURL
133
+ };
134
+ if (opts.preMerge) try {
135
+ ctx.router = createRulesRouter(rules, {}, opts.baseURL, true);
136
+ ctx.preMerge = true;
137
+ } catch (error) {
138
+ console.warn(`[h3] rules: compiler: preMerge could not be applied — falling back to plain compilation.\n ${error.message}`);
139
+ }
140
+ return ctx;
141
+ }
142
+ function emitFindRouteRules(ctx) {
143
+ const router = ctx.router ?? createRulesRouter(ctx.rules, {}, ctx.baseURL, ctx.preMerge);
144
+ return compileRouterToString(router, {
145
+ matchAll: true,
146
+ serialize: (data) => Array.isArray(data) ? serializeRouteRuleEntries(data, ctx.ns, ctx.runtimeRules) : serializePreMergedRouteRules(data, ctx.ns, ctx.runtimeRules)
147
+ });
148
+ }
149
+ function emitHandlersImport(ctx) {
150
+ const names = usedRuleHandlerNames(ctx);
151
+ if (names.length === 0) return "";
152
+ const bySource = /* @__PURE__ */ new Map();
153
+ for (const name of names) {
154
+ assertHandlerBinding(name, "runtime rule name");
155
+ const { source, export: exportName } = resolveRuntimeRule(name, ctx.runtimeRules);
156
+ assertHandlerBinding(exportName, "runtime rule export");
157
+ let specs = bySource.get(source);
158
+ if (!specs) bySource.set(source, specs = []);
159
+ specs.push(`${exportName} as ${ctx.ns}$${name}`);
160
+ }
161
+ return [...bySource.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([source, specs]) => `import { ${specs.join(", ")} } from ${JSON.stringify(source)};`).join("\n");
162
+ }
163
+ function collectRoutes(ctx) {
164
+ const routes = /* @__PURE__ */ new Set();
165
+ for (const key in ctx.rules) routes.add(parseRouteKey(key).path);
166
+ return [...routes];
167
+ }
168
+ function usedRuleHandlerNames(ctx) {
169
+ const used = /* @__PURE__ */ new Set();
170
+ for (const key in ctx.rules) for (const [name, options] of Object.entries(ctx.rules[key])) if (options !== void 0 && (options !== false || !ctx.preMerge) && isRuntimeRule(name, ctx.runtimeRules)) used.add(name);
171
+ return [...used].sort();
172
+ }
173
+ export { DEFAULT_RUNTIME_RULES, compileFindRouteRules, compileHandlersImport, compileRouteRules };
@@ -0,0 +1,77 @@
1
+ import { BuiltinRouteRules, CacheRuleOptions, EventHandler, H3Event, HTTPStatus, MatchResult, MatchedRouteRule, MatchedRouteRules, Middleware, NormalizedRouteRules, ProxyRuleOptions, RedirectRuleOptions, ResolvedRouteRules, RouteRuleConfig, RouteRules, RuleHandler, RuleHandlers } from "../h3.mjs";
2
+ import { FindRouteRules, MatcherMemoizeOptions, RouteRuleEntry, RouteRuleLayer, RouteRulesMatcher, RouteRulesMatcherOptions, createMatcherFromFind, createRouteRulesMatcher, memoizeRouteRulesMatcher, mergeMatchedRouteRules } from "../match.mjs";
3
+
4
+ interface RouteRulesOptions extends RouteRulesMatcherOptions {
5
+ /**
6
+ * Memoize matches by method and pathname. Enabled by default with a 1024-entry
7
+ * cap; shared results must be treated as read-only.
8
+ * @default true
9
+ */
10
+ memoize?: boolean | MatcherMemoizeOptions;
11
+ }
12
+ /**
13
+ * Match route rules, expose merged options on `event.context.routeRules`, and
14
+ * run their middleware before the route handler.
15
+ *
16
+ * Results are memoized and shared by default; treat exposed rule options as
17
+ * read-only or disable memoization.
18
+ */
19
+ export declare function routeRules(config: Record<string, RouteRuleConfig>, opts?: RouteRulesOptions): Middleware;
20
+ /**
21
+ * Normalize authored route rules by expanding shortcuts, canonicalizing keys,
22
+ * and validating built-in options. Custom rules pass through unchanged.
23
+ */
24
+ export declare function normalizeRouteRules(config: Record<string, RouteRuleConfig>): Record<string, NormalizedRouteRules>;
25
+ /**
26
+ * Default handler registry. Cache and proxy handlers are opt-in from their
27
+ * subpath exports; set either to `undefined` explicitly for data-only rules.
28
+ */
29
+ export declare const ruleHandlers: RuleHandlers;
30
+ export declare const headers: RuleHandler<"headers">;
31
+ export declare const redirect: RuleHandler<"redirect">;
32
+ export declare const cors: RuleHandler<"cors">;
33
+ /** Wrap an event handler with an injected cache implementation. */
34
+ type DefineCachedHandler = (handler: EventHandler, opts: CacheRuleOptions) => EventHandler;
35
+ /** Options for {@link createCacheRuleHandler}. */
36
+ interface CacheRuleHandlerOptions {
37
+ /** Creates the cached wrapper for a matched route handler. */
38
+ defineCachedHandler: DefineCachedHandler;
39
+ /**
40
+ * Requests the implementation never reads or writes a cache entry for.
41
+ * The rule continues the middleware chain for them instead of dispatching the
42
+ * matched route itself, so an uncacheable request reaches the rest of the app
43
+ * the way a CDN passes one through to its origin. Without it, *every* request
44
+ * to a matched route terminates the chain, whether or not it is cached.
45
+ */
46
+ shouldBypass?: (event: H3Event) => boolean;
47
+ /** Default options merged into every cache rule (rule options win). */
48
+ defaults?: CacheRuleOptions;
49
+ /**
50
+ * Stable cache-key scope. By default, a process-unique scope isolates apps
51
+ * but prevents persistent cache sharing across processes.
52
+ */
53
+ id?: string;
54
+ }
55
+ /**
56
+ * Create a `cache` rule handler from an injected cache wrapper.
57
+ *
58
+ * Cache keys are isolated by handler, method, and route unless `id` or an
59
+ * explicit cache `name` opts into sharing.
60
+ *
61
+ * Registering `routeRules()` as *route* middleware puts this rule inside the
62
+ * handler it dispatches; the re-entrant pass falls through (see {@link dispatching}).
63
+ *
64
+ * Register `routeRules()` after every global middleware that must run for a
65
+ * cached route: this handler dispatches the matched route handler itself rather
66
+ * than calling `next()`, so global middleware registered after `routeRules()` is
67
+ * skipped on *every* cacheable request to a `cache`-matched route — misses
68
+ * included, not only hits. Per-route middleware is unaffected (it is part of the
69
+ * dispatched `~composed` pair).
70
+ *
71
+ * Requests the implementation reports as uncacheable through
72
+ * {@link CacheRuleHandlerOptions.shouldBypass} continue down the chain instead
73
+ * of being dispatched from inside the rule, so which global middleware runs for
74
+ * a matched route can depend on the request.
75
+ */
76
+ export declare function createCacheRuleHandler(opts: CacheRuleHandlerOptions): RuleHandler<"cache">;
77
+ export { type BuiltinRouteRules, type CacheRuleHandlerOptions, type CacheRuleOptions, type DefineCachedHandler, type FindRouteRules, type HTTPStatus, type MatchResult, type MatchedRouteRule, type MatchedRouteRules, type MatcherMemoizeOptions, type NormalizedRouteRules, type ProxyRuleOptions, type RedirectRuleOptions, type ResolvedRouteRules, type RouteRuleConfig, type RouteRuleEntry, type RouteRuleLayer, type RouteRules, type RouteRulesMatcher, type RouteRulesMatcherOptions, type RouteRulesOptions, type RuleHandler, type RuleHandlers, createMatcherFromFind, createRouteRulesMatcher, memoizeRouteRulesMatcher, mergeMatchedRouteRules };
@@ -0,0 +1,34 @@
1
+ import { callMiddleware } from "../middleware.mjs";
2
+ import { isPreflightRequest } from "../cors.mjs";
3
+ import { HTTP_METHODS, buildRouteRuleMiddleware, cors, createMatcherFromFind, createRouteRulesMatcher, headers, memoizeRouteRulesMatcher, mergeMatchedRouteRules, normalizeRouteRules, redirect, ruleHandlers } from "../normalize.mjs";
4
+ import { createCacheRuleHandler } from "../cache2.mjs";
5
+ function routeRules(config, opts) {
6
+ const memoize = opts?.memoize ?? true;
7
+ const matcher = createRouteRulesMatcher(normalizeRouteRules(config), opts);
8
+ const match = memoize ? memoizeRouteRulesMatcher(matcher, memoize === true ? void 0 : memoize) : matcher;
9
+ return function routeRulesMiddleware(event, next) {
10
+ const pathname = event.url.pathname;
11
+ const method = event.req.method.toUpperCase();
12
+ let matched = match(method, pathname);
13
+ if (method === "OPTIONS" && isPreflightRequest(event)) matched = liftPreflightCors(matched, match, event, pathname);
14
+ const { routeRules, routeRuleMiddleware } = matched;
15
+ const prev = event.context.routeRules;
16
+ event.context.routeRules = prev ? Object.assign(Object.create(null), prev, routeRules) : routeRules;
17
+ return routeRuleMiddleware.length > 0 ? callMiddleware(event, routeRuleMiddleware, () => next()) : next();
18
+ };
19
+ }
20
+ function liftPreflightCors(matched, match, event, pathname) {
21
+ const requested = event.req.headers.get("access-control-request-method");
22
+ if (!requested) return matched;
23
+ const method = requested.toUpperCase();
24
+ if (method === "OPTIONS" || !HTTP_METHODS.has(method)) return matched;
25
+ const cors = match(method, pathname).matchedRules.cors;
26
+ if (!cors || cors === matched.matchedRules.cors) return matched;
27
+ const matchedRules = Object.assign(Object.create(null), matched.matchedRules, { cors });
28
+ return {
29
+ routeRules: Object.assign(Object.create(null), matched.routeRules, { cors: cors.options }),
30
+ matchedRules,
31
+ routeRuleMiddleware: buildRouteRuleMiddleware(matchedRules)
32
+ };
33
+ }
34
+ export { cors, createCacheRuleHandler, createMatcherFromFind, createRouteRulesMatcher, headers, memoizeRouteRulesMatcher, mergeMatchedRouteRules, normalizeRouteRules, redirect, routeRules, ruleHandlers };
@@ -0,0 +1,3 @@
1
+ import { RuleHandler } from "../h3.mjs";
2
+
3
+ export declare const proxy: RuleHandler<"proxy">;
@@ -0,0 +1,14 @@
1
+ import { proxyRequest } from "../proxy.mjs";
2
+ import { prepareRuleTarget } from "../_utils.mjs";
3
+ const proxy = {
4
+ order: 2,
5
+ handler: (m) => {
6
+ const options = m.options;
7
+ const resolveTarget = prepareRuleTarget(options);
8
+ if (!resolveTarget) return function proxyRouteRule() {};
9
+ return function proxyRouteRule(event) {
10
+ return proxyRequest(event, resolveTarget(event), { ...options });
11
+ };
12
+ }
13
+ };
14
+ export { proxy };
@@ -0,0 +1,33 @@
1
+ import { EventHandler, H3Event, H3Plugin } from "./h3.mjs";
2
+
3
+ export interface TracingRequestEvent {
4
+ type: "middleware" | "route";
5
+ event: H3Event;
6
+ }
7
+ /**
8
+ * Options for the tracing plugin.
9
+ */
10
+ export interface TracingPluginOptions {
11
+ /**
12
+ * Whether to trace middleware executions.
13
+ */
14
+ traceMiddleware?: boolean;
15
+ /**
16
+ * Whether to trace route executions.
17
+ */
18
+ traceRoutes?: boolean;
19
+ }
20
+ /**
21
+ * Enables tracing for H3 apps.
22
+ */
23
+ export declare function tracingPlugin(traceOpts?: TracingPluginOptions): H3Plugin;
24
+ /**
25
+ * Wraps an event handler so its execution is traced via the `h3.request`
26
+ * diagnostics channel with `type: "route"`. Intended to be called once per
27
+ * handler at initialization time (e.g. during codegen or module load), not
28
+ * per request.
29
+ *
30
+ * Returns the handler unchanged when `diagnostics_channel` is unavailable
31
+ * or the handler is already traced.
32
+ */
33
+ export declare function wrapHandlerWithTracing(handler: EventHandler): EventHandler;
@@ -0,0 +1,89 @@
1
+ function tracingPlugin(traceOpts) {
2
+ return (h3) => {
3
+ const { tracingChannel } = globalThis.process?.getBuiltinModule?.("diagnostics_channel") ?? {};
4
+ if (!tracingChannel) return;
5
+ const requestHandlerChannel = tracingChannel("h3.request");
6
+ function wrapMiddleware(middleware) {
7
+ if (middleware.__traced__ || traceOpts?.traceMiddleware === false) return middleware;
8
+ const wrappedMiddleware = (...args) => {
9
+ return requestHandlerChannel.tracePromise(async () => middleware(...args), {
10
+ event: args[0],
11
+ type: "middleware"
12
+ });
13
+ };
14
+ wrappedMiddleware.__traced__ = true;
15
+ return wrappedMiddleware;
16
+ }
17
+ function wrapEventHandler(handler) {
18
+ if (handler.__traced__ || traceOpts?.traceRoutes === false) return handler;
19
+ const wrappedHandler = (...args) => {
20
+ return requestHandlerChannel.tracePromise(async () => handler(...args), {
21
+ event: args[0],
22
+ type: "route"
23
+ });
24
+ };
25
+ wrappedHandler.__traced__ = true;
26
+ return wrappedHandler;
27
+ }
28
+ h3["~middleware"] = h3["~middleware"].map((m) => wrapMiddleware(m));
29
+ h3["~routes"] = h3["~routes"].map((route) => {
30
+ return {
31
+ ...route,
32
+ handler: wrapEventHandler(route.handler),
33
+ middleware: route.middleware ? route.middleware.map((m) => wrapMiddleware(m)) : void 0
34
+ };
35
+ });
36
+ if ("on" in h3 && typeof h3.on === "function") {
37
+ const originalOn = h3.on;
38
+ h3.on = (...args) => {
39
+ const instance = originalOn.apply(h3, args);
40
+ const lastRoute = instance["~routes"][instance["~routes"].length - 1];
41
+ if (lastRoute) {
42
+ lastRoute.handler = wrapEventHandler(lastRoute.handler);
43
+ lastRoute.middleware = lastRoute.middleware?.map((m) => wrapMiddleware(m));
44
+ }
45
+ return instance;
46
+ };
47
+ }
48
+ if ("use" in h3 && typeof h3.use === "function") {
49
+ const originalUse = h3.use;
50
+ h3.use = (arg1, arg2, arg3) => {
51
+ let route;
52
+ let fn;
53
+ let opts;
54
+ if (typeof arg1 === "string") {
55
+ route = arg1;
56
+ fn = arg2;
57
+ opts = arg3;
58
+ return originalUse.call(h3, route, wrapMiddleware(fn), opts);
59
+ }
60
+ fn = arg1;
61
+ opts = arg2;
62
+ return originalUse.call(h3, wrapMiddleware(fn), opts);
63
+ };
64
+ }
65
+ if ("mount" in h3 && typeof h3.mount === "function") {
66
+ const originalMount = h3.mount;
67
+ h3.mount = (base, input) => {
68
+ if ("register" in input) input.register(tracingPlugin(traceOpts));
69
+ return originalMount.call(h3, base, input);
70
+ };
71
+ }
72
+ return h3;
73
+ };
74
+ }
75
+ function wrapHandlerWithTracing(handler) {
76
+ const { tracingChannel } = globalThis.process?.getBuiltinModule?.("diagnostics_channel") ?? {};
77
+ if (!tracingChannel) return handler;
78
+ if (handler.__traced__) return handler;
79
+ const channel = tracingChannel("h3.request");
80
+ const wrapped = (...args) => {
81
+ return channel.tracePromise(async () => handler(...args), {
82
+ event: args[0],
83
+ type: "route"
84
+ });
85
+ };
86
+ wrapped.__traced__ = true;
87
+ return wrapped;
88
+ }
89
+ export { tracingPlugin, wrapHandlerWithTracing };
package/package.json ADDED
@@ -0,0 +1,148 @@
1
+ {
2
+ "name": "@depup/h3",
3
+ "version": "2.0.1-depup.0",
4
+ "description": "Minimal H(TTP) framework built for high performance and portability. (with updated dependencies)",
5
+ "homepage": "https://h3.dev",
6
+ "license": "MIT",
7
+ "repository": "h3js/h3",
8
+ "bin": {
9
+ "h3": "./bin/h3.mjs"
10
+ },
11
+ "files": [
12
+ "bin",
13
+ "dist",
14
+ "changes.json",
15
+ "README.md"
16
+ ],
17
+ "type": "module",
18
+ "sideEffects": false,
19
+ "types": "./dist/_entries/generic.d.mts",
20
+ "exports": {
21
+ "./package.json": "./package.json",
22
+ ".": {
23
+ "deno": "./dist/_entries/deno.mjs",
24
+ "bun": "./dist/_entries/bun.mjs",
25
+ "workerd": "./dist/_entries/cloudflare.mjs",
26
+ "browser": "./dist/_entries/service-worker.mjs",
27
+ "node": "./dist/_entries/node.mjs",
28
+ "default": "./dist/_entries/generic.mjs"
29
+ },
30
+ "./deno": "./dist/_entries/deno.mjs",
31
+ "./bun": "./dist/_entries/bun.mjs",
32
+ "./cloudflare": "./dist/_entries/cloudflare.mjs",
33
+ "./service-worker": "./dist/_entries/service-worker.mjs",
34
+ "./node": "./dist/_entries/node.mjs",
35
+ "./generic": "./dist/_entries/generic.mjs",
36
+ "./tracing": "./dist/tracing.mjs",
37
+ "./rules": "./dist/rules/index.mjs",
38
+ "./rules/cache": "./dist/rules/cache.mjs",
39
+ "./rules/proxy": "./dist/rules/proxy.mjs",
40
+ "./rules/compiler": "./dist/rules/compiler.mjs"
41
+ },
42
+ "scripts": {
43
+ "bench:bun": "bun run ./test/bench/bench.ts",
44
+ "bench:node": "node --expose-gc --allow-natives-syntax ./test/bench/bench.ts",
45
+ "build": "obuild",
46
+ "dev": "vitest",
47
+ "fmt": "automd && oxlint --fix . && oxfmt .",
48
+ "lint": "oxlint . && oxfmt --check .",
49
+ "play:bun": "bun ./test/fixture/bun.ts",
50
+ "play:node": "pnpm test/fixture/node.ts",
51
+ "play:plain": "pnpm test/fixture/plain.ts",
52
+ "play:web": "pnpm test/fixture/web.ts",
53
+ "release": "pnpm build && pnpm test && changelogen --release --prerelease && pnpm publish --tag latest && git push --follow-tags",
54
+ "test": "pnpm lint && pnpm typecheck && vitest --run --coverage",
55
+ "typecheck": "tsc --noEmit"
56
+ },
57
+ "dependencies": {
58
+ "rou3": "^1.0.0",
59
+ "srvx": "^1.0.5"
60
+ },
61
+ "devDependencies": {
62
+ "@happy-dom/global-registrator": "^20.14.5",
63
+ "@mitata/counters": "^0.0.8",
64
+ "@types/connect": "^3.4.38",
65
+ "@types/express": "^5.0.6",
66
+ "@types/node": "^26.6.4",
67
+ "@types/react": "^19.3.0",
68
+ "@types/react-dom": "^19.3.0",
69
+ "@typescript/native-preview": "latest",
70
+ "@vitest/coverage-v8": "^5.0.3",
71
+ "automd": "^0.4.3",
72
+ "changelogen": "^0.6.2",
73
+ "connect": "^3.7.0",
74
+ "cookie-es": "^3.1.1",
75
+ "crossws": "^0.4.12",
76
+ "elysia": "^1.4.30",
77
+ "esbuild": "^0.28.2",
78
+ "express": "^5.2.1",
79
+ "fetchdts": "^0.2.0",
80
+ "get-port-please": "^3.2.0",
81
+ "h3": "workspace:*",
82
+ "h3-nightly": "latest",
83
+ "happy-dom": "^20.14.5",
84
+ "hono": "^4.13.12",
85
+ "magic-string": "^1.4.2",
86
+ "mdzilla": "^0.2.1",
87
+ "memoirist": "^1.2.2",
88
+ "mitata": "^1.0.34",
89
+ "obuild": "^0.4.43",
90
+ "ocache": "^0.3.0",
91
+ "oxc-parser": "^0.152.0",
92
+ "oxfmt": ">=0.71.0",
93
+ "oxlint": "^1.86.0",
94
+ "pkg-pr-new": "^0.0.88",
95
+ "react": "^19.3.0",
96
+ "react-dom": "^19.3.0",
97
+ "typescript": "^7.0.2",
98
+ "vite": "^8.3.2",
99
+ "vitest": "^5.0.3",
100
+ "zod": "^4.6.5"
101
+ },
102
+ "peerDependencies": {
103
+ "crossws": "^0.4.12",
104
+ "ocache": ">=0.3.0"
105
+ },
106
+ "peerDependenciesMeta": {
107
+ "crossws": {
108
+ "optional": true
109
+ },
110
+ "ocache": {
111
+ "optional": true
112
+ }
113
+ },
114
+ "resolutions": {
115
+ "h3": "link:.",
116
+ "h3-nightly": "latest"
117
+ },
118
+ "devEngines": {
119
+ "packageManager": {
120
+ "name": "pnpm",
121
+ "version": "12.3.4",
122
+ "onFail": "warn"
123
+ },
124
+ "runtime": {
125
+ "name": "node",
126
+ "version": "^24"
127
+ }
128
+ },
129
+ "engines": {
130
+ "node": ">=20.19.0"
131
+ },
132
+ "keywords": [
133
+ "h3",
134
+ "depup",
135
+ "updated-dependencies",
136
+ "security",
137
+ "latest",
138
+ "patched"
139
+ ],
140
+ "depup": {
141
+ "changes": {},
142
+ "depsUpdated": 0,
143
+ "originalPackage": "h3",
144
+ "originalVersion": "2.0.1",
145
+ "processedAt": "2026-10-03T17:22:51.553Z",
146
+ "smokeTest": "failed"
147
+ }
148
+ }