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