@commercengine/storefront-sdk-nextjs 0.1.0-alpha.1 → 1.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,15 @@
1
1
  # CommerceEngine Next.js SDK
2
2
 
3
- **Production-ready Next.js wrapper** for the CommerceEngine Storefront SDK. Handles the complexities of Next.js runtime environments, automatic token management, and cookie-based authentication across all contexts.
3
+ **Production-ready Next.js wrapper** for the CommerceEngine Storefront SDK. Provides the perfect developer experience with automatic context detection, universal API, and zero configuration complexity.
4
4
 
5
- **✨ What makes this special:**
6
- - **🎯 Universal API** - Single `storefront()` function works everywhere
5
+ **✨ Perfect DX Pattern:**
6
+ - **🎯 One Config File** - Single `lib/storefront.ts` using `createStorefront()`
7
+ - **🌍 Universal API** - Same `storefront()` import works everywhere
7
8
  - **🔥 Automatic Tokens** - Creates and manages tokens automatically
8
- - **🧠 Smart Environment Detection** - Detects Server vs Client contexts
9
+ - **🧠 Smart Context Detection** - Detects Server vs Client vs Build contexts
9
10
  - **🍪 Cookie-based State** - Shared authentication via Next.js cookies
10
11
  - **⚡ Request Isolation** - Proper per-request SDK instances on server
11
- - **🛠 Zero Configuration** - Works with environment variables out of the box
12
+ - **🛠 Zero Complexity** - Environment variables + one lib file = done
12
13
 
13
14
  ## Installation
14
15
 
@@ -20,35 +21,82 @@ pnpm add @commercengine/storefront-sdk-nextjs
20
21
 
21
22
  ## Quick Start
22
23
 
23
- ### 1. Environment Variables
24
+ ### 1. Environment Variables (Required)
24
25
 
25
26
  Add your store configuration to `.env.local`:
26
27
 
27
28
  ```bash
28
29
  NEXT_PUBLIC_STORE_ID=your-store-id
29
- NEXT_PUBLIC_ENVIRONMENT=staging # or "production"
30
30
  NEXT_PUBLIC_API_KEY=your-api-key
31
+ # Environment (defaults to "staging")
32
+ NEXT_PUBLIC_ENVIRONMENT=staging # or "production"
33
+ ```
34
+
35
+ ### 2. Create Your Storefront Configuration
36
+
37
+ Create `lib/storefront.ts` in your project:
38
+
39
+ ```typescript
40
+ // lib/storefront.ts
41
+ import {
42
+ createStorefront,
43
+ type StorefrontRuntimeConfig,
44
+ } from "@commercengine/storefront-sdk-nextjs";
45
+
46
+ // Optional advanced configuration (everything not in environment variables)
47
+ const storefrontConfig: StorefrontRuntimeConfig = {
48
+ debug: true,
49
+ timeout: 15000,
50
+ logger: (msg: string, ...args: any[]) =>
51
+ console.log("[STOREFRONT]", msg, ...args),
52
+ onTokensUpdated: (access: string, refresh: string) => {
53
+ console.log("🔥 TOKENS UPDATED:", {
54
+ access: access.slice(0, 20) + "...",
55
+ refresh: refresh.slice(0, 20) + "...",
56
+ });
57
+ },
58
+ onTokensCleared: () => {
59
+ console.log("🔄 TOKENS CLEARED");
60
+ },
61
+ };
62
+
63
+ // Create the configured storefront function (storefrontConfig is OPTIONAL)
64
+ export const storefront = createStorefront(storefrontConfig);
65
+
66
+ // Re-export types for convenience
67
+ export type { StorefrontRuntimeConfig };
68
+ ```
69
+
70
+ **All Core SDK Types Available:**
71
+ The Next.js SDK re-exports all types from the core SDK, so you can import them directly:
72
+
73
+ ```typescript
74
+ // Import any core SDK types you need
75
+ import type {
76
+ UserInfo,
77
+ SupportedDefaultHeaders,
78
+ StorefrontSDKOptions,
79
+ components,
80
+ operations
81
+ } from "@commercengine/storefront-sdk-nextjs";
82
+
83
+ // Use imported types
84
+ const headers: SupportedDefaultHeaders = {
85
+ customer_group_id: "01ABC123..."
86
+ };
31
87
  ```
32
88
 
33
- ### 2. Initialize in Root Layout
89
+ ### 3. Initialize in Root Layout
34
90
 
35
91
  ```typescript
36
92
  // app/layout.tsx
37
- import { Environment, StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
93
+ import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
38
94
 
39
95
  export default function RootLayout({ children }: { children: React.ReactNode }) {
40
96
  return (
41
97
  <html lang="en">
42
98
  <body>
43
- <StorefrontSDKInitializer
44
- config={{
45
- storeId: process.env.NEXT_PUBLIC_STORE_ID || "",
46
- environment: process.env.NEXT_PUBLIC_ENVIRONMENT === "production"
47
- ? Environment.Production
48
- : Environment.Staging,
49
- apiKey: process.env.NEXT_PUBLIC_API_KEY,
50
- }}
51
- />
99
+ <StorefrontSDKInitializer />
52
100
  {children}
53
101
  </body>
54
102
  </html>
@@ -56,57 +104,39 @@ export default function RootLayout({ children }: { children: React.ReactNode })
56
104
  }
57
105
  ```
