@tspvivek/baasix-sdk 0.1.0-alpha.1

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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +942 -0
  3. package/dist/client-CzF9B60b.d.ts +614 -0
  4. package/dist/client-aXK_gEyr.d.cts +614 -0
  5. package/dist/index.cjs +4159 -0
  6. package/dist/index.cjs.map +1 -0
  7. package/dist/index.d.cts +1498 -0
  8. package/dist/index.d.ts +1498 -0
  9. package/dist/index.js +4135 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/modules/auth.cjs +651 -0
  12. package/dist/modules/auth.cjs.map +1 -0
  13. package/dist/modules/auth.d.cts +384 -0
  14. package/dist/modules/auth.d.ts +384 -0
  15. package/dist/modules/auth.js +649 -0
  16. package/dist/modules/auth.js.map +1 -0
  17. package/dist/modules/files.cjs +266 -0
  18. package/dist/modules/files.cjs.map +1 -0
  19. package/dist/modules/files.d.cts +187 -0
  20. package/dist/modules/files.d.ts +187 -0
  21. package/dist/modules/files.js +264 -0
  22. package/dist/modules/files.js.map +1 -0
  23. package/dist/modules/items.cjs +654 -0
  24. package/dist/modules/items.cjs.map +1 -0
  25. package/dist/modules/items.d.cts +472 -0
  26. package/dist/modules/items.d.ts +472 -0
  27. package/dist/modules/items.js +651 -0
  28. package/dist/modules/items.js.map +1 -0
  29. package/dist/modules/schemas.cjs +269 -0
  30. package/dist/modules/schemas.cjs.map +1 -0
  31. package/dist/modules/schemas.d.cts +239 -0
  32. package/dist/modules/schemas.d.ts +239 -0
  33. package/dist/modules/schemas.js +267 -0
  34. package/dist/modules/schemas.js.map +1 -0
  35. package/dist/storage/index.cjs +162 -0
  36. package/dist/storage/index.cjs.map +1 -0
  37. package/dist/storage/index.d.cts +96 -0
  38. package/dist/storage/index.d.ts +96 -0
  39. package/dist/storage/index.js +157 -0
  40. package/dist/storage/index.js.map +1 -0
  41. package/dist/types-BdjsGANq.d.cts +40 -0
  42. package/dist/types-BdjsGANq.d.ts +40 -0
  43. package/package.json +107 -0
