0.1.2 • Published 5 months ago

@pubflow/nextjs v0.1.2

Weekly downloads
-
License
AGPL-3.0-or-later
Repository
-
Last release
5 months ago

@pubflow/nextjs

Next.js adapter for the Pubflow framework.

Overview

@pubflow/nextjs provides Next.js-specific implementations and utilities for the Pubflow framework, including:

  • Server-side rendering (SSR) support
  • API route handlers
  • Next.js-specific storage adapter
  • Integration with Next.js routing

Installation

# Install the core package and Next.js adapter
npm install @pubflow/core @pubflow/nextjs

# Optional: Install Zod for schema validation
npm install zod

Schema Validation

Pubflow recommends defining schemas at the application level, not in the adapter. This allows for better reusability and separation of concerns.

// lib/schemas/user.ts
import { z } from 'zod';

// Schema for complete user entity
export const userSchema = z.object({
  id: z.string().uuid().optional(),
  name: z.string().min(2, 'Name must be at least 2 characters'),
  email: z.string().email('Invalid email address'),
  role: z.enum(['user', 'admin'], 'Role must be either user or admin')
});

// Schema for creating a user
export const createUserSchema = userSchema.omit({
  id: true
});

// Schema for updating a user
export const updateUserSchema = userSchema
  .partial()
  .extend({
    id: z.string().uuid()
  });

// TypeScript types inferred from schemas
export type User = z.infer<typeof userSchema>;
export type CreateUser = z.infer<typeof createUserSchema>;
export type UpdateUser = z.infer<typeof updateUserSchema>;

These schemas can then be used with Pubflow's CRUD operations:

import { useBridgeCrud } from '@pubflow/nextjs';
import { userSchema, createUserSchema, updateUserSchema } from '../lib/schemas/user';

function UsersPage() {
  const {
    items: users,
    createItem,
    updateItem,
    deleteItem,
    validationErrors
  } = useBridgeCrud({
    entityConfig: {
      endpoint: 'users'
    },
    schemas: {
      entity: userSchema,
      create: createUserSchema,
      update: updateUserSchema
    }
  });

  // Component implementation...
}

Persistent Cache

Pubflow Next.js adapter supports persistent caching to improve performance and offline experience:

import { PubflowProvider, createPersistentCache } from '@pubflow/nextjs';

function MyApp({ Component, pageProps }) {
  // Create a persistent cache provider
  const persistentCacheProvider = createPersistentCache({
    prefix: 'my_nextjs_app_cache',
    ttl: 24 * 60 * 60 * 1000, // 24 hours
  });

  return (
    <PubflowProvider
      config={{
        baseUrl: 'https://api.example.com',
        bridgeBasePath: '/bridge',
        authBasePath: '/auth'
      }}
      persistentCache={{
        enabled: true,
        provider: persistentCacheProvider
      }}
    >
      <Component {...pageProps} />
    </PubflowProvider>
  );
}

export default MyApp;

For more information, see the persistent cache documentation.

Usage

Provider Setup

// pages/_app.tsx
import { AppProps } from 'next/app';
import { PubflowProvider } from '@pubflow/nextjs';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <PubflowProvider
      config={{
        baseUrl: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:8787',
        bridgeBasePath: '/bridge',
        authBasePath: '/auth'
      }}
      loginRedirectPath="/login"
      publicPaths={['/login', '/register', '/forgot-password']}
    >
      <Component {...pageProps} />
    </PubflowProvider>
  );
}

export default MyApp;

Server-Side Authentication

// pages/profile.tsx
import { GetServerSideProps } from 'next';
import { withPubflowSSR, useAuth } from '@pubflow/nextjs';

export const getServerSideProps: GetServerSideProps = withPubflowSSR(
  async (context, api, auth) => {
    // Check if user is authenticated
    const { isValid } = await auth.validateSession();

    if (!isValid) {
      return {
        redirect: {
          destination: '/login',
          permanent: false,
        },
      };
    }

    // Get user data
    const user = await auth.getCurrentUser();

    return {
      props: {
        user,
      },
    };
  }
);

function ProfilePage({ user }) {
  const { logout } = useAuth();

  return (
    <div>
      <h1>Profile</h1>
      <p>Name: {user.name}</p>
      <p>Email: {user.email}</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

export default ProfilePage;

API Routes

// pages/api/custom.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { withPubflow } from '@pubflow/nextjs';

export default withPubflow(async (req, res, api) => {
  // Check method
  if (req.method !== 'GET') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    // Make API request
    const response = await api.get('/some/endpoint');

    // Return response
    return res.status(200).json(response.data);
  } catch (error) {
    return res.status(500).json({ error: 'Internal server error' });
  }
});

Protected Routes with useServerAuth

// pages/dashboard.tsx
import { useServerAuth } from '@pubflow/nextjs';

function DashboardPage() {
  // This hook will automatically redirect to login if not authenticated
  const { user, isAuthenticated, isLoading } = useServerAuth({
    loginRedirectPath: '/login',
    allowedTypes: ['admin', 'manager']
  });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>Dashboard</h1>
      <p>Welcome, {user.name}!</p>
    </div>
  );
}

export default DashboardPage;

License

AGPL-3.0-or-later