@taruvi/sdk 1.5.0 → 1.5.1-beta.4

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 (231) hide show
  1. package/README.md +60 -1289
  2. package/dist/client.d.ts +27 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/{src/client.ts → dist/client.js} +30 -48
  5. package/dist/client.js.map +1 -0
  6. package/dist/index.d.ts +28 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +20 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/lib/analytics/AnalyticsClient.d.ts +9 -0
  11. package/dist/lib/analytics/AnalyticsClient.d.ts.map +1 -0
  12. package/dist/lib/analytics/AnalyticsClient.js +17 -0
  13. package/dist/lib/analytics/AnalyticsClient.js.map +1 -0
  14. package/dist/lib/analytics/types.d.ts +6 -0
  15. package/dist/lib/analytics/types.d.ts.map +1 -0
  16. package/dist/lib/analytics/types.js +2 -0
  17. package/dist/lib/analytics/types.js.map +1 -0
  18. package/dist/lib/app/AppClient.d.ts +15 -0
  19. package/dist/lib/app/AppClient.d.ts.map +1 -0
  20. package/dist/lib/app/AppClient.js +41 -0
  21. package/dist/lib/app/AppClient.js.map +1 -0
  22. package/dist/lib/app/types.d.ts +41 -0
  23. package/dist/lib/app/types.d.ts.map +1 -0
  24. package/dist/lib/app/types.js +2 -0
  25. package/dist/lib/app/types.js.map +1 -0
  26. package/dist/lib/auth/AuthClient.d.ts +38 -0
  27. package/dist/lib/auth/AuthClient.d.ts.map +1 -0
  28. package/dist/lib/auth/AuthClient.js +105 -0
  29. package/dist/lib/auth/AuthClient.js.map +1 -0
  30. package/dist/lib/database/DatabaseClient.d.ts +76 -0
  31. package/dist/lib/database/DatabaseClient.d.ts.map +1 -0
  32. package/dist/lib/database/DatabaseClient.js +250 -0
  33. package/dist/lib/database/DatabaseClient.js.map +1 -0
  34. package/dist/lib/database/types.d.ts +66 -0
  35. package/dist/lib/database/types.d.ts.map +1 -0
  36. package/dist/lib/database/types.js +20 -0
  37. package/dist/lib/database/types.js.map +1 -0
  38. package/dist/lib/functions/FunctionsClient.d.ts +9 -0
  39. package/dist/lib/functions/FunctionsClient.d.ts.map +1 -0
  40. package/dist/lib/functions/FunctionsClient.js +20 -0
  41. package/dist/lib/functions/FunctionsClient.js.map +1 -0
  42. package/dist/lib/functions/types.d.ts +25 -0
  43. package/dist/lib/functions/types.d.ts.map +1 -0
  44. package/dist/lib/functions/types.js +2 -0
  45. package/dist/lib/functions/types.js.map +1 -0
  46. package/dist/lib/policy/PolicyClient.d.ts +25 -0
  47. package/dist/lib/policy/PolicyClient.d.ts.map +1 -0
  48. package/{src/lib/policy/PolicyClient.ts → dist/lib/policy/PolicyClient.js} +26 -40
  49. package/dist/lib/policy/PolicyClient.js.map +1 -0
  50. package/dist/lib/policy/types.d.ts +32 -0
  51. package/dist/lib/policy/types.d.ts.map +1 -0
  52. package/dist/lib/policy/types.js +2 -0
  53. package/dist/lib/policy/types.js.map +1 -0
  54. package/dist/lib/secrets/SecretsClient.d.ts +29 -0
  55. package/dist/lib/secrets/SecretsClient.d.ts.map +1 -0
  56. package/dist/lib/secrets/SecretsClient.js +66 -0
  57. package/dist/lib/secrets/SecretsClient.js.map +1 -0
  58. package/dist/lib/secrets/types.d.ts +43 -0
  59. package/dist/lib/secrets/types.d.ts.map +1 -0
  60. package/dist/lib/secrets/types.js +2 -0
  61. package/dist/lib/secrets/types.js.map +1 -0
  62. package/dist/lib/settings/SettingsClient.d.ts +9 -0
  63. package/dist/lib/settings/SettingsClient.d.ts.map +1 -0
  64. package/dist/lib/settings/SettingsClient.js +17 -0
  65. package/dist/lib/settings/SettingsClient.js.map +1 -0
  66. package/dist/lib/settings/types.d.ts +6 -0
  67. package/dist/lib/settings/types.d.ts.map +1 -0
  68. package/dist/lib/settings/types.js +2 -0
  69. package/dist/lib/settings/types.js.map +1 -0
  70. package/dist/lib/storage/StorageClient.d.ts +38 -0
  71. package/dist/lib/storage/StorageClient.d.ts.map +1 -0
  72. package/dist/lib/storage/StorageClient.js +102 -0
  73. package/dist/lib/storage/StorageClient.js.map +1 -0
  74. package/dist/lib/storage/types.d.ts +73 -0
  75. package/dist/lib/storage/types.d.ts.map +1 -0
  76. package/dist/lib/storage/types.js +2 -0
  77. package/dist/lib/storage/types.js.map +1 -0
  78. package/dist/lib/users/UserClient.d.ts +17 -0
  79. package/dist/lib/users/UserClient.d.ts.map +1 -0
  80. package/dist/lib/users/UserClient.js +40 -0
  81. package/dist/lib/users/UserClient.js.map +1 -0
  82. package/dist/lib/users/types.d.ts +108 -0
  83. package/dist/lib/users/types.d.ts.map +1 -0
  84. package/dist/lib/users/types.js +2 -0
  85. package/dist/lib/users/types.js.map +1 -0
  86. package/dist/lib-internal/errors/ErrorClient.d.ts +42 -0
  87. package/dist/lib-internal/errors/ErrorClient.d.ts.map +1 -0
  88. package/dist/lib-internal/errors/ErrorClient.js +102 -0
  89. package/dist/lib-internal/errors/ErrorClient.js.map +1 -0
  90. package/dist/lib-internal/errors/index.d.ts +4 -0
  91. package/dist/lib-internal/errors/index.d.ts.map +1 -0
  92. package/dist/lib-internal/errors/index.js +3 -0
  93. package/dist/lib-internal/errors/index.js.map +1 -0
  94. package/dist/lib-internal/errors/types.d.ts +29 -0
  95. package/dist/lib-internal/errors/types.d.ts.map +1 -0
  96. package/dist/lib-internal/errors/types.js +18 -0
  97. package/dist/lib-internal/errors/types.js.map +1 -0
  98. package/dist/lib-internal/http/HttpClient.d.ts +24 -0
  99. package/dist/lib-internal/http/HttpClient.d.ts.map +1 -0
  100. package/dist/lib-internal/http/HttpClient.js +103 -0
  101. package/dist/lib-internal/http/HttpClient.js.map +1 -0
  102. package/dist/lib-internal/http/types.d.ts +12 -0
  103. package/dist/lib-internal/http/types.d.ts.map +1 -0
  104. package/{src/lib-internal/http/types.ts → dist/lib-internal/http/types.js} +2 -3
  105. package/dist/lib-internal/http/types.js.map +1 -0
  106. package/dist/lib-internal/routes/AnalyticsRoutes.d.ts +4 -0
  107. package/dist/lib-internal/routes/AnalyticsRoutes.d.ts.map +1 -0
  108. package/dist/lib-internal/routes/AnalyticsRoutes.js +4 -0
  109. package/dist/lib-internal/routes/AnalyticsRoutes.js.map +1 -0
  110. package/dist/lib-internal/routes/AppRoutes.d.ts +10 -0
  111. package/dist/lib-internal/routes/AppRoutes.d.ts.map +1 -0
  112. package/dist/lib-internal/routes/AppRoutes.js +6 -0
  113. package/dist/lib-internal/routes/AppRoutes.js.map +1 -0
  114. package/dist/lib-internal/routes/AuthRoutes.d.ts +2 -0
  115. package/dist/lib-internal/routes/AuthRoutes.d.ts.map +1 -0
  116. package/dist/lib-internal/routes/AuthRoutes.js +2 -0
  117. package/dist/lib-internal/routes/AuthRoutes.js.map +1 -0
  118. package/dist/lib-internal/routes/DatabaseRoutes.d.ts +11 -0
  119. package/dist/lib-internal/routes/DatabaseRoutes.d.ts.map +1 -0
  120. package/dist/lib-internal/routes/DatabaseRoutes.js +7 -0
  121. package/dist/lib-internal/routes/DatabaseRoutes.js.map +1 -0
  122. package/dist/lib-internal/routes/FunctionRoutes.d.ts +4 -0
  123. package/dist/lib-internal/routes/FunctionRoutes.d.ts.map +1 -0
  124. package/dist/lib-internal/routes/FunctionRoutes.js +4 -0
  125. package/dist/lib-internal/routes/FunctionRoutes.js.map +1 -0
  126. package/dist/lib-internal/routes/PolicyRoutes.d.ts +5 -0
  127. package/dist/lib-internal/routes/PolicyRoutes.d.ts.map +1 -0
  128. package/dist/lib-internal/routes/PolicyRoutes.js +5 -0
  129. package/dist/lib-internal/routes/PolicyRoutes.js.map +1 -0
  130. package/dist/lib-internal/routes/SecretsRoutes.d.ts +6 -0
  131. package/dist/lib-internal/routes/SecretsRoutes.d.ts.map +1 -0
  132. package/dist/lib-internal/routes/SecretsRoutes.js +6 -0
  133. package/dist/lib-internal/routes/SecretsRoutes.js.map +1 -0
  134. package/dist/lib-internal/routes/SettingsRoutes.d.ts +5 -0
  135. package/dist/lib-internal/routes/SettingsRoutes.d.ts.map +1 -0
  136. package/{src/lib-internal/routes/SettingsRoutes.ts → dist/lib-internal/routes/SettingsRoutes.js} +2 -1
  137. package/dist/lib-internal/routes/SettingsRoutes.js.map +1 -0
  138. package/dist/lib-internal/routes/StorageRoutes.d.ts +11 -0
  139. package/dist/lib-internal/routes/StorageRoutes.d.ts.map +1 -0
  140. package/dist/lib-internal/routes/StorageRoutes.js +8 -0
  141. package/dist/lib-internal/routes/StorageRoutes.js.map +1 -0
  142. package/dist/lib-internal/routes/UserRoutes.d.ts +13 -0
  143. package/dist/lib-internal/routes/UserRoutes.d.ts.map +1 -0
  144. package/dist/lib-internal/routes/UserRoutes.js +13 -0
  145. package/dist/lib-internal/routes/UserRoutes.js.map +1 -0
  146. package/dist/lib-internal/routes/index.d.ts +2 -0
  147. package/dist/lib-internal/routes/index.d.ts.map +1 -0
  148. package/dist/lib-internal/routes/index.js +2 -0
  149. package/dist/lib-internal/routes/index.js.map +1 -0
  150. package/dist/lib-internal/token/TokenClient.d.ts +38 -0
  151. package/dist/lib-internal/token/TokenClient.d.ts.map +1 -0
  152. package/{src/lib-internal/token/TokenClient.ts → dist/lib-internal/token/TokenClient.js} +44 -59
  153. package/dist/lib-internal/token/TokenClient.js.map +1 -0
  154. package/dist/lib-internal/token/types.d.ts +2 -0
  155. package/dist/lib-internal/token/types.d.ts.map +1 -0
  156. package/dist/lib-internal/token/types.js +2 -0
  157. package/dist/lib-internal/token/types.js.map +1 -0
  158. package/dist/types.d.ts +74 -0
  159. package/dist/types.d.ts.map +1 -0
  160. package/dist/types.js +2 -0
  161. package/dist/types.js.map +1 -0
  162. package/dist/utils/enums.d.ts +31 -0
  163. package/dist/utils/enums.d.ts.map +1 -0
  164. package/dist/utils/enums.js +26 -0
  165. package/dist/utils/enums.js.map +1 -0
  166. package/dist/utils/utils.d.ts +6 -0
  167. package/dist/utils/utils.d.ts.map +1 -0
  168. package/dist/utils/utils.js +38 -0
  169. package/dist/utils/utils.js.map +1 -0
  170. package/package.json +11 -2
  171. package/.github/worflows/publish.yml +0 -57
  172. package/.github/workflows/publish.yml +0 -58
  173. package/.kiro/settings/lsp.json +0 -198
  174. package/MODULE_NAMING_CHANGES.md +0 -81
  175. package/PARAMETER_NAMING_CHANGES.md +0 -106
  176. package/USAGE_EXAMPLE.md +0 -86
  177. package/src/index.ts +0 -50
  178. package/src/lib/analytics/AnalyticsClient.ts +0 -24
  179. package/src/lib/analytics/types.ts +0 -8
  180. package/src/lib/app/AppClient.ts +0 -54
  181. package/src/lib/app/types.ts +0 -50
  182. package/src/lib/auth/AuthClient.ts +0 -148
  183. package/src/lib/auth/types.ts +0 -123
  184. package/src/lib/database/DatabaseClient.ts +0 -244
  185. package/src/lib/database/types.ts +0 -90
  186. package/src/lib/functions/FunctionsClient.ts +0 -27
  187. package/src/lib/functions/types.ts +0 -27
  188. package/src/lib/policy/types.ts +0 -39
  189. package/src/lib/secrets/SecretsClient.ts +0 -75
  190. package/src/lib/secrets/types.ts +0 -59
  191. package/src/lib/settings/SettingsClient.ts +0 -22
  192. package/src/lib/settings/types.ts +0 -9
  193. package/src/lib/storage/StorageClient.ts +0 -131
  194. package/src/lib/storage/types.ts +0 -86
  195. package/src/lib/users/UserClient.ts +0 -63
  196. package/src/lib/users/types.ts +0 -123
  197. package/src/lib-internal/errors/ErrorClient.ts +0 -114
  198. package/src/lib-internal/errors/index.ts +0 -3
  199. package/src/lib-internal/errors/types.ts +0 -29
  200. package/src/lib-internal/http/HttpClient.ts +0 -117
  201. package/src/lib-internal/routes/AnalyticsRoutes.ts +0 -3
  202. package/src/lib-internal/routes/AppRoutes.ts +0 -9
  203. package/src/lib-internal/routes/AuthRoutes.ts +0 -3
  204. package/src/lib-internal/routes/DatabaseRoutes.ts +0 -10
  205. package/src/lib-internal/routes/FunctionRoutes.ts +0 -3
  206. package/src/lib-internal/routes/PolicyRoutes.ts +0 -4
  207. package/src/lib-internal/routes/SecretsRoutes.ts +0 -5
  208. package/src/lib-internal/routes/StorageRoutes.ts +0 -15
  209. package/src/lib-internal/routes/UserRoutes.ts +0 -12
  210. package/src/lib-internal/routes/index.ts +0 -0
  211. package/src/lib-internal/token/types.ts +0 -0
  212. package/src/types.ts +0 -98
  213. package/src/utils/enums.ts +0 -24
  214. package/src/utils/utils.ts +0 -37
  215. package/tests/fixtures/mockClient.ts +0 -19
  216. package/tests/mocks/db.json +0 -1
  217. package/tests/unit/analytics/AnalyticsClient.test.ts +0 -84
  218. package/tests/unit/app/AppClient.test.ts +0 -114
  219. package/tests/unit/auth/AuthClient.test.ts +0 -91
  220. package/tests/unit/client/Client.test.ts +0 -87
  221. package/tests/unit/database/DatabaseClient.test.ts +0 -565
  222. package/tests/unit/edge-cases/robustness.test.ts +0 -258
  223. package/tests/unit/errors/errors.test.ts +0 -236
  224. package/tests/unit/functions/FunctionsClient.test.ts +0 -99
  225. package/tests/unit/policy/PolicyClient.test.ts +0 -180
  226. package/tests/unit/secrets/SecretsClient.test.ts +0 -146
  227. package/tests/unit/settings/SettingsClient.test.ts +0 -50
  228. package/tests/unit/storage/StorageClient.test.ts +0 -252
  229. package/tests/unit/users/UserClient.test.ts +0 -150
  230. package/tsconfig.json +0 -44
  231. package/vitest.config.ts +0 -7
