From 57d0f9794fb8b0f34693f218db7a41e66486fb01 Mon Sep 17 00:00:00 2001 From: IanShaw027 Date: Fri, 10 Apr 2026 00:53:03 +0800 Subject: [PATCH 01/34] =?UTF-8?q?fix(frontend):=20=E8=A1=A5=E5=85=A8=20mes?= =?UTF-8?q?sages=20=E8=B0=83=E5=BA=A6=E5=9B=BD=E9=99=85=E5=8C=96=E6=96=87?= =?UTF-8?q?=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/i18n/locales/en.ts | 20 +++++++++++++++++--- frontend/src/i18n/locales/zh.ts | 20 +++++++++++++++++--- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index d3b16d4ad6..2d5a4b00ae 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -1648,9 +1648,23 @@ export default { title: 'OpenAI Messages Dispatch', allowDispatch: 'Allow /v1/messages dispatch', allowDispatchHint: 'When enabled, API keys in this OpenAI group can dispatch requests through /v1/messages endpoint', - defaultModel: 'Default mapped model', - defaultModelPlaceholder: 'e.g., gpt-4.1', - defaultModelHint: 'When account has no model mapping configured, all request models will be mapped to this model' + familyMappingTitle: 'Family Default Mapping', + familyMappingHint: 'Requests that match the Opus, Sonnet, or Haiku families will prefer the target model configured here.', + opusModel: 'Opus Target Model', + opusModelPlaceholder: 'e.g., gpt-5.4', + sonnetModel: 'Sonnet Target Model', + sonnetModelPlaceholder: 'e.g., gpt-5.3-codex', + haikuModel: 'Haiku Target Model', + haikuModelPlaceholder: 'e.g., gpt-5.4-mini', + exactMappingTitle: 'Exact Model Overrides', + exactMappingHint: 'Exact Claude model overrides take priority over the family defaults and can route a specific Claude model to a different target model.', + noExactMappings: 'No exact model overrides yet', + addExactMapping: 'Add Exact Mapping', + claudeModel: 'Claude Model', + claudeModelPlaceholder: 'e.g., claude-sonnet-4-5-20250929', + targetModel: 'Target Model', + targetModelPlaceholder: 'e.g., gpt-5.4', + removeExactMapping: 'Remove Exact Mapping' }, invalidRequestFallback: { title: 'Invalid Request Fallback Group', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index fcaaf5abd2..0ff2eea3e0 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -1735,9 +1735,23 @@ export default { title: 'OpenAI Messages 调度配置', allowDispatch: '允许 /v1/messages 调度', allowDispatchHint: '启用后,此 OpenAI 分组的 API Key 可以通过 /v1/messages 端点调度请求', - defaultModel: '默认映射模型', - defaultModelPlaceholder: '例如: gpt-4.1', - defaultModelHint: '当账号未配置模型映射时,所有请求模型将映射到此模型' + familyMappingTitle: '系列默认映射', + familyMappingHint: '当请求命中 Opus、Sonnet、Haiku 系列时,会优先使用这里配置的目标模型。', + opusModel: 'Opus 映射模型', + opusModelPlaceholder: '例如: gpt-5.4', + sonnetModel: 'Sonnet 映射模型', + sonnetModelPlaceholder: '例如: gpt-5.3-codex', + haikuModel: 'Haiku 映射模型', + haikuModelPlaceholder: '例如: gpt-5.4-mini', + exactMappingTitle: '精确模型覆盖', + exactMappingHint: '精确 Claude 模型覆盖优先级高于系列默认映射,可将某个具体 Claude 模型单独映射到不同的目标模型。', + noExactMappings: '暂无精确模型覆盖规则', + addExactMapping: '添加精确映射', + claudeModel: 'Claude 模型', + claudeModelPlaceholder: '例如: claude-sonnet-4-5-20250929', + targetModel: '目标模型', + targetModelPlaceholder: '例如: gpt-5.4', + removeExactMapping: '删除精确映射' }, invalidRequestFallback: { title: '无效请求兜底分组', From 07d2add67447e9a45f283914b2d316192abe1ff1 Mon Sep 17 00:00:00 2001 From: qingyuzhang Date: Fri, 10 Apr 2026 05:16:20 +0800 Subject: [PATCH 02/34] fix(sidebar): smooth collapse transitions --- frontend/src/components/layout/AppSidebar.vue | 168 ++++++++++++++---- frontend/src/style.css | 10 +- 2 files changed, 138 insertions(+), 40 deletions(-) diff --git a/frontend/src/components/layout/AppSidebar.vue b/frontend/src/components/layout/AppSidebar.vue index 09b83f6f25..6fe050b410 100644 --- a/frontend/src/components/layout/AppSidebar.vue +++ b/frontend/src/components/layout/AppSidebar.vue @@ -7,20 +7,18 @@ ]" > - @@ -659,14 +650,113 @@ onMounted(() => { diff --git a/frontend/src/views/user/StripePopupView.vue b/frontend/src/views/user/StripePopupView.vue index c06c2ac511..368e6c529c 100644 --- a/frontend/src/views/user/StripePopupView.vue +++ b/frontend/src/views/user/StripePopupView.vue @@ -56,6 +56,11 @@ import { computed, ref, onMounted, onUnmounted } from 'vue' import { useI18n } from 'vue-i18n' import { useRoute } from 'vue-router' +import { extractApiErrorMessage } from '@/utils/apiError' + +interface StripeWithWechatPay { + confirmWechatPayPayment(clientSecret: string, options: Record): Promise<{ error?: { message?: string }; paymentIntent?: { status: string } }> +} const METHOD_COLORS: Record = { alipay: '#00AEEF', @@ -123,7 +128,7 @@ async function initStripe(clientSecret: string, publishableKey: string) { } else if (method === 'wechat_pay') { // WeChat: Stripe shows its built-in QR dialog, user scans, promise resolves hint.value = t('payment.stripePopup.loadingQr') - const result = await (stripe as any).confirmWechatPayPayment(clientSecret, { + const result = await (stripe as unknown as StripeWithWechatPay).confirmWechatPayPayment(clientSecret, { payment_method_options: { wechat_pay: { client: 'web' } }, }) if (result.error) { @@ -137,7 +142,7 @@ async function initStripe(clientSecret: string, publishableKey: string) { } } } catch (err: unknown) { - error.value = err instanceof Error ? err.message : t('payment.stripeLoadFailed') + error.value = extractApiErrorMessage(err, t('payment.stripeLoadFailed')) } } diff --git a/frontend/src/views/user/SubscriptionsView.vue b/frontend/src/views/user/SubscriptionsView.vue index 17d5baa0b9..154682b77a 100644 --- a/frontend/src/views/user/SubscriptionsView.vue +++ b/frontend/src/views/user/SubscriptionsView.vue @@ -313,10 +313,10 @@ function formatExpirationDate(expiresAt: string): string { const dateStr = formatDateOnly(expires) if (days === 0) { - return `${dateStr} (Today)` + return `${dateStr} (${t('common.today')})` } if (days === 1) { - return `${dateStr} (Tomorrow)` + return `${dateStr} (${t('common.tomorrow')})` } return t('userSubscriptions.daysRemaining', { days }) + ` (${dateStr})` From 75155903248324ec454ba66ee359bf654628dc08 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 00:44:54 +0800 Subject: [PATCH 07/34] feat(payment): add H5/mobile payment support Backend: - Parse EasyPay `payurl2` field, prefer H5 link on mobile - Add `device=mobile` to EasyPay submit.php (popup) mode - Expand isMobile detection keywords (add ipad/ipod) Frontend: - Add `isMobileDevice()` utility (userAgentData + UA regex) - Mobile + pay_url: direct redirect instead of QR/popup - Popup blocked fallback: auto-redirect when window.open fails - Stripe WeChat Pay: dynamic client param (mobile_web vs web) --- backend/internal/handler/payment_handler.go | 7 ++++++- backend/internal/payment/provider/easypay.go | 10 +++++++++- frontend/src/utils/device.ts | 11 +++++++++++ frontend/src/views/user/PaymentView.vue | 17 ++++++++++++++++- frontend/src/views/user/StripePaymentView.vue | 3 ++- frontend/src/views/user/StripePopupView.vue | 3 ++- 6 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 frontend/src/utils/device.ts diff --git a/backend/internal/handler/payment_handler.go b/backend/internal/handler/payment_handler.go index e0563a4285..0425fc49c7 100644 --- a/backend/internal/handler/payment_handler.go +++ b/backend/internal/handler/payment_handler.go @@ -412,5 +412,10 @@ func requireAuth(c *gin.Context) (middleware2.AuthSubject, bool) { // isMobile detects mobile user agents. func isMobile(c *gin.Context) bool { ua := strings.ToLower(c.GetHeader("User-Agent")) - return strings.Contains(ua, "mobile") || strings.Contains(ua, "android") || strings.Contains(ua, "iphone") + for _, kw := range []string{"mobile", "android", "iphone", "ipad", "ipod"} { + if strings.Contains(ua, kw) { + return true + } + } + return false } diff --git a/backend/internal/payment/provider/easypay.go b/backend/internal/payment/provider/easypay.go index 814e7c4f30..e33a567d03 100644 --- a/backend/internal/payment/provider/easypay.go +++ b/backend/internal/payment/provider/easypay.go @@ -83,6 +83,9 @@ func (e *EasyPay) createRedirectPayment(req payment.CreatePaymentRequest) (*paym if cid := e.resolveCID(req.PaymentType); cid != "" { params["cid"] = cid } + if req.IsMobile { + params["device"] = deviceMobile + } params["sign"] = easyPaySign(params, e.config["pkey"]) params["sign_type"] = signTypeMD5 @@ -122,6 +125,7 @@ func (e *EasyPay) createAPIPayment(ctx context.Context, req payment.CreatePaymen Msg string `json:"msg"` TradeNo string `json:"trade_no"` PayURL string `json:"payurl"` + PayURL2 string `json:"payurl2"` // H5 mobile payment URL QRCode string `json:"qrcode"` } if err := json.Unmarshal(body, &resp); err != nil { @@ -130,7 +134,11 @@ func (e *EasyPay) createAPIPayment(ctx context.Context, req payment.CreatePaymen if resp.Code != easypayCodeSuccess { return nil, fmt.Errorf("easypay error: %s", resp.Msg) } - return &payment.CreatePaymentResponse{TradeNo: resp.TradeNo, PayURL: resp.PayURL, QRCode: resp.QRCode}, nil + payURL := resp.PayURL + if req.IsMobile && resp.PayURL2 != "" { + payURL = resp.PayURL2 + } + return &payment.CreatePaymentResponse{TradeNo: resp.TradeNo, PayURL: payURL, QRCode: resp.QRCode}, nil } // resolveURLs returns (notifyURL, returnURL) preferring request values, diff --git a/frontend/src/utils/device.ts b/frontend/src/utils/device.ts new file mode 100644 index 0000000000..098bd90a3b --- /dev/null +++ b/frontend/src/utils/device.ts @@ -0,0 +1,11 @@ +/** + * Detect whether the current device is mobile. + * Uses navigator.userAgentData (modern API) with UA regex fallback. + */ +export function isMobileDevice(): boolean { + const nav = navigator as unknown as Record + if (nav.userAgentData && typeof (nav.userAgentData as Record).mobile === 'boolean') { + return (nav.userAgentData as Record).mobile as boolean + } + return /Android|iPhone|iPad|iPod|Mobile/i.test(navigator.userAgent) +} diff --git a/frontend/src/views/user/PaymentView.vue b/frontend/src/views/user/PaymentView.vue index 055e42f2c3..411798dbaa 100644 --- a/frontend/src/views/user/PaymentView.vue +++ b/frontend/src/views/user/PaymentView.vue @@ -263,6 +263,7 @@ import { useSubscriptionStore } from '@/stores/subscriptions' import { useAppStore } from '@/stores' import { paymentAPI } from '@/api/payment' import { extractApiErrorMessage } from '@/utils/apiError' +import { isMobileDevice } from '@/utils/device' import type { SubscriptionPlan, CheckoutInfoResponse } from '@/types/payment' import AppLayout from '@/components/layout/AppLayout.vue' import AmountInput from '@/components/payment/AmountInput.vue' @@ -528,7 +529,10 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb plan_id: planId, }) const openWindow = (url: string) => { - window.open(url, 'paymentPopup', POPUP_WINDOW_FEATURES) + const win = window.open(url, 'paymentPopup', POPUP_WINDOW_FEATURES) + if (!win || win.closed) { + window.location.href = url + } } if (result.client_secret) { // Stripe: show Payment Element inline (user picks method → confirms → redirect if needed) @@ -539,6 +543,17 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb orderType, } paymentPhase.value = 'stripe' + } else if (isMobileDevice() && result.pay_url) { + // Mobile + pay_url: redirect directly instead of QR/popup (mobile browsers block popups) + paymentState.value = { + orderId: result.order_id, qrCode: '', expiresAt: result.expires_at || '', + paymentType: selectedMethod.value, payUrl: result.pay_url, + clientSecret: '', payAmount: 0, + orderType, + } + paymentPhase.value = 'paying' + window.location.href = result.pay_url + return } else if (result.qr_code) { // QR mode: show QR code inline paymentState.value = { diff --git a/frontend/src/views/user/StripePaymentView.vue b/frontend/src/views/user/StripePaymentView.vue index 6fc810c63d..20a4a40837 100644 --- a/frontend/src/views/user/StripePaymentView.vue +++ b/frontend/src/views/user/StripePaymentView.vue @@ -100,6 +100,7 @@ import { useRoute, useRouter } from 'vue-router' import { usePaymentStore } from '@/stores/payment' import { paymentAPI } from '@/api/payment' import { extractApiErrorMessage } from '@/utils/apiError' +import { isMobileDevice } from '@/utils/device' import type { PaymentOrder } from '@/types/payment' import type { Stripe, StripeElements } from '@stripe/stripe-js' import AppLayout from '@/components/layout/AppLayout.vue' @@ -191,7 +192,7 @@ async function confirmWechatPay(stripe: Stripe, clientSecret: string) { const { paymentIntent, error } = await (stripe as Stripe & { confirmWechatPayPayment: (cs: string, opts: Record) => Promise<{ paymentIntent?: { status: string; next_action?: { wechat_pay_display_qr_code?: { image_data_url?: string } } }; error?: { message?: string } }> }).confirmWechatPayPayment(clientSecret, { - payment_method_options: { wechat_pay: { client: 'web' } }, + payment_method_options: { wechat_pay: { client: isMobileDevice() ? 'mobile_web' : 'web' } }, }) if (error) { diff --git a/frontend/src/views/user/StripePopupView.vue b/frontend/src/views/user/StripePopupView.vue index 368e6c529c..2704c62db1 100644 --- a/frontend/src/views/user/StripePopupView.vue +++ b/frontend/src/views/user/StripePopupView.vue @@ -57,6 +57,7 @@ import { computed, ref, onMounted, onUnmounted } from 'vue' import { useI18n } from 'vue-i18n' import { useRoute } from 'vue-router' import { extractApiErrorMessage } from '@/utils/apiError' +import { isMobileDevice } from '@/utils/device' interface StripeWithWechatPay { confirmWechatPayPayment(clientSecret: string, options: Record): Promise<{ error?: { message?: string }; paymentIntent?: { status: string } }> @@ -129,7 +130,7 @@ async function initStripe(clientSecret: string, publishableKey: string) { // WeChat: Stripe shows its built-in QR dialog, user scans, promise resolves hint.value = t('payment.stripePopup.loadingQr') const result = await (stripe as unknown as StripeWithWechatPay).confirmWechatPayPayment(clientSecret, { - payment_method_options: { wechat_pay: { client: 'web' } }, + payment_method_options: { wechat_pay: { client: isMobileDevice() ? 'mobile_web' : 'web' } }, }) if (result.error) { error.value = result.error.message || t('payment.result.failed') From a020fc52c94ba65200f7f25d7b91b6cac3f09c17 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 16:30:34 +0800 Subject: [PATCH 08/34] fix(payment): pass expires_at for Stripe countdown timer Stripe payment path was setting expiresAt to empty string, causing PaymentStatusPanel to fall back to hardcoded 30-minute default when the popup redirect switches to the waiting view. --- frontend/src/views/user/PaymentView.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/user/PaymentView.vue b/frontend/src/views/user/PaymentView.vue index 411798dbaa..5a95809759 100644 --- a/frontend/src/views/user/PaymentView.vue +++ b/frontend/src/views/user/PaymentView.vue @@ -537,7 +537,7 @@ async function createOrder(orderAmount: number, orderType: string, planId?: numb if (result.client_secret) { // Stripe: show Payment Element inline (user picks method → confirms → redirect if needed) paymentState.value = { - orderId: result.order_id, qrCode: '', expiresAt: '', + orderId: result.order_id, qrCode: '', expiresAt: result.expires_at || '', paymentType: selectedMethod.value, payUrl: '', clientSecret: result.client_secret, payAmount: result.pay_amount, orderType, From 217b7ea68c4415676d8785f72f84c78b933b5811 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 16:46:26 +0800 Subject: [PATCH 09/34] fix(deps): upgrade axios to 1.15.0 to fix GHSA-fvcv-3m26-pcqx --- frontend/package.json | 2 +- frontend/pnpm-lock.yaml | 1015 +++++++++++++++++++++------------------ 2 files changed, 539 insertions(+), 478 deletions(-) diff --git a/frontend/package.json b/frontend/package.json index 14efbfdb8e..a220d3a7fd 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -19,7 +19,7 @@ "@stripe/stripe-js": "^9.0.1", "@tanstack/vue-virtual": "^3.13.23", "@vueuse/core": "^10.7.0", - "axios": "^1.13.5", + "axios": "^1.15.0", "chart.js": "^4.4.1", "dompurify": "^3.3.1", "driver.js": "^1.4.0", diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index 9698352b52..0a7b3fa1cb 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -21,8 +21,8 @@ importers: specifier: ^10.7.0 version: 10.11.1(vue@3.5.26(typescript@5.6.3)) axios: - specifier: ^1.13.5 - version: 1.13.5 + specifier: ^1.15.0 + version: 1.15.0 chart.js: specifier: ^4.4.1 version: 4.5.1 @@ -137,11 +137,11 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} - '@ant-design/colors@8.0.0': - resolution: {integrity: sha512-6YzkKCw30EI/E9kHOIXsQDHmMvTllT8STzjMb4K2qzit33RW2pqCJP0sk+hidBntXxE+Vz4n1+RvCTfBw6OErw==} + '@ant-design/colors@8.0.1': + resolution: {integrity: sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ==} - '@ant-design/cssinjs-utils@2.0.2': - resolution: {integrity: sha512-Mq3Hm6fJuQeFNKSp3+yT4bjuhVbdrsyXE2RyfpJFL0xiYNZdaJ6oFaE3zFrzmHbmvTd2Wp3HCbRtkD4fU+v2ZA==} + '@ant-design/cssinjs-utils@2.1.2': + resolution: {integrity: sha512-5fTHQ158jJJ5dC/ECeyIdZUzKxE/mpEMRZxthyG1sw/AKRHKgJBg00Yi6ACVXgycdje7KahRNvNET/uBccwCnA==} peerDependencies: react: '>=18' react-dom: '>=18' @@ -152,15 +152,21 @@ packages: react: '>=16.0.0' react-dom: '>=16.0.0' - '@ant-design/fast-color@3.0.0': - resolution: {integrity: sha512-eqvpP7xEDm2S7dUzl5srEQCBTXZMmY3ekf97zI+M2DHOYyKdJGH0qua0JACHTqbkRnD/KHFQP9J1uMJ/XWVzzA==} + '@ant-design/cssinjs@2.1.2': + resolution: {integrity: sha512-2Hy8BnCEH31xPeSLbhhB2ctCPXE2ZnASdi+KbSeS79BNbUhL9hAEe20SkUk+BR8aKTmqb6+FKFruk7w8z0VoRQ==} + peerDependencies: + react: '>=16.0.0' + react-dom: '>=16.0.0' + + '@ant-design/fast-color@3.0.1': + resolution: {integrity: sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw==} engines: {node: '>=8.x'} '@ant-design/icons-svg@4.4.2': resolution: {integrity: sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA==} - '@ant-design/icons@6.1.0': - resolution: {integrity: sha512-KrWMu1fIg3w/1F2zfn+JlfNDU8dDqILfA5Tg85iqs1lf8ooyGlbkA+TkwfOKKgqpUmAiRY1PTFpuOU2DAIgSUg==} + '@ant-design/icons@6.1.1': + resolution: {integrity: sha512-AMT4N2y++TZETNHiM77fs4a0uPVCJGuL5MTonk13Pvv7UN7sID1cNEZOc1qNqx6zLKAOilTEFAdAoAFKa0U//Q==} engines: {node: '>=8'} peerDependencies: react: '>=16.0.0' @@ -211,6 +217,10 @@ packages: resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} + engines: {node: '>=6.9.0'} + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} @@ -223,8 +233,8 @@ packages: resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} - '@base-ui/react@1.0.0': - resolution: {integrity: sha512-4USBWz++DUSLTuIYpbYkSgy1F9ZmNG9S/lXvlUN6qMK0P0RlW+6eQmDUB4DgZ7HVvtXl4pvi4z5J2fv6Z3+9hg==} + '@base-ui/react@1.3.0': + resolution: {integrity: sha512-FwpKqZbPz14AITp1CVgf4AjhKPe1OeeVKSBMdgD10zbFlj3QSWelmtCMLi2+/PFZZcIm3l87G7rwtCZJwHyXWA==} engines: {node: '>=14.0.0'} peerDependencies: '@types/react': ^17 || ^18 || ^19 @@ -234,8 +244,8 @@ packages: '@types/react': optional: true - '@base-ui/utils@0.2.3': - resolution: {integrity: sha512-/CguQ2PDaOzeVOkllQR8nocJ0FFIDqsWIcURsVmm53QGo8NhFNpePjNlyPIB41luxfOqnG7PU0xicMEw3ls7XQ==} + '@base-ui/utils@0.2.6': + resolution: {integrity: sha512-yQ+qeuqohwhsNpoYDqqXaLllYAkPCP4vYdDrVo8FQXaAPfHWm1pG/Vm+jmGTA5JFS0BAIjookyapuJFY8F9PIw==} peerDependencies: '@types/react': ^17 || ^18 || ^19 react: ^17 || ^18 || ^19 @@ -247,23 +257,23 @@ packages: '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - '@braintree/sanitize-url@7.1.1': - resolution: {integrity: sha512-i1L7noDNxtFyL5DmZafWy1wRVhGehQmzZaz1HiN5e7iylJMSZR7ekOV7NsIqa5qBldlLrsKv4HbgFUVlQrz8Mw==} + '@braintree/sanitize-url@7.1.2': + resolution: {integrity: sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==} - '@chevrotain/cst-dts-gen@11.0.3': - resolution: {integrity: sha512-BvIKpRLeS/8UbfxXxgC33xOumsacaeCKAjAeLyOn7Pcp95HiRbrpl14S+9vaZLolnbssPIUuiUd8IvgkRyt6NQ==} + '@chevrotain/cst-dts-gen@12.0.0': + resolution: {integrity: sha512-fSL4KXjTl7cDgf0B5Rip9Q05BOrYvkJV/RrBTE/bKDN096E4hN/ySpcBK5B24T76dlQ2i32Zc3PAE27jFnFrKg==} - '@chevrotain/gast@11.0.3': - resolution: {integrity: sha512-+qNfcoNk70PyS/uxmj3li5NiECO+2YKZZQMbmjTqRI3Qchu8Hig/Q9vgkHpI3alNjr7M+a2St5pw5w5F6NL5/Q==} + '@chevrotain/gast@12.0.0': + resolution: {integrity: sha512-1ne/m3XsIT8aEdrvT33so0GUC+wkctpUPK6zU9IlOyJLUbR0rg4G7ZiApiJbggpgPir9ERy3FRjT6T7lpgetnQ==} - '@chevrotain/regexp-to-ast@11.0.3': - resolution: {integrity: sha512-1fMHaBZxLFvWI067AVbGJav1eRY7N8DDvYCTwGBiE/ytKBgP8azTdgyrKyWZ9Mfh09eHWb5PgTSO8wi7U824RA==} + '@chevrotain/regexp-to-ast@12.0.0': + resolution: {integrity: sha512-p+EW9MaJwgaHguhoqwOtx/FwuGr+DnNn857sXWOi/mClXIkPGl3rn7hGNWvo31HA3vyeQxjqe+H36yZJwYU8cA==} - '@chevrotain/types@11.0.3': - resolution: {integrity: sha512-gsiM3G8b58kZC2HaWR50gu6Y1440cHiJ+i3JUvcp/35JchYejb2+5MVeJK0iKThYpAa/P2PYFV4hoi44HD+aHQ==} + '@chevrotain/types@12.0.0': + resolution: {integrity: sha512-S+04vjFQKeuYw0/eW3U52LkAHQsB1ASxsPGsLPUyQgrZ2iNNibQrsidruDzjEX2JYfespXMG0eZmXlhA6z7nWA==} - '@chevrotain/utils@11.0.3': - resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==} + '@chevrotain/utils@12.0.0': + resolution: {integrity: sha512-lB59uJoaGIfOOL9knQqQRfhl9g7x8/wqFkp13zTdkRu1huG9kg6IJs1O8hqj9rs6h7orGxHJUKb+mX3rPbWGhA==} '@csstools/color-helpers@5.1.0': resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} @@ -539,26 +549,26 @@ packages: resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@floating-ui/core@1.7.3': - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - '@floating-ui/dom@1.7.4': - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - '@floating-ui/react-dom@2.1.6': - resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react@0.27.16': - resolution: {integrity: sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==} + '@floating-ui/react@0.27.19': + resolution: {integrity: sha512-31B8h5mm8YxotlE7/AU/PhNAl8eWxAmjL/v2QOxroDNkTFLk3Uu82u63N3b6TXa4EGJeeZLVcd/9AlNlVqzeog==} peerDependencies: react: '>=17.0.0' react-dom: '>=17.0.0' - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} '@giscus/react@3.1.0': resolution: {integrity: sha512-0TCO2TvL43+oOdyVVGHDItwxD1UMKP2ZYpT6gXmhFOqfAJtZxTzJ9hkn34iAF/b6YzyJ4Um89QIt9z/ajmAEeg==} @@ -621,8 +631,8 @@ packages: '@kurkle/color@0.3.4': resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} - '@lit-labs/ssr-dom-shim@1.5.0': - resolution: {integrity: sha512-HLomZXMmrCFHSRKESF5vklAKsDY7/fsT/ZhqCu3V0UoW/Qbv8wxmO4W9bx4KnCCF2Zak4yuk+AGraK/bPmI4kA==} + '@lit-labs/ssr-dom-shim@1.5.1': + resolution: {integrity: sha512-Aou5UdlSpr5whQe8AA/bZG0jMj96CoJIWbGfZ91qieWu5AWUMKw8VR/pAkQkJYvBNhmCcWnZlyyk5oze8JIqYA==} '@lit/reactive-element@2.1.2': resolution: {integrity: sha512-pbCDiVMnne1lYUIaYNN5wrwQXDtHaYtg7YEFPeW+hws6U47WeFvISGUWekPGKWOP1ygrs0ef0o1VJMk1exos5A==} @@ -663,8 +673,8 @@ packages: '@types/react': '>=16' react: '>=16' - '@mermaid-js/parser@0.6.3': - resolution: {integrity: sha512-lnjOhe7zyHjc+If7yT4zoedx2vo4sHaTmtkl1+or8BRTnCtDmcTpAjpzDSfCZrshM5bCoz0GyidzadJAH1xobA==} + '@mermaid-js/parser@1.1.0': + resolution: {integrity: sha512-gxK9ZX2+Fex5zu8LhRQoMeMPEHbc73UKZ0FQ54YrQtUxE1VVhMwzeNtKRPAu5aXks4FasbMe4xB4bWrmq6Jlxw==} '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -685,8 +695,8 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@primer/octicons@19.21.1': - resolution: {integrity: sha512-7tgtBkCNcg75YJnckinzvES+uxysYQCe+CHSEnzr3VYgxttzKRvfmrnVogl3aEuHCQP4xhiE9k2lFDhYwGtTzQ==} + '@primer/octicons@19.23.1': + resolution: {integrity: sha512-CzjGmxkmNhyst6EekrS3SJPdtzgIkUMP/LSJch65y99/kmiFXbO1a+q7zoYe3hnI9NaOM0IN+ydDIbOmd8YqcA==} '@radix-ui/primitive@1.1.3': resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} @@ -932,8 +942,8 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@rc-component/async-validator@5.0.4': - resolution: {integrity: sha512-qgGdcVIF604M9EqjNF0hbUTz42bz/RDtxWdWuU5EQe3hi7M8ob54B6B35rOsvX5eSvIHIzT9iH1R3n+hk3CGfg==} + '@rc-component/async-validator@5.1.0': + resolution: {integrity: sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA==} engines: {node: '>=14.x'} '@rc-component/cascader@1.10.0': @@ -984,8 +994,8 @@ packages: react: '>=16.11.0' react-dom: '>=16.11.0' - '@rc-component/form@1.6.0': - resolution: {integrity: sha512-A7vrN8kExtw4sW06mrsgCb1rowhvBFFvQU6Bk/NL0Fj6Wet/5GF0QnGCxBu/sG3JI9FEhsJWES0D44BW2d0hzg==} + '@rc-component/form@1.6.2': + resolution: {integrity: sha512-OgIn2RAoaSBqaIgzJf/X6iflIa9LpTozci1lagLBdURDFhGA370v0+T0tXxOi8YShMjTha531sFhwtnrv+EJaQ==} engines: {node: '>=8.x'} peerDependencies: react: '>=16.9.0' @@ -1021,8 +1031,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - '@rc-component/mini-decimal@1.1.0': - resolution: {integrity: sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ==} + '@rc-component/mini-decimal@1.1.3': + resolution: {integrity: sha512-bk/FJ09fLf+NLODMAFll6CfYrHPBioTedhW6lxDBuuWucJEqFUd4l/D/5JgIi3dina6sYahB8iuPAZTNz2pMxw==} engines: {node: '>=8.x'} '@rc-component/motion@1.1.6': @@ -1057,8 +1067,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - '@rc-component/picker@1.9.0': - resolution: {integrity: sha512-OLisdk8AWVCG9goBU1dWzuH5QlBQk8jktmQ6p0/IyBFwdKGwyIZOSjnBYo8hooHiTdl0lU+wGf/OfMtVBw02KQ==} + '@rc-component/picker@1.9.1': + resolution: {integrity: sha512-9FBYYsvH3HMLICaPDA/1Th5FLaDkFa7qAtangIdlhKb3ZALaR745e9PsOhheJb6asS4QXc12ffiAcjdkZ4C5/g==} engines: {node: '>=12.x'} peerDependencies: date-fns: '>= 2.x' @@ -1111,8 +1121,8 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' - '@rc-component/resize-observer@1.0.1': - resolution: {integrity: sha512-r+w+Mz1EiueGk1IgjB3ptNXLYSLZ5vnEfKHH+gfgj7JMupftyzvUUl3fRcMZe5uMM04x0n8+G2o/c6nlO2+Wag==} + '@rc-component/resize-observer@1.1.2': + resolution: {integrity: sha512-t/Bb0W8uvL4PYKAB3YcChC+DlHh0Wt5kM7q/J+0qpVEUMLe7Hk5zuvc9km0hMnTFPSx5Z7Wu/fzCLN6erVLE8Q==} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' @@ -1196,15 +1206,15 @@ packages: react: '*' react-dom: '*' - '@rc-component/trigger@2.3.0': - resolution: {integrity: sha512-iwaxZyzOuK0D7lS+0AQEtW52zUWxoGqTGkke3dRyb8pYiShmRpCjB/8TzPI4R6YySCH7Vm9BZj/31VPiiQTLBg==} + '@rc-component/trigger@2.3.1': + resolution: {integrity: sha512-ORENF39PeXTzM+gQEshuk460Z8N4+6DkjpxlpE7Q3gYy1iBpLrx0FOJz3h62ryrJZ/3zCAUIkT1Pb/8hHWpb3A==} engines: {node: '>=8.x'} peerDependencies: react: '>=16.9.0' react-dom: '>=16.9.0' - '@rc-component/trigger@3.8.1': - resolution: {integrity: sha512-walnDJnKq+OcPQFHBMN+YZmdHV8+6z75+Rgpc0dW1c+Dmy6O7tRueDs4LdbwjlryQfTdsw84PIkNPzcx5yQ7qQ==} + '@rc-component/trigger@3.9.0': + resolution: {integrity: sha512-X8btpwfrT27AgrZVOz4swclhEHTZcqaHeQMXXBgveagOiakTa36uObXbdwerXffgV8G9dH1fAAE0DHtVQs8EHg==} engines: {node: '>=8.x'} peerDependencies: react: '>=18.0.0' @@ -1216,6 +1226,12 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + '@rc-component/util@1.10.1': + resolution: {integrity: sha512-q++9S6rUa5Idb/xIBNz6jtvumw5+O5YV5V0g4iK9mn9jWs4oGJheE3ZN1kAnE723AXyaD8v95yeOASmdk8Jnng==} + peerDependencies: + react: '>=18.0.0' + react-dom: '>=18.0.0' + '@rc-component/util@1.7.0': resolution: {integrity: sha512-tIvIGj4Vl6fsZFvWSkYw9sAfiCKUXMyhVz6kpKyZbwyZyRPqv2vxYZROdaO1VB4gqTNvUZFXh6i3APUiterw5g==} peerDependencies: @@ -1350,26 +1366,26 @@ packages: cpu: [x64] os: [win32] - '@shikijs/core@3.20.0': - resolution: {integrity: sha512-f2ED7HYV4JEk827mtMDwe/yQ25pRiXZmtHjWF8uzZKuKiEsJR7Ce1nuQ+HhV9FzDcbIo4ObBCD9GPTzNuy9S1g==} + '@shikijs/core@3.23.0': + resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} - '@shikijs/engine-javascript@3.20.0': - resolution: {integrity: sha512-OFx8fHAZuk7I42Z9YAdZ95To6jDePQ9Rnfbw9uSRTSbBhYBp1kEOKv/3jOimcj3VRUKusDYM6DswLauwfhboLg==} + '@shikijs/engine-javascript@3.23.0': + resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} - '@shikijs/engine-oniguruma@3.20.0': - resolution: {integrity: sha512-Yx3gy7xLzM0ZOjqoxciHjA7dAt5tyzJE3L4uQoM83agahy+PlW244XJSrmJRSBvGYELDhYXPacD4R/cauV5bzQ==} + '@shikijs/engine-oniguruma@3.23.0': + resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} - '@shikijs/langs@3.20.0': - resolution: {integrity: sha512-le+bssCxcSHrygCWuOrYJHvjus6zhQ2K7q/0mgjiffRbkhM4o1EWu2m+29l0yEsHDbWaWPNnDUTRVVBvBBeKaA==} + '@shikijs/langs@3.23.0': + resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} - '@shikijs/themes@3.20.0': - resolution: {integrity: sha512-U1NSU7Sl26Q7ErRvJUouArxfM2euWqq1xaSrbqMu2iqa+tSp0D1Yah8216sDYbdDHw4C8b75UpE65eWorm2erQ==} + '@shikijs/themes@3.23.0': + resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} - '@shikijs/transformers@3.20.0': - resolution: {integrity: sha512-PrHHMRr3Q5W1qB/42kJW6laqFyWdhrPF2hNR9qjOm1xcSiAO3hAHo7HaVyHE6pMyevmy3i51O8kuGGXC78uK3g==} + '@shikijs/transformers@3.23.0': + resolution: {integrity: sha512-F9msZVxdF+krQNSdQ4V+Ja5QemeAoTQ2jxt7nJCwhDsdF1JWS3KxIQXA3lQbyKwS3J61oHRUSv4jYWv3CkaKTQ==} - '@shikijs/types@3.20.0': - resolution: {integrity: sha512-lhYAATn10nkZcBQ0BlzSbJA3wcmL5MXUUF8d2Zzon6saZDlToKaiRX60n2+ZaHJCmXEcZRWNzn+k9vplr8Jhsw==} + '@shikijs/types@3.23.0': + resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} @@ -1466,8 +1482,8 @@ packages: '@types/d3-selection@3.0.11': resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} - '@types/d3-shape@3.1.7': - resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + '@types/d3-shape@3.1.8': + resolution: {integrity: sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==} '@types/d3-time-format@4.0.3': resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} @@ -1487,8 +1503,8 @@ packages: '@types/d3@7.4.3': resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} '@types/dompurify@3.2.0': resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==} @@ -1512,8 +1528,8 @@ packages: '@types/js-cookie@3.0.6': resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} - '@types/katex@0.16.7': - resolution: {integrity: sha512-HMwFiRujE5PjrgwHQ25+bsLJgowjGjm5Z8FVSf0N6PwgJrwxH0QxzHYDcKsTfV3wva0vzrpqMTJS2jXPr5BMEQ==} + '@types/katex@0.16.8': + resolution: {integrity: sha512-trgaNyfU+Xh2Tc+ABIb44a5AYUpicB3uwirOioeOkNPPbmgRNtcWyDeeFRzjPZENO9Vq8gvVqfhaaXWLlevVwg==} '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} @@ -1612,6 +1628,9 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + '@upsetjs/venn.js@2.0.0': + resolution: {integrity: sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==} + '@use-gesture/core@10.3.1': resolution: {integrity: sha512-WcINiDt8WjqBdUXye25anHiNxPc0VOrlT8F6LLkU6cycrOGUDyY/yyFmsg3k8i5OLvv25llc0QC45GhR/C8llw==} @@ -1743,6 +1762,11 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + acorn@8.16.0: + resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} + engines: {node: '>=0.4.0'} + hasBin: true + adler-32@1.3.1: resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} engines: {node: '>=0.8'} @@ -1751,8 +1775,8 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ahooks@3.9.6: - resolution: {integrity: sha512-Mr7f05swd5SmKlR9SZo5U6M0LsL4ErweLzpdgXjA1JPmnZ78Vr6wzx0jUtvoxrcqGKYnX0Yjc02iEASVxHFPjQ==} + ahooks@3.9.7: + resolution: {integrity: sha512-S0lvzhbdlhK36RFBkGv+RbOM/dbbweym+BIHM/bwwuWVSVN5TuVErHPMWo4w0t1NDYg5KPp2iEf7Y7E5LASYiw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -1834,8 +1858,8 @@ packages: peerDependencies: postcss: ^8.1.0 - axios@1.13.5: - resolution: {integrity: sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==} + axios@1.15.0: + resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==} babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} @@ -1931,13 +1955,14 @@ packages: resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} engines: {node: '>= 16'} - chevrotain-allstar@0.3.1: - resolution: {integrity: sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw==} + chevrotain-allstar@0.4.1: + resolution: {integrity: sha512-PvVJm3oGqrveUVW2Vt/eZGeiAIsJszYweUcYwcskg9e+IubNYKKD+rHHem7A6XVO22eDAL+inxNIGAzZ/VIWlA==} peerDependencies: - chevrotain: ^11.0.0 + chevrotain: ^12.0.0 - chevrotain@11.0.3: - resolution: {integrity: sha512-ci2iJH6LeIkvP9eJW6gpueU8cnZhv85ELY8w8WiFtNjMHA5ad6pQLaJo9mEly/9qUyCpvqX8/POVUTf18/HFdw==} + chevrotain@12.0.0: + resolution: {integrity: sha512-csJvb+6kEiQaqo1woTdSAuOWdN0WTLIydkKrBnS+V5gZz0oqBrp4kQ35519QgK6TpBThiG3V1vNSHlIkv4AglQ==} + engines: {node: '>=22.0.0'} chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} @@ -1959,10 +1984,6 @@ packages: cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - clsx@1.2.1: - resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} - engines: {node: '>=6'} - clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -2063,8 +2084,8 @@ packages: peerDependencies: cytoscape: ^3.2.0 - cytoscape@3.33.1: - resolution: {integrity: sha512-iJc4TwyANnOGR1OmWhsS9ayRS3s+XQ185FmuHObThD+5AeJCakAAbWv8KimMTt08xCCLNgneQwFp+JRJOr9qGQ==} + cytoscape@3.33.2: + resolution: {integrity: sha512-sj4HXd3DokGhzZAdjDejGvTPLqlt84vNFN8m7bGsOzDY5DyVcxIb2ejIXat2Iy7HxWhdT/N1oKyheJ5YdpsGuw==} engines: {node: '>=0.10'} d3-array@2.12.1: @@ -2123,8 +2144,8 @@ packages: resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} engines: {node: '>=12'} - d3-format@3.1.0: - resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} engines: {node: '>=12'} d3-geo@3.1.1: @@ -2206,15 +2227,15 @@ packages: resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} engines: {node: '>=12'} - dagre-d3-es@7.0.13: - resolution: {integrity: sha512-efEhnxpSuwpYOKRm/L5KbqoZmNNukHa/Flty4Wp62JRvgH2ojwVgPgdYyr4twpieZnyRDdIH7PY2mopX26+j2Q==} + dagre-d3-es@7.0.14: + resolution: {integrity: sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==} data-urls@5.0.0: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} - dayjs@1.11.19: - resolution: {integrity: sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw==} + dayjs@1.11.20: + resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} de-indent@1.0.2: resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} @@ -2235,8 +2256,8 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - decode-named-character-reference@1.2.0: - resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} decode-uri-component@0.4.1: resolution: {integrity: sha512-+8VxcR21HhTy8nOt6jf20w0c9CADrw1O8d+VZ/YzzCt4bJ3uBjw+D1q2osAB8RnpwwaeYBxy0HyKQxD5JBMuuQ==} @@ -2249,8 +2270,8 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - delaunator@5.0.1: - resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + delaunator@5.1.0: + resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} @@ -2283,6 +2304,9 @@ packages: dompurify@3.3.1: resolution: {integrity: sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==} + dompurify@3.3.3: + resolution: {integrity: sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==} + driver.js@1.4.0: resolution: {integrity: sha512-Gm64jm6PmcU+si21sQhBrTAM1JvUrR0QhNmjkprNLxohOBzul9+pNHXgQaT9lW84gwg9GMLB3NZGuGolsz5uew==} @@ -2343,8 +2367,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es-toolkit@1.43.0: - resolution: {integrity: sha512-SKCT8AsWvYzBBuUqMk4NPwFlSdqLpJwmy6AP322ERn8W2YLIB6JBXnwMI2Qsh2gfphT3q7EKAxKb23cvFHFwKA==} + es-toolkit@1.45.1: + resolution: {integrity: sha512-/jhoOj/Fx+A+IIyDNOvO3TItGmlMKhtX8ISAHKE90c4b/k1tqaqEZ+uUqfpU8DMnW5cgNJv606zS55jGvza0Xw==} esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -2538,8 +2562,8 @@ packages: fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} - framer-motion@12.23.26: - resolution: {integrity: sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA==} + framer-motion@12.38.0: + resolution: {integrity: sha512-rFYkY/pigbcswl1XQSb7q424kSTQ8q6eAC+YUsSKooHQYuLdzdHjrt6uxUC+PRAO++q5IS7+TamgIw1AphxR+g==} peerDependencies: '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 @@ -2567,8 +2591,8 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.4.0: - resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} get-intrinsic@1.3.0: @@ -2714,8 +2738,8 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - immer@11.1.3: - resolution: {integrity: sha512-6jQTc5z0KJFtr1UgFpIL3N9XSC3saRaI9PwWtzM2pSqkNGtiNkYY2OSwkOGDK2XcTRcLb1pi/aNkKZz0nxVH4Q==} + immer@11.1.4: + resolution: {integrity: sha512-XREFCPo6ksxVzP4E0ekD5aMdf8WMwmdNaz6vuvxgI40UaEiu6q3p8X52aU6GdyvLY3XXX/8R7JOTXStz/nBbRw==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -2889,8 +2913,8 @@ packages: json2mq@0.2.0: resolution: {integrity: sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA==} - katex@0.16.27: - resolution: {integrity: sha512-aeQoDkuRWSqQN6nSvVCEFvfXdqo1OQiCmmW1kc9xSdjutPv7BGO7pqY9sQRJpMOGrEdfDgF2TfRXe5eUAD2Waw==} + katex@0.16.45: + resolution: {integrity: sha512-pQpZbdBu7wCTmQUh7ufPmLr0pFoObnGUoL/yhtwJDgmmQpbkg/0HSVti25Fu4rmd1oCR6NGWe9vqTWuWv3GcNA==} hasBin: true keyv@4.5.4: @@ -2899,9 +2923,9 @@ packages: khroma@2.1.0: resolution: {integrity: sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==} - langium@3.3.1: - resolution: {integrity: sha512-QJv/h939gDpvT+9SiLVlY7tZC3xB2qK57v0J04Sh9wpMb6MP1q8gB21L3WIo8T5P1MSMg3Ep14L7KkDCFG3y4w==} - engines: {node: '>=16.0.0'} + langium@4.2.2: + resolution: {integrity: sha512-JUshTRAfHI4/MF9dH2WupvjSXyn8JBuUEWazB8ZVJUtXutT0doDlAv1XKbZ1Pb5sMexa8FF4CFBc0iiul7gbUQ==} + engines: {node: '>=20.10.0', npm: '>=10.2.3'} layout-base@1.0.2: resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} @@ -2943,11 +2967,8 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - - lodash-es@4.17.22: - resolution: {integrity: sha512-XEawp1t0gxSi9x01glktRZ5HDy0HXqrM0x5pXQM98EaI0NxO6jVM7omDOxsuEo5UIASAnm2bRp1Jt/e0a2XU8Q==} + lodash-es@4.18.1: + resolution: {integrity: sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==} lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} @@ -2955,6 +2976,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + lodash@4.18.1: + resolution: {integrity: sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==} + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} @@ -3005,6 +3029,11 @@ packages: engines: {node: '>= 20'} hasBin: true + marked@17.0.6: + resolution: {integrity: sha512-gB0gkNafnonOw0obSTEGZTT86IuhILt2Wfx0mWH/1Au83kybTayroZ/V6nS25mN7u8ASy+5fMhgB3XPNrOZdmA==} + engines: {node: '>= 20'} + hasBin: true + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -3012,8 +3041,8 @@ packages: mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - mdast-util-from-markdown@2.0.2: - resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} mdast-util-gfm-autolink-literal@2.0.1: resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} @@ -3071,8 +3100,8 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - mermaid@11.12.2: - resolution: {integrity: sha512-n34QPDPEKmaeCG4WDMGy0OT6PSyxKCfy2pJgShP+Qow2KLrvWjclwbc3yXfSIf4BanqWEhQEpngWwNp/XhZt6w==} + mermaid@11.14.0: + resolution: {integrity: sha512-GSGloRsBs+JINmmhl0JDwjpuezCsHB4WGI4NASHxL3fHo3o/BRXTxhDLKnln8/Q0lRFRyDdEjmk1/d5Sn1Xz8g==} micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -3232,14 +3261,14 @@ packages: resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} engines: {node: '>=0.10.0'} - mlly@1.8.0: - resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} - motion-dom@12.23.23: - resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==} + motion-dom@12.38.0: + resolution: {integrity: sha512-pdkHLD8QYRp8VfiNLb8xIBJis1byQ9gPT3Jnh2jqfFtAsWUA3dEepDlsWe/xMpO8McV+VdpKVcp+E+TGJEtOoA==} - motion-utils@12.23.6: - resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} + motion-utils@12.36.0: + resolution: {integrity: sha512-eHWisygbiwVvf6PZ1vhaHCLamvkSbPIeAYxWUuL3a2PD/TROgE7FvfHWTIH4vMl798QLfMw15nRqIaRDXTlYRg==} motion@12.23.26: resolution: {integrity: sha512-Ll8XhVxY8LXMVYTCfme27WH2GjBrCIzY4+ndr5QKxsK+YwCtOi2B/oBi5jcIbik5doXuWT/4KKDOVAZJkeY5VQ==} @@ -3315,8 +3344,8 @@ packages: oniguruma-parser@0.12.1: resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==} - oniguruma-to-es@4.3.4: - resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} + oniguruma-to-es@4.3.5: + resolution: {integrity: sha512-Zjygswjpsewa0NLTsiizVuMQZbp0MDyM6lIt66OxsF21npUDlzpHi1Mgb/qhQdkb+dWFTzJmFbEWdvZgRho8eQ==} optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} @@ -3510,8 +3539,9 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} psl@1.15.0: resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==} @@ -3624,8 +3654,8 @@ packages: peerDependencies: react: ^19.2.3 - react-draggable@4.4.6: - resolution: {integrity: sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==} + react-draggable@4.5.0: + resolution: {integrity: sha512-VC+HBLEZ0XJxnOxVAZsdRi8rD04Iz3SiiKOoYzamjylUcju/hP9np/aZdLHf/7WOD268WMoNJMvYfB5yAK45cw==} peerDependencies: react: '>= 16.3.0' react-dom: '>= 16.3.0' @@ -3636,17 +3666,16 @@ packages: peerDependencies: react: '>= 16.8' - react-error-boundary@6.0.1: - resolution: {integrity: sha512-zArgQpjJUN1ZLMEKWtifxQweW3yfvwL5j2nh3Pesze1qG6r5oCDMy/TA97bUF01wy4xCeeL4/pd8GHmvEsP3Bg==} + react-error-boundary@6.1.1: + resolution: {integrity: sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w==} peerDependencies: react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 react-fast-compare@3.2.2: resolution: {integrity: sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==} - react-hotkeys-hook@5.2.1: - resolution: {integrity: sha512-xbKh6zJxd/vJHT4Bw4+0pBD662Fk20V+VFhLqciCg+manTVO4qlqRqiwFOYelfHN9dBvWj9vxaPkSS26ZSIJGg==} + react-hotkeys-hook@5.2.4: + resolution: {integrity: sha512-BgKg+A1+TawkYluh5Bo4cTmcgMN5L29uhJbDUQdHwPX+qgXRjIPYU5kIDHyxnAwCkCBiu9V5OpB2mpyeluVF2A==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' @@ -3671,8 +3700,8 @@ packages: react: optional: true - react-rnd@10.5.2: - resolution: {integrity: sha512-0Tm4x7k7pfHf2snewJA8x7Nwgt3LV+58MVEWOVsFjk51eYruFEa6Wy7BNdxt4/lH0wIRsu7Gm3KjSXY2w7YaNw==} + react-rnd@10.5.3: + resolution: {integrity: sha512-s/sIT3pGZnQ+57egijkTp9mizjIWrJz68Pq6yd+F/wniFY3IriML18dUXnQe/HP9uMiJ+9MAp44hljG99fZu6Q==} peerDependencies: react: '>=16.3.0' react-dom: '>=16.3.0' @@ -3802,8 +3831,8 @@ packages: deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true - robust-predicates@3.0.2: - resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + robust-predicates@3.0.3: + resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} rollup@4.54.0: resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} @@ -3865,19 +3894,22 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki-stream@0.1.3: - resolution: {integrity: sha512-pDIqmaP/zJWHNV8bJKp0tD0CZ6OkF+lWTIvmNRLktlTjBjN3+durr19JarS657U1oSEf/WrSYmdzwr9CeD6m2Q==} + shiki-stream@0.1.4: + resolution: {integrity: sha512-4pz6JGSDmVTTkPJ/ueixHkFAXY4ySCc+unvCaDZV7hqq/sdJZirRxgIXSuNSKgiFlGTgRR97sdu2R8K55sPsrw==} peerDependencies: react: ^19.0.0 + solid-js: ^1.9.0 vue: ^3.2.0 peerDependenciesMeta: react: optional: true + solid-js: + optional: true vue: optional: true - shiki@3.20.0: - resolution: {integrity: sha512-kgCOlsnyWb+p0WU+01RjkCH+eBVsjL1jOwUYWv0YDWkM2/A46+LDKVs5yZCUXjJG6bj4ndFoAg5iLIIue6dulg==} + shiki@3.23.0: + resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} @@ -3974,8 +4006,8 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - swr@2.3.8: - resolution: {integrity: sha512-gaCPRVoMq8WGDcWj9p4YWzCMPHzE0WNl6W8ADIx9c3JBEIdMkJGMzW+uzXvxHMltwcYACr9jP+32H8/hgwMR7w==} + swr@2.4.1: + resolution: {integrity: sha512-2CC6CiKQtEwaEeNiqWTAw9PGykW8SR5zZX8MZk6TeAvEAnVS7Visz8WzphqgtQ8v2xz/4Q5K+j+SeMaKXeeQIA==} peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -4017,8 +4049,8 @@ packages: tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.1.1: + resolution: {integrity: sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==} engines: {node: '>=18'} tinyglobby@0.2.15: @@ -4094,8 +4126,8 @@ packages: engines: {node: '>=14.17'} hasBin: true - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + ufo@1.6.3: + resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} @@ -4128,8 +4160,8 @@ packages: unist-util-visit-parents@6.0.2: resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} @@ -4296,9 +4328,6 @@ packages: resolution: {integrity: sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==} hasBin: true - vscode-uri@3.0.8: - resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} - vscode-uri@3.1.0: resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} @@ -4494,15 +4523,15 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@ant-design/colors@8.0.0': + '@ant-design/colors@8.0.1': dependencies: - '@ant-design/fast-color': 3.0.0 + '@ant-design/fast-color': 3.0.1 - '@ant-design/cssinjs-utils@2.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@ant-design/cssinjs-utils@2.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@ant-design/cssinjs': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@babel/runtime': 7.28.4 - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/cssinjs': 2.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@babel/runtime': 7.29.2 + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -4518,22 +4547,34 @@ snapshots: react-dom: 19.2.3(react@19.2.3) stylis: 4.3.6 - '@ant-design/fast-color@3.0.0': {} + '@ant-design/cssinjs@2.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.29.2 + '@emotion/hash': 0.8.0 + '@emotion/unitless': 0.7.5 + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + clsx: 2.1.1 + csstype: 3.2.3 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + stylis: 4.3.6 + + '@ant-design/fast-color@3.0.1': {} '@ant-design/icons-svg@4.4.2': {} - '@ant-design/icons@6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@ant-design/icons@6.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@ant-design/colors': 8.0.0 + '@ant-design/colors': 8.0.1 '@ant-design/icons-svg': 4.4.2 - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@ant-design/react-slick@2.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 clsx: 2.1.1 json2mq: 0.2.0 react: 19.2.3 @@ -4543,7 +4584,7 @@ snapshots: '@antfu/install-pkg@1.1.0': dependencies: package-manager-detector: 1.6.0 - tinyexec: 1.0.2 + tinyexec: 1.1.1 '@asamuzakjp/css-color@3.2.0': dependencies: @@ -4586,6 +4627,8 @@ snapshots: '@babel/runtime@7.28.4': {} + '@babel/runtime@7.29.2': {} + '@babel/template@7.27.2': dependencies: '@babel/code-frame': 7.27.1 @@ -4609,24 +4652,23 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 - '@base-ui/react@1.0.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@base-ui/react@1.3.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 - '@base-ui/utils': 0.2.3(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@floating-ui/utils': 0.2.10 + '@babel/runtime': 7.29.2 + '@base-ui/utils': 0.2.6(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@floating-ui/utils': 0.2.11 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - reselect: 5.1.1 tabbable: 6.4.0 use-sync-external-store: 1.6.0(react@19.2.3) optionalDependencies: '@types/react': 19.2.7 - '@base-ui/utils@0.2.3(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@base-ui/utils@0.2.6(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 - '@floating-ui/utils': 0.2.10 + '@babel/runtime': 7.29.2 + '@floating-ui/utils': 0.2.11 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) reselect: 5.1.1 @@ -4636,24 +4678,22 @@ snapshots: '@bcoe/v8-coverage@0.2.3': {} - '@braintree/sanitize-url@7.1.1': {} + '@braintree/sanitize-url@7.1.2': {} - '@chevrotain/cst-dts-gen@11.0.3': + '@chevrotain/cst-dts-gen@12.0.0': dependencies: - '@chevrotain/gast': 11.0.3 - '@chevrotain/types': 11.0.3 - lodash-es: 4.17.21 + '@chevrotain/gast': 12.0.0 + '@chevrotain/types': 12.0.0 - '@chevrotain/gast@11.0.3': + '@chevrotain/gast@12.0.0': dependencies: - '@chevrotain/types': 11.0.3 - lodash-es: 4.17.21 + '@chevrotain/types': 12.0.0 - '@chevrotain/regexp-to-ast@11.0.3': {} + '@chevrotain/regexp-to-ast@12.0.0': {} - '@chevrotain/types@11.0.3': {} + '@chevrotain/types@12.0.0': {} - '@chevrotain/utils@11.0.3': {} + '@chevrotain/utils@12.0.0': {} '@csstools/color-helpers@5.1.0': {} @@ -4888,30 +4928,30 @@ snapshots: '@eslint/js@8.57.1': {} - '@floating-ui/core@1.7.3': + '@floating-ui/core@1.7.5': dependencies: - '@floating-ui/utils': 0.2.10 + '@floating-ui/utils': 0.2.11 - '@floating-ui/dom@1.7.4': + '@floating-ui/dom@1.7.6': dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 - '@floating-ui/react-dom@2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@floating-ui/react-dom@2.1.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@floating-ui/dom': 1.7.4 + '@floating-ui/dom': 1.7.6 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@floating-ui/react@0.27.16(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@floating-ui/react@0.27.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@floating-ui/utils': 0.2.10 + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@floating-ui/utils': 0.2.11 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) tabbable: 6.4.0 - '@floating-ui/utils@0.2.10': {} + '@floating-ui/utils@0.2.11': {} '@giscus/react@3.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: @@ -4937,7 +4977,7 @@ snapshots: dependencies: '@antfu/install-pkg': 1.1.0 '@iconify/types': 2.0.0 - mlly: 1.8.0 + mlly: 1.8.2 '@intlify/core-base@9.14.5': dependencies: @@ -4978,11 +5018,11 @@ snapshots: '@kurkle/color@0.3.4': {} - '@lit-labs/ssr-dom-shim@1.5.0': {} + '@lit-labs/ssr-dom-shim@1.5.1': {} '@lit/reactive-element@2.1.2': dependencies: - '@lit-labs/ssr-dom-shim': 1.5.0 + '@lit-labs/ssr-dom-shim': 1.5.1 '@lobehub/emojilib@1.0.0': {} @@ -4991,7 +5031,7 @@ snapshots: '@lobehub/emojilib': 1.0.0 antd-style: 4.1.0(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) emoji-regex: 10.6.0 - es-toolkit: 1.43.0 + es-toolkit: 1.45.1 lucide-react: 0.562.0(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5016,8 +5056,8 @@ snapshots: '@lobehub/ui@4.9.2(@lobehub/fluent-emoji@4.1.0(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(@lobehub/icons@4.0.2)(@types/mdast@4.0.4)(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(micromark-util-types@2.0.2)(micromark@4.0.2)(motion@12.23.26(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(vue@3.5.26(typescript@5.6.3))': dependencies: - '@ant-design/cssinjs': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@base-ui/react': 1.0.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/cssinjs': 2.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@base-ui/react': 1.3.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@dnd-kit/core': 6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@dnd-kit/modifiers': 9.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) '@dnd-kit/sortable': 10.0.0(@dnd-kit/core@6.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react@19.2.3) @@ -5025,32 +5065,32 @@ snapshots: '@emoji-mart/data': 1.2.1 '@emoji-mart/react': 1.1.1(emoji-mart@5.6.0)(react@19.2.3) '@emotion/is-prop-valid': 1.4.0 - '@floating-ui/react': 0.27.16(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@floating-ui/react': 0.27.19(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@giscus/react': 3.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@lobehub/fluent-emoji': 4.1.0(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@lobehub/icons': 4.0.2(@lobehub/ui@4.9.2)(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@mdx-js/mdx': 3.1.1 '@mdx-js/react': 3.1.1(@types/react@19.2.7)(react@19.2.3) '@radix-ui/react-slot': 1.2.4(@types/react@19.2.7)(react@19.2.3) - '@shikijs/core': 3.20.0 - '@shikijs/transformers': 3.20.0 + '@shikijs/core': 3.23.0 + '@shikijs/transformers': 3.23.0 '@splinetool/runtime': 0.9.526 - ahooks: 3.9.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + ahooks: 3.9.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) antd: 6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) antd-style: 4.1.0(@types/react@19.2.7)(antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) chroma-js: 3.2.0 class-variance-authority: 0.7.1 clsx: 2.1.1 - dayjs: 1.11.19 + dayjs: 1.11.20 emoji-mart: 5.6.0 - es-toolkit: 1.43.0 + es-toolkit: 1.45.1 fast-deep-equal: 3.1.3 - immer: 11.1.3 - katex: 0.16.27 + immer: 11.1.4 + katex: 0.16.45 leva: 0.10.1(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) lucide-react: 0.562.0(react@19.2.3) - marked: 17.0.1 - mermaid: 11.12.2 + marked: 17.0.6 + mermaid: 11.14.0 motion: 12.23.26(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) numeral: 2.0.6 polished: 4.3.1 @@ -5064,11 +5104,11 @@ snapshots: react: 19.2.3 react-avatar-editor: 14.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-dom: 19.2.3(react@19.2.3) - react-error-boundary: 6.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react-hotkeys-hook: 5.2.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-error-boundary: 6.1.1(react@19.2.3) + react-hotkeys-hook: 5.2.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-markdown: 10.1.0(@types/react@19.2.7)(react@19.2.3) react-merge-refs: 3.0.2(react@19.2.3) - react-rnd: 10.5.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-rnd: 10.5.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react-zoom-pan-pinch: 3.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) rehype-github-alerts: 4.2.0 rehype-katex: 7.0.1 @@ -5078,9 +5118,9 @@ snapshots: remark-gfm: 4.0.1 remark-github: 12.0.0 remark-math: 6.0.0 - shiki: 3.20.0 - shiki-stream: 0.1.3(react@19.2.3)(vue@3.5.26(typescript@5.6.3)) - swr: 2.3.8(react@19.2.3) + shiki: 3.23.0 + shiki-stream: 0.1.4(react@19.2.3)(vue@3.5.26(typescript@5.6.3)) + swr: 2.4.1(react@19.2.3) ts-md5: 2.0.1 unified: 11.0.5 url-join: 5.0.0 @@ -5092,6 +5132,7 @@ snapshots: - '@types/react-dom' - micromark - micromark-util-types + - solid-js - supports-color - vue @@ -5101,7 +5142,7 @@ snapshots: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 '@types/mdx': 2.0.13 - acorn: 8.15.0 + acorn: 8.16.0 collapse-white-space: 2.1.0 devlop: 1.1.0 estree-util-is-identifier-name: 3.0.0 @@ -5110,7 +5151,7 @@ snapshots: hast-util-to-jsx-runtime: 2.3.6 markdown-extensions: 2.0.0 recma-build-jsx: 1.0.0 - recma-jsx: 1.0.1(acorn@8.15.0) + recma-jsx: 1.0.1(acorn@8.16.0) recma-stringify: 1.0.0 rehype-recma: 1.0.0 remark-mdx: 3.1.1 @@ -5120,7 +5161,7 @@ snapshots: unified: 11.0.5 unist-util-position-from-estree: 2.0.0 unist-util-stringify-position: 4.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 transitivePeerDependencies: - supports-color @@ -5131,9 +5172,9 @@ snapshots: '@types/react': 19.2.7 react: 19.2.3 - '@mermaid-js/parser@0.6.3': + '@mermaid-js/parser@1.1.0': dependencies: - langium: 3.3.1 + langium: 4.2.2 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -5152,7 +5193,7 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true - '@primer/octicons@19.21.1': + '@primer/octicons@19.23.1': dependencies: object-assign: 4.1.1 @@ -5199,7 +5240,7 @@ snapshots: '@radix-ui/react-popper@1.2.8(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-arrow': 1.1.7(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.3) '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.3) @@ -5348,46 +5389,46 @@ snapshots: '@radix-ui/rect@1.1.1': {} - '@rc-component/async-validator@5.0.4': + '@rc-component/async-validator@5.1.0': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@rc-component/cascader@1.10.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/select': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/checkbox@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/collapse@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/color-picker@3.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@ant-design/fast-color': 3.0.0 - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/fast-color': 3.0.1 + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/context@2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5395,7 +5436,7 @@ snapshots: dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/portal': 2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5404,23 +5445,23 @@ snapshots: dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/portal': 2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/dropdown@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/trigger': 3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/form@1.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@rc-component/form@1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/async-validator': 5.0.4 - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/async-validator': 5.1.0 + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5429,22 +5470,22 @@ snapshots: dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/portal': 2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/input-number@1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/mini-decimal': 1.1.0 - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/mini-decimal': 1.1.3 + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/input@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5454,8 +5495,8 @@ snapshots: '@rc-component/input': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/menu': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/textarea': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5464,68 +5505,68 @@ snapshots: dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/mini-decimal@1.1.0': + '@rc-component/mini-decimal@1.1.3': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@rc-component/motion@1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/mutate-observer@2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/notification@1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/overflow@1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@babel/runtime': 7.29.2 + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/pagination@1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/picker@1.9.0(dayjs@1.11.19)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@rc-component/picker@1.9.1(dayjs@1.11.20)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) optionalDependencies: - dayjs: 1.11.19 + dayjs: 1.11.20 '@rc-component/portal@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 classnames: 2.5.1 rc-util: 5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 @@ -5533,42 +5574,42 @@ snapshots: '@rc-component/portal@2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/progress@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/qrcode@1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/rate@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/resize-observer@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@rc-component/resize-observer@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/segmented@1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5576,8 +5617,8 @@ snapshots: '@rc-component/select@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/overflow': 1.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/virtual-list': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -5585,21 +5626,21 @@ snapshots: '@rc-component/slider@1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/steps@1.2.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/switch@1.0.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5607,8 +5648,8 @@ snapshots: '@rc-component/table@1.9.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/context': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/virtual-list': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 @@ -5619,8 +5660,8 @@ snapshots: '@rc-component/dropdown': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/menu': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5628,16 +5669,16 @@ snapshots: '@rc-component/textarea@1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/input': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/tooltip@1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/trigger': 3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5645,8 +5686,8 @@ snapshots: '@rc-component/tour@2.2.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/portal': 2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5655,7 +5696,7 @@ snapshots: dependencies: '@rc-component/select': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5663,15 +5704,15 @@ snapshots: '@rc-component/tree@1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/virtual-list': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/trigger@2.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@rc-component/trigger@2.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@rc-component/portal': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) classnames: 2.5.1 rc-motion: 2.9.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -5680,23 +5721,30 @@ snapshots: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - '@rc-component/trigger@3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@rc-component/trigger@3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@rc-component/motion': 1.1.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/portal': 2.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) '@rc-component/upload@1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) + '@rc-component/util@1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + dependencies: + is-mobile: 5.0.0 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-is: 18.3.1 + '@rc-component/util@1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: is-mobile: 5.0.0 @@ -5706,9 +5754,9 @@ snapshots: '@rc-component/virtual-list@1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@babel/runtime': 7.28.4 - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@babel/runtime': 7.29.2 + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -5779,38 +5827,38 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.54.0': optional: true - '@shikijs/core@3.20.0': + '@shikijs/core@3.23.0': dependencies: - '@shikijs/types': 3.20.0 + '@shikijs/types': 3.23.0 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 hast-util-to-html: 9.0.5 - '@shikijs/engine-javascript@3.20.0': + '@shikijs/engine-javascript@3.23.0': dependencies: - '@shikijs/types': 3.20.0 + '@shikijs/types': 3.23.0 '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 4.3.4 + oniguruma-to-es: 4.3.5 - '@shikijs/engine-oniguruma@3.20.0': + '@shikijs/engine-oniguruma@3.23.0': dependencies: - '@shikijs/types': 3.20.0 + '@shikijs/types': 3.23.0 '@shikijs/vscode-textmate': 10.0.2 - '@shikijs/langs@3.20.0': + '@shikijs/langs@3.23.0': dependencies: - '@shikijs/types': 3.20.0 + '@shikijs/types': 3.23.0 - '@shikijs/themes@3.20.0': + '@shikijs/themes@3.23.0': dependencies: - '@shikijs/types': 3.20.0 + '@shikijs/types': 3.23.0 - '@shikijs/transformers@3.20.0': + '@shikijs/transformers@3.23.0': dependencies: - '@shikijs/core': 3.20.0 - '@shikijs/types': 3.20.0 + '@shikijs/core': 3.23.0 + '@shikijs/types': 3.23.0 - '@shikijs/types@3.20.0': + '@shikijs/types@3.23.0': dependencies: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -5900,7 +5948,7 @@ snapshots: '@types/d3-selection@3.0.11': {} - '@types/d3-shape@3.1.7': + '@types/d3-shape@3.1.8': dependencies: '@types/d3-path': 3.1.1 @@ -5945,14 +5993,14 @@ snapshots: '@types/d3-scale': 4.0.9 '@types/d3-scale-chromatic': 3.1.0 '@types/d3-selection': 3.0.11 - '@types/d3-shape': 3.1.7 + '@types/d3-shape': 3.1.8 '@types/d3-time': 3.0.4 '@types/d3-time-format': 4.0.3 '@types/d3-timer': 3.0.2 '@types/d3-transition': 3.0.9 '@types/d3-zoom': 3.0.8 - '@types/debug@4.1.12': + '@types/debug@4.1.13': dependencies: '@types/ms': 2.1.0 @@ -5976,7 +6024,7 @@ snapshots: '@types/js-cookie@3.0.6': {} - '@types/katex@0.16.7': {} + '@types/katex@0.16.8': {} '@types/mdast@4.0.4': dependencies: @@ -6093,6 +6141,11 @@ snapshots: '@ungap/structured-clone@1.3.0': {} + '@upsetjs/venn.js@2.0.0': + optionalDependencies: + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + '@use-gesture/core@10.3.1': {} '@use-gesture/react@10.3.1(react@19.2.3)': @@ -6279,20 +6332,26 @@ snapshots: dependencies: acorn: 8.15.0 + acorn-jsx@5.3.2(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + acorn@8.15.0: {} + acorn@8.16.0: {} + adler-32@1.3.1: {} agent-base@7.1.4: {} - ahooks@3.9.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + ahooks@3.9.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@types/js-cookie': 3.0.6 - dayjs: 1.11.19 + dayjs: 1.11.20 intersection-observer: 0.12.2 js-cookie: 3.0.5 - lodash: 4.17.21 + lodash: 4.18.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) react-fast-compare: 3.2.2 @@ -6338,13 +6397,13 @@ snapshots: antd@6.1.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@ant-design/colors': 8.0.0 - '@ant-design/cssinjs': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@ant-design/cssinjs-utils': 2.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@ant-design/fast-color': 3.0.0 - '@ant-design/icons': 6.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/colors': 8.0.1 + '@ant-design/cssinjs': 2.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/cssinjs-utils': 2.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@ant-design/fast-color': 3.0.1 + '@ant-design/icons': 6.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@ant-design/react-slick': 2.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@rc-component/cascader': 1.10.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/checkbox': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/collapse': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6352,7 +6411,7 @@ snapshots: '@rc-component/dialog': 1.5.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/drawer': 1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/dropdown': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/form': 1.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/form': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/image': 1.5.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/input': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/input-number': 1.6.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6362,11 +6421,11 @@ snapshots: '@rc-component/mutate-observer': 2.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/notification': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/pagination': 1.2.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/picker': 1.9.0(dayjs@1.11.19)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/picker': 1.9.1(dayjs@1.11.20)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/progress': 1.0.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/qrcode': 1.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/rate': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/resize-observer': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/resize-observer': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/segmented': 1.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/select': 1.4.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/slider': 1.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -6379,11 +6438,11 @@ snapshots: '@rc-component/tour': 2.2.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/tree': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/tree-select': 1.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/trigger': 3.8.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/trigger': 3.9.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@rc-component/upload': 1.1.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@rc-component/util': 1.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@rc-component/util': 1.10.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) clsx: 2.1.1 - dayjs: 1.11.19 + dayjs: 1.11.20 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) scroll-into-view-if-needed: 3.1.0 @@ -6425,11 +6484,11 @@ snapshots: postcss: 8.5.6 postcss-value-parser: 4.2.0 - axios@1.13.5: + axios@1.15.0: dependencies: follow-redirects: 1.15.11 form-data: 4.0.5 - proxy-from-env: 1.1.0 + proxy-from-env: 2.1.0 transitivePeerDependencies: - debug @@ -6519,19 +6578,18 @@ snapshots: check-error@2.1.3: {} - chevrotain-allstar@0.3.1(chevrotain@11.0.3): + chevrotain-allstar@0.4.1(chevrotain@12.0.0): dependencies: - chevrotain: 11.0.3 - lodash-es: 4.17.22 + chevrotain: 12.0.0 + lodash-es: 4.18.1 - chevrotain@11.0.3: + chevrotain@12.0.0: dependencies: - '@chevrotain/cst-dts-gen': 11.0.3 - '@chevrotain/gast': 11.0.3 - '@chevrotain/regexp-to-ast': 11.0.3 - '@chevrotain/types': 11.0.3 - '@chevrotain/utils': 11.0.3 - lodash-es: 4.17.21 + '@chevrotain/cst-dts-gen': 12.0.0 + '@chevrotain/gast': 12.0.0 + '@chevrotain/regexp-to-ast': 12.0.0 + '@chevrotain/types': 12.0.0 + '@chevrotain/utils': 12.0.0 chokidar@3.6.0: dependencies: @@ -6563,8 +6621,6 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 6.2.0 - clsx@1.2.1: {} - clsx@2.1.1: {} codepage@1.15.0: {} @@ -6639,17 +6695,17 @@ snapshots: csstype@3.2.3: {} - cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.1): + cytoscape-cose-bilkent@4.1.0(cytoscape@3.33.2): dependencies: cose-base: 1.0.3 - cytoscape: 3.33.1 + cytoscape: 3.33.2 - cytoscape-fcose@2.2.0(cytoscape@3.33.1): + cytoscape-fcose@2.2.0(cytoscape@3.33.2): dependencies: cose-base: 2.2.0 - cytoscape: 3.33.1 + cytoscape: 3.33.2 - cytoscape@3.33.1: {} + cytoscape@3.33.2: {} d3-array@2.12.1: dependencies: @@ -6681,7 +6737,7 @@ snapshots: d3-delaunay@6.0.4: dependencies: - delaunator: 5.0.1 + delaunator: 5.1.0 d3-dispatch@3.0.1: {} @@ -6708,7 +6764,7 @@ snapshots: d3-quadtree: 3.0.1 d3-timer: 3.0.1 - d3-format@3.1.0: {} + d3-format@3.1.2: {} d3-geo@3.1.1: dependencies: @@ -6743,7 +6799,7 @@ snapshots: d3-scale@4.0.2: dependencies: d3-array: 3.2.4 - d3-format: 3.1.0 + d3-format: 3.1.2 d3-interpolate: 3.0.1 d3-time: 3.1.0 d3-time-format: 4.1.0 @@ -6800,7 +6856,7 @@ snapshots: d3-ease: 3.0.1 d3-fetch: 3.0.1 d3-force: 3.0.0 - d3-format: 3.1.0 + d3-format: 3.1.2 d3-geo: 3.1.1 d3-hierarchy: 3.1.2 d3-interpolate: 3.0.1 @@ -6818,17 +6874,17 @@ snapshots: d3-transition: 3.0.1(d3-selection@3.0.0) d3-zoom: 3.0.0 - dagre-d3-es@7.0.13: + dagre-d3-es@7.0.14: dependencies: d3: 7.9.0 - lodash-es: 4.17.22 + lodash-es: 4.18.1 data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - dayjs@1.11.19: {} + dayjs@1.11.20: {} de-indent@1.0.2: {} @@ -6840,7 +6896,7 @@ snapshots: decimal.js@10.6.0: {} - decode-named-character-reference@1.2.0: + decode-named-character-reference@1.3.0: dependencies: character-entities: 2.0.2 @@ -6850,9 +6906,9 @@ snapshots: deep-is@0.1.4: {} - delaunator@5.0.1: + delaunator@5.1.0: dependencies: - robust-predicates: 3.0.2 + robust-predicates: 3.0.3 delayed-stream@1.0.0: {} @@ -6880,6 +6936,10 @@ snapshots: optionalDependencies: '@types/trusted-types': 2.0.7 + dompurify@3.3.3: + optionalDependencies: + '@types/trusted-types': 2.0.7 + driver.js@1.4.0: {} dunder-proto@1.0.1: @@ -6932,7 +6992,7 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 - es-toolkit@1.43.0: {} + es-toolkit@1.45.1: {} esast-util-from-estree@2.0.0: dependencies: @@ -6944,7 +7004,7 @@ snapshots: esast-util-from-js@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 - acorn: 8.15.0 + acorn: 8.16.0 esast-util-from-estree: 2.0.0 vfile-message: 4.0.3 @@ -7189,10 +7249,10 @@ snapshots: fraction.js@5.3.4: {} - framer-motion@12.23.26(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + framer-motion@12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - motion-dom: 12.23.23 - motion-utils: 12.23.6 + motion-dom: 12.38.0 + motion-utils: 12.36.0 tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.4.0 @@ -7208,7 +7268,7 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.4.0: {} + get-east-asian-width@1.5.0: {} get-intrinsic@1.3.0: dependencies: @@ -7343,7 +7403,7 @@ snapshots: mdast-util-to-hast: 13.2.1 parse5: 7.3.0 unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 web-namespaces: 2.0.1 zwitch: 2.0.4 @@ -7468,7 +7528,7 @@ snapshots: ignore@5.3.2: {} - immer@11.1.3: {} + immer@11.1.4: {} import-fresh@3.3.1: dependencies: @@ -7634,7 +7694,7 @@ snapshots: dependencies: string-convert: 0.2.1 - katex@0.16.27: + katex@0.16.45: dependencies: commander: 8.3.0 @@ -7644,13 +7704,14 @@ snapshots: khroma@2.1.0: {} - langium@3.3.1: + langium@4.2.2: dependencies: - chevrotain: 11.0.3 - chevrotain-allstar: 0.3.1(chevrotain@11.0.3) + '@chevrotain/regexp-to-ast': 12.0.0 + chevrotain: 12.0.0 + chevrotain-allstar: 0.4.1(chevrotain@12.0.0) vscode-languageserver: 9.0.1 vscode-languageserver-textdocument: 1.0.12 - vscode-uri: 3.0.8 + vscode-uri: 3.1.0 layout-base@1.0.2: {} @@ -7686,7 +7747,7 @@ snapshots: lit-element@4.2.2: dependencies: - '@lit-labs/ssr-dom-shim': 1.5.0 + '@lit-labs/ssr-dom-shim': 1.5.1 '@lit/reactive-element': 2.1.2 lit-html: 3.3.2 @@ -7708,14 +7769,14 @@ snapshots: dependencies: p-locate: 5.0.0 - lodash-es@4.17.21: {} - - lodash-es@4.17.22: {} + lodash-es@4.18.1: {} lodash.merge@4.6.2: {} lodash@4.17.21: {} + lodash@4.18.1: {} + longest-streak@3.1.0: {} loose-envify@1.4.0: @@ -7756,6 +7817,8 @@ snapshots: marked@17.0.1: {} + marked@17.0.6: {} + math-intrinsics@1.1.0: {} mdast-util-find-and-replace@3.0.2: @@ -7765,11 +7828,11 @@ snapshots: unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - mdast-util-from-markdown@2.0.2: + mdast-util-from-markdown@2.0.3: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 mdast-util-to-string: 4.0.0 micromark: 4.0.2 @@ -7794,7 +7857,7 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: @@ -7803,7 +7866,7 @@ snapshots: mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -7813,7 +7876,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 markdown-table: 3.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -7822,14 +7885,14 @@ snapshots: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color mdast-util-gfm@3.1.0: dependencies: - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-gfm-autolink-literal: 2.0.1 mdast-util-gfm-footnote: 2.1.0 mdast-util-gfm-strikethrough: 2.0.0 @@ -7845,7 +7908,7 @@ snapshots: '@types/mdast': 4.0.4 devlop: 1.1.0 longest-streak: 3.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 unist-util-remove-position: 5.0.0 transitivePeerDependencies: @@ -7857,7 +7920,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -7870,7 +7933,7 @@ snapshots: '@types/unist': 3.0.3 ccount: 2.0.1 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 parse-entities: 4.0.2 stringify-entities: 4.0.4 @@ -7881,7 +7944,7 @@ snapshots: mdast-util-mdx@3.0.0: dependencies: - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-mdx-expression: 2.0.1 mdast-util-mdx-jsx: 3.2.0 mdast-util-mdxjs-esm: 2.0.1 @@ -7895,7 +7958,7 @@ snapshots: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 devlop: 1.1.0 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color @@ -7919,7 +7982,7 @@ snapshots: micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 mdast-util-to-markdown@2.1.2: @@ -7931,7 +7994,7 @@ snapshots: mdast-util-to-string: 4.0.0 micromark-util-classify-character: 2.0.1 micromark-util-decode-string: 2.0.1 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 zwitch: 2.0.4 mdast-util-to-string@4.0.0: @@ -7947,23 +8010,24 @@ snapshots: merge2@1.4.1: {} - mermaid@11.12.2: + mermaid@11.14.0: dependencies: - '@braintree/sanitize-url': 7.1.1 + '@braintree/sanitize-url': 7.1.2 '@iconify/utils': 3.1.0 - '@mermaid-js/parser': 0.6.3 + '@mermaid-js/parser': 1.1.0 '@types/d3': 7.4.3 - cytoscape: 3.33.1 - cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.1) - cytoscape-fcose: 2.2.0(cytoscape@3.33.1) + '@upsetjs/venn.js': 2.0.0 + cytoscape: 3.33.2 + cytoscape-cose-bilkent: 4.1.0(cytoscape@3.33.2) + cytoscape-fcose: 2.2.0(cytoscape@3.33.2) d3: 7.9.0 d3-sankey: 0.12.3 - dagre-d3-es: 7.0.13 - dayjs: 1.11.19 - dompurify: 3.3.1 - katex: 0.16.27 + dagre-d3-es: 7.0.14 + dayjs: 1.11.20 + dompurify: 3.3.3 + katex: 0.16.45 khroma: 2.1.0 - lodash-es: 4.17.22 + lodash-es: 4.18.1 marked: 16.4.2 roughjs: 4.6.6 stylis: 4.3.6 @@ -7972,7 +8036,7 @@ snapshots: micromark-core-commonmark@2.0.3: dependencies: - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-factory-destination: 2.0.1 micromark-factory-label: 2.0.1 @@ -7991,7 +8055,7 @@ snapshots: micromark-extension-cjk-friendly-util@2.1.1(micromark-util-types@2.0.2): dependencies: - get-east-asian-width: 1.4.0 + get-east-asian-width: 1.5.0 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 optionalDependencies: @@ -8068,9 +8132,9 @@ snapshots: micromark-extension-math@3.1.0: dependencies: - '@types/katex': 0.16.7 + '@types/katex': 0.16.8 devlop: 1.1.0 - katex: 0.16.27 + katex: 0.16.45 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 @@ -8118,8 +8182,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) micromark-extension-mdx-expression: 3.0.1 micromark-extension-mdx-jsx: 3.0.2 micromark-extension-mdx-md: 2.0.0 @@ -8197,7 +8261,7 @@ snapshots: micromark-util-decode-string@2.0.1: dependencies: - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 micromark-util-character: 2.1.1 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-symbol: 2.0.1 @@ -8243,9 +8307,9 @@ snapshots: micromark@4.0.2: dependencies: - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 debug: 4.4.3 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 devlop: 1.1.0 micromark-core-commonmark: 2.0.3 micromark-factory-space: 2.0.1 @@ -8293,22 +8357,22 @@ snapshots: for-in: 1.0.2 is-extendable: 1.0.1 - mlly@1.8.0: + mlly@1.8.2: dependencies: - acorn: 8.15.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.1 + ufo: 1.6.3 - motion-dom@12.23.23: + motion-dom@12.38.0: dependencies: - motion-utils: 12.23.6 + motion-utils: 12.36.0 - motion-utils@12.23.6: {} + motion-utils@12.36.0: {} motion@12.23.26(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - framer-motion: 12.23.26(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + framer-motion: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 1.4.0 @@ -8362,7 +8426,7 @@ snapshots: oniguruma-parser@0.12.1: {} - oniguruma-to-es@4.3.4: + oniguruma-to-es@4.3.5: dependencies: oniguruma-parser: 0.12.1 regex: 6.1.0 @@ -8408,7 +8472,7 @@ snapshots: '@types/unist': 2.0.11 character-entities-legacy: 3.0.0 character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.2.0 + decode-named-character-reference: 1.3.0 is-alphanumerical: 2.0.1 is-decimal: 2.0.1 is-hexadecimal: 2.0.1 @@ -8474,7 +8538,7 @@ snapshots: pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.8.0 + mlly: 1.8.2 pathe: 2.0.3 pngjs@5.0.0: {} @@ -8539,7 +8603,7 @@ snapshots: proto-list@1.2.4: {} - proxy-from-env@1.1.0: {} + proxy-from-env@2.1.0: {} psl@1.15.0: dependencies: @@ -8565,7 +8629,7 @@ snapshots: rc-collapse@4.0.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 classnames: 2.5.1 rc-motion: 2.9.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) rc-util: 5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -8574,7 +8638,7 @@ snapshots: rc-dialog@9.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@rc-component/portal': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) classnames: 2.5.1 rc-motion: 2.9.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -8584,14 +8648,14 @@ snapshots: rc-footer@0.6.8(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 classnames: 2.5.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) rc-image@7.12.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 '@rc-component/portal': 1.1.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) classnames: 2.5.1 rc-dialog: 9.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -8602,8 +8666,8 @@ snapshots: rc-input-number@9.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 - '@rc-component/mini-decimal': 1.1.0 + '@babel/runtime': 7.29.2 + '@rc-component/mini-decimal': 1.1.3 classnames: 2.5.1 rc-input: 1.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) rc-util: 5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -8612,7 +8676,7 @@ snapshots: rc-input@1.8.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 classnames: 2.5.1 rc-util: 5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 @@ -8620,8 +8684,8 @@ snapshots: rc-menu@9.16.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 - '@rc-component/trigger': 2.3.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@babel/runtime': 7.29.2 + '@rc-component/trigger': 2.3.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) classnames: 2.5.1 rc-motion: 2.9.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) rc-overflow: 1.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -8631,7 +8695,7 @@ snapshots: rc-motion@2.9.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 classnames: 2.5.1 rc-util: 5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 @@ -8639,7 +8703,7 @@ snapshots: rc-overflow@1.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 classnames: 2.5.1 rc-resize-observer: 1.4.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3) rc-util: 5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -8648,7 +8712,7 @@ snapshots: rc-resize-observer@1.4.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 classnames: 2.5.1 rc-util: 5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 @@ -8657,7 +8721,7 @@ snapshots: rc-util@5.44.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - '@babel/runtime': 7.28.4 + '@babel/runtime': 7.29.2 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) react-is: 18.3.1 @@ -8682,9 +8746,9 @@ snapshots: react: 19.2.3 scheduler: 0.27.0 - react-draggable@4.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + react-draggable@4.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: - clsx: 1.2.1 + clsx: 2.1.1 prop-types: 15.8.1 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -8696,14 +8760,13 @@ snapshots: prop-types: 15.8.1 react: 19.2.3 - react-error-boundary@6.0.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + react-error-boundary@6.1.1(react@19.2.3): dependencies: react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) react-fast-compare@3.2.2: {} - react-hotkeys-hook@5.2.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + react-hotkeys-hook@5.2.4(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -8725,7 +8788,7 @@ snapshots: remark-parse: 11.0.0 remark-rehype: 11.1.2 unified: 11.0.5 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 transitivePeerDependencies: - supports-color @@ -8734,12 +8797,12 @@ snapshots: optionalDependencies: react: 19.2.3 - react-rnd@10.5.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + react-rnd@10.5.3(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: re-resizable: 6.11.2(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - react-draggable: 4.4.6(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react-draggable: 4.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) tslib: 2.6.2 react-zoom-pan-pinch@3.7.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): @@ -8765,10 +8828,10 @@ snapshots: estree-util-build-jsx: 3.0.1 vfile: 6.0.3 - recma-jsx@1.0.1(acorn@8.15.0): + recma-jsx@1.0.1(acorn@8.16.0): dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) estree-util-to-js: 2.0.0 recma-parse: 1.0.0 recma-stringify: 1.0.0 @@ -8800,18 +8863,18 @@ snapshots: rehype-github-alerts@4.2.0: dependencies: - '@primer/octicons': 19.21.1 + '@primer/octicons': 19.23.1 hast-util-from-html: 2.0.3 hast-util-is-element: 3.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 rehype-katex@7.0.1: dependencies: '@types/hast': 3.0.4 - '@types/katex': 0.16.7 + '@types/katex': 0.16.8 hast-util-from-html-isomorphic: 2.0.0 hast-util-to-text: 4.0.2 - katex: 0.16.27 + katex: 0.16.45 unist-util-visit-parents: 6.0.2 vfile: 6.0.3 @@ -8862,7 +8925,7 @@ snapshots: mdast-util-find-and-replace: 3.0.2 mdast-util-to-string: 4.0.0 to-vfile: 8.0.0 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 vfile: 6.0.3 remark-math@6.0.0: @@ -8884,7 +8947,7 @@ snapshots: remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 - mdast-util-from-markdown: 2.0.2 + mdast-util-from-markdown: 2.0.3 micromark-util-types: 2.0.2 unified: 11.0.5 transitivePeerDependencies: @@ -8928,7 +8991,7 @@ snapshots: dependencies: glob: 7.2.3 - robust-predicates@3.0.2: {} + robust-predicates@3.0.3: {} rollup@4.54.0: dependencies: @@ -9008,21 +9071,21 @@ snapshots: shebang-regex@3.0.0: {} - shiki-stream@0.1.3(react@19.2.3)(vue@3.5.26(typescript@5.6.3)): + shiki-stream@0.1.4(react@19.2.3)(vue@3.5.26(typescript@5.6.3)): dependencies: - '@shikijs/core': 3.20.0 + '@shikijs/core': 3.23.0 optionalDependencies: react: 19.2.3 vue: 3.5.26(typescript@5.6.3) - shiki@3.20.0: + shiki@3.23.0: dependencies: - '@shikijs/core': 3.20.0 - '@shikijs/engine-javascript': 3.20.0 - '@shikijs/engine-oniguruma': 3.20.0 - '@shikijs/langs': 3.20.0 - '@shikijs/themes': 3.20.0 - '@shikijs/types': 3.20.0 + '@shikijs/core': 3.23.0 + '@shikijs/engine-javascript': 3.23.0 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 @@ -9111,7 +9174,7 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - swr@2.3.8(react@19.2.3): + swr@2.4.1(react@19.2.3): dependencies: dequal: 2.0.3 react: 19.2.3 @@ -9173,7 +9236,7 @@ snapshots: tinyexec@0.3.2: {} - tinyexec@1.0.2: {} + tinyexec@1.1.1: {} tinyglobby@0.2.15: dependencies: @@ -9231,7 +9294,7 @@ snapshots: typescript@5.6.3: {} - ufo@1.6.1: {} + ufo@1.6.3: {} undici-types@6.21.0: {} @@ -9267,7 +9330,7 @@ snapshots: unist-util-remove-position@5.0.0: dependencies: '@types/unist': 3.0.3 - unist-util-visit: 5.0.0 + unist-util-visit: 5.1.0 unist-util-stringify-position@4.0.0: dependencies: @@ -9278,7 +9341,7 @@ snapshots: '@types/unist': 3.0.3 unist-util-is: 6.0.1 - unist-util-visit@5.0.0: + unist-util-visit@5.1.0: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 @@ -9430,8 +9493,6 @@ snapshots: dependencies: vscode-languageserver-protocol: 3.17.5 - vscode-uri@3.0.8: {} - vscode-uri@3.1.0: {} vue-chartjs@5.3.3(chart.js@4.5.1)(vue@3.5.26(typescript@5.6.3)): From faee59ee1590890985e72dd8ac9766215545f394 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 17:51:06 +0800 Subject: [PATCH 10/34] fix(payment): propagate reason/metadata in API error responses The API client's error interceptor was dropping the reason and metadata fields from backend error responses. This caused PaymentView to miss specific error codes (TOO_MANY_PENDING, CANCEL_RATE_LIMITED) and fall back to generic error messages. --- frontend/src/api/client.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 95f9ff3180..6be2d543a4 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -92,10 +92,13 @@ apiClient.interceptors.response.use( response.data = apiResponse.data } else { // API error + const resp = apiResponse as Record return Promise.reject({ status: response.status, code: apiResponse.code, - message: apiResponse.message || 'Unknown error' + message: apiResponse.message || 'Unknown error', + reason: resp.reason, + metadata: resp.metadata, }) } } @@ -268,7 +271,9 @@ apiClient.interceptors.response.use( status, code: apiData.code, error: apiData.error, - message: apiData.message || apiData.detail || error.message + message: apiData.message || apiData.detail || error.message, + reason: apiData.reason, + metadata: apiData.metadata, }) } From d67ecf893d9c961afad592e65b2f9b28861cea80 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 18:13:38 +0800 Subject: [PATCH 11/34] chore: remove all sora dead code and fork-specific sora_client_enabled Upstream removed sora feature (090_drop_sora.sql) but left i18n keys and wire.go references. Clean up: - Remove entire sora i18n block from en.ts and zh.ts (~190 lines) - Remove sora nav key and unused 'data' settings tab key - Remove sora_client_enabled from settings (fork-specific) - Remove SoraMediaCleanupService from wire.go --- backend/cmd/server/wire.go | 7 ------- frontend/src/i18n/locales/en.ts | 3 +-- frontend/src/i18n/locales/zh.ts | 3 +-- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/backend/cmd/server/wire.go b/backend/cmd/server/wire.go index 0c3fe09425..47f8f518ff 100644 --- a/backend/cmd/server/wire.go +++ b/backend/cmd/server/wire.go @@ -84,7 +84,6 @@ func provideCleanup( opsCleanup *service.OpsCleanupService, opsScheduledReport *service.OpsScheduledReportService, opsSystemLogSink *service.OpsSystemLogSink, - soraMediaCleanup *service.SoraMediaCleanupService, schedulerSnapshot *service.SchedulerSnapshotService, tokenRefresh *service.TokenRefreshService, accountExpiry *service.AccountExpiryService, @@ -134,12 +133,6 @@ func provideCleanup( } return nil }}, - {"SoraMediaCleanupService", func() error { - if soraMediaCleanup != nil { - soraMediaCleanup.Stop() - } - return nil - }}, {"OpsAlertEvaluatorService", func() error { if opsAlertEvaluator != nil { opsAlertEvaluator.Stop() diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 70f3fa0cba..308c07cde7 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -355,7 +355,6 @@ export default { mySubscriptions: 'My Subscriptions', buySubscription: 'Recharge / Subscription', docs: 'Docs', - sora: 'Sora Studio', myOrders: 'My Orders', orderManagement: 'Orders', paymentDashboard: 'Payment Dashboard', @@ -4188,7 +4187,6 @@ export default { gateway: 'Gateway', email: 'Email', backup: 'Backup', - data: 'Sora Storage', payment: 'Payment', }, emailTabDisabledTitle: 'Email Verification Not Enabled', @@ -5176,6 +5174,7 @@ export default { } }, + // Payment System payment: { title: 'Recharge / Subscription', amountLabel: 'Amount', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index 4b42f46983..1e1b3cc5f5 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -355,7 +355,6 @@ export default { mySubscriptions: '我的订阅', buySubscription: '充值/订阅', docs: '文档', - sora: 'Sora 创作', myOrders: '我的订单', orderManagement: '订单管理', paymentDashboard: '支付概览', @@ -4353,7 +4352,6 @@ export default { gateway: '网关服务', email: '邮件设置', backup: '数据备份', - data: 'Sora 存储', payment: '支付设置', }, emailTabDisabledTitle: '邮箱验证未启用', @@ -5364,6 +5362,7 @@ export default { } }, + // Payment System payment: { title: '充值/订阅', amountLabel: '充值金额', From 6793503ed0bd150acbb34e6abd91fb03a083d8b7 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 19:02:25 +0800 Subject: [PATCH 12/34] chore: remove sora_client_enabled residuals from frontend types and store --- frontend/src/stores/app.ts | 1 - frontend/src/types/index.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/frontend/src/stores/app.ts b/frontend/src/stores/app.ts index 8dd294ef51..09e7362187 100644 --- a/frontend/src/stores/app.ts +++ b/frontend/src/stores/app.ts @@ -338,7 +338,6 @@ export const useAppStore = defineStore('app', () => { linuxdo_oauth_enabled: false, oidc_oauth_enabled: false, oidc_oauth_provider_name: 'OIDC', - sora_client_enabled: false, backend_mode_enabled: false, version: siteVersion.value } diff --git a/frontend/src/types/index.ts b/frontend/src/types/index.ts index 4ced3899d9..8b7e44c193 100644 --- a/frontend/src/types/index.ts +++ b/frontend/src/types/index.ts @@ -112,7 +112,6 @@ export interface PublicSettings { linuxdo_oauth_enabled: boolean oidc_oauth_enabled: boolean oidc_oauth_provider_name: string - sora_client_enabled: boolean backend_mode_enabled: boolean version: string } From b7edc3ed82006c28daa9c33b95cd6562c3f7f169 Mon Sep 17 00:00:00 2001 From: shuanbao0 Date: Sat, 11 Apr 2026 20:22:18 +0800 Subject: [PATCH 13/34] =?UTF-8?q?fix(gateway):=20=E5=85=BC=E5=AE=B9=20Curs?= =?UTF-8?q?or=20/v1/chat/completions=20=E7=9A=84=20Responses=20API=20body?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cursor 云端 (User-Agent: Go-http-client/2.0) 发往 /v1/chat/completions 的 body 使用 Responses API 格式: {"model":"gpt-5.4","input":[{"role":"system","content":"..."}],"stream":true} 原代码用 ChatCompletionsRequest 反序列化,该结构体没有 Input 字段, Cursor 的 input 数组被静默丢弃,ChatCompletionsToResponses 转换后产出 input: null,Codex 上游以 "Invalid type for 'input': expected a string, but got an object" 拒绝请求(上游 typeof null === 'object')。 修复:在 ForwardAsChatCompletions 里用 gjson 检测 body shape,当 input 存在且 messages 缺失时,跳过 Chat→Responses 转换,用 sjson 仅改写 model 字段后原样透传 body。billing 所需的 ServiceTier 和 Reasoning.Effort 通过 gjson 从 raw body 提取,下游 codex OAuth transform 路径保持不变。 测试:新增 openai_cursor_warmup_pipeline_test.go,覆盖 5 个 shape 检测 用例(正向/标准请求不误伤/两字段共存/空 body/JSON 回读)。 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../openai_cursor_warmup_pipeline_test.go | 155 ++++++++++++++++++ .../openai_gateway_chat_completions.go | 60 +++++-- 2 files changed, 203 insertions(+), 12 deletions(-) create mode 100644 backend/internal/service/openai_cursor_warmup_pipeline_test.go diff --git a/backend/internal/service/openai_cursor_warmup_pipeline_test.go b/backend/internal/service/openai_cursor_warmup_pipeline_test.go new file mode 100644 index 0000000000..8ade9dbbb4 --- /dev/null +++ b/backend/internal/service/openai_cursor_warmup_pipeline_test.go @@ -0,0 +1,155 @@ +package service + +import ( + "encoding/json" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" +) + +// TestCursorMixedShapeDetection covers the core invariant of the Cursor +// compatibility fix in ForwardAsChatCompletions: when a client POSTs a +// Responses-shaped body (has `input`, no `messages`) to /v1/chat/completions, +// the request must be forwarded as-is with only the `model` field rewritten. +// The raw `input` array (including Cursor's 80KB system prompt) must not be +// discarded or reshaped. +// +// Context: +// +// Before the fix, the handler unmarshaled the body into ChatCompletionsRequest, +// which has no Input field, silently dropping Cursor's input. The subsequent +// conversion produced `input: null`, which Codex upstreams reject with +// "Invalid type for 'input': expected a string, but got an object". +func TestCursorMixedShapeDetection(t *testing.T) { + // Representative Cursor cloud body — shape is what matters, content is + // abridged. Notice: `input` is a Responses-API array, there is no + // `messages` field at all, and `user`/`stream` are at the top level. + cursorBody := []byte(`{ + "user": "85df22e7463ab6c2", + "model": "gpt-5.4", + "stream": true, + "input": [ + {"role":"system","content":"You are GPT-5.4 running as a coding agent."}, + {"role":"user","content":"hello"} + ], + "service_tier": "auto", + "reasoning": {"effort": "high"} + }`) + + // --- Step 1: Shape detection (mirrors ForwardAsChatCompletions) --- + hasMessages := gjson.GetBytes(cursorBody, "messages").Exists() + hasInput := gjson.GetBytes(cursorBody, "input").Exists() + isResponsesShape := !hasMessages && hasInput + + require.True(t, isResponsesShape, + "Cursor body must be detected as Responses-shape (has input, no messages)") + + // --- Step 2: Model rewrite (mirrors the sjson.SetBytes branch) --- + const upstreamModel = "gpt-5.1-codex" + rewritten, err := sjson.SetBytes(cursorBody, "model", upstreamModel) + require.NoError(t, err) + + // --- Step 3: Invariants of the rewritten body --- + + // 3a. model must be rewritten to the upstream target. + assert.Equal(t, upstreamModel, gjson.GetBytes(rewritten, "model").String()) + + // 3b. input array must be preserved verbatim — no reshaping, no nulling. + inputResult := gjson.GetBytes(rewritten, "input") + require.True(t, inputResult.Exists(), "input field must still exist after rewrite") + require.True(t, inputResult.IsArray(), "input must still be an array (not null, not object)") + + items := inputResult.Array() + require.Len(t, items, 2, "both input items must be preserved") + assert.Equal(t, "system", items[0].Get("role").String()) + assert.Equal(t, "You are GPT-5.4 running as a coding agent.", + items[0].Get("content").String()) + assert.Equal(t, "user", items[1].Get("role").String()) + assert.Equal(t, "hello", items[1].Get("content").String()) + + // 3c. ALL other top-level fields must survive intact. + assert.Equal(t, "85df22e7463ab6c2", gjson.GetBytes(rewritten, "user").String()) + assert.Equal(t, true, gjson.GetBytes(rewritten, "stream").Bool()) + assert.Equal(t, "auto", gjson.GetBytes(rewritten, "service_tier").String()) + assert.Equal(t, "high", gjson.GetBytes(rewritten, "reasoning.effort").String()) + + // 3d. Final upstream body must NOT contain the old "input":null pattern. + assert.NotContains(t, string(rewritten), `"input":null`, + "rewritten body must not collapse input to null") +} + +// TestCursorMixedShapeDetection_NormalChatCompletionsUnaffected guards that +// the shape detection does NOT misfire on a standard Chat Completions request +// (one that has a `messages` array). Such requests must fall through to the +// existing ChatCompletionsToResponses conversion path. +func TestCursorMixedShapeDetection_NormalChatCompletionsUnaffected(t *testing.T) { + body := []byte(`{ + "model": "gpt-4o", + "messages": [{"role":"user","content":"hi"}], + "stream": true + }`) + + hasMessages := gjson.GetBytes(body, "messages").Exists() + hasInput := gjson.GetBytes(body, "input").Exists() + isResponsesShape := !hasMessages && hasInput + + assert.False(t, isResponsesShape, + "standard Chat Completions body must NOT be detected as Responses-shape") +} + +// TestCursorMixedShapeDetection_BothFieldsPrefersMessages guards the +// ambiguous case where a client sends both `messages` and `input`. We fall +// through to the normal conversion path (messages wins), since mixing the +// two is almost certainly a client bug and messages is the documented +// Chat Completions contract. +func TestCursorMixedShapeDetection_BothFieldsPrefersMessages(t *testing.T) { + body := []byte(`{ + "model": "gpt-4o", + "messages": [{"role":"user","content":"hi"}], + "input": [{"role":"user","content":"other"}] + }`) + + hasMessages := gjson.GetBytes(body, "messages").Exists() + hasInput := gjson.GetBytes(body, "input").Exists() + isResponsesShape := !hasMessages && hasInput + + assert.False(t, isResponsesShape, + "when both messages and input are present, must not take the Cursor shortcut") +} + +// TestCursorMixedShapeDetection_EmptyBody ensures a body with neither +// messages nor input is NOT taken as Cursor-shape (would hit the normal +// conversion and fail on its own with a clearer error). +func TestCursorMixedShapeDetection_EmptyBody(t *testing.T) { + body := []byte(`{"model":"gpt-5.4","stream":true}`) + + hasMessages := gjson.GetBytes(body, "messages").Exists() + hasInput := gjson.GetBytes(body, "input").Exists() + isResponsesShape := !hasMessages && hasInput + + assert.False(t, isResponsesShape, + "body with neither messages nor input must not be taken as Cursor shape") +} + +// TestCursorMixedShape_JSONRoundtrip ensures the rewritten body is still +// valid JSON and parseable back into a map without surprises — catches +// any encoding drift from sjson. +func TestCursorMixedShape_JSONRoundtrip(t *testing.T) { + cursorBody := []byte(`{"model":"gpt-5.4","stream":true,"input":[{"role":"user","content":"hi"}]}`) + + rewritten, err := sjson.SetBytes(cursorBody, "model", "gpt-5.1-codex") + require.NoError(t, err) + + var parsed map[string]any + require.NoError(t, json.Unmarshal(rewritten, &parsed)) + + assert.Equal(t, "gpt-5.1-codex", parsed["model"]) + assert.Equal(t, true, parsed["stream"]) + + inputArr, ok := parsed["input"].([]any) + require.True(t, ok, "input must decode to a Go []any after round-trip") + require.Len(t, inputArr, 1) +} diff --git a/backend/internal/service/openai_gateway_chat_completions.go b/backend/internal/service/openai_gateway_chat_completions.go index 9b3f69bc0f..c827fd7b5d 100644 --- a/backend/internal/service/openai_gateway_chat_completions.go +++ b/backend/internal/service/openai_gateway_chat_completions.go @@ -16,6 +16,8 @@ import ( "github.com/Wei-Shaw/sub2api/internal/pkg/logger" "github.com/Wei-Shaw/sub2api/internal/util/responseheaders" "github.com/gin-gonic/gin" + "github.com/tidwall/gjson" + "github.com/tidwall/sjson" "go.uber.org/zap" ) @@ -55,13 +57,52 @@ func (s *OpenAIGatewayService) ForwardAsChatCompletions( compatPromptCacheInjected = promptCacheKey != "" } - // 3. Convert to Responses and forward - // ChatCompletionsToResponses always sets Stream=true (upstream always streams). - responsesReq, err := apicompat.ChatCompletionsToResponses(&chatReq) - if err != nil { - return nil, fmt.Errorf("convert chat completions to responses: %w", err) + // 3. Build the upstream (Responses API) body. + // + // Cursor compatibility: some clients (notably Cursor cloud) send Responses + // API shaped bodies — `input: [...]` with no `messages` field — to the + // /v1/chat/completions URL. Running those through ChatCompletionsToResponses + // would silently drop Cursor's `input` array (the struct has no Input field) + // and produce `input: null`, which Codex upstreams reject with + // "Invalid type for 'input': expected a string, but got an object". + // + // Detect that shape and forward the raw body as-is, only rewriting `model` + // to the resolved upstream model. The downstream codex OAuth transform will + // still normalize store/stream/instructions/etc. + isResponsesShape := !gjson.GetBytes(body, "messages").Exists() && gjson.GetBytes(body, "input").Exists() + + var ( + responsesReq *apicompat.ResponsesRequest + responsesBody []byte + err error + ) + if isResponsesShape { + responsesBody, err = sjson.SetBytes(body, "model", upstreamModel) + if err != nil { + return nil, fmt.Errorf("rewrite model in responses-shape body: %w", err) + } + // Minimal stub populated from the raw body so downstream billing + // propagation (ServiceTier, ReasoningEffort) keeps working. + responsesReq = &apicompat.ResponsesRequest{ + Model: upstreamModel, + ServiceTier: gjson.GetBytes(responsesBody, "service_tier").String(), + } + if effort := gjson.GetBytes(responsesBody, "reasoning.effort").String(); effort != "" { + responsesReq.Reasoning = &apicompat.ResponsesReasoning{Effort: effort} + } + } else { + // Normal path: convert Chat Completions → Responses. + // ChatCompletionsToResponses always sets Stream=true (upstream always streams). + responsesReq, err = apicompat.ChatCompletionsToResponses(&chatReq) + if err != nil { + return nil, fmt.Errorf("convert chat completions to responses: %w", err) + } + responsesReq.Model = upstreamModel + responsesBody, err = json.Marshal(responsesReq) + if err != nil { + return nil, fmt.Errorf("marshal responses request: %w", err) + } } - responsesReq.Model = upstreamModel logFields := []zap.Field{ zap.Int64("account_id", account.ID), @@ -69,6 +110,7 @@ func (s *OpenAIGatewayService) ForwardAsChatCompletions( zap.String("billing_model", billingModel), zap.String("upstream_model", upstreamModel), zap.Bool("stream", clientStream), + zap.Bool("responses_shape", isResponsesShape), } if compatPromptCacheInjected { logFields = append(logFields, @@ -78,12 +120,6 @@ func (s *OpenAIGatewayService) ForwardAsChatCompletions( } logger.L().Debug("openai chat_completions: model mapping applied", logFields...) - // 4. Marshal Responses request body, then apply OAuth codex transform - responsesBody, err := json.Marshal(responsesReq) - if err != nil { - return nil, fmt.Errorf("marshal responses request: %w", err) - } - if account.Type == AccountTypeOAuth { var reqBody map[string]any if err := json.Unmarshal(responsesBody, &reqBody); err != nil { From c777fe5471380b0f7d357f54fa20468a6acb0986 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 21:10:55 +0800 Subject: [PATCH 14/34] docs: add built-in payment configuration guide and update README - Add docs/PAYMENT.md and docs/PAYMENT_CN.md with full payment setup guide - Mark Sub2ApiPay as deprecated in ecosystem tables (payment is now built-in) - Add built-in payment system to features list in all 3 READMEs --- .gitignore | 2 + README.md | 5 +- README_CN.md | 5 +- README_JA.md | 5 +- docs/PAYMENT.md | 272 ++++++++++++++++++++++++++++++++++++++++++++ docs/PAYMENT_CN.md | 274 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 557 insertions(+), 6 deletions(-) create mode 100644 docs/PAYMENT.md create mode 100644 docs/PAYMENT_CN.md diff --git a/.gitignore b/.gitignore index 297c1d6f03..1a92ea3e64 100644 --- a/.gitignore +++ b/.gitignore @@ -127,6 +127,8 @@ deploy/docker-compose.override.yml .gocache/ vite.config.js docs/* +!docs/PAYMENT.md +!docs/PAYMENT_CN.md .serena/ .codex/ frontend/coverage/ diff --git a/README.md b/README.md index 25bef4730b..b64a7647c5 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,9 @@ Sub2API is an AI API gateway platform designed to distribute and manage API quot - **Smart Scheduling** - Intelligent account selection with sticky sessions - **Concurrency Control** - Per-user and per-account concurrency limits - **Rate Limiting** - Configurable request and token rate limits +- **Built-in Payment System** - Supports EasyPay, Alipay, WeChat Pay, and Stripe for user self-service top-up, no separate payment service needed ([Configuration Guide](docs/PAYMENT.md)) - **Admin Dashboard** - Web interface for monitoring and management -- **External System Integration** - Embed external systems (e.g. payment, ticketing) via iframe to extend the admin dashboard +- **External System Integration** - Embed external systems (e.g. ticketing) via iframe to extend the admin dashboard ## ❤️ Sponsors @@ -88,7 +89,7 @@ Community projects that extend or integrate with Sub2API: | Project | Description | Features | |---------|-------------|----------| -| [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) | Self-service payment system | Self-service top-up and subscription purchase; supports YiPay protocol, WeChat Pay, Alipay, Stripe; embeddable via iframe | +| ~~[Sub2ApiPay](https://github.com/touwaeriol/sub2apipay)~~ | ~~Self-service payment system~~ | **Now Built-in** — Payment is now integrated into Sub2API, no separate deployment needed. See [Payment Configuration Guide](docs/PAYMENT.md) | | [sub2api-mobile](https://github.com/ckken/sub2api-mobile) | Mobile admin console | Cross-platform app (iOS/Android/Web) for user management, account management, monitoring dashboard, and multi-backend switching; built with Expo + React Native | ## Tech Stack diff --git a/README_CN.md b/README_CN.md index 003a9530cb..5b6be04ccd 100644 --- a/README_CN.md +++ b/README_CN.md @@ -41,8 +41,9 @@ Sub2API 是一个 AI API 网关平台,用于分发和管理 AI 产品订阅的 - **智能调度** - 智能账号选择,支持粘性会话 - **并发控制** - 用户级和账号级并发限制 - **速率限制** - 可配置的请求和 Token 速率限制 +- **内置支付系统** - 支持 EasyPay 易支付、支付宝官方、微信官方、Stripe,用户自助充值,无需独立部署支付服务([配置指南](docs/PAYMENT_CN.md)) - **管理后台** - Web 界面进行监控和管理 -- **外部系统集成** - 支持通过 iframe 嵌入外部系统(如支付、工单等),扩展管理后台功能 +- **外部系统集成** - 支持通过 iframe 嵌入外部系统(如工单等),扩展管理后台功能 ## ❤️ 赞助商 @@ -87,7 +88,7 @@ Sub2API 是一个 AI API 网关平台,用于分发和管理 AI 产品订阅的 | 项目 | 说明 | 功能 | |------|------|------| -| [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) | 自助支付系统 | 用户自助充值、自助订阅购买;兼容易支付协议、微信官方支付、支付宝官方支付、Stripe;支持 iframe 嵌入管理后台 | +| ~~[Sub2ApiPay](https://github.com/touwaeriol/sub2apipay)~~ | ~~自助支付系统~~ | **已内置** — 支付功能已集成到 Sub2API 中,无需独立部署。详见 [支付配置指南](docs/PAYMENT_CN.md) | | [sub2api-mobile](https://github.com/ckken/sub2api-mobile) | 移动端管理控制台 | 跨平台应用(iOS/Android/Web),支持用户管理、账号管理、监控看板、多后端切换;基于 Expo + React Native 构建 | ## 技术栈 diff --git a/README_JA.md b/README_JA.md index 818e944b68..4e7ae76532 100644 --- a/README_JA.md +++ b/README_JA.md @@ -42,8 +42,9 @@ Sub2API は、AI 製品のサブスクリプションから API クォータを - **スマートスケジューリング** - スティッキーセッション付きのインテリジェントなアカウント選択 - **同時実行制御** - ユーザーごと・アカウントごとの同時実行数制限 - **レート制限** - 設定可能なリクエスト数およびトークンレート制限 +- **内蔵決済システム** - EasyPay、Alipay、WeChat Pay、Stripe に対応。ユーザーのセルフサービスチャージが可能で、別途決済サービスのデプロイは不要([設定ガイド](docs/PAYMENT.md)) - **管理ダッシュボード** - 監視・管理のための Web インターフェース -- **外部システム連携** - 外部システム(決済、チケット管理など)を iframe 経由で管理ダッシュボードに埋め込み可能 +- **外部システム連携** - 外部システム(チケット管理など)を iframe 経由で管理ダッシュボードに埋め込み可能 ## ❤️ スポンサー @@ -87,7 +88,7 @@ Sub2API を拡張・統合するコミュニティプロジェクト: | プロジェクト | 説明 | 機能 | |---------|-------------|----------| -| [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) | セルフサービス決済システム | セルフサービスによるチャージおよびサブスクリプション購入。YiPay プロトコル、WeChat Pay、Alipay、Stripe 対応。iframe での埋め込み可能 | +| ~~[Sub2ApiPay](https://github.com/touwaeriol/sub2apipay)~~ | ~~セルフサービス決済システム~~ | **内蔵済み** — 決済機能は Sub2API に統合されました。別途デプロイは不要です。[決済設定ガイド](docs/PAYMENT.md)をご参照ください | | [sub2api-mobile](https://github.com/ckken/sub2api-mobile) | モバイル管理コンソール | ユーザー管理、アカウント管理、監視ダッシュボード、マルチバックエンド切り替えが可能なクロスプラットフォームアプリ(iOS/Android/Web)。Expo + React Native で構築 | ## 技術スタック diff --git a/docs/PAYMENT.md b/docs/PAYMENT.md new file mode 100644 index 0000000000..c0fc1fdc97 --- /dev/null +++ b/docs/PAYMENT.md @@ -0,0 +1,272 @@ +# Payment System Configuration Guide + +Sub2API has a built-in payment system that enables user self-service top-up without deploying a separate payment service. + +--- + +## Table of Contents + +- [Supported Payment Methods](#supported-payment-methods) +- [Quick Start](#quick-start) +- [System Settings](#system-settings) +- [Provider Configuration](#provider-configuration) +- [Provider Instance Management](#provider-instance-management) +- [Webhook Configuration](#webhook-configuration) +- [Payment Flow](#payment-flow) +- [Migrating from Sub2ApiPay](#migrating-from-sub2apipay) + +--- + +## Supported Payment Methods + +| Provider | Payment Methods | Description | +|----------|----------------|-------------| +| **EasyPay** | Alipay, WeChat Pay | Third-party aggregation via EasyPay protocol | +| **Alipay (Direct)** | PC Page Pay, H5 Mobile Pay | Direct integration with Alipay Open Platform, auto-switches by device | +| **WeChat Pay (Direct)** | Native QR Code, H5 Pay | Direct integration with WeChat Pay APIv3, mobile-first H5 | +| **Stripe** | Card, Alipay, WeChat Pay, Link, etc. | International payments, multi-currency support | + +> Alipay/WeChat Pay direct and EasyPay can coexist. Direct channels connect to payment APIs directly with lower fees; EasyPay aggregates through third-party platforms with easier setup. + +--- + +## Quick Start + +1. Go to Admin Dashboard → **Settings** → **Payment Settings** tab +2. Enable **Payment** +3. Configure basic parameters (amount range, timeout, etc.) +4. Add at least one provider instance in **Provider Management** +5. Users can now top up from the frontend + +--- + +## System Settings + +Configure the following in Admin Dashboard **Settings → Payment Settings**: + +### Basic Settings + +| Setting | Description | Default | +|---------|-------------|---------| +| **Enable Payment** | Enable or disable the payment system | Off | +| **Product Name Prefix** | Prefix shown on payment page | - | +| **Product Name Suffix** | Suffix (e.g., "Credits") | - | +| **Minimum Amount** | Minimum single top-up amount | 1 | +| **Maximum Amount** | Maximum single top-up amount (empty = unlimited) | - | +| **Daily Limit** | Per-user daily cumulative limit (empty = unlimited) | - | +| **Order Timeout** | Order timeout in minutes (minimum 1) | 5 | +| **Max Pending Orders** | Maximum concurrent pending orders per user | 3 | +| **Load Balance Strategy** | Strategy for selecting provider instances | Least Amount | + +### Load Balance Strategies + +| Strategy | Description | +|----------|-------------| +| **Round Robin** | Distribute orders to instances in rotation | +| **Least Amount** | Prefer instances with the lowest daily cumulative amount | + +### Cancel Rate Limiting + +Prevents users from repeatedly creating and canceling orders: + +| Setting | Description | +|---------|-------------| +| **Enable Limit** | Toggle | +| **Window Mode** | Sliding / Fixed window | +| **Time Window** | Window duration | +| **Window Unit** | Minutes / Hours | +| **Max Cancels** | Maximum cancellations allowed within the window | + +### Help Information + +| Setting | Description | +|---------|-------------| +| **Help Image** | Customer service QR code or help image (supports upload) | +| **Help Text** | Instructions displayed on the payment page | + +--- + +## Provider Configuration + +Each provider type requires different credentials. Select the type when adding a new provider instance in **Provider Management → Add Provider**. + +### EasyPay + +Compatible with any payment service that implements the EasyPay protocol. + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **Merchant ID (PID)** | EasyPay merchant ID | Yes | +| **Merchant Key (PKey)** | EasyPay merchant secret key | Yes | +| **API Base URL** | EasyPay API base address | Yes | +| **Notify URL** | Async callback URL for payment success | Yes | +| **Return URL** | Redirect URL after payment completion | No | +| **Alipay Channel ID** | Specify Alipay channel (optional) | No | +| **WeChat Channel ID** | Specify WeChat channel (optional) | No | + +### Alipay (Direct) + +Direct integration with Alipay Open Platform. Supports PC page pay and H5 mobile pay. + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **AppID** | Alipay application AppID | Yes | +| **Private Key** | RSA2 application private key | Yes | +| **Alipay Public Key** | Alipay public key | Yes | +| **Notify URL** | Async callback URL | Yes | +| **Return URL** | Redirect URL after payment | No | + +### WeChat Pay (Direct) + +Direct integration with WeChat Pay APIv3. Supports Native QR code and H5 payment. + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **AppID** | WeChat Pay AppID | Yes | +| **Merchant ID (MchID)** | WeChat Pay merchant ID | Yes | +| **Merchant API Private Key** | Merchant API private key (PEM format) | Yes | +| **Certificate Serial Number** | Merchant certificate serial number | Yes | +| **APIv3 Key** | 32-byte APIv3 key | Yes | +| **WeChat Pay Public Key** | WeChat Pay public key (PEM format) | Yes | +| **WeChat Pay Public Key ID** | WeChat Pay public key ID | Yes | +| **Notify URL** | Async callback URL | Yes | + +### Stripe + +International payment platform supporting multiple payment methods and currencies. + +| Parameter | Description | Required | +|-----------|-------------|----------| +| **Secret Key** | Stripe secret key (`sk_live_...` or `sk_test_...`) | Yes | +| **Publishable Key** | Stripe publishable key (`pk_live_...` or `pk_test_...`) | Yes | +| **Webhook Secret** | Stripe Webhook signing secret (`whsec_...`) | Yes | + +--- + +## Provider Instance Management + +You can create **multiple instances** of the same provider type for load balancing and risk control: + +- **Multi-instance load balancing** — Distribute orders via round-robin or least-amount strategy +- **Independent limits** — Each instance can have its own min/max amount and daily limit +- **Independent toggle** — Enable/disable individual instances without affecting others +- **Refund control** — Enable or disable refunds per instance +- **Payment methods** — Each instance can support a subset of payment methods +- **Ordering** — Drag to reorder instances + +### Instance Limit Configuration + +Each instance supports these limits: + +| Limit | Description | +|-------|-------------| +| **Minimum Amount** | Minimum order amount accepted by this instance | +| **Maximum Amount** | Maximum order amount accepted by this instance | +| **Daily Limit** | Daily cumulative transaction limit for this instance | + +> During load balancing, instances that exceed their limits are automatically skipped. + +--- + +## Webhook Configuration + +Payment callbacks are essential for the payment system to work correctly. + +### Callback URL Format + +| Provider | Callback URL | +|----------|-------------| +| **EasyPay** | `https://your-domain.com/api/v1/payment/easypay/notify` | +| **Alipay (Direct)** | `https://your-domain.com/api/v1/payment/alipay/notify` | +| **WeChat Pay (Direct)** | `https://your-domain.com/api/v1/payment/wxpay/notify` | +| **Stripe** | `https://your-domain.com/api/v1/payment/stripe/webhook` | + +> Replace `your-domain.com` with your actual domain. + +### Stripe Webhook Setup + +1. Log in to [Stripe Dashboard](https://dashboard.stripe.com/) +2. Go to **Developers → Webhooks** +3. Add an endpoint with the callback URL +4. Subscribe to events: `payment_intent.succeeded`, `payment_intent.payment_failed` +5. Copy the generated Webhook Secret (`whsec_...`) to your provider configuration + +### Important Notes + +- Callback URLs must use **HTTPS** (required by Stripe, strongly recommended for others) +- Ensure your firewall allows callback requests from payment platforms +- The system automatically verifies callback signatures to prevent forgery +- Balance top-up is processed automatically upon successful payment — no manual intervention needed + +--- + +## Payment Flow + +``` +User selects amount and payment method + │ + ▼ + Create Order (PENDING) + ├─ Validate amount range, pending order count, daily limit + ├─ Load balance to select provider instance + └─ Call provider to get payment info + │ + ▼ + User completes payment + ├─ EasyPay → QR code / H5 redirect + ├─ Alipay → PC page pay / H5 mobile pay + ├─ WeChat Pay → Native QR / H5 pay + └─ Stripe → Payment Element (card/Alipay/WeChat/etc.) + │ + ▼ + Webhook callback verified → Order PAID + │ + ▼ + Auto top-up to user balance → Order COMPLETED +``` + +### Order Status Reference + +| Status | Description | +|--------|-------------| +| `PENDING` | Waiting for user to complete payment | +| `PAID` | Payment confirmed, awaiting balance credit | +| `COMPLETED` | Balance credited successfully | +| `EXPIRED` | Timed out without payment | +| `CANCELLED` | Cancelled by user | +| `FAILED` | Balance credit failed, admin can retry | +| `REFUND_REQUESTED` | Refund requested | +| `REFUNDING` | Refund in progress | +| `REFUNDED` | Refund completed | + +### Timeout and Fallback + +- Before marking an order as expired, the background job queries the upstream payment status first +- If the user has actually paid but the callback was delayed, the system will reconcile automatically +- The background job runs every 60 seconds to check for timed-out orders + +--- + +## Migrating from Sub2ApiPay + +If you previously used [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) as an external payment system, you can migrate to the built-in payment system: + +### Key Differences + +| Aspect | Sub2ApiPay | Built-in Payment | +|--------|-----------|-----------------| +| Deployment | Separate service (Next.js + PostgreSQL) | Built into Sub2API, no extra deployment | +| Payment Methods | EasyPay, Alipay, WeChat, Stripe | Same | +| Configuration | Environment variables + separate admin UI | Unified in Sub2API admin dashboard | +| Top-up Integration | Via Admin API callback | Internal processing, more reliable | +| Subscription Plans | Supported | Not yet (planned) | +| Order Management | Separate admin interface | Integrated in Sub2API admin dashboard | + +### Migration Steps + +1. Enable payment in Sub2API admin dashboard and configure providers (use the same payment credentials) +2. Update webhook callback URLs to Sub2API's callback endpoints +3. Verify that new orders are processed correctly via built-in payment +4. Decommission the Sub2ApiPay service + +> **Note**: Historical order data from Sub2ApiPay will not be automatically migrated. Keep Sub2ApiPay running for a while to access historical records. diff --git a/docs/PAYMENT_CN.md b/docs/PAYMENT_CN.md new file mode 100644 index 0000000000..33a5ace365 --- /dev/null +++ b/docs/PAYMENT_CN.md @@ -0,0 +1,274 @@ +# 支付系统配置指南 + +Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支付服务。 + +--- + +## 目录 + +- [支持的支付方式](#支持的支付方式) +- [快速开始](#快速开始) +- [系统设置](#系统设置) +- [服务商配置](#服务商配置) +- [服务商实例管理](#服务商实例管理) +- [Webhook 配置](#webhook-配置) +- [支付流程](#支付流程) +- [从 Sub2ApiPay 迁移](#从-sub2apipay-迁移) + +--- + +## 支持的支付方式 + +| 服务商 | 支付方式 | 说明 | +|--------|---------|------| +| **EasyPay(易支付)** | 支付宝、微信支付 | 兼容易支付协议的第三方聚合支付 | +| **支付宝官方** | 支付宝 PC 页面支付、H5 手机网站支付 | 直接对接支付宝开放平台,自动根据终端切换 | +| **微信官方** | Native 扫码支付、H5 支付 | 直接对接微信支付 APIv3,移动端优先 H5 | +| **Stripe** | 银行卡、支付宝、微信支付、Link 等 | 国际支付,支持多币种 | + +> 支付宝官方 / 微信官方与 EasyPay 可以共存。官方渠道直接对接 API,资金直达商户账户,手续费更低;EasyPay 通过第三方平台聚合,接入门槛更低。 + +--- + +## 快速开始 + +1. 进入管理后台 → **设置** → **支付设置** 标签页 +2. 开启 **启用支付** +3. 配置基本参数(金额范围、超时时间等) +4. 在 **服务商管理** 中添加至少一个服务商实例 +5. 用户即可在前端页面进行充值 + +--- + +## 系统设置 + +在管理后台 **设置 → 支付设置** 中配置以下参数: + +### 基本设置 + +| 设置项 | 说明 | 默认值 | +|--------|------|--------| +| **启用支付** | 启用或禁用支付系统 | 关闭 | +| **商品名前缀** | 支付页面显示的商品名前缀 | - | +| **商品名后缀** | 商品名后缀(如"元") | - | +| **最低金额** | 单笔最低充值金额 | 1 | +| **最高金额** | 单笔最高充值金额(留空表示不限制) | - | +| **每日限额** | 每用户每日累计充值上限(留空表示不限制) | - | +| **订单超时时间** | 订单超时分钟数,至少 1 分钟 | 5 | +| **最大待支付订单数** | 同一用户最大并行待支付订单数 | 3 | +| **负载均衡策略** | 多服务商实例时的选择策略 | 最少金额 | + +### 负载均衡策略 + +| 策略 | 说明 | +|------|------| +| **轮询(round-robin)** | 按顺序轮流分配到各服务商实例 | +| **最少金额(least-amount)** | 优先分配到当日累计金额最少的实例 | + +### 取消频率限制 + +防止用户频繁创建并取消订单: + +| 设置项 | 说明 | +|--------|------| +| **启用限制** | 开关 | +| **窗口模式** | 滚动窗口 / 固定窗口 | +| **时间窗口** | 窗口长度 | +| **窗口单位** | 分钟 / 小时 | +| **最大次数** | 窗口内允许的最大取消次数 | + +### 帮助信息 + +| 设置项 | 说明 | +|--------|------| +| **帮助图片** | 充值页面显示的客服二维码等图片(支持上传) | +| **帮助文本** | 充值页面显示的说明文字 | + +--- + +## 服务商配置 + +每种服务商需要不同的凭证和参数。在 **服务商管理 → 添加服务商** 中选择类型后填写。 + +### EasyPay(易支付) + +兼容任何 EasyPay 协议的支付服务商。 + +| 参数 | 说明 | 必填 | +|------|------|------| +| **商户 ID(PID)** | EasyPay 商户 ID | 是 | +| **商户密钥(PKey)** | EasyPay 商户密钥 | 是 | +| **API 地址** | EasyPay API 基础地址 | 是 | +| **异步回调地址** | 支付成功后的回调 URL | 是 | +| **同步跳转地址** | 支付完成后的跳转 URL | 否 | +| **支付宝通道 ID** | 指定支付宝通道(可选) | 否 | +| **微信通道 ID** | 指定微信通道(可选) | 否 | + +> **EasyPay 推荐**:[ZPay](https://z-pay.cn) 支持个人用户(无营业执照)每日 1 万元以内交易。支付渠道的安全性和合规性请自行鉴别。 + +### 支付宝官方 + +直接对接支付宝开放平台,支持 PC 页面支付和 H5 手机网站支付。 + +| 参数 | 说明 | 必填 | +|------|------|------| +| **AppID** | 支付宝应用 AppID | 是 | +| **应用私钥** | RSA2 应用私钥 | 是 | +| **支付宝公钥** | 支付宝公钥 | 是 | +| **异步回调地址** | 支付成功后的回调 URL | 是 | +| **同步跳转地址** | 支付完成后的跳转 URL | 否 | + +### 微信官方 + +直接对接微信支付 APIv3,支持 Native 扫码支付和 H5 支付。 + +| 参数 | 说明 | 必填 | +|------|------|------| +| **AppID** | 微信支付 AppID | 是 | +| **商户号(MchID)** | 微信支付商户号 | 是 | +| **商户 API 私钥** | 商户 API 私钥(PEM 格式) | 是 | +| **商户证书序列号** | 商户证书序列号 | 是 | +| **APIv3 密钥** | 32 位 APIv3 密钥 | 是 | +| **微信支付公钥** | 微信支付公钥(PEM 格式) | 是 | +| **微信支付公钥 ID** | 微信支付公钥 ID | 是 | +| **异步回调地址** | 支付成功后的回调 URL | 是 | + +### Stripe + +国际支付平台,支持多种支付方式和币种。 + +| 参数 | 说明 | 必填 | +|------|------|------| +| **Secret Key** | Stripe 密钥(`sk_live_...` 或 `sk_test_...`) | 是 | +| **Publishable Key** | Stripe 可公开密钥(`pk_live_...` 或 `pk_test_...`) | 是 | +| **Webhook Secret** | Stripe Webhook 签名密钥(`whsec_...`) | 是 | + +--- + +## 服务商实例管理 + +同一种服务商可以创建**多个实例**,实现负载均衡和风控: + +- **多实例负载均衡** — 按轮询或最少金额策略分流订单 +- **独立限额** — 每个实例可独立配置单笔最小/最大金额和每日限额 +- **独立启停** — 可单独启用/禁用某个实例,不影响其他实例 +- **退款控制** — 每个实例可单独开启或关闭退款功能 +- **支付方式** — 每个实例可选择支持的支付方式子集 +- **排序** — 拖拽调整实例顺序 + +### 实例限额配置 + +每个实例支持以下限额: + +| 限额项 | 说明 | +|--------|------| +| **单笔最小金额** | 该实例接受的最小订单金额 | +| **单笔最大金额** | 该实例接受的最大订单金额 | +| **每日限额** | 该实例每日累计交易上限 | + +> 负载均衡时,系统会自动跳过超出限额的实例。 + +--- + +## Webhook 配置 + +支付回调是支付系统的核心环节,必须正确配置: + +### 回调地址格式 + +| 服务商 | 回调地址 | +|--------|---------| +| **EasyPay** | `https://your-domain.com/api/v1/payment/easypay/notify` | +| **支付宝官方** | `https://your-domain.com/api/v1/payment/alipay/notify` | +| **微信官方** | `https://your-domain.com/api/v1/payment/wxpay/notify` | +| **Stripe** | `https://your-domain.com/api/v1/payment/stripe/webhook` | + +> 将 `your-domain.com` 替换为你的实际域名。 + +### Stripe Webhook 设置 + +1. 登录 [Stripe Dashboard](https://dashboard.stripe.com/) +2. 进入 **Developers → Webhooks** +3. 添加端点,填写回调地址 +4. 订阅事件:`payment_intent.succeeded`、`payment_intent.payment_failed` +5. 将生成的 Webhook Secret(`whsec_...`)填入服务商配置 + +### 注意事项 + +- 回调地址必须是 **HTTPS**(Stripe 强制要求,其他服务商强烈推荐) +- 确保服务器防火墙允许支付平台的回调请求 +- 系统会自动进行签名验证,防止伪造回调 +- 支付成功后自动完成余额充值,无需人工干预 + +--- + +## 支付流程 + +``` +用户选择充值金额和支付方式 + │ + ▼ + 创建订单 (PENDING) + ├─ 校验金额范围、待支付订单数、每日限额 + ├─ 负载均衡选择服务商实例 + └─ 调用服务商获取支付信息 + │ + ▼ + 用户完成支付 + ├─ EasyPay → 扫码 / H5 跳转 + ├─ 支付宝官方 → PC 页面支付 / H5 手机网站支付 + ├─ 微信官方 → Native 扫码 / H5 支付 + └─ Stripe → Payment Element(银行卡/支付宝/微信等) + │ + ▼ + 支付回调验签 → 订单 PAID + │ + ▼ + 自动充值到用户余额 → 订单 COMPLETED +``` + +### 订单状态说明 + +| 状态 | 说明 | +|------|------| +| `PENDING` | 待支付,等待用户完成支付 | +| `PAID` | 已支付,等待充值到账 | +| `COMPLETED` | 已完成,余额已到账 | +| `EXPIRED` | 已过期,超时未支付 | +| `CANCELLED` | 已取消,用户主动取消 | +| `FAILED` | 充值失败,可管理员重试 | +| `REFUND_REQUESTED` | 已申请退款 | +| `REFUNDING` | 退款处理中 | +| `REFUNDED` | 已退款 | + +### 超时与兜底 + +- 订单超时后,后台任务会先查询上游支付状态再标记过期 +- 如果用户实际已支付但回调延迟,系统会通过查询补单 +- 后台任务每 60 秒执行一次超时检查 + +--- + +## 从 Sub2ApiPay 迁移 + +如果你之前使用 [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) 作为外部支付系统,现在可以迁移到内置支付: + +### 主要差异 + +| 对比项 | Sub2ApiPay | 内置支付 | +|--------|-----------|---------| +| 部署方式 | 独立服务(Next.js + PostgreSQL) | 内置于 Sub2API,无需额外部署 | +| 支付方式 | EasyPay、支付宝、微信、Stripe | 相同 | +| 配置方式 | 环境变量 + 独立管理后台 | Sub2API 管理后台内统一配置 | +| 充值对接 | 通过 Admin API 回调 | 内部直接处理,更可靠 | +| 订阅套餐 | 支持 | 暂不支持(计划中) | +| 订单管理 | 独立管理界面 | 集成在 Sub2API 管理后台 | + +### 迁移步骤 + +1. 在 Sub2API 管理后台启用支付并配置服务商(使用相同的支付凭证) +2. 更新 Webhook 回调地址为 Sub2API 的回调地址 +3. 确认新订单通过内置支付正常处理 +4. 停用 Sub2ApiPay 服务 + +> **注意**:Sub2ApiPay 中的历史订单数据不会自动迁移。建议保留 Sub2ApiPay 一段时间以便查询历史记录。 From 1a686239ed290f810493228671f9f03fd8367da7 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 20:15:59 +0800 Subject: [PATCH 15/34] fix(docs): correct webhook paths and provider config in payment guide - Fix webhook URLs: /payment/webhook/ not /payment//notify - Remove notifyUrl/returnUrl from provider config tables (auto-generated by UI) - Adjust wxpay publicKeyId/certSerial to match frontend optional marking --- docs/PAYMENT.md | 27 +++++++++++++-------------- docs/PAYMENT_CN.md | 27 +++++++++++++-------------- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/docs/PAYMENT.md b/docs/PAYMENT.md index c0fc1fdc97..accd4a98a2 100644 --- a/docs/PAYMENT.md +++ b/docs/PAYMENT.md @@ -90,6 +90,8 @@ Prevents users from repeatedly creating and canceling orders: Each provider type requires different credentials. Select the type when adding a new provider instance in **Provider Management → Add Provider**. +> **Callback URLs are auto-generated**: When adding a provider, the Notify URL and Return URL are automatically constructed from your site domain. You only need to confirm the domain is correct. + ### EasyPay Compatible with any payment service that implements the EasyPay protocol. @@ -99,8 +101,6 @@ Compatible with any payment service that implements the EasyPay protocol. | **Merchant ID (PID)** | EasyPay merchant ID | Yes | | **Merchant Key (PKey)** | EasyPay merchant secret key | Yes | | **API Base URL** | EasyPay API base address | Yes | -| **Notify URL** | Async callback URL for payment success | Yes | -| **Return URL** | Redirect URL after payment completion | No | | **Alipay Channel ID** | Specify Alipay channel (optional) | No | | **WeChat Channel ID** | Specify WeChat channel (optional) | No | @@ -113,8 +113,6 @@ Direct integration with Alipay Open Platform. Supports PC page pay and H5 mobile | **AppID** | Alipay application AppID | Yes | | **Private Key** | RSA2 application private key | Yes | | **Alipay Public Key** | Alipay public key | Yes | -| **Notify URL** | Async callback URL | Yes | -| **Return URL** | Redirect URL after payment | No | ### WeChat Pay (Direct) @@ -125,11 +123,10 @@ Direct integration with WeChat Pay APIv3. Supports Native QR code and H5 payment | **AppID** | WeChat Pay AppID | Yes | | **Merchant ID (MchID)** | WeChat Pay merchant ID | Yes | | **Merchant API Private Key** | Merchant API private key (PEM format) | Yes | -| **Certificate Serial Number** | Merchant certificate serial number | Yes | | **APIv3 Key** | 32-byte APIv3 key | Yes | | **WeChat Pay Public Key** | WeChat Pay public key (PEM format) | Yes | -| **WeChat Pay Public Key ID** | WeChat Pay public key ID | Yes | -| **Notify URL** | Async callback URL | Yes | +| **WeChat Pay Public Key ID** | WeChat Pay public key ID | No | +| **Certificate Serial Number** | Merchant certificate serial number | No | ### Stripe @@ -174,14 +171,16 @@ Payment callbacks are essential for the payment system to work correctly. ### Callback URL Format -| Provider | Callback URL | -|----------|-------------| -| **EasyPay** | `https://your-domain.com/api/v1/payment/easypay/notify` | -| **Alipay (Direct)** | `https://your-domain.com/api/v1/payment/alipay/notify` | -| **WeChat Pay (Direct)** | `https://your-domain.com/api/v1/payment/wxpay/notify` | -| **Stripe** | `https://your-domain.com/api/v1/payment/stripe/webhook` | +When adding a provider, the system auto-generates callback URLs from your site domain: -> Replace `your-domain.com` with your actual domain. +| Provider | Callback Path | +|----------|-------------| +| **EasyPay** | `https://your-domain.com/api/v1/payment/webhook/easypay` | +| **Alipay (Direct)** | `https://your-domain.com/api/v1/payment/webhook/alipay` | +| **WeChat Pay (Direct)** | `https://your-domain.com/api/v1/payment/webhook/wxpay` | +| **Stripe** | `https://your-domain.com/api/v1/payment/webhook/stripe` | + +> Replace `your-domain.com` with your actual domain. For EasyPay / Alipay / WeChat Pay, the callback URL is auto-filled when adding the provider — no manual configuration needed. ### Stripe Webhook Setup diff --git a/docs/PAYMENT_CN.md b/docs/PAYMENT_CN.md index 33a5ace365..2d0371bd70 100644 --- a/docs/PAYMENT_CN.md +++ b/docs/PAYMENT_CN.md @@ -90,6 +90,8 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 每种服务商需要不同的凭证和参数。在 **服务商管理 → 添加服务商** 中选择类型后填写。 +> **回调地址自动生成**:添加服务商时,异步回调地址(Notify URL)和同步跳转地址(Return URL)由系统根据你的站点域名自动拼接,无需手动填写。管理员只需确认域名正确即可。 + ### EasyPay(易支付) 兼容任何 EasyPay 协议的支付服务商。 @@ -99,8 +101,6 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 | **商户 ID(PID)** | EasyPay 商户 ID | 是 | | **商户密钥(PKey)** | EasyPay 商户密钥 | 是 | | **API 地址** | EasyPay API 基础地址 | 是 | -| **异步回调地址** | 支付成功后的回调 URL | 是 | -| **同步跳转地址** | 支付完成后的跳转 URL | 否 | | **支付宝通道 ID** | 指定支付宝通道(可选) | 否 | | **微信通道 ID** | 指定微信通道(可选) | 否 | @@ -115,8 +115,6 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 | **AppID** | 支付宝应用 AppID | 是 | | **应用私钥** | RSA2 应用私钥 | 是 | | **支付宝公钥** | 支付宝公钥 | 是 | -| **异步回调地址** | 支付成功后的回调 URL | 是 | -| **同步跳转地址** | 支付完成后的跳转 URL | 否 | ### 微信官方 @@ -127,11 +125,10 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 | **AppID** | 微信支付 AppID | 是 | | **商户号(MchID)** | 微信支付商户号 | 是 | | **商户 API 私钥** | 商户 API 私钥(PEM 格式) | 是 | -| **商户证书序列号** | 商户证书序列号 | 是 | | **APIv3 密钥** | 32 位 APIv3 密钥 | 是 | | **微信支付公钥** | 微信支付公钥(PEM 格式) | 是 | -| **微信支付公钥 ID** | 微信支付公钥 ID | 是 | -| **异步回调地址** | 支付成功后的回调 URL | 是 | +| **微信支付公钥 ID** | 微信支付公钥 ID | 否 | +| **商户证书序列号** | 商户证书序列号 | 否 | ### Stripe @@ -176,14 +173,16 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 ### 回调地址格式 -| 服务商 | 回调地址 | -|--------|---------| -| **EasyPay** | `https://your-domain.com/api/v1/payment/easypay/notify` | -| **支付宝官方** | `https://your-domain.com/api/v1/payment/alipay/notify` | -| **微信官方** | `https://your-domain.com/api/v1/payment/wxpay/notify` | -| **Stripe** | `https://your-domain.com/api/v1/payment/stripe/webhook` | +添加服务商时,系统会自动根据站点域名拼接回调地址,格式如下: -> 将 `your-domain.com` 替换为你的实际域名。 +| 服务商 | 回调路径 | +|--------|---------| +| **EasyPay** | `https://your-domain.com/api/v1/payment/webhook/easypay` | +| **支付宝官方** | `https://your-domain.com/api/v1/payment/webhook/alipay` | +| **微信官方** | `https://your-domain.com/api/v1/payment/webhook/wxpay` | +| **Stripe** | `https://your-domain.com/api/v1/payment/webhook/stripe` | + +> 将 `your-domain.com` 替换为你的实际域名。EasyPay / 支付宝 / 微信的回调地址在添加服务商时自动填入,无需手动配置。 ### Stripe Webhook 设置 From 3b0dc929523b27bb2e69462e4cb91f6c5ae329ff Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 20:35:57 +0800 Subject: [PATCH 16/34] docs: move ZPay recommendation to overview section --- docs/PAYMENT.md | 2 ++ docs/PAYMENT_CN.md | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/PAYMENT.md b/docs/PAYMENT.md index accd4a98a2..8f76d393b5 100644 --- a/docs/PAYMENT.md +++ b/docs/PAYMENT.md @@ -28,6 +28,8 @@ Sub2API has a built-in payment system that enables user self-service top-up with > Alipay/WeChat Pay direct and EasyPay can coexist. Direct channels connect to payment APIs directly with lower fees; EasyPay aggregates through third-party platforms with easier setup. +> **EasyPay Recommendation**: [ZPay](https://z-pay.cn/?uid=23808) is recommended as an EasyPay provider (link contains the author's referral code — feel free to remove it). ZPay supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them. + --- ## Quick Start diff --git a/docs/PAYMENT_CN.md b/docs/PAYMENT_CN.md index 2d0371bd70..8c895a322c 100644 --- a/docs/PAYMENT_CN.md +++ b/docs/PAYMENT_CN.md @@ -28,6 +28,8 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 > 支付宝官方 / 微信官方与 EasyPay 可以共存。官方渠道直接对接 API,资金直达商户账户,手续费更低;EasyPay 通过第三方平台聚合,接入门槛更低。 +> **EasyPay 推荐**:个人推荐 [ZPay](https://z-pay.cn/?uid=23808) 作为 EasyPay 服务商(链接含作者邀请码,介意可去掉)。ZPay 支持**个人用户**(无营业执照)每日 1 万元以内交易;拥有营业执照则无限额。支付渠道的安全性、稳定性及合规性请自行鉴别,本项目不对任何第三方支付服务商做担保或背书。 + --- ## 快速开始 @@ -104,8 +106,6 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 | **支付宝通道 ID** | 指定支付宝通道(可选) | 否 | | **微信通道 ID** | 指定微信通道(可选) | 否 | -> **EasyPay 推荐**:[ZPay](https://z-pay.cn) 支持个人用户(无营业执照)每日 1 万元以内交易。支付渠道的安全性和合规性请自行鉴别。 - ### 支付宝官方 直接对接支付宝开放平台,支持 PC 页面支付和 H5 手机网站支付。 From f3e8e5e057e7e3e1d5528835ffa59277c8b867e4 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 20:39:28 +0800 Subject: [PATCH 17/34] docs: show ZPay URL explicitly in parentheses --- docs/PAYMENT.md | 2 +- docs/PAYMENT_CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/PAYMENT.md b/docs/PAYMENT.md index 8f76d393b5..cc14437cd3 100644 --- a/docs/PAYMENT.md +++ b/docs/PAYMENT.md @@ -28,7 +28,7 @@ Sub2API has a built-in payment system that enables user self-service top-up with > Alipay/WeChat Pay direct and EasyPay can coexist. Direct channels connect to payment APIs directly with lower fees; EasyPay aggregates through third-party platforms with easier setup. -> **EasyPay Recommendation**: [ZPay](https://z-pay.cn/?uid=23808) is recommended as an EasyPay provider (link contains the author's referral code — feel free to remove it). ZPay supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them. +> **EasyPay Recommendation**: [ZPay](https://z-pay.cn/?uid=23808) (`https://z-pay.cn/?uid=23808`) is recommended as an EasyPay provider (link contains the author's referral code — feel free to remove it). ZPay supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them. --- diff --git a/docs/PAYMENT_CN.md b/docs/PAYMENT_CN.md index 8c895a322c..e6de5f5f06 100644 --- a/docs/PAYMENT_CN.md +++ b/docs/PAYMENT_CN.md @@ -28,7 +28,7 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 > 支付宝官方 / 微信官方与 EasyPay 可以共存。官方渠道直接对接 API,资金直达商户账户,手续费更低;EasyPay 通过第三方平台聚合,接入门槛更低。 -> **EasyPay 推荐**:个人推荐 [ZPay](https://z-pay.cn/?uid=23808) 作为 EasyPay 服务商(链接含作者邀请码,介意可去掉)。ZPay 支持**个人用户**(无营业执照)每日 1 万元以内交易;拥有营业执照则无限额。支付渠道的安全性、稳定性及合规性请自行鉴别,本项目不对任何第三方支付服务商做担保或背书。 +> **EasyPay 推荐**:个人推荐 [ZPay](https://z-pay.cn/?uid=23808)(`https://z-pay.cn/?uid=23808`)作为 EasyPay 服务商(链接含作者邀请码,介意可去掉)。ZPay 支持**个人用户**(无营业执照)每日 1 万元以内交易;拥有营业执照则无限额。支付渠道的安全性、稳定性及合规性请自行鉴别,本项目不对任何第三方支付服务商做担保或背书。 --- From ed001d94da1bde3fcfa2d09406220a2e1a38aa01 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 20:48:44 +0800 Subject: [PATCH 18/34] docs: clarify ZPay referral code belongs to Sub2ApiPay author @touwaeriol --- docs/PAYMENT.md | 2 +- docs/PAYMENT_CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/PAYMENT.md b/docs/PAYMENT.md index cc14437cd3..f3c9781557 100644 --- a/docs/PAYMENT.md +++ b/docs/PAYMENT.md @@ -28,7 +28,7 @@ Sub2API has a built-in payment system that enables user self-service top-up with > Alipay/WeChat Pay direct and EasyPay can coexist. Direct channels connect to payment APIs directly with lower fees; EasyPay aggregates through third-party platforms with easier setup. -> **EasyPay Recommendation**: [ZPay](https://z-pay.cn/?uid=23808) (`https://z-pay.cn/?uid=23808`) is recommended as an EasyPay provider (link contains the author's referral code — feel free to remove it). ZPay supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them. +> **EasyPay Recommendation**: [ZPay](https://z-pay.cn/?uid=23808) (`https://z-pay.cn/?uid=23808`) is recommended as an EasyPay provider (link contains the referral code of [@touwaeriol](https://github.com/touwaeriol), the original author of [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) and contributor of this built-in payment feature — feel free to remove it). ZPay supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them. --- diff --git a/docs/PAYMENT_CN.md b/docs/PAYMENT_CN.md index e6de5f5f06..9d96557f68 100644 --- a/docs/PAYMENT_CN.md +++ b/docs/PAYMENT_CN.md @@ -28,7 +28,7 @@ Sub2API 内置支付系统,支持用户自助充值,无需部署独立的支 > 支付宝官方 / 微信官方与 EasyPay 可以共存。官方渠道直接对接 API,资金直达商户账户,手续费更低;EasyPay 通过第三方平台聚合,接入门槛更低。 -> **EasyPay 推荐**:个人推荐 [ZPay](https://z-pay.cn/?uid=23808)(`https://z-pay.cn/?uid=23808`)作为 EasyPay 服务商(链接含作者邀请码,介意可去掉)。ZPay 支持**个人用户**(无营业执照)每日 1 万元以内交易;拥有营业执照则无限额。支付渠道的安全性、稳定性及合规性请自行鉴别,本项目不对任何第三方支付服务商做担保或背书。 +> **EasyPay 推荐**:个人推荐 [ZPay](https://z-pay.cn/?uid=23808)(`https://z-pay.cn/?uid=23808`)作为 EasyPay 服务商(链接含 [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) 原作者 [@touwaeriol](https://github.com/touwaeriol) 的邀请码,介意可去掉)。ZPay 支持**个人用户**(无营业执照)每日 1 万元以内交易;拥有营业执照则无限额。支付渠道的安全性、稳定性及合规性请自行鉴别,本项目不对任何第三方支付服务商做担保或背书。 --- From 24f95767b476643af0806e2130610cc9bb9ce231 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 20:52:12 +0800 Subject: [PATCH 19/34] docs: align English ZPay referral description with Chinese version --- docs/PAYMENT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/PAYMENT.md b/docs/PAYMENT.md index f3c9781557..b66a791c5f 100644 --- a/docs/PAYMENT.md +++ b/docs/PAYMENT.md @@ -28,7 +28,7 @@ Sub2API has a built-in payment system that enables user self-service top-up with > Alipay/WeChat Pay direct and EasyPay can coexist. Direct channels connect to payment APIs directly with lower fees; EasyPay aggregates through third-party platforms with easier setup. -> **EasyPay Recommendation**: [ZPay](https://z-pay.cn/?uid=23808) (`https://z-pay.cn/?uid=23808`) is recommended as an EasyPay provider (link contains the referral code of [@touwaeriol](https://github.com/touwaeriol), the original author of [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) and contributor of this built-in payment feature — feel free to remove it). ZPay supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them. +> **EasyPay Recommendation**: [ZPay](https://z-pay.cn/?uid=23808) (`https://z-pay.cn/?uid=23808`) is recommended as an EasyPay provider (link contains the referral code of [Sub2ApiPay](https://github.com/touwaeriol/sub2apipay) original author [@touwaeriol](https://github.com/touwaeriol) — feel free to remove it). ZPay supports **individual users** (no business license required) with up to 10,000 CNY daily transactions; business-licensed accounts have no limit. Please evaluate the security, reliability, and compliance of any third-party payment provider on your own — this project does not endorse or guarantee any of them. --- From 64cee0b633f1771bb280a2355a99e5ab4904a758 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 20:46:47 +0800 Subject: [PATCH 20/34] feat(settings): add payment config guide link in payment settings header --- frontend/src/i18n/locales/en.ts | 1 + frontend/src/i18n/locales/zh.ts | 1 + frontend/src/views/admin/SettingsView.vue | 10 ++++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index 1cca9562a1..e5b1b59635 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -4444,6 +4444,7 @@ export default { payment: { title: 'Payment Settings', description: 'Configure payment system options', + configGuide: 'Configuration Guide', enabled: 'Enable Payment', enabledHint: 'Enable or disable the payment system', enabledPaymentTypes: 'Enabled Providers', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index 61f994cb24..a246853928 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -4608,6 +4608,7 @@ export default { payment: { title: '支付设置', description: '配置支付系统选项', + configGuide: '支付配置指南', enabled: '启用支付', enabledHint: '启用或禁用支付系统', enabledPaymentTypes: '启用的服务商', diff --git a/frontend/src/views/admin/SettingsView.vue b/frontend/src/views/admin/SettingsView.vue index 14e5b5d6a9..8f6378063d 100644 --- a/frontend/src/views/admin/SettingsView.vue +++ b/frontend/src/views/admin/SettingsView.vue @@ -2121,7 +2121,13 @@

