@logiteria/commerce-sdk
v1.0.0
Published
Framework-agnostic SDK for Logiteria Commerce storefronts
Maintainers
Readme
@logiteria/commerce-sdk
Framework-agnostic TypeScript SDK for building custom storefronts on Logiteria Commerce.
Zero runtime dependencies. Works with any JavaScript framework. First-class React hooks and Next.js helpers included as optional subpath imports.
Installation
npm install @logiteria/commerce-sdk
# or
pnpm add @logiteria/commerce-sdkFor React projects, also install peer dependencies:
npm install react react-dom zustandFor Next.js projects:
npm install react react-dom zustand nextQuick Start
Vanilla TypeScript
import { createClient } from '@logiteria/commerce-sdk'
const client = createClient({
storeUrl: 'https://your-store.lumocomm.com',
})
// Browse products
const { products, total } = await client.products.list({ per_page: 12 })
// Search
const results = await client.products.search('sneakers', { min_price: 50 })
// Get product detail
const product = await client.products.get('blue-sneakers')
// Cart operations
const cart = await client.cart.create()
await client.cart.addItem(cart.id, { product_id: product.id, quantity: 1 })
await client.cart.applyCoupon(cart.id, 'SAVE10')
// Authentication
const { user, tokens } = await client.auth.login({
email: '[email protected]',
password: 'password',
})
// Access token is stored automatically after login
// Place order
const order = await client.checkout.placeOrder(cart.id, {
payment_method: 'stripe',
})React
import { CommerceProvider } from '@logiteria/commerce-sdk/react'
const config = { storeUrl: 'https://your-store.lumocomm.com' }
function App() {
return (
<CommerceProvider config={config}>
<ProductList />
</CommerceProvider>
)
}import { useProducts, useCart, useAuth } from '@logiteria/commerce-sdk/react'
function ProductList() {
const { products, loading } = useProducts({ per_page: 12 })
const { addItem, itemCount } = useCart()
const { user, isAuthenticated } = useAuth()
if (loading) return <div>Loading...</div>
return (
<div>
<p>Cart: {itemCount} items</p>
{products.map(product => (
<div key={product.id}>
<h3>{product.name}</h3>
<button onClick={() => addItem({
product_id: product.id,
name: product.name,
slug: product.slug,
sku: product.sku,
price: product.price,
quantity: 1,
image: product.thumbnail,
variant_id: null,
variant_label: null,
variant_values: {},
compare_at_price: null,
stock_status: product.stock_status,
})}>
Add to Cart
</button>
</div>
))}
</div>
)
}Next.js (App Router)
Use ISR-compatible fetchers for public pages:
// app/page.tsx — Static/ISR, no cookies
import { getProducts, getCollections } from '@logiteria/commerce-sdk/next'
export const revalidate = 60
export default async function HomePage() {
const storeUrl = process.env.NEXT_PUBLIC_STORE_URL!
const [productsData, collections] = await Promise.all([
getProducts(storeUrl, { per_page: 8 }),
getCollections(storeUrl),
])
return (
<div>
{productsData.products.map(p => <div key={p.id}>{p.name}</div>)}
</div>
)
}Use createServerClient for auth-required pages:
// app/account/orders/page.tsx — Dynamic, reads cookies
import { createServerClient } from '@logiteria/commerce-sdk/next'
export default async function OrdersPage() {
const client = await createServerClient()
const { orders } = await client.customer.orders()
return (
<div>
{orders.map(order => <div key={order.id}>{order.order_number}</div>)}
</div>
)
}API Reference
createClient(config)
Creates a CommerceClient instance.
interface CommerceClientConfig {
storeUrl: string // Base URL of your Logiteria Commerce instance
locale?: string // Default locale (e.g. "en", "tr")
timeout?: number // Request timeout in ms (default: 10000)
fetch?: typeof fetch // Custom fetch for testing
}Resources
client.products
| Method | Description |
|--------|-------------|
| list(params?) | List products with pagination, filtering, and sorting |
| get(slug) | Get a single product by slug |
| search(query, params?) | Full-text search with optional filters |
ProductListParams:
{
page?: number
per_page?: number
sort?: string // "price", "name", "created_at"
order?: 'asc' | 'desc'
category?: string // Category slug
collection?: string // Collection slug
q?: string // Search query
min_price?: number
max_price?: number
brand?: string
in_stock?: boolean
}client.collections
| Method | Description |
|--------|-------------|
| list(params?) | List all collections |
| get(slug) | Get collection with its products |
client.categories
| Method | Description |
|--------|-------------|
| tree() | Get full category tree |
| get(slug) | Get a single category |
client.cart
| Method | Description |
|--------|-------------|
| create() | Create a new cart |
| get(cartId) | Get cart by ID |
| addItem(cartId, item) | Add product to cart |
| updateItem(cartId, productId, quantity) | Update item quantity |
| removeItem(cartId, productId) | Remove item from cart |
| applyCoupon(cartId, code) | Apply coupon code |
| removeCoupon(cartId) | Remove applied coupon |
| setShippingAddress(cartId, address) | Set shipping address |
| setBillingAddress(cartId, address) | Set billing address |
| setShippingMethod(cartId, method) | Set shipping method |
| getShippingMethods() | List available shipping methods |
client.checkout
| Method | Description |
|--------|-------------|
| placeOrder(cartId, data) | Place an order |
| getDeliveryOptions(cartId) | Get delivery options for cart |
client.auth
| Method | Description |
|--------|-------------|
| login(credentials) | Login with email/password |
| register(data) | Create a new account |
| refresh() | Refresh access token |
| logout() | Logout and clear token |
| forgotPassword(email) | Send password reset email |
| resetPassword(token, password) | Reset password with token |
| getProfile() | Get authenticated user profile |
After login() or register(), the access token is stored automatically.
client.customer
All methods require authentication.
| Method | Description |
|--------|-------------|
| getProfile() | Get customer profile |
| updateProfile(data) | Update name, phone |
| orders(params?) | List order history |
| order(id) | Get order details |
| addresses() | List saved addresses |
| createAddress(data) | Add new address |
| updateAddress(id, data) | Update address |
| deleteAddress(id) | Delete address |
| loyaltyBalance() | Get loyalty points balance |
| loyaltyRewards() | List available rewards |
| loyaltyTransactions() | List points history |
| redeemReward(rewardId) | Redeem a loyalty reward |
client.settings
| Method | Description |
|--------|-------------|
| getSettings() | Get store settings (name, currency, logo, etc.) |
| getCapabilities() | Get enabled modules and features |
React Hooks
Import from @logiteria/commerce-sdk/react:
| Hook | Returns |
|------|---------|
| useProducts(params?) | { products, loading, error, total, page, totalPages, refetch } |
| useProduct(slug) | { product, loading, error } |
| useCart() | { cart, items, itemCount, subtotal, total, addItem, removeItem, updateQuantity, applyCoupon, removeCoupon, clear, ... } |
| useAuth() | { user, isAuthenticated, loading, initialized, login, register, logout, refreshProfile } |
| useCollections() | { collections, loading, error, refetch } |
| useCollection(slug) | { collection, loading, error } |
| useSearch(query, params?, debounceMs?) | { results, loading, error, facets, total } |
Next.js Helpers
Import from @logiteria/commerce-sdk/next:
ISR-compatible fetchers (no cookies, cacheable):
| Function | Description |
|----------|-------------|
| getProducts(storeUrl, params?) | Fetch product list (revalidate: 300s) |
| getProduct(storeUrl, slug) | Fetch single product (revalidate: 300s) |
| getCollections(storeUrl) | Fetch collections (revalidate: 300s) |
| getCollection(storeUrl, slug) | Fetch collection (revalidate: 300s) |
| getCategories(storeUrl) | Fetch category tree (revalidate: 300s) |
| getSettings(storeUrl) | Fetch store settings (revalidate: 3600s) |
| getCapabilities(storeUrl) | Fetch capabilities (revalidate: 3600s) |
Server client (reads cookies, forces dynamic rendering):
| Function | Description |
|----------|-------------|
| createServerClient(config?) | Create auth-aware client for Server Components |
Error Handling
All API errors throw CommerceError:
import { CommerceError } from '@logiteria/commerce-sdk'
try {
await client.products.get('nonexistent')
} catch (err) {
if (err instanceof CommerceError) {
console.log(err.code) // "not_found"
console.log(err.status) // 404
console.log(err.message) // "Product not found"
if (err.isNotFound()) { /* 404 */ }
if (err.isValidation()) {
// Field-level errors
const fields = err.fieldErrors()
// { email: ["Email is required"], password: ["Too short"] }
}
if (err.isAuth()) { /* 401/403 */ }
if (err.isServerError()) { /* 5xx */ }
if (err.isNetwork()) { /* network failure */ }
}
}Retry Behavior
- Requests automatically retry up to 2 times on 5xx errors
- Exponential backoff: 500ms, 1000ms
- Network errors also trigger retries (except timeouts)
- Customize per-request:
client.products.list()uses default; override via the HTTP client
Subpath Exports
| Import Path | What | Peer Dependencies |
|-------------|------|-------------------|
| @logiteria/commerce-sdk | Core client + types | None |
| @logiteria/commerce-sdk/react | Provider + hooks | react, zustand |
| @logiteria/commerce-sdk/next | ISR fetchers + server client | next |
The core SDK has zero runtime dependencies. React and Next.js helpers require their respective peer dependencies.
Architecture Notes
Browser vs Server: The SDK detects its environment automatically:
- Browser: Uses relative URLs (
/api/v1/...) — expects your Next.js rewrites to proxy to the store - Server: Uses absolute URLs (
https://store.example.com/api/v1/...)
Cart Hydration: The useCart() hook uses Zustand with skipHydration: true to prevent SSR mismatch. Cart state persists in localStorage and rehydrates on mount via useEffect.
ISR vs Dynamic: Use getProducts()/getCollections() from @logiteria/commerce-sdk/next for ISR/static pages. Use createServerClient() only for pages that need auth (it reads cookies which forces dynamic rendering).
License
MIT
