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,295 +0,0 @@
1
- import { Router } from 'express';
2
- import { getProjects, getSessions } from '../projects.js';
3
- import { userDb, subscriptionDb, paymentDb, apiKeysDb, credentialsDb, relayTokensDb, webhookDb, workflowDb } from '../database/db.js';
4
-
5
- const router = Router();
6
-
7
- // AI provider credential types
8
- const AI_PROVIDER_TYPES = ['anthropic_key', 'openai_key', 'openrouter_key', 'google_key'];
9
- const PROVIDER_LABELS = {
10
- anthropic_key: 'Anthropic',
11
- openai_key: 'OpenAI',
12
- openrouter_key: 'OpenRouter',
13
- google_key: 'Google',
14
- };
15
-
16
- // Per-user stats cache (60s TTL)
17
- const statsCache = new Map();
18
- const CACHE_TTL = 60_000;
19
-
20
- function getCachedStats(userId) {
21
- const entry = statsCache.get(userId);
22
- if (entry && Date.now() - entry.ts < CACHE_TTL) return entry.data;
23
- return null;
24
- }
25
- function setCachedStats(userId, data) {
26
- statsCache.set(userId, { data, ts: Date.now() });
27
- }
28
- function invalidateStatsCache(userId) {
29
- statsCache.delete(userId);
30
- }
31
-
32
- // Periodic expiry of overdue subs (every 5 min, not per-request)
33
- let lastExpireRun = 0;
34
- async function maybeExpireOverdue() {
35
- if (Date.now() - lastExpireRun < 300_000) return;
36
- lastExpireRun = Date.now();
37
- try { await subscriptionDb.expireOverdue(); } catch { /* non-critical */ }
38
- }
39
-
40
- /**
41
- * GET /api/dashboard/user-stats — Per-user dashboard data from Turso
42
- * Aggregates: account, subscription, payments, API keys, AI providers, relay tokens, webhooks, workflows
43
- */
44
- router.get('/user-stats', async (req, res) => {
45
- try {
46
- const userId = req.user.id;
47
-
48
- // Return cached stats if fresh (< 60s)
49
- const cached = getCachedStats(userId);
50
- if (cached) return res.json(cached);
51
-
52
- // Run all DB queries in parallel
53
- const [
54
- fullUser,
55
- activeSub,
56
- allSubs,
57
- payments,
58
- apiKeys,
59
- credentials,
60
- relayTokens,
61
- webhooks,
62
- workflows,
63
- ] = await Promise.all([
64
- userDb.getUserById(userId),
65
- subscriptionDb.getActiveSub(userId).catch(() => null),
66
- subscriptionDb.getAllSubs(userId).catch(() => []),
67
- paymentDb.getUserPayments(userId).catch(() => []),
68
- apiKeysDb.getApiKeys(userId).catch(() => []),
69
- credentialsDb.getCredentials(userId).catch(() => []),
70
- relayTokensDb.getTokens(userId).catch(() => []),
71
- webhookDb.getAll(userId).catch(() => []),
72
- workflowDb.getAll(userId).catch(() => []),
73
- ]);
74
-
75
- // Expire overdue subs periodically (not per-request)
76
- maybeExpireOverdue();
77
-
78
- // Account
79
- const account = fullUser ? {
80
- username: fullUser.username,
81
- email: fullUser.email,
82
- phone: fullUser.phone,
83
- firstName: fullUser.first_name,
84
- lastName: fullUser.last_name,
85
- userCode: fullUser.user_code,
86
- createdAt: fullUser.created_at,
87
- lastLogin: fullUser.last_login,
88
- accessOverride: fullUser.access_override,
89
- } : null;
90
-
91
- // Subscription
92
- const subscription = {
93
- active: activeSub ? {
94
- id: activeSub.id,
95
- planId: activeSub.plan_id,
96
- status: activeSub.status,
97
- startsAt: activeSub.starts_at,
98
- expiresAt: activeSub.expires_at,
99
- amount: activeSub.amount,
100
- currency: activeSub.currency || 'INR',
101
- } : null,
102
- history: allSubs.map(s => ({
103
- id: s.id,
104
- planId: s.plan_id,
105
- status: s.status,
106
- startsAt: s.starts_at,
107
- expiresAt: s.expires_at,
108
- amount: s.amount,
109
- currency: s.currency || 'INR',
110
- createdAt: s.created_at,
111
- })),
112
- };
113
-
114
- // Payments
115
- const paidPayments = payments.filter(p => p.status === 'paid');
116
- const totalAmountPaise = paidPayments.reduce((sum, p) => sum + (Number(p.amount) || 0), 0);
117
- const paymentData = {
118
- total: payments.length,
119
- paid: paidPayments.length,
120
- totalAmountPaise,
121
- recent: payments.slice(0, 10).map(p => ({
122
- id: p.id,
123
- planId: p.plan_id,
124
- amount: p.amount,
125
- currency: p.currency || 'INR',
126
- status: p.status,
127
- createdAt: p.created_at,
128
- })),
129
- };
130
-
131
- // API Keys (include full list for dashboard display)
132
- const activeKeys = apiKeys.filter(k => k.is_active);
133
- const apiKeyData = {
134
- total: apiKeys.length,
135
- active: activeKeys.length,
136
- keys: apiKeys.map(k => ({
137
- id: k.id,
138
- keyName: k.key_name || 'default',
139
- keyPrefix: k.api_key ? k.api_key.slice(0, 12) : '',
140
- keySuffix: k.api_key ? k.api_key.slice(-6) : '',
141
- fullKey: k.api_key,
142
- isActive: !!k.is_active,
143
- createdAt: k.created_at,
144
- lastUsed: k.last_used,
145
- })),
146
- };
147
-
148
- // AI Providers (filter credentials by AI provider types)
149
- const aiCreds = credentials.filter(c => AI_PROVIDER_TYPES.includes(c.credential_type));
150
- const activeAiCreds = aiCreds.filter(c => c.is_active);
151
- const aiProviderData = {
152
- total: aiCreds.length,
153
- active: activeAiCreds.length,
154
- providers: activeAiCreds.map(c => PROVIDER_LABELS[c.credential_type] || c.credential_type),
155
- };
156
-
157
- // Relay Tokens
158
- const activeTokens = relayTokens.filter(t => t.is_active);
159
- const lastConnected = relayTokens
160
- .filter(t => t.last_connected)
161
- .sort((a, b) => new Date(b.last_connected) - new Date(a.last_connected))[0]?.last_connected || null;
162
- const relayData = {
163
- total: relayTokens.length,
164
- active: activeTokens.length,
165
- lastConnected,
166
- };
167
-
168
- // Webhooks
169
- const activeWebhooks = webhooks.filter(w => w.is_active);
170
- const webhookData = {
171
- total: webhooks.length,
172
- active: activeWebhooks.length,
173
- };
174
-
175
- // Workflows
176
- const activeWorkflows = workflows.filter(w => w.is_active);
177
- const workflowData = {
178
- total: workflows.length,
179
- active: activeWorkflows.length,
180
- };
181
-
182
- const result = {
183
- account,
184
- subscription,
185
- payments: paymentData,
186
- apiKeys: apiKeyData,
187
- aiProviders: aiProviderData,
188
- relayTokens: relayData,
189
- webhooks: webhookData,
190
- workflows: workflowData,
191
- };
192
-
193
- setCachedStats(userId, result);
194
- res.json(result);
195
- } catch (error) {
196
- res.status(500).json({ error: 'Failed to fetch user stats' });
197
- }
198
- });
199
-
200
- /**
201
- * GET /api/dashboard/stats — Dashboard usage analytics (local projects)
202
- * Returns session counts, provider breakdown, and today's activity.
203
- */
204
- router.get('/stats', async (req, res) => {
205
- try {
206
- const userId = req.user?.id || req.user?.userId;
207
- const projects = await getProjects(null, userId);
208
- let totalSessions = 0;
209
- let todaySessions = 0;
210
- const providers = {};
211
- const today = new Date().toISOString().slice(0, 10);
212
-
213
- for (const project of projects) {
214
- // Count sessions per provider
215
- for (const provider of ['claude', 'cursor', 'codex']) {
216
- try {
217
- const sessions = await getSessions(project.name, provider);
218
- if (sessions && sessions.length) {
219
- totalSessions += sessions.length;
220
- providers[provider] = (providers[provider] || 0) + sessions.length;
221
-
222
- // Count today's sessions
223
- for (const s of sessions) {
224
- const created = s.created_at || s.createdAt || '';
225
- if (created.startsWith(today)) {
226
- todaySessions++;
227
- }
228
- }
229
- }
230
- } catch (e) {
231
- // Provider not available for this project
232
- }
233
- }
234
- }
235
-
236
- res.json({
237
- total: totalSessions,
238
- today: todaySessions,
239
- providers,
240
- projectCount: projects.length,
241
- });
242
- } catch (error) {
243
- res.status(500).json({ error: 'Failed to fetch dashboard stats' });
244
- }
245
- });
246
-
247
- /**
248
- * POST /api/dashboard/api-keys — Create a new API key
249
- */
250
- router.post('/api-keys', async (req, res) => {
251
- try {
252
- const userId = req.user.id;
253
- const keyName = req.body.keyName || 'default';
254
- const result = await apiKeysDb.createApiKey(userId, keyName);
255
- invalidateStatsCache(userId);
256
- res.json({ success: true, key: result });
257
- } catch (error) {
258
- res.status(500).json({ error: 'Failed to create API key' });
259
- }
260
- });
261
-
262
- /**
263
- * DELETE /api/dashboard/api-keys/:id — Delete a specific API key
264
- */
265
- router.delete('/api-keys/:id', async (req, res) => {
266
- try {
267
- const userId = req.user.id;
268
- const keyId = Number(req.params.id);
269
- const deleted = await apiKeysDb.deleteApiKey(userId, keyId);
270
- if (!deleted) return res.status(404).json({ error: 'API key not found' });
271
- invalidateStatsCache(userId);
272
- res.json({ success: true });
273
- } catch (error) {
274
- res.status(500).json({ error: 'Failed to delete API key' });
275
- }
276
- });
277
-
278
- /**
279
- * PATCH /api/dashboard/api-keys/:id/toggle — Toggle API key active/inactive
280
- */
281
- router.patch('/api-keys/:id/toggle', async (req, res) => {
282
- try {
283
- const userId = req.user.id;
284
- const keyId = Number(req.params.id);
285
- const isActive = !!req.body.isActive;
286
- const toggled = await apiKeysDb.toggleApiKey(userId, keyId, isActive);
287
- invalidateStatsCache(userId);
288
- if (!toggled) return res.status(404).json({ error: 'API key not found' });
289
- res.json({ success: true });
290
- } catch (error) {
291
- res.status(500).json({ error: 'Failed to toggle API key' });
292
- }
293
- });
294
-
295
- export default router;