ScaleRocket/Web

Packages

Shared packages for UI components, configuration, TypeScript types, and email templates.

Overview

ScaleRocket uses four shared packages in packages/ that are consumed by all three apps. They are linked via the pnpm workspace -- no publishing or version management needed.

@saas/ui

Location: packages/ui/

The shared component library built with Tailwind CSS. Based on shadcn/ui patterns.

packages/ui/
├── src/
│   ├── components/
│   │   ├── button.tsx
│   │   ├── card.tsx
│   │   ├── input.tsx
│   │   ├── toast.tsx
│   │   ├── theme-provider.tsx
│   │   └── theme-toggle.tsx
│   ├── hooks/
│   │   ├── use-toast.ts
│   │   └── use-theme.ts
│   ├── lib/
│   │   └── utils.ts          # cn() utility
│   ├── globals.css            # CSS variables, theme
│   └── index.ts               # Public exports
├── package.json
└── tsconfig.json

Usage:

import { Button, Card, Input, useToast, ThemeProvider } from "@saas/ui";

cn() utility:

// packages/ui/src/lib/utils.ts
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

@saas/config

Location: packages/config/

Centralized configuration shared across all apps.

packages/config/
├── src/
│   ├── site.ts        # Site name, URLs, SEO defaults
│   ├── pricing.ts     # Plans, prices, Stripe IDs
│   ├── credits.ts     # Credit costs per feature
│   └── index.ts       # Public exports
├── package.json
└── tsconfig.json

site.ts

export const siteConfig = {
  name: "ScaleRocket",
  description: "Ship your SaaS in days, not months",
  url: "https://scalerocket.dev",
  appUrl: "https://app.scalerocket.dev",
  opsUrl: "https://admin.scalerocket.dev",
  ogImage: "https://scalerocket.dev/og.png",
  links: {
    twitter: "https://twitter.com/scalerocket",
    github: "https://github.com/scalerocket",
  },
  support: {
    email: "support@scalerocket.dev",
  },
};

pricing.ts

export const plans = [
  {
    id: "starter",
    name: "Starter",
    price: { monthly: 9, yearly: 90 },
    stripePriceId: {
      monthly: "price_xxx",
      yearly: "price_xxx",
    },
    credits: 100,
    features: ["100 credits/month", "Email support"],
  },
  // ...more plans
];

Usage:

import { siteConfig, plans } from "@saas/config";

@saas/types

Location: packages/types/

Shared TypeScript types generated from the database schema and manually maintained API types.

packages/types/
├── src/
│   ├── database.ts    # Auto-generated from Supabase
│   ├── api.ts         # API request/response types
│   ├── auth.ts        # User, session types
│   └── index.ts       # Public exports
├── package.json
└── tsconfig.json

database.ts

Auto-generated with:

pnpm supabase gen types typescript --local > packages/types/src/database.ts

This gives you typed queries:

import type { Database } from "@saas/types";

type Profile = Database["public"]["Tables"]["profiles"]["Row"];
type Subscription = Database["public"]["Tables"]["subscriptions"]["Row"];

api.ts

Manually maintained types for Edge Function request/response shapes:

export interface CheckoutRequest {
  priceId: string;
  mode: "subscription" | "payment";
}

export interface CheckoutResponse {
  url: string;
}

export interface CreditBalance {
  balance: number;
  monthly_allowance: number;
  last_reset_at: string;
}

Usage:

import type { Database, Profile, CheckoutRequest } from "@saas/types";

@saas/emails

Location: packages/emails/

React Email templates and a sending utility using Resend.

packages/emails/
├── src/
│   ├── templates/
│   │   ├── welcome.tsx
│   │   ├── password-reset.tsx
│   │   ├── subscription-created.tsx
│   │   └── ...13 templates
│   ├── components/
│   │   └── layout.tsx         # Shared email layout
│   ├── send.ts                # Resend send utility
│   └── index.ts               # Public exports
├── package.json
└── tsconfig.json

Usage:

import { sendEmail, WelcomeEmail } from "@saas/emails";

await sendEmail({
  to: "user@example.com",
  subject: "Welcome!",
  react: WelcomeEmail({ name: "John", loginUrl: "https://..." }),
});

How to Modify a Package

  1. Edit files in packages/<name>/src/.
  2. Export new items from packages/<name>/src/index.ts.
  3. Use them in any app -- the pnpm workspace resolves the link automatically.
  4. Run pnpm type-check to verify nothing is broken.

No build step is needed for development. Turborepo handles builds for production.

How to Add a New Package

# Create the package
mkdir -p packages/analytics/src
cd packages/analytics

# Initialize
pnpm init

Edit package.json:

{
  "name": "@saas/analytics",
  "version": "0.0.0",
  "main": "./src/index.ts",
  "types": "./src/index.ts",
  "scripts": {
    "type-check": "tsc --noEmit"
  }
}

Add it to an app:

pnpm --filter app add @saas/analytics --workspace

Import and use:

import { trackEvent } from "@saas/analytics";

Done reading? Mark this page as complete.

On this page