@tenxyte/core 0.1.5 → 0.9.0
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 +184 -0
- package/dist/index.cjs +951 -496
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1709 -1265
- package/dist/index.d.ts +1709 -1265
- package/dist/index.js +919 -464
- package/dist/index.js.map +1 -1
- package/package.json +70 -66
- package/src/client.ts +50 -21
- package/src/http/client.ts +162 -162
- package/src/http/index.ts +1 -1
- package/src/http/interceptors.ts +117 -117
- package/src/index.ts +7 -7
- package/src/modules/ai.ts +178 -0
- package/src/modules/auth.ts +116 -95
- package/src/modules/b2b.ts +177 -0
- package/src/modules/rbac.ts +207 -160
- package/src/modules/security.ts +313 -122
- package/src/modules/user.ts +95 -80
- package/src/storage/cookie.ts +39 -39
- package/src/storage/index.ts +29 -29
- package/src/storage/localStorage.ts +75 -75
- package/src/storage/memory.ts +30 -30
- package/src/types/index.ts +152 -150
- package/src/utils/base64url.ts +25 -0
- package/src/utils/device_info.ts +94 -94
- package/src/utils/events.ts +71 -71
- package/src/utils/jwt.ts +51 -51
- package/tests/http.test.ts +144 -144
- package/tests/modules/auth.test.ts +93 -93
- package/tests/modules/rbac.test.ts +95 -95
- package/tests/modules/security.test.ts +85 -75
- package/tests/modules/user.test.ts +76 -76
- package/tests/storage.test.ts +96 -96
- package/tests/utils.test.ts +71 -71
- package/tsup.config.ts +10 -10
- package/vitest.config.ts +7 -7
package/src/storage/cookie.ts
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import type { TenxyteStorage } from './index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* CookieStorage implementation
|
|
5
|
-
* Note: To be secure, tokens should be HttpOnly where possible.
|
|
6
|
-
* This class handles client-side cookies if necessary.
|
|
7
|
-
*/
|
|
8
|
-
export class CookieStorage implements TenxyteStorage {
|
|
9
|
-
private defaultOptions: string;
|
|
10
|
-
|
|
11
|
-
constructor(options: { secure?: boolean; sameSite?: 'Strict' | 'Lax' | 'None' } = {}) {
|
|
12
|
-
const secure = options.secure ?? true;
|
|
13
|
-
const sameSite = options.sameSite ?? 'Lax';
|
|
14
|
-
this.defaultOptions = `path=/; SameSite=${sameSite}${secure ? '; Secure' : ''}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
getItem(key: string): string | null {
|
|
18
|
-
if (typeof document === 'undefined') return null;
|
|
19
|
-
const match = document.cookie.match(new RegExp(`(^| )${key}=([^;]+)`));
|
|
20
|
-
return match ? decodeURIComponent(match[2]) : null;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
setItem(key: string, value: string): void {
|
|
24
|
-
if (typeof document === 'undefined') return;
|
|
25
|
-
document.cookie = `${key}=${encodeURIComponent(value)}; ${this.defaultOptions}`;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
removeItem(key: string): void {
|
|
29
|
-
if (typeof document === 'undefined') return;
|
|
30
|
-
document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
clear(): void {
|
|
34
|
-
// Cannot easily clear all cookies securely because we don't know them all
|
|
35
|
-
// Usually auth keys are known, e.g., tx_access, tx_refresh
|
|
36
|
-
this.removeItem('tx_access');
|
|
37
|
-
this.removeItem('tx_refresh');
|
|
38
|
-
}
|
|
39
|
-
}
|
|
1
|
+
import type { TenxyteStorage } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* CookieStorage implementation
|
|
5
|
+
* Note: To be secure, tokens should be HttpOnly where possible.
|
|
6
|
+
* This class handles client-side cookies if necessary.
|
|
7
|
+
*/
|
|
8
|
+
export class CookieStorage implements TenxyteStorage {
|
|
9
|
+
private defaultOptions: string;
|
|
10
|
+
|
|
11
|
+
constructor(options: { secure?: boolean; sameSite?: 'Strict' | 'Lax' | 'None' } = {}) {
|
|
12
|
+
const secure = options.secure ?? true;
|
|
13
|
+
const sameSite = options.sameSite ?? 'Lax';
|
|
14
|
+
this.defaultOptions = `path=/; SameSite=${sameSite}${secure ? '; Secure' : ''}`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
getItem(key: string): string | null {
|
|
18
|
+
if (typeof document === 'undefined') return null;
|
|
19
|
+
const match = document.cookie.match(new RegExp(`(^| )${key}=([^;]+)`));
|
|
20
|
+
return match ? decodeURIComponent(match[2]) : null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
setItem(key: string, value: string): void {
|
|
24
|
+
if (typeof document === 'undefined') return;
|
|
25
|
+
document.cookie = `${key}=${encodeURIComponent(value)}; ${this.defaultOptions}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
removeItem(key: string): void {
|
|
29
|
+
if (typeof document === 'undefined') return;
|
|
30
|
+
document.cookie = `${key}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
clear(): void {
|
|
34
|
+
// Cannot easily clear all cookies securely because we don't know them all
|
|
35
|
+
// Usually auth keys are known, e.g., tx_access, tx_refresh
|
|
36
|
+
this.removeItem('tx_access');
|
|
37
|
+
this.removeItem('tx_refresh');
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/storage/index.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
export interface TenxyteStorage {
|
|
2
|
-
/**
|
|
3
|
-
* Retrieves a value from storage.
|
|
4
|
-
* @param key The key to retrieve
|
|
5
|
-
*/
|
|
6
|
-
getItem(key: string): string | null | Promise<string | null>;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Saves a value to storage.
|
|
10
|
-
* @param key The key to store
|
|
11
|
-
* @param value The string value
|
|
12
|
-
*/
|
|
13
|
-
setItem(key: string, value: string): void | Promise<void>;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Removes a specific key from storage.
|
|
17
|
-
* @param key The key to remove
|
|
18
|
-
*/
|
|
19
|
-
removeItem(key: string): void | Promise<void>;
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Clears all storage keys managed by the SDK.
|
|
23
|
-
*/
|
|
24
|
-
clear(): void | Promise<void>;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export * from './memory';
|
|
28
|
-
export * from './localStorage';
|
|
29
|
-
export * from './cookie';
|
|
1
|
+
export interface TenxyteStorage {
|
|
2
|
+
/**
|
|
3
|
+
* Retrieves a value from storage.
|
|
4
|
+
* @param key The key to retrieve
|
|
5
|
+
*/
|
|
6
|
+
getItem(key: string): string | null | Promise<string | null>;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Saves a value to storage.
|
|
10
|
+
* @param key The key to store
|
|
11
|
+
* @param value The string value
|
|
12
|
+
*/
|
|
13
|
+
setItem(key: string, value: string): void | Promise<void>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Removes a specific key from storage.
|
|
17
|
+
* @param key The key to remove
|
|
18
|
+
*/
|
|
19
|
+
removeItem(key: string): void | Promise<void>;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Clears all storage keys managed by the SDK.
|
|
23
|
+
*/
|
|
24
|
+
clear(): void | Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export * from './memory';
|
|
28
|
+
export * from './localStorage';
|
|
29
|
+
export * from './cookie';
|
|
@@ -1,75 +1,75 @@
|
|
|
1
|
-
import type { TenxyteStorage } from './index';
|
|
2
|
-
import { MemoryStorage } from './memory';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* LocalStorage wrapper for the browser.
|
|
6
|
-
* Degrades gracefully to MemoryStorage if localStorage is unavailable
|
|
7
|
-
* (e.g., SSR, Private Browsing mode strictness).
|
|
8
|
-
*/
|
|
9
|
-
export class LocalStorage implements TenxyteStorage {
|
|
10
|
-
private fallbackMemoryStore: MemoryStorage | null = null;
|
|
11
|
-
private isAvailable: boolean;
|
|
12
|
-
|
|
13
|
-
constructor() {
|
|
14
|
-
this.isAvailable = this.checkAvailability();
|
|
15
|
-
if (!this.isAvailable) {
|
|
16
|
-
this.fallbackMemoryStore = new MemoryStorage();
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
private checkAvailability(): boolean {
|
|
21
|
-
try {
|
|
22
|
-
if (typeof window === 'undefined' || !window.localStorage) {
|
|
23
|
-
return false;
|
|
24
|
-
}
|
|
25
|
-
const testKey = '__tenxyte_test__';
|
|
26
|
-
window.localStorage.setItem(testKey, '1');
|
|
27
|
-
window.localStorage.removeItem(testKey);
|
|
28
|
-
return true;
|
|
29
|
-
} catch (e) {
|
|
30
|
-
return false;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
getItem(key: string): string | null {
|
|
35
|
-
if (!this.isAvailable && this.fallbackMemoryStore) {
|
|
36
|
-
return this.fallbackMemoryStore.getItem(key);
|
|
37
|
-
}
|
|
38
|
-
return window.localStorage.getItem(key);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
setItem(key: string, value: string): void {
|
|
42
|
-
if (!this.isAvailable && this.fallbackMemoryStore) {
|
|
43
|
-
this.fallbackMemoryStore.setItem(key, value);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
try {
|
|
47
|
-
window.localStorage.setItem(key, value);
|
|
48
|
-
} catch (e) {
|
|
49
|
-
// Storage quota exceeded or similar error
|
|
50
|
-
console.warn(`[Tenxyte SDK] Warning: failed to write to localStorage for key ${key}`);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
removeItem(key: string): void {
|
|
55
|
-
if (!this.isAvailable && this.fallbackMemoryStore) {
|
|
56
|
-
this.fallbackMemoryStore.removeItem(key);
|
|
57
|
-
return;
|
|
58
|
-
}
|
|
59
|
-
window.localStorage.removeItem(key);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
clear(): void {
|
|
63
|
-
if (!this.isAvailable && this.fallbackMemoryStore) {
|
|
64
|
-
this.fallbackMemoryStore.clear();
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
// We ideally only clear tenxyte specific keys if needed,
|
|
68
|
-
// but standard clear() removes everything.
|
|
69
|
-
// If the library only ever writes specific keys,
|
|
70
|
-
// we could keep track of them and iterate, but for now clear() is standard.
|
|
71
|
-
// For safer implementation we could just let the caller do removeItems() individually
|
|
72
|
-
// but let's conform to the clear API.
|
|
73
|
-
window.localStorage.clear();
|
|
74
|
-
}
|
|
75
|
-
}
|
|
1
|
+
import type { TenxyteStorage } from './index';
|
|
2
|
+
import { MemoryStorage } from './memory';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* LocalStorage wrapper for the browser.
|
|
6
|
+
* Degrades gracefully to MemoryStorage if localStorage is unavailable
|
|
7
|
+
* (e.g., SSR, Private Browsing mode strictness).
|
|
8
|
+
*/
|
|
9
|
+
export class LocalStorage implements TenxyteStorage {
|
|
10
|
+
private fallbackMemoryStore: MemoryStorage | null = null;
|
|
11
|
+
private isAvailable: boolean;
|
|
12
|
+
|
|
13
|
+
constructor() {
|
|
14
|
+
this.isAvailable = this.checkAvailability();
|
|
15
|
+
if (!this.isAvailable) {
|
|
16
|
+
this.fallbackMemoryStore = new MemoryStorage();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private checkAvailability(): boolean {
|
|
21
|
+
try {
|
|
22
|
+
if (typeof window === 'undefined' || !window.localStorage) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const testKey = '__tenxyte_test__';
|
|
26
|
+
window.localStorage.setItem(testKey, '1');
|
|
27
|
+
window.localStorage.removeItem(testKey);
|
|
28
|
+
return true;
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getItem(key: string): string | null {
|
|
35
|
+
if (!this.isAvailable && this.fallbackMemoryStore) {
|
|
36
|
+
return this.fallbackMemoryStore.getItem(key);
|
|
37
|
+
}
|
|
38
|
+
return window.localStorage.getItem(key);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
setItem(key: string, value: string): void {
|
|
42
|
+
if (!this.isAvailable && this.fallbackMemoryStore) {
|
|
43
|
+
this.fallbackMemoryStore.setItem(key, value);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
window.localStorage.setItem(key, value);
|
|
48
|
+
} catch (e) {
|
|
49
|
+
// Storage quota exceeded or similar error
|
|
50
|
+
console.warn(`[Tenxyte SDK] Warning: failed to write to localStorage for key ${key}`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
removeItem(key: string): void {
|
|
55
|
+
if (!this.isAvailable && this.fallbackMemoryStore) {
|
|
56
|
+
this.fallbackMemoryStore.removeItem(key);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
window.localStorage.removeItem(key);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
clear(): void {
|
|
63
|
+
if (!this.isAvailable && this.fallbackMemoryStore) {
|
|
64
|
+
this.fallbackMemoryStore.clear();
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// We ideally only clear tenxyte specific keys if needed,
|
|
68
|
+
// but standard clear() removes everything.
|
|
69
|
+
// If the library only ever writes specific keys,
|
|
70
|
+
// we could keep track of them and iterate, but for now clear() is standard.
|
|
71
|
+
// For safer implementation we could just let the caller do removeItems() individually
|
|
72
|
+
// but let's conform to the clear API.
|
|
73
|
+
window.localStorage.clear();
|
|
74
|
+
}
|
|
75
|
+
}
|
package/src/storage/memory.ts
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
import type { TenxyteStorage } from './index';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* MemoryStorage implementation primarily used in Node.js (SSR)
|
|
5
|
-
* environments or as a fallback when browser storage is unavailable.
|
|
6
|
-
*/
|
|
7
|
-
export class MemoryStorage implements TenxyteStorage {
|
|
8
|
-
private store: Map<string, string>;
|
|
9
|
-
|
|
10
|
-
constructor() {
|
|
11
|
-
this.store = new Map<string, string>();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
getItem(key: string): string | null {
|
|
15
|
-
const value = this.store.get(key);
|
|
16
|
-
return value !== undefined ? value : null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
setItem(key: string, value: string): void {
|
|
20
|
-
this.store.set(key, value);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
removeItem(key: string): void {
|
|
24
|
-
this.store.delete(key);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
clear(): void {
|
|
28
|
-
this.store.clear();
|
|
29
|
-
}
|
|
30
|
-
}
|
|
1
|
+
import type { TenxyteStorage } from './index';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* MemoryStorage implementation primarily used in Node.js (SSR)
|
|
5
|
+
* environments or as a fallback when browser storage is unavailable.
|
|
6
|
+
*/
|
|
7
|
+
export class MemoryStorage implements TenxyteStorage {
|
|
8
|
+
private store: Map<string, string>;
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.store = new Map<string, string>();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getItem(key: string): string | null {
|
|
15
|
+
const value = this.store.get(key);
|
|
16
|
+
return value !== undefined ? value : null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
setItem(key: string, value: string): void {
|
|
20
|
+
this.store.set(key, value);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
removeItem(key: string): void {
|
|
24
|
+
this.store.delete(key);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
clear(): void {
|
|
28
|
+
this.store.clear();
|
|
29
|
+
}
|
|
30
|
+
}
|
package/src/types/index.ts
CHANGED
|
@@ -1,150 +1,152 @@
|
|
|
1
|
-
import type { components, paths } from './api-schema';
|
|
2
|
-
|
|
3
|
-
export type GeneratedSchema = components['schemas'];
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Core User Interface exposed by the SDK.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
| '
|
|
50
|
-
| '
|
|
51
|
-
| '
|
|
52
|
-
| '
|
|
53
|
-
| '
|
|
54
|
-
| '
|
|
55
|
-
| '
|
|
56
|
-
| '
|
|
57
|
-
| '
|
|
58
|
-
| '
|
|
59
|
-
| '
|
|
60
|
-
| '
|
|
61
|
-
| '
|
|
62
|
-
| '
|
|
63
|
-
| '
|
|
64
|
-
| '
|
|
65
|
-
| '
|
|
66
|
-
|
|
67
|
-
| '
|
|
68
|
-
|
|
69
|
-
| '
|
|
70
|
-
| '
|
|
71
|
-
|
|
72
|
-
| '
|
|
73
|
-
|
|
74
|
-
| '
|
|
75
|
-
| '
|
|
76
|
-
| '
|
|
77
|
-
| '
|
|
78
|
-
| '
|
|
79
|
-
| '
|
|
80
|
-
| '
|
|
81
|
-
| '
|
|
82
|
-
|
|
83
|
-
| '
|
|
84
|
-
|
|
85
|
-
| '
|
|
86
|
-
| '
|
|
87
|
-
| '
|
|
88
|
-
| '
|
|
89
|
-
| '
|
|
90
|
-
| '
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
1
|
+
import type { components, paths } from './api-schema';
|
|
2
|
+
|
|
3
|
+
export type GeneratedSchema = components['schemas'];
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Core User Interface exposed by the SDK.
|
|
7
|
+
* Represents the authenticated entity bound to the active session.
|
|
8
|
+
*/
|
|
9
|
+
export interface TenxyteUser {
|
|
10
|
+
id: string; // UUID
|
|
11
|
+
email: string | null;
|
|
12
|
+
phone_country_code: string | null;
|
|
13
|
+
phone_number: string | null;
|
|
14
|
+
first_name: string;
|
|
15
|
+
last_name: string;
|
|
16
|
+
is_email_verified: boolean;
|
|
17
|
+
is_phone_verified: boolean;
|
|
18
|
+
is_2fa_enabled: boolean;
|
|
19
|
+
roles: string[]; // Role codes e.g., ['admin', 'viewer']
|
|
20
|
+
permissions: string[]; // Permission codes (direct + inherited)
|
|
21
|
+
created_at: string; // ISO 8601
|
|
22
|
+
last_login: string | null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Standard SDK Token Pair (internal structure normalized by interceptors).
|
|
27
|
+
* These are managed automatically if auto-refresh is enabled.
|
|
28
|
+
*/
|
|
29
|
+
export interface TokenPair {
|
|
30
|
+
access_token: string; // JWT Bearer
|
|
31
|
+
refresh_token: string;
|
|
32
|
+
token_type: 'Bearer';
|
|
33
|
+
expires_in: number; // Current access_token lifetime in seconds
|
|
34
|
+
device_summary: string | null; // e.g., "desktop — windows 11 — chrome 122" (null if device_info absent)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Standardized API Error Response wrapper thrown by network interceptors.
|
|
39
|
+
*/
|
|
40
|
+
export interface TenxyteError {
|
|
41
|
+
error: string; // Human message
|
|
42
|
+
code: TenxyteErrorCode; // Machine identifier
|
|
43
|
+
details?: Record<string, string[]> | string; // Per-field errors or free message
|
|
44
|
+
retry_after?: number; // Present on HTTP 429 and 423
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type TenxyteErrorCode =
|
|
48
|
+
// Auth
|
|
49
|
+
| 'LOGIN_FAILED'
|
|
50
|
+
| 'INVALID_CREDENTIALS'
|
|
51
|
+
| 'ACCOUNT_LOCKED'
|
|
52
|
+
| 'ACCOUNT_BANNED'
|
|
53
|
+
| '2FA_REQUIRED'
|
|
54
|
+
| 'ADMIN_2FA_SETUP_REQUIRED'
|
|
55
|
+
| 'TOKEN_EXPIRED'
|
|
56
|
+
| 'TOKEN_BLACKLISTED'
|
|
57
|
+
| 'REFRESH_FAILED'
|
|
58
|
+
| 'PERMISSION_DENIED'
|
|
59
|
+
| 'SESSION_LIMIT_EXCEEDED'
|
|
60
|
+
| 'DEVICE_LIMIT_EXCEEDED'
|
|
61
|
+
| 'RATE_LIMITED'
|
|
62
|
+
| 'INVALID_OTP'
|
|
63
|
+
| 'OTP_EXPIRED'
|
|
64
|
+
| 'INVALID_PROVIDER'
|
|
65
|
+
| 'SOCIAL_AUTH_FAILED'
|
|
66
|
+
| 'VALIDATION_URL_REQUIRED'
|
|
67
|
+
| 'INVALID_TOKEN'
|
|
68
|
+
// User / Account
|
|
69
|
+
| 'CONFIRMATION_REQUIRED'
|
|
70
|
+
| 'PASSWORD_REQUIRED'
|
|
71
|
+
| 'INVALID_PASSWORD'
|
|
72
|
+
| 'INVALID_DEVICE_INFO'
|
|
73
|
+
// B2B / Organizations
|
|
74
|
+
| 'ORG_NOT_FOUND'
|
|
75
|
+
| 'NOT_ORG_MEMBER'
|
|
76
|
+
| 'NOT_OWNER'
|
|
77
|
+
| 'ALREADY_MEMBER'
|
|
78
|
+
| 'MEMBER_LIMIT_EXCEEDED'
|
|
79
|
+
| 'HAS_CHILDREN'
|
|
80
|
+
| 'CIRCULAR_HIERARCHY'
|
|
81
|
+
| 'LAST_OWNER_REQUIRED'
|
|
82
|
+
| 'INVITATION_EXISTS'
|
|
83
|
+
| 'INVALID_ROLE'
|
|
84
|
+
// AIRS — Agent errors
|
|
85
|
+
| 'AGENT_NOT_FOUND'
|
|
86
|
+
| 'AGENT_SUSPENDED'
|
|
87
|
+
| 'AGENT_REVOKED'
|
|
88
|
+
| 'AGENT_EXPIRED'
|
|
89
|
+
| 'BUDGET_EXCEEDED'
|
|
90
|
+
| 'RATE_LIMIT_EXCEEDED'
|
|
91
|
+
| 'HEARTBEAT_MISSING'
|
|
92
|
+
| 'AIRS_DISABLED';
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Organization Structure defining a B2B tenant or hierarchical unit.
|
|
96
|
+
*/
|
|
97
|
+
export interface Organization {
|
|
98
|
+
id: number;
|
|
99
|
+
name: string;
|
|
100
|
+
slug: string;
|
|
101
|
+
description: string | null;
|
|
102
|
+
metadata: Record<string, unknown> | null;
|
|
103
|
+
is_active: boolean;
|
|
104
|
+
max_members: number; // 0 = unlimited
|
|
105
|
+
member_count: number;
|
|
106
|
+
created_at: string;
|
|
107
|
+
updated_at: string;
|
|
108
|
+
parent: { id: number; name: string; slug: string } | null;
|
|
109
|
+
children: Array<{ id: number; name: string; slug: string }>;
|
|
110
|
+
user_role: string | null; // Current user's contextual role inside this exact org
|
|
111
|
+
user_permissions: string[]; // Effective permissions resolving downward in this org
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Base Pagination Response wrapper
|
|
116
|
+
*/
|
|
117
|
+
export interface PaginatedResponse<T> {
|
|
118
|
+
count: number;
|
|
119
|
+
page: number;
|
|
120
|
+
page_size: number;
|
|
121
|
+
total_pages: number;
|
|
122
|
+
next: string | null;
|
|
123
|
+
previous: string | null;
|
|
124
|
+
results: T[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* AIRS Agent Token metadata
|
|
129
|
+
*/
|
|
130
|
+
export interface AgentTokenSummary {
|
|
131
|
+
id: number;
|
|
132
|
+
agent_id: string;
|
|
133
|
+
status: 'ACTIVE' | 'SUSPENDED' | 'REVOKED' | 'EXPIRED';
|
|
134
|
+
expires_at: string;
|
|
135
|
+
created_at: string;
|
|
136
|
+
organization: string | null; // Org slug, or null
|
|
137
|
+
current_request_count: number;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Request awaiting Human-In-The-Loop approval
|
|
142
|
+
*/
|
|
143
|
+
export interface AgentPendingAction {
|
|
144
|
+
id: number;
|
|
145
|
+
agent_id: string;
|
|
146
|
+
permission: string; // e.g., "users.delete"
|
|
147
|
+
endpoint: string;
|
|
148
|
+
payload: unknown;
|
|
149
|
+
confirmation_token: string;
|
|
150
|
+
expires_at: string;
|
|
151
|
+
created_at: string;
|
|
152
|
+
}
|