upfynai-code 3.0.4 → 3.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.
Files changed (246) hide show
  1. package/README.md +66 -91
  2. package/bin/cli.js +191 -0
  3. package/{client/dist/assets/AppContent-CwrTP6TW.js → dist/client/assets/AppContent-BofJquUs.js} +4 -4
  4. package/{client/dist/assets/BrowserPanel-0TLEl-IC.js → dist/client/assets/BrowserPanel-CSvD4jOX.js} +2 -2
  5. package/dist/client/assets/CanvasFullScreen-onRfarpc.js +1 -0
  6. package/dist/client/assets/CanvasWorkspace-DvGKdL-k.js +259 -0
  7. package/dist/client/assets/DashboardPanel-DqAHbXDO.js +1 -0
  8. package/dist/client/assets/FileTree-BE0h-9M9.js +1 -0
  9. package/{client/dist/assets/GitPanel-C_xFM-N2.js → dist/client/assets/GitPanel-DdeJ0bp5.js} +2 -2
  10. package/{client/dist/assets/LoginModal-CImJHRjX.js → dist/client/assets/LoginModal-BP0pCTrH.js} +3 -3
  11. package/dist/client/assets/MermaidBlock-D0rfEhrT.js +2 -0
  12. package/dist/client/assets/Onboarding-B2zQy-_6.js +1 -0
  13. package/dist/client/assets/SetupForm-Be7-WBe-.js +1 -0
  14. package/dist/client/assets/WorkflowsPanel-CusLbVJ6.js +1 -0
  15. package/{client/dist/assets/index-HaY-3pK1.js → dist/client/assets/index-BQy15irW.js} +24 -24
  16. package/dist/client/assets/index-CS0fDqEC.js +1 -0
  17. package/dist/client/assets/index-DYLSCCCp.css +1 -0
  18. package/dist/client/assets/vendor-canvas-QWTduIvM.js +23 -0
  19. package/{client/dist/assets/vendor-icons-GyYE35HP.js → dist/client/assets/vendor-icons-kix3Gb31.js} +1 -1
  20. package/{client/dist/assets/vendor-mermaid-DucWyDEe.js → dist/client/assets/vendor-mermaid-CS3J4_Bz.js} +329 -326
  21. package/dist/client/favicon.png +0 -0
  22. package/dist/client/favicon.svg +15 -0
  23. package/{client/dist → dist/client}/index.html +3 -3
  24. package/{client/dist → dist/client}/manifest.json +12 -12
  25. package/package.json +55 -104
  26. package/scripts/postinstall.js +9 -0
  27. package/scripts/prepublish.js +77 -0
  28. package/src/animation.js +228 -0
  29. package/src/auth.js +142 -0
  30. package/src/config.js +40 -0
  31. package/src/connect.js +416 -0
  32. package/src/launch.js +81 -0
  33. package/src/mcp.js +57 -0
  34. package/src/permissions.js +140 -0
  35. package/src/persistent-shell.js +261 -0
  36. package/src/server.js +54 -0
  37. package/client/dist/assets/CanvasFullScreen-D1GWQsGL.js +0 -1
  38. package/client/dist/assets/CanvasWorkspace-D7ORj358.js +0 -163
  39. package/client/dist/assets/DashboardPanel-BV7ybUDe.js +0 -1
  40. package/client/dist/assets/FileTree-5qfhBqdE.js +0 -1
  41. package/client/dist/assets/MermaidBlock-BFM21cwe.js +0 -2
  42. package/client/dist/assets/Onboarding-B3cteLu2.js +0 -1
  43. package/client/dist/assets/SetupForm-P6dsYgHO.js +0 -1
  44. package/client/dist/assets/WorkflowsPanel-CBoN80kc.js +0 -1
  45. package/client/dist/assets/index-46kkVu2i.css +0 -1
  46. package/client/dist/assets/vendor-canvas-DvHJ_Pn2.js +0 -49
  47. package/client/dist/favicon.png +0 -0
  48. package/client/dist/favicon.svg +0 -5
  49. package/commands/upfynai-connect.md +0 -59
  50. package/commands/upfynai-disconnect.md +0 -31
  51. package/commands/upfynai-doctor.md +0 -99
  52. package/commands/upfynai-export.md +0 -49
  53. package/commands/upfynai-local.md +0 -82
  54. package/commands/upfynai-status.md +0 -75
  55. package/commands/upfynai-stop.md +0 -49
  56. package/commands/upfynai-uninstall.md +0 -58
  57. package/commands/upfynai.md +0 -69
  58. package/scripts/build-client.js +0 -17
  59. package/scripts/fix-node-pty.js +0 -67
  60. package/scripts/install-commands.js +0 -78
  61. package/server/agent-loop.js +0 -242
  62. package/server/auto-compact.js +0 -99
  63. package/server/browser.js +0 -131
  64. package/server/claude-sdk.js +0 -797
  65. package/server/cli-ui.js +0 -798
  66. package/server/cli.js +0 -751
  67. package/server/constants/config.js +0 -31
  68. package/server/cursor-cli.js +0 -270
  69. package/server/database/auth.db +0 -0
  70. package/server/database/db.js +0 -1547
  71. package/server/database/init.sql +0 -70
  72. package/server/index.js +0 -3813
  73. package/server/load-env.js +0 -26
  74. package/server/mcp-server.js +0 -621
  75. package/server/middleware/auth.js +0 -184
  76. package/server/middleware/relayHelpers.js +0 -44
  77. package/server/middleware/sandboxRouter.js +0 -174
  78. package/server/openai-codex.js +0 -403
  79. package/server/openrouter.js +0 -137
  80. package/server/projects.js +0 -1807
  81. package/server/provider-factory.js +0 -174
  82. package/server/relay-client.js +0 -390
  83. package/server/routes/agent.js +0 -1234
  84. package/server/routes/auth.js +0 -559
  85. package/server/routes/browser.js +0 -419
  86. package/server/routes/canvas.js +0 -53
  87. package/server/routes/cli-auth.js +0 -263
  88. package/server/routes/codex.js +0 -396
  89. package/server/routes/commands.js +0 -707
  90. package/server/routes/composio.js +0 -176
  91. package/server/routes/cursor.js +0 -770
  92. package/server/routes/dashboard.js +0 -295
  93. package/server/routes/git.js +0 -1208
  94. package/server/routes/keys.js +0 -34
  95. package/server/routes/mcp-utils.js +0 -48
  96. package/server/routes/mcp.js +0 -661
  97. package/server/routes/payments.js +0 -227
  98. package/server/routes/projects.js +0 -754
  99. package/server/routes/sessions.js +0 -146
  100. package/server/routes/settings.js +0 -261
  101. package/server/routes/taskmaster.js +0 -1928
  102. package/server/routes/user.js +0 -106
  103. package/server/routes/vapi-chat.js +0 -624
  104. package/server/routes/voice.js +0 -235
  105. package/server/routes/webhooks.js +0 -166
  106. package/server/routes/workflows.js +0 -312
  107. package/server/sandbox.js +0 -120
  108. package/server/services/browser-ai.js +0 -154
  109. package/server/services/composio.js +0 -204
  110. package/server/services/sessionRegistry.js +0 -139
  111. package/server/services/whisperService.js +0 -84
  112. package/server/services/workflowScheduler.js +0 -211
  113. package/server/tests/relay-flow.test.js +0 -570
  114. package/server/tests/sessions.test.js +0 -259
  115. package/server/utils/commandParser.js +0 -303
  116. package/server/utils/email.js +0 -66
  117. package/server/utils/gitConfig.js +0 -24
  118. package/server/utils/mcp-detector.js +0 -198
  119. package/server/utils/taskmaster-websocket.js +0 -129
  120. package/shared/integrationCatalog.d.ts +0 -12
  121. package/shared/integrationCatalog.js +0 -172
  122. package/shared/modelConstants.js +0 -96
  123. /package/{shared → dist}/agents/claude.js +0 -0
  124. /package/{shared → dist}/agents/codex.js +0 -0
  125. /package/{shared → dist}/agents/cursor.js +0 -0
  126. /package/{shared → dist}/agents/detect.js +0 -0
  127. /package/{shared → dist}/agents/exec.js +0 -0
  128. /package/{shared → dist}/agents/files.js +0 -0
  129. /package/{shared → dist}/agents/git.js +0 -0
  130. /package/{shared → dist}/agents/gitagent.js +0 -0
  131. /package/{shared → dist}/agents/index.js +0 -0
  132. /package/{shared → dist}/agents/shell.js +0 -0
  133. /package/{shared → dist}/agents/utils.js +0 -0
  134. /package/{client/dist → dist/client}/api-docs.html +0 -0
  135. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  136. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  137. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  138. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  139. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  140. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  141. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  142. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  143. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  144. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  145. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  146. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  147. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  148. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  149. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  150. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  151. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  152. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  153. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  154. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  155. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  156. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  157. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  158. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  159. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  160. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  161. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  162. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  163. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  164. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  165. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  166. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  167. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  168. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  169. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  170. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  171. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  172. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  173. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  174. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  175. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  176. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  177. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  178. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  179. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  180. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  181. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  182. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  183. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  184. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  185. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  186. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  187. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  188. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  189. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  190. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  191. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  192. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  193. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  194. /package/{client/dist → dist/client}/assets/MarkdownPreview-CESjI261.js +0 -0
  195. /package/{client/dist → dist/client}/assets/PreviewPanel-CqCa92Tf.js +0 -0
  196. /package/{client/dist → dist/client}/assets/pdf-CE_K4jFx.js +0 -0
  197. /package/{client/dist → dist/client}/assets/vendor-canvas-BZV40eAE.css +0 -0
  198. /package/{client/dist → dist/client}/assets/vendor-codemirror-D2ALgpaX.js +0 -0
  199. /package/{client/dist → dist/client}/assets/vendor-diff-DNQpbhrT.js +0 -0
  200. /package/{client/dist → dist/client}/assets/vendor-i18n-DCFGyhQR.js +0 -0
  201. /package/{client/dist → dist/client}/assets/vendor-markdown-CimbIo6Y.js +0 -0
  202. /package/{client/dist → dist/client}/assets/vendor-react-96lCPsRK.js +0 -0
  203. /package/{client/dist → dist/client}/assets/vendor-syntax-LS_Nt30I.js +0 -0
  204. /package/{client/dist → dist/client}/assets/vendor-xterm-CZq1hqo1.js +0 -0
  205. /package/{client/dist → dist/client}/assets/vendor-xterm-qxJ8_QYu.css +0 -0
  206. /package/{client/dist → dist/client}/clear-cache.html +0 -0
  207. /package/{client/dist → dist/client}/convert-icons.md +0 -0
  208. /package/{client/dist → dist/client}/generate-icons.js +0 -0
  209. /package/{client/dist → dist/client}/icons/claude-ai-icon.svg +0 -0
  210. /package/{client/dist → dist/client}/icons/codex-white.svg +0 -0
  211. /package/{client/dist → dist/client}/icons/codex.svg +0 -0
  212. /package/{client/dist → dist/client}/icons/cursor-white.svg +0 -0
  213. /package/{client/dist → dist/client}/icons/cursor.svg +0 -0
  214. /package/{client/dist → dist/client}/icons/icon-128x128.png +0 -0
  215. /package/{client/dist → dist/client}/icons/icon-128x128.svg +0 -0
  216. /package/{client/dist → dist/client}/icons/icon-144x144.png +0 -0
  217. /package/{client/dist → dist/client}/icons/icon-144x144.svg +0 -0
  218. /package/{client/dist → dist/client}/icons/icon-152x152.png +0 -0
  219. /package/{client/dist → dist/client}/icons/icon-152x152.svg +0 -0
  220. /package/{client/dist → dist/client}/icons/icon-192x192.png +0 -0
  221. /package/{client/dist → dist/client}/icons/icon-192x192.svg +0 -0
  222. /package/{client/dist → dist/client}/icons/icon-384x384.png +0 -0
  223. /package/{client/dist → dist/client}/icons/icon-384x384.svg +0 -0
  224. /package/{client/dist → dist/client}/icons/icon-512x512.png +0 -0
  225. /package/{client/dist → dist/client}/icons/icon-512x512.svg +0 -0
  226. /package/{client/dist → dist/client}/icons/icon-72x72.png +0 -0
  227. /package/{client/dist → dist/client}/icons/icon-72x72.svg +0 -0
  228. /package/{client/dist → dist/client}/icons/icon-96x96.png +0 -0
  229. /package/{client/dist → dist/client}/icons/icon-96x96.svg +0 -0
  230. /package/{client/dist → dist/client}/icons/icon-template.svg +0 -0
  231. /package/{client/dist → dist/client}/logo-128.png +0 -0
  232. /package/{client/dist → dist/client}/logo-256.png +0 -0
  233. /package/{client/dist → dist/client}/logo-32.png +0 -0
  234. /package/{client/dist → dist/client}/logo-512.png +0 -0
  235. /package/{client/dist → dist/client}/logo-64.png +0 -0
  236. /package/{client/dist → dist/client}/logo.svg +0 -0
  237. /package/{client/dist → dist/client}/mcp-docs.html +0 -0
  238. /package/{client/dist → dist/client}/offline.html +0 -0
  239. /package/{client/dist → dist/client}/screenshots/cli-selection.png +0 -0
  240. /package/{client/dist → dist/client}/screenshots/desktop-main.png +0 -0
  241. /package/{client/dist → dist/client}/screenshots/mobile-chat.png +0 -0
  242. /package/{client/dist → dist/client}/screenshots/tools-modal.png +0 -0
  243. /package/{client/dist → dist/client}/sw.js +0 -0
  244. /package/{shared → dist}/gitagent/index.js +0 -0
  245. /package/{shared → dist}/gitagent/parser.js +0 -0
  246. /package/{shared → dist}/gitagent/prompt-builder.js +0 -0
