@commercengine/storefront-sdk 0.10.0 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -43,16 +43,14 @@ var ResponseUtils = class {
43
43
  * Note: This can only be called once per response
44
44
  */
45
45
  static async getText(response) {
46
- const cloned = response.clone();
47
- return await cloned.text();
46
+ return await response.clone().text();
48
47
  }
49
48
  /**
50
49
  * Clone and read response as JSON (useful for debugging)
51
50
  * Note: This can only be called once per response
52
51
  */
53
52
  static async getJSON(response) {
54
- const cloned = response.clone();
55
- return await cloned.json();
53
+ return await response.clone().json();
56
54
  }
57
55
  /**
58
56
  * Format response information for debugging
@@ -297,7 +295,7 @@ async function executeRequest(apiCall) {
297
295
  status: 0,
298
296
  statusText: "Network Error"
299
297
  });
300
- const errorResult = {
298
+ return {
301
299
  data: null,
302
300
  error: {
303
301
  success: false,
@@ -307,7 +305,6 @@ async function executeRequest(apiCall) {
307
305
  },
308
306
  response: mockResponse
309
307
  };
310
- return errorResult;
311
308
  }
312
309
  }
313
310
  /**
@@ -395,15 +392,6 @@ var BaseAPIClient = class {
395
392
  getDefaultHeaders() {
396
393
  return this.config.defaultHeaders;
397
394
  }
398
- /**
399
- * Add middleware to the client
400
- * This allows SDK extensions to add custom middleware like authentication
401
- *
402
- * @param middleware - Middleware to add to the client
403
- */
404
- use(middleware) {
405
- this.client.use(middleware);
406
- }
407
395
  };
408
396
  /**
409
397
  * Generic URL utility functions for any SDK
@@ -414,8 +402,7 @@ var BaseAPIClient = class {
414
402
  */
