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