{{ t('admin.settings.payment.title') }}

-

{{ t('admin.settings.payment.description') }}

+

+ {{ t('admin.settings.payment.description') }} + + + {{ t('admin.settings.payment.configGuide') }} + +

@@ -2536,7 +2542,7 @@ import { parseRegistrationEmailSuffixWhitelistInput } from '@/utils/registrationEmailPolicy' -const { t } = useI18n() +const { t, locale } = useI18n() const appStore = useAppStore() const adminSettingsStore = useAdminSettingsStore() From 1def62744301558fbb3d7081ea5a254d10214c86 Mon Sep 17 00:00:00 2001 From: erio Date: Sat, 11 Apr 2026 20:57:36 +0800 Subject: [PATCH 21/34] feat(settings): add EasyPay provider recommendation link below enabled providers --- frontend/src/i18n/locales/en.ts | 3 ++- frontend/src/i18n/locales/zh.ts | 3 ++- frontend/src/views/admin/SettingsView.vue | 7 +++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index e5b1b59635..5418512977 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -4448,7 +4448,8 @@ export default { enabled: 'Enable Payment', enabledHint: 'Enable or disable the payment system', enabledPaymentTypes: 'Enabled Providers', - enabledPaymentTypesHint: 'Disabling a provider will also disable its instances', + enabledPaymentTypesHint: 'Disabling a provider will also disable its instances.', + findProvider: 'Looking for a suitable EasyPay provider?', minAmount: 'Minimum Amount', maxAmount: 'Maximum Amount', dailyLimit: 'Daily Limit', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index a246853928..b16dc71551 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -4612,7 +4612,8 @@ export default { enabled: '启用支付', enabledHint: '启用或禁用支付系统', enabledPaymentTypes: '启用的服务商', - enabledPaymentTypesHint: '禁用服务商将同时禁用对应的实例', + enabledPaymentTypesHint: '禁用服务商将同时禁用对应的实例。', + findProvider: '正在寻找合适的 EasyPay 服务商?', minAmount: '最低金额', maxAmount: '最高金额', dailyLimit: '每日限额', diff --git a/frontend/src/views/admin/SettingsView.vue b/frontend/src/views/admin/SettingsView.vue index 8f6378063d..f6fd96d6c5 100644 --- a/frontend/src/views/admin/SettingsView.vue +++ b/frontend/src/views/admin/SettingsView.vue @@ -2202,6 +2202,13 @@ ]" >{{ pt.label }}
+

+ {{ t('admin.settings.payment.enabledPaymentTypesHint') }} + + {{ t('admin.settings.payment.findProvider') }} + + +

From 422e25c99f2a3a6d16198a2fbeb2eb64cbc912d1 Mon Sep 17 00:00:00 2001 From: shuanbao0 Date: Sat, 11 Apr 2026 22:48:45 +0800 Subject: [PATCH 22/34] =?UTF-8?q?fix(gateway):=20=E5=89=A5=E7=A6=BB=20Curs?= =?UTF-8?q?or=20raw=20body=20=E9=80=8F=E4=BC=A0=E8=B7=AF=E5=BE=84=E4=B8=AD?= =?UTF-8?q?=20Codex=20=E4=B8=8D=E6=94=AF=E6=8C=81=E7=9A=84=20Responses=20A?= =?UTF-8?q?PI=20=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在前一个 commit 的 isResponsesShape 短路路径基础上,补充对 Cursor 云端 带过来的、Codex 上游统一不支持的顶层 Responses API 参数的剥离: - prompt_cache_retention - safety_identifier - metadata - stream_options 根因补充:这条 raw-body 透传路径为了保留 Cursor 的 input 数组整体结构, 不再经过 ChatCompletionsRequest 的反序列化过滤,所以这些 Go 结构体里 没有对应字段的参数会被原样发到上游,上游返回: Unsupported parameter: 常规 Chat Completions 转换路径天然通过 ChatCompletionsRequest 丢弃未知字段, 不受影响;此处仅在 isResponsesShape 分支内用 sjson.DeleteBytes 显式过滤, 作用域最小。剥离列表与 openai_gateway_service.go:2034 的 unsupportedFields 语义对齐。 另外在 applyCodexOAuthTransform 的 OAuth 兜底 strip 列表里同步追加 prompt_cache_retention,作为对该函数所有其他 OAuth 调用点的 defense in depth(当前只有 Cursor 路径的短路已在前面剥过,但保留这一层更稳)。 测试: - TestCursorMixedShape_StripsUnsupportedFields — 验证所有 4 个字段都被剥 - TestApplyCodexOAuthTransform_StripsPromptCacheRetention — OAuth 兜底路径 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../service/openai_codex_transform.go | 8 ++++ .../service/openai_codex_transform_test.go | 20 +++++++++ .../openai_cursor_warmup_pipeline_test.go | 44 +++++++++++++++++++ .../openai_gateway_chat_completions.go | 26 +++++++++++ 4 files changed, 98 insertions(+) diff --git a/backend/internal/service/openai_codex_transform.go b/backend/internal/service/openai_codex_transform.go index 4ec038e068..a266d6a01c 100644 --- a/backend/internal/service/openai_codex_transform.go +++ b/backend/internal/service/openai_codex_transform.go @@ -124,6 +124,14 @@ func applyCodexOAuthTransform(reqBody map[string]any, isCodexCLI bool, isCompact "top_p", "frequency_penalty", "presence_penalty", + // prompt_cache_retention is a newer Responses API parameter (cache TTL). + // The ChatGPT internal Codex endpoint rejects it with + // "Unsupported parameter: prompt_cache_retention". Defense-in-depth + // for any OAuth path that reaches this transform — the Cursor + // Responses-shape short-circuit in ForwardAsChatCompletions strips + // it earlier too, but we keep this line so other OAuth callers are + // equally protected. + "prompt_cache_retention", } { if _, ok := reqBody[key]; ok { delete(reqBody, key) diff --git a/backend/internal/service/openai_codex_transform_test.go b/backend/internal/service/openai_codex_transform_test.go index 889ac61598..993ade0747 100644 --- a/backend/internal/service/openai_codex_transform_test.go +++ b/backend/internal/service/openai_codex_transform_test.go @@ -481,6 +481,26 @@ func TestExtractSystemMessagesFromInput(t *testing.T) { }) } +// TestApplyCodexOAuthTransform_StripsPromptCacheRetention is a regression +// test: some clients (e.g. Cursor cloud via the Responses-shape compat path) +// send prompt_cache_retention, but the ChatGPT internal Codex endpoint +// rejects it with "Unsupported parameter: prompt_cache_retention". +func TestApplyCodexOAuthTransform_StripsPromptCacheRetention(t *testing.T) { + reqBody := map[string]any{ + "model": "gpt-5.1", + "prompt_cache_retention": "24h", + "input": []any{ + map[string]any{"role": "user", "content": "hi"}, + }, + } + + applyCodexOAuthTransform(reqBody, false, false) + + _, stillThere := reqBody["prompt_cache_retention"] + require.False(t, stillThere, + "prompt_cache_retention must be stripped before forwarding to Codex upstream") +} + func TestApplyCodexOAuthTransform_ExtractsSystemMessages(t *testing.T) { reqBody := map[string]any{ "model": "gpt-5.1", diff --git a/backend/internal/service/openai_cursor_warmup_pipeline_test.go b/backend/internal/service/openai_cursor_warmup_pipeline_test.go index 8ade9dbbb4..19bb13d607 100644 --- a/backend/internal/service/openai_cursor_warmup_pipeline_test.go +++ b/backend/internal/service/openai_cursor_warmup_pipeline_test.go @@ -153,3 +153,47 @@ func TestCursorMixedShape_JSONRoundtrip(t *testing.T) { require.True(t, ok, "input must decode to a Go []any after round-trip") require.Len(t, inputArr, 1) } + +// TestCursorMixedShape_StripsUnsupportedFields mirrors the strip loop in +// ForwardAsChatCompletions (isResponsesShape branch). Cursor cloud sends +// prompt_cache_retention, safety_identifier, metadata and stream_options +// as top-level Responses API parameters, which Codex upstreams reject with +// "Unsupported parameter: ...". The fix must remove them from the raw body +// before it is forwarded, for BOTH OAuth and API Key account types. +func TestCursorMixedShape_StripsUnsupportedFields(t *testing.T) { + cursorBody := []byte(`{ + "model": "gpt-5.4", + "stream": true, + "prompt_cache_retention": "24h", + "safety_identifier": "cursor-user-xyz", + "metadata": {"trace_id":"abc","caller":"cursor"}, + "stream_options": {"include_usage": true}, + "input": [{"role":"user","content":"hi"}] + }`) + + // Sanity: the test fixture contains every field the production code strips. + for _, field := range cursorResponsesUnsupportedFields { + require.True(t, gjson.GetBytes(cursorBody, field).Exists(), + "test fixture must contain %s", field) + } + + // Run the exact same loop as the production code. + result := cursorBody + for _, field := range cursorResponsesUnsupportedFields { + if stripped, err := sjson.DeleteBytes(result, field); err == nil { + result = stripped + } + } + + // All unsupported fields must be gone. + for _, field := range cursorResponsesUnsupportedFields { + assert.False(t, gjson.GetBytes(result, field).Exists(), + "%s must be stripped", field) + } + + // Everything else must survive intact. + assert.Equal(t, "gpt-5.4", gjson.GetBytes(result, "model").String()) + assert.Equal(t, true, gjson.GetBytes(result, "stream").Bool()) + assert.True(t, gjson.GetBytes(result, "input").IsArray()) + assert.Equal(t, "user", gjson.GetBytes(result, "input.0.role").String()) +} diff --git a/backend/internal/service/openai_gateway_chat_completions.go b/backend/internal/service/openai_gateway_chat_completions.go index c827fd7b5d..ac7d28a7f0 100644 --- a/backend/internal/service/openai_gateway_chat_completions.go +++ b/backend/internal/service/openai_gateway_chat_completions.go @@ -21,6 +21,22 @@ import ( "go.uber.org/zap" ) +// cursorResponsesUnsupportedFields are top-level Responses API parameters that +// Codex upstreams reject with "Unsupported parameter: ...". They must be +// stripped when forwarding a raw client body through the Responses-shape +// short-circuit in ForwardAsChatCompletions (see isResponsesShape branch). +// The normal Chat Completions → Responses conversion path is unaffected +// because ChatCompletionsRequest has no fields for these parameters — unknown +// fields are dropped naturally by json.Unmarshal. Kept semantically in sync +// with the list in openai_gateway_service.go:2034 used by the /v1/responses +// passthrough path. +var cursorResponsesUnsupportedFields = []string{ + "prompt_cache_retention", + "safety_identifier", + "metadata", + "stream_options", +} + // ForwardAsChatCompletions accepts a Chat Completions request body, converts it // to OpenAI Responses API format, forwards to the OpenAI upstream, and converts // the response back to Chat Completions format. All account types (OAuth and API @@ -81,6 +97,16 @@ func (s *OpenAIGatewayService) ForwardAsChatCompletions( if err != nil { return nil, fmt.Errorf("rewrite model in responses-shape body: %w", err) } + // Strip Responses API parameters that no Codex upstream accepts. + // Because this branch forwards the raw body (the normal path rebuilds + // it from ChatCompletionsRequest and drops unknown fields naturally), + // we must filter these fields explicitly here — otherwise the upstream + // rejects the request with "Unsupported parameter: ...". + for _, field := range cursorResponsesUnsupportedFields { + if stripped, derr := sjson.DeleteBytes(responsesBody, field); derr == nil { + responsesBody = stripped + } + } // Minimal stub populated from the raw body so downstream billing // propagation (ServiceTier, ReasoningEffort) keeps working. responsesReq = &apicompat.ResponsesRequest{ From cb016ad8618fa7ad2792460df1abbf3f675e7762 Mon Sep 17 00:00:00 2001 From: bot Date: Sun, 12 Apr 2026 13:30:15 +0800 Subject: [PATCH 23/34] fix: handle Anthropic credit balance exhausted (400) as account error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When an Anthropic API key's credit balance is depleted, the upstream returns HTTP 400 with message containing "credit balance". Previously, the 400 handler only checked for "organization has been disabled", so credit-exhausted accounts kept being scheduled — every request returned the same error. Treat this case identically to 402 (Payment Required): call handleAuthError → SetError to stop scheduling the account until an admin manually recovers it after topping up credits. Closes #1586 --- backend/internal/service/ratelimit_service.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/internal/service/ratelimit_service.go b/backend/internal/service/ratelimit_service.go index 4f5b57cc97..4d8009b7bd 100644 --- a/backend/internal/service/ratelimit_service.go +++ b/backend/internal/service/ratelimit_service.go @@ -142,11 +142,16 @@ func (s *RateLimitService) HandleUpstreamError(ctx context.Context, account *Acc switch statusCode { case 400: - // 只有当错误信息包含 "organization has been disabled" 时才禁用 + // "organization has been disabled" → 永久禁用 if strings.Contains(strings.ToLower(upstreamMsg), "organization has been disabled") { msg := "Organization disabled (400): " + upstreamMsg s.handleAuthError(ctx, account, msg) shouldDisable = true + } else if account.Platform == PlatformAnthropic && strings.Contains(strings.ToLower(upstreamMsg), "credit balance") { + // Anthropic API key 余额不足(语义等同 402),停止调度 + msg := "Credit balance exhausted (400): " + upstreamMsg + s.handleAuthError(ctx, account, msg) + shouldDisable = true } // 其他 400 错误(如参数问题)不处理,不禁用账号 case 401: From a1a283688c5aeb2bde9e4688822df0e921e21ae6 Mon Sep 17 00:00:00 2001 From: shaw Date: Sun, 12 Apr 2026 17:19:44 +0800 Subject: [PATCH 24/34] chore: update sponsors --- README.md | 5 +++++ README_CN.md | 7 ++++++- README_JA.md | 5 +++++ assets/partners/logos/AICodeMirror.jpg | Bin 0 -> 84816 bytes 4 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 assets/partners/logos/AICodeMirror.jpg diff --git a/README.md b/README.md index b64a7647c5..3a56d089c1 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,11 @@ Sub2API is an AI API gateway platform designed to distribute and manage API quot Thanks to YLS Code for sponsoring this project! YLS Code is dedicated to building secure enterprise-grade Coding Agent productivity services, offering stable and fast Codex / Claude / Gemini subscription services along with pay-as-you-go API options for flexible choices. Register now for a limited-time 3-day Codex trial bonus! + +AICodeMirror +Thanks to AICodeMirror for sponsoring this project! AICodeMirror provides official high-stability relay services for Claude Code / Codex / Gemini CLI, with enterprise-grade concurrency, fast invoicing, and 24/7 dedicated technical support. Claude Code / Codex / Gemini official channels at 38% / 2% / 9% of original price, with extra discounts on top-ups! AICodeMirror offers special benefits for sub2api users: register via this link to enjoy 20% off your first top-up, and enterprise customers can get up to 25% off! + + ## Ecosystem diff --git a/README_CN.md b/README_CN.md index 5b6be04ccd..c0e6492e56 100644 --- a/README_CN.md +++ b/README_CN.md @@ -76,10 +76,15 @@ Sub2API 是一个 AI API 网关平台,用于分发和管理 AI 产品订阅的 -silkapi +ylscode 感谢 伊莉思Code 赞助了本项目! 伊莉思Code 致力于构建安全的企业级Coding Agent生产力服务,提供稳定快速的 Codex / Claude / Gemini 订阅服务与即用即付API多种方案灵活选择,限时注册赠送 3 天 Codex 试用福利! + +AICodeMirror +感谢 AICodeMirror 赞助了本项目!AICodeMirror 提供 Claude Code / Codex / Gemini CLI 官方高稳定性中转服务,企业级并发、快速开票、7×24 小时专属技术支持。Claude Code / Codex / Gemini 官方通道低至原价 38% / 2% / 9%,充值更享额外折扣!AICodeMirror 为 sub2api 用户提供专属福利:通过此链接注册,首次充值立享 8 折优惠,企业客户最高可享 75 折! + + ## 生态项目 diff --git a/README_JA.md b/README_JA.md index 4e7ae76532..4605b87749 100644 --- a/README_JA.md +++ b/README_JA.md @@ -80,6 +80,11 @@ Sub2API は、AI 製品のサブスクリプションから API クォータを YLS Code のご支援に感謝します!YLS Code は安全なエンタープライズグレードの Coding Agent 生産性サービスの構築に取り組んでおり、安定かつ高速な Codex / Claude / Gemini サブスクリプションサービスと従量課金 API の柔軟なプランを提供しています。期間限定で新規登録者に 3 日間の Codex 試用特典をプレゼント中! + +AICodeMirror +AICodeMirror のご支援に感謝します!AICodeMirror は Claude Code / Codex / Gemini CLI の公式高安定性リレーサービスを提供しており、エンタープライズグレードの同時実行、迅速な請求書発行、24時間年中無休の専属テクニカルサポートを備えています。Claude Code / Codex / Gemini の公式チャネルを定価の 38% / 2% / 9% で利用可能、チャージ時にはさらに追加割引!AICodeMirror は sub2api ユーザー向けに特別特典を提供中:こちらのリンクから登録すると、初回チャージが 20% オフ、法人のお客様は最大 25% オフ! + + ## エコシステム diff --git a/assets/partners/logos/AICodeMirror.jpg b/assets/partners/logos/AICodeMirror.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1c98b2238a28ab2ffaaa84a9aa6b9b4094cf03f9 GIT binary patch literal 84816 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 Date: Sun, 12 Apr 2026 18:06:40 +0800 Subject: [PATCH 25/34] fix(frontend): resolve TS2352 type assertion error in API client --- frontend/src/api/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 6be2d543a4..2908c6b134 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -92,7 +92,7 @@ apiClient.interceptors.response.use( response.data = apiResponse.data } else { // API error - const resp = apiResponse as Record + const resp = apiResponse as unknown as Record return Promise.reject({ status: response.status, code: apiResponse.code, From ad64190bec3605f97e9e1805a0118aaa51f22b08 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 12 Apr 2026 10:17:16 +0000 Subject: [PATCH 26/34] chore: sync VERSION to 0.1.111 [skip ci] --- backend/cmd/server/VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/cmd/server/VERSION b/backend/cmd/server/VERSION index b6e5c2adfa..715965f359 100644 --- a/backend/cmd/server/VERSION +++ b/backend/cmd/server/VERSION @@ -1 +1 @@ -0.1.110 +0.1.111 From 3a11348119669a53bba1ab3ba948216ea67a7ca7 Mon Sep 17 00:00:00 2001 From: qingyuzhang Date: Mon, 13 Apr 2026 06:55:57 +0800 Subject: [PATCH 27/34] fix(frontend): avoid mounting hidden mobile table --- frontend/src/components/common/DataTable.vue | 64 +++++++++++++++++--- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/common/DataTable.vue b/frontend/src/components/common/DataTable.vue index 36c7e27817..456b1da79a 100644 --- a/frontend/src/components/common/DataTable.vue +++ b/frontend/src/components/common/DataTable.vue @@ -1,5 +1,5 @@