package/README.md CHANGED
@@ -1,1321 +1,92 @@
1
- # Taruvi SDK - AI Implementation Guide
1
+ # Taruvi SDK
2
2
 
3
- > Quick reference for implementing Taruvi SDK features with copy-paste examples from production code
3
+ TypeScript SDK for the Taruvi platform. It gives developers a **consistent, typed way to query the Taruvi backend** — shared configuration, session authentication, fluent query builders, and structured errors across data, storage, auth, users, functions, analytics, policy, secrets, and app services.
4
+
5
+ **Package:** `@taruvi/sdk` · **Version:** 1.5.0-beta.1 · **License:** MIT
6
+
7
+ **Branches:** `main` is for **stable** releases; `beta` is for **experimental** releases. Bumping `version` in `package.json` and pushing to either branch triggers CI/CD (`npm test`, then publish to npm with the matching tag). See [Releases and branches](docs/08-releases-and-branches.md).
4
8
 
5
9
  ## Installation
6
10
 
7
11
  ```bash
12
+ # Stable (from main)
8
13
  npm install @taruvi/sdk
9
- ```
10
-
11
- ## What's New
12
-
13
- Recent updates to the SDK:
14
-
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.
24
-
25
- ## Core Setup
26
-
27
- ### 1. Initialize Client
28
-
29
- ```typescript
30
- import { Client } from '@taruvi/sdk'
31
-
32
- const taruviClient = new Client({
33
- apiKey: "your-site-api-key",
34
- appSlug: "your-app-slug",
35
- apiUrl: "https://taruvi-site.taruvi.cloud"
36
- })
37
- ```
38
-
39
- ### 2. Pass to Components (React)
40
-
41
- ```typescript
42
- // App.tsx
43
- <Route path="/page" element={<MyPage taruviClient={taruviClient} />} />
44
-
45
- // MyPage.tsx
46
- interface MyPageProps {
47
- taruviClient: Client;
48
- }
49
-
50
- export default function MyPage({ taruviClient }: MyPageProps) {
51
- // Use SDK here
52
- }
53
- ```
54
-
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
14
 
