Files
SnowLuma/.pnpm-store/v11/files/8f/b94e32ed4e18733c8585bf6edb2402aad30546552c1fd1a9a96d2099aef596772fea9299579ec581f881c234baa94a21c1c12c760d63c95a7b434c69e43c9d
T
TanTan 2a69b23b47
Dev Build / cleanup (push) Canceled after 0s
Dev Build / typecheck (push) Canceled after 0s
Dev Build / build (linux-arm64, ubuntu-24.04-arm, linux-arm64) (push) Canceled after 0s
Dev Build / build (linux-x64, ubuntu-latest, linux-x64) (push) Canceled after 0s
Dev Build / build (win-x64, windows-latest, win32-x64) (push) Canceled after 0s
Dev Build / dispatch-dev-docker (push) Canceled after 0s
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

139 lines
4.6 KiB
Plaintext

import { compose } from "../../compose.js";
import "../../router.js";
import { TrieRouter } from "../../router/trie-router/router.js";
import "../../router/trie-router/index.js";
//#region src/middleware/combine/index.ts
/**
* @module
* Combine Middleware for Hono.
*/
/**
* Create a composed middleware that runs the first middleware that returns true.
*
* @param middleware - An array of MiddlewareHandler or Condition functions.
* Middleware is applied in the order it is passed, and if any middleware exits without returning
* an exception first, subsequent middleware will not be executed.
* You can also pass a condition function that returns a boolean value. If returns true
* the evaluation will be halted, and rest of the middleware will not be executed.
* @returns A composed middleware.
*
* @example
* ```ts
* import { some } from 'hono/combine'
* import { bearerAuth } from 'hono/bearer-auth'
* import { myRateLimit } from '@/rate-limit'
*
* // If client has a valid token, then skip rate limiting.
* // Otherwise, apply rate limiting.
* app.use('/api/*', some(
* bearerAuth({ token }),
* myRateLimit({ limit: 100 }),
* ));
* ```
*/
const some = (...middleware) => {
return async function some(c, next) {
let isNextCalled = false;
const wrappedNext = () => {
isNextCalled = true;
return next();
};
let lastError;
let response;
for (const handler of middleware) try {
const result = await handler(c, wrappedNext);
if (result === true && !c.finalized) await wrappedNext();
else if (result === false) {
lastError = /* @__PURE__ */ new Error("No successful middleware found");
continue;
} else if (result && result !== true) response = result;
lastError = void 0;
break;
} catch (error) {
lastError = error;
if (isNextCalled) break;
}
if (lastError) throw lastError;
return response;
};
};
/**
* Create a composed middleware that runs all middleware and throws an error if any of them fail.
*
* @param middleware - An array of MiddlewareHandler or Condition functions.
* Middleware is applied in the order it is passed, and if any middleware throws an error,
* subsequent middleware will not be executed.
* You can also pass a condition function that returns a boolean value. If returns false
* the evaluation will be halted, and rest of the middleware will not be executed.
* @returns A composed middleware.
*
* @example
* ```ts
* import { some, every } from 'hono/combine'
* import { bearerAuth } from 'hono/bearer-auth'
* import { myCheckLocalNetwork } from '@/check-local-network'
* import { myRateLimit } from '@/rate-limit'
*
* // If client is in local network, then skip authentication and rate limiting.
* // Otherwise, apply authentication and rate limiting.
* app.use('/api/*', some(
* myCheckLocalNetwork(),
* every(
* bearerAuth({ token }),
* myRateLimit({ limit: 100 }),
* ),
* ));
* ```
*/
const every = (...middleware) => {
return async function every(c, next) {
const currentRouteIndex = c.req.routeIndex;
await compose(middleware.map((m) => [[async (c, next) => {
c.req.routeIndex = currentRouteIndex;
const res = await m(c, next);
if (res === false) throw new Error("Unmet condition");
return res;
}]]))(c, next);
};
};
/**
* Create a composed middleware that runs all middleware except when the condition is met.
*
* @param condition - A string or Condition function.
* If there are multiple targets to match any of them, they can be passed as an array.
* If a string is passed, it will be treated as a path pattern to match.
* If a Condition function is passed, it will be evaluated against the request context.
* @param middleware - Middleware to run when the condition is not met.
* Multiple middleware can be passed, and they are applied in the order they are passed.
* @returns A composed middleware.
*
* @example
* ```ts
* import { except } from 'hono/combine'
* import { bearerAuth } from 'hono/bearer-auth'
*
* // If client is accessing public API, then skip authentication.
* // Otherwise, require a valid token.
* app.use('/api/*', except(
* '/api/public/*',
* bearerAuth({ token }),
* ));
* ```
*/
const except = (condition, ...middleware) => {
let router = void 0;
const conditions = (Array.isArray(condition) ? condition : [condition]).map((condition) => {
if (typeof condition === "string") {
router ||= new TrieRouter();
router.add("ALL", condition, true);
} else return condition;
}).filter(Boolean);
if (router) conditions.unshift((c) => !!router?.match("ALL", c.req.path)?.[0]?.[0]?.[0]);
const handler = some((c) => conditions.some((cond) => cond(c)), every(...middleware));
return async function except(c, next) {
await handler(c, next);
};
};
//#endregion
export { every, except, some };