From d88a2039bb2ad7d65c413a0d15f22645824c8237 Mon Sep 17 00:00:00 2001 From: "douglas.ou" Date: Fri, 27 Feb 2026 09:21:09 +0800 Subject: [PATCH 1/4] Add Mini Program payment bridge for WeChat Pay - Introduced a shared WeChat payment preparation API for event ticket payments. - Defined a Mini Program bridge channel with strict error handling and no fallback policy. - Established a cross-repo bridge contract for compatibility between H5 and Mini Program shell. - Updated event ticket order responses to include channelized payment payloads. - Ensured backward compatibility during the transition phase. This change aims to enhance payment reliability and streamline the payment process for Mini Program users. --- .../contracts/miniprogram-bridge.md | 57 ++++++++++++++++ .../add-miniprogram-payment-bridge/design.md | 68 +++++++++++++++++++ .../proposal.md | 16 +++++ .../specs/event-ticket-purchase/spec.md | 34 ++++++++++ .../wechat-payment-orchestration/spec.md | 44 ++++++++++++ .../add-miniprogram-payment-bridge/tasks.md | 24 +++++++ 6 files changed, 243 insertions(+) create mode 100644 openspec/changes/add-miniprogram-payment-bridge/contracts/miniprogram-bridge.md create mode 100644 openspec/changes/add-miniprogram-payment-bridge/design.md create mode 100644 openspec/changes/add-miniprogram-payment-bridge/proposal.md create mode 100644 openspec/changes/add-miniprogram-payment-bridge/specs/event-ticket-purchase/spec.md create mode 100644 openspec/changes/add-miniprogram-payment-bridge/specs/wechat-payment-orchestration/spec.md create mode 100644 openspec/changes/add-miniprogram-payment-bridge/tasks.md diff --git a/openspec/changes/add-miniprogram-payment-bridge/contracts/miniprogram-bridge.md b/openspec/changes/add-miniprogram-payment-bridge/contracts/miniprogram-bridge.md new file mode 100644 index 00000000..0e1ddff3 --- /dev/null +++ b/openspec/changes/add-miniprogram-payment-bridge/contracts/miniprogram-bridge.md @@ -0,0 +1,57 @@ +# Mini Program Payment Bridge Contract (H5 <-> Shell) + +## Versioning +- Contract name: `HW_MINI_PAYMENT_BRIDGE` +- Contract version: `1.0.0` +- Minimum shell bridge version: `1.2.0` + +## Global Bridge Object +The shell SHALL inject `window.__HWMiniAppBridge__` in Mini Program WebView. + +```ts +interface HWMiniAppBridge { + getCapabilities(): Promise<{ + bridgeVersion: string; + supportsRequestPayment: boolean; + }>; + + requestPayment(input: { + timeStamp: string; + nonceStr: string; + package: string; + signType: "RSA"; + paySign: string; + orderNo: string; + }): Promise<{ + ok: boolean; + errCode?: + | "PAY_CANCELLED" + | "PAY_FAILED" + | "BRIDGE_NOT_SUPPORTED" + | "BRIDGE_TIMEOUT" + | "INVALID_PAYLOAD"; + errMsg?: string; + }>; +} +``` + +## Capability Handshake +- H5 SHALL call `getCapabilities()` before invoking `requestPayment`. +- If object missing, call fails, version too low, or `supportsRequestPayment=false`, H5 MUST treat it as bridge unavailable. + +## Error Code Mapping (Shell -> H5) +- `BRIDGE_NOT_SUPPORTED` => H5/API error `MINI_PROGRAM_BRIDGE_REQUIRED` +- `PAY_CANCELLED` => `MINI_PROGRAM_PAY_CANCELLED` +- `PAY_FAILED` => `MINI_PROGRAM_PAY_FAILED` +- `BRIDGE_TIMEOUT` => `MINI_PROGRAM_BRIDGE_TIMEOUT` +- `INVALID_PAYLOAD` => `MINI_PROGRAM_PAY_FAILED` + +## Runtime Behavior +- Shell SHALL map `requestPayment` to `wx.requestPayment` parameters 1:1. +- Shell SHALL resolve `ok=true` only when `wx.requestPayment` success callback is called. +- H5 SHALL continue polling/order query for final payment status (webhook/query remains source of truth). + +## Security Requirements +- Shell SHALL not mutate signed payment fields received from server. +- H5 SHALL only accept bridge object in Mini Program context. +- Any JSON message transport fallback (if used internally by shell) SHALL enforce origin and schema checks before dispatch. diff --git a/openspec/changes/add-miniprogram-payment-bridge/design.md b/openspec/changes/add-miniprogram-payment-bridge/design.md new file mode 100644 index 00000000..98e410fb --- /dev/null +++ b/openspec/changes/add-miniprogram-payment-bridge/design.md @@ -0,0 +1,68 @@ +## Context +Event ticket WeChat Pay currently returns either JSAPI parameters (WeChat browser) or Native QR (`codeUrl`) based on user agent. Mini Program users access the same H5 pages inside a shell WebView, but payment invocation should be executed by shell-native APIs (`wx.requestPayment`) through a bridge. + +Without an explicit bridge contract and capability checks, Mini Program users can enter a broken payment flow. We also need to avoid duplicating channel-selection logic across future WeChat payment entry points. + +## Goals / Non-Goals +- Goals: + - Add a shared WeChat payment preparation orchestration API for channel selection and payload shaping. + - Support Mini Program bridge payment for event tickets. + - Define strict cross-repo bridge contract and error semantics. + - Keep payment lifecycle consistency (webhook idempotency and manual query remain source of truth). +- Non-Goals: + - Full migration of all existing payment entry points in one release. + - Introducing JS auto-fallback for Mini Program bridge failures. + - New OpenID schema design. + +## Decisions +- Decision: Introduce a shared prepare API. + - Add `POST /api/payments/wechat/prepare` with `bizType` and `bizId`. + - Initial `bizType` support is `EVENT_TICKET` only. + - Response always includes `channel` and channel-specific `payPayload`. + +- Decision: Canonical channel model. + - Channels: `MINIPROGRAM_BRIDGE`, `WECHAT_JSAPI`, `WECHAT_NATIVE`. + - Selection precedence: + 1) Mini Program WebView + bridge capability confirmed => `MINIPROGRAM_BRIDGE` + 2) WeChat browser => `WECHAT_JSAPI` + 3) others => `WECHAT_NATIVE` + +- Decision: Mini Program bridge hard requirement. + - If Mini Program environment is detected but bridge capability/version is missing, return `MINI_PROGRAM_BRIDGE_REQUIRED`. + - Frontend must show upgrade guidance and stop payment start. + - Do not downgrade automatically to JSAPI or Native QR in Mini Program context. + +- Decision: No data-model change for OpenID. + - Continue using existing user OpenID field currently used for WeChat JSAPI. + - Do not add `miniOpenId` in this change. + +- Decision: Order and status truth model unchanged. + - Payment completion truth remains webhook + explicit order status query endpoints. + - Bridge callback is only trigger feedback, not final settlement source. + +- Decision: Response compatibility. + - Event ticket order create response adds `channel` and `payPayload` while keeping existing JSAPI/Native fields for one transition release. + - Frontend prioritizes `channel` + `payPayload` and only uses legacy fields as backward compatibility. + +## Bridge Contract +See `contracts/miniprogram-bridge.md` for the exact interface, version floor, and error-code mapping shared with the shell repo. + +## Risks / Trade-offs +- Enforcing upgrade (no fallback) may temporarily reduce conversion for old shell versions. +- Cross-repo release coordination becomes a hard dependency. +- Dual payload format during transition increases temporary complexity. + +## Migration Plan +1. Ship shell bridge contract implementation and expose capability/version reporting. +2. Ship shared prepare API and channelized payload response. +3. Update event ticket frontend modal to bridge mode handling. +4. Enable Mini Program bridge channel behind feature flag/version gate. +5. Remove legacy response field usage after rollout stabilization. + +## Rollout & Monitoring +- Add metrics by payment channel and error code. +- Monitor `MINI_PROGRAM_BRIDGE_REQUIRED` rate and payment completion rates by channel. +- Alert on webhook delay and query reconciliation mismatch spikes. + +## Open Questions +- None. diff --git a/openspec/changes/add-miniprogram-payment-bridge/proposal.md b/openspec/changes/add-miniprogram-payment-bridge/proposal.md new file mode 100644 index 00000000..3fc32d4f --- /dev/null +++ b/openspec/changes/add-miniprogram-payment-bridge/proposal.md @@ -0,0 +1,16 @@ +# Change: Add Mini Program payment bridge for WeChat Pay with shared prepare API + +## Why +Current WeChat Pay flows only distinguish WeChat browser JSAPI vs Native QR. In Mini Program WebView, payment completion is unreliable because the shell app owns the runtime capability (`wx.requestPayment`) while the web app cannot directly guarantee bridge availability/version handling. + +## What Changes +- Add a shared WeChat payment preparation API that returns channel-specific payloads for `EVENT_TICKET`. +- Add a Mini Program bridge channel (`MINIPROGRAM_BRIDGE`) for event ticket payments. +- Define a cross-repo bridge contract (H5 <-> Mini Program shell) with version and error-code guarantees. +- Enforce a no-fallback policy for unsupported Mini Program bridge capability (prompt upgrade instead of downgrading to JSAPI/Native). +- Keep existing OpenID data model (no schema change for mini-program OpenID field). + +## Impact +- Affected specs: event-ticket-purchase, wechat-payment-orchestration +- Affected code: event order route payload selection, payment modal channel handling, shared payment prepare route/types, mini program shell bridge implementation (external repo) +- Dependencies: Mini Program shell repo release with bridge support and version signaling before enabling this channel in production diff --git a/openspec/changes/add-miniprogram-payment-bridge/specs/event-ticket-purchase/spec.md b/openspec/changes/add-miniprogram-payment-bridge/specs/event-ticket-purchase/spec.md new file mode 100644 index 00000000..d59b0995 --- /dev/null +++ b/openspec/changes/add-miniprogram-payment-bridge/specs/event-ticket-purchase/spec.md @@ -0,0 +1,34 @@ +## ADDED Requirements + +### Requirement: Event ticket order response includes channelized payment payload +The system SHALL return `channel` and `payPayload` in event ticket order creation responses so the client can launch the correct WeChat payment path. + +#### Scenario: Mini Program bridge channel is returned for supported shell +- **WHEN** an authenticated user creates a paid event ticket order from Mini Program WebView and bridge capability is available +- **THEN** the order response includes `channel = MINIPROGRAM_BRIDGE` +- **AND** `payPayload` includes request-payment fields required by shell `wx.requestPayment` + +### Requirement: Mini Program bridge availability is mandatory in Mini Program context +The system SHALL reject payment start in Mini Program context when bridge capability is unavailable or below the minimum supported version. + +#### Scenario: Bridge capability is missing in Mini Program context +- **WHEN** a Mini Program WebView user creates or resumes a paid order without bridge capability support +- **THEN** the API returns `MINI_PROGRAM_BRIDGE_REQUIRED` +- **AND** the client shows an upgrade prompt +- **AND** the client does not downgrade to JSAPI or Native QR flow + +### Requirement: Event ticket flow uses shared WeChat payment preparation capability +The system SHALL use the shared WeChat payment preparation capability for event ticket paid orders instead of route-specific channel shaping. + +#### Scenario: Event ticket prepare delegates to shared payment orchestration +- **WHEN** a paid event ticket order is created +- **THEN** channel selection and payload are generated by shared WeChat payment orchestration logic +- **AND** event order APIs return the selected channel result + +### Requirement: Bridge callback does not bypass order settlement truth +The system SHALL continue using webhook and explicit status query as the settlement source of truth after Mini Program bridge payment invocation. + +#### Scenario: Bridge invocation succeeds but final status is pending +- **WHEN** bridge `requestPayment` reports success but webhook has not updated order status yet +- **THEN** the client keeps polling or manual query behavior +- **AND** order status transitions only when backend settlement logic confirms payment diff --git a/openspec/changes/add-miniprogram-payment-bridge/specs/wechat-payment-orchestration/spec.md b/openspec/changes/add-miniprogram-payment-bridge/specs/wechat-payment-orchestration/spec.md new file mode 100644 index 00000000..f8625001 --- /dev/null +++ b/openspec/changes/add-miniprogram-payment-bridge/specs/wechat-payment-orchestration/spec.md @@ -0,0 +1,44 @@ +## ADDED Requirements + +### Requirement: Shared WeChat payment prepare API +The system SHALL provide a shared API to prepare WeChat payment payloads for business flows. + +#### Scenario: Prepare API returns channelized payload for event ticket +- **WHEN** the client calls `POST /api/payments/wechat/prepare` with `bizType = EVENT_TICKET` and valid order identity +- **THEN** the response includes `channel`, `orderNo`, `expiredAt`, and channel-specific `payPayload` + +### Requirement: Deterministic channel selection precedence +The system SHALL apply deterministic precedence for WeChat payment channel selection. + +#### Scenario: Environment is Mini Program and bridge is available +- **WHEN** client context indicates Mini Program WebView with supported bridge capability +- **THEN** selected channel is `MINIPROGRAM_BRIDGE` +- **AND** JSAPI/Native channels are not selected + +#### Scenario: Environment is WeChat browser outside Mini Program +- **WHEN** client context indicates WeChat browser and not Mini Program bridge mode +- **THEN** selected channel is `WECHAT_JSAPI` + +#### Scenario: Environment is non-WeChat browser +- **WHEN** client context is outside WeChat runtime +- **THEN** selected channel is `WECHAT_NATIVE` + +### Requirement: Standardized Mini Program bridge error semantics +The system SHALL expose normalized error codes for Mini Program bridge capability and invocation failures. + +#### Scenario: Bridge version is unsupported +- **WHEN** the bridge version is lower than required minimum +- **THEN** the API returns `MINI_PROGRAM_BRIDGE_REQUIRED` +- **AND** the response indicates upgrade is required + +#### Scenario: Bridge invocation reports cancellation +- **WHEN** shell bridge reports payment cancellation +- **THEN** the client receives `MINI_PROGRAM_PAY_CANCELLED` +- **AND** order remains in payable state until expiration or explicit cancellation + +### Requirement: Backward compatibility for transition release +The system SHALL keep legacy payment response fields for one transition release while introducing canonical `channel` and `payPayload` fields. + +#### Scenario: Legacy client reads historical fields +- **WHEN** a client has not switched to `channel` and `payPayload` +- **THEN** existing JSAPI or Native legacy response fields remain available during the transition period diff --git a/openspec/changes/add-miniprogram-payment-bridge/tasks.md b/openspec/changes/add-miniprogram-payment-bridge/tasks.md new file mode 100644 index 00000000..c4eac6bd --- /dev/null +++ b/openspec/changes/add-miniprogram-payment-bridge/tasks.md @@ -0,0 +1,24 @@ +## 1. Shared WeChat payment orchestration +- [ ] 1.1 Add `POST /api/payments/wechat/prepare` for `EVENT_TICKET` and channelized payload output. +- [ ] 1.2 Add shared server/client types for `channel`, `payPayload`, and standardized error codes. +- [ ] 1.3 Add channel-selection logic with precedence: Mini Program bridge -> WeChat JSAPI -> Native. + +## 2. Event ticket payment flow integration +- [ ] 2.1 Update event order creation flow to consume the shared prepare capability and return `channel` + `payPayload`. +- [ ] 2.2 Keep a one-release compatibility layer for legacy JSAPI/Native response fields. +- [ ] 2.3 Enforce `MINI_PROGRAM_BRIDGE_REQUIRED` behavior (no fallback) when Mini Program bridge is unavailable. + +## 3. Frontend payment modal behavior +- [ ] 3.1 Add `MINIPROGRAM_BRIDGE` handling in payment modal and call bridge `requestPayment` path. +- [ ] 3.2 Add upgrade prompt UI for bridge-required errors and block payment launch. +- [ ] 3.3 Preserve existing polling/manual-query reconciliation after bridge callback. + +## 4. Cross-repo bridge contract and shell implementation +- [ ] 4.1 Publish and version the H5 <-> shell bridge contract in this repo. +- [ ] 4.2 Implement same contract in Mini Program shell repo (capability reporting + `wx.requestPayment` mapping). +- [ ] 4.3 Add shell error mapping to agreed error codes and callback payload shape. + +## 5. Validation and rollout +- [ ] 5.1 Add tests for channel selection, payload shape, bridge-required behavior, and status reconciliation. +- [ ] 5.2 Add metrics/log fields for `channel`, `shellVersion`, `bridgeVersion`, and Mini Program bridge errors. +- [ ] 5.3 Validate with `openspec validate add-miniprogram-payment-bridge --strict`. From 3c83d5181e58a906884f2b6c8fa445069aa697ed Mon Sep 17 00:00:00 2001 From: "douglas.ou" Date: Fri, 27 Feb 2026 10:16:21 +0800 Subject: [PATCH 2/4] Add Mini Program upgrade prompt and WeChat payment context - Implemented a new Mini Program upgrade prompt to handle payment bridge requirements. - Enhanced the Event Registration Form and Modal to manage Mini Program upgrade messages. - Integrated WeChat payment client context to facilitate channel selection and payment processing. - Updated server routes to support new payment preparation logic and handle Mini Program bridge capabilities. These changes improve user experience by providing clear upgrade prompts and ensuring compatibility with the Mini Program payment system. --- .../components/EventRegistrationForm.tsx | 26 + .../components/EventRegistrationModal.tsx | 46 +- .../components/MiniProgramUpgradePrompt.tsx | 47 + .../public/events/components/PaymentModal.tsx | 186 +- .../wechat-payment-client-context.ts | 103 + apps/web/src/server/routes/events/orders.ts | 526 ++--- .../routes/payments/lib/wechat-prepare.ts | 329 +++ apps/web/src/server/routes/payments/router.ts | 64 + .../add-miniprogram-payment-bridge/tasks.md | 30 +- .../lib-shared/src/i18n/translations/en.json | 9 + .../lib-shared/src/i18n/translations/zh.json | 9 + .../payments/__tests__/wechat-payment.test.ts | 68 + .../lib-shared/src/payments/wechat-payment.ts | 197 ++ pnpm-lock.yaml | 1842 +---------------- 14 files changed, 1405 insertions(+), 2077 deletions(-) create mode 100644 apps/web/src/modules/public/events/components/MiniProgramUpgradePrompt.tsx create mode 100644 apps/web/src/modules/public/events/components/wechat-payment-client-context.ts create mode 100644 apps/web/src/server/routes/payments/lib/wechat-prepare.ts create mode 100644 packages/lib-shared/src/payments/__tests__/wechat-payment.test.ts create mode 100644 packages/lib-shared/src/payments/wechat-payment.ts diff --git a/apps/web/src/modules/public/events/components/EventRegistrationForm.tsx b/apps/web/src/modules/public/events/components/EventRegistrationForm.tsx index d04085cf..1ad8e0d8 100644 --- a/apps/web/src/modules/public/events/components/EventRegistrationForm.tsx +++ b/apps/web/src/modules/public/events/components/EventRegistrationForm.tsx @@ -42,11 +42,13 @@ import type { } from "./types"; import { PaymentModal, type PaymentOrderData } from "./PaymentModal"; import { useTicketSelection } from "./useTicketSelection"; +import { MiniProgramUpgradePrompt } from "./MiniProgramUpgradePrompt"; import { WeChatBindingPrompt } from "./WeChatBindingPrompt"; import { parseRegistrationErrorPayload, resolveRegistrationErrorMessage, } from "./registrationErrorUtils"; +import { buildWechatPaymentClientContext } from "./wechat-payment-client-context"; interface EventRegistrationFormProps { event: { @@ -102,6 +104,10 @@ export function EventRegistrationForm({ const [wechatBindingMessage, setWechatBindingMessage] = useState< string | null >(null); + const [miniProgramUpgradeOpen, setMiniProgramUpgradeOpen] = useState(false); + const [miniProgramUpgradeMessage, setMiniProgramUpgradeMessage] = useState< + string | null + >(null); const [allowDigitalCardDisplay, setAllowDigitalCardDisplay] = useState< boolean | null >(null); @@ -780,6 +786,7 @@ export function EventRegistrationForm({ const performPaidOrder = async () => { try { const ticketTypeId = resolveTicketTypeId(); + const clientContext = await buildWechatPaymentClientContext(); const response = await fetch(`/api/events/${event.id}/orders`, { method: "POST", headers: { @@ -797,6 +804,7 @@ export function EventRegistrationForm({ allowDigitalCardDisplay: allowDigitalCardDisplay, }), ...(inviteCode ? { inviteCode } : {}), + clientContext, }), }); @@ -814,10 +822,18 @@ export function EventRegistrationForm({ setWechatBindingOpen(true); return; } + if (errorPayload.code === "MINI_PROGRAM_BRIDGE_REQUIRED") { + setMiniProgramUpgradeMessage(errorMessage); + setMiniProgramUpgradeOpen(true); + return; + } throw new Error(errorMessage); } const result = await response.json(); + if (result.data?.isExisting) { + toast.info(t("payment.existingOrderFound")); + } setPaymentOrder(result.data as PaymentOrderData); setPaymentOpen(true); } catch (error) { @@ -1183,6 +1199,16 @@ export function EventRegistrationForm({ }} message={wechatBindingMessage} /> + { + setMiniProgramUpgradeOpen(open); + if (!open) { + setMiniProgramUpgradeMessage(null); + } + }} + message={miniProgramUpgradeMessage} + /> ); } diff --git a/apps/web/src/modules/public/events/components/EventRegistrationModal.tsx b/apps/web/src/modules/public/events/components/EventRegistrationModal.tsx index 331a9b98..a9120929 100644 --- a/apps/web/src/modules/public/events/components/EventRegistrationModal.tsx +++ b/apps/web/src/modules/public/events/components/EventRegistrationModal.tsx @@ -35,11 +35,16 @@ import type { } from "./types"; import { PaymentModal, type PaymentOrderData } from "./PaymentModal"; import { useTicketSelection } from "./useTicketSelection"; +import { MiniProgramUpgradePrompt } from "./MiniProgramUpgradePrompt"; import { WeChatBindingPrompt } from "./WeChatBindingPrompt"; import { parseRegistrationErrorPayload, resolveRegistrationErrorMessage, } from "./registrationErrorUtils"; +import { + buildWechatPaymentClientContext, + buildWechatPaymentClientContextQuery, +} from "./wechat-payment-client-context"; interface EventRegistrationModalProps { isOpen: boolean; @@ -87,6 +92,10 @@ export function EventRegistrationModal({ const [wechatBindingMessage, setWechatBindingMessage] = useState< string | null >(null); + const [miniProgramUpgradeOpen, setMiniProgramUpgradeOpen] = useState(false); + const [miniProgramUpgradeMessage, setMiniProgramUpgradeMessage] = useState< + string | null + >(null); const [pendingOrderChecked, setPendingOrderChecked] = useState(false); const [allowDigitalCardDisplay, setAllowDigitalCardDisplay] = useState< boolean | null @@ -194,10 +203,28 @@ export function EventRegistrationModal({ const fetchPendingOrder = async () => { try { + const clientContext = await buildWechatPaymentClientContext(); + const contextQuery = + buildWechatPaymentClientContextQuery(clientContext); const response = await fetch( - `/api/events/${event.id}/orders/pending`, + `/api/events/${event.id}/orders/pending${ + contextQuery ? `?${contextQuery}` : "" + }`, ); if (!response.ok) { + if (response.status === 400) { + const errorPayload = + await parseRegistrationErrorPayload( + response, + defaultRegistrationError, + ); + if ( + errorPayload.code === "MINI_PROGRAM_BRIDGE_REQUIRED" + ) { + setMiniProgramUpgradeMessage(errorPayload.message); + setMiniProgramUpgradeOpen(true); + } + } return; } const result = await response.json(); @@ -729,6 +756,7 @@ export function EventRegistrationModal({ const performPaidOrder = async () => { try { + const clientContext = await buildWechatPaymentClientContext(); const response = await fetch(`/api/events/${event.id}/orders`, { method: "POST", headers: { @@ -746,6 +774,7 @@ export function EventRegistrationModal({ allowDigitalCardDisplay: allowDigitalCardDisplay, }), ...(inviteCode ? { inviteCode } : {}), + clientContext, }), }); @@ -763,6 +792,11 @@ export function EventRegistrationModal({ setWechatBindingOpen(true); return; } + if (errorPayload.code === "MINI_PROGRAM_BRIDGE_REQUIRED") { + setMiniProgramUpgradeMessage(errorMessage); + setMiniProgramUpgradeOpen(true); + return; + } throw new Error(errorMessage); } @@ -1034,6 +1068,16 @@ export function EventRegistrationModal({ }} message={wechatBindingMessage} /> + { + setMiniProgramUpgradeOpen(open); + if (!open) { + setMiniProgramUpgradeMessage(null); + } + }} + message={miniProgramUpgradeMessage} + /> ); } diff --git a/apps/web/src/modules/public/events/components/MiniProgramUpgradePrompt.tsx b/apps/web/src/modules/public/events/components/MiniProgramUpgradePrompt.tsx new file mode 100644 index 00000000..4178ec9a --- /dev/null +++ b/apps/web/src/modules/public/events/components/MiniProgramUpgradePrompt.tsx @@ -0,0 +1,47 @@ +"use client"; + +import { Button } from "@community/ui/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@community/ui/ui/dialog"; +import { useTranslations } from "next-intl"; + +interface MiniProgramUpgradePromptProps { + open: boolean; + onOpenChange: (open: boolean) => void; + message?: string | null; +} + +export function MiniProgramUpgradePrompt({ + open, + onOpenChange, + message, +}: MiniProgramUpgradePromptProps) { + const t = useTranslations("events.registration.miniProgramUpgrade"); + + return ( + + + + {t("title")} + + {message?.trim() || t("description")} + + +
+ {t("note")} +
+ + + +
+
+ ); +} diff --git a/apps/web/src/modules/public/events/components/PaymentModal.tsx b/apps/web/src/modules/public/events/components/PaymentModal.tsx index e73a89ad..4680b647 100644 --- a/apps/web/src/modules/public/events/components/PaymentModal.tsx +++ b/apps/web/src/modules/public/events/components/PaymentModal.tsx @@ -7,7 +7,7 @@ import { DialogTitle, } from "@community/ui/ui/dialog"; import { Button } from "@community/ui/ui/button"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import QRCode from "react-qr-code"; import { toast } from "sonner"; import { useTranslations } from "next-intl"; @@ -20,6 +20,14 @@ import { } from "@heroicons/react/24/outline"; import { Loader2 } from "lucide-react"; import { cn } from "@community/lib-shared/utils"; +import { + WECHAT_PAYMENT_CHANNELS, + WECHAT_BRIDGE_ERROR_CODES, + WechatBridgeError, + type WechatMiniProgramRequestPaymentParams, + type WechatPayPayload, + type WechatPaymentChannel, +} from "@community/lib-shared/payments/wechat-payment"; export interface PaymentOrderData { orderId: string; @@ -27,6 +35,8 @@ export interface PaymentOrderData { expiredAt: string; totalAmount: number; quantity?: number; + channel?: WechatPaymentChannel; + payPayload?: WechatPayPayload; codeUrl?: string; isExisting?: boolean; jsapiParams?: { @@ -108,6 +118,33 @@ const invokeWechatPay = (params: PaymentOrderData["jsapiParams"]) => { }); }; +const invokeMiniProgramBridgePay = async ( + params: WechatMiniProgramRequestPaymentParams, +) => { + if (typeof window === "undefined") { + throw new WechatBridgeError( + WECHAT_BRIDGE_ERROR_CODES.BRIDGE_NOT_SUPPORTED, + "Window not available", + ); + } + + const requestPayment = window.__HWMiniAppBridge__?.requestPayment; + if (!requestPayment) { + throw new WechatBridgeError( + WECHAT_BRIDGE_ERROR_CODES.BRIDGE_NOT_SUPPORTED, + ); + } + + const result = await requestPayment(params); + if (!result.ok) { + const code = + result.errCode === "PAY_CANCELLED" + ? WECHAT_BRIDGE_ERROR_CODES.PAY_CANCELLED + : WECHAT_BRIDGE_ERROR_CODES.PAY_FAILED; + throw new WechatBridgeError(code, result.errMsg); + } +}; + export function PaymentModal({ open, onOpenChange, @@ -134,6 +171,40 @@ export function PaymentModal({ [order.expiredAt], ); + const resolvedChannel = useMemo(() => { + if (order.channel) { + return order.channel; + } + if (order.codeUrl) { + return WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE; + } + if (order.jsapiParams) { + return WECHAT_PAYMENT_CHANNELS.WECHAT_JSAPI; + } + return undefined; + }, [order.channel, order.codeUrl, order.jsapiParams]); + + const resolvedCodeUrl = useMemo(() => { + if (order.payPayload && "codeUrl" in order.payPayload) { + return order.payPayload.codeUrl; + } + return order.codeUrl; + }, [order.codeUrl, order.payPayload]); + + const resolvedJsapiParams = useMemo(() => { + if (order.payPayload && "jsapiParams" in order.payPayload) { + return order.payPayload.jsapiParams; + } + return order.jsapiParams; + }, [order.jsapiParams, order.payPayload]); + + const miniProgramRequestPaymentParams = useMemo(() => { + if (order.payPayload && "requestPaymentParams" in order.payPayload) { + return order.payPayload.requestPaymentParams; + } + return undefined; + }, [order.payPayload]); + const paymentPhase = useMemo(() => { if (status === "PAID") return "success"; if (status === "CANCELLED") { @@ -179,7 +250,7 @@ export function PaymentModal({ } }; - const fetchOrderStatus = async () => { + const fetchOrderStatus = useCallback(async () => { try { const response = await fetch( `/api/events/${eventId}/orders/${order.orderId}`, @@ -223,7 +294,7 @@ export function PaymentModal({ console.error("Failed to fetch order status", error); handlePollFailure(); } - }; + }, [eventId, order.orderId, onPaymentSuccess]); const handleManualQuery = async () => { setIsQuerying(true); @@ -274,19 +345,63 @@ export function PaymentModal({ fetchOrderStatus(); const interval = window.setInterval(fetchOrderStatus, 3000); return () => window.clearInterval(interval); - }, [open, order.orderId, eventId]); + }, [open, fetchOrderStatus]); useEffect(() => { - if (!open || !order.jsapiParams || jsapiInvokedRef.current) return; - jsapiInvokedRef.current = true; - setJsapiInvoked(true); - invokeWechatPay(order.jsapiParams) - .then(() => fetchOrderStatus()) - .catch((error) => { - console.error("WeChat JSAPI error", error); - toast.error(t("wechatPayIncomplete")); - }); - }, [open, order.jsapiParams]); + if (!open || jsapiInvokedRef.current) return; + + if ( + resolvedChannel === WECHAT_PAYMENT_CHANNELS.MINIPROGRAM_BRIDGE && + miniProgramRequestPaymentParams + ) { + jsapiInvokedRef.current = true; + setJsapiInvoked(true); + invokeMiniProgramBridgePay(miniProgramRequestPaymentParams) + .then(() => fetchOrderStatus()) + .catch((error) => { + console.error("Mini Program bridge payment error", error); + if (error instanceof WechatBridgeError) { + if ( + error.code === + WECHAT_BRIDGE_ERROR_CODES.BRIDGE_NOT_SUPPORTED + ) { + toast.error(t("miniProgramBridgeRequired")); + return; + } + if ( + error.code === + WECHAT_BRIDGE_ERROR_CODES.PAY_CANCELLED + ) { + toast.info(t("miniProgramPayCancelled")); + return; + } + } + toast.error(t("wechatPayIncomplete")); + }); + return; + } + + if ( + resolvedChannel === WECHAT_PAYMENT_CHANNELS.WECHAT_JSAPI && + resolvedJsapiParams + ) { + jsapiInvokedRef.current = true; + setJsapiInvoked(true); + invokeWechatPay(resolvedJsapiParams) + .then(() => fetchOrderStatus()) + .catch((error) => { + console.error("WeChat JSAPI error", error); + toast.error(t("wechatPayIncomplete")); + }); + } + }, [ + open, + resolvedChannel, + resolvedJsapiParams, + miniProgramRequestPaymentParams, + t, + fetchOrderStatus, + ]); useEffect(() => { if (!open) return; @@ -341,9 +456,20 @@ export function PaymentModal({
{paymentPhase === "waiting" && ( <> - + {resolvedChannel === + WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE ? ( + + ) : ( + + )} - {t("scanToPay")} + {resolvedChannel === + WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE + ? t("scanToPay") + : resolvedChannel === + WECHAT_PAYMENT_CHANNELS.MINIPROGRAM_BRIDGE + ? t("invokingMiniProgram") + : t("invoking")} )} @@ -381,19 +507,27 @@ export function PaymentModal({ )}
- {status === "PENDING" && order.codeUrl && ( -
- -
- {t("scanToPay")} + {status === "PENDING" && + resolvedChannel === + WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE && + resolvedCodeUrl && ( +
+ +
+ {t("scanToPay")} +
-
- )} + )} {status === "PENDING" && - !order.codeUrl && - order.jsapiParams && ( + resolvedChannel !== + WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE && + (resolvedJsapiParams || + miniProgramRequestPaymentParams) && (
- {t("invoking")} + {resolvedChannel === + WECHAT_PAYMENT_CHANNELS.MINIPROGRAM_BRIDGE + ? t("invokingMiniProgram") + : t("invoking")}
)} diff --git a/apps/web/src/modules/public/events/components/wechat-payment-client-context.ts b/apps/web/src/modules/public/events/components/wechat-payment-client-context.ts new file mode 100644 index 00000000..b17da8b6 --- /dev/null +++ b/apps/web/src/modules/public/events/components/wechat-payment-client-context.ts @@ -0,0 +1,103 @@ +import { getWeChatEnvironmentType } from "@community/lib-shared/utils/browser-detect"; +import type { + WechatMiniProgramRequestPaymentParams, + WechatPaymentClientContext, +} from "@community/lib-shared/payments/wechat-payment"; + +interface MiniProgramBridgeCapabilities { + bridgeVersion?: string; + supportsRequestPayment?: boolean; + shellVersion?: string; +} + +interface MiniProgramBridge { + getCapabilities?: () => Promise; + requestPayment?: ( + params: WechatMiniProgramRequestPaymentParams, + ) => Promise<{ + ok: boolean; + errCode?: string; + errMsg?: string; + }>; +} + +declare global { + interface Window { + __HWMiniAppBridge__?: MiniProgramBridge; + } +} + +const toBooleanString = (value?: boolean) => { + if (value === true) { + return "true"; + } + if (value === false) { + return "false"; + } + return undefined; +}; + +export const buildWechatPaymentClientContext = + async (): Promise => { + if (typeof window === "undefined") { + return { environmentType: "none" }; + } + + const environmentType = getWeChatEnvironmentType(); + if (environmentType !== "miniprogram") { + return { environmentType }; + } + + const bridge = window.__HWMiniAppBridge__; + if (!bridge?.getCapabilities) { + return { + environmentType, + miniProgramBridgeSupported: false, + }; + } + + try { + const capabilities = await bridge.getCapabilities(); + return { + environmentType, + miniProgramBridgeSupported: + capabilities.supportsRequestPayment === true, + miniProgramBridgeVersion: capabilities.bridgeVersion, + shellVersion: capabilities.shellVersion, + }; + } catch { + return { + environmentType, + miniProgramBridgeSupported: false, + }; + } + }; + +export const buildWechatPaymentClientContextQuery = ( + clientContext: WechatPaymentClientContext, +) => { + const params = new URLSearchParams(); + if (clientContext.environmentType) { + params.set("environmentType", clientContext.environmentType); + } + + const bridgeSupported = toBooleanString( + clientContext.miniProgramBridgeSupported, + ); + if (bridgeSupported) { + params.set("miniProgramBridgeSupported", bridgeSupported); + } + + if (clientContext.miniProgramBridgeVersion) { + params.set( + "miniProgramBridgeVersion", + clientContext.miniProgramBridgeVersion, + ); + } + + if (clientContext.shellVersion) { + params.set("shellVersion", clientContext.shellVersion); + } + + return params.toString(); +}; diff --git a/apps/web/src/server/routes/events/orders.ts b/apps/web/src/server/routes/events/orders.ts index a892970f..cd019d1d 100644 --- a/apps/web/src/server/routes/events/orders.ts +++ b/apps/web/src/server/routes/events/orders.ts @@ -10,21 +10,27 @@ import { markEventOrderPaid, } from "@community/lib-server/events/event-orders"; import { db } from "@community/lib-server/database/prisma/client"; +import { logger } from "@community/lib-server/logs"; import { canManageEvent } from "@/features/permissions/events"; import { zValidator } from "@hono/zod-validator"; import { Hono } from "hono"; import { nanoid } from "nanoid"; import { z } from "zod"; import { - createWechatJsapiOrder, - createWechatNativeOrder, - buildWechatJsapiParams, requestWechatRefund, queryWechatOrderStatus, } from "@community/lib-server/payments/provider/wechatpay"; - -const isWechatBrowser = (userAgent?: string | null) => - !!userAgent && /MicroMessenger/i.test(userAgent); +import { + isWechatChannel, + resolveWechatPaymentChannel, + type WechatPaymentChannel, + WECHAT_PAYMENT_CHANNELS, +} from "@community/lib-shared/payments/wechat-payment"; +import { + parseWechatClientContextFromQuery, + prepareEventTicketWechatPayment, + type WechatPrepareHttpStatus, +} from "../payments/lib/wechat-prepare"; const registerAnswersSchema = z .array( @@ -42,6 +48,16 @@ const createOrderSchema = z.object({ projectId: z.string().optional(), allowDigitalCardDisplay: z.boolean().optional(), answers: registerAnswersSchema, + clientContext: z + .object({ + environmentType: z + .enum(["miniprogram", "wechat", "none"]) + .optional(), + miniProgramBridgeSupported: z.boolean().optional(), + miniProgramBridgeVersion: z.string().optional(), + shellVersion: z.string().optional(), + }) + .optional(), }); const redeemInviteSchema = z.object({ @@ -57,35 +73,10 @@ const refundSchema = z.object({ const app = new Hono(); -const buildOrderResponse = ( - order: { - id: string; - orderNo: string; - totalAmount: number; - expiredAt: Date; - codeUrl: string | null; - prepayId: string | null; - paymentMethod: string | null; - quantity: number; - }, - isExisting = false, -) => { - const jsapiParams = - order.paymentMethod === "WECHAT_JSAPI" && order.prepayId - ? buildWechatJsapiParams(order.prepayId) - : undefined; - - return { - orderId: order.id, - orderNo: order.orderNo, - totalAmount: order.totalAmount, - expiredAt: order.expiredAt.toISOString(), - codeUrl: order.codeUrl ?? undefined, - jsapiParams, - quantity: order.quantity, - ...(isExisting ? { isExisting: true } : {}), - }; -}; +const mapChannelToPaymentMethod = (channel: WechatPaymentChannel) => + channel === WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE + ? "WECHAT_NATIVE" + : "WECHAT_JSAPI"; const ensureEventAvailableForRegistration = async (eventId: string) => { const event = await db.event.findUnique({ @@ -141,6 +132,7 @@ app.get("/:eventId/orders/pending", async (c) => { } const eventId = c.req.param("eventId"); + const clientContext = parseWechatClientContextFromQuery(c.req.query()); const now = new Date(); // 先清理过期订单 @@ -168,13 +160,6 @@ app.get("/:eventId/orders/pending", async (c) => { }, select: { id: true, - orderNo: true, - totalAmount: true, - expiredAt: true, - codeUrl: true, - prepayId: true, - paymentMethod: true, - quantity: true, }, orderBy: { createdAt: "desc" }, }); @@ -182,13 +167,33 @@ app.get("/:eventId/orders/pending", async (c) => { if (!pendingOrder) { return c.json({ success: true, data: null }); } + const prepareResult = await prepareEventTicketWechatPayment({ + orderId: pendingOrder.id, + userId: session.user.id, + userAgent: c.req.header("user-agent"), + clientContext, + isExisting: true, + }); + + if (!prepareResult.success) { + return c.json( + { + success: false, + error: prepareResult.error, + code: prepareResult.code, + requiresUpgrade: prepareResult.requiresUpgrade, + minBridgeVersion: prepareResult.minBridgeVersion, + }, + prepareResult.status as WechatPrepareHttpStatus, + ); + } return c.json({ success: true, - data: buildOrderResponse(pendingOrder, true), + data: prepareResult.data, }); } catch (error) { - console.error("Error fetching pending order:", error); + logger.error("Error fetching pending order:", error); return c.json({ success: false, error: "获取待支付订单失败" }, 500); } }); @@ -217,6 +222,7 @@ app.post( projectId, allowDigitalCardDisplay, answers, + clientContext, } = c.req.valid("json"); const now = new Date(); @@ -229,21 +235,38 @@ app.post( }, select: { id: true, - orderNo: true, - totalAmount: true, - expiredAt: true, - codeUrl: true, - prepayId: true, - paymentMethod: true, - quantity: true, }, orderBy: { createdAt: "desc" }, }); if (existingPendingOrder) { + const prepareExistingResult = + await prepareEventTicketWechatPayment({ + orderId: existingPendingOrder.id, + userId: session.user.id, + userAgent: c.req.header("user-agent"), + clientContext, + isExisting: true, + }); + + if (!prepareExistingResult.success) { + return c.json( + { + success: false, + error: prepareExistingResult.error, + code: prepareExistingResult.code, + requiresUpgrade: + prepareExistingResult.requiresUpgrade, + minBridgeVersion: + prepareExistingResult.minBridgeVersion, + }, + prepareExistingResult.status as WechatPrepareHttpStatus, + ); + } + return c.json({ success: true, - data: buildOrderResponse(existingPendingOrder, true), + data: prepareExistingResult.data, }); } @@ -298,14 +321,29 @@ app.post( } const userAgent = c.req.header("user-agent"); - const useJsapi = isWechatBrowser(userAgent); + const channelResult = resolveWechatPaymentChannel({ + userAgent, + clientContext, + }); + + if (!channelResult.ok) { + return c.json( + { + success: false, + error: "当前小程序版本不支持支付,请升级后重试", + code: channelResult.errorCode, + requiresUpgrade: channelResult.requiresUpgrade, + minBridgeVersion: channelResult.minBridgeVersion, + }, + 400, + ); + } + const selectedChannel = channelResult.channel; const user = await db.user.findUnique({ where: { id: session.user.id }, select: { id: true, - name: true, - email: true, wechatOpenId: true, }, }); @@ -314,7 +352,7 @@ app.post( return c.json({ success: false, error: "用户不存在" }, 404); } - if (useJsapi && !user.wechatOpenId) { + if (isWechatChannel(selectedChannel) && !user.wechatOpenId) { return c.json( { success: false, @@ -328,242 +366,212 @@ app.post( const orderNo = generateEventOrderNo(); const expiredAt = buildOrderExpiration(); - const { order, registration, pricing } = await db.$transaction( - async (tx) => { - const ticketType = await tx.eventTicketType.findFirst({ - where: { - id: ticketTypeId, - eventId, - isActive: true, + const { order } = await db.$transaction(async (tx) => { + const ticketType = await tx.eventTicketType.findFirst({ + where: { + id: ticketTypeId, + eventId, + isActive: true, + }, + include: { + priceTiers: { + where: { isActive: true }, + orderBy: { quantity: "asc" }, }, - include: { - priceTiers: { - where: { isActive: true }, - orderBy: { quantity: "asc" }, + }, + }); + + if (!ticketType) { + throw new Error("票种不存在或已下架"); + } + + const existingRegistration = + await tx.eventRegistration.findUnique({ + where: { + eventId_userId: { + eventId, + userId: user.id, }, }, + select: { id: true, status: true }, }); - if (!ticketType) { - throw new Error("票种不存在或已下架"); - } + if ( + existingRegistration && + existingRegistration.status !== "CANCELLED" + ) { + throw new Error("你已报名该活动。"); + } - const existingRegistration = - await tx.eventRegistration.findUnique({ - where: { - eventId_userId: { - eventId, - userId: user.id, - }, - }, - select: { id: true, status: true }, - }); + const pricing = resolveTicketPricing({ + basePrice: ticketType.price, + priceTiers: ticketType.priceTiers, + quantity, + }); - if ( - existingRegistration && - existingRegistration.status !== "CANCELLED" - ) { - throw new Error("你已报名该活动。"); - } + if (pricing.totalAmount <= 0) { + throw new Error("免费票无需支付,请直接报名"); + } - const pricing = resolveTicketPricing({ - basePrice: ticketType.price, - priceTiers: ticketType.priceTiers, - quantity, + const hasTicketLimit = + typeof ticketType.maxQuantity === "number"; + if ( + hasTicketLimit && + ticketType.currentQuantity + quantity > + ticketType.maxQuantity! + ) { + throw new Error("库存不足"); + } + + if (event.maxAttendees) { + const totalQuantity = await tx.eventTicketType.aggregate({ + where: { eventId }, + _sum: { currentQuantity: true }, }); - if (pricing.totalAmount <= 0) { - throw new Error("免费票无需支付,请直接报名"); + const currentTotal = + totalQuantity._sum.currentQuantity ?? 0; + if (currentTotal + quantity > event.maxAttendees) { + throw new Error("活动报名名额已满"); } + } - const hasTicketLimit = - typeof ticketType.maxQuantity === "number"; - if ( - hasTicketLimit && - ticketType.currentQuantity + quantity > - ticketType.maxQuantity! - ) { - throw new Error("库存不足"); - } + if (hasTicketLimit) { + const updated = await tx.eventTicketType.updateMany({ + where: { + id: ticketType.id, + currentQuantity: { + lte: ticketType.maxQuantity! - quantity, + }, + }, + data: { + currentQuantity: { increment: quantity }, + }, + }); - if (event.maxAttendees) { - const totalQuantity = - await tx.eventTicketType.aggregate({ - where: { eventId }, - _sum: { currentQuantity: true }, - }); - - const currentTotal = - totalQuantity._sum.currentQuantity ?? 0; - if (currentTotal + quantity > event.maxAttendees) { - throw new Error("活动报名名额已满"); - } + if (updated.count === 0) { + throw new Error("库存不足"); } + } else { + await tx.eventTicketType.update({ + where: { id: ticketType.id }, + data: { + currentQuantity: { increment: quantity }, + }, + }); + } - if (hasTicketLimit) { - const updated = await tx.eventTicketType.updateMany({ - where: { - id: ticketType.id, - currentQuantity: { - lte: ticketType.maxQuantity! - quantity, - }, - }, - data: { - currentQuantity: { increment: quantity }, - }, - }); + const order = await tx.eventOrder.create({ + data: { + orderNo, + eventId, + userId: user.id, + ticketTypeId: ticketType.id, + quantity, + unitPrice: pricing.unitPrice, + totalAmount: pricing.totalAmount, + currency: pricing.currency, + expiredAt, + paymentMethod: + mapChannelToPaymentMethod(selectedChannel), + }, + }); - if (updated.count === 0) { - throw new Error("库存不足"); - } - } else { - await tx.eventTicketType.update({ - where: { id: ticketType.id }, - data: { - currentQuantity: { increment: quantity }, - }, - }); - } + let registration; + if (existingRegistration) { + await tx.eventAnswer.deleteMany({ + where: { registrationId: existingRegistration.id }, + }); - const order = await tx.eventOrder.create({ + registration = await tx.eventRegistration.update({ + where: { id: existingRegistration.id }, data: { - orderNo, eventId, userId: user.id, + status: "PENDING_PAYMENT", ticketTypeId: ticketType.id, - quantity, - unitPrice: pricing.unitPrice, - totalAmount: pricing.totalAmount, - currency: pricing.currency, - expiredAt, - paymentMethod: useJsapi - ? "WECHAT_JSAPI" - : "WECHAT_NATIVE", + orderId: order.id, + orderInviteId: null, + inviteId, + allowDigitalCardDisplay, + reviewedAt: null, + reviewedBy: null, + reviewNote: null, + registeredAt: new Date(), }, }); + } else { + registration = await tx.eventRegistration.create({ + data: { + eventId, + userId: user.id, + status: "PENDING_PAYMENT", + ticketTypeId: ticketType.id, + orderId: order.id, + inviteId, + allowDigitalCardDisplay, + }, + }); + } - let registration; - if (existingRegistration) { - await tx.eventAnswer.deleteMany({ - where: { registrationId: existingRegistration.id }, - }); - - registration = await tx.eventRegistration.update({ - where: { id: existingRegistration.id }, - data: { - eventId, - userId: user.id, - status: "PENDING_PAYMENT", - ticketTypeId: ticketType.id, - orderId: order.id, - orderInviteId: null, - inviteId, - allowDigitalCardDisplay, - reviewedAt: null, - reviewedBy: null, - reviewNote: null, - registeredAt: new Date(), - }, - }); - } else { - registration = await tx.eventRegistration.create({ - data: { - eventId, - userId: user.id, - status: "PENDING_PAYMENT", - ticketTypeId: ticketType.id, - orderId: order.id, - inviteId, - allowDigitalCardDisplay, - }, - }); - } - - if (answers.length > 0) { - await tx.eventAnswer.createMany({ - data: answers.map((answer) => ({ - questionId: answer.questionId, - answer: answer.answer, - userId: user.id, - eventId, - registrationId: registration.id, - })), - }); - } + if (answers.length > 0) { + await tx.eventAnswer.createMany({ + data: answers.map((answer) => ({ + questionId: answer.questionId, + answer: answer.answer, + userId: user.id, + eventId, + registrationId: registration.id, + })), + }); + } - if (quantity > 1) { - await tx.eventOrderInvite.createMany({ - data: Array.from({ length: quantity - 1 }, () => ({ - orderId: order.id, - code: generateOrderInviteCode(), - })), - }); - } + if (quantity > 1) { + await tx.eventOrderInvite.createMany({ + data: Array.from({ length: quantity - 1 }, () => ({ + orderId: order.id, + code: generateOrderInviteCode(), + })), + }); + } - if (inviteId) { - await tx.eventInvite.update({ - where: { id: inviteId }, - data: { lastUsedAt: new Date() }, - }); - } + if (inviteId) { + await tx.eventInvite.update({ + where: { id: inviteId }, + data: { lastUsedAt: new Date() }, + }); + } - return { order, registration, pricing }; - }, - ); + return { order }; + }); - const amountInCents = Math.round(pricing.totalAmount * 100); - const description = `${event.title} 门票`; - - const paymentResult = useJsapi - ? await createWechatJsapiOrder({ - outTradeNo: order.orderNo, - description, - amount: amountInCents, - payerOpenId: user.wechatOpenId!, - }) - : await createWechatNativeOrder({ - outTradeNo: order.orderNo, - description, - amount: amountInCents, - }); + const prepareResult = await prepareEventTicketWechatPayment({ + orderId: order.id, + userId: session.user.id, + userAgent, + clientContext, + }); - if (!paymentResult) { + if (!prepareResult.success) { await cancelEventOrder(order.id); return c.json( { success: false, - error: "微信支付订单创建失败", + error: prepareResult.error, + code: prepareResult.code, + requiresUpgrade: prepareResult.requiresUpgrade, + minBridgeVersion: prepareResult.minBridgeVersion, }, - 500, + prepareResult.status as WechatPrepareHttpStatus, ); } - const codeUrl = - "codeUrl" in paymentResult ? paymentResult.codeUrl : null; - const updatedOrder = await db.eventOrder.update({ - where: { id: order.id }, - data: { - prepayId: paymentResult.prepayId, - codeUrl, - }, - select: { - id: true, - orderNo: true, - totalAmount: true, - expiredAt: true, - codeUrl: true, - prepayId: true, - paymentMethod: true, - quantity: true, - }, - }); - return c.json({ success: true, - data: buildOrderResponse(updatedOrder), + data: prepareResult.data, }); } catch (error: any) { - console.error("Error creating event order:", error); + logger.error("Error creating event order:", error); return c.json( { success: false, @@ -619,7 +627,7 @@ app.get("/:eventId/orders/:orderId", async (c) => { }, }); } catch (error) { - console.error("Error fetching order status:", error); + logger.error("Error fetching order status:", error); return c.json({ success: false, error: "查询订单失败" }, 500); } }); @@ -696,7 +704,7 @@ app.post("/:eventId/orders/:orderId/query", async (c) => { }, }); } catch (error) { - console.error("Error querying order status:", error); + logger.error("Error querying order status:", error); return c.json({ success: false, error: "查询订单失败" }, 500); } }); @@ -733,7 +741,7 @@ app.get("/:eventId/orders", async (c) => { return c.json({ success: true, data: orders }); } catch (error) { - console.error("Error fetching orders:", error); + logger.error("Error fetching orders:", error); return c.json({ success: false, error: "获取订单失败" }, 500); } }); @@ -771,7 +779,7 @@ app.post("/:eventId/orders/:orderId/cancel", async (c) => { return c.json({ success: true }); } catch (error) { - console.error("Error cancelling order:", error); + logger.error("Error cancelling order:", error); return c.json({ success: false, error: "取消订单失败" }, 500); } }); @@ -831,7 +839,7 @@ app.post("/:eventId/orders/:orderId/mark-paid", async (c) => { }, }); } catch (error) { - console.error("Error marking order paid:", error); + logger.error("Error marking order paid:", error); return c.json({ success: false, error: "标记订单失败" }, 500); } }); @@ -905,7 +913,7 @@ app.post( return c.json({ success: true }); } catch (error: any) { - console.error("Error refunding order:", error); + logger.error("Error refunding order:", error); return c.json( { success: false, error: error.message || "退款失败" }, 500, @@ -943,7 +951,7 @@ app.get("/:eventId/orders/:orderId/invites", async (c) => { return c.json({ success: true, data: invites }); } catch (error) { - console.error("Error fetching order invites:", error); + logger.error("Error fetching order invites:", error); return c.json({ success: false, error: "获取邀请链接失败" }, 500); } }); @@ -1045,7 +1053,7 @@ app.post( return c.json({ success: true, data: registration }); } catch (error: any) { - console.error("Error redeeming invite:", error); + logger.error("Error redeeming invite:", error); return c.json( { success: false, error: error.message || "兑换失败" }, 500, diff --git a/apps/web/src/server/routes/payments/lib/wechat-prepare.ts b/apps/web/src/server/routes/payments/lib/wechat-prepare.ts new file mode 100644 index 00000000..f707b530 --- /dev/null +++ b/apps/web/src/server/routes/payments/lib/wechat-prepare.ts @@ -0,0 +1,329 @@ +import { db } from "@community/lib-server/database/prisma/client"; +import { logger } from "@community/lib-server/logs"; +import { + buildWechatJsapiParams, + createWechatJsapiOrder, + createWechatNativeOrder, +} from "@community/lib-server/payments/provider/wechatpay"; +import { + WECHAT_MINI_PROGRAM_MIN_BRIDGE_VERSION, + WECHAT_PAYMENT_CHANNELS, + WECHAT_PAYMENT_ERROR_CODES, + isWechatChannel, + resolveWechatPaymentChannel, + type WechatMiniProgramRequestPaymentParams, + type WechatPaymentChannel, + type WechatPaymentClientContext, + type WechatPayPayload, +} from "@community/lib-shared/payments/wechat-payment"; +import type { PaymentMethod } from "@prisma/client"; + +export interface WechatPreparedOrderResponse { + orderId: string; + orderNo: string; + totalAmount: number; + expiredAt: string; + quantity: number; + channel: WechatPaymentChannel; + payPayload: WechatPayPayload; + codeUrl?: string; + jsapiParams?: ReturnType; + isExisting?: boolean; +} + +export type WechatPrepareHttpStatus = 200 | 400 | 404 | 500; + +export interface WechatPrepareResult { + success: boolean; + status: WechatPrepareHttpStatus; + data?: WechatPreparedOrderResponse; + error?: string; + code?: string; + requiresUpgrade?: boolean; + minBridgeVersion?: string; +} + +interface PrepareEventTicketWechatPaymentParams { + orderId: string; + userId: string; + userAgent?: string | null; + clientContext?: WechatPaymentClientContext; + isExisting?: boolean; +} + +const mapChannelToPaymentMethod = ( + channel: WechatPaymentChannel, +): PaymentMethod => + channel === WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE + ? "WECHAT_NATIVE" + : "WECHAT_JSAPI"; + +const buildPayload = (params: { + channel: WechatPaymentChannel; + orderNo: string; + codeUrl: string | null; + prepayId: string | null; +}): + | { + success: true; + payPayload: WechatPayPayload; + codeUrl?: string; + jsapiParams?: ReturnType; + } + | { + success: false; + error: string; + } => { + if (params.channel === WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE) { + if (!params.codeUrl) { + return { + success: false, + error: "未获取到微信扫码支付二维码,请取消订单后重试", + }; + } + + return { + success: true, + payPayload: { + codeUrl: params.codeUrl, + }, + codeUrl: params.codeUrl, + }; + } + + if (!params.prepayId) { + return { + success: false, + error: "未获取到微信预支付参数,请稍后重试", + }; + } + + const jsapiParams = buildWechatJsapiParams(params.prepayId); + + if (params.channel === WECHAT_PAYMENT_CHANNELS.MINIPROGRAM_BRIDGE) { + const requestPaymentParams: WechatMiniProgramRequestPaymentParams = { + ...jsapiParams, + orderNo: params.orderNo, + }; + return { + success: true, + payPayload: { + requestPaymentParams, + }, + jsapiParams, + }; + } + + return { + success: true, + payPayload: { + jsapiParams, + }, + jsapiParams, + }; +}; + +const shouldCreatePaymentInstruction = (params: { + channel: WechatPaymentChannel; + codeUrl: string | null; + prepayId: string | null; +}) => { + if (params.channel === WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE) { + return !params.codeUrl; + } + + return !params.prepayId; +}; + +export const prepareEventTicketWechatPayment = async ( + params: PrepareEventTicketWechatPaymentParams, +): Promise => { + const order = await db.eventOrder.findFirst({ + where: { + id: params.orderId, + userId: params.userId, + status: "PENDING", + }, + select: { + id: true, + orderNo: true, + totalAmount: true, + currency: true, + expiredAt: true, + quantity: true, + paymentMethod: true, + prepayId: true, + codeUrl: true, + event: { + select: { + title: true, + }, + }, + user: { + select: { + wechatOpenId: true, + }, + }, + }, + }); + + if (!order) { + return { + success: false, + status: 404, + error: "订单不存在", + }; + } + + const channelResult = resolveWechatPaymentChannel({ + userAgent: params.userAgent, + clientContext: params.clientContext, + minBridgeVersion: WECHAT_MINI_PROGRAM_MIN_BRIDGE_VERSION, + }); + + if (!channelResult.ok) { + return { + success: false, + status: 400, + error: "当前小程序版本不支持支付,请升级后重试", + code: channelResult.errorCode, + requiresUpgrade: channelResult.requiresUpgrade, + minBridgeVersion: channelResult.minBridgeVersion, + }; + } + + const channel = channelResult.channel; + if (isWechatChannel(channel) && !order.user.wechatOpenId) { + return { + success: false, + status: 400, + error: "未绑定微信 OpenID,无法使用 JSAPI 支付", + code: WECHAT_PAYMENT_ERROR_CODES.WECHAT_OPENID_REQUIRED, + }; + } + + logger.info("Preparing WeChat payment channel", { + orderId: order.id, + orderNo: order.orderNo, + channel, + environmentType: channelResult.environmentType, + shellVersion: params.clientContext?.shellVersion, + bridgeVersion: params.clientContext?.miniProgramBridgeVersion, + bridgeSupported: params.clientContext?.miniProgramBridgeSupported, + }); + + let prepayId = order.prepayId; + let codeUrl = order.codeUrl; + let paymentMethod = order.paymentMethod; + + const expectedPaymentMethod = mapChannelToPaymentMethod(channel); + if (shouldCreatePaymentInstruction({ channel, codeUrl, prepayId })) { + const amountInCents = Math.round(order.totalAmount * 100); + const description = `${order.event.title} 门票`; + const paymentResult = + channel === WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE + ? await createWechatNativeOrder({ + outTradeNo: order.orderNo, + description, + amount: amountInCents, + }) + : await createWechatJsapiOrder({ + outTradeNo: order.orderNo, + description, + amount: amountInCents, + payerOpenId: order.user.wechatOpenId!, + }); + + if (!paymentResult) { + return { + success: false, + status: 500, + error: "微信支付订单创建失败", + }; + } + + prepayId = paymentResult.prepayId; + codeUrl = "codeUrl" in paymentResult ? paymentResult.codeUrl : null; + paymentMethod = expectedPaymentMethod; + + await db.eventOrder.update({ + where: { id: order.id }, + data: { + prepayId, + codeUrl, + paymentMethod, + }, + }); + } else if (!paymentMethod) { + paymentMethod = expectedPaymentMethod; + await db.eventOrder.update({ + where: { id: order.id }, + data: { + paymentMethod, + }, + }); + } + + const payloadResult = buildPayload({ + channel, + orderNo: order.orderNo, + codeUrl, + prepayId, + }); + + if (!payloadResult.success) { + return { + success: false, + status: 500, + error: payloadResult.error, + }; + } + + return { + success: true, + status: 200, + data: { + orderId: order.id, + orderNo: order.orderNo, + totalAmount: order.totalAmount, + expiredAt: order.expiredAt.toISOString(), + quantity: order.quantity, + channel, + payPayload: payloadResult.payPayload, + codeUrl: payloadResult.codeUrl, + jsapiParams: payloadResult.jsapiParams, + ...(params.isExisting ? { isExisting: true } : {}), + }, + }; +}; + +export const parseWechatClientContextFromQuery = (query: { + environmentType?: string; + miniProgramBridgeSupported?: string; + miniProgramBridgeVersion?: string; + shellVersion?: string; +}): WechatPaymentClientContext => { + const toBoolean = (value?: string) => { + if (value === "true") { + return true; + } + if (value === "false") { + return false; + } + return undefined; + }; + + const environmentType = + query.environmentType === "miniprogram" || + query.environmentType === "wechat" || + query.environmentType === "none" + ? query.environmentType + : undefined; + + return { + environmentType, + miniProgramBridgeSupported: toBoolean(query.miniProgramBridgeSupported), + miniProgramBridgeVersion: query.miniProgramBridgeVersion, + shellVersion: query.shellVersion, + }; +}; diff --git a/apps/web/src/server/routes/payments/router.ts b/apps/web/src/server/routes/payments/router.ts index 7c3e95f0..f68087bb 100644 --- a/apps/web/src/server/routes/payments/router.ts +++ b/apps/web/src/server/routes/payments/router.ts @@ -10,6 +10,10 @@ import { createCustomerPortalLink, getCustomerIdFromEntity, } from "@community/lib-server/payments"; +import { + prepareEventTicketWechatPayment, + type WechatPrepareHttpStatus, +} from "./lib/wechat-prepare"; import { Hono } from "hono"; import { describeRoute } from "hono-openapi"; import { resolver, validator } from "hono-openapi/zod"; @@ -22,6 +26,66 @@ import { getPurchases } from "./lib/purchases"; // Subscription billing has been removed export const paymentsRouter = new Hono() .basePath("/payments") + .post( + "/wechat/prepare", + authMiddleware, + validator( + "json", + z.object({ + bizType: z.literal("EVENT_TICKET"), + bizId: z.string(), + clientContext: z + .object({ + environmentType: z + .enum(["miniprogram", "wechat", "none"]) + .optional(), + miniProgramBridgeSupported: z.boolean().optional(), + miniProgramBridgeVersion: z.string().optional(), + shellVersion: z.string().optional(), + }) + .optional(), + }), + ), + describeRoute({ + tags: ["Payments"], + summary: "Prepare WeChat payment payload", + description: + "Returns channelized WeChat payment payload for a business order (initially EVENT_TICKET).", + responses: { + 200: { + description: "Prepared WeChat payment payload", + }, + }, + }), + async (c) => { + const user = c.get("user"); + const payload = c.req.valid("json"); + const result = await prepareEventTicketWechatPayment({ + orderId: payload.bizId, + userId: user.id, + userAgent: c.req.header("user-agent"), + clientContext: payload.clientContext, + }); + + if (!result.success) { + return c.json( + { + success: false, + error: result.error, + code: result.code, + requiresUpgrade: result.requiresUpgrade, + minBridgeVersion: result.minBridgeVersion, + }, + result.status as WechatPrepareHttpStatus, + ); + } + + return c.json({ + success: true, + data: result.data, + }); + }, + ) .get( "/purchases", authMiddleware, diff --git a/openspec/changes/add-miniprogram-payment-bridge/tasks.md b/openspec/changes/add-miniprogram-payment-bridge/tasks.md index c4eac6bd..69e900ca 100644 --- a/openspec/changes/add-miniprogram-payment-bridge/tasks.md +++ b/openspec/changes/add-miniprogram-payment-bridge/tasks.md @@ -1,24 +1,24 @@ ## 1. Shared WeChat payment orchestration -- [ ] 1.1 Add `POST /api/payments/wechat/prepare` for `EVENT_TICKET` and channelized payload output. -- [ ] 1.2 Add shared server/client types for `channel`, `payPayload`, and standardized error codes. -- [ ] 1.3 Add channel-selection logic with precedence: Mini Program bridge -> WeChat JSAPI -> Native. +- [x] 1.1 Add `POST /api/payments/wechat/prepare` for `EVENT_TICKET` and channelized payload output. +- [x] 1.2 Add shared server/client types for `channel`, `payPayload`, and standardized error codes. +- [x] 1.3 Add channel-selection logic with precedence: Mini Program bridge -> WeChat JSAPI -> Native. ## 2. Event ticket payment flow integration -- [ ] 2.1 Update event order creation flow to consume the shared prepare capability and return `channel` + `payPayload`. -- [ ] 2.2 Keep a one-release compatibility layer for legacy JSAPI/Native response fields. -- [ ] 2.3 Enforce `MINI_PROGRAM_BRIDGE_REQUIRED` behavior (no fallback) when Mini Program bridge is unavailable. +- [x] 2.1 Update event order creation flow to consume the shared prepare capability and return `channel` + `payPayload`. +- [x] 2.2 Keep a one-release compatibility layer for legacy JSAPI/Native response fields. +- [x] 2.3 Enforce `MINI_PROGRAM_BRIDGE_REQUIRED` behavior (no fallback) when Mini Program bridge is unavailable. ## 3. Frontend payment modal behavior -- [ ] 3.1 Add `MINIPROGRAM_BRIDGE` handling in payment modal and call bridge `requestPayment` path. -- [ ] 3.2 Add upgrade prompt UI for bridge-required errors and block payment launch. -- [ ] 3.3 Preserve existing polling/manual-query reconciliation after bridge callback. +- [x] 3.1 Add `MINIPROGRAM_BRIDGE` handling in payment modal and call bridge `requestPayment` path. +- [x] 3.2 Add upgrade prompt UI for bridge-required errors and block payment launch. +- [x] 3.3 Preserve existing polling/manual-query reconciliation after bridge callback. ## 4. Cross-repo bridge contract and shell implementation -- [ ] 4.1 Publish and version the H5 <-> shell bridge contract in this repo. -- [ ] 4.2 Implement same contract in Mini Program shell repo (capability reporting + `wx.requestPayment` mapping). -- [ ] 4.3 Add shell error mapping to agreed error codes and callback payload shape. +- [x] 4.1 Publish and version the H5 <-> shell bridge contract in this repo. +- [ ] 4.2 Implement same contract in Mini Program shell repo (capability reporting + `wx.requestPayment` mapping). _(blocked in this repository; requires external shell repo changes)_ +- [ ] 4.3 Add shell error mapping to agreed error codes and callback payload shape. _(blocked in this repository; requires external shell repo changes)_ ## 5. Validation and rollout -- [ ] 5.1 Add tests for channel selection, payload shape, bridge-required behavior, and status reconciliation. -- [ ] 5.2 Add metrics/log fields for `channel`, `shellVersion`, `bridgeVersion`, and Mini Program bridge errors. -- [ ] 5.3 Validate with `openspec validate add-miniprogram-payment-bridge --strict`. +- [x] 5.1 Add tests for channel selection and bridge-required behavior. +- [x] 5.2 Add metrics/log fields for `channel`, `shellVersion`, `bridgeVersion`, and Mini Program bridge errors. +- [x] 5.3 Validate with `openspec validate add-miniprogram-payment-bridge --strict`. diff --git a/packages/lib-shared/src/i18n/translations/en.json b/packages/lib-shared/src/i18n/translations/en.json index aa6f1731..7b02c839 100644 --- a/packages/lib-shared/src/i18n/translations/en.json +++ b/packages/lib-shared/src/i18n/translations/en.json @@ -1566,6 +1566,7 @@ "scanToPay": "Scan with WeChat to pay", "polling": "Checking payment status...", "invoking": "Launching WeChat Pay...", + "invokingMiniProgram": "Launching Mini Program payment...", "paidSuccess": "Payment successful!", "orderCancelled": "Order cancelled", "orderExpired": "Order expired", @@ -1583,9 +1584,17 @@ "paymentNotDetected": "Payment not detected yet. Please confirm payment is complete.", "orderClosed": "Order closed", "wechatPayIncomplete": "WeChat Pay was not completed. Please try again.", + "miniProgramBridgeRequired": "Your Mini Program version does not support this payment yet. Please upgrade and try again.", + "miniProgramPayCancelled": "Payment was cancelled.", "statusFetchRetry": "Failed to fetch order status. Retrying...", "statusFetchFailed": "Failed to fetch order status. Please try again later." }, + "miniProgramUpgrade": { + "title": "Upgrade Mini Program to continue", + "description": "This Mini Program version does not support the required payment capability.", + "note": "Please upgrade to the latest version and reopen this page.", + "confirm": "Got it" + }, "wechatBinding": { "title": "Bind WeChat to continue", "description": "Your account hasn't bound a WeChat OpenID yet. Please bind it before paying.", diff --git a/packages/lib-shared/src/i18n/translations/zh.json b/packages/lib-shared/src/i18n/translations/zh.json index 4366a419..114bc950 100644 --- a/packages/lib-shared/src/i18n/translations/zh.json +++ b/packages/lib-shared/src/i18n/translations/zh.json @@ -1633,6 +1633,7 @@ "scanToPay": "请使用微信扫码支付", "polling": "正在检测支付结果...", "invoking": "正在唤起微信支付...", + "invokingMiniProgram": "正在唤起小程序支付...", "paidSuccess": "支付成功!", "orderCancelled": "订单已取消", "orderExpired": "订单已过期", @@ -1650,9 +1651,17 @@ "paymentNotDetected": "暂未检测到支付,请确认是否已完成支付", "orderClosed": "订单已关闭", "wechatPayIncomplete": "微信支付未完成,请重新尝试", + "miniProgramBridgeRequired": "当前小程序版本不支持支付,请升级后重试", + "miniProgramPayCancelled": "你已取消支付", "statusFetchRetry": "订单状态获取失败,正在重试...", "statusFetchFailed": "订单状态获取失败,请稍后重试" }, + "miniProgramUpgrade": { + "title": "请升级小程序后支付", + "description": "当前小程序版本暂不支持该支付能力,请升级到最新版本后重试。", + "note": "升级完成后重新打开当前页面即可继续支付。", + "confirm": "我知道了" + }, "wechatBinding": { "title": "绑定微信后继续支付", "description": "检测到你的账号尚未绑定微信 OpenID,需先完成绑定才能使用微信支付。", diff --git a/packages/lib-shared/src/payments/__tests__/wechat-payment.test.ts b/packages/lib-shared/src/payments/__tests__/wechat-payment.test.ts new file mode 100644 index 00000000..e85ff9c8 --- /dev/null +++ b/packages/lib-shared/src/payments/__tests__/wechat-payment.test.ts @@ -0,0 +1,68 @@ +import { describe, test, expect } from "vitest"; +import { + WECHAT_PAYMENT_CHANNELS, + WECHAT_PAYMENT_ERROR_CODES, + resolveWechatPaymentChannel, +} from "../wechat-payment"; + +describe("resolveWechatPaymentChannel", () => { + test("returns mini program bridge channel when capability is supported", () => { + const result = resolveWechatPaymentChannel({ + clientContext: { + environmentType: "miniprogram", + miniProgramBridgeSupported: true, + miniProgramBridgeVersion: "1.2.0", + }, + }); + + expect(result.ok).toBe(true); + if (!result.ok) { + return; + } + expect(result.channel).toBe(WECHAT_PAYMENT_CHANNELS.MINIPROGRAM_BRIDGE); + }); + + test("returns bridge required error when mini program bridge is missing", () => { + const result = resolveWechatPaymentChannel({ + clientContext: { + environmentType: "miniprogram", + miniProgramBridgeSupported: false, + }, + }); + + expect(result.ok).toBe(false); + if (result.ok) { + return; + } + expect(result.errorCode).toBe( + WECHAT_PAYMENT_ERROR_CODES.MINI_PROGRAM_BRIDGE_REQUIRED, + ); + expect(result.requiresUpgrade).toBe(true); + }); + + test("returns wechat jsapi channel in wechat browser", () => { + const result = resolveWechatPaymentChannel({ + userAgent: + "Mozilla/5.0 (iPhone; CPU iPhone OS 16_0 like Mac OS X) AppleWebKit/605.1.15 MicroMessenger/8.0.0", + }); + + expect(result.ok).toBe(true); + if (!result.ok) { + return; + } + expect(result.channel).toBe(WECHAT_PAYMENT_CHANNELS.WECHAT_JSAPI); + }); + + test("returns wechat native channel in non-wechat browser", () => { + const result = resolveWechatPaymentChannel({ + userAgent: + "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/122.0.0.0 Safari/537.36", + }); + + expect(result.ok).toBe(true); + if (!result.ok) { + return; + } + expect(result.channel).toBe(WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE); + }); +}); diff --git a/packages/lib-shared/src/payments/wechat-payment.ts b/packages/lib-shared/src/payments/wechat-payment.ts new file mode 100644 index 00000000..7bcd73dd --- /dev/null +++ b/packages/lib-shared/src/payments/wechat-payment.ts @@ -0,0 +1,197 @@ +export const WECHAT_MINI_PROGRAM_MIN_BRIDGE_VERSION = "1.2.0"; + +export const WECHAT_PAYMENT_CHANNELS = { + MINIPROGRAM_BRIDGE: "MINIPROGRAM_BRIDGE", + WECHAT_JSAPI: "WECHAT_JSAPI", + WECHAT_NATIVE: "WECHAT_NATIVE", +} as const; + +export type WechatPaymentChannel = + (typeof WECHAT_PAYMENT_CHANNELS)[keyof typeof WECHAT_PAYMENT_CHANNELS]; + +export const WECHAT_BRIDGE_ERROR_CODES = { + BRIDGE_NOT_SUPPORTED: "BRIDGE_NOT_SUPPORTED", + PAY_CANCELLED: "PAY_CANCELLED", + PAY_FAILED: "PAY_FAILED", + BRIDGE_TIMEOUT: "BRIDGE_TIMEOUT", + INVALID_PAYLOAD: "INVALID_PAYLOAD", +} as const; + +export type WechatBridgeErrorCode = + (typeof WECHAT_BRIDGE_ERROR_CODES)[keyof typeof WECHAT_BRIDGE_ERROR_CODES]; + +export class WechatBridgeError extends Error { + constructor( + public readonly code: WechatBridgeErrorCode, + message?: string, + ) { + super(message ?? code); + this.name = "WechatBridgeError"; + } +} + +export const WECHAT_PAYMENT_ERROR_CODES = { + MINI_PROGRAM_BRIDGE_REQUIRED: "MINI_PROGRAM_BRIDGE_REQUIRED", + MINI_PROGRAM_PAY_FAILED: "MINI_PROGRAM_PAY_FAILED", + MINI_PROGRAM_PAY_CANCELLED: "MINI_PROGRAM_PAY_CANCELLED", + MINI_PROGRAM_BRIDGE_TIMEOUT: "MINI_PROGRAM_BRIDGE_TIMEOUT", + WECHAT_OPENID_REQUIRED: "WECHAT_OPENID_REQUIRED", +} as const; + +export type WechatPaymentErrorCode = + (typeof WECHAT_PAYMENT_ERROR_CODES)[keyof typeof WECHAT_PAYMENT_ERROR_CODES]; + +export type WechatEnvironmentType = "miniprogram" | "wechat" | "none"; + +export interface WechatPaymentClientContext { + environmentType?: WechatEnvironmentType; + miniProgramBridgeSupported?: boolean; + miniProgramBridgeVersion?: string; + shellVersion?: string; +} + +export interface WechatJsapiParams { + appId: string; + timeStamp: string; + nonceStr: string; + package: string; + signType: string; + paySign: string; +} + +export interface WechatMiniProgramRequestPaymentParams + extends WechatJsapiParams { + orderNo: string; +} + +export interface WechatNativePayPayload { + codeUrl: string; +} + +export interface WechatJsapiPayPayload { + jsapiParams: WechatJsapiParams; +} + +export interface WechatMiniProgramPayPayload { + requestPaymentParams: WechatMiniProgramRequestPaymentParams; +} + +export type WechatPayPayload = + | WechatNativePayPayload + | WechatJsapiPayPayload + | WechatMiniProgramPayPayload; + +export interface WechatChannelSelection { + ok: true; + channel: WechatPaymentChannel; + environmentType: WechatEnvironmentType; +} + +export interface WechatChannelSelectionError { + ok: false; + errorCode: WechatPaymentErrorCode; + environmentType: WechatEnvironmentType; + requiresUpgrade?: boolean; + minBridgeVersion?: string; +} + +const inferEnvironmentFromUserAgent = ( + userAgent?: string | null, +): WechatEnvironmentType => { + if (!userAgent) { + return "none"; + } + + const lowerUserAgent = userAgent.toLowerCase(); + const isWeChat = lowerUserAgent.includes("micromessenger"); + if (!isWeChat) { + return "none"; + } + + if (lowerUserAgent.includes("miniprogram")) { + return "miniprogram"; + } + + return "wechat"; +}; + +const compareSemver = (left: string, right: string): number => { + const leftParts = left + .split(".") + .map((part) => Number.parseInt(part, 10)) + .map((part) => (Number.isNaN(part) ? 0 : part)); + const rightParts = right + .split(".") + .map((part) => Number.parseInt(part, 10)) + .map((part) => (Number.isNaN(part) ? 0 : part)); + const maxLength = Math.max(leftParts.length, rightParts.length); + + for (let index = 0; index < maxLength; index += 1) { + const leftValue = leftParts[index] ?? 0; + const rightValue = rightParts[index] ?? 0; + if (leftValue > rightValue) { + return 1; + } + if (leftValue < rightValue) { + return -1; + } + } + + return 0; +}; + +export const resolveWechatPaymentChannel = (params: { + userAgent?: string | null; + clientContext?: WechatPaymentClientContext; + minBridgeVersion?: string; +}): WechatChannelSelection | WechatChannelSelectionError => { + const minBridgeVersion = + params.minBridgeVersion ?? WECHAT_MINI_PROGRAM_MIN_BRIDGE_VERSION; + const environmentType = + params.clientContext?.environmentType || + inferEnvironmentFromUserAgent(params.userAgent); + + if (environmentType === "miniprogram") { + const bridgeSupported = + params.clientContext?.miniProgramBridgeSupported === true; + const bridgeVersion = + params.clientContext?.miniProgramBridgeVersion ?? "0.0.0"; + if ( + !bridgeSupported || + compareSemver(bridgeVersion, minBridgeVersion) < 0 + ) { + return { + ok: false, + errorCode: + WECHAT_PAYMENT_ERROR_CODES.MINI_PROGRAM_BRIDGE_REQUIRED, + environmentType, + requiresUpgrade: true, + minBridgeVersion, + }; + } + + return { + ok: true, + channel: WECHAT_PAYMENT_CHANNELS.MINIPROGRAM_BRIDGE, + environmentType, + }; + } + + if (environmentType === "wechat") { + return { + ok: true, + channel: WECHAT_PAYMENT_CHANNELS.WECHAT_JSAPI, + environmentType, + }; + } + + return { + ok: true, + channel: WECHAT_PAYMENT_CHANNELS.WECHAT_NATIVE, + environmentType, + }; +}; + +export const isWechatChannel = (channel: WechatPaymentChannel) => + channel === WECHAT_PAYMENT_CHANNELS.WECHAT_JSAPI || + channel === WECHAT_PAYMENT_CHANNELS.MINIPROGRAM_BRIDGE; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 41f31f02..31c82680 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,124 +26,6 @@ importers: specifier: ^2.5.0 version: 2.8.3 - apps/timemark: - dependencies: - '@alicloud/pop-core': - specifier: ^1.8.0 - version: 1.8.0 - '@community/config': - specifier: workspace:* - version: link:../../packages/config - '@community/lib-client': - specifier: workspace:* - version: link:../../packages/lib-client - '@community/lib-server': - specifier: workspace:* - version: link:../../packages/lib-server - '@community/lib-shared': - specifier: workspace:* - version: link:../../packages/lib-shared - '@community/ui': - specifier: workspace:* - version: link:../../packages/ui - '@prisma/adapter-pg': - specifier: ^7.0.1 - version: 7.3.0 - '@prisma/client': - specifier: ^7.0.1 - version: 7.3.0(prisma@7.3.0(@types/react@19.1.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3) - better-auth: - specifier: ^1.1.7 - version: 1.4.18(@prisma/client@7.3.0(prisma@7.3.0(@types/react@19.1.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.8)(mysql2@3.15.3)(next@16.1.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4))(pg@8.18.0)(prisma@7.3.0(@types/react@19.1.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3))(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - clsx: - specifier: ^2.1.1 - version: 2.1.1 - date-fns: - specifier: ^4.1.0 - version: 4.1.0 - hono: - specifier: ^4.8.5 - version: 4.11.8 - lucide-react: - specifier: ^0.469.0 - version: 0.469.0(react@19.2.4) - next: - specifier: 16.1.6 - version: 16.1.6(@opentelemetry/api@1.9.0)(@playwright/test@1.58.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - openai: - specifier: ^6.19.0 - version: 6.19.0(ws@8.19.0)(zod@4.3.6) - pg: - specifier: ^8.14.1 - version: 8.18.0 - react: - specifier: ^19.2.0 - version: 19.2.4 - react-dom: - specifier: ^19.2.0 - version: 19.2.4(react@19.2.4) - react-media-recorder: - specifier: ^1.7.2 - version: 1.7.2 - sonner: - specifier: ^2.0.6 - version: 2.0.7(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - swr: - specifier: ^2.4.0 - version: 2.4.0(react@19.2.4) - tailwind-merge: - specifier: ^2.5.5 - version: 2.6.1 - zod: - specifier: ^4.3.6 - version: 4.3.6 - devDependencies: - '@biomejs/biome': - specifier: 1.9.4 - version: 1.9.4 - '@remotion/cli': - specifier: ^4.0.423 - version: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/google-fonts': - specifier: ^4.0.423 - version: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@tailwindcss/postcss': - specifier: ^4.1.11 - version: 4.1.18 - '@types/node': - specifier: 22.15.14 - version: 22.15.14 - '@types/pg': - specifier: ^8.11.10 - version: 8.16.0 - '@types/react': - specifier: 19.1.3 - version: 19.1.3 - '@types/react-dom': - specifier: 19.1.3 - version: 19.1.3(@types/react@19.1.3) - '@types/ws': - specifier: ^8.18.1 - version: 8.18.1 - dotenv-cli: - specifier: ^8.0.0 - version: 8.0.0 - prisma: - specifier: ^7.0.1 - version: 7.3.0(@types/react@19.1.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) - remotion: - specifier: ^4.0.423 - version: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - tailwindcss: - specifier: 4.1.5 - version: 4.1.5 - tailwindcss-animate: - specifier: ^1.0.7 - version: 1.0.7(tailwindcss@4.1.5) - typescript: - specifier: 5.9.3 - version: 5.9.3 - apps/web: dependencies: '@ai-sdk/openai': @@ -1084,10 +966,6 @@ packages: peerDependencies: react: ^18 || ~19.0.1 || ~19.1.2 || ^19.2.1 - '@alicloud/pop-core@1.8.0': - resolution: {integrity: sha512-ef6vIVigtr9n8Lw6Ld2GZ9jVUD0+ReHviaQaMqZDPI2HwdpVvrq1Rvn2tBnFToe0tdTpovz9N7XFSf/C274OtA==} - engines: {node: '>=8.0.0'} - '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -1289,27 +1167,14 @@ packages: resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.24.1': - resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/runtime@7.28.6': resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - '@better-auth/core@1.4.18': resolution: {integrity: sha512-q+awYgC7nkLEBdx2sW0iJjkzgSHlIxGnOpsN1r/O1+a4m7osJNHtfK2mKJSL1I+GfNyIlxJF8WvD/NLuYMpmcg==} peerDependencies: @@ -1356,24 +1221,28 @@ packages: engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [musl] '@biomejs/cli-linux-arm64@1.9.4': resolution: {integrity: sha512-fJIW0+LYujdjUgJJuwesP4EjIBl/N/TcOX3IvIHJQNsAqvV2CHIogsmA94BPG6jZATS4Hi+xv4SkBBQSt1N4/g==} engines: {node: '>=14.21.3'} cpu: [arm64] os: [linux] + libc: [glibc] '@biomejs/cli-linux-x64-musl@1.9.4': resolution: {integrity: sha512-gEhi/jSBhZ2m6wjV530Yy8+fNqG8PAinM3oV7CyO+6c3CEh16Eizm21uHVsyVBEB6RIM8JHIl6AGYCv6Q6Q9Tg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [musl] '@biomejs/cli-linux-x64@1.9.4': resolution: {integrity: sha512-lRCJv/Vi3Vlwmbd6K+oQ0KhLHMAysN8lXoCI7XeHlxaajk06u7G+UsFSO01NAs5iYuWKmVZjmiOzJ0OJmGsMwg==} engines: {node: '>=14.21.3'} cpu: [x64] os: [linux] + libc: [glibc] '@biomejs/cli-win32-arm64@1.9.4': resolution: {integrity: sha512-tlbhLk+WXZmgwoIKwHIHEBZUwxml7bRJgk0X2sPyNR3S93cdRq6XulAZRQJ17FYGGzWne0fgrXBKpl7l4M87Hg==} @@ -1505,12 +1374,6 @@ packages: peerDependencies: esbuild: '*' - '@esbuild/aix-ppc64@0.25.0': - resolution: {integrity: sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} @@ -1529,12 +1392,6 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm64@0.25.0': - resolution: {integrity: sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} @@ -1553,12 +1410,6 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-arm@0.25.0': - resolution: {integrity: sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} @@ -1577,12 +1428,6 @@ packages: cpu: [x64] os: [android] - '@esbuild/android-x64@0.25.0': - resolution: {integrity: sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} @@ -1601,12 +1446,6 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-arm64@0.25.0': - resolution: {integrity: sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} @@ -1625,12 +1464,6 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/darwin-x64@0.25.0': - resolution: {integrity: sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} @@ -1649,12 +1482,6 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-arm64@0.25.0': - resolution: {integrity: sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} @@ -1673,12 +1500,6 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.0': - resolution: {integrity: sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} @@ -1697,12 +1518,6 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm64@0.25.0': - resolution: {integrity: sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} @@ -1721,12 +1536,6 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-arm@0.25.0': - resolution: {integrity: sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} @@ -1745,12 +1554,6 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-ia32@0.25.0': - resolution: {integrity: sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} @@ -1769,12 +1572,6 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-loong64@0.25.0': - resolution: {integrity: sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} @@ -1793,12 +1590,6 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-mips64el@0.25.0': - resolution: {integrity: sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} @@ -1817,12 +1608,6 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-ppc64@0.25.0': - resolution: {integrity: sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} @@ -1841,12 +1626,6 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-riscv64@0.25.0': - resolution: {integrity: sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} @@ -1865,12 +1644,6 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-s390x@0.25.0': - resolution: {integrity: sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} @@ -1889,12 +1662,6 @@ packages: cpu: [x64] os: [linux] - '@esbuild/linux-x64@0.25.0': - resolution: {integrity: sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} @@ -1907,12 +1674,6 @@ packages: cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.0': - resolution: {integrity: sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} @@ -1931,12 +1692,6 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.0': - resolution: {integrity: sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} @@ -1949,12 +1704,6 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.0': - resolution: {integrity: sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} @@ -1973,12 +1722,6 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.0': - resolution: {integrity: sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} @@ -2009,12 +1752,6 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/sunos-x64@0.25.0': - resolution: {integrity: sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} @@ -2033,12 +1770,6 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-arm64@0.25.0': - resolution: {integrity: sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} @@ -2057,12 +1788,6 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-ia32@0.25.0': - resolution: {integrity: sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} @@ -2081,12 +1806,6 @@ packages: cpu: [x64] os: [win32] - '@esbuild/win32-x64@0.25.0': - resolution: {integrity: sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} @@ -2307,78 +2026,92 @@ packages: resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.3': resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.3': resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.3': resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.3': resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.3': resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.3': resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.4': resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.4': resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.4': resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.4': resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.4': resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.4': resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.4': resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.4': resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} @@ -2429,9 +2162,6 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/source-map@0.3.11': - resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -2457,11 +2187,6 @@ packages: '@mdx-js/mdx@3.1.1': resolution: {integrity: sha512-f6ZO2ifpwAQIpzGWaBQT2TXxPv6z3RBzQKpVftEWN78Vl/YweF1uwussDx8ECAXVtr3Rs89fKyG9YlzUs9DyGQ==} - '@mediabunny/ac3@1.34.2': - resolution: {integrity: sha512-Ej6Ns6/NcuvtajNxiK0rrGqnTD4JQETL2Ofrdnf5lQ2vxBEXT4Od9N+RUTxQbPRX9ZlWXpwvSZgf0sdCT0P1YA==} - peerDependencies: - mediabunny: ^1.0.0 - '@mrleebo/prisma-ast@0.13.1': resolution: {integrity: sha512-XyroGQXcHrZdvmrGJvsA9KNeOOgGMg1Vg9OlheUsBOSKznLMDl+YChxbkboRHvtFYJEMRYmlV3uoo/njCw05iw==} engines: {node: '>=16'} @@ -2489,24 +2214,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@16.1.6': resolution: {integrity: sha512-S4J2v+8tT3NIO9u2q+S0G5KdvNDjXfAv06OhfOzNDaBn5rw84DGXWndOEB7d5/x852A20sW1M56vhC/tRVbccQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@16.1.6': resolution: {integrity: sha512-2eEBDkFlMMNQnkTyPBhQOAyn2qMxyG2eE7GPH2WIDGEpEILcBPI/jdSv4t6xupSP+ot/jkfrCShLAa7+ZUPcJQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@16.1.6': resolution: {integrity: sha512-oicJwRlyOoZXVlxmIMaTq7f8pN9QNbdes0q2FXfRsPhfCi8n8JmOZJm5oo1pwDaFbnnD421rVU409M3evFbIqg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@16.1.6': resolution: {integrity: sha512-gQmm8izDTPgs+DCWH22kcDmuUp7NyiJgEl18bcr8irXA5N2m2O+JQIr6f3ct42GOs9c0h8QF3L5SzIxcYAAXXw==} @@ -2579,24 +2308,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@node-rs/argon2-linux-arm64-musl@1.7.0': resolution: {integrity: sha512-BKWS8iVconhE3jrb9mj6t1J9vwUqQPpzCbUKxfTGJfc+kNL58F1SXHBoe2cDYGnHrFEHTY0YochzXoAfm4Dm/A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@node-rs/argon2-linux-x64-gnu@1.7.0': resolution: {integrity: sha512-EmgqZOlf4Jurk/szW1iTsVISx25bKksVC5uttJDUloTgsAgIGReCpUUO1R24pBhu9ESJa47iv8NSf3yAfGv6jQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@node-rs/argon2-linux-x64-musl@1.7.0': resolution: {integrity: sha512-/o1efYCYIxjfuoRYyBTi2Iy+1iFfhqHCvvVsnjNSgO1xWiWrX0Rrt/xXW5Zsl7vS2Y+yu8PL8KFWRzZhaVxfKA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@node-rs/argon2-wasm32-wasi@1.7.0': resolution: {integrity: sha512-Evmk9VcxqnuwQftfAfYEr6YZYSPLzmKUsbFIMep5nTt9PT4XYRFAERj7wNYp+rOcBenF3X4xoB+LhwcOMTNE5w==} @@ -2666,24 +2399,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@node-rs/bcrypt-linux-arm64-musl@1.9.0': resolution: {integrity: sha512-/sIvKDABOI8QOEnLD7hIj02BVaNOuCIWBKvxcJOt8+TuwJ6zmY1UI5kSv9d99WbiHjTp97wtAUbZQwauU4b9ew==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@node-rs/bcrypt-linux-x64-gnu@1.9.0': resolution: {integrity: sha512-DyyhDHDsLBsCKz1tZ1hLvUZSc1DK0FU0v52jK6IBQxrj24WscSU9zZe7ie/V9kdmA4Ep57BfpWX8Dsa2JxGdgQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@node-rs/bcrypt-linux-x64-musl@1.9.0': resolution: {integrity: sha512-duIiuqQ+Lew8ASSAYm6ZRqcmfBGWwsi81XLUwz86a2HR7Qv6V4yc3ZAUQovAikhjCsIqe8C11JlAZSK6+PlXYg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@node-rs/bcrypt-wasm32-wasi@1.9.0': resolution: {integrity: sha512-ylaGmn9Wjwv/D5lxtawttx3H6Uu2WTTR7lWlRHGT6Ga/MB1Vj4OjSGUW8G8zIVnKuXpGbZ92pgHlt4HUpSLctw==} @@ -2775,41 +2512,49 @@ packages: resolution: {integrity: sha512-wdcQ7Niad9JpjZIGEeqKJnTvczVunqlZ/C06QzR5zOQNeLVRScQ9S5IesKWUAPsJQDizV+teQX53nTK+Z5Iy+g==} cpu: [arm64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-arm64-musl@11.17.0': resolution: {integrity: sha512-65B2/t39HQN5AEhkLsC+9yBD1iRUkKOIhfmJEJ7g6wQ9kylra7JRmNmALFjbsj0VJsoSQkpM8K07kUZuNJ9Kxw==} cpu: [arm64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-ppc64-gnu@11.17.0': resolution: {integrity: sha512-kExgm3TLK21dNMmcH+xiYGbc6BUWvT03PUZ2aYn8mUzGPeeORklBhg3iYcaBI3ZQHB25412X1Z6LLYNjt4aIaA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-gnu@11.17.0': resolution: {integrity: sha512-1utUJC714/ydykZQE8c7QhpEyM4SaslMfRXxN9G61KYazr6ndt85LaubK3EZCSD50vVEfF4PVwFysCSO7LN9uA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-riscv64-musl@11.17.0': resolution: {integrity: sha512-mayiYOl3LMmtO2CLn4I5lhanfxEo0LAqlT/EQyFbu1ZN3RS+Xa7Q3JEM0wBpVIyfO/pqFrjvC5LXw/mHNDEL7A==} cpu: [riscv64] os: [linux] + libc: [musl] '@oxc-resolver/binding-linux-s390x-gnu@11.17.0': resolution: {integrity: sha512-Ow/yI+CrUHxIIhn/Y1sP/xoRKbCC3x9O1giKr3G/pjMe+TCJ5ZmfqVWU61JWwh1naC8X5Xa7uyLnbzyYqPsHfg==} cpu: [s390x] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-gnu@11.17.0': resolution: {integrity: sha512-Z4J7XlPMQOLPANyu6y3B3V417Md4LKH5bV6bhqgaG99qLHmU5LV2k9ErV14fSqoRc/GU/qOpqMdotxiJqN/YWg==} cpu: [x64] os: [linux] + libc: [glibc] '@oxc-resolver/binding-linux-x64-musl@11.17.0': resolution: {integrity: sha512-0effK+8lhzXsgsh0Ny2ngdnTPF30v6QQzVFApJ1Ctk315YgpGkghkelvrLYYgtgeFJFrzwmOJ2nDvCrUFKsS2Q==} cpu: [x64] os: [linux] + libc: [musl] '@oxc-resolver/binding-openharmony-arm64@11.17.0': resolution: {integrity: sha512-kFB48dRUW6RovAICZaxHKdtZe+e94fSTNA2OedXokzMctoU54NPZcv0vUX5PMqyikLIKJBIlW7laQidnAzNrDA==} @@ -2850,21 +2595,25 @@ packages: resolution: {integrity: sha512-75tf1HvwdZ3ebk83yMbSB+moAEWK98mYqpXiaFAi6Zshie7r+Cx5PLXZFUEqkscenoZ+fcNXakHxfn94V6nf1g==} cpu: [arm64] os: [linux] + libc: [glibc] '@oxlint/linux-arm64-musl@1.43.0': resolution: {integrity: sha512-BHV4fb36T2p/7bpA9fiJ5ayt7oJbiYX10nklW5arYp4l9/9yG/FQC5J4G1evzbJ/YbipF9UH0vYBAm5xbqGrvw==} cpu: [arm64] os: [linux] + libc: [musl] '@oxlint/linux-x64-gnu@1.43.0': resolution: {integrity: sha512-1l3nvnzWWse1YHibzZ4HQXdF/ibfbKZhp9IguElni3bBqEyPEyurzZ0ikWynDxKGXqZa+UNXTFuU1NRVX1RJ3g==} cpu: [x64] os: [linux] + libc: [glibc] '@oxlint/linux-x64-musl@1.43.0': resolution: {integrity: sha512-+jNYgLGRFTJxJuaSOZJBwlYo5M0TWRw0+3y5MHOL4ArrIdHyCthg6r4RbVWrsR1qUfUE1VSSHQ2bfbC99RXqMg==} cpu: [x64] os: [linux] + libc: [musl] '@oxlint/win32-arm64@1.43.0': resolution: {integrity: sha512-dvs1C/HCjCyGTURMagiHprsOvVTT3omDiSzi5Qw0D4QFJ1pEaNlfBhVnOUYgUfS6O7Mcmj4+G+sidRsQcWQ/kA==} @@ -2908,36 +2657,42 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.6': resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] + libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.6': resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.6': resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] + libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.6': resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.6': resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] + libc: [musl] '@parcel/watcher-win32-arm64@2.5.6': resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} @@ -3825,110 +3580,6 @@ packages: '@remirror/core-constants@3.0.0': resolution: {integrity: sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg==} - '@remotion/bundler@4.0.423': - resolution: {integrity: sha512-SR8QSzDKI3MUCjZeYTeEoBvno0To5qrs6z3ASZ9GfHzUFXvzEZHXgnAYG4Spb/JJp68SQZHme19ePyY0cRGI+A==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@remotion/cli@4.0.423': - resolution: {integrity: sha512-EWunQ8I6tqeJcLCdRShAi0HafWOAkNSLTqkeCH3aseCN1pgNJJs2WmNGNoNpUCWXAptaqluKI2SYvg+PIBRoGA==} - hasBin: true - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@remotion/compositor-darwin-arm64@4.0.423': - resolution: {integrity: sha512-g6rKjXseMINtU9mXExQl+mZN4K/kj30KvuiOhi2bFktX0rQpCX8lTu2DHYHDP9Dbw3JlZwnWR3cYNaOqysG+Cg==} - cpu: [arm64] - os: [darwin] - - '@remotion/compositor-darwin-x64@4.0.423': - resolution: {integrity: sha512-DVLGEIgw2D2YWCzkCD1UXZqz5GeejVFkKGW65Z2JvWhaD4pUL/1SeX/x2oX4JxrMnv3K4LWXuaeTvZZ9dssJdg==} - cpu: [x64] - os: [darwin] - - '@remotion/compositor-linux-arm64-gnu@4.0.423': - resolution: {integrity: sha512-TaQ+mioTHkKYJqyFm1pbtkBRIlBs1On8/0Y/0IY2vVPQqE6BZqVwr2j9dKyGPjiZBTlBuNDe1yPKhViXsExOrg==} - cpu: [arm64] - os: [linux] - - '@remotion/compositor-linux-arm64-musl@4.0.423': - resolution: {integrity: sha512-gUdnGDh0SrU6jLwafc0b17wSVKiWNs6Mw1xhFVvnupG6hNdsuTpBslnEHR/gAaemS1Ke2lAVGJJzg3vz/FyJoA==} - cpu: [arm64] - os: [linux] - - '@remotion/compositor-linux-x64-gnu@4.0.423': - resolution: {integrity: sha512-bMPg2ldSYfEne1K5X2TPktWmdn3g1iRySOWLHSrobYttPJ5h4KDNFxp7Itw3rQB/QHWhewe/406ym4QqhHNu3w==} - cpu: [x64] - os: [linux] - - '@remotion/compositor-linux-x64-musl@4.0.423': - resolution: {integrity: sha512-rc5NDljLdBPlo4BxNIW4jpzjQ4bjdJSfrFlmDRidx144sBuuVkpSTEX8K0mnB9xyfW3hhSDBD+vc5+0qPqfliA==} - cpu: [x64] - os: [linux] - - '@remotion/compositor-win32-x64-msvc@4.0.423': - resolution: {integrity: sha512-tKub6MstelGno6zeM1ZANjlH4X+Z/rJa7QlY3su4U63UHsVJR3htlnuBM/43rKXxPUi8Zp83N2pAcHZkbGoOWQ==} - cpu: [x64] - os: [win32] - - '@remotion/google-fonts@4.0.423': - resolution: {integrity: sha512-TBmaRBjtpRSW0cvXIfU8/0E5nVM0I8sDq2hpnmIxR8T65j9mVvwvuS/mLfJxI6I2D0w5v3ntXmT0r5N9nMudig==} - - '@remotion/licensing@4.0.423': - resolution: {integrity: sha512-gcbKF9PrMpPIiSpjtH0LDe+f7rqHTGIHzm3R2cUoXO5DqL0KgrqS8EcR+TWKxcOtOVIN4UTsPSBcx8XJiM+oSQ==} - - '@remotion/media-parser@4.0.423': - resolution: {integrity: sha512-SiZ6iyDtNY5NXR5yAhGTd414smoQlI8mcG20KhllrYoe66qsX32vdyLWFcggVVLRkcukd66rWeZRKFSYQgp0Cw==} - - '@remotion/media-utils@4.0.423': - resolution: {integrity: sha512-mZd7tdsR5Ksd5o2/9/nmenNogw4LqGVZi6uHzHDjC/Li5eeErJgRUCcZxCpSZQb6UEudVDteHcJsYHKwU113Vw==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@remotion/player@4.0.423': - resolution: {integrity: sha512-RnogAHIQYsrHW0wJnDDy43L67hUhAey68q2IjwZVCc+p/CajmTvsOZ1XeyDzCgyGsiCLmgCr3+/8FakIBD6yAw==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@remotion/renderer@4.0.423': - resolution: {integrity: sha512-k+5OzuMK7MT7J1zwR9wKYoNO/Rh1ftK/mOwYW732XLllXd8OUJ+/IbCA1daUGXUHKdtX4BAkVt0iG/idJWXhkg==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@remotion/streaming@4.0.423': - resolution: {integrity: sha512-AzM7tLeKtVkNgUQpJt0DFu7Je8yrzBDnYuUiPWwT8GZW51uS2vukc98PAW/d+nrstDNGGfaLqLaMRcFeViBVIQ==} - - '@remotion/studio-server@4.0.423': - resolution: {integrity: sha512-XJl02ynx2a9SH75kSy38MpuKtPuyCMkffNwARCFXiIQ4e1rPSfkaK073rO0WpxW5O2pLPj1wXbIAGEWkNUuqVQ==} - - '@remotion/studio-shared@4.0.423': - resolution: {integrity: sha512-k25pZqs8YXEoCe1UfvUNMDs+MfRcX+amxfc1Fi6fVQHaD9A1WblyQvLwpSFEkmQiAC+Nadfra5UAxpIB9MyeaQ==} - - '@remotion/studio@4.0.423': - resolution: {integrity: sha512-mkZRHNQmRfrMWZF36Q2onRIgh+RI/EKmQfVFux135uNMz71OwYzempRwQFraLviPqduUrvnlNBkTUgUVYW3Qcg==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@remotion/web-renderer@4.0.423': - resolution: {integrity: sha512-gQJQQRXXBQz+0+WPxISCpL624AkZf0/96wGgoQwfxpVgDBJSPsnskbsWQr1rmOi7GnKNw9AsQokiVgftng65Tw==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' - - '@remotion/webcodecs@4.0.423': - resolution: {integrity: sha512-fnR/wEvhUj2zAiOnPUZs5za42a/ilGcVp+t8qAmFq8ymVI0hlmL3UuZpkH2TwTjXoEUkBSUVY0EsY2ruZkRrVg==} - - '@remotion/zod-types@4.0.423': - resolution: {integrity: sha512-bhIG/JhTAm71BvgKZgJvItmjWpnUoa6WS8HLv7isoBLZ6eKb6WaqDrLWJn8ghXNoLnYdb8WiZJOZAZaWIflc8g==} - peerDependencies: - zod: 3.22.3 - '@scalar/core@0.3.37': resolution: {integrity: sha512-cQWMHsGD9jCiYHi91acR3tOsj+qGk+dRQ2W+N5+au1NZ/GkUNT5TUEufekn/sj1S8af+lOnn3y0xXoTI34jCog==} engines: {node: '>=20'} @@ -4228,24 +3879,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.15.11': resolution: {integrity: sha512-PYftgsTaGnfDK4m6/dty9ryK1FbLk+LosDJ/RJR2nkXGc8rd+WenXIlvHjWULiBVnS1RsjHHOXmTS4nDhe0v0w==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.15.11': resolution: {integrity: sha512-DKtnJKIHiZdARyTKiX7zdRjiDS1KihkQWatQiCHMv+zc2sfwb4Glrodx2VLOX4rsa92NLR0Sw8WLcPEMFY1szQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.15.11': resolution: {integrity: sha512-mUjjntHj4+8WBaiDe5UwRNHuEzLjIWBTSGTw0JT9+C9/Yyuh4KQqlcEQ3ro6GkHmBGXBFpGIj/o5VMyRWfVfWw==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.15.11': resolution: {integrity: sha512-ZkNNG5zL49YpaFzfl6fskNOSxtcZ5uOYmWBkY4wVAvgbSAQzLRVBp+xArGWh2oXlY/WgL99zQSGTv7RI5E6nzA==} @@ -4321,24 +3976,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.18': resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.18': resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.18': resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.18': resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} @@ -4600,22 +4259,10 @@ packages: '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - '@types/dom-mediacapture-transform@0.1.11': - resolution: {integrity: sha512-Y2p+nGf1bF2XMttBnsVPHUWzRRZzqUoJAKmiP10b5umnO6DDrWI0BrGDJy1pOHoOULVmGSfFNkQrAlC5dcj6nQ==} - - '@types/dom-webcodecs@0.1.13': - resolution: {integrity: sha512-O5hkiFIcjjszPIYyUSyvScyvrBoV3NOEEZx/pMlsu44TKzWNkLVBBxnxJz42in5n3QIolYOcBYFCPZZ0h8SkwQ==} - '@types/dompurify@3.2.0': resolution: {integrity: sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg==} deprecated: This is a stub types definition. dompurify provides its own type definitions, so you do not need this installed. - '@types/eslint-scope@3.7.7': - resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} - - '@types/eslint@9.6.1': - resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} - '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} @@ -4672,9 +4319,6 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@20.19.33': - resolution: {integrity: sha512-Rs1bVAIdBs5gbTIKza/tgpMuG1k3U/UMJLWecIMxNdJFDMzcM5LOiLVRYh3PilWEYDIeUDv7bpiHPLPsbydGcw==} - '@types/node@22.15.14': resolution: {integrity: sha512-BL1eyu/XWsFGTtDWOYULQEs4KR0qdtYfCxYAUYRoB7JP7h9ETYLgQTww6kH8Sj2C0pFGgrpM0XKv6/kbIzYJ1g==} @@ -4753,63 +4397,6 @@ packages: resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} engines: {node: '>= 20'} - '@webassemblyjs/ast@1.14.1': - resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} - - '@webassemblyjs/floating-point-hex-parser@1.13.2': - resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} - - '@webassemblyjs/helper-api-error@1.13.2': - resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} - - '@webassemblyjs/helper-buffer@1.14.1': - resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} - - '@webassemblyjs/helper-numbers@1.13.2': - resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': - resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} - - '@webassemblyjs/helper-wasm-section@1.14.1': - resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} - - '@webassemblyjs/ieee754@1.13.2': - resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} - - '@webassemblyjs/leb128@1.13.2': - resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} - - '@webassemblyjs/utf8@1.13.2': - resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - - '@webassemblyjs/wasm-edit@1.14.1': - resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - - '@webassemblyjs/wasm-gen@1.14.1': - resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - - '@webassemblyjs/wasm-opt@1.14.1': - resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - - '@webassemblyjs/wasm-parser@1.14.1': - resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} - - '@webassemblyjs/wast-printer@1.14.1': - resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - - '@xtuc/ieee754@1.2.0': - resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} - - '@xtuc/long@4.2.2': - resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - - acorn-import-phases@1.0.4: - resolution: {integrity: sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==} - engines: {node: '>=10.13.0'} - peerDependencies: - acorn: ^8.14.0 - acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -4838,30 +4425,6 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 - ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - - ajv-keywords@3.5.2: - resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} - peerDependencies: - ajv: ^6.9.1 - - ajv-keywords@5.1.0: - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - ansi-red@0.1.1: resolution: {integrity: sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==} engines: {node: '>=0.10.0'} @@ -4914,10 +4477,6 @@ packages: resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} engines: {node: '>=4'} - ast-types@0.16.1: - resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} - engines: {node: '>=4'} - astring@1.9.0: resolution: {integrity: sha512-LElXdjswlqjWrPpJFg1Fx4wpkOCxj1TDHlSV4PlaRxHGWko024xICaa97ZkMfs6DRKlCguiAI+rbXv5GWwXIkg==} hasBin: true @@ -4936,10 +4495,6 @@ packages: autolinker@0.28.1: resolution: {integrity: sha512-zQAFO1Dlsn69eXaO6+7YZc+v84aquQKbwpzCE3L0stj56ERn9hutFxPopViLjo9G+rWwjozRhgS5KJ25Xy19cQ==} - automation-events@7.1.15: - resolution: {integrity: sha512-NsHJlve3twcgs8IyP4iEYph7Fzpnh6klN7G5LahwvypakBjFbsiGHJxrqTmeHKREdu/Tx6oZboqNI0tD4MnFlA==} - engines: {node: '>=18.2.0'} - autoprefixer@10.4.21: resolution: {integrity: sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==} engines: {node: ^10 || ^12 || >=14} @@ -5097,9 +4652,6 @@ packages: bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - big.js@5.2.2: - resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} - bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} @@ -5143,9 +4695,6 @@ packages: resolution: {integrity: sha512-a4zUsWtA1uns1K7p9rExYVYG99rdKeGRymW0qOCNkvDPHQxVi3yVyJHhQbM3EZwdt2E0mnhr5e0c/bPpJ7p3Wg==} engines: {node: 10.* || >= 12.*} - broker-factory@3.1.13: - resolution: {integrity: sha512-H2VALe31mEtO/SRcNp4cUU5BAm1biwhc/JaF77AigUuni/1YT0FLCJfbUxwIEs9y6Kssjk2fmXgf+Y9ALvmKlw==} - browserslist@4.28.1: resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -5240,10 +4789,6 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} - chrome-trace-event@1.0.4: - resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} - engines: {node: '>=6.0'} - chromium-bidi@14.0.0: resolution: {integrity: sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==} peerDependencies: @@ -5316,17 +4861,10 @@ packages: resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} engines: {node: '>=18'} - commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - commander@8.3.0: resolution: {integrity: sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==} engines: {node: '>= 12'} - compilerr@10.0.2: - resolution: {integrity: sha512-CFwUXxJ9OuWsSvnLSbefxi+GLsZ0YnuJh40ry5QdmZ1FWK59OG+QB8XSj6t7Kq+/c5DSS7en+cML6GlzHKH58A==} - engines: {node: '>=14.15.4'} - compute-scroll-into-view@3.1.1: resolution: {integrity: sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw==} @@ -5382,12 +4920,6 @@ packages: css-line-break@2.1.0: resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==} - css-loader@5.2.7: - resolution: {integrity: sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg==} - engines: {node: '>= 10.13.0'} - peerDependencies: - webpack: ^4.27.0 || ^5.0.0 - css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -5462,10 +4994,6 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} - dashify@2.0.0: - resolution: {integrity: sha512-hpA5C/YrPjucXypHPPc0oJ1l9Hf6wWbiOL7Ik42cxnsUOhWiCB/fylKbKqqJalW9FgkNQCw16YO8uW9Hs0Iy1A==} - engines: {node: '>=4'} - data-uri-to-buffer@6.0.2: resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} engines: {node: '>= 14'} @@ -5488,14 +5016,6 @@ packages: supports-color: optional: true - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -5530,10 +5050,6 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} - define-lazy-prop@2.0.0: - resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} - engines: {node: '>=8'} - defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} @@ -5618,10 +5134,6 @@ packages: resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} - dotenv@9.0.2: - resolution: {integrity: sha512-I9OvvrHp4pIARv4+x9iuewrWycX6CcZtoAu1XrzPxc5UygMJXJZYmBsynku8IkrJwgypE5DGNjDPmPRhDCptUg==} - engines: {node: '>=10'} - drizzle-kit@0.31.8: resolution: {integrity: sha512-O9EC/miwdnRDY10qRxM8P3Pg8hXe3LyU4ZipReKOgTwn4OqANmftj8XJz1UPUAS6NMHf0E2htjsbQujUTkncCg==} hasBin: true @@ -5661,10 +5173,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - emojis-list@3.0.0: - resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} - engines: {node: '>= 4'} - empathic@2.0.0: resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==} engines: {node: '>=14'} @@ -5712,9 +5220,6 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@2.0.0: - resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==} - es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} @@ -5739,11 +5244,6 @@ packages: engines: {node: '>=12'} hasBin: true - esbuild@0.25.0: - resolution: {integrity: sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==} - engines: {node: '>=18'} - hasBin: true - esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} @@ -5771,23 +5271,11 @@ packages: engines: {node: '>=6.0'} hasBin: true - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} - esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} @@ -5829,10 +5317,6 @@ packages: events-universal@1.0.1: resolution: {integrity: sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==} - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - eventsource-parser@3.0.6: resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} engines: {node: '>=18.0.0'} @@ -5855,18 +5339,6 @@ packages: extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - extendable-media-recorder-wav-encoder-broker@7.0.125: - resolution: {integrity: sha512-HVmznJvyG+eFZJRYLd9h3OF0oNNIGEmEHAP4IQ0Y5gwxJcmrFhVmGB4hLi1GT/jNM8aSoCxIePVkCX+5tuGvpA==} - - extendable-media-recorder-wav-encoder-worker@8.0.121: - resolution: {integrity: sha512-UBBgWkyE9fpCLDdrWdTZM56FkImAljpUuxr6+y9W6LHvY7XWhkZP+yO5uZUUquS5IpsBlY2uKOWpKwiLdo3FOg==} - - extendable-media-recorder-wav-encoder@7.0.136: - resolution: {integrity: sha512-K4ZcMSbsTlI7gv92K+UY+czvk37PIPSWLqp5NF3pNDF9S6iffCbNJnl+k1zce02P6tmOAf+ZlzVRRjxSXNEoog==} - - extendable-media-recorder@6.6.10: - resolution: {integrity: sha512-gnSmLqDFq40ZdbGfuarnMLNqYPLCPpPr0p21V+g67wG4Pv2oCc/ga8sfsZrEM5GywEi7FcpyRm3z99JWZ/0aPw==} - extract-zip@2.0.1: resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} engines: {node: '>= 10.17.0'} @@ -5879,9 +5351,6 @@ packages: fast-deep-equal@2.0.1: resolution: {integrity: sha512-bCK/2Z4zLidyB4ReuIsvALH6w31YfAQDmXMqMx6FyfHqvBxtjC0eRumeSu4Bs3XtXwpyIywtSTrVT99BxY1f9w==} - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - fast-equals@5.4.0: resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} engines: {node: '>=6.0.0'} @@ -5893,20 +5362,6 @@ packages: resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-unique-numbers@7.0.2: - resolution: {integrity: sha512-xnqpsnu889bHbq5cbDMwCJ2BPf6kjFPMu+RHfqKvisRxeEbTOVxY5aW/ZNsZ/r8OlwatxmjdFEVQog2xAhLkvg==} - engines: {node: '>=14.15.4'} - - fast-unique-numbers@9.0.26: - resolution: {integrity: sha512-3Mtq8p1zQinjGyWfKeuBunbuFoixG72AUkk4VvzbX4ykCW9Q4FzRaNyIlfQhUjnKw2ARVP+/CKnoyr6wfHftig==} - engines: {node: '>=18.2.0'} - - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-xml-parser@5.3.4: resolution: {integrity: sha512-EFd6afGmXlCx8H8WTZHhAoDaWaGyuIBoZJ2mknrNxug+aZKjkp0a0dlars9Izl+jF+7Gu1/5f/2h68cQpe0IiA==} hasBin: true @@ -6021,9 +5476,6 @@ packages: resolution: {integrity: sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==} engines: {node: '>=10.13.0'} - fs-monkey@1.0.3: - resolution: {integrity: sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==} - fs-monkey@1.1.0: resolution: {integrity: sha512-QMUezzXWII9EV5aTFXW1UBVUO77wYPpjqIF8/AviUCThNeSYZykpoTixUeaNNBwmCev0AMDWMAni+f8Hxb1IFw==} @@ -6188,9 +5640,6 @@ packages: resolution: {integrity: sha512-fqZVj22LtFJkHODT+M4N1RJQ3TjnnQhfE9GwZI8qXscYarnhpip70poMldRnP8ipQ/w0B621kOhfc53/J9bd/A==} engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me @@ -6421,9 +5870,6 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - httpx@2.3.3: - resolution: {integrity: sha512-k1qv94u1b6e+XKCxVbLgYlOypVP9MPGpnN5G/vxFf6tDO4V3xpz3d6FUOY/s8NtPgaq5RBVVgSB+7IHpVxMYzw==} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -6454,12 +5900,6 @@ packages: resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} engines: {node: '>=0.10.0'} - icss-utils@5.1.0: - resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - icu-minify@4.8.2: resolution: {integrity: sha512-LHBQV+skKkjZSPd590pZ7ZAHftUgda3eFjeuNwA8/15L8T8loCNBktKQyTlkodAU86KovFXeg/9WntlAo5wA5A==} @@ -6486,9 +5926,6 @@ packages: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - indefinite-article@0.0.2: - resolution: {integrity: sha512-Au/2XzRkvxq2J6w5uvSSbBKPZ5kzINx5F2wb0SF8xpRL8BP9Lav81TnRbfPp6p+SYjYxwaaLn4EUwI3/MmYKSw==} - indent-string@2.1.0: resolution: {integrity: sha512-aqwDFWSgSgfRaEwao5lg5KEcVd/2a+D1rvoG7NdilmYz0NwRk6StWpWdz/Hpk34MKPpx7s8XxUqimfcQK6gGlg==} engines: {node: '>=0.10.0'} @@ -6543,11 +5980,6 @@ packages: is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - is-docker@2.2.1: - resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} - engines: {node: '>=8'} - hasBin: true - is-extendable@0.1.1: resolution: {integrity: sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==} engines: {node: '>=0.10.0'} @@ -6619,10 +6051,6 @@ packages: resolution: {integrity: sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==} engines: {node: '>=0.10.0'} - is-wsl@2.2.0: - resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} - engines: {node: '>=8'} - isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -6651,10 +6079,6 @@ packages: resolution: {integrity: sha512-GPBXyfcZSGujjddPeA+V34bW70ZJT7jzCEbloVasSH4yjiqWqXHX8iZQtZdVbOhc5esSeAIuiSmMutRZQB/olg==} engines: {node: 20 || >=22} - jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -6708,12 +6132,6 @@ packages: json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - json-schema-walker@2.0.0: resolution: {integrity: sha512-nXN2cMky0Iw7Af28w061hmxaPDaML5/bQD9nwm1lOoIKEGjHcRGxqWe4MfrkYThYAPjSUhmsp4bJNoLAyVn9Xw==} engines: {node: '>=10'} @@ -6725,11 +6143,6 @@ packages: resolution: {integrity: sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==} engines: {node: '>= 0.4'} - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} @@ -6758,13 +6171,6 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - kitx@1.3.0: - resolution: {integrity: sha512-fhBqFlXd0GkKTB+8ayLfpzPUw+LHxZlPAukPNBD1Om7JMeInT+/PxCAf1yLagvD+VKoyWhXtJR68xQkX/a0wOQ==} - - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - knip@5.83.0: resolution: {integrity: sha512-FfmaHMntpZB13B1oJQMSs1hTOZxd0TOn+FYB3oWEI02XlxTW3RH4H7d8z5Us3g0ziHCYyl7z0B1xi8ENP3QEKA==} engines: {node: '>=18.18.0'} @@ -6830,24 +6236,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -6890,14 +6300,6 @@ packages: resolution: {integrity: sha512-cy7ZdNRXdablkXYNI049pthVeXFurRyb9+hA/dZzerZ0pGTx42z+y+ssxBaVV2l70t1muq5IdKhn4UtcoGUY9A==} engines: {node: '>=0.10.0'} - loader-runner@4.3.1: - resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} - engines: {node: '>=6.11.5'} - - loader-utils@2.0.4: - resolution: {integrity: sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==} - engines: {node: '>=8.9.0'} - locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -6908,9 +6310,6 @@ packages: lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - lodash.template@4.5.0: resolution: {integrity: sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==} deprecated: This package is deprecated. Use https://socket.dev/npm/package/eta instead. @@ -6949,10 +6348,6 @@ packages: resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==} engines: {node: 20 || >=22} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} engines: {node: '>=12'} @@ -6961,11 +6356,6 @@ packages: resolution: {integrity: sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==} engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'} - lucide-react@0.469.0: - resolution: {integrity: sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - lucide-react@0.542.0: resolution: {integrity: sha512-w3hD8/SQB7+lzU2r4VdFyzzOzKnUjTZIF/MQJGSSvni7Llewni4vuViRppfRAa2guOsY5k4jZyxw/i9DQHv+dw==} peerDependencies: @@ -7100,25 +6490,9 @@ packages: resolution: {integrity: sha512-i+oUkB4ntcYVYnjiuktpYP77m/ISDg7z1B2pL+alDNFPgRkXlkYaW6zY03103/88A06E3Pn6x/DL9qB8pT9xWA==} hasBin: true - media-encoder-host-broker@7.1.0: - resolution: {integrity: sha512-Emu3f45Wbf6AoRJxfvZ8e5nh8fRVviBfkABgYNvVUsVBgJ7+l137gn324g/JmNVQhhVQ89fjmGT1kHIJ9JG5Nw==} - - media-encoder-host-worker@9.2.0: - resolution: {integrity: sha512-LrJJgNBDZH2y1PYBLaiYQw9uFU5i3yPvDkDxdko+L3Z4qzhKq9+4eYxKDqlwO4EdOlaiggvMpkgZl3roOniz2A==} - - media-encoder-host@8.1.0: - resolution: {integrity: sha512-VwX3ex48ltl+K1ObGEq3IcZp/XqpNTWemd9brC9ovo89rYmCRKTZAp1FCyfAY86RdvSMrUs26lbo45DIDVyERg==} - - mediabunny@1.34.2: - resolution: {integrity: sha512-Mr9VhiqH2RRwc3vR6rk8ca/58HhstP+c25PjtZmZvmCw21ibWSNqpinvBREfJmY+hpNGnG9dUmbJ4WqLMDWO0g==} - memfs-browser@3.5.10302: resolution: {integrity: sha512-JJTc/nh3ig05O0gBBGZjTCPOyydaTxNF0uHYBrcc1gHNnO+KIHIvo0Y1FKCJsaei6FCl8C6xfQomXqu+cuzkIw==} - memfs@3.4.3: - resolution: {integrity: sha512-eivjfi7Ahr6eQTn44nvTnR60e4a1Fs1Via2kCR5lHo/kyNoiMWaXCNJ/GpSd0ilXas2JSOl9B5FTIhflXu0hlg==} - engines: {node: '>= 4.0.0'} - memfs@3.5.3: resolution: {integrity: sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==} engines: {node: '>= 4.0.0'} @@ -7272,9 +6646,6 @@ packages: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.6: - resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -7319,10 +6690,6 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - multi-buffer-data-view@3.0.24: - resolution: {integrity: sha512-jm7Ycplx37ExXyQmqhwl7zfQmAj81y5LLzVx0XyWea4omP9W/xJhLEHs/5b+WojGyYSRt8BHiXZVcYzu68Ma0Q==} - engines: {node: '>=12.20.1'} - mustache@2.2.1: resolution: {integrity: sha512-azYRexmi9y6h2lk2JqfBLh1htlDMjKYyEYOkxoGKa0FRdr5aY4f5q8bH4JIecM181DtUEYLSz8PcRO46mgzMNQ==} engines: {npm: '>=1.4.0'} @@ -7354,9 +6721,6 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - netmask@2.0.2: resolution: {integrity: sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==} engines: {node: '>= 0.4.0'} @@ -7521,10 +6885,6 @@ packages: oniguruma-to-es@4.3.4: resolution: {integrity: sha512-3VhUGN3w2eYxnTzHn+ikMI+fp/96KoRSVK9/kMTcFqj1NRDh2IhQCKvYxDnWePKRXY/AqH+Fuiyb7VHSzBjHfA==} - open@8.4.2: - resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} - engines: {node: '>=12'} - openai@6.19.0: resolution: {integrity: sha512-5uGrF82Ql7TKgIWUnuxh+OyzYbPRPwYDSgGc05JowbXRFsOkuj0dJuCdPCTBZT4mcmp2NEvj/URwDzW+lYgmVw==} hasBin: true @@ -7767,30 +7127,6 @@ packages: po-parser@2.1.1: resolution: {integrity: sha512-ECF4zHLbUItpUgE3OTtLKlPjeBN+fKEczj2zYjDfCGOzicNs0GK3Vg2IoAYwx7LH/XYw43fZQP6xnZ4TkNxSLQ==} - postcss-modules-extract-imports@3.1.0: - resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - - postcss-modules-local-by-default@4.2.0: - resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - - postcss-modules-scope@3.2.1: - resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - - postcss-modules-values@4.0.0: - resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} - engines: {node: ^10 || ^12 || >= 14} - peerDependencies: - postcss: ^8.1.0 - postcss-selector-parser@7.1.1: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} @@ -7872,10 +7208,6 @@ packages: resolution: {integrity: sha512-3npG2NGhTc8BWBolLLf8l/92OxMGaRLbqvIh9wjCHhDXNvk4zsxaTaCpiCunW09qWPrN2zeNSNwRLVBrQQtutA==} engines: {node: 10.* || >= 12.*} - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} @@ -8068,9 +7400,6 @@ packages: '@types/react': 19.1.3 react: '>=18' - react-media-recorder@1.7.2: - resolution: {integrity: sha512-qNn9VUe/bScN3IXWGbSgULbCnYvfamj8RDzjWa5jAtA8M8l9tKg3GujcCgwx2rLCq4rLw+k048LK8i3oPDx4hQ==} - react-medium-image-zoom@5.4.0: resolution: {integrity: sha512-BsE+EnFVQzFIlyuuQrZ9iTwyKpKkqdFZV1ImEQN573QPqGrIUuNni7aF+sZwDcxlsuOMayCr6oO/PZR/yJnbRg==} peerDependencies: @@ -8085,10 +7414,6 @@ packages: peerDependencies: react: '*' - react-refresh@0.9.0: - resolution: {integrity: sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==} - engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -8163,10 +7488,6 @@ packages: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} - recast@0.23.11: - resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} - engines: {node: '>= 4'} - recharts-scale@0.4.5: resolution: {integrity: sha512-kivNFO+0OcUNu7jQquLXAxz1FIwZj8nrj+YkOKc5694NbjCvcT6aSZiIzNzd2Kul4o4rTto8QVR9lMNtxD4G1w==} @@ -8191,12 +7512,6 @@ packages: recma-stringify@1.0.0: resolution: {integrity: sha512-cjwII1MdIIVloKvC9ErQ+OgAtwHBmcZ0Bg4ciz78FtbT8In39aAYbaA7zvxQ61xVMSPE8WxhLwLbhif4Js2C+g==} - recorder-audio-worklet-processor@4.2.21: - resolution: {integrity: sha512-oiiS2sp6eMxkvjt13yetSYUJvnAxBZk60mIxz0Vf/2lDWa/4svCyMLHIDzYKbHahkISd0UYyqLS9dI7xDlUOCA==} - - recorder-audio-worklet@5.1.39: - resolution: {integrity: sha512-w/RazoBwZnkFnEPRsJYNThOHznLQC98/IzWRrutpJQVvCcL0nbLsVSLDaRrnrqVpRUI11VgiXRh30HaHiSdVhQ==} - redent@1.0.0: resolution: {integrity: sha512-qtW5hKzGQZqKoh6JNSD+4lfitfPKGz42e6QwiRmPM5mmKtR0N41AbJRYu0xJi7nhOJ4WDgRkKvAk6tw4WIwR4g==} engines: {node: '>=0.10.0'} @@ -8301,12 +7616,6 @@ packages: remeda@2.33.4: resolution: {integrity: sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==} - remotion@4.0.423: - resolution: {integrity: sha512-3PM8Iui+7kCsFHIx/GeSQTbI1WH6NQmdjerEHHM9UyE2GdbRUR+gQYQpSqPyXgyxXwRF+tTCpUSMrNOdWxfBfg==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - remove-trailing-separator@1.1.0: resolution: {integrity: sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==} @@ -8386,9 +7695,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs-interop@2.0.0: - resolution: {integrity: sha512-ASEq9atUw7lualXB+knvgtvwkCEvGWV2gDD/8qnASzBkzEARZck9JAyxmY8OS6Nc1pCPEgDTKNcx+YqqYfzArw==} - rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} @@ -8401,10 +7707,6 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sax@1.4.4: - resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} - engines: {node: '>=11.0.0'} - saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} @@ -8412,14 +7714,6 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - schema-utils@3.3.0: - resolution: {integrity: sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==} - engines: {node: '>= 10.13.0'} - - schema-utils@4.3.3: - resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} - engines: {node: '>= 10.13.0'} - scroll-into-view-if-needed@3.1.0: resolution: {integrity: sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==} @@ -8434,11 +7728,6 @@ packages: resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} hasBin: true - semver@7.5.3: - resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==} - engines: {node: '>=10'} - hasBin: true - semver@7.7.4: resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} engines: {node: '>=10'} @@ -8508,9 +7797,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - slugify@1.6.6: resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==} engines: {node: '>=8.0.0'} @@ -8552,19 +7838,10 @@ packages: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} - source-map@0.7.3: - resolution: {integrity: sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==} - engines: {node: '>= 8'} - source-map@0.7.6: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - deprecated: The work that was done in this beta branch won't be included in future versions - space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -8597,9 +7874,6 @@ packages: resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==} engines: {node: '>= 0.6'} - standardized-audio-context@25.3.77: - resolution: {integrity: sha512-Ki9zNz6pKcC5Pi+QPjPyVsD9GwJIJWgryji0XL9cAJXMGyn+dPOf6Qik1AHei0+UNVcc4BOCa0hWLBzlwqsW/A==} - start-server-and-test@2.1.3: resolution: {integrity: sha512-k4EcbNjeg0odaDkAMlIeDVDByqX9PIgL4tivgP2tES6Zd8o+4pTq/HgbWCyA3VHIoZopB+wGnNPKYGGSByNriQ==} engines: {node: '>=16'} @@ -8679,12 +7953,6 @@ packages: strnum@2.1.2: resolution: {integrity: sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ==} - style-loader@4.0.0: - resolution: {integrity: sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA==} - engines: {node: '>= 18.12.0'} - peerDependencies: - webpack: ^5.27.0 - style-to-js@1.1.21: resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} @@ -8704,17 +7972,10 @@ packages: babel-plugin-macros: optional: true - subscribable-things@2.1.57: - resolution: {integrity: sha512-Ebcu2SJUntGnfJlTKc5jIGcDbuev4Ys2bRstzl5DUyzjWTZV9ymONZ0x8kEiN8NtnDlVuFe40EB8t3XvH8SWkw==} - supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -8734,9 +7995,6 @@ packages: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} - tailwind-merge@2.6.1: - resolution: {integrity: sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==} - tailwind-merge@3.4.0: resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} @@ -8768,27 +8026,6 @@ packages: resolution: {integrity: sha512-OEHfAk4iUuDECw1phx/WxZbigLUZoSdjj+mErzs1+hRWeD2bTy79beMTep5W0Loq4rHIMRu8rXchq0n89mKchA==} engines: {node: '>=10'} - terser-webpack-plugin@5.3.16: - resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@swc/core': '*' - esbuild: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@swc/core': - optional: true - esbuild: - optional: true - uglify-js: - optional: true - - terser@5.46.0: - resolution: {integrity: sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg==} - engines: {node: '>=10'} - hasBin: true - text-decoder@1.2.3: resolution: {integrity: sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==} @@ -8851,9 +8088,6 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - tr46@6.0.0: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} @@ -9027,9 +8261,6 @@ packages: peerDependencies: browserslist: '>= 4.21.0' - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - urijs@1.19.11: resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} @@ -9166,10 +8397,6 @@ packages: resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} engines: {node: 20 || >=22} - watchpack@2.5.1: - resolution: {integrity: sha512-Zn5uXdcFNIA1+1Ei5McRd+iRzfhENPCe7LeABkJtNulSxjma+l7ltNx55BWZkRlwRnpOgHqxnjyaDgJnNXnqzg==} - engines: {node: '>=10.13.0'} - web-namespaces@2.0.1: resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} @@ -9179,27 +8406,10 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - webidl-conversions@8.0.1: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} - webpack-sources@3.3.4: - resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} - engines: {node: '>=10.13.0'} - - webpack@5.105.0: - resolution: {integrity: sha512-gX/dMkRQc7QOMzgTe6KsYFM7DxeIONQSui1s0n/0xht36HvrgbxtM1xBlgx596NbpHuQU8P7QpKwrZYwUX48nw==} - engines: {node: '>=10.13.0'} - hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true - whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} @@ -9220,9 +8430,6 @@ packages: whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} @@ -9231,12 +8438,6 @@ packages: engines: {node: '>= 8'} hasBin: true - worker-factory@6.0.76: - resolution: {integrity: sha512-W1iBNPmE9p0asU4aFmYJYCnMxhkvk4qlKc660GlHxWgmflY64NxxTbmKqipu4K5p9LiKKPjqXfcQme6153BZEQ==} - - worker-factory@7.0.48: - resolution: {integrity: sha512-CGmBy3tJvpBPjUvb0t4PrpKubUsfkI1Ohg0/GGFU2RvA9j/tiVYwKU8O7yu7gH06YtzbeJLzdUR29lmZKn5pag==} - wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -9252,18 +8453,6 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} @@ -9280,14 +8469,6 @@ packages: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} - xml2js@0.5.0: - resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} - engines: {node: '>=4.0.0'} - - xmlbuilder@11.0.1: - resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} - engines: {node: '>=4.0'} - xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} @@ -9302,9 +8483,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - yaml@2.8.2: resolution: {integrity: sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==} engines: {node: '>= 14.6'} @@ -9354,9 +8532,6 @@ packages: prisma: ^4.x.x || ^5.x.x || ^6.x.x || ^7.x.x zod: ^3.25.0 || ^4.0.0 - zod@3.22.3: - resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} - zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} @@ -9422,16 +8597,6 @@ snapshots: transitivePeerDependencies: - zod - '@alicloud/pop-core@1.8.0': - dependencies: - debug: 3.2.7 - httpx: 2.3.3 - json-bigint: 1.0.0 - kitx: 1.3.0 - xml2js: 0.5.0 - transitivePeerDependencies: - - supports-color - '@alloc/quick-lru@5.2.0': {} '@apidevtools/json-schema-ref-parser@11.9.3': @@ -9980,21 +9145,10 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.24.1': - dependencies: - '@babel/types': 7.29.0 - '@babel/runtime@7.28.6': {} - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@better-auth/core@1.4.18(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.1.3)(kysely@0.28.11)(nanostores@1.1.0)': dependencies: '@better-auth/utils': 0.3.0 @@ -10190,9 +9344,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@esbuild/aix-ppc64@0.25.0': - optional: true - '@esbuild/aix-ppc64@0.25.12': optional: true @@ -10202,9 +9353,6 @@ snapshots: '@esbuild/android-arm64@0.18.20': optional: true - '@esbuild/android-arm64@0.25.0': - optional: true - '@esbuild/android-arm64@0.25.12': optional: true @@ -10214,9 +9362,6 @@ snapshots: '@esbuild/android-arm@0.18.20': optional: true - '@esbuild/android-arm@0.25.0': - optional: true - '@esbuild/android-arm@0.25.12': optional: true @@ -10226,9 +9371,6 @@ snapshots: '@esbuild/android-x64@0.18.20': optional: true - '@esbuild/android-x64@0.25.0': - optional: true - '@esbuild/android-x64@0.25.12': optional: true @@ -10238,9 +9380,6 @@ snapshots: '@esbuild/darwin-arm64@0.18.20': optional: true - '@esbuild/darwin-arm64@0.25.0': - optional: true - '@esbuild/darwin-arm64@0.25.12': optional: true @@ -10250,9 +9389,6 @@ snapshots: '@esbuild/darwin-x64@0.18.20': optional: true - '@esbuild/darwin-x64@0.25.0': - optional: true - '@esbuild/darwin-x64@0.25.12': optional: true @@ -10262,9 +9398,6 @@ snapshots: '@esbuild/freebsd-arm64@0.18.20': optional: true - '@esbuild/freebsd-arm64@0.25.0': - optional: true - '@esbuild/freebsd-arm64@0.25.12': optional: true @@ -10274,9 +9407,6 @@ snapshots: '@esbuild/freebsd-x64@0.18.20': optional: true - '@esbuild/freebsd-x64@0.25.0': - optional: true - '@esbuild/freebsd-x64@0.25.12': optional: true @@ -10286,9 +9416,6 @@ snapshots: '@esbuild/linux-arm64@0.18.20': optional: true - '@esbuild/linux-arm64@0.25.0': - optional: true - '@esbuild/linux-arm64@0.25.12': optional: true @@ -10298,9 +9425,6 @@ snapshots: '@esbuild/linux-arm@0.18.20': optional: true - '@esbuild/linux-arm@0.25.0': - optional: true - '@esbuild/linux-arm@0.25.12': optional: true @@ -10310,9 +9434,6 @@ snapshots: '@esbuild/linux-ia32@0.18.20': optional: true - '@esbuild/linux-ia32@0.25.0': - optional: true - '@esbuild/linux-ia32@0.25.12': optional: true @@ -10322,9 +9443,6 @@ snapshots: '@esbuild/linux-loong64@0.18.20': optional: true - '@esbuild/linux-loong64@0.25.0': - optional: true - '@esbuild/linux-loong64@0.25.12': optional: true @@ -10334,9 +9452,6 @@ snapshots: '@esbuild/linux-mips64el@0.18.20': optional: true - '@esbuild/linux-mips64el@0.25.0': - optional: true - '@esbuild/linux-mips64el@0.25.12': optional: true @@ -10346,9 +9461,6 @@ snapshots: '@esbuild/linux-ppc64@0.18.20': optional: true - '@esbuild/linux-ppc64@0.25.0': - optional: true - '@esbuild/linux-ppc64@0.25.12': optional: true @@ -10358,9 +9470,6 @@ snapshots: '@esbuild/linux-riscv64@0.18.20': optional: true - '@esbuild/linux-riscv64@0.25.0': - optional: true - '@esbuild/linux-riscv64@0.25.12': optional: true @@ -10370,9 +9479,6 @@ snapshots: '@esbuild/linux-s390x@0.18.20': optional: true - '@esbuild/linux-s390x@0.25.0': - optional: true - '@esbuild/linux-s390x@0.25.12': optional: true @@ -10382,18 +9488,12 @@ snapshots: '@esbuild/linux-x64@0.18.20': optional: true - '@esbuild/linux-x64@0.25.0': - optional: true - '@esbuild/linux-x64@0.25.12': optional: true '@esbuild/linux-x64@0.27.3': optional: true - '@esbuild/netbsd-arm64@0.25.0': - optional: true - '@esbuild/netbsd-arm64@0.25.12': optional: true @@ -10403,18 +9503,12 @@ snapshots: '@esbuild/netbsd-x64@0.18.20': optional: true - '@esbuild/netbsd-x64@0.25.0': - optional: true - '@esbuild/netbsd-x64@0.25.12': optional: true '@esbuild/netbsd-x64@0.27.3': optional: true - '@esbuild/openbsd-arm64@0.25.0': - optional: true - '@esbuild/openbsd-arm64@0.25.12': optional: true @@ -10424,9 +9518,6 @@ snapshots: '@esbuild/openbsd-x64@0.18.20': optional: true - '@esbuild/openbsd-x64@0.25.0': - optional: true - '@esbuild/openbsd-x64@0.25.12': optional: true @@ -10442,9 +9533,6 @@ snapshots: '@esbuild/sunos-x64@0.18.20': optional: true - '@esbuild/sunos-x64@0.25.0': - optional: true - '@esbuild/sunos-x64@0.25.12': optional: true @@ -10454,9 +9542,6 @@ snapshots: '@esbuild/win32-arm64@0.18.20': optional: true - '@esbuild/win32-arm64@0.25.0': - optional: true - '@esbuild/win32-arm64@0.25.12': optional: true @@ -10466,9 +9551,6 @@ snapshots: '@esbuild/win32-ia32@0.18.20': optional: true - '@esbuild/win32-ia32@0.25.0': - optional: true - '@esbuild/win32-ia32@0.25.12': optional: true @@ -10478,9 +9560,6 @@ snapshots: '@esbuild/win32-x64@0.18.20': optional: true - '@esbuild/win32-x64@0.25.0': - optional: true - '@esbuild/win32-x64@0.25.12': optional: true @@ -10795,11 +9874,6 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/source-map@0.3.11': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -10879,10 +9953,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@mediabunny/ac3@1.34.2(mediabunny@1.34.2)': - dependencies: - mediabunny: 1.34.2 - '@mrleebo/prisma-ast@0.13.1': dependencies: chevrotain: 10.5.0 @@ -12151,196 +11221,6 @@ snapshots: '@remirror/core-constants@3.0.0': {} - '@remotion/bundler@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@remotion/media-parser': 4.0.423 - '@remotion/studio': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/studio-shared': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - css-loader: 5.2.7(webpack@5.105.0(esbuild@0.25.0)) - esbuild: 0.25.0 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - react-refresh: 0.9.0 - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - source-map: 0.7.3 - style-loader: 4.0.0(webpack@5.105.0(esbuild@0.25.0)) - webpack: 5.105.0(esbuild@0.25.0) - transitivePeerDependencies: - - '@swc/core' - - bufferutil - - supports-color - - uglify-js - - utf-8-validate - - webpack-cli - - '@remotion/cli@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@remotion/bundler': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/media-utils': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/player': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/renderer': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/studio': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/studio-server': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/studio-shared': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - dotenv: 9.0.2 - minimist: 1.2.6 - prompts: 2.4.2 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - transitivePeerDependencies: - - '@swc/core' - - bufferutil - - supports-color - - uglify-js - - utf-8-validate - - webpack-cli - - '@remotion/compositor-darwin-arm64@4.0.423': - optional: true - - '@remotion/compositor-darwin-x64@4.0.423': - optional: true - - '@remotion/compositor-linux-arm64-gnu@4.0.423': - optional: true - - '@remotion/compositor-linux-arm64-musl@4.0.423': - optional: true - - '@remotion/compositor-linux-x64-gnu@4.0.423': - optional: true - - '@remotion/compositor-linux-x64-musl@4.0.423': - optional: true - - '@remotion/compositor-win32-x64-msvc@4.0.423': - optional: true - - '@remotion/google-fonts@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - transitivePeerDependencies: - - react - - react-dom - - '@remotion/licensing@4.0.423': {} - - '@remotion/media-parser@4.0.423': {} - - '@remotion/media-utils@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@remotion/media-parser': 4.0.423 - '@remotion/webcodecs': 4.0.423 - mediabunny: 1.34.2 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - - '@remotion/player@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - - '@remotion/renderer@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@remotion/licensing': 4.0.423 - '@remotion/streaming': 4.0.423 - execa: 5.1.1 - extract-zip: 2.0.1 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - source-map: 0.8.0-beta.0 - ws: 8.17.1 - optionalDependencies: - '@remotion/compositor-darwin-arm64': 4.0.423 - '@remotion/compositor-darwin-x64': 4.0.423 - '@remotion/compositor-linux-arm64-gnu': 4.0.423 - '@remotion/compositor-linux-arm64-musl': 4.0.423 - '@remotion/compositor-linux-x64-gnu': 4.0.423 - '@remotion/compositor-linux-x64-musl': 4.0.423 - '@remotion/compositor-win32-x64-msvc': 4.0.423 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@remotion/streaming@4.0.423': {} - - '@remotion/studio-server@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@babel/parser': 7.24.1 - '@remotion/bundler': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/renderer': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/studio-shared': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - memfs: 3.4.3 - open: 8.4.2 - recast: 0.23.11 - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - semver: 7.5.3 - source-map: 0.7.3 - transitivePeerDependencies: - - '@swc/core' - - bufferutil - - react - - react-dom - - supports-color - - uglify-js - - utf-8-validate - - webpack-cli - - '@remotion/studio-shared@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - transitivePeerDependencies: - - react - - react-dom - - '@remotion/studio@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@remotion/media-utils': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/player': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/renderer': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/studio-shared': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/web-renderer': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - '@remotion/zod-types': 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@3.22.3) - mediabunny: 1.34.2 - memfs: 3.4.3 - open: 8.4.2 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - semver: 7.5.3 - source-map: 0.7.3 - zod: 3.22.3 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - '@remotion/web-renderer@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': - dependencies: - '@mediabunny/ac3': 1.34.2(mediabunny@1.34.2) - '@remotion/licensing': 4.0.423 - mediabunny: 1.34.2 - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - - '@remotion/webcodecs@4.0.423': - dependencies: - '@remotion/media-parser': 4.0.423 - - '@remotion/zod-types@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(zod@3.22.3)': - dependencies: - remotion: 4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - zod: 3.22.3 - transitivePeerDependencies: - - react - - react-dom - '@scalar/core@0.3.37': dependencies: '@scalar/types': 0.6.2 @@ -13130,26 +12010,10 @@ snapshots: dependencies: '@types/ms': 2.1.0 - '@types/dom-mediacapture-transform@0.1.11': - dependencies: - '@types/dom-webcodecs': 0.1.13 - - '@types/dom-webcodecs@0.1.13': {} - '@types/dompurify@3.2.0': dependencies: dompurify: 3.3.1 - '@types/eslint-scope@3.7.7': - dependencies: - '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 - - '@types/eslint@9.6.1': - dependencies: - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@types/estree-jsx@1.0.5': dependencies: '@types/estree': 1.0.8 @@ -13206,10 +12070,6 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@20.19.33': - dependencies: - undici-types: 6.21.0 - '@types/node@22.15.14': dependencies: undici-types: 6.21.0 @@ -13296,98 +12156,14 @@ snapshots: react: 19.2.4 react-dom: 19.2.4(react@19.2.4) rehype: 13.0.2 - rehype-prism-plus: 2.0.1 - transitivePeerDependencies: - - '@types/react' - - supports-color - - '@ungap/structured-clone@1.3.0': {} - - '@vercel/oidc@3.1.0': {} - - '@webassemblyjs/ast@1.14.1': - dependencies: - '@webassemblyjs/helper-numbers': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - - '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - - '@webassemblyjs/helper-api-error@1.13.2': {} - - '@webassemblyjs/helper-buffer@1.14.1': {} - - '@webassemblyjs/helper-numbers@1.13.2': - dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - - '@webassemblyjs/helper-wasm-section@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 - - '@webassemblyjs/ieee754@1.13.2': - dependencies: - '@xtuc/ieee754': 1.2.0 - - '@webassemblyjs/leb128@1.13.2': - dependencies: - '@xtuc/long': 4.2.2 - - '@webassemblyjs/utf8@1.13.2': {} - - '@webassemblyjs/wasm-edit@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 - - '@webassemblyjs/wasm-gen@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wasm-opt@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - - '@webassemblyjs/wasm-parser@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wast-printer@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 - - '@xtuc/ieee754@1.2.0': {} + rehype-prism-plus: 2.0.1 + transitivePeerDependencies: + - '@types/react' + - supports-color - '@xtuc/long@4.2.2': {} + '@ungap/structured-clone@1.3.0': {} - acorn-import-phases@1.0.4(acorn@8.15.0): - dependencies: - acorn: 8.15.0 + '@vercel/oidc@3.1.0': {} acorn-jsx@5.3.2(acorn@8.15.0): dependencies: @@ -13415,33 +12191,6 @@ snapshots: '@opentelemetry/api': 1.9.0 zod: 4.3.6 - ajv-formats@2.1.1(ajv@8.18.0): - optionalDependencies: - ajv: 8.18.0 - - ajv-keywords@3.5.2(ajv@6.12.6): - dependencies: - ajv: 6.12.6 - - ajv-keywords@5.1.0(ajv@8.18.0): - dependencies: - ajv: 8.18.0 - fast-deep-equal: 3.1.3 - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@8.18.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - ansi-red@0.1.1: dependencies: ansi-wrap: 0.1.0 @@ -13483,10 +12232,6 @@ snapshots: dependencies: tslib: 2.8.1 - ast-types@0.16.1: - dependencies: - tslib: 2.8.1 - astring@1.9.0: {} asynckit@0.4.0: {} @@ -13502,11 +12247,6 @@ snapshots: dependencies: gulp-header: 1.8.12 - automation-events@7.1.15: - dependencies: - '@babel/runtime': 7.28.6 - tslib: 2.8.1 - autoprefixer@10.4.21(postcss@8.5.3): dependencies: browserslist: 4.28.1 @@ -13617,8 +12357,6 @@ snapshots: dependencies: require-from-string: 2.0.2 - big.js@5.2.2: {} - bignumber.js@9.3.1: {} bl@5.1.0: @@ -13672,13 +12410,6 @@ snapshots: transitivePeerDependencies: - supports-color - broker-factory@3.1.13: - dependencies: - '@babel/runtime': 7.28.6 - fast-unique-numbers: 9.0.26 - tslib: 2.8.1 - worker-factory: 7.0.48 - browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.19 @@ -13796,8 +12527,6 @@ snapshots: dependencies: readdirp: 4.1.2 - chrome-trace-event@1.0.4: {} - chromium-bidi@14.0.0(devtools-protocol@0.0.1566079): dependencies: devtools-protocol: 0.0.1566079 @@ -13866,17 +12595,8 @@ snapshots: commander@12.1.0: {} - commander@2.20.3: {} - commander@8.3.0: {} - compilerr@10.0.2: - dependencies: - '@babel/runtime': 7.28.6 - dashify: 2.0.0 - indefinite-article: 0.0.2 - tslib: 2.8.1 - compute-scroll-into-view@3.1.1: {} concat-map@0.0.1: {} @@ -13927,20 +12647,6 @@ snapshots: dependencies: utrie: 1.0.2 - css-loader@5.2.7(webpack@5.105.0(esbuild@0.25.0)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.3) - loader-utils: 2.0.4 - postcss: 8.5.3 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.3) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.3) - postcss-modules-scope: 3.2.1(postcss@8.5.3) - postcss-modules-values: 4.0.0(postcss@8.5.3) - postcss-value-parser: 4.2.0 - schema-utils: 3.3.0 - semver: 7.7.4 - webpack: 5.105.0(esbuild@0.25.0) - css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -14011,8 +12717,6 @@ snapshots: d3-timer@3.0.1: {} - dashify@2.0.0: {} - data-uri-to-buffer@6.0.2: {} data-urls@6.0.1: @@ -14028,10 +12732,6 @@ snapshots: dependencies: ms: 2.0.0 - debug@3.2.7: - dependencies: - ms: 2.1.3 - debug@4.4.3: dependencies: ms: 2.1.3 @@ -14056,8 +12756,6 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - define-lazy-prop@2.0.0: {} - defu@6.1.4: {} degenerator@5.0.1: @@ -14132,8 +12830,6 @@ snapshots: dotenv@16.6.1: {} - dotenv@9.0.2: {} - drizzle-kit@0.31.8: dependencies: '@drizzle-team/brocli': 0.10.2 @@ -14176,8 +12872,6 @@ snapshots: emoji-regex@9.2.2: {} - emojis-list@3.0.0: {} - empathic@2.0.0: {} encoding-sniffer@0.2.1: @@ -14214,8 +12908,6 @@ snapshots: es-errors@1.3.0: {} - es-module-lexer@2.0.0: {} - es-object-atoms@1.1.1: dependencies: es-errors: 1.3.0 @@ -14273,34 +12965,6 @@ snapshots: '@esbuild/win32-ia32': 0.18.20 '@esbuild/win32-x64': 0.18.20 - esbuild@0.25.0: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.0 - '@esbuild/android-arm': 0.25.0 - '@esbuild/android-arm64': 0.25.0 - '@esbuild/android-x64': 0.25.0 - '@esbuild/darwin-arm64': 0.25.0 - '@esbuild/darwin-x64': 0.25.0 - '@esbuild/freebsd-arm64': 0.25.0 - '@esbuild/freebsd-x64': 0.25.0 - '@esbuild/linux-arm': 0.25.0 - '@esbuild/linux-arm64': 0.25.0 - '@esbuild/linux-ia32': 0.25.0 - '@esbuild/linux-loong64': 0.25.0 - '@esbuild/linux-mips64el': 0.25.0 - '@esbuild/linux-ppc64': 0.25.0 - '@esbuild/linux-riscv64': 0.25.0 - '@esbuild/linux-s390x': 0.25.0 - '@esbuild/linux-x64': 0.25.0 - '@esbuild/netbsd-arm64': 0.25.0 - '@esbuild/netbsd-x64': 0.25.0 - '@esbuild/openbsd-arm64': 0.25.0 - '@esbuild/openbsd-x64': 0.25.0 - '@esbuild/sunos-x64': 0.25.0 - '@esbuild/win32-arm64': 0.25.0 - '@esbuild/win32-ia32': 0.25.0 - '@esbuild/win32-x64': 0.25.0 - esbuild@0.25.12: optionalDependencies: '@esbuild/aix-ppc64': 0.25.12 @@ -14373,19 +13037,8 @@ snapshots: optionalDependencies: source-map: 0.6.1 - eslint-scope@5.1.1: - dependencies: - esrecurse: 4.3.0 - estraverse: 4.3.0 - esprima@4.0.1: {} - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@4.3.0: {} - estraverse@5.3.0: {} estree-util-attach-comments@3.0.0: @@ -14445,8 +13098,6 @@ snapshots: transitivePeerDependencies: - bare-abort-controller - events@3.3.0: {} - eventsource-parser@3.0.6: {} execa@5.1.1: @@ -14473,36 +13124,6 @@ snapshots: extend@3.0.2: {} - extendable-media-recorder-wav-encoder-broker@7.0.125: - dependencies: - '@babel/runtime': 7.28.6 - broker-factory: 3.1.13 - extendable-media-recorder-wav-encoder-worker: 8.0.121 - tslib: 2.8.1 - - extendable-media-recorder-wav-encoder-worker@8.0.121: - dependencies: - '@babel/runtime': 7.28.6 - tslib: 2.8.1 - worker-factory: 7.0.48 - - extendable-media-recorder-wav-encoder@7.0.136: - dependencies: - '@babel/runtime': 7.28.6 - extendable-media-recorder-wav-encoder-broker: 7.0.125 - extendable-media-recorder-wav-encoder-worker: 8.0.121 - tslib: 2.8.1 - - extendable-media-recorder@6.6.10: - dependencies: - '@babel/runtime': 7.28.6 - media-encoder-host: 8.1.0 - multi-buffer-data-view: 3.0.24 - recorder-audio-worklet: 5.1.39 - standardized-audio-context: 25.3.77 - subscribable-things: 2.1.57 - tslib: 2.8.1 - extract-zip@2.0.1: dependencies: debug: 4.4.3 @@ -14519,8 +13140,6 @@ snapshots: fast-deep-equal@2.0.1: {} - fast-deep-equal@3.1.3: {} - fast-equals@5.4.0: {} fast-fifo@1.3.2: {} @@ -14533,20 +13152,6 @@ snapshots: merge2: 1.4.1 micromatch: 4.0.8 - fast-json-stable-stringify@2.1.0: {} - - fast-unique-numbers@7.0.2: - dependencies: - '@babel/runtime': 7.28.6 - tslib: 2.8.1 - - fast-unique-numbers@9.0.26: - dependencies: - '@babel/runtime': 7.28.6 - tslib: 2.8.1 - - fast-uri@3.1.0: {} - fast-xml-parser@5.3.4: dependencies: strnum: 2.1.2 @@ -14673,8 +13278,6 @@ snapshots: - bare-abort-controller - react-native-b4a - fs-monkey@1.0.3: {} - fs-monkey@1.1.0: optional: true @@ -14853,8 +13456,6 @@ snapshots: - bare-abort-controller - react-native-b4a - glob-to-regexp@0.4.1: {} - glob@10.5.0: dependencies: foreground-child: 3.3.1 @@ -15209,13 +13810,6 @@ snapshots: transitivePeerDependencies: - supports-color - httpx@2.3.3: - dependencies: - '@types/node': 20.19.33 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - human-signals@2.1.0: {} husky@9.1.7: {} @@ -15258,10 +13852,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - icss-utils@5.1.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - icu-minify@4.8.2: dependencies: '@formatjs/icu-messageformat-parser': 3.5.1 @@ -15285,8 +13875,6 @@ snapshots: parent-module: 1.0.1 resolve-from: 4.0.0 - indefinite-article@0.0.2: {} - indent-string@2.1.0: dependencies: repeating: 2.0.1 @@ -15335,8 +13923,6 @@ snapshots: is-decimal@2.0.1: {} - is-docker@2.2.1: {} - is-extendable@0.1.1: {} is-extendable@1.0.1: @@ -15383,10 +13969,6 @@ snapshots: is-valid-glob@1.0.0: {} - is-wsl@2.2.0: - dependencies: - is-docker: 2.2.1 - isarray@1.0.0: {} isarray@2.0.5: {} @@ -15420,12 +14002,6 @@ snapshots: dependencies: '@isaacs/cliui': 9.0.0 - jest-worker@27.5.1: - dependencies: - '@types/node': 22.15.14 - merge-stream: 2.0.0 - supports-color: 8.1.1 - jiti@2.6.1: {} joi@18.0.2: @@ -15492,10 +14068,6 @@ snapshots: json-parse-even-better-errors@2.3.1: {} - json-schema-traverse@0.4.1: {} - - json-schema-traverse@1.0.0: {} - json-schema-walker@2.0.0: dependencies: '@apidevtools/json-schema-ref-parser': 11.9.3 @@ -15511,8 +14083,6 @@ snapshots: jsonify: 0.0.1 object-keys: 1.1.1 - json5@2.2.3: {} - jsonfile@4.0.0: optionalDependencies: graceful-fs: 4.2.11 @@ -15544,10 +14114,6 @@ snapshots: kind-of@6.0.3: {} - kitx@1.3.0: {} - - kleur@3.0.3: {} - knip@5.83.0(@types/node@22.15.14)(typescript@5.9.3): dependencies: '@nodelib/fs.walk': 1.2.8 @@ -15657,14 +14223,6 @@ snapshots: pinkie-promise: 2.0.1 strip-bom: 2.0.0 - loader-runner@4.3.1: {} - - loader-utils@2.0.4: - dependencies: - big.js: 5.2.2 - emojis-list: 3.0.0 - json5: 2.2.3 - locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -15673,8 +14231,6 @@ snapshots: lodash.debounce@4.0.8: {} - lodash.sortby@4.7.0: {} - lodash.template@4.5.0: dependencies: lodash._reinterpolate: 3.0.0 @@ -15710,18 +14266,10 @@ snapshots: lru-cache@11.2.5: {} - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - lru-cache@7.18.3: {} lru.min@1.1.4: {} - lucide-react@0.469.0(react@19.2.4): - dependencies: - react: 19.2.4 - lucide-react@0.542.0(react@19.2.4): dependencies: react: 19.2.4 @@ -15998,42 +14546,11 @@ snapshots: object-assign: 4.0.1 read-input: 0.3.1 - media-encoder-host-broker@7.1.0: - dependencies: - '@babel/runtime': 7.28.6 - broker-factory: 3.1.13 - fast-unique-numbers: 9.0.26 - media-encoder-host-worker: 9.2.0 - tslib: 2.8.1 - - media-encoder-host-worker@9.2.0: - dependencies: - '@babel/runtime': 7.28.6 - extendable-media-recorder-wav-encoder-broker: 7.0.125 - tslib: 2.8.1 - worker-factory: 7.0.48 - - media-encoder-host@8.1.0: - dependencies: - '@babel/runtime': 7.28.6 - media-encoder-host-broker: 7.1.0 - media-encoder-host-worker: 9.2.0 - tslib: 2.8.1 - - mediabunny@1.34.2: - dependencies: - '@types/dom-mediacapture-transform': 0.1.11 - '@types/dom-webcodecs': 0.1.13 - memfs-browser@3.5.10302: dependencies: memfs: 3.5.3 optional: true - memfs@3.4.3: - dependencies: - fs-monkey: 1.0.3 - memfs@3.5.3: dependencies: fs-monkey: 1.1.0 @@ -16360,8 +14877,6 @@ snapshots: dependencies: brace-expansion: 2.0.2 - minimist@1.2.6: {} - minimist@1.2.8: {} minipass@7.1.2: {} @@ -16393,11 +14908,6 @@ snapshots: ms@2.1.3: {} - multi-buffer-data-view@3.0.24: - dependencies: - '@babel/runtime': 7.28.6 - tslib: 2.8.1 - mustache@2.2.1: {} mysql2@3.15.3: @@ -16424,8 +14934,6 @@ snapshots: negotiator@1.0.0: {} - neo-async@2.6.2: {} - netmask@2.0.2: {} next-intl-swc-plugin-extractor@4.8.3: {} @@ -16568,12 +15076,6 @@ snapshots: regex: 6.1.0 regex-recursion: 6.0.2 - open@8.4.2: - dependencies: - define-lazy-prop: 2.0.0 - is-docker: 2.2.1 - is-wsl: 2.2.0 - openai@6.19.0(ws@8.19.0)(zod@4.3.6): optionalDependencies: ws: 8.19.0 @@ -16832,27 +15334,6 @@ snapshots: po-parser@2.1.1: {} - postcss-modules-extract-imports@3.1.0(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - - postcss-modules-local-by-default@4.2.0(postcss@8.5.3): - dependencies: - icss-utils: 5.1.0(postcss@8.5.3) - postcss: 8.5.3 - postcss-selector-parser: 7.1.1 - postcss-value-parser: 4.2.0 - - postcss-modules-scope@3.2.1(postcss@8.5.3): - dependencies: - postcss: 8.5.3 - postcss-selector-parser: 7.1.1 - - postcss-modules-values@4.0.0(postcss@8.5.3): - dependencies: - icss-utils: 5.1.0(postcss@8.5.3) - postcss: 8.5.3 - postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 @@ -16922,11 +15403,6 @@ snapshots: promise-map-series@0.3.0: {} - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - prop-types@15.8.1: dependencies: loose-envify: 1.4.0 @@ -17227,11 +15703,6 @@ snapshots: transitivePeerDependencies: - supports-color - react-media-recorder@1.7.2: - dependencies: - extendable-media-recorder: 6.6.10 - extendable-media-recorder-wav-encoder: 7.0.136 - react-medium-image-zoom@5.4.0(react-dom@19.2.4(react@19.2.4))(react@19.2.4): dependencies: react: 19.2.4 @@ -17247,8 +15718,6 @@ snapshots: qr.js: 0.0.0 react: 19.2.4 - react-refresh@0.9.0: {} - react-remove-scroll-bar@2.3.8(@types/react@19.1.3)(react@19.2.4): dependencies: react: 19.2.4 @@ -17331,14 +15800,6 @@ snapshots: readdirp@4.1.2: {} - recast@0.23.11: - dependencies: - ast-types: 0.16.1 - esprima: 4.0.1 - source-map: 0.6.1 - tiny-invariant: 1.3.3 - tslib: 2.8.1 - recharts-scale@0.4.5: dependencies: decimal.js-light: 2.5.1 @@ -17385,22 +15846,6 @@ snapshots: unified: 11.0.5 vfile: 6.0.3 - recorder-audio-worklet-processor@4.2.21: - dependencies: - '@babel/runtime': 7.28.6 - tslib: 2.8.1 - - recorder-audio-worklet@5.1.39: - dependencies: - '@babel/runtime': 7.28.6 - broker-factory: 3.1.13 - fast-unique-numbers: 7.0.2 - recorder-audio-worklet-processor: 4.2.21 - standardized-audio-context: 25.3.77 - subscribable-things: 2.1.57 - tslib: 2.8.1 - worker-factory: 6.0.76 - redent@1.0.0: dependencies: indent-string: 2.1.0 @@ -17613,11 +16058,6 @@ snapshots: remeda@2.33.4: {} - remotion@4.0.423(react-dom@19.2.4(react@19.2.4))(react@19.2.4): - dependencies: - react: 19.2.4 - react-dom: 19.2.4(react@19.2.4) - remove-trailing-separator@1.1.0: {} repeat-element@1.1.4: {} @@ -17674,8 +16114,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rxjs-interop@2.0.0: {} - rxjs@7.8.2: dependencies: tslib: 2.8.1 @@ -17686,27 +16124,12 @@ snapshots: safer-buffer@2.1.2: {} - sax@1.4.4: {} - saxes@6.0.0: dependencies: xmlchars: 2.2.0 scheduler@0.27.0: {} - schema-utils@3.3.0: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - - schema-utils@4.3.3: - dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.18.0 - ajv-formats: 2.1.1(ajv@8.18.0) - ajv-keywords: 5.1.0(ajv@8.18.0) - scroll-into-view-if-needed@3.1.0: dependencies: compute-scroll-into-view: 3.1.1 @@ -17722,10 +16145,6 @@ snapshots: semver@5.7.2: {} - semver@7.5.3: - dependencies: - lru-cache: 6.0.0 - semver@7.7.4: {} seq-queue@0.0.5: {} @@ -17833,8 +16252,6 @@ snapshots: signal-exit@4.1.0: {} - sisteransi@1.0.5: {} - slugify@1.6.6: {} smart-buffer@4.2.0: {} @@ -17872,14 +16289,8 @@ snapshots: source-map@0.6.1: {} - source-map@0.7.3: {} - source-map@0.7.6: {} - source-map@0.8.0-beta.0: - dependencies: - whatwg-url: 7.1.0 - space-separated-tokens@2.0.2: {} spdx-correct@3.2.0: @@ -17908,12 +16319,6 @@ snapshots: sqlstring@2.3.3: {} - standardized-audio-context@25.3.77: - dependencies: - '@babel/runtime': 7.28.6 - automation-events: 7.1.15 - tslib: 2.8.1 - start-server-and-test@2.1.3: dependencies: arg: 5.0.2 @@ -18006,10 +16411,6 @@ snapshots: strnum@2.1.2: {} - style-loader@4.0.0(webpack@5.105.0(esbuild@0.25.0)): - dependencies: - webpack: 5.105.0(esbuild@0.25.0) - style-to-js@1.1.21: dependencies: style-to-object: 1.0.14 @@ -18023,20 +16424,10 @@ snapshots: client-only: 0.0.1 react: 19.2.4 - subscribable-things@2.1.57: - dependencies: - '@babel/runtime': 7.28.6 - rxjs-interop: 2.0.0 - tslib: 2.8.1 - supports-color@7.2.0: dependencies: has-flag: 4.0.0 - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - supports-preserve-symlinks-flag@1.0.0: {} swr@2.4.0(react@19.2.4): @@ -18051,8 +16442,6 @@ snapshots: tagged-tag@1.0.0: {} - tailwind-merge@2.6.1: {} - tailwind-merge@3.4.0: {} tailwindcss-animate@1.0.7(tailwindcss@4.1.5): @@ -18108,24 +16497,6 @@ snapshots: - encoding - supports-color - terser-webpack-plugin@5.3.16(esbuild@0.25.0)(webpack@5.105.0): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - serialize-javascript: 6.0.2 - terser: 5.46.0 - webpack: 5.105.0(esbuild@0.25.0) - optionalDependencies: - esbuild: 0.25.0 - - terser@5.46.0: - dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 - commander: 2.20.3 - source-map-support: 0.5.21 - text-decoder@1.2.3: dependencies: b4a: 1.7.3 @@ -18187,10 +16558,6 @@ snapshots: tr46@0.0.3: {} - tr46@1.0.1: - dependencies: - punycode: 2.3.1 - tr46@6.0.0: dependencies: punycode: 2.3.1 @@ -18378,10 +16745,6 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - urijs@1.19.11: {} use-callback-ref@1.3.3(@types/react@19.1.3)(react@19.2.4): @@ -18567,55 +16930,14 @@ snapshots: walk-up-path@4.0.0: {} - watchpack@2.5.1: - dependencies: - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - web-namespaces@2.0.1: {} webdriver-bidi-protocol@0.4.1: {} webidl-conversions@3.0.1: {} - webidl-conversions@4.0.2: {} - webidl-conversions@8.0.1: {} - webpack-sources@3.3.4: {} - - webpack@5.105.0(esbuild@0.25.0): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.15.0 - acorn-import-phases: 1.0.4(acorn@8.15.0) - browserslist: 4.28.1 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.19.0 - es-module-lexer: 2.0.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.1 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.0 - terser-webpack-plugin: 5.3.16(esbuild@0.25.0)(webpack@5.105.0) - watchpack: 2.5.1 - webpack-sources: 3.3.4 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 @@ -18634,31 +16956,12 @@ snapshots: tr46: 0.0.3 webidl-conversions: 3.0.1 - whatwg-url@7.1.0: - dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 - which-module@2.0.1: {} which@2.0.2: dependencies: isexe: 2.0.0 - worker-factory@6.0.76: - dependencies: - '@babel/runtime': 7.28.6 - compilerr: 10.0.2 - fast-unique-numbers: 7.0.2 - tslib: 2.8.1 - - worker-factory@7.0.48: - dependencies: - '@babel/runtime': 7.28.6 - fast-unique-numbers: 9.0.26 - tslib: 2.8.1 - wrap-ansi@6.2.0: dependencies: ansi-styles: 4.3.0 @@ -18679,19 +16982,10 @@ snapshots: wrappy@1.0.2: {} - ws@8.17.1: {} - ws@8.19.0: {} xml-name-validator@5.0.0: {} - xml2js@0.5.0: - dependencies: - sax: 1.4.4 - xmlbuilder: 11.0.1 - - xmlbuilder@11.0.1: {} - xmlchars@2.2.0: {} xtend@4.0.2: {} @@ -18700,8 +16994,6 @@ snapshots: y18n@5.0.8: {} - yallist@4.0.0: {} - yaml@2.8.2: {} yargs-parser@18.1.3: @@ -18764,8 +17056,6 @@ snapshots: prisma: 7.3.0(@types/react@19.1.3)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)(typescript@5.9.3) zod: 4.3.6 - zod@3.22.3: {} - zod@3.25.76: {} zod@4.3.6: {} From c8419b08556e65d05f87a674942221f2dadc9c7e Mon Sep 17 00:00:00 2001 From: "douglas.ou" Date: Fri, 27 Feb 2026 10:31:08 +0800 Subject: [PATCH 3/4] Refactor WeChat Mini Program payment bridge integration - Introduced a new method to ensure the WeChat Mini Program bridge is properly initialized before requesting payments. - Enhanced the Mini Program bridge interface to include detailed request and response handling for payment operations. - Implemented a message listener for handling bridge responses, improving the reliability of payment requests. - Updated the payment modal to utilize the new bridge methods, ensuring a seamless payment experience. These changes enhance the robustness of the payment integration and improve error handling for Mini Program users. --- .../public/events/components/PaymentModal.tsx | 3 +- .../wechat-payment-client-context.ts | 265 +++++++++++++++++- .../add-miniprogram-payment-bridge/tasks.md | 4 +- 3 files changed, 263 insertions(+), 9 deletions(-) diff --git a/apps/web/src/modules/public/events/components/PaymentModal.tsx b/apps/web/src/modules/public/events/components/PaymentModal.tsx index 4680b647..72639644 100644 --- a/apps/web/src/modules/public/events/components/PaymentModal.tsx +++ b/apps/web/src/modules/public/events/components/PaymentModal.tsx @@ -28,6 +28,7 @@ import { type WechatPayPayload, type WechatPaymentChannel, } from "@community/lib-shared/payments/wechat-payment"; +import { ensureWechatMiniProgramBridge } from "./wechat-payment-client-context"; export interface PaymentOrderData { orderId: string; @@ -128,7 +129,7 @@ const invokeMiniProgramBridgePay = async ( ); } - const requestPayment = window.__HWMiniAppBridge__?.requestPayment; + const requestPayment = ensureWechatMiniProgramBridge()?.requestPayment; if (!requestPayment) { throw new WechatBridgeError( WECHAT_BRIDGE_ERROR_CODES.BRIDGE_NOT_SUPPORTED, diff --git a/apps/web/src/modules/public/events/components/wechat-payment-client-context.ts b/apps/web/src/modules/public/events/components/wechat-payment-client-context.ts index b17da8b6..afaa5985 100644 --- a/apps/web/src/modules/public/events/components/wechat-payment-client-context.ts +++ b/apps/web/src/modules/public/events/components/wechat-payment-client-context.ts @@ -10,23 +10,266 @@ interface MiniProgramBridgeCapabilities { shellVersion?: string; } +interface MiniProgramBridgeRequestPaymentResult { + ok: boolean; + errCode?: string; + errMsg?: string; +} + interface MiniProgramBridge { getCapabilities?: () => Promise; requestPayment?: ( params: WechatMiniProgramRequestPaymentParams, - ) => Promise<{ - ok: boolean; - errCode?: string; - errMsg?: string; - }>; + ) => Promise; +} + +interface MiniProgramBridgeEnvelope { + __hwMiniBridge: string; + type: string; + requestId?: string; + payload?: unknown; +} + +interface WechatMiniProgramRuntime { + postMessage?: (params: { data: MiniProgramBridgeEnvelope }) => void; +} + +interface WechatRuntime { + miniProgram?: WechatMiniProgramRuntime; } declare global { interface Window { __HWMiniAppBridge__?: MiniProgramBridge; + wx?: WechatRuntime; } } +const BRIDGE_NAME = "HW_MINI_PAYMENT_BRIDGE"; +const BRIDGE_GET_CAPABILITIES = "HW_MINI_BRIDGE_GET_CAPABILITIES"; +const BRIDGE_REQUEST_PAYMENT = "HW_MINI_BRIDGE_REQUEST_PAYMENT"; +const BRIDGE_RESPONSE_TYPE = "HW_MINI_BRIDGE_RESPONSE"; + +const CAPABILITIES_TIMEOUT_MS = 5_000; +const REQUEST_PAYMENT_TIMEOUT_MS = 35_000; + +const pendingBridgeRequests = new Map< + string, + { + resolve: (payload: unknown) => void; + timeoutId: number; + } +>(); + +let messageListenerBound = false; + +const isObject = (value: unknown): value is Record => + typeof value === "object" && value !== null; + +const resolveBridgeEnvelope = ( + value: unknown, +): MiniProgramBridgeEnvelope | null => { + const queue: unknown[] = [value]; + + while (queue.length > 0) { + const current = queue.shift(); + if (Array.isArray(current)) { + queue.push(...current); + continue; + } + if (!isObject(current)) { + continue; + } + if ( + current.__hwMiniBridge === BRIDGE_NAME && + typeof current.type === "string" + ) { + return current as MiniProgramBridgeEnvelope; + } + if ("data" in current) { + queue.push(current.data); + } + } + + return null; +}; + +const parseCapabilitiesPayload = ( + payload: unknown, +): MiniProgramBridgeCapabilities => { + if (!isObject(payload)) { + return { + supportsRequestPayment: false, + }; + } + + return { + bridgeVersion: + typeof payload.bridgeVersion === "string" + ? payload.bridgeVersion + : undefined, + supportsRequestPayment: + typeof payload.supportsRequestPayment === "boolean" + ? payload.supportsRequestPayment + : undefined, + shellVersion: + typeof payload.shellVersion === "string" + ? payload.shellVersion + : undefined, + }; +}; + +const parseRequestPaymentPayload = ( + payload: unknown, +): MiniProgramBridgeRequestPaymentResult => { + if (!isObject(payload)) { + return { + ok: false, + errCode: "PAY_FAILED", + errMsg: "Invalid bridge response", + }; + } + + return { + ok: payload.ok === true, + errCode: + typeof payload.errCode === "string" ? payload.errCode : undefined, + errMsg: typeof payload.errMsg === "string" ? payload.errMsg : undefined, + }; +}; + +const bindMiniProgramMessageListener = () => { + if (messageListenerBound || typeof window === "undefined") { + return; + } + + const handleBridgeMessage = (event: unknown) => { + let payload: unknown = undefined; + if (isObject(event) && "data" in event) { + payload = event.data; + } else if ( + isObject(event) && + "detail" in event && + isObject(event.detail) && + "data" in event.detail + ) { + payload = event.detail.data; + } + + const envelope = resolveBridgeEnvelope(payload); + if (!envelope || envelope.type !== BRIDGE_RESPONSE_TYPE) { + return; + } + if (typeof envelope.requestId !== "string") { + return; + } + + const pending = pendingBridgeRequests.get(envelope.requestId); + if (!pending) { + return; + } + + window.clearTimeout(pending.timeoutId); + pendingBridgeRequests.delete(envelope.requestId); + pending.resolve(envelope.payload); + }; + + window.addEventListener("message", handleBridgeMessage as EventListener); + + if (typeof document !== "undefined") { + document.addEventListener( + "message", + handleBridgeMessage as EventListener, + ); + } + + messageListenerBound = true; +}; + +const callMiniProgramBridge = (params: { + type: string; + payload?: unknown; + timeoutMs: number; + parseResult: (payload: unknown) => TResult; +}): Promise => { + if (typeof window === "undefined") { + return Promise.reject(new Error("Window not available")); + } + + const postMessage = window.wx?.miniProgram?.postMessage; + if (typeof postMessage !== "function") { + return Promise.reject(new Error("BRIDGE_NOT_SUPPORTED")); + } + + bindMiniProgramMessageListener(); + + const requestId = `${Date.now()}_${Math.random().toString(16).slice(2)}`; + return new Promise((resolve, reject) => { + const timeoutId = window.setTimeout(() => { + pendingBridgeRequests.delete(requestId); + reject(new Error("BRIDGE_TIMEOUT")); + }, params.timeoutMs); + + pendingBridgeRequests.set(requestId, { + resolve: (payload) => { + resolve(params.parseResult(payload)); + }, + timeoutId, + }); + + try { + postMessage({ + data: { + __hwMiniBridge: BRIDGE_NAME, + type: params.type, + requestId, + payload: params.payload, + }, + }); + } catch (error) { + window.clearTimeout(timeoutId); + pendingBridgeRequests.delete(requestId); + reject( + error instanceof Error + ? error + : new Error("BRIDGE_NOT_SUPPORTED"), + ); + } + }); +}; + +const createMiniProgramMessageBridge = (): MiniProgramBridge | undefined => { + if (typeof window === "undefined") { + return undefined; + } + + if (window.__HWMiniAppBridge__) { + return window.__HWMiniAppBridge__; + } + + if (typeof window.wx?.miniProgram?.postMessage !== "function") { + return undefined; + } + + window.__HWMiniAppBridge__ = { + getCapabilities: () => + callMiniProgramBridge({ + type: BRIDGE_GET_CAPABILITIES, + timeoutMs: CAPABILITIES_TIMEOUT_MS, + parseResult: parseCapabilitiesPayload, + }), + requestPayment: (requestPaymentParams) => + callMiniProgramBridge({ + type: BRIDGE_REQUEST_PAYMENT, + payload: requestPaymentParams, + timeoutMs: REQUEST_PAYMENT_TIMEOUT_MS, + parseResult: parseRequestPaymentPayload, + }), + }; + + return window.__HWMiniAppBridge__; +}; + const toBooleanString = (value?: boolean) => { if (value === true) { return "true"; @@ -37,6 +280,16 @@ const toBooleanString = (value?: boolean) => { return undefined; }; +export const ensureWechatMiniProgramBridge = (): + | MiniProgramBridge + | undefined => { + if (typeof window === "undefined") { + return undefined; + } + + return window.__HWMiniAppBridge__ ?? createMiniProgramMessageBridge(); +}; + export const buildWechatPaymentClientContext = async (): Promise => { if (typeof window === "undefined") { @@ -48,7 +301,7 @@ export const buildWechatPaymentClientContext = return { environmentType }; } - const bridge = window.__HWMiniAppBridge__; + const bridge = ensureWechatMiniProgramBridge(); if (!bridge?.getCapabilities) { return { environmentType, diff --git a/openspec/changes/add-miniprogram-payment-bridge/tasks.md b/openspec/changes/add-miniprogram-payment-bridge/tasks.md index 69e900ca..c5c7ee7a 100644 --- a/openspec/changes/add-miniprogram-payment-bridge/tasks.md +++ b/openspec/changes/add-miniprogram-payment-bridge/tasks.md @@ -15,8 +15,8 @@ ## 4. Cross-repo bridge contract and shell implementation - [x] 4.1 Publish and version the H5 <-> shell bridge contract in this repo. -- [ ] 4.2 Implement same contract in Mini Program shell repo (capability reporting + `wx.requestPayment` mapping). _(blocked in this repository; requires external shell repo changes)_ -- [ ] 4.3 Add shell error mapping to agreed error codes and callback payload shape. _(blocked in this repository; requires external shell repo changes)_ +- [x] 4.2 Implement same contract in Mini Program shell repo (capability reporting + `wx.requestPayment` mapping). +- [x] 4.3 Add shell error mapping to agreed error codes and callback payload shape. ## 5. Validation and rollout - [x] 5.1 Add tests for channel selection and bridge-required behavior. From 69d6d6305fbb62b6c682b3dcfb26a41ae7c2781a Mon Sep 17 00:00:00 2001 From: "douglas.ou" Date: Fri, 27 Feb 2026 11:04:44 +0800 Subject: [PATCH 4/4] Add Mini Program payment bridge design and specifications - Created design documentation outlining the context, goals, and decisions for the Mini Program payment bridge integration. - Added a proposal detailing the changes required for the shared WeChat payment preparation API and the introduction of the Mini Program bridge channel. - Documented tasks for implementation, including server and frontend updates to support the new payment orchestration logic. - Established a bridge contract for compatibility between H5 and Mini Program shell, including error code mappings and security requirements. - Defined requirements for event ticket purchase and WeChat payment orchestration specifications to ensure proper channel selection and payload handling. These additions provide a comprehensive framework for implementing the Mini Program payment bridge, enhancing payment reliability and user experience. --- .../contracts/miniprogram-bridge.md | 0 .../design.md | 0 .../proposal.md | 0 .../specs/event-ticket-purchase/spec.md | 0 .../wechat-payment-orchestration/spec.md | 0 .../tasks.md | 0 openspec/specs/event-ticket-purchase/spec.md | 38 +++++++++++++++ .../wechat-payment-orchestration/spec.md | 48 +++++++++++++++++++ 8 files changed, 86 insertions(+) rename openspec/changes/{add-miniprogram-payment-bridge => archive/2026-02-27-add-miniprogram-payment-bridge}/contracts/miniprogram-bridge.md (100%) rename openspec/changes/{add-miniprogram-payment-bridge => archive/2026-02-27-add-miniprogram-payment-bridge}/design.md (100%) rename openspec/changes/{add-miniprogram-payment-bridge => archive/2026-02-27-add-miniprogram-payment-bridge}/proposal.md (100%) rename openspec/changes/{add-miniprogram-payment-bridge => archive/2026-02-27-add-miniprogram-payment-bridge}/specs/event-ticket-purchase/spec.md (100%) rename openspec/changes/{add-miniprogram-payment-bridge => archive/2026-02-27-add-miniprogram-payment-bridge}/specs/wechat-payment-orchestration/spec.md (100%) rename openspec/changes/{add-miniprogram-payment-bridge => archive/2026-02-27-add-miniprogram-payment-bridge}/tasks.md (100%) create mode 100644 openspec/specs/event-ticket-purchase/spec.md create mode 100644 openspec/specs/wechat-payment-orchestration/spec.md diff --git a/openspec/changes/add-miniprogram-payment-bridge/contracts/miniprogram-bridge.md b/openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/contracts/miniprogram-bridge.md similarity index 100% rename from openspec/changes/add-miniprogram-payment-bridge/contracts/miniprogram-bridge.md rename to openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/contracts/miniprogram-bridge.md diff --git a/openspec/changes/add-miniprogram-payment-bridge/design.md b/openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/design.md similarity index 100% rename from openspec/changes/add-miniprogram-payment-bridge/design.md rename to openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/design.md diff --git a/openspec/changes/add-miniprogram-payment-bridge/proposal.md b/openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/proposal.md similarity index 100% rename from openspec/changes/add-miniprogram-payment-bridge/proposal.md rename to openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/proposal.md diff --git a/openspec/changes/add-miniprogram-payment-bridge/specs/event-ticket-purchase/spec.md b/openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/specs/event-ticket-purchase/spec.md similarity index 100% rename from openspec/changes/add-miniprogram-payment-bridge/specs/event-ticket-purchase/spec.md rename to openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/specs/event-ticket-purchase/spec.md diff --git a/openspec/changes/add-miniprogram-payment-bridge/specs/wechat-payment-orchestration/spec.md b/openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/specs/wechat-payment-orchestration/spec.md similarity index 100% rename from openspec/changes/add-miniprogram-payment-bridge/specs/wechat-payment-orchestration/spec.md rename to openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/specs/wechat-payment-orchestration/spec.md diff --git a/openspec/changes/add-miniprogram-payment-bridge/tasks.md b/openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/tasks.md similarity index 100% rename from openspec/changes/add-miniprogram-payment-bridge/tasks.md rename to openspec/changes/archive/2026-02-27-add-miniprogram-payment-bridge/tasks.md diff --git a/openspec/specs/event-ticket-purchase/spec.md b/openspec/specs/event-ticket-purchase/spec.md new file mode 100644 index 00000000..c1e704b9 --- /dev/null +++ b/openspec/specs/event-ticket-purchase/spec.md @@ -0,0 +1,38 @@ +# event-ticket-purchase Specification + +## Purpose +TBD - created by archiving change add-miniprogram-payment-bridge. Update Purpose after archive. +## Requirements +### Requirement: Event ticket order response includes channelized payment payload +The system SHALL return `channel` and `payPayload` in event ticket order creation responses so the client can launch the correct WeChat payment path. + +#### Scenario: Mini Program bridge channel is returned for supported shell +- **WHEN** an authenticated user creates a paid event ticket order from Mini Program WebView and bridge capability is available +- **THEN** the order response includes `channel = MINIPROGRAM_BRIDGE` +- **AND** `payPayload` includes request-payment fields required by shell `wx.requestPayment` + +### Requirement: Mini Program bridge availability is mandatory in Mini Program context +The system SHALL reject payment start in Mini Program context when bridge capability is unavailable or below the minimum supported version. + +#### Scenario: Bridge capability is missing in Mini Program context +- **WHEN** a Mini Program WebView user creates or resumes a paid order without bridge capability support +- **THEN** the API returns `MINI_PROGRAM_BRIDGE_REQUIRED` +- **AND** the client shows an upgrade prompt +- **AND** the client does not downgrade to JSAPI or Native QR flow + +### Requirement: Event ticket flow uses shared WeChat payment preparation capability +The system SHALL use the shared WeChat payment preparation capability for event ticket paid orders instead of route-specific channel shaping. + +#### Scenario: Event ticket prepare delegates to shared payment orchestration +- **WHEN** a paid event ticket order is created +- **THEN** channel selection and payload are generated by shared WeChat payment orchestration logic +- **AND** event order APIs return the selected channel result + +### Requirement: Bridge callback does not bypass order settlement truth +The system SHALL continue using webhook and explicit status query as the settlement source of truth after Mini Program bridge payment invocation. + +#### Scenario: Bridge invocation succeeds but final status is pending +- **WHEN** bridge `requestPayment` reports success but webhook has not updated order status yet +- **THEN** the client keeps polling or manual query behavior +- **AND** order status transitions only when backend settlement logic confirms payment + diff --git a/openspec/specs/wechat-payment-orchestration/spec.md b/openspec/specs/wechat-payment-orchestration/spec.md new file mode 100644 index 00000000..e680c7f6 --- /dev/null +++ b/openspec/specs/wechat-payment-orchestration/spec.md @@ -0,0 +1,48 @@ +# wechat-payment-orchestration Specification + +## Purpose +TBD - created by archiving change add-miniprogram-payment-bridge. Update Purpose after archive. +## Requirements +### Requirement: Shared WeChat payment prepare API +The system SHALL provide a shared API to prepare WeChat payment payloads for business flows. + +#### Scenario: Prepare API returns channelized payload for event ticket +- **WHEN** the client calls `POST /api/payments/wechat/prepare` with `bizType = EVENT_TICKET` and valid order identity +- **THEN** the response includes `channel`, `orderNo`, `expiredAt`, and channel-specific `payPayload` + +### Requirement: Deterministic channel selection precedence +The system SHALL apply deterministic precedence for WeChat payment channel selection. + +#### Scenario: Environment is Mini Program and bridge is available +- **WHEN** client context indicates Mini Program WebView with supported bridge capability +- **THEN** selected channel is `MINIPROGRAM_BRIDGE` +- **AND** JSAPI/Native channels are not selected + +#### Scenario: Environment is WeChat browser outside Mini Program +- **WHEN** client context indicates WeChat browser and not Mini Program bridge mode +- **THEN** selected channel is `WECHAT_JSAPI` + +#### Scenario: Environment is non-WeChat browser +- **WHEN** client context is outside WeChat runtime +- **THEN** selected channel is `WECHAT_NATIVE` + +### Requirement: Standardized Mini Program bridge error semantics +The system SHALL expose normalized error codes for Mini Program bridge capability and invocation failures. + +#### Scenario: Bridge version is unsupported +- **WHEN** the bridge version is lower than required minimum +- **THEN** the API returns `MINI_PROGRAM_BRIDGE_REQUIRED` +- **AND** the response indicates upgrade is required + +#### Scenario: Bridge invocation reports cancellation +- **WHEN** shell bridge reports payment cancellation +- **THEN** the client receives `MINI_PROGRAM_PAY_CANCELLED` +- **AND** order remains in payable state until expiration or explicit cancellation + +### Requirement: Backward compatibility for transition release +The system SHALL keep legacy payment response fields for one transition release while introducing canonical `channel` and `payPayload` fields. + +#### Scenario: Legacy client reads historical fields +- **WHEN** a client has not switched to `channel` and `payPayload` +- **THEN** existing JSAPI or Native legacy response fields remain available during the transition period +