apteva 0.2.7 → 0.2.9

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 (46) hide show
  1. package/dist/App.m4hg4bxq.js +218 -0
  2. package/dist/index.html +4 -2
  3. package/dist/styles.css +1 -1
  4. package/package.json +1 -1
  5. package/src/auth/index.ts +386 -0
  6. package/src/auth/middleware.ts +183 -0
  7. package/src/binary.ts +19 -1
  8. package/src/db.ts +688 -45
  9. package/src/integrations/composio.ts +437 -0
  10. package/src/integrations/index.ts +80 -0
  11. package/src/openapi.ts +1724 -0
  12. package/src/routes/api.ts +1476 -118
  13. package/src/routes/auth.ts +242 -0
  14. package/src/server.ts +121 -11
  15. package/src/web/App.tsx +64 -19
  16. package/src/web/components/agents/AgentCard.tsx +24 -22
  17. package/src/web/components/agents/AgentPanel.tsx +810 -45
  18. package/src/web/components/agents/AgentsView.tsx +81 -9
  19. package/src/web/components/agents/CreateAgentModal.tsx +28 -1
  20. package/src/web/components/api/ApiDocsPage.tsx +583 -0
  21. package/src/web/components/auth/CreateAccountStep.tsx +176 -0
  22. package/src/web/components/auth/LoginPage.tsx +91 -0
  23. package/src/web/components/auth/index.ts +2 -0
  24. package/src/web/components/common/Icons.tsx +56 -0
  25. package/src/web/components/common/Modal.tsx +184 -1
  26. package/src/web/components/dashboard/Dashboard.tsx +70 -22
  27. package/src/web/components/index.ts +3 -0
  28. package/src/web/components/layout/Header.tsx +135 -18
  29. package/src/web/components/layout/Sidebar.tsx +87 -43
  30. package/src/web/components/mcp/IntegrationsPanel.tsx +743 -0
  31. package/src/web/components/mcp/McpPage.tsx +451 -63
  32. package/src/web/components/onboarding/OnboardingWizard.tsx +64 -8
  33. package/src/web/components/settings/SettingsPage.tsx +340 -26
  34. package/src/web/components/tasks/TasksPage.tsx +22 -20
  35. package/src/web/components/telemetry/TelemetryPage.tsx +163 -61
  36. package/src/web/context/AuthContext.tsx +230 -0
  37. package/src/web/context/ProjectContext.tsx +182 -0
  38. package/src/web/context/index.ts +5 -0
  39. package/src/web/hooks/useAgents.ts +18 -6
  40. package/src/web/hooks/useOnboarding.ts +20 -4
  41. package/src/web/hooks/useProviders.ts +15 -5
  42. package/src/web/icon.png +0 -0
  43. package/src/web/index.html +1 -1
  44. package/src/web/styles.css +12 -0
  45. package/src/web/types.ts +10 -1
  46. package/dist/App.3kb50qa3.js +0 -213
