@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.
@@ -1,4 +1,5 @@
1
1
  import { a as ANALYTICS_VISITOR_HEADER, r as ANALYTICS_SESSION_HEADER } from "./analytics-CgD70OqH.mjs";
2
+ import { a as createCheckoutRequestSchema, b as startPaymentRequestSchema, d as paymentMethodSchema, g as paymentStatusSchema, h as paymentStartSchema, i as checkoutSessionSchema, o as easyPayProviderResponseSchema, v as retryPaymentRequestSchema } from "./checkout-JFk3b8RG.mjs";
2
3
  import { z } from "zod";
3
4
  //#region src/http.ts
4
5
  /** 표준 엔벨로프의 $.error 상세 */
@@ -178,11 +179,11 @@ const socialProviderSchema = z.enum([
178
179
  ]);
179
180
  /** `POST /auth/idp/{provider}/authorize` 본문 — PKCE(S256)와 state는 SDK가 만든다 */
180
181
  const idpAuthorizeRequestSchema = z.object({
181
- /** 로그인을 마치고 돌아올 스토어프런트 주소. 스토어프런트 도메인 목록 안이어야 한다 */
182
+ /** 로그인을 마치고 돌아올 스토어프론트 주소. 스토어프론트 도메인 목록 안이어야 한다 */
182
183
  redirectUri: z.url(),
183
184
  /** base64url(SHA-256(codeVerifier)) */
184
185
  codeChallenge: z.string().regex(/^[A-Za-z0-9_-]{43}$/),
185
- /** 스토어프런트가 만든 값 — 돌아올 때 그대로 붙어 온다. 세션에 저장해 두고 비교한다 */
186
+ /** 스토어프론트가 만든 값 — 돌아올 때 그대로 붙어 온다. 세션에 저장해 두고 비교한다 */
186
187
  state: z.string().min(16).max(128)
187
188
  });
