Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

rvx-cli

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

rvx-cli

Scaffold a production-ready Vite + React project with permissions, routing, Redux, and shadcn/ui

npmnpm
Version
1.2.0
Version published
Maintainers
1
Created
Source

rvx-cli

A CLI that scaffolds production-ready Vite + React projects with a built-in permission engine, protected routing, centralized API layer, Redux state management, module generator, and shadcn/ui components — all wired together and ready to go.

npx rvx-cli my-app
cd my-app
npm run dev

Table of Contents

Why rvx-cli?

Most React scaffolding tools give you a blank canvas. rvx-cli gives you an opinionated, enterprise-ready architecture out of the box:

  • Permission enginecan(), canAny(), canAll() with super admin bypass, baked into routes, sidebar, and buttons
  • Module generatornpm run hcorp:add product creates page, add page, service, slice, API endpoints, permissions, route, and sidebar entry in one command
  • Feature-selectable — deselect Tailwind, shadcn, Redux, or Router during setup and the CLI cleanly strips all related code, files, and packages
  • POST-only API layer — centralized endpoints with React Query hooks, Bearer token auth, automatic cache invalidation
  • Responsive layout — sidebar + top-nav with mobile overlay, auto-close on navigation
  • Zero config — everything is wired: providers, store, routes, permissions, menu — just start building modules

Quick Start

# Create a new project
npx rvx-cli my-app

# Or pass the name directly
npx rvx-cli my-app

The CLI will:

  • Prompt for a project name (or accept it as an argument)
  • Let you select which features to include via interactive checkboxes
  • Copy the template, strip deselected features, and adjust all code accordingly
  • Run npm install automatically
  • Output next steps
cd my-app
npm run dev       # Start dev server (default: http://localhost:5173)
npm run build     # Production build
npm run preview   # Preview production build

Feature Selection

During scaffolding, you choose which features to include:

? Select features:
  ◉ Tailwind CSS
  ◉ shadcn/ui
  ◉ Redux Toolkit
  ◉ React Router
FeatureDefaultWhat happens when disabled
Tailwind CSSOnRemoves Tailwind packages, generates plain CSS reset, strips className attributes
shadcn/uiOnRemoves Radix/lucide packages, replaces <Button> with plain <button>, removes components/ui/, lib/, hooks/alert/. Auto-enables Tailwind if shadcn is selected
Redux ToolkitOnRemoves Redux packages, deletes src/features/ directory, module generator skips slice creation
React RouterOnRemoves router package, deletes src/layout/, generates state-based App.jsx with inline navigation

The module generator (hcorp:add) also reads this config and adapts generated code accordingly.

Project Structure

src/
├── components/ui/                    # shadcn/ui components (Button, AlertDialog, Switch)
├── constants/
│   ├── api/
│   │   └── api.js                    # Centralized API endpoints with crud() helper
│   ├── config/
│   │   ├── permissions.js            # Permission constants per module
│   │   ├── colors.js                 # Color palette for JS usage (charts, inline styles)
│   │   └── text.js                   # UI text/label constants
│   └── data/
│       └── menu.data.js              # Sidebar menu structure with permission filtering
├── context/
│   ├── auth/auth.context.jsx         # Auth state + permission engine (can, canAny, canAll)
│   ├── theme/theme.context.jsx       # Light/dark theme toggle
│   └── mobile/mobile.context.jsx     # Mobile detection + sidebar state
├── features/
│   ├── store.js                      # Redux store configuration
│   └── master/
│       └── <module>/
│           └── <module>.slice.js     # Redux slice with CRUD reducers
├── hooks/
│   ├── alert/use-alert.jsx           # Alert dialog state management hook
│   └── api/use-api.jsx               # React Query hooks (useApiQuery, useApiMutation)
├── layout/
│   ├── layout.jsx                    # Main layout (sidebar + top-nav + Outlet)
│   ├── top-nav.jsx                   # Header with hamburger, user info, logout
│   ├── sidebar.jsx                   # Permission-filtered navigation sidebar
│   ├── custom-routes.jsx             # Route definitions with ProtectedRoute wrapper
│   └── menu.item.jsx                 # NavLink menu item with active state
├── lib/
│   └── utils.js                      # cn() utility for Tailwind class merging
├── pages/views/
│   ├── dashboard.jsx                 # Dashboard landing page
│   ├── auth/
│   │   ├── auth.jsx                  # Login page with form
│   │   └── auth.service.js           # Auth API hooks (login, logout, me)
│   ├── admin/
│   │   └── permissions.jsx           # Permission toggle admin page (live testing)
│   ├── master/
│   │   └── <module>/
│   │       ├── <module>.jsx          # Module list page
│   │       ├── <module>.service.js   # Module API hooks (React Query)
│   │       └── add/
│   │           └── add.<module>.jsx  # Module add/create page
│   ├── dev-guide/
│   │   ├── dev-guide.jsx             # Interactive developer documentation
│   │   └── sections.jsx              # All documentation sections
│   └── errors/
│       ├── not-found.jsx             # 404 page
│       ├── server-error.jsx          # 500 page
│       ├── unauthorized.jsx          # 403 page
│       └── countdown-redirect.jsx    # Auto-redirect with countdown timer
├── main.jsx                          # Entry point with all providers stacked
└── index.css                         # Tailwind v4 theme variables + base styles

