diff --git a/.github/workflows/ci-lint.yaml b/.github/workflows/ci-lint.yaml
index c25f3a7..7e2c267 100644
--- a/.github/workflows/ci-lint.yaml
+++ b/.github/workflows/ci-lint.yaml
@@ -22,7 +22,7 @@ jobs:
- exchange-oracle/server
- exchange-oracle/client
steps:
- - uses: actions/checkout@v6
+ - uses: actions/checkout@v7
- name: Enable corepack
run: corepack enable
- uses: actions/setup-node@v6
diff --git a/.github/workflows/ci-test.yaml b/.github/workflows/ci-test.yaml
index 88e4732..1945145 100644
--- a/.github/workflows/ci-test.yaml
+++ b/.github/workflows/ci-test.yaml
@@ -21,7 +21,7 @@ jobs:
exchange_oracle_server: ${{ steps.filter.outputs.exchange_oracle_server }}
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
with:
fetch-depth: 0
@@ -45,7 +45,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Enable corepack
run: corepack enable
@@ -72,7 +72,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@v6
+ uses: actions/checkout@v7
- name: Enable corepack
run: corepack enable
diff --git a/campaign-launcher/client/.env.example b/campaign-launcher/client/.env.example
new file mode 100644
index 0000000..63e291a
--- /dev/null
+++ b/campaign-launcher/client/.env.example
@@ -0,0 +1,14 @@
+# General
+VITE_APP_WALLETCONNECT_PROJECT_ID=replace_me
+VITE_APP_DOCS_URL=https://docs.humanprotocol.org
+VITE_APP_STAKING_DASHBOARD_URL=https://staking.humanprotocol.org
+VITE_FOOTER_LINK_GITHUB=https://github.com/Hu-Fi/hufi
+VITE_FOOTER_LINK_TELEGRAM=https://t.me/Hu_Finance
+VITE_FOOTER_LINK_X=https://x.com/Hu_Finance
+
+# Web3
+VITE_APP_ENVIRONMENT=localhost
+VITE_APP_SUPPORTED_CHAINS=1338
+VITE_APP_EXCHANGE_ORACLE_ADDRESS=0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc
+VITE_APP_RECORDING_ORACLE_ADDRESS=0x976EA74026E726554dB657fA54763abd0C3a0aa9
+VITE_APP_REPUTATION_ORACLE_ADDRESS=0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65
diff --git a/campaign-launcher/client/.gitignore b/campaign-launcher/client/.gitignore
new file mode 100644
index 0000000..b25fbaa
--- /dev/null
+++ b/campaign-launcher/client/.gitignore
@@ -0,0 +1,6 @@
+dist
+.env
+.env.local
+.env.*.local
+.yarn/install-state.gz
+node_modules/.yarn-state.yml
diff --git a/campaign-launcher/client/.yarnrc.yml b/campaign-launcher/client/.yarnrc.yml
new file mode 100644
index 0000000..3186f3f
--- /dev/null
+++ b/campaign-launcher/client/.yarnrc.yml
@@ -0,0 +1 @@
+nodeLinker: node-modules
diff --git a/campaign-launcher/client/eslint.config.mjs b/campaign-launcher/client/eslint.config.mjs
new file mode 100644
index 0000000..1f7556b
--- /dev/null
+++ b/campaign-launcher/client/eslint.config.mjs
@@ -0,0 +1,53 @@
+import eslint from '@eslint/js';
+import globals from 'globals';
+import tseslint from 'typescript-eslint';
+import reactHooksPlugin from 'eslint-plugin-react-hooks';
+import reactRefreshPlugin from 'eslint-plugin-react-refresh';
+import { fileURLToPath } from 'node:url';
+import path from 'node:path';
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+const config = tseslint.config(
+ {
+ ignores: ['dist', 'vite.config.ts'],
+ },
+ eslint.configs.recommended,
+ tseslint.configs.recommended,
+ {
+ files: ['**/*.{ts,tsx,js,jsx}'],
+ languageOptions: {
+ globals: {
+ ...globals.browser,
+ ...globals.es2022,
+ },
+ ecmaVersion: 2022,
+ sourceType: 'module',
+ parserOptions: {
+ projectService: true,
+ tsconfigRootDir: __dirname,
+ },
+ },
+ plugins: {
+ 'react-hooks': reactHooksPlugin,
+ 'react-refresh': reactRefreshPlugin,
+ },
+ rules: {
+ 'react-hooks/rules-of-hooks': 'error',
+ 'react-hooks/exhaustive-deps': 'warn',
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ '@typescript-eslint/no-explicit-any': 'off',
+ quotes: [
+ 'error',
+ 'single',
+ { avoidEscape: true, allowTemplateLiterals: true },
+ ],
+ },
+ }
+);
+
+export default config;
diff --git a/campaign-launcher/client/index.html b/campaign-launcher/client/index.html
new file mode 100644
index 0000000..21c82fc
--- /dev/null
+++ b/campaign-launcher/client/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Marketing Campaign Launcher
+
+
+
+
+
+
diff --git a/campaign-launcher/client/package.json b/campaign-launcher/client/package.json
new file mode 100644
index 0000000..b95e299
--- /dev/null
+++ b/campaign-launcher/client/package.json
@@ -0,0 +1,52 @@
+{
+ "name": "marketing-campaign-launcher-client",
+ "private": true,
+ "version": "1.0.0",
+ "description": "Marketing Campaign Launcher Client",
+ "author": "Human Protocol",
+ "license": "MIT",
+ "packageManager": "yarn@4.10.3",
+ "scripts": {
+ "clean": "rm -rf dist",
+ "lint": "eslint \"**/*.{ts,tsx}\"",
+ "start": "vite",
+ "build": "vite build",
+ "preview": "vite preview",
+ "start:prod": "serve -s dist",
+ "format": "prettier --write \"**/*.{ts,tsx,js,jsx}\""
+ },
+ "dependencies": {
+ "@emotion/react": "^11.11.3",
+ "@emotion/styled": "^11.11.0",
+ "@human-protocol/core": "^7.0.0",
+ "@human-protocol/sdk": "^7.3.0",
+ "@mui/icons-material": "^5.18.0",
+ "@mui/material": "^5.16.7",
+ "@reown/appkit": "^1.8.19",
+ "@reown/appkit-adapter-wagmi": "^1.8.19",
+ "@tanstack/react-query": "^5.91.3",
+ "ethers": "^6.16.0",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4",
+ "react-router-dom": "^7.13.0",
+ "serve": "^14.2.4",
+ "viem": "2.x",
+ "wagmi": "^3.6.4"
+ },
+ "devDependencies": {
+ "@eslint/js": "^10.0.1",
+ "@types/node": "^22.15.16",
+ "@types/react": "^19.2.2",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^4.3.1",
+ "eslint": "^10.1.0",
+ "eslint-plugin-react-hooks": "^5.1.0",
+ "eslint-plugin-react-refresh": "^0.4.11",
+ "globals": "^16.3.0",
+ "prettier": "^3.8.1",
+ "typescript": "^5.6.3",
+ "typescript-eslint": "^8.57.0",
+ "vite": "^6.2.4",
+ "vite-plugin-node-polyfills": "^0.25.0"
+ }
+}
diff --git a/campaign-launcher/client/public/robots.txt b/campaign-launcher/client/public/robots.txt
new file mode 100644
index 0000000..eb05362
--- /dev/null
+++ b/campaign-launcher/client/public/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow:
diff --git a/campaign-launcher/client/src/App.tsx b/campaign-launcher/client/src/App.tsx
new file mode 100644
index 0000000..45b4865
--- /dev/null
+++ b/campaign-launcher/client/src/App.tsx
@@ -0,0 +1,35 @@
+import type { ReactNode } from 'react';
+import { Navigate, Route, Routes } from 'react-router-dom';
+import { useAccount } from 'wagmi';
+
+import CreateCampaignPage from '@/pages/CreateCampaignPage';
+import HomePage from '@/pages/HomePage';
+
+function App() {
+ return (
+
+ } />
+
+
+
+ }
+ />
+ } />
+
+ );
+}
+
+const ProtectedRoute = ({ children }: { children: ReactNode }) => {
+ const { isConnected } = useAccount();
+
+ if (!isConnected) {
+ return ;
+ }
+
+ return children;
+};
+
+export default App;
diff --git a/campaign-launcher/client/src/components/AccountDropdown.tsx b/campaign-launcher/client/src/components/AccountDropdown.tsx
new file mode 100644
index 0000000..27d28ce
--- /dev/null
+++ b/campaign-launcher/client/src/components/AccountDropdown.tsx
@@ -0,0 +1,99 @@
+import { useState, type FC } from 'react';
+
+import AccountCircleIcon from '@mui/icons-material/AccountCircle';
+import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
+import LogoutIcon from '@mui/icons-material/Logout';
+import {
+ Button,
+ List,
+ ListItemButton,
+ Popover,
+ Stack,
+ Typography,
+} from '@mui/material';
+import { useAccount, useDisconnect } from 'wagmi';
+
+const formatAddress = (address?: string) => {
+ if (!address) return '';
+ return `${address.slice(0, 6)}...${address.slice(-4)}`;
+};
+
+const AccountDropdown: FC = () => {
+ const [anchorEl, setAnchorEl] = useState(null);
+ const { address } = useAccount();
+ const { disconnect } = useDisconnect();
+ const open = Boolean(anchorEl);
+
+ const closePopover = () => setAnchorEl(null);
+
+ const handleDisconnect = () => {
+ closePopover();
+ disconnect();
+ };
+
+ return (
+ <>
+
+
+
+
+
+ Sign out
+
+
+
+ >
+ );
+};
+
+export default AccountDropdown;
diff --git a/campaign-launcher/client/src/components/ConnectWallet/ConnectWalletContent.tsx b/campaign-launcher/client/src/components/ConnectWallet/ConnectWalletContent.tsx
new file mode 100644
index 0000000..25816f9
--- /dev/null
+++ b/campaign-launcher/client/src/components/ConnectWallet/ConnectWalletContent.tsx
@@ -0,0 +1,386 @@
+import {
+ createElement,
+ useCallback,
+ useEffect,
+ useRef,
+ useState,
+ type FC,
+} from 'react';
+
+import SearchIcon from '@mui/icons-material/Search';
+import {
+ Box,
+ Button,
+ CircularProgress,
+ Grid,
+ InputAdornment,
+ Stack,
+ TextField,
+ Typography,
+} from '@mui/material';
+import '@reown/appkit-ui/wui-qr-code';
+
+import { useIsMobile } from '@/hooks/useBreakpoints';
+import { useReownWalletOptions } from '@/hooks/useReownWalletOptions';
+
+type AppKitQrCodeElement = HTMLElement & {
+ alt?: string;
+ imageSrc?: string;
+ size?: number;
+ theme?: 'dark' | 'light';
+ uri?: string;
+};
+
+type AppKitQrCodeProps = {
+ alt: string;
+ imageSrc?: string;
+ uri: string;
+};
+
+const AppKitQrCode: FC = ({ alt, imageSrc, uri }) => {
+ const qrCodeRef = useRef(null);
+
+ useEffect(() => {
+ if (!qrCodeRef.current) return;
+
+ qrCodeRef.current.alt = alt;
+ qrCodeRef.current.imageSrc = imageSrc;
+ qrCodeRef.current.size = 500;
+ qrCodeRef.current.theme = 'light';
+ qrCodeRef.current.uri = uri;
+ }, [alt, imageSrc, uri]);
+
+ return createElement('wui-qr-code', {
+ ref: qrCodeRef,
+ style: { display: 'block', height: '100%', width: '100%' },
+ });
+};
+
+const ConnectWalletContent: FC = () => {
+ const [search, setSearch] = useState('');
+ const [showAllWallets, setShowAllWallets] = useState(false);
+
+ const isMobile = useIsMobile();
+ const {
+ canOpenMobileWallet,
+ connectingWallet,
+ connectWallet,
+ displayedWallets,
+ fetchMoreWallets,
+ hasMoreWallets,
+ isFetchingWallets,
+ isFetchingWcUri,
+ openMobileWallet,
+ resetSearch,
+ resetWalletConnect,
+ wcUri,
+ } = useReownWalletOptions({ search, showAllWallets });
+
+ const isFetching = isFetchingWallets || isFetchingWcUri;
+
+ const resetState = useCallback(() => {
+ resetWalletConnect();
+ setSearch('');
+ resetSearch();
+ setShowAllWallets(false);
+ }, [resetSearch, resetWalletConnect]);
+
+ useEffect(() => {
+ return () => {
+ resetState();
+ };
+ }, [resetState]);
+
+ if (isMobile && wcUri && connectingWallet && canOpenMobileWallet) {
+ return (
+
+
+ Continue in {connectingWallet.name}
+
+
+
+ Accept the connection request in your wallet.
+
+
+
+
+
+ );
+ }
+
+ if (wcUri && connectingWallet) {
+ return (
+
+
+ Scan with {connectingWallet.name}
+
+
+
+
+
+ Open your wallet app and scan this QR code to continue.
+
+
+
+ );
+ }
+
+ return (
+
+
+ Connect wallet
+
+
+ Connect your wallet to create marketing campaigns and fund escrows
+ directly.
+
+ {showAllWallets && (
+ setSearch(event.target.value)}
+ placeholder="Search wallet"
+ size="small"
+ fullWidth
+ sx={{ mb: 2 }}
+ InputProps={{
+ startAdornment: (
+
+
+
+ ),
+ endAdornment: isFetching ? (
+
+
+
+ ) : null,
+ }}
+ />
+ )}
+
+ {!isFetching && showAllWallets && displayedWallets.length === 0 && (
+
+
+ No wallets found
+
+
+ )}
+ {displayedWallets.length > 0 && (
+
+ {displayedWallets.map((wallet) => {
+ const isConnectingWallet =
+ connectingWallet?.id === wallet.id && isFetchingWcUri;
+
+ return (
+
+ {isFetching && (
+
+ )}
+
+
+ );
+ })}
+
+ )}
+
+
+ {!showAllWallets ? (
+ }
+ onClick={() => setShowAllWallets(true)}
+ >
+ Search wallet
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+ );
+};
+
+export default ConnectWalletContent;
diff --git a/campaign-launcher/client/src/components/ConnectWallet/index.tsx b/campaign-launcher/client/src/components/ConnectWallet/index.tsx
new file mode 100644
index 0000000..9d07eda
--- /dev/null
+++ b/campaign-launcher/client/src/components/ConnectWallet/index.tsx
@@ -0,0 +1,60 @@
+import { type FC } from 'react';
+
+import WalletIcon from '@mui/icons-material/AccountBalanceWallet';
+import { Button, type ButtonProps } from '@mui/material';
+
+import ResponsiveOverlay from '@/components/ResponsiveOverlay';
+import { useConnectWalletModal } from '@/hooks/useConnectWalletModal';
+
+import ConnectWalletContent from './ConnectWalletContent';
+
+type ConnectWalletProps = {
+ size?: ButtonProps['size'];
+};
+
+const ConnectWallet: FC = ({ size = 'large' }) => {
+ const {
+ closeConnectWallet,
+ isConnecting,
+ isConnectWalletOpen,
+ openConnectWallet,
+ } = useConnectWalletModal();
+
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
+
+export default ConnectWallet;
diff --git a/campaign-launcher/client/src/components/Field.tsx b/campaign-launcher/client/src/components/Field.tsx
new file mode 100644
index 0000000..c6fff2e
--- /dev/null
+++ b/campaign-launcher/client/src/components/Field.tsx
@@ -0,0 +1,5 @@
+import { TextField, type TextFieldProps } from '@mui/material';
+
+export const Field = (props: TextFieldProps) => {
+ return ;
+};
diff --git a/campaign-launcher/client/src/components/Footer/index.tsx b/campaign-launcher/client/src/components/Footer/index.tsx
new file mode 100644
index 0000000..58b73e5
--- /dev/null
+++ b/campaign-launcher/client/src/components/Footer/index.tsx
@@ -0,0 +1,110 @@
+import type { FC } from 'react';
+
+import GitHubIcon from '@mui/icons-material/GitHub';
+import TelegramIcon from '@mui/icons-material/Telegram';
+import XIcon from '@mui/icons-material/X';
+import {
+ Box,
+ Container,
+ IconButton,
+ Stack,
+ styled,
+ Typography,
+} from '@mui/material';
+
+import { MOBILE_BOTTOM_NAV_HEIGHT } from '@/constants';
+
+const SocialMediaIconButton = styled(IconButton)(({ theme }) => ({
+ padding: 0,
+ '& svg': {
+ fill: theme.palette.text.primary,
+ fillOpacity: 0.7,
+ },
+
+ '&:hover': {
+ background: 'none',
+ '& svg': {
+ fill: theme.palette.text.primary,
+ fillOpacity: 1,
+ },
+ },
+}));
+
+const handleClickOnSocialButton = (url: string) => {
+ window.open(url, '_blank');
+};
+
+const Footer: FC<{ reserveBottomOffset: boolean }> = ({
+ reserveBottomOffset,
+}) => {
+ return (
+
+
+
+
+ © {new Date().getFullYear()} HuFi powered by HUMAN Protocol
+
+
+
+ handleClickOnSocialButton(
+ import.meta.env.VITE_FOOTER_LINK_GITHUB
+ )
+ }
+ >
+
+
+
+ handleClickOnSocialButton(import.meta.env.VITE_FOOTER_LINK_X)
+ }
+ >
+
+
+
+ handleClickOnSocialButton(
+ import.meta.env.VITE_FOOTER_LINK_TELEGRAM
+ )
+ }
+ >
+
+
+
+
+
+
+ );
+};
+
+export default Footer;
diff --git a/campaign-launcher/client/src/components/KeyValue.tsx b/campaign-launcher/client/src/components/KeyValue.tsx
new file mode 100644
index 0000000..b15297c
--- /dev/null
+++ b/campaign-launcher/client/src/components/KeyValue.tsx
@@ -0,0 +1,22 @@
+import { Box, Typography } from '@mui/material';
+
+type Props = {
+ label: string;
+ value: string;
+};
+
+export const KeyValue = ({ label, value }: Props) => {
+ return (
+
+
+ {label}
+
+
+ {value || '-'}
+
+
+ );
+};
diff --git a/campaign-launcher/client/src/components/ResponsiveOverlay/index.tsx b/campaign-launcher/client/src/components/ResponsiveOverlay/index.tsx
new file mode 100644
index 0000000..cc222bd
--- /dev/null
+++ b/campaign-launcher/client/src/components/ResponsiveOverlay/index.tsx
@@ -0,0 +1,94 @@
+import { type FC, type PropsWithChildren } from 'react';
+
+import CloseIcon from '@mui/icons-material/Close';
+import {
+ Dialog,
+ Drawer,
+ IconButton,
+ Paper,
+ type SxProps,
+ type Theme,
+} from '@mui/material';
+
+import { useIsMobile } from '@/hooks/useBreakpoints';
+
+type Props = {
+ open: boolean;
+ onClose: () => void;
+ desktopSx?: SxProps;
+ mobileSx?: SxProps;
+ closeButtonSx?: SxProps;
+};
+
+const closeButtonBaseSx = {
+ position: 'absolute',
+ color: 'text.secondary',
+ zIndex: 2,
+};
+
+const ResponsiveOverlay: FC> = ({
+ open,
+ onClose,
+ desktopSx,
+ mobileSx,
+ closeButtonSx,
+ children,
+}) => {
+ const isMobile = useIsMobile();
+
+ if (isMobile) {
+ return (
+
+
+
+
+ {children}
+
+ );
+ }
+
+ return (
+
+ );
+};
+
+export default ResponsiveOverlay;
diff --git a/campaign-launcher/client/src/components/campaign/CampaignSteps.tsx b/campaign-launcher/client/src/components/campaign/CampaignSteps.tsx
new file mode 100644
index 0000000..698b9f1
--- /dev/null
+++ b/campaign-launcher/client/src/components/campaign/CampaignSteps.tsx
@@ -0,0 +1,771 @@
+import {
+ Alert,
+ Box,
+ Button,
+ Card,
+ CardActionArea,
+ Checkbox,
+ Divider,
+ FormControlLabel,
+ Grid,
+ MenuItem,
+ Paper,
+ Stack,
+ Typography,
+} from '@mui/material';
+
+import { Field } from '@/components/Field';
+import { KeyValue } from '@/components/KeyValue';
+import { ORACLE_ADDRESSES } from '@/constants';
+import {
+ getFundingTokenConfig,
+ getFundingTokenOptions,
+} from '@/constants/fundingTokens';
+import { supportedChains } from '@/providers/wagmiConfig';
+import {
+ CampaignRequestType,
+ EscrowFundToken,
+ SocialPlatform,
+ type CampaignFormState,
+ type PreparedManifest,
+ type RecordingOracleKeyState,
+} from '@/types';
+import { shortKeyPreview } from '@/utils/manifest';
+
+type JobTypeStepProps = {
+ form: CampaignFormState;
+ onSelect: (requestType: CampaignRequestType) => void;
+};
+
+export const JobTypeStep = ({ form, onSelect }: JobTypeStepProps) => (
+
+
+ Choose job type
+
+ Start with the marketing workflow you want to validate.
+
+
+
+
+ onSelect(CampaignRequestType.SOCIAL_MEDIA_PROMOTION)}
+ />
+
+
+ onSelect(CampaignRequestType.SOCIAL_MEDIA_ENGAGEMENT)}
+ />
+
+
+
+);
+
+type PlatformStepProps = {
+ form: CampaignFormState;
+ onSelect: (platform: SocialPlatform) => void;
+};
+
+export const PlatformStep = ({ form, onSelect }: PlatformStepProps) => {
+ const isPromotion =
+ form.requestType === CampaignRequestType.SOCIAL_MEDIA_PROMOTION;
+
+ return (
+
+
+ Choose platform
+
+ LinkedIn is currently available only for engagement campaigns.
+
+
+
+
+ onSelect(SocialPlatform.X)}
+ />
+
+
+ onSelect(SocialPlatform.LINKEDIN)}
+ />
+
+
+ {isPromotion && (
+
+ Social media promotion is limited to X / Twitter for this version.
+
+ )}
+
+ );
+};
+
+type GeneralDataStepProps = {
+ form: CampaignFormState;
+ updateForm: (
+ key: K,
+ value: CampaignFormState[K],
+ ) => void;
+ onChainChange: (chainId: CampaignFormState['chainId']) => void;
+};
+
+export const GeneralDataStep = ({
+ form,
+ updateForm,
+ onChainChange,
+}: GeneralDataStepProps) => {
+ const fundingTokenOptions = getFundingTokenOptions(form.chainId);
+
+ return (
+
+
+ General campaign data
+
+ These fields are shared by every marketing manifest.
+
+
+
+
+
+ onChainChange(
+ Number(event.target.value) as CampaignFormState['chainId'],
+ )
+ }
+ >
+ {supportedChains.map((chain) => (
+
+ ))}
+
+
+
+
+ updateForm('fundToken', event.target.value as EscrowFundToken)
+ }
+ >
+ {fundingTokenOptions.map((token) => (
+
+ ))}
+
+
+
+ updateForm('fundAmount', event.target.value)}
+ />
+
+
+ updateForm('campaignName', event.target.value)}
+ />
+
+
+
+ updateForm('submissionsRequired', event.target.value)
+ }
+ />
+
+
+
+ updateForm('campaignDescription', event.target.value)
+ }
+ />
+
+
+ updateForm('endDate', event.target.value)}
+ InputLabelProps={{ shrink: true }}
+ />
+
+
+
+ updateForm('qualifications', event.target.value)
+ }
+ />
+
+
+
+ );
+};
+
+type SelectionCardProps = {
+ selected: boolean;
+ title: string;
+ description: string;
+ disabled?: boolean;
+ onClick: () => void;
+};
+
+const SelectionCard = ({
+ selected,
+ title,
+ description,
+ disabled,
+ onClick,
+}: SelectionCardProps) => (
+
+
+
+
+ {title}
+
+ {description}
+
+
+
+);
+
+type PromotionFieldsProps = {
+ form: CampaignFormState;
+ updatePromotion: (
+ key: K,
+ value: CampaignFormState['promotion'][K],
+ ) => void;
+};
+
+export const PromotionFields = ({
+ form,
+ updatePromotion,
+}: PromotionFieldsProps) => (
+
+
+ Promotion details
+
+ Define what a valid social media post must contain.
+
+
+
+
+
+ updatePromotion('requiredHashtags', event.target.value)
+ }
+ />
+
+
+
+ updatePromotion('requiredKeywords', event.target.value)
+ }
+ />
+
+
+
+ updatePromotion('requiredLink', event.target.value)
+ }
+ />
+
+
+ updatePromotion('minLength', event.target.value)}
+ />
+
+
+
+ updatePromotion('minLiveDurationHours', event.target.value)
+ }
+ />
+
+
+
+ updatePromotion('minFollowers', event.target.value)
+ }
+ />
+
+
+
+ updatePromotion('minAccountAgeDays', event.target.value)
+ }
+ />
+
+
+ updatePromotion('minLikes', event.target.value)}
+ />
+
+
+
+ updatePromotion('minReposts', event.target.value)
+ }
+ />
+
+
+
+ updatePromotion(
+ 'allowedAbuseProbability',
+ event.target
+ .value as CampaignFormState['promotion']['allowedAbuseProbability'],
+ )
+ }
+ >
+
+
+
+
+
+
+
+
+ updatePromotion('mustBePublic', event.target.checked)
+ }
+ />
+ }
+ label="Must be public"
+ />
+
+ updatePromotion('requiresMedia', event.target.checked)
+ }
+ />
+ }
+ label="Requires media"
+ />
+
+
+
+
+);
+
+type EngagementFieldsProps = {
+ form: CampaignFormState;
+ updateEngagement: (
+ key: K,
+ value: CampaignFormState['engagement'][K],
+ ) => void;
+ updateXCredentials: <
+ K extends keyof CampaignFormState['engagement']['xApiCredentials'],
+ >(
+ key: K,
+ value: CampaignFormState['engagement']['xApiCredentials'][K],
+ ) => void;
+};
+
+export const EngagementFields = ({
+ form,
+ updateEngagement,
+ updateXCredentials,
+}: EngagementFieldsProps) => {
+ const isLinkedIn = form.platform === SocialPlatform.LINKEDIN;
+ const xLikeRequiresEncryption =
+ form.platform === SocialPlatform.X && form.engagement.checkLike;
+
+ return (
+
+
+ Engagement details
+
+ Define what interactions workers must perform on the target post.
+
+
+
+ updateEngagement('targetPostUrl', event.target.value)
+ }
+ />
+
+
+ updateEngagement('checkLike', event.target.checked)
+ }
+ />
+ }
+ label="Check like"
+ />
+
+ updateEngagement('checkComment', event.target.checked)
+ }
+ />
+ }
+ label="Check comment"
+ />
+
+ updateEngagement('checkRepost', event.target.checked)
+ }
+ />
+ }
+ label="Check repost"
+ />
+
+ updateEngagement('checkQuote', event.target.checked)
+ }
+ />
+ }
+ label="Check quote"
+ />
+
+
+ {isLinkedIn && (
+
+ LinkedIn supports like and comment checks only.
+
+ )}
+
+ {xLikeRequiresEncryption && (
+
+
+ X API credentials
+
+
+ These fields are included only in the encrypted manifest.
+
+
+
+
+ updateXCredentials('consumerKey', event.target.value)
+ }
+ />
+
+
+
+ updateXCredentials('consumerSecret', event.target.value)
+ }
+ />
+
+
+
+ updateXCredentials('accessToken', event.target.value)
+ }
+ />
+
+
+
+ updateXCredentials('accessTokenSecret', event.target.value)
+ }
+ />
+
+
+
+ )}
+
+ );
+};
+
+type SummaryStepProps = {
+ form: CampaignFormState;
+ encryptionRequired: boolean;
+ recordingOracleKey: RecordingOracleKeyState;
+ preparedManifest: PreparedManifest | null;
+ isWrongNetwork: boolean;
+ isSwitchingChain: boolean;
+ selectedChainName: string;
+ manifestPreview: string;
+ onSwitchChain: () => void;
+};
+
+export const SummaryStep = ({
+ form,
+ encryptionRequired,
+ recordingOracleKey,
+ preparedManifest,
+ isWrongNetwork,
+ isSwitchingChain,
+ selectedChainName,
+ manifestPreview,
+ onSwitchChain,
+}: SummaryStepProps) => (
+
+
+ Review and launch
+
+ Confirm the exact manifest string and escrow settings before approving
+ the selected token.
+
+
+
+ {isWrongNetwork && (
+
+ Switch
+
+ }
+ >
+ Switch your wallet to {selectedChainName} before launching.
+
+ )}
+ {encryptionRequired && recordingOracleKey.isLoading && (
+ Fetching recording oracle public key...
+ )}
+
+
+
+
+
+
+
+ Manifest preview
+
+
+ {manifestPreview || 'Manifest is not ready yet.'}
+
+
+
+
+
+
+ The launcher will approve {form.fundToken} if allowance is insufficient,
+ then create the escrow with the prepared manifest.
+
+
+);
+
+type SummaryPanelProps = {
+ form: CampaignFormState;
+ encryptionRequired: boolean;
+ preparedManifest: PreparedManifest | null;
+ recordingOracleKey: RecordingOracleKeyState;
+};
+
+const SummaryPanel = ({
+ form,
+ encryptionRequired,
+ preparedManifest,
+ recordingOracleKey,
+}: SummaryPanelProps) => {
+ const selectedChain = supportedChains.find(
+ (chain) => chain.id === form.chainId,
+ );
+ const selectedToken = getFundingTokenConfig(form.chainId, form.fundToken);
+
+ return (
+
+
+
+ Launch summary
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {encryptionRequired && (
+
+
+
+ )}
+
+
+
+
+ {encryptionRequired && (
+ <>
+
+
+
+
+
+
+ >
+ )}
+
+
+ );
+};
diff --git a/campaign-launcher/client/src/components/campaign/LaunchProgressDialog.tsx b/campaign-launcher/client/src/components/campaign/LaunchProgressDialog.tsx
new file mode 100644
index 0000000..2dad464
--- /dev/null
+++ b/campaign-launcher/client/src/components/campaign/LaunchProgressDialog.tsx
@@ -0,0 +1,114 @@
+import {
+ Alert,
+ Button,
+ Dialog,
+ DialogActions,
+ DialogContent,
+ DialogTitle,
+ Stack,
+ Step,
+ StepContent,
+ StepLabel,
+ Stepper,
+ Typography,
+} from '@mui/material';
+
+type LaunchProgressDialogProps = {
+ open: boolean;
+ isApproving: boolean;
+ isCreating: boolean;
+ isNotifyingExchange: boolean;
+ error?: Error;
+ escrowAddress?: string;
+ onClose: () => void;
+};
+
+const getLaunchProgressStep = ({
+ isApproving,
+ isCreating,
+ isNotifyingExchange,
+ escrowAddress,
+}: Pick<
+ LaunchProgressDialogProps,
+ 'isApproving' | 'isCreating' | 'isNotifyingExchange' | 'escrowAddress'
+>): number => {
+ if (escrowAddress) return 3;
+ if (isNotifyingExchange) return 2;
+ if (isCreating) return 1;
+ if (isApproving) return 0;
+ return 0;
+};
+
+const LaunchProgressDialog = ({
+ open,
+ isApproving,
+ isCreating,
+ isNotifyingExchange,
+ error,
+ escrowAddress,
+ onClose,
+}: LaunchProgressDialogProps) => {
+ const activeStep = getLaunchProgressStep({
+ isApproving,
+ isCreating,
+ isNotifyingExchange,
+ escrowAddress,
+ });
+ const canClose = Boolean(escrowAddress) || Boolean(error);
+ const launchSteps = [
+ {
+ label: 'Approve funds',
+ description: isApproving
+ ? 'Waiting for token approval confirmation.'
+ : 'Token approval confirmed.',
+ },
+ {
+ label: 'Create escrow',
+ description: isCreating
+ ? 'Waiting for escrow creation confirmation.'
+ : 'Escrow creation transaction confirmed.',
+ },
+ {
+ label: 'Sign webhook',
+ description: isNotifyingExchange
+ ? 'Waiting for webhook signature and exchange oracle notification.'
+ : 'Exchange oracle webhook acknowledged.',
+ },
+ {
+ label: 'Escrow completed',
+ description: escrowAddress
+ ? `Escrow created: ${escrowAddress}`
+ : 'Escrow creation is not completed yet.',
+ },
+ ];
+
+ return (
+
+ );
+};
+
+export default LaunchProgressDialog;
diff --git a/campaign-launcher/client/src/components/layout/Shell.tsx b/campaign-launcher/client/src/components/layout/Shell.tsx
new file mode 100644
index 0000000..635be9f
--- /dev/null
+++ b/campaign-launcher/client/src/components/layout/Shell.tsx
@@ -0,0 +1,142 @@
+import { AppBar, Box, Button, Container, Stack, Toolbar } from '@mui/material';
+import type { ReactNode } from 'react';
+import { Link as RouterLink, useLocation } from 'react-router-dom';
+import { useAccount } from 'wagmi';
+
+import AccountDropdown from '@/components/AccountDropdown';
+import ConnectWallet from '@/components/ConnectWallet';
+
+import Footer from '../Footer';
+
+const docsUrl =
+ import.meta.env.VITE_APP_DOCS_URL || 'https://docs.humanprotocol.org';
+const stakeUrl =
+ import.meta.env.VITE_APP_STAKING_DASHBOARD_URL ||
+ 'https://dashboard.humanprotocol.org';
+
+type NavLinkProps = {
+ to: string;
+ active?: boolean;
+ external?: boolean;
+ disabled?: boolean;
+ children: ReactNode;
+};
+
+const NavLink = ({
+ to,
+ active,
+ external,
+ disabled,
+ children,
+}: NavLinkProps) => (
+
+);
+
+type ShellProps = {
+ children: ReactNode;
+};
+
+const Shell = ({ children }: ShellProps) => {
+ const { isConnected } = useAccount();
+ const location = useLocation();
+
+ return (
+
+
+
+
+
+ Marketing
+
+
+
+ Dashboard
+
+
+ Support
+
+
+ Stake HMT
+
+
+ {isConnected ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+
+
+
+ {children}
+
+
+
+ );
+};
+
+export default Shell;
diff --git a/campaign-launcher/client/src/constants/chains.ts b/campaign-launcher/client/src/constants/chains.ts
new file mode 100644
index 0000000..eb546cc
--- /dev/null
+++ b/campaign-launcher/client/src/constants/chains.ts
@@ -0,0 +1,61 @@
+import { ChainId } from '@human-protocol/sdk';
+import * as wagmiChains from 'wagmi/chains';
+import type { Chain } from 'wagmi/chains';
+
+export const LOCALHOST: Chain = {
+ id: ChainId.LOCALHOST,
+ name: 'Localhost',
+ nativeCurrency: {
+ decimals: 18,
+ name: 'Ether',
+ symbol: 'ETH',
+ },
+ rpcUrls: {
+ default: {
+ http: ['http://127.0.0.1:8545'],
+ },
+ },
+};
+
+export const ALL_CHAINS: Chain[] = [
+ wagmiChains.mainnet,
+ wagmiChains.sepolia,
+ wagmiChains.bsc,
+ wagmiChains.bscTestnet,
+ wagmiChains.polygon,
+ wagmiChains.polygonAmoy,
+ wagmiChains.moonbeam,
+ wagmiChains.moonbaseAlpha,
+ wagmiChains.avalancheFuji,
+ wagmiChains.avalanche,
+ wagmiChains.xLayer,
+ wagmiChains.xLayerTestnet,
+ LOCALHOST,
+];
+
+const defaultChainIdsByEnvironment: Record = {
+ mainnet: [ChainId.POLYGON],
+ testnet: [ChainId.POLYGON_AMOY],
+ localhost: [ChainId.LOCALHOST],
+};
+
+export const getSupportedChains = (): [Chain, ...Chain[]] => {
+ const environment = (
+ import.meta.env.VITE_APP_ENVIRONMENT || 'testnet'
+ ).toLowerCase();
+ const defaultChainIds =
+ defaultChainIdsByEnvironment[environment] || defaultChainIdsByEnvironment.testnet;
+ const envChainIds = import.meta.env.VITE_APP_SUPPORTED_CHAINS?.split(',')
+ .map((chainId) => Number(chainId.trim()))
+ .filter(Boolean);
+ const supportedChainIds = envChainIds?.length ? envChainIds : defaultChainIds;
+ const supportedChains = ALL_CHAINS.filter((chain) =>
+ supportedChainIds.includes(chain.id)
+ );
+
+ if (!supportedChains.length) {
+ throw new Error('No supported chains configured');
+ }
+
+ return supportedChains as [Chain, ...Chain[]];
+};
diff --git a/campaign-launcher/client/src/constants/fundingTokens.ts b/campaign-launcher/client/src/constants/fundingTokens.ts
new file mode 100644
index 0000000..90cda37
--- /dev/null
+++ b/campaign-launcher/client/src/constants/fundingTokens.ts
@@ -0,0 +1,124 @@
+import { ChainId, NETWORKS } from '@human-protocol/sdk';
+
+import { EscrowFundToken, type EvmAddress } from '@/types';
+
+export type IERC20Token = {
+ address: EvmAddress;
+ decimals: number;
+ symbol: EscrowFundToken;
+};
+
+export const TOKEN_ADDRESSES: {
+ [chainId in ChainId]?: {
+ [token in EscrowFundToken]?: IERC20Token;
+ };
+} = {
+ [ChainId.MAINNET]: {
+ [EscrowFundToken.HMT]: {
+ address: NETWORKS[ChainId.MAINNET]!.hmtAddress as EvmAddress,
+ decimals: 18,
+ symbol: EscrowFundToken.HMT,
+ },
+ [EscrowFundToken.USDT]: {
+ address: '0xdAC17F958D2ee523a2206206994597C13D831ec7',
+ decimals: 6,
+ symbol: EscrowFundToken.USDT,
+ },
+ [EscrowFundToken.USDC]: {
+ address: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
+ decimals: 6,
+ symbol: EscrowFundToken.USDC,
+ },
+ },
+ [ChainId.SEPOLIA]: {
+ [EscrowFundToken.HMT]: {
+ address: NETWORKS[ChainId.SEPOLIA]!.hmtAddress as EvmAddress,
+ decimals: 18,
+ symbol: EscrowFundToken.HMT,
+ },
+ [EscrowFundToken.USDT]: {
+ address: '0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0',
+ decimals: 6,
+ symbol: EscrowFundToken.USDT,
+ },
+ [EscrowFundToken.USDC]: {
+ address: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
+ decimals: 6,
+ symbol: EscrowFundToken.USDC,
+ },
+ },
+ [ChainId.BSC_MAINNET]: {
+ [EscrowFundToken.HMT]: {
+ address: NETWORKS[ChainId.BSC_MAINNET]!.hmtAddress as EvmAddress,
+ decimals: 18,
+ symbol: EscrowFundToken.HMT,
+ },
+ },
+ [ChainId.POLYGON]: {
+ [EscrowFundToken.HMT]: {
+ address: NETWORKS[ChainId.POLYGON]!.hmtAddress as EvmAddress,
+ decimals: 18,
+ symbol: EscrowFundToken.HMT,
+ },
+ [EscrowFundToken.USDT0]: {
+ address: '0xc2132D05D31c914a87C6611C10748AEb04B58e8F',
+ decimals: 6,
+ symbol: EscrowFundToken.USDT0,
+ },
+ },
+ [ChainId.POLYGON_AMOY]: {
+ [EscrowFundToken.HMT]: {
+ address: NETWORKS[ChainId.POLYGON_AMOY]!.hmtAddress as EvmAddress,
+ decimals: 18,
+ symbol: EscrowFundToken.HMT,
+ },
+ [EscrowFundToken.USDC]: {
+ address: '0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582',
+ decimals: 6,
+ symbol: EscrowFundToken.USDC,
+ },
+ },
+ [ChainId.LOCALHOST]: {
+ [EscrowFundToken.HMT]: {
+ address: NETWORKS[ChainId.LOCALHOST]!.hmtAddress as EvmAddress,
+ decimals: 18,
+ symbol: EscrowFundToken.HMT,
+ },
+ },
+ [ChainId.BSC_TESTNET]: {
+ [EscrowFundToken.HMT]: {
+ address: NETWORKS[ChainId.BSC_TESTNET]!.hmtAddress as EvmAddress,
+ decimals: 18,
+ symbol: EscrowFundToken.HMT,
+ },
+ [EscrowFundToken.USDC]: {
+ address: '0x64544969ed7EBf5f083679233325356EbE738930',
+ decimals: 18,
+ symbol: EscrowFundToken.USDC,
+ },
+ [EscrowFundToken.USDT]: {
+ address: '0x66E972502A34A625828C544a1914E8D8cc2A9dE5',
+ decimals: 18,
+ symbol: EscrowFundToken.USDT,
+ },
+ },
+};
+
+export const getFundingTokenOptions = (chainId: ChainId): IERC20Token[] => {
+ return Object.values(TOKEN_ADDRESSES[chainId] || {}).filter(
+ (token): token is IERC20Token => Boolean(token)
+ );
+};
+
+export const getDefaultFundingToken = (
+ chainId: ChainId
+): EscrowFundToken => {
+ return getFundingTokenOptions(chainId)[0]?.symbol || EscrowFundToken.HMT;
+};
+
+export const getFundingTokenConfig = (
+ chainId: ChainId,
+ token: EscrowFundToken
+): IERC20Token | undefined => {
+ return TOKEN_ADDRESSES[chainId]?.[token];
+};
diff --git a/campaign-launcher/client/src/constants/index.ts b/campaign-launcher/client/src/constants/index.ts
new file mode 100644
index 0000000..c82dd92
--- /dev/null
+++ b/campaign-launcher/client/src/constants/index.ts
@@ -0,0 +1,16 @@
+import type { EvmAddress } from '@/types';
+
+export const ORACLE_ADDRESSES = {
+ exchangeOracle: import.meta.env
+ .VITE_APP_EXCHANGE_ORACLE_ADDRESS as EvmAddress,
+ recordingOracle: import.meta.env
+ .VITE_APP_RECORDING_ORACLE_ADDRESS as EvmAddress,
+ reputationOracle: import.meta.env
+ .VITE_APP_REPUTATION_ORACLE_ADDRESS as EvmAddress,
+};
+
+export const MAX_MANIFEST_PREVIEW_LENGTH = 2800;
+
+export const WALLET_PAGE_SIZE = 20;
+
+export const MOBILE_BOTTOM_NAV_HEIGHT = 90;
diff --git a/campaign-launcher/client/src/hooks/useBreakpoints.ts b/campaign-launcher/client/src/hooks/useBreakpoints.ts
new file mode 100644
index 0000000..ec1284c
--- /dev/null
+++ b/campaign-launcher/client/src/hooks/useBreakpoints.ts
@@ -0,0 +1,6 @@
+import useMediaQuery from '@mui/material/useMediaQuery';
+
+export const useIsMobile = () => {
+ const isSmall = useMediaQuery('(max-width: 900px)');
+ return isSmall;
+};
diff --git a/campaign-launcher/client/src/hooks/useConnectWalletModal.ts b/campaign-launcher/client/src/hooks/useConnectWalletModal.ts
new file mode 100644
index 0000000..1b7cabd
--- /dev/null
+++ b/campaign-launcher/client/src/hooks/useConnectWalletModal.ts
@@ -0,0 +1,75 @@
+import { useCallback, useEffect, useRef, useState } from 'react';
+
+import { useConnection, useDisconnect } from 'wagmi';
+
+import { useIsMobile } from '@/hooks/useBreakpoints';
+
+type UseConnectWalletModalOptions = {
+ onCancel?: () => void;
+ onConnect?: () => void;
+ promptOnMobileConnect?: boolean;
+};
+
+export const useConnectWalletModal = ({
+ onCancel,
+ onConnect,
+ promptOnMobileConnect = true,
+}: UseConnectWalletModalOptions = {}) => {
+ const [isConnectWalletOpen, setIsConnectWalletOpen] = useState(false);
+ const { isConnected, isConnecting } = useConnection();
+ const { mutate: disconnect } = useDisconnect();
+ const isMobile = useIsMobile();
+ const wasConnectedRef = useRef(isConnected);
+ const appKitSessionStartedRef = useRef(false);
+ const promptOnNextConnectRef = useRef(false);
+
+ useEffect(() => {
+ if (!wasConnectedRef.current && isConnected) {
+ const didStartConnectSession = appKitSessionStartedRef.current;
+
+ if (didStartConnectSession) {
+ setIsConnectWalletOpen(false);
+ appKitSessionStartedRef.current = false;
+ promptOnNextConnectRef.current = false;
+ onConnect?.();
+ }
+ }
+
+ wasConnectedRef.current = isConnected;
+ }, [isConnected, isMobile, onConnect]);
+
+ useEffect(() => {
+ return () => {
+ promptOnNextConnectRef.current = false;
+ };
+ }, []);
+
+ const openConnectWallet = useCallback(() => {
+ appKitSessionStartedRef.current = true;
+ promptOnNextConnectRef.current = promptOnMobileConnect;
+ setIsConnectWalletOpen(true);
+ }, [promptOnMobileConnect]);
+
+ const closeConnectWallet = useCallback(() => {
+ setIsConnectWalletOpen(false);
+
+ if (!appKitSessionStartedRef.current || isConnected) {
+ return;
+ }
+
+ appKitSessionStartedRef.current = false;
+ promptOnNextConnectRef.current = false;
+ onCancel?.();
+
+ if (isConnecting) {
+ disconnect();
+ }
+ }, [disconnect, isConnected, isConnecting, onCancel]);
+
+ return {
+ closeConnectWallet,
+ isConnectWalletOpen,
+ isConnecting,
+ openConnectWallet,
+ };
+};
diff --git a/campaign-launcher/client/src/hooks/useMarketingEscrow.ts b/campaign-launcher/client/src/hooks/useMarketingEscrow.ts
new file mode 100644
index 0000000..d99cab2
--- /dev/null
+++ b/campaign-launcher/client/src/hooks/useMarketingEscrow.ts
@@ -0,0 +1,221 @@
+import { useCallback, useState } from 'react';
+
+import HMTokenABI from '@human-protocol/core/abis/HMToken.json';
+import {
+ EscrowClient,
+ KVStoreKeys,
+ KVStoreUtils,
+ NETWORKS,
+} from '@human-protocol/sdk';
+import type { ChainId } from '@human-protocol/sdk';
+import { Contract, ethers } from 'ethers';
+import { useAccount, useWalletClient } from 'wagmi';
+
+import { ORACLE_ADDRESSES } from '@/constants';
+import { getFundingTokenConfig } from '@/constants/fundingTokens';
+import type { EscrowFundToken, EscrowResult, PreparedManifest } from '@/types';
+import { walletClientToSigner } from '@/utils/wallet';
+
+type LaunchEscrowInput = {
+ chainId: ChainId;
+ fundToken: EscrowFundToken;
+ fundAmount: string;
+ preparedManifest: PreparedManifest;
+};
+
+type LaunchState = {
+ isApproving: boolean;
+ isCreating: boolean;
+ isNotifyingExchange: boolean;
+ error?: Error;
+ result?: EscrowResult;
+};
+
+type ExchangeWebhookBody = {
+ chain_id: ChainId;
+ escrow_address: string;
+ event_type: 'escrow_created';
+};
+
+const HEADER_SIGNATURE_KEY = 'human-signature';
+
+const notifyExchangeOracle = async (
+ chainId: ChainId,
+ signer: ethers.Signer,
+ webhookBody: ExchangeWebhookBody,
+): Promise => {
+ const exchangeWebhookUrl = await KVStoreUtils.get(
+ chainId,
+ ORACLE_ADDRESSES.exchangeOracle,
+ KVStoreKeys.webhookUrl,
+ );
+
+ if (!exchangeWebhookUrl) {
+ throw new Error('Exchange oracle webhook URL not found in KVStore');
+ }
+
+ const signature = await signer.signMessage(JSON.stringify(webhookBody));
+ const response = await fetch(exchangeWebhookUrl, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ [HEADER_SIGNATURE_KEY]: signature,
+ },
+ body: JSON.stringify(webhookBody),
+ });
+
+ if (!response.ok) {
+ const responseBody = await response.text();
+ throw new Error(
+ `Exchange webhook failed with status ${response.status}: ${responseBody}`,
+ );
+ }
+};
+
+export const useMarketingEscrow = () => {
+ const { address } = useAccount();
+ const { data: walletClient } = useWalletClient();
+ const [state, setState] = useState({
+ isApproving: false,
+ isCreating: false,
+ isNotifyingExchange: false,
+ });
+
+ const reset = useCallback(() => {
+ setState({
+ isApproving: false,
+ isCreating: false,
+ isNotifyingExchange: false,
+ });
+ }, []);
+
+ const launchEscrow = useCallback(
+ async ({
+ chainId,
+ fundToken,
+ fundAmount,
+ preparedManifest,
+ }: LaunchEscrowInput): Promise => {
+ if (!walletClient || !address) {
+ setState((prev) => ({
+ ...prev,
+ error: new Error('Wallet is not connected'),
+ }));
+ return;
+ }
+
+ const network = NETWORKS[chainId];
+ const token = getFundingTokenConfig(chainId, fundToken);
+ if (!token || !network?.factoryAddress) {
+ setState((prev) => ({
+ ...prev,
+ error: new Error('Funding token or escrow factory is not configured'),
+ }));
+ return;
+ }
+
+ let createdEscrowAddress = '';
+
+ try {
+ setState({
+ isApproving: true,
+ isCreating: false,
+ isNotifyingExchange: false,
+ });
+
+ const signer = await walletClientToSigner(walletClient);
+ const tokenContract = new Contract(token.address, HMTokenABI, signer);
+ const parsedFundAmount = ethers.parseUnits(fundAmount, token.decimals);
+
+ const currentAllowance = (await tokenContract.allowance(
+ address,
+ network.factoryAddress,
+ )) as bigint;
+
+ if (currentAllowance < parsedFundAmount) {
+ const approveTx = await tokenContract.approve(
+ network.factoryAddress,
+ parsedFundAmount,
+ );
+ await approveTx.wait();
+ }
+
+ setState({
+ isApproving: false,
+ isCreating: true,
+ isNotifyingExchange: false,
+ });
+
+ const escrowClient = await EscrowClient.build(signer);
+ const escrowAddress = await escrowClient.createFundAndSetupEscrow(
+ token.address,
+ parsedFundAmount,
+ address,
+ {
+ exchangeOracle: ORACLE_ADDRESSES.exchangeOracle,
+ recordingOracle: ORACLE_ADDRESSES.recordingOracle,
+ reputationOracle: ORACLE_ADDRESSES.reputationOracle,
+ manifest: preparedManifest.manifestString,
+ manifestHash: preparedManifest.manifestHash,
+ },
+ );
+ createdEscrowAddress = escrowAddress;
+
+ setState({
+ isApproving: false,
+ isCreating: false,
+ isNotifyingExchange: true,
+ });
+
+ await notifyExchangeOracle(chainId, signer, {
+ chain_id: chainId,
+ escrow_address: escrowAddress,
+ event_type: 'escrow_created',
+ });
+
+ setState({
+ isApproving: false,
+ isCreating: false,
+ isNotifyingExchange: false,
+ result: {
+ escrowAddress,
+ transactionManifestHash: preparedManifest.manifestHash,
+ },
+ });
+ } catch (error) {
+ setState({
+ isApproving: false,
+ isCreating: false,
+ isNotifyingExchange: false,
+ ...(createdEscrowAddress && {
+ result: {
+ escrowAddress: createdEscrowAddress,
+ transactionManifestHash: preparedManifest.manifestHash,
+ },
+ }),
+ error:
+ error instanceof Error
+ ? new Error(
+ createdEscrowAddress
+ ? `Escrow created (${createdEscrowAddress}), but exchange webhook notification failed: ${error.message}`
+ : error.message,
+ )
+ : new Error(
+ createdEscrowAddress
+ ? `Escrow created (${createdEscrowAddress}), but exchange webhook notification failed`
+ : 'Failed to create escrow',
+ ),
+ });
+ }
+ },
+ [address, walletClient],
+ );
+
+ return {
+ ...state,
+ isLoading:
+ state.isApproving || state.isCreating || state.isNotifyingExchange,
+ launchEscrow,
+ reset,
+ };
+};
diff --git a/campaign-launcher/client/src/hooks/useReownWalletOptions.ts b/campaign-launcher/client/src/hooks/useReownWalletOptions.ts
new file mode 100644
index 0000000..95353d1
--- /dev/null
+++ b/campaign-launcher/client/src/hooks/useReownWalletOptions.ts
@@ -0,0 +1,309 @@
+import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+
+import {
+ ApiController,
+ AssetUtil,
+ ChainController,
+ ConnectionController,
+ ConnectionControllerUtil,
+ ConnectorController,
+ ConnectorControllerUtil,
+ ConnectorUtil,
+ CoreHelperUtil,
+ type ConnectorOrWalletItem,
+ type WalletUtil,
+ type WcWallet,
+} from '@reown/appkit-controllers';
+
+import { WALLET_PAGE_SIZE } from '@/constants';
+
+export type WalletOption = {
+ id: string;
+ imageUrl: string;
+ item: ConnectorOrWalletItem;
+ name: string;
+};
+
+const getWalletImage = (item: ConnectorOrWalletItem) => {
+ if (item.kind === 'wallet') {
+ return (
+ AssetUtil.getWalletImage(item.wallet) ||
+ AssetUtil.getWalletImageUrl(item.wallet.image_id)
+ );
+ }
+
+ return (
+ item.connector.imageUrl ||
+ item.connector.info?.icon ||
+ AssetUtil.getConnectorImage(item.connector) ||
+ AssetUtil.getAssetImageUrl(item.connector.imageId)
+ );
+};
+
+const mapWalletOption = (item: ConnectorOrWalletItem): WalletOption => {
+ if (item.kind === 'wallet') {
+ return {
+ id: item.wallet.id,
+ imageUrl: getWalletImage(item),
+ item,
+ name: item.wallet.name,
+ };
+ }
+
+ return {
+ id: item.connector.id,
+ imageUrl: getWalletImage(item),
+ item,
+ name: item.connector.name,
+ };
+};
+
+const getInitialWallets = () =>
+ ConnectorUtil.connectorList().map(mapWalletOption);
+
+const mapRemoteWallets = (
+ wallets: Parameters[0]
+) =>
+ wallets.map((wallet) =>
+ mapWalletOption({ kind: 'wallet', subtype: 'recommended', wallet })
+ );
+
+const normalizeSearchValue = (value: string) =>
+ value.toLowerCase().replace(/[^a-z0-9]/g, '');
+
+const searchWallets = (walletOptions: WalletOption[], searchValue: string) => {
+ const normalizedSearch = normalizeSearchValue(searchValue);
+
+ if (!normalizedSearch) {
+ return walletOptions;
+ }
+
+ return walletOptions.filter((wallet) =>
+ normalizeSearchValue(wallet.name).includes(normalizedSearch)
+ );
+};
+
+const mergeWalletOptions = (walletOptions: WalletOption[]) => {
+ const uniqueWallets = new Map();
+
+ walletOptions.forEach((wallet) => {
+ const key =
+ normalizeSearchValue(wallet.name) || `${wallet.item.kind}-${wallet.id}`;
+
+ if (!uniqueWallets.has(key)) {
+ uniqueWallets.set(key, wallet);
+ }
+ });
+
+ return [...uniqueWallets.values()];
+};
+
+const getMobileWallet = (wallet: WalletOption): WcWallet | undefined => {
+ if (wallet.item.kind === 'wallet') {
+ return wallet.item.wallet;
+ }
+
+ return wallet.item.connector.explorerWallet;
+};
+
+export const useReownWalletOptions = ({
+ search,
+ showAllWallets,
+}: {
+ search: string;
+ showAllWallets: boolean;
+}) => {
+ const [wallets, setWallets] = useState(getInitialWallets);
+ const [wcWallets, setWcWallets] = useState([]);
+ const [wcWalletsCount, setWcWalletsCount] = useState(0);
+ const [wcWalletsPage, setWcWalletsPage] = useState(1);
+ const [wcUri, setWcUri] = useState(ConnectionController.state.wcUri);
+ const [isFetchingWallets, setIsFetchingWallets] = useState(false);
+ const [isFetchingWcUri, setIsFetchingWcUri] = useState(
+ ConnectionController.state.wcFetchingUri
+ );
+ const [connectingWallet, setConnectingWallet] = useState(
+ null
+ );
+ const [appliedSearchValue, setAppliedSearchValue] = useState('');
+
+ const searchRequestIdRef = useRef(0);
+
+ const fetchWcWallets = useCallback(
+ async (_page: number, _searchValue: string) => {
+ const { data, count } = await ApiController.fetchWallets({
+ chains: ChainController.getRequestedCaipNetworkIds().join(','),
+ entries: WALLET_PAGE_SIZE,
+ search: _searchValue,
+ page: _page,
+ });
+
+ const mappedWallets = mapRemoteWallets(data);
+ setWcWallets((prevWallets) =>
+ _page === 1 ? mappedWallets : [...prevWallets, ...mappedWallets]
+ );
+ setWcWalletsCount(count);
+ },
+ []
+ );
+
+ useEffect(() => {
+ const updateInitialWallets = () => setWallets(getInitialWallets());
+
+ const unsubscribers = [
+ ConnectorController.subscribeKey('connectors', updateInitialWallets),
+ ApiController.subscribeKey('recommended', updateInitialWallets),
+ ConnectionController.subscribeKey('wcUri', setWcUri),
+ ConnectionController.subscribeKey('wcFetchingUri', setIsFetchingWcUri),
+ ];
+
+ updateInitialWallets();
+
+ return () => {
+ unsubscribers.forEach((unsubscribe) => unsubscribe());
+ };
+ }, []);
+
+ useEffect(() => {
+ void ApiController.fetchRecommendedWallets();
+ }, []);
+
+ useEffect(() => {
+ if (!showAllWallets) return;
+
+ const requestedSearchValue = search.trim();
+ const runFetch = async () => {
+ setIsFetchingWallets(true);
+ searchRequestIdRef.current += 1;
+ const requestId = searchRequestIdRef.current;
+
+ try {
+ await fetchWcWallets(1, requestedSearchValue);
+ } catch (error) {
+ console.error('Failed to fetch wallets', error);
+ } finally {
+ if (requestId === searchRequestIdRef.current) {
+ setAppliedSearchValue(requestedSearchValue);
+ setIsFetchingWallets(false);
+ }
+ }
+ };
+
+ if (!requestedSearchValue) {
+ runFetch();
+ return;
+ }
+
+ const timeout = setTimeout(() => {
+ runFetch();
+ }, 250);
+
+ return () => clearTimeout(timeout);
+ }, [search, showAllWallets, fetchWcWallets]);
+
+ const displayedWallets = useMemo(() => {
+ if (showAllWallets) {
+ return mergeWalletOptions([
+ ...searchWallets(wallets, appliedSearchValue),
+ ...wcWallets,
+ ]);
+ }
+
+ return wallets;
+ }, [appliedSearchValue, showAllWallets, wallets, wcWallets]);
+
+ const resetWalletConnect = useCallback(() => {
+ ConnectionController.resetUri();
+ ConnectionController.setWcLinking(undefined);
+ ConnectionController.setRecentWallet(undefined);
+ setConnectingWallet(null);
+ }, []);
+
+ const openMobileWallet = useCallback(
+ (wallet = connectingWallet) => {
+ if (!wallet) return;
+
+ ConnectionControllerUtil.onConnectMobile(getMobileWallet(wallet));
+ },
+ [connectingWallet]
+ );
+
+ const connectWallet = useCallback(
+ async (wallet: WalletOption) => {
+ resetWalletConnect();
+ setConnectingWallet(wallet);
+
+ try {
+ if (
+ wallet.item.kind === 'connector' &&
+ wallet.item.subtype !== 'walletConnect'
+ ) {
+ await ConnectorControllerUtil.connectExternal(wallet.item.connector);
+ return;
+ }
+
+ if (wallet.item.kind === 'wallet') {
+ ConnectionController.setRecentWallet(wallet.item.wallet);
+ }
+
+ await ConnectionController.connectWalletConnect({
+ cache: CoreHelperUtil.isMobile() ? 'auto' : 'never',
+ });
+
+ if (CoreHelperUtil.isMobile() && getMobileWallet(wallet)?.mobile_link) {
+ openMobileWallet(wallet);
+ }
+ } catch {
+ setConnectingWallet(null);
+ }
+ },
+ [openMobileWallet, resetWalletConnect]
+ );
+
+ const resetSearch = useCallback(() => {
+ setAppliedSearchValue('');
+ setWcWallets([]);
+ setWcWalletsCount(0);
+ setWcWalletsPage(1);
+ }, []);
+
+ const fetchMoreWallets = useCallback(async () => {
+ if (isFetchingWallets || isFetchingWcUri) return;
+
+ setIsFetchingWallets(true);
+ try {
+ await fetchWcWallets(wcWalletsPage + 1, appliedSearchValue);
+ setWcWalletsPage(wcWalletsPage + 1);
+ } catch (error) {
+ console.error('Failed to fetch more wallets', error);
+ } finally {
+ setIsFetchingWallets(false);
+ }
+ }, [
+ appliedSearchValue,
+ isFetchingWallets,
+ isFetchingWcUri,
+ fetchWcWallets,
+ wcWalletsPage,
+ ]);
+
+ const hasMoreWallets = wcWalletsCount > wcWallets.length;
+ const canOpenMobileWallet = Boolean(
+ connectingWallet && getMobileWallet(connectingWallet)?.mobile_link
+ );
+
+ return {
+ canOpenMobileWallet,
+ connectingWallet,
+ connectWallet,
+ displayedWallets,
+ fetchMoreWallets,
+ hasMoreWallets,
+ isFetchingWallets,
+ isFetchingWcUri,
+ openMobileWallet,
+ resetSearch,
+ resetWalletConnect,
+ wcUri,
+ };
+};
diff --git a/campaign-launcher/client/src/index.css b/campaign-launcher/client/src/index.css
new file mode 100644
index 0000000..9cb1749
--- /dev/null
+++ b/campaign-launcher/client/src/index.css
@@ -0,0 +1,23 @@
+@font-face {
+ font-family: Inter;
+ font-style: normal;
+ font-weight: 400 800;
+ src: local('Inter');
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ min-width: 320px;
+ background: #f7f8fc;
+}
+
+button,
+input,
+textarea,
+select {
+ font: inherit;
+}
diff --git a/campaign-launcher/client/src/main.tsx b/campaign-launcher/client/src/main.tsx
new file mode 100644
index 0000000..2a9c77c
--- /dev/null
+++ b/campaign-launcher/client/src/main.tsx
@@ -0,0 +1,26 @@
+import CssBaseline from '@mui/material/CssBaseline';
+import { ThemeProvider } from '@mui/material/styles';
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import { BrowserRouter } from 'react-router-dom';
+
+import App from './App';
+import './index.css';
+import { QueryClientProvider } from './providers/QueryClientProvider';
+import { WagmiProvider } from './providers/WagmiProvider';
+import theme from './theme';
+
+ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/campaign-launcher/client/src/pages/CreateCampaignPage.tsx b/campaign-launcher/client/src/pages/CreateCampaignPage.tsx
new file mode 100644
index 0000000..7f0c33a
--- /dev/null
+++ b/campaign-launcher/client/src/pages/CreateCampaignPage.tsx
@@ -0,0 +1,529 @@
+import {
+ Alert,
+ type AlertColor,
+ Box,
+ Button,
+ Card,
+ CardContent,
+ Snackbar,
+ Stack,
+ Step,
+ StepLabel,
+ Stepper,
+ Typography,
+} from '@mui/material';
+import { useEffect, useMemo, useState, type ReactNode } from 'react';
+import { useNavigate } from 'react-router-dom';
+import { useAccount, useSwitchChain } from 'wagmi';
+
+import {
+ EngagementFields,
+ GeneralDataStep,
+ JobTypeStep,
+ PlatformStep,
+ PromotionFields,
+ SummaryStep,
+} from '@/components/campaign/CampaignSteps';
+import LaunchProgressDialog from '@/components/campaign/LaunchProgressDialog';
+import Shell from '@/components/layout/Shell';
+import { MAX_MANIFEST_PREVIEW_LENGTH } from '@/constants';
+import {
+ getDefaultFundingToken,
+ getFundingTokenConfig,
+} from '@/constants/fundingTokens';
+import { useMarketingEscrow } from '@/hooks/useMarketingEscrow';
+import { supportedChains } from '@/providers/wagmiConfig';
+import {
+ CampaignRequestType,
+ SocialPlatform,
+ type CampaignFormState,
+ type PreparedManifest,
+ type RecordingOracleKeyState,
+} from '@/types';
+import {
+ getRecordingOraclePublicKey,
+ prepareManifest,
+ requiresEncryption,
+} from '@/utils/manifest';
+import { validateForm } from '@/utils/validation';
+
+const steps = ['Job type', 'Platform', 'General data', 'Details', 'Summary'];
+
+const toDatetimeLocal = (date: Date): string => {
+ const offsetMs = date.getTimezoneOffset() * 60 * 1000;
+ return new Date(date.getTime() - offsetMs).toISOString().slice(0, 16);
+};
+
+const getDefaultForm = (): CampaignFormState => ({
+ chainId: supportedChains[0].id,
+ requestType: CampaignRequestType.SOCIAL_MEDIA_PROMOTION,
+ platform: SocialPlatform.X,
+ campaignName: '',
+ campaignDescription: '',
+ submissionsRequired: '1',
+ endDate: toDatetimeLocal(new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)),
+ fundToken: getDefaultFundingToken(supportedChains[0].id),
+ fundAmount: '',
+ qualifications: '',
+ promotion: {
+ requiredHashtags: '#humanprotocol',
+ requiredKeywords: '',
+ requiredLink: '',
+ minLength: '',
+ requiresMedia: false,
+ mustBePublic: true,
+ minLiveDurationHours: '24',
+ minFollowers: '',
+ minAccountAgeDays: '',
+ minLikes: '',
+ minReposts: '',
+ allowedAbuseProbability: 'medium',
+ },
+ engagement: {
+ targetPostUrl: '',
+ checkLike: false,
+ checkRepost: false,
+ checkQuote: false,
+ checkComment: true,
+ xApiCredentials: {
+ consumerKey: '',
+ consumerSecret: '',
+ accessToken: '',
+ accessTokenSecret: '',
+ },
+ },
+});
+
+const recordingOracleKeyIdle: RecordingOracleKeyState = {
+ isLoading: false,
+ publicKey: '',
+};
+
+const CreateCampaignPage = () => {
+ const navigate = useNavigate();
+ const [activeStep, setActiveStep] = useState(0);
+ const [form, setForm] = useState(getDefaultForm);
+ const [recordingOracleKey, setRecordingOracleKey] =
+ useState(recordingOracleKeyIdle);
+ const [preparedManifest, setPreparedManifest] =
+ useState(null);
+ const [prepareError, setPrepareError] = useState('');
+ const [toast, setToast] = useState<{
+ message: ReactNode;
+ open: boolean;
+ severity: AlertColor;
+ }>({ message: '', open: false, severity: 'error' });
+ const [launchModalOpen, setLaunchModalOpen] = useState(false);
+
+ const { chainId } = useAccount();
+ const { switchChain, isPending: isSwitchingChain } = useSwitchChain();
+ const escrow = useMarketingEscrow();
+
+ const encryptionRequired = requiresEncryption(form);
+ const selectedChain = supportedChains.find(
+ (chain) => chain.id === form.chainId,
+ );
+ const isWrongNetwork = chainId !== form.chainId;
+ const manifestPreview = useMemo(() => {
+ if (!preparedManifest) return '';
+ const value = JSON.stringify(preparedManifest.manifest, null, 2);
+
+ return value.length > MAX_MANIFEST_PREVIEW_LENGTH
+ ? `${value.slice(0, MAX_MANIFEST_PREVIEW_LENGTH)}...`
+ : value;
+ }, [preparedManifest]);
+
+ const resetPreparedState = () => {
+ setPreparedManifest(null);
+ setPrepareError('');
+ escrow.reset();
+ };
+
+ const updateForm = (
+ key: K,
+ value: CampaignFormState[K],
+ ) => {
+ resetPreparedState();
+ setForm((current) => ({
+ ...current,
+ [key]: value,
+ }));
+ };
+
+ const handleChainChange = (chainId: CampaignFormState['chainId']) => {
+ resetPreparedState();
+ setForm((current) => ({
+ ...current,
+ chainId,
+ fundToken:
+ getFundingTokenConfig(chainId, current.fundToken)?.symbol ||
+ getDefaultFundingToken(chainId),
+ }));
+ };
+
+ const updatePromotion = (
+ key: K,
+ value: CampaignFormState['promotion'][K],
+ ) => {
+ resetPreparedState();
+ setForm((current) => ({
+ ...current,
+ promotion: {
+ ...current.promotion,
+ [key]: value,
+ },
+ }));
+ };
+
+ const updateEngagement = (
+ key: K,
+ value: CampaignFormState['engagement'][K],
+ ) => {
+ resetPreparedState();
+ setForm((current) => ({
+ ...current,
+ engagement: {
+ ...current.engagement,
+ [key]: value,
+ },
+ }));
+ };
+
+ const updateXCredentials = <
+ K extends keyof CampaignFormState['engagement']['xApiCredentials'],
+ >(
+ key: K,
+ value: CampaignFormState['engagement']['xApiCredentials'][K],
+ ) => {
+ resetPreparedState();
+ setForm((current) => ({
+ ...current,
+ engagement: {
+ ...current.engagement,
+ xApiCredentials: {
+ ...current.engagement.xApiCredentials,
+ [key]: value,
+ },
+ },
+ }));
+ };
+
+ const handleRequestTypeChange = (requestType: CampaignRequestType) => {
+ resetPreparedState();
+ setForm((current) => ({
+ ...current,
+ requestType,
+ platform:
+ requestType === CampaignRequestType.SOCIAL_MEDIA_PROMOTION
+ ? SocialPlatform.X
+ : current.platform,
+ }));
+ };
+
+ const handlePlatformChange = (platform: SocialPlatform) => {
+ resetPreparedState();
+ setForm((current) => ({
+ ...current,
+ platform,
+ engagement: {
+ ...current.engagement,
+ checkRepost:
+ platform === SocialPlatform.LINKEDIN
+ ? false
+ : current.engagement.checkRepost,
+ checkQuote:
+ platform === SocialPlatform.LINKEDIN
+ ? false
+ : current.engagement.checkQuote,
+ },
+ }));
+ };
+
+ const stepErrors = (step: number): string[] => {
+ if (step === 0 && !form.requestType) return ['Select a job type'];
+ if (step === 1 && !form.platform) return ['Select a platform'];
+ if (step === 2) {
+ return validateForm({
+ ...form,
+ promotion: {
+ ...form.promotion,
+ requiredHashtags: form.promotion.requiredHashtags || '#placeholder',
+ },
+ engagement: {
+ ...form.engagement,
+ targetPostUrl: form.engagement.targetPostUrl || 'https://example.com',
+ checkComment: true,
+ },
+ }).filter((error) =>
+ [
+ 'Campaign name is required',
+ 'Campaign description is required',
+ 'Submissions required must be greater than zero',
+ 'End date must be in the future',
+ 'Selected currency is not configured for this network',
+ 'Fund amount must be greater than zero',
+ ].includes(error),
+ );
+ }
+ if (step === 3) return validateForm(form);
+ return [];
+ };
+
+ const goNext = () => {
+ const validationErrors = stepErrors(activeStep);
+ if (validationErrors.length) {
+ setToast({
+ open: true,
+ severity: 'error',
+ message: (
+
+ {validationErrors.map((error) => (
+
+ {error}
+
+ ))}
+
+ ),
+ });
+ return;
+ }
+ setActiveStep((current) => Math.min(current + 1, steps.length - 1));
+ };
+
+ const goBack = () => {
+ setActiveStep((current) => Math.max(current - 1, 0));
+ };
+
+ useEffect(() => {
+ let cancelled = false;
+
+ const loadReview = async () => {
+ if (activeStep !== 4) return;
+
+ setPreparedManifest(null);
+ setPrepareError('');
+
+ if (!encryptionRequired) {
+ setRecordingOracleKey(recordingOracleKeyIdle);
+
+ try {
+ const prepared = await prepareManifest(form, recordingOracleKeyIdle);
+ if (!cancelled) setPreparedManifest(prepared);
+ } catch (error) {
+ if (!cancelled) {
+ setPrepareError(
+ error instanceof Error
+ ? error.message
+ : 'Failed to prepare manifest',
+ );
+ }
+ }
+ return;
+ }
+
+ setRecordingOracleKey({ ...recordingOracleKeyIdle, isLoading: true });
+
+ const key = await getRecordingOraclePublicKey(
+ form.chainId,
+ encryptionRequired,
+ );
+
+ if (cancelled) return;
+
+ setRecordingOracleKey(key);
+
+ if (key.error) {
+ setPrepareError(key.error);
+ return;
+ }
+
+ try {
+ const prepared = await prepareManifest(form, key);
+ if (!cancelled) setPreparedManifest(prepared);
+ } catch (error) {
+ if (!cancelled) {
+ setPrepareError(
+ error instanceof Error
+ ? error.message
+ : 'Failed to prepare manifest',
+ );
+ }
+ }
+ };
+
+ loadReview();
+
+ return () => {
+ cancelled = true;
+ };
+ }, [activeStep, encryptionRequired, form]);
+
+ const handleLaunch = async () => {
+ if (!preparedManifest) return;
+ setLaunchModalOpen(true);
+ await escrow.launchEscrow({
+ chainId: form.chainId,
+ fundToken: form.fundToken,
+ fundAmount: form.fundAmount,
+ preparedManifest,
+ });
+ };
+
+ const handleCloseLaunchModal = () => {
+ setLaunchModalOpen(false);
+ navigate('/');
+ };
+
+ useEffect(() => {
+ if (!prepareError) return;
+
+ setToast({
+ open: true,
+ severity: 'error',
+ message: prepareError,
+ });
+ }, [prepareError]);
+
+ useEffect(() => {
+ if (!escrow.error) return;
+
+ setToast({
+ open: true,
+ severity: 'error',
+ message: escrow.error.message,
+ });
+ }, [escrow.error]);
+
+ return (
+
+
+
+
+ Create campaign
+
+
+ Complete each step, then review the final manifest before launch.
+
+
+
+
+
+ {steps.map((label) => (
+
+ {label}
+
+ ))}
+
+
+ {activeStep === 0 && (
+
+ )}
+ {activeStep === 1 && (
+
+ )}
+ {activeStep === 2 && (
+
+ )}
+ {activeStep === 3 &&
+ (form.requestType ===
+ CampaignRequestType.SOCIAL_MEDIA_PROMOTION ? (
+
+ ) : (
+
+ ))}
+ {activeStep === 4 && (
+ switchChain({ chainId: form.chainId })}
+ />
+ )}
+
+
+
+ {activeStep < 4 && (
+
+ )}
+ {activeStep === 4 && (
+
+ )}
+
+
+
+ setToast((current) => ({ ...current, open: false }))}
+ anchorOrigin={{ vertical: 'top', horizontal: 'center' }}
+ >
+ setToast((current) => ({ ...current, open: false }))}
+ sx={{ width: '100%' }}
+ >
+ {toast.message}
+
+
+
+
+
+ );
+};
+
+export default CreateCampaignPage;
diff --git a/campaign-launcher/client/src/pages/HomePage.tsx b/campaign-launcher/client/src/pages/HomePage.tsx
new file mode 100644
index 0000000..129da90
--- /dev/null
+++ b/campaign-launcher/client/src/pages/HomePage.tsx
@@ -0,0 +1,174 @@
+import { Box, Button, Grid, Paper, Stack, Typography } from '@mui/material';
+import { Link as RouterLink } from 'react-router-dom';
+import { useAccount } from 'wagmi';
+
+import Shell from '@/components/layout/Shell';
+
+type DashboardInfoCardProps = {
+ eyebrow: string;
+ title: string;
+ description: string;
+ cta?: boolean;
+ ctaDisabled?: boolean;
+};
+
+const DashboardInfoCard = ({
+ eyebrow,
+ title,
+ description,
+ cta,
+ ctaDisabled,
+}: DashboardInfoCardProps) => (
+
+
+
+ {eyebrow}
+
+
+
+ {title}
+
+ {description}
+
+ {cta && (
+
+ )}
+
+
+);
+
+type MarketingDescriptionCardProps = {
+ label: string;
+ title: string;
+ description: string;
+};
+
+const MarketingDescriptionCard = ({
+ label,
+ title,
+ description,
+}: MarketingDescriptionCardProps) => (
+
+
+
+ {label}
+
+
+ {title}
+
+ {description}
+
+
+);
+
+const HomePage = () => {
+ const { isConnected } = useAccount();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default HomePage;
diff --git a/campaign-launcher/client/src/providers/QueryClientProvider.tsx b/campaign-launcher/client/src/providers/QueryClientProvider.tsx
new file mode 100644
index 0000000..26e89dc
--- /dev/null
+++ b/campaign-launcher/client/src/providers/QueryClientProvider.tsx
@@ -0,0 +1,18 @@
+import type { FC, PropsWithChildren } from 'react';
+
+import { QueryClient, QueryClientProvider as TQueryClientProvider } from '@tanstack/react-query';
+
+const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ refetchOnWindowFocus: false,
+ retry: false,
+ },
+ },
+});
+
+export const QueryClientProvider: FC = ({ children }) => {
+ return (
+ {children}
+ );
+};
diff --git a/campaign-launcher/client/src/providers/WagmiProvider.tsx b/campaign-launcher/client/src/providers/WagmiProvider.tsx
new file mode 100644
index 0000000..61a55a0
--- /dev/null
+++ b/campaign-launcher/client/src/providers/WagmiProvider.tsx
@@ -0,0 +1,51 @@
+import type { FC, PropsWithChildren } from 'react';
+
+import { AppKitProvider } from '@reown/appkit/react';
+import type { ConnectMethod } from '@reown/appkit-controllers';
+import { WagmiProvider as WWagmiProvider } from 'wagmi';
+
+import { appKitNetworks, wagmiAdapter, wagmiConfig } from './wagmiConfig';
+
+const projectId = import.meta.env.VITE_APP_WALLETCONNECT_PROJECT_ID || '';
+const termsUrl = import.meta.env.VITE_APP_TERMS_URL;
+const privacyUrl = import.meta.env.VITE_APP_PRIVACY_URL;
+
+const appKitConfig = {
+ adapters: [wagmiAdapter],
+ networks: appKitNetworks,
+ projectId,
+ metadata: {
+ name: 'Marketing',
+ description: 'Marketing Campaign Launcher',
+ url: window.location.origin,
+ icons: [],
+ },
+ termsConditionsUrl: termsUrl,
+ privacyPolicyUrl: privacyUrl,
+ features: {
+ email: false,
+ socials: false as const,
+ history: false,
+ swaps: false,
+ onramp: false,
+ send: false,
+ connectMethodsOrder: ['wallet'] as ConnectMethod[],
+ },
+};
+
+export const WagmiProvider: FC = ({ children }) => {
+ const initialState = {
+ chainId: appKitNetworks[0].id,
+ connections: new Map(),
+ current: null,
+ status: 'disconnected' as const,
+ };
+
+ return (
+
+
+ {children}
+
+
+ );
+};
diff --git a/campaign-launcher/client/src/providers/wagmiConfig.ts b/campaign-launcher/client/src/providers/wagmiConfig.ts
new file mode 100644
index 0000000..0e6faa8
--- /dev/null
+++ b/campaign-launcher/client/src/providers/wagmiConfig.ts
@@ -0,0 +1,27 @@
+import { WagmiAdapter } from '@reown/appkit-adapter-wagmi';
+import type { AppKitNetwork } from '@reown/appkit/networks';
+import { http } from 'wagmi';
+
+import { getSupportedChains } from '@/constants/chains';
+
+const projectId = import.meta.env.VITE_APP_WALLETCONNECT_PROJECT_ID || '';
+
+export const supportedChains = getSupportedChains();
+export const appKitNetworks = supportedChains as unknown as [
+ AppKitNetwork,
+ ...AppKitNetwork[],
+];
+
+export const wagmiAdapter = new WagmiAdapter({
+ networks: appKitNetworks,
+ projectId,
+ syncConnectedChain: false,
+ transports: Object.fromEntries(
+ supportedChains.map((chain) => [
+ chain.id,
+ http(chain.rpcUrls.default.http[0]),
+ ])
+ ),
+});
+
+export const wagmiConfig = wagmiAdapter.wagmiConfig;
diff --git a/campaign-launcher/client/src/theme.ts b/campaign-launcher/client/src/theme.ts
new file mode 100644
index 0000000..e2e674b
--- /dev/null
+++ b/campaign-launcher/client/src/theme.ts
@@ -0,0 +1,128 @@
+import { createTheme } from '@mui/material/styles';
+
+const theme = createTheme({
+ palette: {
+ primary: {
+ main: '#b9a6ff',
+ dark: '#2a214a',
+ },
+ secondary: {
+ main: '#ff2d7a',
+ },
+ background: {
+ default: '#0c032c',
+ paper: '#251d47',
+ },
+ text: {
+ primary: '#ffffff',
+ secondary: '#a29dca',
+ },
+ error: {
+ main: '#ff2d7a',
+ },
+ warning: {
+ main: '#b56600',
+ },
+ success: {
+ main: '#0e976e',
+ },
+ },
+ typography: {
+ fontFamily: 'Inter, Arial, sans-serif',
+ h4: {
+ fontSize: '32px',
+ fontWeight: 700,
+ lineHeight: 1.2,
+ },
+ h5: {
+ fontSize: '22px',
+ fontWeight: 700,
+ },
+ h6: {
+ fontSize: '17px',
+ fontWeight: 700,
+ },
+ body1: {
+ fontSize: '15px',
+ lineHeight: '24px',
+ },
+ body2: {
+ fontSize: '14px',
+ lineHeight: '22px',
+ },
+ },
+ components: {
+ MuiButton: {
+ styleOverrides: {
+ root: {
+ borderRadius: '8px',
+ textTransform: 'none',
+ fontWeight: 700,
+ },
+ },
+ },
+ MuiCard: {
+ styleOverrides: {
+ root: {
+ borderRadius: '8px',
+ background: '#251d47',
+ border: '1px solid #433679',
+ boxShadow:
+ '0px 1px 4px rgba(0, 0, 0, 0.12), 0px 8px 24px rgba(0, 0, 0, 0.10)',
+ },
+ },
+ },
+ MuiPaper: {
+ styleOverrides: {
+ root: {
+ borderRadius: '8px',
+ backgroundImage: 'none',
+ },
+ },
+ },
+ MuiOutlinedInput: {
+ styleOverrides: {
+ root: {
+ borderRadius: '8px',
+ color: '#ffffff',
+ '& .MuiOutlinedInput-notchedOutline': {
+ borderColor: '#433679',
+ },
+ '&:hover .MuiOutlinedInput-notchedOutline': {
+ borderColor: '#6b5bb2',
+ },
+ '&.Mui-focused .MuiOutlinedInput-notchedOutline': {
+ borderColor: '#b9a6ff',
+ },
+ },
+ },
+ },
+ MuiInputLabel: {
+ styleOverrides: {
+ root: {
+ color: '#a29dca',
+ '&.Mui-focused': {
+ color: '#b9a6ff',
+ },
+ },
+ },
+ },
+ MuiSelect: {
+ styleOverrides: {
+ icon: {
+ color: '#b9a6ff',
+ },
+ },
+ },
+ MuiMenu: {
+ styleOverrides: {
+ paper: {
+ background: '#251d47',
+ color: '#ffffff',
+ },
+ },
+ },
+ },
+});
+
+export default theme;
diff --git a/campaign-launcher/client/src/types/index.ts b/campaign-launcher/client/src/types/index.ts
new file mode 100644
index 0000000..521cf83
--- /dev/null
+++ b/campaign-launcher/client/src/types/index.ts
@@ -0,0 +1,146 @@
+import type { ChainId } from '@human-protocol/sdk';
+
+export type EvmAddress = `0x${string}`;
+
+export enum CampaignRequestType {
+ SOCIAL_MEDIA_PROMOTION = 'social_media_promotion',
+ SOCIAL_MEDIA_ENGAGEMENT = 'social_media_engagement',
+}
+
+export enum SocialPlatform {
+ X = 'x',
+ LINKEDIN = 'linkedin',
+}
+
+export enum EscrowFundToken {
+ HMT = 'HMT',
+ USDT = 'USDT',
+ USDC = 'USDC',
+ USDT0 = 'USDT0',
+}
+
+export type AbuseProbability = 'low' | 'medium' | 'high';
+
+export type XApiCredentials = {
+ consumerKey: string;
+ consumerSecret: string;
+ accessToken: string;
+ accessTokenSecret: string;
+};
+
+export type BaseCampaignForm = {
+ chainId: ChainId;
+ requestType: CampaignRequestType;
+ platform: SocialPlatform;
+ campaignName: string;
+ campaignDescription: string;
+ submissionsRequired: string;
+ endDate: string;
+ fundToken: EscrowFundToken;
+ fundAmount: string;
+ qualifications: string;
+};
+
+export type PromotionRequirementsForm = {
+ requiredHashtags: string;
+ requiredKeywords: string;
+ requiredLink: string;
+ minLength: string;
+ requiresMedia: boolean;
+ mustBePublic: boolean;
+ minLiveDurationHours: string;
+ minFollowers: string;
+ minAccountAgeDays: string;
+ minLikes: string;
+ minReposts: string;
+ allowedAbuseProbability: AbuseProbability;
+};
+
+export type EngagementRequirementsForm = {
+ targetPostUrl: string;
+ checkLike: boolean;
+ checkRepost: boolean;
+ checkQuote: boolean;
+ checkComment: boolean;
+ xApiCredentials: XApiCredentials;
+};
+
+export type CampaignFormState = BaseCampaignForm & {
+ promotion: PromotionRequirementsForm;
+ engagement: EngagementRequirementsForm;
+};
+
+export type SocialMediaPromotionRequirements = {
+ requiredHashtags?: string[];
+ requiredKeywords?: string[];
+ requiredLink?: string;
+ minLength?: number;
+ requiresMedia?: boolean;
+ mustBePublic?: boolean;
+ minLiveDurationHours?: number;
+ minFollowers?: number;
+ minAccountAgeDays?: number;
+ minLikes?: number;
+ minReposts?: number;
+};
+
+export type SocialMediaEngagementRequirements = {
+ targetPostUrl: string;
+ checkLike?: boolean;
+ checkRepost?: boolean;
+ checkQuote?: boolean;
+ checkComment?: boolean;
+ xApiCredentials?: XApiCredentials | string;
+};
+
+export type ManifestCampaign = {
+ name: string;
+ description: string;
+};
+
+export type BaseManifest = {
+ requestType: CampaignRequestType;
+ submissionsRequired: number;
+ endDate: number;
+ platforms: SocialPlatform[];
+ campaign: ManifestCampaign;
+ qualifications?: string[];
+};
+
+export type SocialMediaPromotionManifest = BaseManifest & {
+ requestType: CampaignRequestType.SOCIAL_MEDIA_PROMOTION;
+ requirements: SocialMediaPromotionRequirements;
+ aiValidation: {
+ allowedAbuseProbability: AbuseProbability;
+ };
+};
+
+export type SocialMediaEngagementManifest = BaseManifest & {
+ requestType: CampaignRequestType.SOCIAL_MEDIA_ENGAGEMENT;
+ requirements: SocialMediaEngagementRequirements;
+};
+
+export type CampaignManifest =
+ | SocialMediaPromotionManifest
+ | SocialMediaEngagementManifest;
+
+export type ManifestMode = 'plain' | 'encrypted_credentials';
+
+export type PreparedManifest = {
+ manifest: CampaignManifest;
+ manifestString: string;
+ manifestHash: string;
+ mode: ManifestMode;
+ encryptionRequired: boolean;
+};
+
+export type RecordingOracleKeyState = {
+ isLoading: boolean;
+ error?: string;
+ publicKey: string;
+};
+
+export type EscrowResult = {
+ escrowAddress: string;
+ transactionManifestHash: string;
+};
diff --git a/campaign-launcher/client/src/utils/manifest.ts b/campaign-launcher/client/src/utils/manifest.ts
new file mode 100644
index 0000000..74362b2
--- /dev/null
+++ b/campaign-launcher/client/src/utils/manifest.ts
@@ -0,0 +1,228 @@
+import { EncryptionUtils, KVStoreUtils } from '@human-protocol/sdk';
+import type { ChainId } from '@human-protocol/sdk';
+
+import { ORACLE_ADDRESSES } from '@/constants';
+import {
+ CampaignRequestType,
+ SocialPlatform,
+ type CampaignFormState,
+ type CampaignManifest,
+ type PreparedManifest,
+ type RecordingOracleKeyState,
+ type SocialMediaEngagementRequirements,
+ type SocialMediaPromotionRequirements,
+} from '@/types';
+
+const splitList = (value: string): string[] | undefined => {
+ const items = value
+ .split(',')
+ .map((item) => item.trim())
+ .filter(Boolean);
+
+ return items.length ? items : undefined;
+};
+
+const optionalNumber = (value: string): number | undefined => {
+ if (!value.trim()) return undefined;
+ const parsed = Number(value);
+ return Number.isFinite(parsed) ? parsed : undefined;
+};
+
+const normalizeDateToTimestamp = (value: string): number => {
+ return new Date(value).getTime();
+};
+
+export const requiresEncryption = (form: CampaignFormState): boolean => {
+ return (
+ form.requestType === CampaignRequestType.SOCIAL_MEDIA_ENGAGEMENT &&
+ form.platform === SocialPlatform.X &&
+ form.engagement.checkLike
+ );
+};
+
+const getXApiCredentials = (form: CampaignFormState) => ({
+ consumerKey: form.engagement.xApiCredentials.consumerKey.trim(),
+ consumerSecret: form.engagement.xApiCredentials.consumerSecret.trim(),
+ accessToken: form.engagement.xApiCredentials.accessToken.trim(),
+ accessTokenSecret: form.engagement.xApiCredentials.accessTokenSecret.trim(),
+});
+
+export const buildManifest = (
+ form: CampaignFormState,
+ encryptedXApiCredentials?: string,
+): CampaignManifest => {
+ const qualifications = splitList(form.qualifications);
+ const baseManifest = {
+ requestType: form.requestType,
+ submissionsRequired: Number(form.submissionsRequired),
+ endDate: normalizeDateToTimestamp(form.endDate),
+ platforms: [form.platform],
+ campaign: {
+ name: form.campaignName.trim(),
+ description: form.campaignDescription.trim(),
+ },
+ ...(qualifications && { qualifications }),
+ };
+
+ if (form.requestType === CampaignRequestType.SOCIAL_MEDIA_PROMOTION) {
+ const requirements: SocialMediaPromotionRequirements = {
+ ...(splitList(form.promotion.requiredHashtags) && {
+ requiredHashtags: splitList(form.promotion.requiredHashtags),
+ }),
+ ...(splitList(form.promotion.requiredKeywords) && {
+ requiredKeywords: splitList(form.promotion.requiredKeywords),
+ }),
+ ...(form.promotion.requiredLink.trim() && {
+ requiredLink: form.promotion.requiredLink.trim(),
+ }),
+ ...(optionalNumber(form.promotion.minLength) !== undefined && {
+ minLength: optionalNumber(form.promotion.minLength),
+ }),
+ requiresMedia: form.promotion.requiresMedia,
+ mustBePublic: form.promotion.mustBePublic,
+ ...(optionalNumber(form.promotion.minLiveDurationHours) !== undefined && {
+ minLiveDurationHours: optionalNumber(
+ form.promotion.minLiveDurationHours,
+ ),
+ }),
+ ...(optionalNumber(form.promotion.minFollowers) !== undefined && {
+ minFollowers: optionalNumber(form.promotion.minFollowers),
+ }),
+ ...(optionalNumber(form.promotion.minAccountAgeDays) !== undefined && {
+ minAccountAgeDays: optionalNumber(form.promotion.minAccountAgeDays),
+ }),
+ ...(optionalNumber(form.promotion.minLikes) !== undefined && {
+ minLikes: optionalNumber(form.promotion.minLikes),
+ }),
+ ...(optionalNumber(form.promotion.minReposts) !== undefined && {
+ minReposts: optionalNumber(form.promotion.minReposts),
+ }),
+ };
+
+ return {
+ ...baseManifest,
+ requestType: CampaignRequestType.SOCIAL_MEDIA_PROMOTION,
+ requirements,
+ aiValidation: {
+ allowedAbuseProbability: form.promotion.allowedAbuseProbability,
+ },
+ };
+ }
+
+ const requirements: SocialMediaEngagementRequirements = {
+ targetPostUrl: form.engagement.targetPostUrl.trim(),
+ checkLike: form.engagement.checkLike,
+ checkRepost:
+ form.platform === SocialPlatform.X && form.engagement.checkRepost,
+ checkQuote:
+ form.platform === SocialPlatform.X && form.engagement.checkQuote,
+ checkComment: form.engagement.checkComment,
+ ...(requiresEncryption(form) && {
+ xApiCredentials: encryptedXApiCredentials ?? getXApiCredentials(form),
+ }),
+ };
+
+ return {
+ ...baseManifest,
+ requestType: CampaignRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements,
+ };
+};
+
+export const calculateHash = async (content: string): Promise => {
+ const data = new TextEncoder().encode(content);
+ const hashBuffer = await crypto.subtle.digest('SHA-1', data);
+ return Array.from(new Uint8Array(hashBuffer))
+ .map((byte) => byte.toString(16).padStart(2, '0'))
+ .join('');
+};
+
+export const getRecordingOraclePublicKey = async (
+ chainId: ChainId,
+ encryptionRequired: boolean,
+): Promise => {
+ if (!encryptionRequired) {
+ return {
+ isLoading: false,
+ publicKey: '',
+ };
+ }
+
+ try {
+ const publicKey = await KVStoreUtils.getPublicKey(
+ chainId,
+ ORACLE_ADDRESSES.recordingOracle,
+ );
+
+ return {
+ isLoading: false,
+ publicKey,
+ };
+ } catch (error) {
+ return {
+ isLoading: false,
+ publicKey: '',
+ error: getPublicKeyErrorMessage(error),
+ };
+ }
+};
+
+const getPublicKeyErrorMessage = (error: unknown): string => {
+ const message =
+ error instanceof Error
+ ? error.message
+ : 'Failed to fetch public keys from KVStore';
+
+ if (message.includes('No URL found for the given address and key')) {
+ return 'Recording oracle public key not found in KVStore.';
+ }
+
+ return message;
+};
+
+export const prepareManifest = async (
+ form: CampaignFormState,
+ recordingOracleKey: RecordingOracleKeyState,
+): Promise => {
+ const encryptionRequired = requiresEncryption(form);
+ const manifest = buildManifest(form);
+ const plainManifestString = JSON.stringify(manifest);
+
+ if (!encryptionRequired) {
+ return {
+ manifest,
+ manifestString: plainManifestString,
+ manifestHash: await calculateHash(plainManifestString),
+ mode: 'plain',
+ encryptionRequired,
+ };
+ }
+
+ if (!recordingOracleKey.publicKey) {
+ throw new Error('Recording oracle public key is missing in KVStore.');
+ }
+
+ const encryptedCredentials = await EncryptionUtils.encrypt(
+ JSON.stringify(getXApiCredentials(form)),
+ [recordingOracleKey.publicKey],
+ );
+ const manifestWithEncryptedCredentials = buildManifest(
+ form,
+ encryptedCredentials,
+ );
+ const manifestString = JSON.stringify(manifestWithEncryptedCredentials);
+
+ return {
+ manifest: manifestWithEncryptedCredentials,
+ manifestString,
+ manifestHash: await calculateHash(manifestString),
+ mode: 'encrypted_credentials',
+ encryptionRequired,
+ };
+};
+
+export const shortKeyPreview = (publicKey: string): string => {
+ if (!publicKey) return 'Missing';
+ const compact = publicKey.replace(/\s+/g, ' ').trim();
+ return compact.length > 120 ? `${compact.slice(0, 120)}...` : compact;
+};
diff --git a/campaign-launcher/client/src/utils/validation.ts b/campaign-launcher/client/src/utils/validation.ts
new file mode 100644
index 0000000..8dc7172
--- /dev/null
+++ b/campaign-launcher/client/src/utils/validation.ts
@@ -0,0 +1,93 @@
+import {
+ CampaignRequestType,
+ SocialPlatform,
+ type CampaignFormState,
+} from '@/types';
+import { getFundingTokenConfig } from '@/constants/fundingTokens';
+import { requiresEncryption } from './manifest';
+
+const isPositiveNumber = (value: string): boolean => Number(value) > 0;
+
+const isFutureDate = (value: string): boolean => {
+ const timestamp = new Date(value).getTime();
+ return Number.isFinite(timestamp) && timestamp > Date.now();
+};
+
+export const validateForm = (form: CampaignFormState): string[] => {
+ const errors: string[] = [];
+
+ if (!form.campaignName.trim()) errors.push('Campaign name is required');
+ if (!form.campaignDescription.trim()) {
+ errors.push('Campaign description is required');
+ }
+ if (!isPositiveNumber(form.submissionsRequired)) {
+ errors.push('Submissions required must be greater than zero');
+ }
+ if (!isFutureDate(form.endDate)) errors.push('End date must be in the future');
+ if (!getFundingTokenConfig(form.chainId, form.fundToken)) {
+ errors.push('Selected currency is not configured for this network');
+ }
+ if (!isPositiveNumber(form.fundAmount)) {
+ errors.push('Fund amount must be greater than zero');
+ }
+
+ if (form.requestType === CampaignRequestType.SOCIAL_MEDIA_PROMOTION) {
+ const hasRequirement =
+ form.promotion.requiredHashtags.trim() ||
+ form.promotion.requiredKeywords.trim() ||
+ form.promotion.requiredLink.trim() ||
+ form.promotion.minLength.trim() ||
+ form.promotion.requiresMedia ||
+ form.promotion.mustBePublic;
+
+ if (!hasRequirement) {
+ errors.push('At least one promotion requirement is required');
+ }
+ }
+
+ if (form.requestType === CampaignRequestType.SOCIAL_MEDIA_ENGAGEMENT) {
+ if (!form.engagement.targetPostUrl.trim()) {
+ errors.push('Target post URL is required');
+ }
+
+ const hasEngagementCheck =
+ form.engagement.checkLike ||
+ form.engagement.checkRepost ||
+ form.engagement.checkQuote ||
+ form.engagement.checkComment;
+
+ if (!hasEngagementCheck) {
+ errors.push('At least one engagement check is required');
+ }
+
+ if (form.platform === SocialPlatform.LINKEDIN) {
+ if (form.engagement.checkRepost || form.engagement.checkQuote) {
+ errors.push('LinkedIn supports only like and comment checks');
+ }
+ }
+
+ if (
+ form.platform === SocialPlatform.X &&
+ form.engagement.checkComment &&
+ !form.engagement.checkLike &&
+ !form.engagement.checkRepost &&
+ !form.engagement.checkQuote
+ ) {
+ errors.push('X comments must be requested with like, repost, or quote');
+ }
+
+ if (requiresEncryption(form)) {
+ const credentials = form.engagement.xApiCredentials;
+ if (
+ !credentials.consumerKey.trim() ||
+ !credentials.consumerSecret.trim() ||
+ !credentials.accessToken.trim() ||
+ !credentials.accessTokenSecret.trim()
+ ) {
+ errors.push('X API credentials are required when checking likes');
+ }
+ }
+ }
+
+ return errors;
+};
diff --git a/campaign-launcher/client/src/utils/wallet.ts b/campaign-launcher/client/src/utils/wallet.ts
new file mode 100644
index 0000000..eaba24c
--- /dev/null
+++ b/campaign-launcher/client/src/utils/wallet.ts
@@ -0,0 +1,14 @@
+import { BrowserProvider, type JsonRpcSigner } from 'ethers';
+import type { WalletClient } from 'viem';
+
+export const walletClientToSigner = async (
+ walletClient: WalletClient
+): Promise => {
+ const { account, chain, transport } = walletClient;
+ const provider = new BrowserProvider(transport, {
+ chainId: chain.id,
+ name: chain.name,
+ });
+
+ return provider.getSigner(account.address);
+};
diff --git a/campaign-launcher/client/src/vite-env.d.ts b/campaign-launcher/client/src/vite-env.d.ts
new file mode 100644
index 0000000..5f6eedb
--- /dev/null
+++ b/campaign-launcher/client/src/vite-env.d.ts
@@ -0,0 +1,21 @@
+///
+
+interface ImportMetaEnv {
+ readonly VITE_APP_WALLETCONNECT_PROJECT_ID?: string;
+ readonly VITE_APP_TERMS_URL?: string;
+ readonly VITE_APP_PRIVACY_URL?: string;
+ readonly VITE_APP_DOCS_URL?: string;
+ readonly VITE_APP_STAKING_DASHBOARD_URL?: string;
+ readonly VITE_APP_ENVIRONMENT?: string;
+ readonly VITE_APP_SUPPORTED_CHAINS?: string;
+ readonly VITE_APP_EXCHANGE_ORACLE_ADDRESS?: string;
+ readonly VITE_APP_RECORDING_ORACLE_ADDRESS?: string;
+ readonly VITE_APP_REPUTATION_ORACLE_ADDRESS?: string;
+ readonly VITE_FOOTER_LINK_GITHUB?: string;
+ readonly VITE_FOOTER_LINK_TELEGRAM?: string;
+ readonly VITE_FOOTER_LINK_X?: string;
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/campaign-launcher/client/tsconfig.json b/campaign-launcher/client/tsconfig.json
new file mode 100644
index 0000000..82de0ee
--- /dev/null
+++ b/campaign-launcher/client/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "target": "ES2022",
+ "lib": ["DOM", "DOM.Iterable", "ES2022"],
+ "allowJs": false,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "resolveJsonModule": true,
+ "types": ["node", "vite/client"]
+ },
+ "include": ["src"]
+}
diff --git a/campaign-launcher/client/vite.config.ts b/campaign-launcher/client/vite.config.ts
new file mode 100644
index 0000000..dbd330d
--- /dev/null
+++ b/campaign-launcher/client/vite.config.ts
@@ -0,0 +1,31 @@
+///
+
+import path from 'path';
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+import { nodePolyfills } from 'vite-plugin-node-polyfills';
+
+export default defineConfig({
+ plugins: [
+ react(),
+ nodePolyfills({
+ protocolImports: true,
+ }),
+ ],
+ resolve: {
+ alias: [{ find: '@', replacement: path.resolve(__dirname, 'src') }],
+ },
+ build: {
+ commonjsOptions: {
+ include: [/node_modules/],
+ },
+ rollupOptions: {
+ output: {
+ inlineDynamicImports: true,
+ },
+ },
+ },
+ server: {
+ port: 3004,
+ },
+});
diff --git a/campaign-launcher/client/yarn.lock b/campaign-launcher/client/yarn.lock
new file mode 100644
index 0000000..40eb67a
--- /dev/null
+++ b/campaign-launcher/client/yarn.lock
@@ -0,0 +1,8426 @@
+# This file is generated by running "yarn install" inside your project.
+# Manual changes might be lost - proceed with caution!
+
+__metadata:
+ version: 8
+ cacheKey: 10c0
+
+"@adraffy/ens-normalize@npm:1.10.1":
+ version: 1.10.1
+ resolution: "@adraffy/ens-normalize@npm:1.10.1"
+ checksum: 10c0/fdd647604e8fac6204921888aaf5a6bc65eabf0d2921bc5f93b64d01f4bc33ead167c1445f7de05468d05cd92ac31b74c68d2be840c62b79d73693308f885c06
+ languageName: node
+ linkType: hard
+
+"@adraffy/ens-normalize@npm:^1.10.1, @adraffy/ens-normalize@npm:^1.11.0":
+ version: 1.11.1
+ resolution: "@adraffy/ens-normalize@npm:1.11.1"
+ checksum: 10c0/b364e2a57131db278ebf2f22d1a1ac6d8aea95c49dd2bbbc1825870b38aa91fd8816aba580a1f84edc50a45eb6389213dacfd1889f32893afc8549a82d304767
+ languageName: node
+ linkType: hard
+
+"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/code-frame@npm:7.29.7"
+ dependencies:
+ "@babel/helper-validator-identifier": "npm:^7.29.7"
+ js-tokens: "npm:^4.0.0"
+ picocolors: "npm:^1.1.1"
+ checksum: 10c0/169fc2080169a40c1760155eaaaf739bcb882df0bec76a83adbda5493645bc17270a3434b8848c494b1933e96fe1d147370001e3cda09a39f43ae30f08ef2069
+ languageName: node
+ linkType: hard
+
+"@babel/compat-data@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/compat-data@npm:7.29.7"
+ checksum: 10c0/47913f05e08a45a1c9df38c02b4b49e391005085b489432647a1abe112e5d9c75e3be8ea5972b7f6da4ec5d1339922ceb9ea02b8a25d4ed1cb8636e5261f344e
+ languageName: node
+ linkType: hard
+
+"@babel/core@npm:^7.28.0":
+ version: 7.29.7
+ resolution: "@babel/core@npm:7.29.7"
+ dependencies:
+ "@babel/code-frame": "npm:^7.29.7"
+ "@babel/generator": "npm:^7.29.7"
+ "@babel/helper-compilation-targets": "npm:^7.29.7"
+ "@babel/helper-module-transforms": "npm:^7.29.7"
+ "@babel/helpers": "npm:^7.29.7"
+ "@babel/parser": "npm:^7.29.7"
+ "@babel/template": "npm:^7.29.7"
+ "@babel/traverse": "npm:^7.29.7"
+ "@babel/types": "npm:^7.29.7"
+ "@jridgewell/remapping": "npm:^2.3.5"
+ convert-source-map: "npm:^2.0.0"
+ debug: "npm:^4.1.0"
+ gensync: "npm:^1.0.0-beta.2"
+ json5: "npm:^2.2.3"
+ semver: "npm:^6.3.1"
+ checksum: 10c0/112fb09c24de7a1de64d1de2c31fe65c4e6af4cb2fb6e6d99ea5373e6fc51e75b88581c0efae4c4c68f119a02a988c7106e95011a41530a2fb8ed793c7eaa07b
+ languageName: node
+ linkType: hard
+
+"@babel/generator@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/generator@npm:7.29.7"
+ dependencies:
+ "@babel/parser": "npm:^7.29.7"
+ "@babel/types": "npm:^7.29.7"
+ "@jridgewell/gen-mapping": "npm:^0.3.12"
+ "@jridgewell/trace-mapping": "npm:^0.3.28"
+ jsesc: "npm:^3.0.2"
+ checksum: 10c0/9bf72b01b5bd0ea5b1288a0e37dbd360bff2f2b1ce73342c0d40fb3db2ec3dc004ada5ffa925c5e12939a416eed59e600d562b8ecd938ce0d27dfd0eb6c6c2b7
+ languageName: node
+ linkType: hard
+
+"@babel/helper-compilation-targets@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helper-compilation-targets@npm:7.29.7"
+ dependencies:
+ "@babel/compat-data": "npm:^7.29.7"
+ "@babel/helper-validator-option": "npm:^7.29.7"
+ browserslist: "npm:^4.24.0"
+ lru-cache: "npm:^5.1.1"
+ semver: "npm:^6.3.1"
+ checksum: 10c0/4c15fd4c69a0a7047799a28a88460c19cede0a0ee8af994ea169114986f4af48b92c7393a4a3fee0456c11a656eece3448a6ed06354453d6c27cccf17195453b
+ languageName: node
+ linkType: hard
+
+"@babel/helper-globals@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helper-globals@npm:7.29.7"
+ checksum: 10c0/f38417c40b1129a1b2b519ca961b9040c8827d1444fd74068702286b91b77089431dc76b6b9d5c1496e5da2a4f3ad329c6946e688ba3fa0d1d0b3d2b4f34f36a
+ languageName: node
+ linkType: hard
+
+"@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helper-module-imports@npm:7.29.7"
+ dependencies:
+ "@babel/traverse": "npm:^7.29.7"
+ "@babel/types": "npm:^7.29.7"
+ checksum: 10c0/6adf60d97356027413342a092f818d9678c4f5caff716a33e3284b5ae14e47a9e88059d421dde4ee4894691260039a12602c0e7becadc175602194b40dfa345d
+ languageName: node
+ linkType: hard
+
+"@babel/helper-module-transforms@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helper-module-transforms@npm:7.29.7"
+ dependencies:
+ "@babel/helper-module-imports": "npm:^7.29.7"
+ "@babel/helper-validator-identifier": "npm:^7.29.7"
+ "@babel/traverse": "npm:^7.29.7"
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 10c0/ee5a2172c24a42be696836f4b0d947489c9729d8adf5821885cf77d1ad5333e3c447368e9a71f67df1099570490553dccf9f888ef0a92a48aa63cb086bd8c7e1
+ languageName: node
+ linkType: hard
+
+"@babel/helper-plugin-utils@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helper-plugin-utils@npm:7.29.7"
+ checksum: 10c0/380477a06133274a2759f9355929cb60a95e8b8fee624a1ae1fa349e1d1645b89daca456f72833f6d1062bffa12ee4271c5bf0cc5a61c0166cdc24c7591e2408
+ languageName: node
+ linkType: hard
+
+"@babel/helper-string-parser@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helper-string-parser@npm:7.29.7"
+ checksum: 10c0/194bc0f1716e396d5ffde56ad6119745fb9557662c98611590e5e454906783a4ccb21ce93056b8eb69a4909044834e45d96e50ac695bbe9e3221648fe033c06c
+ languageName: node
+ linkType: hard
+
+"@babel/helper-validator-identifier@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helper-validator-identifier@npm:7.29.7"
+ checksum: 10c0/4795354e7ae0dcafa72de1cd04ec51252dc1498517170beaf019e03effc5b7bf13c6b21a3949a77e07b8125be7f106ed1131350d8ebd4566ae874094a726d62b
+ languageName: node
+ linkType: hard
+
+"@babel/helper-validator-option@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helper-validator-option@npm:7.29.7"
+ checksum: 10c0/d2a06c6d0ac40ba4a2f219fc2cab249c7a94bacdb2686273b7f9598571c908809b48468ff588915a346e6cc7296f60b581023d1d498b747fed06f779d335c2cc
+ languageName: node
+ linkType: hard
+
+"@babel/helpers@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/helpers@npm:7.29.7"
+ dependencies:
+ "@babel/template": "npm:^7.29.7"
+ "@babel/types": "npm:^7.29.7"
+ checksum: 10c0/218e8d10953647c9f44775f5a022b227a182674853b5ea8631889deb7e1a3e4bc870388aaecf59bb8bd92a87f9a96220ed3f70a35bffec6bcf9169ecb67891ac
+ languageName: node
+ linkType: hard
+
+"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/parser@npm:7.29.7"
+ dependencies:
+ "@babel/types": "npm:^7.29.7"
+ bin:
+ parser: ./bin/babel-parser.js
+ checksum: 10c0/65133038f80b54a714d6027cb77cee3f9a6b5c4c6842ce674301e13947cbcbfa8055e63acaf1b84c085d34226a14425b2c2b97b829e0e226d2e8f1299942a51d
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-react-jsx-self@npm:^7.27.1":
+ version: 7.29.7
+ resolution: "@babel/plugin-transform-react-jsx-self@npm:7.29.7"
+ dependencies:
+ "@babel/helper-plugin-utils": "npm:^7.29.7"
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 10c0/288995f0fd0d61ab740a315fb56c8255eb87dd4a4ac2ac7d0fdd4ce173c3878200141e80da2db0e598c7b2a71e74e604afdbb4c8e14ae6e0527ce0b6294c03da
+ languageName: node
+ linkType: hard
+
+"@babel/plugin-transform-react-jsx-source@npm:^7.27.1":
+ version: 7.29.7
+ resolution: "@babel/plugin-transform-react-jsx-source@npm:7.29.7"
+ dependencies:
+ "@babel/helper-plugin-utils": "npm:^7.29.7"
+ peerDependencies:
+ "@babel/core": ^7.0.0-0
+ checksum: 10c0/a121899631e6d99b9e1b276acf736dbb77948a31f8eeeae67b89c8a4ab0f05e51ba64544baa06c286a2b9944f227244e15aac464e2313d286d0511fe51e27975
+ languageName: node
+ linkType: hard
+
+"@babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.23.9, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.7":
+ version: 7.29.7
+ resolution: "@babel/runtime@npm:7.29.7"
+ checksum: 10c0/ca11572f7146b21e0bde6a9ed4bb6a89eafbee5f0944c7eb54d0d8a2dac962c33638a1d611e14faa71dfbb92b4b5f9236232208568a6b7d5c6f3f39ddb91771e
+ languageName: node
+ linkType: hard
+
+"@babel/template@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/template@npm:7.29.7"
+ dependencies:
+ "@babel/code-frame": "npm:^7.29.7"
+ "@babel/parser": "npm:^7.29.7"
+ "@babel/types": "npm:^7.29.7"
+ checksum: 10c0/8bb7f900dcab0e9e1c5ffbc33ca10e0d26b7b2e2ca804becb73ee771b9c4ed6e2908a4ae4a14c08560febb45d2b6b9a173955e42ad404d05f8b04840a14d9c58
+ languageName: node
+ linkType: hard
+
+"@babel/traverse@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/traverse@npm:7.29.7"
+ dependencies:
+ "@babel/code-frame": "npm:^7.29.7"
+ "@babel/generator": "npm:^7.29.7"
+ "@babel/helper-globals": "npm:^7.29.7"
+ "@babel/parser": "npm:^7.29.7"
+ "@babel/template": "npm:^7.29.7"
+ "@babel/types": "npm:^7.29.7"
+ debug: "npm:^4.3.1"
+ checksum: 10c0/e256a1fbdb956555b76f3c285b1e453f6bedec8b3afb61751d99d933efd11c7d79caf5ddf2493570058a9f7deaa1b48324380d7c1aa1443fd9508becbf56331a
+ languageName: node
+ linkType: hard
+
+"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.28.2, @babel/types@npm:^7.29.7":
+ version: 7.29.7
+ resolution: "@babel/types@npm:7.29.7"
+ dependencies:
+ "@babel/helper-string-parser": "npm:^7.29.7"
+ "@babel/helper-validator-identifier": "npm:^7.29.7"
+ checksum: 10c0/b6623994c69717fa27294f5fa46d59140338e2d86c6c1c13085c84ef7d53086ee357fbf4fe9abe3dd3da75734dc77c4c0df2f90fb29e667558bb3b3fb705e88f
+ languageName: node
+ linkType: hard
+
+"@base-org/account@npm:2.4.0":
+ version: 2.4.0
+ resolution: "@base-org/account@npm:2.4.0"
+ dependencies:
+ "@coinbase/cdp-sdk": "npm:^1.0.0"
+ "@noble/hashes": "npm:1.4.0"
+ clsx: "npm:1.2.1"
+ eventemitter3: "npm:5.0.1"
+ idb-keyval: "npm:6.2.1"
+ ox: "npm:0.6.9"
+ preact: "npm:10.24.2"
+ viem: "npm:^2.31.7"
+ zustand: "npm:5.0.3"
+ checksum: 10c0/570a3134b81389f13a24c64e9b30b8e786dd34dfcfd59d56717352dfd892d484d49f7c57120d936f14f2e438ea11a2af543d985c90ceb3934c0e5b3deebab1f7
+ languageName: node
+ linkType: hard
+
+"@coinbase/cdp-sdk@npm:^1.0.0":
+ version: 1.51.0
+ resolution: "@coinbase/cdp-sdk@npm:1.51.0"
+ dependencies:
+ "@solana-program/system": "npm:^0.10.0"
+ "@solana-program/token": "npm:^0.9.0"
+ "@solana/kit": "npm:^5.5.1"
+ abitype: "npm:1.0.6"
+ axios: "npm:1.16.0"
+ axios-retry: "npm:^4.5.0"
+ bs58: "npm:^6.0.0"
+ jose: "npm:^6.2.0"
+ md5: "npm:^2.3.0"
+ uncrypto: "npm:^0.1.3"
+ viem: "npm:^2.47.0"
+ zod: "npm:^3.25.76"
+ checksum: 10c0/26bfd9e0ffb420a106d6c47b7e872174dcdee36ffcbfa18be18fb2318b470ac16289ba70fd2abc1370efce93707170e1be6491b941fa19e4cfbdf6ad7f590b9b
+ languageName: node
+ linkType: hard
+
+"@coinbase/wallet-sdk@npm:4.3.6":
+ version: 4.3.6
+ resolution: "@coinbase/wallet-sdk@npm:4.3.6"
+ dependencies:
+ "@noble/hashes": "npm:1.4.0"
+ clsx: "npm:1.2.1"
+ eventemitter3: "npm:5.0.1"
+ idb-keyval: "npm:6.2.1"
+ ox: "npm:0.6.9"
+ preact: "npm:10.24.2"
+ viem: "npm:^2.27.2"
+ zustand: "npm:5.0.3"
+ checksum: 10c0/ad5c7b124217ef191950c8c485d709d806f4a17eb039b1b8f325510cbc751b48c1e68acf8b44c3b24bb35682e44a6e3140eaba2d623166bf5a4e9dd4c4aef2e1
+ languageName: node
+ linkType: hard
+
+"@emnapi/core@npm:1.10.0":
+ version: 1.10.0
+ resolution: "@emnapi/core@npm:1.10.0"
+ dependencies:
+ "@emnapi/wasi-threads": "npm:1.2.1"
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/f51d08227857b60632de7714d708124f0e100a1462dde6df8221760939aa3204a73193830371830fac0716f3ccd2129f2cac1b17cd7d7958bc4da9018a296edb
+ languageName: node
+ linkType: hard
+
+"@emnapi/runtime@npm:1.10.0":
+ version: 1.10.0
+ resolution: "@emnapi/runtime@npm:1.10.0"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/953f14991d1aefb92ee6f8eb27dea725e484791a53a0cb5f47d9e0087b9a2c929ff2e92adf95af15d6ad456db6300c6b761ebf72b50a875b874a83520b3ba093
+ languageName: node
+ linkType: hard
+
+"@emnapi/wasi-threads@npm:1.2.1":
+ version: 1.2.1
+ resolution: "@emnapi/wasi-threads@npm:1.2.1"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/32fcfa81ab396533b2ec1f4082b1ff779a05d9c836bbbd3f4398405b0e6814c0d9503b7993130e37bc6941dbc1ded49f55e9700ae9ca4e803bab2b5bc5deb331
+ languageName: node
+ linkType: hard
+
+"@emotion/babel-plugin@npm:^11.13.5":
+ version: 11.13.5
+ resolution: "@emotion/babel-plugin@npm:11.13.5"
+ dependencies:
+ "@babel/helper-module-imports": "npm:^7.16.7"
+ "@babel/runtime": "npm:^7.18.3"
+ "@emotion/hash": "npm:^0.9.2"
+ "@emotion/memoize": "npm:^0.9.0"
+ "@emotion/serialize": "npm:^1.3.3"
+ babel-plugin-macros: "npm:^3.1.0"
+ convert-source-map: "npm:^1.5.0"
+ escape-string-regexp: "npm:^4.0.0"
+ find-root: "npm:^1.1.0"
+ source-map: "npm:^0.5.7"
+ stylis: "npm:4.2.0"
+ checksum: 10c0/8ccbfec7defd0e513cb8a1568fa179eac1e20c35fda18aed767f6c59ea7314363ebf2de3e9d2df66c8ad78928dc3dceeded84e6fa8059087cae5c280090aeeeb
+ languageName: node
+ linkType: hard
+
+"@emotion/cache@npm:^11.13.5, @emotion/cache@npm:^11.14.0":
+ version: 11.14.0
+ resolution: "@emotion/cache@npm:11.14.0"
+ dependencies:
+ "@emotion/memoize": "npm:^0.9.0"
+ "@emotion/sheet": "npm:^1.4.0"
+ "@emotion/utils": "npm:^1.4.2"
+ "@emotion/weak-memoize": "npm:^0.4.0"
+ stylis: "npm:4.2.0"
+ checksum: 10c0/3fa3e7a431ab6f8a47c67132a00ac8358f428c1b6c8421d4b20de9df7c18e95eec04a5a6ff5a68908f98d3280044f247b4965ac63df8302d2c94dba718769724
+ languageName: node
+ linkType: hard
+
+"@emotion/hash@npm:^0.9.2":
+ version: 0.9.2
+ resolution: "@emotion/hash@npm:0.9.2"
+ checksum: 10c0/0dc254561a3cc0a06a10bbce7f6a997883fd240c8c1928b93713f803a2e9153a257a488537012efe89dbe1246f2abfe2add62cdb3471a13d67137fcb808e81c2
+ languageName: node
+ linkType: hard
+
+"@emotion/is-prop-valid@npm:^1.3.0":
+ version: 1.4.0
+ resolution: "@emotion/is-prop-valid@npm:1.4.0"
+ dependencies:
+ "@emotion/memoize": "npm:^0.9.0"
+ checksum: 10c0/5f857814ec7d8c7e727727346dfb001af6b1fb31d621a3ce9c3edf944a484d8b0d619546c30899ae3ade2f317c76390ba4394449728e9bf628312defc2c41ac3
+ languageName: node
+ linkType: hard
+
+"@emotion/memoize@npm:^0.9.0":
+ version: 0.9.0
+ resolution: "@emotion/memoize@npm:0.9.0"
+ checksum: 10c0/13f474a9201c7f88b543e6ea42f55c04fb2fdc05e6c5a3108aced2f7e7aa7eda7794c56bba02985a46d8aaa914fcdde238727a98341a96e2aec750d372dadd15
+ languageName: node
+ linkType: hard
+
+"@emotion/react@npm:^11.11.3":
+ version: 11.14.0
+ resolution: "@emotion/react@npm:11.14.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.18.3"
+ "@emotion/babel-plugin": "npm:^11.13.5"
+ "@emotion/cache": "npm:^11.14.0"
+ "@emotion/serialize": "npm:^1.3.3"
+ "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0"
+ "@emotion/utils": "npm:^1.4.2"
+ "@emotion/weak-memoize": "npm:^0.4.0"
+ hoist-non-react-statics: "npm:^3.3.1"
+ peerDependencies:
+ react: ">=16.8.0"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/d0864f571a9f99ec643420ef31fde09e2006d3943a6aba079980e4d5f6e9f9fecbcc54b8f617fe003c00092ff9d5241179149ffff2810cb05cf72b4620cfc031
+ languageName: node
+ linkType: hard
+
+"@emotion/serialize@npm:^1.3.3":
+ version: 1.3.3
+ resolution: "@emotion/serialize@npm:1.3.3"
+ dependencies:
+ "@emotion/hash": "npm:^0.9.2"
+ "@emotion/memoize": "npm:^0.9.0"
+ "@emotion/unitless": "npm:^0.10.0"
+ "@emotion/utils": "npm:^1.4.2"
+ csstype: "npm:^3.0.2"
+ checksum: 10c0/b28cb7de59de382021de2b26c0c94ebbfb16967a1b969a56fdb6408465a8993df243bfbd66430badaa6800e1834724e84895f5a6a9d97d0d224de3d77852acb4
+ languageName: node
+ linkType: hard
+
+"@emotion/sheet@npm:^1.4.0":
+ version: 1.4.0
+ resolution: "@emotion/sheet@npm:1.4.0"
+ checksum: 10c0/3ca72d1650a07d2fbb7e382761b130b4a887dcd04e6574b2d51ce578791240150d7072a9bcb4161933abbcd1e38b243a6fb4464a7fe991d700c17aa66bb5acc7
+ languageName: node
+ linkType: hard
+
+"@emotion/styled@npm:^11.11.0":
+ version: 11.14.1
+ resolution: "@emotion/styled@npm:11.14.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.18.3"
+ "@emotion/babel-plugin": "npm:^11.13.5"
+ "@emotion/is-prop-valid": "npm:^1.3.0"
+ "@emotion/serialize": "npm:^1.3.3"
+ "@emotion/use-insertion-effect-with-fallbacks": "npm:^1.2.0"
+ "@emotion/utils": "npm:^1.4.2"
+ peerDependencies:
+ "@emotion/react": ^11.0.0-rc.0
+ react: ">=16.8.0"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/2bbf8451df49c967e41fbcf8111a7f6dafe6757f0cc113f2f6e287206c45ac1d54dc8a95a483b7c0cee8614b8a8d08155bded6453d6721de1f8cc8d5b9216963
+ languageName: node
+ linkType: hard
+
+"@emotion/unitless@npm:^0.10.0":
+ version: 0.10.0
+ resolution: "@emotion/unitless@npm:0.10.0"
+ checksum: 10c0/150943192727b7650eb9a6851a98034ddb58a8b6958b37546080f794696141c3760966ac695ab9af97efe10178690987aee4791f9f0ad1ff76783cdca83c1d49
+ languageName: node
+ linkType: hard
+
+"@emotion/use-insertion-effect-with-fallbacks@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.2.0"
+ peerDependencies:
+ react: ">=16.8.0"
+ checksum: 10c0/074dbc92b96bdc09209871070076e3b0351b6b47efefa849a7d9c37ab142130767609ca1831da0055988974e3b895c1de7606e4c421fecaa27c3e56a2afd3b08
+ languageName: node
+ linkType: hard
+
+"@emotion/utils@npm:^1.4.2":
+ version: 1.4.2
+ resolution: "@emotion/utils@npm:1.4.2"
+ checksum: 10c0/7d0010bf60a2a8c1a033b6431469de4c80e47aeb8fd856a17c1d1f76bbc3a03161a34aeaa78803566e29681ca551e7bf9994b68e9c5f5c796159923e44f78d9a
+ languageName: node
+ linkType: hard
+
+"@emotion/weak-memoize@npm:^0.4.0":
+ version: 0.4.0
+ resolution: "@emotion/weak-memoize@npm:0.4.0"
+ checksum: 10c0/64376af11f1266042d03b3305c30b7502e6084868e33327e944b539091a472f089db307af69240f7188f8bc6b319276fd7b141a36613f1160d73d12a60f6ca1a
+ languageName: node
+ linkType: hard
+
+"@esbuild/aix-ppc64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/aix-ppc64@npm:0.25.12"
+ conditions: os=aix & cpu=ppc64
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/android-arm64@npm:0.25.12"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-arm@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/android-arm@npm:0.25.12"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@esbuild/android-x64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/android-x64@npm:0.25.12"
+ conditions: os=android & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/darwin-arm64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/darwin-arm64@npm:0.25.12"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/darwin-x64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/darwin-x64@npm:0.25.12"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/freebsd-arm64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/freebsd-arm64@npm:0.25.12"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/freebsd-x64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/freebsd-x64@npm:0.25.12"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-arm64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-arm64@npm:0.25.12"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-arm@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-arm@npm:0.25.12"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-ia32@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-ia32@npm:0.25.12"
+ conditions: os=linux & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-loong64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-loong64@npm:0.25.12"
+ conditions: os=linux & cpu=loong64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-mips64el@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-mips64el@npm:0.25.12"
+ conditions: os=linux & cpu=mips64el
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-ppc64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-ppc64@npm:0.25.12"
+ conditions: os=linux & cpu=ppc64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-riscv64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-riscv64@npm:0.25.12"
+ conditions: os=linux & cpu=riscv64
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-s390x@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-s390x@npm:0.25.12"
+ conditions: os=linux & cpu=s390x
+ languageName: node
+ linkType: hard
+
+"@esbuild/linux-x64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/linux-x64@npm:0.25.12"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/netbsd-arm64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/netbsd-arm64@npm:0.25.12"
+ conditions: os=netbsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/netbsd-x64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/netbsd-x64@npm:0.25.12"
+ conditions: os=netbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-arm64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/openbsd-arm64@npm:0.25.12"
+ conditions: os=openbsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openbsd-x64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/openbsd-x64@npm:0.25.12"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/openharmony-arm64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/openharmony-arm64@npm:0.25.12"
+ conditions: os=openharmony & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/sunos-x64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/sunos-x64@npm:0.25.12"
+ conditions: os=sunos & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-arm64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/win32-arm64@npm:0.25.12"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-ia32@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/win32-ia32@npm:0.25.12"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@esbuild/win32-x64@npm:0.25.12":
+ version: 0.25.12
+ resolution: "@esbuild/win32-x64@npm:0.25.12"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@eslint-community/eslint-utils@npm:^4.8.0, @eslint-community/eslint-utils@npm:^4.9.1":
+ version: 4.9.1
+ resolution: "@eslint-community/eslint-utils@npm:4.9.1"
+ dependencies:
+ eslint-visitor-keys: "npm:^3.4.3"
+ peerDependencies:
+ eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
+ checksum: 10c0/dc4ab5e3e364ef27e33666b11f4b86e1a6c1d7cbf16f0c6ff87b1619b3562335e9201a3d6ce806221887ff780ec9d828962a290bb910759fd40a674686503f02
+ languageName: node
+ linkType: hard
+
+"@eslint-community/regexpp@npm:^4.12.2":
+ version: 4.12.2
+ resolution: "@eslint-community/regexpp@npm:4.12.2"
+ checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d
+ languageName: node
+ linkType: hard
+
+"@eslint/config-array@npm:^0.23.5":
+ version: 0.23.5
+ resolution: "@eslint/config-array@npm:0.23.5"
+ dependencies:
+ "@eslint/object-schema": "npm:^3.0.5"
+ debug: "npm:^4.3.1"
+ minimatch: "npm:^10.2.4"
+ checksum: 10c0/b24833c4c76e78ee075d306cd3f095db46b2db0f90cc13a6ee6e4275f9889731c05bf5403ab5fefb79c756e07ac9184ed0e04570341382f9eccbccc80e6d1a0c
+ languageName: node
+ linkType: hard
+
+"@eslint/config-helpers@npm:^0.6.0":
+ version: 0.6.0
+ resolution: "@eslint/config-helpers@npm:0.6.0"
+ dependencies:
+ "@eslint/core": "npm:^1.2.1"
+ checksum: 10c0/f9af20e8b60b0ba27edb74b8eb40c0c5d51a9bf9baf9e053bb57833a87cb0a1c49b4dfaad88fc24d49c907ad1324c8a0b668684fa9c321351dac4bc9155ec10a
+ languageName: node
+ linkType: hard
+
+"@eslint/core@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "@eslint/core@npm:1.2.1"
+ dependencies:
+ "@types/json-schema": "npm:^7.0.15"
+ checksum: 10c0/10979b40588ecfef771fcb5013a542a35fb30692cc95a65f3481b0b36fbd89f5679efeb30d57f4eed35203d859aabace2a620177d6c536f71b299a1af2f3398f
+ languageName: node
+ linkType: hard
+
+"@eslint/js@npm:^10.0.1":
+ version: 10.0.1
+ resolution: "@eslint/js@npm:10.0.1"
+ peerDependencies:
+ eslint: ^10.0.0
+ peerDependenciesMeta:
+ eslint:
+ optional: true
+ checksum: 10c0/9f3fcaf71ba7fdf65d82e8faad6ecfe97e11801cc3c362b306a88ea1ed1344ae0d35330dddb0e8ad18f010f6687a70b75491b9e01c8af57acd7987cee6b3ec6c
+ languageName: node
+ linkType: hard
+
+"@eslint/object-schema@npm:^3.0.5":
+ version: 3.0.5
+ resolution: "@eslint/object-schema@npm:3.0.5"
+ checksum: 10c0/1db337431f520b99e9edda64ef5fafd7ec6a029843eeb608753025125b6649d861d843cffafafd3c4e37926d7d5f9ec0c6a8e3665c13c3da2144e8132892e92e
+ languageName: node
+ linkType: hard
+
+"@eslint/plugin-kit@npm:^0.7.2":
+ version: 0.7.2
+ resolution: "@eslint/plugin-kit@npm:0.7.2"
+ dependencies:
+ "@eslint/core": "npm:^1.2.1"
+ levn: "npm:^0.4.1"
+ checksum: 10c0/aafba08077bcd6d7dde6c2e21db18086046a88f914f29971a84cac9ad2d48952ded1b293e665e523805297eff756522dafa16f0062195e2c7143dcd1d47d11ed
+ languageName: node
+ linkType: hard
+
+"@graphql-typed-document-node/core@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "@graphql-typed-document-node/core@npm:3.2.0"
+ peerDependencies:
+ graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0
+ checksum: 10c0/94e9d75c1f178bbae8d874f5a9361708a3350c8def7eaeb6920f2c820e82403b7d4f55b3735856d68e145e86c85cbfe2adc444fdc25519cd51f108697e99346c
+ languageName: node
+ linkType: hard
+
+"@human-protocol/core@npm:7.0.0, @human-protocol/core@npm:^7.0.0":
+ version: 7.0.0
+ resolution: "@human-protocol/core@npm:7.0.0"
+ peerDependencies:
+ ethers: ~6.16.0
+ checksum: 10c0/b8083fca9b7fab0bca450b7a520cf9f0e8b3af29f4b90fc36ab1d3f24b2ff76aa53f3c3e160f7c40e7079aad6f32ebc67f5abaf8ad75eb77eee808fee7fd3955
+ languageName: node
+ linkType: hard
+
+"@human-protocol/sdk@npm:^7.3.0":
+ version: 7.3.0
+ resolution: "@human-protocol/sdk@npm:7.3.0"
+ dependencies:
+ "@human-protocol/core": "npm:7.0.0"
+ axios: "npm:^1.4.0"
+ ethers: "npm:~6.16.0"
+ graphql: "npm:^16.8.1"
+ graphql-request: "npm:^7.3.4"
+ graphql-tag: "npm:^2.12.6"
+ openpgp: "npm:^6.3.0"
+ secp256k1: "npm:^5.0.1"
+ validator: "npm:^13.12.0"
+ vitest: "npm:^4.0.18"
+ checksum: 10c0/5835ce09161ab554483c6f9239f9985296491810b28a2f19adb090602c4436732b6787acb875ef2cf3fa9a6ca04ddecc620c52d5829f13a3cec1fd4dc85f1785
+ languageName: node
+ linkType: hard
+
+"@humanfs/core@npm:^0.19.2":
+ version: 0.19.2
+ resolution: "@humanfs/core@npm:0.19.2"
+ dependencies:
+ "@humanfs/types": "npm:^0.15.0"
+ checksum: 10c0/d0a1d52d7b30c27d49475a53072d1510b81c5803e44b342fb8faf3887f1aa27593a1e6dc76a45268e7892d3f4e198146659281f6b6d55eacf3fd5a38bac30c5c
+ languageName: node
+ linkType: hard
+
+"@humanfs/node@npm:^0.16.6":
+ version: 0.16.8
+ resolution: "@humanfs/node@npm:0.16.8"
+ dependencies:
+ "@humanfs/core": "npm:^0.19.2"
+ "@humanfs/types": "npm:^0.15.0"
+ "@humanwhocodes/retry": "npm:^0.4.0"
+ checksum: 10c0/56140579db811af4e160b195d45d0f29acf644d192c93fe24c9e594ebf06f19dfc157494a07c84540b8a071c0e4b37209c2362765d31734f4d0be869c2422e25
+ languageName: node
+ linkType: hard
+
+"@humanfs/types@npm:^0.15.0":
+ version: 0.15.0
+ resolution: "@humanfs/types@npm:0.15.0"
+ checksum: 10c0/fc26b9a024b0e55f7eaf64036df94345bf5d36d6a41ef80ef38e78f1f7430ce26cf435af736adae58913baae18eac3f38c18739054a3d379102015978eae862e
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/module-importer@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "@humanwhocodes/module-importer@npm:1.0.1"
+ checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529
+ languageName: node
+ linkType: hard
+
+"@humanwhocodes/retry@npm:^0.4.0, @humanwhocodes/retry@npm:^0.4.2":
+ version: 0.4.3
+ resolution: "@humanwhocodes/retry@npm:0.4.3"
+ checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42
+ languageName: node
+ linkType: hard
+
+"@isaacs/fs-minipass@npm:^4.0.0":
+ version: 4.0.1
+ resolution: "@isaacs/fs-minipass@npm:4.0.1"
+ dependencies:
+ minipass: "npm:^7.0.4"
+ checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2
+ languageName: node
+ linkType: hard
+
+"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.5":
+ version: 0.3.13
+ resolution: "@jridgewell/gen-mapping@npm:0.3.13"
+ dependencies:
+ "@jridgewell/sourcemap-codec": "npm:^1.5.0"
+ "@jridgewell/trace-mapping": "npm:^0.3.24"
+ checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b
+ languageName: node
+ linkType: hard
+
+"@jridgewell/remapping@npm:^2.3.5":
+ version: 2.3.5
+ resolution: "@jridgewell/remapping@npm:2.3.5"
+ dependencies:
+ "@jridgewell/gen-mapping": "npm:^0.3.5"
+ "@jridgewell/trace-mapping": "npm:^0.3.24"
+ checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194
+ languageName: node
+ linkType: hard
+
+"@jridgewell/resolve-uri@npm:^3.1.0":
+ version: 3.1.2
+ resolution: "@jridgewell/resolve-uri@npm:3.1.2"
+ checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e
+ languageName: node
+ linkType: hard
+
+"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0, @jridgewell/sourcemap-codec@npm:^1.5.5":
+ version: 1.5.5
+ resolution: "@jridgewell/sourcemap-codec@npm:1.5.5"
+ checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0
+ languageName: node
+ linkType: hard
+
+"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28":
+ version: 0.3.31
+ resolution: "@jridgewell/trace-mapping@npm:0.3.31"
+ dependencies:
+ "@jridgewell/resolve-uri": "npm:^3.1.0"
+ "@jridgewell/sourcemap-codec": "npm:^1.4.14"
+ checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9
+ languageName: node
+ linkType: hard
+
+"@lit-labs/ssr-dom-shim@npm:^1.5.0":
+ version: 1.6.0
+ resolution: "@lit-labs/ssr-dom-shim@npm:1.6.0"
+ checksum: 10c0/deffcfd765d268820beef600a1c1cf9d3cf1a5cb4bbe7e80843796ff33d1a122f4e5651ef4a44b33d36e5fa6538e6ee87a95b9d40b4a26cabf3c35b45194c87a
+ languageName: node
+ linkType: hard
+
+"@lit/react@npm:1.0.8":
+ version: 1.0.8
+ resolution: "@lit/react@npm:1.0.8"
+ peerDependencies:
+ "@types/react": 17 || 18 || 19
+ checksum: 10c0/18bf3eb6584fa989e0ad40988b349a4401da1cecd5bf1c6edfc1c5caed80037852a4ebe5685b04941e5b28ccf93e740676dae32773d7ae44b1479b96538392b1
+ languageName: node
+ linkType: hard
+
+"@lit/reactive-element@npm:^2.1.0":
+ version: 2.1.2
+ resolution: "@lit/reactive-element@npm:2.1.2"
+ dependencies:
+ "@lit-labs/ssr-dom-shim": "npm:^1.5.0"
+ checksum: 10c0/557069ce6ebbbafb1140e1e0a25ce73d3501bf455cda231d42bb131baa9065c54b6b7ca1655507eede397decd7ddde16c84192cb72a07d4edf41d54e07725933
+ languageName: node
+ linkType: hard
+
+"@msgpack/msgpack@npm:3.1.3":
+ version: 3.1.3
+ resolution: "@msgpack/msgpack@npm:3.1.3"
+ checksum: 10c0/1fa9a760a58e64e121561d17977b680198ff24d83e951df3896f8639d06824f2cba20af92a19940461e0d5d6dc696bd01222bd901164759432eadd0f482d0816
+ languageName: node
+ linkType: hard
+
+"@mui/core-downloads-tracker@npm:^5.18.0":
+ version: 5.18.0
+ resolution: "@mui/core-downloads-tracker@npm:5.18.0"
+ checksum: 10c0/d82962a1b69878cf6a6785b6600302a943d474af00bba50169e207ce0bb5d072f1ed65783c7d5ca940cbe4228ab86bc95bb57545cf2cd039d588f2571bbefe0c
+ languageName: node
+ linkType: hard
+
+"@mui/icons-material@npm:^5.18.0":
+ version: 5.18.0
+ resolution: "@mui/icons-material@npm:5.18.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.9"
+ peerDependencies:
+ "@mui/material": ^5.0.0
+ "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/4fc61ea1b8ff276c8545b4f4f3881d9be590af24d8c2cbb076b34ec9a9230fd3147c30dd12399133c8d99c9eb748bd73014fa29b187b94229b90783023af4482
+ languageName: node
+ linkType: hard
+
+"@mui/material@npm:^5.16.7":
+ version: 5.18.0
+ resolution: "@mui/material@npm:5.18.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.9"
+ "@mui/core-downloads-tracker": "npm:^5.18.0"
+ "@mui/system": "npm:^5.18.0"
+ "@mui/types": "npm:~7.2.15"
+ "@mui/utils": "npm:^5.17.1"
+ "@popperjs/core": "npm:^2.11.8"
+ "@types/react-transition-group": "npm:^4.4.10"
+ clsx: "npm:^2.1.0"
+ csstype: "npm:^3.1.3"
+ prop-types: "npm:^15.8.1"
+ react-is: "npm:^19.0.0"
+ react-transition-group: "npm:^4.4.5"
+ peerDependencies:
+ "@emotion/react": ^11.5.0
+ "@emotion/styled": ^11.3.0
+ "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@emotion/react":
+ optional: true
+ "@emotion/styled":
+ optional: true
+ "@types/react":
+ optional: true
+ checksum: 10c0/a743c9105d08b636d4d9cf0aa276283b9095113771c188c7f5ac6953606dd77a5eb082dbbd889446a9a8573b8676d7249140c29eec55ae8320592e5f02d0f2cb
+ languageName: node
+ linkType: hard
+
+"@mui/private-theming@npm:^5.17.1":
+ version: 5.17.1
+ resolution: "@mui/private-theming@npm:5.17.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.9"
+ "@mui/utils": "npm:^5.17.1"
+ prop-types: "npm:^15.8.1"
+ peerDependencies:
+ "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/53015616e3497d5fe1b068c49a5f3ebc81160fe4a08a05f1cf61acfe64522a2e6bb3d13110797a5619ceb46dce291dc13b5031cd4bcf4dbf42800b73f98640dd
+ languageName: node
+ linkType: hard
+
+"@mui/styled-engine@npm:^5.18.0":
+ version: 5.18.0
+ resolution: "@mui/styled-engine@npm:5.18.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.9"
+ "@emotion/cache": "npm:^11.13.5"
+ "@emotion/serialize": "npm:^1.3.3"
+ csstype: "npm:^3.1.3"
+ prop-types: "npm:^15.8.1"
+ peerDependencies:
+ "@emotion/react": ^11.4.1
+ "@emotion/styled": ^11.3.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@emotion/react":
+ optional: true
+ "@emotion/styled":
+ optional: true
+ checksum: 10c0/68dad75142eea160fc51abf14915d07afd0e7e7791823f6ea6845b2037fde9de6c17b84247a1f283a1437d130857cb97c1a8474c25c161a934671bc48f205418
+ languageName: node
+ linkType: hard
+
+"@mui/system@npm:^5.18.0":
+ version: 5.18.0
+ resolution: "@mui/system@npm:5.18.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.9"
+ "@mui/private-theming": "npm:^5.17.1"
+ "@mui/styled-engine": "npm:^5.18.0"
+ "@mui/types": "npm:~7.2.15"
+ "@mui/utils": "npm:^5.17.1"
+ clsx: "npm:^2.1.0"
+ csstype: "npm:^3.1.3"
+ prop-types: "npm:^15.8.1"
+ peerDependencies:
+ "@emotion/react": ^11.5.0
+ "@emotion/styled": ^11.3.0
+ "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@emotion/react":
+ optional: true
+ "@emotion/styled":
+ optional: true
+ "@types/react":
+ optional: true
+ checksum: 10c0/9f5ad15f08c71560e9723b1f136214a0871079a976285f8b813041081850e1f9e2e9fb00766c15814217852694a521a9a91cde3bed95b8062defa8052f69eabf
+ languageName: node
+ linkType: hard
+
+"@mui/types@npm:~7.2.15":
+ version: 7.2.24
+ resolution: "@mui/types@npm:7.2.24"
+ peerDependencies:
+ "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/7756339cae70e9b684c4311924e4e3882f908552b69c434b4d13faf2f5908ce72fe889a31890257c5ad42a085207be7c1661981dfc683293e90ac6dfac3759d0
+ languageName: node
+ linkType: hard
+
+"@mui/utils@npm:^5.17.1":
+ version: 5.17.1
+ resolution: "@mui/utils@npm:5.17.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.23.9"
+ "@mui/types": "npm:~7.2.15"
+ "@types/prop-types": "npm:^15.7.12"
+ clsx: "npm:^2.1.1"
+ prop-types: "npm:^15.8.1"
+ react-is: "npm:^19.0.0"
+ peerDependencies:
+ "@types/react": ^17.0.0 || ^18.0.0 || ^19.0.0
+ react: ^17.0.0 || ^18.0.0 || ^19.0.0
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ checksum: 10c0/0a2b033f85b67ad5cab86c5b9e2341cc1a1fa931eaad5489b21281e0bfe9054061817a8de50bcf3363f17f5a3f0c44400950099f36e5039e735c1b5f3b30cf2b
+ languageName: node
+ linkType: hard
+
+"@napi-rs/wasm-runtime@npm:^1.1.4":
+ version: 1.1.5
+ resolution: "@napi-rs/wasm-runtime@npm:1.1.5"
+ dependencies:
+ "@tybys/wasm-util": "npm:^0.10.2"
+ peerDependencies:
+ "@emnapi/core": ^1.7.1
+ "@emnapi/runtime": ^1.7.1
+ checksum: 10c0/727f2b6ae0e68bbe5d39aeb68aa6f183314e9f03dc50bb55a962849535b2db53ecc3fbf1554d8656a54488a608df5a2634670595cf5874dc4af2ee59f817c65d
+ languageName: node
+ linkType: hard
+
+"@noble/ciphers@npm:1.3.0, @noble/ciphers@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "@noble/ciphers@npm:1.3.0"
+ checksum: 10c0/3ba6da645ce45e2f35e3b2e5c87ceba86b21dfa62b9466ede9edfb397f8116dae284f06652c0cd81d99445a2262b606632e868103d54ecc99fd946ae1af8cd37
+ languageName: node
+ linkType: hard
+
+"@noble/curves@npm:1.2.0":
+ version: 1.2.0
+ resolution: "@noble/curves@npm:1.2.0"
+ dependencies:
+ "@noble/hashes": "npm:1.3.2"
+ checksum: 10c0/0bac7d1bbfb3c2286910b02598addd33243cb97c3f36f987ecc927a4be8d7d88e0fcb12b0f0ef8a044e7307d1844dd5c49bb724bfa0a79c8ec50ba60768c97f6
+ languageName: node
+ linkType: hard
+
+"@noble/curves@npm:1.8.0":
+ version: 1.8.0
+ resolution: "@noble/curves@npm:1.8.0"
+ dependencies:
+ "@noble/hashes": "npm:1.7.0"
+ checksum: 10c0/3ebb1795f3f7d74c879bc6262a3444061585a2cab90b7b637dc57d931063dd0c95be858a4c2389e932651825dbc461c215dbcf43984a232de3bd6b2d326ba555
+ languageName: node
+ linkType: hard
+
+"@noble/curves@npm:1.9.1":
+ version: 1.9.1
+ resolution: "@noble/curves@npm:1.9.1"
+ dependencies:
+ "@noble/hashes": "npm:1.8.0"
+ checksum: 10c0/39c84dbfecdca80cfde2ecea4b06ef2ec1255a4df40158d22491d1400057a283f57b2b26c8b1331006e6e061db791f31d47764961c239437032e2f45e8888c1e
+ languageName: node
+ linkType: hard
+
+"@noble/curves@npm:1.9.7, @noble/curves@npm:^1.6.0, @noble/curves@npm:~1.9.0":
+ version: 1.9.7
+ resolution: "@noble/curves@npm:1.9.7"
+ dependencies:
+ "@noble/hashes": "npm:1.8.0"
+ checksum: 10c0/150014751ebe8ca06a8654ca2525108452ea9ee0be23430332769f06808cddabfe84f248b6dbf836916bc869c27c2092957eec62c7506d68a1ed0a624017c2a3
+ languageName: node
+ linkType: hard
+
+"@noble/hashes@npm:1.3.2":
+ version: 1.3.2
+ resolution: "@noble/hashes@npm:1.3.2"
+ checksum: 10c0/2482cce3bce6a596626f94ca296e21378e7a5d4c09597cbc46e65ffacc3d64c8df73111f2265444e36a3168208628258bbbaccba2ef24f65f58b2417638a20e7
+ languageName: node
+ linkType: hard
+
+"@noble/hashes@npm:1.4.0":
+ version: 1.4.0
+ resolution: "@noble/hashes@npm:1.4.0"
+ checksum: 10c0/8c3f005ee72e7b8f9cff756dfae1241485187254e3f743873e22073d63906863df5d4f13d441b7530ea614b7a093f0d889309f28b59850f33b66cb26a779a4a5
+ languageName: node
+ linkType: hard
+
+"@noble/hashes@npm:1.7.0":
+ version: 1.7.0
+ resolution: "@noble/hashes@npm:1.7.0"
+ checksum: 10c0/1ef0c985ebdb5a1bd921ea6d959c90ba826af3ae05b40b459a703e2a5e9b259f190c6e92d6220fb3800e2385521e4159e238415ad3f6b79c52f91dd615e491dc
+ languageName: node
+ linkType: hard
+
+"@noble/hashes@npm:1.8.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:^1.8.0, @noble/hashes@npm:~1.8.0":
+ version: 1.8.0
+ resolution: "@noble/hashes@npm:1.8.0"
+ checksum: 10c0/06a0b52c81a6fa7f04d67762e08b2c476a00285858150caeaaff4037356dd5e119f45b2a530f638b77a5eeca013168ec1b655db41bae3236cb2e9d511484fc77
+ languageName: node
+ linkType: hard
+
+"@oxc-project/types@npm:=0.133.0":
+ version: 0.133.0
+ resolution: "@oxc-project/types@npm:0.133.0"
+ checksum: 10c0/70c57ba58644f7ec217b670c301801f4d06995f4ccdba6b2bd106ea3e5ee49d616573e6ef8d55530b87571a960696543687f3850e87ad173d3f88965c30cdd63
+ languageName: node
+ linkType: hard
+
+"@phosphor-icons/webcomponents@npm:2.1.5":
+ version: 2.1.5
+ resolution: "@phosphor-icons/webcomponents@npm:2.1.5"
+ dependencies:
+ lit: "npm:^3"
+ checksum: 10c0/547c0e3e18b0203e8b432fdbc5aa075219a4e19cffa8582e6da35f0d67ac85441f67a1bb005cadeb3601e5ecda760339fca3fbb729be66ae6ec0c9d3e4d36d38
+ languageName: node
+ linkType: hard
+
+"@popperjs/core@npm:^2.11.8":
+ version: 2.11.8
+ resolution: "@popperjs/core@npm:2.11.8"
+ checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-adapter-wagmi@npm:^1.8.19":
+ version: 1.8.20
+ resolution: "@reown/appkit-adapter-wagmi@npm:1.8.20"
+ dependencies:
+ "@reown/appkit": "npm:1.8.20"
+ "@reown/appkit-common": "npm:1.8.20"
+ "@reown/appkit-controllers": "npm:1.8.20"
+ "@reown/appkit-polyfills": "npm:1.8.20"
+ "@reown/appkit-scaffold-ui": "npm:1.8.20"
+ "@reown/appkit-utils": "npm:1.8.20"
+ "@reown/appkit-wallet": "npm:1.8.20"
+ "@wagmi/connectors": "npm:>=5.9.9"
+ "@walletconnect/universal-provider": "npm:2.23.7"
+ valtio: "npm:2.1.7"
+ peerDependencies:
+ "@wagmi/core": ">=2.21.2"
+ viem: ">=2.45.0"
+ wagmi: ">=2.19.5"
+ dependenciesMeta:
+ "@wagmi/connectors":
+ optional: true
+ checksum: 10c0/9eefcdda07681d20f7e82447e49b0f14f0f3c7ec47b1883d51a1526bed0bb2871b663ed0fb6ddf204870c06e65753f881fc378ebdf6258c4c80daa5480d77388
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-common@npm:1.8.20":
+ version: 1.8.20
+ resolution: "@reown/appkit-common@npm:1.8.20"
+ dependencies:
+ big.js: "npm:6.2.2"
+ dayjs: "npm:1.11.13"
+ viem: "npm:>=2.45.0"
+ checksum: 10c0/cf1c1f6ad732311bb672b52947b48fafc1200bdfecbd3bcc4dc95b3306e568f97ccc682d279aac8d0a68de786392917d683ce3a3afc516ea6cc195c1237701c8
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-controllers@npm:1.8.20":
+ version: 1.8.20
+ resolution: "@reown/appkit-controllers@npm:1.8.20"
+ dependencies:
+ "@reown/appkit-common": "npm:1.8.20"
+ "@reown/appkit-wallet": "npm:1.8.20"
+ "@walletconnect/universal-provider": "npm:2.23.7"
+ valtio: "npm:2.1.7"
+ viem: "npm:>=2.45.0"
+ checksum: 10c0/47754f13416927ab8f901fc5a3e6294a79347f4d431d4b581779f0cfc636348662ebba98e3c0bf3a5688ef74f3bef4df162a7ac1fbfd4ac6ef02b3346a64e8d0
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-pay@npm:1.8.20":
+ version: 1.8.20
+ resolution: "@reown/appkit-pay@npm:1.8.20"
+ dependencies:
+ "@reown/appkit-common": "npm:1.8.20"
+ "@reown/appkit-controllers": "npm:1.8.20"
+ "@reown/appkit-ui": "npm:1.8.20"
+ "@reown/appkit-utils": "npm:1.8.20"
+ lit: "npm:3.3.0"
+ valtio: "npm:2.1.7"
+ checksum: 10c0/2dcec246c7f5698988f14bd179bec4e8a1cd6358ea3daeccddcbc5404767103b8db45d99256e04a667c310113ed6e365cd8a135c429d4c5bcf9bbe226bf01df1
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-polyfills@npm:1.8.20":
+ version: 1.8.20
+ resolution: "@reown/appkit-polyfills@npm:1.8.20"
+ dependencies:
+ buffer: "npm:6.0.3"
+ checksum: 10c0/2d25f0d5c98a909d0a9a0c3e54c2f26ad7c749af8868b7b38a0aa3c2a0008cc82eaf21c846acb3b079e53cfe179f0ae1abd317fbcc6355e6d6fd12be3bc690d9
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-scaffold-ui@npm:1.8.20":
+ version: 1.8.20
+ resolution: "@reown/appkit-scaffold-ui@npm:1.8.20"
+ dependencies:
+ "@reown/appkit-common": "npm:1.8.20"
+ "@reown/appkit-controllers": "npm:1.8.20"
+ "@reown/appkit-pay": "npm:1.8.20"
+ "@reown/appkit-ui": "npm:1.8.20"
+ "@reown/appkit-utils": "npm:1.8.20"
+ "@reown/appkit-wallet": "npm:1.8.20"
+ lit: "npm:3.3.0"
+ checksum: 10c0/4bccdc3a9a690ad4bd3073c87c486abfd6219321c4f58015a0284531513852d3554f0fd47887da8413d96ec531b6b3a5b31412dbe2c64a6c103c2311cca6097d
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-ui@npm:1.8.20":
+ version: 1.8.20
+ resolution: "@reown/appkit-ui@npm:1.8.20"
+ dependencies:
+ "@phosphor-icons/webcomponents": "npm:2.1.5"
+ "@reown/appkit-common": "npm:1.8.20"
+ "@reown/appkit-controllers": "npm:1.8.20"
+ "@reown/appkit-wallet": "npm:1.8.20"
+ lit: "npm:3.3.0"
+ qrcode: "npm:1.5.3"
+ checksum: 10c0/5b92bd2c5c2c002a62638349b560edc99b5f5294a11c4807a086b1a76c2c12332409d195359ff1c6ac3112255e16735956ff60149af38f71f585c7731dfe7d24
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-utils@npm:1.8.20":
+ version: 1.8.20
+ resolution: "@reown/appkit-utils@npm:1.8.20"
+ dependencies:
+ "@base-org/account": "npm:2.4.0"
+ "@coinbase/wallet-sdk": "npm:4.3.6"
+ "@reown/appkit-common": "npm:1.8.20"
+ "@reown/appkit-controllers": "npm:1.8.20"
+ "@reown/appkit-polyfills": "npm:1.8.20"
+ "@reown/appkit-wallet": "npm:1.8.20"
+ "@safe-global/safe-apps-provider": "npm:0.18.6"
+ "@safe-global/safe-apps-sdk": "npm:9.1.0"
+ "@wallet-standard/wallet": "npm:1.1.0"
+ "@walletconnect/logger": "npm:3.0.2"
+ "@walletconnect/universal-provider": "npm:2.23.7"
+ valtio: "npm:2.1.7"
+ viem: "npm:>=2.45.0"
+ peerDependencies:
+ valtio: 2.1.7
+ dependenciesMeta:
+ "@base-org/account":
+ optional: true
+ "@coinbase/wallet-sdk":
+ optional: true
+ "@safe-global/safe-apps-provider":
+ optional: true
+ "@safe-global/safe-apps-sdk":
+ optional: true
+ checksum: 10c0/90759f71bab21b36f718cf70fabe211ae3af7c618fc88bb6e07d57e6865a00b40550537b3192adbb5e33e89fb9dbd8db96d0bdaa3e26d4309343c18606b3b8e6
+ languageName: node
+ linkType: hard
+
+"@reown/appkit-wallet@npm:1.8.20":
+ version: 1.8.20
+ resolution: "@reown/appkit-wallet@npm:1.8.20"
+ dependencies:
+ "@reown/appkit-common": "npm:1.8.20"
+ "@reown/appkit-polyfills": "npm:1.8.20"
+ "@walletconnect/logger": "npm:3.0.2"
+ zod: "npm:3.22.4"
+ checksum: 10c0/23bd444ee13628206672b57926fd31e92c426dabdcf37b58928910a99e899d09ccf8f3d65a11243670f82664d6be3675c17097d7fb59ba14040c174031d5100d
+ languageName: node
+ linkType: hard
+
+"@reown/appkit@npm:1.8.20, @reown/appkit@npm:^1.8.19":
+ version: 1.8.20
+ resolution: "@reown/appkit@npm:1.8.20"
+ dependencies:
+ "@lit/react": "npm:1.0.8"
+ "@reown/appkit-common": "npm:1.8.20"
+ "@reown/appkit-controllers": "npm:1.8.20"
+ "@reown/appkit-pay": "npm:1.8.20"
+ "@reown/appkit-polyfills": "npm:1.8.20"
+ "@reown/appkit-scaffold-ui": "npm:1.8.20"
+ "@reown/appkit-ui": "npm:1.8.20"
+ "@reown/appkit-utils": "npm:1.8.20"
+ "@reown/appkit-wallet": "npm:1.8.20"
+ "@walletconnect/universal-provider": "npm:2.23.7"
+ bs58: "npm:6.0.0"
+ semver: "npm:7.7.2"
+ valtio: "npm:2.1.7"
+ viem: "npm:>=2.45.0"
+ dependenciesMeta:
+ "@lit/react":
+ optional: true
+ checksum: 10c0/92df75c8b18d882c1f91953da261046b85ed42c36fc7922dcdaabd48c36471fffdc0a94fdb43d86ce72c98fc0bb0f4f006ca8a8e525211797d76b631d528f9a5
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-android-arm64@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-android-arm64@npm:1.0.3"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-darwin-arm64@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-darwin-arm64@npm:1.0.3"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-darwin-x64@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-darwin-x64@npm:1.0.3"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-freebsd-x64@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-freebsd-x64@npm:1.0.3"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-linux-arm-gnueabihf@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-linux-arm-gnueabihf@npm:1.0.3"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-linux-arm64-gnu@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-linux-arm64-gnu@npm:1.0.3"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-linux-arm64-musl@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-linux-arm64-musl@npm:1.0.3"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-linux-ppc64-gnu@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-linux-ppc64-gnu@npm:1.0.3"
+ conditions: os=linux & cpu=ppc64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-linux-s390x-gnu@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-linux-s390x-gnu@npm:1.0.3"
+ conditions: os=linux & cpu=s390x & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-linux-x64-gnu@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-linux-x64-gnu@npm:1.0.3"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-linux-x64-musl@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-linux-x64-musl@npm:1.0.3"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-openharmony-arm64@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-openharmony-arm64@npm:1.0.3"
+ conditions: os=openharmony & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-wasm32-wasi@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-wasm32-wasi@npm:1.0.3"
+ dependencies:
+ "@emnapi/core": "npm:1.10.0"
+ "@emnapi/runtime": "npm:1.10.0"
+ "@napi-rs/wasm-runtime": "npm:^1.1.4"
+ conditions: cpu=wasm32
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-win32-arm64-msvc@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-win32-arm64-msvc@npm:1.0.3"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rolldown/binding-win32-x64-msvc@npm:1.0.3":
+ version: 1.0.3
+ resolution: "@rolldown/binding-win32-x64-msvc@npm:1.0.3"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rolldown/pluginutils@npm:1.0.0-beta.27":
+ version: 1.0.0-beta.27
+ resolution: "@rolldown/pluginutils@npm:1.0.0-beta.27"
+ checksum: 10c0/9658f235b345201d4f6bfb1f32da9754ca164f892d1cb68154fe5f53c1df42bd675ecd409836dff46884a7847d6c00bdc38af870f7c81e05bba5c2645eb4ab9c
+ languageName: node
+ linkType: hard
+
+"@rolldown/pluginutils@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "@rolldown/pluginutils@npm:1.0.1"
+ checksum: 10c0/99d9b06d90196823e4d8c841f258db7a16e5dbba5824a2962b05d907b79f1ba929d56f22dd744fd530936e568c865ee56a719dc31e57e13bc0a8eb4764a8d8dd
+ languageName: node
+ linkType: hard
+
+"@rollup/plugin-inject@npm:^5.0.5":
+ version: 5.0.5
+ resolution: "@rollup/plugin-inject@npm:5.0.5"
+ dependencies:
+ "@rollup/pluginutils": "npm:^5.0.1"
+ estree-walker: "npm:^2.0.2"
+ magic-string: "npm:^0.30.3"
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+ checksum: 10c0/22d10cf44fa56a6683d5ac4df24a9003379b3dcaae9897f5c30c844afc2ebca83cfaa5557f13a1399b1c8a0d312c3217bcacd508b7ebc4b2cbee401bd1ec8be2
+ languageName: node
+ linkType: hard
+
+"@rollup/pluginutils@npm:^5.0.1":
+ version: 5.4.0
+ resolution: "@rollup/pluginutils@npm:5.4.0"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ estree-walker: "npm:^2.0.2"
+ picomatch: "npm:^4.0.2"
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+ checksum: 10c0/ccc2cbd3a05df642df60ab05ffb81b2e564bd945e2a118bb8a474ea75b941033c8f44273133d4865643cca1492d0c80b14de1281f74779a64285a80fc3a194d8
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-android-arm-eabi@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-android-arm-eabi@npm:4.61.1"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-android-arm64@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-android-arm64@npm:4.61.1"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-darwin-arm64@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-darwin-arm64@npm:4.61.1"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-darwin-x64@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-darwin-x64@npm:4.61.1"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-freebsd-arm64@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-freebsd-arm64@npm:4.61.1"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-freebsd-x64@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-freebsd-x64@npm:4.61.1"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm-gnueabihf@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.61.1"
+ conditions: os=linux & cpu=arm & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm-musleabihf@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-arm-musleabihf@npm:4.61.1"
+ conditions: os=linux & cpu=arm & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm64-gnu@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.61.1"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-arm64-musl@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-arm64-musl@npm:4.61.1"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-loong64-gnu@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-loong64-gnu@npm:4.61.1"
+ conditions: os=linux & cpu=loong64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-loong64-musl@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-loong64-musl@npm:4.61.1"
+ conditions: os=linux & cpu=loong64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-ppc64-gnu@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-ppc64-gnu@npm:4.61.1"
+ conditions: os=linux & cpu=ppc64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-ppc64-musl@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-ppc64-musl@npm:4.61.1"
+ conditions: os=linux & cpu=ppc64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-riscv64-gnu@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.61.1"
+ conditions: os=linux & cpu=riscv64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-riscv64-musl@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-riscv64-musl@npm:4.61.1"
+ conditions: os=linux & cpu=riscv64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-s390x-gnu@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-s390x-gnu@npm:4.61.1"
+ conditions: os=linux & cpu=s390x & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-x64-gnu@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-x64-gnu@npm:4.61.1"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-linux-x64-musl@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-linux-x64-musl@npm:4.61.1"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-openbsd-x64@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-openbsd-x64@npm:4.61.1"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-openharmony-arm64@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-openharmony-arm64@npm:4.61.1"
+ conditions: os=openharmony & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-arm64-msvc@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.61.1"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-ia32-msvc@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.61.1"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-x64-gnu@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-win32-x64-gnu@npm:4.61.1"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@rollup/rollup-win32-x64-msvc@npm:4.61.1":
+ version: 4.61.1
+ resolution: "@rollup/rollup-win32-x64-msvc@npm:4.61.1"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@safe-global/safe-apps-provider@npm:0.18.6":
+ version: 0.18.6
+ resolution: "@safe-global/safe-apps-provider@npm:0.18.6"
+ dependencies:
+ "@safe-global/safe-apps-sdk": "npm:^9.1.0"
+ events: "npm:^3.3.0"
+ checksum: 10c0/e8567a97e43740bfe21b6f8a7759cabed2bc96eb50fd494118cab13a20f14797fbca3e02d18f0395054fcfbf2fd86315e5433d5b26f73bed6c3c86881087716c
+ languageName: node
+ linkType: hard
+
+"@safe-global/safe-apps-sdk@npm:9.1.0, @safe-global/safe-apps-sdk@npm:^9.1.0":
+ version: 9.1.0
+ resolution: "@safe-global/safe-apps-sdk@npm:9.1.0"
+ dependencies:
+ "@safe-global/safe-gateway-typescript-sdk": "npm:^3.5.3"
+ viem: "npm:^2.1.1"
+ checksum: 10c0/13af12122a6b1388e7960a76c3c421ea5ed97197646cd1f720b9fc9364fad0cc8f21cda23773130cd6bf57935a36f9e93f5222569cc80382709430b5cad26fda
+ languageName: node
+ linkType: hard
+
+"@safe-global/safe-gateway-typescript-sdk@npm:^3.5.3":
+ version: 3.23.1
+ resolution: "@safe-global/safe-gateway-typescript-sdk@npm:3.23.1"
+ checksum: 10c0/609cfdf71e73cb55c2596e6fa6212c73ff96aa5c857d2e5a98db193853638a8b8b2165c8cb8334a9060885acb2e688b33675bab000445bd3ec99bc6245cf8d61
+ languageName: node
+ linkType: hard
+
+"@scure/base@npm:1.2.6, @scure/base@npm:~1.2.5":
+ version: 1.2.6
+ resolution: "@scure/base@npm:1.2.6"
+ checksum: 10c0/49bd5293371c4e062cb6ba689c8fe3ea3981b7bb9c000400dc4eafa29f56814cdcdd27c04311c2fec34de26bc373c593a1d6ca6d754398a488d587943b7c128a
+ languageName: node
+ linkType: hard
+
+"@scure/bip32@npm:1.7.0, @scure/bip32@npm:^1.5.0, @scure/bip32@npm:^1.7.0":
+ version: 1.7.0
+ resolution: "@scure/bip32@npm:1.7.0"
+ dependencies:
+ "@noble/curves": "npm:~1.9.0"
+ "@noble/hashes": "npm:~1.8.0"
+ "@scure/base": "npm:~1.2.5"
+ checksum: 10c0/e3d4c1f207df16abcd79babcdb74d36f89bdafc90bf02218a5140cc5cba25821d80d42957c6705f35210cc5769714ea9501d4ae34732cdd1c26c9ff182a219f7
+ languageName: node
+ linkType: hard
+
+"@scure/bip39@npm:1.6.0, @scure/bip39@npm:^1.4.0, @scure/bip39@npm:^1.6.0":
+ version: 1.6.0
+ resolution: "@scure/bip39@npm:1.6.0"
+ dependencies:
+ "@noble/hashes": "npm:~1.8.0"
+ "@scure/base": "npm:~1.2.5"
+ checksum: 10c0/73a54b5566a50a3f8348a5cfd74d2092efeefc485efbed83d7a7374ffd9a75defddf446e8e5ea0385e4adb49a94b8ae83c5bad3e16333af400e932f7da3aaff8
+ languageName: node
+ linkType: hard
+
+"@solana-program/system@npm:^0.10.0":
+ version: 0.10.0
+ resolution: "@solana-program/system@npm:0.10.0"
+ peerDependencies:
+ "@solana/kit": ^5.0
+ checksum: 10c0/4cc3164d49fe7b10e9c0c89493f738e2d4294e2eae40fafee56b01dfb50b939c88f82eb06d5393333743b0edee961b03e947afcc20e6965252576900266ec52e
+ languageName: node
+ linkType: hard
+
+"@solana-program/token@npm:^0.9.0":
+ version: 0.9.0
+ resolution: "@solana-program/token@npm:0.9.0"
+ peerDependencies:
+ "@solana/kit": ^5.0
+ checksum: 10c0/f23b591e0ad27aa05e940429de73ebc0b9cbb65542e5aae775ac616577307d341d3335e36e24a38ba7612bcc584e50bd7cec360ca4904f42219f2708a9d453aa
+ languageName: node
+ linkType: hard
+
+"@solana/accounts@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/accounts@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/rpc-spec": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/9851005767107f198a7d4dbd5498b271236d83527b25fc05d7beb5b347ac072fb51119b9863d2033e89bb9ee06e78289a1a71b0147d19a444c28ba36f19f970b
+ languageName: node
+ linkType: hard
+
+"@solana/addresses@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/addresses@npm:5.5.1"
+ dependencies:
+ "@solana/assertions": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/nominal-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/4908e3019c930c2c4a13528eae7a5bfac25400b4173144180a68bcbac43d1b90b0771bf952711503814440547ed45d32c3b450bac0aff19974035111e0f79865
+ languageName: node
+ linkType: hard
+
+"@solana/assertions@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/assertions@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/d1a8fbfdd8e551d84b7624d645fcae66a26d9022828795f10b252f45fb84299088cec75e8f156895bb930c977db1bcbdda8ceb011f373fb288f0adb5ea4ecd31
+ languageName: node
+ linkType: hard
+
+"@solana/codecs-core@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/codecs-core@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/a66cd3e3c9a0fcf369be5c3369463db03f4b1e1aa0d322d6cb8440613dcc83608dd52501ff2ee3c56daed2b1f2b07751cfa1fe1aeb584a306a9e14175b0ca994
+ languageName: node
+ linkType: hard
+
+"@solana/codecs-data-structures@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/codecs-data-structures@npm:5.5.1"
+ dependencies:
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-numbers": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/db88246a2fc3d4c3c7d69d5e9ce7fab815be4e10e0b1519ed00454c7ac2189fc3dd2d2ae0cb05a77d560ccdc615652122cfada59e34285ce08545474542e4874
+ languageName: node
+ linkType: hard
+
+"@solana/codecs-numbers@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/codecs-numbers@npm:5.5.1"
+ dependencies:
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/1802ec289a912b086c031c8da7f856ffb2c5a581b2fef9de5bd0ea23e192ca472cc01f1a46747e0f9c1505c826f404bf2862d7403175688136b87056d22fc441
+ languageName: node
+ linkType: hard
+
+"@solana/codecs-strings@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/codecs-strings@npm:5.5.1"
+ dependencies:
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-numbers": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ fastestsmallesttextencoderdecoder: ^1.0.22
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ fastestsmallesttextencoderdecoder:
+ optional: true
+ typescript:
+ optional: true
+ checksum: 10c0/16cf7f6edee96a11862bf41cc31e0162848ecd5ba67826eee3e5fe9f10007631db5f34f794fcf44bb075cbcaf43843e34632659105f75a02c7ff3d703ee49325
+ languageName: node
+ linkType: hard
+
+"@solana/codecs@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/codecs@npm:5.5.1"
+ dependencies:
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-data-structures": "npm:5.5.1"
+ "@solana/codecs-numbers": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/options": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/bf576cb014f342edddb4b77f83a111ceecfc5709ecaa6225c71cbb40b3d31aba26f3c3f5787684d472b1ed0c705df10be517fdbab659cf43cd7a6e21bea9a9c1
+ languageName: node
+ linkType: hard
+
+"@solana/errors@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/errors@npm:5.5.1"
+ dependencies:
+ chalk: "npm:5.6.2"
+ commander: "npm:14.0.2"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ bin:
+ errors: bin/cli.mjs
+ checksum: 10c0/cafa60aa4ca91c78b0d85e5d296c9080fc537b0c62ba1bc3d3d00eaad96d2894178849be478e653cf963a2d18d71b54e0f58f319a7d77f6dbfdd5845af4c6a08
+ languageName: node
+ linkType: hard
+
+"@solana/fast-stable-stringify@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/fast-stable-stringify@npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/b116c515e71cdace7a2e45c001de486c528e178f6170dc6faaea33a3a076a5ddd7806302584e480ef0dbf9f84c9a808cbc99a068c48b0e777bc5b5e178291ed9
+ languageName: node
+ linkType: hard
+
+"@solana/functional@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/functional@npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/17f60572407006b8913529019d928b0b43b6c24798fd743673a7878e8b8db25ebe27b7eb9ef0e28cc24773d34acbb1d5fe617f9096d527efc62c9e6719f7ada2
+ languageName: node
+ linkType: hard
+
+"@solana/instruction-plans@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/instruction-plans@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ "@solana/instructions": "npm:5.5.1"
+ "@solana/keys": "npm:5.5.1"
+ "@solana/promises": "npm:5.5.1"
+ "@solana/transaction-messages": "npm:5.5.1"
+ "@solana/transactions": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/9f1cde9b925f1ecc01f3ceb6b87ba6154befb991ad58b176f58f2f210d75968d2dc26adada623d54eb5039a4116c5f8bf48e5153b813720dfc91301c2e37eb42
+ languageName: node
+ linkType: hard
+
+"@solana/instructions@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/instructions@npm:5.5.1"
+ dependencies:
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/72b3d599e8016ec6fdb34b3cdbc9cca76a8153e911fd18bee3ea9af8caf19591615425eb3c24aa04ee5da16f87fc568a17574532859b7a50c829c49397458dc4
+ languageName: node
+ linkType: hard
+
+"@solana/keys@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/keys@npm:5.5.1"
+ dependencies:
+ "@solana/assertions": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/nominal-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/1b76a7c5b15a331ebc51c003f2f2e248c91a0f3c09659de855b05757c203c7a0e165c18c3a1b3636fd919859eb58b3e51afac234aa186e01305d4c5a38a3255d
+ languageName: node
+ linkType: hard
+
+"@solana/kit@npm:^5.5.1":
+ version: 5.5.1
+ resolution: "@solana/kit@npm:5.5.1"
+ dependencies:
+ "@solana/accounts": "npm:5.5.1"
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/functional": "npm:5.5.1"
+ "@solana/instruction-plans": "npm:5.5.1"
+ "@solana/instructions": "npm:5.5.1"
+ "@solana/keys": "npm:5.5.1"
+ "@solana/offchain-messages": "npm:5.5.1"
+ "@solana/plugin-core": "npm:5.5.1"
+ "@solana/programs": "npm:5.5.1"
+ "@solana/rpc": "npm:5.5.1"
+ "@solana/rpc-api": "npm:5.5.1"
+ "@solana/rpc-parsed-types": "npm:5.5.1"
+ "@solana/rpc-spec-types": "npm:5.5.1"
+ "@solana/rpc-subscriptions": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ "@solana/signers": "npm:5.5.1"
+ "@solana/sysvars": "npm:5.5.1"
+ "@solana/transaction-confirmation": "npm:5.5.1"
+ "@solana/transaction-messages": "npm:5.5.1"
+ "@solana/transactions": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/391fd781c28c2550dae77395b0bc4e37799da13695be03c5c57e82c31b4556c29b8ac4853087908549415c419ed758c34c1ac9cdae37c4e0d28b4c9be6867b81
+ languageName: node
+ linkType: hard
+
+"@solana/nominal-types@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/nominal-types@npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/aa0f5b850c6e74d6f883d9a2513f561112d531cda750ba75efbc84a524ffc69e014740f5fac308b42499b5ea4fcaa5d34fe3acd334ef65dffe22ba822c476fbc
+ languageName: node
+ linkType: hard
+
+"@solana/offchain-messages@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/offchain-messages@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-data-structures": "npm:5.5.1"
+ "@solana/codecs-numbers": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/keys": "npm:5.5.1"
+ "@solana/nominal-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/93ba0fec4a3387e4809d8ebbdeb71901d69821cdd4b3645ee054197f9d564227cb76d66b509b98f1902fe522575662824ea58e583665c624dfb05e9a0d52b6dc
+ languageName: node
+ linkType: hard
+
+"@solana/options@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/options@npm:5.5.1"
+ dependencies:
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-data-structures": "npm:5.5.1"
+ "@solana/codecs-numbers": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/d4ab205e1286ba02a2ad97d8a3ad22e57798ce8f0fd77f3734f2c4a923c9fc7f0f949d5ceeb8b33eaf5484460c49ed0d9138f3eff5a571e754488f8aa4819269
+ languageName: node
+ linkType: hard
+
+"@solana/plugin-core@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/plugin-core@npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/6d981acfde238517692126f66594598b203eec84753677851f0dc038d01a8c55603aff1319513ba5306a29bf6b0018a1ad2d3b9de49d984acc0ecf76abfffbaa
+ languageName: node
+ linkType: hard
+
+"@solana/programs@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/programs@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/4d31ca06655366d368a853772559d5853494e82c559a02b8f6c4f90d390fb196df50b2d0d0540c2f7bbb7cc0abb3ac2e5694c2148a2bcc034a33dd64b7a105f4
+ languageName: node
+ linkType: hard
+
+"@solana/promises@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/promises@npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/d9818a5d38b85a17f74782457d8953c95835cc1190a63ff6749610e5f6272ee50d08f5720a84f9a5885e0faa94390210b86d927cf81c95f63707a122dfae100d
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-api@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-api@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/keys": "npm:5.5.1"
+ "@solana/rpc-parsed-types": "npm:5.5.1"
+ "@solana/rpc-spec": "npm:5.5.1"
+ "@solana/rpc-transformers": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ "@solana/transaction-messages": "npm:5.5.1"
+ "@solana/transactions": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/7ac47bc771d825c251f18d92e0eaef8a1f90542e5313249f88970aff666e8aa4ba446d9efc0ded2188d60c41512c09aa285bf1847bd0c439e1a4ddcb20748fc4
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-parsed-types@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-parsed-types@npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/b042b4d252e7b31a2e2cdc957711f0ecc438d1667da7414c0da25218fb439b1de2de0c1845a2ca776cddd8e399ba886a43a1f72a50e1ae0790ea6a500c90cfdb
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-spec-types@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-spec-types@npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/19b4c0e3de748db5520ab4f21a97e7ddf8e5f7a722bf635eb62aacd72ee334b2b8ab8f9343bf660055ad61f4ff71cc402e52dd41b3742944e71f54e67bf82f5a
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-spec@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-spec@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ "@solana/rpc-spec-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/634d5cd3ea7789ff20ca82782ce2fde6bb96c09fcd49dc9d113ade98a4516d2d080f771f3247454e9d4478933a3c1f1380a8409817c12cd40ef6e3579faa1d0d
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-subscriptions-api@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-subscriptions-api@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/keys": "npm:5.5.1"
+ "@solana/rpc-subscriptions-spec": "npm:5.5.1"
+ "@solana/rpc-transformers": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ "@solana/transaction-messages": "npm:5.5.1"
+ "@solana/transactions": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/3ad059f20c361d5ced84f1d584ff5513d78559497c7cf8855703a7c1437dcb3024fc1dfe9d1be65e8241a4d1a4d0c272ed2ddca7e1aca3086f204546836503f9
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-subscriptions-channel-websocket@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-subscriptions-channel-websocket@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ "@solana/functional": "npm:5.5.1"
+ "@solana/rpc-subscriptions-spec": "npm:5.5.1"
+ "@solana/subscribable": "npm:5.5.1"
+ ws: "npm:^8.19.0"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/37619caefa2f36fdbbbdab0478965a0bc14f72254caa511ecc067700d9c23f4ac221a61079974b8f6286aa2b71bb4ae5fa106297e7044ef0ed7ceb2d816c74a2
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-subscriptions-spec@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-subscriptions-spec@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ "@solana/promises": "npm:5.5.1"
+ "@solana/rpc-spec-types": "npm:5.5.1"
+ "@solana/subscribable": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/9b9e3a81977ee4deac918226a6f6d41fb524563a027d09da4439e18d3c99dd79b2af5a022a16ac97744f8e93ec9dd409714d5c371a313cb811c22194b94f28cc
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-subscriptions@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-subscriptions@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ "@solana/fast-stable-stringify": "npm:5.5.1"
+ "@solana/functional": "npm:5.5.1"
+ "@solana/promises": "npm:5.5.1"
+ "@solana/rpc-spec-types": "npm:5.5.1"
+ "@solana/rpc-subscriptions-api": "npm:5.5.1"
+ "@solana/rpc-subscriptions-channel-websocket": "npm:5.5.1"
+ "@solana/rpc-subscriptions-spec": "npm:5.5.1"
+ "@solana/rpc-transformers": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ "@solana/subscribable": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/4dda3a418bae0eff6f7da59cc21840e45bd80f3e5fee9edd32ad66b4d128490838017e2ade245fbcd8f4f765bb67350bace41fc56e00a82b739be6d24fd00bbd
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-transformers@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-transformers@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ "@solana/functional": "npm:5.5.1"
+ "@solana/nominal-types": "npm:5.5.1"
+ "@solana/rpc-spec-types": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/3500e42b486627be8e39838f02f2f28c759b0183c1bc34e28d2f2289e9ae2e58d5d0825973da601f9f29b1ab366b0017b49df5329c1dcc9932724b9bfdfafafd
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-transport-http@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-transport-http@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ "@solana/rpc-spec": "npm:5.5.1"
+ "@solana/rpc-spec-types": "npm:5.5.1"
+ undici-types: "npm:^7.19.2"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/4300e1a334e2ea8deb66542dabff835ae3dbccbaba0011c1cb027f55219cb3144c7fcd5220da06565ef5fa87a25e73a43497caeb7100ff9f1a947792b2325489
+ languageName: node
+ linkType: hard
+
+"@solana/rpc-types@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc-types@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-numbers": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/nominal-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/84fcad12f65c88bfbbe0689d1fb6715e37c41454b85f50ae0963f2626c45a26155f2395b03ab48f261966f1a5c02b1c96ad42ba0b1ca80c5fe22f08757401b1b
+ languageName: node
+ linkType: hard
+
+"@solana/rpc@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/rpc@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ "@solana/fast-stable-stringify": "npm:5.5.1"
+ "@solana/functional": "npm:5.5.1"
+ "@solana/rpc-api": "npm:5.5.1"
+ "@solana/rpc-spec": "npm:5.5.1"
+ "@solana/rpc-spec-types": "npm:5.5.1"
+ "@solana/rpc-transformers": "npm:5.5.1"
+ "@solana/rpc-transport-http": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/c469655555013f5dcfa67ef3285c9abe48929a34bdc8a3c7c21823f86f58f07f91980ee59d48190bcda5b427399a81cb180ae0ca2542e9dd47e39407f62c7458
+ languageName: node
+ linkType: hard
+
+"@solana/signers@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/signers@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/instructions": "npm:5.5.1"
+ "@solana/keys": "npm:5.5.1"
+ "@solana/nominal-types": "npm:5.5.1"
+ "@solana/offchain-messages": "npm:5.5.1"
+ "@solana/transaction-messages": "npm:5.5.1"
+ "@solana/transactions": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/53957109e4a99122b1225b04d477760e0c557fa9c66095e334de543e78f79c4b35b280dde942a0d7725dc3e61ee63c41d52b7fe5ddfc28967c3db009856573aa
+ languageName: node
+ linkType: hard
+
+"@solana/subscribable@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/subscribable@npm:5.5.1"
+ dependencies:
+ "@solana/errors": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/ff9f4af066488448276a439a9299f481cd70c1866b4ab4cce7c3486d6c950bab092f4f678b8b79b45681942c99090cd624b3eaa2a6c2820079d44c2502e7c77b
+ languageName: node
+ linkType: hard
+
+"@solana/sysvars@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/sysvars@npm:5.5.1"
+ dependencies:
+ "@solana/accounts": "npm:5.5.1"
+ "@solana/codecs": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/773e4ae956ed29999a5e0c76e44c3b390330325b03827a5a5092292678e3d1d46c2958911faf8b94b350bf42db02874b8942bd7679fc63519a259520c269883a
+ languageName: node
+ linkType: hard
+
+"@solana/transaction-confirmation@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/transaction-confirmation@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/keys": "npm:5.5.1"
+ "@solana/promises": "npm:5.5.1"
+ "@solana/rpc": "npm:5.5.1"
+ "@solana/rpc-subscriptions": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ "@solana/transaction-messages": "npm:5.5.1"
+ "@solana/transactions": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/01b96aa0518417bf257f8691e02aba5ce8a7144c64d1b96b0b17045bfe34dfa00b2035e6a930f3e36bb689dd2f00c56fc6b8a521711b2fcd262dcdabd3187966
+ languageName: node
+ linkType: hard
+
+"@solana/transaction-messages@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/transaction-messages@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-data-structures": "npm:5.5.1"
+ "@solana/codecs-numbers": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/functional": "npm:5.5.1"
+ "@solana/instructions": "npm:5.5.1"
+ "@solana/nominal-types": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/711503174284bf449b5ffbf32ae149a82a097781f0eac1cc777d941b3cc3b9de19a6daa9993c77650e001d8f8e9e2f749bd232a4da6e09fa9c856a03a6ec1cc8
+ languageName: node
+ linkType: hard
+
+"@solana/transactions@npm:5.5.1":
+ version: 5.5.1
+ resolution: "@solana/transactions@npm:5.5.1"
+ dependencies:
+ "@solana/addresses": "npm:5.5.1"
+ "@solana/codecs-core": "npm:5.5.1"
+ "@solana/codecs-data-structures": "npm:5.5.1"
+ "@solana/codecs-numbers": "npm:5.5.1"
+ "@solana/codecs-strings": "npm:5.5.1"
+ "@solana/errors": "npm:5.5.1"
+ "@solana/functional": "npm:5.5.1"
+ "@solana/instructions": "npm:5.5.1"
+ "@solana/keys": "npm:5.5.1"
+ "@solana/nominal-types": "npm:5.5.1"
+ "@solana/rpc-types": "npm:5.5.1"
+ "@solana/transaction-messages": "npm:5.5.1"
+ peerDependencies:
+ typescript: ^5.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/1dc87a6599ee60e6026b7de917b1e85a2bc2ec2e13732f872453bed597c86002c8b50ae3a4f2ea5725c969fbebe7f4987c5a2f17b02722a40f0b34191f1c7cf2
+ languageName: node
+ linkType: hard
+
+"@standard-schema/spec@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "@standard-schema/spec@npm:1.1.0"
+ checksum: 10c0/d90f55acde4b2deb983529c87e8025fa693de1a5e8b49ecc6eb84d1fd96328add0e03d7d551442156c7432fd78165b2c26ff561b970a9a881f046abb78d6a526
+ languageName: node
+ linkType: hard
+
+"@tanstack/query-core@npm:5.101.0":
+ version: 5.101.0
+ resolution: "@tanstack/query-core@npm:5.101.0"
+ checksum: 10c0/e3aacbb762887214b71d8f959930644594e2321b0cdca8eac098f894cbb75d1e32d45dc34a4b818fb8c68b344398905cf30f17c69cd87283adf73e64457e9320
+ languageName: node
+ linkType: hard
+
+"@tanstack/react-query@npm:^5.91.3":
+ version: 5.101.0
+ resolution: "@tanstack/react-query@npm:5.101.0"
+ dependencies:
+ "@tanstack/query-core": "npm:5.101.0"
+ peerDependencies:
+ react: ^18 || ^19
+ checksum: 10c0/a86add4402c23e26cf4a8c7dade5b0198a7abfb51720b91e83cfe5db8b5ed89acb027b3d5b67882098d0c83cf50099175f8310a41fd5c4b55f6c343779c3dfb6
+ languageName: node
+ linkType: hard
+
+"@tybys/wasm-util@npm:^0.10.2":
+ version: 0.10.2
+ resolution: "@tybys/wasm-util@npm:0.10.2"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/26165bcd1fd7269f42d7fbe3de318f854a8968de8397e89fc9a423bb3e2da35a52150f382e6323b3367595beb16d9800a6f35971a5599daf76da1742ec3afc25
+ languageName: node
+ linkType: hard
+
+"@types/babel__core@npm:^7.20.5":
+ version: 7.20.5
+ resolution: "@types/babel__core@npm:7.20.5"
+ dependencies:
+ "@babel/parser": "npm:^7.20.7"
+ "@babel/types": "npm:^7.20.7"
+ "@types/babel__generator": "npm:*"
+ "@types/babel__template": "npm:*"
+ "@types/babel__traverse": "npm:*"
+ checksum: 10c0/bdee3bb69951e833a4b811b8ee9356b69a61ed5b7a23e1a081ec9249769117fa83aaaf023bb06562a038eb5845155ff663e2d5c75dd95c1d5ccc91db012868ff
+ languageName: node
+ linkType: hard
+
+"@types/babel__generator@npm:*":
+ version: 7.27.0
+ resolution: "@types/babel__generator@npm:7.27.0"
+ dependencies:
+ "@babel/types": "npm:^7.0.0"
+ checksum: 10c0/9f9e959a8792df208a9d048092fda7e1858bddc95c6314857a8211a99e20e6830bdeb572e3587ae8be5429e37f2a96fcf222a9f53ad232f5537764c9e13a2bbd
+ languageName: node
+ linkType: hard
+
+"@types/babel__template@npm:*":
+ version: 7.4.4
+ resolution: "@types/babel__template@npm:7.4.4"
+ dependencies:
+ "@babel/parser": "npm:^7.1.0"
+ "@babel/types": "npm:^7.0.0"
+ checksum: 10c0/cc84f6c6ab1eab1427e90dd2b76ccee65ce940b778a9a67be2c8c39e1994e6f5bbc8efa309f6cea8dc6754994524cd4d2896558df76d92e7a1f46ecffee7112b
+ languageName: node
+ linkType: hard
+
+"@types/babel__traverse@npm:*":
+ version: 7.28.0
+ resolution: "@types/babel__traverse@npm:7.28.0"
+ dependencies:
+ "@babel/types": "npm:^7.28.2"
+ checksum: 10c0/b52d7d4e8fc6a9018fe7361c4062c1c190f5778cf2466817cb9ed19d69fbbb54f9a85ffedeb748ed8062d2cf7d4cc088ee739848f47c57740de1c48cbf0d0994
+ languageName: node
+ linkType: hard
+
+"@types/chai@npm:^5.2.2":
+ version: 5.2.3
+ resolution: "@types/chai@npm:5.2.3"
+ dependencies:
+ "@types/deep-eql": "npm:*"
+ assertion-error: "npm:^2.0.1"
+ checksum: 10c0/e0ef1de3b6f8045a5e473e867c8565788c444271409d155588504840ad1a53611011f85072188c2833941189400228c1745d78323dac13fcede9c2b28bacfb2f
+ languageName: node
+ linkType: hard
+
+"@types/deep-eql@npm:*":
+ version: 4.0.2
+ resolution: "@types/deep-eql@npm:4.0.2"
+ checksum: 10c0/bf3f811843117900d7084b9d0c852da9a044d12eb40e6de73b552598a6843c21291a8a381b0532644574beecd5e3491c5ff3a0365ab86b15d59862c025384844
+ languageName: node
+ linkType: hard
+
+"@types/esrecurse@npm:^4.3.1":
+ version: 4.3.1
+ resolution: "@types/esrecurse@npm:4.3.1"
+ checksum: 10c0/90dad74d5da3ad27606d8e8e757322f33171cfeaa15ad558b615cf71bb2a516492d18f55f4816384685a3eb2412142e732bbae9a4a7cd2cf3deb7572aa4ebe03
+ languageName: node
+ linkType: hard
+
+"@types/estree@npm:1.0.9, @types/estree@npm:^1.0.0, @types/estree@npm:^1.0.6, @types/estree@npm:^1.0.8":
+ version: 1.0.9
+ resolution: "@types/estree@npm:1.0.9"
+ checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387
+ languageName: node
+ linkType: hard
+
+"@types/json-schema@npm:^7.0.15":
+ version: 7.0.15
+ resolution: "@types/json-schema@npm:7.0.15"
+ checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db
+ languageName: node
+ linkType: hard
+
+"@types/node@npm:22.7.5":
+ version: 22.7.5
+ resolution: "@types/node@npm:22.7.5"
+ dependencies:
+ undici-types: "npm:~6.19.2"
+ checksum: 10c0/cf11f74f1a26053ec58066616e3a8685b6bcd7259bc569738b8f752009f9f0f7f85a1b2d24908e5b0f752482d1e8b6babdf1fbb25758711ec7bb9500bfcd6e60
+ languageName: node
+ linkType: hard
+
+"@types/node@npm:^22.15.16":
+ version: 22.19.21
+ resolution: "@types/node@npm:22.19.21"
+ dependencies:
+ undici-types: "npm:~6.21.0"
+ checksum: 10c0/9a18a5fabaf75a55d63796d6086029c4f9fdd1c026a26d629804f5cc99b3302c749be321df29d7a7141dc227501ed645b5f9d01095d926f5d2c0e2230fcd3f59
+ languageName: node
+ linkType: hard
+
+"@types/parse-json@npm:^4.0.0":
+ version: 4.0.2
+ resolution: "@types/parse-json@npm:4.0.2"
+ checksum: 10c0/b1b863ac34a2c2172fbe0807a1ec4d5cb684e48d422d15ec95980b81475fac4fdb3768a8b13eef39130203a7c04340fc167bae057c7ebcafd7dec9fe6c36aeb1
+ languageName: node
+ linkType: hard
+
+"@types/prop-types@npm:^15.7.12":
+ version: 15.7.15
+ resolution: "@types/prop-types@npm:15.7.15"
+ checksum: 10c0/b59aad1ad19bf1733cf524fd4e618196c6c7690f48ee70a327eb450a42aab8e8a063fbe59ca0a5701aebe2d92d582292c0fb845ea57474f6a15f6994b0e260b2
+ languageName: node
+ linkType: hard
+
+"@types/react-dom@npm:^19.2.3":
+ version: 19.2.3
+ resolution: "@types/react-dom@npm:19.2.3"
+ peerDependencies:
+ "@types/react": ^19.2.0
+ checksum: 10c0/b486ebe0f4e2fb35e2e108df1d8fc0927ca5d6002d5771e8a739de11239fe62d0e207c50886185253c99eb9dedfeeb956ea7429e5ba17f6693c7acb4c02f8cd1
+ languageName: node
+ linkType: hard
+
+"@types/react-transition-group@npm:^4.4.10":
+ version: 4.4.12
+ resolution: "@types/react-transition-group@npm:4.4.12"
+ peerDependencies:
+ "@types/react": "*"
+ checksum: 10c0/0441b8b47c69312c89ec0760ba477ba1a0808a10ceef8dc1c64b1013ed78517332c30f18681b0ec0b53542731f1ed015169fed1d127cc91222638ed955478ec7
+ languageName: node
+ linkType: hard
+
+"@types/react@npm:^19.2.2":
+ version: 19.2.17
+ resolution: "@types/react@npm:19.2.17"
+ dependencies:
+ csstype: "npm:^3.2.2"
+ checksum: 10c0/bc2c4af96b3e480604424de70d5ebda90c5f4b485df471858c0bc2d7d70364b606ec3c4d8579f94f01aa0c6c0591f56bcf14cba5689f5eea4b74250ccdc3a232
+ languageName: node
+ linkType: hard
+
+"@types/trusted-types@npm:^2.0.2":
+ version: 2.0.7
+ resolution: "@types/trusted-types@npm:2.0.7"
+ checksum: 10c0/4c4855f10de7c6c135e0d32ce462419d8abbbc33713b31d294596c0cc34ae1fa6112a2f9da729c8f7a20707782b0d69da3b1f8df6645b0366d08825ca1522e0c
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/eslint-plugin@npm:8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/eslint-plugin@npm:8.61.0"
+ dependencies:
+ "@eslint-community/regexpp": "npm:^4.12.2"
+ "@typescript-eslint/scope-manager": "npm:8.61.0"
+ "@typescript-eslint/type-utils": "npm:8.61.0"
+ "@typescript-eslint/utils": "npm:8.61.0"
+ "@typescript-eslint/visitor-keys": "npm:8.61.0"
+ ignore: "npm:^7.0.5"
+ natural-compare: "npm:^1.4.0"
+ ts-api-utils: "npm:^2.5.0"
+ peerDependencies:
+ "@typescript-eslint/parser": ^8.61.0
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.1.0"
+ checksum: 10c0/1141253e18424a9a21d253dcf28e166894b6b914f2138b3e016144e451385f8e23f0f02028c7bd2d21c81953c52e478657aa9e5888cd0bdffdb8d68aab736878
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/parser@npm:8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/parser@npm:8.61.0"
+ dependencies:
+ "@typescript-eslint/scope-manager": "npm:8.61.0"
+ "@typescript-eslint/types": "npm:8.61.0"
+ "@typescript-eslint/typescript-estree": "npm:8.61.0"
+ "@typescript-eslint/visitor-keys": "npm:8.61.0"
+ debug: "npm:^4.4.3"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.1.0"
+ checksum: 10c0/39b122ab20a3b5fbd4e66874f60917b37c49f32eb987531797561d2f96b443e81546f1c9d03d44d37dede89098276e5d8d0f05c1e5f9e1b998f8cf6c24e8e5e7
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/project-service@npm:8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/project-service@npm:8.61.0"
+ dependencies:
+ "@typescript-eslint/tsconfig-utils": "npm:^8.61.0"
+ "@typescript-eslint/types": "npm:^8.61.0"
+ debug: "npm:^4.4.3"
+ peerDependencies:
+ typescript: ">=4.8.4 <6.1.0"
+ checksum: 10c0/8ff86b93bfcf103a42e8e996e11c46ded83da07d3a0bc8bd9ec4d536116d7f6253a404786510ab13847e69d6e185b17d15d7140075c26966e9b4f85c03296f21
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/scope-manager@npm:8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/scope-manager@npm:8.61.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.61.0"
+ "@typescript-eslint/visitor-keys": "npm:8.61.0"
+ checksum: 10c0/76cdf1c181ebbc706ddc8b2366e8ebfda529c13d82ff10c0797c96c0b38dd82f6471b24995f58ac267194a753b23d77452d925dd615b1e651922ddbe6e451c6b
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/tsconfig-utils@npm:8.61.0, @typescript-eslint/tsconfig-utils@npm:^8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/tsconfig-utils@npm:8.61.0"
+ peerDependencies:
+ typescript: ">=4.8.4 <6.1.0"
+ checksum: 10c0/b498675f14ef90a5730de7c58388eb2522085a56c3fcad42ad9f89320b96221eafb5b4f9650375f29092025153d03533e3f23ea8f45ce3bc95a57593059edef3
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/type-utils@npm:8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/type-utils@npm:8.61.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.61.0"
+ "@typescript-eslint/typescript-estree": "npm:8.61.0"
+ "@typescript-eslint/utils": "npm:8.61.0"
+ debug: "npm:^4.4.3"
+ ts-api-utils: "npm:^2.5.0"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.1.0"
+ checksum: 10c0/6347f451301ca7089500fe6eb3b98e5efd769e56ffda07eb735130fd209b9053c02e952b6fda7a15acf7851fb63f11fc50166ba8bd90513480732c599644b36b
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/types@npm:8.61.0, @typescript-eslint/types@npm:^8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/types@npm:8.61.0"
+ checksum: 10c0/c19407d66fb5ad26e2670cd272bee91d150087d917752422257759e17920220af27cd54593205e9726367a440a237bf8d27ed805cae0b282a79172161f007207
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/typescript-estree@npm:8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/typescript-estree@npm:8.61.0"
+ dependencies:
+ "@typescript-eslint/project-service": "npm:8.61.0"
+ "@typescript-eslint/tsconfig-utils": "npm:8.61.0"
+ "@typescript-eslint/types": "npm:8.61.0"
+ "@typescript-eslint/visitor-keys": "npm:8.61.0"
+ debug: "npm:^4.4.3"
+ minimatch: "npm:^10.2.2"
+ semver: "npm:^7.7.3"
+ tinyglobby: "npm:^0.2.15"
+ ts-api-utils: "npm:^2.5.0"
+ peerDependencies:
+ typescript: ">=4.8.4 <6.1.0"
+ checksum: 10c0/460819feeca826bfd895f821a5008c3eaa79b9495259641976fdc6ec319a7e9587bc28603437ea3d9a10c3b28037f1dea883cbe8d2858616dd33847e8db2179e
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/utils@npm:8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/utils@npm:8.61.0"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.9.1"
+ "@typescript-eslint/scope-manager": "npm:8.61.0"
+ "@typescript-eslint/types": "npm:8.61.0"
+ "@typescript-eslint/typescript-estree": "npm:8.61.0"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.1.0"
+ checksum: 10c0/f7b2241fc4defd40107243642e26697193707be12af1552c60bc414e71df1285c9cdff429f913b30ed08ae87a7e6e13388eaf05c1be5fb8310f6a63a6c4f7f73
+ languageName: node
+ linkType: hard
+
+"@typescript-eslint/visitor-keys@npm:8.61.0":
+ version: 8.61.0
+ resolution: "@typescript-eslint/visitor-keys@npm:8.61.0"
+ dependencies:
+ "@typescript-eslint/types": "npm:8.61.0"
+ eslint-visitor-keys: "npm:^5.0.0"
+ checksum: 10c0/5b656aed426a92dfc9a481f0bf535ceb47321303f476f32ba979f73423c739b51d7a5ad76c81d7be9df0a9beb361f4a11ff530dd86d59f41b89bb5f09af7be9f
+ languageName: node
+ linkType: hard
+
+"@vitejs/plugin-react@npm:^4.3.1":
+ version: 4.7.0
+ resolution: "@vitejs/plugin-react@npm:4.7.0"
+ dependencies:
+ "@babel/core": "npm:^7.28.0"
+ "@babel/plugin-transform-react-jsx-self": "npm:^7.27.1"
+ "@babel/plugin-transform-react-jsx-source": "npm:^7.27.1"
+ "@rolldown/pluginutils": "npm:1.0.0-beta.27"
+ "@types/babel__core": "npm:^7.20.5"
+ react-refresh: "npm:^0.17.0"
+ peerDependencies:
+ vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+ checksum: 10c0/692f23960972879485d647713663ec299c478222c96567d60285acf7c7dc5c178e71abfe9d2eefddef1eeb01514dacbc2ed68aad84628debf9c7116134734253
+ languageName: node
+ linkType: hard
+
+"@vitest/expect@npm:4.1.8":
+ version: 4.1.8
+ resolution: "@vitest/expect@npm:4.1.8"
+ dependencies:
+ "@standard-schema/spec": "npm:^1.1.0"
+ "@types/chai": "npm:^5.2.2"
+ "@vitest/spy": "npm:4.1.8"
+ "@vitest/utils": "npm:4.1.8"
+ chai: "npm:^6.2.2"
+ tinyrainbow: "npm:^3.1.0"
+ checksum: 10c0/f7bf6c720d2427c3bd0b35472ebd84d963be7d09ecf52a0fb05e8c4d5d0c9ee164a8c28eee6360947be1b245b47faefab54560cb98e5cb678c1c1074260b9149
+ languageName: node
+ linkType: hard
+
+"@vitest/mocker@npm:4.1.8":
+ version: 4.1.8
+ resolution: "@vitest/mocker@npm:4.1.8"
+ dependencies:
+ "@vitest/spy": "npm:4.1.8"
+ estree-walker: "npm:^3.0.3"
+ magic-string: "npm:^0.30.21"
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+ checksum: 10c0/f8cb2b8b55dc2cba0b2399aeee528b0187042f22cbc2d50a4fd6141f5aa246ebc41700f45dd1d73eca44ddfb57dcde48b2eb317bfbb1198f5ab2cc4fd04b2ea0
+ languageName: node
+ linkType: hard
+
+"@vitest/pretty-format@npm:4.1.8":
+ version: 4.1.8
+ resolution: "@vitest/pretty-format@npm:4.1.8"
+ dependencies:
+ tinyrainbow: "npm:^3.1.0"
+ checksum: 10c0/553c456692a4b9ae13cd116c234c74b4495e0f1a0d5c51ffc3fab8ea085e3550769967e29db79bdac0cf127b1bf88b7f70bfba3dcc72be6bddf834433e30cc91
+ languageName: node
+ linkType: hard
+
+"@vitest/runner@npm:4.1.8":
+ version: 4.1.8
+ resolution: "@vitest/runner@npm:4.1.8"
+ dependencies:
+ "@vitest/utils": "npm:4.1.8"
+ pathe: "npm:^2.0.3"
+ checksum: 10c0/706808a4b7b95ea9a9268fc152dd39e15a9a754f37c7990aea167486a9094caa913dae454771ae02c18dccfabd667f8cc38eed33a1307a79d32a89878b5bcce1
+ languageName: node
+ linkType: hard
+
+"@vitest/snapshot@npm:4.1.8":
+ version: 4.1.8
+ resolution: "@vitest/snapshot@npm:4.1.8"
+ dependencies:
+ "@vitest/pretty-format": "npm:4.1.8"
+ "@vitest/utils": "npm:4.1.8"
+ magic-string: "npm:^0.30.21"
+ pathe: "npm:^2.0.3"
+ checksum: 10c0/ba4c32112491d42d24986f921c50ede5edbdb4b7eafa16c72cf8d2c9ecc44121fdb3d9365236747a9841f0d6776affc6457470fcbb082df9dbc28c24792a0c6d
+ languageName: node
+ linkType: hard
+
+"@vitest/spy@npm:4.1.8":
+ version: 4.1.8
+ resolution: "@vitest/spy@npm:4.1.8"
+ checksum: 10c0/3c10c0325a09d16bc0e77c0be96c47c15416186e33332880c0d1dd0a51d51a866091067b81f2a2ef6fb422a7760e6cf15c04d91a0eca4d59f62e8c8401fa53fc
+ languageName: node
+ linkType: hard
+
+"@vitest/utils@npm:4.1.8":
+ version: 4.1.8
+ resolution: "@vitest/utils@npm:4.1.8"
+ dependencies:
+ "@vitest/pretty-format": "npm:4.1.8"
+ convert-source-map: "npm:^2.0.0"
+ tinyrainbow: "npm:^3.1.0"
+ checksum: 10c0/acda9d3d640c1ebc81afb358ac30589d7d7d583af81e2d09419f0af9cbe41f3ce0b90527326943bf0da51614be5fc31afcd32259f6beb32b3417999d6ef380f3
+ languageName: node
+ linkType: hard
+
+"@wagmi/connectors@npm:8.0.15, @wagmi/connectors@npm:>=5.9.9":
+ version: 8.0.15
+ resolution: "@wagmi/connectors@npm:8.0.15"
+ peerDependencies:
+ "@base-org/account": ^2.5.1
+ "@coinbase/wallet-sdk": ^4.3.6
+ "@metamask/connect-evm": ^1.3.0
+ "@safe-global/safe-apps-provider": ~0.18.6
+ "@safe-global/safe-apps-sdk": ^9.1.0
+ "@wagmi/core": 3.5.0
+ "@walletconnect/ethereum-provider": ^2.21.1
+ accounts: ~0.10
+ porto: ~0.2.35
+ typescript: ">=5.9.3"
+ viem: 2.x
+ peerDependenciesMeta:
+ "@base-org/account":
+ optional: true
+ "@coinbase/wallet-sdk":
+ optional: true
+ "@metamask/connect-evm":
+ optional: true
+ "@safe-global/safe-apps-provider":
+ optional: true
+ "@safe-global/safe-apps-sdk":
+ optional: true
+ "@walletconnect/ethereum-provider":
+ optional: true
+ accounts:
+ optional: true
+ porto:
+ optional: true
+ typescript:
+ optional: true
+ checksum: 10c0/dde3ca1828754ffe9bc34e83e0ca370671c9ebf611fcf25a967ebe4a309fc857b3dc18b441345cc66c9b42f62e89d36b3776b9e7b0bc0c42e94ad952a51952d1
+ languageName: node
+ linkType: hard
+
+"@wagmi/core@npm:3.5.0":
+ version: 3.5.0
+ resolution: "@wagmi/core@npm:3.5.0"
+ dependencies:
+ eventemitter3: "npm:5.0.1"
+ mipd: "npm:0.0.7"
+ zustand: "npm:5.0.0"
+ peerDependencies:
+ "@tanstack/query-core": ">=5.0.0"
+ accounts: ~0.12
+ typescript: ">=5.9.3"
+ viem: 2.x
+ peerDependenciesMeta:
+ "@tanstack/query-core":
+ optional: true
+ accounts:
+ optional: true
+ typescript:
+ optional: true
+ checksum: 10c0/7e5cae12247f3daef5599f16d141be330c183dfda2261d5a9a95c987b191a61f2cc8240632e19cc4f06c7f4db1584012eb925c0c7065b9e6da3f02c5e2f042ad
+ languageName: node
+ linkType: hard
+
+"@wallet-standard/base@npm:^1.1.0":
+ version: 1.1.1
+ resolution: "@wallet-standard/base@npm:1.1.1"
+ checksum: 10c0/b5ea7bef9d1c7a72e3737d48347d255e43a3fff666ee971c6b5f98bde43c6f3caa742c5c22c64687222ac8091ed917227332000297dffd65817cf355fbf73565
+ languageName: node
+ linkType: hard
+
+"@wallet-standard/wallet@npm:1.1.0":
+ version: 1.1.0
+ resolution: "@wallet-standard/wallet@npm:1.1.0"
+ dependencies:
+ "@wallet-standard/base": "npm:^1.1.0"
+ checksum: 10c0/aa53460568f209d4e38030ee5e98d4f6ea6fec159a1e7fb5a3ee81cf8d91c89f0be86b7188dbf0bb9803d10608bf88bd824f73cd6800823279738827304038e5
+ languageName: node
+ linkType: hard
+
+"@walletconnect/core@npm:2.23.7":
+ version: 2.23.7
+ resolution: "@walletconnect/core@npm:2.23.7"
+ dependencies:
+ "@walletconnect/heartbeat": "npm:1.2.2"
+ "@walletconnect/jsonrpc-provider": "npm:1.0.14"
+ "@walletconnect/jsonrpc-types": "npm:1.0.4"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/jsonrpc-ws-connection": "npm:1.0.16"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
+ "@walletconnect/logger": "npm:3.0.2"
+ "@walletconnect/relay-api": "npm:1.0.11"
+ "@walletconnect/relay-auth": "npm:1.1.0"
+ "@walletconnect/safe-json": "npm:1.0.2"
+ "@walletconnect/time": "npm:1.0.2"
+ "@walletconnect/types": "npm:2.23.7"
+ "@walletconnect/utils": "npm:2.23.7"
+ "@walletconnect/window-getters": "npm:1.0.1"
+ es-toolkit: "npm:1.44.0"
+ events: "npm:3.3.0"
+ uint8arrays: "npm:3.1.1"
+ checksum: 10c0/d2dde35f8b2e32fc8f1429e9767ed810cf2e7b1742f7cba9ef76746024a67d90a14bde4cb1cd124c90e7234df9cec3a71caff1fdd4f8fd4ed0c01f81de334670
+ languageName: node
+ linkType: hard
+
+"@walletconnect/environment@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "@walletconnect/environment@npm:1.0.1"
+ dependencies:
+ tslib: "npm:1.14.1"
+ checksum: 10c0/08eacce6452950a17f4209c443bd4db6bf7bddfc860593bdbd49edda9d08821696dee79e5617a954fbe90ff32c1d1f1691ef0c77455ed3e4201b328856a5e2f7
+ languageName: node
+ linkType: hard
+
+"@walletconnect/events@npm:1.0.1, @walletconnect/events@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "@walletconnect/events@npm:1.0.1"
+ dependencies:
+ keyvaluestorage-interface: "npm:^1.0.0"
+ tslib: "npm:1.14.1"
+ checksum: 10c0/919a97e1dacf7096aefe07af810362cfc190533a576dcfa21387295d825a3c3d5f90bedee73235b1b343f5c696f242d7bffc5ea3359d3833541349ca23f50df8
+ languageName: node
+ linkType: hard
+
+"@walletconnect/heartbeat@npm:1.2.2":
+ version: 1.2.2
+ resolution: "@walletconnect/heartbeat@npm:1.2.2"
+ dependencies:
+ "@walletconnect/events": "npm:^1.0.1"
+ "@walletconnect/time": "npm:^1.0.2"
+ events: "npm:^3.3.0"
+ checksum: 10c0/a97b07764c397fe3cd26e8ea4233ecc8a26049624df7edc05290d286266bc5ba1de740d12c50dc1b7e8605198c5974e34e2d5318087bd4e9db246e7b273f4592
+ languageName: node
+ linkType: hard
+
+"@walletconnect/jsonrpc-http-connection@npm:1.0.8":
+ version: 1.0.8
+ resolution: "@walletconnect/jsonrpc-http-connection@npm:1.0.8"
+ dependencies:
+ "@walletconnect/jsonrpc-utils": "npm:^1.0.6"
+ "@walletconnect/safe-json": "npm:^1.0.1"
+ cross-fetch: "npm:^3.1.4"
+ events: "npm:^3.3.0"
+ checksum: 10c0/cfac9ae74085d383ebc6edf075aeff01312818ac95e706cb8538ef4d4e6d82e75fb51529b3a9b65fa56a3f0f32a1738defad61713ed8a5f67cee25a79b6b4614
+ languageName: node
+ linkType: hard
+
+"@walletconnect/jsonrpc-provider@npm:1.0.14":
+ version: 1.0.14
+ resolution: "@walletconnect/jsonrpc-provider@npm:1.0.14"
+ dependencies:
+ "@walletconnect/jsonrpc-utils": "npm:^1.0.8"
+ "@walletconnect/safe-json": "npm:^1.0.2"
+ events: "npm:^3.3.0"
+ checksum: 10c0/9801bd516d81e92977b6add213da91e0e4a7a5915ad22685a4d2a733bab6199e9053485b76340cd724c7faa17a1b0eb842696247944fd57fb581488a2e1bed75
+ languageName: node
+ linkType: hard
+
+"@walletconnect/jsonrpc-types@npm:1.0.4, @walletconnect/jsonrpc-types@npm:^1.0.2, @walletconnect/jsonrpc-types@npm:^1.0.3":
+ version: 1.0.4
+ resolution: "@walletconnect/jsonrpc-types@npm:1.0.4"
+ dependencies:
+ events: "npm:^3.3.0"
+ keyvaluestorage-interface: "npm:^1.0.0"
+ checksum: 10c0/752978685b0596a4ba02e1b689d23873e464460e4f376c97ef63e6b3ab273658ca062de2bfcaa8a498d31db0c98be98c8bbfbe5142b256a4b3ef425e1707f353
+ languageName: node
+ linkType: hard
+
+"@walletconnect/jsonrpc-utils@npm:1.0.8, @walletconnect/jsonrpc-utils@npm:^1.0.6, @walletconnect/jsonrpc-utils@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "@walletconnect/jsonrpc-utils@npm:1.0.8"
+ dependencies:
+ "@walletconnect/environment": "npm:^1.0.1"
+ "@walletconnect/jsonrpc-types": "npm:^1.0.3"
+ tslib: "npm:1.14.1"
+ checksum: 10c0/e4a6bd801cf555bca775e03d961d1fe5ad0a22838e3496adda43ab4020a73d1b38de7096c06940e51f00fccccc734cd422fe4f1f7a8682302467b9c4d2a93d5d
+ languageName: node
+ linkType: hard
+
+"@walletconnect/jsonrpc-ws-connection@npm:1.0.16":
+ version: 1.0.16
+ resolution: "@walletconnect/jsonrpc-ws-connection@npm:1.0.16"
+ dependencies:
+ "@walletconnect/jsonrpc-utils": "npm:^1.0.6"
+ "@walletconnect/safe-json": "npm:^1.0.2"
+ events: "npm:^3.3.0"
+ ws: "npm:^7.5.1"
+ checksum: 10c0/30a09d24ffb6b4b291e2d1263504c4ea6c6797c992f5e6eb8033e58bd24749c80fd4e5ba6ffaadb28f8ced0c6b131213195b616f8983bb9f56aa7c91e83e6218
+ languageName: node
+ linkType: hard
+
+"@walletconnect/keyvaluestorage@npm:1.1.1":
+ version: 1.1.1
+ resolution: "@walletconnect/keyvaluestorage@npm:1.1.1"
+ dependencies:
+ "@walletconnect/safe-json": "npm:^1.0.1"
+ idb-keyval: "npm:^6.2.1"
+ unstorage: "npm:^1.9.0"
+ peerDependencies:
+ "@react-native-async-storage/async-storage": 1.x
+ peerDependenciesMeta:
+ "@react-native-async-storage/async-storage":
+ optional: true
+ checksum: 10c0/de2ec39d09ce99370865f7d7235b93c42b3e4fd3406bdbc644329eff7faea2722618aa88ffc4ee7d20b1d6806a8331261b65568187494cbbcceeedbe79dc30e8
+ languageName: node
+ linkType: hard
+
+"@walletconnect/logger@npm:3.0.2":
+ version: 3.0.2
+ resolution: "@walletconnect/logger@npm:3.0.2"
+ dependencies:
+ "@walletconnect/safe-json": "npm:^1.0.2"
+ pino: "npm:10.0.0"
+ checksum: 10c0/9a8dc232a3c9f7a6d35149c910326cfbef220677790e9e1c476c597be84db9ac19cf9df8ca835f04ad6facd0a2c83f056c90530e9b5a7c77d0e91a786027190c
+ languageName: node
+ linkType: hard
+
+"@walletconnect/relay-api@npm:1.0.11":
+ version: 1.0.11
+ resolution: "@walletconnect/relay-api@npm:1.0.11"
+ dependencies:
+ "@walletconnect/jsonrpc-types": "npm:^1.0.2"
+ checksum: 10c0/2595d7e68d3a93e7735e0b6204811762898b0ce1466e811d78be5bcec7ac1cde5381637615a99104099165bf63695da5ef9381d6ded29924a57a71b10712a91d
+ languageName: node
+ linkType: hard
+
+"@walletconnect/relay-auth@npm:1.1.0":
+ version: 1.1.0
+ resolution: "@walletconnect/relay-auth@npm:1.1.0"
+ dependencies:
+ "@noble/curves": "npm:1.8.0"
+ "@noble/hashes": "npm:1.7.0"
+ "@walletconnect/safe-json": "npm:^1.0.1"
+ "@walletconnect/time": "npm:^1.0.2"
+ uint8arrays: "npm:^3.0.0"
+ checksum: 10c0/29eb41ce8e70d581a3a8c8f771a70d2775d6feca548ac7ea85a792471d865a6d63be02f7deb1591056299abc2f77e1a7b5e7a0c7f95f0e48cd62e783047cee46
+ languageName: node
+ linkType: hard
+
+"@walletconnect/safe-json@npm:1.0.2, @walletconnect/safe-json@npm:^1.0.1, @walletconnect/safe-json@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "@walletconnect/safe-json@npm:1.0.2"
+ dependencies:
+ tslib: "npm:1.14.1"
+ checksum: 10c0/8689072018c1ff7ab58eca67bd6f06b53702738d8183d67bfe6ed220aeac804e41901b8ee0fb14299e83c70093fafb90a90992202d128d53b2832bb01b591752
+ languageName: node
+ linkType: hard
+
+"@walletconnect/sign-client@npm:2.23.7":
+ version: 2.23.7
+ resolution: "@walletconnect/sign-client@npm:2.23.7"
+ dependencies:
+ "@walletconnect/core": "npm:2.23.7"
+ "@walletconnect/events": "npm:1.0.1"
+ "@walletconnect/heartbeat": "npm:1.2.2"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/logger": "npm:3.0.2"
+ "@walletconnect/time": "npm:1.0.2"
+ "@walletconnect/types": "npm:2.23.7"
+ "@walletconnect/utils": "npm:2.23.7"
+ events: "npm:3.3.0"
+ checksum: 10c0/219d000be5b1c426c085fd2c28ec262a23b2c2e94a5dc370eb49145e133915f66a7c7841da4283e7a3af4acd29b4738d796c25e7b8e535363d93aab7ef5bc26d
+ languageName: node
+ linkType: hard
+
+"@walletconnect/time@npm:1.0.2, @walletconnect/time@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "@walletconnect/time@npm:1.0.2"
+ dependencies:
+ tslib: "npm:1.14.1"
+ checksum: 10c0/6317f93086e36daa3383cab4a8579c7d0bed665fb0f8e9016575200314e9ba5e61468f66142a7bb5b8489bb4c9250196576d90a60b6b00e0e856b5d0ab6ba474
+ languageName: node
+ linkType: hard
+
+"@walletconnect/types@npm:2.23.7":
+ version: 2.23.7
+ resolution: "@walletconnect/types@npm:2.23.7"
+ dependencies:
+ "@walletconnect/events": "npm:1.0.1"
+ "@walletconnect/heartbeat": "npm:1.2.2"
+ "@walletconnect/jsonrpc-types": "npm:1.0.4"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
+ "@walletconnect/logger": "npm:3.0.2"
+ events: "npm:3.3.0"
+ checksum: 10c0/cad0fb208b923a850c77de0a80af921ee1606ab5161285d8405eb21cdfecd80f09c03cc50086c06627d145250d9e46a40403998c55b232e435e55557fcf65458
+ languageName: node
+ linkType: hard
+
+"@walletconnect/universal-provider@npm:2.23.7":
+ version: 2.23.7
+ resolution: "@walletconnect/universal-provider@npm:2.23.7"
+ dependencies:
+ "@walletconnect/events": "npm:1.0.1"
+ "@walletconnect/jsonrpc-http-connection": "npm:1.0.8"
+ "@walletconnect/jsonrpc-provider": "npm:1.0.14"
+ "@walletconnect/jsonrpc-types": "npm:1.0.4"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
+ "@walletconnect/logger": "npm:3.0.2"
+ "@walletconnect/sign-client": "npm:2.23.7"
+ "@walletconnect/types": "npm:2.23.7"
+ "@walletconnect/utils": "npm:2.23.7"
+ es-toolkit: "npm:1.44.0"
+ events: "npm:3.3.0"
+ checksum: 10c0/6b33cc47c085be23705eba100335cfc6d831418ce7d96fb502df6615d83a7df8268ea1d622a5c8945c723d58a31a892d86871a481b8577a60e14f7b0df4aec86
+ languageName: node
+ linkType: hard
+
+"@walletconnect/utils@npm:2.23.7":
+ version: 2.23.7
+ resolution: "@walletconnect/utils@npm:2.23.7"
+ dependencies:
+ "@msgpack/msgpack": "npm:3.1.3"
+ "@noble/ciphers": "npm:1.3.0"
+ "@noble/curves": "npm:1.9.7"
+ "@noble/hashes": "npm:1.8.0"
+ "@scure/base": "npm:1.2.6"
+ "@walletconnect/jsonrpc-utils": "npm:1.0.8"
+ "@walletconnect/keyvaluestorage": "npm:1.1.1"
+ "@walletconnect/logger": "npm:3.0.2"
+ "@walletconnect/relay-api": "npm:1.0.11"
+ "@walletconnect/relay-auth": "npm:1.1.0"
+ "@walletconnect/safe-json": "npm:1.0.2"
+ "@walletconnect/time": "npm:1.0.2"
+ "@walletconnect/types": "npm:2.23.7"
+ "@walletconnect/window-getters": "npm:1.0.1"
+ "@walletconnect/window-metadata": "npm:1.0.1"
+ blakejs: "npm:1.2.1"
+ detect-browser: "npm:5.3.0"
+ ox: "npm:0.9.3"
+ uint8arrays: "npm:3.1.1"
+ checksum: 10c0/12903ae4ab4627d2e9c0e0ea04a6466f7616e5004d0c165c5577ab752a7fc5998e97e001e5cb5686a90f82d04012283bde355b706b60956ff236d5c358fe10d4
+ languageName: node
+ linkType: hard
+
+"@walletconnect/window-getters@npm:1.0.1, @walletconnect/window-getters@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "@walletconnect/window-getters@npm:1.0.1"
+ dependencies:
+ tslib: "npm:1.14.1"
+ checksum: 10c0/c3aedba77aa9274b8277c4189ec992a0a6000377e95656443b3872ca5b5fe77dd91170b1695027fc524dc20362ce89605d277569a0d9a5bedc841cdaf14c95df
+ languageName: node
+ linkType: hard
+
+"@walletconnect/window-metadata@npm:1.0.1":
+ version: 1.0.1
+ resolution: "@walletconnect/window-metadata@npm:1.0.1"
+ dependencies:
+ "@walletconnect/window-getters": "npm:^1.0.1"
+ tslib: "npm:1.14.1"
+ checksum: 10c0/f190e9bed77282d8ba868a4895f4d813e135f9bbecb8dd4aed988ab1b06992f78128ac19d7d073cf41d8a6a74d0c055cd725908ce0a894649fd25443ad934cf4
+ languageName: node
+ linkType: hard
+
+"@zeit/schemas@npm:2.36.0":
+ version: 2.36.0
+ resolution: "@zeit/schemas@npm:2.36.0"
+ checksum: 10c0/858c3ae46d23122f65d576013dc74f120af0ca7f3256c4b7077bcd12e952c8f71d8241a5165c23d18f6378e198a1db7e93bc8fae8ed0769e4cf4e2df953ee955
+ languageName: node
+ linkType: hard
+
+"abbrev@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "abbrev@npm:4.0.0"
+ checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5
+ languageName: node
+ linkType: hard
+
+"abitype@npm:1.0.6":
+ version: 1.0.6
+ resolution: "abitype@npm:1.0.6"
+ peerDependencies:
+ typescript: ">=5.0.4"
+ zod: ^3 >=3.22.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ zod:
+ optional: true
+ checksum: 10c0/30ca97010bbf34b9aaed401858eeb6bc30419f7ff11eb34adcb243522dd56c9d8a9d3d406aa5d4f60a7c263902f5136043005698e3f073ea882a4922d43a2929
+ languageName: node
+ linkType: hard
+
+"abitype@npm:1.2.3":
+ version: 1.2.3
+ resolution: "abitype@npm:1.2.3"
+ peerDependencies:
+ typescript: ">=5.0.4"
+ zod: ^3.22.0 || ^4.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ zod:
+ optional: true
+ checksum: 10c0/c8740de1ae4961723a153224a52cb9a34a57903fb5c2ad61d5082b0b79b53033c9335381aa8c663c7ec213c9955a9853f694d51e95baceedef27356f7745c634
+ languageName: node
+ linkType: hard
+
+"abitype@npm:^1.0.6, abitype@npm:^1.0.9, abitype@npm:^1.2.3":
+ version: 1.2.4
+ resolution: "abitype@npm:1.2.4"
+ peerDependencies:
+ typescript: ">=5.0.4"
+ zod: ^3.22.0 || ^4.0.0
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ zod:
+ optional: true
+ checksum: 10c0/b420d8368f92a9bf456bc51a15866af2d8463e2397006551148e654cef9ca786a31d487e27942992c5b5b443b8a6b8adb0efff0c96d58e2ed81b23940fe86b2f
+ languageName: node
+ linkType: hard
+
+"acorn-jsx@npm:^5.3.2":
+ version: 5.3.2
+ resolution: "acorn-jsx@npm:5.3.2"
+ peerDependencies:
+ acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
+ checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1
+ languageName: node
+ linkType: hard
+
+"acorn@npm:^8.16.0":
+ version: 8.17.0
+ resolution: "acorn@npm:8.17.0"
+ bin:
+ acorn: bin/acorn
+ checksum: 10c0/5dcefea5f8f023b6cc24cbe71fb5a8112b601d36c4fa07d14e4e6ffc2ee47383332c46b36c766d9437725aa6660156eae50efa0c838719823b50d7c327c4ed42
+ languageName: node
+ linkType: hard
+
+"aes-js@npm:4.0.0-beta.5":
+ version: 4.0.0-beta.5
+ resolution: "aes-js@npm:4.0.0-beta.5"
+ checksum: 10c0/444f4eefa1e602cbc4f2a3c644bc990f93fd982b148425fee17634da510586fc09da940dcf8ace1b2d001453c07ff042e55f7a0482b3cc9372bf1ef75479090c
+ languageName: node
+ linkType: hard
+
+"agent-base@npm:6":
+ version: 6.0.2
+ resolution: "agent-base@npm:6.0.2"
+ dependencies:
+ debug: "npm:4"
+ checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261
+ languageName: node
+ linkType: hard
+
+"ajv@npm:8.18.0":
+ version: 8.18.0
+ resolution: "ajv@npm:8.18.0"
+ dependencies:
+ fast-deep-equal: "npm:^3.1.3"
+ fast-uri: "npm:^3.0.1"
+ json-schema-traverse: "npm:^1.0.0"
+ require-from-string: "npm:^2.0.2"
+ checksum: 10c0/e7517c426173513a07391be951879932bdf3348feaebd2199f5b901c20f99d60db8cd1591502d4d551dc82f594e82a05c4fe1c70139b15b8937f7afeaed9532f
+ languageName: node
+ linkType: hard
+
+"ajv@npm:^6.14.0":
+ version: 6.15.0
+ resolution: "ajv@npm:6.15.0"
+ dependencies:
+ fast-deep-equal: "npm:^3.1.1"
+ fast-json-stable-stringify: "npm:^2.0.0"
+ json-schema-traverse: "npm:^0.4.1"
+ uri-js: "npm:^4.2.2"
+ checksum: 10c0/67966499dd272ecde1c2e467084411132891523d057487587879d39ac04207f4351b7b2324c83198013967fbfa632c1612adc960114a30770fbe07a0773b32c2
+ languageName: node
+ linkType: hard
+
+"ansi-align@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "ansi-align@npm:3.0.1"
+ dependencies:
+ string-width: "npm:^4.1.0"
+ checksum: 10c0/ad8b755a253a1bc8234eb341e0cec68a857ab18bf97ba2bda529e86f6e30460416523e0ec58c32e5c21f0ca470d779503244892873a5895dbd0c39c788e82467
+ languageName: node
+ linkType: hard
+
+"ansi-regex@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "ansi-regex@npm:5.0.1"
+ checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737
+ languageName: node
+ linkType: hard
+
+"ansi-regex@npm:^6.2.2":
+ version: 6.2.2
+ resolution: "ansi-regex@npm:6.2.2"
+ checksum: 10c0/05d4acb1d2f59ab2cf4b794339c7b168890d44dda4bf0ce01152a8da0213aca207802f930442ce8cd22d7a92f44907664aac6508904e75e038fa944d2601b30f
+ languageName: node
+ linkType: hard
+
+"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0":
+ version: 4.3.0
+ resolution: "ansi-styles@npm:4.3.0"
+ dependencies:
+ color-convert: "npm:^2.0.1"
+ checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041
+ languageName: node
+ linkType: hard
+
+"ansi-styles@npm:^6.1.0":
+ version: 6.2.3
+ resolution: "ansi-styles@npm:6.2.3"
+ checksum: 10c0/23b8a4ce14e18fb854693b95351e286b771d23d8844057ed2e7d083cd3e708376c3323707ec6a24365f7d7eda3ca00327fe04092e29e551499ec4c8b7bfac868
+ languageName: node
+ linkType: hard
+
+"anymatch@npm:^3.1.3":
+ version: 3.1.3
+ resolution: "anymatch@npm:3.1.3"
+ dependencies:
+ normalize-path: "npm:^3.0.0"
+ picomatch: "npm:^2.0.4"
+ checksum: 10c0/57b06ae984bc32a0d22592c87384cd88fe4511b1dd7581497831c56d41939c8a001b28e7b853e1450f2bf61992dfcaa8ae2d0d161a0a90c4fb631ef07098fbac
+ languageName: node
+ linkType: hard
+
+"arch@npm:^2.2.0":
+ version: 2.2.0
+ resolution: "arch@npm:2.2.0"
+ checksum: 10c0/4ceaf8d8207817c216ebc4469742052cb0a097bc45d9b7fcd60b7507220da545a28562ab5bdd4dfe87921bb56371a0805da4e10d704e01f93a15f83240f1284c
+ languageName: node
+ linkType: hard
+
+"arg@npm:5.0.2":
+ version: 5.0.2
+ resolution: "arg@npm:5.0.2"
+ checksum: 10c0/ccaf86f4e05d342af6666c569f844bec426595c567d32a8289715087825c2ca7edd8a3d204e4d2fb2aa4602e09a57d0c13ea8c9eea75aac3dbb4af5514e6800e
+ languageName: node
+ linkType: hard
+
+"asn1.js@npm:^4.10.1":
+ version: 4.10.1
+ resolution: "asn1.js@npm:4.10.1"
+ dependencies:
+ bn.js: "npm:^4.0.0"
+ inherits: "npm:^2.0.1"
+ minimalistic-assert: "npm:^1.0.0"
+ checksum: 10c0/afa7f3ab9e31566c80175a75b182e5dba50589dcc738aa485be42bdd787e2a07246a4b034d481861123cbe646a7656f318f4f1cad2e9e5e808a210d5d6feaa88
+ languageName: node
+ linkType: hard
+
+"assert@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "assert@npm:2.1.0"
+ dependencies:
+ call-bind: "npm:^1.0.2"
+ is-nan: "npm:^1.3.2"
+ object-is: "npm:^1.1.5"
+ object.assign: "npm:^4.1.4"
+ util: "npm:^0.12.5"
+ checksum: 10c0/7271a5da883c256a1fa690677bf1dd9d6aa882139f2bed1cd15da4f9e7459683e1da8e32a203d6cc6767e5e0f730c77a9532a87b896b4b0af0dd535f668775f0
+ languageName: node
+ linkType: hard
+
+"assertion-error@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "assertion-error@npm:2.0.1"
+ checksum: 10c0/bbbcb117ac6480138f8c93cf7f535614282dea9dc828f540cdece85e3c665e8f78958b96afac52f29ff883c72638e6a87d469ecc9fe5bc902df03ed24a55dba8
+ languageName: node
+ linkType: hard
+
+"async-function@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "async-function@npm:1.0.0"
+ checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73
+ languageName: node
+ linkType: hard
+
+"async-generator-function@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "async-generator-function@npm:1.0.0"
+ checksum: 10c0/2c50ef856c543ad500d8d8777d347e3c1ba623b93e99c9263ecc5f965c1b12d2a140e2ab6e43c3d0b85366110696f28114649411cbcd10b452a92a2318394186
+ languageName: node
+ linkType: hard
+
+"asynckit@npm:^0.4.0":
+ version: 0.4.0
+ resolution: "asynckit@npm:0.4.0"
+ checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d
+ languageName: node
+ linkType: hard
+
+"atomic-sleep@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "atomic-sleep@npm:1.0.0"
+ checksum: 10c0/e329a6665512736a9bbb073e1761b4ec102f7926cce35037753146a9db9c8104f5044c1662e4a863576ce544fb8be27cd2be6bc8c1a40147d03f31eb1cfb6e8a
+ languageName: node
+ linkType: hard
+
+"available-typed-arrays@npm:^1.0.7":
+ version: 1.0.7
+ resolution: "available-typed-arrays@npm:1.0.7"
+ dependencies:
+ possible-typed-array-names: "npm:^1.0.0"
+ checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2
+ languageName: node
+ linkType: hard
+
+"axios-retry@npm:^4.5.0":
+ version: 4.5.0
+ resolution: "axios-retry@npm:4.5.0"
+ dependencies:
+ is-retry-allowed: "npm:^2.2.0"
+ peerDependencies:
+ axios: 0.x || 1.x
+ checksum: 10c0/574e7b1bf24aad99b560042d232a932d51bfaa29b5a6d4612d748ed799a6f11a5afb2582792492c55d95842200cbdfbe3454027a8c1b9a2d3e895d13c3d03c10
+ languageName: node
+ linkType: hard
+
+"axios@npm:1.16.0":
+ version: 1.16.0
+ resolution: "axios@npm:1.16.0"
+ dependencies:
+ follow-redirects: "npm:^1.16.0"
+ form-data: "npm:^4.0.5"
+ proxy-from-env: "npm:^2.1.0"
+ checksum: 10c0/1c91a5221b77b76072026b4cc95ecdf38f7c3e33e63423abec09a85e6e9a12279637dcc9ac2ba1fc333e0c447fb3b0f46d7965acb5d7cea02d188e9c6d425c0b
+ languageName: node
+ linkType: hard
+
+"axios@npm:^1.4.0":
+ version: 1.17.0
+ resolution: "axios@npm:1.17.0"
+ dependencies:
+ follow-redirects: "npm:^1.16.0"
+ form-data: "npm:^4.0.5"
+ https-proxy-agent: "npm:^5.0.1"
+ proxy-from-env: "npm:^2.1.0"
+ checksum: 10c0/c4fa19ff3a3a63bde48beec03ad816b133b9a6385cccffffe172577ab18c6a70e299280d57f12c80c867fe25df41f92cb91d3a8258708a6d2be3e9e085f92650
+ languageName: node
+ linkType: hard
+
+"babel-plugin-macros@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "babel-plugin-macros@npm:3.1.0"
+ dependencies:
+ "@babel/runtime": "npm:^7.12.5"
+ cosmiconfig: "npm:^7.0.0"
+ resolve: "npm:^1.19.0"
+ checksum: 10c0/c6dfb15de96f67871d95bd2e8c58b0c81edc08b9b087dc16755e7157f357dc1090a8dc60ebab955e92587a9101f02eba07e730adc253a1e4cf593ca3ebd3839c
+ languageName: node
+ linkType: hard
+
+"balanced-match@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "balanced-match@npm:1.0.2"
+ checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee
+ languageName: node
+ linkType: hard
+
+"balanced-match@npm:^4.0.2":
+ version: 4.0.4
+ resolution: "balanced-match@npm:4.0.4"
+ checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b
+ languageName: node
+ linkType: hard
+
+"base-x@npm:^5.0.0":
+ version: 5.0.1
+ resolution: "base-x@npm:5.0.1"
+ checksum: 10c0/4ab6b02262b4fd499b147656f63ce7328bd5f895450401ce58a2f9e87828aea507cf0c320a6d8725389f86e8a48397562661c0bca28ef3276a22821b30f7a713
+ languageName: node
+ linkType: hard
+
+"base64-js@npm:^1.3.1":
+ version: 1.5.1
+ resolution: "base64-js@npm:1.5.1"
+ checksum: 10c0/f23823513b63173a001030fae4f2dabe283b99a9d324ade3ad3d148e218134676f1ee8568c877cd79ec1c53158dcf2d2ba527a97c606618928ba99dd930102bf
+ languageName: node
+ linkType: hard
+
+"baseline-browser-mapping@npm:^2.10.12":
+ version: 2.10.36
+ resolution: "baseline-browser-mapping@npm:2.10.36"
+ bin:
+ baseline-browser-mapping: dist/cli.cjs
+ checksum: 10c0/e9a739b48149341a8922355111a88130f1a9aa336f920fb31008f7bca7149b0fd250d50c8fd6247cd17719ac2a27befa71d0b45f96a772ba8aafe40a9a5f0924
+ languageName: node
+ linkType: hard
+
+"big.js@npm:6.2.2":
+ version: 6.2.2
+ resolution: "big.js@npm:6.2.2"
+ checksum: 10c0/58d204f6a1a92508dc2eb98d964e2cc6dabb37a3d9fc8a1f0b77a34dead7c11e17b173d9a6df2d5a7a0f78d5c80853a9ce6df29852da59ab10b088e981195165
+ languageName: node
+ linkType: hard
+
+"blakejs@npm:1.2.1":
+ version: 1.2.1
+ resolution: "blakejs@npm:1.2.1"
+ checksum: 10c0/c284557ce55b9c70203f59d381f1b85372ef08ee616a90162174d1291a45d3e5e809fdf9edab6e998740012538515152471dc4f1f9dbfa974ba2b9c1f7b9aad7
+ languageName: node
+ linkType: hard
+
+"bn.js@npm:^4.0.0, bn.js@npm:^4.1.0, bn.js@npm:^4.11.9":
+ version: 4.12.3
+ resolution: "bn.js@npm:4.12.3"
+ checksum: 10c0/53b6a4db8a583abd2522eacd480fece26fe6c4d8d35d03e5e11e15cb0873a3044eb4e3d1f9fef56f47eb008219e99ba5b620c26f57db49a687c6ab2cf848d50b
+ languageName: node
+ linkType: hard
+
+"bn.js@npm:^5.2.1, bn.js@npm:^5.2.3":
+ version: 5.2.3
+ resolution: "bn.js@npm:5.2.3"
+ checksum: 10c0/eef19cb9cf5e91e91e3e0f036b799ce6c72f79463c3934d62991c3dcdb58f6c94dc3d806495d9b0bf31cd121870ed79bb2115cea71b56c03e794fb71485031fa
+ languageName: node
+ linkType: hard
+
+"boxen@npm:7.0.0":
+ version: 7.0.0
+ resolution: "boxen@npm:7.0.0"
+ dependencies:
+ ansi-align: "npm:^3.0.1"
+ camelcase: "npm:^7.0.0"
+ chalk: "npm:^5.0.1"
+ cli-boxes: "npm:^3.0.0"
+ string-width: "npm:^5.1.2"
+ type-fest: "npm:^2.13.0"
+ widest-line: "npm:^4.0.1"
+ wrap-ansi: "npm:^8.0.1"
+ checksum: 10c0/af5e8bc3f1486ac50ec7485ae482eb1d4db905233d7ab2acafc406b576375be85bdc60b53fab99c842c42c274328b7219c7ae79adab13161f4c84e139f4b06ae
+ languageName: node
+ linkType: hard
+
+"brace-expansion@npm:^1.1.7":
+ version: 1.1.15
+ resolution: "brace-expansion@npm:1.1.15"
+ dependencies:
+ balanced-match: "npm:^1.0.0"
+ concat-map: "npm:0.0.1"
+ checksum: 10c0/648e273f57cfa9ed67d8a77bdb15b408205465d33da9331808ee3c188d8b55674c9cdbf1f320b65bc562e485e1263360ae62ad355e128e0435891f6430e795d7
+ languageName: node
+ linkType: hard
+
+"brace-expansion@npm:^5.0.5":
+ version: 5.0.6
+ resolution: "brace-expansion@npm:5.0.6"
+ dependencies:
+ balanced-match: "npm:^4.0.2"
+ checksum: 10c0/8c919869b90f61d533b341d3340be5ee4413232ea89b8246cbc2f38eb014f1d8182785c98a006eaf6111d02dc9eeffefdc240d5ac158625b2ed084dccd4bbf9b
+ languageName: node
+ linkType: hard
+
+"brorand@npm:^1.0.1, brorand@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "brorand@npm:1.1.0"
+ checksum: 10c0/6f366d7c4990f82c366e3878492ba9a372a73163c09871e80d82fb4ae0d23f9f8924cb8a662330308206e6b3b76ba1d528b4601c9ef73c2166b440b2ea3b7571
+ languageName: node
+ linkType: hard
+
+"browser-resolve@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "browser-resolve@npm:2.0.0"
+ dependencies:
+ resolve: "npm:^1.17.0"
+ checksum: 10c0/06c43adf3cb1939825ab9a4ac355b23272820ee421a20d04f62e0dabd9ea305e497b97f3ac027f87d53c366483aafe8673bbe1aaa5e41cd69eeafa65ac5fda6e
+ languageName: node
+ linkType: hard
+
+"browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "browserify-aes@npm:1.2.0"
+ dependencies:
+ buffer-xor: "npm:^1.0.3"
+ cipher-base: "npm:^1.0.0"
+ create-hash: "npm:^1.1.0"
+ evp_bytestokey: "npm:^1.0.3"
+ inherits: "npm:^2.0.1"
+ safe-buffer: "npm:^5.0.1"
+ checksum: 10c0/967f2ae60d610b7b252a4cbb55a7a3331c78293c94b4dd9c264d384ca93354c089b3af9c0dd023534efdc74ffbc82510f7ad4399cf82bc37bc07052eea485f18
+ languageName: node
+ linkType: hard
+
+"browserify-cipher@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "browserify-cipher@npm:1.0.1"
+ dependencies:
+ browserify-aes: "npm:^1.0.4"
+ browserify-des: "npm:^1.0.0"
+ evp_bytestokey: "npm:^1.0.0"
+ checksum: 10c0/aa256dcb42bc53a67168bbc94ab85d243b0a3b56109dee3b51230b7d010d9b78985ffc1fb36e145c6e4db151f888076c1cfc207baf1525d3e375cbe8187fe27d
+ languageName: node
+ linkType: hard
+
+"browserify-des@npm:^1.0.0":
+ version: 1.0.2
+ resolution: "browserify-des@npm:1.0.2"
+ dependencies:
+ cipher-base: "npm:^1.0.1"
+ des.js: "npm:^1.0.0"
+ inherits: "npm:^2.0.1"
+ safe-buffer: "npm:^5.1.2"
+ checksum: 10c0/943eb5d4045eff80a6cde5be4e5fbb1f2d5002126b5a4789c3c1aae3cdddb1eb92b00fb92277f512288e5c6af330730b1dbabcf7ce0923e749e151fcee5a074d
+ languageName: node
+ linkType: hard
+
+"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "browserify-rsa@npm:4.1.1"
+ dependencies:
+ bn.js: "npm:^5.2.1"
+ randombytes: "npm:^2.1.0"
+ safe-buffer: "npm:^5.2.1"
+ checksum: 10c0/b650ee1192e3d7f3d779edc06dd96ed8720362e72ac310c367b9d7fe35f7e8dbb983c1829142b2b3215458be8bf17c38adc7224920843024ed8cf39e19c513c0
+ languageName: node
+ linkType: hard
+
+"browserify-sign@npm:^4.2.3":
+ version: 4.2.6
+ resolution: "browserify-sign@npm:4.2.6"
+ dependencies:
+ bn.js: "npm:^5.2.3"
+ browserify-rsa: "npm:^4.1.1"
+ create-hash: "npm:^1.2.0"
+ create-hmac: "npm:^1.1.7"
+ elliptic: "npm:^6.6.1"
+ inherits: "npm:^2.0.4"
+ parse-asn1: "npm:^5.1.9"
+ readable-stream: "npm:^2.3.8"
+ safe-buffer: "npm:^5.2.1"
+ checksum: 10c0/3a2ba1c176c19144ad8887b7d23e4cea0a2ea0eedd70724f61040e5f7efc953ff07ede0793ff2ad9d6179e550d8f68936ce885b47d25da131091ea6b855fce5b
+ languageName: node
+ linkType: hard
+
+"browserify-zlib@npm:^0.2.0":
+ version: 0.2.0
+ resolution: "browserify-zlib@npm:0.2.0"
+ dependencies:
+ pako: "npm:~1.0.5"
+ checksum: 10c0/9ab10b6dc732c6c5ec8ebcbe5cb7fe1467f97402c9b2140113f47b5f187b9438f93a8e065d8baf8b929323c18324fbf1105af479ee86d9d36cab7d7ef3424ad9
+ languageName: node
+ linkType: hard
+
+"browserslist@npm:^4.24.0":
+ version: 4.28.2
+ resolution: "browserslist@npm:4.28.2"
+ dependencies:
+ baseline-browser-mapping: "npm:^2.10.12"
+ caniuse-lite: "npm:^1.0.30001782"
+ electron-to-chromium: "npm:^1.5.328"
+ node-releases: "npm:^2.0.36"
+ update-browserslist-db: "npm:^1.2.3"
+ bin:
+ browserslist: cli.js
+ checksum: 10c0/c0228b6330f785b7fa59d2d360124ec6d9322f96ed9f3ee1f873e33ecc9503a6f0ffc3b71191a28c4ff6e930b753b30043da1c33844a9548f3018d491f09ce60
+ languageName: node
+ linkType: hard
+
+"bs58@npm:6.0.0, bs58@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "bs58@npm:6.0.0"
+ dependencies:
+ base-x: "npm:^5.0.0"
+ checksum: 10c0/61910839746625ee4f69369f80e2634e2123726caaa1da6b3bcefcf7efcd9bdca86603360fed9664ffdabe0038c51e542c02581c72ca8d44f60329fe1a6bc8f4
+ languageName: node
+ linkType: hard
+
+"buffer-xor@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "buffer-xor@npm:1.0.3"
+ checksum: 10c0/fd269d0e0bf71ecac3146187cfc79edc9dbb054e2ee69b4d97dfb857c6d997c33de391696d04bdd669272751fa48e7872a22f3a6c7b07d6c0bc31dbe02a4075c
+ languageName: node
+ linkType: hard
+
+"buffer@npm:6.0.3":
+ version: 6.0.3
+ resolution: "buffer@npm:6.0.3"
+ dependencies:
+ base64-js: "npm:^1.3.1"
+ ieee754: "npm:^1.2.1"
+ checksum: 10c0/2a905fbbcde73cc5d8bd18d1caa23715d5f83a5935867c2329f0ac06104204ba7947be098fe1317fbd8830e26090ff8e764f08cd14fefc977bb248c3487bcbd0
+ languageName: node
+ linkType: hard
+
+"buffer@npm:^5.7.1":
+ version: 5.7.1
+ resolution: "buffer@npm:5.7.1"
+ dependencies:
+ base64-js: "npm:^1.3.1"
+ ieee754: "npm:^1.1.13"
+ checksum: 10c0/27cac81cff434ed2876058d72e7c4789d11ff1120ef32c9de48f59eab58179b66710c488987d295ae89a228f835fc66d088652dffeb8e3ba8659f80eb091d55e
+ languageName: node
+ linkType: hard
+
+"builtin-status-codes@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "builtin-status-codes@npm:3.0.0"
+ checksum: 10c0/c37bbba11a34c4431e56bd681b175512e99147defbe2358318d8152b3a01df7bf25e0305873947e5b350073d5ef41a364a22b37e48f1fb6d2fe6d5286a0f348c
+ languageName: node
+ linkType: hard
+
+"bytes@npm:3.0.0":
+ version: 3.0.0
+ resolution: "bytes@npm:3.0.0"
+ checksum: 10c0/91d42c38601c76460519ffef88371caacaea483a354c8e4b8808e7b027574436a5713337c003ea3de63ee4991c2a9a637884fdfe7f761760d746929d9e8fec60
+ languageName: node
+ linkType: hard
+
+"bytes@npm:3.1.2":
+ version: 3.1.2
+ resolution: "bytes@npm:3.1.2"
+ checksum: 10c0/76d1c43cbd602794ad8ad2ae94095cddeb1de78c5dddaa7005c51af10b0176c69971a6d88e805a90c2b6550d76636e43c40d8427a808b8645ede885de4a0358e
+ languageName: node
+ linkType: hard
+
+"call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "call-bind-apply-helpers@npm:1.0.2"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ function-bind: "npm:^1.1.2"
+ checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938
+ languageName: node
+ linkType: hard
+
+"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2, call-bind@npm:^1.0.7, call-bind@npm:^1.0.8, call-bind@npm:^1.0.9":
+ version: 1.0.9
+ resolution: "call-bind@npm:1.0.9"
+ dependencies:
+ call-bind-apply-helpers: "npm:^1.0.2"
+ es-define-property: "npm:^1.0.1"
+ get-intrinsic: "npm:^1.3.0"
+ set-function-length: "npm:^1.2.2"
+ checksum: 10c0/a6621f6da1444481919ce3b4983dff725691e0754d3507ae483ce56e54985f2da7d6f1df512c56dbf28660745cf1ca52553f1fc9aef5557f3ce353ef14fab714
+ languageName: node
+ linkType: hard
+
+"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "call-bound@npm:1.0.4"
+ dependencies:
+ call-bind-apply-helpers: "npm:^1.0.2"
+ get-intrinsic: "npm:^1.3.0"
+ checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644
+ languageName: node
+ linkType: hard
+
+"callsites@npm:^3.0.0":
+ version: 3.1.0
+ resolution: "callsites@npm:3.1.0"
+ checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301
+ languageName: node
+ linkType: hard
+
+"camelcase@npm:^5.0.0":
+ version: 5.3.1
+ resolution: "camelcase@npm:5.3.1"
+ checksum: 10c0/92ff9b443bfe8abb15f2b1513ca182d16126359ad4f955ebc83dc4ddcc4ef3fdd2c078bc223f2673dc223488e75c99b16cc4d056624374b799e6a1555cf61b23
+ languageName: node
+ linkType: hard
+
+"camelcase@npm:^7.0.0":
+ version: 7.0.1
+ resolution: "camelcase@npm:7.0.1"
+ checksum: 10c0/3adfc9a0e96d51b3a2f4efe90a84dad3e206aaa81dfc664f1bd568270e1bf3b010aad31f01db16345b4ffe1910e16ab411c7273a19a859addd1b98ef7cf4cfbd
+ languageName: node
+ linkType: hard
+
+"caniuse-lite@npm:^1.0.30001782":
+ version: 1.0.30001799
+ resolution: "caniuse-lite@npm:1.0.30001799"
+ checksum: 10c0/f24f9834edc7b60188f368ce44714695c3901bc4acb7f2a977dd9b7b697e39ddc0f9947fad6224a955b789f36a73432cb888d620aa7280d728f582d3bd8927a7
+ languageName: node
+ linkType: hard
+
+"chai@npm:^6.2.2":
+ version: 6.2.2
+ resolution: "chai@npm:6.2.2"
+ checksum: 10c0/e6c69e5f0c11dffe6ea13d0290936ebb68fcc1ad688b8e952e131df6a6d5797d5e860bc55cef1aca2e950c3e1f96daf79e9d5a70fb7dbaab4e46355e2635ed53
+ languageName: node
+ linkType: hard
+
+"chalk-template@npm:0.4.0":
+ version: 0.4.0
+ resolution: "chalk-template@npm:0.4.0"
+ dependencies:
+ chalk: "npm:^4.1.2"
+ checksum: 10c0/6a4cb4252966475f0bd3ee1cd8780146e1ba69f445e59c565cab891ac18708c8143515d23e2b0fb7e192574fb7608d429ea5b28f3b7b9507770ad6fccd3467e3
+ languageName: node
+ linkType: hard
+
+"chalk@npm:5.0.1":
+ version: 5.0.1
+ resolution: "chalk@npm:5.0.1"
+ checksum: 10c0/97898611ae40cfdeda9778901731df1404ea49fac0eb8253804e8d21b8064917df9823e29c0c9d766aab623da1a0b43d0e072d19a73d4f62d0d9115aef4c64e6
+ languageName: node
+ linkType: hard
+
+"chalk@npm:5.6.2, chalk@npm:^5.0.1":
+ version: 5.6.2
+ resolution: "chalk@npm:5.6.2"
+ checksum: 10c0/99a4b0f0e7991796b1e7e3f52dceb9137cae2a9dfc8fc0784a550dc4c558e15ab32ed70b14b21b52beb2679b4892b41a0aa44249bcb996f01e125d58477c6976
+ languageName: node
+ linkType: hard
+
+"chalk@npm:^4.1.2":
+ version: 4.1.2
+ resolution: "chalk@npm:4.1.2"
+ dependencies:
+ ansi-styles: "npm:^4.1.0"
+ supports-color: "npm:^7.1.0"
+ checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880
+ languageName: node
+ linkType: hard
+
+"charenc@npm:0.0.2":
+ version: 0.0.2
+ resolution: "charenc@npm:0.0.2"
+ checksum: 10c0/a45ec39363a16799d0f9365c8dd0c78e711415113c6f14787a22462ef451f5013efae8a28f1c058f81fc01f2a6a16955f7a5fd0cd56247ce94a45349c89877d8
+ languageName: node
+ linkType: hard
+
+"chokidar@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "chokidar@npm:5.0.0"
+ dependencies:
+ readdirp: "npm:^5.0.0"
+ checksum: 10c0/42fc907cb2a7ff5c9e220f84dae75380a77997f851c2a5e7865a2cf9ae45dd407a23557208cdcdbf3ac8c93341135a1748e4c48c31855f3bfa095e5159b6bdec
+ languageName: node
+ linkType: hard
+
+"chownr@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "chownr@npm:3.0.0"
+ checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10
+ languageName: node
+ linkType: hard
+
+"cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3":
+ version: 1.0.7
+ resolution: "cipher-base@npm:1.0.7"
+ dependencies:
+ inherits: "npm:^2.0.4"
+ safe-buffer: "npm:^5.2.1"
+ to-buffer: "npm:^1.2.2"
+ checksum: 10c0/53c5046a9d9b60c586479b8f13fde263c3f905e13f11e8e04c7a311ce399c91d9c3ec96642332e0de077d356e1014ee12bba96f74fbaad0de750f49122258836
+ languageName: node
+ linkType: hard
+
+"cli-boxes@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "cli-boxes@npm:3.0.0"
+ checksum: 10c0/4db3e8fbfaf1aac4fb3a6cbe5a2d3fa048bee741a45371b906439b9ffc821c6e626b0f108bdcd3ddf126a4a319409aedcf39a0730573ff050fdd7b6731e99fb9
+ languageName: node
+ linkType: hard
+
+"clipboardy@npm:3.0.0":
+ version: 3.0.0
+ resolution: "clipboardy@npm:3.0.0"
+ dependencies:
+ arch: "npm:^2.2.0"
+ execa: "npm:^5.1.1"
+ is-wsl: "npm:^2.2.0"
+ checksum: 10c0/299d66e13fcaccf656306e76d629ce6927eaba8ba58ae5328e3379ae627e469e29df8ef87408cdb234e2ad0e25f0024dd203393f7e59c67ae79772579c4de052
+ languageName: node
+ linkType: hard
+
+"cliui@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "cliui@npm:6.0.0"
+ dependencies:
+ string-width: "npm:^4.2.0"
+ strip-ansi: "npm:^6.0.0"
+ wrap-ansi: "npm:^6.2.0"
+ checksum: 10c0/35229b1bb48647e882104cac374c9a18e34bbf0bace0e2cf03000326b6ca3050d6b59545d91e17bfe3705f4a0e2988787aa5cde6331bf5cbbf0164732cef6492
+ languageName: node
+ linkType: hard
+
+"clsx@npm:1.2.1":
+ version: 1.2.1
+ resolution: "clsx@npm:1.2.1"
+ checksum: 10c0/34dead8bee24f5e96f6e7937d711978380647e936a22e76380290e35486afd8634966ce300fc4b74a32f3762c7d4c0303f442c3e259f4ce02374eb0c82834f27
+ languageName: node
+ linkType: hard
+
+"clsx@npm:^2.1.0, clsx@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "clsx@npm:2.1.1"
+ checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839
+ languageName: node
+ linkType: hard
+
+"color-convert@npm:^2.0.1":
+ version: 2.0.1
+ resolution: "color-convert@npm:2.0.1"
+ dependencies:
+ color-name: "npm:~1.1.4"
+ checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7
+ languageName: node
+ linkType: hard
+
+"color-name@npm:~1.1.4":
+ version: 1.1.4
+ resolution: "color-name@npm:1.1.4"
+ checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95
+ languageName: node
+ linkType: hard
+
+"combined-stream@npm:^1.0.8":
+ version: 1.0.8
+ resolution: "combined-stream@npm:1.0.8"
+ dependencies:
+ delayed-stream: "npm:~1.0.0"
+ checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5
+ languageName: node
+ linkType: hard
+
+"commander@npm:14.0.2":
+ version: 14.0.2
+ resolution: "commander@npm:14.0.2"
+ checksum: 10c0/245abd1349dbad5414cb6517b7b5c584895c02c4f7836ff5395f301192b8566f9796c82d7bd6c92d07eba8775fe4df86602fca5d86d8d10bcc2aded1e21c2aeb
+ languageName: node
+ linkType: hard
+
+"compressible@npm:~2.0.18":
+ version: 2.0.18
+ resolution: "compressible@npm:2.0.18"
+ dependencies:
+ mime-db: "npm:>= 1.43.0 < 2"
+ checksum: 10c0/8a03712bc9f5b9fe530cc5a79e164e665550d5171a64575d7dcf3e0395d7b4afa2d79ab176c61b5b596e28228b350dd07c1a2a6ead12fd81d1b6cd632af2fef7
+ languageName: node
+ linkType: hard
+
+"compression@npm:1.8.1":
+ version: 1.8.1
+ resolution: "compression@npm:1.8.1"
+ dependencies:
+ bytes: "npm:3.1.2"
+ compressible: "npm:~2.0.18"
+ debug: "npm:2.6.9"
+ negotiator: "npm:~0.6.4"
+ on-headers: "npm:~1.1.0"
+ safe-buffer: "npm:5.2.1"
+ vary: "npm:~1.1.2"
+ checksum: 10c0/85114b0b91c16594dc8c671cd9b05ef5e465066a60e5a4ed8b4551661303559a896ed17bb72c4234c04064e078f6ca86a34b8690349499a43f6fc4b844475da4
+ languageName: node
+ linkType: hard
+
+"concat-map@npm:0.0.1":
+ version: 0.0.1
+ resolution: "concat-map@npm:0.0.1"
+ checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f
+ languageName: node
+ linkType: hard
+
+"console-browserify@npm:^1.1.0":
+ version: 1.2.0
+ resolution: "console-browserify@npm:1.2.0"
+ checksum: 10c0/89b99a53b7d6cee54e1e64fa6b1f7ac24b844b4019c5d39db298637e55c1f4ffa5c165457ad984864de1379df2c8e1886cbbdac85d9dbb6876a9f26c3106f226
+ languageName: node
+ linkType: hard
+
+"constants-browserify@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "constants-browserify@npm:1.0.0"
+ checksum: 10c0/ab49b1d59a433ed77c964d90d19e08b2f77213fb823da4729c0baead55e3c597f8f97ebccfdfc47bd896d43854a117d114c849a6f659d9986420e97da0f83ac5
+ languageName: node
+ linkType: hard
+
+"content-disposition@npm:0.5.2":
+ version: 0.5.2
+ resolution: "content-disposition@npm:0.5.2"
+ checksum: 10c0/49eebaa0da1f9609b192e99d7fec31d1178cb57baa9d01f5b63b29787ac31e9d18b5a1033e854c68c9b6cce790e700a6f7fa60e43f95e2e416404e114a8f2f49
+ languageName: node
+ linkType: hard
+
+"convert-source-map@npm:^1.5.0":
+ version: 1.9.0
+ resolution: "convert-source-map@npm:1.9.0"
+ checksum: 10c0/281da55454bf8126cbc6625385928c43479f2060984180c42f3a86c8b8c12720a24eac260624a7d1e090004028d2dee78602330578ceec1a08e27cb8bb0a8a5b
+ languageName: node
+ linkType: hard
+
+"convert-source-map@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "convert-source-map@npm:2.0.0"
+ checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b
+ languageName: node
+ linkType: hard
+
+"cookie-es@npm:^1.2.3":
+ version: 1.2.3
+ resolution: "cookie-es@npm:1.2.3"
+ checksum: 10c0/429eae6f5130a7380ea024d787d7e1ecc644ca84f9c43dfb70f18761a831d2ba591d28f837ce350892cfff0857d711f3a4ad93a082637bceb478823c339c1a97
+ languageName: node
+ linkType: hard
+
+"cookie@npm:^1.0.1":
+ version: 1.1.1
+ resolution: "cookie@npm:1.1.1"
+ checksum: 10c0/79c4ddc0fcad9c4f045f826f42edf54bcc921a29586a4558b0898277fa89fb47be95bc384c2253f493af7b29500c830da28341274527328f18eba9f58afa112c
+ languageName: node
+ linkType: hard
+
+"core-util-is@npm:~1.0.0":
+ version: 1.0.3
+ resolution: "core-util-is@npm:1.0.3"
+ checksum: 10c0/90a0e40abbddfd7618f8ccd63a74d88deea94e77d0e8dbbea059fa7ebebb8fbb4e2909667fe26f3a467073de1a542ebe6ae4c73a73745ac5833786759cd906c9
+ languageName: node
+ linkType: hard
+
+"cosmiconfig@npm:^7.0.0":
+ version: 7.1.0
+ resolution: "cosmiconfig@npm:7.1.0"
+ dependencies:
+ "@types/parse-json": "npm:^4.0.0"
+ import-fresh: "npm:^3.2.1"
+ parse-json: "npm:^5.0.0"
+ path-type: "npm:^4.0.0"
+ yaml: "npm:^1.10.0"
+ checksum: 10c0/b923ff6af581638128e5f074a5450ba12c0300b71302398ea38dbeabd33bbcaa0245ca9adbedfcf284a07da50f99ede5658c80bb3e39e2ce770a99d28a21ef03
+ languageName: node
+ linkType: hard
+
+"create-ecdh@npm:^4.0.4":
+ version: 4.0.4
+ resolution: "create-ecdh@npm:4.0.4"
+ dependencies:
+ bn.js: "npm:^4.1.0"
+ elliptic: "npm:^6.5.3"
+ checksum: 10c0/77b11a51360fec9c3bce7a76288fc0deba4b9c838d5fb354b3e40c59194d23d66efe6355fd4b81df7580da0661e1334a235a2a5c040b7569ba97db428d466e7f
+ languageName: node
+ linkType: hard
+
+"create-hash@npm:^1.1.0, create-hash@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "create-hash@npm:1.2.0"
+ dependencies:
+ cipher-base: "npm:^1.0.1"
+ inherits: "npm:^2.0.1"
+ md5.js: "npm:^1.3.4"
+ ripemd160: "npm:^2.0.1"
+ sha.js: "npm:^2.4.0"
+ checksum: 10c0/d402e60e65e70e5083cb57af96d89567954d0669e90550d7cec58b56d49c4b193d35c43cec8338bc72358198b8cbf2f0cac14775b651e99238e1cf411490f915
+ languageName: node
+ linkType: hard
+
+"create-hmac@npm:^1.1.7":
+ version: 1.1.7
+ resolution: "create-hmac@npm:1.1.7"
+ dependencies:
+ cipher-base: "npm:^1.0.3"
+ create-hash: "npm:^1.1.0"
+ inherits: "npm:^2.0.1"
+ ripemd160: "npm:^2.0.0"
+ safe-buffer: "npm:^5.0.1"
+ sha.js: "npm:^2.4.8"
+ checksum: 10c0/24332bab51011652a9a0a6d160eed1e8caa091b802335324ae056b0dcb5acbc9fcf173cf10d128eba8548c3ce98dfa4eadaa01bd02f44a34414baee26b651835
+ languageName: node
+ linkType: hard
+
+"create-require@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "create-require@npm:1.1.1"
+ checksum: 10c0/157cbc59b2430ae9a90034a5f3a1b398b6738bf510f713edc4d4e45e169bc514d3d99dd34d8d01ca7ae7830b5b8b537e46ae8f3c8f932371b0875c0151d7ec91
+ languageName: node
+ linkType: hard
+
+"cross-fetch@npm:^3.1.4":
+ version: 3.2.0
+ resolution: "cross-fetch@npm:3.2.0"
+ dependencies:
+ node-fetch: "npm:^2.7.0"
+ checksum: 10c0/d8596adf0269130098a676f6739a0922f3cc7b71cc89729925411ebe851a87026171c82ea89154c4811c9867c01c44793205a52e618ce2684650218c7fbeeb9f
+ languageName: node
+ linkType: hard
+
+"cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6":
+ version: 7.0.6
+ resolution: "cross-spawn@npm:7.0.6"
+ dependencies:
+ path-key: "npm:^3.1.0"
+ shebang-command: "npm:^2.0.0"
+ which: "npm:^2.0.1"
+ checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1
+ languageName: node
+ linkType: hard
+
+"crossws@npm:^0.3.5":
+ version: 0.3.5
+ resolution: "crossws@npm:0.3.5"
+ dependencies:
+ uncrypto: "npm:^0.1.3"
+ checksum: 10c0/9e873546f0806606c4f775219f6811768fc3b3b0765ca8230722e849058ad098318af006e1faa39a8008c03009c37c519f6bccad41b0d78586237585c75fb38b
+ languageName: node
+ linkType: hard
+
+"crypt@npm:0.0.2":
+ version: 0.0.2
+ resolution: "crypt@npm:0.0.2"
+ checksum: 10c0/adbf263441dd801665d5425f044647533f39f4612544071b1471962209d235042fb703c27eea2795c7c53e1dfc242405173003f83cf4f4761a633d11f9653f18
+ languageName: node
+ linkType: hard
+
+"crypto-browserify@npm:^3.12.1":
+ version: 3.12.1
+ resolution: "crypto-browserify@npm:3.12.1"
+ dependencies:
+ browserify-cipher: "npm:^1.0.1"
+ browserify-sign: "npm:^4.2.3"
+ create-ecdh: "npm:^4.0.4"
+ create-hash: "npm:^1.2.0"
+ create-hmac: "npm:^1.1.7"
+ diffie-hellman: "npm:^5.0.3"
+ hash-base: "npm:~3.0.4"
+ inherits: "npm:^2.0.4"
+ pbkdf2: "npm:^3.1.2"
+ public-encrypt: "npm:^4.0.3"
+ randombytes: "npm:^2.1.0"
+ randomfill: "npm:^1.0.4"
+ checksum: 10c0/184a2def7b16628e79841243232ab5497f18d8e158ac21b7ce90ab172427d0a892a561280adc08f9d4d517bce8db2a5b335dc21abb970f787f8e874bd7b9db7d
+ languageName: node
+ linkType: hard
+
+"csstype@npm:^3.0.2, csstype@npm:^3.1.3, csstype@npm:^3.2.2":
+ version: 3.2.3
+ resolution: "csstype@npm:3.2.3"
+ checksum: 10c0/cd29c51e70fa822f1cecd8641a1445bed7063697469d35633b516e60fe8c1bde04b08f6c5b6022136bb669b64c63d4173af54864510fbb4ee23281801841a3ce
+ languageName: node
+ linkType: hard
+
+"dayjs@npm:1.11.13":
+ version: 1.11.13
+ resolution: "dayjs@npm:1.11.13"
+ checksum: 10c0/a3caf6ac8363c7dade9d1ee797848ddcf25c1ace68d9fe8678ecf8ba0675825430de5d793672ec87b24a69bf04a1544b176547b2539982275d5542a7955f35b7
+ languageName: node
+ linkType: hard
+
+"debug@npm:2.6.9":
+ version: 2.6.9
+ resolution: "debug@npm:2.6.9"
+ dependencies:
+ ms: "npm:2.0.0"
+ checksum: 10c0/121908fb839f7801180b69a7e218a40b5a0b718813b886b7d6bdb82001b931c938e2941d1e4450f33a1b1df1da653f5f7a0440c197f29fbf8a6e9d45ff6ef589
+ languageName: node
+ linkType: hard
+
+"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.4.3":
+ version: 4.4.3
+ resolution: "debug@npm:4.4.3"
+ dependencies:
+ ms: "npm:^2.1.3"
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+ checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6
+ languageName: node
+ linkType: hard
+
+"decamelize@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "decamelize@npm:1.2.0"
+ checksum: 10c0/85c39fe8fbf0482d4a1e224ef0119db5c1897f8503bcef8b826adff7a1b11414972f6fef2d7dec2ee0b4be3863cf64ac1439137ae9e6af23a3d8dcbe26a5b4b2
+ languageName: node
+ linkType: hard
+
+"deep-extend@npm:^0.6.0":
+ version: 0.6.0
+ resolution: "deep-extend@npm:0.6.0"
+ checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566
+ languageName: node
+ linkType: hard
+
+"deep-is@npm:^0.1.3":
+ version: 0.1.4
+ resolution: "deep-is@npm:0.1.4"
+ checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c
+ languageName: node
+ linkType: hard
+
+"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4":
+ version: 1.1.4
+ resolution: "define-data-property@npm:1.1.4"
+ dependencies:
+ es-define-property: "npm:^1.0.0"
+ es-errors: "npm:^1.3.0"
+ gopd: "npm:^1.0.1"
+ checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37
+ languageName: node
+ linkType: hard
+
+"define-properties@npm:^1.1.3, define-properties@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "define-properties@npm:1.2.1"
+ dependencies:
+ define-data-property: "npm:^1.0.1"
+ has-property-descriptors: "npm:^1.0.0"
+ object-keys: "npm:^1.1.1"
+ checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3
+ languageName: node
+ linkType: hard
+
+"defu@npm:^6.1.6":
+ version: 6.1.7
+ resolution: "defu@npm:6.1.7"
+ checksum: 10c0/e6635388103c8be3c574ac31302f6930e5e6eeedba32cb1b30cf993c7d9fb571aec2485446dfa23bfa63e55e66156fe109027a9695db82a50f931e91e8d4bedb
+ languageName: node
+ linkType: hard
+
+"delayed-stream@npm:~1.0.0":
+ version: 1.0.0
+ resolution: "delayed-stream@npm:1.0.0"
+ checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19
+ languageName: node
+ linkType: hard
+
+"des.js@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "des.js@npm:1.1.0"
+ dependencies:
+ inherits: "npm:^2.0.1"
+ minimalistic-assert: "npm:^1.0.0"
+ checksum: 10c0/671354943ad67493e49eb4c555480ab153edd7cee3a51c658082fcde539d2690ed2a4a0b5d1f401f9cde822edf3939a6afb2585f32c091f2d3a1b1665cd45236
+ languageName: node
+ linkType: hard
+
+"destr@npm:^2.0.5":
+ version: 2.0.5
+ resolution: "destr@npm:2.0.5"
+ checksum: 10c0/efabffe7312a45ad90d79975376be958c50069f1156b94c181199763a7f971e113bd92227c26b94a169c71ca7dbc13583b7e96e5164743969fc79e1ff153e646
+ languageName: node
+ linkType: hard
+
+"detect-browser@npm:5.3.0":
+ version: 5.3.0
+ resolution: "detect-browser@npm:5.3.0"
+ checksum: 10c0/88d49b70ce3836e7971345b2ebdd486ad0d457d1e4f066540d0c12f9210c8f731ccbed955fcc9af2f048f5d4629702a8e46bedf5bcad42ad49a3a0927bfd5a76
+ languageName: node
+ linkType: hard
+
+"detect-libc@npm:^2.0.3":
+ version: 2.1.2
+ resolution: "detect-libc@npm:2.1.2"
+ checksum: 10c0/acc675c29a5649fa1fb6e255f993b8ee829e510b6b56b0910666949c80c364738833417d0edb5f90e4e46be17228b0f2b66a010513984e18b15deeeac49369c4
+ languageName: node
+ linkType: hard
+
+"diffie-hellman@npm:^5.0.3":
+ version: 5.0.3
+ resolution: "diffie-hellman@npm:5.0.3"
+ dependencies:
+ bn.js: "npm:^4.1.0"
+ miller-rabin: "npm:^4.0.0"
+ randombytes: "npm:^2.0.0"
+ checksum: 10c0/ce53ccafa9ca544b7fc29b08a626e23a9b6562efc2a98559a0c97b4718937cebaa9b5d7d0a05032cc9c1435e9b3c1532b9e9bf2e0ede868525922807ad6e1ecf
+ languageName: node
+ linkType: hard
+
+"dijkstrajs@npm:^1.0.1":
+ version: 1.0.3
+ resolution: "dijkstrajs@npm:1.0.3"
+ checksum: 10c0/2183d61ac1f25062f3c3773f3ea8d9f45ba164a00e77e07faf8cc5750da966222d1e2ce6299c875a80f969190c71a0973042192c5624d5223e4ed196ff584c99
+ languageName: node
+ linkType: hard
+
+"dom-helpers@npm:^5.0.1":
+ version: 5.2.1
+ resolution: "dom-helpers@npm:5.2.1"
+ dependencies:
+ "@babel/runtime": "npm:^7.8.7"
+ csstype: "npm:^3.0.2"
+ checksum: 10c0/f735074d66dd759b36b158fa26e9d00c9388ee0e8c9b16af941c38f014a37fc80782de83afefd621681b19ac0501034b4f1c4a3bff5caa1b8667f0212b5e124c
+ languageName: node
+ linkType: hard
+
+"domain-browser@npm:4.22.0":
+ version: 4.22.0
+ resolution: "domain-browser@npm:4.22.0"
+ checksum: 10c0/2ef7eda6d2161038fda0c9aa4c9e18cc7a0baa89ea6be975d449527c2eefd4b608425db88508e2859acc472f46f402079274b24bd75e3fb506f28c5dba203129
+ languageName: node
+ linkType: hard
+
+"dunder-proto@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "dunder-proto@npm:1.0.1"
+ dependencies:
+ call-bind-apply-helpers: "npm:^1.0.1"
+ es-errors: "npm:^1.3.0"
+ gopd: "npm:^1.2.0"
+ checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031
+ languageName: node
+ linkType: hard
+
+"eastasianwidth@npm:^0.2.0":
+ version: 0.2.0
+ resolution: "eastasianwidth@npm:0.2.0"
+ checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39
+ languageName: node
+ linkType: hard
+
+"electron-to-chromium@npm:^1.5.328":
+ version: 1.5.372
+ resolution: "electron-to-chromium@npm:1.5.372"
+ checksum: 10c0/2071da5329cde5f2eb6c01b181ee4b61c09f8da38609b6203155357427dd3b5489e9cdb0b7686b0be4b0633d5df5c86a96d588fc599be4fb7a65169270a8568b
+ languageName: node
+ linkType: hard
+
+"elliptic@npm:^6.5.3, elliptic@npm:^6.5.7, elliptic@npm:^6.6.1":
+ version: 6.6.1
+ resolution: "elliptic@npm:6.6.1"
+ dependencies:
+ bn.js: "npm:^4.11.9"
+ brorand: "npm:^1.1.0"
+ hash.js: "npm:^1.0.0"
+ hmac-drbg: "npm:^1.0.1"
+ inherits: "npm:^2.0.4"
+ minimalistic-assert: "npm:^1.0.1"
+ minimalistic-crypto-utils: "npm:^1.0.1"
+ checksum: 10c0/8b24ef782eec8b472053793ea1e91ae6bee41afffdfcb78a81c0a53b191e715cbe1292aa07165958a9bbe675bd0955142560b1a007ffce7d6c765bcaf951a867
+ languageName: node
+ linkType: hard
+
+"emoji-regex@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "emoji-regex@npm:8.0.0"
+ checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010
+ languageName: node
+ linkType: hard
+
+"emoji-regex@npm:^9.2.2":
+ version: 9.2.2
+ resolution: "emoji-regex@npm:9.2.2"
+ checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639
+ languageName: node
+ linkType: hard
+
+"encode-utf8@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "encode-utf8@npm:1.0.3"
+ checksum: 10c0/6b3458b73e868113d31099d7508514a5c627d8e16d1e0542d1b4e3652299b8f1f590c468e2b9dcdf1b4021ee961f31839d0be9d70a7f2a8a043c63b63c9b3a88
+ languageName: node
+ linkType: hard
+
+"env-paths@npm:^2.2.0":
+ version: 2.2.1
+ resolution: "env-paths@npm:2.2.1"
+ checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4
+ languageName: node
+ linkType: hard
+
+"error-ex@npm:^1.3.1":
+ version: 1.3.4
+ resolution: "error-ex@npm:1.3.4"
+ dependencies:
+ is-arrayish: "npm:^0.2.1"
+ checksum: 10c0/b9e34ff4778b8f3b31a8377e1c654456f4c41aeaa3d10a1138c3b7635d8b7b2e03eb2475d46d8ae055c1f180a1063e100bffabf64ea7e7388b37735df5328664
+ languageName: node
+ linkType: hard
+
+"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "es-define-property@npm:1.0.1"
+ checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c
+ languageName: node
+ linkType: hard
+
+"es-errors@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "es-errors@npm:1.3.0"
+ checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85
+ languageName: node
+ linkType: hard
+
+"es-module-lexer@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "es-module-lexer@npm:2.1.0"
+ checksum: 10c0/93bcf2454fa72d67fe3ccd0abef8ce7933f5840a319513418a643dd8e9c6aa8f49709cecfae02ded722805dd327232d30723a807cc52e6809d6ac697c62c29fb
+ languageName: node
+ linkType: hard
+
+"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1":
+ version: 1.1.2
+ resolution: "es-object-atoms@npm:1.1.2"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ checksum: 10c0/1772861f094f739d6f41b579cfb9a18579daffeb434552a370a5fbef50a32d22227e27b63fdbb757b7ddd429d1b42fe52ccae7966d9302a2ec221b6f1b41bbc4
+ languageName: node
+ linkType: hard
+
+"es-set-tostringtag@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "es-set-tostringtag@npm:2.1.0"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.6"
+ has-tostringtag: "npm:^1.0.2"
+ hasown: "npm:^2.0.2"
+ checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af
+ languageName: node
+ linkType: hard
+
+"es-toolkit@npm:1.44.0":
+ version: 1.44.0
+ resolution: "es-toolkit@npm:1.44.0"
+ dependenciesMeta:
+ "@trivago/prettier-plugin-sort-imports@4.3.0":
+ unplugged: true
+ prettier-plugin-sort-re-exports@0.0.1:
+ unplugged: true
+ checksum: 10c0/b80ff52ddc85ba26914cda57c9d4e46379ccc38c60dc097ef0d065cc0b20f95a16cf8d537969eea600b51c6687b5900a6cce67489db16d5ccc14d47597a29c34
+ languageName: node
+ linkType: hard
+
+"esbuild@npm:^0.25.0":
+ version: 0.25.12
+ resolution: "esbuild@npm:0.25.12"
+ dependencies:
+ "@esbuild/aix-ppc64": "npm:0.25.12"
+ "@esbuild/android-arm": "npm:0.25.12"
+ "@esbuild/android-arm64": "npm:0.25.12"
+ "@esbuild/android-x64": "npm:0.25.12"
+ "@esbuild/darwin-arm64": "npm:0.25.12"
+ "@esbuild/darwin-x64": "npm:0.25.12"
+ "@esbuild/freebsd-arm64": "npm:0.25.12"
+ "@esbuild/freebsd-x64": "npm:0.25.12"
+ "@esbuild/linux-arm": "npm:0.25.12"
+ "@esbuild/linux-arm64": "npm:0.25.12"
+ "@esbuild/linux-ia32": "npm:0.25.12"
+ "@esbuild/linux-loong64": "npm:0.25.12"
+ "@esbuild/linux-mips64el": "npm:0.25.12"
+ "@esbuild/linux-ppc64": "npm:0.25.12"
+ "@esbuild/linux-riscv64": "npm:0.25.12"
+ "@esbuild/linux-s390x": "npm:0.25.12"
+ "@esbuild/linux-x64": "npm:0.25.12"
+ "@esbuild/netbsd-arm64": "npm:0.25.12"
+ "@esbuild/netbsd-x64": "npm:0.25.12"
+ "@esbuild/openbsd-arm64": "npm:0.25.12"
+ "@esbuild/openbsd-x64": "npm:0.25.12"
+ "@esbuild/openharmony-arm64": "npm:0.25.12"
+ "@esbuild/sunos-x64": "npm:0.25.12"
+ "@esbuild/win32-arm64": "npm:0.25.12"
+ "@esbuild/win32-ia32": "npm:0.25.12"
+ "@esbuild/win32-x64": "npm:0.25.12"
+ dependenciesMeta:
+ "@esbuild/aix-ppc64":
+ optional: true
+ "@esbuild/android-arm":
+ optional: true
+ "@esbuild/android-arm64":
+ optional: true
+ "@esbuild/android-x64":
+ optional: true
+ "@esbuild/darwin-arm64":
+ optional: true
+ "@esbuild/darwin-x64":
+ optional: true
+ "@esbuild/freebsd-arm64":
+ optional: true
+ "@esbuild/freebsd-x64":
+ optional: true
+ "@esbuild/linux-arm":
+ optional: true
+ "@esbuild/linux-arm64":
+ optional: true
+ "@esbuild/linux-ia32":
+ optional: true
+ "@esbuild/linux-loong64":
+ optional: true
+ "@esbuild/linux-mips64el":
+ optional: true
+ "@esbuild/linux-ppc64":
+ optional: true
+ "@esbuild/linux-riscv64":
+ optional: true
+ "@esbuild/linux-s390x":
+ optional: true
+ "@esbuild/linux-x64":
+ optional: true
+ "@esbuild/netbsd-arm64":
+ optional: true
+ "@esbuild/netbsd-x64":
+ optional: true
+ "@esbuild/openbsd-arm64":
+ optional: true
+ "@esbuild/openbsd-x64":
+ optional: true
+ "@esbuild/openharmony-arm64":
+ optional: true
+ "@esbuild/sunos-x64":
+ optional: true
+ "@esbuild/win32-arm64":
+ optional: true
+ "@esbuild/win32-ia32":
+ optional: true
+ "@esbuild/win32-x64":
+ optional: true
+ bin:
+ esbuild: bin/esbuild
+ checksum: 10c0/c205357531423220a9de8e1e6c6514242bc9b1666e762cd67ccdf8fdfdc3f1d0bd76f8d9383958b97ad4c953efdb7b6e8c1f9ca5951cd2b7c5235e8755b34a6b
+ languageName: node
+ linkType: hard
+
+"escalade@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "escalade@npm:3.2.0"
+ checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65
+ languageName: node
+ linkType: hard
+
+"escape-string-regexp@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "escape-string-regexp@npm:4.0.0"
+ checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-react-hooks@npm:^5.1.0":
+ version: 5.2.0
+ resolution: "eslint-plugin-react-hooks@npm:5.2.0"
+ peerDependencies:
+ eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0
+ checksum: 10c0/1c8d50fa5984c6dea32470651807d2922cc3934cf3425e78f84a24c2dfd972e7f019bee84aefb27e0cf2c13fea0ac1d4473267727408feeb1c56333ca1489385
+ languageName: node
+ linkType: hard
+
+"eslint-plugin-react-refresh@npm:^0.4.11":
+ version: 0.4.26
+ resolution: "eslint-plugin-react-refresh@npm:0.4.26"
+ peerDependencies:
+ eslint: ">=8.40"
+ checksum: 10c0/11c2b25b7a7025e621b02970c4cf3815b0b77486027df9f8bb731cc52972156804fd163b0f99404b33e36a3c60cd1a1be8199ba64c66b5276da3173bbb5ab6e7
+ languageName: node
+ linkType: hard
+
+"eslint-scope@npm:^9.1.2":
+ version: 9.1.2
+ resolution: "eslint-scope@npm:9.1.2"
+ dependencies:
+ "@types/esrecurse": "npm:^4.3.1"
+ "@types/estree": "npm:^1.0.8"
+ esrecurse: "npm:^4.3.0"
+ estraverse: "npm:^5.2.0"
+ checksum: 10c0/9fb8bca5a73e5741efb6cec84467027b6cb6f4203ff9b43a938e272c5cd30800bde46a5c20dfd1609f840225f0b62b7673be391b20acadf8658ca9fa4729b3dd
+ languageName: node
+ linkType: hard
+
+"eslint-visitor-keys@npm:^3.4.3":
+ version: 3.4.3
+ resolution: "eslint-visitor-keys@npm:3.4.3"
+ checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820
+ languageName: node
+ linkType: hard
+
+"eslint-visitor-keys@npm:^5.0.0, eslint-visitor-keys@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "eslint-visitor-keys@npm:5.0.1"
+ checksum: 10c0/16190bdf2cbae40a1109384c94450c526a79b0b9c3cb21e544256ed85ac48a4b84db66b74a6561d20fe6ab77447f150d711c2ad5ad74df4fcc133736bce99678
+ languageName: node
+ linkType: hard
+
+"eslint@npm:^10.1.0":
+ version: 10.4.1
+ resolution: "eslint@npm:10.4.1"
+ dependencies:
+ "@eslint-community/eslint-utils": "npm:^4.8.0"
+ "@eslint-community/regexpp": "npm:^4.12.2"
+ "@eslint/config-array": "npm:^0.23.5"
+ "@eslint/config-helpers": "npm:^0.6.0"
+ "@eslint/core": "npm:^1.2.1"
+ "@eslint/plugin-kit": "npm:^0.7.2"
+ "@humanfs/node": "npm:^0.16.6"
+ "@humanwhocodes/module-importer": "npm:^1.0.1"
+ "@humanwhocodes/retry": "npm:^0.4.2"
+ "@types/estree": "npm:^1.0.6"
+ ajv: "npm:^6.14.0"
+ cross-spawn: "npm:^7.0.6"
+ debug: "npm:^4.3.2"
+ escape-string-regexp: "npm:^4.0.0"
+ eslint-scope: "npm:^9.1.2"
+ eslint-visitor-keys: "npm:^5.0.1"
+ espree: "npm:^11.2.0"
+ esquery: "npm:^1.7.0"
+ esutils: "npm:^2.0.2"
+ fast-deep-equal: "npm:^3.1.3"
+ file-entry-cache: "npm:^8.0.0"
+ find-up: "npm:^5.0.0"
+ glob-parent: "npm:^6.0.2"
+ ignore: "npm:^5.2.0"
+ imurmurhash: "npm:^0.1.4"
+ is-glob: "npm:^4.0.0"
+ json-stable-stringify-without-jsonify: "npm:^1.0.1"
+ minimatch: "npm:^10.2.4"
+ natural-compare: "npm:^1.4.0"
+ optionator: "npm:^0.9.3"
+ peerDependencies:
+ jiti: "*"
+ peerDependenciesMeta:
+ jiti:
+ optional: true
+ bin:
+ eslint: bin/eslint.js
+ checksum: 10c0/c5e6bb5158fb0d62f090c8e2671de5c98283bbb37a58b6d871bada63af3018e683483c96c1a92272fedc8f4e5279a273a0451acf0da67c487406639daa05aedb
+ languageName: node
+ linkType: hard
+
+"espree@npm:^11.2.0":
+ version: 11.2.0
+ resolution: "espree@npm:11.2.0"
+ dependencies:
+ acorn: "npm:^8.16.0"
+ acorn-jsx: "npm:^5.3.2"
+ eslint-visitor-keys: "npm:^5.0.1"
+ checksum: 10c0/cf87e18ffd9dc113eb8d16588e7757701bc10c9934a71cce8b89c2611d51672681a918307bd6b19ac3ccd0e7ba1cbccc2f815b36b52fa7e73097b251014c3d81
+ languageName: node
+ linkType: hard
+
+"esquery@npm:^1.7.0":
+ version: 1.7.0
+ resolution: "esquery@npm:1.7.0"
+ dependencies:
+ estraverse: "npm:^5.1.0"
+ checksum: 10c0/77d5173db450b66f3bc685d11af4c90cffeedb340f34a39af96d43509a335ce39c894fd79233df32d38f5e4e219fa0f7076f6ec90bae8320170ba082c0db4793
+ languageName: node
+ linkType: hard
+
+"esrecurse@npm:^4.3.0":
+ version: 4.3.0
+ resolution: "esrecurse@npm:4.3.0"
+ dependencies:
+ estraverse: "npm:^5.2.0"
+ checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5
+ languageName: node
+ linkType: hard
+
+"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0":
+ version: 5.3.0
+ resolution: "estraverse@npm:5.3.0"
+ checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107
+ languageName: node
+ linkType: hard
+
+"estree-walker@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "estree-walker@npm:2.0.2"
+ checksum: 10c0/53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af
+ languageName: node
+ linkType: hard
+
+"estree-walker@npm:^3.0.3":
+ version: 3.0.3
+ resolution: "estree-walker@npm:3.0.3"
+ dependencies:
+ "@types/estree": "npm:^1.0.0"
+ checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d
+ languageName: node
+ linkType: hard
+
+"esutils@npm:^2.0.2":
+ version: 2.0.3
+ resolution: "esutils@npm:2.0.3"
+ checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7
+ languageName: node
+ linkType: hard
+
+"ethers@npm:^6.16.0, ethers@npm:~6.16.0":
+ version: 6.16.0
+ resolution: "ethers@npm:6.16.0"
+ dependencies:
+ "@adraffy/ens-normalize": "npm:1.10.1"
+ "@noble/curves": "npm:1.2.0"
+ "@noble/hashes": "npm:1.3.2"
+ "@types/node": "npm:22.7.5"
+ aes-js: "npm:4.0.0-beta.5"
+ tslib: "npm:2.7.0"
+ ws: "npm:8.17.1"
+ checksum: 10c0/65c0ff7016b1592b1961c3b68508902b89fc75e1ad025bab3a722df1b5699fd077551875a7285e65b2d0cfea9a85b2459bb84010a0fa4e4494d231848aee3a73
+ languageName: node
+ linkType: hard
+
+"eventemitter3@npm:5.0.1":
+ version: 5.0.1
+ resolution: "eventemitter3@npm:5.0.1"
+ checksum: 10c0/4ba5c00c506e6c786b4d6262cfbce90ddc14c10d4667e5c83ae993c9de88aa856033994dd2b35b83e8dc1170e224e66a319fa80adc4c32adcd2379bbc75da814
+ languageName: node
+ linkType: hard
+
+"events@npm:3.3.0, events@npm:^3.0.0, events@npm:^3.3.0":
+ version: 3.3.0
+ resolution: "events@npm:3.3.0"
+ checksum: 10c0/d6b6f2adbccbcda74ddbab52ed07db727ef52e31a61ed26db9feb7dc62af7fc8e060defa65e5f8af9449b86b52cc1a1f6a79f2eafcf4e62add2b7a1fa4a432f6
+ languageName: node
+ linkType: hard
+
+"evp_bytestokey@npm:^1.0.0, evp_bytestokey@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "evp_bytestokey@npm:1.0.3"
+ dependencies:
+ md5.js: "npm:^1.3.4"
+ node-gyp: "npm:latest"
+ safe-buffer: "npm:^5.1.1"
+ checksum: 10c0/77fbe2d94a902a80e9b8f5a73dcd695d9c14899c5e82967a61b1fc6cbbb28c46552d9b127cff47c45fcf684748bdbcfa0a50410349109de87ceb4b199ef6ee99
+ languageName: node
+ linkType: hard
+
+"execa@npm:^5.1.1":
+ version: 5.1.1
+ resolution: "execa@npm:5.1.1"
+ dependencies:
+ cross-spawn: "npm:^7.0.3"
+ get-stream: "npm:^6.0.0"
+ human-signals: "npm:^2.1.0"
+ is-stream: "npm:^2.0.0"
+ merge-stream: "npm:^2.0.0"
+ npm-run-path: "npm:^4.0.1"
+ onetime: "npm:^5.1.2"
+ signal-exit: "npm:^3.0.3"
+ strip-final-newline: "npm:^2.0.0"
+ checksum: 10c0/c8e615235e8de4c5addf2fa4c3da3e3aa59ce975a3e83533b4f6a71750fb816a2e79610dc5f1799b6e28976c9ae86747a36a606655bf8cb414a74d8d507b304f
+ languageName: node
+ linkType: hard
+
+"expect-type@npm:^1.3.0":
+ version: 1.3.0
+ resolution: "expect-type@npm:1.3.0"
+ checksum: 10c0/8412b3fe4f392c420ab41dae220b09700e4e47c639a29ba7ba2e83cc6cffd2b4926f7ac9e47d7e277e8f4f02acda76fd6931cb81fd2b382fa9477ef9ada953fd
+ languageName: node
+ linkType: hard
+
+"exponential-backoff@npm:^3.1.1":
+ version: 3.1.3
+ resolution: "exponential-backoff@npm:3.1.3"
+ checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267
+ languageName: node
+ linkType: hard
+
+"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3":
+ version: 3.1.3
+ resolution: "fast-deep-equal@npm:3.1.3"
+ checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0
+ languageName: node
+ linkType: hard
+
+"fast-json-stable-stringify@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "fast-json-stable-stringify@npm:2.1.0"
+ checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b
+ languageName: node
+ linkType: hard
+
+"fast-levenshtein@npm:^2.0.6":
+ version: 2.0.6
+ resolution: "fast-levenshtein@npm:2.0.6"
+ checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4
+ languageName: node
+ linkType: hard
+
+"fast-uri@npm:^3.0.1":
+ version: 3.1.2
+ resolution: "fast-uri@npm:3.1.2"
+ checksum: 10c0/5b35641895959f3f7ab7a7b1b5542bded159346f25ec9f256817b206d50b64eda5828e90d605a2e2fc645c90519a7259c2bab2c942ee728c88b88e5be21b090d
+ languageName: node
+ linkType: hard
+
+"fdir@npm:^6.4.4, fdir@npm:^6.5.0":
+ version: 6.5.0
+ resolution: "fdir@npm:6.5.0"
+ peerDependencies:
+ picomatch: ^3 || ^4
+ peerDependenciesMeta:
+ picomatch:
+ optional: true
+ checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f
+ languageName: node
+ linkType: hard
+
+"file-entry-cache@npm:^8.0.0":
+ version: 8.0.0
+ resolution: "file-entry-cache@npm:8.0.0"
+ dependencies:
+ flat-cache: "npm:^4.0.0"
+ checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638
+ languageName: node
+ linkType: hard
+
+"find-root@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "find-root@npm:1.1.0"
+ checksum: 10c0/1abc7f3bf2f8d78ff26d9e00ce9d0f7b32e5ff6d1da2857bcdf4746134c422282b091c672cde0572cac3840713487e0a7a636af9aa1b74cb11894b447a521efa
+ languageName: node
+ linkType: hard
+
+"find-up@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "find-up@npm:4.1.0"
+ dependencies:
+ locate-path: "npm:^5.0.0"
+ path-exists: "npm:^4.0.0"
+ checksum: 10c0/0406ee89ebeefa2d507feb07ec366bebd8a6167ae74aa4e34fb4c4abd06cf782a3ce26ae4194d70706f72182841733f00551c209fe575cb00bd92104056e78c1
+ languageName: node
+ linkType: hard
+
+"find-up@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "find-up@npm:5.0.0"
+ dependencies:
+ locate-path: "npm:^6.0.0"
+ path-exists: "npm:^4.0.0"
+ checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a
+ languageName: node
+ linkType: hard
+
+"flat-cache@npm:^4.0.0":
+ version: 4.0.1
+ resolution: "flat-cache@npm:4.0.1"
+ dependencies:
+ flatted: "npm:^3.2.9"
+ keyv: "npm:^4.5.4"
+ checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc
+ languageName: node
+ linkType: hard
+
+"flatted@npm:^3.2.9":
+ version: 3.4.2
+ resolution: "flatted@npm:3.4.2"
+ checksum: 10c0/a65b67aae7172d6cdf63691be7de6c5cd5adbdfdfe2e9da1a09b617c9512ed794037741ee53d93114276bff3f93cd3b0d97d54f9b316e1e4885dde6e9ffdf7ed
+ languageName: node
+ linkType: hard
+
+"follow-redirects@npm:^1.16.0":
+ version: 1.16.0
+ resolution: "follow-redirects@npm:1.16.0"
+ peerDependenciesMeta:
+ debug:
+ optional: true
+ checksum: 10c0/a1e2900163e6f1b4d1ed5c221b607f41decbab65534c63fe7e287e40a5d552a6496e7d9d7d976fa4ba77b4c51c11e5e9f683f10b43011ea11e442ff128d0e181
+ languageName: node
+ linkType: hard
+
+"for-each@npm:^0.3.5":
+ version: 0.3.5
+ resolution: "for-each@npm:0.3.5"
+ dependencies:
+ is-callable: "npm:^1.2.7"
+ checksum: 10c0/0e0b50f6a843a282637d43674d1fb278dda1dd85f4f99b640024cfb10b85058aac0cc781bf689d5fe50b4b7f638e91e548560723a4e76e04fe96ae35ef039cee
+ languageName: node
+ linkType: hard
+
+"form-data@npm:^4.0.5":
+ version: 4.0.5
+ resolution: "form-data@npm:4.0.5"
+ dependencies:
+ asynckit: "npm:^0.4.0"
+ combined-stream: "npm:^1.0.8"
+ es-set-tostringtag: "npm:^2.1.0"
+ hasown: "npm:^2.0.2"
+ mime-types: "npm:^2.1.12"
+ checksum: 10c0/dd6b767ee0bbd6d84039db12a0fa5a2028160ffbfaba1800695713b46ae974a5f6e08b3356c3195137f8530dcd9dfcb5d5ae1eeff53d0db1e5aad863b619ce3b
+ languageName: node
+ linkType: hard
+
+"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3":
+ version: 2.3.3
+ resolution: "fsevents@npm:2.3.3"
+ dependencies:
+ node-gyp: "npm:latest"
+ checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60
+ conditions: os=darwin
+ languageName: node
+ linkType: hard
+
+"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin":
+ version: 2.3.3
+ resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1"
+ dependencies:
+ node-gyp: "npm:latest"
+ conditions: os=darwin
+ languageName: node
+ linkType: hard
+
+"function-bind@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "function-bind@npm:1.1.2"
+ checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5
+ languageName: node
+ linkType: hard
+
+"generator-function@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "generator-function@npm:2.0.1"
+ checksum: 10c0/8a9f59df0f01cfefafdb3b451b80555e5cf6d76487095db91ac461a0e682e4ff7a9dbce15f4ecec191e53586d59eece01949e05a4b4492879600bbbe8e28d6b8
+ languageName: node
+ linkType: hard
+
+"gensync@npm:^1.0.0-beta.2":
+ version: 1.0.0-beta.2
+ resolution: "gensync@npm:1.0.0-beta.2"
+ checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8
+ languageName: node
+ linkType: hard
+
+"get-caller-file@npm:^2.0.1":
+ version: 2.0.5
+ resolution: "get-caller-file@npm:2.0.5"
+ checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde
+ languageName: node
+ linkType: hard
+
+"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0":
+ version: 1.3.1
+ resolution: "get-intrinsic@npm:1.3.1"
+ dependencies:
+ async-function: "npm:^1.0.0"
+ async-generator-function: "npm:^1.0.0"
+ call-bind-apply-helpers: "npm:^1.0.2"
+ es-define-property: "npm:^1.0.1"
+ es-errors: "npm:^1.3.0"
+ es-object-atoms: "npm:^1.1.1"
+ function-bind: "npm:^1.1.2"
+ generator-function: "npm:^2.0.0"
+ get-proto: "npm:^1.0.1"
+ gopd: "npm:^1.2.0"
+ has-symbols: "npm:^1.1.0"
+ hasown: "npm:^2.0.2"
+ math-intrinsics: "npm:^1.1.0"
+ checksum: 10c0/9f4ab0cf7efe0fd2c8185f52e6f637e708f3a112610c88869f8f041bb9ecc2ce44bf285dfdbdc6f4f7c277a5b88d8e94a432374d97cca22f3de7fc63795deb5d
+ languageName: node
+ linkType: hard
+
+"get-proto@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "get-proto@npm:1.0.1"
+ dependencies:
+ dunder-proto: "npm:^1.0.1"
+ es-object-atoms: "npm:^1.0.0"
+ checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c
+ languageName: node
+ linkType: hard
+
+"get-stream@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "get-stream@npm:6.0.1"
+ checksum: 10c0/49825d57d3fd6964228e6200a58169464b8e8970489b3acdc24906c782fb7f01f9f56f8e6653c4a50713771d6658f7cfe051e5eb8c12e334138c9c918b296341
+ languageName: node
+ linkType: hard
+
+"glob-parent@npm:^6.0.2":
+ version: 6.0.2
+ resolution: "glob-parent@npm:6.0.2"
+ dependencies:
+ is-glob: "npm:^4.0.3"
+ checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8
+ languageName: node
+ linkType: hard
+
+"globals@npm:^16.3.0":
+ version: 16.5.0
+ resolution: "globals@npm:16.5.0"
+ checksum: 10c0/615241dae7851c8012f5aa0223005b1ed6607713d6813de0741768bd4ddc39353117648f1a7086b4b0fa45eae733f1c0a0fe369aa4e543bb63f8de8990178ea9
+ languageName: node
+ linkType: hard
+
+"gopd@npm:^1.0.1, gopd@npm:^1.2.0":
+ version: 1.2.0
+ resolution: "gopd@npm:1.2.0"
+ checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead
+ languageName: node
+ linkType: hard
+
+"graceful-fs@npm:^4.2.6":
+ version: 4.2.11
+ resolution: "graceful-fs@npm:4.2.11"
+ checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2
+ languageName: node
+ linkType: hard
+
+"graphql-request@npm:^7.3.4":
+ version: 7.4.0
+ resolution: "graphql-request@npm:7.4.0"
+ dependencies:
+ "@graphql-typed-document-node/core": "npm:^3.2.0"
+ peerDependencies:
+ graphql: 14 - 16
+ checksum: 10c0/066531d70b9c4656251e51c950ce9bee3df05291e12e2b983608d75ac3a70d700efd6488d273b043235dc125658973db38b21eba59e808863831a5a19a6a7b41
+ languageName: node
+ linkType: hard
+
+"graphql-tag@npm:^2.12.6":
+ version: 2.12.6
+ resolution: "graphql-tag@npm:2.12.6"
+ dependencies:
+ tslib: "npm:^2.1.0"
+ peerDependencies:
+ graphql: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
+ checksum: 10c0/7763a72011bda454ed8ff1a0d82325f43ca6478e4ce4ab8b7910c4c651dd00db553132171c04d80af5d5aebf1ef6a8a9fd53ccfa33b90ddc00aa3d4be6114419
+ languageName: node
+ linkType: hard
+
+"graphql@npm:^16.8.1":
+ version: 16.14.2
+ resolution: "graphql@npm:16.14.2"
+ checksum: 10c0/a95a96961eaff55cc9fe9d31fae6f33499ac988b972d07ea5085024cb1333f515b902f376e7393a5489aa82200a8aff3eb96580e4d1b69d702ed19b6eb1ce97a
+ languageName: node
+ linkType: hard
+
+"h3@npm:^1.15.10":
+ version: 1.15.11
+ resolution: "h3@npm:1.15.11"
+ dependencies:
+ cookie-es: "npm:^1.2.3"
+ crossws: "npm:^0.3.5"
+ defu: "npm:^6.1.6"
+ destr: "npm:^2.0.5"
+ iron-webcrypto: "npm:^1.2.1"
+ node-mock-http: "npm:^1.0.4"
+ radix3: "npm:^1.1.2"
+ ufo: "npm:^1.6.3"
+ uncrypto: "npm:^0.1.3"
+ checksum: 10c0/6ccb421b9f92e02e6330c2b6697b18ef18e9550e4a1708f224ca517c40ecd201cd00967d0feb26e718595e86e985edec1755933cf8792d34fb8504f1c7cc261d
+ languageName: node
+ linkType: hard
+
+"has-flag@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "has-flag@npm:4.0.0"
+ checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1
+ languageName: node
+ linkType: hard
+
+"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "has-property-descriptors@npm:1.0.2"
+ dependencies:
+ es-define-property: "npm:^1.0.0"
+ checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236
+ languageName: node
+ linkType: hard
+
+"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "has-symbols@npm:1.1.0"
+ checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e
+ languageName: node
+ linkType: hard
+
+"has-tostringtag@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "has-tostringtag@npm:1.0.2"
+ dependencies:
+ has-symbols: "npm:^1.0.3"
+ checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c
+ languageName: node
+ linkType: hard
+
+"hash-base@npm:^3.0.0, hash-base@npm:^3.1.2":
+ version: 3.1.2
+ resolution: "hash-base@npm:3.1.2"
+ dependencies:
+ inherits: "npm:^2.0.4"
+ readable-stream: "npm:^2.3.8"
+ safe-buffer: "npm:^5.2.1"
+ to-buffer: "npm:^1.2.1"
+ checksum: 10c0/f3b7fae1853b31340048dd659f40f5260ca6f3ff53b932f807f4ab701ee09039f6e9dbe1841723ff61e20f3f69d6387a352e4ccc5f997dedb0d375c7d88bc15e
+ languageName: node
+ linkType: hard
+
+"hash-base@npm:~3.0.4":
+ version: 3.0.5
+ resolution: "hash-base@npm:3.0.5"
+ dependencies:
+ inherits: "npm:^2.0.4"
+ safe-buffer: "npm:^5.2.1"
+ checksum: 10c0/6dc185b79bad9b6d525cd132a588e4215380fdc36fec6f7a8a58c5db8e3b642557d02ad9c367f5e476c7c3ad3ccffa3607f308b124e1ed80e3b80a1b254db61e
+ languageName: node
+ linkType: hard
+
+"hash.js@npm:^1.0.0, hash.js@npm:^1.0.3":
+ version: 1.1.7
+ resolution: "hash.js@npm:1.1.7"
+ dependencies:
+ inherits: "npm:^2.0.3"
+ minimalistic-assert: "npm:^1.0.1"
+ checksum: 10c0/41ada59494eac5332cfc1ce6b7ebdd7b88a3864a6d6b08a3ea8ef261332ed60f37f10877e0c825aaa4bddebf164fbffa618286aeeec5296675e2671cbfa746c4
+ languageName: node
+ linkType: hard
+
+"hasown@npm:^2.0.2, hasown@npm:^2.0.3":
+ version: 2.0.4
+ resolution: "hasown@npm:2.0.4"
+ dependencies:
+ function-bind: "npm:^1.1.2"
+ checksum: 10c0/2d8de939e270b70618f8cebb69746620db10617dbb495bc66ddad326955ea24d3ca4af133aff3eb7c1853e0218f867bc2b050ec26fe02e3aea58f880ffc5e506
+ languageName: node
+ linkType: hard
+
+"hmac-drbg@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "hmac-drbg@npm:1.0.1"
+ dependencies:
+ hash.js: "npm:^1.0.3"
+ minimalistic-assert: "npm:^1.0.0"
+ minimalistic-crypto-utils: "npm:^1.0.1"
+ checksum: 10c0/f3d9ba31b40257a573f162176ac5930109816036c59a09f901eb2ffd7e5e705c6832bedfff507957125f2086a0ab8f853c0df225642a88bf1fcaea945f20600d
+ languageName: node
+ linkType: hard
+
+"hoist-non-react-statics@npm:^3.3.1":
+ version: 3.3.2
+ resolution: "hoist-non-react-statics@npm:3.3.2"
+ dependencies:
+ react-is: "npm:^16.7.0"
+ checksum: 10c0/fe0889169e845d738b59b64badf5e55fa3cf20454f9203d1eb088df322d49d4318df774828e789898dcb280e8a5521bb59b3203385662ca5e9218a6ca5820e74
+ languageName: node
+ linkType: hard
+
+"https-browserify@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "https-browserify@npm:1.0.0"
+ checksum: 10c0/e17b6943bc24ea9b9a7da5714645d808670af75a425f29baffc3284962626efdc1eb3aa9bbffaa6e64028a6ad98af5b09fabcb454a8f918fb686abfdc9e9b8ae
+ languageName: node
+ linkType: hard
+
+"https-proxy-agent@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "https-proxy-agent@npm:5.0.1"
+ dependencies:
+ agent-base: "npm:6"
+ debug: "npm:4"
+ checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1
+ languageName: node
+ linkType: hard
+
+"human-signals@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "human-signals@npm:2.1.0"
+ checksum: 10c0/695edb3edfcfe9c8b52a76926cd31b36978782062c0ed9b1192b36bebc75c4c87c82e178dfcb0ed0fc27ca59d434198aac0bd0be18f5781ded775604db22304a
+ languageName: node
+ linkType: hard
+
+"idb-keyval@npm:6.2.1":
+ version: 6.2.1
+ resolution: "idb-keyval@npm:6.2.1"
+ checksum: 10c0/9f0c83703a365e00bd0b4ed6380ce509a06dedfc6ec39b2ba5740085069fd2f2ff5c14ba19356488e3612a2f9c49985971982d836460a982a5d0b4019eeba48a
+ languageName: node
+ linkType: hard
+
+"idb-keyval@npm:^6.2.1":
+ version: 6.2.5
+ resolution: "idb-keyval@npm:6.2.5"
+ checksum: 10c0/58055106e2447cd4a91c62f1c6d4122d8e6d141c86c6e79860dbb6af0c6462bc9520e84c1d56dc9e5fb66c817dffd04b2a2432efada1273b89db955fc49d374b
+ languageName: node
+ linkType: hard
+
+"ieee754@npm:^1.1.13, ieee754@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "ieee754@npm:1.2.1"
+ checksum: 10c0/b0782ef5e0935b9f12883a2e2aa37baa75da6e66ce6515c168697b42160807d9330de9a32ec1ed73149aea02e0d822e572bca6f1e22bdcbd2149e13b050b17bb
+ languageName: node
+ linkType: hard
+
+"ignore@npm:^5.2.0":
+ version: 5.3.2
+ resolution: "ignore@npm:5.3.2"
+ checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337
+ languageName: node
+ linkType: hard
+
+"ignore@npm:^7.0.5":
+ version: 7.0.5
+ resolution: "ignore@npm:7.0.5"
+ checksum: 10c0/ae00db89fe873064a093b8999fe4cc284b13ef2a178636211842cceb650b9c3e390d3339191acb145d81ed5379d2074840cf0c33a20bdbd6f32821f79eb4ad5d
+ languageName: node
+ linkType: hard
+
+"import-fresh@npm:^3.2.1":
+ version: 3.3.1
+ resolution: "import-fresh@npm:3.3.1"
+ dependencies:
+ parent-module: "npm:^1.0.0"
+ resolve-from: "npm:^4.0.0"
+ checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec
+ languageName: node
+ linkType: hard
+
+"imurmurhash@npm:^0.1.4":
+ version: 0.1.4
+ resolution: "imurmurhash@npm:0.1.4"
+ checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6
+ languageName: node
+ linkType: hard
+
+"inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3, inherits@npm:~2.0.4":
+ version: 2.0.4
+ resolution: "inherits@npm:2.0.4"
+ checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2
+ languageName: node
+ linkType: hard
+
+"ini@npm:~1.3.0":
+ version: 1.3.8
+ resolution: "ini@npm:1.3.8"
+ checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a
+ languageName: node
+ linkType: hard
+
+"iron-webcrypto@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "iron-webcrypto@npm:1.2.1"
+ checksum: 10c0/5cf27c6e2bd3ef3b4970e486235fd82491ab8229e2ed0ac23307c28d6c80d721772a86ed4e9fe2a5cabadd710c2f024b706843b40561fb83f15afee58f809f66
+ languageName: node
+ linkType: hard
+
+"is-arguments@npm:^1.0.4":
+ version: 1.2.0
+ resolution: "is-arguments@npm:1.2.0"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ has-tostringtag: "npm:^1.0.2"
+ checksum: 10c0/6377344b31e9fcb707c6751ee89b11f132f32338e6a782ec2eac9393b0cbd32235dad93052998cda778ee058754860738341d8114910d50ada5615912bb929fc
+ languageName: node
+ linkType: hard
+
+"is-arrayish@npm:^0.2.1":
+ version: 0.2.1
+ resolution: "is-arrayish@npm:0.2.1"
+ checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729
+ languageName: node
+ linkType: hard
+
+"is-buffer@npm:~1.1.6":
+ version: 1.1.6
+ resolution: "is-buffer@npm:1.1.6"
+ checksum: 10c0/ae18aa0b6e113d6c490ad1db5e8df9bdb57758382b313f5a22c9c61084875c6396d50bbf49315f5b1926d142d74dfb8d31b40d993a383e0a158b15fea7a82234
+ languageName: node
+ linkType: hard
+
+"is-callable@npm:^1.2.7":
+ version: 1.2.7
+ resolution: "is-callable@npm:1.2.7"
+ checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f
+ languageName: node
+ linkType: hard
+
+"is-core-module@npm:^2.16.1":
+ version: 2.16.2
+ resolution: "is-core-module@npm:2.16.2"
+ dependencies:
+ hasown: "npm:^2.0.3"
+ checksum: 10c0/14b4258390283709c15476d023ec173e27458d5d014ccdb8ed39d576e551c3fa45498b7c9fe178f1529c4cb2648ddd58852a6a62107a019f6e349529f277518a
+ languageName: node
+ linkType: hard
+
+"is-docker@npm:^2.0.0":
+ version: 2.2.1
+ resolution: "is-docker@npm:2.2.1"
+ bin:
+ is-docker: cli.js
+ checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc
+ languageName: node
+ linkType: hard
+
+"is-extglob@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "is-extglob@npm:2.1.1"
+ checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912
+ languageName: node
+ linkType: hard
+
+"is-fullwidth-code-point@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "is-fullwidth-code-point@npm:3.0.0"
+ checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc
+ languageName: node
+ linkType: hard
+
+"is-generator-function@npm:^1.0.7":
+ version: 1.1.2
+ resolution: "is-generator-function@npm:1.1.2"
+ dependencies:
+ call-bound: "npm:^1.0.4"
+ generator-function: "npm:^2.0.0"
+ get-proto: "npm:^1.0.1"
+ has-tostringtag: "npm:^1.0.2"
+ safe-regex-test: "npm:^1.1.0"
+ checksum: 10c0/83da102e89c3e3b71d67b51d47c9f9bc862bceb58f87201727e27f7fa19d1d90b0ab223644ecaee6fc6e3d2d622bb25c966fbdaf87c59158b01ce7c0fe2fa372
+ languageName: node
+ linkType: hard
+
+"is-glob@npm:^4.0.0, is-glob@npm:^4.0.3":
+ version: 4.0.3
+ resolution: "is-glob@npm:4.0.3"
+ dependencies:
+ is-extglob: "npm:^2.1.1"
+ checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a
+ languageName: node
+ linkType: hard
+
+"is-nan@npm:^1.3.2":
+ version: 1.3.2
+ resolution: "is-nan@npm:1.3.2"
+ dependencies:
+ call-bind: "npm:^1.0.0"
+ define-properties: "npm:^1.1.3"
+ checksum: 10c0/8bfb286f85763f9c2e28ea32e9127702fe980ffd15fa5d63ade3be7786559e6e21355d3625dd364c769c033c5aedf0a2ed3d4025d336abf1b9241e3d9eddc5b0
+ languageName: node
+ linkType: hard
+
+"is-port-reachable@npm:4.0.0":
+ version: 4.0.0
+ resolution: "is-port-reachable@npm:4.0.0"
+ checksum: 10c0/f0fddd9b5c082f7c32356faab38c3c6eab5ea5b54491184f5688f3189d482017d2142c648927ee5964299e4a62da83d41ee52a1d73bf1f700325c370c9ed0cef
+ languageName: node
+ linkType: hard
+
+"is-regex@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "is-regex@npm:1.2.1"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ gopd: "npm:^1.2.0"
+ has-tostringtag: "npm:^1.0.2"
+ hasown: "npm:^2.0.2"
+ checksum: 10c0/1d3715d2b7889932349241680032e85d0b492cfcb045acb75ffc2c3085e8d561184f1f7e84b6f8321935b4aea39bc9c6ba74ed595b57ce4881a51dfdbc214e04
+ languageName: node
+ linkType: hard
+
+"is-retry-allowed@npm:^2.2.0":
+ version: 2.2.0
+ resolution: "is-retry-allowed@npm:2.2.0"
+ checksum: 10c0/013be4f8a0a06a49ed1fe495242952e898325d496202a018f6f9fb3fb9ac8fe3b957a9bd62463d68299ae35dbbda680473c85a9bcefca731b49d500d3ccc08ff
+ languageName: node
+ linkType: hard
+
+"is-stream@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "is-stream@npm:2.0.1"
+ checksum: 10c0/7c284241313fc6efc329b8d7f08e16c0efeb6baab1b4cd0ba579eb78e5af1aa5da11e68559896a2067cd6c526bd29241dda4eb1225e627d5aa1a89a76d4635a5
+ languageName: node
+ linkType: hard
+
+"is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.3":
+ version: 1.1.15
+ resolution: "is-typed-array@npm:1.1.15"
+ dependencies:
+ which-typed-array: "npm:^1.1.16"
+ checksum: 10c0/415511da3669e36e002820584e264997ffe277ff136643a3126cc949197e6ca3334d0f12d084e83b1994af2e9c8141275c741cf2b7da5a2ff62dd0cac26f76c4
+ languageName: node
+ linkType: hard
+
+"is-wsl@npm:^2.2.0":
+ version: 2.2.0
+ resolution: "is-wsl@npm:2.2.0"
+ dependencies:
+ is-docker: "npm:^2.0.0"
+ checksum: 10c0/a6fa2d370d21be487c0165c7a440d567274fbba1a817f2f0bfa41cc5e3af25041d84267baa22df66696956038a43973e72fca117918c91431920bdef490fa25e
+ languageName: node
+ linkType: hard
+
+"isarray@npm:^2.0.5":
+ version: 2.0.5
+ resolution: "isarray@npm:2.0.5"
+ checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd
+ languageName: node
+ linkType: hard
+
+"isarray@npm:~1.0.0":
+ version: 1.0.0
+ resolution: "isarray@npm:1.0.0"
+ checksum: 10c0/18b5be6669be53425f0b84098732670ed4e727e3af33bc7f948aac01782110eb9a18b3b329c5323bcdd3acdaae547ee077d3951317e7f133bff7105264b3003d
+ languageName: node
+ linkType: hard
+
+"isexe@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "isexe@npm:2.0.0"
+ checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d
+ languageName: node
+ linkType: hard
+
+"isexe@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "isexe@npm:4.0.0"
+ checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce
+ languageName: node
+ linkType: hard
+
+"isomorphic-timers-promises@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "isomorphic-timers-promises@npm:1.0.1"
+ checksum: 10c0/3b4761d0012ebe6b6382246079fc667f3513f36fe4042638f2bfb7db1557e4f1acd33a9c9907706c04270890ec6434120f132f3f300161a42a7dd8628926c8a4
+ languageName: node
+ linkType: hard
+
+"isows@npm:1.0.7":
+ version: 1.0.7
+ resolution: "isows@npm:1.0.7"
+ peerDependencies:
+ ws: "*"
+ checksum: 10c0/43c41fe89c7c07258d0be3825f87e12da8ac9023c5b5ae6741ec00b2b8169675c04331ea73ef8c172d37a6747066f4dc93947b17cd369f92828a3b3e741afbda
+ languageName: node
+ linkType: hard
+
+"jose@npm:^6.2.0":
+ version: 6.2.3
+ resolution: "jose@npm:6.2.3"
+ checksum: 10c0/aa91bccba22cc84d86308f833749bcb0b00441e35c24e0ac79abeac5f76dc62d47bdef9c1da6a0c609f5da6478595f52b252085888b89dbdb163861e40ea4188
+ languageName: node
+ linkType: hard
+
+"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "js-tokens@npm:4.0.0"
+ checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed
+ languageName: node
+ linkType: hard
+
+"jsesc@npm:^3.0.2":
+ version: 3.1.0
+ resolution: "jsesc@npm:3.1.0"
+ bin:
+ jsesc: bin/jsesc
+ checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1
+ languageName: node
+ linkType: hard
+
+"json-buffer@npm:3.0.1":
+ version: 3.0.1
+ resolution: "json-buffer@npm:3.0.1"
+ checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7
+ languageName: node
+ linkType: hard
+
+"json-parse-even-better-errors@npm:^2.3.0":
+ version: 2.3.1
+ resolution: "json-parse-even-better-errors@npm:2.3.1"
+ checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3
+ languageName: node
+ linkType: hard
+
+"json-schema-traverse@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "json-schema-traverse@npm:0.4.1"
+ checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce
+ languageName: node
+ linkType: hard
+
+"json-schema-traverse@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "json-schema-traverse@npm:1.0.0"
+ checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6
+ languageName: node
+ linkType: hard
+
+"json-stable-stringify-without-jsonify@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "json-stable-stringify-without-jsonify@npm:1.0.1"
+ checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5
+ languageName: node
+ linkType: hard
+
+"json5@npm:^2.2.3":
+ version: 2.2.3
+ resolution: "json5@npm:2.2.3"
+ bin:
+ json5: lib/cli.js
+ checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c
+ languageName: node
+ linkType: hard
+
+"keyv@npm:^4.5.4":
+ version: 4.5.4
+ resolution: "keyv@npm:4.5.4"
+ dependencies:
+ json-buffer: "npm:3.0.1"
+ checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e
+ languageName: node
+ linkType: hard
+
+"keyvaluestorage-interface@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "keyvaluestorage-interface@npm:1.0.0"
+ checksum: 10c0/0e028ebeda79a4e48c7e36708dbe7ced233c7a1f1bc925e506f150dd2ce43178bee8d20361c445bd915569709d9dc9ea80063b4d3c3cf5d615ab43aa31d3ec3d
+ languageName: node
+ linkType: hard
+
+"levn@npm:^0.4.1":
+ version: 0.4.1
+ resolution: "levn@npm:0.4.1"
+ dependencies:
+ prelude-ls: "npm:^1.2.1"
+ type-check: "npm:~0.4.0"
+ checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e
+ languageName: node
+ linkType: hard
+
+"lightningcss-android-arm64@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-android-arm64@npm:1.32.0"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-darwin-arm64@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-darwin-arm64@npm:1.32.0"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-darwin-x64@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-darwin-x64@npm:1.32.0"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss-freebsd-x64@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-freebsd-x64@npm:1.32.0"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm-gnueabihf@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-arm-gnueabihf@npm:1.32.0"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm64-gnu@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-arm64-gnu@npm:1.32.0"
+ conditions: os=linux & cpu=arm64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-arm64-musl@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-arm64-musl@npm:1.32.0"
+ conditions: os=linux & cpu=arm64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-x64-gnu@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-x64-gnu@npm:1.32.0"
+ conditions: os=linux & cpu=x64 & libc=glibc
+ languageName: node
+ linkType: hard
+
+"lightningcss-linux-x64-musl@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-linux-x64-musl@npm:1.32.0"
+ conditions: os=linux & cpu=x64 & libc=musl
+ languageName: node
+ linkType: hard
+
+"lightningcss-win32-arm64-msvc@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-win32-arm64-msvc@npm:1.32.0"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"lightningcss-win32-x64-msvc@npm:1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss-win32-x64-msvc@npm:1.32.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"lightningcss@npm:^1.32.0":
+ version: 1.32.0
+ resolution: "lightningcss@npm:1.32.0"
+ dependencies:
+ detect-libc: "npm:^2.0.3"
+ lightningcss-android-arm64: "npm:1.32.0"
+ lightningcss-darwin-arm64: "npm:1.32.0"
+ lightningcss-darwin-x64: "npm:1.32.0"
+ lightningcss-freebsd-x64: "npm:1.32.0"
+ lightningcss-linux-arm-gnueabihf: "npm:1.32.0"
+ lightningcss-linux-arm64-gnu: "npm:1.32.0"
+ lightningcss-linux-arm64-musl: "npm:1.32.0"
+ lightningcss-linux-x64-gnu: "npm:1.32.0"
+ lightningcss-linux-x64-musl: "npm:1.32.0"
+ lightningcss-win32-arm64-msvc: "npm:1.32.0"
+ lightningcss-win32-x64-msvc: "npm:1.32.0"
+ dependenciesMeta:
+ lightningcss-android-arm64:
+ optional: true
+ lightningcss-darwin-arm64:
+ optional: true
+ lightningcss-darwin-x64:
+ optional: true
+ lightningcss-freebsd-x64:
+ optional: true
+ lightningcss-linux-arm-gnueabihf:
+ optional: true
+ lightningcss-linux-arm64-gnu:
+ optional: true
+ lightningcss-linux-arm64-musl:
+ optional: true
+ lightningcss-linux-x64-gnu:
+ optional: true
+ lightningcss-linux-x64-musl:
+ optional: true
+ lightningcss-win32-arm64-msvc:
+ optional: true
+ lightningcss-win32-x64-msvc:
+ optional: true
+ checksum: 10c0/70945bd55097af46fc9fab7f5ed09cd5869d85940a2acab7ee06d0117004a1d68155708a2d462531cea2fc3c67aefc9333a7068c80b0b78dd404c16838809e03
+ languageName: node
+ linkType: hard
+
+"lines-and-columns@npm:^1.1.6":
+ version: 1.2.4
+ resolution: "lines-and-columns@npm:1.2.4"
+ checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d
+ languageName: node
+ linkType: hard
+
+"lit-element@npm:^4.2.0":
+ version: 4.2.2
+ resolution: "lit-element@npm:4.2.2"
+ dependencies:
+ "@lit-labs/ssr-dom-shim": "npm:^1.5.0"
+ "@lit/reactive-element": "npm:^2.1.0"
+ lit-html: "npm:^3.3.0"
+ checksum: 10c0/114ab5837f1f9e03a30b1ed1c055fa0e31f01e444464e5ab0453ef88be12d778508235533267c42614d323e3048ee58f865b5c612948a53bd6219abca404c710
+ languageName: node
+ linkType: hard
+
+"lit-html@npm:^3.3.0":
+ version: 3.3.3
+ resolution: "lit-html@npm:3.3.3"
+ dependencies:
+ "@types/trusted-types": "npm:^2.0.2"
+ checksum: 10c0/84e57314412ff385cc67fc482d26b77057370e2cfe3c6495cc45f692bdad840d5ed0519ddddcfae1d043bb098c66daa7e807593d5a21ac72094da14274497879
+ languageName: node
+ linkType: hard
+
+"lit@npm:3.3.0":
+ version: 3.3.0
+ resolution: "lit@npm:3.3.0"
+ dependencies:
+ "@lit/reactive-element": "npm:^2.1.0"
+ lit-element: "npm:^4.2.0"
+ lit-html: "npm:^3.3.0"
+ checksum: 10c0/27e6d109c04c8995f47c82a546407c5ed8d399705f9511d1f3ee562eb1ab4bc00fae5ec897da55fb50f202b2a659466e23cccd809d039e7d4f935fcecb2bc6a7
+ languageName: node
+ linkType: hard
+
+"lit@npm:^3":
+ version: 3.3.3
+ resolution: "lit@npm:3.3.3"
+ dependencies:
+ "@lit/reactive-element": "npm:^2.1.0"
+ lit-element: "npm:^4.2.0"
+ lit-html: "npm:^3.3.0"
+ checksum: 10c0/11b6175ebffce92f4cf835ddd8a198d49707c27f34b0a7c538d2cb294f6c2fb7ff40aabd3589fcf0c2ed162404faaf2bb7c966fad9024bb9e02d013e2d5aa0b5
+ languageName: node
+ linkType: hard
+
+"locate-path@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "locate-path@npm:5.0.0"
+ dependencies:
+ p-locate: "npm:^4.1.0"
+ checksum: 10c0/33a1c5247e87e022f9713e6213a744557a3e9ec32c5d0b5efb10aa3a38177615bf90221a5592674857039c1a0fd2063b82f285702d37b792d973e9e72ace6c59
+ languageName: node
+ linkType: hard
+
+"locate-path@npm:^6.0.0":
+ version: 6.0.0
+ resolution: "locate-path@npm:6.0.0"
+ dependencies:
+ p-locate: "npm:^5.0.0"
+ checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3
+ languageName: node
+ linkType: hard
+
+"loose-envify@npm:^1.4.0":
+ version: 1.4.0
+ resolution: "loose-envify@npm:1.4.0"
+ dependencies:
+ js-tokens: "npm:^3.0.0 || ^4.0.0"
+ bin:
+ loose-envify: cli.js
+ checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e
+ languageName: node
+ linkType: hard
+
+"lru-cache@npm:^11.2.7":
+ version: 11.5.1
+ resolution: "lru-cache@npm:11.5.1"
+ checksum: 10c0/7b341cea79a8efe9c6a6f20c8757a77eca5b25d7ff983ccf4e11e547b81f6787824baa1c84705251dff84ab4ffac85717ac354b9d02e465f86a9f8b166409979
+ languageName: node
+ linkType: hard
+
+"lru-cache@npm:^5.1.1":
+ version: 5.1.1
+ resolution: "lru-cache@npm:5.1.1"
+ dependencies:
+ yallist: "npm:^3.0.2"
+ checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482
+ languageName: node
+ linkType: hard
+
+"magic-string@npm:^0.30.21, magic-string@npm:^0.30.3":
+ version: 0.30.21
+ resolution: "magic-string@npm:0.30.21"
+ dependencies:
+ "@jridgewell/sourcemap-codec": "npm:^1.5.5"
+ checksum: 10c0/299378e38f9a270069fc62358522ddfb44e94244baa0d6a8980ab2a9b2490a1d03b236b447eee309e17eb3bddfa482c61259d47960eb018a904f0ded52780c4a
+ languageName: node
+ linkType: hard
+
+"marketing-campaign-launcher-client@workspace:.":
+ version: 0.0.0-use.local
+ resolution: "marketing-campaign-launcher-client@workspace:."
+ dependencies:
+ "@emotion/react": "npm:^11.11.3"
+ "@emotion/styled": "npm:^11.11.0"
+ "@eslint/js": "npm:^10.0.1"
+ "@human-protocol/core": "npm:^7.0.0"
+ "@human-protocol/sdk": "npm:^7.3.0"
+ "@mui/icons-material": "npm:^5.18.0"
+ "@mui/material": "npm:^5.16.7"
+ "@reown/appkit": "npm:^1.8.19"
+ "@reown/appkit-adapter-wagmi": "npm:^1.8.19"
+ "@tanstack/react-query": "npm:^5.91.3"
+ "@types/node": "npm:^22.15.16"
+ "@types/react": "npm:^19.2.2"
+ "@types/react-dom": "npm:^19.2.3"
+ "@vitejs/plugin-react": "npm:^4.3.1"
+ eslint: "npm:^10.1.0"
+ eslint-plugin-react-hooks: "npm:^5.1.0"
+ eslint-plugin-react-refresh: "npm:^0.4.11"
+ ethers: "npm:^6.16.0"
+ globals: "npm:^16.3.0"
+ prettier: "npm:^3.8.1"
+ react: "npm:^19.2.4"
+ react-dom: "npm:^19.2.4"
+ react-router-dom: "npm:^7.13.0"
+ serve: "npm:^14.2.4"
+ typescript: "npm:^5.6.3"
+ typescript-eslint: "npm:^8.57.0"
+ viem: "npm:2.x"
+ vite: "npm:^6.2.4"
+ vite-plugin-node-polyfills: "npm:^0.25.0"
+ wagmi: "npm:^3.6.4"
+ languageName: unknown
+ linkType: soft
+
+"math-intrinsics@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "math-intrinsics@npm:1.1.0"
+ checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f
+ languageName: node
+ linkType: hard
+
+"md5.js@npm:^1.3.4":
+ version: 1.3.5
+ resolution: "md5.js@npm:1.3.5"
+ dependencies:
+ hash-base: "npm:^3.0.0"
+ inherits: "npm:^2.0.1"
+ safe-buffer: "npm:^5.1.2"
+ checksum: 10c0/b7bd75077f419c8e013fc4d4dada48be71882e37d69a44af65a2f2804b91e253441eb43a0614423a1c91bb830b8140b0dc906bc797245e2e275759584f4efcc5
+ languageName: node
+ linkType: hard
+
+"md5@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "md5@npm:2.3.0"
+ dependencies:
+ charenc: "npm:0.0.2"
+ crypt: "npm:0.0.2"
+ is-buffer: "npm:~1.1.6"
+ checksum: 10c0/14a21d597d92e5b738255fbe7fe379905b8cb97e0a49d44a20b58526a646ec5518c337b817ce0094ca94d3e81a3313879c4c7b510d250c282d53afbbdede9110
+ languageName: node
+ linkType: hard
+
+"merge-stream@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "merge-stream@npm:2.0.0"
+ checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5
+ languageName: node
+ linkType: hard
+
+"miller-rabin@npm:^4.0.0":
+ version: 4.0.1
+ resolution: "miller-rabin@npm:4.0.1"
+ dependencies:
+ bn.js: "npm:^4.0.0"
+ brorand: "npm:^1.0.1"
+ bin:
+ miller-rabin: bin/miller-rabin
+ checksum: 10c0/26b2b96f6e49dbcff7faebb78708ed2f5f9ae27ac8cbbf1d7c08f83cf39bed3d418c0c11034dce997da70d135cc0ff6f3a4c15dc452f8e114c11986388a64346
+ languageName: node
+ linkType: hard
+
+"mime-db@npm:1.52.0":
+ version: 1.52.0
+ resolution: "mime-db@npm:1.52.0"
+ checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa
+ languageName: node
+ linkType: hard
+
+"mime-db@npm:>= 1.43.0 < 2":
+ version: 1.54.0
+ resolution: "mime-db@npm:1.54.0"
+ checksum: 10c0/8d907917bc2a90fa2df842cdf5dfeaf509adc15fe0531e07bb2f6ab15992416479015828d6a74200041c492e42cce3ebf78e5ce714388a0a538ea9c53eece284
+ languageName: node
+ linkType: hard
+
+"mime-db@npm:~1.33.0":
+ version: 1.33.0
+ resolution: "mime-db@npm:1.33.0"
+ checksum: 10c0/79172ce5468c8503b49dddfdddc18d3f5fe2599f9b5fe1bc321a8cbee14c96730fc6db22f907b23701b05b2936f865795f62ec3a78a7f3c8cb2450bb68c6763e
+ languageName: node
+ linkType: hard
+
+"mime-types@npm:2.1.18":
+ version: 2.1.18
+ resolution: "mime-types@npm:2.1.18"
+ dependencies:
+ mime-db: "npm:~1.33.0"
+ checksum: 10c0/a96a8d12f4bb98bc7bfac6a8ccbd045f40368fc1030d9366050c3613825d3715d1c1f393e10a75a885d2cdc1a26cd6d5e11f3a2a0d5c4d361f00242139430a0f
+ languageName: node
+ linkType: hard
+
+"mime-types@npm:^2.1.12":
+ version: 2.1.35
+ resolution: "mime-types@npm:2.1.35"
+ dependencies:
+ mime-db: "npm:1.52.0"
+ checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2
+ languageName: node
+ linkType: hard
+
+"mimic-fn@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "mimic-fn@npm:2.1.0"
+ checksum: 10c0/b26f5479d7ec6cc2bce275a08f146cf78f5e7b661b18114e2506dd91ec7ec47e7a25bf4360e5438094db0560bcc868079fb3b1fb3892b833c1ecbf63f80c95a4
+ languageName: node
+ linkType: hard
+
+"minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "minimalistic-assert@npm:1.0.1"
+ checksum: 10c0/96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd
+ languageName: node
+ linkType: hard
+
+"minimalistic-crypto-utils@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "minimalistic-crypto-utils@npm:1.0.1"
+ checksum: 10c0/790ecec8c5c73973a4fbf2c663d911033e8494d5fb0960a4500634766ab05d6107d20af896ca2132e7031741f19888154d44b2408ada0852446705441383e9f8
+ languageName: node
+ linkType: hard
+
+"minimatch@npm:3.1.5":
+ version: 3.1.5
+ resolution: "minimatch@npm:3.1.5"
+ dependencies:
+ brace-expansion: "npm:^1.1.7"
+ checksum: 10c0/2ecbdc0d33f07bddb0315a8b5afbcb761307a8778b48f0b312418ccbced99f104a2d17d8aca7573433c70e8ccd1c56823a441897a45e384ea76ef401a26ace70
+ languageName: node
+ linkType: hard
+
+"minimatch@npm:^10.2.2, minimatch@npm:^10.2.4":
+ version: 10.2.5
+ resolution: "minimatch@npm:10.2.5"
+ dependencies:
+ brace-expansion: "npm:^5.0.5"
+ checksum: 10c0/6bb058bd6324104b9ec2f763476a35386d05079c1f5fe4fbf1f324a25237cd4534d6813ecd71f48208f4e635c1221899bef94c3c89f7df55698fe373aaae20fd
+ languageName: node
+ linkType: hard
+
+"minimist@npm:^1.2.0":
+ version: 1.2.8
+ resolution: "minimist@npm:1.2.8"
+ checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6
+ languageName: node
+ linkType: hard
+
+"minipass@npm:^7.0.4, minipass@npm:^7.1.2":
+ version: 7.1.3
+ resolution: "minipass@npm:7.1.3"
+ checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb
+ languageName: node
+ linkType: hard
+
+"minizlib@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "minizlib@npm:3.1.0"
+ dependencies:
+ minipass: "npm:^7.1.2"
+ checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec
+ languageName: node
+ linkType: hard
+
+"mipd@npm:0.0.7":
+ version: 0.0.7
+ resolution: "mipd@npm:0.0.7"
+ peerDependencies:
+ typescript: ">=5.0.4"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/c536e4fcdc15793b4538f72da389f8901a7eccb2e1eb55d8878f234a45f1c271064650e76fa2967b94743e19cc32ceab3c7b1e0dc614e28a45b0bbd6c987795d
+ languageName: node
+ linkType: hard
+
+"ms@npm:2.0.0":
+ version: 2.0.0
+ resolution: "ms@npm:2.0.0"
+ checksum: 10c0/f8fda810b39fd7255bbdc451c46286e549794fcc700dc9cd1d25658bbc4dc2563a5de6fe7c60f798a16a60c6ceb53f033cb353f493f0cf63e5199b702943159d
+ languageName: node
+ linkType: hard
+
+"ms@npm:^2.1.3":
+ version: 2.1.3
+ resolution: "ms@npm:2.1.3"
+ checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48
+ languageName: node
+ linkType: hard
+
+"multiformats@npm:^9.4.2":
+ version: 9.9.0
+ resolution: "multiformats@npm:9.9.0"
+ checksum: 10c0/1fdb34fd2fb085142665e8bd402570659b50a5fae5994027e1df3add9e1ce1283ed1e0c2584a5c63ac0a58e871b8ee9665c4a99ca36ce71032617449d48aa975
+ languageName: node
+ linkType: hard
+
+"nanoid@npm:^3.3.12":
+ version: 3.3.12
+ resolution: "nanoid@npm:3.3.12"
+ bin:
+ nanoid: bin/nanoid.cjs
+ checksum: 10c0/ba142b7b39e11e80c16dd74b0365d407880c87c1cf7e1480956981ae940ee36060fa5b6f092cd1e315184dd19244c657bd017d03327bd3c62247d691c5e8edfb
+ languageName: node
+ linkType: hard
+
+"natural-compare@npm:^1.4.0":
+ version: 1.4.0
+ resolution: "natural-compare@npm:1.4.0"
+ checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447
+ languageName: node
+ linkType: hard
+
+"negotiator@npm:~0.6.4":
+ version: 0.6.4
+ resolution: "negotiator@npm:0.6.4"
+ checksum: 10c0/3e677139c7fb7628a6f36335bf11a885a62c21d5390204590a1a214a5631fcbe5ea74ef6a610b60afe84b4d975cbe0566a23f20ee17c77c73e74b80032108dea
+ languageName: node
+ linkType: hard
+
+"node-addon-api@npm:^5.0.0":
+ version: 5.1.0
+ resolution: "node-addon-api@npm:5.1.0"
+ dependencies:
+ node-gyp: "npm:latest"
+ checksum: 10c0/0eb269786124ba6fad9df8007a149e03c199b3e5a3038125dfb3e747c2d5113d406a4e33f4de1ea600aa2339be1f137d55eba1a73ee34e5fff06c52a5c296d1d
+ languageName: node
+ linkType: hard
+
+"node-fetch-native@npm:^1.6.7":
+ version: 1.6.7
+ resolution: "node-fetch-native@npm:1.6.7"
+ checksum: 10c0/8b748300fb053d21ca4d3db9c3ff52593d5e8f8a2d9fe90cbfad159676e324b954fdaefab46aeca007b5b9edab3d150021c4846444e4e8ab1f4e44cd3807be87
+ languageName: node
+ linkType: hard
+
+"node-fetch@npm:^2.7.0":
+ version: 2.7.0
+ resolution: "node-fetch@npm:2.7.0"
+ dependencies:
+ whatwg-url: "npm:^5.0.0"
+ peerDependencies:
+ encoding: ^0.1.0
+ peerDependenciesMeta:
+ encoding:
+ optional: true
+ checksum: 10c0/b55786b6028208e6fbe594ccccc213cab67a72899c9234eb59dba51062a299ea853210fcf526998eaa2867b0963ad72338824450905679ff0fa304b8c5093ae8
+ languageName: node
+ linkType: hard
+
+"node-gyp-build@npm:^4.2.0":
+ version: 4.8.4
+ resolution: "node-gyp-build@npm:4.8.4"
+ bin:
+ node-gyp-build: bin.js
+ node-gyp-build-optional: optional.js
+ node-gyp-build-test: build-test.js
+ checksum: 10c0/444e189907ece2081fe60e75368784f7782cfddb554b60123743dfb89509df89f1f29c03bbfa16b3a3e0be3f48799a4783f487da6203245fa5bed239ba7407e1
+ languageName: node
+ linkType: hard
+
+"node-gyp@npm:latest":
+ version: 12.4.0
+ resolution: "node-gyp@npm:12.4.0"
+ dependencies:
+ env-paths: "npm:^2.2.0"
+ exponential-backoff: "npm:^3.1.1"
+ graceful-fs: "npm:^4.2.6"
+ nopt: "npm:^9.0.0"
+ proc-log: "npm:^6.0.0"
+ semver: "npm:^7.3.5"
+ tar: "npm:^7.5.4"
+ tinyglobby: "npm:^0.2.12"
+ undici: "npm:^6.25.0"
+ which: "npm:^6.0.0"
+ bin:
+ node-gyp: bin/node-gyp.js
+ checksum: 10c0/9acb7c798e124275a6f9c1f7eb64b5abd6196bb885a3945fb44ee0dccf435514e88cdfb0f228ee7ff76ef25107c1f39ff37a067bf92fd00b9aff9234db29ff9e
+ languageName: node
+ linkType: hard
+
+"node-mock-http@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "node-mock-http@npm:1.0.4"
+ checksum: 10c0/86e3f7453cf07ad6b8bd17cf89ff91d45f486a861cf6d891618cf29647d559cbcde1d1f90c9cc02e014ff9f7900b2fb21c96b03ea4b4a415dbe2d65badadceba
+ languageName: node
+ linkType: hard
+
+"node-releases@npm:^2.0.36":
+ version: 2.0.47
+ resolution: "node-releases@npm:2.0.47"
+ checksum: 10c0/fb1a703adb88c3bfe73aa39ebe0a0bc6d59c9d20d74ad61fb50958ffb22840da82a7a256076840b84c8ed57bb80e6fc8e588e675712fcf7af269aab16206b9b5
+ languageName: node
+ linkType: hard
+
+"node-stdlib-browser@npm:^1.3.1":
+ version: 1.3.1
+ resolution: "node-stdlib-browser@npm:1.3.1"
+ dependencies:
+ assert: "npm:^2.0.0"
+ browser-resolve: "npm:^2.0.0"
+ browserify-zlib: "npm:^0.2.0"
+ buffer: "npm:^5.7.1"
+ console-browserify: "npm:^1.1.0"
+ constants-browserify: "npm:^1.0.0"
+ create-require: "npm:^1.1.1"
+ crypto-browserify: "npm:^3.12.1"
+ domain-browser: "npm:4.22.0"
+ events: "npm:^3.0.0"
+ https-browserify: "npm:^1.0.0"
+ isomorphic-timers-promises: "npm:^1.0.1"
+ os-browserify: "npm:^0.3.0"
+ path-browserify: "npm:^1.0.1"
+ pkg-dir: "npm:^5.0.0"
+ process: "npm:^0.11.10"
+ punycode: "npm:^1.4.1"
+ querystring-es3: "npm:^0.2.1"
+ readable-stream: "npm:^3.6.0"
+ stream-browserify: "npm:^3.0.0"
+ stream-http: "npm:^3.2.0"
+ string_decoder: "npm:^1.0.0"
+ timers-browserify: "npm:^2.0.4"
+ tty-browserify: "npm:0.0.1"
+ url: "npm:^0.11.4"
+ util: "npm:^0.12.4"
+ vm-browserify: "npm:^1.0.1"
+ checksum: 10c0/5b0cb5d4499b1b1c73f54db3e9e69b2a3a8aebe2ead2e356b0a03c1dfca6b5c5d2f6516e24301e76dc7b68999b9d0ae3da6c3f1dec421eed80ad6cb9eec0f356
+ languageName: node
+ linkType: hard
+
+"nopt@npm:^9.0.0":
+ version: 9.0.0
+ resolution: "nopt@npm:9.0.0"
+ dependencies:
+ abbrev: "npm:^4.0.0"
+ bin:
+ nopt: bin/nopt.js
+ checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd
+ languageName: node
+ linkType: hard
+
+"normalize-path@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "normalize-path@npm:3.0.0"
+ checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046
+ languageName: node
+ linkType: hard
+
+"npm-run-path@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "npm-run-path@npm:4.0.1"
+ dependencies:
+ path-key: "npm:^3.0.0"
+ checksum: 10c0/6f9353a95288f8455cf64cbeb707b28826a7f29690244c1e4bb61ec573256e021b6ad6651b394eb1ccfd00d6ec50147253aba2c5fe58a57ceb111fad62c519ac
+ languageName: node
+ linkType: hard
+
+"object-assign@npm:^4.1.1":
+ version: 4.1.1
+ resolution: "object-assign@npm:4.1.1"
+ checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414
+ languageName: node
+ linkType: hard
+
+"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4":
+ version: 1.13.4
+ resolution: "object-inspect@npm:1.13.4"
+ checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692
+ languageName: node
+ linkType: hard
+
+"object-is@npm:^1.1.5":
+ version: 1.1.6
+ resolution: "object-is@npm:1.1.6"
+ dependencies:
+ call-bind: "npm:^1.0.7"
+ define-properties: "npm:^1.2.1"
+ checksum: 10c0/506af444c4dce7f8e31f34fc549e2fb8152d6b9c4a30c6e62852badd7f520b579c679af433e7a072f9d78eb7808d230dc12e1cf58da9154dfbf8813099ea0fe0
+ languageName: node
+ linkType: hard
+
+"object-keys@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "object-keys@npm:1.1.1"
+ checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d
+ languageName: node
+ linkType: hard
+
+"object.assign@npm:^4.1.4":
+ version: 4.1.7
+ resolution: "object.assign@npm:4.1.7"
+ dependencies:
+ call-bind: "npm:^1.0.8"
+ call-bound: "npm:^1.0.3"
+ define-properties: "npm:^1.2.1"
+ es-object-atoms: "npm:^1.0.0"
+ has-symbols: "npm:^1.1.0"
+ object-keys: "npm:^1.1.1"
+ checksum: 10c0/3b2732bd860567ea2579d1567525168de925a8d852638612846bd8082b3a1602b7b89b67b09913cbb5b9bd6e95923b2ae73580baa9d99cb4e990564e8cbf5ddc
+ languageName: node
+ linkType: hard
+
+"obug@npm:^2.1.1":
+ version: 2.1.2
+ resolution: "obug@npm:2.1.2"
+ checksum: 10c0/e857080ef23c018bd4ad8553238cd97008cd4ab8472b4b83eafe75c19e9b6f84ac8fe53ef7f50b515a1dbf83e6372dd0b198aece33bc716edfa70366f6f6ed5e
+ languageName: node
+ linkType: hard
+
+"ofetch@npm:^1.5.1":
+ version: 1.5.1
+ resolution: "ofetch@npm:1.5.1"
+ dependencies:
+ destr: "npm:^2.0.5"
+ node-fetch-native: "npm:^1.6.7"
+ ufo: "npm:^1.6.1"
+ checksum: 10c0/97ebc600512ea0ab401e97c73313218cc53c9b530b32ec8c995c347b0c68887129993168d1753f527761a64c6f93a5d823ce1378ccec95fc65a606f323a79a6c
+ languageName: node
+ linkType: hard
+
+"on-exit-leak-free@npm:^2.1.0":
+ version: 2.1.2
+ resolution: "on-exit-leak-free@npm:2.1.2"
+ checksum: 10c0/faea2e1c9d696ecee919026c32be8d6a633a7ac1240b3b87e944a380e8a11dc9c95c4a1f8fb0568de7ab8db3823e790f12bda45296b1d111e341aad3922a0570
+ languageName: node
+ linkType: hard
+
+"on-headers@npm:~1.1.0":
+ version: 1.1.0
+ resolution: "on-headers@npm:1.1.0"
+ checksum: 10c0/2c3b6b0d68ec9adbd561dc2d61c9b14da8ac03d8a2f0fd9e97bdf0600c887d5d97f664ff3be6876cf40cda6e3c587d73a4745e10b426ac50c7664fc5a0dfc0a1
+ languageName: node
+ linkType: hard
+
+"onetime@npm:^5.1.2":
+ version: 5.1.2
+ resolution: "onetime@npm:5.1.2"
+ dependencies:
+ mimic-fn: "npm:^2.1.0"
+ checksum: 10c0/ffcef6fbb2692c3c40749f31ea2e22677a876daea92959b8a80b521d95cca7a668c884d8b2045d1d8ee7d56796aa405c405462af112a1477594cc63531baeb8f
+ languageName: node
+ linkType: hard
+
+"openpgp@npm:^6.3.0":
+ version: 6.3.1
+ resolution: "openpgp@npm:6.3.1"
+ peerDependencies:
+ "@openpgp/web-stream-tools": ~0.3.0
+ peerDependenciesMeta:
+ "@openpgp/web-stream-tools":
+ optional: true
+ checksum: 10c0/5c3d3d973219a1c53ca5994720aabdc36312d39ea3199dcf7010d6b20cd46a66ee6289a403697a9d33676e4e5dd4799ddba3396eb08a23a24419711909b635cd
+ languageName: node
+ linkType: hard
+
+"optionator@npm:^0.9.3":
+ version: 0.9.4
+ resolution: "optionator@npm:0.9.4"
+ dependencies:
+ deep-is: "npm:^0.1.3"
+ fast-levenshtein: "npm:^2.0.6"
+ levn: "npm:^0.4.1"
+ prelude-ls: "npm:^1.2.1"
+ type-check: "npm:^0.4.0"
+ word-wrap: "npm:^1.2.5"
+ checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675
+ languageName: node
+ linkType: hard
+
+"os-browserify@npm:^0.3.0":
+ version: 0.3.0
+ resolution: "os-browserify@npm:0.3.0"
+ checksum: 10c0/6ff32cb1efe2bc6930ad0fd4c50e30c38010aee909eba8d65be60af55efd6cbb48f0287e3649b4e3f3a63dce5a667b23c187c4293a75e557f0d5489d735bcf52
+ languageName: node
+ linkType: hard
+
+"ox@npm:0.14.29":
+ version: 0.14.29
+ resolution: "ox@npm:0.14.29"
+ dependencies:
+ "@adraffy/ens-normalize": "npm:^1.11.0"
+ "@noble/ciphers": "npm:^1.3.0"
+ "@noble/curves": "npm:1.9.1"
+ "@noble/hashes": "npm:^1.8.0"
+ "@scure/bip32": "npm:^1.7.0"
+ "@scure/bip39": "npm:^1.6.0"
+ abitype: "npm:^1.2.3"
+ eventemitter3: "npm:5.0.1"
+ peerDependencies:
+ typescript: ">=5.4.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/bf36b2cd83d67bf43893b73876630554d0bd1748c7ad769607ceb8fe1aaf6afa6f9411a31e7e815de107a035811ebfa790c0af591aa403e363b83a1896acfc7b
+ languageName: node
+ linkType: hard
+
+"ox@npm:0.6.9":
+ version: 0.6.9
+ resolution: "ox@npm:0.6.9"
+ dependencies:
+ "@adraffy/ens-normalize": "npm:^1.10.1"
+ "@noble/curves": "npm:^1.6.0"
+ "@noble/hashes": "npm:^1.5.0"
+ "@scure/bip32": "npm:^1.5.0"
+ "@scure/bip39": "npm:^1.4.0"
+ abitype: "npm:^1.0.6"
+ eventemitter3: "npm:5.0.1"
+ peerDependencies:
+ typescript: ">=5.4.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/02a7ea9795eaac0a7a672e983094f62ae6f19b7d0c786e6d7ef4584683faf535b5b133e42452dd3abb77115382e16b2cb5c0f629d5a0f2b80832c47756e0ecd1
+ languageName: node
+ linkType: hard
+
+"ox@npm:0.9.3":
+ version: 0.9.3
+ resolution: "ox@npm:0.9.3"
+ dependencies:
+ "@adraffy/ens-normalize": "npm:^1.11.0"
+ "@noble/ciphers": "npm:^1.3.0"
+ "@noble/curves": "npm:1.9.1"
+ "@noble/hashes": "npm:^1.8.0"
+ "@scure/bip32": "npm:^1.7.0"
+ "@scure/bip39": "npm:^1.6.0"
+ abitype: "npm:^1.0.9"
+ eventemitter3: "npm:5.0.1"
+ peerDependencies:
+ typescript: ">=5.4.0"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/e04f8f5d6de4fbc65d18e8388bbb4c6a09e7b69e6d51c45985bd2ed01414fda154a78dfb8fcd46e53842794a10ef37fff2b4d8b786bd7a7476a3772e8cc8e64a
+ languageName: node
+ linkType: hard
+
+"p-limit@npm:^2.2.0":
+ version: 2.3.0
+ resolution: "p-limit@npm:2.3.0"
+ dependencies:
+ p-try: "npm:^2.0.0"
+ checksum: 10c0/8da01ac53efe6a627080fafc127c873da40c18d87b3f5d5492d465bb85ec7207e153948df6b9cbaeb130be70152f874229b8242ee2be84c0794082510af97f12
+ languageName: node
+ linkType: hard
+
+"p-limit@npm:^3.0.2":
+ version: 3.1.0
+ resolution: "p-limit@npm:3.1.0"
+ dependencies:
+ yocto-queue: "npm:^0.1.0"
+ checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a
+ languageName: node
+ linkType: hard
+
+"p-locate@npm:^4.1.0":
+ version: 4.1.0
+ resolution: "p-locate@npm:4.1.0"
+ dependencies:
+ p-limit: "npm:^2.2.0"
+ checksum: 10c0/1b476ad69ad7f6059744f343b26d51ce091508935c1dbb80c4e0a2f397ffce0ca3a1f9f5cd3c7ce19d7929a09719d5c65fe70d8ee289c3f267cd36f2881813e9
+ languageName: node
+ linkType: hard
+
+"p-locate@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "p-locate@npm:5.0.0"
+ dependencies:
+ p-limit: "npm:^3.0.2"
+ checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a
+ languageName: node
+ linkType: hard
+
+"p-try@npm:^2.0.0":
+ version: 2.2.0
+ resolution: "p-try@npm:2.2.0"
+ checksum: 10c0/c36c19907734c904b16994e6535b02c36c2224d433e01a2f1ab777237f4d86e6289fd5fd464850491e940379d4606ed850c03e0f9ab600b0ebddb511312e177f
+ languageName: node
+ linkType: hard
+
+"pako@npm:~1.0.5":
+ version: 1.0.11
+ resolution: "pako@npm:1.0.11"
+ checksum: 10c0/86dd99d8b34c3930345b8bbeb5e1cd8a05f608eeb40967b293f72fe469d0e9c88b783a8777e4cc7dc7c91ce54c5e93d88ff4b4f060e6ff18408fd21030d9ffbe
+ languageName: node
+ linkType: hard
+
+"parent-module@npm:^1.0.0":
+ version: 1.0.1
+ resolution: "parent-module@npm:1.0.1"
+ dependencies:
+ callsites: "npm:^3.0.0"
+ checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556
+ languageName: node
+ linkType: hard
+
+"parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.9":
+ version: 5.1.9
+ resolution: "parse-asn1@npm:5.1.9"
+ dependencies:
+ asn1.js: "npm:^4.10.1"
+ browserify-aes: "npm:^1.2.0"
+ evp_bytestokey: "npm:^1.0.3"
+ pbkdf2: "npm:^3.1.5"
+ safe-buffer: "npm:^5.2.1"
+ checksum: 10c0/6dfe27c121be3d63ebbf95f03d2ae0a07dd716d44b70b0bd3458790a822a80de05361c62147271fd7b845dcc2d37755d9c9c393064a3438fe633779df0bc07e7
+ languageName: node
+ linkType: hard
+
+"parse-json@npm:^5.0.0":
+ version: 5.2.0
+ resolution: "parse-json@npm:5.2.0"
+ dependencies:
+ "@babel/code-frame": "npm:^7.0.0"
+ error-ex: "npm:^1.3.1"
+ json-parse-even-better-errors: "npm:^2.3.0"
+ lines-and-columns: "npm:^1.1.6"
+ checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585
+ languageName: node
+ linkType: hard
+
+"path-browserify@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "path-browserify@npm:1.0.1"
+ checksum: 10c0/8b8c3fd5c66bd340272180590ae4ff139769e9ab79522e2eb82e3d571a89b8117c04147f65ad066dccfb42fcad902e5b7d794b3d35e0fd840491a8ddbedf8c66
+ languageName: node
+ linkType: hard
+
+"path-exists@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "path-exists@npm:4.0.0"
+ checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b
+ languageName: node
+ linkType: hard
+
+"path-is-inside@npm:1.0.2":
+ version: 1.0.2
+ resolution: "path-is-inside@npm:1.0.2"
+ checksum: 10c0/7fdd4b41672c70461cce734fc222b33e7b447fa489c7c4377c95e7e6852d83d69741f307d88ec0cc3b385b41cb4accc6efac3c7c511cd18512e95424f5fa980c
+ languageName: node
+ linkType: hard
+
+"path-key@npm:^3.0.0, path-key@npm:^3.1.0":
+ version: 3.1.1
+ resolution: "path-key@npm:3.1.1"
+ checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c
+ languageName: node
+ linkType: hard
+
+"path-parse@npm:^1.0.7":
+ version: 1.0.7
+ resolution: "path-parse@npm:1.0.7"
+ checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1
+ languageName: node
+ linkType: hard
+
+"path-to-regexp@npm:3.3.0":
+ version: 3.3.0
+ resolution: "path-to-regexp@npm:3.3.0"
+ checksum: 10c0/ffa0ebe7088d38d435a8d08b0fe6e8c93ceb2a81a65d4dd1d9a538f52e09d5e3474ed5f553cb3b180d894b0caa10698a68737ab599fd1e56b4663d1a64c9f77b
+ languageName: node
+ linkType: hard
+
+"path-type@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "path-type@npm:4.0.0"
+ checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c
+ languageName: node
+ linkType: hard
+
+"pathe@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "pathe@npm:2.0.3"
+ checksum: 10c0/c118dc5a8b5c4166011b2b70608762e260085180bb9e33e80a50dcdb1e78c010b1624f4280c492c92b05fc276715a4c357d1f9edc570f8f1b3d90b6839ebaca1
+ languageName: node
+ linkType: hard
+
+"pbkdf2@npm:^3.1.2, pbkdf2@npm:^3.1.5":
+ version: 3.1.6
+ resolution: "pbkdf2@npm:3.1.6"
+ dependencies:
+ create-hash: "npm:^1.2.0"
+ create-hmac: "npm:^1.1.7"
+ ripemd160: "npm:^2.0.3"
+ safe-buffer: "npm:^5.2.1"
+ sha.js: "npm:^2.4.12"
+ to-buffer: "npm:^1.2.2"
+ checksum: 10c0/828be4a5eed15c502dfa490247506c6abd4e539f6e1ea265d2b8a668292c9e07af4e6d4d7a5d3aa8ad12274da7cea1bf1b3dfc1f5f19bcdeee5157d1bf83f7f3
+ languageName: node
+ linkType: hard
+
+"picocolors@npm:^1.1.1":
+ version: 1.1.1
+ resolution: "picocolors@npm:1.1.1"
+ checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58
+ languageName: node
+ linkType: hard
+
+"picomatch@npm:^2.0.4":
+ version: 2.3.2
+ resolution: "picomatch@npm:2.3.2"
+ checksum: 10c0/a554d1709e59be97d1acb9eaedbbc700a5c03dbd4579807baed95100b00420bc729335440ef15004ae2378984e2487a7c1cebd743cfdb72b6fa9ab69223c0d61
+ languageName: node
+ linkType: hard
+
+"picomatch@npm:^4.0.2, picomatch@npm:^4.0.3, picomatch@npm:^4.0.4":
+ version: 4.0.4
+ resolution: "picomatch@npm:4.0.4"
+ checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0
+ languageName: node
+ linkType: hard
+
+"pino-abstract-transport@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "pino-abstract-transport@npm:2.0.0"
+ dependencies:
+ split2: "npm:^4.0.0"
+ checksum: 10c0/02c05b8f2ffce0d7c774c8e588f61e8b77de8ccb5f8125afd4a7325c9ea0e6af7fb78168999657712ae843e4462bb70ac550dfd6284f930ee57f17f486f25a9f
+ languageName: node
+ linkType: hard
+
+"pino-std-serializers@npm:^7.0.0":
+ version: 7.1.0
+ resolution: "pino-std-serializers@npm:7.1.0"
+ checksum: 10c0/d158615aa93ebdeac2d3912ad4227a23ef78cf14229e886214771f581e96eff312257f2d6368c75b2fbf53e5024eda475d81305014f4ed1a6d5eeab9107f6ef0
+ languageName: node
+ linkType: hard
+
+"pino@npm:10.0.0":
+ version: 10.0.0
+ resolution: "pino@npm:10.0.0"
+ dependencies:
+ atomic-sleep: "npm:^1.0.0"
+ on-exit-leak-free: "npm:^2.1.0"
+ pino-abstract-transport: "npm:^2.0.0"
+ pino-std-serializers: "npm:^7.0.0"
+ process-warning: "npm:^5.0.0"
+ quick-format-unescaped: "npm:^4.0.3"
+ real-require: "npm:^0.2.0"
+ safe-stable-stringify: "npm:^2.3.1"
+ slow-redact: "npm:^0.3.0"
+ sonic-boom: "npm:^4.0.1"
+ thread-stream: "npm:^3.0.0"
+ bin:
+ pino: bin.js
+ checksum: 10c0/f95fcc51523310e9ece1822f8ef4d8e6c2b35f67eca9805fe18fdef21dfac81fa128f1ebaa3c9a11571120854391b10b3b339f2e5836f805edaf6936781c6e6f
+ languageName: node
+ linkType: hard
+
+"pkg-dir@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "pkg-dir@npm:5.0.0"
+ dependencies:
+ find-up: "npm:^5.0.0"
+ checksum: 10c0/793a496d685dc55bbbdbbb22d884535c3b29241e48e3e8d37e448113a71b9e42f5481a61fdc672d7322de12fbb2c584dd3a68bf89b18fffce5c48a390f911bc5
+ languageName: node
+ linkType: hard
+
+"pngjs@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "pngjs@npm:5.0.0"
+ checksum: 10c0/c074d8a94fb75e2defa8021e85356bf7849688af7d8ce9995b7394d57cd1a777b272cfb7c4bce08b8d10e71e708e7717c81fd553a413f21840c548ec9d4893c6
+ languageName: node
+ linkType: hard
+
+"possible-typed-array-names@npm:^1.0.0":
+ version: 1.1.0
+ resolution: "possible-typed-array-names@npm:1.1.0"
+ checksum: 10c0/c810983414142071da1d644662ce4caebce890203eb2bc7bf119f37f3fe5796226e117e6cca146b521921fa6531072674174a3325066ac66fce089a53e1e5196
+ languageName: node
+ linkType: hard
+
+"postcss@npm:^8.5.15, postcss@npm:^8.5.3":
+ version: 8.5.15
+ resolution: "postcss@npm:8.5.15"
+ dependencies:
+ nanoid: "npm:^3.3.12"
+ picocolors: "npm:^1.1.1"
+ source-map-js: "npm:^1.2.1"
+ checksum: 10c0/7f2e63ae22fbe43aace1bf652bd99da4e90737c64194d49e51ddc9cd0f9e51ff2861a7d734379b494deffa03a880a5c65eec70bc29ee9ebaa7136dde3eee8f31
+ languageName: node
+ linkType: hard
+
+"preact@npm:10.24.2":
+ version: 10.24.2
+ resolution: "preact@npm:10.24.2"
+ checksum: 10c0/d1d22c5e1abc10eb8f83501857ef22c54a3fda2d20449d06f5b3c7d5ae812bd702c16c05b672138b8906504f9c893e072e9cebcbcada8cac320edf36265788fb
+ languageName: node
+ linkType: hard
+
+"prelude-ls@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "prelude-ls@npm:1.2.1"
+ checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd
+ languageName: node
+ linkType: hard
+
+"prettier@npm:^3.8.1":
+ version: 3.8.4
+ resolution: "prettier@npm:3.8.4"
+ bin:
+ prettier: bin/prettier.cjs
+ checksum: 10c0/b90a0cbe75b88ac0af9c13fe0f359bd19926fabccd88483227b21f71f0c1cc42da056fc1ac3a361e665577c568371d5ccfb2c62c31c8a1186f8d1bd531a063e9
+ languageName: node
+ linkType: hard
+
+"proc-log@npm:^6.0.0":
+ version: 6.1.0
+ resolution: "proc-log@npm:6.1.0"
+ checksum: 10c0/4f178d4062733ead9d71a9b1ab24ebcecdfe2250916a5b1555f04fe2eda972a0ec76fbaa8df1ad9c02707add6749219d118a4fc46dc56bdfe4dde4b47d80bb82
+ languageName: node
+ linkType: hard
+
+"process-nextick-args@npm:~2.0.0":
+ version: 2.0.1
+ resolution: "process-nextick-args@npm:2.0.1"
+ checksum: 10c0/bec089239487833d46b59d80327a1605e1c5287eaad770a291add7f45fda1bb5e28b38e0e061add0a1d0ee0984788ce74fa394d345eed1c420cacf392c554367
+ languageName: node
+ linkType: hard
+
+"process-warning@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "process-warning@npm:5.0.0"
+ checksum: 10c0/941f48863d368ec161e0b5890ba0c6af94170078f3d6b5e915c19b36fb59edb0dc2f8e834d25e0d375a8bf368a49d490f080508842168832b93489d17843ec29
+ languageName: node
+ linkType: hard
+
+"process@npm:^0.11.10":
+ version: 0.11.10
+ resolution: "process@npm:0.11.10"
+ checksum: 10c0/40c3ce4b7e6d4b8c3355479df77aeed46f81b279818ccdc500124e6a5ab882c0cc81ff7ea16384873a95a74c4570b01b120f287abbdd4c877931460eca6084b3
+ languageName: node
+ linkType: hard
+
+"prop-types@npm:^15.6.2, prop-types@npm:^15.8.1":
+ version: 15.8.1
+ resolution: "prop-types@npm:15.8.1"
+ dependencies:
+ loose-envify: "npm:^1.4.0"
+ object-assign: "npm:^4.1.1"
+ react-is: "npm:^16.13.1"
+ checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077
+ languageName: node
+ linkType: hard
+
+"proxy-compare@npm:^3.0.1":
+ version: 3.0.1
+ resolution: "proxy-compare@npm:3.0.1"
+ checksum: 10c0/1e3631ef32603d4de263860ce02d84b48384dce9b62238b2148b3c58a4e4ec5b06644615dcc196a339f73b9695443317099d55a9173e02ce8492088c9330c00b
+ languageName: node
+ linkType: hard
+
+"proxy-from-env@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "proxy-from-env@npm:2.1.0"
+ checksum: 10c0/ed01729fd4d094eab619cd7e17ce3698b3413b31eb102c4904f9875e677cd207392795d5b4adee9cec359dfd31c44d5ad7595a3a3ad51c40250e141512281c58
+ languageName: node
+ linkType: hard
+
+"public-encrypt@npm:^4.0.3":
+ version: 4.0.3
+ resolution: "public-encrypt@npm:4.0.3"
+ dependencies:
+ bn.js: "npm:^4.1.0"
+ browserify-rsa: "npm:^4.0.0"
+ create-hash: "npm:^1.1.0"
+ parse-asn1: "npm:^5.0.0"
+ randombytes: "npm:^2.0.1"
+ safe-buffer: "npm:^5.1.2"
+ checksum: 10c0/6c2cc19fbb554449e47f2175065d6b32f828f9b3badbee4c76585ac28ae8641aafb9bb107afc430c33c5edd6b05dbe318df4f7d6d7712b1093407b11c4280700
+ languageName: node
+ linkType: hard
+
+"punycode@npm:^1.4.1":
+ version: 1.4.1
+ resolution: "punycode@npm:1.4.1"
+ checksum: 10c0/354b743320518aef36f77013be6e15da4db24c2b4f62c5f1eb0529a6ed02fbaf1cb52925785f6ab85a962f2b590d9cd5ad730b70da72b5f180e2556b8bd3ca08
+ languageName: node
+ linkType: hard
+
+"punycode@npm:^2.1.0":
+ version: 2.3.1
+ resolution: "punycode@npm:2.3.1"
+ checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9
+ languageName: node
+ linkType: hard
+
+"qrcode@npm:1.5.3":
+ version: 1.5.3
+ resolution: "qrcode@npm:1.5.3"
+ dependencies:
+ dijkstrajs: "npm:^1.0.1"
+ encode-utf8: "npm:^1.0.3"
+ pngjs: "npm:^5.0.0"
+ yargs: "npm:^15.3.1"
+ bin:
+ qrcode: bin/qrcode
+ checksum: 10c0/eb961cd8246e00ae338b6d4a3a28574174456db42cec7070aa2b315fb6576b7f040b0e4347be290032e447359a145c68cb60ef884d55ca3e1076294fed46f719
+ languageName: node
+ linkType: hard
+
+"qs@npm:^6.12.3":
+ version: 6.15.2
+ resolution: "qs@npm:6.15.2"
+ dependencies:
+ side-channel: "npm:^1.1.0"
+ checksum: 10c0/e6fd5f6f0aab06d480fe9ab15cebfc4ce4235303e2f91dc69a8f7f4df1e668a61c11d1cfbabacf4295cbbeb7b670ed23db45307480726259761f98e5695e93a7
+ languageName: node
+ linkType: hard
+
+"querystring-es3@npm:^0.2.1":
+ version: 0.2.1
+ resolution: "querystring-es3@npm:0.2.1"
+ checksum: 10c0/476938c1adb45c141f024fccd2ffd919a3746e79ed444d00e670aad68532977b793889648980e7ca7ff5ffc7bfece623118d0fbadcaf217495eeb7059ae51580
+ languageName: node
+ linkType: hard
+
+"quick-format-unescaped@npm:^4.0.3":
+ version: 4.0.4
+ resolution: "quick-format-unescaped@npm:4.0.4"
+ checksum: 10c0/fe5acc6f775b172ca5b4373df26f7e4fd347975578199e7d74b2ae4077f0af05baa27d231de1e80e8f72d88275ccc6028568a7a8c9ee5e7368ace0e18eff93a4
+ languageName: node
+ linkType: hard
+
+"radix3@npm:^1.1.2":
+ version: 1.1.2
+ resolution: "radix3@npm:1.1.2"
+ checksum: 10c0/d4a295547f71af079868d2c2ed3814a9296ee026c5488212d58c106e6b4797c6eaec1259b46c9728913622f2240c9a944bfc8e2b3b5f6e4a5045338b1609f1e4
+ languageName: node
+ linkType: hard
+
+"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "randombytes@npm:2.1.0"
+ dependencies:
+ safe-buffer: "npm:^5.1.0"
+ checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3
+ languageName: node
+ linkType: hard
+
+"randomfill@npm:^1.0.4":
+ version: 1.0.4
+ resolution: "randomfill@npm:1.0.4"
+ dependencies:
+ randombytes: "npm:^2.0.5"
+ safe-buffer: "npm:^5.1.0"
+ checksum: 10c0/11aeed35515872e8f8a2edec306734e6b74c39c46653607f03c68385ab8030e2adcc4215f76b5e4598e028c4750d820afd5c65202527d831d2a5f207fe2bc87c
+ languageName: node
+ linkType: hard
+
+"range-parser@npm:1.2.0":
+ version: 1.2.0
+ resolution: "range-parser@npm:1.2.0"
+ checksum: 10c0/c7aef4f6588eb974c475649c157f197d07437d8c6c8ff7e36280a141463fb5ab7a45918417334ebd7b665c6b8321cf31c763f7631dd5f5db9372249261b8b02a
+ languageName: node
+ linkType: hard
+
+"rc@npm:^1.0.1, rc@npm:^1.1.6":
+ version: 1.2.8
+ resolution: "rc@npm:1.2.8"
+ dependencies:
+ deep-extend: "npm:^0.6.0"
+ ini: "npm:~1.3.0"
+ minimist: "npm:^1.2.0"
+ strip-json-comments: "npm:~2.0.1"
+ bin:
+ rc: ./cli.js
+ checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15
+ languageName: node
+ linkType: hard
+
+"react-dom@npm:^19.2.4":
+ version: 19.2.7
+ resolution: "react-dom@npm:19.2.7"
+ dependencies:
+ scheduler: "npm:^0.27.0"
+ peerDependencies:
+ react: ^19.2.7
+ checksum: 10c0/970ff600f6e80d47d39e2f226f12f226173b3cba3382efc97c5f0cd663de9af38c7a4c11c213fb936094faeac83060d660247accaa96b752180d5b951b9cfecb
+ languageName: node
+ linkType: hard
+
+"react-is@npm:^16.13.1, react-is@npm:^16.7.0":
+ version: 16.13.1
+ resolution: "react-is@npm:16.13.1"
+ checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1
+ languageName: node
+ linkType: hard
+
+"react-is@npm:^19.0.0":
+ version: 19.2.7
+ resolution: "react-is@npm:19.2.7"
+ checksum: 10c0/419fe54d5bd7fdf5414a5bb7bd9a1e0e36f9fae28ffb4cb73290fbe342bde15d8584a90d1db62547f6aa03018dce517b178a041abb522136cd4b4b51b4e94c83
+ languageName: node
+ linkType: hard
+
+"react-refresh@npm:^0.17.0":
+ version: 0.17.0
+ resolution: "react-refresh@npm:0.17.0"
+ checksum: 10c0/002cba940384c9930008c0bce26cac97a9d5682bc623112c2268ba0c155127d9c178a9a5cc2212d560088d60dfd503edd808669a25f9b377f316a32361d0b23c
+ languageName: node
+ linkType: hard
+
+"react-router-dom@npm:^7.13.0":
+ version: 7.17.0
+ resolution: "react-router-dom@npm:7.17.0"
+ dependencies:
+ react-router: "npm:7.17.0"
+ peerDependencies:
+ react: ">=18"
+ react-dom: ">=18"
+ checksum: 10c0/60fc4022bccf2fb17b0d8ae8e7c4bda866ca9bf2d45edf0bcbefc854e97fa8971a589b6b77b984a19abecb718faffde357c829d9a22a7913790d608cc7433714
+ languageName: node
+ linkType: hard
+
+"react-router@npm:7.17.0":
+ version: 7.17.0
+ resolution: "react-router@npm:7.17.0"
+ dependencies:
+ cookie: "npm:^1.0.1"
+ set-cookie-parser: "npm:^2.6.0"
+ peerDependencies:
+ react: ">=18"
+ react-dom: ">=18"
+ peerDependenciesMeta:
+ react-dom:
+ optional: true
+ checksum: 10c0/dfa9b0182edba6fab14ef5ac297b292068e71e05bf7e07c6b45fe073d77002089e8e164542364232a8bbb0c7d3ec47b57b78db3984c4383e12308f2d31ad404a
+ languageName: node
+ linkType: hard
+
+"react-transition-group@npm:^4.4.5":
+ version: 4.4.5
+ resolution: "react-transition-group@npm:4.4.5"
+ dependencies:
+ "@babel/runtime": "npm:^7.5.5"
+ dom-helpers: "npm:^5.0.1"
+ loose-envify: "npm:^1.4.0"
+ prop-types: "npm:^15.6.2"
+ peerDependencies:
+ react: ">=16.6.0"
+ react-dom: ">=16.6.0"
+ checksum: 10c0/2ba754ba748faefa15f87c96dfa700d5525054a0141de8c75763aae6734af0740e77e11261a1e8f4ffc08fd9ab78510122e05c21c2d79066c38bb6861a886c82
+ languageName: node
+ linkType: hard
+
+"react@npm:^19.2.4":
+ version: 19.2.7
+ resolution: "react@npm:19.2.7"
+ checksum: 10c0/0bd0e2f1bbd4ba97561c6597bf8a5fec05e6476fe61e165c1065598d16668efc6715205599c94d3ddd49d36cb0f21cbf1b9bcc18ee840b805ce222c3e8d558ac
+ languageName: node
+ linkType: hard
+
+"readable-stream@npm:^2.3.8":
+ version: 2.3.8
+ resolution: "readable-stream@npm:2.3.8"
+ dependencies:
+ core-util-is: "npm:~1.0.0"
+ inherits: "npm:~2.0.3"
+ isarray: "npm:~1.0.0"
+ process-nextick-args: "npm:~2.0.0"
+ safe-buffer: "npm:~5.1.1"
+ string_decoder: "npm:~1.1.1"
+ util-deprecate: "npm:~1.0.1"
+ checksum: 10c0/7efdb01f3853bc35ac62ea25493567bf588773213f5f4a79f9c365e1ad13bab845ac0dae7bc946270dc40c3929483228415e92a3fc600cc7e4548992f41ee3fa
+ languageName: node
+ linkType: hard
+
+"readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0":
+ version: 3.6.2
+ resolution: "readable-stream@npm:3.6.2"
+ dependencies:
+ inherits: "npm:^2.0.3"
+ string_decoder: "npm:^1.1.1"
+ util-deprecate: "npm:^1.0.1"
+ checksum: 10c0/e37be5c79c376fdd088a45fa31ea2e423e5d48854be7a22a58869b4e84d25047b193f6acb54f1012331e1bcd667ffb569c01b99d36b0bd59658fb33f513511b7
+ languageName: node
+ linkType: hard
+
+"readdirp@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "readdirp@npm:5.0.0"
+ checksum: 10c0/faf1ec57cff2020f473128da3f8d2a57813cc3a08a36c38cae1c9af32c1579906cc50ba75578043b35bade77e945c098233665797cf9730ba3613a62d6e79219
+ languageName: node
+ linkType: hard
+
+"real-require@npm:^0.2.0":
+ version: 0.2.0
+ resolution: "real-require@npm:0.2.0"
+ checksum: 10c0/23eea5623642f0477412ef8b91acd3969015a1501ed34992ada0e3af521d3c865bb2fe4cdbfec5fe4b505f6d1ef6a03e5c3652520837a8c3b53decff7e74b6a0
+ languageName: node
+ linkType: hard
+
+"registry-auth-token@npm:3.3.2":
+ version: 3.3.2
+ resolution: "registry-auth-token@npm:3.3.2"
+ dependencies:
+ rc: "npm:^1.1.6"
+ safe-buffer: "npm:^5.0.1"
+ checksum: 10c0/934b5d504ec6d94d78672dc5e74646c52793e74a6e400c1cffc78838bbb12c5f45e3ef3edba506f3295db794d4dda76f924f2948d48fe1f8e83b6500b0ba53c5
+ languageName: node
+ linkType: hard
+
+"registry-url@npm:3.1.0":
+ version: 3.1.0
+ resolution: "registry-url@npm:3.1.0"
+ dependencies:
+ rc: "npm:^1.0.1"
+ checksum: 10c0/345cf9638f99d95863d92800b3f595ac312c19d6865595e499fbeb33fcda04021a0dbdafbb5e61a838a89a558bc239d78752a1f90eb68cf53fdf0d91da816a7c
+ languageName: node
+ linkType: hard
+
+"require-directory@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "require-directory@npm:2.1.1"
+ checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99
+ languageName: node
+ linkType: hard
+
+"require-from-string@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "require-from-string@npm:2.0.2"
+ checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2
+ languageName: node
+ linkType: hard
+
+"require-main-filename@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "require-main-filename@npm:2.0.0"
+ checksum: 10c0/db91467d9ead311b4111cbd73a4e67fa7820daed2989a32f7023785a2659008c6d119752d9c4ac011ae07e537eb86523adff99804c5fdb39cd3a017f9b401bb6
+ languageName: node
+ linkType: hard
+
+"resolve-from@npm:^4.0.0":
+ version: 4.0.0
+ resolution: "resolve-from@npm:4.0.0"
+ checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190
+ languageName: node
+ linkType: hard
+
+"resolve@npm:^1.17.0, resolve@npm:^1.19.0":
+ version: 1.22.12
+ resolution: "resolve@npm:1.22.12"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ is-core-module: "npm:^2.16.1"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/b16dc9b537c02e8c3388f7d3dcff9741d3071625f9a97ac1c885f2b0ca51e78df22328fb6d6ef214dd9101fb7cfc19aa2836fe3410402a94f3f7b8639c7149bf
+ languageName: node
+ linkType: hard
+
+"resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin":
+ version: 1.22.12
+ resolution: "resolve@patch:resolve@npm%3A1.22.12#optional!builtin::version=1.22.12&hash=c3c19d"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ is-core-module: "npm:^2.16.1"
+ path-parse: "npm:^1.0.7"
+ supports-preserve-symlinks-flag: "npm:^1.0.0"
+ bin:
+ resolve: bin/resolve
+ checksum: 10c0/fc6519984ae1f894d877c0060ba8b1f5ba3bc0e85a02f74e141929c118c23d74d9735619a9cc2965397387e514884245c65d72a40731dcb6cfc84c7bcdc8321e
+ languageName: node
+ linkType: hard
+
+"ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1, ripemd160@npm:^2.0.3":
+ version: 2.0.3
+ resolution: "ripemd160@npm:2.0.3"
+ dependencies:
+ hash-base: "npm:^3.1.2"
+ inherits: "npm:^2.0.4"
+ checksum: 10c0/3f472fb453241cfe692a77349accafca38dbcdc9d96d5848c088b2932ba41eb968630ecff7b175d291c7487a4945aee5a81e30c064d1f94e36070f7e0c37ed6c
+ languageName: node
+ linkType: hard
+
+"rolldown@npm:1.0.3":
+ version: 1.0.3
+ resolution: "rolldown@npm:1.0.3"
+ dependencies:
+ "@oxc-project/types": "npm:=0.133.0"
+ "@rolldown/binding-android-arm64": "npm:1.0.3"
+ "@rolldown/binding-darwin-arm64": "npm:1.0.3"
+ "@rolldown/binding-darwin-x64": "npm:1.0.3"
+ "@rolldown/binding-freebsd-x64": "npm:1.0.3"
+ "@rolldown/binding-linux-arm-gnueabihf": "npm:1.0.3"
+ "@rolldown/binding-linux-arm64-gnu": "npm:1.0.3"
+ "@rolldown/binding-linux-arm64-musl": "npm:1.0.3"
+ "@rolldown/binding-linux-ppc64-gnu": "npm:1.0.3"
+ "@rolldown/binding-linux-s390x-gnu": "npm:1.0.3"
+ "@rolldown/binding-linux-x64-gnu": "npm:1.0.3"
+ "@rolldown/binding-linux-x64-musl": "npm:1.0.3"
+ "@rolldown/binding-openharmony-arm64": "npm:1.0.3"
+ "@rolldown/binding-wasm32-wasi": "npm:1.0.3"
+ "@rolldown/binding-win32-arm64-msvc": "npm:1.0.3"
+ "@rolldown/binding-win32-x64-msvc": "npm:1.0.3"
+ "@rolldown/pluginutils": "npm:^1.0.0"
+ dependenciesMeta:
+ "@rolldown/binding-android-arm64":
+ optional: true
+ "@rolldown/binding-darwin-arm64":
+ optional: true
+ "@rolldown/binding-darwin-x64":
+ optional: true
+ "@rolldown/binding-freebsd-x64":
+ optional: true
+ "@rolldown/binding-linux-arm-gnueabihf":
+ optional: true
+ "@rolldown/binding-linux-arm64-gnu":
+ optional: true
+ "@rolldown/binding-linux-arm64-musl":
+ optional: true
+ "@rolldown/binding-linux-ppc64-gnu":
+ optional: true
+ "@rolldown/binding-linux-s390x-gnu":
+ optional: true
+ "@rolldown/binding-linux-x64-gnu":
+ optional: true
+ "@rolldown/binding-linux-x64-musl":
+ optional: true
+ "@rolldown/binding-openharmony-arm64":
+ optional: true
+ "@rolldown/binding-wasm32-wasi":
+ optional: true
+ "@rolldown/binding-win32-arm64-msvc":
+ optional: true
+ "@rolldown/binding-win32-x64-msvc":
+ optional: true
+ bin:
+ rolldown: ./bin/cli.mjs
+ checksum: 10c0/5f9dd47b7abf203b16bc600db68542f245e974c800e59ff50b76157d1dada1403657690435b036fabca88e93d13a67c31abe5cfaa6f61ce33717f61720204cdf
+ languageName: node
+ linkType: hard
+
+"rollup@npm:^4.34.9":
+ version: 4.61.1
+ resolution: "rollup@npm:4.61.1"
+ dependencies:
+ "@rollup/rollup-android-arm-eabi": "npm:4.61.1"
+ "@rollup/rollup-android-arm64": "npm:4.61.1"
+ "@rollup/rollup-darwin-arm64": "npm:4.61.1"
+ "@rollup/rollup-darwin-x64": "npm:4.61.1"
+ "@rollup/rollup-freebsd-arm64": "npm:4.61.1"
+ "@rollup/rollup-freebsd-x64": "npm:4.61.1"
+ "@rollup/rollup-linux-arm-gnueabihf": "npm:4.61.1"
+ "@rollup/rollup-linux-arm-musleabihf": "npm:4.61.1"
+ "@rollup/rollup-linux-arm64-gnu": "npm:4.61.1"
+ "@rollup/rollup-linux-arm64-musl": "npm:4.61.1"
+ "@rollup/rollup-linux-loong64-gnu": "npm:4.61.1"
+ "@rollup/rollup-linux-loong64-musl": "npm:4.61.1"
+ "@rollup/rollup-linux-ppc64-gnu": "npm:4.61.1"
+ "@rollup/rollup-linux-ppc64-musl": "npm:4.61.1"
+ "@rollup/rollup-linux-riscv64-gnu": "npm:4.61.1"
+ "@rollup/rollup-linux-riscv64-musl": "npm:4.61.1"
+ "@rollup/rollup-linux-s390x-gnu": "npm:4.61.1"
+ "@rollup/rollup-linux-x64-gnu": "npm:4.61.1"
+ "@rollup/rollup-linux-x64-musl": "npm:4.61.1"
+ "@rollup/rollup-openbsd-x64": "npm:4.61.1"
+ "@rollup/rollup-openharmony-arm64": "npm:4.61.1"
+ "@rollup/rollup-win32-arm64-msvc": "npm:4.61.1"
+ "@rollup/rollup-win32-ia32-msvc": "npm:4.61.1"
+ "@rollup/rollup-win32-x64-gnu": "npm:4.61.1"
+ "@rollup/rollup-win32-x64-msvc": "npm:4.61.1"
+ "@types/estree": "npm:1.0.9"
+ fsevents: "npm:~2.3.2"
+ dependenciesMeta:
+ "@rollup/rollup-android-arm-eabi":
+ optional: true
+ "@rollup/rollup-android-arm64":
+ optional: true
+ "@rollup/rollup-darwin-arm64":
+ optional: true
+ "@rollup/rollup-darwin-x64":
+ optional: true
+ "@rollup/rollup-freebsd-arm64":
+ optional: true
+ "@rollup/rollup-freebsd-x64":
+ optional: true
+ "@rollup/rollup-linux-arm-gnueabihf":
+ optional: true
+ "@rollup/rollup-linux-arm-musleabihf":
+ optional: true
+ "@rollup/rollup-linux-arm64-gnu":
+ optional: true
+ "@rollup/rollup-linux-arm64-musl":
+ optional: true
+ "@rollup/rollup-linux-loong64-gnu":
+ optional: true
+ "@rollup/rollup-linux-loong64-musl":
+ optional: true
+ "@rollup/rollup-linux-ppc64-gnu":
+ optional: true
+ "@rollup/rollup-linux-ppc64-musl":
+ optional: true
+ "@rollup/rollup-linux-riscv64-gnu":
+ optional: true
+ "@rollup/rollup-linux-riscv64-musl":
+ optional: true
+ "@rollup/rollup-linux-s390x-gnu":
+ optional: true
+ "@rollup/rollup-linux-x64-gnu":
+ optional: true
+ "@rollup/rollup-linux-x64-musl":
+ optional: true
+ "@rollup/rollup-openbsd-x64":
+ optional: true
+ "@rollup/rollup-openharmony-arm64":
+ optional: true
+ "@rollup/rollup-win32-arm64-msvc":
+ optional: true
+ "@rollup/rollup-win32-ia32-msvc":
+ optional: true
+ "@rollup/rollup-win32-x64-gnu":
+ optional: true
+ "@rollup/rollup-win32-x64-msvc":
+ optional: true
+ fsevents:
+ optional: true
+ bin:
+ rollup: dist/bin/rollup
+ checksum: 10c0/6f35736125f3c28c5d8ce1c89c9653b282833b93f60fe29fcc20169bac46579b4d4bcfcb2bfb7e36dcfd4a7bbd6d84e4adf58c2bf9e6dbb4a3c1ed5c932ba8c6
+ languageName: node
+ linkType: hard
+
+"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0":
+ version: 5.2.1
+ resolution: "safe-buffer@npm:5.2.1"
+ checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3
+ languageName: node
+ linkType: hard
+
+"safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1":
+ version: 5.1.2
+ resolution: "safe-buffer@npm:5.1.2"
+ checksum: 10c0/780ba6b5d99cc9a40f7b951d47152297d0e260f0df01472a1b99d4889679a4b94a13d644f7dbc4f022572f09ae9005fa2fbb93bbbd83643316f365a3e9a45b21
+ languageName: node
+ linkType: hard
+
+"safe-regex-test@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "safe-regex-test@npm:1.1.0"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ es-errors: "npm:^1.3.0"
+ is-regex: "npm:^1.2.1"
+ checksum: 10c0/f2c25281bbe5d39cddbbce7f86fca5ea9b3ce3354ea6cd7c81c31b006a5a9fff4286acc5450a3b9122c56c33eba69c56b9131ad751457b2b4a585825e6a10665
+ languageName: node
+ linkType: hard
+
+"safe-stable-stringify@npm:^2.3.1":
+ version: 2.5.0
+ resolution: "safe-stable-stringify@npm:2.5.0"
+ checksum: 10c0/baea14971858cadd65df23894a40588ed791769db21bafb7fd7608397dbdce9c5aac60748abae9995e0fc37e15f2061980501e012cd48859740796bea2987f49
+ languageName: node
+ linkType: hard
+
+"scheduler@npm:^0.27.0":
+ version: 0.27.0
+ resolution: "scheduler@npm:0.27.0"
+ checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452
+ languageName: node
+ linkType: hard
+
+"secp256k1@npm:^5.0.1":
+ version: 5.0.1
+ resolution: "secp256k1@npm:5.0.1"
+ dependencies:
+ elliptic: "npm:^6.5.7"
+ node-addon-api: "npm:^5.0.0"
+ node-gyp: "npm:latest"
+ node-gyp-build: "npm:^4.2.0"
+ checksum: 10c0/ea977fcd3a21ee10439a546774d4f3f474f065a561fc2247f65cb2a64f09628732fd606c0a62316858abd7c07b41f5aa09c37773537f233590b4cf94d752dbe7
+ languageName: node
+ linkType: hard
+
+"semver@npm:7.7.2":
+ version: 7.7.2
+ resolution: "semver@npm:7.7.2"
+ bin:
+ semver: bin/semver.js
+ checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea
+ languageName: node
+ linkType: hard
+
+"semver@npm:^6.3.1":
+ version: 6.3.1
+ resolution: "semver@npm:6.3.1"
+ bin:
+ semver: bin/semver.js
+ checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d
+ languageName: node
+ linkType: hard
+
+"semver@npm:^7.3.5, semver@npm:^7.7.3":
+ version: 7.8.4
+ resolution: "semver@npm:7.8.4"
+ bin:
+ semver: bin/semver.js
+ checksum: 10c0/81b7c296fd7927b80f67fa516b75fa1017caac8167795320de28e76ccbc6f7f01763c30ecd10d6a0d8fd089708ab0548a5aebb94b0870e99c2a2b4600a46389b
+ languageName: node
+ linkType: hard
+
+"serve-handler@npm:6.1.7":
+ version: 6.1.7
+ resolution: "serve-handler@npm:6.1.7"
+ dependencies:
+ bytes: "npm:3.0.0"
+ content-disposition: "npm:0.5.2"
+ mime-types: "npm:2.1.18"
+ minimatch: "npm:3.1.5"
+ path-is-inside: "npm:1.0.2"
+ path-to-regexp: "npm:3.3.0"
+ range-parser: "npm:1.2.0"
+ checksum: 10c0/35afb68d81afd3c38d15792a5bc2451915b739bef2898a47ebd190db6a4e29846530ac00292b8008fe7297a819257c3948be2deaf4ffd32c96689e8947cf0ae9
+ languageName: node
+ linkType: hard
+
+"serve@npm:^14.2.4":
+ version: 14.2.6
+ resolution: "serve@npm:14.2.6"
+ dependencies:
+ "@zeit/schemas": "npm:2.36.0"
+ ajv: "npm:8.18.0"
+ arg: "npm:5.0.2"
+ boxen: "npm:7.0.0"
+ chalk: "npm:5.0.1"
+ chalk-template: "npm:0.4.0"
+ clipboardy: "npm:3.0.0"
+ compression: "npm:1.8.1"
+ is-port-reachable: "npm:4.0.0"
+ serve-handler: "npm:6.1.7"
+ update-check: "npm:1.5.4"
+ bin:
+ serve: build/main.js
+ checksum: 10c0/7e1668e0d187719dbe4f3de967012ce2263c967f6135d9c630f803b0f173334e1442ab326fcc4c8e6cd4e293d8bd8c773aebab2746ecaa0fb1ab29a36079763b
+ languageName: node
+ linkType: hard
+
+"set-blocking@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "set-blocking@npm:2.0.0"
+ checksum: 10c0/9f8c1b2d800800d0b589de1477c753492de5c1548d4ade52f57f1d1f5e04af5481554d75ce5e5c43d4004b80a3eb714398d6907027dc0534177b7539119f4454
+ languageName: node
+ linkType: hard
+
+"set-cookie-parser@npm:^2.6.0":
+ version: 2.7.2
+ resolution: "set-cookie-parser@npm:2.7.2"
+ checksum: 10c0/4381a9eb7ee951dfe393fe7aacf76b9a3b4e93a684d2162ab35594fa4053cc82a4d7d7582bf397718012c9adcf839b8cd8f57c6c42901ea9effe33c752da4a45
+ languageName: node
+ linkType: hard
+
+"set-function-length@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "set-function-length@npm:1.2.2"
+ dependencies:
+ define-data-property: "npm:^1.1.4"
+ es-errors: "npm:^1.3.0"
+ function-bind: "npm:^1.1.2"
+ get-intrinsic: "npm:^1.2.4"
+ gopd: "npm:^1.0.1"
+ has-property-descriptors: "npm:^1.0.2"
+ checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c
+ languageName: node
+ linkType: hard
+
+"setimmediate@npm:^1.0.4":
+ version: 1.0.5
+ resolution: "setimmediate@npm:1.0.5"
+ checksum: 10c0/5bae81bfdbfbd0ce992893286d49c9693c82b1bcc00dcaaf3a09c8f428fdeacf4190c013598b81875dfac2b08a572422db7df779a99332d0fce186d15a3e4d49
+ languageName: node
+ linkType: hard
+
+"sha.js@npm:^2.4.0, sha.js@npm:^2.4.12, sha.js@npm:^2.4.8":
+ version: 2.4.12
+ resolution: "sha.js@npm:2.4.12"
+ dependencies:
+ inherits: "npm:^2.0.4"
+ safe-buffer: "npm:^5.2.1"
+ to-buffer: "npm:^1.2.0"
+ bin:
+ sha.js: bin.js
+ checksum: 10c0/9d36bdd76202c8116abbe152a00055ccd8a0099cb28fc17c01fa7bb2c8cffb9ca60e2ab0fe5f274ed6c45dc2633d8c39cf7ab050306c231904512ba9da4d8ab1
+ languageName: node
+ linkType: hard
+
+"shebang-command@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "shebang-command@npm:2.0.0"
+ dependencies:
+ shebang-regex: "npm:^3.0.0"
+ checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e
+ languageName: node
+ linkType: hard
+
+"shebang-regex@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "shebang-regex@npm:3.0.0"
+ checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690
+ languageName: node
+ linkType: hard
+
+"side-channel-list@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "side-channel-list@npm:1.0.1"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ object-inspect: "npm:^1.13.4"
+ checksum: 10c0/d346c787fd2f9f1c2fdea14f00e8250118db0e7596d85a6cb9faa75f105d31a73a8f7a341c93d7df2a2429098c3d37a77bd3be9e88c37094b8c01807bc77c7a2
+ languageName: node
+ linkType: hard
+
+"side-channel-map@npm:^1.0.1":
+ version: 1.0.1
+ resolution: "side-channel-map@npm:1.0.1"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.5"
+ object-inspect: "npm:^1.13.3"
+ checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672
+ languageName: node
+ linkType: hard
+
+"side-channel-weakmap@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "side-channel-weakmap@npm:1.0.2"
+ dependencies:
+ call-bound: "npm:^1.0.2"
+ es-errors: "npm:^1.3.0"
+ get-intrinsic: "npm:^1.2.5"
+ object-inspect: "npm:^1.13.3"
+ side-channel-map: "npm:^1.0.1"
+ checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185
+ languageName: node
+ linkType: hard
+
+"side-channel@npm:^1.1.0":
+ version: 1.1.1
+ resolution: "side-channel@npm:1.1.1"
+ dependencies:
+ es-errors: "npm:^1.3.0"
+ object-inspect: "npm:^1.13.4"
+ side-channel-list: "npm:^1.0.1"
+ side-channel-map: "npm:^1.0.1"
+ side-channel-weakmap: "npm:^1.0.2"
+ checksum: 10c0/dc0ab81d67f61bda9247d053ce93f41c3fd8ad2bdcb9cf9d8d2f8540d488f26d87a5e99ebfc07eea49ec025867b2452b705442d974b1478f0395e69f6bfb3270
+ languageName: node
+ linkType: hard
+
+"siginfo@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "siginfo@npm:2.0.0"
+ checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34
+ languageName: node
+ linkType: hard
+
+"signal-exit@npm:^3.0.3":
+ version: 3.0.7
+ resolution: "signal-exit@npm:3.0.7"
+ checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912
+ languageName: node
+ linkType: hard
+
+"slow-redact@npm:^0.3.0":
+ version: 0.3.2
+ resolution: "slow-redact@npm:0.3.2"
+ checksum: 10c0/d6611e518461d918eda9a77903100e097870035c8ef8ce95eec7d7a2eafc6c0cdfc37476a1fecf9d70e0b6b36eb9d862f4ac58e931c305b3fc010939226fa803
+ languageName: node
+ linkType: hard
+
+"sonic-boom@npm:^4.0.1":
+ version: 4.2.1
+ resolution: "sonic-boom@npm:4.2.1"
+ dependencies:
+ atomic-sleep: "npm:^1.0.0"
+ checksum: 10c0/f374e9c3dfe194d706d8ef8aed4e28bc10638f9952fd19bcbddf2cef05d53334ad9e9dca3e01e24e88dd88fb278c6b8c5b2ae5002494b289c4914aaea3d9eae9
+ languageName: node
+ linkType: hard
+
+"source-map-js@npm:^1.2.1":
+ version: 1.2.1
+ resolution: "source-map-js@npm:1.2.1"
+ checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf
+ languageName: node
+ linkType: hard
+
+"source-map@npm:^0.5.7":
+ version: 0.5.7
+ resolution: "source-map@npm:0.5.7"
+ checksum: 10c0/904e767bb9c494929be013017380cbba013637da1b28e5943b566031e29df04fba57edf3f093e0914be094648b577372bd8ad247fa98cfba9c600794cd16b599
+ languageName: node
+ linkType: hard
+
+"split2@npm:^4.0.0":
+ version: 4.2.0
+ resolution: "split2@npm:4.2.0"
+ checksum: 10c0/b292beb8ce9215f8c642bb68be6249c5a4c7f332fc8ecadae7be5cbdf1ea95addc95f0459ef2e7ad9d45fd1064698a097e4eb211c83e772b49bc0ee423e91534
+ languageName: node
+ linkType: hard
+
+"stackback@npm:0.0.2":
+ version: 0.0.2
+ resolution: "stackback@npm:0.0.2"
+ checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983
+ languageName: node
+ linkType: hard
+
+"std-env@npm:^4.0.0-rc.1":
+ version: 4.1.0
+ resolution: "std-env@npm:4.1.0"
+ checksum: 10c0/2e14b6b490db34cb969a48d9cf7c35bca4a47653914aac2814221baae7b867a5b15940d133625c391621971f98cd2266a5dc7036669960e883f1081db2a56558
+ languageName: node
+ linkType: hard
+
+"stream-browserify@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "stream-browserify@npm:3.0.0"
+ dependencies:
+ inherits: "npm:~2.0.4"
+ readable-stream: "npm:^3.5.0"
+ checksum: 10c0/ec3b975a4e0aa4b3dc5e70ffae3fc8fd29ac725353a14e72f213dff477b00330140ad014b163a8cbb9922dfe90803f81a5ea2b269e1bbfd8bd71511b88f889ad
+ languageName: node
+ linkType: hard
+
+"stream-http@npm:^3.2.0":
+ version: 3.2.0
+ resolution: "stream-http@npm:3.2.0"
+ dependencies:
+ builtin-status-codes: "npm:^3.0.0"
+ inherits: "npm:^2.0.4"
+ readable-stream: "npm:^3.6.0"
+ xtend: "npm:^4.0.2"
+ checksum: 10c0/f128fb8076d60cd548f229554b6a1a70c08a04b7b2afd4dbe7811d20f27f7d4112562eb8bce86d72a8691df3b50573228afcf1271e55e81f981536c67498bc41
+ languageName: node
+ linkType: hard
+
+"string-width@npm:^4.1.0, string-width@npm:^4.2.0":
+ version: 4.2.3
+ resolution: "string-width@npm:4.2.3"
+ dependencies:
+ emoji-regex: "npm:^8.0.0"
+ is-fullwidth-code-point: "npm:^3.0.0"
+ strip-ansi: "npm:^6.0.1"
+ checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b
+ languageName: node
+ linkType: hard
+
+"string-width@npm:^5.0.1, string-width@npm:^5.1.2":
+ version: 5.1.2
+ resolution: "string-width@npm:5.1.2"
+ dependencies:
+ eastasianwidth: "npm:^0.2.0"
+ emoji-regex: "npm:^9.2.2"
+ strip-ansi: "npm:^7.0.1"
+ checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca
+ languageName: node
+ linkType: hard
+
+"string_decoder@npm:^1.0.0, string_decoder@npm:^1.1.1":
+ version: 1.3.0
+ resolution: "string_decoder@npm:1.3.0"
+ dependencies:
+ safe-buffer: "npm:~5.2.0"
+ checksum: 10c0/810614ddb030e271cd591935dcd5956b2410dd079d64ff92a1844d6b7588bf992b3e1b69b0f4d34a3e06e0bd73046ac646b5264c1987b20d0601f81ef35d731d
+ languageName: node
+ linkType: hard
+
+"string_decoder@npm:~1.1.1":
+ version: 1.1.1
+ resolution: "string_decoder@npm:1.1.1"
+ dependencies:
+ safe-buffer: "npm:~5.1.0"
+ checksum: 10c0/b4f89f3a92fd101b5653ca3c99550e07bdf9e13b35037e9e2a1c7b47cec4e55e06ff3fc468e314a0b5e80bfbaf65c1ca5a84978764884ae9413bec1fc6ca924e
+ languageName: node
+ linkType: hard
+
+"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1":
+ version: 6.0.1
+ resolution: "strip-ansi@npm:6.0.1"
+ dependencies:
+ ansi-regex: "npm:^5.0.1"
+ checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952
+ languageName: node
+ linkType: hard
+
+"strip-ansi@npm:^7.0.1":
+ version: 7.2.0
+ resolution: "strip-ansi@npm:7.2.0"
+ dependencies:
+ ansi-regex: "npm:^6.2.2"
+ checksum: 10c0/544d13b7582f8254811ea97db202f519e189e59d35740c46095897e254e4f1aa9fe1524a83ad6bc5ad67d4dd6c0281d2e0219ed62b880a6238a16a17d375f221
+ languageName: node
+ linkType: hard
+
+"strip-final-newline@npm:^2.0.0":
+ version: 2.0.0
+ resolution: "strip-final-newline@npm:2.0.0"
+ checksum: 10c0/bddf8ccd47acd85c0e09ad7375409d81653f645fda13227a9d459642277c253d877b68f2e5e4d819fe75733b0e626bac7e954c04f3236f6d196f79c94fa4a96f
+ languageName: node
+ linkType: hard
+
+"strip-json-comments@npm:~2.0.1":
+ version: 2.0.1
+ resolution: "strip-json-comments@npm:2.0.1"
+ checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43
+ languageName: node
+ linkType: hard
+
+"stylis@npm:4.2.0":
+ version: 4.2.0
+ resolution: "stylis@npm:4.2.0"
+ checksum: 10c0/a7128ad5a8ed72652c6eba46bed4f416521bc9745a460ef5741edc725252cebf36ee45e33a8615a7057403c93df0866ab9ee955960792db210bb80abd5ac6543
+ languageName: node
+ linkType: hard
+
+"supports-color@npm:^7.1.0":
+ version: 7.2.0
+ resolution: "supports-color@npm:7.2.0"
+ dependencies:
+ has-flag: "npm:^4.0.0"
+ checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124
+ languageName: node
+ linkType: hard
+
+"supports-preserve-symlinks-flag@npm:^1.0.0":
+ version: 1.0.0
+ resolution: "supports-preserve-symlinks-flag@npm:1.0.0"
+ checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39
+ languageName: node
+ linkType: hard
+
+"tar@npm:^7.5.4":
+ version: 7.5.16
+ resolution: "tar@npm:7.5.16"
+ dependencies:
+ "@isaacs/fs-minipass": "npm:^4.0.0"
+ chownr: "npm:^3.0.0"
+ minipass: "npm:^7.1.2"
+ minizlib: "npm:^3.1.0"
+ yallist: "npm:^5.0.0"
+ checksum: 10c0/4f37f3c4bd2ca2755fd736a5df1d573c1a868ec1b1e893346aeafa95ac510f9e2fd1469420bd866cc7904799e5bd4ac62b5d4f03fe27747d6e1e373b44505c5c
+ languageName: node
+ linkType: hard
+
+"thread-stream@npm:^3.0.0":
+ version: 3.2.0
+ resolution: "thread-stream@npm:3.2.0"
+ dependencies:
+ real-require: "npm:^0.2.0"
+ checksum: 10c0/417516963f338cf24c27b91e9ac1c1e06ea321333e3369685e9c48afeefc9f18cf5d6c268e24e888f85e9f467d34d35e506c180e2278e2cd9b4c402454206463
+ languageName: node
+ linkType: hard
+
+"timers-browserify@npm:^2.0.4":
+ version: 2.0.12
+ resolution: "timers-browserify@npm:2.0.12"
+ dependencies:
+ setimmediate: "npm:^1.0.4"
+ checksum: 10c0/98e84db1a685bc8827c117a8bc62aac811ad56a995d07938fc7ed8cdc5bf3777bfe2d4e5da868847194e771aac3749a20f6cdd22091300fe889a76fe214a4641
+ languageName: node
+ linkType: hard
+
+"tinybench@npm:^2.9.0":
+ version: 2.9.0
+ resolution: "tinybench@npm:2.9.0"
+ checksum: 10c0/c3500b0f60d2eb8db65250afe750b66d51623057ee88720b7f064894a6cb7eb93360ca824a60a31ab16dab30c7b1f06efe0795b352e37914a9d4bad86386a20c
+ languageName: node
+ linkType: hard
+
+"tinyexec@npm:^1.0.2":
+ version: 1.2.4
+ resolution: "tinyexec@npm:1.2.4"
+ checksum: 10c0/153b8db6b080194b558ff145b9cffc36b80a6e07babd644dcfbe49c807eee668c876049d28bdee90b96304476f883352f2dad91b3f86bc23832532f4363e66ff
+ languageName: node
+ linkType: hard
+
+"tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.13, tinyglobby@npm:^0.2.15, tinyglobby@npm:^0.2.17":
+ version: 0.2.17
+ resolution: "tinyglobby@npm:0.2.17"
+ dependencies:
+ fdir: "npm:^6.5.0"
+ picomatch: "npm:^4.0.4"
+ checksum: 10c0/7f7bb0f197c88bc4b20c231e0deca4240ca3bf313a88f5a7fee93a872b84966a4d50220947c0455ad07a60b3b360961c5b7fd979222aeb716a9f99b412002e4c
+ languageName: node
+ linkType: hard
+
+"tinyrainbow@npm:^3.1.0":
+ version: 3.1.0
+ resolution: "tinyrainbow@npm:3.1.0"
+ checksum: 10c0/f11cf387a26c5c9255bec141a90ac511b26172981b10c3e50053bc6700ea7d2336edcc4a3a21dbb8412fe7c013477d2ba4d7e4877800f3f8107be5105aad6511
+ languageName: node
+ linkType: hard
+
+"to-buffer@npm:^1.2.0, to-buffer@npm:^1.2.1, to-buffer@npm:^1.2.2":
+ version: 1.2.2
+ resolution: "to-buffer@npm:1.2.2"
+ dependencies:
+ isarray: "npm:^2.0.5"
+ safe-buffer: "npm:^5.2.1"
+ typed-array-buffer: "npm:^1.0.3"
+ checksum: 10c0/56bc56352f14a2c4a0ab6277c5fc19b51e9534882b98eb068b39e14146591e62fa5b06bf70f7fed1626230463d7e60dca81e815096656e5e01c195c593873d12
+ languageName: node
+ linkType: hard
+
+"tr46@npm:~0.0.3":
+ version: 0.0.3
+ resolution: "tr46@npm:0.0.3"
+ checksum: 10c0/047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11
+ languageName: node
+ linkType: hard
+
+"ts-api-utils@npm:^2.5.0":
+ version: 2.5.0
+ resolution: "ts-api-utils@npm:2.5.0"
+ peerDependencies:
+ typescript: ">=4.8.4"
+ checksum: 10c0/767849383c114e7f1971fa976b20e73ac28fd0c70d8d65c0004790bf4d8f89888c7e4cf6d5949f9c1beae9bc3c64835bef77bbe27fddf45a3c7b60cebcf85c8c
+ languageName: node
+ linkType: hard
+
+"tslib@npm:1.14.1":
+ version: 1.14.1
+ resolution: "tslib@npm:1.14.1"
+ checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2
+ languageName: node
+ linkType: hard
+
+"tslib@npm:2.7.0":
+ version: 2.7.0
+ resolution: "tslib@npm:2.7.0"
+ checksum: 10c0/469e1d5bf1af585742128827000711efa61010b699cb040ab1800bcd3ccdd37f63ec30642c9e07c4439c1db6e46345582614275daca3e0f4abae29b0083f04a6
+ languageName: node
+ linkType: hard
+
+"tslib@npm:^2.1.0, tslib@npm:^2.4.0":
+ version: 2.8.1
+ resolution: "tslib@npm:2.8.1"
+ checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62
+ languageName: node
+ linkType: hard
+
+"tty-browserify@npm:0.0.1":
+ version: 0.0.1
+ resolution: "tty-browserify@npm:0.0.1"
+ checksum: 10c0/5e34883388eb5f556234dae75b08e069b9e62de12bd6d87687f7817f5569430a6dfef550b51dbc961715ae0cd0eb5a059e6e3fc34dc127ea164aa0f9b5bb033d
+ languageName: node
+ linkType: hard
+
+"type-check@npm:^0.4.0, type-check@npm:~0.4.0":
+ version: 0.4.0
+ resolution: "type-check@npm:0.4.0"
+ dependencies:
+ prelude-ls: "npm:^1.2.1"
+ checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58
+ languageName: node
+ linkType: hard
+
+"type-fest@npm:^2.13.0":
+ version: 2.19.0
+ resolution: "type-fest@npm:2.19.0"
+ checksum: 10c0/a5a7ecf2e654251613218c215c7493574594951c08e52ab9881c9df6a6da0aeca7528c213c622bc374b4e0cb5c443aa3ab758da4e3c959783ce884c3194e12cb
+ languageName: node
+ linkType: hard
+
+"typed-array-buffer@npm:^1.0.3":
+ version: 1.0.3
+ resolution: "typed-array-buffer@npm:1.0.3"
+ dependencies:
+ call-bound: "npm:^1.0.3"
+ es-errors: "npm:^1.3.0"
+ is-typed-array: "npm:^1.1.14"
+ checksum: 10c0/1105071756eb248774bc71646bfe45b682efcad93b55532c6ffa4518969fb6241354e4aa62af679ae83899ec296d69ef88f1f3763657cdb3a4d29321f7b83079
+ languageName: node
+ linkType: hard
+
+"typescript-eslint@npm:^8.57.0":
+ version: 8.61.0
+ resolution: "typescript-eslint@npm:8.61.0"
+ dependencies:
+ "@typescript-eslint/eslint-plugin": "npm:8.61.0"
+ "@typescript-eslint/parser": "npm:8.61.0"
+ "@typescript-eslint/typescript-estree": "npm:8.61.0"
+ "@typescript-eslint/utils": "npm:8.61.0"
+ peerDependencies:
+ eslint: ^8.57.0 || ^9.0.0 || ^10.0.0
+ typescript: ">=4.8.4 <6.1.0"
+ checksum: 10c0/172ba723c7ea07e5b22541ca3e8eb1b5e0b837e21278a915a293a2d5e7cac7ce9f0ad73cd61a3cdec98a511c76586eb3865d1581f2acc0b691e007703d4764b2
+ languageName: node
+ linkType: hard
+
+"typescript@npm:^5.6.3":
+ version: 5.9.3
+ resolution: "typescript@npm:5.9.3"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5
+ languageName: node
+ linkType: hard
+
+"typescript@patch:typescript@npm%3A^5.6.3#optional!builtin":
+ version: 5.9.3
+ resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5"
+ bin:
+ tsc: bin/tsc
+ tsserver: bin/tsserver
+ checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430
+ languageName: node
+ linkType: hard
+
+"ufo@npm:^1.6.1, ufo@npm:^1.6.3":
+ version: 1.6.4
+ resolution: "ufo@npm:1.6.4"
+ checksum: 10c0/3a2b29e7e3d772fbf6893d7d23bf442981457adb2fe122828abdbda89bedcb81aafd0dcc080e41b45f9a877db00cb42cbfee9639753a19d9b9bd39b5627039cf
+ languageName: node
+ linkType: hard
+
+"uint8arrays@npm:3.1.1, uint8arrays@npm:^3.0.0":
+ version: 3.1.1
+ resolution: "uint8arrays@npm:3.1.1"
+ dependencies:
+ multiformats: "npm:^9.4.2"
+ checksum: 10c0/9946668e04f29b46bbb73cca3d190f63a2fbfe5452f8e6551ef4257d9d597b72da48fa895c15ef2ef772808a5335b3305f69da5f13a09f8c2924896b409565ff
+ languageName: node
+ linkType: hard
+
+"uncrypto@npm:^0.1.3":
+ version: 0.1.3
+ resolution: "uncrypto@npm:0.1.3"
+ checksum: 10c0/74a29afefd76d5b77bedc983559ceb33f5bbc8dada84ff33755d1e3355da55a4e03a10e7ce717918c436b4dfafde1782e799ebaf2aadd775612b49f7b5b2998e
+ languageName: node
+ linkType: hard
+
+"undici-types@npm:^7.19.2":
+ version: 7.27.2
+ resolution: "undici-types@npm:7.27.2"
+ checksum: 10c0/d3efff570e7f348eea961706090221f61422fc202d4fb8d78fbea7060f0c6ad11f4ee7e796d0e222d6f3f4a6cc54ef22ced5e7fd4ac192b1738a2d30f45ff51b
+ languageName: node
+ linkType: hard
+
+"undici-types@npm:~6.19.2":
+ version: 6.19.8
+ resolution: "undici-types@npm:6.19.8"
+ checksum: 10c0/078afa5990fba110f6824823ace86073b4638f1d5112ee26e790155f481f2a868cc3e0615505b6f4282bdf74a3d8caad715fd809e870c2bb0704e3ea6082f344
+ languageName: node
+ linkType: hard
+
+"undici-types@npm:~6.21.0":
+ version: 6.21.0
+ resolution: "undici-types@npm:6.21.0"
+ checksum: 10c0/c01ed51829b10aa72fc3ce64b747f8e74ae9b60eafa19a7b46ef624403508a54c526ffab06a14a26b3120d055e1104d7abe7c9017e83ced038ea5cf52f8d5e04
+ languageName: node
+ linkType: hard
+
+"undici@npm:^6.25.0":
+ version: 6.26.0
+ resolution: "undici@npm:6.26.0"
+ checksum: 10c0/cf2b4caf58c33d6582970991290cc7a6486d6e738845f25dcdd16952d708ec844815c6d30362919764fcaf30f719891289341f1ada496f003ce2700310453a47
+ languageName: node
+ linkType: hard
+
+"unstorage@npm:^1.9.0":
+ version: 1.17.5
+ resolution: "unstorage@npm:1.17.5"
+ dependencies:
+ anymatch: "npm:^3.1.3"
+ chokidar: "npm:^5.0.0"
+ destr: "npm:^2.0.5"
+ h3: "npm:^1.15.10"
+ lru-cache: "npm:^11.2.7"
+ node-fetch-native: "npm:^1.6.7"
+ ofetch: "npm:^1.5.1"
+ ufo: "npm:^1.6.3"
+ peerDependencies:
+ "@azure/app-configuration": ^1.8.0
+ "@azure/cosmos": ^4.2.0
+ "@azure/data-tables": ^13.3.0
+ "@azure/identity": ^4.6.0
+ "@azure/keyvault-secrets": ^4.9.0
+ "@azure/storage-blob": ^12.26.0
+ "@capacitor/preferences": ^6 || ^7 || ^8
+ "@deno/kv": ">=0.9.0"
+ "@netlify/blobs": ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0
+ "@planetscale/database": ^1.19.0
+ "@upstash/redis": ^1.34.3
+ "@vercel/blob": ">=0.27.1"
+ "@vercel/functions": ^2.2.12 || ^3.0.0
+ "@vercel/kv": ^1 || ^2 || ^3
+ aws4fetch: ^1.0.20
+ db0: ">=0.2.1"
+ idb-keyval: ^6.2.1
+ ioredis: ^5.4.2
+ uploadthing: ^7.4.4
+ peerDependenciesMeta:
+ "@azure/app-configuration":
+ optional: true
+ "@azure/cosmos":
+ optional: true
+ "@azure/data-tables":
+ optional: true
+ "@azure/identity":
+ optional: true
+ "@azure/keyvault-secrets":
+ optional: true
+ "@azure/storage-blob":
+ optional: true
+ "@capacitor/preferences":
+ optional: true
+ "@deno/kv":
+ optional: true
+ "@netlify/blobs":
+ optional: true
+ "@planetscale/database":
+ optional: true
+ "@upstash/redis":
+ optional: true
+ "@vercel/blob":
+ optional: true
+ "@vercel/functions":
+ optional: true
+ "@vercel/kv":
+ optional: true
+ aws4fetch:
+ optional: true
+ db0:
+ optional: true
+ idb-keyval:
+ optional: true
+ ioredis:
+ optional: true
+ uploadthing:
+ optional: true
+ checksum: 10c0/52bc07d0951129f493cc2d2a5204f49df90c85e7ab3faac0019e3a31f22f507f7a8263fca7ca4d019950c14cbfed4d43e15c9afe4b5dcb307249ebb60d2e538e
+ languageName: node
+ linkType: hard
+
+"update-browserslist-db@npm:^1.2.3":
+ version: 1.2.3
+ resolution: "update-browserslist-db@npm:1.2.3"
+ dependencies:
+ escalade: "npm:^3.2.0"
+ picocolors: "npm:^1.1.1"
+ peerDependencies:
+ browserslist: ">= 4.21.0"
+ bin:
+ update-browserslist-db: cli.js
+ checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec
+ languageName: node
+ linkType: hard
+
+"update-check@npm:1.5.4":
+ version: 1.5.4
+ resolution: "update-check@npm:1.5.4"
+ dependencies:
+ registry-auth-token: "npm:3.3.2"
+ registry-url: "npm:3.1.0"
+ checksum: 10c0/ac4b8dafa5db9b1c8ff5d0cfcc3b4c5687c390526b3218155e27173c7ca647572ea9e523dd3463523e698ef94d273768b395748da54655fe773dada59ac9c7b0
+ languageName: node
+ linkType: hard
+
+"uri-js@npm:^4.2.2":
+ version: 4.4.1
+ resolution: "uri-js@npm:4.4.1"
+ dependencies:
+ punycode: "npm:^2.1.0"
+ checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c
+ languageName: node
+ linkType: hard
+
+"url@npm:^0.11.4":
+ version: 0.11.4
+ resolution: "url@npm:0.11.4"
+ dependencies:
+ punycode: "npm:^1.4.1"
+ qs: "npm:^6.12.3"
+ checksum: 10c0/cc93405ae4a9b97a2aa60ca67f1cb1481c0221cb4725a7341d149be5e2f9cfda26fd432d64dbbec693d16593b68b8a46aad8e5eab21f814932134c9d8620c662
+ languageName: node
+ linkType: hard
+
+"use-sync-external-store@npm:1.4.0":
+ version: 1.4.0
+ resolution: "use-sync-external-store@npm:1.4.0"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
+ checksum: 10c0/ec011a5055962c0f6b509d6e78c0b143f8cd069890ae370528753053c55e3b360d3648e76cfaa854faa7a59eb08d6c5fb1015e60ffde9046d32f5b2a295acea5
+ languageName: node
+ linkType: hard
+
+"util-deprecate@npm:^1.0.1, util-deprecate@npm:~1.0.1":
+ version: 1.0.2
+ resolution: "util-deprecate@npm:1.0.2"
+ checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942
+ languageName: node
+ linkType: hard
+
+"util@npm:^0.12.4, util@npm:^0.12.5":
+ version: 0.12.5
+ resolution: "util@npm:0.12.5"
+ dependencies:
+ inherits: "npm:^2.0.3"
+ is-arguments: "npm:^1.0.4"
+ is-generator-function: "npm:^1.0.7"
+ is-typed-array: "npm:^1.1.3"
+ which-typed-array: "npm:^1.1.2"
+ checksum: 10c0/c27054de2cea2229a66c09522d0fa1415fb12d861d08523a8846bf2e4cbf0079d4c3f725f09dcb87493549bcbf05f5798dce1688b53c6c17201a45759e7253f3
+ languageName: node
+ linkType: hard
+
+"validator@npm:^13.12.0":
+ version: 13.15.35
+ resolution: "validator@npm:13.15.35"
+ checksum: 10c0/1958ebcad578128d154853a2b9bf5b95e7738dcc7d1d065e50a969812272312ec379dcaf375b9d7545e04a71de6755f60f5a4b49c1405737a9c80e11da297eef
+ languageName: node
+ linkType: hard
+
+"valtio@npm:2.1.7":
+ version: 2.1.7
+ resolution: "valtio@npm:2.1.7"
+ dependencies:
+ proxy-compare: "npm:^3.0.1"
+ peerDependencies:
+ "@types/react": ">=18.0.0"
+ react: ">=18.0.0"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ react:
+ optional: true
+ checksum: 10c0/727976e35c7b8853b37cfc5ab14dd5be46ddf572482aa2d888c7e41e9b2d54bb5962c8dd7e26bd9ae69687c818464daf0a814098c3bc64b47e1363f0f7109423
+ languageName: node
+ linkType: hard
+
+"vary@npm:~1.1.2":
+ version: 1.1.2
+ resolution: "vary@npm:1.1.2"
+ checksum: 10c0/f15d588d79f3675135ba783c91a4083dcd290a2a5be9fcb6514220a1634e23df116847b1cc51f66bfb0644cf9353b2abb7815ae499bab06e46dd33c1a6bf1f4f
+ languageName: node
+ linkType: hard
+
+"viem@npm:2.x, viem@npm:>=2.45.0, viem@npm:^2.1.1, viem@npm:^2.27.2, viem@npm:^2.31.7, viem@npm:^2.47.0":
+ version: 2.52.2
+ resolution: "viem@npm:2.52.2"
+ dependencies:
+ "@noble/curves": "npm:1.9.1"
+ "@noble/hashes": "npm:1.8.0"
+ "@scure/bip32": "npm:1.7.0"
+ "@scure/bip39": "npm:1.6.0"
+ abitype: "npm:1.2.3"
+ isows: "npm:1.0.7"
+ ox: "npm:0.14.29"
+ ws: "npm:8.20.1"
+ peerDependencies:
+ typescript: ">=5.0.4"
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/5a94c8170cce7f9dafd1b21da4e9dd6c7782600ada7b02db87cf721a2db5b81e8c13476a5e75fcbd4baf852dd9738254e015482076581cb7ce33059e04f57a02
+ languageName: node
+ linkType: hard
+
+"vite-plugin-node-polyfills@npm:^0.25.0":
+ version: 0.25.0
+ resolution: "vite-plugin-node-polyfills@npm:0.25.0"
+ dependencies:
+ "@rollup/plugin-inject": "npm:^5.0.5"
+ node-stdlib-browser: "npm:^1.3.1"
+ peerDependencies:
+ vite: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0
+ checksum: 10c0/4009951255f2545ce4ec82f48f013b1c2b4509017e42c68cac6af8cc0d3f824ef2002915917c6da317c09ff0cde32eed6e98eb5be0d935a3c5cb0b412ebc1625
+ languageName: node
+ linkType: hard
+
+"vite@npm:^6.0.0 || ^7.0.0 || ^8.0.0":
+ version: 8.0.16
+ resolution: "vite@npm:8.0.16"
+ dependencies:
+ fsevents: "npm:~2.3.3"
+ lightningcss: "npm:^1.32.0"
+ picomatch: "npm:^4.0.4"
+ postcss: "npm:^8.5.15"
+ rolldown: "npm:1.0.3"
+ tinyglobby: "npm:^0.2.17"
+ peerDependencies:
+ "@types/node": ^20.19.0 || >=22.12.0
+ "@vitejs/devtools": ^0.1.18
+ esbuild: ^0.27.0 || ^0.28.0
+ jiti: ">=1.21.0"
+ less: ^4.0.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: ">=0.54.8"
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ peerDependenciesMeta:
+ "@types/node":
+ optional: true
+ "@vitejs/devtools":
+ optional: true
+ esbuild:
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+ bin:
+ vite: bin/vite.js
+ checksum: 10c0/d75be3fbe2f63e6a8145325970338afaf0dd4d96ba9175c13f9a286fd5f95afc489401b693e4fa6c0899a4dd0e137be91cdf9401a40a635563911ad5036e3467
+ languageName: node
+ linkType: hard
+
+"vite@npm:^6.2.4":
+ version: 6.4.3
+ resolution: "vite@npm:6.4.3"
+ dependencies:
+ esbuild: "npm:^0.25.0"
+ fdir: "npm:^6.4.4"
+ fsevents: "npm:~2.3.3"
+ picomatch: "npm:^4.0.2"
+ postcss: "npm:^8.5.3"
+ rollup: "npm:^4.34.9"
+ tinyglobby: "npm:^0.2.13"
+ peerDependencies:
+ "@types/node": ^18.0.0 || ^20.0.0 || >=22.0.0
+ jiti: ">=1.21.0"
+ less: "*"
+ lightningcss: ^1.21.0
+ sass: "*"
+ sass-embedded: "*"
+ stylus: "*"
+ sugarss: "*"
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ peerDependenciesMeta:
+ "@types/node":
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ lightningcss:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+ bin:
+ vite: bin/vite.js
+ checksum: 10c0/23ce22e50d5c7a87321f04b155c5bc3cf915e34e6c40918975741ed5e8b0c257039a643f1bc1cd829ee814ad92a138704e82084b7ebe40b399a62d8effea630c
+ languageName: node
+ linkType: hard
+
+"vitest@npm:^4.0.18":
+ version: 4.1.8
+ resolution: "vitest@npm:4.1.8"
+ dependencies:
+ "@vitest/expect": "npm:4.1.8"
+ "@vitest/mocker": "npm:4.1.8"
+ "@vitest/pretty-format": "npm:4.1.8"
+ "@vitest/runner": "npm:4.1.8"
+ "@vitest/snapshot": "npm:4.1.8"
+ "@vitest/spy": "npm:4.1.8"
+ "@vitest/utils": "npm:4.1.8"
+ es-module-lexer: "npm:^2.0.0"
+ expect-type: "npm:^1.3.0"
+ magic-string: "npm:^0.30.21"
+ obug: "npm:^2.1.1"
+ pathe: "npm:^2.0.3"
+ picomatch: "npm:^4.0.3"
+ std-env: "npm:^4.0.0-rc.1"
+ tinybench: "npm:^2.9.0"
+ tinyexec: "npm:^1.0.2"
+ tinyglobby: "npm:^0.2.15"
+ tinyrainbow: "npm:^3.1.0"
+ vite: "npm:^6.0.0 || ^7.0.0 || ^8.0.0"
+ why-is-node-running: "npm:^2.3.0"
+ peerDependencies:
+ "@edge-runtime/vm": "*"
+ "@opentelemetry/api": ^1.9.0
+ "@types/node": ^20.0.0 || ^22.0.0 || >=24.0.0
+ "@vitest/browser-playwright": 4.1.8
+ "@vitest/browser-preview": 4.1.8
+ "@vitest/browser-webdriverio": 4.1.8
+ "@vitest/coverage-istanbul": 4.1.8
+ "@vitest/coverage-v8": 4.1.8
+ "@vitest/ui": 4.1.8
+ happy-dom: "*"
+ jsdom: "*"
+ vite: ^6.0.0 || ^7.0.0 || ^8.0.0
+ peerDependenciesMeta:
+ "@edge-runtime/vm":
+ optional: true
+ "@opentelemetry/api":
+ optional: true
+ "@types/node":
+ optional: true
+ "@vitest/browser-playwright":
+ optional: true
+ "@vitest/browser-preview":
+ optional: true
+ "@vitest/browser-webdriverio":
+ optional: true
+ "@vitest/coverage-istanbul":
+ optional: true
+ "@vitest/coverage-v8":
+ optional: true
+ "@vitest/ui":
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+ vite:
+ optional: false
+ bin:
+ vitest: vitest.mjs
+ checksum: 10c0/f459c500f8818c7a2318cd23228b4e5c0b5efb25bf8e5cb7f116c6d26e51482b2f800a8bb19837c0b5f0d05c51519edbf502bc8ceb5bd86868e8facf1d2c498e
+ languageName: node
+ linkType: hard
+
+"vm-browserify@npm:^1.0.1":
+ version: 1.1.2
+ resolution: "vm-browserify@npm:1.1.2"
+ checksum: 10c0/0cc1af6e0d880deb58bc974921320c187f9e0a94f25570fca6b1bd64e798ce454ab87dfd797551b1b0cc1849307421aae0193cedf5f06bdb5680476780ee344b
+ languageName: node
+ linkType: hard
+
+"wagmi@npm:^3.6.4":
+ version: 3.6.16
+ resolution: "wagmi@npm:3.6.16"
+ dependencies:
+ "@wagmi/connectors": "npm:8.0.15"
+ "@wagmi/core": "npm:3.5.0"
+ use-sync-external-store: "npm:1.4.0"
+ peerDependencies:
+ "@tanstack/react-query": ">=5.0.0"
+ react: ">=18"
+ typescript: ">=5.9.3"
+ viem: 2.x
+ peerDependenciesMeta:
+ typescript:
+ optional: true
+ checksum: 10c0/7251c4593addd210a7468a59f4a87f763480132b34116bd9d89d893a1e4425e57f6e9485f96598b7b49e622c817f47ec61e9e9612da03f62011b567b344a0d5f
+ languageName: node
+ linkType: hard
+
+"webidl-conversions@npm:^3.0.0":
+ version: 3.0.1
+ resolution: "webidl-conversions@npm:3.0.1"
+ checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db
+ languageName: node
+ linkType: hard
+
+"whatwg-url@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "whatwg-url@npm:5.0.0"
+ dependencies:
+ tr46: "npm:~0.0.3"
+ webidl-conversions: "npm:^3.0.0"
+ checksum: 10c0/1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5
+ languageName: node
+ linkType: hard
+
+"which-module@npm:^2.0.0":
+ version: 2.0.1
+ resolution: "which-module@npm:2.0.1"
+ checksum: 10c0/087038e7992649eaffa6c7a4f3158d5b53b14cf5b6c1f0e043dccfacb1ba179d12f17545d5b85ebd94a42ce280a6fe65d0cbcab70f4fc6daad1dfae85e0e6a3e
+ languageName: node
+ linkType: hard
+
+"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.2":
+ version: 1.1.22
+ resolution: "which-typed-array@npm:1.1.22"
+ dependencies:
+ available-typed-arrays: "npm:^1.0.7"
+ call-bind: "npm:^1.0.9"
+ call-bound: "npm:^1.0.4"
+ for-each: "npm:^0.3.5"
+ get-proto: "npm:^1.0.1"
+ gopd: "npm:^1.2.0"
+ has-tostringtag: "npm:^1.0.2"
+ checksum: 10c0/e59db184a4e78b461fac3b05fafc1e7badbbedafbf04a967ee1de73717f1f9723a79699e7b5de71d449541cb5da8353efc01a4f8a72a152479850e54fa196c40
+ languageName: node
+ linkType: hard
+
+"which@npm:^2.0.1":
+ version: 2.0.2
+ resolution: "which@npm:2.0.2"
+ dependencies:
+ isexe: "npm:^2.0.0"
+ bin:
+ node-which: ./bin/node-which
+ checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f
+ languageName: node
+ linkType: hard
+
+"which@npm:^6.0.0":
+ version: 6.0.1
+ resolution: "which@npm:6.0.1"
+ dependencies:
+ isexe: "npm:^4.0.0"
+ bin:
+ node-which: bin/which.js
+ checksum: 10c0/7e710e54ea36d2d6183bee2f9caa27a3b47b9baf8dee55a199b736fcf85eab3b9df7556fca3d02b50af7f3dfba5ea3a45644189836df06267df457e354da66d5
+ languageName: node
+ linkType: hard
+
+"why-is-node-running@npm:^2.3.0":
+ version: 2.3.0
+ resolution: "why-is-node-running@npm:2.3.0"
+ dependencies:
+ siginfo: "npm:^2.0.0"
+ stackback: "npm:0.0.2"
+ bin:
+ why-is-node-running: cli.js
+ checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054
+ languageName: node
+ linkType: hard
+
+"widest-line@npm:^4.0.1":
+ version: 4.0.1
+ resolution: "widest-line@npm:4.0.1"
+ dependencies:
+ string-width: "npm:^5.0.1"
+ checksum: 10c0/7da9525ba45eaf3e4ed1a20f3dcb9b85bd9443962450694dae950f4bdd752839747bbc14713522b0b93080007de8e8af677a61a8c2114aa553ad52bde72d0f9c
+ languageName: node
+ linkType: hard
+
+"word-wrap@npm:^1.2.5":
+ version: 1.2.5
+ resolution: "word-wrap@npm:1.2.5"
+ checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20
+ languageName: node
+ linkType: hard
+
+"wrap-ansi@npm:^6.2.0":
+ version: 6.2.0
+ resolution: "wrap-ansi@npm:6.2.0"
+ dependencies:
+ ansi-styles: "npm:^4.0.0"
+ string-width: "npm:^4.1.0"
+ strip-ansi: "npm:^6.0.0"
+ checksum: 10c0/baad244e6e33335ea24e86e51868fe6823626e3a3c88d9a6674642afff1d34d9a154c917e74af8d845fd25d170c4ea9cf69a47133c3f3656e1252b3d462d9f6c
+ languageName: node
+ linkType: hard
+
+"wrap-ansi@npm:^8.0.1":
+ version: 8.1.0
+ resolution: "wrap-ansi@npm:8.1.0"
+ dependencies:
+ ansi-styles: "npm:^6.1.0"
+ string-width: "npm:^5.0.1"
+ strip-ansi: "npm:^7.0.1"
+ checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60
+ languageName: node
+ linkType: hard
+
+"ws@npm:8.17.1":
+ version: 8.17.1
+ resolution: "ws@npm:8.17.1"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ">=5.0.2"
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 10c0/f4a49064afae4500be772abdc2211c8518f39e1c959640457dcee15d4488628620625c783902a52af2dd02f68558da2868fd06e6fd0e67ebcd09e6881b1b5bfe
+ languageName: node
+ linkType: hard
+
+"ws@npm:8.20.1":
+ version: 8.20.1
+ resolution: "ws@npm:8.20.1"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ">=5.0.2"
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 10c0/ce162433218399cdedeb76fd33363d4d86a7d910058d4e3c679dce08cea65d6da6b39f11baa4d7808d024cf46ed88f6a05c17611621aaad8fc5e62edacc30c5d
+ languageName: node
+ linkType: hard
+
+"ws@npm:^7.5.1":
+ version: 7.5.11
+ resolution: "ws@npm:7.5.11"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ^5.0.2
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 10c0/7972670b676fb1ccba73b0899ca3c2e04e8c2075629c2614cced7f556536f96a672bbf4619fc5a06c8b8720bb839a47ca88c69c95dc14c9c61a99fbecba1c866
+ languageName: node
+ linkType: hard
+
+"ws@npm:^8.19.0":
+ version: 8.21.0
+ resolution: "ws@npm:8.21.0"
+ peerDependencies:
+ bufferutil: ^4.0.1
+ utf-8-validate: ">=5.0.2"
+ peerDependenciesMeta:
+ bufferutil:
+ optional: true
+ utf-8-validate:
+ optional: true
+ checksum: 10c0/ef4a243476283fc49bc7550966c4af4aa0eef56273837211e700de3b664e08604a760cdddcb5ba43c049140e74ccfec5b0ee0bb439e08c2adf9138902fdde5f9
+ languageName: node
+ linkType: hard
+
+"xtend@npm:^4.0.2":
+ version: 4.0.2
+ resolution: "xtend@npm:4.0.2"
+ checksum: 10c0/366ae4783eec6100f8a02dff02ac907bf29f9a00b82ac0264b4d8b832ead18306797e283cf19de776538babfdcb2101375ec5646b59f08c52128ac4ab812ed0e
+ languageName: node
+ linkType: hard
+
+"y18n@npm:^4.0.0":
+ version: 4.0.3
+ resolution: "y18n@npm:4.0.3"
+ checksum: 10c0/308a2efd7cc296ab2c0f3b9284fd4827be01cfeb647b3ba18230e3a416eb1bc887ac050de9f8c4fd9e7856b2e8246e05d190b53c96c5ad8d8cb56dffb6f81024
+ languageName: node
+ linkType: hard
+
+"yallist@npm:^3.0.2":
+ version: 3.1.1
+ resolution: "yallist@npm:3.1.1"
+ checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1
+ languageName: node
+ linkType: hard
+
+"yallist@npm:^5.0.0":
+ version: 5.0.0
+ resolution: "yallist@npm:5.0.0"
+ checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416
+ languageName: node
+ linkType: hard
+
+"yaml@npm:^1.10.0":
+ version: 1.10.3
+ resolution: "yaml@npm:1.10.3"
+ checksum: 10c0/c309ff85a0a569a981d71ab9cf0fef68672a16b9cdf40639d1c3b30034f6cd16ee428602bd6d64ecf006f8c8bee499023cac236538f79898aa99fb5db529a2ed
+ languageName: node
+ linkType: hard
+
+"yargs-parser@npm:^18.1.2":
+ version: 18.1.3
+ resolution: "yargs-parser@npm:18.1.3"
+ dependencies:
+ camelcase: "npm:^5.0.0"
+ decamelize: "npm:^1.2.0"
+ checksum: 10c0/25df918833592a83f52e7e4f91ba7d7bfaa2b891ebf7fe901923c2ee797534f23a176913ff6ff7ebbc1cc1725a044cc6a6539fed8bfd4e13b5b16376875f9499
+ languageName: node
+ linkType: hard
+
+"yargs@npm:^15.3.1":
+ version: 15.4.1
+ resolution: "yargs@npm:15.4.1"
+ dependencies:
+ cliui: "npm:^6.0.0"
+ decamelize: "npm:^1.2.0"
+ find-up: "npm:^4.1.0"
+ get-caller-file: "npm:^2.0.1"
+ require-directory: "npm:^2.1.1"
+ require-main-filename: "npm:^2.0.0"
+ set-blocking: "npm:^2.0.0"
+ string-width: "npm:^4.2.0"
+ which-module: "npm:^2.0.0"
+ y18n: "npm:^4.0.0"
+ yargs-parser: "npm:^18.1.2"
+ checksum: 10c0/f1ca680c974333a5822732825cca7e95306c5a1e7750eb7b973ce6dc4f97a6b0a8837203c8b194f461969bfe1fb1176d1d423036635285f6010b392fa498ab2d
+ languageName: node
+ linkType: hard
+
+"yocto-queue@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "yocto-queue@npm:0.1.0"
+ checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f
+ languageName: node
+ linkType: hard
+
+"zod@npm:3.22.4":
+ version: 3.22.4
+ resolution: "zod@npm:3.22.4"
+ checksum: 10c0/7578ab283dac0eee66a0ad0fc4a7f28c43e6745aadb3a529f59a4b851aa10872b3890398b3160f257f4b6817b4ce643debdda4fb21a2c040adda7862cab0a587
+ languageName: node
+ linkType: hard
+
+"zod@npm:^3.25.76":
+ version: 3.25.76
+ resolution: "zod@npm:3.25.76"
+ checksum: 10c0/5718ec35e3c40b600316c5b4c5e4976f7fee68151bc8f8d90ec18a469be9571f072e1bbaace10f1e85cf8892ea12d90821b200e980ab46916a6166a4260a983c
+ languageName: node
+ linkType: hard
+
+"zustand@npm:5.0.0":
+ version: 5.0.0
+ resolution: "zustand@npm:5.0.0"
+ peerDependencies:
+ "@types/react": ">=18.0.0"
+ immer: ">=9.0.6"
+ react: ">=18.0.0"
+ use-sync-external-store: ">=1.2.0"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ use-sync-external-store:
+ optional: true
+ checksum: 10c0/7546df78aa512f1d2271e238c44699c0ac4bc57f12ae46fcfe8ba1e8a97686fc690596e654101acfabcd706099aa5d3519fc3f22d32b3082baa60699bb333e9a
+ languageName: node
+ linkType: hard
+
+"zustand@npm:5.0.3":
+ version: 5.0.3
+ resolution: "zustand@npm:5.0.3"
+ peerDependencies:
+ "@types/react": ">=18.0.0"
+ immer: ">=9.0.6"
+ react: ">=18.0.0"
+ use-sync-external-store: ">=1.2.0"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ use-sync-external-store:
+ optional: true
+ checksum: 10c0/dad96c6c123fda088c583d5df6692e9245cd207583078dc15f93d255a67b0f346bad4535545c98852ecde93d254812a0c799579dfde2ab595016b99fbe20e4d5
+ languageName: node
+ linkType: hard
diff --git a/exchange-oracle/client/package.json b/exchange-oracle/client/package.json
index ad4630e..1fdfab1 100644
--- a/exchange-oracle/client/package.json
+++ b/exchange-oracle/client/package.json
@@ -33,7 +33,7 @@
"dependencies": {
"@emotion/react": "^11.11.3",
"@emotion/styled": "^11.11.0",
- "@human-protocol/sdk": "^7.1.0",
+ "@human-protocol/sdk": "^7.3.0",
"@mui/icons-material": "^5.18.0",
"@mui/material": "^5.16.7",
"@tanstack/query-sync-storage-persister": "^5.68.0",
diff --git a/exchange-oracle/client/src/components/Headers/DefaultHeader.tsx b/exchange-oracle/client/src/components/Headers/DefaultHeader.tsx
index c458a4a..cafd64e 100644
--- a/exchange-oracle/client/src/components/Headers/DefaultHeader.tsx
+++ b/exchange-oracle/client/src/components/Headers/DefaultHeader.tsx
@@ -1,3 +1,4 @@
+import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { AppBar, Box, Link as MuiLink, Toolbar } from '@mui/material';
import React from 'react';
import { Link } from 'react-router-dom';
@@ -5,31 +6,78 @@ import logoImg from '../../assets/logo.svg';
export function DefaultHeader() {
return (
-
-
-
+
+
+
-
+
+ Assignment
+
+
Dashboard
+
HUMAN Website
+
diff --git a/exchange-oracle/client/src/components/SolutionForm/index.tsx b/exchange-oracle/client/src/components/SolutionForm/index.tsx
index 6e9e27c..4fec74b 100644
--- a/exchange-oracle/client/src/components/SolutionForm/index.tsx
+++ b/exchange-oracle/client/src/components/SolutionForm/index.tsx
@@ -1,9 +1,236 @@
-import { Box, Button, Grid, TextField, Typography } from '@mui/material';
-import { useState } from 'react';
+import OpenInNewIcon from '@mui/icons-material/OpenInNew';
+import SendIcon from '@mui/icons-material/Send';
+import {
+ Alert,
+ Box,
+ Button,
+ Chip,
+ CircularProgress,
+ Divider,
+ Link,
+ Stack,
+ TextField,
+ Typography,
+} from '@mui/material';
+import { useEffect, useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useSnackbar } from '../../providers/SnackProvider';
import { useAccount, useWalletClient } from 'wagmi';
import * as jobService from '../../services/job';
+import type { AssignmentDetails } from '../../services/job';
+
+type SolutionCopy = {
+ title: string;
+ inputLabel: string;
+ inputPlaceholder: string;
+ helperText: string;
+ submitLabel: string;
+};
+
+type RequirementItem = {
+ label: string;
+ value: string;
+};
+
+const getBooleanRequirementLabels = (
+ requirements: Record,
+): string[] => {
+ const labels: Array<[string, string]> = [
+ ['checkLike', 'Like'],
+ ['checkRepost', 'Repost'],
+ ['checkQuote', 'Quote'],
+ ['checkComment', 'Comment'],
+ ['requiresMedia', 'Media required'],
+ ['mustBePublic', 'Public post'],
+ ];
+
+ return labels
+ .filter(([key]) => requirements[key] === true)
+ .map(([, label]) => label);
+};
+
+const getPlatformLabel = (platform?: string): string => {
+ if (!platform) return 'Social';
+ if (platform.toLowerCase() === 'x') return 'X';
+ if (platform.toLowerCase() === 'linkedin') return 'LinkedIn';
+ return platform;
+};
+
+const getStringListRequirement = (
+ requirements: Record,
+ key: string,
+): string | null => {
+ const value = requirements[key];
+
+ return Array.isArray(value) && value.length > 0
+ ? value.map(String).join(', ')
+ : null;
+};
+
+const getPositiveNumberRequirement = (
+ requirements: Record,
+ key: string,
+): string | null => {
+ const value = requirements[key];
+
+ return typeof value === 'number' && value > 0 ? value.toString() : null;
+};
+
+const getPostRequirementItems = (
+ requirements: Record,
+): RequirementItem[] => {
+ const items: RequirementItem[] = [];
+ const requiredHashtags = getStringListRequirement(
+ requirements,
+ 'requiredHashtags',
+ );
+ const requiredKeywords = getStringListRequirement(
+ requirements,
+ 'requiredKeywords',
+ );
+ const requiredLink =
+ typeof requirements.requiredLink === 'string'
+ ? requirements.requiredLink
+ : null;
+ const minLength = getPositiveNumberRequirement(requirements, 'minLength');
+ const minLiveDurationHours = getPositiveNumberRequirement(
+ requirements,
+ 'minLiveDurationHours',
+ );
+ const minFollowers = getPositiveNumberRequirement(
+ requirements,
+ 'minFollowers',
+ );
+ const minAccountAgeDays = getPositiveNumberRequirement(
+ requirements,
+ 'minAccountAgeDays',
+ );
+ const minLikes = getPositiveNumberRequirement(requirements, 'minLikes');
+ const minReposts = getPositiveNumberRequirement(requirements, 'minReposts');
+
+ if (requiredHashtags) {
+ items.push({ label: 'Hashtags', value: requiredHashtags });
+ }
+ if (requiredKeywords) {
+ items.push({ label: 'Keywords', value: requiredKeywords });
+ }
+ if (requiredLink) {
+ items.push({ label: 'Link', value: requiredLink });
+ }
+ if (minLength) {
+ items.push({ label: 'Minimum length', value: `${minLength} characters` });
+ }
+ if (requirements.requiresMedia === true) {
+ items.push({ label: 'Media', value: 'Required' });
+ }
+ if (requirements.mustBePublic === true) {
+ items.push({ label: 'Visibility', value: 'Public post required' });
+ }
+ if (minLiveDurationHours) {
+ items.push({
+ label: 'Live duration',
+ value: `${minLiveDurationHours} hours`,
+ });
+ }
+ if (minFollowers) {
+ items.push({ label: 'Followers', value: `At least ${minFollowers}` });
+ }
+ if (minAccountAgeDays) {
+ items.push({
+ label: 'Account age',
+ value: `At least ${minAccountAgeDays} days`,
+ });
+ }
+ if (minLikes) {
+ items.push({ label: 'Likes', value: `At least ${minLikes}` });
+ }
+ if (minReposts) {
+ items.push({ label: 'Reposts', value: `At least ${minReposts}` });
+ }
+
+ return items;
+};
+
+const getSolutionCopy = (
+ assignment?: AssignmentDetails | null,
+): SolutionCopy => {
+ const platform = assignment?.platforms?.[0]?.toLowerCase();
+
+ if (assignment?.jobType === 'social_media_engagement') {
+ if (platform === 'x') {
+ return {
+ title: 'Submit X Engagement',
+ inputLabel: 'X handle',
+ inputPlaceholder: '@human_protocol',
+ helperText: 'Enter the X username that engaged with the target post.',
+ submitLabel: 'Submit handle',
+ };
+ }
+
+ if (platform === 'linkedin') {
+ return {
+ title: 'Submit LinkedIn Engagement',
+ inputLabel: 'LinkedIn profile name',
+ inputPlaceholder: 'John Doe',
+ helperText:
+ 'Enter the display name from the LinkedIn profile, not the profile URL.',
+ submitLabel: 'Submit name',
+ };
+ }
+
+ return {
+ title: 'Submit Engagement',
+ inputLabel: 'Social profile',
+ inputPlaceholder: 'Your profile handle or URL',
+ helperText: 'Enter the profile that completed the required engagement.',
+ submitLabel: 'Submit profile',
+ };
+ }
+
+ if (platform === 'linkedin') {
+ return {
+ title: 'Submit LinkedIn Post',
+ inputLabel: 'Post URL',
+ inputPlaceholder: 'https://www.linkedin.com/posts/...',
+ helperText: 'Paste the public LinkedIn post URL for this assignment.',
+ submitLabel: 'Submit post',
+ };
+ }
+
+ return {
+ title: 'Submit X Post',
+ inputLabel: 'Post URL',
+ inputPlaceholder: 'https://x.com/username/status/123',
+ helperText: 'Paste the public X post URL for this assignment.',
+ submitLabel: 'Submit post',
+ };
+};
+
+const isUrlLikeValue = (value: string): boolean => {
+ const trimmedValue = value.trim();
+
+ return (
+ /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmedValue) ||
+ /^www\./i.test(trimmedValue) ||
+ /(^|\.)linkedin\.com\//i.test(trimmedValue)
+ );
+};
+
+const formatEndDate = (value?: string): string | null => {
+ if (!value) {
+ return null;
+ }
+
+ const date = new Date(value);
+ if (Number.isNaN(date.getTime())) {
+ return null;
+ }
+
+ return new Intl.DateTimeFormat(undefined, {
+ dateStyle: 'medium',
+ timeStyle: 'short',
+ }).format(date);
+};
const SolutionForm: React.FC = () => {
const { assignmentId } = useParams<{ assignmentId: string }>();
@@ -18,6 +245,43 @@ const SolutionForm: React.FC = () => {
},
});
const [solution, setSolution] = useState('');
+ const [assignment, setAssignment] = useState(null);
+ const [isLoadingAssignment, setIsLoadingAssignment] = useState(true);
+ const [assignmentError, setAssignmentError] = useState(null);
+
+ const copy = useMemo(() => getSolutionCopy(assignment), [assignment]);
+ const platformLabel = getPlatformLabel(assignment?.platforms?.[0]);
+ const requirementLabels = useMemo(
+ () =>
+ assignment?.jobType === 'social_media_engagement'
+ ? getBooleanRequirementLabels(assignment.requirements)
+ : [],
+ [assignment],
+ );
+ const isXPromotionSubmission =
+ assignment?.jobType === 'social_media_promotion' &&
+ (assignment.platforms?.[0]?.toLowerCase() ?? 'x') === 'x';
+ const postRequirementItems = useMemo(
+ () =>
+ assignment && isXPromotionSubmission
+ ? getPostRequirementItems(assignment.requirements)
+ : [],
+ [assignment, isXPromotionSubmission],
+ );
+ const targetPostUrl =
+ typeof assignment?.requirements.targetPostUrl === 'string'
+ ? assignment.requirements.targetPostUrl
+ : null;
+ const manifestUrl = assignment?.manifestUrl ?? null;
+ const endDateLabel = formatEndDate(assignment?.endDate);
+ const isLinkedInEngagementSubmission =
+ assignment?.jobType === 'social_media_engagement' &&
+ assignment.platforms?.[0]?.toLowerCase() === 'linkedin';
+ const hasInvalidLinkedInName =
+ isLinkedInEngagementSubmission && isUrlLikeValue(solution);
+ const solutionHelperText = hasInvalidLinkedInName
+ ? 'Submit the LinkedIn profile name, for example John Doe. Do not submit a URL.'
+ : copy.helperText;
type SnackbarApi = {
openSnackbar: (
@@ -29,6 +293,41 @@ const SolutionForm: React.FC = () => {
const { showError, openSnackbar } = useSnackbar() as SnackbarApi;
+ useEffect(() => {
+ let isMounted = true;
+
+ const loadAssignment = async () => {
+ if (!assignmentId) {
+ setIsLoadingAssignment(false);
+ setAssignmentError('Missing assignment id');
+ return;
+ }
+
+ try {
+ setIsLoadingAssignment(true);
+ const details = await jobService.getAssignmentDetails(assignmentId);
+ if (isMounted) {
+ setAssignment(details);
+ setAssignmentError(null);
+ }
+ } catch {
+ if (isMounted) {
+ setAssignmentError('Assignment details could not be loaded.');
+ }
+ } finally {
+ if (isMounted) {
+ setIsLoadingAssignment(false);
+ }
+ }
+ };
+
+ loadAssignment();
+
+ return () => {
+ isMounted = false;
+ };
+ }, [assignmentId]);
+
const handleSubmit = async () => {
if (!signer) {
openSnackbar('Please connect your wallet first', 'error');
@@ -39,6 +338,12 @@ const SolutionForm: React.FC = () => {
openSnackbar('Missing assignment id', 'error');
return;
}
+
+ if (hasInvalidLinkedInName) {
+ openSnackbar('Submit the LinkedIn profile name, not a URL', 'error');
+ return;
+ }
+
const message = {
assignment_id: assignmentId,
solution,
@@ -55,56 +360,237 @@ const SolutionForm: React.FC = () => {
return (
-
-
-
+
+ Loading assignment
+
+ ) : (
+
+ {assignmentError && (
+ {assignmentError}
+ )}
+
+
+
+
+
+ {copy.title}
+
+
+ Assignment #{assignmentId}
+
+ {endDateLabel && (
+
+ Actions should be completed by {endDateLabel}
+
+ )}
+
+
+ {assignment?.jobType && (
+
+ )}
+
+
+
+
+ {assignment?.jobDescription && (
+
+
+ Description:
+
+
+ {assignment.jobDescription}
+
+
+ )}
+
+
+
+
+ {(targetPostUrl ||
+ requirementLabels.length > 0 ||
+ postRequirementItems.length > 0) && (
+
+
+ {targetPostUrl && (
+
+
+ Target post
+
+
+
+ )}
+ {postRequirementItems.length > 0 && (
+
+
+ Post requirements:
+
+
+ {postRequirementItems.map((item) => (
+
+
+ {item.label}:
+
+
+ {item.value}
+
+
+ ))}
+
+
+ )}
+ {requirementLabels.length > 0 && (
+
+
+ Required actions:
+
+ {requirementLabels.map((label) => (
+
+ ))}
+
+ )}
+
+
+ )}
+
+ setSolution(e.target.value)}
+ error={hasInvalidLinkedInName}
+ helperText={solutionHelperText}
+ fullWidth
+ InputProps={{
+ sx: {
+ minHeight: 56,
+ fontWeight: 700,
+ },
}}
+ />
+
+ }
>
-
- Submit Your Solution
-
-
-
- setSolution(e.target.value)}
- sx={{ mb: 3, width: '300px' }}
- />
-
-
-
-
-
+ manifest
+
+ )}
+
+ )}
);
};
diff --git a/exchange-oracle/client/src/components/Wallet/FundingMethod.tsx b/exchange-oracle/client/src/components/Wallet/FundingMethod.tsx
index 3db204f..82071a5 100644
--- a/exchange-oracle/client/src/components/Wallet/FundingMethod.tsx
+++ b/exchange-oracle/client/src/components/Wallet/FundingMethod.tsx
@@ -1,4 +1,4 @@
-import { Box, Button, Grid, Typography } from '@mui/material';
+import { Box, Button, Stack, Typography } from '@mui/material';
import { useEffect, useState } from 'react';
import { useAccount } from 'wagmi';
import fundCryptoImg from '../../assets/fund-crypto.png';
@@ -25,54 +25,60 @@ export const FundingMethod = () => {
return (
<>
{isConnected ? (
- // Mostrar el formulario de solución si está conectado
+
) : (
-
-
-
+
+
+
+
+
+ Connect Your Wallet
+
+
-
-
- Click to connect your wallet
-
-
-
-
-
+ Use the worker wallet assigned to this task before submitting
+ your solution.
+
+
+
+
)}
= {
+const WALLET_ICONS: Record = {
metaMask: metaMaskSvg,
+ injected: metaMaskSvg,
coinbaseWalletSDK: coinbaseSvg,
+ coinbaseWallet: coinbaseSvg,
walletConnect: walletConnectSvg,
};
@@ -25,87 +39,273 @@ export default function WalletModal({
open: boolean;
onClose: () => void;
}) {
- const { connect, connectors, error } = useConnect();
+ const { connectAsync } = useConnect();
+ const connectors = useConnectors();
+ const { disconnectAsync } = useDisconnect();
+ const [error, setError] = useState(null);
+ const [showAllWallets, setShowAllWallets] = useState(false);
+ const [connectingConnectorId, setConnectingConnectorId] = useState<
+ string | null
+ >(null);
+ const isMobile = useMediaQuery('(max-width: 900px)');
+
+ const displayedConnectors = useMemo(
+ () => (showAllWallets ? connectors : connectors.slice(0, 6)),
+ [connectors, showAllWallets]
+ );
+
+ const hasMoreWallets = connectors.length > displayedConnectors.length;
+
+ const handleConnect = async (connector: Connector) => {
+ setError(null);
+ setConnectingConnectorId(connector.id);
- const theme = useTheme();
+ try {
+ if (connector.id === 'walletConnect') {
+ onClose();
+ }
+
+ await connectAsync({ connector });
+ onClose();
+ } catch (e) {
+ const err = e as { message?: string };
+
+ if (err.message?.includes('Connector already connected')) {
+ await disconnectAsync();
+ await handleConnect(connector);
+ return;
+ }
+
+ setError(err.message ?? 'Unable to connect wallet');
+ } finally {
+ setConnectingConnectorId(null);
+ }
+ };
+
+ const content = (
+
+
+ Connect Wallet
+
+
+ Connect your wallet to continue and submit your solution.
+
+
+
+ {displayedConnectors.map((connector) => {
+ const isConnectingWallet = connectingConnectorId === connector.id;
+
+ return (
+
+
+
+ );
+ })}
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+ {!showAllWallets ? (
+ }
+ disabled={!hasMoreWallets || !!connectingConnectorId}
+ onClick={() => setShowAllWallets(true)}
+ >
+ Search Wallet
+
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+ );
+
+ const closeButton = (
+
+
+
+ );
+
+ if (isMobile) {
+ return (
+
+ {closeButton}
+ {content}
+
+ );
+ }
return (
-
+
+ {closeButton}
+ {content}
+
+
);
}
diff --git a/exchange-oracle/client/src/index.css b/exchange-oracle/client/src/index.css
index addebdf..1af7577 100644
--- a/exchange-oracle/client/src/index.css
+++ b/exchange-oracle/client/src/index.css
@@ -1,4 +1,15 @@
+html,
+body,
+#root {
+ min-height: 100%;
+ background: #0d0433;
+}
+
+body {
+ margin: 0;
+}
+
a {
- color: #320a8d;
+ color: #c7bdff;
text-decoration: none;
}
diff --git a/exchange-oracle/client/src/pages/Home/index.tsx b/exchange-oracle/client/src/pages/Home/index.tsx
index d2f7cc2..299864e 100644
--- a/exchange-oracle/client/src/pages/Home/index.tsx
+++ b/exchange-oracle/client/src/pages/Home/index.tsx
@@ -1,5 +1,5 @@
import React from 'react';
-import { Box, Grid, Typography } from '@mui/material';
+import { Box, Grid, Stack, Typography } from '@mui/material';
import { Outlet } from 'react-router-dom';
import bagImg from '../../assets/bag.png';
import humanImg from '../../assets/human.png';
@@ -8,19 +8,19 @@ import { DefaultHeader } from '../../components/Headers/DefaultHeader';
const Home: React.FC = () => {
return (
-
+
-
+
{
height: '100%',
}}
>
-
-
-
-
-
+
+ {[bagImg, userImg, humanImg].map((image, index) => (
+
+
+
+ ))}
+
HUMAN
Exchange Oracle
-
- Solve marketing jobs.
+
+ Review the job details, submit the right social proof, and send
+ it for validation.
diff --git a/exchange-oracle/client/src/pages/Solution/index.tsx b/exchange-oracle/client/src/pages/Solution/index.tsx
index c30c7d2..4702855 100644
--- a/exchange-oracle/client/src/pages/Solution/index.tsx
+++ b/exchange-oracle/client/src/pages/Solution/index.tsx
@@ -9,25 +9,25 @@ const Solution: React.FC = () => {
const { isConnected } = useAccount();
return (
-
+
diff --git a/exchange-oracle/client/src/providers/WagmiProvider.tsx b/exchange-oracle/client/src/providers/WagmiProvider.tsx
index a0d72e5..3d56495 100644
--- a/exchange-oracle/client/src/providers/WagmiProvider.tsx
+++ b/exchange-oracle/client/src/providers/WagmiProvider.tsx
@@ -7,6 +7,20 @@ import { LOCALHOST } from '../constants/chains';
const projectId = import.meta.env.VITE_APP_WALLETCONNECT_PROJECT_ID;
+const connectors = [
+ ...(projectId
+ ? [
+ walletConnect({
+ showQrModal: true,
+ projectId,
+ }),
+ ]
+ : []),
+ coinbaseWallet({
+ appName: 'human-job-launcher',
+ }),
+];
+
export const wagmiConfig = createConfig({
chains: [
wagmiChains.mainnet,
@@ -23,15 +37,7 @@ export const wagmiConfig = createConfig({
wagmiChains.xLayerTestnet,
LOCALHOST,
],
- connectors: [
- walletConnect({
- showQrModal: true,
- projectId: projectId ?? '',
- }),
- coinbaseWallet({
- appName: 'human-job-launcher',
- }),
- ],
+ connectors,
transports: {
[wagmiChains.mainnet.id]: http(),
[wagmiChains.sepolia.id]: http(),
diff --git a/exchange-oracle/client/src/services/job.ts b/exchange-oracle/client/src/services/job.ts
index 7861141..ec8cf4c 100644
--- a/exchange-oracle/client/src/services/job.ts
+++ b/exchange-oracle/client/src/services/job.ts
@@ -3,6 +3,26 @@ import { WalletClient } from 'viem';
import { HUMAN_SIGNATURE_KEY } from '../constants';
import api from '../utils/api';
+export type JobType = 'social_media_promotion' | 'social_media_engagement';
+
+export type AssignmentDetails = {
+ assignmentId: string;
+ escrowAddress: string;
+ chainId: number;
+ jobType: JobType;
+ status: string;
+ rewardAmount: number;
+ rewardToken: string;
+ createdAt: string;
+ expiresAt: string;
+ endDate: string;
+ updatedAt?: string;
+ jobDescription: string;
+ manifestUrl: string;
+ platforms: string[];
+ requirements: Record;
+};
+
export const solveJob = async (signer: WalletClient, body: any) => {
if (!signer.account) {
throw new Error('Account not found');
@@ -16,3 +36,13 @@ export const solveJob = async (signer: WalletClient, body: any) => {
headers: { [HUMAN_SIGNATURE_KEY]: signature },
});
};
+
+export const getAssignmentDetails = async (
+ assignmentId: string,
+): Promise => {
+ const response = await api.get(
+ `/assignment/${assignmentId}/details`,
+ );
+
+ return response.data;
+};
diff --git a/exchange-oracle/client/src/theme.ts b/exchange-oracle/client/src/theme.ts
index ae150fc..c09c9de 100644
--- a/exchange-oracle/client/src/theme.ts
+++ b/exchange-oracle/client/src/theme.ts
@@ -2,34 +2,39 @@ import { createTheme } from '@mui/material/styles';
const theme = createTheme({
palette: {
+ mode: 'dark',
primary: {
- main: '#320a8d',
- light: '#320a8d',
- dark: '#4a148c',
+ main: '#ff1f7a',
+ light: '#ff5aa1',
+ dark: '#d81064',
},
info: {
- main: '#eeeeee',
- light: '#f5f5f5',
- dark: '#bdbdbd',
+ main: '#8d83c7',
+ light: '#c9c2ff',
+ dark: '#5e538f',
},
secondary: {
- main: '#858ec6',
- light: '#6309ff',
- dark: '#00867d',
- contrastText: '#000',
+ main: '#c7bdff',
+ light: '#eee9ff',
+ dark: '#7d70b8',
+ contrastText: '#100735',
},
text: {
- primary: '#320a8d',
- secondary: '#858ec6',
+ primary: '#ffffff',
+ secondary: '#9b91d4',
+ },
+ background: {
+ default: '#0d0433',
+ paper: '#271f4f',
},
success: {
- main: '#0E976E',
+ main: '#23b889',
},
warning: {
- main: '#FF9800',
+ main: '#f5b800',
},
error: {
- main: '#F20D5F',
+ main: '#ff3b80',
},
},
typography: {
@@ -37,12 +42,13 @@ const theme = createTheme({
h2: {
fontSize: '80px',
lineHeight: 1.5,
- letterSpacing: '-0.5px',
+ letterSpacing: 0,
fontWeight: 800,
},
h4: {
- fontSize: '34px',
- fontWeight: 600,
+ fontSize: '28px',
+ fontWeight: 800,
+ letterSpacing: 0,
},
h6: {
fontSize: '20px',
@@ -60,19 +66,50 @@ const theme = createTheme({
components: {
MuiAlert: {
styleOverrides: {
+ standardWarning: {
+ color: '#ffffff',
+ backgroundColor: '#33275f',
+ border: '1px solid #4f4380',
+ },
+ standardError: {
+ color: '#ffffff',
+ backgroundColor: '#3c1942',
+ border: '1px solid #7e2d63',
+ },
+ standardSuccess: {
+ color: '#ffffff',
+ backgroundColor: '#173f3d',
+ border: '1px solid #246c62',
+ },
outlinedSuccess: {
- color: '#320a8d',
- borderColor: '#320a8d',
+ color: '#ffffff',
+ borderColor: '#23b889',
},
- // icon: {
- // color: '#320a8d !important',
- // },
},
},
MuiButton: {
styleOverrides: {
root: {
textTransform: 'none',
+ borderRadius: '6px',
+ boxShadow: 'none',
+ fontWeight: 800,
+ },
+ contained: {
+ color: '#ffffff',
+ backgroundColor: '#ff1f7a',
+ '&:hover': {
+ backgroundColor: '#e9166b',
+ boxShadow: '0 8px 18px rgba(255, 31, 122, 0.20)',
+ },
+ },
+ outlined: {
+ color: '#ffffff',
+ borderColor: '#4c3d82',
+ '&:hover': {
+ borderColor: '#ff1f7a',
+ backgroundColor: 'rgba(255, 31, 122, 0.08)',
+ },
},
sizeLarge: {
fontSize: '15px',
@@ -85,10 +122,10 @@ const theme = createTheme({
MuiCard: {
styleOverrides: {
root: {
- borderRadius: '16px',
- background: '#fff',
- boxShadow:
- '0px 1px 5px 0px rgba(233, 235, 250, 0.20), 0px 2px 2px 0px rgba(233, 235, 250, 0.50), 0px 3px 1px -2px #E9EBFA',
+ borderRadius: '8px',
+ background: '#271f4f',
+ border: '1px solid #3f3569',
+ boxShadow: 'none',
},
},
},
@@ -103,25 +140,80 @@ const theme = createTheme({
styleOverrides: {
root: {
textDecoration: 'none',
+ color: '#c7bdff',
},
},
},
MuiOutlinedInput: {
styleOverrides: {
root: {
+ color: '#ffffff',
+ backgroundColor: '#201844',
+ borderRadius: '8px',
'&.Mui-focused .MuiOutlinedInput-notchedOutline': {
borderWidth: '1px',
+ borderColor: '#ff1f7a',
},
},
notchedOutline: {
- borderColor: '#858ec6',
+ borderColor: '#514681',
+ },
+ },
+ },
+ MuiInputLabel: {
+ styleOverrides: {
+ root: {
+ color: '#9b91d4',
+ '&.Mui-focused': {
+ color: '#ff5aa1',
+ },
+ },
+ },
+ },
+ MuiFormHelperText: {
+ styleOverrides: {
+ root: {
+ color: '#9b91d4',
+ },
+ },
+ },
+ MuiChip: {
+ styleOverrides: {
+ root: {
+ height: '28px',
+ borderRadius: '999px',
+ color: '#ffffff',
+ backgroundColor: '#342a60',
+ border: '1px solid #4a3f78',
+ fontWeight: 700,
+ },
+ colorPrimary: {
+ color: '#180a3d',
+ backgroundColor: '#c7bdff',
+ borderColor: '#c7bdff',
+ },
+ },
+ },
+ MuiDivider: {
+ styleOverrides: {
+ root: {
+ borderColor: '#3f3569',
+ },
+ },
+ },
+ MuiDialog: {
+ styleOverrides: {
+ paper: {
+ background: '#271f4f',
+ border: '1px solid #3f3569',
+ borderRadius: '8px',
},
},
},
MuiSelect: {
styleOverrides: {
icon: {
- color: '#320a8d',
+ color: '#c7bdff',
},
},
},
@@ -130,16 +222,16 @@ const theme = createTheme({
root: {
textTransform: 'none',
borderRadius: '8px',
- border: '1px solid #320a8d',
- color: '#320a8d',
+ border: '1px solid #4c3d82',
+ color: '#ffffff',
fontWeight: 600,
fontSize: '14px',
'&.Mui-selected': {
- background: '#320a8d',
+ background: '#ff1f7a',
color: '#fff',
},
'&.Mui-selected:hover': {
- background: '#320a8d',
+ background: '#ff1f7a',
},
},
},
@@ -148,7 +240,7 @@ const theme = createTheme({
styleOverrides: {
root: {
'&.Mui-selected': {
- backgroundColor: '#f9faff',
+ backgroundColor: '#33275f',
},
},
},
diff --git a/exchange-oracle/client/vite.config.ts b/exchange-oracle/client/vite.config.ts
index 846dc0c..ce8efc5 100644
--- a/exchange-oracle/client/vite.config.ts
+++ b/exchange-oracle/client/vite.config.ts
@@ -20,6 +20,11 @@ export default defineConfig({
commonjsOptions: {
include: [/node_modules/],
},
+ rollupOptions: {
+ output: {
+ inlineDynamicImports: true,
+ },
+ },
},
server: {
port: 3003,
diff --git a/exchange-oracle/client/yarn.lock b/exchange-oracle/client/yarn.lock
index 2c89cd5..5f310fa 100644
--- a/exchange-oracle/client/yarn.lock
+++ b/exchange-oracle/client/yarn.lock
@@ -786,20 +786,20 @@ __metadata:
languageName: node
linkType: hard
-"@human-protocol/core@npm:6.0.0":
- version: 6.0.0
- resolution: "@human-protocol/core@npm:6.0.0"
+"@human-protocol/core@npm:7.0.0":
+ version: 7.0.0
+ resolution: "@human-protocol/core@npm:7.0.0"
peerDependencies:
- ethers: ~6.15.0
- checksum: 10c0/10316b23ed6987c75ca1276de85145200bd1190ac8116e5ce6dfad5c427b1b509db63457ba5849fb9c16477264fc521b6737af48cf4700edc968153e1f8e28f2
+ ethers: ~6.16.0
+ checksum: 10c0/b8083fca9b7fab0bca450b7a520cf9f0e8b3af29f4b90fc36ab1d3f24b2ff76aa53f3c3e160f7c40e7079aad6f32ebc67f5abaf8ad75eb77eee808fee7fd3955
languageName: node
linkType: hard
-"@human-protocol/sdk@npm:^7.1.0":
- version: 7.2.0
- resolution: "@human-protocol/sdk@npm:7.2.0"
+"@human-protocol/sdk@npm:^7.3.0":
+ version: 7.3.0
+ resolution: "@human-protocol/sdk@npm:7.3.0"
dependencies:
- "@human-protocol/core": "npm:6.0.0"
+ "@human-protocol/core": "npm:7.0.0"
axios: "npm:^1.4.0"
ethers: "npm:~6.16.0"
graphql: "npm:^16.8.1"
@@ -809,7 +809,7 @@ __metadata:
secp256k1: "npm:^5.0.1"
validator: "npm:^13.12.0"
vitest: "npm:^4.0.18"
- checksum: 10c0/7feac300575a4429f86b9602fd028edd543853d81198377d7a6b921548ba76b3fcb4b8a1f3611783a753b3b30620adcb94f53a8631dd060442eb20a5e382206d
+ checksum: 10c0/5835ce09161ab554483c6f9239f9985296491810b28a2f19adb090602c4436732b6787acb875ef2cf3fa9a6ca04ddecc620c52d5829f13a3cec1fd4dc85f1785
languageName: node
linkType: hard
@@ -5480,7 +5480,7 @@ __metadata:
"@emotion/react": "npm:^11.11.3"
"@emotion/styled": "npm:^11.11.0"
"@eslint/js": "npm:^10.0.1"
- "@human-protocol/sdk": "npm:^7.1.0"
+ "@human-protocol/sdk": "npm:^7.3.0"
"@mui/icons-material": "npm:^5.18.0"
"@mui/material": "npm:^5.16.7"
"@tanstack/query-sync-storage-persister": "npm:^5.68.0"
diff --git a/exchange-oracle/server/package.json b/exchange-oracle/server/package.json
index dea6e6a..43eae61 100644
--- a/exchange-oracle/server/package.json
+++ b/exchange-oracle/server/package.json
@@ -33,7 +33,7 @@
},
"dependencies": {
"@human-protocol/logger": "^1.3.0",
- "@human-protocol/sdk": "^7.1.0",
+ "@human-protocol/sdk": "^7.3.0",
"@nestjs/axios": "^4.0.1",
"@nestjs/common": "^11.1.12",
"@nestjs/config": "^4.0.2",
diff --git a/exchange-oracle/server/src/common/constant/errors.ts b/exchange-oracle/server/src/common/constant/errors.ts
index 4d00583..feb91c2 100644
--- a/exchange-oracle/server/src/common/constant/errors.ts
+++ b/exchange-oracle/server/src/common/constant/errors.ts
@@ -28,6 +28,7 @@ export enum ErrorAssignment {
FullyAssigned = 'Fully assigned job',
ExpiredEscrow = 'Expired escrow',
InsufficientTimeForLiveDuration = 'Not enough time remains before the job end date to satisfy post duration',
+ InvalidEndDate = 'Invalid assignment job end date',
JobNotFound = 'Job not found',
ReputationNetworkMismatch = 'Requested job is not in your reputation network',
}
diff --git a/exchange-oracle/server/src/common/interfaces/job.ts b/exchange-oracle/server/src/common/interfaces/job.ts
index d9251c4..1e442cb 100644
--- a/exchange-oracle/server/src/common/interfaces/job.ts
+++ b/exchange-oracle/server/src/common/interfaces/job.ts
@@ -21,12 +21,20 @@ export interface SocialMediaPromotionRequirements {
minReposts?: number;
}
+export interface XApiCredentials {
+ consumerKey: string;
+ consumerSecret: string;
+ accessToken: string;
+ accessTokenSecret: string;
+}
+
export interface SocialMediaEngagementRequirements {
targetPostUrl: string;
checkLike?: boolean;
checkRepost?: boolean;
checkQuote?: boolean;
checkComment?: boolean;
+ xApiCredentials?: XApiCredentials | string;
}
export type ManifestRequirements =
diff --git a/exchange-oracle/server/src/common/utils/encryption.ts b/exchange-oracle/server/src/common/utils/encryption.ts
new file mode 100644
index 0000000..d657ef4
--- /dev/null
+++ b/exchange-oracle/server/src/common/utils/encryption.ts
@@ -0,0 +1,25 @@
+import { Encryption } from '@human-protocol/sdk';
+
+import type { PGPConfigService } from '../config/pgp-config.service';
+
+export const isFullPgpMessage = (content: string): boolean => {
+ const trimmedContent = content.trim();
+
+ return (
+ trimmedContent.startsWith('-----BEGIN PGP MESSAGE-----') &&
+ trimmedContent.endsWith('-----END PGP MESSAGE-----')
+ );
+};
+
+export async function decryptJson(
+ encryptedContent: string,
+ pgpConfigService: PGPConfigService,
+): Promise {
+ const encryption = await Encryption.build(
+ pgpConfigService.privateKey!,
+ pgpConfigService.passphrase,
+ );
+ const decryptedData = await encryption.decrypt(encryptedContent);
+
+ return JSON.parse(Buffer.from(decryptedData).toString());
+}
diff --git a/exchange-oracle/server/src/database/migrations/1777010000000-renameManifestUrlToManifest.ts b/exchange-oracle/server/src/database/migrations/1777010000000-renameManifestUrlToManifest.ts
new file mode 100644
index 0000000..43710d5
--- /dev/null
+++ b/exchange-oracle/server/src/database/migrations/1777010000000-renameManifestUrlToManifest.ts
@@ -0,0 +1,17 @@
+import { MigrationInterface, QueryRunner } from 'typeorm';
+
+export class RenameManifestUrlToManifest1777010000000 implements MigrationInterface {
+ name = 'RenameManifestUrlToManifest1777010000000';
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`
+ ALTER TABLE "hmt"."jobs" RENAME COLUMN "manifest_url" TO "manifest"
+ `);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`
+ ALTER TABLE "hmt"."jobs" RENAME COLUMN "manifest" TO "manifest_url"
+ `);
+ }
+}
diff --git a/exchange-oracle/server/src/modules/assignment/assignment.controller.spec.ts b/exchange-oracle/server/src/modules/assignment/assignment.controller.spec.ts
index f67ba86..66232be 100644
--- a/exchange-oracle/server/src/modules/assignment/assignment.controller.spec.ts
+++ b/exchange-oracle/server/src/modules/assignment/assignment.controller.spec.ts
@@ -94,6 +94,36 @@ describe('assignmentController', () => {
});
});
+ describe('getAssignmentDetails', () => {
+ it('should call assignmentService.getAssignmentDetails', async () => {
+ const assignmentDetails = {
+ assignmentId: '123',
+ escrowAddress,
+ chainId: 80002,
+ jobType: JobType.SOCIAL_MEDIA_ENGAGEMENT,
+ status: AssignmentStatus.ACTIVE,
+ rewardAmount: 1,
+ rewardToken: 'HMT',
+ createdAt: new Date().toISOString(),
+ expiresAt: new Date().toISOString(),
+ updatedAt: new Date().toISOString(),
+ jobDescription: 'Like the target X post.',
+ endDate: new Date().toISOString(),
+ manifestUrl: 'https://example.com/manifest.json',
+ platforms: ['x'],
+ requirements: { targetPostUrl: 'https://x.com/test/status/123' },
+ };
+ jest
+ .spyOn(assignmentService, 'getAssignmentDetails')
+ .mockResolvedValue(assignmentDetails);
+
+ const result = await assignmentController.getAssignmentDetails('123');
+
+ expect(result).toBe(assignmentDetails);
+ expect(assignmentService.getAssignmentDetails).toHaveBeenCalledWith(123);
+ });
+ });
+
describe('resignJob', () => {
describe('succeed', () => {
it('should call jobService.resignJob', async () => {
diff --git a/exchange-oracle/server/src/modules/assignment/assignment.controller.ts b/exchange-oracle/server/src/modules/assignment/assignment.controller.ts
index 6f2d76e..1964f00 100644
--- a/exchange-oracle/server/src/modules/assignment/assignment.controller.ts
+++ b/exchange-oracle/server/src/modules/assignment/assignment.controller.ts
@@ -5,6 +5,7 @@ import {
UseGuards,
Request,
Get,
+ Param,
Query,
} from '@nestjs/common';
import {
@@ -18,6 +19,7 @@ import { JwtAuthGuard } from '../../common/guards/jwt.auth';
import { AssignmentService } from './assignment.service';
import {
AssignJobResponseDto,
+ AssignmentDetailsDto,
AssignmentDto,
CreateAssignmentDto,
GetAssignmentsDto,
@@ -25,6 +27,7 @@ import {
} from './assignment.dto';
import { RequestWithUser } from '../../common/types/jwt';
import { PageDto } from '../../common/pagination/pagination.dto';
+import { Public } from '../../common/decorators';
@ApiTags('Assignment')
@Controller('assignment')
@@ -102,6 +105,27 @@ export class AssignmentController {
);
}
+ @ApiOperation({
+ summary: 'Get Assignment Details',
+ description: 'Endpoint to retrieve assignment details for the solution UI.',
+ })
+ @ApiResponse({
+ status: 200,
+ description: 'Assignment details retrieved successfully.',
+ type: AssignmentDetailsDto,
+ })
+ @ApiResponse({
+ status: 404,
+ description: 'Assignment not found.',
+ })
+ @Public()
+ @Get(':assignmentId/details')
+ getAssignmentDetails(
+ @Param('assignmentId') assignmentId: string,
+ ): Promise {
+ return this.assignmentService.getAssignmentDetails(Number(assignmentId));
+ }
+
@ApiOperation({
summary: 'Resign Assignment',
description: 'Endpoint to resign from a assignment.',
diff --git a/exchange-oracle/server/src/modules/assignment/assignment.dto.ts b/exchange-oracle/server/src/modules/assignment/assignment.dto.ts
index 1375292..b86487a 100644
--- a/exchange-oracle/server/src/modules/assignment/assignment.dto.ts
+++ b/exchange-oracle/server/src/modules/assignment/assignment.dto.ts
@@ -138,6 +138,51 @@ export class AssignmentDto {
}
}
+export class AssignmentDetailsDto extends AssignmentDto {
+ @ApiProperty({ name: 'job_description' })
+ jobDescription: string;
+
+ @ApiProperty({ name: 'end_date' })
+ endDate: string;
+
+ @ApiProperty({ name: 'manifest_url' })
+ manifestUrl: string;
+
+ @ApiProperty({ isArray: true })
+ platforms: string[];
+
+ @ApiProperty()
+ requirements: Record;
+
+ constructor(
+ assignment: AssignmentDto,
+ jobDescription: string,
+ endDate: string,
+ manifestUrl: string,
+ platforms: string[],
+ requirements: Record,
+ ) {
+ super(
+ assignment.assignmentId,
+ assignment.escrowAddress,
+ assignment.chainId,
+ assignment.jobType,
+ assignment.status,
+ assignment.rewardAmount,
+ assignment.rewardToken,
+ assignment.createdAt,
+ assignment.expiresAt,
+ assignment.updatedAt ?? '',
+ );
+ this.url = assignment.url;
+ this.jobDescription = jobDescription;
+ this.endDate = endDate;
+ this.manifestUrl = manifestUrl;
+ this.platforms = platforms;
+ this.requirements = requirements;
+ }
+}
+
export class ResignDto {
@ApiProperty({ name: 'assignment_id' })
@IsString()
diff --git a/exchange-oracle/server/src/modules/assignment/assignment.service.spec.ts b/exchange-oracle/server/src/modules/assignment/assignment.service.spec.ts
index 041fb98..e717c9d 100644
--- a/exchange-oracle/server/src/modules/assignment/assignment.service.spec.ts
+++ b/exchange-oracle/server/src/modules/assignment/assignment.service.spec.ts
@@ -118,7 +118,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -146,7 +146,7 @@ describe('AssignmentService', () => {
expect(assignmentRepository.createUnique).toHaveBeenCalledWith({
job: {
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
},
@@ -181,7 +181,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -212,7 +212,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -266,7 +266,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: differentReputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -284,7 +284,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.CANCELED,
} as any);
@@ -302,7 +302,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -326,7 +326,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -358,7 +358,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -387,7 +387,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -413,7 +413,7 @@ describe('AssignmentService', () => {
.spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
.mockResolvedValue({
id: 1,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
reputationNetwork: reputationNetwork,
status: JobStatus.ACTIVE,
} as any);
@@ -445,7 +445,7 @@ describe('AssignmentService', () => {
job: {
chainId: 1,
escrowAddress,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
jobType: JobType.SOCIAL_MEDIA_PROMOTION,
rewardToken: 'HMT',
},
@@ -584,6 +584,87 @@ describe('AssignmentService', () => {
});
});
+ describe('getAssignmentDetails', () => {
+ const assignmentId = 3;
+ const assignmentEntity = {
+ id: assignmentId,
+ job: {
+ chainId,
+ escrowAddress,
+ manifest: MOCK_MANIFEST_URL,
+ jobType: JobType.SOCIAL_MEDIA_PROMOTION,
+ rewardToken: 'HMT',
+ },
+ status: AssignmentStatus.ACTIVE,
+ createdAt: new Date('2026-01-01T00:00:00.000Z'),
+ expiresAt: new Date('2026-01-02T00:00:00.000Z'),
+ updatedAt: new Date('2026-01-03T00:00:00.000Z'),
+ rewardAmount: 20,
+ } as unknown as AssignmentEntity;
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ it('should return details when manifest end date is a millisecond timestamp', async () => {
+ const endDate = 1782129600000;
+ const manifest = createManifest({
+ endDate,
+ });
+
+ jest
+ .spyOn(assignmentRepository, 'findOneById')
+ .mockResolvedValue(assignmentEntity);
+ jest.spyOn(jobService, 'getManifest').mockResolvedValue(manifest);
+
+ const result = await assignmentService.getAssignmentDetails(assignmentId);
+
+ expect(result.endDate).toBe('2026-06-22T12:00:00.000Z');
+ expect(result).toEqual(
+ expect.objectContaining({
+ assignmentId: assignmentId.toString(),
+ chainId,
+ escrowAddress,
+ jobDescription: manifest.campaign.description,
+ manifestUrl: MOCK_MANIFEST_URL,
+ platforms: manifest.platforms,
+ }),
+ );
+ });
+
+ it('should return details when manifest end date is snake case', async () => {
+ const manifest = {
+ ...createManifest(),
+ endDate: undefined,
+ end_date: 1782129600000,
+ } as unknown as ManifestDto;
+
+ jest
+ .spyOn(assignmentRepository, 'findOneById')
+ .mockResolvedValue(assignmentEntity);
+ jest.spyOn(jobService, 'getManifest').mockResolvedValue(manifest);
+
+ const result = await assignmentService.getAssignmentDetails(assignmentId);
+
+ expect(result.endDate).toBe('2026-06-22T12:00:00.000Z');
+ });
+
+ it('should fail with validation error when manifest end date is invalid', async () => {
+ const manifest = createManifest({
+ endDate: 'not-a-date',
+ } as unknown as Partial);
+
+ jest
+ .spyOn(assignmentRepository, 'findOneById')
+ .mockResolvedValue(assignmentEntity);
+ jest.spyOn(jobService, 'getManifest').mockResolvedValue(manifest);
+
+ await expect(
+ assignmentService.getAssignmentDetails(assignmentId),
+ ).rejects.toThrow(ErrorAssignment.InvalidEndDate);
+ });
+ });
+
describe('resignJob', () => {
describe('succeed', () => {
it('should successfully cancel an active assignment', async () => {
diff --git a/exchange-oracle/server/src/modules/assignment/assignment.service.ts b/exchange-oracle/server/src/modules/assignment/assignment.service.ts
index d49dfb1..0c4b1e3 100644
--- a/exchange-oracle/server/src/modules/assignment/assignment.service.ts
+++ b/exchange-oracle/server/src/modules/assignment/assignment.service.ts
@@ -16,6 +16,7 @@ import { JobRepository } from '../job/job.repository';
import { JobService } from '../job/job.service';
import { Web3Service } from '../web3/web3.service';
import {
+ AssignmentDetailsDto,
AssignmentDto,
CreateAssignmentDto,
GetAssignmentsDto,
@@ -77,14 +78,16 @@ export class AssignmentService {
const manifest = await this.jobService.getManifest(
data.chainId,
data.escrowAddress,
- jobEntity.manifestUrl,
+ jobEntity.manifest,
);
if (currentAssignments >= manifest.submissionsRequired) {
throw new ValidationError(ErrorAssignment.FullyAssigned);
}
- const jobEndDate = new Date(manifest.endDate);
+ const jobEndDate = this.parseManifestEndDate(
+ this.getManifestEndDate(manifest),
+ );
const requiredLiveDurationHours =
manifest.requestType === JobType.SOCIAL_MEDIA_PROMOTION &&
'minLiveDurationHours' in manifest.requirements
@@ -149,29 +152,40 @@ export class AssignmentService {
});
const assignments = await Promise.all(
entities.map(async (entity) => {
- const assignment = new AssignmentDto(
- entity.id.toString(),
- entity.job.escrowAddress,
- entity.job.chainId,
- entity.job.jobType,
- entity.status,
- entity.rewardAmount,
- entity.job.rewardToken,
- entity.createdAt.toISOString(),
- entity.expiresAt.toISOString(),
- entity.updatedAt.toISOString(),
- );
- if (entity.status === AssignmentStatus.ACTIVE)
- assignment.url =
- this.serverConfigService.feURL +
- '/assignment/' +
- entity.id.toString();
- return assignment;
+ return this.toAssignmentDto(entity);
}),
);
return new PageDto(data.page!, data.pageSize!, itemCount, assignments);
}
+ public async getAssignmentDetails(
+ assignmentId: number,
+ ): Promise {
+ const entity = await this.assignmentRepository.findOneById(assignmentId);
+
+ if (!entity) {
+ throw new ServerError(ErrorAssignment.NotFound);
+ }
+
+ const manifest = await this.jobService.getManifest(
+ entity.job.chainId,
+ entity.job.escrowAddress,
+ entity.job.manifest,
+ );
+ const assignment = this.toAssignmentDto(entity);
+
+ return new AssignmentDetailsDto(
+ assignment,
+ manifest.campaign.description,
+ this.parseManifestEndDate(
+ this.getManifestEndDate(manifest),
+ ).toISOString(),
+ entity.job.manifest,
+ manifest.platforms,
+ this.getPublicRequirements(manifest.requirements),
+ );
+ }
+
async resign(assignmentId: number, workerAddress: string): Promise {
const assignment =
await this.assignmentRepository.findOneById(assignmentId);
@@ -190,4 +204,70 @@ export class AssignmentService {
assignment.status = AssignmentStatus.CANCELED;
await this.assignmentRepository.updateOne(assignment);
}
+
+ private toAssignmentDto(entity: AssignmentEntity): AssignmentDto {
+ const assignment = new AssignmentDto(
+ entity.id.toString(),
+ entity.job.escrowAddress,
+ entity.job.chainId,
+ entity.job.jobType,
+ entity.status,
+ entity.rewardAmount,
+ entity.job.rewardToken,
+ entity.createdAt.toISOString(),
+ entity.expiresAt.toISOString(),
+ entity.updatedAt.toISOString(),
+ );
+
+ if (entity.status === AssignmentStatus.ACTIVE) {
+ assignment.url =
+ this.serverConfigService.feURL + '/assignment/' + entity.id.toString();
+ }
+
+ return assignment;
+ }
+
+ private getPublicRequirements(requirements: object): Record {
+ const publicRequirements = {
+ ...(requirements as Record),
+ };
+ delete publicRequirements.xApiCredentials;
+
+ return publicRequirements;
+ }
+
+ private getManifestEndDate(manifest: unknown): unknown {
+ if (!manifest || typeof manifest !== 'object') {
+ return undefined;
+ }
+
+ const manifestRecord = manifest as Record;
+ return manifestRecord.endDate ?? manifestRecord.end_date;
+ }
+
+ private parseManifestEndDate(endDate: unknown): Date {
+ if (endDate === null || endDate === undefined) {
+ throw new ValidationError(ErrorAssignment.InvalidEndDate);
+ }
+
+ if (
+ typeof endDate !== 'string' &&
+ typeof endDate !== 'number' &&
+ !(endDate instanceof Date)
+ ) {
+ throw new ValidationError(ErrorAssignment.InvalidEndDate);
+ }
+
+ const timestamp =
+ typeof endDate === 'string' && endDate.trim() !== ''
+ ? Number(endDate)
+ : endDate;
+ const date = new Date(timestamp);
+
+ if (Number.isNaN(date.getTime())) {
+ throw new ValidationError(ErrorAssignment.InvalidEndDate);
+ }
+
+ return date;
+ }
}
diff --git a/exchange-oracle/server/src/modules/job/job.entity.ts b/exchange-oracle/server/src/modules/job/job.entity.ts
index b00c67b..7de9e3c 100644
--- a/exchange-oracle/server/src/modules/job/job.entity.ts
+++ b/exchange-oracle/server/src/modules/job/job.entity.ts
@@ -15,7 +15,7 @@ export class JobEntity extends BaseEntity {
public escrowAddress: string;
@Column({ type: 'varchar', nullable: true })
- public manifestUrl: string;
+ public manifest: string;
@Column({ type: 'varchar', default: JobType.SOCIAL_MEDIA_PROMOTION })
public jobType: JobType;
diff --git a/exchange-oracle/server/src/modules/job/job.service.spec.ts b/exchange-oracle/server/src/modules/job/job.service.spec.ts
index 32fac5a..1e54746 100644
--- a/exchange-oracle/server/src/modules/job/job.service.spec.ts
+++ b/exchange-oracle/server/src/modules/job/job.service.spec.ts
@@ -1,12 +1,7 @@
import { faker } from '@faker-js/faker';
import { createMock } from '@golevelup/ts-jest';
import { HMToken__factory } from '@human-protocol/core/typechain-types';
-import {
- Encryption,
- EncryptionUtils,
- EscrowClient,
- EscrowUtils,
-} from '@human-protocol/sdk';
+import { Encryption, EscrowClient, EscrowUtils } from '@human-protocol/sdk';
import { ConfigService } from '@nestjs/config';
import { Test } from '@nestjs/testing';
import { ethers } from 'ethers';
@@ -156,7 +151,7 @@ describe('JobService', () => {
expect(jobRepository.createUnique).toHaveBeenCalledWith({
chainId,
escrowAddress,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
jobType: JobType.SOCIAL_MEDIA_PROMOTION,
reputationNetwork,
rewardToken: 'HMT',
@@ -182,13 +177,46 @@ describe('JobService', () => {
expect(jobRepository.createUnique).toHaveBeenCalledWith({
chainId,
escrowAddress,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
jobType: JobType.SOCIAL_MEDIA_ENGAGEMENT,
reputationNetwork,
rewardToken: 'HMT',
status: JobStatus.ACTIVE,
});
});
+
+ it('should create a new job with an inline manifest source', async () => {
+ const manifest = createManifest();
+ const manifestSource = JSON.stringify(manifest);
+ (EscrowClient.build as any).mockResolvedValueOnce({
+ getManifest: jest.fn().mockResolvedValue(manifestSource),
+ getReputationOracleAddress: jest
+ .fn()
+ .mockResolvedValue(reputationNetwork),
+ getTokenAddress: jest.fn().mockResolvedValue(MOCK_ADDRESS),
+ });
+ jest
+ .spyOn(jobRepository, 'findOneByChainIdAndEscrowAddress')
+ .mockResolvedValue(null);
+ const getManifestSpy = jest
+ .spyOn(jobService, 'getManifest')
+ .mockResolvedValue(manifest);
+
+ await jobService.createJob(webhook);
+
+ expect(getManifestSpy).toHaveBeenCalledWith(
+ chainId,
+ escrowAddress,
+ manifestSource,
+ );
+ expect(jobRepository.createUnique).toHaveBeenCalledWith(
+ expect.objectContaining({
+ manifest: manifestSource,
+ jobType: manifest.requestType,
+ }),
+ );
+ getManifestSpy.mockRestore();
+ });
});
describe('fail', () => {
@@ -368,7 +396,7 @@ describe('JobService', () => {
jobId: 1,
chainId: 1,
escrowAddress,
- manifestUrl: MOCK_MANIFEST_URL,
+ manifest: MOCK_MANIFEST_URL,
jobType: JobType.SOCIAL_MEDIA_PROMOTION,
status: JobStatus.ACTIVE,
createdAt: new Date(),
@@ -699,10 +727,50 @@ describe('JobService', () => {
).resolves.toEqual(manifest);
});
+ it('should return an inline JSON manifest', async () => {
+ const manifest = createManifest();
+
+ await expect(
+ jobService.getManifest(
+ chainId,
+ escrowAddress,
+ JSON.stringify(manifest),
+ ),
+ ).resolves.toEqual(manifest);
+
+ expect(downloadFileFromUrlMock).not.toHaveBeenCalled();
+ });
+
+ it('should return an inline JSON manifest with encrypted X API credentials', async () => {
+ const manifest = {
+ ...createManifest(),
+ requestType: JobType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['x'],
+ requirements: {
+ targetPostUrl: faker.internet.url(),
+ checkLike: true,
+ xApiCredentials:
+ '-----BEGIN PGP MESSAGE-----\ncontent\n-----END PGP MESSAGE-----',
+ },
+ };
+
+ await expect(
+ jobService.getManifest(
+ chainId,
+ escrowAddress,
+ JSON.stringify(manifest),
+ ),
+ ).resolves.toEqual(manifest);
+
+ expect(Encryption.build).not.toHaveBeenCalled();
+ expect(downloadFileFromUrlMock).not.toHaveBeenCalled();
+ });
+
it('should decrypt an encrypted manifest', async () => {
const manifest = createManifest();
- downloadFileFromUrlMock.mockResolvedValueOnce('encrypted');
- jest.spyOn(EncryptionUtils, 'isEncrypted').mockReturnValue(true);
+ downloadFileFromUrlMock.mockResolvedValueOnce(
+ '-----BEGIN PGP MESSAGE-----\nencrypted\n-----END PGP MESSAGE-----',
+ );
(Encryption.build as any).mockResolvedValue({
decrypt: jest.fn().mockResolvedValue(JSON.stringify(manifest)),
});
diff --git a/exchange-oracle/server/src/modules/job/job.service.ts b/exchange-oracle/server/src/modules/job/job.service.ts
index f298c9c..7ac377e 100644
--- a/exchange-oracle/server/src/modules/job/job.service.ts
+++ b/exchange-oracle/server/src/modules/job/job.service.ts
@@ -2,12 +2,7 @@ import {
HMToken,
HMToken__factory,
} from '@human-protocol/core/typechain-types';
-import {
- Encryption,
- EncryptionUtils,
- EscrowClient,
- EscrowUtils,
-} from '@human-protocol/sdk';
+import { EscrowClient, EscrowUtils } from '@human-protocol/sdk';
import { Inject, Injectable } from '@nestjs/common';
import { ethers } from 'ethers';
@@ -33,8 +28,9 @@ import {
ValidationError,
} from '../../common/errors';
import { PageDto } from '../../common/pagination/pagination.dto';
+import { decryptJson, isFullPgpMessage } from '../../common/utils/encryption';
import { formatAxiosError } from '../../common/utils/http';
-import { downloadFileFromUrl } from '../../common/utils/storage';
+import { downloadFileFromUrl, isValidUrl } from '../../common/utils/storage';
import { AssignmentEntity } from '../assignment/assignment.entity';
import { AssignmentRepository } from '../assignment/assignment.repository';
import { Web3Service } from '../web3/web3.service';
@@ -77,11 +73,11 @@ export class JobService {
signer,
);
- const manifestUrl = await escrowClient.getManifest(escrowAddress);
+ const manifestSource = await escrowClient.getManifest(escrowAddress);
const manifest = await this.getManifest(
chainId,
escrowAddress,
- manifestUrl,
+ manifestSource,
);
const jobType = manifest.requestType;
@@ -91,7 +87,7 @@ export class JobService {
const newJobEntity = new JobEntity();
newJobEntity.escrowAddress = escrowAddress;
- newJobEntity.manifestUrl = manifestUrl;
+ newJobEntity.manifest = manifestSource;
newJobEntity.jobType = jobType;
newJobEntity.chainId = chainId;
newJobEntity.rewardToken = await tokenContract.symbol();
@@ -185,7 +181,7 @@ export class JobService {
const manifest = await this.getManifest(
entity.chainId,
entity.escrowAddress,
- entity.manifestUrl,
+ entity.manifest,
);
if (data.fields?.includes(JobFieldName.JobDescription)) {
job.jobDescription = manifest.campaign.description;
@@ -296,28 +292,28 @@ export class JobService {
public async getManifest(
chainId: number,
escrowAddress: string,
- manifestUrl: string,
+ manifestSource: string,
): Promise {
let manifest: ManifestDto | null = null;
try {
- const manifestEncrypted = await downloadFileFromUrl(manifestUrl);
+ const manifestContent = isValidUrl(manifestSource)
+ ? await downloadFileFromUrl(manifestSource)
+ : manifestSource;
if (
- typeof manifestEncrypted === 'string' &&
- EncryptionUtils.isEncrypted(manifestEncrypted)
+ typeof manifestContent === 'string' &&
+ isFullPgpMessage(manifestContent)
) {
- const encryption = await Encryption.build(
- this.pgpConfigService.privateKey!,
- this.pgpConfigService.passphrase,
- );
- const decryptedData = await encryption.decrypt(manifestEncrypted);
- manifest = JSON.parse(Buffer.from(decryptedData).toString());
+ manifest = (await decryptJson(
+ manifestContent,
+ this.pgpConfigService,
+ )) as ManifestDto;
} else {
manifest =
- typeof manifestEncrypted === 'string'
- ? JSON.parse(manifestEncrypted)
- : manifestEncrypted;
+ typeof manifestContent === 'string'
+ ? JSON.parse(manifestContent)
+ : manifestContent;
}
} catch {
manifest = null;
diff --git a/exchange-oracle/server/test/fixtures/manifest.ts b/exchange-oracle/server/test/fixtures/manifest.ts
index 3b0e0f0..4fea3ee 100644
--- a/exchange-oracle/server/test/fixtures/manifest.ts
+++ b/exchange-oracle/server/test/fixtures/manifest.ts
@@ -22,7 +22,7 @@ export function createManifest(
},
requirements: {
targetPostUrl: `https://x.com/${faker.internet.username()}/status/${faker.string.numeric(8)}`,
- checkLike: true,
+ checkQuote: true,
},
...overrides,
} as ManifestDto;
diff --git a/exchange-oracle/server/yarn.lock b/exchange-oracle/server/yarn.lock
index b222538..b5da079 100644
--- a/exchange-oracle/server/yarn.lock
+++ b/exchange-oracle/server/yarn.lock
@@ -641,12 +641,12 @@ __metadata:
languageName: node
linkType: hard
-"@human-protocol/core@npm:6.0.0":
- version: 6.0.0
- resolution: "@human-protocol/core@npm:6.0.0"
+"@human-protocol/core@npm:7.0.0":
+ version: 7.0.0
+ resolution: "@human-protocol/core@npm:7.0.0"
peerDependencies:
- ethers: ~6.15.0
- checksum: 10c0/10316b23ed6987c75ca1276de85145200bd1190ac8116e5ce6dfad5c427b1b509db63457ba5849fb9c16477264fc521b6737af48cf4700edc968153e1f8e28f2
+ ethers: ~6.16.0
+ checksum: 10c0/b8083fca9b7fab0bca450b7a520cf9f0e8b3af29f4b90fc36ab1d3f24b2ff76aa53f3c3e160f7c40e7079aad6f32ebc67f5abaf8ad75eb77eee808fee7fd3955
languageName: node
linkType: hard
@@ -662,21 +662,21 @@ __metadata:
languageName: node
linkType: hard
-"@human-protocol/sdk@npm:^7.1.0":
- version: 7.1.0
- resolution: "@human-protocol/sdk@npm:7.1.0"
+"@human-protocol/sdk@npm:^7.3.0":
+ version: 7.3.0
+ resolution: "@human-protocol/sdk@npm:7.3.0"
dependencies:
- "@human-protocol/core": "npm:6.0.0"
+ "@human-protocol/core": "npm:7.0.0"
axios: "npm:^1.4.0"
ethers: "npm:~6.16.0"
graphql: "npm:^16.8.1"
graphql-request: "npm:^7.3.4"
graphql-tag: "npm:^2.12.6"
- openpgp: "npm:^6.2.2"
+ openpgp: "npm:^6.3.0"
secp256k1: "npm:^5.0.1"
validator: "npm:^13.12.0"
vitest: "npm:^4.0.18"
- checksum: 10c0/8c483aa56f95b95f1a9ea6d6990f19fbb9911bb6792399523cb40cce232361b464a78457c2a60a58572d6b6efe4a1418162e096df344e6397130633c642c0407
+ checksum: 10c0/5835ce09161ab554483c6f9239f9985296491810b28a2f19adb090602c4436732b6787acb875ef2cf3fa9a6ca04ddecc620c52d5829f13a3cec1fd4dc85f1785
languageName: node
linkType: hard
@@ -4465,7 +4465,7 @@ __metadata:
"@faker-js/faker": "npm:^9.7.0"
"@golevelup/ts-jest": "npm:^0.6.1"
"@human-protocol/logger": "npm:^1.3.0"
- "@human-protocol/sdk": "npm:^7.1.0"
+ "@human-protocol/sdk": "npm:^7.3.0"
"@nestjs/axios": "npm:^4.0.1"
"@nestjs/cli": "npm:^11.0.16"
"@nestjs/common": "npm:^11.1.12"
@@ -7110,10 +7110,15 @@ __metadata:
languageName: node
linkType: hard
-"openpgp@npm:^6.2.2":
- version: 6.3.0
- resolution: "openpgp@npm:6.3.0"
- checksum: 10c0/0528cb57d7cfd10ef4ab8ce868a0244a4930019d50feed9158028debfd85e5e1a621a4cc5ae254a0b1820a355b12fc7adbe04c950c731d9bb63ca9a9ed44a948
+"openpgp@npm:^6.3.0":
+ version: 6.3.1
+ resolution: "openpgp@npm:6.3.1"
+ peerDependencies:
+ "@openpgp/web-stream-tools": ~0.3.0
+ peerDependenciesMeta:
+ "@openpgp/web-stream-tools":
+ optional: true
+ checksum: 10c0/5c3d3d973219a1c53ca5994720aabdc36312d39ea3199dcf7010d6b20cd46a66ee6289a403697a9d33676e4e5dd4799ddba3396eb08a23a24419711909b635cd
languageName: node
linkType: hard
diff --git a/recording-oracle/.env.example b/recording-oracle/.env.example
index e423c5f..70e5f68 100644
--- a/recording-oracle/.env.example
+++ b/recording-oracle/.env.example
@@ -34,5 +34,11 @@ X_API_BASE_URL=https://api.x.com/2
X_API_PAGE_SIZE=100
X_API_MAX_PAGES_PER_ACTION=10
+# LinkdAPI
+LINKDAPI_API_KEY=replace_me
+LINKDAPI_BASE_URL=https://linkdapi.com
+LINKDAPI_PAGE_SIZE=100
+LINKDAPI_MAX_PAGES_PER_ACTION=10
+
# Encryption
PGP_ENCRYPT=false
diff --git a/recording-oracle/package.json b/recording-oracle/package.json
index fa5622c..8281830 100644
--- a/recording-oracle/package.json
+++ b/recording-oracle/package.json
@@ -32,7 +32,7 @@
},
"dependencies": {
"@human-protocol/logger": "^1.3.0",
- "@human-protocol/sdk": "^7.1.0",
+ "@human-protocol/sdk": "^7.3.0",
"@nestjs/axios": "^4.0.1",
"@nestjs/common": "^11.1.12",
"@nestjs/config": "^4.0.2",
@@ -48,6 +48,7 @@
"dotenv": "^17.2.2",
"helmet": "^7.1.0",
"joi": "^17.13.3",
+ "linkdapi": "^1.0.2",
"minio": "8.0.6",
"pg": "^8.16.3",
"reflect-metadata": "^0.2.2",
diff --git a/recording-oracle/src/common/config/config.module.ts b/recording-oracle/src/common/config/config.module.ts
index 47cad45..6c3e176 100644
--- a/recording-oracle/src/common/config/config.module.ts
+++ b/recording-oracle/src/common/config/config.module.ts
@@ -7,6 +7,7 @@ import { Web3ConfigService } from './web3-config.service';
import { NetworkConfigService } from './network-config.service';
import { DatabaseConfigService } from './database-config.service';
import { GrokConfigService } from './grok-config.service';
+import { LinkdapiConfigService } from './linkdapi-config.service';
import { XApiConfigService } from './x-api-config.service';
@Global()
@@ -20,6 +21,7 @@ import { XApiConfigService } from './x-api-config.service';
NetworkConfigService,
DatabaseConfigService,
GrokConfigService,
+ LinkdapiConfigService,
XApiConfigService,
],
exports: [
@@ -31,6 +33,7 @@ import { XApiConfigService } from './x-api-config.service';
NetworkConfigService,
DatabaseConfigService,
GrokConfigService,
+ LinkdapiConfigService,
XApiConfigService,
],
})
diff --git a/recording-oracle/src/common/config/env-schema.ts b/recording-oracle/src/common/config/env-schema.ts
index a67ec63..0ba9b11 100644
--- a/recording-oracle/src/common/config/env-schema.ts
+++ b/recording-oracle/src/common/config/env-schema.ts
@@ -75,4 +75,9 @@ export const envValidator = Joi.object({
X_API_BASE_URL: Joi.string().uri(),
X_API_PAGE_SIZE: Joi.number(),
X_API_MAX_PAGES_PER_ACTION: Joi.number(),
+ // LinkdAPI
+ LINKDAPI_API_KEY: Joi.string().optional(),
+ LINKDAPI_BASE_URL: Joi.string().uri(),
+ LINKDAPI_PAGE_SIZE: Joi.number(),
+ LINKDAPI_MAX_PAGES_PER_ACTION: Joi.number(),
});
diff --git a/recording-oracle/src/common/config/linkdapi-config.service.ts b/recording-oracle/src/common/config/linkdapi-config.service.ts
new file mode 100644
index 0000000..e4a3d66
--- /dev/null
+++ b/recording-oracle/src/common/config/linkdapi-config.service.ts
@@ -0,0 +1,29 @@
+import { Injectable } from '@nestjs/common';
+import { ConfigService } from '@nestjs/config';
+
+@Injectable()
+export class LinkdapiConfigService {
+ constructor(private readonly configService: ConfigService) {}
+
+ get apiKey(): string | undefined {
+ return this.configService.get('LINKDAPI_API_KEY');
+ }
+
+ get baseUrl(): string {
+ return this.configService.get(
+ 'LINKDAPI_BASE_URL',
+ 'https://linkdapi.com',
+ );
+ }
+
+ get pageSize(): number {
+ return Math.min(
+ this.configService.get('LINKDAPI_PAGE_SIZE', 100),
+ 100,
+ );
+ }
+
+ get maxPagesPerAction(): number {
+ return this.configService.get('LINKDAPI_MAX_PAGES_PER_ACTION', 10);
+ }
+}
diff --git a/recording-oracle/src/common/constants/errors.ts b/recording-oracle/src/common/constants/errors.ts
index d1a0865..95bd757 100644
--- a/recording-oracle/src/common/constants/errors.ts
+++ b/recording-oracle/src/common/constants/errors.ts
@@ -8,7 +8,8 @@ export enum ErrorJob {
InvalidJobType = 'Manifest contains an invalid job type',
SolutionAlreadyExists = 'Solution already exists',
InvalidPostUrl = 'Post URL must be a valid x.com status URL',
- InvalidXUsername = 'X username must be a valid handle',
+ InvalidSocialProfile = 'Social profile must be a valid handle or profile URL',
+ UnsupportedSocialPlatform = 'Social media engagement platform must be x or linkedin',
}
/**
diff --git a/recording-oracle/src/common/interfaces/job.ts b/recording-oracle/src/common/interfaces/job.ts
index 9b17113..8723777 100644
--- a/recording-oracle/src/common/interfaces/job.ts
+++ b/recording-oracle/src/common/interfaces/job.ts
@@ -17,12 +17,20 @@ export interface ISocialMediaPromotionRequirements {
minReposts?: number;
}
+export interface IXApiCredentials {
+ consumerKey: string;
+ consumerSecret: string;
+ accessToken: string;
+ accessTokenSecret: string;
+}
+
export interface ISocialMediaEngagementRequirements {
targetPostUrl: string;
checkLike?: boolean;
checkRepost?: boolean;
checkQuote?: boolean;
checkComment?: boolean;
+ xApiCredentials?: IXApiCredentials;
}
export type IManifestRequirements =
diff --git a/recording-oracle/src/common/utils/encryption.ts b/recording-oracle/src/common/utils/encryption.ts
new file mode 100644
index 0000000..75e6b0e
--- /dev/null
+++ b/recording-oracle/src/common/utils/encryption.ts
@@ -0,0 +1,35 @@
+import { Encryption } from '@human-protocol/sdk';
+
+import type { PGPConfigService } from '../config/pgp-config.service';
+import { ErrorStorage } from '../constants/errors';
+import { ServerError } from '../errors';
+
+export const isFullPgpMessage = (content: string): boolean => {
+ const trimmedContent = content.trim();
+
+ return (
+ trimmedContent.startsWith('-----BEGIN PGP MESSAGE-----') &&
+ trimmedContent.endsWith('-----END PGP MESSAGE-----')
+ );
+};
+
+export async function decryptJson(
+ encryptedContent: string,
+ pgpConfigService: PGPConfigService,
+): Promise {
+ try {
+ const privateKey = pgpConfigService.privateKey;
+ if (!privateKey) {
+ throw new ServerError(ErrorStorage.UnableDecryptManifest);
+ }
+ const encryption = await Encryption.build(
+ privateKey,
+ pgpConfigService.passphrase,
+ );
+
+ const decryptedData = await encryption.decrypt(encryptedContent);
+ return JSON.parse(Buffer.from(decryptedData).toString());
+ } catch {
+ throw new ServerError(ErrorStorage.UnableDecryptManifest);
+ }
+}
diff --git a/recording-oracle/src/common/utils/manifest.ts b/recording-oracle/src/common/utils/manifest.ts
new file mode 100644
index 0000000..94c25fe
--- /dev/null
+++ b/recording-oracle/src/common/utils/manifest.ts
@@ -0,0 +1,55 @@
+import { EncryptionUtils } from '@human-protocol/sdk';
+
+import type { PGPConfigService } from '../config/pgp-config.service';
+import { decryptJson, isFullPgpMessage } from './encryption';
+
+export async function parseManifestContent(
+ manifestContent: unknown,
+ pgpConfigService: PGPConfigService,
+): Promise {
+ if (
+ typeof manifestContent === 'string' &&
+ isFullPgpMessage(manifestContent)
+ ) {
+ return decryptJson(manifestContent, pgpConfigService);
+ }
+
+ const parsedContent =
+ typeof manifestContent === 'string'
+ ? JSON.parse(manifestContent)
+ : manifestContent;
+
+ return decryptManifestCredentials(parsedContent, pgpConfigService);
+}
+
+async function decryptManifestCredentials(
+ content: unknown,
+ pgpConfigService: PGPConfigService,
+): Promise {
+ if (!content || typeof content !== 'object') {
+ return content;
+ }
+
+ const manifest = content as {
+ requirements?: Record;
+ };
+ const encryptedCredentials = manifest.requirements?.xApiCredentials;
+
+ if (
+ typeof encryptedCredentials !== 'string' ||
+ !EncryptionUtils.isEncrypted(encryptedCredentials)
+ ) {
+ return content;
+ }
+
+ return {
+ ...manifest,
+ requirements: {
+ ...manifest.requirements,
+ xApiCredentials: await decryptJson(
+ encryptedCredentials,
+ pgpConfigService,
+ ),
+ },
+ };
+}
diff --git a/recording-oracle/src/database/migrations/1777010000000-renameManifestUrlToManifest.ts b/recording-oracle/src/database/migrations/1777010000000-renameManifestUrlToManifest.ts
new file mode 100644
index 0000000..43710d5
--- /dev/null
+++ b/recording-oracle/src/database/migrations/1777010000000-renameManifestUrlToManifest.ts
@@ -0,0 +1,17 @@
+import { MigrationInterface, QueryRunner } from 'typeorm';
+
+export class RenameManifestUrlToManifest1777010000000 implements MigrationInterface {
+ name = 'RenameManifestUrlToManifest1777010000000';
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`
+ ALTER TABLE "hmt"."jobs" RENAME COLUMN "manifest_url" TO "manifest"
+ `);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`
+ ALTER TABLE "hmt"."jobs" RENAME COLUMN "manifest" TO "manifest_url"
+ `);
+ }
+}
diff --git a/recording-oracle/src/modules/cron-job/cron-job.service.ts b/recording-oracle/src/modules/cron-job/cron-job.service.ts
index e936b5e..8a7b7b7 100644
--- a/recording-oracle/src/modules/cron-job/cron-job.service.ts
+++ b/recording-oracle/src/modules/cron-job/cron-job.service.ts
@@ -68,7 +68,7 @@ export class CronJobService {
for (const job of jobs) {
try {
- const manifest = await this.jobService.getManifest(job.manifestUrl);
+ const manifest = await this.jobService.getManifest(job.manifest);
const allResults = await this.submissionService.processSubmissions(
job.submissions ?? [],
manifest,
diff --git a/recording-oracle/src/modules/job/fixtures/index.ts b/recording-oracle/src/modules/job/fixtures/index.ts
index 457aa0b..f2c141f 100644
--- a/recording-oracle/src/modules/job/fixtures/index.ts
+++ b/recording-oracle/src/modules/job/fixtures/index.ts
@@ -23,7 +23,7 @@ export const generateManifest = (
},
requirements: {
targetPostUrl: `https://x.com/${faker.internet.username()}/status/${faker.string.numeric(8)}`,
- checkLike: true,
+ checkQuote: true,
},
...overrides,
} as IManifest;
@@ -52,7 +52,7 @@ export const generateJob = (overrides: Partial = {}): JobEntity =>
chainId: 80002,
escrowAddress: faker.finance.ethereumAddress(),
jobType: JobRequestType.SOCIAL_MEDIA_PROMOTION,
- manifestUrl: faker.internet.url(),
+ manifest: faker.internet.url(),
endDate: faker.date.future(),
status: JobStatus.PENDING,
retriesCount: 0,
diff --git a/recording-oracle/src/modules/job/job-manifest.dto.ts b/recording-oracle/src/modules/job/job-manifest.dto.ts
index 9f28958..c0d6b5c 100644
--- a/recording-oracle/src/modules/job/job-manifest.dto.ts
+++ b/recording-oracle/src/modules/job/job-manifest.dto.ts
@@ -78,6 +78,24 @@ class SocialMediaPromotionRequirementsDto {
minReposts?: number;
}
+class XApiCredentialsDto {
+ @IsString()
+ @IsNotEmpty()
+ consumerKey!: string;
+
+ @IsString()
+ @IsNotEmpty()
+ consumerSecret!: string;
+
+ @IsString()
+ @IsNotEmpty()
+ accessToken!: string;
+
+ @IsString()
+ @IsNotEmpty()
+ accessTokenSecret!: string;
+}
+
class SocialMediaEngagementRequirementsDto {
@IsString()
@IsNotEmpty()
@@ -98,6 +116,11 @@ class SocialMediaEngagementRequirementsDto {
@IsOptional()
@IsBoolean()
checkComment?: boolean;
+
+ @ValidateNested()
+ @IsOptional()
+ @Type(() => XApiCredentialsDto)
+ xApiCredentials?: XApiCredentialsDto;
}
class ManifestAiValidationDto {
@@ -193,6 +216,7 @@ export function validateManifestDto(manifest: IManifest): IManifest {
) {
const requirements =
validatedManifest.requirements as ISocialMediaEngagementRequirements;
+ const platform = validatedManifest.platforms[0]?.toLowerCase();
const hasAnyEngagementCheck =
requirements.checkLike ||
requirements.checkRepost ||
@@ -205,15 +229,39 @@ export function validateManifestDto(manifest: IManifest): IManifest {
]);
}
- if (
- requirements.checkComment &&
- !requirements.checkLike &&
- !requirements.checkRepost &&
- !requirements.checkQuote
- ) {
- throw new ValidationError(ErrorJob.InvalidManifest, undefined, [
- 'checkComment requires checkLike, checkRepost, or checkQuote for social_media_engagement',
- ]);
+ if (platform === 'linkedin') {
+ if (requirements.checkRepost || requirements.checkQuote) {
+ throw new ValidationError(ErrorJob.InvalidManifest, undefined, [
+ 'LinkedIn engagement supports only checkLike and checkComment',
+ ]);
+ }
+
+ return validatedManifest as IManifest;
+ }
+
+ if (platform === 'x') {
+ if (
+ requirements.checkComment &&
+ !(requirements.checkLike && requirements.xApiCredentials) &&
+ !requirements.checkRepost &&
+ !requirements.checkQuote
+ ) {
+ throw new ValidationError(ErrorJob.InvalidManifest, undefined, [
+ 'checkComment requires checkRepost, checkQuote, or checkLike with xApiCredentials for social_media_engagement',
+ ]);
+ }
+
+ if (requirements.checkLike && !requirements.xApiCredentials) {
+ throw new ValidationError(ErrorJob.InvalidManifest, undefined, [
+ 'xApiCredentials must be provided when checkLike is enabled for social_media_engagement',
+ ]);
+ }
+
+ if (requirements.xApiCredentials && !requirements.checkLike) {
+ throw new ValidationError(ErrorJob.InvalidManifest, undefined, [
+ 'xApiCredentials can only be provided when checkLike is enabled for social_media_engagement',
+ ]);
+ }
}
}
diff --git a/recording-oracle/src/modules/job/job.entity.ts b/recording-oracle/src/modules/job/job.entity.ts
index bc7034d..471e7e4 100644
--- a/recording-oracle/src/modules/job/job.entity.ts
+++ b/recording-oracle/src/modules/job/job.entity.ts
@@ -21,7 +21,7 @@ export class JobEntity extends BaseEntity {
jobType: JobRequestType;
@Column({ type: 'varchar' })
- manifestUrl: string;
+ manifest: string;
@Column({ type: 'timestamptz' })
endDate: Date;
diff --git a/recording-oracle/src/modules/job/job.service.spec.ts b/recording-oracle/src/modules/job/job.service.spec.ts
index 388a15f..387b549 100644
--- a/recording-oracle/src/modules/job/job.service.spec.ts
+++ b/recording-oracle/src/modules/job/job.service.spec.ts
@@ -1,5 +1,7 @@
import {
ChainId,
+ Encryption,
+ EncryptionUtils,
EscrowClient,
EscrowStatus,
EscrowUtils,
@@ -8,6 +10,7 @@ import { faker } from '@faker-js/faker';
import { Test } from '@nestjs/testing';
import { ethers } from 'ethers';
+import { PGPConfigService } from '../../common/config/pgp-config.service';
import { Web3ConfigService } from '../../common/config/web3-config.service';
import { ErrorCommon, ErrorJob } from '../../common/constants/errors';
import { JobRequestType, JobStatus } from '../../common/enums/job';
@@ -34,6 +37,12 @@ jest.mock('@human-protocol/sdk', () => ({
EscrowUtils: {
getEscrow: jest.fn(),
},
+ Encryption: {
+ build: jest.fn(),
+ },
+ EncryptionUtils: {
+ isEncrypted: jest.fn(),
+ },
}));
describe('JobService', () => {
@@ -54,6 +63,7 @@ describe('JobService', () => {
beforeEach(async () => {
jest.clearAllMocks();
+ (EncryptionUtils.isEncrypted as jest.Mock).mockReturnValue(false);
const moduleRef = await Test.createTestingModule({
providers: [
@@ -92,6 +102,13 @@ describe('JobService', () => {
txTimeoutMs: 10_000,
},
},
+ {
+ provide: PGPConfigService,
+ useValue: {
+ privateKey: 'private-key',
+ passphrase: 'passphrase',
+ },
+ },
],
}).compile();
@@ -122,10 +139,10 @@ describe('JobService', () => {
});
it('creates a job from a valid escrow manifest', async () => {
- const manifestUrl = faker.internet.url();
+ const manifestSource = faker.internet.url();
const manifest = generateManifest();
const escrowClient = {
- getManifest: jest.fn().mockResolvedValue(manifestUrl),
+ getManifest: jest.fn().mockResolvedValue(manifestSource),
};
jobRepository.findOneByChainIdAndEscrowAddress.mockResolvedValue(null);
@@ -142,11 +159,34 @@ describe('JobService', () => {
chainId,
escrowAddress,
jobType: JobRequestType.SOCIAL_MEDIA_PROMOTION,
- manifestUrl,
+ manifest: manifestSource,
endDate: new Date(manifest.endDate),
}),
);
- expect(job.manifestUrl).toBe(manifestUrl);
+ expect(job.manifest).toBe(manifestSource);
+ });
+
+ it('creates a job from an inline escrow manifest', async () => {
+ const manifest = generateManifest();
+ const manifestSource = JSON.stringify(manifest);
+ const escrowClient = {
+ getManifest: jest.fn().mockResolvedValue(manifestSource),
+ };
+
+ jobRepository.findOneByChainIdAndEscrowAddress.mockResolvedValue(null);
+ (EscrowClient.build as jest.Mock).mockResolvedValue(escrowClient);
+ jobRepository.createUnique.mockImplementation(async (job) => job);
+
+ const job = await jobService.createJob(chainId, escrowAddress);
+
+ expect(storageService.download).not.toHaveBeenCalled();
+ expect(jobRepository.createUnique).toHaveBeenCalledWith(
+ expect.objectContaining({
+ manifest: manifestSource,
+ endDate: new Date(manifest.endDate),
+ }),
+ );
+ expect(job.manifest).toBe(manifestSource);
});
});
@@ -159,7 +199,9 @@ describe('JobService', () => {
jobRepository.findOneByChainIdAndEscrowAddress.mockResolvedValue(null);
(EscrowClient.build as jest.Mock).mockResolvedValue(escrowClient);
storageService.download.mockResolvedValue(
- generateManifest({ requestType: 'unsupported' as JobRequestType }),
+ generateManifest({
+ requestType: 'unsupported' as JobRequestType,
+ }),
);
await expect(
@@ -347,6 +389,19 @@ describe('JobService', () => {
);
});
+ it('loads and validates an inline manifest source', async () => {
+ const manifest = generateManifest();
+ const manifestSource = JSON.stringify(manifest);
+
+ await expect(jobService.getManifest(manifestSource)).resolves.toEqual(
+ expect.objectContaining({
+ requestType: JobRequestType.SOCIAL_MEDIA_PROMOTION,
+ submissionsRequired: manifest.submissionsRequired,
+ }),
+ );
+ expect(storageService.download).not.toHaveBeenCalled();
+ });
+
it('validates social media engagement manifests', async () => {
const manifest = generateManifest({
requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
@@ -355,6 +410,12 @@ describe('JobService', () => {
checkLike: true,
checkRepost: true,
checkComment: true,
+ xApiCredentials: {
+ consumerKey: 'consumer-key',
+ consumerSecret: 'consumer-secret',
+ accessToken: 'access-token',
+ accessTokenSecret: 'access-token-secret',
+ },
},
});
storageService.download.mockResolvedValue(manifest);
@@ -368,6 +429,91 @@ describe('JobService', () => {
);
});
+ it('validates like-only engagement manifests with X credentials', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: {
+ targetPostUrl: 'https://x.com/test/status/123',
+ checkLike: true,
+ xApiCredentials: {
+ consumerKey: 'consumer-key',
+ consumerSecret: 'consumer-secret',
+ accessToken: 'access-token',
+ accessTokenSecret: 'access-token-secret',
+ },
+ },
+ });
+ storageService.download.mockResolvedValue(manifest);
+
+ await expect(
+ jobService.getManifest(faker.internet.url()),
+ ).resolves.toEqual(
+ expect.objectContaining({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ }),
+ );
+ });
+
+ it('validates engagement manifests with X credentials', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: {
+ targetPostUrl: 'https://x.com/test/status/123',
+ checkLike: true,
+ xApiCredentials: {
+ consumerKey: 'consumer-key',
+ consumerSecret: 'consumer-secret',
+ accessToken: 'access-token',
+ accessTokenSecret: 'access-token-secret',
+ },
+ },
+ });
+ storageService.download.mockResolvedValue(manifest);
+
+ await expect(
+ jobService.getManifest(faker.internet.url()),
+ ).resolves.toEqual(
+ expect.objectContaining({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ }),
+ );
+ });
+
+ it('decrypts encrypted X API credentials before validating a manifest', async () => {
+ const encryptedCredentials =
+ '-----BEGIN PGP MESSAGE-----\ncredentials\n-----END PGP MESSAGE-----';
+ const credentials = {
+ consumerKey: 'consumer-key',
+ consumerSecret: 'consumer-secret',
+ accessToken: 'access-token',
+ accessTokenSecret: 'access-token-secret',
+ };
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: {
+ targetPostUrl: 'https://x.com/test/status/123',
+ checkLike: true,
+ xApiCredentials: encryptedCredentials as never,
+ },
+ });
+
+ (EncryptionUtils.isEncrypted as jest.Mock).mockReturnValue(true);
+ (Encryption.build as jest.Mock).mockResolvedValue({
+ decrypt: jest.fn().mockResolvedValue(JSON.stringify(credentials)),
+ });
+
+ await expect(
+ jobService.getManifest(JSON.stringify(manifest)),
+ ).resolves.toEqual(
+ expect.objectContaining({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: expect.objectContaining({
+ xApiCredentials: credentials,
+ }),
+ }),
+ );
+ });
+
it('validates quote-only social media engagement manifests', async () => {
const manifest = generateManifest({
requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
@@ -389,6 +535,28 @@ describe('JobService', () => {
}),
);
});
+
+ it('validates LinkedIn like and comment engagement manifests without X credentials', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['linkedin'],
+ requirements: {
+ targetPostUrl:
+ 'https://www.linkedin.com/feed/update/urn:li:activity:7353638537595932672/',
+ checkLike: true,
+ checkComment: true,
+ },
+ });
+ storageService.download.mockResolvedValue(manifest);
+
+ await expect(
+ jobService.getManifest(faker.internet.url()),
+ ).resolves.toEqual(
+ expect.objectContaining({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ }),
+ );
+ });
});
describe('fail', () => {
@@ -420,6 +588,77 @@ describe('JobService', () => {
jobService.getManifest(faker.internet.url()),
).rejects.toBeInstanceOf(ValidationError);
});
+
+ it('rejects LinkedIn engagement manifests that require reposts or quotes', async () => {
+ storageService.download.mockResolvedValue(
+ generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['linkedin'],
+ requirements: {
+ targetPostUrl:
+ 'https://www.linkedin.com/feed/update/urn:li:activity:7353638537595932672/',
+ checkRepost: true,
+ checkQuote: true,
+ },
+ }),
+ );
+
+ await expect(
+ jobService.getManifest(faker.internet.url()),
+ ).rejects.toThrow(ErrorJob.InvalidManifest);
+ });
+
+ it('rejects engagement manifests with partial X credentials', async () => {
+ storageService.download.mockResolvedValue(
+ generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: {
+ targetPostUrl: 'https://x.com/test/status/123',
+ checkLike: true,
+ xApiCredentials: {
+ consumerKey: 'consumer-key',
+ } as never,
+ },
+ }),
+ );
+
+ await expect(
+ jobService.getManifest(faker.internet.url()),
+ ).rejects.toBeInstanceOf(ValidationError);
+ });
+
+ it('rejects engagement manifests that check likes without X credentials', async () => {
+ storageService.download.mockResolvedValue(
+ generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: {
+ targetPostUrl: 'https://x.com/test/status/123',
+ checkLike: true,
+ },
+ }),
+ );
+
+ await expect(
+ jobService.getManifest(faker.internet.url()),
+ ).rejects.toBeInstanceOf(ValidationError);
+ });
+
+ it('rejects engagement manifests where comments depend only on skipped likes', async () => {
+ storageService.download.mockResolvedValue(
+ generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: {
+ targetPostUrl: 'https://x.com/test/status/123',
+ checkLike: true,
+ checkComment: true,
+ },
+ }),
+ );
+
+ await expect(
+ jobService.getManifest(faker.internet.url()),
+ ).rejects.toBeInstanceOf(ValidationError);
+ });
});
});
});
diff --git a/recording-oracle/src/modules/job/job.service.ts b/recording-oracle/src/modules/job/job.service.ts
index 62e03fa..502d02c 100644
--- a/recording-oracle/src/modules/job/job.service.ts
+++ b/recording-oracle/src/modules/job/job.service.ts
@@ -2,6 +2,7 @@ import { EscrowClient, EscrowStatus, EscrowUtils } from '@human-protocol/sdk';
import { Injectable } from '@nestjs/common';
import { ethers } from 'ethers';
+import { PGPConfigService } from '../../common/config/pgp-config.service';
import { Web3ConfigService } from '../../common/config/web3-config.service';
import { ErrorCommon, ErrorJob } from '../../common/constants/errors';
import { JobRequestType, JobStatus } from '../../common/enums/job';
@@ -9,6 +10,8 @@ import { VerificationResult } from '../../common/enums/submission';
import { EventType, WebhookStatus } from '../../common/enums/webhook';
import { ConflictError, ValidationError } from '../../common/errors';
import { IManifest, IRecordingResult } from '../../common/interfaces/job';
+import { parseManifestContent } from '../../common/utils/manifest';
+import { isValidUrl } from '../../common/utils/storage';
import { StorageService } from '../../modules/storage/storage.service';
import { Web3Service } from '../../modules/web3/web3.service';
import { WebhookDto } from '../../modules/webhook/webhook.dto';
@@ -27,6 +30,7 @@ export class JobService {
private readonly web3Service: Web3Service,
private readonly storageService: StorageService,
private readonly web3ConfigService: Web3ConfigService,
+ private readonly pgpConfigService: PGPConfigService,
) {}
async createJob(chainId: number, escrowAddress: string): Promise {
@@ -41,8 +45,8 @@ export class JobService {
const signer = this.web3Service.getSigner(chainId);
const escrowClient = await EscrowClient.build(signer);
- const manifestUrl = await escrowClient.getManifest(escrowAddress);
- const manifest = await this.getManifest(manifestUrl);
+ const manifestSource = await escrowClient.getManifest(escrowAddress);
+ const manifest = await this.getManifest(manifestSource);
if (!Object.values(JobRequestType).includes(manifest.requestType)) {
throw new ValidationError(ErrorJob.InvalidJobType);
@@ -52,7 +56,7 @@ export class JobService {
job.chainId = chainId;
job.escrowAddress = escrowAddress;
job.jobType = manifest.requestType;
- job.manifestUrl = manifestUrl;
+ job.manifest = manifestSource;
job.endDate = new Date(manifest.endDate);
return await this.jobRepository.createUnique(job);
@@ -177,9 +181,15 @@ export class JobService {
return 'Job canceled successfully.';
}
- async getManifest(manifestUrl: string): Promise {
- return validateManifestDto(
- (await this.storageService.download(manifestUrl)) as IManifest,
+ async getManifest(manifestSource: string): Promise {
+ const manifestContent = isValidUrl(manifestSource)
+ ? await this.storageService.download(manifestSource)
+ : manifestSource;
+ const manifest = await parseManifestContent(
+ manifestContent,
+ this.pgpConfigService,
);
+
+ return validateManifestDto(manifest as IManifest);
}
}
diff --git a/recording-oracle/src/modules/storage/storage.service.spec.ts b/recording-oracle/src/modules/storage/storage.service.spec.ts
index dc1dd59..37f86ed 100644
--- a/recording-oracle/src/modules/storage/storage.service.spec.ts
+++ b/recording-oracle/src/modules/storage/storage.service.spec.ts
@@ -1,6 +1,5 @@
import {
ChainId,
- Encryption,
EncryptionUtils,
EscrowClient,
KVStoreUtils,
@@ -9,11 +8,7 @@ import { faker } from '@faker-js/faker';
import { ConfigService } from '@nestjs/config';
import { Test } from '@nestjs/testing';
import { VerificationResult } from '../../common/enums/submission';
-import {
- MOCK_ADDRESS,
- MOCK_FILE_URL,
- mockConfig,
-} from '../../../test/constants';
+import { MOCK_ADDRESS, mockConfig } from '../../../test/constants';
import { PGPConfigService } from '../../common/config/pgp-config.service';
import { S3ConfigService } from '../../common/config/s3-config.service';
import { generateRecordingResult } from '../job/fixtures';
@@ -226,11 +221,17 @@ describe('StorageService', () => {
describe('download', () => {
const downloadFileFromUrlMock = jest.mocked(downloadFileFromUrl);
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
describe('succeed', () => {
it('should download the non encrypted file correctly', async () => {
const exchangeAddress = faker.finance.ethereumAddress();
const workerAddress = faker.finance.ethereumAddress();
const postUrl = generatePostUrl();
+ const fileUrl = faker.internet.url();
const expectedJobFile = {
exchangeAddress,
@@ -243,42 +244,17 @@ describe('StorageService', () => {
};
downloadFileFromUrlMock.mockResolvedValue(expectedJobFile);
- EncryptionUtils.isEncrypted = jest.fn().mockReturnValue(false);
- const solutionsFile = await storageService.download(MOCK_FILE_URL);
- expect(solutionsFile).toStrictEqual(expectedJobFile);
- });
-
- it('should download the encrypted file correctly', async () => {
- const exchangeAddress = faker.finance.ethereumAddress();
- const workerAddress = faker.finance.ethereumAddress();
- const postUrl = generatePostUrl();
-
- const expectedJobFile = {
- exchangeAddress,
- solutions: [
- {
- workerAddress,
- solution: postUrl,
- },
- ],
- };
-
- downloadFileFromUrlMock.mockResolvedValue('encrypted-content');
-
- Encryption.build = jest.fn().mockResolvedValue({
- decrypt: jest.fn().mockResolvedValue(JSON.stringify(expectedJobFile)),
- });
- EncryptionUtils.isEncrypted = jest.fn().mockReturnValue(true);
- const solutionsFile = await storageService.download(MOCK_FILE_URL);
+ const solutionsFile = await storageService.download(fileUrl);
expect(solutionsFile).toStrictEqual(expectedJobFile);
});
});
describe('fail', () => {
it('should return empty array when file cannot be downloaded', async () => {
+ const fileUrl = faker.internet.url();
downloadFileFromUrlMock.mockRejectedValue('Network error');
- const solutionsFile = await storageService.download(MOCK_FILE_URL);
+ const solutionsFile = await storageService.download(fileUrl);
expect(solutionsFile).toStrictEqual([]);
});
});
diff --git a/recording-oracle/src/modules/storage/storage.service.ts b/recording-oracle/src/modules/storage/storage.service.ts
index 2d0dea3..e946dc8 100644
--- a/recording-oracle/src/modules/storage/storage.service.ts
+++ b/recording-oracle/src/modules/storage/storage.service.ts
@@ -1,6 +1,5 @@
import {
ChainId,
- Encryption,
EncryptionUtils,
EscrowClient,
KVStoreUtils,
@@ -13,9 +12,9 @@ import { PGPConfigService } from '../../common/config/pgp-config.service';
import { S3ConfigService } from '../../common/config/s3-config.service';
import { ServerError, ValidationError } from '../../common/errors';
import { IRecordingResult } from '../../common/interfaces/job';
+import { downloadFileFromUrl } from '../../common/utils/storage';
import { SaveSolutionsDto } from '../submission/submission.dto';
import { Web3Service } from '../web3/web3.service';
-import { downloadFileFromUrl } from '../../common/utils/storage';
@Injectable()
export class StorageService {
@@ -43,36 +42,7 @@ export class StorageService {
public async download(url: string): Promise {
try {
- const fileContent = await downloadFileFromUrl(url);
-
- if (
- typeof fileContent === 'string' &&
- EncryptionUtils.isEncrypted(fileContent)
- ) {
- try {
- const privateKey = this.pgpConfigService.privateKey;
- if (!privateKey) {
- throw new ServerError(ErrorStorage.UnableDecryptManifest);
- }
- const encryption = await Encryption.build(
- privateKey,
- this.pgpConfigService.passphrase,
- );
-
- const decryptedData = await encryption.decrypt(fileContent);
- return JSON.parse(Buffer.from(decryptedData).toString());
- } catch {
- throw new ServerError(ErrorStorage.UnableDecryptManifest);
- }
- } else {
- try {
- return typeof fileContent === 'string'
- ? JSON.parse(fileContent)
- : fileContent;
- } catch {
- return null;
- }
- }
+ return await downloadFileFromUrl(url);
} catch {
return [];
}
diff --git a/recording-oracle/src/modules/submission/submission.constants.ts b/recording-oracle/src/modules/submission/submission.constants.ts
index 34472f9..009e348 100644
--- a/recording-oracle/src/modules/submission/submission.constants.ts
+++ b/recording-oracle/src/modules/submission/submission.constants.ts
@@ -2,12 +2,56 @@ import { SubmissionRejectionReason } from '../../common/constants/errors';
import { AbuseProbability } from '../../common/interfaces/job';
import { SubmissionValidationRule } from './submission.dto';
+export type SocialProfileNormalizer = {
+ normalize: (profile: string) => string | null;
+ isValid: (profile: string) => boolean;
+};
+
export const ABUSE_PRIORITY: Record = {
low: 1,
medium: 2,
high: 3,
};
+export const SOCIAL_PROFILE_NORMALIZERS: SocialProfileNormalizer[] = [
+ {
+ normalize: (profile: string): string | null =>
+ profile.trim().replace(/^@/, '').toLowerCase(),
+ isValid: (profile: string): boolean => /^[a-z0-9_]{1,15}$/.test(profile),
+ },
+ {
+ normalize: (profile: string): string | null => {
+ const trimmedProfile = profile.trim().replace(/^@/, '');
+
+ try {
+ const parsedUrl = new URL(trimmedProfile);
+ const path = parsedUrl.pathname.replace(/\/+$/, '');
+ const match = path.match(/^\/in\/([^/]+)$/i);
+
+ if (
+ parsedUrl.protocol === 'https:' &&
+ parsedUrl.hostname.endsWith('linkedin.com') &&
+ match
+ ) {
+ return match[1].toLowerCase();
+ }
+ } catch {
+ return trimmedProfile.toLowerCase();
+ }
+
+ return null;
+ },
+ isValid: (profile: string): boolean =>
+ /^[a-z0-9](?:[a-z0-9._-]{0,98}[a-z0-9])?$/.test(profile),
+ },
+ {
+ normalize: (profile: string): string | null =>
+ profile.trim().replace(/\s+/g, ' ').toLowerCase(),
+ isValid: (profile: string): boolean =>
+ /^[\p{L}\p{N}](?:[\p{L}\p{N} .'-]{0,98}[\p{L}\p{N}])$/u.test(profile),
+ },
+];
+
export const SUBMISSION_VALIDATION_RULES: SubmissionValidationRule[] = [
{
isValid: (validation) => validation.postExists,
diff --git a/recording-oracle/src/modules/submission/submission.service.spec.ts b/recording-oracle/src/modules/submission/submission.service.spec.ts
index ca76b72..d0dfdd6 100644
--- a/recording-oracle/src/modules/submission/submission.service.spec.ts
+++ b/recording-oracle/src/modules/submission/submission.service.spec.ts
@@ -125,6 +125,94 @@ describe('SubmissionService', () => {
}),
);
});
+
+ it('creates an engagement submission with a normalized LinkedIn profile URL', async () => {
+ jobService.createJob.mockResolvedValue(
+ generateJob({ jobType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT }),
+ );
+
+ await expect(
+ submissionService.createSubmission({
+ ...webhook,
+ eventData: {
+ assigneeId: workerAddress,
+ solution: 'https://www.linkedin.com/in/Human-Protocol/',
+ },
+ }),
+ ).resolves.toBe('Submission received.');
+
+ expect(submissionRepository.createUnique).toHaveBeenCalledWith(
+ expect.objectContaining({
+ solution: 'human-protocol',
+ }),
+ );
+ });
+
+ it('creates an engagement submission with a normalized LinkedIn profile URL containing periods', async () => {
+ jobService.createJob.mockResolvedValue(
+ generateJob({ jobType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT }),
+ );
+
+ await expect(
+ submissionService.createSubmission({
+ ...webhook,
+ eventData: {
+ assigneeId: workerAddress,
+ solution: 'https://www.linkedin.com/in/Human.Protocol/',
+ },
+ }),
+ ).resolves.toBe('Submission received.');
+
+ expect(submissionRepository.createUnique).toHaveBeenCalledWith(
+ expect.objectContaining({
+ solution: 'human.protocol',
+ }),
+ );
+ });
+
+ it('creates an engagement submission with a normalized LinkedIn profile slug', async () => {
+ jobService.createJob.mockResolvedValue(
+ generateJob({ jobType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT }),
+ );
+
+ await expect(
+ submissionService.createSubmission({
+ ...webhook,
+ eventData: {
+ assigneeId: workerAddress,
+ solution: 'Human.Protocol',
+ },
+ }),
+ ).resolves.toBe('Submission received.');
+
+ expect(submissionRepository.createUnique).toHaveBeenCalledWith(
+ expect.objectContaining({
+ solution: 'human.protocol',
+ }),
+ );
+ });
+
+ it('creates an engagement submission with a normalized LinkedIn display name', async () => {
+ jobService.createJob.mockResolvedValue(
+ generateJob({ jobType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT }),
+ );
+
+ await expect(
+ submissionService.createSubmission({
+ ...webhook,
+ eventData: {
+ assigneeId: workerAddress,
+ solution: 'Oriol Blanch',
+ },
+ }),
+ ).resolves.toBe('Submission received.');
+
+ expect(submissionRepository.createUnique).toHaveBeenCalledWith(
+ expect.objectContaining({
+ solution: 'oriol blanch',
+ }),
+ );
+ });
});
describe('fail', () => {
@@ -154,6 +242,24 @@ describe('SubmissionService', () => {
expect(submissionRepository.createUnique).not.toHaveBeenCalled();
});
+
+ it('rejects invalid engagement submissions with a social profile message', async () => {
+ jobService.createJob.mockResolvedValue(
+ generateJob({ jobType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT }),
+ );
+
+ await expect(
+ submissionService.createSubmission({
+ ...webhook,
+ eventData: {
+ assigneeId: workerAddress,
+ solution: 'not @ valid profile!',
+ },
+ }),
+ ).rejects.toThrow(ErrorJob.InvalidSocialProfile);
+
+ expect(submissionRepository.createUnique).not.toHaveBeenCalled();
+ });
});
});
diff --git a/recording-oracle/src/modules/submission/submission.service.ts b/recording-oracle/src/modules/submission/submission.service.ts
index 4c4e133..4d801dc 100644
--- a/recording-oracle/src/modules/submission/submission.service.ts
+++ b/recording-oracle/src/modules/submission/submission.service.ts
@@ -26,6 +26,7 @@ import {
WebhookDto,
} from '../../modules/webhook/webhook.dto';
+import { SOCIAL_PROFILE_NORMALIZERS } from './submission.constants';
import { SubmissionEntity } from './submission.entity';
import { SubmissionRepository } from './submission.repository';
@@ -128,7 +129,7 @@ export class SubmissionService {
): Promise {
const normalizedSolution =
jobType === JobRequestType.SOCIAL_MEDIA_ENGAGEMENT
- ? this.validateXUsername(solution)
+ ? this.validateSocialProfile(solution)
: this.validatePostUrl(solution);
const existingSubmission =
await this.submissionRepository.findOneByJobIdAndWorkerAddress(
@@ -183,13 +184,15 @@ export class SubmissionService {
return parsedUrl.toString();
}
- private validateXUsername(username: string): string {
- const normalizedUsername = username.trim().replace(/^@/, '').toLowerCase();
- if (!/^[a-z0-9_]{1,15}$/.test(normalizedUsername)) {
- throw new ValidationError(ErrorJob.InvalidXUsername);
+ private validateSocialProfile(profile: string): string {
+ for (const normalizer of SOCIAL_PROFILE_NORMALIZERS) {
+ const normalizedProfile = normalizer.normalize(profile);
+ if (normalizedProfile && normalizer.isValid(normalizedProfile)) {
+ return normalizedProfile;
+ }
}
- return normalizedUsername;
+ throw new ValidationError(ErrorJob.InvalidSocialProfile);
}
private async recordValidationResult(
diff --git a/recording-oracle/src/modules/validation/linkdapi/linkdapi.interfaces.ts b/recording-oracle/src/modules/validation/linkdapi/linkdapi.interfaces.ts
new file mode 100644
index 0000000..617e452
--- /dev/null
+++ b/recording-oracle/src/modules/validation/linkdapi/linkdapi.interfaces.ts
@@ -0,0 +1,86 @@
+export type LinkdapiErrorResponse = {
+ success?: boolean;
+ message?: string;
+ error?: string | { message?: string };
+ detail?: string;
+};
+
+export type LinkdapiResponse = LinkdapiErrorResponse & {
+ data?: T;
+};
+
+export type LinkdapiProfile = {
+ id?: string;
+ urn?: string;
+ entityUrn?: string;
+ profileUrn?: string;
+ username?: string;
+ publicIdentifier?: string;
+ public_identifier?: string;
+ url?: string;
+ profileUrl?: string;
+ profileURL?: string;
+ name?: string;
+ fullName?: string;
+ full_name?: string;
+ firstName?: string;
+ first_name?: string;
+ lastName?: string;
+ last_name?: string;
+};
+
+export type LinkdapiEngagementItem = LinkdapiProfile & {
+ author?: LinkdapiProfile;
+ actor?: LinkdapiProfile;
+ profile?: LinkdapiProfile;
+ user?: LinkdapiProfile;
+ commenter?: LinkdapiProfile;
+ creator?: LinkdapiProfile;
+ member?: LinkdapiProfile;
+ header?: string;
+ url?: string;
+};
+
+export type LinkdapiPagination = {
+ cursor?: string;
+ nextCursor?: string;
+ next_cursor?: string;
+};
+
+export type LinkdapiPaginatedData = {
+ cursor?: string;
+ nextCursor?: string;
+ next_cursor?: string;
+ pagination?: LinkdapiPagination;
+ currentPage?: number;
+ pages?: number;
+};
+
+export type LinkdapiPostLikesData = LinkdapiPaginatedData & {
+ likes?: LinkdapiEngagementItem[];
+};
+
+export type LinkdapiPostCommentsData = LinkdapiPaginatedData & {
+ comments?: LinkdapiEngagementItem[];
+};
+
+export type LinkdapiPageRequest = {
+ start: number;
+ cursor: string;
+};
+
+export type LinkdapiPaginatedRequest = (
+ page: LinkdapiPageRequest,
+) => Promise>;
+
+export type LinkdapiPaginatedRequestOptions<
+ T extends LinkdapiPaginatedData,
+ TItem,
+> = {
+ operationName: string;
+ pageSize: number;
+ useCursor: boolean;
+ request: LinkdapiPaginatedRequest;
+ selectItems: (data: T) => TItem[];
+ shouldStop?: (items: TItem[]) => boolean;
+};
diff --git a/recording-oracle/src/modules/validation/linkdapi/linkdapi.service.spec.ts b/recording-oracle/src/modules/validation/linkdapi/linkdapi.service.spec.ts
new file mode 100644
index 0000000..9c8c20c
--- /dev/null
+++ b/recording-oracle/src/modules/validation/linkdapi/linkdapi.service.spec.ts
@@ -0,0 +1,399 @@
+import { Test } from '@nestjs/testing';
+
+import { LinkdapiConfigService } from '../../../common/config/linkdapi-config.service';
+import {
+ ErrorJob,
+ SubmissionRejectionReason,
+} from '../../../common/constants/errors';
+import { JobRequestType } from '../../../common/enums/job';
+import { ISocialMediaEngagementManifest } from '../../../common/interfaces/job';
+import { generateManifest } from '../../job/fixtures';
+import { generateSubmission } from '../../submission/fixtures';
+import { LinkdapiService } from './linkdapi.service';
+
+type LinkdapiConfigServiceMock = {
+ apiKey?: string;
+ baseUrl: string;
+ pageSize: number;
+ maxPagesPerAction: number;
+};
+
+describe('LinkdapiService', () => {
+ let service: LinkdapiService;
+ let fetchMock: jest.Mock;
+ let linkdapiConfigService: LinkdapiConfigServiceMock;
+
+ beforeEach(async () => {
+ fetchMock = jest.fn();
+ global.fetch = fetchMock;
+ linkdapiConfigService = {
+ apiKey: 'linkdapi-key',
+ baseUrl: 'https://linkdapi.com',
+ pageSize: 100,
+ maxPagesPerAction: 3,
+ };
+
+ const moduleRef = await Test.createTestingModule({
+ providers: [
+ LinkdapiService,
+ {
+ provide: LinkdapiConfigService,
+ useValue: linkdapiConfigService,
+ },
+ ],
+ }).compile();
+
+ service = moduleRef.get(LinkdapiService);
+ });
+
+ it('paginates liking users and matches LinkedIn profile slugs case-insensitively', async () => {
+ mockLinkdapiResponse({
+ data: {
+ likes: [
+ {
+ profile: {
+ profileUrl: 'https://www.linkedin.com/in/Alice-Builder/',
+ },
+ },
+ ...Array.from({ length: 9 }, () => ({
+ profile: { publicIdentifier: 'someone-else' },
+ })),
+ ],
+ },
+ });
+ mockLinkdapiResponse({
+ data: {
+ likes: [{ profile: { publicIdentifier: 'bob-builder' } }],
+ },
+ });
+
+ const result = await service.getLikingUsers(
+ '7353638537595932672',
+ new Set(['alice-builder', 'bob-builder']),
+ );
+
+ expect(result).toEqual(new Set(['alice-builder', 'bob-builder']));
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(fetchMock.mock.calls[0][0].toString()).toContain(
+ '/api/v1/posts/likes',
+ );
+ expect(fetchMock.mock.calls[1][0].toString()).toContain('start=10');
+ expect(fetchMock.mock.calls[0][1].headers['X-linkdapi-apikey']).toBe(
+ 'linkdapi-key',
+ );
+ });
+
+ it('stops paginating likes when LinkdAPI returns the final page', async () => {
+ mockLinkdapiResponse({
+ data: {
+ currentPage: 1,
+ pages: 1,
+ likes: Array.from({ length: 10 }, () => ({
+ actor: { publicIdentifier: 'bob-builder' },
+ })),
+ },
+ });
+
+ const result = await service.getLikingUsers(
+ '7353638537595932672',
+ new Set(['alice-builder']),
+ );
+
+ expect(result).toEqual(new Set());
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ });
+
+ it('matches LinkedIn display names with and without spaces', async () => {
+ mockLinkdapiResponse({
+ data: {
+ likes: [
+ {
+ actor: {
+ name: 'Oriol Blanch',
+ url: 'https://www.linkedin.com/in/ACoAACEE-_0BbIdm6ZyR4TaauGijdThxUHYtUys',
+ },
+ },
+ ],
+ },
+ });
+
+ const result = await service.getLikingUsers(
+ '7353638537595932672',
+ new Set(['oriol blanch', 'oriolblanch']),
+ );
+
+ expect(result).toEqual(new Set(['oriol blanch']));
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ });
+
+ it('validates a LinkedIn submission using a display name without spaces', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['linkedin'],
+ requirements: {
+ targetPostUrl:
+ 'https://www.linkedin.com/feed/update/urn:li:activity:7353638537595932672/',
+ checkLike: true,
+ },
+ }) as ISocialMediaEngagementManifest;
+ const submission = generateSubmission({ solution: 'OriolBlanch' });
+
+ mockLinkdapiResponse({
+ data: {
+ likes: [{ actor: { name: 'Oriol Blanch' } }],
+ },
+ });
+
+ await expect(
+ service.validateSubmissions([submission], manifest),
+ ).resolves.toEqual([
+ {
+ submission,
+ rejectionReason: null,
+ },
+ ]);
+ });
+
+ it('validates LinkedIn engagement submissions with likes and comments', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['linkedin'],
+ requirements: {
+ targetPostUrl:
+ 'https://www.linkedin.com/feed/update/urn:li:activity:7353638537595932672/',
+ checkLike: true,
+ checkComment: true,
+ },
+ }) as ISocialMediaEngagementManifest;
+ const submissions = [
+ generateSubmission({
+ id: 1,
+ solution: 'https://www.linkedin.com/in/alice-builder/',
+ }),
+ generateSubmission({ id: 2, solution: 'bob-builder' }),
+ ];
+
+ jest
+ .spyOn(service, 'getLikingUsers')
+ .mockResolvedValue(new Set(['alice-builder', 'bob-builder']));
+ jest
+ .spyOn(service, 'getCommentingUsers')
+ .mockResolvedValue(new Set(['alice-builder']));
+
+ await expect(
+ service.validateSubmissions(submissions, manifest),
+ ).resolves.toEqual([
+ {
+ submission: submissions[0],
+ rejectionReason: null,
+ },
+ {
+ submission: submissions[1],
+ rejectionReason: SubmissionRejectionReason.MissingRequiredComment,
+ },
+ ]);
+
+ expect(service.getLikingUsers).toHaveBeenCalledWith(
+ '7353638537595932672',
+ new Set(['alice-builder', 'bob-builder']),
+ );
+ expect(service.getCommentingUsers).toHaveBeenCalledWith(
+ '7353638537595932672',
+ new Set(['alice-builder', 'bob-builder']),
+ );
+ });
+
+ it('requests LinkedIn comments with the configured page size', async () => {
+ mockLinkdapiResponse({
+ data: {
+ comments: [{ commenter: { publicIdentifier: 'alice-builder' } }],
+ },
+ });
+
+ const result = await service.getCommentingUsers(
+ '7353638537595932672',
+ new Set(['alice-builder']),
+ );
+
+ expect(result).toEqual(new Set(['alice-builder']));
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+
+ const requestUrl = new URL(fetchMock.mock.calls[0][0] as string);
+ expect(requestUrl.pathname).toBe('/api/v1/posts/comments');
+ expect(requestUrl.searchParams.get('urn')).toBe('7353638537595932672');
+ expect(requestUrl.searchParams.get('start')).toBe('0');
+ expect(requestUrl.searchParams.get('count')).toBe('100');
+ expect(requestUrl.searchParams.has('sortBy')).toBe(false);
+ expect(fetchMock.mock.calls[0][1].headers['X-linkdapi-apikey']).toBe(
+ 'linkdapi-key',
+ );
+ });
+
+ it('stops paginating LinkedIn comments when the page is shorter than the configured page size', async () => {
+ mockLinkdapiResponse({
+ data: {
+ comments: [{ commenter: { publicIdentifier: 'bob-builder' } }],
+ },
+ });
+
+ const result = await service.getCommentingUsers(
+ '7353638537595932672',
+ new Set(['alice-builder']),
+ );
+
+ expect(result).toEqual(new Set());
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ });
+
+ it('paginates full LinkedIn comment pages by the configured page size', async () => {
+ mockLinkdapiResponse({
+ data: {
+ comments: Array.from({ length: 100 }, () => ({
+ commenter: { publicIdentifier: 'bob-builder' },
+ })),
+ },
+ });
+ mockLinkdapiResponse({
+ data: {
+ comments: [{ commenter: { publicIdentifier: 'alice-builder' } }],
+ },
+ });
+
+ const result = await service.getCommentingUsers(
+ '7353638537595932672',
+ new Set(['alice-builder']),
+ );
+
+ expect(result).toEqual(new Set(['alice-builder']));
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+
+ const secondRequestUrl = new URL(fetchMock.mock.calls[1][0] as string);
+ expect(secondRequestUrl.searchParams.get('start')).toBe('100');
+ });
+
+ it('treats later body-level LinkdAPI failures as the end of engagement results', async () => {
+ mockLinkdapiResponse({
+ data: {
+ likes: Array.from({ length: 10 }, () => ({
+ actor: { publicIdentifier: 'bob-builder' },
+ })),
+ },
+ });
+ mockLinkdapiResponse({
+ success: false,
+ message: "the data cannot be displayed or it doesn't exist",
+ });
+
+ const result = await service.getLikingUsers(
+ '7353638537595932672',
+ new Set(['alice-builder']),
+ );
+
+ expect(result).toEqual(new Set());
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ });
+
+ it('treats later paginated 404 responses as the end of LinkedIn engagement results', async () => {
+ mockLinkdapiResponse({
+ data: {
+ comments: Array.from({ length: 100 }, () => ({
+ commenter: { publicIdentifier: 'bob-builder' },
+ })),
+ },
+ });
+ fetchMock.mockResolvedValueOnce({
+ ok: false,
+ status: 404,
+ statusText: 'Not Found',
+ text: jest.fn().mockResolvedValue(JSON.stringify({ message: 'missing' })),
+ });
+
+ const result = await service.getCommentingUsers(
+ '7353638537595932672',
+ new Set(['alice-builder']),
+ );
+
+ expect(result).toEqual(new Set());
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ });
+
+ it('rejects unsupported LinkedIn repost and quote checks', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['linkedin'],
+ requirements: {
+ targetPostUrl:
+ 'https://www.linkedin.com/feed/update/urn:li:activity:7353638537595932672/',
+ checkRepost: true,
+ checkQuote: true,
+ },
+ }) as ISocialMediaEngagementManifest;
+
+ await expect(
+ service.validateSubmissions(
+ [generateSubmission({ solution: 'alice-builder' })],
+ manifest,
+ ),
+ ).rejects.toThrow(ErrorJob.InvalidManifest);
+
+ expect(fetchMock).not.toHaveBeenCalled();
+ });
+
+ it('returns target post rejection when the LinkedIn post URN cannot be extracted', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['linkedin'],
+ requirements: {
+ targetPostUrl: 'https://www.linkedin.com/posts/no-post-id',
+ checkLike: true,
+ },
+ }) as ISocialMediaEngagementManifest;
+ const submissions = [generateSubmission({ solution: 'alice-builder' })];
+
+ await expect(
+ service.validateSubmissions(submissions, manifest),
+ ).resolves.toEqual([
+ {
+ submission: submissions[0],
+ rejectionReason: SubmissionRejectionReason.TargetPostNotFound,
+ },
+ ]);
+ });
+
+ it('throws a clear server error when LinkdAPI credentials are missing', async () => {
+ const serviceWithoutApiKey = new LinkdapiService({
+ ...linkdapiConfigService,
+ apiKey: undefined,
+ } as LinkdapiConfigService);
+
+ await expect(
+ serviceWithoutApiKey.getLikingUsers(
+ '7353638537595932672',
+ new Set(['alice']),
+ ),
+ ).rejects.toThrow(
+ 'LinkdAPI config is required to process LinkedIn social_media_engagement jobs',
+ );
+ expect(fetchMock).not.toHaveBeenCalled();
+ });
+
+ it('maps 404 LinkdAPI responses to target post not found', async () => {
+ fetchMock.mockResolvedValueOnce({
+ ok: false,
+ status: 404,
+ statusText: 'Not Found',
+ text: jest.fn().mockResolvedValue(JSON.stringify({ message: 'missing' })),
+ });
+
+ await expect(
+ service.getLikingUsers('7353638537595932672', new Set(['alice'])),
+ ).rejects.toThrow(SubmissionRejectionReason.TargetPostNotFound);
+ });
+
+ function mockLinkdapiResponse(payload: unknown): void {
+ fetchMock.mockResolvedValueOnce({
+ ok: true,
+ json: jest.fn().mockResolvedValue(payload),
+ });
+ }
+});
diff --git a/recording-oracle/src/modules/validation/linkdapi/linkdapi.service.ts b/recording-oracle/src/modules/validation/linkdapi/linkdapi.service.ts
new file mode 100644
index 0000000..536cafd
--- /dev/null
+++ b/recording-oracle/src/modules/validation/linkdapi/linkdapi.service.ts
@@ -0,0 +1,430 @@
+import { Injectable } from '@nestjs/common';
+import { HTTPError, LinkdAPI, LinkdAPIError } from 'linkdapi';
+
+import { LinkdapiConfigService } from '../../../common/config/linkdapi-config.service';
+import {
+ ErrorJob,
+ SubmissionRejectionReason,
+} from '../../../common/constants/errors';
+import { ServerError, ValidationError } from '../../../common/errors';
+import { ISocialMediaEngagementManifest } from '../../../common/interfaces/job';
+import { SubmissionEntity } from '../../submission/submission.entity';
+import type { SubmissionValidationResult } from '../validation.service';
+import {
+ LinkdapiEngagementItem,
+ LinkdapiPaginatedData,
+ LinkdapiPaginatedRequestOptions,
+ LinkdapiPostCommentsData,
+ LinkdapiPostLikesData,
+ LinkdapiResponse,
+} from './linkdapi.interfaces';
+
+@Injectable()
+export class LinkdapiService {
+ private readonly api?: LinkdAPI;
+
+ constructor(private readonly linkdapiConfigService: LinkdapiConfigService) {
+ const apiKey = this.linkdapiConfigService.apiKey;
+
+ if (apiKey) {
+ this.api = new LinkdAPI({
+ apiKey,
+ baseUrl: this.linkdapiConfigService.baseUrl,
+ });
+ }
+ }
+
+ async validateSubmissions(
+ submissions: SubmissionEntity[],
+ manifest: ISocialMediaEngagementManifest,
+ ): Promise {
+ if (manifest.requirements.checkRepost || manifest.requirements.checkQuote) {
+ throw new ValidationError(ErrorJob.InvalidManifest, undefined, [
+ 'LinkedIn engagement supports only checkLike and checkComment',
+ ]);
+ }
+
+ const targetPostUrn = this.extractPostUrn(
+ manifest.requirements.targetPostUrl,
+ );
+ if (!targetPostUrn) {
+ return this.rejectSubmissions(
+ submissions,
+ SubmissionRejectionReason.TargetPostNotFound,
+ );
+ }
+
+ const targetUsers = new Set(
+ submissions.flatMap((submission) =>
+ this.getProfileMatchKeys(submission.solution),
+ ),
+ );
+ const matches = {
+ likingUsers: new Set(),
+ commentingUsers: new Set(),
+ };
+ let candidates = new Set(targetUsers);
+
+ try {
+ if (manifest.requirements.checkLike) {
+ matches.likingUsers = await this.getLikingUsers(
+ targetPostUrn,
+ candidates,
+ );
+ candidates = new Set(
+ [...candidates].filter((user) => matches.likingUsers.has(user)),
+ );
+ }
+
+ if (manifest.requirements.checkComment && candidates.size > 0) {
+ matches.commentingUsers = await this.getCommentingUsers(
+ targetPostUrn,
+ candidates,
+ );
+ }
+
+ return submissions.map((submission) => {
+ const userKeys = this.getProfileMatchKeys(submission.solution);
+ let rejectionReason: SubmissionRejectionReason | null = null;
+
+ if (
+ manifest.requirements.checkLike &&
+ !userKeys.some((user) => matches.likingUsers.has(user))
+ ) {
+ rejectionReason = SubmissionRejectionReason.MissingRequiredLike;
+ } else if (
+ manifest.requirements.checkComment &&
+ !userKeys.some((user) => matches.commentingUsers.has(user))
+ ) {
+ rejectionReason = SubmissionRejectionReason.MissingRequiredComment;
+ }
+
+ return {
+ submission,
+ rejectionReason,
+ };
+ });
+ } catch (error) {
+ if (
+ error instanceof ValidationError &&
+ error.message === SubmissionRejectionReason.TargetPostNotFound
+ ) {
+ return this.rejectSubmissions(
+ submissions,
+ SubmissionRejectionReason.TargetPostNotFound,
+ );
+ }
+
+ throw error;
+ }
+ }
+
+ async getLikingUsers(
+ postUrn: string,
+ targetUsers: Set,
+ ): Promise> {
+ if (targetUsers.size === 0) {
+ return new Set();
+ }
+
+ const api = this.ensureApi();
+
+ const items = await this.requestPaginatedData({
+ operationName: 'getPostLikes',
+ pageSize: 10,
+ useCursor: false,
+ request: ({ start }) =>
+ api.getPostLikes(postUrn, start) as Promise<
+ LinkdapiResponse
+ >,
+ selectItems: (data) => data.likes ?? [],
+ shouldStop: (items) => this.hasAllTargetUsers(items, targetUsers),
+ });
+
+ return this.getMatchingUsers(items, targetUsers);
+ }
+
+ async getCommentingUsers(
+ postUrn: string,
+ targetUsers: Set,
+ ): Promise> {
+ if (targetUsers.size === 0) {
+ return new Set();
+ }
+
+ const api = this.ensureApi();
+
+ const items = await this.requestPaginatedData({
+ operationName: 'getPostComments',
+ pageSize: this.linkdapiConfigService.pageSize,
+ useCursor: true,
+ request: ({ start, cursor }) =>
+ api.getPostComments(
+ postUrn,
+ start,
+ this.linkdapiConfigService.pageSize,
+ cursor,
+ ) as Promise>,
+ selectItems: (data) => data.comments ?? [],
+ shouldStop: (items) => this.hasAllTargetUsers(items, targetUsers),
+ });
+
+ return this.getMatchingUsers(items, targetUsers);
+ }
+
+ getTargetPostUrn(postUrl?: string): string | null {
+ return this.extractPostUrn(postUrl);
+ }
+
+ private async requestPaginatedData({
+ operationName,
+ pageSize,
+ useCursor,
+ request,
+ selectItems,
+ shouldStop,
+ }: LinkdapiPaginatedRequestOptions): Promise {
+ const allItems: TItem[] = [];
+ let start = 0;
+ let cursor = '';
+
+ try {
+ for (
+ let page = 0;
+ page < this.linkdapiConfigService.maxPagesPerAction;
+ page += 1
+ ) {
+ const payload = await request({ start, cursor });
+
+ if (payload.success === false) {
+ if (allItems.length > 0) {
+ return allItems;
+ }
+
+ const details = payload.message ?? payload.detail;
+ throw new ServerError(
+ details
+ ? `LinkdAPI ${operationName} failed: ${details}`
+ : `LinkdAPI ${operationName} failed`,
+ );
+ }
+
+ const data =
+ payload && typeof payload === 'object' && 'data' in payload
+ ? (payload.data as T)
+ : (payload as T);
+ const items = selectItems(data);
+
+ if (items.length === 0) {
+ break;
+ }
+
+ allItems.push(...items);
+ if (shouldStop?.(allItems)) {
+ break;
+ }
+
+ const record =
+ data && typeof data === 'object'
+ ? (data as Record)
+ : {};
+ const pagination =
+ record.pagination && typeof record.pagination === 'object'
+ ? (record.pagination as Record)
+ : {};
+ const cursorValue =
+ record.cursor ??
+ record.nextCursor ??
+ record.next_cursor ??
+ pagination.cursor ??
+ pagination.nextCursor;
+ const nextCursor =
+ typeof cursorValue === 'string' && cursorValue.length > 0
+ ? cursorValue
+ : null;
+ const currentPage =
+ typeof record.currentPage === 'number' ? record.currentPage : null;
+ const pages = typeof record.pages === 'number' ? record.pages : null;
+
+ if (
+ items.length < pageSize ||
+ (currentPage !== null && pages !== null && currentPage >= pages)
+ ) {
+ break;
+ }
+
+ if (useCursor && nextCursor && nextCursor !== cursor) {
+ cursor = nextCursor;
+ } else {
+ start += pageSize;
+ cursor = '';
+ }
+ }
+
+ return allItems;
+ } catch (error) {
+ if (error instanceof ServerError) {
+ throw error;
+ }
+
+ if (error instanceof HTTPError) {
+ if (error.statusCode === 404) {
+ if (allItems.length > 0) {
+ return allItems;
+ }
+
+ throw new ValidationError(
+ SubmissionRejectionReason.TargetPostNotFound,
+ );
+ }
+
+ throw new ServerError(
+ error.responseBody
+ ? `LinkdAPI ${operationName} failed with HTTP ${error.statusCode}: ${error.responseBody}`
+ : `LinkdAPI ${operationName} failed with HTTP ${error.statusCode}`,
+ );
+ }
+
+ if (error instanceof LinkdAPIError) {
+ throw new ServerError(
+ `LinkdAPI ${operationName} failed: ${error.message}`,
+ );
+ }
+
+ throw error;
+ }
+ }
+
+ private getMatchingUsers(
+ items: LinkdapiEngagementItem[],
+ targetUsers: Set,
+ ): Set {
+ const matches = new Set();
+
+ for (const item of items) {
+ const profile =
+ [
+ item.author,
+ item.actor,
+ item.profile,
+ item.user,
+ item.commenter,
+ item.creator,
+ item.member,
+ item,
+ ].find((candidate) => candidate && typeof candidate === 'object') ??
+ null;
+
+ if (!profile) {
+ continue;
+ }
+
+ const url =
+ profile.url ?? profile.profileUrl ?? profile.profileURL ?? item.url;
+ const username =
+ profile.username ??
+ profile.publicIdentifier ??
+ profile.public_identifier ??
+ this.profileFromUrl(url);
+ const urn =
+ profile.urn ?? profile.profileUrn ?? profile.entityUrn ?? profile.id;
+ const firstName = profile.firstName ?? profile.first_name;
+ const lastName = profile.lastName ?? profile.last_name;
+ const fullName = [firstName, lastName].filter(Boolean).join(' ');
+ const profileName =
+ profile.name ?? profile.fullName ?? profile.full_name ?? fullName;
+ const name =
+ profileName ||
+ item.header?.replace(
+ /\s+(likes|reacted to|commented on|reposted).*/i,
+ '',
+ );
+
+ [username, url, urn, name].forEach((key) => {
+ if (!key) {
+ return;
+ }
+
+ const matchedKey = this.getProfileMatchKeys(key).find((matchKey) =>
+ targetUsers.has(matchKey),
+ );
+ if (matchedKey) {
+ matches.add(matchedKey);
+ }
+ });
+ }
+
+ return matches;
+ }
+
+ private hasAllTargetUsers(
+ items: LinkdapiEngagementItem[],
+ targetUsers: Set,
+ ): boolean {
+ return this.getMatchingUsers(items, targetUsers).size === targetUsers.size;
+ }
+
+ private extractPostUrn(postUrl?: string): string | null {
+ if (!postUrl) {
+ return null;
+ }
+
+ const decodedUrl = decodeURIComponent(postUrl);
+ const urnMatch = decodedUrl.match(
+ /urn:li:(?:activity|ugcPost|share):(\d+)/i,
+ );
+ if (urnMatch) {
+ return urnMatch[1];
+ }
+
+ const activitySlugMatch = decodedUrl.match(
+ /(?:activity|ugcPost|share)-(\d{10,})/i,
+ );
+ if (activitySlugMatch) {
+ return activitySlugMatch[1];
+ }
+
+ const numericMatch = decodedUrl.match(/\b(\d{16,})\b/);
+ return numericMatch?.[1] ?? null;
+ }
+
+ private normalizeSubmittedProfile(value: string): string {
+ const slug = this.profileFromUrl(value);
+ return (slug ?? value).trim().replace(/\s+/g, ' ').toLowerCase();
+ }
+
+ private getProfileMatchKeys(value: string): string[] {
+ const normalizedValue = this.normalizeSubmittedProfile(value);
+ const withoutSpaces = normalizedValue.replace(/\s+/g, '');
+ return [...new Set([normalizedValue, withoutSpaces])];
+ }
+
+ private ensureApi(): LinkdAPI {
+ if (!this.api) {
+ throw new ServerError(
+ 'LinkdAPI config is required to process LinkedIn social_media_engagement jobs',
+ );
+ }
+
+ return this.api;
+ }
+
+ private profileFromUrl(url?: string): string | null {
+ if (!url) {
+ return null;
+ }
+
+ const match = url.match(/linkedin\.com\/in\/([^/?#]+)/i);
+ return match?.[1] ?? null;
+ }
+
+ private rejectSubmissions(
+ submissions: SubmissionEntity[],
+ rejectionReason: SubmissionRejectionReason,
+ ): SubmissionValidationResult[] {
+ return submissions.map((submission) => ({
+ submission,
+ rejectionReason,
+ }));
+ }
+}
diff --git a/recording-oracle/src/modules/validation/validation.module.ts b/recording-oracle/src/modules/validation/validation.module.ts
index b315b46..f59f4d5 100644
--- a/recording-oracle/src/modules/validation/validation.module.ts
+++ b/recording-oracle/src/modules/validation/validation.module.ts
@@ -1,11 +1,12 @@
import { Module } from '@nestjs/common';
import { GrokService } from './grok/grok.service';
+import { LinkdapiService } from './linkdapi/linkdapi.service';
import { ValidationService } from './validation.service';
import { XApiService } from './x-api/x-api.service';
@Module({
- providers: [GrokService, XApiService, ValidationService],
+ providers: [GrokService, LinkdapiService, XApiService, ValidationService],
exports: [ValidationService],
})
export class ValidationModule {}
diff --git a/recording-oracle/src/modules/validation/validation.service.spec.ts b/recording-oracle/src/modules/validation/validation.service.spec.ts
index c65d4ea..963e981 100644
--- a/recording-oracle/src/modules/validation/validation.service.spec.ts
+++ b/recording-oracle/src/modules/validation/validation.service.spec.ts
@@ -1,5 +1,6 @@
import { Test } from '@nestjs/testing';
+import { ErrorJob } from '../../common/constants/errors';
import { JobRequestType } from '../../common/enums/job';
import {
ISocialMediaEngagementManifest,
@@ -8,12 +9,14 @@ import {
import { generateManifest } from '../job/fixtures';
import { generateSubmission } from '../submission/fixtures';
import { GrokService } from './grok/grok.service';
+import { LinkdapiService } from './linkdapi/linkdapi.service';
import { ValidationService } from './validation.service';
import { XApiService } from './x-api/x-api.service';
describe('ValidationService', () => {
let validationService: ValidationService;
let grokService: jest.Mocked;
+ let linkdapiService: jest.Mocked;
let xApiService: jest.Mocked;
beforeEach(async () => {
@@ -32,11 +35,18 @@ describe('ValidationService', () => {
validateSubmissions: jest.fn(),
},
},
+ {
+ provide: LinkdapiService,
+ useValue: {
+ validateSubmissions: jest.fn(),
+ },
+ },
],
}).compile();
validationService = moduleRef.get(ValidationService);
grokService = moduleRef.get(GrokService);
+ linkdapiService = moduleRef.get(LinkdapiService);
xApiService = moduleRef.get(XApiService);
});
@@ -60,6 +70,7 @@ describe('ValidationService', () => {
manifest,
);
expect(xApiService.validateSubmissions).not.toHaveBeenCalled();
+ expect(linkdapiService.validateSubmissions).not.toHaveBeenCalled();
});
it('delegates engagement validation to X API', async () => {
@@ -83,6 +94,49 @@ describe('ValidationService', () => {
submissions,
manifest,
);
+ expect(linkdapiService.validateSubmissions).not.toHaveBeenCalled();
+ expect(grokService.validateSubmission).not.toHaveBeenCalled();
+ });
+
+ it('delegates LinkedIn engagement validation to LinkdAPI', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['linkedin'],
+ }) as ISocialMediaEngagementManifest;
+ const submissions = [generateSubmission({ solution: 'human-protocol' })];
+ const validationResults = [
+ {
+ submission: submissions[0],
+ rejectionReason: null,
+ },
+ ];
+ linkdapiService.validateSubmissions.mockResolvedValue(validationResults);
+
+ await expect(
+ validationService.validateEngagementSubmissions(submissions, manifest),
+ ).resolves.toBe(validationResults);
+
+ expect(linkdapiService.validateSubmissions).toHaveBeenCalledWith(
+ submissions,
+ manifest,
+ );
+ expect(xApiService.validateSubmissions).not.toHaveBeenCalled();
+ expect(grokService.validateSubmission).not.toHaveBeenCalled();
+ });
+
+ it('throws when engagement platform is not supported', async () => {
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ platforms: ['instagram'],
+ }) as ISocialMediaEngagementManifest;
+ const submissions = [generateSubmission({ solution: 'human-protocol' })];
+
+ expect(() =>
+ validationService.validateEngagementSubmissions(submissions, manifest),
+ ).toThrow(ErrorJob.UnsupportedSocialPlatform);
+
+ expect(linkdapiService.validateSubmissions).not.toHaveBeenCalled();
+ expect(xApiService.validateSubmissions).not.toHaveBeenCalled();
expect(grokService.validateSubmission).not.toHaveBeenCalled();
});
});
diff --git a/recording-oracle/src/modules/validation/validation.service.ts b/recording-oracle/src/modules/validation/validation.service.ts
index ab3fcb9..56ce046 100644
--- a/recording-oracle/src/modules/validation/validation.service.ts
+++ b/recording-oracle/src/modules/validation/validation.service.ts
@@ -1,12 +1,17 @@
import { Injectable } from '@nestjs/common';
-import { SubmissionRejectionReason } from '../../common/constants/errors';
+import {
+ ErrorJob,
+ SubmissionRejectionReason,
+} from '../../common/constants/errors';
+import { ValidationError } from '../../common/errors';
import {
ISocialMediaEngagementManifest,
ISocialMediaPromotionManifest,
} from '../../common/interfaces/job';
import type { SubmissionEntity } from '../submission/submission.entity';
import { GrokService } from './grok/grok.service';
+import { LinkdapiService } from './linkdapi/linkdapi.service';
import { XApiService } from './x-api/x-api.service';
export type SubmissionValidationResult = {
@@ -18,6 +23,7 @@ export type SubmissionValidationResult = {
export class ValidationService {
constructor(
private readonly grokService: GrokService,
+ private readonly linkdapiService: LinkdapiService,
private readonly xApiService: XApiService,
) {}
@@ -32,6 +38,21 @@ export class ValidationService {
submissions: SubmissionEntity[],
manifest: ISocialMediaEngagementManifest,
): Promise {
- return this.xApiService.validateSubmissions(submissions, manifest);
+ const platform = this.getEngagementPlatform(manifest);
+
+ switch (platform) {
+ case 'linkedin':
+ return this.linkdapiService.validateSubmissions(submissions, manifest);
+ case 'x':
+ return this.xApiService.validateSubmissions(submissions, manifest);
+ default:
+ throw new ValidationError(ErrorJob.UnsupportedSocialPlatform);
+ }
+ }
+
+ private getEngagementPlatform(
+ manifest: ISocialMediaEngagementManifest,
+ ): string {
+ return manifest.platforms[0]?.toLowerCase() ?? '';
}
}
diff --git a/recording-oracle/src/modules/validation/x-api/x-api.interfaces.ts b/recording-oracle/src/modules/validation/x-api/x-api.interfaces.ts
index 957eebb..b419d38 100644
--- a/recording-oracle/src/modules/validation/x-api/x-api.interfaces.ts
+++ b/recording-oracle/src/modules/validation/x-api/x-api.interfaces.ts
@@ -48,3 +48,10 @@ export interface XApiErrorResponse {
status?: number;
}>;
}
+
+export type EngagementMatches = {
+ likingUsernames: Set;
+ repostingUsernames: Set;
+ quotingUsernames: Set;
+ commentingUsernames: Set;
+};
diff --git a/recording-oracle/src/modules/validation/x-api/x-api.service.spec.ts b/recording-oracle/src/modules/validation/x-api/x-api.service.spec.ts
index eb2c23c..e2c5a76 100644
--- a/recording-oracle/src/modules/validation/x-api/x-api.service.spec.ts
+++ b/recording-oracle/src/modules/validation/x-api/x-api.service.spec.ts
@@ -22,6 +22,12 @@ describe('XApiService', () => {
let service: XApiService;
let fetchMock: jest.Mock;
let xApiConfigService: XApiConfigServiceMock;
+ const requesterCredentials = {
+ consumerKey: 'requester-consumer-key',
+ consumerSecret: 'requester-consumer-secret',
+ accessToken: 'requester-access-token',
+ accessTokenSecret: 'requester-access-token-secret',
+ };
beforeEach(async () => {
fetchMock = jest.fn();
@@ -131,6 +137,24 @@ describe('XApiService', () => {
);
});
+ it('authenticates liking users requests with manifest X credentials when provided', async () => {
+ mockXApiResponse({ data: [] });
+
+ await service.getLikingUsernames(
+ '123',
+ new Set(['alice']),
+ requesterCredentials,
+ );
+
+ expect(fetchMock).toHaveBeenCalledTimes(1);
+ expect(fetchMock.mock.calls[0][1].headers.Authorization).toContain(
+ 'oauth_consumer_key="requester-consumer-key"',
+ );
+ expect(fetchMock.mock.calls[0][1].headers.Authorization).toContain(
+ 'oauth_token="requester-access-token"',
+ );
+ });
+
it('fails engagement X API calls clearly when OAuth config is missing', async () => {
xApiConfigService.consumerKey = undefined;
@@ -152,6 +176,7 @@ describe('XApiService', () => {
checkRepost: true,
checkQuote: true,
checkComment: true,
+ xApiCredentials: requesterCredentials,
},
});
const submissions = [
@@ -189,14 +214,17 @@ describe('XApiService', () => {
expect(service.getLikingUsernames).toHaveBeenCalledWith(
'123',
new Set(['alice', 'bob']),
+ requesterCredentials,
);
expect(service.getRepostingUsernames).toHaveBeenCalledWith(
'123',
new Set(['alice', 'bob']),
+ requesterCredentials,
);
expect(service.getQuotingUsernames).toHaveBeenCalledWith(
'123',
new Set(['alice']),
+ requesterCredentials,
);
expect(service.getCommentingUsernames).not.toHaveBeenCalled();
});
@@ -211,6 +239,7 @@ describe('XApiService', () => {
checkRepost: true,
checkQuote: true,
checkComment: true,
+ xApiCredentials: requesterCredentials,
},
});
const submissions = [
@@ -293,10 +322,12 @@ describe('XApiService', () => {
expect(service.getQuotingUsernames).toHaveBeenCalledWith(
'123',
new Set(['alice', 'bob']),
+ undefined,
);
expect(service.getCommentingUsernames).toHaveBeenCalledWith(
'123',
new Set(['alice']),
+ undefined,
);
});
@@ -310,6 +341,7 @@ describe('XApiService', () => {
checkRepost: false,
checkQuote: false,
checkComment: true,
+ xApiCredentials: requesterCredentials,
},
});
const submissions = [
@@ -342,6 +374,80 @@ describe('XApiService', () => {
expect(getCommentingUsernamesSpy).not.toHaveBeenCalled();
});
+ it('does not call like validation and rejects when checkLike has no manifest X credentials', async () => {
+ const targetPostUrl = 'https://x.com/human/status/123';
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: {
+ targetPostUrl,
+ checkLike: true,
+ },
+ });
+ const submissions = [generateSubmission({ id: 1, solution: 'alice' })];
+ const getLikingUsernamesSpy = jest.spyOn(service, 'getLikingUsernames');
+
+ await expect(
+ service.validateSubmissions(
+ submissions,
+ manifest as ISocialMediaEngagementManifest,
+ ),
+ ).resolves.toEqual([
+ {
+ submission: submissions[0],
+ rejectionReason: SubmissionRejectionReason.MissingRequiredLike,
+ },
+ ]);
+
+ expect(getLikingUsernamesSpy).not.toHaveBeenCalled();
+ });
+
+ it('uses manifest X credentials for all enabled engagement checks when provided', async () => {
+ mockXApiResponse({
+ data: [{ id: '1', username: 'alice' }],
+ });
+ mockXApiResponse({
+ data: [{ id: '1', username: 'alice' }],
+ });
+
+ const targetPostUrl = 'https://x.com/human/status/123';
+ const manifest = generateManifest({
+ requestType: JobRequestType.SOCIAL_MEDIA_ENGAGEMENT,
+ requirements: {
+ targetPostUrl,
+ checkLike: true,
+ checkRepost: true,
+ xApiCredentials: requesterCredentials,
+ },
+ });
+ const submissions = [generateSubmission({ id: 1, solution: 'alice' })];
+
+ await expect(
+ service.validateSubmissions(
+ submissions,
+ manifest as ISocialMediaEngagementManifest,
+ ),
+ ).resolves.toEqual([
+ {
+ submission: submissions[0],
+ rejectionReason: null,
+ },
+ ]);
+
+ expect(fetchMock).toHaveBeenCalledTimes(2);
+ expect(fetchMock.mock.calls[0][0].toString()).toContain(
+ '/tweets/123/liking_users',
+ );
+ expect(fetchMock.mock.calls[0][1].headers.Authorization).toContain(
+ 'oauth_consumer_key="requester-consumer-key"',
+ );
+ expect(fetchMock.mock.calls[1][0].toString()).toContain(
+ '/tweets/123/retweeted_by',
+ );
+ expect(fetchMock.mock.calls[1][1].headers.Authorization).toContain(
+ 'oauth_consumer_key="requester-consumer-key"',
+ );
+ });
+
it('maps quote authors from includes users for quote validation', async () => {
mockXApiResponse({
data: [
diff --git a/recording-oracle/src/modules/validation/x-api/x-api.service.ts b/recording-oracle/src/modules/validation/x-api/x-api.service.ts
index 2d25c67..d26fec9 100644
--- a/recording-oracle/src/modules/validation/x-api/x-api.service.ts
+++ b/recording-oracle/src/modules/validation/x-api/x-api.service.ts
@@ -4,30 +4,20 @@ import { Injectable } from '@nestjs/common';
import { XApiConfigService } from '../../../common/config/x-api-config.service';
import { SubmissionRejectionReason } from '../../../common/constants/errors';
import { ServerError, ValidationError } from '../../../common/errors';
-import { ISocialMediaEngagementManifest } from '../../../common/interfaces/job';
+import {
+ ISocialMediaEngagementManifest,
+ IXApiCredentials,
+} from '../../../common/interfaces/job';
import { SubmissionEntity } from '../../submission/submission.entity';
import type { SubmissionValidationResult } from '../validation.service';
import {
+ EngagementMatches,
XApiErrorResponse,
XApiListResponse,
XApiTweet,
XApiUser,
} from './x-api.interfaces';
-type EngagementMatches = {
- likingUsernames: Set;
- repostingUsernames: Set;
- quotingUsernames: Set;
- commentingUsernames: Set;
-};
-
-type XApiCredentials = {
- consumerKey: string;
- consumerSecret: string;
- accessToken: string;
- accessTokenSecret: string;
-};
-
@Injectable()
export class XApiService {
constructor(private readonly xApiConfigService: XApiConfigService) {}
@@ -49,6 +39,7 @@ export class XApiService {
const targetUsernames = new Set(
submissions.map((submission) => submission.solution.toLowerCase()),
);
+ const jobCredentials = manifest.requirements.xApiCredentials;
try {
const matches: EngagementMatches = {
@@ -59,10 +50,11 @@ export class XApiService {
};
let candidates = new Set(targetUsernames);
- if (manifest.requirements.checkLike) {
+ if (manifest.requirements.checkLike && jobCredentials) {
matches.likingUsernames = await this.getLikingUsernames(
targetPostId,
candidates,
+ jobCredentials,
);
candidates = this.filterCandidates(candidates, matches.likingUsernames);
}
@@ -71,6 +63,7 @@ export class XApiService {
matches.repostingUsernames = await this.getRepostingUsernames(
targetPostId,
candidates,
+ jobCredentials,
);
candidates = this.filterCandidates(
candidates,
@@ -82,6 +75,7 @@ export class XApiService {
matches.quotingUsernames = await this.getQuotingUsernames(
targetPostId,
candidates,
+ jobCredentials,
);
candidates = this.filterCandidates(
candidates,
@@ -93,6 +87,7 @@ export class XApiService {
matches.commentingUsernames = await this.getCommentingUsernames(
targetPostId,
candidates,
+ jobCredentials,
);
}
@@ -121,6 +116,7 @@ export class XApiService {
getLikingUsernames(
tweetId: string,
targetUsernames: Set,
+ credentials?: IXApiCredentials,
): Promise> {
return this.collectPaginatedMatches(
`/tweets/${tweetId}/liking_users`,
@@ -129,12 +125,14 @@ export class XApiService {
{
'user.fields': 'username,name',
},
+ credentials,
);
}
getRepostingUsernames(
tweetId: string,
targetUsernames: Set,
+ credentials?: IXApiCredentials,
): Promise> {
return this.collectPaginatedMatches(
`/tweets/${tweetId}/retweeted_by`,
@@ -143,12 +141,14 @@ export class XApiService {
{
'user.fields': 'username,name',
},
+ credentials,
);
}
async getCommentingUsernames(
tweetId: string,
targetUsernames: Set,
+ credentials?: IXApiCredentials,
): Promise> {
const matches = new Set();
@@ -170,6 +170,7 @@ export class XApiService {
'tweet.fields': 'author_id,conversation_id,referenced_tweets',
'user.fields': 'username,name',
},
+ credentials,
);
for (const userMatch of userMatches) {
@@ -183,6 +184,7 @@ export class XApiService {
getQuotingUsernames(
tweetId: string,
targetUsernames: Set,
+ credentials?: IXApiCredentials,
): Promise> {
return this.collectPaginatedMatches(
`/tweets/${tweetId}/quote_tweets`,
@@ -193,6 +195,7 @@ export class XApiService {
'tweet.fields': 'author_id,created_at,public_metrics',
'user.fields': 'username,name',
},
+ credentials,
);
}
@@ -201,6 +204,7 @@ export class XApiService {
targetUsernames: Set,
getUsername: (item: T, payload: XApiListResponse) => string | undefined,
endpointParams: Record = {},
+ credentials?: IXApiCredentials,
): Promise> {
const matches = new Set();
let nextToken: string | undefined;
@@ -223,6 +227,7 @@ export class XApiService {
const payload = await this.xGet>(
endpoint,
requestParams,
+ credentials,
);
for (const item of payload.data ?? []) {
const username = getUsername(item, payload);
@@ -346,6 +351,7 @@ export class XApiService {
private async xGet(
endpoint: string,
params: Record,
+ credentials?: IXApiCredentials,
): Promise {
const url = new URL(`${this.xApiConfigService.baseUrl}${endpoint}`);
Object.entries(params).forEach(([key, value]) => {
@@ -354,7 +360,11 @@ export class XApiService {
const response = await fetch(url, {
headers: {
- Authorization: this.getOAuthAuthorizationHeader('GET', url),
+ Authorization: this.getOAuthAuthorizationHeader(
+ 'GET',
+ url,
+ credentials,
+ ),
},
});
@@ -417,14 +427,18 @@ export class XApiService {
return errorMessages?.length ? errorMessages.join('; ') : null;
}
- private getOAuthAuthorizationHeader(method: string, url: URL): string {
- const credentials = this.getOAuthCredentials();
+ private getOAuthAuthorizationHeader(
+ method: string,
+ url: URL,
+ credentials?: IXApiCredentials,
+ ): string {
+ const oauthCredentials = credentials ?? this.getOAuthCredentials();
const oauthParams: Record = {
- oauth_consumer_key: credentials.consumerKey,
+ oauth_consumer_key: oauthCredentials.consumerKey,
oauth_nonce: randomBytes(16).toString('hex'),
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: Math.floor(Date.now() / 1000).toString(),
- oauth_token: credentials.accessToken,
+ oauth_token: oauthCredentials.accessToken,
oauth_version: '1.0',
};
@@ -432,7 +446,7 @@ export class XApiService {
method,
url,
oauthParams,
- credentials,
+ oauthCredentials,
);
return `OAuth ${Object.entries(oauthParams)
@@ -448,7 +462,7 @@ export class XApiService {
method: string,
url: URL,
oauthParams: Record,
- credentials: XApiCredentials,
+ credentials: IXApiCredentials,
): string {
const allParams: Array<[string, string]> = [];
@@ -489,7 +503,7 @@ export class XApiService {
.digest('base64');
}
- private getOAuthCredentials(): XApiCredentials {
+ private getOAuthCredentials(): IXApiCredentials {
const { consumerKey, consumerSecret, accessToken, accessTokenSecret } =
this.xApiConfigService;
diff --git a/recording-oracle/yarn.lock b/recording-oracle/yarn.lock
index 7971601..39ca4b7 100644
--- a/recording-oracle/yarn.lock
+++ b/recording-oracle/yarn.lock
@@ -595,12 +595,12 @@ __metadata:
languageName: node
linkType: hard
-"@human-protocol/core@npm:6.0.0":
- version: 6.0.0
- resolution: "@human-protocol/core@npm:6.0.0"
+"@human-protocol/core@npm:7.0.0":
+ version: 7.0.0
+ resolution: "@human-protocol/core@npm:7.0.0"
peerDependencies:
- ethers: ~6.15.0
- checksum: 10c0/10316b23ed6987c75ca1276de85145200bd1190ac8116e5ce6dfad5c427b1b509db63457ba5849fb9c16477264fc521b6737af48cf4700edc968153e1f8e28f2
+ ethers: ~6.16.0
+ checksum: 10c0/b8083fca9b7fab0bca450b7a520cf9f0e8b3af29f4b90fc36ab1d3f24b2ff76aa53f3c3e160f7c40e7079aad6f32ebc67f5abaf8ad75eb77eee808fee7fd3955
languageName: node
linkType: hard
@@ -616,11 +616,11 @@ __metadata:
languageName: node
linkType: hard
-"@human-protocol/sdk@npm:^7.1.0":
- version: 7.2.0
- resolution: "@human-protocol/sdk@npm:7.2.0"
+"@human-protocol/sdk@npm:^7.3.0":
+ version: 7.3.0
+ resolution: "@human-protocol/sdk@npm:7.3.0"
dependencies:
- "@human-protocol/core": "npm:6.0.0"
+ "@human-protocol/core": "npm:7.0.0"
axios: "npm:^1.4.0"
ethers: "npm:~6.16.0"
graphql: "npm:^16.8.1"
@@ -630,7 +630,7 @@ __metadata:
secp256k1: "npm:^5.0.1"
validator: "npm:^13.12.0"
vitest: "npm:^4.0.18"
- checksum: 10c0/7feac300575a4429f86b9602fd028edd543853d81198377d7a6b921548ba76b3fcb4b8a1f3611783a753b3b30620adcb94f53a8631dd060442eb20a5e382206d
+ checksum: 10c0/5835ce09161ab554483c6f9239f9985296491810b28a2f19adb090602c4436732b6787acb875ef2cf3fa9a6ca04ddecc620c52d5829f13a3cec1fd4dc85f1785
languageName: node
linkType: hard
@@ -5903,6 +5903,13 @@ __metadata:
languageName: node
linkType: hard
+"linkdapi@npm:^1.0.2":
+ version: 1.0.2
+ resolution: "linkdapi@npm:1.0.2"
+ checksum: 10c0/27d47d4be4cf380784a91b32913afcf86c1ac15b44d6bce46df59790c0e883742e02e10c1b887326e13044bbe8eb31b46f46d16d714e1071e453309f619509a7
+ languageName: node
+ linkType: hard
+
"load-esm@npm:1.0.3":
version: 1.0.3
resolution: "load-esm@npm:1.0.3"
@@ -7052,7 +7059,7 @@ __metadata:
"@eslint/js": "npm:^10.0.1"
"@faker-js/faker": "npm:9.7.0"
"@human-protocol/logger": "npm:^1.3.0"
- "@human-protocol/sdk": "npm:^7.1.0"
+ "@human-protocol/sdk": "npm:^7.3.0"
"@nestjs/axios": "npm:^4.0.1"
"@nestjs/cli": "npm:^11.0.16"
"@nestjs/common": "npm:^11.1.12"
@@ -7080,6 +7087,7 @@ __metadata:
helmet: "npm:^7.1.0"
jest: "npm:^29.7.0"
joi: "npm:^17.13.3"
+ linkdapi: "npm:^1.0.2"
minio: "npm:8.0.6"
pg: "npm:^8.16.3"
prettier: "npm:^3.8.1"
diff --git a/scripts/marketing-all-local.sh b/scripts/marketing-all-local.sh
index 13ffa14..5373949 100755
--- a/scripts/marketing-all-local.sh
+++ b/scripts/marketing-all-local.sh
@@ -7,6 +7,7 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
PID_EXCHANGE=""
PID_RECORDING=""
+PID_CAMPAIGN_LAUNCHER=""
run_in_dir() {
local target_dir="$1"
@@ -54,6 +55,10 @@ run_recording_oracle() {
run_in_dir "$PROJECT_ROOT/recording-oracle" env NODE_ENV=local yarn start:dev
}
+run_campaign_launcher() {
+ run_in_dir "$PROJECT_ROOT/campaign-launcher/client" yarn start
+}
+
shutdown() {
local exit_code="${1:-0}"
@@ -70,6 +75,10 @@ shutdown() {
kill -INT "$PID_RECORDING" 2>/dev/null || true
fi
+ if [ -n "$PID_CAMPAIGN_LAUNCHER" ]; then
+ kill -INT "$PID_CAMPAIGN_LAUNCHER" 2>/dev/null || true
+ fi
+
sleep 3
if [ -n "$PID_EXCHANGE" ] && kill -0 "$PID_EXCHANGE" 2>/dev/null; then
@@ -80,6 +89,10 @@ shutdown() {
kill -KILL "$PID_RECORDING" 2>/dev/null || true
fi
+ if [ -n "$PID_CAMPAIGN_LAUNCHER" ] && kill -0 "$PID_CAMPAIGN_LAUNCHER" 2>/dev/null; then
+ kill -KILL "$PID_CAMPAIGN_LAUNCHER" 2>/dev/null || true
+ fi
+
echo "Shutdown finished"
exit "$exit_code"
}
@@ -89,6 +102,7 @@ main() {
ensure_file "$PROJECT_ROOT/exchange-oracle/server/.env.local"
ensure_file "$PROJECT_ROOT/recording-oracle/.env.local"
+ ensure_file "$PROJECT_ROOT/campaign-launcher/client/.env"
setup_oracles
@@ -100,6 +114,10 @@ main() {
run_recording_oracle &
PID_RECORDING=$!
+ echo "Starting Campaign Launcher..."
+ run_campaign_launcher &
+ PID_CAMPAIGN_LAUNCHER=$!
+
echo "Local stack is running. Press Ctrl+C to stop everything."
wait
}