58
106
 
59
- ### 3. Use Anywhere with the Universal API
107
+ ### 4. Use Anywhere with Universal Import
60
108
 
61
109
  ```typescript
62
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
63
- import { cookies } from "next/headers";
110
+ // Import your configured storefront everywhere
111
+ import { storefront } from "@/lib/storefront";
112
+ import { cookies } from "next/headers"; // Only for server contexts
64
113
 
65
- // Client Component - No cookies needed
114
+ // Client Component - No cookies needed
66
115
  const products = await storefront().catalog.listProducts();
67
116
 
68
- // Server Component, Server Action, or API Route
117
+ // Server Component, Server Action, or API Route - MUST pass cookies
69
118
  const products = await storefront(cookies()).catalog.listProducts();
70
- ```
71
-
72
- ## Usage in Different Next.js Contexts
73
-
74
- ### Server Components
75
119
 
76
- Server Components run on the server and can **read** cookies but cannot **write** them. Each request gets its own SDK instance with independent token management.
120
+ // Root Layout - Special exception with explicit flag
121
+ const products = await storefront({ isRootLayout: true }).catalog.listProducts();
77
122
 
78
- ```typescript
79
- // app/products/page.tsx
80
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
81
- import { cookies } from "next/headers";
82
-
83
- export default async function ProductsPage() {
84
- const sdk = storefront(cookies());
85
-
86
- // This will generate a new anonymous token for this request
87
- // Note: Token cannot be persisted (cookies are read-only in Server Components)
88
- const { data: products } = await sdk.catalog.listProducts();
89
-
90
- return (
91
- <div>
92
- {products?.products.map(product => (
93
- <div key={product.id}>{product.name}</div>
94
- ))}
95
- </div>
96
- );
97
- }
123
+ // ✅ SSG/ISR (build contexts) - Automatic fallback to memory storage
124
+ // (NEXT_BUILD_CACHE_TOKENS=true enables this)
125
+ const products = await storefront().catalog.listProducts();
98
126
  ```
99
127
 
128
+ ## Usage in Different Next.js Contexts
129
+
100
130
  ### Client Components
101
131
 
102
- Client Components run in the browser and can both read and write cookies, enabling persistent authentication.
132
+ Client Components run in the browser and can persist tokens via cookies:
103
133
 
104
134
  ```typescript
105
135
  // components/ProductList.tsx
106
136
  "use client";
107
137
 
108
138
  import { useState, useEffect } from "react";
109
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
139
+ import { storefront } from "@/lib/storefront";
110
140
 
111
141
  export default function ProductList() {
112
142
  const [products, setProducts] = useState([]);
@@ -115,7 +145,7 @@ export default function ProductList() {
115
145
  async function loadProducts() {
116
146
  const sdk = storefront(); // No cookies() needed on client-side
117
147
 
118
- // This will create and persist tokens via cookies
148
+ // Tokens are automatically managed by StorefrontSDKInitializer
119
149
  const { data } = await sdk.catalog.listProducts();
120
150
  if (data) setProducts(data.products);
121
151
  }
@@ -133,51 +163,62 @@ export default function ProductList() {
133
163
  }
134
164
  ```
135
165
 
166
+ ### Server Components
167
+
168
+ Server Components run on the server and can read cookies:
169
+
170
+ ```typescript
171
+ // app/products/page.tsx
172
+ import { storefront } from "@/lib/storefront";
173
+ import { cookies } from "next/headers";
174
+
175
+ export default async function ProductsPage() {
176
+ const sdk = storefront(cookies());
177
+
178
+ const { data: products } = await sdk.catalog.listProducts();
179
+
180
+ return (
181
+ <div>
182
+ {products?.products.map(product => (
183
+ <div key={product.id}>{product.name}</div>
184
+ ))}
185
+ </div>
186
+ );
187
+ }
188
+ ```
189
+
136
190
  ### Server Actions
137
191
 
138
- Server Actions run on the server and can both read and write cookies, making them perfect for authentication flows.
192
+ Server Actions can both read and write cookies, perfect for authentication:
139
193
 
