upfynai-code 2.9.0 → 2.9.2

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