npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lessy-js/client

v1.0.22

Published

A react client for Lessy, a Headless CMS Platform.

Readme

@lessy-js/client

@lessy-js/client is a lightweight React library for easily integrating with Lessy, a headless CMS and e-commerce platform. Fetch pages, sections, products, manage customer authentication, addresses, and orders with minimal setup using intuitive hooks and a configurable client.

Installation

# NPM
npm install @lessy-js/client

# Yarn
yarn add @lessy-js/client

# PNPM
pnpm add @lessy-js/client

Quick Start

  1. Initialize your CMS client at the root of your app:

    import React from "react";
    import { initLessy } from "@lessy-js/client";
    
    // This should run once, e.g., in App.js or index.js
    initLessy({
      apiKey: "YOUR_CMS_API_KEY",
      baseUrl: "https://api.lessy.in/public", // Optional, defaults to this
      token: null, // Optional, can be set later via useAuth hook
    });
  2. Use hooks to fetch pages or sections anywhere in your component tree:

    import React from "react";
    import { usePages, useSections } from "@lessy-js/client";
    
    function PageList() {
      const { project, pages, loading, error } = usePages();
      if (loading) return <p>Loading pages...</p>;
      if (error) return <p>Error: {error.message}</p>;
    
      return (
        <>
          <h1>
            #{project.id} - {project.name}
          </h1>
          <ul>
            {pages.map((page) => (
              <li key={page.pageId}>
                {page.pageId} - {page.pageName}
              </li>
            ))}
          </ul>
        </>
      );
    }
    
    function SectionList({ pageId }) {
      const { sections, loading, error } = useSections(pageId);
      if (loading) return <p>Loading sections...</p>;
      if (error) return <p>Error: {error.message}</p>;
    
      return (
        <ul>
          {sections.map((sec) => (
            <li key={sec.sectionId}>{sec.sectionType}</li>
          ))}
        </ul>
      );
    }
    
    export default function App() {
      return (
        <div>
          <h1>My Lessy-driven Site</h1>
          <PageList />
          <h2>Sections of Page 1</h2>
          <SectionList pageId={1} />
        </div>
      );
    }

Table of Contents

Configuration

initLessy(config)

Initialize the Lessy client with your configuration. This should be called once at the root of your application.

Parameters:

  • apiKey (required): Your project's API key
  • baseUrl (optional): API base URL (default: 'https://api.lessy.in/public')
  • token (optional): Initial customer JWT token for authenticated requests

Example:

import { initLessy } from "@lessy-js/client";

initLessy({
  apiKey: "your-api-key-here",
  baseUrl: "https://api.lessy.in/public", // Optional
});

Content & Pages Hooks

usePages()

Fetches all pages for the project.

Returns:

  • project: Project information object
  • pages: Array of page objects
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { project, pages, loading, error } = usePages();

useSections(pageId)

Fetches all sections for a specific page.

Parameters:

  • pageId (required): Page ID to fetch sections for

Returns:

  • sections: Array of section objects
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { sections, loading, error } = useSections(1);

useSectionById(pageId, sectionId)

Gets a specific section by its ID.

Parameters:

  • pageId (required): Page ID
  • sectionId (required): Section ID

Returns:

  • section: Section object or null
  • loading: Boolean indicating loading state
  • error: Error object if request failed

useSectionContentItems(pageId, sectionId?)

Extracts all content items from sections, optionally filtered by section ID.

Parameters:

  • pageId (required): Page ID
  • sectionId (optional): Section ID to filter by

Returns:

  • contentItems: Array of content items
  • loading: Boolean indicating loading state
  • error: Error object if request failed

useContentItemsByType(pageId, type)

Extracts all content items of a specific type from all sections.

Parameters:

  • pageId (required): Page ID
  • type (required): Content item type

Returns:

  • items: Array of content items matching the type
  • loading: Boolean indicating loading state
  • error: Error object if request failed

useContentItem(pageId, sectionId, type, index?)

Gets a specific content item by section, type, and index.

Parameters:

  • pageId (required): Page ID
  • sectionId (required): Section ID
  • type (required): Content item type
  • index (optional): Index of the content item (default: 0)

