npm package: @gobuildlabs/saas-starter-kit
Description: SaaS Starter Kit - Reusable utilities for building SaaS applications (Stripe helpers, Supabase auth, SEO utilities and Database, Utils)
Latest version: 0.1.0

# SaaS Starter Kit

Reusable utilities and helpers for building SaaS applications with Stripe, Supabase, Next.js, and Prisma.

## Overview

This package contains extracted, framework-agnostic utilities from the LaunchKit SaaS boilerplate. It uses dependency injection to eliminate hard-coded configuration imports, making it suitable for distribution as an npm package.

## Installation

```bash
# As workspace package (current setup)
pnpm add @gobuildlabs/saas-starter-kit@workspace:*

# Future: As published npm package
npm install @gobuildlabs/saas-starter-kit
```

## Modules

### 🔐 Authentication (Supabase)

Create Supabase clients and authentication helpers.

```typescript
import { createSupabaseAuth, createAuthHelpers } from '@gobuildlabs/saas-starter-kit/auth';

// Server-side authentication
const supabaseAuth = createSupabaseAuth({
  url: process.env.NEXT_PUBLIC_SUPABASE_URL!,
  anonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
  serviceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY,
});

export async function createServerClient() {
  const cookieStore = await cookies();
  return supabaseAuth.createServerClient(cookieStore);
}

export const supabaseAdmin = supabaseAuth.getAdminClient();

// Auth helpers
const authHelpers = createAuthHelpers({
  defaultRedirect: '/dashboard',
  appUrl: process.env.NEXT_PUBLIC_APP_URL!,
});

const callbackUrl = authHelpers.getValidCallbackUrl('/pricing');
const user = await authHelpers.getUser(supabase);
const isAuth = await authHelpers.isAuthenticated(supabase);
```

**Available Functions:**
- `createSupabaseAuth(config)` - Create server-side Supabase client factory
- `createSupabaseClientFactory(config)` - Create client-side Supabase singleton
- `createAuthHelpers(config)` - Create auth helper functions
  - `getValidCallbackUrl(url)` - Validate callback URLs (prevent open redirects)
  - `getUser(supabase)` - Get current authenticated user
  - `getSession(supabase)` - Get current session
  - `isAuthenticated(supabase)` - Check if user is authenticated

### 💳 Stripe Integration

Stripe pricing and subscription management utilities.

```typescript
import { createStripeHelpers } from '@gobuildlabs/saas-starter-kit/stripe';
import { saasConfig } from './config/saas.config';

const stripe = createStripeHelpers(saasConfig);

// Get plan details
const plan = stripe.getPlan('pro');
const paidPlans = stripe.getPaidPlans();
const hasFeature = stripe.hasPlanFeature('pro', 'hdDownloads');

// Trial management
const trialDays = stripe.getTrialDays('pro');
const trialText = stripe.formatTrialPeriod('pro'); // "14-day free trial"
const isInTrial = stripe.isInTrial(subscription);
const daysRemaining = stripe.getTrialDaysRemaining(subscription);

// Customer portal
const portalUrl = await stripe.createCustomerPortalSession(customerId, returnUrl);

// Webhook helpers
const planType = stripe.getPlanTypeByPriceId(priceId);
```

**Available Functions:**
- `getPlan(planType)` - Get plan details
- `getPaidPlans()` - Get all paid plans
- `getAllPlans()` - Get all plans including free
- `hasPlanFeature(planType, feature)` - Check if plan has feature
- `getPlanLimit(planType, limitKey)` - Get feature limit value
- `hasTrial(planType)` - Check if plan has trial
- `getTrialDays(planType)` - Get trial days
- `formatTrialPeriod(planType)` - Format trial for display
- `isInTrial(subscription)` - Check if subscription in trial
- `getTrialDaysRemaining(subscription)` - Get remaining trial days
- `createCustomerPortalSession(customerId, returnUrl)` - Create Stripe portal session
- `getPlanTypeByPriceId(priceId)` - Get plan type from price ID (for webhooks)

### 🔍 SEO & Metadata

Next.js metadata and structured data helpers.

```typescript
import { createSEOHelpers } from '@gobuildlabs/saas-starter-kit/seo';
import { saasConfig } from './config/saas.config';

const seo = createSEOHelpers(saasConfig);

// Generate page metadata
export const metadata = seo.getSEOTags({
  title: "Pricing",
  description: "Simple, transparent pricing",
  canonicalUrlRelative: "/pricing",
  keywords: ["SaaS", "pricing"],
  twitterCreator: "@yourhandle",
});

// Generate structured data
const orgSchema = seo.getOrganizationSchema();
const websiteSchema = seo.getWebsiteSchema();
const productSchema = seo.getProductSchema({
  name: "Pro Plan",
  description: "Full features",
  price: 19,
  currency: "USD",
});

// Render JSON-LD
const jsonLd = seo.renderStructuredData(orgSchema);
```

**Available Functions:**
- `getSEOTags(params)` - Generate Next.js metadata
- `getOrganizationSchema()` - Generate organization JSON-LD
- `getWebsiteSchema()` - Generate website JSON-LD
- `getProductSchema(product)` - Generate product JSON-LD
- `renderStructuredData(data)` - Convert schema to JSON string

### 🗄️ Database (Prisma)

Prisma client with singleton pattern.

```typescript
import { createPrismaClient } from '@gobuildlabs/saas-starter-kit/db';

export const prisma = createPrismaClient({
  log: ['query'], // Optional: enable query logging
});

// Use as normal
const users = await prisma.user.findMany();
```

### 🎨 Utilities

General helper functions.

```typescript
import { cn } from '@gobuildlabs/saas-starter-kit/utils';

// Merge Tailwind classes (uses clsx + tailwind-merge)
<div className={cn('text-red-500', isActive && 'bg-blue-500')} />
```

