@taruvi/sdk 1.0.9 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -12,7 +12,10 @@ npm install @taruvi-io/sdk
|
|
|
12
12
|
|
|
13
13
|
Recent updates to the SDK:
|
|
14
14
|
|
|
15
|
-
- **
|
|
15
|
+
- **Policy Service**: New service for checking resource-level permissions with `checkResource()` method. Supports batch resource checking with principals, roles, and attributes.
|
|
16
|
+
- **App Service**: New service to retrieve app roles with `roles()` method.
|
|
17
|
+
- **User Types**: Added `UserList`, `UserApp`, and `UserAppsResponse` types for user listing and app associations.
|
|
18
|
+
- **Auth Service**: Web UI Flow with `login()`, `signup()`, `logout()` methods that redirect to backend pages. Token refresh with rotation support, `getCurrentUser()` for JWT decoding.
|
|
16
19
|
- **Database Service**: Added `create()` method for creating records. Comprehensive filter support with Django-style operators (`__gte`, `__lte`, `__icontains`, etc.).
|
|
17
20
|
- **Storage Service**: Added `download()` method. Enhanced filter support with size, date, MIME type, visibility filters. `delete()` now accepts array of paths for bulk deletion.
|
|
18
21
|
- **Client**: Automatic token extraction from URL hash after OAuth callback - no manual token handling needed.
|
|
@@ -749,6 +752,151 @@ await secrets.update("MY_SECRET", {
|
|
|
749
752
|
|
|
750
753
|
---
|
|
751
754
|
|
|
755
|
+
## Policy Service (Resource Permissions)
|
|
756
|
+
|
|
757
|
+
### Check Resource Permissions
|
|
758
|
+
|
|
759
|
+
```typescript
|
|
760
|
+
import { Policy } from '@taruvi-io/sdk'
|
|
761
|
+
|
|
762
|
+
const policy = new Policy(taruviClient)
|
|
763
|
+
|
|
764
|
+
// Check permissions for multiple resources
|
|
765
|
+
const result = await policy.checkResource([
|
|
766
|
+
{
|
|
767
|
+
tableName: "accounts",
|
|
768
|
+
recordId: "record-123",
|
|
769
|
+
attributes: { owner_id: "user-456" },
|
|
770
|
+
actions: ["read", "update"]
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
tableName: "documents",
|
|
774
|
+
recordId: "doc-789",
|
|
775
|
+
attributes: {},
|
|
776
|
+
actions: ["delete"]
|
|
777
|
+
}
|
|
778
|
+
])
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
### Check with Principal Override
|
|
782
|
+
|
|
783
|
+
```typescript
|
|
784
|
+
const policy = new Policy(taruviClient)
|
|
785
|
+
|
|
786
|
+
// Check permissions for a specific principal
|
|
787
|
+
const result = await policy.checkResource(
|
|
788
|
+
[
|
|
789
|
+
{
|
|
790
|
+
tableName: "accounts",
|
|
791
|
+
recordId: "record-123",
|
|
792
|
+
attributes: {},
|
|
793
|
+
actions: ["read"]
|
|
794
|
+
}
|
|
795
|
+
],
|
|
796
|
+
{
|
|
797
|
+
id: "user-123",
|
|
798
|
+
roles: ["admin", "editor"],
|
|
799
|
+
attr: { department: "sales" }
|
|
800
|
+
}
|
|
801
|
+
)
|
|
802
|
+
```
|
|
803
|
+
|
|
804
|
+
### Complete Permission Check Example
|
|
805
|
+
|
|
806
|
+
```typescript
|
|
807
|
+
import { useState } from 'react'
|
|
808
|
+
import { Policy } from '@taruvi-io/sdk'
|
|
809
|
+
|
|
810
|
+
export default function ResourceGuard({ taruviClient, children, resource }) {
|
|
811
|
+
const [allowed, setAllowed] = useState(false)
|
|
812
|
+
const [loading, setLoading] = useState(true)
|
|
813
|
+
|
|
814
|
+
useEffect(() => {
|
|
815
|
+
const checkPermission = async () => {
|
|
816
|
+
try {
|
|
817
|
+
const policy = new Policy(taruviClient)
|
|
818
|
+
const result = await policy.checkResource([
|
|
819
|
+
{
|
|
820
|
+
tableName: resource.table,
|
|
821
|
+
recordId: resource.id,
|
|
822
|
+
attributes: resource.attributes || {},
|
|
823
|
+
actions: ["read"]
|
|
824
|
+
}
|
|
825
|
+
])
|
|
826
|
+
setAllowed(result.allowed)
|
|
827
|
+
} catch (error) {
|
|
828
|
+
console.error("Permission check failed:", error)
|
|
829
|
+
setAllowed(false)
|
|
830
|
+
} finally {
|
|
831
|
+
setLoading(false)
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
checkPermission()
|
|
835
|
+
}, [resource])
|
|
836
|
+
|
|
837
|
+
if (loading) return <div>Checking permissions...</div>
|
|
838
|
+
if (!allowed) return <div>Access denied</div>
|
|
839
|
+
return children
|
|
840
|
+
}
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
---
|
|
844
|
+
|
|
845
|
+
## App Service
|
|
846
|
+
|
|
847
|
+
### Get App Roles
|
|
848
|
+
|
|
849
|
+
```typescript
|
|
850
|
+
import { App } from '@taruvi-io/sdk'
|
|
851
|
+
|
|
852
|
+
const app = new App(taruviClient)
|
|
853
|
+
const roles = await app.roles().execute()
|
|
854
|
+
|
|
855
|
+
console.log(roles) // Array of role objects with id, name, permissions
|
|
856
|
+
```
|
|
857
|
+
|
|
858
|
+
### Complete Roles List Example
|
|
859
|
+
|
|
860
|
+
```typescript
|
|
861
|
+
import { useEffect, useState } from 'react'
|
|
862
|
+
import { App } from '@taruvi-io/sdk'
|
|
863
|
+
|
|
864
|
+
export default function RolesList({ taruviClient }) {
|
|
865
|
+
const [roles, setRoles] = useState([])
|
|
866
|
+
const [loading, setLoading] = useState(true)
|
|
867
|
+
|
|
868
|
+
useEffect(() => {
|
|
869
|
+
const fetchRoles = async () => {
|
|
870
|
+
try {
|
|
871
|
+
const app = new App(taruviClient)
|
|
872
|
+
const response = await app.roles().execute()
|
|
873
|
+
setRoles(response.data || [])
|
|
874
|
+
} catch (error) {
|
|
875
|
+
console.error("Failed to fetch roles:", error)
|
|
876
|
+
} finally {
|
|
877
|
+
setLoading(false)
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
fetchRoles()
|
|
881
|
+
}, [])
|
|
882
|
+
|
|
883
|
+
if (loading) return <div>Loading roles...</div>
|
|
884
|
+
|
|
885
|
+
return (
|
|
886
|
+
<ul>
|
|
887
|
+
{roles.map(role => (
|
|
888
|
+
<li key={role.id}>
|
|
889
|
+
<strong>{role.name}</strong>
|
|
890
|
+
<span>{role.permissions?.join(", ")}</span>
|
|
891
|
+
</li>
|
|
892
|
+
))}
|
|
893
|
+
</ul>
|
|
894
|
+
)
|
|
895
|
+
}
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
---
|
|
899
|
+
|
|
752
900
|
## Common Patterns
|
|
753
901
|
|
|
754
902
|
### Loading States
|
|
@@ -851,7 +999,11 @@ import type {
|
|
|
851
999
|
StorageFilters,
|
|
852
1000
|
SettingsResponse,
|
|
853
1001
|
SecretRequest,
|
|
854
|
-
SecretResponse
|
|
1002
|
+
SecretResponse,
|
|
1003
|
+
Principal,
|
|
1004
|
+
Resource,
|
|
1005
|
+
Resources,
|
|
1006
|
+
RoleResponse
|
|
855
1007
|
} from '@taruvi-io/sdk'
|
|
856
1008
|
```
|
|
857
1009
|
|
|
@@ -900,6 +1052,22 @@ const storageFilters: StorageFilters = {
|
|
|
900
1052
|
ordering: "-created_at",
|
|
901
1053
|
created_by_me: true
|
|
902
1054
|
}
|
|
1055
|
+
|
|
1056
|
+
// Policy types for permission checking
|
|
1057
|
+
const principal: Principal = {
|
|
1058
|
+
id: "user-123",
|
|
1059
|
+
roles: ["admin", "editor"],
|
|
1060
|
+
attr: { department: "engineering" }
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
const resources: Resources = [
|
|
1064
|
+
{
|
|
1065
|
+
tableName: "accounts",
|
|
1066
|
+
recordId: "acc-456",
|
|
1067
|
+
attributes: { owner_id: "user-123" },
|
|
1068
|
+
actions: ["read", "update", "delete"]
|
|
1069
|
+
}
|
|
1070
|
+
]
|
|
903
1071
|
```
|
|
904
1072
|
|
|
905
1073
|
---
|
|
@@ -958,6 +1126,8 @@ The Storage service supports these specialized filters:
|
|
|
958
1126
|
| `Functions` | `import { Functions }` | Serverless functions |
|
|
959
1127
|
| `Settings` | `import { Settings }` | Site configuration |
|
|
960
1128
|
| `Secrets` | `import { Secrets }` | Sensitive data |
|
|
1129
|
+
| `Policy` | `import { Policy }` | Resource permissions |
|
|
1130
|
+
| `App` | `import { App }` | App roles & config |
|
|
961
1131
|
|
|
962
1132
|
---
|
|
963
1133
|
|
|
@@ -1001,4 +1171,4 @@ const client = new Client({
|
|
|
1001
1171
|
|
|
1002
1172
|
---
|
|
1003
1173
|
|
|
1004
|
-
**Generated from production code examples • Last updated: 2025-12-
|
|
1174
|
+
**Generated from production code examples • Last updated: 2025-12-22**
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -9,11 +9,15 @@ export { Database } from "./lib/Database/DatabaseClient.js"
|
|
|
9
9
|
export { Settings } from "./lib/Settings/SettingsClient.js"
|
|
10
10
|
export { Functions } from "./lib/Function/FunctionsClient.js"
|
|
11
11
|
export { Secrets } from "./lib/Secrets/SecretsClient.js"
|
|
12
|
+
export { Policy } from "./lib/Policy/PolicyClient.js"
|
|
13
|
+
export { App } from "./lib/App/AppClient.js"
|
|
12
14
|
|
|
13
15
|
// Export types
|
|
14
16
|
export type { TaruviConfig, StorageFilters, DatabaseFilters } from "./types.js"
|
|
15
17
|
export type { AuthTokens } from "./lib-internal/token/TokenClient.js"
|
|
16
18
|
export type { UserCreateRequest, UserCreateResponse as UserResponse, UserDataResponse } from "./lib/user/types.js"
|
|
19
|
+
export type { Principal, Resource, Resources } from "./lib/Policy/types.js"
|
|
20
|
+
export type { RoleResponse } from "./lib/App/types.js"
|
|
17
21
|
export type { FunctionRequest, FunctionResponse, FunctionInvocation } from "./lib/Function/types.js"
|
|
18
22
|
export type { DatabaseRequest, DatabaseResponse } from "./lib/Database/types.js"
|
|
19
23
|
export type { StorageRequest, StorageUpdateRequest, StorageResponse } from "./lib/Storage/types.js"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Client } from "../../client.js"
|
|
2
|
+
import { PolicyRoutes } from "../../lib-internal/routes/PolicyRoutes.js"
|
|
3
|
+
import type { TaruviConfig } from "../../types.js"
|
|
4
|
+
import type { Principal, Resource, Resources } from "./types.js"
|
|
5
|
+
|
|
6
|
+
export class Policy {
|
|
7
|
+
private client: Client
|
|
8
|
+
private config: TaruviConfig
|
|
9
|
+
constructor(client: Client) {
|
|
10
|
+
this.client = client
|
|
11
|
+
this.config = this.client.getConfig()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async checkResource(resources: Resources, principal?: Principal) {
|
|
15
|
+
const url = PolicyRoutes.baseUrl(this.config.appSlug) + PolicyRoutes.checkResource
|
|
16
|
+
const body = JSON.stringify({
|
|
17
|
+
principal,
|
|
18
|
+
resources: resources.map(r => ({
|
|
19
|
+
resource: {
|
|
20
|
+
kind: `${this.config.appSlug}:${r.tableName}`,
|
|
21
|
+
id: r.recordId,
|
|
22
|
+
attr: r.attributes || {}
|
|
23
|
+
}
|
|
24
|
+
}))
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return await this.client.httpClient.post(url, body)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface Principal {
|
|
2
|
+
id: string
|
|
3
|
+
roles: string[]
|
|
4
|
+
attr: Record<string, unknown>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type Resource = {
|
|
8
|
+
kind: string
|
|
9
|
+
id: string
|
|
10
|
+
attr: Record<string, unknown>
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export type Resources = {
|
|
14
|
+
tableName: string
|
|
15
|
+
recordId: string
|
|
16
|
+
attributes: Record<string, unknown>
|
|
17
|
+
actions: string[]
|
|
18
|
+
}[]
|
|
19
|
+
|
|
20
|
+
export type ResourceCheckResponse = {
|
|
21
|
+
allowed: boolean
|
|
22
|
+
reason: string
|
|
23
|
+
}
|