Returns:

  • content: Content object or null
  • loading: Boolean indicating loading state
  • error: Error object if request failed

useDemoContents(template?)

Fetches demo contents for a template.

Parameters:

  • template (optional): Template name

Returns:

  • data: Demo contents data
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Authentication Hooks

useSendOTP()

Sends an OTP to a customer's phone number.

Returns:

  • sendOTP: Function to send OTP
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { sendOTP, loading, error } = useSendOTP();

const handleSendOTP = async () => {
  try {
    await sendOTP({
      country_code: "+1",
      phone_number: "234567890",
      name: "John Doe", // Optional
    });
  } catch (err) {
    console.error("Failed to send OTP:", err);
  }
};

useVerifyOTP()

Verifies an OTP and returns a customer token.

Returns:

  • verifyOTP: Function to verify OTP
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { verifyOTP, loading, error } = useVerifyOTP();
const { setToken } = useAuth();

const handleVerifyOTP = async () => {
  try {
    const result = await verifyOTP({
      country_code: "+1",
      phone_number: "234567890",
      otp: "123456",
    });
    // Token is automatically set in the client
    setToken(result.token, result.customer);
  } catch (err) {
    console.error("Failed to verify OTP:", err);
  }
};

useAuth()

Manages authentication state and token.

Returns:

  • customer: Customer object or null
  • token: JWT token string or null
  • isAuthenticated: Boolean indicating authentication status
  • setToken: Function to set the token and customer data
  • clearAuth: Function to clear authentication

Example:

const { customer, token, isAuthenticated, setToken, clearAuth } = useAuth();

if (isAuthenticated) {
  return <div>Welcome, {customer.name}!</div>;
}

Product Hooks

useProducts(options?)

Fetches products with pagination.

Parameters:

  • options (optional): Object with page and limit properties
    • page (default: 1): Page number
    • limit (default: 10): Number of products per page

Returns:

  • products: Array of product objects
  • pagination: Pagination metadata object
  • loading: Boolean indicating loading state
  • error: Error object if request failed
  • refetch: Function to refetch products

Example:

const { products, pagination, loading, error, refetch } = useProducts({
  page: 1,
  limit: 20,
});

Customer Hooks

useUpdateCustomer()

Edit cuatomer name

Parameters:

  • id (required): CustomerId

Returns:

  • updateCustomer: Address object or null
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { updateCustomer, loading, error } = useUpdateCustomer();

Address Hooks

useAddresses()

Fetches all addresses for the authenticated customer.

Returns:

  • addresses: Array of address objects
  • loading: Boolean indicating loading state
  • error: Error object if request failed
  • refetch: Function to refetch addresses

Example:

const { addresses, loading, error, refetch } = useAddresses();

useAddress(addressId)

Fetches a specific address by ID.

Parameters:

  • addressId (required): Address ID

Returns:

  • address: Address object or null
  • loading: Boolean indicating loading state
  • error: Error object if request failed
  • refetch: Function to refetch the address

useCreateAddress()

Creates a new address.

Returns:

  • createAddress: Function to create an address
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { createAddress, loading, error } = useCreateAddress();
const { refetch } = useAddresses();

const handleCreateAddress = async () => {
  try {
    await createAddress({
      address: "123 Main St",
      city: "New York",
      state: "NY",
      postal_code: "10001",
      country: "USA",
      is_default: false,
      label: "Home",
    });
    refetch(); // Refresh addresses list
  } catch (err) {
    console.error("Failed to create address:", err);
  }
};

useUpdateAddress()

Updates an existing address.

Returns:

  • updateAddress: Function to update an address
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { updateAddress, loading, error } = useUpdateAddress();

const handleUpdateAddress = async (addressId) => {
  try {
    await updateAddress(addressId, {
      address: "456 Oak Ave",
      city: "Los Angeles",
      is_default: true,
    });
  } catch (err) {
    console.error("Failed to update address:", err);
  }
};

useDeleteAddress()

Deletes an address.

