@01.software/sdk 0.21.0 → 0.23.0

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
@@ -63,6 +63,46 @@ function resolveMetaImage(ref) {
63
63
  }
64
64
 
65
65
  // src/core/collection/query-builder.ts
66
+ var ReadOnlyCollectionQueryBuilder = class {
67
+ constructor(api, collection) {
68
+ this.api = api;
69
+ this.collection = collection;
70
+ }
71
+ async find(options) {
72
+ return this.api.requestFind(
73
+ `/api/${String(this.collection)}`,
74
+ options
75
+ );
76
+ }
77
+ async findById(id, options) {
78
+ return this.api.requestFindById(
79
+ `/api/${String(this.collection)}/${String(id)}`,
80
+ options
81
+ );
82
+ }
83
+ async count(options) {
84
+ return this.api.requestCount(
85
+ `/api/${String(this.collection)}/count`,
86
+ options
87
+ );
88
+ }
89
+ async findMetadata(options, metadataOptions) {
90
+ const { docs } = await this.find({ ...options, limit: 1, depth: 1 });
91
+ const doc = docs[0];
92
+ if (!doc) return null;
93
+ return generateMetadata(
94
+ extractSeo(doc),
95
+ metadataOptions
96
+ );
97
+ }
98
+ async findMetadataById(id, metadataOptions) {
99
+ const doc = await this.findById(id, { depth: 1 });
100
+ return generateMetadata(
101
+ extractSeo(doc),
102
+ metadataOptions
103
+ );
104
+ }
105
+ };
66
106
  var CollectionQueryBuilder = class {
67
107
  constructor(api, collection) {
68
108
  this.api = api;
@@ -194,6 +234,8 @@ var CollectionQueryBuilder = class {
194
234
  );
195
235
  }
196
236
  };
237
+ var ServerCollectionQueryBuilder = class extends CollectionQueryBuilder {
238
+ };
197
239
 
198
240
  // src/core/collection/http-client.ts
199
241
  import { stringify } from "qs-esm";
@@ -236,8 +278,8 @@ var NetworkError = class extends SDKError {
236
278
  }
237
279
  };
