A high-performance, server-rendered Next.js App Router e-commerce application with integrated Zonos Elements for cross-border commerce.
Zonos Commerce is a feature-rich e-commerce application built on the framework of Next.js Commerce that integrates with Zonos Elements to provide seamless cross-border shopping experiences. The platform leverages Zonos Hello for accurate duty and tax calculations and Zonos Checkout for international checkout processing.
For detailed technical specifications and architecture, please refer to SPECS.md.
The project comes with sample data for demonstration purposes. These files are located in:
/lib/data-samples/samples/products.ts- Sample product data/lib/data-samples/samples/collections.ts- Sample collection data/lib/data-samples/samples/pages.ts- Sample page content/lib/data-samples/samples/menu.ts- Sample menu structure
For production use, you should replace these sample files with your actual data by modifying these files or implementing custom data fetching logic.
This project contains three primary Zonos-specific directories that should not be modified as they contain critical integration code:
app/api/zonos/- Server API routes for Zonos communicationcomponents/zonos/- UI components that integrate with Zonos Elementslib/zonos/- Core functions, types, and utilities for Zonos integration
Exception: The lib/zonos/constants.ts file is designed to be customized. This is where you configure your element selectors, URL paths, and other options for Zonos Elements initialization.
// Example configuration in lib/zonos/constants.ts export const ZONOS_CONFIG: ZonosConfig = { PLACE_ORDER_BUTTON: '#your-checkout-button', PRODUCT_ADD_TO_CART: '.your-add-to-cart-class', // Additional selectors... };The ZonosConfig type is defined in lib/zonos/constants.ts and provides proper typing for all available configuration options. This typed interface ensures you're using valid configuration properties for Zonos Elements.
Anything not in a zonos folder may be freely modified, added to, or removed from the project. You have complete freedom to create, update, and delete any file that is not inside a zonos directory, including all UI components. The current implementation serves as a reference example of integrating Zonos with an e-commerce site.
We recommend merchants fork this repository rather than using it directly. By forking the repository:
- You can make your own customizations and changes to fit your specific business needs
- You can easily pull in upstream changes when Zonos Commerce is updated with new features or dependencies
- You maintain full control over your codebase while benefiting from continuous improvements
- Use GitHub's fork button to create your own copy of the repository
- Clone your forked repository to your local machine:
git clone https://github.com/YOUR-USERNAME/commerce.git - Add the original repository as an upstream remote:
git remote add upstream https://github.com/zonos/commerce.git - When you want to pull in updates:
git fetch upstream git merge upstream/main
The following functions provide the foundation for Zonos integration:
-
addToCart({ sku, quantity }): Adds a product to the cart using the Zonos SDK clientconst updatedCartId = await addToCart({ sku: 'product123', quantity: 1 });
-
removeFromCart({ cart, itemIds }): Removes items from the cart using the Zonos SDK clientconst updatedCartId = await removeFromCart({ cart: currentCart, itemIds: ['item-id-1', 'item-id-2'] });
-
updateItemQuantity(null, { sku, quantity }): Updates the quantity of an item in the cartconst updatedCartId = await updateItemQuantity(null, { sku: 'product123', quantity: 2 });
-
getCart(): Retrieves the current cart from cookiesconst currentCart = await getCart();
All server-side Zonos API requests are made using the Zonos TypeScript SDK client, authenticated with CUSTOMER_GRAPH_TOKEN.
revalidate(): Handles cache invalidation for updated contentNote: The// Used in webhook handlers to refresh data await revalidate();
revalidate()function is currently a placeholder and does not yet provide full functionality. It will be implemented in future updates.
- Node.js (version 18.x or later)
- pnpm (version 9.x or later)
- Zonos API key (obtain from the Zonos Dashboard)
-
Clone the repository
-
Install dependencies using pnpm
-
Create a
.env.localfile in the root directory based on the.env.exampletemplate, which includes:Required server-side variables:
CUSTOMER_GRAPH_TOKEN: Secret token for server-side API calls to Zonos ElementsZONOS_REVALIDATION_SECRET: Secret used for cache invalidation
Required client-side variables:
NEXT_PUBLIC_ZONOS_API_KEY: Your Zonos API key for client-side initializationNEXT_PUBLIC_ZONOS_STORE_ID: Your Zonos store IDNEXT_PUBLIC_ZONOS_CDN_URL: URL to the Zonos Elements CDNNEXT_PUBLIC_SITE_NAME: The name of your store for client-side display
Optional configuration variables:
NEXT_PUBLIC_ZONOS_ENVIRONMENT: Set to "sandbox" or "production"NEXT_PUBLIC_COMPANY_NAME: Your company name for client-side display
The CUSTOMER_GRAPH_TOKEN is a required server-side variable used for authenticated API requests to Zonos services. This token is used by the Zonos SDK client for all server-side API calls, particularly for cart operations and checkout processing.
The NEXT_PUBLIC_ZONOS_API_KEY is an organization key used for client-side initialization of Zonos Elements. It allows verification of organization access to the graph and checks for allowed domains in the Zonos Elements API. This key is designed to be safely included in client-side code.
The project uses Zod for robust environment variable validation with separate server and client environments:
- Type Safety: All environment variables are validated for type correctness at build time
- Security: Prevents accidental exposure of server-side variables to the client
- Structure:
lib/environment/environment.server.ts- Server-side variables validationlib/environment/environment.client.ts- Client-side variables validation (prefixed withNEXT_PUBLIC_)lib/environment/environment.base.ts- Shared validation schemas and utilities
To use environment variables in your code:
// Server-side code (API routes, server components) import { serverEnv } from 'lib/environment/environment.server'; const token = serverEnv.CUSTOMER_GRAPH_TOKEN; // Client-side code (hooks, client components) import { clientEnv } from 'lib/environment/environment.client'; const apiKey = clientEnv.NEXT_PUBLIC_ZONOS_API_KEY; // Anywhere (convenience export) import { env } from 'lib/environment'; const siteName = env.NEXT_PUBLIC_SITE_NAME; // server-side context const publicSiteName = env.NEXT_PUBLIC_SITE_NAME; // client-side context# Install dependencies pnpm install # Start the development server pnpm devThe application will be available at http://localhost:3000.
# Create a production build pnpm build # Start the production server pnpm startThis project uses Vitest for unit testing. Some unit tests have already been implemented, and there are plans to expand testing with Storybook (component testing) and Playwright (integration/E2E testing) in the future.
The current test suite includes:
- Unit tests for utility functions in
lib/utils.ts - Tests for server actions in
components/cart/actions.ts - Tests for API client functions in
lib/zonos - Tests for environment variable validation
tests/unit/: Contains unit tests for pure functions- Future component testing will be done with Storybook
- Future integration and E2E testing will be done with Playwright
# Run all tests once pnpm test # or pnpm dlx vitest run # Run tests in watch mode (during development) pnpm run test:watch # or pnpm dlx vitestWhen writing unit tests:
- Focus on testing pure functions that don't require DOM interactions
- Name test files with the
.test.tsor.test.tsxextension - Place tests in a directory structure that mirrors the source code
- Use the Vitest
describe,it, andexpectfunctions
Example test structure:
import { describe, it, expect } from 'vitest'; import { myFunction } from 'path/to/source'; describe('myFunction', () => { it('should do something specific', () => { // Arrange const input = 'test'; // Act const result = myFunction(input); // Assert expect(result).toBe('expected output'); }); });For more details on testing, see the tests/README.md file.
This project can be deployed on either Vercel or Cloudflare. The deployment process is optimized based on the platform you choose through the DEPLOYMENT_PLATFORM environment variable.
- Fork this repository to your GitHub account
- Create a new project in Vercel and connect it to your forked repository
- Configure the required environment variables
- Deploy the project
Vercel will automatically build and deploy your application. Each commit to the main branch will trigger a new production deployment, and pull requests will create preview deployments.
- Fork this repository to your GitHub account
- Create a new project in Cloudflare Pages and connect it to your forked repository
- Configure the build settings:
- Build command:
pnpm run build - Output directory:
.next
- Build command:
- Configure the required environment variables
- Deploy the project
For detailed deployment configurations and strategies, refer to the deployment specification.
This project is licensed under the MIT License - see the LICENSE file for details.