upfynai-code 3.0.4 → 3.2.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.
Files changed (258) hide show
  1. package/README.md +69 -92
  2. package/bin/cli.js +191 -0
  3. package/dist/client/assets/AppContent-M14Au3SB.js +542 -0
  4. package/{client/dist/assets/BrowserPanel-0TLEl-IC.js → dist/client/assets/BrowserPanel-TFKm2NDJ.js} +2 -2
  5. package/dist/client/assets/DashboardPanel-C88HjsCh.js +1 -0
  6. package/dist/client/assets/FileTree-DvO1xnDE.js +1 -0
  7. package/{client/dist/assets/GitPanel-C_xFM-N2.js → dist/client/assets/GitPanel-D-slVlyy.js} +2 -2
  8. package/dist/client/assets/LoginModal-Chi4SYcr.js +21 -0
  9. package/{client/dist/assets/MarkdownPreview-CESjI261.js → dist/client/assets/MarkdownPreview-CuIix2u9.js} +1 -1
  10. package/dist/client/assets/MermaidBlock-Dq9uFv82.js +2 -0
  11. package/dist/client/assets/Onboarding-QYXx24dX.js +1 -0
  12. package/{client/dist/assets/PreviewPanel-CqCa92Tf.js → dist/client/assets/PreviewPanel-Dd8q-jo0.js} +1 -1
  13. package/dist/client/assets/SetupForm-CrspaUva.js +1 -0
  14. package/dist/client/assets/WorkflowsPanel-DIlYAdhB.js +1 -0
  15. package/dist/client/assets/index-CnNNzw9A.css +1 -0
  16. package/{client/dist/assets/index-HaY-3pK1.js → dist/client/assets/index-rUkK9FDP.js} +26 -26
  17. package/{client/dist/assets/vendor-codemirror-D2ALgpaX.js → dist/client/assets/vendor-codemirror-jc6nyJQg.js} +1 -1
  18. package/{client/dist/assets/vendor-diff-DNQpbhrT.js → dist/client/assets/vendor-diff-THJmAcEI.js} +1 -1
  19. package/{client/dist/assets/vendor-icons-GyYE35HP.js → dist/client/assets/vendor-icons-CfjIpdrD.js} +145 -155
  20. package/{client/dist/assets/vendor-markdown-CimbIo6Y.js → dist/client/assets/vendor-markdown-Cdm6NEGf.js} +1 -1
  21. package/dist/client/assets/vendor-mermaid-DTPaBx-U.js +2559 -0
  22. package/{client/dist/assets/vendor-react-96lCPsRK.js → dist/client/assets/vendor-react-wFkb6mSf.js} +1 -1
  23. package/{client/dist/assets/vendor-syntax-LS_Nt30I.js → dist/client/assets/vendor-syntax-C_UZR7tc.js} +1 -1
  24. package/dist/client/favicon.png +0 -0
  25. package/dist/client/icons/icon-128x128.png +0 -0
  26. package/dist/client/icons/icon-144x144.png +0 -0
  27. package/dist/client/icons/icon-152x152.png +0 -0
  28. package/dist/client/icons/icon-192x192.png +0 -0
  29. package/dist/client/icons/icon-384x384.png +0 -0
  30. package/dist/client/icons/icon-512x512.png +0 -0
  31. package/dist/client/icons/icon-72x72.png +0 -0
  32. package/dist/client/icons/icon-96x96.png +0 -0
  33. package/{client/dist → dist/client}/index.html +37 -36
  34. package/dist/client/logo-128.png +0 -0
  35. package/dist/client/logo-256.png +0 -0
  36. package/dist/client/logo-32.png +0 -0
  37. package/dist/client/logo-512.png +0 -0
  38. package/dist/client/logo-64.png +0 -0
  39. package/dist/client/logo.png +0 -0
  40. package/{client/dist → dist/client}/manifest.json +12 -12
  41. package/{client/dist → dist/client}/mcp-docs.html +1 -1
  42. package/{client/dist → dist/client}/sw.js +2 -2
  43. package/package.json +56 -105
  44. package/scripts/postinstall.js +9 -0
  45. package/scripts/prepublish.js +77 -0
  46. package/src/animation.js +228 -0
  47. package/src/auth.js +142 -0
  48. package/src/config.js +40 -0
  49. package/src/connect.js +416 -0
  50. package/src/launch.js +81 -0
  51. package/src/mcp.js +57 -0
  52. package/src/permissions.js +140 -0
  53. package/src/persistent-shell.js +261 -0
  54. package/src/server.js +54 -0
  55. package/client/dist/assets/AppContent-CwrTP6TW.js +0 -545
  56. package/client/dist/assets/CanvasFullScreen-D1GWQsGL.js +0 -1
  57. package/client/dist/assets/CanvasWorkspace-D7ORj358.js +0 -163
  58. package/client/dist/assets/DashboardPanel-BV7ybUDe.js +0 -1
  59. package/client/dist/assets/FileTree-5qfhBqdE.js +0 -1
  60. package/client/dist/assets/LoginModal-CImJHRjX.js +0 -13
  61. package/client/dist/assets/MermaidBlock-BFM21cwe.js +0 -2
  62. package/client/dist/assets/Onboarding-B3cteLu2.js +0 -1
  63. package/client/dist/assets/SetupForm-P6dsYgHO.js +0 -1
  64. package/client/dist/assets/WorkflowsPanel-CBoN80kc.js +0 -1
  65. package/client/dist/assets/index-46kkVu2i.css +0 -1
  66. package/client/dist/assets/pdf-CE_K4jFx.js +0 -12
  67. package/client/dist/assets/vendor-canvas-BZV40eAE.css +0 -1
  68. package/client/dist/assets/vendor-canvas-DvHJ_Pn2.js +0 -49
  69. package/client/dist/assets/vendor-mermaid-DucWyDEe.js +0 -2556
  70. package/client/dist/favicon.png +0 -0
  71. package/client/dist/icons/icon-128x128.png +0 -0
  72. package/client/dist/icons/icon-144x144.png +0 -0
  73. package/client/dist/icons/icon-152x152.png +0 -0
  74. package/client/dist/icons/icon-192x192.png +0 -0
  75. package/client/dist/icons/icon-384x384.png +0 -0
  76. package/client/dist/icons/icon-512x512.png +0 -0
  77. package/client/dist/icons/icon-72x72.png +0 -0
  78. package/client/dist/icons/icon-96x96.png +0 -0
  79. package/client/dist/logo-128.png +0 -0
  80. package/client/dist/logo-256.png +0 -0
  81. package/client/dist/logo-32.png +0 -0
  82. package/client/dist/logo-512.png +0 -0
  83. package/client/dist/logo-64.png +0 -0
  84. package/commands/upfynai-connect.md +0 -59
  85. package/commands/upfynai-disconnect.md +0 -31
  86. package/commands/upfynai-doctor.md +0 -99
  87. package/commands/upfynai-export.md +0 -49
  88. package/commands/upfynai-local.md +0 -82
  89. package/commands/upfynai-status.md +0 -75
  90. package/commands/upfynai-stop.md +0 -49
  91. package/commands/upfynai-uninstall.md +0 -58
  92. package/commands/upfynai.md +0 -69
  93. package/scripts/build-client.js +0 -17
  94. package/scripts/fix-node-pty.js +0 -67
  95. package/scripts/install-commands.js +0 -78
  96. package/server/agent-loop.js +0 -242
  97. package/server/auto-compact.js +0 -99
  98. package/server/browser.js +0 -131
  99. package/server/claude-sdk.js +0 -797
  100. package/server/cli-ui.js +0 -798
  101. package/server/cli.js +0 -751
  102. package/server/constants/config.js +0 -31
  103. package/server/cursor-cli.js +0 -270
  104. package/server/database/auth.db +0 -0
  105. package/server/database/db.js +0 -1547
  106. package/server/database/init.sql +0 -70
  107. package/server/index.js +0 -3813
  108. package/server/load-env.js +0 -26
  109. package/server/mcp-server.js +0 -621
  110. package/server/middleware/auth.js +0 -184
  111. package/server/middleware/relayHelpers.js +0 -44
  112. package/server/middleware/sandboxRouter.js +0 -174
  113. package/server/openai-codex.js +0 -403
  114. package/server/openrouter.js +0 -137
  115. package/server/projects.js +0 -1807
  116. package/server/provider-factory.js +0 -174
  117. package/server/relay-client.js +0 -390
  118. package/server/routes/agent.js +0 -1234
  119. package/server/routes/auth.js +0 -559
  120. package/server/routes/browser.js +0 -419
  121. package/server/routes/canvas.js +0 -53
  122. package/server/routes/cli-auth.js +0 -263
  123. package/server/routes/codex.js +0 -396
  124. package/server/routes/commands.js +0 -707
  125. package/server/routes/composio.js +0 -176
  126. package/server/routes/cursor.js +0 -770
  127. package/server/routes/dashboard.js +0 -295
  128. package/server/routes/git.js +0 -1208
  129. package/server/routes/keys.js +0 -34
  130. package/server/routes/mcp-utils.js +0 -48
  131. package/server/routes/mcp.js +0 -661
  132. package/server/routes/payments.js +0 -227
  133. package/server/routes/projects.js +0 -754
  134. package/server/routes/sessions.js +0 -146
  135. package/server/routes/settings.js +0 -261
  136. package/server/routes/taskmaster.js +0 -1928
  137. package/server/routes/user.js +0 -106
  138. package/server/routes/vapi-chat.js +0 -624
  139. package/server/routes/voice.js +0 -235
  140. package/server/routes/webhooks.js +0 -166
  141. package/server/routes/workflows.js +0 -312
  142. package/server/sandbox.js +0 -120
  143. package/server/services/browser-ai.js +0 -154
  144. package/server/services/composio.js +0 -204
  145. package/server/services/sessionRegistry.js +0 -139
  146. package/server/services/whisperService.js +0 -84
  147. package/server/services/workflowScheduler.js +0 -211
  148. package/server/tests/relay-flow.test.js +0 -570
  149. package/server/tests/sessions.test.js +0 -259
  150. package/server/utils/commandParser.js +0 -303
  151. package/server/utils/email.js +0 -66
  152. package/server/utils/gitConfig.js +0 -24
  153. package/server/utils/mcp-detector.js +0 -198
  154. package/server/utils/taskmaster-websocket.js +0 -129
  155. package/shared/integrationCatalog.d.ts +0 -12
  156. package/shared/integrationCatalog.js +0 -172
  157. package/shared/modelConstants.js +0 -96
  158. /package/{shared → dist}/agents/claude.js +0 -0
  159. /package/{shared → dist}/agents/codex.js +0 -0
  160. /package/{shared → dist}/agents/cursor.js +0 -0
  161. /package/{shared → dist}/agents/detect.js +0 -0
  162. /package/{shared → dist}/agents/exec.js +0 -0
  163. /package/{shared → dist}/agents/files.js +0 -0
  164. /package/{shared → dist}/agents/git.js +0 -0
  165. /package/{shared → dist}/agents/gitagent.js +0 -0
  166. /package/{shared → dist}/agents/index.js +0 -0
  167. /package/{shared → dist}/agents/shell.js +0 -0
  168. /package/{shared → dist}/agents/utils.js +0 -0
  169. /package/{client/dist → dist/client}/api-docs.html +0 -0
  170. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  171. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  172. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  173. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  174. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  175. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  176. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  177. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  178. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  179. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  180. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  181. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  182. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  183. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  184. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  185. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  186. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  187. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  188. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  189. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  190. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  191. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  192. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  193. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  194. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  195. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  196. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  197. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  198. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  199. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  200. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  201. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  202. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  203. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  204. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  205. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  206. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  207. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  208. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  209. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  210. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  211. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  212. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  213. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  214. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  215. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  216. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  217. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  218. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  219. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  220. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  221. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  222. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  223. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  224. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  225. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  226. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  227. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  228. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  229. /package/{client/dist → dist/client}/assets/vendor-i18n-DCFGyhQR.js +0 -0
  230. /package/{client/dist → dist/client}/assets/vendor-xterm-CZq1hqo1.js +0 -0
  231. /package/{client/dist → dist/client}/assets/vendor-xterm-qxJ8_QYu.css +0 -0
  232. /package/{client/dist → dist/client}/clear-cache.html +0 -0
  233. /package/{client/dist → dist/client}/convert-icons.md +0 -0
  234. /package/{client/dist → dist/client}/favicon.svg +0 -0
  235. /package/{client/dist → dist/client}/generate-icons.js +0 -0
  236. /package/{client/dist → dist/client}/icons/claude-ai-icon.svg +0 -0
  237. /package/{client/dist → dist/client}/icons/codex-white.svg +0 -0
  238. /package/{client/dist → dist/client}/icons/codex.svg +0 -0
  239. /package/{client/dist → dist/client}/icons/cursor-white.svg +0 -0
  240. /package/{client/dist → dist/client}/icons/cursor.svg +0 -0
  241. /package/{client/dist → dist/client}/icons/icon-128x128.svg +0 -0
  242. /package/{client/dist → dist/client}/icons/icon-144x144.svg +0 -0
  243. /package/{client/dist → dist/client}/icons/icon-152x152.svg +0 -0
  244. /package/{client/dist → dist/client}/icons/icon-192x192.svg +0 -0
  245. /package/{client/dist → dist/client}/icons/icon-384x384.svg +0 -0
  246. /package/{client/dist → dist/client}/icons/icon-512x512.svg +0 -0
  247. /package/{client/dist → dist/client}/icons/icon-72x72.svg +0 -0
  248. /package/{client/dist → dist/client}/icons/icon-96x96.svg +0 -0
  249. /package/{client/dist → dist/client}/icons/icon-template.svg +0 -0
  250. /package/{client/dist → dist/client}/logo.svg +0 -0
  251. /package/{client/dist → dist/client}/offline.html +0 -0
  252. /package/{client/dist → dist/client}/screenshots/cli-selection.png +0 -0
  253. /package/{client/dist → dist/client}/screenshots/desktop-main.png +0 -0
  254. /package/{client/dist → dist/client}/screenshots/mobile-chat.png +0 -0
  255. /package/{client/dist → dist/client}/screenshots/tools-modal.png +0 -0
  256. /package/{shared → dist}/gitagent/index.js +0 -0
  257. /package/{shared → dist}/gitagent/parser.js +0 -0
  258. /package/{shared → dist}/gitagent/prompt-builder.js +0 -0