238
280
  var ValidationError = class extends SDKError {
239
- constructor(message, details, userMessage, suggestion) {
240
- super("VALIDATION_ERROR", message, 400, details, userMessage, suggestion);
281
+ constructor(message, details, userMessage, suggestion, status = 400) {
282
+ super("VALIDATION_ERROR", message, status, details, userMessage, suggestion);
241
283
  this.name = "ValidationError";
242
284
  }
243
285
  };
@@ -366,7 +408,7 @@ function isRateLimitError(error) {
366
408
  return error instanceof RateLimitError;
367
409
  }
368
410
  var createNetworkError = (message, status, details, userMessage, suggestion) => new NetworkError(message, status, details, userMessage, suggestion);
369
- var createValidationError = (message, details, userMessage, suggestion) => new ValidationError(message, details, userMessage, suggestion);
411
+ var createValidationError = (message, details, userMessage, suggestion, status) => new ValidationError(message, details, userMessage, suggestion, status);
370
412
  var createApiError = (message, status, details, userMessage, suggestion) => new ApiError(message, status, details, userMessage, suggestion);
371
413
  var createConfigError = (message, details, userMessage, suggestion) => new ConfigError(message, details, userMessage, suggestion);
372
414
  var createTimeoutError = (message, details, userMessage, suggestion) => new TimeoutError(message, details, userMessage, suggestion);
@@ -377,6 +419,16 @@ var createNotFoundError = (message, details, userMessage, suggestion, requestId)
377
419
  var createConflictError = (message, details, userMessage, suggestion, requestId) => new ConflictError(message, details, userMessage, suggestion, requestId);
378
420
  var createRateLimitError = (message, retryAfter, details, userMessage, suggestion, requestId) => new RateLimitError(message, retryAfter, details, userMessage, suggestion, requestId);
379
421
 
422
+ // src/core/internal/utils/credentials.ts
423
+ function requirePublishableKeyForSecret(apiName, publishableKey, secretKey) {
424
+ if (secretKey && !publishableKey) {
425
+ throw createConfigError(
426
+ `publishableKey is required for ${apiName} when secretKey is used. It is sent as X-Publishable-Key for tenant routing, rate limiting, and quota enforcement.`
427
+ );
428
+ }
429
+ return publishableKey ?? "";
430
+ }
431
+
380
432
  // src/core/client/types.ts
381
433
  function resolveApiUrl() {
382
434
  if (typeof process !== "undefined" && process.env) {
@@ -391,7 +443,7 @@ function resolveApiUrl() {
391
443
  // src/core/internal/utils/http.ts
392
444
  var DEFAULT_TIMEOUT = 3e4;
393
445
  var DEFAULT_RETRYABLE_STATUSES = [408, 429, 500, 502, 503, 504];
394
- var NON_RETRYABLE_STATUSES = [400, 401, 403, 404, 422];
446
+ var NON_RETRYABLE_STATUSES = [400, 401, 403, 404, 409, 422];
395
447
  var SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
396
448
  function debugLog(debug, type, message, data) {
397
449
  if (!debug) return;
@@ -474,6 +526,80 @@ function attachRequestId(err, id) {
474
526
  if (id) err.requestId = id;
475
527
  return err;
476
528
  }
529
+ function createHttpStatusError(status, parsed, details, requestId) {
530
+ const errorDetails = {
531
+ ...details,
532
+ ...parsed.errors && { errors: parsed.errors },
533
+ ...parsed.body && { body: parsed.body }
534
+ };
535
+ const suggestion = getErrorSuggestion(status);
536
+ if (status === 400 || status === 422) {
537
+ return attachRequestId(
538
+ createValidationError(
539
+ parsed.errorMessage,
540
+ errorDetails,
541
+ parsed.userMessage,
542
+ suggestion,
543
+ status
544
+ ),
545
+ requestId
546
+ );
547
+ }
548
+ if (status === 401) {
549
+ return attachRequestId(
550
+ createAuthError(
551
+ parsed.errorMessage,
552
+ errorDetails,
553
+ parsed.userMessage,
554
+ suggestion
555
+ ),
556
+ requestId
557
+ );
558
+ }
559
+ if (status === 403) {
560
+ return attachRequestId(
561
+ createPermissionError(
562
+ parsed.errorMessage,
563
+ errorDetails,
564
+ parsed.userMessage,
565
+ suggestion
566
+ ),
567
+ requestId
568
+ );
569
+ }
570
+ if (status === 404) {
571
+ return attachRequestId(
572
+ createNotFoundError(
573
+ parsed.errorMessage,
574
+ errorDetails,
575
+ parsed.userMessage,
576
+ suggestion
577
+ ),
578
+ requestId
579
+ );
580
+ }
581
+ if (status === 409) {
582
+ return attachRequestId(
583
+ createConflictError(
584
+ parsed.errorMessage,
585
+ errorDetails,
586
+ parsed.userMessage,
587
+ suggestion
588
+ ),
589
+ requestId
590
+ );
591
+ }
592
+ return attachRequestId(
593
+ createNetworkError(
594
+ parsed.errorMessage,
595
+ status,
596
+ errorDetails,
597
+ parsed.userMessage,
598
+ suggestion
599
+ ),
600
+ requestId
601
+ );
602
+ }
477
603
  async function httpFetch(url, options) {
478
604
  const {
479
605
  publishableKey,
@@ -578,14 +704,10 @@ async function httpFetch(url, options) {
578
704
  attempt: attempt + 1
579
705
  };
580
706
  if (NON_RETRYABLE_STATUSES.includes(response.status)) {
581
- throw attachRequestId(
582
- createNetworkError(
583
- parsed.errorMessage,
584
- response.status,
585
- { ...details, ...parsed.errors && { errors: parsed.errors } },
586
- parsed.userMessage,
587
- getErrorSuggestion(response.status)
588
- ),
707
+ throw createHttpStatusError(
708
+ response.status,
709
+ parsed,
710
+ details,
589
711
  requestId
590
712
  );
591
713
  }
@@ -675,7 +797,11 @@ async function httpFetch(url, options) {
675
797
  // src/core/collection/http-client.ts
676
798
  var HttpClient = class {
677
799
  constructor(publishableKey, secretKey, getCustomerToken, onUnauthorized, onRequestId) {
678
- this.publishableKey = publishableKey;
800
+ this.publishableKey = requirePublishableKeyForSecret(
801
+ "CollectionClient",
802
+ publishableKey,
803
+ secretKey
804
+ );
679
805
  this.secretKey = secretKey;
680
806
  this.getCustomerToken = getCustomerToken;
681
807
  this.onUnauthorized = onUnauthorized;
@@ -948,6 +1074,40 @@ var CollectionClient = class extends HttpClient {
948
1074
  return this.parseMutationResponse(response);
949
1075
  }
950
1076
  };
1077
+ var ServerCollectionClient = class extends CollectionClient {
1078
+ from(collection) {
1079
+ return new ServerCollectionQueryBuilder(this, collection);
1080
+ }
1081
+ };
1082
+ var ReadOnlyCollectionClient = class extends HttpClient {
1083
+ from(collection) {
1084
+ return new ReadOnlyCollectionQueryBuilder(this, collection);
1085
+ }
1086
+ async requestFind(endpoint, options) {
1087
+ const url = this.buildUrl(endpoint, options);
1088
+ const response = await this.fetchWithTracking(url, {
1089
+ ...this.defaultOptions,
1090
+ method: "GET"
1091
+ });
1092
+ return this.parseFindResponse(response);
1093
+ }
1094
+ async requestFindById(endpoint, options) {
1095
+ const url = this.buildUrl(endpoint, options);
1096
+ const response = await this.fetchWithTracking(url, {
1097
+ ...this.defaultOptions,
1098
+ method: "GET"
1099
+ });
1100
+ return this.parseDocumentResponse(response);
1101
+ }
1102
+ async requestCount(endpoint, options) {
1103
+ const url = this.buildUrl(endpoint, options);
1104
+ const response = await this.fetchWithTracking(url, {
1105
+ ...this.defaultOptions,
1106
+ method: "GET"
1107
+ });
1108
+ return this.parseDocumentResponse(response);
1109
+ }
1110
+ };
951
1111
 
952
1112
  // src/core/collection/const.ts
953
1113
  var INTERNAL_COLLECTIONS = [
@@ -970,6 +1130,7 @@ var INTERNAL_COLLECTIONS = [
970
1130
  "api-keys",
971
1131
  "personal-access-tokens",
972
1132
  "tenant-entitlements",
1133
+ "direct-upload-sessions",
973
1134
  "webhook-events",
974
1135
  "webhook-deliveries",
975
1136
  "audit-logs",
@@ -999,8 +1160,8 @@ var COLLECTIONS = [
999
1160
  "transactions",
1000
1161
  "customers",
1001
1162
  "customer-profiles",
1163
+ "customer-profile-lists",
1002
1164
  "customer-addresses",
1003
- "customer-groups",
1004
1165
  "carts",
1005
1166
  "cart-items",
1006
1167
  "discounts",
@@ -1056,6 +1217,11 @@ var COLLECTIONS = [
1056
1217
  "event-occurrences",
1057
1218
  "event-tags"
1058
1219
  ];
1220
+ var SERVER_ONLY_COLLECTIONS = ["customer-groups"];
1221
+ var SERVER_COLLECTIONS = [
1222
+ ...COLLECTIONS,
1223
+ ...SERVER_ONLY_COLLECTIONS
1224
+ ];
1059
1225
 
1060
1226
  // src/core/api/parse-response.ts
1061
1227
  async function parseApiResponse(response, endpoint) {
@@ -1106,7 +1272,11 @@ async function parseApiResponse(response, endpoint) {
1106
1272
  // src/core/community/community-client.ts
1107
1273
  var CommunityClient = class {
1108
1274
  constructor(options) {
1109
- this.publishableKey = options.publishableKey ?? "";
1275
+ this.publishableKey = requirePublishableKeyForSecret(
1276
+ "CommunityClient",
1277
+ options.publishableKey,
1278
+ options.secretKey
1279
+ );
1110
1280
  this.secretKey = options.secretKey;
1111
1281
  this.customerToken = options.customerToken;
1112
1282
  this.onUnauthorized = options.onUnauthorized;
@@ -1276,7 +1446,11 @@ var BaseApi = class {
1276
1446
  if (!options.secretKey) {
1277
1447
  throw createConfigError(`secretKey is required for ${apiName}.`);
1278
1448
  }
1279
- this.publishableKey = options.publishableKey ?? "";
1449
+ this.publishableKey = requirePublishableKeyForSecret(
1450
+ apiName,
1451
+ options.publishableKey,
1452
+ options.secretKey
1453
+ );
1280
1454
  this.secretKey = options.secretKey;
1281
1455
  this.onRequestId = options.onRequestId;
1282
1456
  }
@@ -1570,7 +1744,11 @@ var CartApi = class {
1570
1744
  "Either secretKey or customerToken is required for CartApi."
1571
1745
  );
1572
1746
  }
1573
- this.publishableKey = options.publishableKey ?? "";
1747
+ this.publishableKey = requirePublishableKeyForSecret(
1748
+ "CartApi",
1749
+ options.publishableKey,
1750
+ options.secretKey
1751
+ );
1574
1752
  this.secretKey = options.secretKey;
1575
1753
  this.customerToken = options.customerToken;
1576
1754
  this.onUnauthorized = options.onUnauthorized;
@@ -1766,8 +1944,13 @@ var OrderApi = class extends BaseApi {
1766
1944
  // src/core/commerce/server-commerce-client.ts
1767
1945
  var ServerCommerceClient = class {
1768
1946
  constructor(options) {
1947
+ const publishableKey = requirePublishableKeyForSecret(
1948
+ "ServerCommerceClient",
1949
+ options.publishableKey,
1950
+ options.secretKey
1951
+ );
1769
1952
  const serverOptions = {
1770
- publishableKey: options.publishableKey,
1953
+ publishableKey,
1771
1954
  secretKey: options.secretKey,
1772
1955
  onRequestId: options.onRequestId
1773
1956
  };
@@ -2386,7 +2569,14 @@ var Client = class {
2386
2569
  onUnauthorized,
2387
2570
  onRequestId
2388
2571
  });
2389
- this.collections = new CollectionClient(
2572
+ const collectionClient = new CollectionClient(
2573
+ this.config.publishableKey,
2574
+ void 0,
2575
+ () => this.customer.auth.getToken(),
2576
+ onUnauthorized,
2577
+ onRequestId
2578
+ );
2579
+ this.collections = new ReadOnlyCollectionClient(
2390
2580
  this.config.publishableKey,
2391
2581
  void 0,
2392
2582
  () => this.customer.auth.getToken(),
@@ -2395,7 +2585,7 @@ var Client = class {
2395
2585
  );
2396
2586
  this.query = new QueryHooks(
2397
2587
  this.queryClient,
2398
- this.collections,
2588
+ collectionClient,
2399
2589
  this.customer.auth
2400
2590
  );
2401
2591
  }
@@ -2450,7 +2640,7 @@ var ServerClient = class {
2450
2640
  unbanCustomer: moderationApi.unbanCustomer.bind(moderationApi)
2451
2641
  }
2452
2642
  });
2453
- this.collections = new CollectionClient(
2643
+ this.collections = new ServerCollectionClient(
2454
2644
  this.config.publishableKey,
2455
2645
  this.config.secretKey,
2456
2646
  void 0,
@@ -2772,12 +2962,24 @@ function getVariantPrimaryImage(variant) {
2772
2962
  if (!variant) return null;
2773
2963
  return extractEntityId(variant.thumbnail) ?? getFirstMediaId(variant.images);
2774
2964
  }
2965
+ function getFirstAvailableVariantPrimaryImage(variants) {
2966
+ const orderedVariants = [...variants].sort(compareVariantOrder);
2967
+ for (const variant of orderedVariants) {
2968
+ if (!isVariantAvailableForSale(variant)) continue;
2969
+ const image = getVariantPrimaryImage(variant);
2970
+ if (image != null) return image;
2971
+ }
2972
+ return null;
2973
+ }
2775
2974
  function normalizeOptionValue(value, fallbackOptionId) {
2776
2975
  return {
2777
2976
  id: String(value.id),
2778
2977
  optionId: getRelationID(value.option) ?? fallbackOptionId,
2779
2978
  label: value.value || value.slug || String(value.id),
2780
2979
  slug: value.slug ?? null,
2980
+ swatchColor: value.swatchColor ?? null,
2981
+ thumbnail: value.thumbnail ?? null,
2982
+ images: value.images ?? null,
2781
2983
  order: value._order ?? value["_product-option-values_values_order"] ?? ""
2782
2984
  };
2783
2985
  }
@@ -2806,7 +3008,10 @@ function buildProductOptionMatrix({
2806
3008
  const valuesById = /* @__PURE__ */ new Map();
2807
3009
  for (const rawValue of option.values?.docs ?? []) {
2808
3010
  if (!isProductOptionValueDoc(rawValue)) continue;
2809
- const normalizedValue = normalizeOptionValue(rawValue, String(option.id));
3011
+ const normalizedValue = normalizeOptionValue(
3012
+ rawValue,
3013
+ String(option.id)
3014
+ );
2810
3015
  valuesById.set(normalizedValue.id, normalizedValue);
2811
3016
  }
2812
3017
  return {
@@ -2818,7 +3023,9 @@ function buildProductOptionMatrix({
2818
3023
  )
2819
3024
  };
2820
3025
  }).sort((left, right) => compareOrder(left.order, right.order));
2821
- const optionById = new Map(normalizedOptions.map((option) => [option.id, option]));
3026
+ const optionById = new Map(
3027
+ normalizedOptions.map((option) => [option.id, option])
3028
+ );
2822
3029
  const valueById = /* @__PURE__ */ new Map();
2823
3030
  const valueToOptionId = /* @__PURE__ */ new Map();
2824
3031
  for (const option of normalizedOptions) {
@@ -2897,10 +3104,12 @@ function compareVariantOrder(a, b) {
2897
3104
  function isVariantAvailableForSale(variant) {
2898
3105
  if (variant.isActive === false) return false;
2899
3106
  if (variant.isUnlimited) return true;
2900
- return (variant.stock ?? 0) > 0;
3107
+ return (variant.stock ?? 0) - (variant.reservedStock ?? 0) > 0;
2901
3108
  }
2902
3109
  function getMinMax(values) {
2903
- const numbers = values.filter((value) => typeof value === "number");
3110
+ const numbers = values.filter(
3111
+ (value) => typeof value === "number"
3112
+ );
2904
3113
  if (numbers.length === 0) {
2905
3114
  return { min: null, max: null };
2906
3115
  }
@@ -2911,7 +3120,9 @@ function getMinMax(values) {
2911
3120
  }
2912
3121
  function buildProductListingProjection(product, variants) {
2913
3122
  const orderedVariants = [...variants].sort(compareVariantOrder);
2914
- const activeVariants = orderedVariants.filter((variant) => variant.isActive !== false);
3123
+ const activeVariants = orderedVariants.filter(
3124
+ (variant) => variant.isActive !== false
3125
+ );
2915
3126
  const availableVariants = activeVariants.filter(isVariantAvailableForSale);
2916
3127
  const selectionHintVariant = availableVariants[0] ?? activeVariants[0] ?? null;
2917
3128
  const { min: minPrice, max: maxPrice } = getMinMax(
@@ -2950,7 +3161,9 @@ function buildProductListingGroupsByOption(args) {
2950
3161
  return [];
2951
3162
  }
2952
3163
  const listingBase = buildProductListingProjection(void 0, variants);
3164
+ const optionValuePrimaryImage = extractEntityId(value.thumbnail) ?? getFirstMediaId(value.images);
2953
3165
  const productFallbackImage = extractEntityId(args.product?.thumbnail) ?? getFirstMediaId(args.product?.images);
3166
+ const groupPrimaryImage = getFirstAvailableVariantPrimaryImage(variants) ?? optionValuePrimaryImage ?? productFallbackImage;
2954
3167
  return [
2955
3168
  {
2956
3169
  optionId: primaryOption.id,
@@ -2958,12 +3171,15 @@ function buildProductListingGroupsByOption(args) {
2958
3171
  optionValueId: value.id,
2959
3172
  optionValueLabel: value.label,
2960
3173
  optionValueSlug: value.slug,
3174
+ optionValueSwatchColor: value.swatchColor ?? null,
3175
+ optionValueThumbnail: value.thumbnail ?? null,
3176
+ optionValueImages: value.images ?? null,
2961
3177
  variantIds: variants.map((variant) => String(variant.id)),
2962
3178
  variantCount: variants.length,
2963
3179
  variants,
2964
3180
  listing: {
2965
3181
  ...listingBase,
2966
- primaryImage: listingBase.primaryImage ?? productFallbackImage
3182
+ primaryImage: groupPrimaryImage
2967
3183
  }
2968
3184
  }
2969
3185
  ];
@@ -3284,9 +3500,14 @@ export {
3284
3500
  ProductApi,
3285
3501
  QueryHooks,
3286
3502
  RateLimitError,
3503
+ ReadOnlyCollectionClient,
3287
3504
  RealtimeConnection,
3288
3505
  SDKError,
3506
+ SERVER_COLLECTIONS,
3507
+ SERVER_ONLY_COLLECTIONS,
3289
3508
  ServerClient,
3509
+ ServerCollectionClient,
3510
+ ServerCollectionQueryBuilder,
3290
3511
  ServerCommerceClient,
3291
3512
  ServiceUnavailableError,
3292
3513
  ShippingApi,