@01.software/sdk 0.44.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +366 -2
- package/MIGRATION.md +108 -10
- package/README.md +486 -98
- package/dist/{server-nXOezi4b.d.cts → catalog-mappers-sIshKNb3.d.cts} +14 -3
- package/dist/{server-nXOezi4b.d.ts → catalog-mappers-sIshKNb3.d.ts} +14 -3
- package/dist/client.cjs +2693 -345
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +10 -7
- package/dist/client.d.ts +10 -7
- package/dist/client.js +2693 -345
- package/dist/client.js.map +1 -1
- package/dist/{collection-client-DWooaiTr.d.ts → collection-client-D6kKrYdq.d.ts} +8 -5
- package/dist/{collection-client-Dyl-CDcj.d.cts → collection-client-DolMjCoC.d.cts} +8 -5
- package/dist/{const-pGDnsy0o.d.ts → const-BAG0MH0u.d.cts} +13 -10
- package/dist/{const-1vleZ6ov.d.cts → const-CaPq2AE4.d.ts} +13 -10
- package/dist/errors.cjs +74 -1
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +38 -1
- package/dist/errors.d.ts +38 -1
- package/dist/errors.js +74 -1
- package/dist/errors.js.map +1 -1
- package/dist/{index-DUNySyxV.d.ts → index-BNICJxBL.d.ts} +4 -4
- package/dist/{index-a6g7vqAD.d.cts → index-YGrZrxNn.d.cts} +4 -4
- package/dist/index.cjs +2754 -368
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -19
- package/dist/index.d.ts +18 -19
- package/dist/index.js +2754 -368
- package/dist/index.js.map +1 -1
- package/dist/{payload-types-CDsuOEfM.d.cts → payload-types-CJZuXcgF.d.cts} +6671 -4001
- package/dist/{payload-types-CDsuOEfM.d.ts → payload-types-CJZuXcgF.d.ts} +6671 -4001
- package/dist/query.cjs +558 -101
- package/dist/query.cjs.map +1 -1
- package/dist/query.d.cts +43 -45
- package/dist/query.d.ts +43 -45
- package/dist/query.js +558 -101
- package/dist/query.js.map +1 -1
- package/dist/realtime.cjs.map +1 -1
- package/dist/realtime.d.cts +2 -2
- package/dist/realtime.d.ts +2 -2
- package/dist/realtime.js.map +1 -1
- package/dist/server.cjs +2343 -437
- package/dist/server.cjs.map +1 -1
- package/dist/server.d.cts +11 -10
- package/dist/server.d.ts +11 -10
- package/dist/server.js +2343 -437
- package/dist/server.js.map +1 -1
- package/dist/storefront-cache.cjs +65 -1
- package/dist/storefront-cache.cjs.map +1 -1
- package/dist/storefront-cache.js +65 -1
- package/dist/storefront-cache.js.map +1 -1
- package/dist/types-BC6rVmJa.d.ts +47 -0
- package/dist/{types-CDND3hzq.d.cts → types-C60vHIkY.d.ts} +1134 -509
- package/dist/types-D5p7-m1l.d.cts +47 -0
- package/dist/{types-Dt9FJisi.d.ts → types-xlqBeW2N.d.cts} +1134 -509
- package/dist/ui/canvas/server.cjs +244 -2
- package/dist/ui/canvas/server.cjs.map +1 -1
- package/dist/ui/canvas/server.d.cts +27 -1
- package/dist/ui/canvas/server.d.ts +27 -1
- package/dist/ui/canvas/server.js +244 -2
- package/dist/ui/canvas/server.js.map +1 -1
- package/dist/ui/canvas.cjs +419 -103
- package/dist/ui/canvas.cjs.map +1 -1
- package/dist/ui/canvas.d.cts +19 -7
- package/dist/ui/canvas.d.ts +19 -7
- package/dist/ui/canvas.js +419 -103
- package/dist/ui/canvas.js.map +1 -1
- package/dist/ui/form.d.cts +1 -1
- package/dist/ui/form.d.ts +1 -1
- package/dist/ui/video.d.cts +1 -1
- package/dist/ui/video.d.ts +1 -1
- package/dist/webhook.cjs +2 -1
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.d.cts +4 -4
- package/dist/webhook.d.ts +4 -4
- package/dist/webhook.js +2 -1
- package/dist/webhook.js.map +1 -1
- package/package.json +10 -9
- package/dist/types-SoXsbKhj.d.cts +0 -33
- package/dist/types-oiae_LMm.d.ts +0 -33
package/dist/index.cjs
CHANGED
|
@@ -23,11 +23,11 @@ __export(src_exports, {
|
|
|
23
23
|
ApiError: () => ApiError,
|
|
24
24
|
AuthError: () => AuthError,
|
|
25
25
|
COLLECTIONS: () => COLLECTIONS,
|
|
26
|
+
COMMERCE_ERROR_CODES: () => COMMERCE_ERROR_CODES,
|
|
26
27
|
COMMERCE_NOTIFICATION_EVENTS: () => COMMERCE_NOTIFICATION_EVENTS,
|
|
27
28
|
COMMERCE_NOTIFICATION_EVENT_TYPE: () => COMMERCE_NOTIFICATION_EVENT_TYPE,
|
|
28
29
|
COMMERCE_NOTIFICATION_OPERATION: () => COMMERCE_NOTIFICATION_OPERATION,
|
|
29
30
|
CUSTOMER_PASSWORD_RESET_OPERATION: () => CUSTOMER_PASSWORD_RESET_OPERATION,
|
|
30
|
-
CartApi: () => CartApi,
|
|
31
31
|
CommerceClient: () => CommerceClient,
|
|
32
32
|
CommunityClient: () => CommunityClient,
|
|
33
33
|
ConfigError: () => ConfigError,
|
|
@@ -35,10 +35,12 @@ __export(src_exports, {
|
|
|
35
35
|
ContentClient: () => ContentClient,
|
|
36
36
|
CustomerAuth: () => CustomerAuth,
|
|
37
37
|
CustomerNamespace: () => CustomerNamespace,
|
|
38
|
+
CustomerOAuth: () => CustomerOAuth,
|
|
38
39
|
EventsClient: () => EventsClient,
|
|
39
40
|
GoneError: () => GoneError,
|
|
40
41
|
IMAGE_SIZES: () => IMAGE_SIZES,
|
|
41
42
|
INTERNAL_COLLECTIONS: () => INTERNAL_COLLECTIONS,
|
|
43
|
+
MAX_CART_LINE_ADMISSIONS: () => MAX_CART_LINE_ADMISSIONS,
|
|
42
44
|
NetworkError: () => NetworkError,
|
|
43
45
|
NotFoundError: () => NotFoundError,
|
|
44
46
|
ORDER_CHANGED_EVENT_TYPE: () => ORDER_CHANGED_EVENT_TYPE,
|
|
@@ -56,6 +58,7 @@ __export(src_exports, {
|
|
|
56
58
|
TimeoutError: () => TimeoutError,
|
|
57
59
|
UsageLimitError: () => UsageLimitError,
|
|
58
60
|
ValidationError: () => ValidationError,
|
|
61
|
+
assertCommerceIdempotencyKey: () => assertCommerceIdempotencyKey,
|
|
59
62
|
buildProductHref: () => buildProductHref,
|
|
60
63
|
buildProductListingCard: () => buildProductListingCard,
|
|
61
64
|
buildProductListingGroupProjection: () => buildProductListingGroupProjection,
|
|
@@ -66,6 +69,7 @@ __export(src_exports, {
|
|
|
66
69
|
createAuthError: () => createAuthError,
|
|
67
70
|
createClient: () => createClient2,
|
|
68
71
|
createCommerceEmailWebhookHandler: () => createCommerceEmailWebhookHandler,
|
|
72
|
+
createCommerceIdempotencyKey: () => createCommerceIdempotencyKey,
|
|
69
73
|
createCommerceNotificationWebhookHandler: () => createCommerceNotificationWebhookHandler,
|
|
70
74
|
createConflictError: () => createConflictError,
|
|
71
75
|
createCustomerAuthWebhookHandler: () => createCustomerAuthWebhookHandler,
|
|
@@ -96,7 +100,9 @@ __export(src_exports, {
|
|
|
96
100
|
handleWebhook: () => handleWebhook,
|
|
97
101
|
isApiError: () => isApiError,
|
|
98
102
|
isAuthError: () => isAuthError,
|
|
103
|
+
isCommerceIdempotencyKey: () => isCommerceIdempotencyKey,
|
|
99
104
|
isCommerceNotificationWebhookEvent: () => isCommerceNotificationWebhookEvent,
|
|
105
|
+
isCommerceSDKError: () => isCommerceSDKError,
|
|
100
106
|
isConfigError: () => isConfigError,
|
|
101
107
|
isConflictError: () => isConflictError,
|
|
102
108
|
isCustomerPasswordResetWebhookEvent: () => isCustomerPasswordResetWebhookEvent,
|
|
@@ -167,10 +173,136 @@ var SDKError = class extends Error {
|
|
|
167
173
|
details: this.details,
|
|
168
174
|
userMessage: this.userMessage,
|
|
169
175
|
suggestion: this.suggestion,
|
|
170
|
-
...this.requestId !== void 0 && { requestId: this.requestId }
|
|
176
|
+
...this.requestId !== void 0 && { requestId: this.requestId },
|
|
177
|
+
...this.kind !== void 0 && { kind: this.kind },
|
|
178
|
+
...this.reason !== void 0 && { reason: this.reason },
|
|
179
|
+
...this.rawReason !== void 0 && { rawReason: this.rawReason },
|
|
180
|
+
...this.retryable !== void 0 && { retryable: this.retryable },
|
|
181
|
+
...this.retryAfter !== void 0 && { retryAfter: this.retryAfter }
|
|
171
182
|
};
|
|
172
183
|
}
|
|
173
184
|
};
|
|
185
|
+
var COMMERCE_ERROR_CODES = [
|
|
186
|
+
"validation_failed",
|
|
187
|
+
"unauthorized",
|
|
188
|
+
"forbidden",
|
|
189
|
+
"token_expired",
|
|
190
|
+
"origin_not_allowed",
|
|
191
|
+
"server_credentials_required",
|
|
192
|
+
"not_found",
|
|
193
|
+
"conflict",
|
|
194
|
+
"cart_revision_conflict",
|
|
195
|
+
"rate_limit_exceeded",
|
|
196
|
+
"usage_limit_exceeded",
|
|
197
|
+
"service_unavailable",
|
|
198
|
+
"idempotency_conflict",
|
|
199
|
+
"idempotency_in_progress",
|
|
200
|
+
"cart_not_active",
|
|
201
|
+
"cart_locked",
|
|
202
|
+
"cart_empty",
|
|
203
|
+
"cart_market_unavailable",
|
|
204
|
+
"cart_market_mismatch",
|
|
205
|
+
"checkout_not_open",
|
|
206
|
+
"payment_slot_held",
|
|
207
|
+
"reservation_expired",
|
|
208
|
+
"payment_session_not_cancelable",
|
|
209
|
+
"provider_identity_mismatch",
|
|
210
|
+
"provider_unavailable",
|
|
211
|
+
"lock_timeout",
|
|
212
|
+
"price_changed",
|
|
213
|
+
"pricing_fact_in_use",
|
|
214
|
+
"insufficient_stock",
|
|
215
|
+
"market_not_found",
|
|
216
|
+
"market_shipping_currency_unsupported",
|
|
217
|
+
"missing_market_rate",
|
|
218
|
+
"missing_shipping_amount",
|
|
219
|
+
"no_enabled_payment_provider",
|
|
220
|
+
"product_market_unavailable",
|
|
221
|
+
"unsupported_currency",
|
|
222
|
+
"missing_price_row",
|
|
223
|
+
"payment_provider_currency_unsupported",
|
|
224
|
+
"discount_code_not_found",
|
|
225
|
+
"discount_not_started",
|
|
226
|
+
"discount_expired",
|
|
227
|
+
"discount_usage_limit",
|
|
228
|
+
"discount_per_customer_limit",
|
|
229
|
+
"discount_customer_required",
|
|
230
|
+
"discount_first_order_only",
|
|
231
|
+
"discount_customer_not_eligible",
|
|
232
|
+
"discount_customer_excluded",
|
|
233
|
+
"discount_items_required",
|
|
234
|
+
"discount_product_not_eligible",
|
|
235
|
+
"discount_product_excluded",
|
|
236
|
+
"discount_min_order_amount",
|
|
237
|
+
"discount_currency_scope_required",
|
|
238
|
+
"discount_allocation_method_unsupported",
|
|
239
|
+
"currency_mismatch"
|
|
240
|
+
];
|
|
241
|
+
var COMMERCE_ERROR_CODE_SET = new Set(
|
|
242
|
+
COMMERCE_ERROR_CODES
|
|
243
|
+
);
|
|
244
|
+
var COMMERCE_ERROR_ENVELOPE_KEYS = /* @__PURE__ */ new Set([
|
|
245
|
+
"error",
|
|
246
|
+
"reason",
|
|
247
|
+
"requestId",
|
|
248
|
+
"retryable",
|
|
249
|
+
"details"
|
|
250
|
+
]);
|
|
251
|
+
function isPlainRecord(value) {
|
|
252
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
253
|
+
}
|
|
254
|
+
function commerceProtocolError(issue, trustedRequestId) {
|
|
255
|
+
return createApiError(
|
|
256
|
+
"Invalid canonical commerce error response.",
|
|
257
|
+
502,
|
|
258
|
+
{ protocol: "commerce-error-envelope", issue },
|
|
259
|
+
"The server returned an incompatible commerce error response.",
|
|
260
|
+
"Verify that the Console commerce contract is deployed before using this SDK version.",
|
|
261
|
+
trustedRequestId
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
function parseCommerceErrorEnvelope(body, headerRequestId) {
|
|
265
|
+
if (!isPlainRecord(body)) {
|
|
266
|
+
throw commerceProtocolError("expected_object", headerRequestId);
|
|
267
|
+
}
|
|
268
|
+
if (Object.keys(body).some((key) => !COMMERCE_ERROR_ENVELOPE_KEYS.has(key))) {
|
|
269
|
+
throw commerceProtocolError("unexpected_field", headerRequestId);
|
|
270
|
+
}
|
|
271
|
+
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)) {
|
|
272
|
+
throw commerceProtocolError("invalid_field", headerRequestId);
|
|
273
|
+
}
|
|
274
|
+
if (headerRequestId && headerRequestId !== body.requestId) {
|
|
275
|
+
throw commerceProtocolError("request_id_mismatch", headerRequestId);
|
|
276
|
+
}
|
|
277
|
+
return {
|
|
278
|
+
error: body.error,
|
|
279
|
+
reason: body.reason,
|
|
280
|
+
requestId: body.requestId,
|
|
281
|
+
retryable: body.retryable === true,
|
|
282
|
+
...body.details === void 0 ? {} : { details: body.details }
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function enhanceCommerceError(error, body, headerRequestId) {
|
|
286
|
+
const envelope = parseCommerceErrorEnvelope(body, headerRequestId);
|
|
287
|
+
const known = COMMERCE_ERROR_CODE_SET.has(envelope.reason);
|
|
288
|
+
Object.assign(error, {
|
|
289
|
+
code: envelope.reason,
|
|
290
|
+
kind: "commerce",
|
|
291
|
+
reason: known ? envelope.reason : "unknown_commerce_error",
|
|
292
|
+
...known ? {} : { rawReason: envelope.reason },
|
|
293
|
+
requestId: envelope.requestId,
|
|
294
|
+
retryable: envelope.retryable,
|
|
295
|
+
details: envelope.details
|
|
296
|
+
});
|
|
297
|
+
return error;
|
|
298
|
+
}
|
|
299
|
+
function isCommerceSDKError(error) {
|
|
300
|
+
if (!(error instanceof SDKError) || error.kind !== "commerce") return false;
|
|
301
|
+
if (typeof error.requestId !== "string" || typeof error.retryable !== "boolean" || error.retryAfter !== void 0 && (!Number.isSafeInteger(error.retryAfter) || error.retryAfter < 0) || typeof error.reason !== "string") {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
return error.reason === "unknown_commerce_error" ? typeof error.rawReason === "string" : COMMERCE_ERROR_CODE_SET.has(error.reason) && error.rawReason === void 0;
|
|
305
|
+
}
|
|
174
306
|
var NetworkError = class extends SDKError {
|
|
175
307
|
constructor(message, status, details, userMessage, suggestion) {
|
|
176
308
|
super("NETWORK_ERROR", message, status, details, userMessage, suggestion);
|
|
@@ -409,6 +541,7 @@ var NON_RETRYABLE_STATUSES = [400, 401, 403, 404, 409, 422];
|
|
|
409
541
|
var SAFE_METHODS = ["GET", "HEAD", "OPTIONS"];
|
|
410
542
|
var DEFAULT_MAX_RETRIES = 3;
|
|
411
543
|
var STOREFRONT_BROWSER_MAX_RETRIES = 1;
|
|
544
|
+
var MAX_AUTOMATIC_RETRY_AFTER_SECONDS = 5 * 60;
|
|
412
545
|
function debugLog(debug, type, message, data) {
|
|
413
546
|
if (!debug) return;
|
|
414
547
|
const shouldLog = debug === true || type === "request" && debug.logRequests || type === "response" && debug.logResponses || type === "error" && debug.logErrors;
|
|
@@ -432,6 +565,11 @@ function redactSensitiveHeaders(headers) {
|
|
|
432
565
|
redacted["x-preview-token"]
|
|
433
566
|
);
|
|
434
567
|
}
|
|
568
|
+
if (redacted["x-custom-payment-signature"]) {
|
|
569
|
+
redacted["x-custom-payment-signature"] = redactSensitiveHeader(
|
|
570
|
+
redacted["x-custom-payment-signature"]
|
|
571
|
+
);
|
|
572
|
+
}
|
|
435
573
|
return redacted;
|
|
436
574
|
}
|
|
437
575
|
function getErrorSuggestion(status) {
|
|
@@ -523,116 +661,129 @@ function attachRequestId(err, id) {
|
|
|
523
661
|
}
|
|
524
662
|
function parseRetryAfter(response) {
|
|
525
663
|
const raw = response.headers.get("Retry-After");
|
|
526
|
-
if (!raw) return
|
|
527
|
-
|
|
664
|
+
if (!raw) return { permitsAutomaticRetry: true };
|
|
665
|
+
const trimmed = raw.trim();
|
|
666
|
+
let seconds;
|
|
667
|
+
if (/^\d+$/.test(trimmed)) {
|
|
668
|
+
seconds = Number(trimmed);
|
|
669
|
+
if (!Number.isSafeInteger(seconds)) {
|
|
670
|
+
return { permitsAutomaticRetry: false };
|
|
671
|
+
}
|
|
672
|
+
} else {
|
|
673
|
+
const retryAt = Date.parse(trimmed);
|
|
674
|
+
if (!Number.isFinite(retryAt)) return { permitsAutomaticRetry: true };
|
|
675
|
+
seconds = Math.max(0, Math.ceil((retryAt - Date.now()) / 1e3));
|
|
676
|
+
}
|
|
677
|
+
return {
|
|
678
|
+
seconds,
|
|
679
|
+
permitsAutomaticRetry: seconds <= MAX_AUTOMATIC_RETRY_AFTER_SECONDS
|
|
680
|
+
};
|
|
528
681
|
}
|
|
529
|
-
function mapResponseToError(status, parsed, details, requestId, retryAfter) {
|
|
682
|
+
function mapResponseToError(status, parsed, details, requestId, retryAfter, errorFamily) {
|
|
530
683
|
const errorDetails = {
|
|
531
684
|
...details,
|
|
532
685
|
...parsed.errors && { errors: parsed.errors },
|
|
533
|
-
...parsed.body && { body: parsed.body }
|
|
686
|
+
...errorFamily !== "commerce" && parsed.body && { body: parsed.body }
|
|
534
687
|
};
|
|
535
688
|
const suggestion = getParsedErrorSuggestion(status, parsed);
|
|
689
|
+
const finalize = (error) => {
|
|
690
|
+
const withRequestId = attachRequestId(error, requestId);
|
|
691
|
+
if (retryAfter !== void 0) {
|
|
692
|
+
Object.assign(withRequestId, { retryAfter });
|
|
693
|
+
}
|
|
694
|
+
return errorFamily === "commerce" ? enhanceCommerceError(withRequestId, parsed.body, requestId) : withRequestId;
|
|
695
|
+
};
|
|
536
696
|
if (status === 400 || status === 422) {
|
|
537
|
-
return
|
|
697
|
+
return finalize(
|
|
538
698
|
createValidationError(
|
|
539
699
|
parsed.errorMessage,
|
|
540
700
|
errorDetails,
|
|
541
701
|
parsed.userMessage,
|
|
542
702
|
suggestion,
|
|
543
703
|
status
|
|
544
|
-
)
|
|
545
|
-
requestId
|
|
704
|
+
)
|
|
546
705
|
);
|
|
547
706
|
}
|
|
548
707
|
if (status === 401) {
|
|
549
|
-
return
|
|
708
|
+
return finalize(
|
|
550
709
|
createAuthError(
|
|
551
710
|
parsed.errorMessage,
|
|
552
711
|
errorDetails,
|
|
553
712
|
parsed.userMessage,
|
|
554
713
|
suggestion
|
|
555
|
-
)
|
|
556
|
-
requestId
|
|
714
|
+
)
|
|
557
715
|
);
|
|
558
716
|
}
|
|
559
717
|
if (status === 403) {
|
|
560
|
-
return
|
|
718
|
+
return finalize(
|
|
561
719
|
createPermissionError(
|
|
562
720
|
parsed.errorMessage,
|
|
563
721
|
errorDetails,
|
|
564
722
|
parsed.userMessage,
|
|
565
723
|
suggestion
|
|
566
|
-
)
|
|
567
|
-
requestId
|
|
724
|
+
)
|
|
568
725
|
);
|
|
569
726
|
}
|
|
570
727
|
if (status === 404) {
|
|
571
|
-
return
|
|
728
|
+
return finalize(
|
|
572
729
|
createNotFoundError(
|
|
573
730
|
parsed.errorMessage,
|
|
574
731
|
errorDetails,
|
|
575
732
|
parsed.userMessage,
|
|
576
733
|
suggestion
|
|
577
|
-
)
|
|
578
|
-
requestId
|
|
734
|
+
)
|
|
579
735
|
);
|
|
580
736
|
}
|
|
581
737
|
if (status === 409) {
|
|
582
|
-
return
|
|
738
|
+
return finalize(
|
|
583
739
|
createConflictError(
|
|
584
740
|
parsed.errorMessage,
|
|
585
741
|
errorDetails,
|
|
586
742
|
parsed.userMessage,
|
|
587
743
|
suggestion
|
|
588
|
-
)
|
|
589
|
-
requestId
|
|
744
|
+
)
|
|
590
745
|
);
|
|
591
746
|
}
|
|
592
747
|
if (status === 410) {
|
|
593
|
-
return
|
|
748
|
+
return finalize(
|
|
594
749
|
createGoneError(
|
|
595
750
|
parsed.errorMessage,
|
|
596
751
|
errorDetails,
|
|
597
752
|
parsed.userMessage,
|
|
598
753
|
suggestion
|
|
599
|
-
)
|
|
600
|
-
requestId
|
|
754
|
+
)
|
|
601
755
|
);
|
|
602
756
|
}
|
|
603
757
|
if (status === 429) {
|
|
604
|
-
return
|
|
758
|
+
return finalize(
|
|
605
759
|
createRateLimitError(
|
|
606
760
|
parsed.errorMessage,
|
|
607
761
|
retryAfter,
|
|
608
762
|
errorDetails,
|
|
609
763
|
parsed.userMessage,
|
|
610
764
|
suggestion
|
|
611
|
-
)
|
|
612
|
-
requestId
|
|
765
|
+
)
|
|
613
766
|
);
|
|
614
767
|
}
|
|
615
768
|
if (status === 503) {
|
|
616
|
-
return
|
|
769
|
+
return finalize(
|
|
617
770
|
createServiceUnavailableError(
|
|
618
771
|
parsed.errorMessage,
|
|
619
772
|
retryAfter,
|
|
620
773
|
errorDetails,
|
|
621
774
|
parsed.userMessage,
|
|
622
775
|
suggestion
|
|
623
|
-
)
|
|
624
|
-
requestId
|
|
776
|
+
)
|
|
625
777
|
);
|
|
626
778
|
}
|
|
627
|
-
return
|
|
779
|
+
return finalize(
|
|
628
780
|
createNetworkError(
|
|
629
781
|
parsed.errorMessage,
|
|
630
782
|
status,
|
|
631
783
|
errorDetails,
|
|
632
784
|
parsed.userMessage,
|
|
633
785
|
suggestion
|
|
634
|
-
)
|
|
635
|
-
requestId
|
|
786
|
+
)
|
|
636
787
|
);
|
|
637
788
|
}
|
|
638
789
|
async function httpFetch(url, options) {
|
|
@@ -645,6 +796,7 @@ async function httpFetch(url, options) {
|
|
|
645
796
|
debug,
|
|
646
797
|
retry,
|
|
647
798
|
onUnauthorized,
|
|
799
|
+
errorFamily,
|
|
648
800
|
...requestInit
|
|
649
801
|
} = options || {};
|
|
650
802
|
const baseUrl = resolveApiUrl(apiUrl);
|
|
@@ -697,6 +849,8 @@ async function httpFetch(url, options) {
|
|
|
697
849
|
headers: redactSensitiveHeaders(response.headers)
|
|
698
850
|
});
|
|
699
851
|
if (!response.ok) {
|
|
852
|
+
const parsed = await parseErrorBody(response);
|
|
853
|
+
const commerceEnvelope = errorFamily === "commerce" ? parseCommerceErrorEnvelope(parsed.body, requestId) : void 0;
|
|
700
854
|
if (isUsageLimitExceededResponse(response)) {
|
|
701
855
|
const limit = parseInt(
|
|
702
856
|
response.headers.get("X-Usage-Limit") || "0",
|
|
@@ -710,7 +864,7 @@ async function httpFetch(url, options) {
|
|
|
710
864
|
response.headers.get("X-Usage-Remaining") || "0",
|
|
711
865
|
10
|
|
712
866
|
);
|
|
713
|
-
|
|
867
|
+
const usageError = attachRequestId(
|
|
714
868
|
createUsageLimitError(
|
|
715
869
|
`Monthly API usage limit exceeded (${current.toLocaleString()}/${limit.toLocaleString()})`,
|
|
716
870
|
{ limit, current, remaining },
|
|
@@ -724,9 +878,9 @@ async function httpFetch(url, options) {
|
|
|
724
878
|
),
|
|
725
879
|
requestId
|
|
726
880
|
);
|
|
881
|
+
throw errorFamily === "commerce" ? enhanceCommerceError(usageError, parsed.body, requestId) : usageError;
|
|
727
882
|
}
|
|
728
|
-
|
|
729
|
-
if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && parsed.reason === "token_expired") {
|
|
883
|
+
if (response.status === 401 && onUnauthorized && customerToken && !hasRetried401 && (commerceEnvelope?.reason ?? parsed.reason) === "token_expired") {
|
|
730
884
|
hasRetried401 = true;
|
|
731
885
|
try {
|
|
732
886
|
const newToken = await onUnauthorized();
|
|
@@ -748,13 +902,18 @@ async function httpFetch(url, options) {
|
|
|
748
902
|
parsed,
|
|
749
903
|
details,
|
|
750
904
|
requestId,
|
|
751
|
-
retryAfter
|
|
905
|
+
retryAfter.seconds,
|
|
906
|
+
errorFamily
|
|
752
907
|
);
|
|
753
908
|
const method2 = (requestInit.method || "GET").toUpperCase();
|
|
754
909
|
const isTerminal = error instanceof RateLimitError || error instanceof UsageLimitError;
|
|
755
|
-
|
|
910
|
+
const responseAllowsRetry = isCommerceSDKError(error) ? error.retryable : true;
|
|
911
|
+
if (attempt < retryConfig.maxRetries && SAFE_METHODS.includes(method2) && !isTerminal && responseAllowsRetry && retryAfter.permitsAutomaticRetry && !NON_RETRYABLE_STATUSES.includes(response.status) && retryConfig.retryableStatuses.includes(response.status)) {
|
|
756
912
|
lastError = error;
|
|
757
|
-
const retryDelay =
|
|
913
|
+
const retryDelay = Math.max(
|
|
914
|
+
retryConfig.retryDelay(attempt),
|
|
915
|
+
(retryAfter.seconds ?? 0) * 1e3
|
|
916
|
+
);
|
|
758
917
|
debugLog(debug, "error", `Retrying in ${retryDelay}ms...`, error);
|
|
759
918
|
await delay(retryDelay);
|
|
760
919
|
continue;
|
|
@@ -824,87 +983,45 @@ async function httpFetch(url, options) {
|
|
|
824
983
|
throw lastError ?? new NetworkError("Request failed after retries");
|
|
825
984
|
}
|
|
826
985
|
|
|
827
|
-
// src/core/api/endpoints.ts
|
|
828
|
-
var COMMERCE_ENDPOINTS = {
|
|
829
|
-
orders: {
|
|
830
|
-
create: "/api/orders/create",
|
|
831
|
-
update: "/api/orders/update",
|
|
832
|
-
confirmPayment: "/api/orders/confirm-payment",
|
|
833
|
-
byPayment: "/api/orders/by-payment",
|
|
834
|
-
cancel: "/api/orders/cancel",
|
|
835
|
-
resolveCancelRefund: "/api/orders/resolve-cancel-refund",
|
|
836
|
-
checkout: "/api/orders/checkout",
|
|
837
|
-
createFulfillment: "/api/orders/create-fulfillment",
|
|
838
|
-
updateFulfillment: "/api/orders/update-fulfillment"
|
|
839
|
-
},
|
|
840
|
-
transactions: {
|
|
841
|
-
update: "/api/transactions/update"
|
|
842
|
-
},
|
|
843
|
-
returns: {
|
|
844
|
-
create: "/api/returns/create",
|
|
845
|
-
update: "/api/returns/update",
|
|
846
|
-
returnRefund: "/api/returns/return-refund"
|
|
847
|
-
},
|
|
848
|
-
fulfillmentOrders: {
|
|
849
|
-
prepare: "/api/fulfillment-orders/prepare-fulfillment-order"
|
|
850
|
-
},
|
|
851
|
-
fulfillments: {
|
|
852
|
-
bulkImport: "/api/fulfillments/bulk-import"
|
|
853
|
-
},
|
|
854
|
-
carts: {
|
|
855
|
-
mine: "/api/carts/mine",
|
|
856
|
-
merge: "/api/carts/merge",
|
|
857
|
-
addItem: "/api/carts/add-item",
|
|
858
|
-
updateItem: "/api/carts/update-item",
|
|
859
|
-
removeItem: "/api/carts/remove-item",
|
|
860
|
-
applyDiscount: "/api/carts/apply-discount",
|
|
861
|
-
removeDiscount: "/api/carts/remove-discount",
|
|
862
|
-
clear: "/api/carts/clear"
|
|
863
|
-
},
|
|
864
|
-
products: {
|
|
865
|
-
stockCheck: "/api/products/stock-check",
|
|
866
|
-
stockSnapshot: "/api/products/stock",
|
|
867
|
-
listingGroups: "/api/products/listing-groups",
|
|
868
|
-
listingGroupsCatalog: "/api/products/listing-groups/catalog",
|
|
869
|
-
listingGroupsQuery: "/api/products/listing-groups/query",
|
|
870
|
-
listingGroupsQueryCatalog: "/api/products/listing-groups/query/catalog",
|
|
871
|
-
detail: "/api/products/detail",
|
|
872
|
-
detailCatalog: "/api/products/detail/catalog",
|
|
873
|
-
upsert: "/api/products/upsert"
|
|
874
|
-
}
|
|
875
|
-
};
|
|
876
|
-
var COMMERCE_ENDPOINT_PATHS = Object.values(
|
|
877
|
-
COMMERCE_ENDPOINTS
|
|
878
|
-
).flatMap((group) => Object.values(group));
|
|
879
|
-
var MEMBERSHIP_ENDPOINTS = {
|
|
880
|
-
subscribe: "/api/memberships/subscribe",
|
|
881
|
-
cancel: (id) => `/api/memberships/${id}/cancel`,
|
|
882
|
-
me: "/api/memberships/me"
|
|
883
|
-
};
|
|
884
|
-
|
|
885
986
|
// src/core/internal/utils/query-string.ts
|
|
886
|
-
function
|
|
887
|
-
const
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
987
|
+
function normalizedMarket(value) {
|
|
988
|
+
const market = value?.trim();
|
|
989
|
+
return market || void 0;
|
|
990
|
+
}
|
|
991
|
+
function appendProductLocaleSearchParams(search, options) {
|
|
992
|
+
if (options?.locale) search.set("locale", options.locale);
|
|
993
|
+
if (options?.fallbackLocale !== void 0) {
|
|
994
|
+
search.set(
|
|
995
|
+
"fallbackLocale",
|
|
996
|
+
options.fallbackLocale === false ? "none" : options.fallbackLocale
|
|
997
|
+
);
|
|
892
998
|
}
|
|
893
|
-
return `${COMMERCE_ENDPOINTS.products.detail}?${search}`;
|
|
894
999
|
}
|
|
895
|
-
function
|
|
1000
|
+
function productDetailSearchParams(params) {
|
|
896
1001
|
const search = new URLSearchParams();
|
|
897
1002
|
if ("slug" in params) {
|
|
898
1003
|
search.set("slug", params.slug);
|
|
899
1004
|
} else {
|
|
900
1005
|
search.set("id", params.id);
|
|
901
1006
|
}
|
|
902
|
-
|
|
1007
|
+
const market = normalizedMarket(params.market);
|
|
1008
|
+
if (market) search.set("market", market);
|
|
1009
|
+
appendProductLocaleSearchParams(search, params);
|
|
1010
|
+
return search.toString();
|
|
903
1011
|
}
|
|
904
|
-
function
|
|
905
|
-
|
|
1012
|
+
function listingGroupsSearchParams(params) {
|
|
1013
|
+
const ids = params.productIds.map(encodeURIComponent).join(",");
|
|
1014
|
+
const search = new URLSearchParams();
|
|
1015
|
+
const market = normalizedMarket(params.market);
|
|
1016
|
+
if (market) search.set("market", market);
|
|
1017
|
+
appendProductLocaleSearchParams(search, params);
|
|
1018
|
+
const query = search.toString();
|
|
1019
|
+
return `ids=${ids}${query ? `&${query}` : ""}`;
|
|
906
1020
|
}
|
|
907
1021
|
function appendListingGroupsQuerySearchParams(search, options) {
|
|
1022
|
+
const market = normalizedMarket(options?.market);
|
|
1023
|
+
if (market) search.set("market", market);
|
|
1024
|
+
appendProductLocaleSearchParams(search, options);
|
|
908
1025
|
if (options?.page != null) search.set("page", String(options.page));
|
|
909
1026
|
if (options?.limit != null) search.set("limit", String(options.limit));
|
|
910
1027
|
if (options?.sort != null) {
|
|
@@ -915,20 +1032,13 @@ function appendListingGroupsQuerySearchParams(search, options) {
|
|
|
915
1032
|
search.set("whereJson", JSON.stringify(options.where));
|
|
916
1033
|
}
|
|
917
1034
|
}
|
|
918
|
-
function
|
|
919
|
-
const search = new URLSearchParams();
|
|
920
|
-
appendListingGroupsQuerySearchParams(search, options);
|
|
921
|
-
const query = search.toString();
|
|
922
|
-
return `${COMMERCE_ENDPOINTS.products.listingGroupsQuery}${query ? `?${query}` : ""}`;
|
|
923
|
-
}
|
|
924
|
-
function listingGroupsQueryCatalogUrl(options) {
|
|
1035
|
+
function listingPageSearchParams(options) {
|
|
925
1036
|
const search = new URLSearchParams();
|
|
926
1037
|
appendListingGroupsQuerySearchParams(search, options);
|
|
927
|
-
|
|
928
|
-
return `${COMMERCE_ENDPOINTS.products.listingGroupsQueryCatalog}${query ? `?${query}` : ""}`;
|
|
1038
|
+
return search.toString();
|
|
929
1039
|
}
|
|
930
|
-
function
|
|
931
|
-
return
|
|
1040
|
+
function stockSnapshotSearchParams(params) {
|
|
1041
|
+
return `variantIds=${params.variantIds.map(encodeURIComponent).join(",")}`;
|
|
932
1042
|
}
|
|
933
1043
|
|
|
934
1044
|
// src/core/collection/http-client.ts
|
|
@@ -971,10 +1081,15 @@ var HttpClient = class {
|
|
|
971
1081
|
throw err;
|
|
972
1082
|
}
|
|
973
1083
|
}
|
|
974
|
-
buildUrl(
|
|
975
|
-
if (!options) return
|
|
976
|
-
const
|
|
977
|
-
|
|
1084
|
+
buildUrl(endpoint2, options) {
|
|
1085
|
+
if (!options) return endpoint2;
|
|
1086
|
+
const { fallbackLocale, ...rest } = options;
|
|
1087
|
+
const queryOptions = fallbackLocale === void 0 ? rest : {
|
|
1088
|
+
...rest,
|
|
1089
|
+
"fallback-locale": fallbackLocale === false ? "none" : fallbackLocale
|
|
1090
|
+
};
|
|
1091
|
+
const queryString = (0, import_qs_esm.stringify)(queryOptions, { addQueryPrefix: true });
|
|
1092
|
+
return queryString ? `${endpoint2}${queryString}` : endpoint2;
|
|
978
1093
|
}
|
|
979
1094
|
assertJsonResponse(response) {
|
|
980
1095
|
const contentType = response.headers.get("content-type");
|
|
@@ -1123,39 +1238,39 @@ var ReadOnlyCollectionClient = class extends HttpClient {
|
|
|
1123
1238
|
from(collection) {
|
|
1124
1239
|
return new ReadOnlyCollectionQueryBuilder(this, collection);
|
|
1125
1240
|
}
|
|
1126
|
-
async requestFind(
|
|
1127
|
-
const url = this.buildUrl(
|
|
1241
|
+
async requestFind(endpoint2, options) {
|
|
1242
|
+
const url = this.buildUrl(endpoint2, options);
|
|
1128
1243
|
const response = await this.fetchWithTracking(url, {
|
|
1129
1244
|
...this.defaultOptions,
|
|
1130
1245
|
method: "GET"
|
|
1131
1246
|
});
|
|
1132
1247
|
return this.parseFindResponse(response);
|
|
1133
1248
|
}
|
|
1134
|
-
async requestFindEndpoint(
|
|
1135
|
-
const response = await this.fetchWithTracking(
|
|
1249
|
+
async requestFindEndpoint(endpoint2, data) {
|
|
1250
|
+
const response = await this.fetchWithTracking(endpoint2, {
|
|
1136
1251
|
...this.defaultOptions,
|
|
1137
1252
|
method: "POST",
|
|
1138
1253
|
body: data ? JSON.stringify(data) : void 0
|
|
1139
1254
|
});
|
|
1140
1255
|
return this.parseFindResponse(response);
|
|
1141
1256
|
}
|
|
1142
|
-
async requestFindEndpointGet(
|
|
1143
|
-
const response = await this.fetchWithTracking(
|
|
1257
|
+
async requestFindEndpointGet(endpoint2) {
|
|
1258
|
+
const response = await this.fetchWithTracking(endpoint2, {
|
|
1144
1259
|
...this.defaultOptions,
|
|
1145
1260
|
method: "GET"
|
|
1146
1261
|
});
|
|
1147
1262
|
return this.parseFindResponse(response);
|
|
1148
1263
|
}
|
|
1149
|
-
async requestFindById(
|
|
1150
|
-
const url = this.buildUrl(
|
|
1264
|
+
async requestFindById(endpoint2, options) {
|
|
1265
|
+
const url = this.buildUrl(endpoint2, options);
|
|
1151
1266
|
const response = await this.fetchWithTracking(url, {
|
|
1152
1267
|
...this.defaultOptions,
|
|
1153
1268
|
method: "GET"
|
|
1154
1269
|
});
|
|
1155
1270
|
return this.parseDocumentResponse(response);
|
|
1156
1271
|
}
|
|
1157
|
-
async requestCount(
|
|
1158
|
-
const url = this.buildUrl(
|
|
1272
|
+
async requestCount(endpoint2, options) {
|
|
1273
|
+
const url = this.buildUrl(endpoint2, options);
|
|
1159
1274
|
const response = await this.fetchWithTracking(url, {
|
|
1160
1275
|
...this.defaultOptions,
|
|
1161
1276
|
method: "GET"
|
|
@@ -1165,53 +1280,347 @@ var ReadOnlyCollectionClient = class extends HttpClient {
|
|
|
1165
1280
|
};
|
|
1166
1281
|
|
|
1167
1282
|
// src/core/api/parse-response.ts
|
|
1168
|
-
async function parseApiResponse(response,
|
|
1169
|
-
|
|
1283
|
+
async function parseApiResponse(response, endpoint2, options = {}) {
|
|
1284
|
+
if (response.status === 204 || response.headers.get("content-length") === "0") {
|
|
1285
|
+
return void 0;
|
|
1286
|
+
}
|
|
1287
|
+
let parsed;
|
|
1170
1288
|
try {
|
|
1171
|
-
|
|
1289
|
+
parsed = await response.json();
|
|
1172
1290
|
} catch {
|
|
1173
1291
|
throw createApiError(
|
|
1174
|
-
`Invalid JSON response from ${
|
|
1292
|
+
`Invalid JSON response from ${endpoint2}`,
|
|
1175
1293
|
response.status,
|
|
1176
1294
|
void 0,
|
|
1177
1295
|
"Server returned an invalid response.",
|
|
1178
1296
|
"Check if the API endpoint is available."
|
|
1179
1297
|
);
|
|
1180
1298
|
}
|
|
1299
|
+
if (parsed === null || typeof parsed !== "object") {
|
|
1300
|
+
return parsed;
|
|
1301
|
+
}
|
|
1302
|
+
const data = parsed;
|
|
1181
1303
|
if (data.error) {
|
|
1182
1304
|
const errorMessage = typeof data.error === "string" ? data.error : "Unknown API error";
|
|
1183
1305
|
const reason = typeof data.reason === "string" ? data.reason : void 0;
|
|
1184
1306
|
const requestId = response.headers.get("x-request-id") ?? void 0;
|
|
1185
|
-
const
|
|
1186
|
-
|
|
1307
|
+
const retryAfter = parseRetryAfter(response).seconds;
|
|
1308
|
+
let error;
|
|
1187
1309
|
if (reason === "validation_failed") {
|
|
1188
|
-
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1310
|
+
error = createValidationError(errorMessage, data, errorMessage);
|
|
1311
|
+
} else if (reason === "token_expired" || reason === "token_invalid" || reason === "preview_token_invalid" || reason === "preview_token_required" || reason === "key_invalid" || reason === "key_revoked") {
|
|
1312
|
+
error = createAuthError(errorMessage, data, errorMessage);
|
|
1313
|
+
} else if (reason === "forbidden") {
|
|
1314
|
+
error = createPermissionError(errorMessage, data, errorMessage);
|
|
1315
|
+
} else if (reason === "rate_limit_exceeded") {
|
|
1316
|
+
error = createRateLimitError(errorMessage, retryAfter, data, errorMessage);
|
|
1317
|
+
} else if (reason === "not_found") {
|
|
1318
|
+
error = createNotFoundError(errorMessage, data, errorMessage);
|
|
1319
|
+
} else if (reason === "conflict") {
|
|
1320
|
+
error = createConflictError(errorMessage, data, errorMessage);
|
|
1321
|
+
} else {
|
|
1322
|
+
error = createApiError(
|
|
1323
|
+
errorMessage,
|
|
1324
|
+
response.status,
|
|
1325
|
+
data,
|
|
1326
|
+
errorMessage,
|
|
1327
|
+
"An error occurred while processing the request."
|
|
1328
|
+
);
|
|
1192
1329
|
}
|
|
1193
|
-
|
|
1194
|
-
|
|
1330
|
+
const withRequestId = attachRequestId(error, requestId);
|
|
1331
|
+
if (retryAfter !== void 0) Object.assign(withRequestId, { retryAfter });
|
|
1332
|
+
throw options.errorFamily === "commerce" ? enhanceCommerceError(withRequestId, data, requestId) : withRequestId;
|
|
1333
|
+
}
|
|
1334
|
+
return data;
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
// ../../internal/http-contracts/src/index.ts
|
|
1338
|
+
var operationBrand = /* @__PURE__ */ Symbol("sdk-http-operation");
|
|
1339
|
+
var operation = (collection, method, path) => Object.freeze({
|
|
1340
|
+
[operationBrand]: true,
|
|
1341
|
+
collection,
|
|
1342
|
+
method,
|
|
1343
|
+
path
|
|
1344
|
+
});
|
|
1345
|
+
var COMMERCE_ENDPOINT_OPERATIONS = {
|
|
1346
|
+
products: {
|
|
1347
|
+
detail: operation("products", "get", "/detail"),
|
|
1348
|
+
detailCatalog: operation("products", "get", "/detail/catalog"),
|
|
1349
|
+
listingGroups: operation("products", "get", "/listing-groups"),
|
|
1350
|
+
listingGroupsCatalog: operation(
|
|
1351
|
+
"products",
|
|
1352
|
+
"get",
|
|
1353
|
+
"/listing-groups/catalog"
|
|
1354
|
+
),
|
|
1355
|
+
listingGroupsQuery: operation("products", "post", "/listing-groups/query"),
|
|
1356
|
+
listingGroupsQueryGet: operation(
|
|
1357
|
+
"products",
|
|
1358
|
+
"get",
|
|
1359
|
+
"/listing-groups/query"
|
|
1360
|
+
),
|
|
1361
|
+
listingGroupsQueryCatalog: operation(
|
|
1362
|
+
"products",
|
|
1363
|
+
"get",
|
|
1364
|
+
"/listing-groups/query/catalog"
|
|
1365
|
+
),
|
|
1366
|
+
stockCheck: operation("products", "post", "/stock-check"),
|
|
1367
|
+
stockSnapshot: operation("products", "get", "/stock"),
|
|
1368
|
+
upsert: operation("products", "post", "/upsert")
|
|
1369
|
+
},
|
|
1370
|
+
orders: {
|
|
1371
|
+
create: operation("orders", "post", "/create"),
|
|
1372
|
+
update: operation("orders", "post", "/update"),
|
|
1373
|
+
confirmPayment: operation("orders", "post", "/confirm-payment"),
|
|
1374
|
+
byPayment: operation("orders", "get", "/by-payment"),
|
|
1375
|
+
cancel: operation("orders", "post", "/cancel"),
|
|
1376
|
+
resolveCancelRefund: operation("orders", "post", "/resolve-cancel-refund"),
|
|
1377
|
+
checkout: operation("orders", "post", "/checkout"),
|
|
1378
|
+
createFulfillment: operation("orders", "post", "/create-fulfillment"),
|
|
1379
|
+
updateFulfillment: operation("orders", "post", "/update-fulfillment")
|
|
1380
|
+
},
|
|
1381
|
+
checkouts: {
|
|
1382
|
+
detail: operation("checkouts", "post", "/detail"),
|
|
1383
|
+
query: operation("checkouts", "post", "/query")
|
|
1384
|
+
},
|
|
1385
|
+
transactions: {
|
|
1386
|
+
update: operation("transactions", "post", "/update")
|
|
1387
|
+
},
|
|
1388
|
+
returns: {
|
|
1389
|
+
create: operation("returns", "post", "/create"),
|
|
1390
|
+
update: operation("returns", "post", "/update"),
|
|
1391
|
+
returnRefund: operation("returns", "post", "/return-refund")
|
|
1392
|
+
},
|
|
1393
|
+
fulfillmentOrders: {
|
|
1394
|
+
prepare: operation(
|
|
1395
|
+
"fulfillment-orders",
|
|
1396
|
+
"post",
|
|
1397
|
+
"/prepare-fulfillment-order"
|
|
1398
|
+
)
|
|
1399
|
+
},
|
|
1400
|
+
fulfillments: {
|
|
1401
|
+
bulkImport: operation("fulfillments", "post", "/bulk-import")
|
|
1402
|
+
},
|
|
1403
|
+
carts: {
|
|
1404
|
+
create: operation("carts", "post", "/create"),
|
|
1405
|
+
retrieve: operation("carts", "post", "/retrieve"),
|
|
1406
|
+
mine: operation("carts", "post", "/mine"),
|
|
1407
|
+
merge: operation("carts", "post", "/merge"),
|
|
1408
|
+
addItem: operation("carts", "post", "/add-item"),
|
|
1409
|
+
updateItem: operation("carts", "post", "/update-item"),
|
|
1410
|
+
removeItem: operation("carts", "post", "/remove-item"),
|
|
1411
|
+
updateDiscountCodes: operation("carts", "post", "/update-discount-codes"),
|
|
1412
|
+
updateAttributes: operation("carts", "post", "/update-attributes"),
|
|
1413
|
+
clear: operation("carts", "post", "/clear")
|
|
1414
|
+
},
|
|
1415
|
+
paymentSessions: {
|
|
1416
|
+
create: operation("payment-sessions", "post", "/create"),
|
|
1417
|
+
retrieve: operation("payment-sessions", "post", "/retrieve"),
|
|
1418
|
+
cancel: operation("payment-sessions", "post", "/cancel"),
|
|
1419
|
+
server: {
|
|
1420
|
+
create: operation("payment-sessions", "post", "/server/create"),
|
|
1421
|
+
retrieve: operation("payment-sessions", "post", "/server/retrieve"),
|
|
1422
|
+
cancel: operation("payment-sessions", "post", "/server/cancel"),
|
|
1423
|
+
confirm: operation("payment-sessions", "post", "/server/confirm")
|
|
1424
|
+
},
|
|
1425
|
+
custom: {
|
|
1426
|
+
create: operation("orders", "post", "/custom-payment-sessions"),
|
|
1427
|
+
confirm: operation("orders", "post", "/custom-payment-sessions/confirm")
|
|
1195
1428
|
}
|
|
1196
|
-
|
|
1197
|
-
|
|
1429
|
+
},
|
|
1430
|
+
shippingPolicies: {
|
|
1431
|
+
calculate: operation("shipping-policies", "post", "/calculate")
|
|
1432
|
+
},
|
|
1433
|
+
discounts: {
|
|
1434
|
+
validate: operation("discounts", "post", "/validate")
|
|
1435
|
+
}
|
|
1436
|
+
};
|
|
1437
|
+
var MEMBERSHIP_ENDPOINT_OPERATIONS = {
|
|
1438
|
+
subscribe: operation(null, "post", "/memberships/subscribe"),
|
|
1439
|
+
cancel: operation(null, "post", "/memberships/:id/cancel"),
|
|
1440
|
+
me: operation(null, "get", "/memberships/me")
|
|
1441
|
+
};
|
|
1442
|
+
var EVENTS_ENDPOINT_OPERATIONS = {
|
|
1443
|
+
occurrences: {
|
|
1444
|
+
range: operation("event-occurrences", "get", "/range"),
|
|
1445
|
+
admissionAvailability: operation(
|
|
1446
|
+
"event-occurrences",
|
|
1447
|
+
"get",
|
|
1448
|
+
"/admission-availability"
|
|
1449
|
+
)
|
|
1450
|
+
}
|
|
1451
|
+
};
|
|
1452
|
+
function resolveOperationTemplate(descriptor) {
|
|
1453
|
+
return descriptor.collection ? `/api/${descriptor.collection}${descriptor.path}` : `/api${descriptor.path}`;
|
|
1454
|
+
}
|
|
1455
|
+
function resolveOperationPath(descriptor, options) {
|
|
1456
|
+
const path = resolveOperationTemplate(descriptor).replace(
|
|
1457
|
+
/:([A-Za-z][A-Za-z0-9_]*)/g,
|
|
1458
|
+
(_, key) => {
|
|
1459
|
+
const value = options?.pathParams?.[key];
|
|
1460
|
+
if (value === void 0) {
|
|
1461
|
+
throw new TypeError(`Missing path parameter: ${key}`);
|
|
1462
|
+
}
|
|
1463
|
+
return encodeURIComponent(value);
|
|
1198
1464
|
}
|
|
1199
|
-
|
|
1200
|
-
|
|
1465
|
+
);
|
|
1466
|
+
const unresolved = path.match(/:([A-Za-z][A-Za-z0-9_]*)/);
|
|
1467
|
+
if (unresolved) {
|
|
1468
|
+
throw new TypeError(`Missing path parameter: ${unresolved[1]}`);
|
|
1469
|
+
}
|
|
1470
|
+
const query = options?.query?.toString().replace(/^\?/, "");
|
|
1471
|
+
return query ? `${path}?${query}` : path;
|
|
1472
|
+
}
|
|
1473
|
+
function resolveOperationMethod(descriptor) {
|
|
1474
|
+
return descriptor.method.toUpperCase();
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
// src/core/api/endpoints.ts
|
|
1478
|
+
var endpoint = (method, path) => ({ method, path });
|
|
1479
|
+
var sharedEndpoint = (descriptor) => descriptor;
|
|
1480
|
+
function resolveOperationMethod2(descriptor) {
|
|
1481
|
+
return "collection" in descriptor ? resolveOperationMethod(descriptor) : descriptor.method;
|
|
1482
|
+
}
|
|
1483
|
+
function resolveOperationPath2(descriptor, options) {
|
|
1484
|
+
if ("collection" in descriptor) {
|
|
1485
|
+
return resolveOperationPath(descriptor, options);
|
|
1486
|
+
}
|
|
1487
|
+
const query = options?.query?.toString().replace(/^\?/, "");
|
|
1488
|
+
return query ? `${descriptor.path}?${query}` : descriptor.path;
|
|
1489
|
+
}
|
|
1490
|
+
var COMMERCE_ENDPOINTS = {
|
|
1491
|
+
products: {
|
|
1492
|
+
detail: endpoint("GET", "/api/products/detail"),
|
|
1493
|
+
detailCatalog: endpoint("GET", "/api/products/detail/catalog"),
|
|
1494
|
+
listingGroups: endpoint("GET", "/api/products/listing-groups"),
|
|
1495
|
+
listingGroupsCatalog: endpoint(
|
|
1496
|
+
"GET",
|
|
1497
|
+
"/api/products/listing-groups/catalog"
|
|
1498
|
+
),
|
|
1499
|
+
listingGroupsQuery: endpoint("GET", "/api/products/listing-groups/query"),
|
|
1500
|
+
listingGroupsQueryCatalog: endpoint(
|
|
1501
|
+
"GET",
|
|
1502
|
+
"/api/products/listing-groups/query/catalog"
|
|
1503
|
+
),
|
|
1504
|
+
stockCheck: endpoint("POST", "/api/products/stock-check"),
|
|
1505
|
+
stockSnapshot: endpoint("GET", "/api/products/stock"),
|
|
1506
|
+
upsert: endpoint("POST", "/api/products/upsert")
|
|
1507
|
+
},
|
|
1508
|
+
orders: {
|
|
1509
|
+
update: endpoint("POST", "/api/orders/update"),
|
|
1510
|
+
byPayment: endpoint("GET", "/api/orders/by-payment"),
|
|
1511
|
+
cancel: endpoint("POST", "/api/orders/cancel"),
|
|
1512
|
+
resolveCancelRefund: endpoint("POST", "/api/orders/resolve-cancel-refund"),
|
|
1513
|
+
createFulfillment: endpoint("POST", "/api/orders/create-fulfillment"),
|
|
1514
|
+
updateFulfillment: endpoint("POST", "/api/orders/update-fulfillment")
|
|
1515
|
+
},
|
|
1516
|
+
checkouts: {
|
|
1517
|
+
create: endpoint("POST", "/api/orders/checkout"),
|
|
1518
|
+
retrieve: endpoint("POST", "/api/checkouts/detail"),
|
|
1519
|
+
server: {
|
|
1520
|
+
create: endpoint("POST", "/api/orders/checkout"),
|
|
1521
|
+
retrieve: endpoint("POST", "/api/checkouts/detail"),
|
|
1522
|
+
query: endpoint("POST", "/api/checkouts/query")
|
|
1201
1523
|
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1524
|
+
},
|
|
1525
|
+
returns: {
|
|
1526
|
+
create: endpoint("POST", "/api/returns/create"),
|
|
1527
|
+
update: endpoint("POST", "/api/returns/update"),
|
|
1528
|
+
returnRefund: endpoint("POST", "/api/returns/return-refund")
|
|
1529
|
+
},
|
|
1530
|
+
fulfillmentOrders: {
|
|
1531
|
+
prepare: endpoint(
|
|
1532
|
+
"POST",
|
|
1533
|
+
"/api/fulfillment-orders/prepare-fulfillment-order"
|
|
1534
|
+
)
|
|
1535
|
+
},
|
|
1536
|
+
fulfillments: {
|
|
1537
|
+
bulkImport: endpoint("POST", "/api/fulfillments/bulk-import")
|
|
1538
|
+
},
|
|
1539
|
+
carts: {
|
|
1540
|
+
create: endpoint("POST", "/api/carts/create"),
|
|
1541
|
+
retrieve: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.retrieve),
|
|
1542
|
+
mine: endpoint("POST", "/api/carts/mine"),
|
|
1543
|
+
merge: endpoint("POST", "/api/carts/merge"),
|
|
1544
|
+
server: {
|
|
1545
|
+
// Server credentials are an authorization lane, not a second Cart
|
|
1546
|
+
// transport. These must stay bound to the registered shared operations.
|
|
1547
|
+
create: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.create),
|
|
1548
|
+
retrieve: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.retrieve),
|
|
1549
|
+
mine: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.mine),
|
|
1550
|
+
merge: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.merge),
|
|
1551
|
+
addItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.addItem),
|
|
1552
|
+
updateItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.updateItem),
|
|
1553
|
+
removeItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.removeItem),
|
|
1554
|
+
updateDiscountCodes: sharedEndpoint(
|
|
1555
|
+
COMMERCE_ENDPOINT_OPERATIONS.carts.updateDiscountCodes
|
|
1556
|
+
),
|
|
1557
|
+
updateAttributes: sharedEndpoint(
|
|
1558
|
+
COMMERCE_ENDPOINT_OPERATIONS.carts.updateAttributes
|
|
1559
|
+
),
|
|
1560
|
+
clear: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.clear)
|
|
1561
|
+
},
|
|
1562
|
+
addItem: sharedEndpoint(COMMERCE_ENDPOINT_OPERATIONS.carts.addItem),
|
|
1563
|
+
updateItem: endpoint("POST", "/api/carts/update-item"),
|
|
1564
|
+
removeItem: endpoint("POST", "/api/carts/remove-item"),
|
|
1565
|
+
updateDiscountCodes: endpoint("POST", "/api/carts/update-discount-codes"),
|
|
1566
|
+
updateAttributes: endpoint("POST", "/api/carts/update-attributes"),
|
|
1567
|
+
clear: endpoint("POST", "/api/carts/clear")
|
|
1568
|
+
},
|
|
1569
|
+
paymentSessions: {
|
|
1570
|
+
create: endpoint("POST", "/api/payment-sessions/create"),
|
|
1571
|
+
retrieve: endpoint("POST", "/api/payment-sessions/retrieve"),
|
|
1572
|
+
cancel: endpoint("POST", "/api/payment-sessions/cancel"),
|
|
1573
|
+
custom: {
|
|
1574
|
+
create: sharedEndpoint(
|
|
1575
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.custom.create
|
|
1576
|
+
),
|
|
1577
|
+
confirm: sharedEndpoint(
|
|
1578
|
+
COMMERCE_ENDPOINT_OPERATIONS.paymentSessions.custom.confirm
|
|
1579
|
+
)
|
|
1580
|
+
},
|
|
1581
|
+
server: {
|
|
1582
|
+
create: endpoint("POST", "/api/payment-sessions/server/create"),
|
|
1583
|
+
retrieve: endpoint("POST", "/api/payment-sessions/server/retrieve"),
|
|
1584
|
+
cancel: endpoint("POST", "/api/payment-sessions/server/cancel"),
|
|
1585
|
+
confirm: endpoint("POST", "/api/payment-sessions/server/confirm")
|
|
1204
1586
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
);
|
|
1587
|
+
},
|
|
1588
|
+
shippingPolicies: {
|
|
1589
|
+
calculate: endpoint("POST", "/api/shipping-policies/calculate")
|
|
1209
1590
|
}
|
|
1210
|
-
|
|
1591
|
+
};
|
|
1592
|
+
function isCommerceEndpointDescriptor(value) {
|
|
1593
|
+
if (!value || typeof value !== "object") return false;
|
|
1594
|
+
const candidate = value;
|
|
1595
|
+
return typeof candidate.method === "string" && typeof candidate.path === "string";
|
|
1596
|
+
}
|
|
1597
|
+
function flattenEndpointPaths(value) {
|
|
1598
|
+
if (isCommerceEndpointDescriptor(value)) return [resolveOperationPath2(value)];
|
|
1599
|
+
if (!value || typeof value !== "object") return [];
|
|
1600
|
+
return Object.values(value).flatMap((entry) => flattenEndpointPaths(entry));
|
|
1601
|
+
}
|
|
1602
|
+
function flattenEndpointDescriptors(value) {
|
|
1603
|
+
if (isCommerceEndpointDescriptor(value)) return [value];
|
|
1604
|
+
if (!value || typeof value !== "object") return [];
|
|
1605
|
+
return Object.values(value).flatMap(
|
|
1606
|
+
(entry) => flattenEndpointDescriptors(entry)
|
|
1607
|
+
);
|
|
1211
1608
|
}
|
|
1609
|
+
var COMMERCE_ENDPOINT_PATHS = flattenEndpointPaths(COMMERCE_ENDPOINTS);
|
|
1610
|
+
var COMMERCE_ENDPOINT_DESCRIPTORS = flattenEndpointDescriptors(COMMERCE_ENDPOINTS);
|
|
1611
|
+
var MEMBERSHIP_ENDPOINTS = {
|
|
1612
|
+
subscribe: "/api/memberships/subscribe",
|
|
1613
|
+
cancel: (id) => `/api/memberships/${id}/cancel`,
|
|
1614
|
+
me: "/api/memberships/me"
|
|
1615
|
+
};
|
|
1616
|
+
var MEMBERSHIP_ENDPOINT_PATHS = [
|
|
1617
|
+
MEMBERSHIP_ENDPOINTS.subscribe,
|
|
1618
|
+
MEMBERSHIP_ENDPOINTS.cancel(":id"),
|
|
1619
|
+
MEMBERSHIP_ENDPOINTS.me
|
|
1620
|
+
];
|
|
1212
1621
|
|
|
1213
1622
|
// src/core/api/customer-scoped-api.ts
|
|
1214
|
-
var
|
|
1623
|
+
var CustomerScopedTransport = class {
|
|
1215
1624
|
constructor(apiName, options) {
|
|
1216
1625
|
if (options.requiresCredential !== false && !options.secretKey && !options.customerToken) {
|
|
1217
1626
|
throw createConfigError(
|
|
@@ -1229,10 +1638,10 @@ var CustomerScopedApi = class {
|
|
|
1229
1638
|
this.onUnauthorized = options.onUnauthorized;
|
|
1230
1639
|
this.onRequestId = options.onRequestId;
|
|
1231
1640
|
}
|
|
1232
|
-
async request(
|
|
1641
|
+
async request(endpoint2, options) {
|
|
1233
1642
|
const token = typeof this.customerToken === "function" ? this.customerToken() : this.customerToken;
|
|
1234
1643
|
try {
|
|
1235
|
-
const response = await httpFetch(
|
|
1644
|
+
const response = await httpFetch(endpoint2, {
|
|
1236
1645
|
method: options.method,
|
|
1237
1646
|
apiUrl: this.apiUrl,
|
|
1238
1647
|
publishableKey: this.publishableKey,
|
|
@@ -1242,10 +1651,13 @@ var CustomerScopedApi = class {
|
|
|
1242
1651
|
...options.body !== void 0 && {
|
|
1243
1652
|
body: JSON.stringify(options.body)
|
|
1244
1653
|
},
|
|
1245
|
-
...options.headers && { headers: options.headers }
|
|
1654
|
+
...options.headers && { headers: options.headers },
|
|
1655
|
+
...options.errorFamily && { errorFamily: options.errorFamily }
|
|
1246
1656
|
});
|
|
1247
1657
|
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
1248
|
-
return parseApiResponse(response,
|
|
1658
|
+
return parseApiResponse(response, endpoint2, {
|
|
1659
|
+
errorFamily: options.errorFamily
|
|
1660
|
+
});
|
|
1249
1661
|
} catch (err) {
|
|
1250
1662
|
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
1251
1663
|
this.onRequestId?.(id);
|
|
@@ -1253,6 +1665,26 @@ var CustomerScopedApi = class {
|
|
|
1253
1665
|
}
|
|
1254
1666
|
}
|
|
1255
1667
|
};
|
|
1668
|
+
var CustomerScopedApi = class {
|
|
1669
|
+
constructor(apiName, options) {
|
|
1670
|
+
this.transport = new CustomerScopedTransport(apiName, options);
|
|
1671
|
+
}
|
|
1672
|
+
requestEndpoint(endpoint2, body, options) {
|
|
1673
|
+
return this.transport.request(resolveOperationPath2(endpoint2, options), {
|
|
1674
|
+
method: resolveOperationMethod2(endpoint2),
|
|
1675
|
+
body,
|
|
1676
|
+
headers: options?.headers
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
};
|
|
1680
|
+
var RawCustomerScopedApi = class {
|
|
1681
|
+
constructor(apiName, options) {
|
|
1682
|
+
this.transport = new CustomerScopedTransport(apiName, options);
|
|
1683
|
+
}
|
|
1684
|
+
request(endpoint2, options) {
|
|
1685
|
+
return this.transport.request(endpoint2, options);
|
|
1686
|
+
}
|
|
1687
|
+
};
|
|
1256
1688
|
|
|
1257
1689
|
// src/core/community/community-client.ts
|
|
1258
1690
|
var DEFAULT_POST_LIST_SORT = "-lastActivityAt";
|
|
@@ -1263,7 +1695,7 @@ function unwrapPayloadDoc(value) {
|
|
|
1263
1695
|
}
|
|
1264
1696
|
return value;
|
|
1265
1697
|
}
|
|
1266
|
-
var CommunityClient = class extends
|
|
1698
|
+
var CommunityClient = class extends RawCustomerScopedApi {
|
|
1267
1699
|
constructor(options) {
|
|
1268
1700
|
super("CommunityClient", { ...options, requiresCredential: false });
|
|
1269
1701
|
}
|
|
@@ -1307,11 +1739,11 @@ var CommunityClient = class extends CustomerScopedApi {
|
|
|
1307
1739
|
if (params.page !== void 0) urlParams.set("page", String(params.page));
|
|
1308
1740
|
return `/api/comments/public?${urlParams.toString()}`;
|
|
1309
1741
|
}
|
|
1310
|
-
async execute(
|
|
1311
|
-
return this.request(
|
|
1742
|
+
async execute(endpoint2, method, body) {
|
|
1743
|
+
return this.request(endpoint2, { method, body });
|
|
1312
1744
|
}
|
|
1313
|
-
async executeDoc(
|
|
1314
|
-
const response = await this.execute(
|
|
1745
|
+
async executeDoc(endpoint2, method, body) {
|
|
1746
|
+
const response = await this.execute(endpoint2, method, body);
|
|
1315
1747
|
return unwrapPayloadDoc(response);
|
|
1316
1748
|
}
|
|
1317
1749
|
createPost(params) {
|
|
@@ -1547,56 +1979,1538 @@ var CommunityClient = class extends CustomerScopedApi {
|
|
|
1547
1979
|
body
|
|
1548
1980
|
);
|
|
1549
1981
|
}
|
|
1550
|
-
};
|
|
1551
|
-
|
|
1552
|
-
// src/core/content/content-client.ts
|
|
1553
|
-
var PublicContentApi = class extends
|
|
1554
|
-
get(
|
|
1555
|
-
return this.request(
|
|
1556
|
-
}
|
|
1557
|
-
};
|
|
1558
|
-
function appendCommonParams(search, options, defaultSort) {
|
|
1559
|
-
search.set("sort", options?.sort ?? defaultSort);
|
|
1560
|
-
if (options?.page != null) search.set("page", String(options.page));
|
|
1561
|
-
if (options?.limit != null) search.set("limit", String(options.limit));
|
|
1562
|
-
}
|
|
1563
|
-
function linksListPath(options) {
|
|
1564
|
-
const search = new URLSearchParams();
|
|
1565
|
-
appendCommonParams(search, options, "-publishedAt,-createdAt");
|
|
1566
|
-
if (options?.categoryId) search.set("categoryId", options.categoryId);
|
|
1567
|
-
if (options?.categorySlug) {
|
|
1568
|
-
search.set("categorySlug", options.categorySlug);
|
|
1569
|
-
}
|
|
1570
|
-
if (options?.tagId) search.set("tagId", options.tagId);
|
|
1571
|
-
if (options?.tagSlug) search.set("tagSlug", options.tagSlug);
|
|
1572
|
-
if (options?.featured != null)
|
|
1573
|
-
|
|
1574
|
-
}
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
if (options?.
|
|
1580
|
-
|
|
1982
|
+
};
|
|
1983
|
+
|
|
1984
|
+
// src/core/content/content-client.ts
|
|
1985
|
+
var PublicContentApi = class extends RawCustomerScopedApi {
|
|
1986
|
+
get(endpoint2) {
|
|
1987
|
+
return this.request(endpoint2, { method: "GET" });
|
|
1988
|
+
}
|
|
1989
|
+
};
|
|
1990
|
+
function appendCommonParams(search, options, defaultSort) {
|
|
1991
|
+
search.set("sort", options?.sort ?? defaultSort);
|
|
1992
|
+
if (options?.page != null) search.set("page", String(options.page));
|
|
1993
|
+
if (options?.limit != null) search.set("limit", String(options.limit));
|
|
1994
|
+
}
|
|
1995
|
+
function linksListPath(options) {
|
|
1996
|
+
const search = new URLSearchParams();
|
|
1997
|
+
appendCommonParams(search, options, "-publishedAt,-createdAt");
|
|
1998
|
+
if (options?.categoryId) search.set("categoryId", options.categoryId);
|
|
1999
|
+
if (options?.categorySlug) {
|
|
2000
|
+
search.set("categorySlug", options.categorySlug);
|
|
2001
|
+
}
|
|
2002
|
+
if (options?.tagId) search.set("tagId", options.tagId);
|
|
2003
|
+
if (options?.tagSlug) search.set("tagSlug", options.tagSlug);
|
|
2004
|
+
if (options?.featured != null)
|
|
2005
|
+
search.set("featured", String(options.featured));
|
|
2006
|
+
return `/api/links/storefront?${search}`;
|
|
2007
|
+
}
|
|
2008
|
+
function galleryItemsListPath(options) {
|
|
2009
|
+
const search = new URLSearchParams();
|
|
2010
|
+
appendCommonParams(search, options, "manual");
|
|
2011
|
+
if (options?.galleryId) search.set("galleryId", options.galleryId);
|
|
2012
|
+
if (options?.gallerySlug) search.set("gallerySlug", options.gallerySlug);
|
|
2013
|
+
return `/api/gallery-items/storefront?${search}`;
|
|
2014
|
+
}
|
|
2015
|
+
var ContentClient = class {
|
|
2016
|
+
constructor(options) {
|
|
2017
|
+
const api = new PublicContentApi("ContentClient", {
|
|
2018
|
+
publishableKey: options.publishableKey,
|
|
2019
|
+
apiUrl: options.apiUrl,
|
|
2020
|
+
onRequestId: options.onRequestId,
|
|
2021
|
+
requiresCredential: false
|
|
2022
|
+
});
|
|
2023
|
+
this.links = {
|
|
2024
|
+
list: (params) => api.get(linksListPath(params))
|
|
2025
|
+
};
|
|
2026
|
+
this.galleryItems = {
|
|
2027
|
+
list: (params) => api.get(
|
|
2028
|
+
galleryItemsListPath(params)
|
|
2029
|
+
)
|
|
2030
|
+
};
|
|
2031
|
+
}
|
|
2032
|
+
};
|
|
2033
|
+
|
|
2034
|
+
// src/core/api/canonical-response.ts
|
|
2035
|
+
var CART_STATUSES = ["active", "completed", "abandoned"];
|
|
2036
|
+
var MAX_CART_LINE_QUANTITY = 99;
|
|
2037
|
+
var MAX_COMMERCE_SHORT_TEXT_LENGTH = 200;
|
|
2038
|
+
var MAX_COMMERCE_ADDRESS_LENGTH = 500;
|
|
2039
|
+
var MAX_COMMERCE_EMAIL_LENGTH = 254;
|
|
2040
|
+
var MAX_COMMERCE_PHONE_LENGTH = 32;
|
|
2041
|
+
var MAX_COMMERCE_POSTAL_CODE_LENGTH = 32;
|
|
2042
|
+
var MAX_COMMERCE_EXTENSION_VALUE_LENGTH = 500;
|
|
2043
|
+
var MAX_COMMERCE_RESOURCE_ID_LENGTH = 255;
|
|
2044
|
+
var MAX_COMMERCE_CAPABILITY_LENGTH = 512;
|
|
2045
|
+
var MAX_CART_DISCOUNT_CODE_LENGTH = 128;
|
|
2046
|
+
var ORDER_FINANCIAL_STATUSES = [
|
|
2047
|
+
"pending",
|
|
2048
|
+
"authorized",
|
|
2049
|
+
"expired",
|
|
2050
|
+
"partially_paid",
|
|
2051
|
+
"paid",
|
|
2052
|
+
"canceled",
|
|
2053
|
+
"partially_refunded",
|
|
2054
|
+
"refunded",
|
|
2055
|
+
"reconciliation_required"
|
|
2056
|
+
];
|
|
2057
|
+
var ORDER_FULFILLMENT_STATUSES = [
|
|
2058
|
+
"unfulfilled",
|
|
2059
|
+
"in_progress",
|
|
2060
|
+
"on_hold",
|
|
2061
|
+
"partially_fulfilled",
|
|
2062
|
+
"shipped",
|
|
2063
|
+
"fulfilled",
|
|
2064
|
+
"canceled"
|
|
2065
|
+
];
|
|
2066
|
+
var ORDER_RETURN_STATUSES = [
|
|
2067
|
+
"no_return",
|
|
2068
|
+
"return_requested",
|
|
2069
|
+
"in_progress",
|
|
2070
|
+
"returned"
|
|
2071
|
+
];
|
|
2072
|
+
var ORDER_CONFIRMATION_STATUSES = ["unconfirmed", "confirmed"];
|
|
2073
|
+
var ORDER_PRIMARY_DISPLAY_STATUSES = [
|
|
2074
|
+
"pending",
|
|
2075
|
+
"paid",
|
|
2076
|
+
"canceled",
|
|
2077
|
+
"refunded",
|
|
2078
|
+
"preparing",
|
|
2079
|
+
"shipped",
|
|
2080
|
+
"delivered",
|
|
2081
|
+
"confirmed"
|
|
2082
|
+
];
|
|
2083
|
+
var CHECKOUT_STATUSES = ["open", "placed", "abandoned"];
|
|
2084
|
+
var ABANDONED_REASONS = ["expired", "customer", "operator"];
|
|
2085
|
+
var PAYMENT_PROVIDERS = ["toss"];
|
|
2086
|
+
var PAYMENT_PROVIDER_STATUSES = [
|
|
2087
|
+
"requires_payment_method",
|
|
2088
|
+
"requires_action",
|
|
2089
|
+
"requires_confirmation",
|
|
2090
|
+
"initializing",
|
|
2091
|
+
"processing",
|
|
2092
|
+
"authorized",
|
|
2093
|
+
"canceling",
|
|
2094
|
+
"unknown",
|
|
2095
|
+
"captured",
|
|
2096
|
+
"failed",
|
|
2097
|
+
"canceled"
|
|
2098
|
+
];
|
|
2099
|
+
var PAYMENT_FAILURE_REASONS = [
|
|
2100
|
+
"payment_declined",
|
|
2101
|
+
"authentication_failed",
|
|
2102
|
+
"authorization_expired",
|
|
2103
|
+
"payment_method_unavailable",
|
|
2104
|
+
"provider_terminal_failure",
|
|
2105
|
+
"unknown_provider_terminal_failure"
|
|
2106
|
+
];
|
|
2107
|
+
var CART_WARNING_CODES = [
|
|
2108
|
+
"DISCOUNT_CODE_NOT_HONOURED",
|
|
2109
|
+
"DISCOUNT_CURRENTLY_INACTIVE",
|
|
2110
|
+
"DISCOUNT_CUSTOMER_NOT_ELIGIBLE",
|
|
2111
|
+
"DISCOUNT_CUSTOMER_USAGE_LIMIT_REACHED",
|
|
2112
|
+
"DISCOUNT_ELIGIBLE_CUSTOMER_MISSING",
|
|
2113
|
+
"DISCOUNT_NO_ENTITLED_LINE_ITEMS",
|
|
2114
|
+
"DISCOUNT_NO_ENTITLED_SHIPPING_LINES",
|
|
2115
|
+
"DISCOUNT_NOT_FOUND",
|
|
2116
|
+
"DISCOUNT_PURCHASE_NOT_IN_RANGE",
|
|
2117
|
+
"DISCOUNT_USAGE_LIMIT_REACHED",
|
|
2118
|
+
"MERCHANDISE_NOT_ENOUGH_STOCK",
|
|
2119
|
+
"MERCHANDISE_OUT_OF_STOCK"
|
|
2120
|
+
];
|
|
2121
|
+
function invalidCanonicalResponse(resource, details) {
|
|
2122
|
+
throw createApiError(
|
|
2123
|
+
`Invalid canonical ${resource} response.`,
|
|
2124
|
+
502,
|
|
2125
|
+
{ resource, ...details },
|
|
2126
|
+
`The server returned an incompatible ${resource} response.`,
|
|
2127
|
+
"Verify that the Console commerce contract is deployed before using this SDK version."
|
|
2128
|
+
);
|
|
2129
|
+
}
|
|
2130
|
+
function fail(resource, path, expected) {
|
|
2131
|
+
invalidCanonicalResponse(resource, { path, expected });
|
|
2132
|
+
}
|
|
2133
|
+
function record(value, resource, path) {
|
|
2134
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2135
|
+
fail(resource, path, "object");
|
|
2136
|
+
}
|
|
2137
|
+
return value;
|
|
2138
|
+
}
|
|
2139
|
+
function exact(value, required, optional, resource, path) {
|
|
2140
|
+
for (const key of required) {
|
|
2141
|
+
if (!(key in value)) fail(resource, `${path}.${key}`, "required field");
|
|
2142
|
+
}
|
|
2143
|
+
const allowed = /* @__PURE__ */ new Set([...required, ...optional]);
|
|
2144
|
+
const unexpected = Object.keys(value).find((key) => !allowed.has(key));
|
|
2145
|
+
if (unexpected) fail(resource, `${path}.${unexpected}`, "no unknown fields");
|
|
2146
|
+
}
|
|
2147
|
+
function string(value, resource, path) {
|
|
2148
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
2149
|
+
fail(resource, path, "non-empty string");
|
|
2150
|
+
}
|
|
2151
|
+
return value;
|
|
2152
|
+
}
|
|
2153
|
+
function boundedString(value, maxLength, resource, path, allowEmpty = false) {
|
|
2154
|
+
if (typeof value !== "string" || !allowEmpty && value.length === 0 || value.length > maxLength) {
|
|
2155
|
+
fail(
|
|
2156
|
+
resource,
|
|
2157
|
+
path,
|
|
2158
|
+
`${allowEmpty ? "" : "non-empty "}string of at most ${maxLength} characters`
|
|
2159
|
+
);
|
|
2160
|
+
}
|
|
2161
|
+
return value;
|
|
2162
|
+
}
|
|
2163
|
+
function nullableString(value, resource, path) {
|
|
2164
|
+
if (value !== null && typeof value !== "string") {
|
|
2165
|
+
fail(resource, path, "string or null");
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
function cartLineQuantity(value, resource, path) {
|
|
2169
|
+
const quantity = positiveInteger(value, resource, path);
|
|
2170
|
+
if (quantity > MAX_CART_LINE_QUANTITY) {
|
|
2171
|
+
fail(resource, path, `integer between 1 and ${MAX_CART_LINE_QUANTITY}`);
|
|
2172
|
+
}
|
|
2173
|
+
return quantity;
|
|
2174
|
+
}
|
|
2175
|
+
function boolean(value, resource, path) {
|
|
2176
|
+
if (typeof value !== "boolean") fail(resource, path, "boolean");
|
|
2177
|
+
}
|
|
2178
|
+
function safeMinor(value, resource, path) {
|
|
2179
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
2180
|
+
fail(resource, path, "non-negative safe integer");
|
|
2181
|
+
}
|
|
2182
|
+
return value;
|
|
2183
|
+
}
|
|
2184
|
+
function positiveInteger(value, resource, path) {
|
|
2185
|
+
if (!Number.isSafeInteger(value) || value <= 0) {
|
|
2186
|
+
fail(resource, path, "positive safe integer");
|
|
2187
|
+
}
|
|
2188
|
+
return value;
|
|
2189
|
+
}
|
|
2190
|
+
function enumValue(value, values, resource, path) {
|
|
2191
|
+
if (typeof value !== "string" || !values.includes(value)) {
|
|
2192
|
+
fail(resource, path, values.join(" | "));
|
|
2193
|
+
}
|
|
2194
|
+
return value;
|
|
2195
|
+
}
|
|
2196
|
+
function timestamp(value, resource, path) {
|
|
2197
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}T.*(?:Z|[+-]\d{2}:\d{2})$/.test(value) || !Number.isFinite(Date.parse(value))) {
|
|
2198
|
+
fail(resource, path, "ISO 8601 timestamp with offset");
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
function currency(value, resource, path) {
|
|
2202
|
+
if (typeof value !== "string" || !/^[A-Z]{3}$/.test(value)) {
|
|
2203
|
+
fail(resource, path, "three-letter uppercase currency code");
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
function array(value, resource, path) {
|
|
2207
|
+
if (!Array.isArray(value)) fail(resource, path, "array");
|
|
2208
|
+
return value;
|
|
2209
|
+
}
|
|
2210
|
+
function optionalNullableNumber(value, resource, path) {
|
|
2211
|
+
if (value !== void 0 && value !== null && typeof value !== "number") {
|
|
2212
|
+
fail(resource, path, "number or null");
|
|
2213
|
+
}
|
|
2214
|
+
}
|
|
2215
|
+
function validateMediaSize(value, resource, path) {
|
|
2216
|
+
const item = record(value, resource, path);
|
|
2217
|
+
exact(
|
|
2218
|
+
item,
|
|
2219
|
+
[],
|
|
2220
|
+
["width", "height", "mimeType", "filename", "url"],
|
|
2221
|
+
resource,
|
|
2222
|
+
path
|
|
2223
|
+
);
|
|
2224
|
+
optionalNullableNumber(item.width, resource, `${path}.width`);
|
|
2225
|
+
optionalNullableNumber(item.height, resource, `${path}.height`);
|
|
2226
|
+
for (const key of ["mimeType", "filename", "url"]) {
|
|
2227
|
+
if (item[key] !== void 0)
|
|
2228
|
+
nullableString(item[key], resource, `${path}.${key}`);
|
|
2229
|
+
}
|
|
2230
|
+
}
|
|
2231
|
+
function validateMedia(value, resource, path) {
|
|
2232
|
+
if (typeof value === "string") return;
|
|
2233
|
+
const media = record(value, resource, path);
|
|
2234
|
+
exact(
|
|
2235
|
+
media,
|
|
2236
|
+
[],
|
|
2237
|
+
["id", "alt", "width", "height", "mimeType", "filename", "url", "sizes"],
|
|
2238
|
+
resource,
|
|
2239
|
+
path
|
|
2240
|
+
);
|
|
2241
|
+
if (media.id !== void 0 && media.id !== null && typeof media.id !== "string" && typeof media.id !== "number") {
|
|
2242
|
+
fail(resource, `${path}.id`, "string, number, or null");
|
|
2243
|
+
}
|
|
2244
|
+
for (const key of ["alt", "mimeType", "filename", "url"]) {
|
|
2245
|
+
if (media[key] !== void 0)
|
|
2246
|
+
nullableString(media[key], resource, `${path}.${key}`);
|
|
2247
|
+
}
|
|
2248
|
+
optionalNullableNumber(media.width, resource, `${path}.width`);
|
|
2249
|
+
optionalNullableNumber(media.height, resource, `${path}.height`);
|
|
2250
|
+
if (media.sizes !== void 0) {
|
|
2251
|
+
const sizes = record(media.sizes, resource, `${path}.sizes`);
|
|
2252
|
+
Object.entries(sizes).forEach(
|
|
2253
|
+
([key, size]) => validateMediaSize(size, resource, `${path}.sizes.${key}`)
|
|
2254
|
+
);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
function validateReference(value, resource, path) {
|
|
2258
|
+
const ref = record(value, resource, path);
|
|
2259
|
+
exact(ref, ["id", "title", "handle", "image"], [], resource, path);
|
|
2260
|
+
string(ref.id, resource, `${path}.id`);
|
|
2261
|
+
string(ref.title, resource, `${path}.title`);
|
|
2262
|
+
if (ref.handle !== null) string(ref.handle, resource, `${path}.handle`);
|
|
2263
|
+
if (ref.image !== null) validateMedia(ref.image, resource, `${path}.image`);
|
|
2264
|
+
}
|
|
2265
|
+
function validateAdmission(value, resource, path) {
|
|
2266
|
+
const admission = record(value, resource, path);
|
|
2267
|
+
exact(
|
|
2268
|
+
admission,
|
|
2269
|
+
["eventId", "occurrenceId", "admissionTypeId"],
|
|
2270
|
+
[],
|
|
2271
|
+
resource,
|
|
2272
|
+
path
|
|
2273
|
+
);
|
|
2274
|
+
string(admission.eventId, resource, `${path}.eventId`);
|
|
2275
|
+
string(admission.occurrenceId, resource, `${path}.occurrenceId`);
|
|
2276
|
+
string(admission.admissionTypeId, resource, `${path}.admissionTypeId`);
|
|
2277
|
+
}
|
|
2278
|
+
function compareAdmissions(left, right) {
|
|
2279
|
+
for (const field of ["eventId", "occurrenceId", "admissionTypeId"]) {
|
|
2280
|
+
if (left[field] < right[field]) return -1;
|
|
2281
|
+
if (left[field] > right[field]) return 1;
|
|
2282
|
+
}
|
|
2283
|
+
return 0;
|
|
2284
|
+
}
|
|
2285
|
+
function validateAdmissions(value, resource, path) {
|
|
2286
|
+
const admissions = array(value, resource, path);
|
|
2287
|
+
if (admissions.length > 32) fail(resource, path, "at most 32 admissions");
|
|
2288
|
+
let prior;
|
|
2289
|
+
admissions.forEach((admission, index) => {
|
|
2290
|
+
validateAdmission(admission, resource, `${path}[${index}]`);
|
|
2291
|
+
const item = admission;
|
|
2292
|
+
const comparison = prior ? compareAdmissions(item, prior) : void 0;
|
|
2293
|
+
if (comparison !== void 0 && comparison <= 0) {
|
|
2294
|
+
fail(resource, `${path}[${index}]`, "unique canonical-sorted admissions");
|
|
2295
|
+
}
|
|
2296
|
+
prior = item;
|
|
2297
|
+
});
|
|
2298
|
+
}
|
|
2299
|
+
function validateAttributes(value, resource, path) {
|
|
2300
|
+
const attributes = array(value, resource, path);
|
|
2301
|
+
if (attributes.length > 50) fail(resource, path, "at most 50 attributes");
|
|
2302
|
+
const keys = /* @__PURE__ */ new Set();
|
|
2303
|
+
attributes.forEach((value2, index) => {
|
|
2304
|
+
const itemPath = `${path}[${index}]`;
|
|
2305
|
+
const attribute = record(value2, resource, itemPath);
|
|
2306
|
+
exact(attribute, ["key", "value"], [], resource, itemPath);
|
|
2307
|
+
const key = string(attribute.key, resource, `${itemPath}.key`);
|
|
2308
|
+
if (key.length > 40 || key.startsWith("__") || keys.has(key)) {
|
|
2309
|
+
fail(
|
|
2310
|
+
resource,
|
|
2311
|
+
`${itemPath}.key`,
|
|
2312
|
+
"unique, non-reserved key of at most 40 characters"
|
|
2313
|
+
);
|
|
2314
|
+
}
|
|
2315
|
+
keys.add(key);
|
|
2316
|
+
if (typeof attribute.value !== "string" || attribute.value.length > 500) {
|
|
2317
|
+
fail(resource, `${itemPath}.value`, "string of at most 500 characters");
|
|
2318
|
+
}
|
|
2319
|
+
});
|
|
2320
|
+
}
|
|
2321
|
+
function validateCustomer(value, resource, path) {
|
|
2322
|
+
const customer = record(value, resource, path);
|
|
2323
|
+
exact(customer, ["email"], ["name", "phone"], resource, path);
|
|
2324
|
+
const email = boundedString(
|
|
2325
|
+
customer.email,
|
|
2326
|
+
MAX_COMMERCE_EMAIL_LENGTH,
|
|
2327
|
+
resource,
|
|
2328
|
+
`${path}.email`
|
|
2329
|
+
);
|
|
2330
|
+
if (!/^(?!\.)(?!.*\.\.)([A-Za-z0-9_'+\-.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9-]*\.)+[A-Za-z]{2,}$/.test(
|
|
2331
|
+
email
|
|
2332
|
+
)) {
|
|
2333
|
+
fail(resource, `${path}.email`, "email address");
|
|
2334
|
+
}
|
|
2335
|
+
if (customer.name !== void 0)
|
|
2336
|
+
boundedString(
|
|
2337
|
+
customer.name,
|
|
2338
|
+
MAX_COMMERCE_SHORT_TEXT_LENGTH,
|
|
2339
|
+
resource,
|
|
2340
|
+
`${path}.name`
|
|
2341
|
+
);
|
|
2342
|
+
if (customer.phone !== void 0)
|
|
2343
|
+
boundedString(
|
|
2344
|
+
customer.phone,
|
|
2345
|
+
MAX_COMMERCE_PHONE_LENGTH,
|
|
2346
|
+
resource,
|
|
2347
|
+
`${path}.phone`
|
|
2348
|
+
);
|
|
2349
|
+
}
|
|
2350
|
+
function validateShippingAddress(value, resource, path) {
|
|
2351
|
+
const address = record(value, resource, path);
|
|
2352
|
+
exact(
|
|
2353
|
+
address,
|
|
2354
|
+
["recipientName", "phone", "postalCode", "address", "detailAddress"],
|
|
2355
|
+
["countryCode", "regionCode", "deliveryMessage"],
|
|
2356
|
+
resource,
|
|
2357
|
+
path
|
|
2358
|
+
);
|
|
2359
|
+
boundedString(
|
|
2360
|
+
address.recipientName,
|
|
2361
|
+
MAX_COMMERCE_SHORT_TEXT_LENGTH,
|
|
2362
|
+
resource,
|
|
2363
|
+
`${path}.recipientName`
|
|
2364
|
+
);
|
|
2365
|
+
boundedString(
|
|
2366
|
+
address.phone,
|
|
2367
|
+
MAX_COMMERCE_PHONE_LENGTH,
|
|
2368
|
+
resource,
|
|
2369
|
+
`${path}.phone`
|
|
2370
|
+
);
|
|
2371
|
+
boundedString(
|
|
2372
|
+
address.postalCode,
|
|
2373
|
+
MAX_COMMERCE_POSTAL_CODE_LENGTH,
|
|
2374
|
+
resource,
|
|
2375
|
+
`${path}.postalCode`
|
|
2376
|
+
);
|
|
2377
|
+
for (const key of ["address", "detailAddress"]) {
|
|
2378
|
+
boundedString(
|
|
2379
|
+
address[key],
|
|
2380
|
+
MAX_COMMERCE_ADDRESS_LENGTH,
|
|
2381
|
+
resource,
|
|
2382
|
+
`${path}.${key}`
|
|
2383
|
+
);
|
|
2384
|
+
}
|
|
2385
|
+
if (address.countryCode !== void 0) {
|
|
2386
|
+
if (typeof address.countryCode !== "string" || address.countryCode.trim().length !== 2) {
|
|
2387
|
+
fail(resource, `${path}.countryCode`, "two-letter country code");
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
if (address.regionCode !== void 0) {
|
|
2391
|
+
if (typeof address.regionCode !== "string" || address.regionCode.trim().length === 0 || address.regionCode.trim().length > 64) {
|
|
2392
|
+
fail(
|
|
2393
|
+
resource,
|
|
2394
|
+
`${path}.regionCode`,
|
|
2395
|
+
"trimmed string of at most 64 characters"
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
}
|
|
2399
|
+
if (address.deliveryMessage !== void 0) {
|
|
2400
|
+
boundedString(
|
|
2401
|
+
address.deliveryMessage,
|
|
2402
|
+
MAX_COMMERCE_EXTENSION_VALUE_LENGTH,
|
|
2403
|
+
resource,
|
|
2404
|
+
`${path}.deliveryMessage`,
|
|
2405
|
+
true
|
|
2406
|
+
);
|
|
2407
|
+
}
|
|
2408
|
+
}
|
|
2409
|
+
function validateOrderReference(value, resource, path) {
|
|
2410
|
+
const order = record(value, resource, path);
|
|
2411
|
+
exact(order, ["id", "orderNumber"], [], resource, path);
|
|
2412
|
+
string(order.id, resource, `${path}.id`);
|
|
2413
|
+
string(order.orderNumber, resource, `${path}.orderNumber`);
|
|
2414
|
+
}
|
|
2415
|
+
function validateIntegrationMetadata(value, resource, path) {
|
|
2416
|
+
const metadata = record(value, resource, path);
|
|
2417
|
+
if (Object.keys(metadata).length > 50)
|
|
2418
|
+
fail(resource, path, "at most 50 entries");
|
|
2419
|
+
Object.entries(metadata).forEach(([key, entry]) => {
|
|
2420
|
+
if (!key || key.length > 40 || key.includes("[") || key.includes("]")) {
|
|
2421
|
+
fail(resource, `${path}.${key}`, "valid metadata key");
|
|
2422
|
+
}
|
|
2423
|
+
if (typeof entry !== "string" || entry.length > 500) {
|
|
2424
|
+
fail(resource, `${path}.${key}`, "string of at most 500 characters");
|
|
2425
|
+
}
|
|
2426
|
+
});
|
|
2427
|
+
}
|
|
2428
|
+
function validateCartItem(value, resource, path) {
|
|
2429
|
+
const item = record(value, resource, path);
|
|
2430
|
+
exact(
|
|
2431
|
+
item,
|
|
2432
|
+
[
|
|
2433
|
+
"id",
|
|
2434
|
+
"product",
|
|
2435
|
+
"variant",
|
|
2436
|
+
"admissions",
|
|
2437
|
+
"quantity",
|
|
2438
|
+
"unitPriceMinor",
|
|
2439
|
+
"discountMinor",
|
|
2440
|
+
"estimatedLineTotalMinor",
|
|
2441
|
+
"requiresShipping"
|
|
2442
|
+
],
|
|
2443
|
+
[],
|
|
2444
|
+
resource,
|
|
2445
|
+
path
|
|
2446
|
+
);
|
|
2447
|
+
string(item.id, resource, `${path}.id`);
|
|
2448
|
+
validateReference(item.product, resource, `${path}.product`);
|
|
2449
|
+
validateReference(item.variant, resource, `${path}.variant`);
|
|
2450
|
+
validateAdmissions(item.admissions, resource, `${path}.admissions`);
|
|
2451
|
+
cartLineQuantity(item.quantity, resource, `${path}.quantity`);
|
|
2452
|
+
const unitPrice = safeMinor(
|
|
2453
|
+
item.unitPriceMinor,
|
|
2454
|
+
resource,
|
|
2455
|
+
`${path}.unitPriceMinor`
|
|
2456
|
+
);
|
|
2457
|
+
const discount = safeMinor(
|
|
2458
|
+
item.discountMinor,
|
|
2459
|
+
resource,
|
|
2460
|
+
`${path}.discountMinor`
|
|
2461
|
+
);
|
|
2462
|
+
const estimatedLineTotal = safeMinor(
|
|
2463
|
+
item.estimatedLineTotalMinor,
|
|
2464
|
+
resource,
|
|
2465
|
+
`${path}.estimatedLineTotalMinor`
|
|
2466
|
+
);
|
|
2467
|
+
const quantity = item.quantity;
|
|
2468
|
+
const expectedLineTotal = BigInt(unitPrice) * BigInt(quantity) - BigInt(discount);
|
|
2469
|
+
if (expectedLineTotal < 0n || BigInt(estimatedLineTotal) !== expectedLineTotal) {
|
|
2470
|
+
fail(
|
|
2471
|
+
resource,
|
|
2472
|
+
`${path}.estimatedLineTotalMinor`,
|
|
2473
|
+
"unitPriceMinor * quantity - discountMinor"
|
|
2474
|
+
);
|
|
2475
|
+
}
|
|
2476
|
+
boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
|
|
2477
|
+
}
|
|
2478
|
+
function validatePublicCart(value, resource = "Cart") {
|
|
2479
|
+
const cart = record(value, resource, "$");
|
|
2480
|
+
exact(
|
|
2481
|
+
cart,
|
|
2482
|
+
[
|
|
2483
|
+
"id",
|
|
2484
|
+
"status",
|
|
2485
|
+
"revision",
|
|
2486
|
+
"currency",
|
|
2487
|
+
"market",
|
|
2488
|
+
"subtotalMinor",
|
|
2489
|
+
"discountMinor",
|
|
2490
|
+
"estimatedTotalMinor",
|
|
2491
|
+
"discountCodes",
|
|
2492
|
+
"attributes",
|
|
2493
|
+
"items",
|
|
2494
|
+
"expiresAt",
|
|
2495
|
+
"createdAt",
|
|
2496
|
+
"updatedAt"
|
|
2497
|
+
],
|
|
2498
|
+
[],
|
|
2499
|
+
resource,
|
|
2500
|
+
"$"
|
|
2501
|
+
);
|
|
2502
|
+
string(cart.id, resource, "$.id");
|
|
2503
|
+
enumValue(cart.status, CART_STATUSES, resource, "$.status");
|
|
2504
|
+
safeMinor(cart.revision, resource, "$.revision");
|
|
2505
|
+
currency(cart.currency, resource, "$.currency");
|
|
2506
|
+
const market = record(cart.market, resource, "$.market");
|
|
2507
|
+
exact(market, ["id", "handle", "name"], [], resource, "$.market");
|
|
2508
|
+
for (const key of ["id", "handle", "name"])
|
|
2509
|
+
string(market[key], resource, `$.market.${key}`);
|
|
2510
|
+
const subtotal = safeMinor(cart.subtotalMinor, resource, "$.subtotalMinor");
|
|
2511
|
+
const discount = safeMinor(cart.discountMinor, resource, "$.discountMinor");
|
|
2512
|
+
const estimatedTotal = safeMinor(
|
|
2513
|
+
cart.estimatedTotalMinor,
|
|
2514
|
+
resource,
|
|
2515
|
+
"$.estimatedTotalMinor"
|
|
2516
|
+
);
|
|
2517
|
+
array(cart.discountCodes, resource, "$.discountCodes").forEach(
|
|
2518
|
+
(value2, index) => {
|
|
2519
|
+
const itemPath = `$.discountCodes[${index}]`;
|
|
2520
|
+
const code = record(value2, resource, itemPath);
|
|
2521
|
+
exact(code, ["code", "applicable"], [], resource, itemPath);
|
|
2522
|
+
boundedString(
|
|
2523
|
+
code.code,
|
|
2524
|
+
MAX_CART_DISCOUNT_CODE_LENGTH,
|
|
2525
|
+
resource,
|
|
2526
|
+
`${itemPath}.code`
|
|
2527
|
+
);
|
|
2528
|
+
boolean(code.applicable, resource, `${itemPath}.applicable`);
|
|
2529
|
+
}
|
|
2530
|
+
);
|
|
2531
|
+
validateAttributes(cart.attributes, resource, "$.attributes");
|
|
2532
|
+
const items = array(cart.items, resource, "$.items");
|
|
2533
|
+
items.forEach(
|
|
2534
|
+
(item, index) => validateCartItem(item, resource, `$.items[${index}]`)
|
|
2535
|
+
);
|
|
2536
|
+
const expectedSubtotal = items.reduce((total, value2) => {
|
|
2537
|
+
const item = value2;
|
|
2538
|
+
return total + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
|
|
2539
|
+
}, 0n);
|
|
2540
|
+
const expectedDiscount = items.reduce((total, value2) => {
|
|
2541
|
+
const item = value2;
|
|
2542
|
+
return total + BigInt(item.discountMinor);
|
|
2543
|
+
}, 0n);
|
|
2544
|
+
if (BigInt(subtotal) !== expectedSubtotal) {
|
|
2545
|
+
fail(resource, "$.subtotalMinor", "sum of undiscounted cart line totals");
|
|
2546
|
+
}
|
|
2547
|
+
if (BigInt(discount) !== expectedDiscount) {
|
|
2548
|
+
fail(resource, "$.discountMinor", "sum of cart line discounts");
|
|
2549
|
+
}
|
|
2550
|
+
if (expectedSubtotal - BigInt(discount) < 0n || BigInt(estimatedTotal) !== expectedSubtotal - BigInt(discount)) {
|
|
2551
|
+
fail(resource, "$.estimatedTotalMinor", "subtotalMinor - discountMinor");
|
|
2552
|
+
}
|
|
2553
|
+
timestamp(cart.expiresAt, resource, "$.expiresAt");
|
|
2554
|
+
timestamp(cart.createdAt, resource, "$.createdAt");
|
|
2555
|
+
timestamp(cart.updatedAt, resource, "$.updatedAt");
|
|
2556
|
+
return value;
|
|
2557
|
+
}
|
|
2558
|
+
function validateWarnings(value, resource, path) {
|
|
2559
|
+
array(value, resource, path).forEach((value2, index) => {
|
|
2560
|
+
const itemPath = `${path}[${index}]`;
|
|
2561
|
+
const warning = record(value2, resource, itemPath);
|
|
2562
|
+
exact(warning, ["code", "message", "target"], [], resource, itemPath);
|
|
2563
|
+
enumValue(warning.code, CART_WARNING_CODES, resource, `${itemPath}.code`);
|
|
2564
|
+
string(warning.message, resource, `${itemPath}.message`);
|
|
2565
|
+
string(warning.target, resource, `${itemPath}.target`);
|
|
2566
|
+
});
|
|
2567
|
+
}
|
|
2568
|
+
function validateCartMutationResult(value) {
|
|
2569
|
+
const result = record(value, "Cart mutation result", "$");
|
|
2570
|
+
exact(result, ["cart", "warnings"], [], "Cart mutation result", "$");
|
|
2571
|
+
validatePublicCart(result.cart);
|
|
2572
|
+
validateWarnings(result.warnings, "Cart mutation result", "$.warnings");
|
|
2573
|
+
return value;
|
|
2574
|
+
}
|
|
2575
|
+
function validateCreateCartResult(value) {
|
|
2576
|
+
const result = record(value, "Cart create result", "$");
|
|
2577
|
+
exact(
|
|
2578
|
+
result,
|
|
2579
|
+
["cart", "warnings", "cartToken"],
|
|
2580
|
+
[],
|
|
2581
|
+
"Cart create result",
|
|
2582
|
+
"$"
|
|
2583
|
+
);
|
|
2584
|
+
const cart = record(result.cart, "Cart create result", "$.cart");
|
|
2585
|
+
validatePublicCart(cart);
|
|
2586
|
+
if (cart.revision !== 0) {
|
|
2587
|
+
fail("Cart create result", "$.cart.revision", "0 for a newly created Cart");
|
|
2588
|
+
}
|
|
2589
|
+
validateWarnings(result.warnings, "Cart create result", "$.warnings");
|
|
2590
|
+
boundedString(
|
|
2591
|
+
result.cartToken,
|
|
2592
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
2593
|
+
"Cart create result",
|
|
2594
|
+
"$.cartToken"
|
|
2595
|
+
);
|
|
2596
|
+
return value;
|
|
2597
|
+
}
|
|
2598
|
+
function validateCartMineResult(value) {
|
|
2599
|
+
const result = record(value, "Cart mine result", "$");
|
|
2600
|
+
exact(result, ["cart", "cartToken"], [], "Cart mine result", "$");
|
|
2601
|
+
if (result.cart === null || result.cartToken === null) {
|
|
2602
|
+
if (result.cart !== null || result.cartToken !== null) {
|
|
2603
|
+
fail("Cart mine result", "$", "cart and cartToken must both be null");
|
|
2604
|
+
}
|
|
2605
|
+
} else {
|
|
2606
|
+
validatePublicCart(result.cart);
|
|
2607
|
+
boundedString(
|
|
2608
|
+
result.cartToken,
|
|
2609
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
2610
|
+
"Cart mine result",
|
|
2611
|
+
"$.cartToken"
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
return value;
|
|
2615
|
+
}
|
|
2616
|
+
function validateCartMergeResult(value) {
|
|
2617
|
+
const result = record(value, "Cart merge result", "$");
|
|
2618
|
+
exact(
|
|
2619
|
+
result,
|
|
2620
|
+
["cart", "warnings", "cartToken", "resolution", "merged", "claimed"],
|
|
2621
|
+
[],
|
|
2622
|
+
"Cart merge result",
|
|
2623
|
+
"$"
|
|
2624
|
+
);
|
|
2625
|
+
validatePublicCart(result.cart);
|
|
2626
|
+
validateWarnings(result.warnings, "Cart merge result", "$.warnings");
|
|
2627
|
+
boundedString(
|
|
2628
|
+
result.cartToken,
|
|
2629
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
2630
|
+
"Cart merge result",
|
|
2631
|
+
"$.cartToken"
|
|
2632
|
+
);
|
|
2633
|
+
const resolution = enumValue(
|
|
2634
|
+
result.resolution,
|
|
2635
|
+
["unchanged", "claimed", "merged"],
|
|
2636
|
+
"Cart merge result",
|
|
2637
|
+
"$.resolution"
|
|
2638
|
+
);
|
|
2639
|
+
boolean(result.merged, "Cart merge result", "$.merged");
|
|
2640
|
+
boolean(result.claimed, "Cart merge result", "$.claimed");
|
|
2641
|
+
const expected = resolution === "merged" ? [true, false] : resolution === "claimed" ? [false, true] : [false, false];
|
|
2642
|
+
if (result.merged !== expected[0] || result.claimed !== expected[1]) {
|
|
2643
|
+
fail("Cart merge result", "$", "resolution-consistent merged/claimed flags");
|
|
2644
|
+
}
|
|
2645
|
+
return value;
|
|
2646
|
+
}
|
|
2647
|
+
function validatePublicOrderItem(value, resource, path) {
|
|
2648
|
+
const item = record(value, resource, path);
|
|
2649
|
+
exact(
|
|
2650
|
+
item,
|
|
2651
|
+
[
|
|
2652
|
+
"id",
|
|
2653
|
+
"product",
|
|
2654
|
+
"variant",
|
|
2655
|
+
"productTitle",
|
|
2656
|
+
"variantTitle",
|
|
2657
|
+
"sku",
|
|
2658
|
+
"admissions",
|
|
2659
|
+
"quantity",
|
|
2660
|
+
"unitPriceMinor",
|
|
2661
|
+
"discountMinor",
|
|
2662
|
+
"lineTotalMinor",
|
|
2663
|
+
"requiresShipping"
|
|
2664
|
+
],
|
|
2665
|
+
[],
|
|
2666
|
+
resource,
|
|
2667
|
+
path
|
|
2668
|
+
);
|
|
2669
|
+
string(item.id, resource, `${path}.id`);
|
|
2670
|
+
if (item.product !== null) {
|
|
2671
|
+
validateReference(item.product, resource, `${path}.product`);
|
|
2672
|
+
}
|
|
2673
|
+
if (item.variant !== null) {
|
|
2674
|
+
validateReference(item.variant, resource, `${path}.variant`);
|
|
2675
|
+
}
|
|
2676
|
+
string(item.productTitle, resource, `${path}.productTitle`);
|
|
2677
|
+
nullableString(item.variantTitle, resource, `${path}.variantTitle`);
|
|
2678
|
+
nullableString(item.sku, resource, `${path}.sku`);
|
|
2679
|
+
validateAdmissions(item.admissions, resource, `${path}.admissions`);
|
|
2680
|
+
const quantity = positiveInteger(item.quantity, resource, `${path}.quantity`);
|
|
2681
|
+
const unitPrice = safeMinor(
|
|
2682
|
+
item.unitPriceMinor,
|
|
2683
|
+
resource,
|
|
2684
|
+
`${path}.unitPriceMinor`
|
|
2685
|
+
);
|
|
2686
|
+
const discount = safeMinor(
|
|
2687
|
+
item.discountMinor,
|
|
2688
|
+
resource,
|
|
2689
|
+
`${path}.discountMinor`
|
|
2690
|
+
);
|
|
2691
|
+
const lineTotal = safeMinor(
|
|
2692
|
+
item.lineTotalMinor,
|
|
2693
|
+
resource,
|
|
2694
|
+
`${path}.lineTotalMinor`
|
|
2695
|
+
);
|
|
2696
|
+
const expected = BigInt(unitPrice) * BigInt(quantity) - BigInt(discount);
|
|
2697
|
+
if (expected < 0n || BigInt(lineTotal) !== expected) {
|
|
2698
|
+
fail(
|
|
2699
|
+
resource,
|
|
2700
|
+
`${path}.lineTotalMinor`,
|
|
2701
|
+
"unitPriceMinor * quantity - discountMinor"
|
|
2702
|
+
);
|
|
2703
|
+
}
|
|
2704
|
+
boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
|
|
2705
|
+
}
|
|
2706
|
+
function validatePublicOrderAt(value, resource, path) {
|
|
2707
|
+
const order = record(value, resource, path);
|
|
2708
|
+
exact(
|
|
2709
|
+
order,
|
|
2710
|
+
[
|
|
2711
|
+
"id",
|
|
2712
|
+
"orderNumber",
|
|
2713
|
+
"amounts",
|
|
2714
|
+
"market",
|
|
2715
|
+
"customerSnapshot",
|
|
2716
|
+
"shippingAddress",
|
|
2717
|
+
"attributes",
|
|
2718
|
+
"items",
|
|
2719
|
+
"financialStatus",
|
|
2720
|
+
"fulfillmentStatus",
|
|
2721
|
+
"returnStatus",
|
|
2722
|
+
"confirmationStatus",
|
|
2723
|
+
"primaryDisplayStatus",
|
|
2724
|
+
"placedAt",
|
|
2725
|
+
"createdAt",
|
|
2726
|
+
"updatedAt"
|
|
2727
|
+
],
|
|
2728
|
+
[],
|
|
2729
|
+
resource,
|
|
2730
|
+
path
|
|
2731
|
+
);
|
|
2732
|
+
string(order.id, resource, `${path}.id`);
|
|
2733
|
+
string(order.orderNumber, resource, `${path}.orderNumber`);
|
|
2734
|
+
const amounts = record(order.amounts, resource, `${path}.amounts`);
|
|
2735
|
+
exact(
|
|
2736
|
+
amounts,
|
|
2737
|
+
[
|
|
2738
|
+
"currency",
|
|
2739
|
+
"subtotalMinor",
|
|
2740
|
+
"shippingMinor",
|
|
2741
|
+
"discountMinor",
|
|
2742
|
+
"totalMinor",
|
|
2743
|
+
"refundedMinor",
|
|
2744
|
+
"currentTotalMinor"
|
|
2745
|
+
],
|
|
2746
|
+
[],
|
|
2747
|
+
resource,
|
|
2748
|
+
`${path}.amounts`
|
|
2749
|
+
);
|
|
2750
|
+
currency(amounts.currency, resource, `${path}.amounts.currency`);
|
|
2751
|
+
const subtotal = safeMinor(
|
|
2752
|
+
amounts.subtotalMinor,
|
|
2753
|
+
resource,
|
|
2754
|
+
`${path}.amounts.subtotalMinor`
|
|
2755
|
+
);
|
|
2756
|
+
const shipping = safeMinor(
|
|
2757
|
+
amounts.shippingMinor,
|
|
2758
|
+
resource,
|
|
2759
|
+
`${path}.amounts.shippingMinor`
|
|
2760
|
+
);
|
|
2761
|
+
const discount = safeMinor(
|
|
2762
|
+
amounts.discountMinor,
|
|
2763
|
+
resource,
|
|
2764
|
+
`${path}.amounts.discountMinor`
|
|
2765
|
+
);
|
|
2766
|
+
const total = safeMinor(
|
|
2767
|
+
amounts.totalMinor,
|
|
2768
|
+
resource,
|
|
2769
|
+
`${path}.amounts.totalMinor`
|
|
2770
|
+
);
|
|
2771
|
+
const refunded = safeMinor(
|
|
2772
|
+
amounts.refundedMinor,
|
|
2773
|
+
resource,
|
|
2774
|
+
`${path}.amounts.refundedMinor`
|
|
2775
|
+
);
|
|
2776
|
+
const current = safeMinor(
|
|
2777
|
+
amounts.currentTotalMinor,
|
|
2778
|
+
resource,
|
|
2779
|
+
`${path}.amounts.currentTotalMinor`
|
|
2780
|
+
);
|
|
2781
|
+
const expectedTotal = BigInt(subtotal) + BigInt(shipping) - BigInt(discount);
|
|
2782
|
+
if (expectedTotal < 0n || BigInt(total) !== expectedTotal) {
|
|
2783
|
+
fail(
|
|
2784
|
+
resource,
|
|
2785
|
+
`${path}.amounts.totalMinor`,
|
|
2786
|
+
"subtotalMinor + shippingMinor - discountMinor"
|
|
2787
|
+
);
|
|
2788
|
+
}
|
|
2789
|
+
if (BigInt(total) - BigInt(refunded) < 0n || current !== total - refunded) {
|
|
2790
|
+
fail(
|
|
2791
|
+
resource,
|
|
2792
|
+
`${path}.amounts.currentTotalMinor`,
|
|
2793
|
+
"totalMinor - refundedMinor"
|
|
2794
|
+
);
|
|
2795
|
+
}
|
|
2796
|
+
if (order.market !== null) {
|
|
2797
|
+
const market = record(order.market, resource, `${path}.market`);
|
|
2798
|
+
exact(market, ["id", "handle", "name"], [], resource, `${path}.market`);
|
|
2799
|
+
for (const key of ["id", "handle", "name"]) {
|
|
2800
|
+
string(market[key], resource, `${path}.market.${key}`);
|
|
2801
|
+
}
|
|
2802
|
+
}
|
|
2803
|
+
validateCustomer(order.customerSnapshot, resource, `${path}.customerSnapshot`);
|
|
2804
|
+
if (order.shippingAddress !== null) {
|
|
2805
|
+
validateShippingAddress(
|
|
2806
|
+
order.shippingAddress,
|
|
2807
|
+
resource,
|
|
2808
|
+
`${path}.shippingAddress`
|
|
2809
|
+
);
|
|
2810
|
+
}
|
|
2811
|
+
validateAttributes(order.attributes, resource, `${path}.attributes`);
|
|
2812
|
+
const items = array(order.items, resource, `${path}.items`);
|
|
2813
|
+
if (items.length === 0) fail(resource, `${path}.items`, "non-empty array");
|
|
2814
|
+
items.forEach(
|
|
2815
|
+
(item, index) => validatePublicOrderItem(item, resource, `${path}.items[${index}]`)
|
|
2816
|
+
);
|
|
2817
|
+
const expectedSubtotal = items.reduce((sum, value2) => {
|
|
2818
|
+
const item = value2;
|
|
2819
|
+
return sum + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
|
|
2820
|
+
}, 0n);
|
|
2821
|
+
const expectedDiscount = items.reduce((sum, value2) => {
|
|
2822
|
+
const item = value2;
|
|
2823
|
+
return sum + BigInt(item.discountMinor);
|
|
2824
|
+
}, 0n);
|
|
2825
|
+
if (BigInt(subtotal) !== expectedSubtotal) {
|
|
2826
|
+
fail(resource, `${path}.amounts.subtotalMinor`, "sum of line subtotals");
|
|
2827
|
+
}
|
|
2828
|
+
if (BigInt(discount) !== expectedDiscount) {
|
|
2829
|
+
fail(resource, `${path}.amounts.discountMinor`, "sum of line discounts");
|
|
2830
|
+
}
|
|
2831
|
+
enumValue(
|
|
2832
|
+
order.financialStatus,
|
|
2833
|
+
ORDER_FINANCIAL_STATUSES,
|
|
2834
|
+
resource,
|
|
2835
|
+
`${path}.financialStatus`
|
|
2836
|
+
);
|
|
2837
|
+
enumValue(
|
|
2838
|
+
order.fulfillmentStatus,
|
|
2839
|
+
ORDER_FULFILLMENT_STATUSES,
|
|
2840
|
+
resource,
|
|
2841
|
+
`${path}.fulfillmentStatus`
|
|
2842
|
+
);
|
|
2843
|
+
enumValue(
|
|
2844
|
+
order.returnStatus,
|
|
2845
|
+
ORDER_RETURN_STATUSES,
|
|
2846
|
+
resource,
|
|
2847
|
+
`${path}.returnStatus`
|
|
2848
|
+
);
|
|
2849
|
+
enumValue(
|
|
2850
|
+
order.confirmationStatus,
|
|
2851
|
+
ORDER_CONFIRMATION_STATUSES,
|
|
2852
|
+
resource,
|
|
2853
|
+
`${path}.confirmationStatus`
|
|
2854
|
+
);
|
|
2855
|
+
enumValue(
|
|
2856
|
+
order.primaryDisplayStatus,
|
|
2857
|
+
ORDER_PRIMARY_DISPLAY_STATUSES,
|
|
2858
|
+
resource,
|
|
2859
|
+
`${path}.primaryDisplayStatus`
|
|
2860
|
+
);
|
|
2861
|
+
timestamp(order.placedAt, resource, `${path}.placedAt`);
|
|
2862
|
+
timestamp(order.createdAt, resource, `${path}.createdAt`);
|
|
2863
|
+
timestamp(order.updatedAt, resource, `${path}.updatedAt`);
|
|
2864
|
+
}
|
|
2865
|
+
function nullablePositiveInteger(value, resource, path) {
|
|
2866
|
+
if (value !== null) positiveInteger(value, resource, path);
|
|
2867
|
+
}
|
|
2868
|
+
function validatePublicOrderList(value) {
|
|
2869
|
+
const resource = "Order list";
|
|
2870
|
+
const result = record(value, resource, "$");
|
|
2871
|
+
exact(
|
|
2872
|
+
result,
|
|
2873
|
+
[
|
|
2874
|
+
"docs",
|
|
2875
|
+
"totalDocs",
|
|
2876
|
+
"limit",
|
|
2877
|
+
"totalPages",
|
|
2878
|
+
"page",
|
|
2879
|
+
"pagingCounter",
|
|
2880
|
+
"hasPrevPage",
|
|
2881
|
+
"hasNextPage",
|
|
2882
|
+
"prevPage",
|
|
2883
|
+
"nextPage"
|
|
2884
|
+
],
|
|
2885
|
+
[],
|
|
2886
|
+
resource,
|
|
2887
|
+
"$"
|
|
2888
|
+
);
|
|
2889
|
+
array(result.docs, resource, "$.docs").forEach(
|
|
2890
|
+
(order, index) => validatePublicOrderAt(order, resource, `$.docs[${index}]`)
|
|
2891
|
+
);
|
|
2892
|
+
safeMinor(result.totalDocs, resource, "$.totalDocs");
|
|
2893
|
+
positiveInteger(result.limit, resource, "$.limit");
|
|
2894
|
+
safeMinor(result.totalPages, resource, "$.totalPages");
|
|
2895
|
+
positiveInteger(result.page, resource, "$.page");
|
|
2896
|
+
positiveInteger(result.pagingCounter, resource, "$.pagingCounter");
|
|
2897
|
+
boolean(result.hasPrevPage, resource, "$.hasPrevPage");
|
|
2898
|
+
boolean(result.hasNextPage, resource, "$.hasNextPage");
|
|
2899
|
+
nullablePositiveInteger(result.prevPage, resource, "$.prevPage");
|
|
2900
|
+
nullablePositiveInteger(result.nextPage, resource, "$.nextPage");
|
|
2901
|
+
return value;
|
|
2902
|
+
}
|
|
2903
|
+
function validateCheckoutItem(value, resource, path) {
|
|
2904
|
+
const item = record(value, resource, path);
|
|
2905
|
+
exact(
|
|
2906
|
+
item,
|
|
2907
|
+
[
|
|
2908
|
+
"id",
|
|
2909
|
+
"product",
|
|
2910
|
+
"variant",
|
|
2911
|
+
"productTitle",
|
|
2912
|
+
"variantTitle",
|
|
2913
|
+
"sku",
|
|
2914
|
+
"admissions",
|
|
2915
|
+
"quantity",
|
|
2916
|
+
"unitPriceMinor",
|
|
2917
|
+
"discountMinor",
|
|
2918
|
+
"lineTotalMinor",
|
|
2919
|
+
"requiresShipping"
|
|
2920
|
+
],
|
|
2921
|
+
[],
|
|
2922
|
+
resource,
|
|
2923
|
+
path
|
|
2924
|
+
);
|
|
2925
|
+
string(item.id, resource, `${path}.id`);
|
|
2926
|
+
validateReference(item.product, resource, `${path}.product`);
|
|
2927
|
+
validateReference(item.variant, resource, `${path}.variant`);
|
|
2928
|
+
string(item.productTitle, resource, `${path}.productTitle`);
|
|
2929
|
+
nullableString(item.variantTitle, resource, `${path}.variantTitle`);
|
|
2930
|
+
nullableString(item.sku, resource, `${path}.sku`);
|
|
2931
|
+
validateAdmissions(item.admissions, resource, `${path}.admissions`);
|
|
2932
|
+
cartLineQuantity(item.quantity, resource, `${path}.quantity`);
|
|
2933
|
+
const unitPrice = safeMinor(
|
|
2934
|
+
item.unitPriceMinor,
|
|
2935
|
+
resource,
|
|
2936
|
+
`${path}.unitPriceMinor`
|
|
2937
|
+
);
|
|
2938
|
+
const discount = safeMinor(
|
|
2939
|
+
item.discountMinor,
|
|
2940
|
+
resource,
|
|
2941
|
+
`${path}.discountMinor`
|
|
2942
|
+
);
|
|
2943
|
+
const lineTotal = safeMinor(
|
|
2944
|
+
item.lineTotalMinor,
|
|
2945
|
+
resource,
|
|
2946
|
+
`${path}.lineTotalMinor`
|
|
2947
|
+
);
|
|
2948
|
+
const expectedLineTotal = BigInt(unitPrice) * BigInt(item.quantity) - BigInt(discount);
|
|
2949
|
+
if (expectedLineTotal < 0n || BigInt(lineTotal) !== expectedLineTotal) {
|
|
2950
|
+
fail(
|
|
2951
|
+
resource,
|
|
2952
|
+
`${path}.lineTotalMinor`,
|
|
2953
|
+
"unitPriceMinor * quantity - discountMinor"
|
|
2954
|
+
);
|
|
2955
|
+
}
|
|
2956
|
+
boolean(item.requiresShipping, resource, `${path}.requiresShipping`);
|
|
2957
|
+
}
|
|
2958
|
+
function validateCheckoutAmounts(value, resource, path) {
|
|
2959
|
+
const amounts = record(value, resource, path);
|
|
2960
|
+
exact(
|
|
2961
|
+
amounts,
|
|
2962
|
+
[
|
|
2963
|
+
"currency",
|
|
2964
|
+
"subtotalMinor",
|
|
2965
|
+
"shippingMinor",
|
|
2966
|
+
"discountMinor",
|
|
2967
|
+
"totalMinor"
|
|
2968
|
+
],
|
|
2969
|
+
[],
|
|
2970
|
+
resource,
|
|
2971
|
+
path
|
|
2972
|
+
);
|
|
2973
|
+
currency(amounts.currency, resource, `${path}.currency`);
|
|
2974
|
+
const subtotal = safeMinor(
|
|
2975
|
+
amounts.subtotalMinor,
|
|
2976
|
+
resource,
|
|
2977
|
+
`${path}.subtotalMinor`
|
|
2978
|
+
);
|
|
2979
|
+
const shipping = safeMinor(
|
|
2980
|
+
amounts.shippingMinor,
|
|
2981
|
+
resource,
|
|
2982
|
+
`${path}.shippingMinor`
|
|
2983
|
+
);
|
|
2984
|
+
const discount = safeMinor(
|
|
2985
|
+
amounts.discountMinor,
|
|
2986
|
+
resource,
|
|
2987
|
+
`${path}.discountMinor`
|
|
2988
|
+
);
|
|
2989
|
+
const total = safeMinor(amounts.totalMinor, resource, `${path}.totalMinor`);
|
|
2990
|
+
if (BigInt(total) !== BigInt(subtotal) + BigInt(shipping) - BigInt(discount)) {
|
|
2991
|
+
fail(
|
|
2992
|
+
resource,
|
|
2993
|
+
`${path}.totalMinor`,
|
|
2994
|
+
"subtotalMinor + shippingMinor - discountMinor"
|
|
2995
|
+
);
|
|
2996
|
+
}
|
|
2997
|
+
}
|
|
2998
|
+
function validatePaymentSessionReference(value, resource, path) {
|
|
2999
|
+
const session = record(value, resource, path);
|
|
3000
|
+
exact(session, ["id", "provider", "providerStatus"], [], resource, path);
|
|
3001
|
+
string(session.id, resource, `${path}.id`);
|
|
3002
|
+
enumValue(session.provider, PAYMENT_PROVIDERS, resource, `${path}.provider`);
|
|
3003
|
+
enumValue(
|
|
3004
|
+
session.providerStatus,
|
|
3005
|
+
PAYMENT_PROVIDER_STATUSES,
|
|
3006
|
+
resource,
|
|
3007
|
+
`${path}.providerStatus`
|
|
3008
|
+
);
|
|
3009
|
+
}
|
|
3010
|
+
function checkoutVariantKeys(status, placedVia) {
|
|
3011
|
+
const base = [
|
|
3012
|
+
"id",
|
|
3013
|
+
"amounts",
|
|
3014
|
+
"items",
|
|
3015
|
+
"customerSnapshot",
|
|
3016
|
+
"shippingAddress",
|
|
3017
|
+
"attributes",
|
|
3018
|
+
"expiresAt",
|
|
3019
|
+
"createdAt",
|
|
3020
|
+
"updatedAt",
|
|
3021
|
+
"status",
|
|
3022
|
+
"paymentState",
|
|
3023
|
+
"order"
|
|
3024
|
+
];
|
|
3025
|
+
if (status === "open") return { required: base, optional: [] };
|
|
3026
|
+
if (status === "abandoned") {
|
|
3027
|
+
return {
|
|
3028
|
+
required: [...base, "abandonedAt", "abandonedReason"],
|
|
3029
|
+
optional: []
|
|
3030
|
+
};
|
|
3031
|
+
}
|
|
3032
|
+
return placedVia === "late_capture" ? {
|
|
3033
|
+
required: [
|
|
3034
|
+
...base,
|
|
3035
|
+
"placedAt",
|
|
3036
|
+
"placedVia",
|
|
3037
|
+
"abandonedAt",
|
|
3038
|
+
"abandonedReason"
|
|
3039
|
+
],
|
|
3040
|
+
optional: []
|
|
3041
|
+
} : { required: [...base, "placedAt"], optional: [] };
|
|
3042
|
+
}
|
|
3043
|
+
function validateCheckoutCore(value, resource, list, server) {
|
|
3044
|
+
const checkout = record(value, resource, "$");
|
|
3045
|
+
const status = enumValue(
|
|
3046
|
+
checkout.status,
|
|
3047
|
+
CHECKOUT_STATUSES,
|
|
3048
|
+
resource,
|
|
3049
|
+
"$.status"
|
|
3050
|
+
);
|
|
3051
|
+
const keys = checkoutVariantKeys(status, checkout.placedVia);
|
|
3052
|
+
if (list) {
|
|
3053
|
+
keys.required = keys.required.filter(
|
|
3054
|
+
(key) => !["items", "shippingAddress", "attributes"].includes(key)
|
|
3055
|
+
);
|
|
3056
|
+
keys.required.push("clientReferenceId");
|
|
3057
|
+
} else if (server) {
|
|
3058
|
+
keys.required.push("clientReferenceId", "integrationMetadata");
|
|
3059
|
+
}
|
|
3060
|
+
exact(checkout, keys.required, keys.optional, resource, "$");
|
|
3061
|
+
string(checkout.id, resource, "$.id");
|
|
3062
|
+
validateCheckoutAmounts(checkout.amounts, resource, "$.amounts");
|
|
3063
|
+
if (!list) {
|
|
3064
|
+
const items = array(checkout.items, resource, "$.items");
|
|
3065
|
+
if (items.length === 0) fail(resource, "$.items", "non-empty array");
|
|
3066
|
+
items.forEach(
|
|
3067
|
+
(item, index) => validateCheckoutItem(item, resource, `$.items[${index}]`)
|
|
3068
|
+
);
|
|
3069
|
+
const expectedSubtotal = items.reduce((total, value2) => {
|
|
3070
|
+
const item = value2;
|
|
3071
|
+
return total + BigInt(item.unitPriceMinor) * BigInt(item.quantity);
|
|
3072
|
+
}, 0n);
|
|
3073
|
+
const expectedDiscount = items.reduce((total, value2) => {
|
|
3074
|
+
const item = value2;
|
|
3075
|
+
return total + BigInt(item.discountMinor);
|
|
3076
|
+
}, 0n);
|
|
3077
|
+
const amounts = checkout.amounts;
|
|
3078
|
+
if (BigInt(amounts.subtotalMinor) !== expectedSubtotal) {
|
|
3079
|
+
fail(
|
|
3080
|
+
resource,
|
|
3081
|
+
"$.amounts.subtotalMinor",
|
|
3082
|
+
"sum of undiscounted checkout line totals"
|
|
3083
|
+
);
|
|
3084
|
+
}
|
|
3085
|
+
if (BigInt(amounts.discountMinor) !== expectedDiscount) {
|
|
3086
|
+
fail(
|
|
3087
|
+
resource,
|
|
3088
|
+
"$.amounts.discountMinor",
|
|
3089
|
+
"sum of checkout line discounts"
|
|
3090
|
+
);
|
|
3091
|
+
}
|
|
3092
|
+
if (checkout.shippingAddress !== null) {
|
|
3093
|
+
validateShippingAddress(
|
|
3094
|
+
checkout.shippingAddress,
|
|
3095
|
+
resource,
|
|
3096
|
+
"$.shippingAddress"
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
validateAttributes(checkout.attributes, resource, "$.attributes");
|
|
3100
|
+
}
|
|
3101
|
+
validateCustomer(checkout.customerSnapshot, resource, "$.customerSnapshot");
|
|
3102
|
+
timestamp(checkout.expiresAt, resource, "$.expiresAt");
|
|
3103
|
+
timestamp(checkout.createdAt, resource, "$.createdAt");
|
|
3104
|
+
timestamp(checkout.updatedAt, resource, "$.updatedAt");
|
|
3105
|
+
const paymentState = record(checkout.paymentState, resource, "$.paymentState");
|
|
3106
|
+
exact(paymentState, ["activePaymentSession"], [], resource, "$.paymentState");
|
|
3107
|
+
if (status === "open") {
|
|
3108
|
+
if (paymentState.activePaymentSession !== null) {
|
|
3109
|
+
validatePaymentSessionReference(
|
|
3110
|
+
paymentState.activePaymentSession,
|
|
3111
|
+
resource,
|
|
3112
|
+
"$.paymentState.activePaymentSession"
|
|
3113
|
+
);
|
|
3114
|
+
}
|
|
3115
|
+
if (checkout.order !== null)
|
|
3116
|
+
fail(resource, "$.order", "null for open Checkout");
|
|
3117
|
+
} else {
|
|
3118
|
+
if (paymentState.activePaymentSession !== null) {
|
|
3119
|
+
fail(
|
|
3120
|
+
resource,
|
|
3121
|
+
"$.paymentState.activePaymentSession",
|
|
3122
|
+
"null for spent Checkout"
|
|
3123
|
+
);
|
|
3124
|
+
}
|
|
3125
|
+
if (status === "placed") {
|
|
3126
|
+
timestamp(checkout.placedAt, resource, "$.placedAt");
|
|
3127
|
+
validateOrderReference(checkout.order, resource, "$.order");
|
|
3128
|
+
if (checkout.placedVia !== void 0 && checkout.placedVia !== "late_capture") {
|
|
3129
|
+
fail(resource, "$.placedVia", "late_capture");
|
|
3130
|
+
}
|
|
3131
|
+
if (checkout.placedVia === "late_capture") {
|
|
3132
|
+
timestamp(checkout.abandonedAt, resource, "$.abandonedAt");
|
|
3133
|
+
enumValue(
|
|
3134
|
+
checkout.abandonedReason,
|
|
3135
|
+
ABANDONED_REASONS,
|
|
3136
|
+
resource,
|
|
3137
|
+
"$.abandonedReason"
|
|
3138
|
+
);
|
|
3139
|
+
}
|
|
3140
|
+
} else {
|
|
3141
|
+
timestamp(checkout.abandonedAt, resource, "$.abandonedAt");
|
|
3142
|
+
enumValue(
|
|
3143
|
+
checkout.abandonedReason,
|
|
3144
|
+
ABANDONED_REASONS,
|
|
3145
|
+
resource,
|
|
3146
|
+
"$.abandonedReason"
|
|
3147
|
+
);
|
|
3148
|
+
if (checkout.order !== null)
|
|
3149
|
+
fail(resource, "$.order", "null for abandoned Checkout");
|
|
3150
|
+
}
|
|
3151
|
+
}
|
|
3152
|
+
if (list || server) {
|
|
3153
|
+
if (checkout.clientReferenceId !== null) {
|
|
3154
|
+
boundedString(
|
|
3155
|
+
checkout.clientReferenceId,
|
|
3156
|
+
MAX_COMMERCE_RESOURCE_ID_LENGTH,
|
|
3157
|
+
resource,
|
|
3158
|
+
"$.clientReferenceId"
|
|
3159
|
+
);
|
|
3160
|
+
}
|
|
3161
|
+
}
|
|
3162
|
+
if (server)
|
|
3163
|
+
validateIntegrationMetadata(
|
|
3164
|
+
checkout.integrationMetadata,
|
|
3165
|
+
resource,
|
|
3166
|
+
"$.integrationMetadata"
|
|
3167
|
+
);
|
|
3168
|
+
}
|
|
3169
|
+
function validatePublicCheckout(value) {
|
|
3170
|
+
validateCheckoutCore(value, "Checkout", false, false);
|
|
3171
|
+
return value;
|
|
3172
|
+
}
|
|
3173
|
+
function validateServerCheckout(value) {
|
|
3174
|
+
validateCheckoutCore(value, "Server Checkout", false, true);
|
|
3175
|
+
return value;
|
|
3176
|
+
}
|
|
3177
|
+
function validateCreateCheckoutResult(value, server) {
|
|
3178
|
+
const resource = server ? "Server Checkout create result" : "Checkout create result";
|
|
3179
|
+
const result = record(value, resource, "$");
|
|
3180
|
+
exact(result, ["checkout", "checkoutToken"], [], resource, "$");
|
|
3181
|
+
if (server) validateServerCheckout(result.checkout);
|
|
3182
|
+
else validatePublicCheckout(result.checkout);
|
|
3183
|
+
boundedString(
|
|
3184
|
+
result.checkoutToken,
|
|
3185
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
3186
|
+
resource,
|
|
3187
|
+
"$.checkoutToken"
|
|
3188
|
+
);
|
|
3189
|
+
return value;
|
|
3190
|
+
}
|
|
3191
|
+
function validateCheckoutQueryResult(value) {
|
|
3192
|
+
const result = record(value, "Checkout query result", "$");
|
|
3193
|
+
exact(
|
|
3194
|
+
result,
|
|
3195
|
+
["data", "hasMore", "nextCursor"],
|
|
3196
|
+
[],
|
|
3197
|
+
"Checkout query result",
|
|
3198
|
+
"$"
|
|
3199
|
+
);
|
|
3200
|
+
array(result.data, "Checkout query result", "$.data").forEach(
|
|
3201
|
+
(item) => validateCheckoutCore(item, "Checkout list item", true, false)
|
|
3202
|
+
);
|
|
3203
|
+
boolean(result.hasMore, "Checkout query result", "$.hasMore");
|
|
3204
|
+
if (result.nextCursor !== null)
|
|
3205
|
+
boundedString(
|
|
3206
|
+
result.nextCursor,
|
|
3207
|
+
MAX_COMMERCE_CAPABILITY_LENGTH,
|
|
3208
|
+
"Checkout query result",
|
|
3209
|
+
"$.nextCursor"
|
|
3210
|
+
);
|
|
3211
|
+
if (result.hasMore === true && result.nextCursor === null) {
|
|
3212
|
+
fail(
|
|
3213
|
+
"Checkout query result",
|
|
3214
|
+
"$.nextCursor",
|
|
3215
|
+
"non-null when hasMore is true"
|
|
3216
|
+
);
|
|
3217
|
+
}
|
|
3218
|
+
return value;
|
|
3219
|
+
}
|
|
3220
|
+
function validateMoney(value, resource, path) {
|
|
3221
|
+
const money = record(value, resource, path);
|
|
3222
|
+
exact(money, ["amountMinor", "currency"], [], resource, path);
|
|
3223
|
+
safeMinor(money.amountMinor, resource, `${path}.amountMinor`);
|
|
3224
|
+
currency(money.currency, resource, `${path}.currency`);
|
|
3225
|
+
}
|
|
3226
|
+
function validateCaptureEvidence(value, resource, path) {
|
|
3227
|
+
const evidence = record(value, resource, path);
|
|
3228
|
+
exact(evidence, ["amountMinor", "currency", "observedAt"], [], resource, path);
|
|
3229
|
+
safeMinor(evidence.amountMinor, resource, `${path}.amountMinor`);
|
|
3230
|
+
currency(evidence.currency, resource, `${path}.currency`);
|
|
3231
|
+
timestamp(evidence.observedAt, resource, `${path}.observedAt`);
|
|
3232
|
+
}
|
|
3233
|
+
function validateNoReconciliation(value, resource, path) {
|
|
3234
|
+
const reconciliation = record(value, resource, path);
|
|
3235
|
+
exact(reconciliation, ["status"], [], resource, path);
|
|
3236
|
+
if (reconciliation.status !== "none") fail(resource, `${path}.status`, "none");
|
|
3237
|
+
}
|
|
3238
|
+
function validateRequiredReconciliation(value, allowed, resource, path) {
|
|
3239
|
+
const reconciliation = record(value, resource, path);
|
|
3240
|
+
exact(reconciliation, ["status", "reasons"], [], resource, path);
|
|
3241
|
+
if (reconciliation.status !== "required")
|
|
3242
|
+
fail(resource, `${path}.status`, "required");
|
|
3243
|
+
const reasons = array(reconciliation.reasons, resource, `${path}.reasons`);
|
|
3244
|
+
if (reasons.length === 0) fail(resource, `${path}.reasons`, "non-empty array");
|
|
3245
|
+
let previous = -1;
|
|
3246
|
+
reasons.forEach((reason, index) => {
|
|
3247
|
+
const current = allowed.indexOf(reason);
|
|
3248
|
+
if (current < 0 || current <= previous) {
|
|
3249
|
+
fail(
|
|
3250
|
+
resource,
|
|
3251
|
+
`${path}.reasons[${index}]`,
|
|
3252
|
+
"unique canonical-sorted reconciliation reason"
|
|
3253
|
+
);
|
|
3254
|
+
}
|
|
3255
|
+
previous = current;
|
|
3256
|
+
});
|
|
3257
|
+
}
|
|
3258
|
+
function validateNextAction(value, resource, path) {
|
|
3259
|
+
const action = record(value, resource, path);
|
|
3260
|
+
exact(
|
|
3261
|
+
action,
|
|
3262
|
+
[
|
|
3263
|
+
"type",
|
|
3264
|
+
"clientKey",
|
|
3265
|
+
"paymentMethodVariantKey",
|
|
3266
|
+
"agreementVariantKey",
|
|
3267
|
+
"providerOrderId",
|
|
3268
|
+
"providerCustomerKey",
|
|
3269
|
+
"orderName"
|
|
3270
|
+
],
|
|
3271
|
+
["customerName", "customerEmail"],
|
|
3272
|
+
resource,
|
|
3273
|
+
path
|
|
3274
|
+
);
|
|
3275
|
+
if (action.type !== "toss_widget")
|
|
3276
|
+
fail(resource, `${path}.type`, "toss_widget");
|
|
3277
|
+
for (const key of [
|
|
3278
|
+
"clientKey",
|
|
3279
|
+
"paymentMethodVariantKey",
|
|
3280
|
+
"agreementVariantKey"
|
|
3281
|
+
]) {
|
|
3282
|
+
boundedString(action[key], 255, resource, `${path}.${key}`);
|
|
3283
|
+
}
|
|
3284
|
+
string(action.providerOrderId, resource, `${path}.providerOrderId`);
|
|
3285
|
+
string(action.providerCustomerKey, resource, `${path}.providerCustomerKey`);
|
|
3286
|
+
boundedString(
|
|
3287
|
+
action.orderName,
|
|
3288
|
+
MAX_COMMERCE_SHORT_TEXT_LENGTH,
|
|
3289
|
+
resource,
|
|
3290
|
+
`${path}.orderName`
|
|
3291
|
+
);
|
|
3292
|
+
if (!/^[A-Za-z0-9_-]{6,64}$/.test(action.providerOrderId)) {
|
|
3293
|
+
fail(resource, `${path}.providerOrderId`, "valid Toss provider order ID");
|
|
3294
|
+
}
|
|
3295
|
+
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(
|
|
3296
|
+
action.providerCustomerKey
|
|
3297
|
+
)) {
|
|
3298
|
+
fail(resource, `${path}.providerCustomerKey`, "ANONYMOUS or UUIDv4");
|
|
3299
|
+
}
|
|
3300
|
+
if (action.customerName !== void 0)
|
|
3301
|
+
boundedString(
|
|
3302
|
+
action.customerName,
|
|
3303
|
+
MAX_COMMERCE_SHORT_TEXT_LENGTH,
|
|
3304
|
+
resource,
|
|
3305
|
+
`${path}.customerName`
|
|
3306
|
+
);
|
|
3307
|
+
if (action.customerEmail !== void 0)
|
|
3308
|
+
validateCustomer({ email: action.customerEmail }, resource, path);
|
|
3309
|
+
}
|
|
3310
|
+
function validatePublicPaymentSession(value) {
|
|
3311
|
+
const resource = "PaymentSession";
|
|
3312
|
+
const session = record(value, resource, "$");
|
|
3313
|
+
enumValue(session.provider, PAYMENT_PROVIDERS, resource, "$.provider");
|
|
3314
|
+
const status = enumValue(
|
|
3315
|
+
session.providerStatus,
|
|
3316
|
+
PAYMENT_PROVIDER_STATUSES,
|
|
3317
|
+
resource,
|
|
3318
|
+
"$.providerStatus"
|
|
3319
|
+
);
|
|
3320
|
+
const common = [
|
|
3321
|
+
"id",
|
|
3322
|
+
"money",
|
|
3323
|
+
"expiresAt",
|
|
3324
|
+
"sessionRole",
|
|
3325
|
+
"provider",
|
|
3326
|
+
"providerStatus",
|
|
3327
|
+
"presentationStatus",
|
|
3328
|
+
"finalizationStatus",
|
|
3329
|
+
"reconciliation",
|
|
3330
|
+
"order"
|
|
3331
|
+
];
|
|
3332
|
+
const optional = [];
|
|
3333
|
+
if (status === "requires_payment_method" || status === "requires_action")
|
|
3334
|
+
optional.push("nextAction");
|
|
3335
|
+
else if (status === "captured") common.push("providerEvidence");
|
|
3336
|
+
else if (status === "failed") common.push("failure");
|
|
3337
|
+
else if (status === "canceled") common.push("cancellationReason");
|
|
3338
|
+
exact(session, common, optional, resource, "$");
|
|
3339
|
+
string(session.id, resource, "$.id");
|
|
3340
|
+
validateMoney(session.money, resource, "$.money");
|
|
3341
|
+
if (session.expiresAt !== null)
|
|
3342
|
+
timestamp(session.expiresAt, resource, "$.expiresAt");
|
|
3343
|
+
if (status === "requires_payment_method" || status === "requires_action") {
|
|
3344
|
+
if (session.sessionRole === "active") {
|
|
3345
|
+
if (session.presentationStatus !== "actionable" || session.finalizationStatus !== "not_ready") {
|
|
3346
|
+
fail(resource, "$", "actionable active not-ready state");
|
|
3347
|
+
}
|
|
3348
|
+
if (!("nextAction" in session))
|
|
3349
|
+
fail(resource, "$.nextAction", "required field");
|
|
3350
|
+
validateNextAction(session.nextAction, resource, "$.nextAction");
|
|
3351
|
+
} else if (session.sessionRole === "residual") {
|
|
3352
|
+
if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
|
|
3353
|
+
fail(resource, "$", "suppressed residual not-ready state");
|
|
3354
|
+
}
|
|
3355
|
+
if ("nextAction" in session)
|
|
3356
|
+
fail(resource, "$.nextAction", "absent for suppressed state");
|
|
3357
|
+
} else fail(resource, "$.sessionRole", "active | residual");
|
|
3358
|
+
validateNoReconciliation(
|
|
3359
|
+
session.reconciliation,
|
|
3360
|
+
resource,
|
|
3361
|
+
"$.reconciliation"
|
|
3362
|
+
);
|
|
3363
|
+
if (session.order !== null) fail(resource, "$.order", "null");
|
|
3364
|
+
} else if ([
|
|
3365
|
+
"requires_confirmation",
|
|
3366
|
+
"initializing",
|
|
3367
|
+
"processing",
|
|
3368
|
+
"authorized",
|
|
3369
|
+
"canceling"
|
|
3370
|
+
].includes(status)) {
|
|
3371
|
+
enumValue(
|
|
3372
|
+
session.sessionRole,
|
|
3373
|
+
["active", "residual"],
|
|
3374
|
+
resource,
|
|
3375
|
+
"$.sessionRole"
|
|
3376
|
+
);
|
|
3377
|
+
if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
|
|
3378
|
+
fail(resource, "$", "suppressed not-ready state");
|
|
3379
|
+
}
|
|
3380
|
+
validateNoReconciliation(
|
|
3381
|
+
session.reconciliation,
|
|
3382
|
+
resource,
|
|
3383
|
+
"$.reconciliation"
|
|
3384
|
+
);
|
|
3385
|
+
if (session.order !== null) fail(resource, "$.order", "null");
|
|
3386
|
+
} else if (status === "unknown") {
|
|
3387
|
+
enumValue(
|
|
3388
|
+
session.sessionRole,
|
|
3389
|
+
["active", "residual"],
|
|
3390
|
+
resource,
|
|
3391
|
+
"$.sessionRole"
|
|
3392
|
+
);
|
|
3393
|
+
if (session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready") {
|
|
3394
|
+
fail(resource, "$", "suppressed not-ready state");
|
|
3395
|
+
}
|
|
3396
|
+
validateRequiredReconciliation(
|
|
3397
|
+
session.reconciliation,
|
|
3398
|
+
["provider_outcome_unknown"],
|
|
3399
|
+
resource,
|
|
3400
|
+
"$.reconciliation"
|
|
3401
|
+
);
|
|
3402
|
+
if (session.order !== null) fail(resource, "$.order", "null");
|
|
3403
|
+
} else if (status === "captured") {
|
|
3404
|
+
validateCaptureEvidence(
|
|
3405
|
+
session.providerEvidence,
|
|
3406
|
+
resource,
|
|
3407
|
+
"$.providerEvidence"
|
|
3408
|
+
);
|
|
3409
|
+
if (session.presentationStatus !== "suppressed")
|
|
3410
|
+
fail(resource, "$.presentationStatus", "suppressed");
|
|
3411
|
+
if (session.finalizationStatus === "pending") {
|
|
3412
|
+
enumValue(
|
|
3413
|
+
session.sessionRole,
|
|
3414
|
+
["canonical_candidate", "residual"],
|
|
3415
|
+
resource,
|
|
3416
|
+
"$.sessionRole"
|
|
3417
|
+
);
|
|
3418
|
+
if (session.order !== null)
|
|
3419
|
+
fail(resource, "$.order", "null for pending finalization");
|
|
3420
|
+
const reconciliation = record(
|
|
3421
|
+
session.reconciliation,
|
|
3422
|
+
resource,
|
|
3423
|
+
"$.reconciliation"
|
|
3424
|
+
);
|
|
3425
|
+
if (reconciliation.status === "none")
|
|
3426
|
+
validateNoReconciliation(reconciliation, resource, "$.reconciliation");
|
|
3427
|
+
else
|
|
3428
|
+
validateRequiredReconciliation(
|
|
3429
|
+
reconciliation,
|
|
3430
|
+
[
|
|
3431
|
+
"local_commit_ambiguous",
|
|
3432
|
+
"amount_mismatch",
|
|
3433
|
+
"currency_mismatch",
|
|
3434
|
+
"excess_capture_pending_order"
|
|
3435
|
+
],
|
|
3436
|
+
resource,
|
|
3437
|
+
"$.reconciliation"
|
|
3438
|
+
);
|
|
3439
|
+
} else if (session.finalizationStatus === "committed") {
|
|
3440
|
+
validateOrderReference(session.order, resource, "$.order");
|
|
3441
|
+
const reconciliation = record(
|
|
3442
|
+
session.reconciliation,
|
|
3443
|
+
resource,
|
|
3444
|
+
"$.reconciliation"
|
|
3445
|
+
);
|
|
3446
|
+
if (reconciliation.status === "none") {
|
|
3447
|
+
enumValue(
|
|
3448
|
+
session.sessionRole,
|
|
3449
|
+
["canonical", "historical"],
|
|
3450
|
+
resource,
|
|
3451
|
+
"$.sessionRole"
|
|
3452
|
+
);
|
|
3453
|
+
validateNoReconciliation(reconciliation, resource, "$.reconciliation");
|
|
3454
|
+
} else {
|
|
3455
|
+
enumValue(
|
|
3456
|
+
session.sessionRole,
|
|
3457
|
+
["canonical", "residual"],
|
|
3458
|
+
resource,
|
|
3459
|
+
"$.sessionRole"
|
|
3460
|
+
);
|
|
3461
|
+
validateRequiredReconciliation(
|
|
3462
|
+
reconciliation,
|
|
3463
|
+
[
|
|
3464
|
+
"inventory_unavailable",
|
|
3465
|
+
"admission_unavailable",
|
|
3466
|
+
"amount_mismatch",
|
|
3467
|
+
"currency_mismatch",
|
|
3468
|
+
"excess_capture",
|
|
3469
|
+
"late_capture",
|
|
3470
|
+
"cross_checkout_duplicate"
|
|
3471
|
+
],
|
|
3472
|
+
resource,
|
|
3473
|
+
"$.reconciliation"
|
|
3474
|
+
);
|
|
3475
|
+
}
|
|
3476
|
+
} else fail(resource, "$.finalizationStatus", "pending | committed");
|
|
3477
|
+
} else if (status === "failed") {
|
|
3478
|
+
if (session.sessionRole !== "historical" || session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready" || session.order !== null) {
|
|
3479
|
+
fail(resource, "$", "historical suppressed failed state");
|
|
3480
|
+
}
|
|
3481
|
+
validateNoReconciliation(
|
|
3482
|
+
session.reconciliation,
|
|
3483
|
+
resource,
|
|
3484
|
+
"$.reconciliation"
|
|
3485
|
+
);
|
|
3486
|
+
const failure = record(session.failure, resource, "$.failure");
|
|
3487
|
+
exact(failure, ["reason"], ["message"], resource, "$.failure");
|
|
3488
|
+
enumValue(
|
|
3489
|
+
failure.reason,
|
|
3490
|
+
PAYMENT_FAILURE_REASONS,
|
|
3491
|
+
resource,
|
|
3492
|
+
"$.failure.reason"
|
|
3493
|
+
);
|
|
3494
|
+
if (failure.message !== void 0)
|
|
3495
|
+
string(failure.message, resource, "$.failure.message");
|
|
3496
|
+
} else {
|
|
3497
|
+
if (session.sessionRole !== "historical" || session.presentationStatus !== "suppressed" || session.finalizationStatus !== "not_ready" || session.order !== null) {
|
|
3498
|
+
fail(resource, "$", "historical suppressed canceled state");
|
|
3499
|
+
}
|
|
3500
|
+
validateNoReconciliation(
|
|
3501
|
+
session.reconciliation,
|
|
3502
|
+
resource,
|
|
3503
|
+
"$.reconciliation"
|
|
3504
|
+
);
|
|
3505
|
+
enumValue(
|
|
3506
|
+
session.cancellationReason,
|
|
3507
|
+
["expired", "customer", "operator", "provider"],
|
|
3508
|
+
resource,
|
|
3509
|
+
"$.cancellationReason"
|
|
3510
|
+
);
|
|
3511
|
+
}
|
|
3512
|
+
return value;
|
|
1581
3513
|
}
|
|
1582
|
-
var ContentClient = class {
|
|
1583
|
-
constructor(options) {
|
|
1584
|
-
const api = new PublicContentApi("ContentClient", {
|
|
1585
|
-
publishableKey: options.publishableKey,
|
|
1586
|
-
apiUrl: options.apiUrl,
|
|
1587
|
-
onRequestId: options.onRequestId,
|
|
1588
|
-
requiresCredential: false
|
|
1589
|
-
});
|
|
1590
|
-
this.links = {
|
|
1591
|
-
list: (params) => api.get(linksListPath(params))
|
|
1592
|
-
};
|
|
1593
|
-
this.galleryItems = {
|
|
1594
|
-
list: (params) => api.get(
|
|
1595
|
-
galleryItemsListPath(params)
|
|
1596
|
-
)
|
|
1597
|
-
};
|
|
1598
|
-
}
|
|
1599
|
-
};
|
|
1600
3514
|
|
|
1601
3515
|
// src/core/customer/customer-auth.ts
|
|
1602
3516
|
var DEFAULT_TIMEOUT2 = 15e3;
|
|
@@ -1615,8 +3529,10 @@ var CustomerAuth = class {
|
|
|
1615
3529
|
const persist = options?.persist ?? true;
|
|
1616
3530
|
if (persist) {
|
|
1617
3531
|
const key = typeof persist === "string" ? persist : "customer-token";
|
|
3532
|
+
const refreshKey = `${key}:refresh`;
|
|
1618
3533
|
const isBrowser = typeof window !== "undefined";
|
|
1619
3534
|
this.token = isBrowser ? safeGetItem(key) : null;
|
|
3535
|
+
this.refreshTokenValue = isBrowser ? safeGetItem(refreshKey) : null;
|
|
1620
3536
|
this.onTokenChange = isBrowser ? (token) => {
|
|
1621
3537
|
try {
|
|
1622
3538
|
if (token) localStorage.setItem(key, token);
|
|
@@ -1624,9 +3540,18 @@ var CustomerAuth = class {
|
|
|
1624
3540
|
} catch {
|
|
1625
3541
|
}
|
|
1626
3542
|
} : void 0;
|
|
3543
|
+
this.onRefreshTokenChange = isBrowser ? (refreshToken) => {
|
|
3544
|
+
try {
|
|
3545
|
+
if (refreshToken) localStorage.setItem(refreshKey, refreshToken);
|
|
3546
|
+
else localStorage.removeItem(refreshKey);
|
|
3547
|
+
} catch {
|
|
3548
|
+
}
|
|
3549
|
+
} : void 0;
|
|
1627
3550
|
} else {
|
|
1628
3551
|
this.token = options?.token ?? null;
|
|
3552
|
+
this.refreshTokenValue = options?.refreshToken ?? null;
|
|
1629
3553
|
this.onTokenChange = options?.onTokenChange;
|
|
3554
|
+
this.onRefreshTokenChange = options?.onRefreshTokenChange;
|
|
1630
3555
|
}
|
|
1631
3556
|
}
|
|
1632
3557
|
/**
|
|
@@ -1650,13 +3575,17 @@ var CustomerAuth = class {
|
|
|
1650
3575
|
}
|
|
1651
3576
|
);
|
|
1652
3577
|
this.setToken(result.token);
|
|
3578
|
+
if (result.refreshToken) this.setRefreshToken(result.refreshToken);
|
|
1653
3579
|
return result;
|
|
1654
3580
|
}
|
|
1655
3581
|
/**
|
|
1656
|
-
* Refresh the current token.
|
|
3582
|
+
* Refresh the current token. Uses a refresh token when available, otherwise
|
|
3583
|
+
* falls back to the legacy bearer-token compatibility path.
|
|
1657
3584
|
*/
|
|
1658
3585
|
async refreshToken() {
|
|
1659
|
-
if (!this.token)
|
|
3586
|
+
if (!this.refreshTokenValue && !this.token) {
|
|
3587
|
+
throw new ApiError("Not authenticated", 401);
|
|
3588
|
+
}
|
|
1660
3589
|
if (this.refreshPromise) return this.refreshPromise;
|
|
1661
3590
|
this.refreshPromise = this._doRefreshToken();
|
|
1662
3591
|
try {
|
|
@@ -1666,14 +3595,19 @@ var CustomerAuth = class {
|
|
|
1666
3595
|
}
|
|
1667
3596
|
}
|
|
1668
3597
|
async _doRefreshToken() {
|
|
3598
|
+
const init = this.refreshTokenValue ? {
|
|
3599
|
+
method: "POST",
|
|
3600
|
+
body: JSON.stringify({ refreshToken: this.refreshTokenValue })
|
|
3601
|
+
} : {
|
|
3602
|
+
method: "POST",
|
|
3603
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
3604
|
+
};
|
|
1669
3605
|
const result = await this.requestJson(
|
|
1670
3606
|
"/api/customers/refresh",
|
|
1671
|
-
|
|
1672
|
-
method: "POST",
|
|
1673
|
-
headers: { Authorization: `Bearer ${this.token}` }
|
|
1674
|
-
}
|
|
3607
|
+
init
|
|
1675
3608
|
);
|
|
1676
3609
|
this.setToken(result.token);
|
|
3610
|
+
if (result.refreshToken) this.setRefreshToken(result.refreshToken);
|
|
1677
3611
|
return result;
|
|
1678
3612
|
}
|
|
1679
3613
|
/**
|
|
@@ -1681,6 +3615,7 @@ var CustomerAuth = class {
|
|
|
1681
3615
|
*/
|
|
1682
3616
|
logout() {
|
|
1683
3617
|
this.setToken(null);
|
|
3618
|
+
this.setRefreshToken(null);
|
|
1684
3619
|
}
|
|
1685
3620
|
/**
|
|
1686
3621
|
* Get the current authenticated customer's profile
|
|
@@ -1756,25 +3691,28 @@ var CustomerAuth = class {
|
|
|
1756
3691
|
const params = new URLSearchParams();
|
|
1757
3692
|
if (options?.page) params.set("page", String(options.page));
|
|
1758
3693
|
if (options?.limit) params.set("limit", String(options.limit));
|
|
1759
|
-
if (options?.
|
|
1760
|
-
params.set("
|
|
3694
|
+
if (options?.financialStatus) {
|
|
3695
|
+
params.set("financialStatus", options.financialStatus);
|
|
1761
3696
|
}
|
|
1762
|
-
if (options?.
|
|
1763
|
-
params.set("
|
|
3697
|
+
if (options?.fulfillmentStatus) {
|
|
3698
|
+
params.set("fulfillmentStatus", options.fulfillmentStatus);
|
|
1764
3699
|
}
|
|
1765
3700
|
if (options?.returnStatus) params.set("returnStatus", options.returnStatus);
|
|
3701
|
+
if (options?.confirmationStatus) {
|
|
3702
|
+
params.set("confirmationStatus", options.confirmationStatus);
|
|
3703
|
+
}
|
|
1766
3704
|
if (options?.primaryDisplayStatus) {
|
|
1767
3705
|
params.set("primaryDisplayStatus", options.primaryDisplayStatus);
|
|
1768
3706
|
}
|
|
1769
|
-
if (options?.returnDisplayStatus) {
|
|
1770
|
-
params.set("returnDisplayStatus", options.returnDisplayStatus);
|
|
1771
|
-
}
|
|
1772
|
-
if (options?.status) params.set("status", options.status);
|
|
1773
3707
|
const qs = params.toString();
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
3708
|
+
const result = await this.requestJson(
|
|
3709
|
+
`/api/customers/me/orders${qs ? `?${qs}` : ""}`,
|
|
3710
|
+
{
|
|
3711
|
+
method: "GET",
|
|
3712
|
+
headers: { Authorization: `Bearer ${this.token}` }
|
|
3713
|
+
}
|
|
3714
|
+
);
|
|
3715
|
+
return validatePublicOrderList(result);
|
|
1778
3716
|
}
|
|
1779
3717
|
/**
|
|
1780
3718
|
* Get the current token (or null if not authenticated)
|
|
@@ -1782,6 +3720,12 @@ var CustomerAuth = class {
|
|
|
1782
3720
|
getToken() {
|
|
1783
3721
|
return this.token;
|
|
1784
3722
|
}
|
|
3723
|
+
/**
|
|
3724
|
+
* Get the current refresh token (or null if unavailable)
|
|
3725
|
+
*/
|
|
3726
|
+
getRefreshToken() {
|
|
3727
|
+
return this.refreshTokenValue;
|
|
3728
|
+
}
|
|
1785
3729
|
/**
|
|
1786
3730
|
* Set the token manually (e.g. from SSR)
|
|
1787
3731
|
*/
|
|
@@ -1789,6 +3733,13 @@ var CustomerAuth = class {
|
|
|
1789
3733
|
this.token = token;
|
|
1790
3734
|
this.onTokenChange?.(token);
|
|
1791
3735
|
}
|
|
3736
|
+
/**
|
|
3737
|
+
* Set the refresh token manually (e.g. from SSR cookie)
|
|
3738
|
+
*/
|
|
3739
|
+
setRefreshToken(refreshToken) {
|
|
3740
|
+
this.refreshTokenValue = refreshToken;
|
|
3741
|
+
this.onRefreshTokenChange?.(refreshToken);
|
|
3742
|
+
}
|
|
1792
3743
|
/**
|
|
1793
3744
|
* Check if the customer is currently authenticated
|
|
1794
3745
|
*/
|
|
@@ -1817,91 +3768,362 @@ var CustomerAuth = class {
|
|
|
1817
3768
|
}
|
|
1818
3769
|
};
|
|
1819
3770
|
|
|
3771
|
+
// src/core/customer/customer-oauth.ts
|
|
3772
|
+
var DEFAULT_SCOPES = ["openid", "profile", "email"];
|
|
3773
|
+
var DEFAULT_TIMEOUT3 = 15e3;
|
|
3774
|
+
function issuerUrl(issuer, path) {
|
|
3775
|
+
const base = resolveApiUrl(issuer);
|
|
3776
|
+
return new URL(path, base.endsWith("/") ? base : `${base}/`).toString();
|
|
3777
|
+
}
|
|
3778
|
+
function randomBase64Url(bytes) {
|
|
3779
|
+
const buffer = new Uint8Array(bytes);
|
|
3780
|
+
crypto.getRandomValues(buffer);
|
|
3781
|
+
let binary = "";
|
|
3782
|
+
for (const value of buffer) {
|
|
3783
|
+
binary += String.fromCharCode(value);
|
|
3784
|
+
}
|
|
3785
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
3786
|
+
}
|
|
3787
|
+
async function sha256Base64Url(value) {
|
|
3788
|
+
const data = new TextEncoder().encode(value);
|
|
3789
|
+
const digest = await crypto.subtle.digest("SHA-256", data);
|
|
3790
|
+
let binary = "";
|
|
3791
|
+
for (const byte of new Uint8Array(digest)) {
|
|
3792
|
+
binary += String.fromCharCode(byte);
|
|
3793
|
+
}
|
|
3794
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
3795
|
+
}
|
|
3796
|
+
function normalizeToken(body) {
|
|
3797
|
+
if (body.token_type !== "Bearer") {
|
|
3798
|
+
throw new Error("Unsupported customer OAuth token type");
|
|
3799
|
+
}
|
|
3800
|
+
return {
|
|
3801
|
+
accessToken: body.access_token,
|
|
3802
|
+
expiresAt: Date.now() + body.expires_in * 1e3,
|
|
3803
|
+
expiresIn: body.expires_in,
|
|
3804
|
+
...body.id_token ? { idToken: body.id_token } : {},
|
|
3805
|
+
refreshToken: body.refresh_token,
|
|
3806
|
+
...body.scope ? { scope: body.scope } : {},
|
|
3807
|
+
tokenType: "Bearer"
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
var CustomerOAuth = class {
|
|
3811
|
+
constructor(config) {
|
|
3812
|
+
if (!config.clientId) throw new Error("customer OAuth clientId is required");
|
|
3813
|
+
if (!config.issuer) throw new Error("customer OAuth issuer is required");
|
|
3814
|
+
this.clientId = config.clientId;
|
|
3815
|
+
this.issuer = config.issuer;
|
|
3816
|
+
this.timeout = config.timeout ?? DEFAULT_TIMEOUT3;
|
|
3817
|
+
}
|
|
3818
|
+
async createAuthorizationUrl(input) {
|
|
3819
|
+
const codeVerifier = randomBase64Url(48);
|
|
3820
|
+
const codeChallenge = await sha256Base64Url(codeVerifier);
|
|
3821
|
+
const state = randomBase64Url(32);
|
|
3822
|
+
const nonce = randomBase64Url(32);
|
|
3823
|
+
const scopes = input.scopes ?? DEFAULT_SCOPES;
|
|
3824
|
+
const url = new URL(issuerUrl(this.issuer, "customer-oauth/authorize"));
|
|
3825
|
+
url.searchParams.set("response_type", "code");
|
|
3826
|
+
url.searchParams.set("client_id", this.clientId);
|
|
3827
|
+
url.searchParams.set("redirect_uri", input.redirectUri);
|
|
3828
|
+
url.searchParams.set("scope", scopes.join(" "));
|
|
3829
|
+
url.searchParams.set("state", state);
|
|
3830
|
+
url.searchParams.set("nonce", nonce);
|
|
3831
|
+
url.searchParams.set("code_challenge", codeChallenge);
|
|
3832
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
3833
|
+
return {
|
|
3834
|
+
authorizationUrl: url.toString(),
|
|
3835
|
+
codeChallenge,
|
|
3836
|
+
codeVerifier,
|
|
3837
|
+
nonce,
|
|
3838
|
+
returnTo: input.returnTo ?? null,
|
|
3839
|
+
state
|
|
3840
|
+
};
|
|
3841
|
+
}
|
|
3842
|
+
parseCallback(callbackUrl, options) {
|
|
3843
|
+
const url = new URL(callbackUrl);
|
|
3844
|
+
const error = url.searchParams.get("error");
|
|
3845
|
+
if (error) {
|
|
3846
|
+
throw new Error(
|
|
3847
|
+
url.searchParams.get("error_description") ?? `OAuth error: ${error}`
|
|
3848
|
+
);
|
|
3849
|
+
}
|
|
3850
|
+
const code = url.searchParams.get("code");
|
|
3851
|
+
const state = url.searchParams.get("state");
|
|
3852
|
+
if (!code || !state) throw new Error("OAuth callback is missing code/state");
|
|
3853
|
+
if (state !== options.expectedState) throw new Error("OAuth state mismatch");
|
|
3854
|
+
return { code, state };
|
|
3855
|
+
}
|
|
3856
|
+
async exchangeCode(input) {
|
|
3857
|
+
const body = new URLSearchParams({
|
|
3858
|
+
client_id: this.clientId,
|
|
3859
|
+
code: input.code,
|
|
3860
|
+
code_verifier: input.codeVerifier,
|
|
3861
|
+
grant_type: "authorization_code",
|
|
3862
|
+
redirect_uri: input.redirectUri
|
|
3863
|
+
});
|
|
3864
|
+
return this.tokenRequest(body);
|
|
3865
|
+
}
|
|
3866
|
+
async refresh(input) {
|
|
3867
|
+
const body = new URLSearchParams({
|
|
3868
|
+
client_id: this.clientId,
|
|
3869
|
+
grant_type: "refresh_token",
|
|
3870
|
+
refresh_token: input.refreshToken
|
|
3871
|
+
});
|
|
3872
|
+
return this.tokenRequest(body);
|
|
3873
|
+
}
|
|
3874
|
+
async logout(input) {
|
|
3875
|
+
const body = { client_id: this.clientId };
|
|
3876
|
+
if (input.refreshToken) body.refresh_token = input.refreshToken;
|
|
3877
|
+
if (input.postLogoutRedirectUri) {
|
|
3878
|
+
body.post_logout_redirect_uri = input.postLogoutRedirectUri;
|
|
3879
|
+
}
|
|
3880
|
+
const response = await httpFetch("/customer-oauth/logout", {
|
|
3881
|
+
apiUrl: this.issuer,
|
|
3882
|
+
method: "POST",
|
|
3883
|
+
body: JSON.stringify(body),
|
|
3884
|
+
headers: { "Content-Type": "application/json" },
|
|
3885
|
+
timeout: this.timeout,
|
|
3886
|
+
retry: { maxRetries: 0 }
|
|
3887
|
+
});
|
|
3888
|
+
return parseApiResponse(
|
|
3889
|
+
response,
|
|
3890
|
+
"/customer-oauth/logout"
|
|
3891
|
+
);
|
|
3892
|
+
}
|
|
3893
|
+
verifyIdToken() {
|
|
3894
|
+
throw new Error(
|
|
3895
|
+
"Customer OAuth ID token verification is not implemented; treat idToken as opaque."
|
|
3896
|
+
);
|
|
3897
|
+
}
|
|
3898
|
+
async tokenRequest(body) {
|
|
3899
|
+
const response = await httpFetch("/api/customer-oauth/token", {
|
|
3900
|
+
apiUrl: this.issuer,
|
|
3901
|
+
method: "POST",
|
|
3902
|
+
body,
|
|
3903
|
+
headers: {
|
|
3904
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
3905
|
+
},
|
|
3906
|
+
timeout: this.timeout,
|
|
3907
|
+
retry: { maxRetries: 0 }
|
|
3908
|
+
});
|
|
3909
|
+
return normalizeToken(
|
|
3910
|
+
await parseApiResponse(
|
|
3911
|
+
response,
|
|
3912
|
+
"/api/customer-oauth/token"
|
|
3913
|
+
)
|
|
3914
|
+
);
|
|
3915
|
+
}
|
|
3916
|
+
};
|
|
3917
|
+
|
|
1820
3918
|
// src/core/customer/customer-namespace.ts
|
|
1821
3919
|
var CustomerNamespace = class {
|
|
1822
3920
|
constructor(publishableKey, options, apiUrl) {
|
|
1823
3921
|
this.auth = new CustomerAuth(publishableKey, options, apiUrl);
|
|
3922
|
+
if (options?.oauth) {
|
|
3923
|
+
this.oauth = new CustomerOAuth(options.oauth);
|
|
3924
|
+
}
|
|
1824
3925
|
}
|
|
1825
3926
|
};
|
|
1826
3927
|
|
|
3928
|
+
// src/core/api/commerce-idempotency.ts
|
|
3929
|
+
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;
|
|
3930
|
+
var PREFIXED_BASE64URL_PATTERN = /^ik_[A-Za-z0-9_-]{22}$/;
|
|
3931
|
+
function isCommerceIdempotencyKey(value) {
|
|
3932
|
+
return typeof value === "string" && value.length <= 255 && (UUID_V4_PATTERN.test(value) || PREFIXED_BASE64URL_PATTERN.test(value));
|
|
3933
|
+
}
|
|
3934
|
+
function assertCommerceIdempotencyKey(value) {
|
|
3935
|
+
if (isCommerceIdempotencyKey(value)) return;
|
|
3936
|
+
throw createValidationError(
|
|
3937
|
+
"idempotencyKey must be a UUIDv4 or ik_-prefixed 128-bit base64url value.",
|
|
3938
|
+
{ field: "idempotencyKey" }
|
|
3939
|
+
);
|
|
3940
|
+
}
|
|
3941
|
+
function createCommerceIdempotencyKey() {
|
|
3942
|
+
return globalThis.crypto.randomUUID();
|
|
3943
|
+
}
|
|
3944
|
+
|
|
1827
3945
|
// src/core/api/cart-api.ts
|
|
3946
|
+
var MAX_CART_LINE_ADMISSIONS = 32;
|
|
1828
3947
|
var CartApi = class extends CustomerScopedApi {
|
|
1829
3948
|
constructor(options) {
|
|
1830
3949
|
super("CartApi", { ...options, requiresCredential: false });
|
|
3950
|
+
this.serverTransport = Boolean(options.secretKey);
|
|
1831
3951
|
}
|
|
1832
|
-
|
|
1833
|
-
return this.
|
|
3952
|
+
endpoint(key) {
|
|
3953
|
+
return this.serverTransport ? COMMERCE_ENDPOINTS.carts.server[key] : COMMERCE_ENDPOINTS.carts[key];
|
|
1834
3954
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
3955
|
+
execute(endpoint2, body, idempotencyKey) {
|
|
3956
|
+
return this.requestEndpoint(endpoint2, body, {
|
|
3957
|
+
...idempotencyKey && {
|
|
3958
|
+
headers: { "X-Idempotency-Key": idempotencyKey }
|
|
3959
|
+
}
|
|
3960
|
+
});
|
|
1841
3961
|
}
|
|
1842
|
-
|
|
1843
|
-
return this.execute("
|
|
3962
|
+
create(params = {}) {
|
|
3963
|
+
return this.execute(this.endpoint("create"), params).then(
|
|
3964
|
+
(value) => validateCreateCartResult(value)
|
|
3965
|
+
);
|
|
1844
3966
|
}
|
|
1845
|
-
|
|
1846
|
-
return this.execute(
|
|
1847
|
-
|
|
1848
|
-
"POST",
|
|
1849
|
-
params
|
|
3967
|
+
retrieve(params) {
|
|
3968
|
+
return this.execute(this.endpoint("retrieve"), params).then(
|
|
3969
|
+
(value) => validatePublicCart(value)
|
|
1850
3970
|
);
|
|
1851
3971
|
}
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
3972
|
+
mine(params = {}) {
|
|
3973
|
+
const endpoint2 = this.endpoint("mine");
|
|
3974
|
+
return this.execute(endpoint2, params).then(
|
|
3975
|
+
(value) => validateCartMineResult(value)
|
|
3976
|
+
);
|
|
3977
|
+
}
|
|
3978
|
+
merge(params) {
|
|
3979
|
+
const { idempotencyKey, ...body } = params;
|
|
3980
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3981
|
+
const endpoint2 = this.endpoint("merge");
|
|
3982
|
+
return this.execute(endpoint2, body, idempotencyKey).then(
|
|
3983
|
+
(value) => validateCartMergeResult(value)
|
|
1862
3984
|
);
|
|
1863
3985
|
}
|
|
1864
3986
|
addItem(params) {
|
|
1865
|
-
return this.
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
3987
|
+
return this.mutate(this.endpoint("addItem"), params);
|
|
3988
|
+
}
|
|
3989
|
+
mutate(endpoint2, params) {
|
|
3990
|
+
const { idempotencyKey, ...body } = params;
|
|
3991
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
3992
|
+
return this.execute(endpoint2, body, idempotencyKey).then(
|
|
3993
|
+
(value) => validateCartMutationResult(value)
|
|
1869
3994
|
);
|
|
1870
3995
|
}
|
|
1871
3996
|
updateItem(params) {
|
|
1872
|
-
return this.
|
|
1873
|
-
COMMERCE_ENDPOINTS.carts.updateItem,
|
|
1874
|
-
"POST",
|
|
1875
|
-
params
|
|
1876
|
-
);
|
|
3997
|
+
return this.mutate(this.endpoint("updateItem"), params);
|
|
1877
3998
|
}
|
|
1878
3999
|
removeItem(params) {
|
|
1879
|
-
return this.
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
4000
|
+
return this.mutate(this.endpoint("removeItem"), params);
|
|
4001
|
+
}
|
|
4002
|
+
clear(params) {
|
|
4003
|
+
return this.mutate(this.endpoint("clear"), params);
|
|
4004
|
+
}
|
|
4005
|
+
updateDiscountCodes(params) {
|
|
4006
|
+
return this.mutate(this.endpoint("updateDiscountCodes"), params);
|
|
4007
|
+
}
|
|
4008
|
+
updateAttributes(params) {
|
|
4009
|
+
return this.mutate(this.endpoint("updateAttributes"), params);
|
|
4010
|
+
}
|
|
4011
|
+
};
|
|
4012
|
+
|
|
4013
|
+
// src/core/api/checkout-api.ts
|
|
4014
|
+
var CheckoutApi = class extends CustomerScopedApi {
|
|
4015
|
+
constructor(options) {
|
|
4016
|
+
super("CheckoutApi", { ...options, requiresCredential: false });
|
|
4017
|
+
}
|
|
4018
|
+
post(endpoint2, body, idempotencyKey) {
|
|
4019
|
+
return this.requestEndpoint(endpoint2, body, {
|
|
4020
|
+
...idempotencyKey && {
|
|
4021
|
+
headers: { "X-Idempotency-Key": idempotencyKey }
|
|
4022
|
+
}
|
|
4023
|
+
});
|
|
4024
|
+
}
|
|
4025
|
+
async publicCheckout(result) {
|
|
4026
|
+
return validatePublicCheckout(await result);
|
|
4027
|
+
}
|
|
4028
|
+
async serverCheckout(result) {
|
|
4029
|
+
return validateServerCheckout(await result);
|
|
4030
|
+
}
|
|
4031
|
+
async createResult(result) {
|
|
4032
|
+
return validateCreateCheckoutResult(
|
|
4033
|
+
await result,
|
|
4034
|
+
false
|
|
1883
4035
|
);
|
|
1884
4036
|
}
|
|
1885
|
-
|
|
1886
|
-
return
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
params
|
|
4037
|
+
async createServerResult(result) {
|
|
4038
|
+
return validateCreateCheckoutResult(
|
|
4039
|
+
await result,
|
|
4040
|
+
true
|
|
1890
4041
|
);
|
|
1891
4042
|
}
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
4043
|
+
create(params) {
|
|
4044
|
+
const { idempotencyKey, ...body } = params;
|
|
4045
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4046
|
+
return this.createResult(
|
|
4047
|
+
this.post(COMMERCE_ENDPOINTS.checkouts.create, body, idempotencyKey)
|
|
1897
4048
|
);
|
|
1898
4049
|
}
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
4050
|
+
createServer(params) {
|
|
4051
|
+
const { idempotencyKey, ...body } = params;
|
|
4052
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4053
|
+
return this.createServerResult(
|
|
4054
|
+
this.post(
|
|
4055
|
+
COMMERCE_ENDPOINTS.checkouts.server.create,
|
|
4056
|
+
body,
|
|
4057
|
+
idempotencyKey
|
|
4058
|
+
)
|
|
4059
|
+
);
|
|
4060
|
+
}
|
|
4061
|
+
retrieve(params) {
|
|
4062
|
+
return this.publicCheckout(
|
|
4063
|
+
this.post(COMMERCE_ENDPOINTS.checkouts.retrieve, params)
|
|
4064
|
+
);
|
|
4065
|
+
}
|
|
4066
|
+
retrieveServer(params) {
|
|
4067
|
+
return this.serverCheckout(
|
|
4068
|
+
this.post(COMMERCE_ENDPOINTS.checkouts.server.retrieve, params)
|
|
4069
|
+
);
|
|
4070
|
+
}
|
|
4071
|
+
async query(params = {}) {
|
|
4072
|
+
const result = await this.post(
|
|
4073
|
+
COMMERCE_ENDPOINTS.checkouts.server.query,
|
|
1903
4074
|
params
|
|
1904
4075
|
);
|
|
4076
|
+
return validateCheckoutQueryResult(result);
|
|
4077
|
+
}
|
|
4078
|
+
};
|
|
4079
|
+
|
|
4080
|
+
// src/core/api/payment-session-api.ts
|
|
4081
|
+
var PaymentSessionApi = class extends CustomerScopedApi {
|
|
4082
|
+
constructor(options) {
|
|
4083
|
+
super("PaymentSessionApi", { ...options, requiresCredential: false });
|
|
4084
|
+
this.serverTransport = Boolean(options.secretKey);
|
|
4085
|
+
}
|
|
4086
|
+
post(endpoint2, body, idempotencyKey) {
|
|
4087
|
+
return this.requestEndpoint(endpoint2, body, {
|
|
4088
|
+
...idempotencyKey && {
|
|
4089
|
+
headers: { "X-Idempotency-Key": idempotencyKey }
|
|
4090
|
+
}
|
|
4091
|
+
});
|
|
4092
|
+
}
|
|
4093
|
+
async paymentSession(result) {
|
|
4094
|
+
return validatePublicPaymentSession(await result);
|
|
4095
|
+
}
|
|
4096
|
+
create(params) {
|
|
4097
|
+
const { idempotencyKey, ...body } = params;
|
|
4098
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4099
|
+
return this.paymentSession(
|
|
4100
|
+
this.post(
|
|
4101
|
+
this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.create : COMMERCE_ENDPOINTS.paymentSessions.create,
|
|
4102
|
+
body,
|
|
4103
|
+
idempotencyKey
|
|
4104
|
+
)
|
|
4105
|
+
);
|
|
4106
|
+
}
|
|
4107
|
+
retrieve(params) {
|
|
4108
|
+
const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.retrieve : COMMERCE_ENDPOINTS.paymentSessions.retrieve;
|
|
4109
|
+
return this.paymentSession(this.post(endpoint2, params));
|
|
4110
|
+
}
|
|
4111
|
+
cancel(params) {
|
|
4112
|
+
const { idempotencyKey, ...body } = params;
|
|
4113
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4114
|
+
const endpoint2 = this.serverTransport ? COMMERCE_ENDPOINTS.paymentSessions.server.cancel : COMMERCE_ENDPOINTS.paymentSessions.cancel;
|
|
4115
|
+
return this.paymentSession(this.post(endpoint2, body, idempotencyKey));
|
|
4116
|
+
}
|
|
4117
|
+
confirm(params) {
|
|
4118
|
+
const { idempotencyKey, ...body } = params;
|
|
4119
|
+
assertCommerceIdempotencyKey(idempotencyKey);
|
|
4120
|
+
return this.paymentSession(
|
|
4121
|
+
this.post(
|
|
4122
|
+
COMMERCE_ENDPOINTS.paymentSessions.server.confirm,
|
|
4123
|
+
body,
|
|
4124
|
+
idempotencyKey
|
|
4125
|
+
)
|
|
4126
|
+
);
|
|
1905
4127
|
}
|
|
1906
4128
|
};
|
|
1907
4129
|
|
|
@@ -2904,9 +5126,13 @@ function resolveVariantIdForCompleteSelection(matrix, selectedByOptionId) {
|
|
|
2904
5126
|
return getExactSelectedVariantEntry(matrix, normalized, matchingVariantEntries)?.id ?? null;
|
|
2905
5127
|
}
|
|
2906
5128
|
function buildSelectionPrice(variants) {
|
|
2907
|
-
const { min, max } = getMinMax(
|
|
5129
|
+
const { min, max } = getMinMax(
|
|
5130
|
+
variants.map((variant) => variant.resolvedPrice?.amount ?? variant.price)
|
|
5131
|
+
);
|
|
2908
5132
|
const { min: compareAtMin, max: compareAtMax } = getMinMax(
|
|
2909
|
-
variants.map(
|
|
5133
|
+
variants.map(
|
|
5134
|
+
(variant) => variant.resolvedPrice?.compareAtPrice ?? variant.compareAtPrice
|
|
5135
|
+
)
|
|
2910
5136
|
);
|
|
2911
5137
|
return {
|
|
2912
5138
|
min,
|
|
@@ -2966,8 +5192,8 @@ function buildSelectionStock(selectedVariant, matchingVariants) {
|
|
|
2966
5192
|
return {
|
|
2967
5193
|
availableForSale: getVariantAvailableForSale(selectedVariant),
|
|
2968
5194
|
isUnlimited: selectedVariant.isUnlimited,
|
|
2969
|
-
stock: selectedVariant.stock,
|
|
2970
|
-
reservedStock: selectedVariant.reservedStock,
|
|
5195
|
+
stock: "stock" in selectedVariant ? selectedVariant.stock : null,
|
|
5196
|
+
reservedStock: "reservedStock" in selectedVariant ? selectedVariant.reservedStock : null,
|
|
2971
5197
|
availableStock
|
|
2972
5198
|
};
|
|
2973
5199
|
}
|
|
@@ -3349,6 +5575,9 @@ function compareVariantOrder(a, b) {
|
|
|
3349
5575
|
}
|
|
3350
5576
|
function getVariantAvailableForSale(variant) {
|
|
3351
5577
|
if (variant.isActive === false) return false;
|
|
5578
|
+
if (typeof variant.availableForSale === "boolean") {
|
|
5579
|
+
return variant.availableForSale;
|
|
5580
|
+
}
|
|
3352
5581
|
if (variant.isUnlimited) return true;
|
|
3353
5582
|
if (variant.inventoryPolicy === "continue") return true;
|
|
3354
5583
|
return (variant.stock ?? 0) - (variant.reservedStock ?? 0) > 0;
|
|
@@ -3462,7 +5691,7 @@ function buildProductListingCard(item, options = {}) {
|
|
|
3462
5691
|
{ listing: { selectionHintVariant } },
|
|
3463
5692
|
options
|
|
3464
5693
|
),
|
|
3465
|
-
title: product.title,
|
|
5694
|
+
title: product.title ?? "",
|
|
3466
5695
|
representativeVariant,
|
|
3467
5696
|
primaryImage: listingPrimaryMedia,
|
|
3468
5697
|
priceRange,
|
|
@@ -3649,6 +5878,11 @@ function productDetailResultFromError(error) {
|
|
|
3649
5878
|
if (!reason) return void 0;
|
|
3650
5879
|
return { found: false, reason };
|
|
3651
5880
|
}
|
|
5881
|
+
var MARKET_PRICE_QUERY_UNSUPPORTED_MESSAGE = "Market listing pages do not support base price filters or price sorts.";
|
|
5882
|
+
var BASE_PRICE_RANGE_SORT_FIELDS = /* @__PURE__ */ new Set([
|
|
5883
|
+
"priceRange.minVariantPrice.amount",
|
|
5884
|
+
"priceRange.maxVariantPrice.amount"
|
|
5885
|
+
]);
|
|
3652
5886
|
function nonEmpty(values) {
|
|
3653
5887
|
return values?.length ? values : void 0;
|
|
3654
5888
|
}
|
|
@@ -3696,14 +5930,34 @@ function buildProductListingPageWhere(params) {
|
|
|
3696
5930
|
if (clauses.length === 1) return clauses[0];
|
|
3697
5931
|
return { and: clauses };
|
|
3698
5932
|
}
|
|
3699
|
-
function
|
|
5933
|
+
function productListingPageUsesBasePriceSort(sort) {
|
|
5934
|
+
const values = Array.isArray(sort) ? sort : sort ? [sort] : [];
|
|
5935
|
+
return values.some(
|
|
5936
|
+
(value) => BASE_PRICE_RANGE_SORT_FIELDS.has(String(value).replace(/^-/, ""))
|
|
5937
|
+
);
|
|
5938
|
+
}
|
|
5939
|
+
function assertMarketListingPageQuerySupported(params) {
|
|
5940
|
+
if (!params.market?.trim()) return;
|
|
5941
|
+
const priceFilter = params.filters?.price;
|
|
5942
|
+
if (priceFilter?.min != null || priceFilter?.max != null || productListingPageUsesBasePriceSort(params.sort)) {
|
|
5943
|
+
throw new TypeError(MARKET_PRICE_QUERY_UNSUPPORTED_MESSAGE);
|
|
5944
|
+
}
|
|
5945
|
+
}
|
|
5946
|
+
function buildProductListingPageRequest(params) {
|
|
5947
|
+
assertMarketListingPageQuerySupported(params);
|
|
3700
5948
|
const options = {
|
|
5949
|
+
market: params.market,
|
|
5950
|
+
locale: params.locale,
|
|
5951
|
+
fallbackLocale: params.fallbackLocale,
|
|
3701
5952
|
page: params.page,
|
|
3702
5953
|
limit: params.limit,
|
|
3703
5954
|
sort: params.sort,
|
|
3704
5955
|
where: buildProductListingPageWhere(params)
|
|
3705
5956
|
};
|
|
3706
|
-
return
|
|
5957
|
+
return {
|
|
5958
|
+
operation: params.mode === "full" ? COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryGet : COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsQueryCatalog,
|
|
5959
|
+
query: listingPageSearchParams(options)
|
|
5960
|
+
};
|
|
3707
5961
|
}
|
|
3708
5962
|
function withProductListingCards(response, options) {
|
|
3709
5963
|
return {
|
|
@@ -3720,30 +5974,15 @@ function isProductUpsertFieldValidationErrorBody(value) {
|
|
|
3720
5974
|
return typeof body.error === "string" && typeof body.field === "string" && (reason === PRODUCT_UPSERT_UNKNOWN_FIELD_REASON || reason === PRODUCT_UPSERT_READONLY_FIELD_REASON);
|
|
3721
5975
|
}
|
|
3722
5976
|
|
|
3723
|
-
// src/core/api/order-api.ts
|
|
3724
|
-
function idempotencyRequestOptions(idempotencyKey) {
|
|
3725
|
-
return idempotencyKey ? { headers: { "X-Idempotency-Key": idempotencyKey } } : void 0;
|
|
3726
|
-
}
|
|
3727
|
-
function splitIdempotencyKey(params) {
|
|
3728
|
-
const { idempotencyKey, ...body } = params;
|
|
3729
|
-
return { body, idempotencyKey };
|
|
3730
|
-
}
|
|
3731
|
-
|
|
3732
5977
|
// src/core/commerce/commerce-client.ts
|
|
3733
5978
|
var BrowserCommerceApi = class extends CustomerScopedApi {
|
|
3734
|
-
|
|
3735
|
-
return
|
|
3736
|
-
method: "POST",
|
|
3737
|
-
body,
|
|
3738
|
-
headers: requestOptions?.headers
|
|
3739
|
-
});
|
|
3740
|
-
}
|
|
3741
|
-
get(endpoint) {
|
|
3742
|
-
return this.request(endpoint, { method: "GET" });
|
|
5979
|
+
requestEndpoint(endpoint2, body, options) {
|
|
5980
|
+
return super.requestEndpoint(endpoint2, body, options);
|
|
3743
5981
|
}
|
|
3744
5982
|
};
|
|
3745
5983
|
var CommerceClient = class {
|
|
3746
5984
|
constructor(options) {
|
|
5985
|
+
this.market = options.market;
|
|
3747
5986
|
const cartApi = new CartApi({
|
|
3748
5987
|
publishableKey: options.publishableKey,
|
|
3749
5988
|
apiUrl: options.apiUrl,
|
|
@@ -3751,6 +5990,20 @@ var CommerceClient = class {
|
|
|
3751
5990
|
onUnauthorized: options.onUnauthorized,
|
|
3752
5991
|
onRequestId: options.onRequestId
|
|
3753
5992
|
});
|
|
5993
|
+
const checkoutApi = new CheckoutApi({
|
|
5994
|
+
publishableKey: options.publishableKey,
|
|
5995
|
+
apiUrl: options.apiUrl,
|
|
5996
|
+
customerToken: options.customerToken,
|
|
5997
|
+
onUnauthorized: options.onUnauthorized,
|
|
5998
|
+
onRequestId: options.onRequestId
|
|
5999
|
+
});
|
|
6000
|
+
const paymentSessionApi = new PaymentSessionApi({
|
|
6001
|
+
publishableKey: options.publishableKey,
|
|
6002
|
+
apiUrl: options.apiUrl,
|
|
6003
|
+
customerToken: options.customerToken,
|
|
6004
|
+
onUnauthorized: options.onUnauthorized,
|
|
6005
|
+
onRequestId: options.onRequestId
|
|
6006
|
+
});
|
|
3754
6007
|
const api = new BrowserCommerceApi("CommerceClient", {
|
|
3755
6008
|
publishableKey: options.publishableKey,
|
|
3756
6009
|
apiUrl: options.apiUrl,
|
|
@@ -3759,29 +6012,42 @@ var CommerceClient = class {
|
|
|
3759
6012
|
onRequestId: options.onRequestId
|
|
3760
6013
|
});
|
|
3761
6014
|
this.product = {
|
|
3762
|
-
stockCheck: (params) => api.
|
|
3763
|
-
|
|
6015
|
+
stockCheck: (params) => api.requestEndpoint(
|
|
6016
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.stockCheck,
|
|
3764
6017
|
params
|
|
3765
6018
|
),
|
|
3766
|
-
stockSnapshot: (params) => api.
|
|
3767
|
-
|
|
3768
|
-
|
|
6019
|
+
stockSnapshot: (params) => api.requestEndpoint(
|
|
6020
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.stockSnapshot,
|
|
6021
|
+
void 0,
|
|
6022
|
+
{ query: stockSnapshotSearchParams(params) }
|
|
6023
|
+
),
|
|
6024
|
+
listingGroups: (params) => api.requestEndpoint(
|
|
6025
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog,
|
|
6026
|
+
void 0,
|
|
6027
|
+
{ query: listingGroupsSearchParams(this.withMarket(params)) }
|
|
3769
6028
|
),
|
|
3770
|
-
listingGroupsCatalog: (params) => api.
|
|
3771
|
-
|
|
6029
|
+
listingGroupsCatalog: (params) => api.requestEndpoint(
|
|
6030
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.listingGroupsCatalog,
|
|
6031
|
+
void 0,
|
|
6032
|
+
{ query: listingGroupsSearchParams(this.withMarket(params)) }
|
|
3772
6033
|
),
|
|
3773
6034
|
listingPage: async (params = {}) => {
|
|
3774
6035
|
const catalogParams = {
|
|
3775
6036
|
...params,
|
|
3776
6037
|
mode: "catalog"
|
|
3777
6038
|
};
|
|
3778
|
-
const
|
|
3779
|
-
|
|
6039
|
+
const request = buildProductListingPageRequest(
|
|
6040
|
+
this.withMarket(catalogParams)
|
|
6041
|
+
);
|
|
6042
|
+
const response = await api.requestEndpoint(request.operation, void 0, { query: request.query });
|
|
6043
|
+
return withProductListingCards(response, this.withMarket(catalogParams));
|
|
3780
6044
|
},
|
|
3781
6045
|
detail: async (params) => {
|
|
3782
6046
|
try {
|
|
3783
|
-
const product = await api.
|
|
3784
|
-
|
|
6047
|
+
const product = await api.requestEndpoint(
|
|
6048
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog,
|
|
6049
|
+
void 0,
|
|
6050
|
+
{ query: productDetailSearchParams(this.withMarket(params)) }
|
|
3785
6051
|
);
|
|
3786
6052
|
return { found: true, product };
|
|
3787
6053
|
} catch (err) {
|
|
@@ -3792,8 +6058,10 @@ var CommerceClient = class {
|
|
|
3792
6058
|
},
|
|
3793
6059
|
detailCatalog: async (params) => {
|
|
3794
6060
|
try {
|
|
3795
|
-
const product = await api.
|
|
3796
|
-
|
|
6061
|
+
const product = await api.requestEndpoint(
|
|
6062
|
+
COMMERCE_ENDPOINT_OPERATIONS.products.detailCatalog,
|
|
6063
|
+
void 0,
|
|
6064
|
+
{ query: productDetailSearchParams(this.withMarket(params)) }
|
|
3797
6065
|
);
|
|
3798
6066
|
return { found: true, product };
|
|
3799
6067
|
} catch (err) {
|
|
@@ -3803,39 +6071,51 @@ var CommerceClient = class {
|
|
|
3803
6071
|
}
|
|
3804
6072
|
}
|
|
3805
6073
|
};
|
|
3806
|
-
this.
|
|
3807
|
-
create: cartApi.
|
|
3808
|
-
|
|
6074
|
+
this.carts = {
|
|
6075
|
+
create: (params) => cartApi.create(this.withMarket(params ?? {})),
|
|
6076
|
+
retrieve: cartApi.retrieve.bind(cartApi),
|
|
3809
6077
|
addItem: cartApi.addItem.bind(cartApi),
|
|
3810
6078
|
updateItem: cartApi.updateItem.bind(cartApi),
|
|
3811
6079
|
removeItem: cartApi.removeItem.bind(cartApi),
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
clear: cartApi.
|
|
6080
|
+
updateDiscountCodes: cartApi.updateDiscountCodes.bind(cartApi),
|
|
6081
|
+
updateAttributes: cartApi.updateAttributes.bind(cartApi),
|
|
6082
|
+
clear: cartApi.clear.bind(cartApi),
|
|
3815
6083
|
merge: cartApi.merge.bind(cartApi),
|
|
3816
6084
|
mine: cartApi.mine.bind(cartApi)
|
|
3817
6085
|
};
|
|
3818
6086
|
this.orders = {
|
|
3819
|
-
checkout: (params) => {
|
|
3820
|
-
const { body, idempotencyKey } = splitIdempotencyKey(params);
|
|
3821
|
-
return api.post(
|
|
3822
|
-
"/api/orders/checkout",
|
|
3823
|
-
body,
|
|
3824
|
-
idempotencyRequestOptions(idempotencyKey)
|
|
3825
|
-
);
|
|
3826
|
-
},
|
|
3827
6087
|
listMine: (params) => options.customerAuth.getMyOrders(params)
|
|
3828
6088
|
};
|
|
6089
|
+
this.checkouts = {
|
|
6090
|
+
create: checkoutApi.create.bind(checkoutApi),
|
|
6091
|
+
retrieve: checkoutApi.retrieve.bind(checkoutApi)
|
|
6092
|
+
};
|
|
6093
|
+
this.paymentSessions = {
|
|
6094
|
+
create: paymentSessionApi.create.bind(paymentSessionApi),
|
|
6095
|
+
retrieve: (params) => paymentSessionApi.retrieve(params),
|
|
6096
|
+
cancel: (params) => paymentSessionApi.cancel(params)
|
|
6097
|
+
};
|
|
3829
6098
|
this.discounts = {
|
|
3830
|
-
validate: (params) => api.
|
|
6099
|
+
validate: (params) => api.requestEndpoint(
|
|
6100
|
+
COMMERCE_ENDPOINT_OPERATIONS.discounts.validate,
|
|
6101
|
+
params
|
|
6102
|
+
)
|
|
3831
6103
|
};
|
|
3832
6104
|
this.shipping = {
|
|
3833
|
-
calculate: (params) => api.
|
|
3834
|
-
|
|
6105
|
+
calculate: (params) => api.requestEndpoint(
|
|
6106
|
+
COMMERCE_ENDPOINT_OPERATIONS.shippingPolicies.calculate,
|
|
3835
6107
|
params
|
|
3836
6108
|
)
|
|
3837
6109
|
};
|
|
3838
6110
|
}
|
|
6111
|
+
getDefaultMarket() {
|
|
6112
|
+
return this.market;
|
|
6113
|
+
}
|
|
6114
|
+
withMarket(params) {
|
|
6115
|
+
const defaultMarket = this.market?.trim();
|
|
6116
|
+
if (!defaultMarket || params.market?.trim()) return params;
|
|
6117
|
+
return { ...params, market: defaultMarket };
|
|
6118
|
+
}
|
|
3839
6119
|
};
|
|
3840
6120
|
|
|
3841
6121
|
// src/core/events/events-client.ts
|
|
@@ -3855,7 +6135,17 @@ var EventsClient = class {
|
|
|
3855
6135
|
getRange(params) {
|
|
3856
6136
|
return this.execute(
|
|
3857
6137
|
buildRangeEndpoint(params),
|
|
3858
|
-
|
|
6138
|
+
resolveOperationMethod(EVENTS_ENDPOINT_OPERATIONS.occurrences.range),
|
|
6139
|
+
void 0,
|
|
6140
|
+
{ useCustomerAuth: false }
|
|
6141
|
+
);
|
|
6142
|
+
}
|
|
6143
|
+
getAdmissionAvailability(params) {
|
|
6144
|
+
return this.execute(
|
|
6145
|
+
buildAdmissionAvailabilityEndpoint(params),
|
|
6146
|
+
resolveOperationMethod(
|
|
6147
|
+
EVENTS_ENDPOINT_OPERATIONS.occurrences.admissionAvailability
|
|
6148
|
+
),
|
|
3859
6149
|
void 0,
|
|
3860
6150
|
{ useCustomerAuth: false }
|
|
3861
6151
|
);
|
|
@@ -3884,11 +6174,11 @@ var EventsClient = class {
|
|
|
3884
6174
|
{ useCustomerAuth: false }
|
|
3885
6175
|
);
|
|
3886
6176
|
}
|
|
3887
|
-
async execute(
|
|
6177
|
+
async execute(endpoint2, method, body, options = {}) {
|
|
3888
6178
|
const useCustomerAuth = options.useCustomerAuth === true;
|
|
3889
6179
|
const token = useCustomerAuth ? typeof this.customerToken === "function" ? this.customerToken() : this.customerToken : void 0;
|
|
3890
6180
|
try {
|
|
3891
|
-
const response = await httpFetch(
|
|
6181
|
+
const response = await httpFetch(endpoint2, {
|
|
3892
6182
|
method,
|
|
3893
6183
|
apiUrl: this.apiUrl,
|
|
3894
6184
|
publishableKey: this.publishableKey,
|
|
@@ -3897,7 +6187,7 @@ var EventsClient = class {
|
|
|
3897
6187
|
...body !== void 0 && { body: JSON.stringify(body) }
|
|
3898
6188
|
});
|
|
3899
6189
|
this.onRequestId?.(response.headers.get("x-request-id") ?? null);
|
|
3900
|
-
return parseApiResponse(response,
|
|
6190
|
+
return parseApiResponse(response, endpoint2);
|
|
3901
6191
|
} catch (err) {
|
|
3902
6192
|
const id = err instanceof SDKError ? err.requestId ?? null : null;
|
|
3903
6193
|
this.onRequestId?.(id);
|
|
@@ -3936,7 +6226,17 @@ function buildRangeEndpoint(params) {
|
|
|
3936
6226
|
appendValues(urlParams, "categorySlug", params.categorySlug);
|
|
3937
6227
|
appendValues(urlParams, "tag", params.tag);
|
|
3938
6228
|
appendValues(urlParams, "tagSlug", params.tagSlug);
|
|
3939
|
-
return
|
|
6229
|
+
return resolveOperationPath(EVENTS_ENDPOINT_OPERATIONS.occurrences.range, {
|
|
6230
|
+
query: urlParams
|
|
6231
|
+
});
|
|
6232
|
+
}
|
|
6233
|
+
function buildAdmissionAvailabilityEndpoint(params) {
|
|
6234
|
+
const urlParams = new URLSearchParams();
|
|
6235
|
+
urlParams.set("occurrence", params.occurrence);
|
|
6236
|
+
return resolveOperationPath(
|
|
6237
|
+
EVENTS_ENDPOINT_OPERATIONS.occurrences.admissionAvailability,
|
|
6238
|
+
{ query: urlParams }
|
|
6239
|
+
);
|
|
3940
6240
|
}
|
|
3941
6241
|
function formatDateParam(value) {
|
|
3942
6242
|
return value instanceof Date ? value.toISOString() : value;
|
|
@@ -3949,15 +6249,62 @@ function appendValues(params, key, value) {
|
|
|
3949
6249
|
}
|
|
3950
6250
|
}
|
|
3951
6251
|
|
|
6252
|
+
// src/core/market/market-discovery.ts
|
|
6253
|
+
function toMarketDTO(row) {
|
|
6254
|
+
return {
|
|
6255
|
+
id: row.id,
|
|
6256
|
+
handle: row.handle,
|
|
6257
|
+
name: row.name,
|
|
6258
|
+
countryCode: row.countryCode,
|
|
6259
|
+
targetCountries: (row.targetCountries ?? []).map((c) => c.countryCode),
|
|
6260
|
+
currency: row.currency,
|
|
6261
|
+
isPrimary: row.isPrimary === true,
|
|
6262
|
+
isActive: row.isActive === true
|
|
6263
|
+
};
|
|
6264
|
+
}
|
|
6265
|
+
var MarketDiscovery = class {
|
|
6266
|
+
constructor(read) {
|
|
6267
|
+
this.read = read;
|
|
6268
|
+
}
|
|
6269
|
+
async list() {
|
|
6270
|
+
const res = await this.read({
|
|
6271
|
+
where: { isActive: { equals: true } },
|
|
6272
|
+
limit: 100
|
|
6273
|
+
});
|
|
6274
|
+
if (res.hasNextPage) {
|
|
6275
|
+
console.warn(
|
|
6276
|
+
"[markets.list] more than 100 active markets; results truncated to 100."
|
|
6277
|
+
);
|
|
6278
|
+
}
|
|
6279
|
+
return res.docs.map(toMarketDTO);
|
|
6280
|
+
}
|
|
6281
|
+
async default() {
|
|
6282
|
+
const res = await this.read({
|
|
6283
|
+
where: { isPrimary: { equals: true }, isActive: { equals: true } },
|
|
6284
|
+
limit: 1
|
|
6285
|
+
});
|
|
6286
|
+
const row = res.docs[0];
|
|
6287
|
+
return row ? toMarketDTO(row) : null;
|
|
6288
|
+
}
|
|
6289
|
+
};
|
|
6290
|
+
|
|
3952
6291
|
// src/core/client/client.ts
|
|
3953
6292
|
var BrowserMembershipApi = class extends CustomerScopedApi {
|
|
3954
6293
|
me() {
|
|
3955
|
-
return this.
|
|
3956
|
-
|
|
3957
|
-
|
|
6294
|
+
return this.requestEndpoint(
|
|
6295
|
+
MEMBERSHIP_ENDPOINT_OPERATIONS.me
|
|
6296
|
+
);
|
|
6297
|
+
}
|
|
6298
|
+
cancel(params) {
|
|
6299
|
+
const { id, immediate } = params;
|
|
6300
|
+
return this.requestEndpoint(
|
|
6301
|
+
MEMBERSHIP_ENDPOINT_OPERATIONS.cancel,
|
|
6302
|
+
immediate !== void 0 ? { immediate } : {},
|
|
6303
|
+
{ pathParams: { id } }
|
|
6304
|
+
);
|
|
3958
6305
|
}
|
|
3959
6306
|
};
|
|
3960
|
-
var Client = class {
|
|
6307
|
+
var Client = class _Client {
|
|
3961
6308
|
constructor(options) {
|
|
3962
6309
|
this.lastRequestId = null;
|
|
3963
6310
|
const publishableKey = options.publishableKey;
|
|
@@ -3989,6 +6336,7 @@ var Client = class {
|
|
|
3989
6336
|
this.commerce = new CommerceClient({
|
|
3990
6337
|
publishableKey: this.config.publishableKey,
|
|
3991
6338
|
apiUrl: this.config.apiUrl,
|
|
6339
|
+
market: this.config.market,
|
|
3992
6340
|
customerToken: () => this.customer.auth.getToken(),
|
|
3993
6341
|
onUnauthorized,
|
|
3994
6342
|
onRequestId,
|
|
@@ -4021,6 +6369,9 @@ var Client = class {
|
|
|
4021
6369
|
onRequestId,
|
|
4022
6370
|
this.config.apiUrl
|
|
4023
6371
|
);
|
|
6372
|
+
this.markets = new MarketDiscovery(
|
|
6373
|
+
(options2) => this.collections.from("markets").find(options2)
|
|
6374
|
+
);
|
|
4024
6375
|
const membershipApi = new BrowserMembershipApi("MembershipApi", {
|
|
4025
6376
|
publishableKey: this.config.publishableKey,
|
|
4026
6377
|
apiUrl: this.config.apiUrl,
|
|
@@ -4029,12 +6380,23 @@ var Client = class {
|
|
|
4029
6380
|
onRequestId
|
|
4030
6381
|
});
|
|
4031
6382
|
this.memberships = {
|
|
4032
|
-
me: membershipApi.me.bind(membershipApi)
|
|
6383
|
+
me: membershipApi.me.bind(membershipApi),
|
|
6384
|
+
cancel: membershipApi.cancel.bind(membershipApi)
|
|
4033
6385
|
};
|
|
4034
6386
|
}
|
|
4035
6387
|
getState() {
|
|
4036
6388
|
return { ...this.state };
|
|
4037
6389
|
}
|
|
6390
|
+
withMarket(market) {
|
|
6391
|
+
return new _Client({
|
|
6392
|
+
...this.config,
|
|
6393
|
+
customer: this.config.customer?.persist === false ? {
|
|
6394
|
+
...this.config.customer,
|
|
6395
|
+
token: this.customer.auth.getToken() ?? void 0
|
|
6396
|
+
} : this.config.customer,
|
|
6397
|
+
market
|
|
6398
|
+
});
|
|
6399
|
+
}
|
|
4038
6400
|
getConfig() {
|
|
4039
6401
|
return { ...this.config };
|
|
4040
6402
|
}
|
|
@@ -4100,6 +6462,7 @@ var COMMERCE_NOTIFICATION_EVENTS = [
|
|
|
4100
6462
|
"returnRequested",
|
|
4101
6463
|
"returnApproved",
|
|
4102
6464
|
"returnRejected",
|
|
6465
|
+
"returnCanceled",
|
|
4103
6466
|
"returnCompleted"
|
|
4104
6467
|
];
|
|
4105
6468
|
function isStringOrNumber(value) {
|
|
@@ -4188,7 +6551,7 @@ function isCommerceNotificationWebhookEvent(event) {
|
|
|
4188
6551
|
if (notification.event === "fulfillmentShipped") {
|
|
4189
6552
|
return sourceCollection === "fulfillments" && matchesOptionalId(data.fulfillmentId, sourceId) && typeof notification.fulfillmentId === "string" && notification.fulfillmentId.length > 0 && matchesOptionalId(notification.fulfillmentId, sourceId) && matchesOptionalId(data.fulfillmentId, notification.fulfillmentId) && matchesOptionalId(changeSourceId, notification.fulfillmentId);
|
|
4190
6553
|
}
|
|
4191
|
-
if (notification.event === "returnRequested" || notification.event === "returnApproved" || notification.event === "returnRejected" || notification.event === "returnCompleted") {
|
|
6554
|
+
if (notification.event === "returnRequested" || notification.event === "returnApproved" || notification.event === "returnRejected" || notification.event === "returnCanceled" || notification.event === "returnCompleted") {
|
|
4192
6555
|
return sourceCollection === "returns" && matchesOptionalId(data.returnId, sourceId) && typeof notification.returnId === "string" && notification.returnId.length > 0 && matchesOptionalId(notification.returnId, sourceId) && matchesOptionalId(data.returnId, notification.returnId) && matchesOptionalId(changeSourceId, notification.returnId);
|
|
4193
6556
|
}
|
|
4194
6557
|
return false;
|
|
@@ -4222,8 +6585,8 @@ function createCommerceEmailWebhookHandler(handlers) {
|
|
|
4222
6585
|
function isWebhookCollection(event, collection) {
|
|
4223
6586
|
return isValidWebhookEvent(event) && event.collection === collection;
|
|
4224
6587
|
}
|
|
4225
|
-
function isWebhookOperation(event,
|
|
4226
|
-
return isValidWebhookEvent(event) && event.operation ===
|
|
6588
|
+
function isWebhookOperation(event, operation2) {
|
|
6589
|
+
return isValidWebhookEvent(event) && event.operation === operation2;
|
|
4227
6590
|
}
|
|
4228
6591
|
var CUSTOMER_PASSWORD_RESET_OPERATION = "password-reset";
|
|
4229
6592
|
function isRecord2(value) {
|
|
@@ -4250,7 +6613,7 @@ function createCustomerAuthWebhookHandler(handlers) {
|
|
|
4250
6613
|
await handlers.unhandled?.(event);
|
|
4251
6614
|
};
|
|
4252
6615
|
}
|
|
4253
|
-
async function verifySignature(payload, secret, signature,
|
|
6616
|
+
async function verifySignature(payload, secret, signature, timestamp2, deliveryId) {
|
|
4254
6617
|
const encoder = new TextEncoder();
|
|
4255
6618
|
const key = await crypto.subtle.importKey(
|
|
4256
6619
|
"raw",
|
|
@@ -4269,12 +6632,12 @@ async function verifySignature(payload, secret, signature, timestamp, deliveryId
|
|
|
4269
6632
|
"HMAC",
|
|
4270
6633
|
key,
|
|
4271
6634
|
sigBytes,
|
|
4272
|
-
encoder.encode(`${
|
|
6635
|
+
encoder.encode(`${timestamp2}.${deliveryId}.${payload}`)
|
|
4273
6636
|
);
|
|
4274
6637
|
}
|
|
4275
|
-
function timestampIsFresh(
|
|
4276
|
-
if (!/^\d+$/.test(
|
|
4277
|
-
const timestampMs = Number(
|
|
6638
|
+
function timestampIsFresh(timestamp2, toleranceSeconds) {
|
|
6639
|
+
if (!/^\d+$/.test(timestamp2)) return false;
|
|
6640
|
+
const timestampMs = Number(timestamp2);
|
|
4278
6641
|
if (!Number.isFinite(timestampMs)) return false;
|
|
4279
6642
|
const skewMs = Math.abs(Date.now() - timestampMs);
|
|
4280
6643
|
return skewMs <= toleranceSeconds * 1e3;
|
|
@@ -4284,14 +6647,14 @@ async function handleWebhook(request, handler, options) {
|
|
|
4284
6647
|
const rawBody = await request.text();
|
|
4285
6648
|
if (options?.secret) {
|
|
4286
6649
|
const signature = request.headers.get("x-webhook-signature") || "";
|
|
4287
|
-
const
|
|
6650
|
+
const timestamp2 = request.headers.get("x-webhook-timestamp") || "";
|
|
4288
6651
|
const deliveryId = request.headers.get("x-webhook-delivery-id") || "";
|
|
4289
6652
|
const toleranceSeconds = options.toleranceSeconds ?? 300;
|
|
4290
|
-
const valid = Boolean(
|
|
6653
|
+
const valid = Boolean(timestamp2 && deliveryId) && timestampIsFresh(timestamp2, toleranceSeconds) && await verifySignature(
|
|
4291
6654
|
rawBody,
|
|
4292
6655
|
options.secret,
|
|
4293
6656
|
signature,
|
|
4294
|
-
|
|
6657
|
+
timestamp2,
|
|
4295
6658
|
deliveryId
|
|
4296
6659
|
);
|
|
4297
6660
|
if (!valid) {
|
|
@@ -4355,12 +6718,21 @@ var INTERNAL_COLLECTIONS = [
|
|
|
4355
6718
|
"analytics-event-schemas",
|
|
4356
6719
|
"subscriptions",
|
|
4357
6720
|
"billing-history",
|
|
6721
|
+
"usage-rate-cards",
|
|
6722
|
+
"usage-invoices",
|
|
4358
6723
|
"inventory-reservations",
|
|
4359
6724
|
"inventory-adjustments",
|
|
6725
|
+
"payment-sessions",
|
|
6726
|
+
"payment-event-inbox",
|
|
6727
|
+
"payment-refund-attempts",
|
|
6728
|
+
"portone-payment-interactions",
|
|
4360
6729
|
"commerce-notification-intents",
|
|
6730
|
+
"commerce-idempotency-records",
|
|
4361
6731
|
"product-collection-items",
|
|
4362
6732
|
"order-status-logs",
|
|
6733
|
+
"fulfillment-events",
|
|
4363
6734
|
"tenant-commerce-config",
|
|
6735
|
+
"customer-oauth-clients",
|
|
4364
6736
|
"api-keys",
|
|
4365
6737
|
"personal-access-tokens",
|
|
4366
6738
|
"tenant-entitlements",
|
|
@@ -4368,12 +6740,18 @@ var INTERNAL_COLLECTIONS = [
|
|
|
4368
6740
|
"direct-upload-sessions",
|
|
4369
6741
|
"webhook-events",
|
|
4370
6742
|
"webhook-deliveries",
|
|
6743
|
+
"webhook-outbox-deliveries",
|
|
4371
6744
|
"audit-logs",
|
|
4372
6745
|
"plans",
|
|
4373
6746
|
"webhooks",
|
|
6747
|
+
"custom-field-definitions",
|
|
4374
6748
|
"event-registrations",
|
|
6749
|
+
"event-admission-holds",
|
|
6750
|
+
"event-admission-types",
|
|
4375
6751
|
"customer-payment-methods",
|
|
4376
|
-
"tenant-payment-credentials"
|
|
6752
|
+
"tenant-payment-credentials",
|
|
6753
|
+
"commerce-payment-accounts",
|
|
6754
|
+
"payment-provider-customer-aliases"
|
|
4377
6755
|
];
|
|
4378
6756
|
var COLLECTIONS = [
|
|
4379
6757
|
"tenants",
|
|
@@ -4432,6 +6810,7 @@ var COLLECTIONS = [
|
|
|
4432
6810
|
"event-occurrences",
|
|
4433
6811
|
"event-tags",
|
|
4434
6812
|
"membership-plans",
|
|
6813
|
+
"membership-plan-prices",
|
|
4435
6814
|
"customer-memberships"
|
|
4436
6815
|
];
|
|
4437
6816
|
var SERVER_ONLY_COLLECTIONS = [
|
|
@@ -4440,9 +6819,14 @@ var SERVER_ONLY_COLLECTIONS = [
|
|
|
4440
6819
|
"images",
|
|
4441
6820
|
"videos",
|
|
4442
6821
|
"orders",
|
|
6822
|
+
"order-tags",
|
|
4443
6823
|
"order-items",
|
|
4444
6824
|
"returns",
|
|
4445
6825
|
"return-items",
|
|
6826
|
+
"refunds",
|
|
6827
|
+
"refund-line-items",
|
|
6828
|
+
"order-edit-sessions",
|
|
6829
|
+
"order-staged-changes",
|
|
4446
6830
|
"fulfillment-orders",
|
|
4447
6831
|
"fulfillment-order-items",
|
|
4448
6832
|
"fulfillments",
|
|
@@ -4455,6 +6839,8 @@ var SERVER_ONLY_COLLECTIONS = [
|
|
|
4455
6839
|
"cart-items",
|
|
4456
6840
|
"checkouts",
|
|
4457
6841
|
"checkout-items",
|
|
6842
|
+
"draft-orders",
|
|
6843
|
+
"draft-order-items",
|
|
4458
6844
|
"posts",
|
|
4459
6845
|
"comments",
|
|
4460
6846
|
"reactions",
|
|
@@ -4850,9 +7236,9 @@ var generateOrderNumber = () => {
|
|
|
4850
7236
|
const year = now.getFullYear().toString().slice(-2);
|
|
4851
7237
|
const month = (now.getMonth() + 1).toString().padStart(2, "0");
|
|
4852
7238
|
const day = now.getDate().toString().padStart(2, "0");
|
|
4853
|
-
const
|
|
4854
|
-
globalThis.crypto.getRandomValues(
|
|
4855
|
-
const random = ((
|
|
7239
|
+
const array2 = new Uint32Array(1);
|
|
7240
|
+
globalThis.crypto.getRandomValues(array2);
|
|
7241
|
+
const random = ((array2[0] ?? 0) % 1e6).toString().padStart(6, "0");
|
|
4856
7242
|
return `${year}${month}${day}${random}`;
|
|
4857
7243
|
};
|
|
4858
7244
|
|
|
@@ -4903,7 +7289,7 @@ function createAnalytics(config) {
|
|
|
4903
7289
|
}, destroy() {
|
|
4904
7290
|
} };
|
|
4905
7291
|
}
|
|
4906
|
-
const
|
|
7292
|
+
const endpoint2 = config.endpoint ?? `${resolveApiUrl()}/api/analytics/collect`;
|
|
4907
7293
|
const respectDnt = config.respectDnt !== false;
|
|
4908
7294
|
function isDntActive() {
|
|
4909
7295
|
if (!respectDnt) return false;
|
|
@@ -4944,10 +7330,10 @@ function createAnalytics(config) {
|
|
|
4944
7330
|
try {
|
|
4945
7331
|
if (typeof navigator.sendBeacon === "function") {
|
|
4946
7332
|
const blob = new Blob([body], { type: "text/plain" });
|
|
4947
|
-
const sent = navigator.sendBeacon(
|
|
7333
|
+
const sent = navigator.sendBeacon(endpoint2, blob);
|
|
4948
7334
|
if (sent) return;
|
|
4949
7335
|
}
|
|
4950
|
-
fetch(
|
|
7336
|
+
fetch(endpoint2, {
|
|
4951
7337
|
method: "POST",
|
|
4952
7338
|
keepalive: true,
|
|
4953
7339
|
headers: { "Content-Type": "application/json" },
|