@saaslib/nextjs
TypeScript icon, indicating that this package has built-in type declarations

0.0.55 • Public • Published

Next.js SaaS Library

React hooks and utilities for building SaaS applications with Next.js, designed to work seamlessly with @saaslib/nestjs.

Requirements

{
  "peerDependencies": {
    "@stripe/stripe-js": "^5.5.0",
    "jsonwebtoken": "^9.0.2",
    "next": "^15.1.6",
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  }
}

Features

Authentication Hooks

  • useLoggedInUser(): Get the currently logged-in user from local storage
  • useSignIn(): Handle user sign-in with email/password
  • useSignUp(): Handle user registration
  • useSignOut(): Handle user logout
  • useOAuthSignIn(): Handle OAuth authentication flows
  • usePasswordReset(): Handle password reset flow

User Management

  • useGetMe(): Fetch current user details
  • usePatchMe(): Update user profile
  • useDeleteAvatar(): Remove user avatar
  • Type-safe user operations with generics

Subscription Management

  • useCreateCheckoutSession(): Create Stripe checkout sessions
  • useChangeSubscription(): Handle subscription plan changes
  • useCancelSubscription(): Handle subscription cancellations
  • useResumeSubscription(): Resume cancelled subscriptions
  • useGetBillingUrl(): Get Stripe billing portal URL

Newsletter Management

  • useNewsletterSubscription(): Handle newsletter subscriptions
  • useNewsletterTokenSubscription(): Handle token-based subscriptions
  • useNewsletterSubscriptionStatus(): Check subscription status

Resource Management

  • useFetchOwnableItems(): Fetch user-owned resources
  • useFetchOwnableItem(): Fetch single owned resource
  • useCreateOwneableItem(): Create new owned resource
  • useUpdateOwnableItem(): Update owned resource
  • useDeleteOwnableItem(): Delete owned resource

Installation

npm i @saaslib/nextjs @stripe/stripe-js@^5.5.0 jsonwebtoken@^9.0.2 next@^15.1.6 react@^19.0.0 react-dom@^19.0.0

Basic Usage

Authentication

import { useLoggedInUser, useSignIn } from '@saaslib/nextjs';

function LoginComponent() {
  const { user, loading } = useLoggedInUser();
  const { signIn, error } = useSignIn();

  const handleSubmit = async (email: string, password: string) => {
    await signIn({ email, password });
  };

  return // your component JSX
}

User Management

import { useGetMe, usePatchMe } from '@saaslib/nextjs';

function ProfileComponent() {
  const { data, loading } = useGetMe();
  const { patchMe, success } = usePatchMe();

  const handleUpdate = async (userData: Partial<User>) => {
    await patchMe(userData);
  };

  return // your component JSX
}

Subscription Management

import { useCreateCheckoutSession } from '@saaslib/nextjs';

function SubscriptionComponent() {
  const { createSession, loading } = useCreateCheckoutSession();

  const handleSubscribe = async (priceId: string) => {
    const { sessionId } = await createSession({
      priceId,
      type: 'basic'
    });
    // Redirect to Stripe checkout
  };

  return // your component JSX
}

Resource Management

import { useFetchOwnableItems, useCreateOwneableItem } from '@saaslib/nextjs';

function ResourceComponent() {
  const { data: items, loading } = useFetchOwnableItems('resources');
  const { createItem } = useCreateOwneableItem('resources');

  const handleCreate = async (data: CreateResourceDto) => {
    await createItem(data);
  };

  return // your component JSX
}

Configuration

The library requires some environment variables to be set in your Next.js application:

NEXT_PUBLIC_API_ENDPOINT=http://localhost:8000
NEXT_PUBLIC_STRIPE_PUBLIC_KEY=pk_test_...

Advanced Usage

Custom Hook Options

All fetch hooks support retry options:

const { data } = useGetMe({
  retries: 3,
  initialRetryDelay: 1000,
  backoffMultiplier: 2,
  maxRetryDelay: 30000
});

Type Safety

The library is built with TypeScript and supports generic types for all hooks:

interface CustomUser extends BaseUser {
  customField: string;
}

const { user } = useLoggedInUser<CustomUser>();
const { data } = useGetMe<CustomUser>();

Authentication Middleware

The library provides Next.js middleware for authentication:

// middleware.ts
import { authRequiredMiddleware } from '@saaslib/nextjs';

export async function middleware(req: NextRequest) {
  return await authRequiredMiddleware(req);
}

export const config = {
  matcher: ['/protected/:path*']
};

Form Actions

Type-safe form actions for auth flows and user management:

import { signInAction, signUpAction } from '@saaslib/nextjs';

// Server-side form actions
async function onSignIn(data: FormData) {
  'use server';
  return await signInAction(data);
}

async function onSignUp(data: FormData) {
  'use server';
  return await signUpAction(data);
}

Security Utilities

The package includes utilities for token management and security:

import { isAccessTokenExpired, getUserIdFromToken } from '@saaslib/nextjs';

// Check if JWT is expired
const expired = isAccessTokenExpired(token);

// Extract user ID from token
const userId = getUserIdFromToken(token);

Hooks API Reference

Authentication

useLoggedInUser<T>(): {
  user: T | null;
  loading: boolean;
}

useSignIn(): {
  signIn: (credentials: { email: string; password: string }) => Promise<void>;
  error: Error | null;
  loading: boolean;
}

useSignUp(): {
  signUp: (data: { email: string; password: string }) => Promise<void>;
  error: Error | null;
  loading: boolean;
}