@@ -1,146 +0,0 @@
1
- /**
2
- * Session Management REST API
3
- * Provides unified session listing, abort, delete, and stats endpoints.
4
- * All endpoints filter by userId for user isolation.
5
- */
6
-
7
- import { Router } from 'express';
8
- import {
9
- getAllActiveSessions,
10
- checkSessionStatus,
11
- abortSession,
12
- abortAllSessions,
13
- getSessionStats,
14
- } from '../services/sessionRegistry.js';
15
-
16
- const router = Router();
17
-
18
- // Helper: get sessions owned by the current user
19
- function getUserSessions(req) {
20
- const userId = req.user?.id || req.user?.userId;
21
- const sessionOwners = req.sessionOwners;
22
- const all = getAllActiveSessions();
23
- if (!userId || !sessionOwners) return all; // local mode, no filtering
24
- return all.filter(s => {
25
- const owner = sessionOwners.get(s.sessionId);
26
- return !owner || owner === userId; // include if no owner (legacy) or owned by user
27
- });
28
- }
29
-
30
- /**
31
- * GET /api/sessions — List active sessions for this user
32
- */
33
- router.get('/', (req, res) => {
34
- try {
35
- const sessions = getUserSessions(req);
36
- res.json({ sessions });
37
- } catch (error) {
38
- res.status(500).json({ error: 'Failed to fetch sessions' });
39
- }
40
- });
41
-
42
- /**
43
- * GET /api/sessions/stats — Session counts for this user
44
- */
45
- router.get('/stats', (req, res) => {
46
- try {
47
- const sessions = getUserSessions(req);
48
- const byProvider = { claude: 0, cursor: 0, codex: 0 };
49
- for (const s of sessions) {
50
- byProvider[s.provider] = (byProvider[s.provider] || 0) + 1;
51
- }
52
- res.json({
53
- total: sessions.length,
54
- active: sessions.filter(s => s.status === 'active').length,
55
- byProvider,
56
- });
57
- } catch (error) {
58
- res.status(500).json({ error: 'Failed to fetch session stats' });
59
- }
60
- });
61
-
62
- /**
63
- * GET /api/sessions/:sessionId — Get session details (only if owned)
64
- */
65
- router.get('/:sessionId', (req, res) => {
66
- try {
67
- const { sessionId } = req.params;
68
- const userId = req.user?.id || req.user?.userId;
69
- const sessionOwners = req.sessionOwners;
70
-
71
- // Check ownership
72
- if (userId && sessionOwners) {
73
- const owner = sessionOwners.get(sessionId);
74
- if (owner && owner !== userId) {
75
- return res.status(403).json({ error: 'Access denied' });
76
- }
77
- }
78
-
79
- const status = checkSessionStatus(sessionId);
80
- if (!status.active) {
81
- return res.status(404).json({ error: 'Session not found or inactive' });
82
- }
83
-
84
- res.json({
85
- sessionId,
86
- provider: status.provider,
87
- active: status.active,
88
- });
89
- } catch (error) {
90
- res.status(500).json({ error: 'Failed to fetch session details' });
91
- }
92
- });
93
-
94
- /**
95
- * POST /api/sessions/:sessionId/abort — Abort an active session (only if owned)
96
- */
97
- router.post('/:sessionId/abort', async (req, res) => {
98
- try {
99
- const { sessionId } = req.params;
100
- const { provider } = req.body || {};
101
- const userId = req.user?.id || req.user?.userId;
102
- const sessionOwners = req.sessionOwners;
103
-
104
- // Check ownership before aborting
105
- if (userId && sessionOwners) {
106
- const owner = sessionOwners.get(sessionId);
107
- if (owner && owner !== userId) {
108
- return res.status(403).json({ error: 'Access denied — cannot abort another user\'s session' });
109
- }
110
- }
111
-
112
- const result = await abortSession(sessionId, provider);
113
- if (!result.aborted) {
114
- return res.status(404).json({ error: 'Session not found or already terminated' });
115
- }
116
-
117
- res.json({ success: true, sessionId, provider: result.provider });
118
- } catch (error) {
119
- res.status(500).json({ error: 'Failed to abort session' });
120
- }
121
- });
122
-
123
- /**
124
- * POST /api/sessions/abort-all — Abort all active sessions owned by this user
125
- */
126
- router.post('/abort-all', async (req, res) => {
127
- try {
128
- const userSessions = getUserSessions(req);
129
- const results = [];
130
-
131
- for (const s of userSessions) {
132
- const { aborted } = await abortSession(s.sessionId, s.provider);
133
- results.push({ sessionId: s.sessionId, provider: s.provider, aborted });
134
- }
135
-
136
- res.json({
137
- success: true,
138
- aborted: results.filter(r => r.aborted).length,
139
- results,
140
- });
141
- } catch (error) {
142
- res.status(500).json({ error: 'Failed to abort sessions' });
143
- }
144
- });
145
-
146
- export default router;
@@ -1,261 +0,0 @@
1
- import express from 'express';
2
- import { apiKeysDb, credentialsDb } from '../database/db.js';
3
-
4
- const router = express.Router();
5
-
6
- // ===============================
7
- // API Keys Management
8
- // ===============================
9
-
10
- // Get all API keys for the authenticated user
11
- router.get('/api-keys', async (req, res) => {
12
- try {
13
- const apiKeys = await apiKeysDb.getApiKeys(req.user.id);
14
- // Don't send the full API key in the list for security
15
- const sanitizedKeys = apiKeys.map(key => ({
16
- ...key,
17
- api_key: key.api_key.substring(0, 10) + '...'
18
- }));
19
- res.json({ apiKeys: sanitizedKeys });
20
- } catch (error) {
21
- res.status(500).json({ error: 'Failed to fetch API keys' });
22
- }
23
- });
24
-
25
- // Create a new API key
26
- router.post('/api-keys', async (req, res) => {
27
- try {
28
- const { keyName } = req.body;
29
-
30
- if (!keyName || !keyName.trim()) {
31
- return res.status(400).json({ error: 'Key name is required' });
32
- }
33
-
34
- const result = await apiKeysDb.createApiKey(req.user.id, keyName.trim());
35
- res.json({
36
- success: true,
37
- apiKey: result
38
- });
39
- } catch (error) {
40
- res.status(500).json({ error: 'Failed to create API key' });
41
- }
42
- });
43
-
44
- // Delete an API key
45
- router.delete('/api-keys/:keyId', async (req, res) => {
46
- try {
47
- const { keyId } = req.params;
48
- const success = await apiKeysDb.deleteApiKey(req.user.id, parseInt(keyId));
49
-
50
- if (success) {
51
- res.json({ success: true });
52
- } else {
53
- res.status(404).json({ error: 'API key not found' });
54
- }
55
- } catch (error) {
56
- res.status(500).json({ error: 'Failed to delete API key' });
57
- }
58
- });
59
-
60
- // Toggle API key active status
61
- router.patch('/api-keys/:keyId/toggle', async (req, res) => {
62
- try {
63
- const { keyId } = req.params;
64
- const { isActive } = req.body;
65
-
66
- if (typeof isActive !== 'boolean') {
67
- return res.status(400).json({ error: 'isActive must be a boolean' });
68
- }
69
-
70
- const success = await apiKeysDb.toggleApiKey(req.user.id, parseInt(keyId), isActive);
71
-
72
- if (success) {
73
- res.json({ success: true });
74
- } else {
75
- res.status(404).json({ error: 'API key not found' });
76
- }
77
- } catch (error) {
78
- res.status(500).json({ error: 'Failed to toggle API key' });
79
- }
80
- });
81
-
82
- // ===============================
83
- // Generic Credentials Management
84
- // ===============================
85
-
86
- // Get all credentials for the authenticated user (optionally filtered by type)
87
- router.get('/credentials', async (req, res) => {
88
- try {
89
- const { type } = req.query;
90
- const credentials = await credentialsDb.getCredentials(req.user.id, type || null);
91
- // Don't send the actual credential values for security
92
- res.json({ credentials });
93
- } catch (error) {
94
- res.status(500).json({ error: 'Failed to fetch credentials' });
95
- }
96
- });
97
-
98
- // Create a new credential
99
- router.post('/credentials', async (req, res) => {
100
- try {
101
- const { credentialName, credentialType, credentialValue, description } = req.body;
102
-
103
- if (!credentialName || !credentialName.trim()) {
104
- return res.status(400).json({ error: 'Credential name is required' });
105
- }
106
-
107
- if (!credentialType || !credentialType.trim()) {
108
- return res.status(400).json({ error: 'Credential type is required' });
109
- }
110
-
111
- if (!credentialValue || !credentialValue.trim()) {
112
- return res.status(400).json({ error: 'Credential value is required' });
113
- }
114
-
115
- const result = await credentialsDb.createCredential(
116
- req.user.id,
117
- credentialName.trim(),
118
- credentialType.trim(),
119
- credentialValue.trim(),
120
- description?.trim() || null
121
- );
122
-
123
- res.json({
124
- success: true,
125
- credential: result
126
- });
127
- } catch (error) {
128
- res.status(500).json({ error: 'Failed to create credential' });
129
- }
130
- });
131
-
132
- // Delete a credential
133
- router.delete('/credentials/:credentialId', async (req, res) => {
134
- try {
135
- const { credentialId } = req.params;
136
- const success = await credentialsDb.deleteCredential(req.user.id, parseInt(credentialId));
137
-
138
- if (success) {
139
- res.json({ success: true });
140
- } else {
141
- res.status(404).json({ error: 'Credential not found' });
142
- }
143
- } catch (error) {
144
- res.status(500).json({ error: 'Failed to delete credential' });
145
- }
146
- });
147
-
148
- // Toggle credential active status
149
- router.patch('/credentials/:credentialId/toggle', async (req, res) => {
150
- try {
151
- const { credentialId } = req.params;
152
- const { isActive } = req.body;
153
-
154
- if (typeof isActive !== 'boolean') {
155
- return res.status(400).json({ error: 'isActive must be a boolean' });
156
- }
157
-
158
- const success = await credentialsDb.toggleCredential(req.user.id, parseInt(credentialId), isActive);
159
-
160
- if (success) {
161
- res.json({ success: true });
162
- } else {
163
- res.status(404).json({ error: 'Credential not found' });
164
- }
165
- } catch (error) {
166
- res.status(500).json({ error: 'Failed to toggle credential' });
167
- }
168
- });
169
-
170
- // ===============================
171
- // AI Provider Keys (BYOK)
172
- // ===============================
173
-
174
- const AI_PROVIDER_TYPES = [
175
- 'anthropic_key',
176
- 'openai_key',
177
- 'openrouter_key',
178
- 'google_key',
179
- ];
180
-
181
- // Get all AI provider keys for the authenticated user (masked values)
182
- router.get('/ai-providers', async (req, res) => {
183
- try {
184
- const allCreds = [];
185
- for (const type of AI_PROVIDER_TYPES) {
186
- const creds = await credentialsDb.getCredentials(req.user.id, type);
187
- allCreds.push(...creds.map(c => ({
188
- id: c.id,
189
- credential_name: c.credential_name,
190
- credential_type: c.credential_type,
191
- description: c.description,
192
- is_active: c.is_active,
193
- created_at: c.created_at,
194
- // Mask the key — show first 8 and last 4 chars
195
- masked_value: c.credential_value
196
- ? c.credential_value.slice(0, 8) + '...' + c.credential_value.slice(-4)
197
- : '***',
198
- })));
199
- }
200
- res.json({ providers: allCreds });
201
- } catch (error) {
202
- res.status(500).json({ error: 'Failed to fetch AI provider keys' });
203
- }
204
- });
205
-
206
- // Save an AI provider key
207
- router.post('/ai-providers', async (req, res) => {
208
- try {
209
- const { providerType, apiKey, name } = req.body;
210
-
211
- if (!providerType || !AI_PROVIDER_TYPES.includes(providerType)) {
212
- return res.status(400).json({ error: `Invalid provider type. Supported: ${AI_PROVIDER_TYPES.join(', ')}` });
213
- }
214
- if (!apiKey || !apiKey.trim()) {
215
- return res.status(400).json({ error: 'API key is required' });
216
- }
217
- if (apiKey.trim().length < 10 || apiKey.trim().length > 256) {
218
- return res.status(400).json({ error: 'Invalid API key length' });
219
- }
220
-
221
- const label = providerType.replace('_key', '').replace('_', ' ');
222
- const credName = name?.trim() || `${label} API key`;
223
-
224
- // Deactivate existing keys of same type (user should only have one active per provider)
225
- const existing = await credentialsDb.getCredentials(req.user.id, providerType);
226
- for (const cred of existing) {
227
- if (cred.is_active) {
228
- await credentialsDb.toggleCredential(req.user.id, cred.id, false);
229
- }
230
- }
231
-
232
- const result = await credentialsDb.createCredential(
233
- req.user.id,
234
- credName,
235
- providerType,
236
- apiKey.trim(),
237
- `User-provided ${label} API key`
238
- );
239
-
240
- res.json({ success: true, credential: { id: result.id, credential_type: providerType, credential_name: credName } });
241
- } catch (error) {
242
- res.status(500).json({ error: 'Failed to save AI provider key' });
243
- }
244
- });
245
-
246
- // Delete an AI provider key
247
- router.delete('/ai-providers/:credentialId', async (req, res) => {
248
- try {
249
- const { credentialId } = req.params;
250
- const success = await credentialsDb.deleteCredential(req.user.id, parseInt(credentialId));
251
- if (success) {
252
- res.json({ success: true });
253
- } else {
254
- res.status(404).json({ error: 'Provider key not found' });
255
- }
256
- } catch (error) {
257
- res.status(500).json({ error: 'Failed to delete provider key' });
258
- }
259
- });
260
-
261
- export default router;