@back23/promptly-sdk 2.14.2 → 2.18.1

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 CHANGED
@@ -1,290 +1,495 @@
1
1
  # @back23/promptly-sdk
2
2
 
3
- Official SDK for Promptly AI CMS - A headless CMS with built-in AI capabilities.
3
+ Promptly AI CMS 공식 SDK - 헤드리스 CMS + 이커머스 + AI 기능을 제공합니다.
4
4
 
5
- ## Installation
5
+ **버전: 2.18.0**
6
+
7
+ ## 설치
6
8
 
7
9
  ```bash
8
10
  npm install @back23/promptly-sdk
9
11
  ```
10
12
 
11
- ## Quick Start
13
+ ## 빠른 시작
12
14
 
13
15
  ```typescript
14
16
  import { Promptly } from '@back23/promptly-sdk';
15
17
 
16
18
  const client = new Promptly({
17
19
  tenantId: 'your-tenant-id',
18
- apiKey: 'pky_xxxxxxxxxxxxxxxx', // Required - Get from Dashboard > Settings > API Tokens
19
- baseUrl: 'https://promptly.webbyon.com', // Optional
20
+ apiKey: 'pky_xxxxxxxxxxxxxxxx', // 필수 - Dashboard > Settings > API Tokens
21
+ baseUrl: 'https://promptly.webbyon.com', // 선택
22
+
23
+ // 토큰 자동 저장 (로그인 유지)
24
+ persistToken: true,
25
+ storageType: 'localStorage', // 또는 'sessionStorage'
26
+ onAuthStateChange: (token, user) => {
27
+ console.log('Auth changed:', user);
28
+ },
20
29
  });
21
30
 
22
- // Fetch blog posts
23
- const { data: posts, meta } = await client.blog.list();
31
+ // 블로그 조회
32
+ const { data: posts } = await client.blog.list();
24
33
 
25
- // Fetch products
34
+ // 상품 조회
26
35
  const { data: products } = await client.shop.listProducts();
27
36
  ```
28
37
 
29
- ## Authentication
38
+ ---
39
+
40
+ ## 인증 (Auth)
30
41
 
31
- All API requests require an API key. Get yours from **Dashboard > Settings > API Tokens**.
42
+ ### 기본 설정
32
43
 
33
44
  ```typescript
34
45
  const client = new Promptly({
35
46
  tenantId: 'demo',
36
- apiKey: 'pky_xxxxxxxxxxxxxxxx', // Required
47
+ apiKey: 'pky_xxxxxxxxxxxxxxxx', // 필수
48
+ persistToken: true, // 토큰 자동 저장
37
49
  });
38
50
  ```
39
51
 
40
- For member-specific operations (orders, profile, etc.), authenticate first:
52
+ ### 토큰 자동 저장
53
+
54
+ `persistToken: true` 설정 시:
55
+ - **로그인**: `localStorage`에 자동 저장
56
+ - **새로고침**: 토큰 자동 복원
57
+ - **로그아웃**: 토큰 자동 삭제
58
+ - **저장 키**: `promptly_auth_token_{tenantId}`
41
59
 
42
60
  ```typescript
43
- // Login
44
- await client.auth.login({ email: 'user@example.com', password: 'password' });
61
+ const client = new Promptly({
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
+ ```
45
76
 
46
- // Now member-only APIs work
47
- const profile = await client.members.getProfile();
48
- const orders = await client.orders.list();
77
+ ### 로그인/회원가입
49
78
 
50
- // Check auth status
51
- client.isAuthenticated(); // true
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
+ });
52
93
 
53
- // Logout
94
+ // 로그아웃 (토큰 자동 삭제됨)
54
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
+ });
55
135
  ```
56
136
 
57
- ## API Reference
137
+ ---
58
138
 
59
- ### Blog
139
+ ## Blog API
60
140
 
61
141
  ```typescript
62
- // List posts
142
+ // 목록 조회
63
143
  const { data, meta } = await client.blog.list({
64
144
  page: 1,
65
145
  per_page: 10,
66
- category: 'tech', // Optional filter
67
- tag: 'laravel', // Optional filter
68
- search: 'keyword', // Optional search
146
+ category: 'tech',
147
+ tag: 'laravel',
148
+ search: 'keyword',
69
149
  });
70
150
 
71
- // Get single post
151
+ // 상세 조회
72
152
  const post = await client.blog.get('post-slug');
73
153
 
74
- // Get featured posts
154
+ // 추천
75
155
  const featured = await client.blog.featured(5);
