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