Cover shared zod schemas, extract traversal/refs/downloads, and tts filename/error handling. Document the test setup in the README and docs.
2.5 KiB
2.5 KiB
TTS Workshop
Search the Tabletop Simulator Steam Workshop, fetch full TTS save files, and analyze their contents. A lightweight, client-only pnpm monorepo.
Packages
| Package | Role | Runtime |
|---|---|---|
apps/proxy |
Hono HTTP server: Workshop search + save fetch | Node |
packages/tts |
Fetch save from Steam, BSON-parse to TTSMod |
Node |
packages/extract |
Analyze a TTSMod: objects, asset refs, downloads |
Isomorphic |
packages/shared |
Shared types + zod schemas | Isomorphic |
See docs/architecture.md for the architecture and
docs/implementation-plan.md for the plan.
Setup
pnpm install
cp .env.example .env # then set STEAM_API_KEY
pnpm dev # runs the proxy at http://localhost:3000
Get a Steam Web API key at https://steamcommunity.com/dev/apikey (free).
API
| Method | Path | Description |
|---|---|---|
| GET | /health |
Liveness |
| GET | /search?q=&page= |
Search the Workshop (scrapes browse page) |
| GET | /items/:id |
Full parsed TTSMod (BSON save) |
| GET | /items/:id/file |
Raw save bytes, filename from header |
Commands
pnpm dev # run the proxy (tsx watch)
pnpm build # compile all packages
pnpm typecheck # typecheck all packages
pnpm test # run the unit tests (vitest)
pnpm lint # lint all packages
How search works
Steam has no official search API. The proxy fetches the Workshop browse page
(steamcommunity.com/workshop/browse/?appid=286160) and parses the embedded
window.SSR.renderContext JSON (a React Query cache containing a
workshop_browse entry with the results). This is more robust than scraping
the DOM, but Steam can still change the page structure — if search breaks, that
parser is the first place to look.
Notes
STEAM_API_KEYis only needed for/items/*(resolvingfile_url). Search works without it.- Each request fetches fresh; there is no caching by design (client-only tool).
packages/extracthas zero runtime dependencies and runs in browser or Node, ready for a future frontend.