415
403
  function getPathnameFromUrl(url) {
416
404
  try {
417
- const urlObj = new URL(url);
418
- return urlObj.pathname;
405
+ return new URL(url).pathname;
419
406
  } catch {
420
407
  return url.split("?")[0] || url;
421
408
  }
@@ -465,9 +452,7 @@ function isTokenExpired(token, bufferSeconds = 30) {
465
452
  try {
466
453
  const payload = decodeJwt(token);
467
454
  if (!payload.exp) return true;
468
- const currentTime = Math.floor(Date.now() / 1e3);
469
- const expiryTime = payload.exp;
470
- return currentTime >= expiryTime - bufferSeconds;
455
+ return Math.floor(Date.now() / 1e3) >= payload.exp - bufferSeconds;
471
456
  } catch (error) {
472
457
  console.warn("Failed to decode JWT token:", error);
473
458
  return true;
@@ -480,8 +465,7 @@ function isTokenExpired(token, bufferSeconds = 30) {
480
465
  * @returns User ID (ulid) or null if token is invalid
481
466
  */
482
467
  function getUserIdFromToken(token) {
483
- const userInfo = extractUserInfoFromToken(token);
484
- return userInfo?.id || null;
468
+ return extractUserInfoFromToken(token)?.id || null;
485
469
  }
486
470
  /**
487
471
  * Check if user is logged in based on JWT token
@@ -490,8 +474,7 @@ function getUserIdFromToken(token) {
490
474
  * @returns True if user is logged in, false otherwise
491
475
  */
492
476
  function isUserLoggedIn(token) {
493
- const userInfo = extractUserInfoFromToken(token);
494
- return userInfo?.isLoggedIn || false;
477
+ return extractUserInfoFromToken(token)?.isLoggedIn || false;
495
478
  }
496
479
  /**
497
480
  * Check if user is anonymous based on JWT token
@@ -500,8 +483,7 @@ function isUserLoggedIn(token) {
500
483
  * @returns True if user is anonymous, false otherwise
501
484
  */
502
485
  function isUserAnonymous(token) {
503
- const userInfo = extractUserInfoFromToken(token);
504
- return userInfo?.isAnonymous || true;
486
+ return extractUserInfoFromToken(token)?.isAnonymous || true;
505
487
  }
506
488
 
507
489
  //#endregion
@@ -516,14 +498,13 @@ function isAnonymousAuthEndpoint(pathname) {
516
498
  * Check if a URL path is a login/register endpoint that returns tokens
517
499
  */
518
500
  function isTokenReturningEndpoint(pathname) {
519
- const tokenEndpoints = [
501
+ return [
520
502
  "/auth/login/password",
521
503
  "/auth/register/phone",
522
504
  "/auth/register/email",
523
505
  "/auth/verify-otp",
524
506
  "/auth/refresh-token"
525
- ];
526
- return tokenEndpoints.some((endpoint) => pathname.endsWith(endpoint));
507
+ ].some((endpoint) => pathname.endsWith(endpoint));
527
508
  }
528
509
  /**
529
510
  * Check if a URL path is the logout endpoint
@@ -626,8 +607,7 @@ var CookieTokenStorage = class {
626
607
  }
627
608
  getCookie(name) {
628
609
  if (typeof document === "undefined") return null;
629
- const value = `; ${document.cookie}`;
630
- const parts = value.split(`; ${name}=`);
610
+ const parts = `; ${document.cookie}`.split(`; ${name}=`);
631
611
  if (parts.length === 2) {
632
612
  const cookieValue = parts.pop()?.split(";").shift();
633
613
  return cookieValue ? decodeURIComponent(cookieValue) : null;
@@ -636,8 +616,7 @@ var CookieTokenStorage = class {
636
616
  }
637
617
  setCookie(name, value) {
638
618
  if (typeof document === "undefined") return;
639
- const encodedValue = encodeURIComponent(value);
640
- let cookieString = `${name}=${encodedValue}`;
619
+ let cookieString = `${name}=${encodeURIComponent(value)}`;
641
620
  if (this.options.maxAge) cookieString += `; Max-Age=${this.options.maxAge}`;
642
621
  if (this.options.path) cookieString += `; Path=${this.options.path}`;
643
622
  if (this.options.domain) cookieString += `; Domain=${this.options.domain}`;
@@ -689,8 +668,7 @@ function createAuthMiddleware(config) {
689
668
  body: JSON.stringify({ refresh_token: refreshToken })
690
669
  });
691
670
  if (!response.ok) throw new Error(`Token refresh failed: ${response.status}`);
692
- const data = await response.json();
693
- newTokens = data.content;
671
+ newTokens = (await response.json()).content;
694
672
  }
695
673
  else {
696
674
  const currentAccessToken = await config.tokenStorage.getAccessToken();
@@ -705,8 +683,7 @@ function createAuthMiddleware(config) {
705
683
  }
706
684
  });
707
685
  if (!response.ok) throw new Error(`Anonymous token fallback failed: ${response.status}`);
708
- const data = await response.json();
709
- newTokens = data.content;
686
+ newTokens = (await response.json()).content;
710
687
  console.info(`Token refreshed via anonymous fallback (${reason}) - user may need to re-authenticate for privileged operations`);
711
688
  }
712
689
  await config.tokenStorage.setAccessToken(newTokens.access_token);
@@ -752,8 +729,7 @@ function createAuthMiddleware(config) {
752
729
  }
753
730
  });
754
731
  if (response.ok) {
755
- const data = await response.json();
756
- const tokens = data.content;
732
+ const tokens = (await response.json()).content;
757
733
  if (tokens?.access_token && tokens?.refresh_token) {
758
734
  await config.tokenStorage.setAccessToken(tokens.access_token);
759
735
  await config.tokenStorage.setRefreshToken(tokens.refresh_token);
@@ -776,8 +752,7 @@ function createAuthMiddleware(config) {
776
752
  const pathname = getPathnameFromUrl(request.url);
777
753
  if (response.ok) {
778
754
  if (isTokenReturningEndpoint(pathname) || isAnonymousAuthEndpoint(pathname)) try {
779
- const data = await response.clone().json();
780
- const content = data.content;
755
+ const content = (await response.clone().json()).content;
781
756
  if (content?.access_token && content?.refresh_token) {
782
757
  await config.tokenStorage.setAccessToken(content.access_token);
783
758
  await config.tokenStorage.setRefreshToken(content.refresh_token);
@@ -813,9 +788,8 @@ function createAuthMiddleware(config) {
813
788
  * Helper function to create auth middleware with sensible defaults
814
789
  */
815
790
  function createDefaultAuthMiddleware(options) {
816
- const tokenStorage = options.tokenStorage || (typeof localStorage !== "undefined" ? new BrowserTokenStorage() : new MemoryTokenStorage());
817
791
  return createAuthMiddleware({
818
- tokenStorage,
792
+ tokenStorage: options.tokenStorage || (typeof localStorage !== "undefined" ? new BrowserTokenStorage() : new MemoryTokenStorage()),
819
793
  apiKey: options.apiKey,
820
794
  baseUrl: options.baseUrl,
821
795
  onTokensUpdated: options.onTokensUpdated,
@@ -847,8 +821,7 @@ let Environment = /* @__PURE__ */ function(Environment$1) {
847
821
  */
848
822
  function buildStorefrontURL(config) {
849
823
  if (config.baseUrl) return config.baseUrl;
850
- const env = config.environment || Environment.Production;
851
- switch (env) {
824
+ switch (config.environment || Environment.Production) {
852
825
  case Environment.Staging: return `https://staging.api.commercengine.io/api/v1/${config.storeId}/storefront`;
853
826
  case Environment.Production:
854
827
  default: return `https://prod.api.commercengine.io/api/v1/${config.storeId}/storefront`;
@@ -875,14 +848,16 @@ var StorefrontAPIClient = class extends BaseAPIClient {
875
848
  environment: config.environment,
876
849
  baseUrl: config.baseUrl
877
850
  });
878
- const headerTransformations = { customer_group_id: "x-customer-group-id" };
879
851
  super({
880
852
  baseUrl,
881
853
  timeout: config.timeout,
882
854
  defaultHeaders: config.defaultHeaders,
883
855
  debug: config.debug,
884
856
  logger: config.logger
885
- }, baseUrl, headerTransformations);
857
+ }, baseUrl, {
858
+ customer_group_id: "x-customer-group-id",
859
+ debug_mode: "x-debug-mode"
860
+ });
886
861
  this.config = { ...config };
887
862
  this.setupStorefrontAuth();
888
863
  }
@@ -906,8 +881,7 @@ var StorefrontAPIClient = class extends BaseAPIClient {
906
881
  config.refreshToken = void 0;
907
882
  }
908
883
  } else this.client.use({ onRequest: async ({ request }) => {
909
- const pathname = getPathnameFromUrl(request.url);
910
- if (isAnonymousAuthEndpoint(pathname)) {
884
+ if (isAnonymousAuthEndpoint(getPathnameFromUrl(request.url))) {
911
885
  if (config.apiKey) request.headers.set("X-Api-Key", config.apiKey);
912
886
  if (config.accessToken) request.headers.set("Authorization", `Bearer ${config.accessToken}`);
913
887
  return request;
@@ -1152,10 +1126,11 @@ var CatalogClient = class extends StorefrontAPIClient {
1152
1126
  * console.log("Product with custom pricing:", slugData.product.price);
1153
1127
  * ```
1154
1128
  */
1155
- async getProductDetail(pathParams, headers) {
1129
+ async getProductDetail(pathParams, options, headers) {
1156
1130
  const mergedHeaders = this.mergeHeaders(headers);
1157
1131
  return this.executeRequest(() => this.client.GET("/catalog/products/{product_id_or_slug}", { params: {
1158
1132
  path: pathParams,
1133
+ query: options,
1159
1134
  header: mergedHeaders
1160
1135
  } }));
1161
1136
  }
@@ -1192,10 +1167,11 @@ var CatalogClient = class extends StorefrontAPIClient {
1192
1167
  * );
1193
1168
  * ```
1194
1169
  */
1195
- async listProductVariants(pathParams, headers) {
1170
+ async listProductVariants(pathParams, options, headers) {
1196
1171
  const mergedHeaders = this.mergeHeaders(headers);
1197
1172
  return this.executeRequest(() => this.client.GET("/catalog/products/{product_id}/variants", { params: {
1198
1173
  path: pathParams,
1174
+ query: options,
1199
1175
  header: mergedHeaders
1200
1176
  } }));
1201
1177
  }
@@ -1226,10 +1202,11 @@ var CatalogClient = class extends StorefrontAPIClient {
1226
1202
  * console.log("Stock:", data.variant.stock);
1227
1203
  * ```
1228
1204
  */
1229
- async getVariantDetail(pathParams, headers) {
1205
+ async getVariantDetail(pathParams, options, headers) {
1230
1206
  const mergedHeaders = this.mergeHeaders(headers);
1231
1207
  return this.executeRequest(() => this.client.GET("/catalog/products/{product_id}/variants/{variant_id}", { params: {
1232
1208
  path: pathParams,
1209
+ query: options,
1233
1210
  header: mergedHeaders
1234
1211
  } }));
1235
1212
  }
@@ -1902,31 +1879,32 @@ var CartClient = class extends StorefrontAPIClient {
1902
1879
  }));
1903
1880
  }
1904
1881
  /**
1905
- * Update shipping method
1882
+ * Update fulfillment preference
1906
1883
  *
1907
1884
  * @param cartId - The ID of the cart
1908
1885
  * @param body - The body of the request
1909
1886
  * @returns Promise with updated cart
1910
1887
  * @example
1911
1888
  * ```typescript
1912
- * const { data, error } = await sdk.cart.updateShippingMethod(
1889
+ * const { data, error } = await sdk.cart.updateFulfillmentPreference(
1913
1890
  * { id: "01H9CART12345ABCDE" },
1914
1891
  * {
1915
- * shipping_method_id: "01H9SHIP12345FAST",
1916
- * estimated_delivery_date: "2024-01-15"
1892
+ * fulfillment_type: "delivery",
1893
+ * shipping_provider_id: "01H9SHIP12345FAST",
1894
+ * courier_company_id: "01H9COY12345FAST", // Optional
1917
1895
  * }
1918
1896
  * );
1919
1897
  *
1920
1898
  * if (error) {
1921
- * console.error("Failed to update shipping method:", error.message);
1899
+ * console.error("Failed to update fulfillment preference:", error.message);
1922
1900
  * } else {
1923
- * console.log("Shipping method updated:", data.cart.shipping_method?.name);
1924
- * console.log("Shipping cost:", data.cart.shipping_cost);
1901
+ * console.log("Fulfillment preference updated:", data.cart.fulfillment_preference?.fulfillment_type);
1902
+ * console.log("Shipping cost:", data.cart.shipping_amount);
1925
1903
  * }
1926
1904
  * ```
1927
1905
  */
1928
- async updateShippingMethod(cartId, body) {
1929
- return this.executeRequest(() => this.client.POST("/carts/{id}/shipping-method", {
1906
+ async updateFulfillmentPreference(cartId, body) {
1907
+ return this.executeRequest(() => this.client.POST("/carts/{id}/fulfillment-preference", {
1930
1908
  params: { path: cartId },
1931
1909
  body
1932
1910
  }));
@@ -2241,8 +2219,12 @@ var AuthClient = class extends StorefrontAPIClient {
2241
2219
  * }
2242
2220
  * ```
2243
2221
  */
2244
- async loginWithPhone(body) {
2245
- return this.executeRequest(() => this.client.POST("/auth/login/phone", { body }));
2222
+ async loginWithPhone(body, headers) {
2223
+ const mergedHeaders = this.mergeHeaders(headers);
2224
+ return this.executeRequest(() => this.client.POST("/auth/login/phone", {
2225
+ body,
2226
+ params: { header: mergedHeaders }
2227
+ }));
2246
2228
  }
2247
2229
  /**
2248
2230
  * Login with WhatsApp
@@ -2266,8 +2248,12 @@ var AuthClient = class extends StorefrontAPIClient {
2266
2248
  * }
2267
2249
  * ```
2268
2250
  */
2269
- async loginWithWhatsApp(body) {
2270
- return this.executeRequest(() => this.client.POST("/auth/login/whatsapp", { body }));
2251
+ async loginWithWhatsApp(body, headers) {
2252
+ const mergedHeaders = this.mergeHeaders(headers);
2253
+ return this.executeRequest(() => this.client.POST("/auth/login/whatsapp", {
2254
+ body,
2255
+ params: { header: mergedHeaders }
2256
+ }));
2271
2257
  }
2272
2258
  /**
2273
2259
  * Login with email
@@ -2291,8 +2277,12 @@ var AuthClient = class extends StorefrontAPIClient {
2291
2277
  * }
2292
2278
  * ```
2293
2279
  */
2294
- async loginWithEmail(body) {
2295
- return this.executeRequest(() => this.client.POST("/auth/login/email", { body }));
2280
+ async loginWithEmail(body, headers) {
2281
+ const mergedHeaders = this.mergeHeaders(headers);
2282
+ return this.executeRequest(() => this.client.POST("/auth/login/email", {
2283
+ body,
2284
+ params: { header: mergedHeaders }
2285
+ }));
2296
2286
  }
2297
2287
  /**
2298
2288
  * Login with password
@@ -2816,8 +2806,12 @@ var AuthClient = class extends StorefrontAPIClient {
2816
2806
  * }
2817
2807
  * ```
2818
2808
  */
2819
- async generateOtp(body) {
2820
- return this.executeRequest(() => this.client.POST("/auth/generate-otp", { body }));
2809
+ async generateOtp(body, headers) {
2810
+ const mergedHeaders = this.mergeHeaders(headers);
2811
+ return this.executeRequest(() => this.client.POST("/auth/generate-otp", {
2812
+ body,
2813
+ params: { header: mergedHeaders }
2814
+ }));
2821
2815
  }
2822
2816
  /**
2823
2817
  * Check whether email or phone is already verified
@@ -3147,40 +3141,6 @@ var OrderClient = class extends StorefrontAPIClient {
3147
3141
  * Client for interacting with shipping endpoints
3148
3142
  */
3149
3143
  var ShippingClient = class extends StorefrontAPIClient {
3150
- /**
3151
- * Get shipping options for an order
3152
- *
3153
- * @param body - Shipping methods body
3154
- * @returns Promise with shipping options
3155
- * @example
3156
- * ```typescript
3157
- * const { data, error } = await sdk.shipping.getShippingMethods({
3158
- * delivery_pincode: "400001",
3159
- * cart_id: "cart_01H9XYZ12345ABCDE"
3160
- * });
3161
- *
3162
- * if (error) {
3163
- * console.error("Failed to get shipping methods:", error.message);
3164
- * } else {
3165
- * console.log("Is serviceable:", data.is_serviceable);
3166
- * console.log("Available shipping methods:", data.shipping_methods?.length || 0);
3167
- *
3168
- * data.shipping_methods?.forEach(method => {
3169
- * console.log(`Method: ${method.name} (${method.shipping_type})`);
3170
- * console.log(`Shipping cost: ${method.shipping_amount}`);
3171
- * console.log(`Estimated delivery: ${method.estimated_delivery_days} days`);
3172
- *
3173
- * method.courier_companies?.forEach(courier => {
3174
- * console.log(` - ${courier.name}: ${courier.shipping_amount} (${courier.mode})`);
3175
- * console.log(` Rating: ${courier.rating}/5, Recommended: ${courier.is_recommended}`);
3176
- * });
3177
- * });
3178
- * }
3179
- * ```
3180
- */
3181
- async getShippingMethods(body) {
3182
- return this.executeRequest(() => this.client.POST("/shipping/shipping-methods", { body }));
3183
- }
3184
3144
  /**
3185
3145
  * Check pincode deliverability
3186
3146
  *
@@ -3208,6 +3168,47 @@ var ShippingClient = class extends StorefrontAPIClient {
3208
3168
  async checkPincodeDeliverability(pathParams) {
3209
3169
  return this.executeRequest(() => this.client.GET("/shipping/serviceability/{pincode}", { params: { path: pathParams } }));
3210
3170
  }
3171
+ /**
3172
+ * Get fulfillment options for an order
3173
+ *
3174
+ * @param body - Fulfillment options body containing cart_id and delivery_pincode
3175
+ * @returns Promise with fulfillment options including collect and delivery methods
3176
+ * @example
3177
+ * ```typescript
3178
+ * const { data, error } = await sdk.shipping.getFulfillmentOptions({
3179
+ * cart_id: "cart_01H9XYZ12345ABCDE",
3180
+ * delivery_pincode: "400001"
3181
+ * });
3182
+ *
3183
+ * if (error) {
3184
+ * console.error("Failed to get fulfillment options:", error.message);
3185
+ * } else {
3186
+ * // Check summary information
3187
+ * console.log("Collect available:", data.summary.collect_available);
3188
+ * console.log("Deliver available:", data.summary.deliver_available);
3189
+ * console.log("Recommended fulfillment type:", data.summary.recommended_fulfillment_type);
3190
+ *
3191
+ * // Access collect options
3192
+ * if (data.collect && data.collect.length > 0) {
3193
+ * console.log("Available stores for collection:");
3194
+ * data.collect.forEach(store => {
3195
+ * console.log(`${store.name} - ${store.distance_km}km away, ETA: ${store.collect_eta_minutes} minutes`);
3196
+ * });
3197
+ * }
3198
+ *
3199
+ * // Access delivery options
3200
+ * if (data.deliver && data.deliver.is_serviceable) {
3201
+ * console.log("Available shipping methods:");
3202
+ * data.deliver.shipping_methods.forEach(method => {
3203
+ * console.log(`${method.name} - ${method.shipping_amount}, ${method.estimated_delivery_days} days`);
3204
+ * });
3205
+ * }
3206
+ * }
3207
+ * ```
3208
+ */
3209
+ async getFulfillmentOptions(body) {
3210
+ return this.executeRequest(() => this.client.POST("/shipping/fulfillment-options", { body }));
3211
+ }
3211
3212
  };
3212
3213
 
3213
3214
  //#endregion
@@ -3644,6 +3645,29 @@ var CustomerClient = class extends StorefrontAPIClient {
3644
3645
  async listCustomerReviews(pathParams) {
3645
3646
  return this.executeRequest(() => this.client.GET("/customers/{user_id}/reviews", { params: { path: pathParams } }));
3646
3647
  }
3648
+ /**
3649
+ * List all saved payment methods for a customer
3650
+ *
3651
+ * @param pathParams - Path parameters
3652
+ * @returns Promise with payment methods
3653
+ *
3654
+ * @example
3655
+ * ```typescript
3656
+ * const { data, error } = await sdk.customer.listSavedPaymentMethods({
3657
+ * customer_id: "customer_123"
3658
+ * });
3659
+ *
3660
+ * if (error) {
3661
+ * console.error("Failed to list saved payment methods:", error);
3662
+ * return;
3663
+ * }
3664
+ *
3665
+ * console.log("Saved payment methods:", data.saved_payment_methods);
3666
+ * ```
3667
+ */
3668
+ async listSavedPaymentMethods(pathParams) {
3669
+ return this.executeRequest(() => this.client.GET("/customers/{customer_id}/payment-methods", { params: { path: pathParams } }));
3670
+ }
3647
3671
  };
3648
3672
 
3649
3673
  //#endregion
@@ -3869,8 +3893,7 @@ var StorefrontSDK = class {
3869
3893
  * @returns Customer ID or null if no token, invalid token, or user has no customer ID
3870
3894
  */
3871
3895
  async getCustomerId() {
3872
- const userInfo = await this.getUserInfo();
3873
- return userInfo?.customerId || null;
3896
+ return (await this.getUserInfo())?.customerId || null;
3874
3897
  }
3875
3898
  /**
3876
3899
  * Get the customer group ID from the current access token
@@ -3878,8 +3901,7 @@ var StorefrontSDK = class {
3878
3901
  * @returns Customer group ID or null if no token, invalid token, or user has no customer group
3879
3902
  */
3880
3903
  async getCustomerGroupId() {
3881
- const userInfo = await this.getUserInfo();
3882
- return userInfo?.customerGroupId || null;
3904
+ return (await this.getUserInfo())?.customerGroupId || null;
3883
3905
  }
3884
3906
  /**
3885
3907
  * Set default headers for all clients