@@ -0,0 +1,183 @@
1
+ import { verifyAccessToken, getAuthStatus } from "./index";
2
+ import { UserDB, type User } from "../db";
3
+
4
+ // Extend Request type to include user
5
+ declare global {
6
+ interface Request {
7
+ user?: User;
8
+ }
9
+ }
10
+
11
+ // Helper to create JSON response
12
+ function json(data: unknown, status = 200): Response {
13
+ return new Response(JSON.stringify(data), {
14
+ status,
15
+ headers: { "Content-Type": "application/json" },
16
+ });
17
+ }
18
+
19
+ // Public paths that don't require authentication
20
+ const PUBLIC_PATHS = [
21
+ "/api/auth/check",
22
+ "/api/auth/login",
23
+ "/api/auth/refresh",
24
+ "/api/health",
25
+ "/api/telemetry", // Agents POST telemetry here
26
+ "/api/telemetry/stream", // SSE doesn't support auth headers
27
+ ];
28
+
29
+ // Path prefixes that don't require authentication (for agent communication)
30
+ const PUBLIC_PREFIXES = [
31
+ "/api/agents/", // Agent chat API needs to work without frontend auth
32
+ ];
33
+
34
+ // Paths that only work when no users exist
35
+ const SETUP_PATHS = [
36
+ "/api/onboarding/user",
37
+ ];
38
+
39
+ // Admin-only paths
40
+ const ADMIN_PATHS = [
41
+ "/api/users",
42
+ ];
43
+
44
+ export interface AuthContext {
45
+ user: User | null;
46
+ isAuthenticated: boolean;
47
+ isAdmin: boolean;
48
+ }
49
+
50
+ /**
51
+ * Auth middleware for protecting API routes
52
+ * Returns null if request should proceed, or a Response to return immediately
53
+ */
54
+ export async function authMiddleware(req: Request, path: string): Promise<{ response?: Response; context: AuthContext }> {
55
+ const context: AuthContext = {
56
+ user: null,
57
+ isAuthenticated: false,
58
+ isAdmin: false,
59
+ };
60
+
61
+ // Check if auth is disabled
62
+ if (process.env.AUTH_ENABLED === "false") {
63
+ return { context };
64
+ }
65
+
66
+ // Public paths - no auth needed
67
+ if (PUBLIC_PATHS.some(p => path === p || path.startsWith(p + "/"))) {
68
+ return { context };
69
+ }
70
+
71
+ // Public prefixes - no auth needed (for agent communication)
72
+ if (PUBLIC_PREFIXES.some(p => path.startsWith(p))) {
73
+ return { context };
74
+ }
75
+
76
+ // Setup paths - only allowed when no users exist
77
+ if (SETUP_PATHS.some(p => path === p || path.startsWith(p + "/"))) {
78
+ const hasUsers = UserDB.hasUsers();
79
+ if (!hasUsers) {
80
+ return { context }; // Allow - no users yet
81
+ }
82
+ // Users exist - require auth for these paths
83
+ }
84
+
85
+ // Extract token from Authorization header
86
+ const authHeader = req.headers.get("Authorization");
87
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
88
+ return {
89
+ response: json({ error: "Unauthorized", code: "NO_TOKEN" }, 401),
90
+ context,
91
+ };
92
+ }
93
+
94
+ const token = authHeader.slice(7);
95
+ const payload = verifyAccessToken(token);
96
+
97
+ if (!payload) {
98
+ return {
99
+ response: json({ error: "Invalid or expired token", code: "INVALID_TOKEN" }, 401),
100
+ context,
101
+ };
102
+ }
103
+
104
+ // Get user from database
105
+ const user = UserDB.findById(payload.userId);
106
+ if (!user) {
107
+ return {
108
+ response: json({ error: "User not found", code: "USER_NOT_FOUND" }, 401),
109
+ context,
110
+ };
111
+ }
112
+
113
+ // Update context
114
+ context.user = user;
115
+ context.isAuthenticated = true;
116
+ context.isAdmin = user.role === "admin";
117
+
118
+ // Check admin-only paths
119
+ if (ADMIN_PATHS.some(p => path === p || path.startsWith(p + "/"))) {
120
+ if (user.role !== "admin") {
121
+ return {
122
+ response: json({ error: "Admin access required", code: "FORBIDDEN" }, 403),
123
+ context,
124
+ };
125
+ }
126
+ }
127
+
128
+ return { context };
129
+ }
130
+
131
+ /**
132
+ * Helper to check if a path requires authentication
133
+ */
134
+ export function requiresAuth(path: string): boolean {
135
+ if (process.env.AUTH_ENABLED === "false") {
136
+ return false;
137
+ }
138
+
139
+ if (PUBLIC_PATHS.some(p => path === p || path.startsWith(p + "/"))) {
140
+ return false;
141
+ }
142
+
143
+ return true;
144
+ }
145
+
146
+ /**
147
+ * Helper to extract token from request
148
+ */
149
+ export function getTokenFromRequest(req: Request): string | null {
150
+ const authHeader = req.headers.get("Authorization");
151
+ if (!authHeader || !authHeader.startsWith("Bearer ")) {
152
+ return null;
153
+ }
154
+ return authHeader.slice(7);
155
+ }
156
+
157
+ /**
158
+ * Helper to extract refresh token from cookie
159
+ */
160
+ export function getRefreshTokenFromCookie(req: Request): string | null {
161
+ const cookie = req.headers.get("Cookie");
162
+ if (!cookie) return null;
163
+
164
+ const match = cookie.match(/(?:^|;\s*)apteva_session=([^;]+)/);
165
+ return match ? match[1] : null;
166
+ }
167
+
168
+ /**
169
+ * Create Set-Cookie header for refresh token
170
+ * Note: Secure flag only added when HTTPS is explicitly enabled (not just production mode)
171
+ * This allows Docker deployments to work on localhost without HTTPS
172
+ */
173
+ export function createRefreshTokenCookie(token: string, maxAge: number): string {
174
+ const secure = process.env.HTTPS_ENABLED === "true" ? "; Secure" : "";
175
+ return `apteva_session=${token}; HttpOnly; SameSite=Lax; Path=/; Max-Age=${maxAge}${secure}`;
176
+ }
177
+
178
+ /**
179
+ * Create Set-Cookie header to clear refresh token
180
+ */
181
+ export function clearRefreshTokenCookie(): string {
182
+ return "apteva_session=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0";
183
+ }
package/src/binary.ts CHANGED
@@ -286,6 +286,24 @@ export interface VersionInfo {
286
286
  export interface AllVersionInfo {
287
287
  apteva: VersionInfo;
288
288
  agent: VersionInfo;
289
+ isDocker: boolean;
290
+ }
291
+
292
+ // Detect if running in Docker
293
+ export function isRunningInDocker(): boolean {
294
+ // Check for /.dockerenv file (standard Docker indicator)
295
+ if (existsSync("/.dockerenv")) {
296
+ return true;
297
+ }
298
+ // Check for DATA_DIR=/data (our Docker convention)
299
+ if (process.env.DATA_DIR === "/data") {
300
+ return true;
301
+ }
302
+ // Check for DOCKER env var we could set
303
+ if (process.env.DOCKER === "true") {
304
+ return true;
305
+ }
306
+ return false;
289
307
  }
290
308
 
291
309
  // Initialize version file path
@@ -399,7 +417,7 @@ export async function checkForUpdates(): Promise<AllVersionInfo> {
399
417
  checkForAgentUpdates(),
400
418
  ]);
401
419
 
402
- return { apteva, agent };
420
+ return { apteva, agent, isDocker: isRunningInDocker() };
403
421
  }
404
422
 
405
423
  // Compare semver versions: returns positive if a > b, negative if a < b, 0 if equal