Returns:

  • deleteAddress: Function to delete an address
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { deleteAddress, loading, error } = useDeleteAddress();
const { refetch } = useAddresses();

const handleDeleteAddress = async (addressId) => {
  try {
    await deleteAddress(addressId);
    refetch(); // Refresh addresses list
  } catch (err) {
    console.error("Failed to delete address:", err);
  }
};

Order Hooks

useCheckout()

Creates a new order (checkout).

Returns:

  • checkout: Function to create an order
  • loading: Boolean indicating loading state
  • error: Error object if request failed

Example:

const { checkout, loading, error } = useCheckout();

const handleCheckout = async () => {
  try {
    const order = await checkout({
      items: [
        { product_id: 5, quantity: 2 },
        { product_id: 7, quantity: 1 },
      ],
      address_id: 1,
      notes: "Special delivery instructions",
      currency: "USD",
    });
    console.log("Order created:", order.order_number);
  } catch (err) {
    console.error("Failed to checkout:", err);
  }
};

useOrders()

Fetches all orders for the authenticated customer.

Returns:

  • orders: Array of order objects
  • loading: Boolean indicating loading state
  • error: Error object if request failed
  • refetch: Function to refetch orders

Example:

const { orders, loading, error, refetch } = useOrders();

useOrder(orderNumber)

Fetches a specific order by order number.

Parameters:

  • orderNumber (required): Order number (e.g., "ORD-2025-001")

Returns:

  • order: Order object or null
  • loading: Boolean indicating loading state
  • error: Error object if request failed
  • refetch: Function to refetch the order

Example:

const { order, loading, error } = useOrder("ORD-2025-001");

Client API

If you prefer using the client directly instead of hooks, you can use the createClient function:

import { createClient } from "@lessy-js/client";

const client = createClient({
  apiKey: "your-api-key",
  baseUrl: "https://api.lessy.in/public",
  token: "optional-initial-token",
});

// Set token later
client.setToken("customer-jwt-token");

// Use client methods
const pages = await client.fetchPages();
const products = await client.fetchProducts({ page: 1, limit: 10 });

Available Client Methods

  • Authentication:

    • sendOTP({ country_code, phone_number, name })
    • verifyOTP({ country_code, phone_number, otp })
    • setToken(token)
    • getToken()
  • Content & Pages:

    • fetchPages()
    • fetchSections(pageId)
    • fetchDemoContents(template?)
  • Products:

    • fetchProducts({ page?, limit? })
  • Addresses:

    • fetchAddresses()
    • fetchAddress(addressId)
    • createAddress(addressData)
    • updateAddress(addressId, addressData)
    • deleteAddress(addressId)
  • Orders:

    • checkoutOrder(orderData)
    • fetchOrders()
    • fetchOrder(orderNumber)

Examples

Complete Authentication Flow

import { useSendOTP, useVerifyOTP, useAuth } from "@lessy-js/client";

function LoginForm() {
  const { sendOTP, loading: sendingOTP } = useSendOTP();
  const { verifyOTP, loading: verifyingOTP } = useVerifyOTP();
  const { setToken, isAuthenticated } = useAuth();
  const [phone, setPhone] = useState("");
  const [otp, setOtp] = useState("");
  const [step, setStep] = useState("phone"); // 'phone' or 'otp'

  const handleSendOTP = async (e) => {
    e.preventDefault();
    try {
      await sendOTP({
        country_code: "+1",
        phone_number: phone,
        name: "User",
      });
      setStep("otp");
    } catch (err) {
      alert("Failed to send OTP");
    }
  };

  const handleVerifyOTP = async (e) => {
    e.preventDefault();
    try {
      const result = await verifyOTP({
        country_code: "+1",
        phone_number: phone,
        otp: otp,
      });
      setToken(result.token, result.customer);
    } catch (err) {
      alert("Invalid OTP");
    }
  };

  if (isAuthenticated) {
    return <div>You are logged in!</div>;
  }

  return (
    <form>
      {step === "phone" ? (
        <>
          <input
            value={phone}
            onChange={(e) => setPhone(e.target.value)}
            placeholder="Phone number"
          />
          <button onClick={handleSendOTP} disabled={sendingOTP}>
            Send OTP
          </button>
        </>
      ) : (
        <>
          <input
            value={otp}
            onChange={(e) => setOtp(e.target.value)}
            placeholder="Enter OTP"
          />
          <button onClick={handleVerifyOTP} disabled={verifyingOTP}>
            Verify OTP
          </button>
        </>
      )}
    </form>
  );
}