Module Generator

The most powerful feature — generate a complete CRUD module with a single command:

npm run hcorp:add product

What it creates

FilePath
List pagesrc/pages/views/master/product/product.jsx
Add pagesrc/pages/views/master/product/add/add.product.jsx
Service filesrc/pages/views/master/product/product.service.js
Redux slicesrc/features/master/product/product.slice.js

What it updates automatically

FileChange
constants/api/api.jsAdds PRODUCT: crud("product") — generates LIST, CREATE, UPDATE, DELETE, SEARCH endpoints
constants/config/permissions.jsAdds PRODUCT: { VIEW, ADD, EDIT, DELETE } permission block
features/store.jsImports and registers productReducer
constants/data/menu.data.jsAdds "Product" to the Master menu group with product.view permission
layout/custom-routes.jsxAdds protected routes for /master/product and /master/product/add
context/auth/auth.context.jsxAdds product.view, product.button.add, product.button.edit, product.button.delete to default permissions

Config-aware generation

The generator reads hcorp.config.json and adapts:

  • No Redux — skips slice file and store registration
  • No Router — skips route registration and useNavigate
  • No shadcn — uses plain <button> instead of <Button>
  • No Tailwind — omits all className attributes

Permission System

Permission format

Every module follows a strict 4-permission pattern:

<module>.view              → View the module page
<module>.button.add        → Show add button / access add page
<module>.button.edit       → Show edit button
<module>.button.delete     → Show delete button

Permission constants

// src/constants/config/permissions.js
export const PERMISSIONS = {
  CUSTOMER: {
    VIEW: "customer.view",
    ADD: "customer.button.add",
    EDIT: "customer.button.edit",
    DELETE: "customer.button.delete",
  },
};

Three permission functions

import { useAuth } from "@/context/auth/auth.context";

const { can, canAny, canAll } = useAuth();

can("customer.view")                                    // single check
canAny(["customer.button.add", "customer.button.edit"]) // has ANY of these
canAll(["customer.view", "customer.button.delete"])      // has ALL of these

Super admin bypass

Roles super-admin, Super Admin, or superadmin (case-insensitive) automatically pass all permission checks.

Where permissions are enforced

LayerHow
Buttons{can(PERMISSIONS.CUSTOMER.ADD) && <Button>Add</Button>}
Menu itemspermission: "customer.view" in menu.data.js — sidebar auto-filters
Routes<ProtectedRoute permission="customer.view"> wrapper
Pagescan() / canAny() / canAll() in component logic

Admin permissions page

Navigate to /admin/permissions to toggle permissions in real-time with switch toggles. Shows all registered permissions with a live JSON view — useful for testing permission-based UI behavior during development.

API Layer

Endpoint definitions

// src/constants/api/api.js
const BASE_URL = import.meta.env.VITE_API_BASE_URL || "";

function crud(module) {
  return {
    LIST:   `${BASE_URL}/api/${module}/list`,
    CREATE: `${BASE_URL}/api/${module}/create`,
    UPDATE: `${BASE_URL}/api/${module}/update`,
    DELETE: `${BASE_URL}/api/${module}/delete`,
    SEARCH: `${BASE_URL}/api/${module}/search`,
  };
}