140
194
  ```typescript
141
195
  // app/actions.ts
142
196
  "use server";
143
197
 
144
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
198
+ import { storefront } from "@/lib/storefront";
145
199
  import { cookies } from "next/headers";
146
200
 
147
201
  export async function loginWithEmail(email: string, password: string) {
148
202
  const sdk = storefront(cookies());
149
203
 
150
- // This will create and persist tokens via cookies
151
204
  const { data, error } = await sdk.auth.loginWithPassword({ email, password });
152
205
 
153
206
  if (data) {
154
- // Tokens are automatically saved to cookies by the SDK
207
+ // Tokens are automatically saved to cookies
155
208
  return { success: true, user: data.user };
156
209
  }
157
210
 
158
211
  return { success: false, error: error?.message };
159
212
  }
160
-
161
- export async function addToCart(productId: string, quantity: number) {
162
- const sdk = storefront(cookies());
163
-
164
- // Uses existing authentication from cookies
165
- const { data } = await sdk.cart.addItem({
166
- product_id: productId,
167
- quantity
168
- });
169
-
170
- return data;
171
- }
172
213
  ```
173
214
 
174
215
  ### API Routes
175
216
 
176
- API Routes work identically to Server Actions - they can read and write cookies.
217
+ API Routes work identically to Server Actions:
177
218
 
178
219
  ```typescript
179
220
  // app/api/products/route.ts
180
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
221
+ import { storefront } from "@/lib/storefront";
181
222
  import { cookies } from "next/headers";
182
223
  import { NextResponse } from "next/server";
183
224
 
@@ -198,167 +239,41 @@ export async function GET() {
198
239
  );
199
240
  }
200
241
  }
201
-
202
-
203
- ## Authentication Patterns
204
-
205
- ### Anonymous Users
206
-
207
- The SDK automatically creates anonymous tokens when needed:
208
-
209
- ```typescript
210
- // This works in any context - creates anonymous token automatically
211
- const { data: products } = await storefront(cookies()).catalog.listProducts();
212
242
  ```
213
243
 
214
- ### Email/Password Login
244
+ ### Root Layout (Special Case)
215
245
 
216
- ```typescript
217
- // Server Action
218
- "use server";
219
- export async function loginUser(email: string, password: string) {
220
- const sdk = storefront(cookies());
221
-
222
- const { data, error } = await sdk.auth.loginWithPassword({ email, password });
223
-
224
- if (data) {
225
- // Tokens automatically saved to cookies
226
- redirect('/dashboard');
227
- }
228
-
229
- return { error: error?.message };
230
- }
231
- ```
232
-
233
- ### Phone/OTP Login
246
+ Root Layout requires explicit flag since it's outside request context. Passing this flag will instruct the SDK to fallback to MemoryStore when rendering the root layout as the root layout runs on both server and client before cookie context is available.
234
247
 
235
248
  ```typescript