76
156
 
77
- // Filter by category/tag
157
+ // 카테고리/태그별 필터
78
158
  const { data } = await client.blog.byCategory('news');
79
159
  const { data } = await client.blog.byTag('featured');
80
160
 
81
- // Get all categories and tags
82
- const categories = await client.blog.categories(); // string[]
83
- const tags = await client.blog.tags(); // string[]
161
+ // 카테고리/태그 목록
162
+ const categories = await client.blog.categories(); // string[]
163
+ const tags = await client.blog.tags(); // string[]
84
164
  ```
85
165
 
86
- **BlogPost Type:**
87
- ```typescript
88
- interface BlogPost {
89
- id: number;
90
- title: string;
91
- slug: string;
92
- excerpt: string;
93
- featured_image: string | null;
94
- category: string | null;
95
- tags: string[];
96
- author: string;
97
- views: number;
98
- status: string;
99
- published_at: string | null;
100
- created_at: string;
101
- content?: string; // Detail view only
102
- updated_at?: string; // Detail view only
103
- }
104
- ```
166
+ ---
105
167
 
106
- ### Boards
168
+ ## Boards API
107
169
 
108
170
  ```typescript
109
- // List boards
171
+ // 게시판 목록
110
172
  const { data: boards } = await client.boards.list();
111
173
 
112
- // Get board
174
+ // 게시판 조회
113
175
  const board = await client.boards.get('board-slug');
114
176
 
115
- // List posts
177
+ // 게시글 목록
116
178
  const { data: posts } = await client.boards.listPosts('board-slug', {
117
179
  page: 1,
118
180
  per_page: 10,
119
181
  search: 'keyword',
120
182
  });
121
183
 
122
- // Get post
184
+ // 게시글 상세
123
185
  const post = await client.boards.getPost(postId);
124
186
 
125
- // Create post (auth required)
187
+ // 게시글 작성 (인증 필요)
126
188
  await client.boards.createPost({
127
189
  board_id: 1,
128
190
  title: 'Title',
129
191
  content: 'Content',
192
+ is_secret: false,
130
193
  });
131
194
 
132
- // Update/Delete post (auth required)
195
+ // 게시글 수정/삭제
133
196
  await client.boards.updatePost(postId, { title: 'New Title' });
134
197
  await client.boards.deletePost(postId);
135
198
  ```
136
199
 
137
- ### Comments
200
+ ---
201
+
202
+ ## Comments API
138
203
 
139
- Supports three comment types: board posts, blog posts, and standalone pages (guestbook).
204
+ 게시판, 블로그, 독립 댓글(방명록) 지원
140
205
 
141
206
  ```typescript
142
- // Board post comments
207
+ // 게시판 댓글
143
208
  const { data } = await client.comments.boardPost(postId);
144
209
  await client.comments.createBoardPost(postId, {
145
210
  author_name: 'John',
146
- content: 'Great post!',
147
- password: '1234', // For guest comments
211
+ content: 'Great!',
212
+ password: '1234', // 비회원 댓글
148
213
  });
149
214
 
150
- // Blog post comments
215
+ // 블로그 댓글
151
216
  const { data } = await client.comments.blogPost('post-slug');
152
217
  await client.comments.createBlogPost('post-slug', {
153
- author_name: 'Jane',
154
218
  content: 'Nice article!',
155
219
  });
156
220
 
157
- // Standalone comments (guestbook)
221
+ // 독립 댓글 (방명록)
158
222
  const { data } = await client.comments.standalone('guestbook');
159
223
  await client.comments.createStandalone('guestbook', {
160
224
  author_name: 'Visitor',
161
225
  content: 'Hello!',
162
226
  });
163
227
 
164
- // Common operations
228
+ // 공통
165
229
  await client.comments.update(commentId, { content: 'Updated' });
166
230
  await client.comments.delete(commentId, { password: '1234' });
167
231
  await client.comments.like(commentId);
168
232
  ```
169
233
 
170
- ### Shop
234
+ ---
235
+
236
+ ## Shop API
237
+
238
+ ### 상품
171
239
 
172
240
  ```typescript
173
- // Products
241
+ // 상품 목록
174
242
  const { data: products } = await client.shop.listProducts({
175
- category: 'electronics',
243
+ category: 'shoes',
176
244
  is_featured: true,
245
+ min_price: 10000,
246
+ max_price: 50000,
247
+ search: 'keyword',
177
248
  });
