@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
@@ -0,0 +1,279 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useState, useEffect } from "react";
4
+ import { Card, CardBody, CardHeader, Button, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Spinner, addToast, Chip, Select, SelectItem, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, FileManager, Textarea, CopyButton, Image, } from "@lastbrain/ui";
5
+ import { History, Trash2, Eye, Download, FolderOpen, Ban } from "lucide-react";
6
+ import { useAuth, useModuleTranslation } from "@lastbrain/core";
7
+ import { logger } from "@lastbrain/core";
8
+ export function HistoryPage() {
9
+ const t = useModuleTranslation("ai");
10
+ const { user } = useAuth();
11
+ const [artifacts, setArtifacts] = useState([]);
12
+ const [loading, setLoading] = useState(true);
13
+ const [kindFilter, setKindFilter] = useState("all");
14
+ const [selectedArtifact, setSelectedArtifact] = useState(null);
15
+ const [isModalOpen, setIsModalOpen] = useState(false);
16
+ const [loadingDetail, setLoadingDetail] = useState(false);
17
+ const [hasMore, setHasMore] = useState(false);
18
+ const [cursor, setCursor] = useState();
19
+ const [isFileManagerOpen, setIsFileManagerOpen] = useState(false);
20
+ const [filePath, setFilePath] = useState("");
21
+ const [imageUrls, setImageUrls] = useState(new Map());
22
+ useEffect(() => {
23
+ if (user?.id) {
24
+ fetchArtifacts();
25
+ }
26
+ else {
27
+ setLoading(false);
28
+ }
29
+ // eslint-disable-next-line react-hooks/exhaustive-deps
30
+ }, [kindFilter, user?.id]);
31
+ const fetchArtifacts = async (nextCursor) => {
32
+ if (!user) {
33
+ setLoading(false);
34
+ return;
35
+ }
36
+ try {
37
+ setLoading(true);
38
+ // Get API key for auth
39
+ const apiKeysResponse = await fetch("/api/ai/auth/api-keys");
40
+ if (!apiKeysResponse.ok) {
41
+ throw new Error("Failed to get API keys");
42
+ }
43
+ const keysData = await apiKeysResponse.json();
44
+ const apiKeys = keysData.data || [];
45
+ if (apiKeys.length === 0) {
46
+ addToast({
47
+ color: "warning",
48
+ title: t("history.toast_no_api_key"),
49
+ });
50
+ setLoading(false);
51
+ return;
52
+ }
53
+ const apiKey = apiKeys[0]; // Use first available key
54
+ // Fetch artifacts
55
+ const params = new URLSearchParams({
56
+ kind: kindFilter,
57
+ limit: "20",
58
+ });
59
+ if (nextCursor) {
60
+ params.append("cursor", nextCursor);
61
+ }
62
+ const response = await fetch(`/api/public/v1/history?${params.toString()}`, {
63
+ headers: {
64
+ Authorization: `Bearer ${apiKey.key || apiKey.prefix}...`,
65
+ },
66
+ });
67
+ if (!response.ok) {
68
+ throw new Error("Failed to fetch history");
69
+ }
70
+ const data = await response.json();
71
+ if (nextCursor) {
72
+ setArtifacts((prev) => [...prev, ...data.items]);
73
+ }
74
+ else {
75
+ setArtifacts(data.items);
76
+ }
77
+ setHasMore(data.pagination.has_more);
78
+ setCursor(data.pagination.next_cursor);
79
+ // Load signed URLs for images
80
+ const imageArtifacts = data.items.filter((item) => item.kind === "image" && item.has_storage);
81
+ for (const artifact of imageArtifacts) {
82
+ loadImageUrl(artifact.id);
83
+ }
84
+ }
85
+ catch (error) {
86
+ logger.error("Failed to fetch artifacts", error);
87
+ addToast({
88
+ color: "danger",
89
+ title: t("history.toast_load_failed"),
90
+ });
91
+ }
92
+ finally {
93
+ setLoading(false);
94
+ }
95
+ };
96
+ const loadImageUrl = async (artifactId) => {
97
+ try {
98
+ const apiKeysResponse = await fetch("/api/ai/auth/api-keys");
99
+ const keysData = await apiKeysResponse.json();
100
+ const apiKeys = keysData.data || [];
101
+ const apiKey = apiKeys[0];
102
+ const response = await fetch(`/api/public/v1/history/${artifactId}`, {
103
+ headers: {
104
+ Authorization: `Bearer ${apiKey.key || apiKey.prefix}...`,
105
+ },
106
+ });
107
+ if (response.ok) {
108
+ const data = await response.json();
109
+ if (data.artifact.download_url) {
110
+ setImageUrls((prev) => new Map(prev).set(artifactId, data.artifact.download_url));
111
+ }
112
+ }
113
+ }
114
+ catch (error) {
115
+ logger.debug("Failed to load image URL", error);
116
+ }
117
+ };
118
+ const viewArtifact = async (id) => {
119
+ try {
120
+ setLoadingDetail(true);
121
+ setIsModalOpen(true);
122
+ // Get API key
123
+ const apiKeysResponse = await fetch("/api/ai/auth/api-keys");
124
+ const keysData = await apiKeysResponse.json();
125
+ const apiKeys = keysData.data || [];
126
+ const apiKey = apiKeys[0];
127
+ const response = await fetch(`/api/public/v1/history/${id}`, {
128
+ headers: {
129
+ Authorization: `Bearer ${apiKey.key || apiKey.prefix}...`,
130
+ },
131
+ });
132
+ if (!response.ok) {
133
+ throw new Error("Failed to fetch artifact detail");
134
+ }
135
+ const data = await response.json();
136
+ setSelectedArtifact(data.artifact);
137
+ }
138
+ catch (error) {
139
+ logger.error("Failed to fetch artifact detail", error);
140
+ addToast({
141
+ color: "danger",
142
+ title: t("history.toast_artifact_failed"),
143
+ });
144
+ setIsModalOpen(false);
145
+ }
146
+ finally {
147
+ setLoadingDetail(false);
148
+ }
149
+ };
150
+ const deleteArtifact = async (id) => {
151
+ if (!confirm(t("history.confirm_delete")))
152
+ return;
153
+ try {
154
+ // Get API key
155
+ const apiKeysResponse = await fetch("/api/ai/auth/api-keys");
156
+ const keysData = await apiKeysResponse.json();
157
+ const apiKeys = keysData.data || [];
158
+ const apiKey = apiKeys[0];
159
+ const response = await fetch(`/api/public/v1/history/${id}`, {
160
+ method: "DELETE",
161
+ headers: {
162
+ Authorization: `Bearer ${apiKey.key || apiKey.prefix}...`,
163
+ },
164
+ });
165
+ if (!response.ok) {
166
+ throw new Error("Failed to delete artifact");
167
+ }
168
+ addToast({
169
+ color: "success",
170
+ title: t("history.toast_delete_success"),
171
+ });
172
+ // Refresh list
173
+ fetchArtifacts();
174
+ }
175
+ catch (error) {
176
+ logger.error("Failed to delete artifact", error);
177
+ addToast({
178
+ color: "danger",
179
+ title: t("history.toast_delete_failed"),
180
+ });
181
+ }
182
+ };
183
+ const downloadArtifact = async (id) => {
184
+ try {
185
+ // Get API key
186
+ const apiKeysResponse = await fetch("/api/ai/auth/api-keys");
187
+ const keysData = await apiKeysResponse.json();
188
+ const apiKeys = keysData.data || [];
189
+ const apiKey = apiKeys[0];
190
+ const response = await fetch(`/api/public/v1/history/${id}`, {
191
+ headers: {
192
+ Authorization: `Bearer ${apiKey.key || apiKey.prefix}...`,
193
+ },
194
+ });
195
+ if (!response.ok) {
196
+ throw new Error("Failed to get download URL");
197
+ }
198
+ const data = await response.json();
199
+ if (data.artifact.download_url) {
200
+ window.open(data.artifact.download_url, "_blank");
201
+ }
202
+ else {
203
+ addToast({
204
+ color: "warning",
205
+ title: t("history.toast_no_download_url"),
206
+ });
207
+ }
208
+ }
209
+ catch (error) {
210
+ logger.error("Failed to download artifact", error);
211
+ addToast({
212
+ color: "danger",
213
+ title: t("history.toast_download_failed"),
214
+ });
215
+ }
216
+ };
217
+ const openInFileManager = (artifact) => {
218
+ // Extract path from artifact
219
+ const date = new Date(artifact.created_at);
220
+ setFilePath(artifact.storage_path.split("/").slice(0, -1).join("/"));
221
+ setIsFileManagerOpen(true);
222
+ };
223
+ const formatDate = (dateString) => {
224
+ return new Date(dateString).toLocaleString();
225
+ };
226
+ const formatSize = (bytes) => {
227
+ if (!bytes)
228
+ return "N/A";
229
+ const kb = bytes / 1024;
230
+ if (kb < 1024)
231
+ return `${kb.toFixed(1)} KB`;
232
+ return `${(kb / 1024).toFixed(1)} MB`;
233
+ };
234
+ const getKindColor = (kind) => {
235
+ switch (kind) {
236
+ case "text":
237
+ return "primary";
238
+ case "image":
239
+ return "secondary";
240
+ case "pdf":
241
+ return "warning";
242
+ case "file":
243
+ return "default";
244
+ default:
245
+ return "default";
246
+ }
247
+ };
248
+ return (_jsxs("div", { className: "container mx-auto py-8 space-y-6", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { className: "flex flex-row items-center justify-between", children: [_jsxs("div", { children: [_jsxs("h1", { className: "text-2xl font-bold flex items-center gap-2", children: [_jsx(History, { size: 24 }), t("history.page_title")] }), _jsx("p", { className: "text-sm text-gray-600", children: t("history.page_subtitle") })] }), _jsxs(Select, { label: t("history.filter_label"), size: "sm", selectedKeys: [kindFilter], onSelectionChange: (keys) => {
249
+ const selected = Array.from(keys)[0];
250
+ setKindFilter(selected ? String(selected) : "all");
251
+ }, className: "max-w-xs", children: [_jsx(SelectItem, { children: t("history.filter_all") }, "all"), _jsx(SelectItem, { children: t("history.filter_text") }, "text"), _jsx(SelectItem, { children: t("history.filter_image") }, "image"), _jsx(SelectItem, { children: t("history.filter_pdf") }, "pdf"), _jsx(SelectItem, { children: t("history.filter_file") }, "file")] })] }), _jsx(CardBody, { children: artifacts.length === 0 && !loading ? (_jsxs("div", { className: "text-center py-8", children: [_jsx(History, { size: 48, className: "mx-auto text-gray-400 mb-4" }), _jsx("p", { className: "text-gray-600 mb-4", children: t("history.no_artifacts") }), _jsx("p", { className: "text-sm text-gray-500", dangerouslySetInnerHTML: {
252
+ __html: t("history.no_artifacts_desc"),
253
+ } })] })) : artifacts.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs(Table, { "aria-label": "Artifacts history", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: " " }), _jsx(TableColumn, { children: t("history.table_type") }), _jsx(TableColumn, { children: t("history.table_model") }), _jsx(TableColumn, { children: t("history.table_tokens") }), _jsx(TableColumn, { children: t("history.table_size") }), _jsx(TableColumn, { children: t("history.table_date") }), _jsx(TableColumn, { align: "end", children: t("history.table_actions") })] }), _jsx(TableBody, { children: artifacts.map((artifact) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: artifact.kind === "image" &&
254
+ imageUrls.has(artifact.id) ? (_jsx(Image, { src: imageUrls.get(artifact.id), alt: "Thumbnail", className: "w-12 h-12 object-cover rounded" })) : (_jsx("div", { className: "w-12 h-12 bg-background rounded flex items-center justify-center", children: _jsx(Ban, { size: 16, className: "text-gray-400" }) })) }), _jsx(TableCell, { children: _jsx(Chip, { color: getKindColor(artifact.kind), variant: "flat", size: "sm", children: artifact.kind }) }), _jsx(TableCell, { children: _jsxs("div", { className: "flex flex-col", children: [_jsx("span", { className: "text-sm font-medium", children: artifact.model || "N/A" }), _jsx("span", { className: "text-xs text-gray-500", children: artifact.provider || "" })] }) }), _jsx(TableCell, { children: artifact.tokens_total?.toLocaleString() || "N/A" }), _jsx(TableCell, { children: artifact.has_storage
255
+ ? formatSize(artifact.size_bytes)
256
+ : "—" }), _jsx(TableCell, { children: _jsx("span", { className: "text-xs", children: formatDate(artifact.created_at) }) }), _jsx(TableCell, { children: _jsxs("div", { className: "flex justify-end gap-2", children: [_jsx(Button, { size: "sm", variant: "light", isIconOnly: true, onPress: () => viewArtifact(artifact.id), children: _jsx(Eye, { size: 16 }) }), artifact.has_storage && (_jsxs(_Fragment, { children: [_jsx(Button, { size: "sm", variant: "light", isIconOnly: true, onPress: () => downloadArtifact(artifact.id), children: _jsx(Download, { size: 16 }) }), _jsx(Button, { size: "sm", variant: "light", isIconOnly: true, onPress: () => openInFileManager(artifact), children: _jsx(FolderOpen, { size: 16 }) })] })), _jsx(Button, { size: "sm", variant: "light", color: "danger", isIconOnly: true, onPress: () => deleteArtifact(artifact.id), children: _jsx(Trash2, { size: 16 }) })] }) })] }, artifact.id))) })] }), hasMore && (_jsx("div", { className: "flex justify-center mt-4", children: _jsx(Button, { onPress: () => fetchArtifacts(cursor), disabled: loading, children: loading ? t("history.loading") : t("history.load_more") }) }))] })) : loading ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Spinner, {}) })) : null })] }), _jsx(Modal, { isOpen: isModalOpen, onClose: () => {
257
+ setIsModalOpen(false);
258
+ setSelectedArtifact(null);
259
+ }, size: "3xl", backdrop: "blur", scrollBehavior: "inside", children: _jsxs(ModalContent, { children: [_jsx(ModalHeader, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Chip, { color: selectedArtifact
260
+ ? getKindColor(selectedArtifact.kind)
261
+ : "default", variant: "flat", children: selectedArtifact?.kind }), _jsx("span", { children: t("history.modal_title") })] }) }), _jsx(ModalBody, { children: loadingDetail ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Spinner, {}) })) : selectedArtifact ? (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "grid grid-cols-2 gap-4 text-sm", children: [_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: t("history.modal_model") }), " ", selectedArtifact.model || "N/A"] }), _jsxs("div", { children: [_jsx("span", { className: "font-medium", children: t("history.modal_provider") }), " ", selectedArtifact.provider || "N/A"] }), _jsxs("div", { children: [_jsx("span", { className: "font-medium", children: t("history.modal_tokens") }), " ", selectedArtifact.tokens_total?.toLocaleString() || "N/A"] }), _jsxs("div", { children: [_jsx("span", { className: "font-medium", children: t("history.modal_date") }), " ", formatDate(selectedArtifact.created_at)] })] }), selectedArtifact.meta?.title && (_jsxs("div", { children: [_jsx("span", { className: "font-medium", children: t("history.modal_title_field") }), " ", selectedArtifact.meta.title] })), selectedArtifact.kind === "text" &&
262
+ selectedArtifact.text_content && (_jsxs("div", { children: [_jsx("h3", { className: "font-medium mb-2", children: t("history.modal_content") }), _jsx(Textarea, { className: "w-full p-4 text-sm", maxRows: 1000, defaultValue: selectedArtifact.text_content, endContent: _jsx(CopyButton, { content: selectedArtifact.text_content }) })] })), selectedArtifact.kind !== "text" &&
263
+ selectedArtifact.download_url && (_jsxs("div", { children: [_jsx(Image, { src: selectedArtifact.download_url, alt: "Artifact" }), _jsxs("div", { className: "mt-6 flex flex-col justify-end items-center", children: [_jsxs(Button, { color: "primary", startContent: _jsx(Download, { size: 20 }), onPress: () => window.open(selectedArtifact.download_url, "_blank"), children: [t("history.modal_download_button"), " ", selectedArtifact.kind] }), _jsx("p", { className: "text-xs text-gray-500 mt-2", children: t("history.modal_expires").replace("{seconds}", String(selectedArtifact.expires_in)) })] })] }))] })) : null }), _jsx(ModalFooter, { children: _jsx(Button, { variant: "light", onPress: () => {
264
+ setIsModalOpen(false);
265
+ setSelectedArtifact(null);
266
+ }, children: t("history.modal_close") }) })] }) }), _jsx(Modal, { isOpen: isFileManagerOpen, onClose: () => {
267
+ setIsFileManagerOpen(false);
268
+ setFilePath("");
269
+ }, size: "5xl", backdrop: "blur", children: _jsxs(ModalContent, { children: [_jsx(ModalHeader, { children: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(FolderOpen, { size: 20 }), _jsx("span", { children: t("history.file_manager_title") })] }) }), _jsx(ModalBody, { children: _jsx(FileManager, { bucket: "app", basePath: filePath, allowUpload: false, allowCreateFolder: false, initialView: "list" }) }), _jsxs(ModalFooter, { children: [_jsx(Button, { variant: "light", onPress: () => {
270
+ setIsFileManagerOpen(false);
271
+ setFilePath("");
272
+ }, children: t("history.modal_close") }), _jsx(Button, { color: "primary", onPress: () => {
273
+ navigator.clipboard.writeText(filePath);
274
+ addToast({
275
+ color: "success",
276
+ title: t("history.toast_path_copied"),
277
+ });
278
+ }, children: t("history.copy_path") })] })] }) })] }));
279
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * PromptsPage - Manage user's AI prompts
3
+ */
4
+ export declare function PromptsPage(): import("react/jsx-runtime").JSX.Element;
5
+ //# sourceMappingURL=PromptsPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PromptsPage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/PromptsPage.tsx"],"names":[],"mappings":"AAAA;;GAEG;AA+CH,wBAAgB,WAAW,4CA4V1B"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * PromptsPage - Manage user's AI prompts
3
+ */
4
+ "use client";
5
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
6
+ import { useState, useEffect } from "react";
7
+ import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, useDisclosure, Spinner, Card, CardHeader, CardBody, Button, Input, Textarea, Switch, Chip, } from "@lastbrain/ui";
8
+ import { Sparkles, Plus, Edit, Trash2, Star, Image as ImageIcon, MessageSquare, Eye, } from "lucide-react";
9
+ import { useLanguage } from "@lastbrain/core";
10
+ export function PromptsPage() {
11
+ const [prompts, setPrompts] = useState([]);
12
+ const [loading, setLoading] = useState(true);
13
+ const [filter, setFilter] = useState("all");
14
+ const [editingPrompt, setEditingPrompt] = useState(null);
15
+ const { isOpen, onOpen, onClose } = useDisclosure();
16
+ const { lang } = useLanguage();
17
+ const [formData, setFormData] = useState({
18
+ title: "",
19
+ content: "",
20
+ type: "text",
21
+ is_public: false,
22
+ favorite: false,
23
+ tags: [],
24
+ });
25
+ useEffect(() => {
26
+ fetchPrompts();
27
+ }, [filter]);
28
+ const fetchPrompts = async () => {
29
+ try {
30
+ setLoading(true);
31
+ const params = new URLSearchParams();
32
+ if (filter !== "all") {
33
+ params.append("type", filter);
34
+ }
35
+ const response = await fetch(`/api/ai/auth/prompts?${params}`);
36
+ const data = await response.json();
37
+ if (response.ok) {
38
+ setPrompts(data.prompts || []);
39
+ }
40
+ }
41
+ catch (error) {
42
+ console.error("Failed to fetch prompts:", error);
43
+ }
44
+ finally {
45
+ setLoading(false);
46
+ }
47
+ };
48
+ const openCreateModal = () => {
49
+ setEditingPrompt(null);
50
+ setFormData({
51
+ title: "",
52
+ content: "",
53
+ type: "text",
54
+ is_public: false,
55
+ favorite: false,
56
+ tags: [],
57
+ });
58
+ onOpen();
59
+ };
60
+ const openEditModal = (prompt) => {
61
+ setEditingPrompt(prompt);
62
+ setFormData({
63
+ title: prompt.title,
64
+ content: prompt.content,
65
+ type: prompt.type,
66
+ is_public: prompt.is_public,
67
+ favorite: prompt.favorite,
68
+ tags: prompt.tags || [],
69
+ });
70
+ onOpen();
71
+ };
72
+ const handleSave = async () => {
73
+ try {
74
+ if (editingPrompt) {
75
+ // Update
76
+ const response = await fetch("/api/ai/auth/prompts", {
77
+ method: "PUT",
78
+ headers: { "Content-Type": "application/json" },
79
+ body: JSON.stringify({ id: editingPrompt.id, lang, ...formData }),
80
+ });
81
+ if (response.ok) {
82
+ await fetchPrompts();
83
+ onClose();
84
+ }
85
+ }
86
+ else {
87
+ // Create
88
+ const response = await fetch("/api/ai/auth/prompts", {
89
+ method: "POST",
90
+ headers: { "Content-Type": "application/json" },
91
+ body: JSON.stringify(formData),
92
+ });
93
+ if (response.ok) {
94
+ await fetchPrompts();
95
+ onClose();
96
+ }
97
+ }
98
+ }
99
+ catch (error) {
100
+ console.error("Failed to save prompt:", error);
101
+ }
102
+ };
103
+ const handleDelete = async (id) => {
104
+ if (!confirm("Are you sure you want to delete this prompt?"))
105
+ return;
106
+ try {
107
+ const response = await fetch(`/api/ai/auth/prompts?id=${id}`, {
108
+ method: "DELETE",
109
+ });
110
+ if (response.ok) {
111
+ await fetchPrompts();
112
+ }
113
+ }
114
+ catch (error) {
115
+ console.error("Failed to delete prompt:", error);
116
+ }
117
+ };
118
+ const toggleFavorite = async (prompt) => {
119
+ try {
120
+ const response = await fetch("/api/ai/auth/prompts", {
121
+ method: "PUT",
122
+ headers: { "Content-Type": "application/json" },
123
+ body: JSON.stringify({
124
+ id: prompt.id,
125
+ favorite: !prompt.favorite,
126
+ }),
127
+ });
128
+ if (response.ok) {
129
+ await fetchPrompts();
130
+ }
131
+ }
132
+ catch (error) {
133
+ console.error("Failed to toggle favorite:", error);
134
+ }
135
+ };
136
+ return (_jsxs("div", { className: "space-y-6 mt-6", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { children: [_jsxs("h1", { className: "text-3xl font-bold flex items-center gap-2", children: [_jsx(Sparkles, { className: "w-8 h-8" }), "My AI Prompts"] }), _jsx("p", { className: "text-default-500 mt-2", children: "Save and manage your favorite AI prompts" })] }), _jsx(Button, { color: "primary", onPress: openCreateModal, startContent: _jsx(Plus, { className: "w-4 h-4" }), children: "New Prompt" })] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { variant: filter === "all" ? "solid" : "bordered", onPress: () => setFilter("all"), children: "All" }), _jsx(Button, { variant: filter === "text" ? "solid" : "bordered", onPress: () => setFilter("text"), startContent: _jsx(MessageSquare, { className: "w-4 h-4" }), children: "Text" }), _jsx(Button, { variant: filter === "image" ? "solid" : "bordered", onPress: () => setFilter("image"), startContent: _jsx(ImageIcon, { className: "w-4 h-4" }), children: "Image" })] }), loading ? (_jsx("div", { className: "flex justify-center py-12", children: _jsx(Spinner, { size: "lg" }) })) : prompts.length === 0 ? (_jsx(Card, { children: _jsx(CardBody, { className: "text-center py-12", children: _jsx("p", { className: "text-default-500", children: "No prompts yet. Create your first one!" }) }) })) : (_jsx("div", { className: "grid gap-4 md:grid-cols-2 lg:grid-cols-3", children: prompts.map((prompt) => (_jsxs(Card, { className: "hover:shadow-lg transition-shadow", children: [_jsxs(CardHeader, { className: "flex justify-between items-start", children: [_jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-2 mb-1", children: [prompt.type === "text" ? (_jsx(MessageSquare, { className: "w-4 h-4 text-primary" })) : (_jsx(ImageIcon, { className: "w-4 h-4 text-secondary" })), _jsx("h3", { className: "font-semibold text-lg", children: prompt.title })] }), _jsxs("div", { className: "flex gap-2 mt-2", children: [prompt.is_public && (_jsx(Chip, { size: "sm", color: "success", variant: "flat", startContent: _jsx(Eye, { className: "w-3 h-3" }), children: "Public" })), prompt.favorite && (_jsx(Chip, { size: "sm", color: "warning", variant: "flat", startContent: _jsx(Star, { className: "w-3 h-3" }), children: "Favorite" }))] })] }), _jsx(Button, { isIconOnly: true, size: "sm", variant: "light", onPress: () => toggleFavorite(prompt), children: _jsx(Star, { className: `w-4 h-4 ${prompt.favorite ? "fill-warning text-warning" : ""}` }) })] }), _jsxs(CardBody, { children: [_jsx("p", { className: "text-sm text-default-600 line-clamp-3 mb-4", children: prompt.content }), _jsxs("div", { className: "flex gap-2 justify-end", children: [_jsx(Button, { size: "sm", variant: "light", onPress: () => openEditModal(prompt), startContent: _jsx(Edit, { className: "w-3 h-3" }), children: "Edit" }), _jsx(Button, { size: "sm", variant: "light", color: "danger", onPress: () => handleDelete(prompt.id), startContent: _jsx(Trash2, { className: "w-3 h-3" }), children: "Delete" })] })] })] }, prompt.id))) })), _jsx(Modal, { isOpen: isOpen, onClose: onClose, size: "2xl", scrollBehavior: "inside", backdrop: "blur", children: _jsxs(ModalContent, { children: [_jsx(ModalHeader, { children: editingPrompt ? "Edit Prompt" : "Create New Prompt" }), _jsx(ModalBody, { children: _jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: "Title", placeholder: "Enter prompt title", value: formData.title, onValueChange: (value) => setFormData({ ...formData, title: value }) }), _jsx(Textarea, { label: "Content", placeholder: "Enter your prompt here...", value: formData.content, onValueChange: (value) => setFormData({ ...formData, content: value }), minRows: 5 }), _jsxs("div", { className: "flex gap-4", children: [_jsx(Button, { variant: formData.type === "text" ? "solid" : "bordered", onPress: () => setFormData({ ...formData, type: "text" }), startContent: _jsx(MessageSquare, { className: "w-4 h-4" }), children: "Text" }), _jsx(Button, { variant: formData.type === "image" ? "solid" : "bordered", onPress: () => setFormData({ ...formData, type: "image" }), startContent: _jsx(ImageIcon, { className: "w-4 h-4" }), children: "Image" })] }), _jsxs("div", { className: "flex gap-4", children: [_jsx(Switch, { isSelected: formData.is_public, onValueChange: (value) => setFormData({ ...formData, is_public: value }), children: "Make Public" }), _jsx(Switch, { isSelected: formData.favorite, onValueChange: (value) => setFormData({ ...formData, favorite: value }), children: "Favorite" })] })] }) }), _jsxs(ModalFooter, { children: [_jsx(Button, { variant: "light", onPress: onClose, children: "Cancel" }), _jsx(Button, { color: "primary", onPress: handleSave, children: editingPrompt ? "Update" : "Create" })] })] }) })] }));
137
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"TokenPage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/TokenPage.tsx"],"names":[],"mappings":"AAoEA,wBAAgB,SAAS,4CAkhBxB"}
1
+ {"version":3,"file":"TokenPage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/TokenPage.tsx"],"names":[],"mappings":"AA6FA,wBAAgB,SAAS,4CAsrBxB"}