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