README

tcmts.examples.README · #47jt6xc4 · md file

Examples

Four complete apps, a family of packages and a large library imported, each built into a fresh codebase by its setup.sh. Run the apps on the docs site, each under its own path there (tcm start --base, or as a static site; the notes and polls start over, empty, every six hours), browse each as its codebase (code), or download one and build it yourself: its setup.sh uses the tcm on your PATH (or TCM, a command line for another).

polls: a live polling app

Run it (open it in two windows to see the votes arrive)

curl -fsSL https://tcm.codes/docs/examples/polls.tar.gz | tar xz
polls/setup.sh /tmp/polls      # builds the codebase there and runs its tests
cd /tmp/polls && tcm dev polls.main     # or open /tmp/polls in VS Code with the tcm-ts extension

A small app that uses most of what tcm does, with no annotations saying what runs where:

file what it shows
model.ts plain functions (tally, leader, chart) that run anywhere; tests; sample data
server.ts the server library tcm ships (which setup.sh mounts with tcm lib add tcm server): typed tables, sessions, a rate limit, a background job that announces the winner when a poll closes, a nightly schedule, a streaming function for live results, and a server test using withRequest
ui.ts browser code calling the server like local functions, including for await over the live stream
playground.ts the scratch file you start with: watch expressions over the model, and a definition to change

Its definitions are documented the tcm way: links, and examples that are evaluated (tcm docs polls.chart), and polls.README is the namespace's front page.

setup.sh adds the three files to a new codebase and then deletes them: from then on the code lives in the codebase, not in files. Browse it with tcm ls polls and tcm view polls.vote, or in VS Code's Codebase sidebar. tcm view shows where each definition runs: polls.chart anywhere, polls.vote on the server (and callable from the browser by hash), polls.main in the browser.

tcmts.cli.test.e2e.examples builds this example, starts it, votes, and checks the page in Chrome.

notes: React server components

Run it

curl -fsSL https://tcm.codes/docs/examples/notes.tar.gz | tar xz
notes/setup.sh /tmp/notes      # builds the codebase there and runs its tests
cd /tmp/notes && tcm dev notes.App      # or ▶ Start in VS Code's Apps view

A notes app in the style of React's Server Components demo, without a single "use client" or "use server". tcm infers where each component renders from what it uses (React):

file what it shows
model.ts plain functions (excerpt, matches, ago) that run anywhere; tests; sample notes
markdown.tsx a markdown renderer and its Markdown component: plain elements, so it renders on the server inside a note's page and in the browser inside the editor's live preview, from one hash
server.ts the notes table and the server functions that change it (the server library tcm ships, which setup.sh mounts with tcm lib add tcm server), with a test
styles.css the page's look: a stylesheet kept in the codebase as it's written, which ui.tsx imports like a definition (its text, as a string) and links to with <Stylesheet>, as a file the build serves
ui.tsx server components (NoteList, NotePreview: async, they read the table), browser components (App, NoteEditor, SidebarNote: state and handlers), the URL as state (through the location of the react library tcm ships, which setup.sh mounts with tcm lib add tcm react), and a test of the editor that runs in a browser (it renders a component with state)
playground.tsx the scratch file you start with: watch expressions, including a component rendered to HTML

tcm dev notes.App prints the split: three server components fetched by hash, the browser components they send by hash, and the server functions the browser calls. The first paint is rendered on the server, links to a note included, and the browser hydrates it. Saving a note refreshes the sidebar by itself: after a server function call, server components fetch their trees again.

The test suite builds this example too, then adds, opens, edits and searches notes in Chrome.

userinput: an AT Protocol client

Run it (signing in writes to your own repository, as userinput.app does)

curl -fsSL https://tcm.codes/docs/examples/userinput.tar.gz | tar xz
userinput/setup.sh /tmp/userinput      # builds the codebase there and runs its tests
cd /tmp/userinput && tcm dev userinput.app.App   # then sign in with your Bluesky handle

A client for userinput.app, feedback boards on the AT Protocol: post ideas into a space, vote, reply in threads, and, as a space's owner or moderator, set statuses, pin, hide, lock and ban. There's no server of its own: every record lives in its author's repository, and the app reads them through userinput.app's index of boards, or through an index of which records point at which (Constellation), and signs in with AT Protocol OAuth from the browser. It's the largest example (about two hundred definitions, React and React Aria), styled like Apple's apps:

