rajt
Version:
A serverless bundler layer, fully typed for AWS Lambda (Node.js and LLRT) and Cloudflare Workers.
203 lines (162 loc) • 5.28 kB
text/typescript
import { getCookie, getSignedCookie, setCookie, setSignedCookie, deleteCookie } from 'hono/cookie'
import { HTTPException } from 'hono/http-exception'
import { Authnz, Token } from './auth'
import type { Context } from 'hono'
import { routePath, matchedRoutes } from 'hono/route'
import type { RouterRoute } from 'hono/types'
import type { CookieOptions, CookiePrefixOptions } from 'hono/utils/cookie'
import type { CustomHeader, RequestHeader } from 'hono/utils/headers'
import type { BodyData, ParseBodyOptions } from 'hono/utils/body'
const cookieWrapper = (c: Context) => ({
all: () => getCookie(c),
allSigned: (secret: string) => getSignedCookie(c, secret),
get: (name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getCookie(c, name, prefixOptions) : getCookie(c, name),
getSigned: (secret: string, name: string, prefixOptions?: CookiePrefixOptions) => prefixOptions ? getSignedCookie(c, secret, name, prefixOptions) : getSignedCookie(c, secret, name),
set: (name: string, value: string, opt?: CookieOptions) => setCookie(c, name, value, opt),
setSigned: (name: string, value: string, secret: string, opt?: CookieOptions) => setSignedCookie(c, name, value, secret, opt),
delete: (name: string, opt?: CookieOptions) => deleteCookie(c, name, opt)
})
export const GET_REQUEST: unique symbol = Symbol()
export default class $Request {
#c!: Context
#cookie: ReturnType<typeof cookieWrapper>
#u: Authnz<any> | null = null
#host: string
#routePath: string
#matchedRoutes: RouterRoute[]
constructor(c: Context) {
this.#c = c
this.#cookie = cookieWrapper(c)
this.#u = Authnz.fromToken(Token.fromRequest(this))
const url = new URL(c.req.raw.url)
this.#host = url.protocol +'//'+ url.host
this.#routePath = routePath(c)
this.#matchedRoutes = matchedRoutes(c)
}
get user() {
return this.#u ? this.#u?.data : null
}
get auth() {
return this.#u
}
can(...abilities: string[]) {
return this.#u ? this.#u.can(...abilities) : false
}
cant(...abilities: string[]) {
return !this.can(...abilities)
}
hasRole(...roles: string[]) {
return this.#u ? this.#u.hasRole(...roles) : false
}
has(prop: string, value: any = null) {
return this.#u ? this.#u.has(prop, value) : false
}
hasValue(prop: string, value: any = null) {
return this.has(prop, value)
}
get cx() {
return this.#c
}
get cookie() {
return this.#cookie
}
get ip(): string | undefined {
return this.#c.req.header('cf-connecting-ip')
|| this.#c.req.header('x-forwarded-for')?.split(',')[0]?.trim()
|| this.#c.env?.aws?.lambda?.event?.requestContext?.identity?.sourceIp
|| this.#c.req.header('x-real-ip')
|| this.#c.env?.remoteAddr?.hostname
}
get userAgent(): string | undefined {
return this.#c.req.header('user-agent')
}
get routePath() {
return this.#routePath
}
get url() {
return this.#c.req.raw.url
}
get host() {
return this.#host
}
get path() {
return this.#c.req.path
}
get fullPath() {
const url = this.url
return url.slice(url.indexOf('/', 8))
}
get method() {
return this.#c.req.raw.method
}
get matchedRoutes() {
return this.#matchedRoutes
}
get raw() {
return this.#c.req.raw
}
header(name: RequestHeader): string | undefined
header(name: string): string | undefined
header(): Record<RequestHeader | (string & CustomHeader), string>
header(name?: string) { // @ts-ignore
return this.#c.req.header(name)
}
param(key?: string) { // @ts-ignore
return this.#c.req.param(key)
}
query(): Record<string, string>
query(key: string): string | undefined
query(key?: string) { // @ts-ignore
return this.#c.req.query(key)
}
queries(): Record<string, string[]>
queries(key: string):string[] | undefined
queries(key?: string) { // @ts-ignore
return this.#c.req.queries(key)
}
async body<E>() {
const cType = this.#c.req.header('Content-Type')
if (!cType) return {} as E
if (/^application\/([a-z-\.]+\+)?json(;\s*[a-zA-Z0-9\-]+\=([^;]+))*$/.test(cType))
return await this.json<E>()
if (
cType?.startsWith('multipart/form-data')
|| cType?.startsWith('application/x-www-form-urlencoded')
) {
return await this.parseBody() as E
}
return {} as E
}
async parseBody<Options extends Partial<ParseBodyOptions>, T extends BodyData<Options>>(
options?: Options
): Promise<T>
async parseBody<T extends BodyData>(options?: Partial<ParseBodyOptions>): Promise<T>
async parseBody(options?: Partial<ParseBodyOptions>) {
try {
return await this.#c.req.parseBody(options)
} catch (e) {
throw new HTTPException(400, {
message: 'Malformed FormData request.'+ (e instanceof Error ? ` ${e.message}` : ` ${String(e)}`)
})
}
}
async json<E>() {
try {
return await this.#c.req.json<E>()
} catch {
throw new HTTPException(400, { message: 'Malformed JSON in request body' })
}
}
text() {
return this.#c.req.text()
}
arrayBuffer() {
return this.#c.req.arrayBuffer()
}
blob() {
return this.#c.req.blob()
}
formData() {
return this.#c.req.formData()
}
}