68
- const taruviClient = new Client({ apiKey, appSlug, baseUrl })
69
- // Tokens are now available automatically if present in URL hash
15
+ # Experimental (from beta)
16
+ npm install @taruvi/sdk@beta
70
17
  ```
71
18
 
72
- ---
73
-
74
- ## Auth Service
75
-
76
- ### Check Authentication
77
-
78
- ```typescript
79
- import { Auth } from '@taruvi/sdk'
80
-
81
- const auth = new Auth(taruviClient)
82
- const isAuthenticated = auth.isUserAuthenticated() // Returns boolean (synchronous)
83
- ```
84
-
85
- ### Login Flow (Web UI Flow with Redirect)
86
-
87
- ```typescript
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
- }, [])
104
-
105
- return <div>Checking authentication...</div>
106
- }
107
- ```
108
-
109
- ### Signup Flow
110
-
111
- ```typescript
112
- import { Auth } from '@taruvi/sdk'
113
-
114
- const auth = new Auth(taruviClient)
115
-
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
122
-
123
- ```typescript
124
- import { Auth } from '@taruvi/sdk'
125
-
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
131
- ```
132
-
133
- ### Get Current User
134
-
135
- ```typescript
136
- import { Auth } from '@taruvi/sdk'
137
-
138
- const auth = new Auth(taruviClient)
139
-
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
- ```
146
-
147
- ### Token Management
148
-
149
- ```typescript
150
- import { Auth } from '@taruvi/sdk'
151
-
152
- const auth = new Auth(taruviClient)
153
-
154
- // Get tokens
155
- const accessToken = auth.getAccessToken()
156
- const refreshToken = auth.getRefreshToken()
157
-
158
- // Check if token is expired
159
- const isExpired = auth.isTokenExpired()
160
-
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
- ```
169
-
170
- ---
171
-
172
- ## User Service
173
-
174
- ### Get Current User
175
-
176
- ```typescript
177
- import { User } from '@taruvi/sdk'
178
-
179
- const user = new User(taruviClient)
180
- const userData = await user.getUserData()
181
-
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
-
194
- const newUser = await user.createUser({
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: ""
204
- })
205
- ```
206
-
207
- ### Update User
208
-
209
- ```typescript
210
- const user = new User(taruviClient)
211
-
212
- await user.updateUser("john_doe", {
213
- email: "newemail@example.com",
214
- first_name: "Johnny"
215
- })
216
- ```
217
-
218
- ### Delete User
219
-
220
- ```typescript
221
- const user = new User(taruviClient)
222
- await user.deleteUser("john_doe")
223
- ```
224
-
225
- ### List Users
226
-
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
- ```
19
+ **Peer dependencies:** `axios` (>=1), `typescript` (>=5.7), optional `@types/node` for server use.
241
20
 
242
- ### Get User Apps
21
+ ## Quick start
243
22
 
244
23
  ```typescript
