@commercengine/storefront-sdk 0.3.6 → 0.3.8

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/index.d.ts CHANGED
@@ -6,7 +6,7 @@ import { OrderClient } from "./lib/order";
6
6
  import { ShippingClient } from "./lib/shipping";
7
7
  import { HelpersClient } from "./lib/helper";
8
8
  import { CustomerClient } from "./lib/customer";
9
- import { TokenStorage, MemoryTokenStorage, BrowserTokenStorage } from "./lib/middleware";
9
+ import { TokenStorage, MemoryTokenStorage, BrowserTokenStorage, CookieTokenStorage } from "./lib/middleware";
10
10
  import { type UserInfo } from "./lib/jwt-utils";
11
11
  /**
12
12
  * SDK initialization options
@@ -168,9 +168,10 @@ export declare class StorefrontSDK {
168
168
  getCustomerGroupId(): Promise<string | null>;
169
169
  }
170
170
  export default StorefrontSDK;
171
- export { StorefrontAPIClient, AuthClient, CartClient, CatalogClient, CustomerClient, HelpersClient, ShippingClient, OrderClient };
171
+ export { StorefrontAPIClient, AuthClient, CartClient, CatalogClient, CustomerClient, HelpersClient, ShippingClient, OrderClient, };
172
172
  export { Environment };
173
- export { TokenStorage, MemoryTokenStorage, BrowserTokenStorage };
173
+ export { TokenStorage, MemoryTokenStorage, BrowserTokenStorage, CookieTokenStorage, };
174
+ export type { CookieTokenStorageOptions } from "./lib/middleware";
174
175
  export type { UserInfo } from "./lib/jwt-utils";
175
176
  export type { components, operations, paths } from "./types/storefront";
176
177
  export type * from "./types/storefront-api-types";
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { StorefrontAPIClient, Environment, } from "./lib/client";
1
+ import { StorefrontAPIClient, Environment } from "./lib/client";
2
2
  import { CatalogClient } from "./lib/catalog";
3
3
  import { CartClient } from "./lib/cart";
4
4
  import { AuthClient } from "./lib/auth";
@@ -6,7 +6,7 @@ import { OrderClient } from "./lib/order";
6
6
  import { ShippingClient } from "./lib/shipping";
7
7
  import { HelpersClient } from "./lib/helper";
8
8
  import { CustomerClient } from "./lib/customer";
9
- import { MemoryTokenStorage, BrowserTokenStorage, } from "./lib/middleware";
9
+ import { MemoryTokenStorage, BrowserTokenStorage, CookieTokenStorage, } from "./lib/middleware";
10
10
  import { extractUserInfoFromToken, getUserIdFromToken, isUserLoggedIn, isUserAnonymous, } from "./lib/jwt-utils";
11
11
  /**
12
12
  * Main SDK class for the Storefront API
@@ -132,7 +132,9 @@ export class StorefrontSDK {
132
132
  * Get the current access token if using token storage
133
133
  */
134
134
  async getAccessToken() {
135
- return await this.auth.getAuthorizationHeader().then(header => header.startsWith('Bearer ') ? header.substring(7) : null);
135
+ return await this.auth
136
+ .getAuthorizationHeader()
137
+ .then((header) => header.startsWith("Bearer ") ? header.substring(7) : null);
136
138
  }