file what it shows
model.ts the records (userinput.app's lexicons) as types, at:// URIs, and the services it talks to
network.ts reading the network politely: a couple of dozen requests at a time per service, backing off when asked, each read once
rules.ts what the records add up to: a status counts only from the space's moderators, an edit only from its author; scores, threads, sorting; tested
data.ts each page's data: a board or a discussion from userinput.app's own index (its app view) in one request, with your votes and new posts from your repository, which has them first; or, when the index can't say, assembled from records in many repositories
session.ts, writes.ts signing in (OAuth, or an app password), and every change as a record written to your own repository
design.tsx, markdown.tsx, styles.css the design system on React Aria, accessible by keyboard and screen reader; Markdown rendered safely; large type and squircles
home.tsx, board.tsx, discussion.tsx, people.tsx, app.tsx the pages, with the path as the state: routes matched from the react library's location, and each page's data read once per key with useData, so going back shows it at once and a refresh after a write keeps it on screen

tcm dev says it all runs in the browser. The test suite builds it too, and uses it in Chrome against a fake network (tcmts.cli.test.e2e.examples.startFakeAtproto): reading a board, signing in, replying, voting and posting.

reminders: a local-first PWA

Run it (then go offline and reload, or install it)

curl -fsSL https://tcm.codes/docs/examples/reminders.tar.gz | tar xz
reminders/setup.sh /tmp/reminders      # builds the codebase there and runs its tests
cd /tmp/reminders && tcm build reminders.App --static site   # a static site in site/, for any static host

Reminders in the style of Apple's, kept on the device: there's no server, and nothing leaves it. The docs site serves it as plain files, tcm build --static's, and it's a PWA: it installs, opens without a network, and takes a new version by itself.

file what it shows
model.ts plain functions (which list a reminder is in, due days, a reminder typed in one line) that run anywhere; tests
store.ts the device's IndexedDB database, and a channel that tells the app's other tabs and windows of a change: browser code, inferred from what it uses
ui.tsx the app: smart lists and yours, each list a path (/today, /lists/<id>), so a static build has a page for each smart list, a page at a time on a phone; it says when it's offline, and when a new version is ready (useAppUpdate)
pwa.ts the web app manifest, beside the app: its icons are files of the codebase (icon.svg, appicon.png)
styles.css Apple's look, light and dark
playground.ts the scratch file you start with

tcm view reminders.App says it all runs in the browser, so tcm build --static can write it as files: a static site has no server to run anything. The test suite builds it so, serves the files, and uses it in Chrome: it adds a reminder, reloads with the server gone, and then takes a new version, built into the same directory, by itself.

geometry: packages, releases and changelogs

curl -fsSL https://tcm.codes/docs/examples/geometry.tar.gz | tar xz
geometry/setup.sh /tmp/geometry   # builds the codebase, and its history, there
code /tmp/geometry                         # the Releases view, release-geo.md, the playground

One codebase holding two npm packages: geo, a geometry library, and atlas, a command built on it. Each is a namespace with a manifest (publishing). setup.sh gives them a history, step by step, printing each:

step what it shows
geo.ts, atlas.ts two packages in one codebase, one using the other; documented, with tests, and a command (atlas 0,0 3,4)
tcm release geo@1.0.0 --notes … first releases, declared stable, with a summary each (notes/); tcm writes the rest of the notes
steps/geo-1-1.ts a new definition and an optional parameter: additions, so tcm release geo makes it 1.1.0 by itself
steps/hexagons.ts a contribution, proposed on a branch, commented on and merged through a hub (another codebase, .hub); a new case of Shape is breaking, so it's geo 2.0.0, and its notes name the contribution
steps/next.ts an unreleased change, and a draft of its notes (release-geo.md) for you to write and release
playground.ts the scratch file: watch expressions over both packages

Then:

The test suite builds this example too, and checks its releases, changelog and packages.

effect: a large library

curl -fsSL https://tcm.codes/docs/examples/effect.tar.gz | tar xz
effect/setup.sh /tmp/effect      # fetches effect@4.1.2 from npm, imports it (minutes), runs the playground
cd /tmp/effect && tcm view effect.Effect.Effect && tcm run demo.main

Effect, imported whole from its npm package's source: 580 files, 15,671 definitions, in 6–9 minutes. It's tcm's stress test, a library written without tcm in mind, and it exercises most of what importing takes: interfaces with namespaces of types beside them (Effect.Success<…>), statements setting up constants (Impl.prototype = Proto), declare global and declare module augmentations, namespace imports everywhere, and large cycles. Once imported it's code like any other: tcm verify re-renders and re-hashes every definition in a couple of minutes, and the playground uses it from #codebase/effect/…. Browse it as its codebase (code). It's too large to build for every change to tcm: the test suite doesn't, and pnpm examples:check effect --tests checks it when importing changes.

file what it shows
setup.sh the import: npm pack effect@4.1.2, the changes below, Effect's compiler options, tcm import --into effect
changes.patch what tcm needs changed, in seven files: four where TypeScript 7.1, which tcm checks with, reports errors 7.0 doesn't; a module object used as a value (? Aead : Cipher), which tcm can't import yet; and two imports of the package by its own name (effect/Cause), which its npm package maps to its build
playground.ts programs using Effect: generators, a typed error caught by its tag, an asynchronous sleep; tests

Left out of the import: SchemaJITCompiler/enable.ts, a module that's there only for its side effect, and the Scalar and Swagger pages, which load their bundled UIs with import().

used by