@back23/promptly-sdk 2.4.0 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,23 +24,40 @@ const { data: posts } = await client.blog.list();
24
24
  const products = await client.shop.listProducts();
25
25
  ```
26
26
 
27
+ ## v2.5.0 Changes
28
+
29
+ ### BoardPost Type Extension
30
+
31
+ Added `is_secret` and `is_mine` fields to posts.
32
+
33
+ ```typescript
34
+ interface BoardPost {
35
+ // ... existing fields
36
+ is_notice: boolean; // Whether it's a notice
37
+ is_secret: boolean; // Whether it's a secret post
38
+ is_mine: boolean; // Whether current logged-in user is the author
39
+ }
40
+ ```
41
+
42
+ ---
43
+
27
44
  ## v2.3.1 Changes (Bug Fix)
28
45
 
29
46
  ### Dual Authentication Support Fixed
30
47
 
31
- API Key Bearer Token 동시에 전송되도록 수정되었습니다. 이전 버전에서는 API Key 설정되어 있으면 Authorization 헤더가 무시되어 로그인 멤버 전용 API 호출이 실패하는 문제가 있었습니다.
48
+ Fixed issue where API Key and Bearer Token are now sent simultaneously. In previous versions, when API Key was set, the Authorization header was ignored, causing member-only API calls to fail after login.
32
49
 
33
50
  ```typescript
34
- // 이제 API Key + Bearer Token 동시 사용 가능
51
+ // API Key + Bearer Token now work together
35
52
  const client = new Promptly({
36
53
  tenantId: 'demo',
37
- apiKey: 'pky_xxx', // X-API-Key 헤더
54
+ apiKey: 'pky_xxx', // X-API-Key header
38
55
  });
39
56
 
40
- // 로그인 토큰 설정
57
+ // Set token after login
41
58
  await client.auth.login({ email, password });
42
59
 
43
- // 멤버 전용 API 정상 동작 (Authorization: Bearer xxx 헤더 포함)
60
+ // Member-only APIs work correctly (Authorization: Bearer xxx header included)
44
61
  const profile = await client.members.getProfile();
45
62
  const orders = await client.orders.list();
46
63
  ```
@@ -51,33 +68,33 @@ const orders = await client.orders.list();
51
68
 
52
69
  ### Polymorphic Comments API
53
70
 
54
- 댓글 시스템이 재설계되어 게시판, 블로그, 방명록(독립 페이지) 다양한 곳에서 사용할 있습니다.
71
+ The comment system has been redesigned to support various use cases including boards, blogs, and guestbooks (standalone pages).
55
72
 
56
73
  ```typescript
57
- // 게시판 댓글
74
+ // Board post comments
58
75
  const boardComments = await client.comments.boardPost(postId);
59
76
  await client.comments.createBoardPost(postId, {
60
- author_name: '홍길동',
61
- content: '댓글 내용',
62
- password: '1234', // 비회원 댓글용
77
+ author_name: 'John Doe',
78
+ content: 'Comment content',
79
+ password: '1234', // For guest comments
63
80
  });
64
81
 
65
- // 블로그 댓글
82
+ // Blog post comments
66
83
  const blogComments = await client.comments.blogPost('post-slug');
67
84
  await client.comments.createBlogPost('post-slug', {
68
85
  author_name: 'Jane',
69
86
  content: 'Great post!',
70
87
  });
71
88
 
72
- // 방명록 (독립 페이지)
89
+ // Guestbook (standalone page)
73
90
  const guestbook = await client.comments.standalone('guestbook');
74
91
  await client.comments.createStandalone('guestbook', {
75
- author_name: '방문자',
76
- content: '안녕하세요!',
92
+ author_name: 'Visitor',
93
+ content: 'Hello!',
77
94
  });
78
95
 
79
- // 공통 기능
80
- await client.comments.update(commentId, { content: '수정된 댓글' });
96
+ // Common features
97
+ await client.comments.update(commentId, { content: 'Updated comment' });
81
98
  await client.comments.delete(commentId, { password: '1234' });
82
99
  await client.comments.like(commentId);
83
100
  ```
@@ -88,46 +105,46 @@ await client.comments.like(commentId);
88
105
 
89
106
  ### Entity Definition CRUD
90
107
 
91
- 이제 API/SDK에서 직접 커스텀 엔티티 정의를 생성/수정/삭제할 있습니다.
108
+ You can now create/update/delete custom entity definitions directly from the API/SDK.
92
109
 
93
110
  ```typescript
