TypeScript SDK
Install @trainheroic-unofficial/js, sign in to TrainHeroic, and call the runtime-agnostic client from Node, Cloudflare Workers, or the browser.
@trainheroic-unofficial/js provides the client, auth renewal, exercise library, workout
builder, athlete reads, analytics, and messaging helpers. A common first project is to
build workouts from a spreadsheet or to pull
analytics reports into your own dashboard.
Install
npm install @trainheroic-unofficial/jspnpm add @trainheroic-unofficial/jsyarn add @trainheroic-unofficial/jsbun add @trainheroic-unofficial/jsnub add @trainheroic-unofficial/jsaube add @trainheroic-unofficial/jsRequires global fetch and Web Crypto: Node 18+, Cloudflare workerd, or a modern browser.
Create a client
import { TrainHeroicClient } from "@trainheroic-unofficial/js";
const client = new TrainHeroicClient(
process.env.TRAINHEROIC_EMAIL!,
process.env.TRAINHEROIC_PASSWORD!,
);
const response = await client.request<{ id: number }>("GET", "/user/simple");
if (response.ok) {
console.log(response.data.id);
}
The client signs in lazily on the first request. If a request returns 401 or 403, it signs in again once and retries. Concurrent requests on a cold client share one login.
What request() returns
An HTTP error status does not throw, so check ok before reading data. A failed login throws
TrainHeroicAuthError.
okbooleanrequiredtrue for a 2xx status.
statusnumberrequiredThe HTTP status code TrainHeroic returned.
dataTrequiredThe response body, parsed as JSON when it is JSON and left as text otherwise. It is typed by
the generic you pass to request<T>(), and on an error status it holds the error body.
Two entry points
import { TrainHeroicClient, ExerciseLibrary, buildSession } from "@trainheroic-unofficial/js";import { JsonFileLibraryCache, defaultCachePath } from "@trainheroic-unofficial/js/node";The main entry imports no node:* modules. Filesystem-backed caching stays behind ./node so
the same SDK can run inside Cloudflare Workers.