@sayren/store-sdk 0.17.0 → 0.19.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
@@ -1044,8 +1044,8 @@ const approveClaimResultSchema = z.object({
1044
1044
  */
1045
1045
  const descriptions$3 = {
1046
1046
  preShipmentDeliveryFeeRefund: "발송 전 취소로 배송 묶음(같은 상품의 주문상품)이 모두 취소되면 그 묶음의 배송비를 환불한다. false면 배송비를 환불하지 않는다. 기본 true",
1047
- returnDeliveryFee: "단순 변심(구매자 귀책) 반품의 반품 배송비. 원 단위. 환불액에서 뺀다. 기본 0(무료). 상품별 정책에서 이 값을 주면 상품의 `returnFee`도 같은 값으로 맞춘다",
1048
- exchangeDeliveryFee: "단순 변심(구매자 귀책) 교환의 교환 배송비. 원 단위. 구매자에게 청구할 금액을 안내값으로 싣는다. 기본 0(무료). 상품별 정책에서 이 값을 주면 상품의 `exchangeFee`도 같은 값으로 맞춘다",
1047
+ returnDeliveryFee: "단순 변심(구매자 귀책) 반품의 반품 배송비. 원 단위. 환불액에서 뺀다. 기본 0(무료). 배송 상품에만 있다",
1048
+ exchangeDeliveryFee: "단순 변심(구매자 귀책) 교환의 교환 배송비. 원 단위. 구매자에게 청구할 금액을 안내값으로 싣는다. 기본 0(무료). 배송 상품에만 있다",
1049
1049
  sellerFaultFreeShipping: "판매자 귀책(셀러 직권취소, 불량·오배송 반품)이면 배송비를 셀러가 부담한다 — 배송비를 환불하고 반품비를 받지 않는다. false면 구매자 귀책과 같은 규칙을 쓴다. 기본 true",
1050
1050
  conditionalFreeShortfallCharge: "조건부 무료배송(`CONDITIONAL_FREE`) 상품에서 일부 취소로 남은 금액이 무료 기준액에 미달하면 그 배송비를 환불액에서 뺀다. false면 추가 청구 없이 셀러가 부담한다. 기본 false",
1051
1051
  couponShortfallCharge: "쿠폰 조건 미달 차감. 일부 취소·반품으로 남은 주문상품이 쿠폰 조건(최소 주문 금액 등)을 잃으면 남은 주문상품이 받던 쿠폰 할인을 환불액에서 뺀다. 판매자 귀책(셀러 직권취소, 불량·오배송 반품)은 빼지 않는다. false면 차감 없이 실결제 금액만 나눠 환불한다. 기본 true"
@@ -1095,10 +1095,8 @@ const productRefundPolicyPatchSchema = refundPolicyPatchSchema.omit({ couponShor
1095
1095
  /**
1096
1096
  * 유효 정책 해석 — 상품별 덮어쓰기 → 스토어 기본 → `REFUND_POLICY_DEFAULTS` 순이다.
1097
1097
  *
1098
- * 반품비·교환비는 레거시 필드(`products.returnFee`·`exchangeFee`)와 **연결**한다. 상품이
1099
- * `refundPolicy.returnDeliveryFee`를 정하면 그 값이 원천이고(서버가 `returnFee`도 같은 값으로 맞춘다),
1100
- * 정하지 않았으면 레거시 값이 0보다 클 때 그 값을 쓴다. 0이면 스토어 기본을 따른다 —
1101
- * 정책이 생기기 전에 만든 상품(반품비 0)이 스토어 기본을 물려받게 하는 규칙이다.
1098
+ * 반품·교환 배송비의 원천은 정책 하나다(이슈 #57 결정 3). 상품의 레거시 반품비·교환비 필드와의 연결은 없앴고,
1099
+ * 레거시 값은 마이그레이션이 상품별 정책으로 옮겼다.
1102
1100
  */
1103
1101
  function resolveRefundPolicy(storePolicy, product) {
1104
1102
  return {
@@ -1108,24 +1106,19 @@ function resolveRefundPolicy(storePolicy, product) {
1108
1106
  };
1109
1107
  }
1110
1108
  /**
1111
- * 상품의 **덮어쓰기 자체** — 레거시 반품비·교환비를 같은 형태로 승격한 값이다. 덮어쓰기가 없으면 null.
1109
+ * 상품의 **덮어쓰기 자체** — 덮어쓰기가 없으면 null.
1112
1110
  *
1113
1111
  * `resolveRefundPolicy`가 합친 결과로는 "상품이 정한 값"과 "스토어 기본을 물려받은 값"을 가를 수 없다.
1114
1112
  * 관리 API 응답의 `refundPolicy`와 콘솔 폼의 덮어쓰기 스위치가 이 함수를 원천으로 쓴다 — 가르지 못하면
1115
- * 스토어 기본을 쓰는 상품을 저장할 때 그 순간의 기본값이 상품에 박히거나, 레거시 값이 조용히 사라진다.
1113
+ * 스토어 기본을 쓰는 상품을 저장할 때 그 순간의 기본값이 상품에 박힌다.
1116
1114
  */
1117
1115
  function productRefundPolicyOverride(product) {
1118
- const { couponShortfallCharge: _storeOnly, ...override } = dropUndefined(product?.refundPolicy);
1119
- const legacy = {};
1120
- if (override.returnDeliveryFee === void 0 && (product?.returnFee ?? 0) > 0) legacy.returnDeliveryFee = product?.returnFee ?? 0;
1121
- if (override.exchangeDeliveryFee === void 0 && (product?.exchangeFee ?? 0) > 0) legacy.exchangeDeliveryFee = product?.exchangeFee ?? 0;
1122
- const merged = {
1123
- ...legacy,
1124
- ...override
1125
- };
1126
- if (product?.refundPolicy == null && Object.keys(merged).length === 0) return null;
1127
- return merged;
1116
+ if (product?.refundPolicy == null) return null;
1117
+ const { couponShortfallCharge: _storeOnly, ...override } = dropUndefined(product.refundPolicy);
1118
+ return override;
1128
1119
  }
1120
+ /** 반품·교환 배송비 키 — 배송이 없는 상품의 정책에는 두지 않는다 */
1121
+ const REFUND_POLICY_DELIVERY_FEE_KEYS = ["returnDeliveryFee", "exchangeDeliveryFee"];
1129
1122
  /** `undefined` 값을 빼고 얕게 복사한다 — 전개 순서로 덮어쓸 때 `undefined`가 기본값을 지우지 않게 */
1130
1123
  function dropUndefined(patch) {
1131
1124
  if (!patch) return {};
@@ -2626,6 +2619,259 @@ function resolveFulfillmentMode(type, mode) {
2626
2619
  * 정책 지문 키(`b:…`)와 겹치지 않는다.
2627
2620
  */
2628
2621
  const NO_SHIPPING_BUNDLE_KEY = "none";
2622
+ /** 배송비 유형 — 무료·유료·조건부 무료 */
2623
+ const deliveryTypeSchema = z.enum([
2624
+ "FREE",
2625
+ "PAID",
2626
+ "CONDITIONAL_FREE"
2627
+ ]);
2628
+ /** 파일 다운로드 기본값 — 횟수 5회·기간 30일(#48 결정 8) */
2629
+ const DOWNLOAD_DEFAULTS = {
2630
+ limit: 5,
2631
+ days: 30
2632
+ };
2633
+ const KNOWN_FULFILLMENT_TYPES = fulfillmentTypeSchema.options;
2634
+ const ADDRESS_ID_DESCRIPTIONS = {
2635
+ shipping: "출고지 주소 id(`GET /v1/seller-addresses?type=SHIPPING`). 등록에서 생략하면 그 시점 스토어 기본 출고지를 저장한다. `null`이면 비워 둔다(스토어 기본 출고지를 따른다). 이 스토어의 `SHIPPING` 주소가 아니면 거부한다",
2636
+ return: "반품지 주소 id(`GET /v1/seller-addresses?type=RETURN`). 등록에서 생략하면 그 시점 스토어 기본 반품지를 저장한다. `null`이면 비워 둔다(스토어 기본 반품지를 따른다). 이 스토어의 `RETURN` 주소가 아니면 거부한다",
2637
+ pickup: "방문 수령지 주소 id(`GET /v1/seller-addresses?type=PICKUP`). 등록에서 생략하면 그 시점 스토어 기본 방문 수령지를 저장하고, 기본 방문 수령지도 없으면 400 `PICKUP_ADDRESS_REQUIRED`다. 이 스토어의 `PICKUP` 주소가 아니면 거부한다"
2638
+ };
2639
+ /**
2640
+ * 배송비 필드 사이의 일관성 — FREE의 배송비, 조건부 무료가 아닌 상품의 무료 기준을 조용히 0·null로 바꿔 저장하지 않고 400으로 돌려준다
2641
+ * (셀러가 저장됐다고 믿는 값이 사라지지 않게). 조건부 무료는 기준 금액이 필수다 — 기준 없는 조건부 무료는 계산상 유료 배송이다.
2642
+ */
2643
+ function refineShippingConsistency(value, ctx) {
2644
+ if (value.deliveryType === "FREE" && value.deliveryFee !== void 0 && value.deliveryFee !== 0) ctx.addIssue({
2645
+ code: "custom",
2646
+ path: ["deliveryFee"],
2647
+ message: "무료 배송(FREE)의 배송비는 0이거나 생략해야 합니다"
2648
+ });
2649
+ const threshold = value.conditionalFreeAmount;
2650
+ const hasThreshold = threshold !== void 0 && threshold !== null;
2651
+ if (value.deliveryType === "CONDITIONAL_FREE" && !hasThreshold) ctx.addIssue({
2652
+ code: "custom",
2653
+ path: ["conditionalFreeAmount"],
2654
+ message: "조건부 무료(CONDITIONAL_FREE)는 무료 기준 금액이 필요합니다"
2655
+ });
2656
+ if (value.deliveryType !== "CONDITIONAL_FREE" && hasThreshold) ctx.addIssue({
2657
+ code: "custom",
2658
+ path: ["conditionalFreeAmount"],
2659
+ message: "무료 기준 금액은 조건부 무료(CONDITIONAL_FREE)에서만 받습니다"
2660
+ });
2661
+ }
2662
+ const deliveryTypeDescription = "배송비 유형. `FREE` 무료, `PAID` 유료, `CONDITIONAL_FREE` 조건부 무료";
2663
+ const shippingCreateSchema = z.strictObject({
2664
+ deliveryType: deliveryTypeSchema.default("PAID").describe(deliveryTypeDescription),
2665
+ deliveryFee: z.number().int().min(0).optional().describe("배송비. 원 단위. 생략하면 스토어 기본 배송비(`GET /v1/store`의 `shippingPolicy.baseDeliveryFee`)를 저장한다. FREE면 0이거나 생략한다"),
2666
+ conditionalFreeAmount: z.number().int().min(0).nullable().optional().describe("무료 배송이 되는 묶음 소계. 원 단위. CONDITIONAL_FREE에서만 받고 필수다"),
2667
+ shippingAddressId: z.string().nullable().optional().describe(ADDRESS_ID_DESCRIPTIONS.shipping),
2668
+ returnAddressId: z.string().nullable().optional().describe(ADDRESS_ID_DESCRIPTIONS.return)
2669
+ }).superRefine(refineShippingConsistency);
2670
+ const downloadCreateSchema = z.strictObject({
2671
+ limit: z.number().int().min(1).max(100).default(DOWNLOAD_DEFAULTS.limit).describe("다운로드 횟수 한도(수량 1개당). 생략하면 5회"),
2672
+ days: z.number().int().min(1).max(3650).default(DOWNLOAD_DEFAULTS.days).describe("다운로드 기간(제공일부터 일수). 생략하면 30일"),
2673
+ stockTracking: z.boolean().default(false).describe("재고를 세는가. 생략하면 false(재고와 무관하게 판다)"),
2674
+ withdrawalRestricted: z.boolean().default(false).describe("청약철회 제한 대상인가. true면 주문서가 제한 고지 동의를 받고, 첫 다운로드 뒤 구매자 단순 변심 취소·반품을 받지 않는다")
2675
+ });
2676
+ const codeCreateSchema = z.strictObject({
2677
+ mode: fulfillmentModeSchema.default("AUTO").describe("제공 방식. `AUTO`는 코드 풀에서 결제 확정과 함께 배정하고, `MANUAL`은 셀러가 제공 처리 때 코드를 넘긴다"),
2678
+ withdrawalRestricted: z.boolean().default(false).describe("청약철회 제한 대상인가. true면 첫 열람 뒤 구매자 단순 변심 취소·반품을 받지 않는다")
2679
+ });
2680
+ const serviceCreateSchema = z.strictObject({ mode: fulfillmentModeSchema.default("MANUAL").describe("제공 방식. `AUTO`는 결제 확정과 함께 제공 완료, `MANUAL`은 셀러가 제공 처리한다") });
2681
+ const pickupCreateSchema = z.strictObject({ addressId: z.string().optional().describe(ADDRESS_ID_DESCRIPTIONS.pickup) });
2682
+ /**
2683
+ * 상품 이행 — 등록(POST). 유형 키를 생략하면 그 유형의 기본값이다(`{ "type": "DOWNLOAD" }`만으로 등록할 수 있다).
2684
+ */
2685
+ const productFulfillmentCreateSchema = z.discriminatedUnion("type", [
2686
+ z.strictObject({
2687
+ type: z.literal("SHIPPING"),
2688
+ shipping: shippingCreateSchema.optional()
2689
+ }),
2690
+ z.strictObject({
2691
+ type: z.literal("DOWNLOAD"),
2692
+ download: downloadCreateSchema.default({
2693
+ limit: DOWNLOAD_DEFAULTS.limit,
2694
+ days: DOWNLOAD_DEFAULTS.days,
2695
+ stockTracking: false,
2696
+ withdrawalRestricted: false
2697
+ })
2698
+ }),
2699
+ z.strictObject({
2700
+ type: z.literal("CODE"),
2701
+ code: codeCreateSchema.default({
2702
+ mode: "AUTO",
2703
+ withdrawalRestricted: false
2704
+ })
2705
+ }),
2706
+ z.strictObject({
2707
+ type: z.literal("SERVICE"),
2708
+ service: serviceCreateSchema.default({ mode: "MANUAL" })
2709
+ }),
2710
+ z.strictObject({
2711
+ type: z.literal("PICKUP"),
2712
+ pickup: pickupCreateSchema.default({})
2713
+ })
2714
+ ]);
2715
+ const shippingUpdateSchema = z.strictObject({
2716
+ deliveryType: deliveryTypeSchema.describe(deliveryTypeDescription),
2717
+ deliveryFee: z.number().int().min(0).describe("배송비. 원 단위. FREE면 0"),
2718
+ conditionalFreeAmount: z.number().int().min(0).nullable().describe("무료 배송이 되는 묶음 소계. CONDITIONAL_FREE면 필수, 아니면 null"),
2719
+ shippingAddressId: z.string().nullable().describe(ADDRESS_ID_DESCRIPTIONS.shipping),
2720
+ returnAddressId: z.string().nullable().describe(ADDRESS_ID_DESCRIPTIONS.return)
2721
+ }).superRefine(refineShippingConsistency);
2722
+ /**
2723
+ * 상품 이행 — 수정(PUT·PATCH). 통째 교체이고 유형 키와 그 안의 필드가 **모두 필수**다. 서버는 현재 값과 병합하지 않는다.
2724
+ * `fulfillment` 자체를 생략하면 이행을 바꾸지 않는다.
2725
+ */
2726
+ const productFulfillmentUpdateSchema = z.discriminatedUnion("type", [
2727
+ z.strictObject({
2728
+ type: z.literal("SHIPPING"),
2729
+ shipping: shippingUpdateSchema
2730
+ }),
2731
+ z.strictObject({
2732
+ type: z.literal("DOWNLOAD"),
2733
+ download: z.strictObject({
2734
+ limit: z.number().int().min(1).max(100),
2735
+ days: z.number().int().min(1).max(3650),
2736
+ stockTracking: z.boolean(),
2737
+ withdrawalRestricted: z.boolean()
2738
+ })
2739
+ }),
2740
+ z.strictObject({
2741
+ type: z.literal("CODE"),
2742
+ code: z.strictObject({
2743
+ mode: fulfillmentModeSchema,
2744
+ withdrawalRestricted: z.boolean()
2745
+ })
2746
+ }),
2747
+ z.strictObject({
2748
+ type: z.literal("SERVICE"),
2749
+ service: z.strictObject({ mode: fulfillmentModeSchema })
2750
+ }),
2751
+ z.strictObject({
2752
+ type: z.literal("PICKUP"),
2753
+ pickup: z.strictObject({ addressId: z.string().describe(ADDRESS_ID_DESCRIPTIONS.pickup) })
2754
+ })
2755
+ ]);
2756
+ /**
2757
+ * 저장된 상품 이행 — 알려진 유형의 닫힌 유니온. 서버의 상품 엔티티와 응답이 이 모양을 쓴다.
2758
+ * 응답 파싱은 `productFulfillmentResponseSchema`(열린 유니온)를 쓴다.
2759
+ */
2760
+ const productFulfillmentSchema = z.discriminatedUnion("type", [
2761
+ z.object({
2762
+ type: z.literal("SHIPPING"),
2763
+ shipping: z.object({
2764
+ deliveryType: deliveryTypeSchema,
2765
+ deliveryFee: z.number().int().describe("배송비. 원 단위. FREE면 0"),
2766
+ conditionalFreeAmount: z.number().int().nullable().describe("조건부 무료 기준 묶음 소계. CONDITIONAL_FREE가 아니면 null"),
2767
+ shippingAddressId: z.string().nullable().describe("출고지 주소 id. null이면 스토어 기본 출고지를 따른다"),
2768
+ returnAddressId: z.string().nullable().describe("반품지 주소 id. null이면 스토어 기본 반품지를 따른다")
2769
+ })
2770
+ }),
2771
+ z.object({
2772
+ type: z.literal("DOWNLOAD"),
2773
+ download: z.object({
2774
+ limit: z.number().int().describe("다운로드 횟수 한도(수량 1개당)"),
2775
+ days: z.number().int().describe("다운로드 기간(제공일부터 일수)"),
2776
+ stockTracking: z.boolean().describe("재고를 세는가"),
2777
+ withdrawalRestricted: z.boolean().describe("청약철회 제한 대상인가")
2778
+ })
2779
+ }),
2780
+ z.object({
2781
+ type: z.literal("CODE"),
2782
+ code: z.object({
2783
+ mode: fulfillmentModeSchema.describe("제공 방식"),
2784
+ withdrawalRestricted: z.boolean().describe("청약철회 제한 대상인가")
2785
+ })
2786
+ }),
2787
+ z.object({
2788
+ type: z.literal("SERVICE"),
2789
+ service: z.object({ mode: fulfillmentModeSchema.describe("제공 방식") })
2790
+ }),
2791
+ z.object({
2792
+ type: z.literal("PICKUP"),
2793
+ pickup: z.object({ addressId: z.string().nullable().describe("방문 수령지 주소 id. null은 수령지가 지워진 상품이다(수령지를 다시 지정할 때까지 팔 수 없다)") })
2794
+ })
2795
+ ]);
2796
+ /**
2797
+ * 열린 응답 유니온 — 알려진 유형은 판별 유니온으로 검사하고, **모르는 유형만** `{ type: "OTHER", rawType }`로 읽는다.
2798
+ *
2799
+ * `type: z.string()` 가지를 그대로 두면 TS가 `type === "SHIPPING"`으로 좁혀도 문자열 가지가 남는다. `OTHER` 리터럴로 바꿔 좁히기를
2800
+ * 지킨다. 알려진 유형의 모양이 틀린 응답은 폴백으로 숨기지 않고 파싱 오류로 둔다.
2801
+ */
2802
+ function openFulfillmentUnion(known) {
2803
+ return z.union([known, z.looseObject({ type: z.string().refine((type) => !KNOWN_FULFILLMENT_TYPES.includes(type), { message: "알려진 유형은 해당 유형의 모양이어야 합니다" }) }).transform((value) => ({
2804
+ type: "OTHER",
2805
+ rawType: value.type
2806
+ }))]);
2807
+ }
2808
+ const productFulfillmentResponseSchema = openFulfillmentUnion(productFulfillmentSchema).describe("상품 이행. `type`이 유형이고 같은 이름의 키가 유형별 속성이다. 값이 추가될 수 있어 SDK는 모르는 유형을 `{ type: \"OTHER\", rawType }`로 읽는다");
2809
+ /** 제공 방식 — CODE·SERVICE는 저장된 값, DOWNLOAD는 AUTO, PICKUP은 MANUAL, 배송 상품은 null */
2810
+ function fulfillmentModeOf(fulfillment) {
2811
+ switch (fulfillment.type) {
2812
+ case "CODE": return fulfillment.code.mode;
2813
+ case "SERVICE": return fulfillment.service.mode;
2814
+ default: return FULFILLMENT_RULES[fulfillment.type].defaultMode;
2815
+ }
2816
+ }
2817
+ /** 재고를 세는가 — 파일 다운로드만 끌 수 있다 */
2818
+ function stockTrackingOf(fulfillment) {
2819
+ return fulfillment.type === "DOWNLOAD" ? fulfillment.download.stockTracking : true;
2820
+ }
2821
+ /** 청약철회 제한 대상인가 — 파일 다운로드·코드 발급만 켤 수 있다(전자상거래법 제17조 제2항 제5호, 디지털 콘텐츠) */
2822
+ function withdrawalRestrictedOf(fulfillment) {
2823
+ if (fulfillment.type === "DOWNLOAD") return fulfillment.download.withdrawalRestricted;
2824
+ if (fulfillment.type === "CODE") return fulfillment.code.withdrawalRestricted;
2825
+ return false;
2826
+ }
2827
+ /** 코드 풀을 쓰는가 — 코드 발급 + 자동 제공. 재고가 판매 가능 코드 수다 */
2828
+ function usesCodePool(fulfillment) {
2829
+ return fulfillment.type === "CODE" && fulfillment.code.mode === "AUTO";
2830
+ }
2831
+ /** 결제 확정과 함께 제공까지 끝내는가 — 비실물 + 자동 제공 */
2832
+ function autoFulfillableOf(fulfillment) {
2833
+ return !FULFILLMENT_RULES[fulfillment.type].requiresShipping && fulfillmentModeOf(fulfillment) === "AUTO";
2834
+ }
2835
+ /**
2836
+ * 주문상품의 주문 시점 이행 — 결제 확정이 주문서 줄에서 굳힌다. 상품의 현재 값이 아니다. 서버는 주문상품 컬럼
2837
+ * (`fulfillment_type`·`delivery_bundle_key`·`stock_tracked`·`withdrawal_restricted`)과 jsonb(`fulfillment_snapshot`)를 합쳐 이 모양을 만든다.
2838
+ *
2839
+ * `mode`는 **주문 시점 상품의 방식**이다. 실제 제공 방식은 제공 기록(`fulfillment.mode`)에 있고 다를 수 있다(자동 제공 상품의 수동 복구).
2840
+ */
2841
+ const orderItemFulfillmentSnapshotSchema = z.discriminatedUnion("type", [
2842
+ z.object({
2843
+ type: z.literal("SHIPPING"),
2844
+ shipping: z.object({
2845
+ bundleKey: z.string().nullable().describe("배송 묶음 키. 같은 키의 주문상품이 배송비를 한 번 낸 한 묶음이다. #29 이전 주문은 null"),
2846
+ returnAddressId: z.string().nullable().describe("주문 시점 반품지 주소 id. null이거나 지워진 주소면 스토어 기본 반품지로 안내한다")
2847
+ })
2848
+ }),
2849
+ z.object({
2850
+ type: z.literal("DOWNLOAD"),
2851
+ download: z.object({
2852
+ limit: z.number().int().describe("주문 시점 다운로드 횟수 한도(수량 1개당)"),
2853
+ days: z.number().int().describe("주문 시점 다운로드 기간(제공일부터 일수)"),
2854
+ stockTracked: z.boolean().describe("주문 시점에 재고를 뺐는가"),
2855
+ withdrawalRestricted: z.boolean().describe("구매자가 제한 고지에 동의한 청약철회 제한 주문상품인가")
2856
+ })
2857
+ }),
2858
+ z.object({
2859
+ type: z.literal("CODE"),
2860
+ code: z.object({
2861
+ mode: z.string().describe("주문 시점 상품의 제공 방식. 현재 값은 `AUTO`·`MANUAL`"),
2862
+ withdrawalRestricted: z.boolean().describe("구매자가 제한 고지에 동의한 청약철회 제한 주문상품인가")
2863
+ })
2864
+ }),
2865
+ z.object({
2866
+ type: z.literal("SERVICE"),
2867
+ service: z.object({ mode: z.string().describe("주문 시점 상품의 제공 방식. 현재 값은 `AUTO`·`MANUAL`") })
2868
+ }),
2869
+ z.object({
2870
+ type: z.literal("PICKUP"),
2871
+ pickup: z.object({ addressId: z.string().nullable().describe("주문 시점 방문 수령지 주소 id") })
2872
+ })
2873
+ ]);
2874
+ const orderItemFulfillmentSnapshotResponseSchema = openFulfillmentUnion(orderItemFulfillmentSnapshotSchema).describe("주문 시점 이행 스냅샷. 상품을 나중에 고쳐도 바뀌지 않는다. 실제 제공 기록은 `fulfillment`에 있다. 값이 추가될 수 있어 SDK는 모르는 유형을 `OTHER`로 읽는다");
2629
2875
  //#endregion
2630
2876
  //#region src/schemas/payment.ts
2631
2877
  /**
@@ -3024,7 +3270,7 @@ const orderItemSchema = z.object({
3024
3270
  optionId: z.string().nullable(),
3025
3271
  optionName: z.string().nullable(),
3026
3272
  sellerCode: z.string().nullable(),
3027
- fulfillmentType: fulfillmentTypeResponseSchema.optional().default("SHIPPING").describe("주문 시점 상품 유형. 현재 값은 `SHIPPING`·`DOWNLOAD`·`CODE`·`SERVICE`·`PICKUP`이고 값이 추가될 수 있어 문자열로 받는다. 배송 상품이 아니면 발송·배송완료 대신 제공 처리를 하고, `DELIVERED`는 제공 완료(방문 수령은 수령 완료)다. 서버는 항상 싣는다"),
3273
+ fulfillmentSnapshot: orderItemFulfillmentSnapshotResponseSchema.describe("주문 시점 이행 스냅샷(이슈 #57). `type`이 주문 시점 상품 유형이다. 배송 상품이 아니면 발송·배송완료 대신 제공 처리를 하고, `DELIVERED`는 제공 완료(방문 수령은 수령 완료)다. 상품을 나중에 고쳐도 바뀌지 않는다. 실제 제공 기록은 `fulfillment`에 있다"),
3028
3274
  quantity: z.number().int().describe("주문 수량"),
3029
3275
  canceledQuantity: z.number().int().describe("취소·반품으로 환불된 누적 수량. 수량 단위 부분 취소가 없었으면 0이다"),
3030
3276
  activeQuantity: z.number().int().describe("살아 있는 수량 (`quantity` − `canceledQuantity`). 0이면 주문상품이 전량 취소됐다"),
@@ -3042,7 +3288,6 @@ const orderItemSchema = z.object({
3042
3288
  orderedAt: z.string(),
3043
3289
  lastChangedAt: z.string(),
3044
3290
  lastChangedType: changeTypeSchema,
3045
- withdrawalRestricted: z.boolean().optional().default(false).describe("청약철회 제한 주문상품인가(이슈 #48). 구매자가 결제 전에 동의했고 제공이 시작되면(다운로드·열람·이용 시작) 구매자 취소·반품을 받지 않는다. 서버는 항상 싣는다"),
3046
3291
  testPayment: z.boolean().describe("소속 주문이 테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았습니다")
3047
3292
  });
3048
3293
  /** 주문이 받은 쿠폰 한 장 (이슈 #47) */
@@ -3381,11 +3626,6 @@ const productStatusSchema = z.enum([
3381
3626
  "OUT_OF_STOCK",
3382
3627
  "CLOSED"
3383
3628
  ]);
3384
- const deliveryTypeSchema = z.enum([
3385
- "FREE",
3386
- "PAID",
3387
- "CONDITIONAL_FREE"
3388
- ]);
3389
3629
  const productSummarySchema = z.object({
3390
3630
  productId: z.string(),
3391
3631
  name: z.string(),
@@ -3398,7 +3638,7 @@ const productSummarySchema = z.object({
3398
3638
  thumbnailUrl: z.url().optional(),
3399
3639
  /** optionGroups.length > 0 */
3400
3640
  hasOptions: z.boolean(),
3401
- fulfillmentType: fulfillmentTypeResponseSchema.optional().default("SHIPPING"),
3641
+ fulfillment: z.object({ type: fulfillmentTypeResponseSchema }).describe("상품 이행의 유형. 유형별 속성은 단건 조회(`GET /v1/products/{productId}`)의 `fulfillment`에 있다"),
3402
3642
  updatedAt: z.string()
3403
3643
  });
3404
3644
  /** 옵션 축(그룹)이 가지는 값 하나 — 예: 축 "색상"의 값 "블랙" */
@@ -3441,20 +3681,6 @@ const discountSchema = z.object({
3441
3681
  startAt: z.string().nullable(),
3442
3682
  endAt: z.string().nullable()
3443
3683
  });
3444
- /**
3445
- * 상품 유형 응답 필드 (이슈 #48) — 이 필드 이전 서버의 응답에는 없으므로 기본값을 둔다. 서버는 항상 싣는다.
3446
- */
3447
- function productFulfillmentResponseShape() {
3448
- return {
3449
- fulfillmentType: fulfillmentTypeResponseSchema.optional().default("SHIPPING"),
3450
- fulfillmentMode: z.string().nullable().optional().default(null).describe("제공 방식. `AUTO`(결제 확정과 함께 제공)·`MANUAL`(셀러가 제공 처리). 배송 상품은 null. 값이 추가될 수 있어 문자열로 받는다"),
3451
- stockTracking: z.boolean().optional().default(true).describe("재고를 세는가. false면 재고와 무관하게 판다(파일 다운로드 기본)"),
3452
- downloadLimit: z.number().int().nullable().optional().default(null).describe("파일 다운로드 횟수 한도. 파일 다운로드 상품이 아니면 null"),
3453
- downloadDays: z.number().int().nullable().optional().default(null).describe("파일 다운로드 기간(제공일부터 일수). 파일 다운로드 상품이 아니면 null"),
3454
- withdrawalRestricted: z.boolean().optional().default(false).describe("청약철회 제한 대상인가. 파일 다운로드·코드 발급 상품만 켤 수 있다(그 밖의 유형은 false로 저장한다). true면 주문서에서 제한 고지에 대한 구매자 동의를 받고, 첫 다운로드·열람 뒤 구매자 취소·반품을 받지 않는다"),
3455
- pickupAddressId: z.string().nullable().optional().default(null).describe("방문 수령지 주소 id(`seller_addresses`, 유형 PICKUP). 방문 수령 상품이 아니면 null")
3456
- };
3457
- }
3458
3684
  const productSchema = productSummarySchema.extend({
3459
3685
  description: z.string().optional(),
3460
3686
  /**
@@ -3471,15 +3697,9 @@ const productSchema = productSummarySchema.extend({
3471
3697
  optionGroups: z.array(optionGroupSchema),
3472
3698
  /** 모든 상품이 최소 1개 variant를 갖는다 (옵션 없으면 default variant 1개) */
3473
3699
  variants: z.array(productVariantSchema),
3474
- deliveryType: deliveryTypeSchema.optional(),
3475
- deliveryFee: z.number().int().optional(),
3476
- conditionalFreeAmount: z.number().int().nullable().optional(),
3477
- returnFee: z.number().int().optional(),
3478
- exchangeFee: z.number().int().optional(),
3479
- refundPolicy: productRefundPolicyPatchSchema.nullable().optional().describe("상품별 환불 정책 덮어쓰기. null이면 스토어 기본 환불 정책을 쓴다"),
3480
- shippingAddressId: z.string().nullable().optional(),
3481
- returnAddressId: z.string().nullable().optional(),
3482
- ...productFulfillmentResponseShape(),
3700
+ fulfillment: productFulfillmentResponseSchema,
3701
+ fulfillmentTypeLocked: z.boolean().describe("판매 이력(주문상품)이 있어 상품 유형(`fulfillment.type`)을 바꿀 수 없는가. true면 다른 유형으로 수정하는 요청이 409 `FULFILLMENT_TYPE_LOCKED`다. 같은 유형 안의 속성은 바꿀 수 있다"),
3702
+ refundPolicy: productRefundPolicyPatchSchema.nullable().describe("상품별 환불 정책 덮어쓰기(상품이 정한 항목만). null이면 스토어 기본 환불 정책을 쓴다. 반품·교환 배송비(`returnDeliveryFee`·`exchangeDeliveryFee`)는 배송 상품에만 있다"),
3483
3703
  /**
3484
3704
  * 설정된 즉시할인. `GET /products/{productId}/discount`의 응답과 같은 형태다(이슈 #51).
3485
3705
  * 할인이 없으면 null이다. 이 필드를 싣기 전 서버의 응답에는 없으므로 optional이다.
@@ -3606,38 +3826,12 @@ const variantStockSchema = z.object({
3606
3826
  stockQuantity: z.number().int()
3607
3827
  });
3608
3828
  /**
3609
- * 출고지·반품지 지정 문구 — POST·PUT·PATCH가 같은 규칙을 쓰므로 설명도 한 곳이다 (이슈 #30).
3829
+ * 상품 쓰기 요청의 공통 필드 — 등록(POST)과 전체 수정(PUT)이 같다. 이행(`fulfillment`)만 두 요청의 스키마가 다르다.
3610
3830
  *
3611
- * 세 값이 뜻이 다르다. **생략**은 「정하지 않음」이라 서버가 그 시점 스토어 기본 주소를 박아 저장하고,
3612
- * **null**은 「스토어 기본을 따른다」는 명시적 비우기다. 주소록 항목은 상품이 참조 중이면 지울 수 없어
3613
- * (`409 ADDRESS_IN_USE`) 참조를 푸는 수단이 필요한데, 생략을 기본값으로 되채우면 기본 주소는 영원히
3614
- * 풀리지 않는다 — null이 그 경로다. 배송 묶음 판정은 null을 그 시점 스토어 기본 출고지로 정규화하므로
3615
- * 두 표현이 배송비를 갈라놓지 않는다.
3831
+ * 최상위가 `strictObject`다. 모르는 필드는 400이다 — 이슈 #57 이전의 평면 필드(`deliveryFee`·`fulfillmentType`·`returnFee` 등)를
3832
+ * 보낸 요청이 조용히 무시되지 않게 한다. 옛 필드는 `fulfillment.{유형}.…`과 `refundPolicy`로 옮겼다.
3616
3833
  */
3617
- const ADDRESS_DESCRIPTIONS = {
3618
- shipping: "출고지 주소 id(`GET /v1/seller-addresses?type=SHIPPING`). 생략하면 스토어 기본 출고지를 저장하고, `null`이면 비워 둔다(스토어 기본 출고지를 따른다). 이 스토어의 `SHIPPING` 주소가 아니면 거부한다",
3619
- return: "반품지 주소 id(`GET /v1/seller-addresses?type=RETURN`). 생략하면 스토어 기본 반품지를 저장하고, `null`이면 비워 둔다(스토어 기본 반품지를 따른다). 이 스토어의 `RETURN` 주소가 아니면 거부한다",
3620
- patchShipping: "출고지 주소 id. **생략은 바꾸지 않음**이고 `null`은 비우기다(스토어 기본 출고지를 따른다). 이 스토어의 `SHIPPING` 주소가 아니면 거부한다",
3621
- patchReturn: "반품지 주소 id. **생략은 바꾸지 않음**이고 `null`은 비우기다(스토어 기본 반품지를 따른다). 이 스토어의 `RETURN` 주소가 아니면 거부한다"
3622
- };
3623
- /**
3624
- * 상품 유형 요청 필드 (이슈 #48) — 등록·전체 수정·부분 수정이 같은 필드를 받는다.
3625
- *
3626
- * 생략의 뜻: 등록은 배송 상품(`SHIPPING`)과 유형 기본값이고, 전체 수정(PUT)·부분 수정(PATCH)은 **현재 값을 유지**한다.
3627
- * 이 필드를 모르는 옛 클라이언트가 전체 수정을 보내도 유형이 배송 상품으로 되돌아가지 않게 한다.
3628
- */
3629
- function productFulfillmentRequestShape() {
3630
- return {
3631
- fulfillmentType: fulfillmentTypeSchema.optional().describe("상품 유형. `SHIPPING` 배송 상품 · `DOWNLOAD` 파일 다운로드 · `CODE` 코드 발급 · `SERVICE` 이용권·서비스 · `PICKUP` 방문 수령. 등록에서 생략하면 SHIPPING이고, 수정에서 생략하면 바꾸지 않는다. 판매 이력이 있는 상품의 유형은 바꿀 수 없다(409 `FULFILLMENT_TYPE_LOCKED`). 배송 상품이 아니면 배송비·출고지·반품지·반품비·교환비를 무시하고 0·null로 저장한다"),
3632
- fulfillmentMode: fulfillmentModeSchema.nullable().optional().describe("제공 방식. `AUTO` 결제 확정과 함께 제공 · `MANUAL` 셀러가 제공 처리. 생략·null이면 유형 기본값이다(코드 발급 AUTO, 이용권 MANUAL, 파일 다운로드 AUTO만, 방문 수령 MANUAL만). 배송 상품은 무시한다"),
3633
- stockTracking: z.boolean().optional().describe("재고를 세는가. 파일 다운로드 상품만 끌 수 있다(기본 false). 그 밖의 유형은 항상 true"),
3634
- downloadLimit: z.number().int().min(1).max(100).nullable().optional().describe("파일 다운로드 횟수 한도. 파일 다운로드 상품만 쓰고 생략·null이면 5회"),
3635
- downloadDays: z.number().int().min(1).max(3650).nullable().optional().describe("파일 다운로드 기간(제공일부터 일수). 파일 다운로드 상품만 쓰고 생략·null이면 30일"),
3636
- withdrawalRestricted: z.boolean().optional().describe("청약철회 제한 대상인가. true면 주문서가 제한 고지를 보여 주고 구매자 동의를 받는다. 배송 상품은 false로 저장한다"),
3637
- pickupAddressId: z.string().nullable().optional().describe("방문 수령지 주소 id(`GET /v1/seller-addresses?type=PICKUP`). 방문 수령 상품만 쓴다. 생략하면 스토어 기본 방문 수령지를 저장한다")
3638
- };
3639
- }
3640
- const productCreateRequestSchema = z.object({
3834
+ const productWriteShape = {
3641
3835
  name: z.string().min(1).max(100),
3642
3836
  categoryId: z.string().min(1, "카테고리를 선택해주십시오"),
3643
3837
  salePrice: z.number().int().min(10).multipleOf(10, "판매가는 10원 단위여야 합니다 (INVALID_PRICE_UNIT)").describe("판매가. 원(KRW) 단위 정수, 최소 10원, 10원 단위"),
@@ -3653,24 +3847,25 @@ const productCreateRequestSchema = z.object({
3653
3847
  attributeId: z.string(),
3654
3848
  value: z.string()
3655
3849
  })).optional(),
3656
- deliveryType: deliveryTypeSchema.default("PAID").describe("배송비 유형. FREE 무료, PAID 유료, CONDITIONAL_FREE 조건부 무료"),
3657
- deliveryFee: z.number().int().min(0).optional().describe("배송비. 원 단위. **생략하면 스토어 기본 배송비**(`GET /v1/store`의 `shippingPolicy.baseDeliveryFee`)를 쓴다. `deliveryType`이 FREE면 0으로 저장한다"),
3658
- conditionalFreeAmount: z.number().int().optional().describe("CONDITIONAL_FREE일 때 무료 배송이 되는 주문 금액. 원 단위"),
3659
- returnFee: z.number().int().default(0).describe("반품 배송비. 원 단위. `refundPolicy.returnDeliveryFee`와 같은 값이다"),
3660
- exchangeFee: z.number().int().default(0).describe("교환 배송비. 원 단위. `refundPolicy.exchangeDeliveryFee`와 같은 값이다"),
3661
- refundPolicy: productRefundPolicyPatchSchema.nullish().describe("상품별 환불 정책 — 준 항목만 스토어 기본을 덮어쓴다. `null`이나 생략은 스토어 기본을 그대로 쓴다는 뜻이다. `returnDeliveryFee`·`exchangeDeliveryFee`를 주면 `returnFee`·`exchangeFee`도 같은 값으로 맞춘다"),
3662
- shippingAddressId: z.string().nullable().optional().describe(ADDRESS_DESCRIPTIONS.shipping),
3663
- returnAddressId: z.string().nullable().optional().describe(ADDRESS_DESCRIPTIONS.return),
3664
- ...productFulfillmentRequestShape()
3665
- }).extend(optionModelRequestSchema.shape);
3666
- const productPatchRequestSchema = z.object({
3850
+ refundPolicy: productRefundPolicyPatchSchema.nullish().describe("상품별 환불 정책 — 준 항목만 스토어 기본을 덮어쓴다. `null`이나 생략은 스토어 기본을 그대로 쓴다는 뜻이다. 반품·교환 배송비(`returnDeliveryFee`·`exchangeDeliveryFee`)는 배송 상품에만 줄 수 있다(다른 유형은 400)"),
3851
+ ...optionModelRequestSchema.shape
3852
+ };
3853
+ const productCreateRequestSchema = z.strictObject({
3854
+ ...productWriteShape,
3855
+ fulfillment: productFulfillmentCreateSchema.optional().describe("상품 이행. `type`이 유형이고 같은 이름의 키가 유형별 속성이다. 생략하면 배송 상품(기본값)이다. 배송 상품이 아닌 유형은 판매가 열린 유형만 등록할 수 있다(409 `FULFILLMENT_TYPE_NOT_AVAILABLE`)")
3856
+ });
3857
+ const fulfillmentUpdateDescription = "상품 이행. 생략하면 바꾸지 않는다. 주면 유형 안 필드를 모두 담아 통째로 바꾼다(현재 값과 병합하지 않는다). 판매 이력이 있으면 유형을 바꿀 수 없다(409 `FULFILLMENT_TYPE_LOCKED`)";
3858
+ /** 전체 수정(PUT) — 공통 필드는 등록과 같고, 이행은 생략하면 현재 값 유지, 주면 필드가 모두 필수다 */
3859
+ const productReplaceRequestSchema = z.strictObject({
3860
+ ...productWriteShape,
3861
+ fulfillment: productFulfillmentUpdateSchema.optional().describe(fulfillmentUpdateDescription)
3862
+ });
3863
+ const productPatchRequestSchema = z.strictObject({
3667
3864
  name: z.string().max(100).optional(),
3668
3865
  salePrice: z.number().int().multipleOf(10).optional(),
3669
3866
  status: productStatusSchema.optional(),
3670
- deliveryFee: z.number().int().optional(),
3671
- shippingAddressId: z.string().nullable().optional().describe(ADDRESS_DESCRIPTIONS.patchShipping),
3672
- returnAddressId: z.string().nullable().optional().describe(ADDRESS_DESCRIPTIONS.patchReturn),
3673
- ...productFulfillmentRequestShape()
3867
+ fulfillment: productFulfillmentUpdateSchema.optional().describe(fulfillmentUpdateDescription),
3868
+ refundPolicy: productRefundPolicyPatchSchema.nullable().optional().describe("상품별 환불 정책. 주면 통째로 바꾼다(준 항목만 스토어 기본을 덮어쓴다). `null`은 덮어쓰기를 지워 스토어 기본을 따른다. 생략하면 바꾸지 않는다")
3674
3869
  }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
3675
3870
  const productSortSchema = z.enum([
3676
3871
  "createdAt.desc",
@@ -4364,6 +4559,193 @@ const sellerAddressRequestSchema = z.object({
4364
4559
  address2: z.string().optional()
4365
4560
  });
4366
4561
  //#endregion
4562
+ //#region src/schemas/storefront-hosting.ts
4563
+ /**
4564
+ * 스토어프론트 호스팅 (이슈 #53, M1: 템플릿 발행) — 관리 API `/v1/storefront/**`의 계약이다.
4565
+ *
4566
+ * 셀러는 템플릿을 골라 사이트를 만들고 `{slug}.{호스팅 도메인}` 주소를 받는다. 발행은 버전 단위이고,
4567
+ * 되돌리기는 이전 버전을 다시 발행하는 것이다(재빌드 없음). 상태의 원천은 api DB이고 Cloudflare 쪽 반영
4568
+ * (라우팅 표·사이트 Worker)은 커밋 뒤 비동기다 — 반영 상태는 `provisioning`으로 본다.
4569
+ *
4570
+ * 스코프는 조회 `storefront:r`, 쓰기 `storefront:rw`(역할 OWNER·ADMIN)다. 에이전트(MCP)의 발행·되돌리기·템플릿 변경·
4571
+ * 공개 전환·슬러그 변경·호스팅 끄기는 승인(`APPROVAL_REQUIRED`)이다 — 구매자가 보는 화면을 바꾸는 쓰기다.
4572
+ *
4573
+ * 오류 코드:
4574
+ * - 403 `STOREFRONT_HOSTING_DISABLED` — 플랫폼 스위치가 꺼져 새 사이트를 만들 수 없다
4575
+ * - 404 `STOREFRONT_SITE_NOT_FOUND` · `STOREFRONT_TEMPLATE_NOT_FOUND` · `STOREFRONT_VERSION_NOT_FOUND`
4576
+ * - 409 `STOREFRONT_SITE_EXISTS` — 이미 사이트가 있다(스토어당 1개)
4577
+ * - 409 `STOREFRONT_SLUG_TAKEN` — 다른 사이트가 쓰거나 보류 중인 슬러그다
4578
+ * - 409 `STOREFRONT_SLUG_CHANGE_LIMIT` — 슬러그는 스토어당 30일에 3번까지 바꾼다
4579
+ * - 409 `STOREFRONT_SITE_CREATE_LIMIT` — 사이트는 스토어당 30일에 3번까지 만든다
4580
+ * - 409 `STOREFRONT_SITE_CHANGED` — 읽은 상태(`expected*`)와 현재 상태가 다르다. 다시 읽고 시도한다
4581
+ * - 409 `STOREFRONT_SITE_NOT_ACTIVE` — 정지(`SUSPENDED`)된 사이트는 바꾸거나 끌 수 없다
4582
+ * - 409 `STOREFRONT_VERSION_NOT_READY` — 빌드가 끝나지 않았거나 실패한 버전은 발행할 수 없다
4583
+ * - 409 `STOREFRONT_NO_ROLLBACK_TARGET` — 되돌릴 이전 발행 버전이 없다
4584
+ * - 400 `STOREFRONT_SLUG_CONFIRM_MISMATCH` — 호스팅 끄기 확인 입력이 현재 슬러그와 다르다
4585
+ * - 503 `STOREFRONT_PREVIEW_NOT_CONFIGURED` — 미리보기 서명 키가 설정되지 않았다
4586
+ */
4587
+ /**
4588
+ * 슬러그 형식 — 스토어 코드와 같은 DNS 라벨 규칙(소문자·숫자·하이픈 3~30자, 하이픈으로 시작·끝 불가)에
4589
+ * 연속 하이픈 금지를 더한다. `--`는 버전 미리보기 주소(`v3--{slug}`)와 punycode(`xn--`)가 쓰는 구분자다.
4590
+ */
4591
+ const STOREFRONT_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,28}[a-z0-9])$/;
4592
+ /** 호스팅 도메인에서 플랫폼이 쓰거나 쓸 이름 — 스토어 코드 예약어에 호스팅 전용 이름을 더한다 */
4593
+ const RESERVED_STOREFRONT_SLUGS = [
4594
+ ...RESERVED_STORE_CODES,
4595
+ "mcp",
4596
+ "preview",
4597
+ "previews",
4598
+ "sayren",
4599
+ "shop",
4600
+ "shops",
4601
+ "abuse",
4602
+ "security",
4603
+ "closed",
4604
+ "coming-soon",
4605
+ "suspended",
4606
+ "dispatch",
4607
+ "control",
4608
+ "outbound"
4609
+ ];
4610
+ function isReservedStorefrontSlug(slug) {
4611
+ return RESERVED_STOREFRONT_SLUGS.includes(slug.toLowerCase());
4612
+ }
4613
+ const storefrontSlugSchema = z.string().regex(STOREFRONT_SLUG_PATTERN, "소문자·숫자·하이픈 3~30자여야 하고 하이픈으로 시작하거나 끝날 수 없습니다").refine((slug) => !slug.includes("--"), "하이픈을 연달아 쓸 수 없습니다").refine((slug) => !isReservedStorefrontSlug(slug), "플랫폼이 쓰는 이름이라 쓸 수 없습니다").describe("주소 슬러그. `{slug}.{호스팅 도메인}`이 사이트 주소가 된다");
4614
+ /** 바꾼 슬러그를 다른 사이트가 가져가지 못하게 막는 기간(일). 보류 동안 옛 주소는 새 주소로 301한다 */
4615
+ const STOREFRONT_SLUG_HOLD_DAYS = 90;
4616
+ /** 슬러그 변경 한도 — 이 기간(일) 안에 */
4617
+ const STOREFRONT_SLUG_CHANGE_WINDOW_DAYS = 30;
4618
+ /** 슬러그 변경 한도 — 횟수(스토어 단위. 끄고 다시 만들어도 이어서 센다) */
4619
+ const STOREFRONT_SLUG_CHANGE_LIMIT = 3;
4620
+ /** 사이트 만들기 한도 — 같은 창(30일) 안의 횟수(스토어 단위). 끄고 만들기를 되풀이해 이름을 묶어 두지 못하게 한다 */
4621
+ const STOREFRONT_SITE_CREATE_LIMIT = 3;
4622
+ const storefrontTemplateSchema = z.object({
4623
+ templateId: z.string().describe("템플릿 id (예: `basic`)"),
4624
+ name: z.string().describe("템플릿 이름"),
4625
+ industry: z.string().describe("업종 (예: `general`·`fashion`·`food`). 목록 필터에 쓴다"),
4626
+ description: z.string().describe("템플릿 설명"),
4627
+ thumbnailUrl: z.string().nullable().describe("썸네일 이미지 주소. 없으면 null"),
4628
+ version: z.string().describe("현재 템플릿 버전. 새 사이트·템플릿 변경은 이 버전으로 만든다"),
4629
+ isDefault: z.boolean().describe("기본 템플릿인가 (스토어 생성 시 자동 생성에 쓴다)")
4630
+ });
4631
+ /**
4632
+ * 버전 상태 — M1은 템플릿 빌드 산출물을 그대로 쓰므로 만들 때 곧바로 `READY`다. `BUILDING`·`FAILED`는
4633
+ * 셀러 편집 빌드(M2)가 쓴다. 발행 여부는 상태가 아니라 사이트의 발행 포인터가 원천이다(`published`).
4634
+ */
4635
+ const storefrontVersionStatusSchema = z.enum([
4636
+ "BUILDING",
4637
+ "READY",
4638
+ "FAILED"
4639
+ ]).describe("`BUILDING` 빌드 중 · `READY` 발행 가능 · `FAILED` 빌드 실패");
4640
+ const storefrontVersionSchema = z.object({
4641
+ versionId: z.string(),
4642
+ number: z.number().int().min(1).describe("사이트 안에서 1부터 늘어나는 번호 (v1, v2…)"),
4643
+ templateId: z.string().describe("이 버전의 기준 템플릿"),
4644
+ templateVersion: z.string().describe("이 버전의 기준 템플릿 버전"),
4645
+ status: storefrontVersionStatusSchema,
4646
+ published: z.boolean().describe("지금 발행된 버전인가"),
4647
+ publishedAt: z.string().nullable().describe("마지막으로 발행한 시각 (ISO 8601). 발행한 적 없으면 null"),
4648
+ message: z.string().nullable().describe("버전 메모"),
4649
+ createdByType: z.string().describe("만든 행위자 유형 (`USER`·`AGENT`·`APP`·`TOKEN`·`SYSTEM`). 늘어날 수 있다"),
4650
+ createdAt: z.string().describe("만든 시각 (ISO 8601)")
4651
+ });
4652
+ const storefrontSiteStatusSchema = z.enum([
4653
+ "ACTIVE",
4654
+ "SUSPENDED",
4655
+ "CLOSED"
4656
+ ]).describe("`ACTIVE` 운영 중 · `SUSPENDED` 운영자 정지 · `CLOSED` 호스팅 끔·스토어 폐쇄");
4657
+ const storefrontVisibilitySchema = z.enum(["COMING_SOON", "PUBLIC"]).describe("`COMING_SOON` 오픈 준비 중(방문자에게 준비 중 페이지) · `PUBLIC` 공개");
4658
+ const storefrontSourceModeSchema = z.enum(["MANAGED", "CUSTOM"]).describe("`MANAGED` 템플릿 그대로 · `CUSTOM` 한 번이라도 편집함");
4659
+ const storefrontDomainSchema = z.object({
4660
+ hostname: z.string().describe("호스트 이름 (예: `mystore.sayren.co`)"),
4661
+ kind: z.enum(["PLATFORM", "CUSTOM"]).describe("`PLATFORM` 슬러그 주소 · `CUSTOM` 내 도메인"),
4662
+ status: z.enum(["ACTIVE", "HELD"]).describe("`ACTIVE` 사용 중 · `HELD` 슬러그를 바꿔 보류 중(새 주소로 301)"),
4663
+ isPrimary: z.boolean().describe("대표 주소인가 (`Store.storefrontUrl`)"),
4664
+ holdUntil: z.string().nullable().describe("보류가 끝나는 시각 (ISO 8601). 보류가 아니면 null")
4665
+ });
4666
+ /**
4667
+ * 호스팅 반영 상태 — 발행·슬러그·공개 전환은 DB에 먼저 확정되고 Cloudflare 반영은 커밋 뒤에 한다.
4668
+ * `PENDING`이면 반영 중이거나 재시도 대기다(잡이 다시 한다). 반영 뒤에도 라우팅 전파에 최대 1분이 걸린다.
4669
+ */
4670
+ const storefrontProvisioningSchema = z.object({
4671
+ status: z.enum([
4672
+ "SYNCED",
4673
+ "PENDING",
4674
+ "FAILED"
4675
+ ]).describe("`SYNCED` 반영됨 · `PENDING` 반영 대기 · `FAILED` 반영이 여러 번 실패함(자동 재시도는 계속한다)"),
4676
+ lastErrorCode: z.string().nullable().describe("마지막 반영 실패 코드. 없으면 null"),
4677
+ syncedAt: z.string().nullable().describe("마지막으로 반영한 시각 (ISO 8601)")
4678
+ });
4679
+ const storefrontSiteSchema = z.object({
4680
+ siteId: z.string(),
4681
+ slug: z.string().describe("주소 슬러그"),
4682
+ hostname: z.string().describe("대표 호스트 이름"),
4683
+ url: z.string().describe("대표 주소 (`https://{hostname}`)"),
4684
+ domains: z.array(storefrontDomainSchema).describe("사용 중·보류 중인 호스트 이름"),
4685
+ templateId: z.string().describe("지금 발행된 버전의 템플릿 (발행 전이면 만든 템플릿)"),
4686
+ sourceMode: storefrontSourceModeSchema,
4687
+ status: storefrontSiteStatusSchema,
4688
+ visibility: storefrontVisibilitySchema,
4689
+ publishedVersion: storefrontVersionSchema.nullable().describe("지금 발행된 버전"),
4690
+ provisioning: storefrontProvisioningSchema,
4691
+ slugChangesRemaining: z.number().int().min(0).describe(`최근 30일 기준 남은 슬러그 변경 횟수`),
4692
+ createdAt: z.string(),
4693
+ updatedAt: z.string()
4694
+ });
4695
+ /** `GET /v1/storefront/site` — 스위치 상태와 현재 사이트(없으면 null. 끈 사이트는 싣지 않는다) */
4696
+ const storefrontHostingSchema = z.object({
4697
+ enabled: z.boolean().describe("새 사이트를 만들 수 있는가 (플랫폼 스위치)"),
4698
+ domain: z.string().describe("호스팅 도메인 (예: `sayren.co`). 사이트 주소는 `{slug}.{domain}`"),
4699
+ site: storefrontSiteSchema.nullable()
4700
+ });
4701
+ const storefrontSlugAvailabilitySchema = z.object({
4702
+ slug: z.string(),
4703
+ available: z.boolean(),
4704
+ reason: z.enum([
4705
+ "INVALID",
4706
+ "RESERVED",
4707
+ "TAKEN",
4708
+ "CURRENT"
4709
+ ]).nullable().describe("쓸 수 없는 이유. `INVALID` 형식 · `RESERVED` 예약어 · `TAKEN` 사용·보류 중 · `CURRENT` 지금 내 슬러그")
4710
+ });
4711
+ const createStorefrontSiteRequestSchema = z.object({
4712
+ templateId: z.string().min(1).max(64).describe("템플릿 id"),
4713
+ slug: storefrontSlugSchema.optional().describe("주소 슬러그. 생략하면 스토어 코드")
4714
+ });
4715
+ const changeStorefrontTemplateRequestSchema = z.object({
4716
+ templateId: z.string().min(1).max(64).describe("바꿀 템플릿 id"),
4717
+ publish: z.boolean().optional().describe("새 버전을 곧바로 발행하는가 (기본 true). false면 버전만 만든다"),
4718
+ message: z.string().max(200).optional().describe("버전 메모")
4719
+ });
4720
+ /**
4721
+ * 발행·되돌리기 — 발행은 사이트의 발행 포인터를 바꾸는 조건부 쓰기다. `expectedPublishedVersionId`를 주면
4722
+ * 지금 발행 버전이 그 값일 때만 바꾼다(화면을 본 뒤 다른 사람이 바꿨으면 409 `STOREFRONT_SITE_CHANGED`).
4723
+ * 이미 그 버전이 발행돼 있으면 아무것도 바꾸지 않고 200이다(같은 요청의 재실행이 안전하다).
4724
+ */
4725
+ const publishStorefrontVersionRequestSchema = z.object({ expectedPublishedVersionId: z.string().nullable().optional().describe("화면에서 본 발행 버전 id (발행 전이었으면 null). 생략하면 확인하지 않는다") });
4726
+ const rollbackStorefrontRequestSchema = z.object({
4727
+ versionId: z.string().optional().describe("되돌릴 버전. 생략하면 지금 버전 직전에 발행했던 버전"),
4728
+ expectedPublishedVersionId: z.string().nullable().optional()
4729
+ });
4730
+ const changeStorefrontSlugRequestSchema = z.object({ slug: storefrontSlugSchema });
4731
+ const setStorefrontVisibilityRequestSchema = z.object({
4732
+ visibility: storefrontVisibilitySchema,
4733
+ expectedVisibility: storefrontVisibilitySchema.optional().describe("화면에서 본 공개 상태. 주면 지금 값이 같을 때만 바꾼다")
4734
+ });
4735
+ /** 호스팅 끄기 — 사이트를 닫고(`CLOSED`) 슬러그를 보류한다. 확인 입력은 현재 슬러그다 */
4736
+ const disableStorefrontHostingRequestSchema = z.object({ confirmSlug: z.string().min(1).describe("확인 입력 — 현재 슬러그") });
4737
+ const storefrontSlugAvailabilityQuerySchema = z.object({ slug: z.string().describe("확인할 슬러그") });
4738
+ /**
4739
+ * 오픈 준비 중 미리보기 링크 — 콘솔에서 로그인한 OWNER·ADMIN만 받는다(PAT·에이전트 불가). 링크는 5분 안에 한 번 열면
4740
+ * 그 브라우저에 12시간짜리 미리보기 쿠키가 생기고 오픈 준비 중인 사이트의 실제 화면을 본다. 링크를 남에게 넘기면 그 사람도
4741
+ * 볼 수 있으므로 공유하지 않는다.
4742
+ */
4743
+ const createStorefrontPreviewLinkRequestSchema = z.object({ path: z.string().max(512).optional().describe("열 경로 (`/`로 시작). 생략하면 `/`") });
4744
+ const storefrontPreviewLinkSchema = z.object({
4745
+ url: z.string().describe("미리보기 링크 — 5분 안에 연다"),
4746
+ expiresAt: z.string().describe("링크 만료 시각 (ISO 8601)")
4747
+ });
4748
+ //#endregion
4367
4749
  //#region src/client.ts
4368
4750
  function formBody(fields) {
4369
4751
  return new URLSearchParams(fields).toString();
@@ -4530,7 +4912,7 @@ function createStoreClient(options) {
4530
4912
  body: productCreateRequestSchema.parse(body),
4531
4913
  headers: idempotency(idempotencyKey)
4532
4914
  }),
4533
- update: (productId, body) => storeHttp.request("PUT", path`/products/${productId}`, productSchema, { body: productCreateRequestSchema.parse(body) }),
4915
+ update: (productId, body) => storeHttp.request("PUT", path`/products/${productId}`, productSchema, { body: productReplaceRequestSchema.parse(body) }),
4534
4916
  patch: (productId, body) => storeHttp.requestVoid("PATCH", path`/products/${productId}`, { body: productPatchRequestSchema.parse(body) }),
4535
4917
  remove: (productId) => storeHttp.requestVoid("DELETE", path`/products/${productId}`),
4536
4918
  bulkUpdateStatus: (productIds, status, idempotencyKey) => storeHttp.request("POST", "/products/bulk/status", bulkResultSchema, {
@@ -4966,6 +5348,40 @@ list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, {
4966
5348
  remove: (addressId) => storeHttp.requestVoid("DELETE", path`/seller-addresses/${addressId}`),
4967
5349
  setDefault: (addressId) => storeHttp.requestVoid("POST", path`/seller-addresses/${addressId}/default`)
4968
5350
  },
5351
+ /**
5352
+ * 스토어프론트 호스팅 (이슈 #53) — 조회 `storefront:r`, 쓰기 `storefront:rw`(OWNER·ADMIN).
5353
+ * 쓰기 응답은 바뀐 사이트다. Cloudflare 반영은 커밋 뒤라 `provisioning.status`가 잠시 `PENDING`일 수 있다.
5354
+ * 에이전트 토큰의 발행·되돌리기·템플릿 변경·공개 전환·슬러그 변경·끄기는 승인 대기(`ApprovalPendingError`)다.
5355
+ */
5356
+ storefront: {
5357
+ /** `GET /v1/storefront/templates` — 템플릿 카탈로그 */
5358
+ listTemplates: () => storeHttp.request("GET", "/storefront/templates", z.array(storefrontTemplateSchema)),
5359
+ /** `GET /v1/storefront/site` — 스위치 상태와 현재 사이트(없으면 `site: null`) */
5360
+ get: () => storeHttp.request("GET", "/storefront/site", storefrontHostingSchema),
5361
+ /** `GET /v1/storefront/slug-availability?slug=` — 슬러그를 쓸 수 있는가 */
5362
+ checkSlug: (slug) => storeHttp.request("GET", "/storefront/slug-availability", storefrontSlugAvailabilitySchema, { query: { slug } }),
5363
+ /** `POST /v1/storefront/site` (201) — 템플릿으로 사이트를 만들고 v1을 발행한다. 공개 상태는 오픈 준비 중이다 */
5364
+ create: (body) => storeHttp.request("POST", "/storefront/site", storefrontSiteSchema, { body: createStorefrontSiteRequestSchema.parse(body) }),
5365
+ /** `POST /v1/storefront/site/template` — 템플릿을 바꾼다. 새 버전을 만들고 기본으로 곧바로 발행한다 */
5366
+ changeTemplate: (body) => storeHttp.request("POST", "/storefront/site/template", storefrontSiteSchema, { body: changeStorefrontTemplateRequestSchema.parse(body) }),
5367
+ /** `GET /v1/storefront/site/versions` — 버전 목록(최신 먼저) */
5368
+ listVersions: () => storeHttp.request("GET", "/storefront/site/versions", z.array(storefrontVersionSchema)),
5369
+ /** `POST /v1/storefront/site/versions/{versionId}/publish` — 그 버전을 발행한다(이미 발행돼 있으면 그대로 200) */
5370
+ publish: (versionId, body = {}) => storeHttp.request("POST", path`/storefront/site/versions/${versionId}/publish`, storefrontSiteSchema, { body: publishStorefrontVersionRequestSchema.parse(body) }),
5371
+ /** `POST /v1/storefront/site/rollback` — 이전 발행 버전으로 되돌린다(재빌드 없음) */
5372
+ rollback: (body = {}) => storeHttp.request("POST", "/storefront/site/rollback", storefrontSiteSchema, { body: rollbackStorefrontRequestSchema.parse(body) }),
5373
+ /** `PUT /v1/storefront/site/slug` — 슬러그를 바꾼다. 옛 슬러그는 90일 보류되고 새 주소로 301한다 */
5374
+ changeSlug: (body) => storeHttp.request("PUT", "/storefront/site/slug", storefrontSiteSchema, { body: changeStorefrontSlugRequestSchema.parse(body) }),
5375
+ /** `PUT /v1/storefront/site/visibility` — 오픈 준비 중 ↔ 공개 */
5376
+ setVisibility: (body) => storeHttp.request("PUT", "/storefront/site/visibility", storefrontSiteSchema, { body: setStorefrontVisibilityRequestSchema.parse(body) }),
5377
+ /**
5378
+ * `POST /v1/storefront/site/preview-link` — 오픈 준비 중인 사이트를 구성원이 볼 수 있는 5분짜리 링크.
5379
+ * 콘솔에서 로그인한 OWNER·ADMIN만 받는다
5380
+ */
5381
+ createPreviewLink: (body = {}) => storeHttp.request("POST", "/storefront/site/preview-link", storefrontPreviewLinkSchema, { body: createStorefrontPreviewLinkRequestSchema.parse(body) }),
5382
+ /** `POST /v1/storefront/site/disable` — 호스팅을 끈다(사이트 `CLOSED`, 슬러그 90일 보류). 다시 만들 수 있다 */
5383
+ disable: (body) => storeHttp.request("POST", "/storefront/site/disable", storefrontSiteSchema, { body: disableStorefrontHostingRequestSchema.parse(body) })
5384
+ },
4969
5385
  store: {
4970
5386
  get: () => storeHttp.request("GET", "/store", storeSchema),
4971
5387
  /**
@@ -5094,7 +5510,8 @@ const STORE_SCOPE_RESOURCES = {
5094
5510
  member: ["r", "rw"],
5095
5511
  customer: ["r", "rw"],
5096
5512
  audit: ["r"],
5097
- promotion: ["r", "rw"]
5513
+ promotion: ["r", "rw"],
5514
+ storefront: ["r", "rw"]
5098
5515
  };
5099
5516
  const storeScopeResourceSchema = z.enum(Object.keys(STORE_SCOPE_RESOURCES)).describe("스코프 리소스");
5100
5517
  /** 카탈로그상 존재하는 스코프 문자열인가 (예: `settlement:rw`는 false) */
@@ -5123,7 +5540,8 @@ const STORE_ROLE_SCOPES = {
5123
5540
  "member:rw",
5124
5541
  "customer:rw",
5125
5542
  "audit:r",
5126
- "promotion:rw"
5543
+ "promotion:rw",
5544
+ "storefront:rw"
5127
5545
  ],
5128
5546
  ADMIN: [
5129
5547
  "product:rw",
@@ -5138,7 +5556,8 @@ const STORE_ROLE_SCOPES = {
5138
5556
  "member:rw",
5139
5557
  "customer:rw",
5140
5558
  "audit:r",
5141
- "promotion:rw"
5559
+ "promotion:rw",
5560
+ "storefront:rw"
5142
5561
  ],
5143
5562
  STAFF: [
5144
5563
  "product:rw",
@@ -5203,7 +5622,7 @@ const orderWebhookEventDataSchema = z.object({
5203
5622
  testPayment: z.boolean().optional().default(false).describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았다. 이 필드가 없는 이전 이벤트는 false로 읽는다"),
5204
5623
  couponDiscountAmount: z.number().int().optional().default(0).describe("주문이 받은 상품·주문 쿠폰 할인 합계 (원). 즉시할인(`discountAmount`)과 별개다. 쿠폰이 없거나 이 필드가 없는 이전 이벤트는 0으로 읽는다"),
5205
5624
  orderItemId: z.string().optional().describe("이벤트를 만든 주문상품 ID. 비실물 상품 제공으로 보내는 `ORDER.DELIVERED`에만 실린다. 택배 배송완료와 그 밖의 주문 이벤트에는 없다"),
5206
- fulfillmentType: z.string().optional().describe("이벤트를 만든 주문상품의 상품 유형. 비실물 상품의 제공 완료는 `ORDER.DELIVERED`로도 오고 이 값이 `SHIPPING`이 아니다. 현재 값은 `SHIPPING`·`DOWNLOAD`·`CODE`·`SERVICE`·`PICKUP`이고 값이 추가될 수 있어 문자열로 받는다. 비실물 제공이 아닌 이벤트에는 없고, 없으면 `SHIPPING`으로 읽는다")
5625
+ fulfillmentSnapshot: orderItemFulfillmentSnapshotResponseSchema.optional().describe("이벤트를 만든 주문상품의 주문 시점 이행 스냅샷(주문상품 응답의 `fulfillmentSnapshot`과 같다, 이슈 #57). 비실물 상품의 제공 완료는 `ORDER.DELIVERED`로도 오고 `type`이 `SHIPPING`이 아니다. `orderItemId`가 있는 이벤트에만 실린다")
5207
5626
  });
5208
5627
  /**
5209
5628
  * `ORDER.FULFILLED` — 비실물 주문상품(파일·코드·이용권·방문 수령)을 제공했다(이슈 #48). 자동 제공은 결제 확정과 함께,
@@ -5214,8 +5633,8 @@ const orderFulfilledWebhookEventDataSchema = z.object({
5214
5633
  orderId: z.string().describe("주문 ID"),
5215
5634
  orderItemId: z.string().describe("제공한 주문상품 ID"),
5216
5635
  status: orderItemStatusSchema.describe("이벤트 발생 시점의 주문 대표 상태"),
5217
- fulfillmentType: z.string().describe("상품 유형. 현재 값은 `DOWNLOAD`·`CODE`·`SERVICE`·`PICKUP`이고 값이 추가될 수 있어 문자열로 받는다"),
5218
- fulfillmentMode: z.string().nullable().describe("제공 방식. `AUTO`(결제 확정과 함께)·`MANUAL`(셀러 제공 처리)"),
5636
+ fulfillmentSnapshot: orderItemFulfillmentSnapshotResponseSchema.describe("제공한 주문상품의 주문 시점 이행 스냅샷(주문상품 응답의 `fulfillmentSnapshot`과 같다, 이슈 #57)"),
5637
+ fulfillment: z.object({ mode: z.string().describe("실제 제공 방식. `AUTO`(결제 확정과 함께)·`MANUAL`(셀러 제공 처리). 주문상품 제공 기록의 `mode`와 같다") }).describe("제공 기록"),
5219
5638
  fulfilledAt: z.string().describe("제공 시각 (ISO 8601). 주문상품의 `deliveredAt`과 같다"),
5220
5639
  testPayment: z.boolean().describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 오가지 않았다")
5221
5640
  });
@@ -5474,4 +5893,4 @@ function createStoreSession(options) {
5474
5893
  };
5475
5894
  }
5476
5895
  //#endregion
5477
- export { APPROVAL_ALREADY_DECIDED_CODE, APPROVAL_REQUIRED_CODE, ApiError, ApprovalPendingError, CASH_RECEIPT_STATUS_VALUES, COUPON_CODE_PATTERN, COUPON_CONDITIONS_DEFAULTS, COUPON_TARGET_ALL, COUPON_TARGET_LIST_MAX, FULFILLMENT_RULES, MAX_ANALYTICS_ALLOWED_ORIGINS, MAX_AUTO_TRANSITION_DAYS, MAX_CODES_PER_UPLOAD, MAX_CODE_LENGTH, MAX_OPTION_GROUPS, MAX_PRODUCT_IMAGES, MAX_VALUES_PER_GROUP, MAX_VARIANTS, MCP_TELEMETRY_MAX_RESULTS, MIN_PAYMENT_AMOUNT, NO_COUPON_SETTLEMENT, NO_SHIPPING_BUNDLE_KEY, PAYMENT_ROUTING_EXCLUSION_CODES, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, PRIVATE_UPLOAD_HEADERS, REFUND_POLICY_DEFAULTS, REMOTE_AREA_ZIP_RANGES, RESERVED_STORE_CODES, SHIPPING_POLICY_DEFAULTS, STORE_CODE_PATTERN, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, UPLOAD_PURPOSE_LIMITS, 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, addressChangeRequestListSchema, addressTypeSchema, agentPolicyDecisionSchema, allocateByWeight, analyticsChannelSchema, analyticsCheckoutOutcomeSchema, analyticsCheckoutSchema, analyticsDeviceRowSchema, analyticsDevicesSchema, analyticsFunnelStepSchema, analyticsOriginSchema, analyticsOverviewSchema, analyticsPagesQuerySchema, analyticsPagesSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsRealtimeSchema, analyticsSearchQuerySchema, analyticsSearchSchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiClientListQuerySchema, apiClientSchema, apiClientSecretRotatedSchema, apiClientStatusSchema, apiClientTypeSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, apiTokenCreateRequestSchema, apiTokenCreatedSchema, apiTokenSchema, approvalDecisionRequestSchema, approvalListQuerySchema, approvalPageSchema, approvalRequestSchema, approvalStatusSchema, approveClaimResultSchema, auditActorSchema, auditActorTypeSchema, auditLogListQuerySchema, auditLogOutcomeSchema, auditLogPageSchema, auditLogSchema, auditLogSourceSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, cashReceiptSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeTypeSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimReturnAddressSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, clientCredentialsTokenResponseSchema, consentActionSchema, consentKindSchema, consentSourceSchema, couponBenefitSchema, couponConditionsInputSchema, couponConditionsSchema, couponDiscountOf, couponIssueListQuerySchema, couponIssueMethodSchema, couponIssueSchema, couponIssueStatusSchema, couponKindSchema, couponListQuerySchema, couponRedemptionListQuerySchema, couponRedemptionSchema, couponRejectReasonSchema, couponRuleSchema, couponSchema, couponStatsSchema, couponStatusSchema, couponTargetInputSchema, couponTargetSchema, createCouponRequestSchema, createPkcePair, createStoreClient, createStoreSession, customerAddressSchema, customerConsentListQuerySchema, customerConsentSchema, customerConsentStateSchema, customerConsentsSchema, customerCouponSchema, customerDetailSchema, customerInquiryCategorySchema, customerInquiryListQuerySchema, customerListQuerySchema, customerOrderSchema, customerSortSchema, customerStatsSchema, customerSummarySchema, customerWithdrawalBlockedDetailsSchema, deliveryBundleKeyOf, deliveryFeeWaiverSchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, digitalAssetAttachRequestSchema, digitalAssetPreviewSchema, digitalAssetSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, easyPayProviderResponseSchema, easyPayProviderSchema, eventTypeSchema, exchangeAuthorizationCode, exchangeStoreTokenViaOAuth, fulfillBulkRequestSchema, fulfillRequestSchema, fulfillmentCodeBatchSchema, fulfillmentCodeListQuerySchema, fulfillmentCodePageSchema, fulfillmentCodeRejectionSchema, fulfillmentCodeRevealSchema, fulfillmentCodeSchema, fulfillmentCodeStatusSchema, fulfillmentCodeUploadRequestSchema, fulfillmentMailResendSchema, fulfillmentModeSchema, fulfillmentRuleOf, fulfillmentTypeOf, fulfillmentTypeResponseSchema, fulfillmentTypeSchema, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, invitationDeliveryStatusSchema, invitationListQuerySchema, invitationSchema, inviteMemberRequestSchema, isCouponTargetLine, isReservedStoreCode, isStoreScope, isWebOrigin, issueCouponRequestSchema, issueCouponResultSchema, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, loginProviderSchema, loginProviderStatusSchema, loginProviderTestSchema, loginSettingsSchema, maskedSecretSchema, mcpRuleResultSchema, mcpToolEventSchema, myAccountSchema, myStoreSchema, normalizeCouponCode, oauthClientRegistrationRequestSchema, oauthClientRegistrationResponseSchema, oauthTokenResponseSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionValueRequestSchema, optionValueSchema, orderCanceledWebhookEventDataSchema, orderCanceledWebhookEventSchema, orderDiscountSchema, orderFulfilledWebhookEventDataSchema, orderFulfilledWebhookEventSchema, orderItemCodeSchema, orderItemDownloadSchema, orderItemFulfillmentSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentSettingsSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, policyDocumentUrlSchema, policyVersionSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productImageRejection, productImageUrlSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productRefundPolicyOverride, productRefundPolicyPatchSchema, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, proratedPaidRefundBase, proratedRefundBase, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, quoteDelivery, quotePricing, refreshUserToken, refundPolicyPatchSchema, refundPolicySchema, rejectClaimRequestSchema, remoteAreaLabelOf, remoteAreaOf, remoteAreaSchema, remoteSurchargeOf, requiresCollection, requiresShipping, resolveFulfillmentMode, resolveRefundPolicy, resolveShippingPolicy, reviewListQuerySchema, reviewReportResultSchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, saveLoginProviderRequestSchema, scopeAccessSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCustomerInquirySchema, settleCouponShortfall, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, shippingPolicyPatchSchema, shippingPolicySchema, storeCodeSchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeTokenResponseSchema, tossPaymentsCredentialsInputSchema, trackingStageResponseSchema, trackingUpdateResultSchema, updateCouponRequestSchema, updateLoginProviderRequestSchema, updateLoginSettingsRequestSchema, updateMemberRoleRequestSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, updateStoreRequestSchema, uploadExtensionOf, uploadPurposeSchema, uploadRejection, uploadRequestSchema, uploadTicketSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, userTokenResponseSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryDetailSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliveryResourceSchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookFailureReasonSchema, webhookRedeliverFailedResultSchema, webhookRequestHeaderSchema, webhookRequestSchema, webhookResourceTypeSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema, withdrawCustomerRequestSchema, writeDryRunResultSchema, writePreviewSchema };
5896
+ export { APPROVAL_ALREADY_DECIDED_CODE, APPROVAL_REQUIRED_CODE, ApiError, ApprovalPendingError, CASH_RECEIPT_STATUS_VALUES, COUPON_CODE_PATTERN, COUPON_CONDITIONS_DEFAULTS, COUPON_TARGET_ALL, COUPON_TARGET_LIST_MAX, DOWNLOAD_DEFAULTS, FULFILLMENT_RULES, MAX_ANALYTICS_ALLOWED_ORIGINS, MAX_AUTO_TRANSITION_DAYS, MAX_CODES_PER_UPLOAD, MAX_CODE_LENGTH, MAX_OPTION_GROUPS, MAX_PRODUCT_IMAGES, MAX_VALUES_PER_GROUP, MAX_VARIANTS, MCP_TELEMETRY_MAX_RESULTS, MIN_PAYMENT_AMOUNT, NO_COUPON_SETTLEMENT, NO_SHIPPING_BUNDLE_KEY, PAYMENT_ROUTING_EXCLUSION_CODES, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, PRIVATE_UPLOAD_HEADERS, REFUND_POLICY_DEFAULTS, REFUND_POLICY_DELIVERY_FEE_KEYS, REMOTE_AREA_ZIP_RANGES, RESERVED_STOREFRONT_SLUGS, RESERVED_STORE_CODES, SHIPPING_POLICY_DEFAULTS, STOREFRONT_SITE_CREATE_LIMIT, STOREFRONT_SLUG_CHANGE_LIMIT, STOREFRONT_SLUG_CHANGE_WINDOW_DAYS, STOREFRONT_SLUG_HOLD_DAYS, STOREFRONT_SLUG_PATTERN, STORE_CODE_PATTERN, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, UPLOAD_PURPOSE_LIMITS, 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, addressChangeRequestListSchema, addressTypeSchema, agentPolicyDecisionSchema, allocateByWeight, analyticsChannelSchema, analyticsCheckoutOutcomeSchema, analyticsCheckoutSchema, analyticsDeviceRowSchema, analyticsDevicesSchema, analyticsFunnelStepSchema, analyticsOriginSchema, analyticsOverviewSchema, analyticsPagesQuerySchema, analyticsPagesSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsRealtimeSchema, analyticsSearchQuerySchema, analyticsSearchSchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiClientListQuerySchema, apiClientSchema, apiClientSecretRotatedSchema, apiClientStatusSchema, apiClientTypeSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, apiTokenCreateRequestSchema, apiTokenCreatedSchema, apiTokenSchema, approvalDecisionRequestSchema, approvalListQuerySchema, approvalPageSchema, approvalRequestSchema, approvalStatusSchema, approveClaimResultSchema, auditActorSchema, auditActorTypeSchema, auditLogListQuerySchema, auditLogOutcomeSchema, auditLogPageSchema, auditLogSchema, auditLogSourceSchema, autoFulfillableOf, buildAuthorizeUrl, buildQuery, bulkResultSchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, cashReceiptSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeStorefrontSlugRequestSchema, changeStorefrontTemplateRequestSchema, changeTypeSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimReturnAddressSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, clientCredentialsTokenResponseSchema, consentActionSchema, consentKindSchema, consentSourceSchema, couponBenefitSchema, couponConditionsInputSchema, couponConditionsSchema, couponDiscountOf, couponIssueListQuerySchema, couponIssueMethodSchema, couponIssueSchema, couponIssueStatusSchema, couponKindSchema, couponListQuerySchema, couponRedemptionListQuerySchema, couponRedemptionSchema, couponRejectReasonSchema, couponRuleSchema, couponSchema, couponStatsSchema, couponStatusSchema, couponTargetInputSchema, couponTargetSchema, createCouponRequestSchema, createPkcePair, createStoreClient, createStoreSession, createStorefrontPreviewLinkRequestSchema, createStorefrontSiteRequestSchema, customerAddressSchema, customerConsentListQuerySchema, customerConsentSchema, customerConsentStateSchema, customerConsentsSchema, customerCouponSchema, customerDetailSchema, customerInquiryCategorySchema, customerInquiryListQuerySchema, customerListQuerySchema, customerOrderSchema, customerSortSchema, customerStatsSchema, customerSummarySchema, customerWithdrawalBlockedDetailsSchema, deliveryBundleKeyOf, deliveryFeeWaiverSchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, digitalAssetAttachRequestSchema, digitalAssetPreviewSchema, digitalAssetSchema, disableStorefrontHostingRequestSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, easyPayProviderResponseSchema, easyPayProviderSchema, eventTypeSchema, exchangeAuthorizationCode, exchangeStoreTokenViaOAuth, fulfillBulkRequestSchema, fulfillRequestSchema, fulfillmentCodeBatchSchema, fulfillmentCodeListQuerySchema, fulfillmentCodePageSchema, fulfillmentCodeRejectionSchema, fulfillmentCodeRevealSchema, fulfillmentCodeSchema, fulfillmentCodeStatusSchema, fulfillmentCodeUploadRequestSchema, fulfillmentMailResendSchema, fulfillmentModeOf, fulfillmentModeSchema, fulfillmentRuleOf, fulfillmentTypeOf, fulfillmentTypeResponseSchema, fulfillmentTypeSchema, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, invitationDeliveryStatusSchema, invitationListQuerySchema, invitationSchema, inviteMemberRequestSchema, isCouponTargetLine, isReservedStoreCode, isReservedStorefrontSlug, isStoreScope, isWebOrigin, issueCouponRequestSchema, issueCouponResultSchema, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, loginProviderSchema, loginProviderStatusSchema, loginProviderTestSchema, loginSettingsSchema, maskedSecretSchema, mcpRuleResultSchema, mcpToolEventSchema, myAccountSchema, myStoreSchema, normalizeCouponCode, oauthClientRegistrationRequestSchema, oauthClientRegistrationResponseSchema, oauthTokenResponseSchema, openFulfillmentUnion, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionValueRequestSchema, optionValueSchema, orderCanceledWebhookEventDataSchema, orderCanceledWebhookEventSchema, orderDiscountSchema, orderFulfilledWebhookEventDataSchema, orderFulfilledWebhookEventSchema, orderItemCodeSchema, orderItemDownloadSchema, orderItemFulfillmentSchema, orderItemFulfillmentSnapshotResponseSchema, orderItemFulfillmentSnapshotSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentSettingsSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, 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, proratedRefundBase, publishStorefrontVersionRequestSchema, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, quoteDelivery, quotePricing, refreshUserToken, refundPolicyPatchSchema, refundPolicySchema, rejectClaimRequestSchema, remoteAreaLabelOf, remoteAreaOf, remoteAreaSchema, remoteSurchargeOf, requiresCollection, requiresShipping, resolveFulfillmentMode, resolveRefundPolicy, resolveShippingPolicy, reviewListQuerySchema, reviewReportResultSchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, rollbackStorefrontRequestSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, saveLoginProviderRequestSchema, scopeAccessSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCustomerInquirySchema, setStorefrontVisibilityRequestSchema, settleCouponShortfall, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, shippingPolicyPatchSchema, shippingPolicySchema, stockTrackingOf, storeCodeSchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeTokenResponseSchema, storefrontDomainSchema, storefrontHostingSchema, storefrontPreviewLinkSchema, storefrontProvisioningSchema, storefrontSiteSchema, storefrontSiteStatusSchema, storefrontSlugAvailabilityQuerySchema, storefrontSlugAvailabilitySchema, storefrontSlugSchema, storefrontSourceModeSchema, storefrontTemplateSchema, storefrontVersionSchema, storefrontVersionStatusSchema, storefrontVisibilitySchema, tossPaymentsCredentialsInputSchema, trackingStageResponseSchema, trackingUpdateResultSchema, updateCouponRequestSchema, updateLoginProviderRequestSchema, updateLoginSettingsRequestSchema, updateMemberRoleRequestSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, updateStoreRequestSchema, uploadExtensionOf, uploadPurposeSchema, uploadRejection, uploadRequestSchema, uploadTicketSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, userTokenResponseSchema, usesCodePool, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryDetailSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliveryResourceSchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookFailureReasonSchema, webhookRedeliverFailedResultSchema, webhookRequestHeaderSchema, webhookRequestSchema, webhookResourceTypeSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema, withdrawCustomerRequestSchema, withdrawalRestrictedOf, writeDryRunResultSchema, writePreviewSchema };