94
- // 엔티티 정의 생성
111
+ // Create entity definition
95
112
  const entity = await client.entities.create({
96
- name: '고객',
113
+ name: 'Customer',
97
114
  slug: 'customers', // optional, auto-generated from name
98
- description: '고객 관리',
115
+ description: 'Customer management',
99
116
  schema: {
100
117
  fields: [
101
- { name: 'company', label: '회사명', type: 'text', required: true },
102
- { name: 'email', label: '이메일', type: 'email', required: true },
103
- { name: 'status', label: '상태', type: 'select', options: [
104
- { value: 'active', label: '활성' },
105
- { value: 'inactive', label: '비활성' }
118
+ { name: 'company', label: 'Company Name', type: 'text', required: true },
119
+ { name: 'email', label: 'Email', type: 'email', required: true },
120
+ { name: 'status', label: 'Status', type: 'select', options: [
121
+ { value: 'active', label: 'Active' },
122
+ { value: 'inactive', label: 'Inactive' }
106
123
  ]}
107
124
  ]
108
125
  },
109
126
  icon: 'users'
110
127
  });
111
128
 
112
- // 엔티티 정의 조회
129
+ // Get entity definition
113
130
  const entity = await client.entities.get('customers');
114
131
 
115
- // 엔티티 정의 수정
116
- await client.entities.update('customers', { name: '고객사' });
132
+ // Update entity definition
133
+ await client.entities.update('customers', { name: 'Clients' });
117
134
 
118
- // 엔티티 정의 삭제 (레코드 있으면 force 필요)
135
+ // Delete entity definition (requires force if records exist)
119
136
  await client.entities.delete('customers', true);
120
137
  ```
121
138
 
122
139
  ### Record API Path Change
123
140
 
124
- 레코드 API 경로가 변경되었습니다:
141
+ The record API path has changed:
125
142
 
126
143
  ```typescript
127
- // v2.1.0 이전
144
+ // Before v2.1.0
128
145
  await client.entities.createRecord('customers', { data: { company: 'ACME' } });
129
146
 
130
- // v2.2.0 이후 - data wrapper 불필요
147
+ // v2.2.0 and later - no data wrapper needed
131
148
  await client.entities.createRecord('customers', { company: 'ACME' });
132
149
  ```
133
150
 
@@ -208,275 +225,275 @@ data.map(post => ...); // data is always an array
208
225
 
209
226
  ## API Reference
210
227
 
211
- ### Boards (게시판)
228
+ ### Boards
212
229
 
213
230
  ```typescript
214
- // 게시판 목록
231
+ // List boards
215
232
  const { data: boards, meta } = await client.boards.list();
216
233
  // Returns: ListResponse<Board>
217
234
 
218
- // 게시판 상세
235
+ // Get board details
219
236
  const board = await client.boards.get('first'); // slug or id
220
237
  // Returns: Board
221
238
 
222
- // 게시판 목록
239
+ // List board posts
223
240
  const { data: posts, meta } = await client.boards.listPosts('first', {
224
241
  page: 1,
225
242
  per_page: 10,
226
- search: '검색어', // optional
243
+ search: 'keyword', // optional
227
244
  });
228
245
  // Returns: ListResponse<BoardPost>
229
246
 
230
- // 상세
247
+ // Get post details
231
248
  const post = await client.boards.getPost(1);
232
249
  // Returns: BoardPost
233
250
 
234
- // 댓글 목록
251
+ // List comments
235
252
  const comments = await client.boards.listComments(1);
236
253
  // Returns: BoardComment[] (always an array)
237
254
  ```
238
255
 
239
- ### Posts & Comments - Protected (로그인 필요)
256
+ ### Posts & Comments - Protected (Login Required)
240
257
 
241
258
  ```typescript
242
- // 먼저 로그인
259
+ // Login first
243
260
  await client.auth.login({ email: 'user@example.com', password: 'password' });
244
261
 
245
- // 작성
262
+ // Create post
246
263
  const newPost = await client.boards.createPost({
247
264
  board_id: 1,
248
- title: '제목',
249
- content: '내용',
265
+ title: 'Title',
266
+ content: 'Content',
250
267
  is_notice: false,
251
268
  });
252
269
 
253
- // 수정
270
+ // Update post
254
271
  await client.boards.updatePost(postId, {
255
- title: '수정된 제목',
256
- content: '수정된 내용',
272
+ title: 'Updated title',
273
+ content: 'Updated content',
257
274
  });
258
275
 
259
- // 삭제
276
+ // Delete post
260
277
  await client.boards.deletePost(postId);
261
278
 
262
- // 댓글 작성
279
+ // Create comment
263
280
  await client.boards.createComment(postId, {
264
- content: '댓글 내용',
265
- parent_id: null, // 대댓글이면 부모 댓글 ID
281
+ content: 'Comment content',
282
+ parent_id: null, // Parent comment ID for replies
266
283
  });
267
284
 
268
- // 댓글 수정
285
+ // Update comment
269
286
  await client.boards.updateComment(commentId, {
270
- content: '수정된 댓글',
287
+ content: 'Updated comment',
271
288
  });
272
289
 
273
- // 댓글 삭제
290
+ // Delete comment
274
291
  await client.boards.deleteComment(commentId);
275
292
  ```
276
293
 
277
- ### Blog (블로그)
294
+ ### Blog
278
295
 
279
296
  ```typescript
280
- // 블로그 목록
297
+ // List blog posts
281
298
  const { data: posts, meta } = await client.blog.list({
282
299
  page: 1,
283
300
  per_page: 10,
284
301
  category: 'news', // optional
285
302
  tag: 'featured', // optional
286
- search: '검색어', // optional
303
+ search: 'keyword', // optional
287
304
  });
288
305
  // Returns: ListResponse<BlogPost>
289
306
 
290
- // 블로그 상세
307
+ // Get blog post details
291
308
  const post = await client.blog.get('post-slug');
292
309
  // Returns: BlogPost
293
310
 
294
- // 추천
311
+ // Featured posts
295
312
  const featured = await client.blog.featured(5);
296
313
  // Returns: BlogPost[] (always an array)
297
314
 
298
- // 카테고리별 조회
315
+ // Get posts by category
299
316
  const { data: newsPosts } = await client.blog.byCategory('news');
300
317
 
301
- // 태그별 조회
318
+ // Get posts by tag
302
319
  const { data: taggedPosts } = await client.blog.byTag('featured');
303
320
 
304
- // 카테고리 목록
321
+ // List categories
305
322
  const categories = await client.blog.categories();
306
323
  // Returns: string[] (always an array)
307
324
 
308
- // 태그 목록
325
+ // List tags
309
326
  const tags = await client.blog.tags();
310
327
  // Returns: string[] (always an array)
311
328
  ```
312
329
 
313
- ### Comments (댓글)
330
+ ### Comments
314
331
 
315
- 3가지 댓글 유형을 지원합니다:
316
- - **게시판 댓글** (`board_post`)
317
- - **블로그 댓글** (`blog_post`)
318
- - **방명록/독립 댓글** (`page`)
332
+ Three comment types are supported:
333
+ - **Board comments** (`board_post`)
334
+ - **Blog comments** (`blog_post`)
335
+ - **Guestbook/Standalone comments** (`page`)
319
336
 
320
337
  ```typescript
321
- // 게시판 댓글 조회
338
+ // Get board post comments
322
339
  const { data: comments, meta } = await client.comments.boardPost(postId, {
323
340
  page: 1,
324
341
  per_page: 20,
325
342
  });
326
343
  // Returns: ListResponse<Comment>
327
344
 
328
- // 게시판 댓글 작성
345
+ // Create board post comment
329
346
  await client.comments.createBoardPost(postId, {
330
- author_name: '홍길동',
347
+ author_name: 'John Doe',
331
348
  author_email: 'user@example.com',
332
- content: '댓글 내용',
333
- password: '1234', // 비회원용
334
- parent_id: null, // 대댓글이면 부모 댓글 ID
335
- is_secret: false, // 비밀 댓글 여부
349
+ content: 'Comment content',
350
+ password: '1234', // For guest comments
351
+ parent_id: null, // Parent comment ID for replies
352
+ is_secret: false, // Secret comment flag
336
353
  });
337
354
 
338
- // 블로그 댓글 조회
355
+ // Get blog post comments
339
356
  const { data: blogComments } = await client.comments.blogPost('post-slug');
340
357
  // Returns: ListResponse<Comment>
341
358
 
342
- // 블로그 댓글 작성
359
+ // Create blog post comment
343
360
  await client.comments.createBlogPost('post-slug', {
344
361
  author_name: 'Jane',
345
362
  content: 'Great post!',
346
363
  });
347
364
 
348
- // 방명록 댓글 조회 (page_slug로 구분)
365
+ // Get guestbook comments (identified by page_slug)
349
366
  const { data: guestbook } = await client.comments.standalone('guestbook');
350
367
  // Returns: ListResponse<Comment>
351
368
 
352
- // 방명록 댓글 작성
369
+ // Create guestbook comment
353
370
  await client.comments.createStandalone('guestbook', {
354
- author_name: '방문자',
355
- content: '안녕하세요!',
371
+ author_name: 'Visitor',
372
+ content: 'Hello!',
356
373
  });
357
374
 
358
- // 댓글 수정
375
+ // Update comment
359
376
  await client.comments.update(commentId, {
360
- content: '수정된 댓글',
361
- password: '1234', // 비회원이 작성한 댓글인 경우
377
+ content: 'Updated comment',
378
+ password: '1234', // Required for guest comments
362
379
  });
363
380
 
364
- // 댓글 삭제
381
+ // Delete comment
365
382
  await client.comments.delete(commentId, {
366
- password: '1234', // 비회원이 작성한 댓글인 경우
383
+ password: '1234', // Required for guest comments
367
384
  });
368
385
 
369
- // 댓글 좋아요
386
+ // Like comment
370
387
  const result = await client.comments.like(commentId);
371
388
  // Returns: { data: { likes: number } }
372
389
  ```
373
390
 
374
- ### Shop (쇼핑)
391
+ ### Shop
375
392
 
376
- #### Public (로그인 불필요)
393
+ #### Public (No Login Required)
377
394
 
378
395
  ```typescript
379
- // 상품 목록
396
+ // List products
380
397
  const { data: products, meta } = await client.shop.listProducts({
381
398
  page: 1,
382
399
  per_page: 10,
383
400
  category: 'electronics', // optional
384
401
  is_featured: true, // optional
385
- search: '검색어', // optional
402
+ search: 'keyword', // optional
386
403
  });
387
404
  // Returns: ListResponse<Product>
388
405
 
389
- // 상품 상세
406
+ // Get product details
390
407
  const product = await client.shop.getProduct('product-slug');
391
408
  // Returns: Product
392
409
 
393
- // 추천 상품
410
+ // Featured products
394
411
  const featured = await client.shop.featuredProducts(8);
395
412
  // Returns: Product[] (always an array)
396
413
 
397
- // 카테고리 목록
414
+ // List categories
398
415
  const categories = await client.shop.listCategories();
399
416
  // Returns: ProductCategory[] (always an array)
400
417
  ```
401
418
 
402
- #### Protected (로그인 필요)
419
+ #### Protected (Login Required)
403
420
 
404
421
  ```typescript
405
- // 장바구니 조회
422
+ // Get cart
406
423
  const cart = await client.shop.getCart();
407
424
  // Returns: Cart
408
425
 
409
- // 장바구니 추가
426
+ // Add to cart
410
427
  await client.shop.addToCart({
411
428
  product_id: 1,
412
429
  quantity: 2,
413
- variant_id: 10, // optional - 옵션상품인 경우
430
+ variant_id: 10, // optional - for variant products
414
431
  });
415
432
 
416
- // 장바구니 수량 변경
433
+ // Update cart item quantity
417
434
  await client.shop.updateCartItem(itemId, { quantity: 3 });
418
435
 
419
- // 장바구니 삭제
436
+ // Remove from cart
420
437
  await client.shop.removeFromCart(itemId);
421
438
 
422
- // 장바구니 비우기
439
+ // Clear cart
423
440
  await client.shop.clearCart();
424
441
 
425
- // 주문 생성
442
+ // Create order
426
443
  const order = await client.shop.createOrder({
427
- orderer_name: '홍길동',
428
- orderer_email: 'hong@example.com',
429
- orderer_phone: '010-1234-5678',
430
- shipping_name: '홍길동',
431
- shipping_phone: '010-1234-5678',
444
+ orderer_name: 'John Doe',
445
+ orderer_email: 'john@example.com',
446
+ orderer_phone: '555-123-4567',
447
+ shipping_name: 'John Doe',
448
+ shipping_phone: '555-123-4567',
432
449
  shipping_zipcode: '12345',
433
- shipping_address: '서울시 강남구',
434
- shipping_address_detail: '101',
435
- shipping_memo: ' 앞에 놓아주세요',
450
+ shipping_address: '123 Main St',
451
+ shipping_address_detail: 'Apt 101',
452
+ shipping_memo: 'Leave at door',
436
453
  coupon_code: 'SAVE10', // optional
437
454
  });
438
455
 
439
- // 주문 목록
456
+ // List orders
440
457
  const { data: orders, meta } = await client.shop.listOrders();
441
458
  // Returns: ListResponse<Order>
442
459
 
443
- // 주문 상세
460
+ // Get order details
444
461
  const order = await client.shop.getOrder(orderId);
445
462
  // Returns: Order
446
463
 
447
- // 주문 취소
464
+ // Cancel order
448
465
  await client.shop.cancelOrder(orderId);
449
466
 
450
- // 쿠폰 검증
467
+ // Validate coupon
451
468
  const validation = await client.shop.validateCoupon('SAVE10', 50000);
452
469
  // Returns: { valid: boolean, discount_amount: number, coupon: Coupon }
453
470
 
454
- // 쿠폰 목록
471
+ // My coupons
455
472
  const coupons = await client.shop.myCoupons();
456
473
  // Returns: Coupon[] (always an array)
457
474
  ```
458
475
 
459
- ### Reservation (예약) - NEW in v1.3.0
476
+ ### Reservation - NEW in v1.3.0
460
477
 
461
- #### Public (로그인 불필요)
478
+ #### Public (No Login Required)
462
479
 
463
480
  ```typescript
464
- // 예약 설정 조회
481
+ // Get reservation settings
465
482
  const settings = await client.reservation.getSettings();
466
483
  // Returns: ReservationSettings
467
484
 
468
- // 서비스 목록
485
+ // List services
469
486
  const services = await client.reservation.listServices();
470
487
  // Returns: ReservationService[] (always an array)
471
488
 
472
- // 담당자 목록
489
+ // List staff
473
490
  const staffs = await client.reservation.listStaff();
474
491
  // Returns: ReservationStaff[] (always an array)
475
492
 
476
- // 특정 서비스의 담당자만 조회
493
+ // Get staff for specific service
477
494
  const serviceStaffs = await client.reservation.listStaff(serviceId);
478
495
 
479
- // 예약 가능 날짜 조회
496
+ // Get available dates
480
497
  const dates = await client.reservation.getAvailableDates({
481
498
  service_id: 1,
482
499
  staff_id: 2, // optional
@@ -485,7 +502,7 @@ const dates = await client.reservation.getAvailableDates({
485
502
  });
486
503
  // Returns: string[] (YYYY-MM-DD format)
487
504
 
488
- // 예약 가능 시간 슬롯 조회
505
+ // Get available time slots
489
506
  const slots = await client.reservation.getAvailableSlots({
490
507
  service_id: 1,
491
508
  date: '2026-01-15',
@@ -494,23 +511,23 @@ const slots = await client.reservation.getAvailableSlots({
494
511
  // Returns: ReservationSlot[]
495
512
  ```
496
513
 
497
- #### Protected (로그인 필요)
514
+ #### Protected (Login Required)
498
515
 
499
516
  ```typescript
500
- // 예약 생성
517
+ // Create reservation
501
518
  const result = await client.reservation.create({
502
519
  service_id: 1,
503
520
  staff_id: 2, // optional
504
521
  reservation_date: '2026-01-15',
505
522
  start_time: '14:00',
506
- customer_name: '홍길동',
507
- customer_phone: '010-1234-5678', // optional
508
- customer_email: 'hong@example.com', // optional
509
- customer_memo: '요청사항', // optional
523
+ customer_name: 'John Doe',
524
+ customer_phone: '555-123-4567', // optional
525
+ customer_email: 'john@example.com', // optional
526
+ customer_memo: 'Special requests', // optional
510
527
  });
511
528
  // Returns: { reservation: Reservation, requires_payment: boolean, deposit: number }
512
529
 
513
- // 예약 목록
530
+ // List my reservations
514
531
  const { data: reservations, meta } = await client.reservation.list({
515
532
  status: 'confirmed', // optional
516
533
  upcoming: true, // optional
@@ -518,124 +535,124 @@ const { data: reservations, meta } = await client.reservation.list({
518
535
  });
519
536
  // Returns: ListResponse<Reservation>
520
537
 
521
- // 다가오는 예약
538
+ // Upcoming reservations
522
539
  const upcoming = await client.reservation.upcoming(5);
523
540
  // Returns: Reservation[] (always an array)
524
541
 
525
- // 지난 예약
542
+ // Past reservations
526
543
  const past = await client.reservation.past(10);
527
544
  // Returns: Reservation[] (always an array)
528
545
 
529
- // 예약 상세
546
+ // Get reservation details
530
547
  const reservation = await client.reservation.get('RES-20260115-001');
531
548
  // Returns: Reservation
532
549
 
533
- // 예약 취소
534
- const cancelled = await client.reservation.cancel('RES-20260115-001', '일정 변경');
550
+ // Cancel reservation
551
+ const cancelled = await client.reservation.cancel('RES-20260115-001', 'Schedule change');
535
552
  // Returns: Reservation
536
553
  ```
537
554
 
538
- ### Auth (인증)
555
+ ### Auth (Authentication)
539
556
 
540
557
  ```typescript
541
- // 로그인
558
+ // Login
542
559
  const response = await client.auth.login({
543
560
  email: 'user@example.com',
544
561
  password: 'password',
545
562
  });
546
563
  // Returns: { member: Member, token: string }
547
- // 토큰은 자동으로 저장됨
564
+ // Token is automatically stored
548
565
 
549
- // 회원가입
566
+ // Register
550
567
  await client.auth.register({
551
- name: '홍길동',
568
+ name: 'John Doe',
552
569
  email: 'user@example.com',
553
570
  password: 'password',
554
571
  password_confirmation: 'password',
555
- phone: '010-1234-5678', // optional
572
+ phone: '555-123-4567', // optional
556
573
  });
557
574
 
558
- // 로그아웃
575
+ // Logout
559
576
  await client.auth.logout();
560
577
 
561
- // 정보 조회
578
+ // Get current user
562
579
  const me = await client.auth.me();
563
580
  // Returns: Member
564
581
 
565
- // 프로필 수정
582
+ // Update profile
566
583
  await client.auth.updateProfile({
567
- name: '새이름',
568
- phone: '010-9999-8888',
584
+ name: 'New Name',
585
+ phone: '555-999-8888',
569
586
  });
570
587
 
571
- // 비밀번호 변경
588
+ // Change password
572
589
  await client.auth.updateProfile({
573
- current_password: '현재비밀번호',
574
- password: '새비밀번호',
575
- password_confirmation: '새비밀번호',
590
+ current_password: 'current_password',
591
+ password: 'new_password',
592
+ password_confirmation: 'new_password',
576
593
  });
577
594
 
578
- // 인증 여부 확인
595
+ // Check authentication status
579
596
  client.isAuthenticated(); // true or false
580
597
 
581
- // 토큰 직접 설정 (localStorage에서 복원시)
598
+ // Set token directly (e.g., from localStorage)
582
599
  client.setToken('saved-token');
583
600
 
584
- // 토큰 가져오기
601
+ // Get token
585
602
  const token = client.getToken();
586
603
  ```
587
604
 
588
- #### 소셜 로그인
605
+ #### Social Login
589
606
 
590
607
  ```typescript
591
- // 소셜 로그인 제공자 목록
608
+ // Get social login providers
592
609
  const providers = await client.auth.getSocialProviders();
593
610
  // Returns: SocialProvider[]
594
611
 
595
- // 소셜 로그인 URL 가져오기
612
+ // Get social auth URL
596
613
  const { url } = await client.auth.getSocialAuthUrl('google');
597
- // 해당 URL로 리다이렉트
614
+ // Redirect to this URL
598
615
 
599
- // 콜백 처리 (리다이렉트 )
616
+ // Handle callback (after redirect)
600
617
  const response = await client.auth.socialCallback('google', code);
601
618
  // Returns: { member: Member, token: string }
602
619
  ```
603
620
 
604
- ### Forms (폼)
621
+ ### Forms
605
622
 
606
623
  ```typescript
607
- // 목록
624
+ // List forms
608
625
  const { data: forms } = await client.forms.list();
609
626
  // Returns: ListResponse<Form>
610
627
 
611
- // 상세
628
+ // Get form details
612
629
  const form = await client.forms.get('contact');
613
- // Returns: Form (필드 정보 포함)
630
+ // Returns: Form (includes field definitions)
614
631
 
615
- // 제출 (로그인 불필요)
632
+ // Submit form (no login required)
616
633
  await client.forms.submit('contact', {
617
- name: '홍길동',
634
+ name: 'John Doe',
618
635
  email: 'user@example.com',
619
- message: '문의 내용',
636
+ message: 'Inquiry content',
620
637
  });
621
638
 
622
- // 제출 목록 (로그인 필요)
639
+ // My submissions (login required)
623
640
  const { data: submissions } = await client.forms.mySubmissions();
624
641
  // Returns: ListResponse<FormSubmission>
625
642
  ```
626
643
 
627
- ### Media (미디어) - Protected
644
+ ### Media - Protected
628
645
 
629
646
  ```typescript
630
- // 파일 업로드
647
+ // Upload file
631
648
  const media = await client.media.upload(file); // File or Blob
632
649
  // Returns: Media
633
650
 
634
- // 여러 파일 업로드
651
+ // Upload multiple files
635
652
  const mediaList = await client.media.uploadMultiple([file1, file2]);
636
653
  // Returns: Media[]
637
654
 
638
- // 미디어 목록
655
+ // List my media
639
656
  const { data: mediaList, meta } = await client.media.list({
640
657
  page: 1,
641
658
  per_page: 20,
@@ -643,94 +660,94 @@ const { data: mediaList, meta } = await client.media.list({
643
660
  });
644
661
  // Returns: ListResponse<Media>
645
662
 
646
- // 미디어 삭제
663
+ // Delete media
647
664
  await client.media.delete(mediaId);
648
665
  ```
649
666
 
650
- ### Entities (커스텀 엔티티) - 동적 데이터 구조
667
+ ### Entities (Custom Entities) - Dynamic Data Structures
651
668
 
652
- API/SDK에서 직접 엔티티 정의를 생성하고 데이터를 관리할 있습니다.
669
+ Create entity definitions and manage data directly from the API/SDK.
653
670
 
654
671
  #### Entity Definition CRUD
655
672
 
656
673
  ```typescript
657
- // 엔티티 목록 조회
674
+ // List entities
658
675
  const entities = await client.entities.list();
659
676
  // Returns: CustomEntity[] (always an array)
660
677
 
661
- // 엔티티 정의 생성
678
+ // Create entity definition
662
679
  const entity = await client.entities.create({
663
- name: '고객',
680
+ name: 'Customer',
664
681
  slug: 'customers',
665
- description: '고객 관리',
682
+ description: 'Customer management',
666
683
  schema: {
667
684
  fields: [
668
- { name: 'company', label: '회사명', type: 'text', required: true },
669
- { name: 'email', label: '이메일', type: 'email', required: true },
670
- { name: 'status', label: '상태', type: 'select', options: [
671
- { value: 'active', label: '활성' },
672
- { value: 'inactive', label: '비활성' }
685
+ { name: 'company', label: 'Company Name', type: 'text', required: true },
686
+ { name: 'email', label: 'Email', type: 'email', required: true },
687
+ { name: 'status', label: 'Status', type: 'select', options: [
688
+ { value: 'active', label: 'Active' },
689
+ { value: 'inactive', label: 'Inactive' }
673
690
  ]}
674
691
  ]
675
692
  },
676
693
  icon: 'users'
677
694
  });
678
695
 
679
- // 엔티티 정의 조회 (스키마 포함)
696
+ // Get entity definition (includes schema)
680
697
  const entity = await client.entities.get('customers');
681
698
  // Returns: CustomEntity (includes schema)
682
699
 
683
- // 엔티티 정의 수정
700
+ // Update entity definition
684
701
  await client.entities.update('customers', {
685
- name: '고객사',
686
- description: '고객사 관리'
702
+ name: 'Clients',
703
+ description: 'Client management'
687
704
  });
688
705
 
689
- // 엔티티 정의 삭제 (레코드가 있으면 force 필요)
690
- await client.entities.delete('customers'); // 레코드 없을
691
- await client.entities.delete('customers', true); // 레코드 있어도 강제 삭제
706
+ // Delete entity definition (requires force if records exist)
707
+ await client.entities.delete('customers'); // When no records exist
708
+ await client.entities.delete('customers', true); // Force delete with records
692
709
  ```
693
710
 
694
711
  #### Record CRUD
695
712
 
696
713
  ```typescript
697
- // 레코드 목록 조회
714
+ // List records
698
715
  const { data: customers, meta } = await client.entities.listRecords('customers', {
699
716
  page: 1,
700
717
  per_page: 20,
701
- search: 'ACME', // 검색
702
- sort: 'company', // 정렬 필드
703
- dir: 'asc', // 정렬 방향
704
- filters: JSON.stringify({ status: 'active' }) // JSON 필터
718
+ search: 'ACME', // Search
719
+ sort: 'company', // Sort field
720
+ dir: 'asc', // Sort direction
721
+ filters: JSON.stringify({ status: 'active' }) // JSON filter
705
722
  });
706
723
  // Returns: ListResponse<EntityRecord>
707
724
 
708
- // 단일 레코드 조회
725
+ // Get single record
709
726
  const customer = await client.entities.getRecord('customers', 1);
710
727
  // Returns: EntityRecord
711
728
  console.log(customer.data.company); // 'ABC Corp'
712
729
 
713
- // 레코드 생성 (스키마 필드 직접 전달)
730
+ // Create record (pass schema fields directly)
714
731
  const newCustomer = await client.entities.createRecord('customers', {
715
732
  company: 'ABC Corp',
716
733
  email: 'contact@abc.com',
717
734
  status: 'active',
718
735
  });
719
736
 
720
- // 레코드 수정 (부분 업데이트 - 기존 데이터와 병합)
737
+ // Update record (partial update - merges with existing data)
721
738
  await client.entities.updateRecord('customers', 1, {
722
739
  status: 'inactive',
723
740
  email: 'new@abc.com'
724
741
  });
725
742
 
726
- // 레코드 삭제
743
+ // Delete record
727
744
  await client.entities.deleteRecord('customers', 1);
728
745
  ```
729
746
 
730
- #### TypeScript 타입 지원
747
+ #### TypeScript Type Support
731
748
 
732
749
  ```typescript
733
- // 타입이 지정된 엔티티 접근자
750
+ // Typed entity accessor
734
751
  interface Customer {
735
752
  company: string;
736
753
  email: string;
@@ -739,14 +756,14 @@ interface Customer {
739
756
 
740
757
  const customers = client.entities.typed<Customer>('customer');
741
758
 
742
- // 타입이 추론됨
759
+ // Type inference
743
760
  const list = await customers.list();
744
761
  list.data[0].data.company; // string
745
762
 
746
763
  const record = await customers.get(1);
747
764
  record.data.tier; // 'standard' | 'vip'
748
765
 
749
- // 생성/수정도 타입 체크
766
+ // Type checking on create/update
750
767
  await customers.create({
751
768
  company: 'New Corp',
752
769
  email: 'new@corp.com',
@@ -757,11 +774,11 @@ await customers.create({
757
774
  ### Site Settings
758
775
 
759
776
  ```typescript
760
- // 테마 설정
777
+ // Get theme settings
761
778
  const theme = await client.getTheme();
762
779
  // Returns: { name, colors, fonts }
763
780
 
764
- // 사이트 설정
781
+ // Get site settings
765
782
  const settings = await client.getSettings();
766
783
  // Returns: Record<string, any>
767
784
  ```
@@ -823,6 +840,8 @@ interface BoardPost {
823
840
  author: string;
824
841
  views: number;
825
842
  is_notice: boolean;
843
+ is_secret: boolean;
844
+ is_mine: boolean;
826
845
  is_private: boolean;
827
846
  comment_count: number;
828
847
  attachments?: Media[];
@@ -979,7 +998,7 @@ const client = new Promptly({
979
998
  baseUrl: 'https://promptly.webbyon.com',
980
999
  });
981
1000
 
982
- // 블로그 목록 (with pagination)
1001
+ // Blog post list (with pagination)
983
1002
  function BlogList() {
984
1003
  const [posts, setPosts] = useState([]);
985
1004
  const [meta, setMeta] = useState(null);
@@ -1023,7 +1042,7 @@ function BlogList() {
1023
1042
  );
1024
1043
  }
1025
1044
 
1026
- // 예약
1045
+ // Reservation form
1027
1046
  function ReservationForm() {
1028
1047
  const [services, setServices] = useState([]);
1029
1048
  const [selectedService, setSelectedService] = useState(null);
@@ -1053,7 +1072,7 @@ function ReservationForm() {
1053
1072
  return (
1054
1073
  <div>
1055
1074
  <select onChange={e => setSelectedService(Number(e.target.value))}>
1056
- <option>서비스 선택</option>
1075
+ <option>Select a service</option>
1057
1076
  {services.map(s => (
1058
1077
  <option key={s.id} value={s.id}>{s.name}</option>
1059
1078
  ))}
package/dist/index.d.mts CHANGED
@@ -149,6 +149,8 @@ interface BoardPost {
149
149
  author: string;
150
150
  views: number;
151
151
  is_notice: boolean;
152
+ is_secret: boolean;
153
+ is_mine: boolean;
152
154
  created_at: string;
153
155
  content?: string;
154
156
  updated_at?: string;
@@ -792,6 +794,7 @@ declare class HttpClient {
792
794
  private timeout;
793
795
  private token;
794
796
  private apiKey;
797
+ private cartSessionId;
795
798
  constructor(config: PromptlyConfig);
796
799
  /**
797
800
  * Set authentication token
@@ -813,6 +816,14 @@ declare class HttpClient {
813
816
  * Get current API key
814
817
  */
815
818
  getApiKey(): string | null;
819
+ /**
820
+ * Set cart session ID (for guest cart persistence)
821
+ */
822
+ setCartSessionId(sessionId: string | null): void;
823
+ /**
824
+ * Get cart session ID
825
+ */
826
+ getCartSessionId(): string | null;
816
827
  /**
817
828
  * Build full URL with query params
818
829
  */
@@ -1144,6 +1155,10 @@ declare class ShopResource {
1144
1155
  * @returns ListResponse with data array and pagination meta
1145
1156
  */
1146
1157
  categoryProducts(categoryIdOrSlug: number | string, params?: Omit<ProductListParams, 'category'>): Promise<ListResponse<Product>>;
1158
+ /**
1159
+ * Save cart session ID from response (for guest cart persistence)
1160
+ */
1161
+ private saveCartSession;
1147
1162
  /**
1148
1163
  * Get current cart
1149
1164
  */
package/dist/index.d.ts CHANGED
@@ -149,6 +149,8 @@ interface BoardPost {
149
149
  author: string;
150
150
  views: number;
151
151
  is_notice: boolean;
152
+ is_secret: boolean;
153
+ is_mine: boolean;
152
154
  created_at: string;
153
155
  content?: string;
154
156
  updated_at?: string;
@@ -792,6 +794,7 @@ declare class HttpClient {
792
794
  private timeout;
793
795
  private token;
794
796
  private apiKey;
797
+ private cartSessionId;
795
798
  constructor(config: PromptlyConfig);
796
799
  /**
797
800
  * Set authentication token
@@ -813,6 +816,14 @@ declare class HttpClient {
813
816
  * Get current API key
814
817
  */
815
818
  getApiKey(): string | null;
819
+ /**
820
+ * Set cart session ID (for guest cart persistence)
821
+ */
822
+ setCartSessionId(sessionId: string | null): void;
823
+ /**
824
+ * Get cart session ID
825
+ */
826
+ getCartSessionId(): string | null;
816
827
  /**
817
828
  * Build full URL with query params
818
829
  */
@@ -1144,6 +1155,10 @@ declare class ShopResource {
1144
1155
  * @returns ListResponse with data array and pagination meta
1145
1156
  */
1146
1157
  categoryProducts(categoryIdOrSlug: number | string, params?: Omit<ProductListParams, 'category'>): Promise<ListResponse<Product>>;
1158
+ /**
1159
+ * Save cart session ID from response (for guest cart persistence)
1160
+ */
1161
+ private saveCartSession;
1147
1162
  /**
1148
1163
  * Get current cart
1149
1164
  */
package/dist/index.js CHANGED
@@ -71,10 +71,14 @@ var HttpClient = class {
71
71
  constructor(config) {
72
72
  this.token = null;
73
73
  this.apiKey = null;
74
+ this.cartSessionId = null;
74
75
  this.tenantId = config.tenantId;
75
76
  this.baseUrl = (config.baseUrl || "https://promptly.webbyon.com").replace(/\/$/, "");
76
77
  this.timeout = config.timeout || 3e4;
77
78
  this.apiKey = config.apiKey || null;
79
+ if (typeof window !== "undefined" && window.localStorage) {
80
+ this.cartSessionId = localStorage.getItem(`promptly_cart_session_${this.tenantId}`);
81
+ }
78
82
  }
79
83
  /**
80
84
  * Set authentication token
@@ -106,6 +110,25 @@ var HttpClient = class {
106
110
  getApiKey() {
107
111
  return this.apiKey;
108
112
  }
113
+ /**
114
+ * Set cart session ID (for guest cart persistence)
115
+ */
116
+ setCartSessionId(sessionId) {
117
+ this.cartSessionId = sessionId;
118
+ if (typeof window !== "undefined" && window.localStorage) {
119
+ if (sessionId) {
120
+ localStorage.setItem(`promptly_cart_session_${this.tenantId}`, sessionId);
121
+ } else {
122
+ localStorage.removeItem(`promptly_cart_session_${this.tenantId}`);
123
+ }
124
+ }
125
+ }
126
+ /**
127
+ * Get cart session ID
128
+ */
129
+ getCartSessionId() {
130
+ return this.cartSessionId;
131
+ }
109
132
  /**
110
133
  * Build full URL with query params
111
134
  */
@@ -136,6 +159,9 @@ var HttpClient = class {
136
159
  if (this.token) {
137
160
  headers["Authorization"] = `Bearer ${this.token}`;
138
161
  }
162
+ if (this.cartSessionId) {
163
+ headers["X-Cart-Session"] = this.cartSessionId;
164
+ }
139
165
  return headers;
140
166
  }
141
167
  /**
@@ -712,35 +738,49 @@ var ShopResource = class {
712
738
  // ============================================
713
739
  // Cart
714
740
  // ============================================
741
+ /**
742
+ * Save cart session ID from response (for guest cart persistence)
743
+ */
744
+ saveCartSession(cart) {
745
+ if (cart.session_id) {
746
+ this.http.setCartSessionId(cart.session_id);
747
+ }
748
+ return cart;
749
+ }
715
750
  /**
716
751
  * Get current cart
717
752
  */
718
753
  async getCart() {
719
- return this.http.get("/cart");
754
+ const cart = await this.http.get("/cart");
755
+ return this.saveCartSession(cart);
720
756
  }
721
757
  /**
722
758
  * Add item to cart
723
759
  */
724
760
  async addToCart(data) {
725
- return this.http.post("/cart/items", data);
761
+ const cart = await this.http.post("/cart/items", data);
762
+ return this.saveCartSession(cart);
726
763
  }
727
764
  /**
728
765
  * Update cart item quantity
729
766
  */
730
767
  async updateCartItem(itemId, data) {
731
- return this.http.put(`/cart/items/${itemId}`, data);
768
+ const cart = await this.http.put(`/cart/items/${itemId}`, data);
769
+ return this.saveCartSession(cart);
732
770
  }
733
771
  /**
734
772
  * Remove item from cart
735
773
  */
736
774
  async removeFromCart(itemId) {
737
- return this.http.delete(`/cart/items/${itemId}`);
775
+ const cart = await this.http.delete(`/cart/items/${itemId}`);
776
+ return this.saveCartSession(cart);
738
777
  }
739
778
  /**
740
779
  * Clear entire cart
741
780
  */
742
781
  async clearCart() {
743
- return this.http.delete("/cart");
782
+ await this.http.delete("/cart");
783
+ this.http.setCartSessionId(null);
744
784
  }
745
785
  // ============================================
746
786
  // Orders (Protected)
package/dist/index.mjs CHANGED
@@ -43,10 +43,14 @@ var HttpClient = class {
43
43
  constructor(config) {
44
44
  this.token = null;
45
45
  this.apiKey = null;
46
+ this.cartSessionId = null;
46
47
  this.tenantId = config.tenantId;
47
48
  this.baseUrl = (config.baseUrl || "https://promptly.webbyon.com").replace(/\/$/, "");
48
49
  this.timeout = config.timeout || 3e4;
49
50
  this.apiKey = config.apiKey || null;
51
+ if (typeof window !== "undefined" && window.localStorage) {
52
+ this.cartSessionId = localStorage.getItem(`promptly_cart_session_${this.tenantId}`);
53
+ }
50
54
  }
51
55
  /**
52
56
  * Set authentication token
@@ -78,6 +82,25 @@ var HttpClient = class {
78
82
  getApiKey() {
79
83
  return this.apiKey;
80
84
  }
85
+ /**
86
+ * Set cart session ID (for guest cart persistence)
87
+ */
88
+ setCartSessionId(sessionId) {
89
+ this.cartSessionId = sessionId;
90
+ if (typeof window !== "undefined" && window.localStorage) {
91
+ if (sessionId) {
92
+ localStorage.setItem(`promptly_cart_session_${this.tenantId}`, sessionId);
93
+ } else {
94
+ localStorage.removeItem(`promptly_cart_session_${this.tenantId}`);
95
+ }
96
+ }
97
+ }
98
+ /**
99
+ * Get cart session ID
100
+ */
101
+ getCartSessionId() {
102
+ return this.cartSessionId;
103
+ }
81
104
  /**
82
105
  * Build full URL with query params
83
106
  */
@@ -108,6 +131,9 @@ var HttpClient = class {
108
131
  if (this.token) {
109
132
  headers["Authorization"] = `Bearer ${this.token}`;
110
133
  }
134
+ if (this.cartSessionId) {
135
+ headers["X-Cart-Session"] = this.cartSessionId;
136
+ }
111
137
  return headers;
112
138
  }
113
139
  /**
@@ -684,35 +710,49 @@ var ShopResource = class {
684
710
  // ============================================
685
711
  // Cart
686
712
  // ============================================
713
+ /**
714
+ * Save cart session ID from response (for guest cart persistence)
715
+ */
716
+ saveCartSession(cart) {
717
+ if (cart.session_id) {
718
+ this.http.setCartSessionId(cart.session_id);
719
+ }
720
+ return cart;
721
+ }
687
722
  /**
688
723
  * Get current cart
689
724
  */
690
725
  async getCart() {
691
- return this.http.get("/cart");
726
+ const cart = await this.http.get("/cart");
727
+ return this.saveCartSession(cart);
692
728
  }
693
729
  /**
694
730
  * Add item to cart
695
731
  */
696
732
  async addToCart(data) {
697
- return this.http.post("/cart/items", data);
733
+ const cart = await this.http.post("/cart/items", data);
734
+ return this.saveCartSession(cart);
698
735
  }
699
736
  /**
700
737
  * Update cart item quantity
701
738
  */
702
739
  async updateCartItem(itemId, data) {
703
- return this.http.put(`/cart/items/${itemId}`, data);
740
+ const cart = await this.http.put(`/cart/items/${itemId}`, data);
741
+ return this.saveCartSession(cart);
704
742
  }
705
743
  /**
706
744
  * Remove item from cart
707
745
  */
708
746
  async removeFromCart(itemId) {
709
- return this.http.delete(`/cart/items/${itemId}`);
747
+ const cart = await this.http.delete(`/cart/items/${itemId}`);
748
+ return this.saveCartSession(cart);
710
749
  }
711
750
  /**
712
751
  * Clear entire cart
713
752
  */
714
753
  async clearCart() {
715
- return this.http.delete("/cart");
754
+ await this.http.delete("/cart");
755
+ this.http.setCartSessionId(null);
716
756
  }
717
757
  // ============================================
718
758
  // Orders (Protected)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@back23/promptly-sdk",
3
- "version": "2.4.0",
3
+ "version": "2.6.0",
4
4
  "description": "Promptly AI CMS SDK for JavaScript/TypeScript",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",