@commercengine/storefront-sdk-nextjs 0.1.0-alpha.0 → 0.1.0-alpha.1
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 +610 -108
- package/dist/client.cjs +430 -0
- package/dist/client.d.cts +138 -0
- package/dist/client.d.ts +138 -0
- package/dist/client.js +398 -0
- package/dist/index.cjs +163 -89
- package/dist/index.d.cts +9 -18
- package/dist/index.d.ts +9 -18
- package/dist/index.js +162 -87
- package/dist/middleware.cjs +66 -0
- package/dist/middleware.d.cts +38 -0
- package/dist/middleware.d.ts +38 -0
- package/dist/middleware.js +39 -0
- package/dist/server-D-pFrx8J.d.cts +105 -0
- package/dist/server-DaDfTjsO.d.cts +103 -0
- package/dist/server-DaDfTjsO.d.ts +103 -0
- package/dist/server-DjlQVC11.d.ts +105 -0
- package/dist/server.cjs +416 -0
- package/dist/server.d.cts +4 -0
- package/dist/server.d.ts +4 -0
- package/dist/server.js +385 -0
- package/dist/storefront.cjs +402 -0
- package/dist/storefront.d.cts +40 -0
- package/dist/storefront.d.ts +40 -0
- package/dist/storefront.js +376 -0
- package/package.json +18 -8
package/README.md
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CommerceEngine Next.js SDK
|
|
2
2
|
|
|
3
|
-
**
|
|
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.
|
|
4
4
|
|
|
5
5
|
**✨ What makes this special:**
|
|
6
|
-
-
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
6
|
+
- **🎯 Universal API** - Single `storefront()` function works everywhere
|
|
7
|
+
- **🔥 Automatic Tokens** - Creates and manages tokens automatically
|
|
8
|
+
- **🧠 Smart Environment Detection** - Detects Server vs Client contexts
|
|
9
|
+
- **🍪 Cookie-based State** - Shared authentication via Next.js cookies
|
|
10
|
+
- **⚡ Request Isolation** - Proper per-request SDK instances on server
|
|
11
|
+
- **🛠 Zero Configuration** - Works with environment variables out of the box
|
|
10
12
|
|
|
11
13
|
## Installation
|
|
12
14
|
|
|
@@ -18,20 +20,32 @@ pnpm add @commercengine/storefront-sdk-nextjs
|
|
|
18
20
|
|
|
19
21
|
## Quick Start
|
|
20
22
|
|
|
21
|
-
### 1.
|
|
23
|
+
### 1. Environment Variables
|
|
24
|
+
|
|
25
|
+
Add your store configuration to `.env.local`:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
NEXT_PUBLIC_STORE_ID=your-store-id
|
|
29
|
+
NEXT_PUBLIC_ENVIRONMENT=staging # or "production"
|
|
30
|
+
NEXT_PUBLIC_API_KEY=your-api-key
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Initialize in Root Layout
|
|
22
34
|
|
|
23
35
|
```typescript
|
|
24
36
|
// app/layout.tsx
|
|
25
|
-
import {
|
|
37
|
+
import { Environment, StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
|
|
26
38
|
|
|
27
39
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
28
40
|
return (
|
|
29
|
-
<html>
|
|
41
|
+
<html lang="en">
|
|
30
42
|
<body>
|
|
31
|
-
<StorefrontSDKInitializer
|
|
43
|
+
<StorefrontSDKInitializer
|
|
32
44
|
config={{
|
|
33
|
-
storeId: process.env.NEXT_PUBLIC_STORE_ID
|
|
34
|
-
environment:
|
|
45
|
+
storeId: process.env.NEXT_PUBLIC_STORE_ID || "",
|
|
46
|
+
environment: process.env.NEXT_PUBLIC_ENVIRONMENT === "production"
|
|
47
|
+
? Environment.Production
|
|
48
|
+
: Environment.Staging,
|
|
35
49
|
apiKey: process.env.NEXT_PUBLIC_API_KEY,
|
|
36
50
|
}}
|
|
37
51
|
/>
|
|
@@ -42,87 +56,270 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
42
56
|
}
|
|
43
57
|
```
|
|
44
58
|
|
|
45
|
-
###
|
|
59
|
+
### 3. Use Anywhere with the Universal API
|
|
46
60
|
|
|
47
61
|
```typescript
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
import { getStorefrontSDK } from '@commercengine/storefront-sdk-nextjs';
|
|
62
|
+
import { storefront } from "@commercengine/storefront-sdk-nextjs";
|
|
63
|
+
import { cookies } from "next/headers";
|
|
51
64
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
65
|
+
// Client Component - No cookies needed
|
|
66
|
+
const products = await storefront().catalog.listProducts();
|
|
67
|
+
|
|
68
|
+
// Server Component, Server Action, or API Route
|
|
69
|
+
const products = await storefront(cookies()).catalog.listProducts();
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Usage in Different Next.js Contexts
|
|
73
|
+
|
|
74
|
+
### Server Components
|
|
75
|
+
|
|
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.
|
|
62
77
|
|
|
63
|
-
|
|
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
|
+
);
|
|
64
97
|
}
|
|
65
98
|
```
|
|
66
99
|
|
|
100
|
+
### Client Components
|
|
101
|
+
|
|
102
|
+
Client Components run in the browser and can both read and write cookies, enabling persistent authentication.
|
|
103
|
+
|
|
67
104
|
```typescript
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
import {
|
|
105
|
+
// components/ProductList.tsx
|
|
106
|
+
"use client";
|
|
107
|
+
|
|
108
|
+
import { useState, useEffect } from "react";
|
|
109
|
+
import { storefront } from "@commercengine/storefront-sdk-nextjs";
|
|
72
110
|
|
|
73
|
-
export
|
|
74
|
-
const
|
|
111
|
+
export default function ProductList() {
|
|
112
|
+
const [products, setProducts] = useState([]);
|
|
113
|
+
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
async function loadProducts() {
|
|
116
|
+
const sdk = storefront(); // No cookies() needed on client-side
|
|
117
|
+
|
|
118
|
+
// This will create and persist tokens via cookies
|
|
119
|
+
const { data } = await sdk.catalog.listProducts();
|
|
120
|
+
if (data) setProducts(data.products);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
loadProducts();
|
|
124
|
+
}, []);
|
|
75
125
|
|
|
76
|
-
|
|
77
|
-
|
|
126
|
+
return (
|
|
127
|
+
<div>
|
|
128
|
+
{products.map(product => (
|
|
129
|
+
<div key={product.id}>{product.name}</div>
|
|
130
|
+
))}
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Server Actions
|
|
137
|
+
|
|
138
|
+
Server Actions run on the server and can both read and write cookies, making them perfect for authentication flows.
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// app/actions.ts
|
|
142
|
+
"use server";
|
|
143
|
+
|
|
144
|
+
import { storefront } from "@commercengine/storefront-sdk-nextjs";
|
|
145
|
+
import { cookies } from "next/headers";
|
|
146
|
+
|
|
147
|
+
export async function loginWithEmail(email: string, password: string) {
|
|
148
|
+
const sdk = storefront(cookies());
|
|
149
|
+
|
|
150
|
+
// This will create and persist tokens via cookies
|
|
151
|
+
const { data, error } = await sdk.auth.loginWithPassword({ email, password });
|
|
152
|
+
|
|
153
|
+
if (data) {
|
|
154
|
+
// Tokens are automatically saved to cookies by the SDK
|
|
155
|
+
return { success: true, user: data.user };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { success: false, error: error?.message };
|
|
159
|
+
}
|
|
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({
|
|
78
166
|
product_id: productId,
|
|
79
|
-
quantity
|
|
167
|
+
quantity
|
|
80
168
|
});
|
|
81
169
|
|
|
82
|
-
return
|
|
170
|
+
return data;
|
|
83
171
|
}
|
|
84
172
|
```
|
|
85
173
|
|
|
174
|
+
### API Routes
|
|
175
|
+
|
|
176
|
+
API Routes work identically to Server Actions - they can read and write cookies.
|
|
177
|
+
|
|
86
178
|
```typescript
|
|
87
|
-
//
|
|
88
|
-
import {
|
|
89
|
-
import {
|
|
179
|
+
// app/api/products/route.ts
|
|
180
|
+
import { storefront } from "@commercengine/storefront-sdk-nextjs";
|
|
181
|
+
import { cookies } from "next/headers";
|
|
182
|
+
import { NextResponse } from "next/server";
|
|
183
|
+
|
|
184
|
+
export async function GET() {
|
|
185
|
+
try {
|
|
186
|
+
const sdk = storefront(cookies());
|
|
187
|
+
const { data, error } = await sdk.catalog.listProducts();
|
|
188
|
+
|
|
189
|
+
if (error) {
|
|
190
|
+
return NextResponse.json({ error: error.message }, { status: 400 });
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return NextResponse.json(data);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
return NextResponse.json(
|
|
196
|
+
{ error: "Internal server error" },
|
|
197
|
+
{ status: 500 }
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
90
202
|
|
|
91
|
-
|
|
92
|
-
|
|
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
|
+
```
|
|
213
|
+
|
|
214
|
+
### Email/Password Login
|
|
215
|
+
|
|
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
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
// Server Action - Step 1: Send OTP
|
|
237
|
+
export async function sendOTP(phone: string, country_code: string) {
|
|
238
|
+
const sdk = storefront(cookies());
|
|
93
239
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
240
|
+
return await sdk.auth.loginWithPhone({
|
|
241
|
+
phone,
|
|
242
|
+
country_code,
|
|
243
|
+
register_if_not_exists: true
|
|
97
244
|
});
|
|
245
|
+
}
|
|
98
246
|
|
|
99
|
-
|
|
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 };
|
|
100
263
|
}
|
|
101
264
|
```
|
|
102
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
|
+
```
|
|
103
295
|
|
|
104
296
|
## API Reference
|
|
105
297
|
|
|
106
|
-
### `
|
|
298
|
+
### `storefront()`
|
|
107
299
|
|
|
108
|
-
**
|
|
300
|
+
**Universal function** that works in all Next.js contexts:
|
|
109
301
|
|
|
110
302
|
```typescript
|
|
303
|
+
import { storefront } from "@commercengine/storefront-sdk-nextjs";
|
|
304
|
+
import { cookies } from "next/headers";
|
|
305
|
+
|
|
111
306
|
// ✅ Client-side (browser)
|
|
112
|
-
const sdk =
|
|
307
|
+
const sdk = storefront();
|
|
113
308
|
|
|
114
309
|
// ✅ Server-side (requires cookies for token persistence)
|
|
115
|
-
const sdk =
|
|
310
|
+
const sdk = storefront(cookies());
|
|
116
311
|
|
|
117
312
|
// ❌ Server-side without cookies (helpful error message)
|
|
118
|
-
const sdk =
|
|
313
|
+
const sdk = storefront(); // Throws clear error with instructions
|
|
119
314
|
```
|
|
120
315
|
|
|
121
316
|
### `StorefrontSDKInitializer`
|
|
122
317
|
|
|
123
|
-
**
|
|
318
|
+
**Client-side initializer** component (must be imported from `/client`):
|
|
124
319
|
|
|
125
320
|
```typescript
|
|
321
|
+
import { Environment, StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
|
|
322
|
+
|
|
126
323
|
<StorefrontSDKInitializer
|
|
127
324
|
config={{
|
|
128
325
|
storeId: "your-store-id",
|
|
@@ -131,109 +328,414 @@ const sdk = getStorefrontSDK(); // Throws clear error with instructions
|
|
|
131
328
|
|
|
132
329
|
// Optional: Advanced configuration
|
|
133
330
|
tokenStorageOptions: {
|
|
134
|
-
prefix: "ce_",
|
|
135
|
-
maxAge: 30 * 24 * 60 * 60,
|
|
136
|
-
secure: true,
|
|
331
|
+
prefix: "ce_", // Cookie prefix (default)
|
|
332
|
+
maxAge: 30 * 24 * 60 * 60, // 30 days
|
|
333
|
+
secure: true, // Auto-detected from environment
|
|
137
334
|
sameSite: "Lax",
|
|
138
335
|
},
|
|
139
336
|
}}
|
|
140
337
|
/>
|
|
141
338
|
```
|
|
142
339
|
|
|
143
|
-
##
|
|
340
|
+
## Error Handling
|
|
341
|
+
|
|
342
|
+
All SDK methods return a consistent error structure:
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
const { data, error, response } = await storefront(cookies()).catalog.listProducts();
|
|
346
|
+
|
|
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);
|
|
352
|
+
}
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
## Static Site Generation (SSG) & Build-Time Optimization
|
|
144
356
|
|
|
145
|
-
The SDK
|
|
357
|
+
The SDK provides powerful build-time optimizations for SSG/ISR that dramatically reduce API calls during the build process through intelligent token caching.
|
|
146
358
|
|
|
147
|
-
###
|
|
359
|
+
### Automatic Build-Time Token Caching
|
|
148
360
|
|
|
149
|
-
|
|
150
|
-
2. **Token Expiry**: Refreshes tokens transparently
|
|
151
|
-
3. **Token Corruption**: Cleans up orphaned tokens
|
|
152
|
-
4. **User Login**: Upgrades from anonymous to authenticated tokens
|
|
153
|
-
5. **User Logout**: Downgrades gracefully with continuity
|
|
154
|
-
6. **Page Refresh**: Tokens persist via cookies across server/client
|
|
361
|
+
Enable automatic token caching during production builds:
|
|
155
362
|
|
|
156
|
-
|
|
363
|
+
```typescript
|
|
364
|
+
// next.config.ts
|
|
365
|
+
import type { NextConfig } from "next";
|
|
366
|
+
import { PHASE_PRODUCTION_BUILD } from 'next/constants';
|
|
367
|
+
|
|
368
|
+
const nextConfig = (phase: string): NextConfig => {
|
|
369
|
+
const isBuild = phase === PHASE_PRODUCTION_BUILD;
|
|
370
|
+
|
|
371
|
+
return {
|
|
372
|
+
env: {
|
|
373
|
+
// Enable build-time token caching during production builds
|
|
374
|
+
NEXT_BUILD_CACHE_TOKENS: process.env.NEXT_BUILD_CACHE_TOKENS ?? (isBuild ? 'true' : 'false'),
|
|
375
|
+
},
|
|
376
|
+
};
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
export default nextConfig;
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### SSG with generateStaticParams
|
|
383
|
+
|
|
384
|
+
Create static product pages during build:
|
|
157
385
|
|
|
158
386
|
```typescript
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
|
|
387
|
+
// app/products/[slug]/page.tsx
|
|
388
|
+
import { storefront } from "@commercengine/storefront-sdk-nextjs";
|
|
389
|
+
import { notFound } from "next/navigation";
|
|
390
|
+
|
|
391
|
+
interface ProductPageProps {
|
|
392
|
+
params: Promise<{ slug: string }>;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export default async function ProductPage({ params }: ProductPageProps) {
|
|
396
|
+
const { slug } = await params;
|
|
397
|
+
const sdk = storefront(); // No cookies() - uses build-time storage
|
|
398
|
+
|
|
399
|
+
// Get product detail by slug or ID
|
|
400
|
+
const { data, error } = await sdk.catalog.getProductDetail({
|
|
401
|
+
product_id_or_slug: slug
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
if (error || !data) {
|
|
405
|
+
notFound();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const { product } = data;
|
|
409
|
+
|
|
410
|
+
return (
|
|
411
|
+
<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>
|
|
416
|
+
</div>
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Generate static params from real API data
|
|
421
|
+
export async function generateStaticParams() {
|
|
422
|
+
const sdk = storefront(); // No cookies() - uses build-time storage
|
|
423
|
+
|
|
424
|
+
const { data: productsData, error } = await sdk.catalog.listProducts({
|
|
425
|
+
limit: 100 // Generate pages for first 100 products
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
if (error || !productsData) {
|
|
429
|
+
console.error("Error fetching products for static generation:", error);
|
|
430
|
+
return [];
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return productsData.products.map(product => ({
|
|
434
|
+
slug: product.slug || product.id
|
|
435
|
+
}));
|
|
436
|
+
}
|
|
162
437
|
```
|
|
163
438
|
|
|
164
|
-
|
|
439
|
+
### SSG Test Page Example
|
|
440
|
+
|
|
441
|
+
Create a page that makes multiple API calls during build to test token reuse:
|
|
442
|
+
|
|
443
|
+
```typescript
|
|
444
|
+
// app/ssg-test/page.tsx
|
|
445
|
+
import { storefront } from "@commercengine/storefront-sdk-nextjs";
|
|
165
446
|
|
|
166
|
-
|
|
447
|
+
export default async function SSGTestPage() {
|
|
448
|
+
const sdk = storefront(); // No cookies() - uses build-time storage
|
|
449
|
+
|
|
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
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
const { data: categories, error: categoriesError } = await sdk.catalog.listCategories({
|
|
456
|
+
nested_level: 1
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const { data: anonymousToken, error: tokenError } = await sdk.auth.getAnonymousToken();
|
|
460
|
+
|
|
461
|
+
const buildTime = new Date().toISOString();
|
|
462
|
+
|
|
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
|
+
);
|
|
500
|
+
}
|
|
167
501
|
```
|
|
168
|
-
🚨 Server Environment Detected!
|
|
169
502
|
|
|
170
|
-
|
|
171
|
-
Please pass the Next.js cookie store:
|
|
503
|
+
### Build Performance Benefits
|
|
172
504
|
|
|
173
|
-
|
|
174
|
-
import { cookies } from 'next/headers';
|
|
505
|
+
With token caching enabled, you'll see dramatic performance improvements:
|
|
175
506
|
|
|
176
|
-
|
|
177
|
-
|
|
507
|
+
**Without Caching:**
|
|
508
|
+
- 🔴 Each page creates its own token
|
|
509
|
+
- 🔴 100 pages = 100+ anonymous token API calls
|
|
510
|
+
- 🔴 Slower builds, higher API usage
|
|
178
511
|
|
|
179
|
-
|
|
180
|
-
|
|
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
|
|
181
516
|
|
|
182
|
-
|
|
183
|
-
|
|
517
|
+
### Build Logs to Monitor
|
|
518
|
+
|
|
519
|
+
When build caching is working, you'll see these logs:
|
|
520
|
+
|
|
521
|
+
```
|
|
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
|
|
184
527
|
```
|
|
185
528
|
|
|
186
|
-
|
|
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
|
|
533
|
+
|
|
534
|
+
### Manual Override
|
|
535
|
+
|
|
536
|
+
You can manually control build caching:
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
# Enable caching for this build
|
|
540
|
+
NEXT_BUILD_CACHE_TOKENS=true pnpm build
|
|
541
|
+
|
|
542
|
+
# Disable caching for this build
|
|
543
|
+
NEXT_BUILD_CACHE_TOKENS=false pnpm build
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
## Best Practices
|
|
547
|
+
|
|
548
|
+
### ✅ Do's
|
|
549
|
+
|
|
550
|
+
- **Initialize once**: Call `StorefrontSDKInitializer` only in your root layout
|
|
551
|
+
- **Use `storefront(cookies())`**: Always pass cookies in server contexts
|
|
552
|
+
- **Handle errors**: Always check the error property in responses
|
|
553
|
+
- **Use Server Actions**: For authentication flows that need to persist tokens
|
|
554
|
+
- **Environment variables**: Store sensitive config in environment variables
|
|
555
|
+
|
|
556
|
+
### ❌ Don'ts
|
|
557
|
+
|
|
558
|
+
- **Don't call `cookies()` in Client Components**: It will throw an error
|
|
559
|
+
- **Don't initialize multiple times**: The SDK handles singleton behavior
|
|
560
|
+
- **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
|
|
562
|
+
|
|
563
|
+
## Troubleshooting
|
|
564
|
+
|
|
565
|
+
### Common Issues
|
|
566
|
+
|
|
567
|
+
1. **"Cookie store passed in client environment"**
|
|
568
|
+
```typescript
|
|
569
|
+
// ❌ Wrong
|
|
570
|
+
storefront(cookies()) // in client component
|
|
571
|
+
|
|
572
|
+
// ✅ Correct
|
|
573
|
+
storefront() // in client component
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
2. **"SDK not initialized"**
|
|
577
|
+
```typescript
|
|
578
|
+
// Make sure StorefrontSDKInitializer is in your root layout
|
|
579
|
+
<StorefrontSDKInitializer config={{ ... }} />
|
|
580
|
+
```
|
|
581
|
+
|
|
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!
|
|
588
|
+
|
|
589
|
+
You're calling storefront() on the server without cookies.
|
|
590
|
+
Please pass the Next.js cookie store:
|
|
591
|
+
|
|
592
|
+
✅ Correct usage:
|
|
593
|
+
import { cookies } from 'next/headers';
|
|
594
|
+
const sdk = storefront(cookies());
|
|
595
|
+
|
|
596
|
+
❌ Your current usage:
|
|
597
|
+
const sdk = storefront(); // Missing cookies!
|
|
598
|
+
```
|
|
599
|
+
|
|
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
|
+
## Migration Guide
|
|
615
|
+
|
|
616
|
+
### From Core SDK
|
|
187
617
|
|
|
188
|
-
**Before (Base SDK):**
|
|
189
618
|
```typescript
|
|
190
|
-
|
|
619
|
+
// Before (core SDK)
|
|
620
|
+
import { StorefrontSDK } from "@commercengine/storefront-sdk";
|
|
621
|
+
const sdk = new StorefrontSDK({
|
|
622
|
+
storeId: "...",
|
|
623
|
+
tokenStorage: new BrowserTokenStorage()
|
|
624
|
+
});
|
|
191
625
|
await sdk.auth.getAnonymousToken(); // Manual token creation
|
|
192
|
-
|
|
626
|
+
|
|
627
|
+
// After (Next.js SDK)
|
|
628
|
+
import { storefront } from "@commercengine/storefront-sdk-nextjs";
|
|
629
|
+
const sdk = storefront(cookies()); // Automatic token management
|
|
193
630
|
```
|
|
194
631
|
|
|
195
|
-
|
|
632
|
+
### From Previous Next.js SDK Version
|
|
633
|
+
|
|
196
634
|
```typescript
|
|
197
|
-
|
|
198
|
-
|
|
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";
|
|
641
|
+
const sdk = storefront(cookies());
|
|
199
642
|
```
|
|
200
643
|
|
|
201
644
|
## TypeScript Support
|
|
202
645
|
|
|
203
|
-
|
|
646
|
+
The SDK provides complete TypeScript support with auto-generated types:
|
|
204
647
|
|
|
205
648
|
```typescript
|
|
206
649
|
import type {
|
|
207
650
|
StorefrontSDK,
|
|
651
|
+
ApiResult,
|
|
652
|
+
UserInfo,
|
|
208
653
|
NextJSSDKConfig,
|
|
209
654
|
Environment
|
|
210
|
-
} from
|
|
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);
|
|
211
662
|
```
|
|
212
663
|
|
|
213
|
-
##
|
|
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";
|
|
214
684
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
+
```
|
|
220
706
|
|
|
221
707
|
## Why This Wrapper Exists
|
|
222
708
|
|
|
223
|
-
**The
|
|
224
|
-
- Manual token storage setup
|
|
225
|
-
- Server/client environment handling
|
|
226
|
-
- Cookie configuration for SSR
|
|
227
|
-
-
|
|
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
|
|
715
|
+
|
|
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
|
|
722
|
+
|
|
723
|
+
**Result: Production-ready e-commerce with zero complexity!** 🚀
|
|
724
|
+
|
|
725
|
+
## API Reference
|
|
726
|
+
|
|
727
|
+
For complete API documentation of all available endpoints, visit [docs.commercengine.io/api-reference](https://docs.commercengine.io/api-reference)
|
|
228
728
|
|
|
229
|
-
|
|
230
|
-
- Zero configuration token management
|
|
231
|
-
- Automatic environment detection
|
|
232
|
-
- Cookie-based persistence works out of the box
|
|
233
|
-
- One API that works everywhere
|
|
729
|
+
The Next.js SDK provides access to all the same endpoints as the core SDK:
|
|
234
730
|
|
|
235
|
-
|
|
731
|
+
- `sdk.auth.*` - Authentication and user management
|
|
732
|
+
- `sdk.customer.*` - Customer profiles and preferences
|
|
733
|
+
- `sdk.catalog.*` - Products, categories, and search
|
|
734
|
+
- `sdk.cart.*` - Shopping cart management
|
|
735
|
+
- `sdk.order.*` - Order creation and tracking
|
|
736
|
+
- `sdk.shipping.*` - Shipping methods and rates
|
|
737
|
+
- `sdk.helpers.*` - Countries, currencies, utilities
|
|
236
738
|
|
|
237
739
|
## License
|
|
238
740
|
|
|
239
|
-
All
|
|
741
|
+
All Rights Reserved
|