@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.
package/dist/client.js ADDED
@@ -0,0 +1,378 @@
1
+ "use client";
2
+
3
+ // src/sdk-manager.ts
4
+ import { cache } from "react";
5
+ import {
6
+ StorefrontSDK,
7
+ MemoryTokenStorage,
8
+ Environment
9
+ } from "@commercengine/storefront-sdk";
10
+
11
+ // src/token-storage.ts
12
+ var ClientTokenStorage = class {
13
+ constructor(options = {}) {
14
+ const prefix = options.prefix || "ce_";
15
+ this.accessTokenKey = `${prefix}access_token`;
16
+ this.refreshTokenKey = `${prefix}refresh_token`;
17
+ this.options = {
18
+ maxAge: options.maxAge || 30 * 24 * 60 * 60,
19
+ // 30 days default
20
+ path: options.path || "/",
21
+ domain: options.domain,
22
+ secure: options.secure ?? (typeof window !== "undefined" && window.location?.protocol === "https:"),
23
+ sameSite: options.sameSite || "Lax"
24
+ };
25
+ }
26
+ async getAccessToken() {
27
+ return this.getCookie(this.accessTokenKey);
28
+ }
29
+ async setAccessToken(token) {
30
+ this.setCookie(this.accessTokenKey, token);
31
+ }
32
+ async getRefreshToken() {
33
+ return this.getCookie(this.refreshTokenKey);
34
+ }
35
+ async setRefreshToken(token) {
36
+ this.setCookie(this.refreshTokenKey, token);
37
+ }
38
+ async clearTokens() {
39
+ this.deleteCookie(this.accessTokenKey);
40
+ this.deleteCookie(this.refreshTokenKey);
41
+ }
42
+ getCookie(name) {
43
+ if (typeof document === "undefined") return null;
44
+ const value = `; ${document.cookie}`;
45
+ const parts = value.split(`; ${name}=`);
46
+ if (parts.length === 2) {
47
+ const cookieValue = parts.pop()?.split(";").shift();
48
+ return cookieValue ? decodeURIComponent(cookieValue) : null;
49
+ }
50
+ return null;
51
+ }
52
+ setCookie(name, value) {
53
+ if (typeof document === "undefined") return;
54
+ const encodedValue = encodeURIComponent(value);
55
+ let cookieString = `${name}=${encodedValue}`;
56
+ if (this.options.maxAge) {
57
+ cookieString += `; Max-Age=${this.options.maxAge}`;
58
+ }
59
+ if (this.options.path) {
60
+ cookieString += `; Path=${this.options.path}`;
61
+ }
62
+ if (this.options.domain) {
63
+ cookieString += `; Domain=${this.options.domain}`;
64
+ }
65
+ if (this.options.secure) {
66
+ cookieString += `; Secure`;
67
+ }
68
+ if (this.options.sameSite) {
69
+ cookieString += `; SameSite=${this.options.sameSite}`;
70
+ }
71
+ document.cookie = cookieString;
72
+ }
73
+ deleteCookie(name) {
74
+ if (typeof document === "undefined") return;
75
+ let cookieString = `${name}=; Max-Age=0`;
76
+ if (this.options.path) {
77
+ cookieString += `; Path=${this.options.path}`;
78
+ }
79
+ if (this.options.domain) {
80
+ cookieString += `; Domain=${this.options.domain}`;
81
+ }
82
+ document.cookie = cookieString;
83
+ }
84
+ };
85
+ var ServerTokenStorage = class {
86
+ constructor(cookieStore, options = {}) {
87
+ const prefix = options.prefix || "ce_";
88
+ this.accessTokenKey = `${prefix}access_token`;
89
+ this.refreshTokenKey = `${prefix}refresh_token`;
90
+ this.cookieStore = cookieStore;
91
+ this.options = {
92
+ maxAge: options.maxAge || 30 * 24 * 60 * 60,
93
+ // 30 days default
94
+ path: options.path || "/",
95
+ domain: options.domain,
96
+ secure: options.secure ?? process.env.NODE_ENV === "production",
97
+ sameSite: options.sameSite || "Lax"
98
+ };
99
+ }
100
+ async getAccessToken() {
101
+ try {
102
+ return this.cookieStore.get(this.accessTokenKey)?.value || null;
103
+ } catch (error) {
104
+ console.warn(`Could not get access token from server cookies:`, error);
105
+ return null;
106
+ }
107
+ }
108
+ async setAccessToken(token) {
109
+ try {
110
+ this.cookieStore.set(this.accessTokenKey, token, {
111
+ maxAge: this.options.maxAge,
112
+ path: this.options.path,
113
+ domain: this.options.domain,
114
+ secure: this.options.secure,
115
+ sameSite: this.options.sameSite?.toLowerCase(),
116
+ httpOnly: false
117
+ // Allow client-side access for SDK flexibility
118
+ });
119
+ } catch (error) {
120
+ console.warn(`Could not set access token on server:`, error);
121
+ }
122
+ }
123
+ async getRefreshToken() {
124
+ try {
125
+ return this.cookieStore.get(this.refreshTokenKey)?.value || null;
126
+ } catch (error) {
127
+ console.warn(`Could not get refresh token from server cookies:`, error);
128
+ return null;
129
+ }
130
+ }
131
+ async setRefreshToken(token) {
132
+ try {
133
+ this.cookieStore.set(this.refreshTokenKey, token, {
134
+ maxAge: this.options.maxAge,
135
+ path: this.options.path,
136
+ domain: this.options.domain,
137
+ secure: this.options.secure,
138
+ sameSite: this.options.sameSite?.toLowerCase(),
139
+ httpOnly: false
140
+ // Allow client-side access for SDK flexibility
141
+ });
142
+ } catch (error) {
143
+ console.warn(`Could not set refresh token on server:`, error);
144
+ }
145
+ }
146
+ async clearTokens() {
147
+ try {
148
+ this.cookieStore.delete(this.accessTokenKey);
149
+ this.cookieStore.delete(this.refreshTokenKey);
150
+ } catch (error) {
151
+ console.warn(`Could not clear tokens on server:`, error);
152
+ }
153
+ }
154
+ };
155
+
156
+ // src/build-token-cache.ts
157
+ var store = /* @__PURE__ */ new Map();
158
+ function isExpired(token) {
159
+ if (!token) return true;
160
+ if (!token.expiresAt) return false;
161
+ return Date.now() > token.expiresAt - 3e4;
162
+ }
163
+ function getCachedToken(key) {
164
+ const token = store.get(key);
165
+ return isExpired(token) ? null : token;
166
+ }
167
+ function setCachedToken(key, token) {
168
+ const expiresAt = token.ttlSeconds != null ? Date.now() + token.ttlSeconds * 1e3 : void 0;
169
+ store.set(key, {
170
+ accessToken: token.accessToken,
171
+ refreshToken: token.refreshToken ?? null,
172
+ expiresAt
173
+ });
174
+ }
175
+ function clearCachedToken(key) {
176
+ store.delete(key);
177
+ }
178
+
179
+ // src/build-caching-memory-storage.ts
180
+ var DEFAULT_TTL_SECONDS = 5 * 60;
181
+ var BuildCachingMemoryTokenStorage = class {
182
+ constructor(cacheKey, ttlSeconds = DEFAULT_TTL_SECONDS) {
183
+ this.cacheKey = cacheKey;
184
+ this.ttlSeconds = ttlSeconds;
185
+ this.access = null;
186
+ this.refresh = null;
187
+ }
188
+ async getAccessToken() {
189
+ if (this.access) {
190
+ return this.access;
191
+ }
192
+ const cached = getCachedToken(this.cacheKey);
193
+ if (cached?.accessToken) {
194
+ this.access = cached.accessToken;
195
+ this.refresh = cached.refreshToken ?? null;
196
+ return this.access;
197
+ }
198
+ return null;
199
+ }
200
+ async setAccessToken(token) {
201
+ this.access = token;
202
+ setCachedToken(this.cacheKey, {
203
+ accessToken: token,
204
+ refreshToken: this.refresh,
205
+ ttlSeconds: this.ttlSeconds
206
+ });
207
+ }
208
+ async getRefreshToken() {
209
+ return this.refresh;
210
+ }
211
+ async setRefreshToken(token) {
212
+ this.refresh = token;
213
+ setCachedToken(this.cacheKey, {
214
+ accessToken: this.access ?? "",
215
+ refreshToken: token,
216
+ ttlSeconds: this.ttlSeconds
217
+ });
218
+ }
219
+ async clearTokens() {
220
+ this.access = null;
221
+ this.refresh = null;
222
+ clearCachedToken(this.cacheKey);
223
+ }
224
+ };
225
+
226
+ // src/sdk-manager.ts
227
+ function getConfig() {
228
+ const envStoreId = process.env.NEXT_PUBLIC_STORE_ID;
229
+ const envApiKey = process.env.NEXT_PUBLIC_API_KEY;
230
+ const envEnvironment = process.env.NEXT_PUBLIC_ENVIRONMENT;
231
+ const envBaseUrl = process.env.NEXT_PUBLIC_API_BASE_URL;
232
+ const envTimeout = process.env.NEXT_PUBLIC_API_TIMEOUT ? parseInt(process.env.NEXT_PUBLIC_API_TIMEOUT, 10) : void 0;
233
+ const envDebug = process.env.NEXT_PUBLIC_DEBUG_MODE === "true";
234
+ const envDefaultHeaders = {};
235
+ if (process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_GROUP_ID) {
236
+ envDefaultHeaders.customer_group_id = process.env.NEXT_PUBLIC_DEFAULT_CUSTOMER_GROUP_ID;
237
+ }
238
+ const storeId = globalStorefrontConfig?.storeId || envStoreId;
239
+ const apiKey = globalStorefrontConfig?.apiKey || envApiKey;
240
+ const environment = globalStorefrontConfig?.environment || (envEnvironment === "production" ? Environment.Production : Environment.Staging);
241
+ const baseUrl = globalStorefrontConfig?.baseUrl || envBaseUrl;
242
+ const timeout = globalStorefrontConfig?.timeout || envTimeout;
243
+ const debug = globalStorefrontConfig?.debug !== void 0 ? globalStorefrontConfig.debug : envDebug;
244
+ const defaultHeaders = {
245
+ ...envDefaultHeaders,
246
+ ...globalStorefrontConfig?.defaultHeaders
247
+ };
248
+ if (!storeId || !apiKey) {
249
+ throw new Error(
250
+ `StorefrontSDK configuration missing! Please set the following environment variables:
251
+
252
+ NEXT_PUBLIC_STORE_ID=your-store-id
253
+ NEXT_PUBLIC_API_KEY=your-api-key
254
+ NEXT_PUBLIC_ENVIRONMENT=staging (or production)
255
+
256
+ These variables are required for both client and server contexts to work.`
257
+ );
258
+ }
259
+ const config = {
260
+ storeId,
261
+ apiKey,
262
+ environment
263
+ };
264
+ if (baseUrl) config.baseUrl = baseUrl;
265
+ if (timeout) config.timeout = timeout;
266
+ if (debug) config.debug = debug;
267
+ const logger = globalStorefrontConfig?.logger;
268
+ const accessToken = globalStorefrontConfig?.accessToken;
269
+ const refreshToken = globalStorefrontConfig?.refreshToken;
270
+ const onTokensUpdated = globalStorefrontConfig?.onTokensUpdated;
271
+ const onTokensCleared = globalStorefrontConfig?.onTokensCleared;
272
+ const tokenStorageOptions = globalStorefrontConfig?.tokenStorageOptions;
273
+ if (logger) config.logger = logger;
274
+ if (accessToken) config.accessToken = accessToken;
275
+ if (refreshToken) config.refreshToken = refreshToken;
276
+ if (onTokensUpdated) config.onTokensUpdated = onTokensUpdated;
277
+ if (onTokensCleared) config.onTokensCleared = onTokensCleared;
278
+ if (Object.keys(defaultHeaders).length > 0) config.defaultHeaders = defaultHeaders;
279
+ if (tokenStorageOptions) config.tokenStorageOptions = tokenStorageOptions;
280
+ return config;
281
+ }
282
+ var globalStorefrontConfig = null;
283
+ var clientSDK = null;
284
+ function createTokenStorage(cookieStore, options, config) {
285
+ if (typeof window !== "undefined") {
286
+ return new ClientTokenStorage(options);
287
+ }
288
+ if (cookieStore) {
289
+ return new ServerTokenStorage(cookieStore, options);
290
+ }
291
+ const shouldCache = process.env.NEXT_BUILD_CACHE_TOKENS === "true";
292
+ if (shouldCache && config) {
293
+ const cacheKey = `${config.storeId}:${config.environment || "production"}`;
294
+ return new BuildCachingMemoryTokenStorage(cacheKey);
295
+ }
296
+ return new MemoryTokenStorage();
297
+ }
298
+ var getServerSDKCached = cache((cookieStore) => {
299
+ const config = getConfig();
300
+ return new StorefrontSDK({
301
+ ...config,
302
+ tokenStorage: createTokenStorage(
303
+ cookieStore,
304
+ config.tokenStorageOptions,
305
+ config
306
+ )
307
+ });
308
+ });
309
+ var buildTimeSDK = null;
310
+ function getBuildTimeSDK() {
311
+ const config = getConfig();
312
+ if (!buildTimeSDK) {
313
+ buildTimeSDK = new StorefrontSDK({
314
+ ...config,
315
+ tokenStorage: createTokenStorage(
316
+ void 0,
317
+ config.tokenStorageOptions,
318
+ config
319
+ )
320
+ });
321
+ }
322
+ return buildTimeSDK;
323
+ }
324
+ function getStorefrontSDK(cookieStore) {
325
+ if (typeof window !== "undefined") {
326
+ if (cookieStore) {
327
+ console.warn(
328
+ "Cookie store passed in client environment - this will be ignored"
329
+ );
330
+ }
331
+ const config = getConfig();
332
+ if (!clientSDK) {
333
+ clientSDK = new StorefrontSDK({
334
+ ...config,
335
+ tokenStorage: createTokenStorage(
336
+ void 0,
337
+ config.tokenStorageOptions,
338
+ config
339
+ )
340
+ });
341
+ }
342
+ return clientSDK;
343
+ }
344
+ if (cookieStore) {
345
+ return getServerSDKCached(cookieStore);
346
+ }
347
+ return getBuildTimeSDK();
348
+ }
349
+ function initializeStorefrontSDK() {
350
+ clientSDK = null;
351
+ buildTimeSDK = null;
352
+ }
353
+
354
+ // src/init-client.ts
355
+ import { useEffect } from "react";
356
+ async function bootstrapTokens() {
357
+ const sdk = getStorefrontSDK();
358
+ const accessToken = await sdk.getAccessToken();
359
+ if (!accessToken) {
360
+ await sdk.auth.getAnonymousToken();
361
+ }
362
+ }
363
+ function StorefrontSDKInitializer({ runtimeConfig } = {}) {
364
+ useEffect(() => {
365
+ initializeStorefrontSDK();
366
+ bootstrapTokens().catch(console.error);
367
+ }, [runtimeConfig]);
368
+ return null;
369
+ }
370
+
371
+ // src/client.ts
372
+ export * from "@commercengine/storefront-sdk";
373
+ export {
374
+ ClientTokenStorage,
375
+ StorefrontSDKInitializer,
376
+ getStorefrontSDK,
377
+ initializeStorefrontSDK
378
+ };