upfynai-code 3.0.3 → 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 (243) hide show
  1. package/README.md +66 -91
  2. package/bin/cli.js +191 -0
  3. package/{client/dist → dist/client}/api-docs.html +838 -838
  4. package/{client/dist/assets/AppContent-Bvg0CPCO.js → dist/client/assets/AppContent-BofJquUs.js} +43 -43
  5. package/dist/client/assets/BrowserPanel-CSvD4jOX.js +2 -0
  6. package/dist/client/assets/CanvasFullScreen-onRfarpc.js +1 -0
  7. package/dist/client/assets/CanvasWorkspace-DvGKdL-k.js +259 -0
  8. package/dist/client/assets/DashboardPanel-DqAHbXDO.js +1 -0
  9. package/dist/client/assets/FileTree-BE0h-9M9.js +1 -0
  10. package/{client/dist/assets/GitPanel-RtyZUIWS.js → dist/client/assets/GitPanel-DdeJ0bp5.js} +2 -2
  11. package/{client/dist/assets/LoginModal-BWep8a6g.js → dist/client/assets/LoginModal-BP0pCTrH.js} +3 -3
  12. package/{client/dist/assets/MarkdownPreview-DHmk3qzu.js → dist/client/assets/MarkdownPreview-CESjI261.js} +1 -1
  13. package/dist/client/assets/MermaidBlock-D0rfEhrT.js +2 -0
  14. package/dist/client/assets/Onboarding-B2zQy-_6.js +1 -0
  15. package/dist/client/assets/SetupForm-Be7-WBe-.js +1 -0
  16. package/dist/client/assets/WorkflowsPanel-CusLbVJ6.js +1 -0
  17. package/{client/dist/assets/index-C5ptjuTl.js → dist/client/assets/index-BQy15irW.js} +25 -25
  18. package/dist/client/assets/index-CS0fDqEC.js +1 -0
  19. package/dist/client/assets/index-DYLSCCCp.css +1 -0
  20. package/dist/client/assets/vendor-canvas-QWTduIvM.js +23 -0
  21. package/{client/dist/assets/vendor-codemirror-CbtmxxaB.js → dist/client/assets/vendor-codemirror-D2ALgpaX.js} +1 -1
  22. package/{client/dist/assets/vendor-icons-BaD0x9SL.js → dist/client/assets/vendor-icons-kix3Gb31.js} +178 -138
  23. package/{client/dist/assets/vendor-mermaid-CH7SGc99.js → dist/client/assets/vendor-mermaid-CS3J4_Bz.js} +329 -326
  24. package/{client/dist/assets/vendor-syntax-DuHI9Ok6.js → dist/client/assets/vendor-syntax-LS_Nt30I.js} +1 -1
  25. package/{client/dist → dist/client}/clear-cache.html +85 -85
  26. package/dist/client/favicon.png +0 -0
  27. package/dist/client/favicon.svg +15 -0
  28. package/{client/dist → dist/client}/index.html +17 -17
  29. package/{client/dist → dist/client}/manifest.json +15 -15
  30. package/{client/dist → dist/client}/mcp-docs.html +108 -108
  31. package/{client/dist → dist/client}/offline.html +84 -84
  32. package/{client/dist → dist/client}/sw.js +82 -82
  33. package/package.json +55 -104
  34. package/scripts/postinstall.js +9 -0
  35. package/scripts/prepublish.js +77 -0
  36. package/src/animation.js +228 -0
  37. package/src/auth.js +142 -0
  38. package/src/config.js +40 -0
  39. package/src/connect.js +416 -0
  40. package/src/launch.js +81 -0
  41. package/src/mcp.js +57 -0
  42. package/src/permissions.js +140 -0
  43. package/src/persistent-shell.js +261 -0
  44. package/src/server.js +54 -0
  45. package/client/dist/assets/CanvasFullScreen-BdiJ35aq.js +0 -1
  46. package/client/dist/assets/CanvasWorkspace-Bk9R9_e0.js +0 -163
  47. package/client/dist/assets/DashboardPanel-CblJfTGi.js +0 -1
  48. package/client/dist/assets/FileTree-BDUnBheV.js +0 -1
  49. package/client/dist/assets/MermaidBlock-BuBc_G-F.js +0 -2
  50. package/client/dist/assets/Onboarding-Drnlt75a.js +0 -1
  51. package/client/dist/assets/SetupForm-CtCKitZG.js +0 -1
  52. package/client/dist/assets/WorkflowsPanel-B2mIXDvD.js +0 -1
  53. package/client/dist/assets/index-BFuqS0tY.css +0 -1
  54. package/client/dist/assets/vendor-canvas-D39yWul6.js +0 -49
  55. package/client/dist/favicon.png +0 -0
  56. package/client/dist/favicon.svg +0 -5
  57. package/commands/upfynai-connect.md +0 -59
  58. package/commands/upfynai-disconnect.md +0 -31
  59. package/commands/upfynai-doctor.md +0 -99
  60. package/commands/upfynai-export.md +0 -49
  61. package/commands/upfynai-local.md +0 -82
  62. package/commands/upfynai-status.md +0 -75
  63. package/commands/upfynai-stop.md +0 -49
  64. package/commands/upfynai-uninstall.md +0 -58
  65. package/commands/upfynai.md +0 -69
  66. package/scripts/build-client.js +0 -17
  67. package/scripts/fix-node-pty.js +0 -67
  68. package/scripts/install-commands.js +0 -78
  69. package/server/agent-loop.js +0 -242
  70. package/server/auto-compact.js +0 -99
  71. package/server/claude-sdk.js +0 -797
  72. package/server/cli-ui.js +0 -798
  73. package/server/cli.js +0 -751
  74. package/server/constants/config.js +0 -31
  75. package/server/cursor-cli.js +0 -270
  76. package/server/database/auth.db +0 -0
  77. package/server/database/db.js +0 -1451
  78. package/server/database/init.sql +0 -70
  79. package/server/index.js +0 -3814
  80. package/server/load-env.js +0 -26
  81. package/server/mcp-server.js +0 -621
  82. package/server/middleware/auth.js +0 -181
  83. package/server/middleware/relayHelpers.js +0 -44
  84. package/server/middleware/sandboxRouter.js +0 -174
  85. package/server/openai-codex.js +0 -403
  86. package/server/openrouter.js +0 -137
  87. package/server/projects.js +0 -1807
  88. package/server/provider-factory.js +0 -174
  89. package/server/relay-client.js +0 -390
  90. package/server/routes/agent.js +0 -1234
  91. package/server/routes/auth.js +0 -559
  92. package/server/routes/canvas.js +0 -53
  93. package/server/routes/cli-auth.js +0 -263
  94. package/server/routes/codex.js +0 -396
  95. package/server/routes/commands.js +0 -707
  96. package/server/routes/composio.js +0 -176
  97. package/server/routes/cursor.js +0 -770
  98. package/server/routes/dashboard.js +0 -295
  99. package/server/routes/git.js +0 -1208
  100. package/server/routes/keys.js +0 -34
  101. package/server/routes/mcp-utils.js +0 -48
  102. package/server/routes/mcp.js +0 -661
  103. package/server/routes/payments.js +0 -227
  104. package/server/routes/projects.js +0 -655
  105. package/server/routes/sessions.js +0 -146
  106. package/server/routes/settings.js +0 -261
  107. package/server/routes/taskmaster.js +0 -1928
  108. package/server/routes/user.js +0 -106
  109. package/server/routes/vapi-chat.js +0 -624
  110. package/server/routes/voice.js +0 -235
  111. package/server/routes/webhooks.js +0 -166
  112. package/server/routes/workflows.js +0 -312
  113. package/server/sandbox.js +0 -120
  114. package/server/services/composio.js +0 -204
  115. package/server/services/sessionRegistry.js +0 -139
  116. package/server/services/whisperService.js +0 -84
  117. package/server/services/workflowScheduler.js +0 -211
  118. package/server/tests/relay-flow.test.js +0 -570
  119. package/server/tests/sessions.test.js +0 -259
  120. package/server/utils/commandParser.js +0 -303
  121. package/server/utils/email.js +0 -66
  122. package/server/utils/gitConfig.js +0 -24
  123. package/server/utils/mcp-detector.js +0 -198
  124. package/server/utils/taskmaster-websocket.js +0 -129
  125. package/shared/integrationCatalog.d.ts +0 -12
  126. package/shared/integrationCatalog.js +0 -172
  127. package/shared/modelConstants.js +0 -96
  128. /package/{shared → dist}/agents/claude.js +0 -0
  129. /package/{shared → dist}/agents/codex.js +0 -0
  130. /package/{shared → dist}/agents/cursor.js +0 -0
  131. /package/{shared → dist}/agents/detect.js +0 -0
  132. /package/{shared → dist}/agents/exec.js +0 -0
  133. /package/{shared → dist}/agents/files.js +0 -0
  134. /package/{shared → dist}/agents/git.js +0 -0
  135. /package/{shared → dist}/agents/gitagent.js +0 -0
  136. /package/{shared → dist}/agents/index.js +0 -0
  137. /package/{shared → dist}/agents/shell.js +0 -0
  138. /package/{shared → dist}/agents/utils.js +0 -0
  139. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  140. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  141. /package/{client/dist → dist/client}/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  142. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  143. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  144. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  145. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  146. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  147. /package/{client/dist → dist/client}/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  148. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  149. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  150. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  151. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  152. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  153. /package/{client/dist → dist/client}/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  154. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  155. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  156. /package/{client/dist → dist/client}/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  157. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  158. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  159. /package/{client/dist → dist/client}/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  160. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  161. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  162. /package/{client/dist → dist/client}/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  163. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  164. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  165. /package/{client/dist → dist/client}/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  166. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  167. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  168. /package/{client/dist → dist/client}/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  169. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  170. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  171. /package/{client/dist → dist/client}/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  172. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  173. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  174. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  175. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  176. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  177. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  178. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  179. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  180. /package/{client/dist → dist/client}/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  181. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  182. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  183. /package/{client/dist → dist/client}/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  184. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  185. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  186. /package/{client/dist → dist/client}/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  187. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  188. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  189. /package/{client/dist → dist/client}/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  190. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  191. /package/{client/dist → dist/client}/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  192. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  193. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  194. /package/{client/dist → dist/client}/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  195. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  196. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  197. /package/{client/dist → dist/client}/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  198. /package/{client/dist → dist/client}/assets/PreviewPanel-CqCa92Tf.js +0 -0
  199. /package/{client/dist → dist/client}/assets/pdf-CE_K4jFx.js +0 -0
  200. /package/{client/dist → dist/client}/assets/vendor-canvas-BZV40eAE.css +0 -0
  201. /package/{client/dist → dist/client}/assets/vendor-diff-DNQpbhrT.js +0 -0
  202. /package/{client/dist → dist/client}/assets/vendor-i18n-DCFGyhQR.js +0 -0
  203. /package/{client/dist → dist/client}/assets/vendor-markdown-CimbIo6Y.js +0 -0
  204. /package/{client/dist → dist/client}/assets/vendor-react-96lCPsRK.js +0 -0
  205. /package/{client/dist → dist/client}/assets/vendor-xterm-CZq1hqo1.js +0 -0
  206. /package/{client/dist → dist/client}/assets/vendor-xterm-qxJ8_QYu.css +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}/screenshots/cli-selection.png +0 -0
  238. /package/{client/dist → dist/client}/screenshots/desktop-main.png +0 -0
  239. /package/{client/dist → dist/client}/screenshots/mobile-chat.png +0 -0
  240. /package/{client/dist → dist/client}/screenshots/tools-modal.png +0 -0
  241. /package/{shared → dist}/gitagent/index.js +0 -0
  242. /package/{shared → dist}/gitagent/parser.js +0 -0
  243. /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;