@taruvi/sdk 1.1.6 → 1.1.8

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 CHANGED
@@ -1,703 +1,1328 @@
1
- # Taruvi SDK
1
+ # Taruvi SDK - AI Implementation Guide
2
2
 
3
- > A TypeScript SDK for the Taruvi Platform - Backend-as-a-Service for modern applications
3
+ > Quick reference for implementing Taruvi SDK features with copy-paste examples from production code
4
4
 
5
- [![Version](https://img.shields.io/badge/version-1.1.0-blue.svg)]() [![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue.svg)]() [![License](https://img.shields.io/badge/license-MIT-green.svg)]()
5
+ ## Installation
6
6
 
7
- ## Overview
7
+ ```bash
8
+ npm install @taruvi/sdk
9
+ ```
8
10
 
9
- Taruvi SDK is a type-safe client library that enables JavaScript/TypeScript applications to interact with the Taruvi Backend-as-a-Service platform. It provides a clean, intuitive API for authentication, user management, data storage, and serverless functions.
11
+ ## What's New
10
12
 
11
- ### Key Features
13
+ Recent updates to the SDK:
12
14
 
13
- - **Modern Architecture** - Dependency injection pattern, no singletons
14
- - **Type-Safe** - Full TypeScript support with strict typing
15
- - **Lazy Loading** - Only bundle the services you use
16
- - **Tree-Shakeable** - Optimized for minimal bundle size
17
- - **Testable** - Easy to mock and test with dependency injection
18
- - **Flexible** - Support for multiple instances and configurations
19
- - **Multi-Tenant** - Manage multiple apps under a single site
15
+ - **Analytics Service**: New service for executing analytics queries with `execute()` method. Pass query name and parameters to run predefined analytics.
16
+ - **Policy Service**: New service for checking resource-level permissions with `checkResource()` method. Supports batch resource checking with entity types, tables, and attributes.
17
+ - **App Service**: New service to retrieve app roles with `roles()` method.
18
+ - **User Types**: Added `UserCreateRequest`, `UserResponse`, and `UserDataResponse` types for user management.
19
+ - **Auth Service**: Web UI Flow with `login()`, `signup()`, `logout()` methods that redirect to backend pages. Token refresh with rotation support, `getCurrentUser()` for JWT decoding.
20
+ - **Database Service**: Added `create()` method for creating records. Added `populate()` method for eager loading related records. Comprehensive filter support with Django-style operators (`__gte`, `__lte`, `__icontains`, etc.).
21
+ - **Storage Service**: Added `download()` method. Enhanced filter support with size, date, MIME type, visibility filters. `delete()` now accepts array of paths for bulk deletion.
22
+ - **Client**: Automatic token extraction from URL hash after OAuth callback - no manual token handling needed.
23
+ - **Types**: Comprehensive `StorageFilters` and `DatabaseFilters` interfaces with full operator support.
20
24
 
21
- ---
25
+ ## Core Setup
22
26
 
23
- ## Installation
27
+ ### 1. Initialize Client
24
28
 
25
- ```bash
26
- npm install @taruvi/sdk
27
- # or
28
- yarn add @taruvi/sdk
29
- # or
30
- pnpm add @taruvi/sdk
31
- ```
29
+ ```typescript
30
+ import { Client } from '@taruvi/sdk'
32
31
 
33
- ---
32
+ const taruviClient = new Client({
33
+ apiKey: "your-site-api-key",
34
+ appSlug: "your-app-slug",
35
+ baseUrl: "https://taruvi-site.taruvi.cloud"
36
+ })
37
+ ```
34
38
 
35
- ## Quick Start
39
+ ### 2. Pass to Components (React)
36
40
 
37
41
  ```typescript
38
- import { Client, Auth, User } from '@taruvi/sdk'
42
+ // App.tsx
43
+ <Route path="/page" element={<MyPage taruviClient={taruviClient} />} />
39
44
 
40
- // 1. Create the main client
41
- const client = new Client({
42
- apiKey: 'your-site-api-key',
43
- appSlug: 'my-app',
44
- baseUrl: 'https://test-api.taruvi.cloud'
45
- })
45
+ // MyPage.tsx
46
+ interface MyPageProps {
47
+ taruviClient: Client;
48
+ }
46
49
 
47
- // 2. Initialize only the services you need
48
- const auth = new Auth(client)
49
- const user = new User(client)
50
+ export default function MyPage({ taruviClient }: MyPageProps) {
51
+ // Use SDK here
52
+ }
53
+ ```
50
54
 
51
- // 3. Use the services
52
- await auth.authenticateUser()
53
- const userData = await user.getUserData()
54
- console.log(userData.username)
55
+ ### 3. Automatic Token Handling
56
+
57
+ The Client automatically extracts authentication tokens from URL hash after OAuth callback:
58
+
59
+ ```typescript
60
+ // After login redirect, URL contains:
61
+ // #session_token=xxx&access_token=yyy&refresh_token=zzz&expires_in=172800&token_type=Bearer
62
+
63
+ // Client automatically:
64
+ // 1. Extracts tokens from URL hash
65
+ // 2. Stores them in TokenClient
66
+ // 3. Clears the hash from URL
67
+
68
+ const taruviClient = new Client({ apiKey, appSlug, baseUrl })
69
+ // Tokens are now available automatically if present in URL hash
55
70
  ```
56
71
 
57
72
  ---
58
73
 
59
- ## Core Concepts
74
+ ## Auth Service
60
75
 
61
- ### Dependency Injection Pattern
62
-
63
- Taruvi SDK uses dependency injection instead of singletons, allowing multiple client instances and better testability.
76
+ ### Check Authentication
64
77
 
65
78
  ```typescript
66
- // Multiple environments
67
- const prodClient = new Client({ apiKey: '...', appSlug: 'prod', baseUrl: '...' })
68
- const devClient = new Client({ apiKey: '...', appSlug: 'dev', baseUrl: '...' })
79
+ import { Auth } from '@taruvi/sdk'
69
80
 
70
- // Services use the client they're given
71
- const prodUser = new User(prodClient)
72
- const devUser = new User(devClient)
81
+ const auth = new Auth(taruviClient)
82
+ const isAuthenticated = auth.isUserAuthenticated() // Returns boolean (synchronous)
73
83
  ```
74
84
 
75
- ### Lazy Service Instantiation
76
-
77
- Services are manually instantiated, allowing tree-shaking to eliminate unused code.
85
+ ### Login Flow (Web UI Flow with Redirect)
78
86
 
79
87
  ```typescript
80
- // Only import what you need
81
- import { Client, User } from '@taruvi/sdk' // ✅ Auth not bundled
88
+ import { useEffect } from "react"
89
+ import { Auth } from '@taruvi/sdk'
90
+
91
+ export default function Login({ taruviClient }) {
92
+ const auth = new Auth(taruviClient)
93
+
94
+ useEffect(() => {
95
+ const isAuthenticated = auth.isUserAuthenticated()
96
+
97
+ if (isAuthenticated) {
98
+ window.location.href = "/dashboard"
99
+ } else {
100
+ // Redirects to backend login page, then returns with tokens in URL hash
101
+ auth.login() // Optional: pass callback URL
102
+ }
103
+ }, [])
82
104
 
83
- const client = new Client({ /* config */ })
84
- const user = new User(client) // Only User service loaded
105
+ return <div>Checking authentication...</div>
106
+ }
85
107
  ```
86
108
 
87
- ### Multi-Tenancy Support
109
+ ### Signup Flow
110
+
111
+ ```typescript
112
+ import { Auth } from '@taruvi/sdk'
113
+
114
+ const auth = new Auth(taruviClient)
88
115
 
89
- Single site can manage multiple apps with isolated data using `appSlug`.
116
+ // Redirect to signup page (Web UI Flow)
117
+ auth.signup() // Optional: pass callback URL
118
+ auth.signup("/dashboard") // Redirect to dashboard after signup
119
+ ```
120
+
121
+ ### Logout
90
122
 
91
123
  ```typescript
92
- const customerApp = new Client({
93
- apiKey: 'site_abc123', // Same site
94
- appSlug: 'customer-portal', // Customer data
95
- baseUrl: 'https://test-api.taruvi.cloud'
96
- })
124
+ import { Auth } from '@taruvi/sdk'
97
125
 
98
- const adminApp = new Client({
99
- apiKey: 'site_abc123', // Same site
100
- appSlug: 'admin-dashboard', // Admin data (isolated)
101
- baseUrl: 'https://test-api.taruvi.cloud'
102
- })
126
+ const auth = new Auth(taruviClient)
127
+
128
+ // Clear tokens and redirect to logout page
129
+ await auth.logout() // Optional: pass callback URL
130
+ await auth.logout("/") // Redirect to home after logout
103
131
  ```
104
132
 
105
- ---
133
+ ### Get Current User
106
134
 
107
- ## Services
135
+ ```typescript
136
+ import { Auth } from '@taruvi/sdk'
108
137
 
109
- ### Auth Service
138
+ const auth = new Auth(taruviClient)
110
139
 
111
- User authentication and session management.
140
+ // Get user info from decoded JWT access token
141
+ const user = auth.getCurrentUser()
142
+ console.log(user?.user_id)
143
+ console.log(user?.username)
144
+ console.log(user?.email)
145
+ ```
112
146
 
113
- **Status**: 🚧 60% Complete
147
+ ### Token Management
114
148
 
115
149
  ```typescript
116
- import { Client, Auth } from '@taruvi/sdk'
150
+ import { Auth } from '@taruvi/sdk'
117
151
 
118
- const client = new Client({ /* config */ })
119
- const auth = new Auth(client)
152
+ const auth = new Auth(taruviClient)
120
153
 
121
- // Authenticate user
122
- await auth.authenticateUser()
154
+ // Get tokens
155
+ const accessToken = auth.getAccessToken()
156
+ const refreshToken = auth.getRefreshToken()
123
157
 
124
- // Check authentication status
125
- const isAuth = await auth.isUserAuthenticated() // true/false
126
- ```
158
+ // Check if token is expired
159
+ const isExpired = auth.isTokenExpired()
127
160
 
128
- #### Available Methods
129
- - `authenticateUser()` - Login with email/password
130
- - ✅ `isUserAuthenticated()` - Check if user has valid session
131
- - 📋 `signInWithSSO()` - SSO authentication (planned)
132
- - 📋 `refreshSession()` - Refresh expired token (planned)
133
- - 📋 `signOut()` - End user session (planned)
161
+ // Refresh access token (returns new access AND refresh tokens due to rotation)
162
+ const newTokens = await auth.refreshAccessToken()
163
+ if (newTokens) {
164
+ console.log(newTokens.access)
165
+ console.log(newTokens.refresh)
166
+ console.log(newTokens.expires_in)
167
+ }
168
+ ```
134
169
 
135
170
  ---
136
171
 
137
- ### User Service
138
-
139
- User profile and management operations.
172
+ ## User Service
140
173
 
141
- **Status**: 80% Complete (CRUD functional)
174
+ ### Get Current User
142
175
 
143
176
  ```typescript
144
- import { Client, User } from '@taruvi/sdk'
145
-
146
- const client = new Client({ /* config */ })
147
- const user = new User(client)
177
+ import { User } from '@taruvi/sdk'
148
178
 
149
- // Get current user
179
+ const user = new User(taruviClient)
150
180
  const userData = await user.getUserData()
151
181
 
152
- // Create new user
182
+ console.log(userData.data.username)
183
+ console.log(userData.data.email)
184
+ console.log(userData.data.full_name)
185
+ ```
186
+
187
+ ### Create User (Registration)
188
+
189
+ ```typescript
190
+ import { User } from '@taruvi/sdk'
191
+
192
+ const user = new User(taruviClient)
193
+
153
194
  const newUser = await user.createUser({
154
- username: 'john_doe',
155
- email: 'john@example.com',
156
- password: 'secure123'
195
+ username: "john_doe",
196
+ email: "john@example.com",
197
+ password: "secure123",
198
+ confirm_password: "secure123",
199
+ first_name: "John",
200
+ last_name: "Doe",
201
+ is_active: true,
202
+ is_staff: false,
203
+ attributes: ""
157
204
  })
205
+ ```
158
206
 
159
- // Update user
160
- await user.updateUser('john_doe', {
161
- email: 'newemail@example.com'
162
- })
207
+ ### Update User
208
+
209
+ ```typescript
210
+ const user = new User(taruviClient)
163
211
 
164
- // Delete user
165
- await user.deleteUser('john_doe')
212
+ await user.updateUser("john_doe", {
213
+ email: "newemail@example.com",
214
+ first_name: "Johnny"
215
+ })
166
216
  ```
167
217
 
168
- #### Available Methods
169
- - ✅ `getUserData()` - Fetch current user details
170
- - ✅ `createUser(data)` - Create new user account
171
- - ✅ `updateUser(username, data)` - Update user information
172
- - ✅ `deleteUser(username)` - Delete user account
218
+ ### Delete User
173
219
 
174
- ---
220
+ ```typescript
221
+ const user = new User(taruviClient)
222
+ await user.deleteUser("john_doe")
223
+ ```
175
224
 
176
- ### Storage Service
225
+ ### List Users
177
226
 
178
- Query builder for app-specific data tables.
227
+ ```typescript
228
+ const user = new User(taruviClient)
229
+
230
+ const users = await user.list({
231
+ search: "john",
232
+ is_active: true,
233
+ is_staff: false,
234
+ is_superuser: false,
235
+ is_deleted: false,
236
+ ordering: "-date_joined",
237
+ page: 1,
238
+ page_size: 20
239
+ })
240
+ ```
179
241
 
180
- **Status**: 🚧 70% Complete (Query builder working)
242
+ ### Get User Apps
181
243
 
182
244
  ```typescript
183
- import { Client, Storage } from '@taruvi/sdk'
245
+ const user = new User(taruviClient)
246
+ const apps = await user.getUserApps("john_doe")
184
247
 
185
- const client = new Client({ /* config */ })
186
- const storage = new Storage(client, {})
248
+ // Returns array of apps the user has access to
249
+ apps.forEach(app => {
250
+ console.log(app.name, app.slug, app.url)
251
+ })
252
+ ```
187
253
 
188
- // Get all records from a table
189
- const allPosts = await storage
190
- .from('posts')
191
- .execute()
254
+ ### Complete Registration Form Example
192
255
 
193
- // Get specific record
194
- const post = await storage
195
- .from('posts')
196
- .get('post_123')
197
- .execute()
198
- ```
256
+ ```typescript
257
+ import { useState } from "react"
258
+ import { User } from "@taruvi/sdk"
259
+ import { useNavigate } from "react-router"
260
+
261
+ export default function Register({ taruviClient }) {
262
+ const navigate = useNavigate()
263
+ const [formData, setFormData] = useState({
264
+ username: "",
265
+ email: "",
266
+ password: "",
267
+ confirm_password: "",
268
+ first_name: "",
269
+ last_name: "",
270
+ is_active: true,
271
+ is_staff: false
272
+ })
273
+ const [error, setError] = useState("")
274
+ const [loading, setLoading] = useState(false)
275
+
276
+ const handleSubmit = async (e) => {
277
+ e.preventDefault()
278
+
279
+ if (formData.password !== formData.confirm_password) {
280
+ setError("Passwords do not match")
281
+ return
282
+ }
283
+
284
+ setLoading(true)
285
+ try {
286
+ const userClient = new User(taruviClient)
287
+ await userClient.createUser(formData)
288
+ navigate("/login")
289
+ } catch (err) {
290
+ setError(err.message || "Failed to create user")
291
+ } finally {
292
+ setLoading(false)
293
+ }
294
+ }
199
295
 
200
- #### Available Methods
201
- - ✅ `from(tableName)` - Select table (chainable)
202
- - ✅ `get(recordId)` - Select specific record (chainable)
203
- - ✅ `execute()` - Execute the built query
204
- - 📋 `upload()` - File upload (planned)
205
- - 📋 `download()` - File download (planned)
206
- - 📋 `delete()` - Delete files (planned)
296
+ return (
297
+ <form onSubmit={handleSubmit}>
298
+ <input
299
+ name="username"
300
+ value={formData.username}
301
+ onChange={(e) => setFormData({...formData, username: e.target.value})}
302
+ required
303
+ />
304
+ {/* Add other fields */}
305
+ <button type="submit" disabled={loading}>
306
+ {loading ? "Creating..." : "Register"}
307
+ </button>
308
+ {error && <div>{error}</div>}
309
+ </form>
310
+ )
311
+ }
312
+ ```
207
313
 
208
314
  ---
209
315
 
210
- ### Settings Service
316
+ ## Database Service (CRUD Operations)
211
317
 
212
- Site configuration and settings.
318
+ ### Fetch All Records
213
319
 
214
- **Status**: ✅ 70% Complete
320
+ ```typescript
321
+ import { Database } from '@taruvi/sdk'
322
+
323
+ const db = new Database(taruviClient)
324
+ const response = await db.from("accounts").execute()
325
+
326
+ if (response.data) {
327
+ console.log(response.data) // Array of records
328
+ }
329
+ ```
330
+
331
+ ### Fetch Single Record
215
332
 
216
333
  ```typescript
217
- import { Client, Settings } from '@taruvi/sdk'
334
+ const db = new Database(taruviClient)
335
+ const record = await db.from("accounts").get("record-id").execute()
336
+ ```
218
337
 
219
- const client = new Client({ /* config */ })
220
- const settings = new Settings(client)
338
+ ### Create Record
221
339
 
222
- // Fetch site configuration
223
- const siteConfig = await settings.get()
224
- console.log(siteConfig.site_slug)
340
+ ```typescript
341
+ const db = new Database(taruviClient)
342
+ await db.from("accounts").create({
343
+ name: "John Doe",
344
+ email: "john@example.com",
345
+ status: "active"
346
+ }).execute()
225
347
  ```
226
348
 
227
- ---
349
+ ### Update Record
350
+
351
+ ```typescript
352
+ const db = new Database(taruviClient)
353
+ await db.from("accounts").get("record-id").update({
354
+ name: "Updated Name",
355
+ status: "active"
356
+ }).execute()
357
+ ```
228
358
 
229
- ### Database Service (Planned)
359
+ ### Delete Record
230
360
 
231
- Query builder for database operations.
361
+ ```typescript
362
+ const db = new Database(taruviClient)
363
+ await db.from("accounts").delete("record-id").execute()
364
+ ```
232
365
 
233
- **Status**: 📋 Not Implemented
366
+ ### Filter Records
234
367
 
235
368
  ```typescript
236
- import { Client, Database } from '@taruvi/sdk'
369
+ const db = new Database(taruviClient)
370
+
371
+ // Simple field filters
372
+ const filtered = await db
373
+ .from("accounts")
374
+ .filter({
375
+ status: "active",
376
+ country: "USA"
377
+ })
378
+ .execute()
237
379
 
238
- const client = new Client({ /* config */ })
239
- const database = new Database(client)
380
+ // Advanced filters with operators
381
+ const advanced = await db
382
+ .from("accounts")
383
+ .filter({
384
+ age__gte: 18, // age >= 18
385
+ age__lt: 65, // age < 65
386
+ name__icontains: "john", // case-insensitive contains
387
+ created_at__gte: "2024-01-01",
388
+ ordering: "-created_at" // Sort by created_at descending
389
+ })
390
+ .execute()
240
391
 
241
- // Planned API (not yet functional)
242
- const users = await database
243
- .from('users')
244
- .select('*')
245
- .filter('age', 'gte', 18)
392
+ // Pagination
393
+ const paginated = await db
394
+ .from("accounts")
395
+ .filter({
396
+ page: 1,
397
+ pageSize: 20
398
+ })
246
399
  .execute()
247
400
  ```
248
401
 
249
- ---
402
+ ### Populate Related Records
250
403
 
251
- ### Functions Service (Planned)
404
+ Use `populate()` to eager load related records (foreign key relationships):
252
405
 
253
- Serverless function invocation.
406
+ ```typescript
407
+ const db = new Database(taruviClient)
408
+
409
+ // Populate a single relation
410
+ const orders = await db
411
+ .from("orders")
412
+ .populate(["customer"])
413
+ .execute()
414
+
415
+ // Each order now includes the full customer object instead of just the ID
416
+ console.log(orders.data[0].customer.name)
417
+ console.log(orders.data[0].customer.email)
418
+
419
+ // Populate multiple relations
420
+ const invoices = await db
421
+ .from("invoices")
422
+ .populate(["customer", "created_by", "items"])
423
+ .execute()
424
+
425
+ // Combine with filters
426
+ const recentOrders = await db
427
+ .from("orders")
428
+ .filter({
429
+ status: "completed",
430
+ created_at__gte: "2024-01-01",
431
+ ordering: "-created_at"
432
+ })
433
+ .populate(["customer", "product"])
434
+ .execute()
435
+
436
+ // Combine with pagination
437
+ const paginatedOrders = await db
438
+ .from("orders")
439
+ .filter({ page: 1, pageSize: 10 })
440
+ .populate(["customer"])
441
+ .execute()
442
+ ```
254
443
 
255
- **Status**: 📋 Not Implemented
444
+ ### Complete CRUD Example (CRM Table)
256
445
 
257
446
  ```typescript
258
- import { Client, Functions } from '@taruvi/sdk'
447
+ import { useEffect, useState } from 'react'
448
+ import { Database } from '@taruvi/sdk'
449
+
450
+ export default function CrmTable({ taruviClient }) {
451
+ const [contacts, setContacts] = useState([])
452
+
453
+ const fetchContacts = async () => {
454
+ const db = new Database(taruviClient)
455
+ const response = await db.from("accounts").execute()
456
+ if (response.data) {
457
+ setContacts(response.data)
458
+ }
459
+ }
460
+
461
+ useEffect(() => {
462
+ fetchContacts()
463
+ }, [])
464
+
465
+ const handleCreate = async (data) => {
466
+ const db = new Database(taruviClient)
467
+ await db.from("accounts").create(data).execute()
468
+ fetchContacts() // Refresh
469
+ }
259
470
 
260
- const client = new Client({ /* config */ })
261
- const functions = new Functions(client)
471
+ const handleDelete = async (id) => {
472
+ const db = new Database(taruviClient)
473
+ await db.from("accounts").delete(id).execute()
474
+ fetchContacts() // Refresh
475
+ }
262
476
 
263
- // Planned API (not yet functional)
264
- const result = await functions.invoke('my-function', { data: 'value' })
477
+ const handleUpdate = async (id, data) => {
478
+ const db = new Database(taruviClient)
479
+ await db.from("accounts").get(id).update(data).execute()
480
+ fetchContacts() // Refresh
481
+ }
482
+
483
+ return (
484
+ <div>
485
+ <button onClick={() => handleCreate({ name: 'New Contact', status: 'active' })}>
486
+ Add Contact
487
+ </button>
488
+ <table>
489
+ {contacts.map(contact => (
490
+ <tr key={contact.id}>
491
+ <td>{contact.name}</td>
492
+ <td>
493
+ <button onClick={() => handleUpdate(contact.id, { status: 'updated' })}>
494
+ Edit
495
+ </button>
496
+ <button onClick={() => handleDelete(contact.id)}>
497
+ Delete
498
+ </button>
499
+ </td>
500
+ </tr>
501
+ ))}
502
+ </table>
503
+ </div>
504
+ )
505
+ }
265
506
  ```
266
507
 
267
508
  ---
268
509
 
269
- ## Configuration
510
+ ## Storage Service (File Management)
511
+
512
+ ### List Files in Bucket
513
+
514
+ ```typescript
515
+ import { Storage } from '@taruvi/sdk'
516
+
517
+ const storage = new Storage(taruviClient)
518
+ const files = await storage.from("documents").execute()
519
+
520
+ console.log(files.data) // Array of file objects
521
+ ```
270
522
 
271
- ### TaruviConfig Interface
523
+ ### Upload Files
272
524
 
273
525
  ```typescript
274
- interface TaruviConfig {
275
- apiKey: string // Required: Site/organization identifier
276
- appSlug: string // Required: App identifier (multi-tenant)
277
- baseUrl: string // Required: API endpoint URL
278
- token?: string // Optional: Pre-existing session token
526
+ const storage = new Storage(taruviClient)
527
+
528
+ const filesData = {
529
+ files: [file1, file2], // File objects from input
530
+ metadatas: [{ name: "file1" }, { name: "file2" }],
531
+ paths: ["file1.pdf", "file2.pdf"]
279
532
  }
533
+
534
+ await storage.from("documents").upload(filesData).execute()
280
535
  ```
281
536
 
282
- ### Configuration Examples
537
+ ### Download File
283
538
 
284
- #### Basic Setup
285
539
  ```typescript
286
- const client = new Client({
287
- apiKey: 'your-site-key',
288
- appSlug: 'my-app',
289
- baseUrl: 'https://test-api.taruvi.cloud'
290
- })
540
+ const storage = new Storage(taruviClient)
541
+ const file = await storage.from("documents").download("path/to/file.pdf").execute()
291
542
  ```
292
543
 
293
- #### With Existing Token
544
+ ### Delete Files
545
+
294
546
  ```typescript
295
- const client = new Client({
296
- apiKey: 'your-site-key',
297
- appSlug: 'my-app',
298
- baseUrl: 'https://test-api.taruvi.cloud',
299
- token: 'existing-session-token' // Skip login
300
- })
547
+ const storage = new Storage(taruviClient)
548
+
549
+ // Delete single file
550
+ await storage.from("documents").delete(["path/to/file.pdf"]).execute()
551
+
552
+ // Delete multiple files
553
+ await storage.from("documents").delete([
554
+ "path/to/file1.pdf",
555
+ "path/to/file2.pdf",
556
+ "path/to/file3.pdf"
557
+ ]).execute()
301
558
  ```
302
559
 
303
- #### Multiple Environments
560
+ ### Update File Metadata
561
+
304
562
  ```typescript
305
- const config = {
306
- production: {
307
- apiKey: process.env.PROD_API_KEY!,
308
- appSlug: 'prod-app',
309
- baseUrl: 'https://api.taruvi.cloud'
310
- },
311
- development: {
312
- apiKey: process.env.DEV_API_KEY!,
313
- appSlug: 'dev-app',
314
- baseUrl: 'https://dev-api.taruvi.cloud'
563
+ const storage = new Storage(taruviClient)
564
+ await storage
565
+ .from("documents")
566
+ .update("path/to/file.pdf", {
567
+ filename: "newname.pdf",
568
+ visibility: "public",
569
+ metadata: { category: "reports" }
570
+ })
571
+ .execute()
572
+ ```
573
+
574
+ ### Filter Files
575
+
576
+ ```typescript
577
+ const storage = new Storage(taruviClient)
578
+
579
+ // Basic filters
580
+ const filtered = await storage
581
+ .from("documents")
582
+ .filter({
583
+ search: "invoice",
584
+ visibility: "public",
585
+ mimetype_category: "document",
586
+ min_size: 1024,
587
+ ordering: "-created_at"
588
+ })
589
+ .execute()
590
+
591
+ // Advanced filters with operators
592
+ const advanced = await storage
593
+ .from("documents")
594
+ .filter({
595
+ // Size filters (bytes)
596
+ size__gte: 1024, // >= 1KB
597
+ size__lte: 10485760, // <= 10MB
598
+
599
+ // Date filters (ISO 8601)
600
+ created_at__gte: "2024-01-01",
601
+ created_at__lte: "2024-12-31",
602
+
603
+ // Search filters
604
+ filename__icontains: "report",
605
+ file__startswith: "invoice",
606
+ prefix: "uploads/2024/",
607
+
608
+ // MIME type filters
609
+ mimetype: "application/pdf",
610
+ mimetype_category: "image", // image, document, video, audio, etc.
611
+
612
+ // Visibility & user filters
613
+ visibility: "public",
614
+ created_by_me: true,
615
+ created_by__username: "john",
616
+
617
+ // Pagination & sorting
618
+ page: 1,
619
+ pageSize: 50,
620
+ ordering: "-created_at" // Sort by created_at descending
621
+ })
622
+ .execute()
623
+ ```
624
+
625
+ ### Complete File Upload Example
626
+
627
+ ```typescript
628
+ import { useState, useRef } from 'react'
629
+ import { Storage } from '@taruvi/sdk'
630
+
631
+ export default function FileUploader({ taruviClient }) {
632
+ const [files, setFiles] = useState([])
633
+ const [uploading, setUploading] = useState(false)
634
+ const fileInputRef = useRef(null)
635
+
636
+ const handleFileSelect = (e) => {
637
+ const selectedFiles = Array.from(e.target.files)
638
+ setFiles(selectedFiles)
315
639
  }
316
- }
317
640
 
318
- const client = new Client(
319
- process.env.NODE_ENV === 'production'
320
- ? config.production
321
- : config.development
322
- )
641
+ const uploadFiles = async () => {
642
+ if (files.length === 0) return
643
+
644
+ setUploading(true)
645
+ try {
646
+ const storage = new Storage(taruviClient)
647
+
648
+ const uploadData = {
649
+ files: files,
650
+ metadatas: files.map(f => ({ name: f.name })),
651
+ paths: files.map(f => f.name)
652
+ }
653
+
654
+ await storage.from("documents").upload(uploadData).execute()
655
+
656
+ alert("Upload successful!")
657
+ setFiles([])
658
+ } catch (error) {
659
+ alert("Upload failed: " + error.message)
660
+ } finally {
661
+ setUploading(false)
662
+ }
663
+ }
664
+
665
+ return (
666
+ <div>
667
+ <input
668
+ ref={fileInputRef}
669
+ type="file"
670
+ multiple
671
+ onChange={handleFileSelect}
672
+ />
673
+ <button onClick={uploadFiles} disabled={uploading || files.length === 0}>
674
+ {uploading ? "Uploading..." : `Upload ${files.length} file(s)`}
675
+ </button>
676
+ </div>
677
+ )
678
+ }
323
679
  ```
324
680
 
325
681
  ---
326
682
 
327
- ## Framework Integration
683
+ ## Functions Service (Serverless)
684
+
685
+ ### Execute Function (Sync)
686
+
687
+ ```typescript
688
+ import { Functions } from '@taruvi/sdk'
689
+
690
+ const functions = new Functions(taruviClient)
328
691
 
329
- ### React
692
+ const result = await functions.execute("my-function", {
693
+ async: false,
694
+ params: {
695
+ key1: "value1",
696
+ key2: 123
697
+ }
698
+ })
699
+
700
+ console.log(result.data) // Function response
701
+ ```
330
702
 
331
- Create context and custom hooks for app-wide access.
703
+ ### Execute Function (Async)
332
704
 
333
705
  ```typescript
334
- import { createContext, useContext, ReactNode } from 'react'
335
- import { Client, User, Auth } from '@taruvi/sdk'
706
+ const functions = new Functions(taruviClient)
336
707
 
337
- // Create context
338
- const TaruviContext = createContext<Client | null>(null)
708
+ const result = await functions.execute("long-running-task", {
709
+ async: true,
710
+ params: { data: "value" }
711
+ })
339
712
 
340
- // Provider component
341
- export function TaruviProvider({ children }: { children: ReactNode }) {
342
- const client = new Client({
343
- apiKey: process.env.REACT_APP_TARUVI_API_KEY!,
344
- appSlug: process.env.REACT_APP_TARUVI_APP_SLUG!,
345
- baseUrl: process.env.REACT_APP_TARUVI_BASE_URL!
346
- })
713
+ console.log(result.invocation.invocation_id) // Track async execution
714
+ console.log(result.invocation.celery_task_id)
715
+ console.log(result.invocation.status)
716
+ ```
717
+
718
+ ### Complete Function Executor Example
719
+
720
+ ```typescript
721
+ import { useState } from 'react'
722
+ import { Functions } from '@taruvi/sdk'
723
+
724
+ export default function FunctionExecutor({ taruviClient }) {
725
+ const [functionSlug, setFunctionSlug] = useState("")
726
+ const [params, setParams] = useState({})
727
+ const [isAsync, setIsAsync] = useState(false)
728
+ const [result, setResult] = useState(null)
729
+ const [loading, setLoading] = useState(false)
730
+
731
+ const executeFunction = async () => {
732
+ setLoading(true)
733
+ try {
734
+ const functions = new Functions(taruviClient)
735
+ const response = await functions.execute(functionSlug, {
736
+ async: isAsync,
737
+ params: params
738
+ })
739
+ setResult(response)
740
+ } catch (error) {
741
+ console.error(error)
742
+ } finally {
743
+ setLoading(false)
744
+ }
745
+ }
347
746
 
348
747
  return (
349
- <TaruviContext.Provider value={client}>
350
- {children}
351
- </TaruviContext.Provider>
748
+ <div>
749
+ <input
750
+ placeholder="Function slug"
751
+ value={functionSlug}
752
+ onChange={(e) => setFunctionSlug(e.target.value)}
753
+ />
754
+ <label>
755
+ <input
756
+ type="checkbox"
757
+ checked={isAsync}
758
+ onChange={(e) => setIsAsync(e.target.checked)}
759
+ />
760
+ Async
761
+ </label>
762
+ <button onClick={executeFunction} disabled={loading}>
763
+ Execute
764
+ </button>
765
+ {result && <pre>{JSON.stringify(result, null, 2)}</pre>}
766
+ </div>
352
767
  )
353
768
  }
769
+ ```
354
770
 
355
- // Custom hooks
356
- export function useTaruvi() {
357
- const client = useContext(TaruviContext)
358
- if (!client) throw new Error('useTaruvi must be used within TaruviProvider')
359
- return client
360
- }
771
+ ---
361
772
 
362
- export function useAuth() {
363
- const client = useTaruvi()
364
- return new Auth(client)
365
- }
773
+ ## Analytics Service
366
774
 
367
- export function useUser() {
368
- const client = useTaruvi()
369
- return new User(client)
370
- }
775
+ ### Execute Analytics Query
371
776
 
372
- // Usage in component
373
- function UserProfile() {
374
- const user = useUser()
375
- const [data, setData] = useState(null)
777
+ ```typescript
778
+ import { Analytics } from '@taruvi/sdk'
376
779
 
377
- useEffect(() => {
378
- user.getUserData().then(setData)
379
- }, [])
780
+ const analytics = new Analytics(taruviClient)
380
781
 
381
- return <div>Welcome, {data?.username}!</div>
382
- }
782
+ const result = await analytics.execute("monthly-sales-report", {
783
+ params: {
784
+ start_date: "2024-01-01",
785
+ end_date: "2024-12-31"
786
+ }
787
+ })
788
+
789
+ console.log(result.data) // Analytics query result
383
790
  ```
384
791
 
385
- ### Vue 3
792
+ ### Execute with Typed Response
793
+
794
+ ```typescript
795
+ interface SalesData {
796
+ total_sales: number
797
+ orders_count: number
798
+ average_order_value: number
799
+ }
800
+
801
+ const analytics = new Analytics(taruviClient)
386
802
 
387
- Use provide/inject with Composition API.
803
+ const result = await analytics.execute<SalesData>("sales-summary", {
804
+ params: { period: "monthly" }
805
+ })
806
+
807
+ console.log(result.data?.total_sales)
808
+ console.log(result.data?.orders_count)
809
+ ```
810
+
811
+ ### Complete Analytics Dashboard Example
388
812
 
389
813
  ```typescript
390
- import { provide, inject, InjectionKey } from 'vue'
391
- import { Client, Auth, User } from '@taruvi/sdk'
814
+ import { useEffect, useState } from 'react'
815
+ import { Analytics } from '@taruvi/sdk'
392
816
 
393
- // Create injection key
394
- const TaruviKey: InjectionKey<Client> = Symbol('taruvi')
817
+ export default function AnalyticsDashboard({ taruviClient }) {
818
+ const [metrics, setMetrics] = useState(null)
819
+ const [loading, setLoading] = useState(true)
395
820
 
396
- // Setup in main app or parent component
397
- export function setupTaruvi() {
398
- const client = new Client({
399
- apiKey: import.meta.env.VITE_TARUVI_API_KEY,
400
- appSlug: import.meta.env.VITE_TARUVI_APP_SLUG,
401
- baseUrl: import.meta.env.VITE_TARUVI_BASE_URL
402
- })
821
+ useEffect(() => {
822
+ const fetchMetrics = async () => {
823
+ try {
824
+ const analytics = new Analytics(taruviClient)
825
+ const result = await analytics.execute("dashboard-metrics", {
826
+ params: {
827
+ date_range: "last_30_days"
828
+ }
829
+ })
830
+ setMetrics(result.data)
831
+ } catch (error) {
832
+ console.error("Failed to fetch analytics:", error)
833
+ } finally {
834
+ setLoading(false)
835
+ }
836
+ }
837
+ fetchMetrics()
838
+ }, [])
403
839
 
404
- provide(TaruviKey, client)
405
- }
840
+ if (loading) return <div>Loading analytics...</div>
406
841
 
407
- // Composables
408
- export function useTaruvi() {
409
- const client = inject(TaruviKey)
410
- if (!client) throw new Error('Taruvi not provided')
411
- return client
842
+ return (
843
+ <div>
844
+ <h2>Dashboard Metrics</h2>
845
+ <pre>{JSON.stringify(metrics, null, 2)}</pre>
846
+ </div>
847
+ )
412
848
  }
849
+ ```
413
850
 
414
- export function useAuth() {
415
- const client = useTaruvi()
416
- return new Auth(client)
417
- }
851
+ ---
418
852
 
419
- export function useUser() {
420
- const client = useTaruvi()
421
- return new User(client)
422
- }
853
+ ## Settings Service
423
854
 
424
- // Usage in component
425
- import { ref, onMounted } from 'vue'
426
- import { useUser } from '@/composables/taruvi'
855
+ ### Get Site Settings
427
856
 
428
- export default {
429
- setup() {
430
- const user = useUser()
431
- const userData = ref(null)
857
+ ```typescript
858
+ import { Settings } from '@taruvi/sdk'
432
859
 
433
- onMounted(async () => {
434
- userData.value = await user.getUserData()
435
- })
860
+ const settings = new Settings(taruviClient)
861
+ const config = await settings.get()
436
862
 
437
- return { userData }
438
- }
439
- }
863
+ console.log(config) // Site configuration object
440
864
  ```
441
865
 
442
- ### Vanilla JavaScript
866
+ ---
867
+
868
+ ## Secrets Service
443
869
 
444
- Direct usage without framework.
870
+ ### List Secrets
445
871
 
446
872
  ```typescript
447
- import { Client, Auth, User } from '@taruvi/sdk'
873
+ import { Secrets } from '@taruvi/sdk'
448
874
 
449
- // Create client
450
- const client = new Client({
451
- apiKey: 'your-key',
452
- appSlug: 'your-app',
453
- baseUrl: 'https://test-api.taruvi.cloud'
454
- })
875
+ const secrets = new Secrets(taruviClient)
876
+ const result = await secrets.list().execute()
455
877
 
456
- // Initialize services
457
- const auth = new Auth(client)
458
- const user = new User(client)
878
+ console.log(result.items) // Array of secrets
879
+ ```
459
880
 
460
- // Use services
461
- async function handleLogin() {
462
- await auth.authenticateUser()
881
+ ### Get Secret
463
882
 
464
- if (await auth.isUserAuthenticated()) {
465
- const userData = await user.getUserData()
466
- document.getElementById('username').textContent = userData.username
467
- }
468
- }
883
+ ```typescript
884
+ const secrets = new Secrets(taruviClient)
885
+ const secret = await secrets.get("MY_SECRET_KEY").execute()
886
+
887
+ console.log(secret) // Secret object with value
888
+ ```
469
889
 
470
- handleLogin()
890
+ ### Update Secret
891
+
892
+ ```typescript
893
+ const secrets = new Secrets(taruviClient)
894
+
895
+ await secrets.update("MY_SECRET", {
896
+ value: {
897
+ hostname: "db.example.com",
898
+ port_number: 3306,
899
+ username: "admin",
900
+ password: "secret123"
901
+ },
902
+ tags: ["mysql", "production"],
903
+ secret_type: "Mysql"
904
+ }).execute()
471
905
  ```
472
906
 
473
907
  ---
474
908
 
475
- ## TypeScript Types
909
+ ## Policy Service (Resource Permissions)
476
910
 
477
- All public types are exported from the main entry point.
911
+ ### Check Resource Permissions
478
912
 
479
913
  ```typescript
480
- import type {
481
- TaruviConfig,
482
- UserCreateRequest,
483
- UserResponse,
484
- UserDataResponse
485
- } from '@taruvi/sdk'
914
+ import { Policy } from '@taruvi/sdk'
915
+
916
+ const policy = new Policy(taruviClient)
917
+
918
+ // Check permissions for multiple resources
919
+ const result = await policy.checkResource([
920
+ {
921
+ entityType: "crm",
922
+ tableName: "accounts",
923
+ recordId: "record-123",
924
+ attributes: { owner_id: "user-456" },
925
+ actions: ["read", "update"]
926
+ },
927
+ {
928
+ entityType: "docs",
929
+ tableName: "documents",
930
+ recordId: "doc-789",
931
+ attributes: {},
932
+ actions: ["delete"]
933
+ }
934
+ ])
935
+ ```
486
936
 
487
- // Use types in your application
488
- const config: TaruviConfig = {
489
- apiKey: 'key',
490
- appSlug: 'app',
491
- baseUrl: 'https://test-api.taruvi.cloud'
492
- }
937
+ ### Complete Permission Check Example
938
+
939
+ ```typescript
940
+ import { useState, useEffect } from 'react'
941
+ import { Policy } from '@taruvi/sdk'
942
+
943
+ export default function ResourceGuard({ taruviClient, children, resource }) {
944
+ const [allowed, setAllowed] = useState(false)
945
+ const [loading, setLoading] = useState(true)
493
946
 
494
- const newUser: UserCreateRequest = {
495
- username: 'john_doe',
496
- email: 'john@example.com',
497
- password: 'secure123'
947
+ useEffect(() => {
948
+ const checkPermission = async () => {
949
+ try {
950
+ const policy = new Policy(taruviClient)
951
+ const result = await policy.checkResource([
952
+ {
953
+ entityType: resource.entityType,
954
+ tableName: resource.table,
955
+ recordId: resource.id,
956
+ attributes: resource.attributes || {},
957
+ actions: ["read"]
958
+ }
959
+ ])
960
+ setAllowed(result.allowed)
961
+ } catch (error) {
962
+ console.error("Permission check failed:", error)
963
+ setAllowed(false)
964
+ } finally {
965
+ setLoading(false)
966
+ }
967
+ }
968
+ checkPermission()
969
+ }, [resource])
970
+
971
+ if (loading) return <div>Checking permissions...</div>
972
+ if (!allowed) return <div>Access denied</div>
973
+ return children
498
974
  }
499
975
  ```
500
976
 
501
977
  ---
502
978
 
503
- ## Architecture
979
+ ## App Service
504
980
 
505
- ### Design Principles
981
+ ### Get App Roles
506
982
 
507
- The Taruvi SDK follows these architectural principles:
508
-
509
- 1. **Dependency Injection** - No singletons, explicit dependencies
510
- 2. **Lazy Initialization** - Create only what you need
511
- 3. **Internal API Protection** - Internal utilities marked with `@internal`
512
- 4. **Type Safety** - Full TypeScript support with strict mode
513
- 5. **Tree-Shaking** - Unused code is eliminated by bundlers
983
+ ```typescript
984
+ import { App } from '@taruvi/sdk'
514
985
 
515
- ### Project Structure
986
+ const app = new App(taruviClient)
987
+ const roles = await app.roles().execute()
516
988
 
989
+ console.log(roles) // Array of role objects with id, name, permissions
517
990
  ```
518
- src/
519
- ├── lib/ # Public API (safe to use)
520
- │ ├── auth/ # Auth service
521
- │ ├── user/ # User service
522
- │ ├── storage/ # Storage service
523
- │ ├── settings/ # Settings service
524
- │ ├── database/ # Database service (planned)
525
- │ └── function/ # Functions service (planned)
526
-
527
- ├── lib-internal/ # Internal utilities (not public)
528
- │ ├── http/ # HTTP client wrapper
529
- │ ├── token/ # Token management
530
- │ ├── routes/ # API route definitions
531
- │ ├── errors/ # Error handling
532
- │ └── utils/ # Helper functions
533
-
534
- ├── client.ts # Main Client class
535
- ├── index.ts # Public exports
536
- └── types.ts # Shared types
537
- ```
538
991
 
539
- ### Internal vs Public API
992
+ ### Complete Roles List Example
993
+
994
+ ```typescript
995
+ import { useEffect, useState } from 'react'
996
+ import { App } from '@taruvi/sdk'
540
997
 
541
- **Public API** (safe to use):
542
- - `Client` - Main client class
543
- - `Auth`, `User`, `Database`, `Storage`, `Functions` - Service clients
544
- - `TaruviConfig` - Configuration interface
545
- - Exported types from `index.ts`
998
+ export default function RolesList({ taruviClient }) {
999
+ const [roles, setRoles] = useState([])
1000
+ const [loading, setLoading] = useState(true)
1001
+
1002
+ useEffect(() => {
1003
+ const fetchRoles = async () => {
1004
+ try {
1005
+ const app = new App(taruviClient)
1006
+ const response = await app.roles().execute()
1007
+ setRoles(response.data || [])
1008
+ } catch (error) {
1009
+ console.error("Failed to fetch roles:", error)
1010
+ } finally {
1011
+ setLoading(false)
1012
+ }
1013
+ }
1014
+ fetchRoles()
1015
+ }, [])
546
1016
 
547
- **Internal API** (do not use directly):
548
- - `client.httpClient` - Marked with `@internal`
549
- - `client.tokenClient` - Marked with `@internal`
550
- - Files in `lib-internal/` folder
1017
+ if (loading) return <div>Loading roles...</div>
551
1018
 
552
- > ⚠️ **Warning:** Using internal APIs may break in future versions without notice
1019
+ return (
1020
+ <ul>
1021
+ {roles.map(role => (
1022
+ <li key={role.id}>
1023
+ <strong>{role.name}</strong>
1024
+ <span>{role.permissions?.join(", ")}</span>
1025
+ </li>
1026
+ ))}
1027
+ </ul>
1028
+ )
1029
+ }
1030
+ ```
553
1031
 
554
1032
  ---
555
1033
 
556
- ## Testing
1034
+ ## Common Patterns
557
1035
 
558
- ### Mocking the SDK
1036
+ ### Loading States
559
1037
 
560
1038
  ```typescript
561
- import { Client, User } from '@taruvi/sdk'
562
- import { vi, describe, it, expect } from 'vitest'
563
-
564
- describe('User Service', () => {
565
- it('should fetch user data', async () => {
566
- // Mock HttpClient
567
- const mockHttpClient = {
568
- get: vi.fn().mockResolvedValue({
569
- username: 'testuser',
570
- email: 'test@example.com'
571
- })
1039
+ const [data, setData] = useState(null)
1040
+ const [loading, setLoading] = useState(true)
1041
+ const [error, setError] = useState(null)
1042
+
1043
+ useEffect(() => {
1044
+ const fetchData = async () => {
1045
+ setLoading(true)
1046
+ try {
1047
+ const db = new Database(taruviClient)
1048
+ const response = await db.from("table").execute()
1049
+ setData(response.data)
1050
+ } catch (err) {
1051
+ setError(err.message)
1052
+ } finally {
1053
+ setLoading(false)
572
1054
  }
1055
+ }
1056
+ fetchData()
1057
+ }, [])
573
1058
 
574
- // Mock Client
575
- const mockClient = {
576
- httpClient: mockHttpClient,
577
- getConfig: () => ({
578
- apiKey: 'test',
579
- appSlug: 'test',
580
- baseUrl: 'test'
581
- })
582
- } as unknown as Client
1059
+ if (loading) return <div>Loading...</div>
1060
+ if (error) return <div>Error: {error}</div>
1061
+ return <div>{/* Render data */}</div>
1062
+ ```
583
1063
 
584
- // Test User service
585
- const user = new User(mockClient)
586
- const data = await user.getUserData()
1064
+ ### Error Handling
587
1065
 
588
- expect(data.username).toBe('testuser')
589
- expect(mockHttpClient.get).toHaveBeenCalledWith('api/users/me/')
590
- })
591
- })
1066
+ ```typescript
1067
+ try {
1068
+ const user = new User(taruviClient)
1069
+ await user.createUser(data)
1070
+ } catch (error) {
1071
+ if (error.response?.status === 400) {
1072
+ console.error("Validation error:", error.response.data)
1073
+ } else if (error.response?.status === 401) {
1074
+ console.error("Unauthorized")
1075
+ } else {
1076
+ console.error("Unknown error:", error.message)
1077
+ }
1078
+ }
592
1079
  ```
593
1080
 
594
- ---
1081
+ ### Refresh Data After Mutation
595
1082
 
596
- ## Development Status
1083
+ ```typescript
1084
+ const [items, setItems] = useState([])
1085
+
1086
+ const fetchItems = async () => {
1087
+ const db = new Database(taruviClient)
1088
+ const response = await db.from("items").execute()
1089
+ setItems(response.data || [])
1090
+ }
597
1091
 
598
- ### Implementation Progress
1092
+ const createItem = async (data) => {
1093
+ const db = new Database(taruviClient)
1094
+ await db.from("items").create(data).execute()
1095
+ await fetchItems() // Refresh list
1096
+ }
599
1097
 
600
- | Service | Status | Progress | Notes |
601
- |---------|--------|----------|-------|
602
- | Core Infrastructure | ✅ Complete | 90% | Client, HTTP, Token management |
603
- | User Service | ✅ Functional | 80% | CRUD operations working |
604
- | Auth Service | 🚧 Partial | 60% | Basic auth working, SSO planned |
605
- | Storage Service | 🚧 Partial | 70% | Query builder working |
606
- | Settings Service | ✅ Functional | 70% | Site config fetching |
607
- | Database Service | 📋 Planned | 0% | Not yet implemented |
608
- | Functions Service | 📋 Planned | 0% | Not yet implemented |
1098
+ const deleteItem = async (id) => {
1099
+ const db = new Database(taruviClient)
1100
+ await db.from("items").delete(id).execute()
1101
+ await fetchItems() // Refresh list
1102
+ }
609
1103
 
610
- ### Legend
611
- - **Complete/Functional**: Ready for production use
612
- - 🚧 **Partial**: Core functionality works, some features pending
613
- - 📋 **Planned**: Not yet implemented
1104
+ const updateItem = async (id, data) => {
1105
+ const db = new Database(taruviClient)
1106
+ await db.from("items").get(id).update(data).execute()
1107
+ await fetchItems() // Refresh list
1108
+ }
1109
+ ```
614
1110
 
615
1111
  ---
616
1112
 
617
- ## Roadmap
1113
+ ## TypeScript Types
1114
+
1115
+ ### Import Types
1116
+
1117
+ ```typescript
1118
+ import type {
1119
+ TaruviConfig,
1120
+ AuthTokens,
1121
+ UserCreateRequest,
1122
+ UserResponse,
1123
+ UserDataResponse,
1124
+ FunctionRequest,
1125
+ FunctionResponse,
1126
+ FunctionInvocation,
1127
+ DatabaseRequest,
1128
+ DatabaseResponse,
1129
+ DatabaseFilters,
1130
+ StorageRequest,
1131
+ StorageUpdateRequest,
1132
+ StorageResponse,
1133
+ StorageFilters,
1134
+ SettingsResponse,
1135
+ SecretRequest,
1136
+ SecretResponse,
1137
+ Principal,
1138
+ Resource,
1139
+ Resources,
1140
+ RoleResponse,
1141
+ AnalyticsRequest,
1142
+ AnalyticsResponse
1143
+ } from '@taruvi/sdk'
1144
+ ```
618
1145
 
619
- ### v1.2 (Next Release)
620
- - [ ] Complete Auth service (SSO, token refresh, sign out)
621
- - [ ] Add error handling classes
622
- - [ ] Implement token management (set, clear, expiration)
623
- - [ ] Add PATCH HTTP method
624
- - [ ] Add retry logic for failed requests
1146
+ ### Type Usage
625
1147
 
626
- ### v1.3 (Future)
627
- - [ ] Database service with query builder
628
- - [ ] Functions service for serverless invocation
629
- - [ ] File upload/download in Storage
630
- - [ ] Comprehensive test suite
1148
+ ```typescript
1149
+ const config: TaruviConfig = {
1150
+ apiKey: "key",
1151
+ appSlug: "app",
1152
+ baseUrl: "https://api.taruvi.cloud",
1153
+ deskUrl: "https://desk.taruvi.cloud", // optional
1154
+ token: "existing-token" // optional
1155
+ }
631
1156
 
632
- ### v2.0 (Long-term)
633
- - [ ] Real-time subscriptions (WebSocket)
634
- - [ ] Offline support with local caching
635
- - [ ] Browser DevTools extension
1157
+ const userData: UserCreateRequest = {
1158
+ username: "john",
1159
+ email: "john@example.com",
1160
+ password: "pass123",
1161
+ confirm_password: "pass123",
1162
+ first_name: "John",
1163
+ last_name: "Doe",
1164
+ is_active: true,
1165
+ is_staff: false
1166
+ }
636
1167
 
637
- ---
1168
+ // Database filters with operators
1169
+ const dbFilters: DatabaseFilters = {
1170
+ page: 1,
1171
+ pageSize: 20,
1172
+ ordering: "-created_at",
1173
+ status: "active",
1174
+ age__gte: 18,
1175
+ name__icontains: "john"
1176
+ }
638
1177
 
639
- ## API Reference
1178
+ // Storage filters with comprehensive options
1179
+ const storageFilters: StorageFilters = {
1180
+ page: 1,
1181
+ pageSize: 50,
1182
+ search: "invoice",
1183
+ visibility: "public",
1184
+ mimetype_category: "document",
1185
+ size__gte: 1024,
1186
+ size__lte: 10485760,
1187
+ created_at__gte: "2024-01-01",
1188
+ ordering: "-created_at",
1189
+ created_by_me: true
1190
+ }
640
1191
 
641
- For complete API documentation, see [adr.md](./adr.md).
1192
+ // Policy types for permission checking
1193
+ const principal: Principal = {
1194
+ id: "user-123",
1195
+ roles: ["admin", "editor"],
1196
+ attr: { department: "engineering" }
1197
+ }
642
1198
 
643
- For usage examples, see [USAGE_EXAMPLE.md](./USAGE_EXAMPLE.md).
1199
+ const resources: Resources = [
1200
+ {
1201
+ entityType: "crm",
1202
+ tableName: "accounts",
1203
+ recordId: "acc-456",
1204
+ attributes: { owner_id: "user-123" },
1205
+ actions: ["read", "update", "delete"]
1206
+ }
1207
+ ]
1208
+ ```
644
1209
 
645
1210
  ---
646
1211
 
647
- ## Contributing
1212
+ ## Filter Operators Reference
648
1213
 
649
- Contributions are welcome! Please feel free to submit a Pull Request.
1214
+ ### Database Filter Operators (Django-style)
650
1215
 
651
- ### Development Setup
1216
+ The Database service supports Django-style field lookups:
652
1217
 
653
- ```bash
654
- # Clone repository
655
- git clone https://github.com/taruvi/taruvi-sdk
656
- cd taruvi-sdk
1218
+ | Operator | Description | Example |
1219
+ |----------|-------------|---------|
1220
+ | `field` | Exact match | `{ status: "active" }` |
1221
+ | `field__gte` | Greater than or equal | `{ age__gte: 18 }` |
1222
+ | `field__gt` | Greater than | `{ age__gt: 17 }` |
1223
+ | `field__lte` | Less than or equal | `{ age__lte: 65 }` |
1224
+ | `field__lt` | Less than | `{ age__lt: 66 }` |
1225
+ | `field__icontains` | Case-insensitive contains | `{ name__icontains: "john" }` |
1226
+ | `field__contains` | Case-sensitive contains | `{ name__contains: "John" }` |
1227
+ | `field__istartswith` | Case-insensitive starts with | `{ email__istartswith: "admin" }` |
1228
+ | `field__startswith` | Case-sensitive starts with | `{ code__startswith: "PRE" }` |
1229
+ | `field__iendswith` | Case-insensitive ends with | `{ domain__iendswith: ".com" }` |
1230
+ | `field__endswith` | Case-sensitive ends with | `{ filename__endswith: ".pdf" }` |
1231
+ | `field__in` | Value in list | `{ status__in: ["active", "pending"] }` |
1232
+ | `field__isnull` | Is null check | `{ deleted_at__isnull: true }` |
1233
+ | `ordering` | Sort results | `{ ordering: "-created_at" }` (- for desc) |
1234
+ | `page` | Page number | `{ page: 1 }` |
1235
+ | `pageSize` | Items per page | `{ pageSize: 20 }` |
657
1236
 
658
- # Install dependencies
659
- npm install
1237
+ ### Populate (Eager Loading)
660
1238
 
661
- # Build SDK
662
- npm run build
1239
+ Use the `populate()` method to eager load related records:
663
1240
 
664
- # Run tests (when available)
665
- npm test
1241
+ ```typescript
1242
+ // Populate accepts an array of relation field names
1243
+ db.from("orders").populate(["customer", "items"]).execute()
1244
+
1245
+ // This adds ?populate=customer,items to the query string
666
1246
  ```
667
1247
 
668
- ---
1248
+ | Parameter | Type | Description |
1249
+ |-----------|------|-------------|
1250
+ | `populate` | `string[]` | Array of relation field names to eager load |
669
1251
 
670
- ## License
1252
+ ### Storage Filter Options
671
1253
 
672
- MIT License - see [LICENSE](./LICENSE) file for details.
1254
+ The Storage service supports these specialized filters:
673
1255
 
674
- ---
1256
+ | Category | Filters | Description |
1257
+ |----------|---------|-------------|
1258
+ | **Size** | `size__gte`, `size__lte`, `size__gt`, `size__lt`, `min_size`, `max_size` | Filter by file size in bytes |
1259
+ | **Dates** | `created_at__gte`, `created_at__lte`, `created_after`, `created_before`, `updated_at__gte`, `updated_at__lte` | Filter by dates (ISO 8601 format) |
1260
+ | **Search** | `search`, `filename__icontains`, `prefix`, `file`, `file__icontains`, `file__startswith`, `file__istartswith`, `metadata_search` | Search for files |
1261
+ | **MIME Type** | `mimetype`, `mimetype__in`, `mimetype_category` | Filter by file type (document, image, video, audio, etc.) |
1262
+ | **Visibility** | `visibility` | Filter by public/private visibility |
1263
+ | **User** | `created_by_me`, `modified_by_me`, `created_by__username`, `created_by__username__icontains` | Filter by user |
1264
+ | **Pagination** | `page`, `pageSize` | Paginate results |
1265
+ | **Sorting** | `ordering` | Sort results (e.g., "-created_at") |
675
1266
 
676
- ## Support
1267
+ ---
677
1268
 
678
- For questions, issues, or feature requests:
679
- - 📧 Email: support@taruvi.io
680
- - 🐛 Issues: [GitHub Issues](https://github.com/taruvi/taruvi-sdk/issues)
681
- - 📖 Docs: [Documentation](https://docs.taruvi.io)
1269
+ ## Quick Reference
1270
+
1271
+ | Service | Import | Purpose |
1272
+ |---------|--------|---------|
1273
+ | `Client` | `import { Client }` | Main SDK client |
1274
+ | `Auth` | `import { Auth }` | Authentication |
1275
+ | `User` | `import { User }` | User management |
1276
+ | `Database` | `import { Database }` | App data CRUD |
1277
+ | `Storage` | `import { Storage }` | File management |
1278
+ | `Functions` | `import { Functions }` | Serverless functions |
1279
+ | `Settings` | `import { Settings }` | Site configuration |
1280
+ | `Secrets` | `import { Secrets }` | Sensitive data |
1281
+ | `Policy` | `import { Policy }` | Resource permissions |
1282
+ | `App` | `import { App }` | App roles & config |
1283
+ | `Analytics` | `import { Analytics }` | Analytics queries |
682
1284
 
683
1285
  ---
684
1286
 
685
- ## Related Resources
1287
+ ## Chaining Pattern
686
1288
 
687
- - [Architecture Decision Record (ADR)](./adr.md) - Complete architectural documentation
688
- - [Usage Examples](./USAGE_EXAMPLE.md) - Additional code examples
689
- - [Taruvi Platform Docs](https://docs.taruvi.io) - Platform documentation
690
- - [API Reference](https://api-docs.taruvi.io) - REST API documentation
1289
+ All query-building services use method chaining:
1290
+
1291
+ ```typescript
1292
+ // Database
1293
+ const db = new Database(taruviClient)
1294
+ await db.from("table").get("id").update(data).execute()
1295
+ await db.from("table").filter({ status: "active" }).execute()
1296
+ await db.from("table").filter({ page: 1 }).populate(["related_field"]).execute()
1297
+ await db.from("table").create({ name: "New" }).execute()
1298
+
1299
+ // Storage
1300
+ const storage = new Storage(taruviClient)
1301
+ await storage.from("bucket").delete(["path/to/file.pdf"]).execute()
1302
+ await storage.from("bucket").filter({ search: "query" }).execute()
1303
+ await storage.from("bucket").download("path/to/file.pdf").execute()
1304
+ ```
1305
+
1306
+ **Always call `.execute()` at the end to run the query!**
691
1307
 
692
1308
  ---
693
1309
 
694
- ## Acknowledgments
1310
+ ## Environment Variables
1311
+
1312
+ ```env
1313
+ VITE_TARUVI_API_KEY=your-api-key
1314
+ VITE_TARUVI_APP_SLUG=your-app
1315
+ VITE_TARUVI_BASE_URL=https://taruvi-site.taruvi.cloud
1316
+ ```
695
1317
 
696
- Inspired by:
697
- - [Supabase JS](https://github.com/supabase/supabase-js) - Query builder pattern
698
- - [Appwrite SDK](https://github.com/appwrite/sdk-for-web) - Service architecture
699
- - [Stripe SDK](https://github.com/stripe/stripe-node) - Client pattern
1318
+ ```typescript
1319
+ const client = new Client({
1320
+ apiKey: import.meta.env.VITE_TARUVI_API_KEY,
1321
+ appSlug: import.meta.env.VITE_TARUVI_APP_SLUG,
1322
+ baseUrl: import.meta.env.VITE_TARUVI_BASE_URL
1323
+ })
1324
+ ```
700
1325
 
701
1326
  ---
702
1327
 
703
- **Built with ❤️ by the Taruvi Team**
1328
+ **Generated from production code examples Last updated: 2026-01-05**