@kentcdodds/package-app-kit
Design tokens, PWA install/update, About/version, cache helpers, and optional realtime notes sync for Kody package apps.
TanStack Router starter template
Canonical scaffolder template for @kentcdodds/package-app-kit create-package-app-tanstack (embeds via src/starter-tanstack-templates.ts / scripts/embed-starter.mjs).
Requires the framework-agnostic package-app host (kody#2312+). TanStack Router + React is a recipe with remount / jsx / hydrate boilerplate — do not set kody.app.runtime. Do not use TanStack Start's Vite toolchain — Kody publishes Workers without Vite.
The Remix recipe lives at starter-remix/ (create-package-app). The archived fetch template lives at starter-fetch/.
Layout (TanStack + React recipe)
tsconfig.json # jsx react-jsx, jsxImportSource react
app/router.ts # kody.app.entry — remount + export default { fetch }
app/routeTree.tsx # @tanstack/react-router route tree + createAppRouter
app/ssr.tsx # react-dom/server.edge renderToReadableStream (Workers-safe)
app/routes.ts # createRoutes(appBasePath) href helpers
app/pages/*.tsx # home, about, notes page components
app/controllers/* # manifest, icons, version, notes POST action
app/data/notes.ts # packageStorage() notes + migrations
app/ui/*.tsx # Document, layout, About/Notes/Install React components
app/assets/entry.ts # kody.app.client — hydrateRoot + RouterProvider
public/ # kody.app.assets — styles.css + sw.jspackage.json#kody.app (no runtime field — entry is a fetch handler):
{
"entry": "./app/router.ts",
"client": "./app/assets/entry.ts",
"assets": "./public"
}Hard rules
- Prefer
@tanstack/react-router+react/react-dom(declare independenciesso the host inlines them). - No TanStack Start / Vite / Pitlane inside the Worker publish.
- Mount-aware URLs via
basepath+ remount inapp/router.ts(same remount shape as Remix). - Server-only modules (
app/data/*, controllers usingkody:) must not be imported from the browser graph; loaders fall back toAccept: application/jsonfetches. - Root
tsconfig.jsonsets"jsx": "react-jsx"+"jsxImportSource": "react"(standard React JSX — notremix/componentpragmas). - SW in
public/sw.jsreads/_assets/__version.json— no hash in source.
Placeholders
__PACKAGE_NAME__, __PACKAGE_ID__, __APP_TITLE__, __CACHE_NAME__, __KODY_DESCRIPTION__
List / identity mark
Default mark included: the square TanStack koala (tight head/shoulders crop of the Hawaiian-shirt bust). Ships as:
.kody/icon.png(git lane) and.kody/icon.svg(base64-wrapped PNG for text-onlypackageSave)icons/icon-192.png+icons/icon-512.png(git lane binaries)src/icon-png-bytes.ts— embedded PNG bytes so/icons/icon-192.png+/icons/icon-512.pngroutes work without binarypackageSave
Favicon, PWA, and .kody/icon default to this TanStack mark (not the placeholder “T” SVG, not the Remix race-driver). Replace only when product-branding. Never scaffold root community-icon.*. Keep list identity in .kody/; keep PWA binaries under icons/ (or serve via the bytes module).
After scaffold
Default tokens/theme-color are Remix-dark charcoal + cyan (match or replace when branding). The TanStack koala mark is already the default favicon / .kody/icon / PWA mark — replace it only when the product needs its own brand. Follow the After scaffolding checklist in AGENTS.template.md. Then smoke with packageAppFetch on /, /notes, /about, /manifest.webmanifest, icons, and /health.
Layout stability / press feedback / errors
Same product rules as the Remix starter: zero CLS update toast, spin-delay busy labels (app/ui/busy.ts), ErrorBanner for reserved failures.