@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/src/client.ts CHANGED
@@ -9,7 +9,10 @@ import {
9
9
  idpAuthorizeRequestSchema,
10
10
  idpAuthorizeResponseSchema,
11
11
  idpTokenRequestSchema,
12
+ type LinkIdentityRequest,
13
+ linkIdentityRequestSchema,
12
14
  loginRequestSchema,
15
+ memberIdentitiesSchema,
13
16
  type SocialProvider,
14
17
  signupRequestSchema,
15
18
  tokenPairSchema,
@@ -28,18 +31,18 @@ import {
28
31
  type ProductSearchParams,
29
32
  productCardSchema,
30
33
  productDetailSchema,
31
- productFacetsSchema,
34
+ productPageSchema,
32
35
  } from "./schemas/catalog";
33
36
  import {
34
37
  type CreateCheckoutRequest,
35
38
  checkoutSessionSchema,
36
- confirmPaymentRequestSchema,
37
- confirmPaymentResultSchema,
38
39
  createCheckoutRequestSchema,
39
- paymentParamsSchema,
40
+ paymentStartSchema,
40
41
  paymentStatusSchema,
41
- type RequestPaymentRequest,
42
- requestPaymentRequestSchema,
42
+ type RetryPaymentRequest,
43
+ retryPaymentRequestSchema,
44
+ type StartPaymentRequest,
45
+ startPaymentRequestSchema,
43
46
  } from "./schemas/checkout";
44
47
  import {
45
48
  type CreateClaimRequest,
@@ -73,8 +76,7 @@ import {
73
76
  type CreateReviewRequest,
74
77
  createReviewRequestSchema,
75
78
  createReviewResultSchema,
76
- publicReviewSchema,
77
- reviewSummarySchema,
79
+ reviewPageSchema,
78
80
  type UpdateReviewRequest,
79
81
  updateReviewRequestSchema,
80
82
  writableReviewSchema,
@@ -117,14 +119,6 @@ export interface StorefrontClientOptions {
117
119
  fetch?: typeof globalThis.fetch;
118
120
  }
119
121
 
120
- const productPageSchema = pageSchema(productCardSchema).extend({
121
- facets: productFacetsSchema.optional(),
122
- });
123
-
124
- const reviewPageSchema = pageSchema(publicReviewSchema).extend({
125
- summary: reviewSummarySchema.optional(),
126
- });
127
-
128
122
  export function createStorefrontClient(options: StorefrontClientOptions) {
129
123
  const { session } = options;
130
124
 
@@ -203,6 +197,24 @@ export function createStorefrontClient(options: StorefrontClientOptions) {
203
197
  /** 구매자 탈퇴 — 로그인 상태(accessToken)에서 비밀번호로 본인 확인. 성공하면 토큰은 모두 무효 */
204
198
  withdraw: (body: WithdrawRequest) =>
205
199
  http.requestVoid("POST", "/auth/withdraw", { body: withdrawRequestSchema.parse(body) }),
200
+ /** 로그인 수단 — 비밀번호 여부와 연결된 소셜 계정(로그인 필요) */
201
+ identities: () => http.request("GET", "/me/identities", memberIdentitiesSchema),
202
+ /** 소셜 계정 연결 시작(로그인 필요) — 공급자 로그인 주소를 받는다. 본문은 `idpAuthorize`와 같다 */
203
+ linkIdentityAuthorize: (provider: SocialProvider, body: IdpAuthorizeRequest) =>
204
+ http.request(
205
+ "POST",
206
+ path`/me/identities/${provider}/authorize`,
207
+ idpAuthorizeResponseSchema,
208
+ { body: idpAuthorizeRequestSchema.parse(body) },
209
+ ),
210
+ /** 소셜 계정 연결 마무리 — 돌아온 code + codeVerifier로 이 구매자에 연결한다 */
211
+ linkIdentity: (provider: SocialProvider, body: LinkIdentityRequest) =>
212
+ http.request("POST", path`/me/identities/${provider}`, memberIdentitiesSchema, {
213
+ body: linkIdentityRequestSchema.parse(body),
214
+ }),
215
+ /** 소셜 계정 연결 해제 — 마지막 로그인 수단이면 409 `LAST_LOGIN_METHOD` */
216
+ unlinkIdentity: (provider: SocialProvider) =>
217
+ http.request("DELETE", path`/me/identities/${provider}`, memberIdentitiesSchema),
206
218
  },
207
219
 
208
220
  store: {
@@ -260,48 +272,41 @@ export function createStorefrontClient(options: StorefrontClientOptions) {
260
272
  body: createCheckoutRequestSchema.parse(body),
261
273
  }),
262
274
  /**
263
- * 결제 시작 — 결제 세션을 만들고 결제 팝업 URL(`pgParams.popupUrl`)을 돌려준다.
264
- * `pgProvider`는 첫 결제 시도의 PG다(현재 `tosspayments`·`portone`, 새 PG가 추가돼도 파싱은 깨지지 않는다).
265
- *
266
- * PG 관련 에러(`ApiError.code`) — 둘 다 "결제 수단 준비 중" 안내를 권장한다.
267
- * - 409 `PAYMENT_NOT_CONFIGURED`: 스토어에 사용 중인 PG가 없다. 결제 세션을 만들지 않는다
268
- * - 503 `PAYMENT_PROVIDER_UNAVAILABLE`: 사용 중인 PG가 모두 준비 장애다. 잠시 후 재시도할 수 있다
269
- */
270
- requestPayment: (checkoutId: string, body: RequestPaymentRequest) =>
271
- http.request("POST", path`/checkout/${checkoutId}/payment`, paymentParamsSchema, {
272
- body: requestPaymentRequestSchema.parse(body),
273
- }),
274
- /**
275
- * 결제 승인 확정 — 같은 `paymentId + pgToken` 재호출은 저장된 결과를 돌려준다(멱등).
276
- * `options.attemptId`는 결제창이 돌려준 주문번호(시도 id)이고, 생략하면 현재 시도를 승인한다.
277
- *
278
- * 요청 본문은 보내기 전에 `confirmPaymentRequestSchema`로 검증한다. 빈 `pgToken`처럼 형식이 틀리면
279
- * 요청을 보내지 않고 **동기로 ZodError를 던진다**(Promise reject 아님 — 다른 메서드의 요청 검증과 같다).
275
+ * `POST /checkout/{checkoutId}/payment` — 결제 시작. 배송지와 결제 옵션(`paymentOptions` 항목 또는 직접 쓴 옵션)으로
276
+ * 결제 세션·첫 시도를 만들고 결제 서비스 주소(`payUrl`)를 돌려준다. 그 주소를 열어 결제를 진행하는 것은
277
+ * `@sayren/storefront-sdk/payments`의 `createPayments().start()`다 — 이 메서드는 값만 받는다.
280
278
  *
281
- * 카드 거절(402 `PG_DECLINED` 등)·402 `PAYMENT_NOT_APPROVED`·502 `PG_REQUEST_FAILED`·
282
- * 503 `PG_CREDENTIALS_UNAVAILABLE` 뒤에도 세션은 `pending`으로 남아 다시 시도할 수 있다.
283
- * 409 `LATE_APPROVAL_CANCELED`(미승인으로 판정된 뒤 늦게 온 승인을 서버가 PG 취소함)도 세션이 `pending`으로 남는다.
284
- * 409 `PAYMENT_RESULT_UNKNOWN`은 결과 확인 중이라 재시도하면 안 된다. 그 밖의 409:
285
- * `ATTEMPT_NOT_CURRENT`·`INVALID_ATTEMPT_STATE`·`PAYMENT_SESSION_OUTDATED`·`PG_AMOUNT_MISMATCH`.
286
- * 503 `PG_MERCHANT_MISMATCH`: 승인 시도의 가맹점과 현재 저장된 자격 증명의 가맹점이 다르다.
279
+ * 에러(`ApiError.code`):
280
+ * - 409 `PAYMENT_OPTION_UNAVAILABLE`: 이 스토어에서 쓸 수 없는 옵션. `details.paymentOptions`에 지금 목록
281
+ * - 409 `PAYMENT_NOT_CONFIGURED`: 사용 중인 PG가 없다
282
+ * - 400 `RETURN_URL_NOT_ALLOWED`: `returnUrl`이 https가 아니거나(테스트 결제의 localhost는 예외),
283
+ * 스토어가 결제 도메인을 등록했는데 그 안이 아니다. 등록하지 않았으면 https 주소는 모두 받는다
284
+ * - 503 `PAYMENT_PROVIDER_UNAVAILABLE`: 고른 PG의 결제창을 준비하지 못했다(다른 옵션으로 다시 시도)
287
285
  */
288
- confirmPayment: (paymentId: string, pgToken: string, options?: { attemptId?: string }) =>
289
- http.request("POST", path`/payments/${paymentId}/confirm`, confirmPaymentResultSchema, {
290
- body: confirmPaymentRequestSchema.parse({ pgToken, attemptId: options?.attemptId }),
286
+ startPayment: (checkoutId: string, body: StartPaymentRequest) =>
287
+ http.request("POST", path`/checkout/${checkoutId}/payment`, paymentStartSchema, {
288
+ body: startPaymentRequestSchema.parse(body),
291
289
  }),
292
290
  },
293
291
 
294
292
  payments: {
295
293
  /**
296
- * `GET /storefront/v1/payments/{paymentId}` — 결제 상태 조회. 결제 팝업이 결과(postMessage)를 알리지 못하고 닫혔을 때
297
- * 부모 창이 `expiresAt`까지 폴링해 결과를 확인한다. `completed`면 `orderId`로 완료 화면, `processing`이면 계속 폴링,
298
- * `pending`이면 기존 안내, `failed`·`expired`면 실패 안내다. TTL이 지난 `pending`은 `expired`로 보고된다.
299
- * `testPayment`는 완료면 주문 플래그, 아니면 세션 환경이다.
294
+ * `GET /storefront/v1/payments/{paymentId}` — 결제 상태 조회. 복귀 화면에서 결과가 확인 중(`processing`)이면
295
+ * `expiresAt`까지 폴링한다. `completed`면 `orderId`로 완료 화면, `failed`·`expired`면 실패 안내다.
296
+ * TTL이 지난 `pending`은 `expired`로 보고된다. `testPayment`는 완료면 주문 플래그, 아니면 세션 환경이다.
300
297
  *
301
298
  * 에러: 404 `PAYMENT_NOT_FOUND`(없음·다른 스토어) · 410 `STORE_CLOSED` · 503 `STORE_SUSPENDED`
302
299
  */
303
300
  getStatus: (paymentId: string) =>
304
301
  http.request("GET", path`/payments/${paymentId}`, paymentStatusSchema),
302
+ /**
303
+ * `POST /payments/{paymentId}/attempts` — 같은 결제에서 다른 결제 옵션으로 다시 시도한다. 새 시도의 결제창 값을
304
+ * 돌려준다. 승인 중이거나 결과 확인 중이면 409 `PAYMENT_IN_PROGRESS`다.
305
+ */
306
+ retry: (paymentId: string, body: RetryPaymentRequest) =>
307
+ http.request("POST", path`/payments/${paymentId}/attempts`, paymentStartSchema, {
308
+ body: retryPaymentRequestSchema.parse(body),
309
+ }),
305
310
  },
306
311
 
307
312
  myOrders: {