137
139
  /**
138
140
  * Get user information from the current access token
@@ -200,8 +202,8 @@ export class StorefrontSDK {
200
202
  // Export the main SDK class
201
203
  export default StorefrontSDK;
202
204
  // Export individual clients for advanced usage
203
- export { StorefrontAPIClient, AuthClient, CartClient, CatalogClient, CustomerClient, HelpersClient, ShippingClient, OrderClient };
205
+ export { StorefrontAPIClient, AuthClient, CartClient, CatalogClient, CustomerClient, HelpersClient, ShippingClient, OrderClient, };
204
206
  // Export environment enum
205
207
  export { Environment };
206
208
  // Export token storage types
207
- export { MemoryTokenStorage, BrowserTokenStorage };
209
+ export { MemoryTokenStorage, BrowserTokenStorage, CookieTokenStorage, };
@@ -22,6 +22,7 @@ export declare class StorefrontAPIClient {
22
22
  protected client: ReturnType<typeof createClient<paths>>;
23
23
  protected config: StorefrontSDKOptions;
24
24
  private readonly baseUrl;
25
+ private initializationPromise;
25
26
  /**
26
27
  * Create a new StorefrontAPIClient
27
28
  *
@@ -97,4 +98,8 @@ export declare class StorefrontAPIClient {
97
98
  error?: ApiErrorResponse;
98
99
  response: Response;
99
100
  }>): Promise<ApiResult<T>>;
101
+ /**
102
+ * Initialize tokens in storage (private helper method)
103
+ */
104
+ private initializeTokens;
100
105
  }
@@ -22,6 +22,7 @@ export class StorefrontAPIClient {
22
22
  client;
23
23
  config;
24
24
  baseUrl;
25
+ initializationPromise = null;
25
26
  /**
26
27
  * Create a new StorefrontAPIClient
27
28
  *
@@ -46,17 +47,9 @@ export class StorefrontAPIClient {
46
47
  this.client.use(authMiddleware);
47
48
  // If initial tokens were provided, store them in tokenStorage
48
49
  if (this.config.accessToken) {
49
- this.config.tokenStorage.setAccessToken(this.config.accessToken).catch(error => {
50
- console.warn('Failed to set initial access token in storage:', error);
51
- });
52
- // Clear the manual token since we're using storage
50
+ this.initializationPromise = this.initializeTokens(this.config.accessToken, this.config.refreshToken);
51
+ // Clear the manual tokens since we're using storage
53
52
  this.config.accessToken = undefined;
54
- }
55
- if (this.config.refreshToken) {
56
- this.config.tokenStorage.setRefreshToken(this.config.refreshToken).catch(error => {
57
- console.warn('Failed to set initial refresh token in storage:', error);
58
- });
59
- // Clear the manual refresh token since we're using storage
60
53
  this.config.refreshToken = undefined;
61
54
  }
62
55
  }
@@ -100,14 +93,14 @@ export class StorefrontAPIClient {
100
93
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
101
94
  // Merge with existing signal if present
102
95
  if (request.signal) {
103
- request.signal.addEventListener('abort', () => controller.abort());
96
+ request.signal.addEventListener("abort", () => controller.abort());
104
97
  }
105
98
  // Create new request with timeout signal
106
99
  const newRequest = new Request(request, {
107
100
  signal: controller.signal,
108
101
  });
109
102
  // Clean up timeout when request completes
110
- controller.signal.addEventListener('abort', () => clearTimeout(timeoutId));
103
+ controller.signal.addEventListener("abort", () => clearTimeout(timeoutId));
111
104
  return newRequest;
112
105
  },
113
106
  });
@@ -149,6 +142,10 @@ export class StorefrontAPIClient {
149
142
  * @returns The Authorization header value or empty string if no token is set
150
143
  */
151
144
  async getAuthorizationHeader() {
145
+ // Wait for initialization to complete if using token storage
146
+ if (this.config.tokenStorage && this.initializationPromise) {
147
+ await this.initializationPromise;
148
+ }
152
149
  if (this.config.tokenStorage) {
153
150
  const token = await this.config.tokenStorage.getAccessToken();
154
151
  return token ? `Bearer ${token}` : "";
@@ -236,11 +233,27 @@ export class StorefrontAPIClient {
236
233
  data: null,
237
234
  error: {
238
235
  success: false,
239
- code: 'NETWORK_ERROR',
240
- message: 'Network error occurred',
236
+ code: "NETWORK_ERROR",
237
+ message: "Network error occurred",
241
238
  error: err,
242
239
  },
243
240
  };
244
241
  }
245
242
  }
243
+ /**
244
+ * Initialize tokens in storage (private helper method)
245
+ */
246
+ async initializeTokens(accessToken, refreshToken) {
247
+ try {
248
+ if (this.config.tokenStorage) {
249
+ await this.config.tokenStorage.setAccessToken(accessToken);
250
+ if (refreshToken) {
251
+ await this.config.tokenStorage.setRefreshToken(refreshToken);
252
+ }
253
+ }
254
+ }
255
+ catch (error) {
256
+ console.warn("Failed to initialize tokens in storage:", error);
257
+ }
258
+ }
246
259
  }
