diff --git a/.erb/configs/webpack.config.renderer.dev.dll.ts b/.erb/configs/webpack.config.renderer.dev.dll.ts index 4713e98ab..3650e7a69 100644 --- a/.erb/configs/webpack.config.renderer.dev.dll.ts +++ b/.erb/configs/webpack.config.renderer.dev.dll.ts @@ -14,6 +14,7 @@ checkNodeEnv('development') const EXCLUDE_MODULES = new Set([ '@modelcontextprotocol/sdk', // avoid `Package path . is not exported from package` error + 'mermaid', ]) const dist = webpackPaths.dllPath diff --git a/release/app/package-lock.json b/release/app/package-lock.json index 15041a169..409d8fe86 100644 --- a/release/app/package-lock.json +++ b/release/app/package-lock.json @@ -1,5 +1,4 @@ { - "name": "xyz.chatboxapp.ce", "version": "1.14.3", "lockfileVersion": 2, diff --git a/src/renderer/components/PopoverConfirm.tsx b/src/renderer/components/PopoverConfirm.tsx index 446d20916..ed5cf9c54 100644 --- a/src/renderer/components/PopoverConfirm.tsx +++ b/src/renderer/components/PopoverConfirm.tsx @@ -29,12 +29,14 @@ export const PopoverConfirm: FC = ({ // cloneElement 保证传递事件,不破坏原子元素的所有 CSS let target = children if (isValidElement(children)) { - target = cloneElement(children, { - onClick: (e) => { - if (children.props.onClick) children.props.onClick(e) - setOpened(true) + const elementWithOnClick = children as React.ReactElement<{ onClick?: (e: React.MouseEvent) => void }>; + + target = cloneElement(elementWithOnClick, { + onClick: (e: React.MouseEvent) => { + if (elementWithOnClick.props.onClick) elementWithOnClick.props.onClick(e); + setOpened(true); }, - }) + }); } else { // 不是 react element,警告 console.warn('Popconfirm 的 children 需要是一个 React 元素') diff --git a/src/renderer/components/SimpleSelect.tsx b/src/renderer/components/SimpleSelect.tsx index b81c50835..cd6457a67 100644 --- a/src/renderer/components/SimpleSelect.tsx +++ b/src/renderer/components/SimpleSelect.tsx @@ -3,9 +3,9 @@ import * as React from 'react' export interface Props { label: string | React.ReactNode - value: T + value: T | undefined options: { value: T; label: React.ReactNode; style?: React.CSSProperties }[] - onChange: (value: T) => void + onChange: (value: T | undefined) => void className?: string fullWidth?: boolean size?: 'small' | 'medium' diff --git a/src/renderer/packages/remote.ts b/src/renderer/packages/remote.ts index 696d69db2..9ce5fd435 100644 --- a/src/renderer/packages/remote.ts +++ b/src/renderer/packages/remote.ts @@ -12,6 +12,8 @@ import { import * as cache from './cache' import { getOS } from './navigator' import { afetch, uploadFile } from './request' +import { uniq } from 'lodash' +import platform from '../platform' // ========== API ORIGIN 根据可用性维护 ========== @@ -44,17 +46,21 @@ async function testApiOrigins() { const origin: string = pool[i] const controller = new AbortController() setTimeout(() => controller.abort(), 2000) // 2秒超时 - const res = await ofetch<{ data: { api_origins: string[] } }>(`${origin}/api/api_origins`, { + const res = await afetch(`${origin}/api/api_origins`, { signal: controller.signal, + }, { retry: 1, }) + const json = await res.json() // 如果服务器返回了新的 API 域名,则更新缓存 - if (res.data.api_origins.length > 0) { - pool = uniq([...pool, ...res.data.api_origins]) + if (json.data.api_origins.length > 0) { + pool = uniq([...pool, ...json.data.api_origins]) } // 如果当前 API 可用,则切换所有流量到该域名 API_ORIGIN = origin - pool = uniq([origin, ...pool]) // 将当前 API 域名添加到列表顶部 + if (pool) { // Add null check for pool + pool = uniq([origin, ...pool]) // 将当前 API 域名添加到列表顶部 + } await cache.store.setItem('api_origins', pool) return } catch (e) { @@ -81,8 +87,8 @@ export async function checkNeedUpdate(version: string, os: string, config: Confi type Response = { need_update?: boolean } - // const res = await ofetch(`${RELEASE_ORIGIN}/chatbox_need_update/${version}`, { - const res = await ofetch(`${API_ORIGIN}/chatbox_need_update/${version}`, { + // const res = await afetch(`${RELEASE_ORIGIN}/chatbox_need_update/${version}`, { + const res = await afetch(`${API_ORIGIN}/chatbox_need_update/${version}`, { method: 'POST', retry: 3, body: { @@ -98,8 +104,8 @@ export async function checkNeedUpdate(version: string, os: string, config: Confi // type Response = { // data: null | SponsorAd // } -// // const res = await ofetch(`${RELEASE_ORIGIN}/sponsor_ad`, { -// const res = await ofetch(`${API_ORIGIN}/sponsor_ad`, { +// // const res = await afetch(`${RELEASE_ORIGIN}/sponsor_ad`, { +// const res = await afetch(`${API_ORIGIN}/sponsor_ad`, { // retry: 3, // }) // return res['data'] || null @@ -109,56 +115,64 @@ export async function checkNeedUpdate(version: string, os: string, config: Confi // type Response = { // data: SponsorAboutBanner[] // } -// // const res = await ofetch(`${RELEASE_ORIGIN}/sponsor_about_banner`, { -// const res = await ofetch(`${API_ORIGIN}/sponsor_ad`, { +// // const res = await afetch(`${RELEASE_ORIGIN}/sponsor_about_banner`, { +// const res = await afetch(`${API_ORIGIN}/sponsor_ad`, { // retry: 3, // }) // return res['data'] || [] // } export async function listCopilots(lang: string) { - type Response = { + type CopilotListResponse = { data: CopilotDetail[] } - const res = await ofetch(`${API_ORIGIN}/api/copilots/list`, { + const res = await afetch(`${API_ORIGIN}/api/copilots/list`, { method: 'POST', + body: JSON.stringify({ lang }), + }, { retry: 3, - body: { lang }, }) - return res['data'] + const json: CopilotListResponse = await res.json() + return json['data'] } export async function recordCopilotShare(detail: CopilotDetail) { - await ofetch(`${API_ORIGIN}/api/copilots/share-record`, { + await afetch(`${API_ORIGIN}/api/copilots/share-record`, { method: 'POST', - body: { - detail: detail, - }, + body: JSON.stringify({ detail }), + }, { + retry: 3, }) } export async function getPremiumPrice() { - type Response = { + type PremiumPriceResponse = { data: { price: number discount: number discountLabel: string } } - const res = await ofetch(`${API_ORIGIN}/api/premium/price`, { + const res = await afetch(`${API_ORIGIN}/api/premium/price`, { + method: 'GET', + }, { retry: 3, }) - return res['data'] + const json: PremiumPriceResponse = await res.json() + return json['data'] } export async function getRemoteConfig(config: keyof RemoteConfig) { - type Response = { + type RemoteConfigResponse = { data: Pick } - const res = await ofetch(`${API_ORIGIN}/api/remote_config/${config}`, { + const res = await afetch(`${API_ORIGIN}/api/remote_config/${config}`, { + method: 'GET', + }, { retry: 3, }) - return res['data'] + const json: RemoteConfigResponse = await res.json() + return json['data'] } export interface DialogConfig { @@ -167,41 +181,49 @@ export interface DialogConfig { } export async function getDialogConfig(params: { uuid: string; language: string; version: string }) { - type Response = { + type DialogConfigResponse = { data: null | DialogConfig } - const res = await ofetch(`${API_ORIGIN}/api/dialog_config`, { + const res = await afetch(`${API_ORIGIN}/api/dialog_config`, { method: 'POST', + body: JSON.stringify(params), + }, { retry: 3, - body: params, }) - return res['data'] || null + const json: DialogConfigResponse = await res.json() + return json['data'] || null } export async function getLicenseDetail(params: { licenseKey: string }) { - type Response = { + type LicenseDetailResponse = { data: ChatboxAILicenseDetail | null } - const res = await ofetch(`${API_ORIGIN}/api/license/detail`, { - retry: 3, + const res = await afetch(`${API_ORIGIN}/api/license/detail`, { + method: 'GET', headers: { Authorization: params.licenseKey, }, + }, { + retry: 3, }) - return res['data'] || null + const json: LicenseDetailResponse = await res.json() + return json['data'] || null } export async function getLicenseDetailRealtime(params: { licenseKey: string }) { - type Response = { + type LicenseDetailRealtimeResponse = { data: ChatboxAILicenseDetail | null } - const res = await ofetch(`${API_ORIGIN}/api/license/detail/realtime`, { - retry: 5, + const res = await afetch(`${API_ORIGIN}/api/license/detail/realtime`, { + method: 'GET', headers: { Authorization: params.licenseKey, }, + }, { + retry: 5, }) - return res['data'] || null + const json: LicenseDetailRealtimeResponse = await res.json() + return json['data'] || null } export async function generateUploadUrl(params: { licenseKey: string; filename: string }) { @@ -521,4 +543,4 @@ export async function reportContent(params: { id: string; type: string; details: }, body: JSON.stringify(params), }) -} +} \ No newline at end of file diff --git a/src/types/global.d.ts b/src/types/global.d.ts new file mode 100644 index 000000000..9c099da24 --- /dev/null +++ b/src/types/global.d.ts @@ -0,0 +1,2 @@ +declare module 'lucide-react'; +declare module 'mermaid'; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index a1e6cf76f..74b81f181 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "incremental": true, "target": "es2021", "module": "commonjs", - "lib": ["dom", "es2021"], + "lib": ["dom", "es2023"], "jsx": "react-jsx", "strict": true, "sourceMap": true,