@sayren/storefront-sdk 0.16.0 → 0.17.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.mjs +1 -1
- package/dist/{checkout-DTfoCsMF.mjs → checkout-C25liqdW.mjs} +83 -6
- package/dist/{client-BrDY5HO3.mjs → client-CBAgQuTc.mjs} +10 -3
- package/dist/{index-BeQwCRc8.d.mts → index-BsHuMzBD.d.mts} +350 -74
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +3 -3
- package/dist/payments/index.d.mts +1 -1
- package/dist/payments/index.mjs +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/schemas/cart.ts +9 -0
- package/src/schemas/catalog.ts +15 -0
- package/src/schemas/checkout.ts +13 -1
- package/src/schemas/coupon.ts +19 -2
- package/src/schemas/order.ts +2 -0
- package/src/schemas/product-options.ts +128 -0
package/dist/auth/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { pt as ApiError, t as createStorefrontClient } from "../client-
|
|
1
|
+
import { pt as ApiError, t as createStorefrontClient } from "../client-CBAgQuTc.mjs";
|
|
2
2
|
//#region src/auth/index.ts
|
|
3
3
|
/** 소셜 로그인 실패 — 구매자가 취소했거나(`access_denied`) state가 맞지 않는다 */
|
|
4
4
|
var IdpCallbackError = class extends Error {
|
|
@@ -61,6 +61,77 @@ const myOrderItemFulfillmentSnapshotSchema = openUnion(z.discriminatedUnion("typ
|
|
|
61
61
|
requiresShipping: z.literal(false)
|
|
62
62
|
})])).describe("주문 시점 이행 스냅샷. 값이 추가될 수 있어 SDK는 모르는 유형을 `OTHER`로 읽는다");
|
|
63
63
|
//#endregion
|
|
64
|
+
//#region src/schemas/product-options.ts
|
|
65
|
+
/**
|
|
66
|
+
* 추가 선택·직접 입력 (이슈 #59) — 상품 상세의 옵션 표시, 장바구니 담기·바로 구매 요청, 줄 스냅샷의 공통 모양.
|
|
67
|
+
*
|
|
68
|
+
* 추가 선택은 재고가 없는 옵션이다. 구매자가 조합(옵션이 없으면 상품)을 고른 뒤 옵션명마다 값 하나를 더 고르고, 값의 추가금이
|
|
69
|
+
* 단가에 더해진다. 직접 입력은 구매자가 글자를 적는 항목(각인 문구 등)이다. 추가 선택 값이나 직접 입력값이 다르면 장바구니에서 다른 줄이다.
|
|
70
|
+
*/
|
|
71
|
+
const addonGroupViewSchema = z.object({
|
|
72
|
+
groupId: z.string(),
|
|
73
|
+
name: z.string(),
|
|
74
|
+
required: z.boolean().describe("꼭 골라야 하는가. false면 고르지 않아도 된다(「선택 안 함」)"),
|
|
75
|
+
values: z.array(z.object({
|
|
76
|
+
valueId: z.string(),
|
|
77
|
+
name: z.string(),
|
|
78
|
+
additionalPrice: z.number().int().describe("이 값을 고르면 단가에 더하는 금액(원, 0 이상)")
|
|
79
|
+
})).describe("고를 수 있는 값(셀러가 끈 값은 빠진다)")
|
|
80
|
+
});
|
|
81
|
+
const customInputViewSchema = z.object({
|
|
82
|
+
inputId: z.string(),
|
|
83
|
+
label: z.string().describe("항목명"),
|
|
84
|
+
placeholder: z.string().nullable().describe("입력 안내. 없으면 null"),
|
|
85
|
+
maxLength: z.number().int().describe("최대 글자 수"),
|
|
86
|
+
required: z.boolean()
|
|
87
|
+
});
|
|
88
|
+
/**
|
|
89
|
+
* 직접 입력값 정규화 — NFC로 모으고, 제어 문자(C0·C1·줄바꿈·줄·문단 구분자)는 공백으로, 제로폭·양방향 제어 문자는 지운 뒤
|
|
90
|
+
* 앞뒤 공백을 지운다. 서버가 저장하는 값이 이것이다. 빈 문자열이면 입력하지 않은 것으로 본다.
|
|
91
|
+
* (양방향 제어 문자를 두면 셀러 주문 화면의 각인 문구가 뒤집혀 보이게 할 수 있다.)
|
|
92
|
+
*/
|
|
93
|
+
function normalizeCustomInputValue(value) {
|
|
94
|
+
return value.normalize("NFC").replace(/[\u0000-\u001f\u007f-\u009f\u2028\u2029]/g, " ").replace(/[\u200b-\u200f\u202a-\u202e\u2060-\u2064\u2066-\u2069\ufeff]/g, "").trim();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* 직접 입력값의 글자 수 — 정규화한 값의 **코드 포인트 수**다(이모지 하나가 1자). 서버의 최대 글자 수 판정(`CUSTOM_INPUT_TOO_LONG`)과
|
|
98
|
+
* 스토어프론트·콘솔의 글자 수 표시가 이 함수 하나를 쓴다. `String.length`(UTF-16)로 세면 이모지가 2자로 세어 판정이 갈린다.
|
|
99
|
+
*/
|
|
100
|
+
function customInputLength(value) {
|
|
101
|
+
return [...normalizeCustomInputValue(value)].length;
|
|
102
|
+
}
|
|
103
|
+
/** 담기·바로 구매 요청의 직접 입력값 한 칸. 앞뒤 공백을 지우고, 빈 값은 입력하지 않은 것으로 본다 */
|
|
104
|
+
const customInputEntrySchema = z.object({
|
|
105
|
+
inputId: z.string(),
|
|
106
|
+
value: z.string().max(1e3)
|
|
107
|
+
});
|
|
108
|
+
/** 고른 추가 선택 한 칸 — 옵션명(`groupId`)과 그 옵션명의 값(`valueId`) */
|
|
109
|
+
const addonSelectionSchema = z.object({
|
|
110
|
+
groupId: z.string(),
|
|
111
|
+
valueId: z.string()
|
|
112
|
+
});
|
|
113
|
+
/** 요청의 추가 선택·직접 입력 필드 — 담기·장바구니 수정·바로 구매가 같은 이름을 쓴다 */
|
|
114
|
+
const lineSelectionRequestShape = {
|
|
115
|
+
addons: z.array(addonSelectionSchema).max(20).optional().describe("고른 추가 선택(옵션명마다 하나, 고르지 않은 옵션명은 빼고 보낸다). 필수 옵션명을 빼면 400 `ADDON_OPTION_REQUIRED`, 없거나 꺼진 값이거나 한 옵션명에서 둘을 고르면 400 `ADDON_OPTION_NOT_FOUND`"),
|
|
116
|
+
customInputs: z.array(customInputEntrySchema).max(20).optional().describe("직접 입력값. 필수 항목을 비우면 400 `CUSTOM_INPUT_REQUIRED`, 최대 글자 수를 넘으면 400 `CUSTOM_INPUT_TOO_LONG`, 없는 항목이면 400 `CUSTOM_INPUT_NOT_FOUND`")
|
|
117
|
+
};
|
|
118
|
+
/** 줄의 옵션 선택 스냅샷 한 칸 — 조합 옵션은 옵션명마다 한 칸이고 추가금이 0이다(조합 추가금은 단가에 들어 있다) */
|
|
119
|
+
const optionSelectionViewSchema = z.object({
|
|
120
|
+
kind: z.string().describe("옵션명 방식. 현재 값은 `combination`·`addon`이고 값이 추가될 수 있어 문자열로 받는다"),
|
|
121
|
+
groupName: z.string(),
|
|
122
|
+
valueName: z.string(),
|
|
123
|
+
additionalPrice: z.number().int()
|
|
124
|
+
});
|
|
125
|
+
const customInputValueViewSchema = z.object({
|
|
126
|
+
label: z.string().describe("항목명"),
|
|
127
|
+
value: z.string().describe("구매자가 적은 값")
|
|
128
|
+
});
|
|
129
|
+
/** 응답 줄의 표시 필드 — 장바구니·주문서·주문상품이 같은 이름을 쓴다 */
|
|
130
|
+
const lineSelectionResponseShape = {
|
|
131
|
+
optionSelections: z.array(optionSelectionViewSchema).optional().default([]).describe("옵션 선택(조합 옵션 + 추가 선택). 옵션이 없으면 빈 배열. 서버는 항상 싣는다"),
|
|
132
|
+
customInputs: z.array(customInputValueViewSchema).optional().default([]).describe("직접 입력값(항목명과 값). 없으면 빈 배열. 서버는 항상 싣는다")
|
|
133
|
+
};
|
|
134
|
+
//#endregion
|
|
64
135
|
//#region src/schemas/coupon.ts
|
|
65
136
|
/**
|
|
66
137
|
* 스토어프론트 쿠폰 계약 (이슈 #47).
|
|
@@ -75,7 +146,8 @@ const myOrderItemFulfillmentSnapshotSchema = openUnion(z.discriminatedUnion("typ
|
|
|
75
146
|
const couponApplicationSchema = z.object({
|
|
76
147
|
issueId: z.string().min(1).optional().describe("내 쿠폰(발급 쿠폰) id — `GET /me/coupons`의 `issueId`"),
|
|
77
148
|
code: z.string().trim().min(1).max(30).optional().describe("쿠폰 코드. 대소문자를 구분하지 않는다"),
|
|
78
|
-
optionId: z.string().optional().describe("상품 쿠폰을 걸 주문서 항목의 `optionId`. 생략하면 할인이 가장 큰 항목에 건다. 주문 쿠폰에는 쓰지
|
|
149
|
+
optionId: z.string().optional().describe("상품 쿠폰을 걸 주문서 항목의 `optionId`. 생략하면 할인이 가장 큰 항목에 건다. 주문 쿠폰에는 쓰지 않는다. 같은 `optionId`의 줄이 여럿이면 적용하지 못한다(`LINE_AMBIGUOUS`) — 그때는 `lineId`를 쓴다"),
|
|
150
|
+
lineId: z.string().optional().describe("상품 쿠폰을 걸 주문서 줄의 `lineId`(이슈 #59). 주면 `optionId`보다 우선한다. 주문 쿠폰에는 쓰지 않는다")
|
|
79
151
|
}).refine((value) => (value.issueId ? 1 : 0) + (value.code ? 1 : 0) === 1, { message: "issueId와 code 중 하나만 보내 주십시오" });
|
|
80
152
|
/** 한 번에 적용할 수 있는 쿠폰 수 */
|
|
81
153
|
const MAX_COUPONS_PER_CHECKOUT = 5;
|
|
@@ -96,8 +168,9 @@ const couponResultSchema = z.object({
|
|
|
96
168
|
benefit: couponBenefitViewSchema,
|
|
97
169
|
applied: z.boolean(),
|
|
98
170
|
discountAmount: z.number().int().describe("이 쿠폰의 할인액. 적용하지 못했으면 0"),
|
|
99
|
-
rejectReason: z.string().nullable().describe("적용하지 못한 사유. `MIN_ORDER_AMOUNT`(최소 주문 금액 미달)·`NO_ELIGIBLE_ITEMS`(대상 상품 없음)·`NOT_STARTED`·`EXPIRED`·`MEMBER_ONLY`(회원 전용)·`STACK_LIMIT`(같은 종류 쿠폰이 이미 적용됨)·`DUPLICATE_COUPON`·`LINE_NOT_ELIGIBLE`·`NO_DISCOUNT`·`IN_USE`(다른 결제에서 쓰는 중)·`LIMIT_REACHED`(1인 사용 한도)·`EXHAUSTED`(총 사용 한도)·`INACTIVE`(중지된 쿠폰). 값이 늘 수 있다"),
|
|
100
|
-
optionId: z.string().nullable().describe("상품 쿠폰이 걸린 주문서 항목의 `optionId`. 그 밖은 null")
|
|
171
|
+
rejectReason: z.string().nullable().describe("적용하지 못한 사유. `MIN_ORDER_AMOUNT`(최소 주문 금액 미달)·`NO_ELIGIBLE_ITEMS`(대상 상품 없음)·`NOT_STARTED`·`EXPIRED`·`MEMBER_ONLY`(회원 전용)·`STACK_LIMIT`(같은 종류 쿠폰이 이미 적용됨)·`DUPLICATE_COUPON`·`LINE_NOT_ELIGIBLE`·`NO_DISCOUNT`·`LINE_AMBIGUOUS`(같은 `optionId`의 줄이 여럿, `lineId`로 지목한다)·`IN_USE`(다른 결제에서 쓰는 중)·`LIMIT_REACHED`(1인 사용 한도)·`EXHAUSTED`(총 사용 한도)·`INACTIVE`(중지된 쿠폰). 값이 늘 수 있다"),
|
|
172
|
+
optionId: z.string().nullable().describe("상품 쿠폰이 걸린 주문서 항목의 `optionId`. 그 밖은 null"),
|
|
173
|
+
lineId: z.string().nullable().optional().default(null).describe("상품 쿠폰이 걸린 주문서 줄의 `lineId`(이슈 #59). 그 밖은 null. 서버는 항상 싣는다")
|
|
101
174
|
});
|
|
102
175
|
/** 쿠폰을 반영한 금액 — 결제 금액 = productAmount − couponDiscountAmount + deliveryFee − deliveryDiscountAmount */
|
|
103
176
|
const pricingAmountsSchema = z.object({
|
|
@@ -119,6 +192,7 @@ const checkoutPricingSchema = z.object({
|
|
|
119
192
|
coupons: z.array(couponResultSchema).describe("요청한 쿠폰마다 한 줄, 요청 순서대로"),
|
|
120
193
|
items: z.array(z.object({
|
|
121
194
|
optionId: z.string().nullable(),
|
|
195
|
+
lineId: z.string().optional().describe("주문서 줄의 `lineId`(이슈 #59). 서버는 항상 싣는다"),
|
|
122
196
|
couponDiscountAmount: z.number().int().describe("이 항목에 들어간 쿠폰 할인")
|
|
123
197
|
})).describe("주문서 항목별 쿠폰 할인 — 주문서 `items`와 같은 순서"),
|
|
124
198
|
payable: z.boolean().describe("이 금액으로 결제를 시작할 수 있는가 — 적용하지 못한 쿠폰이 있거나 결제 금액이 100원 미만이면 false")
|
|
@@ -164,7 +238,8 @@ const createCheckoutRequestSchema = z.object({
|
|
|
164
238
|
directItem: z.object({
|
|
165
239
|
productId: z.string(),
|
|
166
240
|
optionId: z.string().optional(),
|
|
167
|
-
quantity: z.number().int().min(1)
|
|
241
|
+
quantity: z.number().int().min(1),
|
|
242
|
+
...lineSelectionRequestShape
|
|
168
243
|
}).optional()
|
|
169
244
|
}).refine((value) => value.cartItemIds ? !value.directItem : !!value.directItem, { message: "cartItemIds와 directItem 중 하나만 전달해야 합니다" });
|
|
170
245
|
/** 지역 추가 배송비 구분 — 우편번호로 판정한다 */
|
|
@@ -195,13 +270,15 @@ const checkoutDeliverySchema = z.object({
|
|
|
195
270
|
const checkoutSessionSchema = z.object({
|
|
196
271
|
checkoutId: z.string(),
|
|
197
272
|
items: z.array(z.object({
|
|
273
|
+
lineId: z.string().optional().describe("주문서 줄 id(이슈 #59). 같은 `optionId`가 추가 선택·직접 입력이 달라 여러 줄에 나올 수 있어, 상품 쿠폰을 걸 줄은 이 값으로 지목한다. 서버는 항상 싣는다"),
|
|
198
274
|
productId: z.string(),
|
|
199
275
|
productName: z.string(),
|
|
200
276
|
/** variantId. 옵션 없는 상품은 default variant id */
|
|
201
277
|
optionId: z.string().nullable(),
|
|
202
278
|
optionName: z.string().nullable(),
|
|
279
|
+
...lineSelectionResponseShape,
|
|
203
280
|
quantity: z.number().int(),
|
|
204
|
-
unitPrice: z.number().int(),
|
|
281
|
+
unitPrice: z.number().int().describe("단가 — 할인 반영 판매가 + 조합 추가금 + 추가 선택 추가금"),
|
|
205
282
|
totalPrice: z.number().int(),
|
|
206
283
|
fulfillment: lineFulfillmentSchema.describe("주문서 시점 상품 이행")
|
|
207
284
|
})),
|
|
@@ -475,4 +552,4 @@ const paymentMessageSchema = z.object({
|
|
|
475
552
|
orderId: z.string().optional()
|
|
476
553
|
});
|
|
477
554
|
//#endregion
|
|
478
|
-
export { startPaymentRequestSchema as A, myCouponListQuerySchema as B, paymentStartSchema as C, residentNumberLike as D, remoteAreaSchema as E, checkoutPricingSchema as F,
|
|
555
|
+
export { lineFulfillmentSchema as $, startPaymentRequestSchema as A, myCouponListQuerySchema as B, paymentStartSchema as C, residentNumberLike as D, remoteAreaSchema as E, checkoutPricingSchema as F, customInputEntrySchema as G, pricingAmountsSchema as H, couponApplicationListSchema as I, customInputViewSchema as J, customInputLength as K, couponApplicationSchema as L, MIN_PAYMENT_AMOUNT as M, applicableCouponSchema as N, retryPaymentRequestSchema as O, checkoutPricingRequestSchema as P, optionSelectionViewSchema as Q, couponBenefitViewSchema as R, paymentOptionSchema as S, pgProviderSchema as T, addonGroupViewSchema as U, myCouponSchema as V, addonSelectionSchema as W, lineSelectionResponseShape as X, lineSelectionRequestShape as Y, normalizeCustomInputValue as Z, paymentFailureCategorySchema as _, cashReceiptAvailable as a, paymentOptionKey as b, cashReceiptTypeSchema as c, createCheckoutRequestSchema as d, myOrderItemFulfillmentSnapshotSchema as et, deliveryQuoteRequestSchema as f, guestInfoSchema as g, easyPayProviderSchema as h, availablePaymentOptionSchema as i, MAX_COUPONS_PER_CHECKOUT as j, shippingAddressInputSchema as k, checkoutDeliverySchema as l, easyPayProviderResponseSchema as m, PAYMENT_RESULT_VALUES as n, productFulfillmentViewSchema as nt, cashReceiptIdentityTypeOf as o, deliveryQuoteSchema as p, customInputValueViewSchema as q, PAYMENT_STATUS_VALUES as r, cashReceiptRequestSchema as s, CASH_RECEIPT_METHODS as t, productCardFulfillmentSchema as tt, checkoutSessionSchema as u, paymentMessageSchema as v, paymentStatusSchema as w, paymentOptionListSchema as x, paymentMethodSchema as y, couponResultSchema as z };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as ANALYTICS_VISITOR_HEADER, r as ANALYTICS_SESSION_HEADER } from "./analytics-CgD70OqH.mjs";
|
|
2
|
-
import { A as startPaymentRequestSchema, C as paymentStartSchema, F as checkoutPricingSchema,
|
|
2
|
+
import { $ as lineFulfillmentSchema, A as startPaymentRequestSchema, C as paymentStartSchema, F as checkoutPricingSchema, J as customInputViewSchema, N as applicableCouponSchema, O as retryPaymentRequestSchema, P as checkoutPricingRequestSchema, U as addonGroupViewSchema, V as myCouponSchema, X as lineSelectionResponseShape, Y as lineSelectionRequestShape, d as createCheckoutRequestSchema, et as myOrderItemFulfillmentSnapshotSchema, f as deliveryQuoteRequestSchema, m as easyPayProviderResponseSchema, nt as productFulfillmentViewSchema, p as deliveryQuoteSchema, tt as productCardFulfillmentSchema, u as checkoutSessionSchema, w as paymentStatusSchema, y as paymentMethodSchema } from "./checkout-C25liqdW.mjs";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/http.ts
|
|
5
5
|
/** 표준 엔벨로프의 $.error 상세 */
|
|
@@ -243,6 +243,7 @@ const cartItemSchema = z.object({
|
|
|
243
243
|
thumbnailUrl: z.url().nullable().describe("담은 상품의 대표 이미지. 없으면 null"),
|
|
244
244
|
optionId: z.string().nullable(),
|
|
245
245
|
optionName: z.string().nullable(),
|
|
246
|
+
...lineSelectionResponseShape,
|
|
246
247
|
quantity: z.number().int(),
|
|
247
248
|
unitPrice: z.number().int(),
|
|
248
249
|
totalPrice: z.number().int(),
|
|
@@ -266,11 +267,14 @@ const cartSchema = z.object({
|
|
|
266
267
|
const addCartItemRequestSchema = z.object({
|
|
267
268
|
productId: z.string(),
|
|
268
269
|
optionId: z.string().optional(),
|
|
269
|
-
quantity: z.number().int().min(1).max(999)
|
|
270
|
+
quantity: z.number().int().min(1).max(999),
|
|
271
|
+
...lineSelectionRequestShape
|
|
270
272
|
});
|
|
271
273
|
const updateCartItemRequestSchema = z.object({
|
|
272
274
|
quantity: z.number().int().min(1).max(999).optional(),
|
|
273
|
-
optionId: z.string().optional()
|
|
275
|
+
optionId: z.string().optional(),
|
|
276
|
+
addons: lineSelectionRequestShape.addons.describe("추가 선택을 통째로 바꾼다. 생략하면 그대로 둔다"),
|
|
277
|
+
customInputs: lineSelectionRequestShape.customInputs.describe("직접 입력값을 통째로 바꾼다. 생략하면 그대로 둔다")
|
|
274
278
|
}).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
|
|
275
279
|
//#endregion
|
|
276
280
|
//#region src/schemas/common.ts
|
|
@@ -347,6 +351,8 @@ const productDetailSchema = productCardSchema.extend({
|
|
|
347
351
|
additionalPrice: z.number().int(),
|
|
348
352
|
soldOut: z.boolean()
|
|
349
353
|
})),
|
|
354
|
+
addonGroups: z.array(addonGroupViewSchema).optional().default([]).describe("추가 선택 옵션명(이슈 #59). 배열 순서가 표시 순서다. 담기·바로 구매의 `addons`로 `{groupId, valueId}`를 보낸다. 없으면 빈 배열. 서버는 항상 싣는다"),
|
|
355
|
+
customInputs: z.array(customInputViewSchema).optional().default([]).describe("직접 입력 항목(이슈 #59). 배열 순서가 표시 순서다. 담기·바로 구매의 `customInputs`로 값을 보낸다. 없으면 빈 배열. 서버는 항상 싣는다"),
|
|
350
356
|
fulfillment: productFulfillmentViewSchema,
|
|
351
357
|
returnPeriodDays: z.number().int().describe("반품·교환을 받는 기간(수령·제공일부터 일수)"),
|
|
352
358
|
categoryPath: z.array(z.object({
|
|
@@ -601,6 +607,7 @@ const myOrderItemSchema = z.object({
|
|
|
601
607
|
productName: z.string(),
|
|
602
608
|
thumbnailUrl: z.url().nullable().describe("주문 시점의 대표 이미지. 없었으면 null"),
|
|
603
609
|
optionName: z.string().nullable(),
|
|
610
|
+
...lineSelectionResponseShape,
|
|
604
611
|
quantity: z.number().int().describe("주문 수량"),
|
|
605
612
|
canceledQuantity: z.number().int().describe("취소·반품으로 환불된 누적 수량. 부분 취소가 없었으면 0이다"),
|
|
606
613
|
activeQuantity: z.number().int().describe("남은 수량 (`quantity` − `canceledQuantity`). 취소·반품·교환 요청 수량의 상한이다"),
|