export const API = {
  AUTH: {
    LOGIN:  `${BASE_URL}/api/auth/login`,
    LOGOUT: `${BASE_URL}/api/auth/logout`,
    ME:     `${BASE_URL}/api/auth/me`,
  },
  CUSTOMER: crud("customer"),
};

Custom endpoints

export const API = {
  // ... existing
  REPORT: {
    SALES: `${BASE_URL}/api/report/sales`,
    INVENTORY: `${BASE_URL}/api/report/inventory`,
  },
};

The crud() helper generates 5 standard endpoints per module. The module generator auto-adds MODULE: crud("module") when you run hcorp:add.

Service Files & React Query

Each module has a service file that exports React Query hooks. The hooks connect API endpoints to the useApi hook.

useApiQuery — Fetching data

import { useApiQuery } from "@/hooks/api/use-api";
import { API } from "@/constants/api/api";

const { data, isLoading, error } = useApiQuery(
  ["customer", "list"],     // cache key
  API.CUSTOMER.LIST,        // endpoint URL
  { page: 1, limit: 10 }   // POST body (optional)
);
ParamTypeDescription
keystring | string[]React Query cache key
endpointstringFull API URL from api.js
bodyobjectPOST body (auto JSON.stringify)
optionsobjectReact Query options (enabled, staleTime, etc.)

useApiMutation — Create/Update/Delete

import { useApiMutation } from "@/hooks/api/use-api";
import { API } from "@/constants/api/api";

const { mutate, isPending } = useApiMutation(
  API.CUSTOMER.CREATE,
  {
    invalidateKeys: [["customer", "list"]],  // auto-refresh list after success
    onSuccess: (data) => { /* handle */ },
    onError: (error) => { /* handle */ },
  }
);

mutate({ name: "John", email: "john@example.com" });
ParamTypeDescription
endpointstringFull API URL from api.js
options.invalidateKeysstring[][]Cache keys to invalidate on success
options.onSuccessfunctionSuccess callback
options.onErrorfunctionError callback

What the hook handles automatically

  • All requests use POST method
  • Bearer token from localStorage.getItem("token")
  • Auto JSON.stringify of request body
  • Auto JSON parse of response
  • Error extraction from response body
  • Cache invalidation on mutation success
  • Loading / error / data states via React Query

Service file pattern

// src/pages/views/master/customer/customer.service.js
import { useApiQuery, useApiMutation } from "@/hooks/api/use-api";
import { API } from "@/constants/api/api";

export function useCustomerList(params) {
  return useApiQuery(["customer", "list", params], API.CUSTOMER.LIST, params);
}

export function useCustomerCreate(options = {}) {
  return useApiMutation(API.CUSTOMER.CREATE, {
    invalidateKeys: [["customer", "list"]],
    ...options,
  });
}

export function useCustomerUpdate(options = {}) {
  return useApiMutation(API.CUSTOMER.UPDATE, {
    invalidateKeys: [["customer", "list"]],
    ...options,
  });
}

export function useCustomerDelete(options = {}) {
  return useApiMutation(API.CUSTOMER.DELETE, {
    invalidateKeys: [["customer", "list"]],
    ...options,
  });
}

Redux Store

Redux Toolkit is used for client-side global state. Server/API state is handled by React Query.

Store configuration

// src/features/store.js
import { configureStore } from "@reduxjs/toolkit";
import customerReducer from "./master/customer/customer.slice";

export const store = configureStore({
  reducer: {
    customer: customerReducer,
  },
});

Slice pattern

// src/features/master/customer/customer.slice.js
import { createSlice } from "@reduxjs/toolkit";

const customerSlice = createSlice({
  name: "customer",
  initialState: { list: [], loading: false, error: null },
  reducers: {
    setCustomers: (state, action) => { state.list = action.payload; },
    addCustomer: (state, action) => { state.list.push(action.payload); },
    updateCustomer: (state, action) => {
      const index = state.list.findIndex(item => item.id === action.payload.id);
      if (index !== -1) state.list[index] = action.payload;
    },
    removeCustomer: (state, action) => {
      state.list = state.list.filter(item => item.id !== action.payload);
    },
    setLoading: (state, action) => { state.loading = action.payload; },
    setError: (state, action) => { state.error = action.payload; },
  },
});

