Files
SnowLuma/.pnpm-store/v11/files/3e/be3497ec2da7a549d0a419d6b7f7a5ffb9308ba45e953a2b19035c9696c5e5fbba64511587a0b33dbbb1b8797ab793ae0d4fa6a7d5df92a079af597535a80b
T
TanTan 2a69b23b47
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

190 lines
5.6 KiB
Plaintext

Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
//#region src/middleware/timing/timing.ts
const getTime = () => {
try {
return performance.now();
} catch {}
return Date.now();
};
/**
* Server-Timing Middleware for Hono.
*
* @see {@link https://hono.dev/docs/middleware/builtin/timing}
*
* @param {TimingOptions} [config] - The options for the timing middleware.
* @param {boolean} [config.total=true] - Show the total response time.
* @param {boolean | ((c: Context) => boolean)} [config.enabled=true] - Whether timings should be added to the headers or not.
* @param {string} [config.totalDescription=Total Response Time] - Description for the total response time.
* @param {boolean} [config.autoEnd=true] - If `startTime()` should end automatically at the end of the request.
* @param {boolean | string | ((c: Context) => boolean | string)} [config.crossOrigin=false] - The origin this timings header should be readable.
* @returns {MiddlewareHandler} The middleware handler function.
*
* @example
* ```ts
* const app = new Hono()
*
* // add the middleware to your router
* app.use(timing());
*
* app.get('/', async (c) => {
* // add custom metrics
* setMetric(c, 'region', 'europe-west3')
*
* // add custom metrics with timing, must be in milliseconds
* setMetric(c, 'custom', 23.8, 'My custom Metric')
*
* // start a new timer
* startTime(c, 'db');
*
* const data = await db.findMany(...);
*
* // end the timer
* endTime(c, 'db');
*
* return c.json({ response: data });
* });
* ```
*/
const timing = (config) => {
const options = {
total: true,
enabled: true,
totalDescription: "Total Response Time",
autoEnd: true,
crossOrigin: false,
...config
};
return async function timing(c, next) {
const headers = [];
const timers = /* @__PURE__ */ new Map();
if (c.get("metric")) return await next();
c.set("metric", {
headers,
timers
});
if (options.total) startTime(c, "total", options.totalDescription);
await next();
if (options.total) endTime(c, "total");
if (options.autoEnd) timers.forEach((_, key) => {
endTime(c, key);
});
if (typeof options.enabled === "function" ? options.enabled(c) : options.enabled) {
c.res.headers.append("Server-Timing", headers.join(","));
const crossOrigin = typeof options.crossOrigin === "function" ? options.crossOrigin(c) : options.crossOrigin;
if (crossOrigin) c.res.headers.append("Timing-Allow-Origin", typeof crossOrigin === "string" ? crossOrigin : "*");
}
};
};
/**
* Set a metric for the timing middleware.
*
* @param {Context} c - The context of the request.
* @param {string} name - The name of the metric.
* @param {number | string} [valueDescription] - The value or description of the metric.
* @param {string} [description] - The description of the metric.
* @param {number} [precision] - The precision of the metric value.
*
* @example
* ```ts
* setMetric(c, 'region', 'europe-west3')
* setMetric(c, 'custom', 23.8, 'My custom Metric')
* ```
*/
const setMetric = (c, name, valueDescription, description, precision) => {
const metrics = c.get("metric");
if (!metrics) {
console.warn("Metrics not initialized! Please add the `timing()` middleware to this route!");
return;
}
if (typeof valueDescription === "number") {
const dur = valueDescription.toFixed(precision || 1);
const metric = description ? `${name};dur=${dur};desc="${description}"` : `${name};dur=${dur}`;
metrics.headers.push(metric);
} else {
const metric = valueDescription ? `${name};desc="${valueDescription}"` : `${name}`;
metrics.headers.push(metric);
}
};
/**
* Start a timer for the timing middleware.
*
* @param {Context} c - The context of the request.
* @param {string} name - The name of the timer.
* @param {string} [description] - The description of the timer.
*
* @example
* ```ts
* startTime(c, 'db')
* ```
*/
const startTime = (c, name, description) => {
const metrics = c.get("metric");
if (!metrics) {
console.warn("Metrics not initialized! Please add the `timing()` middleware to this route!");
return;
}
metrics.timers.set(name, {
description,
start: getTime()
});
};
/**
* End a timer for the timing middleware.
*
* @param {Context} c - The context of the request.
* @param {string} name - The name of the timer.
* @param {number} [precision] - The precision of the timer value.
*
* @example
* ```ts
* endTime(c, 'db')
* ```
*/
const endTime = (c, name, precision) => {
const metrics = c.get("metric");
if (!metrics) {
console.warn("Metrics not initialized! Please add the `timing()` middleware to this route!");
return;
}
const timer = metrics.timers.get(name);
if (!timer) {
console.warn(`Timer "${name}" does not exist!`);
return;
}
const { description, start } = timer;
const duration = getTime() - start;
setMetric(c, name, duration, description, precision);
metrics.timers.delete(name);
};
/**
* Wrap a Promise to capture its duration.
* @param {Context} c - The context of the request.
* @param {string} name - The name of the timer.
* @param {Promise<T>} callable - The Promise to time.
* @param {string} [description] - The description of the timer.
* @param {number} [precision] - The precision of the timer value.
*
* @example
* ```ts
* // Instead of this:
* const data = await db.findMany(...);
*
* // do this:
* const data = await wrapTime(c, 'query', db.findMany(...));
* ```
* */
async function wrapTime(c, name, callable, description, precision) {
startTime(c, name, description);
try {
return await callable;
} finally {
endTime(c, name, precision);
}
}
//#endregion
exports.endTime = endTime;
exports.setMetric = setMetric;
exports.startTime = startTime;
exports.timing = timing;
exports.wrapTime = wrapTime;