@commercengine/storefront-sdk
v0.14.2
Published
TypeScript SDK for the Storefront API
Downloads
1,108
Maintainers
Readme
Storefront SDK
A powerful, type-safe TypeScript SDK for the CommerceEngine Storefront API. Built with modern JavaScript patterns, automatic token management, and comprehensive error handling.
Breaking changes from the previous SDK surface are documented in MIGRATION.md.
If you are building an application on an official framework wrapper such as
Next.js, prefer @commercengine/storefront. This
package is the standalone isomorphic core SDK for SPA usage, advanced custom
integrations, and framework bindings.
✨ Key Features:
- 100% Type Safe: Every API endpoint is fully typed with TypeScript
- Automatic Token Management: Built-in refresh token logic for seamless authentication
- Universal Compatibility: Works in browser, Node.js, and hybrid rendering environments
- Production Ready: Implements all API best practices out of the box
- Zero Configuration: Works with sensible defaults, extensive customization available
Installation
npm install @commercengine/storefront-sdkyarn add @commercengine/storefront-sdkpnpm add @commercengine/storefront-sdkQuick Start
import {
BrowserTokenStorage,
Environment,
createStorefront,
} from "@commercengine/storefront-sdk";
const storefront = createStorefront({
storeId: "your-store-id",
environment: Environment.Staging,
apiKey: "your-api-key",
session: {
tokenStorage: new BrowserTokenStorage("myapp_"),
},
});
// Public reads never touch session lifecycle
const { data: products } = await storefront.public().catalog.listProducts();
// User-scoped APIs can resolve user_id from the active session automatically
const { data: wishlist } = await storefront.session().cart.getWishlist();createStorefront() returns one cached public SDK and one cached default
session SDK for that factory instance. Use storefront.session(overrides) only
for one-off, token-seeded/stateless cases that should not reuse the default
session client.
Configuration Options
The SDK supports extensive configuration to fit your needs:
Recommended Factory Pattern
const storefront = createStorefront({
// Required
storeId: "your-store-id",
// Environment (optional, defaults to Production)
environment: Environment.Staging, // or Environment.Production
// API key for public and session-backed requests
apiKey: "your-api-key",
});Session Defaults
const storefront = createStorefront({
storeId: "your-store-id",
environment: Environment.Production,
apiKey: "your-api-key",
// Custom base URL (optional, overrides environment) - Not needed for most implementations
baseUrl: "https://your-custom-api.example.com",
// Request Configuration
timeout: 10000, // Request timeout in milliseconds
// Default Headers (auto applied to all applicable requests)
defaultHeaders: {
customer_group_id: "01JHS28V83KDWTRBXXJQRTEKA0", // For pricing and promotions
},
// Debug and Logging
debug: true, // Enable detailed request/response logging - Uses console.log by default
logger: console.log, // Custom logger function - structure your logs any way you want. Also helpful to pipe logs into external services
session: {
// Token Management
accessToken: "initial-access-token", // Initial access token
refreshToken: "initial-refresh-token", // Initial refresh token (for automatic mode)
tokenStorage: new BrowserTokenStorage("myapp_"),
},
});Direct Session SDK (Advanced)
If you only need the session-aware client directly, you can still instantiate it yourself:
import {
BrowserTokenStorage,
Environment,
SessionStorefrontSDK,
} from "@commercengine/storefront-sdk";
const sdk = new SessionStorefrontSDK({
storeId: "your-store-id",
environment: Environment.Staging,
apiKey: "your-api-key",
tokenStorage: new BrowserTokenStorage("myapp_"),
});If you need the raw public transport classes directly, the advanced exports are also available:
import {
PublicStorefrontAPIClient,
PublicStorefrontSDK,
SessionStorefrontAPIClient,
SessionStorefrontSDK,
} from "@commercengine/storefront-sdk";Token Management
The SDK supports three primary access patterns:
1. Managed Sessions (Recommended)
Managed mode is enabled when you provide tokenStorage.
The SDK can then:
- Persist tokens
- Refresh expired tokens
- Bootstrap an anonymous session on the first token-required request
- Resolve
user_idautomatically for user-scoped methods
import {
BrowserTokenStorage,
SessionStorefrontSDK,
} from "@commercengine/storefront-sdk";
const sdk = new SessionStorefrontSDK({
storeId: "your-store-id",
apiKey: "your-api-key",
tokenStorage: new BrowserTokenStorage("myapp_"),
});2. Manual Sessions
Manual mode is enabled when you set tokens directly (accessToken or sdk.setTokens) without tokenStorage.
The SDK uses the token you provide but does not auto-refresh or auto-persist sessions.
const storefront = createStorefront({
storeId: "your-store-id",
apiKey: "your-api-key",
});
const sdk = storefront.session();
const { data } = await sdk.auth.loginWithPassword({
email: "[email protected]",
password: "password",
});
if (data) {
await sdk.setTokens(data.access_token, data.refresh_token);
}For stateless/token-seeded requests, create a one-off session client:
const sdk = storefront.session({
accessToken: "existing-access-token",
refreshToken: "existing-refresh-token",
});3. Public Client
Use storefront.public() when a flow should stay API-key-backed and never
participate in session bootstrap, refresh, or token persistence.
Session Helpers (sdk.session)
Use sdk.session when you need explicit control over passive vs active session reads.
peek*methods are passive reads and never mint/refresh.ensure*methods can mint/refresh in managed mode.
// Passive read (no side effects)
const userId = await sdk.session.peekUserId();
// Active resolution (may mint or refresh in managed mode)
const resolvedUserId = await sdk.session.ensureUserId();Token Storage Options
Choose the storage method that fits your environment:
Browser localStorage
import { BrowserTokenStorage } from "@commercengine/storefront-sdk";
const tokenStorage = new BrowserTokenStorage("myapp_"); // Optional prefixBrowser cookies (for browser persistence or cross-tab sync)
import { CookieTokenStorage } from "@commercengine/storefront-sdk";
const tokenStorage = new CookieTokenStorage({
prefix: "myapp_",
maxAge: 7 * 24 * 60 * 60, // 7 days
secure: true,
sameSite: "Lax",
});CookieTokenStorage uses document.cookie and is browser-only. It is useful
for browser cookie persistence and cross-tab visibility, but it is not
request-aware SSR storage. For framework server/client continuity, use an
official wrapper from @commercengine/storefront or a request-aware storage
adapter from @commercengine/ssr-utils.
Memory (for server-side or temporary storage)
import { MemoryTokenStorage } from "@commercengine/storefront-sdk";
const tokenStorage = new MemoryTokenStorage();Custom Storage
class CustomTokenStorage implements TokenStorage {
async getAccessToken(): Promise<string | null> {
// Your implementation
}
async setAccessToken(token: string): Promise<void> {
// Your implementation
}
// ... implement other required methods
}Authentication
If you use managed sessions (tokenStorage), you usually do not need to call
anonymous auth manually. The SDK can bootstrap anonymous sessions
automatically on token-required requests.
That lazy bootstrap is a core SDK capability, not necessarily the primary app pattern for every framework. For official framework wrappers, the recommended pattern is still to bootstrap explicitly in app code when later server-side session reads depend on established cookie continuity.
Anonymous Authentication
// Optional: manually create an anonymous session
const { data } = await sdk.auth.getAnonymousToken();
if (data) {
await sdk.setTokens(data.access_token, data.refresh_token);
}Phone/Email Authentication
// Step 1: Initiate login
const { data: otpData } = await sdk.auth.loginWithPhone({
phone: "9876543210",
country_code: "+91",
register_if_not_exists: true,
});
// Step 2: Verify OTP
if (otpData) {
const { data: authData } = await sdk.auth.verifyOtp({
otp: "123456",
otp_token: otpData.otp_token,
otp_action: otpData.otp_action,
});
if (authData) {
await sdk.setTokens(authData.access_token, authData.refresh_token);
}
}Password Authentication
const { data } = await sdk.auth.loginWithPassword({
email: "[email protected]",
password: "your-password",
});
if (data) {
await sdk.setTokens(data.access_token, data.refresh_token);
}API Clients & Complete Type Safety
The SDK provides complete access to every CommerceEngine API endpoint with full TypeScript support. All clients are automatically generated from the OpenAPI specification, ensuring 100% accuracy and type safety.
Available Clients
// Authentication & User Management
sdk.auth.* // Login, registration, OTP, password management
sdk.customer.* // Customer profiles, addresses, preferences
// E-commerce Core
sdk.catalog.* // Products, categories, search, variants
sdk.cart.* // Cart management, coupons, promotions
sdk.order.* // Order creation, tracking, history
// Supporting Services
sdk.helpers.* // Countries, currencies, utilities
sdk.store.* // Store config and health endpointsExample Usage
// Every method is fully typed - IntelliSense shows all available parameters
const { data: products } = await sdk.catalog.listProducts({
query: {
page: 1,
limit: 20,
category_id: "electronics",
sort: "price_asc",
}
});
// Get product details
const { data: product } = await sdk.catalog.getProduct({
product_id_or_slug: "product-id"
});
// Create a cart with full type checking
const { data: cart } = await sdk.cart.createCart({
items: [
{
product_id: "product-id",
quantity: 2,
variant_id: "variant-id",
}
]
});📚 API Reference: For complete endpoint documentation, parameters, and response schemas, visit docs.commercengine.io/api-reference
User Information & JWT Utilities
The top-level getters are passive lookups. They never mint or refresh a session:
// Passive reads from the current token
const userInfo = await sdk.getUserInfo();
console.log(userInfo?.userId, userInfo?.email, userInfo?.customerId);
// Check authentication status
const isLoggedIn = await sdk.isLoggedIn();
const isAnonymous = await sdk.isAnonymous();
// Get specific user data
const userId = await sdk.getUserId();
const customerId = await sdk.getCustomerId();
const customerGroupId = await sdk.getCustomerGroupId();Use sdk.session.ensure* for active resolution:
const userId = await sdk.session.ensureUserId();
const accessToken = await sdk.session.ensureAccessToken();For user-scoped APIs, user_id can be omitted and resolved automatically in managed mode:
await sdk.cart.getWishlist();
await sdk.customer.listAddresses();
await sdk.order.listOrders({ page: 1, limit: 20 });Error Handling
All API calls return a consistent ApiResult<T> structure with full error information:
const { data, error, response } = await sdk.catalog.listProducts();
if (error) {
console.error("API Error:", error.message, error.code);
console.log("Status:", response.status);
} else {
console.log("Success:", data);
}Network Error Handling
const result = await sdk.catalog.getProduct({ product_id_or_slug: "invalid-id" });
if (result.error) {
switch (result.error.code) {
case "NETWORK_ERROR":
console.log("Network connection failed");
break;
case "UNAUTHORIZED":
console.log("Authentication required");
break;
default:
console.log("API Error:", result.error.message);
}
}Debug Mode
Enable detailed logging for development:
const sdk = new SessionStorefrontSDK({
storeId: "your-store-id",
debug: true,
// Optional: Pass a custom logger
logger: (message, data) => {
console.log(`[SDK Debug] ${message}`, data);
},
});Debug mode logs:
- Request URLs, methods, headers, and bodies
- Response status, headers, and bodies
- Token refresh attempts and results
- Network errors and retry attempts
TypeScript Support
The SDK is built with TypeScript-first design:
import type {
ApiResult,
UserInfo,
DebugLoggerFn,
SupportedDefaultHeaders
} from "@commercengine/storefront-sdk";
// All API responses are properly typed
const { data }: ApiResult<ProductListResponse> = await sdk.catalog.listProducts();
// IntelliSense works for all nested properties
console.log(data?.products[0].name);Universal Compatibility
The SDK works seamlessly across all JavaScript environments:
Client-Side Applications
- React, Vue, Angular: Use
BrowserTokenStoragefor persistent sessions - Automatic token refresh: Handles token expiry transparently
- Cross-tab synchronization: With
CookieTokenStorage
Server-Side Applications
- Node.js, Bun, Deno: Use
MemoryTokenStorageor custom storage - API routes: Perfect for Next.js API routes, Express middleware
- Background jobs: Reliable token management for long-running processes
Hybrid Rendering (SSR/SSG)
- Official framework wrappers: Prefer
@commercengine/storefront - Custom SSR integrations: Use request-aware storage from
@commercengine/ssr-utils - CookieTokenStorage: Browser-only cookie persistence, not server request storage
- Hydration-safe setups: depend on framework-aware request storage, not
document.cookie
Best Practices Built-In
The SDK implements CommerceEngine API best practices automatically:
- ✅ Automatic token refresh before expiry
- ✅ Proper error handling for all edge cases
- ✅ Request retries for transient failures
- ✅ Rate limiting compliance with proper backoff
- ✅ Security headers and CSRF protection
- ✅ Timeout handling with configurable limits
- ✅ Memory leak prevention with proper cleanup
Contributing
Version Management with Changeset
This project uses Changeset for version management and publishing. Here's how to contribute:
Creating Changes
When you make changes to the SDK, create a changeset to document them:
pnpm changesetThis will prompt you to:
- Select the type of change (patch/minor/major)
- Write a summary of what changed
- Create a markdown file in the
.changeset/folder
Version Types
- Patch (0.0.x): Bug fixes, documentation updates, internal refactoring
- Minor (0.x.0): New features, new API endpoints, backwards-compatible changes
- Major (x.0.0): Breaking changes, API modifications that affect existing code
Release Process
During Development: Create changesets for your changes
pnpm changesetBefore Release: Consume changesets and update versions
pnpm versionThis updates
package.json, generates/updatesCHANGELOG.md, and removes consumed changesets.Publishing: Build and publish to npm
pnpm release
Available Scripts
pnpm changeset- Create a new changesetpnpm run version- Consume changesets and bump versionpnpm run release- Build and publish to npm
The changeset workflow ensures proper semantic versioning, comprehensive changelogs, and coordinated releases.
License
All Rights Reserved
