Buckets:
| // src/context.ts | |
| import { HonoRequest } from "./request.js"; | |
| import { HtmlEscapedCallbackPhase, resolveCallback } from "./utils/html.js"; | |
| var TEXT_PLAIN = "text/plain; charset=UTF-8"; | |
| var setDefaultContentType = (contentType, headers) => { | |
| return { | |
| "Content-Type": contentType, | |
| ...headers | |
| }; | |
| }; | |
| var Context = class { | |
| #rawRequest; | |
| #req; | |
| /** | |
| * `.env` can get bindings (environment variables, secrets, KV namespaces, D1 database, R2 bucket etc.) in Cloudflare Workers. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#env} | |
| * | |
| * @example | |
| * ```ts | |
| * // Environment object for Cloudflare Workers | |
| * app.get('*', async c => { | |
| * const counter = c.env.COUNTER | |
| * }) | |
| * ``` | |
| */ | |
| env = {}; | |
| #var; | |
| finalized = false; | |
| /** | |
| * `.error` can get the error object from the middleware if the Handler throws an error. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#error} | |
| * | |
| * @example | |
| * ```ts | |
| * app.use('*', async (c, next) => { | |
| * await next() | |
| * if (c.error) { | |
| * // do something... | |
| * } | |
| * }) | |
| * ``` | |
| */ | |
| error; | |
| #status; | |
| #executionCtx; | |
| #res; | |
| #layout; | |
| #renderer; | |
| #notFoundHandler; | |
| #preparedHeaders; | |
| #matchResult; | |
| #path; | |
| /** | |
| * Creates an instance of the Context class. | |
| * | |
| * @param req - The Request object. | |
| * @param options - Optional configuration options for the context. | |
| */ | |
| constructor(req, options) { | |
| this.#rawRequest = req; | |
| if (options) { | |
| this.#executionCtx = options.executionCtx; | |
| this.env = options.env; | |
| this.#notFoundHandler = options.notFoundHandler; | |
| this.#path = options.path; | |
| this.#matchResult = options.matchResult; | |
| } | |
| } | |
| /** | |
| * `.req` is the instance of {@link HonoRequest}. | |
| */ | |
| get req() { | |
| this.#req ??= new HonoRequest(this.#rawRequest, this.#path, this.#matchResult); | |
| return this.#req; | |
| } | |
| /** | |
| * @see {@link https://hono.dev/docs/api/context#event} | |
| * The FetchEvent associated with the current request. | |
| * | |
| * @throws Will throw an error if the context does not have a FetchEvent. | |
| */ | |
| get event() { | |
| if (this.#executionCtx && "respondWith" in this.#executionCtx) { | |
| return this.#executionCtx; | |
| } else { | |
| throw Error("This context has no FetchEvent"); | |
| } | |
| } | |
| /** | |
| * @see {@link https://hono.dev/docs/api/context#executionctx} | |
| * The ExecutionContext associated with the current request. | |
| * | |
| * @throws Will throw an error if the context does not have an ExecutionContext. | |
| */ | |
| get executionCtx() { | |
| if (this.#executionCtx) { | |
| return this.#executionCtx; | |
| } else { | |
| throw Error("This context has no ExecutionContext"); | |
| } | |
| } | |
| /** | |
| * @see {@link https://hono.dev/docs/api/context#res} | |
| * The Response object for the current request. | |
| */ | |
| get res() { | |
| return this.#res ||= new Response(null, { | |
| headers: this.#preparedHeaders ??= new Headers() | |
| }); | |
| } | |
| /** | |
| * Sets the Response object for the current request. | |
| * | |
| * @param _res - The Response object to set. | |
| */ | |
| set res(_res) { | |
| if (this.#res && _res) { | |
| _res = new Response(_res.body, _res); | |
| for (const [k, v] of this.#res.headers.entries()) { | |
| if (k === "content-type") { | |
| continue; | |
| } | |
| 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()` can create a response within a layout. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#render-setrenderer} | |
| * | |
| * @example | |
| * ```ts | |
| * app.get('/', (c) => { | |
| * return c.render('Hello!') | |
| * }) | |
| * ``` | |
| */ | |
| render = (...args) => { | |
| this.#renderer ??= (content) => this.html(content); | |
| return this.#renderer(...args); | |
| }; | |
| /** | |
| * Sets the layout for the response. | |
| * | |
| * @param layout - The layout to set. | |
| * @returns The layout function. | |
| */ | |
| setLayout = (layout) => this.#layout = layout; | |
| /** | |
| * Gets the current layout for the response. | |
| * | |
| * @returns The current layout function. | |
| */ | |
| getLayout = () => this.#layout; | |
| /** | |
| * `.setRenderer()` can set the layout in the custom middleware. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#render-setrenderer} | |
| * | |
| * @example | |
| * ```tsx | |
| * app.use('*', async (c, next) => { | |
| * c.setRenderer((content) => { | |
| * return c.html( | |
| * <html> | |
| * <body> | |
| * <p>{content}</p> | |
| * </body> | |
| * </html> | |
| * ) | |
| * }) | |
| * await next() | |
| * }) | |
| * ``` | |
| */ | |
| setRenderer = (renderer) => { | |
| this.#renderer = renderer; | |
| }; | |
| /** | |
| * `.header()` can set headers. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#header} | |
| * | |
| * @example | |
| * ```ts | |
| * app.get('/welcome', (c) => { | |
| * // Set headers | |
| * c.header('X-Message', 'Hello!') | |
| * c.header('Content-Type', 'text/plain') | |
| * | |
| * return c.body('Thank you for coming') | |
| * }) | |
| * ``` | |
| */ | |
| header = (name, value, options) => { | |
| if (this.finalized) { | |
| this.#res = new Response(this.#res.body, this.#res); | |
| } | |
| const headers = this.#res ? this.#res.headers : this.#preparedHeaders ??= new Headers(); | |
| if (value === void 0) { | |
| headers.delete(name); | |
| } else if (options?.append) { | |
| headers.append(name, value); | |
| } else { | |
| headers.set(name, value); | |
| } | |
| }; | |
| status = (status) => { | |
| this.#status = status; | |
| }; | |
| /** | |
| * `.set()` can set the value specified by the key. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#set-get} | |
| * | |
| * @example | |
| * ```ts | |
| * app.use('*', async (c, next) => { | |
| * c.set('message', 'Hono is hot!!') | |
| * await next() | |
| * }) | |
| * ``` | |
| */ | |
| set = (key, value) => { | |
| this.#var ??= /* @__PURE__ */ new Map(); | |
| this.#var.set(key, value); | |
| }; | |
| /** | |
| * `.get()` can use the value specified by the key. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#set-get} | |
| * | |
| * @example | |
| * ```ts | |
| * app.get('/', (c) => { | |
| * const message = c.get('message') | |
| * return c.text(`The message is "${message}"`) | |
| * }) | |
| * ``` | |
| */ | |
| get = (key) => { | |
| return this.#var ? this.#var.get(key) : void 0; | |
| }; | |
| /** | |
| * `.var` can access the value of a variable. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#var} | |
| * | |
| * @example | |
| * ```ts | |
| * const result = c.var.client.oneMethod() | |
| * ``` | |
| */ | |
| // c.var.propName is a read-only | |
| get var() { | |
| if (!this.#var) { | |
| return {}; | |
| } | |
| return Object.fromEntries(this.#var); | |
| } | |
| #newResponse(data, arg, headers) { | |
| const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers(); | |
| if (typeof arg === "object" && "headers" in arg) { | |
| const argHeaders = arg.headers instanceof Headers ? arg.headers : new Headers(arg.headers); | |
| for (const [key, value] of argHeaders) { | |
| if (key.toLowerCase() === "set-cookie") { | |
| responseHeaders.append(key, value); | |
| } else { | |
| responseHeaders.set(key, value); | |
| } | |
| } | |
| } | |
| if (headers) { | |
| for (const [k, v] of Object.entries(headers)) { | |
| if (typeof v === "string") { | |
| responseHeaders.set(k, v); | |
| } else { | |
| responseHeaders.delete(k); | |
| for (const v2 of v) { | |
| responseHeaders.append(k, v2); | |
| } | |
| } | |
| } | |
| } | |
| const status = typeof arg === "number" ? arg : arg?.status ?? this.#status; | |
| return new Response(data, { status, headers: responseHeaders }); | |
| } | |
| newResponse = (...args) => this.#newResponse(...args); | |
| /** | |
| * `.body()` can return the HTTP response. | |
| * You can set headers with `.header()` and set HTTP status code with `.status`. | |
| * This can also be set in `.text()`, `.json()` and so on. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#body} | |
| * | |
| * @example | |
| * ```ts | |
| * app.get('/welcome', (c) => { | |
| * // Set headers | |
| * c.header('X-Message', 'Hello!') | |
| * c.header('Content-Type', 'text/plain') | |
| * // Set HTTP status code | |
| * c.status(201) | |
| * | |
| * // Return the response body | |
| * return c.body('Thank you for coming') | |
| * }) | |
| * ``` | |
| */ | |
| body = (data, arg, headers) => this.#newResponse(data, arg, headers); | |
| /** | |
| * `.text()` can render text as `Content-Type:text/plain`. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#text} | |
| * | |
| * @example | |
| * ```ts | |
| * app.get('/say', (c) => { | |
| * return c.text('Hello!') | |
| * }) | |
| * ``` | |
| */ | |
| text = (text, arg, headers) => { | |
| return !this.#preparedHeaders && !this.#status && !arg && !headers && !this.finalized ? new Response(text) : this.#newResponse( | |
| text, | |
| arg, | |
| setDefaultContentType(TEXT_PLAIN, headers) | |
| ); | |
| }; | |
| /** | |
| * `.json()` can render JSON as `Content-Type:application/json`. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#json} | |
| * | |
| * @example | |
| * ```ts | |
| * app.get('/api', (c) => { | |
| * return c.json({ message: 'Hello!' }) | |
| * }) | |
| * ``` | |
| */ | |
| json = (object, arg, headers) => { | |
| return this.#newResponse( | |
| JSON.stringify(object), | |
| arg, | |
| setDefaultContentType("application/json", headers) | |
| ); | |
| }; | |
| html = (html, arg, headers) => { | |
| const res = (html2) => this.#newResponse(html2, arg, setDefaultContentType("text/html; charset=UTF-8", headers)); | |
| return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html); | |
| }; | |
| /** | |
| * `.redirect()` can Redirect, default status code is 302. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#redirect} | |
| * | |
| * @example | |
| * ```ts | |
| * app.get('/redirect', (c) => { | |
| * return c.redirect('/') | |
| * }) | |
| * app.get('/redirect-permanently', (c) => { | |
| * return c.redirect('/', 301) | |
| * }) | |
| * ``` | |
| */ | |
| redirect = (location, status) => { | |
| const locationString = String(location); | |
| this.header( | |
| "Location", | |
| // Multibyes should be encoded | |
| // eslint-disable-next-line no-control-regex | |
| !/[^\x00-\xFF]/.test(locationString) ? locationString : encodeURI(locationString) | |
| ); | |
| return this.newResponse(null, status ?? 302); | |
| }; | |
| /** | |
| * `.notFound()` can return the Not Found Response. | |
| * | |
| * @see {@link https://hono.dev/docs/api/context#notfound} | |
| * | |
| * @example | |
| * ```ts | |
| * app.get('/notfound', (c) => { | |
| * return c.notFound() | |
| * }) | |
| * ``` | |
| */ | |
| notFound = () => { | |
| this.#notFoundHandler ??= () => new Response(); | |
| return this.#notFoundHandler(this); | |
| }; | |
| }; | |
| export { | |
| Context, | |
| TEXT_PLAIN | |
| }; | |
Xet Storage Details
- Size:
- 10.8 kB
- Xet hash:
- 887816475266324dc9b4bc70dcf3a96b1176ab2f1608891e54b68c54afb18ac1
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.