// src/context.ts import { HtmlEscapedCallbackPhase, resolveCallback } from "./utils/html.js"; var TEXT_PLAIN = "text/plain; charset=UTF-8"; var setHeaders = (headers, map = {}) => { Object.entries(map).forEach(([key, value]) => headers.set(key, value)); return headers; }; var Context = class { req; env = {}; _var = {}; finalized = false; error = void 0; #status = 200; #executionCtx; #headers = void 0; #preparedHeaders = void 0; #res; #isFresh = true; layout = void 0; renderer = (content) => this.html(content); notFoundHandler = () => new Response(); constructor(req, options) { this.req = req; if (options) { this.#executionCtx = options.executionCtx; this.env = options.env; if (options.notFoundHandler) { this.notFoundHandler = options.notFoundHandler; } } } get event() { if (this.#executionCtx && "respondWith" in this.#executionCtx) { return this.#executionCtx; } else { throw Error("This context has no FetchEvent"); } } get executionCtx() { if (this.#executionCtx) { return this.#executionCtx; } else { throw Error("This context has no ExecutionContext"); } } get res() { this.#isFresh = false; return this.#res ||= new Response("404 Not Found", { status: 404 }); } set res(_res) { this.#isFresh = false; if (this.#res && _res) { this.#res.headers.delete("content-type"); for (const [k, v] of this.#res.headers.entries()) { if (k === "set-cookie") { const cookies = this.#res.headers.getSetCookie(); _res.headers.delete("set-cookie"); for (const cookie of cookies) { _res.headers.append("set-cookie", cookie); } } else { _res.headers.set(k, v); } } } this.#res = _res; this.finalized = true; } render = (...args) => this.renderer(...args); setLayout = (layout) => this.layout = layout; getLayout = () => this.layout; setRenderer = (renderer) => { this.renderer = renderer; }; header = (name, value, options) => { if (value === void 0) { if (this.#headers) { this.#headers.delete(name); } else if (this.#preparedHeaders) { delete this.#preparedHeaders[name.toLocaleLowerCase()]; } if (this.finalized) { this.res.headers.delete(name); } return; } if (options?.append) { if (!this.#headers) { this.#isFresh = false; this.#headers = new Headers(this.#preparedHeaders); this.#preparedHeaders = {}; } this.#headers.append(name, value); } else { if (this.#headers) { this.#headers.set(name, value); } else { this.#preparedHeaders ??= {}; this.#preparedHeaders[name.toLowerCase()] = value; } } if (this.finalized) { if (options?.append) { this.res.headers.append(name, value); } else { this.res.headers.set(name, value); } } }; status = (status) => { this.#isFresh = false; this.#status = status; }; set = (key, value) => { this._var ??= {}; this._var[key] = value; }; get = (key) => { return this._var ? this._var[key] : void 0; }; get var() { return { ...this._var }; } newResponse = (data, arg, headers) => { if (this.#isFresh && !headers && !arg && this.#status === 200) { return new Response(data, { headers: this.#preparedHeaders }); } if (arg && typeof arg !== "number") { const header = new Headers(arg.headers); if (this.#headers) { this.#headers.forEach((v, k) => { header.set(k, v); }); } const headers2 = setHeaders(header, this.#preparedHeaders); return new Response(data, { headers: headers2, status: arg.status ?? this.#status }); } const status = typeof arg === "number" ? arg : this.#status; this.#preparedHeaders ??= {}; this.#headers ??= new Headers(); setHeaders(this.#headers, this.#preparedHeaders); if (this.#res) { this.#res.headers.forEach((v, k) => { if (k === "set-cookie") { this.#headers?.append(k, v); } else { this.#headers?.set(k, v); } }); setHeaders(this.#headers, this.#preparedHeaders); } headers ??= {}; for (const [k, v] of Object.entries(headers)) { if (typeof v === "string") { this.#headers.set(k, v); } else { this.#headers.delete(k); for (const v2 of v) { this.#headers.append(k, v2); } } } return new Response(data, { status, headers: this.#headers }); }; body = (data, arg, headers) => { return typeof arg === "number" ? this.newResponse(data, arg, headers) : this.newResponse(data, arg); }; text = (text, arg, headers) => { if (!this.#preparedHeaders) { if (this.#isFresh && !headers && !arg) { return new Response(text); } this.#preparedHeaders = {}; } this.#preparedHeaders["content-type"] = TEXT_PLAIN; return typeof arg === "number" ? this.newResponse(text, arg, headers) : this.newResponse(text, arg); }; json = (object, arg, headers) => { const body = JSON.stringify(object); this.#preparedHeaders ??= {}; this.#preparedHeaders["content-type"] = "application/json; charset=UTF-8"; return typeof arg === "number" ? this.newResponse(body, arg, headers) : this.newResponse(body, arg); }; html = (html, arg, headers) => { this.#preparedHeaders ??= {}; this.#preparedHeaders["content-type"] = "text/html; charset=UTF-8"; if (typeof html === "object") { if (!(html instanceof Promise)) { html = html.toString(); } if (html instanceof Promise) { return html.then((html2) => resolveCallback(html2, HtmlEscapedCallbackPhase.Stringify, false, {})).then((html2) => { return typeof arg === "number" ? this.newResponse(html2, arg, headers) : this.newResponse(html2, arg); }); } } return typeof arg === "number" ? this.newResponse(html, arg, headers) : this.newResponse(html, arg); }; redirect = (location, status = 302) => { this.#headers ??= new Headers(); this.#headers.set("Location", location); return this.newResponse(null, status); }; notFound = () => { return this.notFoundHandler(this); }; }; export { Context, TEXT_PLAIN };