249
+
250
+ // 상품 상세
178
251
  const product = await client.shop.getProduct('product-slug');
252
+
253
+ // 추천 상품
179
254
  const featured = await client.shop.featuredProducts(8);
255
+
256
+ // 카테고리 목록
180
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
+ ### 장바구니 (인증 필요)
181
293
 
182
- // Cart (auth required)
294
+ ```typescript
295
+ // 장바구니 조회
183
296
  const cart = await client.shop.getCart();
184
- await client.shop.addToCart({ product_id: 1, quantity: 2 });
297
+
298
+ // 상품 추가
299
+ await client.shop.addToCart({
300
+ product_id: 1,
301
+ quantity: 2,
302
+ variant_id: 3, // 옵션 상품
303
+ });
304
+
305
+ // 수량 변경
185
306
  await client.shop.updateCartItem(itemId, { quantity: 3 });
307
+
308
+ // 상품 제거
186
309
  await client.shop.removeFromCart(itemId);
310
+
311
+ // 장바구니 비우기
187
312
  await client.shop.clearCart();
313
+ ```
188
314
 
189
- // Orders (auth required)
315
+ ### 주문 (인증 필요)
316
+
317
+ ```typescript
318
+ // 주문 생성
190
319
  const order = await client.shop.createOrder({
191
320
  orderer_name: 'John Doe',
192
321
  orderer_email: 'john@example.com',
193
- orderer_phone: '555-1234',
322
+ orderer_phone: '010-1234-5678',
194
323
  shipping_name: 'John Doe',
195
- shipping_phone: '555-1234',
324
+ shipping_phone: '010-1234-5678',
196
325
  shipping_zipcode: '12345',
197
- shipping_address: '123 Main St',
198
- shipping_address_detail: 'Apt 101',
326
+ shipping_address: '서울시 강남구',
327
+ shipping_address_detail: '101동 101',
328
+ shipping_memo: '부재시 경비실',
329
+ coupon_code: 'SAVE10',
199
330
  });
331
+
332
+ // 주문 목록
200
333
  const { data: orders } = await client.shop.listOrders();
334
+
335
+ // 주문 상세
201
336
  const orderDetail = await client.shop.getOrder(orderId);
337
+
338
+ // 주문 취소
202
339
  await client.shop.cancelOrder(orderId);
340
+ ```
341
+
342
+ ### 결제 (토스페이먼츠)
203
343
 
204
- // Coupons
205
- const validation = await client.shop.validateCoupon('SAVE10', 50000);
206
- const myCoupons = await client.shop.myCoupons();
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
+ });
207
359
  ```
208
360
 
209
- ### Reservation
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
210
384
 
211
385
  ```typescript
212
- // Public APIs
386
+ // 예약 설정
213
387
  const settings = await client.reservation.getSettings();
388
+
389
+ // 서비스 목록
214
390
  const services = await client.reservation.listServices();
391
+
392
+ // 담당자 목록
215
393
  const staff = await client.reservation.listStaff(serviceId);
216
394
 
217
- // Get available dates/slots
395
+ // 예약 가능 날짜
218
396
  const dates = await client.reservation.getAvailableDates({
219
397
  service_id: 1,
220
398
  staff_id: 2,
221
399
  start_date: '2026-01-01',
222
400
  end_date: '2026-01-31',
223
401
  });
402
+
403
+ // 예약 가능 시간
224
404
  const slots = await client.reservation.getAvailableSlots({
225
405
  service_id: 1,
226
406
  date: '2026-01-15',
227
407
  staff_id: 2,
228
408
  });
409
+ ```
229
410
 
230
- // Create reservation (auth required)
231
- const result = await client.reservation.create({
411
+ ### 예약 관리 (인증 필요)
412
+
413
+ ```typescript
414
+ // 예약 생성
415
+ await client.reservation.create({
232
416
  service_id: 1,
233
417
  staff_id: 2,
234
418
  reservation_date: '2026-01-15',
235
419
  start_time: '14:00',
236
420
  customer_name: 'John Doe',
237
- customer_phone: '555-1234',
421
+ customer_phone: '010-1234-5678',
422
+ customer_email: 'john@example.com',
423
+ notes: '요청사항',
238
424
  });
239
425
 
240
- // My reservations (auth required)
426
+ // 예약 목록
241
427
  const { data } = await client.reservation.list({ status: 'confirmed' });
428
+
429
+ // 다가오는/지난 예약
242
430
  const upcoming = await client.reservation.upcoming(5);
