@auxiora/dashboard 1.0.0 → 1.3.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.
Files changed (82) hide show
  1. package/dist/router.d.ts.map +1 -1
  2. package/dist/router.js +195 -49
  3. package/dist/router.js.map +1 -1
  4. package/dist/types.d.ts +66 -0
  5. package/dist/types.d.ts.map +1 -1
  6. package/dist/types.js.map +1 -1
  7. package/package.json +10 -4
  8. package/dist-ui/assets/index-BfY0i5jw.css +0 -1
  9. package/dist-ui/assets/index-CXpk9mvw.js +0 -60
  10. package/dist-ui/icon.svg +0 -59
  11. package/dist-ui/index.html +0 -20
  12. package/src/auth.ts +0 -83
  13. package/src/cloud-types.ts +0 -63
  14. package/src/index.ts +0 -5
  15. package/src/router.ts +0 -2494
  16. package/src/types.ts +0 -269
  17. package/tests/auth.test.ts +0 -51
  18. package/tests/cloud-router.test.ts +0 -249
  19. package/tests/desktop-router.test.ts +0 -151
  20. package/tests/router.test.ts +0 -388
  21. package/tests/trust-router.test.ts +0 -170
  22. package/tsconfig.json +0 -12
  23. package/tsconfig.tsbuildinfo +0 -1
  24. package/ui/index.html +0 -19
  25. package/ui/node_modules/.bin/browserslist +0 -17
  26. package/ui/node_modules/.bin/tsc +0 -17
  27. package/ui/node_modules/.bin/tsserver +0 -17
  28. package/ui/node_modules/.bin/vite +0 -17
  29. package/ui/package.json +0 -23
  30. package/ui/public/icon.svg +0 -59
  31. package/ui/src/App.tsx +0 -63
  32. package/ui/src/api.ts +0 -238
  33. package/ui/src/components/ActivityFeed.tsx +0 -123
  34. package/ui/src/components/BehaviorHealth.tsx +0 -105
  35. package/ui/src/components/DataTable.tsx +0 -39
  36. package/ui/src/components/Layout.tsx +0 -160
  37. package/ui/src/components/PasswordStrength.tsx +0 -31
  38. package/ui/src/components/SetupProgress.tsx +0 -26
  39. package/ui/src/components/StatusBadge.tsx +0 -12
  40. package/ui/src/components/ThemeSelector.tsx +0 -39
  41. package/ui/src/contexts/ThemeContext.tsx +0 -58
  42. package/ui/src/hooks/useApi.ts +0 -19
  43. package/ui/src/hooks/usePolling.ts +0 -8
  44. package/ui/src/main.tsx +0 -16
  45. package/ui/src/pages/AuditLog.tsx +0 -36
  46. package/ui/src/pages/Behaviors.tsx +0 -426
  47. package/ui/src/pages/Chat.tsx +0 -688
  48. package/ui/src/pages/Login.tsx +0 -64
  49. package/ui/src/pages/Overview.tsx +0 -56
  50. package/ui/src/pages/Sessions.tsx +0 -26
  51. package/ui/src/pages/SettingsAmbient.tsx +0 -185
  52. package/ui/src/pages/SettingsConnections.tsx +0 -201
  53. package/ui/src/pages/SettingsNotifications.tsx +0 -241
  54. package/ui/src/pages/SetupAppearance.tsx +0 -45
  55. package/ui/src/pages/SetupChannels.tsx +0 -143
  56. package/ui/src/pages/SetupComplete.tsx +0 -31
  57. package/ui/src/pages/SetupConnections.tsx +0 -80
  58. package/ui/src/pages/SetupDashboardPassword.tsx +0 -50
  59. package/ui/src/pages/SetupIdentity.tsx +0 -68
  60. package/ui/src/pages/SetupPersonality.tsx +0 -78
  61. package/ui/src/pages/SetupProvider.tsx +0 -65
  62. package/ui/src/pages/SetupVault.tsx +0 -50
  63. package/ui/src/pages/SetupWelcome.tsx +0 -19
  64. package/ui/src/pages/UnlockVault.tsx +0 -56
  65. package/ui/src/pages/Webhooks.tsx +0 -158
  66. package/ui/src/pages/settings/Appearance.tsx +0 -63
  67. package/ui/src/pages/settings/Channels.tsx +0 -138
  68. package/ui/src/pages/settings/Identity.tsx +0 -61
  69. package/ui/src/pages/settings/Personality.tsx +0 -54
  70. package/ui/src/pages/settings/PersonalityEditor.tsx +0 -577
  71. package/ui/src/pages/settings/Provider.tsx +0 -537
  72. package/ui/src/pages/settings/Security.tsx +0 -111
  73. package/ui/src/styles/global.css +0 -2308
  74. package/ui/src/styles/themes/index.css +0 -7
  75. package/ui/src/styles/themes/monolith.css +0 -125
  76. package/ui/src/styles/themes/nebula.css +0 -90
  77. package/ui/src/styles/themes/neon.css +0 -149
  78. package/ui/src/styles/themes/polar.css +0 -151
  79. package/ui/src/styles/themes/signal.css +0 -163
  80. package/ui/src/styles/themes/terra.css +0 -146
  81. package/ui/tsconfig.json +0 -14
  82. package/ui/vite.config.ts +0 -20