245
- const user = new User(taruviClient)
246
- const apps = await user.getUserApps("john_doe")
24
+ import { Client, Database } from '@taruvi/sdk'
247
25
 
248
- // Returns array of apps the user has access to
249
- apps.forEach(app => {
250
- console.log(app.name, app.slug, app.url)
26
+ const client = new Client({
27
+ apiKey: 'your-site-api-key',
28
+ appSlug: 'your-app-slug',
29
+ apiUrl: 'https://taruvi-site.taruvi.cloud',
251
30
  })
252
- ```
253
-
254
- ### Complete Registration Form Example
255
-
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
- }
295
-
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
- ```
313
-
314
- ---
315
-
316
- ## Database Service (CRUD Operations)
317
-
318
- ### Fetch All Records
319
-
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
332
-
333
- ```typescript
334
- const db = new Database(taruviClient)
335
- const record = await db.from("accounts").get("record-id").execute()
336
- ```
337
-
338
- ### Create Record
339
-
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()
347
- ```
348
-
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
- ```
358
-
359
- ### Delete Record
360
-
361
- ```typescript
362
- const db = new Database(taruviClient)
363
- await db.from("accounts").delete("record-id").execute()
364
- ```
365
-
366
- ### Filter Records
367
-
368
- ```typescript
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()
379
-
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()
391
-
392
- // Pagination
393
- const paginated = await db
394
- .from("accounts")
395
- .filter({
396
- page: 1,
397
- pageSize: 20
398
- })
399
- .execute()
400
- ```
401
-
402
- ### Populate Related Records
403
-
404
- Use `populate()` to eager load related records (foreign key relationships):
405
-
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
- ```
443
-
444
- ### Complete CRUD Example (CRM Table)
445
-
446
- ```typescript
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
- }
470
-
471
- const handleDelete = async (id) => {
472
- const db = new Database(taruviClient)
473
- await db.from("accounts").delete(id).execute()
474
- fetchContacts() // Refresh
475
- }
476
-
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
- }
506
- ```
507
-
508
- ---
509
-
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
- ```
522
-
523
- ### Upload Files
524
-
525
- ```typescript
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"]
532
- }
533
-
534
- await storage.from("documents").upload(filesData).execute()
535
- ```
536
-
537
- ### Download File
538
-
539
- ```typescript
540
- const storage = new Storage(taruviClient)
541
- const file = await storage.from("documents").download("path/to/file.pdf").execute()
542
- ```
543
-
544
- ### Delete Files
545
-
546
- ```typescript
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()
558
- ```
559
-
560
- ### Update File Metadata
561
-
562
- ```typescript
563
- const storage = new Storage(taruviClient)
564
- await storage
565
- .from("documents")
566
- .update("path/to/file.pdf", {
567
- visibility: "public",
568
- metadata: { category: "reports" }
569
- })
570
- .execute()
571
- ```
572
-
573
- ### Filter Files
574
-
575
- ```typescript
576
- const storage = new Storage(taruviClient)
577
-
578
- // Basic filters
579
- const filtered = await storage
580
- .from("documents")
581
- .filter({
582
- search: "invoice",
583
- visibility: "public",
584
- mimetype_category: "document",
585
- min_size: 1024,
586
- ordering: "-created_at"
587
- })
588
- .execute()
589
-
590
- // Advanced filters with operators
591
- const advanced = await storage
592
- .from("documents")
593
- .filter({
594
- // Size filters (bytes)
595
- size__gte: 1024, // >= 1KB
596
- size__lte: 10485760, // <= 10MB
597
-
598
- // Date filters (ISO 8601)
599
- created_at__gte: "2024-01-01",
600
- created_at__lte: "2024-12-31",
601
-
602
- // Search filters
603
- filename__icontains: "report",
604
- file__startswith: "invoice",
605
- prefix: "uploads/2024/",
606
-
607
- // MIME type filters
608
- mimetype: "application/pdf",
609
- mimetype_category: "image", // image, document, video, audio, etc.
610
31
 
611
- // Visibility & user filters
612
- visibility: "public",
613
- created_by_me: true,
614
- created_by__username: "john",
32
+ const db = new Database(client)
615
33
 
616
- // Pagination & sorting
617
- page: 1,
618
- pageSize: 50,
619
- ordering: "-created_at" // Sort by created_at descending
620
- })
34
+ const response = await db
35
+ .from('accounts')
36
+ .filters('status', 'eq', 'active')
37
+ .sort('created_at', 'desc')
38
+ .page(1)
39
+ .pageSize(20)
621
40
  .execute()
622
41
  ```
