@sayren/store-sdk 0.32.0 → 0.34.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/dist/index.mjs CHANGED
@@ -170,7 +170,7 @@ const errorDetailSchema = z.object({
170
170
  */
171
171
  docs: z.url().optional().catch(void 0),
172
172
  /**
173
- * 에러 코드별 보조 데이터(선택). 예: 관리 API `LIVE_GATE_NOT_MET`·`LIVE_PAYMENTS_DISABLED`의
173
+ * 에러 코드별 보조 데이터(선택). 예: 관리 API `LIVE_GATE_NOT_MET`의
174
174
  * `{ conditions: LiveGateCondition[] }`. 형태는 에러 코드마다 다르므로 소비측이 코드별 스키마로 다시 파싱한다
175
175
  */
176
176
  details: z.record(z.string(), z.unknown()).optional().catch(void 0)
@@ -357,6 +357,227 @@ const myAccountSchema = z.object({
357
357
  createdAt: z.string()
358
358
  });
359
359
  //#endregion
360
+ //#region src/schemas/currency.ts
361
+ const INT4_MAX = 2147483647;
362
+ /** Stripe 카드 외 결제 상한이 8자리(999,999.99)라 2자리 통화는 이 값이 int4보다 먼저 걸린다 */
363
+ const PG_8_DIGIT_MAX = 99999999;
364
+ /**
365
+ * 1차 판매 통화 16종(설계 Q6). 판매가 단위는 KRW 10원(현행 규칙), JPY 1엔, 2자리 통화 1센트, TWD 100(= 1달러, PayPal이 TWD를 정수로만 받는다).
366
+ * 최소 결제액은 KRW가 현행 100원이고, 그 밖은 Stripe 최소 청구액(https://docs.stripe.com/currencies#minimum-and-maximum-charge-amounts)을 따른다.
367
+ * Stripe 표에 없는 CNY·TWD·PHP는 USD 0.50 근처의 근사값이다(PG 하한은 어댑터 선언이 따로 더한다).
368
+ */
369
+ const CURRENCIES = {
370
+ KRW: {
371
+ code: "KRW",
372
+ digits: 0,
373
+ saleUnit: 10,
374
+ minPayment: 100,
375
+ maxOrderAmount: INT4_MAX
376
+ },
377
+ USD: {
378
+ code: "USD",
379
+ digits: 2,
380
+ saleUnit: 1,
381
+ minPayment: 50,
382
+ maxOrderAmount: PG_8_DIGIT_MAX
383
+ },
384
+ EUR: {
385
+ code: "EUR",
386
+ digits: 2,
387
+ saleUnit: 1,
388
+ minPayment: 50,
389
+ maxOrderAmount: PG_8_DIGIT_MAX
390
+ },
391
+ JPY: {
392
+ code: "JPY",
393
+ digits: 0,
394
+ saleUnit: 1,
395
+ minPayment: 50,
396
+ maxOrderAmount: PG_8_DIGIT_MAX
397
+ },
398
+ GBP: {
399
+ code: "GBP",
400
+ digits: 2,
401
+ saleUnit: 1,
402
+ minPayment: 30,
403
+ maxOrderAmount: PG_8_DIGIT_MAX
404
+ },
405
+ CNY: {
406
+ code: "CNY",
407
+ digits: 2,
408
+ saleUnit: 1,
409
+ minPayment: 400,
410
+ maxOrderAmount: PG_8_DIGIT_MAX
411
+ },
412
+ HKD: {
413
+ code: "HKD",
414
+ digits: 2,
415
+ saleUnit: 1,
416
+ minPayment: 400,
417
+ maxOrderAmount: PG_8_DIGIT_MAX
418
+ },
419
+ TWD: {
420
+ code: "TWD",
421
+ digits: 2,
422
+ saleUnit: 100,
423
+ minPayment: 2e3,
424
+ maxOrderAmount: PG_8_DIGIT_MAX
425
+ },
426
+ SGD: {
427
+ code: "SGD",
428
+ digits: 2,
429
+ saleUnit: 1,
430
+ minPayment: 50,
431
+ maxOrderAmount: PG_8_DIGIT_MAX
432
+ },
433
+ AUD: {
434
+ code: "AUD",
435
+ digits: 2,
436
+ saleUnit: 1,
437
+ minPayment: 50,
438
+ maxOrderAmount: PG_8_DIGIT_MAX
439
+ },
440
+ CAD: {
441
+ code: "CAD",
442
+ digits: 2,
443
+ saleUnit: 1,
444
+ minPayment: 50,
445
+ maxOrderAmount: PG_8_DIGIT_MAX
446
+ },
447
+ THB: {
448
+ code: "THB",
449
+ digits: 2,
450
+ saleUnit: 1,
451
+ minPayment: 1e3,
452
+ maxOrderAmount: PG_8_DIGIT_MAX
453
+ },
454
+ MYR: {
455
+ code: "MYR",
456
+ digits: 2,
457
+ saleUnit: 1,
458
+ minPayment: 200,
459
+ maxOrderAmount: PG_8_DIGIT_MAX
460
+ },
461
+ PHP: {
462
+ code: "PHP",
463
+ digits: 2,
464
+ saleUnit: 1,
465
+ minPayment: 3e3,
466
+ maxOrderAmount: PG_8_DIGIT_MAX
467
+ },
468
+ NZD: {
469
+ code: "NZD",
470
+ digits: 2,
471
+ saleUnit: 1,
472
+ minPayment: 50,
473
+ maxOrderAmount: PG_8_DIGIT_MAX
474
+ },
475
+ CHF: {
476
+ code: "CHF",
477
+ digits: 2,
478
+ saleUnit: 1,
479
+ minPayment: 50,
480
+ maxOrderAmount: PG_8_DIGIT_MAX
481
+ }
482
+ };
483
+ const CURRENCY_CODES = Object.keys(CURRENCIES);
484
+ /** 기본 통화 — 1차는 KRW 고정(설계 Q9). 기본 권역의 통화이고 지금의 금액 컬럼이 이 통화 값이다 */
485
+ const BASE_CURRENCY = "KRW";
486
+ const currencyCodeSchema = z.enum(CURRENCY_CODES).describe("통화(ISO 4217). 금액 필드는 이 통화의 최소 단위 정수다");
487
+ function isCurrencyCode(value) {
488
+ return Object.hasOwn(CURRENCIES, value);
489
+ }
490
+ /** 통화표 항목. 모르는 통화면 RangeError — 판매 통화가 아닌 값이 계산까지 오면 원천의 검증 누락이다 */
491
+ function currencySpecOf(code) {
492
+ if (!isCurrencyCode(code)) throw new RangeError(`unsupported currency: ${code}`);
493
+ return CURRENCIES[code];
494
+ }
495
+ function scaleOf(spec) {
496
+ return 10 ** spec.digits;
497
+ }
498
+ /** 주 단위 → 최소 단위(반올림). 입력·화면 값 변환용이고 PG 응답 해석은 `fromDecimalString`이다 */
499
+ function toMinor(major, currency) {
500
+ return Math.round(major * scaleOf(currencySpecOf(currency)));
501
+ }
502
+ /** 최소 단위 → 주 단위(표시용 숫자) */
503
+ function minorToMajor(minor, currency) {
504
+ return minor / scaleOf(currencySpecOf(currency));
505
+ }
506
+ /** 최소 단위 → PG 요청 형식 십진 문자열(`1099` USD → `"10.99"`, `1000` KRW → `"1000"`). 정수 연산만 쓴다 */
507
+ function toDecimalString(minor, currency) {
508
+ if (!Number.isSafeInteger(minor)) throw new RangeError(`amount must be an integer: ${minor}`);
509
+ const { digits } = currencySpecOf(currency);
510
+ const sign = minor < 0 ? "-" : "";
511
+ const abs = String(Math.abs(minor));
512
+ if (digits === 0) return `${sign}${abs}`;
513
+ const padded = abs.padStart(digits + 1, "0");
514
+ return `${sign}${padded.slice(0, -digits)}.${padded.slice(-digits)}`;
515
+ }
516
+ /**
517
+ * PG 응답의 십진 문자열 → 최소 단위 정수. 통화 자릿수보다 긴 소수는 끝이 0일 때만 받는다(`"10.990"` → 1099, `"10.999"`는 RangeError).
518
+ * 형식이 틀리면 RangeError다 — 금액을 추정하지 않는다.
519
+ */
520
+ function fromDecimalString(value, currency) {
521
+ const { digits } = currencySpecOf(currency);
522
+ const match = /^(-?)(\d+)(?:\.(\d+))?$/.exec(value.trim());
523
+ if (!match) throw new RangeError(`invalid decimal amount: ${value}`);
524
+ const [, sign, whole, fraction = ""] = match;
525
+ const extra = fraction.slice(digits);
526
+ if (/[^0]/.test(extra)) throw new RangeError(`too many fraction digits for ${currency}: ${value}`);
527
+ const minor = Number(`${whole}${fraction.slice(0, digits).padEnd(digits, "0")}`);
528
+ if (!Number.isSafeInteger(minor)) throw new RangeError(`amount out of range: ${value}`);
529
+ return sign === "-" && minor !== 0 ? -minor : minor;
530
+ }
531
+ /** 판매가 단위로 내림 — 할인·정률 쿠폰 계산의 단위 맞춤(KRW 10원 내림은 현행 규칙 그대로) */
532
+ function floorToSaleUnit(amount, currency) {
533
+ const { saleUnit } = currencySpecOf(currency);
534
+ return Math.floor(amount / saleUnit) * saleUnit;
535
+ }
536
+ /** 판매가 규칙(판매가 단위의 배수, 최소 판매가 단위)을 지키는가 */
537
+ function isSaleUnitPrice(amount, currency) {
538
+ const { saleUnit } = currencySpecOf(currency);
539
+ return Number.isInteger(amount) && amount >= saleUnit && amount % saleUnit === 0;
540
+ }
541
+ /** 판매가 규칙 위반 — api가 400 `INVALID_PRICE_UNIT`으로 바꾼다 */
542
+ var InvalidPriceUnitError = class extends Error {
543
+ amount;
544
+ currency;
545
+ saleUnit;
546
+ code = "INVALID_PRICE_UNIT";
547
+ constructor(amount, currency, saleUnit) {
548
+ super(`sale price ${amount} ${currency} must be a multiple of ${saleUnit} and at least ${saleUnit}`);
549
+ this.amount = amount;
550
+ this.currency = currency;
551
+ this.saleUnit = saleUnit;
552
+ this.name = "InvalidPriceUnitError";
553
+ }
554
+ };
555
+ /** 판매가 단위 검증의 원천 — zod `superRefine`과 api 상품 쓰기가 같이 부른다 */
556
+ function assertSaleUnit(amount, currency) {
557
+ if (!isSaleUnitPrice(amount, currency)) throw new InvalidPriceUnitError(amount, currency, currencySpecOf(currency).saleUnit);
558
+ }
559
+ /**
560
+ * 최소 결제액 = max(통화표 값, 후보들). 후보는 PG 어댑터 선언의 하한(`descriptor.minAmount(currency)`, #131)이고 null은 「하한 없음」이다.
561
+ * 서버의 최소 결제 검사는 이 값 하나를 쓴다.
562
+ */
563
+ function minPaymentOf(currency, candidates = []) {
564
+ let floor = currencySpecOf(currency).minPayment;
565
+ for (const candidate of candidates) if (candidate !== null && candidate !== void 0 && candidate > floor) floor = candidate;
566
+ return floor;
567
+ }
568
+ /** 통화의 규칙 값. `minPayment`를 주면(서버가 `minPaymentOf`로 구한 값) 통화표 값 대신 쓴다 */
569
+ function moneyRulesOf(currency, options = {}) {
570
+ const spec = currencySpecOf(currency);
571
+ return {
572
+ currency: spec.code,
573
+ saleUnit: spec.saleUnit,
574
+ minPayment: options.minPayment ?? spec.minPayment,
575
+ maxOrderAmount: spec.maxOrderAmount
576
+ };
577
+ }
578
+ /** 기본 통화(KRW) 규칙 — 규칙 값을 넘기지 않는 옛 호출부의 기본값 */
579
+ const KRW_MONEY_RULES = moneyRulesOf("KRW");
580
+ //#endregion
360
581
  //#region src/schemas/refund-policy.ts
361
582
  /**
362
583
  * 환불 정책 (이슈 #25) — 취소·반품·교환에서 **배송비를 누가 부담하는지**를 정한다.
@@ -374,8 +595,15 @@ const descriptions$3 = {
374
595
  exchangeDeliveryFee: "단순 변심(구매자 귀책) 교환의 교환 배송비. 원 단위. 구매자에게 청구할 금액을 안내값으로 싣는다. 기본 0(무료). 배송 상품에만 있다",
375
596
  sellerFaultFreeShipping: "판매자 귀책(셀러 직권취소, 불량·오배송 반품)이면 배송비를 셀러가 부담한다 — 배송비를 환불하고 반품비를 받지 않는다. false면 구매자 귀책과 같은 규칙을 쓴다. 기본 true",
376
597
  conditionalFreeShortfallCharge: "조건부 무료배송(`CONDITIONAL_FREE`) 상품에서 일부 취소로 남은 금액이 무료 기준액에 미달하면 그 배송비를 환불액에서 뺀다. false면 추가 청구 없이 셀러가 부담한다. 기본 false",
377
- couponShortfallCharge: "쿠폰 조건 미달 차감. 일부 취소·반품으로 남은 주문상품이 쿠폰 조건(최소 주문 금액 등)을 잃으면 남은 주문상품이 받던 쿠폰 할인을 환불액에서 뺀다. 판매자 귀책(셀러 직권취소, 불량·오배송 반품)은 빼지 않는다. false면 차감 없이 실결제 금액만 나눠 환불한다. 기본 true"
598
+ couponShortfallCharge: "쿠폰 조건 미달 차감. 일부 취소·반품으로 남은 주문상품이 쿠폰 조건(최소 주문 금액 등)을 잃으면 남은 주문상품이 받던 쿠폰 할인을 환불액에서 뺀다. 판매자 귀책(셀러 직권취소, 불량·오배송 반품)은 빼지 않는다. false면 차감 없이 실결제 금액만 나눠 환불한다. 기본 true",
599
+ currencies: "외화별 반품 배송비·교환 배송비(이슈 #130). 키는 판매 통화 코드이고 기본 통화(KRW)는 넣지 않는다. 금액은 그 통화의 최소 단위다. 상품이 정한 통화 값이 상점 값보다 앞선다. 정하지 않은 외화로는 배송 상품을 팔지 않는다. 주면 맵 전체를 바꾼다"
378
600
  };
601
+ /** 외화 한 통화의 반품·교환 배송비 */
602
+ const currencyRefundFeesSchema = z.strictObject({
603
+ returnDeliveryFee: z.number().int().min(0).describe("이 통화의 반품 배송비. 통화의 최소 단위"),
604
+ exchangeDeliveryFee: z.number().int().min(0).describe("이 통화의 교환 배송비. 통화의 최소 단위")
605
+ });
606
+ const currencyRefundMapSchema = z.partialRecord(currencyCodeSchema, currencyRefundFeesSchema).refine((map) => !("KRW" in map), { message: "기본 통화는 currencies에 넣지 않습니다" }).describe(descriptions$3.currencies);
379
607
  /** 유효 환불 정책 — 상점 기본 + 상품별 덮어쓰기를 합친 결과 */
380
608
  const refundPolicySchema = z.object({
381
609
  preShipmentDeliveryFeeRefund: z.boolean().describe(descriptions$3.preShipmentDeliveryFeeRefund),
@@ -383,7 +611,8 @@ const refundPolicySchema = z.object({
383
611
  exchangeDeliveryFee: z.number().int().min(0).describe(descriptions$3.exchangeDeliveryFee),
384
612
  sellerFaultFreeShipping: z.boolean().describe(descriptions$3.sellerFaultFreeShipping),
385
613
  conditionalFreeShortfallCharge: z.boolean().describe(descriptions$3.conditionalFreeShortfallCharge),
386
- couponShortfallCharge: z.boolean().optional().default(true).describe(`${descriptions$3.couponShortfallCharge}. 이 필드가 없는 이전 서버 응답은 true로 읽는다`)
614
+ couponShortfallCharge: z.boolean().optional().default(true).describe(`${descriptions$3.couponShortfallCharge}. 이 필드가 없는 이전 서버 응답은 true로 읽는다`),
615
+ currencies: currencyRefundMapSchema.optional()
387
616
  });
388
617
  /**
389
618
  * 상점이 정하지 않았을 때 서버가 쓰는 값.
@@ -411,24 +640,39 @@ const refundPolicyPatchSchema = z.strictObject({
411
640
  exchangeDeliveryFee: z.number().int().min(0).optional().describe(descriptions$3.exchangeDeliveryFee),
412
641
  sellerFaultFreeShipping: z.boolean().optional().describe(descriptions$3.sellerFaultFreeShipping),
413
642
  conditionalFreeShortfallCharge: z.boolean().optional().describe(descriptions$3.conditionalFreeShortfallCharge),
414
- couponShortfallCharge: z.boolean().optional().describe(descriptions$3.couponShortfallCharge)
643
+ couponShortfallCharge: z.boolean().optional().describe(descriptions$3.couponShortfallCharge),
644
+ currencies: currencyRefundMapSchema.optional()
415
645
  });
416
646
  /**
417
647
  * 상품별 덮어쓰기 — 쿠폰 조건 미달 차감(`couponShortfallCharge`)은 주문 단위 규칙이라 상품이 정하지 않는다.
418
648
  * 상점 정책만 읽는다(이슈 #47).
419
649
  */
420
650
  const productRefundPolicyPatchSchema = refundPolicyPatchSchema.omit({ couponShortfallCharge: true });
421
- /**
422
- * 유효 정책 해석 — 상품별 덮어쓰기 → 상점 기본 → `REFUND_POLICY_DEFAULTS` 순이다.
423
- *
424
- * 반품·교환 배송비의 원천은 정책 하나다(이슈 #57 결정 3). 상품의 레거시 반품비·교환비 필드와의 연결은 없앴고,
425
- * 레거시 값은 마이그레이션이 상품별 정책으로 옮겼다.
426
- */
427
- function resolveRefundPolicy(storePolicy, product) {
428
- return {
651
+ function resolveRefundPolicy(storePolicy, product, currency = "KRW") {
652
+ const store = {
429
653
  ...REFUND_POLICY_DEFAULTS,
430
- ...dropUndefined(storePolicy),
431
- ...productRefundPolicyOverride(product) ?? {}
654
+ ...dropUndefined(storePolicy)
655
+ };
656
+ const override = productRefundPolicyOverride(product) ?? {};
657
+ const merged = {
658
+ ...store,
659
+ ...override
660
+ };
661
+ if (currency === "KRW") {
662
+ if (store.currencies || override.currencies) merged.currencies = {
663
+ ...store.currencies,
664
+ ...override.currencies
665
+ };
666
+ return merged;
667
+ }
668
+ const code = currency;
669
+ const fees = override.currencies?.[code] ?? store.currencies?.[code];
670
+ if (!fees) return null;
671
+ const { currencies: _byCurrency, ...rest } = merged;
672
+ return {
673
+ ...rest,
674
+ returnDeliveryFee: fees.returnDeliveryFee,
675
+ exchangeDeliveryFee: fees.exchangeDeliveryFee
432
676
  };
433
677
  }
434
678
  /**
@@ -470,6 +714,75 @@ function proratedRefundBase(totalPrice, quantity, settledQuantity, cancelQuantit
470
714
  return Math.max(0, after - before);
471
715
  }
472
716
  //#endregion
717
+ //#region src/schemas/currency-prices.ts
718
+ /**
719
+ * 통화별 가격 입력·응답 (이슈 #130 설계 D3·D6·§8.1) — **외화만 담는다.** 기본 통화(KRW) 값은 지금의 평면 필드(`salePrice`·`deliveryFee` 등)다.
720
+ * 금액은 그 통화의 최소 단위 정수다. 목록에 없는 외화로는 그 상품을 팔지 않는다. 쓰기(PUT·POST)는 목록 전체 교체이고 생략하면 유지한다.
721
+ * 통화는 상점의 판매 통화여야 한다(400 `CURRENCY_NOT_SOLD`).
722
+ */
723
+ /** 외화만·통화마다 한 번 — 기본 통화 원소와 같은 통화 두 번은 400이다 */
724
+ function foreignOnce(items, ctx) {
725
+ const seen = /* @__PURE__ */ new Set();
726
+ items.forEach((item, index) => {
727
+ if (item.currency === "KRW") ctx.addIssue({
728
+ code: "custom",
729
+ path: [index, "currency"],
730
+ message: "기본 통화는 prices에 넣지 않습니다"
731
+ });
732
+ if (seen.has(item.currency)) ctx.addIssue({
733
+ code: "custom",
734
+ path: [index, "currency"],
735
+ message: "통화가 겹칩니다"
736
+ });
737
+ seen.add(item.currency);
738
+ });
739
+ }
740
+ /** 상품 판매가의 외화 값 */
741
+ const productCurrencyPriceSchema = z.strictObject({
742
+ currency: currencyCodeSchema,
743
+ salePrice: z.number().int().describe("이 통화의 판매가. 통화의 최소 단위이고 판매가 단위(KRW 10, JPY 1, USD 1센트, TWD 100)의 배수다"),
744
+ originalPrice: z.number().int().min(0).nullable().optional().describe("이 통화의 정가(표시용). 생략은 null"),
745
+ discountAmount: z.number().int().min(0).nullable().optional().describe("정액 즉시할인의 이 통화 값. 정률 할인은 모든 통화에 그대로 적용된다. null이면 이 통화에는 정액 할인이 없다")
746
+ }).superRefine((value, ctx) => {
747
+ if (!isSaleUnitPrice(value.salePrice, value.currency)) ctx.addIssue({
748
+ code: "custom",
749
+ path: ["salePrice"],
750
+ message: "판매가가 이 통화의 판매가 단위가 아닙니다 (INVALID_PRICE_UNIT)"
751
+ });
752
+ });
753
+ const productCurrencyPricesSchema = z.array(productCurrencyPriceSchema).max(15).superRefine(foreignOnce).describe("외화 판매가(이슈 #130). 기본 통화는 넣지 않는다. 주면 판매 중인 외화 안에서 목록 전체를 바꾸고(판매하지 않는 통화의 저장 값은 유지한다) 생략하면 유지한다. 목록에 없는 외화로는 팔지 않는다");
754
+ /** 상품 배송의 외화 값 — 배송비 유형·출고지는 상품 하나다 */
755
+ const shippingCurrencyPriceSchema = z.strictObject({
756
+ currency: currencyCodeSchema,
757
+ deliveryFee: z.number().int().min(0).optional().describe("이 통화의 배송비. 생략하면 그 통화의 상점 기본 배송비이고, 상점 값도 없으면 이 통화로 배송 상품을 팔지 않는다. FREE면 0"),
758
+ conditionalFreeAmount: z.number().int().min(1).nullable().optional().describe("이 통화의 조건부 무료 기준 묶음 소계. CONDITIONAL_FREE가 아니면 무시한다")
759
+ });
760
+ const shippingCurrencyPricesSchema = z.array(shippingCurrencyPriceSchema).max(15).superRefine(foreignOnce).describe("외화 배송비(이슈 #130). 기본 통화는 넣지 않는다. 주면 판매 중인 외화 안에서 목록 전체를 바꾸고(판매하지 않는 통화의 저장 값은 유지한다) 생략하면 유지한다");
761
+ /** 저장된 외화 배송 값(응답) */
762
+ const storedShippingCurrencyPriceSchema = z.object({
763
+ currency: z.string(),
764
+ deliveryFee: z.number().int(),
765
+ conditionalFreeAmount: z.number().int().nullable()
766
+ });
767
+ /** 저장된 외화 판매가(응답) */
768
+ const storedProductCurrencyPriceSchema = z.object({
769
+ currency: z.string(),
770
+ salePrice: z.number().int(),
771
+ originalPrice: z.number().int().nullable(),
772
+ discountAmount: z.number().int().nullable()
773
+ });
774
+ /** 조합·추가 선택 값 추가금의 외화 값 — 추가금은 판매가 단위 규칙이 없다(설계 D4) */
775
+ const additionalCurrencyPriceSchema = z.strictObject({
776
+ currency: currencyCodeSchema,
777
+ additionalPrice: z.number().int().min(0).describe("이 통화의 추가금. 통화의 최소 단위(0 이상)")
778
+ });
779
+ const additionalCurrencyPricesSchema = z.array(additionalCurrencyPriceSchema).max(15).superRefine(foreignOnce).describe("외화 추가금(이슈 #130). 기본 통화는 넣지 않는다. 주면 판매 중인 외화 안에서 목록 전체를 바꾸고(판매하지 않는 통화의 저장 값은 유지한다) 생략하면 유지한다. 기본 통화 추가금이 0이 아닌데 목록에 없는 외화로는 이 조합·값을 팔지 않는다");
780
+ /** 저장된 외화 추가금(응답) */
781
+ const storedAdditionalCurrencyPriceSchema = z.object({
782
+ currency: z.string(),
783
+ additionalPrice: z.number().int()
784
+ });
785
+ //#endregion
473
786
  //#region src/schemas/fulfillment.ts
474
787
  /**
475
788
  * 상품 유형 (이슈 #48·#57) — 배송이 필요한 상품과 필요 없는 상품을 가르는 축이다.
@@ -643,7 +956,8 @@ const shippingCreateSchema = z.strictObject({
643
956
  deliveryFee: z.number().int().min(0).optional().describe("배송비. 원 단위. 생략하면 상점 기본 배송비(`GET /v1/store`의 `shippingPolicy.baseDeliveryFee`)를 저장한다. FREE면 0이거나 생략한다"),
644
957
  conditionalFreeAmount: z.number().int().min(0).nullable().optional().describe("무료 배송이 되는 묶음 소계. 원 단위. CONDITIONAL_FREE에서만 받고 필수다"),
645
958
  shippingAddressId: z.string().nullable().optional().describe(ADDRESS_ID_DESCRIPTIONS.shipping),
646
- returnAddressId: z.string().nullable().optional().describe(ADDRESS_ID_DESCRIPTIONS.return)
959
+ returnAddressId: z.string().nullable().optional().describe(ADDRESS_ID_DESCRIPTIONS.return),
960
+ prices: shippingCurrencyPricesSchema.optional()
647
961
  }).superRefine(refineShippingConsistency);
648
962
  /**
649
963
  * 상품 이행 — 등록(POST). 배송 상품의 `shipping`을 생략하면 기본값(유료 배송·상점 기본 배송비·기본 출고지·반품지)이다.
@@ -661,7 +975,8 @@ const shippingUpdateSchema = z.strictObject({
661
975
  deliveryFee: z.number().int().min(0).describe("배송비. 원 단위. FREE면 0"),
662
976
  conditionalFreeAmount: z.number().int().min(0).nullable().describe("무료 배송이 되는 묶음 소계. CONDITIONAL_FREE면 필수, 아니면 null"),
663
977
  shippingAddressId: z.string().nullable().describe(ADDRESS_ID_DESCRIPTIONS.shipping),
664
- returnAddressId: z.string().nullable().describe(ADDRESS_ID_DESCRIPTIONS.return)
978
+ returnAddressId: z.string().nullable().describe(ADDRESS_ID_DESCRIPTIONS.return),
979
+ prices: shippingCurrencyPricesSchema.optional()
665
980
  }).superRefine(refineShippingConsistency);
666
981
  /**
667
982
  * 상품 이행 — 수정(PUT·PATCH). 통째 교체이고 유형 키와 그 안의 필드가 **모두 필수**다. 서버는 현재 값과 병합하지 않는다.
@@ -686,7 +1001,8 @@ const productFulfillmentSchema = z.discriminatedUnion("type", [z.object({
686
1001
  deliveryFee: z.number().int().describe("배송비. 원 단위. FREE면 0"),
687
1002
  conditionalFreeAmount: z.number().int().nullable().describe("조건부 무료 기준 묶음 소계. CONDITIONAL_FREE가 아니면 null"),
688
1003
  shippingAddressId: z.string().nullable().describe("출고지 주소 id. null이면 상점 기본 출고지를 따른다"),
689
- returnAddressId: z.string().nullable().describe("반품지 주소 id. null이면 상점 기본 반품지를 따른다")
1004
+ returnAddressId: z.string().nullable().describe("반품지 주소 id. null이면 상점 기본 반품지를 따른다"),
1005
+ prices: z.array(storedShippingCurrencyPriceSchema).optional().describe("외화 배송비(이슈 #130). 관리 API 상품 조회만 싣는다")
690
1006
  }),
691
1007
  methods: storedMethodsSchema
692
1008
  }), z.object({
@@ -784,14 +1100,22 @@ const descriptions$2 = {
784
1100
  baseDeliveryFee: "상점 기본 배송비. 원 단위. 상품 등록·수정에서 `deliveryFee`를 생략하면 이 값을 쓴다. 기본 3000",
785
1101
  freeThreshold: "상점 전체 무료배송 기준액. 주문 상품 금액 합이 이 값 이상이면 모든 묶음의 배송비가 0이다. null이면 전체 무료배송을 쓰지 않는다(상품별 조건부 무료는 그대로 동작한다). 기본 null",
786
1102
  jejuSurcharge: "제주 지역 추가 배송비. 원 단위. **배송 묶음마다** 더한다. 기본 0",
787
- isolatedSurcharge: "도서산간 지역 추가 배송비. 원 단위. **배송 묶음마다** 더한다. 기본 0"
1103
+ isolatedSurcharge: "도서산간 지역 추가 배송비. 원 단위. **배송 묶음마다** 더한다. 기본 0",
1104
+ currencies: "외화별 기본 배송비·전체 무료배송 기준액(이슈 #130). 키는 판매 통화 코드이고 기본 통화(KRW)는 넣지 않는다. 금액은 그 통화의 최소 단위다. 정하지 않은 외화로는 배송 상품을 팔지 않는다. 지역 추가 배송비는 국내(기본 통화) 값만 있다. 주면 맵 전체를 바꾼다"
788
1105
  };
1106
+ /** 외화 한 통화의 상점 배송 값 */
1107
+ const currencyShippingPolicySchema = z.strictObject({
1108
+ baseDeliveryFee: z.number().int().min(0).describe("이 통화의 기본 배송비. 통화의 최소 단위"),
1109
+ freeThreshold: z.number().int().min(1).nullable().describe("이 통화의 전체 무료배송 기준액. null이면 쓰지 않는다")
1110
+ });
1111
+ const currencyShippingMapSchema = z.partialRecord(currencyCodeSchema, currencyShippingPolicySchema).refine((map) => !("KRW" in map), { message: "기본 통화는 currencies에 넣지 않습니다" }).describe(descriptions$2.currencies);
789
1112
  /** 유효 배송비 정책 — 상점이 정하지 않은 항목은 `SHIPPING_POLICY_DEFAULTS`로 채운 값이다 */
790
1113
  const shippingPolicySchema = z.object({
791
1114
  baseDeliveryFee: z.number().int().min(0).describe(descriptions$2.baseDeliveryFee),
792
1115
  freeThreshold: z.number().int().min(1).nullable().describe(descriptions$2.freeThreshold),
793
1116
  jejuSurcharge: z.number().int().min(0).describe(descriptions$2.jejuSurcharge),
794
- isolatedSurcharge: z.number().int().min(0).describe(descriptions$2.isolatedSurcharge)
1117
+ isolatedSurcharge: z.number().int().min(0).describe(descriptions$2.isolatedSurcharge),
1118
+ currencies: currencyShippingMapSchema.optional()
795
1119
  });
796
1120
  /**
797
1121
  * 상점이 정하지 않았을 때 서버가 쓰는 값.
@@ -815,16 +1139,24 @@ const shippingPolicyPatchSchema = z.strictObject({
815
1139
  baseDeliveryFee: z.number().int().min(0).optional().describe(descriptions$2.baseDeliveryFee),
816
1140
  freeThreshold: z.number().int().min(1).nullable().optional().describe(descriptions$2.freeThreshold),
817
1141
  jejuSurcharge: z.number().int().min(0).optional().describe(descriptions$2.jejuSurcharge),
818
- isolatedSurcharge: z.number().int().min(0).optional().describe(descriptions$2.isolatedSurcharge)
1142
+ isolatedSurcharge: z.number().int().min(0).optional().describe(descriptions$2.isolatedSurcharge),
1143
+ currencies: currencyShippingMapSchema.optional()
819
1144
  });
820
- /** 유효 정책 해석 — 상점이 정한 항목 + `SHIPPING_POLICY_DEFAULTS` */
821
- function resolveShippingPolicy(patch) {
822
- if (!patch) return { ...SHIPPING_POLICY_DEFAULTS };
823
- const given = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== void 0));
824
- return {
1145
+ function resolveShippingPolicy(patch, currency = "KRW") {
1146
+ const given = patch ? Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== void 0)) : {};
1147
+ const base = {
825
1148
  ...SHIPPING_POLICY_DEFAULTS,
826
1149
  ...given
827
1150
  };
1151
+ if (currency === "KRW") return base;
1152
+ const foreign = base.currencies?.[currency];
1153
+ if (!foreign) return null;
1154
+ return {
1155
+ baseDeliveryFee: foreign.baseDeliveryFee,
1156
+ freeThreshold: foreign.freeThreshold,
1157
+ jejuSurcharge: 0,
1158
+ isolatedSurcharge: 0
1159
+ };
828
1160
  }
829
1161
  /** 지역 구분 — 우편번호로 판정한다 */
830
1162
  const remoteAreaSchema = z.enum([
@@ -1481,7 +1813,6 @@ const sellerAddressRequestSchema = z.object({
1481
1813
  * 공개 전환·슬러그 변경·호스팅 끄기는 승인(`APPROVAL_REQUIRED`)이다 — 구매자가 보는 화면을 바꾸는 쓰기다.
1482
1814
  *
1483
1815
  * 오류 코드:
1484
- * - 403 `STOREFRONT_HOSTING_DISABLED` — 플랫폼 스위치가 꺼져 새 사이트를 만들 수 없다
1485
1816
  * - 404 `STOREFRONT_SITE_NOT_FOUND` · `STOREFRONT_TEMPLATE_NOT_FOUND` · `STOREFRONT_VERSION_NOT_FOUND`
1486
1817
  * - 409 `STOREFRONT_SITE_EXISTS` — 이미 사이트가 있다(상점당 1개)
1487
1818
  * - 409 `STOREFRONT_SLUG_TAKEN` — 다른 사이트가 쓰거나 보류 중인 슬러그다
@@ -1498,7 +1829,7 @@ const sellerAddressRequestSchema = z.object({
1498
1829
  * - 503 `STOREFRONT_PREVIEW_NOT_CONFIGURED` — 미리보기 서명 키가 설정되지 않았다
1499
1830
  *
1500
1831
  * 편집(M2b, `/v1/storefront/site/editing`·`files/**`·`checks/**`·`verify`·`builds/**`, 버전 만들기):
1501
- * - 403 `STOREFRONT_EDITING_DISABLED` — 플랫폼 편집 스위치가 꺼져 있다
1832
+ * - 403 `STOREFRONT_EDITING_DISABLED` — 편집을 쓸 수 없어 셀러 템플릿으로 사이트를 만들 수 없다(사이트 만들기)
1502
1833
  * - 503 `STOREFRONT_EDITING_NOT_CONFIGURED` — 편집 Sandbox가 설정되지 않았다
1503
1834
  * - 409 `EDIT_CAPACITY_FULL` — 플랫폼 전체 동시 편집 상한에 걸렸다. `error.details.retryAfterSeconds` 뒤에 다시 한다
1504
1835
  * - 409 `EDIT_SESSION_REQUIRED` — 편집 미리보기 링크: 편집 환경이 없다
@@ -1728,11 +2059,11 @@ const storefrontSiteSchema = z.object({
1728
2059
  createdAt: z.string(),
1729
2060
  updatedAt: z.string()
1730
2061
  });
1731
- /** `GET /v1/storefront/site` — 스위치 상태와 현재 사이트(없으면 null. 끈 사이트는 싣지 않는다) */
2062
+ /** `GET /v1/storefront/site` — 호스팅 설정과 현재 사이트(없으면 null. 끈 사이트는 싣지 않는다) */
1732
2063
  const storefrontHostingSchema = z.object({
1733
- enabled: z.boolean().describe("새 사이트를 만들 수 있는가 (플랫폼 스위치)"),
2064
+ enabled: z.boolean().describe("새 사이트를 만들 수 있는가 (항상 true)"),
1734
2065
  domain: z.string().describe("호스팅 도메인 (예: `sayren.co`). 사이트 주소는 `{slug}.{domain}`"),
1735
- editingEnabled: z.boolean().describe("파일 편집·버전 만들기를 쓸 수 있는가 (플랫폼 편집 스위치와 Sandbox 설정)"),
2066
+ editingEnabled: z.boolean().describe("파일 편집·버전 만들기를 쓸 수 있는가 (Sandbox 설정)"),
1736
2067
  site: storefrontSiteSchema.nullable()
1737
2068
  });
1738
2069
  const storefrontSlugAvailabilitySchema = z.object({
@@ -2008,7 +2339,7 @@ const storefrontSiteDomainSchema = z.object({
2008
2339
  });
2009
2340
  /** `GET /v1/storefront/site/domains` — 사이트의 주소 목록(기본 주소 + 내 도메인)과 연결 설정 */
2010
2341
  const storefrontSiteDomainsSchema = z.object({
2011
- enabled: z.boolean().describe("내 도메인을 추가할 수 있는가 (플랫폼 스위치)"),
2342
+ enabled: z.boolean().describe("내 도메인을 추가할 수 있는가 (항상 true)"),
2012
2343
  limit: z.number().int().min(0).describe("상점당 내 도메인 수 상한 (해제한 도메인은 세지 않는다)"),
2013
2344
  target: z.string().describe("CNAME 대상 (예: `sites.sayren.co`)"),
2014
2345
  domains: z.array(storefrontSiteDomainSchema).describe("대표 주소 먼저, 그다음 추가한 순서")
@@ -2117,7 +2448,7 @@ const storefrontDevLogsSchema = z.object({
2117
2448
  at: z.string()
2118
2449
  });
2119
2450
  const storefrontEditingSchema = z.object({
2120
- enabled: z.boolean().describe("편집을 쓸 수 있는가 (플랫폼 스위치와 Sandbox 설정)"),
2451
+ enabled: z.boolean().describe("편집을 쓸 수 있는가 (Sandbox 설정)"),
2121
2452
  session: storefrontEditSessionSchema.nullable().describe("열린 편집 환경. 잠들었거나 닫았으면 null"),
2122
2453
  capacity: z.object({
2123
2454
  limit: z.number().int().describe("플랫폼 전체 동시 편집 환경 상한"),
@@ -3100,7 +3431,12 @@ const analyticsOverviewSchema = z.object({
3100
3431
  summary: analyticsTotalsSchema.describe("기간 합계"),
3101
3432
  funnel: z.array(analyticsFunnelStepSchema).describe("세션 기준 구매 퍼널. 각 단계는 그 행동을 한 세션 수이고, 앞 단계를 거쳤는지는 따지지 않는다"),
3102
3433
  rows: z.array(analyticsTotalsSchema.extend({ date: z.string().describe("일자 (YYYY-MM-DD)") })).describe("날짜별 값. 세션이 없는 날은 생략된다"),
3103
- excludedBotSessions: z.number().int().describe("집계에서 뺀 봇 세션 수 — 봇 표시 이벤트가 하나라도 있는 세션은 모든 값에서 빠진다")
3434
+ excludedBotSessions: z.number().int().describe("집계에서 뺀 봇 세션 수 — 봇 표시 이벤트가 하나라도 있는 세션은 모든 값에서 빠진다"),
3435
+ byCurrency: z.array(z.object({
3436
+ currency: z.string().describe("구매 통화(ISO 4217)"),
3437
+ purchases: z.number().int().describe("실결제 구매 수(테스트 결제 제외)"),
3438
+ revenue: z.number().int().describe("매출(그 통화의 최소 단위). `includeTest`면 테스트 결제 매출을 더한다")
3439
+ })).optional().default([]).describe("통화별 매출(이슈 #130) — 기간 합계, 기본 통화(KRW) 포함. 통화 사이는 환산하지 않는다. `summary.revenue`는 기본 통화 매출이다. 옛 서버 응답은 빈 목록")
3104
3440
  });
3105
3441
  const analyticsProductSortSchema = z.enum([
3106
3442
  "VIEWS",
@@ -3861,11 +4197,11 @@ const POINT_ENTRY_TYPES = [
3861
4197
  const pointPolicyNoticeSchema = z.enum(["REVIEW_REWARD_PAUSED", "POINTS_AVAILABLE"]).nullable().describe("상점에 보일 안내. `REVIEW_REWARD_PAUSED`: 지난 90일에 리뷰 적립이 있었는데 적립금 기본값이 끔으로 바뀌어 리뷰 자동 적립(500원 + 사진 500원)이 멈췄다. `POINTS_AVAILABLE`: 적립금 설정을 열었으니 다시 켤 수 있다. 안내할 것이 없으면 null");
3862
4198
  /** `GET /v1/store/point-policy` 응답 */
3863
4199
  const storePointPolicySchema = z.object({
3864
- available: z.boolean().describe("적립금 설정을 바꿀 수 있는가. false면 준비 중이라 정책 저장이 409 `POINTS_UNAVAILABLE`이고 모든 적립이 멈춰 있다"),
4200
+ available: z.boolean().describe("적립금 설정을 바꿀 수 있는가. 지금은 늘 true다(이전 응답 호환 필드)"),
3865
4201
  configured: z.boolean().describe("셀러가 정책을 저장한 적이 있는가. false면 기본(모두 끔)이다"),
3866
4202
  reviewReward: reviewRewardPolicySchema.describe("리뷰 적립. 정하지 않았으면 끔·0원"),
3867
4203
  purchaseEarn: purchaseEarnPolicySchema.describe("구매 적립. 구매확정 때 주문상품 실결제 금액(배송비 제외) × 적립률을 준다. 정하지 않았으면 끔·0"),
3868
- useAvailable: z.boolean().optional().default(false).describe("적립금 사용(결제에 쓰기)을 켤 수 있는가 (#93). false면 준비 중이라 `use.enabled`를 켜는 저장이 409 `POINTS_UNAVAILABLE`이다. 필드가 없는 이전 응답은 false로 읽는다"),
4204
+ useAvailable: z.boolean().optional().default(false).describe("적립금 사용(결제에 쓰기)을 켤 수 있는가 (#93). 지금은 늘 true다. 필드가 없는 이전 응답은 false로 읽는다"),
3869
4205
  use: pointUsePolicySchema.optional().default(POINT_POLICY_DEFAULTS.use).describe("적립금 사용 규칙. 적용 순서는 즉시할인 → 쿠폰 → 적립금이다. 정하지 않았으면 끔. 필드가 없는 이전 응답은 끔으로 읽는다"),
3870
4206
  expiryDays: pointPolicySchema.shape.expiryDays,
3871
4207
  notice: pointPolicyNoticeSchema
@@ -3970,6 +4306,118 @@ function splitRefund(input) {
3970
4306
  };
3971
4307
  }
3972
4308
  //#endregion
4309
+ //#region src/schemas/product-info.ts
4310
+ /**
4311
+ * 상품정보제공 고시·인증 정보·안내 섹션 (이슈 #135).
4312
+ *
4313
+ * **코드 값은 문자열이다.** 품목군(`schemaId`)·인증 종류·대상·면제 사유는 플랫폼 코드 표(서버 DB)가 원천이고, 코드가 늘어도 이 SDK의
4314
+ * 계약이 깨지지 않게 zod enum으로 막지 않는다. 서버가 코드 표에 있는지 검사한다(없으면 400 `INVALID_INFO_CODE`).
4315
+ * enum으로 두는 값은 서버가 그 값으로 분기하는 인증 상태(`CERTIFICATION_STATUSES`)뿐이다.
4316
+ */
4317
+ /**
4318
+ * 칸 값의 출처 — 셀러가 비운 칸을 서버가 채운다. 서버가 분기하는 값이라 형태가 정해져 있지만, 새 출처가 늘 수 있어 응답은 열린 객체다.
4319
+ * - `legal`: 법정 문구(`text`). 셀러가 적지 않는다
4320
+ * - `option`: 이름이 `names` 중 하나인 조합 옵션명의 값 목록
4321
+ * - `store`: 상점 필드(`field`, 예: `customerCenterPhone`)
4322
+ */
4323
+ const infoFieldSourceSchema = z.looseObject({
4324
+ type: z.string(),
4325
+ text: z.string().optional(),
4326
+ names: z.array(z.string()).optional(),
4327
+ field: z.string().optional()
4328
+ });
4329
+ const infoSchemaFieldSchema = z.object({
4330
+ key: z.string(),
4331
+ label: z.string(),
4332
+ required: z.boolean().describe("법정 필수 칸인가. 서버는 비어 있어도 막지 않는다(표시는 「상품상세 참조」)"),
4333
+ maxLength: z.number().int(),
4334
+ source: infoFieldSourceSchema.nullable().optional().describe("값 출처. 없으면 셀러가 적는 칸")
4335
+ });
4336
+ /** 정형 정보 스키마 — 고시 품목군 하나(`kind: "notice"`). 칸 구성은 버전마다 고정이고 상품은 저장한 버전으로 표시된다 */
4337
+ const infoSchemaSchema = z.object({
4338
+ schemaId: z.string().describe("품목군 코드(예: `WEAR`)"),
4339
+ version: z.number().int(),
4340
+ kind: z.string().describe("스키마 종류. 지금은 `notice`(상품정보제공 고시)"),
4341
+ name: z.string(),
4342
+ fallback: z.string().describe("비운 칸의 표시 문구(예: 「상품상세 참조」)"),
4343
+ fields: z.array(infoSchemaFieldSchema).describe("칸. 배열 순서가 표시 순서다")
4344
+ });
4345
+ /** 플랫폼 코드 하나 — 코드 묶음(`setId`) 안에서 유일하다. `attrs`는 묶음마다 다른 부가 정보다 */
4346
+ const platformCodeSchema = z.object({
4347
+ code: z.string(),
4348
+ label: z.string(),
4349
+ attrs: z.record(z.string(), z.unknown()).describe("부가 정보. `certification.subject`는 `kinds`(이 대상을 충족하는 인증 종류)·`exemptions`(허용 면제 사유)를 싣는다")
4350
+ });
4351
+ /** 코드 묶음 — `GET /v1/codes/{setId}` */
4352
+ const PLATFORM_CODE_SETS = {
4353
+ certificationKind: "certification.kind",
4354
+ certificationSubject: "certification.subject",
4355
+ certificationExemption: "certification.exemption"
4356
+ };
4357
+ const productNoticeSchema = z.object({
4358
+ schemaId: z.string(),
4359
+ version: z.number().int(),
4360
+ values: z.record(z.string(), z.string()).describe("칸 키 → 셀러가 적은 값. 비운 칸은 없다")
4361
+ });
4362
+ const MAX_NOTICE_VALUE_LENGTH = 1500;
4363
+ const productNoticeRequestSchema = z.object({
4364
+ schemaId: z.string().trim().min(1).max(50).describe("품목군 코드(`GET /v1/info-schemas`)"),
4365
+ version: z.number().int().positive().optional().describe("품목군 버전. 생략하면 현재 버전"),
4366
+ values: z.record(z.string().max(50), z.string().max(MAX_NOTICE_VALUE_LENGTH)).default({}).describe("칸 키 → 값. 출처가 `legal`인 칸은 받지 않는다(400). 빈 문자열은 비운 칸으로 저장하지 않는다. 칸 길이는 스키마 `maxLength`")
4367
+ });
4368
+ /** 인증 대상 상태 — 서버가 분기한다(대상이면 인증서 필수, 면제면 사유 필수) */
4369
+ const CERTIFICATION_STATUSES = [
4370
+ "REQUIRED",
4371
+ "NOT_REQUIRED",
4372
+ "EXEMPT"
4373
+ ];
4374
+ const MAX_CERTIFICATION_ITEMS = 20;
4375
+ const productCertificationsSchema = z.object({
4376
+ subjects: z.array(z.object({
4377
+ subject: z.string().describe("인증 대상 코드(`certification.subject`)"),
4378
+ status: z.string().describe("`REQUIRED`·`NOT_REQUIRED`·`EXEMPT`. 값이 늘 수 있어 문자열이다"),
4379
+ exemption: z.string().nullable().describe("면제 사유 코드. `EXEMPT`일 때만 있다")
4380
+ })).describe("인증 대상 여부. 없는 대상은 `NOT_REQUIRED`다"),
4381
+ items: z.array(z.object({
4382
+ kind: z.string().describe("인증 종류 코드(`certification.kind`)"),
4383
+ agency: z.string().nullable().describe("인증 기관"),
4384
+ number: z.string().describe("인증 번호")
4385
+ })).describe("인증서. 배열 순서가 표시 순서다")
4386
+ });
4387
+ const productCertificationsRequestSchema = z.object({
4388
+ subjects: z.array(z.object({
4389
+ subject: z.string().trim().min(1).max(50),
4390
+ status: z.enum(CERTIFICATION_STATUSES),
4391
+ exemption: z.string().trim().min(1).max(50).nullish()
4392
+ })).max(20).default([]).describe("인증 대상 여부. `REQUIRED`인데 그 대상의 인증 종류(`attrs.kinds`) 인증서가 `items`에 없으면 400 `CERTIFICATION_REQUIRED`, `EXEMPT`인데 사유가 없거나 대상이 허용하지 않는 사유면 400 `CERTIFICATION_EXEMPTION_INVALID`"),
4393
+ items: z.array(z.object({
4394
+ kind: z.string().trim().min(1).max(50),
4395
+ agency: z.string().trim().max(100).nullish(),
4396
+ number: z.string().trim().min(1).max(100)
4397
+ })).max(20).default([])
4398
+ });
4399
+ /** 상품 하나에 연결할 수 있는 안내 섹션 수 */
4400
+ const MAX_PRODUCT_INFO_SECTIONS = 10;
4401
+ const MAX_INFO_SECTION_TITLE = 100;
4402
+ /**
4403
+ * 안내 섹션 — 사이즈 가이드·세탁 안내처럼 여러 상품이 같이 쓰는 글이다. **상품은 연결만 한다**(복사가 아니다).
4404
+ * 섹션을 고치면 연결된 모든 상품의 표시가 바뀐다.
4405
+ */
4406
+ const infoSectionSchema = z.object({
4407
+ infoSectionId: z.string(),
4408
+ title: z.string(),
4409
+ body: z.string().describe("본문 HTML(상세설명과 같은 정화 규칙)"),
4410
+ bodyJson: z.string().nullable().describe("에디터 복원용 직렬화 상태"),
4411
+ assignedProductCount: z.number().int().describe("이 섹션을 연결한 상품 수"),
4412
+ createdAt: z.string(),
4413
+ updatedAt: z.string()
4414
+ });
4415
+ const infoSectionRequestSchema = z.object({
4416
+ title: z.string().trim().min(1).max(100),
4417
+ body: z.string().default(""),
4418
+ bodyJson: z.string().nullable().optional()
4419
+ });
4420
+ //#endregion
3973
4421
  //#region src/schemas/stay.ts
3974
4422
  /**
3975
4423
  * 날짜별 재고·가격(이슈 #118) — 숙박·회차처럼 날짜마다 재고와 가격이 다른 상품. 상품 `inventoryMode: "DATED"`이면 조합(객실) × 날짜
@@ -4198,6 +4646,7 @@ const productVariantSchema = z.object({
4198
4646
  /** 값 이름을 " / "로 이은 파생 표시명. 옵션 없으면 "" */
4199
4647
  name: z.string(),
4200
4648
  additionalPrice: z.number().int(),
4649
+ prices: z.array(storedAdditionalCurrencyPriceSchema).optional().describe("외화 추가금(이슈 #130, 관리 API만). 기본 통화 값은 `additionalPrice`다"),
4201
4650
  stockQuantity: z.number().int(),
4202
4651
  sku: z.string().nullable(),
4203
4652
  barcode: z.string().nullable(),
@@ -4238,6 +4687,7 @@ const addonValueSchema = z.object({
4238
4687
  name: z.string(),
4239
4688
  sortOrder: z.number().int(),
4240
4689
  additionalPrice: z.number().int().describe("이 값을 고르면 단가에 더하는 금액(원, 0 이상)"),
4690
+ prices: z.array(storedAdditionalCurrencyPriceSchema).optional().describe("외화 추가금(이슈 #130, 관리 API만). 기본 통화 값은 `additionalPrice`다"),
4241
4691
  usable: z.boolean().describe("사용 여부. false면 구매자에게 보이지 않고 고를 수 없다")
4242
4692
  });
4243
4693
  /** 추가 선택 옵션명 */
@@ -4321,6 +4771,7 @@ const addonValueRequestSchema = z.object({
4321
4771
  valueId: z.string().optional(),
4322
4772
  name: optionNameSchema,
4323
4773
  additionalPrice: z.number().int().min(0).default(0).describe("추가금(원, 0 이상)"),
4774
+ prices: additionalCurrencyPricesSchema.optional(),
4324
4775
  usable: z.boolean().default(true)
4325
4776
  });
4326
4777
  const addonGroupRequestSchema = z.object({
@@ -4369,6 +4820,7 @@ const discountSchema = z.object({
4369
4820
  endAt: z.string().nullable()
4370
4821
  });
4371
4822
  const productSchema = productSummarySchema.extend({
4823
+ prices: z.array(storedProductCurrencyPriceSchema).optional().describe("외화 판매가(이슈 #130). 기본 통화 값은 `salePrice`·`originalPrice`다"),
4372
4824
  description: z.string().optional(),
4373
4825
  /**
4374
4826
  * 상세설명 에디터(@avarlabs/editor)의 직렬화 상태. 재편집 때 이 값으로 문서를 복원한다.
@@ -4398,6 +4850,9 @@ const productSchema = productSummarySchema.extend({
4398
4850
  * 할인이 없으면 null이다. 이 필드를 싣기 전 서버의 응답에는 없으므로 optional이다.
4399
4851
  */
4400
4852
  discount: discountSchema.nullable().optional().describe("설정된 즉시할인. GET /v1/products/{productId}/discount 응답과 같은 형태다. 할인이 없으면 null"),
4853
+ notice: productNoticeSchema.nullable().optional().describe("상품정보제공 고시(이슈 #135). 없으면 null. 서버는 항상 싣는다"),
4854
+ certifications: productCertificationsSchema.nullable().optional().describe("인증 정보(이슈 #135). 없으면 null. 서버는 항상 싣는다"),
4855
+ infoSectionIds: z.array(z.string()).optional().default([]).describe("연결한 안내 섹션 id(이슈 #135). 배열 순서가 표시 순서다. 서버는 항상 싣는다"),
4401
4856
  createdAt: z.string().optional()
4402
4857
  });
4403
4858
  /** 상품 하나에 등록할 수 있는 이미지 최대 장수 — 첫 장이 대표(썸네일)다 */
@@ -4471,6 +4926,7 @@ const productVariantRequestSchema = z.object({
4471
4926
  /** optionGroups 순서대로 각 축에서 고른 값 이름. 서버가 이름 → valueId를 해석한다 */
4472
4927
  valueNames: z.array(z.string()).default([]),
4473
4928
  additionalPrice: z.number().int().default(0),
4929
+ prices: additionalCurrencyPricesSchema.optional(),
4474
4930
  /**
4475
4931
  * 생략 = 기존 재고 유지 (신규 variant는 0).
4476
4932
  * 구조 교체(PUT)가 폼 로드 시점의 재고를 되쓰지 않게 하는 옵트인 필드다 —
@@ -4489,8 +4945,8 @@ const productVariantRequestSchema = z.object({
4489
4945
  const optionModelRequestSchema = z.object({
4490
4946
  optionGroups: z.array(optionGroupRequestSchema).max(3).default([]),
4491
4947
  variants: z.array(productVariantRequestSchema).min(1).max(500),
4492
- addonGroups: z.array(addonGroupRequestSchema).max(5).optional().describe("추가 선택 옵션명 전체(이슈 #59). 주면 통째로 바꾸고, 생략하면 등록은 없음·수정은 현재 값을 그대로 둔다. 끄려면 빈 배열을 보낸다. 기능이 열리기 전에는 비어 있지 않은 값이 409 `OPTION_ADDONS_UNAVAILABLE`이다"),
4493
- customInputs: z.array(customInputRequestSchema).max(5).optional().describe("직접 입력 항목 전체(이슈 #59). 배열 순서가 표시 순서다. 주면 통째로 바꾸고, 생략하면 등록은 없음·수정은 현재 값을 그대로 둔다. 항목명에 개인정보성 단어(`CUSTOM_INPUT_FORBIDDEN_WORDS`)가 있으면 400 `CUSTOM_INPUT_LABEL_FORBIDDEN`, 기능이 열리기 전에는 비어 있지 않은 값이 409 `OPTION_ADDONS_UNAVAILABLE`이다"),
4948
+ addonGroups: z.array(addonGroupRequestSchema).max(5).optional().describe("추가 선택 옵션명 전체(이슈 #59). 주면 통째로 바꾸고, 생략하면 등록은 없음·수정은 현재 값을 그대로 둔다. 끄려면 빈 배열을 보낸다"),
4949
+ customInputs: z.array(customInputRequestSchema).max(5).optional().describe("직접 입력 항목 전체(이슈 #59). 배열 순서가 표시 순서다. 주면 통째로 바꾸고, 생략하면 등록은 없음·수정은 현재 값을 그대로 둔다. 항목명에 개인정보성 단어(`CUSTOM_INPUT_FORBIDDEN_WORDS`)가 있으면 400 `CUSTOM_INPUT_LABEL_FORBIDDEN`이다"),
4494
4950
  optionSort: optionSortSchema.optional().describe("옵션 값 정렬 순서(이슈 #59). 서버가 이 순서로 값의 `sortOrder`를 다시 매긴다. 생략하면 등록은 `REGISTERED`, 수정은 현재 값이다")
4495
4951
  });
4496
4952
  /** GET /products/{productId}/options 응답 */
@@ -4527,12 +4983,18 @@ const productImagesRequestSchema = z.array(productImageUrlSchema).min(1).max(10)
4527
4983
  * 최상위가 `strictObject`다. 모르는 필드는 400이다 — 이슈 #57 이전의 평면 필드(`deliveryFee`·`fulfillmentType`·`returnFee` 등)를
4528
4984
  * 보낸 요청이 조용히 무시되지 않게 한다. 옛 필드는 `fulfillment.{유형}.…`과 `refundPolicy`로 옮겼다.
4529
4985
  */
4986
+ /**
4987
+ * 기본 통화 판매가 단위 — 통화표가 원천이다(이슈 #130). zod `multipleOf`로 두어 OpenAPI에 그대로 드러난다.
4988
+ * 외화 판매가(`prices[]`)는 통화마다 `isSaleUnitPrice`로 검사한다
4989
+ */
4990
+ const BASE_SALE_UNIT = CURRENCIES["KRW"].saleUnit;
4530
4991
  const productWriteShape = {
4531
4992
  name: z.string().min(1).max(100),
4532
4993
  categoryId: z.string().min(1, "카테고리를 선택해주십시오"),
4533
- salePrice: z.number().int().min(10).multipleOf(10, "판매가는 10원 단위여야 합니다 (INVALID_PRICE_UNIT)").describe("판매가. 원(KRW) 단위 정수, 최소 10원, 10원 단위"),
4994
+ salePrice: z.number().int().min(BASE_SALE_UNIT).multipleOf(BASE_SALE_UNIT, "판매가는 10원 단위여야 합니다 (INVALID_PRICE_UNIT)").describe("판매가. 원(KRW) 단위 정수, 최소 10원, 10원 단위"),
4534
4995
  originalPrice: z.number().int().optional().describe("정가(할인 전 표시 가격). 원 단위. 비교용 표시 값이고 결제 금액은 판매가(즉시할인이 있으면 할인 적용가)다. 스토어프론트가 판매가보다 클 때 취소선·할인율로 보인다. 즉시할인은 `PUT /v1/products/{productId}/discount`로 따로 정한다"),
4535
4996
  pointEarnRateBp: pointEarnRateBpSchema.nullable().optional().describe("구매 적립률 덮어쓰기(만분율, 100 = 1%, 0~3000, 이슈 #93). null이면 상점 기본 적립률, 0이면 이 상품은 적립하지 않는다. 결제 확정 시점 값이 주문상품에 남는다. 전체 수정(PUT)에서 생략하면 지금 값을 유지한다"),
4997
+ prices: productCurrencyPricesSchema.optional(),
4536
4998
  description: z.string().optional(),
4537
4999
  /**
4538
5000
  * 상세설명 에디터(@avarlabs/editor)의 직렬화 상태. 재편집 때 이 값으로 문서를 복원한다.
@@ -4545,6 +5007,9 @@ const productWriteShape = {
4545
5007
  value: z.string()
4546
5008
  })).optional(),
4547
5009
  refundPolicy: productRefundPolicyPatchSchema.nullish().describe("상품별 환불 정책 — 준 항목만 상점 기본을 덮어쓴다. `null`이나 생략은 상점 기본을 그대로 쓴다는 뜻이다. 반품·교환 배송비(`returnDeliveryFee`·`exchangeDeliveryFee`)는 배송 상품에만 줄 수 있다(다른 유형은 400)"),
5010
+ notice: productNoticeRequestSchema.nullable().optional().describe("상품정보제공 고시(이슈 #135). `null`은 지운다. 등록에서 생략하면 없음, 전체 수정(PUT)에서 생략하면 지금 값을 유지한다"),
5011
+ certifications: productCertificationsRequestSchema.nullable().optional().describe("인증 정보(이슈 #135). `null`은 지운다. 등록에서 생략하면 없음, 전체 수정(PUT)에서 생략하면 지금 값을 유지한다"),
5012
+ infoSectionIds: z.array(z.string().min(1)).max(10).optional().describe("연결할 안내 섹션 id(이슈 #135). 배열 순서가 표시 순서다. 이 상점의 섹션이 아니면 400 `INFO_SECTION_NOT_FOUND`. 전체 수정(PUT)에서 생략하면 지금 연결을 유지한다"),
4548
5013
  ...optionModelRequestSchema.shape,
4549
5014
  sourceOptionSetIds: z.array(z.string()).max(10).optional().describe("쓰기 전용(이슈 #59) — 이 저장으로 옵션을 불러온 저장 옵션 id. 상품 저장과 같은 트랜잭션에서 불러오기 기록을 남겨 저장 옵션의 `importedProductCount`를 센다. 없는 id는 무시한다"),
4550
5015
  inventoryMode: inventoryModeSchema.optional().describe("재고 방식(이슈 #118). `DATED`면 날짜별 달력(`PUT /products/{id}/calendar`)이 재고·가격이고 주문서 줄은 숙박 기간(`stay`)을 받는다. 생략하면 등록은 `STANDARD`, 수정은 지금 값. 판매 이력이 있으면 바꿀 수 없다(409 `INVENTORY_MODE_LOCKED`)"),
@@ -4562,11 +5027,12 @@ const productReplaceRequestSchema = z.strictObject({
4562
5027
  });
4563
5028
  const productPatchRequestSchema = z.strictObject({
4564
5029
  name: z.string().max(100).optional(),
4565
- salePrice: z.number().int().multipleOf(10).optional(),
5030
+ salePrice: z.number().int().multipleOf(BASE_SALE_UNIT).optional(),
4566
5031
  status: productStatusSchema.optional(),
4567
5032
  flowId: z.string().nullable().optional().describe("주문 흐름(이슈 #115) — 게시한 흐름 id, null이면 카테고리의 흐름(없으면 기본 흐름). 생략하면 바꾸지 않는다"),
4568
5033
  images: productImagesRequestSchema.optional().describe("상품 이미지 주소 목록. 주면 통째로 바꾼다(현재 목록과 병합하지 않는다). 첫 장이 대표 이미지(썸네일)다. 생략하면 바꾸지 않는다"),
4569
5034
  fulfillment: productFulfillmentUpdateSchema.optional().describe(fulfillmentUpdateDescription),
5035
+ prices: productCurrencyPricesSchema.optional(),
4570
5036
  refundPolicy: productRefundPolicyPatchSchema.nullable().optional().describe("상품별 환불 정책. 주면 통째로 바꾼다(준 항목만 상점 기본을 덮어쓴다). `null`은 덮어쓰기를 지워 상점 기본을 따른다. 생략하면 바꾸지 않는다"),
4571
5037
  pointEarnRateBp: pointEarnRateBpSchema.nullable().optional().describe("구매 적립률 덮어쓰기(만분율, 100 = 1%, 0~3000, 이슈 #93). null이면 상점 기본 적립률, 0이면 이 상품은 적립하지 않는다. 결제 확정 시점 값이 주문상품에 남는다. 생략하면 바꾸지 않는다")
4572
5038
  }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
@@ -4605,6 +5071,7 @@ const orderWebhookEventDataSchema = z.object({
4605
5071
  orderId: z.string().describe("주문 ID"),
4606
5072
  orderNo: z.string().nullable().optional().default(null).describe("주문번호(이슈 #107) — 숫자 14자리. 이 필드가 없는 이전 이벤트와 번호 체계 이전 주문은 null로 읽는다"),
4607
5073
  status: orderItemStatusSchema.describe("이벤트 발생 시점의 주문 대표 상태"),
5074
+ currency: z.string().optional().describe("주문 통화(ISO 4217, 이슈 #130). 이 이벤트의 금액은 모두 이 통화의 최소 단위다. 외화 주문이 생기면 이 값을 확인한다. 이 필드가 없는 이전 이벤트는 KRW다"),
4608
5075
  testPayment: z.boolean().optional().default(false).describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았다. 이 필드가 없는 이전 이벤트는 false로 읽는다"),
4609
5076
  couponDiscountAmount: z.number().int().optional().default(0).describe("주문이 받은 상품·주문 쿠폰 할인 합계 (원). 즉시할인(`discountAmount`)과 별개다. 쿠폰이 없거나 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
4610
5077
  pointAmount: z.number().int().optional().default(0).describe("주문에 쓴 적립금 (원, #93). 적립금을 쓰지 않았거나 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
@@ -4628,6 +5095,7 @@ const orderFulfilledWebhookEventDataSchema = z.object({
4628
5095
  fulfillmentSnapshot: orderItemFulfillmentSnapshotResponseSchema.describe("제공한 주문상품의 주문 시점 이행 스냅샷(주문상품 응답의 `fulfillmentSnapshot`과 같다, 이슈 #57)"),
4629
5096
  fulfillment: z.object({ mode: z.string() }).optional().describe("**Deprecated** — 항상 `{ mode: \"MANUAL\" }`이다. 자동 제공을 없앴고(이슈 #48) store-sdk 0.19 이하 호환으로만 싣는다. 게시된 연동이 store-sdk 0.20 이상으로 넘어간 뒤 다음 릴리스에서 뺀다"),
4630
5097
  fulfilledAt: z.string().describe("제공 시각 (ISO 8601). 주문상품의 `deliveredAt`과 같다"),
5098
+ currency: z.string().optional().describe("주문 통화(ISO 4217, 이슈 #130). 이 이벤트의 금액은 모두 이 통화의 최소 단위다. 외화 주문이 생기면 이 값을 확인한다. 이 필드가 없는 이전 이벤트는 KRW다"),
4631
5099
  testPayment: z.boolean().describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았다")
4632
5100
  });
4633
5101
  /**
@@ -4650,6 +5118,7 @@ const orderCanceledWebhookEventDataSchema = z.object({
4650
5118
  couponChargeAmount: z.number().int().optional().default(0).describe("환불액에서 뺀 쿠폰 조건 미달 차감 (원). 판매자 취소는 차감하지 않으므로 늘 0이다. 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
4651
5119
  couponChargeRefundAmount: z.number().int().optional().default(0).describe("환불액에 더한 금액 (원) — 앞선 환불에서 뺀 쿠폰 조건 미달 차감을 되돌린 몫이다. 전량 취소면 누적 차감이 모두 되돌아간다. 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
4652
5120
  pointRefundAmount: z.number().int().optional().default(0).describe("돌려준 적립금 (원, #93) — 결제에 쓴 적립금 중 이번 취소·반품 수량의 몫이다. 현금 환불(`refundAmount`)과 별개다. 차감은 현금에서 먼저 빼고 모자란 몫만 여기서 뺀다. 적립금을 쓰지 않은 주문과 이 필드가 없는 이전 응답·이벤트는 0으로 읽는다"),
5121
+ currency: z.string().optional().describe("주문 통화(ISO 4217, 이슈 #130). 이 이벤트의 금액은 모두 이 통화의 최소 단위다. 외화 주문이 생기면 이 값을 확인한다. 이 필드가 없는 이전 이벤트는 KRW다"),
4653
5122
  testPayment: z.boolean().describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았다")
4654
5123
  });
4655
5124
  const claimWebhookEventDataSchema = z.object({
@@ -4667,6 +5136,7 @@ const claimWebhookEventDataSchema = z.object({
4667
5136
  couponChargeAmount: z.number().int().optional().default(0).describe("환불액에서 뺀 쿠폰 조건 미달 차감 (원) — 일부 취소·반품으로 남은 주문상품이 쿠폰 조건(최소 주문 금액 등)을 잃어 남은 주문상품이 받던 할인을 뺀 금액이다. 배송비 차감·추가 차감과 별개다. 접수 이벤트는 예상값이다. 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
4668
5137
  couponChargeRefundAmount: z.number().int().optional().default(0).describe("환불액에 더한 금액 (원) — 앞선 환불에서 뺀 쿠폰 조건 미달 차감을 되돌린 몫이다. 접수 이벤트는 예상값이다. 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
4669
5138
  pointRefundAmount: z.number().int().optional().default(0).describe("돌려준 적립금 (원, #93) — 결제에 쓴 적립금 중 이번 취소·반품 수량의 몫이다. 현금 환불(`refundAmount`)과 별개다. 차감은 현금에서 먼저 빼고 모자란 몫만 여기서 뺀다. 적립금을 쓰지 않은 주문과 이 필드가 없는 이전 응답·이벤트는 0으로 읽는다"),
5139
+ currency: z.string().optional().describe("주문 통화(ISO 4217, 이슈 #130). 이 이벤트의 금액은 모두 이 통화의 최소 단위다. 외화 주문이 생기면 이 값을 확인한다. 이 필드가 없는 이전 이벤트는 KRW다"),
4670
5140
  testPayment: z.boolean().optional().default(false).describe("테스트 결제(샌드박스 결제) 주문의 클레임인가. 이 필드가 없는 이전 이벤트는 false로 읽는다")
4671
5141
  });
4672
5142
  const inquiryWebhookEventDataSchema = z.object({
@@ -7067,16 +7537,17 @@ const couponRejectReasonSchema = z.enum([
7067
7537
  "NO_DISCOUNT"
7068
7538
  ]).describe("쿠폰을 적용하지 못한 사유. `DUPLICATE_COUPON`=같은 쿠폰을 두 번 넣음, `STACK_LIMIT`=같은 종류의 쿠폰이 이미 적용됨(주문 쿠폰·배송비 쿠폰은 주문당 1장, 상품 쿠폰은 주문상품 한 줄에 1장), `NOT_STARTED`=사용 기간 전, `EXPIRED`=사용 기간 지남, `MEMBER_ONLY`=회원 전용, `FIRST_ORDER_ONLY`=첫 구매 전용, `NO_ELIGIBLE_ITEMS`=대상 상품이 주문에 없음, `MIN_ORDER_AMOUNT`=최소 주문 금액 미달, `LINE_NOT_ELIGIBLE`=지정한 주문상품이 대상이 아니거나 이미 상품 쿠폰이 있음, `LINE_AMBIGUOUS`=지정한 `optionId`의 줄이 여럿이라 줄을 정할 수 없음(`lineId`로 지목한다), `NO_DISCOUNT`=할인할 금액이 없음");
7069
7539
  /** 쿠폰 적용 뒤 결제 금액의 하한 — 0원 결제 경로가 없어 이보다 작으면 결제를 시작하지 않는다(400 `PAYMENT_AMOUNT_TOO_LOW`) */
7070
- const MIN_PAYMENT_AMOUNT = 100;
7540
+ const MIN_PAYMENT_AMOUNT = CURRENCIES.KRW.minPayment;
7071
7541
  /**
7072
- * 할인액 — 정률은 10원 단위 내림, 최대 할인액과 기준 금액을 넘지 않는다. 기준 금액이 0 이하면 0이다.
7542
+ * 할인액 — 정률은 판매가 단위(`rules.saleUnit`, KRW 10원) 내림, 최대 할인액과 기준 금액을 넘지 않는다. 기준 금액이 0 이하면 0이다.
7073
7543
  *
7074
- * 곱셈을 먼저 하고 나눈다. `base × 율 ÷ 1000`을 내려 10을 곱하면 `floor(base × 율 / 100 / 10) × 10`과 같고
7075
- * 부동소수 오차가 끼지 않는다.
7544
+ * 곱셈을 먼저 하고 나눈다. `base × 율 ÷ (100 × 단위)`를 내려 단위를 곱하면 `floor(base × 율 / 100 / 단위) × 단위`와 같고
7545
+ * 부동소수 오차가 끼지 않는다(KRW는 지금의 `÷ 1000 × 10` 그대로).
7076
7546
  */
7077
- function couponDiscountOf(benefit, base) {
7547
+ function couponDiscountOf(benefit, base, rules = KRW_MONEY_RULES) {
7078
7548
  if (base <= 0) return 0;
7079
- let raw = benefit.type === "RATE" ? Math.floor(base * benefit.value / 1e3) * 10 : benefit.value;
7549
+ const unit = rules.saleUnit;
7550
+ let raw = benefit.type === "RATE" ? Math.floor(base * benefit.value / (100 * unit)) * unit : benefit.value;
7080
7551
  if (benefit.type === "RATE" && benefit.maxDiscountAmount !== null) raw = Math.min(raw, benefit.maxDiscountAmount);
7081
7552
  return Math.max(0, Math.min(raw, base));
7082
7553
  }
@@ -7144,6 +7615,7 @@ function periodRejectOf(coupon, now) {
7144
7615
  * 사본 중 앞 장이 만료됐으면 뒤 장이 쓰인다. 결과의 `coupons`는 입력 순서 그대로다. 입력이 같으면 결과도 같다.
7145
7616
  */
7146
7617
  function quotePricing(input) {
7618
+ const rules = input.moneyRules ?? KRW_MONEY_RULES;
7147
7619
  const lines = input.lines.map((line) => ({
7148
7620
  line,
7149
7621
  productDiscount: 0,
@@ -7219,14 +7691,14 @@ function quotePricing(input) {
7219
7691
  continue;
7220
7692
  }
7221
7693
  chosen = coupon.lineId;
7222
- best = couponDiscountOf(coupon.rule.benefit, lineOf(chosen)?.line.amount ?? 0);
7694
+ best = couponDiscountOf(coupon.rule.benefit, lineOf(chosen)?.line.amount ?? 0, rules);
7223
7695
  } else {
7224
7696
  if (candidates.length === 0) {
7225
7697
  result.rejectReason = "STACK_LIMIT";
7226
7698
  continue;
7227
7699
  }
7228
7700
  for (const id of candidates) {
7229
- const discount = couponDiscountOf(coupon.rule.benefit, lineOf(id)?.line.amount ?? 0);
7701
+ const discount = couponDiscountOf(coupon.rule.benefit, lineOf(id)?.line.amount ?? 0, rules);
7230
7702
  if (chosen === null || discount > best) {
7231
7703
  chosen = id;
7232
7704
  best = discount;
@@ -7259,7 +7731,7 @@ function quotePricing(input) {
7259
7731
  const targets = result.eligibleLineIds.map((id) => lineOf(id)).filter((entry) => entry !== void 0);
7260
7732
  const weights = targets.map((entry) => Math.max(0, entry.line.amount - entry.productDiscount));
7261
7733
  const base = weights.reduce((sum, w) => sum + w, 0);
7262
- const discount = couponDiscountOf(coupon.rule.benefit, base);
7734
+ const discount = couponDiscountOf(coupon.rule.benefit, base, rules);
7263
7735
  if (discount <= 0) {
7264
7736
  result.rejectReason = "NO_DISCOUNT";
7265
7737
  continue;
@@ -7294,7 +7766,7 @@ function quotePricing(input) {
7294
7766
  }
7295
7767
  const weights = deliveryBundles.map((bundle) => Math.max(0, bundle.fee));
7296
7768
  const base = weights.reduce((sum, w) => sum + w, 0);
7297
- const discount = couponDiscountOf(coupon.rule.benefit, base);
7769
+ const discount = couponDiscountOf(coupon.rule.benefit, base, rules);
7298
7770
  if (discount <= 0) {
7299
7771
  result.rejectReason = "NO_DISCOUNT";
7300
7772
  continue;
@@ -7324,7 +7796,7 @@ function quotePricing(input) {
7324
7796
  productPaid: productWeights.reduce((sum, w) => sum + w, 0),
7325
7797
  deliveryPaid: bundleWeights.reduce((sum, w) => sum + w, 0),
7326
7798
  total: beforePoints
7327
- });
7799
+ }, rules);
7328
7800
  if (points.amount > 0) {
7329
7801
  const productPaid = productWeights.reduce((sum, w) => sum + w, 0);
7330
7802
  const toLines = Math.min(points.amount, productPaid);
@@ -7359,7 +7831,7 @@ function quotePricing(input) {
7359
7831
  * - 그 밖에는 사용 단위로 내리고, 남는 결제 금액이 1~99원이면 적립금을 줄여 100원을 남긴다(`MIN_PAYMENT`)
7360
7832
  * 최소 보유액·최소 사용액에 못 미치면 0이다.
7361
7833
  */
7362
- function pointUseOf(points, amounts) {
7834
+ function pointUseOf(points, amounts, moneyRules = KRW_MONEY_RULES) {
7363
7835
  const none = {
7364
7836
  amount: 0,
7365
7837
  maxUsable: 0,
@@ -7382,8 +7854,8 @@ function pointUseOf(points, amounts) {
7382
7854
  };
7383
7855
  const amount = floorUnit(Math.min(cap, total));
7384
7856
  const remaining = total - amount;
7385
- if (remaining > 0 && remaining < 100) return {
7386
- amount: floorUnit(total - 100),
7857
+ if (remaining > 0 && remaining < moneyRules.minPayment) return {
7858
+ amount: floorUnit(total - moneyRules.minPayment),
7387
7859
  adjusted: true
7388
7860
  };
7389
7861
  return {
@@ -7639,7 +8111,8 @@ const createCouponRequestSchema = z.strictObject({
7639
8111
  totalIssueLimit: limitField(descriptions.totalIssueLimit),
7640
8112
  totalUseLimit: limitField(descriptions.totalUseLimit),
7641
8113
  perMemberIssueLimit: limitField(descriptions.perMemberIssueLimit),
7642
- perMemberUseLimit: limitField(descriptions.perMemberUseLimit)
8114
+ perMemberUseLimit: limitField(descriptions.perMemberUseLimit),
8115
+ currency: currencyCodeSchema.optional().describe("쿠폰 통화(이슈 #130). 정액·최대 할인액·최소 주문 금액이 이 통화 값이고 같은 통화 주문서에만 적용된다. 생략하면 기본 통화(KRW). 판매 통화여야 하고 만든 뒤에는 바꿀 수 없다")
7643
8116
  }).superRefine((body, ctx) => {
7644
8117
  const issue = (path, message) => ctx.addIssue({
7645
8118
  code: "custom",
@@ -7695,6 +8168,7 @@ const couponSchema = z.object({
7695
8168
  issuedCount: z.number().int().describe("발급 수 — 회수한 발급도 센다. 총 발급 한도(`totalIssueLimit`)가 이 값과 비교된다"),
7696
8169
  reservedCount: z.number().int().describe("결제 중인 예약 수 — 결제가 끝나거나 만료되면 풀린다"),
7697
8170
  usedCount: z.number().int().describe("사용 수 — 전량 취소로 복원되면 줄어든다"),
8171
+ currency: z.string().optional().default("KRW").describe("쿠폰 통화(이슈 #130). 금액 필드는 이 통화의 최소 단위다. 옛 서버 응답은 KRW로 읽는다"),
7698
8172
  status: couponStatusSchema,
7699
8173
  locked: z.boolean().describe("발급·사용이 시작돼 혜택·조건·대상·사용 시작일을 바꿀 수 없는가"),
7700
8174
  lockedAt: z.string().nullable(),
@@ -7808,7 +8282,7 @@ const customerListQuerySchema = z.object({
7808
8282
  /** 구매 통계 — 구매 금액은 취소된 주문 상품을 빼고, 완료된 반품은 수량 비율로 뺀 금액이다 */
7809
8283
  const customerStatsSchema = z.object({
7810
8284
  orderCount: z.number().int().describe("주문 수(취소 포함)"),
7811
- totalPaid: z.number().int().describe("구매 금액(원) — 취소·완료된 반품 제외"),
8285
+ totalPaid: z.number().int().describe("구매 금액(원) — 취소·완료된 반품 제외. 원화 주문만 더한다(외화 주문은 환산하지 않고 빠진다)"),
7812
8286
  lastOrderedAt: z.string().nullable().describe("최근 주문 시각")
7813
8287
  });
7814
8288
  /** 목록 행 — 휴대폰은 가운데를 가린다(`010-****-1234`) */
@@ -7830,7 +8304,10 @@ const customerAddressSchema = z.object({
7830
8304
  phone: z.string(),
7831
8305
  zipCode: z.string(),
7832
8306
  address1: z.string(),
7833
- address2: z.string().nullable()
8307
+ address2: z.string().nullable(),
8308
+ countryCode: z.string().optional().default("KR").describe("국가(ISO 3166-1 alpha-2, 이슈 #130). 해외 주소의 `zipCode`는 그 나라 우편번호이고 없으면 빈 문자열이다"),
8309
+ city: z.string().nullable().optional().default(null).describe("해외 주소의 도시. 국내는 null"),
8310
+ region: z.string().nullable().optional().default(null).describe("해외 주소의 주·도·현. 국내는 null")
7834
8311
  });
7835
8312
  /** 동의 종류 — 이용약관·개인정보 수집이용은 가입 필수, 마케팅 수신은 선택 */
7836
8313
  const consentKindSchema = z.enum([
@@ -8143,6 +8620,45 @@ const loginProviderTestSchema = z.object({
8143
8620
  testedAt: z.string()
8144
8621
  });
8145
8622
  //#endregion
8623
+ //#region src/schemas/market.ts
8624
+ /**
8625
+ * 판매 권역 (이슈 #130) — 상점이 어느 국가에 어느 통화로 파는지를 정한다.
8626
+ *
8627
+ * 권역 = 이름 + 통화 하나 + 국가 목록 + 연결 도메인 + 쿠폰·적립금 사용. 국가는 상점 안에서 한 권역에만 속하고, 판매 국가는 보관하지 않은 모든 권역 국가의
8628
+ * 합집합이다. 기본 권역은 상점마다 하나이고 그 통화가 기본 통화(KRW)다. 기본 권역은 보관할 수 없고 국가 목록을 비울 수 없다. 권역의 통화는 만들 때만 정한다.
8629
+ *
8630
+ * 스토어프론트는 요청마다 도메인(`X-Storefront-Host`) → 구매자 국가(`X-Buyer-Country`) → 기본 권역 순으로 권역을 고르고, 주문서가 그 권역·통화를 굳힌다.
8631
+ * 외화 권역은 적립금을 켤 수 없다(적립금은 기본 통화 단위다).
8632
+ */
8633
+ const countryCodeSchema = z.string().regex(/^[A-Za-z]{2}$/, "국가는 ISO 3166-1 alpha-2 두 글자입니다").transform((value) => value.toUpperCase()).describe("국가(ISO 3166-1 alpha-2, 예: KR·US·JP)");
8634
+ const hostnameSchema = z.string().min(1).max(253).regex(/^[A-Za-z0-9.-]+$/, "도메인은 호스트 이름만 입력합니다(예: shop.example.com)").transform((value) => value.toLowerCase().replace(/\.$/, "")).describe("연결 도메인(호스트 이름). 셀러가 직접 호스팅하는 스토어프론트가 `X-Storefront-Host`로 보낸다");
8635
+ const marketSchema = z.object({
8636
+ marketId: z.string(),
8637
+ name: z.string(),
8638
+ currency: currencyCodeSchema,
8639
+ isDefault: z.boolean().describe("기본 권역. 상점마다 하나이고 보관할 수 없다. 이 통화가 기본 통화다"),
8640
+ countries: z.array(z.string()).describe("이 권역 국가. 국가는 상점 안에서 한 권역에만 속한다"),
8641
+ domains: z.array(z.string()).describe("이 권역에 연결한 도메인"),
8642
+ couponsEnabled: z.boolean().describe("이 권역 주문서에서 쿠폰을 쓸 수 있는가"),
8643
+ pointsEnabled: z.boolean().describe("이 권역 주문서에서 적립금을 쓸 수 있는가. 외화 권역은 늘 false다"),
8644
+ archivedAt: z.string().nullable().describe("보관 시각. 보관한 권역은 판정에서 빠지고 그 국가·도메인은 풀린다")
8645
+ });
8646
+ const createMarketRequestSchema = z.strictObject({
8647
+ name: z.string().trim().min(1).max(50),
8648
+ currency: currencyCodeSchema.describe("이 권역의 통화. 만든 뒤에는 바꿀 수 없다"),
8649
+ countries: z.array(countryCodeSchema).min(1).max(250),
8650
+ domains: z.array(hostnameSchema).max(20).optional(),
8651
+ couponsEnabled: z.boolean().optional().describe("기본 false"),
8652
+ pointsEnabled: z.boolean().optional().describe("기본 false. 외화 권역은 true로 둘 수 없다")
8653
+ });
8654
+ const updateMarketRequestSchema = z.strictObject({
8655
+ name: z.string().trim().min(1).max(50).optional(),
8656
+ countries: z.array(countryCodeSchema).max(250).optional().describe("주면 국가 목록 전체를 바꾼다. 다른 권역의 국가는 그 권역에서 먼저 빼야 한다"),
8657
+ domains: z.array(hostnameSchema).max(20).optional().describe("주면 도메인 목록 전체를 바꾼다"),
8658
+ couponsEnabled: z.boolean().optional(),
8659
+ pointsEnabled: z.boolean().optional().describe("외화 권역은 true로 둘 수 없다")
8660
+ });
8661
+ //#endregion
8146
8662
  //#region src/schemas/payment.ts
8147
8663
  /**
8148
8664
  * 상점 결제(PG) 설정과 매출 리포트 계약.
@@ -8155,15 +8671,23 @@ const pgProviderSchema = z.enum([
8155
8671
  "tosspayments",
8156
8672
  "portone",
8157
8673
  "kakaopay",
8158
- "naverpay"
8159
- ]).describe("PG 식별자. `tosspayments`=토스페이먼츠, `portone`=포트원(V2), `kakaopay`=카카오페이(직접 연동), `naverpay`=네이버페이 결제형(직접 연동)");
8674
+ "naverpay",
8675
+ "paypal"
8676
+ ]).describe("PG 식별자. `tosspayments`=토스페이먼츠, `portone`=포트원(V2), `kakaopay`=카카오페이(직접 연동), `naverpay`=네이버페이 결제형(직접 연동), `paypal`=PayPal(직접 연동, 외화)");
8677
+ /**
8678
+ * 응답에 실리는 PG — 서버가 PG를 추가해도 응답 파싱이 깨지지 않게 문자열로 받는다(`easyPayProviderResponseSchema`와 같은 방식, 이슈 #131 CD2).
8679
+ * 요청(우선순위·리포트 필터·경로)은 값을 골라 보내는 자리라 `pgProviderSchema` enum 그대로다. 현재 값은 `pgProviderSchema`의 값이고
8680
+ * 화면은 모르는 값을 원문 그대로 보여 준다
8681
+ */
8682
+ const pgProviderResponseSchema = z.string().describe("PG 식별자(`pgProviderSchema`의 값). 모르는 값이 와도 응답 파싱이 깨지지 않는다");
8160
8683
  /**
8161
8684
  * 간편결제 전용 PG — 결제수단이 간편결제 하나이고 간편결제사가 PG 자신이다(`kakaopay` → `KAKAOPAY`).
8162
8685
  * 이 PG는 `easyPayProviders` 설정 없이 결제 옵션이 하나(`EASY_PAY` + 그 간편결제사) 나온다
8163
8686
  */
8164
8687
  const DEDICATED_EASY_PAY_PROVIDER = {
8165
8688
  kakaopay: "KAKAOPAY",
8166
- naverpay: "NAVERPAY"
8689
+ naverpay: "NAVERPAY",
8690
+ paypal: "PAYPAL"
8167
8691
  };
8168
8692
  const pgPaymentMethodSchema = z.enum([
8169
8693
  "CARD",
@@ -8180,7 +8704,8 @@ const easyPayProviderSchema = z.enum([
8180
8704
  "NAVERPAY",
8181
8705
  "KAKAOPAY",
8182
8706
  "TOSSPAY",
8183
- "PAYCO"
8707
+ "PAYCO",
8708
+ "PAYPAL"
8184
8709
  ]);
8185
8710
  /**
8186
8711
  * 응답에 실리는 간편결제사 — 서버가 간편결제사를 추가해도 파싱이 깨지지 않게 문자열로 받는다
@@ -8246,6 +8771,30 @@ const naverPayCredentialsInputSchema = z.object({
8246
8771
  chainId: z.string().trim().min(4).max(100).describe("네이버페이 Chain ID. 공개 값 — 결제창과 API 요청에 쓰인다"),
8247
8772
  clientSecret: secretInput().optional().describe("Client Secret. 비밀 값. 최초 연결 시 필수, 수정 시 생략하면 기존 값을 유지한다")
8248
8773
  });
8774
+ /**
8775
+ * PayPal이 받는 통화 중 sayren이 여는 것(이슈 #131 설계 §3b) — PayPal 통화 코드(https://developer.paypal.com/api/rest/reference/currency-codes/) ∩ 통화표
8776
+ * − 원화(PayPal이 받지 않는다) − CNY·MYR(현지 계정 전용) − TWD(부분 환불 소수 문제, 설계 Q4)
8777
+ */
8778
+ const PAYPAL_CURRENCIES = [
8779
+ "USD",
8780
+ "EUR",
8781
+ "JPY",
8782
+ "GBP",
8783
+ "HKD",
8784
+ "SGD",
8785
+ "AUD",
8786
+ "CAD",
8787
+ "THB",
8788
+ "PHP",
8789
+ "NZD",
8790
+ "CHF"
8791
+ ];
8792
+ const payPalCredentialsInputSchema = z.object({
8793
+ clientId: z.string().trim().min(10).max(200).describe("PayPal REST 앱의 Client ID(테스트 세트는 샌드박스 앱). 공개 값"),
8794
+ currencies: z.array(z.enum(PAYPAL_CURRENCIES)).min(1).max(PAYPAL_CURRENCIES.length).describe("받는 통화 — PayPal 계정에 열어 둔 통화를 고른다. 결제 세션 통화가 여기 있는 주문서에만 PayPal 옵션이 나온다(원화는 받지 않는다)"),
8795
+ webhookId: z.string().trim().min(1).max(100).nullable().optional().describe("PayPal 앱에 등록한 웹훅의 ID(선택). 주면 서버 통지의 서명을 검증해 결제 확인을 앞당긴다. 생략·null이면 통지를 받지 않고 주기 확인만 한다"),
8796
+ clientSecret: secretInput().optional().describe("Secret. 비밀 값. 최초 연결 시 필수, 수정 시 생략하면 기존 값을 유지한다")
8797
+ });
8249
8798
  const upsertEnvironment = () => pgEnvironmentSchema.describe("저장할 자격 증명 세트. PG마다 `TEST`(샌드박스)·`LIVE`(실결제) 세트를 따로 둔다. 어느 세트로 결제할지는 이 값이 아니라 샌드박스 스위치(`sandboxMode`)가 정한다");
8250
8799
  const upsertTossPaymentsProviderRequestSchema = z.object({
8251
8800
  environment: upsertEnvironment(),
@@ -8263,6 +8812,10 @@ const upsertNaverPayProviderRequestSchema = z.object({
8263
8812
  environment: upsertEnvironment(),
8264
8813
  credentials: naverPayCredentialsInputSchema
8265
8814
  });
8815
+ const upsertPayPalProviderRequestSchema = z.object({
8816
+ environment: upsertEnvironment(),
8817
+ credentials: payPalCredentialsInputSchema
8818
+ });
8266
8819
  const updatePaymentProviderRequestSchema = z.object({
8267
8820
  enabled: z.boolean().optional().describe("사용 여부. 켜려면 활성 환경(샌드박스면 TEST, 아니면 LIVE) 자격 증명이 모두 저장돼 있어야 한다(`PAYMENT_PROVIDER_INCOMPLETE`)"),
8268
8821
  sandboxMode: z.boolean().optional().describe("샌드박스 스위치. `true`면 새 결제에 TEST 세트를 쓴다(항상 허용). `false`(라이브 전환)는 라이브 개방 조건을 모두 충족해야 한다(`LIVE_GATE_NOT_MET`)"),
@@ -8288,6 +8841,11 @@ const publicConfigSchema = z.union([
8288
8841
  z.object({
8289
8842
  clientId: z.string(),
8290
8843
  chainId: z.string()
8844
+ }),
8845
+ z.object({
8846
+ clientId: z.string(),
8847
+ currencies: z.array(z.string()),
8848
+ webhookId: z.string().nullable()
8291
8849
  })
8292
8850
  ]);
8293
8851
  const verificationSchema = z.object({
@@ -8297,7 +8855,7 @@ const verificationSchema = z.object({
8297
8855
  });
8298
8856
  const paymentCredentialSetSchema = z.object({
8299
8857
  environment: pgEnvironmentSchema,
8300
- publicConfig: publicConfigSchema.describe("공개 값. 토스페이먼츠는 `{clientKey}`, 포트원은 `{storeId, channels}`, 카카오페이는 `{cid}`, 네이버페이는 `{clientId, chainId}`"),
8858
+ publicConfig: publicConfigSchema.describe("공개 값. 토스페이먼츠는 `{clientKey}`, 포트원은 `{storeId, channels}`, 카카오페이는 `{cid}`, 네이버페이는 `{clientId, chainId}`, PayPal은 `{clientId, currencies, webhookId}`"),
8301
8859
  secrets: z.array(maskedSecretSchema).describe("비밀 값의 저장 여부와 마스킹. 평문은 어떤 응답에도 나오지 않는다"),
8302
8860
  lastVerification: verificationSchema.nullable().describe("이 세트의 마지막 연결 테스트 결과. 세트를 바꾸면 초기화된다"),
8303
8861
  updatedAt: z.string()
@@ -8310,7 +8868,7 @@ const liveGateConditionCodeSchema = z.enum([
8310
8868
  "PLATFORM_LIVE_ENABLED",
8311
8869
  "NOT_TEMPLATE_STORE",
8312
8870
  "NOT_DEVELOPMENT_STORE"
8313
- ]).describe("라이브 개방 조건. `TEST_CONNECTION`=TEST 세트 연결 테스트 성공, `SANDBOX_PAYMENT`=현재 TEST 세트로 샌드박스 결제 1건 승인, `SANDBOX_REFUND`=그 샌드박스 결제의 환불 1건 성공, `LIVE_CONNECTION`=LIVE 세트 연결 테스트 성공, `PLATFORM_LIVE_ENABLED`=플랫폼이 실결제를 열어 둠, `NOT_TEMPLATE_STORE`=템플릿 상점이 아님(템플릿 상점에만 싣고 늘 미충족), `NOT_DEVELOPMENT_STORE`=앱 개발 상점이 아님(앱 개발 상점에만 싣고 늘 미충족)");
8871
+ ]).describe("라이브 개방 조건. `TEST_CONNECTION`=TEST 세트 연결 테스트 성공, `SANDBOX_PAYMENT`=현재 TEST 세트로 샌드박스 결제 1건 승인, `SANDBOX_REFUND`=그 샌드박스 결제의 환불 1건 성공, `LIVE_CONNECTION`=LIVE 세트 연결 테스트 성공, `PLATFORM_LIVE_ENABLED`=플랫폼이 실결제를 열어 둠(늘 충족), `NOT_TEMPLATE_STORE`=템플릿 상점이 아님(템플릿 상점에만 싣고 늘 미충족), `NOT_DEVELOPMENT_STORE`=앱 개발 상점이 아님(앱 개발 상점에만 싣고 늘 미충족)");
8314
8872
  const liveGateConditionSchema = z.object({
8315
8873
  code: liveGateConditionCodeSchema,
8316
8874
  met: z.boolean().describe("충족 여부"),
@@ -8322,12 +8880,12 @@ const liveGateSchema = z.object({
8322
8880
  openedAt: z.string().nullable().describe("마지막으로 라이브로 전환한 시각. 없으면 null")
8323
8881
  });
8324
8882
  /**
8325
- * 409 `LIVE_GATE_NOT_MET`·`LIVE_PAYMENTS_DISABLED`의 `ApiError.details` 형태.
8883
+ * 409 `LIVE_GATE_NOT_MET`의 `ApiError.details` 형태.
8326
8884
  * 응답 파싱용이라 관대하다 — 알 수 없는 키는 버리고, 형태가 다르면 safeParse 실패로 처리한다.
8327
8885
  */
8328
8886
  const liveGateErrorDetailsSchema = z.object({ conditions: z.array(liveGateConditionSchema).describe("라이브 개방 조건별 충족 여부 (순서 고정)") });
8329
8887
  const paymentProviderSchema = z.object({
8330
- provider: pgProviderSchema,
8888
+ provider: pgProviderResponseSchema,
8331
8889
  displayName: z.string().describe("표시 이름 (토스페이먼츠·포트원)"),
8332
8890
  connected: z.boolean().describe("자격 증명이 저장돼 있는가"),
8333
8891
  enabled: z.boolean().describe("결제에 사용 중인가"),
@@ -8377,14 +8935,14 @@ const paymentFailureWarningSchema = z.object({
8377
8935
  });
8378
8936
  const paymentSettingsSchema = z.object({
8379
8937
  checkoutOrigins: z.array(z.string()).describe("결제 도메인 — 결제를 마친 구매자가 돌아올 스토어프론트 origin 목록"),
8380
- providers: z.array(paymentProviderSchema).describe("연결된 PG(우선순위순)와 연결되지 않은 토스페이먼츠·포트원. 카카오페이·네이버페이는 연결했을 때만 여기에 온다(이 PG를 모르는 이전 SDK가 응답을 읽을 수 있게). 연결할 수 있는 PG 전체는 `connectableProviders`다"),
8938
+ providers: z.array(paymentProviderSchema).describe("연결된 PG(우선순위순)와 연결되지 않은 토스페이먼츠·포트원. 그 밖의 PG(카카오페이·네이버페이 등)는 연결했을 때만 여기에 온다(이 PG를 모르는 이전 SDK가 응답을 읽을 수 있게). 연결할 수 있는 PG 전체는 `connectableProviders`다"),
8381
8939
  connectableProviders: z.array(paymentProviderSchema).optional().default(() => []).describe("연결되지 않은 PG 전체(카카오페이·네이버페이 포함). 서버는 항상 싣는다. 이 필드가 없는 이전 서버 응답은 기본값(빈 배열)으로 읽는다"),
8382
8940
  environment: pgEnvironmentSchema.nullable().optional().default(null).describe("지금 결제를 시작하면 쓰는 결제 환경. 사용 가능한 PG 중 하나라도 라이브면 `LIVE`(샌드박스 PG는 제외), 아니면 `TEST`. 사용 가능한 PG가 없으면 null. 서버는 항상 싣는다. 이 필드가 없는 이전 서버 응답은 기본값(null)으로 읽는다"),
8383
8941
  candidates: z.array(z.string()).optional().default(() => []).describe("지금 결제를 시작하면 쓰는 PG, 우선순위순(`tosspayments`·`portone`). 비어 있으면 구매자가 결제할 수 없다. 빠진 PG의 사유는 `providers[].routingExclusion` — 후보가 아닌 PG에는 항상 사유 코드를 붙인다. 서버는 항상 싣는다. 이 필드가 없는 이전 서버 응답은 기본값(빈 배열)으로 읽는다"),
8384
8942
  warnings: z.array(paymentFailureWarningSchema).optional().default(() => []).describe("최근 24시간 안에 같은 PG·결제수단·간편결제사가 가맹점 설정 문제로 3번 이상 실패한 조합, 마지막 실패가 최근인 순. 판정 규칙은 서버가 정하고 바뀔 수 있다. 서버는 항상 싣는다. 이 필드가 없는 이전 서버 응답은 기본값(빈 배열)으로 읽는다")
8385
8943
  });
8386
8944
  const paymentProviderVerificationSchema = z.object({
8387
- provider: pgProviderSchema,
8945
+ provider: pgProviderResponseSchema,
8388
8946
  environment: pgEnvironmentSchema.describe("연결 테스트한 자격 증명 세트"),
8389
8947
  result: pgVerificationResultSchema,
8390
8948
  message: z.string().nullable().describe("실패 사유 또는 참고 메시지"),
@@ -8415,20 +8973,27 @@ const salesTotalsSchema = z.object({
8415
8973
  });
8416
8974
  const salesReportRowSchema = salesTotalsSchema.extend({
8417
8975
  date: z.string().nullable().describe("일자 (YYYY-MM-DD, Asia/Seoul). groupBy=DAY일 때만 값"),
8418
- provider: pgProviderSchema.nullable().describe("PG. groupBy에 PROVIDER가 포함될 때만 값"),
8976
+ provider: pgProviderResponseSchema.nullable().describe("PG. groupBy에 PROVIDER가 포함될 때만 값"),
8419
8977
  method: pgPaymentMethodSchema.nullable().describe("실제 결제수단(PG가 보고한 수단, 모르면 요청 수단). groupBy에 METHOD가 포함될 때만 값. 관리 주문 API의 method는 호환용이며 간편결제를 CARD로 표시한다. 실제 수단은 approvedMethod를 본다")
8420
8978
  });
8979
+ /** 통화별 매출(이슈 #130) — 환산하지 않는다. 금액은 그 통화의 최소 단위다 */
8980
+ const salesReportCurrencySchema = z.object({
8981
+ currency: z.string().describe("결제 통화(ISO 4217)"),
8982
+ summary: salesTotalsSchema.describe("이 통화의 기간 전체 합계"),
8983
+ rows: z.array(salesReportRowSchema).describe("이 통화의 집계 행(`groupBy` 기준)")
8984
+ });
8421
8985
  const salesReportSchema = z.object({
8422
8986
  from: z.string(),
8423
8987
  to: z.string(),
8424
8988
  timezone: z.literal("Asia/Seoul"),
8425
- currency: z.literal("KRW"),
8989
+ currency: z.literal("KRW").describe("`summary`·`rows`의 통화. 기본 통화(원화) 결제만 집계한다. 외화 결제는 `byCurrency`에 있다"),
8426
8990
  groupBy: salesReportGroupBySchema,
8427
- provider: pgProviderSchema.nullable().describe("적용된 PG 필터"),
8991
+ provider: pgProviderResponseSchema.nullable().describe("적용된 PG 필터"),
8428
8992
  method: pgPaymentMethodSchema.nullable().describe("적용된 결제수단 필터"),
8429
8993
  includeTest: z.boolean().describe("테스트 결제(샌드박스 결제)를 집계에 포함했는가"),
8430
8994
  summary: salesTotalsSchema.describe("기간 전체 합계"),
8431
- rows: z.array(salesReportRowSchema).describe("집계 행. 활동이 없는 날짜·PG는 생략된다")
8995
+ rows: z.array(salesReportRowSchema).describe("집계 행. 활동이 없는 날짜·PG는 생략된다"),
8996
+ byCurrency: z.array(salesReportCurrencySchema).optional().default([]).describe("통화별 매출(이슈 #130) — 활동이 있는 통화마다 한 항목이고 기본 통화(KRW)도 포함한다. 통화 사이는 환산하지 않는다. 옛 서버 응답은 빈 목록")
8432
8997
  });
8433
8998
  /**
8434
8999
  * 결제 내역 — 결제 건(세션) 단위 공개 상태. 주문 단위 상태와 다르다.
@@ -8470,7 +9035,7 @@ const cashReceiptSchema = z.object({
8470
9035
  identityNumberMasked: z.string().describe("가린 식별 번호 (예: 010****5678). 원문은 조회할 수 없다"),
8471
9036
  amount: z.number().int().describe("발급해야 할 금액 = 결제 금액 − 환불 완료 금액. 승인 전에는 결제 금액"),
8472
9037
  issuedAmount: z.number().int().describe("PG에 현재 발급돼 있는 금액. 취소됐거나 발급 전이면 0"),
8473
- provider: pgProviderSchema.nullable().describe("발급 PG — 결제를 승인한 PG. 승인 전에는 null"),
9038
+ provider: pgProviderResponseSchema.nullable().describe("발급 PG — 결제를 승인한 PG. 승인 전에는 null"),
8474
9039
  issueNumber: z.string().nullable().describe("현금영수증 승인 번호"),
8475
9040
  receiptUrl: z.string().nullable().describe("현금영수증 확인 주소"),
8476
9041
  issuedAt: z.string().nullable().describe("최근 발급 시각 (ISO 8601)"),
@@ -8490,7 +9055,7 @@ const paymentRecordSchema = z.object({
8490
9055
  amount: z.number().int().describe("결제 금액"),
8491
9056
  refundedAmount: z.number().int().describe("환불 완료 금액 합계. 실패한 환불은 빼고 센다"),
8492
9057
  heldRefundAmount: z.number().int().optional().default(0).describe("환불 대기 금액 합계(#115) — 주문만 취소하고 아직 환불하지 않은 몫. 결제 상세에서 환불 처리한다"),
8493
- provider: pgProviderSchema.nullable().describe("승인한 PG. 승인 전에 끝났으면 마지막 시도의 PG"),
9058
+ provider: pgProviderResponseSchema.nullable().describe("승인한 PG. 승인 전에 끝났으면 마지막 시도의 PG"),
8494
9059
  method: pgPaymentMethodSchema.nullable().describe("실제 결제수단. 모르면 요청 수단"),
8495
9060
  easyPayProvider: easyPayProviderResponseSchema.nullable().optional().default(null).describe("간편결제사. `method`가 `EASY_PAY`일 때만 값이 있고, PG가 알려 주지 않았으면 요청한 간편결제사다. 그 밖의 결제수단과 간편결제 이전 결제는 null. 서버는 항상 싣는다. 현재 값은 `NAVERPAY`·`KAKAOPAY`·`TOSSPAY`·`PAYCO`이고 값이 추가될 수 있어 문자열로 받는다"),
8496
9061
  environment: pgEnvironmentSchema.nullable().describe("결제 환경"),
@@ -8510,7 +9075,7 @@ const paymentAttemptRecordSchema = z.object({
8510
9075
  attemptId: z.string(),
8511
9076
  pgOrderId: z.string().nullable().optional().default(null).describe("PG에 보낸 주문번호(이슈 #107) — 토스페이먼츠 orderId·포트원 paymentId. 새 시도는 `{주문번호}-{시도 순번 2자리}`이고, 번호 체계 이전 시도는 시도 id(`attemptId`)와 같습니다. PG 관리자 화면에서 결제를 찾을 때 씁니다"),
8512
9077
  sequence: z.number().int().describe("결제 건 안에서의 순번 (1부터)"),
8513
- provider: pgProviderSchema,
9078
+ provider: pgProviderResponseSchema,
8514
9079
  status: paymentAttemptStatusSchema,
8515
9080
  method: pgPaymentMethodSchema.describe("주문서에서 고른 결제수단"),
8516
9081
  easyPayProvider: easyPayProviderResponseSchema.nullable().optional().default(null).describe("주문서에서 고른 간편결제사. 간편결제가 아니면 null. 서버는 항상 싣는다(값이 추가될 수 있어 문자열)"),
@@ -8559,7 +9124,7 @@ const paymentListQuerySchema = z.object({
8559
9124
  const setPlatformTestKeysRequestSchema = z.object({ enabled: z.boolean().describe("`true`면 sayren 지정 테스트 키를 TEST 세트로 저장하고 PG를 켠다. `false`면 고정만 푼다(TEST 세트는 그대로)") });
8560
9125
  /** 결제 상태 PG 한 줄 — 비밀 값·공개 키 없이 연결·사용·환경·테스트모드 키만 */
8561
9126
  const paymentStatusProviderSchema = z.object({
8562
- provider: pgProviderSchema,
9127
+ provider: pgProviderResponseSchema,
8563
9128
  displayName: z.string(),
8564
9129
  connected: z.boolean().describe("자격 증명이 저장돼 있는가"),
8565
9130
  enabled: z.boolean().describe("결제에 사용 중인가"),
@@ -8583,12 +9148,16 @@ const orderSummarySchema = z.object({
8583
9148
  representativeStatus: orderItemStatusSchema,
8584
9149
  progressStatus: orderItemStatusSchema.optional().describe("진행 중 주문상품 가운데 가장 앞 단계(취소 제외, 모두 취소면 CANCELED, #115). 섞인 주문에서 아직 기다리는 단계다. 서버는 항상 싣는다"),
8585
9150
  orderedAt: z.string(),
9151
+ currency: z.string().optional().describe("주문 통화(ISO 4217, 이슈 #130). 금액 필드는 모두 이 통화의 최소 단위다. 외화 주문이 생기면 이 값을 확인한다. 없으면 KRW다. 서버는 항상 싣는다"),
8586
9152
  testPayment: z.boolean().describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았습니다. 상품을 발송하지 않도록 주의하십시오")
8587
9153
  });
8588
9154
  const shippingAddressSchema = z.object({
8589
9155
  receiverName: z.string(),
8590
9156
  phone: z.string(),
8591
- zipCode: z.string(),
9157
+ zipCode: z.string().describe("우편번호. 해외 배송지는 그 나라 우편번호이고 없으면 빈 문자열이다"),
9158
+ countryCode: z.string().optional().describe("배송 국가(이슈 #130). 없으면 국내(KR)다"),
9159
+ region: z.string().nullish().describe("해외 배송지의 1차 행정 구역"),
9160
+ city: z.string().nullish().describe("해외 배송지의 도시. 국내 배송지는 없다"),
8592
9161
  address1: z.string(),
8593
9162
  address2: z.string().nullish(),
8594
9163
  deliveryMemo: z.string().nullish(),
@@ -8682,6 +9251,7 @@ const orderSchema = z.object({
8682
9251
  paidAt: z.string().nullable(),
8683
9252
  cashReceipt: cashReceiptSchema.nullable().optional().default(null).describe("현금영수증. 구매자가 계좌이체·가상계좌 결제에서 신청했을 때만 있고 그 밖에는 null. 서버는 항상 싣는다")
8684
9253
  }),
9254
+ currency: z.string().optional().describe("주문 통화(ISO 4217, 이슈 #130). 금액 필드는 모두 이 통화의 최소 단위다. 외화 주문이 생기면 이 값을 확인한다. 없으면 KRW다. 서버는 항상 싣는다"),
8685
9255
  testPayment: z.boolean().describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았습니다. 상품을 발송하지 않도록 주의하십시오"),
8686
9256
  items: z.array(orderItemSchema)
8687
9257
  });
@@ -9395,6 +9965,23 @@ function createStoreClient(options) {
9395
9965
  saveFromProduct: (body) => storeHttp.request("POST", "/saved-option-sets/from-product", savedOptionSetFromProductResultSchema, { body: savedOptionSetFromProductRequestSchema.parse(body) })
9396
9966
  },
9397
9967
  /**
9968
+ * 상품정보제공 고시 품목군(이슈 #135) — 플랫폼 코드 표. 현재 버전만 싣는다. 권한은 상품 조회(`product:r`)다
9969
+ */
9970
+ infoSchemas: { list: (params) => storeHttp.request("GET", "/info-schemas", z.array(infoSchemaSchema), { query: params }) },
9971
+ /** 플랫폼 코드 묶음(이슈 #135) — 인증 종류·대상·면제 사유(`PLATFORM_CODE_SETS`). 권한은 상품 조회(`product:r`)다 */
9972
+ codes: { list: (setId) => storeHttp.request("GET", path`/codes/${setId}`, z.array(platformCodeSchema)) },
9973
+ /**
9974
+ * 안내 섹션(이슈 #135) — 여러 상품이 같이 쓰는 글. 상품은 `infoSectionIds`로 연결만 하고, 섹션을 고치면 연결 상품 전체가 바뀐다.
9975
+ * 지우면 연결도 풀린다. 권한은 상품과 같다(`product:r`·`product:rw`)
9976
+ */
9977
+ infoSections: {
9978
+ list: () => storeHttp.request("GET", "/info-sections", z.array(infoSectionSchema)),
9979
+ get: (infoSectionId) => storeHttp.request("GET", path`/info-sections/${infoSectionId}`, infoSectionSchema),
9980
+ create: (body) => storeHttp.request("POST", "/info-sections", infoSectionSchema, { body: infoSectionRequestSchema.parse(body) }),
9981
+ update: (infoSectionId, body) => storeHttp.request("PUT", path`/info-sections/${infoSectionId}`, infoSectionSchema, { body: infoSectionRequestSchema.parse(body) }),
9982
+ remove: (infoSectionId) => storeHttp.requestVoid("DELETE", path`/info-sections/${infoSectionId}`)
9983
+ },
9984
+ /**
9398
9985
  * 컬렉션 (이슈 #83) — 상품을 어디에 보여 줄지 정하는 묶음(다대다). 권한은 카테고리와 같다(`category:r`·`category:rw`).
9399
9986
  * 쓰기마다 `revision`이 오른다. 수정 본문에 읽은 `revision`을 주면 그 사이 다른 수정이 있을 때 409 `COLLECTION_CHANGED`다.
9400
9987
  */
@@ -9641,7 +10228,7 @@ listHistory: (params) => storeHttp.request("GET", "/points/history", pageSchema(
9641
10228
  listPointHistory: (customerId, params) => storeHttp.request("GET", path`/customers/${customerId}/points/history`, pageSchema(pointEntrySchema), { query: params }),
9642
10229
  /**
9643
10230
  * `POST /v1/customers/{customerId}/points/adjustments` (201) — 스코프 `promotion:rw`. 양수 지급, 음수 차감. `idempotencyKey`가 필수다.
9644
- * 에러: 409 `POINT_BALANCE_INSUFFICIENT`·`POINTS_UNAVAILABLE`, 400 `POINT_EXPIRY_REQUIRED`. 에이전트 요청은 승인 대상이다
10231
+ * 에러: 409 `POINT_BALANCE_INSUFFICIENT`, 400 `POINT_EXPIRY_REQUIRED`. 에이전트 요청은 승인 대상이다
9645
10232
  */
9646
10233
  adjustPoints: (customerId, body, idempotencyKey) => storeHttp.request("POST", path`/customers/${customerId}/points/adjustments`, pointAdjustmentResultSchema, {
9647
10234
  body: pointAdjustmentRequestSchema.parse(body),
@@ -9786,6 +10373,11 @@ get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, {
9786
10373
  */
9787
10374
  upsertNaverPay: (body) => storeHttp.request("PUT", "/store/payment-providers/naverpay", paymentProviderSchema, { body: upsertNaverPayProviderRequestSchema.parse(body) }),
9788
10375
  /**
10376
+ * `PUT /v1/store/payment-providers/paypal` — PayPal(직접 연동) 자격 증명 세트 저장. 규칙·에러는 `upsertTossPayments`와 같다
10377
+ * (가맹점 식별자는 `clientId`, 비밀 필드는 `clientSecret`). 결제 옵션은 PayPal 간편결제 하나이고 `currencies`의 외화 주문서에만 나온다.
10378
+ */
10379
+ upsertPayPal: (body) => storeHttp.request("PUT", "/store/payment-providers/paypal", paymentProviderSchema, { body: upsertPayPalProviderRequestSchema.parse(body) }),
10380
+ /**
9789
10381
  * `PATCH /v1/store/payment-providers/{provider}` — 사용 여부(`enabled`)·샌드박스 스위치(`sandboxMode`) 변경.
9790
10382
  * 하나 이상 보내야 한다(아니면 요청 전에 ZodError). 검증을 모두 통과해야 한 번에 적용된다(부분 적용 없음).
9791
10383
  * 끈 PG로 승인된 결제의 환불은 계속 그 PG로 간다.
@@ -9795,14 +10387,13 @@ get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, {
9795
10387
  * - 409 `PAYMENT_PROVIDER_INCOMPLETE`: 켜려는데 활성 환경(샌드박스면 TEST, 아니면 LIVE) 세트가 없거나 불완전
9796
10388
  * - 409 `LIVE_GATE_NOT_MET`: `sandboxMode: false`(라이브 전환)인데 개방 조건 미충족. `ApiError.details`가
9797
10389
  * `{ conditions: LiveGateCondition[] }`(조건별 `met`)이다. `liveGateErrorDetailsSchema`로 파싱한다
9798
- * - 409 `LIVE_PAYMENTS_DISABLED`: 플랫폼 실결제 스위치만 미충족. `details`는 위와 같다
9799
10390
  *
9800
10391
  * `sandboxMode: true`는 항상 허용되고 즉시 실결제가 멈춘다.
9801
10392
  */
9802
10393
  updateProvider: updatePaymentProvider,
9803
10394
  /**
9804
10395
  * 샌드박스 스위치만 바꾼다 — `updateProvider(provider, { sandboxMode })`와 같다.
9805
- * `false`(라이브 전환)는 409 `LIVE_GATE_NOT_MET`·`LIVE_PAYMENTS_DISABLED`(둘 다 `ApiError.details.conditions`)가 날 수 있다.
10396
+ * `false`(라이브 전환)는 409 `LIVE_GATE_NOT_MET`(`ApiError.details.conditions`)가 날 수 있다.
9806
10397
  */
9807
10398
  setSandboxMode: (provider, sandboxMode) => updatePaymentProvider(provider, { sandboxMode }),
9808
10399
  /**
@@ -9984,6 +10575,14 @@ list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, {
9984
10575
  headers: idempotency(idempotencyKey)
9985
10576
  })
9986
10577
  },
10578
+ /** 판매 권역(이슈 #130) — 국가·통화·도메인. 쓰기는 다중 통화가 켜진 상점에서만 된다 */
10579
+ markets: {
10580
+ list: () => storeHttp.request("GET", "/markets", z.array(marketSchema)),
10581
+ get: (marketId) => storeHttp.request("GET", path`/markets/${marketId}`, marketSchema),
10582
+ create: (body) => storeHttp.request("POST", "/markets", marketSchema, { body: createMarketRequestSchema.parse(body) }),
10583
+ update: (marketId, body) => storeHttp.request("PATCH", path`/markets/${marketId}`, marketSchema, { body: updateMarketRequestSchema.parse(body) }),
10584
+ archive: (marketId) => storeHttp.requestVoid("DELETE", path`/markets/${marketId}`)
10585
+ },
9987
10586
  pickupLocations: {
9988
10587
  list: () => storeHttp.request("GET", "/pickup-locations", z.array(pickupLocationSchema)),
9989
10588
  create: (body) => storeHttp.request("POST", "/pickup-locations", pickupLocationSchema, { body: pickupLocationRequestSchema.parse(body) }),
@@ -10024,7 +10623,7 @@ list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, {
10024
10623
  getStoreTemplate: () => storeHttp.request("GET", "/storefront/template", storeTemplateSchema),
10025
10624
  /** `PUT /v1/storefront/template` — 템플릿 이름·소개·썸네일을 바꾼다(템플릿 상점만) */
10026
10625
  updateStoreTemplate: (body) => storeHttp.request("PUT", "/storefront/template", storeTemplateSchema, { body: updateStoreTemplateRequestSchema.parse(body) }),
10027
- /** `GET /v1/storefront/site` — 스위치 상태와 현재 사이트(없으면 `site: null`) */
10626
+ /** `GET /v1/storefront/site` — 호스팅 설정과 현재 사이트(없으면 `site: null`) */
10028
10627
  get: () => storeHttp.request("GET", "/storefront/site", storefrontHostingSchema),
10029
10628
  /** `GET /v1/storefront/slug-availability?slug=` — 슬러그를 쓸 수 있는가 */
10030
10629
  checkSlug: (slug) => storeHttp.request("GET", "/storefront/slug-availability", storefrontSlugAvailabilitySchema, { query: { slug } }),
@@ -10160,7 +10759,7 @@ listPublic: () => storeHttp.request("GET", "/public/plans", publicPlansSchema) }
10160
10759
  getPointPolicy: () => storeHttp.request("GET", "/store/point-policy", storePointPolicySchema),
10161
10760
  /**
10162
10761
  * `PUT /v1/store/point-policy` — 스코프 `promotion:rw`. 준 항목만 바꾼다. 에이전트 요청은 승인 대상이다.
10163
- * 에러: 409 `POINTS_UNAVAILABLE`(준비 중) · 400 `POINT_EXPIRY_REQUIRED`(리뷰 적립을 켜는데 유효 기간이 없음)
10762
+ * 에러: 400 `POINT_EXPIRY_REQUIRED`(리뷰 적립을 켜는데 유효 기간이 없음)
10164
10763
  */
10165
10764
  updatePointPolicy: (body) => storeHttp.request("PUT", "/store/point-policy", storePointPolicySchema, { body: updatePointPolicyRequestSchema.parse(body) }),
10166
10765
  listMembers: () => storeHttp.request("GET", "/store/members", z.array(storeMemberSchema)),
@@ -10513,4 +11112,4 @@ function createStoreSession(options) {
10513
11112
  };
10514
11113
  }
10515
11114
  //#endregion
10516
- export { AI_AGENT_NOTES_DIR, AI_AGENT_PHASES, AI_DESIGN_BOARDS_MAX, AI_DESIGN_BOARD_FILE_PATTERN, AI_DESIGN_BOARD_KINDS, AI_DESIGN_CANVAS_PATH, AI_DESIGN_CONFIRM_APPROVE, AI_DESIGN_DIR, AI_DESIGN_VIEWPORTS, AI_MESSAGE_MAX_ATTACHMENTS, AI_MESSAGE_MAX_CHARS, AI_RUN_ACTIVE_STATUSES, AI_RUN_FILE_CHANGES_RETENTION_DAYS, AI_SETUP_CONFIRM_APPROVE, AI_TODOS_MAX, AI_TODO_STATUSES, APPROVAL_ALREADY_DECIDED_CODE, APPROVAL_REQUIRED_CODE, APP_CAPABILITIES, APP_DEPLOY_KEY_PATTERN, APP_DEPLOY_KEY_PREFIX, APP_EVENTS_MAX, APP_EVENT_SCOPES, APP_EVENT_TYPES, APP_FLOW_EVENT_PATTERN, APP_FLOW_ITEMS_MAX, APP_FLOW_NOTIFICATION_PATTERN, APP_HANDLE_PATTERN, APP_HTTP_KEY_PATTERN, APP_ICON_CONTENT_TYPES, APP_ICON_MAX_BYTES, APP_ICON_MIN_PX, APP_LIFECYCLE_EVENT_TYPES, APP_NETWORK_DENIED_SUFFIXES, APP_NETWORK_HOSTS_MAX, APP_PUBLIC_HTTP_MAX, APP_README_MAX_BYTES, APP_RESERVED_HANDLES, APP_SCHEDULES_MAX, APP_SCHEDULE_INTERVALS, APP_SCHEDULE_NAME_PATTERN, APP_SECRETS_MAX, APP_SECRET_NAME_PATTERN, APP_SECRET_PATTERNS, APP_SERVER_BUNDLE_MAX_GZIP_BYTES, APP_SETTINGS_MAX_FIELDS, APP_SETTING_FIELD_TYPES, APP_SETTING_KEY_PATTERN, APP_STORAGE_KEY_PATTERN, APP_STORAGE_MAX_BYTES, APP_STORAGE_MAX_KEYS, APP_TOOL_NAME_PATTERN, APP_UI_MAX_BYTES, APP_UI_MAX_FILES, ApiError, ApprovalPendingError, BRAND_BRIEF_MAX_REFERENCES, BUSINESS_INFO_MAX_LENGTH, BUSINESS_NUMBER_PATTERN, CASH_RECEIPT_STATUS_VALUES, COLLECTION_BEST_SELLING_DAYS, COLLECTION_PREVIEW_SIZE, COLLECTION_PRODUCT_SORTS, COLLECTION_SALES_SORT_DEFAULT_DAYS, COLLECTION_SLUG_PATTERN, COLLECTION_TYPES, COUPON_CODE_PATTERN, COUPON_CONDITIONS_DEFAULTS, COUPON_TARGET_ALL, COUPON_TARGET_LIST_MAX, CUSTOM_INPUT_FORBIDDEN_WORDS, CUSTOM_INPUT_TYPES, DEDICATED_EASY_PAY_PROVIDER, FULFILLMENT_METHODS, FULFILLMENT_METHODS_BY_TYPE, FULFILLMENT_METHOD_RULES, FULFILLMENT_RULES, INSTALLABLE_SCOPES, KAKAOPAY_TEST_CID, KNOWN_WEBHOOK_EVENT_TYPES, MAX_ADDON_GROUPS, MAX_ANALYTICS_ALLOWED_ORIGINS, MAX_AUTO_TRANSITION_DAYS, MAX_CALENDAR_DAYS, MAX_COLLECTIONS, MAX_COLLECTION_BEST_SELLING_TOP, MAX_COLLECTION_CREATED_WITHIN_DAYS, MAX_COLLECTION_DESCRIPTION, MAX_COLLECTION_PRODUCTS, MAX_COLLECTION_PRODUCTS_PER_ADD, MAX_COLLECTION_RULES, MAX_COLLECTION_RULE_CATEGORIES, MAX_COLLECTION_TITLE, MAX_CUSTOM_INPUTS, MAX_CUSTOM_INPUT_LENGTH, MAX_INVENTORY_OPERATION_LINES, MAX_OPTION_GROUPS, MAX_PICKUP_LOCATIONS, MAX_PRODUCT_IMAGES, MAX_SAVED_OPTION_SETS, MAX_SAVED_OPTION_SET_NAME, MAX_STAY_NIGHTS, MAX_VALUES_PER_GROUP, MAX_VARIANTS, MCP_TELEMETRY_MAX_RESULTS, MIN_PAYMENT_AMOUNT, NON_INSTALLABLE_SCOPES, NO_COUPON_SETTLEMENT, NO_SHIPPING_BUNDLE_KEY, PAYMENT_ROUTING_EXCLUSION_CODES, POINT_ADJUSTMENT_MAX, POINT_EARN_RATE_BP_MAX, POINT_ENTRY_TYPES, POINT_EXPIRY_DAYS_MAX, POINT_EXPIRY_DAYS_MIN, POINT_LOT_SOURCES, POINT_POLICY_DEFAULTS, POINT_REVIEW_REWARD_MAX, POINT_USE_UNITS, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, REFUND_POLICY_DEFAULTS, REFUND_POLICY_DELIVERY_FEE_KEYS, REMOTE_AREA_ZIP_RANGES, RESERVED_STOREFRONT_SLUGS, RESERVED_STORE_CODES, SCOPE_DESCRIPTIONS, SHIPPING_POLICY_DEFAULTS, STARTER_SELLER_TASKS, STARTER_STAGES, STOREFRONT_BLOCKED_PATH_SEGMENTS, STOREFRONT_BUILD_STAGES, STOREFRONT_BUILD_TERMINAL_STATUSES, STOREFRONT_CHECK_TERMINAL_STATUSES, STOREFRONT_CLOSED_SITE_HOLD_DAYS, STOREFRONT_CUSTOM_DOMAIN_LIMIT_DEFAULT, STOREFRONT_DOMAIN_DNS_GRACE_DAYS, STOREFRONT_DOMAIN_DNS_WAIT_DAYS, STOREFRONT_DOMAIN_TXT_LABEL, STOREFRONT_EDIT_ACTIVITY_TIMEOUT_MINUTES, STOREFRONT_EDIT_CAPACITY, STOREFRONT_EDIT_IDLE_MINUTES, STOREFRONT_EDIT_PREVIEW_SUFFIX, STOREFRONT_EDIT_START_STAGES, STOREFRONT_FILE_BATCH_MAX, STOREFRONT_FILE_MAX_BYTES, STOREFRONT_PATH_SEGMENT_PATTERN, STOREFRONT_PLATFORM_DOMAINS, STOREFRONT_PUBLIC_SUFFIXES, STOREFRONT_SEARCH_REGEX_MAX_LENGTH, STOREFRONT_SHOWCASE_SLUG_PREFIX, STOREFRONT_SITE_CREATE_LIMIT, STOREFRONT_SLUG_CHANGE_LIMIT, STOREFRONT_SLUG_CHANGE_WINDOW_DAYS, STOREFRONT_SLUG_HOLD_DAYS, STOREFRONT_SLUG_PATTERN, STOREFRONT_SOURCE_BLOB_BATCH_MAX, STOREFRONT_SOURCE_PART_BYTES, STOREFRONT_WORKSPACE_MAX_BYTES, STOREFRONT_WORKSPACE_MAX_FILES, STORE_CODE_PATTERN, STORE_DRAFT_ATTACHMENT_MAX_BYTES, STORE_DRAFT_MAX_ATTACHMENTS, STORE_DRAFT_RETENTION_DAYS, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, STORE_SHOP_TYPES, TEMPLATE_STORE_LOCKED_BUSINESS_FIELDS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, UPLOAD_PURPOSE_LIMITS, VARIANT_COUNT_WARNING, VARIANT_STOCK_EXCLUSIVE_MESSAGE, WEBHOOK_DEFAULT_TOLERANCE_SEC, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_EVENT_TYPE_HEADER, WEBHOOK_FAILURE_REASONS, WEBHOOK_HEADERS, WEBHOOK_PAYLOAD_EXCERPT_MAX_BYTES, WEBHOOK_RESOURCE_TYPES, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_USER_AGENT, addStorefrontDomainRequestSchema, addonGroupRequestSchema, addonGroupSchema, addonValueRequestSchema, addonValueSchema, addressChangeRequestListSchema, addressTypeSchema, agentPolicyDecisionSchema, aiActivitySchema, aiAgentPhaseSchema, aiAttachmentSchema, aiChoiceOptionSchema, aiConversationFileChangesSchema, aiConversationSchema, aiConversationSummarySchema, aiDesignBoardSchema, aiDesignCanvasSchema, aiDesignConfirmBoardSchema, aiDesignSelectionSchema, aiFileChangeKindSchema, aiFocusAreaSchema, aiFocusSchema, aiMessagePartSchema, aiMessageSchema, aiPreviewSelectionSchema, aiRunChangesSchema, aiRunChangesStatusSchema, aiRunFileDiffSchema, aiRunRevertConflictDetailsSchema, aiRunRevertResultSchema, aiRunSchema, aiRunStatusSchema, aiSetupConfirmItemSchema, aiStreamAccessSchema, aiStreamEventSchema, aiStreamRecordSchema, aiTodoSchema, aiToolChangeSchema, allocateByWeight, analyticsChannelSchema, analyticsCheckoutOutcomeSchema, analyticsCheckoutSchema, analyticsDeviceRowSchema, analyticsDevicesSchema, analyticsFunnelStepSchema, analyticsOriginSchema, analyticsOverviewSchema, analyticsPagesQuerySchema, analyticsPagesSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsRealtimeSchema, analyticsSearchQuerySchema, analyticsSearchSchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, appArtifactUploadSchema, appBuildSchema, appBuildStageSchema, appCapabilitiesOf, appDeployKeyCreateSchema, appDeployKeyCreatedSchema, appDeployKeySchema, appDevTokenSchema, appDistributionSchema, appEventTypeSchema, appFlowEventSchema, appFlowEventSummarySchema, appFlowNotificationSchema, appFlowNotificationSummarySchema, appFlowParamSchema, appFlowSummaryOf, appHandleSchema, appHttpKeyMatches, appIconProblem, appInstallRequestSchema, appInstallationActivitySchema, appInstallationAppSchema, appInstallationRunSchema, appInstallationSchema, appInstallationSelfSchema, appInstallationSettingsSchema, appInstallationSettingsUpdateSchema, appInstallationStatusSchema, appInvocationSchema, appListingReviewSchema, appListingReviewStatusSchema, appListingSchema, appManifestProblems, appManifestSchema, appManifestWidens, appNetworkHostProblem, appNetworkHostSchema, appReleaseResultSchema, appRuntimeSchema, appScheduleIntervalLabel, appScheduleListOf, appScheduleSummarySchema, appScopeSchema, appSecretSummarySchema, appSessionSchema, appSettingFieldSchema, appStatusSchema, appStorageEntrySchema, appStorageKeysSchema, appStorageListQuerySchema, appStoragePutSchema, appToolCallSchema, appToolInputSchema, appToolListOf, appToolResultSchema, appToolSchema, appToolSummarySchema, appVersionSchema, appVersionStatusSchema, appVisibilitySchema, approvalDecisionRequestSchema, approvalListQuerySchema, approvalPageSchema, approvalRequestSchema, approvalStatusSchema, approveClaimResultSchema, auditActorSchema, auditActorTypeSchema, auditLogListQuerySchema, auditLogOutcomeSchema, auditLogPageSchema, auditLogSchema, auditLogSourceSchema, bestSellingRuleOf, brandBriefProductSourceSchema, brandBriefReferenceSchema, brandBriefSchema, brandBriefViewSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, businessInfoPatchShape, businessInfoResponseShape, businessNumberSchema, calendarDateSchema, calendarDaySchema, calendarQuerySchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, cashReceiptSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeStorefrontSlugRequestSchema, changeStorefrontTemplateRequestSchema, changeTypeSchema, claimCollectCompleteRequestSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimRedeliveryRequestSchema, claimReturnAddressSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, collectionCreateRequestSchema, collectionListQuerySchema, collectionPageSchema, collectionPatchRequestSchema, collectionPreviewRequestSchema, collectionPreviewSchema, collectionProductListQuerySchema, collectionProductSchema, collectionProductSortRequestSchema, collectionProductsAddRequestSchema, collectionProductsReplaceRequestSchema, collectionRuleCategoryIds, collectionRuleSchema, collectionRuleViewSchema, collectionRulesPredicate, collectionRulesSchema, collectionSchema, collectionStateCountsSchema, collectionStateOf, collectionStateSchema, commerceFlowCheckSchema, commerceFlowSchema, commerceFlowSummarySchema, commerceFlowVersionViewSchema, commerceNumberField, compareBySales, consentActionSchema, consentKindSchema, consentSourceSchema, couponBenefitSchema, couponConditionsInputSchema, couponConditionsSchema, couponDiscountOf, couponIssueListQuerySchema, couponIssueMethodSchema, couponIssueSchema, couponIssueStatusSchema, couponKindSchema, couponListQuerySchema, couponRedemptionListQuerySchema, couponRedemptionSchema, couponRejectReasonSchema, couponRuleSchema, couponSchema, couponStatsSchema, couponStatusSchema, couponTargetInputSchema, couponTargetSchema, createAiConversationRequestSchema, createAiConversationResponseSchema, createCommerceFlowRequestSchema, createCouponRequestSchema, createPkcePair, createStoreClient, createStoreDraftRequestSchema, createStoreDraftResponseSchema, createStoreSession, createStorefrontEditPreviewLinkRequestSchema, createStorefrontPreviewLinkRequestSchema, createStorefrontSiteRequestSchema, createStorefrontVersionRequestSchema, customInputLabelForbiddenWord, customInputRequestSchema, customInputSchema, customInputValueSchema, customerAddressSchema, customerConsentListQuerySchema, customerConsentSchema, customerConsentStateSchema, customerConsentsSchema, customerCouponSchema, customerDelegationRequestSchema, customerDelegationSchema, customerDetailSchema, customerInquiryCategorySchema, customerInquiryListQuerySchema, customerListQuerySchema, customerOrderSchema, customerPointsSchema, customerSortSchema, customerStatsSchema, customerSummarySchema, customerWithdrawalBlockedDetailsSchema, defaultFulfillmentMethodOf, deleteStorefrontFileRequestSchema, deliveryBundleKeyOf, deliveryFeeWaiverSchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, descendantCategoryIdsOf, describeScope, devStoreSchema, developerAppCreateSchema, developerAppSchema, developerInstallationSchema, developerOrgSchema, developerStoreSchema, disableStorefrontHostingRequestSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, easyPayProviderResponseSchema, easyPayProviderSchema, eventTypeSchema, exchangeAuthorizationCode, flowActionRequestSchema, flowActionResultSchema, flowActionSchema, flowFieldValueSchema, flowInputFieldSchema, flowNodeTypesSchema, flowNotificationWebhookEventDataSchema, flowNotificationWebhookEventSchema, flowPresetDetailSchema, flowPresetSummarySchema, flowRunSchema, flowRunStepSchema, flowSecretNameSchema, flowSecretSchema, flowStateChangedWebhookEventDataSchema, flowStateChangedWebhookEventSchema, flowStateSchema, formatOrderNo, fulfillBulkRequestSchema, fulfillRequestSchema, fulfillmentMethodOf, fulfillmentMethodSchema, fulfillmentMethodsOf, fulfillmentRuleOf, fulfillmentTypeOf, fulfillmentTypeResponseSchema, fulfillmentTypeSchema, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, inventoryAdjustmentLineSchema, inventoryAdjustmentReasonSchema, inventoryAdjustmentRequestSchema, inventoryChangedWebhookEventDataSchema, inventoryChangedWebhookEventSchema, inventoryLevelListQuerySchema, inventoryLevelPageSchema, inventoryLevelSchema, inventoryLocationRequestSchema, inventoryLocationSchema, inventoryModeSchema, inventoryMovementKindSchema, inventoryMovementListQuerySchema, inventoryMovementPageSchema, inventoryMovementSchema, inventoryOperationResultSchema, inventoryTransferRequestSchema, invitationDeliveryStatusSchema, invitationListQuerySchema, invitationSchema, inviteMemberRequestSchema, isAiAgentNotesPath, isAiDesignPath, isCouponTargetLine, isEditableStorefrontPath, isInstallableScope, isReservedStoreCode, isReservedStorefrontSlug, isShowcaseStorefrontSlug, isStoreScope, isWebOrigin, issueCouponRequestSchema, issueCouponResultSchema, kakaoPayCredentialsInputSchema, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, loginProviderSchema, loginProviderStatusSchema, loginProviderTestSchema, loginSettingsSchema, maskedSecretSchema, matchesCollectionRules, mcpRuleResultSchema, mcpToolEventSchema, migrateFlowVersionRequestSchema, migrateFlowVersionResultSchema, moveFlowStateRequestSchema, moveStorefrontFileRequestSchema, myAccountSchema, myStoreSchema, naverPayCredentialsInputSchema, nightsOf, normalizeBusinessNumber, normalizeCouponCode, normalizeStorefrontHostname, normalizeStorefrontPath, oauthTokenResponseSchema, openFulfillmentUnion, optionGroupKindSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionSelectionSchema, optionSortSchema, optionValueRequestSchema, optionValueSchema, orderCanceledWebhookEventDataSchema, orderCanceledWebhookEventSchema, orderDiscountSchema, orderFlowActionResultSchema, orderFulfilledWebhookEventDataSchema, orderFulfilledWebhookEventSchema, orderItemFlowSchema, orderItemFulfillmentSchema, orderItemFulfillmentSnapshotResponseSchema, orderItemFulfillmentSnapshotSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, parseOrderNo, parseWebhookEvent, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentFailureWarningSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentSettingsSchema, paymentStatusProviderSchema, paymentStatusSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, pickupLocationRequestSchema, pickupLocationSchema, pickupLocationSnapshotSchema, planCodeSchema, planEntitlementsSchema, planErrorDetailsSchema, pointAdjustmentRequestSchema, pointAdjustmentResultSchema, pointEarnOf, pointEarnRateBpSchema, pointEarningEnabled, pointEntrySchema, pointExpiresAtOf, pointHistoryQuerySchema, pointLotSchema, pointPolicyNoticeSchema, pointPolicySchema, pointRestoreExpiresAtOf, pointUseOf, pointUsePolicySchema, policyDocumentUrlSchema, policyVersionSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productFulfillmentCreateSchema, productFulfillmentResponseSchema, productFulfillmentSchema, productFulfillmentUpdateSchema, productImageRejection, productImageUrlSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productRefundPolicyOverride, productRefundPolicyPatchSchema, productReplaceRequestSchema, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, proratedPaidRefundBase, proratedPointRefund, proratedRefundBase, publicPlanSchema, publicPlansSchema, publishStorefrontVersionRequestSchema, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, purchaseEarnPolicySchema, purchaseEarnRateOf, putBrandBriefRequestSchema, quoteDelivery, quotePricing, rankBestSelling, refreshUserToken, refundPolicyPatchSchema, refundPolicySchema, rejectClaimRequestSchema, remoteAreaLabelOf, remoteAreaOf, remoteAreaSchema, remoteSurchargeOf, replaceStorefrontSourceRequestSchema, replayFlowRequestSchema, replayFlowResultSchema, requiresCollection, requiresShipping, resolvePointPolicy, resolveRefundPolicy, resolveShippingPolicy, resolvedFlowSchema, responsePlanCodeSchema, responsePointEntryTypeSchema, reviewListQuerySchema, reviewReportResultSchema, reviewRewardPointOf, reviewRewardPolicySchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, rollbackStorefrontRequestSchema, runStorefrontCheckRequestSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, saveFlowDraftRequestSchema, saveFlowSecretRequestSchema, saveLoginProviderRequestSchema, savedCustomInputRequestSchema, savedCustomInputSchema, savedOptionGroupRequestSchema, savedOptionGroupSchema, savedOptionSetCompositionSchema, savedOptionSetFromProductRequestSchema, savedOptionSetFromProductResultSchema, savedOptionSetListQuerySchema, savedOptionSetRequestSchema, savedOptionSetSchema, savedOptionSetSortSchema, savedOptionValueRequestSchema, savedOptionValueSchema, scopeAccessSchema, scopesCoverEvent, searchStorefrontFilesRequestSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCancelPreviewSchema, sellerCustomerInquirySchema, sendAiMessageRequestSchema, sendAiMessageResponseSchema, setCalendarRequestSchema, setPlatformTestKeysRequestSchema, setStorefrontVisibilityRequestSchema, settleCouponShortfall, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, shippingPolicyPatchSchema, shippingPolicySchema, simulateFlowRequestSchema, simulateFlowResultSchema, simulationStepSchema, splitRefund, starterSellerTaskSchema, starterStageSchema, starterStatusSchema, starterStoreInfoFieldSchema, stayRangeSchema, staySnapshotSchema, storeAppDetailSchema, storeAppSchema, storeCodeSchema, storeDraftPreviewSchema, storeDraftSchema, storeIndustrySchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storePointPolicySchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeSetupBriefSchema, storeShopTypeSchema, storeSubscriptionSchema, storeTemplateSchema, storefrontBuildDependenciesSchema, storefrontBuildListQuerySchema, storefrontBuildSchema, storefrontBuildStatusSchema, storefrontCheckSchema, storefrontCheckStatusSchema, storefrontCustomDomainStatusSchema, storefrontCustomHostnameProblem, storefrontDependencyFindingSchema, storefrontDeploymentLogSchema, storefrontDeploymentSchema, storefrontDeploymentStepSchema, storefrontDevLogsSchema, storefrontDnsRecordSchema, storefrontDomainSchema, storefrontDomainTxtNameOf, storefrontEditPreviewLabelOf, storefrontEditPreviewSchema, storefrontEditSessionSchema, storefrontEditSessionStatusSchema, storefrontEditingSchema, storefrontFileConflictDetailsSchema, storefrontFileContentQuerySchema, storefrontFileContentSchema, storefrontFileDeleteResultSchema, storefrontFileEncodingSchema, storefrontFileEntrySchema, storefrontFileHashSchema, storefrontFileListQuerySchema, storefrontFileListSchema, storefrontFileMoveResultSchema, storefrontFilePathSchema, storefrontFileSearchResultSchema, storefrontFileWriteResultSchema, storefrontHostingSchema, storefrontPreviewLinkSchema, storefrontProvisioningSchema, storefrontRuleResultSchema, storefrontRuleSeveritySchema, storefrontSiteDomainSchema, storefrontSiteDomainsSchema, storefrontSiteSchema, storefrontSiteSnapshotSchema, storefrontSiteStatusSchema, storefrontSlugAvailabilityQuerySchema, storefrontSlugAvailabilitySchema, storefrontSlugSchema, storefrontSourceArchivePartSchema, storefrontSourceArchiveQuerySchema, storefrontSourceBlobsResultSchema, storefrontSourceModeSchema, storefrontSourceRefSchema, storefrontSourceReplacedSchema, storefrontSourceSchema, storefrontSuspensionSchema, storefrontTemplateSchema, storefrontVerifyReportSchema, storefrontVersionCreatedSchema, storefrontVersionPreviewLabelOf, storefrontVersionSchema, storefrontVersionStatusSchema, storefrontVisibilitySchema, subscriptionLimitsSchema, subscriptionStatusSchema, subscriptionUsageSchema, tossPaymentsCredentialsInputSchema, trackingStageResponseSchema, trackingUpdateResultSchema, unknownWebhookEventSchema, updateCouponRequestSchema, updateLoginProviderRequestSchema, updateLoginSettingsRequestSchema, updateMemberRoleRequestSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, updatePointPolicyRequestSchema, updateStoreRequestSchema, updateStoreTemplateRequestSchema, uploadExtensionOf, uploadPurposeSchema, uploadRejection, uploadRequestSchema, uploadStorefrontSourceBlobsRequestSchema, uploadTicketSchema, upsertKakaoPayProviderRequestSchema, upsertNaverPayProviderRequestSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryDetailSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliveryResourceSchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookFailureReasonSchema, webhookRedeliverFailedResultSchema, webhookRequestHeaderSchema, webhookRequestSchema, webhookResourceTypeSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema, withdrawCustomerRequestSchema, writeDryRunResultSchema, writePreviewSchema, writeStorefrontFilesRequestSchema };
11115
+ export { AI_AGENT_NOTES_DIR, AI_AGENT_PHASES, AI_DESIGN_BOARDS_MAX, AI_DESIGN_BOARD_FILE_PATTERN, AI_DESIGN_BOARD_KINDS, AI_DESIGN_CANVAS_PATH, AI_DESIGN_CONFIRM_APPROVE, AI_DESIGN_DIR, AI_DESIGN_VIEWPORTS, AI_MESSAGE_MAX_ATTACHMENTS, AI_MESSAGE_MAX_CHARS, AI_RUN_ACTIVE_STATUSES, AI_RUN_FILE_CHANGES_RETENTION_DAYS, AI_SETUP_CONFIRM_APPROVE, AI_TODOS_MAX, AI_TODO_STATUSES, APPROVAL_ALREADY_DECIDED_CODE, APPROVAL_REQUIRED_CODE, APP_CAPABILITIES, APP_DEPLOY_KEY_PATTERN, APP_DEPLOY_KEY_PREFIX, APP_EVENTS_MAX, APP_EVENT_SCOPES, APP_EVENT_TYPES, APP_FLOW_EVENT_PATTERN, APP_FLOW_ITEMS_MAX, APP_FLOW_NOTIFICATION_PATTERN, APP_HANDLE_PATTERN, APP_HTTP_KEY_PATTERN, APP_ICON_CONTENT_TYPES, APP_ICON_MAX_BYTES, APP_ICON_MIN_PX, APP_LIFECYCLE_EVENT_TYPES, APP_NETWORK_DENIED_SUFFIXES, APP_NETWORK_HOSTS_MAX, APP_PUBLIC_HTTP_MAX, APP_README_MAX_BYTES, APP_RESERVED_HANDLES, APP_SCHEDULES_MAX, APP_SCHEDULE_INTERVALS, APP_SCHEDULE_NAME_PATTERN, APP_SECRETS_MAX, APP_SECRET_NAME_PATTERN, APP_SECRET_PATTERNS, APP_SERVER_BUNDLE_MAX_GZIP_BYTES, APP_SETTINGS_MAX_FIELDS, APP_SETTING_FIELD_TYPES, APP_SETTING_KEY_PATTERN, APP_STORAGE_KEY_PATTERN, APP_STORAGE_MAX_BYTES, APP_STORAGE_MAX_KEYS, APP_TOOL_NAME_PATTERN, APP_UI_MAX_BYTES, APP_UI_MAX_FILES, ApiError, ApprovalPendingError, BASE_CURRENCY, BRAND_BRIEF_MAX_REFERENCES, BUSINESS_INFO_MAX_LENGTH, BUSINESS_NUMBER_PATTERN, CASH_RECEIPT_STATUS_VALUES, CERTIFICATION_STATUSES, COLLECTION_BEST_SELLING_DAYS, COLLECTION_PREVIEW_SIZE, COLLECTION_PRODUCT_SORTS, COLLECTION_SALES_SORT_DEFAULT_DAYS, COLLECTION_SLUG_PATTERN, COLLECTION_TYPES, COUPON_CODE_PATTERN, COUPON_CONDITIONS_DEFAULTS, COUPON_TARGET_ALL, COUPON_TARGET_LIST_MAX, CURRENCIES, CURRENCY_CODES, CUSTOM_INPUT_FORBIDDEN_WORDS, CUSTOM_INPUT_TYPES, DEDICATED_EASY_PAY_PROVIDER, FULFILLMENT_METHODS, FULFILLMENT_METHODS_BY_TYPE, FULFILLMENT_METHOD_RULES, FULFILLMENT_RULES, INSTALLABLE_SCOPES, InvalidPriceUnitError, KAKAOPAY_TEST_CID, KNOWN_WEBHOOK_EVENT_TYPES, KRW_MONEY_RULES, MAX_ADDON_GROUPS, MAX_ANALYTICS_ALLOWED_ORIGINS, MAX_AUTO_TRANSITION_DAYS, MAX_CALENDAR_DAYS, MAX_CERTIFICATION_ITEMS, MAX_COLLECTIONS, MAX_COLLECTION_BEST_SELLING_TOP, MAX_COLLECTION_CREATED_WITHIN_DAYS, MAX_COLLECTION_DESCRIPTION, MAX_COLLECTION_PRODUCTS, MAX_COLLECTION_PRODUCTS_PER_ADD, MAX_COLLECTION_RULES, MAX_COLLECTION_RULE_CATEGORIES, MAX_COLLECTION_TITLE, MAX_CUSTOM_INPUTS, MAX_CUSTOM_INPUT_LENGTH, MAX_INFO_SECTION_TITLE, MAX_INVENTORY_OPERATION_LINES, MAX_NOTICE_VALUE_LENGTH, MAX_OPTION_GROUPS, MAX_PICKUP_LOCATIONS, MAX_PRODUCT_IMAGES, MAX_PRODUCT_INFO_SECTIONS, MAX_SAVED_OPTION_SETS, MAX_SAVED_OPTION_SET_NAME, MAX_STAY_NIGHTS, MAX_VALUES_PER_GROUP, MAX_VARIANTS, MCP_TELEMETRY_MAX_RESULTS, MIN_PAYMENT_AMOUNT, NON_INSTALLABLE_SCOPES, NO_COUPON_SETTLEMENT, NO_SHIPPING_BUNDLE_KEY, PAYMENT_ROUTING_EXCLUSION_CODES, PAYPAL_CURRENCIES, PLATFORM_CODE_SETS, POINT_ADJUSTMENT_MAX, POINT_EARN_RATE_BP_MAX, POINT_ENTRY_TYPES, POINT_EXPIRY_DAYS_MAX, POINT_EXPIRY_DAYS_MIN, POINT_LOT_SOURCES, POINT_POLICY_DEFAULTS, POINT_REVIEW_REWARD_MAX, POINT_USE_UNITS, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, REFUND_POLICY_DEFAULTS, REFUND_POLICY_DELIVERY_FEE_KEYS, REMOTE_AREA_ZIP_RANGES, RESERVED_STOREFRONT_SLUGS, RESERVED_STORE_CODES, SCOPE_DESCRIPTIONS, SHIPPING_POLICY_DEFAULTS, STARTER_SELLER_TASKS, STARTER_STAGES, STOREFRONT_BLOCKED_PATH_SEGMENTS, STOREFRONT_BUILD_STAGES, STOREFRONT_BUILD_TERMINAL_STATUSES, STOREFRONT_CHECK_TERMINAL_STATUSES, STOREFRONT_CLOSED_SITE_HOLD_DAYS, STOREFRONT_CUSTOM_DOMAIN_LIMIT_DEFAULT, STOREFRONT_DOMAIN_DNS_GRACE_DAYS, STOREFRONT_DOMAIN_DNS_WAIT_DAYS, STOREFRONT_DOMAIN_TXT_LABEL, STOREFRONT_EDIT_ACTIVITY_TIMEOUT_MINUTES, STOREFRONT_EDIT_CAPACITY, STOREFRONT_EDIT_IDLE_MINUTES, STOREFRONT_EDIT_PREVIEW_SUFFIX, STOREFRONT_EDIT_START_STAGES, STOREFRONT_FILE_BATCH_MAX, STOREFRONT_FILE_MAX_BYTES, STOREFRONT_PATH_SEGMENT_PATTERN, STOREFRONT_PLATFORM_DOMAINS, STOREFRONT_PUBLIC_SUFFIXES, STOREFRONT_SEARCH_REGEX_MAX_LENGTH, STOREFRONT_SHOWCASE_SLUG_PREFIX, STOREFRONT_SITE_CREATE_LIMIT, STOREFRONT_SLUG_CHANGE_LIMIT, STOREFRONT_SLUG_CHANGE_WINDOW_DAYS, STOREFRONT_SLUG_HOLD_DAYS, STOREFRONT_SLUG_PATTERN, STOREFRONT_SOURCE_BLOB_BATCH_MAX, STOREFRONT_SOURCE_PART_BYTES, STOREFRONT_WORKSPACE_MAX_BYTES, STOREFRONT_WORKSPACE_MAX_FILES, STORE_CODE_PATTERN, STORE_DRAFT_ATTACHMENT_MAX_BYTES, STORE_DRAFT_MAX_ATTACHMENTS, STORE_DRAFT_RETENTION_DAYS, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, STORE_SHOP_TYPES, TEMPLATE_STORE_LOCKED_BUSINESS_FIELDS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, UPLOAD_PURPOSE_LIMITS, VARIANT_COUNT_WARNING, VARIANT_STOCK_EXCLUSIVE_MESSAGE, WEBHOOK_DEFAULT_TOLERANCE_SEC, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_EVENT_TYPE_HEADER, WEBHOOK_FAILURE_REASONS, WEBHOOK_HEADERS, WEBHOOK_PAYLOAD_EXCERPT_MAX_BYTES, WEBHOOK_RESOURCE_TYPES, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_USER_AGENT, addStorefrontDomainRequestSchema, additionalCurrencyPriceSchema, additionalCurrencyPricesSchema, addonGroupRequestSchema, addonGroupSchema, addonValueRequestSchema, addonValueSchema, addressChangeRequestListSchema, addressTypeSchema, agentPolicyDecisionSchema, aiActivitySchema, aiAgentPhaseSchema, aiAttachmentSchema, aiChoiceOptionSchema, aiConversationFileChangesSchema, aiConversationSchema, aiConversationSummarySchema, aiDesignBoardSchema, aiDesignCanvasSchema, aiDesignConfirmBoardSchema, aiDesignSelectionSchema, aiFileChangeKindSchema, aiFocusAreaSchema, aiFocusSchema, aiMessagePartSchema, aiMessageSchema, aiPreviewSelectionSchema, aiRunChangesSchema, aiRunChangesStatusSchema, aiRunFileDiffSchema, aiRunRevertConflictDetailsSchema, aiRunRevertResultSchema, aiRunSchema, aiRunStatusSchema, aiSetupConfirmItemSchema, aiStreamAccessSchema, aiStreamEventSchema, aiStreamRecordSchema, aiTodoSchema, aiToolChangeSchema, allocateByWeight, analyticsChannelSchema, analyticsCheckoutOutcomeSchema, analyticsCheckoutSchema, analyticsDeviceRowSchema, analyticsDevicesSchema, analyticsFunnelStepSchema, analyticsOriginSchema, analyticsOverviewSchema, analyticsPagesQuerySchema, analyticsPagesSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsRealtimeSchema, analyticsSearchQuerySchema, analyticsSearchSchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, appArtifactUploadSchema, appBuildSchema, appBuildStageSchema, appCapabilitiesOf, appDeployKeyCreateSchema, appDeployKeyCreatedSchema, appDeployKeySchema, appDevTokenSchema, appDistributionSchema, appEventTypeSchema, appFlowEventSchema, appFlowEventSummarySchema, appFlowNotificationSchema, appFlowNotificationSummarySchema, appFlowParamSchema, appFlowSummaryOf, appHandleSchema, appHttpKeyMatches, appIconProblem, appInstallRequestSchema, appInstallationActivitySchema, appInstallationAppSchema, appInstallationRunSchema, appInstallationSchema, appInstallationSelfSchema, appInstallationSettingsSchema, appInstallationSettingsUpdateSchema, appInstallationStatusSchema, appInvocationSchema, appListingReviewSchema, appListingReviewStatusSchema, appListingSchema, appManifestProblems, appManifestSchema, appManifestWidens, appNetworkHostProblem, appNetworkHostSchema, appReleaseResultSchema, appRuntimeSchema, appScheduleIntervalLabel, appScheduleListOf, appScheduleSummarySchema, appScopeSchema, appSecretSummarySchema, appSessionSchema, appSettingFieldSchema, appStatusSchema, appStorageEntrySchema, appStorageKeysSchema, appStorageListQuerySchema, appStoragePutSchema, appToolCallSchema, appToolInputSchema, appToolListOf, appToolResultSchema, appToolSchema, appToolSummarySchema, appVersionSchema, appVersionStatusSchema, appVisibilitySchema, approvalDecisionRequestSchema, approvalListQuerySchema, approvalPageSchema, approvalRequestSchema, approvalStatusSchema, approveClaimResultSchema, assertSaleUnit, auditActorSchema, auditActorTypeSchema, auditLogListQuerySchema, auditLogOutcomeSchema, auditLogPageSchema, auditLogSchema, auditLogSourceSchema, bestSellingRuleOf, brandBriefProductSourceSchema, brandBriefReferenceSchema, brandBriefSchema, brandBriefViewSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, businessInfoPatchShape, businessInfoResponseShape, businessNumberSchema, calendarDateSchema, calendarDaySchema, calendarQuerySchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, cashReceiptSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeStorefrontSlugRequestSchema, changeStorefrontTemplateRequestSchema, changeTypeSchema, claimCollectCompleteRequestSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimRedeliveryRequestSchema, claimReturnAddressSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, collectionCreateRequestSchema, collectionListQuerySchema, collectionPageSchema, collectionPatchRequestSchema, collectionPreviewRequestSchema, collectionPreviewSchema, collectionProductListQuerySchema, collectionProductSchema, collectionProductSortRequestSchema, collectionProductsAddRequestSchema, collectionProductsReplaceRequestSchema, collectionRuleCategoryIds, collectionRuleSchema, collectionRuleViewSchema, collectionRulesPredicate, collectionRulesSchema, collectionSchema, collectionStateCountsSchema, collectionStateOf, collectionStateSchema, commerceFlowCheckSchema, commerceFlowSchema, commerceFlowSummarySchema, commerceFlowVersionViewSchema, commerceNumberField, compareBySales, consentActionSchema, consentKindSchema, consentSourceSchema, couponBenefitSchema, couponConditionsInputSchema, couponConditionsSchema, couponDiscountOf, couponIssueListQuerySchema, couponIssueMethodSchema, couponIssueSchema, couponIssueStatusSchema, couponKindSchema, couponListQuerySchema, couponRedemptionListQuerySchema, couponRedemptionSchema, couponRejectReasonSchema, couponRuleSchema, couponSchema, couponStatsSchema, couponStatusSchema, couponTargetInputSchema, couponTargetSchema, createAiConversationRequestSchema, createAiConversationResponseSchema, createCommerceFlowRequestSchema, createCouponRequestSchema, createMarketRequestSchema, createPkcePair, createStoreClient, createStoreDraftRequestSchema, createStoreDraftResponseSchema, createStoreSession, createStorefrontEditPreviewLinkRequestSchema, createStorefrontPreviewLinkRequestSchema, createStorefrontSiteRequestSchema, createStorefrontVersionRequestSchema, currencyCodeSchema, currencyRefundFeesSchema, currencyShippingPolicySchema, currencySpecOf, customInputLabelForbiddenWord, customInputRequestSchema, customInputSchema, customInputValueSchema, customerAddressSchema, customerConsentListQuerySchema, customerConsentSchema, customerConsentStateSchema, customerConsentsSchema, customerCouponSchema, customerDelegationRequestSchema, customerDelegationSchema, customerDetailSchema, customerInquiryCategorySchema, customerInquiryListQuerySchema, customerListQuerySchema, customerOrderSchema, customerPointsSchema, customerSortSchema, customerStatsSchema, customerSummarySchema, customerWithdrawalBlockedDetailsSchema, defaultFulfillmentMethodOf, deleteStorefrontFileRequestSchema, deliveryBundleKeyOf, deliveryFeeWaiverSchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, descendantCategoryIdsOf, describeScope, devStoreSchema, developerAppCreateSchema, developerAppSchema, developerInstallationSchema, developerOrgSchema, developerStoreSchema, disableStorefrontHostingRequestSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, easyPayProviderResponseSchema, easyPayProviderSchema, eventTypeSchema, exchangeAuthorizationCode, floorToSaleUnit, flowActionRequestSchema, flowActionResultSchema, flowActionSchema, flowFieldValueSchema, flowInputFieldSchema, flowNodeTypesSchema, flowNotificationWebhookEventDataSchema, flowNotificationWebhookEventSchema, flowPresetDetailSchema, flowPresetSummarySchema, flowRunSchema, flowRunStepSchema, flowSecretNameSchema, flowSecretSchema, flowStateChangedWebhookEventDataSchema, flowStateChangedWebhookEventSchema, flowStateSchema, formatOrderNo, fromDecimalString, fulfillBulkRequestSchema, fulfillRequestSchema, fulfillmentMethodOf, fulfillmentMethodSchema, fulfillmentMethodsOf, fulfillmentRuleOf, fulfillmentTypeOf, fulfillmentTypeResponseSchema, fulfillmentTypeSchema, holdOrderItemRequestSchema, infoFieldSourceSchema, infoSchemaFieldSchema, infoSchemaSchema, infoSectionRequestSchema, infoSectionSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, inventoryAdjustmentLineSchema, inventoryAdjustmentReasonSchema, inventoryAdjustmentRequestSchema, inventoryChangedWebhookEventDataSchema, inventoryChangedWebhookEventSchema, inventoryLevelListQuerySchema, inventoryLevelPageSchema, inventoryLevelSchema, inventoryLocationRequestSchema, inventoryLocationSchema, inventoryModeSchema, inventoryMovementKindSchema, inventoryMovementListQuerySchema, inventoryMovementPageSchema, inventoryMovementSchema, inventoryOperationResultSchema, inventoryTransferRequestSchema, invitationDeliveryStatusSchema, invitationListQuerySchema, invitationSchema, inviteMemberRequestSchema, isAiAgentNotesPath, isAiDesignPath, isCouponTargetLine, isCurrencyCode, isEditableStorefrontPath, isInstallableScope, isReservedStoreCode, isReservedStorefrontSlug, isSaleUnitPrice, isShowcaseStorefrontSlug, isStoreScope, isWebOrigin, issueCouponRequestSchema, issueCouponResultSchema, kakaoPayCredentialsInputSchema, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, loginProviderSchema, loginProviderStatusSchema, loginProviderTestSchema, loginSettingsSchema, marketSchema, maskedSecretSchema, matchesCollectionRules, mcpRuleResultSchema, mcpToolEventSchema, migrateFlowVersionRequestSchema, migrateFlowVersionResultSchema, minPaymentOf, minorToMajor, moneyRulesOf, moveFlowStateRequestSchema, moveStorefrontFileRequestSchema, myAccountSchema, myStoreSchema, naverPayCredentialsInputSchema, nightsOf, normalizeBusinessNumber, normalizeCouponCode, normalizeStorefrontHostname, normalizeStorefrontPath, oauthTokenResponseSchema, openFulfillmentUnion, optionGroupKindSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionSelectionSchema, optionSortSchema, optionValueRequestSchema, optionValueSchema, orderCanceledWebhookEventDataSchema, orderCanceledWebhookEventSchema, orderDiscountSchema, orderFlowActionResultSchema, orderFulfilledWebhookEventDataSchema, orderFulfilledWebhookEventSchema, orderItemFlowSchema, orderItemFulfillmentSchema, orderItemFulfillmentSnapshotResponseSchema, orderItemFulfillmentSnapshotSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, parseOrderNo, parseWebhookEvent, payPalCredentialsInputSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentFailureWarningSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentSettingsSchema, paymentStatusProviderSchema, paymentStatusSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderResponseSchema, pgProviderSchema, pgVerificationResultSchema, pickupLocationRequestSchema, pickupLocationSchema, pickupLocationSnapshotSchema, planCodeSchema, planEntitlementsSchema, planErrorDetailsSchema, platformCodeSchema, pointAdjustmentRequestSchema, pointAdjustmentResultSchema, pointEarnOf, pointEarnRateBpSchema, pointEarningEnabled, pointEntrySchema, pointExpiresAtOf, pointHistoryQuerySchema, pointLotSchema, pointPolicyNoticeSchema, pointPolicySchema, pointRestoreExpiresAtOf, pointUseOf, pointUsePolicySchema, policyDocumentUrlSchema, policyVersionSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCertificationsRequestSchema, productCertificationsSchema, productCreateRequestSchema, productCurrencyPriceSchema, productCurrencyPricesSchema, productFulfillmentCreateSchema, productFulfillmentResponseSchema, productFulfillmentSchema, productFulfillmentUpdateSchema, productImageRejection, productImageUrlSchema, productListQuerySchema, productNoticeRequestSchema, productNoticeSchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productRefundPolicyOverride, productRefundPolicyPatchSchema, productReplaceRequestSchema, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, proratedPaidRefundBase, proratedPointRefund, proratedRefundBase, publicPlanSchema, publicPlansSchema, publishStorefrontVersionRequestSchema, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, purchaseEarnPolicySchema, purchaseEarnRateOf, putBrandBriefRequestSchema, quoteDelivery, quotePricing, rankBestSelling, refreshUserToken, refundPolicyPatchSchema, refundPolicySchema, rejectClaimRequestSchema, remoteAreaLabelOf, remoteAreaOf, remoteAreaSchema, remoteSurchargeOf, replaceStorefrontSourceRequestSchema, replayFlowRequestSchema, replayFlowResultSchema, requiresCollection, requiresShipping, resolvePointPolicy, resolveRefundPolicy, resolveShippingPolicy, resolvedFlowSchema, responsePlanCodeSchema, responsePointEntryTypeSchema, reviewListQuerySchema, reviewReportResultSchema, reviewRewardPointOf, reviewRewardPolicySchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, rollbackStorefrontRequestSchema, runStorefrontCheckRequestSchema, salesReportCurrencySchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, saveFlowDraftRequestSchema, saveFlowSecretRequestSchema, saveLoginProviderRequestSchema, savedCustomInputRequestSchema, savedCustomInputSchema, savedOptionGroupRequestSchema, savedOptionGroupSchema, savedOptionSetCompositionSchema, savedOptionSetFromProductRequestSchema, savedOptionSetFromProductResultSchema, savedOptionSetListQuerySchema, savedOptionSetRequestSchema, savedOptionSetSchema, savedOptionSetSortSchema, savedOptionValueRequestSchema, savedOptionValueSchema, scopeAccessSchema, scopesCoverEvent, searchStorefrontFilesRequestSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCancelPreviewSchema, sellerCustomerInquirySchema, sendAiMessageRequestSchema, sendAiMessageResponseSchema, setCalendarRequestSchema, setPlatformTestKeysRequestSchema, setStorefrontVisibilityRequestSchema, settleCouponShortfall, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, shippingCurrencyPriceSchema, shippingCurrencyPricesSchema, shippingPolicyPatchSchema, shippingPolicySchema, simulateFlowRequestSchema, simulateFlowResultSchema, simulationStepSchema, splitRefund, starterSellerTaskSchema, starterStageSchema, starterStatusSchema, starterStoreInfoFieldSchema, stayRangeSchema, staySnapshotSchema, storeAppDetailSchema, storeAppSchema, storeCodeSchema, storeDraftPreviewSchema, storeDraftSchema, storeIndustrySchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storePointPolicySchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeSetupBriefSchema, storeShopTypeSchema, storeSubscriptionSchema, storeTemplateSchema, storedAdditionalCurrencyPriceSchema, storedProductCurrencyPriceSchema, storedShippingCurrencyPriceSchema, storefrontBuildDependenciesSchema, storefrontBuildListQuerySchema, storefrontBuildSchema, storefrontBuildStatusSchema, storefrontCheckSchema, storefrontCheckStatusSchema, storefrontCustomDomainStatusSchema, storefrontCustomHostnameProblem, storefrontDependencyFindingSchema, storefrontDeploymentLogSchema, storefrontDeploymentSchema, storefrontDeploymentStepSchema, storefrontDevLogsSchema, storefrontDnsRecordSchema, storefrontDomainSchema, storefrontDomainTxtNameOf, storefrontEditPreviewLabelOf, storefrontEditPreviewSchema, storefrontEditSessionSchema, storefrontEditSessionStatusSchema, storefrontEditingSchema, storefrontFileConflictDetailsSchema, storefrontFileContentQuerySchema, storefrontFileContentSchema, storefrontFileDeleteResultSchema, storefrontFileEncodingSchema, storefrontFileEntrySchema, storefrontFileHashSchema, storefrontFileListQuerySchema, storefrontFileListSchema, storefrontFileMoveResultSchema, storefrontFilePathSchema, storefrontFileSearchResultSchema, storefrontFileWriteResultSchema, storefrontHostingSchema, storefrontPreviewLinkSchema, storefrontProvisioningSchema, storefrontRuleResultSchema, storefrontRuleSeveritySchema, storefrontSiteDomainSchema, storefrontSiteDomainsSchema, storefrontSiteSchema, storefrontSiteSnapshotSchema, storefrontSiteStatusSchema, storefrontSlugAvailabilityQuerySchema, storefrontSlugAvailabilitySchema, storefrontSlugSchema, storefrontSourceArchivePartSchema, storefrontSourceArchiveQuerySchema, storefrontSourceBlobsResultSchema, storefrontSourceModeSchema, storefrontSourceRefSchema, storefrontSourceReplacedSchema, storefrontSourceSchema, storefrontSuspensionSchema, storefrontTemplateSchema, storefrontVerifyReportSchema, storefrontVersionCreatedSchema, storefrontVersionPreviewLabelOf, storefrontVersionSchema, storefrontVersionStatusSchema, storefrontVisibilitySchema, subscriptionLimitsSchema, subscriptionStatusSchema, subscriptionUsageSchema, toDecimalString, toMinor, tossPaymentsCredentialsInputSchema, trackingStageResponseSchema, trackingUpdateResultSchema, unknownWebhookEventSchema, updateCouponRequestSchema, updateLoginProviderRequestSchema, updateLoginSettingsRequestSchema, updateMarketRequestSchema, updateMemberRoleRequestSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, updatePointPolicyRequestSchema, updateStoreRequestSchema, updateStoreTemplateRequestSchema, uploadExtensionOf, uploadPurposeSchema, uploadRejection, uploadRequestSchema, uploadStorefrontSourceBlobsRequestSchema, uploadTicketSchema, upsertKakaoPayProviderRequestSchema, upsertNaverPayProviderRequestSchema, upsertPayPalProviderRequestSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryDetailSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliveryResourceSchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookFailureReasonSchema, webhookRedeliverFailedResultSchema, webhookRequestHeaderSchema, webhookRequestSchema, webhookResourceTypeSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema, withdrawCustomerRequestSchema, writeDryRunResultSchema, writePreviewSchema, writeStorefrontFilesRequestSchema };