@sayren/storefront-sdk 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,764 +1,6 @@
1
- import { a as ANALYTICS_SESSION_HEADER, c as analyticsBatchSchema, d as analyticsIdSchema, f as analyticsServerEventNameSchema, i as ANALYTICS_SESSION_COOKIE, l as analyticsClientEventNameSchema, o as ANALYTICS_VISITOR_COOKIE, r as ANALYTICS_MAX_BATCH_BYTES, s as ANALYTICS_VISITOR_HEADER, t as analyticsIdsFromCookie, u as analyticsClientEventSchema } from "./analytics-ids-o0a07Ohr.mjs";
2
- import { z } from "zod";
3
- //#region src/http.ts
4
- /** 표준 엔벨로프의 $.error 상세 */
5
- const errorDetailSchema = z.object({
6
- code: z.string(),
7
- message: z.string(),
8
- traceId: z.string().optional(),
9
- /**
10
- * 에러 코드별 보조 데이터(선택). 예: 관리 API `LIVE_GATE_NOT_MET`·`LIVE_PAYMENTS_DISABLED`의
11
- * `{ conditions: LiveGateCondition[] }`. 형태는 에러 코드마다 다르므로 소비측이 코드별 스키마로 다시 파싱한다
12
- */
13
- details: z.record(z.string(), z.unknown()).optional().catch(void 0)
14
- });
15
- /** 표준 응답 엔벨로프 — $.meta / $.data / $.error */
16
- const envelopeSchema = z.object({
17
- meta: z.object({
18
- status: z.number(),
19
- code: z.string(),
20
- message: z.string(),
21
- isSuccess: z.boolean()
22
- }),
23
- data: z.unknown().optional(),
24
- /** 구형 필드 — data로 개명되기 전 응답과의 전환기 호환 */
25
- content: z.unknown().optional(),
26
- error: errorDetailSchema.nullable()
27
- });
28
- /** 표준 엔벨로프면 $.data(구형 $.content)를, 아니면(평면 응답) 본문 전체를 반환 */
29
- function unwrapData(json) {
30
- const envelope = envelopeSchema.safeParse(json);
31
- if (!envelope.success) return json;
32
- return envelope.data.data ?? envelope.data.content ?? null;
33
- }
34
- var ApiError = class extends Error {
35
- status;
36
- code;
37
- traceId;
38
- body;
39
- details;
40
- constructor(status, code, message, traceId, body, details) {
41
- super(message);
42
- this.status = status;
43
- this.code = code;
44
- this.traceId = traceId;
45
- this.body = body;
46
- this.details = details;
47
- this.name = "ApiError";
48
- }
49
- };
50
- /**
51
- * 비-2xx 응답 본문(raw JSON)을 표준 ApiError로 변환한다 — http 클라이언트와 session 매니저가
52
- * **동일한 에러 형태**(status·code·message·traceId)를 던지도록 하는 단일 원천.
53
- * 표준 엔벨로프($.error) 우선, 구형 평면 에러({ code, message })는 폴백.
54
- */
55
- function toApiError(status, raw) {
56
- const envelope = envelopeSchema.safeParse(raw);
57
- const detail = envelope.success ? envelope.data.error : errorDetailSchema.safeParse(raw).data ?? null;
58
- if (detail) return new ApiError(status, detail.code, detail.message, detail.traceId, raw, detail.details);
59
- return new ApiError(status, "UNKNOWN", `HTTP ${status}`, void 0, raw);
60
- }
61
- /**
62
- * 경로 템플릿 태그 — 보간 값(경로 파라미터)마다 encodeURIComponent를 적용한다.
63
- * `/`·`?`·`#` 등이 섞인 id가 다른 경로·쿼리로 해석되지 않게 한다. 예: path`/payments/${id}`
64
- * (store-sdk `path`와 같은 구현)
65
- */
66
- function path(strings, ...params) {
67
- return strings.reduce((acc, part, i) => acc + part + (i < params.length ? encodeURIComponent(String(params[i])) : ""), "");
68
- }
69
- function resolveToken(source) {
70
- return (typeof source === "function" ? source() : source) ?? null;
71
- }
72
- function buildQuery(query) {
73
- if (!query) return "";
74
- const params = new URLSearchParams();
75
- for (const [key, value] of Object.entries(query)) if (value !== void 0) params.set(key, String(value));
76
- const qs = params.toString();
77
- return qs ? `?${qs}` : "";
78
- }
79
- function createHttp(options) {
80
- const fetchFn = options.fetch ?? globalThis.fetch;
81
- async function send(method, path, request, retried = false) {
82
- const url = `${options.baseUrl}${path}${buildQuery(request?.query)}`;
83
- const headers = {
84
- ...request?.body !== void 0 ? { "content-type": "application/json" } : {},
85
- ...options.headers?.(),
86
- ...request?.headers
87
- };
88
- const response = await fetchFn(url, {
89
- method,
90
- headers,
91
- body: request?.body !== void 0 ? JSON.stringify(request.body) : void 0
92
- });
93
- options.onResponse?.(response);
94
- if (response.status === 401 && !retried && options.refresh) {
95
- if (await options.refresh()) return send(method, path, request, true);
96
- }
97
- if (!response.ok) {
98
- if (response.status === 401) options.onUnauthorized?.();
99
- const raw = await response.json().catch(() => null);
100
- throw toApiError(response.status, raw);
101
- }
102
- return response;
103
- }
104
- return {
105
- async request(method, path, schema, request) {
106
- const json = await (await send(method, path, request)).json();
107
- return schema.parse(unwrapData(json));
108
- },
109
- async requestVoid(method, path, request) {
110
- await send(method, path, request);
111
- }
112
- };
113
- }
114
- //#endregion
115
- //#region src/schemas/auth.ts
116
- const tokenPairSchema = z.object({
117
- accessToken: z.string(),
118
- refreshToken: z.string(),
119
- expiresIn: z.number().int()
120
- });
121
- const signupRequestSchema = z.object({
122
- email: z.email(),
123
- password: z.string().min(10, "비밀번호는 10자 이상이어야 합니다").refine((value) => [
124
- /[a-zA-Z]/,
125
- /[0-9]/,
126
- /[^a-zA-Z0-9]/
127
- ].filter((pattern) => pattern.test(value)).length >= 2, "영문/숫자/특수문자 중 2종 이상을 조합해야 합니다"),
128
- name: z.string().min(1).max(50),
129
- phone: z.string().regex(/^01[0-9]{8,9}$/, "휴대폰 번호 형식이 아닙니다 (예: 01012345678)").optional(),
130
- agreements: z.object({
131
- terms: z.literal(true),
132
- privacy: z.literal(true),
133
- marketing: z.boolean().default(false)
134
- })
135
- });
136
- const loginRequestSchema = z.object({
137
- email: z.email(),
138
- password: z.string().min(1),
139
- cartToken: z.string().optional()
140
- });
141
- //#endregion
142
- //#region src/schemas/cart.ts
143
- const cartItemSchema = z.object({
144
- cartItemId: z.string(),
145
- productId: z.string(),
146
- productName: z.string(),
147
- thumbnailUrl: z.url(),
148
- optionId: z.string().nullable(),
149
- optionName: z.string().nullable(),
150
- quantity: z.number().int(),
151
- unitPrice: z.number().int(),
152
- totalPrice: z.number().int(),
153
- purchasable: z.boolean(),
154
- unpurchasableReason: z.enum([
155
- "SOLD_OUT",
156
- "SUSPENDED",
157
- "CLOSED"
158
- ]).nullable()
159
- });
160
- const cartSchema = z.object({
161
- items: z.array(cartItemSchema),
162
- summary: z.object({
163
- productAmount: z.number().int(),
164
- deliveryFee: z.number().int(),
165
- totalAmount: z.number().int()
166
- })
167
- });
168
- const addCartItemRequestSchema = z.object({
169
- productId: z.string(),
170
- optionId: z.string().optional(),
171
- quantity: z.number().int().min(1).max(999)
172
- });
173
- const updateCartItemRequestSchema = z.object({
174
- quantity: z.number().int().min(1).max(999).optional(),
175
- optionId: z.string().optional()
176
- }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
177
- //#endregion
178
- //#region src/schemas/catalog.ts
179
- const categoryNodeSchema = z.lazy(() => z.object({
180
- categoryId: z.string(),
181
- name: z.string(),
182
- depth: z.number().int().min(1).max(4),
183
- children: z.array(categoryNodeSchema)
184
- }));
185
- const productCardSchema = z.object({
186
- productId: z.string(),
187
- name: z.string(),
188
- thumbnailUrl: z.url(),
189
- salePrice: z.number().int(),
190
- discountedPrice: z.number().int().nullable(),
191
- discountRate: z.number().int().nullable(),
192
- freeShipping: z.boolean(),
193
- averageRating: z.number(),
194
- reviewCount: z.number().int(),
195
- soldOut: z.boolean()
196
- });
197
- const productDetailSchema = productCardSchema.extend({
198
- description: z.string(),
199
- images: z.array(z.url()),
200
- /** 옵션 축(그룹). 배열 순서가 곧 표시 순서다 */
201
- optionGroups: z.array(z.object({
202
- groupId: z.string(),
203
- name: z.string(),
204
- values: z.array(z.object({
205
- valueId: z.string(),
206
- name: z.string()
207
- }))
208
- })),
209
- /** 판매 단위(SKU). variantId는 카트·주문의 optionId와 같은 값 공간이다 */
210
- variants: z.array(z.object({
211
- variantId: z.string(),
212
- /** optionGroups 순서와 1:1 대응. 옵션 없는 상품은 [] */
213
- valueIds: z.array(z.string()),
214
- /** 값 이름을 " / "로 이은 표시명. 옵션 없으면 "" */
215
- name: z.string(),
216
- additionalPrice: z.number().int(),
217
- soldOut: z.boolean()
218
- })),
219
- delivery: z.object({
220
- type: z.enum([
221
- "FREE",
222
- "PAID",
223
- "CONDITIONAL_FREE"
224
- ]),
225
- fee: z.number().int(),
226
- conditionalFreeAmount: z.number().int().nullable(),
227
- estimatedDays: z.string()
228
- }),
229
- returnPolicy: z.object({
230
- returnFee: z.number().int(),
231
- exchangeFee: z.number().int(),
232
- periodDays: z.number().int()
233
- }),
234
- categoryPath: z.array(z.object({
235
- categoryId: z.string(),
236
- name: z.string()
237
- }))
238
- });
239
- const productSortSchema = z.enum([
240
- "recommend",
241
- "latest",
242
- "priceAsc",
243
- "priceDesc",
244
- "reviewCount",
245
- "ratingDesc"
246
- ]);
247
- const productFacetsSchema = z.object({
248
- categories: z.array(z.object({
249
- categoryId: z.string(),
250
- name: z.string(),
251
- count: z.number().int()
252
- })).optional(),
253
- priceRange: z.object({
254
- min: z.number().int(),
255
- max: z.number().int()
256
- }).optional()
257
- });
258
- //#endregion
259
- //#region src/schemas/checkout.ts
260
- const createCheckoutRequestSchema = z.object({
261
- cartItemIds: z.array(z.string()).min(1).optional(),
262
- directItem: z.object({
263
- productId: z.string(),
264
- optionId: z.string().optional(),
265
- quantity: z.number().int().min(1)
266
- }).optional()
267
- }).refine((value) => value.cartItemIds ? !value.directItem : !!value.directItem, { message: "cartItemIds와 directItem 중 하나만 전달해야 합니다" });
268
- const checkoutSessionSchema = z.object({
269
- checkoutId: z.string(),
270
- items: z.array(z.object({
271
- productId: z.string(),
272
- productName: z.string(),
273
- /** variantId. 옵션 없는 상품은 default variant id */
274
- optionId: z.string().nullable(),
275
- optionName: z.string().nullable(),
276
- quantity: z.number().int(),
277
- unitPrice: z.number().int(),
278
- totalPrice: z.number().int()
279
- })),
280
- amounts: z.object({
281
- productAmount: z.number().int(),
282
- deliveryFee: z.number().int(),
283
- totalAmount: z.number().int()
284
- }),
285
- expiresAt: z.string(),
286
- testPayment: z.boolean().describe("지금 결제하면 테스트 결제(샌드박스)인가. true면 실제로 돈이 나가지 않아요 — 주문서에 테스트 결제 안내를 표시해요. 결제 요청 시점에 스토어 결제 설정으로 다시 정해지니 최종 값은 결제 요청 응답의 `testPayment`예요")
287
- });
288
- const paymentMethodSchema = z.enum([
289
- "CARD",
290
- "BANK_TRANSFER",
291
- "VIRTUAL_ACCOUNT",
292
- "MOBILE",
293
- "EASY_PAY"
294
- ]);
295
- const shippingAddressInputSchema = z.object({
296
- addressId: z.string().optional(),
297
- receiverName: z.string().min(1, "수령인명을 입력해주세요").max(50),
298
- phone: z.string().regex(/^01[0-9]{8,9}$/, "연락처 형식이 아닙니다 (예: 01012345678)"),
299
- zipCode: z.string().regex(/^[0-9]{5}$/, "우편번호는 5자리 숫자입니다"),
300
- address1: z.string().min(1, "기본 주소를 입력해주세요"),
301
- address2: z.string().optional(),
302
- deliveryMemo: z.string().max(100).optional(),
303
- entranceCode: z.string().max(20).optional()
304
- });
305
- const guestInfoSchema = z.object({
306
- name: z.string().min(1),
307
- phone: z.string().regex(/^01[0-9]{8,9}$/),
308
- email: z.email(),
309
- orderPassword: z.string().min(6, "주문 조회 비밀번호는 6자 이상이어야 합니다")
310
- });
311
- const requestPaymentRequestSchema = z.object({
312
- shippingAddress: shippingAddressInputSchema,
313
- paymentMethod: paymentMethodSchema,
314
- guest: guestInfoSchema.optional()
315
- });
316
- /**
317
- * 결제창 파라미터. 스토어프론트가 쓰는 계약 값은 `popupUrl` 하나다(결제 팝업을 연다).
318
- *
319
- * 나머지는 결제 팝업 내부 값이라 선택 필드로만 타입을 준다(`attemptId`·`provider`·`mock`, 그리고
320
- * 토스 `clientKey`·`orderId`…, 포트원 `storeId`·`channelKey`… 같은 PG별 결제창 값). 공개 값뿐이며
321
- * 시크릿은 어떤 키에도 없다. 서버가 키를 추가·변경해도 파싱이 깨지지 않도록 모르는 키는 그대로 통과시킨다.
322
- */
323
- const pgParamsSchema = z.looseObject({
324
- popupUrl: z.string().describe("결제 팝업 진입 URL. `window.open`으로 띄운다"),
325
- attemptId: z.string().optional().describe("첫 결제 시도 id(`att_…`). PG에 보내는 주문번호(토스 `orderId`, 포트원 `paymentId`)다. 팝업 내부 값"),
326
- provider: z.string().optional().describe("첫 결제 시도의 PG (`pgProvider`와 같다). 팝업 내부 값"),
327
- mock: z.boolean().optional().describe("모의 결제 여부. true면 결제 팝업이 PG SDK 대신 모의 결제 UI를 띄운다. 팝업 내부 값"),
328
- environment: z.string().optional().describe("첫 결제 시도의 결제 환경 (`TEST` 샌드박스 · `LIVE` 실결제). 팝업 내부 값")
329
- });
330
- const paymentParamsSchema = z.object({
331
- paymentId: z.string(),
332
- pgProvider: z.string().describe("첫 결제 시도의 PG. 현재 값은 `tosspayments`·`portone`이다. PG가 추가될 수 있어 문자열로 받는다"),
333
- pgParams: pgParamsSchema,
334
- expiresAt: z.string(),
335
- testPayment: z.boolean().describe("테스트 결제(샌드박스) 여부. true면 실제로 돈이 나가지 않는다 — 결제 화면에 테스트 결제 안내를 표시한다")
336
- });
337
- const confirmPaymentRequestSchema = z.object({
338
- pgToken: z.string().min(1).describe("PG 승인 키 (토스 `paymentKey`, 포트원 `txId`)"),
339
- attemptId: z.string().min(1).optional().describe("승인할 결제 시도 id (결제창이 돌려준 주문번호). 생략하면 현재 시도")
340
- });
341
- const confirmPaymentResultSchema = z.object({
342
- orderId: z.string(),
343
- status: z.literal("PAID"),
344
- totalAmount: z.number().int(),
345
- paidAt: z.string()
346
- });
347
- /**
348
- * 결제 상태 조회의 현재 상태 값 — 응답 스키마는 서버가 상태를 추가해도 파싱이 깨지지 않게 문자열로 받는다
349
- * (`pgProvider`와 같은 방식). 화면 분기는 이 목록으로 하고 모르는 값은 확인 중으로 다룬다.
350
- */
351
- const PAYMENT_STATUS_VALUES = [
352
- "pending",
353
- "processing",
354
- "completed",
355
- "failed",
356
- "expired"
357
- ];
358
- const paymentStatusSchema = z.object({
359
- paymentId: z.string(),
360
- status: z.string().describe("결제 상태. 현재 값은 `pending` 결제 대기 · `processing` 승인 확인 중 · `completed` 결제 완료(주문 생성) · `failed` 실패 · `expired` 만료예요. 상태가 추가될 수 있어 문자열로 받아요 — 모르는 값은 `processing`처럼 다루고 계속 조회하세요"),
361
- orderId: z.string().nullable().describe("결제가 완료됐으면 주문 번호, 그 외에는 null"),
362
- testPayment: z.boolean().describe("테스트 결제(샌드박스)인가. true면 실제로 돈이 나가지 않았어요"),
363
- expiresAt: z.string().describe("결제 요청 만료 시각")
364
- });
365
- //#endregion
366
- //#region src/schemas/common.ts
367
- const pageInfoSchema = z.object({
368
- page: z.number().int(),
369
- size: z.number().int(),
370
- totalElements: z.number().int(),
371
- totalPages: z.number().int()
372
- });
373
- function pageSchema(item) {
374
- return pageInfoSchema.extend({ contents: z.array(item) });
375
- }
376
- const orderItemStatusSchema = z.enum([
377
- "PAYMENT_WAITING",
378
- "PAID",
379
- "CONFIRMED",
380
- "DISPATCHED",
381
- "DELIVERING",
382
- "DELIVERED",
383
- "PURCHASE_DECIDED",
384
- "CANCELED"
385
- ]);
386
- const claimStatusSchema = z.enum([
387
- "REQUESTED",
388
- "HELD",
389
- "COLLECTING",
390
- "COLLECTED",
391
- "REDELIVERING",
392
- "APPROVED",
393
- "REJECTED",
394
- "COMPLETED",
395
- "WITHDRAWN"
396
- ]);
397
- //#endregion
398
- //#region src/schemas/claim.ts
399
- const claimTypeSchema = z.enum([
400
- "CANCEL",
401
- "RETURN",
402
- "EXCHANGE"
403
- ]);
404
- const claimReasonSchema = z.enum([
405
- "CHANGE_OF_MIND",
406
- "WRONG_ORDER",
407
- "DEFECTIVE",
408
- "WRONG_DELIVERY",
409
- "DIFFERENT_FROM_PAGE",
410
- "DELAY"
411
- ]);
412
- const createClaimRequestSchema = z.object({
413
- type: claimTypeSchema,
414
- reason: claimReasonSchema,
415
- reasonDetail: z.string().max(1e3).optional(),
416
- evidenceImages: z.array(z.url()).max(5).optional(),
417
- exchangeOptionId: z.string().optional()
418
- });
419
- const createClaimResultSchema = z.object({
420
- claimId: z.string(),
421
- status: z.literal("REQUESTED"),
422
- expectedRefundAmount: z.number().int().nullable(),
423
- claimDeliveryFee: z.number().int()
424
- });
425
- const myClaimSchema = z.object({
426
- claimId: z.string(),
427
- type: claimTypeSchema,
428
- status: claimStatusSchema,
429
- orderItemId: z.string(),
430
- productName: z.string(),
431
- reason: z.string(),
432
- expectedRefundAmount: z.number().int().nullable(),
433
- rejectReason: z.string().nullable(),
434
- requestedAt: z.string(),
435
- completedAt: z.string().nullable()
436
- });
437
- //#endregion
438
- //#region src/schemas/customer-inquiry.ts
439
- const customerInquiryCategorySchema = z.enum([
440
- "DELIVERY",
441
- "RETURN",
442
- "EXCHANGE",
443
- "PAYMENT",
444
- "ETC"
445
- ]);
446
- /** 구매자 본인 뷰 — 마스킹 없이 본인 데이터, 셀러 답변(수정횟수 제외) */
447
- const customerInquirySchema = z.object({
448
- inquiryId: z.string(),
449
- category: customerInquiryCategorySchema,
450
- title: z.string(),
451
- content: z.string(),
452
- orderItemId: z.string().nullable(),
453
- answered: z.boolean(),
454
- answer: z.object({
455
- content: z.string(),
456
- answeredAt: z.string()
457
- }).nullable(),
458
- createdAt: z.string()
459
- });
460
- const createCustomerInquiryRequestSchema = z.object({
461
- category: customerInquiryCategorySchema,
462
- title: z.string().min(1).max(100),
463
- content: z.string().min(1).max(2e3),
464
- orderItemId: z.string().optional()
465
- });
466
- //#endregion
467
- //#region src/schemas/inquiry.ts
468
- const publicInquirySchema = z.object({
469
- inquiryId: z.string(),
470
- content: z.string().nullable(),
471
- secret: z.boolean(),
472
- mine: z.boolean(),
473
- writerMaskedName: z.string(),
474
- answer: z.object({
475
- content: z.string().nullable(),
476
- answeredAt: z.string()
477
- }).nullable(),
478
- createdAt: z.string()
479
- });
480
- const createInquiryRequestSchema = z.object({
481
- content: z.string().min(1).max(1e3),
482
- secret: z.boolean().default(false)
483
- });
484
- //#endregion
485
- //#region src/schemas/member.ts
486
- const memberSchema = z.object({
487
- memberId: z.string(),
488
- email: z.email(),
489
- name: z.string(),
490
- phone: z.string().nullable(),
491
- point: z.number().int(),
492
- marketingAgreed: z.boolean(),
493
- joinedAt: z.string()
494
- });
495
- const updateProfileRequestSchema = z.object({
496
- name: z.string().max(50).optional(),
497
- phone: z.string().optional(),
498
- marketingAgreed: z.boolean().optional()
499
- }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
500
- const memberAddressSchema = z.object({
501
- addressId: z.string(),
502
- alias: z.string(),
503
- isDefault: z.boolean(),
504
- receiverName: z.string(),
505
- phone: z.string(),
506
- zipCode: z.string(),
507
- address1: z.string(),
508
- address2: z.string().nullable()
509
- });
510
- const memberAddressRequestSchema = z.object({
511
- alias: z.string().min(1).max(20),
512
- receiverName: z.string().min(1).max(50),
513
- phone: z.string().regex(/^01[0-9]{8,9}$/),
514
- zipCode: z.string().regex(/^[0-9]{5}$/),
515
- address1: z.string().min(1),
516
- address2: z.string().optional(),
517
- isDefault: z.boolean().default(false)
518
- });
519
- //#endregion
520
- //#region src/schemas/order.ts
521
- const myOrderItemSchema = z.object({
522
- orderItemId: z.string(),
523
- productId: z.string(),
524
- productName: z.string(),
525
- thumbnailUrl: z.url(),
526
- optionName: z.string().nullable(),
527
- quantity: z.number().int(),
528
- totalPrice: z.number().int(),
529
- status: orderItemStatusSchema,
530
- claimStatus: z.string().nullable(),
531
- reviewWritten: z.boolean(),
532
- autoDecisionDate: z.string().nullable()
533
- });
534
- /**
535
- * 주문 응답의 배송지 — 결제 요청 시 저장된 스냅샷. 요청 스키마(`shippingAddressInputSchema`)와 분리한 응답 스키마라
536
- * 형식 검증(regex·길이)을 하지 않는다. 입력하지 않은 선택 필드는 null로 오거나 빠질 수 있다.
537
- */
538
- const orderShippingAddressSchema = z.object({
539
- receiverName: z.string(),
540
- phone: z.string(),
541
- zipCode: z.string(),
542
- address1: z.string(),
543
- address2: z.string().nullish().describe("상세 주소. 입력하지 않았으면 null이거나 없다"),
544
- deliveryMemo: z.string().nullish().describe("배송 메모. 입력하지 않았으면 null이거나 없다"),
545
- entranceCode: z.string().nullish().describe("공동현관 출입번호. 입력하지 않았으면 null이거나 없다")
546
- });
547
- const myOrderSchema = z.object({
548
- orderId: z.string(),
549
- orderedAt: z.string(),
550
- items: z.array(myOrderItemSchema),
551
- shippingAddress: orderShippingAddressSchema,
552
- payment: z.object({
553
- method: paymentMethodSchema.describe("실제 결제수단(PG가 보고한 수단, 모르면 주문서에서 고른 수단). 결제창에서 바뀔 수 있다(카드 결제창의 간편결제 탭 등)"),
554
- totalAmount: z.number().int(),
555
- paidAt: z.string().nullable(),
556
- receiptUrl: z.url().nullable()
557
- }),
558
- testPayment: z.boolean().describe("테스트 결제(샌드박스 결제) 주문인가. true면 실제로 돈이 나가지 않았어요 — 주문 화면에 테스트 결제 배지를 표시해요")
559
- });
560
- const deliveryTrackingSchema = z.object({
561
- carrierName: z.string(),
562
- trackingNumber: z.string(),
563
- trackingUrl: z.url(),
564
- status: z.enum([
565
- "DISPATCHED",
566
- "DELIVERING",
567
- "DELIVERED"
568
- ]),
569
- trackingEvents: z.array(z.object({
570
- status: z.string(),
571
- location: z.string(),
572
- occurredAt: z.string()
573
- }))
574
- });
575
- //#endregion
576
- //#region src/schemas/review.ts
577
- const publicReviewSchema = z.object({
578
- reviewId: z.string(),
579
- rating: z.number().int().min(1).max(5),
580
- content: z.string(),
581
- images: z.array(z.url()),
582
- optionName: z.string().nullable(),
583
- writerMaskedName: z.string(),
584
- sellerReply: z.object({
585
- content: z.string(),
586
- repliedAt: z.string()
587
- }).nullable(),
588
- createdAt: z.string()
589
- });
590
- const reviewSummarySchema = z.object({
591
- averageRating: z.number(),
592
- totalCount: z.number().int(),
593
- distribution: z.record(z.string(), z.number().int())
594
- });
595
- const writableReviewSchema = z.object({
596
- orderItemId: z.string(),
597
- productId: z.string(),
598
- productName: z.string(),
599
- optionName: z.string().nullable(),
600
- thumbnailUrl: z.url(),
601
- writableUntil: z.string()
602
- });
603
- const createReviewRequestSchema = z.object({
604
- rating: z.number().int().min(1).max(5),
605
- content: z.string().min(10, "리뷰는 10자 이상 작성해주세요").max(2e3),
606
- images: z.array(z.url()).max(5).optional()
607
- });
608
- const createReviewResultSchema = z.object({
609
- reviewId: z.string(),
610
- rewardPoint: z.number().int()
611
- });
612
- const updateReviewRequestSchema = z.object({
613
- rating: z.number().int().min(1).max(5).optional(),
614
- content: z.string().min(10).max(2e3).optional(),
615
- images: z.array(z.url()).max(5).optional()
616
- }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
617
- //#endregion
618
- //#region src/client.ts
619
- const productPageSchema = pageSchema(productCardSchema).extend({ facets: productFacetsSchema.optional() });
620
- const reviewPageSchema = pageSchema(publicReviewSchema).extend({ summary: reviewSummarySchema.optional() });
621
- function createStorefrontClient(options) {
622
- const { session } = options;
623
- const accessTokenSource = options.accessToken ?? options.auth?.accessToken ?? (session ? () => session.accessToken : void 0);
624
- const refresh = session ? () => session.refresh() : void 0;
625
- const onUnauthorized = session ? () => session.clear() : void 0;
626
- const http = createHttp({
627
- baseUrl: options.baseUrl,
628
- fetch: options.fetch,
629
- headers: () => {
630
- const headers = {};
631
- const storeCode = resolveToken(options.storeCode);
632
- if (storeCode) headers["x-store-code"] = storeCode;
633
- const accessToken = resolveToken(accessTokenSource);
634
- if (accessToken) headers.authorization = `Bearer ${accessToken}`;
635
- const cartToken = resolveToken(options.cartToken);
636
- if (cartToken) headers["x-cart-token"] = cartToken;
637
- const visitorId = resolveToken(options.visitorId);
638
- if (visitorId) headers[ANALYTICS_VISITOR_HEADER] = visitorId;
639
- const sessionId = resolveToken(options.sessionId);
640
- if (sessionId) headers[ANALYTICS_SESSION_HEADER] = sessionId;
641
- return headers;
642
- },
643
- onResponse: (response) => {
644
- const issued = response.headers.get("x-cart-token");
645
- if (issued) options.onCartToken?.(issued);
646
- },
647
- refresh,
648
- onUnauthorized
649
- });
650
- return {
651
- /** 현재 세션 accessToken (session 미전달 시 null) */
652
- get accessToken() {
653
- return session ? session.accessToken : null;
654
- },
655
- /** 현재 세션 refreshToken (session 미전달 시 null) */
656
- get refreshToken() {
657
- return session ? session.refreshToken : null;
658
- },
659
- /** session.userinfo() 위임 — session 미전달 시 에러 */
660
- userinfo() {
661
- if (!session) throw new Error("세션 없음 — createStorefrontSession 필요");
662
- return session.userinfo();
663
- },
664
- auth: {
665
- signup: (body) => http.request("POST", "/auth/signup", tokenPairSchema, { body: signupRequestSchema.parse(body) }),
666
- login: (body) => http.request("POST", "/auth/login", tokenPairSchema, { body: loginRequestSchema.parse(body) }),
667
- refresh: (refreshToken) => http.request("POST", "/auth/token/refresh", tokenPairSchema, { body: { refreshToken } }),
668
- logout: () => http.requestVoid("POST", "/auth/logout")
669
- },
670
- catalog: {
671
- listCategories: () => http.request("GET", "/categories", z.array(categoryNodeSchema)),
672
- searchProducts: (params) => http.request("GET", "/products", productPageSchema, { query: params }),
673
- getProduct: (productId) => http.request("GET", path`/products/${productId}`, productDetailSchema),
674
- listProductReviews: (productId, params) => http.request("GET", path`/products/${productId}/reviews`, reviewPageSchema, { query: params }),
675
- listProductInquiries: (productId, params) => http.request("GET", path`/products/${productId}/inquiries`, pageSchema(publicInquirySchema), { query: params }),
676
- createInquiry: (productId, body) => http.requestVoid("POST", path`/products/${productId}/inquiries`, { body })
677
- },
678
- cart: {
679
- get: () => http.request("GET", "/cart", cartSchema),
680
- addItem: (body) => http.request("POST", "/cart/items", cartSchema, { body: addCartItemRequestSchema.parse(body) }),
681
- updateItem: (cartItemId, body) => http.request("PATCH", path`/cart/items/${cartItemId}`, cartSchema, { body: updateCartItemRequestSchema.parse(body) }),
682
- removeItem: (cartItemId) => http.requestVoid("DELETE", path`/cart/items/${cartItemId}`)
683
- },
684
- checkout: {
685
- create: (body) => http.request("POST", "/checkout", checkoutSessionSchema, { body: createCheckoutRequestSchema.parse(body) }),
686
- /**
687
- * 결제 시작 — 결제 세션을 만들고 결제 팝업 URL(`pgParams.popupUrl`)을 돌려준다.
688
- * `pgProvider`는 첫 결제 시도의 PG다(현재 `tosspayments`·`portone`, 새 PG가 추가돼도 파싱은 깨지지 않는다).
689
- *
690
- * PG 관련 에러(`ApiError.code`) — 둘 다 "결제 수단 준비 중" 안내를 권장한다.
691
- * - 409 `PAYMENT_NOT_CONFIGURED`: 스토어에 사용 중인 PG가 없다. 결제 세션을 만들지 않는다
692
- * - 503 `PAYMENT_PROVIDER_UNAVAILABLE`: 사용 중인 PG가 모두 준비 장애다. 잠시 후 재시도할 수 있다
693
- */
694
- requestPayment: (checkoutId, body) => http.request("POST", path`/checkout/${checkoutId}/payment`, paymentParamsSchema, { body: requestPaymentRequestSchema.parse(body) }),
695
- /**
696
- * 결제 승인 확정 — 같은 `paymentId + pgToken` 재호출은 저장된 결과를 돌려준다(멱등).
697
- * `options.attemptId`는 결제창이 돌려준 주문번호(시도 id)이고, 생략하면 현재 시도를 승인한다.
698
- *
699
- * 요청 본문은 보내기 전에 `confirmPaymentRequestSchema`로 검증한다. 빈 `pgToken`처럼 형식이 틀리면
700
- * 요청을 보내지 않고 **동기로 ZodError를 던진다**(Promise reject 아님 — 다른 메서드의 요청 검증과 같다).
701
- *
702
- * 카드 거절(402 `PG_DECLINED` 등)·402 `PAYMENT_NOT_APPROVED`·502 `PG_REQUEST_FAILED`·
703
- * 503 `PG_CREDENTIALS_UNAVAILABLE` 뒤에도 세션은 `pending`으로 남아 다시 시도할 수 있다.
704
- * 409 `LATE_APPROVAL_CANCELED`(미승인으로 판정된 뒤 늦게 온 승인을 서버가 PG 취소함)도 세션이 `pending`으로 남는다.
705
- * 409 `PAYMENT_RESULT_UNKNOWN`은 결과 확인 중이라 재시도하면 안 된다. 그 밖의 409:
706
- * `ATTEMPT_NOT_CURRENT`·`INVALID_ATTEMPT_STATE`·`PAYMENT_SESSION_OUTDATED`·`PG_AMOUNT_MISMATCH`.
707
- * 503 `PG_MERCHANT_MISMATCH`: 승인 시도의 가맹점과 현재 저장된 자격 증명의 가맹점이 다르다.
708
- */
709
- confirmPayment: (paymentId, pgToken, options) => http.request("POST", path`/payments/${paymentId}/confirm`, confirmPaymentResultSchema, { body: confirmPaymentRequestSchema.parse({
710
- pgToken,
711
- attemptId: options?.attemptId
712
- }) })
713
- },
714
- payments: {
715
- /**
716
- * `GET /storefront/v1/payments/{paymentId}` — 결제 상태 조회. 결제 팝업이 결과(postMessage)를 알리지 못하고 닫혔을 때
717
- * 부모 창이 `expiresAt`까지 폴링해 결과를 확인한다. `completed`면 `orderId`로 완료 화면, `processing`이면 계속 폴링,
718
- * `pending`이면 기존 안내, `failed`·`expired`면 실패 안내다. TTL이 지난 `pending`은 `expired`로 보고된다.
719
- * `testPayment`는 완료면 주문 플래그, 아니면 세션 환경이다.
720
- *
721
- * 에러: 404 `PAYMENT_NOT_FOUND`(없음·다른 스토어) · 410 `STORE_CLOSED` · 503 `STORE_SUSPENDED`
722
- */
723
- getStatus: (paymentId) => http.request("GET", path`/payments/${paymentId}`, paymentStatusSchema) },
724
- myOrders: {
725
- list: (params) => http.request("GET", "/me/orders", pageSchema(myOrderSchema), { query: params }),
726
- get: (orderId) => http.request("GET", path`/me/orders/${orderId}`, myOrderSchema),
727
- getGuestOrder: (orderId, body) => http.request("POST", path`/guest/orders/${orderId}`, myOrderSchema, { body }),
728
- getDelivery: (orderItemId) => http.request("GET", path`/me/order-items/${orderItemId}/delivery`, deliveryTrackingSchema),
729
- decidePurchase: (orderItemId) => http.requestVoid("POST", path`/me/order-items/${orderItemId}/purchase-decision`)
730
- },
731
- myClaims: {
732
- create: (orderItemId, body) => http.request("POST", path`/me/order-items/${orderItemId}/claims`, createClaimResultSchema, { body: createClaimRequestSchema.parse(body) }),
733
- list: (params) => http.request("GET", "/me/claims", pageSchema(myClaimSchema), { query: params }),
734
- withdraw: (claimId) => http.requestVoid("POST", path`/me/claims/${claimId}/withdraw`)
735
- },
736
- member: {
737
- me: () => http.request("GET", "/me", memberSchema),
738
- updateMe: (body) => http.requestVoid("PATCH", "/me", { body: updateProfileRequestSchema.parse(body) }),
739
- listAddresses: () => http.request("GET", "/me/addresses", z.array(memberAddressSchema)),
740
- createAddress: (body) => http.requestVoid("POST", "/me/addresses", { body: memberAddressRequestSchema.parse(body) }),
741
- updateAddress: (addressId, body) => http.requestVoid("PUT", path`/me/addresses/${addressId}`, { body: memberAddressRequestSchema.parse(body) }),
742
- deleteAddress: (addressId) => http.requestVoid("DELETE", path`/me/addresses/${addressId}`),
743
- listWishlist: (params) => http.request("GET", "/me/wishlist", pageSchema(productCardSchema), { query: params }),
744
- addWishlist: (productId) => http.requestVoid("POST", "/me/wishlist", { body: { productId } }),
745
- removeWishlist: (productId) => http.requestVoid("DELETE", path`/me/wishlist/${productId}`)
746
- },
747
- reviews: {
748
- listWritable: () => http.request("GET", "/me/reviews/writable", z.array(writableReviewSchema)),
749
- create: (orderItemId, body) => http.request("POST", path`/me/order-items/${orderItemId}/review`, createReviewResultSchema, { body: createReviewRequestSchema.parse(body) }),
750
- update: (reviewId, body) => http.requestVoid("PUT", path`/me/reviews/${reviewId}`, { body: updateReviewRequestSchema.parse(body) }),
751
- remove: (reviewId) => http.requestVoid("DELETE", path`/me/reviews/${reviewId}`)
752
- },
753
- inquiries: { listMine: (params) => http.request("GET", "/me/inquiries", pageSchema(publicInquirySchema), { query: params }) },
754
- me: { customerInquiries: {
755
- create: (body) => http.request("POST", "/me/customer-inquiries", customerInquirySchema, { body: createCustomerInquiryRequestSchema.parse(body) }),
756
- list: (params) => http.request("GET", "/me/customer-inquiries", pageSchema(customerInquirySchema), { query: params }),
757
- get: (inquiryId) => http.request("GET", path`/me/customer-inquiries/${inquiryId}`, customerInquirySchema)
758
- } }
759
- };
760
- }
761
- //#endregion
1
+ import { a as ANALYTICS_VISITOR_HEADER, c as analyticsClientEventSchema, i as ANALYTICS_VISITOR_COOKIE, l as analyticsIdSchema, n as ANALYTICS_SESSION_COOKIE, o as analyticsBatchSchema, r as ANALYTICS_SESSION_HEADER, s as analyticsClientEventNameSchema, t as ANALYTICS_MAX_BATCH_BYTES, u as analyticsServerEventNameSchema } from "./analytics-CgD70OqH.mjs";
2
+ import { t as analyticsIdsFromCookie } from "./analytics-ids-COElZiI3.mjs";
3
+ import { $ as signupRequestSchema, A as PAYMENT_STATUS_VALUES, B as requestPaymentRequestSchema, C as createClaimRequestSchema, D as orderItemStatusSchema, E as claimStatusSchema, F as guestInfoSchema, G as productFacetsSchema, H as categoryNodeSchema, I as paymentMethodSchema, J as cartItemSchema, K as productSortSchema, L as paymentParamsSchema, M as confirmPaymentRequestSchema, N as confirmPaymentResultSchema, O as pageInfoSchema, P as createCheckoutRequestSchema, Q as loginRequestSchema, R as paymentStatusSchema, S as claimTypeSchema, T as myClaimSchema, U as productCardSchema, V as shippingAddressInputSchema, W as productDetailSchema, X as updateCartItemRequestSchema, Y as cartSchema, Z as anonymousSessionSchema, _ as publicInquirySchema, a as reviewSummarySchema, b as customerInquirySchema, c as deliveryTrackingSchema, d as orderShippingAddressSchema, et as tokenPairSchema, f as memberAddressRequestSchema, g as createInquiryRequestSchema, h as updateProfileRequestSchema, i as publicReviewSchema, it as unwrapData, j as checkoutSessionSchema, k as pageSchema, l as myOrderItemSchema, m as memberSchema, n as createReviewRequestSchema, nt as buildQuery, o as updateReviewRequestSchema, p as memberAddressSchema, q as addCartItemRequestSchema, r as createReviewResultSchema, rt as toApiError, s as writableReviewSchema, t as createStorefrontClient, tt as ApiError, u as myOrderSchema, v as createCustomerInquiryRequestSchema, w as createClaimResultSchema, x as claimReasonSchema, y as customerInquiryCategorySchema, z as pgParamsSchema } from "./client-Xb-2tNKT.mjs";
762
4
  //#region src/session.ts
763
5
  /** 세션 키 상수 — SDK가 소유한다. store-sdk와 겹치지 않는 별도 네임스페이스. */
764
6
  const STOREFRONT_SESSION_KEYS = {
@@ -882,4 +124,4 @@ function createStorefrontSession(options) {
882
124
  };
883
125
  }
884
126
  //#endregion
885
- export { ANALYTICS_MAX_BATCH_BYTES, ANALYTICS_SESSION_COOKIE, ANALYTICS_SESSION_HEADER, ANALYTICS_VISITOR_COOKIE, ANALYTICS_VISITOR_HEADER, ApiError, PAYMENT_STATUS_VALUES, STOREFRONT_SESSION_KEYS, addCartItemRequestSchema, analyticsBatchSchema, analyticsClientEventNameSchema, analyticsClientEventSchema, analyticsIdSchema, analyticsIdsFromCookie, analyticsServerEventNameSchema, buildQuery, cartItemSchema, cartSchema, categoryNodeSchema, checkoutSessionSchema, claimReasonSchema, claimStatusSchema, claimTypeSchema, confirmPaymentRequestSchema, confirmPaymentResultSchema, createCheckoutRequestSchema, createClaimRequestSchema, createClaimResultSchema, createCustomerInquiryRequestSchema, createInquiryRequestSchema, createReviewRequestSchema, createReviewResultSchema, createStorefrontClient, createStorefrontSession, customerInquiryCategorySchema, customerInquirySchema, deliveryTrackingSchema, guestInfoSchema, loginRequestSchema, memberAddressRequestSchema, memberAddressSchema, memberSchema, myClaimSchema, myOrderItemSchema, myOrderSchema, orderItemStatusSchema, orderShippingAddressSchema, pageInfoSchema, pageSchema, paymentMethodSchema, paymentParamsSchema, paymentStatusSchema, pgParamsSchema, productCardSchema, productDetailSchema, productFacetsSchema, productSortSchema, publicInquirySchema, publicReviewSchema, requestPaymentRequestSchema, reviewSummarySchema, shippingAddressInputSchema, signupRequestSchema, tokenPairSchema, updateCartItemRequestSchema, updateProfileRequestSchema, updateReviewRequestSchema, writableReviewSchema };
127
+ export { ANALYTICS_MAX_BATCH_BYTES, ANALYTICS_SESSION_COOKIE, ANALYTICS_SESSION_HEADER, ANALYTICS_VISITOR_COOKIE, ANALYTICS_VISITOR_HEADER, ApiError, PAYMENT_STATUS_VALUES, STOREFRONT_SESSION_KEYS, addCartItemRequestSchema, analyticsBatchSchema, analyticsClientEventNameSchema, analyticsClientEventSchema, analyticsIdSchema, analyticsIdsFromCookie, analyticsServerEventNameSchema, anonymousSessionSchema, buildQuery, cartItemSchema, cartSchema, categoryNodeSchema, checkoutSessionSchema, claimReasonSchema, claimStatusSchema, claimTypeSchema, confirmPaymentRequestSchema, confirmPaymentResultSchema, createCheckoutRequestSchema, createClaimRequestSchema, createClaimResultSchema, createCustomerInquiryRequestSchema, createInquiryRequestSchema, createReviewRequestSchema, createReviewResultSchema, createStorefrontClient, createStorefrontSession, customerInquiryCategorySchema, customerInquirySchema, deliveryTrackingSchema, guestInfoSchema, loginRequestSchema, memberAddressRequestSchema, memberAddressSchema, memberSchema, myClaimSchema, myOrderItemSchema, myOrderSchema, orderItemStatusSchema, orderShippingAddressSchema, pageInfoSchema, pageSchema, paymentMethodSchema, paymentParamsSchema, paymentStatusSchema, pgParamsSchema, productCardSchema, productDetailSchema, productFacetsSchema, productSortSchema, publicInquirySchema, publicReviewSchema, requestPaymentRequestSchema, reviewSummarySchema, shippingAddressInputSchema, signupRequestSchema, tokenPairSchema, updateCartItemRequestSchema, updateProfileRequestSchema, updateReviewRequestSchema, writableReviewSchema };