243
431
  const past = await client.reservation.past(10);
244
- await client.reservation.cancel('RES-20260115-001', 'Schedule change');
432
+
433
+ // 예약 취소
434
+ await client.reservation.cancel('RES-20260115-001', '일정 변경');
245
435
  ```
246
436
 
247
- ### Forms
437
+ ---
438
+
439
+ ## Forms API
248
440
 
249
441
  ```typescript
250
- // List forms
442
+ // 목록
251
443
  const { data: forms } = await client.forms.list();
252
444
 
253
- // Get form with fields
445
+ // 상세 (필드 정보 포함)
254
446
  const form = await client.forms.get('contact');
255
447
 
256
- // Submit form
448
+ // 제출
257
449
  await client.forms.submit('contact', {
258
450
  name: 'John Doe',
259
451
  email: 'john@example.com',
260
452
  message: 'Hello!',
261
453
  });
262
454
 
263
- // My submissions (auth required)
455
+ // 제출 목록 (인증 필요)
264
456
  const { data: submissions } = await client.forms.mySubmissions();
265
457
  ```
266
458
 
267
- ### Media (Auth Required)
459
+ ---
460
+
461
+ ## Media API (인증 필요)
268
462
 
269
463
  ```typescript
270
- // Upload
464
+ // 파일 업로드
271
465
  const media = await client.media.upload(file);
466
+
467
+ // 여러 파일 업로드
272
468
  const mediaList = await client.media.uploadMultiple([file1, file2]);
273
469
 
274
- // List & Delete
470
+ // 미디어 목록
275
471
  const { data: myMedia } = await client.media.list({ type: 'image/jpeg' });
472
+
473
+ // 미디어 삭제
276
474
  await client.media.delete(mediaId);
277
475
  ```
278
476
 
279
- ### Custom Entities
477
+ ---
478
+
479
+ ## Custom Entities API
480
+
481
+ 동적 데이터 구조 생성/관리
280
482
 
281
- Dynamic data structures for custom use cases.
483
+ ### 엔티티 정의
282
484
 
283
485
  ```typescript
284
- // Entity definitions
486
+ // 엔티티 목록
285
487
  const entities = await client.entities.list();
488
+
489
+ // 엔티티 조회
286
490
  const entity = await client.entities.get('customers');
287
491
 