package/README.md ADDED
@@ -0,0 +1,942 @@
1
+ # @tspvivek/baasix-sdk
2
+
3
+ Official JavaScript/TypeScript SDK for [Baasix](https://www.baasix.com) Backend-as-a-Service.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@tspvivek/baasix-sdk.svg)](https://www.npmjs.com/package/@tspvivek/baasix-sdk)
6
+ [![npm downloads](https://img.shields.io/npm/dm/@tspvivek/baasix-sdk.svg)](https://www.npmjs.com/package/@tspvivek/baasix-sdk)
7
+ [![license](https://img.shields.io/npm/l/@tspvivek/baasix-sdk.svg)](https://github.com/tspvivek/baasix-sdk/blob/main/LICENSE)
8
+
9
+ ## Features
10
+
11
+ - 🌐 **Universal** - Works in browsers, Node.js, and React Native
12
+ - 🔐 **Flexible Auth** - JWT tokens, HTTP-only cookies, OAuth (Google, Facebook, Apple, GitHub)
13
+ - 💾 **Customizable Storage** - LocalStorage, AsyncStorage, or custom adapters
14
+ - 📝 **Type-Safe** - Full TypeScript support with generics
15
+ - 🔄 **Auto Token Refresh** - Seamless token management
16
+ - 🏢 **Multi-Tenant** - Built-in tenant switching and invitation support
17
+ - ⚡ **Query Builder** - Fluent API for complex queries with 50+ filter operators
18
+ - 📡 **Realtime** - WebSocket subscriptions for live data updates
19
+ - 📁 **File Management** - Upload, download, and transform assets
20
+ - 🔀 **Workflows** - Execute and monitor workflow executions
21
+ - 👥 **User & Role Management** - Admin operations for users and roles
22
+ - 📊 **Reports** - Generate reports with aggregations
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ npm install @tspvivek/baasix-sdk
28
+ # or
29
+ yarn add @tspvivek/baasix-sdk
30
+ # or
31
+ pnpm add @tspvivek/baasix-sdk
32
+ ```
33
+
34
+ ## Quick Start
35
+
36
+ ```typescript
37
+ import { createBaasix } from '@tspvivek/baasix-sdk';
38
+
39
+ // Create client
40
+ const baasix = createBaasix({
41
+ url: 'https://your-baasix-instance.com',
42
+ });
43
+
44
+ // Login
45
+ const { user, token } = await baasix.auth.login({
46
+ email: 'user@example.com',
47
+ password: 'password123',
48
+ });
49
+
50
+ // Query items
51
+ const { data: products } = await baasix.items('products').find({
52
+ filter: { status: { eq: 'active' } },
53
+ sort: { createdAt: 'desc' },
54
+ limit: 10,
55
+ });
56
+
57
+ // Create item
58
+ const productId = await baasix.items('products').create({
59
+ name: 'New Product',
60
+ price: 29.99,
61
+ });
62
+ ```
63
+
64
+ ## Configuration
65
+
66
+ ### Basic Configuration
67
+
68
+ ```typescript
69
+ import { createBaasix } from '@tspvivek/baasix-sdk';
70
+
71
+ const baasix = createBaasix({
72
+ url: 'https://api.example.com', // Required: Your Baasix URL
73
+ authMode: 'jwt', // 'jwt' (default) or 'cookie'
74
+ timeout: 30000, // Request timeout in ms (default: 30000)
75
+ autoRefresh: true, // Auto-refresh tokens (default: true)
76
+ onAuthStateChange: (event, user) => { // Auth state callback
77
+ console.log('Auth changed:', event, user);
78
+ },
79
+ });
80
+ ```
81
+
82
+ ### React Native Setup
83
+
84
+ ```typescript
85
+ import { createBaasix, AsyncStorageAdapter } from '@tspvivek/baasix-sdk';
86
+ import AsyncStorage from '@react-native-async-storage/async-storage';
87
+
88
+ const baasix = createBaasix({
89
+ url: 'https://api.example.com',
90
+ storage: new AsyncStorageAdapter(AsyncStorage),
91
+ });
92
+ ```
93
+
94
+ ### Cookie Mode (Web with HTTP-only cookies)
95
+
96
+ ```typescript
97
+ const baasix = createBaasix({
98
+ url: 'https://api.example.com',
99
+ authMode: 'cookie',
100
+ credentials: 'include', // Required for cookies
101
+ });
102
+ ```
103
+
104
+ ### Server-Side / Service Account
105
+
106
+ ```typescript
107
+ const baasix = createBaasix({
108
+ url: 'https://api.example.com',
109
+ token: 'your-service-account-token', // Static token
110
+ });
111
+ ```
112
+
113
+ ## Authentication
114
+
115
+ ### Register
116
+
117
+ ```typescript
118
+ const { user, token } = await baasix.auth.register({
119
+ email: 'newuser@example.com',
120
+ password: 'securepassword',
121
+ firstName: 'John',
122
+ lastName: 'Doe',
123
+ });
124
+ ```
125
+
126
+ ### Login
127
+
128
+ ```typescript
129
+ const { user, token } = await baasix.auth.login({
130
+ email: 'user@example.com',
131
+ password: 'password123',
132
+ });
133
+
134
+ // With tenant (multi-tenant mode)
135
+ const result = await baasix.auth.login({
136
+ email: 'user@example.com',
137
+ password: 'password123',
138
+ tenantId: 'tenant-uuid',
139
+ });
140
+ ```
141
+
142
+ ### Get Current User
143
+
144
+ ```typescript
145
+ // From server (makes API call)
146
+ const user = await baasix.auth.getUser();
147
+
148
+ // From cache (no API call)
149
+ const cachedUser = await baasix.auth.getCachedUser();
150
+ ```
151
+
152
+ ### Logout
153
+
154
+ ```typescript
155
+ await baasix.auth.logout();
156
+ ```
157
+
158
+ ### Check Authentication
159
+
160
+ ```typescript
161
+ if (await baasix.auth.isAuthenticated()) {
162
+ // User is logged in
163
+ }
164
+ ```
165
+
166
+ ### Magic Link Login
167
+
168
+ ```typescript
169
+ // Send magic link
170
+ await baasix.auth.sendMagicLink({
171
+ email: 'user@example.com',
172
+ redirectUrl: 'https://myapp.com/auth/callback',
173
+ });
174
+
175
+ // Verify (after user clicks link)
176
+ const { user, token } = await baasix.auth.verifyMagicLink('verification-token');
177
+ ```
178
+
179
+ ### Password Reset
180
+
181
+ ```typescript
182
+ // Request reset
183
+ await baasix.auth.forgotPassword({
184
+ email: 'user@example.com',
185
+ redirectUrl: 'https://myapp.com/reset-password',
186
+ });
187
+
188
+ // Reset password
189
+ await baasix.auth.resetPassword('reset-token', 'newpassword123');
190
+ ```
191
+
192
+ ### Multi-Tenant
193
+
194
+ ```typescript
195
+ // Get available tenants
196
+ const tenants = await baasix.auth.getTenants();
197
+
198
+ // Switch tenant
199
+ const { user, token } = await baasix.auth.switchTenant('tenant-uuid');
200
+ ```
201
+
202
+ ## Items (CRUD Operations)
203
+
204
+ ### Query Items
205
+
206
+ ```typescript
207
+ const items = baasix.items('products');
208
+
209
+ // Basic find
210
+ const { data, totalCount } = await items.find();
211
+
212
+ // With parameters
213
+ const { data: activeProducts } = await items.find({
214
+ filter: { status: { eq: 'active' } },
215
+ sort: { createdAt: 'desc' },
216
+ limit: 20,
217
+ page: 1,
218
+ fields: ['id', 'name', 'price', 'category.*'],
219
+ });
220
+
221
+ // Find one by ID
222
+ const product = await items.findOne('product-uuid');
223
+
224
+ // With related data
225
+ const product = await items.findOne('product-uuid', {
226
+ fields: ['*', 'category.*', 'reviews.*'],
227
+ });
228
+ ```
229
+
230
+ ### Query Builder
231
+
232
+ ```typescript
233
+ const results = await baasix.items('posts')
234
+ .query()
235
+ .select('*', 'author.*', 'comments.*')
236
+ .filter({
237
+ AND: [
238
+ { status: { eq: 'published' } },
239
+ { createdAt: { gte: '$NOW-DAYS_30' } },
240
+ ],
241
+ })
242
+ .sort({ createdAt: 'desc' })
243
+ .limit(10)
244
+ .page(1)
245
+ .get();
246
+
247
+ // First result only
248
+ const post = await baasix.items('posts')
249
+ .query()
250
+ .filter({ slug: { eq: 'my-post' } })
251
+ .first();
252
+
253
+ // Count
254
+ const count = await baasix.items('products')
255
+ .query()
256
+ .filter({ inStock: { eq: true } })
257
+ .count();
258
+ ```
259
+
260
+ ### Create Items
261
+
262
+ ```typescript
263
+ // Single item
264
+ const id = await baasix.items('products').create({
265
+ name: 'New Product',
266
+ price: 29.99,
267
+ status: 'draft',
268
+ });
269
+
270
+ // Multiple items
271
+ const ids = await baasix.items('products').createMany([
272
+ { name: 'Product 1', price: 10 },
273
+ { name: 'Product 2', price: 20 },
274
+ ]);
275
+ ```
276
+
277
+ ### Update Items
278
+
279
+ ```typescript
280
+ // Single item
281
+ await baasix.items('products').update('product-uuid', {
282
+ price: 24.99,
283
+ status: 'published',
284
+ });
285
+
286
+ // Multiple items
287
+ await baasix.items('products').updateMany(
288
+ ['id1', 'id2', 'id3'],
289
+ { status: 'archived' }
290
+ );
291
+
292
+ // Upsert (create or update)
293
+ const id = await baasix.items('products').upsert(
294
+ { sku: { eq: 'SKU-001' } },
295
+ { name: 'Widget', price: 29.99, sku: 'SKU-001' }
296
+ );
297
+ ```
298
+
299
+ ### Delete Items
300
+
301
+ ```typescript
302
+ // Single item
303
+ await baasix.items('products').delete('product-uuid');
304
+
305
+ // Multiple items
306
+ await baasix.items('products').deleteMany(['id1', 'id2', 'id3']);
307
+
308
+ // Soft delete (if paranoid mode enabled)
309
+ await baasix.items('products').softDelete('product-uuid');
310
+
311
+ // Restore soft-deleted
312
+ await baasix.items('products').restore('product-uuid');
313
+ ```
314
+
315
+ ### Aggregation
316
+
317
+ ```typescript
318
+ const results = await baasix.items('orders').aggregate({
319
+ aggregate: {
320
+ totalRevenue: { function: 'sum', field: 'total' },
321
+ orderCount: { function: 'count', field: 'id' },
322
+ avgOrderValue: { function: 'avg', field: 'total' },
323
+ },
324
+ groupBy: ['status', 'category'],
325
+ filter: { createdAt: { gte: '$NOW-DAYS_30' } },
326
+ });
327
+ ```
328
+
329
+ ## Filter Operators
330
+
331
+ Baasix supports 50+ filter operators:
332
+
333
+ ```typescript
334
+ // Comparison
335
+ { field: { eq: value } } // Equal
336
+ { field: { ne: value } } // Not equal
337
+ { field: { gt: value } } // Greater than
338
+ { field: { gte: value } } // Greater than or equal
339
+ { field: { lt: value } } // Less than
340
+ { field: { lte: value } } // Less than or equal
341
+
342
+ // Collection
343
+ { field: { in: [1, 2, 3] } } // In list
344
+ { field: { notIn: [1, 2, 3] } } // Not in list
345
+
346
+ // String
347
+ { field: { like: 'pattern' } } // LIKE (case-sensitive)
348
+ { field: { iLike: 'pattern' } } // ILIKE (case-insensitive)
349
+ { field: { startsWith: 'prefix' } } // Starts with
350
+ { field: { endsWith: 'suffix' } } // Ends with
351
+ { field: { contains: 'substring' } } // Contains
352
+
353
+ // Range
354
+ { field: { between: [10, 100] } } // Between
355
+
356
+ // Null
357
+ { field: { isNull: true } } // Is null
358
+ { field: { isNotNull: true } } // Is not null
359
+
360
+ // Array (PostgreSQL)
361
+ { tags: { arraycontains: ['js', 'api'] } }
362
+
363
+ // JSONB
364
+ { metadata: { jsonbHasKey: 'discount' } }
365
+ { metadata: { jsonbKeyEquals: { key: 'status', value: 'active' } } }
366
+
367
+ // Logical
368
+ { AND: [{ status: { eq: 'active' } }, { price: { gt: 0 } }] }
369
+ { OR: [{ status: { eq: 'featured' } }, { views: { gt: 1000 } }] }
370
+
371
+ // Relation filtering
372
+ { 'author.name': { like: 'John' } }
373
+
374
+ // Dynamic variables
375
+ { author_Id: { eq: '$CURRENT_USER' } }
376
+ { createdAt: { gte: '$NOW-DAYS_30' } }
377
+ ```
378
+
379
+ ## Files
380
+
381
+ ### Upload Files
382
+
383
+ ```typescript
384
+ // Browser
385
+ const fileMetadata = await baasix.files.upload(fileInput.files[0], {
386
+ title: 'Product Image',
387
+ folder: 'products',
388
+ isPublic: true,
389
+ onProgress: (progress) => console.log(`${progress}% uploaded`),
390
+ });
391
+
392
+ // React Native with expo-image-picker
393
+ const metadata = await baasix.files.upload({
394
+ uri: result.uri,
395
+ name: 'photo.jpg',
396
+ type: 'image/jpeg',
397
+ });
398
+ ```
399
+
400
+ ### Get Asset URLs
401
+
402
+ ```typescript
403
+ // Original file
404
+ const url = baasix.files.getAssetUrl('file-uuid');
405
+
406
+ // With transformations
407
+ const thumbnailUrl = baasix.files.getAssetUrl('file-uuid', {
408
+ width: 200,
409
+ height: 200,
410
+ fit: 'cover',
411
+ quality: 80,
412
+ format: 'webp',
413
+ });
414
+ ```
415
+
416
+ ### File Operations
417
+
418
+ ```typescript
419
+ // List files
420
+ const { data: files } = await baasix.files.find({
421
+ filter: { mimeType: { startsWith: 'image/' } },
422
+ });
423
+
424
+ // Get file info
425
+ const file = await baasix.files.findOne('file-uuid');
426
+
427
+ // Download file
428
+ const blob = await baasix.files.download('file-uuid');
429
+
430
+ // Delete file
431
+ await baasix.files.delete('file-uuid');
432
+ ```
433
+
434
+ ## Schemas
435
+
436
+ ### Create Collection
437
+
438
+ ```typescript
439
+ await baasix.schemas.create({
440
+ collectionName: 'products',
441
+ schema: {
442
+ name: 'Product',
443
+ timestamps: true,
444
+ paranoid: true, // Soft deletes
445
+ fields: {
446
+ id: {
447
+ type: 'UUID',
448
+ primaryKey: true,
449
+ defaultValue: { type: 'UUIDV4' },
450
+ },
451
+ name: {
452
+ type: 'String',
453
+ allowNull: false,
454
+ values: { length: 255 },
455
+ },
456
+ price: {
457
+ type: 'Decimal',
458
+ values: { precision: 10, scale: 2 },
459
+ defaultValue: 0,
460
+ },
461
+ tags: {
462
+ type: 'Array',
463
+ values: { type: 'String' },
464
+ defaultValue: [],
465
+ },
466
+ metadata: {
467
+ type: 'JSONB',
468
+ defaultValue: {},
469
+ },
470
+ },
471
+ },
472
+ });
473
+ ```
474
+
475
+ ### Relationships
476
+
477
+ ```typescript
478
+ // Many-to-One (BelongsTo)
479
+ await baasix.schemas.createRelationship('products', {
480
+ type: 'M2O',
481
+ target: 'categories',
482
+ name: 'category',
483
+ alias: 'products',
484
+ });
485
+
486
+ // Many-to-Many
487
+ await baasix.schemas.createRelationship('products', {
488
+ type: 'M2M',
489
+ target: 'tags',
490
+ name: 'tags',
491
+ alias: 'products',
492
+ });
493
+ ```
494
+
495
+ ### Indexes
496
+
497
+ ```typescript
498
+ await baasix.schemas.createIndex('products', {
499
+ name: 'idx_products_sku',
500
+ fields: ['sku'],
501
+ unique: true,
502
+ });
503
+ ```
504
+
505
+ ## Reports & Analytics
506
+
507
+ ```typescript
508
+ // Generate report
509
+ const report = await baasix.reports.generate('orders', {
510
+ aggregate: {
511
+ revenue: { function: 'sum', field: 'total' },
512
+ orders: { function: 'count', field: 'id' },
513
+ },
514
+ groupBy: 'category',
515
+ filter: { status: { eq: 'completed' } },
516
+ dateRange: {
517
+ start: '2025-01-01',
518
+ end: '2025-12-31',
519
+ },
520
+ });
521
+
522
+ // Quick count
523
+ const activeUsers = await baasix.reports.count('users', {
524
+ status: { eq: 'active' },
525
+ });
526
+ ```
527
+
528
+ ## Workflows
529
+
530
+ ```typescript
531
+ // Execute workflow
532
+ const result = await baasix.workflows.execute('workflow-uuid', {
533
+ orderId: 'order-123',
534
+ });
535
+
536
+ // Get execution history
537
+ const { data: executions } = await baasix.workflows.getExecutions('workflow-uuid');
538
+
539
+ // Subscribe to execution updates (requires realtime)
540
+ const unsubscribe = baasix.realtime.subscribeToExecution(executionId, (update) => {
541
+ console.log('Execution progress:', update.progress, '%');
542
+ if (update.status === 'complete') {
543
+ console.log('Workflow finished!', update.result);
544
+ }
545
+ });
546
+ ```
547
+
548
+ ## Realtime Subscriptions
549
+
550
+ The SDK supports real-time data updates via WebSocket connections.
551
+
552
+ ### Setup
553
+
554
+ ```typescript
555
+ // Install socket.io-client separately
556
+ npm install socket.io-client
557
+
558
+ // Initialize realtime
559
+ import { io } from 'socket.io-client';
560
+
561
+ // Set the socket client
562
+ baasix.realtime.setSocketClient(io);
563
+
564
+ // Connect to realtime server
565
+ await baasix.realtime.connect();
566
+ ```
567
+
568
+ ### Subscribe to Collections
569
+
570
+ ```typescript
571
+ // Subscribe to all changes on a collection
572
+ const unsubscribe = baasix.realtime.subscribe('products', (payload) => {
573
+ console.log(`Product ${payload.action}:`, payload.data);
574
+ // payload.action: 'create' | 'update' | 'delete'
575
+ // payload.data: the created/updated/deleted item
576
+ // payload.timestamp: ISO timestamp
577
+ });
578
+
579
+ // Subscribe to specific events only
580
+ const unsubscribe = baasix.realtime.on('orders', 'create', (data) => {
581
+ console.log('New order received:', data);
582
+ });
583
+
584
+ // Unsubscribe when done
585
+ unsubscribe();
586
+ ```
587
+
588
+ ### Supabase-style Channel API
589
+
590
+ ```typescript
591
+ const channel = baasix.realtime
592
+ .channel('products')
593
+ .on('INSERT', (payload) => console.log('New:', payload))
594
+ .on('UPDATE', (payload) => console.log('Updated:', payload))
595
+ .on('DELETE', (payload) => console.log('Deleted:', payload))
596
+ .subscribe();
597
+
598
+ // Later
599
+ channel.unsubscribe();
600
+ ```
601
+
602
+ ### Connection Management
603
+
604
+ ```typescript
605
+ // Check connection status
606
+ if (baasix.realtime.isConnected) {
607
+ console.log('Connected to realtime server');
608
+ }
609
+
610
+ // Listen for connection changes
611
+ baasix.realtime.onConnectionChange((connected) => {
612
+ console.log('Realtime:', connected ? 'online' : 'offline');
613
+ });
614
+
615
+ // Disconnect
616
+ baasix.realtime.disconnect();
617
+ ```
618
+
619
+ ## OAuth / Social Login
620
+
621
+ ```typescript
622
+ // Redirect to OAuth provider
623
+ const url = baasix.auth.getOAuthUrl({
624
+ provider: 'google', // 'google' | 'facebook' | 'apple' | 'github'
625
+ redirectUrl: 'https://myapp.com/auth/callback',
626
+ });
627
+ window.location.href = url;
628
+
629
+ // In your callback page
630
+ const params = new URLSearchParams(window.location.search);
631
+ const token = params.get('token');
632
+
633
+ if (token) {
634
+ const { user } = await baasix.auth.handleOAuthCallback(token);
635
+ console.log('Logged in as:', user.email);
636
+ }
637
+ ```
638
+
639
+ ## Invitation System (Multi-tenant)
640
+
641
+ ```typescript
642
+ // Send invitation
643
+ await baasix.auth.sendInvite({
644
+ email: 'newuser@example.com',
645
+ roleId: 'editor-role-uuid',
646
+ tenantId: 'tenant-uuid',
647
+ redirectUrl: 'https://myapp.com/accept-invite',
648
+ });
649
+
650
+ // Verify invitation token (in callback page)
651
+ const result = await baasix.auth.verifyInvite(token);
652
+ if (result.valid) {
653
+ // Show registration form with pre-filled email
654
+ console.log('Invite for:', result.email);
655
+ }
656
+
657
+ // Register with invitation
658
+ const { user } = await baasix.auth.registerWithInvite({
659
+ email: 'newuser@example.com',
660
+ password: 'password123',
661
+ firstName: 'John',
662
+ lastName: 'Doe',
663
+ inviteToken: token,
664
+ });
665
+ ```
666
+
667
+ ## Users Management (Admin)
668
+
669
+ ```typescript
670
+ // List users
671
+ const { data: users } = await baasix.users.find({
672
+ filter: { status: { eq: 'active' } },
673
+ limit: 20,
674
+ });
675
+
676
+ // Create user
677
+ const userId = await baasix.users.create({
678
+ email: 'user@example.com',
679
+ password: 'password123',
680
+ firstName: 'John',
681
+ role_Id: 'role-uuid',
682
+ });
683
+
684
+ // Update user
685
+ await baasix.users.update(userId, { firstName: 'Jane' });
686
+
687
+ // Admin password change
688
+ await baasix.users.changePassword(userId, 'newPassword123');
689
+
690
+ // Suspend/Activate user
691
+ await baasix.users.suspend(userId);
692
+ await baasix.users.activate(userId);
693
+ ```
694
+
695
+ ## Roles Management
696
+
697
+ ```typescript
698
+ // List roles
699
+ const { data: roles } = await baasix.roles.find();
700
+
701
+ // Find by name
702
+ const adminRole = await baasix.roles.findByName('Administrator');
703
+
704
+ // Create role
705
+ const roleId = await baasix.roles.create({
706
+ name: 'Editor',
707
+ description: 'Content editors',
708
+ appAccess: true,
709
+ });
710
+
711
+ // Update role
712
+ await baasix.roles.update(roleId, { description: 'Updated description' });
713
+ ```
714
+
715
+ ## CSV/JSON Import
716
+
717
+ ```typescript
718
+ // Import from CSV file
719
+ const result = await baasix.items('products').importCSV(csvFile, {
720
+ delimiter: ',',
721
+ skipFirstRow: true,
722
+ });
723
+ console.log(`Created: ${result.created}, Errors: ${result.errors.length}`);
724
+
725
+ // Import from JSON file
726
+ const result = await baasix.items('products').importJSON(jsonFile);
727
+
728
+ // Import from data array
729
+ const result = await baasix.items('products').importData([
730
+ { name: 'Product 1', price: 29.99 },
731
+ { name: 'Product 2', price: 39.99 },
732
+ ]);
733
+ ```
734
+
735
+ ## Migrations (Admin)
736
+
737
+ ```typescript
738
+ // Check migration status
739
+ const status = await baasix.migrations.status();
740
+ console.log(`Pending: ${status.pendingCount}`);
741
+
742
+ // Run pending migrations
743
+ if (status.hasPending) {
744
+ const result = await baasix.migrations.run();
745
+ console.log(`Ran ${result.migrationsRun.length} migrations`);
746
+ }
747
+
748
+ // Rollback last batch
749
+ const rollback = await baasix.migrations.rollbackLast();
750
+ ```
751
+
752
+ ## Notifications
753
+
754
+ ```typescript
755
+ // Get notifications
756
+ const { data } = await baasix.notifications.find({
757
+ limit: 20,
758
+ seen: false,
759
+ });
760
+
761
+ // Mark as seen
762
+ await baasix.notifications.markAsSeen('notification-uuid');
763
+ await baasix.notifications.markAllSeen();
764
+
765
+ // Get unread count
766
+ const count = await baasix.notifications.getUnreadCount();
767
+ ```
768
+
769
+ ## Custom Storage Adapter
770
+
771
+ Create a custom storage adapter for any environment:
772
+
773
+ ```typescript
774
+ import { StorageAdapter } from '@tspvivek/baasix-sdk';
775
+
776
+ class MyCustomStorage implements StorageAdapter {
777
+ async get(key: string): Promise<string | null> {
778
+ // Your implementation
779
+ }
780
+
781
+ async set(key: string, value: string): Promise<void> {
782
+ // Your implementation
783
+ }
784
+
785
+ async remove(key: string): Promise<void> {
786
+ // Your implementation
787
+ }
788
+
789
+ async clear(): Promise<void> {
790
+ // Your implementation
791
+ }
792
+ }
793
+
794
+ const baasix = createBaasix({
795
+ url: 'https://api.example.com',
796
+ storage: new MyCustomStorage(),
797
+ });
798
+ ```
799
+
800
+ ## Error Handling
801
+
802
+ ```typescript
803
+ import { BaasixError } from '@tspvivek/baasix-sdk';
804
+
805
+ try {
806
+ await baasix.items('products').create({ name: 'Product' });
807
+ } catch (error) {
808
+ if (error instanceof BaasixError) {
809
+ console.error('Status:', error.status);
810
+ console.error('Code:', error.code);
811
+ console.error('Message:', error.message);
812
+ console.error('Details:', error.details);
813
+
814
+ if (error.status === 401) {
815
+ // Handle unauthorized
816
+ }
817
+ if (error.status === 403) {
818
+ // Handle forbidden
819
+ }
820
+ if (error.isRetryable) {
821
+ // Can retry request
822
+ }
823
+ }
824
+ }
825
+ ```
826
+
827
+ ## TypeScript Support
828
+
829
+ Use generics for type-safe operations:
830
+
831
+ ```typescript
832
+ interface Product {
833
+ id: string;
834
+ name: string;
835
+ price: number;
836
+ category_Id: string;
837
+ createdAt: string;
838
+ }
839
+
840
+ // Typed items module
841
+ const products = baasix.items<Product>('products');
842
+
843
+ // Type inference
844
+ const { data } = await products.find();
845
+ // data is Product[]
846
+
847
+ const product = await products.findOne('uuid');
848
+ // product is Product
849
+
850
+ await products.create({
851
+ name: 'Widget',
852
+ price: 29.99,
853
+ category_Id: 'cat-uuid',
854
+ }); // Type-checked
855
+ ```
856
+
857
+ ## React Example
858
+
859
+ ```tsx
860
+ import { createBaasix } from '@tspvivek/baasix-sdk';
861
+ import { useEffect, useState } from 'react';
862
+
863
+ const baasix = createBaasix({
864
+ url: process.env.REACT_APP_BAASIX_URL!,
865
+ onAuthStateChange: (event, user) => {
866
+ console.log('Auth:', event, user);
867
+ },
868
+ });
869
+
870
+ function App() {
871
+ const [user, setUser] = useState(null);
872
+ const [products, setProducts] = useState([]);
873
+
874
+ useEffect(() => {
875
+ // Initialize auth on mount
876
+ baasix.auth.initialize().then((state) => {
877
+ setUser(state.user);
878
+ });
879
+ }, []);
880
+
881
+ useEffect(() => {
882
+ // Fetch products
883
+ baasix.items('products')
884
+ .find({ filter: { status: { eq: 'active' } } })
885
+ .then(({ data }) => setProducts(data));
886
+ }, []);
887
+
888
+ const handleLogin = async (email, password) => {
889
+ const { user } = await baasix.auth.login({ email, password });
890
+ setUser(user);
891
+ };
892
+
893
+ const handleLogout = async () => {
894
+ await baasix.auth.logout();
895
+ setUser(null);
896
+ };
897
+
898
+ return (
899
+ <div>
900
+ {user ? (
901
+ <>
902
+ <p>Welcome, {user.email}</p>
903
+ <button onClick={handleLogout}>Logout</button>
904
+ </>
905
+ ) : (
906
+ <LoginForm onSubmit={handleLogin} />
907
+ )}
908
+ <ProductList products={products} />
909
+ </div>
910
+ );
911
+ }
912
+ ```
913
+
914
+ ## API Reference
915
+
916
+ ### `createBaasix(config)`
917
+
918
+ Creates a new Baasix SDK instance.
919
+
920
+ | Option | Type | Default | Description |
921
+ |--------|------|---------|-------------|
922
+ | `url` | `string` | Required | Your Baasix server URL |
923
+ | `authMode` | `'jwt' \| 'cookie'` | `'jwt'` | Authentication mode |
924
+ | `storage` | `StorageAdapter` | Auto-detected | Token storage adapter |
925
+ | `token` | `string` | - | Static auth token |
926
+ | `timeout` | `number` | `30000` | Request timeout (ms) |
927
+ | `autoRefresh` | `boolean` | `true` | Auto-refresh tokens |
928
+ | `headers` | `object` | `{}` | Custom headers |
929
+ | `tenantId` | `string` | - | Multi-tenant ID |
930
+ | `credentials` | `RequestCredentials` | Based on authMode | Fetch credentials |
931
+ | `onAuthStateChange` | `function` | - | Auth state callback |
932
+ | `onError` | `function` | - | Global error handler |
933
+
934
+ ### Storage Adapters
935
+
936
+ - `LocalStorageAdapter` - Browser localStorage (default for web)
937
+ - `MemoryStorageAdapter` - In-memory (default for SSR/Node.js)
938
+ - `AsyncStorageAdapter` - React Native AsyncStorage
939
+
940
+ ## License
941
+
942
+ MIT © [Vivek Palanisamy](https://www.baasix.com)