@@ -34,6 +34,52 @@ export declare class BrowserTokenStorage implements TokenStorage {
34
34
  setRefreshToken(token: string): Promise<void>;
35
35
  clearTokens(): Promise<void>;
36
36
  }
37
+ /**
38
+ * Cookie-based token storage implementation
39
+ */
40
+ export declare class CookieTokenStorage implements TokenStorage {
41
+ private accessTokenKey;
42
+ private refreshTokenKey;
43
+ private options;
44
+ constructor(options?: CookieTokenStorageOptions);
45
+ getAccessToken(): Promise<string | null>;
46
+ setAccessToken(token: string): Promise<void>;
47
+ getRefreshToken(): Promise<string | null>;
48
+ setRefreshToken(token: string): Promise<void>;
49
+ clearTokens(): Promise<void>;
50
+ private getCookie;
51
+ private setCookie;
52
+ private deleteCookie;
53
+ }
54
+ /**
55
+ * Configuration options for CookieTokenStorage
56
+ */
57
+ export interface CookieTokenStorageOptions {
58
+ /**
59
+ * Prefix for cookie names (default: "storefront_")
60
+ */
61
+ prefix?: string;
62
+ /**
63
+ * Maximum age of cookies in seconds (default: 7 days)
64
+ */
65
+ maxAge?: number;
66
+ /**
67
+ * Cookie path (default: "/")
68
+ */
69
+ path?: string;
70
+ /**
71
+ * Cookie domain (default: current domain)
72
+ */
73
+ domain?: string;
74
+ /**
75
+ * Whether cookies should be secure (default: auto-detect based on protocol)
76
+ */
77
+ secure?: boolean;
78
+ /**
79
+ * SameSite cookie attribute (default: "Lax")
80
+ */
81
+ sameSite?: "Strict" | "Lax" | "None";
82
+ }
37
83
  /**
38
84
  * Configuration for the auth middleware
39
85
  */
@@ -1,5 +1,5 @@
1
1
  import { isTokenExpired } from "./jwt-utils";
2
- import { getPathnameFromUrl, isAnonymousAuthEndpoint, isTokenReturningEndpoint, isLogoutEndpoint } from "./auth-utils";
2
+ import { getPathnameFromUrl, isAnonymousAuthEndpoint, isTokenReturningEndpoint, isLogoutEndpoint, } from "./auth-utils";
3
3
  /**
4
4
  * Simple in-memory token storage implementation
5
5
  */
@@ -60,6 +60,90 @@ export class BrowserTokenStorage {
60
60
  }
61
61
  }
62
62
  }
