diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..120f81c --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,36 @@ +# CI/CD Workflow + +This directory contains GitHub Actions workflows for automated testing and validation. + +## CI / Validation Workflow (`.github/workflows/test.yml`) + +**Purpose**: Prevents regressions by running all test suites and linting on every pull request to main. + +**Triggers**: + +- Pull requests targeting the `main` branch + +**What it does**: + +1. **Setup**: Installs Rust (stable) and Node.js (v20) with dependency caching +2. **Dependency Installation**: Uses `npm install` for both backend and frontend +3. **Code Quality**: Runs linting on both backend and frontend (if configured) +4. **Backend Tests**: Runs `npm test` in `/backend` (Vitest + TypeScript) +5. **Frontend Tests**: Runs `npm test --if-present` in `/frontend` (no test framework configured yet) +6. **Smart Contract Tests**: Runs `cargo test` in `/contracts` (Rust) + +**Failure Behavior**: + +- Workflow fails if any test or linting step fails +- Blocks PR merge until all checks pass +- Uses `--if-present` to avoid failures when test scripts are missing + +**Requirements for Contributors**: + +- Ensure lint and test scripts are properly configured in `package.json` +- Tests must pass in all directories where they exist +- New dependencies should be added to respective `package.json` files +- Backend uses Vitest, frontend has no test framework configured yet +- react-hot-toast is available as a root dependency + +**Note**: The workflow uses `continue-on-error: false` to ensure strict validation - any failure will prevent the PR from being merged. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..01660c9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,68 @@ +name: CI / Validation + +on: + pull_request: + branches: [main] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "npm" + + - name: Cache Rust dependencies + uses: actions/cache@v4 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + contracts/target + key: ${{ runner.os }}-cargo-${{ hashFiles('contracts/**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Install backend dependencies + run: npm install + working-directory: ./backend + + - name: Install frontend dependencies + run: npm install + working-directory: ./frontend + + - name: Run linting (backend) + run: npm run lint --if-present + working-directory: ./backend + continue-on-error: false + + - name: Run linting (frontend) + run: npm run lint --if-present + working-directory: ./frontend + continue-on-error: false + + - name: Run Rust tests + run: cargo test + working-directory: ./contracts + continue-on-error: false + + - name: Run backend tests + run: npm test + working-directory: ./backend + continue-on-error: false + + - name: Run frontend tests + run: npm test + working-directory: ./frontend + continue-on-error: false diff --git a/backend/package.json b/backend/package.json index e61b139..de75230 100644 --- a/backend/package.json +++ b/backend/package.json @@ -40,6 +40,9 @@ "@types/cors": "^2.8.19", "@types/express": "^5.0.6", "@types/node": "^25.2.3", + + "@types/supertest": "^6.0.3", + "@types/pg": "^8.16.0", "@types/supertest": "^7.2.0", "@types/swagger-jsdoc": "^6.0.4", diff --git a/backend/tsconfig.json b/backend/tsconfig.json index cfba994..2f81df9 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -43,4 +43,4 @@ "src/**/*", "tests/**/*" ] -} \ No newline at end of file +} diff --git a/frontend/__tests__/setup.ts b/frontend/__tests__/setup.ts new file mode 100644 index 0000000..d0de870 --- /dev/null +++ b/frontend/__tests__/setup.ts @@ -0,0 +1 @@ +import "@testing-library/jest-dom"; diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx index f92b217..288f6b5 100644 --- a/frontend/app/layout.tsx +++ b/frontend/app/layout.tsx @@ -2,13 +2,11 @@ import type { Metadata } from "next"; import { IBM_Plex_Mono, Sora } from "next/font/google"; import React from "react"; -import "./globals.css"; -import { WalletProvider } from "@/context/wallet-context"; -import { Toaster } from "react-hot-toast"; import { ThemeProvider } from "@/context/theme-provider"; -import { Banner } from "@/components/ui/Banner"; -import bannerConfig from "@/lib/banner.config"; +import { WalletProvider } from "@/context/wallet-context"; import Link from "next/link"; +import { Toaster } from "react-hot-toast"; +import "./globals.css"; const sora = Sora({ variable: "--font-display", @@ -41,44 +39,50 @@ export default function RootLayout({ enableSystem={false} disableTransitionOnChange > - -
-
-
- - FlowFi - -
- -
-
- - {children} -
+ +
+
+
+ + FlowFi + +
+ +
+
+ + {children} +
diff --git a/frontend/app/outgoing/page.tsx b/frontend/app/outgoing/page.tsx new file mode 100644 index 0000000..60e54f0 --- /dev/null +++ b/frontend/app/outgoing/page.tsx @@ -0,0 +1,170 @@ +"use client"; + +import OutgoingStreams from "../../components/OutgoingStreams"; +import { Navbar } from "@/components/Navbar"; +import { useWallet } from "@/context/wallet-context"; +import React, { useEffect, useState } from "react"; +import { fetchDashboardData, type Stream } from "@/lib/dashboard"; +import toast from "react-hot-toast"; + +// Mock outgoing streams data for development +const mockOutgoingStreams: Stream[] = [ + { + id: "1", + recipient: "GABC123...XYZ", + amount: 1000, + token: "XLM", + status: "Active", + deposited: 1000, + withdrawn: 250, + date: "2024-01-15", + ratePerSecond: 0.0001, + lastUpdateTime: Date.now() / 1000, + isActive: true, + }, + { + id: "2", + recipient: "GDEF456...ABC", + amount: 500, + token: "XLM", + status: "Active", + deposited: 500, + withdrawn: 100, + date: "2024-01-20", + ratePerSecond: 0.00005, + lastUpdateTime: Date.now() / 1000, + isActive: true, + }, + { + id: "3", + recipient: "GHI789...DEF", + amount: 750, + token: "XLM", + status: "Paused", + deposited: 750, + withdrawn: 300, + date: "2024-01-10", + ratePerSecond: 0.00008, + lastUpdateTime: Date.now() / 1000, + isActive: false, + }, + { + id: "4", + recipient: "JKL012...GHI", + amount: 2000, + token: "XLM", + status: "Completed", + deposited: 2000, + withdrawn: 2000, + date: "2024-01-05", + ratePerSecond: 0.0002, + lastUpdateTime: Date.now() / 1000, + isActive: false, + }, +]; + +export default function OutgoingPage() { + const { session, status } = useWallet(); + const [streams, setStreams] = useState([]); + const [loading, setLoading] = useState(true); + const [prevKey, setPrevKey] = useState(session?.publicKey); + const [cancelingStreamId, setCancelingStreamId] = useState(null); + const [modifyingStreamId, setModifyingStreamId] = useState(null); + + // Reset loading state if public key changes + if (session?.publicKey !== prevKey) { + setPrevKey(session?.publicKey); + setLoading(true); + } + + useEffect(() => { + if (session?.publicKey) { + // For now, use mock data. In production, this would fetch from the backend + setLoading(true); + setTimeout(() => { + setStreams(mockOutgoingStreams); + setLoading(false); + }, 1000); + + // Uncomment this line when backend is ready + /* + fetchDashboardData(session.publicKey) + .then(data => setStreams(data.outgoingStreams)) + .catch(err => console.error("Failed to fetch outgoing streams:", err)) + .finally(() => setLoading(false)); + */ + } else { + // Show mock data even when not connected for demo purposes + setStreams(mockOutgoingStreams); + setLoading(false); + } + }, [session?.publicKey]); + + const handleCancel = async (stream: Stream) => { + setCancelingStreamId(stream.id); + try { + // Simulate API call + await new Promise(resolve => setTimeout(resolve, 2000)); + + // Update the stream status to cancelled + setStreams(prev => prev.map(s => + s.id === stream.id + ? { ...s, status: "Cancelled" as const, isActive: false } + : s + )); + + toast.success(`Stream to ${stream.recipient} has been cancelled`); + } catch (error) { + console.error("Failed to cancel stream:", error); + toast.error("Failed to cancel stream"); + } finally { + setCancelingStreamId(null); + } + }; + + const handleModify = async (stream: Stream) => { + setModifyingStreamId(stream.id); + try { + // Simulate API call for modification + await new Promise(resolve => setTimeout(resolve, 1500)); + + toast.success(`Stream to ${stream.recipient} modification dialog would open here`); + // In a real implementation, this would open a modal to modify stream parameters + } catch (error) { + console.error("Failed to modify stream:", error); + toast.error("Failed to modify stream"); + } finally { + setModifyingStreamId(null); + } + }; + + return ( +
+ +
+
+ {status !== "connected" ? ( +
+

Wallet Not Connected

+

Please connect your wallet in the app to view your outgoing streams.

+

Showing demo data for preview purposes.

+
+ ) : loading ? ( +
+
+

Loading outgoing streams...

+
+ ) : ( + + )} +
+
+
+ ); +} diff --git a/frontend/components/OutgoingStreams.tsx b/frontend/components/OutgoingStreams.tsx new file mode 100644 index 0000000..e49f1dd --- /dev/null +++ b/frontend/components/OutgoingStreams.tsx @@ -0,0 +1,172 @@ +'use client'; + +import React, { useState } from 'react'; +import type { Stream } from '@/lib/dashboard'; +import { useStreamingAmount } from '@/hooks/useStreamingAmount'; + +interface OutgoingStreamsProps { + streams: Stream[]; + onCancel: (stream: Stream) => Promise; + onModify: (stream: Stream) => Promise; + cancelingStreamId?: string | null; + modifyingStreamId?: string | null; +} + +function formatTokenAmount(value: number): string { + if (!Number.isFinite(value)) return '0.0000'; + + return new Intl.NumberFormat('en-US', { + minimumFractionDigits: 4, + maximumFractionDigits: 4, + }).format(value); +} + +const RemainingBalance: React.FC<{ stream: Stream }> = ({ stream }) => { + const claimable = useStreamingAmount({ + deposited: stream.deposited, + withdrawn: stream.withdrawn, + ratePerSecond: stream.ratePerSecond, + lastUpdateTime: stream.lastUpdateTime, + isActive: stream.status === 'Active' && stream.isActive, + }); + + const remaining = stream.deposited - stream.withdrawn - claimable; + const liveRate = stream.status === 'Active' && stream.ratePerSecond > 0; + + return ( +
+ + {formatTokenAmount(remaining)} {stream.token} + + + {liveRate + ? `-${formatTokenAmount(stream.ratePerSecond)} ${stream.token}/sec` + : 'Stream inactive'} + +
+ ); +}; + +const OutgoingStreams: React.FC = ({ + streams, + onCancel, + onModify, + cancelingStreamId = null, + modifyingStreamId = null, +}) => { + const [filter, setFilter] = useState<'All' | 'Active' | 'Completed' | 'Paused'>('All'); + + const filteredStreams = filter === 'All' + ? streams + : streams.filter((s) => s.status === filter); + + const handleFilterChange = (e: React.ChangeEvent) => { + setFilter(e.target.value as 'All' | 'Active' | 'Completed' | 'Paused'); + }; + + return ( +
+
+
+

Outgoing Payment Streams

+

+ Manage your active outgoing streams and liabilities +

+
+
+ + +
+
+ +
+ + + + + + + + + + + + + {filteredStreams.map((stream) => ( + + + + + + + + + ))} + +
RecipientTokenRateRemaining BalanceStatusActions
+
{stream.recipient}
+
Stream #{stream.id}
+
{stream.token} + {formatTokenAmount(stream.ratePerSecond)} {stream.token}/sec + + + + + {stream.status} + + +
+ + +
+
+
+ + {filteredStreams.length === 0 && ( +
+

No outgoing streams found matching the filter.

+
+ )} +
+ ); +}; + +export default OutgoingStreams; diff --git a/frontend/package.json b/frontend/package.json index 094fcd2..5c1fe44 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -6,7 +6,8 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "eslint" + "lint": "eslint", + "test": "vitest run" }, "dependencies": { "@stellar/freighter-api": "^6.0.1", @@ -17,16 +18,23 @@ "react": "19.2.4", "react-dom": "19.2.4", "react-hot-toast": "^2.6.0" + }, "devDependencies": { "@eslint/eslintrc": "^3.3.5", "@tailwindcss/postcss": "^4", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@vitest/ui": "^4.0.18", "eslint": "^9", "eslint-config-next": "16.1.6", + "jsdom": "^28.1.0", "tailwindcss": "^4", - "typescript": "^5" + "typescript": "^5", + "vitest": "^4.0.18" } } diff --git a/frontend/vitest.config.ts b/frontend/vitest.config.ts new file mode 100644 index 0000000..7d902f5 --- /dev/null +++ b/frontend/vitest.config.ts @@ -0,0 +1,16 @@ +import { resolve } from "path"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + globals: true, + environment: "jsdom", + setupFiles: ["./__tests__/setup.ts"], + passWithNoTests: true, + }, + resolve: { + alias: { + "@": resolve(__dirname, "./"), + }, + }, +}); diff --git a/package-lock.json b/package-lock.json index c7b1966..ae96a3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,9 @@ "@types/cors": "^2.8.19", "@types/express": "^5.0.6", "@types/node": "^25.2.3", + + "@types/supertest": "^6.0.3", + "@types/pg": "^8.16.0", "@types/supertest": "^7.2.0", "@types/swagger-jsdoc": "^6.0.4", @@ -419,13 +422,19 @@ "devDependencies": { "@eslint/eslintrc": "^3.3.5", "@tailwindcss/postcss": "^4", + "@testing-library/jest-dom": "^6.9.1", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.6.1", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", + "@vitest/ui": "^4.0.18", "eslint": "^9", "eslint-config-next": "16.1.6", + "jsdom": "^28.1.0", "tailwindcss": "^4", - "typescript": "^5" + "typescript": "^5", + "vitest": "^4.0.18" } }, "node_modules/@alloc/quick-lru": { @@ -1471,8 +1480,8 @@ "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@jsdevtools/ono": { @@ -2020,7 +2029,7 @@ "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~7.18.0" } }, "node_modules/@types/node/node_modules/undici-types": { @@ -2325,14 +2334,16 @@ "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { "version": "7.7.4", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch/node_modules/brace-expansion/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, "node_modules/@typescript-eslint/utils": { "version": "8.56.1", "dev": true, @@ -2479,11 +2490,20 @@ "version": "4.3.0", "dev": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "peer": true, "engines": { "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -3570,12 +3590,28 @@ "node_modules/doctrine": { "version": "2.1.0", "dev": true, + "license": "ISC", + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff": { + "version": "4.0.4", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, "node_modules/dotenv": { @@ -5291,7 +5327,7 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-property-descriptors": { @@ -6108,6 +6144,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -6418,10 +6455,14 @@ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "mime-db": "^1.54.0" }, "engines": { - "node": "*" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/minimist": { @@ -7436,7 +7477,8 @@ "node_modules/react-is": { "version": "16.13.1", "dev": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/readable-stream": { "version": "3.6.2", @@ -7548,16 +7590,48 @@ "version": "4.0.0", "dev": true, "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, "engines": { - "node": ">=4" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "dev": true, "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/restore-cursor": { @@ -7762,8 +7836,26 @@ "version": "6.3.1", "dev": true, "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.7.4", + "devOptional": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/send": { @@ -8109,7 +8201,7 @@ "node_modules/stable-hash": { "version": "0.0.5", "dev": true, - "license": "MIT" + "license": "ISC" }, "node_modules/stack-trace": { "version": "0.0.10", @@ -8173,11 +8265,7 @@ "node_modules/stop-iteration-iterator": { "version": "1.1.0", "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, + "license": "ISC", "engines": { "node": ">= 0.4" } @@ -8230,25 +8318,10 @@ "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" + "semver": "^7.5.3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=10" } }, "node_modules/string.prototype.repeat": { @@ -8274,10 +8347,7 @@ "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=18" } }, "node_modules/string.prototype.trimend": { @@ -8285,32 +8355,25 @@ "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/string.prototype.trimstart": { "version": "1.0.8", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/strip-ansi": { @@ -8330,9 +8393,11 @@ "node_modules/strip-bom": { "version": "3.0.0", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", + "optional": true, + "peer": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, "node_modules/strip-json-comments": { @@ -8340,10 +8405,7 @@ "dev": true, "license": "MIT", "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.10.0" } }, "node_modules/styled-jsx": { @@ -8530,32 +8592,14 @@ "node_modules/tinyglobby": { "version": "0.2.15", "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } + "license": "MIT" }, "node_modules/tinyglobby/node_modules/fdir": { "version": "6.5.0", "dev": true, "license": "MIT", "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "node": ">= 0.8" } }, "node_modules/tinyglobby/node_modules/picomatch": { @@ -8606,7 +8650,8 @@ "dev": true, "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" }, "engines": { "node": ">=8.0" @@ -8696,10 +8741,7 @@ "dev": true, "license": "MIT", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "safe-buffer": "~5.2.0" } }, "node_modules/tsconfig-paths/node_modules/json5": { @@ -8747,7 +8789,7 @@ "prelude-ls": "^1.2.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.6.19" } }, "node_modules/type-is": { @@ -8766,12 +8808,14 @@ "version": "1.0.3", "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">= 0.4" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/typed-array-byte-length": { @@ -8779,37 +8823,24 @@ "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/typed-array-byte-offset": { "version": "1.0.4", "dev": true, "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/typed-array-length": { @@ -8818,17 +8849,11 @@ "license": "MIT", "dependencies": { "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3" }, "engines": { "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/typescript": { @@ -8871,9 +8896,17 @@ "license": "MIT", "dependencies": { "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -8935,20 +8968,6 @@ "node_modules/update-browserslist-db": { "version": "1.2.3", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", "dependencies": { "escalade": "^3.2.0", @@ -9192,19 +9211,10 @@ "dev": true, "license": "MIT", "dependencies": { + "call-bind": "^1.0.8", "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -9218,10 +9228,9 @@ "dev": true, "license": "MIT", "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -9234,13 +9243,7 @@ "version": "1.1.20", "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" + "min-indent": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -9416,7 +9419,7 @@ "node": ">=8.0.0" }, "optionalDependencies": { - "commander": "^9.4.1" + "commander": "^10.0.0" } }, "node_modules/z-schema/node_modules/commander": { @@ -9424,7 +9427,7 @@ "license": "MIT", "optional": true, "engines": { - "node": "^12.20.0 || >=14" + "node": ">=14" } }, "node_modules/zeptomatch": {