@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.
Files changed (47) hide show
  1. package/README.md +375 -38
  2. package/dist/Client.d.ts +63 -4
  3. package/dist/Client.js +124 -22
  4. package/dist/errors.d.ts +52 -0
  5. package/dist/errors.js +95 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.js +3 -0
  8. package/dist/resources/Integrations.d.ts +7 -0
  9. package/dist/resources/Integrations.js +6 -0
  10. package/dist/resources/Posts.d.ts +12 -0
  11. package/dist/resources/Posts.js +44 -0
  12. package/dist/resources/PrivateMessages.d.ts +4 -0
  13. package/dist/resources/PrivateMessages.js +6 -0
  14. package/dist/resources/SSO.d.ts +10 -0
  15. package/dist/resources/SSO.js +11 -0
  16. package/dist/resources/Tags.d.ts +8 -0
  17. package/dist/resources/Tags.js +24 -0
  18. package/dist/resources/Threads.d.ts +20 -0
  19. package/dist/resources/Threads.js +85 -0
  20. package/dist/resources/Users.d.ts +10 -0
  21. package/dist/resources/Users.js +26 -0
  22. package/dist/resources/Webhooks.d.ts +69 -0
  23. package/dist/resources/Webhooks.js +115 -0
  24. package/dist/response-types.d.ts +105 -0
  25. package/dist/response-types.js +2 -0
  26. package/dist/utils.d.ts +80 -0
  27. package/dist/utils.js +138 -0
  28. package/examples/README.md +38 -0
  29. package/examples/authentication.ts +79 -0
  30. package/examples/error-handling.ts +133 -0
  31. package/examples/managing-threads.ts +130 -0
  32. package/examples/pagination.ts +81 -0
  33. package/examples/webhooks.ts +176 -0
  34. package/package.json +1 -1
  35. package/src/Client.ts +165 -25
  36. package/src/errors.ts +95 -0
  37. package/src/index.ts +3 -0
  38. package/src/resources/Integrations.ts +11 -0
  39. package/src/resources/Posts.ts +56 -0
  40. package/src/resources/PrivateMessages.ts +10 -0
  41. package/src/resources/SSO.ts +17 -0
  42. package/src/resources/Tags.ts +32 -0
  43. package/src/resources/Threads.ts +109 -0
  44. package/src/resources/Users.ts +36 -0
  45. package/src/resources/Webhooks.ts +131 -0
  46. package/src/response-types.ts +113 -0
  47. 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
- ## Setup & Initialization
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
- // baseUrl: 'https://api.foru.ms/v1' // Optional
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; categoryId?: string; cursor?: string })`: List threads.
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: { query?: string; filter?: 'newest' | 'oldest'; cursor?: string })`: List users.
79
- * `retrieve(id: string)`: Get user by ID.
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
- * `getFollowers(id: string, params: { cursor?: string })`: Get user's followers.
84
- * `getFollowing(id: string, params: { cursor?: string })`: Get who a user follows.
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: { query?: string; cursor?: string })`: List tags.
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
- * `listSubscribed(params: { userId: string; cursor?: string })`: List tags a user is subscribed to.
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?: string; cursor?: string })`: List notifications.
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: string; name: string; config: any })`: Configure an integration (Slack, Discord, etc.).
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: { userId?: string; cursor?: string })`: List private messages.
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: { reporterId?: string; reportedId?: string; read?: boolean; cursor?: string })`: List reports.
143
- * `create(payload: { reporterId: string; type: string; description?: string; ... })`: Submit a report.
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: { cursor?: string })`: List user roles.
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: string; domain: string; config: any })`: Configure SSO.
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
- Thread, Post, User, Tag, Notification,
171
- LoginResponse, RegisterPayload
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
- ## Error Handling
428
+ ## Advanced Usage
176
429
 
177
- All methods return a Promise. If the API returns a non-200 status, the Promise rejects with an Error object containing the server message.
430
+ ### Custom Client Options
178
431
 
179
432
  ```typescript
180
- try {
181
- await client.threads.create({ ... });
182
- } catch (err: any) {
183
- console.error("Error creating thread:", err.message);
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
- constructor(options: {
34
- apiKey: string;
35
- baseUrl?: string;
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
  }