Development
Monorepo workflow, ports, build tasks.
Prerequisites
| Tool | Version |
|---|---|
| Node | 24+ |
| pnpm | 10.33.2 |
| bun | 1.3+ |
| docker | any recent (local Postgres) |
Dev workflow
# Install all dependencies (from repo root)
pnpm install
# One-time: local database (Postgres in docker on localhost:6178)
pnpm db:up
pnpm db:migrate
pnpm db:seed
cp apps/console/.dev.vars.example apps/console/.dev.vars
# Start everything: builds packages, then starts all dev servers
bun run devTurbo builds packages in dependency order, then starts the persistent dev servers in parallel.
The seed creates a superadmin (admin@riftix.test / riftix-dev-password),
the Riftix admin organization (all apps + the internal admin app), and an
Acme Inc. demo organization. Sign in at http://localhost:6173/login.
Invite and password-reset emails are printed to the console dev-server
terminal unless RESEND_API_KEY is set in .dev.vars. See SETUP.md at the
repo root for the full local + production runbook.
What starts
| Server | URL | Notes |
|---|---|---|
| Snippet dev server | http://localhost:6175 | Serves riftix.js with hot-rebuild via tsdown --watch |
| demo-client | http://localhost:6174 | Vite + React product page ("billing") |
| demo-vanilla | http://localhost:6177 | Plain HTML MPA ("crm") |
| console | http://localhost:6173 | Shell (TanStack Start on the Cloudflare vite plugin) |
| docs | http://localhost:6176 | This Fumadocs site (TanStack Start) |
| Postgres | localhost:6178 | docker compose (pnpm db:up) |
Turbo tasks
| Task | Command | Notes |
|---|---|---|
build | bun run build | Builds all packages + apps in dependency order |
dev | bun run dev | dependsOn: ["^build"], persistent, no cache |
typecheck | pnpm typecheck | Runs tsc --noEmit across all packages |
clean | pnpm clean | Removes dist/, .turbo/, node_modules/.cache |
Package structure
console/
├── apps/
│ ├── console/ # Shell (TanStack Start + Better Auth + Drizzle)
│ ├── demo-client/ # Billing product demo (Vite + React)
│ ├── demo-vanilla/ # CRM product demo (plain HTML MPA)
│ └── docs/ # This site (TanStack Start + Fumadocs)
└── packages/
├── console-bridge-types/ # Shared protocol types
├── console-bridge-host/ # Host transport + React adapter
├── console-bridge-snippet/ # IIFE bundle + dev server
├── console-bridge-snippet-types/ # window.Riftix TS types
└── console-bridge-snippet-react/ # React hooksSnippet dev server
The snippet package ships its own standalone dev server at packages/console-bridge-snippet/scripts/dev-server.mjs.
# Start just the snippet server
cd packages/console-bridge-snippet
node scripts/dev-server.mjsEndpoints:
| Route | Description |
|---|---|
GET /riftix.js | The IIFE bundle |
GET /riftix.js.map | Source map |
GET /healthz | 200 ok once built, 503 building before first build |
GET / | HTML usage page |
Headers on every response:
Access-Control-Allow-Origin: *
Cache-Control: no-storeEnvironment variables:
| Variable | Default | Description |
|---|---|---|
RIFTIX_SNIPPET_HOST | 127.0.0.1 | Bind address |
RIFTIX_SNIPPET_PORT | 6175 | Port |
TypeScript config
All packages extend tsconfig.base.json at the repo root:
{
"compilerOptions": {
"strict": true,
"exactOptionalPropertyTypes": true,
"noUncheckedIndexedAccess": true,
"verbatimModuleSyntax": true,
"allowImportingTsExtensions": true,
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler"
}
}Build output
| Package | Format | Output |
|---|---|---|
console-bridge-types | ESM + CJS + .d.ts | dist/ |
console-bridge-host | ESM + CJS + .d.ts | dist/ |
console-bridge-snippet | IIFE (minified) | dist/riftix.js |
console-bridge-snippet-types | ESM + .d.ts | dist/ |
console-bridge-snippet-react | ESM + CJS + .d.ts | dist/ |
The snippet bundle inlines @riftix/console-bridge-types (no external deps at runtime).
Vite optimizeDeps note
When using @riftix/console-bridge-host in a Vite host app, exclude both subpaths from pre-bundling to prevent Vite from creating two copies of the React context:
// vite.config.ts
optimizeDeps: {
exclude: [
"@riftix/console-bridge-host",
"@riftix/console-bridge-host/react",
],
},Failing to exclude the /react subpath causes useConsoleHost to read from a different context instance than ConsoleHostProvider, resulting in the error: useConsoleHost must be used inside <ConsoleHostProvider>.