623
42
 
624
- ### Complete File Upload Example
625
-
626
- ```typescript
627
- import { useState, useRef } from 'react'
628
- import { Storage } from '@taruvi/sdk'
629
-
630
- export default function FileUploader({ taruviClient }) {
631
- const [files, setFiles] = useState([])
632
- const [uploading, setUploading] = useState(false)
633
- const fileInputRef = useRef(null)
634
-
635
- const handleFileSelect = (e) => {
636
- const selectedFiles = Array.from(e.target.files)
637
- setFiles(selectedFiles)
638
- }
639
-
640
- const uploadFiles = async () => {
641
- if (files.length === 0) return
642
-
643
- setUploading(true)
644
- try {
645
- const storage = new Storage(taruviClient)
646
-
647
- const uploadData = {
648
- files: files,
649
- metadatas: files.map(f => ({ name: f.name })),
650
- paths: files.map(f => f.name)
651
- }
652
-
653
- await storage.from("documents").upload(uploadData).execute()
654
-
655
- alert("Upload successful!")
656
- setFiles([])
657
- } catch (error) {
658
- alert("Upload failed: " + error.message)
659
- } finally {
660
- setUploading(false)
661
- }
662
- }
663
-
664
- return (
665
- <div>
666
- <input
667
- ref={fileInputRef}
668
- type="file"
669
- multiple
670
- onChange={handleFileSelect}
671
- />
672
- <button onClick={uploadFiles} disabled={uploading || files.length === 0}>
673
- {uploading ? "Uploading..." : `Upload ${files.length} file(s)`}
674
- </button>
675
- </div>
676
- )
677
- }
678
- ```
679
-
680
- ---
681
-
682
- ## Functions Service (Serverless)
683
-
684
- ### Execute Function (Sync)
685
-
686
- ```typescript
687
- import { Functions } from '@taruvi/sdk'
688
-
689
- const functions = new Functions(taruviClient)
690
-
691
- const result = await functions.execute("my-function", {
692
- async: false,
693
- params: {
694
- key1: "value1",
695
- key2: 123
696
- }
697
- })
698
-
699
- console.log(result.data) // Function response
700
- ```
701
-
702
- ### Execute Function (Async)
703
-
704
- ```typescript
705
- const functions = new Functions(taruviClient)
706
-
707
- const result = await functions.execute("long-running-task", {
708
- async: true,
709
- params: { data: "value" }
710
- })
711
-
712
- console.log(result.invocation.invocation_id) // Track async execution
713
- console.log(result.invocation.celery_task_id)
714
- console.log(result.invocation.status)
715
- ```
716
-
717
- ### Complete Function Executor Example
718
-
719
- ```typescript
720
- import { useState } from 'react'
721
- import { Functions } from '@taruvi/sdk'
722
-
723
- export default function FunctionExecutor({ taruviClient }) {
724
- const [functionSlug, setFunctionSlug] = useState("")
725
- const [params, setParams] = useState({})
726
- const [isAsync, setIsAsync] = useState(false)
727
- const [result, setResult] = useState(null)
728
- const [loading, setLoading] = useState(false)
729
-
730
- const executeFunction = async () => {
731
- setLoading(true)
732
- try {
733
- const functions = new Functions(taruviClient)
734
- const response = await functions.execute(functionSlug, {
735
- async: isAsync,
736
- params: params
737
- })
738
- setResult(response)
739
- } catch (error) {
740
- console.error(error)
741
- } finally {
742
- setLoading(false)
743
- }
744
- }
745
-
746
- return (
747
- <div>
748
- <input
749
- placeholder="Function slug"
750
- value={functionSlug}
751
- onChange={(e) => setFunctionSlug(e.target.value)}
752
- />
753
- <label>
754
- <input
755
- type="checkbox"
756
- checked={isAsync}
757
- onChange={(e) => setIsAsync(e.target.checked)}
758
- />
759
- Async
760
- </label>
761
- <button onClick={executeFunction} disabled={loading}>
762
- Execute
763
- </button>
764
- {result && <pre>{JSON.stringify(result, null, 2)}</pre>}
765
- </div>
766
- )
767
- }
768
- ```
769
-
770
- ---
771
-
772
- ## Analytics Service
773
-
774
- ### Execute Analytics Query
775
-
776
- ```typescript
777
- import { Analytics } from '@taruvi/sdk'
778
-
779
- const analytics = new Analytics(taruviClient)
780
-
781
- const result = await analytics.execute("monthly-sales-report", {
782
- params: {
783
- start_date: "2024-01-01",
784
- end_date: "2024-12-31"
785
- }
786
- })
787
-
788
- console.log(result.data) // Analytics query result
789
- ```
790
-
791
- ### Execute with Typed Response
792
-
793
- ```typescript
794
- interface SalesData {
795
- total_sales: number
796
- orders_count: number
797
- average_order_value: number
798
- }
799
-
800
- const analytics = new Analytics(taruviClient)
801
-
802
- const result = await analytics.execute<SalesData>("sales-summary", {
803
- params: { period: "monthly" }
804
- })
805
-
806
- console.log(result.data?.total_sales)
807
- console.log(result.data?.orders_count)
808
- ```
809
-
810
- ### Complete Analytics Dashboard Example
811
-
812
- ```typescript
813
- import { useEffect, useState } from 'react'
814
- import { Analytics } from '@taruvi/sdk'
815
-
816
- export default function AnalyticsDashboard({ taruviClient }) {
817
- const [metrics, setMetrics] = useState(null)
818
- const [loading, setLoading] = useState(true)
819
-
820
- useEffect(() => {
821
- const fetchMetrics = async () => {
822
- try {
823
- const analytics = new Analytics(taruviClient)
824
- const result = await analytics.execute("dashboard-metrics", {
825
- params: {
826
- date_range: "last_30_days"
827
- }
828
- })
829
- setMetrics(result.data)
830
- } catch (error) {
831
- console.error("Failed to fetch analytics:", error)
832
- } finally {
833
- setLoading(false)
834
- }
835
- }
836
- fetchMetrics()
837
- }, [])
838
-
839
- if (loading) return <div>Loading analytics...</div>
840
-
841
- return (
842
- <div>
843
- <h2>Dashboard Metrics</h2>
844
- <pre>{JSON.stringify(metrics, null, 2)}</pre>
845
- </div>
846
- )
847
- }
848
- ```
849
-
850
- ---
851
-
852
- ## Settings Service
853
-
854
- ### Get Site Settings
855
-
856
- ```typescript
857
- import { Settings } from '@taruvi/sdk'
858
-
859
- const settings = new Settings(taruviClient)
860
- const config = await settings.get()
861
-
862
- console.log(config) // Site configuration object
863
- ```
864
-
865
- ---
866
-
867
- ## Secrets Service
868
-
869
- ### List Secrets
870
-
871
- ```typescript
872
- import { Secrets } from '@taruvi/sdk'
873
-
874
- const secrets = new Secrets(taruviClient)
875
- const result = await secrets.list().execute()
876
-
877
- console.log(result.items) // Array of secrets
878
- ```
879
-
880
- ### Get Secret
881
-
882
- ```typescript
883
- const secrets = new Secrets(taruviClient)
884
- const secret = await secrets.get("MY_SECRET_KEY").execute()
885
-
886
- console.log(secret) // Secret object with value
887
- ```
888
-
889
- ### Update Secret
43
+ ## Documentation
890
44
 
