StatsHub Docs
Packages

Packages

Shared code under packages/ — what each one owns and which apps consume it.

A package is code more than one app imports. One consumer is not a package; it is a directory in that app. Every package is named for its directory — statshub-<name> — flat under packages/.

Two UI kits, and no third

There is no shared component layer and there cannot be one: expo is React Native, web and admin target the DOM, and there is no react-native-web in this repository. A component cannot cross that line, so the kits are parallel rather than shared.

HTTP behavior is shared; platform policy is not

statshub-api-client exists because web and Expo both need the same URL serialization, JSON parsing, auth-header injection, cancellation handling, and typed error. Removing it would put those rules back into both apps, which is the package test.

Next.js revalidation and cookie handling stay in web. React Query, Cloudflare-specific retry and SecureStore stay in Expo. Those are adapters or platform policy, not transport behavior.

One identity, two shapes

Both apps now sign in against the same Supabase project, and the Go API validates its tokens either way — as a bearer header or as the @supabase/ssr cookie. getHeaders is still only injection: the receiving server validates what it is handed.

Conventions

Publish TypeScript source, not build output. Every consumer bundles it, so a build step is only a cache to invalidate.

apps/statshub-web/package.json
"dependencies": { "@statshub/ui-web": "workspace:*" }

Turbo infers build order from the dependency, so ^build already covers it. Add a package has the full walkthrough, including the Metro rules that make native packages different.

On this page