@sayren/store-sdk 0.28.0 → 0.28.1

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
@@ -13,7 +13,7 @@ const auditActorTypeSchema = z.enum([
13
13
  "APP",
14
14
  "TOKEN",
15
15
  "SYSTEM"
16
- ]).describe("행위자 유형. `USER`=콘솔 사용자, `AGENT`=AI 에이전트(MCP·에이전트용 API 토큰), `APP`=앱(OAuth 클라이언트·M2M), `TOKEN`=API 토큰, `SYSTEM`=자동화(주기 잡)");
16
+ ]).describe("행위자 유형. `USER`=상점 플랫폼 사용자, `AGENT`=AI 에이전트(MCP·에이전트용 API 토큰), `APP`=앱(OAuth 클라이언트·M2M), `TOKEN`=API 토큰, `SYSTEM`=자동화(주기 잡)");
17
17
  const auditActorSchema = z.object({
18
18
  type: auditActorTypeSchema,
19
19
  id: z.string().describe("행위자 ID. `USER`=userId, `TOKEN`·`AGENT`(API 토큰)=`pat:{tokenId}`, `APP`=`client:{clientId}`, `SYSTEM`=`system`. 사람이 앱에 위임한 호출은 `APP`이고 위임한 사람은 `metadata.onBehalfOf`에 있다"),
@@ -33,7 +33,7 @@ const auditLogSchema = z.object({
33
33
  source: auditLogSourceSchema,
34
34
  action: z.string().describe("동작. `REQUEST`는 오퍼레이션 ID(OpenAPI `operationId`, 예: `ProductsController_patch`), `DOMAIN`은 도메인 코드(예: `ORDER_ITEM_CANCELED_BY_SELLER`)"),
35
35
  actor: auditActorSchema,
36
- actorRole: z.string().nullable().describe("요청 시점의 스토어 역할. 역할이 없는 토큰·자동화는 null"),
36
+ actorRole: z.string().nullable().describe("요청 시점의 상점 역할. 역할이 없는 토큰·자동화는 null"),
37
37
  target: z.object({
38
38
  type: z.string().describe("대상 리소스 유형 (예: `products`, `order-items`, `claim`)"),
39
39
  id: z.string().nullable().describe("대상 리소스 ID. 목록 대상 요청처럼 하나로 정할 수 없으면 null")
@@ -77,7 +77,7 @@ const agentPolicyDecisionSchema = z.enum([
77
77
  "ALLOW",
78
78
  "APPROVAL_REQUIRED",
79
79
  "DENIED"
80
- ]).describe("에이전트 쓰기 판정. `ALLOW`=바로 실행, `APPROVAL_REQUIRED`=콘솔 승인 뒤 실행, `DENIED`=에이전트는 실행할 수 없음");
80
+ ]).describe("에이전트 쓰기 판정. `ALLOW`=바로 실행, `APPROVAL_REQUIRED`=상점 플랫폼 승인 뒤 실행, `DENIED`=에이전트는 실행할 수 없음");
81
81
  const previewValueSchema = z.union([
82
82
  z.string(),
83
83
  z.number(),
@@ -132,7 +132,7 @@ const approvalRequestSchema = z.object({
132
132
  decidedBy: z.object({
133
133
  id: z.string(),
134
134
  name: z.string().nullable()
135
- }).nullable().describe("승인·거절한 콘솔 사용자"),
135
+ }).nullable().describe("승인·거절한 상점 플랫폼 사용자"),
136
136
  decisionNote: z.string().nullable().describe("승인·거절 메모"),
137
137
  executedAt: z.string().nullable().describe("원 요청 실행을 마친 일시"),
138
138
  result: z.object({
@@ -143,7 +143,7 @@ const approvalRequestSchema = z.object({
143
143
  message: z.string()
144
144
  }).nullable().describe("실패 응답의 `error` 요약")
145
145
  }).nullable().describe("실행 결과. `SUCCEEDED`·`FAILED`·`UNKNOWN`에서 값이 있다. 감사 로그로 확정한 결과는 `data`가 null이다"),
146
- approvalUrl: z.string().nullable().describe("셀러 콘솔의 승인 화면 주소. 이 배포의 콘솔 주소를 알 수 없으면 null")
146
+ approvalUrl: z.string().nullable().describe("상점 플랫폼의 승인 화면 주소. 이 배포의 상점 플랫폼 주소를 알 수 없으면 null")
147
147
  });
148
148
  const approvalListQuerySchema = z.object({
149
149
  status: commaList(approvalStatusSchema).optional().describe("상태 필터. 여러 개는 쉼표로 구분한다 (예: `PENDING,EXECUTING`)"),
@@ -224,7 +224,7 @@ const APPROVAL_ALREADY_DECIDED_CODE = "APPROVAL_ALREADY_DECIDED";
224
224
  * 성공 값으로 돌려주지 않는다 — 돌려주면 호출부가 승인 요청을 상품·주문으로 읽는다.
225
225
  *
226
226
  * - `code = APPROVAL_REQUIRED`(202): 에이전트의 고위험 쓰기가 보류됐다. 아직 아무것도 바뀌지 않았다.
227
- * 셀러가 콘솔(`approval.approvalUrl`)에서 승인하면 서버가 원 요청을 실행한다. 같은 요청을 다시 보내지 말고
227
+ * 셀러가 상점 플랫폼(`approval.approvalUrl`)에서 승인하면 서버가 원 요청을 실행한다. 같은 요청을 다시 보내지 말고
228
228
  * `approvalRequests.get(approvalId)`로 결과를 확인한다.
229
229
  * - `code = APPROVAL_ALREADY_DECIDED`(200): 같은 멱등키로 보낸 요청의 승인이 이미 끝났다. `status`가
230
230
  * `SUCCEEDED`·`FAILED`·`UNKNOWN`이면 실행 결과(`approval.result`)를 보고, `REJECTED`·`EXPIRED`면 새 멱등키로 다시 요청한다.
@@ -552,15 +552,15 @@ const analyticsCheckoutSchema = z.object({
552
552
  //#endregion
553
553
  //#region src/schemas/api-log.ts
554
554
  /**
555
- * API 로그 — `/v1/api-logs`. 스토어가 해석된 관리 API(`/v1/**`) 요청을 7일간 보관한다.
556
- * 인증에 실패해 스토어를 알 수 없는 요청(401 등)은 기록되지 않는다.
555
+ * API 로그 — `/v1/api-logs`. 상점이 해석된 관리 API(`/v1/**`) 요청을 7일간 보관한다.
556
+ * 인증에 실패해 상점을 알 수 없는 요청(401 등)은 기록되지 않는다.
557
557
  * Authorization·쿠키 헤더, 요청 본문, 개인정보는 저장하지 않는다.
558
558
  */
559
559
  const apiLogPrincipalTypeSchema = z.enum([
560
560
  "USER",
561
561
  "PAT",
562
562
  "CLIENT"
563
- ]).describe("호출 주체 유형. `USER`=콘솔 사용자, `PAT`=API 토큰, `CLIENT`=앱(OAuth 클라이언트)");
563
+ ]).describe("호출 주체 유형. `USER`=상점 플랫폼 사용자, `PAT`=API 토큰, `CLIENT`=앱(OAuth 클라이언트)");
564
564
  const apiLogPrincipalSchema = z.object({
565
565
  type: apiLogPrincipalTypeSchema,
566
566
  id: z.string().describe("호출 주체 ID. `USER`=userId, `PAT`=API 토큰 ID, `CLIENT`=clientId"),
@@ -607,11 +607,11 @@ const apiLogPageSchema = z.object({
607
607
  });
608
608
  /**
609
609
  * API 로그 요약 — `GET /api-logs/summary`. 연동 트래픽(호출 주체 `PAT`·`CLIENT`)만 집계하며
610
- * 콘솔 사용자(`USER`) 요청은 제외한다
610
+ * 상점 플랫폼 사용자(`USER`) 요청은 제외한다
611
611
  */
612
612
  const apiLogSummarySchema = z.object({
613
613
  windowHours: z.number().int().describe("집계 구간(시간). 최근 24시간"),
614
- total: z.number().int().min(0).describe("구간 내 연동 요청 수 (호출 주체 `PAT`·`CLIENT`, 콘솔 사용자 제외)"),
614
+ total: z.number().int().min(0).describe("구간 내 연동 요청 수 (호출 주체 `PAT`·`CLIENT`, 상점 플랫폼 사용자 제외)"),
615
615
  errors: z.number().int().min(0).describe("구간 내 연동 요청 중 4xx·5xx 응답 수"),
616
616
  serverErrors: z.number().int().min(0).describe("구간 내 연동 요청 중 5xx 응답 수")
617
617
  });
@@ -810,10 +810,10 @@ const claimReasonSchema = z.enum([
810
810
  "DELAY"
811
811
  ]);
812
812
  /**
813
- * 반품지 (이슈 #30) — 반품·교환 수거가 안내하는 주소다. 스토어 주소록의 기본 반품지이거나,
813
+ * 반품지 (이슈 #30) — 반품·교환 수거가 안내하는 주소다. 상점 주소록의 기본 반품지이거나,
814
814
  * 상품이 반품지를 따로 지정했으면 그 주소다.
815
815
  *
816
- * 취소 클레임은 보낼 물건이 없어 null이고, 반품지를 등록하지 않은 스토어도 null이다.
816
+ * 취소 클레임은 보낼 물건이 없어 null이고, 반품지를 등록하지 않은 상점도 null이다.
817
817
  * 구매자가 직접 보내는 수거(`BUYER_SEND`)에 이 주소가 필요하다.
818
818
  */
819
819
  const claimReturnAddressSchema = z.object({
@@ -854,7 +854,7 @@ const claimSchema = z.object({
854
854
  holdExpiresAt: z.string().nullable(),
855
855
  /** 보류를 이미 썼는지 — 보류는 클레임당 1회라 해제·만료 뒤에도 true */
856
856
  holdUsed: z.boolean(),
857
- returnAddress: claimReturnAddressSchema.nullable().describe("수거 안내에 쓸 반품지(이슈 #30). 상품이 지정한 반품지, 없으면 스토어 기본 반품지다. 취소 클레임과 반품지를 등록하지 않은 스토어는 null")
857
+ returnAddress: claimReturnAddressSchema.nullable().describe("수거 안내에 쓸 반품지(이슈 #30). 상품이 지정한 반품지, 없으면 상점 기본 반품지다. 취소 클레임과 반품지를 등록하지 않은 상점은 null")
858
858
  });
859
859
  /** `GET /v1/claims` 쿼리 — OpenAPI 문서용 형태(값은 쿼리 문자열) */
860
860
  const claimListQuerySchema = z.object({
@@ -907,9 +907,9 @@ const approveClaimResultSchema = z.object({
907
907
  /**
908
908
  * 환불 정책 (이슈 #25) — 취소·반품·교환에서 **배송비를 누가 부담하는지**를 정한다.
909
909
  *
910
- * 두 층이다. 스토어 설정(`PATCH /v1/store`의 `refundPolicy`)이 기본값이고, 상품별 정책
910
+ * 두 층이다. 상점 설정(`PATCH /v1/store`의 `refundPolicy`)이 기본값이고, 상품별 정책
911
911
  * (`POST/PUT /v1/products`의 `refundPolicy`)이 그 상품에만 덮어쓴다. 상품이 정하지 않은 항목은
912
- * 스토어 기본을 따르고, 스토어도 정하지 않았으면 `REFUND_POLICY_DEFAULTS`다.
912
+ * 상점 기본을 따르고, 상점도 정하지 않았으면 `REFUND_POLICY_DEFAULTS`다.
913
913
  *
914
914
  * 한 주문에 정책이 섞이면 **상품별로 계산한다**. 배송비 묶음도 상품 단위다(주문서·장바구니의
915
915
  * 배송비 합산과 같은 규칙: 같은 상품의 주문상품이 한 묶음이고 묶음마다 배송비가 붙는다).
@@ -922,7 +922,7 @@ const descriptions$3 = {
922
922
  conditionalFreeShortfallCharge: "조건부 무료배송(`CONDITIONAL_FREE`) 상품에서 일부 취소로 남은 금액이 무료 기준액에 미달하면 그 배송비를 환불액에서 뺀다. false면 추가 청구 없이 셀러가 부담한다. 기본 false",
923
923
  couponShortfallCharge: "쿠폰 조건 미달 차감. 일부 취소·반품으로 남은 주문상품이 쿠폰 조건(최소 주문 금액 등)을 잃으면 남은 주문상품이 받던 쿠폰 할인을 환불액에서 뺀다. 판매자 귀책(셀러 직권취소, 불량·오배송 반품)은 빼지 않는다. false면 차감 없이 실결제 금액만 나눠 환불한다. 기본 true"
924
924
  };
925
- /** 유효 환불 정책 — 스토어 기본 + 상품별 덮어쓰기를 합친 결과 */
925
+ /** 유효 환불 정책 — 상점 기본 + 상품별 덮어쓰기를 합친 결과 */
926
926
  const refundPolicySchema = z.object({
927
927
  preShipmentDeliveryFeeRefund: z.boolean().describe(descriptions$3.preShipmentDeliveryFeeRefund),
928
928
  returnDeliveryFee: z.number().int().min(0).describe(descriptions$3.returnDeliveryFee),
@@ -932,7 +932,7 @@ const refundPolicySchema = z.object({
932
932
  couponShortfallCharge: z.boolean().optional().default(true).describe(`${descriptions$3.couponShortfallCharge}. 이 필드가 없는 이전 서버 응답은 true로 읽는다`)
933
933
  });
934
934
  /**
935
- * 스토어가 정하지 않았을 때 서버가 쓰는 값.
935
+ * 상점이 정하지 않았을 때 서버가 쓰는 값.
936
936
  *
937
937
  * `as const`가 아니라 `RefundPolicy`로 타입을 좁힌다 — 리터럴 타입이면 `Partial<typeof …>`로 일부만 바꿀 때
938
938
  * `true` 자리에 `false`를 넣을 수 없다.
@@ -946,7 +946,7 @@ const REFUND_POLICY_DEFAULTS = {
946
946
  couponShortfallCharge: true
947
947
  };
948
948
  /**
949
- * 부분 정책 — 스토어 설정 요청과 상품별 덮어쓰기가 쓴다. 준 항목만 바뀐다.
949
+ * 부분 정책 — 상점 설정 요청과 상품별 덮어쓰기가 쓴다. 준 항목만 바뀐다.
950
950
  *
951
951
  * `strictObject`라 모르는 키는 400이다. 오타(`returnFee` 등)를 조용히 무시하면 셀러는 저장됐다고
952
952
  * 믿는데 정책은 기본값으로 남는다.
@@ -961,11 +961,11 @@ const refundPolicyPatchSchema = z.strictObject({
961
961
  });
962
962
  /**
963
963
  * 상품별 덮어쓰기 — 쿠폰 조건 미달 차감(`couponShortfallCharge`)은 주문 단위 규칙이라 상품이 정하지 않는다.
964
- * 스토어 정책만 읽는다(이슈 #47).
964
+ * 상점 정책만 읽는다(이슈 #47).
965
965
  */
966
966
  const productRefundPolicyPatchSchema = refundPolicyPatchSchema.omit({ couponShortfallCharge: true });
967
967
  /**
968
- * 유효 정책 해석 — 상품별 덮어쓰기 → 스토어 기본 → `REFUND_POLICY_DEFAULTS` 순이다.
968
+ * 유효 정책 해석 — 상품별 덮어쓰기 → 상점 기본 → `REFUND_POLICY_DEFAULTS` 순이다.
969
969
  *
970
970
  * 반품·교환 배송비의 원천은 정책 하나다(이슈 #57 결정 3). 상품의 레거시 반품비·교환비 필드와의 연결은 없앴고,
971
971
  * 레거시 값은 마이그레이션이 상품별 정책으로 옮겼다.
@@ -980,9 +980,9 @@ function resolveRefundPolicy(storePolicy, product) {
980
980
  /**
981
981
  * 상품의 **덮어쓰기 자체** — 덮어쓰기가 없으면 null.
982
982
  *
983
- * `resolveRefundPolicy`가 합친 결과로는 "상품이 정한 값"과 "스토어 기본을 물려받은 값"을 가를 수 없다.
984
- * 관리 API 응답의 `refundPolicy`와 콘솔 폼의 덮어쓰기 스위치가 이 함수를 원천으로 쓴다 — 가르지 못하면
985
- * 스토어 기본을 쓰는 상품을 저장할 때 그 순간의 기본값이 상품에 박힌다.
983
+ * `resolveRefundPolicy`가 합친 결과로는 "상품이 정한 값"과 "상점 기본을 물려받은 값"을 가를 수 없다.
984
+ * 관리 API 응답의 `refundPolicy`와 상점 플랫폼 폼의 덮어쓰기 스위치가 이 함수를 원천으로 쓴다 — 가르지 못하면
985
+ * 상점 기본을 쓰는 상품을 저장할 때 그 순간의 기본값이 상품에 박힌다.
986
986
  */
987
987
  function productRefundPolicyOverride(product) {
988
988
  if (product?.refundPolicy == null) return null;
@@ -1032,7 +1032,7 @@ function proratedRefundBase(totalPrice, quantity, settledQuantity, cancelQuantit
1032
1032
  * 4. 배송비 쿠폰(`DELIVERY`) — 주문에 한 장. 기본 배송비(지역 추가 배송비 제외)를 기준으로 할인하고
1033
1033
  * 배송 묶음에 기본 배송비 비율로 나눈다.
1034
1034
  *
1035
- * 무료배송 기준(상품별 조건부 무료·스토어 전체 기준)은 **쿠폰 차감 전 금액**으로 판정한다. 그래서 배송비
1035
+ * 무료배송 기준(상품별 조건부 무료·상점 전체 기준)은 **쿠폰 차감 전 금액**으로 판정한다. 그래서 배송비
1036
1036
  * 견적(`quoteDelivery`)은 쿠폰과 무관하게 먼저 계산되고, 이 함수는 그 결과만 입력으로 받는다.
1037
1037
  *
1038
1038
  * 최소 주문 금액은 대상 상품의 **즉시할인 반영 합계**(쿠폰 차감 전, 배송비 제외)로 판정한다.
@@ -1045,7 +1045,7 @@ const descriptions$2 = {
1045
1045
  benefitValue: "할인 값. `RATE`면 1~100(%), `AMOUNT`면 원 단위 금액",
1046
1046
  maxDiscountAmount: "정률 할인의 최대 할인액(원). null이면 상한이 없다. 정액 할인에는 쓰지 않는다(null)",
1047
1047
  minOrderAmount: "최소 주문 금액(원). 대상 상품의 즉시할인 반영 합계(배송비 제외)가 이 값 이상이어야 쓸 수 있다. 0이면 조건이 없다",
1048
- firstOrderOnly: "이 스토어에서 결제 완료 주문이 없는 회원만 쓸 수 있다",
1048
+ firstOrderOnly: "이 상점에서 결제 완료 주문이 없는 회원만 쓸 수 있다",
1049
1049
  memberOnly: "회원만 쓸 수 있다. false면 비회원도 쓸 수 있다 — 코드 입력형이면서 1인 한도가 없는 쿠폰만 false로 둘 수 있다",
1050
1050
  stackWithInstantDiscount: "상품 즉시할인과 함께 쓸 수 있다. false면 즉시할인이 걸린 주문상품은 쿠폰 대상에서 빠진다",
1051
1051
  includeProductIds: "대상 상품 id. 포함 목록(상품·카테고리)이 모두 비면 전 상품이 대상이다",
@@ -1552,7 +1552,7 @@ const limitField = (description) => z.number().int().min(1).max(1e7).nullable().
1552
1552
  const descriptions$1 = {
1553
1553
  name: "구매자에게 보이는 쿠폰 이름. 1~60자",
1554
1554
  description: "구매자에게 보이는 설명. 300자까지",
1555
- code: "쿠폰 코드 — 발급 방식이 `CODE`일 때 필수. 영문·숫자·`-`·`_` 6~30자, 대소문자 구분 없음(대문자로 저장). 스토어 안에서 유일하다",
1555
+ code: "쿠폰 코드 — 발급 방식이 `CODE`일 때 필수. 영문·숫자·`-`·`_` 6~30자, 대소문자 구분 없음(대문자로 저장). 상점 안에서 유일하다",
1556
1556
  startsAt: "사용 시작 시각(ISO 8601, 시간대 포함). 생략하면 바로 쓸 수 있다",
1557
1557
  endsAt: "사용 종료 시각(ISO 8601, 시간대 포함). 이 시각부터 못 쓴다. 생략하면 제한이 없다. 이미 지급한 쿠폰의 유효 기간은 지급 때 정해지므로 뒤에 종료일을 늦춰도 늘어나지 않는다",
1558
1558
  validDaysAfterIssue: "발급 후 유효 일수 — 셀러 지급(`MANUAL`) 쿠폰만. 쿠폰 종료일과 둘 중 먼저 끝나는 쪽이 적용된다",
@@ -1693,7 +1693,7 @@ const issueCouponResultSchema = z.object({
1693
1693
  })),
1694
1694
  failed: z.array(z.object({
1695
1695
  customerId: z.string(),
1696
- code: z.string().describe("실패 사유. `CUSTOMER_NOT_FOUND`(이 스토어 구매자가 아님)·`COUPON_LIMIT_REACHED`(1인 발급 한도)·`COUPON_EXHAUSTED`(총 발급 한도)"),
1696
+ code: z.string().describe("실패 사유. `CUSTOMER_NOT_FOUND`(이 상점 구매자가 아님)·`COUPON_LIMIT_REACHED`(1인 발급 한도)·`COUPON_EXHAUSTED`(총 발급 한도)"),
1697
1697
  message: z.string()
1698
1698
  }))
1699
1699
  });
@@ -1809,7 +1809,7 @@ const customerConsentSchema = z.object({
1809
1809
  kind: consentKindSchema,
1810
1810
  /** 동의한 약관 버전. 마케팅은 버전이 없어 null */
1811
1811
  version: z.string().nullable(),
1812
- /** 동의 시점의 약관 문서 주소. 스토어가 주소를 정하지 않았거나 마케팅이면 null */
1812
+ /** 동의 시점의 약관 문서 주소. 상점이 주소를 정하지 않았거나 마케팅이면 null */
1813
1813
  documentUrl: z.string().nullable(),
1814
1814
  action: consentActionSchema,
1815
1815
  source: consentSourceSchema,
@@ -1821,9 +1821,9 @@ const customerConsentStateSchema = z.object({
1821
1821
  agreed: z.boolean(),
1822
1822
  /** 동의한 약관 버전. 마케팅이거나 이력이 없으면 null */
1823
1823
  agreedVersion: z.string().nullable(),
1824
- /** 스토어의 현재 약관 버전. 마케팅은 null */
1824
+ /** 상점의 현재 약관 버전. 마케팅은 null */
1825
1825
  currentVersion: z.string().nullable(),
1826
- /** 스토어가 정한 현재 약관 문서 주소. 정하지 않았거나 마케팅이면 null */
1826
+ /** 상점이 정한 현재 약관 문서 주소. 정하지 않았거나 마케팅이면 null */
1827
1827
  currentDocumentUrl: z.string().nullable(),
1828
1828
  updatedAt: z.string().nullable(),
1829
1829
  /** 약관이 개정돼 다시 받아야 하는가. 마케팅은 항상 false */
@@ -2316,8 +2316,8 @@ const deliveryTypeSchema = z.enum([
2316
2316
  ]);
2317
2317
  const KNOWN_FULFILLMENT_TYPES = fulfillmentTypeSchema.options;
2318
2318
  const ADDRESS_ID_DESCRIPTIONS = {
2319
- shipping: "출고지 주소 id(`GET /v1/seller-addresses?type=SHIPPING`). 등록에서 생략하면 그 시점 스토어 기본 출고지를 저장한다. `null`이면 비워 둔다(스토어 기본 출고지를 따른다). 이 스토어의 `SHIPPING` 주소가 아니면 거부한다",
2320
- return: "반품지 주소 id(`GET /v1/seller-addresses?type=RETURN`). 등록에서 생략하면 그 시점 스토어 기본 반품지를 저장한다. `null`이면 비워 둔다(스토어 기본 반품지를 따른다). 이 스토어의 `RETURN` 주소가 아니면 거부한다"
2319
+ shipping: "출고지 주소 id(`GET /v1/seller-addresses?type=SHIPPING`). 등록에서 생략하면 그 시점 상점 기본 출고지를 저장한다. `null`이면 비워 둔다(상점 기본 출고지를 따른다). 이 상점의 `SHIPPING` 주소가 아니면 거부한다",
2320
+ return: "반품지 주소 id(`GET /v1/seller-addresses?type=RETURN`). 등록에서 생략하면 그 시점 상점 기본 반품지를 저장한다. `null`이면 비워 둔다(상점 기본 반품지를 따른다). 이 상점의 `RETURN` 주소가 아니면 거부한다"
2321
2321
  };
2322
2322
  /**
2323
2323
  * 배송비 필드 사이의 일관성 — FREE의 배송비, 조건부 무료가 아닌 상품의 무료 기준을 조용히 0·null로 바꿔 저장하지 않고 400으로 돌려준다
@@ -2345,13 +2345,13 @@ function refineShippingConsistency(value, ctx) {
2345
2345
  const deliveryTypeDescription = "배송비 유형. `FREE` 무료, `PAID` 유료, `CONDITIONAL_FREE` 조건부 무료";
2346
2346
  const shippingCreateSchema = z.strictObject({
2347
2347
  deliveryType: deliveryTypeSchema.default("PAID").describe(deliveryTypeDescription),
2348
- deliveryFee: z.number().int().min(0).optional().describe("배송비. 원 단위. 생략하면 스토어 기본 배송비(`GET /v1/store`의 `shippingPolicy.baseDeliveryFee`)를 저장한다. FREE면 0이거나 생략한다"),
2348
+ deliveryFee: z.number().int().min(0).optional().describe("배송비. 원 단위. 생략하면 상점 기본 배송비(`GET /v1/store`의 `shippingPolicy.baseDeliveryFee`)를 저장한다. FREE면 0이거나 생략한다"),
2349
2349
  conditionalFreeAmount: z.number().int().min(0).nullable().optional().describe("무료 배송이 되는 묶음 소계. 원 단위. CONDITIONAL_FREE에서만 받고 필수다"),
2350
2350
  shippingAddressId: z.string().nullable().optional().describe(ADDRESS_ID_DESCRIPTIONS.shipping),
2351
2351
  returnAddressId: z.string().nullable().optional().describe(ADDRESS_ID_DESCRIPTIONS.return)
2352
2352
  }).superRefine(refineShippingConsistency);
2353
2353
  /**
2354
- * 상품 이행 — 등록(POST). 배송 상품의 `shipping`을 생략하면 기본값(유료 배송·스토어 기본 배송비·기본 출고지·반품지)이다.
2354
+ * 상품 이행 — 등록(POST). 배송 상품의 `shipping`을 생략하면 기본값(유료 배송·상점 기본 배송비·기본 출고지·반품지)이다.
2355
2355
  */
2356
2356
  const productFulfillmentCreateSchema = z.discriminatedUnion("type", [z.strictObject({
2357
2357
  type: z.literal("SHIPPING"),
@@ -2382,8 +2382,8 @@ const productFulfillmentSchema = z.discriminatedUnion("type", [z.object({
2382
2382
  deliveryType: deliveryTypeSchema,
2383
2383
  deliveryFee: z.number().int().describe("배송비. 원 단위. FREE면 0"),
2384
2384
  conditionalFreeAmount: z.number().int().nullable().describe("조건부 무료 기준 묶음 소계. CONDITIONAL_FREE가 아니면 null"),
2385
- shippingAddressId: z.string().nullable().describe("출고지 주소 id. null이면 스토어 기본 출고지를 따른다"),
2386
- returnAddressId: z.string().nullable().describe("반품지 주소 id. null이면 스토어 기본 반품지를 따른다")
2385
+ shippingAddressId: z.string().nullable().describe("출고지 주소 id. null이면 상점 기본 출고지를 따른다"),
2386
+ returnAddressId: z.string().nullable().describe("반품지 주소 id. null이면 상점 기본 반품지를 따른다")
2387
2387
  })
2388
2388
  }), z.object({ type: z.literal("MANUAL") })]);
2389
2389
  /**
@@ -2407,16 +2407,16 @@ const orderItemFulfillmentSnapshotSchema = z.discriminatedUnion("type", [z.objec
2407
2407
  type: z.literal("SHIPPING"),
2408
2408
  shipping: z.object({
2409
2409
  bundleKey: z.string().nullable().describe("배송 묶음 키. 같은 키의 주문상품이 배송비를 한 번 낸 한 묶음이다. #29 이전 주문은 null"),
2410
- returnAddressId: z.string().nullable().describe("주문 시점 반품지 주소 id. null이거나 지워진 주소면 스토어 기본 반품지로 안내한다")
2410
+ returnAddressId: z.string().nullable().describe("주문 시점 반품지 주소 id. null이거나 지워진 주소면 상점 기본 반품지로 안내한다")
2411
2411
  })
2412
2412
  }), z.object({ type: z.literal("MANUAL") })]);
2413
2413
  const orderItemFulfillmentSnapshotResponseSchema = openFulfillmentUnion(orderItemFulfillmentSnapshotSchema).describe("주문 시점 이행 스냅샷. 상품을 나중에 고쳐도 바뀌지 않는다. 제공 기록은 `fulfillment`에 있다. 값이 추가될 수 있어 SDK는 모르는 유형을 `OTHER`로 읽는다");
2414
2414
  //#endregion
2415
2415
  //#region src/schemas/payment.ts
2416
2416
  /**
2417
- * 스토어 결제(PG) 설정과 매출 리포트 계약.
2417
+ * 상점 결제(PG) 설정과 매출 리포트 계약.
2418
2418
  *
2419
- * PG는 셀러가 직접 계약한다. 자격 증명은 스토어별로 저장되고, 비밀 값(시크릿 키·API Secret·
2419
+ * PG는 셀러가 직접 계약한다. 자격 증명은 상점별로 저장되고, 비밀 값(시크릿 키·API Secret·
2420
2420
  * 웹훅 시크릿)은 저장 후 다시 조회할 수 없다. 응답에는 앞 4자리 마스킹만 나온다. 공개 값
2421
2421
  * (클라이언트 키·Store ID·채널 키)은 원래 브라우저 결제창에 노출되는 값이라 그대로 돌려준다.
2422
2422
  */
@@ -2451,7 +2451,7 @@ const secretInput = () => z.string().trim().min(8).max(512);
2451
2451
  /**
2452
2452
  * 토스페이먼츠 결제위젯 키 접두사. 결제창은 API 개별 연동(`*_ck_`·`*_sk_`)만 쓴다. 위젯 키는 결제창 SDK가
2453
2453
  * `NOT_SUPPORTED_WIDGET_KEY`로, 서버 API가 404 `NOT_FOUND_MERCHANT`로 거부하므로 저장 전에 막는다.
2454
- * 요청 스키마·api 어댑터·콘솔 폼이 같은 상수를 쓴다(원천). `g` 플래그가 없어 `.test()`가 상태를 갖지 않는다.
2454
+ * 요청 스키마·api 어댑터·상점 플랫폼 폼이 같은 상수를 쓴다(원천). `g` 플래그가 없어 `.test()`가 상태를 갖지 않는다.
2455
2455
  */
2456
2456
  const TOSS_WIDGET_CLIENT_KEY_PATTERN = /^(test|live)_gck_/;
2457
2457
  /** 토스페이먼츠 결제위젯 시크릿 키 접두사. {@link TOSS_WIDGET_CLIENT_KEY_PATTERN} 참고 */
@@ -2572,7 +2572,7 @@ const paymentProviderSchema = z.object({
2572
2572
  liveGate: liveGateSchema.describe("라이브 개방 조건. 조건을 모두 충족해야 샌드박스를 끌 수 있다"),
2573
2573
  easyPayProviders: z.array(easyPayProviderResponseSchema).describe("이 PG로 받는 간편결제사. 연결되지 않았으면 빈 목록. 현재 값은 `NAVERPAY`·`KAKAOPAY`·`TOSSPAY`·`PAYCO`이고 값이 추가될 수 있어 문자열로 받는다"),
2574
2574
  retiredCredentialCount: z.number().int().describe("보관된(가맹점 교체·연결 해제로 새 결제에 더 쓰이지 않는) 자격 증명 수. 그 가맹점으로 받은 결제의 환불·대사에 계속 쓰인다"),
2575
- routingExclusion: z.string().nullable().optional().default(null).describe("지금 새 결제의 후보가 아닌 사유. 후보면 null. 판정 원천은 서버 라우팅이다(콘솔이 다시 계산하지 않는다). 후보가 아닌 PG에는 항상 사유 코드를 붙인다(연결 안 된 PG 포함) — 모든 PG는 `candidates`에 있거나 이 값이 null이 아니다. 현재 값: `NOT_CONNECTED`(연결 안 됨) · `DISABLED`(사용 중지) · `CREDENTIAL_MISSING`(활성 환경 자격 증명 없음) · `SANDBOX_IN_LIVE_STORE`(다른 PG가 라이브라 이 샌드박스 PG는 실구매자 결제에 쓰지 않음) · `PLATFORM_BLOCKED`(플랫폼이 실결제를 막음) · `MODE_MISMATCH`(라이브를 연 서버 모드와 현재 모드가 다름). 값이 추가될 수 있어 문자열로 받는다 — 모르는 값은 후보 아님으로 다룬다. 서버는 항상 싣는다. 이 필드가 없는 이전 서버 응답은 기본값(null)으로 읽는다")
2575
+ routingExclusion: z.string().nullable().optional().default(null).describe("지금 새 결제의 후보가 아닌 사유. 후보면 null. 판정 원천은 서버 라우팅이다(상점 플랫폼이 다시 계산하지 않는다). 후보가 아닌 PG에는 항상 사유 코드를 붙인다(연결 안 된 PG 포함) — 모든 PG는 `candidates`에 있거나 이 값이 null이 아니다. 현재 값: `NOT_CONNECTED`(연결 안 됨) · `DISABLED`(사용 중지) · `CREDENTIAL_MISSING`(활성 환경 자격 증명 없음) · `SANDBOX_IN_LIVE_STORE`(다른 PG가 라이브라 이 샌드박스 PG는 실구매자 결제에 쓰지 않음) · `PLATFORM_BLOCKED`(플랫폼이 실결제를 막음) · `MODE_MISMATCH`(라이브를 연 서버 모드와 현재 모드가 다름). 값이 추가될 수 있어 문자열로 받는다 — 모르는 값은 후보 아님으로 다룬다. 서버는 항상 싣는다. 이 필드가 없는 이전 서버 응답은 기본값(null)으로 읽는다")
2576
2576
  });
2577
2577
  /**
2578
2578
  * `PaymentProvider.routingExclusion`의 현재 값 — 응답 스키마는 서버가 사유를 추가해도 파싱이 깨지지 않게 문자열로 받는다.
@@ -2686,7 +2686,7 @@ const cashReceiptSchema = z.object({
2686
2686
  canceledAt: z.string().nullable().describe("최근 취소 시각 (ISO 8601)"),
2687
2687
  failCode: z.string().nullable().describe("마지막 실패 코드. 성공하면 비운다"),
2688
2688
  failMessage: z.string().nullable().describe("마지막 실패 사유"),
2689
- reissuable: z.boolean().describe("콘솔 재발급으로 다시 시도할 수 있는가 (`FAILED`·`PENDING`)"),
2689
+ reissuable: z.boolean().describe("상점 플랫폼 재발급으로 다시 시도할 수 있는가 (`FAILED`·`PENDING`)"),
2690
2690
  requestedAt: z.string().describe("신청 시각 (ISO 8601)"),
2691
2691
  updatedAt: z.string().describe("마지막 변경 시각 (ISO 8601)")
2692
2692
  });
@@ -2811,7 +2811,7 @@ function uploadExtensionOf(filename) {
2811
2811
  }
2812
2812
  /**
2813
2813
  * 용도 제한 위반 여부. 통과하면 `null`.
2814
- * 서버가 던지는 오류와 콘솔이 먼저 띄우는 안내가 갈리지 않도록 한 함수로 판정한다.
2814
+ * 서버가 던지는 오류와 상점 플랫폼이 먼저 띄우는 안내가 갈리지 않도록 한 함수로 판정한다.
2815
2815
  */
2816
2816
  function uploadRejection(purpose, filename, size) {
2817
2817
  const limit = UPLOAD_PURPOSE_LIMITS[purpose];
@@ -2867,7 +2867,7 @@ const productSummarySchema = z.object({
2867
2867
  hasOptions: z.boolean(),
2868
2868
  fulfillment: z.object({ type: fulfillmentTypeResponseSchema }).describe("상품 이행의 유형. 유형별 속성은 단건 조회(`GET /v1/products/{productId}`)의 `fulfillment`에 있다"),
2869
2869
  updatedAt: z.string(),
2870
- sample: z.boolean().optional().default(false).describe("스토어를 만들 때 넣은 샘플 상품인가(이슈 #70). 콘솔이 「샘플」 배지를 단다. 스토어프론트에는 싣지 않는다. 서버는 항상 싣는다")
2870
+ sample: z.boolean().optional().default(false).describe("상점을 만들 때 넣은 샘플 상품인가(이슈 #70). 상점 플랫폼이 「샘플」 배지를 단다. 스토어프론트에는 싣지 않는다. 서버는 항상 싣는다")
2871
2871
  });
2872
2872
  /** 옵션 축(그룹)이 가지는 값 하나 — 예: 축 "색상"의 값 "블랙" */
2873
2873
  const optionValueSchema = z.object({
@@ -2914,7 +2914,7 @@ const MAX_ADDON_GROUPS = 5;
2914
2914
  const MAX_CUSTOM_INPUTS = 5;
2915
2915
  /** 직접 입력 항목 최대 글자 수의 상한 */
2916
2916
  const MAX_CUSTOM_INPUT_LENGTH = 200;
2917
- /** 조합 수가 이 값 이상이면 콘솔이 경고한다(상한은 `MAX_VARIANTS`) */
2917
+ /** 조합 수가 이 값 이상이면 상점 플랫폼이 경고한다(상한은 `MAX_VARIANTS`) */
2918
2918
  const VARIANT_COUNT_WARNING = 100;
2919
2919
  /**
2920
2920
  * 옵션 값 정렬 순서 — 등록순·가나다순·낮은 추가금순·높은 추가금순. 서버가 저장할 때 이 순서로 값의 `sortOrder`를 매긴다.
@@ -2953,7 +2953,7 @@ const customInputSchema = z.object({
2953
2953
  sortOrder: z.number().int()
2954
2954
  });
2955
2955
  /**
2956
- * 직접 입력 항목명에 쓸 수 없는 개인정보성 단어 — 콘솔 검사와 서버 400(`CUSTOM_INPUT_LABEL_FORBIDDEN`)이 이 목록 하나를 쓴다.
2956
+ * 직접 입력 항목명에 쓸 수 없는 개인정보성 단어 — 상점 플랫폼 검사와 서버 400(`CUSTOM_INPUT_LABEL_FORBIDDEN`)이 이 목록 하나를 쓴다.
2957
2957
  * 구매자 개인정보는 주문 정보로 받는다. 직접 입력 항목으로 받으면 보관·파기 규칙 밖에 남는다.
2958
2958
  */
2959
2959
  const CUSTOM_INPUT_FORBIDDEN_WORDS = [
@@ -3059,7 +3059,7 @@ const productSchema = productSummarySchema.extend({
3059
3059
  optionSort: optionSortSchema.optional().default("REGISTERED").describe("옵션 값 정렬 순서(이슈 #59). 서버는 항상 싣는다"),
3060
3060
  fulfillment: productFulfillmentResponseSchema,
3061
3061
  fulfillmentTypeLocked: z.boolean().describe("판매 이력(주문상품)이 있어 상품 유형(`fulfillment.type`)을 바꿀 수 없는가. true면 다른 유형으로 수정하는 요청이 409 `FULFILLMENT_TYPE_LOCKED`다. 같은 유형 안의 속성은 바꿀 수 있다"),
3062
- refundPolicy: productRefundPolicyPatchSchema.nullable().describe("상품별 환불 정책 덮어쓰기(상품이 정한 항목만). null이면 스토어 기본 환불 정책을 쓴다. 반품·교환 배송비(`returnDeliveryFee`·`exchangeDeliveryFee`)는 배송 상품에만 있다"),
3062
+ refundPolicy: productRefundPolicyPatchSchema.nullable().describe("상품별 환불 정책 덮어쓰기(상품이 정한 항목만). null이면 상점 기본 환불 정책을 쓴다. 반품·교환 배송비(`returnDeliveryFee`·`exchangeDeliveryFee`)는 배송 상품에만 있다"),
3063
3063
  /**
3064
3064
  * 설정된 즉시할인. `GET /products/{productId}/discount`의 응답과 같은 형태다(이슈 #51).
3065
3065
  * 할인이 없으면 null이다. 이 필드를 싣기 전 서버의 응답에는 없으므로 optional이다.
@@ -3207,7 +3207,7 @@ const productWriteShape = {
3207
3207
  attributeId: z.string(),
3208
3208
  value: z.string()
3209
3209
  })).optional(),
3210
- refundPolicy: productRefundPolicyPatchSchema.nullish().describe("상품별 환불 정책 — 준 항목만 스토어 기본을 덮어쓴다. `null`이나 생략은 스토어 기본을 그대로 쓴다는 뜻이다. 반품·교환 배송비(`returnDeliveryFee`·`exchangeDeliveryFee`)는 배송 상품에만 줄 수 있다(다른 유형은 400)"),
3210
+ refundPolicy: productRefundPolicyPatchSchema.nullish().describe("상품별 환불 정책 — 준 항목만 상점 기본을 덮어쓴다. `null`이나 생략은 상점 기본을 그대로 쓴다는 뜻이다. 반품·교환 배송비(`returnDeliveryFee`·`exchangeDeliveryFee`)는 배송 상품에만 줄 수 있다(다른 유형은 400)"),
3211
3211
  ...optionModelRequestSchema.shape,
3212
3212
  sourceOptionSetIds: z.array(z.string()).max(10).optional().describe("쓰기 전용(이슈 #59) — 이 저장으로 옵션을 불러온 저장 옵션 id. 상품 저장과 같은 트랜잭션에서 불러오기 기록을 남겨 저장 옵션의 `importedProductCount`를 센다. 없는 id는 무시한다")
3213
3213
  };
@@ -3226,7 +3226,7 @@ const productPatchRequestSchema = z.strictObject({
3226
3226
  salePrice: z.number().int().multipleOf(10).optional(),
3227
3227
  status: productStatusSchema.optional(),
3228
3228
  fulfillment: productFulfillmentUpdateSchema.optional().describe(fulfillmentUpdateDescription),
3229
- refundPolicy: productRefundPolicyPatchSchema.nullable().optional().describe("상품별 환불 정책. 주면 통째로 바꾼다(준 항목만 스토어 기본을 덮어쓴다). `null`은 덮어쓰기를 지워 스토어 기본을 따른다. 생략하면 바꾸지 않는다")
3229
+ refundPolicy: productRefundPolicyPatchSchema.nullable().optional().describe("상품별 환불 정책. 주면 통째로 바꾼다(준 항목만 상점 기본을 덮어쓴다). `null`은 덮어쓰기를 지워 상점 기본을 따른다. 생략하면 바꾸지 않는다")
3230
3230
  }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
3231
3231
  const productSortSchema = z.enum([
3232
3232
  "createdAt.desc",
@@ -3402,7 +3402,7 @@ const dispatchRequestSchema = z.object({
3402
3402
  * 발송 시각. ISO 8601이고 시간대(`Z` 또는 `+09:00`)를 포함해야 한다. 생략하면 현재 시각이다.
3403
3403
  *
3404
3404
  * 전에는 `z.string()`이라 아무 문자열이나 그대로 저장됐다. 이 값은 배송 정보 jsonb에 들어가
3405
- * 자동 배송완료·추적 동기화 잡의 대상 선별 조건이 된다 — 잘못된 한 행이 스토어 구분 없이 도는
3405
+ * 자동 배송완료·추적 동기화 잡의 대상 선별 조건이 된다 — 잘못된 한 행이 상점 구분 없이 도는
3406
3406
  * 잡 전체를 멈출 수 있어 입력에서 좁혔다. 검증을 통과한 값도 저장 전에 UTC ISO로 정규화한다.
3407
3407
  */
3408
3408
  dispatchedAt: z.iso.datetime({ offset: true }).optional()
@@ -3524,7 +3524,7 @@ const addressChangeRequestListSchema = z.array(z.record(z.string(), z.unknown())
3524
3524
  * **불러오기는 복사다.** 저장 옵션을 고치거나 지워도 이미 불러온 상품의 옵션은 그대로다. 재고·SKU·사용 여부는 상품마다
3525
3525
  * 달라 저장하지 않는다. 추가금은 조합별이 아니라 **값별**로 둔다 — 조합 옵션으로 불러오면 조합 추가금은 고른 값 추가금의 합이다.
3526
3526
  */
3527
- /** 스토어당 저장 옵션 최대 개수 */
3527
+ /** 상점당 저장 옵션 최대 개수 */
3528
3528
  const MAX_SAVED_OPTION_SETS = 200;
3529
3529
  /** 저장 옵션 이름 최대 글자 수 */
3530
3530
  const MAX_SAVED_OPTION_SET_NAME = 50;
@@ -3631,7 +3631,7 @@ const savedOptionSetListQuerySchema = z.object({
3631
3631
  * (`deliveryBundleKeyOf`). 이슈 #25의 「묶음 = 같은 상품」 규칙을 일반화한 것이다 — 키를 상품 id에서
3632
3632
  * 정책 지문으로 바꿨고, 주문상품이 주문 시점 키를 스냅샷해(`order_items.delivery_bundle_key`)
3633
3633
  * 환불 정산(`refund-settlement.ts`)과 주문 스냅샷(`orders.delivery_fee_settlements`)이 같은 키를 쓴다.
3634
- * 2. **무료 기준**: 상품별 조건부 무료(`CONDITIONAL_FREE`, 묶음 소계 기준)와 스토어 전체 무료 기준
3634
+ * 2. **무료 기준**: 상품별 조건부 무료(`CONDITIONAL_FREE`, 묶음 소계 기준)와 상점 전체 무료 기준
3635
3635
  * (`freeThreshold`, 주문 상품 금액 합 기준)이 있다. 둘 중 하나라도 충족하면 그 배송비는 0이다.
3636
3636
  * 3. **지역 추가 배송비**: 우편번호가 제주·도서산간이면 **묶음마다** 추가된다. 묶음이 곧 한 번의 발송이라
3637
3637
  * 두 출고지에서 각각 보내면 추가 운임도 두 번 든다.
@@ -3642,16 +3642,16 @@ const savedOptionSetListQuerySchema = z.object({
3642
3642
  * 계산은 `quoteDelivery` 하나다. 장바구니·주문서·결제 시작·환불 정산이 모두 이 함수를 쓴다 —
3643
3643
  * 네 곳이 각자 계산하면 화면 금액과 결제 금액이 갈라진다.
3644
3644
  *
3645
- * **비실물 줄은 배송 계산에서 빠진다**(이슈 #48, `requiresShipping`). 묶음을 만들지 않고, 스토어 전체 무료 기준의
3645
+ * **비실물 줄은 배송 계산에서 빠진다**(이슈 #48, `requiresShipping`). 묶음을 만들지 않고, 상점 전체 무료 기준의
3646
3646
  * 판정 금액(`shippableAmount`)에도 넣지 않는다 — 디지털 상품 금액이 실물 배송비를 면제시키지 않게 한다.
3647
3647
  */
3648
3648
  const descriptions = {
3649
- baseDeliveryFee: "스토어 기본 배송비. 원 단위. 상품 등록·수정에서 `deliveryFee`를 생략하면 이 값을 쓴다. 기본 3000",
3650
- freeThreshold: "스토어 전체 무료배송 기준액. 주문 상품 금액 합이 이 값 이상이면 모든 묶음의 배송비가 0이다. null이면 전체 무료배송을 쓰지 않는다(상품별 조건부 무료는 그대로 동작한다). 기본 null",
3649
+ baseDeliveryFee: "상점 기본 배송비. 원 단위. 상품 등록·수정에서 `deliveryFee`를 생략하면 이 값을 쓴다. 기본 3000",
3650
+ freeThreshold: "상점 전체 무료배송 기준액. 주문 상품 금액 합이 이 값 이상이면 모든 묶음의 배송비가 0이다. null이면 전체 무료배송을 쓰지 않는다(상품별 조건부 무료는 그대로 동작한다). 기본 null",
3651
3651
  jejuSurcharge: "제주 지역 추가 배송비. 원 단위. **배송 묶음마다** 더한다. 기본 0",
3652
3652
  isolatedSurcharge: "도서산간 지역 추가 배송비. 원 단위. **배송 묶음마다** 더한다. 기본 0"
3653
3653
  };
3654
- /** 유효 배송비 정책 — 스토어가 정하지 않은 항목은 `SHIPPING_POLICY_DEFAULTS`로 채운 값이다 */
3654
+ /** 유효 배송비 정책 — 상점이 정하지 않은 항목은 `SHIPPING_POLICY_DEFAULTS`로 채운 값이다 */
3655
3655
  const shippingPolicySchema = z.object({
3656
3656
  baseDeliveryFee: z.number().int().min(0).describe(descriptions.baseDeliveryFee),
3657
3657
  freeThreshold: z.number().int().min(1).nullable().describe(descriptions.freeThreshold),
@@ -3659,7 +3659,7 @@ const shippingPolicySchema = z.object({
3659
3659
  isolatedSurcharge: z.number().int().min(0).describe(descriptions.isolatedSurcharge)
3660
3660
  });
3661
3661
  /**
3662
- * 스토어가 정하지 않았을 때 서버가 쓰는 값.
3662
+ * 상점이 정하지 않았을 때 서버가 쓰는 값.
3663
3663
  *
3664
3664
  * `as const`가 아니라 `ShippingPolicy`로 좁힌다 — 리터럴 타입이면 `Partial<typeof …>`로 일부만 바꿀 때
3665
3665
  * `null` 자리에 숫자를 넣을 수 없다(`REFUND_POLICY_DEFAULTS`와 같은 이유).
@@ -3682,7 +3682,7 @@ const shippingPolicyPatchSchema = z.strictObject({
3682
3682
  jejuSurcharge: z.number().int().min(0).optional().describe(descriptions.jejuSurcharge),
3683
3683
  isolatedSurcharge: z.number().int().min(0).optional().describe(descriptions.isolatedSurcharge)
3684
3684
  });
3685
- /** 유효 정책 해석 — 스토어가 정한 항목 + `SHIPPING_POLICY_DEFAULTS` */
3685
+ /** 유효 정책 해석 — 상점이 정한 항목 + `SHIPPING_POLICY_DEFAULTS` */
3686
3686
  function resolveShippingPolicy(patch) {
3687
3687
  if (!patch) return { ...SHIPPING_POLICY_DEFAULTS };
3688
3688
  const given = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== void 0));
@@ -3698,10 +3698,10 @@ const remoteAreaSchema = z.enum([
3698
3698
  "ISOLATED"
3699
3699
  ]);
3700
3700
  /**
3701
- * 제주·도서산간 우편번호 범위 — **코드 상수다.** 금액은 스토어가 정하고 범위는 플랫폼이 고정한다.
3701
+ * 제주·도서산간 우편번호 범위 — **코드 상수다.** 금액은 상점이 정하고 범위는 플랫폼이 고정한다.
3702
3702
  *
3703
3703
  * 국내 택배사가 공표하는 제주·도서산간 할증 구간을 5자리 우편번호 범위로 옮긴 표다. 셀러마다
3704
- * 범위가 다르면 같은 주소에 다른 금액이 나가고 CS가 셀러 수만큼 갈라진다. 스토어별 범위 편집은
3704
+ * 범위가 다르면 같은 주소에 다른 금액이 나가고 CS가 셀러 수만큼 갈라진다. 상점별 범위 편집은
3705
3705
  * 후속 과제이고, 지금은 이 표가 유일한 원천이다.
3706
3706
  *
3707
3707
  * ## 근거
@@ -3740,7 +3740,7 @@ const remoteAreaSchema = z.enum([
3740
3740
  * 도로명주소·건물관리번호 단위 판정은 후속 과제다.
3741
3741
  *
3742
3742
  * 범위는 **닫힌 구간**(`from` ≤ zip ≤ `to`)이고 겹치지 않는다. 앞에서부터 처음 맞는 항목을 쓴다.
3743
- * 순서는 콘솔 「추가 배송비 지역」 표의 행 순서이기도 하다(`remoteAreaGroups`). 제주를 먼저 두고
3743
+ * 순서는 상점 플랫폼 「추가 배송비 지역」 표의 행 순서이기도 하다(`remoteAreaGroups`). 제주를 먼저 두고
3744
3744
  * 도서산간은 우편번호 오름차순으로 둔다.
3745
3745
  */
3746
3746
  const REMOTE_AREA_ZIP_RANGES = [
@@ -3993,7 +3993,7 @@ function deliveryBundleKeyOf(product) {
3993
3993
  * 기본 배송비를 면제한 근거 — 면제하지 않았으면 null이다.
3994
3994
  *
3995
3995
  * 환불 정산이 근거를 구분해야 한다. 조건부 무료 기준 미달 차감은 **상품별 조건부 무료(`CONDITIONAL`)로
3996
- * 면제된 묶음만** 대상이다. 스토어 전체 무료 기준(`STORE_THRESHOLD`)이나 무료배송 상품(`FREE`)은 셀러가
3996
+ * 면제된 묶음만** 대상이다. 상점 전체 무료 기준(`STORE_THRESHOLD`)이나 무료배송 상품(`FREE`)은 셀러가
3997
3997
  * 배송비를 받지 않기로 한 것이므로, 일부 취소로 기준이 깨져도 구매자에게 배송비를 물리지 않는다.
3998
3998
  *
3999
3999
  * 세 값이 겹치면 `FREE` → `STORE_THRESHOLD` → `CONDITIONAL` 순으로 센 근거를 남긴다.
@@ -4007,7 +4007,7 @@ const deliveryFeeWaiverSchema = z.enum([
4007
4007
  * 배송비 계산 — **순수 함수다.** 장바구니 요약, 주문서 금액, 결제 시작의 최종 확정,
4008
4008
  * 주문 배송비 스냅샷이 모두 이 한 곳을 쓴다.
4009
4009
  *
4010
- * 순서가 규칙이다. 묶음별 조건부 무료를 먼저 보고, 그다음 스토어 전체 무료 기준으로 기본 배송비를
4010
+ * 순서가 규칙이다. 묶음별 조건부 무료를 먼저 보고, 그다음 상점 전체 무료 기준으로 기본 배송비를
4011
4011
  * 한꺼번에 0으로 만들고, 마지막에 지역 추가 배송비를 묶음마다 더한다. 추가 배송비는 무료 기준에
4012
4012
  * 걸리지 않는다.
4013
4013
  */
@@ -4065,14 +4065,14 @@ function quoteDelivery(input) {
4065
4065
  //#endregion
4066
4066
  //#region src/schemas/store.ts
4067
4067
  /**
4068
- * 스토어 코드 규칙 — 스토어프론트 API가 테넌트를 가르는 값이다(`X-Store-Code` 헤더).
4068
+ * 상점 코드 규칙 — 스토어프론트 API가 테넌트를 가르는 값이다(`X-Store-Code` 헤더).
4069
4069
  * **개설할 때 서버가 랜덤으로 발급하고** 이후 바꿀 수 없다. 이미 나간 링크와 승인된 결제가
4070
4070
  * 이 값에 묶여 있어서 바꾸면 함께 깨진다.
4071
4071
  *
4072
4072
  * 호스트 라벨로도 쓸 수 있게 DNS 라벨 규칙까지 좁힌다. 하이픈으로 시작하거나 끝나는 라벨은 호스트가 될 수 없다.
4073
4073
  */
4074
4074
  const STORE_CODE_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,28}[a-z0-9])$/;
4075
- /** 플랫폼이 쓰거나 쓸 호스트 이름 — 스토어 코드로 내주지 않는다 */
4075
+ /** 플랫폼이 쓰거나 쓸 호스트 이름 — 상점 코드로 내주지 않는다 */
4076
4076
  const RESERVED_STORE_CODES = [
4077
4077
  "www",
4078
4078
  "api",
@@ -4122,7 +4122,7 @@ const RESERVED_STORE_CODES = [
4122
4122
  function isReservedStoreCode(code) {
4123
4123
  return RESERVED_STORE_CODES.includes(code.toLowerCase());
4124
4124
  }
4125
- const storeCodeSchema = z.string().regex(STORE_CODE_PATTERN, "소문자·숫자·하이픈 3~30자여야 하고 하이픈으로 시작하거나 끝날 수 없습니다").refine((code) => !isReservedStoreCode(code), "플랫폼이 쓰는 이름이라 스토어 코드로 쓸 수 없습니다");
4125
+ const storeCodeSchema = z.string().regex(STORE_CODE_PATTERN, "소문자·숫자·하이픈 3~30자여야 하고 하이픈으로 시작하거나 끝날 수 없습니다").refine((code) => !isReservedStoreCode(code), "플랫폼이 쓰는 이름이라 상점 코드로 쓸 수 없습니다");
4126
4126
  /** `https://shop.example.com`처럼 경로·쿼리 없는 http(s) 오리진인가 */
4127
4127
  function isWebOrigin(value) {
4128
4128
  try {
@@ -4139,7 +4139,7 @@ const MAX_ANALYTICS_ALLOWED_ORIGINS = 20;
4139
4139
  /** 자동 배송완료·자동 구매확정 대기일 상한 */
4140
4140
  const MAX_AUTO_TRANSITION_DAYS = 30;
4141
4141
  /**
4142
- * 약관 버전 — 스토어가 정하는 문자열이다(`1`·`2`·`2026-09-26`·`v1.2` 등). 형식은 강제하지 않고 값이 다르면 다른 버전이다.
4142
+ * 약관 버전 — 상점이 정하는 문자열이다(`1`·`2`·`2026-09-26`·`v1.2` 등). 형식은 강제하지 않고 값이 다르면 다른 버전이다.
4143
4143
  * 올리면 그 약관에 동의한 구매자의 `reconsentRequired`가 켜지고, 재동의가 이력에 남는다. 되돌리면 재동의 요구도 풀린다.
4144
4144
  */
4145
4145
  const policyVersionSchema = z.string().trim().min(1).max(20).describe("약관 버전 문자열(1~20자). 예: `1`, `2026-09-26`");
@@ -4161,8 +4161,8 @@ const updateStoreRequestSchema = z.object({
4161
4161
  guestCheckoutEnabled: z.boolean().optional().describe("비회원 주문 허용. false(회원만)면 로그인하지 않은 구매자의 주문서 생성·결제 요청이 403 `GUEST_CHECKOUT_DISABLED`다. 장바구니 담기와 이미 받은 비회원 주문의 조회·취소는 막지 않는다"),
4162
4162
  autoDeliverDays: z.number().int().min(0).max(30).optional().describe(autoDeliverDaysDescription),
4163
4163
  autoConfirmDays: z.number().int().min(0).max(30).optional().describe(autoConfirmDaysDescription),
4164
- refundPolicy: refundPolicyPatchSchema.optional().describe("스토어 기본 환불 정책 — 준 항목만 바꾼다. 상품별 정책(`products.refundPolicy`)이 없는 상품에 적용된다"),
4165
- shippingPolicy: shippingPolicyPatchSchema.optional().describe("스토어 배송비 규칙 — 준 항목만 바꾼다. 기본 배송비, 전체 무료배송 기준액, 제주·도서산간 추가 배송비다. 바꾼 값은 **새 주문서부터** 적용된다(이미 만든 주문서·주문의 배송비는 스냅샷이 원천이다)"),
4164
+ refundPolicy: refundPolicyPatchSchema.optional().describe("상점 기본 환불 정책 — 준 항목만 바꾼다. 상품별 정책(`products.refundPolicy`)이 없는 상품에 적용된다"),
4165
+ shippingPolicy: shippingPolicyPatchSchema.optional().describe("상점 배송비 규칙 — 준 항목만 바꾼다. 기본 배송비, 전체 무료배송 기준액, 제주·도서산간 추가 배송비다. 바꾼 값은 **새 주문서부터** 적용된다(이미 만든 주문서·주문의 배송비는 스냅샷이 원천이다)"),
4166
4166
  termsVersion: policyVersionSchema.optional().describe("이용약관 버전. 올리면 이 약관에 동의한 구매자에게 재동의를 요구한다(`GET /storefront/v1/me`의 `reconsentRequired`)"),
4167
4167
  privacyVersion: policyVersionSchema.optional().describe("개인정보 수집이용 동의 버전. 올리면 구매자에게 재동의를 요구한다"),
4168
4168
  termsUrl: policyDocumentUrlSchema.optional().describe("이용약관 문서 주소(https). 동의 시점의 값이 동의 이력에 복사된다. `null`을 주면 지운다"),
@@ -4186,8 +4186,8 @@ const storeSchema = z.object({
4186
4186
  guestCheckoutEnabled: z.boolean().describe("비회원 주문 허용. false면 회원만 주문할 수 있다"),
4187
4187
  autoDeliverDays: z.number().int().describe(autoDeliverDaysDescription),
4188
4188
  autoConfirmDays: z.number().int().describe(autoConfirmDaysDescription),
4189
- refundPolicy: refundPolicySchema.describe("스토어 기본 환불 정책. 스토어가 정하지 않은 항목은 플랫폼 기본값으로 채워 항상 전부 싣는다"),
4190
- shippingPolicy: shippingPolicySchema.describe("스토어 배송비 규칙. 스토어가 정하지 않은 항목은 플랫폼 기본값으로 채워 항상 전부 싣는다"),
4189
+ refundPolicy: refundPolicySchema.describe("상점 기본 환불 정책. 상점이 정하지 않은 항목은 플랫폼 기본값으로 채워 항상 전부 싣는다"),
4190
+ shippingPolicy: shippingPolicySchema.describe("상점 배송비 규칙. 상점이 정하지 않은 항목은 플랫폼 기본값으로 채워 항상 전부 싣는다"),
4191
4191
  termsVersion: z.string().describe("현재 이용약관 버전. 가입·재동의가 이 값으로 이력에 남는다"),
4192
4192
  privacyVersion: z.string().describe("현재 개인정보 수집이용 동의 버전"),
4193
4193
  termsVersionUpdatedAt: z.string().nullable().describe("이용약관 버전을 마지막으로 바꾼 시각. 바꾼 적이 없으면 null"),
@@ -4207,7 +4207,7 @@ const storeMemberSchema = z.object({
4207
4207
  });
4208
4208
  /**
4209
4209
  * 초대 메일 발송 결과 — `SENDING`은 발송 요청 중(결과를 아직 적지 못함), `NOT_CONFIGURED`는 메일 발송이 설정되지 않아
4210
- * 보내지 않은 것이다. 스토어의 월 메일 한도(요금제)를 다 써서 보내지 않았으면 `FAILED` + `deliveryErrorCode: MAIL_QUOTA_EXCEEDED`다. 발송 실패는 초대를 무효로 만들지 않는다 — 재발송으로 다시 보낸다
4210
+ * 보내지 않은 것이다. 상점의 월 메일 한도(요금제)를 다 써서 보내지 않았으면 `FAILED` + `deliveryErrorCode: MAIL_QUOTA_EXCEEDED`다. 발송 실패는 초대를 무효로 만들지 않는다 — 재발송으로 다시 보낸다
4211
4211
  */
4212
4212
  const invitationDeliveryStatusSchema = z.enum([
4213
4213
  "SENDING",
@@ -4286,7 +4286,7 @@ const sellerAddressRequestSchema = z.object({
4286
4286
  /**
4287
4287
  * 스토어프론트 호스팅 (이슈 #53, M1: 템플릿 발행) — 관리 API `/v1/storefront/**`의 계약이다.
4288
4288
  *
4289
- * 셀러는 템플릿을 골라 사이트를 만들고 `{slug}.{호스팅 도메인}` 주소를 받는다. 스토어를 만들어도 사이트는 생기지 않고
4289
+ * 셀러는 템플릿을 골라 사이트를 만들고 `{slug}.{호스팅 도메인}` 주소를 받는다. 상점을 만들어도 사이트는 생기지 않고
4290
4290
  * `POST /v1/storefront/site`가 유일한 생성 경로다. 템플릿은 만들 때만 고르고 바꾸지 않는다. 발행은 버전 단위이고,
4291
4291
  * 되돌리기는 이전 버전을 다시 발행하는 것이다(재빌드 없음). 상태의 원천은 api DB이고 Cloudflare 쪽 반영
4292
4292
  * (라우팅 표·사이트 Worker)은 커밋 뒤 비동기다 — 반영 상태는 `provisioning`으로 본다.
@@ -4297,13 +4297,13 @@ const sellerAddressRequestSchema = z.object({
4297
4297
  * 오류 코드:
4298
4298
  * - 403 `STOREFRONT_HOSTING_DISABLED` — 플랫폼 스위치가 꺼져 새 사이트를 만들 수 없다
4299
4299
  * - 404 `STOREFRONT_SITE_NOT_FOUND` · `STOREFRONT_TEMPLATE_NOT_FOUND` · `STOREFRONT_VERSION_NOT_FOUND`
4300
- * - 409 `STOREFRONT_SITE_EXISTS` — 이미 사이트가 있다(스토어당 1개)
4300
+ * - 409 `STOREFRONT_SITE_EXISTS` — 이미 사이트가 있다(상점당 1개)
4301
4301
  * - 409 `STOREFRONT_SLUG_TAKEN` — 다른 사이트가 쓰거나 보류 중인 슬러그다
4302
- * - 409 `STOREFRONT_SLUG_CHANGE_LIMIT` — 슬러그는 스토어당 30일에 3번까지 바꾼다
4303
- * - 409 `STOREFRONT_SITE_CREATE_LIMIT` — 사이트는 스토어당 30일에 3번까지 만든다
4302
+ * - 409 `STOREFRONT_SLUG_CHANGE_LIMIT` — 슬러그는 상점당 30일에 3번까지 바꾼다
4303
+ * - 409 `STOREFRONT_SITE_CREATE_LIMIT` — 사이트는 상점당 30일에 3번까지 만든다
4304
4304
  * - 409 `STOREFRONT_SITE_CHANGED` — 읽은 상태(`expected*`)와 현재 상태가 다르다. 다시 읽고 시도한다
4305
4305
  * - 409 `STOREFRONT_SITE_NOT_ACTIVE` — 정지(`SUSPENDED`)된 사이트는 바꾸거나 끌 수 없다
4306
- * - 409 `STORE_SUSPENDED` — 정지된 스토어에는 사이트를 만들 수 없다
4306
+ * - 409 `STORE_SUSPENDED` — 정지된 상점에는 사이트를 만들 수 없다
4307
4307
  * - 409 `STOREFRONT_VERSION_NOT_READY` — 빌드가 끝나지 않았거나 실패한 버전은 발행할 수 없다
4308
4308
  * - 409 `STOREFRONT_NO_ROLLBACK_TARGET` — 되돌릴 이전 발행 버전이 없다
4309
4309
  * - 409 `STOREFRONT_NOT_READY` — 공개 전환: 판매 중인 상품(샘플 제외)이 없다(이슈 #70). 상품을 등록한 뒤 공개한다
@@ -4329,7 +4329,7 @@ const sellerAddressRequestSchema = z.object({
4329
4329
  * - 502 `STOREFRONT_SANDBOX_UNAVAILABLE` — 편집 Sandbox 호출이 실패했다. 잠시 뒤 다시 한다
4330
4330
  *
4331
4331
  * 소스 내려받기·올리기(#60, `/v1/storefront/site/source/**`, `sayren` CLI):
4332
- * - 409 `SOURCE_CHANGED` — 작업 트리가 내려받은 뒤(`expectedBaseRef`) 바뀌었다(콘솔·AI 편집). `error.details.currentRef`
4332
+ * - 409 `SOURCE_CHANGED` — 작업 트리가 내려받은 뒤(`expectedBaseRef`) 바뀌었다(상점 플랫폼·AI 편집). `error.details.currentRef`
4333
4333
  * - 409 `EDIT_SESSION_OPEN` — 편집 환경이 열려 있다. `endEditSession: true`로 끄고 진행할 수 있다
4334
4334
  * - 409 `SOURCE_BLOBS_MISSING` — 올리지 않은 파일 내용이 있다(`error.details.hashes`). `POST source/blobs`로 올리고 다시 한다
4335
4335
  * - 409 `DEPENDENCY_REJECTED` — 쓸 수 없는 npm 의존성이다(`error.details.rejected: [{ name, version, reason, detail }]`)
@@ -4339,11 +4339,11 @@ const sellerAddressRequestSchema = z.object({
4339
4339
  * - 404 `STOREFRONT_SOURCE_NOT_FOUND` — 그 스냅샷이 없다
4340
4340
  */
4341
4341
  /**
4342
- * 슬러그 형식 — 스토어 코드와 같은 DNS 라벨 규칙(소문자·숫자·하이픈 3~30자, 하이픈으로 시작·끝 불가)에
4342
+ * 슬러그 형식 — 상점 코드와 같은 DNS 라벨 규칙(소문자·숫자·하이픈 3~30자, 하이픈으로 시작·끝 불가)에
4343
4343
  * 연속 하이픈 금지를 더한다. `--`는 버전 미리보기 주소(`v3--{slug}`)와 punycode(`xn--`)가 쓰는 구분자다.
4344
4344
  */
4345
4345
  const STOREFRONT_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{1,28}[a-z0-9])$/;
4346
- /** 호스팅 도메인에서 플랫폼이 쓰거나 쓸 이름 — 스토어 코드 예약어에 호스팅 전용 이름을 더한다 */
4346
+ /** 호스팅 도메인에서 플랫폼이 쓰거나 쓸 이름 — 상점 코드 예약어에 호스팅 전용 이름을 더한다 */
4347
4347
  const RESERVED_STOREFRONT_SLUGS = [
4348
4348
  ...RESERVED_STORE_CODES,
4349
4349
  "mcp",
@@ -4369,7 +4369,7 @@ const RESERVED_STOREFRONT_SLUGS = [
4369
4369
  const STOREFRONT_EDIT_PREVIEW_SUFFIX = "-preview";
4370
4370
  /**
4371
4371
  * 공식 쇼케이스 슬러그 접두사(이슈 #72) — `demo-{템플릿 id}`는 템플릿 미리보기용 쇼케이스 사이트 주소다. 쇼케이스로 지정된
4372
- * 스토어만 쓸 수 있다(서버가 스토어 용도로 판정한다). 공식 미리보기를 흉내 내는 주소를 막는다
4372
+ * 상점만 쓸 수 있다(서버가 상점 용도로 판정한다). 공식 미리보기를 흉내 내는 주소를 막는다
4373
4373
  */
4374
4374
  const STOREFRONT_SHOWCASE_SLUG_PREFIX = "demo-";
4375
4375
  function isShowcaseStorefrontSlug(slug) {
@@ -4392,9 +4392,9 @@ const storefrontSlugSchema = z.string().regex(STOREFRONT_SLUG_PATTERN, "소문
4392
4392
  const STOREFRONT_SLUG_HOLD_DAYS = 90;
4393
4393
  /** 슬러그 변경 한도 — 이 기간(일) 안에 */
4394
4394
  const STOREFRONT_SLUG_CHANGE_WINDOW_DAYS = 30;
4395
- /** 슬러그 변경 한도 — 횟수(스토어 단위. 끄고 다시 만들어도 이어서 센다) */
4395
+ /** 슬러그 변경 한도 — 횟수(상점 단위. 끄고 다시 만들어도 이어서 센다) */
4396
4396
  const STOREFRONT_SLUG_CHANGE_LIMIT = 3;
4397
- /** 사이트 만들기 한도 — 같은 창(30일) 안의 횟수(스토어 단위). 끄고 만들기를 되풀이해 이름을 묶어 두지 못하게 한다 */
4397
+ /** 사이트 만들기 한도 — 같은 창(30일) 안의 횟수(상점 단위). 끄고 만들기를 되풀이해 이름을 묶어 두지 못하게 한다 */
4398
4398
  const STOREFRONT_SITE_CREATE_LIMIT = 3;
4399
4399
  const storefrontTemplateSchema = z.object({
4400
4400
  templateId: z.string().describe("템플릿 id (예: `basic`)"),
@@ -4403,7 +4403,7 @@ const storefrontTemplateSchema = z.object({
4403
4403
  description: z.string().describe("템플릿 설명"),
4404
4404
  thumbnailUrl: z.string().nullable().describe("썸네일 이미지 주소. 없으면 null"),
4405
4405
  version: z.string().describe("현재 템플릿 버전. 새 사이트는 이 버전으로 만든다"),
4406
- isDefault: z.boolean().describe("기본 템플릿인가 (스토어 생성 시 자동 생성에 쓴다)"),
4406
+ isDefault: z.boolean().describe("기본 템플릿인가 (상점 생성 시 자동 생성에 쓴다)"),
4407
4407
  tags: z.array(z.string()).default([]).describe("템플릿 특징 태그 (예: `후기 강조`). 목록 카드에 보인다. 옛 서버 응답은 빈 배열로 읽는다"),
4408
4408
  supportsCheckout: z.boolean().default(true).describe("주문을 받는 템플릿인가. false는 가격·문의 중심의 카탈로그형이다. 옛 서버 응답은 true로 읽는다"),
4409
4409
  previewUrl: z.string().nullable().default(null).describe("공식 쇼케이스 사이트 주소. 연결된 쇼케이스가 공개 중일 때만 싣고 그 밖에는 null")
@@ -4431,14 +4431,14 @@ const storefrontVersionSchema = z.object({
4431
4431
  source: z.enum(["TEMPLATE", "EDIT"]).describe("`TEMPLATE` 템플릿 산출물 그대로 · `EDIT` 편집 작업 트리를 빌드함"),
4432
4432
  buildId: z.string().nullable().describe("편집 버전의 빌드 (`GET /v1/storefront/site/builds/{buildId}`). 템플릿 버전은 null"),
4433
4433
  createdByType: z.string().describe("만든 행위자 유형 (`USER`·`AGENT`·`APP`·`TOKEN`·`SYSTEM`). 늘어날 수 있다"),
4434
- createdVia: z.string().nullable().optional().describe("만든 경로 (`CONSOLE` 콘솔 · `AI` AI 에이전트(MCP) · `CLI` `sayren` CLI · `API` 관리 API · `SYSTEM` 자동). 늘어날 수 있다"),
4434
+ createdVia: z.string().nullable().optional().describe("만든 경로 (`CONSOLE` 상점 플랫폼 · `AI` AI 에이전트(MCP) · `CLI` `sayren` CLI · `API` 관리 API · `SYSTEM` 자동). 늘어날 수 있다"),
4435
4435
  createdAt: z.string().describe("만든 시각 (ISO 8601)")
4436
4436
  });
4437
4437
  const storefrontSiteStatusSchema = z.enum([
4438
4438
  "ACTIVE",
4439
4439
  "SUSPENDED",
4440
4440
  "CLOSED"
4441
- ]).describe("`ACTIVE` 운영 중 · `SUSPENDED` 운영자 정지 · `CLOSED` 호스팅 끔·스토어 폐쇄");
4441
+ ]).describe("`ACTIVE` 운영 중 · `SUSPENDED` 운영자 정지 · `CLOSED` 호스팅 끔·상점 폐쇄");
4442
4442
  const storefrontVisibilitySchema = z.enum(["COMING_SOON", "PUBLIC"]).describe("`COMING_SOON` 오픈 준비 중(방문자에게 준비 중 페이지) · `PUBLIC` 공개");
4443
4443
  const storefrontSourceModeSchema = z.enum(["MANAGED", "CUSTOM"]).describe("`MANAGED` 템플릿 그대로 · `CUSTOM` 한 번이라도 편집함");
4444
4444
  const storefrontDomainSchema = z.object({
@@ -4463,7 +4463,7 @@ const storefrontProvisioningSchema = z.object({
4463
4463
  });
4464
4464
  /**
4465
4465
  * 편집 미리보기 주소(M2b) — 사이트마다 `{사이트 id 정규화}-preview.{호스팅 도메인}` 호스트 하나다. 호스팅 도메인의 와일드카드
4466
- * 인증서가 덮으므로 따로 준비할 것이 없다. 이 주소는 편집 미리보기 링크(콘솔 전용)로 받은 쿠키가 있어야 열린다.
4466
+ * 인증서가 덮으므로 따로 준비할 것이 없다. 이 주소는 편집 미리보기 링크(상점 플랫폼 전용)로 받은 쿠키가 있어야 열린다.
4467
4467
  */
4468
4468
  const storefrontEditPreviewSchema = z.object({ hostname: z.string().nullable().describe("편집 미리보기 호스트 (예: `sfs-ab12cd34-preview.sayren.co`). 편집을 쓸 수 없으면 null") });
4469
4469
  /**
@@ -4510,7 +4510,7 @@ const storefrontSlugAvailabilitySchema = z.object({
4510
4510
  ]).nullable().describe("쓸 수 없는 이유. `INVALID` 형식 · `RESERVED` 예약어 · `TAKEN` 사용·보류 중 · `CURRENT` 지금 내 슬러그")
4511
4511
  });
4512
4512
  /**
4513
- * 배포 진행 — 사이트의 지금 발행 상태가 공개 주소에 반영되기까지의 단계와 기록이다(콘솔의 스토어프론트 만들기 3단계가 폴링한다).
4513
+ * 배포 진행 — 사이트의 지금 발행 상태가 공개 주소에 반영되기까지의 단계와 기록이다(상점 플랫폼의 스토어프론트 만들기 3단계가 폴링한다).
4514
4514
  * 만들기(`POST /v1/storefront/site`)는 곧바로 201로 답하고 반영은 그 뒤에 비동기로 하므로, 끝났는지는 이 조회로 본다.
4515
4515
  * 템플릿 사이트는 미리 빌드한 템플릿 산출물을 올리므로 빌드 단계가 없다. 기록은 사이트 상태에서 만든 요약이다.
4516
4516
  */
@@ -4556,7 +4556,7 @@ const storefrontDeploymentSchema = z.object({
4556
4556
  });
4557
4557
  const createStorefrontSiteRequestSchema = z.object({
4558
4558
  templateId: z.string().min(1).max(64).describe("템플릿 id"),
4559
- slug: storefrontSlugSchema.optional().describe("주소 슬러그. 생략하면 스토어 코드")
4559
+ slug: storefrontSlugSchema.optional().describe("주소 슬러그. 생략하면 상점 코드")
4560
4560
  });
4561
4561
  /** @deprecated 템플릿 변경은 지원하지 않는다(항상 409 `TEMPLATE_CHANGE_NOT_SUPPORTED`). 호환을 위해 스키마만 남겼다 */
4562
4562
  const changeStorefrontTemplateRequestSchema = z.object({
@@ -4583,7 +4583,7 @@ const setStorefrontVisibilityRequestSchema = z.object({
4583
4583
  const disableStorefrontHostingRequestSchema = z.object({ confirmSlug: z.string().min(1).describe("확인 입력 — 현재 슬러그") });
4584
4584
  const storefrontSlugAvailabilityQuerySchema = z.object({ slug: z.string().describe("확인할 슬러그") });
4585
4585
  /**
4586
- * 오픈 준비 중 미리보기 링크 — 콘솔에서 로그인한 OWNER·ADMIN만 받는다(PAT·에이전트 불가). 링크는 5분 안에 한 번 열면
4586
+ * 오픈 준비 중 미리보기 링크 — 상점 플랫폼에서 로그인한 OWNER·ADMIN만 받는다(PAT·에이전트 불가). 링크는 5분 안에 한 번 열면
4587
4587
  * 그 브라우저에 12시간짜리 미리보기 쿠키가 생기고 오픈 준비 중인 사이트의 실제 화면을 본다. 링크를 남에게 넘기면 그 사람도
4588
4588
  * 볼 수 있으므로 공유하지 않는다.
4589
4589
  */
@@ -4683,7 +4683,7 @@ const STOREFRONT_PUBLIC_SUFFIXES = [
4683
4683
  "cafe24.com",
4684
4684
  "imweb.me"
4685
4685
  ];
4686
- /** 스토어당 연결할 수 있는 도메인 수 기본값 — 요금제(#44) 전의 상한이다. 실제 값은 `GET …/domains`의 `limit` */
4686
+ /** 상점당 연결할 수 있는 도메인 수 기본값 — 요금제(#44) 전의 상한이다. 실제 값은 `GET …/domains`의 `limit` */
4687
4687
  const STOREFRONT_CUSTOM_DOMAIN_LIMIT_DEFAULT = 2;
4688
4688
  /** DNS를 넣을 때까지 기다리는 기간(일) — 지나면 `FAILED`(`DNS_NOT_CONFIGURED`) */
4689
4689
  const STOREFRONT_DOMAIN_DNS_WAIT_DAYS = 7;
@@ -4758,7 +4758,7 @@ const storefrontSiteDomainSchema = z.object({
4758
4758
  "ACTIVE",
4759
4759
  "FAILED"
4760
4760
  ]).nullable().describe("인증서 상태. 소유 확인 전·기본 주소는 null"),
4761
- failureCode: z.string().nullable().describe("실패·경고 코드. `DNS_NOT_CONFIGURED` 기한 안에 TXT를 찾지 못함 · `VALIDATION_TIMEOUT` 인증서 발급 기한 지남 · `CERTIFICATE_FAILED` 인증서 발급 실패 · `DNS_NOT_POINTING` 연결된 뒤 DNS가 이 서비스를 가리키지 않음(기한이 지나면 해제) · `DOMAIN_TAKEN` 다른 스토어가 먼저 소유를 확인함 · `HOSTNAME_BLOCKED` 연결이 막힘 · `HOSTNAME_CONFLICT` 연결 준비 중 충돌(운영 확인). 늘어날 수 있다"),
4761
+ failureCode: z.string().nullable().describe("실패·경고 코드. `DNS_NOT_CONFIGURED` 기한 안에 TXT를 찾지 못함 · `VALIDATION_TIMEOUT` 인증서 발급 기한 지남 · `CERTIFICATE_FAILED` 인증서 발급 실패 · `DNS_NOT_POINTING` 연결된 뒤 DNS가 이 서비스를 가리키지 않음(기한이 지나면 해제) · `DOMAIN_TAKEN` 다른 상점이 먼저 소유를 확인함 · `HOSTNAME_BLOCKED` 연결이 막힘 · `HOSTNAME_CONFLICT` 연결 준비 중 충돌(운영 확인). 늘어날 수 있다"),
4762
4762
  verifiedAt: z.string().nullable().describe("소유를 확인한 시각 (ISO 8601)"),
4763
4763
  activatedAt: z.string().nullable().describe("연결된 시각 (ISO 8601)"),
4764
4764
  checkedAt: z.string().nullable().describe("마지막으로 확인한 시각 (ISO 8601)"),
@@ -4767,7 +4767,7 @@ const storefrontSiteDomainSchema = z.object({
4767
4767
  /** `GET /v1/storefront/site/domains` — 사이트의 주소 목록(기본 주소 + 내 도메인)과 연결 설정 */
4768
4768
  const storefrontSiteDomainsSchema = z.object({
4769
4769
  enabled: z.boolean().describe("내 도메인을 추가할 수 있는가 (플랫폼 스위치)"),
4770
- limit: z.number().int().min(0).describe("스토어당 내 도메인 수 상한 (해제한 도메인은 세지 않는다)"),
4770
+ limit: z.number().int().min(0).describe("상점당 내 도메인 수 상한 (해제한 도메인은 세지 않는다)"),
4771
4771
  target: z.string().describe("CNAME 대상 (예: `sites.sayren.co`)"),
4772
4772
  domains: z.array(storefrontSiteDomainSchema).describe("대표 주소 먼저, 그다음 추가한 순서")
4773
4773
  });
@@ -4841,7 +4841,7 @@ const storefrontFileEncodingSchema = z.enum(["utf8", "base64"]).describe("`utf8`
4841
4841
  * 90초). `RUNNING`이면 미리보기와 파일 쓰기가 바로 반영된다(HMR).
4842
4842
  */
4843
4843
  const storefrontEditSessionStatusSchema = z.enum(["STARTING", "RUNNING"]).describe("`STARTING` 띄우는 중 · `RUNNING` 사용 중");
4844
- /** 편집 환경을 띄우는 단계 — 콘솔 진행 표시용이다. 값은 늘어날 수 있다 */
4844
+ /** 편집 환경을 띄우는 단계 — 상점 플랫폼 진행 표시용이다. 값은 늘어날 수 있다 */
4845
4845
  const STOREFRONT_EDIT_START_STAGES = [
4846
4846
  "CONTAINER",
4847
4847
  "RESTORE",
@@ -5121,7 +5121,7 @@ const storefrontVersionCreatedSchema = z.object({
5121
5121
  build: storefrontBuildSchema
5122
5122
  });
5123
5123
  /**
5124
- * `POST /v1/storefront/site/editing/preview-link` — 편집 미리보기(dev 서버) 링크. 콘솔에서 로그인한 OWNER·ADMIN만
5124
+ * `POST /v1/storefront/site/editing/preview-link` — 편집 미리보기(dev 서버) 링크. 상점 플랫폼에서 로그인한 OWNER·ADMIN만
5125
5125
  * 받는다(PAT·에이전트 불가). 5분 안에 열면 그 브라우저에 미리보기 호스트 전용 쿠키(12시간)가 생긴다. 편집 환경이
5126
5126
  * 없으면 409 `EDIT_SESSION_REQUIRED`다(편집 환경이 `STARTING`이면 링크는 주고, 미리보기 화면이 기동 대기를 보여 준다).
5127
5127
  */
@@ -5138,7 +5138,7 @@ const storefrontSourceRefSchema = z.string().regex(/^sources\/sfs_[a-z0-9]{8,40}
5138
5138
  const storefrontSourceSchema = z.object({
5139
5139
  siteId: z.string(),
5140
5140
  storeId: z.string(),
5141
- storeCode: z.string().describe("스토어 코드 — 로컬 개발 서버의 `SAYREN_STORE_CODE`"),
5141
+ storeCode: z.string().describe("상점 코드 — 로컬 개발 서버의 `SAYREN_STORE_CODE`"),
5142
5142
  sourceRef: storefrontSourceRefSchema,
5143
5143
  treeSha256: z.string().describe("트리 지문 (경로 오름차순 `{path}\\t{sha256}\\n`의 SHA-256)"),
5144
5144
  files: z.number().int().min(0).describe("파일 수"),
@@ -5203,8 +5203,8 @@ const storefrontSourceReplacedSchema = z.object({
5203
5203
  //#endregion
5204
5204
  //#region src/schemas/subscription.ts
5205
5205
  /**
5206
- * 요금제·구독 — `GET /v1/store/subscription`(스코프 `store:r`). 구독 단위는 스토어다.
5207
- * 결제 수단·청구 금액은 싣지 않는다. 요금제 변경은 셀러 콘솔에서만 한다.
5206
+ * 요금제·구독 — `GET /v1/store/subscription`(스코프 `store:r`). 구독 단위는 상점이다.
5207
+ * 결제 수단·청구 금액은 싣지 않는다. 요금제 변경은 상점 플랫폼에서만 한다.
5208
5208
  */
5209
5209
  /** 요금제 코드 — 이름(`plan.name`)이 바뀌어도 코드는 바뀌지 않는다. 값은 추가만 한다 */
5210
5210
  const planCodeSchema = z.enum([
@@ -5249,7 +5249,7 @@ const subscriptionUsageSchema = z.object({
5249
5249
  aiActions: z.number().int().describe("이번 기간 MCP(에이전트) 쓰기(AI 작업) 수"),
5250
5250
  aiReads: z.number().int().describe("이번 기간 MCP(에이전트) 읽기 수"),
5251
5251
  storefrontRequests: z.number().int().describe("이번 기간 스토어프론트 요청 수"),
5252
- adminApiRequests: z.number().int().describe("이번 기간 관리 API 요청 수(API 토큰·앱·에이전트 호출, 셀러 콘솔 제외)"),
5252
+ adminApiRequests: z.number().int().describe("이번 기간 관리 API 요청 수(API 토큰·앱·에이전트 호출, 상점 플랫폼 제외)"),
5253
5253
  emails: z.number().int().describe("이번 기간 초대·양도 알림 메일 수(한도 없음, 표시만)"),
5254
5254
  storefrontPreviewMinutes: z.number().int().describe("이번 기간 편집 미리보기 분(끝난 세션)"),
5255
5255
  storefrontBuildMinutes: z.number().int().describe("이번 기간 빌드 분(끝난 빌드)"),
@@ -5273,7 +5273,7 @@ const storeSubscriptionSchema = z.object({
5273
5273
  features: z.object({
5274
5274
  adminApi: z.boolean().describe("관리 API(개인 액세스 토큰·외부 앱 토큰 호출)를 쓸 수 있다"),
5275
5275
  analytics: z.boolean().describe("애널리틱스 조회를 쓸 수 있다"),
5276
- storeClone: z.boolean().describe("더 쓰지 않는다 — 스토어 복제 기능을 없애 항상 false"),
5276
+ storeClone: z.boolean().describe("더 쓰지 않는다 — 상점 복제 기능을 없애 항상 false"),
5277
5277
  removeBadge: z.boolean().describe("더 쓰지 않는다 — 배지 키를 없애 항상 false")
5278
5278
  }),
5279
5279
  usage: subscriptionUsageSchema,
@@ -5300,16 +5300,16 @@ const planErrorDetailsSchema = z.object({
5300
5300
  used: z.number().optional(),
5301
5301
  plan: responsePlanCodeSchema.optional(),
5302
5302
  resetsAt: z.string().optional().describe("월 한도가 초기화되는 시각(ISO 8601)"),
5303
- upgradeUrl: z.string().optional().describe("요금제 화면 주소(셀러 콘솔)"),
5304
- reason: z.string().optional().describe("스토어 수 한도의 이유 — `OWNED_STORES`(소유 스토어 수). `FREE_STORES`는 더 쓰지 않는다")
5303
+ upgradeUrl: z.string().optional().describe("요금제 화면 주소(상점 플랫폼)"),
5304
+ reason: z.string().optional().describe("상점 수 한도의 이유 — `OWNED_STORES`(소유 상점 수). `FREE_STORES`는 더 쓰지 않는다")
5305
5305
  }).loose();
5306
5306
  const limitOrContract = (description) => z.number().int().nullable().describe(`${description}. null이면 계약(엔터프라이즈)·한도 없음`);
5307
5307
  /**
5308
- * 요금제 기능 키 값 — 요금제 비교표·콘솔 요금제 화면이 쓴다. 키는 서버 판정의 기능 키와 같다(추가만 한다). 상위 요금제는 하위 요금제
5308
+ * 요금제 기능 키 값 — 요금제 비교표·상점 플랫폼 요금제 화면이 쓴다. 키는 서버 판정의 기능 키와 같다(추가만 한다). 상위 요금제는 하위 요금제
5309
5309
  * 기능을 모두 포함한다
5310
5310
  */
5311
5311
  const planEntitlementsSchema = z.object({
5312
- "features.admin_api": z.boolean().describe("관리 API(개인 액세스 토큰·외부 앱 토큰 호출). 셀러 콘솔·CLI·MCP는 모든 요금제에서 쓴다"),
5312
+ "features.admin_api": z.boolean().describe("관리 API(개인 액세스 토큰·외부 앱 토큰 호출). 상점 플랫폼·CLI·MCP는 모든 요금제에서 쓴다"),
5313
5313
  "features.analytics": z.boolean().describe("애널리틱스 화면·조회 API"),
5314
5314
  "limits.ai_reads_monthly": limitOrContract("MCP 읽기 월 한도"),
5315
5315
  "limits.ai_actions_monthly": limitOrContract("MCP 쓰기(AI 작업) 월 한도 — 주문 처리는 막지 않는다"),
@@ -5367,7 +5367,7 @@ function createStoreClient(options) {
5367
5367
  const token = resolveToken(tokenSource);
5368
5368
  return token ? { authorization: `Bearer ${token}` } : {};
5369
5369
  }
5370
- /** 계정 API(`/me/*`) — 스토어를 고르지 않는다 */
5370
+ /** 계정 API(`/me/*`) — 상점을 고르지 않는다 */
5371
5371
  const userHttp = createHttp({
5372
5372
  baseUrl: options.baseUrl,
5373
5373
  fetch: fetchFn,
@@ -5375,7 +5375,7 @@ function createStoreClient(options) {
5375
5375
  refresh,
5376
5376
  onUnauthorized
5377
5377
  });
5378
- /** 스토어 API — 같은 계정 토큰 + `X-Store-Id` */
5378
+ /** 상점 API — 같은 계정 토큰 + `X-Store-Id` */
5379
5379
  const storeHttp = createHttp({
5380
5380
  baseUrl: options.baseUrl,
5381
5381
  fetch: fetchFn,
@@ -5414,7 +5414,7 @@ function createStoreClient(options) {
5414
5414
  /** session.userinfo 패스스루 — session 미배선 시 명확한 에러를 던진다 */
5415
5415
  userinfo: () => requireSession().userinfo(),
5416
5416
  auth: {
5417
- /** 소속 스토어 목록 */
5417
+ /** 소속 상점 목록 */
5418
5418
  listMyStores: () => userHttp.request("GET", "/me/stores", z.array(myStoreSchema)),
5419
5419
  me: () => userHttp.request("GET", "/me", myAccountSchema)
5420
5420
  },
@@ -5488,7 +5488,7 @@ function createStoreClient(options) {
5488
5488
  savedOptionSets: {
5489
5489
  list: (params) => storeHttp.request("GET", "/saved-option-sets", pageSchema(savedOptionSetSchema), { query: params }),
5490
5490
  get: (optionSetId) => storeHttp.request("GET", path`/saved-option-sets/${optionSetId}`, savedOptionSetSchema),
5491
- /** 이름이 겹치면 409 `OPTION_SET_NAME_TAKEN`, 스토어당 200개를 넘으면 409 `OPTION_SET_LIMIT_EXCEEDED` */
5491
+ /** 이름이 겹치면 409 `OPTION_SET_NAME_TAKEN`, 상점당 200개를 넘으면 409 `OPTION_SET_LIMIT_EXCEEDED` */
5492
5492
  create: (body) => storeHttp.request("POST", "/saved-option-sets", savedOptionSetSchema, { body: savedOptionSetRequestSchema.parse(body) }),
5493
5493
  /** 통째로 바꾼다. 불러온 상품은 바뀌지 않는다 */
5494
5494
  update: (optionSetId, body) => storeHttp.request("PUT", path`/saved-option-sets/${optionSetId}`, savedOptionSetSchema, { body: savedOptionSetRequestSchema.parse(body) }),
@@ -5518,7 +5518,7 @@ function createStoreClient(options) {
5518
5518
  get: (orderId) => storeHttp.request("GET", path`/orders/${orderId}`, orderSchema),
5519
5519
  /**
5520
5520
  * `POST /v1/orders/{orderId}/cash-receipt/reissue` — 실패했거나 재시도 대기 중인 현금영수증을 지금 다시 발급·취소한다.
5521
- * 콘솔 OWNER·ADMIN 전용(PAT·M2M 403 `INSUFFICIENT_ROLE`). 404 `CASH_RECEIPT_NOT_FOUND`, 409 `CASH_RECEIPT_NOT_REISSUABLE`
5521
+ * 상점 플랫폼 OWNER·ADMIN 전용(PAT·M2M 403 `INSUFFICIENT_ROLE`). 404 `CASH_RECEIPT_NOT_FOUND`, 409 `CASH_RECEIPT_NOT_REISSUABLE`
5522
5522
  */
5523
5523
  reissueCashReceipt: (orderId) => storeHttp.request("POST", path`/orders/${orderId}/cash-receipt/reissue`, cashReceiptSchema)
5524
5524
  },
@@ -5553,7 +5553,7 @@ function createStoreClient(options) {
5553
5553
  } }),
5554
5554
  /**
5555
5555
  * 배송완료 처리 — `DISPATCHED`·`DELIVERING`만 넘어간다. 응답의 `autoDecisionDate`가 자동 구매확정 예정일이다
5556
- * (스토어 설정 `autoConfirmDays`가 0이면 null).
5556
+ * (상점 설정 `autoConfirmDays`가 0이면 null).
5557
5557
  */
5558
5558
  markDelivered: (orderItemId, idempotencyKey) => storeHttp.request("POST", path`/order-items/${orderItemId}/delivered`, orderItemSchema, { headers: idempotency(idempotencyKey) }),
5559
5559
  /** 배송완료 일괄 처리 — 항목별 부분 성공이다 */
@@ -5609,7 +5609,7 @@ function createStoreClient(options) {
5609
5609
  updateAnswer: (inquiryId, content) => storeHttp.requestVoid("PUT", path`/inquiries/${inquiryId}/answer`, { body: { content } })
5610
5610
  },
5611
5611
  /**
5612
- * 구매자 로그인 설정 — 이메일·비밀번호 허용, 소셜 공급자 연결. 비밀 값을 다루므로 콘솔에 로그인한 OWNER만 호출할 수 있다
5612
+ * 구매자 로그인 설정 — 이메일·비밀번호 허용, 소셜 공급자 연결. 비밀 값을 다루므로 상점 플랫폼에 로그인한 OWNER만 호출할 수 있다
5613
5613
  */
5614
5614
  loginSettings: {
5615
5615
  get: () => storeHttp.request("GET", "/store/login-settings", loginSettingsSchema),
@@ -5621,7 +5621,7 @@ function createStoreClient(options) {
5621
5621
  /** 연결 해제 — 키를 지운다. 연결된 구매자 계정은 남는다 */
5622
5622
  removeProvider: (provider) => storeHttp.request("DELETE", path`/store/auth-providers/${provider}`, loginSettingsSchema)
5623
5623
  },
5624
- /** 구매자 관리 — 조회 `customer:r`, 탈퇴 처리 `customer:rw`(콘솔 OWNER·ADMIN) */
5624
+ /** 구매자 관리 — 조회 `customer:r`, 탈퇴 처리 `customer:rw`(상점 플랫폼 OWNER·ADMIN) */
5625
5625
  customers: {
5626
5626
  list: (params) => storeHttp.request("GET", "/customers", pageSchema(customerSummarySchema), { query: params }),
5627
5627
  get: (customerId) => storeHttp.request("GET", path`/customers/${customerId}`, customerDetailSchema),
@@ -5719,8 +5719,8 @@ get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, {
5719
5719
  get: (paymentId) => storeHttp.request("GET", path`/payments/${paymentId}`, paymentRecordDetailSchema)
5720
5720
  },
5721
5721
  /**
5722
- * 결제(PG) 설정 — **콘솔 OWNER 전용**. ADMIN·STAFF·PAT·M2M·3rd-party 앱 토큰은 스코프가 있어도
5723
- * 403 `INSUFFICIENT_ROLE`이다(조회 포함). OWNER 여부는 요청 시점의 스토어 멤버십으로 다시 확인하므로
5722
+ * 결제(PG) 설정 — **상점 플랫폼 OWNER 전용**. ADMIN·STAFF·PAT·M2M·3rd-party 앱 토큰은 스코프가 있어도
5723
+ * 403 `INSUFFICIENT_ROLE`이다(조회 포함). OWNER 여부는 요청 시점의 상점 멤버십으로 다시 확인하므로
5724
5724
  * 양도·강등 직후에도 바로 403이다. 비밀 값(시크릿 키·API Secret·웹훅 시크릿)은 요청으로만 보내고
5725
5725
  * 응답에는 `secrets[].masked`(앞 4자리 마스킹)만 나온다.
5726
5726
  */
@@ -5827,7 +5827,7 @@ get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, {
5827
5827
  */
5828
5828
  sendTest: (webhookId, body) => storeHttp.request("POST", path`/webhooks/${webhookId}/test`, webhookTestResultSchema, { body: webhookTestRequestSchema.parse(body) })
5829
5829
  },
5830
- /** API 로그 (보관 7일, 콘솔 OWNER/ADMIN) */
5830
+ /** API 로그 (보관 7일, 상점 플랫폼 OWNER/ADMIN) */
5831
5831
  apiLogs: {
5832
5832
  /** 최신순 커서 페이지네이션. 다음 페이지는 응답의 `nextCursor`를 `cursor`로 넘긴다 */
5833
5833
  list: (params) => storeHttp.request("GET", "/api-logs", apiLogPageSchema, { query: params && {
@@ -5837,7 +5837,7 @@ get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, {
5837
5837
  /** 최근 24시간 요청 수·에러 수 */
5838
5838
  summary: () => storeHttp.request("GET", "/api-logs/summary", apiLogSummarySchema)
5839
5839
  },
5840
- /** 감사 로그 (관리 API 쓰기의 행위자·대상·결과, 콘솔 OWNER/ADMIN, `audit:r`) */
5840
+ /** 감사 로그 (관리 API 쓰기의 행위자·대상·결과, 상점 플랫폼 OWNER/ADMIN, `audit:r`) */
5841
5841
  auditLogs: {
5842
5842
  /** 최신순 커서 페이지네이션. 다음 페이지는 응답의 `nextCursor`를 `cursor`로 넘긴다 */
5843
5843
  list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, { query: params && {
@@ -5845,7 +5845,7 @@ list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, {
5845
5845
  actorType: Array.isArray(params.actorType) ? params.actorType.join(",") || void 0 : params.actorType
5846
5846
  } }) },
5847
5847
  /**
5848
- * 승인 요청 — 에이전트의 고위험 쓰기가 202로 보류된 건. 목록·승인·거절은 콘솔 OWNER/ADMIN,
5848
+ * 승인 요청 — 에이전트의 고위험 쓰기가 202로 보류된 건. 목록·승인·거절은 상점 플랫폼 OWNER/ADMIN,
5849
5849
  * 단건 조회는 요청한 토큰도 할 수 있다(상태 확인용).
5850
5850
  */
5851
5851
  approvalRequests: {
@@ -5889,7 +5889,7 @@ list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, {
5889
5889
  checkSlug: (slug) => storeHttp.request("GET", "/storefront/slug-availability", storefrontSlugAvailabilitySchema, { query: { slug } }),
5890
5890
  /**
5891
5891
  * `POST /v1/storefront/site` (201) — 템플릿으로 사이트를 만들고 v1을 발행한다. 공개 상태는 오픈 준비 중이다.
5892
- * 사이트를 만드는 유일한 경로다(스토어를 만들어도 사이트는 생기지 않는다). 템플릿은 여기서만 고른다
5892
+ * 사이트를 만드는 유일한 경로다(상점을 만들어도 사이트는 생기지 않는다). 템플릿은 여기서만 고른다
5893
5893
  */
5894
5894
  create: (body) => storeHttp.request("POST", "/storefront/site", storefrontSiteSchema, { body: createStorefrontSiteRequestSchema.parse(body) }),
5895
5895
  /** `GET /v1/storefront/site/deployment` — 배포 진행(단계·기록). 만든 뒤 반영이 끝날 때까지 폴링한다 */
@@ -5914,7 +5914,7 @@ list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, {
5914
5914
  setVisibility: (body) => storeHttp.request("PUT", "/storefront/site/visibility", storefrontSiteSchema, { body: setStorefrontVisibilityRequestSchema.parse(body) }),
5915
5915
  /**
5916
5916
  * `POST /v1/storefront/site/preview-link` — 오픈 준비 중인 사이트를 구성원이 볼 수 있는 5분짜리 링크.
5917
- * 콘솔에서 로그인한 OWNER·ADMIN만 받는다
5917
+ * 상점 플랫폼에서 로그인한 OWNER·ADMIN만 받는다
5918
5918
  */
5919
5919
  createPreviewLink: (body = {}) => storeHttp.request("POST", "/storefront/site/preview-link", storefrontPreviewLinkSchema, { body: createStorefrontPreviewLinkRequestSchema.parse(body) }),
5920
5920
  /** `GET /v1/storefront/site/domains` — 주소 목록(기본 주소 + 내 도메인)과 DNS 안내 */
@@ -5943,7 +5943,7 @@ list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, {
5943
5943
  stopEditing: () => storeHttp.request("DELETE", "/storefront/site/editing", storefrontEditingSchema),
5944
5944
  /**
5945
5945
  * `POST /v1/storefront/site/editing/preview-link` — 편집 미리보기(dev 서버) 5분짜리 링크.
5946
- * 콘솔에서 로그인한 OWNER·ADMIN만 받는다(에이전트 불가)
5946
+ * 상점 플랫폼에서 로그인한 OWNER·ADMIN만 받는다(에이전트 불가)
5947
5947
  */
5948
5948
  createEditPreviewLink: (body = {}) => storeHttp.request("POST", "/storefront/site/editing/preview-link", storefrontPreviewLinkSchema, { body: createStorefrontEditPreviewLinkRequestSchema.parse(body) }),
5949
5949
  /** `GET /v1/storefront/site/files?prefix=` — 작업 트리 파일 목록 */
@@ -5994,7 +5994,7 @@ list: (params) => storeHttp.request("GET", "/audit-logs", auditLogPageSchema, {
5994
5994
  subscription: {
5995
5995
  /**
5996
5996
  * `GET /v1/store/subscription` — 스코프 `store:r`. 현재 요금제·상태·사용량 기간·한도·이번 기간 사용량.
5997
- * 결제 수단·청구 금액은 싣지 않는다. 요금제 변경은 셀러 콘솔에서만 한다
5997
+ * 결제 수단·청구 금액은 싣지 않는다. 요금제 변경은 상점 플랫폼에서만 한다
5998
5998
  */
5999
5999
  get: () => storeHttp.request("GET", "/store/subscription", storeSubscriptionSchema) },
6000
6000
  plans: {
@@ -6018,7 +6018,7 @@ listPublic: () => storeHttp.request("GET", "/public/plans", publicPlansSchema) }
6018
6018
  listInvitations: (params) => storeHttp.request("GET", "/store/invitations", z.array(invitationSchema), { query: params }),
6019
6019
  /**
6020
6020
  * `POST /v1/store/invitations` (201) — 스코프 `member:rw`. 초대 메일을 보낸다. 발송 결과는 응답의
6021
- * `deliveryStatus`다(발송이 실패해도 초대는 만들어진다). 스토어·초대한 사람·받는 주소별 발송 한도가 있다(429, `details.limit`).
6021
+ * `deliveryStatus`다(발송이 실패해도 초대는 만들어진다). 상점·초대한 사람·받는 주소별 발송 한도가 있다(429, `details.limit`).
6022
6022
  */
6023
6023
  invite: (body) => storeHttp.request("POST", "/store/invitations", invitationSchema, { body: inviteMemberRequestSchema.parse(body) }),
6024
6024
  /** `POST /v1/store/invitations/{invitationId}/resend` — 새 수락 링크로 다시 보낸다. 이전 링크는 무효가 되고 만료가 다시 7일이 된다 */
@@ -6139,10 +6139,10 @@ const customerDelegationSchema = z.object({
6139
6139
  //#endregion
6140
6140
  //#region src/schemas/scope.ts
6141
6141
  /**
6142
- * 스토어 스코프 카탈로그 (auth-spec §7) — 형식 `{리소스}:{r|rw}`, rw는 r을 함의한다.
6142
+ * 상점 스코프 카탈로그 (auth-spec §7) — 형식 `{리소스}:{r|rw}`, rw는 r을 함의한다.
6143
6143
  *
6144
6144
  * 관리 API가 요구하는 스코프와 역할별 자동 부여 스코프의 **단일 원천**이다.
6145
- * 서버(apps/api)가 이 상수를 그대로 가져다 역할→스코프를 산출하므로, 콘솔 권한 매트릭스와
6145
+ * 서버(apps/api)가 이 상수를 그대로 가져다 역할→스코프를 산출하므로, 상점 플랫폼 권한 매트릭스와
6146
6146
  * 서버 인가가 갈라지지 않는다.
6147
6147
  */
6148
6148
  const scopeAccessSchema = z.enum(["r", "rw"]).describe("접근 수준. `r`=읽기, `rw`=읽기+쓰기(r을 함의)");
@@ -6173,7 +6173,7 @@ function isStoreScope(scope) {
6173
6173
  }
6174
6174
  /**
6175
6175
  * 역할별 자동 부여 스코프 (auth-spec §7).
6176
- * 계정 토큰으로 스토어를 호출할 때의 스코프는 그 스토어에서의 역할로 이 표에서 결정된다.
6176
+ * 계정 토큰으로 상점을 호출할 때의 스코프는 그 상점에서의 역할로 이 표에서 결정된다.
6177
6177
  */
6178
6178
  const STORE_ROLE_SCOPES = {
6179
6179
  OWNER: [
@@ -6230,7 +6230,7 @@ const STORE_ROLE_SCOPES = {
6230
6230
  * 세는 것이다. 그 숫자가 규칙과 안내를 고치는 근거가 된다.
6231
6231
  *
6232
6232
  * **보내지 않는 것**: 파일 경로·소스 코드·위반 상세(`detail`)·토큰·사람 식별자. 규칙 id와 개수뿐이다.
6233
- * 테넌트는 요청 토큰이 정한다(본문에 스토어 id가 없다). 옵트아웃은 클라이언트의 `SAYREN_TELEMETRY=0`이다.
6233
+ * 테넌트는 요청 토큰이 정한다(본문에 상점 id가 없다). 옵트아웃은 클라이언트의 `SAYREN_TELEMETRY=0`이다.
6234
6234
  *
6235
6235
  * 알 수 없는 키는 저장하지 않고 버린다(`.strict()`를 쓰지 않는다) — 새 버전 클라이언트가 필드를
6236
6236
  * 하나 더 실었다고 계측 전체가 400으로 날아가면 그 버전의 숫자가 통째로 빈다.
@@ -6263,7 +6263,7 @@ const mcpToolEventSchema = z.object({
6263
6263
  const envelopeFields = {
6264
6264
  id: z.string().describe("이벤트 ID (`evt_…`, 테스트 전송은 `evt_test_…`). 중복 제거 키"),
6265
6265
  createdAt: z.string().describe("이벤트 발생 일시 (ISO 8601)"),
6266
- storeId: z.string().describe("이벤트가 발생한 스토어 ID"),
6266
+ storeId: z.string().describe("이벤트가 발생한 상점 ID"),
6267
6267
  sequence: z.number().int().positive().optional().describe("리소스별 순번. 같은 주문·클레임·문의·리뷰·상품의 이벤트마다 1씩 커진다. 도착 순서는 보장하지 않으므로 같은 리소스의 이벤트는 이 값으로 정렬한다. 이 필드가 생기기 전의 이벤트와 테스트 전송에는 없다")
6268
6268
  };
6269
6269
  const orderWebhookEventDataSchema = z.object({