891
- ```typescript
892
- const secrets = new Secrets(taruviClient)
893
-
894
- await secrets.update("MY_SECRET", {
895
- value: "my-secret-value"
896
- }).execute()
897
- ```
898
-
899
- ---
900
-
901
- ## Policy Service (Resource Permissions)
902
-
903
- ### Check Resource Permissions
904
-
905
- ```typescript
906
- import { Policy } from '@taruvi/sdk'
907
-
908
- const policy = new Policy(taruviClient)
909
-
910
- // Check permissions for multiple resources
911
- const result = await policy.checkResource([
912
- {
913
- entityType: "crm",
914
- tableName: "accounts",
915
- recordId: "record-123",
916
- attributes: { owner_id: "user-456" },
917
- actions: ["read", "update"]
918
- },
919
- {
920
- entityType: "docs",
921
- tableName: "documents",
922
- recordId: "doc-789",
923
- attributes: {},
924
- actions: ["delete"]
925
- }
926
- ])
927
- ```
928
-
929
- ### Complete Permission Check Example
930
-
931
- ```typescript
932
- import { useState, useEffect } from 'react'
933
- import { Policy } from '@taruvi/sdk'
934
-
935
- export default function ResourceGuard({ taruviClient, children, resource }) {
936
- const [allowed, setAllowed] = useState(false)
937
- const [loading, setLoading] = useState(true)
938
-
939
- useEffect(() => {
940
- const checkPermission = async () => {
941
- try {
942
- const policy = new Policy(taruviClient)
943
- const result = await policy.checkResource([
944
- {
945
- entityType: resource.entityType,
946
- tableName: resource.table,
947
- recordId: resource.id,
948
- attributes: resource.attributes || {},
949
- actions: ["read"]
950
- }
951
- ])
952
- setAllowed(result.allowed)
953
- } catch (error) {
954
- console.error("Permission check failed:", error)
955
- setAllowed(false)
956
- } finally {
957
- setLoading(false)
958
- }
959
- }
960
- checkPermission()
961
- }, [resource])
962
-
963
- if (loading) return <div>Checking permissions...</div>
964
- if (!allowed) return <div>Access denied</div>
965
- return children
966
- }
967
- ```
968
-
969
- ---
970
-
971
- ## App Service
972
-
973
- ### Get App Roles
974
-
975
- ```typescript
976
- import { App } from '@taruvi/sdk'
977
-
978
- const app = new App(taruviClient)
979
- const roles = await app.roles().execute()
45
+ Full guides live in **[docs/](docs/README.md)**:
980
46
 
981
- console.log(roles) // Array of role objects with id, name, permissions
982
- ```
983
-
984
- ### Complete Roles List Example
985
-
986
- ```typescript
987
- import { useEffect, useState } from 'react'
988
- import { App } from '@taruvi/sdk'
989
-
990
- export default function RolesList({ taruviClient }) {
991
- const [roles, setRoles] = useState([])
992
- const [loading, setLoading] = useState(true)
993
-
994
- useEffect(() => {
995
- const fetchRoles = async () => {
996
- try {
997
- const app = new App(taruviClient)
998
- const response = await app.roles().execute()
999
- setRoles(response.data || [])
1000
- } catch (error) {
1001
- console.error("Failed to fetch roles:", error)
1002
- } finally {
1003
- setLoading(false)
1004
- }
1005
- }
1006
- fetchRoles()
1007
- }, [])
1008
-
1009
- if (loading) return <div>Loading roles...</div>
1010
-
1011
- return (
1012
- <ul>
1013
- {roles.map(role => (
1014
- <li key={role.id}>
1015
- <strong>{role.name}</strong>
1016
- <span>{role.permissions?.join(", ")}</span>
1017
- </li>
1018
- ))}
1019
- </ul>
1020
- )
1021
- }
1022
- ```
1023
-
1024
- ---
1025
-
1026
- ## Common Patterns
1027
-
1028
- ### Loading States
47
+ | Guide | Topic |
48
+ |-------|--------|
49
+ | [Introduction](docs/01-introduction.md) | Purpose, setup, DI, backend-handled login flow |
50
+ | [Builder pattern](docs/02-builder-pattern.md) | Immutable queries and execution |
51
+ | [Architecture](docs/03-architecture.md) | `lib` vs `lib-internal`, request flow |
52
+ | [Clients](docs/04-clients.md) | What each service does |
53
+ | [API reference](docs/05-api-reference.md) | All public methods |
54
+ | [Examples](docs/06-examples.md) | Chaining patterns and workflows |
55
+ | [Advanced & troubleshooting](docs/07-advanced-topics.md) | Typing, filters, CORS, packaging |
56
+ | [Releases & branches](docs/08-releases-and-branches.md) | Stable vs beta, CI/CD publish workflow |
1029
57
 
