@sayren/storefront-sdk 0.6.0 → 0.8.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/auth/index.d.mts +22 -4
- package/dist/auth/index.mjs +42 -3
- package/dist/checkout-JFk3b8RG.mjs +189 -0
- package/dist/{client-Do9-LG5X.mjs → client-DwqExvZN.mjs} +114 -180
- package/dist/{http-CqAR0_w4.d.mts → http-BbFHVGBf.d.mts} +22 -1
- package/dist/index-BRXStiK2.d.mts +1998 -0
- package/dist/index.d.mts +3 -1530
- package/dist/index.mjs +3 -2
- package/dist/payments/index.d.mts +166 -0
- package/dist/payments/index.mjs +310 -0
- package/package.json +7 -2
- package/src/auth/index.ts +49 -2
- package/src/client.ts +51 -46
- package/src/payments/index.ts +541 -0
- package/src/schemas/auth.ts +25 -2
- package/src/schemas/catalog.ts +15 -4
- package/src/schemas/checkout.ts +148 -54
- package/src/schemas/inquiry.ts +8 -0
- package/src/schemas/member.ts +8 -0
- package/src/schemas/order.ts +19 -1
- package/src/schemas/review.ts +16 -0
- package/src/schemas/store.ts +1 -1
package/src/schemas/checkout.ts
CHANGED
|
@@ -37,6 +37,11 @@ export const checkoutSessionSchema = z.object({
|
|
|
37
37
|
totalAmount: z.number().int(),
|
|
38
38
|
}),
|
|
39
39
|
expiresAt: z.string(),
|
|
40
|
+
paymentOptions: z
|
|
41
|
+
.lazy(() => paymentOptionListSchema)
|
|
42
|
+
.describe(
|
|
43
|
+
"이 주문서에서 고를 수 있는 결제 옵션, PG 우선순위순. 셀러가 켠 PG·결제수단·간편결제만 담긴다. 비어 있으면 지금 결제할 수 없다",
|
|
44
|
+
),
|
|
40
45
|
testPayment: z
|
|
41
46
|
.boolean()
|
|
42
47
|
.describe(
|
|
@@ -56,6 +61,70 @@ export const paymentMethodSchema = z.enum([
|
|
|
56
61
|
|
|
57
62
|
export type PaymentMethod = z.infer<typeof paymentMethodSchema>;
|
|
58
63
|
|
|
64
|
+
/** 결제를 처리하는 PG. 셀러가 직접 계약하고 콘솔 설정 › 결제에서 연결한다 */
|
|
65
|
+
export const pgProviderSchema = z.enum(["tosspayments", "portone"]);
|
|
66
|
+
export type PgProvider = z.infer<typeof pgProviderSchema>;
|
|
67
|
+
|
|
68
|
+
/** 간편결제사. 토스페이먼츠·포트원 모두 같은 코드를 쓴다 */
|
|
69
|
+
export const easyPayProviderSchema = z.enum(["NAVERPAY", "KAKAOPAY", "TOSSPAY", "PAYCO"]);
|
|
70
|
+
export type EasyPayProvider = z.infer<typeof easyPayProviderSchema>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 응답에 실리는 간편결제사 — 서버가 간편결제사를 추가해도 파싱이 깨지지 않게 문자열로 받는다
|
|
74
|
+
* (`pgProvider`·결제 상태와 같은 방식). 요청과 결제 옵션은 값을 골라 보내는 자리라 enum 그대로다.
|
|
75
|
+
*/
|
|
76
|
+
export const easyPayProviderResponseSchema = z.string();
|
|
77
|
+
|
|
78
|
+
const pg = pgProviderSchema.describe("결제를 처리할 PG");
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* 결제 옵션 — 어느 PG로 어떤 결제수단을 쓸지. `method`로 좁히면 필요한 필드가 타입으로 정해진다
|
|
82
|
+
* (`EASY_PAY`만 `provider`가 있다). 주문서의 `paymentOptions` 항목을 그대로 넘기거나 직접 써도 된다.
|
|
83
|
+
* 셀러가 켜지 않은 조합이면 서버가 409 `PAYMENT_OPTION_UNAVAILABLE`로 거절한다.
|
|
84
|
+
*/
|
|
85
|
+
export const paymentOptionSchema = z.discriminatedUnion("method", [
|
|
86
|
+
z.object({ pg, method: z.literal("CARD") }),
|
|
87
|
+
z.object({
|
|
88
|
+
pg,
|
|
89
|
+
method: z.literal("EASY_PAY"),
|
|
90
|
+
provider: easyPayProviderSchema.describe("간편결제사 — 이 간편결제 결제창을 바로 연다"),
|
|
91
|
+
}),
|
|
92
|
+
z.object({ pg, method: z.literal("BANK_TRANSFER") }),
|
|
93
|
+
z.object({ pg, method: z.literal("VIRTUAL_ACCOUNT") }),
|
|
94
|
+
z.object({ pg, method: z.literal("MOBILE") }),
|
|
95
|
+
]);
|
|
96
|
+
export type PaymentOption = z.infer<typeof paymentOptionSchema>;
|
|
97
|
+
|
|
98
|
+
/** 주문서가 내려주는 결제 옵션 — 결제 옵션 + 표시 이름 */
|
|
99
|
+
export const availablePaymentOptionSchema = paymentOptionSchema.and(
|
|
100
|
+
z.object({
|
|
101
|
+
label: z.string().describe("결제수단 표시 이름 (예: 신용·체크카드, 네이버페이)"),
|
|
102
|
+
pgName: z.string().describe("PG 표시 이름 (예: 토스페이먼츠)"),
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
export type AvailablePaymentOption = z.infer<typeof availablePaymentOptionSchema>;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 결제 옵션 목록 — 서버가 나중에 추가한 결제수단·PG를 이 SDK가 모르면 **그 항목만 빼고** 읽는다(목록 파싱은 깨지지 않는다).
|
|
109
|
+
*
|
|
110
|
+
* 모르는 항목을 버리는 일은 `preprocess`가 하고 항목 타입은 그대로 남는다 — OpenAPI 문서에 `items` 없는
|
|
111
|
+
* 배열로 나가지 않게 하기 위해서다(`z.array(z.unknown()).transform(...)`은 출력 타입을 표현하지 못한다).
|
|
112
|
+
*/
|
|
113
|
+
export const paymentOptionListSchema = z.preprocess(
|
|
114
|
+
(value) =>
|
|
115
|
+
Array.isArray(value)
|
|
116
|
+
? value.filter((item) => availablePaymentOptionSchema.safeParse(item).success)
|
|
117
|
+
: value,
|
|
118
|
+
z.array(availablePaymentOptionSchema),
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
/** 결제 옵션을 화면 키로 — 라디오 value·React key. 예: `tosspayments:CARD`, `portone:EASY_PAY:NAVERPAY` */
|
|
122
|
+
export function paymentOptionKey(option: PaymentOption): string {
|
|
123
|
+
return option.method === "EASY_PAY"
|
|
124
|
+
? `${option.pg}:EASY_PAY:${option.provider}`
|
|
125
|
+
: `${option.pg}:${option.method}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
59
128
|
export const shippingAddressInputSchema = z.object({
|
|
60
129
|
addressId: z.string().optional(),
|
|
61
130
|
receiverName: z.string().min(1, "수령인명을 입력해주세요").max(50),
|
|
@@ -78,51 +147,43 @@ export const guestInfoSchema = z.object({
|
|
|
78
147
|
|
|
79
148
|
export type GuestInfo = z.infer<typeof guestInfoSchema>;
|
|
80
149
|
|
|
81
|
-
|
|
150
|
+
/**
|
|
151
|
+
* 결제 시작 — 배송지를 확정하고 고른 결제 옵션으로 결제 시도를 연다. 응답의 `payUrl`(결제 서비스)을 팝업(`mode=popup`)이나
|
|
152
|
+
* 전체 페이지로 열면 결제 서비스가 PG 결제창을 띄우고 승인까지 한다. 리다이렉트 결제가 끝나면 구매자는 `returnUrl`로 돌아온다.
|
|
153
|
+
* `returnUrl`의 도메인은 스토어 결제 도메인(콘솔 설정 › 결제)에 등록돼 있어야 한다(테스트 결제는 localhost 허용).
|
|
154
|
+
*/
|
|
155
|
+
export const startPaymentRequestSchema = z.object({
|
|
156
|
+
option: paymentOptionSchema,
|
|
157
|
+
returnUrl: z
|
|
158
|
+
.url()
|
|
159
|
+
.max(2048)
|
|
160
|
+
.describe(
|
|
161
|
+
"결제를 마치면 돌아올 스토어프론트 주소. 스토어 결제 도메인에 등록된 도메인이어야 한다",
|
|
162
|
+
),
|
|
82
163
|
shippingAddress: shippingAddressInputSchema,
|
|
83
|
-
paymentMethod: paymentMethodSchema,
|
|
84
164
|
guest: guestInfoSchema.optional(),
|
|
85
165
|
});
|
|
86
166
|
|
|
87
|
-
export type
|
|
167
|
+
export type StartPaymentRequest = z.infer<typeof startPaymentRequestSchema>;
|
|
88
168
|
|
|
89
|
-
/**
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
* 토스 `clientKey`·`orderId`…, 포트원 `storeId`·`channelKey`… 같은 PG별 결제창 값). 공개 값뿐이며
|
|
94
|
-
* 시크릿은 어떤 키에도 없다. 서버가 키를 추가·변경해도 파싱이 깨지지 않도록 모르는 키는 그대로 통과시킨다.
|
|
95
|
-
*/
|
|
96
|
-
export const pgParamsSchema = z.looseObject({
|
|
97
|
-
popupUrl: z.string().describe("결제 팝업 진입 URL. `window.open`으로 띄운다"),
|
|
98
|
-
attemptId: z
|
|
99
|
-
.string()
|
|
100
|
-
.optional()
|
|
101
|
-
.describe(
|
|
102
|
-
"첫 결제 시도 id(`att_…`). PG에 보내는 주문번호(토스 `orderId`, 포트원 `paymentId`)다. 팝업 내부 값",
|
|
103
|
-
),
|
|
104
|
-
provider: z.string().optional().describe("첫 결제 시도의 PG (`pgProvider`와 같다). 팝업 내부 값"),
|
|
105
|
-
mock: z
|
|
106
|
-
.boolean()
|
|
107
|
-
.optional()
|
|
108
|
-
.describe("모의 결제 여부. true면 결제 팝업이 PG SDK 대신 모의 결제 UI를 띄운다. 팝업 내부 값"),
|
|
109
|
-
environment: z
|
|
110
|
-
.string()
|
|
111
|
-
.optional()
|
|
112
|
-
.describe("첫 결제 시도의 결제 환경 (`TEST` 샌드박스 · `LIVE` 실결제). 팝업 내부 값"),
|
|
169
|
+
/** 같은 결제에서 다른 결제 옵션으로 다시 시도. `returnUrl`을 생략하면 결제 시작 때의 복귀 주소를 쓴다 */
|
|
170
|
+
export const retryPaymentRequestSchema = z.object({
|
|
171
|
+
option: paymentOptionSchema,
|
|
172
|
+
returnUrl: startPaymentRequestSchema.shape.returnUrl.optional(),
|
|
113
173
|
});
|
|
114
174
|
|
|
115
|
-
export type
|
|
175
|
+
export type RetryPaymentRequest = z.infer<typeof retryPaymentRequestSchema>;
|
|
116
176
|
|
|
117
|
-
export const
|
|
118
|
-
paymentId: z.string(),
|
|
119
|
-
|
|
177
|
+
export const paymentStartSchema = z.object({
|
|
178
|
+
paymentId: z.string().describe("결제 id. 상태 조회·재시도의 키다"),
|
|
179
|
+
attemptId: z.string().describe("결제 시도 id. PG 주문번호(토스 orderId, 포트원 paymentId)다"),
|
|
180
|
+
option: paymentOptionSchema.describe("이 시도의 결제 옵션"),
|
|
181
|
+
payUrl: z
|
|
120
182
|
.string()
|
|
121
183
|
.describe(
|
|
122
|
-
"
|
|
184
|
+
"결제 서비스 주소. 팝업으로 열려면 쿼리 `mode=popup`을 붙이고, 그대로 이동하면 리다이렉트 결제다",
|
|
123
185
|
),
|
|
124
|
-
|
|
125
|
-
expiresAt: z.string(),
|
|
186
|
+
expiresAt: z.string().describe("결제 요청 만료 시각"),
|
|
126
187
|
testPayment: z
|
|
127
188
|
.boolean()
|
|
128
189
|
.describe(
|
|
@@ -130,27 +191,15 @@ export const paymentParamsSchema = z.object({
|
|
|
130
191
|
),
|
|
131
192
|
});
|
|
132
193
|
|
|
133
|
-
export type
|
|
134
|
-
|
|
135
|
-
export const confirmPaymentRequestSchema = z.object({
|
|
136
|
-
pgToken: z.string().min(1).describe("PG 승인 키 (토스 `paymentKey`, 포트원 `txId`)"),
|
|
137
|
-
attemptId: z
|
|
138
|
-
.string()
|
|
139
|
-
.min(1)
|
|
140
|
-
.optional()
|
|
141
|
-
.describe("승인할 결제 시도 id (결제창이 돌려준 주문번호). 생략하면 현재 시도"),
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
export type ConfirmPaymentRequest = z.infer<typeof confirmPaymentRequestSchema>;
|
|
145
|
-
|
|
146
|
-
export const confirmPaymentResultSchema = z.object({
|
|
147
|
-
orderId: z.string(),
|
|
148
|
-
status: z.literal("PAID"),
|
|
149
|
-
totalAmount: z.number().int(),
|
|
150
|
-
paidAt: z.string(),
|
|
151
|
-
});
|
|
194
|
+
export type PaymentStart = z.infer<typeof paymentStartSchema>;
|
|
152
195
|
|
|
153
|
-
|
|
196
|
+
/** 결제창에서 결제하지 못한 이유 */
|
|
197
|
+
export const paymentFailureCategorySchema = z.enum([
|
|
198
|
+
"PREPARE_FAILURE",
|
|
199
|
+
"DECLINED",
|
|
200
|
+
"USER_CANCELED",
|
|
201
|
+
]);
|
|
202
|
+
export type PaymentFailureCategory = z.infer<typeof paymentFailureCategorySchema>;
|
|
154
203
|
|
|
155
204
|
/**
|
|
156
205
|
* 결제 상태 조회의 현재 상태 값 — 응답 스키마는 서버가 상태를 추가해도 파싱이 깨지지 않게 문자열로 받는다
|
|
@@ -165,6 +214,17 @@ export const PAYMENT_STATUS_VALUES = [
|
|
|
165
214
|
] as const;
|
|
166
215
|
export type KnownPaymentStatus = (typeof PAYMENT_STATUS_VALUES)[number];
|
|
167
216
|
|
|
217
|
+
/** 결제 결과 구분 — 결제 서비스가 스토어프론트에 돌려주는 값과 같다 */
|
|
218
|
+
export const PAYMENT_RESULT_VALUES = [
|
|
219
|
+
"COMPLETED",
|
|
220
|
+
"PROCESSING",
|
|
221
|
+
"CANCELED",
|
|
222
|
+
"FAILED",
|
|
223
|
+
"EXPIRED",
|
|
224
|
+
"PENDING",
|
|
225
|
+
] as const;
|
|
226
|
+
export type KnownPaymentResult = (typeof PAYMENT_RESULT_VALUES)[number];
|
|
227
|
+
|
|
168
228
|
export const paymentStatusSchema = z.object({
|
|
169
229
|
paymentId: z.string(),
|
|
170
230
|
status: z
|
|
@@ -173,7 +233,28 @@ export const paymentStatusSchema = z.object({
|
|
|
173
233
|
"결제 상태. 현재 값은 `pending` 결제 대기 · `processing` 승인 확인 중 · `completed` 결제 완료(주문 생성) · `failed` 실패 · " +
|
|
174
234
|
"`expired` 만료예요. 상태가 추가될 수 있어 문자열로 받아요 — 모르는 값은 `processing`처럼 다루고 계속 조회하세요",
|
|
175
235
|
),
|
|
236
|
+
result: z
|
|
237
|
+
.string()
|
|
238
|
+
.describe(
|
|
239
|
+
"화면 분기용 결과. `COMPLETED` 결제 완료 · `PROCESSING` 결과 확인 중 · `CANCELED` 구매자가 결제창을 닫음 · " +
|
|
240
|
+
"`FAILED` 결제 실패(다른 결제 옵션으로 재시도 가능) · `EXPIRED` 결제 요청 만료 · `PENDING` 결제 전이에요. " +
|
|
241
|
+
"값이 추가될 수 있어 문자열로 받아요 — 모르는 값은 `PROCESSING`처럼 다루세요",
|
|
242
|
+
),
|
|
176
243
|
orderId: z.string().nullable().describe("결제가 완료됐으면 주문 번호, 그 외에는 null"),
|
|
244
|
+
lastFailure: z
|
|
245
|
+
.object({
|
|
246
|
+
attemptId: z.string(),
|
|
247
|
+
category: z
|
|
248
|
+
.string()
|
|
249
|
+
.describe("`PREPARE_FAILURE`·`DECLINED`·`USER_CANCELED`(값이 추가될 수 있다)"),
|
|
250
|
+
code: z
|
|
251
|
+
.string()
|
|
252
|
+
.nullable()
|
|
253
|
+
.describe("PG가 준 실패 코드. 내부 사유는 null이에요. 화면 분기는 `category`로 하세요"),
|
|
254
|
+
message: z.string().nullable().describe("구매자에게 보여 줄 안내 문구"),
|
|
255
|
+
})
|
|
256
|
+
.nullable()
|
|
257
|
+
.describe("현재 결제 시도가 실패·취소로 끝났으면 그 내용, 아니면 null"),
|
|
177
258
|
testPayment: z
|
|
178
259
|
.boolean()
|
|
179
260
|
.describe("테스트 결제(샌드박스)인가. true면 실제로 돈이 나가지 않았어요"),
|
|
@@ -181,3 +262,16 @@ export const paymentStatusSchema = z.object({
|
|
|
181
262
|
});
|
|
182
263
|
|
|
183
264
|
export type PaymentStatus = z.infer<typeof paymentStatusSchema>;
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* 결제 서비스가 팝업 opener에 보내는 메시지 — `type`으로 거르고 결과의 원천은 결제 상태 조회다.
|
|
268
|
+
* 안내 문구는 싣지 않는다. 화면 문구는 상태 조회의 `lastFailure`를 쓴다
|
|
269
|
+
*/
|
|
270
|
+
export const paymentMessageSchema = z.object({
|
|
271
|
+
type: z.literal("sayren:payment"),
|
|
272
|
+
paymentId: z.string(),
|
|
273
|
+
result: z.string(),
|
|
274
|
+
orderId: z.string().optional(),
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
export type PaymentMessage = z.infer<typeof paymentMessageSchema>;
|
package/src/schemas/inquiry.ts
CHANGED
|
@@ -23,3 +23,11 @@ export const createInquiryRequestSchema = z.object({
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
export type CreateInquiryRequest = z.infer<typeof createInquiryRequestSchema>;
|
|
26
|
+
|
|
27
|
+
/** `POST /products/{productId}/inquiries` 응답 */
|
|
28
|
+
export const createInquiryResultSchema = z.object({
|
|
29
|
+
inquiryId: z.string(),
|
|
30
|
+
createdAt: z.string(),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export type CreateInquiryResult = z.infer<typeof createInquiryResultSchema>;
|
package/src/schemas/member.ts
CHANGED
|
@@ -49,3 +49,11 @@ export const memberAddressRequestSchema = z.object({
|
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
export type MemberAddressRequest = z.infer<typeof memberAddressRequestSchema>;
|
|
52
|
+
|
|
53
|
+
/** `POST /me/wishlist` 응답 — 이미 찜한 상품이어도 같은 응답이다 */
|
|
54
|
+
export const wishlistAddResultSchema = z.object({
|
|
55
|
+
productId: z.string(),
|
|
56
|
+
wished: z.literal(true),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export type WishlistAddResult = z.infer<typeof wishlistAddResultSchema>;
|
package/src/schemas/order.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { paymentMethodSchema } from "./checkout";
|
|
2
|
+
import { easyPayProviderResponseSchema, paymentMethodSchema } from "./checkout";
|
|
3
3
|
import { orderItemStatusSchema } from "./common";
|
|
4
4
|
|
|
5
5
|
export const myOrderItemSchema = z.object({
|
|
@@ -46,6 +46,15 @@ export const myOrderSchema = z.object({
|
|
|
46
46
|
method: paymentMethodSchema.describe(
|
|
47
47
|
"실제 결제수단(PG가 보고한 수단, 모르면 주문서에서 고른 수단). 결제창에서 바뀔 수 있다(카드 결제창의 간편결제 탭 등)",
|
|
48
48
|
),
|
|
49
|
+
easyPayProvider: easyPayProviderResponseSchema
|
|
50
|
+
.nullable()
|
|
51
|
+
.optional()
|
|
52
|
+
.default(null)
|
|
53
|
+
.describe(
|
|
54
|
+
"간편결제사. `method`가 `EASY_PAY`일 때만 값이 있고, PG가 알려 주지 않았으면 주문서에서 고른 간편결제사다. " +
|
|
55
|
+
"그 밖의 결제수단과 간편결제 이전 주문은 null. 서버는 항상 싣는다. " +
|
|
56
|
+
"현재 값은 `NAVERPAY`·`KAKAOPAY`·`TOSSPAY`·`PAYCO`이고 값이 추가될 수 있어 문자열로 받는다",
|
|
57
|
+
),
|
|
49
58
|
totalAmount: z.number().int(),
|
|
50
59
|
paidAt: z.string().nullable(),
|
|
51
60
|
receiptUrl: z.url().nullable(),
|
|
@@ -74,3 +83,12 @@ export const deliveryTrackingSchema = z.object({
|
|
|
74
83
|
});
|
|
75
84
|
|
|
76
85
|
export type DeliveryTracking = z.infer<typeof deliveryTrackingSchema>;
|
|
86
|
+
|
|
87
|
+
/** `POST /me/order-items/{orderItemId}/purchase-decision` 응답 */
|
|
88
|
+
export const purchaseDecisionResultSchema = z.object({
|
|
89
|
+
orderItemId: z.string(),
|
|
90
|
+
status: z.literal("PURCHASE_DECIDED"),
|
|
91
|
+
decidedAt: z.string(),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
export type PurchaseDecisionResult = z.infer<typeof purchaseDecisionResultSchema>;
|
package/src/schemas/review.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { pageSchema } from "./common";
|
|
2
3
|
|
|
3
4
|
export const publicReviewSchema = z.object({
|
|
4
5
|
reviewId: z.string(),
|
|
@@ -63,3 +64,18 @@ export const updateReviewRequestSchema = z
|
|
|
63
64
|
});
|
|
64
65
|
|
|
65
66
|
export type UpdateReviewRequest = z.infer<typeof updateReviewRequestSchema>;
|
|
67
|
+
|
|
68
|
+
/** `GET /products/{productId}/reviews` 응답 — 리뷰 페이지와 평점 분포 */
|
|
69
|
+
export const reviewPageSchema = pageSchema(publicReviewSchema).extend({
|
|
70
|
+
summary: reviewSummarySchema.optional(),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
export type ReviewPage = z.infer<typeof reviewPageSchema>;
|
|
74
|
+
|
|
75
|
+
/** `PUT /me/reviews/{reviewId}` 응답 */
|
|
76
|
+
export const updateReviewResultSchema = z.object({
|
|
77
|
+
reviewId: z.string(),
|
|
78
|
+
updatedAt: z.string(),
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
export type UpdateReviewResult = z.infer<typeof updateReviewResultSchema>;
|