@back23/promptly-sdk 2.11.0 → 2.13.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 +206 -850
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @back23/promptly-sdk
|
|
2
2
|
|
|
3
|
-
Promptly AI CMS
|
|
3
|
+
Official SDK for Promptly AI CMS - A headless CMS with built-in AI capabilities.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -14,608 +14,234 @@ npm install @back23/promptly-sdk
|
|
|
14
14
|
import { Promptly } from '@back23/promptly-sdk';
|
|
15
15
|
|
|
16
16
|
const client = new Promptly({
|
|
17
|
-
tenantId: '
|
|
18
|
-
apiKey: '
|
|
17
|
+
tenantId: 'your-tenant-id',
|
|
18
|
+
apiKey: 'pky_xxxxxxxxxxxxxxxx', // Required - Get from Dashboard > Settings > API Tokens
|
|
19
19
|
baseUrl: 'https://promptly.webbyon.com', // Optional
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
-
//
|
|
23
|
-
const { data: posts } = await client.blog.list();
|
|
24
|
-
const products = await client.shop.listProducts();
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## v2.5.0 Changes
|
|
22
|
+
// Fetch blog posts
|
|
23
|
+
const { data: posts, meta } = await client.blog.list();
|
|
28
24
|
|
|
29
|
-
|
|
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
|
-
}
|
|
25
|
+
// Fetch products
|
|
26
|
+
const { data: products } = await client.shop.listProducts();
|
|
40
27
|
```
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
## v2.3.1 Changes (Bug Fix)
|
|
45
|
-
|
|
46
|
-
### Dual Authentication Support Fixed
|
|
29
|
+
## Authentication
|
|
47
30
|
|
|
48
|
-
|
|
31
|
+
All API requests require an API key. Get yours from **Dashboard > Settings > API Tokens**.
|
|
49
32
|
|
|
50
33
|
```typescript
|
|
51
|
-
// API Key + Bearer Token now work together
|
|
52
34
|
const client = new Promptly({
|
|
53
35
|
tenantId: 'demo',
|
|
54
|
-
apiKey: '
|
|
36
|
+
apiKey: 'pky_xxxxxxxxxxxxxxxx', // Required
|
|
55
37
|
});
|
|
56
|
-
|
|
57
|
-
// Set token after login
|
|
58
|
-
await client.auth.login({ email, password });
|
|
59
|
-
|
|
60
|
-
// Member-only APIs work correctly (Authorization: Bearer xxx header included)
|
|
61
|
-
const profile = await client.members.getProfile();
|
|
62
|
-
const orders = await client.orders.list();
|
|
63
38
|
```
|
|
64
39
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
## v2.3.0 Changes
|
|
68
|
-
|
|
69
|
-
### Polymorphic Comments API
|
|
70
|
-
|
|
71
|
-
The comment system has been redesigned to support various use cases including boards, blogs, and guestbooks (standalone pages).
|
|
40
|
+
For member-specific operations (orders, profile, etc.), authenticate first:
|
|
72
41
|
|
|
73
42
|
```typescript
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
await client.comments.createBoardPost(postId, {
|
|
77
|
-
author_name: 'John Doe',
|
|
78
|
-
content: 'Comment content',
|
|
79
|
-
password: '1234', // For guest comments
|
|
80
|
-
});
|
|
43
|
+
// Login
|
|
44
|
+
await client.auth.login({ email: 'user@example.com', password: 'password' });
|
|
81
45
|
|
|
82
|
-
//
|
|
83
|
-
const
|
|
84
|
-
await client.
|
|
85
|
-
author_name: 'Jane',
|
|
86
|
-
content: 'Great post!',
|
|
87
|
-
});
|
|
46
|
+
// Now member-only APIs work
|
|
47
|
+
const profile = await client.members.getProfile();
|
|
48
|
+
const orders = await client.orders.list();
|
|
88
49
|
|
|
89
|
-
//
|
|
90
|
-
|
|
91
|
-
await client.comments.createStandalone('guestbook', {
|
|
92
|
-
author_name: 'Visitor',
|
|
93
|
-
content: 'Hello!',
|
|
94
|
-
});
|
|
50
|
+
// Check auth status
|
|
51
|
+
client.isAuthenticated(); // true
|
|
95
52
|
|
|
96
|
-
//
|
|
97
|
-
await client.
|
|
98
|
-
await client.comments.delete(commentId, { password: '1234' });
|
|
99
|
-
await client.comments.like(commentId);
|
|
53
|
+
// Logout
|
|
54
|
+
await client.auth.logout();
|
|
100
55
|
```
|
|
101
56
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
## v2.2.0 Changes
|
|
105
|
-
|
|
106
|
-
### Entity Definition CRUD
|
|
57
|
+
## API Reference
|
|
107
58
|
|
|
108
|
-
|
|
59
|
+
### Blog
|
|
109
60
|
|
|
110
61
|
```typescript
|
|
111
|
-
//
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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' }
|
|
123
|
-
]}
|
|
124
|
-
]
|
|
125
|
-
},
|
|
126
|
-
icon: 'users'
|
|
62
|
+
// List posts
|
|
63
|
+
const { data, meta } = await client.blog.list({
|
|
64
|
+
page: 1,
|
|
65
|
+
per_page: 10,
|
|
66
|
+
category: 'tech', // Optional filter
|
|
67
|
+
tag: 'laravel', // Optional filter
|
|
68
|
+
search: 'keyword', // Optional search
|
|
127
69
|
});
|
|
128
70
|
|
|
129
|
-
// Get
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
// Update entity definition
|
|
133
|
-
await client.entities.update('customers', { name: 'Clients' });
|
|
134
|
-
|
|
135
|
-
// Delete entity definition (requires force if records exist)
|
|
136
|
-
await client.entities.delete('customers', true);
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Record API Path Change
|
|
71
|
+
// Get single post
|
|
72
|
+
const post = await client.blog.get('post-slug');
|
|
140
73
|
|
|
141
|
-
|
|
74
|
+
// Get featured posts
|
|
75
|
+
const featured = await client.blog.featured(5);
|
|
142
76
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
77
|
+
// Filter by category/tag
|
|
78
|
+
const { data } = await client.blog.byCategory('news');
|
|
79
|
+
const { data } = await client.blog.byTag('featured');
|
|
146
80
|
|
|
147
|
-
//
|
|
148
|
-
await client.
|
|
81
|
+
// Get all categories and tags
|
|
82
|
+
const categories = await client.blog.categories(); // string[]
|
|
83
|
+
const tags = await client.blog.tags(); // string[]
|
|
149
84
|
```
|
|
150
85
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
## v2.0.0 Breaking Changes
|
|
154
|
-
|
|
155
|
-
### API Key Required
|
|
156
|
-
|
|
157
|
-
**All API requests now require an API key.** There are no public APIs - this ensures security and proper tenant isolation.
|
|
158
|
-
|
|
86
|
+
**BlogPost Type:**
|
|
159
87
|
```typescript
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## v1.3.0 Changes
|
|
179
|
-
|
|
180
|
-
### Unified Response Structure
|
|
181
|
-
|
|
182
|
-
All list APIs now return a consistent `ListResponse<T>` format:
|
|
183
|
-
|
|
184
|
-
```typescript
|
|
185
|
-
interface ListResponse<T> {
|
|
186
|
-
data: T[]; // Always an array (never null/undefined)
|
|
187
|
-
meta: {
|
|
188
|
-
current_page: number;
|
|
189
|
-
last_page: number;
|
|
190
|
-
per_page: number;
|
|
191
|
-
total: number;
|
|
192
|
-
from: number | null;
|
|
193
|
-
to: number | null;
|
|
194
|
-
};
|
|
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
|
|
195
103
|
}
|
|
196
104
|
```
|
|
197
105
|
|
|
198
|
-
**No more defensive code needed:**
|
|
199
|
-
|
|
200
|
-
```typescript
|
|
201
|
-
// Before (v1.1.0)
|
|
202
|
-
const posts = await client.blog.list();
|
|
203
|
-
const items = posts?.data ?? []; // Defensive check needed
|
|
204
|
-
|
|
205
|
-
// After (v1.3.0)
|
|
206
|
-
const { data, meta } = await client.blog.list();
|
|
207
|
-
data.map(post => ...); // data is always an array
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
## API Overview
|
|
211
|
-
|
|
212
|
-
> **Note:** All APIs require API key (v2.0+). "Auth Required" means additional member login token is needed.
|
|
213
|
-
|
|
214
|
-
| Resource | Read Operations | Write Operations (Auth Required) |
|
|
215
|
-
|----------|-----------------|----------------------------------|
|
|
216
|
-
| **Boards** | list, get, listPosts, getPost | createPost, updatePost, deletePost |
|
|
217
|
-
| **Blog** | list, get, featured, byCategory, byTag | - |
|
|
218
|
-
| **Comments** | boardPost, blogPost, standalone | createBoardPost, createBlogPost, createStandalone, update, delete, like |
|
|
219
|
-
| **Shop** | listProducts, getProduct, listCategories | getCart, addToCart, listOrders, createOrder |
|
|
220
|
-
| **Forms** | list, get, submit | mySubmissions |
|
|
221
|
-
| **Auth** | login, register | logout, me, updateProfile |
|
|
222
|
-
| **Media** | - | upload, list, delete |
|
|
223
|
-
| **Entities** | list, get, listRecords, getRecord | create, update, delete, createRecord, updateRecord, deleteRecord |
|
|
224
|
-
| **Reservation** | getSettings, listServices, listStaff, getAvailableDates, getAvailableSlots | create, list, get, cancel |
|
|
225
|
-
|
|
226
|
-
## API Reference
|
|
227
|
-
|
|
228
106
|
### Boards
|
|
229
107
|
|
|
230
108
|
```typescript
|
|
231
109
|
// List boards
|
|
232
|
-
const { data: boards
|
|
233
|
-
// Returns: ListResponse<Board>
|
|
110
|
+
const { data: boards } = await client.boards.list();
|
|
234
111
|
|
|
235
|
-
// Get board
|
|
236
|
-
const board = await client.boards.get('
|
|
237
|
-
// Returns: Board
|
|
112
|
+
// Get board
|
|
113
|
+
const board = await client.boards.get('board-slug');
|
|
238
114
|
|
|
239
|
-
// List
|
|
240
|
-
const { data: posts
|
|
115
|
+
// List posts
|
|
116
|
+
const { data: posts } = await client.boards.listPosts('board-slug', {
|
|
241
117
|
page: 1,
|
|
242
118
|
per_page: 10,
|
|
243
|
-
search: 'keyword',
|
|
119
|
+
search: 'keyword',
|
|
244
120
|
});
|
|
245
|
-
// Returns: ListResponse<BoardPost>
|
|
246
|
-
|
|
247
|
-
// Get post details
|
|
248
|
-
const post = await client.boards.getPost(1);
|
|
249
|
-
// Returns: BoardPost
|
|
250
121
|
|
|
251
|
-
//
|
|
252
|
-
const
|
|
253
|
-
// Returns: BoardComment[] (always an array)
|
|
254
|
-
```
|
|
122
|
+
// Get post
|
|
123
|
+
const post = await client.boards.getPost(postId);
|
|
255
124
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
// Login first
|
|
260
|
-
await client.auth.login({ email: 'user@example.com', password: 'password' });
|
|
261
|
-
|
|
262
|
-
// Create post
|
|
263
|
-
const newPost = await client.boards.createPost({
|
|
125
|
+
// Create post (auth required)
|
|
126
|
+
await client.boards.createPost({
|
|
264
127
|
board_id: 1,
|
|
265
128
|
title: 'Title',
|
|
266
129
|
content: 'Content',
|
|
267
|
-
is_notice: false,
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
// Update post
|
|
271
|
-
await client.boards.updatePost(postId, {
|
|
272
|
-
title: 'Updated title',
|
|
273
|
-
content: 'Updated content',
|
|
274
130
|
});
|
|
275
131
|
|
|
276
|
-
// Delete post
|
|
132
|
+
// Update/Delete post (auth required)
|
|
133
|
+
await client.boards.updatePost(postId, { title: 'New Title' });
|
|
277
134
|
await client.boards.deletePost(postId);
|
|
278
|
-
|
|
279
|
-
// Create comment
|
|
280
|
-
await client.boards.createComment(postId, {
|
|
281
|
-
content: 'Comment content',
|
|
282
|
-
parent_id: null, // Parent comment ID for replies
|
|
283
|
-
});
|
|
284
|
-
|
|
285
|
-
// Update comment
|
|
286
|
-
await client.boards.updateComment(commentId, {
|
|
287
|
-
content: 'Updated comment',
|
|
288
|
-
});
|
|
289
|
-
|
|
290
|
-
// Delete comment
|
|
291
|
-
await client.boards.deleteComment(commentId);
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
### Blog
|
|
295
|
-
|
|
296
|
-
```typescript
|
|
297
|
-
// List blog posts
|
|
298
|
-
const { data: posts, meta } = await client.blog.list({
|
|
299
|
-
page: 1,
|
|
300
|
-
per_page: 10,
|
|
301
|
-
category: 'news', // optional
|
|
302
|
-
tag: 'featured', // optional
|
|
303
|
-
search: 'keyword', // optional
|
|
304
|
-
});
|
|
305
|
-
// Returns: ListResponse<BlogPost>
|
|
306
|
-
|
|
307
|
-
// Get blog post details
|
|
308
|
-
const post = await client.blog.get('post-slug');
|
|
309
|
-
// Returns: BlogPost
|
|
310
|
-
|
|
311
|
-
// Featured posts
|
|
312
|
-
const featured = await client.blog.featured(5);
|
|
313
|
-
// Returns: BlogPost[] (always an array)
|
|
314
|
-
|
|
315
|
-
// Get posts by category
|
|
316
|
-
const { data: newsPosts } = await client.blog.byCategory('news');
|
|
317
|
-
|
|
318
|
-
// Get posts by tag
|
|
319
|
-
const { data: taggedPosts } = await client.blog.byTag('featured');
|
|
320
|
-
|
|
321
|
-
// List categories
|
|
322
|
-
const categories = await client.blog.categories();
|
|
323
|
-
// Returns: string[] (always an array)
|
|
324
|
-
|
|
325
|
-
// List tags
|
|
326
|
-
const tags = await client.blog.tags();
|
|
327
|
-
// Returns: string[] (always an array)
|
|
328
135
|
```
|
|
329
136
|
|
|
330
137
|
### Comments
|
|
331
138
|
|
|
332
|
-
|
|
333
|
-
- **Board comments** (`board_post`)
|
|
334
|
-
- **Blog comments** (`blog_post`)
|
|
335
|
-
- **Guestbook/Standalone comments** (`page`)
|
|
139
|
+
Supports three comment types: board posts, blog posts, and standalone pages (guestbook).
|
|
336
140
|
|
|
337
141
|
```typescript
|
|
338
|
-
//
|
|
339
|
-
const { data
|
|
340
|
-
page: 1,
|
|
341
|
-
per_page: 20,
|
|
342
|
-
});
|
|
343
|
-
// Returns: ListResponse<Comment>
|
|
344
|
-
|
|
345
|
-
// Create board post comment
|
|
142
|
+
// Board post comments
|
|
143
|
+
const { data } = await client.comments.boardPost(postId);
|
|
346
144
|
await client.comments.createBoardPost(postId, {
|
|
347
|
-
author_name: 'John
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
password: '1234', // For guest comments
|
|
351
|
-
parent_id: null, // Parent comment ID for replies
|
|
352
|
-
is_secret: false, // Secret comment flag
|
|
145
|
+
author_name: 'John',
|
|
146
|
+
content: 'Great post!',
|
|
147
|
+
password: '1234', // For guest comments
|
|
353
148
|
});
|
|
354
149
|
|
|
355
|
-
//
|
|
356
|
-
const { data
|
|
357
|
-
// Returns: ListResponse<Comment>
|
|
358
|
-
|
|
359
|
-
// Create blog post comment
|
|
150
|
+
// Blog post comments
|
|
151
|
+
const { data } = await client.comments.blogPost('post-slug');
|
|
360
152
|
await client.comments.createBlogPost('post-slug', {
|
|
361
153
|
author_name: 'Jane',
|
|
362
|
-
content: '
|
|
154
|
+
content: 'Nice article!',
|
|
363
155
|
});
|
|
364
156
|
|
|
365
|
-
//
|
|
366
|
-
const { data
|
|
367
|
-
// Returns: ListResponse<Comment>
|
|
368
|
-
|
|
369
|
-
// Create guestbook comment
|
|
157
|
+
// Standalone comments (guestbook)
|
|
158
|
+
const { data } = await client.comments.standalone('guestbook');
|
|
370
159
|
await client.comments.createStandalone('guestbook', {
|
|
371
160
|
author_name: 'Visitor',
|
|
372
161
|
content: 'Hello!',
|
|
373
162
|
});
|
|
374
163
|
|
|
375
|
-
//
|
|
376
|
-
await client.comments.update(commentId, {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
// Delete comment
|
|
382
|
-
await client.comments.delete(commentId, {
|
|
383
|
-
password: '1234', // Required for guest comments
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// Like comment
|
|
387
|
-
const result = await client.comments.like(commentId);
|
|
388
|
-
// Returns: { data: { likes: number } }
|
|
164
|
+
// Common operations
|
|
165
|
+
await client.comments.update(commentId, { content: 'Updated' });
|
|
166
|
+
await client.comments.delete(commentId, { password: '1234' });
|
|
167
|
+
await client.comments.like(commentId);
|
|
389
168
|
```
|
|
390
169
|
|
|
391
170
|
### Shop
|
|
392
171
|
|
|
393
|
-
#### Public (No Login Required)
|
|
394
|
-
|
|
395
172
|
```typescript
|
|
396
|
-
//
|
|
397
|
-
const { data: products
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
category: 'electronics', // optional
|
|
401
|
-
is_featured: true, // optional
|
|
402
|
-
search: 'keyword', // optional
|
|
173
|
+
// Products
|
|
174
|
+
const { data: products } = await client.shop.listProducts({
|
|
175
|
+
category: 'electronics',
|
|
176
|
+
is_featured: true,
|
|
403
177
|
});
|
|
404
|
-
// Returns: ListResponse<Product>
|
|
405
|
-
|
|
406
|
-
// Get product details
|
|
407
178
|
const product = await client.shop.getProduct('product-slug');
|
|
408
|
-
// Returns: Product
|
|
409
|
-
|
|
410
|
-
// Featured products
|
|
411
179
|
const featured = await client.shop.featuredProducts(8);
|
|
412
|
-
// Returns: Product[] (always an array)
|
|
413
|
-
|
|
414
|
-
// List categories
|
|
415
180
|
const categories = await client.shop.listCategories();
|
|
416
|
-
// Returns: ProductCategory[] (always an array)
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
#### Protected (Login Required)
|
|
420
181
|
|
|
421
|
-
|
|
422
|
-
// Get cart
|
|
182
|
+
// Cart (auth required)
|
|
423
183
|
const cart = await client.shop.getCart();
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
// Add to cart
|
|
427
|
-
await client.shop.addToCart({
|
|
428
|
-
product_id: 1,
|
|
429
|
-
quantity: 2,
|
|
430
|
-
variant_id: 10, // optional - for variant products
|
|
431
|
-
});
|
|
432
|
-
|
|
433
|
-
// Update cart item quantity
|
|
184
|
+
await client.shop.addToCart({ product_id: 1, quantity: 2 });
|
|
434
185
|
await client.shop.updateCartItem(itemId, { quantity: 3 });
|
|
435
|
-
|
|
436
|
-
// Remove from cart
|
|
437
186
|
await client.shop.removeFromCart(itemId);
|
|
438
|
-
|
|
439
|
-
// Clear cart
|
|
440
187
|
await client.shop.clearCart();
|
|
441
188
|
|
|
442
|
-
//
|
|
189
|
+
// Orders (auth required)
|
|
443
190
|
const order = await client.shop.createOrder({
|
|
444
191
|
orderer_name: 'John Doe',
|
|
445
192
|
orderer_email: 'john@example.com',
|
|
446
|
-
orderer_phone: '555-
|
|
193
|
+
orderer_phone: '555-1234',
|
|
447
194
|
shipping_name: 'John Doe',
|
|
448
|
-
shipping_phone: '555-
|
|
195
|
+
shipping_phone: '555-1234',
|
|
449
196
|
shipping_zipcode: '12345',
|
|
450
197
|
shipping_address: '123 Main St',
|
|
451
198
|
shipping_address_detail: 'Apt 101',
|
|
452
|
-
shipping_memo: 'Leave at door',
|
|
453
|
-
coupon_code: 'SAVE10', // optional
|
|
454
199
|
});
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const { data: orders, meta } = await client.shop.listOrders();
|
|
458
|
-
// Returns: ListResponse<Order>
|
|
459
|
-
|
|
460
|
-
// Get order details
|
|
461
|
-
const order = await client.shop.getOrder(orderId);
|
|
462
|
-
// Returns: Order
|
|
463
|
-
|
|
464
|
-
// Cancel order
|
|
200
|
+
const { data: orders } = await client.shop.listOrders();
|
|
201
|
+
const orderDetail = await client.shop.getOrder(orderId);
|
|
465
202
|
await client.shop.cancelOrder(orderId);
|
|
466
203
|
|
|
467
|
-
//
|
|
204
|
+
// Coupons
|
|
468
205
|
const validation = await client.shop.validateCoupon('SAVE10', 50000);
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
// My coupons
|
|
472
|
-
const coupons = await client.shop.myCoupons();
|
|
473
|
-
// Returns: Coupon[] (always an array)
|
|
206
|
+
const myCoupons = await client.shop.myCoupons();
|
|
474
207
|
```
|
|
475
208
|
|
|
476
|
-
### Reservation
|
|
477
|
-
|
|
478
|
-
#### Public (No Login Required)
|
|
209
|
+
### Reservation
|
|
479
210
|
|
|
480
211
|
```typescript
|
|
481
|
-
//
|
|
212
|
+
// Public APIs
|
|
482
213
|
const settings = await client.reservation.getSettings();
|
|
483
|
-
// Returns: ReservationSettings
|
|
484
|
-
|
|
485
|
-
// List services
|
|
486
214
|
const services = await client.reservation.listServices();
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
// List staff
|
|
490
|
-
const staffs = await client.reservation.listStaff();
|
|
491
|
-
// Returns: ReservationStaff[] (always an array)
|
|
492
|
-
|
|
493
|
-
// Get staff for specific service
|
|
494
|
-
const serviceStaffs = await client.reservation.listStaff(serviceId);
|
|
215
|
+
const staff = await client.reservation.listStaff(serviceId);
|
|
495
216
|
|
|
496
|
-
// Get available dates
|
|
217
|
+
// Get available dates/slots
|
|
497
218
|
const dates = await client.reservation.getAvailableDates({
|
|
498
219
|
service_id: 1,
|
|
499
|
-
staff_id: 2,
|
|
500
|
-
start_date: '2026-01-01',
|
|
501
|
-
end_date: '2026-01-31',
|
|
220
|
+
staff_id: 2,
|
|
221
|
+
start_date: '2026-01-01',
|
|
222
|
+
end_date: '2026-01-31',
|
|
502
223
|
});
|
|
503
|
-
// Returns: string[] (YYYY-MM-DD format)
|
|
504
|
-
|
|
505
|
-
// Get available time slots
|
|
506
224
|
const slots = await client.reservation.getAvailableSlots({
|
|
507
225
|
service_id: 1,
|
|
508
226
|
date: '2026-01-15',
|
|
509
|
-
staff_id: 2,
|
|
227
|
+
staff_id: 2,
|
|
510
228
|
});
|
|
511
|
-
// Returns: ReservationSlot[]
|
|
512
|
-
```
|
|
513
229
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
```typescript
|
|
517
|
-
// Create reservation
|
|
230
|
+
// Create reservation (auth required)
|
|
518
231
|
const result = await client.reservation.create({
|
|
519
232
|
service_id: 1,
|
|
520
|
-
staff_id: 2,
|
|
233
|
+
staff_id: 2,
|
|
521
234
|
reservation_date: '2026-01-15',
|
|
522
235
|
start_time: '14:00',
|
|
523
236
|
customer_name: 'John Doe',
|
|
524
|
-
customer_phone: '555-
|
|
525
|
-
customer_email: 'john@example.com', // optional
|
|
526
|
-
customer_memo: 'Special requests', // optional
|
|
527
|
-
});
|
|
528
|
-
// Returns: { reservation: Reservation, requires_payment: boolean, deposit: number }
|
|
529
|
-
|
|
530
|
-
// List my reservations
|
|
531
|
-
const { data: reservations, meta } = await client.reservation.list({
|
|
532
|
-
status: 'confirmed', // optional
|
|
533
|
-
upcoming: true, // optional
|
|
534
|
-
past: false, // optional
|
|
237
|
+
customer_phone: '555-1234',
|
|
535
238
|
});
|
|
536
|
-
// Returns: ListResponse<Reservation>
|
|
537
239
|
|
|
538
|
-
//
|
|
240
|
+
// My reservations (auth required)
|
|
241
|
+
const { data } = await client.reservation.list({ status: 'confirmed' });
|
|
539
242
|
const upcoming = await client.reservation.upcoming(5);
|
|
540
|
-
// Returns: Reservation[] (always an array)
|
|
541
|
-
|
|
542
|
-
// Past reservations
|
|
543
243
|
const past = await client.reservation.past(10);
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
// Get reservation details
|
|
547
|
-
const reservation = await client.reservation.get('RES-20260115-001');
|
|
548
|
-
// Returns: Reservation
|
|
549
|
-
|
|
550
|
-
// Cancel reservation
|
|
551
|
-
const cancelled = await client.reservation.cancel('RES-20260115-001', 'Schedule change');
|
|
552
|
-
// Returns: Reservation
|
|
553
|
-
```
|
|
554
|
-
|
|
555
|
-
### Auth (Authentication)
|
|
556
|
-
|
|
557
|
-
```typescript
|
|
558
|
-
// Login
|
|
559
|
-
const response = await client.auth.login({
|
|
560
|
-
email: 'user@example.com',
|
|
561
|
-
password: 'password',
|
|
562
|
-
});
|
|
563
|
-
// Returns: { member: Member, token: string }
|
|
564
|
-
// Token is automatically stored
|
|
565
|
-
|
|
566
|
-
// Register
|
|
567
|
-
await client.auth.register({
|
|
568
|
-
name: 'John Doe',
|
|
569
|
-
email: 'user@example.com',
|
|
570
|
-
password: 'password',
|
|
571
|
-
password_confirmation: 'password',
|
|
572
|
-
phone: '555-123-4567', // optional
|
|
573
|
-
});
|
|
574
|
-
|
|
575
|
-
// Logout
|
|
576
|
-
await client.auth.logout();
|
|
577
|
-
|
|
578
|
-
// Get current user
|
|
579
|
-
const me = await client.auth.me();
|
|
580
|
-
// Returns: Member
|
|
581
|
-
|
|
582
|
-
// Update profile
|
|
583
|
-
await client.auth.updateProfile({
|
|
584
|
-
name: 'New Name',
|
|
585
|
-
phone: '555-999-8888',
|
|
586
|
-
});
|
|
587
|
-
|
|
588
|
-
// Change password
|
|
589
|
-
await client.auth.updateProfile({
|
|
590
|
-
current_password: 'current_password',
|
|
591
|
-
password: 'new_password',
|
|
592
|
-
password_confirmation: 'new_password',
|
|
593
|
-
});
|
|
594
|
-
|
|
595
|
-
// Check authentication status
|
|
596
|
-
client.isAuthenticated(); // true or false
|
|
597
|
-
|
|
598
|
-
// Set token directly (e.g., from localStorage)
|
|
599
|
-
client.setToken('saved-token');
|
|
600
|
-
|
|
601
|
-
// Get token
|
|
602
|
-
const token = client.getToken();
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
#### Social Login
|
|
606
|
-
|
|
607
|
-
```typescript
|
|
608
|
-
// Get social login providers
|
|
609
|
-
const providers = await client.auth.getSocialProviders();
|
|
610
|
-
// Returns: SocialProvider[]
|
|
611
|
-
|
|
612
|
-
// Get social auth URL
|
|
613
|
-
const { url } = await client.auth.getSocialAuthUrl('google');
|
|
614
|
-
// Redirect to this URL
|
|
615
|
-
|
|
616
|
-
// Handle callback (after redirect)
|
|
617
|
-
const response = await client.auth.socialCallback('google', code);
|
|
618
|
-
// Returns: { member: Member, token: string }
|
|
244
|
+
await client.reservation.cancel('RES-20260115-001', 'Schedule change');
|
|
619
245
|
```
|
|
620
246
|
|
|
621
247
|
### Forms
|
|
@@ -623,350 +249,133 @@ const response = await client.auth.socialCallback('google', code);
|
|
|
623
249
|
```typescript
|
|
624
250
|
// List forms
|
|
625
251
|
const { data: forms } = await client.forms.list();
|
|
626
|
-
// Returns: ListResponse<Form>
|
|
627
252
|
|
|
628
|
-
// Get form
|
|
253
|
+
// Get form with fields
|
|
629
254
|
const form = await client.forms.get('contact');
|
|
630
|
-
// Returns: Form (includes field definitions)
|
|
631
255
|
|
|
632
|
-
// Submit form
|
|
256
|
+
// Submit form
|
|
633
257
|
await client.forms.submit('contact', {
|
|
634
258
|
name: 'John Doe',
|
|
635
|
-
email: '
|
|
636
|
-
message: '
|
|
259
|
+
email: 'john@example.com',
|
|
260
|
+
message: 'Hello!',
|
|
637
261
|
});
|
|
638
262
|
|
|
639
|
-
// My submissions (
|
|
263
|
+
// My submissions (auth required)
|
|
640
264
|
const { data: submissions } = await client.forms.mySubmissions();
|
|
641
|
-
// Returns: ListResponse<FormSubmission>
|
|
642
265
|
```
|
|
643
266
|
|
|
644
|
-
### Media
|
|
267
|
+
### Media (Auth Required)
|
|
645
268
|
|
|
646
269
|
```typescript
|
|
647
|
-
// Upload
|
|
648
|
-
const media = await client.media.upload(file);
|
|
649
|
-
// Returns: Media
|
|
650
|
-
|
|
651
|
-
// Upload multiple files
|
|
270
|
+
// Upload
|
|
271
|
+
const media = await client.media.upload(file);
|
|
652
272
|
const mediaList = await client.media.uploadMultiple([file1, file2]);
|
|
653
|
-
// Returns: Media[]
|
|
654
|
-
|
|
655
|
-
// List my media
|
|
656
|
-
const { data: mediaList, meta } = await client.media.list({
|
|
657
|
-
page: 1,
|
|
658
|
-
per_page: 20,
|
|
659
|
-
type: 'image/jpeg', // optional
|
|
660
|
-
});
|
|
661
|
-
// Returns: ListResponse<Media>
|
|
662
273
|
|
|
663
|
-
// Delete
|
|
274
|
+
// List & Delete
|
|
275
|
+
const { data: myMedia } = await client.media.list({ type: 'image/jpeg' });
|
|
664
276
|
await client.media.delete(mediaId);
|
|
665
277
|
```
|
|
666
278
|
|
|
667
|
-
###
|
|
668
|
-
|
|
669
|
-
Create entity definitions and manage data directly from the API/SDK.
|
|
279
|
+
### Custom Entities
|
|
670
280
|
|
|
671
|
-
|
|
281
|
+
Dynamic data structures for custom use cases.
|
|
672
282
|
|
|
673
283
|
```typescript
|
|
674
|
-
//
|
|
284
|
+
// Entity definitions
|
|
675
285
|
const entities = await client.entities.list();
|
|
676
|
-
|
|
286
|
+
const entity = await client.entities.get('customers');
|
|
677
287
|
|
|
678
|
-
|
|
679
|
-
const entity = await client.entities.create({
|
|
288
|
+
await client.entities.create({
|
|
680
289
|
name: 'Customer',
|
|
681
290
|
slug: 'customers',
|
|
682
|
-
description: 'Customer management',
|
|
683
291
|
schema: {
|
|
684
292
|
fields: [
|
|
685
|
-
{ name: 'company', label: 'Company
|
|
293
|
+
{ name: 'company', label: 'Company', type: 'text', required: true },
|
|
686
294
|
{ name: 'email', label: 'Email', type: 'email', required: true },
|
|
687
295
|
{ name: 'status', label: 'Status', type: 'select', options: [
|
|
688
296
|
{ value: 'active', label: 'Active' },
|
|
689
|
-
{ value: 'inactive', label: 'Inactive' }
|
|
690
|
-
]}
|
|
691
|
-
]
|
|
297
|
+
{ value: 'inactive', label: 'Inactive' },
|
|
298
|
+
]},
|
|
299
|
+
],
|
|
692
300
|
},
|
|
693
|
-
icon: 'users'
|
|
694
|
-
});
|
|
695
|
-
|
|
696
|
-
// Get entity definition (includes schema)
|
|
697
|
-
const entity = await client.entities.get('customers');
|
|
698
|
-
// Returns: CustomEntity (includes schema)
|
|
699
|
-
|
|
700
|
-
// Update entity definition
|
|
701
|
-
await client.entities.update('customers', {
|
|
702
|
-
name: 'Clients',
|
|
703
|
-
description: 'Client management'
|
|
704
301
|
});
|
|
705
302
|
|
|
706
|
-
|
|
707
|
-
await client.entities.delete('customers');
|
|
708
|
-
await client.entities.delete('customers', true); // Force delete with records
|
|
709
|
-
```
|
|
710
|
-
|
|
711
|
-
#### Record CRUD
|
|
303
|
+
await client.entities.update('customers', { name: 'Clients' });
|
|
304
|
+
await client.entities.delete('customers', true); // force delete
|
|
712
305
|
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
per_page: 20,
|
|
718
|
-
search: 'ACME', // Search
|
|
719
|
-
sort: 'company', // Sort field
|
|
720
|
-
dir: 'asc', // Sort direction
|
|
721
|
-
filters: JSON.stringify({ status: 'active' }) // JSON filter
|
|
306
|
+
// Records
|
|
307
|
+
const { data: records } = await client.entities.listRecords('customers', {
|
|
308
|
+
search: 'ACME',
|
|
309
|
+
filters: JSON.stringify({ status: 'active' }),
|
|
722
310
|
});
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
// Get single record
|
|
726
|
-
const customer = await client.entities.getRecord('customers', 1);
|
|
727
|
-
// Returns: EntityRecord
|
|
728
|
-
console.log(customer.data.company); // 'ABC Corp'
|
|
311
|
+
const record = await client.entities.getRecord('customers', 1);
|
|
729
312
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
email: 'contact@abc.com',
|
|
313
|
+
await client.entities.createRecord('customers', {
|
|
314
|
+
company: 'ACME Corp',
|
|
315
|
+
email: 'contact@acme.com',
|
|
734
316
|
status: 'active',
|
|
735
317
|
});
|
|
736
|
-
|
|
737
|
-
// Update record (partial update - merges with existing data)
|
|
738
|
-
await client.entities.updateRecord('customers', 1, {
|
|
739
|
-
status: 'inactive',
|
|
740
|
-
email: 'new@abc.com'
|
|
741
|
-
});
|
|
742
|
-
|
|
743
|
-
// Delete record
|
|
318
|
+
await client.entities.updateRecord('customers', 1, { status: 'inactive' });
|
|
744
319
|
await client.entities.deleteRecord('customers', 1);
|
|
745
|
-
```
|
|
746
|
-
|
|
747
|
-
#### TypeScript Type Support
|
|
748
320
|
|
|
749
|
-
|
|
750
|
-
// Typed entity accessor
|
|
321
|
+
// TypeScript support
|
|
751
322
|
interface Customer {
|
|
752
323
|
company: string;
|
|
753
324
|
email: string;
|
|
754
|
-
|
|
325
|
+
status: 'active' | 'inactive';
|
|
755
326
|
}
|
|
756
|
-
|
|
757
|
-
const
|
|
758
|
-
|
|
759
|
-
// Type inference
|
|
760
|
-
const list = await customers.list();
|
|
761
|
-
list.data[0].data.company; // string
|
|
762
|
-
|
|
763
|
-
const record = await customers.get(1);
|
|
764
|
-
record.data.tier; // 'standard' | 'vip'
|
|
765
|
-
|
|
766
|
-
// Type checking on create/update
|
|
767
|
-
await customers.create({
|
|
768
|
-
company: 'New Corp',
|
|
769
|
-
email: 'new@corp.com',
|
|
770
|
-
tier: 'standard',
|
|
771
|
-
});
|
|
327
|
+
const customers = client.entities.typed<Customer>('customers');
|
|
328
|
+
const { data } = await customers.list();
|
|
772
329
|
```
|
|
773
330
|
|
|
774
|
-
###
|
|
331
|
+
### Auth
|
|
775
332
|
|
|
776
333
|
```typescript
|
|
777
|
-
//
|
|
778
|
-
|
|
779
|
-
|
|
334
|
+
// Register
|
|
335
|
+
await client.auth.register({
|
|
336
|
+
name: 'John Doe',
|
|
337
|
+
email: 'john@example.com',
|
|
338
|
+
password: 'password',
|
|
339
|
+
password_confirmation: 'password',
|
|
340
|
+
});
|
|
780
341
|
|
|
781
|
-
//
|
|
782
|
-
const
|
|
783
|
-
|
|
784
|
-
|
|
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();
|
|
785
348
|
|
|
786
|
-
|
|
349
|
+
// Profile
|
|
350
|
+
const me = await client.auth.me();
|
|
351
|
+
await client.auth.updateProfile({ name: 'New Name' });
|
|
787
352
|
|
|
788
|
-
|
|
353
|
+
// Token management
|
|
354
|
+
client.setToken('saved-token');
|
|
355
|
+
const token = client.getToken();
|
|
356
|
+
client.isAuthenticated();
|
|
789
357
|
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
/** API key (required) - Get from Dashboard > Settings > API Tokens */
|
|
795
|
-
apiKey: string;
|
|
796
|
-
/** Base URL of Promptly API (optional) */
|
|
797
|
-
baseUrl?: string;
|
|
798
|
-
/** Request timeout in milliseconds (optional) */
|
|
799
|
-
timeout?: number;
|
|
800
|
-
}
|
|
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);
|
|
801
362
|
```
|
|
802
363
|
|
|
803
|
-
|
|
364
|
+
## Response Types
|
|
804
365
|
|
|
805
|
-
|
|
806
|
-
// Unified list response type
|
|
807
|
-
interface ListResponse<T> {
|
|
808
|
-
data: T[];
|
|
809
|
-
meta: PaginationMeta;
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
interface PaginationMeta {
|
|
813
|
-
current_page: number;
|
|
814
|
-
last_page: number;
|
|
815
|
-
per_page: number;
|
|
816
|
-
total: number;
|
|
817
|
-
from: number | null;
|
|
818
|
-
to: number | null;
|
|
819
|
-
}
|
|
820
|
-
```
|
|
821
|
-
|
|
822
|
-
### Resource Types
|
|
366
|
+
All list APIs return a consistent format:
|
|
823
367
|
|
|
824
368
|
```typescript
|
|
825
|
-
interface
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
id: number;
|
|
836
|
-
board_id: number;
|
|
837
|
-
title: string;
|
|
838
|
-
content: string;
|
|
839
|
-
excerpt?: string;
|
|
840
|
-
author: string;
|
|
841
|
-
views: number;
|
|
842
|
-
is_notice: boolean;
|
|
843
|
-
is_secret: boolean;
|
|
844
|
-
is_mine: boolean;
|
|
845
|
-
is_private: boolean;
|
|
846
|
-
comment_count: number;
|
|
847
|
-
attachments?: Media[];
|
|
848
|
-
created_at: string;
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
interface BlogPost {
|
|
852
|
-
id: number;
|
|
853
|
-
slug: string;
|
|
854
|
-
title: string;
|
|
855
|
-
content: string;
|
|
856
|
-
excerpt?: string;
|
|
857
|
-
featured_image?: string;
|
|
858
|
-
category?: string;
|
|
859
|
-
tags?: string[];
|
|
860
|
-
author_name?: string;
|
|
861
|
-
is_published: boolean;
|
|
862
|
-
published_at?: string;
|
|
863
|
-
view_count: number;
|
|
864
|
-
created_at: string;
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
interface Comment {
|
|
868
|
-
id: number;
|
|
869
|
-
type: 'board_post' | 'blog_post' | 'page';
|
|
870
|
-
author_name: string;
|
|
871
|
-
author_avatar: string | null;
|
|
872
|
-
content: string;
|
|
873
|
-
is_approved: boolean;
|
|
874
|
-
is_pinned: boolean;
|
|
875
|
-
is_secret: boolean;
|
|
876
|
-
likes: number;
|
|
877
|
-
depth: number;
|
|
878
|
-
created_at: string;
|
|
879
|
-
replies: Comment[];
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
interface Product {
|
|
883
|
-
id: number;
|
|
884
|
-
slug: string;
|
|
885
|
-
name: string;
|
|
886
|
-
description?: string;
|
|
887
|
-
price: number;
|
|
888
|
-
compare_price?: number;
|
|
889
|
-
thumbnail?: string;
|
|
890
|
-
images?: string[];
|
|
891
|
-
status: 'draft' | 'active' | 'inactive';
|
|
892
|
-
is_featured: boolean;
|
|
893
|
-
in_stock?: boolean;
|
|
894
|
-
discount_percent?: number;
|
|
895
|
-
created_at: string;
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
interface Reservation {
|
|
899
|
-
id: number;
|
|
900
|
-
reservation_number: string;
|
|
901
|
-
status: 'pending' | 'confirmed' | 'completed' | 'cancelled' | 'no_show';
|
|
902
|
-
status_label: string;
|
|
903
|
-
reservation_date: string;
|
|
904
|
-
start_time: string;
|
|
905
|
-
end_time: string;
|
|
906
|
-
time_range: string;
|
|
907
|
-
customer_name: string;
|
|
908
|
-
customer_phone: string | null;
|
|
909
|
-
customer_email: string | null;
|
|
910
|
-
price: number;
|
|
911
|
-
deposit: number;
|
|
912
|
-
payment_status: 'pending' | 'paid' | 'refunded' | 'partial';
|
|
913
|
-
can_cancel: boolean;
|
|
914
|
-
service: { id: number; name: string; duration: number; } | null;
|
|
915
|
-
staff: { id: number; name: string; avatar: string | null; } | null;
|
|
916
|
-
created_at: string;
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
interface ReservationService {
|
|
920
|
-
id: number;
|
|
921
|
-
name: string;
|
|
922
|
-
slug: string;
|
|
923
|
-
description: string | null;
|
|
924
|
-
thumbnail: string | null;
|
|
925
|
-
duration: number;
|
|
926
|
-
price: number;
|
|
927
|
-
requires_staff: boolean;
|
|
928
|
-
requires_payment: boolean;
|
|
929
|
-
deposit: number;
|
|
930
|
-
staffs: Array<{ id: number; name: string; avatar: string | null; }>;
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
interface ReservationSettings {
|
|
934
|
-
timezone: string;
|
|
935
|
-
slot_interval: number;
|
|
936
|
-
min_notice_hours: number;
|
|
937
|
-
max_advance_days: number;
|
|
938
|
-
cancellation_hours: number;
|
|
939
|
-
allow_online_payment: boolean;
|
|
940
|
-
bookable_date_range: { start: string; end: string; };
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
interface Member {
|
|
944
|
-
id: number;
|
|
945
|
-
name: string;
|
|
946
|
-
email: string;
|
|
947
|
-
phone?: string;
|
|
948
|
-
avatar?: string;
|
|
949
|
-
is_active: boolean;
|
|
950
|
-
created_at: string;
|
|
951
|
-
}
|
|
952
|
-
|
|
953
|
-
interface CustomEntity {
|
|
954
|
-
id: number;
|
|
955
|
-
name: string;
|
|
956
|
-
slug: string;
|
|
957
|
-
description?: string;
|
|
958
|
-
schema: EntitySchema;
|
|
959
|
-
is_active: boolean;
|
|
960
|
-
created_at: string;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
interface EntityRecord {
|
|
964
|
-
id: number;
|
|
965
|
-
entity_id: number;
|
|
966
|
-
data: Record<string, any>;
|
|
967
|
-
status: 'active' | 'archived' | 'draft';
|
|
968
|
-
created_at: string;
|
|
969
|
-
updated_at: string;
|
|
369
|
+
interface ListResponse<T> {
|
|
370
|
+
data: T[]; // Always an array, never null
|
|
371
|
+
meta: {
|
|
372
|
+
current_page: number;
|
|
373
|
+
last_page: number;
|
|
374
|
+
per_page: number;
|
|
375
|
+
total: number;
|
|
376
|
+
from: number | null;
|
|
377
|
+
to: number | null;
|
|
378
|
+
};
|
|
970
379
|
}
|
|
971
380
|
```
|
|
972
381
|
|
|
@@ -994,23 +403,20 @@ import { Promptly } from '@back23/promptly-sdk';
|
|
|
994
403
|
|
|
995
404
|
const client = new Promptly({
|
|
996
405
|
tenantId: 'demo',
|
|
997
|
-
apiKey: process.env.NEXT_PUBLIC_PROMPTLY_API_KEY!,
|
|
998
|
-
baseUrl: 'https://promptly.webbyon.com',
|
|
406
|
+
apiKey: process.env.NEXT_PUBLIC_PROMPTLY_API_KEY!,
|
|
999
407
|
});
|
|
1000
408
|
|
|
1001
|
-
// Blog post list (with pagination)
|
|
1002
409
|
function BlogList() {
|
|
1003
410
|
const [posts, setPosts] = useState([]);
|
|
1004
|
-
const [
|
|
1005
|
-
const [page, setPage] = useState(1);
|
|
411
|
+
const [loading, setLoading] = useState(true);
|
|
1006
412
|
|
|
1007
413
|
useEffect(() => {
|
|
1008
|
-
client.blog.list({
|
|
1009
|
-
.then(({ data
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
414
|
+
client.blog.list({ per_page: 10 })
|
|
415
|
+
.then(({ data }) => setPosts(data))
|
|
416
|
+
.finally(() => setLoading(false));
|
|
417
|
+
}, []);
|
|
418
|
+
|
|
419
|
+
if (loading) return <div>Loading...</div>;
|
|
1014
420
|
|
|
1015
421
|
return (
|
|
1016
422
|
<div>
|
|
@@ -1018,83 +424,33 @@ function BlogList() {
|
|
|
1018
424
|
<article key={post.id}>
|
|
1019
425
|
<h2>{post.title}</h2>
|
|
1020
426
|
<p>{post.excerpt}</p>
|
|
427
|
+
<span>{post.category}</span>
|
|
428
|
+
{post.tags.map(tag => <span key={tag}>{tag}</span>)}
|
|
1021
429
|
</article>
|
|
1022
430
|
))}
|
|
1023
|
-
|
|
1024
|
-
{meta && (
|
|
1025
|
-
<div>
|
|
1026
|
-
Page {meta.current_page} of {meta.last_page}
|
|
1027
|
-
<button
|
|
1028
|
-
onClick={() => setPage(p => p - 1)}
|
|
1029
|
-
disabled={page <= 1}
|
|
1030
|
-
>
|
|
1031
|
-
Previous
|
|
1032
|
-
</button>
|
|
1033
|
-
<button
|
|
1034
|
-
onClick={() => setPage(p => p + 1)}
|
|
1035
|
-
disabled={page >= meta.last_page}
|
|
1036
|
-
>
|
|
1037
|
-
Next
|
|
1038
|
-
</button>
|
|
1039
|
-
</div>
|
|
1040
|
-
)}
|
|
1041
431
|
</div>
|
|
1042
432
|
);
|
|
1043
433
|
}
|
|
434
|
+
```
|
|
1044
435
|
|
|
1045
|
-
|
|
1046
|
-
function ReservationForm() {
|
|
1047
|
-
const [services, setServices] = useState([]);
|
|
1048
|
-
const [selectedService, setSelectedService] = useState(null);
|
|
1049
|
-
const [dates, setDates] = useState([]);
|
|
1050
|
-
const [slots, setSlots] = useState([]);
|
|
436
|
+
## Changelog
|
|
1051
437
|
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
438
|
+
### v2.12.0
|
|
439
|
+
- Added `category`, `tags`, `views`, `published_at` fields to BlogPost response
|
|
440
|
+
- Added `GET /blog/categories` and `GET /blog/tags` endpoints
|
|
1055
441
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
client.reservation.getAvailableDates({
|
|
1059
|
-
service_id: selectedService,
|
|
1060
|
-
}).then(setDates);
|
|
1061
|
-
}
|
|
1062
|
-
}, [selectedService]);
|
|
1063
|
-
|
|
1064
|
-
const handleDateSelect = async (date) => {
|
|
1065
|
-
const availableSlots = await client.reservation.getAvailableSlots({
|
|
1066
|
-
service_id: selectedService,
|
|
1067
|
-
date,
|
|
1068
|
-
});
|
|
1069
|
-
setSlots(availableSlots);
|
|
1070
|
-
};
|
|
442
|
+
### v2.5.0
|
|
443
|
+
- Added `is_secret` and `is_mine` fields to BoardPost
|
|
1071
444
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
<div>
|
|
1082
|
-
{dates.map(date => (
|
|
1083
|
-
<button key={date} onClick={() => handleDateSelect(date)}>
|
|
1084
|
-
{date}
|
|
1085
|
-
</button>
|
|
1086
|
-
))}
|
|
1087
|
-
</div>
|
|
1088
|
-
|
|
1089
|
-
<div>
|
|
1090
|
-
{slots.filter(s => s.available).map(slot => (
|
|
1091
|
-
<button key={slot.time}>{slot.time}</button>
|
|
1092
|
-
))}
|
|
1093
|
-
</div>
|
|
1094
|
-
</div>
|
|
1095
|
-
);
|
|
1096
|
-
}
|
|
1097
|
-
```
|
|
445
|
+
### v2.3.0
|
|
446
|
+
- Polymorphic comments API (board, blog, standalone)
|
|
447
|
+
|
|
448
|
+
### v2.0.0
|
|
449
|
+
- **Breaking:** API key required for all requests
|
|
450
|
+
|
|
451
|
+
### v1.3.0
|
|
452
|
+
- Unified `ListResponse<T>` format for all list APIs
|
|
453
|
+
- Reservation system support
|
|
1098
454
|
|
|
1099
455
|
## License
|
|
1100
456
|
|