@rooguys/js 0.1.0 → 1.0.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 (28) hide show
  1. package/README.md +342 -141
  2. package/package.json +1 -1
  3. package/src/__tests__/fixtures/responses.js +249 -0
  4. package/src/__tests__/property/batch-event-validation.property.test.js +225 -0
  5. package/src/__tests__/property/email-validation.property.test.js +272 -0
  6. package/src/__tests__/property/error-mapping.property.test.js +506 -0
  7. package/src/__tests__/property/field-selection.property.test.js +297 -0
  8. package/src/__tests__/property/idempotency-key.property.test.js +350 -0
  9. package/src/__tests__/property/leaderboard-filter.property.test.js +585 -0
  10. package/src/__tests__/property/partial-update.property.test.js +251 -0
  11. package/src/__tests__/property/rate-limit-error.property.test.js +276 -0
  12. package/src/__tests__/property/rate-limit-extraction.property.test.js +193 -0
  13. package/src/__tests__/property/request-construction.property.test.js +20 -28
  14. package/src/__tests__/property/response-format.property.test.js +418 -0
  15. package/src/__tests__/property/response-parsing.property.test.js +16 -21
  16. package/src/__tests__/property/timestamp-validation.property.test.js +345 -0
  17. package/src/__tests__/unit/aha.test.js +57 -26
  18. package/src/__tests__/unit/config.test.js +7 -1
  19. package/src/__tests__/unit/errors.test.js +6 -8
  20. package/src/__tests__/unit/events.test.js +253 -14
  21. package/src/__tests__/unit/leaderboards.test.js +249 -0
  22. package/src/__tests__/unit/questionnaires.test.js +6 -6
  23. package/src/__tests__/unit/users.test.js +275 -12
  24. package/src/__tests__/utils/generators.js +87 -0
  25. package/src/__tests__/utils/mockClient.js +71 -5
  26. package/src/errors.js +156 -0
  27. package/src/http-client.js +276 -0
  28. package/src/index.js +856 -66
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Rooguys Javascript SDK
1
+ # Rooguys JavaScript SDK
2
2
 
3
3
  The official Browser SDK for the Rooguys Gamification API. Lightweight and dependency-free (uses native `fetch`).
4
4
 
@@ -21,257 +21,458 @@ import Rooguys from '@rooguys/js';
21
21
 
22
22
  const client = new Rooguys('YOUR_API_KEY', {
23
23
  baseUrl: 'https://api.rooguys.com/v1',
24
+ timeout: 10000,
25
+ // Rate limit handling
26
+ onRateLimitWarning: (info) => {
27
+ console.warn(`Rate limit warning: ${info.remaining}/${info.limit} remaining`);
28
+ },
29
+ autoRetry: true,
30
+ maxRetries: 3,
24
31
  });
25
32
  ```
26
33
 
27
- ## Usage Examples
34
+ ## Migration Guide (v1.x to v2.x)
28
35
 
29
- ### 1. Track an Event
36
+ ### Breaking Changes
30
37
 
31
- ```javascript
32
- client.events.track('level_completed', 'user_123', { difficulty: 'hard' })
33
- .then(response => {
34
- console.log('Event tracked:', response);
35
- })
36
- .catch(console.error);
37
- ```
38
+ 1. **Event Tracking Endpoint**: The SDK now uses `/v1/events` instead of `/v1/event`
39
+ ```javascript
40
+ // Old (deprecated, still works with warning)
41
+ client.events.trackLegacy('event_name', 'user_id', properties);
42
+
43
+ // New (recommended)
44
+ client.events.track('event-name', 'user_id', properties);
45
+ ```
46
+
47
+ 2. **Global Leaderboard Endpoint**: Now uses `/v1/leaderboards/global` with `timeframe` query parameter
48
+ ```javascript
49
+ // Both signatures work
50
+ client.leaderboards.getGlobal('weekly', 1, 10);
51
+ client.leaderboards.getGlobal({ timeframe: 'weekly', page: 1, limit: 10 });
52
+ ```
53
+
54
+ 3. **Response Format**: All responses now follow standardized format `{ success: true, data: {...} }`
55
+
56
+ ### New Features
38
57
 
39
- ### 2. Get User Profile
58
+ - Batch event tracking (`events.trackBatch`)
59
+ - User management (`users.create`, `users.update`, `users.createBatch`)
60
+ - User search (`users.search`)
61
+ - Field selection for user profiles
62
+ - Leaderboard filters (persona, level range, date range)
63
+ - "Around me" leaderboard view (`leaderboards.getAroundUser`)
64
+ - Health check endpoints
65
+ - Rate limit handling with auto-retry
66
+ - Typed error classes
67
+
68
+ ## Usage Examples
69
+
70
+ ### Events
71
+
72
+ #### Track a Single Event
40
73
 
41
74
  ```javascript
