Files
tts-workshop/docs/architecture.md
T

4.5 KiB

Architecture & Dependencies

Scope: The system's architecture and dependency graph. For implementation details (files, endpoints, build order), see implementation-plan.md. For the rationale behind key decisions, see decisions.md.

Overview

A lightweight, client-only pnpm monorepo that lets a user search the Tabletop Simulator Steam Workshop, fetch full TTS save files, and analyze their contents. It is split into four packages with a strict layering: a thin HTTP proxy on top, a low-level fetcher, an isomorphic analysis layer, and a shared types/validation package.

Design principles

  • Client-only & lightweight — no caching layer, no shared server state.
  • Fetch vs analyze separationpackages/tts only fetches and parses; packages/extract only analyzes. Neither depends on the other's concerns.
  • Isomorphic analysispackages/extract runs in browser and Node, using only fetch, Blob, and typed arrays (no Buffer, no Node-only packages).
  • Thin proxy — the HTTP layer exposes search and fetch only; traversal is intentionally not exposed as endpoints.

Package responsibilities

Package Role Runtime
apps/proxy Hono HTTP server: search + fetch endpoints Node
packages/tts Fetch save from Steam, BSON-parse to TTSMod Node
packages/extract Analyze a TTSMod: objects, refs, assets Isomorphic
packages/shared Shared types + zod schemas Isomorphic

Dependency graph

apps/proxy ──► packages/tts ──► packages/shared
      │            │
      │            └──► (fetchMod → TTSMod)
      ▼
packages/extract ──► packages/tts (traverseMod) ──► packages/shared (types)

Edges

  • apps/proxypackages/tts — calls fetchMod / getFileName to serve item requests.
  • apps/proxypackages/shared — uses shared types and zod schemas for request/response validation.
  • packages/ttspackages/shared — consumes TTSMod / TTSObject types.
  • packages/extractpackages/tts — reuses traverseMod (traversal logic lives in extract; see note below).
  • packages/extractpackages/shared — consumes shared types.

Note on traverseMod: traversal is analysis, so it lives in packages/extract. packages/tts is fetch-only. The graph edge extract → tts reflects that extract imports the traversal helper that was originally authored alongside the fetcher; tts does not depend on extract.

Layering rules

  • No upward dependenciespackages/* never import apps/*.
  • No sibling coupling beyond the graph aboveextract and tts do not depend on each other's analysis/fetch concerns.
  • packages/shared is the leaf — everything depends on it; it depends on nothing internal.

External dependencies

Package Purpose Used by
hono HTTP framework apps/proxy
@hono/node-server Node adapter for Hono apps/proxy
@hono/cors CORS middleware apps/proxy
bson BSON deserialization of TTS save files packages/tts
cheerio Workshop browse page scraping apps/proxy
zod Runtime validation apps/proxy, packages/shared

Runtime constraints

  • cheerio is backend-only — it never appears in packages/extract, which must stay isomorphic.
  • bson is Node-only — used by the fetcher, not the analysis layer.
  • packages/extract has zero external runtime deps — it relies only on platform fetch / Blob, keeping it portable to a future frontend.

Tooling dependencies

  • typescript (strict), tsx (dev runner), eslint, prettier.
  • pnpm workspaces for package management.

Deployment / runtime shape

  • The proxy runs as a single Node process via @hono/node-server.
  • packages/extract is published/consumed as a plain ESM module usable from a browser bundle or Node.
  • No shared state between requests; each request fetches fresh.