## Architecture Pattern: Dependency Injection

All utilities use dependency injection instead of hard-coded imports:

**Before (tightly coupled):**
```typescript
import { saasConfig } from '@config/saas.config'; // ❌ Hard-coded

export function getPlan(planType) {
  return saasConfig.stripe.plans[planType];
}
```

**After (dependency injection):**
```typescript
export function createStripeHelpers(config: SaasConfig) {
  return {
    getPlan: (planType) => config.stripe.plans[planType],
    // ... other functions
  };
}
```

This allows the same code to work with any configuration.

## Project Structure

```
packages/saas-starter-kit/
├── src/
│   ├── lib/
│   │   ├── stripe/
│   │   │   ├── config.ts           # Stripe helpers
│   │   │   └── index.ts
│   │   ├── auth/
│   │   │   ├── supabase-server.ts  # Server-side Supabase
│   │   │   ├── supabase-client.ts  # Client-side Supabase
│   │   │   ├── helpers.ts          # Auth utilities
│   │   │   └── index.ts
│   │   ├── seo/
│   │   │   ├── metadata.ts         # SEO & metadata
│   │   │   └── index.ts
│   │   ├── db/
│   │   │   ├── prisma.ts           # Prisma client
│   │   │   └── index.ts
│   │   └── utils/
│   │       ├── classnames.ts       # cn() utility
│   │       └── index.ts
│   ├── types/
│   │   └── index.ts                # TypeScript types
│   └── index.ts                    # Main entry point
├── dist/                           # Compiled JavaScript + declarations
├── package.json
├── tsconfig.json
└── README.md
```

## Development

```bash
# Build the package
pnpm build

# Watch mode (rebuild on changes)
pnpm dev

# Type check
pnpm type-check

# Clean build artifacts
pnpm clean
```

## Migration Status

✅ **Completed Extractions:**
1. **Stripe utilities** - `lib/stripe-config.ts` → `src/lib/stripe/config.ts`
2. **Auth utilities** - `lib/supabase.ts`, `lib/supabase-client.ts`, `lib/auth-helpers.ts` → `src/lib/auth/`
3. **SEO utilities** - `lib/seo.ts` → `src/lib/seo/metadata.ts`
4. **Database utilities** - `lib/prisma.ts` → `src/lib/db/prisma.ts`
5. **General utilities** - `lib/utils.ts` → `src/lib/utils/classnames.ts`

🚧 **Future Enhancements:**
- API route templates (webhooks, checkout)
- Reusable React components (PricingCard, AuthForm, etc.)
- CLI scaffolding tool (`npx @gobuildlabs/saas-init`)
- Email templates
- Analytics helpers
- Feature flag system

## Backward Compatibility

All web app files maintain backward compatibility through wrapper pattern:

```typescript
// apps/web/lib/stripe-config.ts
import { createStripeHelpers } from '@gobuildlabs/saas-starter-kit/stripe';
import { saasConfig } from '@config/saas.config';

const stripeHelpers = createStripeHelpers(saasConfig);

// Re-export for backward compatibility - existing code keeps working!
export const {
  getPlan,
  getPaidPlans,
  // ... all functions
} = stripeHelpers;
```

## Package Exports

The package provides modular exports for tree-shaking:

```typescript
// Main entry
import { createStripeHelpers, createSEOHelpers } from '@gobuildlabs/saas-starter-kit';

// Subpath exports
import { createStripeHelpers } from '@gobuildlabs/saas-starter-kit/stripe';
import { createSupabaseAuth } from '@gobuildlabs/saas-starter-kit/auth';
import { createSEOHelpers } from '@gobuildlabs/saas-starter-kit/seo';
import { createPrismaClient } from '@gobuildlabs/saas-starter-kit/db';
import { cn } from '@gobuildlabs/saas-starter-kit/utils';

// Types
import type { SaasConfig, PricingPlan } from '@gobuildlabs/saas-starter-kit/types';
```

## Type Safety

Full TypeScript support with generated declaration files:

```typescript
import type {
  SaasConfig,
  PricingPlan,
  PricingPlans,
  StripeHelpers,
  SEOHelpers,
  AuthHelpers,
  SupabaseAuthHelpers,
  SupabaseClientFactory,
} from '@gobuildlabs/saas-starter-kit';
```

## Peer Dependencies

The package lists framework dependencies as optional peers:
- `@prisma/client` (optional) - Only needed if using DB utilities
- `@supabase/ssr` (optional) - Only needed if using auth utilities
- `@supabase/supabase-js` (optional) - Only needed if using auth utilities
- `clsx` (optional) - Only needed if using `cn()` utility
- `tailwind-merge` (optional) - Only needed if using `cn()` utility
- `next` (optional) - Only needed if using SEO utilities

This allows consumers to only install what they need.

## License

MIT

## Next Steps

After completing Phase 1 (extraction), the roadmap includes:

**Phase 2: CLI Tool** - Create `npx @gobuildlabs/saas-init` command
**Phase 3: Template Repository** - Minimal starter template
**Phase 4: Component Library** - Extract React components
**Phase 5: API Route Templates** - Parameterized API routes
**Phase 6: Publishing** - Publish to npm registry

## Contributing

This package is currently part of a monorepo. To add new utilities:

1. Create new module in `src/lib/[module-name]/`
2. Use dependency injection pattern (accept config as parameter)
3. Add barrel export in module's `index.ts`
4. Export from main `src/index.ts`
5. Add subpath export in `package.json`
6. Build and test: `pnpm build && pnpm type-check`
7. Create wrapper in `apps/web/lib/` for backward compatibility

## Support

For issues and questions, please open an issue on GitHub.