188
189
  const idpAuthorizeResponseSchema = z.object({
@@ -195,6 +196,23 @@ const idpTokenRequestSchema = z.object({
195
196
  /** 비회원 장바구니 토큰 — 주면 회원 장바구니로 합친다 */
196
197
  cartToken: z.string().optional()
197
198
  });
199
+ /** `GET /me/identities` — 구매자의 로그인 수단(비밀번호 여부와 연결된 소셜 계정) */
200
+ const memberIdentitiesSchema = z.object({
201
+ hasPassword: z.boolean(),
202
+ /** 셀러 자체 회원 연동(구매자 위임)으로 들어온 구매자 — 그 로그인도 로그인 수단으로 센다 */
203
+ hasExternalAuth: z.boolean(),
204
+ identities: z.array(z.object({
205
+ provider: socialProviderSchema,
206
+ /** 공급자가 알려 준 이메일(참고값). 없을 수 있다 */
207
+ email: z.string().nullable(),
208
+ linkedAt: z.string()
209
+ }))
210
+ });
211
+ /** `POST /me/identities/{provider}` 본문 — 연결 흐름에서 돌아온 1회용 code와 PKCE verifier */
212
+ const linkIdentityRequestSchema = z.object({
213
+ code: z.string().min(1),
214
+ codeVerifier: z.string().regex(/^[A-Za-z0-9._~-]{43,128}$/)
215
+ });
198
216
  //#endregion
199
217
  //#region src/schemas/cart.ts
200
218
  const cartItemSchema = z.object({
@@ -232,6 +250,38 @@ const updateCartItemRequestSchema = z.object({
232
250
  optionId: z.string().optional()
233
251
  }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
234
252
  //#endregion
253
+ //#region src/schemas/common.ts
254
+ const pageInfoSchema = z.object({
255
+ page: z.number().int(),
256
+ size: z.number().int(),
257
+ totalElements: z.number().int(),
258
+ totalPages: z.number().int()
259
+ });
260
+ function pageSchema(item) {
261
+ return pageInfoSchema.extend({ contents: z.array(item) });
262
+ }
263
+ const orderItemStatusSchema = z.enum([
264
+ "PAYMENT_WAITING",
265
+ "PAID",
266
+ "CONFIRMED",
267
+ "DISPATCHED",
268
+ "DELIVERING",
269
+ "DELIVERED",
270
+ "PURCHASE_DECIDED",
271
+ "CANCELED"
272
+ ]);
273
+ const claimStatusSchema = z.enum([
274
+ "REQUESTED",
275
+ "HELD",
276
+ "COLLECTING",
277
+ "COLLECTED",
278
+ "REDELIVERING",
279
+ "APPROVED",
280
+ "REJECTED",
281
+ "COMPLETED",
282
+ "WITHDRAWN"
283
+ ]);
284
+ //#endregion
235
285
  //#region src/schemas/catalog.ts
236
286
  const categoryNodeSchema = z.lazy(() => z.object({
237
287
  categoryId: z.string(),
@@ -243,9 +293,9 @@ const productCardSchema = z.object({
243
293
  productId: z.string(),
244
294
  name: z.string(),
245
295
  thumbnailUrl: z.url(),
246
- salePrice: z.number().int(),
247
- discountedPrice: z.number().int().nullable(),
248
- discountRate: z.number().int().nullable(),
296
+ salePrice: z.number().int().describe("판매가. 원(KRW) 단위 정수"),
297
+ discountedPrice: z.number().int().nullable().describe("즉시 할인 적용가. 원 단위. 할인이 없으면 null"),
298
+ discountRate: z.number().int().nullable().describe("할인율(%). 할인이 없으면 null"),
249
299
  freeShipping: z.boolean(),
250
300
  averageRating: z.number(),
251
301
  reviewCount: z.number().int(),
@@ -312,145 +362,8 @@ const productFacetsSchema = z.object({
312
362
  max: z.number().int()
313
363
  }).optional()
314
364
  });
315
- //#endregion
316
- //#region src/schemas/checkout.ts
317
- const createCheckoutRequestSchema = z.object({
318
- cartItemIds: z.array(z.string()).min(1).optional(),
319
- directItem: z.object({
320
- productId: z.string(),
321
- optionId: z.string().optional(),
322
- quantity: z.number().int().min(1)
323
- }).optional()
324
- }).refine((value) => value.cartItemIds ? !value.directItem : !!value.directItem, { message: "cartItemIds와 directItem 중 하나만 전달해야 합니다" });
325
- const checkoutSessionSchema = z.object({
326
- checkoutId: z.string(),
327
- items: z.array(z.object({
328
- productId: z.string(),
329
- productName: z.string(),
330
- /** variantId. 옵션 없는 상품은 default variant id */
331
- optionId: z.string().nullable(),
332
- optionName: z.string().nullable(),
333
- quantity: z.number().int(),
334
- unitPrice: z.number().int(),
335
- totalPrice: z.number().int()
336
- })),
337
- amounts: z.object({
338
- productAmount: z.number().int(),
339
- deliveryFee: z.number().int(),
340
- totalAmount: z.number().int()
341
- }),
342
- expiresAt: z.string(),
343
- testPayment: z.boolean().describe("지금 결제하면 테스트 결제(샌드박스)인가. true면 실제로 돈이 나가지 않아요 — 주문서에 테스트 결제 안내를 표시해요. 결제 요청 시점에 스토어 결제 설정으로 다시 정해지니 최종 값은 결제 요청 응답의 `testPayment`예요")
344
- });
345
- const paymentMethodSchema = z.enum([
346
- "CARD",
347
- "BANK_TRANSFER",
348
- "VIRTUAL_ACCOUNT",
349
- "MOBILE",
350
- "EASY_PAY"
351
- ]);
352
- const shippingAddressInputSchema = z.object({
353
- addressId: z.string().optional(),
354
- receiverName: z.string().min(1, "수령인명을 입력해주세요").max(50),
355
- phone: z.string().regex(/^01[0-9]{8,9}$/, "연락처 형식이 아닙니다 (예: 01012345678)"),
356
- zipCode: z.string().regex(/^[0-9]{5}$/, "우편번호는 5자리 숫자입니다"),
357
- address1: z.string().min(1, "기본 주소를 입력해주세요"),
358
- address2: z.string().optional(),
359
- deliveryMemo: z.string().max(100).optional(),
360
- entranceCode: z.string().max(20).optional()
361
- });
362
- const guestInfoSchema = z.object({
363
- name: z.string().min(1),
364
- phone: z.string().regex(/^01[0-9]{8,9}$/),
365
- email: z.email(),
366
- orderPassword: z.string().min(6, "주문 조회 비밀번호는 6자 이상이어야 합니다")
367
- });
368
- const requestPaymentRequestSchema = z.object({
369
- shippingAddress: shippingAddressInputSchema,
370
- paymentMethod: paymentMethodSchema,
371
- guest: guestInfoSchema.optional()
372
- });
373
- /**
374
- * 결제창 파라미터. 스토어프론트가 쓰는 계약 값은 `popupUrl` 하나다(결제 팝업을 연다).
375
- *
376
- * 나머지는 결제 팝업 내부 값이라 선택 필드로만 타입을 준다(`attemptId`·`provider`·`mock`, 그리고
377
- * 토스 `clientKey`·`orderId`…, 포트원 `storeId`·`channelKey`… 같은 PG별 결제창 값). 공개 값뿐이며
378
- * 시크릿은 어떤 키에도 없다. 서버가 키를 추가·변경해도 파싱이 깨지지 않도록 모르는 키는 그대로 통과시킨다.
379
- */
380
- const pgParamsSchema = z.looseObject({
381
- popupUrl: z.string().describe("결제 팝업 진입 URL. `window.open`으로 띄운다"),
382
- attemptId: z.string().optional().describe("첫 결제 시도 id(`att_…`). PG에 보내는 주문번호(토스 `orderId`, 포트원 `paymentId`)다. 팝업 내부 값"),
383
- provider: z.string().optional().describe("첫 결제 시도의 PG (`pgProvider`와 같다). 팝업 내부 값"),
384
- mock: z.boolean().optional().describe("모의 결제 여부. true면 결제 팝업이 PG SDK 대신 모의 결제 UI를 띄운다. 팝업 내부 값"),
385
- environment: z.string().optional().describe("첫 결제 시도의 결제 환경 (`TEST` 샌드박스 · `LIVE` 실결제). 팝업 내부 값")
386
- });
387
- const paymentParamsSchema = z.object({
388
- paymentId: z.string(),
389
- pgProvider: z.string().describe("첫 결제 시도의 PG. 현재 값은 `tosspayments`·`portone`이다. PG가 추가될 수 있어 문자열로 받는다"),
390
- pgParams: pgParamsSchema,
391
- expiresAt: z.string(),
392
- testPayment: z.boolean().describe("테스트 결제(샌드박스) 여부. true면 실제로 돈이 나가지 않는다 — 결제 화면에 테스트 결제 안내를 표시한다")
393
- });
394
- const confirmPaymentRequestSchema = z.object({
395
- pgToken: z.string().min(1).describe("PG 승인 키 (토스 `paymentKey`, 포트원 `txId`)"),
396
- attemptId: z.string().min(1).optional().describe("승인할 결제 시도 id (결제창이 돌려준 주문번호). 생략하면 현재 시도")
397
- });
398
- const confirmPaymentResultSchema = z.object({
399
- orderId: z.string(),
400
- status: z.literal("PAID"),
401
- totalAmount: z.number().int(),
402
- paidAt: z.string()
403
- });
404
- /**
405
- * 결제 상태 조회의 현재 상태 값 — 응답 스키마는 서버가 상태를 추가해도 파싱이 깨지지 않게 문자열로 받는다
406
- * (`pgProvider`와 같은 방식). 화면 분기는 이 목록으로 하고 모르는 값은 확인 중으로 다룬다.
407
- */
408
- const PAYMENT_STATUS_VALUES = [
409
- "pending",
410
- "processing",
411
- "completed",
412
- "failed",
413
- "expired"
414
- ];
415
- const paymentStatusSchema = z.object({
416
- paymentId: z.string(),
417
- status: z.string().describe("결제 상태. 현재 값은 `pending` 결제 대기 · `processing` 승인 확인 중 · `completed` 결제 완료(주문 생성) · `failed` 실패 · `expired` 만료예요. 상태가 추가될 수 있어 문자열로 받아요 — 모르는 값은 `processing`처럼 다루고 계속 조회하세요"),
418
- orderId: z.string().nullable().describe("결제가 완료됐으면 주문 번호, 그 외에는 null"),
419
- testPayment: z.boolean().describe("테스트 결제(샌드박스)인가. true면 실제로 돈이 나가지 않았어요"),
420
- expiresAt: z.string().describe("결제 요청 만료 시각")
421
- });
422
- //#endregion
423
- //#region src/schemas/common.ts
424
- const pageInfoSchema = z.object({
425
- page: z.number().int(),
426
- size: z.number().int(),
427
- totalElements: z.number().int(),
428
- totalPages: z.number().int()
429
- });
430
- function pageSchema(item) {
431
- return pageInfoSchema.extend({ contents: z.array(item) });
432
- }
433
- const orderItemStatusSchema = z.enum([
434
- "PAYMENT_WAITING",
435
- "PAID",
436
- "CONFIRMED",
437
- "DISPATCHED",
438
- "DELIVERING",
439
- "DELIVERED",
440
- "PURCHASE_DECIDED",
441
- "CANCELED"
442
- ]);
443
- const claimStatusSchema = z.enum([
444
- "REQUESTED",
445
- "HELD",
446
- "COLLECTING",
447
- "COLLECTED",
448
- "REDELIVERING",
449
- "APPROVED",
450
- "REJECTED",
451
- "COMPLETED",
452
- "WITHDRAWN"
453
- ]);
365
+ /** `GET /products` 응답 — 상품 카드 페이지와 검색 패싯 */
366
+ const productPageSchema = pageSchema(productCardSchema).extend({ facets: productFacetsSchema.optional() });
454
367
  //#endregion
455
368
  //#region src/schemas/claim.ts
456
369
  const claimTypeSchema = z.enum([
@@ -538,6 +451,11 @@ const createInquiryRequestSchema = z.object({
538
451
  content: z.string().min(1).max(1e3),
539
452
  secret: z.boolean().default(false)
540
453
  });
454
+ /** `POST /products/{productId}/inquiries` 응답 */
455
+ const createInquiryResultSchema = z.object({
456
+ inquiryId: z.string(),
457
+ createdAt: z.string()
458
+ });
541
459
  //#endregion
542
460
  //#region src/schemas/member.ts
543
461
  const memberSchema = z.object({
@@ -574,6 +492,11 @@ const memberAddressRequestSchema = z.object({
574
492
  address2: z.string().optional(),
575
493
  isDefault: z.boolean().default(false)
576
494
  });
495
+ /** `POST /me/wishlist` 응답 — 이미 찜한 상품이어도 같은 응답이다 */
496
+ const wishlistAddResultSchema = z.object({
497
+ productId: z.string(),
498
+ wished: z.literal(true)
499
+ });
577
500
  //#endregion
578
501
  //#region src/schemas/order.ts
579
502
  const myOrderItemSchema = z.object({
@@ -609,6 +532,7 @@ const myOrderSchema = z.object({
609
532
  shippingAddress: orderShippingAddressSchema,
610
533
  payment: z.object({
611
534
  method: paymentMethodSchema.describe("실제 결제수단(PG가 보고한 수단, 모르면 주문서에서 고른 수단). 결제창에서 바뀔 수 있다(카드 결제창의 간편결제 탭 등)"),
535
+ easyPayProvider: easyPayProviderResponseSchema.nullable().optional().default(null).describe("간편결제사. `method`가 `EASY_PAY`일 때만 값이 있고, PG가 알려 주지 않았으면 주문서에서 고른 간편결제사다. 그 밖의 결제수단과 간편결제 이전 주문은 null. 서버는 항상 싣는다. 현재 값은 `NAVERPAY`·`KAKAOPAY`·`TOSSPAY`·`PAYCO`이고 값이 추가될 수 있어 문자열로 받는다"),
612
536
  totalAmount: z.number().int(),
613
537
  paidAt: z.string().nullable(),
614
538
  receiptUrl: z.url().nullable()
@@ -630,6 +554,12 @@ const deliveryTrackingSchema = z.object({
630
554
  occurredAt: z.string()
631
555
  }))
632
556
  });
557
+ /** `POST /me/order-items/{orderItemId}/purchase-decision` 응답 */
558
+ const purchaseDecisionResultSchema = z.object({
559
+ orderItemId: z.string(),
560
+ status: z.literal("PURCHASE_DECIDED"),
561
+ decidedAt: z.string()
562
+ });
633
563
  //#endregion
634
564
  //#region src/schemas/review.ts
635
565
  const publicReviewSchema = z.object({
@@ -672,10 +602,17 @@ const updateReviewRequestSchema = z.object({
672
602
  content: z.string().min(10).max(2e3).optional(),
673
603
  images: z.array(z.url()).max(5).optional()
674
604
  }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
605
+ /** `GET /products/{productId}/reviews` 응답 — 리뷰 페이지와 평점 분포 */
606
+ const reviewPageSchema = pageSchema(publicReviewSchema).extend({ summary: reviewSummarySchema.optional() });
607
+ /** `PUT /me/reviews/{reviewId}` 응답 */
608
+ const updateReviewResultSchema = z.object({
609
+ reviewId: z.string(),
610
+ updatedAt: z.string()
611
+ });
675
612
  //#endregion
676
613
  //#region src/schemas/store.ts
677
614
  /**
678
- * 스토어 공개 설정 — `GET /store`. 스토어프런트가 화면을 그릴 때 읽는 값만 담는다.
615
+ * 스토어 공개 설정 — `GET /store`. 스토어프론트가 화면을 그릴 때 읽는 값만 담는다.
679
616
  */
680
617
  const storefrontStoreSchema = z.object({
681
618
  storeCode: z.string(),
@@ -700,8 +637,6 @@ const storefrontStoreSchema = z.object({
700
637
  });
701
638
  //#endregion
702
639
  //#region src/client.ts
703
- const productPageSchema = pageSchema(productCardSchema).extend({ facets: productFacetsSchema.optional() });
704
- const reviewPageSchema = pageSchema(publicReviewSchema).extend({ summary: reviewSummarySchema.optional() });
705
640
  function createStorefrontClient(options) {
706
641
  const { session } = options;
707
642
  const accessTokenSource = options.accessToken ?? options.auth?.accessToken ?? (session ? () => session.accessToken : void 0);
@@ -757,7 +692,15 @@ function createStorefrontClient(options) {
757
692
  /** 소셜 로그인 마무리 — 돌아온 1회용 code + codeVerifier를 구매자 토큰으로 바꾼다 */
758
693
  idpToken: (body) => http.request("POST", "/auth/idp/token", tokenPairSchema, { body: idpTokenRequestSchema.parse(body) }),
759
694
  /** 구매자 탈퇴 — 로그인 상태(accessToken)에서 비밀번호로 본인 확인. 성공하면 토큰은 모두 무효 */
760
- withdraw: (body) => http.requestVoid("POST", "/auth/withdraw", { body: withdrawRequestSchema.parse(body) })
695
+ withdraw: (body) => http.requestVoid("POST", "/auth/withdraw", { body: withdrawRequestSchema.parse(body) }),
696
+ /** 로그인 수단 — 비밀번호 여부와 연결된 소셜 계정(로그인 필요) */
697
+ identities: () => http.request("GET", "/me/identities", memberIdentitiesSchema),
698
+ /** 소셜 계정 연결 시작(로그인 필요) — 공급자 로그인 주소를 받는다. 본문은 `idpAuthorize`와 같다 */
699
+ linkIdentityAuthorize: (provider, body) => http.request("POST", path`/me/identities/${provider}/authorize`, idpAuthorizeResponseSchema, { body: idpAuthorizeRequestSchema.parse(body) }),
700
+ /** 소셜 계정 연결 마무리 — 돌아온 code + codeVerifier로 이 구매자에 연결한다 */
701
+ linkIdentity: (provider, body) => http.request("POST", path`/me/identities/${provider}`, memberIdentitiesSchema, { body: linkIdentityRequestSchema.parse(body) }),
702
+ /** 소셜 계정 연결 해제 — 마지막 로그인 수단이면 409 `LAST_LOGIN_METHOD` */
703
+ unlinkIdentity: (provider) => http.request("DELETE", path`/me/identities/${provider}`, memberIdentitiesSchema)
761
704
  },
762
705
  store: {
763
706
  /** 스토어 공개 설정 — 이름·고객센터·비회원 주문 허용 여부 */
@@ -779,43 +722,34 @@ get: () => http.request("GET", "/store", storefrontStoreSchema) },
779
722
  checkout: {
780
723
  create: (body) => http.request("POST", "/checkout", checkoutSessionSchema, { body: createCheckoutRequestSchema.parse(body) }),
781
724
  /**
782
- * 결제 시작 — 결제 세션을 만들고 결제 팝업 URL(`pgParams.popupUrl`)을 돌려준다.
783
- * `pgProvider`는 첫 결제 시도의 PG다(현재 `tosspayments`·`portone`, 새 PG가 추가돼도 파싱은 깨지지 않는다).
725
+ * `POST /checkout/{checkoutId}/payment` — 결제 시작. 배송지와 결제 옵션(`paymentOptions` 항목 또는 직접 쓴 옵션)으로
726
+ * 결제 세션·첫 시도를 만들고 결제 서비스 주소(`payUrl`)를 돌려준다. 그 주소를 열어 결제를 진행하는 것은
727
+ * `@sayren/storefront-sdk/payments`의 `createPayments().start()`다 — 이 메서드는 값만 받는다.
784
728
  *
785
- * PG 관련 에러(`ApiError.code`) — 둘 다 "결제 수단 준비 중" 안내를 권장한다.
786
- * - 409 `PAYMENT_NOT_CONFIGURED`: 스토어에 사용 중인 PG가 없다. 결제 세션을 만들지 않는다
787
- * - 503 `PAYMENT_PROVIDER_UNAVAILABLE`: 사용 중인 PG가 모두 준비 장애다. 잠시 후 재시도할 수 있다
729
+ * 에러(`ApiError.code`):
730
+ * - 409 `PAYMENT_OPTION_UNAVAILABLE`: 이 스토어에서 쓸 수 없는 옵션. `details.paymentOptions`에 지금 목록
731
+ * - 409 `PAYMENT_NOT_CONFIGURED`: 사용 중인 PG가 없다
732
+ * - 400 `RETURN_URL_NOT_ALLOWED`: `returnUrl`이 https가 아니거나(테스트 결제의 localhost는 예외),
733
+ * 스토어가 결제 도메인을 등록했는데 그 안이 아니다. 등록하지 않았으면 https 주소는 모두 받는다
734
+ * - 503 `PAYMENT_PROVIDER_UNAVAILABLE`: 고른 PG의 결제창을 준비하지 못했다(다른 옵션으로 다시 시도)
788
735
  */
789
- requestPayment: (checkoutId, body) => http.request("POST", path`/checkout/${checkoutId}/payment`, paymentParamsSchema, { body: requestPaymentRequestSchema.parse(body) }),
736
+ startPayment: (checkoutId, body) => http.request("POST", path`/checkout/${checkoutId}/payment`, paymentStartSchema, { body: startPaymentRequestSchema.parse(body) })
737
+ },
738
+ payments: {
790
739
  /**
791
- * 결제 승인 확정 — 같은 `paymentId + pgToken` 재호출은 저장된 결과를 돌려준다(멱등).
792
- * `options.attemptId`는 결제창이 돌려준 주문번호(시도 id)이고, 생략하면 현재 시도를 승인한다.
740
+ * `GET /storefront/v1/payments/{paymentId}` — 결제 상태 조회. 복귀 화면에서 결과가 확인 중(`processing`)이면
741
+ * `expiresAt`까지 폴링한다. `completed`면 `orderId`로 완료 화면, `failed`·`expired`면 실패 안내다.
742
+ * TTL이 지난 `pending`은 `expired`로 보고된다. `testPayment`는 완료면 주문 플래그, 아니면 세션 환경이다.
793
743
  *
794
- * 요청 본문은 보내기 전에 `confirmPaymentRequestSchema`로 검증한다. 빈 `pgToken`처럼 형식이 틀리면
795
- * 요청을 보내지 않고 **동기로 ZodError를 던진다**(Promise reject 아님 — 다른 메서드의 요청 검증과 같다).
796
- *
797
- * 카드 거절(402 `PG_DECLINED` 등)·402 `PAYMENT_NOT_APPROVED`·502 `PG_REQUEST_FAILED`·
798
- * 503 `PG_CREDENTIALS_UNAVAILABLE` 뒤에도 세션은 `pending`으로 남아 다시 시도할 수 있다.
799
- * 409 `LATE_APPROVAL_CANCELED`(미승인으로 판정된 뒤 늦게 온 승인을 서버가 PG 취소함)도 세션이 `pending`으로 남는다.
800
- * 409 `PAYMENT_RESULT_UNKNOWN`은 결과 확인 중이라 재시도하면 안 된다. 그 밖의 409:
801
- * `ATTEMPT_NOT_CURRENT`·`INVALID_ATTEMPT_STATE`·`PAYMENT_SESSION_OUTDATED`·`PG_AMOUNT_MISMATCH`.
802
- * 503 `PG_MERCHANT_MISMATCH`: 승인 시도의 가맹점과 현재 저장된 자격 증명의 가맹점이 다르다.
744
+ * 에러: 404 `PAYMENT_NOT_FOUND`(없음·다른 스토어) · 410 `STORE_CLOSED` · 503 `STORE_SUSPENDED`
745
+ */
746
+ getStatus: (paymentId) => http.request("GET", path`/payments/${paymentId}`, paymentStatusSchema),
747
+ /**
748
+ * `POST /payments/{paymentId}/attempts` — 같은 결제에서 다른 결제 옵션으로 다시 시도한다. 새 시도의 결제창 값을
749
+ * 돌려준다. 승인 중이거나 결과 확인 중이면 409 `PAYMENT_IN_PROGRESS`다.
803
750
  */
804
- confirmPayment: (paymentId, pgToken, options) => http.request("POST", path`/payments/${paymentId}/confirm`, confirmPaymentResultSchema, { body: confirmPaymentRequestSchema.parse({
805
- pgToken,
806
- attemptId: options?.attemptId
807
- }) })
751
+ retry: (paymentId, body) => http.request("POST", path`/payments/${paymentId}/attempts`, paymentStartSchema, { body: retryPaymentRequestSchema.parse(body) })
808
752
  },
809
- payments: {
810
- /**
811
- * `GET /storefront/v1/payments/{paymentId}` — 결제 상태 조회. 결제 팝업이 결과(postMessage)를 알리지 못하고 닫혔을 때
812
- * 부모 창이 `expiresAt`까지 폴링해 결과를 확인한다. `completed`면 `orderId`로 완료 화면, `processing`이면 계속 폴링,
813
- * `pending`이면 기존 안내, `failed`·`expired`면 실패 안내다. TTL이 지난 `pending`은 `expired`로 보고된다.
814
- * `testPayment`는 완료면 주문 플래그, 아니면 세션 환경이다.
815
- *
816
- * 에러: 404 `PAYMENT_NOT_FOUND`(없음·다른 스토어) · 410 `STORE_CLOSED` · 503 `STORE_SUSPENDED`
817
- */
818
- getStatus: (paymentId) => http.request("GET", path`/payments/${paymentId}`, paymentStatusSchema) },
819
753
  myOrders: {
820
754
  list: (params) => http.request("GET", "/me/orders", pageSchema(myOrderSchema), { query: params }),
821
755
  get: (orderId) => http.request("GET", path`/me/orders/${orderId}`, myOrderSchema),
@@ -854,4 +788,4 @@ getStatus: (paymentId) => http.request("GET", path`/payments/${paymentId}`, paym
854
788
  };
855
789
  }
856
790
  //#endregion
857
- export { idpAuthorizeRequestSchema as $, pageSchema as A, pgParamsSchema as B, claimTypeSchema as C, claimStatusSchema as D, myClaimSchema as E, createCheckoutRequestSchema as F, productDetailSchema as G, shippingAddressInputSchema as H, guestInfoSchema as I, addCartItemRequestSchema as J, productFacetsSchema as K, paymentMethodSchema as L, checkoutSessionSchema as M, confirmPaymentRequestSchema as N, orderItemStatusSchema as O, confirmPaymentResultSchema as P, anonymousSessionSchema as Q, paymentParamsSchema as R, claimReasonSchema as S, createClaimResultSchema as T, categoryNodeSchema as U, requestPaymentRequestSchema as V, productCardSchema as W, cartSchema as X, cartItemSchema as Y, updateCartItemRequestSchema as Z, createInquiryRequestSchema as _, publicReviewSchema as a, tokenPairSchema as at, customerInquiryCategorySchema as b, writableReviewSchema as c, ApiError as ct, myOrderSchema as d, unwrapData as dt, idpAuthorizeResponseSchema as et, orderShippingAddressSchema as f, updateProfileRequestSchema as g, memberSchema as h, createReviewResultSchema as i, socialProviderSchema as it, PAYMENT_STATUS_VALUES as j, pageInfoSchema as k, deliveryTrackingSchema as l, buildQuery as lt, memberAddressSchema as m, storefrontStoreSchema as n, loginRequestSchema as nt, reviewSummarySchema as o, withdrawRequestSchema as ot, memberAddressRequestSchema as p, productSortSchema as q, createReviewRequestSchema as r, signupRequestSchema as rt, updateReviewRequestSchema as s, withdrawalBlockedDetailsSchema as st, createStorefrontClient as t, idpTokenRequestSchema as tt, myOrderItemSchema as u, toApiError as ut, publicInquirySchema as v, createClaimRequestSchema as w, customerInquirySchema as x, createCustomerInquiryRequestSchema as y, paymentStatusSchema as z };
791
+ export { signupRequestSchema as $, createClaimResultSchema as A, pageInfoSchema as B, publicInquirySchema as C, claimReasonSchema as D, customerInquirySchema as E, productFacetsSchema as F, updateCartItemRequestSchema as G, addCartItemRequestSchema as H, productPageSchema as I, idpAuthorizeResponseSchema as J, anonymousSessionSchema as K, productSortSchema as L, categoryNodeSchema as M, productCardSchema as N, claimTypeSchema as O, productDetailSchema as P, memberIdentitiesSchema as Q, claimStatusSchema as R, createInquiryResultSchema as S, customerInquiryCategorySchema as T, cartItemSchema as U, pageSchema as V, cartSchema as W, linkIdentityRequestSchema as X, idpTokenRequestSchema as Y, loginRequestSchema as Z, memberAddressSchema as _, publicReviewSchema as a, buildQuery as at, wishlistAddResultSchema as b, updateReviewRequestSchema as c, deliveryTrackingSchema as d, socialProviderSchema as et, myOrderItemSchema as f, memberAddressRequestSchema as g, purchaseDecisionResultSchema as h, createReviewResultSchema as i, ApiError as it, myClaimSchema as j, createClaimRequestSchema as k, updateReviewResultSchema as l, orderShippingAddressSchema as m, storefrontStoreSchema as n, withdrawRequestSchema as nt, reviewPageSchema as o, toApiError as ot, myOrderSchema as p, idpAuthorizeRequestSchema as q, createReviewRequestSchema as r, withdrawalBlockedDetailsSchema as rt, reviewSummarySchema as s, unwrapData as st, createStorefrontClient as t, tokenPairSchema as tt, writableReviewSchema as u, memberSchema as v, createCustomerInquiryRequestSchema as w, createInquiryRequestSchema as x, updateProfileRequestSchema as y, orderItemStatusSchema as z };
@@ -75,6 +75,27 @@ declare const idpTokenRequestSchema: z.ZodObject<{
75
75
  cartToken: z.ZodOptional<z.ZodString>;
76
76
  }, z.core.$strip>;
77
77
  type IdpTokenRequest = z.infer<typeof idpTokenRequestSchema>;
78
+ /** `GET /me/identities` — 구매자의 로그인 수단(비밀번호 여부와 연결된 소셜 계정) */
79
+ declare const memberIdentitiesSchema: z.ZodObject<{
80
+ hasPassword: z.ZodBoolean;
81
+ hasExternalAuth: z.ZodBoolean;
82
+ identities: z.ZodArray<z.ZodObject<{
83
+ provider: z.ZodEnum<{
84
+ kakao: "kakao";
85
+ naver: "naver";
86
+ google: "google";
87
+ }>;
88
+ email: z.ZodNullable<z.ZodString>;
89
+ linkedAt: z.ZodString;
90
+ }, z.core.$strip>>;
91
+ }, z.core.$strip>;
92
+ type MemberIdentities = z.infer<typeof memberIdentitiesSchema>;
93
+ /** `POST /me/identities/{provider}` 본문 — 연결 흐름에서 돌아온 1회용 code와 PKCE verifier */
94
+ declare const linkIdentityRequestSchema: z.ZodObject<{
95
+ code: z.ZodString;
96
+ codeVerifier: z.ZodString;
97
+ }, z.core.$strip>;
98
+ type LinkIdentityRequest = z.infer<typeof linkIdentityRequestSchema>;
78
99
  //#endregion
79
100
  //#region src/http.d.ts
80
101
  declare class ApiError extends Error {
@@ -92,4 +113,4 @@ type TokenSource = string | null | undefined | (() => string | null | undefined)
92
113
  type Query = Record<string, string | number | boolean | undefined>;
93
114
  declare function buildQuery(query?: Query): string;
94
115
  //#endregion
95
- export { withdrawalBlockedDetailsSchema as C, withdrawRequestSchema as S, idpTokenRequestSchema as _, AnonymousSession as a, socialProviderSchema as b, LoginRequest as c, TokenPair as d, WithdrawRequest as f, idpAuthorizeResponseSchema as g, idpAuthorizeRequestSchema as h, buildQuery as i, SignupRequest as l, anonymousSessionSchema as m, Query as n, IdpAuthorizeRequest as o, WithdrawalBlockedDetails as p, TokenSource as r, IdpTokenRequest as s, ApiError as t, SocialProvider as u, loginRequestSchema as v, tokenPairSchema as x, signupRequestSchema as y };
116
+ export { signupRequestSchema as C, withdrawalBlockedDetailsSchema as D, withdrawRequestSchema as E, memberIdentitiesSchema as S, tokenPairSchema as T, idpAuthorizeRequestSchema as _, AnonymousSession as a, linkIdentityRequestSchema as b, LinkIdentityRequest as c, SignupRequest as d, SocialProvider as f, anonymousSessionSchema as g, WithdrawalBlockedDetails as h, buildQuery as i, LoginRequest as l, WithdrawRequest as m, Query as n, IdpAuthorizeRequest as o, TokenPair as p, TokenSource as r, IdpTokenRequest as s, ApiError as t, MemberIdentities as u, idpAuthorizeResponseSchema as v, socialProviderSchema as w, loginRequestSchema as x, idpTokenRequestSchema as y };