@sayren/store-sdk 0.41.0 → 0.42.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.
@@ -23,6 +23,7 @@ import {
23
23
  } from "./product-info";
24
24
  import { productRefundPolicyPatchSchema } from "./refund-policy";
25
25
  import { inventoryModeSchema } from "./stay";
26
+ import { strictRequest } from "./strict";
26
27
  import { UPLOAD_PURPOSE_LIMITS, uploadExtensionOf } from "./upload";
27
28
 
28
29
  export const productStatusSchema = z.enum(["SALE", "SUSPENDED", "OUT_OF_STOCK", "CLOSED"]);
@@ -301,7 +302,7 @@ export function customInputLabelForbiddenWord(label: string): string | null {
301
302
  /** 옵션명·값 이름 — 앞뒤 공백을 지우고 빈 값은 받지 않는다 */
302
303
  const optionNameSchema = z.string().trim().min(1).max(50);
303
304
 
304
- export const addonValueRequestSchema = z.object({
305
+ export const addonValueRequestSchema = z.strictObject({
305
306
  /** 전달 시 기존 값 행을 유지(UPDATE). 생략하면 신규 발급 */
306
307
  valueId: z.string().optional(),
307
308
  name: optionNameSchema,
@@ -312,7 +313,7 @@ export const addonValueRequestSchema = z.object({
312
313
 
313
314
  export type AddonValueRequest = z.infer<typeof addonValueRequestSchema>;
314
315
 
315
- export const addonGroupRequestSchema = z.object({
316
+ export const addonGroupRequestSchema = z.strictObject({
316
317
  /** 전달 시 기존 옵션명 행을 유지(UPDATE). 조합 옵션명의 id는 줄 수 없다(방식을 바꾸려면 새 옵션명으로 보낸다) */
317
318
  groupId: z.string().optional(),
318
319
  name: optionNameSchema,
@@ -322,7 +323,7 @@ export const addonGroupRequestSchema = z.object({
322
323
 
323
324
  export type AddonGroupRequest = z.infer<typeof addonGroupRequestSchema>;
324
325
 
325
- export const customInputRequestSchema = z.object({
326
+ export const customInputRequestSchema = z.strictObject({
326
327
  /** 전달 시 기존 항목 행을 유지(UPDATE). 생략하면 신규 발급 */
327
328
  inputId: z.string().optional(),
328
329
  label: z.string().trim().min(1).max(30),
@@ -545,7 +546,7 @@ export function productImageRejection(url: string): ProductImageRejection | null
545
546
  */
546
547
  const codeSchema = z.string().trim().min(1).max(64);
547
548
 
548
- export const optionValueRequestSchema = z.object({
549
+ export const optionValueRequestSchema = z.strictObject({
549
550
  /** 전달 시 기존 값 행을 유지(UPDATE). 생략하면 신규 발급 */
550
551
  valueId: z.string().optional(),
551
552
  name: z.string().min(1).max(50),
@@ -553,7 +554,7 @@ export const optionValueRequestSchema = z.object({
553
554
 
554
555
  export type OptionValueRequest = z.infer<typeof optionValueRequestSchema>;
555
556
 
556
- export const optionGroupRequestSchema = z.object({
557
+ export const optionGroupRequestSchema = z.strictObject({
557
558
  /** 전달 시 기존 축 행을 유지(UPDATE). 생략하면 신규 발급 */
558
559
  groupId: z.string().optional(),
559
560
  name: z.string().min(1).max(50),
@@ -562,7 +563,7 @@ export const optionGroupRequestSchema = z.object({
562
563
 
563
564
  export type OptionGroupRequest = z.infer<typeof optionGroupRequestSchema>;
564
565
 
565
- export const productVariantRequestSchema = z.object({
566
+ export const productVariantRequestSchema = z.strictObject({
566
567
  /** 기존 variant 유지 시 전달. 생략하면 신규 생성 */
567
568
  variantId: z.string().optional(),
568
569
  /** optionGroups 순서대로 각 축에서 고른 값 이름. 서버가 이름 → valueId를 해석한다 */
@@ -593,7 +594,7 @@ export const productVariantRequestSchema = z.object({
593
594
  export type ProductVariantRequest = z.infer<typeof productVariantRequestSchema>;
594
595
 
595
596
  /** 축 × 값 → variant 전체 교체 요청 (PUT /products/{productId}/options) */
596
- export const optionModelRequestSchema = z.object({
597
+ export const optionModelRequestSchema = z.strictObject({
597
598
  optionGroups: z.array(optionGroupRequestSchema).max(MAX_OPTION_GROUPS).default([]),
598
599
  variants: z.array(productVariantRequestSchema).min(1).max(MAX_VARIANTS),
599
600
  addonGroups: z
@@ -719,7 +720,7 @@ const productWriteShape = {
719
720
  images: productImagesRequestSchema
720
721
  .optional()
721
722
  .describe("상품 이미지 주소 목록. 첫 장이 대표 이미지(썸네일)다"),
722
- attributes: z.array(z.object({ attributeId: z.string(), value: z.string() })).optional(),
723
+ attributes: z.array(z.strictObject({ attributeId: z.string(), value: z.string() })).optional(),
723
724
  refundPolicy: productRefundPolicyPatchSchema
724
725
  .nullish()
725
726
  .describe(
@@ -870,12 +871,14 @@ export const productListQuerySchema = z.object({
870
871
  ...pageQueryShape(),
871
872
  });
872
873
 
873
- export const discountRequestSchema = z.object({
874
- discountType: z.enum(["RATE", "AMOUNT"]),
875
- discountValue: z.number().int().min(1),
876
- startAt: z.string().optional(),
877
- endAt: z.string().optional(),
878
- });
874
+ export const discountRequestSchema = strictRequest(
875
+ z.object({
876
+ discountType: z.enum(["RATE", "AMOUNT"]),
877
+ discountValue: z.number().int().min(1),
878
+ startAt: z.string().optional(),
879
+ endAt: z.string().optional(),
880
+ }),
881
+ );
879
882
 
880
883
  export type DiscountRequest = z.infer<typeof discountRequestSchema>;
881
884
 
@@ -75,12 +75,12 @@ export const savedOptionSetSchema = z.object({
75
75
 
76
76
  export type SavedOptionSet = z.infer<typeof savedOptionSetSchema>;
77
77
 
78
- export const savedOptionValueRequestSchema = z.object({
78
+ export const savedOptionValueRequestSchema = z.strictObject({
79
79
  name: nameSchema,
80
80
  additionalPrice: z.number().int().min(0).default(0),
81
81
  });
82
82
 
83
- export const savedOptionGroupRequestSchema = z.object({
83
+ export const savedOptionGroupRequestSchema = z.strictObject({
84
84
  name: nameSchema,
85
85
  kind: optionGroupKindSchema,
86
86
  required: z
@@ -92,7 +92,7 @@ export const savedOptionGroupRequestSchema = z.object({
92
92
 
93
93
  export type SavedOptionGroupRequest = z.infer<typeof savedOptionGroupRequestSchema>;
94
94
 
95
- export const savedCustomInputRequestSchema = z.object({
95
+ export const savedCustomInputRequestSchema = z.strictObject({
96
96
  label: z.string().trim().min(1).max(30),
97
97
  placeholder: z.string().trim().max(100).nullish(),
98
98
  maxLength: z.number().int().min(1).max(MAX_CUSTOM_INPUT_LENGTH),
@@ -107,7 +107,7 @@ export const savedCustomInputRequestSchema = z.object({
107
107
  * 저장 옵션 만들기·수정 본문. 조합 옵션명은 최대 `MAX_OPTION_GROUPS`개, 추가 선택은 최대 `MAX_ADDON_GROUPS`개이고
108
108
  * 옵션명과 직접 입력 항목이 모두 비면 400이다. 수정(PUT)은 통째로 바꾼다.
109
109
  */
110
- export const savedOptionSetRequestSchema = z.object({
110
+ export const savedOptionSetRequestSchema = z.strictObject({
111
111
  name: z.string().trim().min(1).max(MAX_SAVED_OPTION_SET_NAME),
112
112
  optionSort: optionSortSchema.default("REGISTERED"),
113
113
  groups: z
@@ -126,7 +126,7 @@ export type SavedOptionSetRequestInput = z.input<typeof savedOptionSetRequestSch
126
126
  * 조합 추가금이 값별 추가금의 합으로 되돌려지면 값별로 저장하고, 조합마다 제각각이면 추가금을 빼고
127
127
  * 응답 `additionalPriceDropped: true`로 알린다. `replaceOptionSetId`를 주면 그 저장 옵션을 덮어쓴다(이름 중복의 덮어쓰기).
128
128
  */
129
- export const savedOptionSetFromProductRequestSchema = z.object({
129
+ export const savedOptionSetFromProductRequestSchema = z.strictObject({
130
130
  productId: z.string(),
131
131
  name: z.string().trim().min(1).max(MAX_SAVED_OPTION_SET_NAME),
132
132
  includeOptions: z.boolean().default(true).describe("옵션명(조합·추가 선택)을 저장하는가"),
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { strictRequest } from "./strict";
2
3
 
3
4
  /**
4
5
  * 쇼핑몰 시작(starter, 이슈 #122) — 원격 MCP의 starter 절차가 쓰는 브랜드 브리프와 진행 상태.
@@ -70,18 +71,20 @@ export const brandBriefSchema = z.object({
70
71
  export type BrandBrief = z.infer<typeof brandBriefSchema>;
71
72
 
72
73
  /** `PUT /v1/storefront/brand-brief` — 브리프 전체를 바꾼다. 생략한 항목은 비운다 */
73
- export const putBrandBriefRequestSchema = z.object({
74
- industry: storeIndustrySchema.nullable().default(null),
75
- mood: z.string().trim().max(200).nullable().default(null),
76
- pointColor: z
77
- .string()
78
- .regex(/^#[0-9a-fA-F]{6}$/, "#RRGGBB 형식이어야 합니다")
79
- .nullable()
80
- .default(null),
81
- references: z.array(brandBriefReferenceSchema).max(BRAND_BRIEF_MAX_REFERENCES).default([]),
82
- productSource: brandBriefProductSourceSchema.nullable().default(null),
83
- notes: z.string().trim().max(4000).nullable().default(null),
84
- });
74
+ export const putBrandBriefRequestSchema = strictRequest(
75
+ z.object({
76
+ industry: storeIndustrySchema.nullable().default(null),
77
+ mood: z.string().trim().max(200).nullable().default(null),
78
+ pointColor: z
79
+ .string()
80
+ .regex(/^#[0-9a-fA-F]{6}$/, "#RRGGBB 형식이어야 합니다")
81
+ .nullable()
82
+ .default(null),
83
+ references: z.array(brandBriefReferenceSchema).max(BRAND_BRIEF_MAX_REFERENCES).default([]),
84
+ productSource: brandBriefProductSourceSchema.nullable().default(null),
85
+ notes: z.string().trim().max(4000).nullable().default(null),
86
+ }),
87
+ );
85
88
  export type PutBrandBriefRequest = z.input<typeof putBrandBriefRequestSchema>;
86
89
 
87
90
  /** `GET·PUT /v1/storefront/brand-brief` 응답 — 저장한 적이 없으면 `brief`·`updatedAt`이 null이다 */
@@ -1,4 +1,5 @@
1
1
  import { z } from "zod";
2
+ import { strictRequest } from "./strict";
2
3
 
3
4
  /**
4
5
  * 날짜별 재고·가격(이슈 #118) — 숙박·회차처럼 날짜마다 재고와 가격이 다른 상품. 상품 `inventoryMode: "DATED"`이면 조합(객실) × 날짜
@@ -75,16 +76,18 @@ export const calendarQuerySchema = z.object({
75
76
  * 달력 설정 — 기간의 날짜마다 재고·가격을 덮어쓴다(없는 날은 만든다). `stock`·`price`는 준 것만 바꾸고, `price: null`은 조합 가격으로
76
77
  * 되돌린다. `daysOfWeek`(0=일~6=토)를 주면 그 요일만 바꾼다
77
78
  */
78
- export const setCalendarRequestSchema = z
79
- .object({
80
- variantIds: z.array(z.string()).min(1).max(50),
81
- from: calendarDateSchema,
82
- to: calendarDateSchema,
83
- stock: z.number().int().min(0).max(100_000).optional(),
84
- price: z.number().int().min(0).multipleOf(10).nullable().optional(),
85
- daysOfWeek: z.array(z.number().int().min(0).max(6)).min(1).max(7).optional(),
86
- })
87
- .refine((value) => value.stock !== undefined || value.price !== undefined, {
88
- message: "stock이나 price 중 하나는 있어야 합니다",
89
- });
79
+ export const setCalendarRequestSchema = strictRequest(
80
+ z
81
+ .object({
82
+ variantIds: z.array(z.string()).min(1).max(50),
83
+ from: calendarDateSchema,
84
+ to: calendarDateSchema,
85
+ stock: z.number().int().min(0).max(100_000).optional(),
86
+ price: z.number().int().min(0).multipleOf(10).nullable().optional(),
87
+ daysOfWeek: z.array(z.number().int().min(0).max(6)).min(1).max(7).optional(),
88
+ })
89
+ .refine((value) => value.stock !== undefined || value.price !== undefined, {
90
+ message: "stock이나 price 중 하나는 있어야 합니다",
91
+ }),
92
+ );
90
93
  export type SetCalendarRequest = z.input<typeof setCalendarRequestSchema>;
@@ -3,6 +3,7 @@ import { storeRoleSchema } from "./auth";
3
3
  import { localeCodeSchema } from "./locale";
4
4
  import { refundPolicyPatchSchema, refundPolicySchema } from "./refund-policy";
5
5
  import { shippingPolicyPatchSchema, shippingPolicySchema } from "./shipping-policy";
6
+ import { strictRequest } from "./strict";
6
7
 
7
8
  /**
8
9
  * 상점 코드 규칙 — 스토어프론트 API가 테넌트를 가르는 값이다(`X-Store-Code` 헤더).
@@ -227,96 +228,98 @@ const autoConfirmDaysDescription =
227
228
  "그 날짜가 지나면 구매확정(`PURCHASE_DECIDED`)으로 바꾼다. 진행 중인 클레임이 있으면 건너뛴다. `0`이면 자동 구매확정을 하지 않는다";
228
229
 
229
230
  /** `PATCH /v1/store` 본문 — 바꿀 필드만 보낸다 */
230
- export const updateStoreRequestSchema = z
231
- .object({
232
- name: z.string().min(2).max(50).optional(),
233
- logoUrl: z.url().optional(),
234
- customerCenterPhone: z
235
- .string()
236
- .nullable()
237
- .optional()
238
- .describe("고객센터 전화번호. `null`을 주면 지운다"),
239
- businessHours: z.string().max(100).optional(),
240
- ...businessInfoPatchShape,
241
- analyticsAllowedOrigins: z
242
- .array(analyticsOriginSchema)
243
- .max(MAX_ANALYTICS_ALLOWED_ORIGINS)
244
- .optional()
245
- .describe(
246
- "@deprecated `storefrontOrigins`를 쓴다(같은 목록). 방문 분석 수집을 받을 스토어프론트 오리진(최대 20개). 비우면 모든 오리진에서 받는다. " +
247
- "넣으면 목록에 없는 오리진의 수집 요청은 403 `ORIGIN_NOT_ALLOWED`이고, 페이지 URL이 목록 밖인 이벤트는 버린다",
248
- ),
249
- storefrontOrigins: z
250
- .array(analyticsOriginSchema)
251
- .max(MAX_ANALYTICS_ALLOWED_ORIGINS)
252
- .optional()
253
- .describe(
254
- "스토어프론트 도메인(최대 20개) — 소셜 로그인 뒤 돌아갈 주소와 방문 분석 수집을 함께 제한한다. " +
255
- "`analyticsAllowedOrigins`와 같은 목록이다(둘 다 주면 이 값이 이긴다)",
256
- ),
257
- guestCheckoutEnabled: z
258
- .boolean()
259
- .optional()
260
- .describe(
261
- "비회원 주문 허용. false(회원만)면 로그인하지 않은 구매자의 주문서 생성·결제 요청이 403 `GUEST_CHECKOUT_DISABLED`다. " +
262
- "장바구니 담기와 이미 받은 비회원 주문의 조회·취소는 막지 않는다",
263
- ),
264
- testOrderReviewsAllowed: z
265
- .boolean()
266
- .optional()
267
- .describe(
268
- "테스트 결제(샌드박스) 주문의 리뷰 허용. 기본 false — 돈을 내지 않은 주문으로 구매 인증 리뷰가 쌓이지 않게 막는다",
269
- ),
270
- autoDeliverDays: z
271
- .number()
272
- .int()
273
- .min(0)
274
- .max(MAX_AUTO_TRANSITION_DAYS)
275
- .optional()
276
- .describe(autoDeliverDaysDescription),
277
- autoConfirmDays: z
278
- .number()
279
- .int()
280
- .min(0)
281
- .max(MAX_AUTO_TRANSITION_DAYS)
282
- .optional()
283
- .describe(autoConfirmDaysDescription),
284
- refundPolicy: refundPolicyPatchSchema
285
- .optional()
286
- .describe(
287
- "상점 기본 환불 정책 — 준 항목만 바꾼다. 상품별 정책(`products.refundPolicy`)이 없는 상품에 적용된다",
288
- ),
289
- shippingPolicy: shippingPolicyPatchSchema
290
- .optional()
291
- .describe(
292
- "상점 배송비 규칙 — 준 항목만 바꾼다. 기본 배송비, 전체 무료배송 기준액, 제주·도서산간 추가 배송비다. " +
293
- "바꾼 값은 **새 주문서부터** 적용된다(이미 만든 주문서·주문의 배송비는 스냅샷이 원천이다)",
294
- ),
295
- termsVersion: policyVersionSchema
296
- .optional()
297
- .describe(
298
- "이용약관 버전. 올리면 이 약관에 동의한 구매자에게 재동의를 요구한다(`GET /storefront/v1/me`의 `reconsentRequired`)",
299
- ),
300
- privacyVersion: policyVersionSchema
301
- .optional()
302
- .describe("개인정보 수집이용 동의 버전. 올리면 구매자에게 재동의를 요구한다"),
303
- termsUrl: policyDocumentUrlSchema
304
- .optional()
305
- .describe(
306
- "이용약관 문서 주소(https). 동의 시점의 값이 동의 이력에 복사된다. `null`을 주면 지운다",
307
- ),
308
- privacyUrl: policyDocumentUrlSchema
309
- .optional()
310
- .describe("개인정보 수집이용 동의 문서 주소(https). `null`을 주면 지운다"),
311
- defaultLocale: localeCodeSchema
312
- .optional()
313
- .describe(
314
- "상점 기본 언어(이슈 #134). 상품·카테고리 필드가 이 언어 값이고 번역이 없는 칸은 이 값으로 보인다. 바꿔도 저장된 값은 그대로다",
315
- ),
316
- })
317
- .refine((value) => Object.values(value).some((v) => v !== undefined), {
318
- message: "최소 1개 필드가 필요합니다",
319
- });
231
+ export const updateStoreRequestSchema = strictRequest(
232
+ z
233
+ .object({
234
+ name: z.string().min(2).max(50).optional(),
235
+ logoUrl: z.url().optional(),
236
+ customerCenterPhone: z
237
+ .string()
238
+ .nullable()
239
+ .optional()
240
+ .describe("고객센터 전화번호. `null`을 주면 지운다"),
241
+ businessHours: z.string().max(100).optional(),
242
+ ...businessInfoPatchShape,
243
+ analyticsAllowedOrigins: z
244
+ .array(analyticsOriginSchema)
245
+ .max(MAX_ANALYTICS_ALLOWED_ORIGINS)
246
+ .optional()
247
+ .describe(
248
+ "@deprecated `storefrontOrigins`를 쓴다(같은 목록). 방문 분석 수집을 받을 스토어프론트 오리진(최대 20개). 비우면 모든 오리진에서 받는다. " +
249
+ "넣으면 목록에 없는 오리진의 수집 요청은 403 `ORIGIN_NOT_ALLOWED`이고, 페이지 URL이 목록 밖인 이벤트는 버린다",
250
+ ),
251
+ storefrontOrigins: z
252
+ .array(analyticsOriginSchema)
253
+ .max(MAX_ANALYTICS_ALLOWED_ORIGINS)
254
+ .optional()
255
+ .describe(
256
+ "스토어프론트 도메인(최대 20개) — 소셜 로그인 뒤 돌아갈 주소와 방문 분석 수집을 함께 제한한다. " +
257
+ "`analyticsAllowedOrigins`와 같은 목록이다(둘 다 주면 이 값이 이긴다)",
258
+ ),
259
+ guestCheckoutEnabled: z
260
+ .boolean()
261
+ .optional()
262
+ .describe(
263
+ "비회원 주문 허용. false(회원만)면 로그인하지 않은 구매자의 주문서 생성·결제 요청이 403 `GUEST_CHECKOUT_DISABLED`다. " +
264
+ "장바구니 담기와 이미 받은 비회원 주문의 조회·취소는 막지 않는다",
265
+ ),
266
+ testOrderReviewsAllowed: z
267
+ .boolean()
268
+ .optional()
269
+ .describe(
270
+ "테스트 결제(샌드박스) 주문의 리뷰 허용. 기본 false — 돈을 내지 않은 주문으로 구매 인증 리뷰가 쌓이지 않게 막는다",
271
+ ),
272
+ autoDeliverDays: z
273
+ .number()
274
+ .int()
275
+ .min(0)
276
+ .max(MAX_AUTO_TRANSITION_DAYS)
277
+ .optional()
278
+ .describe(autoDeliverDaysDescription),
279
+ autoConfirmDays: z
280
+ .number()
281
+ .int()
282
+ .min(0)
283
+ .max(MAX_AUTO_TRANSITION_DAYS)
284
+ .optional()
285
+ .describe(autoConfirmDaysDescription),
286
+ refundPolicy: refundPolicyPatchSchema
287
+ .optional()
288
+ .describe(
289
+ "상점 기본 환불 정책 — 준 항목만 바꾼다. 상품별 정책(`products.refundPolicy`)이 없는 상품에 적용된다",
290
+ ),
291
+ shippingPolicy: shippingPolicyPatchSchema
292
+ .optional()
293
+ .describe(
294
+ "상점 배송비 규칙 — 준 항목만 바꾼다. 기본 배송비, 전체 무료배송 기준액, 제주·도서산간 추가 배송비다. " +
295
+ "바꾼 값은 **새 주문서부터** 적용된다(이미 만든 주문서·주문의 배송비는 스냅샷이 원천이다)",
296
+ ),
297
+ termsVersion: policyVersionSchema
298
+ .optional()
299
+ .describe(
300
+ "이용약관 버전. 올리면 이 약관에 동의한 구매자에게 재동의를 요구한다(`GET /storefront/v1/me`의 `reconsentRequired`)",
301
+ ),
302
+ privacyVersion: policyVersionSchema
303
+ .optional()
304
+ .describe("개인정보 수집이용 동의 버전. 올리면 구매자에게 재동의를 요구한다"),
305
+ termsUrl: policyDocumentUrlSchema
306
+ .optional()
307
+ .describe(
308
+ "이용약관 문서 주소(https). 동의 시점의 값이 동의 이력에 복사된다. `null`을 주면 지운다",
309
+ ),
310
+ privacyUrl: policyDocumentUrlSchema
311
+ .optional()
312
+ .describe("개인정보 수집이용 동의 문서 주소(https). `null`을 주면 지운다"),
313
+ defaultLocale: localeCodeSchema
314
+ .optional()
315
+ .describe(
316
+ "상점 기본 언어(이슈 #134). 상품·카테고리 필드가 이 언어 값이고 번역이 없는 칸은 이 값으로 보인다. 바꿔도 저장된 값은 그대로다",
317
+ ),
318
+ })
319
+ .refine((value) => Object.values(value).some((v) => v !== undefined), {
320
+ message: "최소 1개 필드가 필요합니다",
321
+ }),
322
+ );
320
323
  export type UpdateStoreRequest = z.infer<typeof updateStoreRequestSchema>;
321
324
 
322
325
  export const storeSchema = z.object({
@@ -423,17 +426,21 @@ export const invitationSchema = z.object({
423
426
  export type Invitation = z.infer<typeof invitationSchema>;
424
427
 
425
428
  /** `POST /v1/store/invitations` 요청 — ADMIN 초대는 OWNER만 할 수 있다 */
426
- export const inviteMemberRequestSchema = z.object({
427
- email: z.email(),
428
- role: z.enum(["ADMIN", "STAFF"]),
429
- });
429
+ export const inviteMemberRequestSchema = strictRequest(
430
+ z.object({
431
+ email: z.email(),
432
+ role: z.enum(["ADMIN", "STAFF"]),
433
+ }),
434
+ );
430
435
 
431
436
  export type InviteMemberRequest = z.infer<typeof inviteMemberRequestSchema>;
432
437
 
433
438
  /** `PATCH /v1/store/members/{userId}` 요청 */
434
- export const updateMemberRoleRequestSchema = z.object({
435
- role: z.enum(["ADMIN", "STAFF"]),
436
- });
439
+ export const updateMemberRoleRequestSchema = strictRequest(
440
+ z.object({
441
+ role: z.enum(["ADMIN", "STAFF"]),
442
+ }),
443
+ );
437
444
 
438
445
  export type UpdateMemberRoleRequest = z.infer<typeof updateMemberRoleRequestSchema>;
439
446
 
@@ -484,19 +491,23 @@ export const sellerAddressSchema = z.object({
484
491
 
485
492
  export type SellerAddress = z.infer<typeof sellerAddressSchema>;
486
493
 
487
- export const sellerAddressRequestSchema = z.object({
488
- type: addressTypeSchema,
489
- name: z.string().min(1).max(50),
490
- contactName: z.string().min(1),
491
- phone: z.string().regex(/^01[0-9]{8,9}$/),
492
- zipCode: z.string().regex(/^[0-9]{5}$/),
493
- address1: z.string().min(1),
494
- address2: z.string().optional(),
495
- inventoryLocationId: z
496
- .string()
497
- .min(1)
498
- .optional()
499
- .describe("재고 위치 ID. 등록에서 생략하면 기본 위치, 수정에서 생략하면 지금 연결을 유지한다"),
500
- });
494
+ export const sellerAddressRequestSchema = strictRequest(
495
+ z.object({
496
+ type: addressTypeSchema,
497
+ name: z.string().min(1).max(50),
498
+ contactName: z.string().min(1),
499
+ phone: z.string().regex(/^01[0-9]{8,9}$/),
500
+ zipCode: z.string().regex(/^[0-9]{5}$/),
501
+ address1: z.string().min(1),
502
+ address2: z.string().optional(),
503
+ inventoryLocationId: z
504
+ .string()
505
+ .min(1)
506
+ .optional()
507
+ .describe(
508
+ "재고 위치 ID. 등록에서 생략하면 기본 위치, 수정에서 생략하면 지금 연결을 유지한다",
509
+ ),
510
+ }),
511
+ );
501
512
 
502
513
  export type SellerAddressRequest = z.infer<typeof sellerAddressRequestSchema>;