@diffsome/sdk 3.0.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/README.md +667 -0
- package/dist/index.d.mts +9856 -0
- package/dist/index.d.ts +9856 -0
- package/dist/index.js +1493 -0
- package/dist/index.mjs +1463 -0
- package/package.json +51 -0
package/README.md
ADDED
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
# @diffsome/sdk
|
|
2
|
+
|
|
3
|
+
Diffsome 공식 SDK - 헤드리스 CMS + 이커머스 + AI 기능을 제공합니다.
|
|
4
|
+
|
|
5
|
+
**버전: 2.18.0**
|
|
6
|
+
|
|
7
|
+
## 설치
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @diffsome/sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 빠른 시작
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { Diffsome } from '@diffsome/sdk';
|
|
17
|
+
|
|
18
|
+
const client = new Diffsome({
|
|
19
|
+
tenantId: 'your-tenant-id',
|
|
20
|
+
apiKey: 'pky_xxxxxxxxxxxxxxxx', // 필수 - Dashboard > Settings > API Tokens
|
|
21
|
+
baseUrl: 'https://diffsome.com', // 선택
|
|
22
|
+
|
|
23
|
+
// 토큰 자동 저장 (로그인 유지)
|
|
24
|
+
persistToken: true,
|
|
25
|
+
storageType: 'localStorage', // 또는 'sessionStorage'
|
|
26
|
+
onAuthStateChange: (token, user) => {
|
|
27
|
+
console.log('Auth changed:', user);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// 블로그 조회
|
|
32
|
+
const { data: posts } = await client.blog.list();
|
|
33
|
+
|
|
34
|
+
// 상품 조회
|
|
35
|
+
const { data: products } = await client.shop.listProducts();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 인증 (Auth)
|
|
41
|
+
|
|
42
|
+
### 기본 설정
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
const client = new Diffsome({
|
|
46
|
+
tenantId: 'demo',
|
|
47
|
+
apiKey: 'pky_xxxxxxxxxxxxxxxx', // 필수
|
|
48
|
+
persistToken: true, // 토큰 자동 저장
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 토큰 자동 저장
|
|
53
|
+
|
|
54
|
+
`persistToken: true` 설정 시:
|
|
55
|
+
- **로그인**: `localStorage`에 자동 저장
|
|
56
|
+
- **새로고침**: 토큰 자동 복원
|
|
57
|
+
- **로그아웃**: 토큰 자동 삭제
|
|
58
|
+
- **저장 키**: `promptly_auth_token_{tenantId}`
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
const client = new Diffsome({
|
|
62
|
+
tenantId: 'demo',
|
|
63
|
+
apiKey: 'pky_xxx',
|
|
64
|
+
persistToken: true,
|
|
65
|
+
storageType: 'localStorage', // 기본값, 또는 'sessionStorage'
|
|
66
|
+
onAuthStateChange: (token, user) => {
|
|
67
|
+
// 로그인/로그아웃 시 호출
|
|
68
|
+
if (token) {
|
|
69
|
+
console.log('Logged in:', user);
|
|
70
|
+
} else {
|
|
71
|
+
console.log('Logged out');
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 로그인/회원가입
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// 회원가입
|
|
81
|
+
await client.auth.register({
|
|
82
|
+
name: 'John Doe',
|
|
83
|
+
email: 'john@example.com',
|
|
84
|
+
password: 'password',
|
|
85
|
+
password_confirmation: 'password',
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// 로그인 (토큰 자동 저장됨)
|
|
89
|
+
const { member, token } = await client.auth.login({
|
|
90
|
+
email: 'john@example.com',
|
|
91
|
+
password: 'password',
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// 로그아웃 (토큰 자동 삭제됨)
|
|
95
|
+
await client.auth.logout();
|
|
96
|
+
|
|
97
|
+
// 인증 상태 확인
|
|
98
|
+
client.auth.isAuthenticated(); // true/false
|
|
99
|
+
|
|
100
|
+
// 현재 사용자
|
|
101
|
+
const me = await client.auth.me();
|
|
102
|
+
|
|
103
|
+
// 프로필 수정
|
|
104
|
+
await client.auth.updateProfile({ name: 'New Name' });
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### 소셜 로그인
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
// 사용 가능한 프로바이더
|
|
111
|
+
const providers = await client.auth.getSocialProviders();
|
|
112
|
+
// ['google', 'kakao', 'naver']
|
|
113
|
+
|
|
114
|
+
// 로그인 URL 획득
|
|
115
|
+
const { url } = await client.auth.getSocialAuthUrl('google');
|
|
116
|
+
window.location.href = url;
|
|
117
|
+
|
|
118
|
+
// 콜백 처리 (리다이렉트 후)
|
|
119
|
+
const { member, token } = await client.auth.socialCallback('google', code);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 비밀번호 재설정
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
// 재설정 이메일 발송
|
|
126
|
+
await client.auth.forgotPassword({ email: 'john@example.com' });
|
|
127
|
+
|
|
128
|
+
// 비밀번호 재설정
|
|
129
|
+
await client.auth.resetPassword({
|
|
130
|
+
token: 'reset-token',
|
|
131
|
+
email: 'john@example.com',
|
|
132
|
+
password: 'newpassword',
|
|
133
|
+
password_confirmation: 'newpassword',
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Blog API
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// 목록 조회
|
|
143
|
+
const { data, meta } = await client.blog.list({
|
|
144
|
+
page: 1,
|
|
145
|
+
per_page: 10,
|
|
146
|
+
category: 'tech',
|
|
147
|
+
tag: 'laravel',
|
|
148
|
+
search: 'keyword',
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// 상세 조회
|
|
152
|
+
const post = await client.blog.get('post-slug');
|
|
153
|
+
|
|
154
|
+
// 추천 글
|
|
155
|
+
const featured = await client.blog.featured(5);
|
|
156
|
+
|
|
157
|
+
// 카테고리/태그별 필터
|
|
158
|
+
const { data } = await client.blog.byCategory('news');
|
|
159
|
+
const { data } = await client.blog.byTag('featured');
|
|
160
|
+
|
|
161
|
+
// 카테고리/태그 목록
|
|
162
|
+
const categories = await client.blog.categories(); // string[]
|
|
163
|
+
const tags = await client.blog.tags(); // string[]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Boards API
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
// 게시판 목록
|
|
172
|
+
const { data: boards } = await client.boards.list();
|
|
173
|
+
|
|
174
|
+
// 게시판 조회
|
|
175
|
+
const board = await client.boards.get('board-slug');
|
|
176
|
+
|
|
177
|
+
// 게시글 목록
|
|
178
|
+
const { data: posts } = await client.boards.listPosts('board-slug', {
|
|
179
|
+
page: 1,
|
|
180
|
+
per_page: 10,
|
|
181
|
+
search: 'keyword',
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// 게시글 상세
|
|
185
|
+
const post = await client.boards.getPost(postId);
|
|
186
|
+
|
|
187
|
+
// 게시글 작성 (인증 필요)
|
|
188
|
+
await client.boards.createPost({
|
|
189
|
+
board_id: 1,
|
|
190
|
+
title: 'Title',
|
|
191
|
+
content: 'Content',
|
|
192
|
+
is_secret: false,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// 게시글 수정/삭제
|
|
196
|
+
await client.boards.updatePost(postId, { title: 'New Title' });
|
|
197
|
+
await client.boards.deletePost(postId);
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Comments API
|
|
203
|
+
|
|
204
|
+
게시판, 블로그, 독립 댓글(방명록) 지원
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
// 게시판 댓글
|
|
208
|
+
const { data } = await client.comments.boardPost(postId);
|
|
209
|
+
await client.comments.createBoardPost(postId, {
|
|
210
|
+
author_name: 'John',
|
|
211
|
+
content: 'Great!',
|
|
212
|
+
password: '1234', // 비회원 댓글
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// 블로그 댓글
|
|
216
|
+
const { data } = await client.comments.blogPost('post-slug');
|
|
217
|
+
await client.comments.createBlogPost('post-slug', {
|
|
218
|
+
content: 'Nice article!',
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// 독립 댓글 (방명록)
|
|
222
|
+
const { data } = await client.comments.standalone('guestbook');
|
|
223
|
+
await client.comments.createStandalone('guestbook', {
|
|
224
|
+
author_name: 'Visitor',
|
|
225
|
+
content: 'Hello!',
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// 공통
|
|
229
|
+
await client.comments.update(commentId, { content: 'Updated' });
|
|
230
|
+
await client.comments.delete(commentId, { password: '1234' });
|
|
231
|
+
await client.comments.like(commentId);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
## Shop API
|
|
237
|
+
|
|
238
|
+
### 상품
|
|
239
|
+
|
|
240
|
+
```typescript
|
|
241
|
+
// 상품 목록
|
|
242
|
+
const { data: products } = await client.shop.listProducts({
|
|
243
|
+
category: 'shoes',
|
|
244
|
+
is_featured: true,
|
|
245
|
+
min_price: 10000,
|
|
246
|
+
max_price: 50000,
|
|
247
|
+
search: 'keyword',
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// 상품 상세
|
|
251
|
+
const product = await client.shop.getProduct('product-slug');
|
|
252
|
+
|
|
253
|
+
// 추천 상품
|
|
254
|
+
const featured = await client.shop.featuredProducts(8);
|
|
255
|
+
|
|
256
|
+
// 카테고리 목록
|
|
257
|
+
const categories = await client.shop.listCategories();
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
### 상품 리뷰
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
// 리뷰 목록
|
|
264
|
+
const { data: reviews, stats } = await client.shop.getProductReviews('product-slug', {
|
|
265
|
+
page: 1,
|
|
266
|
+
per_page: 10,
|
|
267
|
+
rating: 5, // 별점 필터
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// 리뷰 통계
|
|
271
|
+
// stats = { average_rating: 4.5, total_count: 123, rating_counts: { 5: 80, 4: 30, ... } }
|
|
272
|
+
|
|
273
|
+
// 리뷰 작성 (인증 + 구매 필요)
|
|
274
|
+
await client.shop.createProductReview('product-slug', {
|
|
275
|
+
rating: 5,
|
|
276
|
+
title: 'Great product!',
|
|
277
|
+
content: 'Highly recommended.',
|
|
278
|
+
images: ['https://...'],
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// 리뷰 수정/삭제
|
|
282
|
+
await client.shop.updateProductReview(reviewId, { rating: 4 });
|
|
283
|
+
await client.shop.deleteProductReview(reviewId);
|
|
284
|
+
|
|
285
|
+
// 도움이 됐어요
|
|
286
|
+
await client.shop.markReviewHelpful(reviewId);
|
|
287
|
+
|
|
288
|
+
// 내 리뷰 목록
|
|
289
|
+
const { data: myReviews } = await client.shop.getMyReviews();
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### 장바구니 (인증 필요)
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
// 장바구니 조회
|
|
296
|
+
const cart = await client.shop.getCart();
|
|
297
|
+
|
|
298
|
+
// 상품 추가
|
|
299
|
+
await client.shop.addToCart({
|
|
300
|
+
product_id: 1,
|
|
301
|
+
quantity: 2,
|
|
302
|
+
variant_id: 3, // 옵션 상품
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// 수량 변경
|
|
306
|
+
await client.shop.updateCartItem(itemId, { quantity: 3 });
|
|
307
|
+
|
|
308
|
+
// 상품 제거
|
|
309
|
+
await client.shop.removeFromCart(itemId);
|
|
310
|
+
|
|
311
|
+
// 장바구니 비우기
|
|
312
|
+
await client.shop.clearCart();
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### 주문 (인증 필요)
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
// 주문 생성
|
|
319
|
+
const order = await client.shop.createOrder({
|
|
320
|
+
orderer_name: 'John Doe',
|
|
321
|
+
orderer_email: 'john@example.com',
|
|
322
|
+
orderer_phone: '010-1234-5678',
|
|
323
|
+
shipping_name: 'John Doe',
|
|
324
|
+
shipping_phone: '010-1234-5678',
|
|
325
|
+
shipping_zipcode: '12345',
|
|
326
|
+
shipping_address: '서울시 강남구',
|
|
327
|
+
shipping_address_detail: '101동 101호',
|
|
328
|
+
shipping_memo: '부재시 경비실',
|
|
329
|
+
coupon_code: 'SAVE10',
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
// 주문 목록
|
|
333
|
+
const { data: orders } = await client.shop.listOrders();
|
|
334
|
+
|
|
335
|
+
// 주문 상세
|
|
336
|
+
const orderDetail = await client.shop.getOrder(orderId);
|
|
337
|
+
|
|
338
|
+
// 주문 취소
|
|
339
|
+
await client.shop.cancelOrder(orderId);
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 결제 (토스페이먼츠)
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
// 결제 준비
|
|
346
|
+
const payment = await client.shop.preparePayment({
|
|
347
|
+
order_number: 'ORD-123',
|
|
348
|
+
success_url: 'https://mysite.com/payment/success',
|
|
349
|
+
fail_url: 'https://mysite.com/payment/fail',
|
|
350
|
+
});
|
|
351
|
+
// payment = { client_key, order_id, order_name, amount, customer_name, ... }
|
|
352
|
+
|
|
353
|
+
// 결제 승인 (토스 결제 완료 후)
|
|
354
|
+
await client.shop.confirmPayment({
|
|
355
|
+
payment_key: 'toss_payment_key',
|
|
356
|
+
order_id: 'ORD-123',
|
|
357
|
+
amount: 50000,
|
|
358
|
+
});
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### 쿠폰
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
// 쿠폰 검증
|
|
365
|
+
const result = await client.shop.validateCoupon('SAVE10', 50000);
|
|
366
|
+
// { valid: true, discount_amount: 5000, coupon: { ... } }
|
|
367
|
+
|
|
368
|
+
// 내 쿠폰 목록
|
|
369
|
+
const coupons = await client.shop.myCoupons();
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### 배송 설정
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
const settings = await client.shop.getShippingSettings();
|
|
376
|
+
// { base_fee, free_shipping_threshold, ... }
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Reservation API
|
|
382
|
+
|
|
383
|
+
### 공개 API
|
|
384
|
+
|
|
385
|
+
```typescript
|
|
386
|
+
// 예약 설정
|
|
387
|
+
const settings = await client.reservation.getSettings();
|
|
388
|
+
|
|
389
|
+
// 서비스 목록
|
|
390
|
+
const services = await client.reservation.listServices();
|
|
391
|
+
|
|
392
|
+
// 담당자 목록
|
|
393
|
+
const staff = await client.reservation.listStaff(serviceId);
|
|
394
|
+
|
|
395
|
+
// 예약 가능 날짜
|
|
396
|
+
const dates = await client.reservation.getAvailableDates({
|
|
397
|
+
service_id: 1,
|
|
398
|
+
staff_id: 2,
|
|
399
|
+
start_date: '2026-01-01',
|
|
400
|
+
end_date: '2026-01-31',
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// 예약 가능 시간
|
|
404
|
+
const slots = await client.reservation.getAvailableSlots({
|
|
405
|
+
service_id: 1,
|
|
406
|
+
date: '2026-01-15',
|
|
407
|
+
staff_id: 2,
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### 예약 관리 (인증 필요)
|
|
412
|
+
|
|
413
|
+
```typescript
|
|
414
|
+
// 예약 생성
|
|
415
|
+
await client.reservation.create({
|
|
416
|
+
service_id: 1,
|
|
417
|
+
staff_id: 2,
|
|
418
|
+
reservation_date: '2026-01-15',
|
|
419
|
+
start_time: '14:00',
|
|
420
|
+
customer_name: 'John Doe',
|
|
421
|
+
customer_phone: '010-1234-5678',
|
|
422
|
+
customer_email: 'john@example.com',
|
|
423
|
+
notes: '요청사항',
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
// 내 예약 목록
|
|
427
|
+
const { data } = await client.reservation.list({ status: 'confirmed' });
|
|
428
|
+
|
|
429
|
+
// 다가오는/지난 예약
|
|
430
|
+
const upcoming = await client.reservation.upcoming(5);
|
|
431
|
+
const past = await client.reservation.past(10);
|
|
432
|
+
|
|
433
|
+
// 예약 취소
|
|
434
|
+
await client.reservation.cancel('RES-20260115-001', '일정 변경');
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## Forms API
|
|
440
|
+
|
|
441
|
+
```typescript
|
|
442
|
+
// 폼 목록
|
|
443
|
+
const { data: forms } = await client.forms.list();
|
|
444
|
+
|
|
445
|
+
// 폼 상세 (필드 정보 포함)
|
|
446
|
+
const form = await client.forms.get('contact');
|
|
447
|
+
|
|
448
|
+
// 폼 제출
|
|
449
|
+
await client.forms.submit('contact', {
|
|
450
|
+
name: 'John Doe',
|
|
451
|
+
email: 'john@example.com',
|
|
452
|
+
message: 'Hello!',
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// 내 제출 목록 (인증 필요)
|
|
456
|
+
const { data: submissions } = await client.forms.mySubmissions();
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## Media API (인증 필요)
|
|
462
|
+
|
|
463
|
+
```typescript
|
|
464
|
+
// 파일 업로드
|
|
465
|
+
const media = await client.media.upload(file);
|
|
466
|
+
|
|
467
|
+
// 여러 파일 업로드
|
|
468
|
+
const mediaList = await client.media.uploadMultiple([file1, file2]);
|
|
469
|
+
|
|
470
|
+
// 내 미디어 목록
|
|
471
|
+
const { data: myMedia } = await client.media.list({ type: 'image/jpeg' });
|
|
472
|
+
|
|
473
|
+
// 미디어 삭제
|
|
474
|
+
await client.media.delete(mediaId);
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## Custom Entities API
|
|
480
|
+
|
|
481
|
+
동적 데이터 구조 생성/관리
|
|
482
|
+
|
|
483
|
+
### 엔티티 정의
|
|
484
|
+
|
|
485
|
+
```typescript
|
|
486
|
+
// 엔티티 목록
|
|
487
|
+
const entities = await client.entities.list();
|
|
488
|
+
|
|
489
|
+
// 엔티티 조회
|
|
490
|
+
const entity = await client.entities.get('customers');
|
|
491
|
+
|
|
492
|
+
// 엔티티 생성
|
|
493
|
+
await client.entities.create({
|
|
494
|
+
name: 'Customer',
|
|
495
|
+
slug: 'customers',
|
|
496
|
+
schema: {
|
|
497
|
+
fields: [
|
|
498
|
+
{ name: 'company', label: 'Company', type: 'text', required: true },
|
|
499
|
+
{ name: 'email', label: 'Email', type: 'email', required: true },
|
|
500
|
+
{ name: 'status', label: 'Status', type: 'select', options: [
|
|
501
|
+
{ value: 'active', label: 'Active' },
|
|
502
|
+
{ value: 'inactive', label: 'Inactive' },
|
|
503
|
+
]},
|
|
504
|
+
],
|
|
505
|
+
},
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
// 엔티티 수정/삭제
|
|
509
|
+
await client.entities.update('customers', { name: 'Clients' });
|
|
510
|
+
await client.entities.delete('customers', true); // force
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
### 레코드
|
|
514
|
+
|
|
515
|
+
```typescript
|
|
516
|
+
// 레코드 목록
|
|
517
|
+
const { data: records } = await client.entities.listRecords('customers', {
|
|
518
|
+
search: 'ACME',
|
|
519
|
+
filters: JSON.stringify({ status: 'active' }),
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
// 레코드 조회
|
|
523
|
+
const record = await client.entities.getRecord('customers', 1);
|
|
524
|
+
|
|
525
|
+
// 레코드 생성
|
|
526
|
+
await client.entities.createRecord('customers', {
|
|
527
|
+
company: 'ACME Corp',
|
|
528
|
+
email: 'contact@acme.com',
|
|
529
|
+
status: 'active',
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
// 레코드 수정/삭제
|
|
533
|
+
await client.entities.updateRecord('customers', 1, { status: 'inactive' });
|
|
534
|
+
await client.entities.deleteRecord('customers', 1);
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### TypeScript 지원
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
interface Customer {
|
|
541
|
+
company: string;
|
|
542
|
+
email: string;
|
|
543
|
+
status: 'active' | 'inactive';
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
const customers = client.entities.typed<Customer>('customers');
|
|
547
|
+
const { data } = await customers.list(); // data: Customer[]
|
|
548
|
+
```
|
|
549
|
+
|
|
550
|
+
---
|
|
551
|
+
|
|
552
|
+
## 응답 타입
|
|
553
|
+
|
|
554
|
+
모든 목록 API는 일관된 형식 반환:
|
|
555
|
+
|
|
556
|
+
```typescript
|
|
557
|
+
interface ListResponse<T> {
|
|
558
|
+
data: T[]; // 항상 배열, null 아님
|
|
559
|
+
meta: {
|
|
560
|
+
current_page: number;
|
|
561
|
+
last_page: number;
|
|
562
|
+
per_page: number;
|
|
563
|
+
total: number;
|
|
564
|
+
from: number | null;
|
|
565
|
+
to: number | null;
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
---
|
|
571
|
+
|
|
572
|
+
## 에러 처리
|
|
573
|
+
|
|
574
|
+
```typescript
|
|
575
|
+
import { Promptly, PromptlyError } from '@diffsome/sdk';
|
|
576
|
+
|
|
577
|
+
try {
|
|
578
|
+
await client.auth.login({ email: 'wrong@email.com', password: 'wrong' });
|
|
579
|
+
} catch (error) {
|
|
580
|
+
if (error instanceof PromptlyError) {
|
|
581
|
+
console.log(error.message); // "Invalid credentials"
|
|
582
|
+
console.log(error.status); // 401
|
|
583
|
+
console.log(error.errors); // { email: ["Invalid email or password"] }
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
```
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
## React 예시
|
|
591
|
+
|
|
592
|
+
```tsx
|
|
593
|
+
'use client';
|
|
594
|
+
|
|
595
|
+
import { useState, useEffect } from 'react';
|
|
596
|
+
import { Diffsome } from '@diffsome/sdk';
|
|
597
|
+
|
|
598
|
+
// 싱글톤 클라이언트
|
|
599
|
+
const client = new Diffsome({
|
|
600
|
+
tenantId: process.env.NEXT_PUBLIC_PROMPTLY_TENANT_ID!,
|
|
601
|
+
apiKey: process.env.NEXT_PUBLIC_PROMPTLY_API_KEY!,
|
|
602
|
+
persistToken: true,
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
function BlogList() {
|
|
606
|
+
const [posts, setPosts] = useState([]);
|
|
607
|
+
const [loading, setLoading] = useState(true);
|
|
608
|
+
|
|
609
|
+
useEffect(() => {
|
|
610
|
+
client.blog.list({ per_page: 10 })
|
|
611
|
+
.then(({ data }) => setPosts(data))
|
|
612
|
+
.finally(() => setLoading(false));
|
|
613
|
+
}, []);
|
|
614
|
+
|
|
615
|
+
if (loading) return <div>Loading...</div>;
|
|
616
|
+
|
|
617
|
+
return (
|
|
618
|
+
<div>
|
|
619
|
+
{posts.map(post => (
|
|
620
|
+
<article key={post.id}>
|
|
621
|
+
<h2>{post.title}</h2>
|
|
622
|
+
<p>{post.excerpt}</p>
|
|
623
|
+
</article>
|
|
624
|
+
))}
|
|
625
|
+
</div>
|
|
626
|
+
);
|
|
627
|
+
}
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
## Changelog
|
|
633
|
+
|
|
634
|
+
### v2.18.0
|
|
635
|
+
- 상품 리뷰 API 추가
|
|
636
|
+
- 배송 설정 API 추가
|
|
637
|
+
|
|
638
|
+
### v2.15.0
|
|
639
|
+
- 토스페이먼츠 결제 API 추가
|
|
640
|
+
|
|
641
|
+
### v2.12.0
|
|
642
|
+
- 블로그 카테고리/태그 필터 추가
|
|
643
|
+
- `category`, `tags`, `views`, `published_at` 필드 추가
|
|
644
|
+
|
|
645
|
+
### v2.10.0
|
|
646
|
+
- `persistToken` 옵션 추가 (토큰 자동 저장)
|
|
647
|
+
- `onAuthStateChange` 콜백 추가
|
|
648
|
+
- `storageType` 옵션 추가
|
|
649
|
+
|
|
650
|
+
### v2.5.0
|
|
651
|
+
- 게시판 비밀글 지원 (`is_secret`, `is_mine`)
|
|
652
|
+
|
|
653
|
+
### v2.3.0
|
|
654
|
+
- 다형성 댓글 API (board, blog, standalone)
|
|
655
|
+
|
|
656
|
+
### v2.0.0
|
|
657
|
+
- **Breaking:** API key 필수
|
|
658
|
+
|
|
659
|
+
### v1.3.0
|
|
660
|
+
- `ListResponse<T>` 통일
|
|
661
|
+
- 예약 시스템 지원
|
|
662
|
+
|
|
663
|
+
---
|
|
664
|
+
|
|
665
|
+
## 라이선스
|
|
666
|
+
|
|
667
|
+
MIT
|