Initial commit

This commit is contained in:
Devin Zuczek
2026-06-08 18:23:40 -04:00
commit 8e644a5c20
141 changed files with 21414 additions and 0 deletions
@@ -0,0 +1,78 @@
import { httpStatus } from 'http-codex/status'
import type { Context, Next } from 'hono'
import type { StatusCode } from 'hono/utils/http-status'
import type { HonoApp } from '../types'
/** Caches status: 200 responses for given ttl */
export function withCache<T extends HonoApp>(ttl: number) {
return async (ctx: Context<T>, next: Next): Promise<Response | void> => {
const c = ctx as unknown as Context<HonoApp>
const cache = await caches.open('default')
const reqMatcher = new Request(c.req.url, { method: c.req.method })
const cachedRes = await cache.match(reqMatcher)
if (cachedRes) {
return c.newResponse(cachedRes.body, cachedRes)
}
await next()
if (c.res.status === httpStatus.OK) {
const clonedRes = c.res.clone()
clonedRes.headers.set('Cloudflare-CDN-Cache-Control', `max-age=${ttl}`)
c.executionCtx.waitUntil(cache.put(reqMatcher, clonedRes))
}
}
}
/** Caches using default CF Cache behavior */
export function withCacheDefault<T extends HonoApp>(ttl: number) {
return async (ctx: Context<T>, next: Next): Promise<Response | void> => {
const c = ctx as unknown as Context<HonoApp>
const cache = await caches.open('default')
const cachedRes = await cache.match(c.req.raw)
if (cachedRes) {
return c.newResponse(cachedRes.body, cachedRes)
}
await next()
if (c.res.status === httpStatus.OK) {
const clonedRes = c.res.clone()
clonedRes.headers.set('Cloudflare-CDN-Cache-Control', `max-age=${ttl}`)
c.executionCtx.waitUntil(cache.put(c.req.raw, clonedRes))
}
}
}
interface CacheByStatus {
status: StatusCode
/** Time in milliseconds to cache this status */
ttl: number
}
interface WithCacheByStatusOptions {
rules: CacheByStatus[]
/** Force caching rather than using default CF cache behavior */
force: boolean
}
/** Caches responses based on status */
export function withCacheByStatus<T extends HonoApp>(options: WithCacheByStatusOptions) {
return async (ctx: Context<T>, next: Next): Promise<Response | void> => {
const c = ctx as unknown as Context<HonoApp>
const cache = await caches.open('default')
const reqMatcher = options.force ? new Request(c.req.url, { method: c.req.method }) : c.req.raw
const cachedRes = await cache.match(reqMatcher)
if (cachedRes) {
return c.newResponse(cachedRes.body, cachedRes)
}
await next()
const opts = options.rules.find((o) => o.status === c.res.status)
if (opts) {
const clonedRes = c.res.clone()
clonedRes.headers.set('Cloudflare-CDN-Cache-Control', `max-age=${opts.ttl}`)
c.executionCtx.waitUntil(cache.put(reqMatcher, clonedRes))
}
}
}
@@ -0,0 +1,10 @@
import { cors } from 'hono/cors'
/** Default CORS handler */
export function withDefaultCors() {
return cors({
origin: '*',
allowMethods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD'],
allowHeaders: ['Content-Type', 'Authorization'],
})
}
@@ -0,0 +1,19 @@
import { httpStatus } from 'http-codex/status'
import type { Context } from 'hono'
import type { APIError } from '../helpers/errors'
import type { HonoApp } from '../types'
/** Handles typical notFound hooks */
export function withNotFound<T extends HonoApp>() {
return async (ctx: Context<T>): Promise<Response> => {
const c = ctx as unknown as Context<HonoApp>
return c.json(notFoundResponse, httpStatus.NotFound)
}
}
export const notFoundResponse = {
success: false,
error: { message: 'not found' },
} satisfies APIError
@@ -0,0 +1,40 @@
import { HTTPException } from 'hono/http-exception'
import { httpStatus } from 'http-codex/status'
import { logger } from '../helpers/logger'
import type { Context } from 'hono'
import type { ContentfulStatusCode } from 'hono/utils/http-status'
import type { APIError } from '../helpers/errors'
import type { HonoApp } from '../types'
/** Handles typical onError hooks */
export function withOnError<T extends HonoApp>() {
return async (err: Error, ctx: Context<T>): Promise<Response> => {
const c = ctx as unknown as Context<HonoApp>
if (err instanceof HTTPException) {
const status = err.getResponse().status as ContentfulStatusCode
const body: APIError = { success: false, error: { message: err.message } }
if (status >= 500) {
// TODO: Capture to Sentry
// Log to Sentry
logger.error(err)
} else if (status === httpStatus.Unauthorized) {
body.error.message = 'unauthorized'
}
return c.json(body, status)
}
// TODO: Capture to Sentry
logger.error(err)
return c.json(
{
success: false,
error: { message: 'internal server error' },
} satisfies APIError,
500
)
}
}