@agentarea/cli 0.1.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/dist/app.d.ts +7 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +32 -0
- package/dist/app.js.map +1 -0
- package/dist/cli-commands.d.ts +9 -0
- package/dist/cli-commands.d.ts.map +1 -0
- package/dist/cli-commands.js +62 -0
- package/dist/cli-commands.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +66 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/agentsList.d.ts +2 -0
- package/dist/commands/agentsList.d.ts.map +1 -0
- package/dist/commands/agentsList.js +67 -0
- package/dist/commands/agentsList.js.map +1 -0
- package/dist/commands/authToken.d.ts +6 -0
- package/dist/commands/authToken.d.ts.map +1 -0
- package/dist/commands/authToken.js +67 -0
- package/dist/commands/authToken.js.map +1 -0
- package/dist/commands/connect.d.ts +10 -0
- package/dist/commands/connect.d.ts.map +1 -0
- package/dist/commands/connect.js +204 -0
- package/dist/commands/connect.js.map +1 -0
- package/dist/commands/interactiveTUI.d.ts +7 -0
- package/dist/commands/interactiveTUI.d.ts.map +1 -0
- package/dist/commands/interactiveTUI.js +186 -0
- package/dist/commands/interactiveTUI.js.map +1 -0
- package/dist/components/ErrorBoundary.d.ts +18 -0
- package/dist/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/components/ErrorBoundary.js +32 -0
- package/dist/components/ErrorBoundary.js.map +1 -0
- package/dist/components/InteractiveCLI.d.ts +7 -0
- package/dist/components/InteractiveCLI.d.ts.map +1 -0
- package/dist/components/InteractiveCLI.js +129 -0
- package/dist/components/InteractiveCLI.js.map +1 -0
- package/dist/components/REPL.d.ts +7 -0
- package/dist/components/REPL.d.ts.map +1 -0
- package/dist/components/REPL.js +153 -0
- package/dist/components/REPL.js.map +1 -0
- package/dist/context/AuthContext.d.ts +28 -0
- package/dist/context/AuthContext.d.ts.map +1 -0
- package/dist/context/AuthContext.js +14 -0
- package/dist/context/AuthContext.js.map +1 -0
- package/dist/hooks/useAgent.d.ts +39 -0
- package/dist/hooks/useAgent.d.ts.map +1 -0
- package/dist/hooks/useAgent.js +125 -0
- package/dist/hooks/useAgent.js.map +1 -0
- package/dist/hooks/useAuth.d.ts +45 -0
- package/dist/hooks/useAuth.d.ts.map +1 -0
- package/dist/hooks/useAuth.js +177 -0
- package/dist/hooks/useAuth.js.map +1 -0
- package/dist/hooks/useSSE.d.ts +32 -0
- package/dist/hooks/useSSE.d.ts.map +1 -0
- package/dist/hooks/useSSE.js +113 -0
- package/dist/hooks/useSSE.js.map +1 -0
- package/dist/services/agent.d.ts +13 -0
- package/dist/services/agent.d.ts.map +1 -0
- package/dist/services/agent.js +114 -0
- package/dist/services/agent.js.map +1 -0
- package/dist/services/apiClient.d.ts +25 -0
- package/dist/services/apiClient.d.ts.map +1 -0
- package/dist/services/apiClient.js +258 -0
- package/dist/services/apiClient.js.map +1 -0
- package/dist/services/auth.d.ts +20 -0
- package/dist/services/auth.d.ts.map +1 -0
- package/dist/services/auth.js +147 -0
- package/dist/services/auth.js.map +1 -0
- package/dist/services/sse.d.ts +18 -0
- package/dist/services/sse.d.ts.map +1 -0
- package/dist/services/sse.js +153 -0
- package/dist/services/sse.js.map +1 -0
- package/dist/services/task.d.ts +15 -0
- package/dist/services/task.d.ts.map +1 -0
- package/dist/services/task.js +110 -0
- package/dist/services/task.js.map +1 -0
- package/dist/tui.d.ts +6 -0
- package/dist/tui.d.ts.map +1 -0
- package/dist/tui.js +94 -0
- package/dist/tui.js.map +1 -0
- package/dist/types/index.d.ts +119 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/config.d.ts +14 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +146 -0
- package/dist/utils/config.js.map +1 -0
- package/dist/utils/error.d.ts +33 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +83 -0
- package/dist/utils/error.js.map +1 -0
- package/dist/utils/formatting.d.ts +18 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/formatting.js +62 -0
- package/dist/utils/formatting.js.map +1 -0
- package/dist/utils/logger.d.ts +14 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +49 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/signals.d.ts +10 -0
- package/dist/utils/signals.d.ts.map +1 -0
- package/dist/utils/signals.js +71 -0
- package/dist/utils/signals.js.map +1 -0
- package/dist/utils/storage.d.ts +11 -0
- package/dist/utils/storage.d.ts.map +1 -0
- package/dist/utils/storage.js +73 -0
- package/dist/utils/storage.js.map +1 -0
- package/package.json +103 -0
- package/readme.md +229 -0
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { apiClient } from './apiClient.js';
|
|
2
|
+
import { logger } from '../utils/logger.js';
|
|
3
|
+
import { NetworkError } from '../utils/error.js';
|
|
4
|
+
export class AgentService {
|
|
5
|
+
async fetchAgents(skip = 0, limit = 50, status, search) {
|
|
6
|
+
try {
|
|
7
|
+
const params = new URLSearchParams();
|
|
8
|
+
params.append('skip', String(skip));
|
|
9
|
+
params.append('limit', String(limit));
|
|
10
|
+
if (status) {
|
|
11
|
+
params.append('status', status);
|
|
12
|
+
}
|
|
13
|
+
if (search) {
|
|
14
|
+
params.append('search', search);
|
|
15
|
+
}
|
|
16
|
+
// AgentArea API uses /v1/agents endpoint
|
|
17
|
+
const response = await apiClient
|
|
18
|
+
.getClient()
|
|
19
|
+
.get(`/v1/agents?${params.toString()}`);
|
|
20
|
+
const agentList = {
|
|
21
|
+
agents: response.data.agents,
|
|
22
|
+
total: response.data.total,
|
|
23
|
+
timestamp: new Date(response.data.timestamp),
|
|
24
|
+
};
|
|
25
|
+
logger.debug(`Fetched ${agentList.agents.length} agents`);
|
|
26
|
+
return agentList;
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
logger.error('Failed to fetch agents:', error);
|
|
30
|
+
throw new NetworkError(`Failed to fetch agents: ${error}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async getAgent(agentId) {
|
|
34
|
+
try {
|
|
35
|
+
const response = await apiClient
|
|
36
|
+
.getClient()
|
|
37
|
+
.get(`/v1/agents/${agentId}`);
|
|
38
|
+
logger.debug(`Fetched agent ${agentId}`);
|
|
39
|
+
return response.data;
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
logger.error(`Failed to fetch agent ${agentId}:`, error);
|
|
43
|
+
throw new NetworkError(`Failed to fetch agent: ${error}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async getAgentCapabilities(agentId) {
|
|
47
|
+
try {
|
|
48
|
+
// Get agent details which includes capabilities
|
|
49
|
+
const agent = await this.getAgent(agentId);
|
|
50
|
+
logger.debug(`Fetched ${agent.capabilities.length} capabilities for agent ${agentId}`);
|
|
51
|
+
return agent.capabilities;
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
logger.error(`Failed to fetch capabilities for agent ${agentId}:`, error);
|
|
55
|
+
throw new NetworkError(`Failed to fetch agent capabilities: ${error}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
filterAgents(agents, status, search) {
|
|
59
|
+
let filtered = agents;
|
|
60
|
+
if (status) {
|
|
61
|
+
filtered = filtered.filter(agent => agent.status === status);
|
|
62
|
+
}
|
|
63
|
+
if (search) {
|
|
64
|
+
const searchLower = search.toLowerCase();
|
|
65
|
+
filtered = filtered.filter(agent => agent.name.toLowerCase().includes(searchLower) ||
|
|
66
|
+
(agent.description?.toLowerCase().includes(searchLower) ?? false));
|
|
67
|
+
}
|
|
68
|
+
return filtered;
|
|
69
|
+
}
|
|
70
|
+
paginateAgents(agents, skip, limit) {
|
|
71
|
+
return agents.slice(skip, skip + limit);
|
|
72
|
+
}
|
|
73
|
+
async searchAgents(query) {
|
|
74
|
+
try {
|
|
75
|
+
const agentList = await this.fetchAgents(0, 100, undefined, query);
|
|
76
|
+
return agentList.agents;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
logger.error('Failed to search agents:', error);
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
getAgentStatusColor(status) {
|
|
84
|
+
switch (status) {
|
|
85
|
+
case 'online':
|
|
86
|
+
return 'green';
|
|
87
|
+
case 'offline':
|
|
88
|
+
return 'gray';
|
|
89
|
+
case 'busy':
|
|
90
|
+
return 'yellow';
|
|
91
|
+
case 'error':
|
|
92
|
+
return 'red';
|
|
93
|
+
default:
|
|
94
|
+
return 'white';
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
getAgentStatusIcon(status) {
|
|
98
|
+
switch (status) {
|
|
99
|
+
case 'online':
|
|
100
|
+
return '🟢';
|
|
101
|
+
case 'offline':
|
|
102
|
+
return '⚪';
|
|
103
|
+
case 'busy':
|
|
104
|
+
return '🟡';
|
|
105
|
+
case 'error':
|
|
106
|
+
return '🔴';
|
|
107
|
+
default:
|
|
108
|
+
return '⚪';
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Export a singleton instance
|
|
113
|
+
export const agentService = new AgentService();
|
|
114
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../source/services/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import axios, { type AxiosInstance, type AxiosError } from 'axios';
|
|
2
|
+
import { type AuthToken } from '../types/index.js';
|
|
3
|
+
declare class ApiClient {
|
|
4
|
+
private client;
|
|
5
|
+
private currentToken;
|
|
6
|
+
private on401Callback;
|
|
7
|
+
constructor();
|
|
8
|
+
private setupInterceptors;
|
|
9
|
+
initialize(): Promise<void>;
|
|
10
|
+
setToken(token: AuthToken): void;
|
|
11
|
+
login(email: string, password: string): Promise<AuthToken>;
|
|
12
|
+
refreshToken(): Promise<AuthToken>;
|
|
13
|
+
logout(): Promise<void>;
|
|
14
|
+
private extractCsrfToken;
|
|
15
|
+
private extractSessionToken;
|
|
16
|
+
set401Callback(callback: (error: AxiosError) => Promise<void>): void;
|
|
17
|
+
reinitialize(): void;
|
|
18
|
+
getClient(): AxiosInstance;
|
|
19
|
+
getToken(): AuthToken | null;
|
|
20
|
+
hasToken(): boolean;
|
|
21
|
+
clearToken(): void;
|
|
22
|
+
}
|
|
23
|
+
export declare const apiClient: ApiClient;
|
|
24
|
+
export { axios };
|
|
25
|
+
//# sourceMappingURL=apiClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.d.ts","sourceRoot":"","sources":["../../source/services/apiClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAC,KAAK,aAAa,EAAE,KAAK,UAAU,EAAC,MAAM,OAAO,CAAC;AAKjE,OAAO,EAAC,KAAK,SAAS,EAAC,MAAM,mBAAmB,CAAC;AAEjD,cAAM,SAAS;IACd,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,YAAY,CAA0B;IAC9C,OAAO,CAAC,aAAa,CAAuD;;IAgB5E,OAAO,CAAC,iBAAiB;IA8DnB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA4BjC,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAK1B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAuE1D,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IA8BlC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAqB7B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,mBAAmB;IAgB3B,cAAc,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIpE,YAAY,IAAI,IAAI;IAgBpB,SAAS,IAAI,aAAa;IAI1B,QAAQ,IAAI,SAAS,GAAG,IAAI;IAI5B,QAAQ,IAAI,OAAO;IAInB,UAAU,IAAI,IAAI;CAIlB;AAGD,eAAO,MAAM,SAAS,WAAkB,CAAC;AAGzC,OAAO,EAAC,KAAK,EAAC,CAAC"}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import axios from 'axios';
|
|
2
|
+
import { tokenStorage } from '../utils/storage.js';
|
|
3
|
+
import { configManager } from '../utils/config.js';
|
|
4
|
+
import { logger } from '../utils/logger.js';
|
|
5
|
+
import { NetworkError, AuthenticationError } from '../utils/error.js';
|
|
6
|
+
class ApiClient {
|
|
7
|
+
constructor() {
|
|
8
|
+
Object.defineProperty(this, "client", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true,
|
|
12
|
+
value: void 0
|
|
13
|
+
});
|
|
14
|
+
Object.defineProperty(this, "currentToken", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: null
|
|
19
|
+
});
|
|
20
|
+
Object.defineProperty(this, "on401Callback", {
|
|
21
|
+
enumerable: true,
|
|
22
|
+
configurable: true,
|
|
23
|
+
writable: true,
|
|
24
|
+
value: null
|
|
25
|
+
});
|
|
26
|
+
const config = configManager.get();
|
|
27
|
+
this.client = axios.create({
|
|
28
|
+
baseURL: config.apiBaseUrl,
|
|
29
|
+
timeout: config.apiTimeout,
|
|
30
|
+
headers: {
|
|
31
|
+
'Content-Type': 'application/json',
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
this.setupInterceptors();
|
|
35
|
+
}
|
|
36
|
+
setupInterceptors() {
|
|
37
|
+
// Add request interceptor to include auth token
|
|
38
|
+
this.client.interceptors.request.use(config => {
|
|
39
|
+
if (this.currentToken) {
|
|
40
|
+
config.headers.Authorization = `${this.currentToken.tokenType} ${this.currentToken.accessToken}`;
|
|
41
|
+
}
|
|
42
|
+
return config;
|
|
43
|
+
}, error => {
|
|
44
|
+
return Promise.reject(error);
|
|
45
|
+
});
|
|
46
|
+
// Add response interceptor to handle token refresh and 401 errors
|
|
47
|
+
this.client.interceptors.response.use(response => response, async (error) => {
|
|
48
|
+
const originalConfig = error.config;
|
|
49
|
+
// Handle 401 Unauthorized
|
|
50
|
+
if (error.response?.status === 401 &&
|
|
51
|
+
originalConfig &&
|
|
52
|
+
!originalConfig._retry) {
|
|
53
|
+
originalConfig._retry = true;
|
|
54
|
+
try {
|
|
55
|
+
if (this.currentToken?.refreshToken) {
|
|
56
|
+
// Try to refresh token if available
|
|
57
|
+
const newToken = await this.refreshToken();
|
|
58
|
+
this.currentToken = newToken;
|
|
59
|
+
await tokenStorage.saveToken(newToken);
|
|
60
|
+
// Retry the original request with new token
|
|
61
|
+
return this.client(originalConfig);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// No refresh token available, invoke callback if set
|
|
65
|
+
if (this.on401Callback) {
|
|
66
|
+
await this.on401Callback(error);
|
|
67
|
+
// After callback, retry the request with potentially updated token
|
|
68
|
+
return this.client(originalConfig);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch (refreshError) {
|
|
73
|
+
logger.error('Token refresh failed:', refreshError);
|
|
74
|
+
// Token refresh failed, user needs to re-authenticate
|
|
75
|
+
await tokenStorage.clearToken();
|
|
76
|
+
this.currentToken = null;
|
|
77
|
+
throw new AuthenticationError('Session expired. Please login again.');
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return Promise.reject(error);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async initialize() {
|
|
84
|
+
try {
|
|
85
|
+
// Load stored token if available
|
|
86
|
+
const storedToken = await tokenStorage.getToken();
|
|
87
|
+
if (storedToken) {
|
|
88
|
+
// Check if token needs refresh
|
|
89
|
+
if (tokenStorage.shouldRefreshToken(storedToken)) {
|
|
90
|
+
logger.debug('Refreshing stored token');
|
|
91
|
+
const newToken = await this.refreshToken();
|
|
92
|
+
this.currentToken = newToken;
|
|
93
|
+
await tokenStorage.saveToken(newToken);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
this.currentToken = storedToken;
|
|
97
|
+
}
|
|
98
|
+
logger.debug('API client initialized with stored token');
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
logger.debug('No stored token found, API client initialized without auth');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
logger.error('Failed to initialize API client:', error);
|
|
106
|
+
throw new NetworkError(`Failed to initialize API client: ${error}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
setToken(token) {
|
|
110
|
+
this.currentToken = token;
|
|
111
|
+
logger.debug('API client token updated');
|
|
112
|
+
}
|
|
113
|
+
async login(email, password) {
|
|
114
|
+
try {
|
|
115
|
+
const config = configManager.get();
|
|
116
|
+
// Use Kratos for authentication via self-service API
|
|
117
|
+
// 1. Create a login flow
|
|
118
|
+
const flowResponse = await axios.get(`${config.kratosUrl}/self-service/login/api`, {
|
|
119
|
+
withCredentials: true,
|
|
120
|
+
headers: {
|
|
121
|
+
Accept: 'application/json',
|
|
122
|
+
},
|
|
123
|
+
});
|
|
124
|
+
const flowId = flowResponse.data.id;
|
|
125
|
+
if (!flowId) {
|
|
126
|
+
throw new AuthenticationError('Failed to create login flow');
|
|
127
|
+
}
|
|
128
|
+
logger.debug(`Created login flow: ${flowId}`);
|
|
129
|
+
// 2. Submit login credentials to Kratos
|
|
130
|
+
const submitResponse = await axios.post(`${config.kratosUrl}/self-service/login?flow=${flowId}`, {
|
|
131
|
+
csrf_token: this.extractCsrfToken(flowResponse.data),
|
|
132
|
+
method: 'password',
|
|
133
|
+
password,
|
|
134
|
+
identifier: email,
|
|
135
|
+
}, {
|
|
136
|
+
withCredentials: true,
|
|
137
|
+
validateStatus: () => true,
|
|
138
|
+
});
|
|
139
|
+
// Check if login was successful (Kratos redirects on success)
|
|
140
|
+
if (submitResponse.status >= 400) {
|
|
141
|
+
throw new AuthenticationError('Invalid email or password');
|
|
142
|
+
}
|
|
143
|
+
// Extract session token from cookies (Kratos sets ory_kratos_session)
|
|
144
|
+
const sessionToken = this.extractSessionToken(submitResponse.headers);
|
|
145
|
+
if (!sessionToken) {
|
|
146
|
+
throw new AuthenticationError('Failed to obtain session token');
|
|
147
|
+
}
|
|
148
|
+
const token = {
|
|
149
|
+
accessToken: sessionToken,
|
|
150
|
+
tokenType: 'Bearer',
|
|
151
|
+
expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000), // 24h default
|
|
152
|
+
};
|
|
153
|
+
this.currentToken = token;
|
|
154
|
+
logger.info('Successfully logged in');
|
|
155
|
+
return token;
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
logger.error('Login failed:', error);
|
|
159
|
+
if (error instanceof AuthenticationError) {
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
throw new NetworkError(`Login failed: ${error}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
async refreshToken() {
|
|
166
|
+
try {
|
|
167
|
+
if (!this.currentToken?.refreshToken) {
|
|
168
|
+
throw new AuthenticationError('No refresh token available');
|
|
169
|
+
}
|
|
170
|
+
const response = await this.client.post('/auth/refresh', {
|
|
171
|
+
refreshToken: this.currentToken.refreshToken,
|
|
172
|
+
});
|
|
173
|
+
const token = {
|
|
174
|
+
accessToken: response.data.accessToken,
|
|
175
|
+
refreshToken: this.currentToken.refreshToken,
|
|
176
|
+
tokenType: 'Bearer',
|
|
177
|
+
expiresAt: response.data.expiresIn
|
|
178
|
+
? new Date(Date.now() + response.data.expiresIn * 1000)
|
|
179
|
+
: undefined,
|
|
180
|
+
};
|
|
181
|
+
logger.debug('Token refreshed successfully');
|
|
182
|
+
return token;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
logger.error('Token refresh failed:', error);
|
|
186
|
+
throw new AuthenticationError(`Token refresh failed: ${error}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async logout() {
|
|
190
|
+
try {
|
|
191
|
+
const config = configManager.get();
|
|
192
|
+
// Logout from Kratos
|
|
193
|
+
await axios.get(`${config.kratosUrl}/self-service/logout/browser`, {
|
|
194
|
+
withCredentials: true,
|
|
195
|
+
});
|
|
196
|
+
this.currentToken = null;
|
|
197
|
+
logger.info('Successfully logged out');
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
logger.warn('Logout failed (may be expected if session already expired):', error);
|
|
201
|
+
// Clear token anyway
|
|
202
|
+
this.currentToken = null;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
extractCsrfToken(html) {
|
|
206
|
+
// Extract CSRF token from Kratos login form HTML
|
|
207
|
+
const match = html.match(/name="csrf_token"\s+value="([^"]+)"/);
|
|
208
|
+
return match ? match[1] : '';
|
|
209
|
+
}
|
|
210
|
+
extractSessionToken(headers) {
|
|
211
|
+
// Extract session token from Set-Cookie header
|
|
212
|
+
const setCookie = headers['set-cookie'];
|
|
213
|
+
if (Array.isArray(setCookie)) {
|
|
214
|
+
for (const cookie of setCookie) {
|
|
215
|
+
if (cookie.includes('ory_kratos_session')) {
|
|
216
|
+
const match = cookie.match(/ory_kratos_session=([^;]+)/);
|
|
217
|
+
if (match) {
|
|
218
|
+
return match[1];
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
set401Callback(callback) {
|
|
226
|
+
this.on401Callback = callback;
|
|
227
|
+
}
|
|
228
|
+
reinitialize() {
|
|
229
|
+
const config = configManager.get();
|
|
230
|
+
this.client = axios.create({
|
|
231
|
+
baseURL: config.apiBaseUrl,
|
|
232
|
+
timeout: config.apiTimeout,
|
|
233
|
+
headers: {
|
|
234
|
+
'Content-Type': 'application/json',
|
|
235
|
+
},
|
|
236
|
+
});
|
|
237
|
+
this.setupInterceptors();
|
|
238
|
+
logger.debug('API client reinitialized');
|
|
239
|
+
}
|
|
240
|
+
getClient() {
|
|
241
|
+
return this.client;
|
|
242
|
+
}
|
|
243
|
+
getToken() {
|
|
244
|
+
return this.currentToken;
|
|
245
|
+
}
|
|
246
|
+
hasToken() {
|
|
247
|
+
return this.currentToken !== null;
|
|
248
|
+
}
|
|
249
|
+
clearToken() {
|
|
250
|
+
this.currentToken = null;
|
|
251
|
+
logger.debug('API client token cleared');
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Export a singleton instance
|
|
255
|
+
export const apiClient = new ApiClient();
|
|
256
|
+
// Make axios error checking available
|
|
257
|
+
export { axios };
|
|
258
|
+
//# sourceMappingURL=apiClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../../source/services/apiClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type AuthToken, type User } from '../types/index.js';
|
|
2
|
+
export declare class AuthService {
|
|
3
|
+
private currentUser;
|
|
4
|
+
initialize(): Promise<void>;
|
|
5
|
+
login(email: string, password: string): Promise<{
|
|
6
|
+
token: AuthToken;
|
|
7
|
+
user: User;
|
|
8
|
+
}>;
|
|
9
|
+
logout(): Promise<void>;
|
|
10
|
+
refreshToken(): Promise<AuthToken>;
|
|
11
|
+
isAuthenticated(): Promise<boolean>;
|
|
12
|
+
getToken(): Promise<AuthToken | null>;
|
|
13
|
+
getCurrentUser(): User | null;
|
|
14
|
+
setCurrentUser(user: User): void;
|
|
15
|
+
clearCurrentUser(): void;
|
|
16
|
+
private isValidEmail;
|
|
17
|
+
private extractIdFromToken;
|
|
18
|
+
}
|
|
19
|
+
export declare const authService: AuthService;
|
|
20
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../source/services/auth.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,KAAK,SAAS,EAAE,KAAK,IAAI,EAAC,MAAM,mBAAmB,CAAC;AAE5D,qBAAa,WAAW;IACvB,OAAO,CAAC,WAAW,CAAqB;IAElC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAe3B,KAAK,CACV,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACd,OAAO,CAAC;QAAC,KAAK,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAC,CAAC;IAmCpC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAevB,YAAY,IAAI,OAAO,CAAC,SAAS,CAAC;IAYlC,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC;IAwBnC,QAAQ,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IAS3C,cAAc,IAAI,IAAI,GAAG,IAAI;IAI7B,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAIhC,gBAAgB,IAAI,IAAI;IAIxB,OAAO,CAAC,YAAY;IAKpB,OAAO,CAAC,kBAAkB;CAe1B;AAGD,eAAO,MAAM,WAAW,aAAoB,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { apiClient } from './apiClient.js';
|
|
2
|
+
import { tokenStorage } from '../utils/storage.js';
|
|
3
|
+
import { logger } from '../utils/logger.js';
|
|
4
|
+
import { AuthenticationError } from '../utils/error.js';
|
|
5
|
+
export class AuthService {
|
|
6
|
+
constructor() {
|
|
7
|
+
Object.defineProperty(this, "currentUser", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
configurable: true,
|
|
10
|
+
writable: true,
|
|
11
|
+
value: null
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async initialize() {
|
|
15
|
+
try {
|
|
16
|
+
await apiClient.initialize();
|
|
17
|
+
// Try to load stored token
|
|
18
|
+
const token = await tokenStorage.getToken();
|
|
19
|
+
if (token) {
|
|
20
|
+
apiClient.setToken(token);
|
|
21
|
+
logger.debug('Auth service initialized with stored token');
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
logger.error('Failed to initialize auth service:', error);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async login(email, password) {
|
|
29
|
+
try {
|
|
30
|
+
// Validate input
|
|
31
|
+
if (!email || !password) {
|
|
32
|
+
throw new AuthenticationError('Email and password are required');
|
|
33
|
+
}
|
|
34
|
+
if (!this.isValidEmail(email)) {
|
|
35
|
+
throw new AuthenticationError('Invalid email format');
|
|
36
|
+
}
|
|
37
|
+
// Login via API
|
|
38
|
+
const token = await apiClient.login(email, password);
|
|
39
|
+
// Store token
|
|
40
|
+
await tokenStorage.saveToken(token);
|
|
41
|
+
// Extract user info from token (normally would be in response, but for now using email)
|
|
42
|
+
const user = {
|
|
43
|
+
id: this.extractIdFromToken(token.accessToken),
|
|
44
|
+
email,
|
|
45
|
+
createdAt: new Date(),
|
|
46
|
+
lastLoginAt: new Date(),
|
|
47
|
+
};
|
|
48
|
+
this.currentUser = user;
|
|
49
|
+
logger.info(`User logged in: ${email}`);
|
|
50
|
+
return { token, user };
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
logger.error('Login failed:', error);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async logout() {
|
|
58
|
+
try {
|
|
59
|
+
await apiClient.logout();
|
|
60
|
+
await tokenStorage.clearToken();
|
|
61
|
+
this.currentUser = null;
|
|
62
|
+
logger.info('User logged out');
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
logger.error('Logout failed:', error);
|
|
66
|
+
// Still clear local state even if API call fails
|
|
67
|
+
await tokenStorage.clearToken();
|
|
68
|
+
this.currentUser = null;
|
|
69
|
+
throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
async refreshToken() {
|
|
73
|
+
try {
|
|
74
|
+
const newToken = await apiClient.refreshToken();
|
|
75
|
+
await tokenStorage.saveToken(newToken);
|
|
76
|
+
logger.debug('Token refreshed successfully');
|
|
77
|
+
return newToken;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
logger.error('Token refresh failed:', error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async isAuthenticated() {
|
|
85
|
+
try {
|
|
86
|
+
const token = await tokenStorage.getToken();
|
|
87
|
+
if (!token) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
if (tokenStorage.isTokenExpired(token)) {
|
|
91
|
+
// Try to refresh
|
|
92
|
+
try {
|
|
93
|
+
await this.refreshToken();
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
logger.error('Error checking authentication:', error);
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
async getToken() {
|
|
108
|
+
try {
|
|
109
|
+
return await tokenStorage.getToken();
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
logger.error('Error getting token:', error);
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
getCurrentUser() {
|
|
117
|
+
return this.currentUser;
|
|
118
|
+
}
|
|
119
|
+
setCurrentUser(user) {
|
|
120
|
+
this.currentUser = user;
|
|
121
|
+
}
|
|
122
|
+
clearCurrentUser() {
|
|
123
|
+
this.currentUser = null;
|
|
124
|
+
}
|
|
125
|
+
isValidEmail(email) {
|
|
126
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
127
|
+
return emailRegex.test(email);
|
|
128
|
+
}
|
|
129
|
+
extractIdFromToken(token) {
|
|
130
|
+
// In a real scenario, you would decode the JWT and extract the user ID
|
|
131
|
+
// For now, we'll use a placeholder
|
|
132
|
+
try {
|
|
133
|
+
const parts = token.split('.');
|
|
134
|
+
if (parts.length === 3) {
|
|
135
|
+
const decoded = JSON.parse(Buffer.from(parts[1], 'base64').toString());
|
|
136
|
+
return decoded.sub || decoded.id || 'unknown';
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
logger.debug('Could not decode token payload');
|
|
141
|
+
}
|
|
142
|
+
return 'unknown';
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Export a singleton instance
|
|
146
|
+
export const authService = new AuthService();
|
|
147
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../source/services/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type TaskOutputEvent } from '../types/index.js';
|
|
2
|
+
export type SSEEventHandler = (event: TaskOutputEvent) => void;
|
|
3
|
+
export type SSEErrorHandler = (error: Error) => void;
|
|
4
|
+
export declare class SSEService {
|
|
5
|
+
private eventSources;
|
|
6
|
+
private handlers;
|
|
7
|
+
private reconnectAttempts;
|
|
8
|
+
private maxReconnectAttempts;
|
|
9
|
+
private reconnectDelay;
|
|
10
|
+
connect(taskId: string, onMessage: SSEEventHandler, onError: SSEErrorHandler, token?: string): Promise<void>;
|
|
11
|
+
private handleConnectionError;
|
|
12
|
+
disconnect(taskId: string): void;
|
|
13
|
+
disconnectAll(): void;
|
|
14
|
+
isConnected(taskId: string): boolean;
|
|
15
|
+
getActiveConnections(): string[];
|
|
16
|
+
}
|
|
17
|
+
export declare const sseService: SSEService;
|
|
18
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../source/services/sse.ts"],"names":[],"mappings":"AAIA,OAAO,EAAC,KAAK,eAAe,EAAC,MAAM,mBAAmB,CAAC;AAEvD,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AAC/D,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;AAErD,qBAAa,UAAU;IACtB,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,QAAQ,CAGF;IACd,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,oBAAoB,CAAK;IACjC,OAAO,CAAC,cAAc,CAAQ;IAExB,OAAO,CACZ,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE,eAAe,EACxB,KAAK,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;IAmFhB,OAAO,CAAC,qBAAqB;IAgC7B,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAahC,aAAa,IAAI,IAAI;IAYrB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAOpC,oBAAoB,IAAI,MAAM,EAAE;CAGhC;AAGD,eAAO,MAAM,UAAU,YAAmB,CAAC"}
|