@commercengine/storefront-sdk-nextjs 0.1.0-alpha.0 → 1.0.0-alpha.2

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.
@@ -0,0 +1,448 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/sdk-manager.ts
9
+ import { cache } from "react";
10
+ import {
11
+ StorefrontSDK,
12
+ MemoryTokenStorage,
13
+ Environment
14
+ } from "@commercengine/storefront-sdk";
15
+
16
+ // src/token-storage.ts
17
+ var ClientTokenStorage = class {
18
+ constructor(options = {}) {
19
+ const prefix = options.prefix || "ce_";
20
+ this.accessTokenKey = `${prefix}access_token`;
21
+ this.refreshTokenKey = `${prefix}refresh_token`;
22
+ this.options = {
23
+ maxAge: options.maxAge || 30 * 24 * 60 * 60,
24
+ // 30 days default
25
+ path: options.path || "/",
26
+ domain: options.domain,
27
+ secure: options.secure ?? (typeof window !== "undefined" && window.location?.protocol === "https:"),
28
+ sameSite: options.sameSite || "Lax"
29
+ };
30
+ }
31
+ async getAccessToken() {
32
+ return this.getCookie(this.accessTokenKey);
33
+ }
34
+ async setAccessToken(token) {
35
+ this.setCookie(this.accessTokenKey, token);
36
+ }
37
+ async getRefreshToken() {
38
+ return this.getCookie(this.refreshTokenKey);
39
+ }
40
+ async setRefreshToken(token) {
41
+ this.setCookie(this.refreshTokenKey, token);
42
+ }
43
+ async clearTokens() {
44
+ this.deleteCookie(this.accessTokenKey);
45
+ this.deleteCookie(this.refreshTokenKey);
46
+ }
47
+ getCookie(name) {
48
+ if (typeof document === "undefined") return null;
49
+ const value = `; ${document.cookie}`;
50
+ const parts = value.split(`; ${name}=`);
51
+ if (parts.length === 2) {
52
+ const cookieValue = parts.pop()?.split(";").shift();
53
+ return cookieValue ? decodeURIComponent(cookieValue) : null;
54
+ }
55
+ return null;
56
+ }
57
+ setCookie(name, value) {
58
+ if (typeof document === "undefined") return;
59
+ const encodedValue = encodeURIComponent(value);
60
+ let cookieString = `${name}=${encodedValue}`;
61
+ if (this.options.maxAge) {
62
+ cookieString += `; Max-Age=${this.options.maxAge}`;
63
+ }
64
+ if (this.options.path) {
65
+ cookieString += `; Path=${this.options.path}`;
66
+ }
67
+ if (this.options.domain) {
68
+ cookieString += `; Domain=${this.options.domain}`;
69
+ }
70
+ if (this.options.secure) {
71
+ cookieString += `; Secure`;
72
+ }
73
+ if (this.options.sameSite) {
74
+ cookieString += `; SameSite=${this.options.sameSite}`;
75
+ }
76
+ document.cookie = cookieString;
77
+ }
78
+ deleteCookie(name) {
79
+ if (typeof document === "undefined") return;
80
+ let cookieString = `${name}=; Max-Age=0`;
81
+ if (this.options.path) {
82
+ cookieString += `; Path=${this.options.path}`;
83
+ }
84
+ if (this.options.domain) {
85
+ cookieString += `; Domain=${this.options.domain}`;
86
+ }
87
+ document.cookie = cookieString;
88
+ }
89
+ };
90
+ var ServerTokenStorage = class {
91
+ constructor(cookieStore, options = {}) {
92
+ const prefix = options.prefix || "ce_";
93
+ this.accessTokenKey = `${prefix}access_token`;
94
+ this.refreshTokenKey = `${prefix}refresh_token`;
95
+ this.cookieStore = cookieStore;
96
+ this.options = {
97
+ maxAge: options.maxAge || 30 * 24 * 60 * 60,
98
+ // 30 days default
99
+ path: options.path || "/",
100
+ domain: options.domain,
101
+ secure: options.secure ?? process.env.NODE_ENV === "production",
102
+ sameSite: options.sameSite || "Lax"
103
+ };
104
+ }
105
+ async getAccessToken() {
106
+ try {
107
+ return this.cookieStore.get(this.accessTokenKey)?.value || null;
108
+ } catch (error) {
109
+ console.warn(`Could not get access token from server cookies:`, error);
110
+ return null;
111
+ }
112
+ }
113
+ async setAccessToken(token) {
114
+ try {
115
+ this.cookieStore.set(this.accessTokenKey, token, {
116
+ maxAge: this.options.maxAge,
117
+ path: this.options.path,
118
+ domain: this.options.domain,
119
+ secure: this.options.secure,
120
+ sameSite: this.options.sameSite?.toLowerCase(),
121
+ httpOnly: false
122
+ // Allow client-side access for SDK flexibility
123
+ });
124
+ } catch (error) {
125
+ console.warn(`Could not set access token on server:`, error);
126
+ }
127
+ }
128
+ async getRefreshToken() {
129
+ try {
130
+ return this.cookieStore.get(this.refreshTokenKey)?.value || null;
131
+ } catch (error) {
132
+ console.warn(`Could not get refresh token from server cookies:`, error);
133
+ return null;
134
+ }
135
+ }
136
+ async setRefreshToken(token) {
137
+ try {
138
+ this.cookieStore.set(this.refreshTokenKey, token, {
139
+ maxAge: this.options.maxAge,
140
+ path: this.options.path,
141
+ domain: this.options.domain,
142
+ secure: this.options.secure,
143
+ sameSite: this.options.sameSite?.toLowerCase(),
144
+ httpOnly: false
145
+ // Allow client-side access for SDK flexibility
146
+ });
147
+ } catch (error) {
148
+ console.warn(`Could not set refresh token on server:`, error);
149
+ }
150
+ }
151
+ async clearTokens() {
152
+ try {
153
+ this.cookieStore.delete(this.accessTokenKey);
154
+ this.cookieStore.delete(this.refreshTokenKey);
155
+ } catch (error) {
156
+ console.warn(`Could not clear tokens on server:`, error);
157
+ }
158
+ }
159
+ };
160
+
161
+ // src/build-token-cache.ts
162
+ var store = /* @__PURE__ */ new Map();
163
+ function isExpired(token) {
164
+ if (!token) return true;
165
+ if (!token.expiresAt) return false;
166
+ return Date.now() > token.expiresAt - 3e4;
167
+ }
168
+ function getCachedToken(key) {
169
+ const token = store.get(key);
170
+ return isExpired(token) ? null : token;
171
+ }
172
+ function setCachedToken(key, token) {
173
+ const expiresAt = token.ttlSeconds != null ? Date.now() + token.ttlSeconds * 1e3 : void 0;
174
+ store.set(key, {
175
+ accessToken: token.accessToken,
176
+ refreshToken: token.refreshToken ?? null,
177
+ expiresAt
178
+ });
179
+ }
180
+ function clearCachedToken(key) {
181
+ store.delete(key);
182
+ }
183
+
184
+ // src/build-caching-memory-storage.ts
185
+ var DEFAULT_TTL_SECONDS = 5 * 60;
186
+ var BuildCachingMemoryTokenStorage = class {
187
+ constructor(cacheKey, ttlSeconds = DEFAULT_TTL_SECONDS) {
188
+ this.cacheKey = cacheKey;
189
+ this.ttlSeconds = ttlSeconds;
190
+ this.access = null;
191
+ this.refresh = null;
192
+ }
193
+ async getAccessToken() {
194
+ if (this.access) {
195
+ console.log(`\u{1F535} [BuildCache] Using instance token for key: ${this.cacheKey}`);
196
+ return this.access;
197
+ }
198
+ const cached = getCachedToken(this.cacheKey);
199
+ if (cached?.accessToken) {
200
+ console.log(`\u{1F7E2} [BuildCache] Using cached token for key: ${this.cacheKey}`);
201
+ this.access = cached.accessToken;
202
+ this.refresh = cached.refreshToken ?? null;
203
+ return this.access;
204
+ }
205
+ console.log(`\u{1F7E1} [BuildCache] No cached token found for key: ${this.cacheKey}`);
206
+ return null;
207
+ }
208
+ async setAccessToken(token) {
209
+ console.log(`\u{1F7E0} [BuildCache] Caching new access token for key: ${this.cacheKey}`);
210
+ this.access = token;
211
+ setCachedToken(this.cacheKey, {
212
+ accessToken: token,
213
+ refreshToken: this.refresh,
214
+ ttlSeconds: this.ttlSeconds
215
+ });
216
+ }
217
+ async getRefreshToken() {
218
+ return this.refresh;
219
+ }
220
+ async setRefreshToken(token) {
221
+ this.refresh = token;
222
+ setCachedToken(this.cacheKey, {
223
+ accessToken: this.access ?? "",
224
+ refreshToken: token,
225
+ ttlSeconds: this.ttlSeconds
226
+ });
227
+ }
228
+ async clearTokens() {
229
+ this.access = null;
230
+ this.refresh = null;
231
+ clearCachedToken(this.cacheKey);
232
+ }
233
+ };
234
+
235
+ // src/sdk-manager.ts
236
+ function getConfig(requestConfig) {
237
+ const envStoreId = process.env.NEXT_PUBLIC_STORE_ID;
238
+ const envApiKey = process.env.NEXT_PUBLIC_API_KEY;
239
+ const envEnvironment = process.env.NEXT_PUBLIC_ENVIRONMENT;
240
+ const envBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
241
+ const envTimeout = process.env.NEXT_PUBLIC_API_TIMEOUT ? parseInt(process.env.NEXT_PUBLIC_API_TIMEOUT, 10) : void 0;
242
+ const envDebug = process.env.NEXT_PUBLIC_DEBUG_MODE === "true";
243
+ const envDefaultHeaders = {};
244
+ if (process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_GROUP_ID) {
245
+ envDefaultHeaders.customer_group_id = process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_GROUP_ID;
246
+ }
247
+ const storeId = requestConfig?.storeId || globalStorefrontConfig?.storeId || envStoreId;
248
+ const apiKey = requestConfig?.apiKey || globalStorefrontConfig?.apiKey || envApiKey;
249
+ const environment = requestConfig?.environment || globalStorefrontConfig?.environment || (envEnvironment === "production" ? Environment.Production : Environment.Staging);
250
+ const baseUrl = requestConfig?.baseUrl || globalStorefrontConfig?.baseUrl || envBaseUrl;
251
+ const timeout = requestConfig?.timeout || globalStorefrontConfig?.timeout || envTimeout;
252
+ const debug = requestConfig?.debug !== void 0 ? requestConfig.debug : globalStorefrontConfig?.debug !== void 0 ? globalStorefrontConfig.debug : envDebug;
253
+ const defaultHeaders = {
254
+ ...envDefaultHeaders,
255
+ ...globalStorefrontConfig?.defaultHeaders,
256
+ ...requestConfig?.defaultHeaders
257
+ };
258
+ if (!storeId || !apiKey) {
259
+ throw new Error(
260
+ `StorefrontSDK configuration missing! Please set the following environment variables:
261
+
262
+ NEXT_PUBLIC_STORE_ID=your-store-id
263
+ NEXT_PUBLIC_API_KEY=your-api-key
264
+ NEXT_PUBLIC_ENVIRONMENT=staging (or production)
265
+
266
+ These variables are required for both client and server contexts to work.
267
+ Alternatively, you can pass them via the storefront() function config parameter.`
268
+ );
269
+ }
270
+ const config = {
271
+ storeId,
272
+ apiKey,
273
+ environment
274
+ };
275
+ if (baseUrl) config.baseUrl = baseUrl;
276
+ if (timeout) config.timeout = timeout;
277
+ if (debug) config.debug = debug;
278
+ const logger = requestConfig?.logger || globalStorefrontConfig?.logger;
279
+ const accessToken = requestConfig?.accessToken || globalStorefrontConfig?.accessToken;
280
+ const refreshToken = requestConfig?.refreshToken || globalStorefrontConfig?.refreshToken;
281
+ const onTokensUpdated = requestConfig?.onTokensUpdated || globalStorefrontConfig?.onTokensUpdated;
282
+ const onTokensCleared = requestConfig?.onTokensCleared || globalStorefrontConfig?.onTokensCleared;
283
+ const tokenStorageOptions = requestConfig?.tokenStorageOptions || globalStorefrontConfig?.tokenStorageOptions;
284
+ if (logger) config.logger = logger;
285
+ if (accessToken) config.accessToken = accessToken;
286
+ if (refreshToken) config.refreshToken = refreshToken;
287
+ if (onTokensUpdated) config.onTokensUpdated = onTokensUpdated;
288
+ if (onTokensCleared) config.onTokensCleared = onTokensCleared;
289
+ if (Object.keys(defaultHeaders).length > 0) config.defaultHeaders = defaultHeaders;
290
+ if (tokenStorageOptions) config.tokenStorageOptions = tokenStorageOptions;
291
+ return config;
292
+ }
293
+ var globalStorefrontConfig = null;
294
+ var clientSDK = null;
295
+ function hasRequestContext() {
296
+ try {
297
+ const { cookies } = __require("next/headers");
298
+ cookies();
299
+ return true;
300
+ } catch {
301
+ return false;
302
+ }
303
+ }
304
+ function createTokenStorage(cookieStore, options, config) {
305
+ if (typeof window !== "undefined") {
306
+ return new ClientTokenStorage(options);
307
+ }
308
+ if (cookieStore) {
309
+ return new ServerTokenStorage(cookieStore, options);
310
+ }
311
+ const shouldCache = process.env.NEXT_BUILD_CACHE_TOKENS === "true";
312
+ if (shouldCache && config) {
313
+ const cacheKey = `${config.storeId}:${config.environment || "production"}`;
314
+ console.log(`\u{1F680} [BuildCache] Using BuildCachingMemoryTokenStorage with key: ${cacheKey}`);
315
+ return new BuildCachingMemoryTokenStorage(cacheKey);
316
+ }
317
+ console.log(`\u{1F504} [Build] Using standard MemoryTokenStorage (caching disabled)`);
318
+ return new MemoryTokenStorage();
319
+ }
320
+ var getServerSDKCached = cache((cookieStore, requestConfig) => {
321
+ const config = getConfig(requestConfig);
322
+ return new StorefrontSDK({
323
+ ...config,
324
+ tokenStorage: createTokenStorage(
325
+ cookieStore,
326
+ config.tokenStorageOptions,
327
+ config
328
+ )
329
+ });
330
+ });
331
+ var buildTimeSDK = null;
332
+ function getBuildTimeSDK(requestConfig) {
333
+ const config = getConfig(requestConfig);
334
+ if (requestConfig) {
335
+ return new StorefrontSDK({
336
+ ...config,
337
+ tokenStorage: createTokenStorage(
338
+ void 0,
339
+ config.tokenStorageOptions,
340
+ config
341
+ )
342
+ });
343
+ }
344
+ if (!buildTimeSDK) {
345
+ buildTimeSDK = new StorefrontSDK({
346
+ ...config,
347
+ tokenStorage: createTokenStorage(
348
+ void 0,
349
+ config.tokenStorageOptions,
350
+ config
351
+ )
352
+ });
353
+ }
354
+ return buildTimeSDK;
355
+ }
356
+ function getStorefrontSDK(cookieStore, requestConfig) {
357
+ if (typeof window !== "undefined") {
358
+ if (cookieStore) {
359
+ console.warn(
360
+ "Cookie store passed in client environment - this will be ignored"
361
+ );
362
+ }
363
+ const config = getConfig(requestConfig);
364
+ if (requestConfig) {
365
+ return new StorefrontSDK({
366
+ ...config,
367
+ tokenStorage: createTokenStorage(
368
+ void 0,
369
+ config.tokenStorageOptions,
370
+ config
371
+ )
372
+ });
373
+ }
374
+ if (!clientSDK) {
375
+ clientSDK = new StorefrontSDK({
376
+ ...config,
377
+ tokenStorage: createTokenStorage(
378
+ void 0,
379
+ config.tokenStorageOptions,
380
+ config
381
+ )
382
+ });
383
+ }
384
+ return clientSDK;
385
+ }
386
+ if (cookieStore) {
387
+ return getServerSDKCached(cookieStore, requestConfig);
388
+ }
389
+ if (hasRequestContext()) {
390
+ let autoDetectMessage = "";
391
+ try {
392
+ __require.resolve("next/headers");
393
+ autoDetectMessage = `
394
+
395
+ \u{1F50D} Auto-detection attempted but failed. You may be in:
396
+ - Server Action (use: const sdk = getStorefrontSDK(await cookies()))
397
+ - API Route (use: const sdk = getStorefrontSDK(cookies()))
398
+ - Server Component in App Router (use: const sdk = getStorefrontSDK(cookies()))
399
+ `;
400
+ } catch {
401
+ autoDetectMessage = `
402
+
403
+ \u{1F4A1} Make sure you have Next.js installed and are in a server context.
404
+ `;
405
+ }
406
+ throw new Error(
407
+ `
408
+ \u{1F6A8} Server Environment Detected!
409
+
410
+ You're calling getStorefrontSDK() on the server without cookies.
411
+ Please pass the Next.js cookie store:
412
+
413
+ \u2705 Correct usage:
414
+ import { cookies } from 'next/headers';
415
+
416
+ // Server Actions & Route Handlers
417
+ const sdk = getStorefrontSDK(await cookies());
418
+
419
+ // API Routes & Server Components (App Router)
420
+ const sdk = getStorefrontSDK(cookies());
421
+
422
+ \u274C Your current usage:
423
+ const sdk = getStorefrontSDK(); // Missing cookies!
424
+ ${autoDetectMessage}
425
+ This is required for server-side token access.
426
+ `.trim()
427
+ );
428
+ }
429
+ return getBuildTimeSDK(requestConfig);
430
+ }
431
+
432
+ // src/storefront.ts
433
+ function storefront(cookieStoreOrConfig, config) {
434
+ let cookieStore;
435
+ let requestConfig;
436
+ if (cookieStoreOrConfig && typeof cookieStoreOrConfig === "object" && !("get" in cookieStoreOrConfig)) {
437
+ requestConfig = cookieStoreOrConfig;
438
+ } else {
439
+ cookieStore = cookieStoreOrConfig;
440
+ requestConfig = config;
441
+ }
442
+ return getStorefrontSDK(cookieStore, requestConfig);
443
+ }
444
+ var storefront_default = storefront;
445
+ export {
446
+ storefront_default as default,
447
+ storefront
448
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercengine/storefront-sdk-nextjs",
3
- "version": "0.1.0-alpha.0",
3
+ "version": "1.0.0-alpha.2",
4
4
  "description": "Next.js wrapper for the Commerce Engine Storefront SDK",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -10,6 +10,16 @@
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js",
12
12
  "require": "./dist/index.cjs"
13
+ },
14
+ "./server": {
15
+ "types": "./dist/server.d.ts",
16
+ "import": "./dist/server.js",
17
+ "require": "./dist/server.cjs"
18
+ },
19
+ "./client": {
20
+ "types": "./dist/client.d.ts",
21
+ "import": "./dist/client.js",
22
+ "require": "./dist/client.cjs"
13
23
  }
14
24
  },
15
25
  "files": [
@@ -27,19 +37,19 @@
27
37
  "author": "Commerce Engine",
28
38
  "license": "All rights reserved",
29
39
  "peerDependencies": {
30
- "next": ">=13.0.0",
31
- "react": ">=18.0.0",
32
- "react-dom": ">=18.0.0"
40
+ "next": ">=15.0.0",
41
+ "react": ">=19.0.0",
42
+ "react-dom": ">=19.0.0"
33
43
  },
34
44
  "dependencies": {
35
45
  "@commercengine/storefront-sdk": "0.8.0"
36
46
  },
37
47
  "devDependencies": {
38
48
  "@types/node": "^24.3.0",
39
- "@types/react": "^18.0.0",
40
- "next": ">=13.0.0",
41
- "react": ">=18.0.0",
42
- "react-dom": ">=18.0.0",
49
+ "@types/react": "^19.0.0",
50
+ "next": ">=15.0.0",
51
+ "react": ">=19.0.0",
52
+ "react-dom": ">=19.0.0",
43
53
  "rimraf": "^6.0.1",
44
54
  "tsup": "^8.5.0",
45
55
  "typescript": "^5.9.2"