@foru-ms/sdk 1.1.0 → 1.2.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 +375 -38
- package/dist/Client.d.ts +63 -4
- package/dist/Client.js +124 -22
- package/dist/errors.d.ts +52 -0
- package/dist/errors.js +95 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/resources/Integrations.d.ts +7 -0
- package/dist/resources/Integrations.js +6 -0
- package/dist/resources/Posts.d.ts +12 -0
- package/dist/resources/Posts.js +44 -0
- package/dist/resources/PrivateMessages.d.ts +4 -0
- package/dist/resources/PrivateMessages.js +6 -0
- package/dist/resources/SSO.d.ts +10 -0
- package/dist/resources/SSO.js +11 -0
- package/dist/resources/Tags.d.ts +8 -0
- package/dist/resources/Tags.js +24 -0
- package/dist/resources/Threads.d.ts +20 -0
- package/dist/resources/Threads.js +85 -0
- package/dist/resources/Users.d.ts +10 -0
- package/dist/resources/Users.js +26 -0
- package/dist/resources/Webhooks.d.ts +69 -0
- package/dist/resources/Webhooks.js +115 -0
- package/dist/response-types.d.ts +105 -0
- package/dist/response-types.js +2 -0
- package/dist/utils.d.ts +80 -0
- package/dist/utils.js +138 -0
- package/examples/README.md +38 -0
- package/examples/authentication.ts +79 -0
- package/examples/error-handling.ts +133 -0
- package/examples/managing-threads.ts +130 -0
- package/examples/pagination.ts +81 -0
- package/examples/webhooks.ts +176 -0
- package/package.json +1 -1
- package/src/Client.ts +165 -25
- package/src/errors.ts +95 -0
- package/src/index.ts +3 -0
- package/src/resources/Integrations.ts +11 -0
- package/src/resources/Posts.ts +56 -0
- package/src/resources/PrivateMessages.ts +10 -0
- package/src/resources/SSO.ts +17 -0
- package/src/resources/Tags.ts +32 -0
- package/src/resources/Threads.ts +109 -0
- package/src/resources/Users.ts +36 -0
- package/src/resources/Webhooks.ts +131 -0
- package/src/response-types.ts +113 -0
- package/src/utils.ts +182 -0
package/README.md
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
# @foru-ms/sdk
|
|
2
2
|
|
|
3
|
-
The official JavaScript/TypeScript SDK for [Foru.ms](https://foru.ms). Build powerful community features directly into your application.
|
|
3
|
+
The official JavaScript/ TypeScript SDK for [Foru.ms](https://foru.ms). Build powerful community features directly into your application.
|
|
4
4
|
|
|
5
|
-
This SDK is fully typed and provides a comprehensive interface to the Foru.ms API.
|
|
5
|
+
This SDK is fully typed and provides a comprehensive interface to the Foru.ms API with built-in error handling, automatic retries, and pagination helpers.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
✨ **Fully Typed** - Complete TypeScript support with detailed type definitions
|
|
10
|
+
🔄 **Auto Retry** - Automatic retry logic for rate limits and server errors
|
|
11
|
+
📄 **Easy Pagination** - Built-in helpers for cursor-based pagination
|
|
12
|
+
🚨 **Rich Error Classes** - Specific error types for better error handling
|
|
13
|
+
🔐 **Webhook Verification** - Built-in signature verification for webhooks
|
|
14
|
+
📊 **Rate Limit Tracking** - Automatic tracking of API rate limits
|
|
15
|
+
📚 **Comprehensive Examples** - Detailed examples for common use cases
|
|
6
16
|
|
|
7
17
|
## Installation
|
|
8
18
|
|
|
@@ -14,20 +24,156 @@ yarn add @foru-ms/sdk
|
|
|
14
24
|
pnpm add @foru-ms/sdk
|
|
15
25
|
```
|
|
16
26
|
|
|
17
|
-
##
|
|
27
|
+
## Quick Start
|
|
18
28
|
|
|
19
29
|
```typescript
|
|
20
30
|
import { ForumClient } from '@foru-ms/sdk';
|
|
21
31
|
|
|
22
32
|
const client = new ForumClient({
|
|
23
33
|
apiKey: 'your_api_key',
|
|
24
|
-
|
|
34
|
+
baseUrl: 'https://api.foru.ms/v1', // Optional
|
|
35
|
+
maxRetries: 3, // Optional, default: 3
|
|
36
|
+
enableRetry: true, // Optional, default: true
|
|
25
37
|
});
|
|
26
38
|
|
|
27
39
|
// Set an authentication token (JWT) for user-scoped requests
|
|
28
40
|
client.setToken('user_jwt_token');
|
|
41
|
+
|
|
42
|
+
// Create a thread
|
|
43
|
+
const thread = await client.threads.create({
|
|
44
|
+
title: 'My First Thread',
|
|
45
|
+
body: 'Hello, Foru.ms!',
|
|
46
|
+
userId: 'user-123',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// List threads with auto-pagination
|
|
50
|
+
for await (const thread of client.pagination.paginateAll(
|
|
51
|
+
(cursor) => client.threads.list({ cursor })
|
|
52
|
+
)) {
|
|
53
|
+
console.log(thread.title);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Error Handling
|
|
58
|
+
|
|
59
|
+
The SDK provides specific error classes for different scenarios:
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
import {
|
|
63
|
+
ForumClient,
|
|
64
|
+
AuthenticationError,
|
|
65
|
+
NotFoundError,
|
|
66
|
+
RateLimitError,
|
|
67
|
+
ValidationError
|
|
68
|
+
} from '@foru-ms/sdk';
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
await client.threads.retrieve('thread-id');
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (error instanceof NotFoundError) {
|
|
74
|
+
console.log('Thread not found');
|
|
75
|
+
} else if (error instanceof RateLimitError) {
|
|
76
|
+
console.log('Rate limited, retry after:', error.retryAfter);
|
|
77
|
+
} else if (error instanceof AuthenticationError) {
|
|
78
|
+
console.log('Authentication failed');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**Available Error Classes:**
|
|
84
|
+
- `ForumAPIError` - Base class for all API errors
|
|
85
|
+
- `AuthenticationError` - 401 errors
|
|
86
|
+
- `AuthorizationError` - 403 errors
|
|
87
|
+
- `NotFoundError` - 404 errors
|
|
88
|
+
- `ValidationError` - 422 errors
|
|
89
|
+
- `RateLimitError` - 429 errors
|
|
90
|
+
- `ServerError` - 5xx errors
|
|
91
|
+
- `NetworkError` - Network/connection errors
|
|
92
|
+
|
|
93
|
+
## Pagination
|
|
94
|
+
|
|
95
|
+
The SDK provides multiple ways to handle pagination:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// Auto-pagination with async iterator
|
|
99
|
+
for await (const thread of client.pagination.paginateAll(
|
|
100
|
+
(cursor) => client.threads.list({ cursor, filter: 'newest' })
|
|
101
|
+
)) {
|
|
102
|
+
console.log(thread.title);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Fetch all pages at once
|
|
106
|
+
const allThreads = await client.pagination.fetchAllPages(
|
|
107
|
+
(cursor) => client.threads.list({ cursor }),
|
|
108
|
+
5 // max pages
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// Manual pagination
|
|
112
|
+
let cursor: string | undefined;
|
|
113
|
+
do {
|
|
114
|
+
const response = await client.threads.list({ cursor });
|
|
115
|
+
// Process threads...
|
|
116
|
+
cursor = response.nextThreadCursor;
|
|
117
|
+
} while (cursor);
|
|
29
118
|
```
|
|
30
119
|
|
|
120
|
+
## Webhooks
|
|
121
|
+
|
|
122
|
+
Verify webhook signatures for security. All webhooks include:
|
|
123
|
+
- `X-Webhook-Signature`: HMAC-SHA256 signature
|
|
124
|
+
- `X-Webhook-Timestamp`: Unix timestamp (milliseconds)
|
|
125
|
+
- `X-Webhook-Event`: Event type
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
app.post('/webhooks/foru', (req, res) => {
|
|
129
|
+
const signature = req.headers['x-webhook-signature'];
|
|
130
|
+
const timestamp = req.headers['x-webhook-timestamp'];
|
|
131
|
+
const event = req.headers['x-webhook-event'];
|
|
132
|
+
|
|
133
|
+
// Verify signature with timestamp (prevents replay attacks)
|
|
134
|
+
const isValid = client.webhooks.verifySignature(
|
|
135
|
+
req.body,
|
|
136
|
+
signature,
|
|
137
|
+
timestamp,
|
|
138
|
+
'your_webhook_secret'
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
if (!isValid) {
|
|
142
|
+
return res.status(401).send('Invalid signature');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Process webhook...
|
|
146
|
+
console.log('Event:', event);
|
|
147
|
+
res.send('OK');
|
|
148
|
+
});
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Rate Limiting
|
|
152
|
+
|
|
153
|
+
Track rate limit information automatically:
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
await client.threads.list();
|
|
157
|
+
|
|
158
|
+
if (client.lastRateLimitInfo) {
|
|
159
|
+
console.log('Limit:', client.lastRateLimitInfo.limit);
|
|
160
|
+
console.log('Remaining:', client.lastRateLimitInfo.remaining);
|
|
161
|
+
console.log('Resets at:', new Date(client.lastRateLimitInfo.reset * 1000));
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Examples
|
|
166
|
+
|
|
167
|
+
Check the `/examples` directory for detailed examples:
|
|
168
|
+
|
|
169
|
+
- [Authentication](./examples/authentication.ts) - Login, registration, token management
|
|
170
|
+
- [Managing Threads](./examples/managing-threads.ts) - CRUD operations, polls, interactions
|
|
171
|
+
- [Pagination](./examples/pagination.ts) - Different pagination strategies
|
|
172
|
+
- [Error Handling](./examples/error-handling.ts) - Comprehensive error handling
|
|
173
|
+
- [Webhooks](./examples/webhooks.ts) - Setup and verification
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
|
|
31
177
|
## API Reference
|
|
32
178
|
|
|
33
179
|
### Auth (`client.auth`)
|
|
@@ -40,7 +186,7 @@ client.setToken('user_jwt_token');
|
|
|
40
186
|
|
|
41
187
|
### Threads (`client.threads`)
|
|
42
188
|
|
|
43
|
-
* `list(params: { limit?: number; filter?: 'newest' | 'oldest'; tagId?: string;
|
|
189
|
+
* `list(params: { limit?: number; filter?: 'newest' | 'oldest'; tagId?: string; cursor?: string })`: List threads.
|
|
44
190
|
* `create(payload: CreateThreadPayload)`: Create a new thread.
|
|
45
191
|
* `retrieve(id: string)`: Get a thread by ID.
|
|
46
192
|
* `update(id: string, payload: UpdateThreadPayload)`: Update a thread.
|
|
@@ -48,10 +194,20 @@ client.setToken('user_jwt_token');
|
|
|
48
194
|
* `getPosts(id: string, params: { cursor?: string; filter?: 'newest' | 'oldest' })`: Get posts in a thread.
|
|
49
195
|
* `like(id: string, userId: string, extendedData?: any)`: Like a thread.
|
|
50
196
|
* `unlike(id: string, userId: string)`: Unlike a thread.
|
|
197
|
+
* `getLikes(id: string, params?: { cursor?: string })`: Get users who liked a thread.
|
|
51
198
|
* `dislike(id: string, userId: string, extendedData?: any)`: Dislike a thread.
|
|
52
199
|
* `undislike(id: string, userId: string)`: Remove dislike from a thread.
|
|
200
|
+
* `getDislikes(id: string, params?: { cursor?: string })`: Get users who disliked a thread.
|
|
53
201
|
* `subscribe(id: string, userId: string)`: Subscribe to a thread.
|
|
54
202
|
* `unsubscribe(id: string, userId: string)`: Unsubscribe from a thread.
|
|
203
|
+
* `getSubscribers(id: string, params?: { cursor?: string })`: Get users subscribed to a thread.
|
|
204
|
+
* `upvote(id: string, userId: string, extendedData?: any)`: Upvote a thread.
|
|
205
|
+
* `unupvote(id: string, userId: string)`: Remove upvote from a thread.
|
|
206
|
+
* `getUpvotes(id: string, params?: { cursor?: string })`: Get users who upvoted a thread.
|
|
207
|
+
* `downvote(id: string, userId: string, extendedData?: any)`: Downvote a thread.
|
|
208
|
+
* `undownvote(id: string, userId: string)`: Remove downvote from a thread.
|
|
209
|
+
* `getDownvotes(id: string, params?: { cursor?: string })`: Get users who downvoted a thread.
|
|
210
|
+
* `getPoll(id: string, userId?: string)`: Get poll results.
|
|
55
211
|
* `vote(id: string, userId: string, optionId: string)`: Vote in a thread poll.
|
|
56
212
|
* `voteUpdate(id: string, userId: string, optionId: string)`: Change vote.
|
|
57
213
|
* `unvote(id: string, userId: string)`: Remove vote.
|
|
@@ -66,41 +222,51 @@ client.setToken('user_jwt_token');
|
|
|
66
222
|
* `getChildren(id: string, params: { cursor?: string; filter?: 'newest' | 'oldest' })`: Get child posts (nested replies).
|
|
67
223
|
* `like(id: string, userId: string, extendedData?: any)`: Like a post.
|
|
68
224
|
* `unlike(id: string, userId: string)`: Unlike a post.
|
|
225
|
+
* `getLikes(id: string, params?: { cursor?: string })`: Get users who liked a post.
|
|
69
226
|
* `dislike(id: string, userId: string, extendedData?: any)`: Dislike a post.
|
|
70
227
|
* `undislike(id: string, userId: string)`: Remove dislike.
|
|
228
|
+
* `getDislikes(id: string, params?: { cursor?: string })`: Get users who disliked a post.
|
|
71
229
|
* `upvote(id: string, userId: string, extendedData?: any)`: Upvote a post.
|
|
72
230
|
* `unupvote(id: string, userId: string)`: Remove upvote.
|
|
231
|
+
* `getUpvotes(id: string, params?: { cursor?: string })`: Get users who upvoted a post.
|
|
73
232
|
* `downvote(id: string, userId: string, extendedData?: any)`: Downvote a post.
|
|
74
233
|
* `undownvote(id: string, userId: string)`: Remove downvote.
|
|
234
|
+
* `getDownvotes(id: string, params?: { cursor?: string })`: Get users who downvoted a post.
|
|
75
235
|
|
|
76
236
|
### Users (`client.users`)
|
|
77
237
|
|
|
78
|
-
* `list(params
|
|
79
|
-
* `retrieve(
|
|
80
|
-
* `create(payload: any)`: Create a user (Admin).
|
|
81
|
-
* `update(id: string, payload: any)`: Update a user.
|
|
238
|
+
* `list(params?: { query?: string; filter?: 'newest' | 'oldest'; cursor?: string })`: List users.
|
|
239
|
+
* `retrieve(userId: string)`: Get user by ID.
|
|
240
|
+
* `create(payload: { username: string; email: string; password: string; displayName?: string; emailVerified?: boolean; roles?: string[]; bio?: string; signature?: string; url?: string; extendedData?: Record<string, any> })`: Create a user (Admin).
|
|
241
|
+
* `update(id: string, payload: { username?: string; email?: string; password?: string; displayName?: string; emailVerified?: boolean; roles?: string[]; bio?: string; signature?: string; url?: string; extendedData?: Record<string, any> })`: Update a user.
|
|
82
242
|
* `delete(id: string)`: Delete a user.
|
|
83
|
-
* `
|
|
84
|
-
* `
|
|
243
|
+
* `getThreads(id: string, params?: { query?: string; cursor?: string; filter?: 'newest' | 'oldest' })`: Get all threads created by a user.
|
|
244
|
+
* `getPosts(id: string, params?: { query?: string; cursor?: string; filter?: 'newest' | 'oldest' })`: Get all posts created by a user.
|
|
245
|
+
* `getFollowers(id: string, params?: { query?: string; cursor?: string; filter?: 'newest' | 'oldest' })`: Get user's followers.
|
|
246
|
+
* `getFollowing(id: string, params?: { query?: string; cursor?: string; filter?: 'newest' | 'oldest' })`: Get who a user follows.
|
|
85
247
|
* `follow(id: string, followerId: string, extendedData?: any)`: Follow a user.
|
|
86
248
|
* `unfollow(id: string, followerId: string)`: Unfollow a user.
|
|
87
249
|
|
|
250
|
+
|
|
88
251
|
### Tags (`client.tags`)
|
|
89
252
|
|
|
90
|
-
* `list(params
|
|
91
|
-
* `create(payload: { name: string; description?: string; color?: string; extendedData?: any })`: Create a tag.
|
|
253
|
+
* `list(params?: { query?: string; cursor?: string })`: List tags.
|
|
254
|
+
* `create(payload: { name: string; description?: string; color?: string; extendedData?: Record<string, any> })`: Create a tag.
|
|
92
255
|
* `retrieve(id: string, params?: { userId?: string })`: Get a tag.
|
|
93
|
-
* `update(id: string, payload: any)`: Update a tag.
|
|
256
|
+
* `update(id: string, payload: { name?: string; description?: string; color?: string; extendedData?: Record<string, any> })`: Update a tag.
|
|
94
257
|
* `delete(id: string)`: Delete a tag.
|
|
258
|
+
* `getThreads(id: string, params?: { query?: string; cursor?: string; filter?: 'newest' | 'oldest' })`: Get all threads with a specific tag.
|
|
95
259
|
* `subscribe(id: string, userId: string)`: Subscribe to a tag.
|
|
96
260
|
* `unsubscribe(id: string, userId: string)`: Unsubscribe from a tag.
|
|
97
|
-
* `
|
|
261
|
+
* `getSubscribers(id: string, params?: { cursor?: string })`: Get users subscribed to a tag.
|
|
262
|
+
* `listSubscribed(params: { userId: string; query?: string; cursor?: string })`: List tags a user is subscribed to.
|
|
263
|
+
|
|
98
264
|
|
|
99
265
|
### Notifications (`client.notifications`)
|
|
100
266
|
|
|
101
|
-
* `list(params: { userId: string; read?: boolean; filter?:
|
|
102
|
-
* `markAllAsRead(userId: string, read?: boolean)`: Bulk update read status.
|
|
103
|
-
* `create(payload: any)`: Create a notification manually.
|
|
267
|
+
* `list(params: { userId: string; read?: boolean; filter?: 'newest' | 'oldest'; cursor?: string })`: List notifications.
|
|
268
|
+
* `markAllAsRead(userId: string, read?: boolean)`: Bulk update read status. Default is `true`.
|
|
269
|
+
* `create(payload: { threadId?: string; postId?: string; privateMessageId?: string; notifierId: string; notifiedId: string; type: string; description?: string; extendedData?: Record<string, any> })`: Create a notification manually.
|
|
104
270
|
* `retrieve(id: string)`: Get a notification.
|
|
105
271
|
* `update(id: string, payload: { read: boolean })`: Update a notification.
|
|
106
272
|
* `delete(id: string)`: Delete a notification.
|
|
@@ -125,65 +291,236 @@ client.setToken('user_jwt_token');
|
|
|
125
291
|
### Integrations (`client.integrations`)
|
|
126
292
|
|
|
127
293
|
* `list()`: Get all configured integrations.
|
|
128
|
-
* `create(payload: { type:
|
|
294
|
+
* `create(payload: { type: 'SLACK' | 'DISCORD' | 'SALESFORCE' | 'HUBSPOT' | 'OKTA' | 'AUTH0'; name: string; config: any })`: Configure an integration (Slack, Discord, etc.).
|
|
129
295
|
* `retrieve(id: string)`: Get integration details.
|
|
296
|
+
* `update(id: string, payload: { name?: string; config?: any; active?: boolean })`: Update an integration.
|
|
130
297
|
* `delete(id: string)`: Remove an integration.
|
|
131
298
|
|
|
132
299
|
### Private Messages (`client.privateMessages`)
|
|
133
300
|
|
|
134
|
-
* `list(params
|
|
135
|
-
* `create(payload: { title?: string; body: string; recipientId: string; senderId?: string })`: Send a direct message.
|
|
301
|
+
* `list(params?: { query?: string; userId?: string; filter?: 'newest' | 'oldest'; cursor?: string })`: List private messages.
|
|
302
|
+
* `create(payload: { title?: string; body: string; recipientId: string; senderId?: string; extendedData?: Record<string, any> })`: Send a direct message.
|
|
136
303
|
* `retrieve(id: string)`: Get a message thread.
|
|
137
|
-
* `reply(id: string, payload: { body: string; senderId: string; recipientId: string })`: Reply to a message.
|
|
304
|
+
* `reply(id: string, payload: { body: string; senderId: string; recipientId: string; extendedData?: Record<string, any> })`: Reply to a message.
|
|
305
|
+
* `update(id: string, payload: { read?: boolean; extendedData?: Record<string, any> })`: Update a message (e.g., mark as read).
|
|
138
306
|
* `delete(id: string)`: Delete a message.
|
|
139
307
|
|
|
140
308
|
### Reports (`client.reports`)
|
|
141
309
|
|
|
142
|
-
* `list(params
|
|
143
|
-
* `create(payload: { reporterId: string; type
|
|
310
|
+
* `list(params?: { reporterId?: string; reportedId?: string; read?: boolean; cursor?: string; filter?: 'newest' | 'oldest' })`: List reports.
|
|
311
|
+
* `create(payload: { reporterId: string; reportedId?: string; threadId?: string; postId?: string; privateMessageId?: string; type?: string; description?: string; extendedData?: Record<string, any> })`: Submit a report.
|
|
144
312
|
* `batchUpdate(payload: { reportIds: string[]; read: boolean })`: Bulk update status.
|
|
145
313
|
* `retrieve(id: string)`: Get a report.
|
|
146
|
-
* `update(id: string, payload: any)`: Update report details.
|
|
314
|
+
* `update(id: string, payload: { threadId?: string; postId?: string; privateMessageId?: string; reportedId?: string; reporterId?: string; type?: string; description?: string; read?: boolean; extendedData?: Record<string, any> })`: Update report details.
|
|
147
315
|
* `delete(id: string)`: Delete a report.
|
|
148
316
|
* `updateStatus(id: string, read: boolean)`: Update read status of a report.
|
|
149
317
|
|
|
150
318
|
### Roles (`client.roles`)
|
|
151
319
|
|
|
152
|
-
* `list(params
|
|
153
|
-
* `create(payload: { name: string; description?: string; color?: string })`: Create a new role.
|
|
320
|
+
* `list(params?: { filter?: 'newest' | 'oldest'; cursor?: string })`: List user roles.
|
|
321
|
+
* `create(payload: { name: string; description?: string; color?: string; extendedData?: Record<string, any> })`: Create a new role.
|
|
154
322
|
* `retrieve(id: string)`: Get a role.
|
|
155
|
-
* `update(id: string, payload: any)`: Update a role.
|
|
323
|
+
* `update(id: string, payload: { name?: string; description?: string; color?: string; extendedData?: Record<string, any> })`: Update a role.
|
|
156
324
|
* `delete(id: string)`: Delete a role.
|
|
157
325
|
|
|
158
326
|
### SSO (`client.sso`)
|
|
159
327
|
|
|
160
328
|
* `list()`: List SSO providers.
|
|
161
|
-
* `create(payload: { provider:
|
|
329
|
+
* `create(payload: { provider: 'OKTA' | 'AUTH0' | 'SAML'; domain: string; config: any })`: Configure SSO.
|
|
330
|
+
* `retrieve(id: string)`: Get SSO provider details.
|
|
331
|
+
* `update(id: string, payload: { domain?: string; config?: any; active?: boolean })`: Update SSO configuration.
|
|
162
332
|
* `delete(id: string)`: Remove SSO provider.
|
|
163
333
|
|
|
164
334
|
## Types
|
|
165
335
|
|
|
166
|
-
Import interfaces directly from the package:
|
|
336
|
+
Import all available interfaces and types directly from the package:
|
|
167
337
|
|
|
168
338
|
```typescript
|
|
169
339
|
import {
|
|
170
|
-
|
|
171
|
-
|
|
340
|
+
// Auth Types
|
|
341
|
+
RegisterPayload,
|
|
342
|
+
User,
|
|
343
|
+
LoginResponse,
|
|
344
|
+
|
|
345
|
+
// Thread Types
|
|
346
|
+
Thread,
|
|
347
|
+
CreateThreadPayload,
|
|
348
|
+
UpdateThreadPayload,
|
|
349
|
+
ThreadListResponse,
|
|
350
|
+
ThreadFilter,
|
|
351
|
+
|
|
352
|
+
// Post Types
|
|
353
|
+
Post,
|
|
354
|
+
CreatePostPayload,
|
|
355
|
+
UpdatePostPayload,
|
|
356
|
+
PostListResponse,
|
|
357
|
+
|
|
358
|
+
// Tag Types
|
|
359
|
+
Tag,
|
|
360
|
+
TagListResponse,
|
|
361
|
+
|
|
362
|
+
// User Types
|
|
363
|
+
UserListResponse,
|
|
364
|
+
|
|
365
|
+
// Notification Types
|
|
366
|
+
Notification,
|
|
367
|
+
NotificationListResponse,
|
|
368
|
+
|
|
369
|
+
// Search Types
|
|
370
|
+
SearchResponse,
|
|
371
|
+
|
|
372
|
+
// Webhook Types
|
|
373
|
+
Webhook,
|
|
374
|
+
WebhookListResponse,
|
|
375
|
+
|
|
376
|
+
// Stats Types
|
|
377
|
+
StatsResponse,
|
|
378
|
+
|
|
379
|
+
// Integration Types
|
|
380
|
+
Integration,
|
|
381
|
+
IntegrationListResponse,
|
|
382
|
+
|
|
383
|
+
// Private Message Types
|
|
384
|
+
PrivateMessage,
|
|
385
|
+
PrivateMessageListResponse,
|
|
386
|
+
|
|
387
|
+
// Report Types
|
|
388
|
+
Report,
|
|
389
|
+
ReportListResponse,
|
|
390
|
+
|
|
391
|
+
// Role Types
|
|
392
|
+
Role,
|
|
393
|
+
RoleListResponse,
|
|
394
|
+
|
|
395
|
+
// SSO Types
|
|
396
|
+
SSOProvider,
|
|
397
|
+
SSOProviderListResponse,
|
|
398
|
+
|
|
399
|
+
// Utility Types
|
|
400
|
+
PaginatedResponse,
|
|
401
|
+
InteractionType,
|
|
402
|
+
|
|
403
|
+
// Error Classes
|
|
404
|
+
ForumAPIError,
|
|
405
|
+
AuthenticationError,
|
|
406
|
+
AuthorizationError,
|
|
407
|
+
NotFoundError,
|
|
408
|
+
ValidationError,
|
|
409
|
+
RateLimitError,
|
|
410
|
+
ServerError,
|
|
411
|
+
NetworkError,
|
|
412
|
+
|
|
413
|
+
// Response Types
|
|
414
|
+
RateLimitInfo,
|
|
415
|
+
ResponseMetadata,
|
|
416
|
+
APIResponse,
|
|
417
|
+
InteractionListResponse,
|
|
418
|
+
PollResponse,
|
|
419
|
+
PollOption,
|
|
420
|
+
|
|
421
|
+
// Utilities
|
|
422
|
+
PaginationHelper,
|
|
423
|
+
Validator,
|
|
424
|
+
RetryHelper
|
|
172
425
|
} from '@foru-ms/sdk';
|
|
173
426
|
```
|
|
174
427
|
|
|
175
|
-
##
|
|
428
|
+
## Advanced Usage
|
|
176
429
|
|
|
177
|
-
|
|
430
|
+
### Custom Client Options
|
|
178
431
|
|
|
179
432
|
```typescript
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
433
|
+
const client = new ForumClient({
|
|
434
|
+
apiKey: 'your_api_key',
|
|
435
|
+
baseUrl: 'https://api.foru.ms/v1',
|
|
436
|
+
maxRetries: 5, // Increase retry attempts
|
|
437
|
+
enableRetry: true, // Enable auto-retry (default: true)
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
// Access rate limit info after any request
|
|
441
|
+
await client.threads.list();
|
|
442
|
+
console.log('Rate limit:', client.lastRateLimitInfo);
|
|
443
|
+
|
|
444
|
+
// Check authentication status
|
|
445
|
+
if (client.isAuthenticated()) {
|
|
446
|
+
const user = await client.auth.me();
|
|
184
447
|
}
|
|
185
448
|
```
|
|
186
449
|
|
|
450
|
+
### Async Iteration for Large Datasets
|
|
451
|
+
|
|
452
|
+
```typescript
|
|
453
|
+
// Automatically fetch all pages
|
|
454
|
+
for await (const user of client.pagination.paginateAll(
|
|
455
|
+
(cursor) => client.users.list({ cursor })
|
|
456
|
+
)) {
|
|
457
|
+
await processUser(user);
|
|
458
|
+
// Pagination happens automatically in the background
|
|
459
|
+
}
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
### Batch Operations
|
|
463
|
+
|
|
464
|
+
```typescript
|
|
465
|
+
// Fetch multiple items efficiently
|
|
466
|
+
const threadIds = ['id1', 'id2', 'id3'];
|
|
467
|
+
const threads = await Promise.all(
|
|
468
|
+
threadIds.map(id => client.threads.retrieve(id))
|
|
469
|
+
);
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
## Best Practices
|
|
473
|
+
|
|
474
|
+
1. **Error Handling**: Always use try-catch with specific error types
|
|
475
|
+
2. **Rate Limits**: Monitor `client.lastRateLimitInfo` for API usage
|
|
476
|
+
3. **Webhooks**: Always verify signatures to prevent unauthorized requests
|
|
477
|
+
4. **Pagination**: Use async iterators for large result sets
|
|
478
|
+
5. **Authentication**: Store tokens securely, never in client-side code
|
|
479
|
+
|
|
480
|
+
## Troubleshooting
|
|
481
|
+
|
|
482
|
+
### Rate Limit Errors
|
|
483
|
+
|
|
484
|
+
If you encounter rate limit errors frequently, consider:
|
|
485
|
+
- Implementing caching for frequently accessed data
|
|
486
|
+
- Using pagination helpers to avoid fetching too much data
|
|
487
|
+
- Batching operations where possible
|
|
488
|
+
|
|
489
|
+
### Authentication Issues
|
|
490
|
+
|
|
491
|
+
- Ensure your API key is valid and active
|
|
492
|
+
- Check that tokens haven't expired
|
|
493
|
+
- Use `client.isAuthenticated()` to verify authentication status
|
|
494
|
+
|
|
495
|
+
### Webhook Verification Failures
|
|
496
|
+
|
|
497
|
+
- Verify you're using the correct webhook secret
|
|
498
|
+
- Check that timestamps aren't too old (default: 5 minutes)
|
|
499
|
+
- Ensure you're passing the raw payload object, not a string
|
|
500
|
+
|
|
501
|
+
## Contributing
|
|
502
|
+
|
|
503
|
+
We welcome contributions! Please see our contributing guidelines for more information.
|
|
504
|
+
|
|
505
|
+
## Support
|
|
506
|
+
|
|
507
|
+
- 📧 Email: support@foru.ms
|
|
508
|
+
- 📚 Documentation: https://docs.foru.ms
|
|
509
|
+
- 🐛 Issues: https://github.com/foru-ms/sdk/issues
|
|
510
|
+
|
|
511
|
+
## Changelog
|
|
512
|
+
|
|
513
|
+
### v1.2.0
|
|
514
|
+
- Added custom error classes for better error handling
|
|
515
|
+
- Added automatic retry logic with exponential backoff
|
|
516
|
+
- Added pagination helpers for easy iteration
|
|
517
|
+
- Added webhook signature verification
|
|
518
|
+
- Added 22 new endpoints
|
|
519
|
+
- Enhanced documentation and examples
|
|
520
|
+
|
|
521
|
+
### v1.x
|
|
522
|
+
- Initial SDK release with core functionality
|
|
523
|
+
|
|
187
524
|
## License
|
|
188
525
|
|
|
189
526
|
MIT
|
package/dist/Client.d.ts
CHANGED
|
@@ -12,10 +12,42 @@ import { PrivateMessagesResource } from './resources/PrivateMessages';
|
|
|
12
12
|
import { ReportsResource } from './resources/Reports';
|
|
13
13
|
import { RolesResource } from './resources/Roles';
|
|
14
14
|
import { SSOResource } from './resources/SSO';
|
|
15
|
+
import { PaginationHelper } from './utils';
|
|
16
|
+
import { RateLimitInfo } from './response-types';
|
|
17
|
+
export interface ClientOptions {
|
|
18
|
+
/** API key for authentication */
|
|
19
|
+
apiKey: string;
|
|
20
|
+
/** Base URL for the API (default: https://api.foru.ms/v1) */
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
/** Maximum number of retry attempts for failed requests (default: 3) */
|
|
23
|
+
maxRetries?: number;
|
|
24
|
+
/** Enable automatic retry for rate limits and server errors (default: true) */
|
|
25
|
+
enableRetry?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Main client for interacting with the Foru.ms API
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const client = new ForumClient({
|
|
32
|
+
* apiKey: 'your_api_key',
|
|
33
|
+
* baseUrl: 'https://api.foru.ms/v1'
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* // Set user token
|
|
37
|
+
* client.setToken('user_jwt_token');
|
|
38
|
+
*
|
|
39
|
+
* // Use resources
|
|
40
|
+
* const threads = await client.threads.list();
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
15
43
|
export declare class ForumClient {
|
|
16
44
|
apiKey: string;
|
|
17
45
|
token: string | null;
|
|
18
46
|
baseUrl: string;
|
|
47
|
+
maxRetries: number;
|
|
48
|
+
enableRetry: boolean;
|
|
49
|
+
/** Last known rate limit info */
|
|
50
|
+
lastRateLimitInfo?: RateLimitInfo;
|
|
19
51
|
auth: AuthResource;
|
|
20
52
|
threads: ThreadsResource;
|
|
21
53
|
posts: PostsResource;
|
|
@@ -30,10 +62,37 @@ export declare class ForumClient {
|
|
|
30
62
|
reports: ReportsResource;
|
|
31
63
|
roles: RolesResource;
|
|
32
64
|
sso: SSOResource;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
65
|
+
/** Pagination helper for auto-paginating through results */
|
|
66
|
+
pagination: PaginationHelper;
|
|
67
|
+
constructor(options: ClientOptions);
|
|
68
|
+
/**
|
|
69
|
+
* Make an HTTP request to the API
|
|
70
|
+
* @param path - API endpoint path
|
|
71
|
+
* @param options - Fetch options
|
|
72
|
+
* @returns Promise resolving to the response data
|
|
73
|
+
* @throws {ForumAPIError} When the API returns an error
|
|
74
|
+
* @throws {NetworkError} When the network request fails
|
|
75
|
+
*/
|
|
37
76
|
request<T>(path: string, options?: RequestInit): Promise<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Set the authentication token for user-scoped requests
|
|
79
|
+
* @param token - JWT token
|
|
80
|
+
*/
|
|
38
81
|
setToken(token: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Clear the authentication token
|
|
84
|
+
*/
|
|
85
|
+
clearToken(): void;
|
|
86
|
+
/**
|
|
87
|
+
* Check if client is authenticated
|
|
88
|
+
*/
|
|
89
|
+
isAuthenticated(): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Extract and store rate limit information from response headers
|
|
92
|
+
*/
|
|
93
|
+
private extractRateLimitInfo;
|
|
94
|
+
/**
|
|
95
|
+
* Handle error responses by throwing appropriate error types
|
|
96
|
+
*/
|
|
97
|
+
private handleErrorResponse;
|
|
39
98
|
}
|