@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.
- package/README.md +52 -1
- package/dist/ai.build.config.d.ts.map +1 -1
- package/dist/ai.build.config.js +508 -9
- package/dist/api/admin/ai-provider-models/[id].d.ts +18 -0
- package/dist/api/admin/ai-provider-models/[id].d.ts.map +1 -0
- package/dist/api/admin/ai-provider-models/[id].js +58 -0
- package/dist/api/admin/ai-provider-models.d.ts +20 -0
- package/dist/api/admin/ai-provider-models.d.ts.map +1 -0
- package/dist/api/admin/ai-provider-models.js +26 -0
- package/dist/api/admin/ai-providers/[key].d.ts +18 -0
- package/dist/api/admin/ai-providers/[key].d.ts.map +1 -0
- package/dist/api/admin/ai-providers/[key].js +55 -0
- package/dist/api/admin/ai-providers.d.ts +20 -0
- package/dist/api/admin/ai-providers.d.ts.map +1 -0
- package/dist/api/admin/ai-providers.js +26 -0
- package/dist/api/admin/billing-analytics.d.ts +43 -0
- package/dist/api/admin/billing-analytics.d.ts.map +1 -0
- package/dist/api/admin/billing-analytics.js +144 -0
- package/dist/api/admin/global-ai-settings.d.ts +14 -0
- package/dist/api/admin/global-ai-settings.d.ts.map +1 -0
- package/dist/api/admin/global-ai-settings.js +63 -0
- package/dist/api/admin/token-packs/[id].d.ts.map +1 -1
- package/dist/api/admin/token-packs/[id].js +3 -2
- package/dist/api/admin/token-packs.d.ts.map +1 -1
- package/dist/api/admin/token-packs.js +3 -2
- package/dist/api/admin/user-monthly-details.d.ts +49 -0
- package/dist/api/admin/user-monthly-details.d.ts.map +1 -0
- package/dist/api/admin/user-monthly-details.js +140 -0
- package/dist/api/admin/user-quota.d.ts +21 -0
- package/dist/api/admin/user-quota.d.ts.map +1 -0
- package/dist/api/admin/user-quota.js +59 -0
- package/dist/api/admin/user-token/[id].d.ts.map +1 -1
- package/dist/api/admin/user-token/[id].js +2 -1
- package/dist/api/admin/user-token.d.ts +5 -2
- package/dist/api/admin/user-token.d.ts.map +1 -1
- package/dist/api/admin/user-token.js +91 -17
- package/dist/api/admin/user-usage-by-model.d.ts +22 -0
- package/dist/api/admin/user-usage-by-model.d.ts.map +1 -0
- package/dist/api/admin/user-usage-by-model.js +78 -0
- package/dist/api/admin/user-wallet-analytics.d.ts +15 -0
- package/dist/api/admin/user-wallet-analytics.d.ts.map +1 -0
- package/dist/api/admin/user-wallet-analytics.js +67 -0
- package/dist/api/admin/wallet-repair/route.d.ts +30 -0
- package/dist/api/admin/wallet-repair/route.d.ts.map +1 -0
- package/dist/api/admin/wallet-repair/route.js +63 -0
- package/dist/api/auth/ai-model-settings.d.ts +21 -0
- package/dist/api/auth/ai-model-settings.d.ts.map +1 -0
- package/dist/api/auth/ai-model-settings.js +86 -0
- package/dist/api/auth/ai-settings.d.ts +17 -0
- package/dist/api/auth/ai-settings.d.ts.map +1 -0
- package/dist/api/auth/ai-settings.js +87 -0
- package/dist/api/auth/api-keys/[id].d.ts +17 -0
- package/dist/api/auth/api-keys/[id].d.ts.map +1 -0
- package/dist/api/auth/api-keys/[id].js +66 -0
- package/dist/api/auth/api-keys.d.ts +19 -0
- package/dist/api/auth/api-keys.d.ts.map +1 -0
- package/dist/api/auth/api-keys.js +94 -0
- package/dist/api/auth/create-checkout.d.ts +1 -1
- package/dist/api/auth/create-checkout.d.ts.map +1 -1
- package/dist/api/auth/create-checkout.js +8 -6
- package/dist/api/auth/generate-image.d.ts +2 -2
- package/dist/api/auth/generate-image.d.ts.map +1 -1
- package/dist/api/auth/generate-image.js +404 -104
- package/dist/api/auth/generate-text.d.ts +3 -2
- package/dist/api/auth/generate-text.d.ts.map +1 -1
- package/dist/api/auth/generate-text.js +130 -58
- package/dist/api/auth/process-ocr.d.ts +9 -0
- package/dist/api/auth/process-ocr.d.ts.map +1 -0
- package/dist/api/auth/process-ocr.js +43 -0
- package/dist/api/auth/prompts/stats.d.ts +14 -0
- package/dist/api/auth/prompts/stats.d.ts.map +1 -0
- package/dist/api/auth/prompts/stats.js +46 -0
- package/dist/api/auth/prompts.d.ts +26 -0
- package/dist/api/auth/prompts.d.ts.map +1 -0
- package/dist/api/auth/prompts.js +175 -0
- package/dist/api/auth/token-balance.d.ts +26 -0
- package/dist/api/auth/token-balance.d.ts.map +1 -0
- package/dist/api/auth/token-balance.js +47 -0
- package/dist/api/auth/token-checkout.d.ts.map +1 -1
- package/dist/api/auth/token-checkout.js +22 -4
- package/dist/api/auth/token-packs.d.ts.map +1 -1
- package/dist/api/auth/token-packs.js +2 -1
- package/dist/api/auth/usage-by-model.d.ts +25 -0
- package/dist/api/auth/usage-by-model.d.ts.map +1 -0
- package/dist/api/auth/usage-by-model.js +95 -0
- package/dist/api/auth/usage.d.ts +26 -0
- package/dist/api/auth/usage.d.ts.map +1 -0
- package/dist/api/auth/usage.js +127 -0
- package/dist/api/auth/user-tokens.d.ts.map +1 -1
- package/dist/api/auth/user-tokens.js +36 -2
- package/dist/api/auth/wallet/route.d.ts +17 -0
- package/dist/api/auth/wallet/route.d.ts.map +1 -0
- package/dist/api/auth/wallet/route.js +68 -0
- package/dist/api/auth/wallet.d.ts +16 -0
- package/dist/api/auth/wallet.d.ts.map +1 -0
- package/dist/api/auth/wallet.js +71 -0
- package/dist/api/public/gateway-models.d.ts +25 -0
- package/dist/api/public/gateway-models.d.ts.map +1 -0
- package/dist/api/public/gateway-models.js +49 -0
- package/dist/api/public/pricing-summary.d.ts +46 -0
- package/dist/api/public/pricing-summary.d.ts.map +1 -0
- package/dist/api/public/pricing-summary.js +70 -0
- package/dist/api/public/prompts/[id]/stats.d.ts +15 -0
- package/dist/api/public/prompts/[id]/stats.d.ts.map +1 -0
- package/dist/api/public/prompts/[id]/stats.js +37 -0
- package/dist/api/public/prompts/[id]/view.d.ts +15 -0
- package/dist/api/public/prompts/[id]/view.d.ts.map +1 -0
- package/dist/api/public/prompts/[id]/view.js +41 -0
- package/dist/api/public/prompts/slug/[slug].d.ts +15 -0
- package/dist/api/public/prompts/slug/[slug].d.ts.map +1 -0
- package/dist/api/public/prompts/slug/[slug].js +40 -0
- package/dist/api/public/prompts/user/[username].d.ts +17 -0
- package/dist/api/public/prompts/user/[username].d.ts.map +1 -0
- package/dist/api/public/prompts/user/[username].js +51 -0
- package/dist/api/public/prompts.d.ts +15 -0
- package/dist/api/public/prompts.d.ts.map +1 -0
- package/dist/api/public/prompts.js +45 -0
- package/dist/api/public/token-packs.d.ts +11 -0
- package/dist/api/public/token-packs.d.ts.map +1 -0
- package/dist/api/public/token-packs.js +25 -0
- package/dist/api/public/token-pricing.d.ts +44 -0
- package/dist/api/public/token-pricing.d.ts.map +1 -0
- package/dist/api/public/token-pricing.js +168 -0
- package/dist/api/public/v1/_lib/artifacts.d.ts +52 -0
- package/dist/api/public/v1/_lib/artifacts.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/artifacts.js +217 -0
- package/dist/api/public/v1/_lib/auth.d.ts +43 -0
- package/dist/api/public/v1/_lib/auth.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/auth.js +108 -0
- package/dist/api/public/v1/_lib/errors.d.ts +17 -0
- package/dist/api/public/v1/_lib/errors.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/errors.js +16 -0
- package/dist/api/public/v1/_lib/log.d.ts +29 -0
- package/dist/api/public/v1/_lib/log.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/log.js +68 -0
- package/dist/api/public/v1/_lib/quota.d.ts +24 -0
- package/dist/api/public/v1/_lib/quota.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/quota.js +118 -0
- package/dist/api/public/v1/_lib/router.d.ts +54 -0
- package/dist/api/public/v1/_lib/router.d.ts.map +1 -0
- package/dist/api/public/v1/_lib/router.js +119 -0
- package/dist/api/public/v1/connect.d.ts +20 -0
- package/dist/api/public/v1/connect.d.ts.map +1 -0
- package/dist/api/public/v1/connect.js +119 -0
- package/dist/api/public/v1/doc.d.ts +239 -0
- package/dist/api/public/v1/doc.d.ts.map +1 -0
- package/dist/api/public/v1/doc.js +253 -0
- package/dist/api/public/v1/history/[id].d.ts +92 -0
- package/dist/api/public/v1/history/[id].d.ts.map +1 -0
- package/dist/api/public/v1/history/[id].js +176 -0
- package/dist/api/public/v1/history.d.ts +30 -0
- package/dist/api/public/v1/history.d.ts.map +1 -0
- package/dist/api/public/v1/history.js +142 -0
- package/dist/api/public/v1/image-ai.d.ts +24 -0
- package/dist/api/public/v1/image-ai.d.ts.map +1 -0
- package/dist/api/public/v1/image-ai.js +233 -0
- package/dist/api/public/v1/prompts.d.ts +19 -0
- package/dist/api/public/v1/prompts.d.ts.map +1 -0
- package/dist/api/public/v1/prompts.js +107 -0
- package/dist/api/public/v1/provider.d.ts +16 -0
- package/dist/api/public/v1/provider.d.ts.map +1 -0
- package/dist/api/public/v1/provider.js +130 -0
- package/dist/api/public/v1/purchase.d.ts +11 -0
- package/dist/api/public/v1/purchase.d.ts.map +1 -0
- package/dist/api/public/v1/purchase.js +18 -0
- package/dist/api/public/v1/status.d.ts +35 -0
- package/dist/api/public/v1/status.d.ts.map +1 -0
- package/dist/api/public/v1/status.js +163 -0
- package/dist/api/public/v1/text-ai.d.ts +26 -0
- package/dist/api/public/v1/text-ai.d.ts.map +1 -0
- package/dist/api/public/v1/text-ai.js +239 -0
- package/dist/api/public/webhook.d.ts.map +1 -1
- package/dist/api/public/webhook.js +50 -39
- package/dist/api/track-usage.d.ts +12 -0
- package/dist/api/track-usage.d.ts.map +1 -0
- package/dist/api/track-usage.js +37 -0
- package/dist/components/Doc.d.ts.map +1 -1
- package/dist/components/Doc.js +1 -1
- package/dist/components/DocUsageCustom.js +6 -6
- package/dist/components/admin/UserTokenTab.d.ts.map +1 -1
- package/dist/components/admin/UserTokenTab.js +170 -23
- package/dist/components/auth/AuthDashboardAi.d.ts +2 -0
- package/dist/components/auth/AuthDashboardAi.d.ts.map +1 -0
- package/dist/components/auth/AuthDashboardAi.js +53 -0
- package/dist/docs/REFACTORING_BILLING_GUIDE.d.ts +277 -0
- package/dist/docs/REFACTORING_BILLING_GUIDE.d.ts.map +1 -0
- package/dist/docs/REFACTORING_BILLING_GUIDE.js +276 -0
- package/dist/index.d.ts +15 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/scripts/migrate-tokens-to-wallet.d.ts +13 -0
- package/dist/scripts/migrate-tokens-to-wallet.d.ts.map +1 -0
- package/dist/scripts/migrate-tokens-to-wallet.js +165 -0
- package/dist/server/__tests__/billing.test.d.ts +5 -0
- package/dist/server/__tests__/billing.test.d.ts.map +1 -0
- package/dist/server/__tests__/billing.test.js +223 -0
- package/dist/server/ai-client.d.ts +59 -0
- package/dist/server/ai-client.d.ts.map +1 -0
- package/dist/server/ai-client.js +111 -0
- package/dist/server/ai-generation-service.d.ts +66 -0
- package/dist/server/ai-generation-service.d.ts.map +1 -0
- package/dist/server/ai-generation-service.js +274 -0
- package/dist/server/billing.d.ts +200 -0
- package/dist/server/billing.d.ts.map +1 -0
- package/dist/server/billing.js +488 -0
- package/dist/server/gateway-service.d.ts +13 -0
- package/dist/server/gateway-service.d.ts.map +1 -0
- package/dist/server/gateway-service.js +161 -0
- package/dist/server/global-settings.d.ts +16 -0
- package/dist/server/global-settings.d.ts.map +1 -0
- package/dist/server/global-settings.js +42 -0
- package/dist/server/model-filter.d.ts +25 -0
- package/dist/server/model-filter.d.ts.map +1 -0
- package/dist/server/model-filter.js +240 -0
- package/dist/server/ocr.d.ts +39 -0
- package/dist/server/ocr.d.ts.map +1 -0
- package/dist/server/ocr.js +280 -0
- package/dist/server/openai-client.d.ts +19 -0
- package/dist/server/openai-client.d.ts.map +1 -0
- package/dist/server/openai-client.js +26 -0
- package/dist/server/pricing-config.d.ts +18 -0
- package/dist/server/pricing-config.d.ts.map +1 -0
- package/dist/server/pricing-config.js +94 -0
- package/dist/server/pricing-validator.d.ts +41 -0
- package/dist/server/pricing-validator.d.ts.map +1 -0
- package/dist/server/pricing-validator.js +113 -0
- package/dist/server/pricing.d.ts +121 -0
- package/dist/server/pricing.d.ts.map +1 -0
- package/dist/server/pricing.js +225 -0
- package/dist/server/quota.d.ts +66 -0
- package/dist/server/quota.d.ts.map +1 -0
- package/dist/server/quota.js +538 -0
- package/dist/server/wallet-repair.d.ts +32 -0
- package/dist/server/wallet-repair.d.ts.map +1 -0
- package/dist/server/wallet-repair.js +189 -0
- package/dist/server.d.ts +13 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +87 -16
- package/dist/sitemap/handlers/prompts.d.ts +6 -0
- package/dist/sitemap/handlers/prompts.d.ts.map +1 -0
- package/dist/sitemap/handlers/prompts.js +72 -0
- package/dist/sitemap/handlers/users.d.ts +6 -0
- package/dist/sitemap/handlers/users.d.ts.map +1 -0
- package/dist/sitemap/handlers/users.js +80 -0
- package/dist/sitemap/manifest.d.ts +8 -0
- package/dist/sitemap/manifest.d.ts.map +1 -0
- package/dist/sitemap/manifest.js +27 -0
- package/dist/types/gateway.d.ts +40 -0
- package/dist/types/gateway.d.ts.map +1 -0
- package/dist/types/gateway.js +4 -0
- package/dist/types/quota.d.ts +74 -0
- package/dist/types/quota.d.ts.map +1 -0
- package/dist/types/quota.js +11 -0
- package/dist/utils/date.d.ts +7 -0
- package/dist/utils/date.d.ts.map +1 -0
- package/dist/utils/date.js +17 -0
- package/dist/web/admin/AdminTokenPacksPage.js +1 -1
- package/dist/web/admin/BillingAnalyticsPage.d.ts +2 -0
- package/dist/web/admin/BillingAnalyticsPage.d.ts.map +1 -0
- package/dist/web/admin/BillingAnalyticsPage.js +141 -0
- package/dist/web/admin/GlobalAISettingsPage.d.ts +2 -0
- package/dist/web/admin/GlobalAISettingsPage.d.ts.map +1 -0
- package/dist/web/admin/GlobalAISettingsPage.js +93 -0
- package/dist/web/admin/UserTokenPage.d.ts.map +1 -1
- package/dist/web/admin/UserTokenPage.js +20 -7
- package/dist/web/auth/AISettingsPage.d.ts +2 -0
- package/dist/web/auth/AISettingsPage.d.ts.map +1 -0
- package/dist/web/auth/AISettingsPage.js +258 -0
- package/dist/web/auth/APIKeysPage.d.ts +2 -0
- package/dist/web/auth/APIKeysPage.d.ts.map +1 -0
- package/dist/web/auth/APIKeysPage.js +154 -0
- package/dist/web/auth/HistoryPage.d.ts +2 -0
- package/dist/web/auth/HistoryPage.d.ts.map +1 -0
- package/dist/web/auth/HistoryPage.js +279 -0
- package/dist/web/auth/PromptsPage.d.ts +5 -0
- package/dist/web/auth/PromptsPage.d.ts.map +1 -0
- package/dist/web/auth/PromptsPage.js +137 -0
- package/dist/web/auth/TokenPage.d.ts.map +1 -1
- package/dist/web/auth/TokenPage.js +88 -31
- package/dist/web/auth/UsageAndTokensPage.d.ts +2 -0
- package/dist/web/auth/UsageAndTokensPage.d.ts.map +1 -0
- package/dist/web/auth/UsageAndTokensPage.js +157 -0
- package/dist/web/auth/UsagePage.d.ts +2 -0
- package/dist/web/auth/UsagePage.d.ts.map +1 -0
- package/dist/web/auth/UsagePage.js +62 -0
- package/dist/web/auth/components/ApiKeyFilterSelect.d.ts +13 -0
- package/dist/web/auth/components/ApiKeyFilterSelect.d.ts.map +1 -0
- package/dist/web/auth/components/ApiKeyFilterSelect.js +16 -0
- package/dist/web/auth/components/ModelUsageTable.d.ts +19 -0
- package/dist/web/auth/components/ModelUsageTable.d.ts.map +1 -0
- package/dist/web/auth/components/ModelUsageTable.js +37 -0
- package/dist/web/auth/components/PurchaseButton.d.ts +7 -0
- package/dist/web/auth/components/PurchaseButton.d.ts.map +1 -0
- package/dist/web/auth/components/PurchaseButton.js +13 -0
- package/dist/web/auth/components/TokenHistoryCard.d.ts +20 -0
- package/dist/web/auth/components/TokenHistoryCard.d.ts.map +1 -0
- package/dist/web/auth/components/TokenHistoryCard.js +76 -0
- package/dist/web/auth/components/TokenKpiGrid.d.ts +24 -0
- package/dist/web/auth/components/TokenKpiGrid.d.ts.map +1 -0
- package/dist/web/auth/components/TokenKpiGrid.js +38 -0
- package/dist/web/auth/components/UsageByDayChart.d.ts +11 -0
- package/dist/web/auth/components/UsageByDayChart.d.ts.map +1 -0
- package/dist/web/auth/components/UsageByDayChart.js +32 -0
- package/dist/web/auth/components/UsageByModelBarChart.d.ts +12 -0
- package/dist/web/auth/components/UsageByModelBarChart.d.ts.map +1 -0
- package/dist/web/auth/components/UsageByModelBarChart.js +32 -0
- package/dist/web/auth/components/WalletStatusCard.d.ts +9 -0
- package/dist/web/auth/components/WalletStatusCard.d.ts.map +1 -0
- package/dist/web/auth/components/WalletStatusCard.js +50 -0
- package/dist/web/components/ImageGenerative.d.ts +3 -1
- package/dist/web/components/ImageGenerative.d.ts.map +1 -1
- package/dist/web/components/ImageGenerative.js +139 -52
- package/dist/web/components/TextareaGenerative.d.ts +3 -1
- package/dist/web/components/TextareaGenerative.d.ts.map +1 -1
- package/dist/web/components/TextareaGenerative.js +10 -5
- package/dist/web/public/PromptDetailPage.d.ts +25 -0
- package/dist/web/public/PromptDetailPage.d.ts.map +1 -0
- package/dist/web/public/PromptDetailPage.js +71 -0
- package/dist/web/public/PromptDetailPageServer.d.ts +15 -0
- package/dist/web/public/PromptDetailPageServer.d.ts.map +1 -0
- package/dist/web/public/PromptDetailPageServer.js +68 -0
- package/dist/web/public/PublicPromptsPage.d.ts +5 -0
- package/dist/web/public/PublicPromptsPage.d.ts.map +1 -0
- package/dist/web/public/PublicPromptsPage.js +110 -0
- package/dist/web/public/PurchaseTokensPage.d.ts +2 -0
- package/dist/web/public/PurchaseTokensPage.d.ts.map +1 -0
- package/dist/web/public/PurchaseTokensPage.js +98 -0
- package/dist/web/public/UserAvatar.d.ts +13 -0
- package/dist/web/public/UserAvatar.d.ts.map +1 -0
- package/dist/web/public/UserAvatar.js +13 -0
- package/dist/web/public/UserDetailPageServer.d.ts +15 -0
- package/dist/web/public/UserDetailPageServer.d.ts.map +1 -0
- package/dist/web/public/UserDetailPageServer.js +31 -0
- package/dist/web/public/UserPromptsPage.d.ts +9 -0
- package/dist/web/public/UserPromptsPage.d.ts.map +1 -0
- package/dist/web/public/UserPromptsPage.js +112 -0
- package/dist/web/public/UserPromptsPageServer.d.ts +15 -0
- package/dist/web/public/UserPromptsPageServer.d.ts.map +1 -0
- package/dist/web/public/UserPromptsPageServer.js +31 -0
- package/package.json +18 -9
- package/supabase/migrations/20251125000000_ai_tokens.sql +7 -0
- package/supabase/migrations/20260123100002_user_token_quota_monthly copy.sql +173 -0
- package/supabase/migrations/20260128100003_update_and_add_table.sql +368 -0
- package/supabase/migrations/20260128120000_seed_providers_models.sql +78 -0
- package/supabase/migrations/20260128131405_add_api_key_id_to_ledgers.sql +41 -0
- package/supabase/migrations/20260128140000_ai_artifacts_storage.sql +99 -0
- package/supabase/migrations/20260128140002_ai_user_settings.sql +57 -0
- package/supabase/migrations/20260128150000_drop_ai_user_settings.sql +21 -0
- package/supabase/migrations/20260128160000_wallet_billing_system.sql +192 -0
- package/supabase/migrations/20260128160001_wallet_rpc_functions.sql +165 -0
- package/supabase/migrations/20260128170000_add_pack_coef_to_token_packs.sql +30 -0
- package/supabase/migrations/20260129120000_wallet_view_rpc.sql +41 -0
- package/supabase/migrations/20260129220003_update_pack_margins.sql +31 -0
- package/supabase/migrations/20260129330004_ai_user_prompts.sql +151 -0
- package/supabase/migrations/20260129330005_ai_prompts_ip_tracking.sql +92 -0
- package/supabase/migrations/20260129330006_ai_prompts_slug.sql +64 -0
- package/supabase/migrations/20260129330007_ai_prompts_view_slug.sql +26 -0
- package/supabase/migrations/20260129440000_ai_prompts_view_username.sql +33 -0
- package/supabase/migrations/20260129450000_ai_prompts_add_lang.sql +40 -0
- package/supabase/migrations/20260131000000_extract_model_prompt_in_ledger.sql +92 -0
- package/supabase/migrations/20260131140000_fix_duplicate_purchases.sql +64 -0
- package/supabase/migrations/20260201120000_module-ai_default_models.sql +63 -0
- package/supabase/migrations/20260201130000_module-ai_remove_provider_tables.sql +17 -0
- package/supabase/migrations-down/20251217120000_user_token_quota_monthly.sql +34 -0
- package/supabase/migrations-down/20260128131405_add_api_key_id_to_ledgers.sql +25 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/public/v1/text-ai
|
|
3
|
+
* Generate text using AI
|
|
4
|
+
*/
|
|
5
|
+
import { NextResponse } from "next/server";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
import { randomUUID } from "crypto";
|
|
8
|
+
import { logger } from "@lastbrain/core";
|
|
9
|
+
import { getSupabaseServiceClient } from "@lastbrain/core/server";
|
|
10
|
+
import { validateApiKey, verifyScope } from "./_lib/auth";
|
|
11
|
+
import { checkMaxTokensPerCall } from "./_lib/quota";
|
|
12
|
+
import { createErrorResponse } from "./_lib/errors";
|
|
13
|
+
import { logApiCall, updateApiKeyLastUsed } from "./_lib/log";
|
|
14
|
+
import { generateText } from "./_lib/router";
|
|
15
|
+
import { shouldStoreOutputs, createArtifact } from "./_lib/artifacts";
|
|
16
|
+
const TextGenerationSchema = z.object({
|
|
17
|
+
prompt: z.string().min(1).max(10000),
|
|
18
|
+
model: z.string().optional(),
|
|
19
|
+
max_tokens: z.number().int().min(1).max(32000).optional(),
|
|
20
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
21
|
+
system_prompt: z.string().max(5000).optional(),
|
|
22
|
+
store_outputs: z.boolean().optional(),
|
|
23
|
+
artifact_title: z.string().max(200).optional(),
|
|
24
|
+
actionType: z
|
|
25
|
+
.enum(["generate-text", "generate-recipe-text", "autocomplete"])
|
|
26
|
+
.optional(),
|
|
27
|
+
});
|
|
28
|
+
export async function POST(request) {
|
|
29
|
+
const startTime = Date.now();
|
|
30
|
+
const requestId = randomUUID();
|
|
31
|
+
let apiKeyId = null;
|
|
32
|
+
let ownerId = null;
|
|
33
|
+
let statusCode = 200;
|
|
34
|
+
let errorCode = null;
|
|
35
|
+
try {
|
|
36
|
+
const authHeader = request.headers.get("Authorization");
|
|
37
|
+
// 1. Validate API key
|
|
38
|
+
const authResult = await validateApiKey(authHeader);
|
|
39
|
+
if (!authResult.success || !authResult.apiKey) {
|
|
40
|
+
const { response, status } = createErrorResponse(authResult.errorCode, authResult.error || "Authentication failed", requestId, undefined, 401);
|
|
41
|
+
statusCode = status;
|
|
42
|
+
errorCode = authResult.errorCode || null;
|
|
43
|
+
return NextResponse.json(response, { status });
|
|
44
|
+
}
|
|
45
|
+
const apiKey = authResult.apiKey;
|
|
46
|
+
apiKeyId = apiKey.id;
|
|
47
|
+
ownerId = apiKey.owner_id;
|
|
48
|
+
// 2. Verify scope
|
|
49
|
+
const scopeResult = verifyScope(apiKey, "text");
|
|
50
|
+
if (!scopeResult.success) {
|
|
51
|
+
const { response, status } = createErrorResponse("INSUFFICIENT_SCOPE", scopeResult.error || "Missing required scope", requestId, undefined, 403);
|
|
52
|
+
statusCode = status;
|
|
53
|
+
errorCode = "INSUFFICIENT_SCOPE";
|
|
54
|
+
return NextResponse.json(response, { status });
|
|
55
|
+
}
|
|
56
|
+
// 3. Parse and validate request body
|
|
57
|
+
const body = await request.json();
|
|
58
|
+
const validation = TextGenerationSchema.safeParse(body);
|
|
59
|
+
if (!validation.success) {
|
|
60
|
+
const { response, status } = createErrorResponse("VALIDATION_ERROR", validation.error.errors.map((e) => e.message).join(", "), requestId, undefined, 400);
|
|
61
|
+
statusCode = status;
|
|
62
|
+
errorCode = "VALIDATION_ERROR";
|
|
63
|
+
return NextResponse.json(response, { status });
|
|
64
|
+
}
|
|
65
|
+
const data = validation.data;
|
|
66
|
+
// 4. Check max_tokens_per_call setting
|
|
67
|
+
const maxTokensCheck = await checkMaxTokensPerCall(ownerId, data.max_tokens || 3000);
|
|
68
|
+
if (!maxTokensCheck.allowed) {
|
|
69
|
+
const { response, status } = createErrorResponse("VALIDATION_ERROR", `max_tokens exceeds limit of ${maxTokensCheck.limit}`, requestId, undefined, 400);
|
|
70
|
+
statusCode = status;
|
|
71
|
+
errorCode = "VALIDATION_ERROR";
|
|
72
|
+
return NextResponse.json(response, { status });
|
|
73
|
+
}
|
|
74
|
+
// 5. Check wallet USD balance BEFORE calling model (prevent free consumption)
|
|
75
|
+
const supabase = getSupabaseServiceClient();
|
|
76
|
+
const { data: walletData, error: walletError } = await supabase
|
|
77
|
+
.from("user_token_wallet")
|
|
78
|
+
.select("wallet_provider_budget_usd")
|
|
79
|
+
.eq("user_id", ownerId)
|
|
80
|
+
.single();
|
|
81
|
+
const currentWalletUsd = walletData?.wallet_provider_budget_usd || 0;
|
|
82
|
+
logger.info(`[text-ai] Wallet check for user_id=${ownerId}: $${currentWalletUsd}`, { walletData, walletError });
|
|
83
|
+
// Simple check: user must have credits (> 0)
|
|
84
|
+
// Real cost will be computed post-generation based on actual usage
|
|
85
|
+
if (currentWalletUsd <= 0) {
|
|
86
|
+
logger.warn(`[text-ai] Insufficient wallet: have $${currentWalletUsd} for owner_id=${ownerId}`);
|
|
87
|
+
const purchaseUrl = process.env.NEXT_PUBLIC_APP_URL + "/auth/module-ai/tokens";
|
|
88
|
+
const { response, status } = createErrorResponse("INSUFFICIENT_CREDITS", `Insufficient credits. Wallet balance: $${currentWalletUsd.toFixed(2)}`, requestId, purchaseUrl, 402);
|
|
89
|
+
statusCode = status;
|
|
90
|
+
errorCode = "INSUFFICIENT_CREDITS";
|
|
91
|
+
return NextResponse.json(response, { status });
|
|
92
|
+
}
|
|
93
|
+
// 5b. Check daily limit (if set on API key)
|
|
94
|
+
if (apiKey.daily_token_limit !== null) {
|
|
95
|
+
const estimatedTokens = Math.ceil(data.prompt.length / 4) + (data.max_tokens || 3000);
|
|
96
|
+
const today = new Date();
|
|
97
|
+
today.setHours(0, 0, 0, 0);
|
|
98
|
+
const { data: todayUsage } = await supabase
|
|
99
|
+
.from("ai_call_log")
|
|
100
|
+
.select("tokens_total")
|
|
101
|
+
.eq("api_key_id", apiKey.id)
|
|
102
|
+
.gte("created_at", today.toISOString());
|
|
103
|
+
const usedToday = todayUsage?.reduce((sum, log) => sum + (log.tokens_total || 0), 0) || 0;
|
|
104
|
+
const dailyLimit = Number(apiKey.daily_token_limit);
|
|
105
|
+
if (usedToday + estimatedTokens > dailyLimit) {
|
|
106
|
+
const { response, status } = createErrorResponse("DAILY_LIMIT_EXCEEDED", `Daily token limit exceeded. Used: ${usedToday}, Limit: ${dailyLimit}`, requestId, undefined, 429);
|
|
107
|
+
statusCode = status;
|
|
108
|
+
errorCode = "DAILY_LIMIT_EXCEEDED";
|
|
109
|
+
return NextResponse.json(response, { status });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// 6. Generate text via router
|
|
113
|
+
const generateResult = await generateText(ownerId, {
|
|
114
|
+
prompt: data.prompt,
|
|
115
|
+
model: data.model,
|
|
116
|
+
maxTokens: data.max_tokens,
|
|
117
|
+
temperature: data.temperature,
|
|
118
|
+
systemPrompt: data.system_prompt,
|
|
119
|
+
actionType: data.actionType || "generate-text",
|
|
120
|
+
});
|
|
121
|
+
if (!generateResult.success) {
|
|
122
|
+
const { response, status } = createErrorResponse("PROVIDER_ERROR", generateResult.error || "Text generation failed", requestId, undefined, 500);
|
|
123
|
+
statusCode = status;
|
|
124
|
+
errorCode = "PROVIDER_ERROR";
|
|
125
|
+
return NextResponse.json(response, { status });
|
|
126
|
+
}
|
|
127
|
+
// 7. Token debit already handled by computeAndDebitAIUsage() in generateText()
|
|
128
|
+
// No need to call debitTokensWithPriority() - it would create duplicate ledger entries
|
|
129
|
+
const tokensUsed = generateResult.tokensTotal || 0;
|
|
130
|
+
logger.info(`[text-ai] ✅ Success: billing handled via computeAndDebitAIUsage()`);
|
|
131
|
+
// 8. Log API call
|
|
132
|
+
const latencyMs = Date.now() - startTime;
|
|
133
|
+
await logApiCall({
|
|
134
|
+
apiKeyId,
|
|
135
|
+
ownerId,
|
|
136
|
+
endpoint: "text",
|
|
137
|
+
provider: generateResult.provider || null,
|
|
138
|
+
model: generateResult.model || null,
|
|
139
|
+
tokensIn: generateResult.tokensIn || null,
|
|
140
|
+
tokensOut: generateResult.tokensOut || null,
|
|
141
|
+
tokensTotal: tokensUsed,
|
|
142
|
+
latencyMs,
|
|
143
|
+
statusCode,
|
|
144
|
+
errorCode: null,
|
|
145
|
+
requestId,
|
|
146
|
+
meta: {
|
|
147
|
+
prompt_length: data.prompt.length,
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
// 9. Update API key last used
|
|
151
|
+
await updateApiKeyLastUsed(apiKey);
|
|
152
|
+
// 10. Store artifact if enabled
|
|
153
|
+
let artifactId;
|
|
154
|
+
let artifactStored = false;
|
|
155
|
+
const shouldStore = await shouldStoreOutputs(ownerId, data.store_outputs);
|
|
156
|
+
if (shouldStore && generateResult.text) {
|
|
157
|
+
const artifactResult = await createArtifact({
|
|
158
|
+
apiKey,
|
|
159
|
+
kind: "text",
|
|
160
|
+
endpoint: "text-ai",
|
|
161
|
+
provider: generateResult.provider,
|
|
162
|
+
model: generateResult.model,
|
|
163
|
+
tokensTotal: tokensUsed,
|
|
164
|
+
statusCode: 200,
|
|
165
|
+
textContent: generateResult.text,
|
|
166
|
+
meta: {
|
|
167
|
+
request_id: requestId,
|
|
168
|
+
title: data.artifact_title,
|
|
169
|
+
temperature: data.temperature,
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
if (artifactResult.success) {
|
|
173
|
+
artifactId = artifactResult.artifactId;
|
|
174
|
+
artifactStored = true;
|
|
175
|
+
logger.debug("[text-ai] Artifact stored", { artifactId });
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
logger.warn("[text-ai] Failed to store artifact", {
|
|
179
|
+
error: artifactResult.error,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// 11. Get updated balance for response
|
|
184
|
+
const { data: finalBalanceData } = await supabase
|
|
185
|
+
.from("user_token_balance_v")
|
|
186
|
+
.select("balance")
|
|
187
|
+
.eq("owner_id", ownerId)
|
|
188
|
+
.single();
|
|
189
|
+
const totalBalance = finalBalanceData?.balance || 0;
|
|
190
|
+
// 12. Return response
|
|
191
|
+
return NextResponse.json({
|
|
192
|
+
request_id: requestId,
|
|
193
|
+
text: generateResult.text,
|
|
194
|
+
model: generateResult.model,
|
|
195
|
+
provider: generateResult.provider,
|
|
196
|
+
tokens: {
|
|
197
|
+
input: generateResult.tokensIn,
|
|
198
|
+
output: generateResult.tokensOut,
|
|
199
|
+
total: tokensUsed,
|
|
200
|
+
},
|
|
201
|
+
balance: {
|
|
202
|
+
remaining_quota: 0, // No quota system for now
|
|
203
|
+
remaining_purchased: totalBalance,
|
|
204
|
+
total: totalBalance,
|
|
205
|
+
},
|
|
206
|
+
artifact: artifactStored
|
|
207
|
+
? {
|
|
208
|
+
id: artifactId,
|
|
209
|
+
stored: true,
|
|
210
|
+
}
|
|
211
|
+
: undefined,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
logger.error("[text-ai] Unexpected error", error);
|
|
216
|
+
statusCode = 500;
|
|
217
|
+
errorCode = "INTERNAL_ERROR";
|
|
218
|
+
// Log error even in catch
|
|
219
|
+
if (apiKeyId && ownerId) {
|
|
220
|
+
const latencyMs = Date.now() - startTime;
|
|
221
|
+
await logApiCall({
|
|
222
|
+
apiKeyId,
|
|
223
|
+
ownerId,
|
|
224
|
+
endpoint: "text",
|
|
225
|
+
provider: null,
|
|
226
|
+
model: null,
|
|
227
|
+
tokensIn: null,
|
|
228
|
+
tokensOut: null,
|
|
229
|
+
tokensTotal: null,
|
|
230
|
+
latencyMs,
|
|
231
|
+
statusCode,
|
|
232
|
+
errorCode,
|
|
233
|
+
requestId,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
const { response, status } = createErrorResponse("INTERNAL_ERROR", error.message || "Internal server error", requestId, undefined, 500);
|
|
237
|
+
return NextResponse.json(response, { status });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/api/public/webhook.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/api/public/webhook.ts"],"names":[],"mappings":"AA0BA,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO,qBAoP1C"}
|
|
@@ -4,26 +4,29 @@
|
|
|
4
4
|
// Receives webhook calls from the central payment webhook when a token purchase
|
|
5
5
|
// payment succeeds. Adds tokens to user balance.
|
|
6
6
|
// CRITICAL: This endpoint must ONLY be callable by service_role to prevent abuse.
|
|
7
|
+
import { logger } from "@lastbrain/core";
|
|
7
8
|
import { getSupabaseServiceClient } from "@lastbrain/core/server";
|
|
8
9
|
export async function POST(request) {
|
|
9
10
|
try {
|
|
10
11
|
const supabase = await getSupabaseServiceClient();
|
|
11
12
|
const payload = (await request.json());
|
|
12
13
|
const { payment, metadata } = payload;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
logger.debug("[AI Webhook] Received webhook for payment", payment.id);
|
|
15
|
+
logger.debug("[AI Webhook] Metadata:", JSON.stringify(metadata, null, 2));
|
|
16
|
+
// Verify this is a token purchase (accept both "token" and "token_purchase" for compatibility)
|
|
17
|
+
if (metadata.purpose !== "token" && metadata.purpose !== "token_purchase") {
|
|
18
|
+
logger.debug("[AI Webhook] Not a token purchase, skipping. Purpose:", metadata.purpose);
|
|
17
19
|
return Response.json({ received: true }, { status: 200 });
|
|
18
20
|
}
|
|
19
21
|
if (!payment?.owner_id) {
|
|
20
22
|
return Response.json({ error: "Missing owner_id" }, { status: 400 });
|
|
21
23
|
}
|
|
22
|
-
// Extract token pack info from metadata
|
|
23
|
-
const tokenPackId = metadata.token_pack_id
|
|
24
|
-
|
|
24
|
+
// Extract token pack info from metadata (support both naming conventions)
|
|
25
|
+
const tokenPackId = (metadata.token_pack_id ||
|
|
26
|
+
metadata.tokenPackId);
|
|
27
|
+
const tokensAmount = parseInt((metadata.token_amount || metadata.tokens_amount || "0"), 10);
|
|
25
28
|
if (!tokenPackId || !tokensAmount) {
|
|
26
|
-
|
|
29
|
+
logger.debug("[AI Webhook] Missing token pack metadata. token_pack_id:", tokenPackId, "token_amount:", tokensAmount);
|
|
27
30
|
return Response.json({ error: "Missing token pack metadata" }, { status: 400 });
|
|
28
31
|
}
|
|
29
32
|
// Verify token pack exists
|
|
@@ -33,40 +36,48 @@ export async function POST(request) {
|
|
|
33
36
|
.eq("id", tokenPackId)
|
|
34
37
|
.single();
|
|
35
38
|
if (packError || !pack) {
|
|
36
|
-
|
|
39
|
+
logger.debug("[AI Webhook] Token pack not found:", tokenPackId);
|
|
37
40
|
return Response.json({ error: "Token pack not found" }, { status: 404 });
|
|
38
41
|
}
|
|
39
|
-
//
|
|
40
|
-
const
|
|
42
|
+
// Extract wallet metadata
|
|
43
|
+
const packPriceUsd = parseFloat((metadata.pack_price_usd || "0"));
|
|
44
|
+
const packCoef = parseFloat((metadata.pack_coef || "1.35"));
|
|
45
|
+
const packTokens = parseInt((metadata.pack_tokens || tokensAmount.toString()), 10);
|
|
46
|
+
const packName = (metadata.pack_name || pack.name);
|
|
47
|
+
// Calculate wallet USD values
|
|
48
|
+
const providerBudgetAdded = packPriceUsd / packCoef;
|
|
49
|
+
const sellValueAdded = packPriceUsd;
|
|
50
|
+
// Idempotency: use payment.id as ledger/wallet id
|
|
51
|
+
const userId = payment.user_id || payment.owner_id;
|
|
41
52
|
const meta = {
|
|
42
53
|
token_pack_id: tokenPackId,
|
|
43
|
-
token_pack_name:
|
|
54
|
+
token_pack_name: packName,
|
|
44
55
|
payment_id: payment.id,
|
|
45
56
|
provider_payment_id: payment.provider_payment_id,
|
|
46
57
|
amount_cents: payment.amount?.value_cents,
|
|
47
58
|
currency: payment.currency,
|
|
59
|
+
pack_tokens: packTokens,
|
|
48
60
|
};
|
|
49
61
|
try {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
meta,
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
console.warn("[AI Webhook] Upsert ledger warning:", upsertErr);
|
|
62
|
+
// Use RPC for atomic wallet + ledger update
|
|
63
|
+
logger.info(`[AI Webhook] Recording purchase via RPC: ${packTokens} tokens, $${packPriceUsd} (coef ${packCoef})`);
|
|
64
|
+
const { data: rpcResult, error: rpcError } = await supabase.rpc("record_token_purchase", {
|
|
65
|
+
p_user_id: userId,
|
|
66
|
+
p_amount: packTokens,
|
|
67
|
+
p_pack_coef: packCoef,
|
|
68
|
+
p_pack_price_usd: packPriceUsd,
|
|
69
|
+
p_provider_budget_added_usd: providerBudgetAdded,
|
|
70
|
+
p_sell_value_added_usd: sellValueAdded,
|
|
71
|
+
p_meta: meta,
|
|
72
|
+
});
|
|
73
|
+
if (rpcError) {
|
|
74
|
+
logger.error("[AI Webhook] RPC record_token_purchase failed:", rpcError);
|
|
75
|
+
return Response.json({ error: "Failed to record purchase" }, { status: 500 });
|
|
65
76
|
}
|
|
66
|
-
|
|
77
|
+
logger.info(`[AI Webhook] ✅ Credited ${packTokens} tokens + updated wallet for user ${userId} (payment ${payment.id})`);
|
|
67
78
|
}
|
|
68
79
|
catch (error) {
|
|
69
|
-
|
|
80
|
+
logger.error("[AI Webhook] Error recording purchase:", error);
|
|
70
81
|
return Response.json({ error: "Error adding tokens" }, { status: 500 });
|
|
71
82
|
}
|
|
72
83
|
// Create an order for this token purchase so the user can retrieve an invoice/receipt
|
|
@@ -97,7 +108,7 @@ export async function POST(request) {
|
|
|
97
108
|
.select()
|
|
98
109
|
.single();
|
|
99
110
|
if (orderErr) {
|
|
100
|
-
|
|
111
|
+
logger.warn("[AI Webhook] Could not create order for token purchase:", orderErr);
|
|
101
112
|
}
|
|
102
113
|
else if (order?.id) {
|
|
103
114
|
// Create a single order item representing the token pack
|
|
@@ -115,7 +126,7 @@ export async function POST(request) {
|
|
|
115
126
|
snapshot: { token_pack_id: tokenPackId, tokens: pack.tokens },
|
|
116
127
|
});
|
|
117
128
|
if (itemErr) {
|
|
118
|
-
|
|
129
|
+
logger.warn("[AI Webhook] Could not insert order item:", itemErr);
|
|
119
130
|
}
|
|
120
131
|
// Link payment to order for downstream queries
|
|
121
132
|
const { error: linkErr } = await supabase
|
|
@@ -124,10 +135,10 @@ export async function POST(request) {
|
|
|
124
135
|
.eq("id", payment.id)
|
|
125
136
|
.eq("owner_id", payment.owner_id);
|
|
126
137
|
if (linkErr) {
|
|
127
|
-
|
|
138
|
+
logger.warn("[AI Webhook] Could not link payment to order:", linkErr);
|
|
128
139
|
}
|
|
129
140
|
else {
|
|
130
|
-
|
|
141
|
+
logger.debug(`[AI Webhook] Created order ${order.id} for token purchase and linked payment`);
|
|
131
142
|
}
|
|
132
143
|
// Delete the dedicated token cart (and its items) after order creation
|
|
133
144
|
if (payment.cart_id) {
|
|
@@ -138,7 +149,7 @@ export async function POST(request) {
|
|
|
138
149
|
.eq("cart_id", payment.cart_id)
|
|
139
150
|
.eq("owner_id", payment.owner_id);
|
|
140
151
|
if (delItemsErr) {
|
|
141
|
-
|
|
152
|
+
logger.warn("[AI Webhook] Could not delete token cart items:", delItemsErr);
|
|
142
153
|
}
|
|
143
154
|
const { error: delCartErr } = await supabase
|
|
144
155
|
.from("carts")
|
|
@@ -146,26 +157,26 @@ export async function POST(request) {
|
|
|
146
157
|
.eq("id", payment.cart_id)
|
|
147
158
|
.eq("owner_id", payment.owner_id);
|
|
148
159
|
if (delCartErr) {
|
|
149
|
-
|
|
160
|
+
logger.warn("[AI Webhook] Could not delete token cart:", delCartErr);
|
|
150
161
|
}
|
|
151
162
|
else {
|
|
152
|
-
|
|
163
|
+
logger.debug(`[AI Webhook] Deleted token cart ${payment.cart_id}`);
|
|
153
164
|
}
|
|
154
165
|
}
|
|
155
166
|
catch (cartDeleteErr) {
|
|
156
|
-
|
|
167
|
+
logger.warn("[AI Webhook] Token cart deletion failed:", cartDeleteErr);
|
|
157
168
|
}
|
|
158
169
|
}
|
|
159
170
|
}
|
|
160
171
|
}
|
|
161
172
|
}
|
|
162
173
|
catch (orderCreateErr) {
|
|
163
|
-
|
|
174
|
+
logger.warn("[AI Webhook] Order creation for token purchase failed:", orderCreateErr);
|
|
164
175
|
}
|
|
165
176
|
return Response.json({ received: true, tokens_added: tokensAmount }, { status: 200 });
|
|
166
177
|
}
|
|
167
178
|
catch (error) {
|
|
168
|
-
|
|
179
|
+
logger.debug("[AI Webhook] Error:", error);
|
|
169
180
|
return Response.json({ error: error instanceof Error ? error.message : "Webhook error" }, { status: 400 });
|
|
170
181
|
}
|
|
171
182
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/ai/track-usage
|
|
3
|
+
* Edge function to track prompt usage after AI generation
|
|
4
|
+
*/
|
|
5
|
+
import { NextRequest, NextResponse } from "next/server";
|
|
6
|
+
export declare const runtime = "edge";
|
|
7
|
+
export declare function POST(request: NextRequest): Promise<NextResponse<{
|
|
8
|
+
success: boolean;
|
|
9
|
+
}> | NextResponse<{
|
|
10
|
+
error: any;
|
|
11
|
+
}>>;
|
|
12
|
+
//# sourceMappingURL=track-usage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"track-usage.d.ts","sourceRoot":"","sources":["../../src/api/track-usage.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD,eAAO,MAAM,OAAO,SAAS,CAAC;AAE9B,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IAkC9C"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /api/ai/track-usage
|
|
3
|
+
* Edge function to track prompt usage after AI generation
|
|
4
|
+
*/
|
|
5
|
+
import { NextResponse } from "next/server";
|
|
6
|
+
import { getSupabaseServiceClient } from "@lastbrain/core/server";
|
|
7
|
+
import { logger } from "@lastbrain/core";
|
|
8
|
+
export const runtime = "edge";
|
|
9
|
+
export async function POST(request) {
|
|
10
|
+
try {
|
|
11
|
+
const body = await request.json();
|
|
12
|
+
const { promptId } = body;
|
|
13
|
+
if (!promptId) {
|
|
14
|
+
return NextResponse.json({ error: "Missing promptId" }, { status: 400 });
|
|
15
|
+
}
|
|
16
|
+
const supabase = getSupabaseServiceClient();
|
|
17
|
+
// Get IP address
|
|
18
|
+
const ip = request.headers.get("x-forwarded-for") ||
|
|
19
|
+
request.headers.get("x-real-ip") ||
|
|
20
|
+
"unknown";
|
|
21
|
+
// Increment used count with IP tracking
|
|
22
|
+
const { error } = await supabase.rpc("increment_prompt_stat_with_ip", {
|
|
23
|
+
p_prompt_id: promptId,
|
|
24
|
+
p_stat_type: "used",
|
|
25
|
+
p_ip_address: ip,
|
|
26
|
+
});
|
|
27
|
+
if (error) {
|
|
28
|
+
logger.error("[track-usage] Error incrementing stat:", error);
|
|
29
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
30
|
+
}
|
|
31
|
+
return NextResponse.json({ success: true });
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
logger.error("[track-usage] POST unexpected error:", error);
|
|
35
|
+
return NextResponse.json({ error: error.message }, { status: 500 });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Doc.d.ts","sourceRoot":"","sources":["../../src/components/Doc.tsx"],"names":[],"mappings":"AAiBA;;;;;;GAMG;AACH,wBAAgB,GAAG,
|
|
1
|
+
{"version":3,"file":"Doc.d.ts","sourceRoot":"","sources":["../../src/components/Doc.tsx"],"names":[],"mappings":"AAiBA;;;;;;GAMG;AACH,wBAAgB,GAAG,4CAuTlB"}
|
package/dist/components/Doc.js
CHANGED
|
@@ -15,5 +15,5 @@ import { DocUsageCustom } from "./DocUsageCustom";
|
|
|
15
15
|
* pnpm update:module-docs
|
|
16
16
|
*/
|
|
17
17
|
export function Doc() {
|
|
18
|
-
return (_jsxs("div", { className: "container mx-auto p-6 space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-bold mb-2", children: "\uD83D\uDCE6 Module ai" }), _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "@lastbrain/module-ai" })] }) }), _jsx(CardBody, { children: _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400", children: "Package" }), _jsx("code", { className: "text-sm font-semibold", children: "@lastbrain/module-ai" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400", children: "Slug" }), _jsx("code", { className: "text-sm font-semibold", children: "module-ai" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400", children: "Type" }), _jsx("code", { className: "text-sm font-semibold", children: "Module LastBrain" })] })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(FileText, { size: 24 }), "Pages Disponibles"] }) }), _jsxs(CardBody, { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Pages Prot\u00E9g\u00E9es (Auth)" }), _jsx("div", { className: "space-y-2", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "GET" }), _jsx("code", { className: "text-sm", children: "/token" }), _jsx("span", { className: "text-sm text-slate-600 dark:text-slate-400", children: "- TokenPage" })] }) })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Pages Admin" }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Chip, { size: "sm", color: "secondary", variant: "flat", children: "GET" }), _jsx("code", { className: "text-sm", children: "/user-token" }), _jsx("span", { className: "text-sm text-slate-600 dark:text-slate-400", children: "- UserTokenPage" })] }), _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Chip, { size: "sm", color: "secondary", variant: "flat", children: "GET" }), _jsx("code", { className: "text-sm", children: "/token-packs" }), _jsx("span", { className: "text-sm text-slate-600 dark:text-slate-400", children: "- AdminTokenPacksPage" })] })] })] })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(Zap, { size: 24 }), "API Routes"] }) }), _jsxs(CardBody, { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: _jsx("code", { children: "/api/auth/user_token_ledger" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { size: "sm", color: "success", variant: "flat", children: "GET" }), _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "POST" }), _jsx(Chip, { size: "sm", color: "warning", variant: "flat", children: "PUT" }), _jsx(Chip, { size: "sm", color: "danger", variant: "flat", children: "DELETE" })] })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: _jsx("code", { children: "/api/auth/user_prompts" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { size: "sm", color: "success", variant: "flat", children: "GET" }), _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "POST" }), _jsx(Chip, { size: "sm", color: "warning", variant: "flat", children: "PUT" }), _jsx(Chip, { size: "sm", color: "danger", variant: "flat", children: "DELETE" })] })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: _jsx("code", { children: "/api/auth/token_packs" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { size: "sm", color: "success", variant: "flat", children: "GET" }), _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "POST" }), _jsx(Chip, { size: "sm", color: "warning", variant: "flat", children: "PUT" }), _jsx(Chip, { size: "sm", color: "danger", variant: "flat", children: "DELETE" })] })] })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(Database, { size: 24 }), "Base de Donn\u00E9es"] }) }), _jsxs(CardBody, { className: "space-y-6", children: [_jsx(TableStructure, { tableName: "user_token_ledger", title: "user_token_ledger", description: "Table user_token_ledger du module ai" }), _jsx(TableStructure, { tableName: "user_prompts", title: "user_prompts", description: "Table user_prompts du module ai" }), _jsx(TableStructure, { tableName: "token_packs", title: "token_packs", description: "Table token_packs du module ai" })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(Package, { size: 24 }), "Installation"] }) }), _jsxs(CardBody, { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Ajouter le module" }), _jsx(Snippet, { symbol: "", hideSymbol: true, className: "text-sm mb-2", children: "pnpm lastbrain add-module ai" }), _jsx(Snippet, { symbol: "", hideSymbol: true, className: "text-sm mb-2", children: "pnpm build:modules" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Appliquer les migrations" }), _jsx(Snippet, { symbol: "", hideSymbol: true, className: "text-sm mb-2", children: "cd apps/votre-app" }), _jsx(Snippet, { symbol: "", hideSymbol: true, className: "text-sm mb-2", children: "supabase migration up" })] })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(BookOpen, { size: 24 }), "Utilisation"] }) }), _jsx(CardBody, { className: "space-y-4", children: _jsx(DocUsageCustom, {}) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2 text-danger", children: [_jsx(AlertTriangle, { size: 24 }), "Danger Zone"] }) }), _jsxs(CardBody, { className: "space-y-4", children: [_jsxs(Alert, { color: "danger", className: "mb-4", children: [_jsx("p", { className: "text-sm font-semibold", children: "Cette action est irr\u00E9versible" }), _jsx("p", { className: "text-sm mt-2", children: "La suppression du module supprimera toutes les pages, routes API et migrations associ\u00E9es." })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Supprimer le module" }), _jsx(Snippet, { symbol: "", hideSymbol: true, color: "danger", className: "text-sm mb-2", children: "pnpm lastbrain remove-module ai" }), _jsx(Snippet, { symbol: "", hideSymbol: true, color: "danger", className: "text-sm mb-2", children: "pnpm build:modules" })] })] })] })] }));
|
|
18
|
+
return (_jsxs("div", { className: "container mx-auto p-6 space-y-6", children: [_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("div", { children: [_jsx("h1", { className: "text-3xl font-bold mb-2", children: "\uD83D\uDCE6 Module ai" }), _jsx("p", { className: "text-slate-600 dark:text-slate-400", children: "@lastbrain/module-ai" })] }) }), _jsx(CardBody, { children: _jsxs("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-4", children: [_jsxs("div", { children: [_jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400", children: "Package" }), _jsx("code", { className: "text-sm font-semibold", children: "@lastbrain/module-ai" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400", children: "Slug" }), _jsx("code", { className: "text-sm font-semibold", children: "module-ai" })] }), _jsxs("div", { children: [_jsx("p", { className: "text-sm text-slate-600 dark:text-slate-400", children: "Type" }), _jsx("code", { className: "text-sm font-semibold", children: "Module LastBrain" })] })] }) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(FileText, { size: 24 }), "Pages Disponibles"] }) }), _jsxs(CardBody, { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Pages Prot\u00E9g\u00E9es (Auth)" }), _jsx("div", { className: "space-y-2", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "GET" }), _jsx("code", { className: "text-sm", children: "/token" }), _jsx("span", { className: "text-sm text-slate-600 dark:text-slate-400", children: "- TokenPage" })] }) })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Pages Admin" }), _jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Chip, { size: "sm", color: "secondary", variant: "flat", children: "GET" }), _jsx("code", { className: "text-sm", children: "/user-token" }), _jsx("span", { className: "text-sm text-slate-600 dark:text-slate-400", children: "- UserTokenPage" })] }), _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(Chip, { size: "sm", color: "secondary", variant: "flat", children: "GET" }), _jsx("code", { className: "text-sm", children: "/token-packs" }), _jsx("span", { className: "text-sm text-slate-600 dark:text-slate-400", children: "- AdminTokenPacksPage" })] })] })] })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(Zap, { size: 24 }), "API Routes"] }) }), _jsxs(CardBody, { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: _jsx("code", { children: "/api/auth/user_token_ledger" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { size: "sm", color: "success", variant: "flat", children: "GET" }), _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "POST" }), _jsx(Chip, { size: "sm", color: "warning", variant: "flat", children: "PUT" }), _jsx(Chip, { size: "sm", color: "danger", variant: "flat", children: "DELETE" })] })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: _jsx("code", { children: "/api/auth/user_prompts" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { size: "sm", color: "success", variant: "flat", children: "GET" }), _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "POST" }), _jsx(Chip, { size: "sm", color: "warning", variant: "flat", children: "PUT" }), _jsx(Chip, { size: "sm", color: "danger", variant: "flat", children: "DELETE" })] })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: _jsx("code", { children: "/api/auth/token_packs" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { size: "sm", color: "success", variant: "flat", children: "GET" }), _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "POST" }), _jsx(Chip, { size: "sm", color: "warning", variant: "flat", children: "PUT" }), _jsx(Chip, { size: "sm", color: "danger", variant: "flat", children: "DELETE" })] })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: _jsx("code", { children: "/api/auth/user_token_quota_monthly" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { size: "sm", color: "success", variant: "flat", children: "GET" }), _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "POST" }), _jsx(Chip, { size: "sm", color: "warning", variant: "flat", children: "PUT" }), _jsx(Chip, { size: "sm", color: "danger", variant: "flat", children: "DELETE" })] })] }), _jsxs("div", { children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: _jsx("code", { children: "/api/auth/user_token_quota_ledger" }) }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Chip, { size: "sm", color: "success", variant: "flat", children: "GET" }), _jsx(Chip, { size: "sm", color: "primary", variant: "flat", children: "POST" }), _jsx(Chip, { size: "sm", color: "warning", variant: "flat", children: "PUT" }), _jsx(Chip, { size: "sm", color: "danger", variant: "flat", children: "DELETE" })] })] })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(Database, { size: 24 }), "Base de Donn\u00E9es"] }) }), _jsxs(CardBody, { className: "space-y-6", children: [_jsx(TableStructure, { tableName: "user_token_ledger", title: "user_token_ledger", description: "Table user_token_ledger du module ai" }), _jsx(TableStructure, { tableName: "user_prompts", title: "user_prompts", description: "Table user_prompts du module ai" }), _jsx(TableStructure, { tableName: "token_packs", title: "token_packs", description: "Table token_packs du module ai" }), _jsx(TableStructure, { tableName: "user_token_quota_monthly", title: "user_token_quota_monthly", description: "Table user_token_quota_monthly du module ai" }), _jsx(TableStructure, { tableName: "user_token_quota_ledger", title: "user_token_quota_ledger", description: "Table user_token_quota_ledger du module ai" })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(Package, { size: 24 }), "Installation"] }) }), _jsxs(CardBody, { className: "space-y-4", children: [_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Ajouter le module" }), _jsx(Snippet, { symbol: "", hideSymbol: true, className: "text-sm mb-2", children: "pnpm lastbrain add-module ai" }), _jsx(Snippet, { symbol: "", hideSymbol: true, className: "text-sm mb-2", children: "pnpm build:modules" })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Appliquer les migrations" }), _jsx(Snippet, { symbol: "", hideSymbol: true, className: "text-sm mb-2", children: "cd apps/votre-app" }), _jsx(Snippet, { symbol: "", hideSymbol: true, className: "text-sm mb-2", children: "supabase migration up" })] })] })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2", children: [_jsx(BookOpen, { size: 24 }), "Utilisation"] }) }), _jsx(CardBody, { className: "space-y-4", children: _jsx(DocUsageCustom, {}) })] }), _jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs("h2", { className: "text-2xl font-semibold flex items-center gap-2 text-danger", children: [_jsx(AlertTriangle, { size: 24 }), "Danger Zone"] }) }), _jsxs(CardBody, { className: "space-y-4", children: [_jsxs(Alert, { color: "danger", className: "mb-4", children: [_jsx("p", { className: "text-sm font-semibold", children: "Cette action est irr\u00E9versible" }), _jsx("p", { className: "text-sm mt-2", children: "La suppression du module supprimera toutes les pages, routes API et migrations associ\u00E9es." })] }), _jsxs("div", { className: "flex flex-col gap-2", children: [_jsx("h3", { className: "text-lg font-semibold mb-2", children: "Supprimer le module" }), _jsx(Snippet, { symbol: "", hideSymbol: true, color: "danger", className: "text-sm mb-2", children: "pnpm lastbrain remove-module ai" }), _jsx(Snippet, { symbol: "", hideSymbol: true, color: "danger", className: "text-sm mb-2", children: "pnpm build:modules" })] })] })] })] }));
|
|
19
19
|
}
|
|
@@ -22,11 +22,11 @@ export function MyComponent() {
|
|
|
22
22
|
model="gpt-4o-mini"
|
|
23
23
|
showTokenBalance={true}
|
|
24
24
|
onChange={(text, response) => {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
logger.log("Texte généré:", text);
|
|
26
|
+
logger.log("Tokens utilisés:", response?.tokensUsed);
|
|
27
27
|
}}
|
|
28
28
|
onError={(error) => {
|
|
29
|
-
|
|
29
|
+
logger.error("Erreur:", error);
|
|
30
30
|
}}
|
|
31
31
|
/>
|
|
32
32
|
);
|
|
@@ -42,11 +42,11 @@ export function MyComponent() {
|
|
|
42
42
|
quality="hd"
|
|
43
43
|
showTokenBalance={true}
|
|
44
44
|
onChange={(imageUrl, response) => {
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
logger.log("Image générée:", imageUrl);
|
|
46
|
+
logger.log("Tokens utilisés:", response?.tokensUsed);
|
|
47
47
|
}}
|
|
48
48
|
onError={(error) => {
|
|
49
|
-
|
|
49
|
+
logger.error("Erreur:", error);
|
|
50
50
|
}}
|
|
51
51
|
/>
|
|
52
52
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"UserTokenTab.d.ts","sourceRoot":"","sources":["../../../src/components/admin/UserTokenTab.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"UserTokenTab.d.ts","sourceRoot":"","sources":["../../../src/components/admin/UserTokenTab.tsx"],"names":[],"mappings":"AA2BA,UAAU,iBAAiB;IACzB,MAAM,EAAE,MAAM,CAAC;CAChB;AAkDD,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,iBAAiB,2CAw1BzD"}
|