useOAuthSignIn(): {
  signInWithGoogle: () => void;
  signInWithLinkedIn: () => void;
  error: Error | null;
  loading: boolean;
}

User Management

useGetMe<T>(): {
  data: { user: T } | null;
  error: Error | null;
  loading: boolean;
}

usePatchMe<T>(): {
  patchMe: (data: Partial<T>) => Promise<void>;
  error: Error | null;
  loading: boolean;
}

useDeleteAvatar(): {
  deleteAvatar: () => Promise<void>;
  error: Error | null;
  loading: boolean;
}

Subscription Management

useCreateCheckoutSession(): {
  createSession: (options: {
    priceId: string;
    type: string;
  }) => Promise<{ sessionId: string }>;
  error: Error | null;
  loading: boolean;
}

useChangeSubscription(): {
  changeSubscription: (options: {
    subscriptionId: string;
    priceId: string;
  }) => Promise<void>;
  error: Error | null;
  loading: boolean;
}

useCancelSubscription(): {
  cancelSubscription: (subscriptionId: string) => Promise<void>;
  error: Error | null;
  loading: boolean;
}

Resource Management

useFetchOwnableItems<T>(entityKey: string): {
  data: T[] | null;
  error: Error | null;
  loading: boolean;
}

useCreateOwneableItem<CreateDto, T>(entityKey: string): {
  createItem: (data: CreateDto) => Promise<T>;
  error: Error | null;
  loading: boolean;
}

useUpdateOwnableItem<UpdateDto>(entityKey: string): {
  updateItem: (itemId: string, data: UpdateDto) => Promise<void>;
  error: Error | null;
  loading: boolean;
}

Resource Management

The library provides hooks and utilities for working with ownable resources from the @saaslib/nestjs backend.

Resource Hooks API

// Fetch all resources owned by the current user
const { data: items, loading, error } = useFetchOwnableItems<T>(entityKey: string, options?: {
  retries?: number;
  initialRetryDelay?: number;
  credentials?: RequestCredentials;
});

// Fetch a single resource
const { data: item, loading, error } = useFetchOwnableItem<T>(
  entityKey: string,
  itemId: string,
  options?: FetchHookOptions
);

// Create a new resource
const { createItem, loading, error } = useCreateOwneableItem<CreateDto, T>(entityKey: string);
await createItem({
  name: 'My Resource',
  description: 'Details here'
});

// Update an existing resource
const { updateItem, loading, error } = useUpdateOwnableItem<UpdateDto>(entityKey: string);
await updateItem('resource-id', {
  name: 'Updated Name'
});

// Delete a resource
const { deleteItem, loading, error } = useDeleteOwnableItem(entityKey: string);
await deleteItem('resource-id');

Type-Safe Resource Management

interface Project {
  id: string;
  name: string;
  description?: string;
  createdAt: Date;
}

interface CreateProjectDto {
  name: string;
  description?: string;
}

interface UpdateProjectDto {
  name?: string;
  description?: string;
}

function ProjectList() {
  // Fully typed responses
  const { data: projects, loading } = useFetchOwnableItems<Project>('projects');
  const { createItem } = useCreateOwneableItem<CreateProjectDto, Project>('projects');

  const handleCreate = async (data: CreateProjectDto) => {
    const newProject = await createItem(data);
    // newProject is typed as Project
  };

  return (
    // Your JSX
  );
}

Server Actions Integration

// app/actions.ts
'use server'

import { createOwnableItem, updateOwnableItem, deleteOwnableItem } from '@saaslib/nextjs';

export async function createProject(data: CreateProjectDto) {
  return await createOwnableItem<CreateProjectDto, Project>('projects', data);
}

export async function updateProject(id: string, data: UpdateProjectDto) {
  return await updateOwnableItem<UpdateProjectDto, Project>('projects', id, data);
}

export async function deleteProject(id: string) {
  return await deleteOwnableItem('projects', id);
}

Error Handling

function ProjectManager() {
  const { createItem, error, loading } = useCreateOwneableItem<CreateProjectDto, Project>('projects');

  return (
    <div>
      {error && <ErrorAlert message={error.message} />}
      {loading && <LoadingSpinner />}
      <form onSubmit={async (e) => {
        e.preventDefault();
        try {
          await createItem({
            name: 'New Project'
          });
        } catch (e) {
          // Handle specific error cases
          if (e.status === 403) {
            // Resource limit exceeded
          }
        }
      }}>
        {/* Form fields */}
      </form>
    </div>
  );
}

Advanced Options

All resource hooks support the standard fetch options plus additional configuration:

const { data: projects } = useFetchOwnableItems<Project>('projects', {
  // Retry configuration
  retries: 3,
  initialRetryDelay: 1000,
  backoffMultiplier: 2,
  maxRetryDelay: 30000,

  // Authentication
  credentials: 'include',

  // Custom headers
  headers: {
    'Custom-Header': 'value'
  }
});

Development and Testing

// Set up testing environment
jest.mock('@saaslib/nextjs', () => ({
  useLoggedInUser: () => ({
    user: { id: 'test-user' },
    loading: false
  })
}));

// Test component
describe('Protected Component', () => {
  it('renders with user', () => {
    const { getByText } = render(<ProtectedComponent />);
    expect(getByText('Welcome')).toBeInTheDocument();
  });
});

License

MIT License - see LICENSE file for details.

Readme

Keywords

none

Package Sidebar

Install

npm i @saaslib/nextjs

Weekly Downloads

26

Version

0.0.55

License

MIT

Unpacked Size

79.2 kB

Total Files

75

Last publish

Collaborators

  • marianopardo