@lastbrain/module-ai 2.0.26 → 2.0.30

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 (365) hide show
  1. package/README.md +52 -1
  2. package/dist/ai.build.config.d.ts.map +1 -1
  3. package/dist/ai.build.config.js +508 -9
  4. package/dist/api/admin/ai-provider-models/[id].d.ts +18 -0
  5. package/dist/api/admin/ai-provider-models/[id].d.ts.map +1 -0
  6. package/dist/api/admin/ai-provider-models/[id].js +58 -0
  7. package/dist/api/admin/ai-provider-models.d.ts +20 -0
  8. package/dist/api/admin/ai-provider-models.d.ts.map +1 -0
  9. package/dist/api/admin/ai-provider-models.js +26 -0
  10. package/dist/api/admin/ai-providers/[key].d.ts +18 -0
  11. package/dist/api/admin/ai-providers/[key].d.ts.map +1 -0
  12. package/dist/api/admin/ai-providers/[key].js +55 -0
  13. package/dist/api/admin/ai-providers.d.ts +20 -0
  14. package/dist/api/admin/ai-providers.d.ts.map +1 -0
  15. package/dist/api/admin/ai-providers.js +26 -0
  16. package/dist/api/admin/billing-analytics.d.ts +43 -0
  17. package/dist/api/admin/billing-analytics.d.ts.map +1 -0
  18. package/dist/api/admin/billing-analytics.js +144 -0
  19. package/dist/api/admin/global-ai-settings.d.ts +14 -0
  20. package/dist/api/admin/global-ai-settings.d.ts.map +1 -0
  21. package/dist/api/admin/global-ai-settings.js +63 -0
  22. package/dist/api/admin/token-packs/[id].d.ts.map +1 -1
  23. package/dist/api/admin/token-packs/[id].js +3 -2
  24. package/dist/api/admin/token-packs.d.ts.map +1 -1
  25. package/dist/api/admin/token-packs.js +3 -2
  26. package/dist/api/admin/user-monthly-details.d.ts +49 -0
  27. package/dist/api/admin/user-monthly-details.d.ts.map +1 -0
  28. package/dist/api/admin/user-monthly-details.js +140 -0
  29. package/dist/api/admin/user-quota.d.ts +21 -0
  30. package/dist/api/admin/user-quota.d.ts.map +1 -0
  31. package/dist/api/admin/user-quota.js +59 -0
  32. package/dist/api/admin/user-token/[id].d.ts.map +1 -1
  33. package/dist/api/admin/user-token/[id].js +2 -1
  34. package/dist/api/admin/user-token.d.ts +5 -2
  35. package/dist/api/admin/user-token.d.ts.map +1 -1
  36. package/dist/api/admin/user-token.js +91 -17
  37. package/dist/api/admin/user-usage-by-model.d.ts +22 -0
  38. package/dist/api/admin/user-usage-by-model.d.ts.map +1 -0
  39. package/dist/api/admin/user-usage-by-model.js +78 -0
  40. package/dist/api/admin/user-wallet-analytics.d.ts +15 -0
  41. package/dist/api/admin/user-wallet-analytics.d.ts.map +1 -0
  42. package/dist/api/admin/user-wallet-analytics.js +67 -0
  43. package/dist/api/admin/wallet-repair/route.d.ts +30 -0
  44. package/dist/api/admin/wallet-repair/route.d.ts.map +1 -0
  45. package/dist/api/admin/wallet-repair/route.js +63 -0
  46. package/dist/api/auth/ai-model-settings.d.ts +21 -0
  47. package/dist/api/auth/ai-model-settings.d.ts.map +1 -0
  48. package/dist/api/auth/ai-model-settings.js +86 -0
  49. package/dist/api/auth/ai-settings.d.ts +17 -0
  50. package/dist/api/auth/ai-settings.d.ts.map +1 -0
  51. package/dist/api/auth/ai-settings.js +87 -0
  52. package/dist/api/auth/api-keys/[id].d.ts +17 -0
  53. package/dist/api/auth/api-keys/[id].d.ts.map +1 -0
  54. package/dist/api/auth/api-keys/[id].js +66 -0
  55. package/dist/api/auth/api-keys.d.ts +19 -0
  56. package/dist/api/auth/api-keys.d.ts.map +1 -0
  57. package/dist/api/auth/api-keys.js +94 -0
  58. package/dist/api/auth/create-checkout.d.ts +1 -1
  59. package/dist/api/auth/create-checkout.d.ts.map +1 -1
  60. package/dist/api/auth/create-checkout.js +8 -6
  61. package/dist/api/auth/generate-image.d.ts +2 -2
  62. package/dist/api/auth/generate-image.d.ts.map +1 -1
  63. package/dist/api/auth/generate-image.js +404 -104
  64. package/dist/api/auth/generate-text.d.ts +3 -2
  65. package/dist/api/auth/generate-text.d.ts.map +1 -1
  66. package/dist/api/auth/generate-text.js +130 -58
  67. package/dist/api/auth/process-ocr.d.ts +9 -0
  68. package/dist/api/auth/process-ocr.d.ts.map +1 -0
  69. package/dist/api/auth/process-ocr.js +43 -0
  70. package/dist/api/auth/prompts/stats.d.ts +14 -0
  71. package/dist/api/auth/prompts/stats.d.ts.map +1 -0
  72. package/dist/api/auth/prompts/stats.js +46 -0
  73. package/dist/api/auth/prompts.d.ts +26 -0
  74. package/dist/api/auth/prompts.d.ts.map +1 -0
  75. package/dist/api/auth/prompts.js +175 -0
  76. package/dist/api/auth/token-balance.d.ts +26 -0
  77. package/dist/api/auth/token-balance.d.ts.map +1 -0
  78. package/dist/api/auth/token-balance.js +47 -0
  79. package/dist/api/auth/token-checkout.d.ts.map +1 -1
  80. package/dist/api/auth/token-checkout.js +22 -4
  81. package/dist/api/auth/token-packs.d.ts.map +1 -1
  82. package/dist/api/auth/token-packs.js +2 -1
  83. package/dist/api/auth/usage-by-model.d.ts +25 -0
  84. package/dist/api/auth/usage-by-model.d.ts.map +1 -0
  85. package/dist/api/auth/usage-by-model.js +95 -0
  86. package/dist/api/auth/usage.d.ts +26 -0
  87. package/dist/api/auth/usage.d.ts.map +1 -0
  88. package/dist/api/auth/usage.js +127 -0
  89. package/dist/api/auth/user-tokens.d.ts.map +1 -1
  90. package/dist/api/auth/user-tokens.js +36 -2
  91. package/dist/api/auth/wallet/route.d.ts +17 -0
  92. package/dist/api/auth/wallet/route.d.ts.map +1 -0
  93. package/dist/api/auth/wallet/route.js +68 -0
  94. package/dist/api/auth/wallet.d.ts +16 -0
  95. package/dist/api/auth/wallet.d.ts.map +1 -0
  96. package/dist/api/auth/wallet.js +71 -0
  97. package/dist/api/public/gateway-models.d.ts +25 -0
  98. package/dist/api/public/gateway-models.d.ts.map +1 -0
  99. package/dist/api/public/gateway-models.js +49 -0
  100. package/dist/api/public/pricing-summary.d.ts +46 -0
  101. package/dist/api/public/pricing-summary.d.ts.map +1 -0
  102. package/dist/api/public/pricing-summary.js +70 -0
  103. package/dist/api/public/prompts/[id]/stats.d.ts +15 -0
  104. package/dist/api/public/prompts/[id]/stats.d.ts.map +1 -0
  105. package/dist/api/public/prompts/[id]/stats.js +37 -0
  106. package/dist/api/public/prompts/[id]/view.d.ts +15 -0
  107. package/dist/api/public/prompts/[id]/view.d.ts.map +1 -0
  108. package/dist/api/public/prompts/[id]/view.js +41 -0
  109. package/dist/api/public/prompts/slug/[slug].d.ts +15 -0
  110. package/dist/api/public/prompts/slug/[slug].d.ts.map +1 -0
  111. package/dist/api/public/prompts/slug/[slug].js +40 -0
  112. package/dist/api/public/prompts/user/[username].d.ts +17 -0
  113. package/dist/api/public/prompts/user/[username].d.ts.map +1 -0
  114. package/dist/api/public/prompts/user/[username].js +51 -0
  115. package/dist/api/public/prompts.d.ts +15 -0
  116. package/dist/api/public/prompts.d.ts.map +1 -0
  117. package/dist/api/public/prompts.js +45 -0
  118. package/dist/api/public/token-packs.d.ts +11 -0
  119. package/dist/api/public/token-packs.d.ts.map +1 -0
  120. package/dist/api/public/token-packs.js +25 -0
  121. package/dist/api/public/token-pricing.d.ts +44 -0
  122. package/dist/api/public/token-pricing.d.ts.map +1 -0
  123. package/dist/api/public/token-pricing.js +168 -0
  124. package/dist/api/public/v1/_lib/artifacts.d.ts +52 -0
  125. package/dist/api/public/v1/_lib/artifacts.d.ts.map +1 -0
  126. package/dist/api/public/v1/_lib/artifacts.js +217 -0
  127. package/dist/api/public/v1/_lib/auth.d.ts +43 -0
  128. package/dist/api/public/v1/_lib/auth.d.ts.map +1 -0
  129. package/dist/api/public/v1/_lib/auth.js +108 -0
  130. package/dist/api/public/v1/_lib/errors.d.ts +17 -0
  131. package/dist/api/public/v1/_lib/errors.d.ts.map +1 -0
  132. package/dist/api/public/v1/_lib/errors.js +16 -0
  133. package/dist/api/public/v1/_lib/log.d.ts +29 -0
  134. package/dist/api/public/v1/_lib/log.d.ts.map +1 -0
  135. package/dist/api/public/v1/_lib/log.js +68 -0
  136. package/dist/api/public/v1/_lib/quota.d.ts +24 -0
  137. package/dist/api/public/v1/_lib/quota.d.ts.map +1 -0
  138. package/dist/api/public/v1/_lib/quota.js +118 -0
  139. package/dist/api/public/v1/_lib/router.d.ts +54 -0
  140. package/dist/api/public/v1/_lib/router.d.ts.map +1 -0
  141. package/dist/api/public/v1/_lib/router.js +119 -0
  142. package/dist/api/public/v1/connect.d.ts +20 -0
  143. package/dist/api/public/v1/connect.d.ts.map +1 -0
  144. package/dist/api/public/v1/connect.js +119 -0
  145. package/dist/api/public/v1/doc.d.ts +239 -0
  146. package/dist/api/public/v1/doc.d.ts.map +1 -0
  147. package/dist/api/public/v1/doc.js +253 -0
  148. package/dist/api/public/v1/history/[id].d.ts +92 -0
  149. package/dist/api/public/v1/history/[id].d.ts.map +1 -0
  150. package/dist/api/public/v1/history/[id].js +176 -0
  151. package/dist/api/public/v1/history.d.ts +30 -0
  152. package/dist/api/public/v1/history.d.ts.map +1 -0
  153. package/dist/api/public/v1/history.js +142 -0
  154. package/dist/api/public/v1/image-ai.d.ts +24 -0
  155. package/dist/api/public/v1/image-ai.d.ts.map +1 -0
  156. package/dist/api/public/v1/image-ai.js +233 -0
  157. package/dist/api/public/v1/prompts.d.ts +19 -0
  158. package/dist/api/public/v1/prompts.d.ts.map +1 -0
  159. package/dist/api/public/v1/prompts.js +107 -0
  160. package/dist/api/public/v1/provider.d.ts +16 -0
  161. package/dist/api/public/v1/provider.d.ts.map +1 -0
  162. package/dist/api/public/v1/provider.js +130 -0
  163. package/dist/api/public/v1/purchase.d.ts +11 -0
  164. package/dist/api/public/v1/purchase.d.ts.map +1 -0
  165. package/dist/api/public/v1/purchase.js +18 -0
  166. package/dist/api/public/v1/status.d.ts +35 -0
  167. package/dist/api/public/v1/status.d.ts.map +1 -0
  168. package/dist/api/public/v1/status.js +163 -0
  169. package/dist/api/public/v1/text-ai.d.ts +26 -0
  170. package/dist/api/public/v1/text-ai.d.ts.map +1 -0
  171. package/dist/api/public/v1/text-ai.js +239 -0
  172. package/dist/api/public/webhook.d.ts.map +1 -1
  173. package/dist/api/public/webhook.js +50 -39
  174. package/dist/api/track-usage.d.ts +12 -0
  175. package/dist/api/track-usage.d.ts.map +1 -0
  176. package/dist/api/track-usage.js +37 -0
  177. package/dist/components/Doc.d.ts.map +1 -1
  178. package/dist/components/Doc.js +1 -1
  179. package/dist/components/DocUsageCustom.js +6 -6
  180. package/dist/components/admin/UserTokenTab.d.ts.map +1 -1
  181. package/dist/components/admin/UserTokenTab.js +170 -23
  182. package/dist/components/auth/AuthDashboardAi.d.ts +2 -0
  183. package/dist/components/auth/AuthDashboardAi.d.ts.map +1 -0
  184. package/dist/components/auth/AuthDashboardAi.js +53 -0
  185. package/dist/docs/REFACTORING_BILLING_GUIDE.d.ts +277 -0
  186. package/dist/docs/REFACTORING_BILLING_GUIDE.d.ts.map +1 -0
  187. package/dist/docs/REFACTORING_BILLING_GUIDE.js +276 -0
  188. package/dist/index.d.ts +15 -1
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js +18 -1
  191. package/dist/scripts/migrate-tokens-to-wallet.d.ts +13 -0
  192. package/dist/scripts/migrate-tokens-to-wallet.d.ts.map +1 -0
  193. package/dist/scripts/migrate-tokens-to-wallet.js +165 -0
  194. package/dist/server/__tests__/billing.test.d.ts +5 -0
  195. package/dist/server/__tests__/billing.test.d.ts.map +1 -0
  196. package/dist/server/__tests__/billing.test.js +223 -0
  197. package/dist/server/ai-client.d.ts +59 -0
  198. package/dist/server/ai-client.d.ts.map +1 -0
  199. package/dist/server/ai-client.js +111 -0
  200. package/dist/server/ai-generation-service.d.ts +66 -0
  201. package/dist/server/ai-generation-service.d.ts.map +1 -0
  202. package/dist/server/ai-generation-service.js +274 -0
  203. package/dist/server/billing.d.ts +200 -0
  204. package/dist/server/billing.d.ts.map +1 -0
  205. package/dist/server/billing.js +488 -0
  206. package/dist/server/gateway-service.d.ts +13 -0
  207. package/dist/server/gateway-service.d.ts.map +1 -0
  208. package/dist/server/gateway-service.js +161 -0
  209. package/dist/server/global-settings.d.ts +16 -0
  210. package/dist/server/global-settings.d.ts.map +1 -0
  211. package/dist/server/global-settings.js +42 -0
  212. package/dist/server/model-filter.d.ts +25 -0
  213. package/dist/server/model-filter.d.ts.map +1 -0
  214. package/dist/server/model-filter.js +240 -0
  215. package/dist/server/ocr.d.ts +39 -0
  216. package/dist/server/ocr.d.ts.map +1 -0
  217. package/dist/server/ocr.js +280 -0
  218. package/dist/server/openai-client.d.ts +19 -0
  219. package/dist/server/openai-client.d.ts.map +1 -0
  220. package/dist/server/openai-client.js +26 -0
  221. package/dist/server/pricing-config.d.ts +18 -0
  222. package/dist/server/pricing-config.d.ts.map +1 -0
  223. package/dist/server/pricing-config.js +94 -0
  224. package/dist/server/pricing-validator.d.ts +41 -0
  225. package/dist/server/pricing-validator.d.ts.map +1 -0
  226. package/dist/server/pricing-validator.js +113 -0
  227. package/dist/server/pricing.d.ts +121 -0
  228. package/dist/server/pricing.d.ts.map +1 -0
  229. package/dist/server/pricing.js +225 -0
  230. package/dist/server/quota.d.ts +66 -0
  231. package/dist/server/quota.d.ts.map +1 -0
  232. package/dist/server/quota.js +538 -0
  233. package/dist/server/wallet-repair.d.ts +32 -0
  234. package/dist/server/wallet-repair.d.ts.map +1 -0
  235. package/dist/server/wallet-repair.js +189 -0
  236. package/dist/server.d.ts +13 -1
  237. package/dist/server.d.ts.map +1 -1
  238. package/dist/server.js +87 -16
  239. package/dist/sitemap/handlers/prompts.d.ts +6 -0
  240. package/dist/sitemap/handlers/prompts.d.ts.map +1 -0
  241. package/dist/sitemap/handlers/prompts.js +72 -0
  242. package/dist/sitemap/handlers/users.d.ts +6 -0
  243. package/dist/sitemap/handlers/users.d.ts.map +1 -0
  244. package/dist/sitemap/handlers/users.js +80 -0
  245. package/dist/sitemap/manifest.d.ts +8 -0
  246. package/dist/sitemap/manifest.d.ts.map +1 -0
  247. package/dist/sitemap/manifest.js +27 -0
  248. package/dist/types/gateway.d.ts +40 -0
  249. package/dist/types/gateway.d.ts.map +1 -0
  250. package/dist/types/gateway.js +4 -0
  251. package/dist/types/quota.d.ts +74 -0
  252. package/dist/types/quota.d.ts.map +1 -0
  253. package/dist/types/quota.js +11 -0
  254. package/dist/utils/date.d.ts +7 -0
  255. package/dist/utils/date.d.ts.map +1 -0
  256. package/dist/utils/date.js +17 -0
  257. package/dist/web/admin/AdminTokenPacksPage.js +1 -1
  258. package/dist/web/admin/BillingAnalyticsPage.d.ts +2 -0
  259. package/dist/web/admin/BillingAnalyticsPage.d.ts.map +1 -0
  260. package/dist/web/admin/BillingAnalyticsPage.js +141 -0
  261. package/dist/web/admin/GlobalAISettingsPage.d.ts +2 -0
  262. package/dist/web/admin/GlobalAISettingsPage.d.ts.map +1 -0
  263. package/dist/web/admin/GlobalAISettingsPage.js +93 -0
  264. package/dist/web/admin/UserTokenPage.d.ts.map +1 -1
  265. package/dist/web/admin/UserTokenPage.js +20 -7
  266. package/dist/web/auth/AISettingsPage.d.ts +2 -0
  267. package/dist/web/auth/AISettingsPage.d.ts.map +1 -0
  268. package/dist/web/auth/AISettingsPage.js +258 -0
  269. package/dist/web/auth/APIKeysPage.d.ts +2 -0
  270. package/dist/web/auth/APIKeysPage.d.ts.map +1 -0
  271. package/dist/web/auth/APIKeysPage.js +154 -0
  272. package/dist/web/auth/HistoryPage.d.ts +2 -0
  273. package/dist/web/auth/HistoryPage.d.ts.map +1 -0
  274. package/dist/web/auth/HistoryPage.js +279 -0
  275. package/dist/web/auth/PromptsPage.d.ts +5 -0
  276. package/dist/web/auth/PromptsPage.d.ts.map +1 -0
  277. package/dist/web/auth/PromptsPage.js +137 -0
  278. package/dist/web/auth/TokenPage.d.ts.map +1 -1
  279. package/dist/web/auth/TokenPage.js +88 -31
  280. package/dist/web/auth/UsageAndTokensPage.d.ts +2 -0
  281. package/dist/web/auth/UsageAndTokensPage.d.ts.map +1 -0
  282. package/dist/web/auth/UsageAndTokensPage.js +157 -0
  283. package/dist/web/auth/UsagePage.d.ts +2 -0
  284. package/dist/web/auth/UsagePage.d.ts.map +1 -0
  285. package/dist/web/auth/UsagePage.js +62 -0
  286. package/dist/web/auth/components/ApiKeyFilterSelect.d.ts +13 -0
  287. package/dist/web/auth/components/ApiKeyFilterSelect.d.ts.map +1 -0
  288. package/dist/web/auth/components/ApiKeyFilterSelect.js +16 -0
  289. package/dist/web/auth/components/ModelUsageTable.d.ts +19 -0
  290. package/dist/web/auth/components/ModelUsageTable.d.ts.map +1 -0
  291. package/dist/web/auth/components/ModelUsageTable.js +37 -0
  292. package/dist/web/auth/components/PurchaseButton.d.ts +7 -0
  293. package/dist/web/auth/components/PurchaseButton.d.ts.map +1 -0
  294. package/dist/web/auth/components/PurchaseButton.js +13 -0
  295. package/dist/web/auth/components/TokenHistoryCard.d.ts +20 -0
  296. package/dist/web/auth/components/TokenHistoryCard.d.ts.map +1 -0
  297. package/dist/web/auth/components/TokenHistoryCard.js +76 -0
  298. package/dist/web/auth/components/TokenKpiGrid.d.ts +24 -0
  299. package/dist/web/auth/components/TokenKpiGrid.d.ts.map +1 -0
  300. package/dist/web/auth/components/TokenKpiGrid.js +38 -0
  301. package/dist/web/auth/components/UsageByDayChart.d.ts +11 -0
  302. package/dist/web/auth/components/UsageByDayChart.d.ts.map +1 -0
  303. package/dist/web/auth/components/UsageByDayChart.js +32 -0
  304. package/dist/web/auth/components/UsageByModelBarChart.d.ts +12 -0
  305. package/dist/web/auth/components/UsageByModelBarChart.d.ts.map +1 -0
  306. package/dist/web/auth/components/UsageByModelBarChart.js +32 -0
  307. package/dist/web/auth/components/WalletStatusCard.d.ts +9 -0
  308. package/dist/web/auth/components/WalletStatusCard.d.ts.map +1 -0
  309. package/dist/web/auth/components/WalletStatusCard.js +50 -0
  310. package/dist/web/components/ImageGenerative.d.ts +3 -1
  311. package/dist/web/components/ImageGenerative.d.ts.map +1 -1
  312. package/dist/web/components/ImageGenerative.js +139 -52
  313. package/dist/web/components/TextareaGenerative.d.ts +3 -1
  314. package/dist/web/components/TextareaGenerative.d.ts.map +1 -1
  315. package/dist/web/components/TextareaGenerative.js +10 -5
  316. package/dist/web/public/PromptDetailPage.d.ts +25 -0
  317. package/dist/web/public/PromptDetailPage.d.ts.map +1 -0
  318. package/dist/web/public/PromptDetailPage.js +71 -0
  319. package/dist/web/public/PromptDetailPageServer.d.ts +15 -0
  320. package/dist/web/public/PromptDetailPageServer.d.ts.map +1 -0
  321. package/dist/web/public/PromptDetailPageServer.js +68 -0
  322. package/dist/web/public/PublicPromptsPage.d.ts +5 -0
  323. package/dist/web/public/PublicPromptsPage.d.ts.map +1 -0
  324. package/dist/web/public/PublicPromptsPage.js +110 -0
  325. package/dist/web/public/PurchaseTokensPage.d.ts +2 -0
  326. package/dist/web/public/PurchaseTokensPage.d.ts.map +1 -0
  327. package/dist/web/public/PurchaseTokensPage.js +98 -0
  328. package/dist/web/public/UserAvatar.d.ts +13 -0
  329. package/dist/web/public/UserAvatar.d.ts.map +1 -0
  330. package/dist/web/public/UserAvatar.js +13 -0
  331. package/dist/web/public/UserDetailPageServer.d.ts +15 -0
  332. package/dist/web/public/UserDetailPageServer.d.ts.map +1 -0
  333. package/dist/web/public/UserDetailPageServer.js +31 -0
  334. package/dist/web/public/UserPromptsPage.d.ts +9 -0
  335. package/dist/web/public/UserPromptsPage.d.ts.map +1 -0
  336. package/dist/web/public/UserPromptsPage.js +112 -0
  337. package/dist/web/public/UserPromptsPageServer.d.ts +15 -0
  338. package/dist/web/public/UserPromptsPageServer.d.ts.map +1 -0
  339. package/dist/web/public/UserPromptsPageServer.js +31 -0
  340. package/package.json +18 -9
  341. package/supabase/migrations/20251125000000_ai_tokens.sql +7 -0
  342. package/supabase/migrations/20260123100002_user_token_quota_monthly copy.sql +173 -0
  343. package/supabase/migrations/20260128100003_update_and_add_table.sql +368 -0
  344. package/supabase/migrations/20260128120000_seed_providers_models.sql +78 -0
  345. package/supabase/migrations/20260128131405_add_api_key_id_to_ledgers.sql +41 -0
  346. package/supabase/migrations/20260128140000_ai_artifacts_storage.sql +99 -0
  347. package/supabase/migrations/20260128140002_ai_user_settings.sql +57 -0
  348. package/supabase/migrations/20260128150000_drop_ai_user_settings.sql +21 -0
  349. package/supabase/migrations/20260128160000_wallet_billing_system.sql +192 -0
  350. package/supabase/migrations/20260128160001_wallet_rpc_functions.sql +165 -0
  351. package/supabase/migrations/20260128170000_add_pack_coef_to_token_packs.sql +30 -0
  352. package/supabase/migrations/20260129120000_wallet_view_rpc.sql +41 -0
  353. package/supabase/migrations/20260129220003_update_pack_margins.sql +31 -0
  354. package/supabase/migrations/20260129330004_ai_user_prompts.sql +151 -0
  355. package/supabase/migrations/20260129330005_ai_prompts_ip_tracking.sql +92 -0
  356. package/supabase/migrations/20260129330006_ai_prompts_slug.sql +64 -0
  357. package/supabase/migrations/20260129330007_ai_prompts_view_slug.sql +26 -0
  358. package/supabase/migrations/20260129440000_ai_prompts_view_username.sql +33 -0
  359. package/supabase/migrations/20260129450000_ai_prompts_add_lang.sql +40 -0
  360. package/supabase/migrations/20260131000000_extract_model_prompt_in_ledger.sql +92 -0
  361. package/supabase/migrations/20260131140000_fix_duplicate_purchases.sql +64 -0
  362. package/supabase/migrations/20260201120000_module-ai_default_models.sql +63 -0
  363. package/supabase/migrations/20260201130000_module-ai_remove_provider_tables.sql +17 -0
  364. package/supabase/migrations-down/20251217120000_user_token_quota_monthly.sql +34 -0
  365. package/supabase/migrations-down/20260128131405_add_api_key_id_to_ledgers.sql +25 -0
