@tenxyte/react 0.5.0 → 0.5.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.
- package/README.md +192 -0
- package/dist/index.cjs +188 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +171 -0
- package/dist/index.d.ts +171 -0
- package/dist/index.js +144 -0
- package/dist/index.js.map +1 -0
- package/package.json +3 -2
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# @tenxyte/react
|
|
2
|
+
|
|
3
|
+
React bindings for the [Tenxyte SDK](https://www.npmjs.com/package/@tenxyte/core). Provides reactive hooks that automatically re-render your components when authentication state changes.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @tenxyte/core @tenxyte/react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### 1. Create the client and wrap your app
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { TenxyteClient } from '@tenxyte/core';
|
|
17
|
+
import { TenxyteProvider } from '@tenxyte/react';
|
|
18
|
+
import App from './App';
|
|
19
|
+
|
|
20
|
+
const tx = new TenxyteClient({
|
|
21
|
+
baseUrl: 'https://api.example.com',
|
|
22
|
+
applicationId: 'your-app-id',
|
|
23
|
+
apiKey: 'your-api-key',
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
function Root() {
|
|
27
|
+
return (
|
|
28
|
+
<TenxyteProvider client={tx}>
|
|
29
|
+
<App />
|
|
30
|
+
</TenxyteProvider>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Use hooks in any component
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { useAuth, useUser, useRbac, useOrganization } from '@tenxyte/react';
|
|
39
|
+
|
|
40
|
+
function Dashboard() {
|
|
41
|
+
const { isAuthenticated, loading, logout } = useAuth();
|
|
42
|
+
const { user } = useUser();
|
|
43
|
+
const { hasRole } = useRbac();
|
|
44
|
+
|
|
45
|
+
if (loading) return <p>Loading...</p>;
|
|
46
|
+
if (!isAuthenticated) return <LoginPage />;
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div>
|
|
50
|
+
<p>Welcome, {user?.email}</p>
|
|
51
|
+
{hasRole('admin') && <AdminPanel />}
|
|
52
|
+
<button onClick={logout}>Logout</button>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Hooks
|
|
59
|
+
|
|
60
|
+
### `useAuth()`
|
|
61
|
+
|
|
62
|
+
Reactive authentication state and actions.
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
const {
|
|
66
|
+
isAuthenticated, // boolean — true if access token is valid and not expired
|
|
67
|
+
loading, // boolean — true while initial state loads from storage
|
|
68
|
+
accessToken, // string | null — raw JWT access token
|
|
69
|
+
loginWithEmail, // (data: { email, password, device_info?, totp_code? }) => Promise<void>
|
|
70
|
+
loginWithPhone, // (data: { phone_country_code, phone_number, password, device_info? }) => Promise<void>
|
|
71
|
+
logout, // () => Promise<void>
|
|
72
|
+
register, // (data) => Promise<void>
|
|
73
|
+
} = useAuth();
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Example — Login form:**
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
function LoginPage() {
|
|
80
|
+
const { loginWithEmail } = useAuth();
|
|
81
|
+
const [email, setEmail] = useState('');
|
|
82
|
+
const [password, setPassword] = useState('');
|
|
83
|
+
|
|
84
|
+
const handleSubmit = async (e: FormEvent) => {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
await loginWithEmail({ email, password });
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<form onSubmit={handleSubmit}>
|
|
91
|
+
<input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" />
|
|
92
|
+
<input value={password} onChange={(e) => setPassword(e.target.value)} type="password" />
|
|
93
|
+
<button type="submit">Sign In</button>
|
|
94
|
+
</form>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### `useUser()`
|
|
100
|
+
|
|
101
|
+
Decoded JWT user and profile management.
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
const {
|
|
105
|
+
user, // DecodedTenxyteToken | null — decoded JWT payload
|
|
106
|
+
loading, // boolean
|
|
107
|
+
getProfile, // () => Promise<UserProfile> — fetch full profile from API
|
|
108
|
+
updateProfile, // (data) => Promise<unknown>
|
|
109
|
+
} = useUser();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Example:**
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
function UserBadge() {
|
|
116
|
+
const { user, loading } = useUser();
|
|
117
|
+
if (loading || !user) return null;
|
|
118
|
+
return <span>{user.email}</span>;
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `useOrganization()`
|
|
123
|
+
|
|
124
|
+
Multi-tenant organization context (B2B).
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
const {
|
|
128
|
+
activeOrg, // string | null — current org slug
|
|
129
|
+
switchOrganization, // (slug: string) => void
|
|
130
|
+
clearOrganization, // () => void
|
|
131
|
+
} = useOrganization();
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Example:**
|
|
135
|
+
|
|
136
|
+
```tsx
|
|
137
|
+
function OrgSwitcher({ orgs }: { orgs: { slug: string; name: string }[] }) {
|
|
138
|
+
const { activeOrg, switchOrganization, clearOrganization } = useOrganization();
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<select
|
|
142
|
+
value={activeOrg ?? ''}
|
|
143
|
+
onChange={(e) =>
|
|
144
|
+
e.target.value ? switchOrganization(e.target.value) : clearOrganization()
|
|
145
|
+
}
|
|
146
|
+
>
|
|
147
|
+
<option value="">No organization</option>
|
|
148
|
+
{orgs.map((o) => (
|
|
149
|
+
<option key={o.slug} value={o.slug}>{o.name}</option>
|
|
150
|
+
))}
|
|
151
|
+
</select>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### `useRbac()`
|
|
157
|
+
|
|
158
|
+
Synchronous role and permission checks from the current JWT.
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
const {
|
|
162
|
+
hasRole, // (role: string) => boolean
|
|
163
|
+
hasPermission, // (permission: string) => boolean
|
|
164
|
+
hasAnyRole, // (roles: string[]) => boolean
|
|
165
|
+
hasAllRoles, // (roles: string[]) => boolean
|
|
166
|
+
} = useRbac();
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Example:**
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
function AdminPanel() {
|
|
173
|
+
const { hasRole } = useRbac();
|
|
174
|
+
if (!hasRole('admin')) return <p>Access denied</p>;
|
|
175
|
+
return <AdminDashboard />;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## How It Works
|
|
180
|
+
|
|
181
|
+
`TenxyteProvider` places the `TenxyteClient` instance into React context. Each hook subscribes to SDK events (`token:stored`, `token:refreshed`, `session:expired`) and triggers a re-render when the auth state changes. All state updates are automatic — no manual invalidation needed.
|
|
182
|
+
|
|
183
|
+
## Peer Dependencies
|
|
184
|
+
|
|
185
|
+
| Package | Version |
|
|
186
|
+
|---|---|
|
|
187
|
+
| `@tenxyte/core` | `^0.9.2` |
|
|
188
|
+
| `react` | `^18.0.0 \|\| ^19.0.0` |
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
TenxyteContext: () => TenxyteContext,
|
|
34
|
+
TenxyteProvider: () => TenxyteProvider,
|
|
35
|
+
useAuth: () => useAuth,
|
|
36
|
+
useOrganization: () => useOrganization,
|
|
37
|
+
useRbac: () => useRbac,
|
|
38
|
+
useTenxyteClient: () => useTenxyteClient,
|
|
39
|
+
useTenxyteState: () => useTenxyteState,
|
|
40
|
+
useUser: () => useUser
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(index_exports);
|
|
43
|
+
|
|
44
|
+
// src/context.tsx
|
|
45
|
+
var import_react = require("react");
|
|
46
|
+
var TenxyteContext = (0, import_react.createContext)(null);
|
|
47
|
+
function useTenxyteClient() {
|
|
48
|
+
const client = (0, import_react.useContext)(TenxyteContext);
|
|
49
|
+
if (!client) {
|
|
50
|
+
throw new Error(
|
|
51
|
+
"[@tenxyte/react] useTenxyteClient must be used within a <TenxyteProvider>. Wrap your app with <TenxyteProvider client={tx}>."
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
return client;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/provider.tsx
|
|
58
|
+
var import_react2 = __toESM(require("react"), 1);
|
|
59
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
60
|
+
function TenxyteProvider({ client, children }) {
|
|
61
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(TenxyteContext.Provider, { value: client, children });
|
|
62
|
+
}
|
|
63
|
+
function useTenxyteState() {
|
|
64
|
+
const client = import_react2.default.useContext(TenxyteContext);
|
|
65
|
+
if (!client) {
|
|
66
|
+
throw new Error("[@tenxyte/react] useTenxyteState must be used within a <TenxyteProvider>.");
|
|
67
|
+
}
|
|
68
|
+
const [state, setState] = (0, import_react2.useState)({
|
|
69
|
+
isAuthenticated: false,
|
|
70
|
+
user: null,
|
|
71
|
+
accessToken: null,
|
|
72
|
+
activeOrg: null,
|
|
73
|
+
isAgentMode: false
|
|
74
|
+
});
|
|
75
|
+
const [loading, setLoading] = (0, import_react2.useState)(true);
|
|
76
|
+
const refresh = (0, import_react2.useCallback)(async () => {
|
|
77
|
+
const snapshot = await client.getState();
|
|
78
|
+
setState(snapshot);
|
|
79
|
+
setLoading(false);
|
|
80
|
+
}, [client]);
|
|
81
|
+
(0, import_react2.useEffect)(() => {
|
|
82
|
+
refresh();
|
|
83
|
+
const unsubs = [
|
|
84
|
+
client.on("token:stored", () => {
|
|
85
|
+
refresh();
|
|
86
|
+
}),
|
|
87
|
+
client.on("token:refreshed", () => {
|
|
88
|
+
refresh();
|
|
89
|
+
}),
|
|
90
|
+
client.on("session:expired", () => {
|
|
91
|
+
refresh();
|
|
92
|
+
})
|
|
93
|
+
];
|
|
94
|
+
return () => {
|
|
95
|
+
unsubs.forEach((unsub) => unsub());
|
|
96
|
+
};
|
|
97
|
+
}, [client, refresh]);
|
|
98
|
+
return (0, import_react2.useMemo)(() => ({ ...state, loading }), [state, loading]);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/hooks.ts
|
|
102
|
+
var import_react3 = require("react");
|
|
103
|
+
function useAuth() {
|
|
104
|
+
const client = useTenxyteClient();
|
|
105
|
+
const { isAuthenticated, loading, accessToken } = useTenxyteState();
|
|
106
|
+
const loginWithEmail = (0, import_react3.useCallback)(
|
|
107
|
+
async (data) => {
|
|
108
|
+
await client.auth.loginWithEmail({ ...data, device_info: data.device_info ?? "" });
|
|
109
|
+
},
|
|
110
|
+
[client]
|
|
111
|
+
);
|
|
112
|
+
const loginWithPhone = (0, import_react3.useCallback)(
|
|
113
|
+
async (data) => {
|
|
114
|
+
await client.auth.loginWithPhone({ ...data, device_info: data.device_info ?? "" });
|
|
115
|
+
},
|
|
116
|
+
[client]
|
|
117
|
+
);
|
|
118
|
+
const logout = (0, import_react3.useCallback)(async () => {
|
|
119
|
+
await client.auth.logoutAll();
|
|
120
|
+
}, [client]);
|
|
121
|
+
const register = (0, import_react3.useCallback)(
|
|
122
|
+
async (data) => {
|
|
123
|
+
await client.auth.register(data);
|
|
124
|
+
},
|
|
125
|
+
[client]
|
|
126
|
+
);
|
|
127
|
+
return { isAuthenticated, loading, accessToken, loginWithEmail, loginWithPhone, logout, register };
|
|
128
|
+
}
|
|
129
|
+
function useUser() {
|
|
130
|
+
const client = useTenxyteClient();
|
|
131
|
+
const { user, loading } = useTenxyteState();
|
|
132
|
+
const getProfile = (0, import_react3.useCallback)(() => client.user.getProfile(), [client]);
|
|
133
|
+
const updateProfile = (0, import_react3.useCallback)(
|
|
134
|
+
(data) => client.user.updateProfile(data),
|
|
135
|
+
[client]
|
|
136
|
+
);
|
|
137
|
+
return { user, loading, getProfile, updateProfile };
|
|
138
|
+
}
|
|
139
|
+
function useOrganization() {
|
|
140
|
+
const client = useTenxyteClient();
|
|
141
|
+
const { activeOrg } = useTenxyteState();
|
|
142
|
+
const switchOrganization = (0, import_react3.useCallback)(
|
|
143
|
+
(slug) => {
|
|
144
|
+
client.b2b.switchOrganization(slug);
|
|
145
|
+
},
|
|
146
|
+
[client]
|
|
147
|
+
);
|
|
148
|
+
const clearOrganization = (0, import_react3.useCallback)(
|
|
149
|
+
() => {
|
|
150
|
+
client.b2b.clearOrganization();
|
|
151
|
+
},
|
|
152
|
+
[client]
|
|
153
|
+
);
|
|
154
|
+
return { activeOrg, switchOrganization, clearOrganization };
|
|
155
|
+
}
|
|
156
|
+
function useRbac() {
|
|
157
|
+
const client = useTenxyteClient();
|
|
158
|
+
const { accessToken } = useTenxyteState();
|
|
159
|
+
const hasRole = (0, import_react3.useCallback)(
|
|
160
|
+
(role) => client.rbac.hasRole(role, accessToken ?? void 0),
|
|
161
|
+
[client, accessToken]
|
|
162
|
+
);
|
|
163
|
+
const hasPermission = (0, import_react3.useCallback)(
|
|
164
|
+
(permission) => client.rbac.hasPermission(permission, accessToken ?? void 0),
|
|
165
|
+
[client, accessToken]
|
|
166
|
+
);
|
|
167
|
+
const hasAnyRole = (0, import_react3.useCallback)(
|
|
168
|
+
(roles) => client.rbac.hasAnyRole(roles, accessToken ?? void 0),
|
|
169
|
+
[client, accessToken]
|
|
170
|
+
);
|
|
171
|
+
const hasAllRoles = (0, import_react3.useCallback)(
|
|
172
|
+
(roles) => client.rbac.hasAllRoles(roles, accessToken ?? void 0),
|
|
173
|
+
[client, accessToken]
|
|
174
|
+
);
|
|
175
|
+
return { hasRole, hasPermission, hasAnyRole, hasAllRoles };
|
|
176
|
+
}
|
|
177
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
178
|
+
0 && (module.exports = {
|
|
179
|
+
TenxyteContext,
|
|
180
|
+
TenxyteProvider,
|
|
181
|
+
useAuth,
|
|
182
|
+
useOrganization,
|
|
183
|
+
useRbac,
|
|
184
|
+
useTenxyteClient,
|
|
185
|
+
useTenxyteState,
|
|
186
|
+
useUser
|
|
187
|
+
});
|
|
188
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/context.tsx","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["export { TenxyteContext, useTenxyteClient } from './context';\nexport { TenxyteProvider, useTenxyteState } from './provider';\nexport type { TenxyteProviderProps } from './provider';\nexport { useAuth, useUser, useOrganization, useRbac } from './hooks';\nexport type { UseAuthReturn, UseUserReturn, UseOrganizationReturn, UseRbacReturn } from './hooks';\n","import { createContext, useContext } from 'react';\nimport type { TenxyteClient } from '@tenxyte/core';\n\n/**\n * React context holding the TenxyteClient instance.\n * Must be provided via <TenxyteProvider>.\n */\nexport const TenxyteContext = createContext<TenxyteClient | null>(null);\n\n/**\n * Internal hook to access the TenxyteClient instance.\n * Throws if used outside of a <TenxyteProvider>.\n */\nexport function useTenxyteClient(): TenxyteClient {\n const client = useContext(TenxyteContext);\n if (!client) {\n throw new Error(\n '[@tenxyte/react] useTenxyteClient must be used within a <TenxyteProvider>. ' +\n 'Wrap your app with <TenxyteProvider client={tx}>.',\n );\n }\n return client;\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { TenxyteClient, TenxyteClientState } from '@tenxyte/core';\nimport { TenxyteContext } from './context';\n\nexport interface TenxyteProviderProps {\n /** The initialized TenxyteClient instance. */\n client: TenxyteClient;\n children: React.ReactNode;\n}\n\n/**\n * Provides the TenxyteClient to all descendant components and manages\n * reactive state synchronization via SDK events.\n *\n * @example\n * ```tsx\n * import { TenxyteClient } from '@tenxyte/core';\n * import { TenxyteProvider } from '@tenxyte/react';\n *\n * const tx = new TenxyteClient({ baseUrl: '...' });\n *\n * function App() {\n * return (\n * <TenxyteProvider client={tx}>\n * <MyApp />\n * </TenxyteProvider>\n * );\n * }\n * ```\n */\nexport function TenxyteProvider({ client, children }: TenxyteProviderProps): React.JSX.Element {\n return (\n <TenxyteContext.Provider value={client}>\n {children}\n </TenxyteContext.Provider>\n );\n}\n\n/**\n * Internal hook that subscribes to SDK events and returns a reactive state snapshot.\n * Re-renders consuming components whenever auth state changes.\n */\nexport function useTenxyteState(): TenxyteClientState & { loading: boolean } {\n const client = React.useContext(TenxyteContext);\n if (!client) {\n throw new Error('[@tenxyte/react] useTenxyteState must be used within a <TenxyteProvider>.');\n }\n\n const [state, setState] = useState<TenxyteClientState>({\n isAuthenticated: false,\n user: null,\n accessToken: null,\n activeOrg: null,\n isAgentMode: false,\n });\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n const snapshot = await client.getState();\n setState(snapshot);\n setLoading(false);\n }, [client]);\n\n useEffect(() => {\n // Initial state load\n refresh();\n\n // Subscribe to all state-changing events\n const unsubs = [\n client.on('token:stored', () => { refresh(); }),\n client.on('token:refreshed', () => { refresh(); }),\n client.on('session:expired', () => { refresh(); }),\n ];\n\n return () => {\n unsubs.forEach((unsub) => unsub());\n };\n }, [client, refresh]);\n\n return useMemo(() => ({ ...state, loading }), [state, loading]);\n}\n","import { useCallback } from 'react';\nimport type { DecodedTenxyteToken } from '@tenxyte/core';\nimport { useTenxyteClient } from './context';\nimport { useTenxyteState } from './provider';\n\n// ─── useAuth ───\n\nexport interface UseAuthReturn {\n /** Whether the user has a valid, non-expired access token. */\n isAuthenticated: boolean;\n /** Whether the initial state is still loading from storage. */\n loading: boolean;\n /** Raw access token string, or null. */\n accessToken: string | null;\n /** Login with email/password. Triggers re-render on success. */\n loginWithEmail: (data: { email: string; password: string; device_info?: string; totp_code?: string }) => Promise<void>;\n /** Login with phone/password. */\n loginWithPhone: (data: { phone_country_code: string; phone_number: string; password: string; device_info?: string }) => Promise<void>;\n /** Logout from all sessions. */\n logout: () => Promise<void>;\n /** Register a new account. */\n register: (data: Record<string, unknown>) => Promise<void>;\n}\n\n/**\n * Reactive authentication hook.\n * Automatically re-renders when the auth state changes (login, logout, refresh, expiry).\n *\n * @example\n * ```tsx\n * function LoginPage() {\n * const { isAuthenticated, loginWithEmail, logout, loading } = useAuth();\n *\n * if (loading) return <p>Loading...</p>;\n * if (isAuthenticated) return <button onClick={logout}>Logout</button>;\n *\n * return <button onClick={() => loginWithEmail({ email: '...', password: '...' })}>Login</button>;\n * }\n * ```\n */\nexport function useAuth(): UseAuthReturn {\n const client = useTenxyteClient();\n const { isAuthenticated, loading, accessToken } = useTenxyteState();\n\n const loginWithEmail = useCallback(\n async (data: { email: string; password: string; device_info?: string; totp_code?: string }) => {\n await client.auth.loginWithEmail({ ...data, device_info: data.device_info ?? '' });\n },\n [client],\n );\n\n const loginWithPhone = useCallback(\n async (data: { phone_country_code: string; phone_number: string; password: string; device_info?: string }) => {\n await client.auth.loginWithPhone({ ...data, device_info: data.device_info ?? '' });\n },\n [client],\n );\n\n const logout = useCallback(async () => {\n await client.auth.logoutAll();\n }, [client]);\n\n const register = useCallback(\n async (data: Record<string, unknown>) => {\n await client.auth.register(data as any);\n },\n [client],\n );\n\n return { isAuthenticated, loading, accessToken, loginWithEmail, loginWithPhone, logout, register };\n}\n\n// ─── useUser ───\n\nexport interface UseUserReturn {\n /** Decoded JWT payload of the current access token, or null. */\n user: DecodedTenxyteToken | null;\n /** Whether the initial state is still loading. */\n loading: boolean;\n /** Fetch the full user profile from the backend. */\n getProfile: () => ReturnType<typeof import('@tenxyte/core').TenxyteClient.prototype.user.getProfile>;\n /** Update the current user's profile. */\n updateProfile: (data: Record<string, unknown>) => Promise<unknown>;\n}\n\n/**\n * Reactive user hook.\n * Returns the decoded JWT user and convenience methods for profile management.\n *\n * @example\n * ```tsx\n * function UserBadge() {\n * const { user, loading } = useUser();\n * if (loading || !user) return null;\n * return <span>{user.email}</span>;\n * }\n * ```\n */\nexport function useUser(): UseUserReturn {\n const client = useTenxyteClient();\n const { user, loading } = useTenxyteState();\n\n const getProfile = useCallback(() => client.user.getProfile(), [client]);\n\n const updateProfile = useCallback(\n (data: Record<string, unknown>) => client.user.updateProfile(data),\n [client],\n );\n\n return { user, loading, getProfile, updateProfile };\n}\n\n// ─── useOrganization ───\n\nexport interface UseOrganizationReturn {\n /** Currently active organization slug, or null. */\n activeOrg: string | null;\n /** Switch the SDK to operate within an organization context. */\n switchOrganization: (slug: string) => void;\n /** Clear the organization context. */\n clearOrganization: () => void;\n}\n\n/**\n * Reactive organization context hook.\n * Returns the current org slug and methods to switch/clear context.\n *\n * @example\n * ```tsx\n * function OrgSwitcher({ orgs }) {\n * const { activeOrg, switchOrganization, clearOrganization } = useOrganization();\n * return (\n * <select value={activeOrg ?? ''} onChange={(e) =>\n * e.target.value ? switchOrganization(e.target.value) : clearOrganization()\n * }>\n * <option value=\"\">No org</option>\n * {orgs.map(o => <option key={o.slug} value={o.slug}>{o.name}</option>)}\n * </select>\n * );\n * }\n * ```\n */\nexport function useOrganization(): UseOrganizationReturn {\n const client = useTenxyteClient();\n const { activeOrg } = useTenxyteState();\n\n const switchOrganization = useCallback(\n (slug: string) => { client.b2b.switchOrganization(slug); },\n [client],\n );\n\n const clearOrganization = useCallback(\n () => { client.b2b.clearOrganization(); },\n [client],\n );\n\n return { activeOrg, switchOrganization, clearOrganization };\n}\n\n// ─── useRbac ───\n\nexport interface UseRbacReturn {\n /** Check if the current user has a specific role (synchronous JWT check). */\n hasRole: (role: string) => boolean;\n /** Check if the current user has a specific permission (synchronous JWT check). */\n hasPermission: (permission: string) => boolean;\n /** Check if the current user has any of the given roles. */\n hasAnyRole: (roles: string[]) => boolean;\n /** Check if the current user has all of the given roles. */\n hasAllRoles: (roles: string[]) => boolean;\n}\n\n/**\n * Reactive RBAC hook.\n * Provides synchronous role/permission checks based on the current JWT.\n *\n * @example\n * ```tsx\n * function AdminPanel() {\n * const { hasRole } = useRbac();\n * if (!hasRole('admin')) return <p>Access denied</p>;\n * return <AdminDashboard />;\n * }\n * ```\n */\nexport function useRbac(): UseRbacReturn {\n const client = useTenxyteClient();\n const { accessToken } = useTenxyteState();\n\n const hasRole = useCallback(\n (role: string) => client.rbac.hasRole(role, accessToken ?? undefined),\n [client, accessToken],\n );\n\n const hasPermission = useCallback(\n (permission: string) => client.rbac.hasPermission(permission, accessToken ?? undefined),\n [client, accessToken],\n );\n\n const hasAnyRole = useCallback(\n (roles: string[]) => client.rbac.hasAnyRole(roles, accessToken ?? undefined),\n [client, accessToken],\n );\n\n const hasAllRoles = useCallback(\n (roles: string[]) => client.rbac.hasAllRoles(roles, accessToken ?? undefined),\n [client, accessToken],\n );\n\n return { hasRole, hasPermission, hasAnyRole, hasAllRoles };\n}\n"],"mappings":"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","names":["import_react","React","import_react"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
import * as _tenxyte_core from '@tenxyte/core';
|
|
4
|
+
import { TenxyteClient, TenxyteClientState, DecodedTenxyteToken } from '@tenxyte/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* React context holding the TenxyteClient instance.
|
|
8
|
+
* Must be provided via <TenxyteProvider>.
|
|
9
|
+
*/
|
|
10
|
+
declare const TenxyteContext: React.Context<TenxyteClient | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Internal hook to access the TenxyteClient instance.
|
|
13
|
+
* Throws if used outside of a <TenxyteProvider>.
|
|
14
|
+
*/
|
|
15
|
+
declare function useTenxyteClient(): TenxyteClient;
|
|
16
|
+
|
|
17
|
+
interface TenxyteProviderProps {
|
|
18
|
+
/** The initialized TenxyteClient instance. */
|
|
19
|
+
client: TenxyteClient;
|
|
20
|
+
children: React__default.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Provides the TenxyteClient to all descendant components and manages
|
|
24
|
+
* reactive state synchronization via SDK events.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* import { TenxyteClient } from '@tenxyte/core';
|
|
29
|
+
* import { TenxyteProvider } from '@tenxyte/react';
|
|
30
|
+
*
|
|
31
|
+
* const tx = new TenxyteClient({ baseUrl: '...' });
|
|
32
|
+
*
|
|
33
|
+
* function App() {
|
|
34
|
+
* return (
|
|
35
|
+
* <TenxyteProvider client={tx}>
|
|
36
|
+
* <MyApp />
|
|
37
|
+
* </TenxyteProvider>
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare function TenxyteProvider({ client, children }: TenxyteProviderProps): React__default.JSX.Element;
|
|
43
|
+
/**
|
|
44
|
+
* Internal hook that subscribes to SDK events and returns a reactive state snapshot.
|
|
45
|
+
* Re-renders consuming components whenever auth state changes.
|
|
46
|
+
*/
|
|
47
|
+
declare function useTenxyteState(): TenxyteClientState & {
|
|
48
|
+
loading: boolean;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
interface UseAuthReturn {
|
|
52
|
+
/** Whether the user has a valid, non-expired access token. */
|
|
53
|
+
isAuthenticated: boolean;
|
|
54
|
+
/** Whether the initial state is still loading from storage. */
|
|
55
|
+
loading: boolean;
|
|
56
|
+
/** Raw access token string, or null. */
|
|
57
|
+
accessToken: string | null;
|
|
58
|
+
/** Login with email/password. Triggers re-render on success. */
|
|
59
|
+
loginWithEmail: (data: {
|
|
60
|
+
email: string;
|
|
61
|
+
password: string;
|
|
62
|
+
device_info?: string;
|
|
63
|
+
totp_code?: string;
|
|
64
|
+
}) => Promise<void>;
|
|
65
|
+
/** Login with phone/password. */
|
|
66
|
+
loginWithPhone: (data: {
|
|
67
|
+
phone_country_code: string;
|
|
68
|
+
phone_number: string;
|
|
69
|
+
password: string;
|
|
70
|
+
device_info?: string;
|
|
71
|
+
}) => Promise<void>;
|
|
72
|
+
/** Logout from all sessions. */
|
|
73
|
+
logout: () => Promise<void>;
|
|
74
|
+
/** Register a new account. */
|
|
75
|
+
register: (data: Record<string, unknown>) => Promise<void>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Reactive authentication hook.
|
|
79
|
+
* Automatically re-renders when the auth state changes (login, logout, refresh, expiry).
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```tsx
|
|
83
|
+
* function LoginPage() {
|
|
84
|
+
* const { isAuthenticated, loginWithEmail, logout, loading } = useAuth();
|
|
85
|
+
*
|
|
86
|
+
* if (loading) return <p>Loading...</p>;
|
|
87
|
+
* if (isAuthenticated) return <button onClick={logout}>Logout</button>;
|
|
88
|
+
*
|
|
89
|
+
* return <button onClick={() => loginWithEmail({ email: '...', password: '...' })}>Login</button>;
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
declare function useAuth(): UseAuthReturn;
|
|
94
|
+
interface UseUserReturn {
|
|
95
|
+
/** Decoded JWT payload of the current access token, or null. */
|
|
96
|
+
user: DecodedTenxyteToken | null;
|
|
97
|
+
/** Whether the initial state is still loading. */
|
|
98
|
+
loading: boolean;
|
|
99
|
+
/** Fetch the full user profile from the backend. */
|
|
100
|
+
getProfile: () => ReturnType<typeof _tenxyte_core.TenxyteClient.prototype.user.getProfile>;
|
|
101
|
+
/** Update the current user's profile. */
|
|
102
|
+
updateProfile: (data: Record<string, unknown>) => Promise<unknown>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Reactive user hook.
|
|
106
|
+
* Returns the decoded JWT user and convenience methods for profile management.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```tsx
|
|
110
|
+
* function UserBadge() {
|
|
111
|
+
* const { user, loading } = useUser();
|
|
112
|
+
* if (loading || !user) return null;
|
|
113
|
+
* return <span>{user.email}</span>;
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare function useUser(): UseUserReturn;
|
|
118
|
+
interface UseOrganizationReturn {
|
|
119
|
+
/** Currently active organization slug, or null. */
|
|
120
|
+
activeOrg: string | null;
|
|
121
|
+
/** Switch the SDK to operate within an organization context. */
|
|
122
|
+
switchOrganization: (slug: string) => void;
|
|
123
|
+
/** Clear the organization context. */
|
|
124
|
+
clearOrganization: () => void;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Reactive organization context hook.
|
|
128
|
+
* Returns the current org slug and methods to switch/clear context.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```tsx
|
|
132
|
+
* function OrgSwitcher({ orgs }) {
|
|
133
|
+
* const { activeOrg, switchOrganization, clearOrganization } = useOrganization();
|
|
134
|
+
* return (
|
|
135
|
+
* <select value={activeOrg ?? ''} onChange={(e) =>
|
|
136
|
+
* e.target.value ? switchOrganization(e.target.value) : clearOrganization()
|
|
137
|
+
* }>
|
|
138
|
+
* <option value="">No org</option>
|
|
139
|
+
* {orgs.map(o => <option key={o.slug} value={o.slug}>{o.name}</option>)}
|
|
140
|
+
* </select>
|
|
141
|
+
* );
|
|
142
|
+
* }
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
declare function useOrganization(): UseOrganizationReturn;
|
|
146
|
+
interface UseRbacReturn {
|
|
147
|
+
/** Check if the current user has a specific role (synchronous JWT check). */
|
|
148
|
+
hasRole: (role: string) => boolean;
|
|
149
|
+
/** Check if the current user has a specific permission (synchronous JWT check). */
|
|
150
|
+
hasPermission: (permission: string) => boolean;
|
|
151
|
+
/** Check if the current user has any of the given roles. */
|
|
152
|
+
hasAnyRole: (roles: string[]) => boolean;
|
|
153
|
+
/** Check if the current user has all of the given roles. */
|
|
154
|
+
hasAllRoles: (roles: string[]) => boolean;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Reactive RBAC hook.
|
|
158
|
+
* Provides synchronous role/permission checks based on the current JWT.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```tsx
|
|
162
|
+
* function AdminPanel() {
|
|
163
|
+
* const { hasRole } = useRbac();
|
|
164
|
+
* if (!hasRole('admin')) return <p>Access denied</p>;
|
|
165
|
+
* return <AdminDashboard />;
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare function useRbac(): UseRbacReturn;
|
|
170
|
+
|
|
171
|
+
export { TenxyteContext, TenxyteProvider, type TenxyteProviderProps, type UseAuthReturn, type UseOrganizationReturn, type UseRbacReturn, type UseUserReturn, useAuth, useOrganization, useRbac, useTenxyteClient, useTenxyteState, useUser };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
import * as _tenxyte_core from '@tenxyte/core';
|
|
4
|
+
import { TenxyteClient, TenxyteClientState, DecodedTenxyteToken } from '@tenxyte/core';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* React context holding the TenxyteClient instance.
|
|
8
|
+
* Must be provided via <TenxyteProvider>.
|
|
9
|
+
*/
|
|
10
|
+
declare const TenxyteContext: React.Context<TenxyteClient | null>;
|
|
11
|
+
/**
|
|
12
|
+
* Internal hook to access the TenxyteClient instance.
|
|
13
|
+
* Throws if used outside of a <TenxyteProvider>.
|
|
14
|
+
*/
|
|
15
|
+
declare function useTenxyteClient(): TenxyteClient;
|
|
16
|
+
|
|
17
|
+
interface TenxyteProviderProps {
|
|
18
|
+
/** The initialized TenxyteClient instance. */
|
|
19
|
+
client: TenxyteClient;
|
|
20
|
+
children: React__default.ReactNode;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Provides the TenxyteClient to all descendant components and manages
|
|
24
|
+
* reactive state synchronization via SDK events.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* import { TenxyteClient } from '@tenxyte/core';
|
|
29
|
+
* import { TenxyteProvider } from '@tenxyte/react';
|
|
30
|
+
*
|
|
31
|
+
* const tx = new TenxyteClient({ baseUrl: '...' });
|
|
32
|
+
*
|
|
33
|
+
* function App() {
|
|
34
|
+
* return (
|
|
35
|
+
* <TenxyteProvider client={tx}>
|
|
36
|
+
* <MyApp />
|
|
37
|
+
* </TenxyteProvider>
|
|
38
|
+
* );
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
declare function TenxyteProvider({ client, children }: TenxyteProviderProps): React__default.JSX.Element;
|
|
43
|
+
/**
|
|
44
|
+
* Internal hook that subscribes to SDK events and returns a reactive state snapshot.
|
|
45
|
+
* Re-renders consuming components whenever auth state changes.
|
|
46
|
+
*/
|
|
47
|
+
declare function useTenxyteState(): TenxyteClientState & {
|
|
48
|
+
loading: boolean;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
interface UseAuthReturn {
|
|
52
|
+
/** Whether the user has a valid, non-expired access token. */
|
|
53
|
+
isAuthenticated: boolean;
|
|
54
|
+
/** Whether the initial state is still loading from storage. */
|
|
55
|
+
loading: boolean;
|
|
56
|
+
/** Raw access token string, or null. */
|
|
57
|
+
accessToken: string | null;
|
|
58
|
+
/** Login with email/password. Triggers re-render on success. */
|
|
59
|
+
loginWithEmail: (data: {
|
|
60
|
+
email: string;
|
|
61
|
+
password: string;
|
|
62
|
+
device_info?: string;
|
|
63
|
+
totp_code?: string;
|
|
64
|
+
}) => Promise<void>;
|
|
65
|
+
/** Login with phone/password. */
|
|
66
|
+
loginWithPhone: (data: {
|
|
67
|
+
phone_country_code: string;
|
|
68
|
+
phone_number: string;
|
|
69
|
+
password: string;
|
|
70
|
+
device_info?: string;
|
|
71
|
+
}) => Promise<void>;
|
|
72
|
+
/** Logout from all sessions. */
|
|
73
|
+
logout: () => Promise<void>;
|
|
74
|
+
/** Register a new account. */
|
|
75
|
+
register: (data: Record<string, unknown>) => Promise<void>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Reactive authentication hook.
|
|
79
|
+
* Automatically re-renders when the auth state changes (login, logout, refresh, expiry).
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```tsx
|
|
83
|
+
* function LoginPage() {
|
|
84
|
+
* const { isAuthenticated, loginWithEmail, logout, loading } = useAuth();
|
|
85
|
+
*
|
|
86
|
+
* if (loading) return <p>Loading...</p>;
|
|
87
|
+
* if (isAuthenticated) return <button onClick={logout}>Logout</button>;
|
|
88
|
+
*
|
|
89
|
+
* return <button onClick={() => loginWithEmail({ email: '...', password: '...' })}>Login</button>;
|
|
90
|
+
* }
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
declare function useAuth(): UseAuthReturn;
|
|
94
|
+
interface UseUserReturn {
|
|
95
|
+
/** Decoded JWT payload of the current access token, or null. */
|
|
96
|
+
user: DecodedTenxyteToken | null;
|
|
97
|
+
/** Whether the initial state is still loading. */
|
|
98
|
+
loading: boolean;
|
|
99
|
+
/** Fetch the full user profile from the backend. */
|
|
100
|
+
getProfile: () => ReturnType<typeof _tenxyte_core.TenxyteClient.prototype.user.getProfile>;
|
|
101
|
+
/** Update the current user's profile. */
|
|
102
|
+
updateProfile: (data: Record<string, unknown>) => Promise<unknown>;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Reactive user hook.
|
|
106
|
+
* Returns the decoded JWT user and convenience methods for profile management.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```tsx
|
|
110
|
+
* function UserBadge() {
|
|
111
|
+
* const { user, loading } = useUser();
|
|
112
|
+
* if (loading || !user) return null;
|
|
113
|
+
* return <span>{user.email}</span>;
|
|
114
|
+
* }
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
declare function useUser(): UseUserReturn;
|
|
118
|
+
interface UseOrganizationReturn {
|
|
119
|
+
/** Currently active organization slug, or null. */
|
|
120
|
+
activeOrg: string | null;
|
|
121
|
+
/** Switch the SDK to operate within an organization context. */
|
|
122
|
+
switchOrganization: (slug: string) => void;
|
|
123
|
+
/** Clear the organization context. */
|
|
124
|
+
clearOrganization: () => void;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Reactive organization context hook.
|
|
128
|
+
* Returns the current org slug and methods to switch/clear context.
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```tsx
|
|
132
|
+
* function OrgSwitcher({ orgs }) {
|
|
133
|
+
* const { activeOrg, switchOrganization, clearOrganization } = useOrganization();
|
|
134
|
+
* return (
|
|
135
|
+
* <select value={activeOrg ?? ''} onChange={(e) =>
|
|
136
|
+
* e.target.value ? switchOrganization(e.target.value) : clearOrganization()
|
|
137
|
+
* }>
|
|
138
|
+
* <option value="">No org</option>
|
|
139
|
+
* {orgs.map(o => <option key={o.slug} value={o.slug}>{o.name}</option>)}
|
|
140
|
+
* </select>
|
|
141
|
+
* );
|
|
142
|
+
* }
|
|
143
|
+
* ```
|
|
144
|
+
*/
|
|
145
|
+
declare function useOrganization(): UseOrganizationReturn;
|
|
146
|
+
interface UseRbacReturn {
|
|
147
|
+
/** Check if the current user has a specific role (synchronous JWT check). */
|
|
148
|
+
hasRole: (role: string) => boolean;
|
|
149
|
+
/** Check if the current user has a specific permission (synchronous JWT check). */
|
|
150
|
+
hasPermission: (permission: string) => boolean;
|
|
151
|
+
/** Check if the current user has any of the given roles. */
|
|
152
|
+
hasAnyRole: (roles: string[]) => boolean;
|
|
153
|
+
/** Check if the current user has all of the given roles. */
|
|
154
|
+
hasAllRoles: (roles: string[]) => boolean;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Reactive RBAC hook.
|
|
158
|
+
* Provides synchronous role/permission checks based on the current JWT.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```tsx
|
|
162
|
+
* function AdminPanel() {
|
|
163
|
+
* const { hasRole } = useRbac();
|
|
164
|
+
* if (!hasRole('admin')) return <p>Access denied</p>;
|
|
165
|
+
* return <AdminDashboard />;
|
|
166
|
+
* }
|
|
167
|
+
* ```
|
|
168
|
+
*/
|
|
169
|
+
declare function useRbac(): UseRbacReturn;
|
|
170
|
+
|
|
171
|
+
export { TenxyteContext, TenxyteProvider, type TenxyteProviderProps, type UseAuthReturn, type UseOrganizationReturn, type UseRbacReturn, type UseUserReturn, useAuth, useOrganization, useRbac, useTenxyteClient, useTenxyteState, useUser };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// src/context.tsx
|
|
2
|
+
import { createContext, useContext } from "react";
|
|
3
|
+
var TenxyteContext = createContext(null);
|
|
4
|
+
function useTenxyteClient() {
|
|
5
|
+
const client = useContext(TenxyteContext);
|
|
6
|
+
if (!client) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
"[@tenxyte/react] useTenxyteClient must be used within a <TenxyteProvider>. Wrap your app with <TenxyteProvider client={tx}>."
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
return client;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/provider.tsx
|
|
15
|
+
import React, { useCallback, useEffect, useMemo, useState } from "react";
|
|
16
|
+
import { jsx } from "react/jsx-runtime";
|
|
17
|
+
function TenxyteProvider({ client, children }) {
|
|
18
|
+
return /* @__PURE__ */ jsx(TenxyteContext.Provider, { value: client, children });
|
|
19
|
+
}
|
|
20
|
+
function useTenxyteState() {
|
|
21
|
+
const client = React.useContext(TenxyteContext);
|
|
22
|
+
if (!client) {
|
|
23
|
+
throw new Error("[@tenxyte/react] useTenxyteState must be used within a <TenxyteProvider>.");
|
|
24
|
+
}
|
|
25
|
+
const [state, setState] = useState({
|
|
26
|
+
isAuthenticated: false,
|
|
27
|
+
user: null,
|
|
28
|
+
accessToken: null,
|
|
29
|
+
activeOrg: null,
|
|
30
|
+
isAgentMode: false
|
|
31
|
+
});
|
|
32
|
+
const [loading, setLoading] = useState(true);
|
|
33
|
+
const refresh = useCallback(async () => {
|
|
34
|
+
const snapshot = await client.getState();
|
|
35
|
+
setState(snapshot);
|
|
36
|
+
setLoading(false);
|
|
37
|
+
}, [client]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
refresh();
|
|
40
|
+
const unsubs = [
|
|
41
|
+
client.on("token:stored", () => {
|
|
42
|
+
refresh();
|
|
43
|
+
}),
|
|
44
|
+
client.on("token:refreshed", () => {
|
|
45
|
+
refresh();
|
|
46
|
+
}),
|
|
47
|
+
client.on("session:expired", () => {
|
|
48
|
+
refresh();
|
|
49
|
+
})
|
|
50
|
+
];
|
|
51
|
+
return () => {
|
|
52
|
+
unsubs.forEach((unsub) => unsub());
|
|
53
|
+
};
|
|
54
|
+
}, [client, refresh]);
|
|
55
|
+
return useMemo(() => ({ ...state, loading }), [state, loading]);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/hooks.ts
|
|
59
|
+
import { useCallback as useCallback2 } from "react";
|
|
60
|
+
function useAuth() {
|
|
61
|
+
const client = useTenxyteClient();
|
|
62
|
+
const { isAuthenticated, loading, accessToken } = useTenxyteState();
|
|
63
|
+
const loginWithEmail = useCallback2(
|
|
64
|
+
async (data) => {
|
|
65
|
+
await client.auth.loginWithEmail({ ...data, device_info: data.device_info ?? "" });
|
|
66
|
+
},
|
|
67
|
+
[client]
|
|
68
|
+
);
|
|
69
|
+
const loginWithPhone = useCallback2(
|
|
70
|
+
async (data) => {
|
|
71
|
+
await client.auth.loginWithPhone({ ...data, device_info: data.device_info ?? "" });
|
|
72
|
+
},
|
|
73
|
+
[client]
|
|
74
|
+
);
|
|
75
|
+
const logout = useCallback2(async () => {
|
|
76
|
+
await client.auth.logoutAll();
|
|
77
|
+
}, [client]);
|
|
78
|
+
const register = useCallback2(
|
|
79
|
+
async (data) => {
|
|
80
|
+
await client.auth.register(data);
|
|
81
|
+
},
|
|
82
|
+
[client]
|
|
83
|
+
);
|
|
84
|
+
return { isAuthenticated, loading, accessToken, loginWithEmail, loginWithPhone, logout, register };
|
|
85
|
+
}
|
|
86
|
+
function useUser() {
|
|
87
|
+
const client = useTenxyteClient();
|
|
88
|
+
const { user, loading } = useTenxyteState();
|
|
89
|
+
const getProfile = useCallback2(() => client.user.getProfile(), [client]);
|
|
90
|
+
const updateProfile = useCallback2(
|
|
91
|
+
(data) => client.user.updateProfile(data),
|
|
92
|
+
[client]
|
|
93
|
+
);
|
|
94
|
+
return { user, loading, getProfile, updateProfile };
|
|
95
|
+
}
|
|
96
|
+
function useOrganization() {
|
|
97
|
+
const client = useTenxyteClient();
|
|
98
|
+
const { activeOrg } = useTenxyteState();
|
|
99
|
+
const switchOrganization = useCallback2(
|
|
100
|
+
(slug) => {
|
|
101
|
+
client.b2b.switchOrganization(slug);
|
|
102
|
+
},
|
|
103
|
+
[client]
|
|
104
|
+
);
|
|
105
|
+
const clearOrganization = useCallback2(
|
|
106
|
+
() => {
|
|
107
|
+
client.b2b.clearOrganization();
|
|
108
|
+
},
|
|
109
|
+
[client]
|
|
110
|
+
);
|
|
111
|
+
return { activeOrg, switchOrganization, clearOrganization };
|
|
112
|
+
}
|
|
113
|
+
function useRbac() {
|
|
114
|
+
const client = useTenxyteClient();
|
|
115
|
+
const { accessToken } = useTenxyteState();
|
|
116
|
+
const hasRole = useCallback2(
|
|
117
|
+
(role) => client.rbac.hasRole(role, accessToken ?? void 0),
|
|
118
|
+
[client, accessToken]
|
|
119
|
+
);
|
|
120
|
+
const hasPermission = useCallback2(
|
|
121
|
+
(permission) => client.rbac.hasPermission(permission, accessToken ?? void 0),
|
|
122
|
+
[client, accessToken]
|
|
123
|
+
);
|
|
124
|
+
const hasAnyRole = useCallback2(
|
|
125
|
+
(roles) => client.rbac.hasAnyRole(roles, accessToken ?? void 0),
|
|
126
|
+
[client, accessToken]
|
|
127
|
+
);
|
|
128
|
+
const hasAllRoles = useCallback2(
|
|
129
|
+
(roles) => client.rbac.hasAllRoles(roles, accessToken ?? void 0),
|
|
130
|
+
[client, accessToken]
|
|
131
|
+
);
|
|
132
|
+
return { hasRole, hasPermission, hasAnyRole, hasAllRoles };
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
TenxyteContext,
|
|
136
|
+
TenxyteProvider,
|
|
137
|
+
useAuth,
|
|
138
|
+
useOrganization,
|
|
139
|
+
useRbac,
|
|
140
|
+
useTenxyteClient,
|
|
141
|
+
useTenxyteState,
|
|
142
|
+
useUser
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["import { createContext, useContext } from 'react';\nimport type { TenxyteClient } from '@tenxyte/core';\n\n/**\n * React context holding the TenxyteClient instance.\n * Must be provided via <TenxyteProvider>.\n */\nexport const TenxyteContext = createContext<TenxyteClient | null>(null);\n\n/**\n * Internal hook to access the TenxyteClient instance.\n * Throws if used outside of a <TenxyteProvider>.\n */\nexport function useTenxyteClient(): TenxyteClient {\n const client = useContext(TenxyteContext);\n if (!client) {\n throw new Error(\n '[@tenxyte/react] useTenxyteClient must be used within a <TenxyteProvider>. ' +\n 'Wrap your app with <TenxyteProvider client={tx}>.',\n );\n }\n return client;\n}\n","import React, { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { TenxyteClient, TenxyteClientState } from '@tenxyte/core';\nimport { TenxyteContext } from './context';\n\nexport interface TenxyteProviderProps {\n /** The initialized TenxyteClient instance. */\n client: TenxyteClient;\n children: React.ReactNode;\n}\n\n/**\n * Provides the TenxyteClient to all descendant components and manages\n * reactive state synchronization via SDK events.\n *\n * @example\n * ```tsx\n * import { TenxyteClient } from '@tenxyte/core';\n * import { TenxyteProvider } from '@tenxyte/react';\n *\n * const tx = new TenxyteClient({ baseUrl: '...' });\n *\n * function App() {\n * return (\n * <TenxyteProvider client={tx}>\n * <MyApp />\n * </TenxyteProvider>\n * );\n * }\n * ```\n */\nexport function TenxyteProvider({ client, children }: TenxyteProviderProps): React.JSX.Element {\n return (\n <TenxyteContext.Provider value={client}>\n {children}\n </TenxyteContext.Provider>\n );\n}\n\n/**\n * Internal hook that subscribes to SDK events and returns a reactive state snapshot.\n * Re-renders consuming components whenever auth state changes.\n */\nexport function useTenxyteState(): TenxyteClientState & { loading: boolean } {\n const client = React.useContext(TenxyteContext);\n if (!client) {\n throw new Error('[@tenxyte/react] useTenxyteState must be used within a <TenxyteProvider>.');\n }\n\n const [state, setState] = useState<TenxyteClientState>({\n isAuthenticated: false,\n user: null,\n accessToken: null,\n activeOrg: null,\n isAgentMode: false,\n });\n const [loading, setLoading] = useState(true);\n\n const refresh = useCallback(async () => {\n const snapshot = await client.getState();\n setState(snapshot);\n setLoading(false);\n }, [client]);\n\n useEffect(() => {\n // Initial state load\n refresh();\n\n // Subscribe to all state-changing events\n const unsubs = [\n client.on('token:stored', () => { refresh(); }),\n client.on('token:refreshed', () => { refresh(); }),\n client.on('session:expired', () => { refresh(); }),\n ];\n\n return () => {\n unsubs.forEach((unsub) => unsub());\n };\n }, [client, refresh]);\n\n return useMemo(() => ({ ...state, loading }), [state, loading]);\n}\n","import { useCallback } from 'react';\nimport type { DecodedTenxyteToken } from '@tenxyte/core';\nimport { useTenxyteClient } from './context';\nimport { useTenxyteState } from './provider';\n\n// ─── useAuth ───\n\nexport interface UseAuthReturn {\n /** Whether the user has a valid, non-expired access token. */\n isAuthenticated: boolean;\n /** Whether the initial state is still loading from storage. */\n loading: boolean;\n /** Raw access token string, or null. */\n accessToken: string | null;\n /** Login with email/password. Triggers re-render on success. */\n loginWithEmail: (data: { email: string; password: string; device_info?: string; totp_code?: string }) => Promise<void>;\n /** Login with phone/password. */\n loginWithPhone: (data: { phone_country_code: string; phone_number: string; password: string; device_info?: string }) => Promise<void>;\n /** Logout from all sessions. */\n logout: () => Promise<void>;\n /** Register a new account. */\n register: (data: Record<string, unknown>) => Promise<void>;\n}\n\n/**\n * Reactive authentication hook.\n * Automatically re-renders when the auth state changes (login, logout, refresh, expiry).\n *\n * @example\n * ```tsx\n * function LoginPage() {\n * const { isAuthenticated, loginWithEmail, logout, loading } = useAuth();\n *\n * if (loading) return <p>Loading...</p>;\n * if (isAuthenticated) return <button onClick={logout}>Logout</button>;\n *\n * return <button onClick={() => loginWithEmail({ email: '...', password: '...' })}>Login</button>;\n * }\n * ```\n */\nexport function useAuth(): UseAuthReturn {\n const client = useTenxyteClient();\n const { isAuthenticated, loading, accessToken } = useTenxyteState();\n\n const loginWithEmail = useCallback(\n async (data: { email: string; password: string; device_info?: string; totp_code?: string }) => {\n await client.auth.loginWithEmail({ ...data, device_info: data.device_info ?? '' });\n },\n [client],\n );\n\n const loginWithPhone = useCallback(\n async (data: { phone_country_code: string; phone_number: string; password: string; device_info?: string }) => {\n await client.auth.loginWithPhone({ ...data, device_info: data.device_info ?? '' });\n },\n [client],\n );\n\n const logout = useCallback(async () => {\n await client.auth.logoutAll();\n }, [client]);\n\n const register = useCallback(\n async (data: Record<string, unknown>) => {\n await client.auth.register(data as any);\n },\n [client],\n );\n\n return { isAuthenticated, loading, accessToken, loginWithEmail, loginWithPhone, logout, register };\n}\n\n// ─── useUser ───\n\nexport interface UseUserReturn {\n /** Decoded JWT payload of the current access token, or null. */\n user: DecodedTenxyteToken | null;\n /** Whether the initial state is still loading. */\n loading: boolean;\n /** Fetch the full user profile from the backend. */\n getProfile: () => ReturnType<typeof import('@tenxyte/core').TenxyteClient.prototype.user.getProfile>;\n /** Update the current user's profile. */\n updateProfile: (data: Record<string, unknown>) => Promise<unknown>;\n}\n\n/**\n * Reactive user hook.\n * Returns the decoded JWT user and convenience methods for profile management.\n *\n * @example\n * ```tsx\n * function UserBadge() {\n * const { user, loading } = useUser();\n * if (loading || !user) return null;\n * return <span>{user.email}</span>;\n * }\n * ```\n */\nexport function useUser(): UseUserReturn {\n const client = useTenxyteClient();\n const { user, loading } = useTenxyteState();\n\n const getProfile = useCallback(() => client.user.getProfile(), [client]);\n\n const updateProfile = useCallback(\n (data: Record<string, unknown>) => client.user.updateProfile(data),\n [client],\n );\n\n return { user, loading, getProfile, updateProfile };\n}\n\n// ─── useOrganization ───\n\nexport interface UseOrganizationReturn {\n /** Currently active organization slug, or null. */\n activeOrg: string | null;\n /** Switch the SDK to operate within an organization context. */\n switchOrganization: (slug: string) => void;\n /** Clear the organization context. */\n clearOrganization: () => void;\n}\n\n/**\n * Reactive organization context hook.\n * Returns the current org slug and methods to switch/clear context.\n *\n * @example\n * ```tsx\n * function OrgSwitcher({ orgs }) {\n * const { activeOrg, switchOrganization, clearOrganization } = useOrganization();\n * return (\n * <select value={activeOrg ?? ''} onChange={(e) =>\n * e.target.value ? switchOrganization(e.target.value) : clearOrganization()\n * }>\n * <option value=\"\">No org</option>\n * {orgs.map(o => <option key={o.slug} value={o.slug}>{o.name}</option>)}\n * </select>\n * );\n * }\n * ```\n */\nexport function useOrganization(): UseOrganizationReturn {\n const client = useTenxyteClient();\n const { activeOrg } = useTenxyteState();\n\n const switchOrganization = useCallback(\n (slug: string) => { client.b2b.switchOrganization(slug); },\n [client],\n );\n\n const clearOrganization = useCallback(\n () => { client.b2b.clearOrganization(); },\n [client],\n );\n\n return { activeOrg, switchOrganization, clearOrganization };\n}\n\n// ─── useRbac ───\n\nexport interface UseRbacReturn {\n /** Check if the current user has a specific role (synchronous JWT check). */\n hasRole: (role: string) => boolean;\n /** Check if the current user has a specific permission (synchronous JWT check). */\n hasPermission: (permission: string) => boolean;\n /** Check if the current user has any of the given roles. */\n hasAnyRole: (roles: string[]) => boolean;\n /** Check if the current user has all of the given roles. */\n hasAllRoles: (roles: string[]) => boolean;\n}\n\n/**\n * Reactive RBAC hook.\n * Provides synchronous role/permission checks based on the current JWT.\n *\n * @example\n * ```tsx\n * function AdminPanel() {\n * const { hasRole } = useRbac();\n * if (!hasRole('admin')) return <p>Access denied</p>;\n * return <AdminDashboard />;\n * }\n * ```\n */\nexport function useRbac(): UseRbacReturn {\n const client = useTenxyteClient();\n const { accessToken } = useTenxyteState();\n\n const hasRole = useCallback(\n (role: string) => client.rbac.hasRole(role, accessToken ?? undefined),\n [client, accessToken],\n );\n\n const hasPermission = useCallback(\n (permission: string) => client.rbac.hasPermission(permission, accessToken ?? undefined),\n [client, accessToken],\n );\n\n const hasAnyRole = useCallback(\n (roles: string[]) => client.rbac.hasAnyRole(roles, accessToken ?? undefined),\n [client, accessToken],\n );\n\n const hasAllRoles = useCallback(\n (roles: string[]) => client.rbac.hasAllRoles(roles, accessToken ?? undefined),\n [client, accessToken],\n );\n\n return { hasRole, hasPermission, hasAnyRole, hasAllRoles };\n}\n"],"mappings":"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","names":["useCallback","useCallback"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tenxyte/react",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "React bindings for the Tenxyte SDK",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
],
|
|
23
23
|
"sideEffects": false,
|
|
24
24
|
"publishConfig": {
|
|
25
|
-
"access": "public"
|
|
25
|
+
"access": "public",
|
|
26
|
+
"provenance": true
|
|
26
27
|
},
|
|
27
28
|
"scripts": {
|
|
28
29
|
"build": "tsup",
|