492
+ // 엔티티 생성
288
493
  await client.entities.create({
289
494
  name: 'Customer',
290
495
  slug: 'customers',
@@ -300,74 +505,57 @@ await client.entities.create({
300
505
  },
301
506
  });
302
507
 
508
+ // 엔티티 수정/삭제
303
509
  await client.entities.update('customers', { name: 'Clients' });
304
- await client.entities.delete('customers', true); // force delete
510
+ await client.entities.delete('customers', true); // force
511
+ ```
305
512
 
306
- // Records
513
+ ### 레코드
514
+
515
+ ```typescript
516
+ // 레코드 목록
307
517
  const { data: records } = await client.entities.listRecords('customers', {
308
518
  search: 'ACME',
309
519
  filters: JSON.stringify({ status: 'active' }),
310
520
  });
521
+
522
+ // 레코드 조회
311
523
  const record = await client.entities.getRecord('customers', 1);
312
524
 
525
+ // 레코드 생성
313
526
  await client.entities.createRecord('customers', {
314
527
  company: 'ACME Corp',
315
528
  email: 'contact@acme.com',
316
529
  status: 'active',
317
530
  });
531
+
532
+ // 레코드 수정/삭제
318
533
  await client.entities.updateRecord('customers', 1, { status: 'inactive' });
319
534
  await client.entities.deleteRecord('customers', 1);
535
+ ```
320
536
 
321
- // TypeScript support
537
+ ### TypeScript 지원
538
+
539
+ ```typescript
322
540
  interface Customer {
323
541
  company: string;
324
542
  email: string;
325
543
  status: 'active' | 'inactive';
326
544
  }
545
+
327
546
  const customers = client.entities.typed<Customer>('customers');
328
- const { data } = await customers.list();
547
+ const { data } = await customers.list(); // data: Customer[]
329
548
  ```
330
549
 
331
- ### Auth
550
+ ---
332
551
 
333
- ```typescript
334
- // Register
335
- await client.auth.register({
336
- name: 'John Doe',
337
- email: 'john@example.com',
338
- password: 'password',
339
- password_confirmation: 'password',
340
- });
552
+ ## 응답 타입
341
553
 
342
- // Login/Logout
343
- const { member, token } = await client.auth.login({
344
- email: 'john@example.com',
345
- password: 'password',
346
- });
347
- await client.auth.logout();
348
-
349
- // Profile
350
- const me = await client.auth.me();
351
- await client.auth.updateProfile({ name: 'New Name' });
352
-
353
- // Token management
354
- client.setToken('saved-token');
355
- const token = client.getToken();
356
- client.isAuthenticated();
357
-
358
- // Social login
359
- const providers = await client.auth.getSocialProviders();
360
- const { url } = await client.auth.getSocialAuthUrl('google');
361
- const response = await client.auth.socialCallback('google', code);
362
- ```
363
-
364
- ## Response Types
365
-
366
- All list APIs return a consistent format:
554
+ 모든 목록 API는 일관된 형식 반환:
367
555
 
368
556
  ```typescript
369
557
  interface ListResponse<T> {
370
- data: T[]; // Always an array, never null
558
+ data: T[]; // 항상 배열, null 아님
371
559
  meta: {
372
560
  current_page: number;
373
561
  last_page: number;
@@ -379,7 +567,9 @@ interface ListResponse<T> {
379
567
  }
380
568
  ```
381
569
 
382
- ## Error Handling
570
+ ---
571
+
572
+ ## 에러 처리
383
573
 
384
574
  ```typescript
385
575
  import { Promptly, PromptlyError } from '@back23/promptly-sdk';
@@ -395,15 +585,21 @@ try {
395
585
  }
396
586
  ```
397
587
 
398
- ## React Example
588
+ ---
589
+
590
+ ## React 예시
399
591
 
400
592
  ```tsx
593
+ 'use client';
594
+
401
595
  import { useState, useEffect } from 'react';
402
596
  import { Promptly } from '@back23/promptly-sdk';
403
597
 
598
+ // 싱글톤 클라이언트
404
599
  const client = new Promptly({
405
- tenantId: 'demo',
600
+ tenantId: process.env.NEXT_PUBLIC_PROMPTLY_TENANT_ID!,
406
601
  apiKey: process.env.NEXT_PUBLIC_PROMPTLY_API_KEY!,
602
+ persistToken: true,
407
603
  });
408
604
 
409
605
  function BlogList() {
@@ -424,8 +620,6 @@ function BlogList() {
424
620
  <article key={post.id}>
425
621
  <h2>{post.title}</h2>
426
622
  <p>{post.excerpt}</p>
427
- <span>{post.category}</span>
428
- {post.tags.map(tag => <span key={tag}>{tag}</span>)}
429
623
  </article>
430
624
  ))}
431
625
  </div>
@@ -433,25 +627,41 @@ function BlogList() {
433
627
  }
434
628
  ```
435
629
 
630
+ ---
631
+
436
632
  ## Changelog
437
633
 
634
+ ### v2.18.0
635
+ - 상품 리뷰 API 추가
636
+ - 배송 설정 API 추가
637
+
638
+ ### v2.15.0
639
+ - 토스페이먼츠 결제 API 추가
640
+
438
641
  ### v2.12.0
439
- - Added `category`, `tags`, `views`, `published_at` fields to BlogPost response
440
- - Added `GET /blog/categories` and `GET /blog/tags` endpoints
642
+ - 블로그 카테고리/태그 필터 추가
643
+ - `category`, `tags`, `views`, `published_at` 필드 추가
644
+
645
+ ### v2.10.0
646
+ - `persistToken` 옵션 추가 (토큰 자동 저장)
647
+ - `onAuthStateChange` 콜백 추가
648
+ - `storageType` 옵션 추가
441
649
 
442
650
  ### v2.5.0
443
- - Added `is_secret` and `is_mine` fields to BoardPost
651
+ - 게시판 비밀글 지원 (`is_secret`, `is_mine`)
444
652
 
445
653
  ### v2.3.0
446
- - Polymorphic comments API (board, blog, standalone)
654
+ - 다형성 댓글 API (board, blog, standalone)
447
655
 
448
656
  ### v2.0.0
449
- - **Breaking:** API key required for all requests
657
+ - **Breaking:** API key 필수
450
658
 
451
659
  ### v1.3.0
452
- - Unified `ListResponse<T>` format for all list APIs
453
- - Reservation system support
660
+ - `ListResponse<T>` 통일
661
+ - 예약 시스템 지원
662
+
663
+ ---
454
664
 
455
- ## License
665
+ ## 라이선스
456
666
 
457
667
  MIT