@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,258 @@
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, Select, SelectItem, Input, Switch, Spinner, addToast, Checkbox, CheckboxGroup, Chip, } from "@lastbrain/ui";
5
+ import { Save } from "lucide-react";
6
+ import { useAuth, useModuleTranslation } from "@lastbrain/core";
7
+ export function AISettingsPage() {
8
+ const t = useModuleTranslation("ai");
9
+ const { user } = useAuth();
10
+ const [loading, setLoading] = useState(true);
11
+ const [saving, setSaving] = useState(false);
12
+ const [providers, setProviders] = useState([]);
13
+ const [textModels, setTextModels] = useState([]);
14
+ const [imageModels, setImageModels] = useState([]);
15
+ const [settings, setSettings] = useState({
16
+ mode: "auto",
17
+ default_text_provider: null,
18
+ default_text_model: null,
19
+ default_image_provider: null,
20
+ default_image_model: null,
21
+ max_tokens_per_call: null,
22
+ });
23
+ // Gateway models management
24
+ const [gatewayProviders, setGatewayProviders] = useState([]);
25
+ const [modelSettings, setModelSettings] = useState({
26
+ enabled_models: [],
27
+ enabled_providers: null,
28
+ });
29
+ const [loadingGateway, setLoadingGateway] = useState(false);
30
+ const [searchQuery, setSearchQuery] = useState("");
31
+ const [hasSettings, setHasSettings] = useState(false); // Track if user has settings
32
+ const [tokenPacks, setTokenPacks] = useState([]);
33
+ useEffect(() => {
34
+ fetchData();
35
+ fetchGatewayModels();
36
+ }, []);
37
+ const fetchGatewayModels = async () => {
38
+ try {
39
+ setLoadingGateway(true);
40
+ const [modelsRes, settingsRes, packsRes] = await Promise.all([
41
+ fetch("/api/ai/public/gateway-models"),
42
+ fetch("/api/ai/auth/ai-model-settings"),
43
+ fetch("/api/ai/auth/token-packs"),
44
+ ]);
45
+ if (modelsRes.ok) {
46
+ const data = await modelsRes.json();
47
+ setGatewayProviders(data.providers || []);
48
+ }
49
+ if (settingsRes.ok) {
50
+ const data = await settingsRes.json();
51
+ console.log("[AISettings] Fetched enabled_models:", data.enabled_models);
52
+ const hasUserSettings = data.enabled_models && data.enabled_models.length > 0;
53
+ setHasSettings(hasUserSettings);
54
+ setModelSettings({
55
+ enabled_models: data.enabled_models || [],
56
+ enabled_providers: data.enabled_providers || null,
57
+ });
58
+ }
59
+ if (packsRes.ok) {
60
+ const data = await packsRes.json();
61
+ setTokenPacks(data.data || []);
62
+ }
63
+ }
64
+ catch (error) {
65
+ addToast({ color: "danger", title: error.message });
66
+ }
67
+ finally {
68
+ setLoadingGateway(false);
69
+ }
70
+ };
71
+ const fetchData = async () => {
72
+ try {
73
+ setLoading(true);
74
+ // Fetch providers and models
75
+ const [providersRes, modelsRes, settingsRes] = await Promise.all([
76
+ fetch("/api/ai/admin/ai-providers"),
77
+ fetch("/api/ai/admin/ai-provider-models"),
78
+ fetch("/api/ai/auth/ai-settings"),
79
+ ]);
80
+ if (providersRes.ok) {
81
+ const data = await providersRes.json();
82
+ setProviders(data.data.filter((p) => p.is_active));
83
+ }
84
+ if (modelsRes.ok) {
85
+ const data = await modelsRes.json();
86
+ const activeModels = data.data.filter((m) => m.is_active);
87
+ setTextModels(activeModels.filter((m) => m.kind === "text"));
88
+ setImageModels(activeModels.filter((m) => m.kind === "image"));
89
+ }
90
+ if (settingsRes.ok) {
91
+ const data = await settingsRes.json();
92
+ if (data.data) {
93
+ setSettings(data.data);
94
+ }
95
+ }
96
+ }
97
+ catch (error) {
98
+ addToast({ color: "danger", title: error.message });
99
+ }
100
+ finally {
101
+ setLoading(false);
102
+ }
103
+ };
104
+ const handleSave = async () => {
105
+ try {
106
+ setSaving(true);
107
+ // Save old settings
108
+ const response = await fetch("/api/ai/auth/ai-settings", {
109
+ method: "PUT",
110
+ headers: { "Content-Type": "application/json" },
111
+ body: JSON.stringify(settings),
112
+ });
113
+ if (!response.ok) {
114
+ const error = await response.json();
115
+ throw new Error(error.error || "Failed to save settings");
116
+ }
117
+ // Save model settings
118
+ const modelRes = await fetch("/api/ai/auth/ai-model-settings", {
119
+ method: "POST",
120
+ headers: { "Content-Type": "application/json" },
121
+ body: JSON.stringify(modelSettings),
122
+ });
123
+ if (!modelRes.ok) {
124
+ const error = await modelRes.json();
125
+ throw new Error(error.error || "Failed to save model settings");
126
+ }
127
+ addToast({ color: "success", title: "Settings saved successfully" });
128
+ }
129
+ catch (error) {
130
+ addToast({ color: "danger", title: error.message });
131
+ }
132
+ finally {
133
+ setSaving(false);
134
+ }
135
+ };
136
+ const handleModelsChange = (modelIds) => {
137
+ setModelSettings((prev) => ({
138
+ ...prev,
139
+ enabled_models: modelIds,
140
+ }));
141
+ setHasSettings(true); // Mark as having settings once user interacts
142
+ };
143
+ const handleProviderToggle = (provider, enabled) => {
144
+ const providerModelIds = provider.models.map((m) => m.id);
145
+ setModelSettings((prev) => {
146
+ let newEnabledModels;
147
+ if (enabled) {
148
+ // Add all provider models
149
+ newEnabledModels = Array.from(new Set([...prev.enabled_models, ...providerModelIds]));
150
+ }
151
+ else {
152
+ // Remove all provider models
153
+ newEnabledModels = prev.enabled_models.filter((id) => !providerModelIds.includes(id));
154
+ }
155
+ return {
156
+ ...prev,
157
+ enabled_models: newEnabledModels,
158
+ };
159
+ });
160
+ setHasSettings(true);
161
+ };
162
+ // Calculate internal token price based on token packs
163
+ const calculateTokenPrice = () => {
164
+ if (tokenPacks.length === 0)
165
+ return null;
166
+ // Use the best value pack (lowest price per token)
167
+ const pricesPerToken = tokenPacks.map((pack) => pack.price_cents / pack.tokens / 100);
168
+ return Math.min(...pricesPerToken);
169
+ };
170
+ // Calculate price ratio and display pricing
171
+ const calculatePricing = (model) => {
172
+ const tokenPrice = calculateTokenPrice();
173
+ if (!tokenPrice || !model.pricing)
174
+ return null;
175
+ // Convert pricing from per 1M tokens to per token
176
+ const providerInputCost = parseFloat(model.pricing.input?.toString() || "0") / 1000000;
177
+ const providerOutputCost = parseFloat(model.pricing.output?.toString() || "0") / 1000000;
178
+ const avgCost = (providerInputCost + providerOutputCost) / 2 ||
179
+ providerInputCost ||
180
+ providerOutputCost;
181
+ const ratio = avgCost > 0 ? tokenPrice / avgCost : 0;
182
+ return {
183
+ ratio: ratio.toFixed(2),
184
+ internalInput: providerInputCost > 0
185
+ ? (providerInputCost / tokenPrice).toFixed(2)
186
+ : "0",
187
+ internalOutput: providerOutputCost > 0
188
+ ? (providerOutputCost / tokenPrice).toFixed(2)
189
+ : "0",
190
+ };
191
+ };
192
+ // Filter models based on search
193
+ const filterModels = (models) => {
194
+ if (!searchQuery)
195
+ return models;
196
+ const query = searchQuery.toLowerCase();
197
+ return models.filter((m) => m.name.toLowerCase().includes(query) ||
198
+ m.id.toLowerCase().includes(query));
199
+ };
200
+ const availableTextModels = settings.default_text_provider
201
+ ? textModels.filter((m) => m.provider_key === settings.default_text_provider)
202
+ : [];
203
+ const availableImageModels = settings.default_image_provider
204
+ ? imageModels.filter((m) => m.provider_key === settings.default_image_provider)
205
+ : [];
206
+ if (loading) {
207
+ return (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Spinner, {}) }));
208
+ }
209
+ return (_jsxs("div", { className: "mx-auto max-w-lg mx-auto py-8 space-y-6 pb-32", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold", children: "AI Settings" }), _jsx("p", { className: "text-sm text-default-800", children: "Configure your default AI providers and model preferences" })] }) }), _jsxs(CardBody, { className: "space-y-6", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-4", children: "Mode" }), _jsx(Switch, { isSelected: settings.mode === "manual", onValueChange: (val) => setSettings({
210
+ ...settings,
211
+ mode: val ? "manual" : "auto",
212
+ }), children: "Manual Mode (Choose specific providers)" }), settings.mode === "auto" && (_jsx("p", { className: "text-sm text-default-800 mt-2", children: "Auto mode will automatically select the best available provider" }))] }), settings.mode === "manual" && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: "Text Generation" }), _jsx(Select, { label: "Default Text Provider", selectedKeys: settings.default_text_provider
213
+ ? [settings.default_text_provider]
214
+ : [], onSelectionChange: (keys) => {
215
+ const provider = Array.from(keys)[0];
216
+ setSettings({
217
+ ...settings,
218
+ default_text_provider: provider,
219
+ default_text_model: null,
220
+ });
221
+ }, children: providers
222
+ .filter((p) => p.supports_text)
223
+ .map((provider) => (_jsx(SelectItem, { children: provider.name }, provider.key))) }), settings.default_text_provider && (_jsx(Select, { label: "Default Text Model", selectedKeys: settings.default_text_model
224
+ ? [settings.default_text_model]
225
+ : [], onSelectionChange: (keys) => setSettings({
226
+ ...settings,
227
+ default_text_model: Array.from(keys)[0],
228
+ }), children: availableTextModels.map((model) => (_jsx(SelectItem, { children: model.model }, model.model))) }))] }), _jsxs("div", { className: "space-y-4", children: [_jsx("h3", { className: "text-lg font-semibold", children: "Image Generation" }), _jsx(Select, { label: "Default Image Provider", selectedKeys: settings.default_image_provider
229
+ ? [settings.default_image_provider]
230
+ : [], onSelectionChange: (keys) => {
231
+ const provider = Array.from(keys)[0];
232
+ setSettings({
233
+ ...settings,
234
+ default_image_provider: provider,
235
+ default_image_model: null,
236
+ });
237
+ }, children: providers
238
+ .filter((p) => p.supports_image)
239
+ .map((provider) => (_jsx(SelectItem, { children: provider.name }, provider.key))) }), settings.default_image_provider && (_jsx(Select, { label: "Default Image Model", selectedKeys: settings.default_image_model
240
+ ? [settings.default_image_model]
241
+ : [], onSelectionChange: (keys) => setSettings({
242
+ ...settings,
243
+ default_image_model: Array.from(keys)[0],
244
+ }), children: availableImageModels.map((model) => (_jsx(SelectItem, { children: model.model }, model.model))) }))] })] })), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-4", children: "Limits" }), _jsx(Input, { type: "number", label: "Max Tokens Per Call", value: String(settings.max_tokens_per_call || ""), onChange: (e) => setSettings({
245
+ ...settings,
246
+ max_tokens_per_call: e.target.value
247
+ ? parseInt(e.target.value)
248
+ : null,
249
+ }), description: "Maximum tokens allowed per API call (leave empty for no limit)" })] })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { className: "w-full space-y-3", children: [_jsxs("div", { className: "w-full flex justify-between", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-xl font-bold", children: "Available Models" }), _jsx("p", { className: "text-sm text-gray-600", children: "Select which models are available for use. Only enabled models can be called via API." })] }), _jsxs(Chip, { color: "success", children: [modelSettings.enabled_models.length || 0, " Enabled"] })] }), _jsx(Input, { type: "text", placeholder: "Search models...", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), onClear: () => setSearchQuery(""), className: "max-w-md", isClearable: true })] }) }), _jsx(CardBody, { className: "space-y-6", children: loadingGateway ? (_jsx("div", { className: "flex justify-center py-4", children: _jsx(Spinner, {}) })) : (_jsxs(_Fragment, { children: [gatewayProviders.map((provider) => {
250
+ const filteredModels = filterModels(provider.models);
251
+ if (filteredModels.length === 0)
252
+ return null;
253
+ return (_jsxs("div", { className: "space-y-3 border-b border-default-200 pb-4", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx("h3", { className: "text-lg font-semibold", children: provider.display_name }), _jsx(Switch, { size: "sm", isSelected: provider.models.every((m) => modelSettings.enabled_models.includes(m.id)), onValueChange: (enabled) => handleProviderToggle(provider, enabled), children: "Enable All" })] }), _jsx(CheckboxGroup, { value: modelSettings.enabled_models, onValueChange: handleModelsChange, classNames: { base: "w-full" }, children: _jsx("div", { className: "flex flex-col pl-4", children: filteredModels.map((model) => (_jsx(Checkbox, { value: model.id, classNames: {
254
+ base: "inline-flex max-w-full w-full bg-content1 m-0 hover:bg-content2 items-center justify-start cursor-pointer rounded-lg gap-2 p-4 border-2 border-transparent data-[selected=true]:border-primary",
255
+ label: "w-full",
256
+ }, children: _jsxs("div", { className: "w-full flex flex-col gap-1", children: [_jsx("span", { className: "font-medium text-sm", children: model.name }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-xs text-default-500", children: model.type }), _jsx("span", { className: "text-xs text-default-400", children: "\u2022" }), _jsx("span", { className: "text-xs text-default-500 truncate", children: model.id })] })] }) }, model.id))) }) })] }, provider.name));
257
+ }), gatewayProviders.length === 0 && (_jsx("p", { className: "text-center text-default-800 py-4", children: "No models available from gateway" }))] })) })] }), _jsx("div", { className: "fixed bottom-0 left-0 right-0 bg-background/80 backdrop-blur-md border-t border-divider py-4 z-10", children: _jsx("div", { className: "container mx-auto flex justify-center", children: _jsx(Button, { color: "primary", size: "md", startContent: _jsx(Save, { size: 20 }), onPress: handleSave, isLoading: saving, className: "shadow-lg", children: "Save" }) }) })] }));
258
+ }
@@ -0,0 +1,2 @@
1
+ export declare function APIKeysPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=APIKeysPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"APIKeysPage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/APIKeysPage.tsx"],"names":[],"mappings":"AAsDA,wBAAgB,WAAW,4CA6a1B"}
@@ -0,0 +1,154 @@
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, Input, Select, SelectItem, Switch, Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Spinner, addToast, Chip, Snippet, } from "@lastbrain/ui";
5
+ import { Plus, Eye, EyeOff, Copy, Key, Trash2, Ban, Check, X, } from "lucide-react";
6
+ import { useAuth, useModuleTranslation } from "@lastbrain/core";
7
+ export function APIKeysPage() {
8
+ const t = useModuleTranslation("ai");
9
+ const { user } = useAuth();
10
+ const [apiKeys, setApiKeys] = useState([]);
11
+ const [loading, setLoading] = useState(true);
12
+ const [isModalOpen, setIsModalOpen] = useState(false);
13
+ const [newKey, setNewKey] = useState(null);
14
+ const [showNewKey, setShowNewKey] = useState(false);
15
+ const [formData, setFormData] = useState({
16
+ name: "",
17
+ env: "dev",
18
+ scopes: ["text", "image", "status"],
19
+ rate_limit_rpm: 60,
20
+ daily_token_limit: "",
21
+ });
22
+ useEffect(() => {
23
+ fetchApiKeys();
24
+ }, []);
25
+ const fetchApiKeys = async () => {
26
+ try {
27
+ setLoading(true);
28
+ const response = await fetch("/api/ai/auth/api-keys");
29
+ if (!response.ok)
30
+ throw new Error("Error loading API keys");
31
+ const result = await response.json();
32
+ setApiKeys(result.data || []);
33
+ }
34
+ catch (error) {
35
+ addToast({ color: "danger", title: error.message });
36
+ }
37
+ finally {
38
+ setLoading(false);
39
+ }
40
+ };
41
+ const handleCreate = () => {
42
+ setNewKey(null);
43
+ setShowNewKey(false);
44
+ setFormData({
45
+ name: "",
46
+ env: "dev",
47
+ scopes: ["text", "image", "status"],
48
+ rate_limit_rpm: 60,
49
+ daily_token_limit: "",
50
+ });
51
+ setIsModalOpen(true);
52
+ };
53
+ const handleSave = async () => {
54
+ try {
55
+ const response = await fetch("/api/ai/auth/api-keys", {
56
+ method: "POST",
57
+ headers: { "Content-Type": "application/json" },
58
+ body: JSON.stringify({
59
+ ...formData,
60
+ daily_token_limit: formData.daily_token_limit
61
+ ? parseInt(formData.daily_token_limit)
62
+ : null,
63
+ }),
64
+ });
65
+ if (!response.ok) {
66
+ const error = await response.json();
67
+ throw new Error(error.error || "Failed to create API key");
68
+ }
69
+ const result = await response.json();
70
+ setNewKey(result.api_key);
71
+ setShowNewKey(false);
72
+ addToast({
73
+ color: "success",
74
+ title: "API key created successfully",
75
+ });
76
+ fetchApiKeys();
77
+ }
78
+ catch (error) {
79
+ addToast({ color: "danger", title: error.message });
80
+ }
81
+ };
82
+ const handleRevoke = async (id) => {
83
+ if (!confirm("Are you sure you want to revoke this API key? This action cannot be undone."))
84
+ return;
85
+ try {
86
+ const response = await fetch(`/api/ai/auth/api-keys/${id}`, {
87
+ method: "DELETE",
88
+ });
89
+ if (!response.ok) {
90
+ const error = await response.json();
91
+ throw new Error(error.error || "Failed to revoke API key");
92
+ }
93
+ addToast({ color: "success", title: "API key revoked successfully" });
94
+ fetchApiKeys();
95
+ }
96
+ catch (error) {
97
+ addToast({ color: "danger", title: error.message });
98
+ }
99
+ };
100
+ const handleDelete = async (id) => {
101
+ if (!confirm("Are you sure you want to permanently delete this API key? This action cannot be undone."))
102
+ return;
103
+ try {
104
+ const response = await fetch(`/api/ai/auth/api-keys/${id}?permanent=true`, {
105
+ method: "DELETE",
106
+ });
107
+ if (!response.ok) {
108
+ const error = await response.json();
109
+ throw new Error(error.error || "Failed to delete API key");
110
+ }
111
+ addToast({ color: "success", title: "API key deleted successfully" });
112
+ fetchApiKeys();
113
+ }
114
+ catch (error) {
115
+ addToast({ color: "danger", title: error.message });
116
+ }
117
+ };
118
+ const handleCopy = async (text) => {
119
+ try {
120
+ await navigator.clipboard.writeText(text);
121
+ addToast({ color: "success", title: "Copied to clipboard" });
122
+ }
123
+ catch (error) {
124
+ addToast({ color: "danger", title: "Failed to copy" });
125
+ }
126
+ };
127
+ const handleToggleScope = (scope) => {
128
+ const newScopes = formData.scopes.includes(scope)
129
+ ? formData.scopes.filter((s) => s !== scope)
130
+ : [...formData.scopes, scope];
131
+ setFormData({ ...formData, scopes: newScopes });
132
+ };
133
+ const formatDate = (dateString) => {
134
+ if (!dateString)
135
+ return "Never";
136
+ return new Date(dateString).toLocaleDateString();
137
+ };
138
+ 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: [_jsx("h1", { className: "text-2xl font-bold", children: "API Keys" }), _jsx("p", { className: "text-sm text-gray-600", children: "Manage API keys for external access to AI services" })] }), _jsx(Button, { color: "primary", startContent: _jsx(Plus, { size: 20 }), onPress: handleCreate, children: "Create API Key" })] }), _jsx(CardBody, { children: loading ? (_jsx("div", { className: "flex justify-center py-8", children: _jsx(Spinner, {}) })) : apiKeys.length === 0 ? (_jsxs("div", { className: "text-center py-8", children: [_jsx(Key, { size: 48, className: "mx-auto text-gray-400 mb-4" }), _jsx("p", { className: "text-gray-600 mb-4", children: "No API keys yet" }), _jsx(Button, { color: "primary", onPress: handleCreate, children: "Create Your First API Key" })] })) : (_jsxs(Table, { "aria-label": "API Keys table", children: [_jsxs(TableHeader, { children: [_jsx(TableColumn, { children: "NAME" }), _jsx(TableColumn, { children: "PREFIX" }), _jsx(TableColumn, { children: "ENV" }), _jsx(TableColumn, { children: "SCOPES" }), _jsx(TableColumn, { children: "RPM LIMIT" }), _jsx(TableColumn, { children: "LAST USED" }), _jsx(TableColumn, { children: "STATUS" }), _jsx(TableColumn, { align: "end", children: "ACTIONS" })] }), _jsx(TableBody, { children: apiKeys.map((apiKey) => (_jsxs(TableRow, { children: [_jsx(TableCell, { children: apiKey.name }), _jsx(TableCell, { children: _jsxs("code", { className: "text-sm", children: [apiKey.prefix, "..."] }) }), _jsx(TableCell, { children: _jsx(Chip, { color: apiKey.env === "prod" ? "primary" : "default", variant: "flat", size: "sm", children: apiKey.env }) }), _jsx(TableCell, { children: _jsx("div", { className: "flex flex-wrap gap-1", children: apiKey.scopes.map((scope) => (_jsx(Chip, { size: "sm", variant: "flat", children: scope }, scope))) }) }), _jsx(TableCell, { children: apiKey.rate_limit_rpm }), _jsx(TableCell, { children: formatDate(apiKey.last_used_at) }), _jsx(TableCell, { children: _jsx(Chip, { color: apiKey.is_active ? "success" : "warning", variant: "flat", size: "sm", startContent: apiKey.is_active ? (_jsx(Check, { size: 16 })) : (_jsx(X, { size: 16 })), children: apiKey.is_active ? "Active" : "Inactive" }) }), _jsx(TableCell, { children: _jsx("div", { className: "flex justify-end gap-2", children: apiKey.is_active ? (_jsx(Button, { size: "sm", variant: "light", color: "danger", isIconOnly: true, onPress: () => handleRevoke(apiKey.id), children: _jsx(Ban, { size: 16 }) })) : (_jsx(Button, { size: "sm", variant: "light", color: "danger", isIconOnly: true, onPress: () => handleDelete(apiKey.id), children: _jsx(Trash2, { size: 16 }) })) }) })] }, apiKey.id))) })] })) })] }), _jsx(Modal, { isOpen: isModalOpen, onClose: () => {
139
+ setIsModalOpen(false);
140
+ setNewKey(null);
141
+ }, size: "4xl", backdrop: "blur", children: _jsxs(ModalContent, { children: [_jsx(ModalHeader, { children: newKey ? "API Key Created" : "Create API Key" }), _jsx(ModalBody, { children: newKey ? (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "p-4 bg-yellow-50 border border-yellow-200 rounded-lg", children: [_jsx("p", { className: "text-sm text-yellow-800 font-medium mb-2", children: "\u26A0\uFE0F Important: Copy your API key now" }), _jsx("p", { className: "text-xs text-yellow-700", children: "This is the only time you'll see this key. Store it securely." })] }), _jsx("div", { className: "relative", children: _jsx(Input, { label: "API Key", value: newKey, type: showNewKey ? "text" : "password", readOnly: true, endContent: _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "light", isIconOnly: true, onPress: () => setShowNewKey(!showNewKey), children: showNewKey ? (_jsx(EyeOff, { size: 16 })) : (_jsx(Eye, { size: 16 })) }), _jsx(Button, { size: "sm", variant: "light", isIconOnly: true, onPress: () => handleCopy(newKey), children: _jsx(Copy, { size: 16 }) })] }) }) }), _jsxs(Snippet, { hideSymbol: true, className: "w-full p-4 text-xs", children: [_jsx("span", { children: `curl -X POST ${typeof window !== "undefined" ? window.location.origin : ""}/api/public/v1/text-ai \\` }), _jsx("span", { children: ` -H "Authorization: Bearer ${newKey}" \\` }), _jsx("span", { children: ` -H "Content-Type: application/json" \\` }), _jsx("span", { children: ` -d '{"prompt": "Hello world"}'` })] })] })) : (_jsxs("div", { className: "space-y-4", children: [_jsx(Input, { label: "Name", value: formData.name, onChange: (e) => setFormData({ ...formData, name: e.target.value }), placeholder: "My API Key", description: "A friendly name to identify this key" }), _jsxs(Select, { label: "Environment", selectedKeys: [formData.env], onSelectionChange: (keys) => setFormData({
142
+ ...formData,
143
+ env: Array.from(keys)[0],
144
+ }), children: [_jsx(SelectItem, { children: "Development" }, "dev"), _jsx(SelectItem, { children: "Production" }, "prod")] }), _jsxs("div", { children: [_jsx("label", { className: "text-sm font-medium mb-2 block", children: "Scopes" }), _jsx("div", { className: "flex flex-wrap gap-2", children: ["text", "image", "status"].map((scope) => (_jsx(Switch, { size: "sm", isSelected: formData.scopes.includes(scope), onValueChange: () => handleToggleScope(scope), children: scope }, scope))) })] }), _jsx(Input, { type: "number", label: "Rate Limit (RPM)", value: String(formData.rate_limit_rpm), onChange: (e) => setFormData({
145
+ ...formData,
146
+ rate_limit_rpm: parseInt(e.target.value) || 60,
147
+ }), description: "Requests per minute limit" }), _jsx(Input, { type: "number", label: "Daily Token Limit (Optional)", value: formData.daily_token_limit, onChange: (e) => setFormData({
148
+ ...formData,
149
+ daily_token_limit: e.target.value,
150
+ }), description: "Leave empty for no limit" })] })) }), _jsx(ModalFooter, { children: newKey ? (_jsx(Button, { color: "primary", onPress: () => {
151
+ setIsModalOpen(false);
152
+ setNewKey(null);
153
+ }, children: "Done" })) : (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "light", onPress: () => setIsModalOpen(false), children: "Cancel" }), _jsx(Button, { color: "primary", onPress: handleSave, children: "Create" })] })) })] }) })] }));
154
+ }
@@ -0,0 +1,2 @@
1
+ export declare function HistoryPage(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=HistoryPage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HistoryPage.d.ts","sourceRoot":"","sources":["../../../src/web/auth/HistoryPage.tsx"],"names":[],"mappings":"AAgEA,wBAAgB,WAAW,4CAwnB1B"}