@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.
- package/CHANGELOG.md +358 -2
- package/MIGRATION.md +89 -10
- package/README.md +441 -98
- package/dist/{server-nXOezi4b.d.cts → catalog-mappers-sIshKNb3.d.cts} +14 -3
- package/dist/{server-nXOezi4b.d.ts → catalog-mappers-sIshKNb3.d.ts} +14 -3
- package/dist/client.cjs +2680 -345
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +10 -7
- package/dist/client.d.ts +10 -7
- package/dist/client.js +2680 -345
- package/dist/client.js.map +1 -1
- package/dist/{collection-client-Dyl-CDcj.d.cts → collection-client-BSo7VXQE.d.cts} +8 -5
- package/dist/{collection-client-DWooaiTr.d.ts → collection-client-Ckfusuee.d.ts} +8 -5
- package/dist/{const-pGDnsy0o.d.ts → const-BAG0MH0u.d.cts} +13 -10
- package/dist/{const-1vleZ6ov.d.cts → const-CaPq2AE4.d.ts} +13 -10
- package/dist/errors.cjs +74 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +38 -1
- package/dist/errors.d.ts +38 -1
- package/dist/errors.js +74 -1
- package/dist/errors.js.map +1 -1
- package/dist/{index-DUNySyxV.d.ts → index-BNICJxBL.d.ts} +4 -4
- package/dist/{index-a6g7vqAD.d.cts → index-YGrZrxNn.d.cts} +4 -4
- package/dist/index.cjs +2741 -368
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -19
- package/dist/index.d.ts +18 -19
- package/dist/index.js +2741 -368
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-CDsuOEfM.d.cts → payload-types-CJZuXcgF.d.cts} +6671 -4001
- package/dist/{payload-types-CDsuOEfM.d.ts → payload-types-CJZuXcgF.d.ts} +6671 -4001
- package/dist/query.cjs +550 -101
- package/dist/query.cjs.map +1 -1
- package/dist/query.d.cts +43 -45
- package/dist/query.d.ts +43 -45
- package/dist/query.js +550 -101
- package/dist/query.js.map +1 -1
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/realtime.js.map +1 -1
- package/dist/server.cjs +2252 -444
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +11 -10
- package/dist/server.d.ts +11 -10
- package/dist/server.js +2252 -444
- package/dist/server.js.map +1 -1
- package/dist/storefront-cache.cjs +65 -1
- package/dist/storefront-cache.cjs.map +1 -1
- package/dist/storefront-cache.js +65 -1
- package/dist/storefront-cache.js.map +1 -1
- package/dist/types-BC6rVmJa.d.ts +47 -0
- package/dist/{types-CDND3hzq.d.cts → types-BlOvjoTX.d.ts} +1095 -509
- package/dist/{types-Dt9FJisi.d.ts → types-C4WuJfw7.d.cts} +1095 -509
- package/dist/types-D5p7-m1l.d.cts +47 -0
- package/dist/ui/canvas/server.cjs +244 -2
- package/dist/ui/canvas/server.cjs.map +1 -1
- package/dist/ui/canvas/server.d.cts +27 -1
- package/dist/ui/canvas/server.d.ts +27 -1
- package/dist/ui/canvas/server.js +244 -2
- package/dist/ui/canvas/server.js.map +1 -1
- package/dist/ui/canvas.cjs +419 -103
- package/dist/ui/canvas.cjs.map +1 -1
- package/dist/ui/canvas.d.cts +19 -7
- package/dist/ui/canvas.d.ts +19 -7
- package/dist/ui/canvas.js +419 -103
- package/dist/ui/canvas.js.map +1 -1
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.d.cts +1 -1
- package/dist/ui/video.d.ts +1 -1
- package/dist/webhook.cjs +2 -1
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.d.cts +4 -4
- package/dist/webhook.d.ts +4 -4
- package/dist/webhook.js +2 -1
- package/dist/webhook.js.map +1 -1
- package/package.json +12 -11
- package/dist/types-SoXsbKhj.d.cts +0 -33
- package/dist/types-oiae_LMm.d.ts +0 -33
package/dist/index.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);
|
|
@@ -270,6 +396,7 @@ var NON_RETRYABLE_STATUSES = [400, 401, 403, 404, 409, 422];
|
|
|
270
396
|
var SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
|
|
271
397
|
var DEFAULT_MAX_RETRIES = 3;
|
|
272
398
|
var STOREFRONT_BROWSER_MAX_RETRIES = 1;
|
|
399
|
+
var MAX_AUTOMATIC_RETRY_AFTER_SECONDS = 5 * 60;
|
|
273
400
|
function debugLog(debug, type, message, data) {
|
|
274
401
|
if (!debug) return;
|
|
275
402
|
const shouldLog = debug === true || type === "request" && debug.logRequests || type === "response" && debug.logResponses || type === "error" && debug.logErrors;
|
|
@@ -384,116 +511,129 @@ function attachRequestId(err, id) {
|
|
|
384
511
|
}
|
|
385
512
|
function parseRetryAfter(response) {
|
|
386
513
|
const raw = response.headers.get("Retry-After");
|
|
387
|
-
if (!raw) return
|
|
388
|
-
|
|
514
|
+
if (!raw) return { permitsAutomaticRetry: true };
|
|
515
|
+
const trimmed = raw.trim();
|
|
516
|
+
let seconds;
|
|
517
|
+
if (/^\d+$/.test(trimmed)) {
|
|
518
|
+
seconds = Number(trimmed);
|
|
519
|
+
if (!Number.isSafeInteger(seconds)) {
|
|
520
|
+
return { permitsAutomaticRetry: false };
|
|
521
|
+
}
|
|
522
|
+
} else {
|
|
523
|
+
const retryAt = Date.parse(trimmed);
|
|
524
|
+
if (!Number.isFinite(retryAt)) return { permitsAutomaticRetry: true };
|
|
525
|
+
seconds = Math.max(0, Math.ceil((retryAt - Date.now()) / 1e3));
|
|
526
|
+
}
|
|
527
|
+
return {
|
|
528
|
+
seconds,
|
|
529
|
+
permitsAutomaticRetry: seconds <= MAX_AUTOMATIC_RETRY_AFTER_SECONDS
|
|
530
|
+
};
|
|
389
531
|
}
|
|
390
|
-
function mapResponseToError(status, parsed, details, requestId, retryAfter) {
|
|
532
|
+
function mapResponseToError(status, parsed, details, requestId, retryAfter, errorFamily) {
|
|
391
533
|
const errorDetails = {
|
|
392
534
|
...details,
|
|
393
535
|
...parsed.errors && { errors: parsed.errors },
|
|
394
|
-
...parsed.body && { body: parsed.body }
|
|
536
|
+
...errorFamily !== "commerce" && parsed.body && { body: parsed.body }
|
|
395
537
|
};
|
|
396
538
|
const suggestion = getParsedErrorSuggestion(status, parsed);
|
|
539
|
+
const finalize = (error) => {
|
|
540
|
+
const withRequestId = attachRequestId(error, requestId);
|
|
541
|
+
if (retryAfter !== void 0) {
|
|
542
|
+
Object.assign(withRequestId, { retryAfter });
|
|
543
|
+
}
|
|
544
|
+
return errorFamily === "commerce" ? enhanceCommerceError(withRequestId, parsed.body, requestId) : withRequestId;
|
|
545
|
+
};
|
|
397
546
|
if (status === 400 || status === 422) {
|
|
398
|
-
return
|
|
547
|
+
return finalize(
|
|
399
548
|
createValidationError(
|
|
400
549
|
parsed.errorMessage,
|
|
401
550
|
errorDetails,
|
|
402
551
|
parsed.userMessage,
|
|
403
552
|
suggestion,
|
|
404
553
|
status
|
|
405
|
-
)
|
|
406
|
-
requestId
|
|
554
|
+
)
|
|
407
555
|
);
|
|
408
556
|
}
|
|
409
557
|
if (status === 401) {
|
|
410
|
-
return
|
|
558
|
+
return finalize(
|
|
411
559
|
createAuthError(
|
|
412
560
|
parsed.errorMessage,
|
|
413
561
|
errorDetails,
|
|
414
562
|
parsed.userMessage,
|
|
415
563
|
suggestion
|
|
416
|
-
)
|
|
417
|
-
requestId
|
|
564
|
+
)
|
|
418
565
|
);
|
|
419
566
|
}
|
|
420
567
|
if (status === 403) {
|
|
421
|
-
return
|
|
568
|
+
return finalize(
|
|
422
569
|
createPermissionError(
|
|
423
570
|
parsed.errorMessage,
|
|
424
571
|
errorDetails,
|
|
425
572
|
parsed.userMessage,
|
|
426
573
|
suggestion
|
|
427
|
-
)
|
|
428
|
-
requestId
|
|
574
|
+
)
|
|
429
575
|
);
|
|
430
576
|
}
|
|
431
577
|
if (status === 404) {
|
|
432
|
-
return
|
|
578
|
+
return finalize(
|
|
433
579
|
createNotFoundError(
|
|
434
580
|
parsed.errorMessage,
|
|
435
581
|
errorDetails,
|
|
436
582
|
parsed.userMessage,
|
|
437
583
|
suggestion
|
|
438
|
-
)
|
|
439
|
-
requestId
|
|
584
|
+
)
|
|
440
585
|
);
|
|
441
586
|
}
|
|
442
587
|
if (status === 409) {
|
|
443
|
-
return
|
|
588
|
+
return finalize(
|
|
444
589
|
createConflictError(
|
|
445
590
|
parsed.errorMessage,
|
|
446
591
|
errorDetails,
|
|
447
592
|
parsed.userMessage,
|
|
448
593
|
suggestion
|
|
449
|
-
)
|
|
450
|
-
requestId
|
|
594
|
+
)
|
|
451
595
|
);
|
|
452
596
|
}
|
|
453
597
|
if (status === 410) {
|
|
454
|
-
return
|
|
598
|
+
return finalize(
|
|
455
599
|
createGoneError(
|
|
456
600
|
parsed.errorMessage,
|
|
457
601
|
errorDetails,
|
|
458
602
|
parsed.userMessage,
|
|
459
603
|
suggestion
|
|
460
|
-
)
|
|
461
|
-
requestId
|
|
604
|
+
)
|
|
462
605
|
);
|
|
463
606
|
}
|
|
464
607
|
if (status === 429) {
|
|
465
|
-
return
|
|
608
|
+
return finalize(
|
|
466
609
|
createRateLimitError(
|
|
467
610
|
parsed.errorMessage,
|
|
468
611
|
retryAfter,
|
|
469
612
|
errorDetails,
|
|
470
613
|
parsed.userMessage,
|
|
471
614
|
suggestion
|
|
472
|
-
)
|
|
473
|
-
requestId
|
|
615
|
+
)
|
|
474
616
|
);
|
|
475
617
|
}
|
|
476
618
|
if (status === 503) {
|
|
477
|
-
return
|
|
619
|
+
return finalize(
|
|
478
620
|
createServiceUnavailableError(
|
|
479
621
|
parsed.errorMessage,
|
|
480
622
|
retryAfter,
|
|
481
623
|
errorDetails,
|
|
482
624
|
parsed.userMessage,
|
|
483
625
|
suggestion
|
|
484
|
-
)
|
|
485
|
-
requestId
|
|
626
|
+
)
|
|
486
627
|
);
|
|
487
628
|
}
|
|
488
|
-
return
|
|
629
|
+
return finalize(
|
|
489
630
|
createNetworkError(
|
|
490
631
|
parsed.errorMessage,
|
|
491
632
|
status,
|
|
492
633
|
errorDetails,
|
|
493
634
|
parsed.userMessage,
|
|
494
635
|
suggestion
|
|
495
|
-
)
|
|
496
|
-
requestId
|
|
636
|
+
)
|
|
497
637
|
);
|
|
498
638
|
}
|
|
499
639
|
async function httpFetch(url, options) {
|
|
@@ -506,6 +646,7 @@ async function httpFetch(url, options) {
|
|
|
506
646
|
debug,
|
|
507
647
|
retry,
|
|
508
648
|
onUnauthorized,
|
|
649
|
+
errorFamily,
|
|
509
650
|
...requestInit
|
|
510
651
|
} = options || {};
|
|
511
652
|
const baseUrl = resolveApiUrl(apiUrl);
|
|
@@ -558,6 +699,8 @@ async function httpFetch(url, options) {
|
|
|
558
699
|
headers: redactSensitiveHeaders(response.headers)
|
|
559
700
|
});
|
|
560
701
|
if (!response.ok) {
|
|
702
|
+
const parsed = await parseErrorBody(response);
|
|
703
|
+
const commerceEnvelope = errorFamily === "commerce" ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
|
|
561
704
|
if (isUsageLimitExceededResponse(response)) {
|
|
562
705
|
const limit = parseInt(
|
|
563
706
|
response.headers.get("X-Usage-Limit") || "0",
|
|
@@ -571,7 +714,7 @@ async function httpFetch(url, options) {
|
|
|
571
714
|
response.headers.get("X-Usage-Remaining") || "0",
|
|
572
715
|
10
|
|
573
716
|
);
|
|
574
|
-
|
|
717
|
+
const usageError = attachRequestId(
|
|
575
718
|
createUsageLimitError(
|
|
576
719
|
`Monthly API usage limit exceeded (${current.toLocaleString()}/${limit.toLocaleString()})`,
|
|
577
720
|
{ limit, current, remaining },
|
|
@@ -585,9 +728,9 @@ async function httpFetch(url, options) {
|
|
|
585
728
|
),
|
|
586
729
|
requestId
|
|
587
730
|
);
|
|
731
|
+
throw errorFamily === "commerce" ? enhanceCommerceError(usageError, parsed.body, requestId) : usageError;
|
|
588
732
|
}
|
|
589
|
-
|
|
590
|
-
if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && parsed.reason === "token_expired") {
|
|
733
|
+
if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && (commerceEnvelope?.reason ?? parsed.reason) === "token_expired") {
|
|
591
734
|
hasRetried401 = true;
|
|
592
735
|
try {
|
|
593
736
|
const newToken = await onUnauthorized();
|
|
@@ -609,13 +752,18 @@ async function httpFetch(url, options) {
|
|
|
609
752
|
parsed,
|
|
610
753
|
details,
|
|
611
754
|
requestId,
|
|
612
|
-
retryAfter
|
|
755
|
+
retryAfter.seconds,
|
|
756
|
+
errorFamily
|
|
613
757
|
);
|
|
614
758
|
const method2 = (requestInit.method || "GET").toUpperCase();
|
|
615
759
|
const isTerminal = error instanceof RateLimitError || error instanceof UsageLimitError;
|
|
616
|
-
|
|
760
|
+
const responseAllowsRetry = isCommerceSDKError(error) ? error.retryable : true;
|
|
761
|
+
if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(method2) && !isTerminal && responseAllowsRetry && retryAfter.permitsAutomaticRetry && !NON_RETRYABLE_STATUSES.includes(response.status) && retryConfig.retryableStatuses.includes(response.status)) {
|
|
617
762
|
lastError = error;
|
|
618
|
-
const retryDelay =
|
|
763
|
+
const retryDelay = Math.max(
|
|
764
|
+
retryConfig.retryDelay(attempt),
|
|
765
|
+
(retryAfter.seconds ?? 0) * 1e3
|
|
766
|
+
);
|
|
619
767
|
debugLog(debug, "error", `Retrying in ${retryDelay}ms...`, error);
|
|
620
768
|
await delay(retryDelay);
|
|
621
769
|
continue;
|
|
@@ -685,87 +833,45 @@ async function httpFetch(url, options) {
|
|
|
685
833
|
throw lastError ?? new NetworkError("Request failed after retries");
|
|
686
834
|
}
|
|
687
835
|
|
|
688
|
-
// src/core/api/endpoints.ts
|
|
689
|
-
var COMMERCE_ENDPOINTS = {
|
|
690
|
-
orders: {
|
|
691
|
-
create: "/api/orders/create",
|
|
692
|
-
update: "/api/orders/update",
|
|
693
|
-
confirmPayment: "/api/orders/confirm-payment",
|
|
694
|
-
byPayment: "/api/orders/by-payment",
|
|
695
|
-
cancel: "/api/orders/cancel",
|
|
696
|
-
resolveCancelRefund: "/api/orders/resolve-cancel-refund",
|
|
697
|
-
checkout: "/api/orders/checkout",
|
|
698
|
-
createFulfillment: "/api/orders/create-fulfillment",
|
|
699
|
-
updateFulfillment: "/api/orders/update-fulfillment"
|
|
700
|
-
},
|
|
701
|
-
transactions: {
|
|
702
|
-
update: "/api/transactions/update"
|
|
703
|
-
},
|
|
704
|
-
returns: {
|
|
705
|
-
create: "/api/returns/create",
|
|
706
|
-
update: "/api/returns/update",
|
|
707
|
-
returnRefund: "/api/returns/return-refund"
|
|
708
|
-
},
|
|
709
|
-
fulfillmentOrders: {
|
|
710
|
-
prepare: "/api/fulfillment-orders/prepare-fulfillment-order"
|
|
711
|
-
},
|
|
712
|
-
fulfillments: {
|
|
713
|
-
bulkImport: "/api/fulfillments/bulk-import"
|
|
714
|
-
},
|
|
715
|
-
carts: {
|
|
716
|
-
mine: "/api/carts/mine",
|
|
717
|
-
merge: "/api/carts/merge",
|
|
718
|
-
addItem: "/api/carts/add-item",
|
|
719
|
-
updateItem: "/api/carts/update-item",
|
|
720
|
-
removeItem: "/api/carts/remove-item",
|
|
721
|
-
applyDiscount: "/api/carts/apply-discount",
|
|
722
|
-
removeDiscount: "/api/carts/remove-discount",
|
|
723
|
-
clear: "/api/carts/clear"
|
|
724
|
-
},
|
|
725
|
-
products: {
|
|
726
|
-
stockCheck: "/api/products/stock-check",
|
|
727
|
-
stockSnapshot: "/api/products/stock",
|
|
728
|
-
listingGroups: "/api/products/listing-groups",
|
|
729
|
-
listingGroupsCatalog: "/api/products/listing-groups/catalog",
|
|
730
|
-
listingGroupsQuery: "/api/products/listing-groups/query",
|
|
731
|
-
listingGroupsQueryCatalog: "/api/products/listing-groups/query/catalog",
|
|
732
|
-
detail: "/api/products/detail",
|
|
733
|
-
detailCatalog: "/api/products/detail/catalog",
|
|
734
|
-
upsert: "/api/products/upsert"
|
|
735
|
-
}
|
|
736
|
-
};
|
|
737
|
-
var COMMERCE_ENDPOINT_PATHS = Object.values(
|
|
738
|
-
COMMERCE_ENDPOINTS
|
|
739
|
-
).flatMap((group) => Object.values(group));
|
|
740
|
-
var MEMBERSHIP_ENDPOINTS = {
|
|
741
|
-
subscribe: "/api/memberships/subscribe",
|
|
742
|
-
cancel: (id) => `/api/memberships/${id}/cancel`,
|
|
743
|
-
me: "/api/memberships/me"
|
|
744
|
-
};
|
|
745
|
-
|
|
746
836
|
// src/core/internal/utils/query-string.ts
|
|
747
|
-
function
|
|
748
|
-
const
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
837
|
+
function normalizedMarket(value) {
|
|
838
|
+
const market = value?.trim();
|
|
839
|
+
return market || void 0;
|
|
840
|
+
}
|
|
841
|
+
function appendProductLocaleSearchParams(search, options) {
|
|
842
|
+
if (options?.locale) search.set("locale", options.locale);
|
|
843
|
+
if (options?.fallbackLocale !== void 0) {
|
|
844
|
+
search.set(
|
|
845
|
+
"fallbackLocale",
|
|
846
|
+
options.fallbackLocale === false ? "none" : options.fallbackLocale
|
|
847
|
+
);
|
|
753
848
|
}
|
|
754
|
-
return `${COMMERCE_ENDPOINTS.products.detail}?${search}`;
|
|
755
849
|
}
|
|
756
|
-
function
|
|
850
|
+
function productDetailSearchParams(params) {
|
|
757
851
|
const search = new URLSearchParams();
|
|
758
852
|
if ("slug" in params) {
|
|
759
853
|
search.set("slug", params.slug);
|
|
760
854
|
} else {
|
|
761
855
|
search.set("id", params.id);
|
|
762
856
|
}
|
|
763
|
-
|
|
857
|
+
const market = normalizedMarket(params.market);
|
|
858
|
+
if (market) search.set("market", market);
|
|
859
|
+
appendProductLocaleSearchParams(search, params);
|
|
860
|
+
return search.toString();
|
|
764
861
|
}
|
|
765
|
-
function
|
|
766
|
-
|
|
862
|
+
function listingGroupsSearchParams(params) {
|
|
863
|
+
const ids = params.productIds.map(encodeURIComponent).join(",");
|
|
864
|
+
const search = new URLSearchParams();
|
|
865
|
+
const market = normalizedMarket(params.market);
|
|
866
|
+
if (market) search.set("market", market);
|
|
867
|
+
appendProductLocaleSearchParams(search, params);
|
|
868
|
+
const query = search.toString();
|
|
869
|
+
return `ids=${ids}${query ? `&${query}` : ""}`;
|
|
767
870
|
}
|
|
768
871
|
function appendListingGroupsQuerySearchParams(search, options) {
|
|
872
|
+
const market = normalizedMarket(options?.market);
|
|
873
|
+
if (market) search.set("market", market);
|
|
874
|
+
appendProductLocaleSearchParams(search, options);
|
|
769
875
|
if (options?.page != null) search.set("page", String(options.page));
|
|
770
876
|
if (options?.limit != null) search.set("limit", String(options.limit));
|
|
771
877
|
if (options?.sort != null) {
|
|
@@ -776,20 +882,13 @@ function appendListingGroupsQuerySearchParams(search, options) {
|
|
|
776
882
|
search.set("whereJson", JSON.stringify(options.where));
|
|
777
883
|
}
|
|
778
884
|
}
|
|
779
|
-
function
|
|
885
|
+
function listingPageSearchParams(options) {
|
|
780
886
|
const search = new URLSearchParams();
|
|
781
887
|
appendListingGroupsQuerySearchParams(search, options);
|
|
782
|
-
|
|
783
|
-
return `${COMMERCE_ENDPOINTS.products.listingGroupsQuery}${query ? `?${query}` : ""}`;
|
|
784
|
-
}
|
|
785
|
-
function listingGroupsQueryCatalogUrl(options) {
|
|
786
|
-
const search = new URLSearchParams();
|
|
787
|
-
appendListingGroupsQuerySearchParams(search, options);
|
|
788
|
-
const query = search.toString();
|
|
789
|
-
return `${COMMERCE_ENDPOINTS.products.listingGroupsQueryCatalog}${query ? `?${query}` : ""}`;
|
|
888
|
+
return search.toString();
|
|
790
889
|
}
|
|
791
|
-
function
|
|
792
|
-
return
|
|
890
|
+
function stockSnapshotSearchParams(params) {
|
|
891
|
+
return `variantIds=${params.variantIds.map(encodeURIComponent).join(",")}`;
|
|
793
892
|
}
|
|
794
893
|
|
|
795
894
|
// src/core/collection/http-client.ts
|
|
@@ -832,10 +931,15 @@ var HttpClient = class {
|
|
|
832
931
|
throw err;
|
|
833
932
|
}
|
|
834
933
|
}
|
|
835
|
-
buildUrl(
|
|
836
|
-
if (!options) return
|
|
837
|
-
const
|
|
838
|
-
|
|
934
|
+
buildUrl(endpoint2, options) {
|
|
935
|
+
if (!options) return endpoint2;
|
|
936
|
+
const { fallbackLocale, ...rest } = options;
|
|
937
|
+
const queryOptions = fallbackLocale === void 0 ? rest : {
|
|
938
|
+
...rest,
|
|
939
|
+
"fallback-locale": fallbackLocale === false ? "none" : fallbackLocale
|
|
940
|
+
};
|
|
941
|
+
const queryString = stringify(queryOptions, { addQueryPrefix: true });
|
|
942
|
+
return queryString ? `${endpoint2}${queryString}` : endpoint2;
|
|
839
943
|
}
|
|
840
944
|
assertJsonResponse(response) {
|
|
841
945
|
const contentType = response.headers.get("content-type");
|
|
@@ -984,39 +1088,39 @@ var ReadOnlyCollectionClient = class extends HttpClient {
|
|
|
984
1088
|
from(collection) {
|
|
985
1089
|
return new ReadOnlyCollectionQueryBuilder(this, collection);
|
|
986
1090
|
}
|
|
987
|
-
async requestFind(
|
|
988
|
-
const url = this.buildUrl(
|
|
1091
|
+
async requestFind(endpoint2, options) {
|
|
1092
|
+
const url = this.buildUrl(endpoint2, options);
|
|
989
1093
|
const response = await this.fetchWithTracking(url, {
|
|
990
1094
|
...this.defaultOptions,
|
|
991
1095
|
method: "GET"
|
|
992
1096
|
});
|
|
993
1097
|
return this.parseFindResponse(response);
|
|
994
1098
|
}
|
|
995
|
-
async requestFindEndpoint(
|
|
996
|
-
const response = await this.fetchWithTracking(
|
|
1099
|
+
async requestFindEndpoint(endpoint2, data) {
|
|
1100
|
+
const response = await this.fetchWithTracking(endpoint2, {
|
|
997
1101
|
...this.defaultOptions,
|
|
998
1102
|
method: "POST",
|
|
999
1103
|
body: data ? JSON.stringify(data) : void 0
|
|
1000
1104
|
});
|
|
1001
1105
|
return this.parseFindResponse(response);
|
|
1002
1106
|
}
|
|
1003
|
-
async requestFindEndpointGet(
|
|
1004
|
-
const response = await this.fetchWithTracking(
|
|
1107
|
+
async requestFindEndpointGet(endpoint2) {
|
|
1108
|
+
const response = await this.fetchWithTracking(endpoint2, {
|
|
1005
1109
|
...this.defaultOptions,
|
|
1006
1110
|
method: "GET"
|
|
1007
1111
|
});
|
|
1008
1112
|
return this.parseFindResponse(response);
|
|
1009
1113
|
}
|
|
1010
|
-
async requestFindById(
|
|
1011
|
-
const url = this.buildUrl(
|
|
1114
|
+
async requestFindById(endpoint2, options) {
|
|
1115
|
+
const url = this.buildUrl(endpoint2, options);
|
|
1012
1116
|
const response = await this.fetchWithTracking(url, {
|
|
1013
1117
|
...this.defaultOptions,
|
|
1014
1118
|
method: "GET"
|
|
1015
1119
|
});
|
|
1016
1120
|
return this.parseDocumentResponse(response);
|
|
1017
1121
|
}
|
|
1018
|
-
async requestCount(
|
|
1019
|
-
const url = this.buildUrl(
|
|
1122
|
+
async requestCount(endpoint2, options) {
|
|
1123
|
+
const url = this.buildUrl(endpoint2, options);
|
|
1020
1124
|
const response = await this.fetchWithTracking(url, {
|
|
1021
1125
|
...this.defaultOptions,
|
|
1022
1126
|
method: "GET"
|
|
@@ -1026,53 +1130,339 @@ var ReadOnlyCollectionClient = class extends HttpClient {
|
|
|
1026
1130
|
};
|
|
1027
1131
|
|
|
1028
1132
|
// src/core/api/parse-response.ts
|
|
1029
|
-
async function parseApiResponse(response,
|
|
1030
|
-
|
|
1133
|
+
async function parseApiResponse(response, endpoint2, options = {}) {
|
|
1134
|
+
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
1135
|
+
return void 0;
|
|
1136
|
+
}
|
|
1137
|
+
let parsed;
|
|
1031
1138
|
try {
|
|
1032
|
-
|
|
1139
|
+
parsed = await response.json();
|
|
1033
1140
|
} catch {
|
|
1034
1141
|
throw createApiError(
|
|
1035
|
-
`Invalid JSON response from ${
|
|
1142
|
+
`Invalid JSON response from ${endpoint2}`,
|
|
1036
1143
|
response.status,
|
|
1037
1144
|
void 0,
|
|
1038
1145
|
"Server returned an invalid response.",
|
|
1039
1146
|
"Check if the API endpoint is available."
|
|
1040
1147
|
);
|
|
1041
1148
|
}
|
|
1149
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
1150
|
+
return parsed;
|
|
1151
|
+
}
|
|
1152
|
+
const data = parsed;
|
|
1042
1153
|
if (data.error) {
|
|
1043
1154
|
const errorMessage = typeof data.error === "string" ? data.error : "Unknown API error";
|
|
1044
1155
|
const reason = typeof data.reason === "string" ? data.reason : void 0;
|
|
1045
1156
|
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
1046
|
-
const
|
|
1047
|
-
|
|
1157
|
+
const retryAfter = parseRetryAfter(response).seconds;
|
|
1158
|
+
let error;
|
|
1048
1159
|
if (reason === "validation_failed") {
|
|
1049
|
-
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
|
|
1160
|
+
error = createValidationError(errorMessage, data, errorMessage);
|
|
1161
|
+
} else if (reason === "token_expired" || reason === "token_invalid" || reason === "preview_token_invalid" || reason === "preview_token_required" || reason === "key_invalid" || reason === "key_revoked") {
|
|
1162
|
+
error = createAuthError(errorMessage, data, errorMessage);
|
|
1163
|
+
} else if (reason === "forbidden") {
|
|
1164
|
+
error = createPermissionError(errorMessage, data, errorMessage);
|
|
1165
|
+
} else if (reason === "rate_limit_exceeded") {
|
|
1166
|
+
error = createRateLimitError(errorMessage, retryAfter, data, errorMessage);
|
|
1167
|
+
} else if (reason === "not_found") {
|
|
1168
|
+
error = createNotFoundError(errorMessage, data, errorMessage);
|
|
1169
|
+
} else if (reason === "conflict") {
|
|
1170
|
+
error = createConflictError(errorMessage, data, errorMessage);
|
|
1171
|
+
} else {
|
|
1172
|
+
error = createApiError(
|
|
1173
|
+
errorMessage,
|
|
1174
|
+
response.status,
|
|
1175
|
+
data,
|
|
1176
|
+
errorMessage,
|
|
1177
|
+
"An error occurred while processing the request."
|
|
1178
|
+
);
|
|
1053
1179
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1180
|
+
const withRequestId = attachRequestId(error, requestId);
|
|
1181
|
+
if (retryAfter !== void 0) Object.assign(withRequestId, { retryAfter });
|
|
1182
|
+
throw options.errorFamily === "commerce" ? enhanceCommerceError(withRequestId, data, requestId) : withRequestId;
|
|
1183
|
+
}
|
|
1184
|
+
return data;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// ../../internal/http-contracts/src/index.ts
|
|
1188
|
+
var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
|
|
1189
|
+
var operation = (collection, method, path) => Object.freeze({
|
|
1190
|
+
[operationBrand]: true,
|
|
1191
|
+
collection,
|
|
1192
|
+
method,
|
|
1193
|
+
path
|
|
1194
|
+
});
|
|
1195
|
+
var COMMERCE_ENDPOINT_OPERATIONS = {
|
|
1196
|
+
products: {
|
|
1197
|
+
detail: operation("products", "get", "/detail"),
|
|
1198
|
+
detailCatalog: operation("products", "get", "/detail/catalog"),
|
|
1199
|
+
listingGroups: operation("products", "get", "/listing-groups"),
|
|
1200
|
+
listingGroupsCatalog: operation(
|
|
1201
|
+
"products",
|
|
1202
|
+
"get",
|
|
1203
|
+
"/listing-groups/catalog"
|
|
1204
|
+
),
|
|
1205
|
+
listingGroupsQuery: operation("products", "post", "/listing-groups/query"),
|
|
1206
|
+
listingGroupsQueryGet: operation(
|
|
1207
|
+
"products",
|
|
1208
|
+
"get",
|
|
1209
|
+
"/listing-groups/query"
|
|
1210
|
+
),
|
|
1211
|
+
listingGroupsQueryCatalog: operation(
|
|
1212
|
+
"products",
|
|
1213
|
+
"get",
|
|
1214
|
+
"/listing-groups/query/catalog"
|
|
1215
|
+
),
|
|
1216
|
+
stockCheck: operation("products", "post", "/stock-check"),
|
|
1217
|
+
stockSnapshot: operation("products", "get", "/stock"),
|
|
1218
|
+
upsert: operation("products", "post", "/upsert")
|
|
1219
|
+
},
|
|
1220
|
+
orders: {
|
|
1221
|
+
create: operation("orders", "post", "/create"),
|
|
1222
|
+
update: operation("orders", "post", "/update"),
|
|
1223
|
+
confirmPayment: operation("orders", "post", "/confirm-payment"),
|
|
1224
|
+
byPayment: operation("orders", "get", "/by-payment"),
|
|
1225
|
+
cancel: operation("orders", "post", "/cancel"),
|
|
1226
|
+
resolveCancelRefund: operation("orders", "post", "/resolve-cancel-refund"),
|
|
1227
|
+
checkout: operation("orders", "post", "/checkout"),
|
|
1228
|
+
createFulfillment: operation("orders", "post", "/create-fulfillment"),
|
|
1229
|
+
updateFulfillment: operation("orders", "post", "/update-fulfillment")
|
|
1230
|
+
},
|
|
1231
|
+
checkouts: {
|
|
1232
|
+
detail: operation("checkouts", "post", "/detail"),
|
|
1233
|
+
query: operation("checkouts", "post", "/query")
|
|
1234
|
+
},
|
|
1235
|
+
transactions: {
|
|
1236
|
+
update: operation("transactions", "post", "/update")
|
|
1237
|
+
},
|
|
1238
|
+
returns: {
|
|
1239
|
+
create: operation("returns", "post", "/create"),
|
|
1240
|
+
update: operation("returns", "post", "/update"),
|
|
1241
|
+
returnRefund: operation("returns", "post", "/return-refund")
|
|
1242
|
+
},
|
|
1243
|
+
fulfillmentOrders: {
|
|
1244
|
+
prepare: operation(
|
|
1245
|
+
"fulfillment-orders",
|
|
1246
|
+
"post",
|
|
1247
|
+
"/prepare-fulfillment-order"
|
|
1248
|
+
)
|
|
1249
|
+
},
|
|
1250
|
+
fulfillments: {
|
|
1251
|
+
bulkImport: operation("fulfillments", "post", "/bulk-import")
|
|
1252
|
+
},
|
|
1253
|
+
carts: {
|
|
1254
|
+
create: operation("carts", "post", "/create"),
|
|
1255
|
+
retrieve: operation("carts", "post", "/retrieve"),
|
|
1256
|
+
mine: operation("carts", "post", "/mine"),
|
|
1257
|
+
merge: operation("carts", "post", "/merge"),
|
|
1258
|
+
addItem: operation("carts", "post", "/add-item"),
|
|
1259
|
+
updateItem: operation("carts", "post", "/update-item"),
|
|
1260
|
+
removeItem: operation("carts", "post", "/remove-item"),
|
|
1261
|
+
updateDiscountCodes: operation("carts", "post", "/update-discount-codes"),
|
|
1262
|
+
updateAttributes: operation("carts", "post", "/update-attributes"),
|
|
1263
|
+
clear: operation("carts", "post", "/clear")
|
|
1264
|
+
},
|
|
1265
|
+
paymentSessions: {
|
|
1266
|
+
create: operation("payment-sessions", "post", "/create"),
|
|
1267
|
+
retrieve: operation("payment-sessions", "post", "/retrieve"),
|
|
1268
|
+
cancel: operation("payment-sessions", "post", "/cancel"),
|
|
1269
|
+
server: {
|
|
1270
|
+
create: operation("payment-sessions", "post", "/server/create"),
|
|
1271
|
+
retrieve: operation("payment-sessions", "post", "/server/retrieve"),
|
|
1272
|
+
cancel: operation("payment-sessions", "post", "/server/cancel"),
|
|
1273
|
+
confirm: operation("payment-sessions", "post", "/server/confirm")
|
|
1274
|
+
},
|
|
1275
|
+
custom: {
|
|
1276
|
+
create: operation("orders", "post", "/custom-payment-sessions"),
|
|
1277
|
+
confirm: operation("orders", "post", "/custom-payment-sessions/confirm")
|
|
1056
1278
|
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1279
|
+
},
|
|
1280
|
+
shippingPolicies: {
|
|
1281
|
+
calculate: operation("shipping-policies", "post", "/calculate")
|
|
1282
|
+
},
|
|
1283
|
+
discounts: {
|
|
1284
|
+
validate: operation("discounts", "post", "/validate")
|
|
1285
|
+
}
|
|
1286
|
+
};
|
|
1287
|
+
var MEMBERSHIP_ENDPOINT_OPERATIONS = {
|
|
1288
|
+
subscribe: operation(null, "post", "/memberships/subscribe"),
|
|
1289
|
+
cancel: operation(null, "post", "/memberships/:id/cancel"),
|
|
1290
|
+
me: operation(null, "get", "/memberships/me")
|
|
1291
|
+
};
|
|
1292
|
+
var EVENTS_ENDPOINT_OPERATIONS = {
|
|
1293
|
+
occurrences: {
|
|
1294
|
+
range: operation("event-occurrences", "get", "/range"),
|
|
1295
|
+
admissionAvailability: operation(
|
|
1296
|
+
"event-occurrences",
|
|
1297
|
+
"get",
|
|
1298
|
+
"/admission-availability"
|
|
1299
|
+
)
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
function resolveOperationTemplate(descriptor) {
|
|
1303
|
+
return descriptor.collection ? `/api/${descriptor.collection}${descriptor.path}` : `/api${descriptor.path}`;
|
|
1304
|
+
}
|
|
1305
|
+
function resolveOperationPath(descriptor, options) {
|
|
1306
|
+
const path = resolveOperationTemplate(descriptor).replace(
|
|
1307
|
+
/:([A-Za-z][A-Za-z0-9_]*)/g,
|
|
1308
|
+
(_, key) => {
|
|
1309
|
+
const value = options?.pathParams?.[key];
|
|
1310
|
+
if (value === void 0) {
|
|
1311
|
+
throw new TypeError(`Missing path parameter: ${key}`);
|
|
1312
|
+
}
|
|
1313
|
+
return encodeURIComponent(value);
|
|
1059
1314
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1315
|
+
);
|
|
1316
|
+
const unresolved = path.match(/:([A-Za-z][A-Za-z0-9_]*)/);
|
|
1317
|
+
if (unresolved) {
|
|
1318
|
+
throw new TypeError(`Missing path parameter: ${unresolved[1]}`);
|
|
1319
|
+
}
|
|
1320
|
+
const query = options?.query?.toString().replace(/^\?/, "");
|
|
1321
|
+
return query ? `${path}?${query}` : path;
|
|
1322
|
+
}
|
|
1323
|
+
function resolveOperationMethod(descriptor) {
|
|
1324
|
+
return descriptor.method.toUpperCase();
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
// src/core/api/endpoints.ts
|
|
1328
|
+
var endpoint = (method, path) => ({ method, path });
|
|
1329
|
+
var sharedEndpoint = (descriptor) => descriptor;
|
|
1330
|
+
function resolveOperationMethod2(descriptor) {
|
|
1331
|
+
return "collection" in descriptor ? resolveOperationMethod(descriptor) : descriptor.method;
|
|
1332
|
+
}
|
|
1333
|
+
function resolveOperationPath2(descriptor, options) {
|
|
1334
|
+
if ("collection" in descriptor) {
|
|
1335
|
+
return resolveOperationPath(descriptor, options);
|
|
1336
|
+
}
|
|
1337
|
+
const query = options?.query?.toString().replace(/^\?/, "");
|
|
1338
|
+
return query ? `${descriptor.path}?${query}` : descriptor.path;
|
|
1339
|
+
}
|
|
1340
|
+
var COMMERCE_ENDPOINTS = {
|
|
1341
|
+
products: {
|
|
1342
|
+
detail: endpoint("GET", "/api/products/detail"),
|
|
1343
|
+
detailCatalog: endpoint("GET", "/api/products/detail/catalog"),
|
|
1344
|
+
listingGroups: endpoint("GET", "/api/products/listing-groups"),
|
|
1345
|
+
listingGroupsCatalog: endpoint(
|
|
1346
|
+
"GET",
|
|
1347
|
+
"/api/products/listing-groups/catalog"
|
|
1348
|
+
),
|
|
1349
|
+
listingGroupsQuery: endpoint("GET", "/api/products/listing-groups/query"),
|
|
1350
|
+
listingGroupsQueryCatalog: endpoint(
|
|
1351
|
+
"GET",
|
|
1352
|
+
"/api/products/listing-groups/query/catalog"
|
|
1353
|
+
),
|
|
1354
|
+
stockCheck: endpoint("POST", "/api/products/stock-check"),
|
|
1355
|
+
stockSnapshot: endpoint("GET", "/api/products/stock"),
|
|
1356
|
+
upsert: endpoint("POST", "/api/products/upsert")
|
|
1357
|
+
},
|
|
1358
|
+
orders: {
|
|
1359
|
+
update: endpoint("POST", "/api/orders/update"),
|
|
1360
|
+
byPayment: endpoint("GET", "/api/orders/by-payment"),
|
|
1361
|
+
cancel: endpoint("POST", "/api/orders/cancel"),
|
|
1362
|
+
resolveCancelRefund: endpoint("POST", "/api/orders/resolve-cancel-refund"),
|
|
1363
|
+
createFulfillment: endpoint("POST", "/api/orders/create-fulfillment"),
|
|
1364
|
+
updateFulfillment: endpoint("POST", "/api/orders/update-fulfillment")
|
|
1365
|
+
},
|
|
1366
|
+
checkouts: {
|
|
1367
|
+
create: endpoint("POST", "/api/orders/checkout"),
|
|
1368
|
+
retrieve: endpoint("POST", "/api/checkouts/detail"),
|
|
1369
|
+
server: {
|
|
1370
|
+
create: endpoint("POST", "/api/orders/checkout"),
|
|
1371
|
+
retrieve: endpoint("POST", "/api/checkouts/detail"),
|
|
1372
|
+
query: endpoint("POST", "/api/checkouts/query")
|
|
1062
1373
|
}
|
|
1063
|
-
|
|
1064
|
-
|
|
1374
|
+
},
|
|
1375
|
+
returns: {
|
|
1376
|
+
create: endpoint("POST", "/api/returns/create"),
|
|
1377
|
+
update: endpoint("POST", "/api/returns/update"),
|
|
1378
|
+
returnRefund: endpoint("POST", "/api/returns/return-refund")
|
|
1379
|
+
},
|
|
1380
|
+
fulfillmentOrders: {
|
|
1381
|
+
prepare: endpoint(
|
|
1382
|
+
"POST",
|
|
1383
|
+
"/api/fulfillment-orders/prepare-fulfillment-order"
|
|
1384
|
+
)
|
|
1385
|
+
},
|
|
1386
|
+
fulfillments: {
|
|
1387
|
+
bulkImport: endpoint("POST", "/api/fulfillments/bulk-import")
|
|
1388
|
+
},
|
|
1389
|
+
carts: {
|
|
1390
|
+
create: endpoint("POST", "/api/carts/create"),
|
|
1391
|
+
retrieve: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.retrieve),
|
|
1392
|
+
mine: endpoint("POST", "/api/carts/mine"),
|
|
1393
|
+
merge: endpoint("POST", "/api/carts/merge"),
|
|
1394
|
+
server: {
|
|
1395
|
+
// Server credentials are an authorization lane, not a second Cart
|
|
1396
|
+
// transport. These must stay bound to the registered shared operations.
|
|
1397
|
+
create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.create),
|
|
1398
|
+
retrieve: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.retrieve),
|
|
1399
|
+
mine: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.mine),
|
|
1400
|
+
merge: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.merge),
|
|
1401
|
+
addItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.addItem),
|
|
1402
|
+
updateItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.updateItem),
|
|
1403
|
+
removeItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.removeItem),
|
|
1404
|
+
updateDiscountCodes: sharedEndpoint(
|
|
1405
|
+
COMMERCE_ENDPOINT_OPERATIONS.carts.updateDiscountCodes
|
|
1406
|
+
),
|
|
1407
|
+
updateAttributes: sharedEndpoint(
|
|
1408
|
+
COMMERCE_ENDPOINT_OPERATIONS.carts.updateAttributes
|
|
1409
|
+
),
|
|
1410
|
+
clear: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.clear)
|
|
1411
|
+
},
|
|
1412
|
+
addItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.addItem),
|
|
1413
|
+
updateItem: endpoint("POST", "/api/carts/update-item"),
|
|
1414
|
+
removeItem: endpoint("POST", "/api/carts/remove-item"),
|
|
1415
|
+
updateDiscountCodes: endpoint("POST", "/api/carts/update-discount-codes"),
|
|
1416
|
+
updateAttributes: endpoint("POST", "/api/carts/update-attributes"),
|
|
1417
|
+
clear: endpoint("POST", "/api/carts/clear")
|
|
1418
|
+
},
|
|
1419
|
+
paymentSessions: {
|
|
1420
|
+
create: endpoint("POST", "/api/payment-sessions/create"),
|
|
1421
|
+
retrieve: endpoint("POST", "/api/payment-sessions/retrieve"),
|
|
1422
|
+
cancel: endpoint("POST", "/api/payment-sessions/cancel"),
|
|
1423
|
+
server: {
|
|
1424
|
+
create: endpoint("POST", "/api/payment-sessions/server/create"),
|
|
1425
|
+
retrieve: endpoint("POST", "/api/payment-sessions/server/retrieve"),
|
|
1426
|
+
cancel: endpoint("POST", "/api/payment-sessions/server/cancel"),
|
|
1427
|
+
confirm: endpoint("POST", "/api/payment-sessions/server/confirm")
|
|
1065
1428
|
}
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
);
|
|
1429
|
+
},
|
|
1430
|
+
shippingPolicies: {
|
|
1431
|
+
calculate: endpoint("POST", "/api/shipping-policies/calculate")
|
|
1070
1432
|
}
|
|
1071
|
-
|
|
1433
|
+
};
|
|
1434
|
+
function isCommerceEndpointDescriptor(value) {
|
|
1435
|
+
if (!value || typeof value !== "object") return false;
|
|
1436
|
+
const candidate = value;
|
|
1437
|
+
return typeof candidate.method === "string" && typeof candidate.path === "string";
|
|
1438
|
+
}
|
|
1439
|
+
function flattenEndpointPaths(value) {
|
|
1440
|
+
if (isCommerceEndpointDescriptor(value)) return [resolveOperationPath2(value)];
|
|
1441
|
+
if (!value || typeof value !== "object") return [];
|
|
1442
|
+
return Object.values(value).flatMap((entry) => flattenEndpointPaths(entry));
|
|
1443
|
+
}
|
|
1444
|
+
function flattenEndpointDescriptors(value) {
|
|
1445
|
+
if (isCommerceEndpointDescriptor(value)) return [value];
|
|
1446
|
+
if (!value || typeof value !== "object") return [];
|
|
1447
|
+
return Object.values(value).flatMap(
|
|
1448
|
+
(entry) => flattenEndpointDescriptors(entry)
|
|
1449
|
+
);
|
|
1072
1450
|
}
|
|
1451
|
+
var COMMERCE_ENDPOINT_PATHS = flattenEndpointPaths(COMMERCE_ENDPOINTS);
|
|
1452
|
+
var COMMERCE_ENDPOINT_DESCRIPTORS = flattenEndpointDescriptors(COMMERCE_ENDPOINTS);
|
|
1453
|
+
var MEMBERSHIP_ENDPOINTS = {
|
|
1454
|
+
subscribe: "/api/memberships/subscribe",
|
|
1455
|
+
cancel: (id) => `/api/memberships/${id}/cancel`,
|
|
1456
|
+
me: "/api/memberships/me"
|
|
1457
|
+
};
|
|
1458
|
+
var MEMBERSHIP_ENDPOINT_PATHS = [
|
|
1459
|
+
MEMBERSHIP_ENDPOINTS.subscribe,
|
|
1460
|
+
MEMBERSHIP_ENDPOINTS.cancel(":id"),
|
|
1461
|
+
MEMBERSHIP_ENDPOINTS.me
|
|
1462
|
+
];
|
|
1073
1463
|
|
|
1074
1464
|
// src/core/api/customer-scoped-api.ts
|
|
1075
|
-
var
|
|
1465
|
+
var CustomerScopedTransport = class {
|
|
1076
1466
|
constructor(apiName, options) {
|
|
1077
1467
|
if (options.requiresCredential !== false && !options.secretKey && !options.customerToken) {
|
|
1078
1468
|
throw createConfigError(
|
|
@@ -1090,10 +1480,10 @@ var CustomerScopedApi = class {
|
|
|
1090
1480
|
this.onUnauthorized = options.onUnauthorized;
|
|
1091
1481
|
this.onRequestId = options.onRequestId;
|
|
1092
1482
|
}
|
|
1093
|
-
async request(
|
|
1483
|
+
async request(endpoint2, options) {
|
|
1094
1484
|
const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
|
|
1095
1485
|
try {
|
|
1096
|
-
const response = await httpFetch(
|
|
1486
|
+
const response = await httpFetch(endpoint2, {
|
|
1097
1487
|
method: options.method,
|
|
1098
1488
|
apiUrl: this.apiUrl,
|
|
1099
1489
|
publishableKey: this.publishableKey,
|
|
@@ -1103,10 +1493,13 @@ var CustomerScopedApi = class {
|
|
|
1103
1493
|
...options.body !== void 0 && {
|
|
1104
1494
|
body: JSON.stringify(options.body)
|
|
1105
1495
|
},
|
|
1106
|
-
...options.headers && { headers: options.headers }
|
|
1496
|
+
...options.headers && { headers: options.headers },
|
|
1497
|
+
...options.errorFamily && { errorFamily: options.errorFamily }
|
|
1107
1498
|
});
|
|
1108
1499
|
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1109
|
-
return parseApiResponse(response,
|
|
1500
|
+
return parseApiResponse(response, endpoint2, {
|
|
1501
|
+
errorFamily: options.errorFamily
|
|
1502
|
+
});
|
|
1110
1503
|
} catch (err) {
|
|
1111
1504
|
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
1112
1505
|
this.onRequestId?.(id);
|
|
@@ -1114,6 +1507,26 @@ var CustomerScopedApi = class {
|
|
|
1114
1507
|
}
|
|
1115
1508
|
}
|
|
1116
1509
|
};
|
|
1510
|
+
var CustomerScopedApi = class {
|
|
1511
|
+
constructor(apiName, options) {
|
|
1512
|
+
this.transport = new CustomerScopedTransport(apiName, options);
|
|
1513
|
+
}
|
|
1514
|
+
requestEndpoint(endpoint2, body, options) {
|
|
1515
|
+
return this.transport.request(resolveOperationPath2(endpoint2, options), {
|
|
1516
|
+
method: resolveOperationMethod2(endpoint2),
|
|
1517
|
+
body,
|
|
1518
|
+
headers: options?.headers
|
|
1519
|
+
});
|
|
1520
|
+
}
|
|
1521
|
+
};
|
|
1522
|
+
var RawCustomerScopedApi = class {
|
|
1523
|
+
constructor(apiName, options) {
|
|
1524
|
+
this.transport = new CustomerScopedTransport(apiName, options);
|
|
1525
|
+
}
|
|
1526
|
+
request(endpoint2, options) {
|
|
1527
|
+
return this.transport.request(endpoint2, options);
|
|
1528
|
+
}
|
|
1529
|
+
};
|
|
1117
1530
|
|
|
1118
1531
|
// src/core/community/community-client.ts
|
|
1119
1532
|
var DEFAULT_POST_LIST_SORT = "-lastActivityAt";
|
|
@@ -1124,7 +1537,7 @@ function unwrapPayloadDoc(value) {
|
|
|
1124
1537
|
}
|
|
1125
1538
|
return value;
|
|
1126
1539
|
}
|
|
1127
|
-
var CommunityClient = class extends
|
|
1540
|
+
var CommunityClient = class extends RawCustomerScopedApi {
|
|
1128
1541
|
constructor(options) {
|
|
1129
1542
|
super("CommunityClient", { ...options, requiresCredential: false });
|
|
1130
1543
|
}
|
|
@@ -1168,11 +1581,11 @@ var CommunityClient = class extends CustomerScopedApi {
|
|
|
1168
1581
|
if (params.page !== void 0) urlParams.set("page", String(params.page));
|
|
1169
1582
|
return `/api/comments/public?${urlParams.toString()}`;
|
|
1170
1583
|
}
|
|
1171
|
-
async execute(
|
|
1172
|
-
return this.request(
|
|
1584
|
+
async execute(endpoint2, method, body) {
|
|
1585
|
+
return this.request(endpoint2, { method, body });
|
|
1173
1586
|
}
|
|
1174
|
-
async executeDoc(
|
|
1175
|
-
const response = await this.execute(
|
|
1587
|
+
async executeDoc(endpoint2, method, body) {
|
|
1588
|
+
const response = await this.execute(endpoint2, method, body);
|
|
1176
1589
|
return unwrapPayloadDoc(response);
|
|
1177
1590
|
}
|
|
1178
1591
|
createPost(params) {
|
|
@@ -1408,56 +1821,1538 @@ var CommunityClient = class extends CustomerScopedApi {
|
|
|
1408
1821
|
body
|
|
1409
1822
|
);
|
|
1410
1823
|
}
|
|
1411
|
-
};
|
|
1412
|
-
|
|
1413
|
-
// src/core/content/content-client.ts
|
|
1414
|
-
var PublicContentApi = class extends
|
|
1415
|
-
get(
|
|
1416
|
-
return this.request(
|
|
1417
|
-
}
|
|
1418
|
-
};
|
|
1419
|
-
function appendCommonParams(search, options, defaultSort) {
|
|
1420
|
-
search.set("sort", options?.sort ?? defaultSort);
|
|
1421
|
-
if (options?.page != null) search.set("page", String(options.page));
|
|
1422
|
-
if (options?.limit != null) search.set("limit", String(options.limit));
|
|
1423
|
-
}
|
|
1424
|
-
function linksListPath(options) {
|
|
1425
|
-
const search = new URLSearchParams();
|
|
1426
|
-
appendCommonParams(search, options, "-publishedAt,-createdAt");
|
|
1427
|
-
if (options?.categoryId) search.set("categoryId", options.categoryId);
|
|
1428
|
-
if (options?.categorySlug) {
|
|
1429
|
-
search.set("categorySlug", options.categorySlug);
|
|
1430
|
-
}
|
|
1431
|
-
if (options?.tagId) search.set("tagId", options.tagId);
|
|
1432
|
-
if (options?.tagSlug) search.set("tagSlug", options.tagSlug);
|
|
1433
|
-
if (options?.featured != null)
|
|
1434
|
-
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
if (options?.
|
|
1441
|
-
|
|
1824
|
+
};
|
|
1825
|
+
|
|
1826
|
+
// src/core/content/content-client.ts
|
|
1827
|
+
var PublicContentApi = class extends RawCustomerScopedApi {
|
|
1828
|
+
get(endpoint2) {
|
|
1829
|
+
return this.request(endpoint2, { method: "GET" });
|
|
1830
|
+
}
|
|
1831
|
+
};
|
|
1832
|
+
function appendCommonParams(search, options, defaultSort) {
|
|
1833
|
+
search.set("sort", options?.sort ?? defaultSort);
|
|
1834
|
+
if (options?.page != null) search.set("page", String(options.page));
|
|
1835
|
+
if (options?.limit != null) search.set("limit", String(options.limit));
|
|
1836
|
+
}
|
|
1837
|
+
function linksListPath(options) {
|
|
1838
|
+
const search = new URLSearchParams();
|
|
1839
|
+
appendCommonParams(search, options, "-publishedAt,-createdAt");
|
|
1840
|
+
if (options?.categoryId) search.set("categoryId", options.categoryId);
|
|
1841
|
+
if (options?.categorySlug) {
|
|
1842
|
+
search.set("categorySlug", options.categorySlug);
|
|
1843
|
+
}
|
|
1844
|
+
if (options?.tagId) search.set("tagId", options.tagId);
|
|
1845
|
+
if (options?.tagSlug) search.set("tagSlug", options.tagSlug);
|
|
1846
|
+
if (options?.featured != null)
|
|
1847
|
+
search.set("featured", String(options.featured));
|
|
1848
|
+
return `/api/links/storefront?${search}`;
|
|
1849
|
+
}
|
|
1850
|
+
function galleryItemsListPath(options) {
|
|
1851
|
+
const search = new URLSearchParams();
|
|
1852
|
+
appendCommonParams(search, options, "manual");
|
|
1853
|
+
if (options?.galleryId) search.set("galleryId", options.galleryId);
|
|
1854
|
+
if (options?.gallerySlug) search.set("gallerySlug", options.gallerySlug);
|
|
1855
|
+
return `/api/gallery-items/storefront?${search}`;
|
|
1856
|
+
}
|
|
1857
|
+
var ContentClient = class {
|
|
1858
|
+
constructor(options) {
|
|
1859
|
+
const api = new PublicContentApi("ContentClient", {
|
|
1860
|
+
publishableKey: options.publishableKey,
|
|
1861
|
+
apiUrl: options.apiUrl,
|
|
1862
|
+
onRequestId: options.onRequestId,
|
|
1863
|
+
requiresCredential: false
|
|
1864
|
+
});
|
|
1865
|
+
this.links = {
|
|
1866
|
+
list: (params) => api.get(linksListPath(params))
|
|
1867
|
+
};
|
|
1868
|
+
this.galleryItems = {
|
|
1869
|
+
list: (params) => api.get(
|
|
1870
|
+
galleryItemsListPath(params)
|
|
1871
|
+
)
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
};
|
|
1875
|
+
|
|
1876
|
+
// src/core/api/canonical-response.ts
|
|
1877
|
+
var CART_STATUSES = ["active", "completed", "abandoned"];
|
|
1878
|
+
var MAX_CART_LINE_QUANTITY = 99;
|
|
1879
|
+
var MAX_COMMERCE_SHORT_TEXT_LENGTH = 200;
|
|
1880
|
+
var MAX_COMMERCE_ADDRESS_LENGTH = 500;
|
|
1881
|
+
var MAX_COMMERCE_EMAIL_LENGTH = 254;
|
|
1882
|
+
var MAX_COMMERCE_PHONE_LENGTH = 32;
|
|
1883
|
+
var MAX_COMMERCE_POSTAL_CODE_LENGTH = 32;
|
|
1884
|
+
var MAX_COMMERCE_EXTENSION_VALUE_LENGTH = 500;
|
|
1885
|
+
var MAX_COMMERCE_RESOURCE_ID_LENGTH = 255;
|
|
1886
|
+
var MAX_COMMERCE_CAPABILITY_LENGTH = 512;
|
|
1887
|
+
var MAX_CART_DISCOUNT_CODE_LENGTH = 128;
|
|
1888
|
+
var ORDER_FINANCIAL_STATUSES = [
|
|
1889
|
+
"pending",
|
|
1890
|
+
"authorized",
|
|
1891
|
+
"expired",
|
|
1892
|
+
"partially_paid",
|
|
1893
|
+
"paid",
|
|
1894
|
+
"canceled",
|
|
1895
|
+
"partially_refunded",
|
|
1896
|
+
"refunded",
|
|
1897
|
+
"reconciliation_required"
|
|
1898
|
+
];
|
|
1899
|
+
var ORDER_FULFILLMENT_STATUSES = [
|
|
1900
|
+
"unfulfilled",
|
|
1901
|
+
"in_progress",
|
|
1902
|
+
"on_hold",
|
|
1903
|
+
"partially_fulfilled",
|
|
1904
|
+
"shipped",
|
|
1905
|
+
"fulfilled",
|
|
1906
|
+
"canceled"
|
|
1907
|
+
];
|
|
1908
|
+
var ORDER_RETURN_STATUSES = [
|
|
1909
|
+
"no_return",
|
|
1910
|
+
"return_requested",
|
|
1911
|
+
"in_progress",
|
|
1912
|
+
"returned"
|
|
1913
|
+
];
|
|
1914
|
+
var ORDER_CONFIRMATION_STATUSES = ["unconfirmed", "confirmed"];
|
|
1915
|
+
var ORDER_PRIMARY_DISPLAY_STATUSES = [
|
|
1916
|
+
"pending",
|
|
1917
|
+
"paid",
|
|
1918
|
+
"canceled",
|
|
1919
|
+
"refunded",
|
|
1920
|
+
"preparing",
|
|
1921
|
+
"shipped",
|
|
1922
|
+
"delivered",
|
|
1923
|
+
"confirmed"
|
|
1924
|
+
];
|
|
1925
|
+
var CHECKOUT_STATUSES = ["open", "placed", "abandoned"];
|
|
1926
|
+
var ABANDONED_REASONS = ["expired", "customer", "operator"];
|
|
1927
|
+
var PAYMENT_PROVIDERS = ["toss"];
|
|
1928
|
+
var PAYMENT_PROVIDER_STATUSES = [
|
|
1929
|
+
"requires_payment_method",
|
|
1930
|
+
"requires_action",
|
|
1931
|
+
"requires_confirmation",
|
|
1932
|
+
"initializing",
|
|
1933
|
+
"processing",
|
|
1934
|
+
"authorized",
|
|
1935
|
+
"canceling",
|
|
1936
|
+
"unknown",
|
|
1937
|
+
"captured",
|
|
1938
|
+
"failed",
|
|
1939
|
+
"canceled"
|
|
1940
|
+
];
|
|
1941
|
+
var PAYMENT_FAILURE_REASONS = [
|
|
1942
|
+
"payment_declined",
|
|
1943
|
+
"authentication_failed",
|
|
1944
|
+
"authorization_expired",
|
|
1945
|
+
"payment_method_unavailable",
|
|
1946
|
+
"provider_terminal_failure",
|
|
1947
|
+
"unknown_provider_terminal_failure"
|
|
1948
|
+
];
|
|
1949
|
+
var CART_WARNING_CODES = [
|
|
1950
|
+
"DISCOUNT_CODE_NOT_HONOURED",
|
|
1951
|
+
"DISCOUNT_CURRENTLY_INACTIVE",
|
|
1952
|
+
"DISCOUNT_CUSTOMER_NOT_ELIGIBLE",
|
|
1953
|
+
"DISCOUNT_CUSTOMER_USAGE_LIMIT_REACHED",
|
|
1954
|
+
"DISCOUNT_ELIGIBLE_CUSTOMER_MISSING",
|
|
1955
|
+
"DISCOUNT_NO_ENTITLED_LINE_ITEMS",
|
|
1956
|
+
"DISCOUNT_NO_ENTITLED_SHIPPING_LINES",
|
|
1957
|
+
"DISCOUNT_NOT_FOUND",
|
|
1958
|
+
"DISCOUNT_PURCHASE_NOT_IN_RANGE",
|
|
1959
|
+
"DISCOUNT_USAGE_LIMIT_REACHED",
|
|
1960
|
+
"MERCHANDISE_NOT_ENOUGH_STOCK",
|
|
1961
|
+
"MERCHANDISE_OUT_OF_STOCK"
|
|
1962
|
+
];
|
|
1963
|
+
function invalidCanonicalResponse(resource, details) {
|
|
1964
|
+
throw createApiError(
|
|
1965
|
+
`Invalid canonical ${resource} response.`,
|
|
1966
|
+
502,
|
|
1967
|
+
{ resource, ...details },
|
|
1968
|
+
`The server returned an incompatible ${resource} response.`,
|
|
1969
|
+
"Verify that the Console commerce contract is deployed before using this SDK version."
|
|
1970
|
+
);
|
|
1971
|
+
}
|
|
1972
|
+
function fail(resource, path, expected) {
|
|
1973
|
+
invalidCanonicalResponse(resource, { path, expected });
|
|
1974
|
+
}
|
|
1975
|
+
function record(value, resource, path) {
|
|
1976
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1977
|
+
fail(resource, path, "object");
|
|
1978
|
+
}
|
|
1979
|
+
return value;
|
|
1980
|
+
}
|
|
1981
|
+
function exact(value, required, optional, resource, path) {
|
|
1982
|
+
for (const key of required) {
|
|
1983
|
+
if (!(key in value)) fail(resource, `${path}.${key}`, "required field");
|
|
1984
|
+
}
|
|
1985
|
+
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
1986
|
+
const unexpected = Object.keys(value).find((key) => !allowed.has(key));
|
|
1987
|
+
if (unexpected) fail(resource, `${path}.${unexpected}`, "no unknown fields");
|
|
1988
|
+
}
|
|
1989
|
+
function string(value, resource, path) {
|
|
1990
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
1991
|
+
fail(resource, path, "non-empty string");
|
|
1992
|
+
}
|
|
1993
|
+
return value;
|
|
1994
|
+
}
|
|
1995
|
+
function boundedString(value, maxLength, resource, path, allowEmpty = false) {
|
|
1996
|
+
if (typeof value !== "string" || !allowEmpty && value.length === 0 || value.length > maxLength) {
|
|
1997
|
+
fail(
|
|
1998
|
+
resource,
|
|
1999
|
+
path,
|
|
2000
|
+
`${allowEmpty ? "" : "non-empty "}string of at most ${maxLength} characters`
|
|
2001
|
+
);
|
|
2002
|
+
}
|
|
2003
|
+
return value;
|
|
2004
|
+
}
|
|
2005
|
+
function nullableString(value, resource, path) {
|
|
2006
|
+
if (value !== null && typeof value !== "string") {
|
|
2007
|
+
fail(resource, path, "string or null");
|
|
2008
|
+
}
|
|
2009
|
+
}
|
|
2010
|
+
function cartLineQuantity(value, resource, path) {
|
|
2011
|
+
const quantity = positiveInteger(value, resource, path);
|
|
2012
|
+
if (quantity > MAX_CART_LINE_QUANTITY) {
|
|
2013
|
+
fail(resource, path, `integer between 1 and ${MAX_CART_LINE_QUANTITY}`);
|
|
2014
|
+
}
|
|
2015
|
+
return quantity;
|
|
2016
|
+
}
|
|
2017
|
+
function boolean(value, resource, path) {
|
|
2018
|
+
if (typeof value !== "boolean") fail(resource, path, "boolean");
|
|
2019
|
+
}
|
|
2020
|
+
function safeMinor(value, resource, path) {
|
|
2021
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
2022
|
+
fail(resource, path, "non-negative safe integer");
|
|
2023
|
+
}
|
|
2024
|
+
return value;
|
|
2025
|
+
}
|
|
2026
|
+
function positiveInteger(value, resource, path) {
|
|
2027
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
2028
|
+
fail(resource, path, "positive safe integer");
|
|
2029
|
+
}
|
|
2030
|
+
return value;
|
|
2031
|
+
}
|
|
2032
|
+
function enumValue(value, values, resource, path) {
|
|
2033
|
+
if (typeof value !== "string" || !values.includes(value)) {
|
|
2034
|
+
fail(resource, path, values.join(" | "));
|
|
2035
|
+
}
|
|
2036
|
+
return value;
|
|
2037
|
+
}
|
|
2038
|
+
function timestamp(value, resource, path) {
|
|
2039
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d{2}:\d{2})$/.test(value) || !Number.isFinite(Date.parse(value))) {
|
|
2040
|
+
fail(resource, path, "ISO 8601 timestamp with offset");
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
function currency(value, resource, path) {
|
|
2044
|
+
if (typeof value !== "string" || !/^[A-Z]{3}$/.test(value)) {
|
|
2045
|
+
fail(resource, path, "three-letter uppercase currency code");
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
function array(value, resource, path) {
|
|
2049
|
+
if (!Array.isArray(value)) fail(resource, path, "array");
|
|
2050
|
+
return value;
|
|
2051
|
+
}
|
|
2052
|
+
function optionalNullableNumber(value, resource, path) {
|
|
2053
|
+
if (value !== void 0 && value !== null && typeof value !== "number") {
|
|
2054
|
+
fail(resource, path, "number or null");
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
function validateMediaSize(value, resource, path) {
|
|
2058
|
+
const item = record(value, resource, path);
|
|
2059
|
+
exact(
|
|
2060
|
+
item,
|
|
2061
|
+
[],
|
|
2062
|
+
["width", "height", "mimeType", "filename", "url"],
|
|
2063
|
+
resource,
|
|
2064
|
+
path
|
|
2065
|
+
);
|
|
2066
|
+
optionalNullableNumber(item.width, resource, `${path}.width`);
|
|
2067
|
+
optionalNullableNumber(item.height, resource, `${path}.height`);
|
|
2068
|
+
for (const key of ["mimeType", "filename", "url"]) {
|
|
2069
|
+
if (item[key] !== void 0)
|
|
2070
|
+
nullableString(item[key], resource, `${path}.${key}`);
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
function validateMedia(value, resource, path) {
|
|
2074
|
+
if (typeof value === "string") return;
|
|
2075
|
+
const media = record(value, resource, path);
|
|
2076
|
+
exact(
|
|
2077
|
+
media,
|
|
2078
|
+
[],
|
|
2079
|
+
["id", "alt", "width", "height", "mimeType", "filename", "url", "sizes"],
|
|
2080
|
+
resource,
|
|
2081
|
+
path
|
|
2082
|
+
);
|
|
2083
|
+
if (media.id !== void 0 && media.id !== null && typeof media.id !== "string" && typeof media.id !== "number") {
|
|
2084
|
+
fail(resource, `${path}.id`, "string, number, or null");
|
|
2085
|
+
}
|
|
2086
|
+
for (const key of ["alt", "mimeType", "filename", "url"]) {
|
|
2087
|
+
if (media[key] !== void 0)
|
|
2088
|
+
nullableString(media[key], resource, `${path}.${key}`);
|
|
2089
|
+
}
|
|
2090
|
+
optionalNullableNumber(media.width, resource, `${path}.width`);
|
|
2091
|
+
optionalNullableNumber(media.height, resource, `${path}.height`);
|
|
2092
|
+
if (media.sizes !== void 0) {
|
|
2093
|
+
const sizes = record(media.sizes, resource, `${path}.sizes`);
|
|
2094
|
+
Object.entries(sizes).forEach(
|
|
2095
|
+
([key, size]) => validateMediaSize(size, resource, `${path}.sizes.${key}`)
|
|
2096
|
+
);
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
function validateReference(value, resource, path) {
|
|
2100
|
+
const ref = record(value, resource, path);
|
|
2101
|
+
exact(ref, ["id", "title", "handle", "image"], [], resource, path);
|
|
2102
|
+
string(ref.id, resource, `${path}.id`);
|
|
2103
|
+
string(ref.title, resource, `${path}.title`);
|
|
2104
|
+
if (ref.handle !== null) string(ref.handle, resource, `${path}.handle`);
|
|
2105
|
+
if (ref.image !== null) validateMedia(ref.image, resource, `${path}.image`);
|
|
2106
|
+
}
|
|
2107
|
+
function validateAdmission(value, resource, path) {
|
|
2108
|
+
const admission = record(value, resource, path);
|
|
2109
|
+
exact(
|
|
2110
|
+
admission,
|
|
2111
|
+
["eventId", "occurrenceId", "admissionTypeId"],
|
|
2112
|
+
[],
|
|
2113
|
+
resource,
|
|
2114
|
+
path
|
|
2115
|
+
);
|
|
2116
|
+
string(admission.eventId, resource, `${path}.eventId`);
|
|
2117
|
+
string(admission.occurrenceId, resource, `${path}.occurrenceId`);
|
|
2118
|
+
string(admission.admissionTypeId, resource, `${path}.admissionTypeId`);
|
|
2119
|
+
}
|
|
2120
|
+
function compareAdmissions(left, right) {
|
|
2121
|
+
for (const field of ["eventId", "occurrenceId", "admissionTypeId"]) {
|
|
2122
|
+
if (left[field] < right[field]) return -1;
|
|
2123
|
+
if (left[field] > right[field]) return 1;
|
|
2124
|
+
}
|
|
2125
|
+
return 0;
|
|
2126
|
+
}
|
|
2127
|
+
function validateAdmissions(value, resource, path) {
|
|
2128
|
+
const admissions = array(value, resource, path);
|
|
2129
|
+
if (admissions.length > 32) fail(resource, path, "at most 32 admissions");
|
|
2130
|
+
let prior;
|
|
2131
|
+
admissions.forEach((admission, index) => {
|
|
2132
|
+
validateAdmission(admission, resource, `${path}[${index}]`);
|
|
2133
|
+
const item = admission;
|
|
2134
|
+
const comparison = prior ? compareAdmissions(item, prior) : void 0;
|
|
2135
|
+
if (comparison !== void 0 && comparison <= 0) {
|
|
2136
|
+
fail(resource, `${path}[${index}]`, "unique canonical-sorted admissions");
|
|
2137
|
+
}
|
|
2138
|
+
prior = item;
|
|
2139
|
+
});
|
|
2140
|
+
}
|
|
2141
|
+
function validateAttributes(value, resource, path) {
|
|
2142
|
+
const attributes = array(value, resource, path);
|
|
2143
|
+
if (attributes.length > 50) fail(resource, path, "at most 50 attributes");
|
|
2144
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2145
|
+
attributes.forEach((value2, index) => {
|
|
2146
|
+
const itemPath = `${path}[${index}]`;
|
|
2147
|
+
const attribute = record(value2, resource, itemPath);
|
|
2148
|
+
exact(attribute, ["key", "value"], [], resource, itemPath);
|
|
2149
|
+
const key = string(attribute.key, resource, `${itemPath}.key`);
|
|
2150
|
+
if (key.length > 40 || key.startsWith("__") || keys.has(key)) {
|
|
2151
|
+
fail(
|
|
2152
|
+
resource,
|
|
2153
|
+
`${itemPath}.key`,
|
|
2154
|
+
"unique, non-reserved key of at most 40 characters"
|
|
2155
|
+
);
|
|
2156
|
+
}
|
|
2157
|
+
keys.add(key);
|
|
2158
|
+
if (typeof attribute.value !== "string" || attribute.value.length > 500) {
|
|
2159
|
+
fail(resource, `${itemPath}.value`, "string of at most 500 characters");
|
|
2160
|
+
}
|
|
2161
|
+
});
|
|
2162
|
+
}
|
|
2163
|
+
function validateCustomer(value, resource, path) {
|
|
2164
|
+
const customer = record(value, resource, path);
|
|
2165
|
+
exact(customer, ["email"], ["name", "phone"], resource, path);
|
|
2166
|
+
const email = boundedString(
|
|
2167
|
+
customer.email,
|
|
2168
|
+
MAX_COMMERCE_EMAIL_LENGTH,
|
|
2169
|
+
resource,
|
|
2170
|
+
`${path}.email`
|
|
2171
|
+
);
|
|
2172
|
+
if (!/^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9-]*\.)+[A-Za-z]{2,}$/.test(
|
|
2173
|
+
email
|
|
2174
|
+
)) {
|
|
2175
|
+
fail(resource, `${path}.email`, "email address");
|
|
2176
|
+
}
|
|
2177
|
+
if (customer.name !== void 0)
|
|
2178
|
+
boundedString(
|
|
2179
|
+
customer.name,
|
|
2180
|
+
MAX_COMMERCE_SHORT_TEXT_LENGTH,
|
|
2181
|
+
resource,
|
|
2182
|
+
`${path}.name`
|
|
2183
|
+
);
|
|
2184
|
+
if (customer.phone !== void 0)
|
|
2185
|
+
boundedString(
|
|
2186
|
+
customer.phone,
|
|
2187
|
+
MAX_COMMERCE_PHONE_LENGTH,
|
|
2188
|
+
resource,
|
|
2189
|
+
`${path}.phone`
|
|
2190
|
+
);
|
|
2191
|
+
}
|
|
2192
|
+
function validateShippingAddress(value, resource, path) {
|
|
2193
|
+
const address = record(value, resource, path);
|
|
2194
|
+
exact(
|
|
2195
|
+
address,
|
|
2196
|
+
["recipientName", "phone", "postalCode", "address", "detailAddress"],
|
|
2197
|
+
["countryCode", "regionCode", "deliveryMessage"],
|
|
2198
|
+
resource,
|
|
2199
|
+
path
|
|
2200
|
+
);
|
|
2201
|
+
boundedString(
|
|
2202
|
+
address.recipientName,
|
|
2203
|
+
MAX_COMMERCE_SHORT_TEXT_LENGTH,
|
|
2204
|
+
resource,
|
|
2205
|
+
`${path}.recipientName`
|
|
2206
|
+
);
|
|
2207
|
+
boundedString(
|
|
2208
|
+
address.phone,
|
|
2209
|
+
MAX_COMMERCE_PHONE_LENGTH,
|
|
2210
|
+
resource,
|
|
2211
|
+
`${path}.phone`
|
|
2212
|
+
);
|
|
2213
|
+
boundedString(
|
|
2214
|
+
address.postalCode,
|
|
2215
|
+
MAX_COMMERCE_POSTAL_CODE_LENGTH,
|
|
2216
|
+
resource,
|
|
2217
|
+
`${path}.postalCode`
|
|
2218
|
+
);
|
|
2219
|
+
for (const key of ["address", "detailAddress"]) {
|
|
2220
|
+
boundedString(
|
|
2221
|
+
address[key],
|
|
2222
|
+
MAX_COMMERCE_ADDRESS_LENGTH,
|
|
2223
|
+
resource,
|
|
2224
|
+
`${path}.${key}`
|
|
2225
|
+
);
|
|
2226
|
+
}
|
|
2227
|
+
if (address.countryCode !== void 0) {
|
|
2228
|
+
if (typeof address.countryCode !== "string" || address.countryCode.trim().length !== 2) {
|
|
2229
|
+
fail(resource, `${path}.countryCode`, "two-letter country code");
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
if (address.regionCode !== void 0) {
|
|
2233
|
+
if (typeof address.regionCode !== "string" || address.regionCode.trim().length === 0 || address.regionCode.trim().length > 64) {
|
|
2234
|
+
fail(
|
|
2235
|
+
resource,
|
|
2236
|
+
`${path}.regionCode`,
|
|
2237
|
+
"trimmed string of at most 64 characters"
|
|
2238
|
+
);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
if (address.deliveryMessage !== void 0) {
|
|
2242
|
+
boundedString(
|
|
2243
|
+
address.deliveryMessage,
|
|
2244
|
+
MAX_COMMERCE_EXTENSION_VALUE_LENGTH,
|
|
2245
|
+
resource,
|
|
2246
|
+
`${path}.deliveryMessage`,
|
|
2247
|
+
true
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
function validateOrderReference(value, resource, path) {
|
|
2252
|
+
const order = record(value, resource, path);
|
|
2253
|
+
exact(order, ["id", "orderNumber"], [], resource, path);
|
|
2254
|
+
string(order.id, resource, `${path}.id`);
|
|
2255
|
+
string(order.orderNumber, resource, `${path}.orderNumber`);
|
|
2256
|
+
}
|
|
2257
|
+
function validateIntegrationMetadata(value, resource, path) {
|
|
2258
|
+
const metadata = record(value, resource, path);
|
|
2259
|
+
if (Object.keys(metadata).length > 50)
|
|
2260
|
+
fail(resource, path, "at most 50 entries");
|
|
2261
|
+
Object.entries(metadata).forEach(([key, entry]) => {
|
|
2262
|
+
if (!key || key.length > 40 || key.includes("[") || key.includes("]")) {
|
|
2263
|
+
fail(resource, `${path}.${key}`, "valid metadata key");
|
|
2264
|
+
}
|
|
2265
|
+
if (typeof entry !== "string" || entry.length > 500) {
|
|
2266
|
+
fail(resource, `${path}.${key}`, "string of at most 500 characters");
|
|
2267
|
+
}
|
|
2268
|
+
});
|
|
2269
|
+
}
|
|
2270
|
+
function validateCartItem(value, resource, path) {
|
|
2271
|
+
const item = record(value, resource, path);
|
|
2272
|
+
exact(
|
|
2273
|
+
item,
|
|
2274
|
+
[
|
|
2275
|
+
"id",
|
|
2276
|
+
"product",
|
|
2277
|
+
"variant",
|
|
2278
|
+
"admissions",
|
|
2279
|
+
"quantity",
|
|
2280
|
+
"unitPriceMinor",
|
|
2281
|
+
"discountMinor",
|
|
2282
|
+
"estimatedLineTotalMinor",
|
|
2283
|
+
"requiresShipping"
|
|
2284
|
+
],
|
|
2285
|
+
[],
|
|
2286
|
+
resource,
|
|
2287
|
+
path
|
|
2288
|
+
);
|
|
2289
|
+
string(item.id, resource, `${path}.id`);
|
|
2290
|
+
validateReference(item.product, resource, `${path}.product`);
|
|
2291
|
+
validateReference(item.variant, resource, `${path}.variant`);
|
|
2292
|
+
validateAdmissions(item.admissions, resource, `${path}.admissions`);
|
|
2293
|
+
cartLineQuantity(item.quantity, resource, `${path}.quantity`);
|
|
2294
|
+
const unitPrice = safeMinor(
|
|
2295
|
+
item.unitPriceMinor,
|
|
2296
|
+
resource,
|
|
2297
|
+
`${path}.unitPriceMinor`
|
|
2298
|
+
);
|
|
2299
|
+
const discount = safeMinor(
|
|
2300
|
+
item.discountMinor,
|
|
2301
|
+
resource,
|
|
2302
|
+
`${path}.discountMinor`
|
|
2303
|
+
);
|
|
2304
|
+
const estimatedLineTotal = safeMinor(
|
|
2305
|
+
item.estimatedLineTotalMinor,
|
|
2306
|
+
resource,
|
|
2307
|
+
`${path}.estimatedLineTotalMinor`
|
|
2308
|
+
);
|
|
2309
|
+
const quantity = item.quantity;
|
|
2310
|
+
const expectedLineTotal = BigInt(unitPrice) * BigInt(quantity) - BigInt(discount);
|
|
2311
|
+
if (expectedLineTotal < 0n || BigInt(estimatedLineTotal) !== expectedLineTotal) {
|
|
2312
|
+
fail(
|
|
2313
|
+
resource,
|
|
2314
|
+
`${path}.estimatedLineTotalMinor`,
|
|
2315
|
+
"unitPriceMinor * quantity - discountMinor"
|
|
2316
|
+
);
|
|
2317
|
+
}
|
|
2318
|
+
boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
|
|
2319
|
+
}
|
|
2320
|
+
function validatePublicCart(value, resource = "Cart") {
|
|
2321
|
+
const cart = record(value, resource, "$");
|
|
2322
|
+
exact(
|
|
2323
|
+
cart,
|
|
2324
|
+
[
|
|
2325
|
+
"id",
|
|
2326
|
+
"status",
|
|
2327
|
+
"revision",
|
|
2328
|
+
"currency",
|
|
2329
|
+
"market",
|
|
2330
|
+
"subtotalMinor",
|
|
2331
|
+
"discountMinor",
|
|
2332
|
+
"estimatedTotalMinor",
|
|
2333
|
+
"discountCodes",
|
|
2334
|
+
"attributes",
|
|
2335
|
+
"items",
|
|
2336
|
+
"expiresAt",
|
|
2337
|
+
"createdAt",
|
|
2338
|
+
"updatedAt"
|
|
2339
|
+
],
|
|
2340
|
+
[],
|
|
2341
|
+
resource,
|
|
2342
|
+
"$"
|
|
2343
|
+
);
|
|
2344
|
+
string(cart.id, resource, "$.id");
|
|
2345
|
+
enumValue(cart.status, CART_STATUSES, resource, "$.status");
|
|
2346
|
+
safeMinor(cart.revision, resource, "$.revision");
|
|
2347
|
+
currency(cart.currency, resource, "$.currency");
|
|
2348
|
+
const market = record(cart.market, resource, "$.market");
|
|
2349
|
+
exact(market, ["id", "handle", "name"], [], resource, "$.market");
|
|
2350
|
+
for (const key of ["id", "handle", "name"])
|
|
2351
|
+
string(market[key], resource, `$.market.${key}`);
|
|
2352
|
+
const subtotal = safeMinor(cart.subtotalMinor, resource, "$.subtotalMinor");
|
|
2353
|
+
const discount = safeMinor(cart.discountMinor, resource, "$.discountMinor");
|
|
2354
|
+
const estimatedTotal = safeMinor(
|
|
2355
|
+
cart.estimatedTotalMinor,
|
|
2356
|
+
resource,
|
|
2357
|
+
"$.estimatedTotalMinor"
|
|
2358
|
+
);
|
|
2359
|
+
array(cart.discountCodes, resource, "$.discountCodes").forEach(
|
|
2360
|
+
(value2, index) => {
|
|
2361
|
+
const itemPath = `$.discountCodes[${index}]`;
|
|
2362
|
+
const code = record(value2, resource, itemPath);
|
|
2363
|
+
exact(code, ["code", "applicable"], [], resource, itemPath);
|
|
2364
|
+
boundedString(
|
|
2365
|
+
code.code,
|
|
2366
|
+
MAX_CART_DISCOUNT_CODE_LENGTH,
|
|
2367
|
+
resource,
|
|
2368
|
+
`${itemPath}.code`
|
|
2369
|
+
);
|
|
2370
|
+
boolean(code.applicable, resource, `${itemPath}.applicable`);
|
|
2371
|
+
}
|
|
2372
|
+
);
|
|
2373
|
+
validateAttributes(cart.attributes, resource, "$.attributes");
|
|
2374
|
+
const items = array(cart.items, resource, "$.items");
|
|
2375
|
+
items.forEach(
|
|
2376
|
+
(item, index) => validateCartItem(item, resource, `$.items[${index}]`)
|
|
2377
|
+
);
|
|
2378
|
+
const expectedSubtotal = items.reduce((total, value2) => {
|
|
2379
|
+
const item = value2;
|
|
2380
|
+
return total + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
|
|
2381
|
+
}, 0n);
|
|
2382
|
+
const expectedDiscount = items.reduce((total, value2) => {
|
|
2383
|
+
const item = value2;
|
|
2384
|
+
return total + BigInt(item.discountMinor);
|
|
2385
|
+
}, 0n);
|
|
2386
|
+
if (BigInt(subtotal) !== expectedSubtotal) {
|
|
2387
|
+
fail(resource, "$.subtotalMinor", "sum of undiscounted cart line totals");
|
|
2388
|
+
}
|
|
2389
|
+
if (BigInt(discount) !== expectedDiscount) {
|
|
2390
|
+
fail(resource, "$.discountMinor", "sum of cart line discounts");
|
|
2391
|
+
}
|
|
2392
|
+
if (expectedSubtotal - BigInt(discount) < 0n || BigInt(estimatedTotal) !== expectedSubtotal - BigInt(discount)) {
|
|
2393
|
+
fail(resource, "$.estimatedTotalMinor", "subtotalMinor - discountMinor");
|
|
2394
|
+
}
|
|
2395
|
+
timestamp(cart.expiresAt, resource, "$.expiresAt");
|
|
2396
|
+
timestamp(cart.createdAt, resource, "$.createdAt");
|
|
2397
|
+
timestamp(cart.updatedAt, resource, "$.updatedAt");
|
|
2398
|
+
return value;
|
|
2399
|
+
}
|
|
2400
|
+
function validateWarnings(value, resource, path) {
|
|
2401
|
+
array(value, resource, path).forEach((value2, index) => {
|
|
2402
|
+
const itemPath = `${path}[${index}]`;
|
|
2403
|
+
const warning = record(value2, resource, itemPath);
|
|
2404
|
+
exact(warning, ["code", "message", "target"], [], resource, itemPath);
|
|
2405
|
+
enumValue(warning.code, CART_WARNING_CODES, resource, `${itemPath}.code`);
|
|
2406
|
+
string(warning.message, resource, `${itemPath}.message`);
|
|
2407
|
+
string(warning.target, resource, `${itemPath}.target`);
|
|
2408
|
+
});
|
|
2409
|
+
}
|
|
2410
|
+
function validateCartMutationResult(value) {
|
|
2411
|
+
const result = record(value, "Cart mutation result", "$");
|
|
2412
|
+
exact(result, ["cart", "warnings"], [], "Cart mutation result", "$");
|
|
2413
|
+
validatePublicCart(result.cart);
|
|
2414
|
+
validateWarnings(result.warnings, "Cart mutation result", "$.warnings");
|
|
2415
|
+
return value;
|
|
2416
|
+
}
|
|
2417
|
+
function validateCreateCartResult(value) {
|
|
2418
|
+
const result = record(value, "Cart create result", "$");
|
|
2419
|
+
exact(
|
|
2420
|
+
result,
|
|
2421
|
+
["cart", "warnings", "cartToken"],
|
|
2422
|
+
[],
|
|
2423
|
+
"Cart create result",
|
|
2424
|
+
"$"
|
|
2425
|
+
);
|
|
2426
|
+
const cart = record(result.cart, "Cart create result", "$.cart");
|
|
2427
|
+
validatePublicCart(cart);
|
|
2428
|
+
if (cart.revision !== 0) {
|
|
2429
|
+
fail("Cart create result", "$.cart.revision", "0 for a newly created Cart");
|
|
2430
|
+
}
|
|
2431
|
+
validateWarnings(result.warnings, "Cart create result", "$.warnings");
|
|
2432
|
+
boundedString(
|
|
2433
|
+
result.cartToken,
|
|
2434
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
2435
|
+
"Cart create result",
|
|
2436
|
+
"$.cartToken"
|
|
2437
|
+
);
|
|
2438
|
+
return value;
|
|
2439
|
+
}
|
|
2440
|
+
function validateCartMineResult(value) {
|
|
2441
|
+
const result = record(value, "Cart mine result", "$");
|
|
2442
|
+
exact(result, ["cart", "cartToken"], [], "Cart mine result", "$");
|
|
2443
|
+
if (result.cart === null || result.cartToken === null) {
|
|
2444
|
+
if (result.cart !== null || result.cartToken !== null) {
|
|
2445
|
+
fail("Cart mine result", "$", "cart and cartToken must both be null");
|
|
2446
|
+
}
|
|
2447
|
+
} else {
|
|
2448
|
+
validatePublicCart(result.cart);
|
|
2449
|
+
boundedString(
|
|
2450
|
+
result.cartToken,
|
|
2451
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
2452
|
+
"Cart mine result",
|
|
2453
|
+
"$.cartToken"
|
|
2454
|
+
);
|
|
2455
|
+
}
|
|
2456
|
+
return value;
|
|
2457
|
+
}
|
|
2458
|
+
function validateCartMergeResult(value) {
|
|
2459
|
+
const result = record(value, "Cart merge result", "$");
|
|
2460
|
+
exact(
|
|
2461
|
+
result,
|
|
2462
|
+
["cart", "warnings", "cartToken", "resolution", "merged", "claimed"],
|
|
2463
|
+
[],
|
|
2464
|
+
"Cart merge result",
|
|
2465
|
+
"$"
|
|
2466
|
+
);
|
|
2467
|
+
validatePublicCart(result.cart);
|
|
2468
|
+
validateWarnings(result.warnings, "Cart merge result", "$.warnings");
|
|
2469
|
+
boundedString(
|
|
2470
|
+
result.cartToken,
|
|
2471
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
2472
|
+
"Cart merge result",
|
|
2473
|
+
"$.cartToken"
|
|
2474
|
+
);
|
|
2475
|
+
const resolution = enumValue(
|
|
2476
|
+
result.resolution,
|
|
2477
|
+
["unchanged", "claimed", "merged"],
|
|
2478
|
+
"Cart merge result",
|
|
2479
|
+
"$.resolution"
|
|
2480
|
+
);
|
|
2481
|
+
boolean(result.merged, "Cart merge result", "$.merged");
|
|
2482
|
+
boolean(result.claimed, "Cart merge result", "$.claimed");
|
|
2483
|
+
const expected = resolution === "merged" ? [true, false] : resolution === "claimed" ? [false, true] : [false, false];
|
|
2484
|
+
if (result.merged !== expected[0] || result.claimed !== expected[1]) {
|
|
2485
|
+
fail("Cart merge result", "$", "resolution-consistent merged/claimed flags");
|
|
2486
|
+
}
|
|
2487
|
+
return value;
|
|
2488
|
+
}
|
|
2489
|
+
function validatePublicOrderItem(value, resource, path) {
|
|
2490
|
+
const item = record(value, resource, path);
|
|
2491
|
+
exact(
|
|
2492
|
+
item,
|
|
2493
|
+
[
|
|
2494
|
+
"id",
|
|
2495
|
+
"product",
|
|
2496
|
+
"variant",
|
|
2497
|
+
"productTitle",
|
|
2498
|
+
"variantTitle",
|
|
2499
|
+
"sku",
|
|
2500
|
+
"admissions",
|
|
2501
|
+
"quantity",
|
|
2502
|
+
"unitPriceMinor",
|
|
2503
|
+
"discountMinor",
|
|
2504
|
+
"lineTotalMinor",
|
|
2505
|
+
"requiresShipping"
|
|
2506
|
+
],
|
|
2507
|
+
[],
|
|
2508
|
+
resource,
|
|
2509
|
+
path
|
|
2510
|
+
);
|
|
2511
|
+
string(item.id, resource, `${path}.id`);
|
|
2512
|
+
if (item.product !== null) {
|
|
2513
|
+
validateReference(item.product, resource, `${path}.product`);
|
|
2514
|
+
}
|
|
2515
|
+
if (item.variant !== null) {
|
|
2516
|
+
validateReference(item.variant, resource, `${path}.variant`);
|
|
2517
|
+
}
|
|
2518
|
+
string(item.productTitle, resource, `${path}.productTitle`);
|
|
2519
|
+
nullableString(item.variantTitle, resource, `${path}.variantTitle`);
|
|
2520
|
+
nullableString(item.sku, resource, `${path}.sku`);
|
|
2521
|
+
validateAdmissions(item.admissions, resource, `${path}.admissions`);
|
|
2522
|
+
const quantity = positiveInteger(item.quantity, resource, `${path}.quantity`);
|
|
2523
|
+
const unitPrice = safeMinor(
|
|
2524
|
+
item.unitPriceMinor,
|
|
2525
|
+
resource,
|
|
2526
|
+
`${path}.unitPriceMinor`
|
|
2527
|
+
);
|
|
2528
|
+
const discount = safeMinor(
|
|
2529
|
+
item.discountMinor,
|
|
2530
|
+
resource,
|
|
2531
|
+
`${path}.discountMinor`
|
|
2532
|
+
);
|
|
2533
|
+
const lineTotal = safeMinor(
|
|
2534
|
+
item.lineTotalMinor,
|
|
2535
|
+
resource,
|
|
2536
|
+
`${path}.lineTotalMinor`
|
|
2537
|
+
);
|
|
2538
|
+
const expected = BigInt(unitPrice) * BigInt(quantity) - BigInt(discount);
|
|
2539
|
+
if (expected < 0n || BigInt(lineTotal) !== expected) {
|
|
2540
|
+
fail(
|
|
2541
|
+
resource,
|
|
2542
|
+
`${path}.lineTotalMinor`,
|
|
2543
|
+
"unitPriceMinor * quantity - discountMinor"
|
|
2544
|
+
);
|
|
2545
|
+
}
|
|
2546
|
+
boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
|
|
2547
|
+
}
|
|
2548
|
+
function validatePublicOrderAt(value, resource, path) {
|
|
2549
|
+
const order = record(value, resource, path);
|
|
2550
|
+
exact(
|
|
2551
|
+
order,
|
|
2552
|
+
[
|
|
2553
|
+
"id",
|
|
2554
|
+
"orderNumber",
|
|
2555
|
+
"amounts",
|
|
2556
|
+
"market",
|
|
2557
|
+
"customerSnapshot",
|
|
2558
|
+
"shippingAddress",
|
|
2559
|
+
"attributes",
|
|
2560
|
+
"items",
|
|
2561
|
+
"financialStatus",
|
|
2562
|
+
"fulfillmentStatus",
|
|
2563
|
+
"returnStatus",
|
|
2564
|
+
"confirmationStatus",
|
|
2565
|
+
"primaryDisplayStatus",
|
|
2566
|
+
"placedAt",
|
|
2567
|
+
"createdAt",
|
|
2568
|
+
"updatedAt"
|
|
2569
|
+
],
|
|
2570
|
+
[],
|
|
2571
|
+
resource,
|
|
2572
|
+
path
|
|
2573
|
+
);
|
|
2574
|
+
string(order.id, resource, `${path}.id`);
|
|
2575
|
+
string(order.orderNumber, resource, `${path}.orderNumber`);
|
|
2576
|
+
const amounts = record(order.amounts, resource, `${path}.amounts`);
|
|
2577
|
+
exact(
|
|
2578
|
+
amounts,
|
|
2579
|
+
[
|
|
2580
|
+
"currency",
|
|
2581
|
+
"subtotalMinor",
|
|
2582
|
+
"shippingMinor",
|
|
2583
|
+
"discountMinor",
|
|
2584
|
+
"totalMinor",
|
|
2585
|
+
"refundedMinor",
|
|
2586
|
+
"currentTotalMinor"
|
|
2587
|
+
],
|
|
2588
|
+
[],
|
|
2589
|
+
resource,
|
|
2590
|
+
`${path}.amounts`
|
|
2591
|
+
);
|
|
2592
|
+
currency(amounts.currency, resource, `${path}.amounts.currency`);
|
|
2593
|
+
const subtotal = safeMinor(
|
|
2594
|
+
amounts.subtotalMinor,
|
|
2595
|
+
resource,
|
|
2596
|
+
`${path}.amounts.subtotalMinor`
|
|
2597
|
+
);
|
|
2598
|
+
const shipping = safeMinor(
|
|
2599
|
+
amounts.shippingMinor,
|
|
2600
|
+
resource,
|
|
2601
|
+
`${path}.amounts.shippingMinor`
|
|
2602
|
+
);
|
|
2603
|
+
const discount = safeMinor(
|
|
2604
|
+
amounts.discountMinor,
|
|
2605
|
+
resource,
|
|
2606
|
+
`${path}.amounts.discountMinor`
|
|
2607
|
+
);
|
|
2608
|
+
const total = safeMinor(
|
|
2609
|
+
amounts.totalMinor,
|
|
2610
|
+
resource,
|
|
2611
|
+
`${path}.amounts.totalMinor`
|
|
2612
|
+
);
|
|
2613
|
+
const refunded = safeMinor(
|
|
2614
|
+
amounts.refundedMinor,
|
|
2615
|
+
resource,
|
|
2616
|
+
`${path}.amounts.refundedMinor`
|
|
2617
|
+
);
|
|
2618
|
+
const current = safeMinor(
|
|
2619
|
+
amounts.currentTotalMinor,
|
|
2620
|
+
resource,
|
|
2621
|
+
`${path}.amounts.currentTotalMinor`
|
|
2622
|
+
);
|
|
2623
|
+
const expectedTotal = BigInt(subtotal) + BigInt(shipping) - BigInt(discount);
|
|
2624
|
+
if (expectedTotal < 0n || BigInt(total) !== expectedTotal) {
|
|
2625
|
+
fail(
|
|
2626
|
+
resource,
|
|
2627
|
+
`${path}.amounts.totalMinor`,
|
|
2628
|
+
"subtotalMinor + shippingMinor - discountMinor"
|
|
2629
|
+
);
|
|
2630
|
+
}
|
|
2631
|
+
if (BigInt(total) - BigInt(refunded) < 0n || current !== total - refunded) {
|
|
2632
|
+
fail(
|
|
2633
|
+
resource,
|
|
2634
|
+
`${path}.amounts.currentTotalMinor`,
|
|
2635
|
+
"totalMinor - refundedMinor"
|
|
2636
|
+
);
|
|
2637
|
+
}
|
|
2638
|
+
if (order.market !== null) {
|
|
2639
|
+
const market = record(order.market, resource, `${path}.market`);
|
|
2640
|
+
exact(market, ["id", "handle", "name"], [], resource, `${path}.market`);
|
|
2641
|
+
for (const key of ["id", "handle", "name"]) {
|
|
2642
|
+
string(market[key], resource, `${path}.market.${key}`);
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2645
|
+
validateCustomer(order.customerSnapshot, resource, `${path}.customerSnapshot`);
|
|
2646
|
+
if (order.shippingAddress !== null) {
|
|
2647
|
+
validateShippingAddress(
|
|
2648
|
+
order.shippingAddress,
|
|
2649
|
+
resource,
|
|
2650
|
+
`${path}.shippingAddress`
|
|
2651
|
+
);
|
|
2652
|
+
}
|
|
2653
|
+
validateAttributes(order.attributes, resource, `${path}.attributes`);
|
|
2654
|
+
const items = array(order.items, resource, `${path}.items`);
|
|
2655
|
+
if (items.length === 0) fail(resource, `${path}.items`, "non-empty array");
|
|
2656
|
+
items.forEach(
|
|
2657
|
+
(item, index) => validatePublicOrderItem(item, resource, `${path}.items[${index}]`)
|
|
2658
|
+
);
|
|
2659
|
+
const expectedSubtotal = items.reduce((sum, value2) => {
|
|
2660
|
+
const item = value2;
|
|
2661
|
+
return sum + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
|
|
2662
|
+
}, 0n);
|
|
2663
|
+
const expectedDiscount = items.reduce((sum, value2) => {
|
|
2664
|
+
const item = value2;
|
|
2665
|
+
return sum + BigInt(item.discountMinor);
|
|
2666
|
+
}, 0n);
|
|
2667
|
+
if (BigInt(subtotal) !== expectedSubtotal) {
|
|
2668
|
+
fail(resource, `${path}.amounts.subtotalMinor`, "sum of line subtotals");
|
|
2669
|
+
}
|
|
2670
|
+
if (BigInt(discount) !== expectedDiscount) {
|
|
2671
|
+
fail(resource, `${path}.amounts.discountMinor`, "sum of line discounts");
|
|
2672
|
+
}
|
|
2673
|
+
enumValue(
|
|
2674
|
+
order.financialStatus,
|
|
2675
|
+
ORDER_FINANCIAL_STATUSES,
|
|
2676
|
+
resource,
|
|
2677
|
+
`${path}.financialStatus`
|
|
2678
|
+
);
|
|
2679
|
+
enumValue(
|
|
2680
|
+
order.fulfillmentStatus,
|
|
2681
|
+
ORDER_FULFILLMENT_STATUSES,
|
|
2682
|
+
resource,
|
|
2683
|
+
`${path}.fulfillmentStatus`
|
|
2684
|
+
);
|
|
2685
|
+
enumValue(
|
|
2686
|
+
order.returnStatus,
|
|
2687
|
+
ORDER_RETURN_STATUSES,
|
|
2688
|
+
resource,
|
|
2689
|
+
`${path}.returnStatus`
|
|
2690
|
+
);
|
|
2691
|
+
enumValue(
|
|
2692
|
+
order.confirmationStatus,
|
|
2693
|
+
ORDER_CONFIRMATION_STATUSES,
|
|
2694
|
+
resource,
|
|
2695
|
+
`${path}.confirmationStatus`
|
|
2696
|
+
);
|
|
2697
|
+
enumValue(
|
|
2698
|
+
order.primaryDisplayStatus,
|
|
2699
|
+
ORDER_PRIMARY_DISPLAY_STATUSES,
|
|
2700
|
+
resource,
|
|
2701
|
+
`${path}.primaryDisplayStatus`
|
|
2702
|
+
);
|
|
2703
|
+
timestamp(order.placedAt, resource, `${path}.placedAt`);
|
|
2704
|
+
timestamp(order.createdAt, resource, `${path}.createdAt`);
|
|
2705
|
+
timestamp(order.updatedAt, resource, `${path}.updatedAt`);
|
|
2706
|
+
}
|
|
2707
|
+
function nullablePositiveInteger(value, resource, path) {
|
|
2708
|
+
if (value !== null) positiveInteger(value, resource, path);
|
|
2709
|
+
}
|
|
2710
|
+
function validatePublicOrderList(value) {
|
|
2711
|
+
const resource = "Order list";
|
|
2712
|
+
const result = record(value, resource, "$");
|
|
2713
|
+
exact(
|
|
2714
|
+
result,
|
|
2715
|
+
[
|
|
2716
|
+
"docs",
|
|
2717
|
+
"totalDocs",
|
|
2718
|
+
"limit",
|
|
2719
|
+
"totalPages",
|
|
2720
|
+
"page",
|
|
2721
|
+
"pagingCounter",
|
|
2722
|
+
"hasPrevPage",
|
|
2723
|
+
"hasNextPage",
|
|
2724
|
+
"prevPage",
|
|
2725
|
+
"nextPage"
|
|
2726
|
+
],
|
|
2727
|
+
[],
|
|
2728
|
+
resource,
|
|
2729
|
+
"$"
|
|
2730
|
+
);
|
|
2731
|
+
array(result.docs, resource, "$.docs").forEach(
|
|
2732
|
+
(order, index) => validatePublicOrderAt(order, resource, `$.docs[${index}]`)
|
|
2733
|
+
);
|
|
2734
|
+
safeMinor(result.totalDocs, resource, "$.totalDocs");
|
|
2735
|
+
positiveInteger(result.limit, resource, "$.limit");
|
|
2736
|
+
safeMinor(result.totalPages, resource, "$.totalPages");
|
|
2737
|
+
positiveInteger(result.page, resource, "$.page");
|
|
2738
|
+
positiveInteger(result.pagingCounter, resource, "$.pagingCounter");
|
|
2739
|
+
boolean(result.hasPrevPage, resource, "$.hasPrevPage");
|
|
2740
|
+
boolean(result.hasNextPage, resource, "$.hasNextPage");
|
|
2741
|
+
nullablePositiveInteger(result.prevPage, resource, "$.prevPage");
|
|
2742
|
+
nullablePositiveInteger(result.nextPage, resource, "$.nextPage");
|
|
2743
|
+
return value;
|
|
2744
|
+
}
|
|
2745
|
+
function validateCheckoutItem(value, resource, path) {
|
|
2746
|
+
const item = record(value, resource, path);
|
|
2747
|
+
exact(
|
|
2748
|
+
item,
|
|
2749
|
+
[
|
|
2750
|
+
"id",
|
|
2751
|
+
"product",
|
|
2752
|
+
"variant",
|
|
2753
|
+
"productTitle",
|
|
2754
|
+
"variantTitle",
|
|
2755
|
+
"sku",
|
|
2756
|
+
"admissions",
|
|
2757
|
+
"quantity",
|
|
2758
|
+
"unitPriceMinor",
|
|
2759
|
+
"discountMinor",
|
|
2760
|
+
"lineTotalMinor",
|
|
2761
|
+
"requiresShipping"
|
|
2762
|
+
],
|
|
2763
|
+
[],
|
|
2764
|
+
resource,
|
|
2765
|
+
path
|
|
2766
|
+
);
|
|
2767
|
+
string(item.id, resource, `${path}.id`);
|
|
2768
|
+
validateReference(item.product, resource, `${path}.product`);
|
|
2769
|
+
validateReference(item.variant, resource, `${path}.variant`);
|
|
2770
|
+
string(item.productTitle, resource, `${path}.productTitle`);
|
|
2771
|
+
nullableString(item.variantTitle, resource, `${path}.variantTitle`);
|
|
2772
|
+
nullableString(item.sku, resource, `${path}.sku`);
|
|
2773
|
+
validateAdmissions(item.admissions, resource, `${path}.admissions`);
|
|
2774
|
+
cartLineQuantity(item.quantity, resource, `${path}.quantity`);
|
|
2775
|
+
const unitPrice = safeMinor(
|
|
2776
|
+
item.unitPriceMinor,
|
|
2777
|
+
resource,
|
|
2778
|
+
`${path}.unitPriceMinor`
|
|
2779
|
+
);
|
|
2780
|
+
const discount = safeMinor(
|
|
2781
|
+
item.discountMinor,
|
|
2782
|
+
resource,
|
|
2783
|
+
`${path}.discountMinor`
|
|
2784
|
+
);
|
|
2785
|
+
const lineTotal = safeMinor(
|
|
2786
|
+
item.lineTotalMinor,
|
|
2787
|
+
resource,
|
|
2788
|
+
`${path}.lineTotalMinor`
|
|
2789
|
+
);
|
|
2790
|
+
const expectedLineTotal = BigInt(unitPrice) * BigInt(item.quantity) - BigInt(discount);
|
|
2791
|
+
if (expectedLineTotal < 0n || BigInt(lineTotal) !== expectedLineTotal) {
|
|
2792
|
+
fail(
|
|
2793
|
+
resource,
|
|
2794
|
+
`${path}.lineTotalMinor`,
|
|
2795
|
+
"unitPriceMinor * quantity - discountMinor"
|
|
2796
|
+
);
|
|
2797
|
+
}
|
|
2798
|
+
boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
|
|
2799
|
+
}
|
|
2800
|
+
function validateCheckoutAmounts(value, resource, path) {
|
|
2801
|
+
const amounts = record(value, resource, path);
|
|
2802
|
+
exact(
|
|
2803
|
+
amounts,
|
|
2804
|
+
[
|
|
2805
|
+
"currency",
|
|
2806
|
+
"subtotalMinor",
|
|
2807
|
+
"shippingMinor",
|
|
2808
|
+
"discountMinor",
|
|
2809
|
+
"totalMinor"
|
|
2810
|
+
],
|
|
2811
|
+
[],
|
|
2812
|
+
resource,
|
|
2813
|
+
path
|
|
2814
|
+
);
|
|
2815
|
+
currency(amounts.currency, resource, `${path}.currency`);
|
|
2816
|
+
const subtotal = safeMinor(
|
|
2817
|
+
amounts.subtotalMinor,
|
|
2818
|
+
resource,
|
|
2819
|
+
`${path}.subtotalMinor`
|
|
2820
|
+
);
|
|
2821
|
+
const shipping = safeMinor(
|
|
2822
|
+
amounts.shippingMinor,
|
|
2823
|
+
resource,
|
|
2824
|
+
`${path}.shippingMinor`
|
|
2825
|
+
);
|
|
2826
|
+
const discount = safeMinor(
|
|
2827
|
+
amounts.discountMinor,
|
|
2828
|
+
resource,
|
|
2829
|
+
`${path}.discountMinor`
|
|
2830
|
+
);
|
|
2831
|
+
const total = safeMinor(amounts.totalMinor, resource, `${path}.totalMinor`);
|
|
2832
|
+
if (BigInt(total) !== BigInt(subtotal) + BigInt(shipping) - BigInt(discount)) {
|
|
2833
|
+
fail(
|
|
2834
|
+
resource,
|
|
2835
|
+
`${path}.totalMinor`,
|
|
2836
|
+
"subtotalMinor + shippingMinor - discountMinor"
|
|
2837
|
+
);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
function validatePaymentSessionReference(value, resource, path) {
|
|
2841
|
+
const session = record(value, resource, path);
|
|
2842
|
+
exact(session, ["id", "provider", "providerStatus"], [], resource, path);
|
|
2843
|
+
string(session.id, resource, `${path}.id`);
|
|
2844
|
+
enumValue(session.provider, PAYMENT_PROVIDERS, resource, `${path}.provider`);
|
|
2845
|
+
enumValue(
|
|
2846
|
+
session.providerStatus,
|
|
2847
|
+
PAYMENT_PROVIDER_STATUSES,
|
|
2848
|
+
resource,
|
|
2849
|
+
`${path}.providerStatus`
|
|
2850
|
+
);
|
|
2851
|
+
}
|
|
2852
|
+
function checkoutVariantKeys(status, placedVia) {
|
|
2853
|
+
const base = [
|
|
2854
|
+
"id",
|
|
2855
|
+
"amounts",
|
|
2856
|
+
"items",
|
|
2857
|
+
"customerSnapshot",
|
|
2858
|
+
"shippingAddress",
|
|
2859
|
+
"attributes",
|
|
2860
|
+
"expiresAt",
|
|
2861
|
+
"createdAt",
|
|
2862
|
+
"updatedAt",
|
|
2863
|
+
"status",
|
|
2864
|
+
"paymentState",
|
|
2865
|
+
"order"
|
|
2866
|
+
];
|
|
2867
|
+
if (status === "open") return { required: base, optional: [] };
|
|
2868
|
+
if (status === "abandoned") {
|
|
2869
|
+
return {
|
|
2870
|
+
required: [...base, "abandonedAt", "abandonedReason"],
|
|
2871
|
+
optional: []
|
|
2872
|
+
};
|
|
2873
|
+
}
|
|
2874
|
+
return placedVia === "late_capture" ? {
|
|
2875
|
+
required: [
|
|
2876
|
+
...base,
|
|
2877
|
+
"placedAt",
|
|
2878
|
+
"placedVia",
|
|
2879
|
+
"abandonedAt",
|
|
2880
|
+
"abandonedReason"
|
|
2881
|
+
],
|
|
2882
|
+
optional: []
|
|
2883
|
+
} : { required: [...base, "placedAt"], optional: [] };
|
|
2884
|
+
}
|
|
2885
|
+
function validateCheckoutCore(value, resource, list, server) {
|
|
2886
|
+
const checkout = record(value, resource, "$");
|
|
2887
|
+
const status = enumValue(
|
|
2888
|
+
checkout.status,
|
|
2889
|
+
CHECKOUT_STATUSES,
|
|
2890
|
+
resource,
|
|
2891
|
+
"$.status"
|
|
2892
|
+
);
|
|
2893
|
+
const keys = checkoutVariantKeys(status, checkout.placedVia);
|
|
2894
|
+
if (list) {
|
|
2895
|
+
keys.required = keys.required.filter(
|
|
2896
|
+
(key) => !["items", "shippingAddress", "attributes"].includes(key)
|
|
2897
|
+
);
|
|
2898
|
+
keys.required.push("clientReferenceId");
|
|
2899
|
+
} else if (server) {
|
|
2900
|
+
keys.required.push("clientReferenceId", "integrationMetadata");
|
|
2901
|
+
}
|
|
2902
|
+
exact(checkout, keys.required, keys.optional, resource, "$");
|
|
2903
|
+
string(checkout.id, resource, "$.id");
|
|
2904
|
+
validateCheckoutAmounts(checkout.amounts, resource, "$.amounts");
|
|
2905
|
+
if (!list) {
|
|
2906
|
+
const items = array(checkout.items, resource, "$.items");
|
|
2907
|
+
if (items.length === 0) fail(resource, "$.items", "non-empty array");
|
|
2908
|
+
items.forEach(
|
|
2909
|
+
(item, index) => validateCheckoutItem(item, resource, `$.items[${index}]`)
|
|
2910
|
+
);
|
|
2911
|
+
const expectedSubtotal = items.reduce((total, value2) => {
|
|
2912
|
+
const item = value2;
|
|
2913
|
+
return total + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
|
|
2914
|
+
}, 0n);
|
|
2915
|
+
const expectedDiscount = items.reduce((total, value2) => {
|
|
2916
|
+
const item = value2;
|
|
2917
|
+
return total + BigInt(item.discountMinor);
|
|
2918
|
+
}, 0n);
|
|
2919
|
+
const amounts = checkout.amounts;
|
|
2920
|
+
if (BigInt(amounts.subtotalMinor) !== expectedSubtotal) {
|
|
2921
|
+
fail(
|
|
2922
|
+
resource,
|
|
2923
|
+
"$.amounts.subtotalMinor",
|
|
2924
|
+
"sum of undiscounted checkout line totals"
|
|
2925
|
+
);
|
|
2926
|
+
}
|
|
2927
|
+
if (BigInt(amounts.discountMinor) !== expectedDiscount) {
|
|
2928
|
+
fail(
|
|
2929
|
+
resource,
|
|
2930
|
+
"$.amounts.discountMinor",
|
|
2931
|
+
"sum of checkout line discounts"
|
|
2932
|
+
);
|
|
2933
|
+
}
|
|
2934
|
+
if (checkout.shippingAddress !== null) {
|
|
2935
|
+
validateShippingAddress(
|
|
2936
|
+
checkout.shippingAddress,
|
|
2937
|
+
resource,
|
|
2938
|
+
"$.shippingAddress"
|
|
2939
|
+
);
|
|
2940
|
+
}
|
|
2941
|
+
validateAttributes(checkout.attributes, resource, "$.attributes");
|
|
2942
|
+
}
|
|
2943
|
+
validateCustomer(checkout.customerSnapshot, resource, "$.customerSnapshot");
|
|
2944
|
+
timestamp(checkout.expiresAt, resource, "$.expiresAt");
|
|
2945
|
+
timestamp(checkout.createdAt, resource, "$.createdAt");
|
|
2946
|
+
timestamp(checkout.updatedAt, resource, "$.updatedAt");
|
|
2947
|
+
const paymentState = record(checkout.paymentState, resource, "$.paymentState");
|
|
2948
|
+
exact(paymentState, ["activePaymentSession"], [], resource, "$.paymentState");
|
|
2949
|
+
if (status === "open") {
|
|
2950
|
+
if (paymentState.activePaymentSession !== null) {
|
|
2951
|
+
validatePaymentSessionReference(
|
|
2952
|
+
paymentState.activePaymentSession,
|
|
2953
|
+
resource,
|
|
2954
|
+
"$.paymentState.activePaymentSession"
|
|
2955
|
+
);
|
|
2956
|
+
}
|
|
2957
|
+
if (checkout.order !== null)
|
|
2958
|
+
fail(resource, "$.order", "null for open Checkout");
|
|
2959
|
+
} else {
|
|
2960
|
+
if (paymentState.activePaymentSession !== null) {
|
|
2961
|
+
fail(
|
|
2962
|
+
resource,
|
|
2963
|
+
"$.paymentState.activePaymentSession",
|
|
2964
|
+
"null for spent Checkout"
|
|
2965
|
+
);
|
|
2966
|
+
}
|
|
2967
|
+
if (status === "placed") {
|
|
2968
|
+
timestamp(checkout.placedAt, resource, "$.placedAt");
|
|
2969
|
+
validateOrderReference(checkout.order, resource, "$.order");
|
|
2970
|
+
if (checkout.placedVia !== void 0 && checkout.placedVia !== "late_capture") {
|
|
2971
|
+
fail(resource, "$.placedVia", "late_capture");
|
|
2972
|
+
}
|
|
2973
|
+
if (checkout.placedVia === "late_capture") {
|
|
2974
|
+
timestamp(checkout.abandonedAt, resource, "$.abandonedAt");
|
|
2975
|
+
enumValue(
|
|
2976
|
+
checkout.abandonedReason,
|
|
2977
|
+
ABANDONED_REASONS,
|
|
2978
|
+
resource,
|
|
2979
|
+
"$.abandonedReason"
|
|
2980
|
+
);
|
|
2981
|
+
}
|
|
2982
|
+
} else {
|
|
2983
|
+
timestamp(checkout.abandonedAt, resource, "$.abandonedAt");
|
|
2984
|
+
enumValue(
|
|
2985
|
+
checkout.abandonedReason,
|
|
2986
|
+
ABANDONED_REASONS,
|
|
2987
|
+
resource,
|
|
2988
|
+
"$.abandonedReason"
|
|
2989
|
+
);
|
|
2990
|
+
if (checkout.order !== null)
|
|
2991
|
+
fail(resource, "$.order", "null for abandoned Checkout");
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
if (list || server) {
|
|
2995
|
+
if (checkout.clientReferenceId !== null) {
|
|
2996
|
+
boundedString(
|
|
2997
|
+
checkout.clientReferenceId,
|
|
2998
|
+
MAX_COMMERCE_RESOURCE_ID_LENGTH,
|
|
2999
|
+
resource,
|
|
3000
|
+
"$.clientReferenceId"
|
|
3001
|
+
);
|
|
3002
|
+
}
|
|
3003
|
+
}
|
|
3004
|
+
if (server)
|
|
3005
|
+
validateIntegrationMetadata(
|
|
3006
|
+
checkout.integrationMetadata,
|
|
3007
|
+
resource,
|
|
3008
|
+
"$.integrationMetadata"
|
|
3009
|
+
);
|
|
3010
|
+
}
|
|
3011
|
+
function validatePublicCheckout(value) {
|
|
3012
|
+
validateCheckoutCore(value, "Checkout", false, false);
|
|
3013
|
+
return value;
|
|
3014
|
+
}
|
|
3015
|
+
function validateServerCheckout(value) {
|
|
3016
|
+
validateCheckoutCore(value, "Server Checkout", false, true);
|
|
3017
|
+
return value;
|
|
3018
|
+
}
|
|
3019
|
+
function validateCreateCheckoutResult(value, server) {
|
|
3020
|
+
const resource = server ? "Server Checkout create result" : "Checkout create result";
|
|
3021
|
+
const result = record(value, resource, "$");
|
|
3022
|
+
exact(result, ["checkout", "checkoutToken"], [], resource, "$");
|
|
3023
|
+
if (server) validateServerCheckout(result.checkout);
|
|
3024
|
+
else validatePublicCheckout(result.checkout);
|
|
3025
|
+
boundedString(
|
|
3026
|
+
result.checkoutToken,
|
|
3027
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
3028
|
+
resource,
|
|
3029
|
+
"$.checkoutToken"
|
|
3030
|
+
);
|
|
3031
|
+
return value;
|
|
3032
|
+
}
|
|
3033
|
+
function validateCheckoutQueryResult(value) {
|
|
3034
|
+
const result = record(value, "Checkout query result", "$");
|
|
3035
|
+
exact(
|
|
3036
|
+
result,
|
|
3037
|
+
["data", "hasMore", "nextCursor"],
|
|
3038
|
+
[],
|
|
3039
|
+
"Checkout query result",
|
|
3040
|
+
"$"
|
|
3041
|
+
);
|
|
3042
|
+
array(result.data, "Checkout query result", "$.data").forEach(
|
|
3043
|
+
(item) => validateCheckoutCore(item, "Checkout list item", true, false)
|
|
3044
|
+
);
|
|
3045
|
+
boolean(result.hasMore, "Checkout query result", "$.hasMore");
|
|
3046
|
+
if (result.nextCursor !== null)
|
|
3047
|
+
boundedString(
|
|
3048
|
+
result.nextCursor,
|
|
3049
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
3050
|
+
"Checkout query result",
|
|
3051
|
+
"$.nextCursor"
|
|
3052
|
+
);
|
|
3053
|
+
if (result.hasMore === true && result.nextCursor === null) {
|
|
3054
|
+
fail(
|
|
3055
|
+
"Checkout query result",
|
|
3056
|
+
"$.nextCursor",
|
|
3057
|
+
"non-null when hasMore is true"
|
|
3058
|
+
);
|
|
3059
|
+
}
|
|
3060
|
+
return value;
|
|
3061
|
+
}
|
|
3062
|
+
function validateMoney(value, resource, path) {
|
|
3063
|
+
const money = record(value, resource, path);
|
|
3064
|
+
exact(money, ["amountMinor", "currency"], [], resource, path);
|
|
3065
|
+
safeMinor(money.amountMinor, resource, `${path}.amountMinor`);
|
|
3066
|
+
currency(money.currency, resource, `${path}.currency`);
|
|
3067
|
+
}
|
|
3068
|
+
function validateCaptureEvidence(value, resource, path) {
|
|
3069
|
+
const evidence = record(value, resource, path);
|
|
3070
|
+
exact(evidence, ["amountMinor", "currency", "observedAt"], [], resource, path);
|
|
3071
|
+
safeMinor(evidence.amountMinor, resource, `${path}.amountMinor`);
|
|
3072
|
+
currency(evidence.currency, resource, `${path}.currency`);
|
|
3073
|
+
timestamp(evidence.observedAt, resource, `${path}.observedAt`);
|
|
3074
|
+
}
|
|
3075
|
+
function validateNoReconciliation(value, resource, path) {
|
|
3076
|
+
const reconciliation = record(value, resource, path);
|
|
3077
|
+
exact(reconciliation, ["status"], [], resource, path);
|
|
3078
|
+
if (reconciliation.status !== "none") fail(resource, `${path}.status`, "none");
|
|
3079
|
+
}
|
|
3080
|
+
function validateRequiredReconciliation(value, allowed, resource, path) {
|
|
3081
|
+
const reconciliation = record(value, resource, path);
|
|
3082
|
+
exact(reconciliation, ["status", "reasons"], [], resource, path);
|
|
3083
|
+
if (reconciliation.status !== "required")
|
|
3084
|
+
fail(resource, `${path}.status`, "required");
|
|
3085
|
+
const reasons = array(reconciliation.reasons, resource, `${path}.reasons`);
|
|
3086
|
+
if (reasons.length === 0) fail(resource, `${path}.reasons`, "non-empty array");
|
|
3087
|
+
let previous = -1;
|
|
3088
|
+
reasons.forEach((reason, index) => {
|
|
3089
|
+
const current = allowed.indexOf(reason);
|
|
3090
|
+
if (current < 0 || current <= previous) {
|
|
3091
|
+
fail(
|
|
3092
|
+
resource,
|
|
3093
|
+
`${path}.reasons[${index}]`,
|
|
3094
|
+
"unique canonical-sorted reconciliation reason"
|
|
3095
|
+
);
|
|
3096
|
+
}
|
|
3097
|
+
previous = current;
|
|
3098
|
+
});
|
|
3099
|
+
}
|
|
3100
|
+
function validateNextAction(value, resource, path) {
|
|
3101
|
+
const action = record(value, resource, path);
|
|
3102
|
+
exact(
|
|
3103
|
+
action,
|
|
3104
|
+
[
|
|
3105
|
+
"type",
|
|
3106
|
+
"clientKey",
|
|
3107
|
+
"paymentMethodVariantKey",
|
|
3108
|
+
"agreementVariantKey",
|
|
3109
|
+
"providerOrderId",
|
|
3110
|
+
"providerCustomerKey",
|
|
3111
|
+
"orderName"
|
|
3112
|
+
],
|
|
3113
|
+
["customerName", "customerEmail"],
|
|
3114
|
+
resource,
|
|
3115
|
+
path
|
|
3116
|
+
);
|
|
3117
|
+
if (action.type !== "toss_widget")
|
|
3118
|
+
fail(resource, `${path}.type`, "toss_widget");
|
|
3119
|
+
for (const key of [
|
|
3120
|
+
"clientKey",
|
|
3121
|
+
"paymentMethodVariantKey",
|
|
3122
|
+
"agreementVariantKey"
|
|
3123
|
+
]) {
|
|
3124
|
+
boundedString(action[key], 255, resource, `${path}.${key}`);
|
|
3125
|
+
}
|
|
3126
|
+
string(action.providerOrderId, resource, `${path}.providerOrderId`);
|
|
3127
|
+
string(action.providerCustomerKey, resource, `${path}.providerCustomerKey`);
|
|
3128
|
+
boundedString(
|
|
3129
|
+
action.orderName,
|
|
3130
|
+
MAX_COMMERCE_SHORT_TEXT_LENGTH,
|
|
3131
|
+
resource,
|
|
3132
|
+
`${path}.orderName`
|
|
3133
|
+
);
|
|
3134
|
+
if (!/^[A-Za-z0-9_-]{6,64}$/.test(action.providerOrderId)) {
|
|
3135
|
+
fail(resource, `${path}.providerOrderId`, "valid Toss provider order ID");
|
|
3136
|
+
}
|
|
3137
|
+
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(
|
|
3138
|
+
action.providerCustomerKey
|
|
3139
|
+
)) {
|
|
3140
|
+
fail(resource, `${path}.providerCustomerKey`, "ANONYMOUS or UUIDv4");
|
|
3141
|
+
}
|
|
3142
|
+
if (action.customerName !== void 0)
|
|
3143
|
+
boundedString(
|
|
3144
|
+
action.customerName,
|
|
3145
|
+
MAX_COMMERCE_SHORT_TEXT_LENGTH,
|
|
3146
|
+
resource,
|
|
3147
|
+
`${path}.customerName`
|
|
3148
|
+
);
|
|
3149
|
+
if (action.customerEmail !== void 0)
|
|
3150
|
+
validateCustomer({ email: action.customerEmail }, resource, path);
|
|
3151
|
+
}
|
|
3152
|
+
function validatePublicPaymentSession(value) {
|
|
3153
|
+
const resource = "PaymentSession";
|
|
3154
|
+
const session = record(value, resource, "$");
|
|
3155
|
+
enumValue(session.provider, PAYMENT_PROVIDERS, resource, "$.provider");
|
|
3156
|
+
const status = enumValue(
|
|
3157
|
+
session.providerStatus,
|
|
3158
|
+
PAYMENT_PROVIDER_STATUSES,
|
|
3159
|
+
resource,
|
|
3160
|
+
"$.providerStatus"
|
|
3161
|
+
);
|
|
3162
|
+
const common = [
|
|
3163
|
+
"id",
|
|
3164
|
+
"money",
|
|
3165
|
+
"expiresAt",
|
|
3166
|
+
"sessionRole",
|
|
3167
|
+
"provider",
|
|
3168
|
+
"providerStatus",
|
|
3169
|
+
"presentationStatus",
|
|
3170
|
+
"finalizationStatus",
|
|
3171
|
+
"reconciliation",
|
|
3172
|
+
"order"
|
|
3173
|
+
];
|
|
3174
|
+
const optional = [];
|
|
3175
|
+
if (status === "requires_payment_method" || status === "requires_action")
|
|
3176
|
+
optional.push("nextAction");
|
|
3177
|
+
else if (status === "captured") common.push("providerEvidence");
|
|
3178
|
+
else if (status === "failed") common.push("failure");
|
|
3179
|
+
else if (status === "canceled") common.push("cancellationReason");
|
|
3180
|
+
exact(session, common, optional, resource, "$");
|
|
3181
|
+
string(session.id, resource, "$.id");
|
|
3182
|
+
validateMoney(session.money, resource, "$.money");
|
|
3183
|
+
if (session.expiresAt !== null)
|
|
3184
|
+
timestamp(session.expiresAt, resource, "$.expiresAt");
|
|
3185
|
+
if (status === "requires_payment_method" || status === "requires_action") {
|
|
3186
|
+
if (session.sessionRole === "active") {
|
|
3187
|
+
if (session.presentationStatus !== "actionable" || session.finalizationStatus !== "not_ready") {
|
|
3188
|
+
fail(resource, "$", "actionable active not-ready state");
|
|
3189
|
+
}
|
|
3190
|
+
if (!("nextAction" in session))
|
|
3191
|
+
fail(resource, "$.nextAction", "required field");
|
|
3192
|
+
validateNextAction(session.nextAction, resource, "$.nextAction");
|
|
3193
|
+
} else if (session.sessionRole === "residual") {
|
|
3194
|
+
if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
|
|
3195
|
+
fail(resource, "$", "suppressed residual not-ready state");
|
|
3196
|
+
}
|
|
3197
|
+
if ("nextAction" in session)
|
|
3198
|
+
fail(resource, "$.nextAction", "absent for suppressed state");
|
|
3199
|
+
} else fail(resource, "$.sessionRole", "active | residual");
|
|
3200
|
+
validateNoReconciliation(
|
|
3201
|
+
session.reconciliation,
|
|
3202
|
+
resource,
|
|
3203
|
+
"$.reconciliation"
|
|
3204
|
+
);
|
|
3205
|
+
if (session.order !== null) fail(resource, "$.order", "null");
|
|
3206
|
+
} else if ([
|
|
3207
|
+
"requires_confirmation",
|
|
3208
|
+
"initializing",
|
|
3209
|
+
"processing",
|
|
3210
|
+
"authorized",
|
|
3211
|
+
"canceling"
|
|
3212
|
+
].includes(status)) {
|
|
3213
|
+
enumValue(
|
|
3214
|
+
session.sessionRole,
|
|
3215
|
+
["active", "residual"],
|
|
3216
|
+
resource,
|
|
3217
|
+
"$.sessionRole"
|
|
3218
|
+
);
|
|
3219
|
+
if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
|
|
3220
|
+
fail(resource, "$", "suppressed not-ready state");
|
|
3221
|
+
}
|
|
3222
|
+
validateNoReconciliation(
|
|
3223
|
+
session.reconciliation,
|
|
3224
|
+
resource,
|
|
3225
|
+
"$.reconciliation"
|
|
3226
|
+
);
|
|
3227
|
+
if (session.order !== null) fail(resource, "$.order", "null");
|
|
3228
|
+
} else if (status === "unknown") {
|
|
3229
|
+
enumValue(
|
|
3230
|
+
session.sessionRole,
|
|
3231
|
+
["active", "residual"],
|
|
3232
|
+
resource,
|
|
3233
|
+
"$.sessionRole"
|
|
3234
|
+
);
|
|
3235
|
+
if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
|
|
3236
|
+
fail(resource, "$", "suppressed not-ready state");
|
|
3237
|
+
}
|
|
3238
|
+
validateRequiredReconciliation(
|
|
3239
|
+
session.reconciliation,
|
|
3240
|
+
["provider_outcome_unknown"],
|
|
3241
|
+
resource,
|
|
3242
|
+
"$.reconciliation"
|
|
3243
|
+
);
|
|
3244
|
+
if (session.order !== null) fail(resource, "$.order", "null");
|
|
3245
|
+
} else if (status === "captured") {
|
|
3246
|
+
validateCaptureEvidence(
|
|
3247
|
+
session.providerEvidence,
|
|
3248
|
+
resource,
|
|
3249
|
+
"$.providerEvidence"
|
|
3250
|
+
);
|
|
3251
|
+
if (session.presentationStatus !== "suppressed")
|
|
3252
|
+
fail(resource, "$.presentationStatus", "suppressed");
|
|
3253
|
+
if (session.finalizationStatus === "pending") {
|
|
3254
|
+
enumValue(
|
|
3255
|
+
session.sessionRole,
|
|
3256
|
+
["canonical_candidate", "residual"],
|
|
3257
|
+
resource,
|
|
3258
|
+
"$.sessionRole"
|
|
3259
|
+
);
|
|
3260
|
+
if (session.order !== null)
|
|
3261
|
+
fail(resource, "$.order", "null for pending finalization");
|
|
3262
|
+
const reconciliation = record(
|
|
3263
|
+
session.reconciliation,
|
|
3264
|
+
resource,
|
|
3265
|
+
"$.reconciliation"
|
|
3266
|
+
);
|
|
3267
|
+
if (reconciliation.status === "none")
|
|
3268
|
+
validateNoReconciliation(reconciliation, resource, "$.reconciliation");
|
|
3269
|
+
else
|
|
3270
|
+
validateRequiredReconciliation(
|
|
3271
|
+
reconciliation,
|
|
3272
|
+
[
|
|
3273
|
+
"local_commit_ambiguous",
|
|
3274
|
+
"amount_mismatch",
|
|
3275
|
+
"currency_mismatch",
|
|
3276
|
+
"excess_capture_pending_order"
|
|
3277
|
+
],
|
|
3278
|
+
resource,
|
|
3279
|
+
"$.reconciliation"
|
|
3280
|
+
);
|
|
3281
|
+
} else if (session.finalizationStatus === "committed") {
|
|
3282
|
+
validateOrderReference(session.order, resource, "$.order");
|
|
3283
|
+
const reconciliation = record(
|
|
3284
|
+
session.reconciliation,
|
|
3285
|
+
resource,
|
|
3286
|
+
"$.reconciliation"
|
|
3287
|
+
);
|
|
3288
|
+
if (reconciliation.status === "none") {
|
|
3289
|
+
enumValue(
|
|
3290
|
+
session.sessionRole,
|
|
3291
|
+
["canonical", "historical"],
|
|
3292
|
+
resource,
|
|
3293
|
+
"$.sessionRole"
|
|
3294
|
+
);
|
|
3295
|
+
validateNoReconciliation(reconciliation, resource, "$.reconciliation");
|
|
3296
|
+
} else {
|
|
3297
|
+
enumValue(
|
|
3298
|
+
session.sessionRole,
|
|
3299
|
+
["canonical", "residual"],
|
|
3300
|
+
resource,
|
|
3301
|
+
"$.sessionRole"
|
|
3302
|
+
);
|
|
3303
|
+
validateRequiredReconciliation(
|
|
3304
|
+
reconciliation,
|
|
3305
|
+
[
|
|
3306
|
+
"inventory_unavailable",
|
|
3307
|
+
"admission_unavailable",
|
|
3308
|
+
"amount_mismatch",
|
|
3309
|
+
"currency_mismatch",
|
|
3310
|
+
"excess_capture",
|
|
3311
|
+
"late_capture",
|
|
3312
|
+
"cross_checkout_duplicate"
|
|
3313
|
+
],
|
|
3314
|
+
resource,
|
|
3315
|
+
"$.reconciliation"
|
|
3316
|
+
);
|
|
3317
|
+
}
|
|
3318
|
+
} else fail(resource, "$.finalizationStatus", "pending | committed");
|
|
3319
|
+
} else if (status === "failed") {
|
|
3320
|
+
if (session.sessionRole !== "historical" || session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready" || session.order !== null) {
|
|
3321
|
+
fail(resource, "$", "historical suppressed failed state");
|
|
3322
|
+
}
|
|
3323
|
+
validateNoReconciliation(
|
|
3324
|
+
session.reconciliation,
|
|
3325
|
+
resource,
|
|
3326
|
+
"$.reconciliation"
|
|
3327
|
+
);
|
|
3328
|
+
const failure = record(session.failure, resource, "$.failure");
|
|
3329
|
+
exact(failure, ["reason"], ["message"], resource, "$.failure");
|
|
3330
|
+
enumValue(
|
|
3331
|
+
failure.reason,
|
|
3332
|
+
PAYMENT_FAILURE_REASONS,
|
|
3333
|
+
resource,
|
|
3334
|
+
"$.failure.reason"
|
|
3335
|
+
);
|
|
3336
|
+
if (failure.message !== void 0)
|
|
3337
|
+
string(failure.message, resource, "$.failure.message");
|
|
3338
|
+
} else {
|
|
3339
|
+
if (session.sessionRole !== "historical" || session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready" || session.order !== null) {
|
|
3340
|
+
fail(resource, "$", "historical suppressed canceled state");
|
|
3341
|
+
}
|
|
3342
|
+
validateNoReconciliation(
|
|
3343
|
+
session.reconciliation,
|
|
3344
|
+
resource,
|
|
3345
|
+
"$.reconciliation"
|
|
3346
|
+
);
|
|
3347
|
+
enumValue(
|
|
3348
|
+
session.cancellationReason,
|
|
3349
|
+
["expired", "customer", "operator", "provider"],
|
|
3350
|
+
resource,
|
|
3351
|
+
"$.cancellationReason"
|
|
3352
|
+
);
|
|
3353
|
+
}
|
|
3354
|
+
return value;
|
|
1442
3355
|
}
|
|
1443
|
-
var ContentClient = class {
|
|
1444
|
-
constructor(options) {
|
|
1445
|
-
const api = new PublicContentApi("ContentClient", {
|
|
1446
|
-
publishableKey: options.publishableKey,
|
|
1447
|
-
apiUrl: options.apiUrl,
|
|
1448
|
-
onRequestId: options.onRequestId,
|
|
1449
|
-
requiresCredential: false
|
|
1450
|
-
});
|
|
1451
|
-
this.links = {
|
|
1452
|
-
list: (params) => api.get(linksListPath(params))
|
|
1453
|
-
};
|
|
1454
|
-
this.galleryItems = {
|
|
1455
|
-
list: (params) => api.get(
|
|
1456
|
-
galleryItemsListPath(params)
|
|
1457
|
-
)
|
|
1458
|
-
};
|
|
1459
|
-
}
|
|
1460
|
-
};
|
|
1461
3356
|
|
|
1462
3357
|
// src/core/customer/customer-auth.ts
|
|
1463
3358
|
var DEFAULT_TIMEOUT2 = 15e3;
|
|
@@ -1476,8 +3371,10 @@ var CustomerAuth = class {
|
|
|
1476
3371
|
const persist = options?.persist ?? true;
|
|
1477
3372
|
if (persist) {
|
|
1478
3373
|
const key = typeof persist === "string" ? persist : "customer-token";
|
|
3374
|
+
const refreshKey = `${key}:refresh`;
|
|
1479
3375
|
const isBrowser = typeof window !== "undefined";
|
|
1480
3376
|
this.token = isBrowser ? safeGetItem(key) : null;
|
|
3377
|
+
this.refreshTokenValue = isBrowser ? safeGetItem(refreshKey) : null;
|
|
1481
3378
|
this.onTokenChange = isBrowser ? (token) => {
|
|
1482
3379
|
try {
|
|
1483
3380
|
if (token) localStorage.setItem(key, token);
|
|
@@ -1485,9 +3382,18 @@ var CustomerAuth = class {
|
|
|
1485
3382
|
} catch {
|
|
1486
3383
|
}
|
|
1487
3384
|
} : void 0;
|
|
3385
|
+
this.onRefreshTokenChange = isBrowser ? (refreshToken) => {
|
|
3386
|
+
try {
|
|
3387
|
+
if (refreshToken) localStorage.setItem(refreshKey, refreshToken);
|
|
3388
|
+
else localStorage.removeItem(refreshKey);
|
|
3389
|
+
} catch {
|
|
3390
|
+
}
|
|
3391
|
+
} : void 0;
|
|
1488
3392
|
} else {
|
|
1489
3393
|
this.token = options?.token ?? null;
|
|
3394
|
+
this.refreshTokenValue = options?.refreshToken ?? null;
|
|
1490
3395
|
this.onTokenChange = options?.onTokenChange;
|
|
3396
|
+
this.onRefreshTokenChange = options?.onRefreshTokenChange;
|
|
1491
3397
|
}
|
|
1492
3398
|
}
|
|
1493
3399
|
/**
|
|
@@ -1511,13 +3417,17 @@ var CustomerAuth = class {
|
|
|
1511
3417
|
}
|
|
1512
3418
|
);
|
|
1513
3419
|
this.setToken(result.token);
|
|
3420
|
+
if (result.refreshToken) this.setRefreshToken(result.refreshToken);
|
|
1514
3421
|
return result;
|
|
1515
3422
|
}
|
|
1516
3423
|
/**
|
|
1517
|
-
* Refresh the current token.
|
|
3424
|
+
* Refresh the current token. Uses a refresh token when available, otherwise
|
|
3425
|
+
* falls back to the legacy bearer-token compatibility path.
|
|
1518
3426
|
*/
|
|
1519
3427
|
async refreshToken() {
|
|
1520
|
-
if (!this.token)
|
|
3428
|
+
if (!this.refreshTokenValue && !this.token) {
|
|
3429
|
+
throw new ApiError("Not authenticated", 401);
|
|
3430
|
+
}
|
|
1521
3431
|
if (this.refreshPromise) return this.refreshPromise;
|
|
1522
3432
|
this.refreshPromise = this._doRefreshToken();
|
|
1523
3433
|
try {
|
|
@@ -1527,14 +3437,19 @@ var CustomerAuth = class {
|
|
|
1527
3437
|
}
|
|
1528
3438
|
}
|
|
1529
3439
|
async _doRefreshToken() {
|
|
3440
|
+
const init = this.refreshTokenValue ? {
|
|
3441
|
+
method: "POST",
|
|
3442
|
+
body: JSON.stringify({ refreshToken: this.refreshTokenValue })
|
|
3443
|
+
} : {
|
|
3444
|
+
method: "POST",
|
|
3445
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
3446
|
+
};
|
|
1530
3447
|
const result = await this.requestJson(
|
|
1531
3448
|
"/api/customers/refresh",
|
|
1532
|
-
|
|
1533
|
-
method: "POST",
|
|
1534
|
-
headers: { Authorization: `Bearer ${this.token}` }
|
|
1535
|
-
}
|
|
3449
|
+
init
|
|
1536
3450
|
);
|
|
1537
3451
|
this.setToken(result.token);
|
|
3452
|
+
if (result.refreshToken) this.setRefreshToken(result.refreshToken);
|
|
1538
3453
|
return result;
|
|
1539
3454
|
}
|
|
1540
3455
|
/**
|
|
@@ -1542,6 +3457,7 @@ var CustomerAuth = class {
|
|
|
1542
3457
|
*/
|
|
1543
3458
|
logout() {
|
|
1544
3459
|
this.setToken(null);
|
|
3460
|
+
this.setRefreshToken(null);
|
|
1545
3461
|
}
|
|
1546
3462
|
/**
|
|
1547
3463
|
* Get the current authenticated customer's profile
|
|
@@ -1617,25 +3533,28 @@ var CustomerAuth = class {
|
|
|
1617
3533
|
const params = new URLSearchParams();
|
|
1618
3534
|
if (options?.page) params.set("page", String(options.page));
|
|
1619
3535
|
if (options?.limit) params.set("limit", String(options.limit));
|
|
1620
|
-
if (options?.
|
|
1621
|
-
params.set("
|
|
3536
|
+
if (options?.financialStatus) {
|
|
3537
|
+
params.set("financialStatus", options.financialStatus);
|
|
1622
3538
|
}
|
|
1623
|
-
if (options?.
|
|
1624
|
-
params.set("
|
|
3539
|
+
if (options?.fulfillmentStatus) {
|
|
3540
|
+
params.set("fulfillmentStatus", options.fulfillmentStatus);
|
|
1625
3541
|
}
|
|
1626
3542
|
if (options?.returnStatus) params.set("returnStatus", options.returnStatus);
|
|
3543
|
+
if (options?.confirmationStatus) {
|
|
3544
|
+
params.set("confirmationStatus", options.confirmationStatus);
|
|
3545
|
+
}
|
|
1627
3546
|
if (options?.primaryDisplayStatus) {
|
|
1628
3547
|
params.set("primaryDisplayStatus", options.primaryDisplayStatus);
|
|
1629
3548
|
}
|
|
1630
|
-
if (options?.returnDisplayStatus) {
|
|
1631
|
-
params.set("returnDisplayStatus", options.returnDisplayStatus);
|
|
1632
|
-
}
|
|
1633
|
-
if (options?.status) params.set("status", options.status);
|
|
1634
3549
|
const qs = params.toString();
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
3550
|
+
const result = await this.requestJson(
|
|
3551
|
+
`/api/customers/me/orders${qs ? `?${qs}` : ""}`,
|
|
3552
|
+
{
|
|
3553
|
+
method: "GET",
|
|
3554
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
3555
|
+
}
|
|
3556
|
+
);
|
|
3557
|
+
return validatePublicOrderList(result);
|
|
1639
3558
|
}
|
|
1640
3559
|
/**
|
|
1641
3560
|
* Get the current token (or null if not authenticated)
|
|
@@ -1643,6 +3562,12 @@ var CustomerAuth = class {
|
|
|
1643
3562
|
getToken() {
|
|
1644
3563
|
return this.token;
|
|
1645
3564
|
}
|
|
3565
|
+
/**
|
|
3566
|
+
* Get the current refresh token (or null if unavailable)
|
|
3567
|
+
*/
|
|
3568
|
+
getRefreshToken() {
|
|
3569
|
+
return this.refreshTokenValue;
|
|
3570
|
+
}
|
|
1646
3571
|
/**
|
|
1647
3572
|
* Set the token manually (e.g. from SSR)
|
|
1648
3573
|
*/
|
|
@@ -1650,6 +3575,13 @@ var CustomerAuth = class {
|
|
|
1650
3575
|
this.token = token;
|
|
1651
3576
|
this.onTokenChange?.(token);
|
|
1652
3577
|
}
|
|
3578
|
+
/**
|
|
3579
|
+
* Set the refresh token manually (e.g. from SSR cookie)
|
|
3580
|
+
*/
|
|
3581
|
+
setRefreshToken(refreshToken) {
|
|
3582
|
+
this.refreshTokenValue = refreshToken;
|
|
3583
|
+
this.onRefreshTokenChange?.(refreshToken);
|
|
3584
|
+
}
|
|
1653
3585
|
/**
|
|
1654
3586
|
* Check if the customer is currently authenticated
|
|
1655
3587
|
*/
|
|
@@ -1678,91 +3610,362 @@ var CustomerAuth = class {
|
|
|
1678
3610
|
}
|
|
1679
3611
|
};
|
|
1680
3612
|
|
|
3613
|
+
// src/core/customer/customer-oauth.ts
|
|
3614
|
+
var DEFAULT_SCOPES = ["openid", "profile", "email"];
|
|
3615
|
+
var DEFAULT_TIMEOUT3 = 15e3;
|
|
3616
|
+
function issuerUrl(issuer, path) {
|
|
3617
|
+
const base = resolveApiUrl(issuer);
|
|
3618
|
+
return new URL(path, base.endsWith("/") ? base : `${base}/`).toString();
|
|
3619
|
+
}
|
|
3620
|
+
function randomBase64Url(bytes) {
|
|
3621
|
+
const buffer = new Uint8Array(bytes);
|
|
3622
|
+
crypto.getRandomValues(buffer);
|
|
3623
|
+
let binary = "";
|
|
3624
|
+
for (const value of buffer) {
|
|
3625
|
+
binary += String.fromCharCode(value);
|
|
3626
|
+
}
|
|
3627
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
3628
|
+
}
|
|
3629
|
+
async function sha256Base64Url(value) {
|
|
3630
|
+
const data = new TextEncoder().encode(value);
|
|
3631
|
+
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
3632
|
+
let binary = "";
|
|
3633
|
+
for (const byte of new Uint8Array(digest)) {
|
|
3634
|
+
binary += String.fromCharCode(byte);
|
|
3635
|
+
}
|
|
3636
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
3637
|
+
}
|
|
3638
|
+
function normalizeToken(body) {
|
|
3639
|
+
if (body.token_type !== "Bearer") {
|
|
3640
|
+
throw new Error("Unsupported customer OAuth token type");
|
|
3641
|
+
}
|
|
3642
|
+
return {
|
|
3643
|
+
accessToken: body.access_token,
|
|
3644
|
+
expiresAt: Date.now() + body.expires_in * 1e3,
|
|
3645
|
+
expiresIn: body.expires_in,
|
|
3646
|
+
...body.id_token ? { idToken: body.id_token } : {},
|
|
3647
|
+
refreshToken: body.refresh_token,
|
|
3648
|
+
...body.scope ? { scope: body.scope } : {},
|
|
3649
|
+
tokenType: "Bearer"
|
|
3650
|
+
};
|
|
3651
|
+
}
|
|
3652
|
+
var CustomerOAuth = class {
|
|
3653
|
+
constructor(config) {
|
|
3654
|
+
if (!config.clientId) throw new Error("customer OAuth clientId is required");
|
|
3655
|
+
if (!config.issuer) throw new Error("customer OAuth issuer is required");
|
|
3656
|
+
this.clientId = config.clientId;
|
|
3657
|
+
this.issuer = config.issuer;
|
|
3658
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT3;
|
|
3659
|
+
}
|
|
3660
|
+
async createAuthorizationUrl(input) {
|
|
3661
|
+
const codeVerifier = randomBase64Url(48);
|
|
3662
|
+
const codeChallenge = await sha256Base64Url(codeVerifier);
|
|
3663
|
+
const state = randomBase64Url(32);
|
|
3664
|
+
const nonce = randomBase64Url(32);
|
|
3665
|
+
const scopes = input.scopes ?? DEFAULT_SCOPES;
|
|
3666
|
+
const url = new URL(issuerUrl(this.issuer, "customer-oauth/authorize"));
|
|
3667
|
+
url.searchParams.set("response_type", "code");
|
|
3668
|
+
url.searchParams.set("client_id", this.clientId);
|
|
3669
|
+
url.searchParams.set("redirect_uri", input.redirectUri);
|
|
3670
|
+
url.searchParams.set("scope", scopes.join(" "));
|
|
3671
|
+
url.searchParams.set("state", state);
|
|
3672
|
+
url.searchParams.set("nonce", nonce);
|
|
3673
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
3674
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
3675
|
+
return {
|
|
3676
|
+
authorizationUrl: url.toString(),
|
|
3677
|
+
codeChallenge,
|
|
3678
|
+
codeVerifier,
|
|
3679
|
+
nonce,
|
|
3680
|
+
returnTo: input.returnTo ?? null,
|
|
3681
|
+
state
|
|
3682
|
+
};
|
|
3683
|
+
}
|
|
3684
|
+
parseCallback(callbackUrl, options) {
|
|
3685
|
+
const url = new URL(callbackUrl);
|
|
3686
|
+
const error = url.searchParams.get("error");
|
|
3687
|
+
if (error) {
|
|
3688
|
+
throw new Error(
|
|
3689
|
+
url.searchParams.get("error_description") ?? `OAuth error: ${error}`
|
|
3690
|
+
);
|
|
3691
|
+
}
|
|
3692
|
+
const code = url.searchParams.get("code");
|
|
3693
|
+
const state = url.searchParams.get("state");
|
|
3694
|
+
if (!code || !state) throw new Error("OAuth callback is missing code/state");
|
|
3695
|
+
if (state !== options.expectedState) throw new Error("OAuth state mismatch");
|
|
3696
|
+
return { code, state };
|
|
3697
|
+
}
|
|
3698
|
+
async exchangeCode(input) {
|
|
3699
|
+
const body = new URLSearchParams({
|
|
3700
|
+
client_id: this.clientId,
|
|
3701
|
+
code: input.code,
|
|
3702
|
+
code_verifier: input.codeVerifier,
|
|
3703
|
+
grant_type: "authorization_code",
|
|
3704
|
+
redirect_uri: input.redirectUri
|
|
3705
|
+
});
|
|
3706
|
+
return this.tokenRequest(body);
|
|
3707
|
+
}
|
|
3708
|
+
async refresh(input) {
|
|
3709
|
+
const body = new URLSearchParams({
|
|
3710
|
+
client_id: this.clientId,
|
|
3711
|
+
grant_type: "refresh_token",
|
|
3712
|
+
refresh_token: input.refreshToken
|
|
3713
|
+
});
|
|
3714
|
+
return this.tokenRequest(body);
|
|
3715
|
+
}
|
|
3716
|
+
async logout(input) {
|
|
3717
|
+
const body = { client_id: this.clientId };
|
|
3718
|
+
if (input.refreshToken) body.refresh_token = input.refreshToken;
|
|
3719
|
+
if (input.postLogoutRedirectUri) {
|
|
3720
|
+
body.post_logout_redirect_uri = input.postLogoutRedirectUri;
|
|
3721
|
+
}
|
|
3722
|
+
const response = await httpFetch("/customer-oauth/logout", {
|
|
3723
|
+
apiUrl: this.issuer,
|
|
3724
|
+
method: "POST",
|
|
3725
|
+
body: JSON.stringify(body),
|
|
3726
|
+
headers: { "Content-Type": "application/json" },
|
|
3727
|
+
timeout: this.timeout,
|
|
3728
|
+
retry: { maxRetries: 0 }
|
|
3729
|
+
});
|
|
3730
|
+
return parseApiResponse(
|
|
3731
|
+
response,
|
|
3732
|
+
"/customer-oauth/logout"
|
|
3733
|
+
);
|
|
3734
|
+
}
|
|
3735
|
+
verifyIdToken() {
|
|
3736
|
+
throw new Error(
|
|
3737
|
+
"Customer OAuth ID token verification is not implemented; treat idToken as opaque."
|
|
3738
|
+
);
|
|
3739
|
+
}
|
|
3740
|
+
async tokenRequest(body) {
|
|
3741
|
+
const response = await httpFetch("/api/customer-oauth/token", {
|
|
3742
|
+
apiUrl: this.issuer,
|
|
3743
|
+
method: "POST",
|
|
3744
|
+
body,
|
|
3745
|
+
headers: {
|
|
3746
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
3747
|
+
},
|
|
3748
|
+
timeout: this.timeout,
|
|
3749
|
+
retry: { maxRetries: 0 }
|
|
3750
|
+
});
|
|
3751
|
+
return normalizeToken(
|
|
3752
|
+
await parseApiResponse(
|
|
3753
|
+
response,
|
|
3754
|
+
"/api/customer-oauth/token"
|
|
3755
|
+
)
|
|
3756
|
+
);
|
|
3757
|
+
}
|
|
3758
|
+
};
|
|
3759
|
+
|
|
1681
3760
|
// src/core/customer/customer-namespace.ts
|
|
1682
3761
|
var CustomerNamespace = class {
|
|
1683
3762
|
constructor(publishableKey, options, apiUrl) {
|
|
1684
3763
|
this.auth = new CustomerAuth(publishableKey, options, apiUrl);
|
|
3764
|
+
if (options?.oauth) {
|
|
3765
|
+
this.oauth = new CustomerOAuth(options.oauth);
|
|
3766
|
+
}
|
|
1685
3767
|
}
|
|
1686
3768
|
};
|
|
1687
3769
|
|
|
3770
|
+
// src/core/api/commerce-idempotency.ts
|
|
3771
|
+
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;
|
|
3772
|
+
var PREFIXED_BASE64URL_PATTERN = /^ik_[A-Za-z0-9_-]{22}$/;
|
|
3773
|
+
function isCommerceIdempotencyKey(value) {
|
|
3774
|
+
return typeof value === "string" && value.length <= 255 && (UUID_V4_PATTERN.test(value) || PREFIXED_BASE64URL_PATTERN.test(value));
|
|
3775
|
+
}
|
|
3776
|
+
function assertCommerceIdempotencyKey(value) {
|
|
3777
|
+
if (isCommerceIdempotencyKey(value)) return;
|
|
3778
|
+
throw createValidationError(
|
|
3779
|
+
"idempotencyKey must be a UUIDv4 or ik_-prefixed 128-bit base64url value.",
|
|
3780
|
+
{ field: "idempotencyKey" }
|
|
3781
|
+
);
|
|
3782
|
+
}
|
|
3783
|
+
function createCommerceIdempotencyKey() {
|
|
3784
|
+
return globalThis.crypto.randomUUID();
|
|
3785
|
+
}
|
|
3786
|
+
|
|
1688
3787
|
// src/core/api/cart-api.ts
|
|
3788
|
+
var MAX_CART_LINE_ADMISSIONS = 32;
|
|
1689
3789
|
var CartApi = class extends CustomerScopedApi {
|
|
1690
3790
|
constructor(options) {
|
|
1691
3791
|
super("CartApi", { ...options, requiresCredential: false });
|
|
3792
|
+
this.serverTransport = Boolean(options.secretKey);
|
|
1692
3793
|
}
|
|
1693
|
-
|
|
1694
|
-
return this.
|
|
3794
|
+
endpoint(key) {
|
|
3795
|
+
return this.serverTransport ? COMMERCE_ENDPOINTS.carts.server[key] : COMMERCE_ENDPOINTS.carts[key];
|
|
1695
3796
|
}
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
3797
|
+
execute(endpoint2, body, idempotencyKey) {
|
|
3798
|
+
return this.requestEndpoint(endpoint2, body, {
|
|
3799
|
+
...idempotencyKey && {
|
|
3800
|
+
headers: { "X-Idempotency-Key": idempotencyKey }
|
|
3801
|
+
}
|
|
3802
|
+
});
|
|
1702
3803
|
}
|
|
1703
|
-
|
|
1704
|
-
return this.execute("
|
|
3804
|
+
create(params = {}) {
|
|
3805
|
+
return this.execute(this.endpoint("create"), params).then(
|
|
3806
|
+
(value) => validateCreateCartResult(value)
|
|
3807
|
+
);
|
|
1705
3808
|
}
|
|
1706
|
-
|
|
1707
|
-
return this.execute(
|
|
1708
|
-
|
|
1709
|
-
"POST",
|
|
1710
|
-
params
|
|
3809
|
+
retrieve(params) {
|
|
3810
|
+
return this.execute(this.endpoint("retrieve"), params).then(
|
|
3811
|
+
(value) => validatePublicCart(value)
|
|
1711
3812
|
);
|
|
1712
3813
|
}
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
3814
|
+
mine(params = {}) {
|
|
3815
|
+
const endpoint2 = this.endpoint("mine");
|
|
3816
|
+
return this.execute(endpoint2, params).then(
|
|
3817
|
+
(value) => validateCartMineResult(value)
|
|
3818
|
+
);
|
|
3819
|
+
}
|
|
3820
|
+
merge(params) {
|
|
3821
|
+
const { idempotencyKey, ...body } = params;
|
|
3822
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3823
|
+
const endpoint2 = this.endpoint("merge");
|
|
3824
|
+
return this.execute(endpoint2, body, idempotencyKey).then(
|
|
3825
|
+
(value) => validateCartMergeResult(value)
|
|
1723
3826
|
);
|
|
1724
3827
|
}
|
|
1725
3828
|
addItem(params) {
|
|
1726
|
-
return this.
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
3829
|
+
return this.mutate(this.endpoint("addItem"), params);
|
|
3830
|
+
}
|
|
3831
|
+
mutate(endpoint2, params) {
|
|
3832
|
+
const { idempotencyKey, ...body } = params;
|
|
3833
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3834
|
+
return this.execute(endpoint2, body, idempotencyKey).then(
|
|
3835
|
+
(value) => validateCartMutationResult(value)
|
|
1730
3836
|
);
|
|
1731
3837
|
}
|
|
1732
3838
|
updateItem(params) {
|
|
1733
|
-
return this.
|
|
1734
|
-
COMMERCE_ENDPOINTS.carts.updateItem,
|
|
1735
|
-
"POST",
|
|
1736
|
-
params
|
|
1737
|
-
);
|
|
3839
|
+
return this.mutate(this.endpoint("updateItem"), params);
|
|
1738
3840
|
}
|
|
1739
3841
|
removeItem(params) {
|
|
1740
|
-
return this.
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
3842
|
+
return this.mutate(this.endpoint("removeItem"), params);
|
|
3843
|
+
}
|
|
3844
|
+
clear(params) {
|
|
3845
|
+
return this.mutate(this.endpoint("clear"), params);
|
|
3846
|
+
}
|
|
3847
|
+
updateDiscountCodes(params) {
|
|
3848
|
+
return this.mutate(this.endpoint("updateDiscountCodes"), params);
|
|
3849
|
+
}
|
|
3850
|
+
updateAttributes(params) {
|
|
3851
|
+
return this.mutate(this.endpoint("updateAttributes"), params);
|
|
3852
|
+
}
|
|
3853
|
+
};
|
|
3854
|
+
|
|
3855
|
+
// src/core/api/checkout-api.ts
|
|
3856
|
+
var CheckoutApi = class extends CustomerScopedApi {
|
|
3857
|
+
constructor(options) {
|
|
3858
|
+
super("CheckoutApi", { ...options, requiresCredential: false });
|
|
3859
|
+
}
|
|
3860
|
+
post(endpoint2, body, idempotencyKey) {
|
|
3861
|
+
return this.requestEndpoint(endpoint2, body, {
|
|
3862
|
+
...idempotencyKey && {
|
|
3863
|
+
headers: { "X-Idempotency-Key": idempotencyKey }
|
|
3864
|
+
}
|
|
3865
|
+
});
|
|
3866
|
+
}
|
|
3867
|
+
async publicCheckout(result) {
|
|
3868
|
+
return validatePublicCheckout(await result);
|
|
3869
|
+
}
|
|
3870
|
+
async serverCheckout(result) {
|
|
3871
|
+
return validateServerCheckout(await result);
|
|
3872
|
+
}
|
|
3873
|
+
async createResult(result) {
|
|
3874
|
+
return validateCreateCheckoutResult(
|
|
3875
|
+
await result,
|
|
3876
|
+
false
|
|
1744
3877
|
);
|
|
1745
3878
|
}
|
|
1746
|
-
|
|
1747
|
-
return
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
params
|
|
3879
|
+
async createServerResult(result) {
|
|
3880
|
+
return validateCreateCheckoutResult(
|
|
3881
|
+
await result,
|
|
3882
|
+
true
|
|
1751
3883
|
);
|
|
1752
3884
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
3885
|
+
create(params) {
|
|
3886
|
+
const { idempotencyKey, ...body } = params;
|
|
3887
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3888
|
+
return this.createResult(
|
|
3889
|
+
this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey)
|
|
1758
3890
|
);
|
|
1759
3891
|
}
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
3892
|
+
createServer(params) {
|
|
3893
|
+
const { idempotencyKey, ...body } = params;
|
|
3894
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3895
|
+
return this.createServerResult(
|
|
3896
|
+
this.post(
|
|
3897
|
+
COMMERCE_ENDPOINTS.checkouts.server.create,
|
|
3898
|
+
body,
|
|
3899
|
+
idempotencyKey
|
|
3900
|
+
)
|
|
3901
|
+
);
|
|
3902
|
+
}
|
|
3903
|
+
retrieve(params) {
|
|
3904
|
+
return this.publicCheckout(
|
|
3905
|
+
this.post(COMMERCE_ENDPOINTS.checkouts.retrieve, params)
|
|
3906
|
+
);
|
|
3907
|
+
}
|
|
3908
|
+
retrieveServer(params) {
|
|
3909
|
+
return this.serverCheckout(
|
|
3910
|
+
this.post(COMMERCE_ENDPOINTS.checkouts.server.retrieve, params)
|
|
3911
|
+
);
|
|
3912
|
+
}
|
|
3913
|
+
async query(params = {}) {
|
|
3914
|
+
const result = await this.post(
|
|
3915
|
+
COMMERCE_ENDPOINTS.checkouts.server.query,
|
|
1764
3916
|
params
|
|
1765
3917
|
);
|
|
3918
|
+
return validateCheckoutQueryResult(result);
|
|
3919
|
+
}
|
|
3920
|
+
};
|
|
3921
|
+
|
|
3922
|
+
// src/core/api/payment-session-api.ts
|
|
3923
|
+
var PaymentSessionApi = class extends CustomerScopedApi {
|
|
3924
|
+
constructor(options) {
|
|
3925
|
+
super("PaymentSessionApi", { ...options, requiresCredential: false });
|
|
3926
|
+
this.serverTransport = Boolean(options.secretKey);
|
|
3927
|
+
}
|
|
3928
|
+
post(endpoint2, body, idempotencyKey) {
|
|
3929
|
+
return this.requestEndpoint(endpoint2, body, {
|
|
3930
|
+
...idempotencyKey && {
|
|
3931
|
+
headers: { "X-Idempotency-Key": idempotencyKey }
|
|
3932
|
+
}
|
|
3933
|
+
});
|
|
3934
|
+
}
|
|
3935
|
+
async paymentSession(result) {
|
|
3936
|
+
return validatePublicPaymentSession(await result);
|
|
3937
|
+
}
|
|
3938
|
+
create(params) {
|
|
3939
|
+
const { idempotencyKey, ...body } = params;
|
|
3940
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3941
|
+
return this.paymentSession(
|
|
3942
|
+
this.post(
|
|
3943
|
+
this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.create : COMMERCE_ENDPOINTS.paymentSessions.create,
|
|
3944
|
+
body,
|
|
3945
|
+
idempotencyKey
|
|
3946
|
+
)
|
|
3947
|
+
);
|
|
3948
|
+
}
|
|
3949
|
+
retrieve(params) {
|
|
3950
|
+
const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
|
|
3951
|
+
return this.paymentSession(this.post(endpoint2, params));
|
|
3952
|
+
}
|
|
3953
|
+
cancel(params) {
|
|
3954
|
+
const { idempotencyKey, ...body } = params;
|
|
3955
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3956
|
+
const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
|
|
3957
|
+
return this.paymentSession(this.post(endpoint2, body, idempotencyKey));
|
|
3958
|
+
}
|
|
3959
|
+
confirm(params) {
|
|
3960
|
+
const { idempotencyKey, ...body } = params;
|
|
3961
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3962
|
+
return this.paymentSession(
|
|
3963
|
+
this.post(
|
|
3964
|
+
COMMERCE_ENDPOINTS.paymentSessions.server.confirm,
|
|
3965
|
+
body,
|
|
3966
|
+
idempotencyKey
|
|
3967
|
+
)
|
|
3968
|
+
);
|
|
1766
3969
|
}
|
|
1767
3970
|
};
|
|
1768
3971
|
|
|
@@ -2765,9 +4968,13 @@ function resolveVariantIdForCompleteSelection(matrix, selectedByOptionId) {
|
|
|
2765
4968
|
return getExactSelectedVariantEntry(matrix, normalized, matchingVariantEntries)?.id ?? null;
|
|
2766
4969
|
}
|
|
2767
4970
|
function buildSelectionPrice(variants) {
|
|
2768
|
-
const { min, max } = getMinMax(
|
|
4971
|
+
const { min, max } = getMinMax(
|
|
4972
|
+
variants.map((variant) => variant.resolvedPrice?.amount ?? variant.price)
|
|
4973
|
+
);
|
|
2769
4974
|
const { min: compareAtMin, max: compareAtMax } = getMinMax(
|
|
2770
|
-
variants.map(
|
|
4975
|
+
variants.map(
|
|
4976
|
+
(variant) => variant.resolvedPrice?.compareAtPrice ?? variant.compareAtPrice
|
|
4977
|
+
)
|
|
2771
4978
|
);
|
|
2772
4979
|
return {
|
|
2773
4980
|
min,
|
|
@@ -2827,8 +5034,8 @@ function buildSelectionStock(selectedVariant, matchingVariants) {
|
|
|
2827
5034
|
return {
|
|
2828
5035
|
availableForSale: getVariantAvailableForSale(selectedVariant),
|
|
2829
5036
|
isUnlimited: selectedVariant.isUnlimited,
|
|
2830
|
-
stock: selectedVariant.stock,
|
|
2831
|
-
reservedStock: selectedVariant.reservedStock,
|
|
5037
|
+
stock: "stock" in selectedVariant ? selectedVariant.stock : null,
|
|
5038
|
+
reservedStock: "reservedStock" in selectedVariant ? selectedVariant.reservedStock : null,
|
|
2832
5039
|
availableStock
|
|
2833
5040
|
};
|
|
2834
5041
|
}
|
|
@@ -3210,6 +5417,9 @@ function compareVariantOrder(a, b) {
|
|
|
3210
5417
|
}
|
|
3211
5418
|
function getVariantAvailableForSale(variant) {
|
|
3212
5419
|
if (variant.isActive === false) return false;
|
|
5420
|
+
if (typeof variant.availableForSale === "boolean") {
|
|
5421
|
+
return variant.availableForSale;
|
|
5422
|
+
}
|
|
3213
5423
|
if (variant.isUnlimited) return true;
|
|
3214
5424
|
if (variant.inventoryPolicy === "continue") return true;
|
|
3215
5425
|
return (variant.stock ?? 0) - (variant.reservedStock ?? 0) > 0;
|
|
@@ -3323,7 +5533,7 @@ function buildProductListingCard(item, options = {}) {
|
|
|
3323
5533
|
{ listing: { selectionHintVariant } },
|
|
3324
5534
|
options
|
|
3325
5535
|
),
|
|
3326
|
-
title: product.title,
|
|
5536
|
+
title: product.title ?? "",
|
|
3327
5537
|
representativeVariant,
|
|
3328
5538
|
primaryImage: listingPrimaryMedia,
|
|
3329
5539
|
priceRange,
|
|
@@ -3510,6 +5720,11 @@ function productDetailResultFromError(error) {
|
|
|
3510
5720
|
if (!reason) return void 0;
|
|
3511
5721
|
return { found: false, reason };
|
|
3512
5722
|
}
|
|
5723
|
+
var MARKET_PRICE_QUERY_UNSUPPORTED_MESSAGE = "Market listing pages do not support base price filters or price sorts.";
|
|
5724
|
+
var BASE_PRICE_RANGE_SORT_FIELDS = /* @__PURE__ */ new Set([
|
|
5725
|
+
"priceRange.minVariantPrice.amount",
|
|
5726
|
+
"priceRange.maxVariantPrice.amount"
|
|
5727
|
+
]);
|
|
3513
5728
|
function nonEmpty(values) {
|
|
3514
5729
|
return values?.length ? values : void 0;
|
|
3515
5730
|
}
|
|
@@ -3557,14 +5772,34 @@ function buildProductListingPageWhere(params) {
|
|
|
3557
5772
|
if (clauses.length === 1) return clauses[0];
|
|
3558
5773
|
return { and: clauses };
|
|
3559
5774
|
}
|
|
3560
|
-
function
|
|
5775
|
+
function productListingPageUsesBasePriceSort(sort) {
|
|
5776
|
+
const values = Array.isArray(sort) ? sort : sort ? [sort] : [];
|
|
5777
|
+
return values.some(
|
|
5778
|
+
(value) => BASE_PRICE_RANGE_SORT_FIELDS.has(String(value).replace(/^-/, ""))
|
|
5779
|
+
);
|
|
5780
|
+
}
|
|
5781
|
+
function assertMarketListingPageQuerySupported(params) {
|
|
5782
|
+
if (!params.market?.trim()) return;
|
|
5783
|
+
const priceFilter = params.filters?.price;
|
|
5784
|
+
if (priceFilter?.min != null || priceFilter?.max != null || productListingPageUsesBasePriceSort(params.sort)) {
|
|
5785
|
+
throw new TypeError(MARKET_PRICE_QUERY_UNSUPPORTED_MESSAGE);
|
|
5786
|
+
}
|
|
5787
|
+
}
|
|
5788
|
+
function buildProductListingPageRequest(params) {
|
|
5789
|
+
assertMarketListingPageQuerySupported(params);
|
|
3561
5790
|
const options = {
|
|
5791
|
+
market: params.market,
|
|
5792
|
+
locale: params.locale,
|
|
5793
|
+
fallbackLocale: params.fallbackLocale,
|
|
3562
5794
|
page: params.page,
|
|
3563
5795
|
limit: params.limit,
|
|
3564
5796
|
sort: params.sort,
|
|
3565
5797
|
where: buildProductListingPageWhere(params)
|
|
3566
5798
|
};
|
|
3567
|
-
return
|
|
5799
|
+
return {
|
|
5800
|
+
operation: params.mode === "full" ? COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryGet : COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryCatalog,
|
|
5801
|
+
query: listingPageSearchParams(options)
|
|
5802
|
+
};
|
|
3568
5803
|
}
|
|
3569
5804
|
function withProductListingCards(response, options) {
|
|
3570
5805
|
return {
|
|
@@ -3581,30 +5816,15 @@ function isProductUpsertFieldValidationErrorBody(value) {
|
|
|
3581
5816
|
return typeof body.error === "string" && typeof body.field === "string" && (reason === PRODUCT_UPSERT_UNKNOWN_FIELD_REASON || reason === PRODUCT_UPSERT_READONLY_FIELD_REASON);
|
|
3582
5817
|
}
|
|
3583
5818
|
|
|
3584
|
-
// src/core/api/order-api.ts
|
|
3585
|
-
function idempotencyRequestOptions(idempotencyKey) {
|
|
3586
|
-
return idempotencyKey ? { headers: { "X-Idempotency-Key": idempotencyKey } } : void 0;
|
|
3587
|
-
}
|
|
3588
|
-
function splitIdempotencyKey(params) {
|
|
3589
|
-
const { idempotencyKey, ...body } = params;
|
|
3590
|
-
return { body, idempotencyKey };
|
|
3591
|
-
}
|
|
3592
|
-
|
|
3593
5819
|
// src/core/commerce/commerce-client.ts
|
|
3594
5820
|
var BrowserCommerceApi = class extends CustomerScopedApi {
|
|
3595
|
-
|
|
3596
|
-
return
|
|
3597
|
-
method: "POST",
|
|
3598
|
-
body,
|
|
3599
|
-
headers: requestOptions?.headers
|
|
3600
|
-
});
|
|
3601
|
-
}
|
|
3602
|
-
get(endpoint) {
|
|
3603
|
-
return this.request(endpoint, { method: "GET" });
|
|
5821
|
+
requestEndpoint(endpoint2, body, options) {
|
|
5822
|
+
return super.requestEndpoint(endpoint2, body, options);
|
|
3604
5823
|
}
|
|
3605
5824
|
};
|
|
3606
5825
|
var CommerceClient = class {
|
|
3607
5826
|
constructor(options) {
|
|
5827
|
+
this.market = options.market;
|
|
3608
5828
|
const cartApi = new CartApi({
|
|
3609
5829
|
publishableKey: options.publishableKey,
|
|
3610
5830
|
apiUrl: options.apiUrl,
|
|
@@ -3612,6 +5832,20 @@ var CommerceClient = class {
|
|
|
3612
5832
|
onUnauthorized: options.onUnauthorized,
|
|
3613
5833
|
onRequestId: options.onRequestId
|
|
3614
5834
|
});
|
|
5835
|
+
const checkoutApi = new CheckoutApi({
|
|
5836
|
+
publishableKey: options.publishableKey,
|
|
5837
|
+
apiUrl: options.apiUrl,
|
|
5838
|
+
customerToken: options.customerToken,
|
|
5839
|
+
onUnauthorized: options.onUnauthorized,
|
|
5840
|
+
onRequestId: options.onRequestId
|
|
5841
|
+
});
|
|
5842
|
+
const paymentSessionApi = new PaymentSessionApi({
|
|
5843
|
+
publishableKey: options.publishableKey,
|
|
5844
|
+
apiUrl: options.apiUrl,
|
|
5845
|
+
customerToken: options.customerToken,
|
|
5846
|
+
onUnauthorized: options.onUnauthorized,
|
|
5847
|
+
onRequestId: options.onRequestId
|
|
5848
|
+
});
|
|
3615
5849
|
const api = new BrowserCommerceApi("CommerceClient", {
|
|
3616
5850
|
publishableKey: options.publishableKey,
|
|
3617
5851
|
apiUrl: options.apiUrl,
|
|
@@ -3620,29 +5854,42 @@ var CommerceClient = class {
|
|
|
3620
5854
|
onRequestId: options.onRequestId
|
|
3621
5855
|
});
|
|
3622
5856
|
this.product = {
|
|
3623
|
-
stockCheck: (params) => api.
|
|
3624
|
-
|
|
5857
|
+
stockCheck: (params) => api.requestEndpoint(
|
|
5858
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.stockCheck,
|
|
3625
5859
|
params
|
|
3626
5860
|
),
|
|
3627
|
-
stockSnapshot: (params) => api.
|
|
3628
|
-
|
|
3629
|
-
|
|
5861
|
+
stockSnapshot: (params) => api.requestEndpoint(
|
|
5862
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.stockSnapshot,
|
|
5863
|
+
void 0,
|
|
5864
|
+
{ query: stockSnapshotSearchParams(params) }
|
|
5865
|
+
),
|
|
5866
|
+
listingGroups: (params) => api.requestEndpoint(
|
|
5867
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog,
|
|
5868
|
+
void 0,
|
|
5869
|
+
{ query: listingGroupsSearchParams(this.withMarket(params)) }
|
|
3630
5870
|
),
|
|
3631
|
-
listingGroupsCatalog: (params) => api.
|
|
3632
|
-
|
|
5871
|
+
listingGroupsCatalog: (params) => api.requestEndpoint(
|
|
5872
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog,
|
|
5873
|
+
void 0,
|
|
5874
|
+
{ query: listingGroupsSearchParams(this.withMarket(params)) }
|
|
3633
5875
|
),
|
|
3634
5876
|
listingPage: async (params = {}) => {
|
|
3635
5877
|
const catalogParams = {
|
|
3636
5878
|
...params,
|
|
3637
5879
|
mode: "catalog"
|
|
3638
5880
|
};
|
|
3639
|
-
const
|
|
3640
|
-
|
|
5881
|
+
const request = buildProductListingPageRequest(
|
|
5882
|
+
this.withMarket(catalogParams)
|
|
5883
|
+
);
|
|
5884
|
+
const response = await api.requestEndpoint(request.operation, void 0, { query: request.query });
|
|
5885
|
+
return withProductListingCards(response, this.withMarket(catalogParams));
|
|
3641
5886
|
},
|
|
3642
5887
|
detail: async (params) => {
|
|
3643
5888
|
try {
|
|
3644
|
-
const product = await api.
|
|
3645
|
-
|
|
5889
|
+
const product = await api.requestEndpoint(
|
|
5890
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog,
|
|
5891
|
+
void 0,
|
|
5892
|
+
{ query: productDetailSearchParams(this.withMarket(params)) }
|
|
3646
5893
|
);
|
|
3647
5894
|
return { found: true, product };
|
|
3648
5895
|
} catch (err) {
|
|
@@ -3653,8 +5900,10 @@ var CommerceClient = class {
|
|
|
3653
5900
|
},
|
|
3654
5901
|
detailCatalog: async (params) => {
|
|
3655
5902
|
try {
|
|
3656
|
-
const product = await api.
|
|
3657
|
-
|
|
5903
|
+
const product = await api.requestEndpoint(
|
|
5904
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog,
|
|
5905
|
+
void 0,
|
|
5906
|
+
{ query: productDetailSearchParams(this.withMarket(params)) }
|
|
3658
5907
|
);
|
|
3659
5908
|
return { found: true, product };
|
|
3660
5909
|
} catch (err) {
|
|
@@ -3664,39 +5913,51 @@ var CommerceClient = class {
|
|
|
3664
5913
|
}
|
|
3665
5914
|
}
|
|
3666
5915
|
};
|
|
3667
|
-
this.
|
|
3668
|
-
create: cartApi.
|
|
3669
|
-
|
|
5916
|
+
this.carts = {
|
|
5917
|
+
create: (params) => cartApi.create(this.withMarket(params ?? {})),
|
|
5918
|
+
retrieve: cartApi.retrieve.bind(cartApi),
|
|
3670
5919
|
addItem: cartApi.addItem.bind(cartApi),
|
|
3671
5920
|
updateItem: cartApi.updateItem.bind(cartApi),
|
|
3672
5921
|
removeItem: cartApi.removeItem.bind(cartApi),
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
clear: cartApi.
|
|
5922
|
+
updateDiscountCodes: cartApi.updateDiscountCodes.bind(cartApi),
|
|
5923
|
+
updateAttributes: cartApi.updateAttributes.bind(cartApi),
|
|
5924
|
+
clear: cartApi.clear.bind(cartApi),
|
|
3676
5925
|
merge: cartApi.merge.bind(cartApi),
|
|
3677
5926
|
mine: cartApi.mine.bind(cartApi)
|
|
3678
5927
|
};
|
|
3679
5928
|
this.orders = {
|
|
3680
|
-
checkout: (params) => {
|
|
3681
|
-
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
3682
|
-
return api.post(
|
|
3683
|
-
"/api/orders/checkout",
|
|
3684
|
-
body,
|
|
3685
|
-
idempotencyRequestOptions(idempotencyKey)
|
|
3686
|
-
);
|
|
3687
|
-
},
|
|
3688
5929
|
listMine: (params) => options.customerAuth.getMyOrders(params)
|
|
3689
5930
|
};
|
|
5931
|
+
this.checkouts = {
|
|
5932
|
+
create: checkoutApi.create.bind(checkoutApi),
|
|
5933
|
+
retrieve: checkoutApi.retrieve.bind(checkoutApi)
|
|
5934
|
+
};
|
|
5935
|
+
this.paymentSessions = {
|
|
5936
|
+
create: paymentSessionApi.create.bind(paymentSessionApi),
|
|
5937
|
+
retrieve: (params) => paymentSessionApi.retrieve(params),
|
|
5938
|
+
cancel: (params) => paymentSessionApi.cancel(params)
|
|
5939
|
+
};
|
|
3690
5940
|
this.discounts = {
|
|
3691
|
-
validate: (params) => api.
|
|
5941
|
+
validate: (params) => api.requestEndpoint(
|
|
5942
|
+
COMMERCE_ENDPOINT_OPERATIONS.discounts.validate,
|
|
5943
|
+
params
|
|
5944
|
+
)
|
|
3692
5945
|
};
|
|
3693
5946
|
this.shipping = {
|
|
3694
|
-
calculate: (params) => api.
|
|
3695
|
-
|
|
5947
|
+
calculate: (params) => api.requestEndpoint(
|
|
5948
|
+
COMMERCE_ENDPOINT_OPERATIONS.shippingPolicies.calculate,
|
|
3696
5949
|
params
|
|
3697
5950
|
)
|
|
3698
5951
|
};
|
|
3699
5952
|
}
|
|
5953
|
+
getDefaultMarket() {
|
|
5954
|
+
return this.market;
|
|
5955
|
+
}
|
|
5956
|
+
withMarket(params) {
|
|
5957
|
+
const defaultMarket = this.market?.trim();
|
|
5958
|
+
if (!defaultMarket || params.market?.trim()) return params;
|
|
5959
|
+
return { ...params, market: defaultMarket };
|
|
5960
|
+
}
|
|
3700
5961
|
};
|
|
3701
5962
|
|
|
3702
5963
|
// src/core/events/events-client.ts
|
|
@@ -3716,7 +5977,17 @@ var EventsClient = class {
|
|
|
3716
5977
|
getRange(params) {
|
|
3717
5978
|
return this.execute(
|
|
3718
5979
|
buildRangeEndpoint(params),
|
|
3719
|
-
|
|
5980
|
+
resolveOperationMethod(EVENTS_ENDPOINT_OPERATIONS.occurrences.range),
|
|
5981
|
+
void 0,
|
|
5982
|
+
{ useCustomerAuth: false }
|
|
5983
|
+
);
|
|
5984
|
+
}
|
|
5985
|
+
getAdmissionAvailability(params) {
|
|
5986
|
+
return this.execute(
|
|
5987
|
+
buildAdmissionAvailabilityEndpoint(params),
|
|
5988
|
+
resolveOperationMethod(
|
|
5989
|
+
EVENTS_ENDPOINT_OPERATIONS.occurrences.admissionAvailability
|
|
5990
|
+
),
|
|
3720
5991
|
void 0,
|
|
3721
5992
|
{ useCustomerAuth: false }
|
|
3722
5993
|
);
|
|
@@ -3745,11 +6016,11 @@ var EventsClient = class {
|
|
|
3745
6016
|
{ useCustomerAuth: false }
|
|
3746
6017
|
);
|
|
3747
6018
|
}
|
|
3748
|
-
async execute(
|
|
6019
|
+
async execute(endpoint2, method, body, options = {}) {
|
|
3749
6020
|
const useCustomerAuth = options.useCustomerAuth === true;
|
|
3750
6021
|
const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
|
|
3751
6022
|
try {
|
|
3752
|
-
const response = await httpFetch(
|
|
6023
|
+
const response = await httpFetch(endpoint2, {
|
|
3753
6024
|
method,
|
|
3754
6025
|
apiUrl: this.apiUrl,
|
|
3755
6026
|
publishableKey: this.publishableKey,
|
|
@@ -3758,7 +6029,7 @@ var EventsClient = class {
|
|
|
3758
6029
|
...body !== void 0 && { body: JSON.stringify(body) }
|
|
3759
6030
|
});
|
|
3760
6031
|
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
3761
|
-
return parseApiResponse(response,
|
|
6032
|
+
return parseApiResponse(response, endpoint2);
|
|
3762
6033
|
} catch (err) {
|
|
3763
6034
|
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
3764
6035
|
this.onRequestId?.(id);
|
|
@@ -3797,7 +6068,17 @@ function buildRangeEndpoint(params) {
|
|
|
3797
6068
|
appendValues(urlParams, "categorySlug", params.categorySlug);
|
|
3798
6069
|
appendValues(urlParams, "tag", params.tag);
|
|
3799
6070
|
appendValues(urlParams, "tagSlug", params.tagSlug);
|
|
3800
|
-
return
|
|
6071
|
+
return resolveOperationPath(EVENTS_ENDPOINT_OPERATIONS.occurrences.range, {
|
|
6072
|
+
query: urlParams
|
|
6073
|
+
});
|
|
6074
|
+
}
|
|
6075
|
+
function buildAdmissionAvailabilityEndpoint(params) {
|
|
6076
|
+
const urlParams = new URLSearchParams();
|
|
6077
|
+
urlParams.set("occurrence", params.occurrence);
|
|
6078
|
+
return resolveOperationPath(
|
|
6079
|
+
EVENTS_ENDPOINT_OPERATIONS.occurrences.admissionAvailability,
|
|
6080
|
+
{ query: urlParams }
|
|
6081
|
+
);
|
|
3801
6082
|
}
|
|
3802
6083
|
function formatDateParam(value) {
|
|
3803
6084
|
return value instanceof Date ? value.toISOString() : value;
|
|
@@ -3810,15 +6091,62 @@ function appendValues(params, key, value) {
|
|
|
3810
6091
|
}
|
|
3811
6092
|
}
|
|
3812
6093
|
|
|
6094
|
+
// src/core/market/market-discovery.ts
|
|
6095
|
+
function toMarketDTO(row) {
|
|
6096
|
+
return {
|
|
6097
|
+
id: row.id,
|
|
6098
|
+
handle: row.handle,
|
|
6099
|
+
name: row.name,
|
|
6100
|
+
countryCode: row.countryCode,
|
|
6101
|
+
targetCountries: (row.targetCountries ?? []).map((c) => c.countryCode),
|
|
6102
|
+
currency: row.currency,
|
|
6103
|
+
isPrimary: row.isPrimary === true,
|
|
6104
|
+
isActive: row.isActive === true
|
|
6105
|
+
};
|
|
6106
|
+
}
|
|
6107
|
+
var MarketDiscovery = class {
|
|
6108
|
+
constructor(read) {
|
|
6109
|
+
this.read = read;
|
|
6110
|
+
}
|
|
6111
|
+
async list() {
|
|
6112
|
+
const res = await this.read({
|
|
6113
|
+
where: { isActive: { equals: true } },
|
|
6114
|
+
limit: 100
|
|
6115
|
+
});
|
|
6116
|
+
if (res.hasNextPage) {
|
|
6117
|
+
console.warn(
|
|
6118
|
+
"[markets.list] more than 100 active markets; results truncated to 100."
|
|
6119
|
+
);
|
|
6120
|
+
}
|
|
6121
|
+
return res.docs.map(toMarketDTO);
|
|
6122
|
+
}
|
|
6123
|
+
async default() {
|
|
6124
|
+
const res = await this.read({
|
|
6125
|
+
where: { isPrimary: { equals: true }, isActive: { equals: true } },
|
|
6126
|
+
limit: 1
|
|
6127
|
+
});
|
|
6128
|
+
const row = res.docs[0];
|
|
6129
|
+
return row ? toMarketDTO(row) : null;
|
|
6130
|
+
}
|
|
6131
|
+
};
|
|
6132
|
+
|
|
3813
6133
|
// src/core/client/client.ts
|
|
3814
6134
|
var BrowserMembershipApi = class extends CustomerScopedApi {
|
|
3815
6135
|
me() {
|
|
3816
|
-
return this.
|
|
3817
|
-
|
|
3818
|
-
|
|
6136
|
+
return this.requestEndpoint(
|
|
6137
|
+
MEMBERSHIP_ENDPOINT_OPERATIONS.me
|
|
6138
|
+
);
|
|
6139
|
+
}
|
|
6140
|
+
cancel(params) {
|
|
6141
|
+
const { id, immediate } = params;
|
|
6142
|
+
return this.requestEndpoint(
|
|
6143
|
+
MEMBERSHIP_ENDPOINT_OPERATIONS.cancel,
|
|
6144
|
+
immediate !== void 0 ? { immediate } : {},
|
|
6145
|
+
{ pathParams: { id } }
|
|
6146
|
+
);
|
|
3819
6147
|
}
|
|
3820
6148
|
};
|
|
3821
|
-
var Client = class {
|
|
6149
|
+
var Client = class _Client {
|
|
3822
6150
|
constructor(options) {
|
|
3823
6151
|
this.lastRequestId = null;
|
|
3824
6152
|
const publishableKey = options.publishableKey;
|
|
@@ -3850,6 +6178,7 @@ var Client = class {
|
|
|
3850
6178
|
this.commerce = new CommerceClient({
|
|
3851
6179
|
publishableKey: this.config.publishableKey,
|
|
3852
6180
|
apiUrl: this.config.apiUrl,
|
|
6181
|
+
market: this.config.market,
|
|
3853
6182
|
customerToken: () => this.customer.auth.getToken(),
|
|
3854
6183
|
onUnauthorized,
|
|
3855
6184
|
onRequestId,
|
|
@@ -3882,6 +6211,9 @@ var Client = class {
|
|
|
3882
6211
|
onRequestId,
|
|
3883
6212
|
this.config.apiUrl
|
|
3884
6213
|
);
|
|
6214
|
+
this.markets = new MarketDiscovery(
|
|
6215
|
+
(options2) => this.collections.from("markets").find(options2)
|
|
6216
|
+
);
|
|
3885
6217
|
const membershipApi = new BrowserMembershipApi("MembershipApi", {
|
|
3886
6218
|
publishableKey: this.config.publishableKey,
|
|
3887
6219
|
apiUrl: this.config.apiUrl,
|
|
@@ -3890,12 +6222,23 @@ var Client = class {
|
|
|
3890
6222
|
onRequestId
|
|
3891
6223
|
});
|
|
3892
6224
|
this.memberships = {
|
|
3893
|
-
me: membershipApi.me.bind(membershipApi)
|
|
6225
|
+
me: membershipApi.me.bind(membershipApi),
|
|
6226
|
+
cancel: membershipApi.cancel.bind(membershipApi)
|
|
3894
6227
|
};
|
|
3895
6228
|
}
|
|
3896
6229
|
getState() {
|
|
3897
6230
|
return { ...this.state };
|
|
3898
6231
|
}
|
|
6232
|
+
withMarket(market) {
|
|
6233
|
+
return new _Client({
|
|
6234
|
+
...this.config,
|
|
6235
|
+
customer: this.config.customer?.persist === false ? {
|
|
6236
|
+
...this.config.customer,
|
|
6237
|
+
token: this.customer.auth.getToken() ?? void 0
|
|
6238
|
+
} : this.config.customer,
|
|
6239
|
+
market
|
|
6240
|
+
});
|
|
6241
|
+
}
|
|
3899
6242
|
getConfig() {
|
|
3900
6243
|
return { ...this.config };
|
|
3901
6244
|
}
|
|
@@ -3961,6 +6304,7 @@ var COMMERCE_NOTIFICATION_EVENTS = [
|
|
|
3961
6304
|
"returnRequested",
|
|
3962
6305
|
"returnApproved",
|
|
3963
6306
|
"returnRejected",
|
|
6307
|
+
"returnCanceled",
|
|
3964
6308
|
"returnCompleted"
|
|
3965
6309
|
];
|
|
3966
6310
|
function isStringOrNumber(value) {
|
|
@@ -4049,7 +6393,7 @@ function isCommerceNotificationWebhookEvent(event) {
|
|
|
4049
6393
|
if (notification.event === "fulfillmentShipped") {
|
|
4050
6394
|
return sourceCollection === "fulfillments" && matchesOptionalId(data.fulfillmentId, sourceId) && typeof notification.fulfillmentId === "string" && notification.fulfillmentId.length > 0 && matchesOptionalId(notification.fulfillmentId, sourceId) && matchesOptionalId(data.fulfillmentId, notification.fulfillmentId) && matchesOptionalId(changeSourceId, notification.fulfillmentId);
|
|
4051
6395
|
}
|
|
4052
|
-
if (notification.event === "returnRequested" || notification.event === "returnApproved" || notification.event === "returnRejected" || notification.event === "returnCompleted") {
|
|
6396
|
+
if (notification.event === "returnRequested" || notification.event === "returnApproved" || notification.event === "returnRejected" || notification.event === "returnCanceled" || notification.event === "returnCompleted") {
|
|
4053
6397
|
return sourceCollection === "returns" && matchesOptionalId(data.returnId, sourceId) && typeof notification.returnId === "string" && notification.returnId.length > 0 && matchesOptionalId(notification.returnId, sourceId) && matchesOptionalId(data.returnId, notification.returnId) && matchesOptionalId(changeSourceId, notification.returnId);
|
|
4054
6398
|
}
|
|
4055
6399
|
return false;
|
|
@@ -4083,8 +6427,8 @@ function createCommerceEmailWebhookHandler(handlers) {
|
|
|
4083
6427
|
function isWebhookCollection(event, collection) {
|
|
4084
6428
|
return isValidWebhookEvent(event) && event.collection === collection;
|
|
4085
6429
|
}
|
|
4086
|
-
function isWebhookOperation(event,
|
|
4087
|
-
return isValidWebhookEvent(event) && event.operation ===
|
|
6430
|
+
function isWebhookOperation(event, operation2) {
|
|
6431
|
+
return isValidWebhookEvent(event) && event.operation === operation2;
|
|
4088
6432
|
}
|
|
4089
6433
|
var CUSTOMER_PASSWORD_RESET_OPERATION = "password-reset";
|
|
4090
6434
|
function isRecord2(value) {
|
|
@@ -4111,7 +6455,7 @@ function createCustomerAuthWebhookHandler(handlers) {
|
|
|
4111
6455
|
await handlers.unhandled?.(event);
|
|
4112
6456
|
};
|
|
4113
6457
|
}
|
|
4114
|
-
async function verifySignature(payload, secret, signature,
|
|
6458
|
+
async function verifySignature(payload, secret, signature, timestamp2, deliveryId) {
|
|
4115
6459
|
const encoder = new TextEncoder();
|
|
4116
6460
|
const key = await crypto.subtle.importKey(
|
|
4117
6461
|
"raw",
|
|
@@ -4130,12 +6474,12 @@ async function verifySignature(payload, secret, signature, timestamp, deliveryId
|
|
|
4130
6474
|
"HMAC",
|
|
4131
6475
|
key,
|
|
4132
6476
|
sigBytes,
|
|
4133
|
-
encoder.encode(`${
|
|
6477
|
+
encoder.encode(`${timestamp2}.${deliveryId}.${payload}`)
|
|
4134
6478
|
);
|
|
4135
6479
|
}
|
|
4136
|
-
function timestampIsFresh(
|
|
4137
|
-
if (!/^\d+$/.test(
|
|
4138
|
-
const timestampMs = Number(
|
|
6480
|
+
function timestampIsFresh(timestamp2, toleranceSeconds) {
|
|
6481
|
+
if (!/^\d+$/.test(timestamp2)) return false;
|
|
6482
|
+
const timestampMs = Number(timestamp2);
|
|
4139
6483
|
if (!Number.isFinite(timestampMs)) return false;
|
|
4140
6484
|
const skewMs = Math.abs(Date.now() - timestampMs);
|
|
4141
6485
|
return skewMs <= toleranceSeconds * 1e3;
|
|
@@ -4145,14 +6489,14 @@ async function handleWebhook(request, handler, options) {
|
|
|
4145
6489
|
const rawBody = await request.text();
|
|
4146
6490
|
if (options?.secret) {
|
|
4147
6491
|
const signature = request.headers.get("x-webhook-signature") || "";
|
|
4148
|
-
const
|
|
6492
|
+
const timestamp2 = request.headers.get("x-webhook-timestamp") || "";
|
|
4149
6493
|
const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
|
|
4150
6494
|
const toleranceSeconds = options.toleranceSeconds ?? 300;
|
|
4151
|
-
const valid = Boolean(
|
|
6495
|
+
const valid = Boolean(timestamp2 && deliveryId) && timestampIsFresh(timestamp2, toleranceSeconds) && await verifySignature(
|
|
4152
6496
|
rawBody,
|
|
4153
6497
|
options.secret,
|
|
4154
6498
|
signature,
|
|
4155
|
-
|
|
6499
|
+
timestamp2,
|
|
4156
6500
|
deliveryId
|
|
4157
6501
|
);
|
|
4158
6502
|
if (!valid) {
|
|
@@ -4216,12 +6560,21 @@ var INTERNAL_COLLECTIONS = [
|
|
|
4216
6560
|
"analytics-event-schemas",
|
|
4217
6561
|
"subscriptions",
|
|
4218
6562
|
"billing-history",
|
|
6563
|
+
"usage-rate-cards",
|
|
6564
|
+
"usage-invoices",
|
|
4219
6565
|
"inventory-reservations",
|
|
4220
6566
|
"inventory-adjustments",
|
|
6567
|
+
"payment-sessions",
|
|
6568
|
+
"payment-event-inbox",
|
|
6569
|
+
"payment-refund-attempts",
|
|
6570
|
+
"portone-payment-interactions",
|
|
4221
6571
|
"commerce-notification-intents",
|
|
6572
|
+
"commerce-idempotency-records",
|
|
4222
6573
|
"product-collection-items",
|
|
4223
6574
|
"order-status-logs",
|
|
6575
|
+
"fulfillment-events",
|
|
4224
6576
|
"tenant-commerce-config",
|
|
6577
|
+
"customer-oauth-clients",
|
|
4225
6578
|
"api-keys",
|
|
4226
6579
|
"personal-access-tokens",
|
|
4227
6580
|
"tenant-entitlements",
|
|
@@ -4229,12 +6582,18 @@ var INTERNAL_COLLECTIONS = [
|
|
|
4229
6582
|
"direct-upload-sessions",
|
|
4230
6583
|
"webhook-events",
|
|
4231
6584
|
"webhook-deliveries",
|
|
6585
|
+
"webhook-outbox-deliveries",
|
|
4232
6586
|
"audit-logs",
|
|
4233
6587
|
"plans",
|
|
4234
6588
|
"webhooks",
|
|
6589
|
+
"custom-field-definitions",
|
|
4235
6590
|
"event-registrations",
|
|
6591
|
+
"event-admission-holds",
|
|
6592
|
+
"event-admission-types",
|
|
4236
6593
|
"customer-payment-methods",
|
|
4237
|
-
"tenant-payment-credentials"
|
|
6594
|
+
"tenant-payment-credentials",
|
|
6595
|
+
"commerce-payment-accounts",
|
|
6596
|
+
"payment-provider-customer-aliases"
|
|
4238
6597
|
];
|
|
4239
6598
|
var COLLECTIONS = [
|
|
4240
6599
|
"tenants",
|
|
@@ -4293,6 +6652,7 @@ var COLLECTIONS = [
|
|
|
4293
6652
|
"event-occurrences",
|
|
4294
6653
|
"event-tags",
|
|
4295
6654
|
"membership-plans",
|
|
6655
|
+
"membership-plan-prices",
|
|
4296
6656
|
"customer-memberships"
|
|
4297
6657
|
];
|
|
4298
6658
|
var SERVER_ONLY_COLLECTIONS = [
|
|
@@ -4301,9 +6661,14 @@ var SERVER_ONLY_COLLECTIONS = [
|
|
|
4301
6661
|
"images",
|
|
4302
6662
|
"videos",
|
|
4303
6663
|
"orders",
|
|
6664
|
+
"order-tags",
|
|
4304
6665
|
"order-items",
|
|
4305
6666
|
"returns",
|
|
4306
6667
|
"return-items",
|
|
6668
|
+
"refunds",
|
|
6669
|
+
"refund-line-items",
|
|
6670
|
+
"order-edit-sessions",
|
|
6671
|
+
"order-staged-changes",
|
|
4307
6672
|
"fulfillment-orders",
|
|
4308
6673
|
"fulfillment-order-items",
|
|
4309
6674
|
"fulfillments",
|
|
@@ -4316,6 +6681,8 @@ var SERVER_ONLY_COLLECTIONS = [
|
|
|
4316
6681
|
"cart-items",
|
|
4317
6682
|
"checkouts",
|
|
4318
6683
|
"checkout-items",
|
|
6684
|
+
"draft-orders",
|
|
6685
|
+
"draft-order-items",
|
|
4319
6686
|
"posts",
|
|
4320
6687
|
"comments",
|
|
4321
6688
|
"reactions",
|
|
@@ -4711,9 +7078,9 @@ var generateOrderNumber = () => {
|
|
|
4711
7078
|
const year = now.getFullYear().toString().slice(-2);
|
|
4712
7079
|
const month = (now.getMonth() + 1).toString().padStart(2, "0");
|
|
4713
7080
|
const day = now.getDate().toString().padStart(2, "0");
|
|
4714
|
-
const
|
|
4715
|
-
globalThis.crypto.getRandomValues(
|
|
4716
|
-
const random = ((
|
|
7081
|
+
const array2 = new Uint32Array(1);
|
|
7082
|
+
globalThis.crypto.getRandomValues(array2);
|
|
7083
|
+
const random = ((array2[0] ?? 0) % 1e6).toString().padStart(6, "0");
|
|
4717
7084
|
return `${year}${month}${day}${random}`;
|
|
4718
7085
|
};
|
|
4719
7086
|
|
|
@@ -4764,7 +7131,7 @@ function createAnalytics(config) {
|
|
|
4764
7131
|
}, destroy() {
|
|
4765
7132
|
} };
|
|
4766
7133
|
}
|
|
4767
|
-
const
|
|
7134
|
+
const endpoint2 = config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`;
|
|
4768
7135
|
const respectDnt = config.respectDnt !== false;
|
|
4769
7136
|
function isDntActive() {
|
|
4770
7137
|
if (!respectDnt) return false;
|
|
@@ -4805,10 +7172,10 @@ function createAnalytics(config) {
|
|
|
4805
7172
|
try {
|
|
4806
7173
|
if (typeof navigator.sendBeacon === "function") {
|
|
4807
7174
|
const blob = new Blob([body], { type: "text/plain" });
|
|
4808
|
-
const sent = navigator.sendBeacon(
|
|
7175
|
+
const sent = navigator.sendBeacon(endpoint2, blob);
|
|
4809
7176
|
if (sent) return;
|
|
4810
7177
|
}
|
|
4811
|
-
fetch(
|
|
7178
|
+
fetch(endpoint2, {
|
|
4812
7179
|
method: "POST",
|
|
4813
7180
|
keepalive: true,
|
|
4814
7181
|
headers: { "Content-Type": "application/json" },
|
|
@@ -4958,11 +7325,11 @@ export {
|
|
|
4958
7325
|
ApiError,
|
|
4959
7326
|
AuthError,
|
|
4960
7327
|
COLLECTIONS,
|
|
7328
|
+
COMMERCE_ERROR_CODES,
|
|
4961
7329
|
COMMERCE_NOTIFICATION_EVENTS,
|
|
4962
7330
|
COMMERCE_NOTIFICATION_EVENT_TYPE,
|
|
4963
7331
|
COMMERCE_NOTIFICATION_OPERATION,
|
|
4964
7332
|
CUSTOMER_PASSWORD_RESET_OPERATION,
|
|
4965
|
-
CartApi,
|
|
4966
7333
|
CommerceClient,
|
|
4967
7334
|
CommunityClient,
|
|
4968
7335
|
ConfigError,
|
|
@@ -4970,10 +7337,12 @@ export {
|
|
|
4970
7337
|
ContentClient,
|
|
4971
7338
|
CustomerAuth,
|
|
4972
7339
|
CustomerNamespace,
|
|
7340
|
+
CustomerOAuth,
|
|
4973
7341
|
EventsClient,
|
|
4974
7342
|
GoneError,
|
|
4975
7343
|
IMAGE_SIZES,
|
|
4976
7344
|
INTERNAL_COLLECTIONS,
|
|
7345
|
+
MAX_CART_LINE_ADMISSIONS,
|
|
4977
7346
|
NetworkError,
|
|
4978
7347
|
NotFoundError,
|
|
4979
7348
|
ORDER_CHANGED_EVENT_TYPE,
|
|
@@ -4991,6 +7360,7 @@ export {
|
|
|
4991
7360
|
TimeoutError,
|
|
4992
7361
|
UsageLimitError,
|
|
4993
7362
|
ValidationError,
|
|
7363
|
+
assertCommerceIdempotencyKey,
|
|
4994
7364
|
buildProductHref,
|
|
4995
7365
|
buildProductListingCard,
|
|
4996
7366
|
buildProductListingGroupProjection,
|
|
@@ -5001,6 +7371,7 @@ export {
|
|
|
5001
7371
|
createAuthError,
|
|
5002
7372
|
createClient2 as createClient,
|
|
5003
7373
|
createCommerceEmailWebhookHandler,
|
|
7374
|
+
createCommerceIdempotencyKey,
|
|
5004
7375
|
createCommerceNotificationWebhookHandler,
|
|
5005
7376
|
createConflictError,
|
|
5006
7377
|
createCustomerAuthWebhookHandler,
|
|
@@ -5031,7 +7402,9 @@ export {
|
|
|
5031
7402
|
handleWebhook,
|
|
5032
7403
|
isApiError,
|
|
5033
7404
|
isAuthError,
|
|
7405
|
+
isCommerceIdempotencyKey,
|
|
5034
7406
|
isCommerceNotificationWebhookEvent,
|
|
7407
|
+
isCommerceSDKError,
|
|
5035
7408
|
isConfigError,
|
|
5036
7409
|
isConflictError,
|
|
5037
7410
|
isCustomerPasswordResetWebhookEvent,
|