@@ -1,227 +0,0 @@
1
- import express from 'express';
2
- import crypto from 'crypto';
3
- import { subscriptionDb, paymentDb, userDb, PLAN_DURATIONS } from '../database/db.js';
4
-
5
- const router = express.Router();
6
-
7
- // Plan prices in paise (INR × 100) — source of truth
8
- const PLAN_PRICES = {
9
- monthly: { amount: 49900, original: 49900 }, // ₹499
10
- 'half-yearly': { amount: 249900, original: 249900 }, // ₹2,499
11
- yearly: { amount: 49900, original: 499900 }, // ₹499 offer (original ₹4,999)
12
- };
13
-
14
- // Plan tier ordering — higher number = higher tier
15
- const PLAN_TIERS = { monthly: 1, 'half-yearly': 2, yearly: 3 };
16
-
17
- // Lazy-load Razorpay instance
18
- let _razorpay = null;
19
- async function getRazorpay() {
20
- if (_razorpay) return _razorpay;
21
- const keyId = process.env.RAZORPAY_KEY_ID?.trim();
22
- const keySecret = process.env.RAZORPAY_KEY_SECRET?.trim();
23
- if (!keyId || !keySecret) throw new Error('Razorpay credentials not configured');
24
- const Razorpay = (await import('razorpay')).default;
25
- _razorpay = new Razorpay({ key_id: keyId, key_secret: keySecret });
26
- return _razorpay;
27
- }
28
-
29
- // ─── Create Order ───────────────────────────────────────────────────────────────
30
- // Body: { planId, isDowngrade? }
31
- // isDowngrade: if true, uses changePlan (cancels current sub + starts fresh)
32
- // otherwise uses createSub (extends from current expiry for upgrades/renewals)
33
- router.post('/create-order', async (req, res) => {
34
- try {
35
- const userId = req.user.id;
36
- const { planId, isDowngrade } = req.body;
37
-
38
- const plan = PLAN_PRICES[planId];
39
- if (!planId || !plan) {
40
- return res.status(400).json({ error: 'Invalid plan' });
41
- }
42
-
43
- const amountPaise = plan.amount;
44
- const razorpay = await getRazorpay();
45
-
46
- const notes = { userId: String(userId), planId };
47
- if (plan.original !== plan.amount) {
48
- notes.originalPrice = String(plan.original);
49
- notes.offerPrice = String(plan.amount);
50
- }
51
- if (isDowngrade) notes.isDowngrade = 'true';
52
-
53
- const order = await razorpay.orders.create({
54
- amount: amountPaise,
55
- currency: 'INR',
56
- receipt: `upfyn_${userId}_${planId}_${Date.now()}`,
57
- notes,
58
- });
59
-
60
- // Record pending payment
61
- await paymentDb.createPayment(userId, planId, amountPaise, 'INR', order.id);
62
-
63
- res.json({
64
- orderId: order.id,
65
- amount: amountPaise,
66
- originalAmount: plan.original,
67
- currency: 'INR',
68
- });
69
- } catch (error) {
70
- res.status(500).json({ error: 'Could not create order' });
71
- }
72
- });
73
-
74
- // ─── Verify Payment ─────────────────────────────────────────────────────────────
75
- // Body: { orderId, paymentId, signature, planId, isDowngrade? }
76
- router.post('/verify', async (req, res) => {
77
- try {
78
- const userId = req.user.id;
79
- const { orderId, paymentId, signature, planId, isDowngrade } = req.body;
80
-
81
- if (!orderId || !paymentId || !signature || !planId) {
82
- return res.status(400).json({ error: 'Missing payment details' });
83
- }
84
-
85
- // Verify Razorpay signature
86
- const keySecret = process.env.RAZORPAY_KEY_SECRET?.trim();
87
- if (!keySecret) return res.status(500).json({ error: 'Server payment config missing' });
88
-
89
- const expectedSig = crypto
90
- .createHmac('sha256', keySecret)
91
- .update(`${orderId}|${paymentId}`)
92
- .digest('hex');
93
-
94
- if (expectedSig !== signature) {
95
- await paymentDb.markFailed(orderId);
96
- return res.status(400).json({ error: 'Invalid payment signature' });
97
- }
98
-
99
- // Look up the pending payment to get the amount
100
- const payment = await paymentDb.getByOrderId(orderId);
101
- if (!payment) {
102
- return res.status(404).json({ error: 'Order not found' });
103
- }
104
-
105
- if (payment.user_id !== userId) {
106
- return res.status(403).json({ error: 'Order does not belong to this user' });
107
- }
108
-
109
- let sub;
110
- if (isDowngrade) {
111
- // Downgrade: cancel current sub and create new one starting now
112
- sub = await subscriptionDb.changePlan(
113
- userId, planId, payment.amount, payment.currency,
114
- orderId, paymentId, signature
115
- );
116
- } else {
117
- // Upgrade or new: extends from current expiry (or starts now if no active sub)
118
- sub = await subscriptionDb.createSub(
119
- userId, planId, payment.amount, payment.currency,
120
- orderId, paymentId, signature
121
- );
122
- }
123
-
124
- // Mark payment as paid
125
- await paymentDb.markPaid(orderId, paymentId, signature, sub.id);
126
-
127
- // Grant paid access
128
- await userDb.setAccessOverride(userId, 'paid');
129
-
130
- res.json({
131
- success: true,
132
- subscription: {
133
- id: sub.id,
134
- planId: sub.planId,
135
- status: sub.status,
136
- startsAt: sub.startsAt,
137
- expiresAt: sub.expiresAt,
138
- },
139
- });
140
- } catch (error) {
141
- res.status(500).json({ error: 'Payment verification failed' });
142
- }
143
- });
144
-
145
- // ─── Get Current Subscription ───────────────────────────────────────────────────
146
- router.get('/subscription', async (req, res) => {
147
- try {
148
- await subscriptionDb.expireOverdue();
149
- const sub = await subscriptionDb.getActiveSub(req.user.id);
150
- res.json({ subscription: sub || null });
151
- } catch (error) {
152
- res.status(500).json({ error: 'Could not fetch subscription' });
153
- }
154
- });
155
-
156
- // ─── Get Payment History ────────────────────────────────────────────────────────
157
- router.get('/history', async (req, res) => {
158
- try {
159
- const payments = await paymentDb.getUserPayments(req.user.id);
160
- const subscriptions = await subscriptionDb.getAllSubs(req.user.id);
161
- res.json({ payments, subscriptions });
162
- } catch (error) {
163
- res.status(500).json({ error: 'Could not fetch payment history' });
164
- }
165
- });
166
-
167
- // ─── Cancel Subscription ────────────────────────────────────────────────────────
168
- router.post('/cancel', async (req, res) => {
169
- try {
170
- const sub = await subscriptionDb.getActiveSub(req.user.id);
171
- if (!sub) {
172
- return res.status(404).json({ error: 'No active subscription found' });
173
- }
174
- const cancelled = await subscriptionDb.cancelSub(req.user.id, sub.id);
175
- res.json({ success: cancelled });
176
- } catch (error) {
177
- res.status(500).json({ error: 'Could not cancel subscription' });
178
- }
179
- });
180
-
181
- // ─── Invoice / Receipt Details ─────────────────────────────────────────────────
182
- // Returns payment details for a given payment ID (for receipt / invoice view)
183
- router.get('/invoice/:paymentId', async (req, res) => {
184
- try {
185
- const payments = await paymentDb.getUserPayments(req.user.id);
186
- const payment = payments.find(p => String(p.id) === req.params.paymentId);
187
- if (!payment) {
188
- return res.status(404).json({ error: 'Payment not found' });
189
- }
190
-
191
- // Fetch payment details from Razorpay if payment ID is available
192
- let razorpayDetails = null;
193
- if (payment.razorpay_payment_id) {
194
- try {
195
- const razorpay = await getRazorpay();
196
- razorpayDetails = await razorpay.payments.fetch(payment.razorpay_payment_id);
197
- } catch { /* Razorpay fetch failed — return local data only */ }
198
- }
199
-
200
- const planName = {
201
- monthly: 'Monthly Plan',
202
- 'half-yearly': '6-Month Plan',
203
- yearly: 'Annual Plan',
204
- }[payment.plan_id] || payment.plan_id;
205
-
206
- res.json({
207
- id: payment.id,
208
- planId: payment.plan_id,
209
- planName,
210
- amount: payment.amount,
211
- currency: payment.currency || 'INR',
212
- status: payment.status,
213
- createdAt: payment.created_at,
214
- razorpayOrderId: payment.razorpay_order_id || null,
215
- razorpayPaymentId: payment.razorpay_payment_id || null,
216
- // Razorpay payment details (method, email, contact, etc.)
217
- method: razorpayDetails?.method || null,
218
- email: razorpayDetails?.email || null,
219
- contact: razorpayDetails?.contact || null,
220
- description: razorpayDetails?.description || null,
221
- });
222
- } catch (error) {
223
- res.status(500).json({ error: 'Could not fetch invoice details' });
224
- }
225
- });
226
-
227
- export default router;