Skip to main content
Module

x/darkflare/Route.ts

The API Engine
Go to Latest
File
import type { DarkflareContext } from './DarkflareContext.d.ts'import type { Static, TSchema } from 'https://esm.sh/@sinclair/typebox@0.25.16'import { Value } from 'https://esm.sh/@sinclair/typebox@0.25.16/value'import { DarkflareError } from './DarkflareError.d.ts'
export class Route { public schema private handler
constructor(schema: { body?: unknown, query?: unknown, headers?: unknown, cookies?: unknown, parameters?: unknown }, handler: (ctx: any) => any) { this.schema = schema this.handler = handler }
async handle(__darkflare: { onError: (err: DarkflareError, request: Request) => Response, cors?: string, cache?: number }, request: Request, parameters: Record<string, string>, query: Record<string, unknown>, cf: Record<string, string>, waitUntil: (promise: Promise<unknown>) => void, env: darkflare.Environment) { // request const headers: { [key: string]: string } = {} let body = {} , cookies = {}
// response const h = new Headers() let p: Record<string, unknown> | string | undefined , c: number | undefined
if (this.schema.parameters && !Value.Check((this.schema.parameters as unknown) as TSchema, parameters)) return __darkflare.onError('malformed_parameters', request)
if (this.schema.query && !Value.Check((this.schema.query as unknown) as TSchema, query)) return __darkflare.onError('malformed_query', request)
for (const [key, value] of request.headers) headers[key.toLowerCase()] = value
if (this.schema.headers && !Value.Check((this.schema.headers as unknown) as TSchema, headers)) return __darkflare.onError('malformed_headers', request)
try { const type = headers['content-type'] if (type?.includes('application/json')) body = await request.json() else if (type?.includes('text/plain')) body = await request.text() } catch (_err) { body = {} } if (this.schema.body && !Value.Check((this.schema.body as unknown) as TSchema, body)) return __darkflare.onError('malformed_body', request)
try { cookies = (headers.cookies || '') .split(/;\s*/) .map(pair => pair.split(/=(.+)/)) .reduce((acc: { [key: string]: string }, [key, value]) => { acc[key] = value return acc }, {}) } catch (_err) { cookies = {} }
if (this.schema.cookies && !Value.Check((this.schema.cookies as unknown) as TSchema, cookies)) return __darkflare.onError('malformed_cookies', request)
const ctx: DarkflareContext = { env,
req: { body, query, headers, cookies, parameters, geo: { ip: headers['CF-Connecting-IP'], city: cf.city, region: cf.region, country: cf.country, continent: cf.continent, regionCode: cf.regionCode, latitude: cf.latitude, longitude: cf.longitude, postalCode: cf.postalCode, timezone: cf.timezone, datacenter: cf.colo }, raw: request },
res: { code: (code: number) => { c = code }, cookie: (name: string, value: string, options?: { expiresAt?: Date, maxAge?: number, domain?: string, path?: string, secure?: boolean, httpOnly?: boolean, sameSite?: 'strict' | 'lax' | 'none' }) => { let cookie = `${name}=${value};` h.set('set-cookie', ( options?.expiresAt && (cookie += ` expires=${options.expiresAt.toUTCString()};`), options?.maxAge && (cookie += ` max-age=${options.maxAge};`), options?.domain && (cookie += ` domain=${options.domain};`), options?.path && (cookie += ` path=${options.path};`), options?.secure && (cookie += ' secure;'), options?.httpOnly && (cookie += ' httpOnly;'), options?.sameSite && (cookie += ` sameSite=${options.sameSite.charAt(0).toUpperCase() + options.sameSite.slice(1)};`), cookie )) }, header: (name: string, value: string) => { h.set(name, value) }, html: (payload: string, code?: number) => { h.set('content-type', 'text/html; charset=utf-8;') p = payload c = code }, json: (payload: Record<string, unknown>, code?: number) => { h.set('content-type', 'application/json; charset=utf-8;') p = payload c = code }, text: (payload: string, code?: number) => { h.set('content-type', 'text/plain; charset=utf-8;') p = payload c = code }, redirect: (destination: string, code?: number) => { h.set('location', destination)
c = code ?? 307 } },
waitUntil }
try { const result = await this.handler(ctx)
if (result) p = result
if (typeof p === 'object' && !h.get('content-type')) { h.set('content-type', 'application/json; charset=utf-8;')
if ((p as { code: number, [key: string]: unknown }).code) c = (p as { code: number, [key: string]: unknown }).code
p = JSON.stringify(p) } else if (typeof p === 'string' && !h.get('content-type')) { h.set('content-type', 'text/plain; charset=utf-8;') }
if (__darkflare.cors) h.set('access-control-allow-origin', __darkflare.cors)
h.set('cache-control', `max-age=${__darkflare.cache ?? 0}`)
if (typeof p === 'string') h.set('content-length', p.length.toString())
return new Response(typeof p === 'string' ? p : null, { headers: h, status: c }) } catch (_err) { return __darkflare.onError('something_went_wrong', request) } }}
export const Delete = <B = unknown, Q = unknown, H = unknown, C = unknown, P = unknown>( schema: { body?: B, query?: Q, headers?: H, cookies?: C, parameters?: P }, handler: ( ctx: DarkflareContext & { req: { body: B extends TSchema ? Static<B> : B query: Q extends TSchema ? Static<Q> : Q headers: H extends TSchema ? Static<H> : H cookies: C extends TSchema ? Static<C> : C parameters: P extends TSchema ? Static<P> : P } } ) => any) => new Route(schema, handler)
export const Get = <B = unknown, Q = unknown, H = unknown, C = unknown, P = unknown>( schema: { body?: B, query?: Q, headers?: H, cookies?: C, parameters?: P }, handler: ( ctx: DarkflareContext & { req: { body: B extends TSchema ? Static<B> : B query: Q extends TSchema ? Static<Q> : Q headers: H extends TSchema ? Static<H> : H cookies: C extends TSchema ? Static<C> : C parameters: P extends TSchema ? Static<P> : P } } ) => any) => new Route(schema, handler)
export const Head = <B = unknown, Q = unknown, H = unknown, C = unknown, P = unknown>( schema: { body?: B, query?: Q, headers?: H, cookies?: C, parameters?: P }, handler: ( ctx: DarkflareContext & { req: { body: B extends TSchema ? Static<B> : B query: Q extends TSchema ? Static<Q> : Q headers: H extends TSchema ? Static<H> : H cookies: C extends TSchema ? Static<C> : C parameters: P extends TSchema ? Static<P> : P } } ) => any) => new Route(schema, handler)
export const Patch = <B = unknown, Q = unknown, H = unknown, C = unknown, P = unknown>( schema: { body?: B, query?: Q, headers?: H, cookies?: C, parameters?: P }, handler: ( ctx: DarkflareContext & { req: { body: B extends TSchema ? Static<B> : B query: Q extends TSchema ? Static<Q> : Q headers: H extends TSchema ? Static<H> : H cookies: C extends TSchema ? Static<C> : C parameters: P extends TSchema ? Static<P> : P } } ) => any) => new Route(schema, handler)
export const Post = <B = unknown, Q = unknown, H = unknown, C = unknown, P = unknown>( schema: { body?: B, query?: Q, headers?: H, cookies?: C, parameters?: P }, handler: ( ctx: DarkflareContext & { req: { body: B extends TSchema ? Static<B> : B query: Q extends TSchema ? Static<Q> : Q headers: H extends TSchema ? Static<H> : H cookies: C extends TSchema ? Static<C> : C parameters: P extends TSchema ? Static<P> : P } } ) => any) => new Route(schema, handler)
export const Put = <B = unknown, Q = unknown, H = unknown, C = unknown, P = unknown>( schema: { body?: B, query?: Q, headers?: H, cookies?: C, parameters?: P }, handler: ( ctx: DarkflareContext & { req: { body: B extends TSchema ? Static<B> : B query: Q extends TSchema ? Static<Q> : Q headers: H extends TSchema ? Static<H> : H cookies: C extends TSchema ? Static<C> : C parameters: P extends TSchema ? Static<P> : P } } ) => any) => new Route(schema, handler)