Product Listing with Pagination

import { useProducts } from "@lessy-js/client";

function ProductList() {
  const [page, setPage] = useState(1);
  const { products, pagination, loading, error } = useProducts({
    page,
    limit: 12,
  });

  if (loading) return <div>Loading products...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <div className="products-grid">
        {products.map((product) => (
          <div key={product.id}>
            <h3>{product.title}</h3>
            <p>{product.description}</p>
            <p>
              ${product.price} {product.currency}
            </p>
          </div>
        ))}
      </div>
      {pagination && (
        <div className="pagination">
          <button disabled={page === 1} onClick={() => setPage(page - 1)}>
            Previous
          </button>
          <span>
            Page {pagination.page} of {pagination.totalPages}
          </span>
          <button
            disabled={page === pagination.totalPages}
            onClick={() => setPage(page + 1)}
          >
            Next
          </button>
        </div>
      )}
    </div>
  );
}

Address Management

import {
  useAddresses,
  useCreateAddress,
  useDeleteAddress,
} from "@lessy-js/client";

function AddressManager() {
  const { addresses, loading, refetch } = useAddresses();
  const { createAddress, loading: creating } = useCreateAddress();
  const { deleteAddress, loading: deleting } = useDeleteAddress();

  const handleCreate = async () => {
    try {
      await createAddress({
        address: "123 Main St",
        city: "New York",
        state: "NY",
        postal_code: "10001",
        country: "USA",
        label: "Home",
        is_default: true,
      });
      refetch();
    } catch (err) {
      alert("Failed to create address");
    }
  };

  const handleDelete = async (id) => {
    if (confirm("Delete this address?")) {
      try {
        await deleteAddress(id);
        refetch();
      } catch (err) {
        alert("Failed to delete address");
      }
    }
  };

  if (loading) return <div>Loading addresses...</div>;

  return (
    <div>
      <button onClick={handleCreate} disabled={creating}>
        Add New Address
      </button>
      <ul>
        {addresses.map((addr) => (
          <li key={addr.id}>
            <strong>{addr.label}</strong> - {addr.address}, {addr.city}
            {addr.is_default && <span> (Default)</span>}
            <button onClick={() => handleDelete(addr.id)} disabled={deleting}>
              Delete
            </button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Order Checkout

import { useCheckout, useOrders } from "@lessy-js/client";

function Checkout({ cartItems, selectedAddressId }) {
  const { checkout, loading } = useCheckout();
  const { refetch: refetchOrders } = useOrders();

  const handleCheckout = async () => {
    try {
      const order = await checkout({
        items: cartItems.map((item) => ({
          product_id: item.productId,
          quantity: item.quantity,
        })),
        address_id: selectedAddressId,
        notes: "Please deliver in the morning",
      });
      alert(`Order ${order.order_number} created successfully!`);
      refetchOrders();
    } catch (err) {
      alert("Checkout failed: " + err.message);
    }
  };

  return (
    <button onClick={handleCheckout} disabled={loading}>
      {loading ? "Processing..." : "Complete Order"}
    </button>
  );
}

Error Handling

All hooks return an error object when requests fail. You should always check for errors:

const { data, loading, error } = useSomeHook();

if (error) {
  return <div>Error: {error.message}</div>;
}

Common error scenarios:

  • 401 Unauthorized: Missing or invalid authentication token
  • 404 Not Found: Resource doesn't exist
  • 400 Bad Request: Invalid parameters or validation errors
  • 429 Too Many Requests: Rate limit exceeded (especially for OTP endpoints)

TypeScript Support

This library is written in JavaScript but can be used with TypeScript. Type definitions may be added in future versions.

License

MIT © Bititude Technologies LLP