package/src/types.ts DELETED
@@ -1,269 +0,0 @@
1
- export interface DashboardConfig {
2
- enabled: boolean;
3
- sessionTtlMs: number;
4
- }
5
-
6
- export interface DashboardSession {
7
- id: string;
8
- createdAt: number;
9
- lastActive: number;
10
- ip: string;
11
- }
12
-
13
- export interface PersonalityTemplateSummary {
14
- id: string;
15
- name: string;
16
- description: string;
17
- preview: string;
18
- }
19
-
20
- export interface SetupDeps {
21
- personality?: {
22
- listTemplates(): Promise<PersonalityTemplateSummary[]>;
23
- applyTemplate(id: string): Promise<void>;
24
- buildCustom(config: Record<string, unknown>): Promise<string>;
25
- getActiveTemplate?(): Promise<{ id: string; name: string } | null>;
26
- };
27
- saveConfig?: (updates: Record<string, unknown>) => Promise<void>;
28
- getAgentName?: () => string;
29
- getAgentPronouns?: () => string;
30
- getAgentConfig?: () => Record<string, unknown>;
31
- getSoulContent?: () => Promise<string | null>;
32
- saveSoulContent?: (content: string) => Promise<void>;
33
- hasSoulFile?: () => Promise<boolean>;
34
- vaultExists?: () => Promise<boolean>;
35
- onSetupComplete?: () => Promise<void>;
36
- }
37
-
38
- export interface DashboardDeps {
39
- vault: {
40
- get(name: string): string | undefined;
41
- has(name: string): boolean;
42
- add(name: string, value: string): Promise<void>;
43
- unlock(password: string): Promise<void>;
44
- changePassword(newPassword: string): Promise<void>;
45
- };
46
- onVaultUnlocked?: () => Promise<void>;
47
- getActiveModel?: () => { provider: string; model: string };
48
- behaviors?: {
49
- list(filter?: { type?: string; status?: string }): Promise<any[]>;
50
- get(id: string): Promise<any | undefined>;
51
- create(input: Record<string, unknown>): Promise<any>;
52
- update(id: string, updates: Record<string, unknown>): Promise<any>;
53
- remove(id: string): Promise<boolean>;
54
- };
55
- webhooks?: {
56
- list(): Promise<any[]>;
57
- create(options: Record<string, unknown>): Promise<any>;
58
- update?(id: string, updates: Record<string, unknown>): Promise<any>;
59
- delete(id: string): Promise<boolean>;
60
- };
61
- getConfiguredChannels?: () => Array<{ type: string; enabled: boolean }>;
62
- getActiveAgents?: () => Array<{
63
- id: string;
64
- type: string;
65
- description: string;
66
- channelType?: string;
67
- startedAt: string;
68
- }>;
69
- getConnections: () => Array<{
70
- id: string;
71
- authenticated: boolean;
72
- channelType: string;
73
- lastActive: number;
74
- voiceActive?: boolean;
75
- }>;
76
- getAuditEntries: (limit?: number) => Promise<any[]>;
77
- getPlugins?: () => Array<{
78
- name: string;
79
- version: string;
80
- file: string;
81
- toolCount: number;
82
- toolNames: string[];
83
- behaviorNames: string[];
84
- providerNames: string[];
85
- permissions: string[];
86
- status: string;
87
- error?: string;
88
- }>;
89
- pluginManager?: {
90
- enable(id: string): Promise<boolean>;
91
- disable(id: string): Promise<boolean>;
92
- remove(id: string): Promise<boolean>;
93
- getConfig(id: string): Record<string, unknown> | null;
94
- setConfig(id: string, config: Record<string, unknown>): Promise<boolean>;
95
- getPermissions(id: string): string[] | null;
96
- setPermissions(id: string, permissions: string[]): Promise<boolean>;
97
- };
98
- marketplace?: {
99
- search(query: string): Promise<any[]>;
100
- getPlugin(id: string): Promise<any | null>;
101
- install(id: string): Promise<{ success: boolean; error?: string }>;
102
- };
103
- getMemories?: () => Promise<Array<{
104
- id: string;
105
- content: string;
106
- category: string;
107
- source: string;
108
- createdAt: number;
109
- updatedAt: number;
110
- accessCount: number;
111
- }>>;
112
- memory?: {
113
- getLivingState(): Promise<{
114
- facts: any[];
115
- relationships: any[];
116
- patterns: any[];
117
- adaptations: any[];
118
- stats: any;
119
- }>;
120
- getStats(): Promise<any>;
121
- getAdaptations(): Promise<any[]>;
122
- deleteMemory(id: string): Promise<boolean>;
123
- exportAll(): Promise<any>;
124
- importAll(data: { memories: any[] }): Promise<{ imported: number; skipped: number }>;
125
- };
126
- setup?: SetupDeps;
127
- orchestration?: {
128
- getConfig(): {
129
- enabled: boolean;
130
- maxConcurrentAgents: number;
131
- allowedPatterns: string[];
132
- };
133
- getHistory(limit?: number): Array<{
134
- workflowId: string;
135
- pattern: string;
136
- taskCount: number;
137
- totalCost: number;
138
- duration: number;
139
- timestamp: number;
140
- }>;
141
- };
142
- models?: {
143
- listProviders(): Array<{
144
- name: string;
145
- displayName: string;
146
- available: boolean;
147
- models: Record<string, unknown>;
148
- }>;
149
- getRoutingConfig(): {
150
- enabled: boolean;
151
- primary: string;
152
- fallback?: string;
153
- defaultModel?: string;
154
- rules: unknown[];
155
- preferences: Record<string, unknown>;
156
- costLimits: Record<string, unknown>;
157
- };
158
- getCostSummary(): {
159
- today: number;
160
- thisMonth: number;
161
- budgetRemaining?: number;
162
- isOverBudget: boolean;
163
- warningThresholdReached: boolean;
164
- };
165
- };
166
- // --- [P13] Connectors ---
167
- connectors?: {
168
- list(): Array<{ id: string; name: string; category: string; auth: { type: string } }>;
169
- get(id: string): any | undefined;
170
- connect(connectorId: string, credentials: Record<string, string>, label?: string): Promise<any | null>;
171
- disconnect(connectorId: string): Promise<boolean>;
172
- getActions(connectorId: string): any[];
173
- executeAction(connectorId: string, actionId: string, params: Record<string, unknown>): Promise<{ success: boolean; data?: unknown; error?: string }>;
174
- };
175
- // --- Trust / Autonomy (Phase 12) ---
176
- trust?: {
177
- getLevels(): Record<string, number>;
178
- getLevel(domain: string): number;
179
- setLevel(domain: string, level: number, reason: string): Promise<void>;
180
- getAuditEntries(limit?: number): any[];
181
- getAuditEntry(id: string): any | undefined;
182
- rollback(id: string): Promise<{ success: boolean; error?: string }>;
183
- getPromotions(): any[];
184
- };
185
- // --- [P6] Desktop ---
186
- desktop?: {
187
- getStatus(): {
188
- status: string;
189
- autoStart: boolean;
190
- hotkey: string;
191
- notificationsEnabled: boolean;
192
- ollamaRunning: boolean;
193
- updateChannel: string;
194
- };
195
- updateConfig(updates: Record<string, unknown>): Promise<Record<string, unknown>>;
196
- sendNotification(payload: { title: string; body: string }): Promise<void>;
197
- checkUpdates(): Promise<{
198
- available: boolean;
199
- currentVersion: string;
200
- latestVersion?: string;
201
- channel: string;
202
- }>;
203
- };
204
- // --- Cloud (Phase 7) ---
205
- cloud?: import('./cloud-types.js').CloudDeps;
206
- // --- [P14] Team / Social ---
207
- team?: {
208
- listUsers(): Promise<any[]>;
209
- createUser(name: string, role: string, channels?: any[]): Promise<any>;
210
- deleteUser(id: string): Promise<boolean>;
211
- };
212
- // --- [P14] Workflows ---
213
- workflows?: {
214
- listActive(): Promise<any[]>;
215
- listAll(): Promise<any[]>;
216
- getStatus(id: string): Promise<any | undefined>;
217
- createWorkflow(options: any): Promise<any>;
218
- completeStep(workflowId: string, stepId: string, completedBy: string): Promise<any>;
219
- cancelWorkflow(id: string): Promise<boolean>;
220
- getPendingApprovals(userId?: string): Promise<any[]>;
221
- approve(id: string, userId: string, reason?: string): Promise<any>;
222
- reject(id: string, userId: string, reason?: string): Promise<any>;
223
- };
224
- // --- [P14] Agent Protocol ---
225
- agentProtocol?: {
226
- getIdentity(): any;
227
- getInbox(limit?: number): any[];
228
- discover(query: string): Promise<any[]>;
229
- getDirectory(): Promise<any[]>;
230
- };
231
- // --- [P15] Screen ---
232
- screen?: {
233
- capture(): Promise<{ image: string; dimensions: { width: number; height: number } }>;
234
- analyze(question?: string): Promise<string>;
235
- };
236
- // --- [P15] Ambient ---
237
- ambient?: {
238
- getPatterns(): any[];
239
- getNotifications(): any[];
240
- dismissNotification(id: string): boolean;
241
- getBriefing(time: string): any;
242
- getAnticipations(): any[];
243
- };
244
- // --- [P15] Conversation ---
245
- conversation?: {
246
- getState(): string;
247
- start(): void;
248
- stop(): void;
249
- getTurnCount(): number;
250
- };
251
- // --- Chat session history ---
252
- sessions?: {
253
- getWebchatMessages(): Promise<Array<{ id: string; role: string; content: string; timestamp: number }>>;
254
- listChats(options?: { archived?: boolean; limit?: number; offset?: number }): Array<{ id: string; title: string; channel: string; createdAt: number; updatedAt: number; archived: boolean }>;
255
- createChat(title?: string): { id: string; title: string; channel: string; createdAt: number; updatedAt: number; archived: boolean };
256
- renameChat(chatId: string, title: string): void;
257
- archiveChat(chatId: string): void;
258
- deleteChat(chatId: string): void;
259
- getChatMessages(chatId: string): Array<{ id: string; role: string; content: string; timestamp: number }>;
260
- };
261
- }
262
-
263
- export const DEFAULT_DASHBOARD_CONFIG: DashboardConfig = {
264
- enabled: false,
265
- sessionTtlMs: 86_400_000,
266
- };
267
-
268
- export const MAX_LOGIN_ATTEMPTS = 5;
269
- export const LOGIN_WINDOW_MS = 60_000;
@@ -1,51 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { DashboardAuth } from '../src/auth.js';
3
- import { MAX_LOGIN_ATTEMPTS } from '../src/types.js';
4
-
5
- describe('DashboardAuth', () => {
6
- let auth: DashboardAuth;
7
-
8
- beforeEach(() => {
9
- auth = new DashboardAuth(3_600_000); // 1 hour TTL
10
- });
11
-
12
- it('should create and validate a session', () => {
13
- const sessionId = auth.createSession('127.0.0.1');
14
- expect(auth.validateSession(sessionId)).toBe(true);
15
- });
16
-
17
- it('should reject unknown session', () => {
18
- expect(auth.validateSession('nonexistent')).toBe(false);
19
- });
20
-
21
- it('should expire sessions after TTL', () => {
22
- const shortAuth = new DashboardAuth(1); // 1ms TTL
23
- const sessionId = shortAuth.createSession('127.0.0.1');
24
-
25
- // Wait for expiry
26
- vi.useFakeTimers();
27
- vi.advanceTimersByTime(10);
28
- expect(shortAuth.validateSession(sessionId)).toBe(false);
29
- vi.useRealTimers();
30
- });
31
-
32
- it('should destroy a session on logout', () => {
33
- const sessionId = auth.createSession('127.0.0.1');
34
- expect(auth.destroySession(sessionId)).toBe(true);
35
- expect(auth.validateSession(sessionId)).toBe(false);
36
- });
37
-
38
- it('should rate limit after max attempts', () => {
39
- const ip = '192.168.1.1';
40
- for (let i = 0; i < MAX_LOGIN_ATTEMPTS; i++) {
41
- auth.recordAttempt(ip);
42
- }
43
- expect(auth.isRateLimited(ip)).toBe(true);
44
- });
45
-
46
- it('should not rate limit under the threshold', () => {
47
- const ip = '192.168.1.1';
48
- auth.recordAttempt(ip);
49
- expect(auth.isRateLimited(ip)).toBe(false);
50
- });
51
- });
@@ -1,249 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import express from 'express';
3
- import request from 'supertest';
4
- import { createDashboardRouter } from '../src/router.js';
5
- import type { DashboardDeps } from '../src/types.js';
6
- import type { CloudDeps } from '../src/cloud-types.js';
7
-
8
- function createMockCloud(): CloudDeps {
9
- return {
10
- signup: vi.fn().mockResolvedValue({ tenantId: 'tenant-123', token: 'jwt-token-abc' }),
11
- login: vi.fn().mockResolvedValue({ tenantId: 'tenant-123', token: 'jwt-token-abc' }),
12
- getTenant: vi.fn().mockResolvedValue({
13
- id: 'tenant-123',
14
- name: 'Alice',
15
- email: 'alice@test.com',
16
- plan: 'pro',
17
- status: 'active',
18
- createdAt: '2025-01-01T00:00:00Z',
19
- }),
20
- changePlan: vi.fn().mockResolvedValue({ success: true }),
21
- getUsage: vi.fn().mockResolvedValue({
22
- usage: { maxMessages: 42 },
23
- quotas: { maxMessages: 5000 },
24
- }),
25
- getBilling: vi.fn().mockResolvedValue({
26
- plan: 'pro',
27
- invoices: [{ id: 'inv_1', amount: 1900, status: 'paid', created: '2025-01-01' }],
28
- }),
29
- addPaymentMethod: vi.fn().mockResolvedValue({ success: true }),
30
- exportData: vi.fn().mockResolvedValue({ downloadUrl: '/exports/tenant-123.zip' }),
31
- deleteTenant: vi.fn().mockResolvedValue({ success: true }),
32
- };
33
- }
34
-
35
- function createMockDeps(cloud?: CloudDeps): DashboardDeps {
36
- return {
37
- vault: {
38
- get: vi.fn(),
39
- has: vi.fn().mockReturnValue(false),
40
- add: vi.fn(),
41
- },
42
- getConnections: vi.fn().mockReturnValue([]),
43
- getAuditEntries: vi.fn().mockResolvedValue([]),
44
- cloud,
45
- };
46
- }
47
-
48
- function createApp(deps: DashboardDeps) {
49
- const app = express();
50
- app.use(express.json());
51
- const { router, auth } = createDashboardRouter({
52
- deps,
53
- config: { enabled: true, sessionTtlMs: 86_400_000 },
54
- verifyPassword: (input: string) => input === 'correct-password',
55
- });
56
- app.use('/api/v1/dashboard', router);
57
- return { app, auth };
58
- }
59
-
60
- function loginAndGetCookie(app: express.Express): Promise<string> {
61
- return request(app)
62
- .post('/api/v1/dashboard/auth/login')
63
- .send({ password: 'correct-password' })
64
- .then((res) => {
65
- const cookie = res.headers['set-cookie'];
66
- return Array.isArray(cookie) ? cookie[0] : cookie;
67
- });
68
- }
69
-
70
- describe('Cloud Dashboard Routes', () => {
71
- let cloud: CloudDeps;
72
- let app: express.Express;
73
-
74
- beforeEach(() => {
75
- cloud = createMockCloud();
76
- const deps = createMockDeps(cloud);
77
- ({ app } = createApp(deps));
78
- });
79
-
80
- describe('POST /cloud/signup', () => {
81
- it('should create a new tenant', async () => {
82
- const cookie = await loginAndGetCookie(app);
83
- const res = await request(app)
84
- .post('/api/v1/dashboard/cloud/signup')
85
- .set('Cookie', cookie)
86
- .send({ email: 'alice@test.com', name: 'Alice', password: 'secret123' });
87
- expect(res.status).toBe(201);
88
- expect(res.body.data.tenantId).toBe('tenant-123');
89
- expect(res.body.data.token).toBeDefined();
90
- });
91
-
92
- it('should reject missing fields', async () => {
93
- const cookie = await loginAndGetCookie(app);
94
- const res = await request(app)
95
- .post('/api/v1/dashboard/cloud/signup')
96
- .set('Cookie', cookie)
97
- .send({ email: 'alice@test.com' });
98
- expect(res.status).toBe(400);
99
- });
100
-
101
- it('should return 503 when cloud not configured', async () => {
102
- const deps = createMockDeps(); // no cloud
103
- const { app: noCloudApp } = createApp(deps);
104
- const cookie = await loginAndGetCookie(noCloudApp);
105
- const res = await request(noCloudApp)
106
- .post('/api/v1/dashboard/cloud/signup')
107
- .set('Cookie', cookie)
108
- .send({ email: 'a@b.com', name: 'A', password: 'pass' });
109
- expect(res.status).toBe(503);
110
- });
111
- });
112
-
113
- describe('POST /cloud/login', () => {
114
- it('should login a tenant', async () => {
115
- const cookie = await loginAndGetCookie(app);
116
- const res = await request(app)
117
- .post('/api/v1/dashboard/cloud/login')
118
- .set('Cookie', cookie)
119
- .send({ email: 'alice@test.com', password: 'secret123' });
120
- expect(res.status).toBe(200);
121
- expect(res.body.data.token).toBeDefined();
122
- });
123
-
124
- it('should reject invalid credentials', async () => {
125
- (cloud.login as any).mockResolvedValue(null);
126
- const cookie = await loginAndGetCookie(app);
127
- const res = await request(app)
128
- .post('/api/v1/dashboard/cloud/login')
129
- .set('Cookie', cookie)
130
- .send({ email: 'alice@test.com', password: 'wrong' });
131
- expect(res.status).toBe(401);
132
- });
133
- });
134
-
135
- describe('GET /cloud/tenant', () => {
136
- it('should return tenant info', async () => {
137
- const cookie = await loginAndGetCookie(app);
138
- const res = await request(app)
139
- .get('/api/v1/dashboard/cloud/tenant')
140
- .set('Cookie', cookie)
141
- .set('x-tenant-id', 'tenant-123');
142
- expect(res.status).toBe(200);
143
- expect(res.body.data.email).toBe('alice@test.com');
144
- });
145
-
146
- it('should require x-tenant-id header', async () => {
147
- const cookie = await loginAndGetCookie(app);
148
- const res = await request(app)
149
- .get('/api/v1/dashboard/cloud/tenant')
150
- .set('Cookie', cookie);
151
- expect(res.status).toBe(400);
152
- });
153
-
154
- it('should return 404 for unknown tenant', async () => {
155
- (cloud.getTenant as any).mockResolvedValue(null);
156
- const cookie = await loginAndGetCookie(app);
157
- const res = await request(app)
158
- .get('/api/v1/dashboard/cloud/tenant')
159
- .set('Cookie', cookie)
160
- .set('x-tenant-id', 'nonexistent');
161
- expect(res.status).toBe(404);
162
- });
163
- });
164
-
165
- describe('POST /cloud/tenant/plan', () => {
166
- it('should change plan', async () => {
167
- const cookie = await loginAndGetCookie(app);
168
- const res = await request(app)
169
- .post('/api/v1/dashboard/cloud/tenant/plan')
170
- .set('Cookie', cookie)
171
- .set('x-tenant-id', 'tenant-123')
172
- .send({ plan: 'team' });
173
- expect(res.status).toBe(200);
174
- expect(res.body.data.success).toBe(true);
175
- });
176
- });
177
-
178
- describe('GET /cloud/tenant/usage', () => {
179
- it('should return usage data', async () => {
180
- const cookie = await loginAndGetCookie(app);
181
- const res = await request(app)
182
- .get('/api/v1/dashboard/cloud/tenant/usage')
183
- .set('Cookie', cookie)
184
- .set('x-tenant-id', 'tenant-123');
185
- expect(res.status).toBe(200);
186
- expect(res.body.data.usage.maxMessages).toBe(42);
187
- });
188
- });
189
-
190
- describe('GET /cloud/tenant/billing', () => {
191
- it('should return billing info', async () => {
192
- const cookie = await loginAndGetCookie(app);
193
- const res = await request(app)
194
- .get('/api/v1/dashboard/cloud/tenant/billing')
195
- .set('Cookie', cookie)
196
- .set('x-tenant-id', 'tenant-123');
197
- expect(res.status).toBe(200);
198
- expect(res.body.data.plan).toBe('pro');
199
- expect(res.body.data.invoices).toHaveLength(1);
200
- });
201
- });
202
-
203
- describe('POST /cloud/tenant/billing/payment-method', () => {
204
- it('should add payment method', async () => {
205
- const cookie = await loginAndGetCookie(app);
206
- const res = await request(app)
207
- .post('/api/v1/dashboard/cloud/tenant/billing/payment-method')
208
- .set('Cookie', cookie)
209
- .set('x-tenant-id', 'tenant-123')
210
- .send({ token: 'tok_visa' });
211
- expect(res.status).toBe(200);
212
- expect(res.body.data.success).toBe(true);
213
- });
214
-
215
- it('should reject missing token', async () => {
216
- const cookie = await loginAndGetCookie(app);
217
- const res = await request(app)
218
- .post('/api/v1/dashboard/cloud/tenant/billing/payment-method')
219
- .set('Cookie', cookie)
220
- .set('x-tenant-id', 'tenant-123')
221
- .send({});
222
- expect(res.status).toBe(400);
223
- });
224
- });
225
-
226
- describe('POST /cloud/tenant/export', () => {
227
- it('should export tenant data', async () => {
228
- const cookie = await loginAndGetCookie(app);
229
- const res = await request(app)
230
- .post('/api/v1/dashboard/cloud/tenant/export')
231
- .set('Cookie', cookie)
232
- .set('x-tenant-id', 'tenant-123');
233
- expect(res.status).toBe(200);
234
- expect(res.body.data.downloadUrl).toBeDefined();
235
- });
236
- });
237
-
238
- describe('DELETE /cloud/tenant', () => {
239
- it('should delete tenant', async () => {
240
- const cookie = await loginAndGetCookie(app);
241
- const res = await request(app)
242
- .delete('/api/v1/dashboard/cloud/tenant')
243
- .set('Cookie', cookie)
244
- .set('x-tenant-id', 'tenant-123');
245
- expect(res.status).toBe(200);
246
- expect(res.body.data.success).toBe(true);
247
- });
248
- });
249
- });