63
+ /**
64
+ * Cookie-based token storage implementation
65
+ */
66
+ export class CookieTokenStorage {
67
+ accessTokenKey;
68
+ refreshTokenKey;
69
+ options;
70
+ constructor(options = {}) {
71
+ const prefix = options.prefix || "storefront_";
72
+ this.accessTokenKey = `${prefix}access_token`;
73
+ this.refreshTokenKey = `${prefix}refresh_token`;
74
+ this.options = {
75
+ maxAge: options.maxAge || 7 * 24 * 60 * 60, // 7 days default
76
+ path: options.path || "/",
77
+ domain: options.domain,
78
+ secure: options.secure ??
79
+ (typeof window !== "undefined" &&
80
+ window.location?.protocol === "https:"),
81
+ sameSite: options.sameSite || "Lax",
82
+ httpOnly: false, // Must be false for client-side access
83
+ };
84
+ }
85
+ async getAccessToken() {
86
+ return this.getCookie(this.accessTokenKey);
87
+ }
88
+ async setAccessToken(token) {
89
+ this.setCookie(this.accessTokenKey, token);
90
+ }
91
+ async getRefreshToken() {
92
+ return this.getCookie(this.refreshTokenKey);
93
+ }
94
+ async setRefreshToken(token) {
95
+ this.setCookie(this.refreshTokenKey, token);
96
+ }
97
+ async clearTokens() {
98
+ this.deleteCookie(this.accessTokenKey);
99
+ this.deleteCookie(this.refreshTokenKey);
100
+ }
101
+ getCookie(name) {
102
+ if (typeof document === "undefined")
103
+ return null;
104
+ const value = `; ${document.cookie}`;
105
+ const parts = value.split(`; ${name}=`);
106
+ if (parts.length === 2) {
107
+ const cookieValue = parts.pop()?.split(";").shift();
108
+ return cookieValue ? decodeURIComponent(cookieValue) : null;
109
+ }
110
+ return null;
111
+ }
112
+ setCookie(name, value) {
113
+ if (typeof document === "undefined")
114
+ return;
115
+ const encodedValue = encodeURIComponent(value);
116
+ let cookieString = `${name}=${encodedValue}`;
117
+ if (this.options.maxAge) {
118
+ cookieString += `; Max-Age=${this.options.maxAge}`;
119
+ }
120
+ if (this.options.path) {
121
+ cookieString += `; Path=${this.options.path}`;
122
+ }
123
+ if (this.options.domain) {
124
+ cookieString += `; Domain=${this.options.domain}`;
125
+ }
126
+ if (this.options.secure) {
127
+ cookieString += `; Secure`;
128
+ }
129
+ if (this.options.sameSite) {
130
+ cookieString += `; SameSite=${this.options.sameSite}`;
131
+ }
132
+ document.cookie = cookieString;
133
+ }
134
+ deleteCookie(name) {
135
+ if (typeof document === "undefined")
136
+ return;
137
+ let cookieString = `${name}=; Max-Age=0`;
138
+ if (this.options.path) {
139
+ cookieString += `; Path=${this.options.path}`;
140
+ }
141
+ if (this.options.domain) {
142
+ cookieString += `; Domain=${this.options.domain}`;
143
+ }
144
+ document.cookie = cookieString;
145
+ }
146
+ }
63
147
  /**
64
148
  * Create authentication middleware for openapi-fetch
65
149
  */
@@ -115,7 +199,7 @@ export function createAuthMiddleware(config) {
115
199
  headers: {
116
200
  "Content-Type": "application/json",
117
201
  ...(config.apiKey && { "X-Api-Key": config.apiKey }),
118
- "Authorization": `Bearer ${currentAccessToken}`, // For user_id continuity
202
+ Authorization: `Bearer ${currentAccessToken}`, // For user_id continuity
119
203
  },
120
204
  });
121
205
  if (!response.ok) {
@@ -184,7 +268,8 @@ export function createAuthMiddleware(config) {
184
268
  const pathname = getPathnameFromUrl(request.url);
185
269
  // Handle successful responses that return tokens
186
270
  if (response.ok) {
187
- if (isTokenReturningEndpoint(pathname) || isAnonymousAuthEndpoint(pathname)) {
271
+ if (isTokenReturningEndpoint(pathname) ||
272
+ isAnonymousAuthEndpoint(pathname)) {
188
273
  try {
189
274
  const data = await response.clone().json();
190
275
  const content = data.content;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@commercengine/storefront-sdk",
3
- "version": "0.3.6",
3
+ "version": "0.3.8",
4
4
  "description": "TypeScript SDK for the Storefront API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",