export const { setCustomers, addCustomer, updateCustomer, removeCustomer, setLoading, setError } = customerSlice.actions;
export default customerSlice.reducer;

When to use what

Use CaseTechnology
API data (fetch, create, update, delete)React Query (useApiQuery / useApiMutation)
Client-only global state (UI state, selections)Redux Toolkit
Auth / Theme / Mobile stateContext API

Auth Context

// src/context/auth/auth.context.jsx
import { useAuth } from "@/context/auth/auth.context";

const {
  user,                    // { name, email, role, permissions } | null
  isAuthenticated,         // boolean
  can(permission),         // check single permission
  canAny([permissions]),   // check if user has ANY
  canAll([permissions]),   // check if user has ALL
  isSuperAdmin(),          // check super admin role
  login(userData),         // set user + save token to localStorage
  logout(),                // clear user + token
  updatePermissions([]),   // update permission array
  updateRole(role),        // update user role
} = useAuth();

Login flow

const { login } = useAuth();

login({
  name: "John",
  email: "john@example.com",
  role: "admin",
  permissions: ["customer.view", "customer.button.add"],
  token: "jwt-token-from-api",
});
// Token is stored in localStorage automatically

Default demo user

The template ships with a default super-admin user for development with all permissions pre-enabled. Replace this with your actual auth API integration.

Routing & Protected Routes

Route structure

/auth                    → Login page (public, redirects if authenticated)
/                        → Dashboard (authenticated)
/master/customer         → Customer list (permission: customer.view)
/master/customer/add     → Add customer (permission: customer.button.add)
/admin/permissions       → Permission admin (authenticated)
/dev-guide               → Developer guide (authenticated)
/error/unauthorized      → 403 page
/error/server-error      → 500 page
*                        → 404 page

ProtectedRoute wrapper

function ProtectedRoute({ children, permission }) {
  const { isAuthenticated, can } = useAuth();

  if (!isAuthenticated) return <Navigate to="/auth" replace />;
  if (permission && !can(permission)) return <Navigate to="/error/unauthorized" replace />;

  return children;
}

Adding a route manually

// In custom-routes.jsx
import Product from "@/pages/views/master/product/product";

<Route
  path="master/product"
  element={
    <ProtectedRoute permission="product.view">
      <Product />
    </ProtectedRoute>
  }
/>

Or use npm run hcorp:add product to do this automatically.

Layout System

┌────────────────────────────────────────────────┐
│                   TopNav                        │
│  [☰]           App Name           [User] [Out] │
├──────────┬─────────────────────────────────────┤
│          │                                     │
│ Sidebar  │           <Outlet />                │
│  (w-64)  │        (page content)               │
│          │                                     │
│  Menu    │                                     │
│  Items   │                                     │
│          │                                     │
└──────────┴─────────────────────────────────────┘
FilePurpose
layout/layout.jsxMain wrapper — renders Sidebar + TopNav + <Outlet /> for child routes
layout/top-nav.jsxHeader with hamburger toggle, user display, and logout button
layout/sidebar.jsxNavigation sidebar with permission-filtered menu items, grouped sections
layout/menu.item.jsxIndividual NavLink item with active state styling

The sidebar width is w-64 (256px). On desktop it pushes content via ml-64. On mobile it overlays with a backdrop.

Sidebar & Menu Configuration

// src/constants/data/menu.data.js
import { LayoutDashboard, Users, Shield } from "lucide-react";

export const MENU_ITEMS = [
  {
    title: "Dashboard",
    items: [
      { label: "Dashboard", path: "/", icon: LayoutDashboard, permission: null },
    ],
  },
  {
    title: "Master",
    items: [
      { label: "Customer", path: "/master/customer", icon: Users, permission: "customer.view" },
    ],
  },
  {
    title: "Admin",
    items: [
      { label: "Permissions", path: "/admin/permissions", icon: Shield, permission: null },
    ],
  },
];
  • Set permission: null to make an item always visible to authenticated users
  • Set permission: "module.view" to filter by permission — the sidebar auto-hides items the user can't access
  • Icons are from lucide-react
  • The module generator automatically adds entries to the Master group

