Skip to content

Kody is live

Watch the launch video — what Kody is, and why it exists.

← Public packages

@kentcdodds/package-app-kit

Design tokens, PWA install/update, About/version, cache helpers, and optional realtime notes sync for Kody package apps.

app/router.ts

65 lines · 2.2 KB · TypeScript
import { packageContext } from 'kody:runtime'
import { createRouter } from 'remix/router'
import { formData } from 'remix/middleware/form-data'
import { requestId } from './middleware/request-id.ts'
import { routes } from './routes.ts'
import home from './controllers/home.tsx'
import about from './controllers/about.tsx'
import notes from './controllers/notes.tsx'
import manifest from './controllers/manifest.ts'
import version from './controllers/version.ts'
import { icon192, icon512 } from './controllers/icons.ts'
import { logoBust, logoFull } from './controllers/brand.ts'
import { serverCachified } from '../src/server-cache.ts'
import { handleRealtimeEvent as kitHandleRealtimeEvent } from '../src/realtime.ts'

const router = createRouter({ middleware: [requestId(), formData()] })

router.map(routes.home, home)
router.map(routes.about, about)
router.map(routes.notes, notes)
router.map(routes.manifest, manifest)
router.map(routes.versionApi, version)
router.map(routes.icon192, icon192)
router.map(routes.icon512, icon512)
router.map(routes.logoBust, logoBust)
router.map(routes.logoFull, logoFull)

async function demoHealth() {
	let fresh = false
	const value = await serverCachified({
		key: 'demo-health',
		ttl: 15_000,
		getFreshValue: async () => {
			fresh = true
			return {
				ok: true,
				generatedAt: new Date().toISOString(),
				cache: 'cachified+packageStorage',
			}
		},
	})
	return { ...value, fresh }
}

router.get(routes.health, async () => Response.json(await demoHealth()))

// Host strips the mount before forwarding. Remix route contracts that include
// appBasePath need the hosted pathname, so remount here.
function remountRequest(request: Request) {
	const appBasePath = String(packageContext?.appBasePath ?? '').replace(/\/+$/, '')
	if (!appBasePath) return request
	const url = new URL(request.url)
	url.pathname = url.pathname === '/' ? appBasePath : appBasePath + url.pathname
	return new Request(url, request)
}

/** Package realtime hook — notes topic subscribe + ping/pong (see `./realtime`). */
export const handleRealtimeEvent = kitHandleRealtimeEvent

// Default-export { fetch } — do not export the router object (Worker env is not RequestInit).
export default {
	fetch(request: Request) {
		return router.fetch(remountRequest(request))
	},
}