@commercengine/storefront-sdk-nextjs 0.2.10 → 0.3.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/MIGRATION.md +89 -0
- package/README.md +180 -440
- package/dist/client.d.mts +4 -4
- package/dist/client.mjs +9 -9
- package/dist/index.d.mts +23 -24
- package/dist/index.mjs +13 -35
- package/dist/manager.d.mts +18 -13
- package/dist/manager.mjs +67 -50
- package/dist/server.d.mts +3 -3
- package/dist/server.mjs +3 -3
- package/package.json +5 -4
package/README.md
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# CommerceEngine Next.js SDK
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Production-ready Next.js wrapper for the CommerceEngine Storefront SDK.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Breaking changes from the previous wrapper API are documented in
|
|
6
|
+
[MIGRATION.md](./MIGRATION.md).
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
This package gives Next.js apps one configured storefront factory with two
|
|
9
|
+
explicit access patterns:
|
|
10
|
+
|
|
11
|
+
- `storefront.public()` for build-safe and public server reads
|
|
12
|
+
- `storefront.session()` / `storefront.session(await cookies())` for live user
|
|
13
|
+
session flows
|
|
14
|
+
|
|
15
|
+
It builds on [`@commercengine/ssr-utils`](../ssr-utils) for cookie-backed server
|
|
16
|
+
storage, but the primary DX is the Next.js-specific `createStorefront()` API.
|
|
15
17
|
|
|
16
18
|
## Installation
|
|
17
19
|
|
|
@@ -23,82 +25,51 @@ pnpm add @commercengine/storefront-sdk-nextjs
|
|
|
23
25
|
|
|
24
26
|
## Quick Start
|
|
25
27
|
|
|
26
|
-
### 1.
|
|
27
|
-
|
|
28
|
-
Add your store configuration to `.env.local`:
|
|
28
|
+
### 1. Add environment variables
|
|
29
29
|
|
|
30
30
|
```bash
|
|
31
31
|
NEXT_PUBLIC_STORE_ID=your-store-id
|
|
32
32
|
NEXT_PUBLIC_API_KEY=your-api-key
|
|
33
|
-
|
|
34
|
-
NEXT_PUBLIC_ENVIRONMENT=staging # or "production"
|
|
33
|
+
NEXT_PUBLIC_ENVIRONMENT=staging
|
|
35
34
|
```
|
|
36
35
|
|
|
37
|
-
### 2. Create
|
|
38
|
-
|
|
39
|
-
Create `lib/storefront.ts` in your project:
|
|
36
|
+
### 2. Create `lib/storefront.ts`
|
|
40
37
|
|
|
41
38
|
```typescript
|
|
42
|
-
// lib/storefront.ts
|
|
43
39
|
import {
|
|
44
40
|
createStorefront,
|
|
45
41
|
type StorefrontRuntimeConfig,
|
|
46
42
|
} from "@commercengine/storefront-sdk-nextjs";
|
|
47
43
|
|
|
48
|
-
// Optional advanced configuration (everything not in environment variables)
|
|
49
44
|
const storefrontConfig: StorefrontRuntimeConfig = {
|
|
50
45
|
debug: true,
|
|
51
46
|
timeout: 15000,
|
|
52
|
-
logger: (msg
|
|
53
|
-
console.log("[STOREFRONT]", msg, ...args),
|
|
54
|
-
onTokensUpdated: (access: string, refresh: string) => {
|
|
55
|
-
console.log("🔥 TOKENS UPDATED:", {
|
|
56
|
-
access: access.slice(0, 20) + "...",
|
|
57
|
-
refresh: refresh.slice(0, 20) + "...",
|
|
58
|
-
});
|
|
59
|
-
},
|
|
60
|
-
onTokensCleared: () => {
|
|
61
|
-
console.log("🔄 TOKENS CLEARED");
|
|
62
|
-
},
|
|
47
|
+
logger: (msg, ...args) => console.log("[STOREFRONT]", msg, ...args),
|
|
63
48
|
};
|
|
64
49
|
|
|
65
|
-
// Create the configured storefront function (storefrontConfig is OPTIONAL)
|
|
66
50
|
export const storefront = createStorefront(storefrontConfig);
|
|
67
51
|
|
|
68
|
-
// Re-export types for convenience
|
|
69
52
|
export type { StorefrontRuntimeConfig };
|
|
70
53
|
```
|
|
71
54
|
|
|
72
|
-
|
|
73
|
-
The Next.js SDK re-exports all types from the core SDK, so you can import them directly:
|
|
74
|
-
|
|
75
|
-
```typescript
|
|
76
|
-
// Import any core SDK types you need
|
|
77
|
-
import type {
|
|
78
|
-
UserInfo,
|
|
79
|
-
SupportedDefaultHeaders,
|
|
80
|
-
StorefrontSDKOptions,
|
|
81
|
-
components,
|
|
82
|
-
operations
|
|
83
|
-
} from "@commercengine/storefront-sdk-nextjs";
|
|
84
|
-
|
|
85
|
-
// Use imported types
|
|
86
|
-
const headers: SupportedDefaultHeaders = {
|
|
87
|
-
customer_group_id: "01ABC123..."
|
|
88
|
-
};
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### 3. Initialize in Root Layout
|
|
55
|
+
### 3. Initialize once in the root layout
|
|
92
56
|
|
|
93
57
|
```typescript
|
|
94
|
-
// app/layout.tsx
|
|
95
58
|
import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
|
|
59
|
+
import { storefront } from "@/lib/storefront";
|
|
60
|
+
|
|
61
|
+
const { data: storeConfig } = await storefront.public().store.getStoreConfig();
|
|
96
62
|
|
|
97
|
-
export default function RootLayout({
|
|
63
|
+
export default function RootLayout({
|
|
64
|
+
children,
|
|
65
|
+
}: {
|
|
66
|
+
children: React.ReactNode;
|
|
67
|
+
}) {
|
|
98
68
|
return (
|
|
99
69
|
<html lang="en">
|
|
100
70
|
<body>
|
|
101
71
|
<StorefrontSDKInitializer />
|
|
72
|
+
<h1>{storeConfig?.store_config?.brand.name}</h1>
|
|
102
73
|
{children}
|
|
103
74
|
</body>
|
|
104
75
|
</html>
|
|
@@ -106,349 +77,202 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
106
77
|
}
|
|
107
78
|
```
|
|
108
79
|
|
|
109
|
-
### 4. Use
|
|
80
|
+
### 4. Use the correct accessor
|
|
110
81
|
|
|
111
82
|
```typescript
|
|
112
|
-
// Import your configured storefront everywhere
|
|
113
83
|
import { storefront } from "@/lib/storefront";
|
|
114
|
-
import { cookies } from "next/headers";
|
|
115
|
-
|
|
116
|
-
// ✅ Client Component - No cookies needed
|
|
117
|
-
const products = await storefront().catalog.listProducts();
|
|
84
|
+
import { cookies } from "next/headers";
|
|
118
85
|
|
|
119
|
-
//
|
|
120
|
-
const
|
|
86
|
+
// Build/prerender-safe reads
|
|
87
|
+
const publicSdk = storefront.public();
|
|
121
88
|
|
|
122
|
-
//
|
|
123
|
-
const
|
|
89
|
+
// Client Components
|
|
90
|
+
const clientSessionSdk = storefront.session();
|
|
124
91
|
|
|
125
|
-
//
|
|
126
|
-
|
|
127
|
-
const products = await storefront().catalog.listProducts();
|
|
92
|
+
// Server Components, Server Actions, Route Handlers
|
|
93
|
+
const serverSessionSdk = storefront.session(await cookies());
|
|
128
94
|
```
|
|
129
95
|
|
|
130
|
-
##
|
|
96
|
+
## Mental Model
|
|
131
97
|
|
|
132
|
-
|
|
98
|
+
- `public()` is for public reads that should stay API-key-backed and never touch
|
|
99
|
+
session bootstrap, refresh, or token persistence.
|
|
100
|
+
- `session()` is for live requests that operate on behalf of an anonymous or
|
|
101
|
+
authenticated user.
|
|
102
|
+
- The server version of `session()` requires `cookies()` so request continuity
|
|
103
|
+
is explicit and session state can flow across server/client boundaries.
|
|
104
|
+
|
|
105
|
+
That means:
|
|
133
106
|
|
|
134
|
-
|
|
107
|
+
- Root layouts use `storefront.public()`
|
|
108
|
+
- SSG/ISR pages use `storefront.public()`
|
|
109
|
+
- Client Components use `storefront.session()`
|
|
110
|
+
- Server Components, Server Actions, and Route Handlers use
|
|
111
|
+
`storefront.session(await cookies())`
|
|
112
|
+
|
|
113
|
+
## Usage Examples
|
|
114
|
+
|
|
115
|
+
### Client Components
|
|
135
116
|
|
|
136
117
|
```typescript
|
|
137
|
-
// components/ProductList.tsx
|
|
138
118
|
"use client";
|
|
139
119
|
|
|
140
|
-
import {
|
|
120
|
+
import { useEffect, useState } from "react";
|
|
141
121
|
import { storefront } from "@/lib/storefront";
|
|
142
122
|
|
|
143
123
|
export default function ProductList() {
|
|
144
|
-
const [products, setProducts] = useState([]);
|
|
145
|
-
|
|
124
|
+
const [products, setProducts] = useState<string[]>([]);
|
|
125
|
+
|
|
146
126
|
useEffect(() => {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (data) setProducts(data.products);
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
loadProducts();
|
|
127
|
+
const sdk = storefront.session();
|
|
128
|
+
|
|
129
|
+
sdk.catalog.listProducts({ limit: 5 }).then(({ data }) => {
|
|
130
|
+
setProducts(data?.products.map((product) => product.name) ?? []);
|
|
131
|
+
});
|
|
156
132
|
}, []);
|
|
157
|
-
|
|
133
|
+
|
|
158
134
|
return (
|
|
159
|
-
<
|
|
160
|
-
{products.map(
|
|
161
|
-
<
|
|
135
|
+
<ul>
|
|
136
|
+
{products.map((name) => (
|
|
137
|
+
<li key={name}>{name}</li>
|
|
162
138
|
))}
|
|
163
|
-
</
|
|
139
|
+
</ul>
|
|
164
140
|
);
|
|
165
141
|
}
|
|
166
142
|
```
|
|
167
143
|
|
|
168
144
|
### Server Components
|
|
169
145
|
|
|
170
|
-
|
|
146
|
+
Use `public()` for public content and `session(await cookies())` when the read
|
|
147
|
+
depends on live session state.
|
|
171
148
|
|
|
172
149
|
```typescript
|
|
173
|
-
// app/products/page.tsx
|
|
174
150
|
import { storefront } from "@/lib/storefront";
|
|
175
151
|
import { cookies } from "next/headers";
|
|
176
152
|
|
|
177
|
-
export default async function
|
|
178
|
-
const sdk = storefront(cookies());
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
return (
|
|
183
|
-
<div>
|
|
184
|
-
{products?.products.map(product => (
|
|
185
|
-
<div key={product.id}>{product.name}</div>
|
|
186
|
-
))}
|
|
187
|
-
</div>
|
|
188
|
-
);
|
|
153
|
+
export default async function CartPage() {
|
|
154
|
+
const sdk = storefront.session(await cookies());
|
|
155
|
+
const { data: cart } = await sdk.cart.getCart();
|
|
156
|
+
|
|
157
|
+
return <pre>{JSON.stringify(cart, null, 2)}</pre>;
|
|
189
158
|
}
|
|
190
159
|
```
|
|
191
160
|
|
|
192
161
|
### Server Actions
|
|
193
162
|
|
|
194
|
-
Server Actions can both read and write cookies, perfect for authentication:
|
|
195
|
-
|
|
196
163
|
```typescript
|
|
197
|
-
// app/actions.ts
|
|
198
164
|
"use server";
|
|
199
165
|
|
|
200
166
|
import { storefront } from "@/lib/storefront";
|
|
201
167
|
import { cookies } from "next/headers";
|
|
202
168
|
|
|
203
|
-
export async function
|
|
204
|
-
const sdk = storefront(cookies());
|
|
205
|
-
|
|
169
|
+
export async function loginWithPassword(email: string, password: string) {
|
|
170
|
+
const sdk = storefront.session(await cookies());
|
|
206
171
|
const { data, error } = await sdk.auth.loginWithPassword({ email, password });
|
|
207
|
-
|
|
208
|
-
if (data) {
|
|
209
|
-
// Tokens are automatically saved to cookies
|
|
210
|
-
return { success: true, user: data.user };
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return { success: false, error: error?.message };
|
|
214
|
-
}
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
### API Routes
|
|
218
|
-
|
|
219
|
-
API Routes work identically to Server Actions:
|
|
220
172
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
import { storefront } from "@/lib/storefront";
|
|
224
|
-
import { cookies } from "next/headers";
|
|
225
|
-
import { NextResponse } from "next/server";
|
|
226
|
-
|
|
227
|
-
export async function GET() {
|
|
228
|
-
try {
|
|
229
|
-
const sdk = storefront(cookies());
|
|
230
|
-
const { data, error } = await sdk.catalog.listProducts();
|
|
231
|
-
|
|
232
|
-
if (error) {
|
|
233
|
-
return NextResponse.json({ error: error.message }, { status: 400 });
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return NextResponse.json(data);
|
|
237
|
-
} catch (error) {
|
|
238
|
-
return NextResponse.json(
|
|
239
|
-
{ error: "Internal server error" },
|
|
240
|
-
{ status: 500 }
|
|
241
|
-
);
|
|
173
|
+
if (error) {
|
|
174
|
+
return { success: false, error: error.message };
|
|
242
175
|
}
|
|
243
|
-
}
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Root Layout (Special Case)
|
|
247
|
-
|
|
248
|
-
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.
|
|
249
|
-
|
|
250
|
-
```typescript
|
|
251
|
-
// app/layout.tsx
|
|
252
|
-
import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
|
|
253
|
-
import { storefront } from "@/lib/storefront";
|
|
254
|
-
|
|
255
|
-
// Root Layout requires explicit flag - no request context available
|
|
256
|
-
const sdk = storefront({ isRootLayout: true });
|
|
257
|
-
const { data: storeConfig } = await sdk.store.getStoreConfig();
|
|
258
176
|
|
|
259
|
-
|
|
260
|
-
return (
|
|
261
|
-
<html lang="en">
|
|
262
|
-
<body>
|
|
263
|
-
<StorefrontSDKInitializer />
|
|
264
|
-
<h1>Welcome to {storeConfig?.store_config?.brand.name}</h1>
|
|
265
|
-
{children}
|
|
266
|
-
</body>
|
|
267
|
-
</html>
|
|
268
|
-
);
|
|
177
|
+
return { success: true, user: data?.user ?? null };
|
|
269
178
|
}
|
|
270
179
|
```
|
|
271
180
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
The SDK provides powerful build-time optimizations through intelligent token caching.
|
|
275
|
-
|
|
276
|
-
### Configure Next.js for Build-Time Optimization
|
|
277
|
-
|
|
278
|
-
Create or update your `next.config.ts` (or `next.config.js`) to enable automatic token caching during builds:
|
|
181
|
+
### Static Generation
|
|
279
182
|
|
|
280
183
|
```typescript
|
|
281
|
-
// next.config.ts
|
|
282
|
-
import type { NextConfig } from "next";
|
|
283
|
-
import { PHASE_PRODUCTION_BUILD } from 'next/constants';
|
|
284
|
-
|
|
285
|
-
const nextConfig = (phase: string): NextConfig => {
|
|
286
|
-
const isBuild = phase === PHASE_PRODUCTION_BUILD;
|
|
287
|
-
|
|
288
|
-
return {
|
|
289
|
-
env: {
|
|
290
|
-
// Enable build-time token caching during production builds and when explicitly set
|
|
291
|
-
NEXT_BUILD_CACHE_TOKENS: process.env.NEXT_BUILD_CACHE_TOKENS ?? (isBuild ? 'true' : 'false'),
|
|
292
|
-
// Critical: tells SDK to use MemoryStore during SSG/Build/ISR to avoid cookie context failures
|
|
293
|
-
NEXT_IS_BUILD: isBuild ? 'true' : 'false',
|
|
294
|
-
},
|
|
295
|
-
|
|
296
|
-
// Ensure static generation is enabled
|
|
297
|
-
output: undefined, // Let Next.js decide based on usage
|
|
298
|
-
};
|
|
299
|
-
};
|
|
300
|
-
|
|
301
|
-
export default nextConfig;
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### SSG with generateStaticParams
|
|
305
|
-
|
|
306
|
-
```typescript
|
|
307
|
-
// app/products/[slug]/page.tsx
|
|
308
184
|
import { storefront } from "@/lib/storefront";
|
|
309
185
|
import { notFound } from "next/navigation";
|
|
310
186
|
|
|
311
|
-
|
|
187
|
+
export default async function ProductPage({
|
|
188
|
+
params,
|
|
189
|
+
}: {
|
|
312
190
|
params: Promise<{ slug: string }>;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
export default async function ProductPage({ params }: ProductPageProps) {
|
|
191
|
+
}) {
|
|
316
192
|
const { slug } = await params;
|
|
317
|
-
const sdk = storefront();
|
|
318
|
-
|
|
193
|
+
const sdk = storefront.public();
|
|
194
|
+
|
|
319
195
|
const { data, error } = await sdk.catalog.getProductDetail({
|
|
320
|
-
product_id_or_slug: slug
|
|
196
|
+
product_id_or_slug: slug,
|
|
321
197
|
});
|
|
322
|
-
|
|
198
|
+
|
|
323
199
|
if (error || !data) {
|
|
324
200
|
notFound();
|
|
325
201
|
}
|
|
326
|
-
|
|
327
|
-
return
|
|
328
|
-
<div>
|
|
329
|
-
<h1>{data.product.name}</h1>
|
|
330
|
-
<p>SKU: {data.product.sku}</p>
|
|
331
|
-
<p>Description: {data.product.short_description}</p>
|
|
332
|
-
</div>
|
|
333
|
-
);
|
|
202
|
+
|
|
203
|
+
return <h1>{data.product.name}</h1>;
|
|
334
204
|
}
|
|
335
205
|
|
|
336
|
-
// Generate static params from real API data
|
|
337
206
|
export async function generateStaticParams() {
|
|
338
|
-
const sdk = storefront();
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
return productsData.products.map(product => ({
|
|
349
|
-
slug: product.slug || product.id
|
|
350
|
-
}));
|
|
207
|
+
const sdk = storefront.public();
|
|
208
|
+
const { data } = await sdk.catalog.listProducts({ limit: 100 });
|
|
209
|
+
|
|
210
|
+
return (
|
|
211
|
+
data?.products.map((product) => ({
|
|
212
|
+
slug: product.slug || product.id,
|
|
213
|
+
})) ?? []
|
|
214
|
+
);
|
|
351
215
|
}
|
|
352
216
|
```
|
|
353
217
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
With token caching enabled:
|
|
357
|
-
- ✅ Token created once and reused across all pages
|
|
358
|
-
- ✅ 100 pages = ~1 anonymous token API call total
|
|
359
|
-
- ✅ Faster builds, dramatically lower API usage
|
|
360
|
-
|
|
361
|
-
## Authentication Patterns
|
|
218
|
+
## Authentication Model
|
|
362
219
|
|
|
363
|
-
|
|
364
|
-
> - ✅ **Server Actions** (recommended for authentication flows)
|
|
365
|
-
> - ✅ **API Routes** (`/api` directory)
|
|
366
|
-
> - ✅ **Client Components** (browser environment)
|
|
367
|
-
> - ❌ **Server Components** (cannot set cookies, tokens won't persist)
|
|
368
|
-
>
|
|
369
|
-
> This ensures the SDK can automatically handle token storage and user session continuity.
|
|
370
|
-
|
|
371
|
-
### Anonymous Users
|
|
220
|
+
### `StorefrontSDKInitializer`
|
|
372
221
|
|
|
373
|
-
|
|
222
|
+
`StorefrontSDKInitializer` is a client component that eagerly bootstraps the
|
|
223
|
+
anonymous session once on first load by calling `ensureAccessToken()`.
|
|
374
224
|
|
|
375
225
|
```typescript
|
|
376
|
-
|
|
377
|
-
|
|
226
|
+
import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
|
|
227
|
+
|
|
228
|
+
<StorefrontSDKInitializer />
|
|
378
229
|
```
|
|
379
230
|
|
|
380
|
-
|
|
231
|
+
It accepts an optional `runtimeConfig` prop when you need client-only runtime
|
|
232
|
+
overrides:
|
|
381
233
|
|
|
382
234
|
```typescript
|
|
383
|
-
|
|
384
|
-
"use server";
|
|
385
|
-
export async function loginUser(email: string, password: string) {
|
|
386
|
-
const sdk = storefront(cookies());
|
|
387
|
-
|
|
388
|
-
const { data, error } = await sdk.auth.loginWithPassword({ email, password });
|
|
389
|
-
|
|
390
|
-
if (data) {
|
|
391
|
-
// Tokens automatically saved to cookies
|
|
392
|
-
redirect('/dashboard');
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
return { error: error?.message };
|
|
396
|
-
}
|
|
235
|
+
<StorefrontSDKInitializer runtimeConfig={{ debug: true }} />
|
|
397
236
|
```
|
|
398
237
|
|
|
399
|
-
###
|
|
238
|
+
### Where token-returning endpoints should run
|
|
400
239
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
export async function sendOTP(phone: string, country_code: string) {
|
|
404
|
-
const sdk = storefront(await cookies());
|
|
405
|
-
|
|
406
|
-
return await sdk.auth.loginWithPhone({
|
|
407
|
-
phone,
|
|
408
|
-
country_code,
|
|
409
|
-
register_if_not_exists: true
|
|
410
|
-
});
|
|
411
|
-
}
|
|
240
|
+
Calls that create or replace tokens should run in places that can persist the
|
|
241
|
+
resulting session cleanly:
|
|
412
242
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
otp_token,
|
|
420
|
-
otp_action
|
|
421
|
-
});
|
|
422
|
-
|
|
423
|
-
if (data) {
|
|
424
|
-
// Tokens automatically saved to cookies
|
|
425
|
-
return { success: true, user: data.user };
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
return { success: false, error: error?.message };
|
|
429
|
-
}
|
|
430
|
-
```
|
|
243
|
+
- Client Components
|
|
244
|
+
- Server Actions
|
|
245
|
+
- Route Handlers
|
|
246
|
+
|
|
247
|
+
Server Components are best used for reads against an already-established
|
|
248
|
+
session, not for login/register/reset-password flows.
|
|
431
249
|
|
|
432
250
|
## API Reference
|
|
433
251
|
|
|
434
252
|
### `createStorefront(config?)`
|
|
435
253
|
|
|
436
|
-
Creates
|
|
254
|
+
Creates the configured Next.js storefront factory.
|
|
437
255
|
|
|
438
256
|
```typescript
|
|
439
257
|
import { createStorefront } from "@commercengine/storefront-sdk-nextjs";
|
|
440
258
|
|
|
441
259
|
export const storefront = createStorefront({
|
|
442
260
|
debug: true,
|
|
443
|
-
|
|
261
|
+
timeout: 15000,
|
|
444
262
|
});
|
|
445
263
|
```
|
|
446
264
|
|
|
447
|
-
|
|
448
|
-
- `config` (optional): `StorefrontRuntimeConfig` - Advanced configuration options
|
|
265
|
+
The returned type is:
|
|
449
266
|
|
|
450
|
-
|
|
451
|
-
|
|
267
|
+
```typescript
|
|
268
|
+
type NextJSStorefront = {
|
|
269
|
+
public: () => PublicStorefrontSDK;
|
|
270
|
+
session: {
|
|
271
|
+
(): SessionStorefrontSDK;
|
|
272
|
+
(cookieStore: NextCookieStore): SessionStorefrontSDK;
|
|
273
|
+
};
|
|
274
|
+
};
|
|
275
|
+
```
|
|
452
276
|
|
|
453
277
|
### `StorefrontRuntimeConfig`
|
|
454
278
|
|
|
@@ -456,15 +280,12 @@ Optional configuration object for `createStorefront()`:
|
|
|
456
280
|
|
|
457
281
|
```typescript
|
|
458
282
|
interface StorefrontRuntimeConfig {
|
|
459
|
-
// Override environment variables
|
|
460
283
|
storeId?: string;
|
|
461
284
|
apiKey?: string;
|
|
462
285
|
environment?: Environment;
|
|
463
286
|
baseUrl?: string;
|
|
464
287
|
timeout?: number;
|
|
465
288
|
debug?: boolean;
|
|
466
|
-
|
|
467
|
-
// Advanced options (not available via environment variables)
|
|
468
289
|
accessToken?: string;
|
|
469
290
|
refreshToken?: string;
|
|
470
291
|
defaultHeaders?: SupportedDefaultHeaders;
|
|
@@ -475,167 +296,86 @@ interface StorefrontRuntimeConfig {
|
|
|
475
296
|
}
|
|
476
297
|
```
|
|
477
298
|
|
|
478
|
-
|
|
299
|
+
All core SDK types are re-exported from this package, so you can also import
|
|
300
|
+
`UserInfo`, `SessionStorefrontSDKOptions`, `components`, `operations`, and more
|
|
301
|
+
directly from `@commercengine/storefront-sdk-nextjs`.
|
|
479
302
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
```typescript
|
|
483
|
-
// Client-side (browser)
|
|
484
|
-
const sdk = storefront();
|
|
303
|
+
## Best Practices
|
|
485
304
|
|
|
486
|
-
|
|
487
|
-
|
|
305
|
+
- Create one `lib/storefront.ts` file and reuse it everywhere.
|
|
306
|
+
- Use `storefront.public()` for root layouts, static generation, and other
|
|
307
|
+
public reads.
|
|
308
|
+
- Use `storefront.session(await cookies())` for server-side session reads.
|
|
309
|
+
- Use `storefront.session()` in Client Components.
|
|
310
|
+
- Mount `StorefrontSDKInitializer` once in the root layout.
|
|
311
|
+
- Treat `public()` and `session()` as different semantics, not just different
|
|
312
|
+
runtimes.
|
|
488
313
|
|
|
489
|
-
|
|
490
|
-
const sdk = storefront({ isRootLayout: true });
|
|
314
|
+
## Troubleshooting
|
|
491
315
|
|
|
492
|
-
|
|
493
|
-
const sdk = storefront(); // ❌ Throws error in server contexts
|
|
494
|
-
```
|
|
316
|
+
### "Server session access requires cookies"
|
|
495
317
|
|
|
496
|
-
|
|
318
|
+
You called `storefront.session()` on the server without `cookies()`.
|
|
497
319
|
|
|
498
320
|
```typescript
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
function storefront(options: { isRootLayout: true }): StorefrontSDK;
|
|
502
|
-
function storefront(cookieStore: NextCookieStore, options: { isRootLayout?: boolean }): StorefrontSDK;
|
|
503
|
-
```
|
|
321
|
+
// Wrong on the server
|
|
322
|
+
const sdk = storefront.session();
|
|
504
323
|
|
|
505
|
-
|
|
324
|
+
// Correct on the server
|
|
325
|
+
const sdk = storefront.session(await cookies());
|
|
506
326
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
```typescript
|
|
510
|
-
import { StorefrontSDKInitializer } from "@commercengine/storefront-sdk-nextjs/client";
|
|
511
|
-
|
|
512
|
-
<StorefrontSDKInitializer />
|
|
327
|
+
// Correct for public reads
|
|
328
|
+
const publicSdk = storefront.public();
|
|
513
329
|
```
|
|
514
330
|
|
|
515
|
-
|
|
331
|
+
### Root layout usage
|
|
516
332
|
|
|
517
|
-
|
|
333
|
+
There is no special `isRootLayout` escape hatch anymore. Root layouts should use
|
|
334
|
+
`storefront.public()` for public reads and `StorefrontSDKInitializer` to eager
|
|
335
|
+
bootstrap the client session.
|
|
518
336
|
|
|
519
|
-
|
|
337
|
+
### Missing environment variables
|
|
520
338
|
|
|
521
|
-
|
|
522
|
-
const { data, error, response } = await storefront(cookies()).catalog.listProducts();
|
|
339
|
+
Make sure these are set:
|
|
523
340
|
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
console.log("Products:", data.products);
|
|
529
|
-
}
|
|
341
|
+
```bash
|
|
342
|
+
NEXT_PUBLIC_STORE_ID=your-store-id
|
|
343
|
+
NEXT_PUBLIC_API_KEY=your-api-key
|
|
344
|
+
NEXT_PUBLIC_ENVIRONMENT=staging
|
|
530
345
|
```
|
|
531
346
|
|
|
532
|
-
## Best Practices
|
|
533
|
-
|
|
534
|
-
### ✅ Do's
|
|
535
|
-
|
|
536
|
-
- **Set required environment variables**: `NEXT_PUBLIC_STORE_ID` and `NEXT_PUBLIC_API_KEY` are mandatory
|
|
537
|
-
- **Create one lib/storefront.ts file**: Use `createStorefront()` to configure advanced options
|
|
538
|
-
- **Initialize once**: Call `StorefrontSDKInitializer` only in your root layout
|
|
539
|
-
- **Use `storefront(cookies())`**: Always pass cookies in server contexts
|
|
540
|
-
- **Handle errors**: Always check the error property in responses
|
|
541
|
-
- **Use Server Actions**: For authentication flows that need to persist tokens
|
|
542
|
-
|
|
543
|
-
### ❌ Don'ts
|
|
544
|
-
|
|
545
|
-
- **Don't call `cookies()` in Client Components**: It will throw an error
|
|
546
|
-
- **Don't initialize multiple times**: The SDK handles singleton behavior
|
|
547
|
-
- **Don't forget error handling**: API calls can fail for various reasons
|
|
548
|
-
- **Don't skip environment variables**: Missing required variables will cause errors
|
|
549
|
-
|
|
550
|
-
## Troubleshooting
|
|
551
|
-
|
|
552
|
-
### Common Issues
|
|
553
|
-
|
|
554
|
-
1. **"Server context requires cookies for user continuity!"**
|
|
555
|
-
```typescript
|
|
556
|
-
// ❌ Wrong - server context without cookies (breaks user sessions)
|
|
557
|
-
storefront()
|
|
558
|
-
|
|
559
|
-
// ✅ Correct - server context with cookies
|
|
560
|
-
storefront(cookies())
|
|
561
|
-
|
|
562
|
-
// ✅ Root Layout exception
|
|
563
|
-
storefront({ isRootLayout: true })
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
2. **Missing Environment Variables**
|
|
567
|
-
```bash
|
|
568
|
-
# Ensure your .env.local has the required variables:
|
|
569
|
-
NEXT_PUBLIC_STORE_ID=your-store-id
|
|
570
|
-
NEXT_PUBLIC_API_KEY=your-api-key
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
3. **"Cookie store passed in client environment"**
|
|
574
|
-
```typescript
|
|
575
|
-
// ❌ Wrong - client component with cookies
|
|
576
|
-
storefront(cookies())
|
|
577
|
-
|
|
578
|
-
// ✅ Correct - client component without cookies
|
|
579
|
-
storefront()
|
|
580
|
-
```
|
|
581
|
-
|
|
582
|
-
4. **Server Actions and async cookies()**
|
|
583
|
-
```typescript
|
|
584
|
-
// ✅ Correct - Server Actions need await cookies()
|
|
585
|
-
const sdk = storefront(await cookies());
|
|
586
|
-
|
|
587
|
-
// ✅ Server Components and API Routes use cookies() directly
|
|
588
|
-
const sdk = storefront(cookies());
|
|
589
|
-
```
|
|
590
|
-
|
|
591
347
|
## Migration Guide
|
|
592
348
|
|
|
593
|
-
### From
|
|
349
|
+
### From the previous Next.js wrapper API
|
|
594
350
|
|
|
595
351
|
```typescript
|
|
596
|
-
// Before
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
const sdk = storefront(cookies());
|
|
352
|
+
// Before
|
|
353
|
+
storefront();
|
|
354
|
+
storefront(await cookies());
|
|
355
|
+
storefront({ isRootLayout: true });
|
|
356
|
+
|
|
357
|
+
// After
|
|
358
|
+
storefront.session();
|
|
359
|
+
storefront.session(await cookies());
|
|
360
|
+
storefront.public();
|
|
606
361
|
```
|
|
607
362
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
**The Perfect DX Pattern provides:**
|
|
611
|
-
- **One Config File**: All advanced configuration in `lib/storefront.ts`
|
|
612
|
-
- **Environment Variables**: Basic config (storeId, apiKey) via env vars
|
|
613
|
-
- **Universal Import**: Same `storefront()` import everywhere
|
|
614
|
-
- **Strict User Continuity**: Enforces cookie passing to protect user sessions and analytics
|
|
615
|
-
- **Explicit Exceptions**: Clear patterns for special cases like Root Layout
|
|
616
|
-
- **Zero Guesswork**: Helpful errors guide developers to correct patterns
|
|
617
|
-
|
|
618
|
-
**Result: Production-ready e-commerce with bulletproof user session management!** 🛡️
|
|
363
|
+
### From direct core SDK usage
|
|
619
364
|
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
The Next.js SDK provides access to all the same endpoints as the core SDK:
|
|
365
|
+
```typescript
|
|
366
|
+
// Before
|
|
367
|
+
import { SessionStorefrontSDK } from "@commercengine/storefront-sdk";
|
|
625
368
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
- `sdk.cart.*` - Shopping cart management
|
|
630
|
-
- `sdk.order.*` - Order creation and tracking
|
|
631
|
-
- `sdk.payments.*` - Payment methods and processing
|
|
632
|
-
- `sdk.store.*` - Store configuration
|
|
633
|
-
- `sdk.helpers.*` - Countries, currencies, utilities
|
|
369
|
+
// After
|
|
370
|
+
import { SessionStorefrontSDK } from "@commercengine/storefront-sdk";
|
|
371
|
+
```
|
|
634
372
|
|
|
635
|
-
|
|
373
|
+
Or, for the recommended DX:
|
|
636
374
|
|
|
637
|
-
|
|
375
|
+
```typescript
|
|
376
|
+
import { createStorefront } from "@commercengine/storefront-sdk-nextjs";
|
|
377
|
+
```
|
|
638
378
|
|
|
639
379
|
## License
|
|
640
380
|
|
|
641
|
-
All Rights Reserved
|
|
381
|
+
All Rights Reserved
|