feat: sync deployed v1.0.0-rc.38-custom.42

Sync production source including routing, billing, Astra detection and public uptime. Update custom build instructions and license packaging.
This commit is contained in:
cneicy committed 2026-09-26 04:49:11 +08:00
1 parent aa6c3f50f4
commit ceddfd3d6b
828 files changed
+122253 -13702

No files matched your search

@@ -0,0 +1,80 @@
/*
Copyright (C) 2023-2026 QuantumNous
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
For commercial licensing, please contact support@quantumnous.com
*/
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ConfirmDialog } from '@/components/confirm-dialog'
import { getUserProfile, updateUserSettings } from '@/features/profile/api'
import { parseUserSettings } from '@/features/profile/lib/format'
import { handleServerError } from '@/lib/handle-server-error'
import { requireServerSuccess } from '@/lib/server-error-message'
import { useAuthStore } from '@/stores/auth-store'
import { getApiKeys } from '../api'
export function AstraCostNotice() {
const { t } = useTranslation()
const userId = useAuthStore((state) => state.auth.user?.id)
const queryClient = useQueryClient()
const [dismissedUserId, setDismissedUserId] = useState<number>()
const noticeKey = ['astra-cost-notice', userId]
const { data: profile } = useQuery({
queryKey: noticeKey,
queryFn: async () => requireServerSuccess(await getUserProfile()).data,
enabled: userId !== undefined,
})
const { data: hasMigratedToken } = useQuery({
queryKey: ['astra-cost-notice-tokens', userId],
queryFn: async () => {
let page = 1
for (;;) {
const result = await getApiKeys({ p: page, size: 100 })
if (!result.success || !result.data) {
throw new Error(result.message || t('Failed to load API keys'))
}
if (result.data.items.some((token) => token.astra_auto_switch === true)) {
return true
}
if (page * result.data.page_size >= result.data.total) return false
page += 1
}
},
enabled: userId !== undefined,
})
const acknowledge = useMutation({
mutationFn: async () => requireServerSuccess(await updateUserSettings({ astra_cost_notice_ack: true })),
onSuccess: () => {
setDismissedUserId(userId)
void queryClient.invalidateQueries({ queryKey: noticeKey })
},
onError: (error) => handleServerError(error, t('Failed to update settings')),
})
return (
<ConfirmDialog
open={!!profile && hasMigratedToken === true && !parseUserSettings(profile.setting).astra_cost_notice_ack && dismissedUserId !== userId}
onOpenChange={(value) => { if (!value && !acknowledge.isPending) setDismissedUserId(userId) }}
title={t('Astra auto-switch and charges')}
desc={t('Existing API keys keep Astra auto-switch enabled; new keys default to off. Rejected results still incur usage charges, and every additional upstream attempt is charged separately. You can change this setting for each API key.')}
cancelBtnText={t('Remind me next time')}
confirmText={t('I understand')}
isLoading={acknowledge.isPending}
handleConfirm={() => acknowledge.mutate()}
/>
)
}