@sayren/store-sdk 0.3.0 → 0.5.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 +403 -3
- package/dist/index.mjs +188 -6
- package/package.json +1 -1
- package/src/client.ts +71 -0
- package/src/index.ts +2 -0
- package/src/schemas/customer.ts +126 -0
- package/src/schemas/login.ts +59 -0
- package/src/schemas/scope.ts +12 -1
- package/src/schemas/store.ts +22 -1
package/dist/index.d.mts
CHANGED
|
@@ -1108,6 +1108,226 @@ export declare const approveClaimResultSchema: z.ZodObject<{
|
|
|
1108
1108
|
}, z.core.$strip>;
|
|
1109
1109
|
export type ApproveClaimResult = z.infer<typeof approveClaimResultSchema>;
|
|
1110
1110
|
//#endregion
|
|
1111
|
+
//#region src/schemas/customer.d.ts
|
|
1112
|
+
/** 구매자 목록 정렬 */
|
|
1113
|
+
export declare const customerSortSchema: z.ZodEnum<{
|
|
1114
|
+
joined_desc: "joined_desc";
|
|
1115
|
+
joined_asc: "joined_asc";
|
|
1116
|
+
total_paid_desc: "total_paid_desc";
|
|
1117
|
+
order_count_desc: "order_count_desc";
|
|
1118
|
+
last_ordered_desc: "last_ordered_desc";
|
|
1119
|
+
}>;
|
|
1120
|
+
export type CustomerSort = z.infer<typeof customerSortSchema>;
|
|
1121
|
+
/** `GET /v1/customers` 쿼리 */
|
|
1122
|
+
export declare const customerListQuerySchema: z.ZodObject<{
|
|
1123
|
+
page: z.ZodOptional<z.ZodString>;
|
|
1124
|
+
size: z.ZodOptional<z.ZodString>;
|
|
1125
|
+
q: z.ZodOptional<z.ZodString>;
|
|
1126
|
+
joinedFrom: z.ZodOptional<z.ZodString>;
|
|
1127
|
+
joinedTo: z.ZodOptional<z.ZodString>;
|
|
1128
|
+
marketing: z.ZodOptional<z.ZodEnum<{
|
|
1129
|
+
agreed: "agreed";
|
|
1130
|
+
declined: "declined";
|
|
1131
|
+
}>>;
|
|
1132
|
+
sort: z.ZodOptional<z.ZodEnum<{
|
|
1133
|
+
joined_desc: "joined_desc";
|
|
1134
|
+
joined_asc: "joined_asc";
|
|
1135
|
+
total_paid_desc: "total_paid_desc";
|
|
1136
|
+
order_count_desc: "order_count_desc";
|
|
1137
|
+
last_ordered_desc: "last_ordered_desc";
|
|
1138
|
+
}>>;
|
|
1139
|
+
}, z.core.$strip>;
|
|
1140
|
+
/** 구매 통계 — 구매 금액은 취소된 주문 상품을 빼고, 완료된 반품은 수량 비율로 뺀 금액이다 */
|
|
1141
|
+
export declare const customerStatsSchema: z.ZodObject<{
|
|
1142
|
+
orderCount: z.ZodNumber;
|
|
1143
|
+
totalPaid: z.ZodNumber;
|
|
1144
|
+
lastOrderedAt: z.ZodNullable<z.ZodString>;
|
|
1145
|
+
}, z.core.$strip>;
|
|
1146
|
+
/** 목록 행 — 휴대폰은 가운데를 가린다(`010-****-1234`) */
|
|
1147
|
+
export declare const customerSummarySchema: z.ZodObject<{
|
|
1148
|
+
customerId: z.ZodString;
|
|
1149
|
+
name: z.ZodString;
|
|
1150
|
+
email: z.ZodNullable<z.ZodString>;
|
|
1151
|
+
maskedPhone: z.ZodNullable<z.ZodString>;
|
|
1152
|
+
joinedAt: z.ZodString;
|
|
1153
|
+
point: z.ZodNumber;
|
|
1154
|
+
marketingAgreed: z.ZodBoolean;
|
|
1155
|
+
orderCount: z.ZodNumber;
|
|
1156
|
+
totalPaid: z.ZodNumber;
|
|
1157
|
+
lastOrderedAt: z.ZodNullable<z.ZodString>;
|
|
1158
|
+
}, z.core.$strip>;
|
|
1159
|
+
export type CustomerSummary = z.infer<typeof customerSummarySchema>;
|
|
1160
|
+
export declare const customerAddressSchema: z.ZodObject<{
|
|
1161
|
+
addressId: z.ZodString;
|
|
1162
|
+
alias: z.ZodString;
|
|
1163
|
+
isDefault: z.ZodBoolean;
|
|
1164
|
+
receiverName: z.ZodString;
|
|
1165
|
+
phone: z.ZodString;
|
|
1166
|
+
zipCode: z.ZodString;
|
|
1167
|
+
address1: z.ZodString;
|
|
1168
|
+
address2: z.ZodNullable<z.ZodString>;
|
|
1169
|
+
}, z.core.$strip>;
|
|
1170
|
+
/** 구매자 상세 — 휴대폰 전체를 보여 준다 */
|
|
1171
|
+
export declare const customerDetailSchema: z.ZodObject<{
|
|
1172
|
+
customerId: z.ZodString;
|
|
1173
|
+
name: z.ZodString;
|
|
1174
|
+
email: z.ZodNullable<z.ZodString>;
|
|
1175
|
+
phone: z.ZodNullable<z.ZodString>;
|
|
1176
|
+
joinedAt: z.ZodString;
|
|
1177
|
+
point: z.ZodNumber;
|
|
1178
|
+
marketingAgreed: z.ZodBoolean;
|
|
1179
|
+
loginMethods: z.ZodArray<z.ZodObject<{
|
|
1180
|
+
method: z.ZodEnum<{
|
|
1181
|
+
kakao: "kakao";
|
|
1182
|
+
naver: "naver";
|
|
1183
|
+
google: "google";
|
|
1184
|
+
password: "password";
|
|
1185
|
+
}>;
|
|
1186
|
+
linkedAt: z.ZodString;
|
|
1187
|
+
}, z.core.$strip>>;
|
|
1188
|
+
addresses: z.ZodArray<z.ZodObject<{
|
|
1189
|
+
addressId: z.ZodString;
|
|
1190
|
+
alias: z.ZodString;
|
|
1191
|
+
isDefault: z.ZodBoolean;
|
|
1192
|
+
receiverName: z.ZodString;
|
|
1193
|
+
phone: z.ZodString;
|
|
1194
|
+
zipCode: z.ZodString;
|
|
1195
|
+
address1: z.ZodString;
|
|
1196
|
+
address2: z.ZodNullable<z.ZodString>;
|
|
1197
|
+
}, z.core.$strip>>;
|
|
1198
|
+
stats: z.ZodObject<{
|
|
1199
|
+
orderCount: z.ZodNumber;
|
|
1200
|
+
totalPaid: z.ZodNumber;
|
|
1201
|
+
lastOrderedAt: z.ZodNullable<z.ZodString>;
|
|
1202
|
+
canceledOrReturnedCount: z.ZodNumber;
|
|
1203
|
+
reviewCount: z.ZodNumber;
|
|
1204
|
+
inquiryCount: z.ZodNumber;
|
|
1205
|
+
}, z.core.$strip>;
|
|
1206
|
+
}, z.core.$strip>;
|
|
1207
|
+
export type CustomerDetail = z.infer<typeof customerDetailSchema>;
|
|
1208
|
+
/** 구매자의 주문 — 전체 기간 */
|
|
1209
|
+
export declare const customerOrderSchema: z.ZodObject<{
|
|
1210
|
+
orderId: z.ZodString;
|
|
1211
|
+
orderedAt: z.ZodString;
|
|
1212
|
+
totalAmount: z.ZodNumber;
|
|
1213
|
+
testPayment: z.ZodBoolean;
|
|
1214
|
+
items: z.ZodArray<z.ZodObject<{
|
|
1215
|
+
orderItemId: z.ZodString;
|
|
1216
|
+
productName: z.ZodString;
|
|
1217
|
+
optionName: z.ZodNullable<z.ZodString>;
|
|
1218
|
+
quantity: z.ZodNumber;
|
|
1219
|
+
status: z.ZodEnum<{
|
|
1220
|
+
PAID: "PAID";
|
|
1221
|
+
PAYMENT_WAITING: "PAYMENT_WAITING";
|
|
1222
|
+
CONFIRMED: "CONFIRMED";
|
|
1223
|
+
DISPATCHED: "DISPATCHED";
|
|
1224
|
+
DELIVERING: "DELIVERING";
|
|
1225
|
+
DELIVERED: "DELIVERED";
|
|
1226
|
+
PURCHASE_DECIDED: "PURCHASE_DECIDED";
|
|
1227
|
+
CANCELED: "CANCELED";
|
|
1228
|
+
}>;
|
|
1229
|
+
claimStatus: z.ZodNullable<z.ZodEnum<{
|
|
1230
|
+
CANCEL_REQUESTED: "CANCEL_REQUESTED";
|
|
1231
|
+
RETURN_REQUESTED: "RETURN_REQUESTED";
|
|
1232
|
+
EXCHANGE_REQUESTED: "EXCHANGE_REQUESTED";
|
|
1233
|
+
}>>;
|
|
1234
|
+
}, z.core.$strip>>;
|
|
1235
|
+
}, z.core.$strip>;
|
|
1236
|
+
export type CustomerOrder = z.infer<typeof customerOrderSchema>;
|
|
1237
|
+
/** `POST /v1/customers/{id}/withdraw` 본문 */
|
|
1238
|
+
export declare const withdrawCustomerRequestSchema: z.ZodObject<{
|
|
1239
|
+
reason: z.ZodEnum<{
|
|
1240
|
+
BUYER_REQUEST: "BUYER_REQUEST";
|
|
1241
|
+
DORMANT: "DORMANT";
|
|
1242
|
+
ABUSE: "ABUSE";
|
|
1243
|
+
OTHER: "OTHER";
|
|
1244
|
+
}>;
|
|
1245
|
+
memo: z.ZodOptional<z.ZodString>;
|
|
1246
|
+
}, z.core.$strip>;
|
|
1247
|
+
export type WithdrawCustomerRequest = z.infer<typeof withdrawCustomerRequestSchema>;
|
|
1248
|
+
/** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프런트 탈퇴와 같다) */
|
|
1249
|
+
export declare const customerWithdrawalBlockedDetailsSchema: z.ZodObject<{
|
|
1250
|
+
inProgressOrderItems: z.ZodNumber;
|
|
1251
|
+
openClaims: z.ZodNumber;
|
|
1252
|
+
pendingPayments: z.ZodNumber;
|
|
1253
|
+
}, z.core.$strip>;
|
|
1254
|
+
export type CustomerWithdrawalBlockedDetails = z.infer<typeof customerWithdrawalBlockedDetailsSchema>;
|
|
1255
|
+
//#endregion
|
|
1256
|
+
//#region src/schemas/login.d.ts
|
|
1257
|
+
/** 소셜 로그인 공급자 */
|
|
1258
|
+
export declare const loginProviderSchema: z.ZodEnum<{
|
|
1259
|
+
kakao: "kakao";
|
|
1260
|
+
naver: "naver";
|
|
1261
|
+
google: "google";
|
|
1262
|
+
}>;
|
|
1263
|
+
export type LoginProvider = z.infer<typeof loginProviderSchema>;
|
|
1264
|
+
/** 공급자 연결 상태 — 비밀 값은 앞 4자리만 */
|
|
1265
|
+
export declare const loginProviderStatusSchema: z.ZodObject<{
|
|
1266
|
+
provider: z.ZodEnum<{
|
|
1267
|
+
kakao: "kakao";
|
|
1268
|
+
naver: "naver";
|
|
1269
|
+
google: "google";
|
|
1270
|
+
}>;
|
|
1271
|
+
connected: z.ZodBoolean;
|
|
1272
|
+
enabled: z.ZodBoolean;
|
|
1273
|
+
clientIdPrefix: z.ZodNullable<z.ZodString>;
|
|
1274
|
+
secretPrefix: z.ZodNullable<z.ZodString>;
|
|
1275
|
+
lastTestedAt: z.ZodNullable<z.ZodString>;
|
|
1276
|
+
lastTestOk: z.ZodNullable<z.ZodBoolean>;
|
|
1277
|
+
linkedMemberCount: z.ZodNumber;
|
|
1278
|
+
onlyMethodMemberCount: z.ZodNumber;
|
|
1279
|
+
callbackUrl: z.ZodURL;
|
|
1280
|
+
}, z.core.$strip>;
|
|
1281
|
+
export type LoginProviderStatus = z.infer<typeof loginProviderStatusSchema>;
|
|
1282
|
+
/** `GET /v1/store/login-settings` */
|
|
1283
|
+
export declare const loginSettingsSchema: z.ZodObject<{
|
|
1284
|
+
passwordLoginEnabled: z.ZodBoolean;
|
|
1285
|
+
passwordOnlyMemberCount: z.ZodNumber;
|
|
1286
|
+
storefrontOrigins: z.ZodArray<z.ZodString>;
|
|
1287
|
+
providers: z.ZodArray<z.ZodObject<{
|
|
1288
|
+
provider: z.ZodEnum<{
|
|
1289
|
+
kakao: "kakao";
|
|
1290
|
+
naver: "naver";
|
|
1291
|
+
google: "google";
|
|
1292
|
+
}>;
|
|
1293
|
+
connected: z.ZodBoolean;
|
|
1294
|
+
enabled: z.ZodBoolean;
|
|
1295
|
+
clientIdPrefix: z.ZodNullable<z.ZodString>;
|
|
1296
|
+
secretPrefix: z.ZodNullable<z.ZodString>;
|
|
1297
|
+
lastTestedAt: z.ZodNullable<z.ZodString>;
|
|
1298
|
+
lastTestOk: z.ZodNullable<z.ZodBoolean>;
|
|
1299
|
+
linkedMemberCount: z.ZodNumber;
|
|
1300
|
+
onlyMethodMemberCount: z.ZodNumber;
|
|
1301
|
+
callbackUrl: z.ZodURL;
|
|
1302
|
+
}, z.core.$strip>>;
|
|
1303
|
+
}, z.core.$strip>;
|
|
1304
|
+
export type LoginSettings = z.infer<typeof loginSettingsSchema>;
|
|
1305
|
+
/** `PATCH /v1/store/login-settings` */
|
|
1306
|
+
export declare const updateLoginSettingsRequestSchema: z.ZodObject<{
|
|
1307
|
+
passwordLoginEnabled: z.ZodBoolean;
|
|
1308
|
+
}, z.core.$strip>;
|
|
1309
|
+
export type UpdateLoginSettingsRequest = z.infer<typeof updateLoginSettingsRequestSchema>;
|
|
1310
|
+
/** `PUT /v1/store/auth-providers/{provider}` — 저장 전에 연결 테스트를 한다 */
|
|
1311
|
+
export declare const saveLoginProviderRequestSchema: z.ZodObject<{
|
|
1312
|
+
clientId: z.ZodString;
|
|
1313
|
+
clientSecret: z.ZodString;
|
|
1314
|
+
}, z.core.$strip>;
|
|
1315
|
+
export type SaveLoginProviderRequest = z.infer<typeof saveLoginProviderRequestSchema>;
|
|
1316
|
+
/** `PATCH /v1/store/auth-providers/{provider}` */
|
|
1317
|
+
export declare const updateLoginProviderRequestSchema: z.ZodObject<{
|
|
1318
|
+
enabled: z.ZodBoolean;
|
|
1319
|
+
}, z.core.$strip>;
|
|
1320
|
+
/** 연결 테스트 결과 */
|
|
1321
|
+
export declare const loginProviderTestSchema: z.ZodObject<{
|
|
1322
|
+
ok: z.ZodBoolean;
|
|
1323
|
+
code: z.ZodNullable<z.ZodEnum<{
|
|
1324
|
+
INVALID_CLIENT: "INVALID_CLIENT";
|
|
1325
|
+
PROVIDER_UNAVAILABLE: "PROVIDER_UNAVAILABLE";
|
|
1326
|
+
}>>;
|
|
1327
|
+
testedAt: z.ZodString;
|
|
1328
|
+
}, z.core.$strip>;
|
|
1329
|
+
export type LoginProviderTest = z.infer<typeof loginProviderTestSchema>;
|
|
1330
|
+
//#endregion
|
|
1111
1331
|
//#region src/schemas/misc.d.ts
|
|
1112
1332
|
export declare const inquirySchema: z.ZodObject<{
|
|
1113
1333
|
inquiryId: z.ZodString;
|
|
@@ -3333,6 +3553,8 @@ export declare const updateStoreRequestSchema: z.ZodObject<{
|
|
|
3333
3553
|
customerCenterPhone: z.ZodOptional<z.ZodString>;
|
|
3334
3554
|
businessHours: z.ZodOptional<z.ZodString>;
|
|
3335
3555
|
analyticsAllowedOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
3556
|
+
storefrontOrigins: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
3557
|
+
guestCheckoutEnabled: z.ZodOptional<z.ZodBoolean>;
|
|
3336
3558
|
}, z.core.$strip>;
|
|
3337
3559
|
export type UpdateStoreRequest = z.infer<typeof updateStoreRequestSchema>;
|
|
3338
3560
|
export declare const storeSchema: z.ZodObject<{
|
|
@@ -3349,6 +3571,8 @@ export declare const storeSchema: z.ZodObject<{
|
|
|
3349
3571
|
businessNumber: z.ZodNullable<z.ZodString>;
|
|
3350
3572
|
customerCenterPhone: z.ZodNullable<z.ZodString>;
|
|
3351
3573
|
analyticsAllowedOrigins: z.ZodArray<z.ZodString>;
|
|
3574
|
+
storefrontOrigins: z.ZodArray<z.ZodString>;
|
|
3575
|
+
guestCheckoutEnabled: z.ZodBoolean;
|
|
3352
3576
|
memberCount: z.ZodNumber;
|
|
3353
3577
|
createdAt: z.ZodString;
|
|
3354
3578
|
}, z.core.$strip>;
|
|
@@ -4464,6 +4688,176 @@ export declare function createStoreClient(options: StoreClientOptions): {
|
|
|
4464
4688
|
answer: (inquiryId: string, content: string) => Promise<void>;
|
|
4465
4689
|
updateAnswer: (inquiryId: string, content: string) => Promise<void>;
|
|
4466
4690
|
};
|
|
4691
|
+
/**
|
|
4692
|
+
* 구매자 로그인 설정 — 이메일·비밀번호 허용, 소셜 공급자 연결. 비밀 값을 다루므로 콘솔에 로그인한 OWNER만 호출할 수 있다
|
|
4693
|
+
*/
|
|
4694
|
+
loginSettings: {
|
|
4695
|
+
get: () => Promise<{
|
|
4696
|
+
passwordLoginEnabled: boolean;
|
|
4697
|
+
passwordOnlyMemberCount: number;
|
|
4698
|
+
storefrontOrigins: string[];
|
|
4699
|
+
providers: {
|
|
4700
|
+
provider: "kakao" | "naver" | "google";
|
|
4701
|
+
connected: boolean;
|
|
4702
|
+
enabled: boolean;
|
|
4703
|
+
clientIdPrefix: string | null;
|
|
4704
|
+
secretPrefix: string | null;
|
|
4705
|
+
lastTestedAt: string | null;
|
|
4706
|
+
lastTestOk: boolean | null;
|
|
4707
|
+
linkedMemberCount: number;
|
|
4708
|
+
onlyMethodMemberCount: number;
|
|
4709
|
+
callbackUrl: string;
|
|
4710
|
+
}[];
|
|
4711
|
+
}>;
|
|
4712
|
+
update: (body: UpdateLoginSettingsRequest) => Promise<{
|
|
4713
|
+
passwordLoginEnabled: boolean;
|
|
4714
|
+
passwordOnlyMemberCount: number;
|
|
4715
|
+
storefrontOrigins: string[];
|
|
4716
|
+
providers: {
|
|
4717
|
+
provider: "kakao" | "naver" | "google";
|
|
4718
|
+
connected: boolean;
|
|
4719
|
+
enabled: boolean;
|
|
4720
|
+
clientIdPrefix: string | null;
|
|
4721
|
+
secretPrefix: string | null;
|
|
4722
|
+
lastTestedAt: string | null;
|
|
4723
|
+
lastTestOk: boolean | null;
|
|
4724
|
+
linkedMemberCount: number;
|
|
4725
|
+
onlyMethodMemberCount: number;
|
|
4726
|
+
callbackUrl: string;
|
|
4727
|
+
}[];
|
|
4728
|
+
}>;
|
|
4729
|
+
/** 키 저장 — 저장 전에 연결 테스트를 하고, 실패하면 422 `LOGIN_PROVIDER_VERIFICATION_FAILED` */
|
|
4730
|
+
saveProvider: (provider: LoginProvider, body: SaveLoginProviderRequest) => Promise<{
|
|
4731
|
+
passwordLoginEnabled: boolean;
|
|
4732
|
+
passwordOnlyMemberCount: number;
|
|
4733
|
+
storefrontOrigins: string[];
|
|
4734
|
+
providers: {
|
|
4735
|
+
provider: "kakao" | "naver" | "google";
|
|
4736
|
+
connected: boolean;
|
|
4737
|
+
enabled: boolean;
|
|
4738
|
+
clientIdPrefix: string | null;
|
|
4739
|
+
secretPrefix: string | null;
|
|
4740
|
+
lastTestedAt: string | null;
|
|
4741
|
+
lastTestOk: boolean | null;
|
|
4742
|
+
linkedMemberCount: number;
|
|
4743
|
+
onlyMethodMemberCount: number;
|
|
4744
|
+
callbackUrl: string;
|
|
4745
|
+
}[];
|
|
4746
|
+
}>;
|
|
4747
|
+
setProviderEnabled: (provider: LoginProvider, enabled: boolean) => Promise<{
|
|
4748
|
+
passwordLoginEnabled: boolean;
|
|
4749
|
+
passwordOnlyMemberCount: number;
|
|
4750
|
+
storefrontOrigins: string[];
|
|
4751
|
+
providers: {
|
|
4752
|
+
provider: "kakao" | "naver" | "google";
|
|
4753
|
+
connected: boolean;
|
|
4754
|
+
enabled: boolean;
|
|
4755
|
+
clientIdPrefix: string | null;
|
|
4756
|
+
secretPrefix: string | null;
|
|
4757
|
+
lastTestedAt: string | null;
|
|
4758
|
+
lastTestOk: boolean | null;
|
|
4759
|
+
linkedMemberCount: number;
|
|
4760
|
+
onlyMethodMemberCount: number;
|
|
4761
|
+
callbackUrl: string;
|
|
4762
|
+
}[];
|
|
4763
|
+
}>;
|
|
4764
|
+
testProvider: (provider: LoginProvider) => Promise<{
|
|
4765
|
+
ok: boolean;
|
|
4766
|
+
code: "INVALID_CLIENT" | "PROVIDER_UNAVAILABLE" | null;
|
|
4767
|
+
testedAt: string;
|
|
4768
|
+
}>;
|
|
4769
|
+
/** 연결 해제 — 키를 지운다. 연결된 구매자 계정은 남는다 */
|
|
4770
|
+
removeProvider: (provider: LoginProvider) => Promise<{
|
|
4771
|
+
passwordLoginEnabled: boolean;
|
|
4772
|
+
passwordOnlyMemberCount: number;
|
|
4773
|
+
storefrontOrigins: string[];
|
|
4774
|
+
providers: {
|
|
4775
|
+
provider: "kakao" | "naver" | "google";
|
|
4776
|
+
connected: boolean;
|
|
4777
|
+
enabled: boolean;
|
|
4778
|
+
clientIdPrefix: string | null;
|
|
4779
|
+
secretPrefix: string | null;
|
|
4780
|
+
lastTestedAt: string | null;
|
|
4781
|
+
lastTestOk: boolean | null;
|
|
4782
|
+
linkedMemberCount: number;
|
|
4783
|
+
onlyMethodMemberCount: number;
|
|
4784
|
+
callbackUrl: string;
|
|
4785
|
+
}[];
|
|
4786
|
+
}>;
|
|
4787
|
+
};
|
|
4788
|
+
/** 구매자 관리 — 조회 `customer:r`, 탈퇴 처리 `customer:rw`(콘솔 OWNER·ADMIN) */
|
|
4789
|
+
customers: {
|
|
4790
|
+
list: (params?: PageParams & Omit<z.input<typeof customerListQuerySchema>, "page" | "size">) => Promise<{
|
|
4791
|
+
page: number;
|
|
4792
|
+
size: number;
|
|
4793
|
+
totalElements: number;
|
|
4794
|
+
totalPages: number;
|
|
4795
|
+
contents: {
|
|
4796
|
+
customerId: string;
|
|
4797
|
+
name: string;
|
|
4798
|
+
email: string | null;
|
|
4799
|
+
maskedPhone: string | null;
|
|
4800
|
+
joinedAt: string;
|
|
4801
|
+
point: number;
|
|
4802
|
+
marketingAgreed: boolean;
|
|
4803
|
+
orderCount: number;
|
|
4804
|
+
totalPaid: number;
|
|
4805
|
+
lastOrderedAt: string | null;
|
|
4806
|
+
}[];
|
|
4807
|
+
}>;
|
|
4808
|
+
get: (customerId: string) => Promise<{
|
|
4809
|
+
customerId: string;
|
|
4810
|
+
name: string;
|
|
4811
|
+
email: string | null;
|
|
4812
|
+
phone: string | null;
|
|
4813
|
+
joinedAt: string;
|
|
4814
|
+
point: number;
|
|
4815
|
+
marketingAgreed: boolean;
|
|
4816
|
+
loginMethods: {
|
|
4817
|
+
method: "kakao" | "naver" | "google" | "password";
|
|
4818
|
+
linkedAt: string;
|
|
4819
|
+
}[];
|
|
4820
|
+
addresses: {
|
|
4821
|
+
addressId: string;
|
|
4822
|
+
alias: string;
|
|
4823
|
+
isDefault: boolean;
|
|
4824
|
+
receiverName: string;
|
|
4825
|
+
phone: string;
|
|
4826
|
+
zipCode: string;
|
|
4827
|
+
address1: string;
|
|
4828
|
+
address2: string | null;
|
|
4829
|
+
}[];
|
|
4830
|
+
stats: {
|
|
4831
|
+
orderCount: number;
|
|
4832
|
+
totalPaid: number;
|
|
4833
|
+
lastOrderedAt: string | null;
|
|
4834
|
+
canceledOrReturnedCount: number;
|
|
4835
|
+
reviewCount: number;
|
|
4836
|
+
inquiryCount: number;
|
|
4837
|
+
};
|
|
4838
|
+
}>;
|
|
4839
|
+
orders: (customerId: string, params?: PageParams) => Promise<{
|
|
4840
|
+
page: number;
|
|
4841
|
+
size: number;
|
|
4842
|
+
totalElements: number;
|
|
4843
|
+
totalPages: number;
|
|
4844
|
+
contents: {
|
|
4845
|
+
orderId: string;
|
|
4846
|
+
orderedAt: string;
|
|
4847
|
+
totalAmount: number;
|
|
4848
|
+
testPayment: boolean;
|
|
4849
|
+
items: {
|
|
4850
|
+
orderItemId: string;
|
|
4851
|
+
productName: string;
|
|
4852
|
+
optionName: string | null;
|
|
4853
|
+
quantity: number;
|
|
4854
|
+
status: "PAID" | "PAYMENT_WAITING" | "CONFIRMED" | "DISPATCHED" | "DELIVERING" | "DELIVERED" | "PURCHASE_DECIDED" | "CANCELED";
|
|
4855
|
+
claimStatus: "CANCEL_REQUESTED" | "RETURN_REQUESTED" | "EXCHANGE_REQUESTED" | null;
|
|
4856
|
+
}[];
|
|
4857
|
+
}[];
|
|
4858
|
+
}>;
|
|
4859
|
+
withdraw: (customerId: string, body: WithdrawCustomerRequest) => Promise<void>;
|
|
4860
|
+
};
|
|
4467
4861
|
customerInquiries: {
|
|
4468
4862
|
list: (params?: PageParams & {
|
|
4469
4863
|
answered?: boolean;
|
|
@@ -5723,6 +6117,8 @@ export declare function createStoreClient(options: StoreClientOptions): {
|
|
|
5723
6117
|
businessNumber: string | null;
|
|
5724
6118
|
customerCenterPhone: string | null;
|
|
5725
6119
|
analyticsAllowedOrigins: string[];
|
|
6120
|
+
storefrontOrigins: string[];
|
|
6121
|
+
guestCheckoutEnabled: boolean;
|
|
5726
6122
|
memberCount: number;
|
|
5727
6123
|
createdAt: string;
|
|
5728
6124
|
}>;
|
|
@@ -5740,6 +6136,8 @@ export declare function createStoreClient(options: StoreClientOptions): {
|
|
|
5740
6136
|
businessNumber: string | null;
|
|
5741
6137
|
customerCenterPhone: string | null;
|
|
5742
6138
|
analyticsAllowedOrigins: string[];
|
|
6139
|
+
storefrontOrigins: string[];
|
|
6140
|
+
guestCheckoutEnabled: boolean;
|
|
5743
6141
|
memberCount: number;
|
|
5744
6142
|
createdAt: string;
|
|
5745
6143
|
}>;
|
|
@@ -5849,6 +6247,7 @@ export declare const STORE_SCOPE_RESOURCES: {
|
|
|
5849
6247
|
readonly webhook: readonly ["r", "rw"];
|
|
5850
6248
|
readonly store: readonly ["r", "rw"];
|
|
5851
6249
|
readonly member: readonly ["r", "rw"];
|
|
6250
|
+
readonly customer: readonly ["r", "rw"];
|
|
5852
6251
|
};
|
|
5853
6252
|
export type StoreScopeResource = keyof typeof STORE_SCOPE_RESOURCES;
|
|
5854
6253
|
export declare const storeScopeResourceSchema: z.ZodEnum<{
|
|
@@ -5863,6 +6262,7 @@ export declare const storeScopeResourceSchema: z.ZodEnum<{
|
|
|
5863
6262
|
webhook: "webhook";
|
|
5864
6263
|
store: "store";
|
|
5865
6264
|
member: "member";
|
|
6265
|
+
customer: "customer";
|
|
5866
6266
|
}>;
|
|
5867
6267
|
/** 카탈로그상 존재하는 스코프 문자열인가 (예: `settlement:rw`는 false) */
|
|
5868
6268
|
export declare function isStoreScope(scope: string): boolean;
|
|
@@ -5872,9 +6272,9 @@ export declare function isStoreScope(scope: string): boolean;
|
|
|
5872
6272
|
* 발급 시 지정한 스코프만 갖는다(발급자 보유 스코프 이내).
|
|
5873
6273
|
*/
|
|
5874
6274
|
export declare const STORE_ROLE_SCOPES: {
|
|
5875
|
-
readonly OWNER: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "settlement:r", "analytics:r", "webhook:rw", "store:rw", "member:rw"];
|
|
5876
|
-
readonly ADMIN: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "analytics:r", "webhook:rw", "store:rw", "member:rw"];
|
|
5877
|
-
readonly STAFF: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw"];
|
|
6275
|
+
readonly OWNER: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "settlement:r", "analytics:r", "webhook:rw", "store:rw", "member:rw", "customer:rw"];
|
|
6276
|
+
readonly ADMIN: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "analytics:r", "webhook:rw", "store:rw", "member:rw", "customer:rw"];
|
|
6277
|
+
readonly STAFF: readonly ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw", "customer:r"];
|
|
5878
6278
|
};
|
|
5879
6279
|
//#endregion
|
|
5880
6280
|
//#region src/schemas/webhook-event.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -698,6 +698,160 @@ const approveClaimResultSchema = z.object({
|
|
|
698
698
|
refundedAt: z.string()
|
|
699
699
|
});
|
|
700
700
|
//#endregion
|
|
701
|
+
//#region src/schemas/customer.ts
|
|
702
|
+
/** 구매자 목록 정렬 */
|
|
703
|
+
const customerSortSchema = z.enum([
|
|
704
|
+
"joined_desc",
|
|
705
|
+
"joined_asc",
|
|
706
|
+
"total_paid_desc",
|
|
707
|
+
"order_count_desc",
|
|
708
|
+
"last_ordered_desc"
|
|
709
|
+
]).describe("정렬. `joined_desc`(기본, 최근 가입순)·`joined_asc`·`total_paid_desc`(구매 금액순)·`order_count_desc`(주문 수순)·`last_ordered_desc`(최근 주문순)");
|
|
710
|
+
/** `GET /v1/customers` 쿼리 */
|
|
711
|
+
const customerListQuerySchema = z.object({
|
|
712
|
+
q: z.string().optional().describe("검색어 — 이름·이메일(포함). 숫자 4자리면 휴대폰 뒤 4자리로도 찾는다"),
|
|
713
|
+
joinedFrom: z.string().optional().describe("가입일 시작(YYYY-MM-DD, KST, 포함)"),
|
|
714
|
+
joinedTo: z.string().optional().describe("가입일 끝(YYYY-MM-DD, KST, 포함)"),
|
|
715
|
+
marketing: z.enum(["agreed", "declined"]).optional().describe("마케팅 수신 동의 필터. 생략하면 전체"),
|
|
716
|
+
sort: customerSortSchema.optional(),
|
|
717
|
+
...pageQueryShape()
|
|
718
|
+
});
|
|
719
|
+
/** 구매 통계 — 구매 금액은 취소된 주문 상품을 빼고, 완료된 반품은 수량 비율로 뺀 금액이다 */
|
|
720
|
+
const customerStatsSchema = z.object({
|
|
721
|
+
orderCount: z.number().int().describe("주문 수(취소 포함)"),
|
|
722
|
+
totalPaid: z.number().int().describe("구매 금액(원) — 취소·완료된 반품 제외"),
|
|
723
|
+
lastOrderedAt: z.string().nullable().describe("최근 주문 시각")
|
|
724
|
+
});
|
|
725
|
+
/** 목록 행 — 휴대폰은 가운데를 가린다(`010-****-1234`) */
|
|
726
|
+
const customerSummarySchema = z.object({
|
|
727
|
+
customerId: z.string(),
|
|
728
|
+
name: z.string(),
|
|
729
|
+
/** 소셜 가입에서 이메일을 받지 못했으면 null */
|
|
730
|
+
email: z.string().nullable(),
|
|
731
|
+
maskedPhone: z.string().nullable(),
|
|
732
|
+
joinedAt: z.string(),
|
|
733
|
+
point: z.number().int(),
|
|
734
|
+
marketingAgreed: z.boolean()
|
|
735
|
+
}).extend(customerStatsSchema.shape);
|
|
736
|
+
const customerAddressSchema = z.object({
|
|
737
|
+
addressId: z.string(),
|
|
738
|
+
alias: z.string(),
|
|
739
|
+
isDefault: z.boolean(),
|
|
740
|
+
receiverName: z.string(),
|
|
741
|
+
phone: z.string(),
|
|
742
|
+
zipCode: z.string(),
|
|
743
|
+
address1: z.string(),
|
|
744
|
+
address2: z.string().nullable()
|
|
745
|
+
});
|
|
746
|
+
/** 구매자 상세 — 휴대폰 전체를 보여 준다 */
|
|
747
|
+
const customerDetailSchema = z.object({
|
|
748
|
+
customerId: z.string(),
|
|
749
|
+
name: z.string(),
|
|
750
|
+
email: z.string().nullable(),
|
|
751
|
+
phone: z.string().nullable(),
|
|
752
|
+
joinedAt: z.string(),
|
|
753
|
+
point: z.number().int(),
|
|
754
|
+
marketingAgreed: z.boolean(),
|
|
755
|
+
loginMethods: z.array(z.object({
|
|
756
|
+
method: z.enum([
|
|
757
|
+
"password",
|
|
758
|
+
"kakao",
|
|
759
|
+
"naver",
|
|
760
|
+
"google"
|
|
761
|
+
]),
|
|
762
|
+
/** 소셜 연결 시각. 비밀번호는 가입 시각 */
|
|
763
|
+
linkedAt: z.string()
|
|
764
|
+
})).describe("로그인 방법 — 이메일·비밀번호(`password`)와 연결된 소셜 계정"),
|
|
765
|
+
addresses: z.array(customerAddressSchema),
|
|
766
|
+
stats: customerStatsSchema.extend({
|
|
767
|
+
canceledOrReturnedCount: z.number().int().describe("취소된 주문 상품 + 완료된 반품 수"),
|
|
768
|
+
reviewCount: z.number().int(),
|
|
769
|
+
inquiryCount: z.number().int().describe("상품 문의 + 1:1 문의")
|
|
770
|
+
})
|
|
771
|
+
});
|
|
772
|
+
/** 구매자의 주문 — 전체 기간 */
|
|
773
|
+
const customerOrderSchema = z.object({
|
|
774
|
+
orderId: z.string(),
|
|
775
|
+
orderedAt: z.string(),
|
|
776
|
+
totalAmount: z.number().int().describe("결제 금액"),
|
|
777
|
+
testPayment: z.boolean(),
|
|
778
|
+
items: z.array(z.object({
|
|
779
|
+
orderItemId: z.string(),
|
|
780
|
+
productName: z.string(),
|
|
781
|
+
optionName: z.string().nullable(),
|
|
782
|
+
quantity: z.number().int(),
|
|
783
|
+
status: orderItemStatusSchema,
|
|
784
|
+
claimStatus: z.enum([
|
|
785
|
+
"CANCEL_REQUESTED",
|
|
786
|
+
"RETURN_REQUESTED",
|
|
787
|
+
"EXCHANGE_REQUESTED"
|
|
788
|
+
]).nullable()
|
|
789
|
+
}))
|
|
790
|
+
});
|
|
791
|
+
/** `POST /v1/customers/{id}/withdraw` 본문 */
|
|
792
|
+
const withdrawCustomerRequestSchema = z.object({
|
|
793
|
+
reason: z.enum([
|
|
794
|
+
"BUYER_REQUEST",
|
|
795
|
+
"DORMANT",
|
|
796
|
+
"ABUSE",
|
|
797
|
+
"OTHER"
|
|
798
|
+
]).describe("처리 사유 — 구매자 요청·장기 미이용·부정 이용·기타. 감사 로그에 남는다"),
|
|
799
|
+
memo: z.string().max(200).optional().describe("사유 보충(선택)")
|
|
800
|
+
});
|
|
801
|
+
/** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프런트 탈퇴와 같다) */
|
|
802
|
+
const customerWithdrawalBlockedDetailsSchema = z.object({
|
|
803
|
+
inProgressOrderItems: z.number().int(),
|
|
804
|
+
openClaims: z.number().int(),
|
|
805
|
+
pendingPayments: z.number().int()
|
|
806
|
+
});
|
|
807
|
+
//#endregion
|
|
808
|
+
//#region src/schemas/login.ts
|
|
809
|
+
/** 소셜 로그인 공급자 */
|
|
810
|
+
const loginProviderSchema = z.enum([
|
|
811
|
+
"kakao",
|
|
812
|
+
"naver",
|
|
813
|
+
"google"
|
|
814
|
+
]);
|
|
815
|
+
/** 공급자 연결 상태 — 비밀 값은 앞 4자리만 */
|
|
816
|
+
const loginProviderStatusSchema = z.object({
|
|
817
|
+
provider: loginProviderSchema,
|
|
818
|
+
connected: z.boolean(),
|
|
819
|
+
/** 스토어프런트에서 사용 중인지. 연결 안 됐으면 false */
|
|
820
|
+
enabled: z.boolean(),
|
|
821
|
+
clientIdPrefix: z.string().nullable().describe("클라이언트 ID(카카오 REST API 키) 앞 4자리"),
|
|
822
|
+
secretPrefix: z.string().nullable(),
|
|
823
|
+
lastTestedAt: z.string().nullable(),
|
|
824
|
+
lastTestOk: z.boolean().nullable(),
|
|
825
|
+
linkedMemberCount: z.number().int().describe("이 공급자로 연결된 구매자 수"),
|
|
826
|
+
/** 이 공급자로만 로그인하는 구매자 수 — 연결을 해제하면 로그인할 방법이 없어진다 */
|
|
827
|
+
onlyMethodMemberCount: z.number().int(),
|
|
828
|
+
callbackUrl: z.url().describe("공급자 개발자 콘솔에 등록할 리디렉트 URI")
|
|
829
|
+
});
|
|
830
|
+
/** `GET /v1/store/login-settings` */
|
|
831
|
+
const loginSettingsSchema = z.object({
|
|
832
|
+
passwordLoginEnabled: z.boolean(),
|
|
833
|
+
/** 비밀번호로만 로그인하는 구매자 수 — 이메일·비밀번호를 끄면 이들은 로그인할 수 없다 */
|
|
834
|
+
passwordOnlyMemberCount: z.number().int(),
|
|
835
|
+
storefrontOrigins: z.array(z.string()),
|
|
836
|
+
providers: z.array(loginProviderStatusSchema)
|
|
837
|
+
});
|
|
838
|
+
/** `PATCH /v1/store/login-settings` */
|
|
839
|
+
const updateLoginSettingsRequestSchema = z.object({ passwordLoginEnabled: z.boolean() });
|
|
840
|
+
/** `PUT /v1/store/auth-providers/{provider}` — 저장 전에 연결 테스트를 한다 */
|
|
841
|
+
const saveLoginProviderRequestSchema = z.object({
|
|
842
|
+
clientId: z.string().trim().min(1).max(200),
|
|
843
|
+
clientSecret: z.string().trim().min(1).max(500)
|
|
844
|
+
});
|
|
845
|
+
/** `PATCH /v1/store/auth-providers/{provider}` */
|
|
846
|
+
const updateLoginProviderRequestSchema = z.object({ enabled: z.boolean() });
|
|
847
|
+
/** 연결 테스트 결과 */
|
|
848
|
+
const loginProviderTestSchema = z.object({
|
|
849
|
+
ok: z.boolean(),
|
|
850
|
+
/** 실패 이유 — `INVALID_CLIENT`(키가 틀림)·`PROVIDER_UNAVAILABLE`(공급자 응답 없음) */
|
|
851
|
+
code: z.enum(["INVALID_CLIENT", "PROVIDER_UNAVAILABLE"]).nullable(),
|
|
852
|
+
testedAt: z.string()
|
|
853
|
+
});
|
|
854
|
+
//#endregion
|
|
701
855
|
//#region src/schemas/misc.ts
|
|
702
856
|
const inquirySchema = z.object({
|
|
703
857
|
inquiryId: z.string(),
|
|
@@ -1729,7 +1883,9 @@ const updateStoreRequestSchema = z.object({
|
|
|
1729
1883
|
logoUrl: z.url().optional(),
|
|
1730
1884
|
customerCenterPhone: z.string().optional(),
|
|
1731
1885
|
businessHours: z.string().max(100).optional(),
|
|
1732
|
-
analyticsAllowedOrigins: z.array(analyticsOriginSchema).max(20).optional().describe("방문 분석 수집을 받을 스토어프런트 오리진(최대 20개). 비우면 모든 오리진에서 받는다. 넣으면 목록에 없는 오리진의 수집 요청은 403 `ORIGIN_NOT_ALLOWED`이고, 페이지 URL이 목록 밖인 이벤트는 버린다")
|
|
1886
|
+
analyticsAllowedOrigins: z.array(analyticsOriginSchema).max(20).optional().describe("@deprecated `storefrontOrigins`를 쓴다(같은 목록). 방문 분석 수집을 받을 스토어프런트 오리진(최대 20개). 비우면 모든 오리진에서 받는다. 넣으면 목록에 없는 오리진의 수집 요청은 403 `ORIGIN_NOT_ALLOWED`이고, 페이지 URL이 목록 밖인 이벤트는 버린다"),
|
|
1887
|
+
storefrontOrigins: z.array(analyticsOriginSchema).max(20).optional().describe("스토어프런트 도메인(최대 20개) — 소셜 로그인 뒤 돌아갈 주소와 방문 분석 수집을 함께 제한한다. `analyticsAllowedOrigins`와 같은 목록이다(둘 다 주면 이 값이 이긴다)"),
|
|
1888
|
+
guestCheckoutEnabled: z.boolean().optional().describe("비회원 주문 허용. false(회원만)면 로그인하지 않은 구매자의 주문서 생성·결제 요청이 403 `GUEST_CHECKOUT_DISABLED`다. 장바구니 담기와 이미 받은 비회원 주문의 조회·취소는 막지 않는다")
|
|
1733
1889
|
}).refine((value) => Object.values(value).some((v) => v !== void 0), { message: "최소 1개 필드가 필요합니다" });
|
|
1734
1890
|
const storeSchema = z.object({
|
|
1735
1891
|
storeId: z.string(),
|
|
@@ -1745,6 +1901,8 @@ const storeSchema = z.object({
|
|
|
1745
1901
|
businessNumber: z.string().nullable(),
|
|
1746
1902
|
customerCenterPhone: z.string().nullable(),
|
|
1747
1903
|
analyticsAllowedOrigins: z.array(z.string()).describe("방문 분석 수집을 받는 스토어프런트 오리진. 비어 있으면 모든 오리진에서 받는다"),
|
|
1904
|
+
storefrontOrigins: z.array(z.string()).describe("스토어프런트 도메인 — 소셜 로그인 리디렉트와 방문 분석 수집이 함께 쓴다(`analyticsAllowedOrigins`와 같은 값)"),
|
|
1905
|
+
guestCheckoutEnabled: z.boolean().describe("비회원 주문 허용. false면 회원만 주문할 수 있다"),
|
|
1748
1906
|
memberCount: z.number().int(),
|
|
1749
1907
|
createdAt: z.string()
|
|
1750
1908
|
});
|
|
@@ -2052,6 +2210,26 @@ function createStoreClient(options) {
|
|
|
2052
2210
|
answer: (inquiryId, content) => storeHttp.requestVoid("POST", path`/inquiries/${inquiryId}/answer`, { body: { content } }),
|
|
2053
2211
|
updateAnswer: (inquiryId, content) => storeHttp.requestVoid("PUT", path`/inquiries/${inquiryId}/answer`, { body: { content } })
|
|
2054
2212
|
},
|
|
2213
|
+
/**
|
|
2214
|
+
* 구매자 로그인 설정 — 이메일·비밀번호 허용, 소셜 공급자 연결. 비밀 값을 다루므로 콘솔에 로그인한 OWNER만 호출할 수 있다
|
|
2215
|
+
*/
|
|
2216
|
+
loginSettings: {
|
|
2217
|
+
get: () => storeHttp.request("GET", "/store/login-settings", loginSettingsSchema),
|
|
2218
|
+
update: (body) => storeHttp.request("PATCH", "/store/login-settings", loginSettingsSchema, { body: updateLoginSettingsRequestSchema.parse(body) }),
|
|
2219
|
+
/** 키 저장 — 저장 전에 연결 테스트를 하고, 실패하면 422 `LOGIN_PROVIDER_VERIFICATION_FAILED` */
|
|
2220
|
+
saveProvider: (provider, body) => storeHttp.request("PUT", path`/store/auth-providers/${provider}`, loginSettingsSchema, { body: saveLoginProviderRequestSchema.parse(body) }),
|
|
2221
|
+
setProviderEnabled: (provider, enabled) => storeHttp.request("PATCH", path`/store/auth-providers/${provider}`, loginSettingsSchema, { body: { enabled } }),
|
|
2222
|
+
testProvider: (provider) => storeHttp.request("POST", path`/store/auth-providers/${provider}/test`, loginProviderTestSchema),
|
|
2223
|
+
/** 연결 해제 — 키를 지운다. 연결된 구매자 계정은 남는다 */
|
|
2224
|
+
removeProvider: (provider) => storeHttp.request("DELETE", path`/store/auth-providers/${provider}`, loginSettingsSchema)
|
|
2225
|
+
},
|
|
2226
|
+
/** 구매자 관리 — 조회 `customer:r`, 탈퇴 처리 `customer:rw`(콘솔 OWNER·ADMIN) */
|
|
2227
|
+
customers: {
|
|
2228
|
+
list: (params) => storeHttp.request("GET", "/customers", pageSchema(customerSummarySchema), { query: params }),
|
|
2229
|
+
get: (customerId) => storeHttp.request("GET", path`/customers/${customerId}`, customerDetailSchema),
|
|
2230
|
+
orders: (customerId, params) => storeHttp.request("GET", path`/customers/${customerId}/orders`, pageSchema(customerOrderSchema), { query: params }),
|
|
2231
|
+
withdraw: (customerId, body) => storeHttp.requestVoid("POST", path`/customers/${customerId}/withdraw`, { body: withdrawCustomerRequestSchema.parse(body) })
|
|
2232
|
+
},
|
|
2055
2233
|
customerInquiries: {
|
|
2056
2234
|
list: (params) => storeHttp.request("GET", "/customer-inquiries", pageSchema(sellerCustomerInquirySchema), { query: params }),
|
|
2057
2235
|
get: (inquiryId) => storeHttp.request("GET", path`/customer-inquiries/${inquiryId}`, sellerCustomerInquirySchema),
|
|
@@ -2344,7 +2522,8 @@ const STORE_SCOPE_RESOURCES = {
|
|
|
2344
2522
|
analytics: ["r"],
|
|
2345
2523
|
webhook: ["r", "rw"],
|
|
2346
2524
|
store: ["r", "rw"],
|
|
2347
|
-
member: ["r", "rw"]
|
|
2525
|
+
member: ["r", "rw"],
|
|
2526
|
+
customer: ["r", "rw"]
|
|
2348
2527
|
};
|
|
2349
2528
|
const storeScopeResourceSchema = z.enum(Object.keys(STORE_SCOPE_RESOURCES)).describe("스코프 리소스");
|
|
2350
2529
|
/** 카탈로그상 존재하는 스코프 문자열인가 (예: `settlement:rw`는 false) */
|
|
@@ -2370,7 +2549,8 @@ const STORE_ROLE_SCOPES = {
|
|
|
2370
2549
|
"analytics:r",
|
|
2371
2550
|
"webhook:rw",
|
|
2372
2551
|
"store:rw",
|
|
2373
|
-
"member:rw"
|
|
2552
|
+
"member:rw",
|
|
2553
|
+
"customer:rw"
|
|
2374
2554
|
],
|
|
2375
2555
|
ADMIN: [
|
|
2376
2556
|
"product:rw",
|
|
@@ -2382,7 +2562,8 @@ const STORE_ROLE_SCOPES = {
|
|
|
2382
2562
|
"analytics:r",
|
|
2383
2563
|
"webhook:rw",
|
|
2384
2564
|
"store:rw",
|
|
2385
|
-
"member:rw"
|
|
2565
|
+
"member:rw",
|
|
2566
|
+
"customer:rw"
|
|
2386
2567
|
],
|
|
2387
2568
|
STAFF: [
|
|
2388
2569
|
"product:rw",
|
|
@@ -2390,7 +2571,8 @@ const STORE_ROLE_SCOPES = {
|
|
|
2390
2571
|
"order:rw",
|
|
2391
2572
|
"claim:rw",
|
|
2392
2573
|
"inquiry:rw",
|
|
2393
|
-
"review:rw"
|
|
2574
|
+
"review:rw",
|
|
2575
|
+
"customer:r"
|
|
2394
2576
|
]
|
|
2395
2577
|
};
|
|
2396
2578
|
//#endregion
|
|
@@ -2621,4 +2803,4 @@ function createStoreSession(options) {
|
|
|
2621
2803
|
};
|
|
2622
2804
|
}
|
|
2623
2805
|
//#endregion
|
|
2624
|
-
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, customerInquiryCategorySchema, customerInquiryListQuerySchema, 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 };
|
|
2806
|
+
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
package/src/client.ts
CHANGED
|
@@ -52,6 +52,23 @@ import {
|
|
|
52
52
|
rejectClaimRequestSchema,
|
|
53
53
|
} from "./schemas/claim";
|
|
54
54
|
import { bulkResultSchema, type PageParams, pageSchema } from "./schemas/common";
|
|
55
|
+
import {
|
|
56
|
+
customerDetailSchema,
|
|
57
|
+
type customerListQuerySchema,
|
|
58
|
+
customerOrderSchema,
|
|
59
|
+
customerSummarySchema,
|
|
60
|
+
type WithdrawCustomerRequest,
|
|
61
|
+
withdrawCustomerRequestSchema,
|
|
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";
|
|
55
72
|
import {
|
|
56
73
|
type CustomerInquiryCategory,
|
|
57
74
|
inquirySchema,
|
|
@@ -559,6 +576,60 @@ export function createStoreClient(options: StoreClientOptions) {
|
|
|
559
576
|
storeHttp.requestVoid("PUT", path`/inquiries/${inquiryId}/answer`, { body: { content } }),
|
|
560
577
|
},
|
|
561
578
|
|
|
579
|
+
/**
|
|
580
|
+
* 구매자 로그인 설정 — 이메일·비밀번호 허용, 소셜 공급자 연결. 비밀 값을 다루므로 콘솔에 로그인한 OWNER만 호출할 수 있다
|
|
581
|
+
*/
|
|
582
|
+
loginSettings: {
|
|
583
|
+
get: () => storeHttp.request("GET", "/store/login-settings", loginSettingsSchema),
|
|
584
|
+
update: (body: UpdateLoginSettingsRequest) =>
|
|
585
|
+
storeHttp.request("PATCH", "/store/login-settings", loginSettingsSchema, {
|
|
586
|
+
body: updateLoginSettingsRequestSchema.parse(body),
|
|
587
|
+
}),
|
|
588
|
+
/** 키 저장 — 저장 전에 연결 테스트를 하고, 실패하면 422 `LOGIN_PROVIDER_VERIFICATION_FAILED` */
|
|
589
|
+
saveProvider: (provider: LoginProvider, body: SaveLoginProviderRequest) =>
|
|
590
|
+
storeHttp.request("PUT", path`/store/auth-providers/${provider}`, loginSettingsSchema, {
|
|
591
|
+
body: saveLoginProviderRequestSchema.parse(body),
|
|
592
|
+
}),
|
|
593
|
+
setProviderEnabled: (provider: LoginProvider, enabled: boolean) =>
|
|
594
|
+
storeHttp.request("PATCH", path`/store/auth-providers/${provider}`, loginSettingsSchema, {
|
|
595
|
+
body: { enabled },
|
|
596
|
+
}),
|
|
597
|
+
testProvider: (provider: LoginProvider) =>
|
|
598
|
+
storeHttp.request(
|
|
599
|
+
"POST",
|
|
600
|
+
path`/store/auth-providers/${provider}/test`,
|
|
601
|
+
loginProviderTestSchema,
|
|
602
|
+
),
|
|
603
|
+
/** 연결 해제 — 키를 지운다. 연결된 구매자 계정은 남는다 */
|
|
604
|
+
removeProvider: (provider: LoginProvider) =>
|
|
605
|
+
storeHttp.request("DELETE", path`/store/auth-providers/${provider}`, loginSettingsSchema),
|
|
606
|
+
},
|
|
607
|
+
|
|
608
|
+
/** 구매자 관리 — 조회 `customer:r`, 탈퇴 처리 `customer:rw`(콘솔 OWNER·ADMIN) */
|
|
609
|
+
customers: {
|
|
610
|
+
list: (
|
|
611
|
+
params?: PageParams & Omit<z.input<typeof customerListQuerySchema>, "page" | "size">,
|
|
612
|
+
) =>
|
|
613
|
+
storeHttp.request("GET", "/customers", pageSchema(customerSummarySchema), {
|
|
614
|
+
query: params as Query,
|
|
615
|
+
}),
|
|
616
|
+
get: (customerId: string) =>
|
|
617
|
+
storeHttp.request("GET", path`/customers/${customerId}`, customerDetailSchema),
|
|
618
|
+
orders: (customerId: string, params?: PageParams) =>
|
|
619
|
+
storeHttp.request(
|
|
620
|
+
"GET",
|
|
621
|
+
path`/customers/${customerId}/orders`,
|
|
622
|
+
pageSchema(customerOrderSchema),
|
|
623
|
+
{
|
|
624
|
+
query: params as Query,
|
|
625
|
+
},
|
|
626
|
+
),
|
|
627
|
+
withdraw: (customerId: string, body: WithdrawCustomerRequest) =>
|
|
628
|
+
storeHttp.requestVoid("POST", path`/customers/${customerId}/withdraw`, {
|
|
629
|
+
body: withdrawCustomerRequestSchema.parse(body),
|
|
630
|
+
}),
|
|
631
|
+
},
|
|
632
|
+
|
|
562
633
|
customerInquiries: {
|
|
563
634
|
list: (
|
|
564
635
|
params?: PageParams & {
|
package/src/index.ts
CHANGED
|
@@ -18,6 +18,8 @@ export * from "./schemas/auth";
|
|
|
18
18
|
export * from "./schemas/category";
|
|
19
19
|
export * from "./schemas/claim";
|
|
20
20
|
export * from "./schemas/common";
|
|
21
|
+
export * from "./schemas/customer";
|
|
22
|
+
export * from "./schemas/login";
|
|
21
23
|
export * from "./schemas/misc";
|
|
22
24
|
export * from "./schemas/order";
|
|
23
25
|
export * from "./schemas/payment";
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { orderItemStatusSchema, pageQueryShape } from "./common";
|
|
3
|
+
|
|
4
|
+
/** 구매자 목록 정렬 */
|
|
5
|
+
export const customerSortSchema = z
|
|
6
|
+
.enum(["joined_desc", "joined_asc", "total_paid_desc", "order_count_desc", "last_ordered_desc"])
|
|
7
|
+
.describe(
|
|
8
|
+
"정렬. `joined_desc`(기본, 최근 가입순)·`joined_asc`·`total_paid_desc`(구매 금액순)·`order_count_desc`(주문 수순)·`last_ordered_desc`(최근 주문순)",
|
|
9
|
+
);
|
|
10
|
+
export type CustomerSort = z.infer<typeof customerSortSchema>;
|
|
11
|
+
|
|
12
|
+
/** `GET /v1/customers` 쿼리 */
|
|
13
|
+
export const customerListQuerySchema = z.object({
|
|
14
|
+
q: z
|
|
15
|
+
.string()
|
|
16
|
+
.optional()
|
|
17
|
+
.describe("검색어 — 이름·이메일(포함). 숫자 4자리면 휴대폰 뒤 4자리로도 찾는다"),
|
|
18
|
+
joinedFrom: z.string().optional().describe("가입일 시작(YYYY-MM-DD, KST, 포함)"),
|
|
19
|
+
joinedTo: z.string().optional().describe("가입일 끝(YYYY-MM-DD, KST, 포함)"),
|
|
20
|
+
marketing: z
|
|
21
|
+
.enum(["agreed", "declined"])
|
|
22
|
+
.optional()
|
|
23
|
+
.describe("마케팅 수신 동의 필터. 생략하면 전체"),
|
|
24
|
+
sort: customerSortSchema.optional(),
|
|
25
|
+
...pageQueryShape(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
/** 구매 통계 — 구매 금액은 취소된 주문 상품을 빼고, 완료된 반품은 수량 비율로 뺀 금액이다 */
|
|
29
|
+
export const customerStatsSchema = z.object({
|
|
30
|
+
orderCount: z.number().int().describe("주문 수(취소 포함)"),
|
|
31
|
+
totalPaid: z.number().int().describe("구매 금액(원) — 취소·완료된 반품 제외"),
|
|
32
|
+
lastOrderedAt: z.string().nullable().describe("최근 주문 시각"),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
/** 목록 행 — 휴대폰은 가운데를 가린다(`010-****-1234`) */
|
|
36
|
+
export const customerSummarySchema = z
|
|
37
|
+
.object({
|
|
38
|
+
customerId: z.string(),
|
|
39
|
+
name: z.string(),
|
|
40
|
+
/** 소셜 가입에서 이메일을 받지 못했으면 null */
|
|
41
|
+
email: z.string().nullable(),
|
|
42
|
+
maskedPhone: z.string().nullable(),
|
|
43
|
+
joinedAt: z.string(),
|
|
44
|
+
point: z.number().int(),
|
|
45
|
+
marketingAgreed: z.boolean(),
|
|
46
|
+
})
|
|
47
|
+
.extend(customerStatsSchema.shape);
|
|
48
|
+
export type CustomerSummary = z.infer<typeof customerSummarySchema>;
|
|
49
|
+
|
|
50
|
+
export const customerAddressSchema = z.object({
|
|
51
|
+
addressId: z.string(),
|
|
52
|
+
alias: z.string(),
|
|
53
|
+
isDefault: z.boolean(),
|
|
54
|
+
receiverName: z.string(),
|
|
55
|
+
phone: z.string(),
|
|
56
|
+
zipCode: z.string(),
|
|
57
|
+
address1: z.string(),
|
|
58
|
+
address2: z.string().nullable(),
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/** 구매자 상세 — 휴대폰 전체를 보여 준다 */
|
|
62
|
+
export const customerDetailSchema = z.object({
|
|
63
|
+
customerId: z.string(),
|
|
64
|
+
name: z.string(),
|
|
65
|
+
email: z.string().nullable(),
|
|
66
|
+
phone: z.string().nullable(),
|
|
67
|
+
joinedAt: z.string(),
|
|
68
|
+
point: z.number().int(),
|
|
69
|
+
marketingAgreed: z.boolean(),
|
|
70
|
+
loginMethods: z
|
|
71
|
+
.array(
|
|
72
|
+
z.object({
|
|
73
|
+
method: z.enum(["password", "kakao", "naver", "google"]),
|
|
74
|
+
/** 소셜 연결 시각. 비밀번호는 가입 시각 */
|
|
75
|
+
linkedAt: z.string(),
|
|
76
|
+
}),
|
|
77
|
+
)
|
|
78
|
+
.describe("로그인 방법 — 이메일·비밀번호(`password`)와 연결된 소셜 계정"),
|
|
79
|
+
addresses: z.array(customerAddressSchema),
|
|
80
|
+
stats: customerStatsSchema.extend({
|
|
81
|
+
canceledOrReturnedCount: z.number().int().describe("취소된 주문 상품 + 완료된 반품 수"),
|
|
82
|
+
reviewCount: z.number().int(),
|
|
83
|
+
inquiryCount: z.number().int().describe("상품 문의 + 1:1 문의"),
|
|
84
|
+
}),
|
|
85
|
+
});
|
|
86
|
+
export type CustomerDetail = z.infer<typeof customerDetailSchema>;
|
|
87
|
+
|
|
88
|
+
/** 구매자의 주문 — 전체 기간 */
|
|
89
|
+
export const customerOrderSchema = z.object({
|
|
90
|
+
orderId: z.string(),
|
|
91
|
+
orderedAt: z.string(),
|
|
92
|
+
totalAmount: z.number().int().describe("결제 금액"),
|
|
93
|
+
testPayment: z.boolean(),
|
|
94
|
+
items: z.array(
|
|
95
|
+
z.object({
|
|
96
|
+
orderItemId: z.string(),
|
|
97
|
+
productName: z.string(),
|
|
98
|
+
optionName: z.string().nullable(),
|
|
99
|
+
quantity: z.number().int(),
|
|
100
|
+
status: orderItemStatusSchema,
|
|
101
|
+
claimStatus: z
|
|
102
|
+
.enum(["CANCEL_REQUESTED", "RETURN_REQUESTED", "EXCHANGE_REQUESTED"])
|
|
103
|
+
.nullable(),
|
|
104
|
+
}),
|
|
105
|
+
),
|
|
106
|
+
});
|
|
107
|
+
export type CustomerOrder = z.infer<typeof customerOrderSchema>;
|
|
108
|
+
|
|
109
|
+
/** `POST /v1/customers/{id}/withdraw` 본문 */
|
|
110
|
+
export const withdrawCustomerRequestSchema = z.object({
|
|
111
|
+
reason: z
|
|
112
|
+
.enum(["BUYER_REQUEST", "DORMANT", "ABUSE", "OTHER"])
|
|
113
|
+
.describe("처리 사유 — 구매자 요청·장기 미이용·부정 이용·기타. 감사 로그에 남는다"),
|
|
114
|
+
memo: z.string().max(200).optional().describe("사유 보충(선택)"),
|
|
115
|
+
});
|
|
116
|
+
export type WithdrawCustomerRequest = z.infer<typeof withdrawCustomerRequestSchema>;
|
|
117
|
+
|
|
118
|
+
/** `WITHDRAWAL_BLOCKED`의 `error.details` — 탈퇴를 막는 항목 수(스토어프런트 탈퇴와 같다) */
|
|
119
|
+
export const customerWithdrawalBlockedDetailsSchema = z.object({
|
|
120
|
+
inProgressOrderItems: z.number().int(),
|
|
121
|
+
openClaims: z.number().int(),
|
|
122
|
+
pendingPayments: z.number().int(),
|
|
123
|
+
});
|
|
124
|
+
export type CustomerWithdrawalBlockedDetails = z.infer<
|
|
125
|
+
typeof customerWithdrawalBlockedDetailsSchema
|
|
126
|
+
>;
|
|
@@ -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>;
|
package/src/schemas/scope.ts
CHANGED
|
@@ -27,6 +27,7 @@ export const STORE_SCOPE_RESOURCES = {
|
|
|
27
27
|
webhook: ["r", "rw"],
|
|
28
28
|
store: ["r", "rw"],
|
|
29
29
|
member: ["r", "rw"],
|
|
30
|
+
customer: ["r", "rw"],
|
|
30
31
|
} as const satisfies Record<string, readonly ScopeAccess[]>;
|
|
31
32
|
|
|
32
33
|
export type StoreScopeResource = keyof typeof STORE_SCOPE_RESOURCES;
|
|
@@ -61,6 +62,7 @@ export const STORE_ROLE_SCOPES = {
|
|
|
61
62
|
"webhook:rw",
|
|
62
63
|
"store:rw",
|
|
63
64
|
"member:rw",
|
|
65
|
+
"customer:rw",
|
|
64
66
|
],
|
|
65
67
|
ADMIN: [
|
|
66
68
|
"product:rw",
|
|
@@ -73,6 +75,15 @@ export const STORE_ROLE_SCOPES = {
|
|
|
73
75
|
"webhook:rw",
|
|
74
76
|
"store:rw",
|
|
75
77
|
"member:rw",
|
|
78
|
+
"customer:rw",
|
|
79
|
+
],
|
|
80
|
+
STAFF: [
|
|
81
|
+
"product:rw",
|
|
82
|
+
"category:rw",
|
|
83
|
+
"order:rw",
|
|
84
|
+
"claim:rw",
|
|
85
|
+
"inquiry:rw",
|
|
86
|
+
"review:rw",
|
|
87
|
+
"customer:r",
|
|
76
88
|
],
|
|
77
|
-
STAFF: ["product:rw", "category:rw", "order:rw", "claim:rw", "inquiry:rw", "review:rw"],
|
|
78
89
|
} as const satisfies Record<StoreRole, readonly string[]>;
|
package/src/schemas/store.ts
CHANGED
|
@@ -114,9 +114,24 @@ 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
|
+
),
|
|
128
|
+
guestCheckoutEnabled: z
|
|
129
|
+
.boolean()
|
|
130
|
+
.optional()
|
|
131
|
+
.describe(
|
|
132
|
+
"비회원 주문 허용. false(회원만)면 로그인하지 않은 구매자의 주문서 생성·결제 요청이 403 `GUEST_CHECKOUT_DISABLED`다. " +
|
|
133
|
+
"장바구니 담기와 이미 받은 비회원 주문의 조회·취소는 막지 않는다",
|
|
134
|
+
),
|
|
120
135
|
})
|
|
121
136
|
.refine((value) => Object.values(value).some((v) => v !== undefined), {
|
|
122
137
|
message: "최소 1개 필드가 필요합니다",
|
|
@@ -135,6 +150,12 @@ export const storeSchema = z.object({
|
|
|
135
150
|
analyticsAllowedOrigins: z
|
|
136
151
|
.array(z.string())
|
|
137
152
|
.describe("방문 분석 수집을 받는 스토어프런트 오리진. 비어 있으면 모든 오리진에서 받는다"),
|
|
153
|
+
storefrontOrigins: z
|
|
154
|
+
.array(z.string())
|
|
155
|
+
.describe(
|
|
156
|
+
"스토어프런트 도메인 — 소셜 로그인 리디렉트와 방문 분석 수집이 함께 쓴다(`analyticsAllowedOrigins`와 같은 값)",
|
|
157
|
+
),
|
|
158
|
+
guestCheckoutEnabled: z.boolean().describe("비회원 주문 허용. false면 회원만 주문할 수 있다"),
|
|
138
159
|
memberCount: z.number().int(),
|
|
139
160
|
createdAt: z.string(),
|
|
140
161
|
});
|