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