Theme & Styling

Tailwind CSS v4 theme variables

All theme colors are defined as CSS variables in src/index.css:

@theme {
  --color-background: #ffffff;
  --color-foreground: #0a0a0a;
  --color-primary: #171717;
  --color-primary-foreground: #fafafa;
  --color-secondary: #f5f5f5;
  --color-muted: #f5f5f5;
  --color-muted-foreground: #737373;
  --color-accent: #f5f5f5;
  --color-destructive: #ef4444;
  --color-border: #e5e5e5;
  --color-sidebar-background: #fafafa;
  --color-sidebar-foreground: #404040;
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
}

Using theme colors

<div className="bg-primary text-primary-foreground">Primary</div>
<div className="bg-destructive">Error</div>
<div className="text-muted-foreground">Subtle text</div>
<div className="bg-sidebar-background">Sidebar</div>

Theme toggle (light/dark)

import { useTheme } from "@/context/theme/theme.context";

const { theme, toggleTheme } = useTheme();
// theme is "light" or "dark"

Color constants for JavaScript

// For charts, inline styles, etc.
import { COLORS } from "@/constants/config/colors";
// COLORS.primary, COLORS.danger, COLORS.success, etc.

To change the entire app's color scheme, edit the CSS variables in index.css — all components reference these variables.

Mobile & Responsive

import { useMobile } from "@/context/mobile/mobile.context";

const { isMobile, sidebarOpen, setSidebarOpen, toggleSidebar } = useMobile();
PropertyTypeDescription
isMobilebooleantrue when viewport < 768px
sidebarOpenbooleanCurrent sidebar state
setSidebarOpenfunctionSet sidebar state directly
toggleSidebarfunctionToggle sidebar open/close

Behavior:

  • Desktop: sidebar starts open, pushes main content
  • Mobile: sidebar starts closed, opens as overlay with backdrop
  • Auto-closes on mobile when a menu item is clicked
  • Listens to window resize events

Alert Dialog System

Use the useAlert hook instead of window.alert() or window.confirm():

import { useAlert } from "@/hooks/alert/use-alert";
import {
  AlertDialog, AlertDialogContent, AlertDialogHeader,
  AlertDialogTitle, AlertDialogDescription,
  AlertDialogFooter, AlertDialogAction, AlertDialogCancel,
} from "@/components/ui/alert-dialog";

function MyComponent() {
  const { alertState, showAlert, handleConfirm, handleCancel } = useAlert();

  const handleDelete = () => {
    showAlert({
      title: "Delete Customer",
      description: "Are you sure? This cannot be undone.",
      onConfirm: () => { /* delete logic */ },
    });
  };

  return (
    <>
      <Button onClick={handleDelete}>Delete</Button>

      <AlertDialog open={alertState.open}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>{alertState.title}</AlertDialogTitle>
            <AlertDialogDescription>{alertState.description}</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel onClick={handleCancel}>Cancel</AlertDialogCancel>
            <AlertDialogAction onClick={handleConfirm}>Confirm</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  );
}
MethodDescription
showAlert({ title, description, onConfirm, onCancel })Open the dialog
handleConfirm()Execute onConfirm and close
handleCancel()Execute onCancel and close
closeAlert()Close without running callbacks
alertState.openBoolean — is dialog currently open

shadcn/ui Components

Pre-installed components in src/components/ui/:

ComponentFileRadix Primitive
Buttonbutton.jsx@radix-ui/react-slot
AlertDialogalert-dialog.jsx@radix-ui/react-alert-dialog
Switchswitch.jsx@radix-ui/react-switch

Button variants

import { Button } from "@/components/ui/button";

<Button>Default</Button>
<Button variant="destructive">Delete</Button>
<Button variant="outline">Cancel</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
<Button size="icon"><Icon /></Button>

Adding more shadcn components

Since this is JavaScript (not TypeScript), npx shadcn@latest add won't work directly. Instead:

  • Copy the component source from shadcn/ui docs
  • Create the file in src/components/ui/
  • Remove TypeScript types
  • Install the required Radix primitive: npm install @radix-ui/react-*