@@ -1,38 +1,77 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { getSupabaseServerClient } from "@lastbrain/core/server";
3
- import { deductTokens, getTokenBalance } from "../../server";
4
- import OpenAI from "openai";
5
- let openai = null;
6
- function getOpenAIClient() {
7
- if (!openai) {
8
- openai = new OpenAI({
9
- apiKey: process.env.OPENAI_API_KEY,
10
- });
11
- }
12
- return openai;
13
- }
3
+ import { textAI } from "../../server/ai-client";
4
+ import { logger } from "@lastbrain/core";
5
+ import { computeAndDebitAIUsage, computeProviderCostUsd, getWalletState, } from "../../server/billing";
6
+ import { isModelEnabled } from "../../server/model-filter";
7
+ import { validateTextPricing } from "../../server/pricing-validator";
8
+ import { getDefaultTextModel } from "../../server/global-settings";
14
9
  export async function POST(request) {
15
10
  try {
16
- const supabase = await getSupabaseServerClient();
11
+ const MAX_CHARS = 1200;
12
+ const supabaseAuth = await getSupabaseServerClient();
17
13
  // Vérifier l'authentification
18
- const { data: { user }, } = await supabase.auth.getUser();
14
+ const { data: { user }, } = await supabaseAuth.auth.getUser();
19
15
  // L'utilisateur est déjà authentifié grâce au middleware
20
16
  const body = await request.json();
21
- const { prompt, model = "gpt-4o-mini", context, maxTokens = 3000, temperature = 0.7, } = body;
17
+ // Get default model from global settings if not provided
18
+ const defaultModel = await getDefaultTextModel();
19
+ const { prompt, promptUser, model = defaultModel, // Use global default instead of hardcoded
20
+ context, maxTokens = 3000, temperature = 0.7, actionType = "generate-text", // Default to generate-text if not specified
21
+ } = body;
22
22
  if (!prompt) {
23
23
  return NextResponse.json({ error: "Le prompt est requis" }, { status: 400 });
24
24
  }
25
+ if (promptUser) {
26
+ logger.info("promptUser length:", promptUser.length);
27
+ }
28
+ if (promptUser && promptUser.length > MAX_CHARS) {
29
+ return NextResponse.json({ error: "Prompt trop long max 1200 caractères" }, { status: 400 });
30
+ }
25
31
  if (!user) {
26
32
  return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
27
33
  }
28
- // Vérifier le solde de tokens
29
- const currentBalance = await getTokenBalance(user.id);
30
- const estimatedCost = 0; //Math.ceil(prompt.length / 4) + maxTokens; // Estimation approximative
31
- if (currentBalance < estimatedCost || currentBalance <= 0) {
32
- return NextResponse.json({
33
- error: `Solde insuffisant. Disponible: ${currentBalance}`,
34
- }, { status: 402 });
34
+ // Build model string: "openai/model" or use full if already formatted
35
+ const fullModel = model.includes("/") ? model : `openai/${model}`;
36
+ // Parse provider/model from fullModel
37
+ const [provider, modelName] = fullModel.includes("/")
38
+ ? fullModel.split("/", 2)
39
+ : ["openai", fullModel];
40
+ // Skip model check for recipe and image generation (always allowed)
41
+ const isRecipeAction = actionType === "generate-recipe-text";
42
+ // Get model pricing via model-filter (BEFORE generation to check credits)
43
+ // For recipes, bypass user settings and use default pricing
44
+ const filterResult = isRecipeAction
45
+ ? {
46
+ allowed: true,
47
+ model: {
48
+ pricing: {
49
+ input: 0.15 / 1000000, // $0.15 per 1M tokens (gpt-4o-mini default)
50
+ output: 0.6 / 1000000, // $0.60 per 1M tokens
51
+ },
52
+ },
53
+ }
54
+ : await isModelEnabled(user.id, fullModel);
55
+ if (!filterResult.allowed) {
56
+ logger.warn(`[generate-text] Model ${fullModel} not allowed for user ${user.id}`);
57
+ return NextResponse.json({ error: "Modèle non autorisé" }, { status: 403 });
58
+ }
59
+ // Prepare pricing for wallet billing
60
+ const pricingValidation = validateTextPricing(filterResult.model?.pricing, fullModel);
61
+ if (!pricingValidation.valid) {
62
+ return NextResponse.json({ error: pricingValidation.error }, { status: 503 });
63
+ }
64
+ const pricing = pricingValidation.pricing;
65
+ // Get current wallet state
66
+ const wallet = await getWalletState(user.id);
67
+ // PRE-CHECK: Simple check - user must have credits (> 0)
68
+ // The real debit with minimums will be computed post-generation
69
+ if (!wallet.walletProviderBudgetUsd ||
70
+ wallet.walletProviderBudgetUsd <= 0) {
71
+ logger.warn(`[generate-text] No credits for user ${user.id}: wallet=$${wallet.walletProviderBudgetUsd}`);
72
+ return NextResponse.json({ error: "Crédits insuffisants pour cette opération" }, { status: 402 });
35
73
  }
74
+ logger.info(`[generate-text] Pre-check passed for user ${user.id}: wallet=$${wallet.walletProviderBudgetUsd.toFixed(6)}`);
36
75
  // Construire les messages
37
76
  const messages = [
38
77
  {
@@ -50,56 +89,89 @@ export async function POST(request) {
50
89
  role: "user",
51
90
  content: prompt,
52
91
  });
53
- // Appeler OpenAI
54
- const openaiClient = getOpenAIClient();
55
- const completion = await openaiClient.chat.completions.create({
56
- model,
57
- messages,
92
+ logger.info(`[AI] Generating text with model: ${fullModel}`);
93
+ // Call our simplified AI client
94
+ const completion = await textAI({
95
+ prompt,
96
+ model: fullModel,
97
+ system: "Tu es un assistant IA qui aide à générer du texte de qualité.",
98
+ maxTokens,
58
99
  temperature,
59
- max_tokens: maxTokens,
60
100
  });
61
- const generatedText = completion.choices[0]?.message?.content || "";
62
- const tokensUsed = completion.usage?.total_tokens || 0;
63
- // Calculer le coût approximatif (exemple pour gpt-4o-mini: $0.150/1M input, $0.600/1M output)
64
- const inputTokens = completion.usage?.prompt_tokens || 0;
65
- const outputTokens = completion.usage?.completion_tokens || 0;
66
- let cost = 0;
67
- if (model.includes("gpt-4o-mini")) {
68
- cost =
69
- (inputTokens / 1_000_000) * 0.15 + (outputTokens / 1_000_000) * 0.6;
70
- }
71
- else if (model.includes("gpt-4o")) {
72
- cost = (inputTokens / 1_000_000) * 2.5 + (outputTokens / 1_000_000) * 10;
73
- }
74
- else if (model.includes("gpt-4")) {
75
- cost = (inputTokens / 1_000_000) * 30 + (outputTokens / 1_000_000) * 60;
76
- }
77
- else {
78
- cost = (tokensUsed / 1_000_000) * 2; // Fallback
79
- }
80
- // Déduire les tokens utilisés
81
- const tokenResult = await deductTokens(user.id, tokensUsed, model, prompt, {
101
+ const generatedText = completion.text || "";
102
+ const inputTokens = completion.usage?.promptTokens || 0;
103
+ const outputTokens = completion.usage?.completionTokens || 0;
104
+ const tokensUsedFromAI = completion.usage?.totalTokens || 0;
105
+ // Prepare usage for actual billing (from API response)
106
+ const actualUsage = {
82
107
  inputTokens,
83
108
  outputTokens,
84
- cost,
85
- generatedText: generatedText.substring(0, 500), // Stocker un extrait
109
+ };
110
+ // Compute actual provider cost from API usage
111
+ const actualProviderCost = computeProviderCostUsd(actualUsage, pricing);
112
+ // Compute and debit using centralized billing logic
113
+ const billingResult = computeAndDebitAIUsage({
114
+ userId: user.id,
115
+ actionType: actionType, // Use the actionType from request (default: "generate-text")
116
+ providerCostUsd: actualProviderCost,
117
+ wallet,
118
+ metadata: {
119
+ model: modelName,
120
+ provider,
121
+ endpoint: "generate-text",
122
+ inputTokens,
123
+ outputTokens,
124
+ prompt: prompt.substring(0, 32),
125
+ generatedText: generatedText.substring(0, 500),
126
+ },
86
127
  });
87
- if (!tokenResult.success) {
128
+ // Check if billing failed (insufficient credits post-check)
129
+ if (!billingResult.success) {
130
+ logger.error(`[generate-text] Billing failed for user ${user.id}: ${billingResult.error}`, {
131
+ providerCost: actualProviderCost,
132
+ walletSellValue: wallet.walletSellValueUsd,
133
+ walletProviderBudget: wallet.walletProviderBudgetUsd,
134
+ });
88
135
  return NextResponse.json({
89
- error: tokenResult.error || "Erreur lors de la déduction des tokens",
90
- }, { status: 500 });
136
+ error: billingResult.error || "Crédits insuffisants pour cette opération",
137
+ }, { status: 402 } // Payment Required
138
+ );
139
+ }
140
+ // Record consumption in database (ledger)
141
+ const supabase = await getSupabaseServerClient();
142
+ const { error: ledgerError } = await supabase.rpc("record_token_consumption", {
143
+ p_user_id: user.id,
144
+ p_debit_tokens: 0, // Calculated by wallet system
145
+ p_provider_cost_usd: billingResult.providerCostUsd || 0,
146
+ p_sell_usd: billingResult.sellCostUsd || 0,
147
+ p_margin_usd: billingResult.marginUsd || 0,
148
+ p_meta: {
149
+ model: modelName,
150
+ provider,
151
+ endpoint: "generate-text",
152
+ inputTokens,
153
+ outputTokens,
154
+ prompt: prompt.substring(0, 32),
155
+ generatedText: generatedText.substring(0, 500),
156
+ },
157
+ });
158
+ if (ledgerError) {
159
+ logger.error("[generate-text] Failed to record in ledger:", ledgerError);
160
+ // Continue anyway - billing logic already validated
91
161
  }
162
+ logger.info(`[generate-text] Text generation completed: cost=$${billingResult.providerCostUsd?.toFixed(6)}, sell=$${billingResult.sellCostUsd?.toFixed(6)}, margin=${billingResult.marginPercent?.toFixed(1)}%`);
92
163
  return NextResponse.json({
93
164
  text: generatedText,
94
- tokensUsed,
95
- tokensRemaining: tokenResult.balance,
96
- model,
165
+ model: modelName,
166
+ provider,
167
+ inputTokens,
168
+ outputTokens,
97
169
  });
98
170
  }
99
171
  catch (error) {
100
- console.error("Erreur de génération:", error);
172
+ logger.error("Erreur de génération:", error);
101
173
  if (error.code === "insufficient_quota") {
102
- return NextResponse.json({ error: "Quota OpenAI dépassé. Contactez l'administrateur." }, { status: 503 });
174
+ return NextResponse.json({ error: "Quota IA dépassé. Contactez l'administrateur." }, { status: 503 });
103
175
  }
104
176
  return NextResponse.json({ error: error.message || "Erreur lors de la génération" }, { status: 500 });
105
177
  }
@@ -0,0 +1,9 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ /**
3
+ * POST /api/ai/process-ocr
4
+ * Process OCR using OpenAI Vision with proper token debit
5
+ */
6
+ export declare function POST(request: NextRequest): Promise<NextResponse<{
7
+ error: string | undefined;
8
+ }> | NextResponse<import("../../server").ProcessOCRResponse>>;
9
+ //# sourceMappingURL=process-ocr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"process-ocr.d.ts","sourceRoot":"","sources":["../../../src/api/auth/process-ocr.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAgBxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;8DAqD9C"}
@@ -0,0 +1,43 @@
1
+ import { NextResponse } from "next/server";
2
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
3
+ import { processOCRWithTokens } from "../../server/ocr";
4
+ /**
5
+ * POST /api/ai/process-ocr
6
+ * Process OCR using OpenAI Vision with proper token debit
7
+ */
8
+ export async function POST(request) {
9
+ try {
10
+ const supabase = await getSupabaseServerClient();
11
+ // Verify authentication
12
+ const { data: { user }, } = await supabase.auth.getUser();
13
+ if (!user) {
14
+ return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
15
+ }
16
+ const body = await request.json();
17
+ const { files, mode, prompt, extractionSchema } = body;
18
+ if (!files || files.length === 0) {
19
+ return NextResponse.json({ error: "Aucun fichier à traiter" }, { status: 400 });
20
+ }
21
+ if (!prompt) {
22
+ return NextResponse.json({ error: "Le prompt est requis" }, { status: 400 });
23
+ }
24
+ // Process OCR with token debit
25
+ const result = await processOCRWithTokens({
26
+ userId: user.id,
27
+ files,
28
+ mode,
29
+ prompt,
30
+ extractionSchema,
31
+ allowOverdraft: false,
32
+ });
33
+ if (!result.success) {
34
+ const status = result.error?.includes("insuffisant") ? 402 : 500;
35
+ return NextResponse.json({ error: result.error }, { status });
36
+ }
37
+ return NextResponse.json(result);
38
+ }
39
+ catch (error) {
40
+ const err = error;
41
+ return NextResponse.json({ error: err.message || "Erreur lors du traitement OCR" }, { status: 500 });
42
+ }
43
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Increment prompt stats
3
+ * POST /api/ai/auth/prompts/stats
4
+ */
5
+ import type { NextRequest } from "next/server";
6
+ import { NextResponse } from "next/server";
7
+ export declare function POST(req: NextRequest): Promise<NextResponse<{
8
+ success: boolean;
9
+ error: string;
10
+ }> | NextResponse<{
11
+ success: boolean;
12
+ message: string;
13
+ }>>;
14
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../../../src/api/auth/prompts/stats.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,wBAAsB,IAAI,CAAC,GAAG,EAAE,WAAW;;;;;;IA+D1C"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Increment prompt stats
3
+ * POST /api/ai/auth/prompts/stats
4
+ */
5
+ import { NextResponse } from "next/server";
6
+ import { getSupabaseServiceClient } from "@lastbrain/core/server";
7
+ import { logger } from "@lastbrain/core";
8
+ export async function POST(req) {
9
+ try {
10
+ const supabase = getSupabaseServiceClient();
11
+ // Get authenticated user
12
+ const { data: { user }, error: authError, } = await supabase.auth.getUser();
13
+ if (authError || !user) {
14
+ return NextResponse.json({ success: false, error: "Unauthorized" }, { status: 401 });
15
+ }
16
+ const body = await req.json();
17
+ const { prompt_id, stat_type } = body;
18
+ if (!prompt_id || !stat_type) {
19
+ return NextResponse.json({ success: false, error: "Missing prompt_id or stat_type" }, { status: 400 });
20
+ }
21
+ // Validate stat_type
22
+ if (!["views", "used", "picked"].includes(stat_type)) {
23
+ return NextResponse.json({
24
+ success: false,
25
+ error: "Invalid stat_type. Must be views, used, or picked",
26
+ }, { status: 400 });
27
+ }
28
+ // Call function to increment stat
29
+ const { error } = await supabase.rpc("increment_prompt_stat", {
30
+ p_prompt_id: prompt_id,
31
+ p_stat_type: stat_type,
32
+ });
33
+ if (error) {
34
+ logger.error("Failed to increment prompt stat:", error);
35
+ return NextResponse.json({ success: false, error: "Failed to increment stat" }, { status: 500 });
36
+ }
37
+ return NextResponse.json({
38
+ success: true,
39
+ message: `${stat_type} incremented`,
40
+ });
41
+ }
42
+ catch (error) {
43
+ logger.error("Prompt stat increment error:", error);
44
+ return NextResponse.json({ success: false, error: "Internal server error" }, { status: 500 });
45
+ }
46
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * GET/POST/PUT/DELETE /api/ai/auth/prompts
3
+ * CRUD for user's AI prompts
4
+ */
5
+ import { NextRequest, NextResponse } from "next/server";
6
+ export declare function GET(request: NextRequest): Promise<NextResponse<{
7
+ prompts: any[];
8
+ }> | NextResponse<{
9
+ error: any;
10
+ }>>;
11
+ export declare function POST(request: NextRequest): Promise<NextResponse<{
12
+ prompt: any;
13
+ }> | NextResponse<{
14
+ error: any;
15
+ }>>;
16
+ export declare function PUT(request: NextRequest): Promise<NextResponse<{
17
+ prompt: any;
18
+ }> | NextResponse<{
19
+ error: any;
20
+ }>>;
21
+ export declare function DELETE(request: NextRequest): Promise<NextResponse<{
22
+ success: boolean;
23
+ }> | NextResponse<{
24
+ error: any;
25
+ }>>;
26
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/api/auth/prompts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKxD,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;IA8D7C;AAGD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IA6D9C;AAGD,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;IAsD7C;AAGD,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW;;;;IAuChD"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * GET/POST/PUT/DELETE /api/ai/auth/prompts
3
+ * CRUD for user's AI prompts
4
+ */
5
+ import { NextResponse } from "next/server";
6
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
7
+ import { logger } from "@lastbrain/core";
8
+ // GET - List user's prompts
9
+ export async function GET(request) {
10
+ try {
11
+ const supabase = await getSupabaseServerClient();
12
+ const { data: { user }, error: authError, } = await supabase.auth.getUser();
13
+ if (authError || !user) {
14
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
15
+ }
16
+ const { searchParams } = new URL(request.url);
17
+ const type = searchParams.get("type"); // 'text' or 'image'
18
+ const favorite = searchParams.get("favorite") === "true";
19
+ let query = supabase
20
+ .from("user_prompt")
21
+ .select(`
22
+ *,
23
+ prompt_stats (
24
+ views,
25
+ used_count,
26
+ picked_count
27
+ )
28
+ `)
29
+ .eq("owner_id", user.id)
30
+ .order("favorite", { ascending: false })
31
+ .order("created_at", { ascending: false });
32
+ if (type) {
33
+ query = query.eq("type", type);
34
+ }
35
+ if (favorite) {
36
+ query = query.eq("favorite", true);
37
+ }
38
+ const { data: prompts, error } = await query;
39
+ if (error) {
40
+ logger.error("[prompts] GET error:", error);
41
+ return NextResponse.json({ error: error.message }, { status: 500 });
42
+ }
43
+ // Flatten stats into prompt object
44
+ const promptsWithStats = prompts?.map((p) => ({
45
+ ...p,
46
+ views: p.prompt_stats?.[0]?.views || 0,
47
+ used_count: p.prompt_stats?.[0]?.used_count || 0,
48
+ picked_count: p.prompt_stats?.[0]?.picked_count || 0,
49
+ prompt_stats: undefined, // Remove nested object
50
+ }));
51
+ return NextResponse.json({ prompts: promptsWithStats });
52
+ }
53
+ catch (error) {
54
+ logger.error("[prompts] GET unexpected error:", error);
55
+ return NextResponse.json({ error: error.message }, { status: 500 });
56
+ }
57
+ }
58
+ // POST - Create new prompt
59
+ export async function POST(request) {
60
+ try {
61
+ const supabase = await getSupabaseServerClient();
62
+ const { data: { user }, error: authError, } = await supabase.auth.getUser();
63
+ if (authError || !user) {
64
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
65
+ }
66
+ const body = await request.json();
67
+ const { title, content, type, is_public = false, favorite = false, tags = [], } = body;
68
+ if (!title || !content || !type) {
69
+ return NextResponse.json({ error: "Missing required fields: title, content, type" }, { status: 400 });
70
+ }
71
+ if (!["text", "image"].includes(type)) {
72
+ return NextResponse.json({ error: "Invalid type. Must be 'text' or 'image'" }, { status: 400 });
73
+ }
74
+ const { data: prompt, error } = await supabase
75
+ .from("user_prompt")
76
+ .insert({
77
+ owner_id: user.id,
78
+ title,
79
+ content,
80
+ type,
81
+ is_public,
82
+ favorite,
83
+ tags,
84
+ })
85
+ .select()
86
+ .single();
87
+ if (error) {
88
+ logger.error("[prompts] POST error:", error);
89
+ return NextResponse.json({ error: error.message }, { status: 500 });
90
+ }
91
+ return NextResponse.json({ prompt }, { status: 201 });
92
+ }
93
+ catch (error) {
94
+ logger.error("[prompts] POST unexpected error:", error);
95
+ return NextResponse.json({ error: error.message }, { status: 500 });
96
+ }
97
+ }
98
+ // PUT - Update prompt
99
+ export async function PUT(request) {
100
+ try {
101
+ const supabase = await getSupabaseServerClient();
102
+ const { data: { user }, error: authError, } = await supabase.auth.getUser();
103
+ if (authError || !user) {
104
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
105
+ }
106
+ const body = await request.json();
107
+ const { id, title, content, type, is_public, favorite, tags, lang } = body;
108
+ if (!id) {
109
+ return NextResponse.json({ error: "Missing required field: id" }, { status: 400 });
110
+ }
111
+ const updates = {};
112
+ if (title !== undefined)
113
+ updates.title = title;
114
+ if (content !== undefined)
115
+ updates.content = content;
116
+ if (type !== undefined)
117
+ updates.type = type;
118
+ if (is_public !== undefined)
119
+ updates.is_public = is_public;
120
+ if (favorite !== undefined)
121
+ updates.favorite = favorite;
122
+ if (tags !== undefined)
123
+ updates.tags = tags;
124
+ if (lang)
125
+ updates.lang = lang;
126
+ const { data: prompt, error } = await supabase
127
+ .from("user_prompt")
128
+ .update(updates)
129
+ .eq("id", id)
130
+ .eq("owner_id", user.id)
131
+ .select()
132
+ .single();
133
+ if (error) {
134
+ logger.error("[prompts] PUT error:", error);
135
+ return NextResponse.json({ error: error.message }, { status: 500 });
136
+ }
137
+ if (!prompt) {
138
+ return NextResponse.json({ error: "Prompt not found" }, { status: 404 });
139
+ }
140
+ return NextResponse.json({ prompt });
141
+ }
142
+ catch (error) {
143
+ logger.error("[prompts] PUT unexpected error:", error);
144
+ return NextResponse.json({ error: error.message }, { status: 500 });
145
+ }
146
+ }
147
+ // DELETE - Delete prompt
148
+ export async function DELETE(request) {
149
+ try {
150
+ const supabase = await getSupabaseServerClient();
151
+ const { data: { user }, error: authError, } = await supabase.auth.getUser();
152
+ if (authError || !user) {
153
+ return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
154
+ }
155
+ const { searchParams } = new URL(request.url);
156
+ const id = searchParams.get("id");
157
+ if (!id) {
158
+ return NextResponse.json({ error: "Missing required parameter: id" }, { status: 400 });
159
+ }
160
+ const { error } = await supabase
161
+ .from("user_prompt")
162
+ .delete()
163
+ .eq("id", id)
164
+ .eq("owner_id", user.id);
165
+ if (error) {
166
+ logger.error("[prompts] DELETE error:", error);
167
+ return NextResponse.json({ error: error.message }, { status: 500 });
168
+ }
169
+ return NextResponse.json({ success: true });
170
+ }
171
+ catch (error) {
172
+ logger.error("[prompts] DELETE unexpected error:", error);
173
+ return NextResponse.json({ error: error.message }, { status: 500 });
174
+ }
175
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * GET /api/ai/auth/token-balance
3
+ * Returns combined token balance: quota + purchased tokens
4
+ */
5
+ import { NextRequest, NextResponse } from "next/server";
6
+ export declare function GET(request: NextRequest): Promise<NextResponse<{
7
+ quota: {
8
+ hasQuota: boolean;
9
+ plan: import("../..").PlanType;
10
+ effectiveQuota: number;
11
+ usedQuota: number;
12
+ remainingQuota: number;
13
+ periodStart: string | null;
14
+ periodEnd: string | null;
15
+ isActive: boolean;
16
+ };
17
+ purchased: {
18
+ balance: number;
19
+ totalAdded: number;
20
+ totalUsed: number;
21
+ };
22
+ balance: number;
23
+ }> | NextResponse<{
24
+ error: any;
25
+ }>>;
26
+ //# sourceMappingURL=token-balance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-balance.d.ts","sourceRoot":"","sources":["../../../src/api/auth/token-balance.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMxD,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;;;;;;;;;;IA+C7C"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * GET /api/ai/auth/token-balance
3
+ * Returns combined token balance: quota + purchased tokens
4
+ */
5
+ import { NextResponse } from "next/server";
6
+ import { getSupabaseServerClient } from "@lastbrain/core/server";
7
+ import { getUserQuotaStatus } from "../../server/quota";
8
+ import { getTokenBalance, getTokenStats } from "../../server";
9
+ import { logger } from "@lastbrain/core";
10
+ export async function GET(request) {
11
+ try {
12
+ const supabase = await getSupabaseServerClient();
13
+ // Auth check
14
+ const { data: { user }, error: authError, } = await supabase.auth.getUser();
15
+ if (authError || !user) {
16
+ return NextResponse.json({ error: "Non authentifié" }, { status: 401 });
17
+ }
18
+ // Get quota status
19
+ const quotaStatus = await getUserQuotaStatus(user.id);
20
+ // Get purchased tokens balance
21
+ const purchasedBalance = await getTokenBalance(user.id);
22
+ const purchasedStats = await getTokenStats(user.id);
23
+ return NextResponse.json({
24
+ quota: {
25
+ hasQuota: quotaStatus.hasQuota,
26
+ plan: quotaStatus.plan,
27
+ effectiveQuota: quotaStatus.effectiveQuota,
28
+ usedQuota: quotaStatus.usedQuota,
29
+ remainingQuota: quotaStatus.remainingQuota,
30
+ periodStart: quotaStatus.periodStart,
31
+ periodEnd: quotaStatus.periodEnd,
32
+ isActive: quotaStatus.isActive,
33
+ },
34
+ purchased: {
35
+ balance: purchasedBalance,
36
+ totalAdded: purchasedStats.totalPurchased + purchasedStats.totalGifted,
37
+ totalUsed: purchasedStats.totalUsed,
38
+ },
39
+ // For backward compatibility
40
+ balance: purchasedBalance,
41
+ });
42
+ }
43
+ catch (error) {
44
+ logger.error("[GET /api/ai/auth/token-balance] Error:", error);
45
+ return NextResponse.json({ error: error.message || "Erreur serveur" }, { status: 500 });
46
+ }
47
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"token-checkout.d.ts","sourceRoot":"","sources":["../../../src/api/auth/token-checkout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;IAiE9C"}
1
+ {"version":3,"file":"token-checkout.d.ts","sourceRoot":"","sources":["../../../src/api/auth/token-checkout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKxD;;;GAGG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;IAuF9C"}