1030
- ```typescript
1031
- const [data, setData] = useState(null)
1032
- const [loading, setLoading] = useState(true)
1033
- const [error, setError] = useState(null)
1034
-
1035
- useEffect(() => {
1036
- const fetchData = async () => {
1037
- setLoading(true)
1038
- try {
1039
- const db = new Database(taruviClient)
1040
- const response = await db.from("table").execute()
1041
- setData(response.data)
1042
- } catch (err) {
1043
- setError(err.message)
1044
- } finally {
1045
- setLoading(false)
1046
- }
1047
- }
1048
- fetchData()
1049
- }, [])
1050
-
1051
- if (loading) return <div>Loading...</div>
1052
- if (error) return <div>Error: {error}</div>
1053
- return <div>{/* Render data */}</div>
1054
- ```
1055
-
1056
- ### Error Handling
1057
-
1058
- ```typescript
1059
- try {
1060
- const user = new User(taruviClient)
1061
- await user.createUser(data)
1062
- } catch (error) {
1063
- if (error.response?.status === 400) {
1064
- console.error("Validation error:", error.response.data)
1065
- } else if (error.response?.status === 401) {
1066
- console.error("Unauthorized")
1067
- } else {
1068
- console.error("Unknown error:", error.message)
1069
- }
1070
- }
1071
- ```
1072
-
1073
- ### Refresh Data After Mutation
58
+ ## Services at a glance
1074
59
 
1075
- ```typescript
1076
- const [items, setItems] = useState([])
1077
-
1078
- const fetchItems = async () => {
1079
- const db = new Database(taruviClient)
1080
- const response = await db.from("items").execute()
1081
- setItems(response.data || [])
1082
- }
60
+ | Client | Use for |
61
+ |--------|---------|
62
+ | `Database` | Table CRUD, filters, pagination, graph/edges |
63
+ | `Storage` | Bucket files: list, upload, download, delete |
64
+ | `Auth` | Browser login/signup/logout, session token |
65
+ | `User` | User admin, roles, preferences |
66
+ | `Functions` | Invoke serverless functions |
67
+ | `Analytics` | Run predefined analytics queries |
68
+ | `Settings` | Site metadata, user attribute schema |
69
+ | `Secrets` | Read secret values |
70
+ | `Policy` | Permission checks |
71
+ | `App` | App roles and settings |
1083
72
 
1084
- const createItem = async (data) => {
1085
- const db = new Database(taruviClient)
1086
- await db.from("items").create(data).execute()
1087
- await fetchItems() // Refresh list
1088
- }
73
+ ## What's included
1089
74
 
1090
- const deleteItem = async (id) => {
1091
- const db = new Database(taruviClient)
1092
- await db.from("items").delete(id).execute()
1093
- await fetchItems() // Refresh list
1094
- }
75
+ - **Immutable builder pattern** for `Database`, `Storage`, `App`, and `Secrets.get()` each chain step returns a new instance so parallel queries never overwrite each other's URLs or filters.
76
+ - **Session authentication** via `X-Session-Token`; automatic token extraction from URL hash after OAuth redirect in the browser.
77
+ - **Typed errors** — `AuthError`, `NotFoundError`, `ValidationError`, and others exported from the package.
1095
78
 
1096
- const updateItem = async (id, data) => {
1097
- const db = new Database(taruviClient)
1098
- await db.from("items").get(id).update(data).execute()
1099
- await fetchItems() // Refresh list
1100
- }
1101
- ```
79
+ ## Development
1102
80
 