236
- // Server Action - Step 1: Send OTP
237
- export async function sendOTP(phone: string, country_code: string) {
238
- const sdk = storefront(cookies());
239
-
240
- return await sdk.auth.loginWithPhone({
241
- phone,
242
- country_code,
243
- register_if_not_exists: true
244
- });
245
- }
246
-
247
- // Server Action - Step 2: Verify OTP
248
- export async function verifyOTP(otp: string, otp_token: string, otp_action: string) {
249
- const sdk = storefront(cookies());
250
-
251
- const { data, error } = await sdk.auth.verifyOtp({
252
- otp,
253
- otp_token,
254
- otp_action
255
- });
256
-
257
- if (data) {
258
- // Tokens automatically saved to cookies
259
- return { success: true, user: data.user };
260
- }
261
-
262
- return { success: false, error: error?.message };
263
- }
264
- ```
265
-
266
- ## Token Management & Cookie Behavior
267
-
268
- ### How It Works
269
-
270
- 1. **Server Components**: Generate tokens but can't persist them (read-only cookies)
271
- 2. **Client Components**: Generate and persist tokens via `document.cookie`
272
- 3. **Server Actions/API Routes**: Generate and persist tokens via Next.js `cookies()`
273
- 4. **Shared State**: All contexts read from the same cookie storage
274
-
275
- ### Cookie Configuration
276
-
277
- The SDK uses secure cookies with sensible defaults:
278
-
279
- ```typescript
280
- // Advanced cookie configuration (optional)
281
- <StorefrontSDKInitializer
282
- config={{
283
- storeId: "your-store-id",
284
- apiKey: "your-api-key",
285
- tokenStorageOptions: {
286
- prefix: "ce_", // Cookie name prefix
287
- maxAge: 30 * 24 * 60 * 60, // 30 days
288
- path: "/",
289
- secure: true, // HTTPS only (auto-detected)
290
- sameSite: "Lax",
291
- }
292
- }}
293
- />
294
- ```
295
-
296
- ## API Reference
297
-
298
- ### `storefront()`
299
-
300
- **Universal function** that works in all Next.js contexts:
301
-
302
- ```typescript
303
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
304
- import { cookies } from "next/headers";
305
-
306
- // ✅ Client-side (browser)
307
- const sdk = storefront();
308
-
309
- // ✅ Server-side (requires cookies for token persistence)
310
- const sdk = storefront(cookies());
311
-
312
- // ❌ Server-side without cookies (helpful error message)
313
- const sdk = storefront(); // Throws clear error with instructions
314
- ```
315
-
316
- ### `StorefrontSDKInitializer`
317
-
318
- **Client-side initializer** component (must be imported from `/client`):
319
-
320
- ```typescript
321
- import { Environment, StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
322
-
323
- <StorefrontSDKInitializer
324
- config={{
325
- storeId: "your-store-id",
326
- environment: Environment.Production, // or Environment.Staging
327
- apiKey: "your-api-key",
328
-
329
- // Optional: Advanced configuration
330
- tokenStorageOptions: {
331
- prefix: "ce_", // Cookie prefix (default)
332
- maxAge: 30 * 24 * 60 * 60, // 30 days
333
- secure: true, // Auto-detected from environment
334
- sameSite: "Lax",
335
- },
336
- }}
337
- />
338
- ```
339
-
340
- ## Error Handling
341
-
342
- All SDK methods return a consistent error structure:
249
+ // app/layout.tsx
250
+ import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
251
+ import { storefront } from "@/lib/storefront";
343
252
 
344
- ```typescript
345
- const { data, error, response } = await storefront(cookies()).catalog.listProducts();
253
+ // Root Layout requires explicit flag - no request context available
254
+ const sdk = storefront({ isRootLayout: true });
255
+ const { data: storeConfig } = await sdk.store.getStoreConfig();
346
256
 
347
- if (error) {
348
- console.error("API Error:", error.message, error.code);
349
- console.log("Status:", response.status);
350
- } else {
351
- console.log("Products:", data.products);
257
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
258
+ return (
259
+ <html lang="en">
260
+ <body>
261
+ <StorefrontSDKInitializer />
262
+ <h1>Welcome to {storeConfig?.store_config?.brand.name}</h1>
263
+ {children}
264
+ </body>
265
+ </html>
266
+ );
352
267
  }
353
268
  ```
354
269
 
355
270
  ## Static Site Generation (SSG) & Build-Time Optimization
356
271
 
357
- The SDK provides powerful build-time optimizations for SSG/ISR that dramatically reduce API calls during the build process through intelligent token caching.
272
+ The SDK provides powerful build-time optimizations through intelligent token caching.
358
273
 
359
- ### Automatic Build-Time Token Caching
274
+ ### Configure Next.js for Build-Time Optimization
360
275
 
361
- Enable automatic token caching during production builds:
276
+ Create or update your `next.config.ts` (or `next.config.js`) to enable automatic token caching during builds:
362
277
 
363
278
  ```typescript
364
279
  // next.config.ts
@@ -370,9 +285,14 @@ const nextConfig = (phase: string): NextConfig => {
370
285
 
371
286
  return {
372
287
  env: {
373
- // Enable build-time token caching during production builds
288
+ // Enable build-time token caching during production builds and when explicitly set
374
289
  NEXT_BUILD_CACHE_TOKENS: process.env.NEXT_BUILD_CACHE_TOKENS ?? (isBuild ? 'true' : 'false'),
290
+ // Critical: tells SDK to use MemoryStore during SSG/Build/ISR to avoid cookie context failures
291
+ NEXT_IS_BUILD: isBuild ? 'true' : 'false',
375
292
  },
293
+
294
+ // Ensure static generation is enabled
295
+ output: undefined, // Let Next.js decide based on usage
376
296
  };
377
297
  };
378
298
 
@@ -381,11 +301,9 @@ export default nextConfig;
381
301
 
382
302
  ### SSG with generateStaticParams
383
303
 
384
- Create static product pages during build:
385
-
386
304
  ```typescript
387
305
  // app/products/[slug]/page.tsx
388
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
306
+ import { storefront } from "@/lib/storefront";
389
307
  import { notFound } from "next/navigation";
390
308
 
391
309
  interface ProductPageProps {
@@ -396,7 +314,6 @@ export default async function ProductPage({ params }: ProductPageProps) {
396
314
  const { slug } = await params;
397
315
  const sdk = storefront(); // No cookies() - uses build-time storage
398
316
 
399
- // Get product detail by slug or ID
400
317
  const { data, error } = await sdk.catalog.getProductDetail({
401
318
  product_id_or_slug: slug
402
319
  });
@@ -405,28 +322,24 @@ export default async function ProductPage({ params }: ProductPageProps) {
405
322
  notFound();
406
323
  }
407
324
 
408
- const { product } = data;
409
-
410
325
  return (
411
326
  <div>
412
- <h1>{product.name}</h1>
413
- <p>SKU: {product.sku}</p>
414
- <p>Type: {product.product_type}</p>
415
- <p>Description: {product.short_description}</p>
327
+ <h1>{data.product.name}</h1>
328
+ <p>SKU: {data.product.sku}</p>
329
+ <p>Description: {data.product.short_description}</p>
416
330
  </div>
417
331
  );
418
332
  }
419
333
 
420
334
  // Generate static params from real API data
421
335
  export async function generateStaticParams() {
422
- const sdk = storefront(); // No cookies() - uses build-time storage
336
+ const sdk = storefront(); // Token will be cached and reused
423
337
 
424
338
  const { data: productsData, error } = await sdk.catalog.listProducts({
425
- limit: 100 // Generate pages for first 100 products
339
+ limit: 100
426
340
  });
427
341
 
428
342
  if (error || !productsData) {
429
- console.error("Error fetching products for static generation:", error);
430
343
  return [];
431
344
  }
432
345
 
@@ -436,181 +349,243 @@ export async function generateStaticParams() {
436
349
  }
437
350
  ```
438
351
 
439
- ### SSG Test Page Example
352
+ ### Build Performance Benefits
353
+
354
+ With token caching enabled:
355
+ - ✅ Token created once and reused across all pages
356
+ - ✅ 100 pages = ~1 anonymous token API call total
357
+ - ✅ Faster builds, dramatically lower API usage
358
+
359
+ ## Authentication Patterns
360
+
361
+ > **⚠️ Important:** Any authentication endpoint that returns tokens (like `loginWithPassword`, `verifyOtp`, `register`, etc.) **must** be called in contexts where cookies can be set and managed:
362
+ > - ✅ **Server Actions** (recommended for authentication flows)
363
+ > - ✅ **API Routes** (`/api` directory)
364
+ > - ✅ **Client Components** (browser environment)
365
+ > - ❌ **Server Components** (cannot set cookies, tokens won't persist)
366
+ >
367
+ > This ensures the SDK can automatically handle token storage and user session continuity.
440
368
 
441
- Create a page that makes multiple API calls during build to test token reuse:
369
+ ### Anonymous Users
370
+
371
+ The SDK automatically creates anonymous tokens via the `StorefrontSDKInitializer` component imported in your root layout. If this component is not imported (not recommended), a new token will be minted for each request as a fallback. **It is highly recommended** to use the `StorefrontSDKInitializer` and ensure all token-returning endpoints are called from request contexts that can set cookies. [Authentication Patterns](#authentication-patterns).
442
372
 
443
373
  ```typescript
444
- // app/ssg-test/page.tsx
445
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
374
+ // This works everywhere - creates anonymous token automatically
375
+ const { data: products } = await storefront(cookies()).catalog.listProducts();
376
+ ```
446
377
 
447
- export default async function SSGTestPage() {
448
- const sdk = storefront(); // No cookies() - uses build-time storage
378
+ ### Email/Password Login
379
+
380
+ ```typescript
381
+ // Server Action (✅ Recommended - can set cookies for token persistence)
382
+ "use server";
383
+ export async function loginUser(email: string, password: string) {
384
+ const sdk = storefront(cookies());
385
+
386
+ const { data, error } = await sdk.auth.loginWithPassword({ email, password });
387
+
388
+ if (data) {
389
+ // Tokens automatically saved to cookies
390
+ redirect('/dashboard');
391
+ }
449
392
 
450
- // Make multiple API calls - token will be created once and reused
451
- const { data: products, error: productsError } = await sdk.catalog.listProducts({
452
- limit: 10
393
+ return { error: error?.message };
394
+ }
395
+ ```
396
+
397
+ ### Phone/OTP Login
398
+
399
+ ```typescript
400
+ // Server Action - Step 1: Send OTP (✅ Recommended context)
401
+ export async function sendOTP(phone: string, country_code: string) {
402
+ const sdk = storefront(await cookies());
403
+
404
+ return await sdk.auth.loginWithPhone({
405
+ phone,
406
+ country_code,
407
+ register_if_not_exists: true
453
408
  });
409
+ }
410
+
411
+ // Server Action - Step 2: Verify OTP (✅ Recommended - can set cookies for token persistence)
412
+ export async function verifyOTP(otp: string, otp_token: string, otp_action: string) {
413
+ const sdk = storefront(await cookies());
454
414
 
455
- const { data: categories, error: categoriesError } = await sdk.catalog.listCategories({
456
- nested_level: 1
415
+ const { data, error } = await sdk.auth.verifyOtp({
416
+ otp,
417
+ otp_token,
418
+ otp_action
457
419
  });
458
420
 
459
- const { data: anonymousToken, error: tokenError } = await sdk.auth.getAnonymousToken();
421
+ if (data) {
422
+ // Tokens automatically saved to cookies
423
+ return { success: true, user: data.user };
424
+ }
460
425
 
461
- const buildTime = new Date().toISOString();
426
+ return { success: false, error: error?.message };
427
+ }
428
+ ```
429
+
430
+ ## API Reference
431
+
432
+ ### `createStorefront(config?)`
433
+
434
+ Creates a configured storefront function that works universally across all Next.js contexts.
435
+
436
+ ```typescript
437
+ import { createStorefront } from "@commercengine/storefront-sdk-nextjs";
438
+
439
+ export const storefront = createStorefront({
440
+ debug: true,
441
+ logger: (msg, ...args) => console.log('[DEBUG]', msg, ...args)
442
+ });
443
+ ```
444
+
445
+ **Parameters:**
446
+ - `config` (optional): `StorefrontRuntimeConfig` - Advanced configuration options
447
+
448
+ **Returns:**
449
+ - Universal `storefront()` function that works in all Next.js contexts
450
+
451
+ ### `StorefrontRuntimeConfig`
452
+
453
+ Optional configuration object for `createStorefront()`:
454
+
455
+ ```typescript
456
+ interface StorefrontRuntimeConfig {
457
+ // Override environment variables
458
+ storeId?: string;
459
+ apiKey?: string;
460
+ environment?: Environment;
461
+ baseUrl?: string;
462
+ timeout?: number;
463
+ debug?: boolean;
462
464
 
463
- return (
464
- <div>
465
- <h1>SSG Test Page</h1>
466
- <p><strong>Built at:</strong> {buildTime}</p>
467
-
468
- <div>
469
- <h2>Build-time API Results:</h2>
470
-
471
- <div>
472
- <h3>Products Call:</h3>
473
- {productsError ? (
474
- <p style={{ color: 'red' }}>Error: {productsError.message}</p>
475
- ) : (
476
- <p>✅ Success: Found {products?.products?.length || 0} products</p>
477
- )}
478
- </div>
479
-
480
- <div>
481
- <h3>Categories Call:</h3>
482
- {categoriesError ? (
483
- <p style={{ color: 'red' }}>Error: {categoriesError.message}</p>
484
- ) : (
485
- <p>✅ Success: Found {categories?.categories?.length || 0} categories</p>
486
- )}
487
- </div>
488
-
489
- <div>
490
- <h3>Anonymous Token Call:</h3>
491
- {tokenError ? (
492
- <p style={{ color: 'red' }}>Error: {tokenError.message}</p>
493
- ) : (
494
- <p>✅ Success: User ID {anonymousToken?.user?.id}</p>
495
- )}
496
- </div>
497
- </div>
498
- </div>
499
- );
465
+ // Advanced options (not available via environment variables)
466
+ accessToken?: string;
467
+ refreshToken?: string;
468
+ defaultHeaders?: SupportedDefaultHeaders;
469
+ logger?: (message: string, ...args: any[]) => void;
470
+ onTokensUpdated?: (accessToken: string, refreshToken: string) => void;
471
+ onTokensCleared?: () => void;
472
+ tokenStorageOptions?: NextJSTokenStorageOptions;
500
473
  }
501
474
  ```
502
475
 
503
- ### Build Performance Benefits
476
+ ### Universal `storefront()` Function
504
477
 
505
- With token caching enabled, you'll see dramatic performance improvements:
478
+ The function returned by `createStorefront()` works in all contexts with strict enforcement:
506
479
 
507
- **Without Caching:**
508
- - 🔴 Each page creates its own token
509
- - 🔴 100 pages = 100+ anonymous token API calls
510
- - 🔴 Slower builds, higher API usage
480
+ ```typescript
481
+ // Client-side (browser)
482
+ const sdk = storefront();
511
483
 
512
- **With Caching:**
513
- - Token created once and reused across all pages
514
- - ✅ 100 pages = ~3 anonymous token API calls total
515
- - Faster builds, dramatically lower API usage
484
+ // Server-side (requires cookies for user continuity)
485
+ const sdk = storefront(cookies());
486
+
487
+ // Root Layout (special exception with explicit flag)
488
+ const sdk = storefront({ isRootLayout: true });
516
489
 
517
- ### Build Logs to Monitor
490
+ // Server-side without cookies - throws helpful error to protect user sessions
491
+ const sdk = storefront(); // ❌ Throws error in server contexts
492
+ ```
518
493
 
519
- When build caching is working, you'll see these logs:
494
+ ### Function Signatures
520
495
 
496
+ ```typescript
497
+ function storefront(): StorefrontSDK;
498
+ function storefront(cookieStore: NextCookieStore): StorefrontSDK;
499
+ function storefront(options: { isRootLayout: true }): StorefrontSDK;
500
+ function storefront(cookieStore: NextCookieStore, options: { isRootLayout?: boolean }): StorefrontSDK;
521
501
  ```
522
- 🚀 [BuildCache] Using BuildCachingMemoryTokenStorage with key: store:staging
523
- 🟡 [BuildCache] No cached token found for key: store:staging
524
- 🟠 [BuildCache] Caching new access token for key: store:staging
525
- 🔵 [BuildCache] Using instance token for key: store:staging
526
- 🟢 [BuildCache] Using cached token for key: store:staging
502
+
503
+ ### `StorefrontSDKInitializer`
504
+
505
+ Client-side initializer component (must be imported from `/client`):
506
+
507
+ ```typescript
508
+ import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
509
+
510
+ <StorefrontSDKInitializer />
527
511
  ```
528
512
 
529
- **Key Indicators:**
530
- - ✅ Only 1-3 "Automatically created anonymous session" messages
531
- - ✅ Many "Using instance token" or "Using cached token" messages
532
- - ✅ Minimal "Caching new access token" messages
513
+ No props needed - configuration comes from environment variables and your `lib/storefront.ts` file.
533
514
 
534
- ### Manual Override
515
+ ## Error Handling
535
516
 
536
- You can manually control build caching:
517
+ All SDK methods return a consistent error structure:
537
518
 
538
- ```bash
539
- # Enable caching for this build
540
- NEXT_BUILD_CACHE_TOKENS=true pnpm build
519
+ ```typescript
520
+ const { data, error, response } = await storefront(cookies()).catalog.listProducts();
541
521
 
542
- # Disable caching for this build
543
- NEXT_BUILD_CACHE_TOKENS=false pnpm build
522
+ if (error) {
523
+ console.error("API Error:", error.message, error.code);
524
+ console.log("Status:", response.status);
525
+ } else {
526
+ console.log("Products:", data.products);
527
+ }
544
528
  ```
545
529
 
546
530
  ## Best Practices
547
531
 
548
532
  ### ✅ Do's
549
533
 
534
+ - **Set required environment variables**: `NEXT_PUBLIC_STORE_ID` and `NEXT_PUBLIC_API_KEY` are mandatory
535
+ - **Create one lib/storefront.ts file**: Use `createStorefront()` to configure advanced options
550
536
  - **Initialize once**: Call `StorefrontSDKInitializer` only in your root layout
551
537
  - **Use `storefront(cookies())`**: Always pass cookies in server contexts
552
538
  - **Handle errors**: Always check the error property in responses
553
539
  - **Use Server Actions**: For authentication flows that need to persist tokens
554
- - **Environment variables**: Store sensitive config in environment variables
555
540
 
556
541
  ### ❌ Don'ts
557
542
 
558
543
  - **Don't call `cookies()` in Client Components**: It will throw an error
559
544
  - **Don't initialize multiple times**: The SDK handles singleton behavior
560
545
  - **Don't forget error handling**: API calls can fail for various reasons
561
- - **Don't rely on Server Component token persistence**: They can't write cookies
546
+ - **Don't skip environment variables**: Missing required variables will cause errors
562
547
 
563
548
  ## Troubleshooting
564
549
 
565
550
  ### Common Issues
566
551
 
567
- 1. **"Cookie store passed in client environment"**
552
+ 1. **"Server context requires cookies for user continuity!"**
568
553
  ```typescript
569
- // ❌ Wrong
570
- storefront(cookies()) // in client component
554
+ // ❌ Wrong - server context without cookies (breaks user sessions)
555
+ storefront()
571
556
 
572
- // ✅ Correct
573
- storefront() // in client component
557
+ // ✅ Correct - server context with cookies
558
+ storefront(cookies())
559
+
560
+ // ✅ Root Layout exception
561
+ storefront({ isRootLayout: true })
574
562
  ```
575
563
 
576
- 2. **"SDK not initialized"**
577
- ```typescript
578
- // Make sure StorefrontSDKInitializer is in your root layout
579
- <StorefrontSDKInitializer config={{ ... }} />
564
+ 2. **Missing Environment Variables**
565
+ ```bash
566
+ # Ensure your .env.local has the required variables:
567
+ NEXT_PUBLIC_STORE_ID=your-store-id
568
+ NEXT_PUBLIC_API_KEY=your-api-key
580
569
  ```
581
570
 
582
- 3. **"Cookies can only be modified in Server Action"**
583
- This is expected behavior. Server Components can't persist tokens, but they can still make API calls with per-request tokens.
584
-
585
- 4. **Server Environment Detection Error**
586
- ```
587
- 🚨 Server Environment Detected!
571
+ 3. **"Cookie store passed in client environment"**
572
+ ```typescript
573
+ // ❌ Wrong - client component with cookies
574
+ storefront(cookies())
588
575
 
589
- You're calling storefront() on the server without cookies.
590
- Please pass the Next.js cookie store:
576
+ // Correct - client component without cookies
577
+ storefront()
578
+ ```
579
+
580
+ 4. **Server Actions and async cookies()**
581
+ ```typescript
582
+ // ✅ Correct - Server Actions need await cookies()
583
+ const sdk = storefront(await cookies());
591
584
 
592
- Correct usage:
593
- import { cookies } from 'next/headers';
585
+ // Server Components and API Routes use cookies() directly
594
586
  const sdk = storefront(cookies());
595
-
596
- ❌ Your current usage:
597
- const sdk = storefront(); // Missing cookies!
598
587
  ```
599
588
 
600
- ### Debug Mode
601
-
602
- Enable detailed logging during development:
603
-
604
- ```typescript
605
- <StorefrontSDKInitializer
606
- config={{
607
- storeId: "your-store-id",
608
- apiKey: "your-api-key",
609
- debug: true, // Enable debug logging
610
- }}
611
- />
612
- ```
613
-
614
589
  ## Migration Guide
615
590
 
616
591
  ### From Core SDK
@@ -622,109 +597,27 @@ const sdk = new StorefrontSDK({
622
597
  storeId: "...",
623
598
  tokenStorage: new BrowserTokenStorage()
624
599
  });
625
- await sdk.auth.getAnonymousToken(); // Manual token creation
626
600
 
627
601
  // After (Next.js SDK)
628
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
629
- const sdk = storefront(cookies()); // Automatic token management
630
- ```
631
-
632
- ### From Previous Next.js SDK Version
633
-
634
- ```typescript
635
- // Before (old pattern)
636
- import { getStorefrontSDK } from "@commercengine/storefront-sdk-nextjs";
637
- const sdk = getStorefrontSDK(cookies());
638
-
639
- // After (new universal pattern)
640
- import { storefront } from "@commercengine/storefront-sdk-nextjs";
602
+ import { storefront } from "@/lib/storefront";
641
603
  const sdk = storefront(cookies());
642
604
  ```
643
605
 
644
- ## TypeScript Support
645
-
646
- The SDK provides complete TypeScript support with auto-generated types:
647
-
648
- ```typescript
649
- import type {
650
- StorefrontSDK,
651
- ApiResult,
652
- UserInfo,
653
- NextJSSDKConfig,
654
- Environment
655
- } from "@commercengine/storefront-sdk-nextjs";
656
-
657
- // All API responses are properly typed
658
- const { data }: ApiResult<ProductListResponse> = await storefront(cookies()).catalog.listProducts();
659
-
660
- // IntelliSense works for all nested properties
661
- console.log(data?.products[0].name);
662
- ```
663
-
664
- ## User Information
665
-
666
- Get current user information from tokens:
667
-
668
- ```typescript
669
- const sdk = storefront(cookies());
670
-
671
- const userInfo = await sdk.getUserInfo();
672
- const isLoggedIn = await sdk.isLoggedIn();
673
- const isAnonymous = await sdk.isAnonymous();
674
- const userId = await sdk.getUserId();
675
- const customerId = await sdk.getCustomerId();
676
- ```
677
-
678
- ## Advanced Usage
679
-
680
- ### Custom Token Storage
681
-
682
- ```typescript
683
- import { TokenStorage } from "@commercengine/storefront-sdk-nextjs";
684
-
685
- class RedisTokenStorage implements TokenStorage {
686
- async getAccessToken(): Promise<string | null> {
687
- // Your Redis implementation
688
- }
689
-
690
- async setAccessToken(token: string): Promise<void> {
691
- // Your Redis implementation
692
- }
693
-
694
- // ... implement other methods
695
- }
696
-
697
- // Use with the core SDK directly if needed
698
- import { StorefrontSDK } from "@commercengine/storefront-sdk-nextjs";
699
-
700
- const sdk = new StorefrontSDK({
701
- storeId: "your-store-id",
702
- apiKey: "your-api-key",
703
- tokenStorage: new RedisTokenStorage(),
704
- });
705
- ```
706
-
707
- ## Why This Wrapper Exists
708
-
709
- **The core SDK is powerful but complex for Next.js:**
710
- - Manual token storage setup and configuration
711
- - Server/client runtime environment handling
712
- - Cookie configuration for SSR/SSG
713
- - Request isolation and per-request instances
714
- - Next.js-specific execution model complexities
606
+ ## Why This Pattern?
715
607
 
716
- **This wrapper handles it all automatically:**
717
- - Universal `storefront()` API that works everywhere
718
- - Request-scoped server instances with React cache
719
- - Cookie-based token persistence across boundaries
720
- - Environment detection and configuration
721
- - Build-time optimizations for SSG/ISR
608
+ **The Perfect DX Pattern provides:**
609
+ - **One Config File**: All advanced configuration in `lib/storefront.ts`
610
+ - **Environment Variables**: Basic config (storeId, apiKey) via env vars
611
+ - **Universal Import**: Same `storefront()` import everywhere
612
+ - **Strict User Continuity**: Enforces cookie passing to protect user sessions and analytics
613
+ - **Explicit Exceptions**: Clear patterns for special cases like Root Layout
614
+ - **Zero Guesswork**: Helpful errors guide developers to correct patterns
722
615
 
723
- **Result: Production-ready e-commerce with zero complexity!** 🚀
616
+ **Result: Production-ready e-commerce with bulletproof user session management!** 🛡️
724
617
 
725
618
  ## API Reference
726
619
 
727
- For complete API documentation of all available endpoints, visit [docs.commercengine.io/api-reference](https://docs.commercengine.io/api-reference)
620
+ For complete API documentation of all available endpoints, visit [SDK DOCS REFERENCE](https://sdk-docs.commercengine.io/sdk/)
728
621
 
729
622
  The Next.js SDK provides access to all the same endpoints as the core SDK:
730
623