# 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](https://github.com/kody-hq/kody/pull/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.js ``` `package.json#kody.app` (no `runtime` field — entry is a fetch handler): ```json { "entry": "./app/router.ts", "client": "./app/assets/entry.ts", "assets": "./public" } ``` ## Hard rules - Prefer `@tanstack/react-router` + `react` / `react-dom` (declare in `dependencies` so the host inlines them). - **No** TanStack Start / Vite / Pitlane inside the Worker publish. - Mount-aware URLs via `basepath` + remount in `app/router.ts` (same remount shape as Remix). - Server-only modules (`app/data/*`, controllers using `kody:`) must not be imported from the browser graph; loaders fall back to `Accept: application/json` fetches. - Root `tsconfig.json` sets `"jsx": "react-jsx"` + `"jsxImportSource": "react"` (standard React JSX — **not** `remix/component` pragmas). - SW in `public/sw.js` reads `/_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-only `packageSave`) - `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.png` routes work without binary `packageSave` 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.