@sayren/storefront-sdk 0.6.0 → 0.7.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,4 @@
1
- import { a as AnonymousSession, c as LoginRequest, d as TokenPair, f as WithdrawRequest, l as SignupRequest, p as WithdrawalBlockedDetails, t as ApiError, u as SocialProvider } from "../http-CqAR0_w4.mjs";
1
+ import { a as AnonymousSession, d as SignupRequest, f as SocialProvider, h as WithdrawalBlockedDetails, l as LoginRequest, m as WithdrawRequest, p as TokenPair, t as ApiError, u as MemberIdentities } from "../http-BbFHVGBf.mjs";
2
2
  //#region src/auth/index.d.ts
3
3
  /** 소셜 로그인 시작 결과 — `codeVerifier`와 `state`는 돌아올 때까지 서버 세션(httpOnly 쿠키 등)에 보관한다 */
4
4
  export interface IdpStart {
@@ -31,7 +31,7 @@ export interface StorefrontAuthOptions {
31
31
  fetch?: typeof globalThis.fetch;
32
32
  }
33
33
  /**
34
- * 구매자 인증 — 화면은 스토어프런트가 그리고, 계정 저장과 인증 처리는 sayren이 한다.
34
+ * 구매자 인증 — 화면은 스토어프론트가 그리고, 계정 저장과 인증 처리는 sayren이 한다.
35
35
  * 어느 방식으로 로그인해도 결과는 같은 구매자 토큰(`TokenPair`)이고 `/me/*`·장바구니·주문 API에 그대로 쓴다.
36
36
  *
37
37
  * 토큰 보관은 앱 몫이다. 서버(loader·action)에서 호출하고 httpOnly 쿠키에 두기를 권한다.
@@ -56,7 +56,7 @@ export declare function createStorefrontAuth(options: StorefrontAuthOptions): {
56
56
  /**
57
57
  * 소셜 로그인 시작 — PKCE(S256)와 state를 만들고 공급자 로그인 주소를 받는다. 반환한 `state`·`codeVerifier`를
58
58
  * 서버 세션에 보관하고 구매자를 `url`로 보낸다. 로그인을 마치면 `redirectUri`로 `?code=&state=`가 붙어 돌아온다.
59
- * `redirectUri`는 스토어프런트 도메인 목록 안이어야 한다
59
+ * `redirectUri`는 스토어프론트 도메인 목록 안이어야 한다
60
60
  */
61
61
  idp(provider: SocialProvider, options: {
62
62
  redirectUri: string;
@@ -68,6 +68,24 @@ export declare function createStorefrontAuth(options: StorefrontAuthOptions): {
68
68
  idpCallback(input: IdpCallbackInput & {
69
69
  error?: string | null;
70
70
  }): Promise<TokenPair>;
71
+ /** 로그인 수단 — 비밀번호가 있는지, 어떤 소셜 계정이 연결됐는지 */
72
+ identities(accessToken: string): Promise<MemberIdentities>;
73
+ /**
74
+ * 소셜 계정 연결 시작 — 로그인한 구매자에 공급자 계정을 붙인다. `idp()`처럼 `state`·`codeVerifier`를 보관하고
75
+ * 구매자를 `url`로 보낸다. 돌아오면 `linkIdpCallback()`으로 마무리한다. 연결은 흐름을 시작한 구매자에게만 된다
76
+ */
77
+ linkIdp(accessToken: string, provider: SocialProvider, options: {
78
+ redirectUri: string;
79
+ }): Promise<IdpStart>;
80
+ /**
81
+ * 소셜 계정 연결 마무리 — state를 비교하고 code를 바꿔 연결한다. 다른 구매자에 이미 연결된 계정이면
82
+ * 409 `IDENTITY_IN_USE`, 같은 공급자의 다른 계정을 이미 연결했으면 409 `PROVIDER_ALREADY_LINKED`
83
+ */
84
+ linkIdpCallback(accessToken: string, provider: SocialProvider, input: Omit<IdpCallbackInput, "cartToken"> & {
85
+ error?: string | null;
86
+ }): Promise<MemberIdentities>;
87
+ /** 소셜 계정 연결 해제 — 마지막 로그인 수단이면 409 `LAST_LOGIN_METHOD` */
88
+ unlinkIdp(accessToken: string, provider: SocialProvider): Promise<MemberIdentities>;
71
89
  /** 토큰 갱신 — refreshToken은 한 번 쓰면 폐기되고 새 쌍이 온다(회전) */
72
90
  refresh(refreshToken: string): Promise<TokenPair>;
73
91
  /**
@@ -84,4 +102,4 @@ export declare function createStorefrontAuth(options: StorefrontAuthOptions): {
84
102
  };
85
103
  export type StorefrontAuth = ReturnType<typeof createStorefrontAuth>;
86
104
  //#endregion
87
- export { type AnonymousSession, ApiError, type LoginRequest, type SignupRequest, type SocialProvider, type TokenPair, type WithdrawRequest, type WithdrawalBlockedDetails };
105
+ export { type AnonymousSession, ApiError, type LoginRequest, type MemberIdentities, type SignupRequest, type SocialProvider, type TokenPair, type WithdrawRequest, type WithdrawalBlockedDetails };
@@ -1,4 +1,4 @@
1
- import { ct as ApiError, t as createStorefrontClient } from "../client-Do9-LG5X.mjs";
1
+ import { gt as ApiError, t as createStorefrontClient } from "../client-B1uXGefY.mjs";
2
2
  //#region src/auth/index.ts
3
3
  /** 소셜 로그인 실패 — 구매자가 취소했거나(`access_denied`) state가 맞지 않는다 */
4
4
  var IdpCallbackError = class extends Error {
@@ -22,7 +22,7 @@ async function s256(verifier) {
22
22
  return base64url(new Uint8Array(digest));
23
23
  }
24
24
  /**
25
- * 구매자 인증 — 화면은 스토어프런트가 그리고, 계정 저장과 인증 처리는 sayren이 한다.
25
+ * 구매자 인증 — 화면은 스토어프론트가 그리고, 계정 저장과 인증 처리는 sayren이 한다.
26
26
  * 어느 방식으로 로그인해도 결과는 같은 구매자 토큰(`TokenPair`)이고 `/me/*`·장바구니·주문 API에 그대로 쓴다.
27
27
  *
28
28
  * 토큰 보관은 앱 몫이다. 서버(loader·action)에서 호출하고 httpOnly 쿠키에 두기를 권한다.
@@ -60,7 +60,7 @@ function createStorefrontAuth(options) {
60
60
  /**
61
61
  * 소셜 로그인 시작 — PKCE(S256)와 state를 만들고 공급자 로그인 주소를 받는다. 반환한 `state`·`codeVerifier`를
62
62
  * 서버 세션에 보관하고 구매자를 `url`로 보낸다. 로그인을 마치면 `redirectUri`로 `?code=&state=`가 붙어 돌아온다.
63
- * `redirectUri`는 스토어프런트 도메인 목록 안이어야 한다
63
+ * `redirectUri`는 스토어프론트 도메인 목록 안이어야 한다
64
64
  */
65
65
  async idp(provider, options) {
66
66
  const state = randomToken(24);
@@ -90,6 +90,45 @@ function createStorefrontAuth(options) {
90
90
  cartToken: input.cartToken
91
91
  });
92
92
  },
93
+ /** 로그인 수단 — 비밀번호가 있는지, 어떤 소셜 계정이 연결됐는지 */
94
+ identities(accessToken) {
95
+ return client(accessToken).auth.identities();
96
+ },
97
+ /**
98
+ * 소셜 계정 연결 시작 — 로그인한 구매자에 공급자 계정을 붙인다. `idp()`처럼 `state`·`codeVerifier`를 보관하고
99
+ * 구매자를 `url`로 보낸다. 돌아오면 `linkIdpCallback()`으로 마무리한다. 연결은 흐름을 시작한 구매자에게만 된다
100
+ */
101
+ async linkIdp(accessToken, provider, options) {
102
+ const state = randomToken(24);
103
+ const codeVerifier = randomToken(32);
104
+ const { url } = await client(accessToken).auth.linkIdentityAuthorize(provider, {
105
+ redirectUri: options.redirectUri,
106
+ codeChallenge: await s256(codeVerifier),
107
+ state
108
+ });
109
+ return {
110
+ url,
111
+ state,
112
+ codeVerifier
113
+ };
114
+ },
115
+ /**
116
+ * 소셜 계정 연결 마무리 — state를 비교하고 code를 바꿔 연결한다. 다른 구매자에 이미 연결된 계정이면
117
+ * 409 `IDENTITY_IN_USE`, 같은 공급자의 다른 계정을 이미 연결했으면 409 `PROVIDER_ALREADY_LINKED`
118
+ */
119
+ linkIdpCallback(accessToken, provider, input) {
120
+ if (input.error) return Promise.reject(new IdpCallbackError(input.error));
121
+ if (!input.state || input.state !== input.expectedState) return Promise.reject(new IdpCallbackError("state_mismatch"));
122
+ if (!input.code) return Promise.reject(new IdpCallbackError("missing_code"));
123
+ return client(accessToken).auth.linkIdentity(provider, {
124
+ code: input.code,
125
+ codeVerifier: input.codeVerifier
126
+ });
127
+ },
128
+ /** 소셜 계정 연결 해제 — 마지막 로그인 수단이면 409 `LAST_LOGIN_METHOD` */
129
+ unlinkIdp(accessToken, provider) {
130
+ return client(accessToken).auth.unlinkIdentity(provider);
131
+ },
93
132
  /** 토큰 갱신 — refreshToken은 한 번 쓰면 폐기되고 새 쌍이 온다(회전) */
94
133
  refresh(refreshToken) {
95
134
  return client().auth.refresh(refreshToken);
@@ -178,11 +178,11 @@ const socialProviderSchema = z.enum([
178
178
  ]);
179
179
  /** `POST /auth/idp/{provider}/authorize` 본문 — PKCE(S256)와 state는 SDK가 만든다 */
180
180
  const idpAuthorizeRequestSchema = z.object({
181
- /** 로그인을 마치고 돌아올 스토어프런트 주소. 스토어프런트 도메인 목록 안이어야 한다 */
181
+ /** 로그인을 마치고 돌아올 스토어프론트 주소. 스토어프론트 도메인 목록 안이어야 한다 */
182
182
  redirectUri: z.url(),
183
183
  /** base64url(SHA-256(codeVerifier)) */
184
184
  codeChallenge: z.string().regex(/^[A-Za-z0-9_-]{43}$/),
185
- /** 스토어프런트가 만든 값 — 돌아올 때 그대로 붙어 온다. 세션에 저장해 두고 비교한다 */
185
+ /** 스토어프론트가 만든 값 — 돌아올 때 그대로 붙어 온다. 세션에 저장해 두고 비교한다 */
186
186
  state: z.string().min(16).max(128)
187
187
  });
188
188
  const idpAuthorizeResponseSchema = z.object({
@@ -195,6 +195,23 @@ const idpTokenRequestSchema = z.object({
195
195
  /** 비회원 장바구니 토큰 — 주면 회원 장바구니로 합친다 */
196
196
  cartToken: z.string().optional()
197
197
  });
198
+ /** `GET /me/identities` — 구매자의 로그인 수단(비밀번호 여부와 연결된 소셜 계정) */
199
+ const memberIdentitiesSchema = z.object({
200
+ hasPassword: z.boolean(),
201
+ /** 셀러 자체 회원 연동(구매자 위임)으로 들어온 구매자 — 그 로그인도 로그인 수단으로 센다 */
202
+ hasExternalAuth: z.boolean(),
203
+ identities: z.array(z.object({
204
+ provider: socialProviderSchema,
205
+ /** 공급자가 알려 준 이메일(참고값). 없을 수 있다 */
206
+ email: z.string().nullable(),
207
+ linkedAt: z.string()
208
+ }))
209
+ });
210
+ /** `POST /me/identities/{provider}` 본문 — 연결 흐름에서 돌아온 1회용 code와 PKCE verifier */
211
+ const linkIdentityRequestSchema = z.object({
212
+ code: z.string().min(1),
213
+ codeVerifier: z.string().regex(/^[A-Za-z0-9._~-]{43,128}$/)
214
+ });
198
215
  //#endregion
199
216
  //#region src/schemas/cart.ts
200
217
  const cartItemSchema = z.object({
@@ -232,6 +249,38 @@ const updateCartItemRequestSchema = z.object({
232
249
  optionId: z.string().optional()
233
250
  }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
234
251
  //#endregion
252
+ //#region src/schemas/common.ts
253
+ const pageInfoSchema = z.object({
254
+ page: z.number().int(),
255
+ size: z.number().int(),
256
+ totalElements: z.number().int(),
257
+ totalPages: z.number().int()
258
+ });
259
+ function pageSchema(item) {
260
+ return pageInfoSchema.extend({ contents: z.array(item) });
261
+ }
262
+ const orderItemStatusSchema = z.enum([
263
+ "PAYMENT_WAITING",
264
+ "PAID",
265
+ "CONFIRMED",
266
+ "DISPATCHED",
267
+ "DELIVERING",
268
+ "DELIVERED",
269
+ "PURCHASE_DECIDED",
270
+ "CANCELED"
271
+ ]);
272
+ const claimStatusSchema = z.enum([
273
+ "REQUESTED",
274
+ "HELD",
275
+ "COLLECTING",
276
+ "COLLECTED",
277
+ "REDELIVERING",
278
+ "APPROVED",
279
+ "REJECTED",
280
+ "COMPLETED",
281
+ "WITHDRAWN"
282
+ ]);
283
+ //#endregion
235
284
  //#region src/schemas/catalog.ts
236
285
  const categoryNodeSchema = z.lazy(() => z.object({
237
286
  categoryId: z.string(),
@@ -243,9 +292,9 @@ const productCardSchema = z.object({
243
292
  productId: z.string(),
244
293
  name: z.string(),
245
294
  thumbnailUrl: z.url(),
246
- salePrice: z.number().int(),
247
- discountedPrice: z.number().int().nullable(),
248
- discountRate: z.number().int().nullable(),
295
+ salePrice: z.number().int().describe("판매가. 원(KRW) 단위 정수"),
296
+ discountedPrice: z.number().int().nullable().describe("즉시 할인 적용가. 원 단위. 할인이 없으면 null"),
297
+ discountRate: z.number().int().nullable().describe("할인율(%). 할인이 없으면 null"),
249
298
  freeShipping: z.boolean(),
250
299
  averageRating: z.number(),
251
300
  reviewCount: z.number().int(),
@@ -312,6 +361,8 @@ const productFacetsSchema = z.object({
312
361
  max: z.number().int()
313
362
  }).optional()
314
363
  });
364
+ /** `GET /products` 응답 — 상품 카드 페이지와 검색 패싯 */
365
+ const productPageSchema = pageSchema(productCardSchema).extend({ facets: productFacetsSchema.optional() });
315
366
  //#endregion
316
367
  //#region src/schemas/checkout.ts
317
368
  const createCheckoutRequestSchema = z.object({
@@ -420,38 +471,6 @@ const paymentStatusSchema = z.object({
420
471
  expiresAt: z.string().describe("결제 요청 만료 시각")
421
472
  });
422
473
  //#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
- ]);
454
- //#endregion
455
474
  //#region src/schemas/claim.ts
456
475
  const claimTypeSchema = z.enum([
457
476
  "CANCEL",
@@ -538,6 +557,11 @@ const createInquiryRequestSchema = z.object({
538
557
  content: z.string().min(1).max(1e3),
539
558
  secret: z.boolean().default(false)
540
559
  });
560
+ /** `POST /products/{productId}/inquiries` 응답 */
561
+ const createInquiryResultSchema = z.object({
562
+ inquiryId: z.string(),
563
+ createdAt: z.string()
564
+ });
541
565
  //#endregion
542
566
  //#region src/schemas/member.ts
543
567
  const memberSchema = z.object({
@@ -574,6 +598,11 @@ const memberAddressRequestSchema = z.object({
574
598
  address2: z.string().optional(),
575
599
  isDefault: z.boolean().default(false)
576
600
  });
601
+ /** `POST /me/wishlist` 응답 — 이미 찜한 상품이어도 같은 응답이다 */
602
+ const wishlistAddResultSchema = z.object({
603
+ productId: z.string(),
604
+ wished: z.literal(true)
605
+ });
577
606
  //#endregion
578
607
  //#region src/schemas/order.ts
579
608
  const myOrderItemSchema = z.object({
@@ -630,6 +659,12 @@ const deliveryTrackingSchema = z.object({
630
659
  occurredAt: z.string()
631
660
  }))
632
661
  });
662
+ /** `POST /me/order-items/{orderItemId}/purchase-decision` 응답 */
663
+ const purchaseDecisionResultSchema = z.object({
664
+ orderItemId: z.string(),
665
+ status: z.literal("PURCHASE_DECIDED"),
666
+ decidedAt: z.string()
667
+ });
633
668
  //#endregion
634
669
  //#region src/schemas/review.ts
635
670
  const publicReviewSchema = z.object({
@@ -672,10 +707,17 @@ const updateReviewRequestSchema = z.object({
672
707
  content: z.string().min(10).max(2e3).optional(),
673
708
  images: z.array(z.url()).max(5).optional()
674
709
  }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
710
+ /** `GET /products/{productId}/reviews` 응답 — 리뷰 페이지와 평점 분포 */
711
+ const reviewPageSchema = pageSchema(publicReviewSchema).extend({ summary: reviewSummarySchema.optional() });
712
+ /** `PUT /me/reviews/{reviewId}` 응답 */
713
+ const updateReviewResultSchema = z.object({
714
+ reviewId: z.string(),
715
+ updatedAt: z.string()
716
+ });
675
717
  //#endregion
676
718
  //#region src/schemas/store.ts
677
719
  /**
678
- * 스토어 공개 설정 — `GET /store`. 스토어프런트가 화면을 그릴 때 읽는 값만 담는다.
720
+ * 스토어 공개 설정 — `GET /store`. 스토어프론트가 화면을 그릴 때 읽는 값만 담는다.
679
721
  */
680
722
  const storefrontStoreSchema = z.object({
681
723
  storeCode: z.string(),
@@ -700,8 +742,6 @@ const storefrontStoreSchema = z.object({
700
742
  });
701
743
  //#endregion
702
744
  //#region src/client.ts
703
- const productPageSchema = pageSchema(productCardSchema).extend({ facets: productFacetsSchema.optional() });
704
- const reviewPageSchema = pageSchema(publicReviewSchema).extend({ summary: reviewSummarySchema.optional() });
705
745
  function createStorefrontClient(options) {
706
746
  const { session } = options;
707
747
  const accessTokenSource = options.accessToken ?? options.auth?.accessToken ?? (session ? () => session.accessToken : void 0);
@@ -757,7 +797,15 @@ function createStorefrontClient(options) {
757
797
  /** 소셜 로그인 마무리 — 돌아온 1회용 code + codeVerifier를 구매자 토큰으로 바꾼다 */
758
798
  idpToken: (body) => http.request("POST", "/auth/idp/token", tokenPairSchema, { body: idpTokenRequestSchema.parse(body) }),
759
799
  /** 구매자 탈퇴 — 로그인 상태(accessToken)에서 비밀번호로 본인 확인. 성공하면 토큰은 모두 무효 */
760
- withdraw: (body) => http.requestVoid("POST", "/auth/withdraw", { body: withdrawRequestSchema.parse(body) })
800
+ withdraw: (body) => http.requestVoid("POST", "/auth/withdraw", { body: withdrawRequestSchema.parse(body) }),
801
+ /** 로그인 수단 — 비밀번호 여부와 연결된 소셜 계정(로그인 필요) */
802
+ identities: () => http.request("GET", "/me/identities", memberIdentitiesSchema),
803
+ /** 소셜 계정 연결 시작(로그인 필요) — 공급자 로그인 주소를 받는다. 본문은 `idpAuthorize`와 같다 */
804
+ linkIdentityAuthorize: (provider, body) => http.request("POST", path`/me/identities/${provider}/authorize`, idpAuthorizeResponseSchema, { body: idpAuthorizeRequestSchema.parse(body) }),
805
+ /** 소셜 계정 연결 마무리 — 돌아온 code + codeVerifier로 이 구매자에 연결한다 */
806
+ linkIdentity: (provider, body) => http.request("POST", path`/me/identities/${provider}`, memberIdentitiesSchema, { body: linkIdentityRequestSchema.parse(body) }),
807
+ /** 소셜 계정 연결 해제 — 마지막 로그인 수단이면 409 `LAST_LOGIN_METHOD` */
808
+ unlinkIdentity: (provider) => http.request("DELETE", path`/me/identities/${provider}`, memberIdentitiesSchema)
761
809
  },
762
810
  store: {
763
811
  /** 스토어 공개 설정 — 이름·고객센터·비회원 주문 허용 여부 */
@@ -854,4 +902,4 @@ getStatus: (paymentId) => http.request("GET", path`/payments/${paymentId}`, paym
854
902
  };
855
903
  }
856
904
  //#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 };
905
+ export { pageSchema as $, createClaimResultSchema as A, paymentStatusSchema as B, publicInquirySchema as C, claimReasonSchema as D, customerInquirySchema as E, confirmPaymentResultSchema as F, productCardSchema as G, requestPaymentRequestSchema as H, createCheckoutRequestSchema as I, productPageSchema as J, productDetailSchema as K, guestInfoSchema as L, PAYMENT_STATUS_VALUES as M, checkoutSessionSchema as N, claimTypeSchema as O, confirmPaymentRequestSchema as P, pageInfoSchema as Q, paymentMethodSchema as R, createInquiryResultSchema as S, customerInquiryCategorySchema as T, shippingAddressInputSchema as U, pgParamsSchema as V, categoryNodeSchema as W, claimStatusSchema as X, productSortSchema as Y, orderItemStatusSchema as Z, memberAddressSchema as _, buildQuery as _t, publicReviewSchema as a, idpAuthorizeRequestSchema as at, wishlistAddResultSchema as b, updateReviewRequestSchema as c, linkIdentityRequestSchema as ct, deliveryTrackingSchema as d, signupRequestSchema as dt, addCartItemRequestSchema as et, myOrderItemSchema as f, socialProviderSchema as ft, memberAddressRequestSchema as g, ApiError as gt, purchaseDecisionResultSchema as h, withdrawalBlockedDetailsSchema as ht, createReviewResultSchema as i, anonymousSessionSchema as it, myClaimSchema as j, createClaimRequestSchema as k, updateReviewResultSchema as l, loginRequestSchema as lt, orderShippingAddressSchema as m, withdrawRequestSchema as mt, storefrontStoreSchema as n, cartSchema as nt, reviewPageSchema as o, idpAuthorizeResponseSchema as ot, myOrderSchema as p, tokenPairSchema as pt, productFacetsSchema as q, createReviewRequestSchema as r, updateCartItemRequestSchema as rt, reviewSummarySchema as s, idpTokenRequestSchema as st, createStorefrontClient as t, cartItemSchema as tt, writableReviewSchema as u, memberIdentitiesSchema as ut, memberSchema as v, toApiError as vt, createCustomerInquiryRequestSchema as w, createInquiryRequestSchema as x, updateProfileRequestSchema as y, unwrapData as yt, paymentParamsSchema 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 };
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as withdrawalBlockedDetailsSchema, S as withdrawRequestSchema, _ as idpTokenRequestSchema, a as AnonymousSession, b as socialProviderSchema, c as LoginRequest, d as TokenPair, f as WithdrawRequest, g as idpAuthorizeResponseSchema, h as idpAuthorizeRequestSchema, i as buildQuery, l as SignupRequest, m as anonymousSessionSchema, n as Query, o as IdpAuthorizeRequest, p as WithdrawalBlockedDetails, r as TokenSource, s as IdpTokenRequest, t as ApiError, u as SocialProvider, v as loginRequestSchema, x as tokenPairSchema, y as signupRequestSchema } from "./http-CqAR0_w4.mjs";
1
+ import { C as signupRequestSchema, D as withdrawalBlockedDetailsSchema, E as withdrawRequestSchema, S as memberIdentitiesSchema, T as tokenPairSchema, _ as idpAuthorizeRequestSchema, a as AnonymousSession, b as linkIdentityRequestSchema, c as LinkIdentityRequest, d as SignupRequest, f as SocialProvider, g as anonymousSessionSchema, h as WithdrawalBlockedDetails, i as buildQuery, l as LoginRequest, m as WithdrawRequest, n as Query, o as IdpAuthorizeRequest, p as TokenPair, r as TokenSource, s as IdpTokenRequest, t as ApiError, u as MemberIdentities, v as idpAuthorizeResponseSchema, w as socialProviderSchema, x as loginRequestSchema, y as idpTokenRequestSchema } from "./http-BbFHVGBf.mjs";
2
2
  import { z } from "zod";
3
3
  //#region src/analytics-ids.d.ts
4
4
  /**
@@ -213,6 +213,37 @@ export declare const productFacetsSchema: z.ZodObject<{
213
213
  }, z.core.$strip>>;
214
214
  }, z.core.$strip>;
215
215
  export type ProductFacets = z.infer<typeof productFacetsSchema>;
216
+ /** `GET /products` 응답 — 상품 카드 페이지와 검색 패싯 */
217
+ export declare const productPageSchema: z.ZodObject<{
218
+ page: z.ZodNumber;
219
+ size: z.ZodNumber;
220
+ totalElements: z.ZodNumber;
221
+ totalPages: z.ZodNumber;
222
+ contents: z.ZodArray<z.ZodObject<{
223
+ productId: z.ZodString;
224
+ name: z.ZodString;
225
+ thumbnailUrl: z.ZodURL;
226
+ salePrice: z.ZodNumber;
227
+ discountedPrice: z.ZodNullable<z.ZodNumber>;
228
+ discountRate: z.ZodNullable<z.ZodNumber>;
229
+ freeShipping: z.ZodBoolean;
230
+ averageRating: z.ZodNumber;
231
+ reviewCount: z.ZodNumber;
232
+ soldOut: z.ZodBoolean;
233
+ }, z.core.$strip>>;
234
+ facets: z.ZodOptional<z.ZodObject<{
235
+ categories: z.ZodOptional<z.ZodArray<z.ZodObject<{
236
+ categoryId: z.ZodString;
237
+ name: z.ZodString;
238
+ count: z.ZodNumber;
239
+ }, z.core.$strip>>>;
240
+ priceRange: z.ZodOptional<z.ZodObject<{
241
+ min: z.ZodNumber;
242
+ max: z.ZodNumber;
243
+ }, z.core.$strip>>;
244
+ }, z.core.$strip>>;
245
+ }, z.core.$strip>;
246
+ export type ProductPage = z.infer<typeof productPageSchema>;
216
247
  //#endregion
217
248
  //#region src/schemas/checkout.d.ts
218
249
  export declare const createCheckoutRequestSchema: z.ZodObject<{
@@ -485,6 +516,12 @@ export declare const createInquiryRequestSchema: z.ZodObject<{
485
516
  secret: z.ZodDefault<z.ZodBoolean>;
486
517
  }, z.core.$strip>;
487
518
  export type CreateInquiryRequest = z.infer<typeof createInquiryRequestSchema>;
519
+ /** `POST /products/{productId}/inquiries` 응답 */
520
+ export declare const createInquiryResultSchema: z.ZodObject<{
521
+ inquiryId: z.ZodString;
522
+ createdAt: z.ZodString;
523
+ }, z.core.$strip>;
524
+ export type CreateInquiryResult = z.infer<typeof createInquiryResultSchema>;
488
525
  //#endregion
489
526
  //#region src/schemas/member.d.ts
490
527
  export declare const memberSchema: z.ZodObject<{
@@ -524,6 +561,12 @@ export declare const memberAddressRequestSchema: z.ZodObject<{
524
561
  isDefault: z.ZodDefault<z.ZodBoolean>;
525
562
  }, z.core.$strip>;
526
563
  export type MemberAddressRequest = z.infer<typeof memberAddressRequestSchema>;
564
+ /** `POST /me/wishlist` 응답 — 이미 찜한 상품이어도 같은 응답이다 */
565
+ export declare const wishlistAddResultSchema: z.ZodObject<{
566
+ productId: z.ZodString;
567
+ wished: z.ZodLiteral<true>;
568
+ }, z.core.$strip>;
569
+ export type WishlistAddResult = z.infer<typeof wishlistAddResultSchema>;
527
570
  //#endregion
528
571
  //#region src/schemas/review.d.ts
529
572
  export declare const publicReviewSchema: z.ZodObject<{
@@ -572,6 +615,38 @@ export declare const updateReviewRequestSchema: z.ZodObject<{
572
615
  images: z.ZodOptional<z.ZodArray<z.ZodURL>>;
573
616
  }, z.core.$strip>;
574
617
  export type UpdateReviewRequest = z.infer<typeof updateReviewRequestSchema>;
618
+ /** `GET /products/{productId}/reviews` 응답 — 리뷰 페이지와 평점 분포 */
619
+ export declare const reviewPageSchema: z.ZodObject<{
620
+ page: z.ZodNumber;
621
+ size: z.ZodNumber;
622
+ totalElements: z.ZodNumber;
623
+ totalPages: z.ZodNumber;
624
+ contents: z.ZodArray<z.ZodObject<{
625
+ reviewId: z.ZodString;
626
+ rating: z.ZodNumber;
627
+ content: z.ZodString;
628
+ images: z.ZodArray<z.ZodURL>;
629
+ optionName: z.ZodNullable<z.ZodString>;
630
+ writerMaskedName: z.ZodString;
631
+ sellerReply: z.ZodNullable<z.ZodObject<{
632
+ content: z.ZodString;
633
+ repliedAt: z.ZodString;
634
+ }, z.core.$strip>>;
635
+ createdAt: z.ZodString;
636
+ }, z.core.$strip>>;
637
+ summary: z.ZodOptional<z.ZodObject<{
638
+ averageRating: z.ZodNumber;
639
+ totalCount: z.ZodNumber;
640
+ distribution: z.ZodRecord<z.ZodString, z.ZodNumber>;
641
+ }, z.core.$strip>>;
642
+ }, z.core.$strip>;
643
+ export type ReviewPage = z.infer<typeof reviewPageSchema>;
644
+ /** `PUT /me/reviews/{reviewId}` 응답 */
645
+ export declare const updateReviewResultSchema: z.ZodObject<{
646
+ reviewId: z.ZodString;
647
+ updatedAt: z.ZodString;
648
+ }, z.core.$strip>;
649
+ export type UpdateReviewResult = z.infer<typeof updateReviewResultSchema>;
575
650
  //#endregion
576
651
  //#region src/session.d.ts
577
652
  /**
@@ -713,6 +788,40 @@ export declare function createStorefrontClient(options: StorefrontClientOptions)
713
788
  }>;
714
789
  /** 구매자 탈퇴 — 로그인 상태(accessToken)에서 비밀번호로 본인 확인. 성공하면 토큰은 모두 무효 */
715
790
  withdraw: (body: WithdrawRequest) => Promise<void>;
791
+ /** 로그인 수단 — 비밀번호 여부와 연결된 소셜 계정(로그인 필요) */
792
+ identities: () => Promise<{
793
+ hasPassword: boolean;
794
+ hasExternalAuth: boolean;
795
+ identities: {
796
+ provider: "kakao" | "naver" | "google";
797
+ email: string | null;
798
+ linkedAt: string;
799
+ }[];
800
+ }>;
801
+ /** 소셜 계정 연결 시작(로그인 필요) — 공급자 로그인 주소를 받는다. 본문은 `idpAuthorize`와 같다 */
802
+ linkIdentityAuthorize: (provider: SocialProvider, body: IdpAuthorizeRequest) => Promise<{
803
+ url: string;
804
+ }>;
805
+ /** 소셜 계정 연결 마무리 — 돌아온 code + codeVerifier로 이 구매자에 연결한다 */
806
+ linkIdentity: (provider: SocialProvider, body: LinkIdentityRequest) => Promise<{
807
+ hasPassword: boolean;
808
+ hasExternalAuth: boolean;
809
+ identities: {
810
+ provider: "kakao" | "naver" | "google";
811
+ email: string | null;
812
+ linkedAt: string;
813
+ }[];
814
+ }>;
815
+ /** 소셜 계정 연결 해제 — 마지막 로그인 수단이면 409 `LAST_LOGIN_METHOD` */
816
+ unlinkIdentity: (provider: SocialProvider) => Promise<{
817
+ hasPassword: boolean;
818
+ hasExternalAuth: boolean;
819
+ identities: {
820
+ provider: "kakao" | "naver" | "google";
821
+ email: string | null;
822
+ linkedAt: string;
823
+ }[];
824
+ }>;
716
825
  };
717
826
  store: {
718
827
  /** 스토어 공개 설정 — 이름·고객센터·비회원 주문 허용 여부 */
@@ -1506,10 +1615,17 @@ export declare const deliveryTrackingSchema: z.ZodObject<{
1506
1615
  }, z.core.$strip>>;
1507
1616
  }, z.core.$strip>;
1508
1617
  export type DeliveryTracking = z.infer<typeof deliveryTrackingSchema>;
1618
+ /** `POST /me/order-items/{orderItemId}/purchase-decision` 응답 */
1619
+ export declare const purchaseDecisionResultSchema: z.ZodObject<{
1620
+ orderItemId: z.ZodString;
1621
+ status: z.ZodLiteral<"PURCHASE_DECIDED">;
1622
+ decidedAt: z.ZodString;
1623
+ }, z.core.$strip>;
1624
+ export type PurchaseDecisionResult = z.infer<typeof purchaseDecisionResultSchema>;
1509
1625
  //#endregion
1510
1626
  //#region src/schemas/store.d.ts
1511
1627
  /**
1512
- * 스토어 공개 설정 — `GET /store`. 스토어프런트가 화면을 그릴 때 읽는 값만 담는다.
1628
+ * 스토어 공개 설정 — `GET /store`. 스토어프론트가 화면을 그릴 때 읽는 값만 담는다.
1513
1629
  */
1514
1630
  export declare const storefrontStoreSchema: z.ZodObject<{
1515
1631
  storeCode: z.ZodString;
@@ -1527,4 +1643,4 @@ export declare const storefrontStoreSchema: z.ZodObject<{
1527
1643
  }, z.core.$strip>;
1528
1644
  export type StorefrontStore = z.infer<typeof storefrontStoreSchema>;
1529
1645
  //#endregion
1530
- export { AnonymousSession, ApiError, IdpAuthorizeRequest, IdpTokenRequest, LoginRequest, type Query, type SessionStorage, SignupRequest, SocialProvider, type StorefrontClient, type StorefrontClientOptions, type StorefrontSession, type StorefrontSessionOptions, TokenPair, type TokenSource, WithdrawRequest, WithdrawalBlockedDetails, anonymousSessionSchema, buildQuery, idpAuthorizeRequestSchema, idpAuthorizeResponseSchema, idpTokenRequestSchema, loginRequestSchema, signupRequestSchema, socialProviderSchema, tokenPairSchema, withdrawRequestSchema, withdrawalBlockedDetailsSchema };
1646
+ export { AnonymousSession, ApiError, IdpAuthorizeRequest, IdpTokenRequest, LinkIdentityRequest, LoginRequest, MemberIdentities, type Query, type SessionStorage, SignupRequest, SocialProvider, type StorefrontClient, type StorefrontClientOptions, type StorefrontSession, type StorefrontSessionOptions, TokenPair, type TokenSource, WithdrawRequest, WithdrawalBlockedDetails, anonymousSessionSchema, buildQuery, idpAuthorizeRequestSchema, idpAuthorizeResponseSchema, idpTokenRequestSchema, linkIdentityRequestSchema, loginRequestSchema, memberIdentitiesSchema, signupRequestSchema, socialProviderSchema, tokenPairSchema, withdrawRequestSchema, withdrawalBlockedDetailsSchema };
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
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
2
  import { t as analyticsIdsFromCookie } from "./analytics-ids-COElZiI3.mjs";
3
- import { $ as idpAuthorizeRequestSchema, A as pageSchema, B as pgParamsSchema, C as claimTypeSchema, D as claimStatusSchema, E as myClaimSchema, F as createCheckoutRequestSchema, G as productDetailSchema, H as shippingAddressInputSchema, I as guestInfoSchema, J as addCartItemRequestSchema, K as productFacetsSchema, L as paymentMethodSchema, M as checkoutSessionSchema, N as confirmPaymentRequestSchema, O as orderItemStatusSchema, P as confirmPaymentResultSchema, Q as anonymousSessionSchema, R as paymentParamsSchema, S as claimReasonSchema, T as createClaimResultSchema, U as categoryNodeSchema, V as requestPaymentRequestSchema, W as productCardSchema, X as cartSchema, Y as cartItemSchema, Z as updateCartItemRequestSchema, _ as createInquiryRequestSchema, a as publicReviewSchema, at as tokenPairSchema, b as customerInquiryCategorySchema, c as writableReviewSchema, ct as ApiError, d as myOrderSchema, dt as unwrapData, et as idpAuthorizeResponseSchema, f as orderShippingAddressSchema, g as updateProfileRequestSchema, h as memberSchema, i as createReviewResultSchema, it as socialProviderSchema, j as PAYMENT_STATUS_VALUES, k as pageInfoSchema, l as deliveryTrackingSchema, lt as buildQuery, m as memberAddressSchema, n as storefrontStoreSchema, nt as loginRequestSchema, o as reviewSummarySchema, ot as withdrawRequestSchema, p as memberAddressRequestSchema, q as productSortSchema, r as createReviewRequestSchema, rt as signupRequestSchema, s as updateReviewRequestSchema, st as withdrawalBlockedDetailsSchema, t as createStorefrontClient, tt as idpTokenRequestSchema, u as myOrderItemSchema, ut as toApiError, v as publicInquirySchema, w as createClaimRequestSchema, x as customerInquirySchema, y as createCustomerInquiryRequestSchema, z as paymentStatusSchema } from "./client-Do9-LG5X.mjs";
3
+ import { $ as pageSchema, A as createClaimResultSchema, B as paymentStatusSchema, C as publicInquirySchema, D as claimReasonSchema, E as customerInquirySchema, F as confirmPaymentResultSchema, G as productCardSchema, H as requestPaymentRequestSchema, I as createCheckoutRequestSchema, J as productPageSchema, K as productDetailSchema, L as guestInfoSchema, M as PAYMENT_STATUS_VALUES, N as checkoutSessionSchema, O as claimTypeSchema, P as confirmPaymentRequestSchema, Q as pageInfoSchema, R as paymentMethodSchema, S as createInquiryResultSchema, T as customerInquiryCategorySchema, U as shippingAddressInputSchema, V as pgParamsSchema, W as categoryNodeSchema, X as claimStatusSchema, Y as productSortSchema, Z as orderItemStatusSchema, _ as memberAddressSchema, _t as buildQuery, a as publicReviewSchema, at as idpAuthorizeRequestSchema, b as wishlistAddResultSchema, c as updateReviewRequestSchema, ct as linkIdentityRequestSchema, d as deliveryTrackingSchema, dt as signupRequestSchema, et as addCartItemRequestSchema, f as myOrderItemSchema, ft as socialProviderSchema, g as memberAddressRequestSchema, gt as ApiError, h as purchaseDecisionResultSchema, ht as withdrawalBlockedDetailsSchema, i as createReviewResultSchema, it as anonymousSessionSchema, j as myClaimSchema, k as createClaimRequestSchema, l as updateReviewResultSchema, lt as loginRequestSchema, m as orderShippingAddressSchema, mt as withdrawRequestSchema, n as storefrontStoreSchema, nt as cartSchema, o as reviewPageSchema, ot as idpAuthorizeResponseSchema, p as myOrderSchema, pt as tokenPairSchema, q as productFacetsSchema, r as createReviewRequestSchema, rt as updateCartItemRequestSchema, s as reviewSummarySchema, st as idpTokenRequestSchema, t as createStorefrontClient, tt as cartItemSchema, u as writableReviewSchema, ut as memberIdentitiesSchema, v as memberSchema, vt as toApiError, w as createCustomerInquiryRequestSchema, x as createInquiryRequestSchema, y as updateProfileRequestSchema, yt as unwrapData, z as paymentParamsSchema } from "./client-B1uXGefY.mjs";
4
4
  //#region src/session.ts
5
5
  /** 세션 키 상수 — SDK가 소유한다. store-sdk와 겹치지 않는 별도 네임스페이스. */
6
6
  const STOREFRONT_SESSION_KEYS = {
@@ -124,4 +124,4 @@ function createStorefrontSession(options) {
124
124
  };
125
125
  }
126
126
  //#endregion
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, idpAuthorizeRequestSchema, idpAuthorizeResponseSchema, idpTokenRequestSchema, 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, socialProviderSchema, storefrontStoreSchema, tokenPairSchema, updateCartItemRequestSchema, updateProfileRequestSchema, updateReviewRequestSchema, withdrawRequestSchema, withdrawalBlockedDetailsSchema, 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, createInquiryResultSchema, createReviewRequestSchema, createReviewResultSchema, createStorefrontClient, createStorefrontSession, customerInquiryCategorySchema, customerInquirySchema, deliveryTrackingSchema, guestInfoSchema, idpAuthorizeRequestSchema, idpAuthorizeResponseSchema, idpTokenRequestSchema, linkIdentityRequestSchema, loginRequestSchema, memberAddressRequestSchema, memberAddressSchema, memberIdentitiesSchema, memberSchema, myClaimSchema, myOrderItemSchema, myOrderSchema, orderItemStatusSchema, orderShippingAddressSchema, pageInfoSchema, pageSchema, paymentMethodSchema, paymentParamsSchema, paymentStatusSchema, pgParamsSchema, productCardSchema, productDetailSchema, productFacetsSchema, productPageSchema, productSortSchema, publicInquirySchema, publicReviewSchema, purchaseDecisionResultSchema, requestPaymentRequestSchema, reviewPageSchema, reviewSummarySchema, shippingAddressInputSchema, signupRequestSchema, socialProviderSchema, storefrontStoreSchema, tokenPairSchema, updateCartItemRequestSchema, updateProfileRequestSchema, updateReviewRequestSchema, updateReviewResultSchema, wishlistAddResultSchema, withdrawRequestSchema, withdrawalBlockedDetailsSchema, writableReviewSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sayren/storefront-sdk",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "main": "./dist/index.mjs",
5
5
  "types": "./dist/index.d.mts",
6
6
  "exports": {
package/src/auth/index.ts CHANGED
@@ -3,6 +3,7 @@ import { ApiError } from "../http";
3
3
  import type {
4
4
  AnonymousSession,
5
5
  LoginRequest,
6
+ MemberIdentities,
6
7
  SignupRequest,
7
8
  SocialProvider,
8
9
  TokenPair,
@@ -14,6 +15,7 @@ export { ApiError } from "../http";
14
15
  export type {
15
16
  AnonymousSession,
16
17
  LoginRequest,
18
+ MemberIdentities,
17
19
  SignupRequest,
18
20
  SocialProvider,
19
21
  TokenPair,
@@ -78,7 +80,7 @@ export interface StorefrontAuthOptions {
78
80
  }
79
81
 
80
82
  /**
81
- * 구매자 인증 — 화면은 스토어프런트가 그리고, 계정 저장과 인증 처리는 sayren이 한다.
83
+ * 구매자 인증 — 화면은 스토어프론트가 그리고, 계정 저장과 인증 처리는 sayren이 한다.
82
84
  * 어느 방식으로 로그인해도 결과는 같은 구매자 토큰(`TokenPair`)이고 `/me/*`·장바구니·주문 API에 그대로 쓴다.
83
85
  *
84
86
  * 토큰 보관은 앱 몫이다. 서버(loader·action)에서 호출하고 httpOnly 쿠키에 두기를 권한다.
@@ -118,7 +120,7 @@ export function createStorefrontAuth(options: StorefrontAuthOptions) {
118
120
  /**
119
121
  * 소셜 로그인 시작 — PKCE(S256)와 state를 만들고 공급자 로그인 주소를 받는다. 반환한 `state`·`codeVerifier`를
120
122
  * 서버 세션에 보관하고 구매자를 `url`로 보낸다. 로그인을 마치면 `redirectUri`로 `?code=&state=`가 붙어 돌아온다.
121
- * `redirectUri`는 스토어프런트 도메인 목록 안이어야 한다
123
+ * `redirectUri`는 스토어프론트 도메인 목록 안이어야 한다
122
124
  */
123
125
  async idp(provider: SocialProvider, options: { redirectUri: string }): Promise<IdpStart> {
124
126
  const state = randomToken(24);
@@ -146,6 +148,51 @@ export function createStorefrontAuth(options: StorefrontAuthOptions) {
146
148
  cartToken: input.cartToken,
147
149
  });
148
150
  },
151
+ /** 로그인 수단 — 비밀번호가 있는지, 어떤 소셜 계정이 연결됐는지 */
152
+ identities(accessToken: string): Promise<MemberIdentities> {
153
+ return client(accessToken).auth.identities();
154
+ },
155
+ /**
156
+ * 소셜 계정 연결 시작 — 로그인한 구매자에 공급자 계정을 붙인다. `idp()`처럼 `state`·`codeVerifier`를 보관하고
157
+ * 구매자를 `url`로 보낸다. 돌아오면 `linkIdpCallback()`으로 마무리한다. 연결은 흐름을 시작한 구매자에게만 된다
158
+ */
159
+ async linkIdp(
160
+ accessToken: string,
161
+ provider: SocialProvider,
162
+ options: { redirectUri: string },
163
+ ): Promise<IdpStart> {
164
+ const state = randomToken(24);
165
+ const codeVerifier = randomToken(32);
166
+ const { url } = await client(accessToken).auth.linkIdentityAuthorize(provider, {
167
+ redirectUri: options.redirectUri,
168
+ codeChallenge: await s256(codeVerifier),
169
+ state,
170
+ });
171
+ return { url, state, codeVerifier };
172
+ },
173
+ /**
174
+ * 소셜 계정 연결 마무리 — state를 비교하고 code를 바꿔 연결한다. 다른 구매자에 이미 연결된 계정이면
175
+ * 409 `IDENTITY_IN_USE`, 같은 공급자의 다른 계정을 이미 연결했으면 409 `PROVIDER_ALREADY_LINKED`
176
+ */
177
+ linkIdpCallback(
178
+ accessToken: string,
179
+ provider: SocialProvider,
180
+ input: Omit<IdpCallbackInput, "cartToken"> & { error?: string | null },
181
+ ): Promise<MemberIdentities> {
182
+ if (input.error) return Promise.reject(new IdpCallbackError(input.error));
183
+ if (!input.state || input.state !== input.expectedState) {
184
+ return Promise.reject(new IdpCallbackError("state_mismatch"));
185
+ }
186
+ if (!input.code) return Promise.reject(new IdpCallbackError("missing_code"));
187
+ return client(accessToken).auth.linkIdentity(provider, {
188
+ code: input.code,
189
+ codeVerifier: input.codeVerifier,
190
+ });
191
+ },
192
+ /** 소셜 계정 연결 해제 — 마지막 로그인 수단이면 409 `LAST_LOGIN_METHOD` */
193
+ unlinkIdp(accessToken: string, provider: SocialProvider): Promise<MemberIdentities> {
194
+ return client(accessToken).auth.unlinkIdentity(provider);
195
+ },
149
196
  /** 토큰 갱신 — refreshToken은 한 번 쓰면 폐기되고 새 쌍이 온다(회전) */
150
197
  refresh(refreshToken: string): Promise<TokenPair> {
151
198
  return client().auth.refresh(refreshToken);
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,7 +31,7 @@ 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,
@@ -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: {
@@ -88,11 +88,11 @@ export type SocialProvider = z.infer<typeof socialProviderSchema>;
88
88
 
89
89
  /** `POST /auth/idp/{provider}/authorize` 본문 — PKCE(S256)와 state는 SDK가 만든다 */
90
90
  export const idpAuthorizeRequestSchema = z.object({
91
- /** 로그인을 마치고 돌아올 스토어프런트 주소. 스토어프런트 도메인 목록 안이어야 한다 */
91
+ /** 로그인을 마치고 돌아올 스토어프론트 주소. 스토어프론트 도메인 목록 안이어야 한다 */
92
92
  redirectUri: z.url(),
93
93
  /** base64url(SHA-256(codeVerifier)) */
94
94
  codeChallenge: z.string().regex(/^[A-Za-z0-9_-]{43}$/),
95
- /** 스토어프런트가 만든 값 — 돌아올 때 그대로 붙어 온다. 세션에 저장해 두고 비교한다 */
95
+ /** 스토어프론트가 만든 값 — 돌아올 때 그대로 붙어 온다. 세션에 저장해 두고 비교한다 */
96
96
  state: z.string().min(16).max(128),
97
97
  });
98
98
  export type IdpAuthorizeRequest = z.infer<typeof idpAuthorizeRequestSchema>;
@@ -110,3 +110,26 @@ export const idpTokenRequestSchema = z.object({
110
110
  cartToken: z.string().optional(),
111
111
  });
112
112
  export type IdpTokenRequest = z.infer<typeof idpTokenRequestSchema>;
113
+
114
+ /** `GET /me/identities` — 구매자의 로그인 수단(비밀번호 여부와 연결된 소셜 계정) */
115
+ export const memberIdentitiesSchema = z.object({
116
+ hasPassword: z.boolean(),
117
+ /** 셀러 자체 회원 연동(구매자 위임)으로 들어온 구매자 — 그 로그인도 로그인 수단으로 센다 */
118
+ hasExternalAuth: z.boolean(),
119
+ identities: z.array(
120
+ z.object({
121
+ provider: socialProviderSchema,
122
+ /** 공급자가 알려 준 이메일(참고값). 없을 수 있다 */
123
+ email: z.string().nullable(),
124
+ linkedAt: z.string(),
125
+ }),
126
+ ),
127
+ });
128
+ export type MemberIdentities = z.infer<typeof memberIdentitiesSchema>;
129
+
130
+ /** `POST /me/identities/{provider}` 본문 — 연결 흐름에서 돌아온 1회용 code와 PKCE verifier */
131
+ export const linkIdentityRequestSchema = z.object({
132
+ code: z.string().min(1),
133
+ codeVerifier: z.string().regex(/^[A-Za-z0-9._~-]{43,128}$/),
134
+ });
135
+ export type LinkIdentityRequest = z.infer<typeof linkIdentityRequestSchema>;
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import type { PageParams } from "./common";
2
+ import { type PageParams, pageSchema } from "./common";
3
3
 
4
4
  export interface CategoryNode {
5
5
  categoryId: string;
@@ -21,9 +21,13 @@ export const productCardSchema = z.object({
21
21
  productId: z.string(),
22
22
  name: z.string(),
23
23
  thumbnailUrl: z.url(),
24
- salePrice: z.number().int(),
25
- discountedPrice: z.number().int().nullable(),
26
- discountRate: z.number().int().nullable(),
24
+ salePrice: z.number().int().describe("판매가. 원(KRW) 단위 정수"),
25
+ discountedPrice: z
26
+ .number()
27
+ .int()
28
+ .nullable()
29
+ .describe("즉시 할인 적용가. 원 단위. 할인이 없으면 null"),
30
+ discountRate: z.number().int().nullable().describe("할인율(%). 할인이 없으면 null"),
27
31
  freeShipping: z.boolean(),
28
32
  averageRating: z.number(),
29
33
  reviewCount: z.number().int(),
@@ -99,3 +103,10 @@ export const productFacetsSchema = z.object({
99
103
  });
100
104
 
101
105
  export type ProductFacets = z.infer<typeof productFacetsSchema>;
106
+
107
+ /** `GET /products` 응답 — 상품 카드 페이지와 검색 패싯 */
108
+ export const productPageSchema = pageSchema(productCardSchema).extend({
109
+ facets: productFacetsSchema.optional(),
110
+ });
111
+
112
+ export type ProductPage = z.infer<typeof productPageSchema>;
@@ -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>;
@@ -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>;
@@ -74,3 +74,12 @@ export const deliveryTrackingSchema = z.object({
74
74
  });
75
75
 
76
76
  export type DeliveryTracking = z.infer<typeof deliveryTrackingSchema>;
77
+
78
+ /** `POST /me/order-items/{orderItemId}/purchase-decision` 응답 */
79
+ export const purchaseDecisionResultSchema = z.object({
80
+ orderItemId: z.string(),
81
+ status: z.literal("PURCHASE_DECIDED"),
82
+ decidedAt: z.string(),
83
+ });
84
+
85
+ export type PurchaseDecisionResult = z.infer<typeof purchaseDecisionResultSchema>;
@@ -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>;
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
 
3
3
  /**
4
- * 스토어 공개 설정 — `GET /store`. 스토어프런트가 화면을 그릴 때 읽는 값만 담는다.
4
+ * 스토어 공개 설정 — `GET /store`. 스토어프론트가 화면을 그릴 때 읽는 값만 담는다.
5
5
  */
6
6
  export const storefrontStoreSchema = z.object({
7
7
  storeCode: z.string(),