@sayren/store-sdk 0.4.0 → 0.6.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.d.mts CHANGED
@@ -976,11 +976,14 @@ export declare const claimSchema: z.ZodObject<{
976
976
  }, z.core.$strip>>;
977
977
  requestedAt: z.ZodString;
978
978
  completedAt: z.ZodNullable<z.ZodString>;
979
+ holdExpiresAt: z.ZodNullable<z.ZodString>;
980
+ holdUsed: z.ZodBoolean;
979
981
  }, z.core.$strip>;
980
982
  export type Claim = z.infer<typeof claimSchema>;
981
983
  export interface ClaimListParams extends PageParams {
982
984
  type?: ClaimType;
983
- status?: ClaimStatus;
985
+ /** 여러 상태를 한 번에 거를 수 있다(처리 대기 목록 등) */
986
+ status?: ClaimStatus | ClaimStatus[];
984
987
  orderItemId?: string;
985
988
  requestedFrom?: string;
986
989
  requestedTo?: string;
@@ -994,17 +997,7 @@ export declare const claimListQuerySchema: z.ZodObject<{
994
997
  EXCHANGE: "EXCHANGE";
995
998
  CANCEL: "CANCEL";
996
999
  }>>;
997
- status: z.ZodOptional<z.ZodEnum<{
998
- REQUESTED: "REQUESTED";
999
- HELD: "HELD";
1000
- COLLECTING: "COLLECTING";
1001
- COLLECTED: "COLLECTED";
1002
- REDELIVERING: "REDELIVERING";
1003
- APPROVED: "APPROVED";
1004
- REJECTED: "REJECTED";
1005
- COMPLETED: "COMPLETED";
1006
- WITHDRAWN: "WITHDRAWN";
1007
- }>>;
1000
+ status: z.ZodOptional<z.ZodString>;
1008
1001
  orderItemId: z.ZodOptional<z.ZodString>;
1009
1002
  requestedFrom: z.ZodOptional<z.ZodString>;
1010
1003
  requestedTo: z.ZodOptional<z.ZodString>;
@@ -1061,6 +1054,8 @@ export declare const claimDetailSchema: z.ZodObject<{
1061
1054
  }, z.core.$strip>>;
1062
1055
  requestedAt: z.ZodString;
1063
1056
  completedAt: z.ZodNullable<z.ZodString>;
1057
+ holdExpiresAt: z.ZodNullable<z.ZodString>;
1058
+ holdUsed: z.ZodBoolean;
1064
1059
  histories: z.ZodOptional<z.ZodArray<z.ZodObject<{
1065
1060
  status: z.ZodEnum<{
1066
1061
  REQUESTED: "REQUESTED";
@@ -1147,7 +1142,7 @@ export declare const customerStatsSchema: z.ZodObject<{
1147
1142
  export declare const customerSummarySchema: z.ZodObject<{
1148
1143
  customerId: z.ZodString;
1149
1144
  name: z.ZodString;
1150
- email: z.ZodString;
1145
+ email: z.ZodNullable<z.ZodString>;
1151
1146
  maskedPhone: z.ZodNullable<z.ZodString>;
1152
1147
  joinedAt: z.ZodString;
1153
1148
  point: z.ZodNumber;
@@ -1171,14 +1166,20 @@ export declare const customerAddressSchema: z.ZodObject<{
1171
1166
  export declare const customerDetailSchema: z.ZodObject<{
1172
1167
  customerId: z.ZodString;
1173
1168
  name: z.ZodString;
1174
- email: z.ZodString;
1169
+ email: z.ZodNullable<z.ZodString>;
1175
1170
  phone: z.ZodNullable<z.ZodString>;
1176
1171
  joinedAt: z.ZodString;
1177
1172
  point: z.ZodNumber;
1178
1173
  marketingAgreed: z.ZodBoolean;
1179
- loginMethods: z.ZodArray<z.ZodEnum<{
1180
- password: "password";
1181
- }>>;
1174
+ loginMethods: z.ZodArray<z.ZodObject<{
1175
+ method: z.ZodEnum<{
1176
+ kakao: "kakao";
1177
+ naver: "naver";
1178
+ google: "google";
1179
+ password: "password";
1180
+ }>;
1181
+ linkedAt: z.ZodString;
1182
+ }, z.core.$strip>>;
1182
1183
  addresses: z.ZodArray<z.ZodObject<{
1183
1184
  addressId: z.ZodString;
1184
1185
  alias: z.ZodString;
@@ -1239,7 +1240,7 @@ export declare const withdrawCustomerRequestSchema: z.ZodObject<{
1239
1240
  memo: z.ZodOptional<z.ZodString>;
1240
1241
  }, z.core.$strip>;
1241
1242
  export type WithdrawCustomerRequest = z.infer<typeof withdrawCustomerRequestSchema>;
1242
- /** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프런트 탈퇴와 같다) */
1243
+ /** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프론트 탈퇴와 같다) */
1243
1244
  export declare const customerWithdrawalBlockedDetailsSchema: z.ZodObject<{
1244
1245
  inProgressOrderItems: z.ZodNumber;
1245
1246
  openClaims: z.ZodNumber;
@@ -1247,6 +1248,81 @@ export declare const customerWithdrawalBlockedDetailsSchema: z.ZodObject<{
1247
1248
  }, z.core.$strip>;
1248
1249
  export type CustomerWithdrawalBlockedDetails = z.infer<typeof customerWithdrawalBlockedDetailsSchema>;
1249
1250
  //#endregion
1251
+ //#region src/schemas/login.d.ts
1252
+ /** 소셜 로그인 공급자 */
1253
+ export declare const loginProviderSchema: z.ZodEnum<{
1254
+ kakao: "kakao";
1255
+ naver: "naver";
1256
+ google: "google";
1257
+ }>;
1258
+ export type LoginProvider = z.infer<typeof loginProviderSchema>;
1259
+ /** 공급자 연결 상태 — 비밀 값은 앞 4자리만 */
1260
+ export declare const loginProviderStatusSchema: z.ZodObject<{
1261
+ provider: z.ZodEnum<{
1262
+ kakao: "kakao";
1263
+ naver: "naver";
1264
+ google: "google";
1265
+ }>;
1266
+ connected: z.ZodBoolean;
1267
+ enabled: z.ZodBoolean;
1268
+ clientIdPrefix: z.ZodNullable<z.ZodString>;
1269
+ secretPrefix: z.ZodNullable<z.ZodString>;
1270
+ lastTestedAt: z.ZodNullable<z.ZodString>;
1271
+ lastTestOk: z.ZodNullable<z.ZodBoolean>;
1272
+ linkedMemberCount: z.ZodNumber;
1273
+ onlyMethodMemberCount: z.ZodNumber;
1274
+ callbackUrl: z.ZodURL;
1275
+ }, z.core.$strip>;
1276
+ export type LoginProviderStatus = z.infer<typeof loginProviderStatusSchema>;
1277
+ /** `GET /v1/store/login-settings` */
1278
+ export declare const loginSettingsSchema: z.ZodObject<{
1279
+ passwordLoginEnabled: z.ZodBoolean;
1280
+ passwordOnlyMemberCount: z.ZodNumber;
1281
+ storefrontOrigins: z.ZodArray<z.ZodString>;
1282
+ providers: z.ZodArray<z.ZodObject<{
1283
+ provider: z.ZodEnum<{
1284
+ kakao: "kakao";
1285
+ naver: "naver";
1286
+ google: "google";
1287
+ }>;
1288
+ connected: z.ZodBoolean;
1289
+ enabled: z.ZodBoolean;
1290
+ clientIdPrefix: z.ZodNullable<z.ZodString>;
1291
+ secretPrefix: z.ZodNullable<z.ZodString>;
1292
+ lastTestedAt: z.ZodNullable<z.ZodString>;
1293
+ lastTestOk: z.ZodNullable<z.ZodBoolean>;
1294
+ linkedMemberCount: z.ZodNumber;
1295
+ onlyMethodMemberCount: z.ZodNumber;
1296
+ callbackUrl: z.ZodURL;
1297
+ }, z.core.$strip>>;
1298
+ }, z.core.$strip>;
1299
+ export type LoginSettings = z.infer<typeof loginSettingsSchema>;
1300
+ /** `PATCH /v1/store/login-settings` */
1301
+ export declare const updateLoginSettingsRequestSchema: z.ZodObject<{
1302
+ passwordLoginEnabled: z.ZodBoolean;
1303
+ }, z.core.$strip>;
1304
+ export type UpdateLoginSettingsRequest = z.infer<typeof updateLoginSettingsRequestSchema>;
1305
+ /** `PUT /v1/store/auth-providers/{provider}` — 저장 전에 연결 테스트를 한다 */
1306
+ export declare const saveLoginProviderRequestSchema: z.ZodObject<{
1307
+ clientId: z.ZodString;
1308
+ clientSecret: z.ZodString;
1309
+ }, z.core.$strip>;
1310
+ export type SaveLoginProviderRequest = z.infer<typeof saveLoginProviderRequestSchema>;
1311
+ /** `PATCH /v1/store/auth-providers/{provider}` */
1312
+ export declare const updateLoginProviderRequestSchema: z.ZodObject<{
1313
+ enabled: z.ZodBoolean;
1314
+ }, z.core.$strip>;
1315
+ /** 연결 테스트 결과 */
1316
+ export declare const loginProviderTestSchema: z.ZodObject<{
1317
+ ok: z.ZodBoolean;
1318
+ code: z.ZodNullable<z.ZodEnum<{
1319
+ INVALID_CLIENT: "INVALID_CLIENT";
1320
+ PROVIDER_UNAVAILABLE: "PROVIDER_UNAVAILABLE";
1321
+ }>>;
1322
+ testedAt: z.ZodString;
1323
+ }, z.core.$strip>;
1324
+ export type LoginProviderTest = z.infer<typeof loginProviderTestSchema>;
1325
+ //#endregion
1250
1326
  //#region src/schemas/misc.d.ts
1251
1327
  export declare const inquirySchema: z.ZodObject<{
1252
1328
  inquiryId: z.ZodString;
@@ -3461,7 +3537,7 @@ export declare function isReservedStoreCode(code: string): boolean;
3461
3537
  export declare const storeCodeSchema: z.ZodString;
3462
3538
  /** `https://shop.example.com`처럼 경로·쿼리 없는 http(s) 오리진인가 */
3463
3539
  export declare function isWebOrigin(value: string): boolean;
3464
- /** 방문 분석을 보낼 수 있는 스토어프런트 오리진 — 스킴·호스트(·포트)만. 서버가 소문자·끝 슬래시 제거로 정규화한다 */
3540
+ /** 방문 분석을 보낼 수 있는 스토어프론트 오리진 — 스킴·호스트(·포트)만. 서버가 소문자·끝 슬래시 제거로 정규화한다 */
3465
3541
  export declare const analyticsOriginSchema: z.ZodString;
3466
3542
  /** 허용 오리진 상한 */
3467
3543
  export declare const MAX_ANALYTICS_ALLOWED_ORIGINS = 20;
@@ -3472,6 +3548,7 @@ export declare const updateStoreRequestSchema: z.ZodObject<{
3472
3548
  customerCenterPhone: z.ZodOptional<z.ZodString>;
3473
3549
  businessHours: z.ZodOptional<z.ZodString>;
3474
3550
  analyticsAllowedOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
3551
+ storefrontOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
3475
3552
  guestCheckoutEnabled: z.ZodOptional<z.ZodBoolean>;
3476
3553
  }, z.core.$strip>;
3477
3554
  export type UpdateStoreRequest = z.infer<typeof updateStoreRequestSchema>;
@@ -3489,6 +3566,7 @@ export declare const storeSchema: z.ZodObject<{
3489
3566
  businessNumber: z.ZodNullable<z.ZodString>;
3490
3567
  customerCenterPhone: z.ZodNullable<z.ZodString>;
3491
3568
  analyticsAllowedOrigins: z.ZodArray<z.ZodString>;
3569
+ storefrontOrigins: z.ZodArray<z.ZodString>;
3492
3570
  guestCheckoutEnabled: z.ZodBoolean;
3493
3571
  memberCount: z.ZodNumber;
3494
3572
  createdAt: z.ZodString;
@@ -4506,6 +4584,8 @@ export declare function createStoreClient(options: StoreClientOptions): {
4506
4584
  } | null;
4507
4585
  requestedAt: string;
4508
4586
  completedAt: string | null;
4587
+ holdExpiresAt: string | null;
4588
+ holdUsed: boolean;
4509
4589
  }[];
4510
4590
  }>;
4511
4591
  get: (claimId: string) => Promise<{
@@ -4532,6 +4612,8 @@ export declare function createStoreClient(options: StoreClientOptions): {
4532
4612
  } | null;
4533
4613
  requestedAt: string;
4534
4614
  completedAt: string | null;
4615
+ holdExpiresAt: string | null;
4616
+ holdUsed: boolean;
4535
4617
  histories?: {
4536
4618
  status: "REQUESTED" | "HELD" | "COLLECTING" | "COLLECTED" | "REDELIVERING" | "APPROVED" | "REJECTED" | "COMPLETED" | "WITHDRAWN";
4537
4619
  actor: "BUYER" | "SELLER" | "SYSTEM";
@@ -4556,6 +4638,34 @@ export declare function createStoreClient(options: StoreClientOptions): {
4556
4638
  holdExpiresAt: string;
4557
4639
  }>;
4558
4640
  releaseHold: (claimId: string) => Promise<void>;
4641
+ /** 교환 완료 — 재배송 중인 교환을 셀러가 명시적으로 끝낸다 */
4642
+ completeExchange: (claimId: string) => Promise<{
4643
+ claimId: string;
4644
+ type: "RETURN" | "EXCHANGE" | "CANCEL";
4645
+ status: "REQUESTED" | "HELD" | "COLLECTING" | "COLLECTED" | "REDELIVERING" | "APPROVED" | "REJECTED" | "COMPLETED" | "WITHDRAWN";
4646
+ orderId: string;
4647
+ orderItemId: string;
4648
+ productName: string;
4649
+ quantity: number;
4650
+ reason: "CHANGE_OF_MIND" | "WRONG_ORDER" | "DEFECTIVE" | "WRONG_DELIVERY" | "DIFFERENT_FROM_PAGE" | "DELAY";
4651
+ reasonDetail: string | null;
4652
+ responsibility: "BUYER" | "SELLER";
4653
+ claimDeliveryFee: number;
4654
+ expectedRefundAmount: number | null;
4655
+ exchangeOption: {
4656
+ optionId: string;
4657
+ optionName: string;
4658
+ } | null;
4659
+ collect: {
4660
+ method: "SELLER_PICKUP" | "BUYER_SEND";
4661
+ carrierCode: string | null;
4662
+ trackingNumber: string | null;
4663
+ } | null;
4664
+ requestedAt: string;
4665
+ completedAt: string | null;
4666
+ holdExpiresAt: string | null;
4667
+ holdUsed: boolean;
4668
+ }>;
4559
4669
  };
4560
4670
  inquiries: {
4561
4671
  list: (params?: PageParams & {
@@ -4605,6 +4715,103 @@ export declare function createStoreClient(options: StoreClientOptions): {
4605
4715
  answer: (inquiryId: string, content: string) => Promise<void>;
4606
4716
  updateAnswer: (inquiryId: string, content: string) => Promise<void>;
4607
4717
  };
4718
+ /**
4719
+ * 구매자 로그인 설정 — 이메일·비밀번호 허용, 소셜 공급자 연결. 비밀 값을 다루므로 콘솔에 로그인한 OWNER만 호출할 수 있다
4720
+ */
4721
+ loginSettings: {
4722
+ get: () => Promise<{
4723
+ passwordLoginEnabled: boolean;
4724
+ passwordOnlyMemberCount: number;
4725
+ storefrontOrigins: string[];
4726
+ providers: {
4727
+ provider: "kakao" | "naver" | "google";
4728
+ connected: boolean;
4729
+ enabled: boolean;
4730
+ clientIdPrefix: string | null;
4731
+ secretPrefix: string | null;
4732
+ lastTestedAt: string | null;
4733
+ lastTestOk: boolean | null;
4734
+ linkedMemberCount: number;
4735
+ onlyMethodMemberCount: number;
4736
+ callbackUrl: string;
4737
+ }[];
4738
+ }>;
4739
+ update: (body: UpdateLoginSettingsRequest) => Promise<{
4740
+ passwordLoginEnabled: boolean;
4741
+ passwordOnlyMemberCount: number;
4742
+ storefrontOrigins: string[];
4743
+ providers: {
4744
+ provider: "kakao" | "naver" | "google";
4745
+ connected: boolean;
4746
+ enabled: boolean;
4747
+ clientIdPrefix: string | null;
4748
+ secretPrefix: string | null;
4749
+ lastTestedAt: string | null;
4750
+ lastTestOk: boolean | null;
4751
+ linkedMemberCount: number;
4752
+ onlyMethodMemberCount: number;
4753
+ callbackUrl: string;
4754
+ }[];
4755
+ }>;
4756
+ /** 키 저장 — 저장 전에 연결 테스트를 하고, 실패하면 422 `LOGIN_PROVIDER_VERIFICATION_FAILED` */
4757
+ saveProvider: (provider: LoginProvider, body: SaveLoginProviderRequest) => Promise<{
4758
+ passwordLoginEnabled: boolean;
4759
+ passwordOnlyMemberCount: number;
4760
+ storefrontOrigins: string[];
4761
+ providers: {
4762
+ provider: "kakao" | "naver" | "google";
4763
+ connected: boolean;
4764
+ enabled: boolean;
4765
+ clientIdPrefix: string | null;
4766
+ secretPrefix: string | null;
4767
+ lastTestedAt: string | null;
4768
+ lastTestOk: boolean | null;
4769
+ linkedMemberCount: number;
4770
+ onlyMethodMemberCount: number;
4771
+ callbackUrl: string;
4772
+ }[];
4773
+ }>;
4774
+ setProviderEnabled: (provider: LoginProvider, enabled: boolean) => Promise<{
4775
+ passwordLoginEnabled: boolean;
4776
+ passwordOnlyMemberCount: number;
4777
+ storefrontOrigins: string[];
4778
+ providers: {
4779
+ provider: "kakao" | "naver" | "google";
4780
+ connected: boolean;
4781
+ enabled: boolean;
4782
+ clientIdPrefix: string | null;
4783
+ secretPrefix: string | null;
4784
+ lastTestedAt: string | null;
4785
+ lastTestOk: boolean | null;
4786
+ linkedMemberCount: number;
4787
+ onlyMethodMemberCount: number;
4788
+ callbackUrl: string;
4789
+ }[];
4790
+ }>;
4791
+ testProvider: (provider: LoginProvider) => Promise<{
4792
+ ok: boolean;
4793
+ code: "INVALID_CLIENT" | "PROVIDER_UNAVAILABLE" | null;
4794
+ testedAt: string;
4795
+ }>;
4796
+ /** 연결 해제 — 키를 지운다. 연결된 구매자 계정은 남는다 */
4797
+ removeProvider: (provider: LoginProvider) => Promise<{
4798
+ passwordLoginEnabled: boolean;
4799
+ passwordOnlyMemberCount: number;
4800
+ storefrontOrigins: string[];
4801
+ providers: {
4802
+ provider: "kakao" | "naver" | "google";
4803
+ connected: boolean;
4804
+ enabled: boolean;
4805
+ clientIdPrefix: string | null;
4806
+ secretPrefix: string | null;
4807
+ lastTestedAt: string | null;
4808
+ lastTestOk: boolean | null;
4809
+ linkedMemberCount: number;
4810
+ onlyMethodMemberCount: number;
4811
+ callbackUrl: string;
4812
+ }[];
4813
+ }>;
4814
+ };
4608
4815
  /** 구매자 관리 — 조회 `customer:r`, 탈퇴 처리 `customer:rw`(콘솔 OWNER·ADMIN) */
4609
4816
  customers: {
4610
4817
  list: (params?: PageParams & Omit<z.input<typeof customerListQuerySchema>, "page" | "size">) => Promise<{
@@ -4615,7 +4822,7 @@ export declare function createStoreClient(options: StoreClientOptions): {
4615
4822
  contents: {
4616
4823
  customerId: string;
4617
4824
  name: string;
4618
- email: string;
4825
+ email: string | null;
4619
4826
  maskedPhone: string | null;
4620
4827
  joinedAt: string;
4621
4828
  point: number;
@@ -4628,12 +4835,15 @@ export declare function createStoreClient(options: StoreClientOptions): {
4628
4835
  get: (customerId: string) => Promise<{
4629
4836
  customerId: string;
4630
4837
  name: string;
4631
- email: string;
4838
+ email: string | null;
4632
4839
  phone: string | null;
4633
4840
  joinedAt: string;
4634
4841
  point: number;
4635
4842
  marketingAgreed: boolean;
4636
- loginMethods: "password"[];
4843
+ loginMethods: {
4844
+ method: "kakao" | "naver" | "google" | "password";
4845
+ linkedAt: string;
4846
+ }[];
4637
4847
  addresses: {
4638
4848
  addressId: string;
4639
4849
  alias: string;
@@ -4810,7 +5020,7 @@ export declare function createStoreClient(options: StoreClientOptions): {
4810
5020
  }>;
4811
5021
  };
4812
5022
  /**
4813
- * 방문 분석 — 스코프 `analytics:r`. 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
5023
+ * 방문 분석 — 스코프 `analytics:r`. 스토어프론트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
4814
5024
  * 집계한 값이다. 집계는 주기적으로 갱신되고 응답 `lastComputedAt`이 마지막 집계 시각이다. 봇 세션은 빠진다.
4815
5025
  * 기간은 양끝 포함 최대 92일이고, 테스트 결제 구매는 `includeTest: "true"`일 때만 포함한다.
4816
5026
  */
@@ -5934,13 +6144,14 @@ export declare function createStoreClient(options: StoreClientOptions): {
5934
6144
  businessNumber: string | null;
5935
6145
  customerCenterPhone: string | null;
5936
6146
  analyticsAllowedOrigins: string[];
6147
+ storefrontOrigins: string[];
5937
6148
  guestCheckoutEnabled: boolean;
5938
6149
  memberCount: number;
5939
6150
  createdAt: string;
5940
6151
  }>;
5941
6152
  /**
5942
6153
  * `PATCH /v1/store` — 스코프 `store:rw`. 바꿀 필드만 보낸다. `analyticsAllowedOrigins`는 방문 분석 수집을 받을
5943
- * 스토어프런트 오리진 목록이다(빈 배열이면 모든 오리진 허용).
6154
+ * 스토어프론트 오리진 목록이다(빈 배열이면 모든 오리진 허용).
5944
6155
  */
5945
6156
  update: (body: UpdateStoreRequest) => Promise<{
5946
6157
  storeId: string;
@@ -5952,6 +6163,7 @@ export declare function createStoreClient(options: StoreClientOptions): {
5952
6163
  businessNumber: string | null;
5953
6164
  customerCenterPhone: string | null;
5954
6165
  analyticsAllowedOrigins: string[];
6166
+ storefrontOrigins: string[];
5955
6167
  guestCheckoutEnabled: boolean;
5956
6168
  memberCount: number;
5957
6169
  createdAt: string;
package/dist/index.mjs CHANGED
@@ -150,7 +150,7 @@ function createHttp(options) {
150
150
  /**
151
151
  * 방문 분석 조회 (관리 API `/v1/analytics/*`, 스코프 `analytics:r`).
152
152
  *
153
- * 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 서버가 날짜(Asia/Seoul)별로 집계한 값이다. 집계는 주기적으로
153
+ * 스토어프론트가 `@sayren/storefront-sdk`로 수집한 이벤트를 서버가 날짜(Asia/Seoul)별로 집계한 값이다. 집계는 주기적으로
154
154
  * 갱신되므로 오늘 값은 `lastComputedAt` 시점까지 반영돼 있다. 봇·자동화 브라우저의 세션은 모든 집계에서 빠진다.
155
155
  */
156
156
  const reportDate$1 = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "날짜 형식은 YYYY-MM-DD 입니다");
@@ -654,12 +654,16 @@ const claimSchema = z.object({
654
654
  trackingNumber: z.string().nullable()
655
655
  }).nullable(),
656
656
  requestedAt: z.string(),
657
- completedAt: z.string().nullable()
657
+ completedAt: z.string().nullable(),
658
+ /** 보류 중이면 자동 해제 시각(ISO 8601), 아니면 null */
659
+ holdExpiresAt: z.string().nullable(),
660
+ /** 보류를 이미 썼는지 — 보류는 클레임당 1회라 해제·만료 뒤에도 true */
661
+ holdUsed: z.boolean()
658
662
  });
659
663
  /** `GET /v1/claims` 쿼리 — OpenAPI 문서용 형태(값은 쿼리 문자열) */
660
664
  const claimListQuerySchema = z.object({
661
665
  type: claimTypeSchema.optional().describe("클레임 유형 필터"),
662
- status: claimStatusSchema.optional().describe("클레임 상태 필터"),
666
+ status: z.string().optional().describe("클레임 상태 필터. 쉼표로 여러 개를 줄 수 있다 (예: `REQUESTED,HELD,COLLECTED`)"),
663
667
  orderItemId: z.string().optional().describe("주문상품 id 필터"),
664
668
  requestedFrom: z.string().optional().describe("요청 시각 조회 시작 (ISO 8601, 포함)"),
665
669
  requestedTo: z.string().optional().describe("요청 시각 조회 끝 (ISO 8601, 포함)"),
@@ -726,7 +730,8 @@ const customerStatsSchema = z.object({
726
730
  const customerSummarySchema = z.object({
727
731
  customerId: z.string(),
728
732
  name: z.string(),
729
- email: z.string(),
733
+ /** 소셜 가입에서 이메일을 받지 못했으면 null */
734
+ email: z.string().nullable(),
730
735
  maskedPhone: z.string().nullable(),
731
736
  joinedAt: z.string(),
732
737
  point: z.number().int(),
@@ -746,12 +751,21 @@ const customerAddressSchema = z.object({
746
751
  const customerDetailSchema = z.object({
747
752
  customerId: z.string(),
748
753
  name: z.string(),
749
- email: z.string(),
754
+ email: z.string().nullable(),
750
755
  phone: z.string().nullable(),
751
756
  joinedAt: z.string(),
752
757
  point: z.number().int(),
753
758
  marketingAgreed: z.boolean(),
754
- loginMethods: z.array(z.enum(["password"])).describe("로그인 방법. 지금은 이메일·비밀번호(`password`)뿐이다"),
759
+ loginMethods: z.array(z.object({
760
+ method: z.enum([
761
+ "password",
762
+ "kakao",
763
+ "naver",
764
+ "google"
765
+ ]),
766
+ /** 소셜 연결 시각. 비밀번호는 가입 시각 */
767
+ linkedAt: z.string()
768
+ })).describe("로그인 방법 — 이메일·비밀번호(`password`)와 연결된 소셜 계정"),
755
769
  addresses: z.array(customerAddressSchema),
756
770
  stats: customerStatsSchema.extend({
757
771
  canceledOrReturnedCount: z.number().int().describe("취소된 주문 상품 + 완료된 반품 수"),
@@ -788,13 +802,60 @@ const withdrawCustomerRequestSchema = z.object({
788
802
  ]).describe("처리 사유 — 구매자 요청·장기 미이용·부정 이용·기타. 감사 로그에 남는다"),
789
803
  memo: z.string().max(200).optional().describe("사유 보충(선택)")
790
804
  });
791
- /** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프런트 탈퇴와 같다) */
805
+ /** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프론트 탈퇴와 같다) */
792
806
  const customerWithdrawalBlockedDetailsSchema = z.object({
793
807
  inProgressOrderItems: z.number().int(),
794
808
  openClaims: z.number().int(),
795
809
  pendingPayments: z.number().int()
796
810
  });
797
811
  //#endregion
812
+ //#region src/schemas/login.ts
813
+ /** 소셜 로그인 공급자 */
814
+ const loginProviderSchema = z.enum([
815
+ "kakao",
816
+ "naver",
817
+ "google"
818
+ ]);
819
+ /** 공급자 연결 상태 — 비밀 값은 앞 4자리만 */
820
+ const loginProviderStatusSchema = z.object({
821
+ provider: loginProviderSchema,
822
+ connected: z.boolean(),
823
+ /** 스토어프론트에서 사용 중인지. 연결 안 됐으면 false */
824
+ enabled: z.boolean(),
825
+ clientIdPrefix: z.string().nullable().describe("클라이언트 ID(카카오 REST API 키) 앞 4자리"),
826
+ secretPrefix: z.string().nullable(),
827
+ lastTestedAt: z.string().nullable(),
828
+ lastTestOk: z.boolean().nullable(),
829
+ linkedMemberCount: z.number().int().describe("이 공급자로 연결된 구매자 수"),
830
+ /** 이 공급자로만 로그인하는 구매자 수 — 연결을 해제하면 로그인할 방법이 없어진다 */
831
+ onlyMethodMemberCount: z.number().int(),
832
+ callbackUrl: z.url().describe("공급자 개발자 콘솔에 등록할 리디렉트 URI")
833
+ });
834
+ /** `GET /v1/store/login-settings` */
835
+ const loginSettingsSchema = z.object({
836
+ passwordLoginEnabled: z.boolean(),
837
+ /** 비밀번호로만 로그인하는 구매자 수 — 이메일·비밀번호를 끄면 이들은 로그인할 수 없다 */
838
+ passwordOnlyMemberCount: z.number().int(),
839
+ storefrontOrigins: z.array(z.string()),
840
+ providers: z.array(loginProviderStatusSchema)
841
+ });
842
+ /** `PATCH /v1/store/login-settings` */
843
+ const updateLoginSettingsRequestSchema = z.object({ passwordLoginEnabled: z.boolean() });
844
+ /** `PUT /v1/store/auth-providers/{provider}` — 저장 전에 연결 테스트를 한다 */
845
+ const saveLoginProviderRequestSchema = z.object({
846
+ clientId: z.string().trim().min(1).max(200),
847
+ clientSecret: z.string().trim().min(1).max(500)
848
+ });
849
+ /** `PATCH /v1/store/auth-providers/{provider}` */
850
+ const updateLoginProviderRequestSchema = z.object({ enabled: z.boolean() });
851
+ /** 연결 테스트 결과 */
852
+ const loginProviderTestSchema = z.object({
853
+ ok: z.boolean(),
854
+ /** 실패 이유 — `INVALID_CLIENT`(키가 틀림)·`PROVIDER_UNAVAILABLE`(공급자 응답 없음) */
855
+ code: z.enum(["INVALID_CLIENT", "PROVIDER_UNAVAILABLE"]).nullable(),
856
+ testedAt: z.string()
857
+ });
858
+ //#endregion
798
859
  //#region src/schemas/misc.ts
799
860
  const inquirySchema = z.object({
800
861
  inquiryId: z.string(),
@@ -1543,10 +1604,10 @@ const productSummarySchema = z.object({
1543
1604
  productId: z.string(),
1544
1605
  name: z.string(),
1545
1606
  status: productStatusSchema,
1546
- salePrice: z.number().int(),
1547
- discountedPrice: z.number().int().nullable(),
1607
+ salePrice: z.number().int().describe("판매가. 원(KRW) 단위 정수"),
1608
+ discountedPrice: z.number().int().nullable().describe("즉시 할인 적용가. 원 단위. 할인이 없으면 null"),
1548
1609
  /** usable variant 재고 합계 (서버 계산) */
1549
- stockQuantity: z.number().int(),
1610
+ stockQuantity: z.number().int().describe("판매 가능한 옵션 재고의 합계. 서버가 계산한다"),
1550
1611
  categoryId: z.string().nullable(),
1551
1612
  thumbnailUrl: z.url().optional(),
1552
1613
  /** optionGroups.length > 0 */
@@ -1683,8 +1744,8 @@ const variantStockSchema = z.object({
1683
1744
  const productCreateRequestSchema = z.object({
1684
1745
  name: z.string().min(1).max(100),
1685
1746
  categoryId: z.string().min(1, "카테고리를 선택해주세요"),
1686
- salePrice: z.number().int().min(10).multipleOf(10, "판매가는 10원 단위여야 합니다 (INVALID_PRICE_UNIT)"),
1687
- originalPrice: z.number().int().optional(),
1747
+ salePrice: z.number().int().min(10).multipleOf(10, "판매가는 10원 단위여야 합니다 (INVALID_PRICE_UNIT)").describe("판매가. 원(KRW) 단위 정수, 최소 10원, 10원 단위"),
1748
+ originalPrice: z.number().int().optional().describe("정가(할인 전 표시 가격). 원 단위"),
1688
1749
  description: z.string().optional(),
1689
1750
  /**
1690
1751
  * 상세설명 에디터(@avarlabs/editor)의 직렬화 상태. 재편집 때 이 값으로 문서를 복원한다.
@@ -1696,11 +1757,11 @@ const productCreateRequestSchema = z.object({
1696
1757
  attributeId: z.string(),
1697
1758
  value: z.string()
1698
1759
  })).optional(),
1699
- deliveryType: deliveryTypeSchema.default("PAID"),
1700
- deliveryFee: z.number().int().default(0),
1701
- conditionalFreeAmount: z.number().int().optional(),
1702
- returnFee: z.number().int().default(0),
1703
- exchangeFee: z.number().int().default(0),
1760
+ deliveryType: deliveryTypeSchema.default("PAID").describe("배송비 유형. FREE 무료, PAID 유료, CONDITIONAL_FREE 조건부 무료"),
1761
+ deliveryFee: z.number().int().default(0).describe("배송비. 원 단위"),
1762
+ conditionalFreeAmount: z.number().int().optional().describe("CONDITIONAL_FREE일 때 무료 배송이 되는 주문 금액. 원 단위"),
1763
+ returnFee: z.number().int().default(0).describe("반품 배송비. 원 단위"),
1764
+ exchangeFee: z.number().int().default(0).describe("교환 배송비. 원 단위"),
1704
1765
  shippingAddressId: z.string().optional(),
1705
1766
  returnAddressId: z.string().optional()
1706
1767
  }).extend(optionModelRequestSchema.shape);
@@ -1816,8 +1877,8 @@ function isWebOrigin(value) {
1816
1877
  return false;
1817
1878
  }
1818
1879
  }
1819
- /** 방문 분석을 보낼 수 있는 스토어프런트 오리진 — 스킴·호스트(·포트)만. 서버가 소문자·끝 슬래시 제거로 정규화한다 */
1820
- const analyticsOriginSchema = z.string().trim().max(255).refine(isWebOrigin, "https://shop.example.com 형식(경로 없이)으로 입력해 주세요").describe("스토어프런트 오리진. 예: `https://shop.example.com`");
1880
+ /** 방문 분석을 보낼 수 있는 스토어프론트 오리진 — 스킴·호스트(·포트)만. 서버가 소문자·끝 슬래시 제거로 정규화한다 */
1881
+ const analyticsOriginSchema = z.string().trim().max(255).refine(isWebOrigin, "https://shop.example.com 형식(경로 없이)으로 입력해 주세요").describe("스토어프론트 오리진. 예: `https://shop.example.com`");
1821
1882
  /** 허용 오리진 상한 */
1822
1883
  const MAX_ANALYTICS_ALLOWED_ORIGINS = 20;
1823
1884
  /** `PATCH /v1/store` 본문 — 바꿀 필드만 보낸다 */
@@ -1826,7 +1887,8 @@ const updateStoreRequestSchema = z.object({
1826
1887
  logoUrl: z.url().optional(),
1827
1888
  customerCenterPhone: z.string().optional(),
1828
1889
  businessHours: z.string().max(100).optional(),
1829
- analyticsAllowedOrigins: z.array(analyticsOriginSchema).max(20).optional().describe("방문 분석 수집을 받을 스토어프런트 오리진(최대 20개). 비우면 모든 오리진에서 받는다. 넣으면 목록에 없는 오리진의 수집 요청은 403 `ORIGIN_NOT_ALLOWED`이고, 페이지 URL이 목록 밖인 이벤트는 버린다"),
1890
+ analyticsAllowedOrigins: z.array(analyticsOriginSchema).max(20).optional().describe("@deprecated `storefrontOrigins`를 쓴다(같은 목록). 방문 분석 수집을 받을 스토어프론트 오리진(최대 20개). 비우면 모든 오리진에서 받는다. 넣으면 목록에 없는 오리진의 수집 요청은 403 `ORIGIN_NOT_ALLOWED`이고, 페이지 URL이 목록 밖인 이벤트는 버린다"),
1891
+ storefrontOrigins: z.array(analyticsOriginSchema).max(20).optional().describe("스토어프론트 도메인(최대 20개) — 소셜 로그인 뒤 돌아갈 주소와 방문 분석 수집을 함께 제한한다. `analyticsAllowedOrigins`와 같은 목록이다(둘 다 주면 이 값이 이긴다)"),
1830
1892
  guestCheckoutEnabled: z.boolean().optional().describe("비회원 주문 허용. false(회원만)면 로그인하지 않은 구매자의 주문서 생성·결제 요청이 403 `GUEST_CHECKOUT_DISABLED`다. 장바구니 담기와 이미 받은 비회원 주문의 조회·취소는 막지 않는다")
1831
1893
  }).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
1832
1894
  const storeSchema = z.object({
@@ -1842,7 +1904,8 @@ const storeSchema = z.object({
1842
1904
  logoUrl: z.url().nullable(),
1843
1905
  businessNumber: z.string().nullable(),
1844
1906
  customerCenterPhone: z.string().nullable(),
1845
- analyticsAllowedOrigins: z.array(z.string()).describe("방문 분석 수집을 받는 스토어프런트 오리진. 비어 있으면 모든 오리진에서 받는다"),
1907
+ analyticsAllowedOrigins: z.array(z.string()).describe("방문 분석 수집을 받는 스토어프론트 오리진. 비어 있으면 모든 오리진에서 받는다"),
1908
+ storefrontOrigins: z.array(z.string()).describe("스토어프론트 도메인 — 소셜 로그인 리디렉트와 방문 분석 수집이 함께 쓴다(`analyticsAllowedOrigins`와 같은 값)"),
1846
1909
  guestCheckoutEnabled: z.boolean().describe("비회원 주문 허용. false면 회원만 주문할 수 있다"),
1847
1910
  memberCount: z.number().int(),
1848
1911
  createdAt: z.string()
@@ -2129,7 +2192,10 @@ function createStoreClient(options) {
2129
2192
  },
2130
2193
  carriers: { list: () => storeHttp.request("GET", "/carriers", z.array(carrierSchema)) },
2131
2194
  claims: {
2132
- list: (params) => storeHttp.request("GET", "/claims", pageSchema(claimSchema), { query: params }),
2195
+ list: (params) => storeHttp.request("GET", "/claims", pageSchema(claimSchema), { query: {
2196
+ ...params,
2197
+ status: Array.isArray(params?.status) ? params.status.join(",") : params?.status
2198
+ } }),
2133
2199
  get: (claimId) => storeHttp.request("GET", path`/claims/${claimId}`, claimDetailSchema),
2134
2200
  approve: (claimId, deductAmount, idempotencyKey) => storeHttp.request("POST", path`/claims/${claimId}/approve`, approveClaimResultSchema, {
2135
2201
  body: deductAmount !== void 0 ? { deductAmount } : {},
@@ -2143,7 +2209,9 @@ function createStoreClient(options) {
2143
2209
  trackingNumber
2144
2210
  } }),
2145
2211
  hold: (claimId, reason) => storeHttp.request("POST", path`/claims/${claimId}/hold`, claimHoldResultSchema, { body: { reason } }),
2146
- releaseHold: (claimId) => storeHttp.requestVoid("DELETE", path`/claims/${claimId}/hold`)
2212
+ releaseHold: (claimId) => storeHttp.requestVoid("DELETE", path`/claims/${claimId}/hold`),
2213
+ /** 교환 완료 — 재배송 중인 교환을 셀러가 명시적으로 끝낸다 */
2214
+ completeExchange: (claimId) => storeHttp.request("POST", path`/claims/${claimId}/complete-exchange`, claimSchema)
2147
2215
  },
2148
2216
  inquiries: {
2149
2217
  list: (params) => storeHttp.request("GET", "/inquiries", pageSchema(inquirySchema), { query: params }),
@@ -2151,6 +2219,19 @@ function createStoreClient(options) {
2151
2219
  answer: (inquiryId, content) => storeHttp.requestVoid("POST", path`/inquiries/${inquiryId}/answer`, { body: { content } }),
2152
2220
  updateAnswer: (inquiryId, content) => storeHttp.requestVoid("PUT", path`/inquiries/${inquiryId}/answer`, { body: { content } })
2153
2221
  },
2222
+ /**
2223
+ * 구매자 로그인 설정 — 이메일·비밀번호 허용, 소셜 공급자 연결. 비밀 값을 다루므로 콘솔에 로그인한 OWNER만 호출할 수 있다
2224
+ */
2225
+ loginSettings: {
2226
+ get: () => storeHttp.request("GET", "/store/login-settings", loginSettingsSchema),
2227
+ update: (body) => storeHttp.request("PATCH", "/store/login-settings", loginSettingsSchema, { body: updateLoginSettingsRequestSchema.parse(body) }),
2228
+ /** 키 저장 — 저장 전에 연결 테스트를 하고, 실패하면 422 `LOGIN_PROVIDER_VERIFICATION_FAILED` */
2229
+ saveProvider: (provider, body) => storeHttp.request("PUT", path`/store/auth-providers/${provider}`, loginSettingsSchema, { body: saveLoginProviderRequestSchema.parse(body) }),
2230
+ setProviderEnabled: (provider, enabled) => storeHttp.request("PATCH", path`/store/auth-providers/${provider}`, loginSettingsSchema, { body: { enabled } }),
2231
+ testProvider: (provider) => storeHttp.request("POST", path`/store/auth-providers/${provider}/test`, loginProviderTestSchema),
2232
+ /** 연결 해제 — 키를 지운다. 연결된 구매자 계정은 남는다 */
2233
+ removeProvider: (provider) => storeHttp.request("DELETE", path`/store/auth-providers/${provider}`, loginSettingsSchema)
2234
+ },
2154
2235
  /** 구매자 관리 — 조회 `customer:r`, 탈퇴 처리 `customer:rw`(콘솔 OWNER·ADMIN) */
2155
2236
  customers: {
2156
2237
  list: (params) => storeHttp.request("GET", "/customers", pageSchema(customerSummarySchema), { query: params }),
@@ -2186,7 +2267,7 @@ function createStoreClient(options) {
2186
2267
  */
2187
2268
  get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, { query: salesReportQuerySchema.parse(params) }) },
2188
2269
  /**
2189
- * 방문 분석 — 스코프 `analytics:r`. 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
2270
+ * 방문 분석 — 스코프 `analytics:r`. 스토어프론트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
2190
2271
  * 집계한 값이다. 집계는 주기적으로 갱신되고 응답 `lastComputedAt`이 마지막 집계 시각이다. 봇 세션은 빠진다.
2191
2272
  * 기간은 양끝 포함 최대 92일이고, 테스트 결제 구매는 `includeTest: "true"`일 때만 포함한다.
2192
2273
  */
@@ -2342,7 +2423,7 @@ get: (params) => storeHttp.request("GET", "/sales-report", salesReportSchema, {
2342
2423
  get: () => storeHttp.request("GET", "/store", storeSchema),
2343
2424
  /**
2344
2425
  * `PATCH /v1/store` — 스코프 `store:rw`. 바꿀 필드만 보낸다. `analyticsAllowedOrigins`는 방문 분석 수집을 받을
2345
- * 스토어프런트 오리진 목록이다(빈 배열이면 모든 오리진 허용).
2426
+ * 스토어프론트 오리진 목록이다(빈 배열이면 모든 오리진 허용).
2346
2427
  */
2347
2428
  update: (body) => storeHttp.request("PATCH", "/store", storeSchema, { body: updateStoreRequestSchema.parse(body) }),
2348
2429
  listMembers: () => storeHttp.request("GET", "/store/members", z.array(storeMemberSchema)),
@@ -2731,4 +2812,4 @@ function createStoreSession(options) {
2731
2812
  };
2732
2813
  }
2733
2814
  //#endregion
2734
- export { ApiError, MAX_ANALYTICS_ALLOWED_ORIGINS, MAX_OPTION_GROUPS, MAX_VALUES_PER_GROUP, MAX_VARIANTS, PAYMENT_ROUTING_EXCLUSION_CODES, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, RESERVED_STORE_CODES, STORE_CODE_PATTERN, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, VARIANT_STOCK_EXCLUSIVE_MESSAGE, WEBHOOK_DEFAULT_TOLERANCE_SEC, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_EVENT_TYPE_HEADER, WEBHOOK_HEADERS, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_USER_AGENT, addressChangeRequestListSchema, addressTypeSchema, analyticsChannelSchema, analyticsFunnelStepSchema, analyticsOriginSchema, analyticsOverviewSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiClientListQuerySchema, apiClientSchema, apiClientSecretRotatedSchema, apiClientStatusSchema, apiClientTypeSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, apiTokenCreateRequestSchema, apiTokenCreatedSchema, apiTokenSchema, approveClaimResultSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeTypeSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, clientCredentialsTokenResponseSchema, createPkcePair, createStoreClient, createStoreSession, customerAddressSchema, customerDetailSchema, customerInquiryCategorySchema, customerInquiryListQuerySchema, customerListQuerySchema, customerOrderSchema, customerSortSchema, customerStatsSchema, customerSummarySchema, customerWithdrawalBlockedDetailsSchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, effectivePaymentRoutingModeSchema, eventTypeSchema, exchangeAuthorizationCode, exchangeStoreTokenViaOAuth, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, invitationListQuerySchema, invitationSchema, isReservedStoreCode, isStoreScope, isWebOrigin, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, maskedSecretSchema, myAccountSchema, myStoreSchema, oauthClientRegistrationRequestSchema, oauthClientRegistrationResponseSchema, oauthTokenResponseSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionValueRequestSchema, optionValueSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentRoutingModeSchema, paymentSettingsSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productImageUploadResultSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, refreshUserToken, rejectClaimRequestSchema, reviewListQuerySchema, reviewReportResultSchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, scopeAccessSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCustomerInquirySchema, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, storeCodeSchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeTokenResponseSchema, tossPaymentsCredentialsInputSchema, trackingUpdateResultSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, updateStoreRequestSchema, uploadRequestSchema, uploadTicketSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, userTokenResponseSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookRedeliverFailedResultSchema, webhookRequestSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema, withdrawCustomerRequestSchema };
2815
+ export { ApiError, MAX_ANALYTICS_ALLOWED_ORIGINS, MAX_OPTION_GROUPS, MAX_VALUES_PER_GROUP, MAX_VARIANTS, PAYMENT_ROUTING_EXCLUSION_CODES, PORTONE_CHANNEL_NAME_MAX_LENGTH, PORTONE_MAX_CHANNELS, PORTONE_MIN_CHANNELS, RESERVED_STORE_CODES, STORE_CODE_PATTERN, STORE_ROLE_SCOPES, STORE_SCOPE_RESOURCES, STORE_SESSION_KEYS, TOSS_WIDGET_CLIENT_KEY_PATTERN, TOSS_WIDGET_KEY_MESSAGE, TOSS_WIDGET_SECRET_KEY_PATTERN, VARIANT_STOCK_EXCLUSIVE_MESSAGE, WEBHOOK_DEFAULT_TOLERANCE_SEC, WEBHOOK_DELIVERY_ID_HEADER, WEBHOOK_EVENT_ID_HEADER, WEBHOOK_EVENT_TYPE_HEADER, WEBHOOK_HEADERS, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_USER_AGENT, addressChangeRequestListSchema, addressTypeSchema, analyticsChannelSchema, analyticsFunnelStepSchema, analyticsOriginSchema, analyticsOverviewSchema, analyticsProductRowSchema, analyticsProductSortSchema, analyticsProductsQuerySchema, analyticsProductsSchema, analyticsRangeQuerySchema, analyticsSourceGroupBySchema, analyticsSourceRowSchema, analyticsSourcesQuerySchema, analyticsSourcesSchema, analyticsTotalsSchema, apiClientListQuerySchema, apiClientSchema, apiClientSecretRotatedSchema, apiClientStatusSchema, apiClientTypeSchema, apiLogErrorSchema, apiLogListQuerySchema, apiLogPageSchema, apiLogPrincipalSchema, apiLogPrincipalTypeSchema, apiLogSchema, apiLogStatusFilterSchema, apiLogSummarySchema, apiTokenCreateRequestSchema, apiTokenCreatedSchema, apiTokenSchema, approveClaimResultSchema, buildAuthorizeUrl, buildQuery, bulkResultSchema, cancelBySellerRequestSchema, cancelBySellerResultSchema, carrierSchema, categoryAttributeSchema, categoryCreateRequestSchema, categoryDeleteQuerySchema, categoryDeleteStrategySchema, categoryListQuerySchema, categoryPatchRequestSchema, categoryProductSortSchema, categorySchema, categorySearchResultSchema, categoryTreeNodeSchema, categoryWithPathSchema, changeTypeSchema, claimDetailSchema, claimHoldResultSchema, claimListQuerySchema, claimReasonSchema, claimSchema, claimStatusSchema, claimTypeSchema, claimWebhookEventDataSchema, claimWebhookEventSchema, clientCredentialsTokenResponseSchema, createPkcePair, createStoreClient, createStoreSession, customerAddressSchema, customerDetailSchema, customerInquiryCategorySchema, customerInquiryListQuerySchema, customerListQuerySchema, customerOrderSchema, customerSortSchema, customerStatsSchema, customerSummarySchema, customerWithdrawalBlockedDetailsSchema, deliveryInfoSchema, deliveryMethodSchema, deliveryStatusSchema, deliveryTypeSchema, discountRequestSchema, discountSchema, dispatchRequestSchema, effectivePaymentRoutingModeSchema, eventTypeSchema, exchangeAuthorizationCode, exchangeStoreTokenViaOAuth, holdOrderItemRequestSchema, inquiryListQuerySchema, inquirySchema, inquiryWebhookEventDataSchema, inquiryWebhookEventSchema, invitationListQuerySchema, invitationSchema, isReservedStoreCode, isStoreScope, isWebOrigin, liveGateConditionCodeSchema, liveGateConditionSchema, liveGateErrorDetailsSchema, liveGateSchema, loginProviderSchema, loginProviderStatusSchema, loginProviderTestSchema, loginSettingsSchema, maskedSecretSchema, myAccountSchema, myStoreSchema, oauthClientRegistrationRequestSchema, oauthClientRegistrationResponseSchema, oauthTokenResponseSchema, optionGroupRequestSchema, optionGroupSchema, optionModelRequestSchema, optionModelSchema, optionValueRequestSchema, optionValueSchema, orderItemListQuerySchema, orderItemMemoResultSchema, orderItemPageSchema, orderItemSchema, orderItemStatusSchema, orderListQuerySchema, orderSchema, orderSummaryPageSchema, orderSummarySchema, orderWebhookEventDataSchema, orderWebhookEventSchema, pageInfoSchema, pageQueryShape, pageSchema, paymentAttemptRecordSchema, paymentAttemptStatusSchema, paymentCredentialSetSchema, paymentListQuerySchema, paymentProviderSchema, paymentProviderVerificationSchema, paymentRecordDetailSchema, paymentRecordPageSchema, paymentRecordSchema, paymentRecordStatusSchema, paymentRefundRecordSchema, paymentRoutingModeSchema, paymentSettingsSchema, pgEnvironmentSchema, pgPaymentMethodSchema, pgProviderSchema, pgVerificationResultSchema, portOneChannelSchema, portOneCredentialsInputSchema, productCreateRequestSchema, productImageUploadResultSchema, productListQuerySchema, productOutOfStockWebhookEventDataSchema, productOutOfStockWebhookEventSchema, productPatchRequestSchema, productSchema, productSortSchema, productStatusSchema, productSummarySchema, productVariantRequestSchema, productVariantSchema, purchaseDecisionExtendResultSchema, purchaseDecisionRequestResultSchema, refreshUserToken, rejectClaimRequestSchema, reviewListQuerySchema, reviewReportResultSchema, reviewSchema, reviewSortSchema, reviewWebhookEventDataSchema, reviewWebhookEventSchema, salesReportGroupBySchema, salesReportQuerySchema, salesReportRowSchema, salesReportSchema, salesTotalsSchema, saveLoginProviderRequestSchema, scopeAccessSchema, sellerAddressListQuerySchema, sellerAddressRequestSchema, sellerAddressSchema, sellerCustomerInquirySchema, settlementDetailQuerySchema, settlementDetailSchema, settlementListQuerySchema, settlementStatusSchema, settlementSummarySchema, settlementWithDetailsSchema, shippingAddressSchema, storeCodeSchema, storeMemberRoleUpdatedSchema, storeMemberSchema, storeRoleSchema, storeSchema, storeScopeResourceSchema, storeTokenResponseSchema, tossPaymentsCredentialsInputSchema, trackingUpdateResultSchema, updateLoginProviderRequestSchema, updateLoginSettingsRequestSchema, updatePaymentProviderRequestSchema, updatePaymentSettingsRequestSchema, updateStoreRequestSchema, uploadRequestSchema, uploadTicketSchema, upsertPortOneProviderRequestSchema, upsertTossPaymentsProviderRequestSchema, userTokenResponseSchema, variantStockRequestSchema, variantStockSchema, verifyPaymentProviderRequestSchema, webhookCreatedSchema, webhookDeliveryErrorCodeSchema, webhookDeliveryListQuerySchema, webhookDeliverySchema, webhookDeliveryStatusSchema, webhookEventSchema, webhookRedeliverFailedResultSchema, webhookRequestSchema, webhookSchema, webhookSecretRotatedSchema, webhookStatusSchema, webhookTestRequestSchema, webhookTestResultSchema, withdrawCustomerRequestSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sayren/store-sdk",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "main": "./dist/index.mjs",
5
5
  "types": "./dist/index.d.mts",
6
6
  "exports": {
package/src/client.ts CHANGED
@@ -60,6 +60,15 @@ import {
60
60
  type WithdrawCustomerRequest,
61
61
  withdrawCustomerRequestSchema,
62
62
  } from "./schemas/customer";
63
+ import {
64
+ type LoginProvider,
65
+ loginProviderTestSchema,
66
+ loginSettingsSchema,
67
+ type SaveLoginProviderRequest,
68
+ saveLoginProviderRequestSchema,
69
+ type UpdateLoginSettingsRequest,
70
+ updateLoginSettingsRequestSchema,
71
+ } from "./schemas/login";
63
72
  import {
64
73
  type CustomerInquiryCategory,
65
74
  inquirySchema,
@@ -524,7 +533,12 @@ export function createStoreClient(options: StoreClientOptions) {
524
533
 
525
534
  claims: {
526
535
  list: (params?: ClaimListParams) =>
527
- storeHttp.request("GET", "/claims", pageSchema(claimSchema), { query: params as Query }),
536
+ storeHttp.request("GET", "/claims", pageSchema(claimSchema), {
537
+ query: {
538
+ ...params,
539
+ status: Array.isArray(params?.status) ? params.status.join(",") : params?.status,
540
+ } as Query,
541
+ }),
528
542
  get: (claimId: string) =>
529
543
  storeHttp.request("GET", path`/claims/${claimId}`, claimDetailSchema),
530
544
  approve: (claimId: string, deductAmount?: number, idempotencyKey?: string) =>
@@ -552,6 +566,9 @@ export function createStoreClient(options: StoreClientOptions) {
552
566
  }),
553
567
  releaseHold: (claimId: string) =>
554
568
  storeHttp.requestVoid("DELETE", path`/claims/${claimId}/hold`),
569
+ /** 교환 완료 — 재배송 중인 교환을 셀러가 명시적으로 끝낸다 */
570
+ completeExchange: (claimId: string) =>
571
+ storeHttp.request("POST", path`/claims/${claimId}/complete-exchange`, claimSchema),
555
572
  },
556
573
 
557
574
  inquiries: {
@@ -567,6 +584,35 @@ export function createStoreClient(options: StoreClientOptions) {
567
584
  storeHttp.requestVoid("PUT", path`/inquiries/${inquiryId}/answer`, { body: { content } }),
568
585
  },
569
586
 
587
+ /**
588
+ * 구매자 로그인 설정 — 이메일·비밀번호 허용, 소셜 공급자 연결. 비밀 값을 다루므로 콘솔에 로그인한 OWNER만 호출할 수 있다
589
+ */
590
+ loginSettings: {
591
+ get: () => storeHttp.request("GET", "/store/login-settings", loginSettingsSchema),
592
+ update: (body: UpdateLoginSettingsRequest) =>
593
+ storeHttp.request("PATCH", "/store/login-settings", loginSettingsSchema, {
594
+ body: updateLoginSettingsRequestSchema.parse(body),
595
+ }),
596
+ /** 키 저장 — 저장 전에 연결 테스트를 하고, 실패하면 422 `LOGIN_PROVIDER_VERIFICATION_FAILED` */
597
+ saveProvider: (provider: LoginProvider, body: SaveLoginProviderRequest) =>
598
+ storeHttp.request("PUT", path`/store/auth-providers/${provider}`, loginSettingsSchema, {
599
+ body: saveLoginProviderRequestSchema.parse(body),
600
+ }),
601
+ setProviderEnabled: (provider: LoginProvider, enabled: boolean) =>
602
+ storeHttp.request("PATCH", path`/store/auth-providers/${provider}`, loginSettingsSchema, {
603
+ body: { enabled },
604
+ }),
605
+ testProvider: (provider: LoginProvider) =>
606
+ storeHttp.request(
607
+ "POST",
608
+ path`/store/auth-providers/${provider}/test`,
609
+ loginProviderTestSchema,
610
+ ),
611
+ /** 연결 해제 — 키를 지운다. 연결된 구매자 계정은 남는다 */
612
+ removeProvider: (provider: LoginProvider) =>
613
+ storeHttp.request("DELETE", path`/store/auth-providers/${provider}`, loginSettingsSchema),
614
+ },
615
+
570
616
  /** 구매자 관리 — 조회 `customer:r`, 탈퇴 처리 `customer:rw`(콘솔 OWNER·ADMIN) */
571
617
  customers: {
572
618
  list: (
@@ -653,7 +699,7 @@ export function createStoreClient(options: StoreClientOptions) {
653
699
  },
654
700
 
655
701
  /**
656
- * 방문 분석 — 스코프 `analytics:r`. 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
702
+ * 방문 분석 — 스코프 `analytics:r`. 스토어프론트가 `@sayren/storefront-sdk`로 수집한 이벤트를 Asia/Seoul 날짜별로
657
703
  * 집계한 값이다. 집계는 주기적으로 갱신되고 응답 `lastComputedAt`이 마지막 집계 시각이다. 봇 세션은 빠진다.
658
704
  * 기간은 양끝 포함 최대 92일이고, 테스트 결제 구매는 `includeTest: "true"`일 때만 포함한다.
659
705
  */
@@ -906,7 +952,7 @@ export function createStoreClient(options: StoreClientOptions) {
906
952
  get: () => storeHttp.request("GET", "/store", storeSchema),
907
953
  /**
908
954
  * `PATCH /v1/store` — 스코프 `store:rw`. 바꿀 필드만 보낸다. `analyticsAllowedOrigins`는 방문 분석 수집을 받을
909
- * 스토어프런트 오리진 목록이다(빈 배열이면 모든 오리진 허용).
955
+ * 스토어프론트 오리진 목록이다(빈 배열이면 모든 오리진 허용).
910
956
  */
911
957
  update: (body: UpdateStoreRequest) =>
912
958
  storeHttp.request("PATCH", "/store", storeSchema, {
package/src/index.ts CHANGED
@@ -19,6 +19,7 @@ export * from "./schemas/category";
19
19
  export * from "./schemas/claim";
20
20
  export * from "./schemas/common";
21
21
  export * from "./schemas/customer";
22
+ export * from "./schemas/login";
22
23
  export * from "./schemas/misc";
23
24
  export * from "./schemas/order";
24
25
  export * from "./schemas/payment";
@@ -3,7 +3,7 @@ import { z } from "zod";
3
3
  /**
4
4
  * 방문 분석 조회 (관리 API `/v1/analytics/*`, 스코프 `analytics:r`).
5
5
  *
6
- * 스토어프런트가 `@sayren/storefront-sdk`로 수집한 이벤트를 서버가 날짜(Asia/Seoul)별로 집계한 값이다. 집계는 주기적으로
6
+ * 스토어프론트가 `@sayren/storefront-sdk`로 수집한 이벤트를 서버가 날짜(Asia/Seoul)별로 집계한 값이다. 집계는 주기적으로
7
7
  * 갱신되므로 오늘 값은 `lastComputedAt` 시점까지 반영돼 있다. 봇·자동화 브라우저의 세션은 모든 집계에서 빠진다.
8
8
  */
9
9
 
@@ -53,13 +53,18 @@ export const claimSchema = z.object({
53
53
  .nullable(),
54
54
  requestedAt: z.string(),
55
55
  completedAt: z.string().nullable(),
56
+ /** 보류 중이면 자동 해제 시각(ISO 8601), 아니면 null */
57
+ holdExpiresAt: z.string().nullable(),
58
+ /** 보류를 이미 썼는지 — 보류는 클레임당 1회라 해제·만료 뒤에도 true */
59
+ holdUsed: z.boolean(),
56
60
  });
57
61
 
58
62
  export type Claim = z.infer<typeof claimSchema>;
59
63
 
60
64
  export interface ClaimListParams extends PageParams {
61
65
  type?: ClaimType;
62
- status?: ClaimStatus;
66
+ /** 여러 상태를 한 번에 거를 수 있다(처리 대기 목록 등) */
67
+ status?: ClaimStatus | ClaimStatus[];
63
68
  orderItemId?: string;
64
69
  requestedFrom?: string;
65
70
  requestedTo?: string;
@@ -68,7 +73,10 @@ export interface ClaimListParams extends PageParams {
68
73
  /** `GET /v1/claims` 쿼리 — OpenAPI 문서용 형태(값은 쿼리 문자열) */
69
74
  export const claimListQuerySchema = z.object({
70
75
  type: claimTypeSchema.optional().describe("클레임 유형 필터"),
71
- status: claimStatusSchema.optional().describe("클레임 상태 필터"),
76
+ status: z
77
+ .string()
78
+ .optional()
79
+ .describe("클레임 상태 필터. 쉼표로 여러 개를 줄 수 있다 (예: `REQUESTED,HELD,COLLECTED`)"),
72
80
  orderItemId: z.string().optional().describe("주문상품 id 필터"),
73
81
  requestedFrom: z.string().optional().describe("요청 시각 조회 시작 (ISO 8601, 포함)"),
74
82
  requestedTo: z.string().optional().describe("요청 시각 조회 끝 (ISO 8601, 포함)"),
@@ -37,7 +37,8 @@ export const customerSummarySchema = z
37
37
  .object({
38
38
  customerId: z.string(),
39
39
  name: z.string(),
40
- email: z.string(),
40
+ /** 소셜 가입에서 이메일을 받지 못했으면 null */
41
+ email: z.string().nullable(),
41
42
  maskedPhone: z.string().nullable(),
42
43
  joinedAt: z.string(),
43
44
  point: z.number().int(),
@@ -61,14 +62,20 @@ export const customerAddressSchema = z.object({
61
62
  export const customerDetailSchema = z.object({
62
63
  customerId: z.string(),
63
64
  name: z.string(),
64
- email: z.string(),
65
+ email: z.string().nullable(),
65
66
  phone: z.string().nullable(),
66
67
  joinedAt: z.string(),
67
68
  point: z.number().int(),
68
69
  marketingAgreed: z.boolean(),
69
70
  loginMethods: z
70
- .array(z.enum(["password"]))
71
- .describe("로그인 방법. 지금은 이메일·비밀번호(`password`)뿐이다"),
71
+ .array(
72
+ z.object({
73
+ method: z.enum(["password", "kakao", "naver", "google"]),
74
+ /** 소셜 연결 시각. 비밀번호는 가입 시각 */
75
+ linkedAt: z.string(),
76
+ }),
77
+ )
78
+ .describe("로그인 방법 — 이메일·비밀번호(`password`)와 연결된 소셜 계정"),
72
79
  addresses: z.array(customerAddressSchema),
73
80
  stats: customerStatsSchema.extend({
74
81
  canceledOrReturnedCount: z.number().int().describe("취소된 주문 상품 + 완료된 반품 수"),
@@ -108,7 +115,7 @@ export const withdrawCustomerRequestSchema = z.object({
108
115
  });
109
116
  export type WithdrawCustomerRequest = z.infer<typeof withdrawCustomerRequestSchema>;
110
117
 
111
- /** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프런트 탈퇴와 같다) */
118
+ /** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프론트 탈퇴와 같다) */
112
119
  export const customerWithdrawalBlockedDetailsSchema = z.object({
113
120
  inProgressOrderItems: z.number().int(),
114
121
  openClaims: z.number().int(),
@@ -0,0 +1,59 @@
1
+ import { z } from "zod";
2
+
3
+ /** 소셜 로그인 공급자 */
4
+ export const loginProviderSchema = z.enum(["kakao", "naver", "google"]);
5
+ export type LoginProvider = z.infer<typeof loginProviderSchema>;
6
+
7
+ /** 공급자 연결 상태 — 비밀 값은 앞 4자리만 */
8
+ export const loginProviderStatusSchema = z.object({
9
+ provider: loginProviderSchema,
10
+ connected: z.boolean(),
11
+ /** 스토어프론트에서 사용 중인지. 연결 안 됐으면 false */
12
+ enabled: z.boolean(),
13
+ clientIdPrefix: z.string().nullable().describe("클라이언트 ID(카카오 REST API 키) 앞 4자리"),
14
+ secretPrefix: z.string().nullable(),
15
+ lastTestedAt: z.string().nullable(),
16
+ lastTestOk: z.boolean().nullable(),
17
+ linkedMemberCount: z.number().int().describe("이 공급자로 연결된 구매자 수"),
18
+ /** 이 공급자로만 로그인하는 구매자 수 — 연결을 해제하면 로그인할 방법이 없어진다 */
19
+ onlyMethodMemberCount: z.number().int(),
20
+ callbackUrl: z.url().describe("공급자 개발자 콘솔에 등록할 리디렉트 URI"),
21
+ });
22
+ export type LoginProviderStatus = z.infer<typeof loginProviderStatusSchema>;
23
+
24
+ /** `GET /v1/store/login-settings` */
25
+ export const loginSettingsSchema = z.object({
26
+ passwordLoginEnabled: z.boolean(),
27
+ /** 비밀번호로만 로그인하는 구매자 수 — 이메일·비밀번호를 끄면 이들은 로그인할 수 없다 */
28
+ passwordOnlyMemberCount: z.number().int(),
29
+ storefrontOrigins: z.array(z.string()),
30
+ providers: z.array(loginProviderStatusSchema),
31
+ });
32
+ export type LoginSettings = z.infer<typeof loginSettingsSchema>;
33
+
34
+ /** `PATCH /v1/store/login-settings` */
35
+ export const updateLoginSettingsRequestSchema = z.object({
36
+ passwordLoginEnabled: z.boolean(),
37
+ });
38
+ export type UpdateLoginSettingsRequest = z.infer<typeof updateLoginSettingsRequestSchema>;
39
+
40
+ /** `PUT /v1/store/auth-providers/{provider}` — 저장 전에 연결 테스트를 한다 */
41
+ export const saveLoginProviderRequestSchema = z.object({
42
+ clientId: z.string().trim().min(1).max(200),
43
+ clientSecret: z.string().trim().min(1).max(500),
44
+ });
45
+ export type SaveLoginProviderRequest = z.infer<typeof saveLoginProviderRequestSchema>;
46
+
47
+ /** `PATCH /v1/store/auth-providers/{provider}` */
48
+ export const updateLoginProviderRequestSchema = z.object({
49
+ enabled: z.boolean(),
50
+ });
51
+
52
+ /** 연결 테스트 결과 */
53
+ export const loginProviderTestSchema = z.object({
54
+ ok: z.boolean(),
55
+ /** 실패 이유 — `INVALID_CLIENT`(키가 틀림)·`PROVIDER_UNAVAILABLE`(공급자 응답 없음) */
56
+ code: z.enum(["INVALID_CLIENT", "PROVIDER_UNAVAILABLE"]).nullable(),
57
+ testedAt: z.string(),
58
+ });
59
+ export type LoginProviderTest = z.infer<typeof loginProviderTestSchema>;
@@ -13,10 +13,14 @@ export const productSummarySchema = z.object({
13
13
  productId: z.string(),
14
14
  name: z.string(),
15
15
  status: productStatusSchema,
16
- salePrice: z.number().int(),
17
- discountedPrice: z.number().int().nullable(),
16
+ salePrice: z.number().int().describe("판매가. 원(KRW) 단위 정수"),
17
+ discountedPrice: z
18
+ .number()
19
+ .int()
20
+ .nullable()
21
+ .describe("즉시 할인 적용가. 원 단위. 할인이 없으면 null"),
18
22
  /** usable variant 재고 합계 (서버 계산) */
19
- stockQuantity: z.number().int(),
23
+ stockQuantity: z.number().int().describe("판매 가능한 옵션 재고의 합계. 서버가 계산한다"),
20
24
  categoryId: z.string().nullable(),
21
25
  thumbnailUrl: z.url().optional(),
22
26
  /** optionGroups.length > 0 */
@@ -199,8 +203,9 @@ export const productCreateRequestSchema = z
199
203
  .number()
200
204
  .int()
201
205
  .min(10)
202
- .multipleOf(10, "판매가는 10원 단위여야 합니다 (INVALID_PRICE_UNIT)"),
203
- originalPrice: z.number().int().optional(),
206
+ .multipleOf(10, "판매가는 10원 단위여야 합니다 (INVALID_PRICE_UNIT)")
207
+ .describe("판매가. 원(KRW) 단위 정수, 최소 10원, 10원 단위"),
208
+ originalPrice: z.number().int().optional().describe("정가(할인 전 표시 가격). 원 단위"),
204
209
  description: z.string().optional(),
205
210
  /**
206
211
  * 상세설명 에디터(@avarlabs/editor)의 직렬화 상태. 재편집 때 이 값으로 문서를 복원한다.
@@ -209,11 +214,17 @@ export const productCreateRequestSchema = z
209
214
  descriptionJson: z.string().nullable().optional(),
210
215
  images: z.array(z.url()).min(1).max(10).optional(),
211
216
  attributes: z.array(z.object({ attributeId: z.string(), value: z.string() })).optional(),
212
- deliveryType: deliveryTypeSchema.default("PAID"),
213
- deliveryFee: z.number().int().default(0),
214
- conditionalFreeAmount: z.number().int().optional(),
215
- returnFee: z.number().int().default(0),
216
- exchangeFee: z.number().int().default(0),
217
+ deliveryType: deliveryTypeSchema
218
+ .default("PAID")
219
+ .describe("배송비 유형. FREE 무료, PAID 유료, CONDITIONAL_FREE 조건부 무료"),
220
+ deliveryFee: z.number().int().default(0).describe("배송비. 원 단위"),
221
+ conditionalFreeAmount: z
222
+ .number()
223
+ .int()
224
+ .optional()
225
+ .describe("CONDITIONAL_FREE일 때 무료 배송이 되는 주문 금액. 원 단위"),
226
+ returnFee: z.number().int().default(0).describe("반품 배송비. 원 단위"),
227
+ exchangeFee: z.number().int().default(0).describe("교환 배송비. 원 단위"),
217
228
  shippingAddressId: z.string().optional(),
218
229
  returnAddressId: z.string().optional(),
219
230
  })
@@ -91,13 +91,13 @@ export function isWebOrigin(value: string): boolean {
91
91
  }
92
92
  }
93
93
 
94
- /** 방문 분석을 보낼 수 있는 스토어프런트 오리진 — 스킴·호스트(·포트)만. 서버가 소문자·끝 슬래시 제거로 정규화한다 */
94
+ /** 방문 분석을 보낼 수 있는 스토어프론트 오리진 — 스킴·호스트(·포트)만. 서버가 소문자·끝 슬래시 제거로 정규화한다 */
95
95
  export const analyticsOriginSchema = z
96
96
  .string()
97
97
  .trim()
98
98
  .max(255)
99
99
  .refine(isWebOrigin, "https://shop.example.com 형식(경로 없이)으로 입력해 주세요")
100
- .describe("스토어프런트 오리진. 예: `https://shop.example.com`");
100
+ .describe("스토어프론트 오리진. 예: `https://shop.example.com`");
101
101
 
102
102
  /** 허용 오리진 상한 */
103
103
  export const MAX_ANALYTICS_ALLOWED_ORIGINS = 20;
@@ -114,9 +114,17 @@ export const updateStoreRequestSchema = z
114
114
  .max(MAX_ANALYTICS_ALLOWED_ORIGINS)
115
115
  .optional()
116
116
  .describe(
117
- "방문 분석 수집을 받을 스토어프런트 오리진(최대 20개). 비우면 모든 오리진에서 받는다. " +
117
+ "@deprecated `storefrontOrigins`를 쓴다(같은 목록). 방문 분석 수집을 받을 스토어프론트 오리진(최대 20개). 비우면 모든 오리진에서 받는다. " +
118
118
  "넣으면 목록에 없는 오리진의 수집 요청은 403 `ORIGIN_NOT_ALLOWED`이고, 페이지 URL이 목록 밖인 이벤트는 버린다",
119
119
  ),
120
+ storefrontOrigins: z
121
+ .array(analyticsOriginSchema)
122
+ .max(MAX_ANALYTICS_ALLOWED_ORIGINS)
123
+ .optional()
124
+ .describe(
125
+ "스토어프론트 도메인(최대 20개) — 소셜 로그인 뒤 돌아갈 주소와 방문 분석 수집을 함께 제한한다. " +
126
+ "`analyticsAllowedOrigins`와 같은 목록이다(둘 다 주면 이 값이 이긴다)",
127
+ ),
120
128
  guestCheckoutEnabled: z
121
129
  .boolean()
122
130
  .optional()
@@ -141,7 +149,12 @@ export const storeSchema = z.object({
141
149
  customerCenterPhone: z.string().nullable(),
142
150
  analyticsAllowedOrigins: z
143
151
  .array(z.string())
144
- .describe("방문 분석 수집을 받는 스토어프런트 오리진. 비어 있으면 모든 오리진에서 받는다"),
152
+ .describe("방문 분석 수집을 받는 스토어프론트 오리진. 비어 있으면 모든 오리진에서 받는다"),
153
+ storefrontOrigins: z
154
+ .array(z.string())
155
+ .describe(
156
+ "스토어프론트 도메인 — 소셜 로그인 리디렉트와 방문 분석 수집이 함께 쓴다(`analyticsAllowedOrigins`와 같은 값)",
157
+ ),
145
158
  guestCheckoutEnabled: z.boolean().describe("비회원 주문 허용. false면 회원만 주문할 수 있다"),
146
159
  memberCount: z.number().int(),
147
160
  createdAt: z.string(),