Environment Variables

All env vars must be prefixed with VITE_ to be exposed to client code.

FileWhen LoadedGit Tracked
.envAlways (base defaults)Yes
.env.localAlways, overrides .envNo
.env.stagingWhen --mode stagingYes
.env.productionWhen building for prodYes

Default variables

VITE_API_BASE_URL=http://localhost:3000
VITE_APP_NAME=HCorp App
VITE_PORT=5173

Accessing in code

const baseUrl = import.meta.env.VITE_API_BASE_URL;
const appName = import.meta.env.VITE_APP_NAME;

VITE_API_BASE_URL is used inside constants/api/api.js to construct all endpoint URLs — you never need to reference it directly elsewhere.

Staging build

npx vite build --mode staging

Configuration File

After scaffolding, hcorp.config.json is created in the project root:

{
  "tailwind": true,
  "shadcn": true,
  "redux": true,
  "router": true
}

This file tells the module generator which features are available. Do not manually change it after project creation — it reflects what was installed during scaffolding.

Naming Conventions

File names

TypePatternExample
Page<module>.jsxcustomer.jsx
Add Pageadd.<module>.jsxadd.customer.jsx
Service<module>.service.jscustomer.service.js
Slice<module>.slice.jscustomer.slice.js
Context<name>.context.jsxauth.context.jsx
Hookuse-<name>.jsxuse-api.jsx
Data<name>.data.jsmenu.data.js

Service hook names

use<Module>List     → useCustomerList
use<Module>Create   → useCustomerCreate
use<Module>Update   → useCustomerUpdate
use<Module>Delete   → useCustomerDelete

Redux slice actions

set<Module>s    → setCustomers
add<Module>     → addCustomer
update<Module>  → updateCustomer
remove<Module>  → removeCustomer

Permission names

<module>.view              → customer.view
<module>.button.add        → customer.button.add
<module>.button.edit       → customer.button.edit
<module>.button.delete     → customer.button.delete

Folder structure per module

src/
├── constants/api/api.js             → API.CUSTOMER: crud("customer")
├── constants/config/permissions.js  → PERMISSIONS.CUSTOMER
├── features/master/customer/        → customer.slice.js
└── pages/views/master/customer/
    ├── customer.jsx                 → List page
    ├── customer.service.js          → React Query hooks
    └── add/
        └── add.customer.jsx         → Add page

Built-in Dev Guide

Every scaffolded project includes an interactive developer guide at /dev-guide. It covers:

  • Overview & tech stack
  • Installation & setup
  • Project structure & naming conventions
  • Environment configuration
  • API layer & endpoint definitions
  • useApiQuery & useApiMutation hook reference
  • Service file patterns
  • Redux store & slice patterns
  • Auth context & login flow
  • Permission system (format, constants, functions, UI usage)
  • Protected routes
  • Layout system
  • Sidebar & menu configuration
  • shadcn/ui components
  • Alert hook
  • Module generator (hcorp:add) with generated file examples
  • Theme & Tailwind configuration
  • hcorp.config.json reference
  • Vite configuration

The guide is built as a React page with sidebar navigation — it's a living reference that stays in sync with the template.

Error Pages

PageRouteDescription
Not Found/error/not-found or *404 page with countdown redirect to home
Server Error/error/server-error500 page with countdown redirect
Unauthorized/error/unauthorized403 page with countdown redirect

All error pages use the CountdownRedirect component that displays a countdown timer and auto-redirects to the home page.

Tech Stack

TechnologyVersionPurpose
Vite6.0Build tool & dev server
React18.3UI library (JavaScript only, no TypeScript)
Tailwind CSS4.1Utility-first styling via Vite plugin
shadcn/uiAccessible UI components (Radix + Tailwind)
Redux Toolkit2.5Client-side global state management
React Router7.1Client-side routing with protected routes
TanStack React Query5.62Server state, caching, API call management
Lucide React0.468Icon library
Radix UIAccessible primitives (AlertDialog, Switch, Slot)

License

MIT

Keywords

vite

FAQs

Package last updated on 07 May 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts