@01.software/sdk 0.43.0 → 0.45.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.
Files changed (80) hide show
  1. package/CHANGELOG.md +375 -2
  2. package/MIGRATION.md +89 -10
  3. package/README.md +451 -109
  4. package/dist/{server-nXOezi4b.d.cts → catalog-mappers-sIshKNb3.d.cts} +14 -3
  5. package/dist/{server-nXOezi4b.d.ts → catalog-mappers-sIshKNb3.d.ts} +14 -3
  6. package/dist/client.cjs +2680 -345
  7. package/dist/client.cjs.map +1 -1
  8. package/dist/client.d.cts +10 -7
  9. package/dist/client.d.ts +10 -7
  10. package/dist/client.js +2680 -345
  11. package/dist/client.js.map +1 -1
  12. package/dist/{collection-client-U70KizLf.d.cts → collection-client-BSo7VXQE.d.cts} +8 -5
  13. package/dist/{collection-client-gWsA7BVP.d.ts → collection-client-Ckfusuee.d.ts} +8 -5
  14. package/dist/{const-_WWHU-gX.d.ts → const-BAG0MH0u.d.cts} +13 -10
  15. package/dist/{const-BBynifk0.d.cts → const-CaPq2AE4.d.ts} +13 -10
  16. package/dist/errors.cjs +74 -1
  17. package/dist/errors.cjs.map +1 -1
  18. package/dist/errors.d.cts +38 -1
  19. package/dist/errors.d.ts +38 -1
  20. package/dist/errors.js +74 -1
  21. package/dist/errors.js.map +1 -1
  22. package/dist/{index-DPi5NWU8.d.ts → index-BNICJxBL.d.ts} +4 -4
  23. package/dist/{index-Dg4Y6Aq7.d.cts → index-YGrZrxNn.d.cts} +4 -4
  24. package/dist/index.cjs +2741 -368
  25. package/dist/index.cjs.map +1 -1
  26. package/dist/index.d.cts +18 -19
  27. package/dist/index.d.ts +18 -19
  28. package/dist/index.js +2741 -368
  29. package/dist/index.js.map +1 -1
  30. package/dist/{payload-types-DLxkB7Mv.d.cts → payload-types-CJZuXcgF.d.cts} +6873 -4208
  31. package/dist/{payload-types-DLxkB7Mv.d.ts → payload-types-CJZuXcgF.d.ts} +6873 -4208
  32. package/dist/query.cjs +550 -101
  33. package/dist/query.cjs.map +1 -1
  34. package/dist/query.d.cts +43 -45
  35. package/dist/query.d.ts +43 -45
  36. package/dist/query.js +550 -101
  37. package/dist/query.js.map +1 -1
  38. package/dist/realtime.cjs.map +1 -1
  39. package/dist/realtime.d.cts +2 -2
  40. package/dist/realtime.d.ts +2 -2
  41. package/dist/realtime.js.map +1 -1
  42. package/dist/server.cjs +2252 -444
  43. package/dist/server.cjs.map +1 -1
  44. package/dist/server.d.cts +11 -10
  45. package/dist/server.d.ts +11 -10
  46. package/dist/server.js +2252 -444
  47. package/dist/server.js.map +1 -1
  48. package/dist/storefront-cache.cjs +65 -1
  49. package/dist/storefront-cache.cjs.map +1 -1
  50. package/dist/storefront-cache.js +65 -1
  51. package/dist/storefront-cache.js.map +1 -1
  52. package/dist/types-BC6rVmJa.d.ts +47 -0
  53. package/dist/{types-B9lGhZlB.d.ts → types-BlOvjoTX.d.ts} +1095 -504
  54. package/dist/{types-Bpx5sYKo.d.cts → types-C4WuJfw7.d.cts} +1095 -504
  55. package/dist/types-D5p7-m1l.d.cts +47 -0
  56. package/dist/ui/canvas/server.cjs +244 -2
  57. package/dist/ui/canvas/server.cjs.map +1 -1
  58. package/dist/ui/canvas/server.d.cts +27 -1
  59. package/dist/ui/canvas/server.d.ts +27 -1
  60. package/dist/ui/canvas/server.js +244 -2
  61. package/dist/ui/canvas/server.js.map +1 -1
  62. package/dist/ui/canvas.cjs +419 -103
  63. package/dist/ui/canvas.cjs.map +1 -1
  64. package/dist/ui/canvas.d.cts +19 -7
  65. package/dist/ui/canvas.d.ts +19 -7
  66. package/dist/ui/canvas.js +419 -103
  67. package/dist/ui/canvas.js.map +1 -1
  68. package/dist/ui/form.d.cts +1 -1
  69. package/dist/ui/form.d.ts +1 -1
  70. package/dist/ui/video.d.cts +1 -1
  71. package/dist/ui/video.d.ts +1 -1
  72. package/dist/webhook.cjs +2 -1
  73. package/dist/webhook.cjs.map +1 -1
  74. package/dist/webhook.d.cts +4 -4
  75. package/dist/webhook.d.ts +4 -4
  76. package/dist/webhook.js +2 -1
  77. package/dist/webhook.js.map +1 -1
  78. package/package.json +12 -11
  79. package/dist/types-B1ngKbWI.d.cts +0 -33
  80. package/dist/types-BiKNBwRA.d.ts +0 -33
package/dist/client.cjs CHANGED
@@ -56,10 +56,136 @@ var SDKError = class extends Error {
56
56
  details: this.details,
57
57
  userMessage: this.userMessage,
58
58
  suggestion: this.suggestion,
59
- ...this.requestId !== void 0 && { requestId: this.requestId }
59
+ ...this.requestId !== void 0 && { requestId: this.requestId },
60
+ ...this.kind !== void 0 && { kind: this.kind },
61
+ ...this.reason !== void 0 && { reason: this.reason },
62
+ ...this.rawReason !== void 0 && { rawReason: this.rawReason },
63
+ ...this.retryable !== void 0 && { retryable: this.retryable },
64
+ ...this.retryAfter !== void 0 && { retryAfter: this.retryAfter }
60
65
  };
61
66
  }
62
67
  };
68
+ var COMMERCE_ERROR_CODES = [
69
+ "validation_failed",
70
+ "unauthorized",
71
+ "forbidden",
72
+ "token_expired",
73
+ "origin_not_allowed",
74
+ "server_credentials_required",
75
+ "not_found",
76
+ "conflict",
77
+ "cart_revision_conflict",
78
+ "rate_limit_exceeded",
79
+ "usage_limit_exceeded",
80
+ "service_unavailable",
81
+ "idempotency_conflict",
82
+ "idempotency_in_progress",
83
+ "cart_not_active",
84
+ "cart_locked",
85
+ "cart_empty",
86
+ "cart_market_unavailable",
87
+ "cart_market_mismatch",
88
+ "checkout_not_open",
89
+ "payment_slot_held",
90
+ "reservation_expired",
91
+ "payment_session_not_cancelable",
92
+ "provider_identity_mismatch",
93
+ "provider_unavailable",
94
+ "lock_timeout",
95
+ "price_changed",
96
+ "pricing_fact_in_use",
97
+ "insufficient_stock",
98
+ "market_not_found",
99
+ "market_shipping_currency_unsupported",
100
+ "missing_market_rate",
101
+ "missing_shipping_amount",
102
+ "no_enabled_payment_provider",
103
+ "product_market_unavailable",
104
+ "unsupported_currency",
105
+ "missing_price_row",
106
+ "payment_provider_currency_unsupported",
107
+ "discount_code_not_found",
108
+ "discount_not_started",
109
+ "discount_expired",
110
+ "discount_usage_limit",
111
+ "discount_per_customer_limit",
112
+ "discount_customer_required",
113
+ "discount_first_order_only",
114
+ "discount_customer_not_eligible",
115
+ "discount_customer_excluded",
116
+ "discount_items_required",
117
+ "discount_product_not_eligible",
118
+ "discount_product_excluded",
119
+ "discount_min_order_amount",
120
+ "discount_currency_scope_required",
121
+ "discount_allocation_method_unsupported",
122
+ "currency_mismatch"
123
+ ];
124
+ var COMMERCE_ERROR_CODE_SET = new Set(
125
+ COMMERCE_ERROR_CODES
126
+ );
127
+ var COMMERCE_ERROR_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
128
+ "error",
129
+ "reason",
130
+ "requestId",
131
+ "retryable",
132
+ "details"
133
+ ]);
134
+ function isPlainRecord(value) {
135
+ return typeof value === "object" && value !== null && !Array.isArray(value);
136
+ }
137
+ function commerceProtocolError(issue, trustedRequestId) {
138
+ return createApiError(
139
+ "Invalid canonical commerce error response.",
140
+ 502,
141
+ { protocol: "commerce-error-envelope", issue },
142
+ "The server returned an incompatible commerce error response.",
143
+ "Verify that the Console commerce contract is deployed before using this SDK version.",
144
+ trustedRequestId
145
+ );
146
+ }
147
+ function parseCommerceErrorEnvelope(body, headerRequestId) {
148
+ if (!isPlainRecord(body)) {
149
+ throw commerceProtocolError("expected_object", headerRequestId);
150
+ }
151
+ if (Object.keys(body).some((key) => !COMMERCE_ERROR_ENVELOPE_KEYS.has(key))) {
152
+ throw commerceProtocolError("unexpected_field", headerRequestId);
153
+ }
154
+ if (typeof body.error !== "string" || body.error.length === 0 || typeof body.reason !== "string" || body.reason.length === 0 || typeof body.requestId !== "string" || body.requestId.length === 0 || body.retryable !== void 0 && typeof body.retryable !== "boolean" || body.details !== void 0 && !isPlainRecord(body.details)) {
155
+ throw commerceProtocolError("invalid_field", headerRequestId);
156
+ }
157
+ if (headerRequestId && headerRequestId !== body.requestId) {
158
+ throw commerceProtocolError("request_id_mismatch", headerRequestId);
159
+ }
160
+ return {
161
+ error: body.error,
162
+ reason: body.reason,
163
+ requestId: body.requestId,
164
+ retryable: body.retryable === true,
165
+ ...body.details === void 0 ? {} : { details: body.details }
166
+ };
167
+ }
168
+ function enhanceCommerceError(error, body, headerRequestId) {
169
+ const envelope = parseCommerceErrorEnvelope(body, headerRequestId);
170
+ const known = COMMERCE_ERROR_CODE_SET.has(envelope.reason);
171
+ Object.assign(error, {
172
+ code: envelope.reason,
173
+ kind: "commerce",
174
+ reason: known ? envelope.reason : "unknown_commerce_error",
175
+ ...known ? {} : { rawReason: envelope.reason },
176
+ requestId: envelope.requestId,
177
+ retryable: envelope.retryable,
178
+ details: envelope.details
179
+ });
180
+ return error;
181
+ }
182
+ function isCommerceSDKError(error) {
183
+ if (!(error instanceof SDKError) || error.kind !== "commerce") return false;
184
+ if (typeof error.requestId !== "string" || typeof error.retryable !== "boolean" || error.retryAfter !== void 0 && (!Number.isSafeInteger(error.retryAfter) || error.retryAfter < 0) || typeof error.reason !== "string") {
185
+ return false;
186
+ }
187
+ return error.reason === "unknown_commerce_error" ? typeof error.rawReason === "string" : COMMERCE_ERROR_CODE_SET.has(error.reason) && error.rawReason === void 0;
188
+ }
63
189
  var NetworkError = class extends SDKError {
64
190
  constructor(message, status, details, userMessage, suggestion) {
65
191
  super("NETWORK_ERROR", message, status, details, userMessage, suggestion);
@@ -253,6 +379,7 @@ var NON_RETRYABLE_STATUSES = [400, 401, 403, 404, 409, 422];
253
379
  var SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
254
380
  var DEFAULT_MAX_RETRIES = 3;
255
381
  var STOREFRONT_BROWSER_MAX_RETRIES = 1;
382
+ var MAX_AUTOMATIC_RETRY_AFTER_SECONDS = 5 * 60;
256
383
  function debugLog(debug, type, message, data) {
257
384
  if (!debug) return;
258
385
  const shouldLog = debug === true || type === "request" && debug.logRequests || type === "response" && debug.logResponses || type === "error" && debug.logErrors;
@@ -367,116 +494,129 @@ function attachRequestId(err, id) {
367
494
  }
368
495
  function parseRetryAfter(response) {
369
496
  const raw = response.headers.get("Retry-After");
370
- if (!raw) return void 0;
371
- return parseInt(raw, 10) || void 0;
497
+ if (!raw) return { permitsAutomaticRetry: true };
498
+ const trimmed = raw.trim();
499
+ let seconds;
500
+ if (/^\d+$/.test(trimmed)) {
501
+ seconds = Number(trimmed);
502
+ if (!Number.isSafeInteger(seconds)) {
503
+ return { permitsAutomaticRetry: false };
504
+ }
505
+ } else {
506
+ const retryAt = Date.parse(trimmed);
507
+ if (!Number.isFinite(retryAt)) return { permitsAutomaticRetry: true };
508
+ seconds = Math.max(0, Math.ceil((retryAt - Date.now()) / 1e3));
509
+ }
510
+ return {
511
+ seconds,
512
+ permitsAutomaticRetry: seconds <= MAX_AUTOMATIC_RETRY_AFTER_SECONDS
513
+ };
372
514
  }
373
- function mapResponseToError(status, parsed, details, requestId, retryAfter) {
515
+ function mapResponseToError(status, parsed, details, requestId, retryAfter, errorFamily) {
374
516
  const errorDetails = {
375
517
  ...details,
376
518
  ...parsed.errors && { errors: parsed.errors },
377
- ...parsed.body && { body: parsed.body }
519
+ ...errorFamily !== "commerce" && parsed.body && { body: parsed.body }
378
520
  };
379
521
  const suggestion = getParsedErrorSuggestion(status, parsed);
522
+ const finalize = (error) => {
523
+ const withRequestId = attachRequestId(error, requestId);
524
+ if (retryAfter !== void 0) {
525
+ Object.assign(withRequestId, { retryAfter });
526
+ }
527
+ return errorFamily === "commerce" ? enhanceCommerceError(withRequestId, parsed.body, requestId) : withRequestId;
528
+ };
380
529
  if (status === 400 || status === 422) {
381
- return attachRequestId(
530
+ return finalize(
382
531
  createValidationError(
383
532
  parsed.errorMessage,
384
533
  errorDetails,
385
534
  parsed.userMessage,
386
535
  suggestion,
387
536
  status
388
- ),
389
- requestId
537
+ )
390
538
  );
391
539
  }
392
540
  if (status === 401) {
393
- return attachRequestId(
541
+ return finalize(
394
542
  createAuthError(
395
543
  parsed.errorMessage,
396
544
  errorDetails,
397
545
  parsed.userMessage,
398
546
  suggestion
399
- ),
400
- requestId
547
+ )
401
548
  );
402
549
  }
403
550
  if (status === 403) {
404
- return attachRequestId(
551
+ return finalize(
405
552
  createPermissionError(
406
553
  parsed.errorMessage,
407
554
  errorDetails,
408
555
  parsed.userMessage,
409
556
  suggestion
410
- ),
411
- requestId
557
+ )
412
558
  );
413
559
  }
414
560
  if (status === 404) {
415
- return attachRequestId(
561
+ return finalize(
416
562
  createNotFoundError(
417
563
  parsed.errorMessage,
418
564
  errorDetails,
419
565
  parsed.userMessage,
420
566
  suggestion
421
- ),
422
- requestId
567
+ )
423
568
  );
424
569
  }
425
570
  if (status === 409) {
426
- return attachRequestId(
571
+ return finalize(
427
572
  createConflictError(
428
573
  parsed.errorMessage,
429
574
  errorDetails,
430
575
  parsed.userMessage,
431
576
  suggestion
432
- ),
433
- requestId
577
+ )
434
578
  );
435
579
  }
436
580
  if (status === 410) {
437
- return attachRequestId(
581
+ return finalize(
438
582
  createGoneError(
439
583
  parsed.errorMessage,
440
584
  errorDetails,
441
585
  parsed.userMessage,
442
586
  suggestion
443
- ),
444
- requestId
587
+ )
445
588
  );
446
589
  }
447
590
  if (status === 429) {
448
- return attachRequestId(
591
+ return finalize(
449
592
  createRateLimitError(
450
593
  parsed.errorMessage,
451
594
  retryAfter,
452
595
  errorDetails,
453
596
  parsed.userMessage,
454
597
  suggestion
455
- ),
456
- requestId
598
+ )
457
599
  );
458
600
  }
459
601
  if (status === 503) {
460
- return attachRequestId(
602
+ return finalize(
461
603
  createServiceUnavailableError(
462
604
  parsed.errorMessage,
463
605
  retryAfter,
464
606
  errorDetails,
465
607
  parsed.userMessage,
466
608
  suggestion
467
- ),
468
- requestId
609
+ )
469
610
  );
470
611
  }
471
- return attachRequestId(
612
+ return finalize(
472
613
  createNetworkError(
473
614
  parsed.errorMessage,
474
615
  status,
475
616
  errorDetails,
476
617
  parsed.userMessage,
477
618
  suggestion
478
- ),
479
- requestId
619
+ )
480
620
  );
481
621
  }
482
622
  async function httpFetch(url, options) {
@@ -489,6 +629,7 @@ async function httpFetch(url, options) {
489
629
  debug,
490
630
  retry,
491
631
  onUnauthorized,
632
+ errorFamily,
492
633
  ...requestInit
493
634
  } = options || {};
494
635
  const baseUrl = resolveApiUrl(apiUrl);
@@ -541,6 +682,8 @@ async function httpFetch(url, options) {
541
682
  headers: redactSensitiveHeaders(response.headers)
542
683
  });
543
684
  if (!response.ok) {
685
+ const parsed = await parseErrorBody(response);
686
+ const commerceEnvelope = errorFamily === "commerce" ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
544
687
  if (isUsageLimitExceededResponse(response)) {
545
688
  const limit = parseInt(
546
689
  response.headers.get("X-Usage-Limit") || "0",
@@ -554,7 +697,7 @@ async function httpFetch(url, options) {
554
697
  response.headers.get("X-Usage-Remaining") || "0",
555
698
  10
556
699
  );
557
- throw attachRequestId(
700
+ const usageError = attachRequestId(
558
701
  createUsageLimitError(
559
702
  `Monthly API usage limit exceeded (${current.toLocaleString()}/${limit.toLocaleString()})`,
560
703
  { limit, current, remaining },
@@ -568,9 +711,9 @@ async function httpFetch(url, options) {
568
711
  ),
569
712
  requestId
570
713
  );
714
+ throw errorFamily === "commerce" ? enhanceCommerceError(usageError, parsed.body, requestId) : usageError;
571
715
  }
572
- const parsed = await parseErrorBody(response);
573
- if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && parsed.reason === "token_expired") {
716
+ if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && (commerceEnvelope?.reason ?? parsed.reason) === "token_expired") {
574
717
  hasRetried401 = true;
575
718
  try {
576
719
  const newToken = await onUnauthorized();
@@ -592,13 +735,18 @@ async function httpFetch(url, options) {
592
735
  parsed,
593
736
  details,
594
737
  requestId,
595
- retryAfter
738
+ retryAfter.seconds,
739
+ errorFamily
596
740
  );
597
741
  const method2 = (requestInit.method || "GET").toUpperCase();
598
742
  const isTerminal = error instanceof RateLimitError || error instanceof UsageLimitError;
599
- if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(method2) && !isTerminal && !NON_RETRYABLE_STATUSES.includes(response.status) && retryConfig.retryableStatuses.includes(response.status)) {
743
+ const responseAllowsRetry = isCommerceSDKError(error) ? error.retryable : true;
744
+ if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(method2) && !isTerminal && responseAllowsRetry && retryAfter.permitsAutomaticRetry && !NON_RETRYABLE_STATUSES.includes(response.status) && retryConfig.retryableStatuses.includes(response.status)) {
600
745
  lastError = error;
601
- const retryDelay = retryConfig.retryDelay(attempt);
746
+ const retryDelay = Math.max(
747
+ retryConfig.retryDelay(attempt),
748
+ (retryAfter.seconds ?? 0) * 1e3
749
+ );
602
750
  debugLog(debug, "error", `Retrying in ${retryDelay}ms...`, error);
603
751
  await delay(retryDelay);
604
752
  continue;
@@ -668,87 +816,45 @@ async function httpFetch(url, options) {
668
816
  throw lastError ?? new NetworkError("Request failed after retries");
669
817
  }
670
818
 
671
- // src/core/api/endpoints.ts
672
- var COMMERCE_ENDPOINTS = {
673
- orders: {
674
- create: "/api/orders/create",
675
- update: "/api/orders/update",
676
- confirmPayment: "/api/orders/confirm-payment",
677
- byPayment: "/api/orders/by-payment",
678
- cancel: "/api/orders/cancel",
679
- resolveCancelRefund: "/api/orders/resolve-cancel-refund",
680
- checkout: "/api/orders/checkout",
681
- createFulfillment: "/api/orders/create-fulfillment",
682
- updateFulfillment: "/api/orders/update-fulfillment"
683
- },
684
- transactions: {
685
- update: "/api/transactions/update"
686
- },
687
- returns: {
688
- create: "/api/returns/create",
689
- update: "/api/returns/update",
690
- returnRefund: "/api/returns/return-refund"
691
- },
692
- fulfillmentOrders: {
693
- prepare: "/api/fulfillment-orders/prepare-fulfillment-order"
694
- },
695
- fulfillments: {
696
- bulkImport: "/api/fulfillments/bulk-import"
697
- },
698
- carts: {
699
- mine: "/api/carts/mine",
700
- merge: "/api/carts/merge",
701
- addItem: "/api/carts/add-item",
702
- updateItem: "/api/carts/update-item",
703
- removeItem: "/api/carts/remove-item",
704
- applyDiscount: "/api/carts/apply-discount",
705
- removeDiscount: "/api/carts/remove-discount",
706
- clear: "/api/carts/clear"
707
- },
708
- products: {
709
- stockCheck: "/api/products/stock-check",
710
- stockSnapshot: "/api/products/stock",
711
- listingGroups: "/api/products/listing-groups",
712
- listingGroupsCatalog: "/api/products/listing-groups/catalog",
713
- listingGroupsQuery: "/api/products/listing-groups/query",
714
- listingGroupsQueryCatalog: "/api/products/listing-groups/query/catalog",
715
- detail: "/api/products/detail",
716
- detailCatalog: "/api/products/detail/catalog",
717
- upsert: "/api/products/upsert"
718
- }
719
- };
720
- var COMMERCE_ENDPOINT_PATHS = Object.values(
721
- COMMERCE_ENDPOINTS
722
- ).flatMap((group) => Object.values(group));
723
- var MEMBERSHIP_ENDPOINTS = {
724
- subscribe: "/api/memberships/subscribe",
725
- cancel: (id) => `/api/memberships/${id}/cancel`,
726
- me: "/api/memberships/me"
727
- };
728
-
729
819
  // src/core/internal/utils/query-string.ts
730
- function productDetailQuery(params) {
731
- const search = new URLSearchParams();
732
- if ("slug" in params) {
733
- search.set("slug", params.slug);
734
- } else {
735
- search.set("id", params.id);
820
+ function normalizedMarket(value) {
821
+ const market = value?.trim();
822
+ return market || void 0;
823
+ }
824
+ function appendProductLocaleSearchParams(search, options) {
825
+ if (options?.locale) search.set("locale", options.locale);
826
+ if (options?.fallbackLocale !== void 0) {
827
+ search.set(
828
+ "fallbackLocale",
829
+ options.fallbackLocale === false ? "none" : options.fallbackLocale
830
+ );
736
831
  }
737
- return `${COMMERCE_ENDPOINTS.products.detail}?${search}`;
738
832
  }
739
- function productDetailCatalogQuery(params) {
833
+ function productDetailSearchParams(params) {
740
834
  const search = new URLSearchParams();
741
835
  if ("slug" in params) {
742
836
  search.set("slug", params.slug);
743
837
  } else {
744
838
  search.set("id", params.id);
745
839
  }
746
- return `${COMMERCE_ENDPOINTS.products.detailCatalog}?${search}`;
840
+ const market = normalizedMarket(params.market);
841
+ if (market) search.set("market", market);
842
+ appendProductLocaleSearchParams(search, params);
843
+ return search.toString();
747
844
  }
748
- function listingGroupsCatalogQuery(params) {
749
- return `${COMMERCE_ENDPOINTS.products.listingGroupsCatalog}?ids=${params.productIds.map(encodeURIComponent).join(",")}`;
845
+ function listingGroupsSearchParams(params) {
846
+ const ids = params.productIds.map(encodeURIComponent).join(",");
847
+ const search = new URLSearchParams();
848
+ const market = normalizedMarket(params.market);
849
+ if (market) search.set("market", market);
850
+ appendProductLocaleSearchParams(search, params);
851
+ const query = search.toString();
852
+ return `ids=${ids}${query ? `&${query}` : ""}`;
750
853
  }
751
854
  function appendListingGroupsQuerySearchParams(search, options) {
855
+ const market = normalizedMarket(options?.market);
856
+ if (market) search.set("market", market);
857
+ appendProductLocaleSearchParams(search, options);
752
858
  if (options?.page != null) search.set("page", String(options.page));
753
859
  if (options?.limit != null) search.set("limit", String(options.limit));
754
860
  if (options?.sort != null) {
@@ -759,20 +865,13 @@ function appendListingGroupsQuerySearchParams(search, options) {
759
865
  search.set("whereJson", JSON.stringify(options.where));
760
866
  }
761
867
  }
762
- function listingGroupsQueryUrl(options) {
868
+ function listingPageSearchParams(options) {
763
869
  const search = new URLSearchParams();
764
870
  appendListingGroupsQuerySearchParams(search, options);
765
- const query = search.toString();
766
- return `${COMMERCE_ENDPOINTS.products.listingGroupsQuery}${query ? `?${query}` : ""}`;
871
+ return search.toString();
767
872
  }
768
- function listingGroupsQueryCatalogUrl(options) {
769
- const search = new URLSearchParams();
770
- appendListingGroupsQuerySearchParams(search, options);
771
- const query = search.toString();
772
- return `${COMMERCE_ENDPOINTS.products.listingGroupsQueryCatalog}${query ? `?${query}` : ""}`;
773
- }
774
- function stockSnapshotQuery(params) {
775
- return `${COMMERCE_ENDPOINTS.products.stockSnapshot}?variantIds=${params.variantIds.map(encodeURIComponent).join(",")}`;
873
+ function stockSnapshotSearchParams(params) {
874
+ return `variantIds=${params.variantIds.map(encodeURIComponent).join(",")}`;
776
875
  }
777
876
 
778
877
  // src/core/collection/http-client.ts
@@ -815,10 +914,15 @@ var HttpClient = class {
815
914
  throw err;
816
915
  }
817
916
  }
818
- buildUrl(endpoint, options) {
819
- if (!options) return endpoint;
820
- const queryString = (0, import_qs_esm.stringify)(options, { addQueryPrefix: true });
821
- return queryString ? `${endpoint}${queryString}` : endpoint;
917
+ buildUrl(endpoint2, options) {
918
+ if (!options) return endpoint2;
919
+ const { fallbackLocale, ...rest } = options;
920
+ const queryOptions = fallbackLocale === void 0 ? rest : {
921
+ ...rest,
922
+ "fallback-locale": fallbackLocale === false ? "none" : fallbackLocale
923
+ };
924
+ const queryString = (0, import_qs_esm.stringify)(queryOptions, { addQueryPrefix: true });
925
+ return queryString ? `${endpoint2}${queryString}` : endpoint2;
822
926
  }
823
927
  assertJsonResponse(response) {
824
928
  const contentType = response.headers.get("content-type");
@@ -960,39 +1064,39 @@ var ReadOnlyCollectionClient = class extends HttpClient {
960
1064
  from(collection) {
961
1065
  return new ReadOnlyCollectionQueryBuilder(this, collection);
962
1066
  }
963
- async requestFind(endpoint, options) {
964
- const url = this.buildUrl(endpoint, options);
1067
+ async requestFind(endpoint2, options) {
1068
+ const url = this.buildUrl(endpoint2, options);
965
1069
  const response = await this.fetchWithTracking(url, {
966
1070
  ...this.defaultOptions,
967
1071
  method: "GET"
968
1072
  });
969
1073
  return this.parseFindResponse(response);
970
1074
  }
971
- async requestFindEndpoint(endpoint, data) {
972
- const response = await this.fetchWithTracking(endpoint, {
1075
+ async requestFindEndpoint(endpoint2, data) {
1076
+ const response = await this.fetchWithTracking(endpoint2, {
973
1077
  ...this.defaultOptions,
974
1078
  method: "POST",
975
1079
  body: data ? JSON.stringify(data) : void 0
976
1080
  });
977
1081
  return this.parseFindResponse(response);
978
1082
  }
979
- async requestFindEndpointGet(endpoint) {
980
- const response = await this.fetchWithTracking(endpoint, {
1083
+ async requestFindEndpointGet(endpoint2) {
1084
+ const response = await this.fetchWithTracking(endpoint2, {
981
1085
  ...this.defaultOptions,
982
1086
  method: "GET"
983
1087
  });
984
1088
  return this.parseFindResponse(response);
985
1089
  }
986
- async requestFindById(endpoint, options) {
987
- const url = this.buildUrl(endpoint, options);
1090
+ async requestFindById(endpoint2, options) {
1091
+ const url = this.buildUrl(endpoint2, options);
988
1092
  const response = await this.fetchWithTracking(url, {
989
1093
  ...this.defaultOptions,
990
1094
  method: "GET"
991
1095
  });
992
1096
  return this.parseDocumentResponse(response);
993
1097
  }
994
- async requestCount(endpoint, options) {
995
- const url = this.buildUrl(endpoint, options);
1098
+ async requestCount(endpoint2, options) {
1099
+ const url = this.buildUrl(endpoint2, options);
996
1100
  const response = await this.fetchWithTracking(url, {
997
1101
  ...this.defaultOptions,
998
1102
  method: "GET"
@@ -1002,53 +1106,339 @@ var ReadOnlyCollectionClient = class extends HttpClient {
1002
1106
  };
1003
1107
 
1004
1108
  // src/core/api/parse-response.ts
1005
- async function parseApiResponse(response, endpoint) {
1006
- let data;
1109
+ async function parseApiResponse(response, endpoint2, options = {}) {
1110
+ if (response.status === 204 || response.headers.get("content-length") === "0") {
1111
+ return void 0;
1112
+ }
1113
+ let parsed;
1007
1114
  try {
1008
- data = await response.json();
1115
+ parsed = await response.json();
1009
1116
  } catch {
1010
1117
  throw createApiError(
1011
- `Invalid JSON response from ${endpoint}`,
1118
+ `Invalid JSON response from ${endpoint2}`,
1012
1119
  response.status,
1013
1120
  void 0,
1014
1121
  "Server returned an invalid response.",
1015
1122
  "Check if the API endpoint is available."
1016
1123
  );
1017
1124
  }
1125
+ if (parsed === null || typeof parsed !== "object") {
1126
+ return parsed;
1127
+ }
1128
+ const data = parsed;
1018
1129
  if (data.error) {
1019
1130
  const errorMessage = typeof data.error === "string" ? data.error : "Unknown API error";
1020
1131
  const reason = typeof data.reason === "string" ? data.reason : void 0;
1021
1132
  const requestId = response.headers.get("x-request-id") ?? void 0;
1022
- const retryAfterRaw = response.headers.get("Retry-After");
1023
- const retryAfter = retryAfterRaw ? parseInt(retryAfterRaw, 10) || void 0 : void 0;
1133
+ const retryAfter = parseRetryAfter(response).seconds;
1134
+ let error;
1024
1135
  if (reason === "validation_failed") {
1025
- throw attachRequestId(createValidationError(errorMessage, data, errorMessage), requestId);
1026
- }
1027
- if (reason === "token_expired" || reason === "token_invalid" || reason === "preview_token_invalid" || reason === "preview_token_required" || reason === "key_invalid" || reason === "key_revoked") {
1028
- throw attachRequestId(createAuthError(errorMessage, data, errorMessage), requestId);
1136
+ error = createValidationError(errorMessage, data, errorMessage);
1137
+ } else if (reason === "token_expired" || reason === "token_invalid" || reason === "preview_token_invalid" || reason === "preview_token_required" || reason === "key_invalid" || reason === "key_revoked") {
1138
+ error = createAuthError(errorMessage, data, errorMessage);
1139
+ } else if (reason === "forbidden") {
1140
+ error = createPermissionError(errorMessage, data, errorMessage);
1141
+ } else if (reason === "rate_limit_exceeded") {
1142
+ error = createRateLimitError(errorMessage, retryAfter, data, errorMessage);
1143
+ } else if (reason === "not_found") {
1144
+ error = createNotFoundError(errorMessage, data, errorMessage);
1145
+ } else if (reason === "conflict") {
1146
+ error = createConflictError(errorMessage, data, errorMessage);
1147
+ } else {
1148
+ error = createApiError(
1149
+ errorMessage,
1150
+ response.status,
1151
+ data,
1152
+ errorMessage,
1153
+ "An error occurred while processing the request."
1154
+ );
1029
1155
  }
1030
- if (reason === "forbidden") {
1031
- throw attachRequestId(createPermissionError(errorMessage, data, errorMessage), requestId);
1156
+ const withRequestId = attachRequestId(error, requestId);
1157
+ if (retryAfter !== void 0) Object.assign(withRequestId, { retryAfter });
1158
+ throw options.errorFamily === "commerce" ? enhanceCommerceError(withRequestId, data, requestId) : withRequestId;
1159
+ }
1160
+ return data;
1161
+ }
1162
+
1163
+ // ../../internal/http-contracts/src/index.ts
1164
+ var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
1165
+ var operation = (collection, method, path) => Object.freeze({
1166
+ [operationBrand]: true,
1167
+ collection,
1168
+ method,
1169
+ path
1170
+ });
1171
+ var COMMERCE_ENDPOINT_OPERATIONS = {
1172
+ products: {
1173
+ detail: operation("products", "get", "/detail"),
1174
+ detailCatalog: operation("products", "get", "/detail/catalog"),
1175
+ listingGroups: operation("products", "get", "/listing-groups"),
1176
+ listingGroupsCatalog: operation(
1177
+ "products",
1178
+ "get",
1179
+ "/listing-groups/catalog"
1180
+ ),
1181
+ listingGroupsQuery: operation("products", "post", "/listing-groups/query"),
1182
+ listingGroupsQueryGet: operation(
1183
+ "products",
1184
+ "get",
1185
+ "/listing-groups/query"
1186
+ ),
1187
+ listingGroupsQueryCatalog: operation(
1188
+ "products",
1189
+ "get",
1190
+ "/listing-groups/query/catalog"
1191
+ ),
1192
+ stockCheck: operation("products", "post", "/stock-check"),
1193
+ stockSnapshot: operation("products", "get", "/stock"),
1194
+ upsert: operation("products", "post", "/upsert")
1195
+ },
1196
+ orders: {
1197
+ create: operation("orders", "post", "/create"),
1198
+ update: operation("orders", "post", "/update"),
1199
+ confirmPayment: operation("orders", "post", "/confirm-payment"),
1200
+ byPayment: operation("orders", "get", "/by-payment"),
1201
+ cancel: operation("orders", "post", "/cancel"),
1202
+ resolveCancelRefund: operation("orders", "post", "/resolve-cancel-refund"),
1203
+ checkout: operation("orders", "post", "/checkout"),
1204
+ createFulfillment: operation("orders", "post", "/create-fulfillment"),
1205
+ updateFulfillment: operation("orders", "post", "/update-fulfillment")
1206
+ },
1207
+ checkouts: {
1208
+ detail: operation("checkouts", "post", "/detail"),
1209
+ query: operation("checkouts", "post", "/query")
1210
+ },
1211
+ transactions: {
1212
+ update: operation("transactions", "post", "/update")
1213
+ },
1214
+ returns: {
1215
+ create: operation("returns", "post", "/create"),
1216
+ update: operation("returns", "post", "/update"),
1217
+ returnRefund: operation("returns", "post", "/return-refund")
1218
+ },
1219
+ fulfillmentOrders: {
1220
+ prepare: operation(
1221
+ "fulfillment-orders",
1222
+ "post",
1223
+ "/prepare-fulfillment-order"
1224
+ )
1225
+ },
1226
+ fulfillments: {
1227
+ bulkImport: operation("fulfillments", "post", "/bulk-import")
1228
+ },
1229
+ carts: {
1230
+ create: operation("carts", "post", "/create"),
1231
+ retrieve: operation("carts", "post", "/retrieve"),
1232
+ mine: operation("carts", "post", "/mine"),
1233
+ merge: operation("carts", "post", "/merge"),
1234
+ addItem: operation("carts", "post", "/add-item"),
1235
+ updateItem: operation("carts", "post", "/update-item"),
1236
+ removeItem: operation("carts", "post", "/remove-item"),
1237
+ updateDiscountCodes: operation("carts", "post", "/update-discount-codes"),
1238
+ updateAttributes: operation("carts", "post", "/update-attributes"),
1239
+ clear: operation("carts", "post", "/clear")
1240
+ },
1241
+ paymentSessions: {
1242
+ create: operation("payment-sessions", "post", "/create"),
1243
+ retrieve: operation("payment-sessions", "post", "/retrieve"),
1244
+ cancel: operation("payment-sessions", "post", "/cancel"),
1245
+ server: {
1246
+ create: operation("payment-sessions", "post", "/server/create"),
1247
+ retrieve: operation("payment-sessions", "post", "/server/retrieve"),
1248
+ cancel: operation("payment-sessions", "post", "/server/cancel"),
1249
+ confirm: operation("payment-sessions", "post", "/server/confirm")
1250
+ },
1251
+ custom: {
1252
+ create: operation("orders", "post", "/custom-payment-sessions"),
1253
+ confirm: operation("orders", "post", "/custom-payment-sessions/confirm")
1032
1254
  }
1033
- if (reason === "rate_limit_exceeded") {
1034
- throw attachRequestId(createRateLimitError(errorMessage, retryAfter, data, errorMessage), requestId);
1255
+ },
1256
+ shippingPolicies: {
1257
+ calculate: operation("shipping-policies", "post", "/calculate")
1258
+ },
1259
+ discounts: {
1260
+ validate: operation("discounts", "post", "/validate")
1261
+ }
1262
+ };
1263
+ var MEMBERSHIP_ENDPOINT_OPERATIONS = {
1264
+ subscribe: operation(null, "post", "/memberships/subscribe"),
1265
+ cancel: operation(null, "post", "/memberships/:id/cancel"),
1266
+ me: operation(null, "get", "/memberships/me")
1267
+ };
1268
+ var EVENTS_ENDPOINT_OPERATIONS = {
1269
+ occurrences: {
1270
+ range: operation("event-occurrences", "get", "/range"),
1271
+ admissionAvailability: operation(
1272
+ "event-occurrences",
1273
+ "get",
1274
+ "/admission-availability"
1275
+ )
1276
+ }
1277
+ };
1278
+ function resolveOperationTemplate(descriptor) {
1279
+ return descriptor.collection ? `/api/${descriptor.collection}${descriptor.path}` : `/api${descriptor.path}`;
1280
+ }
1281
+ function resolveOperationPath(descriptor, options) {
1282
+ const path = resolveOperationTemplate(descriptor).replace(
1283
+ /:([A-Za-z][A-Za-z0-9_]*)/g,
1284
+ (_, key) => {
1285
+ const value = options?.pathParams?.[key];
1286
+ if (value === void 0) {
1287
+ throw new TypeError(`Missing path parameter: ${key}`);
1288
+ }
1289
+ return encodeURIComponent(value);
1035
1290
  }
1036
- if (reason === "not_found") {
1037
- throw attachRequestId(createNotFoundError(errorMessage, data, errorMessage), requestId);
1291
+ );
1292
+ const unresolved = path.match(/:([A-Za-z][A-Za-z0-9_]*)/);
1293
+ if (unresolved) {
1294
+ throw new TypeError(`Missing path parameter: ${unresolved[1]}`);
1295
+ }
1296
+ const query = options?.query?.toString().replace(/^\?/, "");
1297
+ return query ? `${path}?${query}` : path;
1298
+ }
1299
+ function resolveOperationMethod(descriptor) {
1300
+ return descriptor.method.toUpperCase();
1301
+ }
1302
+
1303
+ // src/core/api/endpoints.ts
1304
+ var endpoint = (method, path) => ({ method, path });
1305
+ var sharedEndpoint = (descriptor) => descriptor;
1306
+ function resolveOperationMethod2(descriptor) {
1307
+ return "collection" in descriptor ? resolveOperationMethod(descriptor) : descriptor.method;
1308
+ }
1309
+ function resolveOperationPath2(descriptor, options) {
1310
+ if ("collection" in descriptor) {
1311
+ return resolveOperationPath(descriptor, options);
1312
+ }
1313
+ const query = options?.query?.toString().replace(/^\?/, "");
1314
+ return query ? `${descriptor.path}?${query}` : descriptor.path;
1315
+ }
1316
+ var COMMERCE_ENDPOINTS = {
1317
+ products: {
1318
+ detail: endpoint("GET", "/api/products/detail"),
1319
+ detailCatalog: endpoint("GET", "/api/products/detail/catalog"),
1320
+ listingGroups: endpoint("GET", "/api/products/listing-groups"),
1321
+ listingGroupsCatalog: endpoint(
1322
+ "GET",
1323
+ "/api/products/listing-groups/catalog"
1324
+ ),
1325
+ listingGroupsQuery: endpoint("GET", "/api/products/listing-groups/query"),
1326
+ listingGroupsQueryCatalog: endpoint(
1327
+ "GET",
1328
+ "/api/products/listing-groups/query/catalog"
1329
+ ),
1330
+ stockCheck: endpoint("POST", "/api/products/stock-check"),
1331
+ stockSnapshot: endpoint("GET", "/api/products/stock"),
1332
+ upsert: endpoint("POST", "/api/products/upsert")
1333
+ },
1334
+ orders: {
1335
+ update: endpoint("POST", "/api/orders/update"),
1336
+ byPayment: endpoint("GET", "/api/orders/by-payment"),
1337
+ cancel: endpoint("POST", "/api/orders/cancel"),
1338
+ resolveCancelRefund: endpoint("POST", "/api/orders/resolve-cancel-refund"),
1339
+ createFulfillment: endpoint("POST", "/api/orders/create-fulfillment"),
1340
+ updateFulfillment: endpoint("POST", "/api/orders/update-fulfillment")
1341
+ },
1342
+ checkouts: {
1343
+ create: endpoint("POST", "/api/orders/checkout"),
1344
+ retrieve: endpoint("POST", "/api/checkouts/detail"),
1345
+ server: {
1346
+ create: endpoint("POST", "/api/orders/checkout"),
1347
+ retrieve: endpoint("POST", "/api/checkouts/detail"),
1348
+ query: endpoint("POST", "/api/checkouts/query")
1038
1349
  }
1039
- if (reason === "conflict") {
1040
- throw attachRequestId(createConflictError(errorMessage, data, errorMessage), requestId);
1350
+ },
1351
+ returns: {
1352
+ create: endpoint("POST", "/api/returns/create"),
1353
+ update: endpoint("POST", "/api/returns/update"),
1354
+ returnRefund: endpoint("POST", "/api/returns/return-refund")
1355
+ },
1356
+ fulfillmentOrders: {
1357
+ prepare: endpoint(
1358
+ "POST",
1359
+ "/api/fulfillment-orders/prepare-fulfillment-order"
1360
+ )
1361
+ },
1362
+ fulfillments: {
1363
+ bulkImport: endpoint("POST", "/api/fulfillments/bulk-import")
1364
+ },
1365
+ carts: {
1366
+ create: endpoint("POST", "/api/carts/create"),
1367
+ retrieve: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.retrieve),
1368
+ mine: endpoint("POST", "/api/carts/mine"),
1369
+ merge: endpoint("POST", "/api/carts/merge"),
1370
+ server: {
1371
+ // Server credentials are an authorization lane, not a second Cart
1372
+ // transport. These must stay bound to the registered shared operations.
1373
+ create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.create),
1374
+ retrieve: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.retrieve),
1375
+ mine: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.mine),
1376
+ merge: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.merge),
1377
+ addItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.addItem),
1378
+ updateItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.updateItem),
1379
+ removeItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.removeItem),
1380
+ updateDiscountCodes: sharedEndpoint(
1381
+ COMMERCE_ENDPOINT_OPERATIONS.carts.updateDiscountCodes
1382
+ ),
1383
+ updateAttributes: sharedEndpoint(
1384
+ COMMERCE_ENDPOINT_OPERATIONS.carts.updateAttributes
1385
+ ),
1386
+ clear: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.clear)
1387
+ },
1388
+ addItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.addItem),
1389
+ updateItem: endpoint("POST", "/api/carts/update-item"),
1390
+ removeItem: endpoint("POST", "/api/carts/remove-item"),
1391
+ updateDiscountCodes: endpoint("POST", "/api/carts/update-discount-codes"),
1392
+ updateAttributes: endpoint("POST", "/api/carts/update-attributes"),
1393
+ clear: endpoint("POST", "/api/carts/clear")
1394
+ },
1395
+ paymentSessions: {
1396
+ create: endpoint("POST", "/api/payment-sessions/create"),
1397
+ retrieve: endpoint("POST", "/api/payment-sessions/retrieve"),
1398
+ cancel: endpoint("POST", "/api/payment-sessions/cancel"),
1399
+ server: {
1400
+ create: endpoint("POST", "/api/payment-sessions/server/create"),
1401
+ retrieve: endpoint("POST", "/api/payment-sessions/server/retrieve"),
1402
+ cancel: endpoint("POST", "/api/payment-sessions/server/cancel"),
1403
+ confirm: endpoint("POST", "/api/payment-sessions/server/confirm")
1041
1404
  }
1042
- throw attachRequestId(
1043
- createApiError(errorMessage, response.status, data, errorMessage, "An error occurred while processing the request."),
1044
- requestId
1045
- );
1405
+ },
1406
+ shippingPolicies: {
1407
+ calculate: endpoint("POST", "/api/shipping-policies/calculate")
1046
1408
  }
1047
- return data;
1409
+ };
1410
+ function isCommerceEndpointDescriptor(value) {
1411
+ if (!value || typeof value !== "object") return false;
1412
+ const candidate = value;
1413
+ return typeof candidate.method === "string" && typeof candidate.path === "string";
1048
1414
  }
1415
+ function flattenEndpointPaths(value) {
1416
+ if (isCommerceEndpointDescriptor(value)) return [resolveOperationPath2(value)];
1417
+ if (!value || typeof value !== "object") return [];
1418
+ return Object.values(value).flatMap((entry) => flattenEndpointPaths(entry));
1419
+ }
1420
+ function flattenEndpointDescriptors(value) {
1421
+ if (isCommerceEndpointDescriptor(value)) return [value];
1422
+ if (!value || typeof value !== "object") return [];
1423
+ return Object.values(value).flatMap(
1424
+ (entry) => flattenEndpointDescriptors(entry)
1425
+ );
1426
+ }
1427
+ var COMMERCE_ENDPOINT_PATHS = flattenEndpointPaths(COMMERCE_ENDPOINTS);
1428
+ var COMMERCE_ENDPOINT_DESCRIPTORS = flattenEndpointDescriptors(COMMERCE_ENDPOINTS);
1429
+ var MEMBERSHIP_ENDPOINTS = {
1430
+ subscribe: "/api/memberships/subscribe",
1431
+ cancel: (id) => `/api/memberships/${id}/cancel`,
1432
+ me: "/api/memberships/me"
1433
+ };
1434
+ var MEMBERSHIP_ENDPOINT_PATHS = [
1435
+ MEMBERSHIP_ENDPOINTS.subscribe,
1436
+ MEMBERSHIP_ENDPOINTS.cancel(":id"),
1437
+ MEMBERSHIP_ENDPOINTS.me
1438
+ ];
1049
1439
 
1050
1440
  // src/core/api/customer-scoped-api.ts
1051
- var CustomerScopedApi = class {
1441
+ var CustomerScopedTransport = class {
1052
1442
  constructor(apiName, options) {
1053
1443
  if (options.requiresCredential !== false && !options.secretKey && !options.customerToken) {
1054
1444
  throw createConfigError(
@@ -1066,10 +1456,10 @@ var CustomerScopedApi = class {
1066
1456
  this.onUnauthorized = options.onUnauthorized;
1067
1457
  this.onRequestId = options.onRequestId;
1068
1458
  }
1069
- async request(endpoint, options) {
1459
+ async request(endpoint2, options) {
1070
1460
  const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
1071
1461
  try {
1072
- const response = await httpFetch(endpoint, {
1462
+ const response = await httpFetch(endpoint2, {
1073
1463
  method: options.method,
1074
1464
  apiUrl: this.apiUrl,
1075
1465
  publishableKey: this.publishableKey,
@@ -1079,10 +1469,13 @@ var CustomerScopedApi = class {
1079
1469
  ...options.body !== void 0 && {
1080
1470
  body: JSON.stringify(options.body)
1081
1471
  },
1082
- ...options.headers && { headers: options.headers }
1472
+ ...options.headers && { headers: options.headers },
1473
+ ...options.errorFamily && { errorFamily: options.errorFamily }
1083
1474
  });
1084
1475
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
1085
- return parseApiResponse(response, endpoint);
1476
+ return parseApiResponse(response, endpoint2, {
1477
+ errorFamily: options.errorFamily
1478
+ });
1086
1479
  } catch (err) {
1087
1480
  const id = err instanceof SDKError ? err.requestId ?? null : null;
1088
1481
  this.onRequestId?.(id);
@@ -1090,6 +1483,26 @@ var CustomerScopedApi = class {
1090
1483
  }
1091
1484
  }
1092
1485
  };
1486
+ var CustomerScopedApi = class {
1487
+ constructor(apiName, options) {
1488
+ this.transport = new CustomerScopedTransport(apiName, options);
1489
+ }
1490
+ requestEndpoint(endpoint2, body, options) {
1491
+ return this.transport.request(resolveOperationPath2(endpoint2, options), {
1492
+ method: resolveOperationMethod2(endpoint2),
1493
+ body,
1494
+ headers: options?.headers
1495
+ });
1496
+ }
1497
+ };
1498
+ var RawCustomerScopedApi = class {
1499
+ constructor(apiName, options) {
1500
+ this.transport = new CustomerScopedTransport(apiName, options);
1501
+ }
1502
+ request(endpoint2, options) {
1503
+ return this.transport.request(endpoint2, options);
1504
+ }
1505
+ };
1093
1506
 
1094
1507
  // src/core/community/community-client.ts
1095
1508
  var DEFAULT_POST_LIST_SORT = "-lastActivityAt";
@@ -1100,7 +1513,7 @@ function unwrapPayloadDoc(value) {
1100
1513
  }
1101
1514
  return value;
1102
1515
  }
1103
- var CommunityClient = class extends CustomerScopedApi {
1516
+ var CommunityClient = class extends RawCustomerScopedApi {
1104
1517
  constructor(options) {
1105
1518
  super("CommunityClient", { ...options, requiresCredential: false });
1106
1519
  }
@@ -1144,11 +1557,11 @@ var CommunityClient = class extends CustomerScopedApi {
1144
1557
  if (params.page !== void 0) urlParams.set("page", String(params.page));
1145
1558
  return `/api/comments/public?${urlParams.toString()}`;
1146
1559
  }
1147
- async execute(endpoint, method, body) {
1148
- return this.request(endpoint, { method, body });
1560
+ async execute(endpoint2, method, body) {
1561
+ return this.request(endpoint2, { method, body });
1149
1562
  }
1150
- async executeDoc(endpoint, method, body) {
1151
- const response = await this.execute(endpoint, method, body);
1563
+ async executeDoc(endpoint2, method, body) {
1564
+ const response = await this.execute(endpoint2, method, body);
1152
1565
  return unwrapPayloadDoc(response);
1153
1566
  }
1154
1567
  createPost(params) {
@@ -1384,56 +1797,1538 @@ var CommunityClient = class extends CustomerScopedApi {
1384
1797
  body
1385
1798
  );
1386
1799
  }
1387
- };
1388
-
1389
- // src/core/content/content-client.ts
1390
- var PublicContentApi = class extends CustomerScopedApi {
1391
- get(endpoint) {
1392
- return this.request(endpoint, { method: "GET" });
1393
- }
1394
- };
1395
- function appendCommonParams(search, options, defaultSort) {
1396
- search.set("sort", options?.sort ?? defaultSort);
1397
- if (options?.page != null) search.set("page", String(options.page));
1398
- if (options?.limit != null) search.set("limit", String(options.limit));
1399
- }
1400
- function linksListPath(options) {
1401
- const search = new URLSearchParams();
1402
- appendCommonParams(search, options, "-publishedAt,-createdAt");
1403
- if (options?.categoryId) search.set("categoryId", options.categoryId);
1404
- if (options?.categorySlug) {
1405
- search.set("categorySlug", options.categorySlug);
1406
- }
1407
- if (options?.tagId) search.set("tagId", options.tagId);
1408
- if (options?.tagSlug) search.set("tagSlug", options.tagSlug);
1409
- if (options?.featured != null) search.set("featured", String(options.featured));
1410
- return `/api/links/storefront?${search}`;
1411
- }
1412
- function galleryItemsListPath(options) {
1413
- const search = new URLSearchParams();
1414
- appendCommonParams(search, options, "manual");
1415
- if (options?.galleryId) search.set("galleryId", options.galleryId);
1416
- if (options?.gallerySlug) search.set("gallerySlug", options.gallerySlug);
1417
- return `/api/gallery-items/storefront?${search}`;
1800
+ };
1801
+
1802
+ // src/core/content/content-client.ts
1803
+ var PublicContentApi = class extends RawCustomerScopedApi {
1804
+ get(endpoint2) {
1805
+ return this.request(endpoint2, { method: "GET" });
1806
+ }
1807
+ };
1808
+ function appendCommonParams(search, options, defaultSort) {
1809
+ search.set("sort", options?.sort ?? defaultSort);
1810
+ if (options?.page != null) search.set("page", String(options.page));
1811
+ if (options?.limit != null) search.set("limit", String(options.limit));
1812
+ }
1813
+ function linksListPath(options) {
1814
+ const search = new URLSearchParams();
1815
+ appendCommonParams(search, options, "-publishedAt,-createdAt");
1816
+ if (options?.categoryId) search.set("categoryId", options.categoryId);
1817
+ if (options?.categorySlug) {
1818
+ search.set("categorySlug", options.categorySlug);
1819
+ }
1820
+ if (options?.tagId) search.set("tagId", options.tagId);
1821
+ if (options?.tagSlug) search.set("tagSlug", options.tagSlug);
1822
+ if (options?.featured != null)
1823
+ search.set("featured", String(options.featured));
1824
+ return `/api/links/storefront?${search}`;
1825
+ }
1826
+ function galleryItemsListPath(options) {
1827
+ const search = new URLSearchParams();
1828
+ appendCommonParams(search, options, "manual");
1829
+ if (options?.galleryId) search.set("galleryId", options.galleryId);
1830
+ if (options?.gallerySlug) search.set("gallerySlug", options.gallerySlug);
1831
+ return `/api/gallery-items/storefront?${search}`;
1832
+ }
1833
+ var ContentClient = class {
1834
+ constructor(options) {
1835
+ const api = new PublicContentApi("ContentClient", {
1836
+ publishableKey: options.publishableKey,
1837
+ apiUrl: options.apiUrl,
1838
+ onRequestId: options.onRequestId,
1839
+ requiresCredential: false
1840
+ });
1841
+ this.links = {
1842
+ list: (params) => api.get(linksListPath(params))
1843
+ };
1844
+ this.galleryItems = {
1845
+ list: (params) => api.get(
1846
+ galleryItemsListPath(params)
1847
+ )
1848
+ };
1849
+ }
1850
+ };
1851
+
1852
+ // src/core/api/canonical-response.ts
1853
+ var CART_STATUSES = ["active", "completed", "abandoned"];
1854
+ var MAX_CART_LINE_QUANTITY = 99;
1855
+ var MAX_COMMERCE_SHORT_TEXT_LENGTH = 200;
1856
+ var MAX_COMMERCE_ADDRESS_LENGTH = 500;
1857
+ var MAX_COMMERCE_EMAIL_LENGTH = 254;
1858
+ var MAX_COMMERCE_PHONE_LENGTH = 32;
1859
+ var MAX_COMMERCE_POSTAL_CODE_LENGTH = 32;
1860
+ var MAX_COMMERCE_EXTENSION_VALUE_LENGTH = 500;
1861
+ var MAX_COMMERCE_RESOURCE_ID_LENGTH = 255;
1862
+ var MAX_COMMERCE_CAPABILITY_LENGTH = 512;
1863
+ var MAX_CART_DISCOUNT_CODE_LENGTH = 128;
1864
+ var ORDER_FINANCIAL_STATUSES = [
1865
+ "pending",
1866
+ "authorized",
1867
+ "expired",
1868
+ "partially_paid",
1869
+ "paid",
1870
+ "canceled",
1871
+ "partially_refunded",
1872
+ "refunded",
1873
+ "reconciliation_required"
1874
+ ];
1875
+ var ORDER_FULFILLMENT_STATUSES = [
1876
+ "unfulfilled",
1877
+ "in_progress",
1878
+ "on_hold",
1879
+ "partially_fulfilled",
1880
+ "shipped",
1881
+ "fulfilled",
1882
+ "canceled"
1883
+ ];
1884
+ var ORDER_RETURN_STATUSES = [
1885
+ "no_return",
1886
+ "return_requested",
1887
+ "in_progress",
1888
+ "returned"
1889
+ ];
1890
+ var ORDER_CONFIRMATION_STATUSES = ["unconfirmed", "confirmed"];
1891
+ var ORDER_PRIMARY_DISPLAY_STATUSES = [
1892
+ "pending",
1893
+ "paid",
1894
+ "canceled",
1895
+ "refunded",
1896
+ "preparing",
1897
+ "shipped",
1898
+ "delivered",
1899
+ "confirmed"
1900
+ ];
1901
+ var CHECKOUT_STATUSES = ["open", "placed", "abandoned"];
1902
+ var ABANDONED_REASONS = ["expired", "customer", "operator"];
1903
+ var PAYMENT_PROVIDERS = ["toss"];
1904
+ var PAYMENT_PROVIDER_STATUSES = [
1905
+ "requires_payment_method",
1906
+ "requires_action",
1907
+ "requires_confirmation",
1908
+ "initializing",
1909
+ "processing",
1910
+ "authorized",
1911
+ "canceling",
1912
+ "unknown",
1913
+ "captured",
1914
+ "failed",
1915
+ "canceled"
1916
+ ];
1917
+ var PAYMENT_FAILURE_REASONS = [
1918
+ "payment_declined",
1919
+ "authentication_failed",
1920
+ "authorization_expired",
1921
+ "payment_method_unavailable",
1922
+ "provider_terminal_failure",
1923
+ "unknown_provider_terminal_failure"
1924
+ ];
1925
+ var CART_WARNING_CODES = [
1926
+ "DISCOUNT_CODE_NOT_HONOURED",
1927
+ "DISCOUNT_CURRENTLY_INACTIVE",
1928
+ "DISCOUNT_CUSTOMER_NOT_ELIGIBLE",
1929
+ "DISCOUNT_CUSTOMER_USAGE_LIMIT_REACHED",
1930
+ "DISCOUNT_ELIGIBLE_CUSTOMER_MISSING",
1931
+ "DISCOUNT_NO_ENTITLED_LINE_ITEMS",
1932
+ "DISCOUNT_NO_ENTITLED_SHIPPING_LINES",
1933
+ "DISCOUNT_NOT_FOUND",
1934
+ "DISCOUNT_PURCHASE_NOT_IN_RANGE",
1935
+ "DISCOUNT_USAGE_LIMIT_REACHED",
1936
+ "MERCHANDISE_NOT_ENOUGH_STOCK",
1937
+ "MERCHANDISE_OUT_OF_STOCK"
1938
+ ];
1939
+ function invalidCanonicalResponse(resource, details) {
1940
+ throw createApiError(
1941
+ `Invalid canonical ${resource} response.`,
1942
+ 502,
1943
+ { resource, ...details },
1944
+ `The server returned an incompatible ${resource} response.`,
1945
+ "Verify that the Console commerce contract is deployed before using this SDK version."
1946
+ );
1947
+ }
1948
+ function fail(resource, path, expected) {
1949
+ invalidCanonicalResponse(resource, { path, expected });
1950
+ }
1951
+ function record(value, resource, path) {
1952
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1953
+ fail(resource, path, "object");
1954
+ }
1955
+ return value;
1956
+ }
1957
+ function exact(value, required, optional, resource, path) {
1958
+ for (const key of required) {
1959
+ if (!(key in value)) fail(resource, `${path}.${key}`, "required field");
1960
+ }
1961
+ const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
1962
+ const unexpected = Object.keys(value).find((key) => !allowed.has(key));
1963
+ if (unexpected) fail(resource, `${path}.${unexpected}`, "no unknown fields");
1964
+ }
1965
+ function string(value, resource, path) {
1966
+ if (typeof value !== "string" || value.length === 0) {
1967
+ fail(resource, path, "non-empty string");
1968
+ }
1969
+ return value;
1970
+ }
1971
+ function boundedString(value, maxLength, resource, path, allowEmpty = false) {
1972
+ if (typeof value !== "string" || !allowEmpty && value.length === 0 || value.length > maxLength) {
1973
+ fail(
1974
+ resource,
1975
+ path,
1976
+ `${allowEmpty ? "" : "non-empty "}string of at most ${maxLength} characters`
1977
+ );
1978
+ }
1979
+ return value;
1980
+ }
1981
+ function nullableString(value, resource, path) {
1982
+ if (value !== null && typeof value !== "string") {
1983
+ fail(resource, path, "string or null");
1984
+ }
1985
+ }
1986
+ function cartLineQuantity(value, resource, path) {
1987
+ const quantity = positiveInteger(value, resource, path);
1988
+ if (quantity > MAX_CART_LINE_QUANTITY) {
1989
+ fail(resource, path, `integer between 1 and ${MAX_CART_LINE_QUANTITY}`);
1990
+ }
1991
+ return quantity;
1992
+ }
1993
+ function boolean(value, resource, path) {
1994
+ if (typeof value !== "boolean") fail(resource, path, "boolean");
1995
+ }
1996
+ function safeMinor(value, resource, path) {
1997
+ if (!Number.isSafeInteger(value) || value < 0) {
1998
+ fail(resource, path, "non-negative safe integer");
1999
+ }
2000
+ return value;
2001
+ }
2002
+ function positiveInteger(value, resource, path) {
2003
+ if (!Number.isSafeInteger(value) || value <= 0) {
2004
+ fail(resource, path, "positive safe integer");
2005
+ }
2006
+ return value;
2007
+ }
2008
+ function enumValue(value, values, resource, path) {
2009
+ if (typeof value !== "string" || !values.includes(value)) {
2010
+ fail(resource, path, values.join(" | "));
2011
+ }
2012
+ return value;
2013
+ }
2014
+ function timestamp(value, resource, path) {
2015
+ if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d{2}:\d{2})$/.test(value) || !Number.isFinite(Date.parse(value))) {
2016
+ fail(resource, path, "ISO 8601 timestamp with offset");
2017
+ }
2018
+ }
2019
+ function currency(value, resource, path) {
2020
+ if (typeof value !== "string" || !/^[A-Z]{3}$/.test(value)) {
2021
+ fail(resource, path, "three-letter uppercase currency code");
2022
+ }
2023
+ }
2024
+ function array(value, resource, path) {
2025
+ if (!Array.isArray(value)) fail(resource, path, "array");
2026
+ return value;
2027
+ }
2028
+ function optionalNullableNumber(value, resource, path) {
2029
+ if (value !== void 0 && value !== null && typeof value !== "number") {
2030
+ fail(resource, path, "number or null");
2031
+ }
2032
+ }
2033
+ function validateMediaSize(value, resource, path) {
2034
+ const item = record(value, resource, path);
2035
+ exact(
2036
+ item,
2037
+ [],
2038
+ ["width", "height", "mimeType", "filename", "url"],
2039
+ resource,
2040
+ path
2041
+ );
2042
+ optionalNullableNumber(item.width, resource, `${path}.width`);
2043
+ optionalNullableNumber(item.height, resource, `${path}.height`);
2044
+ for (const key of ["mimeType", "filename", "url"]) {
2045
+ if (item[key] !== void 0)
2046
+ nullableString(item[key], resource, `${path}.${key}`);
2047
+ }
2048
+ }
2049
+ function validateMedia(value, resource, path) {
2050
+ if (typeof value === "string") return;
2051
+ const media = record(value, resource, path);
2052
+ exact(
2053
+ media,
2054
+ [],
2055
+ ["id", "alt", "width", "height", "mimeType", "filename", "url", "sizes"],
2056
+ resource,
2057
+ path
2058
+ );
2059
+ if (media.id !== void 0 && media.id !== null && typeof media.id !== "string" && typeof media.id !== "number") {
2060
+ fail(resource, `${path}.id`, "string, number, or null");
2061
+ }
2062
+ for (const key of ["alt", "mimeType", "filename", "url"]) {
2063
+ if (media[key] !== void 0)
2064
+ nullableString(media[key], resource, `${path}.${key}`);
2065
+ }
2066
+ optionalNullableNumber(media.width, resource, `${path}.width`);
2067
+ optionalNullableNumber(media.height, resource, `${path}.height`);
2068
+ if (media.sizes !== void 0) {
2069
+ const sizes = record(media.sizes, resource, `${path}.sizes`);
2070
+ Object.entries(sizes).forEach(
2071
+ ([key, size]) => validateMediaSize(size, resource, `${path}.sizes.${key}`)
2072
+ );
2073
+ }
2074
+ }
2075
+ function validateReference(value, resource, path) {
2076
+ const ref = record(value, resource, path);
2077
+ exact(ref, ["id", "title", "handle", "image"], [], resource, path);
2078
+ string(ref.id, resource, `${path}.id`);
2079
+ string(ref.title, resource, `${path}.title`);
2080
+ if (ref.handle !== null) string(ref.handle, resource, `${path}.handle`);
2081
+ if (ref.image !== null) validateMedia(ref.image, resource, `${path}.image`);
2082
+ }
2083
+ function validateAdmission(value, resource, path) {
2084
+ const admission = record(value, resource, path);
2085
+ exact(
2086
+ admission,
2087
+ ["eventId", "occurrenceId", "admissionTypeId"],
2088
+ [],
2089
+ resource,
2090
+ path
2091
+ );
2092
+ string(admission.eventId, resource, `${path}.eventId`);
2093
+ string(admission.occurrenceId, resource, `${path}.occurrenceId`);
2094
+ string(admission.admissionTypeId, resource, `${path}.admissionTypeId`);
2095
+ }
2096
+ function compareAdmissions(left, right) {
2097
+ for (const field of ["eventId", "occurrenceId", "admissionTypeId"]) {
2098
+ if (left[field] < right[field]) return -1;
2099
+ if (left[field] > right[field]) return 1;
2100
+ }
2101
+ return 0;
2102
+ }
2103
+ function validateAdmissions(value, resource, path) {
2104
+ const admissions = array(value, resource, path);
2105
+ if (admissions.length > 32) fail(resource, path, "at most 32 admissions");
2106
+ let prior;
2107
+ admissions.forEach((admission, index) => {
2108
+ validateAdmission(admission, resource, `${path}[${index}]`);
2109
+ const item = admission;
2110
+ const comparison = prior ? compareAdmissions(item, prior) : void 0;
2111
+ if (comparison !== void 0 && comparison <= 0) {
2112
+ fail(resource, `${path}[${index}]`, "unique canonical-sorted admissions");
2113
+ }
2114
+ prior = item;
2115
+ });
2116
+ }
2117
+ function validateAttributes(value, resource, path) {
2118
+ const attributes = array(value, resource, path);
2119
+ if (attributes.length > 50) fail(resource, path, "at most 50 attributes");
2120
+ const keys = /* @__PURE__ */ new Set();
2121
+ attributes.forEach((value2, index) => {
2122
+ const itemPath = `${path}[${index}]`;
2123
+ const attribute = record(value2, resource, itemPath);
2124
+ exact(attribute, ["key", "value"], [], resource, itemPath);
2125
+ const key = string(attribute.key, resource, `${itemPath}.key`);
2126
+ if (key.length > 40 || key.startsWith("__") || keys.has(key)) {
2127
+ fail(
2128
+ resource,
2129
+ `${itemPath}.key`,
2130
+ "unique, non-reserved key of at most 40 characters"
2131
+ );
2132
+ }
2133
+ keys.add(key);
2134
+ if (typeof attribute.value !== "string" || attribute.value.length > 500) {
2135
+ fail(resource, `${itemPath}.value`, "string of at most 500 characters");
2136
+ }
2137
+ });
2138
+ }
2139
+ function validateCustomer(value, resource, path) {
2140
+ const customer = record(value, resource, path);
2141
+ exact(customer, ["email"], ["name", "phone"], resource, path);
2142
+ const email = boundedString(
2143
+ customer.email,
2144
+ MAX_COMMERCE_EMAIL_LENGTH,
2145
+ resource,
2146
+ `${path}.email`
2147
+ );
2148
+ if (!/^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9-]*\.)+[A-Za-z]{2,}$/.test(
2149
+ email
2150
+ )) {
2151
+ fail(resource, `${path}.email`, "email address");
2152
+ }
2153
+ if (customer.name !== void 0)
2154
+ boundedString(
2155
+ customer.name,
2156
+ MAX_COMMERCE_SHORT_TEXT_LENGTH,
2157
+ resource,
2158
+ `${path}.name`
2159
+ );
2160
+ if (customer.phone !== void 0)
2161
+ boundedString(
2162
+ customer.phone,
2163
+ MAX_COMMERCE_PHONE_LENGTH,
2164
+ resource,
2165
+ `${path}.phone`
2166
+ );
2167
+ }
2168
+ function validateShippingAddress(value, resource, path) {
2169
+ const address = record(value, resource, path);
2170
+ exact(
2171
+ address,
2172
+ ["recipientName", "phone", "postalCode", "address", "detailAddress"],
2173
+ ["countryCode", "regionCode", "deliveryMessage"],
2174
+ resource,
2175
+ path
2176
+ );
2177
+ boundedString(
2178
+ address.recipientName,
2179
+ MAX_COMMERCE_SHORT_TEXT_LENGTH,
2180
+ resource,
2181
+ `${path}.recipientName`
2182
+ );
2183
+ boundedString(
2184
+ address.phone,
2185
+ MAX_COMMERCE_PHONE_LENGTH,
2186
+ resource,
2187
+ `${path}.phone`
2188
+ );
2189
+ boundedString(
2190
+ address.postalCode,
2191
+ MAX_COMMERCE_POSTAL_CODE_LENGTH,
2192
+ resource,
2193
+ `${path}.postalCode`
2194
+ );
2195
+ for (const key of ["address", "detailAddress"]) {
2196
+ boundedString(
2197
+ address[key],
2198
+ MAX_COMMERCE_ADDRESS_LENGTH,
2199
+ resource,
2200
+ `${path}.${key}`
2201
+ );
2202
+ }
2203
+ if (address.countryCode !== void 0) {
2204
+ if (typeof address.countryCode !== "string" || address.countryCode.trim().length !== 2) {
2205
+ fail(resource, `${path}.countryCode`, "two-letter country code");
2206
+ }
2207
+ }
2208
+ if (address.regionCode !== void 0) {
2209
+ if (typeof address.regionCode !== "string" || address.regionCode.trim().length === 0 || address.regionCode.trim().length > 64) {
2210
+ fail(
2211
+ resource,
2212
+ `${path}.regionCode`,
2213
+ "trimmed string of at most 64 characters"
2214
+ );
2215
+ }
2216
+ }
2217
+ if (address.deliveryMessage !== void 0) {
2218
+ boundedString(
2219
+ address.deliveryMessage,
2220
+ MAX_COMMERCE_EXTENSION_VALUE_LENGTH,
2221
+ resource,
2222
+ `${path}.deliveryMessage`,
2223
+ true
2224
+ );
2225
+ }
2226
+ }
2227
+ function validateOrderReference(value, resource, path) {
2228
+ const order = record(value, resource, path);
2229
+ exact(order, ["id", "orderNumber"], [], resource, path);
2230
+ string(order.id, resource, `${path}.id`);
2231
+ string(order.orderNumber, resource, `${path}.orderNumber`);
2232
+ }
2233
+ function validateIntegrationMetadata(value, resource, path) {
2234
+ const metadata = record(value, resource, path);
2235
+ if (Object.keys(metadata).length > 50)
2236
+ fail(resource, path, "at most 50 entries");
2237
+ Object.entries(metadata).forEach(([key, entry]) => {
2238
+ if (!key || key.length > 40 || key.includes("[") || key.includes("]")) {
2239
+ fail(resource, `${path}.${key}`, "valid metadata key");
2240
+ }
2241
+ if (typeof entry !== "string" || entry.length > 500) {
2242
+ fail(resource, `${path}.${key}`, "string of at most 500 characters");
2243
+ }
2244
+ });
2245
+ }
2246
+ function validateCartItem(value, resource, path) {
2247
+ const item = record(value, resource, path);
2248
+ exact(
2249
+ item,
2250
+ [
2251
+ "id",
2252
+ "product",
2253
+ "variant",
2254
+ "admissions",
2255
+ "quantity",
2256
+ "unitPriceMinor",
2257
+ "discountMinor",
2258
+ "estimatedLineTotalMinor",
2259
+ "requiresShipping"
2260
+ ],
2261
+ [],
2262
+ resource,
2263
+ path
2264
+ );
2265
+ string(item.id, resource, `${path}.id`);
2266
+ validateReference(item.product, resource, `${path}.product`);
2267
+ validateReference(item.variant, resource, `${path}.variant`);
2268
+ validateAdmissions(item.admissions, resource, `${path}.admissions`);
2269
+ cartLineQuantity(item.quantity, resource, `${path}.quantity`);
2270
+ const unitPrice = safeMinor(
2271
+ item.unitPriceMinor,
2272
+ resource,
2273
+ `${path}.unitPriceMinor`
2274
+ );
2275
+ const discount = safeMinor(
2276
+ item.discountMinor,
2277
+ resource,
2278
+ `${path}.discountMinor`
2279
+ );
2280
+ const estimatedLineTotal = safeMinor(
2281
+ item.estimatedLineTotalMinor,
2282
+ resource,
2283
+ `${path}.estimatedLineTotalMinor`
2284
+ );
2285
+ const quantity = item.quantity;
2286
+ const expectedLineTotal = BigInt(unitPrice) * BigInt(quantity) - BigInt(discount);
2287
+ if (expectedLineTotal < 0n || BigInt(estimatedLineTotal) !== expectedLineTotal) {
2288
+ fail(
2289
+ resource,
2290
+ `${path}.estimatedLineTotalMinor`,
2291
+ "unitPriceMinor * quantity - discountMinor"
2292
+ );
2293
+ }
2294
+ boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
2295
+ }
2296
+ function validatePublicCart(value, resource = "Cart") {
2297
+ const cart = record(value, resource, "$");
2298
+ exact(
2299
+ cart,
2300
+ [
2301
+ "id",
2302
+ "status",
2303
+ "revision",
2304
+ "currency",
2305
+ "market",
2306
+ "subtotalMinor",
2307
+ "discountMinor",
2308
+ "estimatedTotalMinor",
2309
+ "discountCodes",
2310
+ "attributes",
2311
+ "items",
2312
+ "expiresAt",
2313
+ "createdAt",
2314
+ "updatedAt"
2315
+ ],
2316
+ [],
2317
+ resource,
2318
+ "$"
2319
+ );
2320
+ string(cart.id, resource, "$.id");
2321
+ enumValue(cart.status, CART_STATUSES, resource, "$.status");
2322
+ safeMinor(cart.revision, resource, "$.revision");
2323
+ currency(cart.currency, resource, "$.currency");
2324
+ const market = record(cart.market, resource, "$.market");
2325
+ exact(market, ["id", "handle", "name"], [], resource, "$.market");
2326
+ for (const key of ["id", "handle", "name"])
2327
+ string(market[key], resource, `$.market.${key}`);
2328
+ const subtotal = safeMinor(cart.subtotalMinor, resource, "$.subtotalMinor");
2329
+ const discount = safeMinor(cart.discountMinor, resource, "$.discountMinor");
2330
+ const estimatedTotal = safeMinor(
2331
+ cart.estimatedTotalMinor,
2332
+ resource,
2333
+ "$.estimatedTotalMinor"
2334
+ );
2335
+ array(cart.discountCodes, resource, "$.discountCodes").forEach(
2336
+ (value2, index) => {
2337
+ const itemPath = `$.discountCodes[${index}]`;
2338
+ const code = record(value2, resource, itemPath);
2339
+ exact(code, ["code", "applicable"], [], resource, itemPath);
2340
+ boundedString(
2341
+ code.code,
2342
+ MAX_CART_DISCOUNT_CODE_LENGTH,
2343
+ resource,
2344
+ `${itemPath}.code`
2345
+ );
2346
+ boolean(code.applicable, resource, `${itemPath}.applicable`);
2347
+ }
2348
+ );
2349
+ validateAttributes(cart.attributes, resource, "$.attributes");
2350
+ const items = array(cart.items, resource, "$.items");
2351
+ items.forEach(
2352
+ (item, index) => validateCartItem(item, resource, `$.items[${index}]`)
2353
+ );
2354
+ const expectedSubtotal = items.reduce((total, value2) => {
2355
+ const item = value2;
2356
+ return total + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
2357
+ }, 0n);
2358
+ const expectedDiscount = items.reduce((total, value2) => {
2359
+ const item = value2;
2360
+ return total + BigInt(item.discountMinor);
2361
+ }, 0n);
2362
+ if (BigInt(subtotal) !== expectedSubtotal) {
2363
+ fail(resource, "$.subtotalMinor", "sum of undiscounted cart line totals");
2364
+ }
2365
+ if (BigInt(discount) !== expectedDiscount) {
2366
+ fail(resource, "$.discountMinor", "sum of cart line discounts");
2367
+ }
2368
+ if (expectedSubtotal - BigInt(discount) < 0n || BigInt(estimatedTotal) !== expectedSubtotal - BigInt(discount)) {
2369
+ fail(resource, "$.estimatedTotalMinor", "subtotalMinor - discountMinor");
2370
+ }
2371
+ timestamp(cart.expiresAt, resource, "$.expiresAt");
2372
+ timestamp(cart.createdAt, resource, "$.createdAt");
2373
+ timestamp(cart.updatedAt, resource, "$.updatedAt");
2374
+ return value;
2375
+ }
2376
+ function validateWarnings(value, resource, path) {
2377
+ array(value, resource, path).forEach((value2, index) => {
2378
+ const itemPath = `${path}[${index}]`;
2379
+ const warning = record(value2, resource, itemPath);
2380
+ exact(warning, ["code", "message", "target"], [], resource, itemPath);
2381
+ enumValue(warning.code, CART_WARNING_CODES, resource, `${itemPath}.code`);
2382
+ string(warning.message, resource, `${itemPath}.message`);
2383
+ string(warning.target, resource, `${itemPath}.target`);
2384
+ });
2385
+ }
2386
+ function validateCartMutationResult(value) {
2387
+ const result = record(value, "Cart mutation result", "$");
2388
+ exact(result, ["cart", "warnings"], [], "Cart mutation result", "$");
2389
+ validatePublicCart(result.cart);
2390
+ validateWarnings(result.warnings, "Cart mutation result", "$.warnings");
2391
+ return value;
2392
+ }
2393
+ function validateCreateCartResult(value) {
2394
+ const result = record(value, "Cart create result", "$");
2395
+ exact(
2396
+ result,
2397
+ ["cart", "warnings", "cartToken"],
2398
+ [],
2399
+ "Cart create result",
2400
+ "$"
2401
+ );
2402
+ const cart = record(result.cart, "Cart create result", "$.cart");
2403
+ validatePublicCart(cart);
2404
+ if (cart.revision !== 0) {
2405
+ fail("Cart create result", "$.cart.revision", "0 for a newly created Cart");
2406
+ }
2407
+ validateWarnings(result.warnings, "Cart create result", "$.warnings");
2408
+ boundedString(
2409
+ result.cartToken,
2410
+ MAX_COMMERCE_CAPABILITY_LENGTH,
2411
+ "Cart create result",
2412
+ "$.cartToken"
2413
+ );
2414
+ return value;
2415
+ }
2416
+ function validateCartMineResult(value) {
2417
+ const result = record(value, "Cart mine result", "$");
2418
+ exact(result, ["cart", "cartToken"], [], "Cart mine result", "$");
2419
+ if (result.cart === null || result.cartToken === null) {
2420
+ if (result.cart !== null || result.cartToken !== null) {
2421
+ fail("Cart mine result", "$", "cart and cartToken must both be null");
2422
+ }
2423
+ } else {
2424
+ validatePublicCart(result.cart);
2425
+ boundedString(
2426
+ result.cartToken,
2427
+ MAX_COMMERCE_CAPABILITY_LENGTH,
2428
+ "Cart mine result",
2429
+ "$.cartToken"
2430
+ );
2431
+ }
2432
+ return value;
2433
+ }
2434
+ function validateCartMergeResult(value) {
2435
+ const result = record(value, "Cart merge result", "$");
2436
+ exact(
2437
+ result,
2438
+ ["cart", "warnings", "cartToken", "resolution", "merged", "claimed"],
2439
+ [],
2440
+ "Cart merge result",
2441
+ "$"
2442
+ );
2443
+ validatePublicCart(result.cart);
2444
+ validateWarnings(result.warnings, "Cart merge result", "$.warnings");
2445
+ boundedString(
2446
+ result.cartToken,
2447
+ MAX_COMMERCE_CAPABILITY_LENGTH,
2448
+ "Cart merge result",
2449
+ "$.cartToken"
2450
+ );
2451
+ const resolution = enumValue(
2452
+ result.resolution,
2453
+ ["unchanged", "claimed", "merged"],
2454
+ "Cart merge result",
2455
+ "$.resolution"
2456
+ );
2457
+ boolean(result.merged, "Cart merge result", "$.merged");
2458
+ boolean(result.claimed, "Cart merge result", "$.claimed");
2459
+ const expected = resolution === "merged" ? [true, false] : resolution === "claimed" ? [false, true] : [false, false];
2460
+ if (result.merged !== expected[0] || result.claimed !== expected[1]) {
2461
+ fail("Cart merge result", "$", "resolution-consistent merged/claimed flags");
2462
+ }
2463
+ return value;
2464
+ }
2465
+ function validatePublicOrderItem(value, resource, path) {
2466
+ const item = record(value, resource, path);
2467
+ exact(
2468
+ item,
2469
+ [
2470
+ "id",
2471
+ "product",
2472
+ "variant",
2473
+ "productTitle",
2474
+ "variantTitle",
2475
+ "sku",
2476
+ "admissions",
2477
+ "quantity",
2478
+ "unitPriceMinor",
2479
+ "discountMinor",
2480
+ "lineTotalMinor",
2481
+ "requiresShipping"
2482
+ ],
2483
+ [],
2484
+ resource,
2485
+ path
2486
+ );
2487
+ string(item.id, resource, `${path}.id`);
2488
+ if (item.product !== null) {
2489
+ validateReference(item.product, resource, `${path}.product`);
2490
+ }
2491
+ if (item.variant !== null) {
2492
+ validateReference(item.variant, resource, `${path}.variant`);
2493
+ }
2494
+ string(item.productTitle, resource, `${path}.productTitle`);
2495
+ nullableString(item.variantTitle, resource, `${path}.variantTitle`);
2496
+ nullableString(item.sku, resource, `${path}.sku`);
2497
+ validateAdmissions(item.admissions, resource, `${path}.admissions`);
2498
+ const quantity = positiveInteger(item.quantity, resource, `${path}.quantity`);
2499
+ const unitPrice = safeMinor(
2500
+ item.unitPriceMinor,
2501
+ resource,
2502
+ `${path}.unitPriceMinor`
2503
+ );
2504
+ const discount = safeMinor(
2505
+ item.discountMinor,
2506
+ resource,
2507
+ `${path}.discountMinor`
2508
+ );
2509
+ const lineTotal = safeMinor(
2510
+ item.lineTotalMinor,
2511
+ resource,
2512
+ `${path}.lineTotalMinor`
2513
+ );
2514
+ const expected = BigInt(unitPrice) * BigInt(quantity) - BigInt(discount);
2515
+ if (expected < 0n || BigInt(lineTotal) !== expected) {
2516
+ fail(
2517
+ resource,
2518
+ `${path}.lineTotalMinor`,
2519
+ "unitPriceMinor * quantity - discountMinor"
2520
+ );
2521
+ }
2522
+ boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
2523
+ }
2524
+ function validatePublicOrderAt(value, resource, path) {
2525
+ const order = record(value, resource, path);
2526
+ exact(
2527
+ order,
2528
+ [
2529
+ "id",
2530
+ "orderNumber",
2531
+ "amounts",
2532
+ "market",
2533
+ "customerSnapshot",
2534
+ "shippingAddress",
2535
+ "attributes",
2536
+ "items",
2537
+ "financialStatus",
2538
+ "fulfillmentStatus",
2539
+ "returnStatus",
2540
+ "confirmationStatus",
2541
+ "primaryDisplayStatus",
2542
+ "placedAt",
2543
+ "createdAt",
2544
+ "updatedAt"
2545
+ ],
2546
+ [],
2547
+ resource,
2548
+ path
2549
+ );
2550
+ string(order.id, resource, `${path}.id`);
2551
+ string(order.orderNumber, resource, `${path}.orderNumber`);
2552
+ const amounts = record(order.amounts, resource, `${path}.amounts`);
2553
+ exact(
2554
+ amounts,
2555
+ [
2556
+ "currency",
2557
+ "subtotalMinor",
2558
+ "shippingMinor",
2559
+ "discountMinor",
2560
+ "totalMinor",
2561
+ "refundedMinor",
2562
+ "currentTotalMinor"
2563
+ ],
2564
+ [],
2565
+ resource,
2566
+ `${path}.amounts`
2567
+ );
2568
+ currency(amounts.currency, resource, `${path}.amounts.currency`);
2569
+ const subtotal = safeMinor(
2570
+ amounts.subtotalMinor,
2571
+ resource,
2572
+ `${path}.amounts.subtotalMinor`
2573
+ );
2574
+ const shipping = safeMinor(
2575
+ amounts.shippingMinor,
2576
+ resource,
2577
+ `${path}.amounts.shippingMinor`
2578
+ );
2579
+ const discount = safeMinor(
2580
+ amounts.discountMinor,
2581
+ resource,
2582
+ `${path}.amounts.discountMinor`
2583
+ );
2584
+ const total = safeMinor(
2585
+ amounts.totalMinor,
2586
+ resource,
2587
+ `${path}.amounts.totalMinor`
2588
+ );
2589
+ const refunded = safeMinor(
2590
+ amounts.refundedMinor,
2591
+ resource,
2592
+ `${path}.amounts.refundedMinor`
2593
+ );
2594
+ const current = safeMinor(
2595
+ amounts.currentTotalMinor,
2596
+ resource,
2597
+ `${path}.amounts.currentTotalMinor`
2598
+ );
2599
+ const expectedTotal = BigInt(subtotal) + BigInt(shipping) - BigInt(discount);
2600
+ if (expectedTotal < 0n || BigInt(total) !== expectedTotal) {
2601
+ fail(
2602
+ resource,
2603
+ `${path}.amounts.totalMinor`,
2604
+ "subtotalMinor + shippingMinor - discountMinor"
2605
+ );
2606
+ }
2607
+ if (BigInt(total) - BigInt(refunded) < 0n || current !== total - refunded) {
2608
+ fail(
2609
+ resource,
2610
+ `${path}.amounts.currentTotalMinor`,
2611
+ "totalMinor - refundedMinor"
2612
+ );
2613
+ }
2614
+ if (order.market !== null) {
2615
+ const market = record(order.market, resource, `${path}.market`);
2616
+ exact(market, ["id", "handle", "name"], [], resource, `${path}.market`);
2617
+ for (const key of ["id", "handle", "name"]) {
2618
+ string(market[key], resource, `${path}.market.${key}`);
2619
+ }
2620
+ }
2621
+ validateCustomer(order.customerSnapshot, resource, `${path}.customerSnapshot`);
2622
+ if (order.shippingAddress !== null) {
2623
+ validateShippingAddress(
2624
+ order.shippingAddress,
2625
+ resource,
2626
+ `${path}.shippingAddress`
2627
+ );
2628
+ }
2629
+ validateAttributes(order.attributes, resource, `${path}.attributes`);
2630
+ const items = array(order.items, resource, `${path}.items`);
2631
+ if (items.length === 0) fail(resource, `${path}.items`, "non-empty array");
2632
+ items.forEach(
2633
+ (item, index) => validatePublicOrderItem(item, resource, `${path}.items[${index}]`)
2634
+ );
2635
+ const expectedSubtotal = items.reduce((sum, value2) => {
2636
+ const item = value2;
2637
+ return sum + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
2638
+ }, 0n);
2639
+ const expectedDiscount = items.reduce((sum, value2) => {
2640
+ const item = value2;
2641
+ return sum + BigInt(item.discountMinor);
2642
+ }, 0n);
2643
+ if (BigInt(subtotal) !== expectedSubtotal) {
2644
+ fail(resource, `${path}.amounts.subtotalMinor`, "sum of line subtotals");
2645
+ }
2646
+ if (BigInt(discount) !== expectedDiscount) {
2647
+ fail(resource, `${path}.amounts.discountMinor`, "sum of line discounts");
2648
+ }
2649
+ enumValue(
2650
+ order.financialStatus,
2651
+ ORDER_FINANCIAL_STATUSES,
2652
+ resource,
2653
+ `${path}.financialStatus`
2654
+ );
2655
+ enumValue(
2656
+ order.fulfillmentStatus,
2657
+ ORDER_FULFILLMENT_STATUSES,
2658
+ resource,
2659
+ `${path}.fulfillmentStatus`
2660
+ );
2661
+ enumValue(
2662
+ order.returnStatus,
2663
+ ORDER_RETURN_STATUSES,
2664
+ resource,
2665
+ `${path}.returnStatus`
2666
+ );
2667
+ enumValue(
2668
+ order.confirmationStatus,
2669
+ ORDER_CONFIRMATION_STATUSES,
2670
+ resource,
2671
+ `${path}.confirmationStatus`
2672
+ );
2673
+ enumValue(
2674
+ order.primaryDisplayStatus,
2675
+ ORDER_PRIMARY_DISPLAY_STATUSES,
2676
+ resource,
2677
+ `${path}.primaryDisplayStatus`
2678
+ );
2679
+ timestamp(order.placedAt, resource, `${path}.placedAt`);
2680
+ timestamp(order.createdAt, resource, `${path}.createdAt`);
2681
+ timestamp(order.updatedAt, resource, `${path}.updatedAt`);
2682
+ }
2683
+ function nullablePositiveInteger(value, resource, path) {
2684
+ if (value !== null) positiveInteger(value, resource, path);
2685
+ }
2686
+ function validatePublicOrderList(value) {
2687
+ const resource = "Order list";
2688
+ const result = record(value, resource, "$");
2689
+ exact(
2690
+ result,
2691
+ [
2692
+ "docs",
2693
+ "totalDocs",
2694
+ "limit",
2695
+ "totalPages",
2696
+ "page",
2697
+ "pagingCounter",
2698
+ "hasPrevPage",
2699
+ "hasNextPage",
2700
+ "prevPage",
2701
+ "nextPage"
2702
+ ],
2703
+ [],
2704
+ resource,
2705
+ "$"
2706
+ );
2707
+ array(result.docs, resource, "$.docs").forEach(
2708
+ (order, index) => validatePublicOrderAt(order, resource, `$.docs[${index}]`)
2709
+ );
2710
+ safeMinor(result.totalDocs, resource, "$.totalDocs");
2711
+ positiveInteger(result.limit, resource, "$.limit");
2712
+ safeMinor(result.totalPages, resource, "$.totalPages");
2713
+ positiveInteger(result.page, resource, "$.page");
2714
+ positiveInteger(result.pagingCounter, resource, "$.pagingCounter");
2715
+ boolean(result.hasPrevPage, resource, "$.hasPrevPage");
2716
+ boolean(result.hasNextPage, resource, "$.hasNextPage");
2717
+ nullablePositiveInteger(result.prevPage, resource, "$.prevPage");
2718
+ nullablePositiveInteger(result.nextPage, resource, "$.nextPage");
2719
+ return value;
2720
+ }
2721
+ function validateCheckoutItem(value, resource, path) {
2722
+ const item = record(value, resource, path);
2723
+ exact(
2724
+ item,
2725
+ [
2726
+ "id",
2727
+ "product",
2728
+ "variant",
2729
+ "productTitle",
2730
+ "variantTitle",
2731
+ "sku",
2732
+ "admissions",
2733
+ "quantity",
2734
+ "unitPriceMinor",
2735
+ "discountMinor",
2736
+ "lineTotalMinor",
2737
+ "requiresShipping"
2738
+ ],
2739
+ [],
2740
+ resource,
2741
+ path
2742
+ );
2743
+ string(item.id, resource, `${path}.id`);
2744
+ validateReference(item.product, resource, `${path}.product`);
2745
+ validateReference(item.variant, resource, `${path}.variant`);
2746
+ string(item.productTitle, resource, `${path}.productTitle`);
2747
+ nullableString(item.variantTitle, resource, `${path}.variantTitle`);
2748
+ nullableString(item.sku, resource, `${path}.sku`);
2749
+ validateAdmissions(item.admissions, resource, `${path}.admissions`);
2750
+ cartLineQuantity(item.quantity, resource, `${path}.quantity`);
2751
+ const unitPrice = safeMinor(
2752
+ item.unitPriceMinor,
2753
+ resource,
2754
+ `${path}.unitPriceMinor`
2755
+ );
2756
+ const discount = safeMinor(
2757
+ item.discountMinor,
2758
+ resource,
2759
+ `${path}.discountMinor`
2760
+ );
2761
+ const lineTotal = safeMinor(
2762
+ item.lineTotalMinor,
2763
+ resource,
2764
+ `${path}.lineTotalMinor`
2765
+ );
2766
+ const expectedLineTotal = BigInt(unitPrice) * BigInt(item.quantity) - BigInt(discount);
2767
+ if (expectedLineTotal < 0n || BigInt(lineTotal) !== expectedLineTotal) {
2768
+ fail(
2769
+ resource,
2770
+ `${path}.lineTotalMinor`,
2771
+ "unitPriceMinor * quantity - discountMinor"
2772
+ );
2773
+ }
2774
+ boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
2775
+ }
2776
+ function validateCheckoutAmounts(value, resource, path) {
2777
+ const amounts = record(value, resource, path);
2778
+ exact(
2779
+ amounts,
2780
+ [
2781
+ "currency",
2782
+ "subtotalMinor",
2783
+ "shippingMinor",
2784
+ "discountMinor",
2785
+ "totalMinor"
2786
+ ],
2787
+ [],
2788
+ resource,
2789
+ path
2790
+ );
2791
+ currency(amounts.currency, resource, `${path}.currency`);
2792
+ const subtotal = safeMinor(
2793
+ amounts.subtotalMinor,
2794
+ resource,
2795
+ `${path}.subtotalMinor`
2796
+ );
2797
+ const shipping = safeMinor(
2798
+ amounts.shippingMinor,
2799
+ resource,
2800
+ `${path}.shippingMinor`
2801
+ );
2802
+ const discount = safeMinor(
2803
+ amounts.discountMinor,
2804
+ resource,
2805
+ `${path}.discountMinor`
2806
+ );
2807
+ const total = safeMinor(amounts.totalMinor, resource, `${path}.totalMinor`);
2808
+ if (BigInt(total) !== BigInt(subtotal) + BigInt(shipping) - BigInt(discount)) {
2809
+ fail(
2810
+ resource,
2811
+ `${path}.totalMinor`,
2812
+ "subtotalMinor + shippingMinor - discountMinor"
2813
+ );
2814
+ }
2815
+ }
2816
+ function validatePaymentSessionReference(value, resource, path) {
2817
+ const session = record(value, resource, path);
2818
+ exact(session, ["id", "provider", "providerStatus"], [], resource, path);
2819
+ string(session.id, resource, `${path}.id`);
2820
+ enumValue(session.provider, PAYMENT_PROVIDERS, resource, `${path}.provider`);
2821
+ enumValue(
2822
+ session.providerStatus,
2823
+ PAYMENT_PROVIDER_STATUSES,
2824
+ resource,
2825
+ `${path}.providerStatus`
2826
+ );
2827
+ }
2828
+ function checkoutVariantKeys(status, placedVia) {
2829
+ const base = [
2830
+ "id",
2831
+ "amounts",
2832
+ "items",
2833
+ "customerSnapshot",
2834
+ "shippingAddress",
2835
+ "attributes",
2836
+ "expiresAt",
2837
+ "createdAt",
2838
+ "updatedAt",
2839
+ "status",
2840
+ "paymentState",
2841
+ "order"
2842
+ ];
2843
+ if (status === "open") return { required: base, optional: [] };
2844
+ if (status === "abandoned") {
2845
+ return {
2846
+ required: [...base, "abandonedAt", "abandonedReason"],
2847
+ optional: []
2848
+ };
2849
+ }
2850
+ return placedVia === "late_capture" ? {
2851
+ required: [
2852
+ ...base,
2853
+ "placedAt",
2854
+ "placedVia",
2855
+ "abandonedAt",
2856
+ "abandonedReason"
2857
+ ],
2858
+ optional: []
2859
+ } : { required: [...base, "placedAt"], optional: [] };
2860
+ }
2861
+ function validateCheckoutCore(value, resource, list, server) {
2862
+ const checkout = record(value, resource, "$");
2863
+ const status = enumValue(
2864
+ checkout.status,
2865
+ CHECKOUT_STATUSES,
2866
+ resource,
2867
+ "$.status"
2868
+ );
2869
+ const keys = checkoutVariantKeys(status, checkout.placedVia);
2870
+ if (list) {
2871
+ keys.required = keys.required.filter(
2872
+ (key) => !["items", "shippingAddress", "attributes"].includes(key)
2873
+ );
2874
+ keys.required.push("clientReferenceId");
2875
+ } else if (server) {
2876
+ keys.required.push("clientReferenceId", "integrationMetadata");
2877
+ }
2878
+ exact(checkout, keys.required, keys.optional, resource, "$");
2879
+ string(checkout.id, resource, "$.id");
2880
+ validateCheckoutAmounts(checkout.amounts, resource, "$.amounts");
2881
+ if (!list) {
2882
+ const items = array(checkout.items, resource, "$.items");
2883
+ if (items.length === 0) fail(resource, "$.items", "non-empty array");
2884
+ items.forEach(
2885
+ (item, index) => validateCheckoutItem(item, resource, `$.items[${index}]`)
2886
+ );
2887
+ const expectedSubtotal = items.reduce((total, value2) => {
2888
+ const item = value2;
2889
+ return total + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
2890
+ }, 0n);
2891
+ const expectedDiscount = items.reduce((total, value2) => {
2892
+ const item = value2;
2893
+ return total + BigInt(item.discountMinor);
2894
+ }, 0n);
2895
+ const amounts = checkout.amounts;
2896
+ if (BigInt(amounts.subtotalMinor) !== expectedSubtotal) {
2897
+ fail(
2898
+ resource,
2899
+ "$.amounts.subtotalMinor",
2900
+ "sum of undiscounted checkout line totals"
2901
+ );
2902
+ }
2903
+ if (BigInt(amounts.discountMinor) !== expectedDiscount) {
2904
+ fail(
2905
+ resource,
2906
+ "$.amounts.discountMinor",
2907
+ "sum of checkout line discounts"
2908
+ );
2909
+ }
2910
+ if (checkout.shippingAddress !== null) {
2911
+ validateShippingAddress(
2912
+ checkout.shippingAddress,
2913
+ resource,
2914
+ "$.shippingAddress"
2915
+ );
2916
+ }
2917
+ validateAttributes(checkout.attributes, resource, "$.attributes");
2918
+ }
2919
+ validateCustomer(checkout.customerSnapshot, resource, "$.customerSnapshot");
2920
+ timestamp(checkout.expiresAt, resource, "$.expiresAt");
2921
+ timestamp(checkout.createdAt, resource, "$.createdAt");
2922
+ timestamp(checkout.updatedAt, resource, "$.updatedAt");
2923
+ const paymentState = record(checkout.paymentState, resource, "$.paymentState");
2924
+ exact(paymentState, ["activePaymentSession"], [], resource, "$.paymentState");
2925
+ if (status === "open") {
2926
+ if (paymentState.activePaymentSession !== null) {
2927
+ validatePaymentSessionReference(
2928
+ paymentState.activePaymentSession,
2929
+ resource,
2930
+ "$.paymentState.activePaymentSession"
2931
+ );
2932
+ }
2933
+ if (checkout.order !== null)
2934
+ fail(resource, "$.order", "null for open Checkout");
2935
+ } else {
2936
+ if (paymentState.activePaymentSession !== null) {
2937
+ fail(
2938
+ resource,
2939
+ "$.paymentState.activePaymentSession",
2940
+ "null for spent Checkout"
2941
+ );
2942
+ }
2943
+ if (status === "placed") {
2944
+ timestamp(checkout.placedAt, resource, "$.placedAt");
2945
+ validateOrderReference(checkout.order, resource, "$.order");
2946
+ if (checkout.placedVia !== void 0 && checkout.placedVia !== "late_capture") {
2947
+ fail(resource, "$.placedVia", "late_capture");
2948
+ }
2949
+ if (checkout.placedVia === "late_capture") {
2950
+ timestamp(checkout.abandonedAt, resource, "$.abandonedAt");
2951
+ enumValue(
2952
+ checkout.abandonedReason,
2953
+ ABANDONED_REASONS,
2954
+ resource,
2955
+ "$.abandonedReason"
2956
+ );
2957
+ }
2958
+ } else {
2959
+ timestamp(checkout.abandonedAt, resource, "$.abandonedAt");
2960
+ enumValue(
2961
+ checkout.abandonedReason,
2962
+ ABANDONED_REASONS,
2963
+ resource,
2964
+ "$.abandonedReason"
2965
+ );
2966
+ if (checkout.order !== null)
2967
+ fail(resource, "$.order", "null for abandoned Checkout");
2968
+ }
2969
+ }
2970
+ if (list || server) {
2971
+ if (checkout.clientReferenceId !== null) {
2972
+ boundedString(
2973
+ checkout.clientReferenceId,
2974
+ MAX_COMMERCE_RESOURCE_ID_LENGTH,
2975
+ resource,
2976
+ "$.clientReferenceId"
2977
+ );
2978
+ }
2979
+ }
2980
+ if (server)
2981
+ validateIntegrationMetadata(
2982
+ checkout.integrationMetadata,
2983
+ resource,
2984
+ "$.integrationMetadata"
2985
+ );
2986
+ }
2987
+ function validatePublicCheckout(value) {
2988
+ validateCheckoutCore(value, "Checkout", false, false);
2989
+ return value;
2990
+ }
2991
+ function validateServerCheckout(value) {
2992
+ validateCheckoutCore(value, "Server Checkout", false, true);
2993
+ return value;
2994
+ }
2995
+ function validateCreateCheckoutResult(value, server) {
2996
+ const resource = server ? "Server Checkout create result" : "Checkout create result";
2997
+ const result = record(value, resource, "$");
2998
+ exact(result, ["checkout", "checkoutToken"], [], resource, "$");
2999
+ if (server) validateServerCheckout(result.checkout);
3000
+ else validatePublicCheckout(result.checkout);
3001
+ boundedString(
3002
+ result.checkoutToken,
3003
+ MAX_COMMERCE_CAPABILITY_LENGTH,
3004
+ resource,
3005
+ "$.checkoutToken"
3006
+ );
3007
+ return value;
3008
+ }
3009
+ function validateCheckoutQueryResult(value) {
3010
+ const result = record(value, "Checkout query result", "$");
3011
+ exact(
3012
+ result,
3013
+ ["data", "hasMore", "nextCursor"],
3014
+ [],
3015
+ "Checkout query result",
3016
+ "$"
3017
+ );
3018
+ array(result.data, "Checkout query result", "$.data").forEach(
3019
+ (item) => validateCheckoutCore(item, "Checkout list item", true, false)
3020
+ );
3021
+ boolean(result.hasMore, "Checkout query result", "$.hasMore");
3022
+ if (result.nextCursor !== null)
3023
+ boundedString(
3024
+ result.nextCursor,
3025
+ MAX_COMMERCE_CAPABILITY_LENGTH,
3026
+ "Checkout query result",
3027
+ "$.nextCursor"
3028
+ );
3029
+ if (result.hasMore === true && result.nextCursor === null) {
3030
+ fail(
3031
+ "Checkout query result",
3032
+ "$.nextCursor",
3033
+ "non-null when hasMore is true"
3034
+ );
3035
+ }
3036
+ return value;
3037
+ }
3038
+ function validateMoney(value, resource, path) {
3039
+ const money = record(value, resource, path);
3040
+ exact(money, ["amountMinor", "currency"], [], resource, path);
3041
+ safeMinor(money.amountMinor, resource, `${path}.amountMinor`);
3042
+ currency(money.currency, resource, `${path}.currency`);
3043
+ }
3044
+ function validateCaptureEvidence(value, resource, path) {
3045
+ const evidence = record(value, resource, path);
3046
+ exact(evidence, ["amountMinor", "currency", "observedAt"], [], resource, path);
3047
+ safeMinor(evidence.amountMinor, resource, `${path}.amountMinor`);
3048
+ currency(evidence.currency, resource, `${path}.currency`);
3049
+ timestamp(evidence.observedAt, resource, `${path}.observedAt`);
3050
+ }
3051
+ function validateNoReconciliation(value, resource, path) {
3052
+ const reconciliation = record(value, resource, path);
3053
+ exact(reconciliation, ["status"], [], resource, path);
3054
+ if (reconciliation.status !== "none") fail(resource, `${path}.status`, "none");
3055
+ }
3056
+ function validateRequiredReconciliation(value, allowed, resource, path) {
3057
+ const reconciliation = record(value, resource, path);
3058
+ exact(reconciliation, ["status", "reasons"], [], resource, path);
3059
+ if (reconciliation.status !== "required")
3060
+ fail(resource, `${path}.status`, "required");
3061
+ const reasons = array(reconciliation.reasons, resource, `${path}.reasons`);
3062
+ if (reasons.length === 0) fail(resource, `${path}.reasons`, "non-empty array");
3063
+ let previous = -1;
3064
+ reasons.forEach((reason, index) => {
3065
+ const current = allowed.indexOf(reason);
3066
+ if (current < 0 || current <= previous) {
3067
+ fail(
3068
+ resource,
3069
+ `${path}.reasons[${index}]`,
3070
+ "unique canonical-sorted reconciliation reason"
3071
+ );
3072
+ }
3073
+ previous = current;
3074
+ });
3075
+ }
3076
+ function validateNextAction(value, resource, path) {
3077
+ const action = record(value, resource, path);
3078
+ exact(
3079
+ action,
3080
+ [
3081
+ "type",
3082
+ "clientKey",
3083
+ "paymentMethodVariantKey",
3084
+ "agreementVariantKey",
3085
+ "providerOrderId",
3086
+ "providerCustomerKey",
3087
+ "orderName"
3088
+ ],
3089
+ ["customerName", "customerEmail"],
3090
+ resource,
3091
+ path
3092
+ );
3093
+ if (action.type !== "toss_widget")
3094
+ fail(resource, `${path}.type`, "toss_widget");
3095
+ for (const key of [
3096
+ "clientKey",
3097
+ "paymentMethodVariantKey",
3098
+ "agreementVariantKey"
3099
+ ]) {
3100
+ boundedString(action[key], 255, resource, `${path}.${key}`);
3101
+ }
3102
+ string(action.providerOrderId, resource, `${path}.providerOrderId`);
3103
+ string(action.providerCustomerKey, resource, `${path}.providerCustomerKey`);
3104
+ boundedString(
3105
+ action.orderName,
3106
+ MAX_COMMERCE_SHORT_TEXT_LENGTH,
3107
+ resource,
3108
+ `${path}.orderName`
3109
+ );
3110
+ if (!/^[A-Za-z0-9_-]{6,64}$/.test(action.providerOrderId)) {
3111
+ fail(resource, `${path}.providerOrderId`, "valid Toss provider order ID");
3112
+ }
3113
+ if (action.providerCustomerKey !== "ANONYMOUS" && !/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(
3114
+ action.providerCustomerKey
3115
+ )) {
3116
+ fail(resource, `${path}.providerCustomerKey`, "ANONYMOUS or UUIDv4");
3117
+ }
3118
+ if (action.customerName !== void 0)
3119
+ boundedString(
3120
+ action.customerName,
3121
+ MAX_COMMERCE_SHORT_TEXT_LENGTH,
3122
+ resource,
3123
+ `${path}.customerName`
3124
+ );
3125
+ if (action.customerEmail !== void 0)
3126
+ validateCustomer({ email: action.customerEmail }, resource, path);
3127
+ }
3128
+ function validatePublicPaymentSession(value) {
3129
+ const resource = "PaymentSession";
3130
+ const session = record(value, resource, "$");
3131
+ enumValue(session.provider, PAYMENT_PROVIDERS, resource, "$.provider");
3132
+ const status = enumValue(
3133
+ session.providerStatus,
3134
+ PAYMENT_PROVIDER_STATUSES,
3135
+ resource,
3136
+ "$.providerStatus"
3137
+ );
3138
+ const common = [
3139
+ "id",
3140
+ "money",
3141
+ "expiresAt",
3142
+ "sessionRole",
3143
+ "provider",
3144
+ "providerStatus",
3145
+ "presentationStatus",
3146
+ "finalizationStatus",
3147
+ "reconciliation",
3148
+ "order"
3149
+ ];
3150
+ const optional = [];
3151
+ if (status === "requires_payment_method" || status === "requires_action")
3152
+ optional.push("nextAction");
3153
+ else if (status === "captured") common.push("providerEvidence");
3154
+ else if (status === "failed") common.push("failure");
3155
+ else if (status === "canceled") common.push("cancellationReason");
3156
+ exact(session, common, optional, resource, "$");
3157
+ string(session.id, resource, "$.id");
3158
+ validateMoney(session.money, resource, "$.money");
3159
+ if (session.expiresAt !== null)
3160
+ timestamp(session.expiresAt, resource, "$.expiresAt");
3161
+ if (status === "requires_payment_method" || status === "requires_action") {
3162
+ if (session.sessionRole === "active") {
3163
+ if (session.presentationStatus !== "actionable" || session.finalizationStatus !== "not_ready") {
3164
+ fail(resource, "$", "actionable active not-ready state");
3165
+ }
3166
+ if (!("nextAction" in session))
3167
+ fail(resource, "$.nextAction", "required field");
3168
+ validateNextAction(session.nextAction, resource, "$.nextAction");
3169
+ } else if (session.sessionRole === "residual") {
3170
+ if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
3171
+ fail(resource, "$", "suppressed residual not-ready state");
3172
+ }
3173
+ if ("nextAction" in session)
3174
+ fail(resource, "$.nextAction", "absent for suppressed state");
3175
+ } else fail(resource, "$.sessionRole", "active | residual");
3176
+ validateNoReconciliation(
3177
+ session.reconciliation,
3178
+ resource,
3179
+ "$.reconciliation"
3180
+ );
3181
+ if (session.order !== null) fail(resource, "$.order", "null");
3182
+ } else if ([
3183
+ "requires_confirmation",
3184
+ "initializing",
3185
+ "processing",
3186
+ "authorized",
3187
+ "canceling"
3188
+ ].includes(status)) {
3189
+ enumValue(
3190
+ session.sessionRole,
3191
+ ["active", "residual"],
3192
+ resource,
3193
+ "$.sessionRole"
3194
+ );
3195
+ if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
3196
+ fail(resource, "$", "suppressed not-ready state");
3197
+ }
3198
+ validateNoReconciliation(
3199
+ session.reconciliation,
3200
+ resource,
3201
+ "$.reconciliation"
3202
+ );
3203
+ if (session.order !== null) fail(resource, "$.order", "null");
3204
+ } else if (status === "unknown") {
3205
+ enumValue(
3206
+ session.sessionRole,
3207
+ ["active", "residual"],
3208
+ resource,
3209
+ "$.sessionRole"
3210
+ );
3211
+ if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
3212
+ fail(resource, "$", "suppressed not-ready state");
3213
+ }
3214
+ validateRequiredReconciliation(
3215
+ session.reconciliation,
3216
+ ["provider_outcome_unknown"],
3217
+ resource,
3218
+ "$.reconciliation"
3219
+ );
3220
+ if (session.order !== null) fail(resource, "$.order", "null");
3221
+ } else if (status === "captured") {
3222
+ validateCaptureEvidence(
3223
+ session.providerEvidence,
3224
+ resource,
3225
+ "$.providerEvidence"
3226
+ );
3227
+ if (session.presentationStatus !== "suppressed")
3228
+ fail(resource, "$.presentationStatus", "suppressed");
3229
+ if (session.finalizationStatus === "pending") {
3230
+ enumValue(
3231
+ session.sessionRole,
3232
+ ["canonical_candidate", "residual"],
3233
+ resource,
3234
+ "$.sessionRole"
3235
+ );
3236
+ if (session.order !== null)
3237
+ fail(resource, "$.order", "null for pending finalization");
3238
+ const reconciliation = record(
3239
+ session.reconciliation,
3240
+ resource,
3241
+ "$.reconciliation"
3242
+ );
3243
+ if (reconciliation.status === "none")
3244
+ validateNoReconciliation(reconciliation, resource, "$.reconciliation");
3245
+ else
3246
+ validateRequiredReconciliation(
3247
+ reconciliation,
3248
+ [
3249
+ "local_commit_ambiguous",
3250
+ "amount_mismatch",
3251
+ "currency_mismatch",
3252
+ "excess_capture_pending_order"
3253
+ ],
3254
+ resource,
3255
+ "$.reconciliation"
3256
+ );
3257
+ } else if (session.finalizationStatus === "committed") {
3258
+ validateOrderReference(session.order, resource, "$.order");
3259
+ const reconciliation = record(
3260
+ session.reconciliation,
3261
+ resource,
3262
+ "$.reconciliation"
3263
+ );
3264
+ if (reconciliation.status === "none") {
3265
+ enumValue(
3266
+ session.sessionRole,
3267
+ ["canonical", "historical"],
3268
+ resource,
3269
+ "$.sessionRole"
3270
+ );
3271
+ validateNoReconciliation(reconciliation, resource, "$.reconciliation");
3272
+ } else {
3273
+ enumValue(
3274
+ session.sessionRole,
3275
+ ["canonical", "residual"],
3276
+ resource,
3277
+ "$.sessionRole"
3278
+ );
3279
+ validateRequiredReconciliation(
3280
+ reconciliation,
3281
+ [
3282
+ "inventory_unavailable",
3283
+ "admission_unavailable",
3284
+ "amount_mismatch",
3285
+ "currency_mismatch",
3286
+ "excess_capture",
3287
+ "late_capture",
3288
+ "cross_checkout_duplicate"
3289
+ ],
3290
+ resource,
3291
+ "$.reconciliation"
3292
+ );
3293
+ }
3294
+ } else fail(resource, "$.finalizationStatus", "pending | committed");
3295
+ } else if (status === "failed") {
3296
+ if (session.sessionRole !== "historical" || session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready" || session.order !== null) {
3297
+ fail(resource, "$", "historical suppressed failed state");
3298
+ }
3299
+ validateNoReconciliation(
3300
+ session.reconciliation,
3301
+ resource,
3302
+ "$.reconciliation"
3303
+ );
3304
+ const failure = record(session.failure, resource, "$.failure");
3305
+ exact(failure, ["reason"], ["message"], resource, "$.failure");
3306
+ enumValue(
3307
+ failure.reason,
3308
+ PAYMENT_FAILURE_REASONS,
3309
+ resource,
3310
+ "$.failure.reason"
3311
+ );
3312
+ if (failure.message !== void 0)
3313
+ string(failure.message, resource, "$.failure.message");
3314
+ } else {
3315
+ if (session.sessionRole !== "historical" || session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready" || session.order !== null) {
3316
+ fail(resource, "$", "historical suppressed canceled state");
3317
+ }
3318
+ validateNoReconciliation(
3319
+ session.reconciliation,
3320
+ resource,
3321
+ "$.reconciliation"
3322
+ );
3323
+ enumValue(
3324
+ session.cancellationReason,
3325
+ ["expired", "customer", "operator", "provider"],
3326
+ resource,
3327
+ "$.cancellationReason"
3328
+ );
3329
+ }
3330
+ return value;
1418
3331
  }
1419
- var ContentClient = class {
1420
- constructor(options) {
1421
- const api = new PublicContentApi("ContentClient", {
1422
- publishableKey: options.publishableKey,
1423
- apiUrl: options.apiUrl,
1424
- onRequestId: options.onRequestId,
1425
- requiresCredential: false
1426
- });
1427
- this.links = {
1428
- list: (params) => api.get(linksListPath(params))
1429
- };
1430
- this.galleryItems = {
1431
- list: (params) => api.get(
1432
- galleryItemsListPath(params)
1433
- )
1434
- };
1435
- }
1436
- };
1437
3332
 
1438
3333
  // src/core/customer/customer-auth.ts
1439
3334
  var DEFAULT_TIMEOUT2 = 15e3;
@@ -1452,8 +3347,10 @@ var CustomerAuth = class {
1452
3347
  const persist = options?.persist ?? true;
1453
3348
  if (persist) {
1454
3349
  const key = typeof persist === "string" ? persist : "customer-token";
3350
+ const refreshKey = `${key}:refresh`;
1455
3351
  const isBrowser = typeof window !== "undefined";
1456
3352
  this.token = isBrowser ? safeGetItem(key) : null;
3353
+ this.refreshTokenValue = isBrowser ? safeGetItem(refreshKey) : null;
1457
3354
  this.onTokenChange = isBrowser ? (token) => {
1458
3355
  try {
1459
3356
  if (token) localStorage.setItem(key, token);
@@ -1461,9 +3358,18 @@ var CustomerAuth = class {
1461
3358
  } catch {
1462
3359
  }
1463
3360
  } : void 0;
3361
+ this.onRefreshTokenChange = isBrowser ? (refreshToken) => {
3362
+ try {
3363
+ if (refreshToken) localStorage.setItem(refreshKey, refreshToken);
3364
+ else localStorage.removeItem(refreshKey);
3365
+ } catch {
3366
+ }
3367
+ } : void 0;
1464
3368
  } else {
1465
3369
  this.token = options?.token ?? null;
3370
+ this.refreshTokenValue = options?.refreshToken ?? null;
1466
3371
  this.onTokenChange = options?.onTokenChange;
3372
+ this.onRefreshTokenChange = options?.onRefreshTokenChange;
1467
3373
  }
1468
3374
  }
1469
3375
  /**
@@ -1487,13 +3393,17 @@ var CustomerAuth = class {
1487
3393
  }
1488
3394
  );
1489
3395
  this.setToken(result.token);
3396
+ if (result.refreshToken) this.setRefreshToken(result.refreshToken);
1490
3397
  return result;
1491
3398
  }
1492
3399
  /**
1493
- * Refresh the current token. Requires a valid (non-expired) token.
3400
+ * Refresh the current token. Uses a refresh token when available, otherwise
3401
+ * falls back to the legacy bearer-token compatibility path.
1494
3402
  */
1495
3403
  async refreshToken() {
1496
- if (!this.token) throw new ApiError("Not authenticated", 401);
3404
+ if (!this.refreshTokenValue && !this.token) {
3405
+ throw new ApiError("Not authenticated", 401);
3406
+ }
1497
3407
  if (this.refreshPromise) return this.refreshPromise;
1498
3408
  this.refreshPromise = this._doRefreshToken();
1499
3409
  try {
@@ -1503,14 +3413,19 @@ var CustomerAuth = class {
1503
3413
  }
1504
3414
  }
1505
3415
  async _doRefreshToken() {
3416
+ const init = this.refreshTokenValue ? {
3417
+ method: "POST",
3418
+ body: JSON.stringify({ refreshToken: this.refreshTokenValue })
3419
+ } : {
3420
+ method: "POST",
3421
+ headers: { Authorization: `Bearer ${this.token}` }
3422
+ };
1506
3423
  const result = await this.requestJson(
1507
3424
  "/api/customers/refresh",
1508
- {
1509
- method: "POST",
1510
- headers: { Authorization: `Bearer ${this.token}` }
1511
- }
3425
+ init
1512
3426
  );
1513
3427
  this.setToken(result.token);
3428
+ if (result.refreshToken) this.setRefreshToken(result.refreshToken);
1514
3429
  return result;
1515
3430
  }
1516
3431
  /**
@@ -1518,6 +3433,7 @@ var CustomerAuth = class {
1518
3433
  */
1519
3434
  logout() {
1520
3435
  this.setToken(null);
3436
+ this.setRefreshToken(null);
1521
3437
  }
1522
3438
  /**
1523
3439
  * Get the current authenticated customer's profile
@@ -1593,25 +3509,28 @@ var CustomerAuth = class {
1593
3509
  const params = new URLSearchParams();
1594
3510
  if (options?.page) params.set("page", String(options.page));
1595
3511
  if (options?.limit) params.set("limit", String(options.limit));
1596
- if (options?.displayFinancialStatus) {
1597
- params.set("displayFinancialStatus", options.displayFinancialStatus);
3512
+ if (options?.financialStatus) {
3513
+ params.set("financialStatus", options.financialStatus);
1598
3514
  }
1599
- if (options?.displayFulfillmentStatus) {
1600
- params.set("displayFulfillmentStatus", options.displayFulfillmentStatus);
3515
+ if (options?.fulfillmentStatus) {
3516
+ params.set("fulfillmentStatus", options.fulfillmentStatus);
1601
3517
  }
1602
3518
  if (options?.returnStatus) params.set("returnStatus", options.returnStatus);
3519
+ if (options?.confirmationStatus) {
3520
+ params.set("confirmationStatus", options.confirmationStatus);
3521
+ }
1603
3522
  if (options?.primaryDisplayStatus) {
1604
3523
  params.set("primaryDisplayStatus", options.primaryDisplayStatus);
1605
3524
  }
1606
- if (options?.returnDisplayStatus) {
1607
- params.set("returnDisplayStatus", options.returnDisplayStatus);
1608
- }
1609
- if (options?.status) params.set("status", options.status);
1610
3525
  const qs = params.toString();
1611
- return this.requestJson(`/api/customers/me/orders${qs ? `?${qs}` : ""}`, {
1612
- method: "GET",
1613
- headers: { Authorization: `Bearer ${this.token}` }
1614
- });
3526
+ const result = await this.requestJson(
3527
+ `/api/customers/me/orders${qs ? `?${qs}` : ""}`,
3528
+ {
3529
+ method: "GET",
3530
+ headers: { Authorization: `Bearer ${this.token}` }
3531
+ }
3532
+ );
3533
+ return validatePublicOrderList(result);
1615
3534
  }
1616
3535
  /**
1617
3536
  * Get the current token (or null if not authenticated)
@@ -1619,6 +3538,12 @@ var CustomerAuth = class {
1619
3538
  getToken() {
1620
3539
  return this.token;
1621
3540
  }
3541
+ /**
3542
+ * Get the current refresh token (or null if unavailable)
3543
+ */
3544
+ getRefreshToken() {
3545
+ return this.refreshTokenValue;
3546
+ }
1622
3547
  /**
1623
3548
  * Set the token manually (e.g. from SSR)
1624
3549
  */
@@ -1626,6 +3551,13 @@ var CustomerAuth = class {
1626
3551
  this.token = token;
1627
3552
  this.onTokenChange?.(token);
1628
3553
  }
3554
+ /**
3555
+ * Set the refresh token manually (e.g. from SSR cookie)
3556
+ */
3557
+ setRefreshToken(refreshToken) {
3558
+ this.refreshTokenValue = refreshToken;
3559
+ this.onRefreshTokenChange?.(refreshToken);
3560
+ }
1629
3561
  /**
1630
3562
  * Check if the customer is currently authenticated
1631
3563
  */
@@ -1654,91 +3586,358 @@ var CustomerAuth = class {
1654
3586
  }
1655
3587
  };
1656
3588
 
3589
+ // src/core/customer/customer-oauth.ts
3590
+ var DEFAULT_SCOPES = ["openid", "profile", "email"];
3591
+ var DEFAULT_TIMEOUT3 = 15e3;
3592
+ function issuerUrl(issuer, path) {
3593
+ const base = resolveApiUrl(issuer);
3594
+ return new URL(path, base.endsWith("/") ? base : `${base}/`).toString();
3595
+ }
3596
+ function randomBase64Url(bytes) {
3597
+ const buffer = new Uint8Array(bytes);
3598
+ crypto.getRandomValues(buffer);
3599
+ let binary = "";
3600
+ for (const value of buffer) {
3601
+ binary += String.fromCharCode(value);
3602
+ }
3603
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
3604
+ }
3605
+ async function sha256Base64Url(value) {
3606
+ const data = new TextEncoder().encode(value);
3607
+ const digest = await crypto.subtle.digest("SHA-256", data);
3608
+ let binary = "";
3609
+ for (const byte of new Uint8Array(digest)) {
3610
+ binary += String.fromCharCode(byte);
3611
+ }
3612
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
3613
+ }
3614
+ function normalizeToken(body) {
3615
+ if (body.token_type !== "Bearer") {
3616
+ throw new Error("Unsupported customer OAuth token type");
3617
+ }
3618
+ return {
3619
+ accessToken: body.access_token,
3620
+ expiresAt: Date.now() + body.expires_in * 1e3,
3621
+ expiresIn: body.expires_in,
3622
+ ...body.id_token ? { idToken: body.id_token } : {},
3623
+ refreshToken: body.refresh_token,
3624
+ ...body.scope ? { scope: body.scope } : {},
3625
+ tokenType: "Bearer"
3626
+ };
3627
+ }
3628
+ var CustomerOAuth = class {
3629
+ constructor(config) {
3630
+ if (!config.clientId) throw new Error("customer OAuth clientId is required");
3631
+ if (!config.issuer) throw new Error("customer OAuth issuer is required");
3632
+ this.clientId = config.clientId;
3633
+ this.issuer = config.issuer;
3634
+ this.timeout = config.timeout ?? DEFAULT_TIMEOUT3;
3635
+ }
3636
+ async createAuthorizationUrl(input) {
3637
+ const codeVerifier = randomBase64Url(48);
3638
+ const codeChallenge = await sha256Base64Url(codeVerifier);
3639
+ const state = randomBase64Url(32);
3640
+ const nonce = randomBase64Url(32);
3641
+ const scopes = input.scopes ?? DEFAULT_SCOPES;
3642
+ const url = new URL(issuerUrl(this.issuer, "customer-oauth/authorize"));
3643
+ url.searchParams.set("response_type", "code");
3644
+ url.searchParams.set("client_id", this.clientId);
3645
+ url.searchParams.set("redirect_uri", input.redirectUri);
3646
+ url.searchParams.set("scope", scopes.join(" "));
3647
+ url.searchParams.set("state", state);
3648
+ url.searchParams.set("nonce", nonce);
3649
+ url.searchParams.set("code_challenge", codeChallenge);
3650
+ url.searchParams.set("code_challenge_method", "S256");
3651
+ return {
3652
+ authorizationUrl: url.toString(),
3653
+ codeChallenge,
3654
+ codeVerifier,
3655
+ nonce,
3656
+ returnTo: input.returnTo ?? null,
3657
+ state
3658
+ };
3659
+ }
3660
+ parseCallback(callbackUrl, options) {
3661
+ const url = new URL(callbackUrl);
3662
+ const error = url.searchParams.get("error");
3663
+ if (error) {
3664
+ throw new Error(
3665
+ url.searchParams.get("error_description") ?? `OAuth error: ${error}`
3666
+ );
3667
+ }
3668
+ const code = url.searchParams.get("code");
3669
+ const state = url.searchParams.get("state");
3670
+ if (!code || !state) throw new Error("OAuth callback is missing code/state");
3671
+ if (state !== options.expectedState) throw new Error("OAuth state mismatch");
3672
+ return { code, state };
3673
+ }
3674
+ async exchangeCode(input) {
3675
+ const body = new URLSearchParams({
3676
+ client_id: this.clientId,
3677
+ code: input.code,
3678
+ code_verifier: input.codeVerifier,
3679
+ grant_type: "authorization_code",
3680
+ redirect_uri: input.redirectUri
3681
+ });
3682
+ return this.tokenRequest(body);
3683
+ }
3684
+ async refresh(input) {
3685
+ const body = new URLSearchParams({
3686
+ client_id: this.clientId,
3687
+ grant_type: "refresh_token",
3688
+ refresh_token: input.refreshToken
3689
+ });
3690
+ return this.tokenRequest(body);
3691
+ }
3692
+ async logout(input) {
3693
+ const body = { client_id: this.clientId };
3694
+ if (input.refreshToken) body.refresh_token = input.refreshToken;
3695
+ if (input.postLogoutRedirectUri) {
3696
+ body.post_logout_redirect_uri = input.postLogoutRedirectUri;
3697
+ }
3698
+ const response = await httpFetch("/customer-oauth/logout", {
3699
+ apiUrl: this.issuer,
3700
+ method: "POST",
3701
+ body: JSON.stringify(body),
3702
+ headers: { "Content-Type": "application/json" },
3703
+ timeout: this.timeout,
3704
+ retry: { maxRetries: 0 }
3705
+ });
3706
+ return parseApiResponse(
3707
+ response,
3708
+ "/customer-oauth/logout"
3709
+ );
3710
+ }
3711
+ verifyIdToken() {
3712
+ throw new Error(
3713
+ "Customer OAuth ID token verification is not implemented; treat idToken as opaque."
3714
+ );
3715
+ }
3716
+ async tokenRequest(body) {
3717
+ const response = await httpFetch("/api/customer-oauth/token", {
3718
+ apiUrl: this.issuer,
3719
+ method: "POST",
3720
+ body,
3721
+ headers: {
3722
+ "Content-Type": "application/x-www-form-urlencoded"
3723
+ },
3724
+ timeout: this.timeout,
3725
+ retry: { maxRetries: 0 }
3726
+ });
3727
+ return normalizeToken(
3728
+ await parseApiResponse(
3729
+ response,
3730
+ "/api/customer-oauth/token"
3731
+ )
3732
+ );
3733
+ }
3734
+ };
3735
+
1657
3736
  // src/core/customer/customer-namespace.ts
1658
3737
  var CustomerNamespace = class {
1659
3738
  constructor(publishableKey, options, apiUrl) {
1660
3739
  this.auth = new CustomerAuth(publishableKey, options, apiUrl);
3740
+ if (options?.oauth) {
3741
+ this.oauth = new CustomerOAuth(options.oauth);
3742
+ }
1661
3743
  }
1662
3744
  };
1663
3745
 
3746
+ // src/core/api/commerce-idempotency.ts
3747
+ var UUID_V4_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
3748
+ var PREFIXED_BASE64URL_PATTERN = /^ik_[A-Za-z0-9_-]{22}$/;
3749
+ function isCommerceIdempotencyKey(value) {
3750
+ return typeof value === "string" && value.length <= 255 && (UUID_V4_PATTERN.test(value) || PREFIXED_BASE64URL_PATTERN.test(value));
3751
+ }
3752
+ function assertCommerceIdempotencyKey(value) {
3753
+ if (isCommerceIdempotencyKey(value)) return;
3754
+ throw createValidationError(
3755
+ "idempotencyKey must be a UUIDv4 or ik_-prefixed 128-bit base64url value.",
3756
+ { field: "idempotencyKey" }
3757
+ );
3758
+ }
3759
+
1664
3760
  // src/core/api/cart-api.ts
1665
3761
  var CartApi = class extends CustomerScopedApi {
1666
3762
  constructor(options) {
1667
3763
  super("CartApi", { ...options, requiresCredential: false });
3764
+ this.serverTransport = Boolean(options.secretKey);
1668
3765
  }
1669
- async execute(endpoint, method, body) {
1670
- return this.request(endpoint, { method, body });
3766
+ endpoint(key) {
3767
+ return this.serverTransport ? COMMERCE_ENDPOINTS.carts.server[key] : COMMERCE_ENDPOINTS.carts[key];
1671
3768
  }
1672
- /**
1673
- * Create a cart and receive its `cartToken`. Store the token and pass it to
1674
- * every subsequent cart operation.
1675
- */
1676
- createCart(params = {}) {
1677
- return this.execute("/api/carts/create", "POST", params);
3769
+ execute(endpoint2, body, idempotencyKey) {
3770
+ return this.requestEndpoint(endpoint2, body, {
3771
+ ...idempotencyKey && {
3772
+ headers: { "X-Idempotency-Key": idempotencyKey }
3773
+ }
3774
+ });
1678
3775
  }
1679
- getCart(cartToken) {
1680
- return this.execute("/api/carts/get", "POST", { cartToken });
3776
+ create(params = {}) {
3777
+ return this.execute(this.endpoint("create"), params).then(
3778
+ (value) => validateCreateCartResult(value)
3779
+ );
1681
3780
  }
1682
- merge(params) {
1683
- return this.execute(
1684
- COMMERCE_ENDPOINTS.carts.merge,
1685
- "POST",
1686
- params
3781
+ retrieve(params) {
3782
+ return this.execute(this.endpoint("retrieve"), params).then(
3783
+ (value) => validatePublicCart(value)
1687
3784
  );
1688
3785
  }
1689
- /**
1690
- * Resolve the authenticated customer's active cart by JWT (no `cartToken`
1691
- * required). Returns the cart and its capability handle, or both `null` when
1692
- * the customer has no active cart. Requires a customer token.
1693
- */
1694
- mine() {
1695
- return this.execute(
1696
- COMMERCE_ENDPOINTS.carts.mine,
1697
- "POST",
1698
- {}
3786
+ mine(params = {}) {
3787
+ const endpoint2 = this.endpoint("mine");
3788
+ return this.execute(endpoint2, params).then(
3789
+ (value) => validateCartMineResult(value)
3790
+ );
3791
+ }
3792
+ merge(params) {
3793
+ const { idempotencyKey, ...body } = params;
3794
+ assertCommerceIdempotencyKey(idempotencyKey);
3795
+ const endpoint2 = this.endpoint("merge");
3796
+ return this.execute(endpoint2, body, idempotencyKey).then(
3797
+ (value) => validateCartMergeResult(value)
1699
3798
  );
1700
3799
  }
1701
3800
  addItem(params) {
1702
- return this.execute(
1703
- COMMERCE_ENDPOINTS.carts.addItem,
1704
- "POST",
1705
- params
3801
+ return this.mutate(this.endpoint("addItem"), params);
3802
+ }
3803
+ mutate(endpoint2, params) {
3804
+ const { idempotencyKey, ...body } = params;
3805
+ assertCommerceIdempotencyKey(idempotencyKey);
3806
+ return this.execute(endpoint2, body, idempotencyKey).then(
3807
+ (value) => validateCartMutationResult(value)
1706
3808
  );
1707
3809
  }
1708
3810
  updateItem(params) {
1709
- return this.execute(
1710
- COMMERCE_ENDPOINTS.carts.updateItem,
1711
- "POST",
1712
- params
1713
- );
3811
+ return this.mutate(this.endpoint("updateItem"), params);
1714
3812
  }
1715
3813
  removeItem(params) {
1716
- return this.execute(
1717
- COMMERCE_ENDPOINTS.carts.removeItem,
1718
- "POST",
1719
- params
3814
+ return this.mutate(this.endpoint("removeItem"), params);
3815
+ }
3816
+ clear(params) {
3817
+ return this.mutate(this.endpoint("clear"), params);
3818
+ }
3819
+ updateDiscountCodes(params) {
3820
+ return this.mutate(this.endpoint("updateDiscountCodes"), params);
3821
+ }
3822
+ updateAttributes(params) {
3823
+ return this.mutate(this.endpoint("updateAttributes"), params);
3824
+ }
3825
+ };
3826
+
3827
+ // src/core/api/checkout-api.ts
3828
+ var CheckoutApi = class extends CustomerScopedApi {
3829
+ constructor(options) {
3830
+ super("CheckoutApi", { ...options, requiresCredential: false });
3831
+ }
3832
+ post(endpoint2, body, idempotencyKey) {
3833
+ return this.requestEndpoint(endpoint2, body, {
3834
+ ...idempotencyKey && {
3835
+ headers: { "X-Idempotency-Key": idempotencyKey }
3836
+ }
3837
+ });
3838
+ }
3839
+ async publicCheckout(result) {
3840
+ return validatePublicCheckout(await result);
3841
+ }
3842
+ async serverCheckout(result) {
3843
+ return validateServerCheckout(await result);
3844
+ }
3845
+ async createResult(result) {
3846
+ return validateCreateCheckoutResult(
3847
+ await result,
3848
+ false
1720
3849
  );
1721
3850
  }
1722
- applyDiscount(params) {
1723
- return this.execute(
1724
- COMMERCE_ENDPOINTS.carts.applyDiscount,
1725
- "POST",
1726
- params
3851
+ async createServerResult(result) {
3852
+ return validateCreateCheckoutResult(
3853
+ await result,
3854
+ true
1727
3855
  );
1728
3856
  }
1729
- removeDiscount(params) {
1730
- return this.execute(
1731
- COMMERCE_ENDPOINTS.carts.removeDiscount,
1732
- "POST",
1733
- params
3857
+ create(params) {
3858
+ const { idempotencyKey, ...body } = params;
3859
+ assertCommerceIdempotencyKey(idempotencyKey);
3860
+ return this.createResult(
3861
+ this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey)
1734
3862
  );
1735
3863
  }
1736
- clearCart(params) {
1737
- return this.execute(
1738
- COMMERCE_ENDPOINTS.carts.clear,
1739
- "POST",
3864
+ createServer(params) {
3865
+ const { idempotencyKey, ...body } = params;
3866
+ assertCommerceIdempotencyKey(idempotencyKey);
3867
+ return this.createServerResult(
3868
+ this.post(
3869
+ COMMERCE_ENDPOINTS.checkouts.server.create,
3870
+ body,
3871
+ idempotencyKey
3872
+ )
3873
+ );
3874
+ }
3875
+ retrieve(params) {
3876
+ return this.publicCheckout(
3877
+ this.post(COMMERCE_ENDPOINTS.checkouts.retrieve, params)
3878
+ );
3879
+ }
3880
+ retrieveServer(params) {
3881
+ return this.serverCheckout(
3882
+ this.post(COMMERCE_ENDPOINTS.checkouts.server.retrieve, params)
3883
+ );
3884
+ }
3885
+ async query(params = {}) {
3886
+ const result = await this.post(
3887
+ COMMERCE_ENDPOINTS.checkouts.server.query,
1740
3888
  params
1741
3889
  );
3890
+ return validateCheckoutQueryResult(result);
3891
+ }
3892
+ };
3893
+
3894
+ // src/core/api/payment-session-api.ts
3895
+ var PaymentSessionApi = class extends CustomerScopedApi {
3896
+ constructor(options) {
3897
+ super("PaymentSessionApi", { ...options, requiresCredential: false });
3898
+ this.serverTransport = Boolean(options.secretKey);
3899
+ }
3900
+ post(endpoint2, body, idempotencyKey) {
3901
+ return this.requestEndpoint(endpoint2, body, {
3902
+ ...idempotencyKey && {
3903
+ headers: { "X-Idempotency-Key": idempotencyKey }
3904
+ }
3905
+ });
3906
+ }
3907
+ async paymentSession(result) {
3908
+ return validatePublicPaymentSession(await result);
3909
+ }
3910
+ create(params) {
3911
+ const { idempotencyKey, ...body } = params;
3912
+ assertCommerceIdempotencyKey(idempotencyKey);
3913
+ return this.paymentSession(
3914
+ this.post(
3915
+ this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.create : COMMERCE_ENDPOINTS.paymentSessions.create,
3916
+ body,
3917
+ idempotencyKey
3918
+ )
3919
+ );
3920
+ }
3921
+ retrieve(params) {
3922
+ const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
3923
+ return this.paymentSession(this.post(endpoint2, params));
3924
+ }
3925
+ cancel(params) {
3926
+ const { idempotencyKey, ...body } = params;
3927
+ assertCommerceIdempotencyKey(idempotencyKey);
3928
+ const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
3929
+ return this.paymentSession(this.post(endpoint2, body, idempotencyKey));
3930
+ }
3931
+ confirm(params) {
3932
+ const { idempotencyKey, ...body } = params;
3933
+ assertCommerceIdempotencyKey(idempotencyKey);
3934
+ return this.paymentSession(
3935
+ this.post(
3936
+ COMMERCE_ENDPOINTS.paymentSessions.server.confirm,
3937
+ body,
3938
+ idempotencyKey
3939
+ )
3940
+ );
1742
3941
  }
1743
3942
  };
1744
3943
 
@@ -2545,6 +4744,9 @@ function compareVariantOrder(a, b) {
2545
4744
  }
2546
4745
  function getVariantAvailableForSale(variant) {
2547
4746
  if (variant.isActive === false) return false;
4747
+ if (typeof variant.availableForSale === "boolean") {
4748
+ return variant.availableForSale;
4749
+ }
2548
4750
  if (variant.isUnlimited) return true;
2549
4751
  if (variant.inventoryPolicy === "continue") return true;
2550
4752
  return (variant.stock ?? 0) - (variant.reservedStock ?? 0) > 0;
@@ -2654,7 +4856,7 @@ function buildProductListingCard(item, options = {}) {
2654
4856
  { listing: { selectionHintVariant } },
2655
4857
  options
2656
4858
  ),
2657
- title: product.title,
4859
+ title: product.title ?? "",
2658
4860
  representativeVariant,
2659
4861
  primaryImage: listingPrimaryMedia,
2660
4862
  priceRange,
@@ -2782,6 +4984,11 @@ function productDetailResultFromError(error) {
2782
4984
  if (!reason) return void 0;
2783
4985
  return { found: false, reason };
2784
4986
  }
4987
+ var MARKET_PRICE_QUERY_UNSUPPORTED_MESSAGE = "Market listing pages do not support base price filters or price sorts.";
4988
+ var BASE_PRICE_RANGE_SORT_FIELDS = /* @__PURE__ */ new Set([
4989
+ "priceRange.minVariantPrice.amount",
4990
+ "priceRange.maxVariantPrice.amount"
4991
+ ]);
2785
4992
  function nonEmpty(values) {
2786
4993
  return values?.length ? values : void 0;
2787
4994
  }
@@ -2829,14 +5036,34 @@ function buildProductListingPageWhere(params) {
2829
5036
  if (clauses.length === 1) return clauses[0];
2830
5037
  return { and: clauses };
2831
5038
  }
2832
- function buildProductListingPageUrl(params) {
5039
+ function productListingPageUsesBasePriceSort(sort) {
5040
+ const values = Array.isArray(sort) ? sort : sort ? [sort] : [];
5041
+ return values.some(
5042
+ (value) => BASE_PRICE_RANGE_SORT_FIELDS.has(String(value).replace(/^-/, ""))
5043
+ );
5044
+ }
5045
+ function assertMarketListingPageQuerySupported(params) {
5046
+ if (!params.market?.trim()) return;
5047
+ const priceFilter = params.filters?.price;
5048
+ if (priceFilter?.min != null || priceFilter?.max != null || productListingPageUsesBasePriceSort(params.sort)) {
5049
+ throw new TypeError(MARKET_PRICE_QUERY_UNSUPPORTED_MESSAGE);
5050
+ }
5051
+ }
5052
+ function buildProductListingPageRequest(params) {
5053
+ assertMarketListingPageQuerySupported(params);
2833
5054
  const options = {
5055
+ market: params.market,
5056
+ locale: params.locale,
5057
+ fallbackLocale: params.fallbackLocale,
2834
5058
  page: params.page,
2835
5059
  limit: params.limit,
2836
5060
  sort: params.sort,
2837
5061
  where: buildProductListingPageWhere(params)
2838
5062
  };
2839
- return params.mode === "full" ? listingGroupsQueryUrl(options) : listingGroupsQueryCatalogUrl(options);
5063
+ return {
5064
+ operation: params.mode === "full" ? COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryGet : COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryCatalog,
5065
+ query: listingPageSearchParams(options)
5066
+ };
2840
5067
  }
2841
5068
  function withProductListingCards(response, options) {
2842
5069
  return {
@@ -2845,30 +5072,15 @@ function withProductListingCards(response, options) {
2845
5072
  };
2846
5073
  }
2847
5074
 
2848
- // src/core/api/order-api.ts
2849
- function idempotencyRequestOptions(idempotencyKey) {
2850
- return idempotencyKey ? { headers: { "X-Idempotency-Key": idempotencyKey } } : void 0;
2851
- }
2852
- function splitIdempotencyKey(params) {
2853
- const { idempotencyKey, ...body } = params;
2854
- return { body, idempotencyKey };
2855
- }
2856
-
2857
5075
  // src/core/commerce/commerce-client.ts
2858
5076
  var BrowserCommerceApi = class extends CustomerScopedApi {
2859
- post(endpoint, body, requestOptions) {
2860
- return this.request(endpoint, {
2861
- method: "POST",
2862
- body,
2863
- headers: requestOptions?.headers
2864
- });
2865
- }
2866
- get(endpoint) {
2867
- return this.request(endpoint, { method: "GET" });
5077
+ requestEndpoint(endpoint2, body, options) {
5078
+ return super.requestEndpoint(endpoint2, body, options);
2868
5079
  }
2869
5080
  };
2870
5081
  var CommerceClient = class {
2871
5082
  constructor(options) {
5083
+ this.market = options.market;
2872
5084
  const cartApi = new CartApi({
2873
5085
  publishableKey: options.publishableKey,
2874
5086
  apiUrl: options.apiUrl,
@@ -2876,6 +5088,20 @@ var CommerceClient = class {
2876
5088
  onUnauthorized: options.onUnauthorized,
2877
5089
  onRequestId: options.onRequestId
2878
5090
  });
5091
+ const checkoutApi = new CheckoutApi({
5092
+ publishableKey: options.publishableKey,
5093
+ apiUrl: options.apiUrl,
5094
+ customerToken: options.customerToken,
5095
+ onUnauthorized: options.onUnauthorized,
5096
+ onRequestId: options.onRequestId
5097
+ });
5098
+ const paymentSessionApi = new PaymentSessionApi({
5099
+ publishableKey: options.publishableKey,
5100
+ apiUrl: options.apiUrl,
5101
+ customerToken: options.customerToken,
5102
+ onUnauthorized: options.onUnauthorized,
5103
+ onRequestId: options.onRequestId
5104
+ });
2879
5105
  const api = new BrowserCommerceApi("CommerceClient", {
2880
5106
  publishableKey: options.publishableKey,
2881
5107
  apiUrl: options.apiUrl,
@@ -2884,29 +5110,42 @@ var CommerceClient = class {
2884
5110
  onRequestId: options.onRequestId
2885
5111
  });
2886
5112
  this.product = {
2887
- stockCheck: (params) => api.post(
2888
- COMMERCE_ENDPOINTS.products.stockCheck,
5113
+ stockCheck: (params) => api.requestEndpoint(
5114
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockCheck,
2889
5115
  params
2890
5116
  ),
2891
- stockSnapshot: (params) => api.get(stockSnapshotQuery(params)),
2892
- listingGroups: (params) => api.get(
2893
- listingGroupsCatalogQuery(params)
5117
+ stockSnapshot: (params) => api.requestEndpoint(
5118
+ COMMERCE_ENDPOINT_OPERATIONS.products.stockSnapshot,
5119
+ void 0,
5120
+ { query: stockSnapshotSearchParams(params) }
5121
+ ),
5122
+ listingGroups: (params) => api.requestEndpoint(
5123
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog,
5124
+ void 0,
5125
+ { query: listingGroupsSearchParams(this.withMarket(params)) }
2894
5126
  ),
2895
- listingGroupsCatalog: (params) => api.get(
2896
- listingGroupsCatalogQuery(params)
5127
+ listingGroupsCatalog: (params) => api.requestEndpoint(
5128
+ COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog,
5129
+ void 0,
5130
+ { query: listingGroupsSearchParams(this.withMarket(params)) }
2897
5131
  ),
2898
5132
  listingPage: async (params = {}) => {
2899
5133
  const catalogParams = {
2900
5134
  ...params,
2901
5135
  mode: "catalog"
2902
5136
  };
2903
- const response = await api.get(buildProductListingPageUrl(catalogParams));
2904
- return withProductListingCards(response, catalogParams);
5137
+ const request = buildProductListingPageRequest(
5138
+ this.withMarket(catalogParams)
5139
+ );
5140
+ const response = await api.requestEndpoint(request.operation, void 0, { query: request.query });
5141
+ return withProductListingCards(response, this.withMarket(catalogParams));
2905
5142
  },
2906
5143
  detail: async (params) => {
2907
5144
  try {
2908
- const product = await api.get(
2909
- productDetailQuery(params)
5145
+ const product = await api.requestEndpoint(
5146
+ COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog,
5147
+ void 0,
5148
+ { query: productDetailSearchParams(this.withMarket(params)) }
2910
5149
  );
2911
5150
  return { found: true, product };
2912
5151
  } catch (err) {
@@ -2917,8 +5156,10 @@ var CommerceClient = class {
2917
5156
  },
2918
5157
  detailCatalog: async (params) => {
2919
5158
  try {
2920
- const product = await api.get(
2921
- productDetailCatalogQuery(params)
5159
+ const product = await api.requestEndpoint(
5160
+ COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog,
5161
+ void 0,
5162
+ { query: productDetailSearchParams(this.withMarket(params)) }
2922
5163
  );
2923
5164
  return { found: true, product };
2924
5165
  } catch (err) {
@@ -2928,39 +5169,51 @@ var CommerceClient = class {
2928
5169
  }
2929
5170
  }
2930
5171
  };
2931
- this.cart = {
2932
- create: cartApi.createCart.bind(cartApi),
2933
- get: cartApi.getCart.bind(cartApi),
5172
+ this.carts = {
5173
+ create: (params) => cartApi.create(this.withMarket(params ?? {})),
5174
+ retrieve: cartApi.retrieve.bind(cartApi),
2934
5175
  addItem: cartApi.addItem.bind(cartApi),
2935
5176
  updateItem: cartApi.updateItem.bind(cartApi),
2936
5177
  removeItem: cartApi.removeItem.bind(cartApi),
2937
- applyDiscount: cartApi.applyDiscount.bind(cartApi),
2938
- removeDiscount: cartApi.removeDiscount.bind(cartApi),
2939
- clear: cartApi.clearCart.bind(cartApi),
5178
+ updateDiscountCodes: cartApi.updateDiscountCodes.bind(cartApi),
5179
+ updateAttributes: cartApi.updateAttributes.bind(cartApi),
5180
+ clear: cartApi.clear.bind(cartApi),
2940
5181
  merge: cartApi.merge.bind(cartApi),
2941
5182
  mine: cartApi.mine.bind(cartApi)
2942
5183
  };
2943
5184
  this.orders = {
2944
- checkout: (params) => {
2945
- const { body, idempotencyKey } = splitIdempotencyKey(params);
2946
- return api.post(
2947
- "/api/orders/checkout",
2948
- body,
2949
- idempotencyRequestOptions(idempotencyKey)
2950
- );
2951
- },
2952
5185
  listMine: (params) => options.customerAuth.getMyOrders(params)
2953
5186
  };
5187
+ this.checkouts = {
5188
+ create: checkoutApi.create.bind(checkoutApi),
5189
+ retrieve: checkoutApi.retrieve.bind(checkoutApi)
5190
+ };
5191
+ this.paymentSessions = {
5192
+ create: paymentSessionApi.create.bind(paymentSessionApi),
5193
+ retrieve: (params) => paymentSessionApi.retrieve(params),
5194
+ cancel: (params) => paymentSessionApi.cancel(params)
5195
+ };
2954
5196
  this.discounts = {
2955
- validate: (params) => api.post("/api/discounts/validate", params)
5197
+ validate: (params) => api.requestEndpoint(
5198
+ COMMERCE_ENDPOINT_OPERATIONS.discounts.validate,
5199
+ params
5200
+ )
2956
5201
  };
2957
5202
  this.shipping = {
2958
- calculate: (params) => api.post(
2959
- "/api/shipping-policies/calculate",
5203
+ calculate: (params) => api.requestEndpoint(
5204
+ COMMERCE_ENDPOINT_OPERATIONS.shippingPolicies.calculate,
2960
5205
  params
2961
5206
  )
2962
5207
  };
2963
5208
  }
5209
+ getDefaultMarket() {
5210
+ return this.market;
5211
+ }
5212
+ withMarket(params) {
5213
+ const defaultMarket = this.market?.trim();
5214
+ if (!defaultMarket || params.market?.trim()) return params;
5215
+ return { ...params, market: defaultMarket };
5216
+ }
2964
5217
  };
2965
5218
 
2966
5219
  // src/core/events/events-client.ts
@@ -2980,7 +5233,17 @@ var EventsClient = class {
2980
5233
  getRange(params) {
2981
5234
  return this.execute(
2982
5235
  buildRangeEndpoint(params),
2983
- "GET",
5236
+ resolveOperationMethod(EVENTS_ENDPOINT_OPERATIONS.occurrences.range),
5237
+ void 0,
5238
+ { useCustomerAuth: false }
5239
+ );
5240
+ }
5241
+ getAdmissionAvailability(params) {
5242
+ return this.execute(
5243
+ buildAdmissionAvailabilityEndpoint(params),
5244
+ resolveOperationMethod(
5245
+ EVENTS_ENDPOINT_OPERATIONS.occurrences.admissionAvailability
5246
+ ),
2984
5247
  void 0,
2985
5248
  { useCustomerAuth: false }
2986
5249
  );
@@ -3009,11 +5272,11 @@ var EventsClient = class {
3009
5272
  { useCustomerAuth: false }
3010
5273
  );
3011
5274
  }
3012
- async execute(endpoint, method, body, options = {}) {
5275
+ async execute(endpoint2, method, body, options = {}) {
3013
5276
  const useCustomerAuth = options.useCustomerAuth === true;
3014
5277
  const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
3015
5278
  try {
3016
- const response = await httpFetch(endpoint, {
5279
+ const response = await httpFetch(endpoint2, {
3017
5280
  method,
3018
5281
  apiUrl: this.apiUrl,
3019
5282
  publishableKey: this.publishableKey,
@@ -3022,7 +5285,7 @@ var EventsClient = class {
3022
5285
  ...body !== void 0 && { body: JSON.stringify(body) }
3023
5286
  });
3024
5287
  this.onRequestId?.(response.headers.get("x-request-id") ?? null);
3025
- return parseApiResponse(response, endpoint);
5288
+ return parseApiResponse(response, endpoint2);
3026
5289
  } catch (err) {
3027
5290
  const id = err instanceof SDKError ? err.requestId ?? null : null;
3028
5291
  this.onRequestId?.(id);
@@ -3061,7 +5324,17 @@ function buildRangeEndpoint(params) {
3061
5324
  appendValues(urlParams, "categorySlug", params.categorySlug);
3062
5325
  appendValues(urlParams, "tag", params.tag);
3063
5326
  appendValues(urlParams, "tagSlug", params.tagSlug);
3064
- return `/api/event-occurrences/range?${urlParams.toString()}`;
5327
+ return resolveOperationPath(EVENTS_ENDPOINT_OPERATIONS.occurrences.range, {
5328
+ query: urlParams
5329
+ });
5330
+ }
5331
+ function buildAdmissionAvailabilityEndpoint(params) {
5332
+ const urlParams = new URLSearchParams();
5333
+ urlParams.set("occurrence", params.occurrence);
5334
+ return resolveOperationPath(
5335
+ EVENTS_ENDPOINT_OPERATIONS.occurrences.admissionAvailability,
5336
+ { query: urlParams }
5337
+ );
3065
5338
  }
3066
5339
  function formatDateParam(value) {
3067
5340
  return value instanceof Date ? value.toISOString() : value;
@@ -3074,15 +5347,62 @@ function appendValues(params, key, value) {
3074
5347
  }
3075
5348
  }
3076
5349
 
5350
+ // src/core/market/market-discovery.ts
5351
+ function toMarketDTO(row) {
5352
+ return {
5353
+ id: row.id,
5354
+ handle: row.handle,
5355
+ name: row.name,
5356
+ countryCode: row.countryCode,
5357
+ targetCountries: (row.targetCountries ?? []).map((c) => c.countryCode),
5358
+ currency: row.currency,
5359
+ isPrimary: row.isPrimary === true,
5360
+ isActive: row.isActive === true
5361
+ };
5362
+ }
5363
+ var MarketDiscovery = class {
5364
+ constructor(read) {
5365
+ this.read = read;
5366
+ }
5367
+ async list() {
5368
+ const res = await this.read({
5369
+ where: { isActive: { equals: true } },
5370
+ limit: 100
5371
+ });
5372
+ if (res.hasNextPage) {
5373
+ console.warn(
5374
+ "[markets.list] more than 100 active markets; results truncated to 100."
5375
+ );
5376
+ }
5377
+ return res.docs.map(toMarketDTO);
5378
+ }
5379
+ async default() {
5380
+ const res = await this.read({
5381
+ where: { isPrimary: { equals: true }, isActive: { equals: true } },
5382
+ limit: 1
5383
+ });
5384
+ const row = res.docs[0];
5385
+ return row ? toMarketDTO(row) : null;
5386
+ }
5387
+ };
5388
+
3077
5389
  // src/core/client/client.ts
3078
5390
  var BrowserMembershipApi = class extends CustomerScopedApi {
3079
5391
  me() {
3080
- return this.request(MEMBERSHIP_ENDPOINTS.me, {
3081
- method: "GET"
3082
- });
5392
+ return this.requestEndpoint(
5393
+ MEMBERSHIP_ENDPOINT_OPERATIONS.me
5394
+ );
5395
+ }
5396
+ cancel(params) {
5397
+ const { id, immediate } = params;
5398
+ return this.requestEndpoint(
5399
+ MEMBERSHIP_ENDPOINT_OPERATIONS.cancel,
5400
+ immediate !== void 0 ? { immediate } : {},
5401
+ { pathParams: { id } }
5402
+ );
3083
5403
  }
3084
5404
  };
3085
- var Client = class {
5405
+ var Client = class _Client {
3086
5406
  constructor(options) {
3087
5407
  this.lastRequestId = null;
3088
5408
  const publishableKey = options.publishableKey;
@@ -3114,6 +5434,7 @@ var Client = class {
3114
5434
  this.commerce = new CommerceClient({
3115
5435
  publishableKey: this.config.publishableKey,
3116
5436
  apiUrl: this.config.apiUrl,
5437
+ market: this.config.market,
3117
5438
  customerToken: () => this.customer.auth.getToken(),
3118
5439
  onUnauthorized,
3119
5440
  onRequestId,
@@ -3146,6 +5467,9 @@ var Client = class {
3146
5467
  onRequestId,
3147
5468
  this.config.apiUrl
3148
5469
  );
5470
+ this.markets = new MarketDiscovery(
5471
+ (options2) => this.collections.from("markets").find(options2)
5472
+ );
3149
5473
  const membershipApi = new BrowserMembershipApi("MembershipApi", {
3150
5474
  publishableKey: this.config.publishableKey,
3151
5475
  apiUrl: this.config.apiUrl,
@@ -3154,12 +5478,23 @@ var Client = class {
3154
5478
  onRequestId
3155
5479
  });
3156
5480
  this.memberships = {
3157
- me: membershipApi.me.bind(membershipApi)
5481
+ me: membershipApi.me.bind(membershipApi),
5482
+ cancel: membershipApi.cancel.bind(membershipApi)
3158
5483
  };
3159
5484
  }
3160
5485
  getState() {
3161
5486
  return { ...this.state };
3162
5487
  }
5488
+ withMarket(market) {
5489
+ return new _Client({
5490
+ ...this.config,
5491
+ customer: this.config.customer?.persist === false ? {
5492
+ ...this.config.customer,
5493
+ token: this.customer.auth.getToken() ?? void 0
5494
+ } : this.config.customer,
5495
+ market
5496
+ });
5497
+ }
3163
5498
  getConfig() {
3164
5499
  return { ...this.config };
3165
5500
  }