import type { State } from "./application.ts";import type { Context } from "./context.ts";import { calculate, type ETagOptions } from "./deps.ts";import type { Middleware } from "./middleware.ts";import { BODY_TYPES, isAsyncIterable, isReader } from "./util.ts";
export { calculate, type ETagOptions, type FileInfo, ifMatch, ifNoneMatch,} from "./deps.ts";
function isFsFile(value: unknown): value is Deno.FsFile { return !!(value && typeof value === "object" && "stat" in value && typeof value.stat === "function");}
export function getEntity<S extends State = Record<string, any>>( context: Context<S>,): Promise<string | Uint8Array | Deno.FileInfo | undefined> { const { body } = context.response; if (isFsFile(body)) { return body.stat(); } if (body instanceof Uint8Array) { return Promise.resolve(body); } if (BODY_TYPES.includes(typeof body)) { return Promise.resolve(String(body)); } if (isAsyncIterable(body) || isReader(body)) { return Promise.resolve(undefined); } if (typeof body === "object" && body !== null) { try { const bodyText = JSON.stringify(body); return Promise.resolve(bodyText); } catch { } } return Promise.resolve(undefined);}
export function factory<S extends State = Record<string, any>>( options?: ETagOptions,): Middleware<S> { return async function etag(context: Context<S>, next) { await next(); if (!context.response.headers.has("ETag")) { const entity = await getEntity(context); if (entity) { const etag = await calculate(entity, options); if (etag) { context.response.headers.set("ETag", etag); } } } };}