1103
- ---
1104
-
1105
- ## TypeScript Types
1106
-
1107
- ### Import Types
1108
-
1109
- ```typescript
1110
- import type {
1111
- TaruviConfig,
1112
- AuthTokens,
1113
- UserCreateRequest,
1114
- UserResponse,
1115
- UserDataResponse,
1116
- FunctionRequest,
1117
- FunctionResponse,
1118
- FunctionInvocation,
1119
- DatabaseRequest,
1120
- DatabaseResponse,
1121
- DatabaseFilters,
1122
- StorageRequest,
1123
- StorageUpdateRequest,
1124
- StorageResponse,
1125
- StorageFilters,
1126
- SettingsResponse,
1127
- SecretRequest,
1128
- SecretResponse,
1129
- Principal,
1130
- Resource,
1131
- Resources,
1132
- RoleResponse,
1133
- AnalyticsRequest,
1134
- AnalyticsResponse
1135
- } from '@taruvi/sdk'
1136
- ```
1137
-
1138
- ### Type Usage
1139
-
1140
- ```typescript
1141
- const config: TaruviConfig = {
1142
- apiKey: "key",
1143
- appSlug: "app",
1144
- apiUrl: "https://api.taruvi.cloud",
1145
- deskUrl: "https://desk.taruvi.cloud", // optional
1146
- token: "existing-token" // optional
1147
- }
1148
-
1149
- const userData: UserCreateRequest = {
1150
- username: "john",
1151
- email: "john@example.com",
1152
- password: "pass123",
1153
- confirm_password: "pass123",
1154
- first_name: "John",
1155
- last_name: "Doe",
1156
- is_active: true,
1157
- is_staff: false,
1158
- attributes: ""
1159
- }
1160
-
1161
- // Database filters with operators
1162
- const dbFilters: DatabaseFilters = {
1163
- page: 1,
1164
- pageSize: 20,
1165
- ordering: "-created_at",
1166
- status: "active",
1167
- age__gte: 18,
1168
- name__icontains: "john"
1169
- }
1170
-
1171
- // Storage filters with comprehensive options
1172
- const storageFilters: StorageFilters = {
1173
- page: 1,
1174
- pageSize: 50,
1175
- search: "invoice",
1176
- visibility: "public",
1177
- mimetype_category: "document",
1178
- size__gte: 1024,
1179
- size__lte: 10485760,
1180
- created_at__gte: "2024-01-01",
1181
- ordering: "-created_at",
1182
- created_by_me: true
1183
- }
1184
-
1185
- // Policy types for permission checking
1186
- const principal: Principal = {
1187
- id: "user-123",
1188
- roles: ["admin", "editor"],
1189
- attr: { department: "engineering" }
1190
- }
1191
-
1192
- const resources: Resources = [
1193
- {
1194
- entityType: "crm",
1195
- tableName: "accounts",
1196
- recordId: "acc-456",
1197
- attributes: { owner_id: "user-123" },
1198
- actions: ["read", "update", "delete"]
1199
- }
1200
- ]
1201
- ```
1202
-
1203
- ---
1204
-
1205
- ## Filter Operators Reference
1206
-
1207
- ### Database Filter Operators (Django-style)
1208
-
1209
- The Database service supports Django-style field lookups:
1210
-
1211
- | Operator | Description | Example |
1212
- |----------|-------------|---------|
1213
- | `field` | Exact match | `{ status: "active" }` |
1214
- | `field__gte` | Greater than or equal | `{ age__gte: 18 }` |
1215
- | `field__gt` | Greater than | `{ age__gt: 17 }` |
1216
- | `field__lte` | Less than or equal | `{ age__lte: 65 }` |
1217
- | `field__lt` | Less than | `{ age__lt: 66 }` |
1218
- | `field__icontains` | Case-insensitive contains | `{ name__icontains: "john" }` |
1219
- | `field__contains` | Case-sensitive contains | `{ name__contains: "John" }` |
1220
- | `field__istartswith` | Case-insensitive starts with | `{ email__istartswith: "admin" }` |
1221
- | `field__startswith` | Case-sensitive starts with | `{ code__startswith: "PRE" }` |
1222
- | `field__iendswith` | Case-insensitive ends with | `{ domain__iendswith: ".com" }` |
1223
- | `field__endswith` | Case-sensitive ends with | `{ filename__endswith: ".pdf" }` |
1224
- | `field__in` | Value in list | `{ status__in: ["active", "pending"] }` |
1225
- | `field__isnull` | Is null check | `{ deleted_at__isnull: true }` |
1226
- | `ordering` | Sort results | `{ ordering: "-created_at" }` (- for desc) |
1227
- | `page` | Page number | `{ page: 1 }` |
1228
- | `pageSize` | Items per page | `{ pageSize: 20 }` |
1229
-
1230
- ### Populate (Eager Loading)
1231
-
1232
- Use the `populate()` method to eager load related records:
1233
-
1234
- ```typescript
1235
- // Populate accepts an array of relation field names
1236
- db.from("orders").populate(["customer", "items"]).execute()
1237
-
1238
- // This adds ?populate=customer,items to the query string
1239
- ```
1240
-
1241
- | Parameter | Type | Description |
1242
- |-----------|------|-------------|
1243
- | `populate` | `string[]` | Array of relation field names to eager load |
1244
-
1245
- ### Storage Filter Options
1246
-
1247
- The Storage service supports these specialized filters:
1248
-
1249
- | Category | Filters | Description |
1250
- |----------|---------|-------------|
1251
- | **Size** | `size__gte`, `size__lte`, `size__gt`, `size__lt`, `min_size`, `max_size` | Filter by file size in bytes |
1252
- | **Dates** | `created_at__gte`, `created_at__lte`, `created_after`, `created_before`, `updated_at__gte`, `updated_at__lte` | Filter by dates (ISO 8601 format) |
1253
- | **Search** | `search`, `filename__icontains`, `prefix`, `file`, `file__icontains`, `file__startswith`, `file__istartswith`, `metadata_search` | Search for files |
1254
- | **MIME Type** | `mimetype`, `mimetype__in`, `mimetype_category` | Filter by file type (document, image, video, audio, etc.) |
1255
- | **Visibility** | `visibility` | Filter by public/private visibility |
1256
- | **User** | `created_by_me`, `modified_by_me`, `created_by__username`, `created_by__username__icontains` | Filter by user |
1257
- | **Pagination** | `page`, `pageSize` | Paginate results |
1258
- | **Sorting** | `ordering` | Sort results (e.g., "-created_at") |
1259
-
1260
- ---
1261
-
1262
- ## Quick Reference
1263
-
1264
- | Service | Import | Purpose |
1265
- |---------|--------|---------|
1266
- | `Client` | `import { Client }` | Main SDK client |
1267
- | `Auth` | `import { Auth }` | Authentication |
1268
- | `User` | `import { User }` | User management |
1269
- | `Database` | `import { Database }` | App data CRUD |
1270
- | `Storage` | `import { Storage }` | File management |
1271
- | `Functions` | `import { Functions }` | Serverless functions |
1272
- | `Settings` | `import { Settings }` | Site configuration |
1273
- | `Secrets` | `import { Secrets }` | Sensitive data |
1274
- | `Policy` | `import { Policy }` | Resource permissions |
1275
- | `App` | `import { App }` | App roles & config |
1276
- | `Analytics` | `import { Analytics }` | Analytics queries |
1277
-
1278
- ---
1279
-
1280
- ## Chaining Pattern
1281
-
1282
- All query-building services use method chaining:
1283
-
1284
- ```typescript
1285
- // Database
1286
- const db = new Database(taruviClient)
1287
- await db.from("table").get("id").update(data).execute()
1288
- await db.from("table").filter({ status: "active" }).execute()
1289
- await db.from("table").filter({ page: 1 }).populate(["related_field"]).execute()
1290
- await db.from("table").create({ name: "New" }).execute()
1291
-
1292
- // Storage
1293
- const storage = new Storage(taruviClient)
1294
- await storage.from("bucket").delete(["path/to/file.pdf"]).execute()
1295
- await storage.from("bucket").filter({ search: "query" }).execute()
1296
- await storage.from("bucket").download("path/to/file.pdf").execute()
81
+ ```bash
82
+ npm run build # TypeScript compile
83
+ npm test # Vitest unit tests
1297
84
  ```
1298
85
 
1299
- **Always call `.execute()` at the end to run the query!**
86
+ ## Additional resources
1300
87
 
1301
- ---
1302
-
1303
- ## Environment Variables
1304
-
1305
- ```env
1306
- VITE_TARUVI_API_KEY=your-api-key
1307
- VITE_TARUVI_APP_SLUG=your-app
1308
- VITE_TARUVI_API_URL=https://taruvi-site.taruvi.cloud
1309
- ```
1310
-
1311
- ```typescript
1312
- const client = new Client({
1313
- apiKey: import.meta.env.VITE_TARUVI_API_KEY,
1314
- appSlug: import.meta.env.VITE_TARUVI_APP_SLUG,
1315
- apiUrl: import.meta.env.VITE_TARUVI_API_URL
1316
- })
1317
- ```
88
+ - [SDK design context](SDK_DESIGN_CONTEXT.md) — backend API contract notes (SDK ↔ API mapping)
1318
89
 
1319
- ---
90
+ ## Author
1320
91
 
1321
- **Generated from production code examples • Last updated: 2026-01-12**
92
+ Curran C Doddabele · EOX Vantage