42
- async function showProfile(userId) {
43
- try {
44
- const user = await client.users.get(userId);
45
- document.getElementById('points').innerText = user.points;
46
- document.getElementById('level').innerText = user.level?.name || 'No Level';
47
- } catch (error) {
48
- console.error('Failed to load profile:', error);
49
- }
75
+ const response = await client.events.track('level-completed', 'user_123', {
76
+ difficulty: 'hard',
77
+ score: 1500
78
+ }, {
79
+ includeProfile: true,
80
+ idempotencyKey: 'unique-request-id'
81
+ });
82
+
83
+ console.log('Event tracked:', response.status);
84
+ if (response.profile) {
85
+ console.log('Updated points:', response.profile.points);
50
86
  }
51
87
  ```
52
88
 
53
- ### 3. Display Leaderboard
89
+ #### Track Events with Custom Timestamp
54
90
 
55
91
  ```javascript
56
- async function loadLeaderboard() {
57
- const data = await client.leaderboards.getGlobal('weekly');
58
-
59
- const list = document.getElementById('leaderboard');
60
- list.innerHTML = data.rankings
61
- .map(r => `<li>#${r.rank} ${r.user_id}: ${r.points}</li>`)
62
- .join('');
63
- }
92
+ // Track historical events (up to 7 days in the past)
93
+ const response = await client.events.track('purchase', 'user_123', {
94
+ amount: 99.99
95
+ }, {
96
+ timestamp: new Date('2024-01-15T10:30:00Z')
97
+ });
64
98
  ```
65
99
 
66
- ### 4. List Custom Leaderboards
100
+ #### Batch Event Tracking
67
101
 
68
102
  ```javascript
69
- // Get all available leaderboards
70
- const leaderboards = await client.leaderboards.list(1, 20);
103
+ // Track up to 100 events in a single request
104
+ const response = await client.events.trackBatch([
105
+ { eventName: 'page-view', userId: 'user_123', properties: { page: '/home' } },
106
+ { eventName: 'button-click', userId: 'user_123', properties: { button: 'signup' } },
107
+ { eventName: 'purchase', userId: 'user_456', properties: { amount: 50 }, timestamp: new Date() }
108
+ ], {
109
+ idempotencyKey: 'batch-123'
110
+ });
71
111
 
72
- leaderboards.data.forEach(lb => {
73
- console.log(`${lb.name}: ${lb.description}`);
112
+ // Check individual results
113
+ response.results.forEach((result, index) => {
114
+ if (result.status === 'queued') {
115
+ console.log(`Event ${index} queued successfully`);
116
+ } else {
117
+ console.error(`Event ${index} failed:`, result.error);
118
+ }
74
119
  });
75
120
  ```
76
121
 
77
- ### 5. Get Custom Leaderboard Rankings
122
+ ### Users
78
123
 
79
- ```javascript
80
- // Get rankings for a specific leaderboard
81
- const customLb = await client.leaderboards.getCustom('leaderboard_id', 1, 10);
124
+ #### Create a New User
82
125
 
83
- console.log(`Leaderboard: ${customLb.name}`);
84
- customLb.rankings.forEach(entry => {
85
- console.log(`#${entry.rank} - ${entry.user_id}: ${entry.points} pts`);
126
+ ```javascript
127
+ const user = await client.users.create({
128
+ userId: 'user_123',
129
+ displayName: 'John Doe',
130
+ email: 'john@example.com',
131
+ firstName: 'John',
132
+ lastName: 'Doe',
133
+ metadata: { plan: 'premium' }
86
134
  });
87
135
  ```
88
136
 
89
- ### 6. Get User Rank in Custom Leaderboard
137
+ #### Update User Profile
90
138
 
91
139
  ```javascript
92
- const rank = await client.leaderboards.getUserRank('leaderboard_id', 'user_123');
93
-
94
- console.log(`User rank: #${rank.rank} out of ${rank.total_users}`);
140
+ // Partial update - only sends provided fields
141
+ const updated = await client.users.update('user_123', {
142
+ displayName: 'Johnny Doe',
143
+ metadata: { plan: 'enterprise' }
144
+ });
95
145
  ```
96
146
 
97
- ### 7. List Badges
147
+ #### Batch User Creation
98
148
 
99
149
  ```javascript
100
- // Get all active badges
101
- const badges = await client.badges.list(1, 50, true);
150
+ const response = await client.users.createBatch([
151
+ { userId: 'user_1', displayName: 'User One', email: 'one@example.com' },
152
+ { userId: 'user_2', displayName: 'User Two', email: 'two@example.com' },
153
+ // ... up to 100 users
154
+ ]);
155
+ ```
102
156
 
103
- badges.data.forEach(badge => {
104
- console.log(`${badge.name}: ${badge.description}`);
157
+ #### Get User Profile with Field Selection
158
+
159
+ ```javascript
160
+ // Only fetch specific fields
161
+ const user = await client.users.get('user_123', {
162
+ fields: ['points', 'level', 'badges']
105
163
  });
106
164
  ```
107
165
 
108
- ### 8. List Levels
166
+ #### Search Users
109
167
 
110
168
  ```javascript
111
- const levels = await client.levels.list();
169
+ const results = await client.users.search('john', {
170
+ page: 1,
171
+ limit: 20,
172
+ fields: ['userId', 'displayName', 'points']
173
+ });
112
174
 
113
- levels.data.forEach(level => {
114
- console.log(`Level ${level.level_number}: ${level.name} (${level.points_required} pts)`);
175
+ results.users.forEach(user => {
176
+ console.log(`${user.displayName}: ${user.points} points`);
115
177
  });
116
178
  ```
117
179
 
118
- ### 9. Get Questionnaire
180
+ #### Access Enhanced Profile Data
119
181
 
120
182
  ```javascript
121
- // Get questionnaire by slug
122
- const questionnaire = await client.questionnaires.get('onboarding-survey');
183
+ const user = await client.users.get('user_123');
123
184
 
124
- console.log(`Title: ${questionnaire.title}`);
125
- questionnaire.questions.forEach(q => {
126
- console.log(`Q: ${q.text}`);
127
- });
185
+ // Activity summary
186
+ if (user.activitySummary) {
187
+ console.log(`Last active: ${user.activitySummary.lastEventAt}`);
188
+ console.log(`Total events: ${user.activitySummary.eventCount}`);
189
+ console.log(`Days active: ${user.activitySummary.daysActive}`);
190
+ }
191
+
192
+ // Streak information
193
+ if (user.streak) {
194
+ console.log(`Current streak: ${user.streak.currentStreak} days`);
195
+ console.log(`Longest streak: ${user.streak.longestStreak} days`);
196
+ }
197
+
198
+ // Inventory summary
199
+ if (user.inventory) {
200
+ console.log(`Items owned: ${user.inventory.itemCount}`);
201
+ console.log(`Active effects: ${user.inventory.activeEffects.join(', ')}`);
202
+ }
128
203
  ```
129
204
 
130
- ### 10. Get Active Questionnaire
205
+ ### Leaderboards
206
+
207
+ #### Global Leaderboard with Filters
131
208
 
132
209
  ```javascript
133
- const activeQuestionnaire = await client.questionnaires.getActive();
210
+ // Using options object (recommended)
211
+ const leaderboard = await client.leaderboards.getGlobal({
212
+ timeframe: 'weekly',
213
+ page: 1,
214
+ limit: 10,
215
+ persona: 'competitor',
216
+ minLevel: 5,
217
+ maxLevel: 20,
218
+ startDate: new Date('2024-01-01'),
219
+ endDate: new Date('2024-01-31')
220
+ });
134
221
 
135
- if (activeQuestionnaire) {
136
- console.log(`Active: ${activeQuestionnaire.title}`);
222
+ // Access cache metadata
223
+ if (leaderboard.cacheMetadata) {
224
+ console.log(`Cached at: ${leaderboard.cacheMetadata.cachedAt}`);
225
+ console.log(`TTL: ${leaderboard.cacheMetadata.ttl}s`);
137
226
  }
227
+
228
+ // Rankings include percentile
229
+ leaderboard.rankings.forEach(entry => {
230
+ console.log(`#${entry.rank} ${entry.userId}: ${entry.score} pts (top ${entry.percentile}%)`);
231
+ });
138
232
  ```
139
233
 
140
- ### 11. Aha Score - Declare User Activation
234
+ #### Custom Leaderboard with Filters
141
235
 
142
- Track when users reach their "Aha Moment" with declarative scores (1-5).
236
+ ```javascript
237
+ const customLb = await client.leaderboards.getCustom('leaderboard_id', {
238
+ page: 1,
239
+ limit: 10,
240
+ persona: 'achiever',
241
+ minLevel: 10
242
+ });
243
+ ```
244
+
245
+ #### "Around Me" View
143
246
 
144
247
  ```javascript
145
- // Declare that a user has reached an activation milestone
146
- const result = await client.aha.declare('user_123', 4);
248
+ // Get entries around a specific user
249
+ const aroundMe = await client.leaderboards.getAroundUser(
250
+ 'leaderboard_id',
251
+ 'user_123',
252
+ 5 // 5 entries above and below
253
+ );
147
254
 
148
- console.log(result.message); // "Aha score declared successfully"
255
+ aroundMe.rankings.forEach(entry => {
256
+ const marker = entry.userId === 'user_123' ? '→' : ' ';
257
+ console.log(`${marker} #${entry.rank} ${entry.userId}: ${entry.score}`);
258
+ });
149
259
  ```
150
260
 
151
- ### 12. Aha Score - Get User Score
152
-
153
- Retrieve a user's Aha Score, including declarative and inferred scores.
261
+ #### Get User Rank with Percentile
154
262
 
155
263
  ```javascript
156
- const ahaScore = await client.aha.getUserScore('user_123');
264
+ const rank = await client.leaderboards.getUserRank('leaderboard_id', 'user_123');
265
+
266
+ console.log(`Rank: #${rank.rank}`);
267
+ console.log(`Score: ${rank.score}`);
268
+ console.log(`Percentile: top ${rank.percentile}%`);
269
+ ```
157
270
 
158
- console.log(`Current Score: ${ahaScore.data.current_score}`);
159
- console.log(`Status: ${ahaScore.data.status}`); // 'not_started', 'progressing', or 'activated'
160
- console.log(`Declarative Score: ${ahaScore.data.declarative_score}`);
161
- console.log(`Inferred Score: ${ahaScore.data.inferred_score}`);
271
+ ### Health Checks
162
272
 
163
- // Access history
164
- if (ahaScore.data.history.initial) {
165
- console.log(`Initial Score: ${ahaScore.data.history.initial}`);
166
- console.log(`Initial Date: ${ahaScore.data.history.initial_date}`);
273
+ ```javascript
274
+ // Full health check
275
+ const health = await client.health.check();
276
+ console.log(`Status: ${health.status}`);
277
+ console.log(`Version: ${health.version}`);
278
+
279
+ // Quick availability check
280
+ const isReady = await client.health.isReady();
281
+ if (isReady) {
282
+ console.log('API is ready');
167
283
  }
168
284
  ```
169
285
 
286
+ ### Aha Score
287
+
288
+ ```javascript
289
+ // Declare user activation milestone (1-5)
290
+ const result = await client.aha.declare('user_123', 4);
291
+ console.log(result.message);
292
+
293
+ // Get user's aha score
294
+ const score = await client.aha.getUserScore('user_123');
295
+ console.log(`Current Score: ${score.data.current_score}`);
296
+ console.log(`Status: ${score.data.status}`);
297
+ ```
298
+
170
299
  ## API Reference
171
300
 
172
301
  ### Events
173
302
 
174
- - `track(eventName, userId, properties, options)` - Track a user event
303
+ | Method | Description |
304
+ |--------|-------------|
305
+ | `track(eventName, userId, properties?, options?)` | Track a single event |
306
+ | `trackBatch(events, options?)` | Track multiple events (max 100) |
307
+ | `trackLegacy(eventName, userId, properties?, options?)` | **Deprecated** - Use `track()` |
175
308
 
176
309
  ### Users
177
310
 
178
- - `get(userId)` - Get user profile
179
- - `getBulk(userIds)` - Get multiple user profiles
180
- - `getBadges(userId)` - Get user's badges
181
- - `getRank(userId, timeframe)` - Get user's rank in global leaderboard
182
- - `submitAnswers(userId, questionnaireId, answers)` - Submit questionnaire answers
311
+ | Method | Description |
312
+ |--------|-------------|
313
+ | `create(userData)` | Create a new user |
314
+ | `update(userId, userData)` | Update user profile (partial update) |
315
+ | `createBatch(users)` | Create multiple users (max 100) |
316
+ | `get(userId, options?)` | Get user profile with optional field selection |
317
+ | `search(query, options?)` | Search users with pagination |
318
+ | `getBulk(userIds)` | Get multiple user profiles |
319
+ | `getBadges(userId)` | Get user's badges |
320
+ | `getRank(userId, timeframe?)` | Get user's global rank |
321
+ | `submitAnswers(userId, questionnaireId, answers)` | Submit questionnaire answers |
183
322
 
184
323
  ### Leaderboards
185
324
 
186
- - `getGlobal(timeframe, page, limit)` - Get global leaderboard rankings
187
- - `list(page, limit, search)` - List all available leaderboards
188
- - `getCustom(leaderboardId, page, limit, search)` - Get custom leaderboard rankings
189
- - `getUserRank(leaderboardId, userId)` - Get user's rank in a custom leaderboard
325
+ | Method | Description |
326
+ |--------|-------------|
327
+ | `getGlobal(timeframeOrOptions?, page?, limit?, options?)` | Get global leaderboard with filters |
328
+ | `list(pageOrOptions?, limit?, search?)` | List all leaderboards |
329
+ | `getCustom(leaderboardId, pageOrOptions?, limit?, search?, options?)` | Get custom leaderboard with filters |
330
+ | `getUserRank(leaderboardId, userId)` | Get user's rank in leaderboard |
331
+ | `getAroundUser(leaderboardId, userId, range?)` | Get entries around a user |
190
332
 
191
333
  ### Badges
192
334
 
193
- - `list(page, limit, activeOnly)` - List all badges
335
+ | Method | Description |
336
+ |--------|-------------|
337
+ | `list(page?, limit?, activeOnly?)` | List all badges |
194
338
 
195
339
  ### Levels
196
340
 
197
- - `list(page, limit)` - List all levels
341
+ | Method | Description |
342
+ |--------|-------------|
343
+ | `list(page?, limit?)` | List all levels |
198
344
 
199
345
  ### Questionnaires
200
346
 
201
- - `get(slug)` - Get questionnaire by slug
202
- - `getActive()` - Get the currently active questionnaire
347
+ | Method | Description |
348
+ |--------|-------------|
349
+ | `get(slug)` | Get questionnaire by slug |
350
+ | `getActive()` | Get active questionnaire |
203
351
 
204
352
  ### Aha Score
205
353
 
206
- - `declare(userId, value)` - Declare a user's Aha Moment score (value must be between 1-5)
207
- - `getUserScore(userId)` - Retrieve a user's current Aha Score and history
354
+ | Method | Description |
355
+ |--------|-------------|
356
+ | `declare(userId, value)` | Declare aha score (1-5) |
357
+ | `getUserScore(userId)` | Get user's aha score |
358
+
359
+ ### Health
360
+
361
+ | Method | Description |
362
+ |--------|-------------|
363
+ | `check()` | Get full health status |
364
+ | `isReady()` | Quick availability check |
208
365
 
209
366
  ## Error Handling
210
367
 
368
+ The SDK provides typed error classes for different error scenarios:
369
+
211
370
  ```javascript
371
+ import Rooguys, {
372
+ ValidationError,
373
+ AuthenticationError,
374
+ NotFoundError,
375
+ ConflictError,
376
+ RateLimitError,
377
+ ServerError
378
+ } from '@rooguys/js';
379
+
212
380
  try {
213
- await client.users.get('unknown_user');
381
+ await client.users.create({ userId: 'user_123', email: 'invalid-email' });
214
382
  } catch (error) {
215
- console.error('API Error:', error.message);
383
+ if (error instanceof ValidationError) {
384
+ console.error('Validation failed:', error.message);
385
+ console.error('Field errors:', error.fieldErrors);
386
+ console.error('Error code:', error.code);
387
+ } else if (error instanceof AuthenticationError) {
388
+ console.error('Invalid API key');
389
+ } else if (error instanceof NotFoundError) {
390
+ console.error('Resource not found');
391
+ } else if (error instanceof ConflictError) {
392
+ console.error('Resource already exists');
393
+ } else if (error instanceof RateLimitError) {
394
+ console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
395
+ } else if (error instanceof ServerError) {
396
+ console.error('Server error:', error.message);
397
+ }
398
+
399
+ // All errors include requestId for debugging
400
+ console.error('Request ID:', error.requestId);
216
401
  }
217
402
  ```
218
403
 
219
- ### Validation Errors
404
+ ### Error Types
220
405
 
221
- ```javascript
222
- try {
223
- // Invalid Aha Score value (must be 1-5)
224
- await client.aha.declare('user_123', 10);
225
- } catch (error) {
226
- console.error(error.message); // "Aha score value must be between 1 and 5"
227
- }
228
- ```
406
+ | Error Class | HTTP Status | Description |
407
+ |-------------|-------------|-------------|
408
+ | `ValidationError` | 400 | Invalid input data |
409
+ | `AuthenticationError` | 401 | Invalid or missing API key |
410
+ | `ForbiddenError` | 403 | Insufficient permissions |
411
+ | `NotFoundError` | 404 | Resource not found |
412
+ | `ConflictError` | 409 | Resource already exists |
413
+ | `RateLimitError` | 429 | Rate limit exceeded |
414
+ | `ServerError` | 500+ | Server-side error |
229
415
 
230
- ## Testing
416
+ ### Error Properties
231
417
 
232
- The SDK includes comprehensive test coverage with both unit tests and property-based tests.
418
+ All errors include:
419
+ - `message` - Human-readable error message
420
+ - `code` - Machine-readable error code (e.g., `INVALID_EMAIL`, `USER_NOT_FOUND`)
421
+ - `requestId` - Unique request identifier for debugging
422
+ - `statusCode` - HTTP status code
233
423
 
234
- ### Running Tests
424
+ `ValidationError` also includes:
425
+ - `fieldErrors` - Array of `{ field, message }` for field-level errors
235
426
 
236
- ```bash
237
- npm test
427
+ `RateLimitError` also includes:
428
+ - `retryAfter` - Seconds until rate limit resets
429
+
430
+ ## Rate Limiting
431
+
432
+ The SDK provides built-in rate limit handling:
433
+
434
+ ```javascript
435
+ const client = new Rooguys('YOUR_API_KEY', {
436
+ // Get notified when 80% of rate limit is consumed
437
+ onRateLimitWarning: (info) => {
438
+ console.warn(`Rate limit: ${info.remaining}/${info.limit} remaining`);
439
+ console.warn(`Resets at: ${new Date(info.reset * 1000)}`);
440
+ },
441
+
442
+ // Automatically retry rate-limited requests
443
+ autoRetry: true,
444
+ maxRetries: 3
445
+ });
238
446
  ```
239
447
 
240
- ### Test Coverage
448
+ Rate limit info is available in response metadata:
449
+ ```javascript
450
+ const response = await client._httpClient.get('/users/user_123');
451
+ console.log('Rate limit:', response.rateLimit);
452
+ // { limit: 1000, remaining: 950, reset: 1704067200 }
453
+ ```
454
+
455
+ ## Testing
241
456
 
242
457
  ```bash
243
- npm run test:coverage
458
+ npm test # Run all tests
459
+ npm run test:coverage # Run with coverage report
244
460
  ```
245
461
 
246
- The SDK maintains >90% test coverage across all modules, including:
462
+ The SDK maintains >90% test coverage with:
247
463
  - Unit tests for all API methods
248
464
  - Property-based tests using fast-check
249
- - Error handling and edge case validation
250
- - Concurrent request handling
251
-
252
- ### Property-Based Testing
253
-
254
- The SDK uses [fast-check](https://github.com/dubzzz/fast-check) for property-based testing to verify correctness across a wide range of inputs:
255
-
256
- ```javascript
257
- // Example: Verifying response parsing preservation
258
- fc.assert(
259
- fc.property(
260
- fc.jsonValue(),
261
- async (responseData) => {
262
- // Test that any valid JSON response is parsed correctly
263
- // and data structure is preserved
264
- }
265
- ),
266
- { numRuns: 100 }
267
- );
268
- ```
465
+ - Error handling validation
466
+ - Rate limit handling tests
269
467
 
270
468
  ## Requirements
271
469
 
272
- This SDK requires a browser environment with support for:
273
- - `fetch` API
274
- - `Promise`
275
- - `AbortController` (for timeouts)
470
+ - Browser with support for:
471
+ - `fetch` API
472
+ - `Promise`
473
+ - `AbortController` (for timeouts)
474
+ - Most modern browsers support these features
475
+
476
+ ## License
276
477
 
277
- Most modern browsers support these features.
478
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rooguys/js",
3
- "version": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "Official Browser SDK for Rooguys API",
5
5
  "type": "module",
6
6
  "main": "src/index.js",