@commercengine/storefront-sdk 0.13.4 → 0.14.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.
@@ -1,6 +1,6 @@
1
1
  var CE_SDK = (function(exports) {
2
2
 
3
- Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: 'Module' } });
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
4
 
5
5
  //#region ../../node_modules/.pnpm/openapi-fetch@0.17.0/node_modules/openapi-fetch/dist/index.mjs
6
6
  const PATH_PARAM_RE = /\{[^{}]+\}/g;
@@ -455,7 +455,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
455
455
  */
456
456
  var DebugLogger = class {
457
457
  logger;
458
- responseTextCache = /* @__PURE__ */ new Map();
459
458
  constructor(logger) {
460
459
  this.logger = logger || ((level, message, data) => {
461
460
  console.log(`[${level.toUpperCase()}]`, message);
@@ -478,7 +477,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
478
477
  * Log debug information about API response
479
478
  */
480
479
  async logResponse(response, responseBody) {
481
- if (responseBody && typeof responseBody === "string") this.responseTextCache.set(response.url, responseBody);
482
480
  this.logger("info", "API Response Debug Info", {
483
481
  url: response.url,
484
482
  status: response.status,
@@ -502,17 +500,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
502
500
  this.logger("error", message, error);
503
501
  }
504
502
  /**
505
- * Get cached response text for a URL (if available)
503
+ * Compatibility shim retained for older internal callers.
504
+ * Response bodies are no longer cached by the debug logger.
506
505
  */
507
- getCachedResponseText(url) {
508
- return this.responseTextCache.get(url) || null;
506
+ getCachedResponseText(_url) {
507
+ return null;
509
508
  }
510
509
  /**
511
- * Clear cached response texts
510
+ * Compatibility shim retained for older internal callers.
511
+ * Response bodies are no longer cached by the debug logger.
512
512
  */
513
- clearCache() {
514
- this.responseTextCache.clear();
515
- }
513
+ clearCache() {}
516
514
  info(message, data) {
517
515
  this.logger("info", message, data);
518
516
  }
@@ -598,14 +596,33 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
598
596
  * @returns Middleware object with onRequest handler
599
597
  */
600
598
  function createTimeoutMiddleware(timeoutMs) {
601
- return { onRequest: async ({ request }) => {
602
- const controller = new AbortController();
603
- const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
604
- if (request.signal) request.signal.addEventListener("abort", () => controller.abort());
605
- const newRequest = new Request(request, { signal: controller.signal });
606
- controller.signal.addEventListener("abort", () => clearTimeout(timeoutId));
607
- return newRequest;
608
- } };
599
+ const timeouts = /* @__PURE__ */ new WeakMap();
600
+ const clearRequestTimeout = (signal) => {
601
+ const timeoutId = timeouts.get(signal);
602
+ if (timeoutId) {
603
+ clearTimeout(timeoutId);
604
+ timeouts.delete(signal);
605
+ }
606
+ };
607
+ return {
608
+ onRequest: async ({ request }) => {
609
+ const controller = new AbortController();
610
+ const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
611
+ if (request.signal) request.signal.addEventListener("abort", () => controller.abort(), { once: true });
612
+ const newRequest = new Request(request, { signal: controller.signal });
613
+ timeouts.set(newRequest.signal, timeoutId);
614
+ controller.signal.addEventListener("abort", () => clearRequestTimeout(newRequest.signal), { once: true });
615
+ return newRequest;
616
+ },
617
+ onResponse: async ({ request, response }) => {
618
+ clearRequestTimeout(request.signal);
619
+ return response;
620
+ },
621
+ onError: async ({ request, error }) => {
622
+ clearRequestTimeout(request.signal);
623
+ throw error;
624
+ }
625
+ };
609
626
  }
610
627
  /**
611
628
  * Transform headers using a transformation mapping
@@ -671,8 +688,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
671
688
  };
672
689
  } catch (err) {
673
690
  const mockResponse = new Response(null, {
674
- status: 0,
675
- statusText: "Network Error"
691
+ status: 503,
692
+ statusText: "Service Unavailable"
676
693
  });
677
694
  return {
678
695
  data: null,
@@ -792,619 +809,228 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
792
809
  }
793
810
 
794
811
  //#endregion
795
- //#region src/lib/jwt-utils.ts
812
+ //#region src/lib/shared/url-utils.ts
796
813
  /**
797
- * Decode a JWT token payload without signature verification.
798
- * This is a lightweight replacement for jose's decodeJwt.
799
- *
800
- * @param token - The JWT token to decode
801
- * @returns The decoded payload
802
- * @throws Error if the token is malformed
814
+ * URL utility functions for the Storefront SDK
803
815
  */
804
- function decodeJwt(token) {
805
- if (typeof token !== "string") throw new Error("Invalid token: must be a string");
806
- const parts = token.split(".");
807
- if (parts.length !== 3) throw new Error("Invalid token: must have 3 parts");
808
- const base64Url = parts[1];
809
- if (!base64Url) throw new Error("Invalid token: missing payload");
810
- let base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
811
- const padding = base64.length % 4;
812
- if (padding) base64 += "=".repeat(4 - padding);
813
- const binaryStr = atob(base64);
814
- const bytes = new Uint8Array(binaryStr.length);
815
- for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
816
- const payload = JSON.parse(new TextDecoder().decode(bytes));
817
- if (typeof payload !== "object" || payload === null) throw new Error("Invalid token: payload must be an object");
818
- return payload;
819
- }
820
816
  /**
821
- * Decode and extract user information from a JWT token
822
- *
823
- * @param token - The JWT token to decode
824
- * @returns User information or null if token is invalid
817
+ * Available API environments for Commerce Engine
825
818
  */
826
- function extractUserInfoFromToken(token) {
827
- try {
828
- const payload = decodeJwt(token);
829
- return {
830
- id: payload.ulid,
831
- email: payload.email,
832
- phone: payload.phone,
833
- username: payload.username,
834
- firstName: payload.first_name,
835
- lastName: payload.last_name,
836
- storeId: payload.store_id,
837
- isLoggedIn: payload.is_logged_in,
838
- isAnonymous: payload.is_anonymous,
839
- customerId: payload.customer_id,
840
- customerGroupId: payload.customer_group_id,
841
- anonymousId: payload.anonymous_id,
842
- channel: payload.channel,
843
- tokenExpiry: /* @__PURE__ */ new Date(payload.exp * 1e3),
844
- tokenIssuedAt: /* @__PURE__ */ new Date(payload.iat * 1e3)
845
- };
846
- } catch (error) {
847
- console.warn("Failed to decode JWT token:", error);
848
- return null;
849
- }
850
- }
819
+ let Environment = /* @__PURE__ */ function(Environment) {
820
+ /**
821
+ * Staging environment
822
+ */
823
+ Environment["Staging"] = "staging";
824
+ /**
825
+ * Production environment
826
+ */
827
+ Environment["Production"] = "production";
828
+ return Environment;
829
+ }({});
851
830
  /**
852
- * Check if a JWT token is expired
853
- *
854
- * @param token - The JWT token to check
855
- * @param bufferSeconds - Buffer time in seconds (default: 30)
856
- * @returns True if token is expired or will expire within buffer time
831
+ * Build base URL for Storefront API
857
832
  */
858
- function isTokenExpired(token, bufferSeconds = 30) {
859
- try {
860
- const payload = decodeJwt(token);
861
- if (!payload.exp) return true;
862
- return Math.floor(Date.now() / 1e3) >= payload.exp - bufferSeconds;
863
- } catch (error) {
864
- console.warn("Failed to decode JWT token:", error);
865
- return true;
833
+ function buildStorefrontURL(config) {
834
+ if (config.baseUrl) return config.baseUrl;
835
+ switch (config.environment || Environment.Production) {
836
+ case Environment.Staging: return `https://staging.api.commercengine.io/api/v1/${config.storeId}/storefront`;
837
+ case Environment.Production:
838
+ default: return `https://prod.api.commercengine.io/api/v1/${config.storeId}/storefront`;
866
839
  }
867
840
  }
868
- /**
869
- * Get the user ID from a JWT token
870
- *
871
- * @param token - The JWT token
872
- * @returns User ID (ulid) or null if token is invalid
873
- */
874
- function getUserIdFromToken(token) {
875
- return extractUserInfoFromToken(token)?.id || null;
876
- }
877
- /**
878
- * Check if user is logged in based on JWT token
879
- *
880
- * @param token - The JWT token
881
- * @returns True if user is logged in, false otherwise
882
- */
883
- function isUserLoggedIn(token) {
884
- return extractUserInfoFromToken(token)?.isLoggedIn || false;
885
- }
886
- /**
887
- * Check if user is anonymous based on JWT token
888
- *
889
- * @param token - The JWT token
890
- * @returns True if user is anonymous, false otherwise
891
- */
892
- function isUserAnonymous(token) {
893
- return extractUserInfoFromToken(token)?.isAnonymous ?? true;
894
- }
895
-
896
- //#endregion
897
- //#region src/types/api-key-endpoints.ts
898
- const API_KEY_ENDPOINTS = [
899
- "/auth/anonymous",
900
- "/store/check",
901
- "/store/config"
902
- ];
903
841
 
904
842
  //#endregion
905
- //#region src/lib/auth-utils.ts
843
+ //#region src/lib/shared/client.ts
906
844
  /**
907
- * Check if a URL path is an auth endpoint that should use API key
908
- */
909
- function isAnonymousAuthEndpoint(pathname) {
910
- return pathname.endsWith("/auth/anonymous");
911
- }
912
- /**
913
- * Check if a URL path requires API key authentication (auto-generated from OpenAPI spec)
914
- */
915
- function isApiKeyRequiredEndpoint(pathname) {
916
- return API_KEY_ENDPOINTS.some((endpoint) => pathname.endsWith(endpoint));
917
- }
918
- /**
919
- * Check if a URL path is a login/register endpoint that returns tokens
845
+ * Shared base class for Storefront API clients.
846
+ *
847
+ * This centralizes Storefront-specific URL construction, default header
848
+ * transformations, and shared API key state while leaving auth middleware
849
+ * decisions to the public and session-specific subclasses.
920
850
  */
921
- function isTokenReturningEndpoint(pathname) {
922
- return [
923
- "/auth/login/password",
924
- "/auth/register/phone",
925
- "/auth/register/email",
926
- "/auth/verify-otp",
927
- "/auth/refresh-token",
928
- "/auth/logout"
929
- ].some((endpoint) => pathname.endsWith(endpoint));
930
- }
851
+ var StorefrontAPIClientBase = class extends BaseAPIClient {
852
+ apiKey;
853
+ constructor(config) {
854
+ const baseUrl = buildStorefrontURL({
855
+ storeId: config.storeId,
856
+ environment: config.environment,
857
+ baseUrl: config.baseUrl
858
+ });
859
+ super({
860
+ baseUrl,
861
+ timeout: config.timeout,
862
+ defaultHeaders: config.defaultHeaders,
863
+ debug: config.debug,
864
+ logger: config.logger
865
+ }, baseUrl, {
866
+ customer_group_id: "x-customer-group-id",
867
+ debug_mode: "x-debug-mode"
868
+ });
869
+ this.apiKey = config.apiKey;
870
+ }
871
+ setApiKey(apiKey) {
872
+ this.apiKey = apiKey;
873
+ }
874
+ clearApiKey() {
875
+ this.apiKey = void 0;
876
+ }
877
+ useMiddleware(middleware) {
878
+ this.client.use(middleware);
879
+ }
880
+ };
931
881
 
932
882
  //#endregion
933
- //#region src/lib/middleware.ts
934
- /**
935
- * Simple in-memory token storage implementation
883
+ //#region src/lib/session/client.ts
884
+ function attachSessionAuth(client, sessionManager) {
885
+ client.useMiddleware(sessionManager.createAuthMiddleware());
886
+ }
887
+ /**
888
+ * Storefront API client that extends the generic BaseAPIClient
889
+ * Adds Commerce Engine specific authentication and token management
936
890
  */
937
- var MemoryTokenStorage = class {
938
- accessToken = null;
939
- refreshToken = null;
940
- async getAccessToken() {
941
- return this.accessToken;
891
+ var SessionStorefrontAPIClient = class extends StorefrontAPIClientBase {
892
+ config;
893
+ /**
894
+ * Create a new SessionStorefrontAPIClient
895
+ *
896
+ * @param config - Configuration for the API client
897
+ */
898
+ constructor(config) {
899
+ super(config);
900
+ this.config = { ...config };
901
+ this.setupStorefrontAuth();
942
902
  }
943
- async setAccessToken(token) {
944
- this.accessToken = token;
903
+ /**
904
+ * Set up Storefront-specific authentication middleware
905
+ */
906
+ setupStorefrontAuth() {
907
+ attachSessionAuth(this, this.config.sessionManager);
945
908
  }
946
- async getRefreshToken() {
947
- return this.refreshToken;
909
+ /**
910
+ * Get the authorization header value
911
+ * without creating a new session.
912
+ *
913
+ * @returns The Authorization header value or empty string if no token is set
914
+ */
915
+ async getAuthorizationHeader() {
916
+ return this.config.sessionManager.getAuthorizationHeader();
948
917
  }
949
- async setRefreshToken(token) {
950
- this.refreshToken = token;
918
+ /**
919
+ * Set authentication tokens
920
+ *
921
+ * @param accessToken - The access token (required)
922
+ * @param refreshToken - The refresh token (optional)
923
+ *
924
+ * Behavior:
925
+ * - If tokenStorage is provided: Stores tokens for automatic management
926
+ * - If tokenStorage is not provided: Only stores access token for manual management
927
+ */
928
+ async setTokens(accessToken, refreshToken) {
929
+ await this.config.sessionManager.setTokens(accessToken, refreshToken);
951
930
  }
931
+ /**
932
+ * Clear all authentication tokens
933
+ *
934
+ * Behavior:
935
+ * - If tokenStorage is provided: Clears both access and refresh tokens from storage
936
+ * - If tokenStorage is not provided: Clears the manual access token
937
+ */
952
938
  async clearTokens() {
953
- this.accessToken = null;
954
- this.refreshToken = null;
939
+ await this.config.sessionManager.clearTokens();
955
940
  }
956
- };
957
- /**
958
- * Browser localStorage token storage implementation
959
- */
960
- var BrowserTokenStorage = class {
961
- accessTokenKey;
962
- refreshTokenKey;
963
- constructor(prefix = "storefront_") {
964
- this.accessTokenKey = `${prefix}access_token`;
965
- this.refreshTokenKey = `${prefix}refresh_token`;
941
+ /**
942
+ * Set the X-Api-Key header
943
+ *
944
+ * @param apiKey - The API key to set
945
+ */
946
+ setApiKey(apiKey) {
947
+ super.setApiKey(apiKey);
948
+ this.config.apiKey = apiKey;
949
+ this.config.sessionManager.setApiKey(apiKey);
966
950
  }
967
- async getAccessToken() {
968
- if (typeof localStorage === "undefined") return null;
969
- return localStorage.getItem(this.accessTokenKey);
951
+ /**
952
+ * Clear the X-Api-Key header
953
+ */
954
+ clearApiKey() {
955
+ super.clearApiKey();
956
+ this.config.apiKey = void 0;
957
+ this.config.sessionManager.clearApiKey();
970
958
  }
971
- async setAccessToken(token) {
972
- if (typeof localStorage !== "undefined") localStorage.setItem(this.accessTokenKey, token);
959
+ /**
960
+ * Resolve the current user ID from explicit parameters or the active session.
961
+ *
962
+ * @param explicitUserId - Optional user ID supplied by the caller
963
+ * @returns The resolved user ID
964
+ * @throws When no user ID is available
965
+ */
966
+ async resolveCurrentUserId(explicitUserId) {
967
+ if (explicitUserId) return explicitUserId;
968
+ return this.config.sessionManager.ensureUserId();
973
969
  }
974
- async getRefreshToken() {
975
- if (typeof localStorage === "undefined") return null;
976
- return localStorage.getItem(this.refreshTokenKey);
970
+ /**
971
+ * Resolve path parameters that require `user_id`.
972
+ *
973
+ * @param pathParams - Path parameters with an optional `user_id`
974
+ * @returns Path parameters with a guaranteed `user_id`
975
+ */
976
+ async resolveUserPathParams(pathParams) {
977
+ return {
978
+ ...pathParams,
979
+ user_id: await this.resolveCurrentUserId(pathParams.user_id)
980
+ };
977
981
  }
978
- async setRefreshToken(token) {
979
- if (typeof localStorage !== "undefined") localStorage.setItem(this.refreshTokenKey, token);
982
+ /**
983
+ * Resolve query parameters that require `user_id`.
984
+ *
985
+ * @param queryParams - Query parameters with an optional `user_id`
986
+ * @returns Query parameters with a guaranteed `user_id`
987
+ */
988
+ async resolveUserQueryParams(queryParams) {
989
+ return {
990
+ ...queryParams,
991
+ user_id: await this.resolveCurrentUserId(queryParams.user_id)
992
+ };
980
993
  }
981
- async clearTokens() {
982
- if (typeof localStorage !== "undefined") {
983
- localStorage.removeItem(this.accessTokenKey);
984
- localStorage.removeItem(this.refreshTokenKey);
985
- }
986
- }
987
- };
988
- /**
989
- * Cookie-based token storage implementation
990
- */
991
- var CookieTokenStorage = class {
992
- accessTokenKey;
993
- refreshTokenKey;
994
- options;
995
- constructor(options = {}) {
996
- const prefix = options.prefix || "storefront_";
997
- this.accessTokenKey = `${prefix}access_token`;
998
- this.refreshTokenKey = `${prefix}refresh_token`;
999
- this.options = {
1000
- maxAge: options.maxAge || 10080 * 60,
1001
- path: options.path || "/",
1002
- domain: options.domain,
1003
- secure: options.secure ?? (typeof window !== "undefined" && window.location?.protocol === "https:"),
1004
- sameSite: options.sameSite || "Lax",
1005
- httpOnly: false
1006
- };
1007
- }
1008
- async getAccessToken() {
1009
- return this.getCookie(this.accessTokenKey);
1010
- }
1011
- async setAccessToken(token) {
1012
- this.setCookie(this.accessTokenKey, token);
1013
- }
1014
- async getRefreshToken() {
1015
- return this.getCookie(this.refreshTokenKey);
1016
- }
1017
- async setRefreshToken(token) {
1018
- this.setCookie(this.refreshTokenKey, token);
1019
- }
1020
- async clearTokens() {
1021
- this.deleteCookie(this.accessTokenKey);
1022
- this.deleteCookie(this.refreshTokenKey);
1023
- }
1024
- getCookie(name) {
1025
- if (typeof document === "undefined") return null;
1026
- const parts = `; ${document.cookie}`.split(`; ${name}=`);
1027
- if (parts.length === 2) {
1028
- const cookieValue = parts.pop()?.split(";").shift();
1029
- return cookieValue ? decodeURIComponent(cookieValue) : null;
1030
- }
1031
- return null;
1032
- }
1033
- setCookie(name, value) {
1034
- if (typeof document === "undefined") return;
1035
- let cookieString = `${name}=${encodeURIComponent(value)}`;
1036
- if (this.options.maxAge) cookieString += `; Max-Age=${this.options.maxAge}`;
1037
- if (this.options.path) cookieString += `; Path=${this.options.path}`;
1038
- if (this.options.domain) cookieString += `; Domain=${this.options.domain}`;
1039
- if (this.options.secure) cookieString += `; Secure`;
1040
- if (this.options.sameSite) cookieString += `; SameSite=${this.options.sameSite}`;
1041
- document.cookie = cookieString;
1042
- }
1043
- deleteCookie(name) {
1044
- if (typeof document === "undefined") return;
1045
- let cookieString = `${name}=; Max-Age=0`;
1046
- if (this.options.path) cookieString += `; Path=${this.options.path}`;
1047
- if (this.options.domain) cookieString += `; Domain=${this.options.domain}`;
1048
- document.cookie = cookieString;
1049
- }
1050
- };
1051
- /**
1052
- * Create authentication middleware for openapi-fetch
1053
- */
1054
- function createAuthMiddleware(config) {
1055
- let isRefreshing = false;
1056
- let refreshPromise = null;
1057
- let hasAssessedTokens = false;
1058
- const assessTokenStateOnce = async () => {
1059
- if (hasAssessedTokens) return;
1060
- hasAssessedTokens = true;
1061
- try {
1062
- const accessToken = await config.tokenStorage.getAccessToken();
1063
- const refreshToken = await config.tokenStorage.getRefreshToken();
1064
- if (!accessToken && refreshToken) {
1065
- await config.tokenStorage.clearTokens();
1066
- console.info("Cleaned up orphaned refresh token");
1067
- }
1068
- } catch (error) {
1069
- console.warn("Token state assessment failed:", error);
1070
- }
1071
- };
1072
- const refreshTokens = async () => {
1073
- if (isRefreshing && refreshPromise) return refreshPromise;
1074
- isRefreshing = true;
1075
- refreshPromise = (async () => {
1076
- try {
1077
- const refreshToken = await config.tokenStorage.getRefreshToken();
1078
- let newTokens;
1079
- if (refreshToken && !isTokenExpired(refreshToken)) if (config.refreshTokenFn) newTokens = await config.refreshTokenFn(refreshToken);
1080
- else {
1081
- const response = await fetch(`${config.baseUrl}/auth/refresh-token`, {
1082
- method: "POST",
1083
- headers: { "Content-Type": "application/json" },
1084
- body: JSON.stringify({ refresh_token: refreshToken })
1085
- });
1086
- if (!response.ok) throw new Error(`Token refresh failed: ${response.status}`);
1087
- newTokens = (await response.json()).content;
1088
- }
1089
- else {
1090
- const currentAccessToken = await config.tokenStorage.getAccessToken();
1091
- if (!currentAccessToken) throw new Error("No tokens available for refresh");
1092
- const reason = refreshToken ? "refresh token expired" : "no refresh token available";
1093
- const response = await fetch(`${config.baseUrl}/auth/anonymous`, {
1094
- method: "POST",
1095
- headers: {
1096
- "Content-Type": "application/json",
1097
- ...config.apiKey && { "X-Api-Key": config.apiKey },
1098
- Authorization: `Bearer ${currentAccessToken}`
1099
- }
1100
- });
1101
- if (!response.ok) throw new Error(`Anonymous token fallback failed: ${response.status}`);
1102
- newTokens = (await response.json()).content;
1103
- console.info(`Token refreshed via anonymous fallback (${reason}) - user may need to re-authenticate for privileged operations`);
1104
- }
1105
- await config.tokenStorage.setAccessToken(newTokens.access_token);
1106
- await config.tokenStorage.setRefreshToken(newTokens.refresh_token);
1107
- config.onTokensUpdated?.(newTokens.access_token, newTokens.refresh_token);
1108
- } catch (error) {
1109
- console.error("Token refresh failed:", error);
1110
- await config.tokenStorage.clearTokens();
1111
- config.onTokensCleared?.();
1112
- throw error;
1113
- } finally {
1114
- isRefreshing = false;
1115
- refreshPromise = null;
1116
- }
1117
- })();
1118
- return refreshPromise;
1119
- };
1120
- return {
1121
- async onRequest({ request }) {
1122
- const pathname = getPathnameFromUrl(request.url);
1123
- await assessTokenStateOnce();
1124
- if (isAnonymousAuthEndpoint(pathname)) {
1125
- if (config.apiKey) request.headers.set("X-Api-Key", config.apiKey);
1126
- const existingToken = await config.tokenStorage.getAccessToken();
1127
- if (existingToken && !isTokenExpired(existingToken) && isUserLoggedIn(existingToken)) return new Response(JSON.stringify({
1128
- message: "Cannot create anonymous session while authenticated",
1129
- success: false,
1130
- code: "USER_ALREADY_AUTHENTICATED"
1131
- }), {
1132
- status: 400,
1133
- headers: { "Content-Type": "application/json" }
1134
- });
1135
- if (existingToken) request.headers.set("Authorization", `Bearer ${existingToken}`);
1136
- return request;
1137
- }
1138
- if (isApiKeyRequiredEndpoint(pathname)) {
1139
- if (config.apiKey) request.headers.set("X-Api-Key", config.apiKey);
1140
- return request;
1141
- }
1142
- let accessToken = await config.tokenStorage.getAccessToken();
1143
- if (!accessToken) try {
1144
- const response = await fetch(`${config.baseUrl}/auth/anonymous`, {
1145
- method: "POST",
1146
- headers: {
1147
- "Content-Type": "application/json",
1148
- ...config.apiKey && { "X-Api-Key": config.apiKey }
1149
- }
1150
- });
1151
- if (response.ok) {
1152
- const tokens = (await response.json()).content;
1153
- if (tokens?.access_token && tokens?.refresh_token) {
1154
- await config.tokenStorage.setAccessToken(tokens.access_token);
1155
- await config.tokenStorage.setRefreshToken(tokens.refresh_token);
1156
- accessToken = tokens.access_token;
1157
- config.onTokensUpdated?.(tokens.access_token, tokens.refresh_token);
1158
- console.info("Automatically created anonymous session for first API request");
1159
- }
1160
- }
1161
- } catch (error) {
1162
- console.warn("Failed to automatically create anonymous tokens:", error);
1163
- }
1164
- if (accessToken && isTokenExpired(accessToken)) try {
1165
- await refreshTokens();
1166
- accessToken = await config.tokenStorage.getAccessToken();
1167
- } catch (error) {}
1168
- if (accessToken) request.headers.set("Authorization", `Bearer ${accessToken}`);
1169
- return request;
1170
- },
1171
- async onResponse({ request, response }) {
1172
- const pathname = getPathnameFromUrl(request.url);
1173
- if (response.ok) {
1174
- if (isTokenReturningEndpoint(pathname) || isAnonymousAuthEndpoint(pathname)) try {
1175
- const content = (await response.clone().json()).content;
1176
- if (content?.access_token && content?.refresh_token) {
1177
- await config.tokenStorage.setAccessToken(content.access_token);
1178
- await config.tokenStorage.setRefreshToken(content.refresh_token);
1179
- config.onTokensUpdated?.(content.access_token, content.refresh_token);
1180
- }
1181
- } catch (error) {
1182
- console.warn("Failed to extract tokens from response:", error);
1183
- }
1184
- }
1185
- if (response.status === 401 && !isAnonymousAuthEndpoint(pathname)) {
1186
- const currentToken = await config.tokenStorage.getAccessToken();
1187
- if (currentToken && isTokenExpired(currentToken, 0)) try {
1188
- await refreshTokens();
1189
- const newToken = await config.tokenStorage.getAccessToken();
1190
- if (newToken) {
1191
- const retryRequest = request.clone();
1192
- retryRequest.headers.set("Authorization", `Bearer ${newToken}`);
1193
- return fetch(retryRequest);
1194
- }
1195
- } catch (error) {
1196
- console.warn("Token refresh failed on 401 response:", error);
1197
- }
1198
- }
1199
- return response;
1200
- }
1201
- };
1202
- }
1203
- /**
1204
- * Helper function to create auth middleware with sensible defaults
1205
- */
1206
- function createDefaultAuthMiddleware(options) {
1207
- return createAuthMiddleware({
1208
- tokenStorage: options.tokenStorage || (typeof localStorage !== "undefined" ? new BrowserTokenStorage() : new MemoryTokenStorage()),
1209
- apiKey: options.apiKey,
1210
- baseUrl: options.baseUrl,
1211
- onTokensUpdated: options.onTokensUpdated,
1212
- onTokensCleared: options.onTokensCleared
1213
- });
1214
- }
1215
-
1216
- //#endregion
1217
- //#region src/lib/url-utils.ts
1218
- /**
1219
- * URL utility functions for the Storefront SDK
1220
- */
1221
- /**
1222
- * Available API environments for Commerce Engine
1223
- */
1224
- let Environment = /* @__PURE__ */ function(Environment) {
1225
- /**
1226
- * Staging environment
1227
- */
1228
- Environment["Staging"] = "staging";
1229
994
  /**
1230
- * Production environment
995
+ * Resolve path parameters that require `customer_id`.
996
+ *
997
+ * @param pathParams - Path parameters with an optional `customer_id`
998
+ * @returns Path parameters with a guaranteed `customer_id`
999
+ * @throws When the user is anonymous or no session can be established
1231
1000
  */
1232
- Environment["Production"] = "production";
1233
- return Environment;
1234
- }({});
1235
- /**
1236
- * Build base URL for Storefront API
1237
- */
1238
- function buildStorefrontURL(config) {
1239
- if (config.baseUrl) return config.baseUrl;
1240
- switch (config.environment || Environment.Production) {
1241
- case Environment.Staging: return `https://staging.api.commercengine.io/api/v1/${config.storeId}/storefront`;
1242
- case Environment.Production:
1243
- default: return `https://prod.api.commercengine.io/api/v1/${config.storeId}/storefront`;
1001
+ async resolveCustomerPathParams(pathParams) {
1002
+ return {
1003
+ ...pathParams,
1004
+ customer_id: pathParams.customer_id ?? await this.config.sessionManager.ensureCustomerId()
1005
+ };
1244
1006
  }
1245
- }
1007
+ };
1246
1008
 
1247
1009
  //#endregion
1248
- //#region src/lib/client.ts
1010
+ //#region src/lib/shared/catalog.ts
1249
1011
  /**
1250
- * Storefront API client that extends the generic BaseAPIClient
1251
- * Adds Commerce Engine specific authentication and token management
1012
+ * Client for interacting with catalog endpoints
1252
1013
  */
1253
- var StorefrontAPIClient = class extends BaseAPIClient {
1254
- config;
1255
- initializationPromise = null;
1256
- /**
1257
- * Create a new StorefrontAPIClient
1258
- *
1259
- * @param config - Configuration for the API client
1260
- */
1261
- constructor(config) {
1262
- const baseUrl = buildStorefrontURL({
1263
- storeId: config.storeId,
1264
- environment: config.environment,
1265
- baseUrl: config.baseUrl
1266
- });
1267
- super({
1268
- baseUrl,
1269
- timeout: config.timeout,
1270
- defaultHeaders: config.defaultHeaders,
1271
- debug: config.debug,
1272
- logger: config.logger
1273
- }, baseUrl, {
1274
- customer_group_id: "x-customer-group-id",
1275
- debug_mode: "x-debug-mode"
1276
- });
1277
- this.config = { ...config };
1278
- this.setupStorefrontAuth();
1279
- }
1280
- /**
1281
- * Set up Storefront-specific authentication middleware
1282
- */
1283
- setupStorefrontAuth() {
1284
- const config = this.config;
1285
- if (config.tokenStorage) {
1286
- const authMiddleware = createDefaultAuthMiddleware({
1287
- apiKey: config.apiKey,
1288
- baseUrl: this.getBaseUrl(),
1289
- tokenStorage: config.tokenStorage,
1290
- onTokensUpdated: config.onTokensUpdated,
1291
- onTokensCleared: config.onTokensCleared
1292
- });
1293
- this.client.use(authMiddleware);
1294
- if (config.accessToken) {
1295
- this.initializationPromise = this.initializeTokens(config.accessToken, config.refreshToken);
1296
- config.accessToken = void 0;
1297
- config.refreshToken = void 0;
1298
- }
1299
- } else this.client.use({ onRequest: async ({ request }) => {
1300
- if (isAnonymousAuthEndpoint(getPathnameFromUrl(request.url))) {
1301
- if (config.apiKey) request.headers.set("X-Api-Key", config.apiKey);
1302
- if (config.accessToken) request.headers.set("Authorization", `Bearer ${config.accessToken}`);
1303
- return request;
1304
- }
1305
- if (config.accessToken) request.headers.set("Authorization", `Bearer ${config.accessToken}`);
1306
- return request;
1307
- } });
1308
- }
1014
+ var BaseCatalogClient = class extends StorefrontAPIClientBase {
1309
1015
  /**
1310
- * Get the authorization header value
1311
- * If using token storage, gets the current token from storage
1312
- * Otherwise returns the manual token
1016
+ * List all products
1313
1017
  *
1314
- * @returns The Authorization header value or empty string if no token is set
1315
- */
1316
- async getAuthorizationHeader() {
1317
- if (this.config.tokenStorage && this.initializationPromise) await this.initializationPromise;
1318
- if (this.config.tokenStorage) {
1319
- const token = await this.config.tokenStorage.getAccessToken();
1320
- return token ? `Bearer ${token}` : "";
1321
- }
1322
- return this.config.accessToken ? `Bearer ${this.config.accessToken}` : "";
1323
- }
1324
- /**
1325
- * Set authentication tokens
1018
+ * @param options - Optional query parameters
1019
+ * @param headers - Optional header parameters (customer_group_id, etc.)
1020
+ * @returns Promise with products and pagination info
1326
1021
  *
1327
- * @param accessToken - The access token (required)
1328
- * @param refreshToken - The refresh token (optional)
1022
+ * @example
1023
+ * ```typescript
1024
+ * // Basic product listing
1025
+ * const { data, error } = await sdk.catalog.listProducts();
1329
1026
  *
1330
- * Behavior:
1331
- * - If tokenStorage is provided: Stores tokens for automatic management
1332
- * - If tokenStorage is not provided: Only stores access token for manual management
1333
- */
1334
- async setTokens(accessToken, refreshToken) {
1335
- if (this.config.tokenStorage) {
1336
- await this.config.tokenStorage.setAccessToken(accessToken);
1337
- if (refreshToken) await this.config.tokenStorage.setRefreshToken(refreshToken);
1338
- } else {
1339
- this.config.accessToken = accessToken;
1340
- if (refreshToken) console.warn("Refresh token provided but ignored in manual token management mode. Use tokenStorage for automatic management.");
1341
- }
1342
- }
1343
- /**
1344
- * Clear all authentication tokens
1027
+ * if (error) {
1028
+ * console.error("Failed to list products:", error);
1029
+ * return;
1030
+ * }
1345
1031
  *
1346
- * Behavior:
1347
- * - If tokenStorage is provided: Clears both access and refresh tokens from storage
1348
- * - If tokenStorage is not provided: Clears the manual access token
1349
- */
1350
- async clearTokens() {
1351
- if (this.config.tokenStorage) await this.config.tokenStorage.clearTokens();
1352
- else this.config.accessToken = void 0;
1353
- }
1354
- /**
1355
- * Set the X-Api-Key header
1356
- *
1357
- * @param apiKey - The API key to set
1358
- */
1359
- setApiKey(apiKey) {
1360
- this.config.apiKey = apiKey;
1361
- }
1362
- /**
1363
- * Clear the X-Api-Key header
1364
- */
1365
- clearApiKey() {
1366
- this.config.apiKey = void 0;
1367
- }
1368
- /**
1369
- * Initialize tokens in storage (private helper method)
1370
- */
1371
- async initializeTokens(accessToken, refreshToken) {
1372
- try {
1373
- if (this.config.tokenStorage) {
1374
- await this.config.tokenStorage.setAccessToken(accessToken);
1375
- if (refreshToken) await this.config.tokenStorage.setRefreshToken(refreshToken);
1376
- }
1377
- } catch (error) {
1378
- console.warn("Failed to initialize tokens in storage:", error);
1379
- }
1380
- }
1381
- };
1382
-
1383
- //#endregion
1384
- //#region src/lib/catalog.ts
1385
- /**
1386
- * Client for interacting with catalog endpoints
1387
- */
1388
- var CatalogClient = class extends StorefrontAPIClient {
1389
- /**
1390
- * List all products
1391
- *
1392
- * @param options - Optional query parameters
1393
- * @param headers - Optional header parameters (customer_group_id, etc.)
1394
- * @returns Promise with products and pagination info
1395
- *
1396
- * @example
1397
- * ```typescript
1398
- * // Basic product listing
1399
- * const { data, error } = await sdk.catalog.listProducts();
1400
- *
1401
- * if (error) {
1402
- * console.error("Failed to list products:", error);
1403
- * return;
1404
- * }
1405
- *
1406
- * console.log("Products found:", data.products?.length || 0);
1407
- * console.log("Pagination:", data.pagination);
1032
+ * console.log("Products found:", data.products?.length || 0);
1033
+ * console.log("Pagination:", data.pagination);
1408
1034
  *
1409
1035
  * // With filtering and pagination
1410
1036
  * const { data: filteredData, error: filteredError } = await sdk.catalog.listProducts({
@@ -1717,49 +1343,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1717
1343
  } }));
1718
1344
  }
1719
1345
  /**
1720
- * Create a product review
1721
- *
1722
- * @param pathParams - The path parameters (product ID)
1723
- * @param formData - The review data including rating, comment, and optional images
1724
- * @returns Promise with review creation response
1725
- *
1726
- * @example
1727
- * ```typescript
1728
- * const { data, error } = await sdk.catalog.createProductReview(
1729
- * { product_id: "prod_123" },
1730
- * {
1731
- * user_id: "user_123",
1732
- * order_number: "ORD-001",
1733
- * rating: 5,
1734
- * review_text: "Excellent product! Highly recommended.",
1735
- * images: [
1736
- * new File(["image data"], "review1.jpg", { type: "image/jpeg" }),
1737
- * new File(["image data"], "review2.jpg", { type: "image/jpeg" })
1738
- * ]
1739
- * }
1740
- * );
1741
- *
1742
- * if (error) {
1743
- * console.error("Failed to create review:", error);
1744
- * return;
1745
- * }
1746
- *
1747
- * console.log("Review created successfully:", data.message);
1748
- * ```
1749
- */
1750
- async createProductReview(pathParams, formData) {
1751
- return this.executeRequest(() => this.client.POST("/catalog/products/{product_id}/reviews", {
1752
- params: { path: pathParams },
1753
- body: formData,
1754
- bodySerializer: (body) => {
1755
- const fd = new FormData();
1756
- for (const [key, value] of Object.entries(body)) if (value !== void 0 && value !== null) if (value instanceof File || value instanceof Blob) fd.append(key, value);
1757
- else fd.append(key, String(value));
1758
- return fd;
1759
- }
1760
- }));
1761
- }
1762
- /**
1763
1346
  * Search for products
1764
1347
  *
1765
1348
  * @param searchData - The search query, filters, sort, and pagination options
@@ -1999,12 +1582,100 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
1999
1582
  }
2000
1583
  };
2001
1584
 
1585
+ //#endregion
1586
+ //#region src/lib/public/client.ts
1587
+ /**
1588
+ * Storefront API client that always authenticates with `X-Api-Key`.
1589
+ *
1590
+ * This client is used by the public storefront surface where no session or
1591
+ * token lifecycle should be involved.
1592
+ */
1593
+ var PublicStorefrontAPIClient = class extends StorefrontAPIClientBase {
1594
+ constructor(config) {
1595
+ super(config);
1596
+ attachPublicAuth(this);
1597
+ }
1598
+ };
1599
+ function attachPublicAuth(client) {
1600
+ client.useMiddleware({ onRequest: async ({ request }) => {
1601
+ if (client.apiKey) request.headers.set("X-Api-Key", client.apiKey);
1602
+ return request;
1603
+ } });
1604
+ }
1605
+
1606
+ //#endregion
1607
+ //#region src/lib/public/catalog.ts
1608
+ /**
1609
+ * Client for interacting with catalog endpoints
1610
+ */
1611
+ var PublicCatalogClient = class extends BaseCatalogClient {
1612
+ constructor(config) {
1613
+ super(config);
1614
+ attachPublicAuth(this);
1615
+ }
1616
+ };
1617
+
1618
+ //#endregion
1619
+ //#region src/lib/catalog.ts
1620
+ /**
1621
+ * Client for interacting with catalog endpoints
1622
+ */
1623
+ var CatalogClient = class extends BaseCatalogClient {
1624
+ constructor(config) {
1625
+ super(config);
1626
+ attachSessionAuth(this, config.sessionManager);
1627
+ }
1628
+ /**
1629
+ * Create a product review
1630
+ *
1631
+ * @param pathParams - The path parameters (product ID)
1632
+ * @param formData - The review data including rating, comment, and optional images
1633
+ * @returns Promise with review creation response
1634
+ *
1635
+ * @example
1636
+ * ```typescript
1637
+ * const { data, error } = await sdk.catalog.createProductReview(
1638
+ * { product_id: "prod_123" },
1639
+ * {
1640
+ * user_id: "user_123",
1641
+ * order_number: "ORD-001",
1642
+ * rating: 5,
1643
+ * review_text: "Excellent product! Highly recommended.",
1644
+ * images: [
1645
+ * new File(["image data"], "review1.jpg", { type: "image/jpeg" }),
1646
+ * new File(["image data"], "review2.jpg", { type: "image/jpeg" })
1647
+ * ]
1648
+ * }
1649
+ * );
1650
+ *
1651
+ * if (error) {
1652
+ * console.error("Failed to create review:", error);
1653
+ * return;
1654
+ * }
1655
+ *
1656
+ * console.log("Review created successfully:", data.message);
1657
+ * ```
1658
+ */
1659
+ async createProductReview(pathParams, formData) {
1660
+ return this.executeRequest(() => this.client.POST("/catalog/products/{product_id}/reviews", {
1661
+ params: { path: pathParams },
1662
+ body: formData,
1663
+ bodySerializer: (body) => {
1664
+ const fd = new FormData();
1665
+ for (const [key, value] of Object.entries(body)) if (value !== void 0 && value !== null) if (value instanceof File || value instanceof Blob) fd.append(key, value);
1666
+ else fd.append(key, String(value));
1667
+ return fd;
1668
+ }
1669
+ }));
1670
+ }
1671
+ };
1672
+
2002
1673
  //#endregion
2003
1674
  //#region src/lib/cart.ts
2004
1675
  /**
2005
1676
  * Client for interacting with cart endpoints
2006
1677
  */
2007
- var CartClient = class extends StorefrontAPIClient {
1678
+ var CartClient = class extends SessionStorefrontAPIClient {
2008
1679
  /**
2009
1680
  * Create a new cart
2010
1681
  *
@@ -2126,49 +1797,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
2126
1797
  body
2127
1798
  }));
2128
1799
  }
2129
- /**
2130
- * Get cart details by user ID
2131
- *
2132
- * @param userId - The ID of the user
2133
- * @returns Promise with cart details
2134
- * @example
2135
- * ```typescript
2136
- * const { data, error } = await sdk.cart.getUserCart({
2137
- * user_id: "01H9USER12345ABCDE"
2138
- * });
2139
- *
2140
- * if (error) {
2141
- * console.error("Failed to get user cart:", error.message);
2142
- * } else {
2143
- * console.log("User cart ID:", data.cart.id);
2144
- * console.log("Cart value:", data.cart.subtotal);
2145
- * }
2146
- * ```
2147
- */
2148
- async getUserCart(userId) {
2149
- return this.executeRequest(() => this.client.GET("/carts/users/{user_id}", { params: { path: userId } }));
1800
+ async getUserCart(pathParams = {}) {
1801
+ const resolvedPathParams = await this.resolveUserPathParams(pathParams);
1802
+ return this.executeRequest(() => this.client.GET("/carts/users/{user_id}", { params: { path: resolvedPathParams } }));
2150
1803
  }
2151
- /**
2152
- * Delete a cart by user ID
2153
- *
2154
- * @param userId - The ID of the user
2155
- * @returns Promise that resolves when the cart is deleted
2156
- * @example
2157
- * ```typescript
2158
- * const { data, error } = await sdk.cart.deleteUserCart({
2159
- * user_id: "01H9USER12345ABCDE"
2160
- * });
2161
- *
2162
- * if (error) {
2163
- * console.error("Failed to delete user cart:", error.message);
2164
- * } else {
2165
- * console.log("User cart cleared:", data.message);
2166
- * }
2167
- * ```
2168
- */
2169
- async deleteUserCart(userId) {
1804
+ async deleteUserCart(pathParams = {}) {
1805
+ const resolvedPathParams = await this.resolveUserPathParams(pathParams);
2170
1806
  return this.executeRequest(() => this.client.DELETE("/carts/users/{user_id}", {
2171
- params: { path: userId },
1807
+ params: { path: resolvedPathParams },
2172
1808
  body: void 0
2173
1809
  }));
2174
1810
  }
@@ -2661,92 +2297,31 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
2661
2297
  body: void 0
2662
2298
  }));
2663
2299
  }
2664
- /**
2665
- * Get wishlist items
2666
- *
2667
- * @param userId - The ID of the user
2668
- * @param options - Optional query parameters for filtering by seller_id (only for multi-seller marketplace stores)
2669
- * @returns Promise with wishlist items
2670
- * @example
2671
- * ```typescript
2672
- * const { data, error } = await sdk.cart.getWishlist({
2673
- * user_id: "01H9USER12345ABCDE"
2674
- * });
2675
- *
2676
- * if (error) {
2677
- * console.error("Failed to get wishlist:", error.message);
2678
- * } else {
2679
- * const products = data.products;
2680
- * console.log("Wishlist items:", products.length);
2681
- * products.forEach(product => {
2682
- * console.log("Product:", product.product_name, "Price:", product.pricing?.selling_price);
2683
- * });
2684
- * }
2685
- * ```
2686
- */
2687
- async getWishlist(userId, options) {
2300
+ async getWishlist(pathParamsOrQuery, options) {
2301
+ const hasPathParams = options !== void 0 || !!pathParamsOrQuery && typeof pathParamsOrQuery === "object" && "user_id" in pathParamsOrQuery;
2302
+ const pathParams = hasPathParams ? pathParamsOrQuery : {};
2303
+ const queryParams = hasPathParams ? options : pathParamsOrQuery;
2304
+ const resolvedPathParams = await this.resolveUserPathParams(pathParams);
2688
2305
  return this.executeRequest(() => this.client.GET("/wishlist/{user_id}", { params: {
2689
- path: userId,
2690
- query: options
2306
+ path: resolvedPathParams,
2307
+ query: queryParams
2691
2308
  } }));
2692
2309
  }
2693
- /**
2694
- * Add item to wishlist
2695
- *
2696
- * @param userId - The ID of the user
2697
- * @param itemId - The ID of the item
2698
- * @returns Promise with updated wishlist
2699
- * @example
2700
- * ```typescript
2701
- * const { data, error } = await sdk.cart.addToWishlist(
2702
- * { user_id: "01H9USER12345ABCDE" },
2703
- * {
2704
- * product_id: "01F3Z7KG06J4ACWH1C4926KJEC",
2705
- * variant_id: null
2706
- * }
2707
- * );
2708
- *
2709
- * if (error) {
2710
- * console.error("Failed to add to wishlist:", error.message);
2711
- * } else {
2712
- * const products = data.products;
2713
- * console.log("Item added to wishlist, total items:", products.length);
2714
- * }
2715
- * ```
2716
- */
2717
- async addToWishlist(userId, itemId) {
2310
+ async addToWishlist(pathParamsOrBody, maybeBody) {
2311
+ const pathParams = maybeBody ? pathParamsOrBody : {};
2312
+ const body = maybeBody ?? pathParamsOrBody;
2313
+ const resolvedPathParams = await this.resolveUserPathParams(pathParams);
2718
2314
  return this.executeRequest(() => this.client.POST("/wishlist/{user_id}", {
2719
- params: { path: userId },
2720
- body: itemId
2315
+ params: { path: resolvedPathParams },
2316
+ body
2721
2317
  }));
2722
2318
  }
2723
- /**
2724
- * Remove item from wishlist
2725
- *
2726
- * @param userId - The ID of the user
2727
- * @param body - The body containing product details to remove
2728
- * @returns Promise with updated wishlist
2729
- * @example
2730
- * ```typescript
2731
- * const { data, error } = await sdk.cart.removeFromWishlist(
2732
- * { user_id: "01H9USER12345ABCDE" },
2733
- * {
2734
- * product_id: "01F3Z7KG06J4ACWH1C4926KJEC",
2735
- * variant_id: null
2736
- * }
2737
- * );
2738
- *
2739
- * if (error) {
2740
- * console.error("Failed to remove from wishlist:", error.message);
2741
- * } else {
2742
- * const products = data.products;
2743
- * console.log("Item removed from wishlist, remaining items:", products.length);
2744
- * }
2745
- * ```
2746
- */
2747
- async removeFromWishlist(userId, body) {
2319
+ async removeFromWishlist(pathParamsOrBody, maybeBody) {
2320
+ const pathParams = maybeBody ? pathParamsOrBody : {};
2321
+ const body = maybeBody ?? pathParamsOrBody;
2322
+ const resolvedPathParams = await this.resolveUserPathParams(pathParams);
2748
2323
  return this.executeRequest(() => this.client.DELETE("/wishlist/{user_id}", {
2749
- params: { path: userId },
2324
+ params: { path: resolvedPathParams },
2750
2325
  body
2751
2326
  }));
2752
2327
  }
@@ -2757,7 +2332,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
2757
2332
  /**
2758
2333
  * Client for interacting with authentication endpoints
2759
2334
  */
2760
- var AuthClient = class extends StorefrontAPIClient {
2335
+ var AuthClient = class extends SessionStorefrontAPIClient {
2761
2336
  /**
2762
2337
  * Get anonymous token for guest users
2763
2338
  *
@@ -2890,13 +2465,14 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
2890
2465
  return this.executeRequest(() => this.client.POST("/auth/login/password", { body }));
2891
2466
  }
2892
2467
  /**
2893
- * Forgot password
2468
+ * Start forgot-password OTP flow
2894
2469
  *
2895
- * @param body - Request body containing email address
2896
- * @returns Promise with password reset information
2470
+ * @param body - Request body containing email or phone details
2471
+ * @param headers - Optional header parameters (for example `x-debug-mode`)
2472
+ * @returns Promise with OTP token and action for the reset flow
2897
2473
  * @example
2898
2474
  * ```typescript
2899
- * // Send password reset email
2475
+ * // Send password reset OTP
2900
2476
  * const { data, error } = await sdk.auth.forgotPassword({
2901
2477
  * email: "customer@example.com"
2902
2478
  * });
@@ -2904,13 +2480,17 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
2904
2480
  * if (error) {
2905
2481
  * console.error("Password reset failed:", error.message);
2906
2482
  * } else {
2907
- * console.log("Reset email sent successfully");
2908
- * // Show confirmation message to user
2483
+ * console.log("OTP token:", data.otp_token);
2484
+ * console.log("Action:", data.otp_action);
2909
2485
  * }
2910
2486
  * ```
2911
2487
  */
2912
- async forgotPassword(body) {
2913
- return this.executeRequest(() => this.client.POST("/auth/forgot-password", { body }));
2488
+ async forgotPassword(body, headers) {
2489
+ const mergedHeaders = this.mergeHeaders(headers);
2490
+ return this.executeRequest(() => this.client.POST("/auth/forgot-password", {
2491
+ body,
2492
+ params: { header: mergedHeaders }
2493
+ }));
2914
2494
  }
2915
2495
  /**
2916
2496
  * Reset password
@@ -2992,7 +2572,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
2992
2572
  * Register with phone
2993
2573
  *
2994
2574
  * @param body - Registration details including phone number and user information
2995
- * @returns Promise with user info and tokens
2575
+ * @param headers - Optional header parameters (for example `x-debug-mode`)
2576
+ * @returns Promise with OTP token and action for completing registration
2996
2577
  * @example
2997
2578
  * ```typescript
2998
2579
  * // Register a new user with phone number
@@ -3007,20 +2588,24 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3007
2588
  * if (error) {
3008
2589
  * console.error("Phone registration failed:", error.message);
3009
2590
  * } else {
3010
- * console.log("Registration successful:", data.user.first_name);
3011
- * console.log("User ID:", data.user.id);
3012
- * console.log("Access token:", data.access_token);
2591
+ * console.log("OTP token:", data.otp_token);
2592
+ * console.log("Action:", data.otp_action);
3013
2593
  * }
3014
2594
  * ```
3015
2595
  */
3016
- async registerWithPhone(body) {
3017
- return this.executeRequest(() => this.client.POST("/auth/register/phone", { body }));
2596
+ async registerWithPhone(body, headers) {
2597
+ const mergedHeaders = this.mergeHeaders(headers);
2598
+ return this.executeRequest(() => this.client.POST("/auth/register/phone", {
2599
+ body,
2600
+ params: { header: mergedHeaders }
2601
+ }));
3018
2602
  }
3019
2603
  /**
3020
2604
  * Register with email
3021
2605
  *
3022
2606
  * @param body - Registration details including email and user information
3023
- * @returns Promise with user info and tokens
2607
+ * @param headers - Optional header parameters (for example `x-debug-mode`)
2608
+ * @returns Promise with OTP token and action for completing registration
3024
2609
  * @example
3025
2610
  * ```typescript
3026
2611
  * // Register a new user with email address
@@ -3034,28 +2619,92 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3034
2619
  * if (error) {
3035
2620
  * console.error("Email registration failed:", error.message);
3036
2621
  * } else {
3037
- * console.log("Registration successful:", data.user.email);
3038
- * console.log("User ID:", data.user.id);
3039
- * console.log("Access token:", data.access_token);
2622
+ * console.log("OTP token:", data.otp_token);
2623
+ * console.log("Action:", data.otp_action);
3040
2624
  * }
3041
2625
  * ```
3042
2626
  */
3043
- async registerWithEmail(body) {
3044
- return this.executeRequest(() => this.client.POST("/auth/register/email", { body }));
2627
+ async registerWithEmail(body, headers) {
2628
+ const mergedHeaders = this.mergeHeaders(headers);
2629
+ return this.executeRequest(() => this.client.POST("/auth/register/email", {
2630
+ body,
2631
+ params: { header: mergedHeaders }
2632
+ }));
3045
2633
  }
3046
2634
  /**
3047
- * Refresh the access token using a refresh token
3048
- * @param body - Request body containing the refresh token
3049
- * @returns Promise with the new access token and refresh token
2635
+ * Register with WhatsApp
2636
+ *
2637
+ * @param body - Registration details including WhatsApp number and user information
2638
+ * @param headers - Optional header parameters (for example `x-debug-mode`)
2639
+ * @returns Promise with OTP token and action for completing registration
3050
2640
  * @example
3051
2641
  * ```typescript
3052
- * // Refresh access token when it expires
3053
- * const { data, error } = await sdk.auth.refreshToken({
3054
- * refresh_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
3055
- * });
3056
- *
3057
- * if (error) {
3058
- * console.error("Token refresh failed:", error.message);
2642
+ * // Register a new user with WhatsApp number
2643
+ * const { data, error } = await sdk.auth.registerWithWhatsapp({
2644
+ * phone: "9876543210",
2645
+ * country_code: "+91",
2646
+ * first_name: "John",
2647
+ * last_name: "Doe",
2648
+ * email: "john.doe@example.com"
2649
+ * });
2650
+ *
2651
+ * if (error) {
2652
+ * console.error("WhatsApp registration failed:", error.message);
2653
+ * } else {
2654
+ * console.log("OTP token:", data.otp_token);
2655
+ * console.log("Action:", data.otp_action);
2656
+ * }
2657
+ * ```
2658
+ */
2659
+ async registerWithWhatsapp(body, headers) {
2660
+ const mergedHeaders = this.mergeHeaders(headers);
2661
+ return this.executeRequest(() => this.client.POST("/auth/register/whatsapp", {
2662
+ body,
2663
+ params: { header: mergedHeaders }
2664
+ }));
2665
+ }
2666
+ /**
2667
+ * Register with password
2668
+ *
2669
+ * @param body - Registration details including email or phone and password
2670
+ * @param headers - Optional header parameters (for example `x-debug-mode`)
2671
+ * @returns Promise with OTP token and action for completing registration
2672
+ * @example
2673
+ * ```typescript
2674
+ * const { data, error } = await sdk.auth.registerWithPassword({
2675
+ * email: "jane.smith@example.com",
2676
+ * password: "securePassword123",
2677
+ * confirm_password: "securePassword123",
2678
+ * });
2679
+ *
2680
+ * if (error) {
2681
+ * console.error("Password registration failed:", error.message);
2682
+ * } else {
2683
+ * console.log("OTP token:", data.otp_token);
2684
+ * console.log("Action:", data.otp_action);
2685
+ * }
2686
+ * ```
2687
+ */
2688
+ async registerWithPassword(body, headers) {
2689
+ const mergedHeaders = this.mergeHeaders(headers);
2690
+ return this.executeRequest(() => this.client.POST("/auth/register/password", {
2691
+ body,
2692
+ params: { header: mergedHeaders }
2693
+ }));
2694
+ }
2695
+ /**
2696
+ * Refresh the access token using a refresh token
2697
+ * @param body - Request body containing the refresh token
2698
+ * @returns Promise with the new access token and refresh token
2699
+ * @example
2700
+ * ```typescript
2701
+ * // Refresh access token when it expires
2702
+ * const { data, error } = await sdk.auth.refreshToken({
2703
+ * refresh_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
2704
+ * });
2705
+ *
2706
+ * if (error) {
2707
+ * console.error("Token refresh failed:", error.message);
3059
2708
  * // Redirect to login
3060
2709
  * } else {
3061
2710
  * console.log("Token refreshed successfully");
@@ -3310,90 +2959,6 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3310
2959
  return this.executeRequest(() => this.client.PUT("/auth/user/{id}/deactivate", { params: { path: pathParams } }));
3311
2960
  }
3312
2961
  /**
3313
- * Get user notification preferences
3314
- *
3315
- * @param pathParams - Path parameters containing user ID
3316
- * @returns Promise with user's notification preferences
3317
- * @example
3318
- * ```typescript
3319
- * // Get user's notification preferences
3320
- * const { data, error } = await sdk.auth.getUserNotificationPreferences({
3321
- * id: "01H9XYZ12345USERID"
3322
- * });
3323
- *
3324
- * if (error) {
3325
- * console.error("Failed to get preferences:", error.message);
3326
- * } else {
3327
- * console.log("Notification preferences:", data.notification_preferences);
3328
- * }
3329
- * ```
3330
- */
3331
- async getUserNotificationPreferences(pathParams) {
3332
- return this.executeRequest(() => this.client.GET("/auth/user/{id}/notification-preferences", { params: { path: pathParams } }));
3333
- }
3334
- /**
3335
- * Update user notification preferences
3336
- *
3337
- * @param pathParams - Path parameters containing user ID
3338
- * @param body - Updated notification preferences
3339
- * @returns Promise with updated notification preferences
3340
- * @example
3341
- * ```typescript
3342
- * // Update user's notification preferences
3343
- * const { data, error } = await sdk.auth.updateUserNotificationPreferences(
3344
- * { id: "01H9XYZ12345USERID" },
3345
- * {
3346
- * email_notifications: true,
3347
- * sms_notifications: false,
3348
- * push_notifications: true
3349
- * }
3350
- * );
3351
- *
3352
- * if (error) {
3353
- * console.error("Failed to update preferences:", error.message);
3354
- * } else {
3355
- * console.log("Preferences updated successfully");
3356
- * }
3357
- * ```
3358
- */
3359
- async updateUserNotificationPreferences(pathParams, body) {
3360
- return this.executeRequest(() => this.client.PUT("/auth/user/{id}/notification-preferences", {
3361
- params: { path: pathParams },
3362
- body
3363
- }));
3364
- }
3365
- /**
3366
- * Create user notification preference
3367
- *
3368
- * @param pathParams - Path parameters containing user ID
3369
- * @param body - Notification preferences to create
3370
- * @returns Promise with created notification preferences
3371
- * @example
3372
- * ```typescript
3373
- * // Create notification preferences for a user
3374
- * const { data, error } = await sdk.auth.createUserNotificationPreference(
3375
- * { id: "01H9XYZ12345USERID" },
3376
- * {
3377
- * email_notifications: true,
3378
- * sms_notifications: true,
3379
- * push_notifications: false
3380
- * }
3381
- * );
3382
- *
3383
- * if (error) {
3384
- * console.error("Failed to create preferences:", error.message);
3385
- * } else {
3386
- * console.log("Preferences created successfully");
3387
- * }
3388
- * ```
3389
- */
3390
- async createUserNotificationPreference(pathParams, body) {
3391
- return this.executeRequest(() => this.client.POST("/auth/user/{id}/notification-preferences", {
3392
- params: { path: pathParams },
3393
- body
3394
- }));
3395
- }
3396
- /**
3397
2962
  * Generate OTP
3398
2963
  *
3399
2964
  * @param body - OTP generation body (phone or email)
@@ -3453,7 +3018,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3453
3018
  /**
3454
3019
  * Client for interacting with order endpoints
3455
3020
  */
3456
- var OrderClient = class extends StorefrontAPIClient {
3021
+ var OrderClient = class extends SessionStorefrontAPIClient {
3457
3022
  /**
3458
3023
  * Get order details
3459
3024
  *
@@ -3584,41 +3149,9 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3584
3149
  async createOrder(body) {
3585
3150
  return this.executeRequest(() => this.client.POST("/orders", { body }));
3586
3151
  }
3587
- /**
3588
- * List all orders
3589
- *
3590
- * @param queryParams - Query parameters for filtering and pagination
3591
- * @returns Promise with order list
3592
- * @example
3593
- * ```typescript
3594
- * // Basic usage - only required parameter
3595
- * const { data, error } = await sdk.order.listOrders({
3596
- * user_id: "user_01H9XYZ12345ABCDE"
3597
- * });
3598
- *
3599
- * // Advanced usage with optional parameters
3600
- * const { data, error } = await sdk.order.listOrders({
3601
- * user_id: "user_01H9XYZ12345ABCDE",
3602
- * page: 1,
3603
- * limit: 20,
3604
- * sort_by: '{"created_at":"desc"}',
3605
- * status: ["confirmed", "shipped", "delivered"]
3606
- * });
3607
- *
3608
- * if (error) {
3609
- * console.error("Failed to list orders:", error.message);
3610
- * } else {
3611
- * console.log("Orders found:", data.orders?.length || 0);
3612
- * console.log("Pagination:", data.pagination);
3613
- *
3614
- * data.orders?.forEach(order => {
3615
- * console.log(`Order ${order.order_number}: ${order.status}`);
3616
- * });
3617
- * }
3618
- * ```
3619
- */
3620
- async listOrders(queryParams) {
3621
- return this.executeRequest(() => this.client.GET("/orders", { params: { query: queryParams } }));
3152
+ async listOrders(queryParams = {}) {
3153
+ const resolvedQueryParams = await this.resolveUserQueryParams(queryParams);
3154
+ return this.executeRequest(() => this.client.GET("/orders", { params: { query: resolvedQueryParams } }));
3622
3155
  }
3623
3156
  /**
3624
3157
  * Get payment status for an order
@@ -3849,7 +3382,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3849
3382
  /**
3850
3383
  * Client for interacting with payment endpoints
3851
3384
  */
3852
- var PaymentsClient = class extends StorefrontAPIClient {
3385
+ var PaymentsClient = class extends SessionStorefrontAPIClient {
3853
3386
  /**
3854
3387
  * List all available payment methods
3855
3388
  *
@@ -3991,474 +3524,1094 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
3991
3524
  }
3992
3525
  };
3993
3526
 
3527
+ //#endregion
3528
+ //#region src/lib/shared/helper.ts
3529
+ /**
3530
+ * Client for interacting with helper endpoints
3531
+ */
3532
+ var BaseHelpersClient = class extends StorefrontAPIClientBase {
3533
+ /**
3534
+ * Get a list of countries
3535
+ *
3536
+ * @returns Promise with countries
3537
+ *
3538
+ * @example
3539
+ * ```typescript
3540
+ * const { data, error } = await sdk.helpers.listCountries();
3541
+ *
3542
+ * if (error) {
3543
+ * console.error("Failed to get countries:", error);
3544
+ * return;
3545
+ * }
3546
+ *
3547
+ * console.log("Countries found:", data.countries?.length || 0);
3548
+ *
3549
+ * data.countries?.forEach(country => {
3550
+ * console.log(`Country: ${country.country_name} (${country.country_iso_code})`);
3551
+ * console.log("Currency:", country.currency_code);
3552
+ * });
3553
+ * ```
3554
+ */
3555
+ async listCountries() {
3556
+ return this.executeRequest(() => this.client.GET("/common/countries", {}));
3557
+ }
3558
+ /**
3559
+ * Get a list of states for a country
3560
+ *
3561
+ * @param pathParams - Path parameters
3562
+ * @returns Promise with states
3563
+ *
3564
+ * @example
3565
+ * ```typescript
3566
+ * const { data, error } = await sdk.helpers.listCountryStates({
3567
+ * country_iso_code: "IN"
3568
+ * });
3569
+ *
3570
+ * if (error) {
3571
+ * console.error("Failed to get states:", error);
3572
+ * return;
3573
+ * }
3574
+ *
3575
+ * console.log("States found:", data.states?.length || 0);
3576
+ *
3577
+ * data.states?.forEach(state => {
3578
+ * console.log(`State: ${state.name} (${state.iso_code})`);
3579
+ * });
3580
+ *
3581
+ * // Get states for different country
3582
+ * const { data: usStates, error: usError } = await sdk.helpers.listCountryStates({
3583
+ * country_iso_code: "US"
3584
+ * });
3585
+ *
3586
+ * if (usError) {
3587
+ * console.error("Failed to get US states:", usError);
3588
+ * return;
3589
+ * }
3590
+ *
3591
+ * console.log("US States:", usStates.states?.map(s => s.name).join(", "));
3592
+ * ```
3593
+ */
3594
+ async listCountryStates(pathParams) {
3595
+ return this.executeRequest(() => this.client.GET("/common/countries/{country_iso_code}/states", { params: { path: pathParams } }));
3596
+ }
3597
+ /**
3598
+ * Get pincodes for a country
3599
+ *
3600
+ * @param pathParams - Path parameters
3601
+ * @returns Promise with pincodes
3602
+ *
3603
+ * @example
3604
+ * ```typescript
3605
+ * const { data, error } = await sdk.helpers.listCountryPincodes({
3606
+ * country_iso_code: "IN"
3607
+ * });
3608
+ *
3609
+ * if (error) {
3610
+ * console.error("Failed to get pincodes:", error);
3611
+ * return;
3612
+ * }
3613
+ *
3614
+ * console.log("Pincodes found:", data.pincodes?.length || 0);
3615
+ *
3616
+ * data.pincodes?.forEach(pincode => {
3617
+ * console.log(`Pincode: ${pincode.pincode} - ${pincode.city}, ${pincode.state_name}`);
3618
+ * });
3619
+ *
3620
+ * // Get pincodes for different country
3621
+ * const { data: usPincodes, error: usError } = await sdk.helpers.listCountryPincodes({
3622
+ * country_iso_code: "US"
3623
+ * });
3624
+ *
3625
+ * if (usError) {
3626
+ * console.error("Failed to get US pincodes:", usError);
3627
+ * return;
3628
+ * }
3629
+ *
3630
+ * console.log("US Pincodes:", usPincodes.pincodes?.map(p => p.pincode).join(", "));
3631
+ * ```
3632
+ */
3633
+ async listCountryPincodes(pathParams, queryParams) {
3634
+ return this.executeRequest(() => this.client.GET("/common/countries/{country_iso_code}/pincodes", { params: {
3635
+ path: pathParams,
3636
+ query: queryParams
3637
+ } }));
3638
+ }
3639
+ };
3640
+
3641
+ //#endregion
3642
+ //#region src/lib/public/helper.ts
3643
+ /**
3644
+ * Client for interacting with helper endpoints
3645
+ */
3646
+ var PublicHelpersClient = class extends BaseHelpersClient {
3647
+ constructor(config) {
3648
+ super(config);
3649
+ attachPublicAuth(this);
3650
+ }
3651
+ };
3652
+
3994
3653
  //#endregion
3995
3654
  //#region src/lib/helper.ts
3996
3655
  /**
3997
3656
  * Client for interacting with helper endpoints
3998
3657
  */
3999
- var HelpersClient = class extends StorefrontAPIClient {
3658
+ var HelpersClient = class extends BaseHelpersClient {
3659
+ constructor(config) {
3660
+ super(config);
3661
+ attachSessionAuth(this, config.sessionManager);
3662
+ }
3663
+ };
3664
+
3665
+ //#endregion
3666
+ //#region src/lib/customer.ts
3667
+ /**
3668
+ * Client for interacting with customer endpoints
3669
+ */
3670
+ var CustomerClient = class extends SessionStorefrontAPIClient {
3671
+ async listAddresses(pathParamsOrQuery, queryParams) {
3672
+ const hasPathParams = queryParams !== void 0 || !!pathParamsOrQuery && typeof pathParamsOrQuery === "object" && "customer_id" in pathParamsOrQuery;
3673
+ const pathParams = hasPathParams ? pathParamsOrQuery : {};
3674
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3675
+ const resolvedQueryParams = hasPathParams ? queryParams : pathParamsOrQuery;
3676
+ return this.executeRequest(() => this.client.GET("/customers/{customer_id}/addresses", { params: {
3677
+ path: resolvedPathParams,
3678
+ query: resolvedQueryParams
3679
+ } }));
3680
+ }
3681
+ async createAddress(pathParamsOrBody, maybeBody) {
3682
+ const pathParams = maybeBody ? pathParamsOrBody : {};
3683
+ const body = maybeBody ?? pathParamsOrBody;
3684
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3685
+ return this.executeRequest(() => this.client.POST("/customers/{customer_id}/addresses", {
3686
+ params: { path: resolvedPathParams },
3687
+ body
3688
+ }));
3689
+ }
3690
+ async getAddress(pathParams) {
3691
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3692
+ return this.executeRequest(() => this.client.GET("/customers/{customer_id}/addresses/{address_id}", { params: { path: resolvedPathParams } }));
3693
+ }
3694
+ async updateAddress(pathParams, body) {
3695
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3696
+ return this.executeRequest(() => this.client.PUT("/customers/{customer_id}/addresses/{address_id}", {
3697
+ params: { path: resolvedPathParams },
3698
+ body
3699
+ }));
3700
+ }
3701
+ async deleteAddress(pathParams) {
3702
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3703
+ return this.executeRequest(() => this.client.DELETE("/customers/{customer_id}/addresses/{address_id}", { params: { path: resolvedPathParams } }));
3704
+ }
3705
+ async getLoyaltyDetails(pathParams = {}) {
3706
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3707
+ return this.executeRequest(() => this.client.GET("/customers/{customer_id}/loyalty", { params: { path: resolvedPathParams } }));
3708
+ }
3709
+ async listLoyaltyPointsActivity(pathParamsOrQuery, queryParams) {
3710
+ const hasPathParams = queryParams !== void 0 || !!pathParamsOrQuery && typeof pathParamsOrQuery === "object" && "customer_id" in pathParamsOrQuery;
3711
+ const pathParams = hasPathParams ? pathParamsOrQuery : {};
3712
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3713
+ const resolvedQueryParams = hasPathParams ? queryParams : pathParamsOrQuery;
3714
+ return this.executeRequest(() => this.client.GET("/customers/{customer_id}/loyalty-points-activity", { params: {
3715
+ path: resolvedPathParams,
3716
+ query: resolvedQueryParams
3717
+ } }));
3718
+ }
3719
+ async listCustomerReviews(pathParams = {}) {
3720
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3721
+ return this.executeRequest(() => this.client.GET("/customers/{customer_id}/reviews", { params: { path: resolvedPathParams } }));
3722
+ }
3723
+ async listSavedPaymentMethods(pathParams = {}, queryParams) {
3724
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3725
+ return this.executeRequest(() => this.client.GET("/customers/{customer_id}/payment-methods", { params: {
3726
+ path: resolvedPathParams,
3727
+ query: queryParams
3728
+ } }));
3729
+ }
3730
+ async listCustomerCards(pathParams = {}) {
3731
+ const resolvedPathParams = await this.resolveCustomerPathParams(pathParams);
3732
+ return this.executeRequest(() => this.client.GET("/customers/{customer_id}/cards", { params: { path: resolvedPathParams } }));
3733
+ }
3734
+ };
3735
+
3736
+ //#endregion
3737
+ //#region src/lib/shared/store-config.ts
3738
+ /**
3739
+ * Client for interacting with store config endpoints
3740
+ */
3741
+ var BaseStoreConfigClient = class extends StorefrontAPIClientBase {
3742
+ /**
3743
+ * Check store existence
3744
+ *
3745
+ * @description Checks whether a store with the configured store ID exists.
3746
+ * Returns `success: true` if the store exists, `false` otherwise.
3747
+ *
3748
+ * @returns Promise with store existence check result
3749
+ * @example
3750
+ * ```typescript
3751
+ * const { data, error } = await sdk.store.checkStore();
3752
+ *
3753
+ * if (error) {
3754
+ * console.error("Failed to check store:", error.message);
3755
+ * } else {
3756
+ * console.log("Store exists:", data.success);
3757
+ * }
3758
+ * ```
3759
+ */
3760
+ async checkStore() {
3761
+ return this.executeRequest(() => this.client.GET("/store/check"));
3762
+ }
3763
+ /**
3764
+ * Get store config
3765
+ *
3766
+ * @returns Promise with store configuration data
3767
+ *
3768
+ * @example
3769
+ * ```typescript
3770
+ * const { data, error } = await sdk.store.getStoreConfig();
3771
+ *
3772
+ * if (error) {
3773
+ * console.error('Failed to get store config:', error.message);
3774
+ * return;
3775
+ * }
3776
+ *
3777
+ * // Access store configuration data
3778
+ * const storeConfig = data.store_config;
3779
+ * console.log('Store brand:', storeConfig.brand.name);
3780
+ * console.log('Currency:', storeConfig.currency.code);
3781
+ * console.log('KYC enabled:', storeConfig.is_kyc_enabled);
3782
+ * console.log('Customer groups enabled:', storeConfig.is_customer_group_enabled);
3783
+ * ```
3784
+ */
3785
+ async getStoreConfig() {
3786
+ return this.executeRequest(() => this.client.GET("/store/config"));
3787
+ }
3788
+ };
3789
+
3790
+ //#endregion
3791
+ //#region src/lib/public/store-config.ts
3792
+ /**
3793
+ * Client for interacting with store config endpoints
3794
+ */
3795
+ var PublicStoreConfigClient = class extends BaseStoreConfigClient {
3796
+ constructor(config) {
3797
+ super(config);
3798
+ attachPublicAuth(this);
3799
+ }
3800
+ };
3801
+
3802
+ //#endregion
3803
+ //#region src/lib/store-config.ts
3804
+ /**
3805
+ * Client for interacting with store config endpoints
3806
+ */
3807
+ var StoreConfigClient = class extends BaseStoreConfigClient {
3808
+ constructor(config) {
3809
+ super(config);
3810
+ attachSessionAuth(this, config.sessionManager);
3811
+ }
3812
+ };
3813
+
3814
+ //#endregion
3815
+ //#region src/lib/storage/token-storage.ts
3816
+ /**
3817
+ * Simple in-memory token storage implementation
3818
+ */
3819
+ var MemoryTokenStorage = class {
3820
+ accessToken = null;
3821
+ refreshToken = null;
3822
+ async getAccessToken() {
3823
+ return this.accessToken;
3824
+ }
3825
+ async setAccessToken(token) {
3826
+ this.accessToken = token;
3827
+ }
3828
+ async getRefreshToken() {
3829
+ return this.refreshToken;
3830
+ }
3831
+ async setRefreshToken(token) {
3832
+ this.refreshToken = token;
3833
+ }
3834
+ async clearTokens() {
3835
+ this.accessToken = null;
3836
+ this.refreshToken = null;
3837
+ }
3838
+ };
3839
+ /**
3840
+ * Browser localStorage token storage implementation
3841
+ */
3842
+ var BrowserTokenStorage = class {
3843
+ accessTokenKey;
3844
+ refreshTokenKey;
3845
+ constructor(prefix = "storefront_") {
3846
+ this.accessTokenKey = `${prefix}access_token`;
3847
+ this.refreshTokenKey = `${prefix}refresh_token`;
3848
+ }
3849
+ async getAccessToken() {
3850
+ if (typeof localStorage === "undefined") return null;
3851
+ return localStorage.getItem(this.accessTokenKey);
3852
+ }
3853
+ async setAccessToken(token) {
3854
+ if (typeof localStorage !== "undefined") localStorage.setItem(this.accessTokenKey, token);
3855
+ }
3856
+ async getRefreshToken() {
3857
+ if (typeof localStorage === "undefined") return null;
3858
+ return localStorage.getItem(this.refreshTokenKey);
3859
+ }
3860
+ async setRefreshToken(token) {
3861
+ if (typeof localStorage !== "undefined") localStorage.setItem(this.refreshTokenKey, token);
3862
+ }
3863
+ async clearTokens() {
3864
+ if (typeof localStorage !== "undefined") {
3865
+ localStorage.removeItem(this.accessTokenKey);
3866
+ localStorage.removeItem(this.refreshTokenKey);
3867
+ }
3868
+ }
3869
+ };
3870
+ /**
3871
+ * Cookie-based token storage implementation
3872
+ */
3873
+ var CookieTokenStorage = class {
3874
+ accessTokenKey;
3875
+ refreshTokenKey;
3876
+ options;
3877
+ constructor(options = {}) {
3878
+ const prefix = options.prefix || "storefront_";
3879
+ this.accessTokenKey = `${prefix}access_token`;
3880
+ this.refreshTokenKey = `${prefix}refresh_token`;
3881
+ this.options = {
3882
+ maxAge: options.maxAge || 10080 * 60,
3883
+ path: options.path || "/",
3884
+ domain: options.domain,
3885
+ secure: options.secure ?? (typeof window !== "undefined" && window.location?.protocol === "https:"),
3886
+ sameSite: options.sameSite || "Lax",
3887
+ httpOnly: false
3888
+ };
3889
+ }
3890
+ async getAccessToken() {
3891
+ return this.getCookie(this.accessTokenKey);
3892
+ }
3893
+ async setAccessToken(token) {
3894
+ this.setCookie(this.accessTokenKey, token);
3895
+ }
3896
+ async getRefreshToken() {
3897
+ return this.getCookie(this.refreshTokenKey);
3898
+ }
3899
+ async setRefreshToken(token) {
3900
+ this.setCookie(this.refreshTokenKey, token);
3901
+ }
3902
+ async clearTokens() {
3903
+ this.deleteCookie(this.accessTokenKey);
3904
+ this.deleteCookie(this.refreshTokenKey);
3905
+ }
3906
+ getCookie(name) {
3907
+ if (typeof document === "undefined") return null;
3908
+ const parts = `; ${document.cookie}`.split(`; ${name}=`);
3909
+ if (parts.length === 2) {
3910
+ const cookieValue = parts.pop()?.split(";").shift();
3911
+ return cookieValue ? decodeURIComponent(cookieValue) : null;
3912
+ }
3913
+ return null;
3914
+ }
3915
+ setCookie(name, value) {
3916
+ if (typeof document === "undefined") return;
3917
+ let cookieString = `${name}=${encodeURIComponent(value)}`;
3918
+ if (this.options.maxAge) cookieString += `; Max-Age=${this.options.maxAge}`;
3919
+ if (this.options.path) cookieString += `; Path=${this.options.path}`;
3920
+ if (this.options.domain) cookieString += `; Domain=${this.options.domain}`;
3921
+ if (this.options.secure) cookieString += `; Secure`;
3922
+ if (this.options.sameSite) cookieString += `; SameSite=${this.options.sameSite}`;
3923
+ document.cookie = cookieString;
3924
+ }
3925
+ deleteCookie(name) {
3926
+ if (typeof document === "undefined") return;
3927
+ let cookieString = `${name}=; Max-Age=0`;
3928
+ if (this.options.path) cookieString += `; Path=${this.options.path}`;
3929
+ if (this.options.domain) cookieString += `; Domain=${this.options.domain}`;
3930
+ document.cookie = cookieString;
3931
+ }
3932
+ };
3933
+
3934
+ //#endregion
3935
+ //#region src/lib/session/jwt-utils.ts
3936
+ /**
3937
+ * Decode a JWT token payload without signature verification.
3938
+ * This is a lightweight replacement for jose's decodeJwt.
3939
+ *
3940
+ * @param token - The JWT token to decode
3941
+ * @returns The decoded payload
3942
+ * @throws Error if the token is malformed
3943
+ */
3944
+ function decodeJwt(token) {
3945
+ if (typeof token !== "string") throw new Error("Invalid token: must be a string");
3946
+ const parts = token.split(".");
3947
+ if (parts.length !== 3) throw new Error("Invalid token: must have 3 parts");
3948
+ const base64Url = parts[1];
3949
+ if (!base64Url) throw new Error("Invalid token: missing payload");
3950
+ let base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
3951
+ const padding = base64.length % 4;
3952
+ if (padding) base64 += "=".repeat(4 - padding);
3953
+ const binaryStr = atob(base64);
3954
+ const bytes = new Uint8Array(binaryStr.length);
3955
+ for (let i = 0; i < binaryStr.length; i++) bytes[i] = binaryStr.charCodeAt(i);
3956
+ const payload = JSON.parse(new TextDecoder().decode(bytes));
3957
+ if (typeof payload !== "object" || payload === null) throw new Error("Invalid token: payload must be an object");
3958
+ return payload;
3959
+ }
3960
+ /**
3961
+ * Decode and extract user information from a JWT token
3962
+ *
3963
+ * @param token - The JWT token to decode
3964
+ * @returns User information or null if token is invalid
3965
+ */
3966
+ function extractUserInfoFromToken(token) {
3967
+ try {
3968
+ const payload = decodeJwt(token);
3969
+ return {
3970
+ id: payload.ulid,
3971
+ email: payload.email,
3972
+ phone: payload.phone,
3973
+ username: payload.username,
3974
+ firstName: payload.first_name,
3975
+ lastName: payload.last_name,
3976
+ storeId: payload.store_id,
3977
+ isLoggedIn: payload.is_logged_in,
3978
+ isAnonymous: payload.is_anonymous,
3979
+ customerId: payload.customer_id,
3980
+ customerGroupId: payload.customer_group_id,
3981
+ anonymousId: payload.anonymous_id,
3982
+ channel: payload.channel,
3983
+ tokenExpiry: /* @__PURE__ */ new Date(payload.exp * 1e3),
3984
+ tokenIssuedAt: /* @__PURE__ */ new Date(payload.iat * 1e3)
3985
+ };
3986
+ } catch (error) {
3987
+ console.warn("Failed to decode JWT token:", error);
3988
+ return null;
3989
+ }
3990
+ }
3991
+ /**
3992
+ * Check if a JWT token is expired
3993
+ *
3994
+ * @param token - The JWT token to check
3995
+ * @param bufferSeconds - Buffer time in seconds (default: 30)
3996
+ * @returns True if token is expired or will expire within buffer time
3997
+ */
3998
+ function isTokenExpired(token, bufferSeconds = 30) {
3999
+ try {
4000
+ const payload = decodeJwt(token);
4001
+ if (!payload.exp) return true;
4002
+ return Math.floor(Date.now() / 1e3) >= payload.exp - bufferSeconds;
4003
+ } catch (error) {
4004
+ console.warn("Failed to decode JWT token:", error);
4005
+ return true;
4006
+ }
4007
+ }
4008
+ /**
4009
+ * Get the user ID from a JWT token
4010
+ *
4011
+ * @param token - The JWT token
4012
+ * @returns User ID (ulid) or null if token is invalid
4013
+ */
4014
+ function getUserIdFromToken(token) {
4015
+ return extractUserInfoFromToken(token)?.id || null;
4016
+ }
4017
+ /**
4018
+ * Check if user is logged in based on JWT token
4019
+ *
4020
+ * @param token - The JWT token
4021
+ * @returns True if user is logged in, false otherwise
4022
+ */
4023
+ function isUserLoggedIn(token) {
4024
+ return extractUserInfoFromToken(token)?.isLoggedIn || false;
4025
+ }
4026
+ /**
4027
+ * Check if user is anonymous based on JWT token
4028
+ *
4029
+ * @param token - The JWT token
4030
+ * @returns True if user is anonymous, false otherwise
4031
+ */
4032
+ function isUserAnonymous(token) {
4033
+ return extractUserInfoFromToken(token)?.isAnonymous ?? true;
4034
+ }
4035
+
4036
+ //#endregion
4037
+ //#region src/types/auth-operation-metadata.ts
4038
+ const API_KEY_ONLY_OPERATIONS = [
4039
+ {
4040
+ method: "POST",
4041
+ path: "/auth/anonymous"
4042
+ },
4043
+ {
4044
+ method: "GET",
4045
+ path: "/common/countries"
4046
+ },
4047
+ {
4048
+ method: "GET",
4049
+ path: "/common/countries/{country_iso_code}/pincodes"
4050
+ },
4051
+ {
4052
+ method: "GET",
4053
+ path: "/common/countries/{country_iso_code}/states"
4054
+ },
4055
+ {
4056
+ method: "GET",
4057
+ path: "/store/check"
4058
+ },
4059
+ {
4060
+ method: "GET",
4061
+ path: "/store/config"
4062
+ },
4063
+ {
4064
+ method: "GET",
4065
+ path: "/store/kyc-document"
4066
+ },
4067
+ {
4068
+ method: "GET",
4069
+ path: "/store/sellers/{id}"
4070
+ },
4071
+ {
4072
+ method: "GET",
4073
+ path: "/store/sellers/{id}/reviews"
4074
+ }
4075
+ ];
4076
+
4077
+ //#endregion
4078
+ //#region src/lib/session/auth-utils.ts
4079
+ const TOKEN_RETURNING_OPERATIONS = [
4080
+ {
4081
+ method: "POST",
4082
+ path: "/auth/change-password"
4083
+ },
4084
+ {
4085
+ method: "POST",
4086
+ path: "/auth/login/password"
4087
+ },
4088
+ {
4089
+ method: "POST",
4090
+ path: "/auth/reset-password"
4091
+ },
4092
+ {
4093
+ method: "POST",
4094
+ path: "/auth/verify-otp"
4095
+ },
4096
+ {
4097
+ method: "POST",
4098
+ path: "/auth/refresh-token"
4099
+ },
4100
+ {
4101
+ method: "POST",
4102
+ path: "/auth/logout"
4103
+ }
4104
+ ];
4105
+ const ANONYMOUS_AUTH_OPERATION = {
4106
+ method: "POST",
4107
+ path: "/auth/anonymous"
4108
+ };
4109
+ function normalizeMethod(method) {
4110
+ return method.toUpperCase();
4111
+ }
4112
+ function normalizePathname(pathname) {
4113
+ let normalizedPathname = pathname;
4114
+ const storefrontMarkerIndex = normalizedPathname.indexOf("/storefront");
4115
+ if (storefrontMarkerIndex !== -1) normalizedPathname = normalizedPathname.slice(storefrontMarkerIndex + 11) || "/";
4116
+ if (normalizedPathname.length > 1 && normalizedPathname.endsWith("/")) return normalizedPathname.slice(0, -1);
4117
+ return normalizedPathname;
4118
+ }
4119
+ function matchesPathTemplate(pathTemplate, pathname) {
4120
+ const normalizedTemplate = normalizePathname(pathTemplate);
4121
+ const normalizedPathname = normalizePathname(pathname);
4122
+ const templateSegments = normalizedTemplate.split("/").filter(Boolean);
4123
+ const pathSegments = normalizedPathname.split("/").filter(Boolean);
4124
+ if (templateSegments.length !== pathSegments.length) return false;
4125
+ return templateSegments.every((templateSegment, index) => {
4126
+ if (templateSegment.startsWith("{") && templateSegment.endsWith("}")) return true;
4127
+ return templateSegment === pathSegments[index];
4128
+ });
4129
+ }
4130
+ function matchesOperation(method, pathname, operation) {
4131
+ return normalizeMethod(method) === operation.method && matchesPathTemplate(operation.path, pathname);
4132
+ }
4133
+ function matchesOperationList(method, pathname, operations) {
4134
+ return operations.some((operation) => matchesOperation(method, pathname, operation));
4135
+ }
4136
+ /**
4137
+ * Check if a method+path pair is the anonymous auth operation.
4138
+ */
4139
+ function isAnonymousAuthOperation(method, pathname) {
4140
+ return matchesOperation(method, pathname, ANONYMOUS_AUTH_OPERATION);
4141
+ }
4142
+ /**
4143
+ * Check if a method+path pair requires API key only authentication.
4144
+ */
4145
+ function isApiKeyOnlyOperation(method, pathname) {
4146
+ return matchesOperationList(method, pathname, API_KEY_ONLY_OPERATIONS);
4147
+ }
4148
+ /**
4149
+ * Check if a method+path pair returns tokens in a successful response.
4150
+ */
4151
+ function isTokenReturningOperation(method, pathname) {
4152
+ return matchesOperationList(method, pathname, TOKEN_RETURNING_OPERATIONS);
4153
+ }
4154
+
4155
+ //#endregion
4156
+ //#region src/lib/session/manager.ts
4157
+ /**
4158
+ * Internal per-SDK session controller.
4159
+ *
4160
+ * A single instance is shared by all API clients created from the same
4161
+ * `SessionStorefrontSDK`. This keeps refresh locks, token assessment, and session
4162
+ * bootstrap logic coordinated in one place while preserving optional manual
4163
+ * token management when `tokenStorage` is not provided.
4164
+ */
4165
+ var StorefrontSessionManager = class {
4166
+ tokenStorage;
4167
+ onTokensUpdated;
4168
+ onTokensCleared;
4169
+ baseUrl;
4170
+ refreshTokenFn;
4171
+ apiKey;
4172
+ accessToken;
4173
+ refreshToken;
4174
+ initializationPromise = null;
4175
+ refreshPromise = null;
4176
+ bootstrapPromise = null;
4177
+ hasAssessedTokens = false;
4178
+ constructor(options) {
4179
+ this.tokenStorage = options.tokenStorage;
4180
+ this.baseUrl = options.baseUrl;
4181
+ this.apiKey = options.apiKey;
4182
+ this.onTokensUpdated = options.onTokensUpdated;
4183
+ this.onTokensCleared = options.onTokensCleared;
4184
+ this.accessToken = options.accessToken ?? null;
4185
+ this.refreshToken = options.refreshToken ?? null;
4186
+ this.refreshTokenFn = options.refreshTokenFn;
4187
+ if (this.tokenStorage && this.accessToken) this.initializationPromise = this.initializeManagedTokens(this.accessToken, this.refreshToken);
4188
+ }
4189
+ /**
4190
+ * Update the API key used by session bootstrap and refresh flows.
4191
+ */
4192
+ setApiKey(apiKey) {
4193
+ this.apiKey = apiKey;
4194
+ }
4195
+ /**
4196
+ * Remove the API key used by session bootstrap and refresh flows.
4197
+ */
4198
+ clearApiKey() {
4199
+ this.apiKey = void 0;
4200
+ }
4000
4201
  /**
4001
- * Get a list of countries
4002
- *
4003
- * @returns Promise with countries
4004
- *
4005
- * @example
4006
- * ```typescript
4007
- * const { data, error } = await sdk.helpers.listCountries();
4008
- *
4009
- * if (error) {
4010
- * console.error("Failed to get countries:", error);
4011
- * return;
4012
- * }
4013
- *
4014
- * console.log("Countries found:", data.countries?.length || 0);
4202
+ * Create the auth middleware used by each API client.
4015
4203
  *
4016
- * data.countries?.forEach(country => {
4017
- * console.log(`Country: ${country.country_name} (${country.country_iso_code})`);
4018
- * console.log("Currency:", country.currency_code);
4019
- * });
4020
- * ```
4204
+ * The returned middleware shares the same session state and refresh locking
4205
+ * across all clients attached to a single `SessionStorefrontSDK` instance.
4021
4206
  */
4022
- async listCountries() {
4023
- return this.executeRequest(() => this.client.GET("/common/countries", {}));
4207
+ createAuthMiddleware() {
4208
+ return {
4209
+ onRequest: async ({ request }) => this.handleRequest(request),
4210
+ onResponse: async ({ request, response }) => this.handleResponse(request, response)
4211
+ };
4024
4212
  }
4025
4213
  /**
4026
- * Get a list of states for a country
4027
- *
4028
- * @param pathParams - Path parameters
4029
- * @returns Promise with states
4030
- *
4031
- * @example
4032
- * ```typescript
4033
- * const { data, error } = await sdk.helpers.listCountryStates({
4034
- * country_iso_code: "IN"
4035
- * });
4036
- *
4037
- * if (error) {
4038
- * console.error("Failed to get states:", error);
4039
- * return;
4040
- * }
4041
- *
4042
- * console.log("States found:", data.states?.length || 0);
4043
- *
4044
- * data.states?.forEach(state => {
4045
- * console.log(`State: ${state.name} (${state.iso_code})`);
4046
- * });
4047
- *
4048
- * // Get states for different country
4049
- * const { data: usStates, error: usError } = await sdk.helpers.listCountryStates({
4050
- * country_iso_code: "US"
4051
- * });
4052
- *
4053
- * if (usError) {
4054
- * console.error("Failed to get US states:", usError);
4055
- * return;
4056
- * }
4214
+ * Read the current authorization header without creating a new session.
4057
4215
  *
4058
- * console.log("US States:", usStates.states?.map(s => s.name).join(", "));
4059
- * ```
4216
+ * @returns A `Bearer` header value, or an empty string when no token exists
4060
4217
  */
4061
- async listCountryStates(pathParams) {
4062
- return this.executeRequest(() => this.client.GET("/common/countries/{country_iso_code}/states", { params: { path: pathParams } }));
4218
+ async getAuthorizationHeader() {
4219
+ const token = await this.peekAccessToken();
4220
+ return token ? `Bearer ${token}` : "";
4063
4221
  }
4064
4222
  /**
4065
- * Get pincodes for a country
4066
- *
4067
- * @param pathParams - Path parameters
4068
- * @returns Promise with pincodes
4069
- *
4070
- * @example
4071
- * ```typescript
4072
- * const { data, error } = await sdk.helpers.listCountryPincodes({
4073
- * country_iso_code: "IN"
4074
- * });
4075
- *
4076
- * if (error) {
4077
- * console.error("Failed to get pincodes:", error);
4078
- * return;
4079
- * }
4080
- *
4081
- * console.log("Pincodes found:", data.pincodes?.length || 0);
4082
- *
4083
- * data.pincodes?.forEach(pincode => {
4084
- * console.log(`Pincode: ${pincode.pincode} - ${pincode.city}, ${pincode.state_name}`);
4085
- * });
4086
- *
4087
- * // Get pincodes for different country
4088
- * const { data: usPincodes, error: usError } = await sdk.helpers.listCountryPincodes({
4089
- * country_iso_code: "US"
4090
- * });
4223
+ * Persist new session tokens.
4091
4224
  *
4092
- * if (usError) {
4093
- * console.error("Failed to get US pincodes:", usError);
4094
- * return;
4095
- * }
4096
- *
4097
- * console.log("US Pincodes:", usPincodes.pincodes?.map(p => p.pincode).join(", "));
4098
- * ```
4225
+ * In managed mode, tokens are written to the configured token storage. In
4226
+ * manual mode, they are stored in memory for header injection and session
4227
+ * inspection.
4099
4228
  */
4100
- async listCountryPincodes(pathParams, queryParams) {
4101
- return this.executeRequest(() => this.client.GET("/common/countries/{country_iso_code}/pincodes", { params: {
4102
- path: pathParams,
4103
- query: queryParams
4104
- } }));
4229
+ async setTokens(accessToken, refreshToken) {
4230
+ const previousTokens = await this.getCurrentTokenState();
4231
+ if (this.tokenStorage) {
4232
+ await this.awaitInitialization();
4233
+ await this.storeManagedTokens(accessToken, refreshToken ?? null);
4234
+ } else {
4235
+ this.accessToken = accessToken;
4236
+ if (refreshToken) {
4237
+ this.refreshToken = refreshToken;
4238
+ console.warn("Refresh token provided but automatic refresh is disabled because tokenStorage is not configured.");
4239
+ }
4240
+ }
4241
+ const nextTokens = await this.getCurrentTokenState();
4242
+ this.notifyTokensUpdatedIfChanged(previousTokens, nextTokens);
4105
4243
  }
4106
- };
4107
-
4108
- //#endregion
4109
- //#region src/lib/customer.ts
4110
- /**
4111
- * Client for interacting with customer endpoints
4112
- */
4113
- var CustomerClient = class extends StorefrontAPIClient {
4114
4244
  /**
4115
- * Get all saved addresses for a customer
4116
- *
4117
- * @param pathParams - Path parameters
4118
- * @returns Promise with addresses
4119
- *
4120
- * @example
4121
- * ```typescript
4122
- * const { data, error } = await sdk.customer.listAddresses({
4123
- * user_id: "user_456"
4124
- * });
4125
- *
4126
- * if (error) {
4127
- * console.error("Failed to list addresses:", error);
4128
- * return;
4129
- * }
4130
- *
4131
- * console.log("Addresses:", data.addresses);
4132
- * console.log("Pagination:", data.pagination);
4133
- *
4134
- * // With pagination
4135
- * const { data: page2, error: page2Error } = await sdk.customer.listAddresses({
4136
- * user_id: "user_456",
4137
- * page: 2,
4138
- * limit: 10
4139
- * });
4140
- * ```
4245
+ * Clear all session tokens managed by this controller.
4141
4246
  */
4142
- async listAddresses(pathParams, queryParams) {
4143
- return this.executeRequest(() => this.client.GET("/customers/{user_id}/addresses", { params: {
4144
- path: pathParams,
4145
- query: queryParams
4146
- } }));
4247
+ async clearTokens() {
4248
+ if (this.tokenStorage) {
4249
+ await this.awaitInitialization();
4250
+ await this.tokenStorage.clearTokens();
4251
+ } else {
4252
+ this.accessToken = null;
4253
+ this.refreshToken = null;
4254
+ }
4255
+ this.onTokensCleared?.();
4147
4256
  }
4148
4257
  /**
4149
- * Create a new address for a customer
4150
- *
4151
- * @param pathParams - Path parameters
4152
- * @param body - Address creation body
4153
- * @returns Promise with address details
4154
- *
4155
- * @example
4156
- * ```typescript
4157
- * const { data, error } = await sdk.customer.createAddress(
4158
- * { user_id: "user_456" },
4159
- * {
4160
- * address_line1: "123 Main Street",
4161
- * address_line2: "Apt 4B",
4162
- * city: "New York",
4163
- * state: "NY",
4164
- * country: "US",
4165
- * pincode: "10001",
4166
- * is_default_billing: true,
4167
- * is_default_shipping: false
4168
- * }
4169
- * );
4170
- *
4171
- * if (error) {
4172
- * console.error("Failed to create address:", error);
4173
- * return;
4174
- * }
4175
- *
4176
- * console.log("Address created:", data.address);
4177
- * ```
4258
+ * Clear all session tokens through the public session interface.
4178
4259
  */
4179
- async createAddress(pathParams, body) {
4180
- return this.executeRequest(() => this.client.POST("/customers/{user_id}/addresses", {
4181
- params: { path: pathParams },
4182
- body
4183
- }));
4260
+ async clear() {
4261
+ await this.clearTokens();
4262
+ }
4263
+ async peekAccessToken() {
4264
+ await this.awaitInitialization();
4265
+ if (this.tokenStorage) return this.tokenStorage.getAccessToken();
4266
+ return this.accessToken;
4267
+ }
4268
+ async peekRefreshToken() {
4269
+ await this.awaitInitialization();
4270
+ if (this.tokenStorage) return this.tokenStorage.getRefreshToken();
4271
+ return this.refreshToken;
4272
+ }
4273
+ async peekUserInfo() {
4274
+ const token = await this.peekAccessToken();
4275
+ if (!token) return null;
4276
+ return extractUserInfoFromToken(token);
4277
+ }
4278
+ async peekUserId() {
4279
+ const token = await this.peekAccessToken();
4280
+ if (!token) return null;
4281
+ return getUserIdFromToken(token);
4282
+ }
4283
+ async peekCustomerId() {
4284
+ return (await this.peekUserInfo())?.customerId ?? null;
4285
+ }
4286
+ async peekCustomerGroupId() {
4287
+ return (await this.peekUserInfo())?.customerGroupId ?? null;
4288
+ }
4289
+ async ensureAccessToken() {
4290
+ const token = await this.getOrCreateAccessToken();
4291
+ if (!token) throw new Error("No session available. Configure tokenStorage + apiKey for automatic session management, or call setTokens() to set tokens manually.");
4292
+ return token;
4293
+ }
4294
+ async ensureUserInfo() {
4295
+ const userInfo = extractUserInfoFromToken(await this.ensureAccessToken());
4296
+ if (!userInfo) throw new Error("Failed to extract user information from access token.");
4297
+ return userInfo;
4298
+ }
4299
+ async ensureUserId() {
4300
+ const userId = getUserIdFromToken(await this.ensureAccessToken());
4301
+ if (!userId) throw new Error("Failed to extract user ID from access token.");
4302
+ return userId;
4303
+ }
4304
+ async ensureCustomerId() {
4305
+ const userInfo = await this.ensureUserInfo();
4306
+ if (!userInfo.customerId) throw new Error("No customer_id available. User must be logged in (not anonymous) for this operation. Pass customer_id explicitly or log in first.");
4307
+ return userInfo.customerId;
4308
+ }
4309
+ async handleRequest(request) {
4310
+ const method = request.method;
4311
+ const pathname = getPathnameFromUrl(request.url);
4312
+ if (this.tokenStorage) await this.assessTokenStateOnce();
4313
+ if (isAnonymousAuthOperation(method, pathname)) return this.prepareAnonymousAuthRequest(request);
4314
+ if (isApiKeyOnlyOperation(method, pathname)) {
4315
+ this.applyApiKeyHeader(request);
4316
+ return request;
4317
+ }
4318
+ const accessToken = await this.getOrCreateAccessToken();
4319
+ if (accessToken) request.headers.set("Authorization", `Bearer ${accessToken}`);
4320
+ return request;
4321
+ }
4322
+ async handleResponse(request, response) {
4323
+ if (!this.tokenStorage) return response;
4324
+ const method = request.method;
4325
+ const pathname = getPathnameFromUrl(request.url);
4326
+ if (response.ok) {
4327
+ await this.captureTokensFromResponse(method, pathname, response);
4328
+ return response;
4329
+ }
4330
+ if (response.status === 401 && !isAnonymousAuthOperation(method, pathname) && !isApiKeyOnlyOperation(method, pathname)) {
4331
+ const currentToken = await this.peekAccessToken();
4332
+ if (currentToken && isTokenExpired(currentToken, 0)) try {
4333
+ await this.refreshTokens();
4334
+ const refreshedToken = await this.peekAccessToken();
4335
+ if (refreshedToken) {
4336
+ const retryRequest = request.clone();
4337
+ retryRequest.headers.set("Authorization", `Bearer ${refreshedToken}`);
4338
+ return fetch(retryRequest);
4339
+ }
4340
+ } catch (error) {
4341
+ console.warn("Token refresh failed on 401 response:", error);
4342
+ }
4343
+ }
4344
+ return response;
4345
+ }
4346
+ async prepareAnonymousAuthRequest(request) {
4347
+ this.applyApiKeyHeader(request);
4348
+ const existingToken = await this.peekAccessToken();
4349
+ if (this.tokenStorage && existingToken && !isTokenExpired(existingToken) && isUserLoggedIn(existingToken)) return new Response(JSON.stringify({
4350
+ message: "Cannot create anonymous session while authenticated",
4351
+ success: false,
4352
+ code: "USER_ALREADY_AUTHENTICATED"
4353
+ }), {
4354
+ status: 400,
4355
+ headers: { "Content-Type": "application/json" }
4356
+ });
4357
+ if (existingToken) request.headers.set("Authorization", `Bearer ${existingToken}`);
4358
+ return request;
4359
+ }
4360
+ applyApiKeyHeader(request) {
4361
+ if (this.apiKey) request.headers.set("X-Api-Key", this.apiKey);
4184
4362
  }
4185
4363
  /**
4186
- * Get an address for a customer
4187
- *
4188
- * @param pathParams - Path parameters
4189
- * @returns Promise with address details
4190
- *
4191
- * @example
4192
- * ```typescript
4193
- * const { data, error } = await sdk.customer.getAddress({
4194
- * user_id: "user_456",
4195
- * address_id: "addr_789"
4196
- * });
4197
- *
4198
- * if (error) {
4199
- * console.error("Failed to get address:", error);
4200
- * return;
4201
- * }
4202
- *
4203
- * console.log("Address details:", data.address);
4204
- * ```
4364
+ * Snapshot the effective token pair from storage (managed mode) or
4365
+ * in-memory fields (manual mode). Used before and after `setTokens()` to
4366
+ * detect whether the tokens actually changed.
4205
4367
  */
4206
- async getAddress(pathParams) {
4207
- return this.executeRequest(() => this.client.GET("/customers/{user_id}/addresses/{address_id}", { params: { path: pathParams } }));
4368
+ async getCurrentTokenState() {
4369
+ await this.awaitInitialization();
4370
+ if (this.tokenStorage) return {
4371
+ accessToken: await this.tokenStorage.getAccessToken(),
4372
+ refreshToken: await this.tokenStorage.getRefreshToken()
4373
+ };
4374
+ return {
4375
+ accessToken: this.accessToken,
4376
+ refreshToken: this.refreshToken
4377
+ };
4378
+ }
4379
+ /**
4380
+ * Fire `onTokensUpdated` only when the effective token pair differs from
4381
+ * the previous snapshot. This prevents duplicate notifications when
4382
+ * `setTokens()` is called with the same values already in storage.
4383
+ */
4384
+ notifyTokensUpdatedIfChanged(previousTokens, nextTokens) {
4385
+ if (!this.onTokensUpdated || !nextTokens.accessToken) return;
4386
+ if (previousTokens.accessToken === nextTokens.accessToken && previousTokens.refreshToken === nextTokens.refreshToken) return;
4387
+ this.onTokensUpdated(nextTokens.accessToken, nextTokens.refreshToken ?? "");
4388
+ }
4389
+ /**
4390
+ * Internal token acquisition — returns null on failure instead of throwing.
4391
+ * Used by middleware so requests degrade gracefully.
4392
+ */
4393
+ async getOrCreateAccessToken() {
4394
+ if (!this.tokenStorage) return this.peekAccessToken();
4395
+ await this.awaitInitialization();
4396
+ await this.assessTokenStateOnce();
4397
+ let accessToken = await this.tokenStorage.getAccessToken();
4398
+ if (!accessToken) accessToken = await this.bootstrapAnonymousSession();
4399
+ if (accessToken && isTokenExpired(accessToken)) try {
4400
+ await this.refreshTokens();
4401
+ accessToken = await this.tokenStorage.getAccessToken();
4402
+ } catch {
4403
+ accessToken = await this.tokenStorage.getAccessToken();
4404
+ }
4405
+ return accessToken;
4406
+ }
4407
+ async initializeManagedTokens(accessToken, refreshToken) {
4408
+ try {
4409
+ await this.storeManagedTokens(accessToken, refreshToken);
4410
+ } catch (error) {
4411
+ console.warn("Failed to initialize tokens in storage:", error);
4412
+ } finally {
4413
+ this.accessToken = null;
4414
+ this.refreshToken = null;
4415
+ }
4416
+ }
4417
+ async awaitInitialization() {
4418
+ if (this.initializationPromise) {
4419
+ await this.initializationPromise;
4420
+ this.initializationPromise = null;
4421
+ }
4422
+ }
4423
+ async assessTokenStateOnce() {
4424
+ if (!this.tokenStorage || this.hasAssessedTokens) return;
4425
+ this.hasAssessedTokens = true;
4426
+ try {
4427
+ const accessToken = await this.tokenStorage.getAccessToken();
4428
+ const refreshToken = await this.tokenStorage.getRefreshToken();
4429
+ if (!accessToken && refreshToken) {
4430
+ await this.tokenStorage.clearTokens();
4431
+ console.info("Cleaned up orphaned refresh token");
4432
+ }
4433
+ } catch (error) {
4434
+ console.warn("Token state assessment failed:", error);
4435
+ }
4436
+ }
4437
+ async bootstrapAnonymousSession() {
4438
+ if (!this.tokenStorage) return null;
4439
+ if (this.bootstrapPromise) return this.bootstrapPromise;
4440
+ this.bootstrapPromise = (async () => {
4441
+ try {
4442
+ const response = await fetch(`${this.baseUrl}/auth/anonymous`, {
4443
+ method: "POST",
4444
+ headers: {
4445
+ "Content-Type": "application/json",
4446
+ ...this.apiKey && { "X-Api-Key": this.apiKey }
4447
+ }
4448
+ });
4449
+ if (!response.ok) return null;
4450
+ const tokens = (await response.json()).content;
4451
+ if (tokens?.access_token && tokens?.refresh_token) {
4452
+ await this.storeManagedTokens(tokens.access_token, tokens.refresh_token);
4453
+ this.onTokensUpdated?.(tokens.access_token, tokens.refresh_token);
4454
+ console.info("Automatically created anonymous session for first API request");
4455
+ return tokens.access_token;
4456
+ }
4457
+ return null;
4458
+ } catch (error) {
4459
+ console.warn("Failed to automatically create anonymous tokens:", error);
4460
+ return null;
4461
+ } finally {
4462
+ this.bootstrapPromise = null;
4463
+ }
4464
+ })();
4465
+ return this.bootstrapPromise;
4466
+ }
4467
+ async refreshTokens() {
4468
+ if (!this.tokenStorage) return;
4469
+ const tokenStorage = this.tokenStorage;
4470
+ if (this.refreshPromise) return this.refreshPromise;
4471
+ this.refreshPromise = (async () => {
4472
+ try {
4473
+ const refreshToken = await tokenStorage.getRefreshToken();
4474
+ let newTokens;
4475
+ if (refreshToken && !isTokenExpired(refreshToken)) if (this.refreshTokenFn) newTokens = await this.refreshTokenFn(refreshToken);
4476
+ else {
4477
+ const response = await fetch(`${this.baseUrl}/auth/refresh-token`, {
4478
+ method: "POST",
4479
+ headers: { "Content-Type": "application/json" },
4480
+ body: JSON.stringify({ refresh_token: refreshToken })
4481
+ });
4482
+ if (!response.ok) throw new Error(`Token refresh failed: ${response.status}`);
4483
+ newTokens = (await response.json()).content;
4484
+ }
4485
+ else {
4486
+ const currentAccessToken = await tokenStorage.getAccessToken();
4487
+ if (!currentAccessToken) throw new Error("No tokens available for refresh");
4488
+ const reason = refreshToken ? "refresh token expired" : "no refresh token available";
4489
+ const response = await fetch(`${this.baseUrl}/auth/anonymous`, {
4490
+ method: "POST",
4491
+ headers: {
4492
+ "Content-Type": "application/json",
4493
+ ...this.apiKey && { "X-Api-Key": this.apiKey },
4494
+ Authorization: `Bearer ${currentAccessToken}`
4495
+ }
4496
+ });
4497
+ if (!response.ok) throw new Error(`Anonymous token fallback failed: ${response.status}`);
4498
+ newTokens = (await response.json()).content;
4499
+ console.info(`Token refreshed via anonymous fallback (${reason}) - user may need to re-authenticate for privileged operations`);
4500
+ }
4501
+ await this.storeManagedTokens(newTokens.access_token, newTokens.refresh_token);
4502
+ this.onTokensUpdated?.(newTokens.access_token, newTokens.refresh_token);
4503
+ } catch (error) {
4504
+ console.error("Token refresh failed:", error);
4505
+ await this.clearTokens();
4506
+ throw error;
4507
+ } finally {
4508
+ this.refreshPromise = null;
4509
+ }
4510
+ })();
4511
+ return this.refreshPromise;
4512
+ }
4513
+ async captureTokensFromResponse(method, pathname, response) {
4514
+ if (!this.tokenStorage || !(isTokenReturningOperation(method, pathname) || isAnonymousAuthOperation(method, pathname))) return;
4515
+ try {
4516
+ const content = (await response.clone().json()).content;
4517
+ if (content?.access_token && content?.refresh_token) {
4518
+ await this.storeManagedTokens(content.access_token, content.refresh_token);
4519
+ this.onTokensUpdated?.(content.access_token, content.refresh_token);
4520
+ }
4521
+ } catch (error) {
4522
+ console.warn("Failed to extract tokens from response:", error);
4523
+ }
4208
4524
  }
4209
- /**
4210
- * Update an address for a customer
4211
- *
4212
- * @param pathParams - Path parameters
4213
- * @param body - Address update body
4214
- * @returns Promise with address details
4215
- *
4216
- * @example
4217
- * ```typescript
4218
- * const { data, error } = await sdk.customer.updateAddress(
4219
- * {
4220
- * user_id: "user_456",
4221
- * address_id: "addr_789"
4222
- * },
4223
- * {
4224
- * address_line1: "456 Oak Avenue",
4225
- * city: "Los Angeles",
4226
- * state: "CA",
4227
- * pincode: "90210"
4228
- * }
4229
- * );
4230
- *
4231
- * if (error) {
4232
- * console.error("Failed to update address:", error);
4233
- * return;
4234
- * }
4235
- *
4236
- * console.log("Address updated:", data.address);
4237
- * ```
4238
- */
4239
- async updateAddress(pathParams, body) {
4240
- return this.executeRequest(() => this.client.PUT("/customers/{user_id}/addresses/{address_id}", {
4241
- params: { path: pathParams },
4242
- body
4243
- }));
4525
+ async storeManagedTokens(accessToken, refreshToken) {
4526
+ if (!this.tokenStorage) return;
4527
+ await this.tokenStorage.setAccessToken(accessToken);
4528
+ if (refreshToken) await this.tokenStorage.setRefreshToken(refreshToken);
4244
4529
  }
4530
+ };
4531
+
4532
+ //#endregion
4533
+ //#region src/index.ts
4534
+ /**
4535
+ * Public SDK class for the Storefront API.
4536
+ *
4537
+ * This surface is intentionally limited to API-key-backed, public read
4538
+ * operations so it can be used safely during build and prerender flows.
4539
+ */
4540
+ var PublicStorefrontSDK = class {
4245
4541
  /**
4246
- * Delete an address for a customer
4247
- *
4248
- * @param pathParams - Path parameters
4249
- * @returns Promise with deletion response
4250
- *
4251
- * @example
4252
- * ```typescript
4253
- * const { data, error } = await sdk.customer.deleteAddress({
4254
- * user_id: "user_456",
4255
- * address_id: "addr_789"
4256
- * });
4257
- *
4258
- * if (error) {
4259
- * console.error("Failed to delete address:", error);
4260
- * return;
4261
- * }
4262
- *
4263
- * console.log("Address deleted:", data.message);
4264
- * ```
4542
+ * Client for catalog-related read-only endpoints
4265
4543
  */
4266
- async deleteAddress(pathParams) {
4267
- return this.executeRequest(() => this.client.DELETE("/customers/{user_id}/addresses/{address_id}", { params: { path: pathParams } }));
4268
- }
4544
+ catalog;
4269
4545
  /**
4270
- * Get customer loyalty details
4271
- *
4272
- * @param pathParams - Path parameters
4273
- * @returns Promise with loyalty details
4274
- *
4275
- * @example
4276
- * ```typescript
4277
- * const { data, error } = await sdk.customer.getLoyaltyDetails({
4278
- * user_id: "user_456"
4279
- * });
4280
- *
4281
- * if (error) {
4282
- * console.error("Failed to get loyalty details:", error);
4283
- * return;
4284
- * }
4285
- *
4286
- * console.log("Loyalty info:", data.loyalty);
4287
- * console.log("Points balance:", data.loyalty_point_balance);
4288
- * ```
4546
+ * Client for helper-related endpoints
4289
4547
  */
4290
- async getLoyaltyDetails(pathParams) {
4291
- return this.executeRequest(() => this.client.GET("/customers/{user_id}/loyalty", { params: { path: pathParams } }));
4292
- }
4548
+ helpers;
4293
4549
  /**
4294
- * List all loyalty points activity for a customer
4295
- *
4296
- * @param pathParams - Path parameters
4297
- * @returns Promise with loyalty points activity
4298
- *
4299
- * @example
4300
- * ```typescript
4301
- * const { data, error } = await sdk.customer.listLoyaltyPointsActivity({
4302
- * user_id: "user_456"
4303
- * });
4304
- *
4305
- * if (error) {
4306
- * console.error("Failed to get loyalty activity:", error);
4307
- * return;
4308
- * }
4309
- *
4310
- * console.log("Loyalty activity:", data.loyalty_points_activity);
4311
- *
4312
- * // With pagination and sorting
4313
- * const { data: sortedData, error: sortedError } = await sdk.customer.listLoyaltyPointsActivity({
4314
- * user_id: "user_456",
4315
- * page: 1,
4316
- * limit: 20,
4317
- * sort_by: JSON.stringify({ "created_at": "desc" })
4318
- * });
4319
- * ```
4550
+ * Client for store config-related endpoints
4320
4551
  */
4321
- async listLoyaltyPointsActivity(pathParams, queryParams) {
4322
- return this.executeRequest(() => this.client.GET("/customers/{user_id}/loyalty-points-activity", { params: {
4323
- path: pathParams,
4324
- query: queryParams
4325
- } }));
4326
- }
4552
+ store;
4327
4553
  /**
4328
- * List all reviews left by a customer
4329
- *
4330
- * @param pathParams - Path parameters
4331
- * @returns Promise with reviews
4332
- *
4333
- * @example
4334
- * ```typescript
4335
- * const { data, error } = await sdk.customer.listCustomerReviews({
4336
- * user_id: "user_456"
4337
- * });
4338
- *
4339
- * if (error) {
4340
- * console.error("Failed to get customer reviews:", error);
4341
- * return;
4342
- * }
4343
- *
4344
- * console.log("Customer reviews:", data.reviews);
4345
- * console.log("Ready for review:", data.ready_for_review);
4346
- * ```
4554
+ * Centrally stored default headers for consistency
4347
4555
  */
4348
- async listCustomerReviews(pathParams) {
4349
- return this.executeRequest(() => this.client.GET("/customers/{user_id}/reviews", { params: { path: pathParams } }));
4556
+ defaultHeaders;
4557
+ constructor(options) {
4558
+ this.defaultHeaders = options.defaultHeaders;
4559
+ const config = {
4560
+ storeId: options.storeId,
4561
+ environment: options.environment,
4562
+ baseUrl: options.baseUrl,
4563
+ apiKey: options.apiKey,
4564
+ timeout: options.timeout,
4565
+ defaultHeaders: options.defaultHeaders,
4566
+ debug: options.debug,
4567
+ logger: options.logger
4568
+ };
4569
+ this.catalog = new PublicCatalogClient(config);
4570
+ this.helpers = new PublicHelpersClient(config);
4571
+ this.store = new PublicStoreConfigClient(config);
4350
4572
  }
4351
4573
  /**
4352
- * List all saved payment methods for a customer
4353
- *
4354
- * @param pathParams - Path parameters
4355
- * @returns Promise with payment methods
4574
+ * Set the API key for all public clients
4356
4575
  *
4357
- * @example
4358
- * ```typescript
4359
- * const { data, error } = await sdk.customer.listSavedPaymentMethods({
4360
- * customer_id: "customer_123"
4361
- * });
4362
- *
4363
- * if (error) {
4364
- * console.error("Failed to list saved payment methods:", error);
4365
- * return;
4366
- * }
4367
- *
4368
- * console.log("Saved payment methods:", data.saved_payment_methods);
4369
- * ```
4576
+ * @param apiKey - The API key to set
4370
4577
  */
4371
- async listSavedPaymentMethods(pathParams, queryParams) {
4372
- return this.executeRequest(() => this.client.GET("/customers/{customer_id}/payment-methods", { params: {
4373
- path: pathParams,
4374
- query: queryParams
4375
- } }));
4578
+ setApiKey(apiKey) {
4579
+ this.catalog.setApiKey(apiKey);
4580
+ this.helpers.setApiKey(apiKey);
4581
+ this.store.setApiKey(apiKey);
4376
4582
  }
4377
4583
  /**
4378
- * List all saved cards for a customer
4379
- *
4380
- * @param pathParams - Path parameters
4381
- * @returns Promise with cards
4382
- *
4383
- * @example
4384
- * ```typescript
4385
- * const { data, error } = await sdk.customer.listCustomerCards({
4386
- * customer_id: "customer_123"
4387
- * });
4388
- *
4389
- * if (error) {
4390
- * console.error("Failed to list customer cards:", error);
4391
- * return;
4392
- * }
4393
- *
4394
- * console.log("Customer cards:", data.cards);
4395
- * ```
4584
+ * Clear the API key from all public clients
4396
4585
  */
4397
- async listCustomerCards(pathParams) {
4398
- return this.executeRequest(() => this.client.GET("/customers/{customer_id}/cards", { params: { path: pathParams } }));
4586
+ clearApiKey() {
4587
+ this.catalog.clearApiKey();
4588
+ this.helpers.clearApiKey();
4589
+ this.store.clearApiKey();
4399
4590
  }
4400
- };
4401
-
4402
- //#endregion
4403
- //#region src/lib/store-config.ts
4404
- /**
4405
- * Client for interacting with store config endpoints
4406
- */
4407
- var StoreConfigClient = class extends StorefrontAPIClient {
4408
4591
  /**
4409
- * Check store existence
4410
- *
4411
- * @description Checks whether a store with the configured store ID exists.
4412
- * Returns `success: true` if the store exists, `false` otherwise.
4413
- *
4414
- * @returns Promise with store existence check result
4415
- * @example
4416
- * ```typescript
4417
- * const { data, error } = await sdk.storeConfig.checkStore();
4592
+ * Set default headers for all public clients
4418
4593
  *
4419
- * if (error) {
4420
- * console.error("Failed to check store:", error.message);
4421
- * } else {
4422
- * console.log("Store exists:", data.success);
4423
- * }
4424
- * ```
4594
+ * @param headers - Default headers to set (only supported headers allowed)
4425
4595
  */
4426
- async checkStore() {
4427
- return this.executeRequest(() => this.client.GET("/store/check"));
4596
+ setDefaultHeaders(headers) {
4597
+ this.defaultHeaders = headers;
4598
+ this.catalog.setDefaultHeaders(headers);
4599
+ this.helpers.setDefaultHeaders(headers);
4600
+ this.store.setDefaultHeaders(headers);
4428
4601
  }
4429
4602
  /**
4430
- * Get store config
4431
- *
4432
- * @returns Promise with store configuration data
4433
- *
4434
- * @example
4435
- * ```typescript
4436
- * const { data, error } = await sdk.storeConfig.getStoreConfig();
4437
- *
4438
- * if (error) {
4439
- * console.error('Failed to get store config:', error.message);
4440
- * return;
4441
- * }
4603
+ * Get current default headers
4442
4604
  *
4443
- * // Access store configuration data
4444
- * const storeConfig = data.store_config;
4445
- * console.log('Store brand:', storeConfig.brand.name);
4446
- * console.log('Currency:', storeConfig.currency.code);
4447
- * console.log('KYC enabled:', storeConfig.is_kyc_enabled);
4448
- * console.log('Customer groups enabled:', storeConfig.is_customer_group_enabled);
4449
- * ```
4605
+ * @returns Current default headers from central storage (always consistent)
4450
4606
  */
4451
- async getStoreConfig() {
4452
- return this.executeRequest(() => this.client.GET("/store/config"));
4607
+ getDefaultHeaders() {
4608
+ return this.defaultHeaders;
4453
4609
  }
4454
4610
  };
4455
-
4456
- //#endregion
4457
- //#region src/index.ts
4458
- /**
4459
- * Main SDK class for the Storefront API
4611
+ /**
4612
+ * Main session-aware SDK class for the Storefront API
4460
4613
  */
4461
- var StorefrontSDK = class {
4614
+ var SessionStorefrontSDK = class {
4462
4615
  /**
4463
4616
  * Client for catalog-related endpoints (products, categories, etc.)
4464
4617
  */
@@ -4496,12 +4649,33 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
4496
4649
  */
4497
4650
  defaultHeaders;
4498
4651
  /**
4499
- * Create a new StorefrontSDK instance
4652
+ * Shared session helper and coordinator for all API clients in this SDK instance.
4653
+ */
4654
+ session;
4655
+ sessionManager;
4656
+ /**
4657
+ * Create a new SessionStorefrontSDK instance
4500
4658
  *
4501
4659
  * @param options - Configuration options for the SDK
4502
4660
  */
4503
4661
  constructor(options) {
4504
4662
  this.defaultHeaders = options.defaultHeaders;
4663
+ const sessionManager = new StorefrontSessionManager({
4664
+ accessToken: options.accessToken,
4665
+ apiKey: options.apiKey,
4666
+ baseUrl: buildStorefrontURL({
4667
+ storeId: options.storeId,
4668
+ environment: options.environment,
4669
+ baseUrl: options.baseUrl
4670
+ }),
4671
+ onTokensCleared: options.onTokensCleared,
4672
+ onTokensUpdated: options.onTokensUpdated,
4673
+ refreshToken: options.refreshToken,
4674
+ refreshTokenFn: options.refreshTokenFn,
4675
+ tokenStorage: options.tokenStorage
4676
+ });
4677
+ this.sessionManager = sessionManager;
4678
+ this.session = sessionManager;
4505
4679
  const config = {
4506
4680
  storeId: options.storeId,
4507
4681
  environment: options.environment,
@@ -4515,7 +4689,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
4515
4689
  onTokensCleared: options.onTokensCleared,
4516
4690
  defaultHeaders: options.defaultHeaders,
4517
4691
  debug: options.debug,
4518
- logger: options.logger
4692
+ logger: options.logger,
4693
+ sessionManager
4519
4694
  };
4520
4695
  this.catalog = new CatalogClient(config);
4521
4696
  this.cart = new CartClient(config);
@@ -4537,14 +4712,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
4537
4712
  * - If tokenStorage is not provided: Only stores access token for manual management
4538
4713
  */
4539
4714
  async setTokens(accessToken, refreshToken) {
4540
- await this.catalog.setTokens(accessToken, refreshToken);
4541
- await this.cart.setTokens(accessToken, refreshToken);
4542
- await this.auth.setTokens(accessToken, refreshToken);
4543
- await this.customer.setTokens(accessToken, refreshToken);
4544
- await this.helpers.setTokens(accessToken, refreshToken);
4545
- await this.order.setTokens(accessToken, refreshToken);
4546
- await this.payments.setTokens(accessToken, refreshToken);
4547
- await this.store.setTokens(accessToken, refreshToken);
4715
+ await this.sessionManager.setTokens(accessToken, refreshToken);
4548
4716
  }
4549
4717
  /**
4550
4718
  * Clear all authentication tokens from all clients
@@ -4554,14 +4722,7 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
4554
4722
  * - If tokenStorage is not provided: Clears the manual access token
4555
4723
  */
4556
4724
  async clearTokens() {
4557
- await this.catalog.clearTokens();
4558
- await this.cart.clearTokens();
4559
- await this.auth.clearTokens();
4560
- await this.customer.clearTokens();
4561
- await this.helpers.clearTokens();
4562
- await this.order.clearTokens();
4563
- await this.payments.clearTokens();
4564
- await this.store.clearTokens();
4725
+ await this.sessionManager.clearTokens();
4565
4726
  }
4566
4727
  /**
4567
4728
  * Set the API key for all clients
@@ -4569,57 +4730,58 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
4569
4730
  * @param apiKey - The API key to set
4570
4731
  */
4571
4732
  setApiKey(apiKey) {
4572
- this.catalog.setApiKey(apiKey);
4573
- this.cart.setApiKey(apiKey);
4574
- this.auth.setApiKey(apiKey);
4575
- this.customer.setApiKey(apiKey);
4576
- this.helpers.setApiKey(apiKey);
4577
- this.order.setApiKey(apiKey);
4578
- this.payments.setApiKey(apiKey);
4579
- this.store.setApiKey(apiKey);
4733
+ this.sessionManager.setApiKey(apiKey);
4580
4734
  }
4581
4735
  /**
4582
4736
  * Clear the API key from all clients
4583
4737
  */
4584
4738
  clearApiKey() {
4585
- this.catalog.clearApiKey();
4586
- this.cart.clearApiKey();
4587
- this.auth.clearApiKey();
4588
- this.customer.clearApiKey();
4589
- this.helpers.clearApiKey();
4590
- this.order.clearApiKey();
4591
- this.payments.clearApiKey();
4592
- this.store.clearApiKey();
4739
+ this.sessionManager.clearApiKey();
4593
4740
  }
4594
4741
  /**
4595
4742
  * Get the current access token if using token storage
4743
+ *
4744
+ * This is a passive lookup. It will not create or refresh a session.
4596
4745
  */
4597
4746
  async getAccessToken() {
4598
- return await this.auth.getAuthorizationHeader().then((header) => header.startsWith("Bearer ") ? header.substring(7) : null);
4747
+ return this.session.peekAccessToken();
4748
+ }
4749
+ /**
4750
+ * Ensure an access token is available for the current session.
4751
+ *
4752
+ * This may create or refresh a managed session when automatic token
4753
+ * management is configured.
4754
+ *
4755
+ * @returns A usable access token
4756
+ */
4757
+ async ensureAccessToken() {
4758
+ return this.session.ensureAccessToken();
4599
4759
  }
4600
4760
  /**
4601
4761
  * Get user information from the current access token
4602
4762
  *
4763
+ * This is a passive lookup. It will not create or refresh a session.
4764
+ *
4603
4765
  * @returns User information extracted from JWT token, or null if no token or invalid token
4604
4766
  */
4605
4767
  async getUserInfo() {
4606
- const token = await this.getAccessToken();
4607
- if (!token) return null;
4608
- return extractUserInfoFromToken(token);
4768
+ return this.session.peekUserInfo();
4609
4769
  }
4610
4770
  /**
4611
4771
  * Get the current user ID from the access token
4612
4772
  *
4773
+ * This is a passive lookup. It will not create or refresh a session.
4774
+ *
4613
4775
  * @returns User ID (ulid) or null if no token or invalid token
4614
4776
  */
4615
4777
  async getUserId() {
4616
- const token = await this.getAccessToken();
4617
- if (!token) return null;
4618
- return getUserIdFromToken(token);
4778
+ return this.session.peekUserId();
4619
4779
  }
4620
4780
  /**
4621
4781
  * Check if the current user is logged in (not anonymous)
4622
4782
  *
4783
+ * This is a passive lookup. It will not create or refresh a session.
4784
+ *
4623
4785
  * @returns True if user is logged in, false if anonymous or no token
4624
4786
  */
4625
4787
  async isLoggedIn() {
@@ -4630,6 +4792,8 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
4630
4792
  /**
4631
4793
  * Check if the current user is anonymous
4632
4794
  *
4795
+ * This is a passive lookup. It will not create or refresh a session.
4796
+ *
4633
4797
  * @returns True if user is anonymous or no token, false if logged in
4634
4798
  */
4635
4799
  async isAnonymous() {
@@ -4640,18 +4804,22 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
4640
4804
  /**
4641
4805
  * Get the customer ID from the current access token
4642
4806
  *
4807
+ * This is a passive lookup. It will not create or refresh a session.
4808
+ *
4643
4809
  * @returns Customer ID or null if no token, invalid token, or user has no customer ID
4644
4810
  */
4645
4811
  async getCustomerId() {
4646
- return (await this.getUserInfo())?.customerId || null;
4812
+ return this.session.peekCustomerId();
4647
4813
  }
4648
4814
  /**
4649
4815
  * Get the customer group ID from the current access token
4650
4816
  *
4817
+ * This is a passive lookup. It will not create or refresh a session.
4818
+ *
4651
4819
  * @returns Customer group ID or null if no token, invalid token, or user has no customer group
4652
4820
  */
4653
4821
  async getCustomerGroupId() {
4654
- return (await this.getUserInfo())?.customerGroupId || null;
4822
+ return this.session.peekCustomerGroupId();
4655
4823
  }
4656
4824
  /**
4657
4825
  * Set default headers for all clients
@@ -4678,6 +4846,70 @@ Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toString
4678
4846
  return this.defaultHeaders;
4679
4847
  }
4680
4848
  };
4849
+ function buildPublicStorefrontOptions(options) {
4850
+ return {
4851
+ storeId: options.storeId,
4852
+ environment: options.environment,
4853
+ baseUrl: options.baseUrl,
4854
+ apiKey: options.apiKey,
4855
+ timeout: options.timeout,
4856
+ defaultHeaders: options.defaultHeaders,
4857
+ debug: options.debug,
4858
+ logger: options.logger
4859
+ };
4860
+ }
4861
+ function buildSessionStorefrontOptions(options, overrides) {
4862
+ return {
4863
+ ...buildPublicStorefrontOptions(options),
4864
+ ...options.session,
4865
+ ...overrides
4866
+ };
4867
+ }
4868
+ /**
4869
+ * Create a configured storefront factory with explicit public and session
4870
+ * access patterns.
4871
+ *
4872
+ * @example
4873
+ * ```typescript
4874
+ * import {
4875
+ * BrowserTokenStorage,
4876
+ * createStorefront,
4877
+ * Environment,
4878
+ * } from "@commercengine/storefront-sdk";
4879
+ *
4880
+ * export const storefront = createStorefront({
4881
+ * storeId: "your-store-id",
4882
+ * apiKey: "your-api-key",
4883
+ * environment: Environment.Staging,
4884
+ * session: {
4885
+ * tokenStorage: new BrowserTokenStorage("myapp_"),
4886
+ * },
4887
+ * });
4888
+ *
4889
+ * const { data: products } = await storefront.public().catalog.listProducts();
4890
+ * const { data: cart } = await storefront.session().cart.getCart();
4891
+ * ```
4892
+ *
4893
+ * @param options - Shared public config plus optional default session config
4894
+ * @returns A storefront factory with explicit `public()` and `session()` accessors
4895
+ */
4896
+ function createStorefront(options) {
4897
+ const publicOptions = buildPublicStorefrontOptions(options);
4898
+ let publicSDK = null;
4899
+ let sessionSDK = null;
4900
+ const session = (overrides) => {
4901
+ if (overrides && Object.keys(overrides).length > 0) return new SessionStorefrontSDK(buildSessionStorefrontOptions(options, overrides));
4902
+ if (!sessionSDK) sessionSDK = new SessionStorefrontSDK(buildSessionStorefrontOptions(options));
4903
+ return sessionSDK;
4904
+ };
4905
+ return {
4906
+ public: () => {
4907
+ if (!publicSDK) publicSDK = new PublicStorefrontSDK(publicOptions);
4908
+ return publicSDK;
4909
+ },
4910
+ session
4911
+ };
4912
+ }
4681
4913
 
4682
4914
  //#endregion
4683
4915
  exports.AuthClient = AuthClient;
@@ -4691,11 +4923,16 @@ exports.HelpersClient = HelpersClient;
4691
4923
  exports.MemoryTokenStorage = MemoryTokenStorage;
4692
4924
  exports.OrderClient = OrderClient;
4693
4925
  exports.PaymentsClient = PaymentsClient;
4926
+ exports.PublicCatalogClient = PublicCatalogClient;
4927
+ exports.PublicHelpersClient = PublicHelpersClient;
4928
+ exports.PublicStoreConfigClient = PublicStoreConfigClient;
4929
+ exports.PublicStorefrontAPIClient = PublicStorefrontAPIClient;
4930
+ exports.PublicStorefrontSDK = PublicStorefrontSDK;
4694
4931
  exports.ResponseUtils = ResponseUtils;
4932
+ exports.SessionStorefrontAPIClient = SessionStorefrontAPIClient;
4933
+ exports.SessionStorefrontSDK = SessionStorefrontSDK;
4695
4934
  exports.StoreConfigClient = StoreConfigClient;
4696
- exports.StorefrontAPIClient = StorefrontAPIClient;
4697
- exports.StorefrontSDK = StorefrontSDK;
4698
- exports.default = StorefrontSDK;
4935
+ exports.createStorefront = createStorefront;
4699
4936
  return exports;
4700
4937
  })({});
4701
4938
  //# sourceMappingURL=index.iife.js.map