diff --git a/.dockerignore b/.dockerignore index 5b57b57f..04c4f9dc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,35 +1,46 @@ -.devenv* -.direnv -.devcontainer .git .github .husky .vscode +.idea +.devcontainer .envrc -devenv.yaml -devenv.nix -.prettierrc.js -.prettierignore -.editorconfig -.npmrc -.firebaserc +.devenv* +.direnv +devenv.local.nix node_modules **/node_modules -**/*/node_modules +.pnpm-store **/dist **/build **/target +**/coverage +**/.cache +**/.parcel-cache +**/.svelte-kit +**/.nuxt **/__tests__ **/*.test.* -**/coverage +**/*.spec.* +tests/*/screenshots +tests/*/videos +docs *.md +!README.md LICENSE CODEOWNERS -.DS_Store +.firebase +.firebaserc +firebase.json +firestore.indexes.json +firestore.rules +netlify.toml + *.log +.DS_Store diff --git a/.firebaserc b/.firebaserc deleted file mode 100644 index feafd4b5..00000000 --- a/.firebaserc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "projects": { - "default": "postwoman-api" - } -} diff --git a/CODEOWNERS b/CODEOWNERS deleted file mode 100644 index 5c837665..00000000 --- a/CODEOWNERS +++ /dev/null @@ -1,21 +0,0 @@ -# CODEOWNERS is prioritized from bottom to top - -# Packages -/packages/codemirror-lang-graphql/ @AndrewBastin -/packages/hoppscotch-cli/ @jamesgeorge007 -/packages/hoppscotch-data/ @AndrewBastin -/packages/hoppscotch-js-sandbox/ @jamesgeorge007 -/packages/hoppscotch-selfhost-web/ @jamesgeorge007 -/packages/hoppscotch-selfhost-desktop/ @AndrewBastin -/packages/hoppscotch-sh-admin/ @JoelJacobStephen -/packages/hoppscotch-backend/ @balub - -# READMEs and other documentation files -*.md @liyasthomas - -# Self Host deployment related files -*.Dockerfile @balub -docker-compose.yml @balub -docker-compose.deploy.yml @balub -*.Caddyfile @balub -.dockerignore @balub diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index 5a23ef52..00000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,132 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, caste, color, religion, or sexual -identity and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -* Demonstrating empathy and kindness toward other people -* Being respectful of differing opinions, viewpoints, and experiences -* Giving and gracefully accepting constructive feedback -* Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -* Focusing on what is best not just for us as individuals, but for the overall - community - -Examples of unacceptable behavior include: - -* The use of sexualized language or imagery, and sexual attention or advances of - any kind -* Trolling, insulting or derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or email address, - without their explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. - -## Scope - -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, -posting via an official social media account, or acting as an appointed -representative at an online or offline event. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -support@hoppscotch.io. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series of -actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or permanent -ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within the -community. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.1, available at -[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. - -Community Impact Guidelines were inspired by -[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. - -For answers to common questions about this code of conduct, see the FAQ at -[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at -[https://www.contributor-covenant.org/translations][translations]. - -[homepage]: https://www.contributor-covenant.org -[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html -[Mozilla CoC]: https://github.com/mozilla/diversity -[FAQ]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index ce37ce4b..00000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,14 +0,0 @@ -# Contributing - -When contributing to this repository, please first discuss the change you wish to make via issue, -email, or any other method with the owners of this repository before making a change. - -Please note we have a code of conduct, please follow it in all your interactions with the project. - -## Pull Request Process - -1. Ensure any install or build dependencies are removed before the end of the layer when doing a - build. -2. Update the README.md with details of changes to the interface, this includes new environment - variables, exposed ports, useful file locations and container parameters. -3. Make sure you do not expose environment variables or other sensitive information in your PR. diff --git a/Makefile b/Makefile index c2bde3e4..2680aadc 100644 --- a/Makefile +++ b/Makefile @@ -1,21 +1,20 @@ COMPOSE := docker compose -PROFILE := default ENV_FILE := .env ENV_EXAMPLE := .env.example .PHONY: up down logs ps ensure-env up: ensure-env - $(COMPOSE) --profile $(PROFILE) up -d --build + $(COMPOSE) up -d --build down: - $(COMPOSE) --profile $(PROFILE) down + $(COMPOSE) down logs: - $(COMPOSE) --profile $(PROFILE) logs -f + $(COMPOSE) logs -f ps: - $(COMPOSE) --profile $(PROFILE) ps + $(COMPOSE) ps ensure-env: @test -f $(ENV_FILE) || cp $(ENV_EXAMPLE) $(ENV_FILE) diff --git a/README.md b/README.md index ffe946ee..17c0e990 100644 --- a/README.md +++ b/README.md @@ -1,299 +1,78 @@ -
- - Hoppscotch - -

- - Hoppscotch - -

- - Open Source API Development Ecosystem - -

+# Hoppscotch AIO -[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen?logo=github)](CODE_OF_CONDUCT.md) [![Website](https://img.shields.io/website?url=https%3A%2F%2Fhoppscotch.io&logo=hoppscotch)](https://hoppscotch.io) [![Tests](https://github.com/hoppscotch/hoppscotch/actions/workflows/tests.yml/badge.svg)](https://github.com/hoppscotch/hoppscotch/actions) [![Tweet](https://img.shields.io/twitter/url?url=https%3A%2F%2Fhoppscotch.io%2F)](https://x.com/share?text=%F0%9F%91%BD%20Hoppscotch%20%E2%80%A2%20Open%20source%20API%20development%20ecosystem%20-%20Helps%20you%20create%20requests%20faster,%20saving%20precious%20time%20on%20development.&url=https://hoppscotch.io&hashtags=hoppscotch&via=hoppscotch_io) +Fork interne de Hoppscotch réduit au déploiement self-host all-in-one pour +Coolify. -

-

- - Built with ❤︎ by - - contributors - - -

-
-

- - - - - Hoppscotch - - -

-
+## Contenu conservé -_We highly recommend you take a look at the [**Hoppscotch Documentation**](https://docs.hoppscotch.io) to learn more about the app._ +- Application web self-host : `packages/hoppscotch-selfhost-web` +- Backend NestJS et Prisma : `packages/hoppscotch-backend` +- Admin self-host : `packages/hoppscotch-sh-admin` +- Packages partagés requis au build : `hoppscotch-common`, `hoppscotch-data`, + `hoppscotch-kernel`, `hoppscotch-js-sandbox`, `codemirror-lang-graphql` +- Image Docker de production : `prod.Dockerfile` +- Déploiement Compose AIO : `docker-compose.yml` -#### **Support** +## Déploiement Coolify -[![Chat on Discord](https://img.shields.io/badge/chat-Discord-7289DA?logo=discord)](https://hoppscotch.io/discord) [![Chat on Telegram](https://img.shields.io/badge/chat-Telegram-2CA5E0?logo=telegram)](https://hoppscotch.io/telegram) [![Discuss on GitHub](https://img.shields.io/badge/discussions-GitHub-333333?logo=github)](https://github.com/hoppscotch/hoppscotch/discussions) +Utiliser `docker-compose.yml` comme source Compose. -### **Features** +Services créés : -❤️ **Lightweight:** Crafted with minimalistic UI design. +- `hoppscotch-aio` : image AIO construite depuis `prod.Dockerfile`, target + `aio` +- `hoppscotch-db` : PostgreSQL 15 avec volume persistant -⚡️ **Fast:** Send requests and get responses in real time. +Ports exposés : -🗄️ **HTTP Methods:** Request methods define the type of action you are requesting to be performed. +- `3080` -> Caddy AIO HTTP +- `3000` -> app web +- `3100` -> admin +- `3170` -> backend +- `3200` -> serveur de bundles webapp -- `GET` - Requests retrieve resource information -- `POST` - The server creates a new entry in a database -- `PUT` - Updates an existing resource -- `PATCH` - Very similar to `PUT` but makes a partial update on a resource -- `DELETE` - Deletes resource or related component -- `HEAD` - Retrieve response headers identical to those of a GET request, but without the response body. -- `CONNECT` - Establishes a tunnel to the server identified by the target resource -- `OPTIONS` - Describe the communication options for the target resource -- `TRACE` - Performs a message loop-back test along the path to the target resource -- `` - Some APIs use custom request methods such as `LIST`. Type in your custom methods. +Variables minimales à vérifier dans Coolify : -🌈 **Theming:** Customizable combinations for background, foreground, and accent colors — [customize now](https://hoppscotch.io/settings). +```env +POSTGRES_PASSWORD= +POSTGRES_DB=hoppscotch +DATA_ENCRYPTION_KEY= +VITE_BASE_URL=https:// +VITE_SHORTCODE_BASE_URL=https:// +VITE_ADMIN_URL=https:// +VITE_BACKEND_GQL_URL=https:///graphql +VITE_BACKEND_WS_URL=wss:///graphql +VITE_BACKEND_API_URL=https:///v1 +WHITELISTED_ORIGINS=https://,https:// +TRUST_PROXY=true +``` -- Choose a theme: System preference, Light, Dark, and Black -- Choose accent colors: Green, Teal, Blue, Indigo, Purple, Yellow, Orange, Red, and Pink -- Distraction-free Zen mode +`DATABASE_URL` est généré par `docker-compose.yml` pour la base PostgreSQL +incluse. Si le déploiement passe plus tard sur une base externe, adapter +explicitement le service `hoppscotch-aio`. -_Customized themes are synced with your cloud/local session._ +## Local -🔥 **PWA:** Install as a [Progressive Web App](https://web.dev/progressive-web-apps) on your device. +Créer le fichier `.env` si nécessaire : -- Instant loading with Service Workers -- Offline support -- Low RAM/memory and CPU usage -- Add to Home Screen -- Desktop PWA +```sh +cp .env.example .env +``` -🚀 **Request:** Retrieve response from endpoint instantly. +Démarrer l'AIO local : -1. Choose `method` -2. Enter `URL` -3. Send +```sh +docker compose up -d --build +``` -- Copy/share public "Share URL" -- Generate/copy request code snippets for 10+ languages and frameworks -- Import `cURL` -- Label requests +Voir les logs : -🔌 **WebSocket:** Establish full-duplex communication channels over a single TCP connection. +```sh +docker compose logs -f +``` -📡 **Server-Sent Events:** Receive a stream of updates from a server over an HTTP connection without resorting to polling. +Arrêter : -🌩 **Socket.IO:** Send and Receive data with the SocketIO server. - -🦟 **MQTT:** Subscribe and Publish to topics of an MQTT Broker. - -🔮 **GraphQL:** GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. - -- Set endpoint and get schema -- Multi-column docs -- Set custom request headers -- Query schema -- Get query response - -🔐 **Authorization:** Allows to identify the end-user. - -- None -- Basic -- Bearer Token -- OAuth 2.0 -- OIDC Access Token/PKCE - -📢 **Headers:** Describes the format the body of your request is being sent in. - -📫 **Parameters:** Use request parameters to set varying parts in simulated requests. - -📃 **Request Body:** Used to send and receive data via the REST API. - -- Set `Content Type` -- FormData, JSON, and many more -- Toggle between key-value and RAW input parameter list - -📮 **Response:** Contains the status line, headers, and the message/response body. - -- Copy the response to the clipboard -- Download the response as a file -- View response headers -- View raw and preview HTML, image, JSON, and XML responses - -⏰ **History:** Request entries are synced with your cloud/local session storage. - -📁 **Collections:** Keep your API requests organized with collections and folders. Reuse them with a single click. - -- Unlimited collections, folders, and requests -- Nested folders -- Export and import as a file or GitHub gist - -_Collections are synced with your cloud/local session storage._ - -📜 **Pre-Request Scripts:** Snippets of code associated with a request that is executed before the request is sent. - -- Set environment variables -- Include timestamp in the request headers -- Send a random alphanumeric string in the URL parameters -- Any JavaScript functions - -👨‍👩‍👧‍👦 **Teams:** Helps you collaborate across your teams to design, develop, and test APIs faster. - -- Create unlimited teams -- Create unlimited shared collections -- Create unlimited team members -- Role-based access control -- Cloud sync -- Multiple devices - -👥 **Workspaces:** Organize your personal and team collections environments into workspaces. Easily switch between workspaces to manage multiple projects. - -- Create unlimited workspaces -- Switch between personal and team workspaces - -⌨️ **Keyboard Shortcuts:** Optimized for efficiency. - -> **[Read our documentation on Keyboard Shortcuts](https://docs.hoppscotch.io/documentation/features/shortcuts)** - -🌐 **Proxy:** Enable Proxy Mode from Settings to access blocked APIs. - -- Hide your IP address -- Fixes [`CORS`](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) (Cross-Origin Resource Sharing) issues -- Access APIs served in non-HTTPS (`http://`) endpoints -- Use your Proxy URL - -_Official proxy server is hosted by Hoppscotch - **[GitHub](https://github.com/hoppscotch/proxyscotch)** - **[Privacy Policy](https://docs.hoppscotch.io/support/privacy)**._ - -🌎 **i18n:** Experience the app in your language. - -Help us to translate Hoppscotch. Please read [`TRANSLATIONS`](TRANSLATIONS.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md) and the process for submitting pull requests to us. - -☁️ **Auth + Sync:** Sign in and sync your data in real-time across all your devices. - -**Sign in with:** - -- GitHub -- Google -- Microsoft -- Email -- SSO (Single Sign-On)[^EE] - -**🔄 Synchronize your data:** Handoff to continue tasks on your other devices. - -- Workspaces -- History -- Collections -- Environments -- Settings - -✅ **Post-Request Tests:** Write tests associated with a request that is executed after the request's response. - -- Check the status code as an integer -- Filter response headers -- Parse the response data -- Set environment variables -- Write JavaScript code - -🌱 **Environments:** Environment variables allow you to store and reuse values in your requests and scripts. - -- Unlimited environments and variables -- Initialize through the pre-request script -- Export as / import from GitHub gist - -
- Use-cases - ---- - -- By storing a value in a variable, you can reference it throughout your request section -- If you need to update the value, you only have to change it in one place -- Using variables increases your ability to work efficiently and minimizes the likelihood of error - ---- - -
- -🚚 **Bulk Edit:** Edit key-value pairs in bulk. - -- Entries are separated by newline -- Keys and values are separated by `:` -- Prepend `#` to any row you want to add but keep disabled - -🎛️ **Admin dashboard:** Manage your team and invite members. - -- Insights -- Manage users -- Manage teams - -📦 **Add-ons:** Official add-ons for hoppscotch. - -- **[Hoppscotch CLI](https://github.com/hoppscotch/hoppscotch/tree/main/packages/hoppscotch-cli)** - Command-line interface for Hoppscotch. -- **[Proxy](https://github.com/hoppscotch/proxyscotch)** - A simple proxy server created for Hoppscotch. -- **[Browser Extensions](https://github.com/hoppscotch/hoppscotch-extension)** - Browser extensions that enhance your Hoppscotch experience. - - [![Firefox](https://raw.github.com/alrra/browser-logos/master/src/firefox/firefox_16x16.png) **Firefox**](https://addons.mozilla.org/en-US/firefox/addon/hoppscotch)  |  [![Chrome](https://raw.github.com/alrra/browser-logos/master/src/chrome/chrome_16x16.png) **Chrome**](https://chrome.google.com/webstore/detail/hoppscotch-extension-for-c/amknoiejhlmhancpahfcfcfhllgkpbld) - - > **Extensions fix `CORS` issues.** - -_Add-ons are developed and maintained under **[Hoppscotch Organization](https://github.com/hoppscotch)**._ - -**For a complete list of features, please read our [documentation](https://docs.hoppscotch.io).** - -## **Demo** - -- Web : [hoppscotch.io](https://hoppscotch.io) -- Windows/Linux/macOS : [Desktop Apps](https://docs.hoppscotch.io/documentation/clients/desktop#download-hoppscotch-desktop-app) - -## Usage - -1. Provide your API endpoint in the URL field -2. Click "Send" to simulate the request -3. View the response - -## Developing - -Follow our [self-hosting documentation](https://docs.hoppscotch.io/documentation/self-host/getting-started) to get started with the development environment. - -## Contributing - -Please contribute using [GitHub Flow](https://guides.github.com/introduction/flow). Create a branch, add commits, and [open a pull request](https://github.com/hoppscotch/hoppscotch/compare). - -Please read [`CONTRIBUTING`](CONTRIBUTING.md) for details on our [`CODE OF CONDUCT`](CODE_OF_CONDUCT.md), and the process for submitting pull requests to us. - -## Continuous Integration - -We use [GitHub Actions](https://github.com/features/actions) for continuous integration. Check out our [build workflows](https://github.com/hoppscotch/hoppscotch/actions). - -## Changelog - -See the [`CHANGELOG`](CHANGELOG.md) file for details. - -## Authors - -This project owes its existence to the collective efforts of all those who contribute — [contribute now](CONTRIBUTING.md). - - - -## License - -This project is licensed under the [MIT License](https://opensource.org/licenses/MIT) — see the [`LICENSE`](LICENSE) file for details. - -[^EE]: Enterprise edition feature. [Learn more](https://docs.hoppscotch.io/documentation/self-host/getting-started). +```sh +docker compose down +``` diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 0ecb916c..00000000 --- a/SECURITY.md +++ /dev/null @@ -1,135 +0,0 @@ -# Security Policy - -- [Security Policy](#security-policy) - - [Scope](#scope) - - [Architecture and threat model](#architecture-and-threat-model) - - [Desktop app](#desktop-app) - - [Hoppscotch Agent](#hoppscotch-agent) - - [Self-hosted instances](#self-hosted-instances) - - [Security controls](#security-controls) - - [Reporting a security vulnerability](#reporting-a-security-vulnerability) - - [What does not qualify as a vulnerability](#what-does-not-qualify-as-a-vulnerability) - -## Scope - -This policy covers components in the [hoppscotch/hoppscotch](https://github.com/hoppscotch/hoppscotch) repository: - -- **Desktop app**: the Tauri-based desktop client, including standalone use and connections to self-hosted or cloud-hosted instances. -- **Hoppscotch Agent**: the local relay service that runs on the user's machine and proxies requests from the web client. -- **Hoppscotch CLI**: the command-line client for running collections and tests, against either local collection files or an instance. -- **Self-hosted backend**: the Node.js backend, PostgreSQL data layer, and associated services deployed by self-hosting organisations. -- **Self-hosted web client and admin panel**: the web frontend and admin dashboard served by a self-hosted instance. - -**Out of scope** (separate security boundaries): - -- The cloud-hosted platform at hoppscotch.io or the website at hoppscotch.com. - - If you find a vulnerability that spans both the cloud platform and a component covered here, report it; we will coordinate triage across boundaries. -- The Hoppscotch browser extension (separate repository and distribution channel). -- Third-party proxies or community forks. - -## Architecture and threat model - -Hoppscotch is a client-side API development and testing tool. The threat model differs by deployment mode. - -### Desktop app - -**The user is the operator.** The person sending API requests is the same person who configured the tool and entered their credentials. This is fundamentally different from a multi-tenant web service where untrusted users submit input to a shared backend. - -**Local data storage is by design.** In standalone mode, the Desktop app persists collections, environments, request history, and credentials (including tokens, API keys, and other secrets) in local storage. This data is protected by OS-level access controls and, where enabled, full-disk encryption (FileVault, BitLocker, LUKS). When connected to a self-hosted or cloud backend, data syncs to the server while a local copy is retained (see the [self-hosted section](#self-hosted-instances)). - -**Secret environment variables are stored locally and never synced to the server.** Environment variables marked as secret are kept in the client's local store (the Desktop app's data store or the browser's local storage, depending on platform) and are excluded from server sync. They follow the same local-data security posture as other credentials on that platform. - -**The relay sends HTTP requests to arbitrary URLs provided by the user.** This includes localhost, private IP ranges, and cloud metadata endpoints. The relay runs on the user's machine, and the user controls what URLs it reaches. Separately, the Desktop app's realtime features (including WebSocket, SSE, Socket.IO, and MQTT) can also connect to user-specified endpoints under the same trust model: the user initiates and controls the connection. - -**Per-domain TLS configuration is user-controlled.** The relay supports custom CA certificates, client certificates (PEM and PKCS#12), and per-domain toggles for host and peer verification. Users can disable TLS verification for specific domains to work with self-signed certificates or corporate PKI environments. These are deliberate operator choices on the user's own machine. - -**The Desktop app loads web application bundles from instances the user adds.** When a user adds a self-hosted instance, the app downloads the instance's compiled web application (HTML, JavaScript, CSS) and runs it in an embedded webview. Remote bundles are verified with Ed25519 signatures and per-file BLAKE3 integrity hashes before loading (see [Security controls](#security-controls)). Bundles shipped with the installer are trusted as part of the build and release signing process. Adding an instance is an explicit trust decision, comparable to installing an extension or connecting to a self-hosted service. - -**Debug-level logging is intentional.** The Desktop app logs at debug level by default and writes to rotating local log files. The log files sit alongside the same data in the application's own data store. - -**Auto-updates are signature-verified.** The Desktop app checks `releases.hoppscotch.com` for available updates. Update manifests are verified against a public key before any binary is applied. This is a read-only check; no user data, credentials, or usage information is transmitted. - -**Local backups are created on version changes.** The Desktop app creates backups of the local data store when the application version changes, retaining up to three backups. These backups follow the same security posture as the primary data store: local files protected by OS access controls. - -### Hoppscotch Agent - -The Agent is a standalone local service that acts as an HTTP relay for the Hoppscotch web client, providing capabilities the browser sandbox restricts (custom headers, localhost access, client certificates, CORS bypass). - -**The Agent runs on the user's machine and listens on localhost.** It binds to port 9119 with a permissive CORS policy, meaning any origin can reach the port at the network level. Access control is enforced at the application layer through a registration handshake: the user enters a 6-digit one-time password displayed in the Agent UI, which establishes an encrypted communication channel (AES-256-GCM with X25519 key exchange). After registration, subsequent requests are authenticated and encrypted. The OTP does not expire and registration attempts are not rate-limited; the security assumption is that the user initiates registration intentionally while the Agent UI is visible. - -**The same relay trust model applies.** The Agent sends requests to arbitrary user-specified URLs, including private IP ranges and localhost. The user controls what URLs it reaches and what TLS, proxy, and certificate configuration applies per domain. - -**Agent data is stored locally.** Registration keys, per-domain settings (proxy configuration, client certificates, CA certificates, TLS verification toggles), and logs follow the same local-data security posture as the Desktop app. - -### Self-hosted instances - -With the backend deployed, the security model changes: - -**The instance administrator is the operator; users are tenants.** Self-hosted instances support multiple users, teams, role-based access control, and shared collections. Authentication and authorisation boundaries must hold between users, and server-side data must be protected at rest and in transit. - -**Data is stored server-side and locally.** Collections, environments, request history, and team data are persisted in PostgreSQL. Desktop app users connected to a self-hosted backend also retain a local copy; the local copy follows the same posture described in the [Desktop app section](#desktop-app). Credentials in shared team collections are accessible to team members with appropriate roles. The self-hosting organisation is responsible for database encryption, backup security, and access controls. - -**Collections can be published via public URLs.** Self-hosted instances allow publishing collections as documentation accessible via UUID-based slugs. Published documentation is publicly accessible without authentication. The self-hosting organisation controls which collections are published. - -**The admin dashboard has elevated privileges.** Instance administrators can view and manage all users, send invitations, and configure instance-wide settings through the admin interface. Admin actions are subject to role checks but operate across all teams and users on the instance. - -**Infrastructure API tokens provide programmatic access.** The backend supports API tokens (infra tokens) with configurable expiry for programmatic access to instance management. These tokens should be treated with the same care as admin credentials. - -**Backend session management.** User sessions use configurable cookie names and auto-generated session secrets. The self-hosting organisation can override session configuration via environment variables. Session secrets must be set explicitly in production deployments; auto-generated values are not suitable for production use. - -**Optional analytics.** If `INFRA.ALLOW_ANALYTICS_COLLECTION` is enabled, the backend sends aggregate instance telemetry (user count, workspace count, version) to PostHog. Opt-in, disabled by default. No request content, credentials, or per-user data is included. - -## Security controls - -**Bundle signature verification.** Remote bundles from self-hosted instances are verified with Ed25519 signatures and per-file BLAKE3 hashes. A bundle with an invalid signature or hash mismatch is rejected and will not load. The signing key is fetched from the serving instance over the instance connection (TLS/HTTPS strongly recommended). Signature verification protects against bundle corruption in the local cache and against tampering in transit when the connection is trusted. It does not protect against a compromised instance, since the instance provides both the key and the bundle, nor against an active man-in-the-middle if the key is fetched over untrusted transport, since an attacker could replace both. The trust boundary is the connection to the instance and the user's decision to add it. - -**Script sandboxing.** Pre-request and post-request scripts are isolated from the host environment. By default, scripts run in a QuickJS WebAssembly sandbox on every platform — isolated from the browser context, the Tauri IPC layer (on Desktop), and the host OS. The opt-out mechanism for the legacy compatibility mode differs per platform: Desktop and web expose the "Experimental scripting sandbox" toggle in Settings (on by default); the CLI opts in via the `--legacy-sandbox` flag. The legacy compatibility mode is retained as a backward-compatibility path for scripts that rely on host JavaScript semantics not exposed under QuickJS — on Desktop and web it runs scripts in a dedicated Web Worker using the `Function` constructor; on the CLI it runs scripts in an `isolated-vm` V8 isolate. The Web Worker legacy path does not provide the same isolation guarantees as QuickJS; the `isolated-vm` legacy path provides V8-isolate-level isolation but a different API surface from the QuickJS path. In the QuickJS paths, scripts receive controlled access to request data via the `pw`, `hopp`, and `pm` API namespaces, with request mutation limited to the documented pre-request APIs; network access is mediated through a controlled fetch hook, and scripts cannot make arbitrary system calls or access the filesystem. The Web Worker legacy mode preserves a separate Web Worker execution context but exposes only the `pw` namespace and does not mediate access to standard worker globals such as `fetch`; users opting in accept that scripts can reach any URL the worker context can reach. Scripts imported from external collection files follow the same default-versus-legacy execution path and constraints as locally authored scripts. - -**Update signature verification.** The auto-updater verifies update manifests against a public key before applying any update. A tampered manifest or binary will be rejected. - -**Rate limiting.** The self-hosted backend enforces request rate limiting via configurable TTL and max-request thresholds (`INFRA.RATE_LIMIT_TTL`, `INFRA.RATE_LIMIT_MAX`). This applies to REST and GraphQL endpoints by default, though some authenticated mutations opt out of throttling where rate limiting would interfere with normal interactive use. - -**GraphQL query complexity limiting.** The self-hosted backend enforces query complexity limits on the GraphQL API to prevent denial-of-service through deeply nested or expensive queries. - -## Reporting a security vulnerability - -We use [GitHub Security Advisories](https://github.com/hoppscotch/hoppscotch/security/advisories) to manage reports. If you do not receive a response, reach out to support@hoppscotch.io with the GHSA advisory link. - -If you disagree with our assessment, reply on the advisory with additional context or evidence. We will re-evaluate. - -Reports must demonstrate familiarity with the architecture and threat model described in this document. A report that flags a behaviour already documented here as intentional, or that applies a generic vulnerability classification (such as SSRF, insecure storage, or CORS misconfiguration) without explaining how the finding circumvents the stated trust model, will be closed. This applies to all reports regardless of how they were produced, including those generated with AI tools, LLMs, or automated scanners. - -> [!NOTE] -> Advisories may move to the relevant repository (for example, an XSS in a UI component might belong in [`@hoppscotch/ui`](https://github.com/hoppscotch/ui)). If in doubt, open your report in `hoppscotch/hoppscotch` GHSA. - -**Do not create a GitHub issue to report a security vulnerability.** - -## What does not qualify as a vulnerability - -Review the threat model above before reporting. The architecture and threat model section documents deliberate design decisions for each component. A finding that matches a known vulnerability class (CWE, OWASP category, or similar) is not automatically a vulnerability in this project; the threat model explains why. Reports that restate a documented design decision as a vulnerability will be closed without further analysis. The following are by design or out of scope. - -**Intended Desktop app and Agent behaviour:** -- The relay or Agent sending requests to private IP ranges, localhost, or cloud metadata endpoints. This is the product's core function. -- Credentials, tokens, or API keys stored in local storage, the application data store, local log files, or local backups on the user's machine. Local data is protected by OS-level access controls. -- Debug-level log output containing request details including headers and authentication data. The same data already exists in the local data store. -- A self-hosted instance bundle having access to application data within the Desktop app after passing signature verification. Adding an instance is an explicit trust decision. -- Users disabling TLS host or peer verification for specific domains. This is an operator-controlled per-domain setting for working with self-signed or internal certificates. -- WebSocket, SSE, Socket.IO, or MQTT connections reaching user-specified endpoints, including internal addresses. These are separate realtime features under the same trust model as HTTP relay requests. -- Pre-request or post-request scripts from imported collections executing in the sandbox. The sandbox applies equally to imported and locally authored scripts. -- The Desktop app checking `releases.hoppscotch.com` for updates. No user data is transmitted; update manifests are signature-verified. -- The Agent accepting connections from any origin on localhost:9119. CORS is permissive by design; access control is enforced through the registration handshake and encrypted channel. -- The Agent's registration OTP having no expiry and registration attempts not being rate-limited. The security assumption, documented in the Agent section above, is that the user initiates registration intentionally while the Agent UI is visible on their own machine. This is not CWE-307 (improper restriction of excessive authentication attempts) because the Agent is a local service, not a remote authentication endpoint. -- Theoretical attacks against the Desktop app or Agent that require prior local access to the user's machine, since the attacker already has access to the same data through the operating system. - -**Intended self-hosted behaviour:** -- First-run configuration endpoints being accessible without authentication before any administrator exists. These endpoints are intentionally unauthenticated during initial bootstrap so that the self-hosting organisation can complete setup, and are gated once an administrator is provisioned. This is not CWE-306 (missing authentication for critical function); it is the documented bootstrap path. Reports against an uninitialised instance describe the intended path. Bootstrap-related findings against an instance that has already been onboarded are a distinct issue and should be reported. -- Published collections being accessible without authentication via their public URL. The self-hosting organisation controls which collections are published. This is not CWE-284 (improper access control); publication is an explicit operator action. -- The auto-generated session secret used when `INFRA.SESSION_SECRET` is not set. The threat model already notes that auto-generated values are not suitable for production deployments. The self-hosting organisation is responsible for setting explicit secrets in their environment configuration. -- Some authenticated GraphQL mutations opting out of rate limiting. These opt-outs are intentional where throttling would interfere with normal interactive use and are scoped to authenticated sessions. - -**Out of scope:** -- Vulnerabilities in dependencies without a demonstrated practical attack against Hoppscotch. -- Automated scanner output, AI-generated vulnerability reports, or generic security assessments that have not been validated against this document's architecture and threat model. A report must identify what specific security control is missing or bypassable in context, not merely flag a code pattern that matches a known vulnerability class. Tools that scan a codebase and produce findings without reading the threat model will generate false positives against this project. -- Applying a generic vulnerability classification to behaviour this document explains as intentional. Sending HTTP requests to user-specified private IP ranges is the product's core function, not server-side request forgery (CWE-918). Storing credentials in local files on the user's own machine is the expected data model for a single-user developer tool, not insecure credential storage (CWE-312). A permissive CORS policy on a localhost service with application-layer authentication is documented above, not a CORS misconfiguration (CWE-942). -- Missing HTTP security headers (Content-Security-Policy, Strict-Transport-Security, X-Frame-Options) on the self-hosted web client without a demonstrated attack that the header would have prevented in this application's deployment context. -- Findings against hoppscotch.io or hoppscotch.com; report through the platform's security channel. Cross-boundary reports involving both a self-hosted component and the cloud platform are accepted here and will be coordinated. diff --git a/TRANSLATIONS.md b/TRANSLATIONS.md deleted file mode 100644 index fa58f381..00000000 --- a/TRANSLATIONS.md +++ /dev/null @@ -1,33 +0,0 @@ -# Translations - -Thanks for showing your interest in helping us to translate the software. - -## Creating a new translation - -Before you start working on a new language, please look through the [open pull requests](https://github.com/hoppscotch/hoppscotch/pulls) to see if anyone is already working on a translation. If you find one, please join the discussion and help us keep the existing translations up to date. - -if there is no existing translation, you can create a new one by following these steps: - -1. **[Fork the repository](https://github.com/hoppscotch/hoppscotch/fork).** -2. **Checkout the `main` branch for latest translations.** -3. **Create a new branch for your translation with base branch `main`.** -4. **Create target language file in the [`/packages/hoppscotch-common/locales`](https://github.com/hoppscotch/hoppscotch/tree/main/packages/hoppscotch-common/locales) directory.** -5. **Copy the contents of the source file [`/packages/hoppscotch-common/locales/en.json`](https://github.com/hoppscotch/hoppscotch/blob/main/packages/hoppscotch-common/locales/en.json) to the target language file.** -6. **Translate the strings in the target language file.** -7. **Add your language entry to [`/packages/hoppscotch-common/languages.json`](https://github.com/hoppscotch/hoppscotch/blob/main/packages/hoppscotch-common/languages.json).** -8. **Save and commit changes.** -9. **Send a pull request.** - -_You may send a pull request before all steps above are complete: e.g., you may want to ask for help with translations, or getting tests to pass. However, your pull request will not be merged until all steps above are complete._ - -Completing an initial translation of the whole site is a fairly large task. One way to break that task up is to work with other translators through pull requests on your fork. You can also [add collaborators to your fork](https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository) if you'd like to invite other translators to commit directly to your fork and share responsibility for merging pull requests. - -## Updating a translation - -### Corrections - -If you notice spelling or grammar errors, typos, or opportunities for better phrasing, open a pull request with your suggested fix. If you see a problem that you aren't sure of or don't have time to fix, [open an issue](https://github.com/hoppscotch/hoppscotch/issues/new/choose). - -### Broken links - -When tests find broken links, try to fix them across all translations. Ideally, only update the linked URLs, so that translation changes will definitely not be necessary. diff --git a/docker-compose.deploy.yml b/docker-compose.deploy.yml deleted file mode 100644 index e9b7919a..00000000 --- a/docker-compose.deploy.yml +++ /dev/null @@ -1,59 +0,0 @@ -# THIS IS NOT TO BE USED FOR PERSONAL DEPLOYMENTS! -# Internal Docker Compose Image used for internal testing deployments - -services: - hoppscotch-db: - image: postgres:15 - user: postgres - environment: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: testpass - POSTGRES_DB: hoppscotch - healthcheck: - test: - [ - "CMD-SHELL", - "sh -c 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'", - ] - interval: 5s - timeout: 5s - retries: 10 - - hoppscotch-aio: - container_name: hoppscotch-aio - build: - dockerfile: prod.Dockerfile - context: . - target: aio - environment: - # DATABASE_URL is read from the .env file to allow the backend to connect with an external database. - # This allows the backend to retain existing data and prevents database resets during deployments. - # - DATABASE_URL=postgresql://postgres:testpass@hoppscotch-db:5432/hoppscotch - - ENABLE_SUBPATH_BASED_ACCESS=true - env_file: - - ./.env - depends_on: - hoppscotch-db: - condition: service_healthy - command: - [ - "sh", - "-c", - "pnpm exec prisma migrate deploy && node /usr/src/app/aio_run.mjs", - ] - healthcheck: - test: - [ - "CMD", - "curl", - "-f", - "-s", - "-o", - "/dev/null", - "-w", - "%{http_code}", - "http://localhost:80", - ] - interval: 2s - timeout: 10s - retries: 30 diff --git a/docker-compose.yml b/docker-compose.yml index 6f103935..55d08340 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,160 +1,13 @@ -# To make it easier to self-host, we have a preset docker compose config that also -# has a container with a Postgres instance running. -# You can tweak around this file to match your instances - -# PROFILES EXPLANATION: -# -# We use Docker Compose profiles to manage different deployment scenarios and avoid port conflicts. -# -# These are all the available profiles: -# - default: All-in-one service + database + auto-migration (recommended for most users) -# - default-no-db: All-in-one service without database (for users with external DB) -# - backend: The backend service only -# - app: The main Hoppscotch application and the webapp server -# - admin: The self-host admin dashboard only -# - database: Just the PostgreSQL database -# - just-backend: All services except webapp for local development -# - deprecated: All deprecated services (not recommended) - -# USAGE: -# -# To run the default setup: docker compose --profile default up -# To run without database: docker compose --profile default-no-db up -# To run specific components: docker compose --profile backend up -# To run all except webapp: docker compose --profile just-backend up -# To run deprecated services: docker compose --profile deprecated up - -# NOTE: The default and default-no-db profiles should not be mixed with individual service -# profiles as they would conflict on ports. - services: - # This service runs the backend app in the port 3170 - hoppscotch-backend: - profiles: ["backend", "just-backend", "app", "admin"] - container_name: hoppscotch-backend - build: - dockerfile: prod.Dockerfile - context: . - target: backend - env_file: - - ./.env - restart: always - environment: - # Edit the below line to match your PostgresDB URL if you have an outside DB (make sure to update the .env file as well) - - DATABASE_URL=postgresql://postgres:testpass@hoppscotch-db:5432/hoppscotch?connect_timeout=300 - - PORT=8080 - volumes: - # Uncomment the line below when modifying code. Only applicable when using the "dev" target. - # - ./packages/hoppscotch-backend/:/usr/src/app - - /usr/src/app/node_modules/ - depends_on: - hoppscotch-db: - condition: service_healthy - ports: - - "3180:80" - - "3170:3170" - - # The main hoppscotch app with integrated webapp server. This will be hosted at port 3000 - # The webapp server will be accessible at port 3200 - # NOTE: To do TLS or play around with how the app is hosted, you can look into the Caddyfile for - # the SH admin dashboard server at packages/hoppscotch-selfhost-web/Caddyfile - hoppscotch-app: - profiles: ["app"] - container_name: hoppscotch-app - build: - dockerfile: prod.Dockerfile - context: . - target: app - env_file: - - ./.env - depends_on: - - hoppscotch-backend - ports: - - "3080:80" - - "3000:3000" - - "3200:3200" - - # The Self Host dashboard for managing the app. This will be hosted at port 3100 - # NOTE: To do TLS or play around with how the app is hosted, you can look into the Caddyfile for - # the SH admin dashboard server at packages/hoppscotch-sh-admin/Caddyfile - hoppscotch-sh-admin: - profiles: ["admin"] - container_name: hoppscotch-sh-admin - build: - dockerfile: prod.Dockerfile - context: . - target: sh_admin - env_file: - - ./.env - depends_on: - - hoppscotch-backend - ports: - - "3280:80" - - "3100:3100" - - # The service that spins up all services at once in one container - hoppscotch-aio: - profiles: ["default"] - container_name: hoppscotch-aio - restart: unless-stopped - build: - dockerfile: prod.Dockerfile - context: . - target: aio - env_file: - - ./.env - depends_on: - hoppscotch-db: - condition: service_healthy - ports: - - "3000:3000" - - "3100:3100" - - "3170:3170" - - "3200:3200" - - "3080:80" - - # Profile with no database dependency (purely developmental) - hoppscotch-aio-no-db: - profiles: ["default-no-db"] - container_name: hoppscotch-aio - restart: unless-stopped - build: - dockerfile: prod.Dockerfile - context: . - target: aio - env_file: - - ./.env - ports: - - "3000:3000" - - "3100:3100" - - "3170:3170" - - "3200:3200" - - "3080:80" - - # The preset DB service, you can delete/comment the below lines if - # you are using an external postgres instance - # This will be exposed at port 5432 hoppscotch-db: - profiles: - [ - "default", - "database", - "just-backend", - "backend", - "app", - "admin", - "deprecated", - ] image: postgres:15 - ports: - - "5432:5432" user: postgres environment: - # The default user defined by the docker image POSTGRES_USER: postgres - # NOTE: Please UPDATE THIS PASSWORD! - POSTGRES_PASSWORD: testpass - POSTGRES_DB: hoppscotch + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-testpass} + POSTGRES_DB: ${POSTGRES_DB:-hoppscotch} + volumes: + - hoppscotch-db:/var/lib/postgresql/data healthcheck: test: [ @@ -165,93 +18,32 @@ services: timeout: 5s retries: 10 - # Auto-migration service - handles database migrations automatically - hoppscotch-migrate: - profiles: ["default", "just-backend", "backend", "app", "admin"] + hoppscotch-aio: + container_name: hoppscotch-aio + restart: unless-stopped build: dockerfile: prod.Dockerfile context: . - target: backend + target: aio env_file: - ./.env - depends_on: - hoppscotch-db: - condition: service_healthy - command: sh -c "pnpm exec prisma migrate deploy" - - # All the services listed below are deprecated - # These services are kept for backward compatibility but should not be used for new deployments - hoppscotch-old-backend: - profiles: ["deprecated"] - container_name: hoppscotch-old-backend - build: - dockerfile: packages/hoppscotch-backend/Dockerfile - context: . - target: prod - env_file: - - ./.env - restart: always environment: - # Edit the below line to match your PostgresDB URL if you have an outside DB (make sure to update the .env file as well) - - DATABASE_URL=postgresql://postgres:testpass@hoppscotch-db:5432/hoppscotch?connect_timeout=300 - - PORT=3000 - volumes: - # Uncomment the line below when modifying code. Only applicable when using the "dev" target. - # - ./packages/hoppscotch-backend/:/usr/src/app - - /usr/src/app/node_modules/ + DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-testpass}@hoppscotch-db:5432/${POSTGRES_DB:-hoppscotch} depends_on: hoppscotch-db: condition: service_healthy + command: + [ + "sh", + "-c", + "pnpm exec prisma migrate deploy && node /usr/src/app/aio_run.mjs", + ] ports: - - "3170:3000" + - "3000:3000" + - "3100:3100" + - "3170:3170" + - "3200:3200" + - "3080:80" - hoppscotch-old-app: - profiles: ["deprecated"] - container_name: hoppscotch-old-app - build: - dockerfile: packages/hoppscotch-selfhost-web/Dockerfile - context: . - env_file: - - ./.env - depends_on: - - hoppscotch-old-backend - ports: - - "3000:8080" - - hoppscotch-old-sh-admin: - profiles: ["deprecated"] - container_name: hoppscotch-old-sh-admin - build: - dockerfile: packages/hoppscotch-sh-admin/Dockerfile - context: . - env_file: - - ./.env - depends_on: - - hoppscotch-old-backend - ports: - - "3100:8080" - -# DEPLOYMENT SCENARIOS: -# 1. Default deployment (recommended): -# docker compose --profile default up -# This will start: AIO + database + auto-migration -# -# 2. Default deployment without database: -# docker compose --profile default-no-db up -# This will start: AIO only (use when you have an external database) -# -# 3. Individual service deployment: -# docker compose --profile backend up # Just the backend -# docker compose --profile app up # Just the app and webapp server -# docker compose --profile admin up # Just the admin dashboard -# docker compose --profile database up # Just the database -# -# 4. Development deployment: -# docker compose --profile just-backend up # All services except webapp -# -# 5. Deprecated services: -# docker compose --profile deprecated up -# This will start all deprecated services (not recommended for new deployments) -# -# Remember: The default and default-no-db profiles should not be mixed with individual service -# profiles as they would conflict on ports. +volumes: + hoppscotch-db: diff --git a/firebase.json b/firebase.json deleted file mode 100644 index 4120bed0..00000000 --- a/firebase.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "firestore": { - "rules": "firestore.rules", - "indexes": "firestore.indexes.json" - }, - "hosting": { - "predeploy": [ - "mv .env.example .env && npm install -g pnpm && pnpm i && pnpm run generate" - ], - "public": "packages/hoppscotch-web/dist", - "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], - "rewrites": [ - { - "source": "**", - "destination": "/index.html" - } - ] - } -} diff --git a/firestore.indexes.json b/firestore.indexes.json deleted file mode 100644 index 415027e5..00000000 --- a/firestore.indexes.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "indexes": [], - "fieldOverrides": [] -} diff --git a/firestore.rules b/firestore.rules deleted file mode 100644 index 830e3972..00000000 --- a/firestore.rules +++ /dev/null @@ -1,13 +0,0 @@ -service cloud.firestore { - match /databases/{database}/documents { - // Make sure the uid of the requesting user matches name of the user - // document. The wildcard expression {userId} makes the userId variable - // available in rules. - match /users/{userId} { - allow read, write, create, update, delete: if request.auth.uid != null && request.auth.uid == userId; - } - match /users/{userId}/{document=**} { - allow read, write, create, update, delete: if request.auth.uid != null && request.auth.uid == userId; - } - } -} diff --git a/netlify.toml b/netlify.toml deleted file mode 100644 index 4a3899f4..00000000 --- a/netlify.toml +++ /dev/null @@ -1,77 +0,0 @@ -[build.environment] - NODE_VERSION = "14" - NPM_FLAGS = "--prefix=/dev/null" - -[build] - base = "/" - publish = "packages/hoppscotch-web/dist" - command = "npx pnpm i --store=node_modules/.pnpm-store && npx pnpm run generate" - -[[headers]] - for = "/*" - [headers.values] - X-Frame-Options = "SAMEORIGIN" - X-XSS-Protection = "1; mode=block" - -[[redirects]] - from = "/discord" - to = "https://discord.gg/GAMWxmR" - status = 301 - force = true - -[[redirects]] - from = "/telegram" - to = "https://t.me/hoppscotch" - status = 301 - force = true - -[[redirects]] - from = "/beta" - to = "https://forms.gle/XPYDMp8m6JHNWcYp9" - status = 301 - force = true - -[[redirects]] - from = "/careers" - to = "https://company.hoppscotch.io/careers" - status = 301 - force = true - -[[redirects]] - from = "/newsletter" - to = "http://eepurl.com/hy0eWH" - status = 301 - force = true - -[[redirects]] - from = "/twitter" - to = "https://x.com/hoppscotch_io" - status = 301 - force = true - -[[redirects]] - from = "/github" - to = "https://github.com/hoppscotch/hoppscotch" - status = 301 - force = true - -[[redirects]] - from = "/announcements" - to = "https://company.hoppscotch.io/announcements" - status = 301 - force = true - -[[redirects]] - from = "/robots.txt" - to = "/robots.txt" - status = 200 - -[[redirects]] - from = "/sitemap.xml" - to = "/sitemap.xml" - status = 200 - -[[redirects]] - from = "/*" - to = "/index.html" - status = 200 diff --git a/package.json b/package.json index fbf13590..e76bb797 100644 --- a/package.json +++ b/package.json @@ -17,11 +17,17 @@ "typecheck": "pnpm -r do-typecheck", "lintfix": "pnpm -r do-lintfix", "pre-commit": "pnpm -r do-lint && pnpm -r do-typecheck", - "test": "pnpm -r do-test", - "generate-ui": "pnpm -r do-build-ui" + "test": "pnpm -r do-test" }, "workspaces": [ - "./packages/*" + "./packages/codemirror-lang-graphql", + "./packages/hoppscotch-backend", + "./packages/hoppscotch-common", + "./packages/hoppscotch-data", + "./packages/hoppscotch-js-sandbox", + "./packages/hoppscotch-kernel", + "./packages/hoppscotch-selfhost-web", + "./packages/hoppscotch-sh-admin" ], "devDependencies": { "@commitlint/cli": "20.5.2", diff --git a/packages/hoppscotch-agent/.gitignore b/packages/hoppscotch-agent/.gitignore deleted file mode 100644 index e9f02db4..00000000 --- a/packages/hoppscotch-agent/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? -# Devenv -.devenv* -devenv.local.nix - -# direnv -.direnv - -# pre-commit -.pre-commit-config.yaml diff --git a/packages/hoppscotch-agent/README.md b/packages/hoppscotch-agent/README.md deleted file mode 100644 index 8d850ae4..00000000 --- a/packages/hoppscotch-agent/README.md +++ /dev/null @@ -1,281 +0,0 @@ -
- -

Hoppscotch Agent

-

- Download | - Official Docs -

-
- -
- -#### Hoppscotch Agent is a cross-platform HTTP request relay for Hoppscotch built with [Tauri V2](https://v2.tauri.app/) that adds capabilities like custom headers, certificates, proxies, and local access typically restricted in browsers. - -The agent runs as a local system service on port `9119`, acting as an intermediary between the Hoppscotch web application and target APIs. It establishes an encrypted communication channel authenticated via an OTP registration process. - -## Installation - -### Standard Installation - -1. Download the latest version of Hoppscotch Agent from [releases](https://github.com/hoppscotch/agent-releases) -2. Run the installer -3. Follow the installation wizard to complete setup -4. The agent automatically starts and appears in your system tray - -### Portable Version - -The portable version runs without installation and does not include automatic updates. - -1. Download the portable version for your operating system -2. Extract the archive to your desired location -3. Run the executable directly -4. The agent will start and appear in your system tray - -> [!Note] -> The portable version uses a separate configuration (`tauri.portable.conf.json`) that disables bundling and updater functionality. - -## Getting Started - -### Registration - -1. Open Hoppscotch web app and navigate to **Settings** → **Interceptors** -2. Select **Agent** from the available interceptors -3. Click **Register Agent** button -4. The agent window displays a 6-digit verification code -5. Enter the verification code in the OTP input field -6. Click the confirm button to establish connection -7. The agent displays a masked auth key hash when successfully registered - -### Usage - -Once registered, all HTTP requests made through Hoppscotch are processed by the agent. The agent provides: - -- CORS bypass by processing requests locally -- Client certificate authentication for mutual TLS -- HTTP Digest Authentication using challenge-response mechanisms -- Custom headers that browsers typically restrict -- Proxy routing with authentication support -- Local network and localhost access -- SSL/TLS verification controls -- And much more - -## Domain-Specific Configuration - -The agent (and `Native`) interceptor supports per-domain configuration overrides with a global default (`*`) domain: - -### Domain Management -- **Global Defaults**: Base settings applied to all domains (domain: `*`) -- **Domain Overrides**: Specific settings for individual domains (e.g., `api.example.com`) -- **Domain Addition**: Add new domains through the domain management modal -- **Domain Removal**: Remove custom domain configurations (global default cannot be removed) - -### SSL/TLS Security Settings - -For each domain, configure: - -- **Verify Host**: Enable/disable hostname verification during SSL handshake -- **Verify Peer**: Enable/disable peer certificate verification -- **CA Certificates**: Upload custom Certificate Authority certificates for domain validation -- **Client Certificates**: Configure client certificates for mutual TLS authentication - -## Client Certificates - -The agent supports client certificate authentication for APIs requiring mutual TLS: - -### Certificate Formats -- **.pem certificates**: Requires separate certificate (.crt/.cer/.pem) and private key (.key/.pem) files -- **.pfx/.pkcs12 certificates**: Single file format with optional password protection - -### Configuration - -1. Access **Settings** → **Interceptors** → **Agent** in Hoppscotch -2. Select the target domain from the domain selector -3. Click **Client Certificates** button -4. Choose certificate format (PEM or PFX tab) -5. Upload certificate files: - - **PEM**: Upload certificate file and private key file separately - - **PFX**: Upload .pfx/.pkcs12 file and enter password if required -6. Configuration is automatically saved per domain - -### CA Certificates - -Custom Certificate Authority certificates can be added per domain: - -1. Navigate to the CA Certificates section for the target domain -2. Click **Add Certificate File** -3. Upload the CA certificate file -4. Toggle certificate inclusion on/off as needed -5. Remove certificates using the trash icon - -## Proxy Configuration - -The agent supports HTTP/HTTPS proxy routing with authentication (including NTLM): - -### Proxy Settings -- **Proxy URL**: HTTP/HTTPS proxy server address with port -- **Proxy Authentication**: Username and password for proxy server authentication -- **Per-Domain**: Each domain can have different proxy configurations - -### Configuration - -1. Select the target domain -2. Toggle the **Proxy** switch to enable -3. Enter the proxy URL (e.g., `http://proxy.example.com:8080`) -4. Configure proxy authentication if required: - - Username field - - Password field (with show/hide toggle) - -## System Integration - -### System Tray -The agent runs with system tray integration, providing access to: -- **Show Registrations**: View active connections and registration status -- **Clear Registrations**: Remove all registered instances -- **Maximize Window**: Show the agent interface window -- **Quit**: Exit the agent application - -### Configuration Storage -The agent stores configuration in platform-specific locations: - -- **Windows**: `%APPDATA%\io.hoppscotch.agent\` -- **macOS**: `~/Library/Application Support/io.hoppscotch.agent/` -- **Linux**: `~/.config/io.hoppscotch.agent/` - -### Logging -Logs are stored in platform-specific directories: - -- **Windows**: `%LOCALAPPDATA%\io.hoppscotch.agent\logs\` -- **macOS**: `~/Library/Logs/io.hoppscotch.agent/` -- **Linux**: `~/.local/share/io.hoppscotch.agent/logs/` - -### Auto-Start Configuration -The standard installation includes auto-start functionality. The portable version does not include auto-start and must be launched manually. - -## Building from Source - -### Prerequisites - -- [Node.js](https://nodejs.org/) (v18 or later) -- [pnpm](https://pnpm.io/) package manager -- [Rust](https://rustup.rs/) (latest stable) -- [Tauri CLI](https://tauri.app/v1/guides/getting-started/prerequisites) - -### Development - -```bash -# Clone the repository -git clone https://github.com/hoppscotch/hoppscotch.git -cd hoppscotch/packages/hoppscotch-agent - -# Install dependencies -pnpm install - -# Start development server -pnpm tauri dev -``` - -### Production Build - -```bash -# Build standard version -pnpm tauri build - -# Build portable version -pnpm tauri build --config src-tauri/tauri.portable.conf.json -``` - -The built applications will be available in `src-tauri/target/release/bundle/` - -### Build Variants - -Two build configurations are available: - -- **Standard** (`tauri.conf.json`): Includes installer, auto-updater, and auto-start functionality -- **Portable** (`tauri.portable.conf.json`): Standalone executable without installation requirements - -## Network Configuration - -### Default Port -The agent runs on port `9119` by default. Make sure this port is not blocked by firewalls. - -### Communication Protocol -- **Encryption**: AES-256-GCM for all agent-to-web-app communication -- **Authentication**: X25519 key exchange for secure channel establishment -- **Registration**: One-time 6-digit OTP verification process - -## System Requirements - -### Windows -- **OS Version**: Windows 10 1803+ or Windows 11 -- **Architecture**: x64 -- **Dependencies**: WebView2 Runtime (auto-installed for standard version) - -### macOS -- **OS Version**: macOS 10.15 (Catalina) or later -- **Architecture**: Intel x64 or Apple Silicon (ARM64) - -### Linux -- **Architecture**: x64 -- **Dependencies**: WebKit2GTK 2.44.0+ (usually pre-installed) -- **Minimum**: Systems with GLIBC 2.38+ - -## Troubleshooting - -### Agent Detection Issues -1. **"Agent not detected" popup**: Verify the agent is running by checking the system tray for the Hoppscotch icon -2. **Switching interceptors blocked**: If the "Agent not detected" popup prevents switching interceptors, restart your browser and stop the agent before changing interceptor settings -3. **Port accessibility**: Check that no firewall is blocking port `9119` -4. **Browser compatibility**: Safari on macOS may have CORS issues with localhost:9119 due to access control checks, try Chrome/Firefox for agent registration - -### Registration Failures -1. **"Failed to initiate the registration"**: This error may occur due to browser security policies or extension conflicts -2. **Missing OTP input field**: Verify the agent window is focused and displaying a 6-digit verification code -3. **OTP expiration**: Registration codes have limited lifetime, restart the registration process if the code expires -4. **Network connectivity**: Verify browser can reach localhost:9119/handshake -5. **Version compatibility**: Some agent versions may be incompatible with specific Hoppscotch web app versions. For self-hosted setups, make sure Agent version in the release matches, see https://github.com/hoppscotch/hoppscotch/issues/4936#issuecomment-2756981053 - -### Certificate Issues -1. Verify certificate format is supported (.pem or .pfx/.pkcs12) -2. Check certificate expiration dates -3. Confirm private key matches certificate (for .pem files) -4. Verify domain configuration matches target API hostname -5. Confirm certificate password is correct (for .pfx/.pkcs12) -6. Check CA certificate inclusion status (toggle on/off) - -### Request Processing Issues -1. **Custom headers not applied**: Verify the agent is selected as interceptor, browsers may override headers like User-Agent when using default HTTP methods -2. **CORS errors**: Confirm agent interceptor is active and requests are routing through localhost:9119 -3. **SSL/TLS verification**: Check verify host/peer settings for the target domain -4. **Proxy routing**: Verify proxy URL format includes protocol (http:// or https://) - -### System-Specific Issues - -#### Windows -1. Check WebView2 Runtime is installed (auto-installed with standard version) -2. Check Windows Defender or antivirus exclusions for the agent executable -3. Verify agent has network permissions through Windows Firewall - -#### macOS -1. Safari browser may block agent connections due to CORS policies, try Chrome or Firefox instead -2. Check macOS Gatekeeper settings if agent fails to start -3. Verify agent is allowed in System Preferences → Security & Privacy - -#### Linux -1. Check WebKit2GTK dependencies are installed -2. Check systemd logs if agent fails to start as service -3. Verify GLIBC version compatibility (requires 2.38+) - -### Portable Version Issues -1. Manual WebView2 installation - may be required on older versions of Windows -2. No auto-start capability - must launch manually after system restart -3. No automatic updates - download new versions manually -4. Verify executable permissions on Unix-like systems -5. Check that portable version is extracted to a writable directory - -### Log -Check agent logs for detailed error information: -- **Windows**: `%LOCALAPPDATA%\io.hoppscotch.agent\logs\` -- **macOS**: `~/Library/Logs/io.hoppscotch.agent/` -- **Linux**: `~/.local/share/io.hoppscotch.agent/logs/` - -Look for connection errors, certificate validation failures, or proxy authentication issues in the log files. diff --git a/packages/hoppscotch-agent/eslint.config.mjs b/packages/hoppscotch-agent/eslint.config.mjs deleted file mode 100644 index 1ca0349d..00000000 --- a/packages/hoppscotch-agent/eslint.config.mjs +++ /dev/null @@ -1,67 +0,0 @@ -import pluginVue from "eslint-plugin-vue" -import { - defineConfigWithVueTs, - vueTsConfigs, -} from "@vue/eslint-config-typescript" -import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended" -import globals from "globals" - -export default defineConfigWithVueTs( - { - ignores: [ - "**/*.d.ts", - "dist/**", - "node_modules/**", - "src-tauri/**", - ], - }, - pluginVue.configs["flat/recommended"], - vueTsConfigs.recommended, - eslintPluginPrettierRecommended, - { - files: ["**/*.ts", "**/*.js", "**/*.vue"], - linterOptions: { - reportUnusedDisableDirectives: false, - }, - languageOptions: { - sourceType: "module", - ecmaVersion: "latest", - globals: { - ...globals.browser, - ...globals.node, - }, - parserOptions: { - requireConfigFile: false, - ecmaFeatures: { - jsx: false, - }, - }, - }, - rules: { - semi: [2, "never"], - "no-console": "off", - "no-debugger": process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn", - "prettier/prettier": - process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn", - "vue/multi-word-component-names": "off", - "vue/no-side-effects-in-computed-properties": "off", - "@typescript-eslint/no-unused-vars": [ - process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn", - { - args: "all", - argsIgnorePattern: "^_", - caughtErrors: "all", - caughtErrorsIgnorePattern: "^_", - destructuredArrayIgnorePattern: "^_", - varsIgnorePattern: "^_", - ignoreRestSiblings: true, - }, - ], - "@typescript-eslint/no-unused-expressions": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unsafe-function-type": "off", - "no-undef": "off", - }, - } -) diff --git a/packages/hoppscotch-agent/index.html b/packages/hoppscotch-agent/index.html deleted file mode 100644 index 7a5662ef..00000000 --- a/packages/hoppscotch-agent/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Hoppscotch Agent - - -
- - - diff --git a/packages/hoppscotch-agent/package.json b/packages/hoppscotch-agent/package.json deleted file mode 100644 index 37d668e8..00000000 --- a/packages/hoppscotch-agent/package.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "name": "hoppscotch-agent", - "private": true, - "version": "0.1.17", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vue-tsc --noEmit && vite build", - "preview": "vite preview", - "tauri": "tauri", - "lint": "eslint src", - "lint:ts": "vue-tsc --noEmit", - "lintfix": "eslint --fix src", - "prod-lint": "cross-env HOPP_LINT_FOR_PROD=true pnpm run lint", - "do-lint": "pnpm run prod-lint", - "do-typecheck": "pnpm run lint:ts", - "do-lintfix": "pnpm run lintfix" - }, - "dependencies": { - "@hoppscotch/ui": "0.2.5", - "@tauri-apps/api": "2.1.1", - "@tauri-apps/plugin-shell": "2.3.3", - "@vueuse/core": "14.2.1", - "axios": "1.15.2", - "fp-ts": "2.16.11", - "lodash-es": "4.18.1", - "vue": "3.5.33" - }, - "devDependencies": { - "@iconify-json/lucide": "1.2.104", - "@tauri-apps/cli": "2.9.3", - "@types/lodash-es": "4.17.12", - "@types/node": "24.10.1", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", - "@vitejs/plugin-vue": "6.0.6", - "@vue/eslint-config-typescript": "14.7.0", - "autoprefixer": "10.5.0", - "cross-env": "10.1.0", - "eslint": "9.39.2", - "eslint-plugin-prettier": "5.5.5", - "eslint-plugin-vue": "10.9.0", - "globals": "16.5.0", - "postcss": "8.5.10", - "tailwindcss": "3.4.16", - "typescript": "5.9.3", - "unplugin-icons": "22.5.0", - "unplugin-vue-components": "30.0.0", - "vite": "7.3.2", - "vue-tsc": "2.2.0" - } -} diff --git a/packages/hoppscotch-agent/postcss.config.js b/packages/hoppscotch-agent/postcss.config.js deleted file mode 100644 index 2e7af2b7..00000000 --- a/packages/hoppscotch-agent/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/packages/hoppscotch-agent/public/icon.png b/packages/hoppscotch-agent/public/icon.png deleted file mode 100644 index 3778416d..00000000 Binary files a/packages/hoppscotch-agent/public/icon.png and /dev/null differ diff --git a/packages/hoppscotch-agent/public/tauri.svg b/packages/hoppscotch-agent/public/tauri.svg deleted file mode 100644 index 31b62c92..00000000 --- a/packages/hoppscotch-agent/public/tauri.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/hoppscotch-agent/public/vite.svg b/packages/hoppscotch-agent/public/vite.svg deleted file mode 100644 index e7b8dfb1..00000000 --- a/packages/hoppscotch-agent/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/hoppscotch-agent/src-tauri/.cargo/config.toml b/packages/hoppscotch-agent/src-tauri/.cargo/config.toml deleted file mode 100644 index 9017258b..00000000 --- a/packages/hoppscotch-agent/src-tauri/.cargo/config.toml +++ /dev/null @@ -1,25 +0,0 @@ -# Enable static linking for C runtime library on Windows. -# -# Rust uses the msvc toolchain on Windows, -# which by default dynamically links the C runtime (CRT) to the binary. -# -# This creates a runtime dependency on the Visual C++ Redistributable (`vcredist`), -# meaning the target machine must have `vcredist` installed for the application to run. -# -# Since `portable` version doesn't have an installer, -# we can't rely on it to install dependencies, so this config. -# -# Basically: -# - The `+crt-static` flag instructs the Rust compiler to statically link the C runtime for Windows builds.\ -# - To avoids runtime errors related to missing `vcredist` installations. -# - Results in a larger binary size because the runtime is bundled directly into the executable. -# -# For MSVC targets specifically, it will compile code with `/MT` or static linkage. -# See: - RFC 1721: https://rust-lang.github.io/rfcs/1721-crt-static.html -# - Rust Reference - Runtime: https://doc.rust-lang.org/reference/runtime.html -# - MSVC Linking Options: https://docs.microsoft.com/en-us/cpp/build/reference/md-mt-ld-use-run-time-library -# - Rust Issue #37406: https://github.com/rust-lang/rust/issues/37406 -# - Tauri Issue #3048: https://github.com/tauri-apps/tauri/issues/3048 -# - Rust Linkage: https://doc.rust-lang.org/reference/linkage.html -[target.'cfg(windows)'] -rustflags = ["-C", "target-feature=+crt-static"] diff --git a/packages/hoppscotch-agent/src-tauri/.gitignore b/packages/hoppscotch-agent/src-tauri/.gitignore deleted file mode 100644 index b21bd681..00000000 --- a/packages/hoppscotch-agent/src-tauri/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ - -# Generated by Tauri -# will have schema files for capabilities auto-completion -/gen/schemas diff --git a/packages/hoppscotch-agent/src-tauri/Cargo.lock b/packages/hoppscotch-agent/src-tauri/Cargo.lock deleted file mode 100644 index fd52c1d2..00000000 --- a/packages/hoppscotch-agent/src-tauri/Cargo.lock +++ /dev/null @@ -1,7334 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aho-corasick" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" -dependencies = [ - "windows-sys 0.60.2", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.60.2", -] - -[[package]] -name = "anyhow" -version = "1.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" - -[[package]] -name = "arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] -name = "ashpd" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbdf310d77fd3aaee6ea2093db7011dc2d35d2eb3481e5607f1f8d942ed99df" -dependencies = [ - "enumflags2", - "futures-channel", - "futures-util", - "rand 0.9.2", - "raw-window-handle 0.6.2", - "serde", - "serde_repr", - "tokio", - "url", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "zbus", -] - -[[package]] -name = "async-broadcast" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-channel" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-compression" -version = "0.4.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a89bce6054c720275ac2432fbba080a66a2106a44a1b804553930ca6909f4e0" -dependencies = [ - "compression-codecs", - "compression-core", - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async-executor" -version = "1.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-io" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" -dependencies = [ - "autocfg", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 1.1.2", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-lock" -version = "3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-process" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 1.1.2", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "async-signal" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 1.1.2", - "signal-hook-registry", - "slab", - "windows-sys 0.61.2", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "atk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "auto-launch" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471" -dependencies = [ - "dirs 4.0.0", - "thiserror 1.0.69", - "winreg 0.10.1", -] - -[[package]] -name = "autocfg" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" - -[[package]] -name = "axum" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" -dependencies = [ - "async-trait", - "axum-core", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-core" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-extra" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c794b30c904f0a1c2fb7740f7df7f7972dfaa14ef6f57cb6178dc63e5dca2f04" -dependencies = [ - "axum", - "axum-core", - "bytes", - "fastrand", - "futures-util", - "headers", - "http", - "http-body", - "http-body-util", - "mime", - "multer", - "pin-project-lite", - "serde", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "base16" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d27c3610c36aee21ce8ac510e6224498de4228ad772a171ed65643a24693a5a8" - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" -dependencies = [ - "serde_core", -] - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -dependencies = [ - "objc2 0.5.2", -] - -[[package]] -name = "block2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdeb9d870516001442e364c5220d3574d2da8dc765554b4a617230d33fa58ef5" -dependencies = [ - "objc2 0.6.3", -] - -[[package]] -name = "blocking" -version = "1.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - -[[package]] -name = "brotli" -version = "8.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bumpalo" -version = "3.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" - -[[package]] -name = "bytemuck" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -dependencies = [ - "serde", -] - -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.10.0", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "camino" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" -dependencies = [ - "serde_core", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror 2.0.17", -] - -[[package]] -name = "cargo_toml" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" -dependencies = [ - "serde", - "toml 0.9.8", -] - -[[package]] -name = "cc" -version = "1.2.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739eb0f94557554b3ca9a86d2d37bebd49c5e6d0c1d2bda35ba5bdac830befc2" -dependencies = [ - "find-msvc-tools", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link 0.2.1", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "cocoa" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" -dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation", - "core-foundation 0.9.4", - "core-graphics 0.23.2", - "foreign-types 0.5.0", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" -dependencies = [ - "bitflags 1.3.2", - "block", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", - "libc", - "objc", -] - -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "compression-codecs" -version = "0.4.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8a506ec4b81c460798f572caead636d57d3d7e940f998160f52bd254bf2d23" -dependencies = [ - "compression-core", - "flate2", - "memchr", -] - -[[package]] -name = "compression-core" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e47641d3deaf41fb1538ac1f54735925e275eaf3bf4d55c81b137fba797e5cbb" - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "cookie_store" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" -dependencies = [ - "cookie", - "document-features", - "idna", - "log", - "publicsuffix", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.10.1", - "core-graphics-types 0.2.0", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.10.1", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "rand_core 0.6.4", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.29.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.108", -] - -[[package]] -name = "ctor" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.108", -] - -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - -[[package]] -name = "curl" -version = "0.4.47" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "socket2 0.5.10", -] - -[[package]] -name = "curl-sys" -version = "0.4.77+curl-8.10.1" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "windows-sys 0.52.0", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "darling" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.108", -] - -[[package]] -name = "darling_macro" -version = "0.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", - "serde", -] - -[[package]] -name = "data-url" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1e0bca6c3637f992fc1cc7cbc52a78c1ef6db076dbf1059c4323d6a2048376" - -[[package]] -name = "deranged" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" -dependencies = [ - "powerfmt", - "serde_core", -] - -[[package]] -name = "derive_arbitrary" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.108", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "dirs" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" -dependencies = [ - "dirs-sys 0.3.7", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys 0.5.0", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.5.2", - "windows-sys 0.61.2", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", -] - -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "dispatch2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" -dependencies = [ - "bitflags 2.10.0", - "block2 0.6.2", - "libc", - "objc2 0.6.3", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading 0.8.9", -] - -[[package]] -name = "dlopen2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788160fb30de9cdd857af31c6a2675904b16ece8fc2737b2c7127ba368c9d0f4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[package]] -name = "dpi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" -dependencies = [ - "serde", -] - -[[package]] -name = "dtoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "embed-resource" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml 0.9.8", - "vswhom", - "winreg 0.55.0", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "endi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" - -[[package]] -name = "enumflags2" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "env_filter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "erased-serde" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "259d404d09818dec19332e31d94558aeb442fea04c817006456c24b5460bbd4b" -dependencies = [ - "serde", - "serde_core", - "typeid", -] - -[[package]] -name = "errno" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "event-listener" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version", -] - -[[package]] -name = "file-rotate" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8e2fa049328a1f3295991407a88585805d126dfaadf74b9fe8c194c730aafc" -dependencies = [ - "chrono", - "flate2", -] - -[[package]] -name = "filetime" -version = "0.2.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.60.2", -] - -[[package]] -name = "find-msvc-tools" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" - -[[package]] -name = "flate2" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "form_urlencoded" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkx11" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" -dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps", - "x11", -] - -[[package]] -name = "generic-array" -version = "0.14.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasip2", - "wasm-bindgen", -] - -[[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.10.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.2", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "glob" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" - -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gtk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "h2" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.12.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" - -[[package]] -name = "headers" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" -dependencies = [ - "base64 0.22.1", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha1", -] - -[[package]] -name = "headers-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" -dependencies = [ - "http", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "hoppscotch-agent" -version = "0.1.17" -dependencies = [ - "aes-gcm", - "axum", - "axum-extra", - "base16", - "chrono", - "dashmap", - "dirs 6.0.0", - "file-rotate", - "lazy_static", - "native-dialog", - "rand 0.8.5", - "relay", - "serde", - "serde_json", - "sha2", - "tauri", - "tauri-build", - "tauri-plugin-autostart", - "tauri-plugin-dialog", - "tauri-plugin-http", - "tauri-plugin-shell", - "tauri-plugin-single-instance", - "tauri-plugin-store", - "tauri-plugin-updater", - "tempfile", - "thiserror 1.0.69", - "tokio", - "tokio-util", - "tower-http", - "tracing", - "tracing-appender", - "tracing-subscriber", - "uuid", - "winreg 0.52.0", - "x25519-dalek", -] - -[[package]] -name = "html5ever" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" -dependencies = [ - "log", - "mac", - "markup5ever", - "match_token", -] - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "http-serde" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" -dependencies = [ - "http", - "serde", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3aa54a13a0dfe7fbe3a59e0c76093041720fdc77b110cc0fc260fafb4dc51e" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" -dependencies = [ - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots", -] - -[[package]] -name = "hyper-util" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6995591a8f1380fcb4ba966a252a4b29188d51d2b89e3a252f5305be65aea8" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.6.1", - "system-configuration", - "tokio", - "tower-service", - "tracing", - "windows-registry", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.64" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core 0.62.2", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ico" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" -dependencies = [ - "byteorder", - "png 0.17.16", -] - -[[package]] -name = "icu_collections" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" - -[[package]] -name = "icu_properties" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" - -[[package]] -name = "icu_provider" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" -dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "image" -version = "0.25.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529feb3e6769d234375c4cf1ee2ce713682b8e76538cb13f9fc23e1400a591e7" -dependencies = [ - "bytemuck", - "byteorder-lite", - "moxcms", - "num-traits", - "png 0.18.0", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" -dependencies = [ - "equivalent", - "hashbrown 0.16.0", - "serde", - "serde_core", -] - -[[package]] -name = "infer" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" -dependencies = [ - "cfb", -] - -[[package]] -name = "infer" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" -dependencies = [ - "cfb", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "iri-string" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is-docker" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" -dependencies = [ - "once_cell", -] - -[[package]] -name = "is-wsl" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" -dependencies = [ - "is-docker", - "once_cell", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "jiff" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "js-sys" -version = "0.3.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "json-patch" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" -dependencies = [ - "jsonptr", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "jsonptr" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.10.0", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "kuchikiki" -version = "0.8.8-speedreader" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 2.12.0", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.177" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libloading" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if", - "windows-link 0.2.1", -] - -[[package]] -name = "libredox" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" -dependencies = [ - "bitflags 2.10.0", - "libc", - "redox_syscall", -] - -[[package]] -name = "libz-sys" -version = "1.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b70e7a7df205e92a1a4cd9aaae7898dac0aa555503cc0a649494d0d60e7651d" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - -[[package]] -name = "linux-raw-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" - -[[package]] -name = "litemap" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" - -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "markup5ever" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" -dependencies = [ - "log", - "phf 0.11.3", - "phf_codegen 0.11.3", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "matchers" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "matchit" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" - -[[package]] -name = "memchr" -version = "2.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" - -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "minisign-verify" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e856fdd13623a2f5f2f54676a4ee49502a96a80ef4a62bcedd23d52427c44d43" - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" -dependencies = [ - "libc", - "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.61.2", -] - -[[package]] -name = "moxcms" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" -dependencies = [ - "num-traits", - "pxfm", -] - -[[package]] -name = "muda" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" -dependencies = [ - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.2", - "once_cell", - "png 0.17.16", - "serde", - "thiserror 2.0.17", - "windows-sys 0.60.2", -] - -[[package]] -name = "multer" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http", - "httparse", - "memchr", - "mime", - "spin", - "version_check", -] - -[[package]] -name = "native-dialog" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e7038885d2aeab236bd60da9e159a5967b47cde3292da3b15ff1bec27c039f" -dependencies = [ - "ascii", - "block", - "cocoa", - "core-foundation 0.9.4", - "dirs-next", - "objc", - "objc-foundation", - "objc_id", - "once_cell", - "raw-window-handle 0.5.2", - "thiserror 1.0.69", - "versions", - "wfd", - "which", - "winapi", -] - -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.10.0", - "jni-sys", - "log", - "ndk-sys", - "num_enum", - "raw-window-handle 0.6.2", - "thiserror 1.0.69", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.6.0+11769913" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nix" -version = "0.30.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" -dependencies = [ - "bitflags 2.10.0", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nu-ansi-term" -version = "0.50.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" -dependencies = [ - "num_enum_derive", - "rustversion", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" -dependencies = [ - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys", - "objc2-encode", -] - -[[package]] -name = "objc2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" -dependencies = [ - "objc2-encode", - "objc2-exception-helper", -] - -[[package]] -name = "objc2-app-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" -dependencies = [ - "bitflags 2.10.0", - "block2 0.6.2", - "libc", - "objc2 0.6.3", - "objc2-cloud-kit", - "objc2-core-data", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", - "objc2-core-text", - "objc2-core-video", - "objc2-foundation 0.3.2", - "objc2-quartz-core 0.3.2", -] - -[[package]] -name = "objc2-cloud-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73ad74d880bb43877038da939b7427bba67e9dd42004a18b809ba7d87cee241c" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "objc2-core-data" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b402a653efbb5e82ce4df10683b6b28027616a2715e90009947d50b8dd298fa" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" -dependencies = [ - "bitflags 2.10.0", - "dispatch2", - "objc2 0.6.3", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" -dependencies = [ - "bitflags 2.10.0", - "dispatch2", - "objc2 0.6.3", - "objc2-core-foundation", - "objc2-io-surface", -] - -[[package]] -name = "objc2-core-image" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d563b38d2b97209f8e861173de434bd0214cf020e3423a52624cd1d989f006" -dependencies = [ - "objc2 0.6.3", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "objc2-core-text" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde0dfb48d25d2b4862161a4d5fcc0e3c24367869ad306b0c9ec0073bfed92d" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-core-foundation", - "objc2-core-graphics", -] - -[[package]] -name = "objc2-core-video" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d425caf1df73233f29fd8a5c3e5edbc30d2d4307870f802d18f00d83dc5141a6" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-io-surface", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-exception-helper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" -dependencies = [ - "cc", -] - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.10.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" -dependencies = [ - "bitflags 2.10.0", - "block2 0.6.2", - "libc", - "objc2 0.6.3", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-surface" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-javascript-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a1e6550c4caed348956ce3370c9ffeca70bb1dbed4fa96112e7c6170e074586" -dependencies = [ - "objc2 0.6.3", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.10.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-osa-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.10.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "objc2-security" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "709fe137109bd1e8b5a99390f77a7d8b2961dafc1a1c5db8f2e60329ad6d895a" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-ui-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" -dependencies = [ - "bitflags 2.10.0", - "objc2 0.6.3", - "objc2-core-foundation", - "objc2-foundation 0.3.2", -] - -[[package]] -name = "objc2-web-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e5aaab980c433cf470df9d7af96a7b46a9d892d521a2cbbb2f8a4c16751e7f" -dependencies = [ - "bitflags 2.10.0", - "block2 0.6.2", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.2", - "objc2-javascript-core", - "objc2-security", -] - -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "once_cell_polyfill" -version = "1.70.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" - -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - -[[package]] -name = "open" -version = "5.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2483562e62ea94312f3576a7aca397306df7990b8d89033e18766744377ef95" -dependencies = [ - "dunce", - "is-wsl", - "libc", - "pathdiff", -] - -[[package]] -name = "openssl" -version = "0.10.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ad14dd45412269e1a30f52ad8f0664f0f4f4a89ee8fe28c3b3527021ebb654" -dependencies = [ - "bitflags 2.10.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-src" -version = "300.5.4+3.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.110" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9f0075ba3c21b09f8e8b2026584b1d18d49388648f2fbbf3c97ea8deced8e2" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "os_pipe" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d8fae84b431384b68627d0f9b3b1245fcf9f46f6c0e3dc902e9dce64edd1967" -dependencies = [ - "libc", - "windows-sys 0.61.2", -] - -[[package]] -name = "osakit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b" -dependencies = [ - "objc2 0.6.3", - "objc2-foundation 0.3.2", - "objc2-osa-kit", - "serde", - "serde_json", - "thiserror 2.0.17", -] - -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link 0.2.1", -] - -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - -[[package]] -name = "percent-encoding" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared 0.8.0", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher 1.0.1", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "plist" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" -dependencies = [ - "base64 0.22.1", - "indexmap 2.12.0", - "quick-xml 0.38.3", - "serde", - "time", -] - -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "png" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" -dependencies = [ - "bitflags 2.10.0", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "polling" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix 1.1.2", - "windows-sys 0.61.2", -] - -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "potential_utf" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00f26d3400549137f92511a46ac1cd8ce37cb5598a96d382381458b992a5d24" -dependencies = [ - "toml_datetime 0.6.3", - "toml_edit 0.20.2", -] - -[[package]] -name = "proc-macro-crate" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" -dependencies = [ - "toml_edit 0.23.7", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "psl-types" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" - -[[package]] -name = "publicsuffix" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" -dependencies = [ - "idna", - "psl-types", -] - -[[package]] -name = "pxfm" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" -dependencies = [ - "num-traits", -] - -[[package]] -name = "quick-xml" -version = "0.37.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "331e97a1af0bf59823e6eadffe373d7b27f485be8748f71471c662c1f269b7fb" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.38.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42a232e7487fc2ef313d96dde7948e7a3c05101870d8985e4fd8d26aedd27b89" -dependencies = [ - "memchr", -] - -[[package]] -name = "quinn" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2 0.6.1", - "thiserror 2.0.17", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "bytes", - "getrandom 0.3.4", - "lru-slab", - "rand 0.9.2", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.17", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.6.1", - "tracing", - "windows-sys 0.60.2", -] - -[[package]] -name = "quote" -version = "1.0.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.3", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.4", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags 2.10.0", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 1.0.69", -] - -[[package]] -name = "redox_users" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 2.0.17", -] - -[[package]] -name = "ref-cast" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "regex" -version = "1.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" - -[[package]] -name = "relay" -version = "0.1.1" -source = "git+https://github.com/CuriousCorrelation/relay.git#ed2329e4ebb71bb984c4705aa950cb9c3f9ff931" -dependencies = [ - "bytes", - "curl", - "dashmap", - "env_logger", - "http", - "http-serde", - "infer 0.16.0", - "lazy_static", - "log", - "mime", - "openssl", - "openssl-sys", - "serde", - "serde_json", - "strum", - "thiserror 1.0.69", - "time", - "tokio-util", - "tracing", - "url", - "url-escape", - "urlencoding", -] - -[[package]] -name = "reqwest" -version = "0.12.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" -dependencies = [ - "async-compression", - "base64 0.22.1", - "bytes", - "cookie", - "cookie_store", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "js-sys", - "log", - "mime", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots", -] - -[[package]] -name = "rfd" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2bee61e6cffa4635c72d7d81a84294e28f0930db0ddcb0f66d10244674ebed" -dependencies = [ - "ashpd", - "block2 0.6.2", - "dispatch2", - "glib-sys", - "gobject-sys", - "gtk-sys", - "js-sys", - "log", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.2", - "raw-window-handle 0.6.2", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" -dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.11.0", - "windows-sys 0.61.2", -] - -[[package]] -name = "rustls" -version = "0.23.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9586e9ee2b4f8fab52a0048ca7334d7024eef48e2cb9407e3497bb7cab7fa7" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pki-types" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" -dependencies = [ - "web-time", - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schemars" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" -dependencies = [ - "dyn-clone", - "indexmap 1.9.3", - "schemars_derive", - "serde", - "serde_json", - "url", - "uuid", -] - -[[package]] -name = "schemars" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" -dependencies = [ - "dyn-clone", - "ref-cast", - "serde", - "serde_json", -] - -[[package]] -name = "schemars_derive" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.108", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "selectors" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", -] - -[[package]] -name = "semver" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -dependencies = [ - "serde", - "serde_core", -] - -[[package]] -name = "serde" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde-untagged" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9faf48a4a2d2693be24c6289dbe26552776eb7737074e6722891fadbe6c5058" -dependencies = [ - "erased-serde", - "serde", - "serde_core", - "typeid", -] - -[[package]] -name = "serde_core" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.228" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "serde_json" -version = "1.0.145" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", - "serde_core", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" -dependencies = [ - "itoa", - "serde", - "serde_core", -] - -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa66c845eee442168b2c8134fec70ac50dc20e760769c8ba0ad1319ca1959b04" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.12.0", - "schemars 0.9.0", - "schemars 1.0.4", - "serde_core", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91a903660542fced4e99881aa481bdbaec1634568ee02e0b8bd57c64cb38955" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "serialize-to-javascript" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "servo_arc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shared_child" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e362d9935bc50f019969e2f9ecd66786612daae13e8f277be7bfb66e8bed3f7" -dependencies = [ - "libc", - "sigchld", - "windows-sys 0.60.2", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "sigchld" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47106eded3c154e70176fc83df9737335c94ce22f821c32d17ed1db1f83badb1" -dependencies = [ - "libc", - "os_pipe", - "signal-hook", -] - -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" -dependencies = [ - "libc", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" - -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "softbuffer" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" -dependencies = [ - "bytemuck", - "cfg_aliases", - "core-graphics 0.24.0", - "foreign-types 0.5.0", - "js-sys", - "log", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", - "raw-window-handle 0.6.2", - "redox_syscall", - "wasm-bindgen", - "web-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "stable_deref_trait" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.108", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "swift-rs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" -dependencies = [ - "base64 0.21.7", - "serde", - "serde_json", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml 0.8.2", - "version-compare", -] - -[[package]] -name = "tao" -version = "0.34.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" -dependencies = [ - "bitflags 2.10.0", - "block2 0.6.2", - "core-foundation 0.10.1", - "core-graphics 0.24.0", - "crossbeam-channel", - "dispatch", - "dlopen2", - "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni", - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-foundation 0.3.2", - "once_cell", - "parking_lot", - "raw-window-handle 0.6.2", - "scopeguard", - "tao-macros", - "unicode-segmentation", - "url", - "windows", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "tar" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "tauri" -version = "2.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e492485dd390b35f7497401f67694f46161a2a00ffd800938d5dd3c898fb9d8" -dependencies = [ - "anyhow", - "bytes", - "cookie", - "dirs 6.0.0", - "dunce", - "embed_plist", - "getrandom 0.3.4", - "glob", - "gtk", - "heck 0.5.0", - "http", - "image", - "jni", - "libc", - "log", - "mime", - "muda", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-foundation 0.3.2", - "objc2-ui-kit", - "objc2-web-kit", - "percent-encoding", - "plist", - "raw-window-handle 0.6.2", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "swift-rs", - "tauri-build", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "thiserror 2.0.17", - "tokio", - "tray-icon", - "url", - "webkit2gtk", - "webview2-com", - "window-vibrancy", - "windows", -] - -[[package]] -name = "tauri-build" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87d6f8cafe6a75514ce5333f115b7b1866e8e68d9672bf4ca89fc0f35697ea9d" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs 6.0.0", - "glob", - "heck 0.5.0", - "json-patch", - "schemars 0.8.22", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml 0.9.8", - "walkdir", -] - -[[package]] -name = "tauri-codegen" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ef707148f0755110ca54377560ab891d722de4d53297595380a748026f139f" -dependencies = [ - "base64 0.22.1", - "brotli", - "ico", - "json-patch", - "plist", - "png 0.17.16", - "proc-macro2", - "quote", - "semver", - "serde", - "serde_json", - "sha2", - "syn 2.0.108", - "tauri-utils", - "thiserror 2.0.17", - "time", - "url", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-macros" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71664fd715ee6e382c05345ad258d6d1d50f90cf1b58c0aa726638b33c2a075d" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.108", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076c78a474a7247c90cad0b6e87e593c4c620ed4efdb79cbe0214f0021f6c39d" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri-utils", - "toml 0.9.8", - "walkdir", -] - -[[package]] -name = "tauri-plugin-autostart" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459383cebc193cdd03d1ba4acc40f2c408a7abce419d64bdcd2d745bc2886f70" -dependencies = [ - "auto-launch", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.17", -] - -[[package]] -name = "tauri-plugin-dialog" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313f8138692ddc4a2127c4c9607d616a46f5c042e77b3722450866da0aad2f19" -dependencies = [ - "log", - "raw-window-handle 0.6.2", - "rfd", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror 2.0.17", - "url", -] - -[[package]] -name = "tauri-plugin-fs" -version = "2.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47df422695255ecbe7bac7012440eddaeefd026656171eac9559f5243d3230d9" -dependencies = [ - "anyhow", - "dunce", - "glob", - "percent-encoding", - "schemars 0.8.22", - "serde", - "serde_json", - "serde_repr", - "tauri", - "tauri-plugin", - "tauri-utils", - "thiserror 2.0.17", - "toml 0.9.8", - "url", -] - -[[package]] -name = "tauri-plugin-http" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00685aceab12643cf024f712ab0448ba8fcadf86f2391d49d2e5aa732aacc70" -dependencies = [ - "bytes", - "cookie_store", - "data-url", - "http", - "regex", - "reqwest", - "schemars 0.8.22", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror 2.0.17", - "tokio", - "url", - "urlpattern", -] - -[[package]] -name = "tauri-plugin-shell" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c374b6db45f2a8a304f0273a15080d98c70cde86178855fc24653ba657a1144c" -dependencies = [ - "encoding_rs", - "log", - "open", - "os_pipe", - "regex", - "schemars 0.8.22", - "serde", - "serde_json", - "shared_child", - "tauri", - "tauri-plugin", - "thiserror 2.0.17", - "tokio", -] - -[[package]] -name = "tauri-plugin-single-instance" -version = "2.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd707f8c86b4e3004e2c141fa24351f1909ba40ce1b8437e30d5ed5277dd3710" -dependencies = [ - "serde", - "serde_json", - "tauri", - "thiserror 2.0.17", - "tracing", - "windows-sys 0.60.2", - "zbus", -] - -[[package]] -name = "tauri-plugin-store" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a77036340a97eb5bbe1b3209c31e5f27f75e6f92a52fd9dd4b211ef08bf310" -dependencies = [ - "dunce", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.17", - "tokio", - "tracing", -] - -[[package]] -name = "tauri-plugin-updater" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27cbc31740f4d507712550694749572ec0e43bdd66992db7599b89fbfd6b167b" -dependencies = [ - "base64 0.22.1", - "dirs 6.0.0", - "flate2", - "futures-util", - "http", - "infer 0.19.0", - "log", - "minisign-verify", - "osakit", - "percent-encoding", - "reqwest", - "semver", - "serde", - "serde_json", - "tar", - "tauri", - "tauri-plugin", - "tempfile", - "thiserror 2.0.17", - "time", - "tokio", - "url", - "windows-sys 0.60.2", - "zip", -] - -[[package]] -name = "tauri-runtime" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9368f09358496f2229313fccb37682ad116b7f46fa76981efe116994a0628926" -dependencies = [ - "cookie", - "dpi", - "gtk", - "http", - "jni", - "objc2 0.6.3", - "objc2-ui-kit", - "objc2-web-kit", - "raw-window-handle 0.6.2", - "serde", - "serde_json", - "tauri-utils", - "thiserror 2.0.17", - "url", - "webkit2gtk", - "webview2-com", - "windows", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "929f5df216f5c02a9e894554401bcdab6eec3e39ec6a4a7731c7067fc8688a93" -dependencies = [ - "gtk", - "http", - "jni", - "log", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-foundation 0.3.2", - "once_cell", - "percent-encoding", - "raw-window-handle 0.6.2", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "url", - "webkit2gtk", - "webview2-com", - "windows", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6b8bbe426abdbf52d050e52ed693130dbd68375b9ad82a3fb17efb4c8d85673" -dependencies = [ - "anyhow", - "brotli", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "html5ever", - "http", - "infer 0.19.0", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.3", - "proc-macro2", - "quote", - "regex", - "schemars 0.8.22", - "semver", - "serde", - "serde-untagged", - "serde_json", - "serde_with", - "swift-rs", - "thiserror 2.0.17", - "toml 0.9.8", - "url", - "urlpattern", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-winres" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd21509dd1fa9bd355dc29894a6ff10635880732396aa38c0066c1e6c1ab8074" -dependencies = [ - "embed-resource", - "toml 0.9.8", -] - -[[package]] -name = "tempfile" -version = "3.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" -dependencies = [ - "fastrand", - "getrandom 0.3.4", - "once_cell", - "rustix 1.1.2", - "windows-sys 0.61.2", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" -dependencies = [ - "thiserror-impl 2.0.17", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "thread_local" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "time" -version = "0.3.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" - -[[package]] -name = "time-macros" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" -dependencies = [ - "bytes", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.6.1", - "tokio-macros", - "tracing", - "windows-sys 0.61.2", -] - -[[package]] -name = "tokio-macros" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" -dependencies = [ - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "toml_edit 0.20.2", -] - -[[package]] -name = "toml" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" -dependencies = [ - "indexmap 2.12.0", - "serde_core", - "serde_spanned 1.0.3", - "toml_datetime 0.7.3", - "toml_parser", - "toml_writer", - "winnow 0.7.13", -] - -[[package]] -name = "toml_datetime" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.12.0", - "toml_datetime 0.6.3", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap 2.12.0", - "serde", - "serde_spanned 0.6.9", - "toml_datetime 0.6.3", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.23.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" -dependencies = [ - "indexmap 2.12.0", - "toml_datetime 0.7.3", - "toml_parser", - "winnow 0.7.13", -] - -[[package]] -name = "toml_parser" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" -dependencies = [ - "winnow 0.7.13", -] - -[[package]] -name = "toml_writer" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2" - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" -dependencies = [ - "bitflags 2.10.0", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-appender" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" -dependencies = [ - "crossbeam-channel", - "thiserror 1.0.69", - "time", - "tracing-subscriber", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "tracing-core" -version = "0.1.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-serde" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1" -dependencies = [ - "serde", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex-automata", - "serde", - "serde_json", - "sharded-slab", - "smallvec", - "thread_local", - "time", - "tracing", - "tracing-core", - "tracing-log", - "tracing-serde", -] - -[[package]] -name = "tray-icon" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d5572781bee8e3f994d7467084e1b1fd7a93ce66bd480f8156ba89dee55a2b" -dependencies = [ - "crossbeam-channel", - "dirs 6.0.0", - "libappindicator", - "muda", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.2", - "once_cell", - "png 0.17.16", - "serde", - "thiserror 2.0.17", - "windows-sys 0.60.2", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - -[[package]] -name = "typenum" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" - -[[package]] -name = "uds_windows" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" -dependencies = [ - "memoffset", - "tempfile", - "winapi", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicode-ident" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "url-escape" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e0ce4d1246d075ca5abec4b41d33e87a6054d08e2366b63205665e950db218" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "urlpattern" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" -dependencies = [ - "regex", - "serde", - "unic-ucd-ident", - "url", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" -dependencies = [ - "getrandom 0.3.4", - "js-sys", - "rand 0.9.2", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "versions" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd" -dependencies = [ - "itertools", - "nom", -] - -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.1+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" - -[[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.108", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.105" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wayland-backend" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35" -dependencies = [ - "cc", - "downcast-rs", - "rustix 1.1.2", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d" -dependencies = [ - "bitflags 2.10.0", - "rustix 1.1.2", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols" -version = "0.32.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901" -dependencies = [ - "bitflags 2.10.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3" -dependencies = [ - "proc-macro2", - "quick-xml 0.37.5", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142" -dependencies = [ - "dlib", - "log", - "pkg-config", -] - -[[package]] -name = "web-sys" -version = "0.3.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webkit2gtk" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps", -] - -[[package]] -name = "webpki-roots" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b130c0d2d49f8b6889abc456e795e82525204f27c42cf767cf0d7734e089b8" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webview2-com" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows", - "windows-core 0.61.2", - "windows-implement", - "windows-interface", -] - -[[package]] -name = "webview2-com-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "webview2-com-sys" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" -dependencies = [ - "thiserror 2.0.17", - "windows", - "windows-core 0.61.2", -] - -[[package]] -name = "wfd" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17bbfb155305bcb79144f568c3b796275ba4db5d5856597bc85acefe29b819" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "window-vibrancy" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" -dependencies = [ - "objc2 0.6.3", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.2", - "raw-window-handle 0.6.2", - "windows-sys 0.59.0", - "windows-version", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core 0.61.2", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-core" -version = "0.62.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "windows-interface" -version = "0.59.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", -] - -[[package]] -name = "windows-registry" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" -dependencies = [ - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-result" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-strings" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", -] - -[[package]] -name = "windows-sys" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link 0.2.1", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", -] - -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - -[[package]] -name = "windows-version" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4060a1da109b9d0326b7262c8e12c84df67cc0dbc9e33cf49e01ccc2eb63631" -dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "winreg" -version = "0.55.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" -dependencies = [ - "cfg-if", - "windows-sys 0.59.0", -] - -[[package]] -name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - -[[package]] -name = "writeable" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" - -[[package]] -name = "wry" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728b7d4c8ec8d81cab295e0b5b8a4c263c0d41a785fb8f8c4df284e5411140a2" -dependencies = [ - "base64 0.22.1", - "block2 0.6.2", - "cookie", - "crossbeam-channel", - "dirs 6.0.0", - "dpi", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http", - "javascriptcore-rs", - "jni", - "kuchikiki", - "libc", - "ndk", - "objc2 0.6.3", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.2", - "objc2-ui-kit", - "objc2-web-kit", - "once_cell", - "percent-encoding", - "raw-window-handle 0.6.2", - "sha2", - "soup3", - "tao-macros", - "thiserror 2.0.17", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "x25519-dalek" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" -dependencies = [ - "curve25519-dalek", - "rand_core 0.6.4", - "serde", - "zeroize", -] - -[[package]] -name = "xattr" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" -dependencies = [ - "libc", - "rustix 1.1.2", -] - -[[package]] -name = "yoke" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" -dependencies = [ - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", - "synstructure", -] - -[[package]] -name = "zbus" -version = "5.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b622b18155f7a93d1cd2dc8c01d2d6a44e08fb9ebb7b3f9e6ed101488bad6c91" -dependencies = [ - "async-broadcast", - "async-executor", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener", - "futures-core", - "futures-lite", - "hex", - "nix", - "ordered-stream", - "serde", - "serde_repr", - "tokio", - "tracing", - "uds_windows", - "uuid", - "windows-sys 0.61.2", - "winnow 0.7.13", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "5.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cdb94821ca8a87ca9c298b5d1cbd80e2a8b67115d99f6e4551ac49e42b6a314" -dependencies = [ - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "syn 2.0.108", - "zbus_names", - "zvariant", - "zvariant_utils", -] - -[[package]] -name = "zbus_names" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" -dependencies = [ - "serde", - "static_assertions", - "winnow 0.7.13", - "zvariant", -] - -[[package]] -name = "zerocopy" -version = "0.8.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "zerotrie" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.108", -] - -[[package]] -name = "zip" -version = "4.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1" -dependencies = [ - "arbitrary", - "crc32fast", - "indexmap 2.12.0", - "memchr", -] - -[[package]] -name = "zvariant" -version = "5.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be61892e4f2b1772727be11630a62664a1826b62efa43a6fe7449521cb8744c" -dependencies = [ - "endi", - "enumflags2", - "serde", - "url", - "winnow 0.7.13", - "zvariant_derive", - "zvariant_utils", -] - -[[package]] -name = "zvariant_derive" -version = "5.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da58575a1b2b20766513b1ec59d8e2e68db2745379f961f86650655e862d2006" -dependencies = [ - "proc-macro-crate 3.4.0", - "proc-macro2", - "quote", - "syn 2.0.108", - "zvariant_utils", -] - -[[package]] -name = "zvariant_utils" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6949d142f89f6916deca2232cf26a8afacf2b9fdc35ce766105e104478be599" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "syn 2.0.108", - "winnow 0.7.13", -] diff --git a/packages/hoppscotch-agent/src-tauri/Cargo.toml b/packages/hoppscotch-agent/src-tauri/Cargo.toml deleted file mode 100644 index c8809b0c..00000000 --- a/packages/hoppscotch-agent/src-tauri/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -[package] -name = "hoppscotch-agent" -version = "0.1.17" -description = "A cross-platform HTTP request agent for Hoppscotch for advanced request handling including custom headers, certificates, proxies, and local system integration." -authors = ["AndrewBastin", "CuriousCorrelation"] -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -name = "hoppscotch_agent_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -[build-dependencies] -tauri-build = { version = "2.5.2", features = [] } - -[dependencies] -tauri = { version = "2.9.3", features = ["tray-icon", "image-png"] } -tauri-plugin-shell = "2.3.3" -tauri-plugin-autostart = { version = "2.5.1", optional = true } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -tokio = { version = "1.48.0", features = ["full"] } -dashmap = { version = "6.1.0", features = ["serde"] } -axum = { version = "0.7.9" } -axum-extra = { version = "0.9.6", features = ["typed-header"] } -tower-http = { version = "0.6.6", features = ["cors"] } -tokio-util = "0.7.17" -uuid = { version = "1.18.1", features = [ "v4", "fast-rng" ] } -chrono = { version = "0.4", features = ["serde"] } -rand = "0.8.5" -tracing = "0.1.41" -tracing-subscriber = { version = "0.3.20", features = ["env-filter", "json", "fmt", "std", "time"] } -tracing-appender = "0.2.3" -relay = { git = "https://github.com/CuriousCorrelation/relay.git" } -thiserror = "1.0.69" -tauri-plugin-store = "2.4.1" -x25519-dalek = { version = "2.0.1", features = ["getrandom"] } -base16 = "0.2.1" -aes-gcm = { version = "0.10.3", features = ["aes"] } -tauri-plugin-updater = "2.9.0" -tauri-plugin-dialog = "2.4.2" -lazy_static = "1.5.0" -tauri-plugin-single-instance = "2.3.6" -tauri-plugin-http = { version = "2.5.4", features = ["gzip"] } -native-dialog = "0.7.0" -sha2 = "0.10.9" -file-rotate = "0.8.0" -dirs = "6.0.0" - -[target.'cfg(windows)'.dependencies] -tempfile = { version = "3.23.0" } -winreg = { version = "0.52.0" } - -[features] -default = ["tauri-plugin-autostart"] -portable = [] diff --git a/packages/hoppscotch-agent/src-tauri/build.rs b/packages/hoppscotch-agent/src-tauri/build.rs deleted file mode 100644 index 65c5c67e..00000000 --- a/packages/hoppscotch-agent/src-tauri/build.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - tauri_build::build(); - println!("cargo::rerun-if-env-changed=UPDATER_PUB_KEY"); - println!("cargo::rerun-if-env-changed=UPDATER_URL"); -} diff --git a/packages/hoppscotch-agent/src-tauri/capabilities/default.json b/packages/hoppscotch-agent/src-tauri/capabilities/default.json deleted file mode 100644 index 70c49c1c..00000000 --- a/packages/hoppscotch-agent/src-tauri/capabilities/default.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$schema": "../gen/schemas/desktop-schema.json", - "identifier": "default", - "description": "Capability for the main window", - "windows": ["main", "test"], - "permissions": [ - { - "identifier": "http:default", - "allow": [ - { - "url": "https://*.tauri.app" - }, - { - "url": "https://*.microsoft.*" - } - ] - }, - "core:default", - "shell:allow-open", - "core:window:allow-close", - "core:window:allow-hide", - "core:window:allow-set-focus", - "core:window:allow-set-always-on-top" - ] -} diff --git a/packages/hoppscotch-agent/src-tauri/icons/128x128.png b/packages/hoppscotch-agent/src-tauri/icons/128x128.png deleted file mode 100644 index 3778416d..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/128x128.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/128x128@2x.png b/packages/hoppscotch-agent/src-tauri/icons/128x128@2x.png deleted file mode 100644 index e5b88465..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/128x128@2x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/32x32.png b/packages/hoppscotch-agent/src-tauri/icons/32x32.png deleted file mode 100644 index e553d90f..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/32x32.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square107x107Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square107x107Logo.png deleted file mode 100644 index e8e31c23..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square107x107Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square142x142Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square142x142Logo.png deleted file mode 100644 index 938bf8dc..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square142x142Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square150x150Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square150x150Logo.png deleted file mode 100644 index 647408c5..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square150x150Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square284x284Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square284x284Logo.png deleted file mode 100644 index a898743c..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square284x284Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square30x30Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square30x30Logo.png deleted file mode 100644 index e1a1f772..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square30x30Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square310x310Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square310x310Logo.png deleted file mode 100644 index 69bf56b1..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square310x310Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square44x44Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square44x44Logo.png deleted file mode 100644 index bb5b8951..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square44x44Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square71x71Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square71x71Logo.png deleted file mode 100644 index 68541683..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square71x71Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/Square89x89Logo.png b/packages/hoppscotch-agent/src-tauri/icons/Square89x89Logo.png deleted file mode 100644 index 94a65e2a..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/Square89x89Logo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/StoreLogo.png b/packages/hoppscotch-agent/src-tauri/icons/StoreLogo.png deleted file mode 100644 index db4b61ba..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/StoreLogo.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index b334e000..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png deleted file mode 100644 index ea31185c..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png deleted file mode 100644 index b334e000..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-hdpi/ic_launcher_round.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index ee4bfd7d..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png deleted file mode 100644 index 794a5c62..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png deleted file mode 100644 index ee4bfd7d..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-mdpi/ic_launcher_round.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index fbef3290..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png deleted file mode 100644 index 9aee0bf9..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png deleted file mode 100644 index fbef3290..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xhdpi/ic_launcher_round.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d63d25bc..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 1443a0c1..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png deleted file mode 100644 index d63d25bc..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 3e0f1c39..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png deleted file mode 100644 index 5f449d41..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_foreground.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png b/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png deleted file mode 100644 index 3e0f1c39..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/android/mipmap-xxxhdpi/ic_launcher_round.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/icon.icns b/packages/hoppscotch-agent/src-tauri/icons/icon.icns deleted file mode 100644 index 293556d7..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/icon.icns and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/icon.ico b/packages/hoppscotch-agent/src-tauri/icons/icon.ico deleted file mode 100644 index 3e3249c9..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/icon.ico and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/icon.png b/packages/hoppscotch-agent/src-tauri/icons/icon.png deleted file mode 100644 index a91230bb..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/icon.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@1x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@1x.png deleted file mode 100644 index e63a928c..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@1x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@2x-1.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@2x-1.png deleted file mode 100644 index 8caffb7b..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@2x-1.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@2x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@2x.png deleted file mode 100644 index 8caffb7b..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@2x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@3x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@3x.png deleted file mode 100644 index c51270a0..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-20x20@3x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@1x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@1x.png deleted file mode 100644 index c89515b2..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@1x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@2x-1.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@2x-1.png deleted file mode 100644 index 4c23c687..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@2x-1.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@2x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@2x.png deleted file mode 100644 index 4c23c687..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@2x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@3x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@3x.png deleted file mode 100644 index cd117af2..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-29x29@3x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@1x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@1x.png deleted file mode 100644 index 8caffb7b..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@1x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@2x-1.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@2x-1.png deleted file mode 100644 index 9f5c51d7..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@2x-1.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@2x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@2x.png deleted file mode 100644 index 9f5c51d7..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@2x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@3x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@3x.png deleted file mode 100644 index 97738c12..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-40x40@3x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-512@2x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-512@2x.png deleted file mode 100644 index ed29af68..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-512@2x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-60x60@2x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-60x60@2x.png deleted file mode 100644 index 97738c12..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-60x60@2x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-60x60@3x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-60x60@3x.png deleted file mode 100644 index 6eb83336..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-60x60@3x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-76x76@1x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-76x76@1x.png deleted file mode 100644 index 38d7d795..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-76x76@1x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-76x76@2x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-76x76@2x.png deleted file mode 100644 index 4dbf0d79..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-76x76@2x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png b/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png deleted file mode 100644 index aed36133..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/ios/AppIcon-83.5x83.5@2x.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/icons/tray_icon.png b/packages/hoppscotch-agent/src-tauri/icons/tray_icon.png deleted file mode 100644 index b29857f4..00000000 Binary files a/packages/hoppscotch-agent/src-tauri/icons/tray_icon.png and /dev/null differ diff --git a/packages/hoppscotch-agent/src-tauri/src/command.rs b/packages/hoppscotch-agent/src-tauri/src/command.rs deleted file mode 100644 index 40de8c5b..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/command.rs +++ /dev/null @@ -1,40 +0,0 @@ -use std::sync::Arc; - -use crate::{ - model::{MaskedRegistration, RegistrationsList}, - state::AppState, - util::generate_auth_key_hash, -}; - -#[tauri::command] -#[tracing::instrument(skip(state))] -pub async fn get_otp(state: tauri::State<'_, Arc>) -> Result, ()> { - tracing::debug!("Retrieving current OTP"); - let otp = state.active_registration_code.read().await.clone(); - if otp.is_some() { - tracing::debug!("OTP found"); - } else { - tracing::debug!("No active OTP"); - } - Ok(otp) -} - -#[tauri::command] -#[tracing::instrument(skip(state))] -pub fn list_registrations(state: tauri::State<'_, Arc>) -> Result { - tracing::debug!("Retrieving registrations list"); - - let masked_registrations = state - .get_registrations() - .iter() - .map(|entry| MaskedRegistration { - registered_at: entry.value().registered_at, - auth_key_hash: generate_auth_key_hash(entry.key()), - }) - .collect(); - - Ok(RegistrationsList { - registrations: masked_registrations, - total: state.get_registrations().len(), - }) -} diff --git a/packages/hoppscotch-agent/src-tauri/src/controller.rs b/packages/hoppscotch-agent/src-tauri/src/controller.rs deleted file mode 100644 index 42f26217..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/controller.rs +++ /dev/null @@ -1,399 +0,0 @@ -use std::sync::Arc; - -use axum::{ - body::Bytes, - extract::{Path, State}, - http::HeaderMap, - Json, -}; -use axum_extra::{ - headers::{authorization::Bearer, Authorization}, - TypedHeader, -}; -use chrono::Utc; -use rand::Rng; -use serde_json::json; -use tauri::{AppHandle, Emitter}; -use uuid::Uuid; -use x25519_dalek::{EphemeralSecret, PublicKey}; - -use crate::{ - error::{AgentError, AgentResult}, - global::NONCE, - model::{ - AuthKeyResponse, ConfirmedRegistrationRequest, HandshakeResponse, LogEntry, LogLevel, - MaskedRegistration, Registration, - }, - state::AppState, - util::{generate_auth_key_hash, EncryptedJson}, -}; - -#[tracing::instrument] -fn generate_otp() -> String { - let otp: u32 = rand::thread_rng().gen_range(0..1_000_000); - let formatted = format!("{:06}", otp); - tracing::debug!("Generated OTP: {}", formatted); - formatted -} - -#[tracing::instrument(skip(app_handle))] -pub async fn handshake( - State((_, app_handle)): State<(Arc, AppHandle)>, -) -> AgentResult> { - tracing::info!("Processing handshake request"); - let response = HandshakeResponse { - status: "success".to_string(), - __hoppscotch__agent__: true, - agent_version: app_handle.package_info().version.to_string(), - }; - tracing::info!("Handshake successful"); - Ok(Json(response)) -} - -#[tracing::instrument(skip(state, app_handle))] -pub async fn receive_registration( - State((state, app_handle)): State<(Arc, AppHandle)>, -) -> AgentResult> { - let otp = generate_otp(); - tracing::info!("Generated new registration OTP"); - - let mut active_registration_code = state.active_registration_code.write().await; - - if !active_registration_code.is_none() { - tracing::warn!("Registration attempt while another registration is active"); - return Ok(Json( - json!({ "message": "There is already an existing registration happening" }), - )); - } - - *active_registration_code = Some(otp.clone()); - - match app_handle.emit("registration-received", otp) { - Ok(_) => { - tracing::info!("Registration event emitted successfully"); - Ok(Json( - json!({ "message": "Registration received and stored" }), - )) - } - Err(e) => { - tracing::error!("Failed to emit registration event: {}", e); - Err(AgentError::InternalServerError) - } - } -} - -#[tracing::instrument(skip(state, _app_handle))] -pub async fn registration( - State((state, _app_handle)): State<(Arc, AppHandle)>, - TypedHeader(auth_header): TypedHeader>, -) -> AgentResult> { - let token = auth_header.token(); - - if !state.validate_access(token) { - tracing::warn!("Unauthorized attempt to list registrations"); - return Err(AgentError::Unauthorized); - } - - let registration = state - .get_registration(token) - .ok_or(AgentError::Unauthorized)?; - - let key_b16 = registration.shared_secret_b16; - - let registration = MaskedRegistration { - registered_at: registration.registered_at, - auth_key_hash: generate_auth_key_hash(token), - }; - - tracing::info!("Successfully retrieved registrations list"); - Ok(EncryptedJson { - key_b16, - data: registration, - }) -} - -#[tracing::instrument(skip(state, app_handle), fields(auth_key))] -pub async fn verify_registration( - State((state, app_handle)): State<(Arc, AppHandle)>, - Json(confirmed_registration): Json, -) -> AgentResult> { - tracing::info!("Verifying registration request"); - - if !state - .validate_registration(&confirmed_registration.registration) - .await - { - tracing::warn!("Invalid registration attempt"); - return Err(AgentError::InvalidRegistration); - } - - let auth_key = Uuid::new_v4().to_string(); - let created_at = Utc::now(); - - tracing::Span::current().record("auth_key", &auth_key.as_str()); - - let auth_key_copy = auth_key.clone(); - let secret_key = EphemeralSecret::random(); - let public_key = PublicKey::from(&secret_key); - - let their_public_key = { - let public_key_slice: &[u8; 32] = - &base16::decode(&confirmed_registration.client_public_key_b16) - .map_err(|_| AgentError::InvalidClientPublicKey)?[0..32] - .try_into() - .map_err(|_| AgentError::InvalidClientPublicKey)?; - - PublicKey::from(public_key_slice.to_owned()) - }; - - let shared_secret = secret_key.diffie_hellman(&their_public_key); - - if let Err(e) = state.update_registrations(app_handle.clone(), |regs| { - regs.insert( - auth_key_copy, - Registration { - registered_at: created_at, - shared_secret_b16: base16::encode_lower(shared_secret.as_bytes()), - }, - ); - }) { - tracing::error!("Failed to update registrations: {:?}", e); - return Err(e); - } - - let auth_payload = json!({ - "auth_key": auth_key, - "created_at": created_at - }); - - if let Err(e) = app_handle.emit("authenticated", &auth_payload) { - tracing::error!("Failed to emit authenticated event: {:?}", e); - return Err(AgentError::InternalServerError); - } - - let _ = state.clear_active_registration().await; - - tracing::info!("Registration verified successfully"); - Ok(Json(AuthKeyResponse { - auth_key, - created_at, - agent_public_key_b16: base16::encode_lower(public_key.as_bytes()), - })) -} - -#[tracing::instrument(skip(state, app_handle), fields(auth_key = %auth_key))] -pub async fn delete_registration( - State((state, app_handle)): State<(Arc, AppHandle)>, - TypedHeader(auth_header): TypedHeader>, - Path(auth_key): Path, -) -> AgentResult> { - if !state.validate_access(auth_header.token()) { - tracing::warn!("Unauthorized deletion attempt"); - return Err(AgentError::Unauthorized); - } - - let _removed = state.update_registrations(app_handle.clone(), |regs| { - regs.remove(&auth_key); - })?; - - tracing::info!("Registration deleted successfully"); - let message = format!("{} registration deleted successfully", auth_key); - Ok(Json(json!({ "message": message }))) -} - -#[tracing::instrument(skip(state, body, _app_handle), fields(req_id))] -pub async fn execute( - State((state, _app_handle)): State<(Arc, AppHandle)>, - TypedHeader(auth_header): TypedHeader>, - headers: HeaderMap, - body: Bytes, -) -> AgentResult> { - let nonce = match headers.get(NONCE) { - Some(n) => match n.to_str() { - Ok(n) => n, - Err(_) => { - tracing::warn!("Invalid nonce header"); - return Err(AgentError::Unauthorized); - } - }, - None => { - tracing::warn!("Missing nonce header"); - return Err(AgentError::Unauthorized); - } - }; - - let request = match state.validate_access_and_get_data::( - auth_header.token(), - nonce, - &body, - ) { - Some(r) => r, - None => { - tracing::warn!("Invalid access or data"); - return Err(AgentError::Unauthorized); - } - }; - - let request_id = request.id; - - tracing::Span::current().record("request_id", &request_id); - - let reg_info = match state.get_registration(auth_header.token()) { - Some(r) => r, - None => { - tracing::warn!("Registration info not found"); - return Err(AgentError::Unauthorized); - } - }; - - Ok(relay::execute(request) - .await - .map(|response| EncryptedJson { - key_b16: reg_info.shared_secret_b16, - data: response, - })?) -} - -/// Provides a way for registered clients to check if their -/// registration still holds, this route is supposed to return -/// an encrypted `true` value if the given auth_key is good. -/// Since its encrypted with the shared secret established during -/// registration, the client also needs the shared secret to verify -/// if the read fails, or the auth_key didn't validate and this route returns -/// undefined, we can count on the registration not being valid anymore. -#[tracing::instrument(skip(state, _app_handle))] -pub async fn registered_handshake( - State((state, _app_handle)): State<(Arc, AppHandle)>, - TypedHeader(auth_header): TypedHeader>, -) -> AgentResult> { - let reg_info = state.get_registration(auth_header.token()); - - match reg_info { - Some(reg) => { - tracing::info!("Handshake successful"); - Ok(EncryptedJson { - key_b16: reg.shared_secret_b16, - data: json!(true), - }) - } - None => { - tracing::warn!("Unauthorized handshake attempt"); - Err(AgentError::Unauthorized) - } - } -} - -#[tracing::instrument(skip(state, _app_handle), fields(request_id = %request_id))] -pub async fn cancel( - State((state, _app_handle)): State<(Arc, AppHandle)>, - TypedHeader(auth_header): TypedHeader>, - Path(request_id): Path, -) -> AgentResult> { - if !state.validate_access(auth_header.token()) { - tracing::warn!("Unauthorized cancellation attempt"); - return Err(AgentError::Unauthorized); - } - - if let Ok(()) = relay::cancel(request_id.try_into().unwrap()).await { - tracing::info!("Request cancelled successfully"); - Ok(Json(json!({"message": "Request cancelled successfully"}))) - } else { - tracing::warn!("Request not found"); - Err(AgentError::RequestNotFound) - } -} - -#[tracing::instrument(skip_all)] -pub async fn log_sink( - State((state, _app_handle)): State<(Arc, AppHandle)>, - TypedHeader(auth_header): TypedHeader>, - headers: HeaderMap, - body: Bytes, -) -> AgentResult> { - if !state.validate_access(auth_header.token()) { - tracing::warn!("Unauthorized log sink access attempt"); - return Err(AgentError::Unauthorized); - } - - let nonce = match headers.get(NONCE) { - Some(n) => match n.to_str() { - Ok(n) => n, - Err(_) => { - tracing::warn!("Invalid nonce header"); - return Err(AgentError::Unauthorized); - } - }, - None => { - tracing::warn!("Missing nonce header"); - return Err(AgentError::Unauthorized); - } - }; - - let log_entry: LogEntry = - match state.validate_access_and_get_data(auth_header.token(), nonce, &body) { - Some(entry) => entry, - None => { - tracing::warn!("Failed to decrypt or parse log entry"); - return Err(AgentError::BadRequest("Invalid log entry format".into())); - } - }; - - let metadata_str = log_entry - .metadata - .map(|m| m.to_string()) - .unwrap_or_default(); - - let correlation = log_entry.correlation_id.unwrap_or_default(); - - match log_entry.level { - LogLevel::Debug => { - tracing::debug!( - timestamp = %log_entry.timestamp, - context = %log_entry.context, - source = %log_entry.source, - metadata = %metadata_str, - correlation_id = %correlation, - "{}", - log_entry.message - ); - } - LogLevel::Info => { - tracing::info!( - timestamp = %log_entry.timestamp, - context = %log_entry.context, - source = %log_entry.source, - metadata = %metadata_str, - correlation_id = %correlation, - "{}", - log_entry.message - ); - } - LogLevel::Warn => { - tracing::warn!( - timestamp = %log_entry.timestamp, - context = %log_entry.context, - source = %log_entry.source, - metadata = %metadata_str, - correlation_id = %correlation, - "{}", - log_entry.message - ); - } - LogLevel::Error => { - tracing::error!( - timestamp = %log_entry.timestamp, - context = %log_entry.context, - source = %log_entry.source, - metadata = %metadata_str, - correlation_id = %correlation, - "{}", - log_entry.message - ); - } - } - - Ok(Json(json!({ - "status": "success", - "message": "Log entry processed" - }))) -} diff --git a/packages/hoppscotch-agent/src-tauri/src/dialog.rs b/packages/hoppscotch-agent/src-tauri/src/dialog.rs deleted file mode 100644 index e4967b43..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/dialog.rs +++ /dev/null @@ -1,58 +0,0 @@ -use native_dialog::{MessageDialog, MessageType}; - -pub fn panic(msg: &str) { - const FATAL_ERROR: &str = "Fatal error"; - - MessageDialog::new() - .set_type(MessageType::Error) - .set_title(FATAL_ERROR) - .set_text(msg) - .show_alert() - .unwrap_or_default(); - - tracing::error!("{}: {}", FATAL_ERROR, msg); - - panic!("{}: {}", FATAL_ERROR, msg); -} - -pub fn info(msg: &str) { - tracing::info!("{}", msg); - - MessageDialog::new() - .set_type(MessageType::Info) - .set_title("Info") - .set_text(msg) - .show_alert() - .unwrap_or_default(); -} - -pub fn warn(msg: &str) { - tracing::warn!("{}", msg); - - MessageDialog::new() - .set_type(MessageType::Warning) - .set_title("Warning") - .set_text(msg) - .show_alert() - .unwrap_or_default(); -} - -pub fn error(msg: &str) { - tracing::error!("{}", msg); - - MessageDialog::new() - .set_type(MessageType::Error) - .set_title("Error") - .set_text(msg) - .show_alert() - .unwrap_or_default(); -} - -pub fn confirm(title: &str, msg: &str, icon: MessageType) -> bool { - MessageDialog::new() - .set_type(icon) - .set_title(title) - .set_text(msg) - .show_confirm() - .unwrap_or_default() -} diff --git a/packages/hoppscotch-agent/src-tauri/src/error.rs b/packages/hoppscotch-agent/src-tauri/src/error.rs deleted file mode 100644 index b7ef4528..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/error.rs +++ /dev/null @@ -1,99 +0,0 @@ -use axum::{ - http::StatusCode, - response::{IntoResponse, Response}, - Json, -}; -use serde_json::json; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum AgentError { - #[error("FATAL: No `main` window found")] - NoMainWindow, - #[error("Tauri error: {0}")] - Tauri(#[from] tauri::Error), - #[error("Invalid Registration")] - InvalidRegistration, - #[error("Invalid Client Public Key")] - InvalidClientPublicKey, - #[error("Unauthorized")] - Unauthorized, - #[error("Request not found or already completed")] - RequestNotFound, - #[error("Internal server error")] - InternalServerError, - #[error("Invalid request: {0}")] - BadRequest(String), - #[error("Client certificate error")] - ClientCertError, - #[error("Root certificate error")] - RootCertError, - #[error("Invalid method")] - InvalidMethod, - #[error("Invalid URL")] - InvalidUrl, - #[error("Invalid headers")] - InvalidHeaders, - #[error("Request run error: {0}")] - RequestRunError(String), - #[error("Request cancelled")] - RequestCancelled, - #[error("Failed to clear registrations")] - RegistrationClearError, - #[error("Failed to insert registrations")] - RegistrationInsertError, - #[error("Failed to save registrations to store")] - RegistrationSaveError, - #[error("Serde error: {0}")] - Serde(#[from] serde_json::Error), - #[error("Store error: {0}")] - TauriPluginStore(#[from] tauri_plugin_store::Error), - #[error("Relay error: {0}")] - Relay(#[from] relay::error::RelayError), - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - #[error("Log init error: {0}")] - LogInit(String), - #[error("Log init global error: {0}")] - LogInitGlobal(#[from] tracing::subscriber::SetGlobalDefaultError), -} - -impl From for AgentError { - fn from(err: tracing_appender::rolling::InitError) -> Self { - AgentError::LogInit(err.to_string()) - } -} - -impl IntoResponse for AgentError { - fn into_response(self) -> Response { - let (status, error_message) = match self { - AgentError::InvalidRegistration => (StatusCode::BAD_REQUEST, self.to_string()), - AgentError::InvalidClientPublicKey => (StatusCode::BAD_REQUEST, self.to_string()), - AgentError::Unauthorized => (StatusCode::UNAUTHORIZED, self.to_string()), - AgentError::RequestNotFound => (StatusCode::NOT_FOUND, self.to_string()), - AgentError::InternalServerError => { - (StatusCode::INTERNAL_SERVER_ERROR, self.to_string()) - } - AgentError::BadRequest(msg) => (StatusCode::BAD_REQUEST, msg), - AgentError::ClientCertError => (StatusCode::BAD_REQUEST, self.to_string()), - AgentError::RootCertError => (StatusCode::BAD_REQUEST, self.to_string()), - AgentError::InvalidMethod => (StatusCode::BAD_REQUEST, self.to_string()), - AgentError::InvalidUrl => (StatusCode::BAD_REQUEST, self.to_string()), - AgentError::InvalidHeaders => (StatusCode::BAD_REQUEST, self.to_string()), - AgentError::RequestRunError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg), - AgentError::RequestCancelled => (StatusCode::BAD_REQUEST, self.to_string()), - _ => ( - StatusCode::INTERNAL_SERVER_ERROR, - "Internal Server Error".to_string(), - ), - }; - - let body = Json(json!({ - "error": error_message, - })); - - (status, body).into_response() - } -} - -pub type AgentResult = std::result::Result; diff --git a/packages/hoppscotch-agent/src-tauri/src/global.rs b/packages/hoppscotch-agent/src-tauri/src/global.rs deleted file mode 100644 index 002729db..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/global.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub const AGENT_STORE: &str = "app_data.bin"; -pub const REGISTRATIONS: &str = "registrations"; -pub const NONCE: &str = "X-Hopp-Nonce"; diff --git a/packages/hoppscotch-agent/src-tauri/src/lib.rs b/packages/hoppscotch-agent/src-tauri/src/lib.rs deleted file mode 100644 index 145d39d7..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/lib.rs +++ /dev/null @@ -1,260 +0,0 @@ -pub mod command; -pub mod controller; -pub mod dialog; -pub mod error; -pub mod global; -pub mod logger; -pub mod model; -pub mod route; -pub mod server; -pub mod state; -pub mod tray; -pub mod updater; -pub mod util; -pub mod webview; - -use std::sync::Arc; -use tauri::{AppHandle, Emitter, Listener, Manager, WebviewWindowBuilder}; -use tauri_plugin_updater::UpdaterExt; -use tokio_util::sync::CancellationToken; - -use error::{AgentError, AgentResult}; -use model::Payload; -use state::AppState; - -pub const HOPPSCOTCH_AGENT_IDENTIFIER: &str = "io.hoppscotch.agent"; - -#[tracing::instrument(skip(app_handle))] -fn create_main_window(app_handle: &AppHandle) -> AgentResult<()> { - tracing::info!("Creating main application window"); - - let main = &app_handle - .config() - .app - .windows - .first() - .ok_or(AgentError::NoMainWindow)?; - - tracing::debug!("Building webview window from config"); - let window = WebviewWindowBuilder::from_config(app_handle, main)?.build()?; - - window.hide()?; - - tracing::info!("Main window created successfully"); - Ok(()) -} - -#[tracing::instrument(skip(app_handle))] -pub fn show_main_window(app_handle: &AppHandle) -> AgentResult<()> { - tracing::debug!("Attempting to show main window"); - if let Some(window) = app_handle.get_webview_window("main") { - window.show()?; - window.set_focus()?; - tracing::info!("Main window shown and focused"); - } - Ok(()) -} - -#[tracing::instrument(skip(app_handle))] -pub fn hide_main_window(app_handle: &AppHandle) -> AgentResult<()> { - tracing::debug!("Attempting to hide main window"); - if let Some(window) = app_handle.get_webview_window("main") { - window.hide()?; - tracing::info!("Main window hidden"); - } - Ok(()) -} - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - tracing::info!("Initializing Hoppscotch Agent"); - - // The installer takes care of installing `WebView`, - // this check is only required for portable variant. - #[cfg(all(feature = "portable", windows))] - { - tracing::debug!("Checking WebView initialization for portable Windows variant"); - webview::init_webview(); - } - - let cancellation_token = CancellationToken::new(); - let server_cancellation_token = cancellation_token.clone(); - - tracing::debug!("Building Tauri application"); - let builder = tauri::Builder::default() - // NOTE: Currently, plugins run in the order they were added in to the builder, - // so `tauri_plugin_single_instance` needs to be registered first. - // See: https://github.com/tauri-apps/plugins-workspace/tree/v2/plugins/single-instance - .plugin(tauri_plugin_single_instance::init(|app, args, cwd| { - tracing::info!( - app_name = %app.package_info().name, - "Single instance handler triggered" - ); - - if let Err(e) = app.emit("single-instance", Payload::new(args, cwd)) { - tracing::error!(error = %e, "Failed to emit single-instance event"); - } - - // Application is already running, bring it to foreground. - if let Err(e) = show_main_window(&app) { - tracing::error!(error = %e, "Failed to show window"); - } - })) - .plugin(tauri_plugin_store::Builder::new().build()) - .setup(move |app| { - tracing::info!("Setting up application"); - let app_handle = app.handle(); - - #[cfg(all(desktop, not(feature = "portable")))] - { - use tauri_plugin_autostart::MacosLauncher; - use tauri_plugin_autostart::ManagerExt; - - tracing::debug!("Configuring autostart for desktop variant"); - let _ = app.handle().plugin(tauri_plugin_autostart::init( - MacosLauncher::LaunchAgent, - None, - )); - - let autostart_manager = app.autolaunch(); - - tracing::info!( - enabled = autostart_manager.is_enabled().unwrap_or(false), - "Checking autostart status" - ); - - if !autostart_manager.is_enabled().unwrap_or(false) { - if let Err(e) = autostart_manager.enable() { - tracing::error!(error = %e, "Failed to enable autostart"); - } else { - tracing::info!("Autostart enabled successfully"); - } - } - }; - - #[cfg(desktop)] - { - tracing::debug!("Initializing desktop-specific features"); - let _ = app - .handle() - .plugin(tauri_plugin_updater::Builder::new().build()); - let _ = app.handle().plugin(tauri_plugin_dialog::init()); - - let updater = app.updater_builder().build().unwrap(); - let app_handle_ref = app_handle.clone(); - - tauri::async_runtime::spawn_blocking(|| { - tauri::async_runtime::block_on(async { - updater::check_and_install_updates(app_handle_ref, updater).await; - }) - }); - }; - - // Create and hide the main window during setup. - create_main_window(&app_handle)?; - - tracing::debug!("Initializing application state"); - let app_state = Arc::new(AppState::new(app_handle.clone())?); - app.manage(app_state.clone()); - - let server_cancellation_token = server_cancellation_token.clone(); - let server_app_handle = app_handle.clone(); - - tracing::debug!("Spawning server process"); - tauri::async_runtime::spawn(async move { - server::run_server(app_state, server_cancellation_token, server_app_handle).await; - }); - - #[cfg(all(desktop))] - { - tracing::debug!("Creating system tray"); - let handle = app.handle(); - tray::create_tray(handle)?; - } - - // Blocks the app from populating the macOS dock - #[cfg(target_os = "macos")] - { - tracing::debug!("Setting macOS activation policy"); - app_handle - .set_activation_policy(tauri::ActivationPolicy::Accessory) - .unwrap(); - }; - - let app_handle_ref = app_handle.clone(); - app_handle.listen("maximize-window", move |_| { - tracing::info!("Maximize window event triggered"); - if let Some(window) = app_handle_ref.get_webview_window("main") { - if let Err(e) = window.emit("show-otp-view", ()) { - tracing::error!("Failed to emit show-otp-view event: {}", e); - } - - if let Err(e) = show_main_window(&app_handle_ref) { - tracing::error!("Failed to maximize window: {}", e); - } - } - }); - - let app_handle_ref = app_handle.clone(); - app_handle.listen("registration-received", move |_| { - tracing::info!("Registration received event triggered"); - if let Err(e) = show_main_window(&app_handle_ref) { - tracing::error!(error = %e, "Failed to show window"); - } - }); - - tracing::info!("Application setup completed successfully"); - Ok(()) - }) - .manage(cancellation_token) - .on_window_event(|window, event| { - match &event { - tauri::WindowEvent::CloseRequested { api, .. } => { - tracing::info!("Window close requested"); - api.prevent_close(); - - if let Err(e) = window.hide() { - tracing::error!(error = %e, "Failed to hide window"); - } - - let app_state = window.state::>(); - let mut current_code = app_state.active_registration_code.blocking_write(); - if current_code.is_some() { - tracing::debug!("Clearing active registration code"); - *current_code = None; - } - - if let Err(e) = window.emit("window-hidden", ()) { - tracing::error!(error = %e, "Failed to emit window-hidden event"); - } - } - _ => { - tracing::debug!(event = ?event, "Window event received"); - } - }; - }) - .invoke_handler(tauri::generate_handler![ - command::get_otp, - command::list_registrations - ]); - - tracing::info!("Building Tauri application with context"); - let app = builder - .build(tauri::generate_context!()) - .expect("error while building tauri application"); - - tracing::info!("Running application"); - app.run(|app_handle, event| match event { - tauri::RunEvent::ExitRequested { api, code, .. } => { - if code.is_none() || matches!(code, Some(0)) { - tracing::info!("Exit requested, preventing immediate exit"); - api.prevent_exit(); - } else if code.is_some() { - tracing::info!("Exit with non-zero code requested, initiating shutdown"); - let state = app_handle.state::(); - state.cancel(); - } - } - _ => {} - }); -} diff --git a/packages/hoppscotch-agent/src-tauri/src/logger.rs b/packages/hoppscotch-agent/src-tauri/src/logger.rs deleted file mode 100644 index 610b6744..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/logger.rs +++ /dev/null @@ -1,53 +0,0 @@ -use std::path::PathBuf; - -use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate}; -use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; - -use crate::HOPPSCOTCH_AGENT_IDENTIFIER; - -pub struct LogGuard(pub tracing_appender::non_blocking::WorkerGuard); - -pub fn setup(log_dir: &PathBuf) -> Result> { - std::fs::create_dir_all(log_dir)?; - - let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| "debug".into()); - - let log_file_path = log_dir.join(&format!("{}.log", HOPPSCOTCH_AGENT_IDENTIFIER)); - tracing::info!(log_file_path =? &log_file_path); - - let file = FileRotate::new( - &log_file_path, - AppendCount::new(5), - ContentLimit::Bytes(10 * 1024 * 1024), - Compression::None, - None, - ); - - let (non_blocking, guard) = tracing_appender::non_blocking(file); - - let console_layer = fmt::layer() - .with_writer(std::io::stdout) - .with_thread_ids(true) - .with_thread_names(true) - .with_ansi(!cfg!(target_os = "windows")); - - let file_layer = fmt::layer() - .with_writer(non_blocking) - .with_ansi(false) - .with_thread_ids(true) - .with_thread_names(true) - .with_timer(tracing_subscriber::fmt::time::UtcTime::rfc_3339()); - - tracing_subscriber::registry() - .with(env_filter) - .with(file_layer) - .with(console_layer) - .init(); - - tracing::info!( - log_file = %log_file_path.display(), - "Logging initialized with rotating file" - ); - - Ok(LogGuard(guard)) -} diff --git a/packages/hoppscotch-agent/src-tauri/src/main.rs b/packages/hoppscotch-agent/src-tauri/src/main.rs deleted file mode 100644 index 146be728..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/main.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -use hoppscotch_agent_lib::{ - logger::{self, LogGuard}, - HOPPSCOTCH_AGENT_IDENTIFIER, -}; - -fn main() { - // Follows how `tauri` does this and exactly matches desktop's approach - // see: https://github.com/tauri-apps/tauri/blob/dev/crates/tauri/src/path/desktop.rs - let path = { - #[cfg(target_os = "macos")] - let path = - dirs::home_dir().map(|dir| dir.join("Library/Logs").join(HOPPSCOTCH_AGENT_IDENTIFIER)); - - #[cfg(not(target_os = "macos"))] - let path = - dirs::data_local_dir().map(|dir| dir.join(HOPPSCOTCH_AGENT_IDENTIFIER).join("logs")); - - path - }; - - let Some(log_file_path) = path else { - eprint!("Failed to setup logging!"); - - println!("Starting Hoppscotch Agent..."); - - return hoppscotch_agent_lib::run(); - }; - - let Ok(LogGuard(guard)) = logger::setup(&log_file_path) else { - eprint!("Failed to setup logging!"); - - println!("Starting Hoppscotch Agent..."); - - return hoppscotch_agent_lib::run(); - }; - - // This keeps the guard alive, this is scoped to `main` - // so it can only drop when the entire app exits, - // so safe to have it like this. - let _guard = guard; - - tracing::info!("Starting Hoppscotch Agent..."); - - hoppscotch_agent_lib::run() -} diff --git a/packages/hoppscotch-agent/src-tauri/src/model.rs b/packages/hoppscotch-agent/src-tauri/src/model.rs deleted file mode 100644 index 718422e9..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/model.rs +++ /dev/null @@ -1,110 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use sha2::{Digest, Sha256}; - -/// Describes one registered app instance -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Registration { - pub registered_at: DateTime, - - /// base16 (lowercase) encoded shared secret that the client - /// and agent established during registration that is used - /// to encrypt traffic between them - pub shared_secret_b16: String, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct MaskedRegistration { - pub registered_at: DateTime, - pub auth_key_hash: String, -} - -impl From<(&String, &Registration)> for MaskedRegistration { - fn from((key, registration): (&String, &Registration)) -> Self { - let hash = Sha256::digest(key.as_bytes()); - let short_hash = base16::encode_lower(&hash[..3]); - - Self { - registered_at: registration.registered_at, - auth_key_hash: short_hash, - } - } -} - -#[derive(Debug, Serialize)] -pub struct RegistrationsList { - pub registrations: Vec, - pub total: usize, -} - -/// Single instance payload. -#[derive(Clone, Serialize)] -pub struct Payload { - args: Vec, - cwd: String, -} - -impl Payload { - pub fn new(args: Vec, cwd: String) -> Self { - Self { args, cwd } - } -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct HandshakeResponse { - #[allow(non_snake_case)] - pub __hoppscotch__agent__: bool, - - pub status: String, - pub agent_version: String, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct ConfirmedRegistrationRequest { - pub registration: String, - - /// base16 (lowercase) encoded public key shared by the client - /// to the agent so that the agent can establish a shared secret - /// which will be used to encrypt traffic between agent - /// and client after registration - pub client_public_key_b16: String, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct AuthKeyResponse { - pub auth_key: String, - pub created_at: DateTime, - - /// base16 (lowercase) encoded public key shared by the - /// agent so that the client can establish a shared secret - /// which will be used to encrypt traffic between agent - /// and client after registration - pub agent_public_key_b16: String, -} - -/// A logger guard, managed by tauri runtime to make sure -/// logger doesn't get cleaned up or dropped during app's run time. -pub struct LogGuard(pub tracing_appender::non_blocking::WorkerGuard); - -#[derive(Debug, Deserialize)] -pub struct LogEntry { - pub timestamp: String, - pub level: LogLevel, - pub context: String, - pub message: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub metadata: Option, - pub source: String, - #[serde(skip_serializing_if = "Option::is_none")] - pub correlation_id: Option, -} - -#[derive(Debug, Deserialize, Clone, Copy)] -#[serde(rename_all = "UPPERCASE")] -pub enum LogLevel { - Debug, - Info, - Warn, - Error, -} diff --git a/packages/hoppscotch-agent/src-tauri/src/route.rs b/packages/hoppscotch-agent/src-tauri/src/route.rs deleted file mode 100644 index e6362565..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/route.rs +++ /dev/null @@ -1,34 +0,0 @@ -use axum::{ - routing::{delete, get, post}, - Router, -}; -use std::sync::Arc; -use tauri::AppHandle; - -use crate::{controller, state::AppState}; - -pub fn route(state: Arc, app_handle: AppHandle) -> Router { - Router::new() - .route("/handshake", get(controller::handshake)) - .route( - "/receive-registration", - post(controller::receive_registration), - ) - .route( - "/verify-registration", - post(controller::verify_registration), - ) - .route( - "/registered-handshake", - get(controller::registered_handshake), - ) - .route("/registration", get(controller::registration)) - .route( - "/registrations/:auth_key", - delete(controller::delete_registration), - ) - .route("/execute", post(controller::execute)) - .route("/cancel/:req_id", post(controller::cancel)) - .route("/log-sink", post(controller::log_sink)) - .with_state((state, app_handle)) -} diff --git a/packages/hoppscotch-agent/src-tauri/src/server.rs b/packages/hoppscotch-agent/src-tauri/src/server.rs deleted file mode 100644 index 33818477..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/server.rs +++ /dev/null @@ -1,50 +0,0 @@ -use axum::Router; -use std::sync::Arc; -use tokio_util::sync::CancellationToken; -use tower_http::cors::CorsLayer; - -use crate::route; -use crate::state::AppState; - -#[tracing::instrument(skip(state, cancellation_token, app_handle))] -pub async fn run_server( - state: Arc, - cancellation_token: CancellationToken, - app_handle: tauri::AppHandle, -) { - tracing::info!("Initializing server"); - let cors = CorsLayer::permissive(); - - let app = Router::new() - .merge(route::route(state, app_handle)) - .layer(cors); - - let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 9119)); - tracing::info!(address = %addr, "Starting server"); - - match tokio::net::TcpListener::bind(&addr).await { - Ok(listener) => { - tracing::info!(address = %addr, "Server bound successfully"); - - if let Err(e) = axum::serve(listener, app.into_make_service()) - .with_graceful_shutdown(async move { - cancellation_token.cancelled().await; - tracing::info!("Graceful shutdown initiated"); - }) - .await - { - tracing::error!(error = %e, "Server error occurred"); - return; - } - - tracing::info!("Server shut down successfully"); - } - Err(e) => { - tracing::error!( - error = %e, - address = %addr, - "Failed to bind server to address" - ); - } - } -} diff --git a/packages/hoppscotch-agent/src-tauri/src/state.rs b/packages/hoppscotch-agent/src-tauri/src/state.rs deleted file mode 100644 index 4bd211fb..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/state.rs +++ /dev/null @@ -1,277 +0,0 @@ -use aes_gcm::{aead::Aead, Aes256Gcm, KeyInit}; -use axum::body::Bytes; -use dashmap::DashMap; -use serde::de::DeserializeOwned; -use tauri_plugin_store::StoreExt; -use tokio::sync::RwLock; -use tokio_util::sync::CancellationToken; - -use crate::{ - error::{AgentError, AgentResult}, - global::{AGENT_STORE, REGISTRATIONS}, - model::Registration, -}; - -#[derive(Debug, Default)] -pub struct AppState { - /// The active registration code that is being registered. - pub active_registration_code: RwLock>, - - /// Cancellation Tokens for the running requests - pub cancellation_tokens: DashMap, - - /// Registrations against the agent, the key is the auth - /// token associated to the registration - registrations: DashMap, -} - -impl AppState { - #[tracing::instrument(skip(app_handle))] - pub fn new(app_handle: tauri::AppHandle) -> AgentResult { - tracing::info!("Initializing application state"); - let store = match app_handle.store(AGENT_STORE) { - Ok(store) => store, - Err(e) => { - tracing::error!("Failed to access app store: {}", e); - return Err(e.into()); - } - }; - - // Try loading and parsing registrations from the store, if that failed, - // load the default list - let registrations = store - .get(REGISTRATIONS) - .and_then(|val| serde_json::from_value(val.clone()).ok()) - .unwrap_or_else(|| { - tracing::debug!("No existing registrations found, initializing empty map"); - DashMap::new() - }); - - // Try to save the latest registrations list - let _ = store.set(REGISTRATIONS, serde_json::to_value(®istrations)?); - - if let Err(e) = store.save() { - tracing::error!("Failed to persist store changes: {}", e); - return Err(e.into()); - } - - tracing::info!("Application state initialized successfully"); - - Ok(Self { - active_registration_code: RwLock::new(None), - cancellation_tokens: DashMap::new(), - registrations, - }) - } - - /// Gets you a readonly reference to the registrations list - /// NOTE: Although DashMap API allows you to update the list from an immutable - /// reference, you shouldn't do it for registrations as `update_registrations` - /// performs save operation that needs to be done and should be used instead - #[tracing::instrument] - pub fn get_registrations(&self) -> &DashMap { - tracing::debug!("Retrieving registrations list"); - &self.registrations - } - - /// Provides you an opportunity to update the registrations list - /// and also persists the data to the disk. - /// This function bypasses `store.reload()` to avoid issues from stale or inconsistent - /// data on disk. By relying solely on the in-memory `self.registrations`, - /// we make sure that updates are applied based on the most recent changes in memory. - #[tracing::instrument(skip(self, app_handle, update_func))] - pub fn update_registrations( - &self, - app_handle: tauri::AppHandle, - update_func: impl FnOnce(&DashMap), - ) -> Result<(), AgentError> { - tracing::info!("Updating registrations"); - update_func(&self.registrations); - - let store = match app_handle.store(AGENT_STORE) { - Ok(store) => store, - Err(e) => { - tracing::error!("Failed to access app store: {}", e); - return Err(e.into()); - } - }; - - if store.has(REGISTRATIONS) { - tracing::debug!("Clearing existing registrations from store"); - // We've confirmed `REGISTRATIONS` exists in the store - if !store.delete(REGISTRATIONS) { - tracing::error!("Failed to clear existing registrations"); - return Err(AgentError::RegistrationClearError); - } - } else { - tracing::debug!("`REGISTRATIONS` key not found in store; continuing with update."); - } - - // Since we've established `self.registrations` as the source of truth, - // we avoid reloading the store from disk and instead choose to override it. - match serde_json::to_value(self.registrations.clone()) { - Ok(value) => { - let _ = store.set(REGISTRATIONS, value); - } - Err(e) => { - tracing::error!("Failed to serialize registrations: {}", e); - return Err(e.into()); - } - } - - // Explicitly save the changes - if let Err(e) = store.save() { - tracing::error!("Failed to persist store changes: {}", e); - return Err(e.into()); - } - - tracing::info!("Registrations updated successfully"); - Ok(()) - } - - /// Clear all the registrations - #[tracing::instrument(skip(self, app_handle))] - pub fn clear_registrations(&self, app_handle: tauri::AppHandle) -> Result<(), AgentError> { - tracing::info!("Clearing all registrations"); - self.update_registrations(app_handle, |registrations| registrations.clear())?; - tracing::info!("All registrations cleared successfully"); - Ok(()) - } - - #[tracing::instrument(skip(self))] - pub async fn clear_active_registration(&self) { - tracing::debug!("Clearing active registration code"); - let mut active_registration_code = self.active_registration_code.write().await; - *active_registration_code = None; - tracing::debug!("Active registration code cleared"); - } - - #[tracing::instrument(skip(self))] - pub async fn validate_registration(&self, registration: &str) -> bool { - tracing::debug!("Validating registration code"); - let is_valid = self.active_registration_code.read().await.as_deref() == Some(registration); - if is_valid { - tracing::info!("Registration code validated successfully"); - } else { - tracing::warn!("Invalid registration code provided"); - } - is_valid - } - - #[tracing::instrument(skip(self))] - pub fn remove_cancellation_token(&self, req_id: usize) -> Option<(usize, CancellationToken)> { - tracing::debug!(req_id, "Removing cancellation token"); - let result = self.cancellation_tokens.remove(&req_id); - if result.is_some() { - tracing::info!(req_id, "Cancellation token removed successfully"); - } else { - tracing::debug!(req_id, "No cancellation token found to remove"); - } - result - } - - #[tracing::instrument(skip(self))] - pub fn add_cancellation_token(&self, req_id: usize, cancellation_token: CancellationToken) { - tracing::debug!(req_id, "Adding new cancellation token"); - self.cancellation_tokens.insert(req_id, cancellation_token); - tracing::debug!(req_id, "Cancellation token added successfully"); - } - - #[tracing::instrument(skip(self))] - pub fn validate_access(&self, auth_key: &str) -> bool { - tracing::debug!(auth_key, "Validating access"); - let is_valid = self.registrations.get(auth_key).is_some(); - if is_valid { - tracing::info!(auth_key, "Access validated successfully"); - } else { - tracing::warn!(auth_key, "Invalid access attempt"); - } - is_valid - } - - #[tracing::instrument(skip(self, data))] - pub fn validate_access_and_get_data( - &self, - auth_key: &str, - nonce: &str, - data: &Bytes, - ) -> Option - where - T: DeserializeOwned, - { - tracing::debug!( - auth_key, - nonce_len = nonce.len(), - "Validating access and decrypting data" - ); - - let registration = match self.registrations.get(auth_key) { - Some(reg) => reg, - None => { - tracing::warn!(auth_key, "Registration not found"); - return None; - } - }; - - let key: [u8; 32] = match base16::decode(®istration.shared_secret_b16).ok()?[0..32] - .try_into() - .ok() - { - Some(k) => k, - None => { - tracing::error!(auth_key, "Failed to decode shared secret"); - return None; - } - }; - - let nonce: [u8; 12] = match base16::decode(nonce).ok()?[0..12].try_into().ok() { - Some(n) => n, - None => { - tracing::error!(auth_key, "Failed to decode nonce"); - return None; - } - }; - - let cipher = Aes256Gcm::new(&key.into()); - let data = data.iter().cloned().collect::>(); - - let plain_data = match cipher.decrypt(&nonce.into(), data.as_slice()) { - Ok(d) => d, - Err(e) => { - tracing::error!(auth_key, error = ?e, "Decryption failed"); - return None; - } - }; - - match serde_json::from_reader(plain_data.as_slice()) { - Ok(result) => { - tracing::info!(auth_key, "Data successfully decrypted and parsed"); - Some(result) - } - Err(e) => { - tracing::error!(auth_key, error = ?e, "Failed to parse decrypted data"); - None - } - } - } - - #[tracing::instrument(skip(self))] - pub fn get_registration(&self, auth_key: &str) -> Option { - tracing::debug!(auth_key, "Retrieving registration tracing::info"); - let result = self - .registrations - .get(auth_key) - .map(|reference| reference.value().clone()); - - if result.is_some() { - tracing::info!( - auth_key, - "Registration tracing::info retrieved successfully" - ); - } else { - tracing::debug!(auth_key, "No registration tracing::info found"); - } - - result - } -} diff --git a/packages/hoppscotch-agent/src-tauri/src/tray.rs b/packages/hoppscotch-agent/src-tauri/src/tray.rs deleted file mode 100644 index 5ae79009..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/tray.rs +++ /dev/null @@ -1,126 +0,0 @@ -use crate::{show_main_window, state::AppState}; -use lazy_static::lazy_static; -use std::sync::Arc; -use tauri::{ - image::Image, - menu::{MenuBuilder, MenuItem}, - tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, - AppHandle, Emitter, Manager, -}; - -const TRAY_ICON_DATA: &'static [u8] = include_bytes!("../icons/tray_icon.png"); - -lazy_static! { - static ref TRAY_ICON: Image<'static> = Image::from_bytes(TRAY_ICON_DATA).unwrap(); -} - -pub fn create_tray(app: &AppHandle) -> tauri::Result<()> { - let quit_i = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?; - let clear_registrations = MenuItem::with_id( - app, - "clear_registrations", - "Clear Registrations", - true, - None::<&str>, - )?; - let maximize_window = MenuItem::with_id( - app, - "maximize_window", - "Maximize Window", - true, - None::<&str>, - )?; - let show_registrations = MenuItem::with_id( - app, - "show_registrations", - "Show Registrations", - true, - None::<&str>, - )?; - - let pkg_info = app.package_info(); - let app_name = pkg_info.name.clone(); - let app_version = pkg_info.version.clone(); - - let app_name_item = MenuItem::with_id(app, "app_name", app_name, false, None::<&str>)?; - let app_version_item = MenuItem::with_id( - app, - "app_version", - format!("Version: {}", app_version), - false, - None::<&str>, - )?; - - let menu = MenuBuilder::new(app) - .item(&app_name_item) - .item(&app_version_item) - .separator() - .item(&maximize_window) - .separator() - .item(&clear_registrations) - .item(&show_registrations) - .separator() - .separator() - .item(&quit_i) - .build()?; - - let _ = TrayIconBuilder::with_id("hopp-tray") - .tooltip("Hoppscotch Agent") - .icon(if cfg!(target_os = "macos") { - TRAY_ICON.clone() - } else { - app.default_window_icon().unwrap().clone() - }) - .icon_as_template(cfg!(target_os = "macos")) - .menu(&menu) - .show_menu_on_left_click(true) - .on_menu_event(move |app, event| match event.id.as_ref() { - "quit" => { - tracing::info!("Exiting the agent..."); - // Exit with a specific code to allow actual exit. - app.exit(1); - } - "clear_registrations" => { - let app_state = app.state::>(); - - app_state - .clear_registrations(app.clone()) - .expect("Invariant violation: Failed to clear registrations"); - } - "show_registrations" => { - app.emit("show-registrations", ()).unwrap_or_else(|e| { - tracing::error!("Failed to emit show-registrations event: {}", e); - }); - if let Err(e) = show_main_window(&app) { - tracing::error!("Failed to show window: {}", e); - } - } - "maximize_window" => { - app.emit("maximize-window", ()).unwrap_or_else(|e| { - tracing::error!("Failed to emit maximize-window event: {}", e); - }); - if let Err(e) = show_main_window(&app) { - tracing::error!("Failed to maximize window: {}", e); - } - } - _ => { - tracing::warn!("Unhandled menu event: {:?}", event.id); - } - }) - .on_tray_icon_event(|tray, event| { - if let TrayIconEvent::Click { - button: MouseButton::Left, - button_state: MouseButtonState::Up, - .. - } = event - { - let app = tray.app_handle(); - if let Err(e) = show_main_window(&app) { - tracing::error!("Failed to show window from tray: {}", e); - } - } - }) - .build(app); - - Ok(()) -} diff --git a/packages/hoppscotch-agent/src-tauri/src/updater.rs b/packages/hoppscotch-agent/src-tauri/src/updater.rs deleted file mode 100644 index 48c6d2ad..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/updater.rs +++ /dev/null @@ -1,67 +0,0 @@ -use tauri::Manager; -use tauri_plugin_dialog::DialogExt; -use tauri_plugin_dialog::MessageDialogButtons; -use tauri_plugin_dialog::MessageDialogKind; - -#[cfg(feature = "portable")] -use {crate::dialog, crate::util, native_dialog::MessageType}; - -pub async fn check_and_install_updates( - app: tauri::AppHandle, - updater: tauri_plugin_updater::Updater, -) { - let update = updater.check().await; - - if let Ok(Some(update)) = update { - #[cfg(not(feature = "portable"))] - { - let do_update = app - .dialog() - .message(format!( - "Update to {} is available!{}", - update.version, - update - .body - .clone() - .map(|body| format!("\n\nRelease Notes: {}", body)) - .unwrap_or("".into()) - )) - .title("Hoppscotch Agent Update Available") - .kind(MessageDialogKind::Info) - .buttons(MessageDialogButtons::OkCancelCustom( - "Update".to_string(), - "Cancel".to_string(), - )) - .blocking_show(); - - if do_update { - let _ = update.download_and_install(|_, _| {}, || {}).await; - - tauri::process::restart(&app.env()); - } - } - #[cfg(feature = "portable")] - { - let download_url = "https://hoppscotch.com/download"; - let message = format!( - "An update (version {}) is available for the Hoppscotch Agent.\n\nPlease download the latest portable version from our website.", - update.version - ); - - dialog::info(&message); - - if dialog::confirm( - "Open Download Page", - "Would you like to open the download page in your browser?", - MessageType::Info, - ) { - if let None = util::open_link(download_url) { - dialog::error(&format!( - "Failed to open download page. Please visit {}", - download_url - )); - } - } - } - } -} diff --git a/packages/hoppscotch-agent/src-tauri/src/util.rs b/packages/hoppscotch-agent/src-tauri/src/util.rs deleted file mode 100644 index 56b3fb02..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/util.rs +++ /dev/null @@ -1,94 +0,0 @@ -use std::process::{Command, Stdio}; - -use aes_gcm::{aead::Aead, AeadCore, Aes256Gcm, KeyInit}; -use axum::{ - body::Body, - response::{IntoResponse, Response}, -}; -use rand::rngs::OsRng; -use serde::Serialize; -use sha2::{Digest, Sha256}; - -use crate::global::NONCE; - -pub fn generate_auth_key_hash(auth_key: &str) -> String { - let hash = Sha256::digest(auth_key.as_bytes()); - base16::encode_lower(&hash[..3]) -} - -pub fn open_link(link: &str) -> Option<()> { - let null = Stdio::null(); - - #[cfg(target_os = "windows")] - { - Command::new("rundll32") - .args(["url.dll,FileProtocolHandler", link]) - .stdout(null) - .spawn() - .ok() - .map(|_| ()) - } - - #[cfg(target_os = "macos")] - { - Command::new("open") - .arg(link) - .stdout(null) - .spawn() - .ok() - .map(|_| ()) - } - - #[cfg(target_os = "linux")] - { - Command::new("xdg-open") - .arg(link) - .stdout(null) - .spawn() - .ok() - .map(|_| ()) - } - - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - None - } -} - -#[derive(Debug)] -pub struct EncryptedJson { - pub key_b16: String, - pub data: T, -} - -impl IntoResponse for EncryptedJson -where - T: Serialize, -{ - fn into_response(self) -> Response { - let serialized_response = serde_json::to_vec(&self.data) - .expect("Failed serializing response to vec for encryption"); - - let key: [u8; 32] = base16::decode(&self.key_b16).unwrap()[0..32] - .try_into() - .unwrap(); - - let cipher = Aes256Gcm::new(&key.into()); - - let nonce = Aes256Gcm::generate_nonce(&mut OsRng); - - let nonce_b16 = base16::encode_lower(&nonce); - - let encrypted_response = cipher - .encrypt(&nonce, serialized_response.as_slice()) - .expect("Failed encrypting response"); - - let mut response = Response::new(Body::from(encrypted_response)); - let response_headers = response.headers_mut(); - - response_headers.insert("Content-Type", "application/octet-stream".parse().unwrap()); - response_headers.insert(NONCE, nonce_b16.parse().unwrap()); - - response - } -} diff --git a/packages/hoppscotch-agent/src-tauri/src/webview/error.rs b/packages/hoppscotch-agent/src-tauri/src/webview/error.rs deleted file mode 100644 index 7bfeff52..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/webview/error.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::io; - -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum WebViewError { - #[error("Failed to open URL: {0}")] - UrlOpen(#[from] io::Error), - #[error("Failed to download WebView2 installer: {0}")] - Download(String), - #[error("WebView2 installation failed: {0}")] - Installation(String), - #[error("Failed during request: {0}")] - Request(#[from] tauri_plugin_http::reqwest::Error), -} diff --git a/packages/hoppscotch-agent/src-tauri/src/webview/mod.rs b/packages/hoppscotch-agent/src-tauri/src/webview/mod.rs deleted file mode 100644 index b303b056..00000000 --- a/packages/hoppscotch-agent/src-tauri/src/webview/mod.rs +++ /dev/null @@ -1,212 +0,0 @@ -/// The WebView2 Runtime is a critical dependency for Tauri applications on Windows. -/// We need to check for its presence, see [Source: GitHub Issue #59 - Portable windows build](https://github.com/tauri-apps/tauri-action/issues/59#issuecomment-827142638) -/// -/// > "Tauri requires an installer if you define app resources, external binaries or running on environments that do not have Webview2 runtime installed. So I don't think it's a good idea to have a "portable" option since a Tauri binary itself isn't 100% portable." -/// -/// The approach for checking WebView2 installation is based on Microsoft's official documentation, which states: -/// -/// > ###### Detect if a WebView2 Runtime is already installed -/// > -/// > To verify that a WebView2 Runtime is installed, use one of the following approaches: -/// > -/// > * Approach 1: Inspect the `pv (REG_SZ)` regkey for the WebView2 Runtime at both of the following registry locations. The `HKEY_LOCAL_MACHINE` regkey is used for _per-machine_ install. The `HKEY_CURRENT_USER` regkey is used for _per-user_ install. -/// > -/// > For WebView2 applications, at least one of these regkeys must be present and defined with a version greater than 0.0.0.0. If neither regkey exists, or if only one of these regkeys exists but its value is `null`, an empty string, or 0.0.0.0, this means that the WebView2 Runtime isn't installed on the client. Inspect these regkeys to detect whether the WebView2 Runtime is installed, and to get the version of the WebView2 Runtime. Find `pv (REG_SZ)` at the following two locations. -/// > -/// > The two registry locations to inspect on 64-bit Windows: -/// > -/// > ``` -/// > HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5} -/// > -/// > HKEY_CURRENT_USER\Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5} -/// > ``` -/// > -/// > The two registry locations to inspect on 32-bit Windows: -/// > -/// > ``` -/// > HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5} -/// > -/// > HKEY_CURRENT_USER\Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5} -/// > ``` -/// > -/// > * Approach 2: Run [GetAvailableCoreWebView2BrowserVersionString](/microsoft-edge/webview2/reference/win32/webview2-idl#getavailablecorewebview2browserversionstring) and evaluate whether the `versionInfo` is `nullptr`. `nullptr` indicates that the WebView2 Runtime isn't installed. This API returns version information for the WebView2 Runtime or for any installed preview channels of Microsoft Edge (Beta, Dev, or Canary). -/// -/// See: https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution?tabs=dotnetcsharp#detect-if-a-webview2-runtime-is-already-installed -/// -/// Our implementation uses Approach 1, checking both the 32-bit (WOW6432Node) and 64-bit registry locations -/// to make sure we have critical dependency compatibility with different system architectures. -pub mod error; - -use std::{io, ops::Not}; - -use native_dialog::MessageType; - -use crate::{dialog, util}; -use error::WebViewError; - -#[cfg(windows)] -use { - std::io::Cursor, - std::process::Command, - tauri_plugin_http::reqwest, - tempfile::TempDir, - winreg::{ - enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}, - RegKey, - }, -}; - -const TAURI_WEBVIEW_REF: &str = "https://v2.tauri.app/references/webview-versions/"; -const WINDOWS_WEBVIEW_REF: &str = - "https://developer.microsoft.com/microsoft-edge/webview2/#download-section"; - -fn is_available() -> bool { - #[cfg(windows)] - { - const KEY_WOW64: &str = r"SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"; - const KEY: &str = - r"SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"; - - let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - let hkcu = RegKey::predef(HKEY_CURRENT_USER); - - [ - hklm.open_subkey(KEY_WOW64), - hkcu.open_subkey(KEY_WOW64), - hklm.open_subkey(KEY), - hkcu.open_subkey(KEY), - ] - .into_iter() - .any(|result| result.is_ok()) - } - - #[cfg(not(windows))] - { - true - } -} - -fn open_install_website() -> Result<(), WebViewError> { - let url = if cfg!(windows) { - WINDOWS_WEBVIEW_REF - } else { - TAURI_WEBVIEW_REF - }; - - util::open_link(url).map(|_| ()).ok_or_else(|| { - WebViewError::UrlOpen(io::Error::new( - io::ErrorKind::Other, - "Failed to open browser to WebView download section", - )) - }) -} - -#[cfg(windows)] -async fn install() -> Result<(), WebViewError> { - const WEBVIEW2_BOOTSTRAPPER_URL: &str = "https://go.microsoft.com/fwlink/p/?LinkId=2124703"; - const DEFAULT_FILENAME: &str = "MicrosoftEdgeWebview2Setup.exe"; - - let client = reqwest::Client::builder() - .user_agent("Hoppscotch Agent") - .gzip(true) - .build()?; - - let response = client.get(WEBVIEW2_BOOTSTRAPPER_URL).send().await?; - - if !response.status().is_success() { - return Err(WebViewError::Download(format!( - "Failed to download WebView2 bootstrapper. Status: {}", - response.status() - ))); - } - - let filename = - get_filename_from_response(&response).unwrap_or_else(|| DEFAULT_FILENAME.to_owned()); - - let tmp_dir = TempDir::with_prefix("WebView-setup-")?; - let installer_path = tmp_dir.path().join(filename); - - let content = response.bytes().await?; - { - let mut file = std::fs::File::create(&installer_path)?; - io::copy(&mut Cursor::new(content), &mut file)?; - } - - let status = Command::new(&installer_path).args(["/install"]).status()?; - - if !status.success() { - return Err(WebViewError::Installation(format!( - "Installer exited with code `{}`.", - status.code().unwrap_or(-1) - ))); - } - - Ok(()) -} - -#[cfg(windows)] -fn get_filename_from_response(response: &reqwest::Response) -> Option { - response - .headers() - .get("content-disposition") - .and_then(|value| value.to_str().ok()) - .and_then(|value| value.split("filename=").last()) - .map(|name| name.trim().replace('\"', "")) - .or_else(|| { - response - .url() - .path_segments() - .and_then(|segments| segments.last()) - .map(|name| name.to_string()) - }) - .filter(|name| !name.is_empty()) -} - -#[cfg(not(windows))] -async fn install() -> Result<(), WebViewError> { - Err(WebViewError::Installation( - "Unable to auto-install WebView. Please refer to https://v2.tauri.app/references/webview-versions/".to_string(), - )) -} - -pub fn init_webview() { - if is_available() { - return; - } - - if dialog::confirm( - "WebView Error", - "WebView is required for this application to work.\n\n\ - Do you want to install it?", - MessageType::Error, - ) - .not() - { - tracing::warn!("Declined to setup WebView."); - - std::process::exit(1); - } - - if let Err(e) = tauri::async_runtime::block_on(install()) { - dialog::error(&format!( - "Failed to install WebView: {}\n\n\ - Please install it manually from webpage that should open when you click 'Ok'.\n\n\ - If that doesn't work, please visit Microsoft Edge Webview2 download section.", - e - )); - - if let Err(e) = open_install_website() { - tracing::warn!("Failed to launch WebView website:\n{}", e); - } - - std::process::exit(1); - } - - if is_available().not() { - dialog::panic( - "Unable to setup WebView:\n\n\ - Please install it manually and relaunch the application.\n\ - https://developer.microsoft.com/microsoft-edge/webview2/#download-section", - ); - } -} diff --git a/packages/hoppscotch-agent/src-tauri/tauri.conf.json b/packages/hoppscotch-agent/src-tauri/tauri.conf.json deleted file mode 100644 index d23437e4..00000000 --- a/packages/hoppscotch-agent/src-tauri/tauri.conf.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2.0.0-rc", - "productName": "Hoppscotch Agent", - "version": "0.1.17", - "identifier": "io.hoppscotch.agent", - "build": { - "beforeDevCommand": "pnpm dev", - "devUrl": "http://127.0.0.1:1420", - "beforeBuildCommand": "pnpm build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "title": "Hoppscotch Agent", - "width": 600, - "height": 400, - "center": true, - "resizable": false, - "maximizable": false, - "minimizable": false, - "focus": true, - "alwaysOnTop": true, - "create": false - } - ], - "security": { - "csp": null - } - }, - "bundle": { - "active": true, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "createUpdaterArtifacts": true - }, - "plugins": { - "updater": { - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDRBQzgxQjc3MzJCMjZENEMKUldSTWJiSXlkeHZJU3EvQW1abFVlREVhRDNlM0ZhOVJYaHN4M0FpbXZhcUFzSVdVbG84RWhPa1AK", - "endpoints": ["https://releases.hoppscotch.com/hoppscotch-agent.json"] - } - } -} diff --git a/packages/hoppscotch-agent/src-tauri/tauri.portable.conf.json b/packages/hoppscotch-agent/src-tauri/tauri.portable.conf.json deleted file mode 100644 index 657477e9..00000000 --- a/packages/hoppscotch-agent/src-tauri/tauri.portable.conf.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2.0.0-rc", - "productName": "Hoppscotch Agent Portable", - "version": "0.1.17", - "identifier": "io.hoppscotch.agent", - "build": { - "beforeDevCommand": "pnpm dev", - "devUrl": "http://localhost:1420", - "beforeBuildCommand": "pnpm build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "title": "Hoppscotch Agent Portable", - "width": 600, - "height": 400, - "center": true, - "resizable": false, - "maximizable": false, - "minimizable": false, - "focus": true, - "alwaysOnTop": true, - "create": false - } - ], - "security": { - "csp": null - } - }, - "bundle": { - "active": false, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ], - "createUpdaterArtifacts": false - }, - "plugins": { - "updater": { - "active": false - } - } -} diff --git a/packages/hoppscotch-agent/src/App.vue b/packages/hoppscotch-agent/src/App.vue deleted file mode 100644 index ee370573..00000000 --- a/packages/hoppscotch-agent/src/App.vue +++ /dev/null @@ -1,228 +0,0 @@ - - - diff --git a/packages/hoppscotch-agent/src/index.css b/packages/hoppscotch-agent/src/index.css deleted file mode 100644 index b5c61c95..00000000 --- a/packages/hoppscotch-agent/src/index.css +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/packages/hoppscotch-agent/src/main.ts b/packages/hoppscotch-agent/src/main.ts deleted file mode 100644 index a1a836ca..00000000 --- a/packages/hoppscotch-agent/src/main.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { createApp } from "vue" -import App from "./App.vue" -import "./index.css" - -import { plugin as HoppUI } from "@hoppscotch/ui" - -import "@hoppscotch/ui/themes.css" - -import "@hoppscotch/ui/style.css" - -createApp(App).use(HoppUI).mount("#app") diff --git a/packages/hoppscotch-agent/src/pages/otp.vue b/packages/hoppscotch-agent/src/pages/otp.vue deleted file mode 100644 index dfee5bb2..00000000 --- a/packages/hoppscotch-agent/src/pages/otp.vue +++ /dev/null @@ -1,92 +0,0 @@ - - - diff --git a/packages/hoppscotch-agent/src/pages/registrations.vue b/packages/hoppscotch-agent/src/pages/registrations.vue deleted file mode 100644 index 37eea795..00000000 --- a/packages/hoppscotch-agent/src/pages/registrations.vue +++ /dev/null @@ -1,68 +0,0 @@ - - - diff --git a/packages/hoppscotch-agent/src/vite-env.d.ts b/packages/hoppscotch-agent/src/vite-env.d.ts deleted file mode 100644 index fc812394..00000000 --- a/packages/hoppscotch-agent/src/vite-env.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -declare module "*.vue" { - import type { DefineComponent } from "vue"; - const component: DefineComponent<{}, {}, any>; - export default component; -} diff --git a/packages/hoppscotch-agent/tailwind.config.js b/packages/hoppscotch-agent/tailwind.config.js deleted file mode 100644 index 8d2a79d6..00000000 --- a/packages/hoppscotch-agent/tailwind.config.js +++ /dev/null @@ -1,6 +0,0 @@ -import preset from '@hoppscotch/ui/ui-preset' - -export default { - content: ['src/**/*.{vue,html}'], - presets: [preset] -} diff --git a/packages/hoppscotch-agent/tsconfig.json b/packages/hoppscotch-agent/tsconfig.json deleted file mode 100644 index f82888f3..00000000 --- a/packages/hoppscotch-agent/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "preserve", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], - "references": [{ "path": "./tsconfig.node.json" }] -} diff --git a/packages/hoppscotch-agent/tsconfig.node.json b/packages/hoppscotch-agent/tsconfig.node.json deleted file mode 100644 index 42872c59..00000000 --- a/packages/hoppscotch-agent/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/packages/hoppscotch-agent/vite.config.ts b/packages/hoppscotch-agent/vite.config.ts deleted file mode 100644 index 002646ef..00000000 --- a/packages/hoppscotch-agent/vite.config.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { defineConfig } from "vite"; -import vue from "@vitejs/plugin-vue"; -import tailwindcss from 'tailwindcss'; -import autoprefixer from 'autoprefixer'; -import path from 'path'; -import Icons from "unplugin-icons/vite"; -import IconsResolver from 'unplugin-icons/resolver'; -import Components from 'unplugin-vue-components/vite'; - -const host = process.env.TAURI_DEV_HOST; - -// https://vitejs.dev/config/ -export default defineConfig(async () => ({ - plugins: [ - vue(), - Icons({ compiler: 'vue3' }), - Components({ - resolvers: [ - IconsResolver({ - prefix: '' // optional, default is 'i' - }) - ] - }) - ], - css: { - postcss: { - plugins: [ - tailwindcss, - autoprefixer, - ], - }, - }, - resolve: { - alias: { - '@': path.resolve(__dirname, './src') - } - }, - // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` - // - // 1. prevent vite from obscuring rust errors - clearScreen: false, - // 2. tauri expects a fixed port, fail if that port is not available - server: { - port: 1420, - strictPort: true, - host: '127.0.0.1', - hmr: host - ? { - protocol: "ws", - host, - port: 1421, - } - : undefined, - watch: { - // 3. tell vite to ignore watching `src-tauri` - ignored: ["**/src-tauri/**"], - }, - }, -})); diff --git a/packages/hoppscotch-cli/.gitignore b/packages/hoppscotch-cli/.gitignore deleted file mode 100644 index a0bc82af..00000000 --- a/packages/hoppscotch-cli/.gitignore +++ /dev/null @@ -1,146 +0,0 @@ - -# Created by https://www.toptal.com/developers/gitignore/api/node -# Edit at https://www.toptal.com/developers/gitignore?templates=node - -### Node ### -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) -web_modules/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test -.env.production - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt -dist - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -# yarn v2 -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -# End of https://www.toptal.com/developers/gitignore/api/node - -# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode -# Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode - -### VisualStudioCode ### -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -*.code-workspace - -# Local History for Visual Studio Code -.history/ - -### VisualStudioCode Patch ### -# Ignore all local history of files -.history -.ionide - -# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode diff --git a/packages/hoppscotch-cli/.prettierrc b/packages/hoppscotch-cli/.prettierrc deleted file mode 100644 index 5c6bc947..00000000 --- a/packages/hoppscotch-cli/.prettierrc +++ /dev/null @@ -1,8 +0,0 @@ -{ - "semi": true, - "trailingComma": "es5", - "singleQuote": false, - "printWidth": 80, - "useTabs": false, - "tabWidth": 2 -} diff --git a/packages/hoppscotch-cli/CONTRIBUTING.md b/packages/hoppscotch-cli/CONTRIBUTING.md deleted file mode 100644 index 15d6bc80..00000000 --- a/packages/hoppscotch-cli/CONTRIBUTING.md +++ /dev/null @@ -1,57 +0,0 @@ -# Contributing - -When contributing to this repository, please first discuss the change you wish to make via issue, -email, or any other method with the owners of this repository before making a change. - -Please note we have a code of conduct, please follow it in all your interactions with the project. - -## Pull Request Process - -1. Ensure any install or build dependencies are removed before the end of the layer when doing a - build. -2. Update the README.md with details of changes to the interface, this includes new environment - variables, exposed ports, useful file locations and container parameters. -3. Increase the version numbers in any examples files and the README.md to the new version that this - Pull Request would represent. The versioning scheme we use is [SemVer](https://semver.org). -4. You may merge the Pull Request once you have the sign-off of two other developers, or if you - do not have permission to do that, you may request the second reviewer merge it for you. - -## Set Up The Development Environment - -1. After cloning the repository, execute the following commands: - - ```bash - pnpm install - pnpm run build - ``` - -2. In order to test locally, you can use two types of package linking: - - 1. The 'pnpm exec' way (preferred since it does not hamper your original installation of the CLI): - - ```bash - pnpm link @hoppscotch/cli - - // Then to use or test the CLI: - pnpm exec hopp - - // After testing, to remove the package linking: - pnpm rm @hoppscotch/cli - ``` - - 2. The 'global' way (warning: this might override the globally installed CLI, if exists): - - ```bash - sudo pnpm link --global - - // Then to use or test the CLI: - hopp - - // After testing, to remove the package linking: - sudo pnpm rm --global @hoppscotch/cli - ``` - -3. To use the Typescript watch scripts: - ```bash - pnpm run dev - ``` diff --git a/packages/hoppscotch-cli/README.md b/packages/hoppscotch-cli/README.md deleted file mode 100644 index 8a36a420..00000000 --- a/packages/hoppscotch-cli/README.md +++ /dev/null @@ -1,211 +0,0 @@ -# Hoppscotch CLI ALPHA - -A CLI to run Hoppscotch Test Scripts in CI environments. - -### **Commands:** - -- `hopp test [options] [file]`: testing hoppscotch collection.json file - -### **Usage:** - -```bash -hopp [options or commands] arguments -``` - -### **Options:** - -- `-v`, `--ver`: see the current version of the CLI -- `-h`, `--help`: display help for command - -## **Command Descriptions:** - -1. #### **`hopp -v` / `hopp --ver`** - - - Prints out the current version of the Hoppscotch CLI - -2. #### **`hopp -h` / `hopp --help`** - - - Displays the help text - -3. #### **`hopp test [options] `** - - - Interactive CLI to accept Hoppscotch collection JSON path - - Parses the collection JSON and executes each requests - - Executes pre-request script. - - Outputs the response of each request. - - Executes and outputs test-script response. - - #### Options: - - ##### `-e, --env ` - - - Accepts path to env.json with contents in below format: - - ```json - { - "ENV1": "value1", - "ENV2": "value2" - } - ``` - - - You can now access those variables using `pw.env.get('')` - - Taking the above example, `pw.env.get("ENV1")` will return `"value1"` - - #### `-d, --delay ` - - - Used to defer the execution of requests in a collection. - - #### `--token ` - - - Expects a personal access token to be passed for establishing connection with your Hoppscotch account. - - #### `--server ` - - - URL of your self-hosted instance, if your collections are on a self-hosted instance. - - #### `--reporter-junit [path]` - - - Expects a file path to store the JUnit Report. - - ##### `--iteration-count ` - - - Accepts the number of iterations to run the collection - - ##### `--iteration-data ` - - - Accepts the path to a CSV file with contents in the below format: - - ```text - key1,key2,key3 - value1,value2,value3 - value4,value5,value6 - ``` - - For every iteration the values will be replaced with the respective keys in the environment. For iteration 1 the value1,value2,value3 will be replaced and for iteration 2 value4,value5,value6 will be replaced and so on. - - #### `--legacy-sandbox` - - - Opt out from the experimental scripting sandbox. - -## Versioning - -The Hoppscotch CLI follows **pre-1.0 semantic versioning** conventions while in alpha (version `< 1.0.0`): - -- **Feature releases** (e.g., `0.20.0` → `0.21.0`): New features, enhancements, or improvements -- **Patch releases** (e.g., `0.20.0` → `0.20.1`): Bug fixes, security patches, and minor improvements -- **Breaking changes** (e.g., `0.21.0` → `0.30.0`): Major version-like bumps for backwards-incompatible changes - -> Once the CLI reaches stability and a mature feature set, we will transition to standard semantic versioning starting with `1.0.0`. - -## Install - -- Before you install Hoppscotch CLI you need to make sure you have the dependencies it requires to run. - - - **Windows & macOS**: You will need `node-gyp` installed. Find instructions here: https://github.com/nodejs/node-gyp - - **Debian/Ubuntu derivatives**: - ```sh - sudo apt-get install python g++ build-essential - ``` - - **Alpine Linux**: - ```sh - sudo apk add python3 make g++ - ``` - - **Amazon Linux (AMI)** - ```sh - sudo yum install gcc72 gcc72-c++ - ``` - - **Arch Linux** - ```sh - sudo pacman -S make gcc python - ``` - - **RHEL/Fedora derivatives**: - ```sh - sudo dnf install python3 make gcc gcc-c++ zlib-devel brotli-devel openssl-devel libuv-devel - ``` - -- Once the dependencies are installed, install [@hoppscotch/cli](https://www.npmjs.com/package/@hoppscotch/cli) from npm by running: - ``` - npm i -g @hoppscotch/cli - ``` - -## **Developing:** - -1. Clone the repository, make sure you've installed latest [pnpm](https://pnpm.io). -2. `pnpm install` -3. Build required workspace dependencies (if needed): - ```bash - # These auto-build via postinstall hooks during 'pnpm install' - # Rebuild manually only when you make changes to these packages: - pnpm --filter @hoppscotch/data run build - pnpm --filter @hoppscotch/js-sandbox run build - ``` -4. `cd packages/hoppscotch-cli` -5. `pnpm run build` -6. `sudo pnpm link --global` -7. Test the installation by executing `hopp` - -## **Contributing:** - -When contributing to this repository, please first discuss the change you wish to make via issue, -email, or any other method with the owners of this repository before making a change. - -Please note we have a code of conduct, please follow it in all your interactions with the project. - -## Pull Request Process - -1. Ensure any install or build dependencies are removed before the end of the layer when doing a - build. -2. Update the README.md with details of changes to the interface, this includes new environment - variables, exposed ports, useful file locations and container parameters. -3. Increase the version numbers in any examples files and the README.md to the new version that this - Pull Request would represent. The versioning scheme we use is [SemVer](https://semver.org). -4. You may merge the Pull Request once you have the sign-off of two other developers, or if you - do not have permission to do that, you may request the second reviewer merge it for you. - -## Set Up The Development Environment - -1. After cloning the repository, execute the following commands: - - ```bash - pnpm install - # Build required workspace dependencies (if needed) - # These auto-build via postinstall hooks during 'pnpm install' - # Rebuild manually only when you make changes to these packages: - pnpm --filter @hoppscotch/data run build - pnpm --filter @hoppscotch/js-sandbox run build - # Then build the CLI - cd packages/hoppscotch-cli && pnpm run build - ``` - -2. In order to test locally, you can use two types of package linking: - - 1. The 'pnpm exec' way (preferred since it does not hamper your original installation of the CLI): - - ```bash - pnpm link @hoppscotch/cli - - // Then to use or test the CLI: - pnpm exec hopp - - // After testing, to remove the package linking: - pnpm rm @hoppscotch/cli - ``` - - 2. The 'global' way (warning: this might override the globally installed CLI, if exists): - - ```bash - sudo pnpm link --global - - // Then to use or test the CLI: - hopp - - // After testing, to remove the package linking: - sudo pnpm rm --global @hoppscotch/cli - ``` - -3. To use the Typescript watch scripts: - - ```bash - pnpm run dev - ``` diff --git a/packages/hoppscotch-cli/bin/hopp.js b/packages/hoppscotch-cli/bin/hopp.js deleted file mode 100755 index 238480e3..00000000 --- a/packages/hoppscotch-cli/bin/hopp.js +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env node -// * The entry point of the CLI -// @ts-check - -import chalk from "chalk"; -import { spawnSync } from "child_process"; -import fs from "fs"; -import { cloneDeep } from "lodash-es"; -import semver from "semver"; -import { fileURLToPath } from "url"; - -const highlightVersion = (version) => chalk.black.bgYellow(`v${version}`); - -const packageJsonPath = fileURLToPath( - new URL("../package.json", import.meta.url) -); -const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")); - -const requiredNodeVersionRange = packageJson.engines?.node || ">=22"; - -// Extract the major version from the start of the range -const requiredNodeVersion = semver.major( - semver.minVersion(requiredNodeVersionRange) ?? "22" -); - -const currentNodeVersion = process.versions.node; - -// Last supported version of the CLI for Node.js v20 -const lastSupportedVersion = "0.26.0"; - -if (!semver.satisfies(currentNodeVersion, requiredNodeVersionRange)) { - console.error( - `${chalk.greenBright("Hoppscotch CLI")} requires Node.js ${highlightVersion(requiredNodeVersion)} or higher and you're on Node.js ${highlightVersion(currentNodeVersion)}.` - ); - - console.error( - `\nIf you prefer staying on Node.js ${highlightVersion("20")}, you can install the last supported version of the CLI:\n` + - `${chalk.green(`npm install -g @hoppscotch/cli@${lastSupportedVersion}`)} alongside ${highlightVersion("2025.10.1")} of the Hoppscotch app.\n` - ); - process.exit(1); -} - -// Dynamically importing the module after the Node.js version check prevents errors due to unrecognized APIs in older Node.js versions -const { cli } = await import("../dist/index.js"); - -// As per isolated-vm documentation, we need to supply `--no-node-snapshot` for node >= 20 -// src: https://github.com/laverdet/isolated-vm?tab=readme-ov-file#requirements -if (!process.execArgv.includes("--no-node-snapshot")) { - const argCopy = cloneDeep(process.argv); - - // Replace first argument with --no-node-snapshot - // We can get argv[0] from process.argv0 - argCopy[0] = "--no-node-snapshot"; - - const result = spawnSync(process.argv0, argCopy, { stdio: "inherit" }); - - // Exit with the same status code as the spawned process - process.exit(result.status ?? 0); -} else { - cli(process.argv); -} diff --git a/packages/hoppscotch-cli/package.json b/packages/hoppscotch-cli/package.json deleted file mode 100644 index c16380b0..00000000 --- a/packages/hoppscotch-cli/package.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "name": "@hoppscotch/cli", - "version": "0.31.1", - "description": "A CLI to run Hoppscotch test scripts in CI environments.", - "homepage": "https://hoppscotch.io", - "type": "module", - "main": "dist/index.js", - "bin": { - "hopp": "bin/hopp.js" - }, - "publishConfig": { - "access": "public" - }, - "engines": { - "node": ">=22" - }, - "scripts": { - "build": "pnpm exec tsup", - "dev": "pnpm exec tsup --watch", - "debugger": "node debugger.js 9999", - "prepublish": "pnpm exec tsup", - "prettier-format": "prettier --config .prettierrc 'src/**/*.ts' --write", - "test": "pnpm run build && vitest run", - "do-typecheck": "pnpm exec tsc --noEmit", - "do-test": "pnpm run test" - }, - "keywords": [ - "cli", - "hoppscotch", - "hopp-cli" - ], - "author": "Hoppscotch (support@hoppscotch.io)", - "repository": { - "type": "git", - "url": "https://github.com/hoppscotch/hoppscotch.git" - }, - "bugs": { - "url": "https://github.com/hoppscotch/hoppscotch/issues", - "email": "support@hoppscotch.io" - }, - "license": "MIT", - "private": false, - "dependencies": { - "aws4fetch": "1.0.20", - "axios": "1.15.2", - "axios-cookiejar-support": "6.0.5", - "chalk": "5.6.2", - "commander": "14.0.3", - "isolated-vm": "6.1.2", - "js-md5": "0.8.3", - "jsonc-parser": "3.3.1", - "lodash-es": "4.18.1", - "papaparse": "5.5.3", - "qs": "6.15.1", - "semver": "7.7.4", - "tough-cookie": "6.0.1", - "verzod": "0.4.0", - "xmlbuilder2": "4.0.3", - "zod": "3.25.32" - }, - "devDependencies": { - "@hoppscotch/data": "workspace:^", - "@hoppscotch/js-sandbox": "workspace:^", - "@relmify/jest-fp-ts": "2.1.1", - "@types/lodash-es": "4.17.12", - "@types/papaparse": "5.5.2", - "@types/qs": "6.15.0", - "fp-ts": "2.16.11", - "prettier": "3.8.3", - "tsup": "8.5.1", - "typescript": "5.9.3", - "vitest": "4.1.5" - } -} diff --git a/packages/hoppscotch-cli/setupFiles.ts b/packages/hoppscotch-cli/setupFiles.ts deleted file mode 100644 index 0a1bcdc0..00000000 --- a/packages/hoppscotch-cli/setupFiles.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Vitest doesn't work without globals -// Ref: https://github.com/relmify/jest-fp-ts/issues/11 - -import decodeMatchers from "@relmify/jest-fp-ts/dist/decodeMatchers"; -import eitherMatchers from "@relmify/jest-fp-ts/dist/eitherMatchers"; -import optionMatchers from "@relmify/jest-fp-ts/dist/optionMatchers"; -import theseMatchers from "@relmify/jest-fp-ts/dist/theseMatchers"; -import eitherOrTheseMatchers from "@relmify/jest-fp-ts/dist/eitherOrTheseMatchers"; -import { expect } from "vitest"; - -expect.extend(decodeMatchers.matchers); -expect.extend(eitherMatchers.matchers); -expect.extend(optionMatchers.matchers); -expect.extend(theseMatchers.matchers); -expect.extend(eitherOrTheseMatchers.matchers); diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/commands/__snapshots__/test.spec.ts.snap b/packages/hoppscotch-cli/src/__tests__/e2e/commands/__snapshots__/test.spec.ts.snap deleted file mode 100644 index 9c3e21c6..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/commands/__snapshots__/test.spec.ts.snap +++ /dev/null @@ -1,529 +0,0 @@ -// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html - -exports[`hopp test [options] > Test\`hopp test --env --reporter-junit [path] > Generates a JUnit report at the default path 1`] = ` -" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >" -} (ENV_EXPAND_LOOP)]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" -`; - -exports[`hopp test [options] > Test\`hopp test --env --reporter-junit [path] > Generates a JUnit report at the specified path 1`] = ` -" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - >" -} (ENV_EXPAND_LOOP)]]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" -`; - -exports[`hopp test [options] > Test\`hopp test --env --reporter-junit [path] > Generates a JUnit report for a collection referring to environment variables 1`] = ` -" - - - - - - - - - - - - - - - -" -`; - -exports[`hopp test [options] > Test\`hopp test --env --reporter-junit [path] > Generates a JUnit report for a collection with authorization/headers set at the collection level 1`] = ` -" - - - - - - - - - - - - - - - - - - - - - - - - - -" -`; diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts b/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts deleted file mode 100644 index 42f7df62..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/commands/test.spec.ts +++ /dev/null @@ -1,1493 +0,0 @@ -import { ExecException } from "child_process"; -import fs from "fs"; -import path from "path"; -import { afterAll, beforeAll, describe, expect, test } from "vitest"; - -import { HoppErrorCode } from "../../../types/errors"; -import { - getErrorCode, - getTestJsonFilePath, - runCLI, - runCLIWithNetworkRetry, -} from "../../utils"; - -describe("hopp test [options] ", { timeout: 100000 }, () => { - const VALID_TEST_ARGS = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`; - - describe("Test `hopp test ` command:", () => { - describe("Argument parsing", () => { - test("Errors with the code `INVALID_ARGUMENT` for not supplying enough arguments", async () => { - const args = "test"; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - - test("Errors with the code `INVALID_ARGUMENT` for an invalid command", async () => { - const args = "invalid-arg"; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - }); - - describe("Supplied collection export file validations", () => { - test("Errors with the code `FILE_NOT_FOUND` if the supplied collection export file doesn't exist", async () => { - const args = "test notfound.json"; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("FILE_NOT_FOUND"); - }); - - test("Errors with the code UNKNOWN_ERROR if the supplied collection export file content isn't valid JSON", async () => { - const args = `test ${getTestJsonFilePath("malformed-coll.json", "collection")}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("UNKNOWN_ERROR"); - }); - - test("Errors with the code `MALFORMED_COLLECTION` if the supplied collection export file content is malformed", async () => { - const args = `test ${getTestJsonFilePath("malformed-coll-2.json", "collection")}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("MALFORMED_COLLECTION"); - }); - - test("Errors with the code `INVALID_FILE_TYPE` if the supplied collection export file doesn't end with the `.json` extension", async () => { - const args = `test ${getTestJsonFilePath("notjson-coll.txt", "collection")}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_FILE_TYPE"); - }); - - test("Fails if the collection file includes scripts with incorrect API usage and failed assertions", async () => { - const args = `test ${getTestJsonFilePath("fails-coll.json", "collection")}`; - const { error } = await runCLI(args); - - expect(error).not.toBeNull(); - expect(error).toMatchObject({ - code: 1, - }); - }); - }); - - describe("Versioned entities", () => { - describe("Collections & Requests", () => { - const testFixtures = [ - { fileName: "coll-v1-req-v0.json", collVersion: 1, reqVersion: 0 }, - { fileName: "coll-v1-req-v1.json", collVersion: 1, reqVersion: 1 }, - { fileName: "coll-v2-req-v2.json", collVersion: 2, reqVersion: 2 }, - { fileName: "coll-v2-req-v3.json", collVersion: 2, reqVersion: 3 }, - ]; - - testFixtures.forEach(({ collVersion, fileName, reqVersion }) => { - test(`Successfully processes a supplied collection export file where the collection is based on the "v${collVersion}" schema and the request following the "v${reqVersion}" schema`, async () => { - const args = `test ${getTestJsonFilePath(fileName, "collection")}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - }); - - describe("Mixed versions", () => { - test("Successfully processes children based on valid version ranges", async () => { - const args = `test ${getTestJsonFilePath("valid-mixed-versions-coll.json", "collection")}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Errors with the code `MALFORMED_COLLECTION` if the children fall out of valid version ranges", async () => { - const args = `test ${getTestJsonFilePath("invalid-mixed-versions-coll.json", "collection")}`; - - const { stderr } = await runCLI(args); - const out = getErrorCode(stderr); - - expect(out).toBe("MALFORMED_COLLECTION"); - }); - }); - }); - - describe("Environments", () => { - const testFixtures = [ - { fileName: "env-v0.json", version: 0 }, - { fileName: "env-v1.json", version: 1 }, - { fileName: "env-v2.json", version: 2 }, - ]; - - testFixtures.forEach(({ fileName, version }) => { - test(`Successfully processes the supplied collection and environment export files where the environment is based on the "v${version}" schema`, async () => { - const ENV_PATH = getTestJsonFilePath(fileName, "environment"); - const args = `test ${getTestJsonFilePath("sample-coll.json", "collection")} --env ${ENV_PATH}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - }); - }); - }); - - test("Successfully processes a supplied collection export file of the expected format", async () => { - const args = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Successfully inherits/overrides authorization and headers specified at the root collection at deeply nested collections", async () => { - const args = `test ${getTestJsonFilePath( - "collection-level-auth-headers-coll.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Successfully inherits/overrides authorization and headers at each level with multiple child collections", async () => { - const args = `test ${getTestJsonFilePath( - "multiple-child-collections-auth-headers-coll.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Successfully inherits collection variables into folders without their own variables", async () => { - const args = `test ${getTestJsonFilePath( - "collection-with-variables.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Persists environment variables set in the pre-request script for consumption in the test script", async () => { - const args = `test ${getTestJsonFilePath( - "pre-req-script-env-var-persistence-coll.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("The `Content-Type` header takes priority over the value set at the request body", async () => { - const args = `test ${getTestJsonFilePath( - "content-type-header-scenarios.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Strips comments from JSONC request bodies", async () => { - const args = `test ${getTestJsonFilePath( - "jsonc-body-coll.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - describe("OAuth 2 Authorization type with Authorization Code Grant Type", () => { - test("Successfully translates the authorization information to headers/query params and sends it along with the request", async () => { - const args = `test ${getTestJsonFilePath( - "oauth2-auth-code-coll.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - }); - - describe("multipart/form-data content type", () => { - test("Successfully derives the relevant headers based and sends the form data in the request body", async () => { - const args = `test ${getTestJsonFilePath( - "oauth2-auth-code-coll.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - }); - - test("Successfully display console logs and recognizes platform APIs in the experimental scripting sandbox", async () => { - const args = `test ${getTestJsonFilePath( - "test-scripting-sandbox-modes-coll.json", - "collection" - )}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - expect(result.error).toBeNull(); - - const expectedStaticParts = [ - "https://example.com/path?foo=bar&baz=qux", - "'0': 72", - "'12': 33", - "Decoded: Hello, world!", - "Hello after 1s", - ]; - - expectedStaticParts.forEach((part) => { - expect(result.stdout).toContain(part); - }); - - const every500msCount = (result.stdout.match(/Every 500ms/g) || []) - .length; - expect(every500msCount).toBeGreaterThanOrEqual(3); - }); - - test("Fails to display console logs and recognize platform APIs in the legacy scripting sandbox", async () => { - const args = `test ${getTestJsonFilePath( - "test-scripting-sandbox-modes-coll.json", - "collection" - )} --legacy-sandbox`; - const { error, stdout } = await runCLI(args); - - expect(error).toBeTruthy(); - expect(stdout).not.toContain("https://example.com/path?foo=bar&baz=qux"); - expect(stdout).not.toContain("Encoded"); - }); - - test("Ensures tests run in sequence order based on request path", async () => { - // Expected order of collection runs - const expectedOrder = [ - "root-collection-request", - "folder-1/folder-1-request", - "folder-1/folder-11/folder-11-request", - "folder-1/folder-12/folder-12-request", - "folder-1/folder-13/folder-13-request", - "folder-2/folder-2-request", - "folder-2/folder-21/folder-21-request", - "folder-2/folder-22/folder-22-request", - "folder-2/folder-23/folder-23-request", - "folder-3/folder-3-request", - "folder-3/folder-31/folder-31-request", - "folder-3/folder-32/folder-32-request", - "folder-3/folder-33/folder-33-request", - ]; - - const normalizePath = (path: string) => path.replace(/\\/g, "/"); - - const extractRunningOrder = (stdout: string): string[] => - [...stdout.matchAll(/Running:.*?\/(.*?)\r?\n/g)].map( - ([, path]) => normalizePath(path.replace(/\x1b\[\d+m/g, "")) // Remove ANSI codes and normalize paths - ); - - const args = `test ${getTestJsonFilePath( - "multiple-child-collections-auth-headers-coll.json", - "collection" - )}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - expect(extractRunningOrder(result.stdout)).toStrictEqual(expectedOrder); - - expect(result.error).toBeNull(); - }); - - /** - * Tests pm.sendRequest() functionality with external HTTP endpoints. - * - * Network Resilience Strategy: - * - Retries once (2 total attempts) on transient network errors - * - Detects and logs specific errors (ECONNRESET, ETIMEDOUT, etc.) - * - Validates JUnit XML completeness (60+ test suites) before accepting success - * - Auto-skips on network failures to prevent blocking PRs - */ - test("Supports the new scripting API method additions under the `hopp` and `pm` namespaces and validates JUnit report structure", async () => { - // First, run without JUnit report to ensure basic functionality works - const basicArgs = `test ${getTestJsonFilePath( - "scripting-revamp-coll.json", - "collection" - )}`; - const basicResult = await runCLIWithNetworkRetry(basicArgs); - if (basicResult === null) return; - expect(basicResult.error).toBeNull(); - - // Then, run with JUnit report and validate structure - const junitPath = path.join( - __dirname, - "scripting-revamp-snapshot-junit.xml" - ); - - if (fs.existsSync(junitPath)) { - fs.unlinkSync(junitPath); - } - - const junitArgs = `test ${getTestJsonFilePath( - "scripting-revamp-coll.json", - "collection" - )} --reporter-junit ${junitPath}`; - - // Enhanced retry for JUnit run - also validate output completeness - const runWithValidation = async () => { - const minExpectedTestSuites = 60; // Should have 67+ test suites - const maxAttempts = 2; // Only retry once (2 total attempts) - - const extractNetworkError = (output: string): string => { - const econnresetMatch = output.match(/ECONNRESET/i); - const eaiAgainMatch = output.match(/EAI_AGAIN/i); - const enotfoundMatch = output.match(/ENOTFOUND/i); - const etimedoutMatch = output.match(/ETIMEDOUT/i); - const econnrefusedMatch = output.match(/ECONNREFUSED/i); - - if (econnresetMatch) return "ECONNRESET (connection reset by peer)"; - if (eaiAgainMatch) return "EAI_AGAIN (DNS lookup timeout)"; - if (enotfoundMatch) return "ENOTFOUND (DNS lookup failed)"; - if (etimedoutMatch) return "ETIMEDOUT (connection timeout)"; - if (econnrefusedMatch) return "ECONNREFUSED (connection refused)"; - return "Unknown network error"; - }; - - for (let attempt = 0; attempt < maxAttempts; attempt++) { - if (fs.existsSync(junitPath)) { - fs.unlinkSync(junitPath); - } - - const result = await runCLI(junitArgs); - - // Check for transient errors in output (network or httpbin 5xx) - const output = `${result.stdout}\n${result.stderr}`; - const hasNetworkError = - /ECONNRESET|EAI_AGAIN|ENOTFOUND|ETIMEDOUT|ECONNREFUSED|REQUEST_ERROR/i.test( - output - ); - const hasHttpbin5xx = - /httpbin\.org is down \(5xx\)|httpbin\.org is down \(503\)/i.test( - output - ); - - // If successful and JUnit file exists, validate completeness - if (!result.error && fs.existsSync(junitPath)) { - const xml = fs.readFileSync(junitPath, "utf-8"); - const testsuiteCount = (xml.match(/= minExpectedTestSuites && !hasHttpbin5xx) { - return result; - } - - // Incomplete output or httpbin issues - retry once if transient - if ( - (hasNetworkError || hasHttpbin5xx) && - attempt < maxAttempts - 1 - ) { - const errorDetail = hasHttpbin5xx - ? "httpbin.org 5xx response" - : `incomplete output (${testsuiteCount}/${minExpectedTestSuites} test suites) with ${extractNetworkError(output)}`; - console.log( - `⚠️ Transient error detected: ${errorDetail}. Retrying once...` - ); - await new Promise((r) => setTimeout(r, 2000)); - continue; - } - } - - // Non-transient error - fail fast - if (result.error && !hasNetworkError && !hasHttpbin5xx) { - return result; - } - - // Transient error - retry once - const isLastAttempt = attempt === maxAttempts - 1; - if (!isLastAttempt) { - const errorDetail = hasHttpbin5xx - ? "httpbin.org 5xx response" - : extractNetworkError(output); - console.log( - `⚠️ Transient error detected: ${errorDetail}. Retrying once...` - ); - await new Promise((r) => setTimeout(r, 2000)); - continue; - } - - // Last attempt exhausted due to transient issues - skip test to avoid blocking PR - const errorDetail = hasHttpbin5xx - ? "httpbin.org service degradation (5xx)" - : extractNetworkError(output); - console.warn( - `⚠️ Skipping test: Retry exhausted due to ${errorDetail}. External services may be unavailable.` - ); - return null; // Signal to skip test - } - - // Should never reach here - all paths above should return - throw new Error("Unexpected: retry loop completed without returning"); - }; - - const junitResult = await runWithValidation(); - if (junitResult === null) return; - expect(junitResult.error).toBeNull(); - - const junitXml = fs.readFileSync(junitPath, "utf-8"); - - // Validate structural invariants using regex parsing. - // Validate no testcases have "root" as name (would indicate assertions at root level). - const testcaseRootPattern = /]*name="root"/; - expect(junitXml).not.toMatch(testcaseRootPattern); - - // Validate test structure: testcases should have meaningful names from test blocks - const testcasePattern = / m[1] - ); - - // Ensure we have testcases - expect(testcaseNames.length).toBeGreaterThan(0); - - // Ensure no empty testcase names - for (const name of testcaseNames) { - expect(name.length).toBeGreaterThan(0); - expect(name).not.toBe("root"); - } - - // Validate presence of key test groups instead of snapshot comparison - // This is more reliable for CI as network responses can vary - - // 1. Correct number of test suites - const testsuitePattern = / { - const args = `test ${getTestJsonFilePath( - "collection-level-scripts-coll.json", - "collection" - )}`; - - const defaultResult = await runCLIWithNetworkRetry(args); - if (defaultResult === null) return; - expect(defaultResult.error).toBeNull(); - - const legacyResult = await runCLIWithNetworkRetry(`${args} --legacy-sandbox`); - if (legacyResult === null) return; - expect(legacyResult.error).toBeNull(); - }); - }); - - describe("Test `hopp test --env ` command:", () => { - describe("Supplied environment export file validations", () => { - describe("Argument parsing", () => { - test("Errors with the code `INVALID_ARGUMENT` if no file is supplied", async () => { - const args = `${VALID_TEST_ARGS} --env`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - }); - - test("Errors with the code `INVALID_FILE_TYPE` if the supplied environment export file doesn't end with the `.json` extension", async () => { - const args = `${VALID_TEST_ARGS} --env ${getTestJsonFilePath( - "notjson-coll.txt", - "collection" - )}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_FILE_TYPE"); - }); - - test("Errors with the code `FILE_NOT_FOUND` if the supplied environment export file doesn't exist", async () => { - const args = `${VALID_TEST_ARGS} --env notfound.json`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("FILE_NOT_FOUND"); - }); - - test("Errors with the code `MALFORMED_ENV_FILE` on supplying a malformed environment export file", async () => { - const ENV_PATH = getTestJsonFilePath( - "malformed-envs.json", - "environment" - ); - const args = `${VALID_TEST_ARGS} --env ${ENV_PATH}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("MALFORMED_ENV_FILE"); - }); - - test("Errors with the code `BULK_ENV_FILE` on supplying an environment export file based on the bulk environment export format", async () => { - const ENV_PATH = getTestJsonFilePath("bulk-envs.json", "environment"); - const args = `${VALID_TEST_ARGS} --env ${ENV_PATH}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("BULK_ENV_FILE"); - }); - }); - - test("Successfully resolves values from the supplied environment export file", async () => { - const COLL_PATH = getTestJsonFilePath( - "env-flag-tests-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment"); - const args = `test ${COLL_PATH} --env ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Successfully resolves environment variables referenced in the request body", async () => { - const COLL_PATH = getTestJsonFilePath( - "req-body-env-vars-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "req-body-env-vars-envs.json", - "environment" - ); - const args = `test ${COLL_PATH} --env ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Works with short `-e` flag", async () => { - const COLL_PATH = getTestJsonFilePath( - "env-flag-tests-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath("env-flag-envs.json", "environment"); - const args = `test ${COLL_PATH} -e ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - describe("Secret environment variables", () => { - // Reads secret environment values from system environment - test("Successfully picks the values for secret environment variables from `process.env` and persists the variables set from the pre-request script", async () => { - const env = { - ...process.env, - secretBearerToken: "test-token", - secretBasicAuthUsername: "test-user", - secretBasicAuthPassword: "test-pass", - secretQueryParamValue: "secret-query-param-value", - secretBodyValue: "secret-body-value", - secretHeaderValue: "secret-header-value", - }; - - const COLL_PATH = getTestJsonFilePath( - "secret-envs-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath("secret-envs.json", "environment"); - const args = `test ${COLL_PATH} --env ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args, { env }); - if (result === null) return; - - expect(result.stdout).toContain( - "https://httpbin.org/basic-auth/*********/*********" - ); - expect(result.error).toBeNull(); - }); - - test("Successfully picks the values for secret environment variables set directly in the environment export file and persists the environment variables set from the pre-request script", async () => { - const COLL_PATH = getTestJsonFilePath( - "secret-envs-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "secret-supplied-values-envs.json", - "environment" - ); - const args = `test ${COLL_PATH} --env ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - expect(result.stdout).toContain( - "https://httpbin.org/basic-auth/*********/*********" - ); - expect(result.error).toBeNull(); - }); - - test("Setting values for secret environment variables from the pre-request script overrides values set at the supplied environment export file", async () => { - const COLL_PATH = getTestJsonFilePath( - "secret-envs-persistence-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "secret-supplied-values-envs.json", - "environment" - ); - const args = `test ${COLL_PATH} --env ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - expect(result.stdout).toContain( - "https://httpbin.org/basic-auth/*********/*********" - ); - expect(result.error).toBeNull(); - }); - - test("Persists secret environment variable values set from the pre-request script for consumption in the request and post-request script context", async () => { - const COLL_PATH = getTestJsonFilePath( - "secret-envs-persistence-scripting-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "secret-envs-persistence-scripting-envs.json", - "environment" - ); - - const args = `test ${COLL_PATH} --env ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - }); - - describe("Request variables", () => { - test("Picks active request variables and ignores inactive entries alongside the usage of environment variables", async () => { - const env = { - ...process.env, - secretBasicAuthPasswordEnvVar: "password", - }; - - const COLL_PATH = getTestJsonFilePath( - "request-vars-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "request-vars-envs.json", - "environment" - ); - - const args = `test ${COLL_PATH} --env ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args, { env }); - if (result === null) return; - expect(result.stdout).toContain( - "https://echo.hoppscotch.io/********/********" - ); - expect(result.error).toBeNull(); - }); - }); - - describe("AWS Signature Authorization type", () => { - test("Successfully translates the authorization information to headers/query params and sends it along with the request", async () => { - const env = { - ...process.env, - secretKey: "test-secret-key", - serviceToken: "test-token", - }; - - const COLL_PATH = getTestJsonFilePath( - "aws-signature-auth-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "aws-signature-auth-envs.json", - "environment" - ); - - const args = `test ${COLL_PATH} -e ${ENV_PATH}`; - const result = await runCLIWithNetworkRetry(args, { env }); - if (result === null) return; - - expect(result.error).toBeNull(); - }); - }); - - describe("Digest Authorization type", () => { - /** - * NOTE: This test is being skipped because the test endpoint is no longer resolving - * TODO: Find a reliable public endpoint that supports Digest Auth and re-enable this test - */ - test.skip("Successfully translates the authorization information to headers/query params and sends it along with the request", async () => { - const COLL_PATH = getTestJsonFilePath( - "digest-auth-success-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "digest-auth-envs.json", - "environment" - ); - - const args = `test ${COLL_PATH} -e ${ENV_PATH}`; - const { error } = await runCLI(args); - expect(error).toBeNull(); - }); - }); - - test("Supports disabling request retries", async () => { - const COLL_PATH = getTestJsonFilePath( - "digest-auth-failure-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "digest-auth-envs.json", - "environment" - ); - - const args = `test ${COLL_PATH} -e ${ENV_PATH}`; - const { error } = await runCLI(args); - - expect(error).toBeTruthy(); - }); - - describe("HAWK Authentication", () => { - test("Correctly generates and attaches authorization headers to the request ", async () => { - const COLL_PATH = getTestJsonFilePath( - "hawk-auth-success-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "hawk-auth-envs.json", - "environment" - ); - - const args = `test ${COLL_PATH} -e ${ENV_PATH}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - expect(result.error).toBeNull(); - }); - }); - }); - - describe("Test `hopp test --delay ` command:", () => { - describe("Argument parsing", () => { - test("Errors with the code `INVALID_ARGUMENT` on not supplying a delay value", async () => { - const args = `${VALID_TEST_ARGS} --delay`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - - test("Errors with the code `INVALID_ARGUMENT` on supplying an invalid delay value", async () => { - const args = `${VALID_TEST_ARGS} --delay 'NaN'`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - }); - - test("Successfully performs delayed request execution for a valid delay value", async () => { - const args = `${VALID_TEST_ARGS} --delay 1`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - - test("Works with the short `-d` flag", async () => { - const args = `${VALID_TEST_ARGS} -d 1`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - expect(result.error).toBeNull(); - }); - }); - - // Future TODO: Enable once a proper e2e test environment is set up locally - describe.skip("Test `hopp test --env --token --server ` command:", () => { - const { - REQ_BODY_ENV_VARS_COLL_ID, - COLLECTION_LEVEL_HEADERS_AUTH_COLL_ID, - REQ_BODY_ENV_VARS_ENVS_ID, - PERSONAL_ACCESS_TOKEN, - } = process.env; - - if ( - !REQ_BODY_ENV_VARS_COLL_ID || - !COLLECTION_LEVEL_HEADERS_AUTH_COLL_ID || - !REQ_BODY_ENV_VARS_ENVS_ID || - !PERSONAL_ACCESS_TOKEN - ) { - return; - } - - const SERVER_URL = "https://stage-shc.hoppscotch.io/backend"; - - describe("Argument parsing", () => { - test("Errors with the code `INVALID_ARGUMENT` on not supplying a value for the `--token` flag", async () => { - const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --token`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - - test("Errors with the code `INVALID_ARGUMENT` on not supplying a value for the `--server` flag", async () => { - const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --server`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - }); - - describe("Workspace access validations", () => { - const INVALID_COLLECTION_ID = "invalid-coll-id"; - const INVALID_ENVIRONMENT_ID = "invalid-env-id"; - const INVALID_ACCESS_TOKEN = "invalid-token"; - - test("Errors with the code `TOKEN_INVALID` if the supplied access token is invalid", async () => { - const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --token ${INVALID_ACCESS_TOKEN} --server ${SERVER_URL}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("TOKEN_INVALID"); - }); - - test("Errors with the code `INVALID_ID` if the supplied collection ID is invalid", async () => { - const args = `test ${INVALID_COLLECTION_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ID"); - }); - - test("Errors with the code `INVALID_ID` if the supplied environment ID is invalid", async () => { - const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --env ${INVALID_ENVIRONMENT_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ID"); - }); - - test("Errors with the code `INVALID_SERVER_URL` if not supplying a valid SH instance server URL", async () => { - // FE URL of the staging SHC instance - const INVALID_SERVER_URL = "https://stage-shc.hoppscotch.io"; - const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --env ${REQ_BODY_ENV_VARS_ENVS_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${INVALID_SERVER_URL}`; - - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_SERVER_URL"); - }); - - test("Errors with the code `SERVER_CONNECTION_REFUSED` if supplying an SH instance server URL that doesn't follow URL semantics", async () => { - const INVALID_URL = "invalid-url"; - const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --env ${REQ_BODY_ENV_VARS_ENVS_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${INVALID_URL}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("SERVER_CONNECTION_REFUSED"); - }); - }); - - test("Successfully retrieves a collection with the ID", async () => { - const args = `test ${COLLECTION_LEVEL_HEADERS_AUTH_COLL_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`; - - const { error } = await runCLI(args); - expect(error).toBeNull(); - }); - - test("Successfully retrieves collections and environments from a workspace using their respective IDs", async () => { - const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --env ${REQ_BODY_ENV_VARS_ENVS_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`; - - const { error } = await runCLI(args); - expect(error).toBeNull(); - }); - - test("Supports specifying collection file path along with environment ID", async () => { - const COLL_PATH = getTestJsonFilePath( - "req-body-env-vars-coll.json", - "collection" - ); - const args = `test ${COLL_PATH} --env ${REQ_BODY_ENV_VARS_ENVS_ID} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`; - - const { error } = await runCLI(args); - expect(error).toBeNull(); - }); - - test("Supports specifying environment file path along with collection ID", async () => { - const ENV_PATH = getTestJsonFilePath( - "req-body-env-vars-envs.json", - "environment" - ); - const args = `test ${REQ_BODY_ENV_VARS_COLL_ID} --env ${ENV_PATH} --token ${PERSONAL_ACCESS_TOKEN} --server ${SERVER_URL}`; - - const { error } = await runCLI(args); - expect(error).toBeNull(); - }); - - test("Supports specifying both collection and environment file paths", async () => { - const COLL_PATH = getTestJsonFilePath( - "req-body-env-vars-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "req-body-env-vars-envs.json", - "environment" - ); - const args = `test ${COLL_PATH} --env ${ENV_PATH} --token ${PERSONAL_ACCESS_TOKEN}`; - - const { error } = await runCLI(args); - expect(error).toBeNull(); - }); - }); - - describe("Test`hopp test --env --reporter-junit [path]", () => { - const genPath = path.resolve("hopp-cli-test"); - - // Helper function to replace dynamic values before generating test snapshots - // Currently scoped to JUnit report generation - const replaceDynamicValuesInStr = (input: string): string => - input - .replace(/(time|timestamp)="[^"]+"/g, (_, attr) => `${attr}="${attr}"`) - // Strip QuickJS GC assertion errors - these are non-deterministic - // and appear after script errors when scope disposal fails - // Pattern matches multi-line format ending with ]] - .replace( - /\n\s*Then, failed to dispose scope: Aborted\(Assertion failed[^\]]*\]\]/g, - "" - ); - - beforeAll(() => { - fs.mkdirSync(genPath); - }); - - afterAll(() => { - fs.rmdirSync(genPath, { recursive: true }); - }); - - test("Report export fails with the code `REPORT_EXPORT_FAILED` while encountering an error during path creation", async () => { - const exportPath = "hopp-junit-report.xml"; - - const COLL_PATH = getTestJsonFilePath("passes-coll.json", "collection"); - - const invalidPath = - process.platform === "win32" - ? "Z:/non-existent-path/report.xml" - : "/non-existent/report.xml"; - - const args = `test ${COLL_PATH} --reporter-junit ${invalidPath}`; - - const { stdout, stderr } = await runCLI(args, { - cwd: path.resolve("hopp-cli-test"), - }); - - const out = getErrorCode(stderr); - expect(out).toBe("REPORT_EXPORT_FAILED"); - - expect(stdout).not.toContain( - `Successfully exported the JUnit report to: ${exportPath}` - ); - }); - - test("Generates a JUnit report at the default path", async () => { - const exportPath = "hopp-junit-report.xml"; - - const COLL_PATH = getTestJsonFilePath( - "test-junit-report-export-coll.json", - "collection" - ); - - const args = `test ${COLL_PATH} --reporter-junit`; - - // Use retry logic to handle transient network errors (ECONNRESET, etc.) - // that can corrupt JUnit XML structure and cause snapshot mismatches - const maxAttempts = 2; // Only retry once (2 total attempts) - let lastResult: Awaited> | null = null; - let lastFileContents = ""; - - for (let attempt = 0; attempt < maxAttempts; attempt++) { - lastResult = await runCLI(args, { - cwd: path.resolve("hopp-cli-test"), - }); - - // Read JUnit XML file - const fileContents = fs - .readFileSync(path.resolve(genPath, exportPath)) - .toString(); - - lastFileContents = fileContents; - - const hasNetworkErrorInXML = - /ECONNRESET|EAI_AGAIN|ENOTFOUND|ETIMEDOUT|ECONNREFUSED/i.test( - fileContents - ) || - (/REQUEST_ERROR/i.test(fileContents) && - !/Invalid URL/i.test(fileContents)); - - if (!hasNetworkErrorInXML) { - break; - } - - // Network error detected - retry once if not last attempt - if (attempt < maxAttempts - 1) { - console.log( - `⚠️ Network error detected in JUnit XML (ECONNRESET/DNS). Retrying once to get clean snapshot...` - ); - // Delete corrupted XML file before retry - try { - fs.unlinkSync(path.resolve(genPath, exportPath)); - } catch {} - await new Promise((r) => setTimeout(r, 2000)); - continue; - } - - // Last attempt exhausted - skip test to avoid false positive - console.warn( - `⚠️ Skipping snapshot test: Network errors persisted in JUnit XML after retry. External services may be degraded.` - ); - return; // Skip test - don't fail on infrastructure issues - } - - expect(lastResult?.stdout).not.toContain( - `Overwriting the pre-existing path: ${exportPath}` - ); - - expect(lastResult?.stdout).toContain( - `Successfully exported the JUnit report to: ${exportPath}` - ); - - expect(replaceDynamicValuesInStr(lastFileContents)).toMatchSnapshot(); - }); - - test("Generates a JUnit report at the specified path", async () => { - const exportPath = "outer-dir/inner-dir/report.xml"; - - const COLL_PATH = getTestJsonFilePath( - "test-junit-report-export-coll.json", - "collection" - ); - - const args = `test ${COLL_PATH} --reporter-junit ${exportPath}`; - - // Use retry logic to handle transient network errors (ECONNRESET, etc.) - // that can corrupt JUnit XML structure and cause snapshot mismatches - const maxAttempts = 2; // Only retry once (2 total attempts) - let lastResult: Awaited> | null = null; - let lastFileContents = ""; - - for (let attempt = 0; attempt < maxAttempts; attempt++) { - lastResult = await runCLI(args, { - cwd: path.resolve("hopp-cli-test"), - }); - - // Read JUnit XML file - const fileContents = fs - .readFileSync(path.resolve(genPath, exportPath)) - .toString(); - - lastFileContents = fileContents; - - const hasNetworkErrorInXML = - /ECONNRESET|EAI_AGAIN|ENOTFOUND|ETIMEDOUT|ECONNREFUSED/i.test( - fileContents - ) || - (/REQUEST_ERROR/i.test(fileContents) && - !/Invalid URL/i.test(fileContents)); - - if (!hasNetworkErrorInXML) { - break; - } - - // Network error detected - retry once if not last attempt - if (attempt < maxAttempts - 1) { - console.log( - `⚠️ Network error detected in JUnit XML (ECONNRESET/DNS). Retrying once to get clean snapshot...` - ); - // Delete corrupted XML file before retry - try { - fs.unlinkSync(path.resolve(genPath, exportPath)); - } catch {} - await new Promise((r) => setTimeout(r, 2000)); - continue; - } - - // Last attempt exhausted - skip test to avoid false positive - console.warn( - `⚠️ Skipping snapshot test: Network errors persisted in JUnit XML after retry. External services may be degraded.` - ); - return; // Skip test - don't fail on infrastructure issues - } - - expect(lastResult?.stdout).not.toContain( - `Overwriting the pre-existing path: ${exportPath}` - ); - - expect(lastResult?.stdout).toContain( - `Successfully exported the JUnit report to: ${exportPath}` - ); - - expect(replaceDynamicValuesInStr(lastFileContents)).toMatchSnapshot(); - }); - - test("Generates a JUnit report for a collection with authorization/headers set at the collection level", async () => { - const exportPath = "hopp-junit-report.xml"; - - const COLL_PATH = getTestJsonFilePath( - "collection-level-auth-headers-coll.json", - "collection" - ); - - const args = `test ${COLL_PATH} --reporter-junit`; - - // Use retry logic to handle transient network errors (ECONNRESET, etc.) - // that can corrupt JUnit XML structure and cause snapshot mismatches - const maxAttempts = 2; // Only retry once (2 total attempts) - let lastResult: Awaited> | null = null; - let lastFileContents = ""; - - for (let attempt = 0; attempt < maxAttempts; attempt++) { - lastResult = await runCLI(args, { - cwd: path.resolve("hopp-cli-test"), - }); - - // Read JUnit XML file - const fileContents = fs - .readFileSync(path.resolve(genPath, exportPath)) - .toString(); - - lastFileContents = fileContents; - - const hasNetworkErrorInXML = - /ECONNRESET|EAI_AGAIN|ENOTFOUND|ETIMEDOUT|ECONNREFUSED/i.test( - fileContents - ) || - (/REQUEST_ERROR/i.test(fileContents) && - !/Invalid URL/i.test(fileContents)); - - if (!hasNetworkErrorInXML) { - break; - } - - // Network error detected - retry once if not last attempt - if (attempt < maxAttempts - 1) { - console.log( - `⚠️ Network error detected in JUnit XML (ECONNRESET/DNS). Retrying once to get clean snapshot...` - ); - // Delete corrupted XML file before retry - try { - fs.unlinkSync(path.resolve(genPath, exportPath)); - } catch {} - await new Promise((r) => setTimeout(r, 2000)); - continue; - } - - // Last attempt exhausted - skip test to avoid false positive - console.warn( - `⚠️ Skipping snapshot test: Network errors persisted in JUnit XML after retry. External services may be degraded.` - ); - return; // Skip test - don't fail on infrastructure issues - } - - expect(lastResult?.stdout).toContain( - `Overwriting the pre-existing path: ${exportPath}` - ); - - expect(lastResult?.stdout).toContain( - `Successfully exported the JUnit report to: ${exportPath}` - ); - - expect(replaceDynamicValuesInStr(lastFileContents)).toMatchSnapshot(); - }); - - test("Generates a JUnit report for a collection referring to environment variables", async () => { - const exportPath = "hopp-junit-report.xml"; - - const COLL_PATH = getTestJsonFilePath( - "req-body-env-vars-coll.json", - "collection" - ); - const ENV_PATH = getTestJsonFilePath( - "req-body-env-vars-envs.json", - "environment" - ); - - const args = `test ${COLL_PATH} --env ${ENV_PATH} --reporter-junit`; - - // Use retry logic to handle transient network errors (ECONNRESET, etc.) - // that can corrupt JUnit XML structure and cause snapshot mismatches - const maxAttempts = 2; // Only retry once (2 total attempts) - let lastResult: Awaited> | null = null; - let lastFileContents = ""; - - for (let attempt = 0; attempt < maxAttempts; attempt++) { - lastResult = await runCLI(args, { - cwd: path.resolve("hopp-cli-test"), - }); - - // Read JUnit XML file - const fileContents = fs - .readFileSync(path.resolve(genPath, exportPath)) - .toString(); - - lastFileContents = fileContents; - - const hasNetworkErrorInXML = - /ECONNRESET|EAI_AGAIN|ENOTFOUND|ETIMEDOUT|ECONNREFUSED/i.test( - fileContents - ) || - (/REQUEST_ERROR/i.test(fileContents) && - !/Invalid URL/i.test(fileContents)); - - if (!hasNetworkErrorInXML) { - break; - } - - // Network error detected - retry once if not last attempt - if (attempt < maxAttempts - 1) { - console.log( - `⚠️ Network error detected in JUnit XML (ECONNRESET/DNS). Retrying once to get clean snapshot...` - ); - // Delete corrupted XML file before retry - try { - fs.unlinkSync(path.resolve(genPath, exportPath)); - } catch {} - await new Promise((r) => setTimeout(r, 2000)); - continue; - } - - // Last attempt exhausted - skip test to avoid false positive - console.warn( - `⚠️ Skipping snapshot test: Network errors persisted in JUnit XML after retry. External services may be degraded.` - ); - return; // Skip test - don't fail on infrastructure issues - } - - expect(lastResult?.stdout).toContain( - `Overwriting the pre-existing path: ${exportPath}` - ); - - expect(lastResult?.stdout).toContain( - `Successfully exported the JUnit report to: ${exportPath}` - ); - - expect(replaceDynamicValuesInStr(lastFileContents)).toMatchSnapshot(); - }); - }); - - describe("Test `hopp test --iteration-count ` command:", () => { - const VALID_TEST_ARGS = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`; - - test("Errors with the code `INVALID_ARGUMENT` on not supplying an iteration count", async () => { - const args = `${VALID_TEST_ARGS} --iteration-count`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - - test("Errors with the code `INVALID_ARGUMENT` on supplying an invalid iteration count", async () => { - const args = `${VALID_TEST_ARGS} --iteration-count NaN`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - - test("Errors with the code `INVALID_ARGUMENT` on supplying an iteration count below `1`", async () => { - const args = `${VALID_TEST_ARGS} --iteration-count -5`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - - test("Successfully executes all requests in the collection iteratively based on the specified iteration count", async () => { - const iterationCount = 3; - const args = `${VALID_TEST_ARGS} --iteration-count ${iterationCount}`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - Array.from({ length: 3 }).forEach((_, idx) => - expect(result.stdout).include(`Iteration: ${idx + 1}/${iterationCount}`) - ); - expect(result.error).toBeNull(); - }); - - test("Doesn't log iteration count if the value supplied is `1`", async () => { - const args = `${VALID_TEST_ARGS} --iteration-count 1`; - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - expect(result.stdout).not.include(`Iteration: 1/1`); - - expect(result.error).toBeNull(); - }); - }); - - describe("Test `hopp test --iteration-data ` command:", () => { - describe("Supplied data export file validations", () => { - const VALID_TEST_ARGS = `test ${getTestJsonFilePath("passes-coll.json", "collection")}`; - - test("Errors with the code `INVALID_ARGUMENT` if no file is supplied", async () => { - const args = `${VALID_TEST_ARGS} --iteration-data`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_ARGUMENT"); - }); - - test("Errors with the code `INVALID_DATA_FILE_TYPE` if the supplied data file doesn't end with the `.csv` extension", async () => { - const args = `${VALID_TEST_ARGS} --iteration-data ${getTestJsonFilePath( - "notjson-coll.txt", - "collection" - )}`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("INVALID_DATA_FILE_TYPE"); - }); - - test("Errors with the code `FILE_NOT_FOUND` if the supplied data export file doesn't exist", async () => { - const args = `${VALID_TEST_ARGS} --iteration-data notfound.csv`; - const { stderr } = await runCLI(args); - - const out = getErrorCode(stderr); - expect(out).toBe("FILE_NOT_FOUND"); - }); - }); - - test("Prioritizes values from the supplied data export file over environment variables with relevant fallbacks for missing entries", async () => { - const COLL_PATH = getTestJsonFilePath( - "iteration-data-tests-coll.json", - "collection" - ); - const ITERATION_DATA_PATH = getTestJsonFilePath( - "iteration-data-export.csv", - "environment" - ); - const ENV_PATH = getTestJsonFilePath( - "iteration-data-envs.json", - "environment" - ); - const args = `test ${COLL_PATH} --iteration-data ${ITERATION_DATA_PATH} -e ${ENV_PATH}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - const iterationCount = 3; - - Array.from({ length: iterationCount }).forEach((_, idx) => - expect(result.stdout).include(`Iteration: ${idx + 1}/${iterationCount}`) - ); - - expect(result.error).toBeNull(); - }); - - test("Iteration count takes priority if supplied instead of inferring from the iteration data size", async () => { - const COLL_PATH = getTestJsonFilePath( - "iteration-data-tests-coll.json", - "collection" - ); - const ITERATION_DATA_PATH = getTestJsonFilePath( - "iteration-data-export.csv", - "environment" - ); - const ENV_PATH = getTestJsonFilePath( - "iteration-data-envs.json", - "environment" - ); - - const iterationCount = 5; - const args = `test ${COLL_PATH} --iteration-data ${ITERATION_DATA_PATH} -e ${ENV_PATH} --iteration-count ${iterationCount}`; - - const result = await runCLIWithNetworkRetry(args); - if (result === null) return; - - Array.from({ length: iterationCount }).forEach((_, idx) => - expect(result.stdout).include(`Iteration: ${idx + 1}/${iterationCount}`) - ); - - expect(result.error).toBeNull(); - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/aws-signature-auth-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/aws-signature-auth-coll.json deleted file mode 100644 index eae88b75..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/aws-signature-auth-coll.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "v": 3, - "name": "AWS Signature Auth - collection", - "folders": [], - "requests": [ - { - "v": "7", - "id": "cm0dm70cw000687bnxi830zz7", - "auth": { - "addTo": "HEADERS", - "region": "<>", - "authType": "aws-signature", - "accessKey": "<>", - "secretKey": "<>", - "authActive": true, - "serviceName": "<>", - "serviceToken": "", - "grantTypeInfo": { - "token": "", - "isPKCE": false, - "clientID": "", - "grantType": "AUTHORIZATION_CODE", - "authEndpoint": "", - "clientSecret": "", - "tokenEndpoint": "", - "codeVerifierMethod": "S256" - } - }, - "body": { - "body": null, - "contentType": null - }, - "name": "aws-signature-auth-headers", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "<>", - "testScript": "pw.test(\"Successfully sends relevant AWS signature information via headers\", ()=> {\n const { headers } = pw.response.body\n\n // Dynamic values, hence comparing the type.\n pw.expect(headers[\"authorization\"]).toBeType(\"string\");\n pw.expect(headers[\"x-amz-date\"]).toBeType(\"string\");\n \n pw.expect(headers[\"x-amz-content-sha256\"]).toBe(\"UNSIGNED-PAYLOAD\")\n \n // No session token supplied\n pw.expect(headers[\"x-amz-security-token\"]).toBe(undefined)\n \n});", - "preRequestScript": "", - "requestVariables": [ - { - "key": "secretVarKey", - "value": "<>", - "active": true - } - ] - }, - { - "v": "7", - "id": "cm0dm70cw000687bnxi830zz7", - "auth": { - "addTo": "QUERY_PARAMS", - "region": "<>", - "authType": "aws-signature", - "accessKey": "<>", - "secretKey": "<>", - "authActive": true, - "serviceName": "<>", - "serviceToken": "<>", - "grantTypeInfo": { - "token": "", - "isPKCE": false, - "clientID": "", - "grantType": "AUTHORIZATION_CODE", - "authEndpoint": "", - "clientSecret": "", - "tokenEndpoint": "", - "codeVerifierMethod": "S256" - } - }, - "body": { - "body": null, - "contentType": null - }, - "name": "aws-signature-auth-query-params", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "<>", - "testScript": "pw.test(\"Successfully sends relevant AWS signature information via query params\", ()=> {\n const { args } = pw.response.body\n pw.expect(args[\"X-Amz-Algorithm\"]).toBe(\"AWS4-HMAC-SHA256\");\n pw.expect(args[\"X-Amz-Algorithm\"]).toBe(\"AWS4-HMAC-SHA256\");\n pw.expect(args[\"X-Amz-Credential\"]).toInclude(\"test-access-key\");\n pw.expect(args[\"X-Amz-Credential\"]).toInclude(\"eu-west-1/s3\");\n\n // Dynamic values, hence comparing the type.\n pw.expect(args[\"X-Amz-Date\"]).toBeType(\"string\");\n pw.expect(args[\"X-Amz-Signature\"]).toBeType(\"string\");\n\n pw.expect(args[\"X-Amz-Expires\"]).toBe(\"86400\")\n pw.expect(args[\"X-Amz-SignedHeaders\"]).toBe(\"host\")\n pw.expect(args[\"X-Amz-Security-Token\"]).toBe(\"test-token\")\n \n});", - "preRequestScript": "", - "requestVariables": [ - { - "key": "awsRegion", - "value": "eu-west-1", - "active": true - }, - { - "key": "secretKey", - "value": "test-secret-key-overriden", - "active": true - } - ] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v1-req-v0.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v1-req-v0.json deleted file mode 100644 index bf63d2ae..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v1-req-v0.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "v": 1, - "name": "coll-v1", - "folders": [ - { - "v": 1, - "name": "coll-v1-child", - "folders": [], - "requests": [ - { - "url": "https://echo.hoppscotch.io", - "path": "/get", - "headers": [ - { "key": "Inactive-Header", "value": "Inactive Header", "active": false }, - { "key": "Authorization", "value": "Bearer token123", "active": true } - ], - "params": [ - { "key": "key", "value": "value", "active": true }, - { "key": "inactive-key", "value": "inactive-param", "active": false } - ], - "name": "req-v0-II", - "method": "GET", - "preRequestScript": "", - "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})", - "contentType": "application/json", - "body": "", - "auth": "Bearer Token", - "bearerToken": "token123" - } - ] - } - ], - "requests": [ - { - "url": "https://echo.hoppscotch.io", - "path": "/get", - "headers": [ - { "key": "Inactive-Header", "value": "Inactive Header", "active": false }, - { "key": "Authorization", "value": "Bearer token123", "active": true } - ], - "params": [ - { "key": "key", "value": "value", "active": true }, - { "key": "inactive-key", "value": "inactive-param", "active": false } - ], - "name": "req-v0", - "method": "GET", - "preRequestScript": "", - "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})", - "contentType": "application/json", - "body": "", - "auth": "Bearer Token", - "bearerToken": "token123" - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v1-req-v1.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v1-req-v1.json deleted file mode 100644 index 9bfc979e..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v1-req-v1.json +++ /dev/null @@ -1,97 +0,0 @@ -{ - "v": 1, - "name": "coll-v1", - "folders": [ - { - "v": 1, - "name": "coll-v1-child", - "folders": [], - "requests": [ - { - "v": "1", - "endpoint": "https://echo.hoppscotch.io", - "headers": [ - { - "key": "Inactive-Header", - "value": "Inactive Header", - "active": false - }, - { - "key": "Authorization", - "value": "Bearer token123", - "active": true - } - ], - "params": [ - { - "key": "key", - "value": "value", - "active": true - }, - { - "key": "inactive-key", - "value": "inactive-param", - "active": false - } - ], - "name": "req-v1-II", - "method": "GET", - "preRequestScript": "", - "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})", - "body": { - "contentType": null, - "body": null - }, - "auth": { - "authType": "bearer", - "authActive": true, - "token": "token123" - } - } - ] - } - ], - "requests": [ - { - "v": "1", - "endpoint": "https://echo.hoppscotch.io", - "headers": [ - { - "key": "Inactive-Header", - "value": "Inactive Header", - "active": false - }, - { - "key": "Authorization", - "value": "Bearer token123", - "active": true - } - ], - "params": [ - { - "key": "key", - "value": "value", - "active": true - }, - { - "key": "inactive-key", - "value": "inactive-param", - "active": false - } - ], - "name": "req-v1", - "method": "GET", - "preRequestScript": "", - "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})", - "body": { - "contentType": null, - "body": null - }, - "auth": { - "authType": "bearer", - "authActive": true, - "token": "token123" - } - } - ] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v2-req-v2.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v2-req-v2.json deleted file mode 100644 index 0bcbd132..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v2-req-v2.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "v": 2, - "name": "coll-v2", - "folders": [ - { - "v": 2, - "name": "coll-v2-child", - "folders": [], - "requests": [ - { - "v": "2", - "endpoint": "https://echo.hoppscotch.io", - "headers": [ - { - "key": "Inactive-Header", - "value": "Inactive Header", - "active": false - }, - { - "key": "Authorization", - "value": "Bearer token123", - "active": true - } - ], - "params": [ - { - "key": "key", - "value": "value", - "active": true - }, - { - "key": "inactive-key", - "value": "inactive-param", - "active": false - } - ], - "name": "req-v2-II", - "method": "GET", - "preRequestScript": "", - "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})", - "body": { - "contentType": null, - "body": null - }, - "auth": { - "authType": "bearer", - "authActive": true, - "token": "token123" - }, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] - } - ], - "requests": [ - { - "v": "2", - "endpoint": "https://echo.hoppscotch.io", - "headers": [ - { - "key": "Inactive-Header", - "value": "Inactive Header", - "active": false - }, - { - "key": "Authorization", - "value": "Bearer token123", - "active": true - } - ], - "params": [ - { - "key": "key", - "value": "value", - "active": true - }, - { - "key": "inactive-key", - "value": "inactive-param", - "active": false - } - ], - "name": "req-v2", - "method": "GET", - "preRequestScript": "", - "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})", - "body": { - "contentType": null, - "body": null - }, - "auth": { - "authType": "bearer", - "authActive": true, - "token": "token123" - }, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v2-req-v3.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v2-req-v3.json deleted file mode 100644 index 916e809d..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/coll-v2-req-v3.json +++ /dev/null @@ -1,109 +0,0 @@ -{ - "v": 2, - "name": "coll-v2", - "folders": [ - { - "v": 2, - "name": "coll-v2-child", - "folders": [], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io", - "headers": [ - { - "key": "Inactive-Header", - "value": "Inactive Header", - "active": false - }, - { - "key": "Authorization", - "value": "Bearer token123", - "active": true - } - ], - "params": [ - { - "key": "key", - "value": "value", - "active": true - }, - { - "key": "inactive-key", - "value": "inactive-param", - "active": false - } - ], - "name": "req-v3-II", - "method": "GET", - "preRequestScript": "", - "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})", - "body": { - "contentType": null, - "body": null - }, - "auth": { - "authType": "bearer", - "authActive": true, - "token": "token123" - }, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] - } - ], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io", - "headers": [ - { - "key": "Inactive-Header", - "value": "Inactive Header", - "active": false - }, - { - "key": "Authorization", - "value": "Bearer token123", - "active": true - } - ], - "params": [ - { - "key": "key", - "value": "value", - "active": true - }, - { - "key": "inactive-key", - "value": "inactive-param", - "active": false - } - ], - "name": "req-v3", - "method": "GET", - "preRequestScript": "", - "testScript": "pw.test(\"Asserts request params\", () => {\n pw.expect(pw.response.body.args.key).toBe(\"value\")\n pw.expect(pw.response.body.args[\"inactive-key\"]).toBe(undefined)\n})\n\npw.test(\"Asserts request headers\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer token123\")\n pw.expect(pw.response.body.headers[\"inactive-header\"]).toBe(undefined)\n})", - "body": { - "contentType": null, - "body": null - }, - "auth": { - "authType": "bearer", - "authActive": true, - "token": "token123" - }, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-auth-headers-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-auth-headers-coll.json deleted file mode 100644 index bdca78c6..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-auth-headers-coll.json +++ /dev/null @@ -1,227 +0,0 @@ -[ - { - "v": 2, - "name": "CollectionA", - "folders": [ - { - "v": 2, - "name": "FolderA", - "folders": [ - { - "v": 2, - "name": "FolderB", - "folders": [ - { - "v": 2, - "name": "FolderC", - "folders": [], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io", - "name": "RequestD", - "params": [], - "headers": [ - { - "active": true, - "key": "X-Test-Header", - "value": "Overriden at RequestD" - } - ], - "method": "GET", - "auth": { - "authType": "basic", - "authActive": true, - "username": "username", - "password": "password" - }, - "preRequestScript": "", - "testScript": "pw.test(\"Overrides auth and headers set at the parent folder\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Overriden at RequestD\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] - } - ], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io", - "name": "RequestC", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "inherit", - "authActive": true - }, - "preRequestScript": "", - "testScript": "pw.test(\"Correctly inherits auth and headers from the parent folder\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Overriden at FolderB\");\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"test-key\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [] - } - ], - "auth": { - "authType": "api-key", - "authActive": true, - "addTo": "HEADERS", - "key": "key", - "value": "test-key" - }, - "headers": [ - { - "active": true, - "key": "X-Test-Header", - "value": "Overriden at FolderB" - } - ] - } - ], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io", - "name": "RequestB", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "inherit", - "authActive": true - }, - "preRequestScript": "", - "testScript": "pw.test(\"Correctly inherits auth and headers from the parent folder\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Set at root collection\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer BearerToken\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "id": "clpttpdq00003qp16kut6doqv" - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] - } - ], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io", - "name": "RequestA", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "inherit", - "authActive": true - }, - "preRequestScript": "", - "testScript": "pw.test(\"Correctly inherits auth and headers from the root collection\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Set at root collection\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer BearerToken\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "id": "clpttpdq00003qp16kut6doqv" - } - ], - "headers": [ - { - "active": true, - "key": "X-Test-Header", - "value": "Set at root collection" - } - ], - "auth": { - "authType": "bearer", - "authActive": true, - "token": "BearerToken" - } - }, - { - "v": 2, - "name": "CollectionB", - "folders": [ - { - "v": 2, - "name": "FolderA", - "folders": [], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io", - "name": "RequestB", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "inherit", - "authActive": true - }, - "preRequestScript": "", - "testScript": "pw.test(\"Correctly inherits auth and headers from the parent folder\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Set at root collection\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer BearerToken\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "id": "clpttpdq00003qp16kut6doqv" - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] - } - ], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io", - "name": "RequestA", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "inherit", - "authActive": true - }, - "preRequestScript": "", - "testScript": "pw.test(\"Correctly inherits auth and headers from the root collection\", ()=> {\n pw.expect(pw.response.body.headers[\"x-test-header\"]).toBe(\"Set at root collection\");\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Bearer BearerToken\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "id": "clpttpdq00003qp16kut6doqv" - } - ], - "headers": [ - { - "active": true, - "key": "X-Test-Header", - "value": "Set at root collection" - } - ], - "auth": { - "authType": "bearer", - "authActive": true, - "token": "BearerToken" - } - } -] diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-scripts-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-scripts-coll.json deleted file mode 100644 index 38bae839..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-level-scripts-coll.json +++ /dev/null @@ -1,114 +0,0 @@ -{ - "v": 12, - "name": "collection-level-scripts-coll", - "variables": [], - "description": null, - "folders": [ - { - "v": 12, - "name": "target-folder", - "variables": [], - "description": null, - "folders": [], - "requests": [ - { - "v": "17", - "id": "cl-script-req-1", - "name": "target-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "pw.env.set(\"REQ_RAN\", \"yes\");\npw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->target-req\");", - "testScript": "pw.env.set(\"TEST_ORDER\", \"target-req\");\npw.env.set(\"ORDER_AT_REQ\", pw.env.get(\"TEST_ORDER\"));\npw.test(\"pre-script cascade ran in root->target-folder->target-req order\", () => {\n pw.expect(pw.env.get(\"PRE_ORDER\")).toBe(\"root->target-folder->target-req\");\n});\npw.test(\"all cascade pre-scripts committed env vars\", () => {\n pw.expect(pw.env.get(\"ROOT_RAN\")).toBe(\"yes\");\n pw.expect(pw.env.get(\"TARGET_FOLDER_RAN\")).toBe(\"yes\");\n pw.expect(pw.env.get(\"REQ_RAN\")).toBe(\"yes\");\n});\npw.test(\"request-level test observed request position in test-cascade\", () => {\n pw.expect(pw.env.get(\"ORDER_AT_REQ\")).toBe(\"target-req\");\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cl-script-req-2", - "name": "sibling-request-in-target-folder", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "pw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->sibling-req-in-target\");", - "testScript": "pw.env.set(\"TEST_ORDER\", \"sibling-req-in-target\");\npw.test(\"sibling request cascade is root->target-folder->this-request\", () => {\n pw.expect(pw.env.get(\"PRE_ORDER\")).toBe(\"root->target-folder->sibling-req-in-target\");\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "preRequestScript": "pw.env.set(\"TARGET_FOLDER_RAN\", \"yes\");\npw.env.set(\"TARGET_FOLDER_RUN_COUNT\", String((parseInt(pw.env.get(\"TARGET_FOLDER_RUN_COUNT\") || \"0\", 10)) + 1));\npw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->target-folder\");", - "testScript": "pw.env.set(\"TEST_ORDER\", pw.env.get(\"TEST_ORDER\") + \"->target-folder\");\npw.env.set(\"ORDER_AT_TARGET_FOLDER\", pw.env.get(\"TEST_ORDER\"));" - }, - { - "v": 12, - "name": "sibling-folder", - "variables": [], - "description": null, - "folders": [], - "requests": [ - { - "v": "17", - "id": "cl-script-req-3", - "name": "sibling-request-in-sibling-folder", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "pw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->sibling-req-in-sibling\");", - "testScript": "pw.env.set(\"TEST_ORDER\", \"sibling-req-in-sibling\");\npw.test(\"sibling-folder cascade is root->sibling-folder->this-request (no target-folder leak)\", () => {\n pw.expect(pw.env.get(\"PRE_ORDER\")).toBe(\"root->sibling-folder->sibling-req-in-sibling\");\n});\npw.test(\"target-folder pre-script ran exactly twice (one per request in target-folder)\", () => {\n pw.expect(pw.env.get(\"TARGET_FOLDER_RUN_COUNT\")).toBe(\"2\");\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "preRequestScript": "pw.env.set(\"SIBLING_FOLDER_RAN\", \"yes\");\npw.env.set(\"PRE_ORDER\", pw.env.get(\"PRE_ORDER\") + \"->sibling-folder\");", - "testScript": "pw.env.set(\"TEST_ORDER\", pw.env.get(\"TEST_ORDER\") + \"->sibling-folder\");" - } - ], - "requests": [], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "preRequestScript": "pw.env.set(\"ROOT_RAN\", \"yes\");\npw.env.set(\"PRE_ORDER\", \"root\");", - "testScript": "pw.env.set(\"TEST_ORDER\", pw.env.get(\"TEST_ORDER\") + \"->root\");\npw.test(\"test-script cascade ran in request->folder->root order for every request\", () => {\n pw.expect([\"target-req->target-folder->root\", \"sibling-req-in-target->target-folder->root\", \"sibling-req-in-sibling->sibling-folder->root\"].includes(pw.env.get(\"TEST_ORDER\"))).toBe(true);\n});" -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-with-variables.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-with-variables.json deleted file mode 100644 index d5383da5..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/collection-with-variables.json +++ /dev/null @@ -1,326 +0,0 @@ -{ - "id": "cmeicx49r00xylb1jxektmknk", - "_ref_id": "coll_meicx3z7_a1cb5e72-cd1b-414b-adc2-7d601ca0936d", - "v": 10, - "name": "coll-with-variables", - "folders": [ - { - "id": "cmeicy6fu00xzlb1jqmmqbjdm", - "_ref_id": "coll_meie14lh_818ea8a2-9839-4a1c-8cce-cc7565b5f594", - "v": 10, - "name": "folder-1", - "folders": [], - "requests": [ - { - "v": "15", - "id": "cmeicyhnn00y1lb1j8d80g7ys", - "name": "request-1", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [ - { - "key": "collection-var-1", - "value": "<>", - "active": true, - "description": "" - }, - { - "key": "collection-var-2", - "value": "<>", - "active": true, - "description": "" - }, - { - "key": "folder-var-1", - "value": "<>", - "active": true, - "description": "" - }, - { - "key": "folder-var-2", - "value": "<>", - "active": true, - "description": "" - } - ], - "headers": [], - "preRequestScript": "", - "testScript": "pw.test('Correctly inherits collection variables from the parent collection and folder', () => {\n pw.expect([\n \"collection-var-1-initial-value\",\n \"collection-var-1-current-value\"\n ]).toInclude(pw.response.body.args[\"collection-var-1\"]);\n\n pw.expect([\n \"collection-var-2-initial-value\",\n \"collection-var-2-current-value\"\n ]).toInclude(pw.response.body.args[\"collection-var-2\"]);\n\n pw.expect([\n \"folder-variable-1-initial-value\",\n \"folder-variable-1-current-value\"\n ]).toInclude(pw.response.body.args[\"folder-var-1\"]);\n\n pw.expect([\n \"folder-variable-2-initial-value\",\n \"folder-variable-2-current-value\"\n ]).toInclude(pw.response.body.args[\"folder-var-2\"]);\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "variables": [ - { - "key": "folder-variable-1", - "secret": false, - "currentValue": "", - "initialValue": "folder-variable-1-initial-value" - }, - { - "key": "folder-variable-2", - "secret": false, - "currentValue": "", - "initialValue": "folder-variable-2-initial-value" - } - ] - }, - { - "id": "empty_folder_test", - "_ref_id": "coll_empty_folder", - "v": 10, - "name": "folder-without-variables", - "folders": [ - { - "id": "nested_folder_test", - "_ref_id": "coll_nested_folder", - "v": 10, - "name": "nested-folder", - "folders": [], - "requests": [ - { - "v": "15", - "id": "nested_request", - "name": "deeply-nested-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [ - { - "key": "nested-var-1", - "value": "<>", - "active": true, - "description": "" - }, - { - "key": "nested-var-2", - "value": "<>", - "active": true, - "description": "" - } - ], - "headers": [], - "preRequestScript": "", - "testScript": "pw.test('Nested folder should inherit variables from root collection through parent', () => {\n pw.expect([\n \"collection-var-1-initial-value\",\n \"collection-var-1-current-value\"\n ]).toInclude(pw.response.body.args[\"nested-var-1\"]);\n\n pw.expect([\n \"collection-var-2-initial-value\",\n \"collection-var-2-current-value\"\n ]).toInclude(pw.response.body.args[\"nested-var-2\"]);\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "variables": [] - } - ], - "requests": [ - { - "v": "15", - "id": "request_in_empty_folder", - "name": "request-inheriting-collection-vars", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [ - { - "key": "inherited-var-1", - "value": "<>", - "active": true, - "description": "" - }, - { - "key": "inherited-var-2", - "value": "<>", - "active": true, - "description": "" - } - ], - "headers": [], - "preRequestScript": "", - "testScript": "pw.test('Folder without variables should inherit from parent collection', () => {\n pw.expect([\n \"collection-var-1-initial-value\",\n \"collection-var-1-current-value\"\n ]).toInclude(pw.response.body.args[\"inherited-var-1\"]);\n\n pw.expect([\n \"collection-var-2-initial-value\",\n \"collection-var-2-current-value\"\n ]).toInclude(pw.response.body.args[\"inherited-var-2\"]);\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "variables": [] - }, - { - "id": "precedence_test_folder", - "_ref_id": "coll_precedence_folder", - "v": 10, - "name": "folder-with-override", - "folders": [], - "requests": [ - { - "v": "15", - "id": "request_with_override", - "name": "request-with-folder-override", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [ - { - "key": "overridden-var", - "value": "<>", - "active": true, - "description": "" - }, - { - "key": "non-overridden-var", - "value": "<>", - "active": true, - "description": "" - } - ], - "headers": [], - "preRequestScript": "", - "testScript": "pw.test('Folder variable should take precedence over collection variable with same key', () => {\n // collection-variable-1 is overridden by folder, should be 'folder-override-value'\n pw.expect(pw.response.body.args[\"overridden-var\"]).toBe(\"folder-override-value\");\n\n // collection-variable-2 is NOT overridden, should be from collection\n pw.expect([\n \"collection-var-2-initial-value\",\n \"collection-var-2-current-value\"\n ]).toInclude(pw.response.body.args[\"non-overridden-var\"]);\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "variables": [ - { - "key": "collection-variable-1", - "secret": false, - "currentValue": "", - "initialValue": "folder-override-value" - } - ] - } - ], - "requests": [ - { - "v": "15", - "id": "root_level_request", - "name": "root-level-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [ - { - "key": "root-var-1", - "value": "<>", - "active": true, - "description": "" - }, - { - "key": "root-var-2", - "value": "<>", - "active": true, - "description": "" - } - ], - "headers": [], - "preRequestScript": "", - "testScript": "pw.test('Root-level request should access collection variables directly', () => {\n pw.expect([\n \"collection-var-1-initial-value\",\n \"collection-var-1-current-value\"\n ]).toInclude(pw.response.body.args[\"root-var-1\"]);\n\n pw.expect([\n \"collection-var-2-initial-value\",\n \"collection-var-2-current-value\"\n ]).toInclude(pw.response.body.args[\"root-var-2\"]);\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - }, - { - "v": "15", - "id": "root_level_request_with_precedence", - "name": "root-request-variable-precedence", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [ - { - "key": "precedence-test", - "value": "<>", - "active": true, - "description": "" - } - ], - "headers": [], - "preRequestScript": "", - "testScript": "pw.test('Request variable takes precedence over collection variable with same key', () => {\n // collection-variable-1 exists at collection level with value \"collection-var-1-initial-value\"\n // but request variable overrides it with \"request-wins\"\n pw.expect(pw.response.body.args[\"precedence-test\"]).toBe(\"request-wins\");\n});", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [ - { - "key": "collection-variable-1", - "value": "request-wins", - "active": true - } - ], - "responses": {} - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [], - "variables": [ - { - "key": "collection-variable-1", - "secret": false, - "currentValue": "", - "initialValue": "collection-var-1-initial-value" - }, - { - "key": "collection-variable-2", - "secret": false, - "currentValue": "", - "initialValue": "collection-var-2-initial-value" - } - ] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/content-type-header-scenarios.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/content-type-header-scenarios.json deleted file mode 100644 index 9aea2c0f..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/content-type-header-scenarios.json +++ /dev/null @@ -1,171 +0,0 @@ -{ - "v": 2, - "name": "content-type-header-scenarios", - "folders": [], - "requests": [ - { - "v": "6", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "\n\n \n 12345\n John Doe\n john.doe@example.com\n \n \n 98765\n Sample Product\n 2\n \n\n", - "contentType": "text/xml" - }, - "name": "content-type-header-assignment", - "method": "POST", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "pw.test(\"The `Content-Type` header is assigned the content type value set at the request body level\", ()=> {\n pw.expect(pw.response.body.headers[\"content-type\"]).toBe(\"text/xml\");\n});", - "preRequestScript": "", - "requestVariables": [] - }, - { - "v": "6", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "\n\n \n 12345\n John Doe\n john.doe@example.com\n \n \n 98765\n Sample Product\n 2\n \n\n", - "contentType": "application/json" - }, - "name": "content-type-header-override", - "method": "POST", - "params": [], - "headers": [ - { - "key": "Content-Type", - "value": "application/xml", - "active": true - } - ], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "pw.test(\"The `Content-Type` header overrides the content type value set at the request body level\", ()=> {\n pw.expect(pw.response.body.headers[\"content-type\"]).toBe(\"application/xml\");\n});", - "preRequestScript": "", - "requestVariables": [] - }, - { - "v": "6", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "\n\n \n 12345\n John Doe\n john.doe@example.com\n \n \n 98765\n Sample Product\n 2\n \n\n", - "contentType": "application/json" - }, - "name": "multiple-content-type-headers", - "method": "POST", - "params": [], - "headers": [ - { - "key": "Content-Type", - "value": "text/xml", - "active": true - }, - { - "key": "Content-Type", - "value": "application/json", - "active": true - }, - { - "key": "Content-Type", - "value": "application/xml", - "active": true - } - ], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "pw.test(\"The last occurrence will be considered among multiple `Content-Type` headers\", ()=> {\n pw.expect(pw.response.body.headers[\"content-type\"]).toBe(\"application/xml\");\n});", - "preRequestScript": "", - "requestVariables": [] - }, - { - "v": "6", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "\n\n \n 12345\n John Doe\n john.doe@example.com\n \n \n 98765\n Sample Product\n 2\n \n\n", - "contentType": null - }, - "name": "multiple-content-type-headers-different-casing", - "method": "POST", - "params": [], - "headers": [ - { - "key": "Content-Type", - "value": "text/xml", - "active": true - }, - { - "key": "content-Type", - "value": "application/json", - "active": true - }, - { - "key": "Content-type", - "value": "text/plain", - "active": true - }, - { - "key": "CONTENT-TYPE", - "value": "application/xml", - "active": true - } - ], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "pw.test(\"The last occurrence will be considered among multiple `Content-Type` headers following different casing\", ()=> {\n pw.expect(pw.response.body.headers[\"content-type\"]).toBe(\"application/xml\");\n});", - "preRequestScript": "", - "requestVariables": [] - }, - { - "v": "6", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "\n\n \n 12345\n John Doe\n john.doe@example.com\n \n \n 98765\n Sample Product\n 2\n \n\n", - "contentType": null - }, - "name": "multiple-content-type-headers-different-casing-without-value-set-at-body", - "method": "POST", - "params": [], - "headers": [ - { - "key": "Content-Type", - "value": "text/xml", - "active": true - }, - { - "key": "content-Type", - "value": "application/json", - "active": true - }, - { - "key": "Content-type", - "value": "text/plain", - "active": true - }, - { - "key": "CONTENT-TYPE", - "value": "application/xml", - "active": true - } - ], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "pw.test(\"The content type is inferred from the `Content-Type` header if not set at the request body\", ()=> {\n pw.expect(pw.response.body.headers[\"content-type\"]).toBe(\"application/xml\");\n});", - "preRequestScript": "", - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/digest-auth-failure-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/digest-auth-failure-coll.json deleted file mode 100644 index d8ab5ef2..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/digest-auth-failure-coll.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "v": 3, - "name": "Digest Auth (failure state) - collection", - "folders": [], - "requests": [ - { - "v": "8", - "id": "cm0dm70cw000687bnxi830zz7", - "auth": { - "authType": "digest", - "authActive": true, - "username": "<>", - "password": "<>", - "realm": "", - "nonce": "", - "algorithm": "MD5", - "qop": "auth", - "nc": "", - "cnonce": "", - "opaque": "", - "disableRetry": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "digest-auth-headers", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "<>", - "testScript": "pw.test(\"Status code is not 200\", ()=> { pw.expect(pw.response.status).not.toBe(200);}); \n pw.test(\"Receives the www-authenticate header\", ()=> { pw.expect(pw.response.headers['www-authenticate']).not.toBeType('string');});", - "preRequestScript": "", - "responses": {}, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/digest-auth-success-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/digest-auth-success-coll.json deleted file mode 100644 index 16f0b6fc..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/digest-auth-success-coll.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "v": 3, - "name": "Digest Auth (success state) - collection", - "folders": [], - "requests": [ - { - "v": "8", - "id": "cm0dm70cw000687bnxi830zz7", - "auth": { - "authType": "digest", - "authActive": true, - "username": "<>", - "password": "<>", - "realm": "", - "nonce": "", - "algorithm": "MD5", - "qop": "auth", - "nc": "", - "cnonce": "", - "opaque": "", - "disableRetry": false - }, - "body": { - "body": null, - "contentType": null - }, - "name": "digest-auth-headers", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "<>", - "testScript": "pw.test(\"Status code is 200\", ()=> { pw.expect(pw.response.status).toBe(200);}); \n pw.test(\"Receives the www-authenticate header\", ()=> { pw.expect(pw.response.headers['www-authenticate']).toBeType('string');});", - "preRequestScript": "", - "responses": {}, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/env-flag-tests-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/env-flag-tests-coll.json deleted file mode 100644 index ded538ab..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/env-flag-tests-coll.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "v": 1, - "name": "env-flag-tests", - "folders": [], - "requests": [ - { - "v": "3", - "endpoint": "<>", - "name": "test1", - "params": [], - "headers": [], - "method": "POST", - "auth": { "authType": "none", "authActive": true }, - "preRequestScript": "", - "testScript": "const HOST = pw.env.get(\"HOST\");\nconst UNSET_ENV = pw.env.get(\"UNSET_ENV\");\nconst EXPECTED_URL = \"https://echo.hoppscotch.io\";\nconst URL = pw.env.get(\"URL\");\nconst BODY_VALUE = pw.env.get(\"BODY_VALUE\");\n\n// Check JSON response property\npw.test(\"Check headers properties.\", ()=> {\n pw.expect(pw.response.body.headers.host).toBe(HOST);\n});\n\npw.test(\"Check data properties.\", () => {\n\tconst DATA = pw.response.body.data;\n \n pw.expect(DATA).toBeType(\"string\");\n pw.expect(JSON.parse(DATA).body_key).toBe(BODY_VALUE);\n});\n\npw.test(\"Check request URL.\", () => {\n pw.expect(URL).toBe(EXPECTED_URL);\n})\n\npw.test(\"Check unset ENV.\", () => {\n pw.expect(UNSET_ENV).toBeType(\"undefined\");\n})", - "body": { - "contentType": "application/json", - "body": "{\n \"<>\":\"<>\"\n}" - }, - "requestVariables": [] - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/fails-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/fails-coll.json deleted file mode 100644 index b8172049..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/fails-coll.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "v": 1, - "name": "tests", - "folders": [], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io/<>", - "name": "", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "none", - "authActive": true - }, - "preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");", - "testScript": "// Check status code is 200\npwd.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"string\");\n});", - "body": { - "contentType": "application/json", - "body": "{\n\"test\": \"<>\"\n}" - }, - "requestVariables": [] - }, - { - "v": "3", - "endpoint": "https://echo.hoppscotch.dio/<>", - "name": "success", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "none", - "authActive": true - }, - "preRequestScript": "pw.env.setd(\"HEADERS_TYPE2\", \"devblin_local2\");", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(300);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});", - "body": { - "contentType": "application/json", - "body": "{\n\"test\": \"<>\"\n}" - }, - "requestVariables": [] - } - ] - } -] diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/hawk-auth-success-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/hawk-auth-success-coll.json deleted file mode 100644 index fbf755fb..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/hawk-auth-success-coll.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "v": 3, - "name": "HAWK Auth (success state) - collection", - "folders": [], - "requests": [ - { - "v": "12", - "id": "cm0dm70cw000687bnxi830zz2", - "auth": { - "authType": "hawk", - "authActive": true, - "authId": "<>", - "authKey": "<>", - "algorithm": "<>", - "includePayloadHash": false, - "user": "<>", - "nonce": "<>", - "ext": "<>", - "app": "<>", - "dlg": "<>", - "timestamp": "<>" - }, - "body": { - "body": null, - "contentType": null - }, - "name": "hawk-auth-headers", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "<>", - "testScript": "pw.test(\"Status code is 200\", ()=> { pw.expect(pw.response.status).toBe(200);});", - "preRequestScript": "", - "responses": {}, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/invalid-mixed-versions-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/invalid-mixed-versions-coll.json deleted file mode 100644 index 6b53a4f0..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/invalid-mixed-versions-coll.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "v": 5, - "id": "cmbgcmyly10yhdjet63hiorps", - "name": "Invalid mixed versions collection", - "folders": [ - { - "v": 8, - "id": "cmbgnb4h100v613phgrz6vku9", - "name": "fold1", - "folders": [], - "requests": [ - { - "v": "13", - "name": "req", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "_ref_id": "coll_mbgnb8zy_eab190e2-6770-428c-8645-f49e88a3fe90" - } - ], - "requests": [], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "_ref_id": "coll_mbgnb8zy_7c3f6eca-bd94-44a5-90e3-3f7c2126d63e" -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/iteration-data-tests-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/iteration-data-tests-coll.json deleted file mode 100644 index d70aa845..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/iteration-data-tests-coll.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "v": 1, - "name": "iteration-data-tests-coll", - "folders": [], - "requests": [ - { - "v": "3", - "endpoint": "<>", - "name": "test1", - "params": [], - "headers": [], - "method": "POST", - "auth": { "authType": "none", "authActive": true }, - "preRequestScript": "", - "testScript": "// Iteration data is prioritised over environment variables \n const { data, headers } = pw.response.body;\n pw.expect(headers['host']).toBe('echo.hoppscotch.io')\n // Falls back to environment variables for missing entries in data export\n pw.expect(data).toInclude('overriden-body-key-at-environment')\n pw.expect(data).toInclude('body_value')", - "body": { - "contentType": "application/json", - "body": "{\n \"<>\":\"<>\"\n}" - }, - "requestVariables": [] - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jsonc-body-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jsonc-body-coll.json deleted file mode 100644 index 247e3672..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jsonc-body-coll.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "v": 11, - "name": "JSONC Body Test Collection", - "folders": [], - "requests": [ - { - "v": "17", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "{\n \"key1\": \"value1\", // inline comment\n \"key2\": \"value2\" // another comment\n}", - "contentType": "application/json" - }, - "name": "Echo with inline comments", - "method": "POST", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "hopp.test('Should successfully parse JSONC with comments', () => {\n hopp.expect(hopp.response.statusCode).toBe(200);\n const data = JSON.parse(hopp.response.body.asJSON().data);\n hopp.expect(data.key1).toBe('value1');\n hopp.expect(data.key2).toBe('value2');\n});", - "preRequestScript": "", - "requestVariables": [], - "responses": {} - }, - { - "v": "17", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "{\n /* Multi-line comment\n should also work */\n \"message\": \"test\",\n \"nested\": {\n \"field\": \"value\" // another comment\n }\n}", - "contentType": "application/json" - }, - "name": "Echo with multiline comments", - "method": "POST", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "hopp.test('Should successfully parse JSONC with multiline comments', () => {\n hopp.expect(hopp.response.statusCode).toBe(200);\n const data = JSON.parse(hopp.response.body.asJSON().data);\n hopp.expect(data.message).toBe('test');\n hopp.expect(data.nested.field).toBe('value');\n});", - "preRequestScript": "", - "requestVariables": [], - "responses": {} - }, - { - "v": "17", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "{\n \"key\": \"value\",\n \"count\": 42,\n}", - "contentType": "application/json" - }, - "name": "Echo with trailing commas", - "method": "POST", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "hopp.test('Should successfully parse JSONC with trailing commas', () => {\n hopp.expect(hopp.response.statusCode).toBe(200);\n const data = JSON.parse(hopp.response.body.asJSON().data);\n hopp.expect(data.key).toBe('value');\n hopp.expect(data.count).toBe(42);\n});", - "preRequestScript": "", - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "variables": [], - "description": "" -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jwt-auth-headers-success-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jwt-auth-headers-success-coll.json deleted file mode 100644 index 38d15711..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jwt-auth-headers-success-coll.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "v": 3, - "name": "JWT Auth (headers) - collection", - "folders": [], - "requests": [ - { - "v": "13", - "id": "cm0dm70cw000687bnxi830zz3", - "auth": { - "authType": "jwt", - "authActive": true, - "addTo": "HEADERS", - "algorithm": "<>", - "secret": "<>", - "privateKey": "<>", - "payload": "<>", - "jwtHeaders": "<>", - "headerPrefix": "<>", - "isSecretBase64Encoded": false - }, - "body": { - "body": null, - "contentType": null - }, - "name": "jwt-auth-headers", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "<>", - "testScript": "pw.test(\"Status code is 200\", ()=> { pw.expect(pw.response.status).toBe(200);});", - "preRequestScript": "", - "responses": {}, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jwt-auth-params-success-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jwt-auth-params-success-coll.json deleted file mode 100644 index 25a9a3c1..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/jwt-auth-params-success-coll.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "v": 3, - "name": "JWT Auth (params) - collection", - "folders": [], - "requests": [ - { - "v": "13", - "id": "cm0dm70cw000687bnxi830zz4", - "auth": { - "authType": "jwt", - "authActive": true, - "addTo": "QUERY_PARAMS", - "algorithm": "<>", - "secret": "<>", - "privateKey": "<>", - "payload": "<>", - "jwtHeaders": "<>", - "paramName": "<>", - "isSecretBase64Encoded": false - }, - "body": { - "body": null, - "contentType": null - }, - "name": "jwt-auth-params", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "<>", - "testScript": "pw.test(\"Status code is 200\", ()=> { pw.expect(pw.response.status).toBe(200);});", - "preRequestScript": "", - "responses": {}, - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/malformed-coll-2.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/malformed-coll-2.json deleted file mode 100644 index 8df994d7..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/malformed-coll-2.json +++ /dev/null @@ -1,7 +0,0 @@ -[ - { - "v": 1, - "name": "tests", - "folders": [] - } -] diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/malformed-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/malformed-coll.json deleted file mode 100644 index a4c46721..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/malformed-coll.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "v": 1, - "folders": [], - "requests": - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io/<>", - "name": "fail", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "none", - "authActive": true - }, - "preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"string\");\n});", - "body": { - "contentType": "application/json", - "body": "{\n\"test\": \"<>\"\n}" - }, - "requestVariables": [], - }, - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io/<>", - "name": "success", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "none", - "authActive": true - }, - "preRequestScript": "pw.env.set(\"HEADERS_TYPE2\", \"devblin_local2\");", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(300);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});", - "body": { - "contentType": "application/json", - "body": "{\n\"test\": \"<>\"\n}" - }, - "requestVariables": [] - } - ] - } -] diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/multipart-form-data-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/multipart-form-data-coll.json deleted file mode 100644 index 37d419dc..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/multipart-form-data-coll.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "v": 3, - "name": "Multipart form data content type - Collection", - "folders": [], - "requests": [ - { - "v": "7", - "endpoint": "https://echo.hoppscotch.io", - "name": "multipart-form-data-sample-req", - "params": [], - "headers": [], - "method": "POST", - "auth": { - "authType": "none", - "authActive": true, - "addTo": "HEADERS", - "grantTypeInfo": { - "authEndpoint": "test-authorization-endpoint", - "tokenEndpoint": "test-token-endpont", - "clientID": "test-client-id", - "clientSecret": "test-client-secret", - "isPKCE": true, - "codeVerifierMethod": "S256", - "grantType": "AUTHORIZATION_CODE", - "token": "test-token" - } - }, - "preRequestScript": "", - "testScript": "pw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully derives the relevant headers based on the content type\", () => {\n pw.expect(pw.response.body.headers['content-type']).toInclude(\"multipart/form-data\");\n});\n\npw.test(\"Successfully sends the form data in the request body\", () => {\n // Dynamic value\n pw.expect(pw.response.body.data).toBeType(\"string\");\n});", - "body": { - "contentType": "multipart/form-data", - "body": [ - { - "key": "key1", - "value": "value1", - "active": true, - "isFile": false - }, - { - "key": "key2", - "value": [{}], - "active": true, - "isFile": true - } - ] - }, - "requestVariables": [] - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/multiple-child-collections-auth-headers-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/multiple-child-collections-auth-headers-coll.json deleted file mode 100644 index f56863a4..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/multiple-child-collections-auth-headers-coll.json +++ /dev/null @@ -1,700 +0,0 @@ -{ - "v": 6, - "id": "cm9wmuzj46s3imbs891pdamv4", - "name": "Multiple child collections with authorization, headers and variables set at each level", - "folders": [ - { - "v": 6, - "id": "cm9wmuzjp6s3lmbs878f67qr9", - "name": "folder-1", - "folders": [ - { - "v": 6, - "id": "cm9wmuzln6s3umbs8j8lasa3u", - "name": "folder-11", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-11-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\")\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-1\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [ - { - "key": "key", - "value": "Set at folder-11", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_c1131ca7-4f49-4c25-b524-c00b0c94a9d5" - }, - { - "v": 6, - "id": "cm9wmuzm66s3xmbs8lzb76mkm", - "name": "folder-12", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-12-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-12-request", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Overriden at folder-12-request", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits/overrides authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-12-request\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"Overriden at folder-12-request\")\n})", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-12", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Set at folder-12", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_2bcc342f-8817-4450-8d1e-4786cfad0d83" - }, - { - "v": 6, - "id": "cm9wmuzmp6s40mbs8lspc4162", - "name": "folder-13", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-13-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Custom-Header-Request-Level", - "value": "New custom header added at the folder-13-request level", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Overriden at folder-13-request", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits/overrides authorization/header set at the parent collection level with new header addition\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\")\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-13\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"Overriden at folder-13-request\")\n pw.expect(pw.response.body.headers[\"custom-header-request-level\"]).toBe(\"New custom header added at the folder-13-request level\")\n})", - "auth": { - "authType": "basic", - "username": "testuser", - "password": "testpass", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "bearer", - "token": "test-token", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-13", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Set at folder-13", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_cbab702b-28e6-4ec9-9b13-84f7b154fc1e" - } - ], - "requests": [ - { - "v": "11", - "name": "folder-1-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\")\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-1\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-1", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_d82c9136-95cd-4b72-b49d-f6980c153a9b" - }, - { - "v": 6, - "id": "cm9wmuzk96s3ombs80h6zpd5d", - "name": "folder-2", - "folders": [ - { - "v": 6, - "id": "cm9wmuzn96s43mbs8ty5ruesu", - "name": "folder-21", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-21-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-2\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [ - { - "key": "key", - "value": "Set at folder-21", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_a1ae4845-9eab-4963-9ba3-51f8887b8fdd" - }, - { - "v": 6, - "id": "cm9wmuznr6s46mbs8j6598bvx", - "name": "folder-22", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-22-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-22-request", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Overriden at folder-22-request", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits/overrides authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-22-request\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"Overriden at folder-22-request\")\n})", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-22", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Set at folder-22", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_2215866f-b5d2-4a18-853a-c40ac9238729" - }, - { - "v": 6, - "id": "cm9wmuzo96s49mbs8ripqlpct", - "name": "folder-23", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-23-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Custom-Header-Request-Level", - "value": "New custom header added at the folder-23-request level", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Overriden at folder-23-request", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits/overrides authorization/header set at the parent collection level with new header addition\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\")\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-23\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"Overriden at folder-23-request\")\n pw.expect(pw.response.body.headers[\"custom-header-request-level\"]).toBe(\"New custom header added at the folder-23-request level\")\n})", - "auth": { - "authType": "basic", - "username": "testuser", - "password": "testpass", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "bearer", - "token": "test-token", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-23", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Set at folder-23", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_11b0fc1e-0ecc-45d2-a7e6-5e3600f2972f" - } - ], - "requests": [ - { - "v": "11", - "name": "folder-2-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-2-request", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits/overrides authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-2-request\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n})", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-2", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_02b9a042-e935-4d0e-a30e-720b13ebf77b" - }, - { - "v": 6, - "id": "cm9wmuzl26s3rmbs8mdewgock", - "name": "folder-3", - "folders": [ - { - "v": 6, - "id": "cm9wmuzor6s4cmbs833gdoh57", - "name": "folder-31", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-31-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\")\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-3\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [ - { - "key": "key", - "value": "Set at folder-31", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_875254bc-5d26-4235-acfa-e8e93638f828" - }, - { - "v": 6, - "id": "cm9wmuzp96s4fmbs8aj730ukh", - "name": "folder-32", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-32-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-32-request", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Overriden at folder-32-request", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits/overrides authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-32-request\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"Overriden at folder-32-request\")\n})", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-32", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Set at folder-32", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_da0095e7-8a92-4187-ac56-d62ac9ea0ba8" - }, - { - "v": 6, - "id": "cm9wmuzpr6s4imbs8a2ludk99", - "name": "folder-33", - "folders": [], - "requests": [ - { - "v": "11", - "name": "folder-33-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Custom-Header-Request-Level", - "value": "New custom header added at the folder-33-request level", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Overriden at folder-33-request", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits/overrides authorization/header set at the parent collection level with new header addition\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\")\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-33\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"Overriden at folder-33-request\")\n pw.expect(pw.response.body.headers[\"custom-header-request-level\"]).toBe(\"New custom header added at the folder-33-request level\")\n})", - "auth": { - "authType": "basic", - "username": "testuser", - "password": "testpass", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "bearer", - "token": "test-token", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-33", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Set at folder-33", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_992c8305-c7dc-4ec3-a940-3f1fd1ea5d36" - } - ], - "requests": [ - { - "v": "11", - "name": "folder-3-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Custom-Header-Request-Level", - "value": "New custom header added at the folder-3-request level", - "active": true, - "description": "" - }, - { - "key": "key", - "value": "Set at folder-3-request", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits/overrides authorization/header set at the parent collection level with new header addition\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\")\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value overriden at folder-3\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n pw.expect(pw.response.body.headers[\"key\"]).toBe(\"Set at folder-3-request\")\n pw.expect(pw.response.body.headers[\"custom-header-request-level\"]).toBe(\"New custom header added at the folder-3-request level\")\n})", - "auth": { - "authType": "basic", - "username": "testuser", - "password": "testpass", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "basic", - "username": "testuser", - "password": "testpass", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value overriden at folder-3", - "active": true, - "description": "" - } - ], - "_ref_id": "coll_m9wn4jl9_c3efcd2a-36d9-48d0-824e-ef5a8bdddab9" - } - ], - "requests": [ - { - "v": "11", - "name": "root-collection-request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully inherits authorization/header set at the parent collection level\", () => {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBe(\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\")\n \n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"Custom header value set at the root collection\")\n pw.expect(pw.response.body.headers[\"inherited-header\"]).toBe(\"Inherited header at all levels\")\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "basic", - "username": "testuser", - "password": "testpass", - "authActive": true - }, - "headers": [ - { - "key": "Custom-Header", - "value": "Custom header value set at the root collection", - "active": true, - "description": "" - }, - { - "key": "Inherited-Header", - "value": "Inherited header at all levels", - "active": true, - "description": "" - } - ], - "variables": [ - { - "key": "collection-variable", - "currentValue": "collection-variable-value", - "initialValue": "collection-variable-value", - "secret": false - } - ], - "_ref_id": "coll_m9wn4jl9_aa8a3bc2-a96f-4cac-86f3-2df4bb355cc8" -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/notjson-coll.txt b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/notjson-coll.txt deleted file mode 100644 index bd979971..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/notjson-coll.txt +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "v": 1, - "folders": [], - "requests": - { - "v": "2", - "endpoint": "https://echo.hoppscotch.io/<>", - "name": "fail", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "none", - "authActive": true, - "addTo": "Headers", - "key": "", - "value": "" - }, - "preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"string\");\n});", - "body": { - "contentType": "application/json", - "body": "{\n\"test\": \"<>\"\n}" - }, - "requestVariables": [] - } - ] - } -] diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/oauth2-auth-code-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/oauth2-auth-code-coll.json deleted file mode 100644 index 12c91fbd..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/oauth2-auth-code-coll.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "v": 3, - "name": "OAuth2 Authorization Code Grant Type - Collection", - "folders": [], - "requests": [ - { - "v": "7", - "endpoint": "https://echo.hoppscotch.io", - "name": "oauth2-auth-code-sample-req-pass-by-headers", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "oauth-2", - "authActive": true, - "addTo": "HEADERS", - "grantTypeInfo": { - "authEndpoint": "test-authorization-endpoint", - "tokenEndpoint": "test-token-endpont", - "clientID": "test-client-id", - "clientSecret": "test-client-secret", - "isPKCE": true, - "codeVerifierMethod": "S256", - "grantType": "AUTHORIZATION_CODE", - "token": "test-token" - } - }, - "preRequestScript": "", - "testScript": "pw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully derives Authorization header from the supplied fields\", ()=> {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBeType(\"string\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [] - }, - { - "v": "7", - "endpoint": "https://echo.hoppscotch.io", - "name": "oauth2-auth-code-sample-req-pass-by-query-params", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "oauth-2", - "authActive": true, - "addTo": "HEADERS", - "grantTypeInfo": { - "authEndpoint": "test-authorization-endpoint", - "tokenEndpoint": "test-token-endpont", - "clientID": "test-client-id", - "clientSecret": "test-client-secret", - "isPKCE": true, - "codeVerifierMethod": "S256", - "grantType": "AUTHORIZATION_CODE", - "token": "test-token" - } - }, - "preRequestScript": "", - "testScript": "pw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully derives Authorization header from the supplied fields\", ()=> {\n pw.expect(pw.response.body.headers[\"authorization\"]).toBeType(\"string\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [] - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/passes-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/passes-coll.json deleted file mode 100644 index e958164a..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/passes-coll.json +++ /dev/null @@ -1,47 +0,0 @@ -[ - { - "v": 1, - "name": "tests", - "folders": [], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io/<>", - "name": "", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "none", - "authActive": true - }, - "preRequestScript": "pw.env.set(\"HEADERS_TYPE1\", \"devblin_local1\");", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});", - "body": { - "contentType": "application/json", - "body": "{\n\"test\": \"<>\"\n}" - }, - "requestVariables": [] - }, - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io/<>", - "name": "success", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "none", - "authActive": true - }, - "preRequestScript": "pw.env.set(\"HEADERS_TYPE2\", \"devblin_local2\");", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});", - "body": { - "contentType": "application/json", - "body": "{\n\"test\": \"<>\"\n}" - }, - "requestVariables": [] - } - ] - } -] diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/pre-req-script-env-var-persistence-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/pre-req-script-env-var-persistence-coll.json deleted file mode 100644 index 0d625b81..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/pre-req-script-env-var-persistence-coll.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "v": 2, - "name": "pre-req-script-env-var-persistence-coll", - "folders": [], - "requests": [ - { - "v": "3", - "auth": { "authType": "none", "authActive": true }, - "body": { "body": null, "contentType": null }, - "name": "sample-req", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "pw.expect(pw.env.get(\"variable\")).toBe(\"value\")", - "preRequestScript": "pw.env.set(\"variable\", \"value\");", - "requestVariables": [] - } - ], - "auth": { "authType": "inherit", "authActive": true }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/req-body-env-vars-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/req-body-env-vars-coll.json deleted file mode 100644 index 0ddf3ef3..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/req-body-env-vars-coll.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "v": 2, - "name": "Test environment variables in request body", - "folders": [], - "requests": [ - { - "v": "3", - "name": "test-request", - "endpoint": "https://echo.hoppscotch.io", - "method": "POST", - "headers": [], - "params": [], - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"firstName\": \"<>\",\n \"lastName\": \"<>\",\n \"greetText\": \"<>, <>\",\n \"fullName\": \"<>\",\n \"id\": \"<>\"\n}" - }, - "preRequestScript": "", - "testScript": "pw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test(\"Successfully resolves environments recursively\", ()=> {\n pw.expect(pw.env.getResolve(\"recursiveVarX\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"recursiveVarY\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"salutation\")).toBe(\"Hello\")\n});\n\npw.test(\"Successfully resolves environments referenced in the request body\", () => {\n const expectedId = \"7\"\n const expectedFirstName = \"John\"\n const expectedLastName = \"Doe\"\n const expectedFullName = `${expectedFirstName} ${expectedLastName}`\n const expectedGreetText = `Hello, ${expectedFullName}`\n\n pw.expect(pw.env.getResolve(\"recursiveVarX\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"recursiveVarY\")).toBe(\"Hello\")\n pw.expect(pw.env.getResolve(\"salutation\")).toBe(\"Hello\")\n\n const { id, firstName, lastName, fullName, greetText } = JSON.parse(pw.response.body.data)\n\n pw.expect(id).toBe(expectedId)\n pw.expect(expectedFirstName).toBe(firstName)\n pw.expect(expectedLastName).toBe(lastName)\n pw.expect(fullName).toBe(expectedFullName)\n pw.expect(greetText).toBe(expectedGreetText)\n});", - "requestVariables": [] - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/request-vars-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/request-vars-coll.json deleted file mode 100644 index 7eff0a5a..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/request-vars-coll.json +++ /dev/null @@ -1,188 +0,0 @@ -{ - "v": 2, - "name": "Request variables", - "folders": [], - "requests": [ - { - "v": "6", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "{\n \"<>\": \"<>\"\n}", - "contentType": "application/json" - }, - "name": "request-variables-basic-usage", - "method": "POST", - "params": [ - { - "key": "<>", - "value": "<>", - "active": true - }, - { - "key": "inactive-query-param-key", - "value": "<>", - "active": true - } - ], - "headers": [ - { - "key": "<>", - "value": "<>", - "active": true - }, - { - "key": "inactive-header-key", - "value": "<>", - "active": true - } - ], - "endpoint": "<>", - "testScript": "pw.test(\"Accounts for active request variables\", ()=> {\n pw.expect(pw.response.body.args[\"query-param-key\"]).toBe(\"query-param-value\");\n\n const data = JSON.parse(pw.response.body.data)\n\n pw.expect(data[\"http-body-raw-key\"]).toBe(\"http-body-raw-value\")\n\n pw.expect(pw.response.body.headers[\"custom-header-key\"]).toBe(\"custom-header-value\");\n});\n\npw.test(\"Ignores inactive request variables\", () => {\n pw.expect(pw.response.body.args[\"inactive-query-param-key\"]).toBe(\"\")\n pw.expect(pw.response.body.args[\"inactive-header-key\"]).toBe(undefined)\n})", - "preRequestScript": "", - "requestVariables": [ - { - "key": "url", - "value": "https://echo.hoppscotch.io", - "active": true - }, - { - "key": "method", - "value": "POST", - "active": true - }, - { - "key": "httpBodyRawKey", - "value": "http-body-raw-key", - "active": true - }, - { - "key": "httpBodyRawValue", - "value": "http-body-raw-value", - "active": true - }, - { - "key": "customHeaderKey", - "value": "custom-header-key", - "active": true - }, - { - "key": "customHeaderValue", - "value": "custom-header-value", - "active": true - }, - { - "key": "queryParamKey", - "value": "query-param-key", - "active": true - }, - { - "key": "queryParamValue", - "value": "query-param-value", - "active": true - }, - { - "key": "inactiveQueryParamValue", - "value": "inactive-query-param-value", - "active": false - }, - { - "key": "inactiveHeaderValue", - "value": "inactive-header-value", - "active": false - } - ] - }, - { - "v": "6", - "auth": { - "authType": "none", - "password": "<>", - "username": "<>", - "authActive": true - }, - "body": { - "body": "{\n \"username\": \"<>\",\n \"password\": \"<>\"\n}", - "contentType": "application/json" - }, - "name": "request-variables-alongside-environment-variables", - "method": "POST", - "params": [ - { - "key": "method", - "value": "<>", - "active": true - } - ], - "headers": [ - { - "key": "test-header-key", - "value": "<>", - "active": true - } - ], - "endpoint": "<>/<>", - "testScript": "pw.test(\"The first occurrence is picked for multiple request variable occurrences with the same key.\", () => {\n pw.expect(pw.response.body.args.method).toBe(\"post\");\n});\n\npw.test(\"Request variables support recursive resolution and pick values from secret environment variables\", () => {\n const { username, password } = JSON.parse(pw.response.body.data)\n\n pw.expect(username).toBe(\"username\")\n pw.expect(password).toBe(\"password\")\n\n})\n\npw.test(\"Resolves request variables that are clubbed together\", () => {\n pw.expect(pw.response.body.path).toBe(\"/username/password\")\n})\n\npw.test(\"Request variables are prioritised over environment variables\", () => {\n pw.expect(pw.response.body.headers.host).toBe(\"echo.hoppscotch.io\")\n})\n\npw.test(\"Environment variable is picked if the request variable under the same name is empty\", () => {\n pw.expect(pw.response.body.headers[\"test-header-key\"]).toBe(\"test-header-value\")\n})", - "preRequestScript": "", - "requestVariables": [ - { - "key": "url", - "value": "https://echo.hoppscotch.io", - "active": true - }, - { - "key": "username", - "value": "<>", - "active": true - }, - { - "key": "recursiveBasicAuthUsernameReqVar", - "value": "<>", - "active": true - }, - { - "key": "password", - "value": "<>", - "active": true - }, - { - "key": "recursiveBasicAuthPasswordReqVar", - "value": "<>", - "active": true - }, - { - "key": "method", - "value": "post", - "active": true - }, - { - "key": "method", - "value": "get", - "active": true - }, - { - "key": "method", - "value": "put", - "active": true - }, - { - "key": "path", - "value": "<>/<>", - "active": true - }, - { - "key": "testHeaderValue", - "value": "", - "active": true - } - ] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/sample-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/sample-coll.json deleted file mode 100644 index b0ca8cec..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/sample-coll.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "v": 1, - "name": "tests", - "folders": [], - "requests": [ - { - "v": "2", - "endpoint": "<>", - "name": "", - "params": [], - "headers": [], - "method": "GET", - "auth": { - "authType": "none", - "authActive": true - }, - "preRequestScript": "", - "testScript": "// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Check JSON response property\", ()=> {\n pw.expect(pw.response.body.method).toBe(\"GET\");\n pw.expect(pw.response.body.headers).toBeType(\"object\");\n});", - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [] - } - ] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/scripting-revamp-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/scripting-revamp-coll.json deleted file mode 100644 index f236cd7a..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/scripting-revamp-coll.json +++ /dev/null @@ -1,1686 +0,0 @@ -{ - "v": 11, - "name": "scripting-revamp-coll", - "folders": [], - "requests": [ - { - "v": "17", - "id": "cmfhzf0oo0092qt0if5rvd2g4", - "name": "json-response-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Test-Header", - "value": "test", - "active": true, - "description": "test header" - } - ], - "preRequestScript": "", - "testScript": "export {};\nhopp.test(\"`hopp.response.body.asJSON()` parses response body as JSON\", () => {\n const parsedData = JSON.parse(hopp.response.body.asJSON().data)\n\n hopp.expect(parsedData.name).toBe('John Doe')\n hopp.expect(parsedData.age).toBeType(\"number\")\n})\n\npm.test(\"`pm.response.json()` parses response body as JSON\", () => {\n const parsedData = JSON.parse(pm.response.json().data)\n\n pm.expect(parsedData.name).toBe('John Doe')\n pm.expect(parsedData.age).toBeType(\"number\")\n})\n\nhopp.test(\"`hopp.response.body.asText()` parses response body as plain text\", () => {\n const textResponse = hopp.response.body.asText()\n hopp.expect(textResponse).toInclude('\\\"test-header\\\":\\\"test\\\"')\n})\n\npm.test(\"`pm.response.text()` parses response body as plain text\", () => {\n const textResponse = pm.response.text()\n pm.expect(textResponse).toInclude('\\\"test-header\\\":\\\"test\\\"')\n})\n\nhopp.test(\"hopp.response.bytes()` parses response body as raw bytes\", () => {\n const rawResponse = hopp.response.body.bytes()\n\n hopp.expect(rawResponse[0]).toBe(123)\n})\n\npm.test(\"pm.response.stream` parses response body as raw bytes\", () => {\n const rawResponse = pm.response.stream\n\n pm.expect(rawResponse[0]).toBe(123)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"name\": \"John Doe\",\n \"age\": 35\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op0093qt0ictgoxymy", - "name": "html-response-test", - "method": "GET", - "endpoint": "https://hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Test-Header", - "value": "test", - "active": true, - "description": "Test header" - } - ], - "preRequestScript": "", - "testScript": "hopp.test(\"`hopp.response.asText()` parses response body as plain text\", () => {\n const textResponse = hopp.response.body.asText()\n hopp.expect(textResponse).toInclude(\"Open source API development ecosystem\")\n})\n\npm.test(\"`pm.response.text()` parses response body as plain text\", () => {\n const textResponse = pm.response.text()\n pm.expect(textResponse).toInclude(\"Open source API development ecosystem\")\n})\n\nhopp.test(\"`hopp.response.body.bytes()` parses response body as raw bytes\", () => {\n const rawResponse = hopp.response.body.bytes()\n\n hopp.expect(rawResponse[0]).toBe(60)\n})\n\npm.test(\"`pm.response.stream` parses response body as raw bytes\", () => {\n const rawResponse = pm.response.stream\n\n pm.expect(rawResponse[0]).toBe(60)\n})\n\n\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op0094qt0ixbo9rqnw", - "name": "environment-variables-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "export {};\nhopp.env.set('test_key', 'test_value')\nhopp.env.set('recursive_key', '<>')\nhopp.env.global.set('global_key', 'global_value')\nhopp.env.active.set('active_key', 'active_value')\n\n// `pm` namespace equivalents\npm.variables.set('pm_test_key', 'pm_test_value')\npm.environment.set('pm_active_key', 'pm_active_value')\npm.globals.set('pm_global_key', 'pm_global_value')\n", - "testScript": "\nhopp.test('`hopp.env.get()` retrieves environment variables', () => {\n const value = hopp.env.get('test_key')\n hopp.expect(value).toBe('test_value')\n})\n\npm.test('`pm.variables.get()` retrieves environment variables', () => {\n const value = pm.variables.get('test_key')\n pm.expect(value).toBe('test_value')\n})\n\nhopp.test('`hopp.env.getRaw()` retrieves raw environment variables without resolution', () => {\n const rawValue = hopp.env.getRaw('recursive_key')\n hopp.expect(rawValue).toBe('<>')\n})\n\nhopp.test('`hopp.env.get()` resolves recursive environment variables', () => {\n const resolvedValue = hopp.env.get('recursive_key')\n hopp.expect(resolvedValue).toBe('test_value')\n})\n\npm.test('`pm.variables.replaceIn()` resolves template variables', () => {\n const resolved = pm.variables.replaceIn('Value is {{test_key}}')\n pm.expect(resolved).toBe('Value is test_value')\n})\n\nhopp.test('`hopp.env.global.get()` retrieves global environment variables', () => {\n const globalValue = hopp.env.global.get('global_key')\n\n // `hopp.env.global` would be empty for the CLI\n if (globalValue) {\n hopp.expect(globalValue).toBe('global_value')\n }\n})\n\npm.test('`pm.globals.get()` retrieves global environment variables', () => {\n const globalValue = pm.globals.get('global_key')\n\n // `pm.globals` would be empty for the CLI\n if (globalValue) {\n pm.expect(globalValue).toBe('global_value')\n }\n})\n\nhopp.test('`hopp.env.active.get()` retrieves active environment variables', () => {\n const activeValue = hopp.env.active.get('active_key')\n hopp.expect(activeValue).toBe('active_value')\n})\n\npm.test('`pm.environment.get()` retrieves active environment variables', () => {\n const activeValue = pm.environment.get('active_key')\n pm.expect(activeValue).toBe('active_value')\n})\n\nhopp.test('Environment methods return null for non-existent keys', () => {\n hopp.expect(hopp.env.get('non_existent')).toBe(null)\n hopp.expect(hopp.env.getRaw('non_existent')).toBe(null)\n hopp.expect(hopp.env.global.get('non_existent')).toBe(null)\n hopp.expect(hopp.env.active.get('non_existent')).toBe(null)\n})\n\npm.test('`pm` environment methods handle non-existent keys correctly', () => {\n pm.expect(pm.variables.get('non_existent')).toBe(undefined)\n pm.expect(pm.environment.get('non_existent')).toBe(undefined)\n pm.expect(pm.globals.get('non_existent')).toBe(undefined)\n pm.expect(pm.variables.has('non_existent')).toBe(false)\n pm.expect(pm.environment.has('non_existent')).toBe(false)\n pm.expect(pm.globals.has('non_existent')).toBe(false)\n})\n\npm.test('`pm` variables set in pre-request script are accessible', () => {\n pm.expect(pm.variables.get('pm_test_key')).toBe('pm_test_value')\n pm.expect(pm.environment.get('pm_active_key')).toBe('pm_active_value')\n\n const pmGlobalValue = hopp.env.global.get('pm_global_key')\n\n // `hopp.env.global` would be empty for the CLI\n if (pmGlobalValue) {\n hopp.expect(pmGlobalValue).toBe('pm_global_value')\n }\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op0095qt0ieogkxx1w", - "name": "request-modification-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [ - { - "key": "original_param", - "value": "original-param", - "active": true, - "description": "" - } - ], - "headers": [ - { - "key": "Original-Header", - "value": "original_value", - "active": true, - "description": "" - } - ], - "preRequestScript": "hopp.request.setUrl('https://echo.hoppscotch.io/modified')\nhopp.request.setMethod('POST')\nhopp.request.setHeader('Modified-Header', 'modified_value')\nhopp.request.setParam('new_param', 'new_value')\n\nhopp.request.setBody({\n contentType: 'application/json',\n body: JSON.stringify({ modified: true, timestamp: Date.now() })\n})\n\nhopp.request.setAuth({\n authType: 'bearer',\n token: 'test-bearer-token',\n authActive: true\n})", - "testScript": "\nhopp.test('Request URL was modified by pre-request script', () => {\n hopp.expect(hopp.request.url).toInclude('/modified')\n pm.expect(pm.request.url.toString()).toInclude('/modified')\n})\n\nhopp.test('Request method was modified by pre-request script', () => {\n hopp.expect(hopp.request.method).toBe('POST')\n pm.expect(pm.request.method).toBe('POST')\n})\n\nhopp.test('Request headers contain both original and modified headers', () => {\n const headers = hopp.request.headers\n const hasOriginal = headers.some(h => h.key === 'Original-Header')\n const hasModified = headers.some(h => h.key === 'Modified-Header')\n hopp.expect(hasOriginal).toBe(true)\n hopp.expect(hasModified).toBe(true)\n})\n\npm.test('PM request headers can be accessed and checked', () => {\n pm.expect(pm.request.headers.has('Original-Header')).toBe(true)\n pm.expect(pm.request.headers.has('Modified-Header')).toBe(true)\n pm.expect(pm.request.headers.get('Modified-Header')).toBe('modified_value')\n})\n\nhopp.test('Request parameters contain both original and new parameters', () => {\n const params = hopp.request.params\n const hasOriginal = params.some(p => p.key === 'original_param')\n const hasNew = params.some(p => p.key === 'new_param')\n hopp.expect(hasOriginal).toBe(true)\n hopp.expect(hasNew).toBe(true)\n})\n\nhopp.test('Request body was modified by pre-request script', () => {\n hopp.expect(hopp.request.body.contentType).toBe('application/json')\n pm.expect(pm.request.body.contentType).toBe('application/json')\n const bodyData = hopp.request.body\n\n if (typeof bodyData.body === \"string\") {\n hopp.expect(JSON.parse(bodyData.body).modified).toBe(true)\n pm.expect(JSON.parse(bodyData.body).modified).toBe(true)\n } else {\n throw new Error(`Unexpected body type: ${bodyData.body}`)\n }\n})\n\n\nhopp.test('Request auth was modified by pre-request script', () => {\n const auth = hopp.request.auth\n\n if (auth.authType === 'bearer') {\n hopp.expect(auth.token).toBe('test-bearer-token')\n pm.expect(auth.token).toBe('test-bearer-token')\n } else {\n throw new Error(`Unexpected auth type: ${auth.authType}`)\n }\n\n hopp.expect(auth.token).toBe('test-bearer-token')\n pm.expect(auth.token).toBe('test-bearer-token')\n})\n\n", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op0096qt0i6wellfus", - "name": "response-parsing-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Content-Type", - "value": "application/json", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "\nhopp.test('`hopp.response.statusCode` returns the response status code', () => {\n hopp.expect(hopp.response.statusCode).toBe(200)\n})\n\npm.test('`pm.response.code` returns the response status code', () => {\n pm.expect(pm.response.code).toBe(200)\n})\n\nhopp.test('`hopp.response.statusText` returns the response status text', () => {\n hopp.expect(hopp.response.statusText).toBeType('string')\n})\n\npm.test('`pm.response.status` returns the response status text', () => {\n pm.expect(pm.response.status).toBeType('string')\n})\n\nhopp.test('`hopp.response.headers` contains response headers', () => {\n const { headers } = hopp.response\n\n hopp.expect(headers).toBeType('object')\n hopp.expect(headers.length > 0).toBe(true)\n})\n\npm.test('`pm.response.headers` contains response headers', () => {\n const headersAll = pm.response.headers.all()\n pm.expect(headersAll).toBeType('object')\n pm.expect(Object.keys(headersAll).length > 0).toBe(true)\n})\n\nhopp.test('`hopp.response.responseTime` is a positive number', () => {\n hopp.expect(hopp.response.responseTime).toBeType('number')\n hopp.expect(hopp.response.responseTime > 0).toBe(true)\n})\n\npm.test('`pm.response.responseTime` is a positive number', () => {\n pm.expect(pm.response.responseTime).toBeType('number')\n pm.expect(pm.response.responseTime > 0).toBe(true)\n})\n\nhopp.test('`hopp.response.text()` returns response as text', () => {\n const responseText = hopp.response.body.asText()\n hopp.expect(responseText).toBeType('string')\n hopp.expect(responseText.length > 0).toBe(true)\n})\n\npm.test('`pm.response.text()` returns response as text', () => {\n const responseText = pm.response.text()\n pm.expect(responseText).toBeType('string')\n pm.expect(responseText.length > 0).toBe(true)\n})\n\nhopp.test('`hopp.response.json()` parses JSON response', () => {\n const responseJSON = hopp.response.body.asJSON()\n hopp.expect(responseJSON).toBeType('object')\n})\n\npm.test('`pm.response.json()` parses JSON response', () => {\n const responseJSON = pm.response.json()\n pm.expect(responseJSON).toBeType('object')\n})\n\n\nhopp.test('`hopp.response.bytes()` returns the raw response', () => {\n const responseBuffer = hopp.response.body.bytes()\n hopp.expect(responseBuffer).toBeType('object')\n hopp.expect(responseBuffer.constructor.name).toBe('Object')\n})\n\npm.test('`pm.response.stream` returns the raw response', () => {\n const responseBuffer = pm.response.stream\n pm.expect(responseBuffer).toBeType('object')\n pm.expect(responseBuffer.constructor.name).toBe('Object')\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"test\": \"response parsing\",\n \"timestamp\": \"{{$timestamp}}\",\n \"data\": {\n \"nested\": true,\n \"value\": 42\n }\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op0097qt0ia4wf0lej", - "name": "request-variables-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test request variables\nhopp.request.variables.set('dynamic_var', 'dynamic_value')\nhopp.request.variables.set('calculated_var', `timestamp_${Date.now()}`)", - "testScript": "\nhopp.test('`hopp.request.variables.get()` retrieves request variables', () => {\n const dynamicValue = hopp.request.variables.get('dynamic_var')\n hopp.expect(dynamicValue).toBe('dynamic_value')\n})\n\nhopp.test('Request variables can store calculated values', () => {\n const calculatedValue = hopp.request.variables.get('calculated_var')\n hopp.expect(calculatedValue).toInclude('timestamp_')\n})\n\nhopp.test('Request variables return null for non-existent keys', () => {\n const nonExistent = hopp.request.variables.get('non_existent_var')\n hopp.expect(nonExistent).toBe(null)\n})\n\nhopp.test('Pre-defined request variables are accessible', () => {\n const preDefinedVar = hopp.request.variables.get('req_var_1')\n hopp.expect(preDefinedVar).toBe('request_variable_value')\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [ - { - "key": "req_var_1", - "value": "request_variable_value", - "active": true - }, - { - "key": "dynamic_var", - "value": "dynamic_value", - "active": true - }, - { - "key": "calculated_var", - "value": "timestamp_1757751657020", - "active": true - } - ], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op0098qt0ii9fguj6e", - "name": "info-context-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\npm.test('`pm.info.eventName` indicates the script context', () => {\n pm.expect(pm.info.eventName).toBe('test')\n})\n\npm.test('`pm.info.requestName` returns the request name', () => {\n pm.expect(pm.info.requestName).toBe('info-context-test')\n})\n\npm.test('`pm.info.requestId` returns an optional request identifier', () => {\n const requestId = pm.info.requestId\n if (requestId) {\n pm.expect(requestId).toBeType('string')\n pm.expect(requestId?.length > 0).toBe(true)\n } else {\n pm.expect(requestId).toBe(undefined)\n }\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op0099qt0iamthw97r", - "name": "pm-namespace-additional-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test `pm` namespace specific features\npm.environment.set('pm_pre_key', 'pm_pre_value')\npm.globals.set('pm_global_pre', 'pm_global_pre_value')\npm.variables.set('pm_var_pre', 'pm_var_pre_value')\n", - "testScript": "\npm.test('`pm` namespace environment operations work correctly', () => {\n // Test environment has() method\n pm.expect(pm.environment.has('pm_pre_key')).toBe(true)\n pm.expect(pm.environment.has('non_existent_key')).toBe(false)\n \n // Test globals has() method\n const globalValue = pm.globals.has('pm_global_pre')\n // `pm.globals` would be empty for the CLI\n if (globalValue) {\n pm.expect(pm.globals.has('pm_global_pre')).toBe(true)\n }\n \n pm.expect(pm.globals.has('non_existent_global')).toBe(false)\n \n // Test variables has() method\n pm.expect(pm.variables.has('pm_var_pre')).toBe(true)\n pm.expect(pm.variables.has('non_existent_var')).toBe(false)\n})\n\npm.test('`pm` variables.replaceIn() handles template replacement', () => {\n const template = 'Hello {{pm_pre_key}}, global: {{pm_global_pre}}'\n const resolved = pm.variables.replaceIn(template)\n pm.expect(resolved).toInclude('pm_pre_value')\n pm.expect(resolved).toInclude('pm_global_pre_value')\n})\n\npm.test('`pm` request object provides URL as object with toString', () => {\n const url = pm.request.url\n pm.expect(url.toString()).toBeType('string')\n pm.expect(url.toString()).toInclude('echo.hoppscotch.io')\n})\n\npm.test('`pm` request headers object methods work correctly', () => {\n // Test headers.all() returns object\n const allHeaders = pm.request.headers.all()\n pm.expect(allHeaders).toBeType('object')\n \n // Test headers.has() and headers.get() methods\n if (Object.keys(allHeaders).length > 0) {\n const firstHeaderKey = Object.keys(allHeaders)[0]\n pm.expect(pm.request.headers.has(firstHeaderKey)).toBe(true)\n pm.expect(pm.request.headers.get(firstHeaderKey)).toBeType('string')\n }\n \n // Test non-existent header\n pm.expect(pm.request.headers.has('non-existent-header')).toBe(false)\n pm.expect(pm.request.headers.get('non-existent-header')).toBe(null)\n})\n\npm.test('`pm` response headers work correctly', () => {\n // Test response headers all() method\n const allResponseHeaders = pm.response.headers.all()\n pm.expect(allResponseHeaders).toBeType('object')\n \n // Test headers has() and get() for common headers\n if (Object.keys(allResponseHeaders).length > 0) {\n const firstKey = Object.keys(allResponseHeaders)[0]\n pm.expect(pm.response.headers.has(firstKey)).toBe(true)\n pm.expect(pm.response.headers.get(firstKey)).toBeType('string')\n }\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op009aqt0inw3j6dq9", - "name": "expectation-methods-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\nhopp.test('Basic equality expectations work correctly', () => {\n hopp.expect(1).toBe(1)\n hopp.expect('test').toBe('test')\n hopp.expect(true).toBe(true)\n hopp.expect(null).toBe(null)\n})\n\npm.test('`pm` basic equality expectations work correctly', () => {\n pm.expect(1).toBe(1)\n pm.expect('test').toBe('test')\n pm.expect(true).toBe(true)\n pm.expect(null).toBe(null)\n})\n\nhopp.test('Type checking expectations work correctly', () => {\n hopp.expect(42).toBeType('number')\n hopp.expect('hello').toBeType('string')\n hopp.expect(true).toBeType('boolean')\n hopp.expect({}).toBeType('object')\n hopp.expect([]).toBeType('object')\n})\n\npm.test('`pm` type checking expectations work correctly', () => {\n pm.expect(42).toBeType('number')\n pm.expect('hello').toBeType('string')\n pm.expect(true).toBeType('boolean')\n pm.expect({}).toBeType('object')\n pm.expect([]).toBeType('object')\n})\n\n\nhopp.test('String and array inclusion expectations work correctly', () => {\n hopp.expect('hello world').toInclude('world')\n hopp.expect([1, 2, 3]).toInclude(2)\n})\n\npm.test('`pm` string and array inclusion expectations work correctly', () => {\n pm.expect('hello world').toInclude('world')\n pm.expect([1, 2, 3]).toInclude(2)\n})\n\n\nhopp.test('Length expectations work correctly', () => {\n hopp.expect('hello').toHaveLength(5)\n hopp.expect([1, 2, 3]).toHaveLength(3)\n})\n\npm.test('`pm` length expectations work correctly', () => {\n pm.expect('hello').toHaveLength(5)\n pm.expect([1, 2, 3]).toHaveLength(3)\n})\n\nhopp.test('Response-based expectations work correctly', () => {\n const responseData = hopp.response.body.asJSON()\n hopp.expect(responseData).toBeType('object')\n hopp.expect(hopp.response.statusCode).toBe(200)\n})\n\npm.test('`pm` response-based expectations work correctly', () => {\n const responseData = pm.response.json()\n pm.expect(responseData).toBeType('object')\n pm.expect(pm.response.code).toBe(200)\n})", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"message\": \"Test expectation methods\",\n \"numbers\": [1, 2, 3, 4, 5],\n \"metadata\": {\n \"timestamp\": \"{{$timestamp}}\",\n \"test\": true\n }\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00chai1qt0inext01", - "name": "chai-assertions-hopp-extended", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\n// EQUALITY ASSERTIONS\nhopp.test('Chai equality - equal() method', () => {\n hopp.expect(5).to.equal(5)\n hopp.expect('hello').to.equal('hello')\n hopp.expect(true).to.equal(true)\n})\n\nhopp.test('Chai equality - eql() for deep equality', () => {\n hopp.expect({ a: 1 }).to.eql({ a: 1 })\n hopp.expect([1, 2, 3]).to.eql([1, 2, 3])\n})\n\nhopp.test('Chai equality - negation with .not', () => {\n hopp.expect(5).to.not.equal(10)\n hopp.expect('hello').to.not.equal('world')\n})\n\n// TYPE ASSERTIONS\nhopp.test('Chai type - .a() and .an() assertions', () => {\n hopp.expect('test').to.be.a('string')\n hopp.expect(42).to.be.a('number')\n hopp.expect([]).to.be.an('array')\n hopp.expect({}).to.be.an('object')\n})\n\nhopp.test('Chai type - instanceof assertions', () => {\n hopp.expect([1, 2, 3]).to.be.instanceof(Array)\n hopp.expect(new Date()).to.be.instanceof(Date)\n hopp.expect(new Error('test')).to.be.instanceof(Error)\n})\n\n// TRUTHINESS ASSERTIONS\nhopp.test('Chai truthiness - .true, .false, .null, .undefined', () => {\n hopp.expect(true).to.be.true\n hopp.expect(false).to.be.false\n hopp.expect(null).to.be.null\n hopp.expect(undefined).to.be.undefined\n})\n\nhopp.test('Chai truthiness - .ok and .exist', () => {\n hopp.expect(1).to.be.ok\n hopp.expect('string').to.exist\n hopp.expect(0).to.not.be.ok\n})\n\nhopp.test('Chai truthiness - .NaN assertion', () => {\n hopp.expect(NaN).to.be.NaN\n hopp.expect(42).to.not.be.NaN\n})\n\n// NUMERICAL COMPARISONS\nhopp.test('Chai numbers - .above() and .below()', () => {\n hopp.expect(10).to.be.above(5)\n hopp.expect(5).to.be.below(10)\n hopp.expect(5).to.not.be.above(10)\n})\n\nhopp.test('Chai numbers - aliases gt, lt, gte, lte', () => {\n hopp.expect(10).to.be.gt(5)\n hopp.expect(5).to.be.lt(10)\n hopp.expect(5).to.be.gte(5)\n hopp.expect(5).to.be.lte(5)\n})\n\nhopp.test('Chai numbers - .least() and .most()', () => {\n hopp.expect(10).to.be.at.least(10)\n hopp.expect(10).to.be.at.most(10)\n hopp.expect(15).to.be.at.least(10)\n})\n\nhopp.test('Chai numbers - .within() range', () => {\n hopp.expect(7).to.be.within(5, 10)\n hopp.expect(5).to.be.within(5, 10)\n hopp.expect(10).to.be.within(5, 10)\n})\n\nhopp.test('Chai numbers - .closeTo() with delta', () => {\n hopp.expect(10).to.be.closeTo(10.5, 0.6)\n hopp.expect(9.99).to.be.closeTo(10, 0.1)\n})\n\n// PROPERTY ASSERTIONS\nhopp.test('Chai properties - .property() checks', () => {\n const obj = { name: 'test', nested: { value: 42 } }\n hopp.expect(obj).to.have.property('name')\n hopp.expect(obj).to.have.property('name', 'test')\n hopp.expect(obj).to.have.nested.property('nested.value', 42)\n})\n\nhopp.test('Chai properties - .ownProperty() checks', () => {\n const obj = { own: 'value' }\n hopp.expect(obj).to.have.ownProperty('own')\n hopp.expect(obj).to.not.have.ownProperty('toString')\n})\n\n// LENGTH ASSERTIONS\nhopp.test('Chai length - .lengthOf() for arrays and strings', () => {\n hopp.expect([1, 2, 3]).to.have.lengthOf(3)\n hopp.expect('hello').to.have.lengthOf(5)\n hopp.expect([]).to.have.lengthOf(0)\n})\n\n// COLLECTION ASSERTIONS\nhopp.test('Chai collections - .keys() assertions', () => {\n const obj = { a: 1, b: 2, c: 3 }\n hopp.expect(obj).to.have.keys('a', 'b', 'c')\n hopp.expect(obj).to.have.all.keys('a', 'b', 'c')\n hopp.expect(obj).to.have.any.keys('a', 'd')\n})\n\nhopp.test('Chai collections - .members() for arrays', () => {\n hopp.expect([1, 2, 3]).to.have.members([3, 2, 1])\n hopp.expect([1, 2, 3]).to.include.members([1, 2])\n})\n\nhopp.test('Chai collections - .deep.members() for object arrays', () => {\n hopp.expect([{ a: 1 }, { b: 2 }]).to.have.deep.members([{ b: 2 }, { a: 1 }])\n})\n\nhopp.test('Chai collections - .oneOf() checks', () => {\n hopp.expect(2).to.be.oneOf([1, 2, 3])\n hopp.expect('a').to.be.oneOf(['a', 'b', 'c'])\n})\n\n// INCLUSION ASSERTIONS\nhopp.test('Chai inclusion - .include() for arrays and strings', () => {\n hopp.expect([1, 2, 3]).to.include(2)\n hopp.expect('hello world').to.include('world')\n})\n\nhopp.test('Chai inclusion - .deep.include() for objects', () => {\n hopp.expect([{ a: 1 }, { b: 2 }]).to.deep.include({ a: 1 })\n})\n\n// FUNCTION/ERROR ASSERTIONS\nhopp.test('Chai functions - .throw() assertions', () => {\n const throwFn = () => { throw new Error('test error') }\n const noThrow = () => { return 42 }\n \n hopp.expect(throwFn).to.throw()\n hopp.expect(throwFn).to.throw(Error)\n hopp.expect(throwFn).to.throw('test error')\n hopp.expect(noThrow).to.not.throw()\n})\n\nhopp.test('Chai functions - .respondTo() method checks', () => {\n const obj = { method: function() {} }\n hopp.expect(obj).to.respondTo('method')\n hopp.expect([]).to.respondTo('push')\n})\n\nhopp.test('Chai functions - .satisfy() custom matcher', () => {\n hopp.expect(10).to.satisfy((num) => num > 5)\n hopp.expect('hello').to.satisfy((str) => str.length === 5)\n})\n\n// OBJECT STATE ASSERTIONS\nhopp.test('Chai object state - .sealed, .frozen, .extensible', () => {\n const sealed = Object.seal({ a: 1 })\n const frozen = Object.freeze({ b: 2 })\n const extensible = { c: 3 }\n \n hopp.expect(sealed).to.be.sealed\n hopp.expect(frozen).to.be.frozen\n hopp.expect(extensible).to.be.extensible\n})\n\nhopp.test('Chai number state - .finite', () => {\n hopp.expect(42).to.be.finite\n hopp.expect(Infinity).to.not.be.finite\n})\n\n// EXOTIC OBJECTS\nhopp.test('Chai exotic - Set assertions', () => {\n const mySet = new Set([1, 2, 3])\n hopp.expect(mySet).to.be.instanceof(Set)\n hopp.expect(mySet).to.have.lengthOf(3)\n})\n\nhopp.test('Chai exotic - Map assertions', () => {\n const myMap = new Map([['key', 'value']])\n hopp.expect(myMap).to.be.instanceof(Map)\n hopp.expect(myMap).to.have.lengthOf(1)\n})\n\n// SIDE-EFFECT ASSERTIONS\nhopp.test('Chai side-effects - .change() assertions', () => {\n const obj = { count: 0 }\n const changeFn = () => { obj.count = 5 }\n hopp.expect(changeFn).to.change(obj, 'count')\n \n const noChangeFn = () => {} \n hopp.expect(noChangeFn).to.not.change(obj, 'count')\n})\n\nhopp.test('Chai side-effects - .change().by() delta', () => {\n const obj = { count: 10 }\n const addFive = () => { obj.count += 5 }\n hopp.expect(addFive).to.change(obj, 'count').by(5)\n})\n\nhopp.test('Chai side-effects - .increase() assertions', () => {\n const obj = { count: 0 }\n const incFn = () => { obj.count++ }\n hopp.expect(incFn).to.increase(obj, 'count')\n})\n\nhopp.test('Chai side-effects - .decrease() assertions', () => {\n const obj = { count: 10 }\n const decFn = () => { obj.count-- }\n hopp.expect(decFn).to.decrease(obj, 'count')\n})\n\n// LANGUAGE CHAINS AND MODIFIERS\nhopp.test('Chai chains - Complex chaining with multiple modifiers', () => {\n hopp.expect([1, 2, 3]).to.be.an('array').that.includes(2)\n hopp.expect({ a: 1, b: 2 }).to.be.an('object').that.has.property('a')\n})\n\nhopp.test('Chai modifiers - .deep with .equal()', () => {\n hopp.expect({ a: { b: 1 } }).to.deep.equal({ a: { b: 1 } })\n hopp.expect([{ a: 1 }]).to.deep.equal([{ a: 1 }])\n})\n\n// RESPONSE-BASED TESTS\nhopp.test('Chai with response - status code checks', () => {\n hopp.expect(hopp.response.statusCode).to.equal(200)\n hopp.expect(hopp.response.statusCode).to.be.within(200, 299)\n})\n\nhopp.test('Chai with response - body parsing', () => {\n const response = hopp.response.body.asJSON()\n hopp.expect(response).to.be.an('object')\n hopp.expect(response).to.have.property('data')\n \n const body = JSON.parse(response.data)\n hopp.expect(body).to.have.property('testData')\n hopp.expect(body.testData).to.have.property('number', 42)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"testData\": {\n \"number\": 42,\n \"string\": \"hello world\",\n \"array\": [1, 2, 3, 4, 5],\n \"object\": { \"nested\": { \"value\": true } },\n \"bool\": true,\n \"nullValue\": null\n }\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00chai2qt0inext02", - "name": "chai-assertions-pm-parity", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\npm.test('PM Chai - equality assertions', () => {\n pm.expect(5).to.equal(5)\n pm.expect('test').to.not.equal('other')\n pm.expect({ a: 1 }).to.eql({ a: 1 })\n})\n\npm.test('PM Chai - type assertions', () => {\n pm.expect('string').to.be.a('string')\n pm.expect(42).to.be.a('number')\n pm.expect([]).to.be.an('array')\n})\n\npm.test('PM Chai - truthiness assertions', () => {\n pm.expect(true).to.be.true\n pm.expect(false).to.be.false\n pm.expect(null).to.be.null\n})\n\npm.test('PM Chai - numerical comparisons', () => {\n pm.expect(10).to.be.above(5)\n pm.expect(5).to.be.below(10)\n pm.expect(7).to.be.within(5, 10)\n})\n\npm.test('PM Chai - property and length assertions', () => {\n const obj = { name: 'test' }\n pm.expect(obj).to.have.property('name')\n pm.expect([1, 2, 3]).to.have.lengthOf(3)\n pm.expect('hello').to.have.lengthOf(5)\n})\n\npm.test('PM Chai - string and collection assertions', () => {\n pm.expect('hello world').to.include('world')\n pm.expect([1, 2, 3]).to.include(2)\n pm.expect({ a: 1, b: 2 }).to.have.keys('a', 'b')\n})\n\npm.test('PM Chai - function assertions', () => {\n const throwFn = () => { throw new Error('test') }\n pm.expect(throwFn).to.throw()\n pm.expect([]).to.respondTo('push')\n})\n\npm.test('PM Chai - response validation', () => {\n pm.expect(pm.response.code).to.equal(200)\n pm.expect(pm.response.responseTime).to.be.a('number')\n \n const response = pm.response.json()\n pm.expect(response).to.have.property('data')\n \n const body = JSON.parse(response.data)\n pm.expect(body).to.have.property('pmTest')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"pmTest\": {\n \"value\": 42,\n \"text\": \"postman compatible\"\n }\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00cookies01", - "name": "cookie-assertions-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Cookie", - "value": "session_id=abc123; user_token=xyz789; preferences=theme%3Ddark", - "active": true, - "description": "Test cookies" - } - ], - "preRequestScript": "", - "testScript": "\n// NOTE: Full cookie behavior with Set-Cookie headers is tested in js-sandbox unit tests\n// (see packages/hoppscotch-js-sandbox/src/__tests__/pm-namespace/response/cookies.spec.ts)\n// These CLI E2E tests verify API contracts and integration behavior\n\npm.test('pm.response.cookies API contract - all methods exist', () => {\n pm.expect(pm.response.cookies).to.be.an('object')\n pm.expect(typeof pm.response.cookies.get).to.equal('function')\n pm.expect(typeof pm.response.cookies.has).to.equal('function')\n pm.expect(typeof pm.response.cookies.toObject).to.equal('function')\n})\n\npm.test('pm.response.cookies.toObject() returns proper structure', () => {\n const allCookies = pm.response.cookies.toObject()\n pm.expect(allCookies).to.be.an('object')\n pm.expect(typeof allCookies).to.equal('object')\n})\n\npm.test('pm.response.cookies.has() returns boolean for cookie checks', () => {\n const hasCookie = pm.response.cookies.has('test_cookie_name')\n pm.expect(hasCookie).to.be.a('boolean')\n})\n\npm.test('pm.response.cookies.get() returns null for non-existent cookies', () => {\n const cookieValue = pm.response.cookies.get('non_existent_cookie_xyz')\n pm.expect(cookieValue).to.be.null\n})\n\npm.test('pm.response.cookies API integrates with response object', () => {\n pm.expect(pm.response.code).to.equal(200)\n \n // Verify cookies object is accessible from response\n pm.expect(pm.response).to.have.property('cookies')\n pm.expect(pm.response.cookies).to.not.be.null\n pm.expect(pm.response.cookies).to.not.be.undefined\n})\n\npm.test('Request cookies are properly sent via Cookie header', () => {\n const hasCookieHeader = pm.request.headers.has('Cookie')\n \n if (hasCookieHeader) {\n const cookieHeader = pm.request.headers.get('Cookie')\n pm.expect(cookieHeader).to.be.a('string')\n pm.expect(cookieHeader).to.include('session_id')\n pm.expect(cookieHeader).to.include('user_token')\n }\n})\n\npm.test('pm.response.to.have.cookie() assertion method exists', () => {\n // Verify the cookie assertion is defined in the type system\n pm.expect(typeof pm.response.to.have.cookie).to.equal('function')\n})\n\nhopp.test('hopp.cookies API contract matches pm.response.cookies', () => {\n hopp.expect(typeof hopp.cookies).toBe('object')\n hopp.expect(typeof hopp.cookies.get).toBe('function')\n hopp.expect(typeof hopp.cookies.has).toBe('function')\n hopp.expect(typeof hopp.cookies.getAll).toBe('function')\n hopp.expect(typeof hopp.cookies.set).toBe('function')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00schema01", - "name": "json-schema-validation-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\npm.test('pm.response.to.have.jsonSchema() validates response structure', () => {\n const schema = {\n type: 'object',\n required: ['data'],\n properties: {\n data: { type: 'string' },\n headers: { type: 'object' }\n }\n }\n \n pm.response.to.have.jsonSchema(schema)\n \n // Explicit assertions to ensure schema validation passed\n const json = pm.response.json()\n pm.expect(json).to.have.property('data')\n pm.expect(json.data).to.be.a('string')\n})\n\npm.test('JSON Schema validation with nested properties', () => {\n const response = pm.response.json()\n const body = JSON.parse(response.data)\n \n const userSchema = {\n type: 'object',\n required: ['name', 'age'],\n properties: {\n name: { type: 'string' },\n age: { type: 'number', minimum: 0, maximum: 150 },\n email: { type: 'string' }\n }\n }\n \n pm.expect(body).to.have.jsonSchema(userSchema)\n \n // Explicit assertions to ensure schema validation passed\n pm.expect(body).to.have.property('name')\n pm.expect(body).to.have.property('age')\n pm.expect(body.name).to.equal('Alice Smith')\n pm.expect(body.age).to.equal(28)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"name\": \"Alice Smith\",\n \"age\": 28,\n \"email\": \"alice@example.com\"\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00charset01", - "name": "charset-validation-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\n// NOTE: Full charset behavior with actual charset values is tested in js-sandbox unit tests\n// (see packages/hoppscotch-js-sandbox/src/__tests__/pm-namespace/advanced-assertions.spec.ts)\n// These CLI E2E tests verify API contracts and header parsing behavior\n\npm.test('pm.expect().to.have.charset() assertion API contract exists', () => {\n const testString = 'test'\n pm.expect(typeof pm.expect(testString).to.have.charset).to.equal('function')\n})\n\npm.test('pm.response.to.have.charset() assertion API contract exists', () => {\n pm.expect(typeof pm.response.to.have.charset).to.equal('function')\n})\n\npm.test('Response Content-Type header is accessible and parseable', () => {\n const contentType = pm.response.headers.get('content-type')\n pm.expect(contentType).to.be.a('string')\n pm.expect(contentType.length).to.be.above(0)\n pm.expect(contentType).to.include('application/')\n})\n\npm.test('Content-Type header parsing logic validates structure', () => {\n const contentType = pm.response.headers.get('content-type')\n \n // Test charset detection logic\n const hasCharset = contentType.includes('charset=')\n pm.expect(typeof hasCharset).to.equal('boolean')\n \n // Test charset extraction pattern\n const charsetMatch = contentType.match(/charset=([^;\\s]+)/i)\n if (hasCharset) {\n pm.expect(charsetMatch).to.be.an('array')\n pm.expect(charsetMatch[1]).to.be.a('string')\n } else {\n pm.expect(charsetMatch).to.be.null\n }\n})\n\npm.test('Charset handling works with or without explicit charset', () => {\n const contentType = pm.response.headers.get('content-type')\n const hasExplicitCharset = contentType.toLowerCase().includes('charset=')\n \n // Whether charset is present or not, response decoding should work\n const responseText = pm.response.text()\n pm.expect(responseText).to.be.a('string')\n pm.expect(responseText.length).to.be.above(0)\n})\n\npm.test('Response text decoding works with UTF-8 default', () => {\n const responseText = pm.response.text()\n pm.expect(responseText).to.be.a('string')\n \n // Verify JSON parsing works (implies correct encoding)\n const responseJson = pm.response.json()\n pm.expect(responseJson).to.be.an('object')\n pm.expect(responseJson).to.have.property('data')\n})\n\npm.test('Response headers integrate correctly with charset assertions', () => {\n const allHeaders = pm.response.headers.all()\n pm.expect(allHeaders).to.be.an('object')\n pm.expect(Object.keys(allHeaders).length).to.be.above(0)\n})\n\nhopp.test('hopp namespace handles response encoding with proper defaults', () => {\n const textResponse = hopp.response.body.asText()\n hopp.expect(textResponse).toBeType('string')\n hopp.expect(textResponse.length > 0).toBe(true)\n \n // Verify JSON parsing works with default encoding\n const jsonResponse = hopp.response.body.asJSON()\n hopp.expect(jsonResponse).toBeType('object')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00jsonpath01", - "name": "jsonpath-query-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\npm.test('pm.response.to.have.jsonPath() queries nested JSON data', () => {\n const response = pm.response.json()\n const body = JSON.parse(response.data)\n \n pm.expect(body).to.have.jsonPath('$.users[0].name')\n pm.expect(body).to.have.jsonPath('$.users[*].active')\n pm.expect(body).to.have.jsonPath('$.metadata.version')\n})\n\npm.test('JSONPath with value validation', () => {\n const response = pm.response.json()\n const body = JSON.parse(response.data)\n \n pm.expect(body).to.have.jsonPath('$.users[0].name', 'John')\n pm.expect(body).to.have.jsonPath('$.metadata.version', '1.0')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"users\": [\n { \"name\": \"John\", \"active\": true },\n { \"name\": \"Jane\", \"active\": false }\n ],\n \"metadata\": {\n \"version\": \"1.0\",\n \"timestamp\": \"2025-01-15\"\n }\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00envext01", - "name": "environment-extensions-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "pm.environment.set('template_var', 'world')\npm.environment.set('user_id', '12345')\npm.globals.set('api_base', 'https://api.example.com')\npm.globals.set('version', 'v2')\n", - "testScript": "\npm.test('pm.environment.name returns environment identifier', () => {\n pm.expect(pm.environment.name).to.be.a('string')\n pm.expect(pm.environment.name).to.equal('active')\n})\n\npm.test('pm.environment.replaceIn() resolves template variables', () => {\n const template = 'Hello {{template_var}}, user {{user_id}}!'\n const resolved = pm.environment.replaceIn(template)\n pm.expect(resolved).to.equal('Hello world, user 12345!')\n})\n\npm.test('pm.globals.replaceIn() resolves global template variables', () => {\n const template = '{{api_base}}/{{version}}/users'\n const resolved = pm.globals.replaceIn(template)\n pm.expect(resolved).to.equal('https://api.example.com/v2/users')\n})\n\npm.test('pm.environment.toObject() returns all environment variables', () => {\n const allVars = pm.environment.toObject()\n pm.expect(allVars).to.be.an('object')\n pm.expect(allVars).to.have.property('template_var', 'world')\n pm.expect(allVars).to.have.property('user_id', '12345')\n})\n\npm.test('pm.globals.toObject() returns all global variables', () => {\n const allGlobals = pm.globals.toObject()\n pm.expect(allGlobals).to.be.an('object')\n \n // globals might be empty in CLI context\n if (Object.keys(allGlobals).length > 0) {\n pm.expect(allGlobals).to.have.property('api_base')\n }\n})\n\npm.test('pm.variables.toObject() returns combined variables with precedence', () => {\n const allVariables = pm.variables.toObject()\n pm.expect(allVariables).to.be.an('object')\n pm.expect(allVariables).to.have.property('template_var')\n})\n\npm.test('pm.environment.clear() removes all environment variables', () => {\n pm.environment.clear()\n const clearedVars = pm.environment.toObject()\n pm.expect(Object.keys(clearedVars).length).to.equal(0)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00respext01", - "name": "response-extensions-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\npm.test('pm.response.responseSize returns response body size in bytes', () => {\n pm.expect(pm.response.responseSize).to.be.a('number')\n pm.expect(pm.response.responseSize).to.be.above(0)\n})\n\npm.test('pm.response.responseSize matches actual body length', () => {\n const bodyText = pm.response.text()\n // Use the same workaround as pm.response.responseSize for QuickJS\n const encoder = new TextEncoder()\n const encoded = encoder.encode(bodyText)\n // QuickJS represents Uint8Array as object with numeric keys\n const actualSize = encoded && typeof encoded.length === 'number' && encoded.length > 0\n ? encoded.length\n : Object.keys(encoded).filter(k => !isNaN(k)).length\n pm.expect(pm.response.responseSize).to.equal(actualSize)\n})\n\npm.test('Response size is calculated correctly for JSON payload', () => {\n const response = pm.response.json()\n pm.expect(pm.response.responseSize).to.be.a('number')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"message\": \"Testing response size calculation\",\n \"data\": {\n \"items\": [1, 2, 3, 4, 5],\n \"metadata\": {\n \"count\": 5,\n \"type\": \"numeric\"\n }\n }\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00execext01", - "name": "execution-context-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\npm.test('pm.execution.location provides execution path', () => {\n pm.expect(pm.execution.location).to.be.an('array')\n pm.expect(pm.execution.location.length).to.be.above(0)\n})\n\npm.test('pm.execution.location.current returns current location', () => {\n pm.expect(pm.execution.location.current).to.be.a('string')\n pm.expect(pm.execution.location.current).to.equal('Hoppscotch')\n})\n\npm.test('pm.execution.location is immutable', () => {\n const location = pm.execution.location\n const throwFn = () => { location.push('test') }\n pm.expect(throwFn).to.throw()\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00bddassert01", - "name": "bdd-response-assertions-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Content-Type", - "value": "application/json", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "\npm.test('pm.response.to.have.status() validates exact status code', () => {\n pm.response.to.have.status(200)\n pm.expect(pm.response.code).to.equal(200)\n})\n\npm.test('pm.response.to.be.ok validates 2xx status codes', () => {\n pm.response.to.be.ok()\n})\n\npm.test('pm.response.to.be.success validates 2xx status codes (alias)', () => {\n pm.response.to.be.success()\n})\n\npm.test('pm.response.to.have.header() validates response headers', () => {\n pm.response.to.have.header('content-type')\n pm.expect(pm.response.headers.has('content-type')).to.be.true\n})\n\npm.test('pm.response.to.have.jsonBody() validates JSON response', () => {\n pm.response.to.have.jsonBody()\n pm.response.to.have.jsonBody('data')\n \n const json = pm.response.json()\n pm.expect(json).to.have.property('data')\n})\n\npm.test('pm.response.to.be.json validates JSON content type', () => {\n pm.response.to.be.json()\n})\n\npm.test('pm.response.to.have.responseTime assertions', () => {\n pm.response.to.have.responseTime.below(5000)\n pm.expect(pm.response.responseTime).to.be.a('number')\n pm.expect(pm.response.responseTime).to.be.above(0)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"test\": \"BDD assertions\",\n \"status\": \"success\"\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00includecontain01", - "name": "include-contain-assertions-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\npm.test('pm.expect().to.include() validates string inclusion', () => {\n pm.expect('hello world').to.include('world')\n pm.expect('hello world').to.include('hello')\n pm.expect('test string').to.not.include('missing')\n})\n\npm.test('pm.expect().to.contain() validates array inclusion', () => {\n pm.expect([1, 2, 3]).to.contain(2)\n pm.expect([1, 2, 3]).to.include(1)\n pm.expect(['a', 'b', 'c']).to.contain('b')\n})\n\npm.test('pm.expect().to.includes() alias works', () => {\n pm.expect('testing').to.includes('test')\n pm.expect([10, 20, 30]).to.includes(20)\n})\n\npm.test('pm.expect().to.contains() alias works', () => {\n pm.expect('contains test').to.contains('contains')\n pm.expect([true, false]).to.contains(true)\n})\n\npm.test('include/contain with response data', () => {\n const response = pm.response.json()\n pm.expect(response).to.have.property('data')\n \n const bodyText = pm.response.text()\n pm.expect(bodyText).to.include('includeTest')\n})\n\nhopp.test('hopp.expect() also supports toInclude()', () => {\n hopp.expect('hopp test').toInclude('hopp')\n hopp.expect([1, 2]).toInclude(1)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"includeTest\": \"This text should be found\",\n \"array\": [1, 2, 3]\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00envunsetclear01", - "name": "environment-unset-clear-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "pm.environment.set('to_unset1', 'value1')\npm.environment.set('to_unset2', 'value2')\npm.environment.set('to_clear1', 'clear_value1')\npm.environment.set('to_clear2', 'clear_value2')\npm.environment.set('to_clear3', 'clear_value3')\npm.globals.set('global_to_unset', 'global_value')\npm.globals.set('global_to_clear1', 'global_clear1')\npm.globals.set('global_to_clear2', 'global_clear2')\n", - "testScript": "\npm.test('pm.environment.unset() removes specific variables', () => {\n pm.expect(pm.environment.has('to_unset1')).to.be.true\n pm.environment.unset('to_unset1')\n pm.expect(pm.environment.has('to_unset1')).to.be.false\n pm.expect(pm.environment.get('to_unset1')).to.be.undefined\n})\n\npm.test('pm.environment.unset() handles non-existent keys gracefully', () => {\n pm.environment.unset('non_existent_key')\n pm.expect(pm.environment.has('non_existent_key')).to.be.false\n})\n\npm.test('pm.globals.unset() removes specific global variables', () => {\n const hasGlobal = pm.globals.has('global_to_unset')\n if (hasGlobal) {\n pm.globals.unset('global_to_unset')\n pm.expect(pm.globals.has('global_to_unset')).to.be.false\n }\n})\n\npm.test('pm.environment.clear() removes ALL environment variables', () => {\n // Verify variables exist before clear\n pm.expect(pm.environment.has('to_clear1')).to.be.true\n pm.expect(pm.environment.has('to_clear2')).to.be.true\n pm.expect(pm.environment.has('to_clear3')).to.be.true\n \n // Clear all environment variables\n pm.environment.clear()\n \n // Verify ALL variables are removed\n const allVars = pm.environment.toObject()\n pm.expect(Object.keys(allVars).length).to.equal(0)\n pm.expect(pm.environment.has('to_clear1')).to.be.false\n pm.expect(pm.environment.has('to_clear2')).to.be.false\n pm.expect(pm.environment.has('to_clear3')).to.be.false\n})\n\npm.test('pm.globals.clear() removes ALL global variables', () => {\n // Verify globals exist before clear (might be empty in CLI)\n const globalsBeforeClear = pm.globals.toObject()\n \n pm.globals.clear()\n \n // Verify all globals are removed\n const globalsAfterClear = pm.globals.toObject()\n pm.expect(Object.keys(globalsAfterClear).length).to.equal(0)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00pmmutate01", - "name": "pm-request-mutation-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/original", - "params": [ - { - "key": "original_param", - "value": "original", - "active": true, - "description": "" - } - ], - "headers": [ - { - "key": "Original-Header", - "value": "original", - "active": true, - "description": "" - } - ], - "preRequestScript": "// Test PM namespace mutability - URL string assignment\npm.request.url = 'https://echo.hoppscotch.io/mutated-via-string'\n\n// Test method mutation\npm.request.method = 'POST'\n\n// Test header mutations\npm.request.headers.add({ key: 'Added-Header', value: 'added-value' })\npm.request.headers.upsert({ key: 'Original-Header', value: 'mutated-value' })\n\n// Test body mutation via update()\npm.request.body.update({\n mode: 'raw',\n raw: JSON.stringify({ pmMutated: true, timestamp: Date.now() }),\n options: { raw: { language: 'json' } }\n})\n\n// Test auth mutation\npm.request.auth = {\n authType: 'bearer',\n authActive: true,\n token: 'pm-bearer-token-123'\n}\n", - "testScript": "\npm.test('pm.request.url string assignment was applied', () => {\n const urlString = pm.request.url.toString()\n pm.expect(urlString).to.include('/mutated-via-string')\n pm.expect(urlString).to.not.include('/original')\n})\n\npm.test('pm.request.method mutation was applied', () => {\n pm.expect(pm.request.method).to.equal('POST')\n pm.expect(pm.request.method).to.not.equal('GET')\n})\n\npm.test('pm.request.headers.add() added new header', () => {\n pm.expect(pm.request.headers.has('Added-Header')).to.be.true\n pm.expect(pm.request.headers.get('Added-Header')).to.equal('added-value')\n})\n\npm.test('pm.request.headers.upsert() updated existing header', () => {\n pm.expect(pm.request.headers.has('Original-Header')).to.be.true\n pm.expect(pm.request.headers.get('Original-Header')).to.equal('mutated-value')\n pm.expect(pm.request.headers.get('Original-Header')).to.not.equal('original')\n})\n\npm.test('pm.request.body.update() changed body content', () => {\n pm.expect(pm.request.body.contentType).to.equal('application/json')\n const bodyString = typeof pm.request.body.body === 'string' \n ? pm.request.body.body \n : JSON.stringify(pm.request.body.body)\n pm.expect(bodyString).to.include('pmMutated')\n const bodyData = JSON.parse(bodyString)\n pm.expect(bodyData.pmMutated).to.be.true\n})\n\npm.test('pm.request.auth mutation was applied', () => {\n pm.expect(pm.request.auth.authType).to.equal('bearer')\n pm.expect(pm.request.auth.token).to.equal('pm-bearer-token-123')\n})\n\npm.test('pm.request.id and pm.request.name are accessible', () => {\n pm.expect(pm.request.id).to.be.a('string')\n pm.expect(pm.request.id.length).to.be.above(0)\n pm.expect(pm.request.name).to.equal('pm-request-mutation-test')\n})\n\nhopp.test('hopp.request reflects pm namespace mutations', () => {\n hopp.expect(hopp.request.url).toInclude('/mutated-via-string')\n hopp.expect(hopp.request.method).toBe('POST')\n const hasAddedHeader = hopp.request.headers.some(h => h.key === 'Added-Header')\n hopp.expect(hasAddedHeader).toBe(true)\n})\n", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00urlmutate01", - "name": "pm-url-property-mutations-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/original?old=value", - "params": [], - "headers": [], - "preRequestScript": "// Test URL object property mutations\npm.request.url.protocol = 'http'\npm.request.url.host = ['echo', 'hoppscotch', 'io']\npm.request.url.path = ['v2', 'test']\npm.request.url.port = '443'\npm.request.url.query.add({ key: 'new', value: 'param' })\npm.request.url.query.remove('old')\n", - "testScript": "\npm.test('URL protocol mutation works', () => {\n const url = pm.request.url\n pm.expect(url.protocol).to.equal('http')\n pm.expect(url.toString()).to.include('http://')\n})\n\npm.test('URL host mutation works', () => {\n const url = pm.request.url\n pm.expect(url.host).to.be.an('array')\n pm.expect(url.host.join('.')).to.equal('echo.hoppscotch.io')\n pm.expect(url.toString()).to.include('echo.hoppscotch.io')\n})\n\npm.test('URL path mutation works', () => {\n const url = pm.request.url\n pm.expect(url.path).to.be.an('array')\n pm.expect(url.path).to.include('v2')\n pm.expect(url.path).to.include('test')\n pm.expect(url.toString()).to.include('/v2/test')\n})\n\npm.test('URL query.add() adds parameter', () => {\n const allParams = pm.request.url.query.all()\n pm.expect(allParams).to.have.property('new', 'param')\n})\n\npm.test('URL query.remove() removes parameter', () => {\n const allParams = pm.request.url.query.all()\n pm.expect(allParams).to.not.have.property('old')\n})\n\npm.test('Full URL reflects all mutations', () => {\n const fullUrl = pm.request.url.toString()\n pm.expect(fullUrl).to.include('http://')\n pm.expect(fullUrl).to.include('echo.hoppscotch.io')\n pm.expect(fullUrl).to.include('/v2/test')\n pm.expect(fullUrl).to.include('new=param')\n pm.expect(fullUrl).to.not.include('old=value')\n})\n\nhopp.test('hopp.request reflects URL mutations', () => {\n hopp.expect(hopp.request.url).toInclude('echo.hoppscotch.io')\n hopp.expect(hopp.request.url).toInclude('/v2/test')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00unsupported01", - "name": "unsupported-features-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "\nconst unsupportedApis = [\n { api: 'pm.info.iteration', script: () => { const x = pm.info.iteration }, errorMessage: /Collection Runner feature/ },\n { api: 'pm.info.iterationCount', script: () => { const x = pm.info.iterationCount }, errorMessage: /Collection Runner feature/ },\n { api: 'pm.collectionVariables.get()', script: () => pm.collectionVariables.get('test'), errorMessage: /use environment or request variables instead/ },\n { api: 'pm.collectionVariables.set()', script: () => pm.collectionVariables.set('key', 'value'), errorMessage: /use environment or request variables instead/ },\n { api: 'pm.collectionVariables.unset()', script: () => pm.collectionVariables.unset('key'), errorMessage: /use environment or request variables instead/ },\n { api: 'pm.collectionVariables.has()', script: () => pm.collectionVariables.has('key'), errorMessage: /use environment or request variables instead/ },\n { api: 'pm.collectionVariables.clear()', script: () => pm.collectionVariables.clear(), errorMessage: /use environment or request variables instead/ },\n { api: 'pm.collectionVariables.toObject()', script: () => pm.collectionVariables.toObject(), errorMessage: /use environment or request variables instead/ },\n { api: 'pm.collectionVariables.replaceIn()', script: () => pm.collectionVariables.replaceIn('{{test}}'), errorMessage: /use environment or request variables instead/ },\n { api: 'pm.vault.get()', script: () => pm.vault.get('test'), errorMessage: /Postman Vault feature/ },\n { api: 'pm.vault.set()', script: () => pm.vault.set('key', 'value'), errorMessage: /Postman Vault feature/ },\n { api: 'pm.vault.unset()', script: () => pm.vault.unset('key'), errorMessage: /Postman Vault feature/ },\n { api: 'pm.iterationData.get()', script: () => pm.iterationData.get('test'), errorMessage: /Collection Runner feature/ },\n { api: 'pm.iterationData.set()', script: () => pm.iterationData.set('key', 'value'), errorMessage: /Collection Runner feature/ },\n { api: 'pm.iterationData.unset()', script: () => pm.iterationData.unset('key'), errorMessage: /Collection Runner feature/ },\n { api: 'pm.iterationData.has()', script: () => pm.iterationData.has('key'), errorMessage: /Collection Runner feature/ },\n { api: 'pm.iterationData.toObject()', script: () => pm.iterationData.toObject(), errorMessage: /Collection Runner feature/ },\n { api: 'pm.iterationData.toJSON()', script: () => pm.iterationData.toJSON(), errorMessage: /Collection Runner feature/ },\n { api: 'pm.execution.setNextRequest()', script: () => pm.execution.setNextRequest('next'), errorMessage: /Collection Runner feature/ },\n { api: 'pm.execution.skipRequest()', script: () => pm.execution.skipRequest(), errorMessage: /Collection Runner feature/ },\n { api: 'pm.execution.runRequest()', script: () => pm.execution.runRequest(), errorMessage: /Collection Runner feature/ },\n { api: 'pm.visualizer.set()', script: () => pm.visualizer.set('

Test

'), errorMessage: /Postman Visualizer feature/ },\n { api: 'pm.visualizer.clear()', script: () => pm.visualizer.clear(), errorMessage: /Postman Visualizer feature/ },\n { api: 'pm.require()', script: () => pm.require('lodash'), errorMessage: /not supported in Hoppscotch/ },\n]\n\nunsupportedApis.forEach(({ api, script, errorMessage }) => {\n pm.test(`${api} throws descriptive error`, () => {\n pm.expect(script).to.throw(errorMessage)\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00urlpropertylist01", - "name": "url-propertylist-helpers-test", - "method": "GET", - "endpoint": "https://api.example.com:8080/v1/users?filter=active&sort=name&tag=js&tag=ts#section1", - "params": [ - { - "key": "filter", - "value": "active", - "active": true, - "description": "" - }, - { - "key": "sort", - "value": "name", - "active": true, - "description": "" - }, - { - "key": "tag", - "value": "js", - "active": true, - "description": "" - }, - { - "key": "tag", - "value": "ts", - "active": true, - "description": "" - } - ], - "headers": [ - { - "key": "Content-Type", - "value": "application/json", - "active": true, - "description": "" - }, - { - "key": "Authorization", - "value": "Bearer test-token", - "active": true, - "description": "" - } - ], - "preRequestScript": "// Test URL helper methods\npm.request.url.update('https://echo.hoppscotch.io/updated?test=value')\npm.request.url.addQueryParams([{ key: 'page', value: '1' }, { key: 'limit', value: '20' }])\npm.request.url.removeQueryParams('test')\n\n// Test hostname and hash properties\npm.request.url.hostname = 'echo.hoppscotch.io'\npm.request.url.hash = 'results'\n\n// Test query PropertyList methods\npm.request.url.query.upsert({ key: 'status', value: 'published' })\npm.request.url.query.add({ key: 'include', value: 'metadata' })\n", - "testScript": "\npm.test('URL helper methods - getHost() returns hostname as string', () => {\n const host = pm.request.url.getHost()\n pm.expect(host).to.be.a('string')\n pm.expect(host).to.equal('echo.hoppscotch.io')\n})\n\npm.test('URL helper methods - getPath() returns path with leading slash', () => {\n const path = pm.request.url.getPath()\n pm.expect(path).to.be.a('string')\n pm.expect(path).to.include('/')\n pm.expect(path).to.equal('/updated')\n})\n\npm.test('URL helper methods - getPathWithQuery() includes query string', () => {\n const pathWithQuery = pm.request.url.getPathWithQuery()\n pm.expect(pathWithQuery).to.include('?')\n pm.expect(pathWithQuery).to.include('page=1')\n pm.expect(pathWithQuery).to.include('limit=20')\n})\n\npm.test('URL helper methods - getQueryString() returns query without ?', () => {\n const queryString = pm.request.url.getQueryString()\n pm.expect(queryString).to.be.a('string')\n pm.expect(queryString).to.not.include('?')\n pm.expect(queryString).to.include('page=1')\n})\n\npm.test('URL helper methods - getRemote() returns host with port', () => {\n const remote = pm.request.url.getRemote()\n pm.expect(remote).to.be.a('string')\n pm.expect(remote).to.equal('echo.hoppscotch.io')\n})\n\npm.test('URL helper methods - update() changes entire URL', () => {\n const url = pm.request.url.toString()\n pm.expect(url).to.include('echo.hoppscotch.io')\n pm.expect(url).to.include('/updated')\n})\n\npm.test('URL helper methods - addQueryParams() adds multiple params', () => {\n const allParams = pm.request.url.query.all()\n pm.expect(allParams).to.have.property('page', '1')\n pm.expect(allParams).to.have.property('limit', '20')\n})\n\npm.test('URL helper methods - removeQueryParams() removes params', () => {\n const allParams = pm.request.url.query.all()\n pm.expect(allParams).to.not.have.property('test')\n})\n\npm.test('URL properties - hostname getter returns string', () => {\n const hostname = pm.request.url.hostname\n pm.expect(hostname).to.be.a('string')\n pm.expect(hostname).to.equal('echo.hoppscotch.io')\n})\n\npm.test('URL properties - hostname matches host array', () => {\n const hostname = pm.request.url.hostname\n const hostString = pm.request.url.host.join('.')\n pm.expect(hostname).to.equal(hostString)\n})\n\npm.test('URL properties - hash getter returns string', () => {\n const hash = pm.request.url.hash\n pm.expect(hash).to.be.a('string')\n // Hash might not persist through URL mutations in E2E context\n})\n\npm.test('Query PropertyList - get() retrieves parameter value', () => {\n const pageValue = pm.request.url.query.get('page')\n pm.expect(pageValue).to.equal('1')\n})\n\npm.test('Query PropertyList - has() checks parameter existence', () => {\n pm.expect(pm.request.url.query.has('page')).to.be.true\n pm.expect(pm.request.url.query.has('nonexistent')).to.be.false\n})\n\npm.test('Query PropertyList - upsert() adds/updates parameter', () => {\n pm.expect(pm.request.url.query.has('status')).to.be.true\n pm.expect(pm.request.url.query.get('status')).to.equal('published')\n})\n\npm.test('Query PropertyList - count() returns parameter count', () => {\n const count = pm.request.url.query.count()\n pm.expect(count).to.be.a('number')\n pm.expect(count).to.be.above(0)\n})\n\npm.test('Query PropertyList - each() iterates over parameters', () => {\n let iterationCount = 0\n pm.request.url.query.each((param) => {\n pm.expect(param).to.have.property('key')\n pm.expect(param).to.have.property('value')\n iterationCount++\n })\n pm.expect(iterationCount).to.be.above(0)\n})\n\npm.test('Query PropertyList - map() transforms parameters', () => {\n const keys = pm.request.url.query.map((param) => param.key)\n pm.expect(keys).to.be.an('array')\n pm.expect(keys).to.include('page')\n pm.expect(keys).to.include('limit')\n})\n\npm.test('Query PropertyList - filter() filters parameters', () => {\n const filtered = pm.request.url.query.filter((param) => param.key === 'page')\n pm.expect(filtered).to.be.an('array')\n pm.expect(filtered.length).to.be.above(0)\n pm.expect(filtered[0].key).to.equal('page')\n})\n\npm.test('Query PropertyList - idx() accesses by index', () => {\n const firstParam = pm.request.url.query.idx(0)\n pm.expect(firstParam).to.be.an('object')\n pm.expect(firstParam).to.have.property('key')\n pm.expect(firstParam).to.have.property('value')\n})\n\npm.test('Query PropertyList - idx() returns null for out of bounds', () => {\n const param = pm.request.url.query.idx(999)\n pm.expect(param).to.be.null\n})\n\npm.test('Query PropertyList - toObject() returns object', () => {\n const obj = pm.request.url.query.toObject()\n pm.expect(obj).to.be.an('object')\n pm.expect(obj).to.have.property('page')\n})\n\npm.test('Headers PropertyList - each() iterates over headers', () => {\n let count = 0\n pm.request.headers.each((header) => {\n pm.expect(header).to.have.property('key')\n pm.expect(header).to.have.property('value')\n count++\n })\n pm.expect(count).to.be.above(0)\n})\n\npm.test('Headers PropertyList - map() transforms headers', () => {\n const keys = pm.request.headers.map((h) => h.key)\n pm.expect(keys).to.be.an('array')\n pm.expect(keys).to.include('Content-Type')\n})\n\npm.test('Headers PropertyList - filter() filters headers', () => {\n const filtered = pm.request.headers.filter((h) => h.key === 'Content-Type')\n pm.expect(filtered).to.be.an('array')\n pm.expect(filtered.length).to.be.above(0)\n})\n\npm.test('Headers PropertyList - count() returns header count', () => {\n const count = pm.request.headers.count()\n pm.expect(count).to.be.a('number')\n pm.expect(count).to.be.above(0)\n})\n\npm.test('Headers PropertyList - idx() accesses by index', () => {\n const firstHeader = pm.request.headers.idx(0)\n pm.expect(firstHeader).to.be.an('object')\n pm.expect(firstHeader).to.have.property('key')\n})\n\npm.test('Headers PropertyList - toObject() returns object', () => {\n const obj = pm.request.headers.toObject()\n pm.expect(obj).to.be.an('object')\n pm.expect(obj).to.have.property('Content-Type')\n})\n\nhopp.test('hopp namespace URL methods work identically', () => {\n const url = hopp.request.url\n hopp.expect(url).toInclude('echo.hoppscotch.io')\n hopp.expect(url).toInclude('/updated')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "name": "propertylist-advanced-methods-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/propertylist", - "params": [ - { - "key": "filter", - "value": "active", - "active": true, - "description": "" - }, - { - "key": "sort", - "value": "name", - "active": true, - "description": "" - }, - { - "key": "page", - "value": "1", - "active": true, - "description": "" - } - ], - "headers": [ - { - "key": "Content-Type", - "value": "application/json", - "active": true, - "description": "" - }, - { - "key": "Authorization", - "value": "Bearer token123", - "active": true, - "description": "" - } - ], - "preRequestScript": "// Test query.insert() - insert limit before page\npm.request.url.query.insert({ key: 'limit', value: '10' }, 'page')\n\n// Test query.append() - add new param at end\npm.request.url.query.append({ key: 'offset', value: '0' })\n\n// Test query.assimilate() - merge params\npm.request.url.query.assimilate({ include: 'metadata', status: 'active' })\n\n// Test headers.insert() - insert before Authorization\npm.request.headers.insert({ key: 'X-API-Key', value: 'secret123' }, 'Authorization')\n\n// Test headers.append() - add at end\npm.request.headers.append({ key: 'X-Request-ID', value: 'req-456' })\n\n// Test headers.assimilate() - merge headers\npm.request.headers.assimilate({ 'X-Custom-Header': 'custom-value' })\n", - "testScript": "\npm.test('query.find() - finds param by string key', () => {\n const limitParam = pm.request.url.query.find('limit')\n if (limitParam) {\n pm.expect(limitParam).to.be.an('object')\n pm.expect(limitParam.key).to.equal('limit')\n } else {\n pm.expect(pm.request.url.query.has('limit')).to.be.true\n }\n})\n\npm.test('query.find() - finds param by predicate function', () => {\n const limitParam = pm.request.url.query.find((p) => p && p.key === 'limit')\n if (limitParam) {\n pm.expect(limitParam).to.be.an('object')\n pm.expect(limitParam.value).to.equal('10')\n } else {\n pm.expect(pm.request.url.query.get('limit')).to.equal('10')\n }\n})\n\npm.test('query.find() - returns null when not found', () => {\n const result = pm.request.url.query.find('nonexistent')\n pm.expect(result).to.be.null\n})\n\npm.test('query.indexOf() - returns index for existing params', () => {\n // Verify indexOf works - check params that exist in actual URL\n const allParams = pm.request.url.query.all()\n const keys = Object.keys(allParams)\n if (keys.length > 0) {\n const firstKey = keys[0]\n const idx = pm.request.url.query.indexOf(firstKey)\n pm.expect(idx).to.be.a('number')\n pm.expect(idx).to.be.at.least(0)\n }\n})\n\npm.test('query.indexOf() - returns index by object', () => {\n const allParams = pm.request.url.query.all()\n const keys = Object.keys(allParams)\n if (keys.length > 0) {\n const idx = pm.request.url.query.indexOf({ key: keys[0] })\n pm.expect(idx).to.be.a('number')\n pm.expect(idx).to.be.at.least(0)\n }\n})\n\npm.test('query.indexOf() - returns -1 when not found', () => {\n const idx = pm.request.url.query.indexOf('notfound')\n pm.expect(idx).to.equal(-1)\n})\n\npm.test('query.insert/append/assimilate - methods executed successfully', () => {\n // Verify the methods executed without errors in pre-request\n // Post-request sees actual sent URL, so we just verify params exist\n const allParams = pm.request.url.query.all()\n pm.expect(allParams).to.be.an('object')\n pm.expect(pm.request.url.query.has('limit')).to.be.true\n pm.expect(pm.request.url.query.has('offset')).to.be.true\n})\n\npm.test('query.append() - adds param at end', () => {\n const offsetIdx = pm.request.url.query.indexOf('offset')\n pm.expect(offsetIdx).to.be.at.least(0)\n pm.expect(pm.request.url.query.get('offset')).to.equal('0')\n})\n\npm.test('query.assimilate() - adds/updates params', () => {\n pm.expect(pm.request.url.query.has('include')).to.be.true\n pm.expect(pm.request.url.query.get('include')).to.equal('metadata')\n pm.expect(pm.request.url.query.has('status')).to.be.true\n pm.expect(pm.request.url.query.get('status')).to.equal('active')\n})\n\npm.test('headers.find() - finds header by string (case-insensitive)', () => {\n const ct = pm.request.headers.find('content-type')\n pm.expect(ct).to.be.an('object')\n pm.expect(ct.key).to.equal('Content-Type')\n})\n\npm.test('headers.find() - finds header by predicate function', () => {\n const auth = pm.request.headers.find((h) => h.key === 'Authorization')\n pm.expect(auth).to.be.an('object')\n pm.expect(auth.value).to.include('Bearer')\n})\n\npm.test('headers.find() - returns null when not found', () => {\n const result = pm.request.headers.find('nonexistent')\n pm.expect(result).to.be.null\n})\n\npm.test('headers.indexOf() - returns correct index (case-insensitive)', () => {\n const authIdx = pm.request.headers.indexOf('authorization')\n pm.expect(authIdx).to.be.a('number')\n pm.expect(authIdx).to.be.at.least(0)\n})\n\npm.test('headers.indexOf() - returns correct index by object', () => {\n const ctIdx = pm.request.headers.indexOf({ key: 'Content-Type' })\n pm.expect(ctIdx).to.be.a('number')\n pm.expect(ctIdx).to.be.at.least(0)\n})\n\npm.test('headers.indexOf() - returns -1 when not found', () => {\n const idx = pm.request.headers.indexOf('NotFound')\n pm.expect(idx).to.equal(-1)\n})\n\npm.test('headers.insert() - inserts header before specified header', () => {\n const apiKeyIdx = pm.request.headers.indexOf('X-API-Key')\n const authIdx = pm.request.headers.indexOf('Authorization')\n pm.expect(apiKeyIdx).to.be.below(authIdx)\n})\n\npm.test('headers.append() - adds header at end', () => {\n pm.expect(pm.request.headers.has('X-Request-ID')).to.be.true\n pm.expect(pm.request.headers.get('X-Request-ID')).to.equal('req-456')\n})\n\npm.test('headers.assimilate() - adds/updates headers', () => {\n pm.expect(pm.request.headers.has('X-Custom-Header')).to.be.true\n pm.expect(pm.request.headers.get('X-Custom-Header')).to.equal('custom-value')\n})\n\npm.test('query PropertyList - all methods work together', () => {\n const allParams = pm.request.url.query.all()\n pm.expect(allParams).to.be.an('object')\n // At minimum we should have the params added in pre-request\n pm.expect(Object.keys(allParams).length).to.be.at.least(4)\n})\n\npm.test('headers PropertyList - all methods work together', () => {\n const allHeaders = pm.request.headers.all()\n pm.expect(allHeaders).to.be.an('object')\n pm.expect(Object.keys(allHeaders).length).to.be.at.least(5)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "advanced-response-methods-test", - "name": "advanced-response-methods-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [ - { - "key": "Content-Type", - "value": "application/json", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "\n// Test pm.response.reason()\npm.test('pm.response.reason() returns HTTP reason phrase', () => {\n const reason = pm.response.reason()\n pm.expect(reason).to.be.a('string')\n pm.expect(reason).to.equal('OK')\n})\n\n// Test hopp.response.reason() for parity\npm.test('hopp.response.reason() returns HTTP reason phrase', () => {\n const reason = hopp.response.reason()\n hopp.expect(reason).toBeType('string')\n hopp.expect(reason).toBe('OK')\n})\n\n// Test pm.response.dataURI()\npm.test('pm.response.dataURI() converts response to data URI', () => {\n const dataURI = pm.response.dataURI()\n pm.expect(dataURI).to.be.a('string')\n pm.expect(dataURI).to.include('data:')\n pm.expect(dataURI).to.include('base64')\n})\n\n// Test hopp.response.dataURI() for parity\npm.test('hopp.response.dataURI() converts response to data URI', () => {\n const dataURI = hopp.response.dataURI()\n hopp.expect(dataURI).toBeType('string')\n hopp.expect(dataURI.startsWith('data:')).toBe(true)\n})\n\n// Test .nested property assertions\npm.test('pm.expect().to.have.nested.property() accesses nested properties', () => {\n const obj = { a: { b: { c: 'deep value' } } }\n pm.expect(obj).to.have.nested.property('a.b.c', 'deep value')\n pm.expect(obj).to.have.nested.property('a.b')\n})\n\n// Test hopp namespace nested property for parity\npm.test('hopp.expect().to.have.nested.property() accesses nested properties', () => {\n const obj = { x: { y: { z: 'nested' } } }\n hopp.expect(obj).to.have.nested.property('x.y.z', 'nested')\n hopp.expect(obj).to.have.nested.property('x.y')\n})\n\npm.test('pm.expect().to.have.nested.property() handles arrays', () => {\n const obj = { items: [{ name: 'first' }, { name: 'second' }] }\n pm.expect(obj).to.have.nested.property('items[0].name', 'first')\n pm.expect(obj).to.have.nested.property('items[1].name', 'second')\n})\n\npm.test('pm.expect().to.not.have.nested.property() negation works', () => {\n const obj = { a: { b: 'value' } }\n pm.expect(obj).to.not.have.nested.property('a.c')\n pm.expect(obj).to.not.have.nested.property('x.y.z')\n})\n\n// Test .by() chaining for change assertions\npm.test('pm.expect().to.change().by() validates exact delta', () => {\n const obj = { value: 10 }\n pm.expect(() => { obj.value = 25 }).to.change(obj, 'value').by(15)\n})\n\n// Test hopp namespace .by() chaining for parity\npm.test('hopp.expect().to.change().by() validates exact delta', () => {\n const obj = { val: 100 }\n hopp.expect(() => { obj.val = 150 }).to.change(obj, 'val').by(50)\n})\n\npm.test('pm.expect().to.increase().by() validates exact increase', () => {\n const obj = { count: 5 }\n pm.expect(() => { obj.count += 7 }).to.increase(obj, 'count').by(7)\n})\n\npm.test('pm.expect().to.decrease().by() validates exact decrease', () => {\n const obj = { score: 100 }\n pm.expect(() => { obj.score -= 30 }).to.decrease(obj, 'score').by(30)\n})\n\npm.test('pm.expect().to.change().by() with negative delta', () => {\n const obj = { value: 50 }\n pm.expect(() => { obj.value = 20 }).to.change(obj, 'value').by(-30)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\"test\": \"data\"}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "advanced-chai-map-set-test", - "name": "advanced-chai-map-set-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "export {};\n", - "testScript": "\n// Map & Set Assertions\npm.test('Map assertions - size property', () => {\n const map = new Map([['key1', 'value1'], ['key2', 'value2']])\n pm.expect(map).to.have.property('size', 2)\n pm.expect(map.size).to.equal(2)\n})\n\npm.test('Set assertions - size property', () => {\n const set = new Set([1, 2, 3, 4])\n pm.expect(set).to.have.property('size', 4)\n pm.expect(set.size).to.equal(4)\n})\n\npm.test('Map instanceOf assertion', () => {\n const map = new Map()\n pm.expect(map).to.be.instanceOf(Map)\n pm.expect(map).to.be.an.instanceOf(Map)\n})\n\npm.test('Set instanceOf assertion', () => {\n const set = new Set()\n pm.expect(set).to.be.instanceOf(Set)\n pm.expect(set).to.be.an.instanceOf(Set)\n})\n\n// Advanced Chai - closeTo\npm.test('closeTo - validates numbers within delta', () => {\n pm.expect(3.14159).to.be.closeTo(3.14, 0.01)\n pm.expect(10.5).to.be.closeTo(11, 1)\n})\n\npm.test('closeTo - negation works', () => {\n pm.expect(100).to.not.be.closeTo(50, 10)\n pm.expect(3.14).to.not.be.closeTo(10, 0.1)\n})\n\npm.test('approximately - alias for closeTo', () => {\n pm.expect(2.5).to.approximately(2.4, 0.2)\n pm.expect(99.99).to.approximately(100, 0.1)\n})\n\n// Advanced Chai - finite\npm.test('finite - validates finite numbers', () => {\n pm.expect(123).to.be.finite\n pm.expect(0).to.be.finite\n pm.expect(-456).to.be.finite\n})\n\npm.test('finite - negation for Infinity', () => {\n pm.expect(Infinity).to.not.be.finite\n pm.expect(-Infinity).to.not.be.finite\n pm.expect(NaN).to.not.be.finite\n})\n\n// Advanced Chai - satisfy\npm.test('satisfy - custom predicate function', () => {\n pm.expect(10).to.satisfy((num) => num > 5)\n pm.expect('hello').to.satisfy((str) => str.length === 5)\n})\n\npm.test('satisfy - complex validation', () => {\n const obj = { name: 'test', value: 100 }\n pm.expect(obj).to.satisfy((o) => o.value > 50 && o.name.length > 0)\n})\n\npm.test('satisfy - negation works', () => {\n pm.expect(5).to.not.satisfy((num) => num > 10)\n pm.expect('abc').to.not.satisfy((str) => str.length > 5)\n})\n\n// Advanced Chai - respondTo\npm.test('respondTo - validates method existence', () => {\n class TestClass {\n testMethod() { return 'test' }\n anotherMethod() { return 'another' }\n }\n pm.expect(TestClass).to.respondTo('testMethod')\n pm.expect(TestClass).to.respondTo('anotherMethod')\n})\n\npm.test('respondTo - with itself for static methods', () => {\n class MyClass {\n static staticMethod() { return 'static' }\n instanceMethod() { return 'instance' }\n }\n pm.expect(MyClass).itself.to.respondTo('staticMethod')\n pm.expect(MyClass).to.not.itself.respondTo('instanceMethod')\n pm.expect(MyClass).to.respondTo('instanceMethod')\n})\n\n// Property Ownership - own.property\npm.test('own.property - distinguishes own vs inherited', () => {\n const parent = { inherited: true }\n const obj = Object.create(parent)\n obj.own = true\n pm.expect(obj).to.have.own.property('own')\n pm.expect(obj).to.not.have.own.property('inherited')\n pm.expect(obj).to.have.property('inherited')\n})\n\npm.test('deep.own.property - deep check with ownership', () => {\n const proto = { shared: 'inherited' }\n const obj = Object.create(proto)\n obj.data = { nested: 'value' }\n pm.expect(obj).to.have.deep.own.property('data', { nested: 'value' })\n pm.expect(obj).to.not.have.deep.own.property('shared')\n})\n\npm.test('ownProperty - alias for own.property', () => {\n const obj = { prop: 'value' }\n pm.expect(obj).to.have.ownProperty('prop')\n pm.expect(obj).to.have.ownProperty('prop', 'value')\n})\n\n// Hopp namespace parity tests\npm.test('hopp.expect Map/Set support', () => {\n const map = new Map([['x', 1]])\n const set = new Set([1, 2])\n hopp.expect(map.size).toBe(1)\n hopp.expect(set.size).toBe(2)\n})\n\npm.test('hopp.expect closeTo support', () => {\n hopp.expect(3.14).to.be.closeTo(3.1, 0.1)\n hopp.expect(10).to.be.closeTo(10.5, 1)\n})\n\npm.test('hopp.expect finite support', () => {\n hopp.expect(42).to.be.finite\n hopp.expect(Infinity).to.not.be.finite\n})\n\npm.test('hopp.expect satisfy support', () => {\n hopp.expect(100).to.satisfy((n) => n > 50)\n hopp.expect('test').to.satisfy((s) => s.length === 4)\n})\n\npm.test('hopp.expect respondTo support', () => {\n class TestClass { method() {} }\n hopp.expect(TestClass).to.respondTo('method')\n})\n\npm.test('hopp.expect own.property support', () => {\n const obj = Object.create({ inherited: 1 })\n obj.own = 2\n hopp.expect(obj).to.have.own.property('own')\n hopp.expect(obj).to.not.have.own.property('inherited')\n})\n\npm.test('hopp.expect ordered.members support', () => {\n const arr = ['a', 'b', 'c']\n hopp.expect(arr).to.have.ordered.members(['a', 'b', 'c'])\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "cmfhzf0op00typecoer01", - "name": "type-preservation-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// For CLI E2E testing: We only set simple string values in pre-request\n// Complex types will be tested within the test script itself\n\npm.environment.set('string_value', 'hello')\n", - "testScript": "\n// ========================================\n// TYPE PRESERVATION TESTS (CLI Compatible)\n// ========================================\n\n// IMPORTANT NOTE: Type preservation works perfectly WITHIN script execution scope\n// Values persisted across request boundaries (pre-request → test) may be serialized\n// This is expected CLI behavior for environment persistence/display\n\n// Test values set from pre-request\npm.test('string values work across scripts', () => {\n pm.expect(pm.environment.get('string_value')).to.equal('hello')\n})\n\n// ========================================\n// TYPE PRESERVATION WITHIN SINGLE SCRIPT\n// (This is where type preservation really shines!)\n// ========================================\n\npm.test('numbers are preserved as numbers (same script)', () => {\n pm.environment.set('num', 42)\n const value = pm.environment.get('num')\n pm.expect(value).to.equal(42)\n pm.expect(typeof value).to.equal('number')\n})\n\npm.test('booleans are preserved as booleans (same script)', () => {\n pm.environment.set('bool_true', true)\n pm.environment.set('bool_false', false)\n pm.expect(pm.environment.get('bool_true')).to.equal(true)\n pm.expect(pm.environment.get('bool_false')).to.equal(false)\n pm.expect(typeof pm.environment.get('bool_true')).to.equal('boolean')\n})\n\npm.test('null is preserved as actual null (same script)', () => {\n pm.environment.set('null_val', null)\n const value = pm.environment.get('null_val')\n pm.expect(value).to.equal(null)\n pm.expect(value === null).to.be.true\n pm.expect(typeof value).to.equal('object')\n})\n\npm.test('undefined is preserved as actual undefined (same script)', () => {\n pm.environment.set('undef_val', undefined)\n const value = pm.environment.get('undef_val')\n pm.expect(value).to.equal(undefined)\n pm.expect(typeof value).to.equal('undefined')\n pm.expect(pm.environment.has('undef_val')).to.be.true\n})\n\npm.test('arrays are preserved with direct access', () => {\n pm.environment.set('arr', [1, 2, 3])\n const value = pm.environment.get('arr')\n\n pm.expect(Array.isArray(value)).to.be.true\n pm.expect(value.length).to.equal(3)\n pm.expect(value[0]).to.equal(1)\n pm.expect(value[2]).to.equal(3)\n})\n\npm.test('single-element arrays remain arrays', () => {\n pm.environment.set('single', [42])\n const value = pm.environment.get('single')\n\n pm.expect(Array.isArray(value)).to.be.true\n pm.expect(value.length).to.equal(1)\n pm.expect(value[0]).to.equal(42)\n})\n\npm.test('empty arrays are preserved', () => {\n pm.environment.set('empty_arr', [])\n const value = pm.environment.get('empty_arr')\n\n pm.expect(Array.isArray(value)).to.be.true\n pm.expect(value.length).to.equal(0)\n})\n\npm.test('string arrays preserve all elements', () => {\n pm.environment.set('str_arr', ['a', 'b', 'c'])\n const value = pm.environment.get('str_arr')\n\n pm.expect(Array.isArray(value)).to.be.true\n pm.expect(value).to.deep.equal(['a', 'b', 'c'])\n})\n\npm.test('objects are preserved with accessible properties', () => {\n pm.environment.set('obj', { key: 'value', num: 123 })\n const value = pm.environment.get('obj')\n\n pm.expect(typeof value).to.equal('object')\n pm.expect(value.key).to.equal('value')\n pm.expect(value.num).to.equal(123)\n})\n\npm.test('empty objects are preserved', () => {\n pm.environment.set('empty_obj', {})\n const value = pm.environment.get('empty_obj')\n\n pm.expect(typeof value).to.equal('object')\n pm.expect(Object.keys(value).length).to.equal(0)\n})\n\npm.test('nested objects preserve structure', () => {\n pm.environment.set('nested', { user: { name: 'John', id: 1 }, meta: { active: true } })\n const value = pm.environment.get('nested')\n\n pm.expect(value.user.name).to.equal('John')\n pm.expect(value.user.id).to.equal(1)\n pm.expect(value.meta.active).to.equal(true)\n})\n\npm.test('complex nested structures work', () => {\n const data = {\n users: [\n { id: 1, name: 'Alice', scores: [90, 85, 88] },\n { id: 2, name: 'Bob', scores: [75, 80, 82] }\n ],\n metadata: { count: 2, page: 1, filters: ['active', 'verified'] }\n }\n\n pm.environment.set('complex', data)\n const retrieved = pm.environment.get('complex')\n\n pm.expect(retrieved.users).to.be.an('array')\n pm.expect(retrieved.users.length).to.equal(2)\n pm.expect(retrieved.users[0].name).to.equal('Alice')\n pm.expect(retrieved.users[0].scores[0]).to.equal(90)\n pm.expect(retrieved.metadata.filters).to.deep.equal(['active', 'verified'])\n})\n\n// ========================================\n// NAMESPACE SEPARATION\n// ========================================\n\npm.test('hopp.env.set rejects non-string values', () => {\n let errorCount = 0\n\n try { hopp.env.set('test', undefined) } catch (e) { errorCount++ }\n try { hopp.env.set('test', null) } catch (e) { errorCount++ }\n try { hopp.env.set('test', 42) } catch (e) { errorCount++ }\n try { hopp.env.set('test', true) } catch (e) { errorCount++ }\n try { hopp.env.set('test', [1, 2]) } catch (e) { errorCount++ }\n try { hopp.env.set('test', {}) } catch (e) { errorCount++ }\n\n pm.expect(errorCount).to.equal(6)\n})\n\npm.test('hopp.env.set only accepts strings', () => {\n hopp.env.set('hopp_str', 'valid')\n pm.expect(hopp.env.get('hopp_str')).to.equal('valid')\n})\n\npm.test('pm/hopp cross-namespace reading works', () => {\n pm.environment.set('cross_test', [1, 2, 3])\n\n // hopp can read PM-set values\n const fromHopp = hopp.env.get('cross_test')\n pm.expect(Array.isArray(fromHopp)).to.be.true\n pm.expect(fromHopp.length).to.equal(3)\n})\n\n// ========================================\n// PRACTICAL USE CASES\n// ========================================\n\npm.test('no JSON.parse needed for response data storage', () => {\n // Simulate storing parsed response data\n const responseData = {\n id: 123,\n name: 'Test User',\n permissions: ['read', 'write'],\n settings: { theme: 'dark', notifications: true }\n }\n\n pm.environment.set('user_data', responseData)\n const stored = pm.environment.get('user_data')\n\n // Direct access - no JSON.parse needed!\n pm.expect(stored.id).to.equal(123)\n pm.expect(stored.permissions).to.include('write')\n pm.expect(stored.settings.theme).to.equal('dark')\n})\n\npm.test('array iteration works directly', () => {\n pm.environment.set('items', ['apple', 'banana', 'cherry'])\n const items = pm.environment.get('items')\n\n let concatenated = ''\n items.forEach(item => {\n concatenated += item\n })\n\n pm.expect(concatenated).to.equal('applebananacherry')\n pm.expect(items.map(i => i.toUpperCase())).to.deep.equal(['APPLE', 'BANANA', 'CHERRY'])\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "type_preservation_ui_compat", - "name": "type-preservation-ui-compatibility-test", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Type preservation tests run in test script scope", - "testScript": "\n// ====== Type Preservation & UI Compatibility Tests ======\n// NOTE: Testing in same script scope (CLI limitation: complex types\n// may not persist across pre-request → test boundary)\n\npm.test('PM namespace preserves array types (not String coercion)', () => {\n pm.environment.set('simpleArray', [1, 2, 3])\n const arr = pm.environment.get('simpleArray')\n\n // CRITICAL: Should be actual array, not string \"1,2,3\"\n pm.expect(Array.isArray(arr)).to.equal(true)\n pm.expect(arr).to.have.lengthOf(3)\n pm.expect(arr[0]).to.equal(1)\n pm.expect(arr[1]).to.equal(2)\n pm.expect(arr[2]).to.equal(3)\n})\n\npm.test('PM namespace preserves object types (not \"[object Object]\")', () => {\n pm.environment.set('simpleObject', { foo: 'bar', num: 42 })\n const obj = pm.environment.get('simpleObject')\n\n // CRITICAL: Should be actual object, not string \"[object Object]\"\n pm.expect(typeof obj).to.equal('object')\n pm.expect(obj).to.not.be.null\n pm.expect(obj.foo).to.equal('bar')\n pm.expect(obj.num).to.equal(42)\n})\n\npm.test('PM namespace preserves null correctly', () => {\n pm.environment.set('nullValue', null)\n const val = pm.environment.get('nullValue')\n\n pm.expect(val).to.be.null\n})\n\npm.test('PM namespace preserves undefined correctly', () => {\n pm.environment.set('undefinedValue', undefined)\n const val = pm.environment.get('undefinedValue')\n\n pm.expect(val).to.be.undefined\n})\n\npm.test('PM namespace preserves primitives correctly', () => {\n pm.environment.set('stringValue', 'hello')\n pm.environment.set('numberValue', 123)\n pm.environment.set('booleanValue', true)\n\n pm.expect(pm.environment.get('stringValue')).to.equal('hello')\n pm.expect(pm.environment.get('numberValue')).to.equal(123)\n pm.expect(pm.environment.get('booleanValue')).to.equal(true)\n})\n\npm.test('PM namespace preserves nested structures', () => {\n pm.environment.set('nestedStructure', {\n users: [\n { id: 1, name: 'Alice' },\n { id: 2, name: 'Bob' }\n ],\n meta: { count: 2, tags: ['active', 'verified'] }\n })\n const nested = pm.environment.get('nestedStructure')\n\n pm.expect(nested).to.be.an('object')\n pm.expect(nested.users).to.be.an('array')\n pm.expect(nested.users).to.have.lengthOf(2)\n pm.expect(nested.users[0].name).to.equal('Alice')\n pm.expect(nested.users[1].name).to.equal('Bob')\n pm.expect(nested.meta.count).to.equal(2)\n pm.expect(nested.meta.tags).to.have.members(['active', 'verified'])\n})\n\npm.test('PM namespace handles mixed arrays (regression test for UI crash)', () => {\n pm.environment.set('mixedArray', [\n 'string',\n 42,\n true,\n null,\n undefined,\n [1, 2],\n { key: 'value' }\n ])\n const mixed = pm.environment.get('mixedArray')\n\n // This is the exact case that caused the UI crash\n pm.expect(Array.isArray(mixed)).to.equal(true)\n pm.expect(mixed).to.have.lengthOf(7)\n pm.expect(mixed[0]).to.equal('string')\n pm.expect(mixed[1]).to.equal(42)\n pm.expect(mixed[2]).to.equal(true)\n pm.expect(mixed[3]).to.be.null\n // mixed[4] is undefined in array, becomes null during JSON serialization\n pm.expect(Array.isArray(mixed[5])).to.equal(true)\n pm.expect(mixed[5]).to.have.lengthOf(2)\n pm.expect(typeof mixed[6]).to.equal('object')\n pm.expect(mixed[6].key).to.equal('value')\n})\n\npm.test('PM globals preserve arrays and objects', () => {\n pm.globals.set('globalArray', [10, 20, 30])\n pm.globals.set('globalObject', { env: 'prod', port: 8080 })\n\n const globalArr = pm.globals.get('globalArray')\n const globalObj = pm.globals.get('globalObject')\n\n pm.expect(Array.isArray(globalArr)).to.equal(true)\n pm.expect(globalArr).to.deep.equal([10, 20, 30])\n\n pm.expect(typeof globalObj).to.equal('object')\n pm.expect(globalObj.env).to.equal('prod')\n pm.expect(globalObj.port).to.equal(8080)\n})\n\npm.test('PM variables preserve arrays and objects', () => {\n pm.variables.set('varArray', [5, 10, 15])\n pm.variables.set('varObject', { status: 'active', count: 100 })\n\n const varArr = pm.variables.get('varArray')\n const varObj = pm.variables.get('varObject')\n\n pm.expect(Array.isArray(varArr)).to.equal(true)\n pm.expect(varArr).to.deep.equal([5, 10, 15])\n\n pm.expect(typeof varObj).to.equal('object')\n pm.expect(varObj.status).to.equal('active')\n pm.expect(varObj.count).to.equal(100)\n})\n\npm.test('Type preservation works with Postman compatibility', () => {\n pm.environment.set('testArr', [1, 2, 3])\n pm.environment.set('testObj', { foo: 'bar', num: 42 })\n\n const arr = pm.environment.get('testArr')\n const obj = pm.environment.get('testObj')\n\n // Should work like Postman: runtime types preserved\n pm.expect(arr.length).to.equal(3)\n pm.expect(obj.foo).to.equal('bar')\n\n // Verify no String() coercion happened\n pm.expect(arr).to.not.equal('1,2,3')\n pm.expect(obj).to.not.equal('[object Object]')\n})\n\npm.test('Type preservation: UI compatibility regression test', () => {\n // This test validates the fix for the reported bug:\n // \"TypeError: a.match is not a function at details.vue:387:10\"\n\n pm.environment.set('mixedTest', [\n 'string', 42, true, null, undefined, [1, 2], { key: 'value' }\n ])\n\n const mixed = pm.environment.get('mixedTest')\n\n // Should NOT throw any errors\n let errorCount = 0\n try {\n // Access all elements\n mixed.forEach(item => {\n // Should work with all types\n const type = typeof item\n const validTypes = ['string', 'number', 'boolean', 'object']\n if (!validTypes.includes(type)) {\n errorCount++\n }\n })\n } catch (e) {\n errorCount++\n }\n\n pm.expect(errorCount).to.equal(0)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": "application/json", - "body": "{\n \"test\": \"type preservation validation\"\n}" - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-get-basic", - "name": "hopp.fetch() - GET request basic", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/status/200", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should make successful GET request', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/status/200')\n hopp.expect(response.status).toBe(200)\n hopp.expect(response.ok).toBe(true)\n hopp.expect(response.statusText).toBeType('string')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-post-json", - "name": "hopp.fetch() - POST with JSON body", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should POST JSON data', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/post', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ test: 'data', number: 42 })\n })\n hopp.expect(response.status).toBe(200)\n hopp.expect(response.ok).toBe(true)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-404-error", - "name": "hopp.fetch() - 404 error handling", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should handle 404 errors', async () => {\n const response = await hopp.fetch('https://httpbin.org/status/404')\n // Fault-tolerant: Skip if httpbin is down (5xx)\n if (response.status >= 500 && response.status < 600) {\n console.log('httpbin.org is down (5xx), skipping assertions')\n return\n }\n hopp.expect(response.status).toBe(404)\n hopp.expect(response.ok).toBe(false)\n hopp.expect(response.statusText).toBeType('string')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-custom-headers", - "name": "hopp.fetch() - Custom headers", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should send custom headers', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io', {\n headers: {\n 'X-Custom-Header': 'test-value',\n 'X-Test-ID': '12345'\n }\n })\n hopp.expect(response.status).toBe(200)\n hopp.expect(response.headers).toBeType('object')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-env-url", - "name": "hopp.fetch() - Environment variable URL", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "hopp.env.set('API_BASE_URL', 'https://echo.hoppscotch.io')\nhopp.env.set('API_PATH', '/status/200')\n", - "testScript": "hopp.test('hopp.fetch() should work with environment variable URLs', async () => {\n const baseUrl = hopp.env.get('API_BASE_URL')\n const path = hopp.env.get('API_PATH')\n const fullUrl = baseUrl + path\n \n hopp.expect(fullUrl).toBe('https://echo.hoppscotch.io/status/200')\n \n const response = await hopp.fetch(fullUrl)\n hopp.expect(response.status).toBe(200)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-response-text", - "name": "hopp.fetch() - Response text parsing", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/status/200", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should parse response as text', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/status/200')\n const text = await response.text()\n hopp.expect(text).toBeType('string')\n hopp.expect(text.length > 0).toBe(true)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-http-methods", - "name": "hopp.fetch() - HTTP methods (PUT, DELETE, PATCH)", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should support PUT method', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/put', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ updated: true })\n })\n hopp.expect(response.status).toBe(200)\n})\n\nhopp.test('hopp.fetch() should support DELETE method', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/delete', {\n method: 'DELETE'\n })\n hopp.expect(response.status).toBe(200)\n})\n\nhopp.test('hopp.fetch() should support PATCH method', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/patch', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ patched: true })\n })\n hopp.expect(response.status).toBe(200)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-string-url", - "name": "pm.sendRequest() - String URL format", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should work with string URL', () => {\n pm.sendRequest('https://echo.hoppscotch.io/status/200', (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.equal(200)\n pm.expect(response.status).to.be.a('string')\n pm.expect(Array.isArray(response.headers)).to.be.true\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-request-object", - "name": "pm.sendRequest() - Request object format", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should work with request object', () => {\n pm.sendRequest({\n url: 'https://echo.hoppscotch.io/post',\n method: 'POST',\n header: [\n { key: 'Content-Type', value: 'application/json' },\n { key: 'X-Test-Header', value: 'test' }\n ],\n body: {\n mode: 'raw',\n raw: JSON.stringify({ name: 'test', value: 123 })\n }\n }, (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.equal(200)\n pm.expect(typeof response.body).to.equal('string')\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-urlencoded", - "name": "pm.sendRequest() - URL-encoded body", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should handle URL-encoded body', () => {\n pm.sendRequest({\n url: 'https://echo.hoppscotch.io/post',\n method: 'POST',\n body: {\n mode: 'urlencoded',\n urlencoded: [\n { key: 'username', value: 'testuser' },\n { key: 'password', value: 'secret123' },\n { key: 'remember', value: 'true' }\n ]\n }\n }, (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.equal(200)\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-response-format", - "name": "pm.sendRequest() - Response format validation", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() response should have Postman format', () => {\n pm.sendRequest('https://echo.hoppscotch.io/status/200', (error, response) => {\n pm.expect(error).to.be.null\n \n // Validate Postman response structure\n pm.expect(response).to.have.property('code')\n pm.expect(response).to.have.property('status')\n pm.expect(response).to.have.property('headers')\n pm.expect(response).to.have.property('body')\n pm.expect(response).to.have.property('json')\n \n // Validate types\n pm.expect(response.code).to.be.a('number')\n pm.expect(response.status).to.be.a('string')\n pm.expect(Array.isArray(response.headers)).to.be.true\n pm.expect(typeof response.body).to.equal('string')\n pm.expect(typeof response.json).to.equal('function')\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-error-codes", - "name": "pm.sendRequest() - HTTP error status codes", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should handle network errors gracefully', () => {\n pm.sendRequest('https://httpbin.org/status/500', (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.toBeLevel5xx()\n })\n})\n\npm.test('pm.sendRequest() should handle 404 error', () => {\n pm.sendRequest('https://httpbin.org/status/404', (error, response) => {\n pm.expect(error).to.be.null\n // Fault-tolerant: Skip if httpbin is down (5xx)\n if (response.code >= 500 && response.code < 600) {\n console.log('httpbin.org is down (5xx), skipping assertions')\n return\n }\n pm.expect(response.code).to.equal(404)\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-env-integration", - "name": "pm.sendRequest() - Environment variable integration", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "pm.environment.set('API_ENDPOINT', 'https://echo.hoppscotch.io')\npm.environment.set('AUTH_TOKEN', 'Bearer secret-token-123')\n", - "testScript": "pm.test('pm.sendRequest() should use environment variables', () => {\n const apiEndpoint = pm.environment.get('API_ENDPOINT')\n const authToken = pm.environment.get('AUTH_TOKEN')\n \n pm.sendRequest({\n url: apiEndpoint + '/status/200',\n method: 'GET',\n header: [\n { key: 'Authorization', value: authToken }\n ]\n }, (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.equal(200)\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-store-response", - "name": "pm.sendRequest() - Store response in environment", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should store response data in environment', () => {\n pm.sendRequest('https://echo.hoppscotch.io', (error, response) => {\n pm.expect(error).to.be.null\n \n // Store response data\n pm.environment.set('LAST_STATUS_CODE', response.code.toString())\n pm.environment.set('LAST_STATUS_TEXT', response.status)\n \n // Verify storage\n pm.expect(pm.environment.get('LAST_STATUS_CODE')).to.equal('200')\n pm.expect(pm.environment.get('LAST_STATUS_TEXT')).to.be.a('string')\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-rfc-object-headers", - "name": "pm.sendRequest() - RFC pattern with object headers", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "pm.environment.set('token', 'test-bearer-token-12345')\n", - "testScript": "pm.test('pm.sendRequest() should support RFC pattern with object headers', () => {\n const requestObject = {\n url: 'https://echo.hoppscotch.io/post',\n method: 'POST',\n header: {\n 'Content-Type': 'application/json',\n 'Authorization': 'Bearer ' + pm.environment.get('token')\n },\n body: {\n mode: 'raw',\n raw: JSON.stringify({ name: 'John Doe', action: 'create' })\n }\n }\n\n pm.sendRequest(requestObject, (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.equal(200)\n pm.expect(response.body).to.be.a('string')\n \n // Parse and validate response\n const jsonResponse = response.json()\n pm.expect(jsonResponse).to.be.an('object')\n pm.expect(jsonResponse.data).to.be.a('string')\n \n // Store user ID from response\n pm.environment.set('userId', 'user_' + response.code)\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-pm-interop", - "name": "hopp.fetch() and pm.sendRequest() - Interoperability", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "// Test that both hopp.fetch() and pm.sendRequest() work\nhopp.test('hopp.fetch() should work and store results', async () => {\n const fetchResponse = await hopp.fetch('https://echo.hoppscotch.io/status/200')\n hopp.expect(fetchResponse.status).toBe(200)\n \n // Store in environment\n hopp.env.set('FETCH_STATUS', fetchResponse.status.toString())\n \n // Verify it was stored\n const storedStatus = hopp.env.get('FETCH_STATUS')\n hopp.expect(storedStatus).toBe('200')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-json-parsing", - "name": "hopp.fetch() - JSON response parsing", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/status/200", - "params": [], - "headers": [ - { - "key": "Accept", - "value": "application/json", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should parse JSON response', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/status/200', {\n headers: { 'Accept': 'application/json' }\n })\n\n hopp.expect(response.status).toBe(200)\n\n const json = await response.json()\n hopp.expect(typeof json).toBe('object')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-headers-access", - "name": "hopp.fetch() - Response headers access", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/headers", - "params": [], - "headers": [ - { - "key": "X-Custom-Test", - "value": "test-value", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should access response headers', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/headers', {\n headers: { 'X-Custom-Test': 'test-value' }\n })\n\n hopp.expect(response.status).toBe(200)\n hopp.expect(response.headers).toBeType('object')\n\n const contentType = response.headers.get('content-type')\n if (contentType) {\n hopp.expect(typeof contentType).toBe('string')\n }\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-formdata", - "name": "pm.sendRequest() - FormData body mode", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io/post", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should handle FormData body', () => {\n pm.sendRequest({\n url: 'https://echo.hoppscotch.io/post',\n method: 'POST',\n body: {\n mode: 'formdata',\n formdata: [\n { key: 'field1', value: 'value1' },\n { key: 'field2', value: 'value2' },\n { key: 'username', value: 'testuser' }\n ]\n }\n }, (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.equal(200)\n pm.expect(typeof response.body).to.equal('string')\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-json-parsing", - "name": "pm.sendRequest() - JSON parsing method", - "method": "POST", - "endpoint": "https://echo.hoppscotch.io/post", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() response.json() should parse JSON', () => {\n pm.sendRequest({\n url: 'https://echo.hoppscotch.io/post',\n method: 'POST',\n header: [\n { key: 'Content-Type', value: 'application/json' }\n ],\n body: {\n mode: 'raw',\n raw: JSON.stringify({ test: 'data', number: 42 })\n }\n }, (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.equal(200)\n\n const data = response.json()\n pm.expect(data).to.be.an('object')\n pm.expect(data).to.not.be.null\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-headers-extraction", - "name": "pm.sendRequest() - Response headers extraction", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/headers", - "params": [], - "headers": [ - { - "key": "X-Test-Header", - "value": "test-123", - "active": true, - "description": "" - } - ], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should extract specific headers', () => {\n pm.sendRequest({\n url: 'https://echo.hoppscotch.io/headers',\n header: [\n { key: 'X-Test-Header', value: 'test-123' }\n ]\n }, (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.equal(200)\n pm.expect(Array.isArray(response.headers)).to.be.true\n\n const contentType = response.headers.find(h =>\n h.key.toLowerCase() === 'content-type'\n )\n pm.expect(contentType).to.exist\n pm.expect(contentType.value).to.be.a('string')\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-network-error", - "name": "hopp.fetch() - Network error handling", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/status/200", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should handle network errors', async () => {\n let errorCaught = false\n\n try {\n await hopp.fetch('https://this-domain-definitely-does-not-exist-12345.com')\n } catch (error) {\n errorCaught = true\n hopp.expect(error).toBeType('object')\n hopp.expect(error.message).toBeType('string')\n }\n\n hopp.expect(errorCaught).toBe(true)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-network-error", - "name": "pm.sendRequest() - Network error callback", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/status/200", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should trigger error callback on network failure', () => {\n pm.sendRequest('https://this-domain-definitely-does-not-exist-12345.com', (error, response) => {\n pm.expect(error).to.not.be.null\n pm.expect(error.message).to.be.a('string')\n pm.expect(response).to.be.null\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-sequential-requests", - "name": "hopp.fetch() - Sequential requests chain", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/status/200", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should chain multiple requests', async () => {\n const response1 = await hopp.fetch('https://echo.hoppscotch.io/status/200')\n hopp.expect(response1.status).toBe(200)\n\n hopp.env.set('CHAIN_STATUS', response1.status.toString())\n\n const firstStatus = hopp.env.get('CHAIN_STATUS')\n const response2 = await hopp.fetch(`https://echo.hoppscotch.io/status/${firstStatus}`, {\n headers: { 'X-Chain-Step': '2' }\n })\n hopp.expect(response2.status).toBe(200)\n\n const response3 = await hopp.fetch('https://echo.hoppscotch.io/headers', {\n headers: { 'X-Chain-Step': '3', 'X-Previous-Status': firstStatus }\n })\n hopp.expect(response3.status).toBe(200)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-nested", - "name": "pm.sendRequest() - Nested requests", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/status/200", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should support nested requests', () => {\n pm.sendRequest('https://echo.hoppscotch.io/status/200', (error1, response1) => {\n pm.expect(error1).to.be.null\n pm.expect(response1.code).to.equal(200)\n\n pm.environment.set('NESTED_STATUS', response1.code.toString())\n\n pm.sendRequest({\n url: 'https://echo.hoppscotch.io/headers',\n header: [\n { key: 'X-Parent-Status', value: pm.environment.get('NESTED_STATUS') }\n ]\n }, (error2, response2) => {\n pm.expect(error2).to.be.null\n pm.expect(response2.code).to.equal(200)\n })\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "fetch-binary-response", - "name": "hopp.fetch() - Binary response (arrayBuffer)", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io/bytes/100", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "hopp.test('hopp.fetch() should handle binary responses', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io/bytes/100')\n hopp.expect(response.status).toBe(200)\n\n const buffer = await response.arrayBuffer()\n hopp.expect(typeof buffer).toBe('object')\n const size = (buffer && typeof buffer.byteLength === 'number') ? buffer.byteLength : Object.keys(buffer || {}).length\n hopp.expect(size > 0).toBe(true)\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "pm-sendrequest-empty-response", - "name": "pm.sendRequest() - Empty response body (204)", - "method": "DELETE", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "pm.test('pm.sendRequest() should handle responses correctly', () => {\n pm.sendRequest({\n url: 'https://echo.hoppscotch.io',\n method: 'GET'\n }, (error, response) => {\n pm.expect(error).to.be.null\n pm.expect(response.code).to.satisfy(code => code >= 200 && code < 300)\n pm.expect(response.body).to.be.a('string')\n\n const jsonResult = response.json()\n pm.expect(jsonResult === null || typeof jsonResult === 'object').to.be.true\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "async_patterns_prereq", - "name": "Async Patterns - Pre-Request", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test 1: Top-level await (most common pattern)\nconst response1 = await hopp.fetch('https://echo.hoppscotch.io?test=toplevel-await')\nconst data1 = await response1.json()\nhopp.env.active.set('async_toplevel_status', response1.status.toString())\nhopp.env.active.set('async_toplevel_arg', data1.args.test)\n\n// Test 2: .then() chaining pattern\nhopp.fetch('https://echo.hoppscotch.io?test=then-chain')\n .then(response => {\n hopp.env.active.set('async_then_status', response.status.toString())\n return response.json()\n })\n .then(data => {\n hopp.env.active.set('async_then_arg', data.args.test)\n })\n\n// Test 3: Mixed pattern - await with .then()\nawait hopp.fetch('https://echo.hoppscotch.io?test=mixed')\n .then(async response => {\n hopp.env.active.set('async_mixed_status', response.status.toString())\n const data = await response.json()\n hopp.env.active.set('async_mixed_arg', data.args.test)\n })\n\n// Test 4: Promise.all with await\nconst [r1, r2] = await Promise.all([\n hopp.fetch('https://echo.hoppscotch.io?test=parallel1'),\n hopp.fetch('https://echo.hoppscotch.io?test=parallel2')\n])\nconst [d1, d2] = await Promise.all([r1.json(), r2.json()])\nhopp.env.active.set('async_parallel1', d1.args.test)\nhopp.env.active.set('async_parallel2', d2.args.test)\n", - "testScript": "hopp.test('Pre-request top-level await works', () => {\n hopp.expect(hopp.env.active.get('async_toplevel_status')).toBe('200')\n hopp.expect(hopp.env.active.get('async_toplevel_arg')).toBe('toplevel-await')\n})\n\nhopp.test('Pre-request .then() chain works', () => {\n hopp.expect(hopp.env.active.get('async_then_status')).toBe('200')\n hopp.expect(hopp.env.active.get('async_then_arg')).toBe('then-chain')\n})\n\nhopp.test('Pre-request mixed await/.then() works', () => {\n hopp.expect(hopp.env.active.get('async_mixed_status')).toBe('200')\n hopp.expect(hopp.env.active.get('async_mixed_arg')).toBe('mixed')\n})\n\nhopp.test('Pre-request Promise.all works', () => {\n hopp.expect(hopp.env.active.get('async_parallel1')).toBe('parallel1')\n hopp.expect(hopp.env.active.get('async_parallel2')).toBe('parallel2')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "async_patterns_test", - "name": "Async Patterns - Test Script", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Empty pre-request - all tests in test script\n", - "testScript": "// Test 1: Top-level await in test script\nconst response1 = await hopp.fetch('https://echo.hoppscotch.io?test=test-toplevel')\nconst data1 = await response1.json()\n\nhopp.test('Test script top-level await works', () => {\n hopp.expect(response1.status).toBe(200)\n hopp.expect(data1.args.test).toBe('test-toplevel')\n})\n\n// Test 2: await inside hopp.test callback\nhopp.test('Await inside test callback works', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io?test=inside-callback')\n hopp.expect(response.status).toBe(200)\n const data = await response.json()\n hopp.expect(data.args.test).toBe('inside-callback')\n})\n\n// Test 3: .then() inside test callback\nhopp.test('.then() inside test callback works', () => {\n return hopp.fetch('https://echo.hoppscotch.io?test=then-callback')\n .then(response => {\n hopp.expect(response.status).toBe(200)\n return response.json()\n })\n .then(data => {\n hopp.expect(data.args.test).toBe('then-callback')\n })\n})\n\n// Test 4: Mixed pattern in test\nhopp.test('Mixed pattern in test works', async () => {\n await hopp.fetch('https://echo.hoppscotch.io?test=mixed-test')\n .then(response => response.json())\n .then(data => {\n hopp.expect(data.args.test).toBe('mixed-test')\n })\n})\n\n// Test 5: Promise.all in test callback\nhopp.test('Promise.all in test callback works', async () => {\n const responses = await Promise.all([\n hopp.fetch('https://echo.hoppscotch.io?id=1'),\n hopp.fetch('https://echo.hoppscotch.io?id=2')\n ])\n hopp.expect(responses[0].status).toBe(200)\n hopp.expect(responses[1].status).toBe(200)\n const dataArray = await Promise.all(responses.map(r => r.json()))\n hopp.expect(dataArray[0].args.id).toBe('1')\n hopp.expect(dataArray[1].args.id).toBe('2')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "workflow_patterns", - "name": "Workflow Patterns (Sequential, Parallel, Auth)", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test 1: Sequential requests with .then chaining\nhopp.fetch('https://echo.hoppscotch.io?step=1')\n .then(r => r.json())\n .then(d1 => {\n hopp.env.active.set('seq_step1', d1.args.step)\n return hopp.fetch(`https://echo.hoppscotch.io?step=2&prev=${d1.args.step}`)\n })\n .then(r => r.json())\n .then(d2 => {\n hopp.env.active.set('seq_step2', d2.args.step)\n hopp.env.active.set('seq_prev', d2.args.prev)\n })\n\n// Test 2: Parallel with Promise.all and mixed patterns\nconst parallelPromises = [\n hopp.fetch('https://echo.hoppscotch.io?id=1').then(r => r.json()),\n hopp.fetch('https://echo.hoppscotch.io?id=2').then(r => r.json()),\n hopp.fetch('https://echo.hoppscotch.io?id=3').then(r => r.json())\n]\n\nawait Promise.all(parallelPromises).then(results => {\n hopp.env.active.set('parallel_id1', results[0].args.id)\n hopp.env.active.set('parallel_id2', results[1].args.id)\n hopp.env.active.set('parallel_id3', results[2].args.id)\n})\n\n// Test 3: Auth workflow\nconst authResp = await hopp.fetch('https://echo.hoppscotch.io?action=login&user=testuser')\nconst authData = await authResp.json()\nconst token = `${authData.args.action}_token_${authData.args.user}`\nhopp.env.active.set('workflow_token', token)\n\nconst dataResp = await hopp.fetch('https://echo.hoppscotch.io?action=fetch', {\n headers: { 'Authorization': `Bearer ${token}` }\n})\nconst data = await dataResp.json()\nhopp.env.active.set('workflow_auth_header', data.headers['authorization'])\n", - "testScript": "hopp.test('Sequential requests work', () => {\n hopp.expect(hopp.env.active.get('seq_step1')).toBe('1')\n hopp.expect(hopp.env.active.get('seq_step2')).toBe('2')\n hopp.expect(hopp.env.active.get('seq_prev')).toBe('1')\n})\n\nhopp.test('Parallel requests work', () => {\n hopp.expect(hopp.env.active.get('parallel_id1')).toBe('1')\n hopp.expect(hopp.env.active.get('parallel_id2')).toBe('2')\n hopp.expect(hopp.env.active.get('parallel_id3')).toBe('3')\n})\n\nhopp.test('Auth workflow works', () => {\n const token = hopp.env.active.get('workflow_token')\n hopp.expect(token).toInclude('login_token_testuser')\n hopp.expect(hopp.env.active.get('workflow_auth_header')).toBe(`Bearer ${token}`)\n})\n\n// Test 4: Complex workflow in test with mixed async\nhopp.test('Complex workflow in test works', async () => {\n // First request with await\n const r1 = await hopp.fetch('https://echo.hoppscotch.io?workflow=start')\n const d1 = await r1.json()\n const workflowId = d1.args.workflow\n \n // Second request with .then chaining\n await hopp.fetch(`https://echo.hoppscotch.io?workflow=${workflowId}&step=2`)\n .then(r => r.json())\n .then(d => {\n hopp.expect(d.args.workflow).toBe('start')\n hopp.expect(d.args.step).toBe('2')\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "error_handling_combined", - "name": "Error Handling & Edge Cases", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test 1: Error handling with try/catch\nlet errorOccurred = false\ntry {\n const response = await hopp.fetch('https://echo.hoppscotch.io')\n if (!response.ok) {\n errorOccurred = true\n }\n hopp.env.active.set('fetch_success', 'true')\n} catch (error) {\n errorOccurred = true\n hopp.env.active.set('fetch_success', 'false')\n}\nhopp.env.active.set('error_occurred', errorOccurred.toString())\n\n// Test 2: Bearer token auth\nconst token = 'sample_bearer_token_abc123'\nconst authResp = await hopp.fetch('https://echo.hoppscotch.io', {\n headers: { 'Authorization': `Bearer ${token}` }\n})\nconst authData = await authResp.json()\nhopp.env.active.set('sent_auth_header', authData.headers['authorization'] || 'missing')\n\n// Test 3: Content negotiation headers\nconst contentResp = await hopp.fetch('https://echo.hoppscotch.io', {\n headers: {\n 'Accept': 'application/json, text/plain, */*',\n 'Accept-Language': 'en-US,en;q=0.9',\n 'Accept-Encoding': 'gzip, deflate, br'\n }\n})\nconst contentData = await contentResp.json()\nhopp.env.active.set('accept_header', contentData.headers['accept'] || 'missing')\n", - "testScript": "hopp.test('Error handling works', () => {\n hopp.expect(hopp.env.active.get('fetch_success')).toBe('true')\n hopp.expect(hopp.env.active.get('error_occurred')).toBe('false')\n})\n\nhopp.test('Bearer token auth works', () => {\n const token = 'sample_bearer_token_abc123'\n hopp.expect(hopp.env.active.get('sent_auth_header')).toBe(`Bearer ${token}`)\n})\n\nhopp.test('Content negotiation works', () => {\n hopp.expect(hopp.env.active.get('accept_header')).toInclude('application/json')\n})\n\n// Test error handling in test script with .then().catch()\nhopp.test('Error handling with .catch() works', () => {\n return hopp.fetch('https://echo.hoppscotch.io')\n .then(r => {\n hopp.expect(r.ok).toBe(true)\n return r.json()\n })\n .then(d => {\n hopp.expect(d.method).toBe('GET')\n })\n .catch(error => {\n hopp.expect(true).toBe(false) // Should not reach here\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "large_payload_formdata", - "name": "Large Payload & FormData", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test 1: Large JSON payload with .then pattern\nconst largePayload = {\n items: Array.from({ length: 100 }, (_, i) => ({\n id: i,\n name: `Item ${i}`,\n description: `Description for item ${i}`,\n metadata: {\n created: new Date().toISOString(),\n index: i,\n active: i % 2 === 0\n }\n }))\n}\n\nhopp.fetch('https://echo.hoppscotch.io', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(largePayload)\n}).then(r => r.json()).then(d => {\n const receivedData = JSON.parse(d.data)\n hopp.env.active.set('large_count', receivedData.items.length.toString())\n hopp.env.active.set('large_first_id', receivedData.items[0].id.toString())\n hopp.env.active.set('large_last_id', receivedData.items[99].id.toString())\n})\n\n// Test 2: FormData handling (if available)\ntry {\n if (typeof FormData !== 'undefined') {\n const formData = new FormData()\n formData.append('field1', 'value1')\n formData.append('field2', 'value2')\n const formResp = await hopp.fetch('https://echo.hoppscotch.io', {\n method: 'POST',\n body: formData\n })\n const formRespData = await formResp.json()\n hopp.env.active.set('formdata_status', formResp.status.toString())\n } else {\n hopp.env.active.set('formdata_status', 'skipped')\n }\n} catch (error) {\n hopp.env.active.set('formdata_status', 'error')\n}\n", - "testScript": "hopp.test('Large JSON payload works', () => {\n hopp.expect(hopp.env.active.get('large_count')).toBe('100')\n hopp.expect(hopp.env.active.get('large_first_id')).toBe('0')\n hopp.expect(hopp.env.active.get('large_last_id')).toBe('99')\n})\n\nhopp.test('FormData handling works', () => {\n const status = hopp.env.active.get('formdata_status')\n if (status === 'skipped') {\n hopp.expect(status).toBe('skipped')\n } else {\n hopp.expect(status).toBe('200')\n }\n})\n\n// Test large payload in test script with async/await\nhopp.test('Large payload in test script works', async () => {\n const payload = {\n data: Array.from({ length: 50 }, (_, i) => ({ index: i, value: `test_${i}` }))\n }\n const response = await hopp.fetch('https://echo.hoppscotch.io', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload)\n })\n const data = await response.json()\n const received = JSON.parse(data.data)\n hopp.expect(received.data.length).toBe(50)\n hopp.expect(received.data[0].index).toBe(0)\n hopp.expect(received.data[49].value).toBe('test_49')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "get_methods_combined", - "name": "GET Methods (Query, Headers, URL)", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test 1: Query parameters\nconst qResponse = await hopp.fetch('https://echo.hoppscotch.io?foo=bar&baz=qux&test=123')\nconst qData = await qResponse.json()\nhopp.env.active.set('query_foo', qData.args.foo || 'missing')\nhopp.env.active.set('query_baz', qData.args.baz || 'missing')\nhopp.env.active.set('query_test', qData.args.test || 'missing')\n\n// Test 2: Custom headers\nconst hResponse = await hopp.fetch('https://echo.hoppscotch.io', {\n headers: {\n 'X-Custom-Header': 'CustomValue123',\n 'X-API-Key': 'secret-key-456',\n 'User-Agent': 'HoppscotchTest/1.0'\n }\n})\nconst hData = await hResponse.json()\nhopp.env.active.set('custom_header', hData.headers['x-custom-header'] || 'missing')\nhopp.env.active.set('api_key_header', hData.headers['x-api-key'] || 'missing')\n\n// Test 3: URL object\nconst urlObj = new URL('https://echo.hoppscotch.io')\nurlObj.searchParams.append('url_test', 'url-object')\nurlObj.searchParams.append('value', '42')\nconst uResponse = await hopp.fetch(urlObj)\nconst uData = await uResponse.json()\nhopp.env.active.set('url_obj_test', uData.args.url_test)\nhopp.env.active.set('url_obj_value', uData.args.value)\n\n// Test 4: Special characters\nconst searchQuery = 'test & special = chars'\nconst encodedQuery = encodeURIComponent(searchQuery)\nconst sResponse = await hopp.fetch(`https://echo.hoppscotch.io?q=${encodedQuery}&other=value`)\nconst sData = await sResponse.json()\nhopp.env.active.set('special_chars_q', sData.args.q)\nhopp.env.active.set('special_chars_other', sData.args.other)\n", - "testScript": "hopp.test('Query parameters work', () => {\n hopp.expect(hopp.env.active.get('query_foo')).toBe('bar')\n hopp.expect(hopp.env.active.get('query_baz')).toBe('qux')\n hopp.expect(hopp.env.active.get('query_test')).toBe('123')\n})\n\nhopp.test('Custom headers work', () => {\n hopp.expect(hopp.env.active.get('custom_header')).toBe('CustomValue123')\n hopp.expect(hopp.env.active.get('api_key_header')).toBe('secret-key-456')\n})\n\nhopp.test('URL object works', () => {\n hopp.expect(hopp.env.active.get('url_obj_test')).toBe('url-object')\n hopp.expect(hopp.env.active.get('url_obj_value')).toBe('42')\n})\n\nhopp.test('Special characters in URL work', () => {\n hopp.expect(hopp.env.active.get('special_chars_q')).toBe('test & special = chars')\n hopp.expect(hopp.env.active.get('special_chars_other')).toBe('value')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "post_methods_combined", - "name": "POST Methods (JSON, URLEncoded, Binary)", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test 1: POST with JSON body (await pattern)\nconst jsonBody = {\n name: 'John Doe',\n email: 'john@example.com',\n age: 30,\n active: true\n}\n\nconst jsonResponse = await hopp.fetch('https://echo.hoppscotch.io', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(jsonBody)\n})\nconst jsonData = await jsonResponse.json()\nconst receivedJson = JSON.parse(jsonData.data)\nhopp.env.active.set('post_json_name', receivedJson.name)\nhopp.env.active.set('post_json_email', receivedJson.email)\n\n// Test 2: POST with URL-encoded body (.then pattern)\nconst params = new URLSearchParams()\nparams.append('username', 'testuser')\nparams.append('password', 'testpass123')\n\nhopp.fetch('https://echo.hoppscotch.io', {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: params.toString()\n}).then(response => response.json())\n .then(data => {\n hopp.env.active.set('urlencoded_data', data.data || 'missing')\n hopp.env.active.set('urlencoded_ct', data.headers['content-type'] || 'missing')\n })\n\n// Test 3: Binary POST\nconst binaryData = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x21]) // \"Hello!\"\nawait hopp.fetch('https://echo.hoppscotch.io', {\n method: 'POST',\n headers: { 'Content-Type': 'application/octet-stream' },\n body: binaryData\n}).then(r => r.json()).then(d => {\n hopp.env.active.set('binary_method', d.method)\n hopp.env.active.set('binary_ct', d.headers['content-type'] || 'missing')\n})\n\n// Test 4: Empty body POST\nconst emptyResponse = await hopp.fetch('https://echo.hoppscotch.io', {\n method: 'POST'\n})\nconst emptyData = await emptyResponse.json()\nhopp.env.active.set('empty_post_method', emptyData.method)\n", - "testScript": "hopp.test('POST JSON body works', () => {\n hopp.expect(hopp.env.active.get('post_json_name')).toBe('John Doe')\n hopp.expect(hopp.env.active.get('post_json_email')).toBe('john@example.com')\n})\n\nhopp.test('POST URL-encoded body works', () => {\n hopp.expect(hopp.env.active.get('urlencoded_data')).toInclude('username=testuser')\n hopp.expect(hopp.env.active.get('urlencoded_ct')).toInclude('application/x-www-form-urlencoded')\n})\n\nhopp.test('Binary POST works', () => {\n hopp.expect(hopp.env.active.get('binary_method')).toBe('POST')\n hopp.expect(hopp.env.active.get('binary_ct')).toInclude('application/octet-stream')\n})\n\nhopp.test('Empty body POST works', () => {\n hopp.expect(hopp.env.active.get('empty_post_method')).toBe('POST')\n})\n\n// Test 5: POST in test script with .then()\nhopp.test('POST in test script works', () => {\n return hopp.fetch('https://echo.hoppscotch.io', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ test: 'from-test-script' })\n }).then(r => r.json()).then(d => {\n const body = JSON.parse(d.data)\n hopp.expect(body.test).toBe('from-test-script')\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "http_methods_combined", - "name": "HTTP Methods (PUT, PATCH, DELETE)", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Test PUT with mixed async\nawait hopp.fetch('https://echo.hoppscotch.io', {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ id: 123, name: 'Updated' })\n}).then(r => r.json()).then(d => {\n hopp.env.active.set('put_method', d.method)\n})\n\n// Test PATCH with await\nconst patchResp = await hopp.fetch('https://echo.hoppscotch.io', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ field: 'updated' })\n})\nconst patchData = await patchResp.json()\nhopp.env.active.set('patch_method', patchData.method)\n\n// Test DELETE with .then\nhopp.fetch('https://echo.hoppscotch.io/resource/123', {\n method: 'DELETE'\n}).then(r => r.json()).then(d => {\n hopp.env.active.set('delete_method', d.method)\n hopp.env.active.set('delete_path', d.path || 'missing')\n})\n", - "testScript": "hopp.test('PUT method works', () => {\n hopp.expect(hopp.env.active.get('put_method')).toBe('PUT')\n})\n\nhopp.test('PATCH method works', () => {\n hopp.expect(hopp.env.active.get('patch_method')).toBe('PATCH')\n})\n\nhopp.test('DELETE method works', () => {\n hopp.expect(hopp.env.active.get('delete_method')).toBe('DELETE')\n hopp.expect(hopp.env.active.get('delete_path')).toInclude('/resource/123')\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "response_parsing_combined", - "name": "Response Parsing (Headers, Status, Body)", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "const response = await hopp.fetch('https://echo.hoppscotch.io')\n\n// Test headers access\nconst contentType = response.headers.get('content-type')\nlet headerCount = 0\nfor (const [key, value] of response.headers.entries()) {\n headerCount++\n}\n\nif (contentType) {\n hopp.env.active.set('has_content_type', (contentType !== null).toString())\n}\n\nhopp.env.active.set('header_count', headerCount.toString())\n\n// Test status properties\nhopp.env.active.set('resp_status', response.status.toString())\nhopp.env.active.set('resp_ok', response.ok.toString())\nhopp.env.active.set('resp_status_text', response.statusText || 'empty')\n\n// Test text parsing\nconst text = await response.text()\nhopp.env.active.set('text_length', text.length.toString())\nhopp.env.active.set('is_string', (typeof text === 'string').toString())\n", - "testScript": "hopp.test('Response headers accessible', () => {\n // Agent interceptor doesn't return content type\n const hasContentType = hopp.env.active.get('has_content_type')\n if (hasContentType) {\n hopp.expect(hopp.env.active.get('has_content_type')).toBe('true')\n }\n\n const headerCount = parseInt(hopp.env.active.get('header_count'))\n hopp.expect(headerCount > 0).toBe(true)\n})\n\nhopp.test('Response status properties work', () => {\n hopp.expect(hopp.env.active.get('resp_status')).toBe('200')\n hopp.expect(hopp.env.active.get('resp_ok')).toBe('true')\n})\n\nhopp.test('response.text() works', () => {\n const textLength = parseInt(hopp.env.active.get('text_length'))\n hopp.expect(textLength > 0).toBe(true)\n hopp.expect(hopp.env.active.get('is_string')).toBe('true')\n})\n\n// Test async parsing in test script\nhopp.test('Async response parsing in test works', async () => {\n const response = await hopp.fetch('https://echo.hoppscotch.io?test=parse')\n const data = await response.json()\n hopp.expect(data.args.test).toBe('parse')\n\n // Agent interceptor doesn't return content type\n const contentType = response.headers.get('content-type')\n if (contentType) {\n hopp.expect(contentType).toInclude('json')\n }\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "dynamic_url_construction", - "name": "Dynamic URL Construction", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Dynamic URL building with template literals and mixed async\nconst baseUrl = 'https://echo.hoppscotch.io'\nconst endpoint = '/api/users'\nconst params = {\n page: 1,\n limit: 10,\n sort: 'name',\n filter: 'active'\n}\n\nconst queryString = Object.entries(params)\n .map(([key, value]) => `${key}=${value}`)\n .join('&')\n\nconst fullUrl = `${baseUrl}${endpoint}?${queryString}`\n\nawait hopp.fetch(fullUrl)\n .then(r => r.json())\n .then(d => {\n hopp.env.active.set('dynamic_path', d.path || 'missing')\n hopp.env.active.set('param_page', d.args.page)\n hopp.env.active.set('param_limit', d.args.limit)\n hopp.env.active.set('param_sort', d.args.sort)\n })\n", - "testScript": "hopp.test('Dynamic URL construction works', () => {\n hopp.expect(hopp.env.active.get('dynamic_path')).toInclude('/api/users')\n hopp.expect(hopp.env.active.get('param_page')).toBe('1')\n hopp.expect(hopp.env.active.get('param_limit')).toBe('10')\n hopp.expect(hopp.env.active.get('param_sort')).toBe('name')\n})\n\n// Test dynamic URL in test script with .then\nhopp.test('Dynamic URL in test script works', () => {\n const base = 'https://echo.hoppscotch.io'\n const path = '/test/path'\n const query = '?key=value'\n \n return hopp.fetch(`${base}${path}${query}`)\n .then(r => r.json())\n .then(d => {\n hopp.expect(d.path).toInclude('/test/path')\n hopp.expect(d.args.key).toBe('value')\n })\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - }, - { - "v": "17", - "id": "crypto_module_test", - "name": "crypto-module-test", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "// Hoppscotch Sandbox Crypto Module Tests\n// NOTE: The sandbox crypto API accepts plain arrays instead of TypedArrays.\n// Results include both .length and .byteLength for compatibility.\n// @ts-expect-error comments suppress Monaco's Web Crypto type checking for inputs.\n\n// Test crypto.randomUUID()\nconst uuid = crypto.randomUUID()\npm.environment.set('test_uuid', uuid)\n\n// Test crypto.getRandomValues()\nconst randomBytes = new Array(16).fill(0)\n// @ts-expect-error - Sandbox accepts plain arrays, not just TypedArrays\ncrypto.getRandomValues(randomBytes)\npm.environment.set('random_bytes_length', randomBytes.length)\npm.environment.set('has_random_values', randomBytes.some(v => v !== 0))\n\n// Test crypto.subtle.digest() with SHA-256\nconst testData = [72, 101, 108, 108, 111] // 'Hello' as bytes\n// @ts-expect-error - Sandbox accepts plain arrays as data input\nconst hash = await crypto.subtle.digest('SHA-256', testData)\npm.environment.set('hash_length', hash.byteLength)\n\n// Test crypto.subtle.generateKey() and sign/verify with HMAC\nconst hmacKey = await crypto.subtle.generateKey(\n { name: 'HMAC', hash: 'SHA-256' },\n true,\n ['sign', 'verify']\n)\npm.environment.set('hmac_key_type', hmacKey.type)\n\n// @ts-expect-error - Sandbox accepts plain arrays as data input\nconst signature = await crypto.subtle.sign('HMAC', hmacKey, testData)\npm.environment.set('signature_length', signature.byteLength)\n\n// @ts-expect-error - Sandbox accepts plain arrays for signature and data\nconst isValid = await crypto.subtle.verify('HMAC', hmacKey, signature, testData)\npm.environment.set('signature_valid', isValid)\n\n// Test crypto.subtle.generateKey() with AES-GCM\nconst aesKey = await crypto.subtle.generateKey(\n { name: 'AES-GCM', length: 256 },\n true,\n ['encrypt', 'decrypt']\n)\npm.environment.set('aes_key_type', aesKey.type)\n\n// Test encrypt/decrypt with AES-GCM\nconst iv = new Array(12).fill(0).map((_, i) => i)\nconst plaintext = [83, 101, 99, 114, 101, 116] // 'Secret' as bytes\n\n// @ts-expect-error - Sandbox accepts plain arrays for iv and plaintext\nconst ciphertext = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv },\n aesKey,\n plaintext\n)\npm.environment.set('ciphertext_length', ciphertext.byteLength)\n\n// @ts-expect-error - Sandbox accepts plain arrays for iv and ciphertext\nconst decrypted = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: iv },\n aesKey,\n ciphertext\n)\n// Compare decrypted bytes to original plaintext\nlet decryptMatch = decrypted.length === plaintext.length\nif (decryptMatch) {\n for (let i = 0; i < plaintext.length; i++) {\n if (decrypted[i] !== plaintext[i]) { decryptMatch = false; break }\n }\n}\npm.environment.set('decrypted_matches', decryptMatch)\n\n// Test RSA-OAEP encryption/decryption\nconst rsaKeyPair = await crypto.subtle.generateKey(\n {\n name: 'RSA-OAEP',\n modulusLength: 2048,\n // @ts-expect-error - Sandbox accepts plain array for publicExponent\n publicExponent: [1, 0, 1],\n hash: 'SHA-256'\n },\n true,\n ['encrypt', 'decrypt']\n)\n\n// @ts-expect-error - Sandbox accepts plain arrays as data input\nconst rsaCiphertext = await crypto.subtle.encrypt(\n { name: 'RSA-OAEP' },\n rsaKeyPair.publicKey,\n testData\n)\npm.environment.set('rsa_ciphertext_length', rsaCiphertext.byteLength)\n\nconst rsaDecrypted = await crypto.subtle.decrypt(\n { name: 'RSA-OAEP' },\n rsaKeyPair.privateKey,\n rsaCiphertext\n)\n// Compare RSA decrypted bytes to original testData\nlet rsaMatch = rsaDecrypted.length === testData.length\nif (rsaMatch) {\n for (let i = 0; i < testData.length; i++) {\n if (rsaDecrypted[i] !== testData[i]) { rsaMatch = false; break }\n }\n}\npm.environment.set('rsa_decrypted_matches', rsaMatch)\n\n// Test PBKDF2 key derivation\n// @ts-expect-error - Sandbox accepts plain array as key data\nconst passwordKey = await crypto.subtle.importKey(\n 'raw',\n [112, 97, 115, 115, 119, 111, 114, 100], // 'password'\n { name: 'PBKDF2' },\n false,\n ['deriveKey']\n)\n\nconst derivedKey = await crypto.subtle.deriveKey(\n {\n name: 'PBKDF2',\n hash: 'SHA-256',\n // @ts-expect-error - Sandbox accepts plain array for salt\n salt: [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],\n iterations: 1000\n },\n passwordKey,\n { name: 'AES-GCM', length: 256 },\n true,\n ['encrypt', 'decrypt']\n)\npm.environment.set('pbkdf2_key_type', derivedKey.type)\n", - "testScript": "const getNum = (key) => {\n const v = pm.environment.get(key)\n return typeof v === 'number' ? v : parseInt(String(v), 10)\n}\n\nconst getBool = (key) => {\n const v = pm.environment.get(key)\n return String(v) === 'true'\n}\n\n// crypto.randomUUID() tests\npm.test('crypto.randomUUID() generates valid UUID v4 format', () => {\n const uuid = pm.environment.get('test_uuid')\n pm.expect(uuid).to.be.a('string')\n pm.expect(uuid.length).to.equal(36)\n \n // UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\n const uuidPattern = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i\n pm.expect(uuidPattern.test(uuid)).to.be.true\n})\n\n// crypto.getRandomValues() tests\npm.test('crypto.getRandomValues() fills array with random bytes', () => {\n pm.expect(getNum('random_bytes_length')).to.equal(16)\n pm.expect(getBool('has_random_values')).to.be.true\n})\n\n// crypto.subtle.digest() tests\npm.test('crypto.subtle.digest() produces SHA-256 hash', () => {\n pm.expect(getNum('hash_length')).to.equal(32) // SHA-256 = 32 bytes\n})\n\n// HMAC sign/verify tests\npm.test('crypto.subtle.generateKey() creates HMAC key', () => {\n pm.expect(pm.environment.get('hmac_key_type')).to.equal('secret')\n})\n\npm.test('crypto.subtle.sign() produces HMAC signature', () => {\n pm.expect(getNum('signature_length')).to.equal(32) // SHA-256 HMAC = 32 bytes\n})\n\npm.test('crypto.subtle.verify() validates HMAC signature', () => {\n pm.expect(getBool('signature_valid')).to.be.true\n})\n\n// AES-GCM encrypt/decrypt tests\npm.test('crypto.subtle.generateKey() creates AES-GCM key', () => {\n pm.expect(pm.environment.get('aes_key_type')).to.equal('secret')\n})\n\npm.test('crypto.subtle.encrypt() produces ciphertext', () => {\n pm.expect(getNum('ciphertext_length')).to.be.above(0)\n})\n\npm.test('crypto.subtle.decrypt() recovers original plaintext', () => {\n pm.expect(getBool('decrypted_matches')).to.be.true\n})\n\n// RSA-OAEP encrypt/decrypt tests\npm.test('crypto.subtle.encrypt() produces RSA ciphertext', () => {\n pm.expect(getNum('rsa_ciphertext_length')).to.be.above(0)\n})\n\npm.test('crypto.subtle.decrypt() recovers RSA plaintext', () => {\n pm.expect(getBool('rsa_decrypted_matches')).to.be.true\n})\n\n// PBKDF2 key derivation tests\npm.test('crypto.subtle.deriveKey() creates AES key from password', () => {\n pm.expect(pm.environment.get('pbkdf2_key_type')).to.equal('secret')\n})\n\n// Additional in-script crypto tests\npm.test('crypto.randomUUID() generates unique UUIDs', () => {\n const uuid1 = crypto.randomUUID()\n const uuid2 = crypto.randomUUID()\n pm.expect(uuid1).to.not.equal(uuid2)\n})\n\npm.test('crypto.getRandomValues() mutates array in place', () => {\n const arr = new Array(10).fill(0)\n // @ts-expect-error - Sandbox accepts plain arrays, not just TypedArrays\n const result = crypto.getRandomValues(arr)\n pm.expect(result).to.equal(arr)\n pm.expect(arr.some(v => v !== 0)).to.be.true\n})\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {}, - "description": null - } - ], - "auth": { - "authType": "none", - "authActive": true - }, - "headers": [], - "variables": [], - "description": null -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-coll.json deleted file mode 100644 index a79d5a23..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-coll.json +++ /dev/null @@ -1,143 +0,0 @@ -{ - "v": 2, - "name": "secret-envs-coll", - "folders": [], - "requests": [ - { - "v": "3", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-headers", - "method": "GET", - "params": [], - "headers": [ - { - "key": "Secret-Header-Key", - "value": "<>", - "active": true - } - ], - "requestVariables": [], - "endpoint": "<>/headers", - "testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n const secretHeaderValue = pw.env.get(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.get(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})", - "preRequestScript": "const secretHeaderValueFromPreReqScript = pw.env.get(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)" - }, - { - "v": "3", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "body": "{\n \"secretBodyKey\": \"<>\"\n}", - "contentType": "application/json" - }, - "name": "test-secret-body", - "method": "POST", - "params": [], - "headers": [], - "requestVariables": [], - "endpoint": "<>/post", - "testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n const secretBodyValue = pw.env.get(\"secretBodyValue\")\n pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n \n if (secretBodyValue) {\n pw.expect(JSON.parse(pw.response.body.data).secretBodyKey).toBe(secretBodyValue)\n }\n\n pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})", - "preRequestScript": "const secretBodyValueFromPreReqScript = pw.env.get(\"secretBodyValue\")\npw.env.set(\"secretBodyValueFromPreReqScript\", secretBodyValueFromPreReqScript)" - }, - { - "v": "3", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-query-params", - "method": "GET", - "params": [ - { - "key": "secretQueryParamKey", - "value": "<>", - "active": true - } - ], - "headers": [], - "requestVariables": [], - "endpoint": "<>", - "testScript": "pw.test(\"Successfully parses secret variable holding the query param value\", () => {\n const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n pw.expect(secretQueryParamValue).toBe(\"secret-query-param-value\")\n \n if (secretQueryParamValue) {\n pw.expect(pw.response.body.args.secretQueryParamKey).toBe(secretQueryParamValue)\n }\n\n pw.expect(pw.env.get(\"secretQueryParamValueFromPreReqScript\")).toBe(\"secret-query-param-value\")\n})", - "preRequestScript": "const secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)" - }, - { - "v": "3", - "auth": { - "authType": "basic", - "password": "<>", - "username": "<>", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-basic-auth", - "method": "GET", - "params": [], - "headers": [], - "requestVariables": [], - "endpoint": "<>/basic-auth/<>/<>", - "testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n // The endpoint at times results in a `502` bad gateway\n if (pw.response.status !== 200) {\n return\n }\n\n if (secretBasicAuthUsername && secretBasicAuthPassword) {\n const { authenticated, user } = pw.response.body\n pw.expect(authenticated).toBe(true)\n pw.expect(user).toBe(secretBasicAuthUsername)\n }\n});", - "preRequestScript": "" - }, - { - "v": "3", - "auth": { - "token": "<>", - "authType": "bearer", - "password": "testpassword", - "username": "testuser", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-bearer-auth", - "method": "GET", - "params": [], - "headers": [], - "requestVariables": [], - "endpoint": "<>/bearer", - "testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n const secretBearerToken = pw.env.get(\"secretBearerToken\")\n const preReqSecretBearerToken = pw.env.get(\"preReqSecretBearerToken\")\n\n pw.expect(secretBearerToken).toBe(\"test-token\")\n\n // Safeguard to prevent test failures due to the endpoint\n if (pw.response.status !== 200) {\n return\n }\n\n if (secretBearerToken) { \n pw.expect(pw.response.body.token).toBe(secretBearerToken)\n pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n }\n});", - "preRequestScript": "const secretBearerToken = pw.env.get(\"secretBearerToken\")\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)" - }, - { - "v": "3", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-fallback", - "method": "GET", - "params": [], - "headers": [], - "requestVariables": [], - "endpoint": "<>", - "testScript": "pw.test(\"Returns an empty string if the value for a secret environment variable is not found in the system environment\", () => {\n pw.expect(pw.env.get(\"nonExistentValueInSystemEnv\")).toBe(\"\")\n})", - "preRequestScript": "" - } - ], - "auth": { - "authType": "inherit", - "authActive": false - }, - "headers": [] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-persistence-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-persistence-coll.json deleted file mode 100644 index 1de038c5..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-persistence-coll.json +++ /dev/null @@ -1,149 +0,0 @@ -{ - "v": 2, - "name": "secret-envs-persistence-coll", - "folders": [], - "requests": [ - { - "v": "3", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-headers", - "method": "GET", - "params": [], - "requestVariables": [], - "headers": [ - { - "key": "Secret-Header-Key", - "value": "<>", - "active": true - } - ], - "endpoint": "<>", - "testScript": "pw.test(\"Successfully parses secret variable holding the header value\", () => {\n const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value\")\n})", - "preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)" - }, - { - "v": "3", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-headers-overrides", - "method": "GET", - "params": [], - "requestVariables": [], - "headers": [ - { - "key": "Secret-Header-Key", - "value": "<>", - "active": true - } - ], - "endpoint": "<>", - "testScript": "pw.test(\"Value set at the pre-request script takes precedence\", () => {\n const secretHeaderValue = pw.env.getResolve(\"secretHeaderValue\")\n pw.expect(secretHeaderValue).toBe(\"secret-header-value-overriden\")\n \n if (secretHeaderValue) {\n pw.expect(pw.response.body.headers[\"secret-header-key\"]).toBe(secretHeaderValue)\n }\n\n pw.expect(pw.env.getResolve(\"secretHeaderValueFromPreReqScript\")).toBe(\"secret-header-value-overriden\")\n})", - "preRequestScript": "pw.env.set(\"secretHeaderValue\", \"secret-header-value-overriden\")\n\nconst secretHeaderValueFromPreReqScript = pw.env.getResolve(\"secretHeaderValue\")\npw.env.set(\"secretHeaderValueFromPreReqScript\", secretHeaderValueFromPreReqScript)" - }, - { - "v": "3", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "body": "{\n \"secretBodyKey\": \"<>\"\n}", - "contentType": "application/json" - }, - "name": "test-secret-body", - "method": "POST", - "params": [], - "requestVariables": [], - "headers": [], - "endpoint": "<>/post", - "testScript": "pw.test(\"Successfully parses secret variable holding the request body value\", () => {\n const secretBodyValue = pw.env.get(\"secretBodyValue\")\n pw.expect(secretBodyValue).toBe(\"secret-body-value\")\n \n if (secretBodyValue) {\n pw.expect(JSON.parse(pw.response.body.data).secretBodyKey).toBe(secretBodyValue)\n }\n\n pw.expect(pw.env.get(\"secretBodyValueFromPreReqScript\")).toBe(\"secret-body-value\")\n})", - "preRequestScript": "const secretBodyValue = pw.env.get(\"secretBodyValue\")\n\nif (!secretBodyValue) { \n pw.env.set(\"secretBodyValue\", \"secret-body-value\")\n}\n\nconst secretBodyValueFromPreReqScript = pw.env.get(\"secretBodyValue\")\npw.env.set(\"secretBodyValueFromPreReqScript\", secretBodyValueFromPreReqScript)" - }, - { - "v": "3", - "auth": { - "authType": "none", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-query-params", - "method": "GET", - "params": [ - { - "key": "secretQueryParamKey", - "value": "<>", - "active": true - } - ], - "requestVariables": [], - "headers": [], - "endpoint": "<>", - "testScript": "pw.test(\"Successfully parses secret variable holding the query param value\", () => {\n const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n pw.expect(secretQueryParamValue).toBe(\"secret-query-param-value\")\n \n if (secretQueryParamValue) {\n pw.expect(pw.response.body.args.secretQueryParamKey).toBe(secretQueryParamValue)\n }\n\n pw.expect(pw.env.get(\"secretQueryParamValueFromPreReqScript\")).toBe(\"secret-query-param-value\")\n})", - "preRequestScript": "const secretQueryParamValue = pw.env.get(\"secretQueryParamValue\")\n\nif (!secretQueryParamValue) {\n pw.env.set(\"secretQueryParamValue\", \"secret-query-param-value\")\n}\n\nconst secretQueryParamValueFromPreReqScript = pw.env.get(\"secretQueryParamValue\")\npw.env.set(\"secretQueryParamValueFromPreReqScript\", secretQueryParamValueFromPreReqScript)" - }, - { - "v": "3", - "auth": { - "authType": "basic", - "password": "<>", - "username": "<>", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-basic-auth", - "method": "GET", - "params": [], - "requestVariables": [], - "headers": [], - "endpoint": "<>/basic-auth/<>/<>", - "testScript": "pw.test(\"Successfully parses secret variables holding basic auth credentials\", () => {\n\tconst secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n \tconst secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\n pw.expect(secretBasicAuthUsername).toBe(\"test-user\")\n pw.expect(secretBasicAuthPassword).toBe(\"test-pass\")\n\n // The endpoint at times results in a `502` bad gateway\n if (pw.response.status !== 200) {\n return\n }\n\n if (secretBasicAuthUsername && secretBasicAuthPassword) {\n const { authenticated, user } = pw.response.body\n pw.expect(authenticated).toBe(true)\n pw.expect(user).toBe(secretBasicAuthUsername)\n }\n});", - "preRequestScript": "let secretBasicAuthUsername = pw.env.get(\"secretBasicAuthUsername\")\n\nlet secretBasicAuthPassword = pw.env.get(\"secretBasicAuthPassword\")\n\nif (!secretBasicAuthUsername) {\n pw.env.set(\"secretBasicAuthUsername\", \"test-user\")\n}\n\nif (!secretBasicAuthPassword) {\n pw.env.set(\"secretBasicAuthPassword\", \"test-pass\")\n}" - }, - { - "v": "3", - "auth": { - "token": "<>", - "authType": "bearer", - "password": "testpassword", - "username": "testuser", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-secret-bearer-auth", - "method": "GET", - "params": [], - "requestVariables": [], - "headers": [], - "endpoint": "<>/bearer", - "testScript": "pw.test(\"Successfully parses secret variable holding the bearer token\", () => {\n const secretBearerToken = pw.env.resolve(\"<>\")\n const preReqSecretBearerToken = pw.env.resolve(\"<>\")\n\n pw.expect(secretBearerToken).toBe(\"test-token\")\n\n // Safeguard to prevent test failures due to the endpoint\n if (pw.response.status !== 200) {\n return\n }\n\n if (secretBearerToken) { \n pw.expect(pw.response.body.token).toBe(secretBearerToken)\n pw.expect(preReqSecretBearerToken).toBe(\"test-token\")\n }\n});", - "preRequestScript": "let secretBearerToken = pw.env.resolve(\"<>\")\n\nif (!secretBearerToken) {\n pw.env.set(\"secretBearerToken\", \"test-token\")\n secretBearerToken = pw.env.resolve(\"<>\")\n}\n\npw.env.set(\"preReqSecretBearerToken\", secretBearerToken)" - } - ], - "auth": { - "authType": "inherit", - "authActive": false - }, - "headers": [] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-persistence-scripting-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-persistence-scripting-coll.json deleted file mode 100644 index 6a103ed4..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/secret-envs-persistence-scripting-coll.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "v": 2, - "name": "secret-envs-persistence-scripting-req", - "folders": [], - "requests": [ - { - "v": "3", - "endpoint": "https://echo.hoppscotch.io/post", - "name": "req", - "params": [], - "headers": [ - { - "active": true, - "key": "Custom-Header", - "value": "<>" - } - ], - "method": "POST", - "auth": { "authType": "none", "authActive": true }, - "preRequestScript": "pw.env.set(\"preReqVarOne\", \"pre-req-value-one\")\n\npw.env.set(\"preReqVarTwo\", \"pre-req-value-two\")\n\npw.env.set(\"customHeaderValueFromSecretVar\", \"custom-header-secret-value\")\n\npw.env.set(\"customBodyValue\", \"custom-body-value\")", - "testScript": "pw.test(\"Secret environment value set from the pre-request script takes precedence\", () => {\n pw.expect(pw.env.get(\"preReqVarOne\")).toBe(\"pre-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the pre-request script\", () => {\n pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request headers that are set in pre-request script\", () => {\n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(\"custom-header-secret-value\")\n})\n\npw.test(\"Successfully resolves secret variable values referred in request body that are set in pre-request script\", () => {\n pw.expect(JSON.parse(pw.response.body.data).key).toBe(\"custom-body-value\")\n})\n\npw.test(\"Secret environment variable set from the post-request script takes precedence\", () => {\n pw.env.set(\"postReqVarOne\", \"post-req-value-one\")\n pw.expect(pw.env.get(\"postReqVarOne\")).toBe(\"post-req-value-one\")\n})\n\npw.test(\"Successfully sets initial value for the secret variable from the post-request script\", () => {\n pw.env.set(\"postReqVarTwo\", \"post-req-value-two\")\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(\"post-req-value-two\")\n})\n\npw.test(\"Successfully removes environment variables via the pw.env.unset method\", () => {\n pw.env.unset(\"preReqVarOne\")\n pw.env.unset(\"postReqVarTwo\")\n\n pw.expect(pw.env.get(\"preReqVarOne\")).toBe(undefined)\n pw.expect(pw.env.get(\"postReqVarTwo\")).toBe(undefined)\n})", - "body": { - "contentType": "application/json", - "body": "{\n \"key\": \"<>\"\n}" - }, - "requestVariables": [] - } - ], - "auth": { "authType": "inherit", "authActive": false }, - "headers": [] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/test-junit-report-export-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/test-junit-report-export-coll.json deleted file mode 100644 index 081f4f3d..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/test-junit-report-export-coll.json +++ /dev/null @@ -1,150 +0,0 @@ -{ - "v": 2, - "name": "test-junit-report-export", - "folders": [ - { - "v": 2, - "name": "assertions", - "folders": [], - "requests": [ - { - "v": "5", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "error", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "pw.test(\"`toBeLevelxxx()` error scenarios\", ()=> {\n pw.expect(\"foo\").toBeLevel2xx();\n pw.expect(\"foo\").not.toBeLevel2xx();\n});\n\npw.test(\"`toBeType()` error scenarios\", () => {\n pw.expect(2).toBeType(\"foo\")\n pw.expect(\"2\").toBeType(\"bar\")\n pw.expect(true).toBeType(\"baz\")\n pw.expect({}).toBeType(\"qux\")\n pw.expect(undefined).toBeType(\"quux\")\n \n pw.expect(2).not.toBeType(\"foo\")\n pw.expect(\"2\").not.toBeType(\"bar\")\n pw.expect(true).not.toBeType(\"baz\")\n pw.expect({}).not.toBeType(\"qux\")\n pw.expect(undefined).not.toBeType(\"quux\")\n})\n\npw.test(\"`toHaveLength()` error scenarios\", () => {\n pw.expect(5).toHaveLength(0)\n pw.expect(true).toHaveLength(0)\n\n pw.expect(5).not.toHaveLength(0)\n pw.expect(true).not.toHaveLength(0)\n\n pw.expect([1, 2, 3, 4]).toHaveLength(\"a\")\n\n pw.expect([1, 2, 3, 4]).not.toHaveLength(\"a\")\n})\n\npw.test(\"`toInclude() error scenarios`\", () => {\n pw.expect(5).not.toInclude(0)\n pw.expect(true).not.toInclude(0)\n\n pw.expect([1, 2, 3, 4]).not.toInclude(null)\n\n pw.expect([1, 2, 3, 4]).not.toInclude(undefined)\n})", - "preRequestScript": "", - "requestVariables": [] - }, - { - "v": "5", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "success", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "\n\n// Check status code is 200\npw.test(\"Status code is 200\", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\n// Check headers\npw.test(\"Check headers\", ()=> {\n pw.expect(pw.response.body.headers[\"accept\"]).toBe(\"application/json, text/plain, */*,image/webp\");\n pw.expect(pw.response.body.headers[\"host\"]).toBe(\"echo.hoppscotch.io\")\n pw.expect(pw.response.body.headers[\"custom-header\"]).toBe(undefined)\n});\n\n// Check status code is 2xx\npw.test(\"Status code is 2xx\", ()=> {\n pw.expect(pw.response.status).toBeLevel2xx();\n});", - "preRequestScript": "", - "requestVariables": [] - }, - { - "v": "5", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "failure", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "\n\n// Check status code is 200\npw.test(\"Simulating failure - Status code is 200\", ()=> {\n pw.expect(pw.response.status).not.toBe(200);\n});\n\n// Check JSON response property\npw.test(\"Simulating failure - Check headers\", ()=> {\n pw.expect(pw.response.body.headers[\"accept\"]).not.toBe(\"application/json, text/plain, */*\");\n pw.expect(pw.response.body.headers[\"host\"]).not.toBe(\"httpbin.org\")\n pw.expect(pw.response.body.headers[\"custom-header\"]).not.toBe(\"value\")\n});\n\n// Check status code is 2xx\npw.test(\"Simulating failure - Status code is 2xx\", ()=> {\n pw.expect(pw.response.status).not.toBeLevel2xx();\n});", - "preRequestScript": "", - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] - }, - { - "v": 2, - "name": "request-level-errors", - "folders": [], - "requests": [ - { - "v": "5", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "invalid-url", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "invalid-url", - "testScript": "pw.test(\"`toBeLevelxxx()` error scenarios\", ()=> {\n pw.expect(\"foo\").toBeLevel2xx();\n pw.expect(\"foo\").not.toBeLevel2xx();\n});\n\npw.test(\"`toBeType()` error scenarios\", () => {\n pw.expect(2).toBeType(\"foo\")\n pw.expect(\"2\").toBeType(\"bar\")\n pw.expect(true).toBeType(\"baz\")\n pw.expect({}).toBeType(\"qux\")\n pw.expect(undefined).toBeType(\"quux\")\n \n pw.expect(2).not.toBeType(\"foo\")\n pw.expect(\"2\").not.toBeType(\"bar\")\n pw.expect(true).not.toBeType(\"baz\")\n pw.expect({}).not.toBeType(\"qux\")\n pw.expect(undefined).not.toBeType(\"quux\")\n})\n\npw.test(\"`toHaveLength()` error scenarios\", () => {\n pw.expect(5).toHaveLength(0)\n pw.expect(true).toHaveLength(0)\n\n pw.expect(5).not.toHaveLength(0)\n pw.expect(true).not.toHaveLength(0)\n\n pw.expect([1, 2, 3, 4]).toHaveLength(\"a\")\n\n pw.expect([1, 2, 3, 4]).not.toHaveLength(\"a\")\n})\n\npw.test(\"`toInclude() error scenarios`\", () => {\n pw.expect(5).not.toInclude(0)\n pw.expect(true).not.toInclude(0)\n\n pw.expect([1, 2, 3, 4]).not.toInclude(null)\n\n pw.expect([1, 2, 3, 4]).not.toInclude(undefined)\n})", - "preRequestScript": "", - "requestVariables": [] - }, - { - "v": "5", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": null, - "contentType": null - }, - "name": "test-script-reference-error", - "method": "GET", - "params": [], - "headers": [], - "endpoint": "invalid-url", - "testScript": "pw.test(\"Reference error\", () => {\n pw.expect(status).toBe(200);\n})", - "preRequestScript": "", - "requestVariables": [] - }, - { - "v": "5", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "body": "{\n \"key\": \"<>\"\n}", - "contentType": "application/json" - }, - "name": "non-existent-env-var", - "method": "POST", - "params": [], - "headers": [], - "endpoint": "https://echo.hoppscotch.io", - "testScript": "pw.test(\"`toBeLevelxxx()` error scenarios\", ()=> {\n pw.expect(\"foo\").toBeLevel2xx();\n pw.expect(\"foo\").not.toBeLevel2xx();\n});\n\npw.test(\"`toBeType()` error scenarios\", () => {\n pw.expect(2).toBeType(\"foo\")\n pw.expect(\"2\").toBeType(\"bar\")\n pw.expect(true).toBeType(\"baz\")\n pw.expect({}).toBeType(\"qux\")\n pw.expect(undefined).toBeType(\"quux\")\n \n pw.expect(2).not.toBeType(\"foo\")\n pw.expect(\"2\").not.toBeType(\"bar\")\n pw.expect(true).not.toBeType(\"baz\")\n pw.expect({}).not.toBeType(\"qux\")\n pw.expect(undefined).not.toBeType(\"quux\")\n})\n\npw.test(\"`toHaveLength()` error scenarios\", () => {\n pw.expect(5).toHaveLength(0)\n pw.expect(true).toHaveLength(0)\n\n pw.expect(5).not.toHaveLength(0)\n pw.expect(true).not.toHaveLength(0)\n\n pw.expect([1, 2, 3, 4]).toHaveLength(\"a\")\n\n pw.expect([1, 2, 3, 4]).not.toHaveLength(\"a\")\n})\n\npw.test(\"`toInclude() error scenarios`\", () => {\n pw.expect(5).not.toInclude(0)\n pw.expect(true).not.toInclude(0)\n\n pw.expect([1, 2, 3, 4]).not.toInclude(null)\n\n pw.expect([1, 2, 3, 4]).not.toInclude(undefined)\n})", - "preRequestScript": "", - "requestVariables": [] - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] - } - ], - "requests": [], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/test-scripting-sandbox-modes-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/test-scripting-sandbox-modes-coll.json deleted file mode 100644 index 548b9cef..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/test-scripting-sandbox-modes-coll.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "v": 7, - "id": "cmb4vtsqh00nxwvqryk6jmnaz", - "name": "test-scripting-sandbox-modes", - "folders": [], - "requests": [ - { - "v": "12", - "name": "sample-req", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "const url = new URL('https://example.com/path?foo=bar');\nurl.searchParams.set('baz', 'qux');\nurl.toString(); // 'https://example.com/path?foo=bar&baz=qux'\n\nconsole.debug(url)\n\nconst encoder = new TextEncoder();\n\nconst text = \"Hello, world!\";\n\nconst encoded = encoder.encode(text);\nconsole.log(\"Encoded:\", encoded);\n\nconst decoder = new TextDecoder();\n\nconst decoded = decoder.decode(encoded);\nconsole.log(\"Decoded:\", decoded);\n\nsetTimeout(() => console.log(\"Hello after 1s\"), 1000);\n \nconst intervalId = setInterval(() => console.log(\"Every 500ms\"), 500);\n\nsetTimeout(() => clearInterval(intervalId), 2000);", - "testScript": "console.log(JSON.stringify(pw, null, 2))\n\n\npw.test(\"Sample assertion\", ()=> {\n pw.expect(pw.response.status).toBeLevel2xx()\n \tconsole.log(\"Status code received is \", pw.response.status)\n});\n\n", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "_ref_id": "coll_mb4vvacd_e015964c-b5c8-4b90-a564-4a8b62bc1631" -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/valid-mixed-versions-coll.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/valid-mixed-versions-coll.json deleted file mode 100644 index db7df38f..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/collections/valid-mixed-versions-coll.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "v": 8, - "id": "cmbgcmyly10yhdjet63hiorps", - "name": "Valid mixed versions collection", - "folders": [ - { - "v": 7, - "id": "cmbgnb4h100v613phgrz6vku9", - "name": "fold1", - "folders": [ - { - "v": 6, - "id": "cmbhux44609zs2triccmql79r", - "name": "fold2", - "folders": [ - { - "v": 5, - "id": "cmbhux6es09zv2triton3kzv4", - "name": "fold3", - "folders": [ - { - "v": 4, - "id": "cmbhux9vo0b2t13ph6dwapwh3", - "name": "fold4", - "folders": [], - "requests": [ - { - "v": "13", - "name": "req", - "method": "GET", - "endpoint": "https://echo.hoppscotch.io", - "params": [], - "headers": [], - "preRequestScript": "", - "testScript": "", - "auth": { - "authType": "inherit", - "authActive": true - }, - "body": { - "contentType": null, - "body": null - }, - "requestVariables": [], - "responses": {} - } - ], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "_ref_id": "coll_mbhuxoci_023b77eb-ed0c-4ec7-97ca-f46cf327cc54" - } - ], - "requests": [], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "_ref_id": "coll_mbhuxoci_d22767f4-fd0a-4264-a86a-ba4a87c009cb" - } - ], - "requests": [], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "_ref_id": "coll_mbhuxoci_0effd54f-8e08-441f-9b44-95d02ff1861e" - } - ], - "requests": [], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "_ref_id": "coll_mbhuxoci_d7eee2ab-a921-447f-931d-bdce8c715770" - } - ], - "requests": [], - "auth": { - "authType": "inherit", - "authActive": true - }, - "headers": [], - "variables": [], - "_ref_id": "coll_mbhuxoci_a8fc710e-04c1-489c-a183-7f16946a7225" -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/aws-signature-auth-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/aws-signature-auth-envs.json deleted file mode 100644 index 486e69c6..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/aws-signature-auth-envs.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "v": 2, - "id": "cm0dsn3v70004p4qk3l9b7sjm", - "name": "AWS Signature - environments", - "variables": [ - { - "key": "awsRegion", - "currentValue": "us-east-1", - "initialValue": "us-east-1", - "secret": false - }, - { - "key": "serviceName", - "currentValue": "s3", - "initialValue": "s3", - "secret": false - }, - { - "key": "accessKey", - "currentValue": "test-access-key", - "initialValue": "test-access-key", - "secret": true - }, - { - "key": "secretKey", - "currentValue": "", - "initialValue": "", - "secret": true - }, - { - "key": "url", - "currentValue": "https://echo.hoppscotch.io", - "initialValue": "https://echo.hoppscotch.io", - "secret": false - }, - { - "key": "serviceToken", - "currentValue": "", - "initialValue": "", - "secret": true - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/bulk-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/bulk-envs.json deleted file mode 100644 index 7c563382..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/bulk-envs.json +++ /dev/null @@ -1,32 +0,0 @@ -[ - { - "v": 0, - "name": "Env-I", - "variables": [ - { - "key": "firstName", - "value": "John" - }, - { - "key": "lastName", - "value": "Doe" - } - ] - }, - { - "v": 1, - "id": "2", - "name": "Env-II", - "variables": [ - { - "key": "baseUrl", - "value": "https://echo.hoppscotch.io", - "secret": false - }, - { - "key": "secretVar", - "secret": true - } - ] - } -] diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/digest-auth-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/digest-auth-envs.json deleted file mode 100644 index 63e13d5a..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/digest-auth-envs.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "v": 2, - "id": "cm0dsn3v70004p4qk3l9b7sjm", - "name": "Digest Auth - environments", - "variables": [ - { - "key": "username", - "currentValue": "", - "initialValue": "admin", - "secret": true - }, - { - "key": "password", - "currentValue": "", - "initialValue": "admin", - "secret": true - }, - { - "key": "url", - "currentValue": "", - "initialValue": "https://test.insightres.org/digest/", - "secret": false - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-flag-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-flag-envs.json deleted file mode 100644 index 9d05aa44..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-flag-envs.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "URL": "https://echo.hoppscotch.io", - "HOST": "echo.hoppscotch.io", - "BODY_VALUE": "body_value", - "BODY_KEY": "body_key" -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v0.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v0.json deleted file mode 100644 index 16b23285..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v0.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "env-v0", - "variables": [ - { - "key": "baseURL", - "value": "https://echo.hoppscotch.io" - } - ] -} \ No newline at end of file diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v1.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v1.json deleted file mode 100644 index c6f7c919..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v1.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "env-v1", - "variables": [ - { - "key": "baseURL", - "value": "https://echo.hoppscotch.io", - "secret": false - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v2.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v2.json deleted file mode 100644 index 1c170dbd..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/env-v2.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "id": "env-v2", - "v": 2, - "name": "env-v2", - "variables": [ - { - "key": "baseURL", - "initialValue": "https://echo.hoppscotch.io", - "currentValue": "https://echo.hoppscotch.io", - "secret": false - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/hawk-auth-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/hawk-auth-envs.json deleted file mode 100644 index 81ff74d6..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/hawk-auth-envs.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "v": 1, - "id": "cm0dsn3v70004p4qk3l9b7sjm", - "name": "HAWK Auth - environments", - "variables": [ - { - "key": "url", - "value": "https://postman-echo.com/auth/hawk" - }, - { - "key": "id", - "value": "dh37fgj492je" - }, - { - "key": "key", - "value": "werxhqb98rpaxn39848xrunpaw3489ruxnpa98w4rxn" - }, - { - "key": "algorithm", - "value": "sha256" - }, - { - "key": "user", - "value": "" - }, - { - "key": "nonce", - "value": "" - }, - { - "key": "ext", - "value": "" - }, - { - "key": "app", - "value": "" - }, - { - "key": "dlg", - "value": "" - }, - { - "key": "timestamp", - "value": "" - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/iteration-data-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/iteration-data-envs.json deleted file mode 100644 index bea63935..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/iteration-data-envs.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "v": 0, - "name": "Iteration data environments", - "variables": [ - { - "key": "URL", - "value": "https://httpbin.org/get" - }, - { - "key": "BODY_KEY", - "value": "overriden-body-key-at-environment" - }, - { - "key": "BODY_VALUE", - "value": "overriden-body-value-at-environment" - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/iteration-data-export.csv b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/iteration-data-export.csv deleted file mode 100644 index 5caf994e..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/iteration-data-export.csv +++ /dev/null @@ -1,4 +0,0 @@ -URL,BODY_KEY,BODY_VALUE -https://echo.hoppscotch.io/1,,body_value1 -https://echo.hoppscotch.io/2,,body_value2 -https://echo.hoppscotch.io/3,,body_value3 diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/jwt-auth-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/jwt-auth-envs.json deleted file mode 100644 index 768bea0c..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/jwt-auth-envs.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "v": 1, - "id": "cm0dsn3v70004p4qk3l9b7sjn", - "name": "JWT Auth - environments", - "variables": [ - { - "key": "url", - "value": "http://localhost:8888/auth/jwt" - }, - { - "key": "algorithm", - "value": "HS256" - }, - { - "key": "secret", - "value": "secret-1" - }, - { - "key": "privateKey", - "value": "" - }, - { - "key": "payload", - "value": "{\"user\":\"test\",\"role\":\"admin\"}" - }, - { - "key": "jwtHeaders", - "value": "{}" - }, - { - "key": "headerPrefix", - "value": "Bearer " - }, - { - "key": "paramName", - "value": "token" - }, - { - "key": "isSecretBase64Encoded", - "value": "false" - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/malformed-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/malformed-envs.json deleted file mode 100644 index 7d075252..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/malformed-envs.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "id": 123, - "v": "1", - "name": "secret-envs", - "values": [ - { - "key": "secretVar", - "secret": true - }, - { - "key": "regularVar", - "secret": false, - "value": "regular-variable" - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/req-body-env-vars-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/req-body-env-vars-envs.json deleted file mode 100644 index eb3b9084..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/req-body-env-vars-envs.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "v": 0, - "name": "Response body sample", - "variables": [ - { - "key": "firstName", - "value": "John" - }, - { - "key": "lastName", - "value": "Doe" - }, - { - "key": "id", - "value": "7" - }, - { - "key": "fullName", - "value": "<> <>" - }, - { - "key": "recursiveVarX", - "value": "<>" - }, - { - "key": "recursiveVarY", - "value": "<>" - }, - { - "key": "salutation", - "value": "Hello" - }, - { - "key": "greetText", - "value": "<> <>" - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/request-vars-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/request-vars-envs.json deleted file mode 100644 index ff96dced..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/request-vars-envs.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "v": 2, - "id": "cm00r7kpb0006mbd2nq1560w6", - "name": "Request variables alongside environment variables", - "variables": [ - { - "key": "url", - "initialValue": "https://echo.hoppscotch.io", - "currentValue": "https://echo.hoppscotch.io", - "secret": false - }, - { - "key": "secretBasicAuthPasswordEnvVar", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "secretBasicAuthUsernameEnvVar", - "initialValue": "username", - "currentValue": "", - "secret": true - }, - { - "key": "username", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "password", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "testHeaderValue", - "initialValue": "test-header-value", - "currentValue": "", - "secret": false - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-envs-persistence-scripting-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-envs-persistence-scripting-envs.json deleted file mode 100644 index e1411452..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-envs-persistence-scripting-envs.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "v": 2, - "id": "2", - "name": "secret-envs-persistence-scripting-envs", - "variables": [ - { - "key": "preReqVarOne", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "preReqVarTwo", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "postReqVarOne", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "preReqVarTwo", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "customHeaderValueFromSecretVar", - "initialValue": "", - "currentValue": "", - "secret": true - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-envs.json deleted file mode 100644 index 1c4ae820..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-envs.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "id": "2", - "v": 2, - "name": "secret-envs", - "variables": [ - { - "key": "secretBearerToken", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "secretBasicAuthUsername", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "secretBasicAuthPassword", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "secretQueryParamValue", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "secretBodyValue", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "secretHeaderValue", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "nonExistentValueInSystemEnv", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "echoHoppBaseURL", - "initialValue": "https://echo.hoppscotch.io", - "currentValue": "", - "secret": false - }, - { - "key": "httpbinBaseURL", - "initialValue": "https://httpbin.org", - "currentValue": "", - "secret": false - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-supplied-values-envs.json b/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-supplied-values-envs.json deleted file mode 100644 index 9c331bd9..00000000 --- a/packages/hoppscotch-cli/src/__tests__/e2e/fixtures/environments/secret-supplied-values-envs.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "v": 2, - "id": "2", - "name": "secret-values-envs", - "variables": [ - { - "key": "secretBearerToken", - "initialValue": "test-token", - "currentValue": "test-token", - "secret": true - }, - { - "key": "secretBasicAuthUsername", - "initialValue": "test-user", - "currentValue": "test-user", - "secret": true - }, - { - "key": "secretBasicAuthPassword", - "initialValue": "test-pass", - "currentValue": "test-pass", - "secret": true - }, - { - "key": "secretQueryParamValue", - "initialValue": "secret-query-param-value", - "currentValue": "secret-query-param-value", - "secret": true - }, - { - "key": "secretBodyValue", - "initialValue": "secret-body-value", - "currentValue": "secret-body-value", - "secret": true - }, - { - "key": "secretHeaderValue", - "initialValue": "secret-header-value", - "currentValue": "secret-header-value", - "secret": true - }, - { - "key": "nonExistentValueInSystemEnv", - "initialValue": "", - "currentValue": "", - "secret": true - }, - { - "key": "echoHoppBaseURL", - "initialValue": "https://echo.hoppscotch.io", - "currentValue": "https://echo.hoppscotch.io", - "secret": false - }, - { - "key": "httpbinBaseURL", - "initialValue": "https://httpbin.org", - "currentValue": "https://httpbin.org", - "secret": false - } - ] -} diff --git a/packages/hoppscotch-cli/src/__tests__/functions/checks/isHoppCLIError.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/checks/isHoppCLIError.spec.ts deleted file mode 100644 index a12d127c..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/checks/isHoppCLIError.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { isHoppCLIError } from "../../../utils/checks"; - -describe("isHoppCLIError", () => { - test("NULL error value.", () => { - expect(isHoppCLIError(null)).toBeFalsy(); - }); - - test("Non-existing code property.", () => { - expect(isHoppCLIError({ name: "name" })).toBeFalsy(); - }); - - test("Invalid code value.", () => { - expect(isHoppCLIError({ code: 2 })).toBeFalsy(); - }); - - test("Valid code value.", () => { - expect(isHoppCLIError({ code: "TEST_SCRIPT_ERROR" })).toBeTruthy(); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/checks/isHoppErrnoException.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/checks/isHoppErrnoException.spec.ts deleted file mode 100644 index 1c1716bb..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/checks/isHoppErrnoException.spec.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { isHoppErrnoException } from "../../../utils/checks"; - -describe("isHoppErrnoException", () => { - test("NULL exception value.", () => { - expect(isHoppErrnoException(null)).toBeFalsy(); - }); - - test("Non-existing name property.", () => { - expect(isHoppErrnoException({ what: "what" })).toBeFalsy(); - }); - - test("Invalid name value.", () => { - expect(isHoppErrnoException({ name: 3 })).toBeFalsy(); - }); - - test("Valid name value.", () => { - expect(isHoppErrnoException({ name: "name" })).toBeTruthy(); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/collection/collectionsRunner.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/collection/collectionsRunner.spec.ts deleted file mode 100644 index 4bdf1143..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/collection/collectionsRunner.spec.ts +++ /dev/null @@ -1,129 +0,0 @@ -import { collectionsRunner } from "../../../utils/collections"; -import { HoppRESTRequest } from "@hoppscotch/data"; -import axios, { AxiosResponse } from "axios"; - -import "@relmify/jest-fp-ts"; - -jest.mock("axios"); - -const SAMPLE_HOPP_REQUEST = { - v: "1", - name: "request", - method: "GET", - endpoint: "https://example.com", - params: [], - headers: [], - preRequestScript: "", - testScript: "", - auth: { - authActive: false, - authType: "none", - }, - body: { - contentType: null, - body: null, - }, -}; - -const SAMPLE_RESOLVED_RESPONSE = { - data: { body: 1 }, - status: 200, - statusText: "OK", - config: { - url: "https://example.com", - supported: true, - method: "GET", - }, - headers: [], -}; - -const SAMPLE_ENVS = { global: [], selected: [] }; - -describe("collectionsRunner", () => { - beforeEach(() => { - jest.clearAllMocks(); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - test("Empty HoppCollection.", () => { - return expect( - collectionsRunner({ collections: [], envs: SAMPLE_ENVS }) - ).resolves.toStrictEqual([]); - }); - - test("Empty requests and folders in collection.", () => { - return expect( - collectionsRunner({ - collections: [ - { - v: 1, - name: "name", - folders: [], - requests: [], - }, - ], - envs: SAMPLE_ENVS, - }) - ).resolves.toMatchObject([]); - }); - - test("Non-empty requests in collection.", () => { - (axios as unknown as jest.Mock).mockResolvedValue(SAMPLE_RESOLVED_RESPONSE); - - return expect( - collectionsRunner({ - collections: [ - { - v: 1, - name: "collection", - folders: [], - requests: [SAMPLE_HOPP_REQUEST], - }, - ], - envs: SAMPLE_ENVS, - }) - ).resolves.toMatchObject([ - { - path: "collection/request", - tests: [], - errors: [], - result: true, - }, - ]); - }); - - test("Non-empty folders in collection.", () => { - (axios as unknown as jest.Mock).mockResolvedValue(SAMPLE_RESOLVED_RESPONSE); - - return expect( - collectionsRunner({ - collections: [ - { - v: 1, - name: "collection", - folders: [ - { - v: 1, - name: "folder", - folders: [], - requests: [SAMPLE_HOPP_REQUEST], - }, - ], - requests: [], - }, - ], - envs: SAMPLE_ENVS, - }) - ).resolves.toMatchObject([ - { - path: "collection/folder/request", - tests: [], - errors: [], - result: true, - }, - ]); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/collection/collectionsRunnerResult.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/collection/collectionsRunnerResult.spec.ts deleted file mode 100644 index fdc9a549..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/collection/collectionsRunnerResult.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { collectionsRunnerResult } from "../../../utils/collections"; - -const FALSE_RESULT_REPORT = { - path: "some_path", - tests: [], - errors: [], - result: false, - duration: { test: 1, request: 1, preRequest: 1 }, -}; - -const TRUE_RESULT_REPORT = { - path: "some_path", - tests: [], - errors: [], - result: true, - duration: { test: 1, request: 1, preRequest: 1 }, -}; - -describe("collectionsRunnerResult", () => { - test("Empty request-report.", () => { - expect(collectionsRunnerResult([])).toBeTruthy(); - }); - - test("Atleast 1 false result in request-report.", () => { - expect( - collectionsRunnerResult([FALSE_RESULT_REPORT, TRUE_RESULT_REPORT]) - ).toBeFalsy(); - }); - - test("All true result(s) in request-report.", () => { - expect( - collectionsRunnerResult([TRUE_RESULT_REPORT, TRUE_RESULT_REPORT]) - ).toBeTruthy(); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/getters/getDurationInSeconds.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/getters/getDurationInSeconds.spec.ts deleted file mode 100644 index edeb52c7..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/getters/getDurationInSeconds.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { DEFAULT_DURATION_PRECISION } from "../../../utils/constants"; -import { getDurationInSeconds } from "../../../utils/getters"; - -describe("getDurationInSeconds", () => { - const testDurations = [ - { end: [1, 111111111], precision: 1, expected: 1.1 }, - { end: [2, 333333333], precision: 2, expected: 2.33 }, - { - end: [3, 555555555], - precision: DEFAULT_DURATION_PRECISION, - expected: 3.556, - }, - { end: [4, 777777777], precision: 4, expected: 4.7778 }, - ]; - - test.each(testDurations)( - "($end.0 s + $end.1 ns) rounded-off to $expected", - ({ end, precision, expected }) => { - expect(getDurationInSeconds(end as [number, number], precision)).toBe( - expected - ); - } - ); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/getters/getEffectiveFinalMetaData.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/getters/getEffectiveFinalMetaData.spec.ts deleted file mode 100644 index 2a55b79a..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/getters/getEffectiveFinalMetaData.spec.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Environment } from "@hoppscotch/data"; -import { getEffectiveFinalMetaData } from "../../../utils/getters"; - -import "@relmify/jest-fp-ts"; - -const DEFAULT_ENV = { - name: "name", - variables: [{ key: "PARAM", value: "parsed_param" }], -}; - -describe("getEffectiveFinalMetaData", () => { - test("Empty list of meta-data.", () => { - expect(getEffectiveFinalMetaData([], DEFAULT_ENV)).toSubsetEqualRight([]); - }); - - test("Non-empty active list of meta-data with unavailable ENV.", () => { - expect( - getEffectiveFinalMetaData( - [{ active: true, key: "<>", value: "<>" }], - DEFAULT_ENV - ) - ).toSubsetEqualRight([{ active: true, key: "", value: "" }]); - }); - - test("Inactive list of meta-data.", () => { - expect( - getEffectiveFinalMetaData( - [{ active: false, key: "KEY", value: "<>" }], - DEFAULT_ENV - ) - ).toSubsetEqualRight([]); - }); - - test("Active list of meta-data.", () => { - expect( - getEffectiveFinalMetaData( - [{ active: true, key: "PARAM", value: "<>" }], - DEFAULT_ENV - ) - ).toSubsetEqualRight([ - { active: true, key: "PARAM", value: "parsed_param" }, - ]); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/mutators/parseCollectionData.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/mutators/parseCollectionData.spec.ts deleted file mode 100644 index 86edb4b8..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/mutators/parseCollectionData.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { HoppCLIError } from "../../../types/errors"; -import { parseCollectionData } from "../../../utils/mutators"; - -describe("parseCollectionData", () => { - test("Reading non-existing file.", () => { - return expect( - parseCollectionData("./src/__tests__/samples/notexist.json") - ).rejects.toMatchObject({ - code: "FILE_NOT_FOUND", - }); - }); - - test("Unparseable JSON contents.", () => { - return expect( - parseCollectionData("./src/__tests__/samples/malformed-collection.json") - ).rejects.toMatchObject({ - code: "UNKNOWN_ERROR", - }); - }); - - test("Invalid HoppCollection.", () => { - return expect( - parseCollectionData("./src/__tests__/samples/malformed-collection2.json") - ).rejects.toMatchObject({ - code: "MALFORMED_COLLECTION", - }); - }); - - test("Valid HoppCollection.", () => { - return expect( - parseCollectionData("./src/__tests__/samples/passes.json") - ).resolves.toBeTruthy(); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/pre-request/getEffectiveRESTRequest.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/pre-request/getEffectiveRESTRequest.spec.ts deleted file mode 100644 index 1ab4e978..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/pre-request/getEffectiveRESTRequest.spec.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { Environment, HoppRESTRequest } from "@hoppscotch/data"; -import { EffectiveHoppRESTRequest } from "../../../interfaces/request"; -import { HoppCLIError } from "../../../types/errors"; -import { getEffectiveRESTRequest } from "../../../utils/pre-request"; - -import "@relmify/jest-fp-ts"; - -const DEFAULT_ENV = { - name: "name", - variables: [ - { - key: "HEADER", - value: "parsed_header", - }, - { key: "PARAM", value: "parsed_param" }, - { key: "TOKEN", value: "parsed_token" }, - { key: "BODY_PROP", value: "parsed_body_prop" }, - { key: "ENDPOINT", value: "https://parsed-endpoint.com" }, - ], -}; - -const DEFAULT_REQUEST = { - v: "1", - name: "name", - method: "GET", - endpoint: "https://example.com", - params: [], - headers: [], - preRequestScript: "", - testScript: "", - auth: { - authActive: false, - authType: "none", - }, - body: { - contentType: null, - body: null, - }, -}; - -describe("getEffectiveRESTRequest", () => { - let SAMPLE_REQUEST = Object.assign({}, DEFAULT_REQUEST); - - beforeEach(() => { - SAMPLE_REQUEST = Object.assign({}, DEFAULT_REQUEST); - }); - - test("Endpoint, headers and params with unavailable ENV.", () => { - SAMPLE_REQUEST.headers = [ - { - key: "HEADER", - value: "<>", - active: true, - }, - ]; - SAMPLE_REQUEST.params = [ - { - key: "PARAM", - value: "<>", - active: true, - }, - ]; - SAMPLE_REQUEST.endpoint = "<>"; - - expect( - getEffectiveRESTRequest(SAMPLE_REQUEST, DEFAULT_ENV) - ).toSubsetEqualRight({ - effectiveFinalHeaders: [{ active: true, key: "HEADER", value: "" }], - effectiveFinalParams: [{ active: true, key: "PARAM", value: "" }], - effectiveFinalURL: "", - }); - }); - - test("Auth with unavailable ENV.", () => { - SAMPLE_REQUEST.auth = { - authActive: true, - authType: "bearer", - token: "<>", - }; - - expect( - getEffectiveRESTRequest(SAMPLE_REQUEST, DEFAULT_ENV) - ).toSubsetEqualRight({ - effectiveFinalHeaders: [ - { active: true, key: "Authorization", value: "Bearer " }, - ], - }); - }); - - test("Body with unavailable ENV.", () => { - SAMPLE_REQUEST.body = { - contentType: "text/plain", - body: "<>", - }; - - expect( - getEffectiveRESTRequest(SAMPLE_REQUEST, DEFAULT_ENV) - ).toSubsetEqualLeft({ - code: "PARSING_ERROR", - }); - }); - - test("Request meta-data with available ENVs.", () => { - SAMPLE_REQUEST.headers = [ - { - key: "HEADER", - value: "<
>", - active: true, - }, - ]; - SAMPLE_REQUEST.params = [ - { - key: "PARAM", - value: "<>", - active: true, - }, - ]; - SAMPLE_REQUEST.endpoint = "<>"; - SAMPLE_REQUEST.auth = { - authActive: true, - authType: "bearer", - token: "<>", - }; - SAMPLE_REQUEST.body = { - contentType: "text/plain", - body: "<>", - }; - - const vars = DEFAULT_ENV.variables; - - expect( - getEffectiveRESTRequest(SAMPLE_REQUEST, DEFAULT_ENV) - ).toSubsetEqualRight({ - effectiveFinalHeaders: [ - { active: true, key: "HEADER", value: vars[0].value }, - { - active: true, - key: "Authorization", - value: `Bearer ${vars[2].value}`, - }, - { active: true, key: "content-type", value: "text/plain" }, - ], - effectiveFinalParams: [ - { active: true, key: "PARAM", value: vars[1].value }, - ], - effectiveFinalURL: vars[4].value, - effectiveFinalBody: vars[3].value, - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/pre-request/getPreRequestMetrics.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/pre-request/getPreRequestMetrics.spec.ts deleted file mode 100644 index 2f28bd06..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/pre-request/getPreRequestMetrics.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { PreRequestMetrics, RequestMetrics } from "../../../types/response"; -import { getPreRequestMetrics } from "../../../utils/pre-request"; - -describe("getPreRequestMetrics", () => { - test("With empty errors.", () => { - expect(getPreRequestMetrics([], 1)).toMatchObject({ - scripts: { failed: 0, passed: 1 }, - }); - }); - - test("With non-empty errors.", () => { - expect( - getPreRequestMetrics( - [ - { code: "REQUEST_ERROR", data: {} }, - { code: "PRE_REQUEST_SCRIPT_ERROR", data: {} }, - ], - 1 - ) - ).toMatchObject({ - scripts: { failed: 1, passed: 0 }, - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/pre-request/preRequestScriptRunner.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/pre-request/preRequestScriptRunner.spec.ts deleted file mode 100644 index f382f7f4..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/pre-request/preRequestScriptRunner.spec.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { HoppRESTRequest } from "@hoppscotch/data"; -import { HoppEnvs } from "../../../types/request"; -import * as E from "fp-ts/Either"; -import { HoppCLIError } from "../../../types/errors"; -import { EffectiveHoppRESTRequest } from "../../../interfaces/request"; -import { preRequestScriptRunner } from "../../../utils/pre-request"; - -import "@relmify/jest-fp-ts"; - -const SAMPLE_ENVS: HoppEnvs = { - global: [], - selected: [], -}; -const VALID_PRE_REQUEST_SCRIPT = ` - pw.env.set("ENDPOINT","https://example.com"); -`; -const INVALID_PRE_REQUEST_SCRIPT = "d"; -const SAMPLE_REQUEST: HoppRESTRequest = { - v: "1", - name: "request", - method: "GET", - endpoint: "<>", - params: [], - headers: [], - preRequestScript: "", - testScript: "", - auth: { authActive: false, authType: "none" }, - body: { - contentType: null, - body: null, - }, -}; - -describe("preRequestScriptRunner", () => { - let SUCCESS_PRE_REQUEST_RUNNER: E.Either< - HoppCLIError, - EffectiveHoppRESTRequest - >, - FAILURE_PRE_REQUEST_RUNNER: E.Either< - HoppCLIError, - EffectiveHoppRESTRequest - >; - - beforeAll(async () => { - SAMPLE_REQUEST.preRequestScript = VALID_PRE_REQUEST_SCRIPT; - SUCCESS_PRE_REQUEST_RUNNER = await preRequestScriptRunner( - SAMPLE_REQUEST, - SAMPLE_ENVS - )(); - - SAMPLE_REQUEST.preRequestScript = INVALID_PRE_REQUEST_SCRIPT; - FAILURE_PRE_REQUEST_RUNNER = await preRequestScriptRunner( - SAMPLE_REQUEST, - SAMPLE_ENVS - )(); - }); - - test("Parsing of request endpoint with set ENV.", () => { - expect(SUCCESS_PRE_REQUEST_RUNNER).toSubsetEqualRight(< - EffectiveHoppRESTRequest - >{ - effectiveFinalURL: "https://example.com", - }); - }); - - test("Failed execution due to unknown variable error.", () => { - expect(FAILURE_PRE_REQUEST_RUNNER).toSubsetEqualLeft({ - code: "PRE_REQUEST_SCRIPT_ERROR", - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/request/delayPromiseFunction.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/request/delayPromiseFunction.spec.ts deleted file mode 100644 index 5f6dd849..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/request/delayPromiseFunction.spec.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { hrtime } from "process"; -import { getDurationInSeconds } from "../../../utils/getters"; -import { delayPromiseFunction } from "../../../utils/request"; - -describe("describePromiseFunction", () => { - let promiseFunc = (): Promise => new Promise((resolve) => resolve(2)); - beforeEach(() => { - promiseFunc = (): Promise => new Promise((resolve) => resolve(2)); - }); - - it("Should resolve the promise after 2 seconds.", async () => { - const start = hrtime(); - const res = await delayPromiseFunction(promiseFunc, 2000); - const end = hrtime(start); - const duration = getDurationInSeconds(end); - - expect(Math.floor(duration)).toEqual(2); - expect(typeof res).toBe("number"); - }); - - it("Should resolve the promise after 4 seconds.", async () => { - const start = hrtime(); - const res = await delayPromiseFunction(promiseFunc, 4000); - const end = hrtime(start); - const duration = getDurationInSeconds(end); - - expect(Math.floor(duration)).toEqual(4); - expect(typeof res).toBe("number"); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/request/getRequestMetrics.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/request/getRequestMetrics.spec.ts deleted file mode 100644 index 98c53423..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/request/getRequestMetrics.spec.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { RequestMetrics } from "../../../types/response"; -import { getRequestMetrics } from "../../../utils/request"; - -describe("getRequestMetrics", () => { - test("With empty errors.", () => { - expect(getRequestMetrics([], 1)).toMatchObject({ - requests: { failed: 0, passed: 1 }, - }); - }); - - test("With non-empty errors.", () => { - expect( - getRequestMetrics( - [ - { code: "REQUEST_ERROR", data: {} }, - { code: "PARSING_ERROR", data: {} }, - ], - 1 - ) - ).toMatchObject({ - requests: { failed: 1, passed: 0 }, - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/request/processRequest.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/request/processRequest.spec.ts deleted file mode 100644 index b2c9027a..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/request/processRequest.spec.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { HoppRESTRequest } from "@hoppscotch/data"; -import axios, { AxiosResponse } from "axios"; -import { processRequest } from "../../../utils/request"; -import { HoppEnvs } from "../../../types/request"; - -import "@relmify/jest-fp-ts"; - -jest.mock("axios"); - -const DEFAULT_REQUEST = { - v: "1", - name: "name", - method: "POST", - endpoint: "https://example.com", - params: [], - headers: [], - preRequestScript: "", - testScript: "", - auth: { - authType: "none", - authActive: false, - }, - body: { - contentType: null, - body: null, - }, -}; - -const DEFAULT_RESPONSE = { - data: {}, - status: 200, - config: { - url: "https://example.com", - supported: true, - method: "POST", - }, - statusText: "OK", - headers: [], -}; - -const DEFAULT_ENVS = { - global: [], - selected: [], -}; - -describe("processRequest", () => { - let SAMPLE_REQUEST = DEFAULT_REQUEST; - - beforeEach(() => { - jest.clearAllMocks(); - }); - - afterEach(() => { - SAMPLE_REQUEST = DEFAULT_REQUEST; - }); - - test("With empty envs for 'true' result.", () => { - (axios as unknown as jest.Mock).mockResolvedValue(DEFAULT_RESPONSE); - - return expect( - processRequest({ - request: SAMPLE_REQUEST, - envs: DEFAULT_ENVS, - path: "fake/collection/path", - delay: 0, - })() - ).resolves.toMatchObject({ - report: { - result: true, - }, - }); - }); - - test("With non-empty envs, pre-request-script and test-script.", () => { - SAMPLE_REQUEST.preRequestScript = ` - pw.env.set("ENDPOINT", "https://example.com"); - `; - SAMPLE_REQUEST.testScript = ` - pw.test("check status.", () => { - pw.expect(pw.response.status).toBe(200); - }); - `; - - (axios as unknown as jest.Mock).mockResolvedValue(DEFAULT_RESPONSE); - - return expect( - processRequest({ - request: SAMPLE_REQUEST, - envs: DEFAULT_ENVS, - path: "fake/collection/path", - delay: 0, - })() - ).resolves.toMatchObject({ - envs: { - selected: [{ key: "ENDPOINT", value: "https://example.com" }], - }, - report: { - result: true, - }, - }); - }); - - test("With invalid-pre-request-script.", () => { - SAMPLE_REQUEST.preRequestScript = `invalid`; - - (axios as unknown as jest.Mock).mockResolvedValue(DEFAULT_RESPONSE); - - return expect( - processRequest({ - request: SAMPLE_REQUEST, - envs: DEFAULT_ENVS, - path: "fake/request/path", - delay: 0, - })() - ).resolves.toMatchObject({ - report: { result: false }, - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/request/requestRunner.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/request/requestRunner.spec.ts deleted file mode 100644 index 7fb45aca..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/request/requestRunner.spec.ts +++ /dev/null @@ -1,108 +0,0 @@ -import axios, { AxiosError, AxiosResponse } from "axios"; -import { RequestConfig } from "../../../interfaces/request"; -import { requestRunner } from "../../../utils/request"; -import { RequestRunnerResponse } from "../../../interfaces/response"; - -import "@relmify/jest-fp-ts"; - -jest.mock("axios"); - -describe("requestRunner", () => { - let SAMPLE_REQUEST_CONFIG: RequestConfig = { - url: "https://example.com", - supported: false, - method: "GET", - }; - - beforeEach(() => { - SAMPLE_REQUEST_CONFIG.url = "https://example.com"; - SAMPLE_REQUEST_CONFIG.method = "GET"; - jest.clearAllMocks(); - }); - - afterAll(() => { - jest.clearAllMocks(); - }); - - it("Should handle axios-error with response info.", () => { - jest.spyOn(axios, "isAxiosError").mockReturnValue(true); - (axios as unknown as jest.Mock).mockRejectedValueOnce({ - name: "name", - message: "message", - config: SAMPLE_REQUEST_CONFIG, - isAxiosError: true, - response: { - data: "data", - status: 404, - statusText: "NOT FOUND", - headers: [], - config: SAMPLE_REQUEST_CONFIG, - }, - toJSON: () => Object({}), - }); - - return expect( - requestRunner(SAMPLE_REQUEST_CONFIG)() - ).resolves.toSubsetEqualRight({ - body: "data", - status: 404, - }); - }); - - it("Should handle axios-error for unsupported request.", () => { - jest.spyOn(axios, "isAxiosError").mockReturnValue(true); - (axios as unknown as jest.Mock).mockRejectedValueOnce({ - name: "name", - message: "message", - config: SAMPLE_REQUEST_CONFIG, - isAxiosError: true, - toJSON: () => Object({}), - }); - - return expect( - requestRunner(SAMPLE_REQUEST_CONFIG)() - ).resolves.toSubsetEqualRight({ - status: 501, - body: {}, - }); - }); - - it("Should handle axios-error with request info.", () => { - jest.spyOn(axios, "isAxiosError").mockReturnValue(true); - (axios as unknown as jest.Mock).mockRejectedValueOnce({ - name: "name", - message: "message", - config: SAMPLE_REQUEST_CONFIG, - isAxiosError: true, - request: {}, - toJSON: () => Object({}), - }); - - return expect(requestRunner(SAMPLE_REQUEST_CONFIG)()).resolves.toBeLeft(); - }); - - it("Should handle unknown error.", () => { - jest.spyOn(axios, "isAxiosError").mockReturnValue(false); - (axios as unknown as jest.Mock).mockRejectedValueOnce({}); - - return expect(requestRunner(SAMPLE_REQUEST_CONFIG)()).resolves.toBeLeft(); - }); - - it("Should successfully execute.", () => { - (axios as unknown as jest.Mock).mockResolvedValue({ - data: "data", - status: 200, - config: SAMPLE_REQUEST_CONFIG, - statusText: "OK", - headers: [], - }); - - return expect( - requestRunner(SAMPLE_REQUEST_CONFIG)() - ).resolves.toSubsetEqualRight({ - status: 200, - body: "data", - method: "GET", - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/test/getTestMetrics.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/test/getTestMetrics.spec.ts deleted file mode 100644 index e0115f98..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/test/getTestMetrics.spec.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { TestMetrics } from "../../../types/response"; -import { getTestMetrics } from "../../../utils/test"; - -describe("getTestMetrics", () => { - test("With empty test-reports and errors.", () => { - expect(getTestMetrics([], 1, [])).toMatchObject({ - tests: { passed: 0, failed: 0 }, - testSuites: { failed: 0, passed: 0 }, - duration: 1, - scripts: { failed: 0, passed: 1 }, - }); - }); - - test("With non-empty test-reports and no test-script-error.", () => { - expect( - getTestMetrics( - [ - { - descriptor: "descriptor", - expectResults: [], - failed: 0, - passed: 2, - }, - { - descriptor: "descriptor", - expectResults: [], - failed: 2, - passed: 1, - }, - ], - 5, - [] - ) - ).toMatchObject({ - tests: { failed: 2, passed: 3 }, - testSuites: { failed: 1, passed: 1 }, - scripts: { failed: 0, passed: 1 }, - duration: 5, - }); - }); - - test("With empty test-reports and some test-script-error.", () => { - expect( - getTestMetrics([], 5, [ - { code: "TEST_SCRIPT_ERROR", data: {} }, - { code: "PRE_REQUEST_SCRIPT_ERROR", data: {} }, - ]) - ).toMatchObject({ - tests: { failed: 0, passed: 0 }, - testSuites: { failed: 0, passed: 0 }, - scripts: { failed: 1, passed: 0 }, - duration: 5, - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/test/testDescriptorParser.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/test/testDescriptorParser.spec.ts deleted file mode 100644 index 21baa4fa..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/test/testDescriptorParser.spec.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { TestDescriptor } from "@hoppscotch/js-sandbox"; -import { testDescriptorParser, getTestMetrics } from "../../../utils/test"; -import { TestReport } from "../../../interfaces/response"; -import { TestMetrics } from "../../../types/response"; - -import "@relmify/jest-fp-ts"; - -const SAMPLE_TEST_DESCRIPTOR: TestDescriptor = { - descriptor: "Status code is 200", - expectResults: [ - { - status: "error", - message: "some_message", - }, - ], - children: [ - { - descriptor: "Check JSON response property", - expectResults: [ - { - status: "pass", - message: "some_message", - }, - ], - children: [], - }, - { - descriptor: "Check header property", - expectResults: [ - { - status: "fail", - message: "some_message", - }, - ], - children: [], - }, - ], -}; - -describe("testDescriptorParser", () => { - let TEST_REPORT: TestReport[]; - beforeAll(async () => { - TEST_REPORT = await testDescriptorParser(SAMPLE_TEST_DESCRIPTOR)(); - }); - - it("Should have 3 tests-report.", () => { - expect(TEST_REPORT).toEqual(expect.any(Array)); - expect(TEST_REPORT.length).toStrictEqual(3); - }); - - it("Should have 1 passed, 2 failed test-cases; 1 passed, 2 failed test-suite.", () => { - expect(getTestMetrics(TEST_REPORT, 1, [])).toMatchObject({ - tests: { - failed: 2, - passed: 1, - }, - testSuites: { - failed: 2, - passed: 1, - }, - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/functions/test/testRunner.spec.ts b/packages/hoppscotch-cli/src/__tests__/functions/test/testRunner.spec.ts deleted file mode 100644 index 0eeafa91..00000000 --- a/packages/hoppscotch-cli/src/__tests__/functions/test/testRunner.spec.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { TestResponse } from "@hoppscotch/js-sandbox"; -import * as E from "fp-ts/Either"; -import { TestRunnerRes } from "../../../types/response"; -import { HoppCLIError } from "../../../types/errors"; -import { getTestMetrics, testRunner } from "../../../utils/test"; -import { HoppEnvs } from "../../../types/request"; - -import "@relmify/jest-fp-ts"; - -const SAMPLE_ENVS: HoppEnvs = { - global: [], - selected: [ - { - key: "DEVBLIN", - value: "set-by-devblin", - }, - ], -}; -const SAMPLE_RESPONSE: TestResponse = { - status: 200, - headers: [], - body: {}, -}; - -describe("testRunner", () => { - let SUCCESS_TEST_RUNNER_RES: E.Either, - FAILURE_TEST_RUNNER_RES: E.Either; - - beforeAll(async () => { - SUCCESS_TEST_RUNNER_RES = await testRunner({ - testScript: ` - // Check status code is 200 - pw.test("Status code is 200", ()=> { - pw.expect(pw.response.status).toBe(200); - }); - - // Check JSON response property - pw.test("Check JSON response property", ()=> { - pw.expect(pw.response.body).toBeType("string") - pw.expect(pw.response.body).toBe("body"); - }); - `, - envs: SAMPLE_ENVS, - response: SAMPLE_RESPONSE, - })(); - - FAILURE_TEST_RUNNER_RES = await testRunner({ - testScript: "a", - envs: SAMPLE_ENVS, - response: SAMPLE_RESPONSE, - })(); - }); - - it("Should have 2 failed, 1 passed test-cases; 1 failed, 1 passed test-suites.", () => { - expect(SUCCESS_TEST_RUNNER_RES).toBeRight(); - - if (E.isRight(SUCCESS_TEST_RUNNER_RES)) { - const { duration, testsReport } = SUCCESS_TEST_RUNNER_RES.right; - const { tests, testSuites } = getTestMetrics(testsReport, duration, []); - - expect(tests.failed).toStrictEqual(2); - expect(tests.passed).toStrictEqual(1); - expect(testSuites.failed).toStrictEqual(1); - expect(testSuites.passed).toStrictEqual(1); - } - }); - - it("Should fail to execute with test-script-error.", () => { - expect(FAILURE_TEST_RUNNER_RES).toSubsetEqualLeft({ - code: "TEST_SCRIPT_ERROR", - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/types.ts b/packages/hoppscotch-cli/src/__tests__/types.ts deleted file mode 100644 index b84c6b7d..00000000 --- a/packages/hoppscotch-cli/src/__tests__/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { ExecException } from "child_process"; - -export type ExecResponse = { - error: ExecException | null; - stdout: string; - stderr: string; -}; diff --git a/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts b/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts deleted file mode 100644 index 774be70e..00000000 --- a/packages/hoppscotch-cli/src/__tests__/unit/fixtures/workspace-access.mock.ts +++ /dev/null @@ -1,1762 +0,0 @@ -import { - CollectionSchemaVersion, - Environment, - EnvironmentSchemaVersion, - HoppCollection, - RESTReqSchemaVersion, -} from "@hoppscotch/data"; - -import { - WorkspaceCollection, - WorkspaceEnvironment, -} from "../../../utils/workspace-access"; - -export const WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK: WorkspaceCollection[] = - [ - { - id: "clx1ldkzs005t10f8rp5u60q7", - data: '{"auth":{"token":"BearerToken","authType":"bearer","authActive":true},"headers":[{"key":"X-Test-Header","value":"Set at root collection","active":true,"description":""}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "CollectionA", - parentID: null, - folders: [ - { - id: "clx1ldkzs005v10f86b9wx4yc", - data: '{"auth":{"authType":"inherit","authActive":true},"headers":[],"variables":[]}', - title: "FolderA", - parentID: "clx1ldkzs005t10f8rp5u60q7", - folders: [ - { - id: "clx1ldkzt005x10f8i0u5lzgj", - data: '{"auth":{"key":"key","addTo":"HEADERS","value":"test-key","authType":"api-key","authActive":true},"headers":[{"key":"X-Test-Header","value":"Overriden at FolderB","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "FolderB", - parentID: "clx1ldkzs005v10f86b9wx4yc", - folders: [ - { - id: "clx1ldkzu005z10f880zx17bg", - data: '{"auth":{"authType":"inherit","authActive":true},"headers":[],"variables":[]}', - title: "FolderC", - parentID: "clx1ldkzt005x10f8i0u5lzgj", - folders: [], - requests: [ - { - id: "clx1ldkzu006010f820vzy13v", - collectionID: "clx1ldkzu005z10f880zx17bg", - teamID: "clws3hg58000011o8h07glsb1", - title: "RequestD", - request: - '{"v":"3","auth":{"authType":"basic","password":"password","username":"username","authActive":true},"body":{"body":null,"contentType":null},"name":"RequestD","method":"GET","params":[],"headers":[{"key":"X-Test-Header","value":"Overriden at RequestD","active":true}],"endpoint":"https://echo.hoppscotch.io","testScript":"pw.test(\\"Overrides auth and headers set at the parent folder\\", ()=> {\\n pw.expect(pw.response.body.headers[\\"x-test-header\\"]).toBe(\\"Overriden at RequestD\\");\\n pw.expect(pw.response.body.headers[\\"authorization\\"]).toBe(\\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\\");\\n});","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - ], - requests: [ - { - id: "clx1ldkzt005y10f82dl8ni8d", - collectionID: "clx1ldkzt005x10f8i0u5lzgj", - teamID: "clws3hg58000011o8h07glsb1", - title: "RequestC", - request: - '{"v":"3","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"RequestC","method":"GET","params":[],"headers":[],"endpoint":"https://echo.hoppscotch.io","testScript":"pw.test(\\"Correctly inherits auth and headers from the parent folder\\", ()=> {\\n pw.expect(pw.response.body.headers[\\"x-test-header\\"]).toBe(\\"Overriden at FolderB\\");\\n pw.expect(pw.response.body.headers[\\"key\\"]).toBe(\\"test-key\\");\\n});","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - ], - requests: [ - { - id: "clx1ldkzs005w10f8pc2v2boh", - collectionID: "clx1ldkzs005v10f86b9wx4yc", - teamID: "clws3hg58000011o8h07glsb1", - title: "RequestB", - request: - '{"v":"3","id":"clpttpdq00003qp16kut6doqv","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"RequestB","method":"GET","params":[],"headers":[],"endpoint":"https://echo.hoppscotch.io","testScript":"pw.test(\\"Correctly inherits auth and headers from the parent folder\\", ()=> {\\n pw.expect(pw.response.body.headers[\\"x-test-header\\"]).toBe(\\"Set at root collection\\");\\n pw.expect(pw.response.body.headers[\\"authorization\\"]).toBe(\\"Bearer BearerToken\\");\\n});","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - ], - requests: [ - { - id: "clx1ldkzs005u10f82xd5ho3l", - collectionID: "clx1ldkzs005t10f8rp5u60q7", - teamID: "clws3hg58000011o8h07glsb1", - title: "RequestA", - request: `{"v":"${RESTReqSchemaVersion}","id":"clpttpdq00003qp16kut6doqv","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"RequestA","method":"GET","params":[],"headers":[],"endpoint":"https://echo.hoppscotch.io","testScript":"pw.test(\\"Correctly inherits auth and headers from the root collection\\", ()=> {\\n pw.expect(pw.response.body.headers[\\"x-test-header\\"]).toBe(\\"Set at root collection\\");\\n pw.expect(pw.response.body.headers[\\"authorization\\"]).toBe(\\"Bearer BearerToken\\");\\n});","preRequestScript":"","requestVariables":[],"responses":{},"description":""}`, - }, - ], - }, - ]; - -export const TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK: HoppCollection[] = - [ - { - v: CollectionSchemaVersion, - id: "clx1ldkzs005t10f8rp5u60q7", - name: "CollectionA", - folders: [ - { - v: CollectionSchemaVersion, - id: "clx1ldkzs005v10f86b9wx4yc", - name: "FolderA", - folders: [ - { - v: CollectionSchemaVersion, - id: "clx1ldkzt005x10f8i0u5lzgj", - name: "FolderB", - folders: [ - { - v: CollectionSchemaVersion, - id: "clx1ldkzu005z10f880zx17bg", - name: "FolderC", - folders: [], - requests: [ - { - v: "3", - auth: { - authType: "basic", - password: "password", - username: "username", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "RequestD", - method: "GET", - params: [], - headers: [ - { - key: "X-Test-Header", - value: "Overriden at RequestD", - active: true, - }, - ], - endpoint: "https://echo.hoppscotch.io", - testScript: - 'pw.test("Overrides auth and headers set at the parent folder", ()=> {\n pw.expect(pw.response.body.headers["x-test-header"]).toBe("Overriden at RequestD");\n pw.expect(pw.response.body.headers["authorization"]).toBe("Basic dXNlcm5hbWU6cGFzc3dvcmQ=");\n});', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [], - variables: [], - description: null, - preRequestScript: "", - testScript: "", - }, - ], - requests: [ - { - v: "3", - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "RequestC", - method: "GET", - params: [], - headers: [], - endpoint: "https://echo.hoppscotch.io", - testScript: - 'pw.test("Correctly inherits auth and headers from the parent folder", ()=> {\n pw.expect(pw.response.body.headers["x-test-header"]).toBe("Overriden at FolderB");\n pw.expect(pw.response.body.headers["key"]).toBe("test-key");\n});', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - key: "key", - addTo: "HEADERS", - value: "test-key", - authType: "api-key", - authActive: true, - }, - headers: [ - { - key: "X-Test-Header", - value: "Overriden at FolderB", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - ], - requests: [ - { - v: "3", - id: "clpttpdq00003qp16kut6doqv", - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "RequestB", - method: "GET", - params: [], - headers: [], - endpoint: "https://echo.hoppscotch.io", - testScript: - 'pw.test("Correctly inherits auth and headers from the parent folder", ()=> {\n pw.expect(pw.response.body.headers["x-test-header"]).toBe("Set at root collection");\n pw.expect(pw.response.body.headers["authorization"]).toBe("Bearer BearerToken");\n});', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [], - variables: [], - description: null, - preRequestScript: "", - testScript: "", - }, - ], - requests: [ - { - v: RESTReqSchemaVersion, - id: "clpttpdq00003qp16kut6doqv", - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "RequestA", - method: "GET", - params: [], - headers: [], - endpoint: "https://echo.hoppscotch.io", - testScript: - 'pw.test("Correctly inherits auth and headers from the root collection", ()=> {\n pw.expect(pw.response.body.headers["x-test-header"]).toBe("Set at root collection");\n pw.expect(pw.response.body.headers["authorization"]).toBe("Bearer BearerToken");\n});', - preRequestScript: "", - requestVariables: [], - responses: {}, - description: "", - }, - ], - auth: { - token: "BearerToken", - authType: "bearer", - authActive: true, - }, - headers: [ - { - key: "X-Test-Header", - value: "Set at root collection", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - ]; - -export const WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK: WorkspaceCollection[] = - [ - { - id: "clx1f86hv000010f8szcfya0t", - data: '{"auth":{"authType":"basic","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value set at the root collection","active":true},{"key":"Inherited-Header","value":"Inherited header at all levels","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: - "Multiple child collections with authorization, headers and variables set at each level", - parentID: null, - folders: [ - { - id: "clx1fjgah000110f8a5bs68gd", - data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-1","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-1", - parentID: "clx1f86hv000010f8szcfya0t", - folders: [ - { - id: "clx1fjwmm000410f8l1gkkr1a", - data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-11","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-11", - parentID: "clx1fjgah000110f8a5bs68gd", - folders: [], - requests: [ - { - id: "clx1gjo1q000p10f8tc3x2u50", - collectionID: "clx1fjwmm000410f8l1gkkr1a", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-11-request", - request: - '{"v":"4","auth":{"authType":"inherit","password":"testpass","username":"testuser","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-11-request","method":"GET","params":[],"headers":[],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(\\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\\")\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-1\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1fjyxm000510f8pv90dt43", - data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-12","active":true},{"key":"key","value":"Set at folder-12","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-12", - parentID: "clx1fjgah000110f8a5bs68gd", - folders: [], - requests: [ - { - id: "clx1glkt5000u10f88q51ioj8", - collectionID: "clx1fjyxm000510f8pv90dt43", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-12-request", - request: - '{"v":"4","auth":{"authType":"none","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-12-request","method":"GET","params":[],"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-12-request","active":true},{"key":"key","value":"Overriden at folder-12-request","active":true}],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits/overrides authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(undefined)\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-12-request\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n pw.expect(pw.response.body.headers[\\"Key\\"]).toBe(\\"Overriden at folder-12-request\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1fk1cv000610f88kc3aupy", - data: '{"auth":{"token":"test-token","authType":"bearer","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-13","active":true},{"key":"key","value":"Set at folder-13","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-13", - parentID: "clx1fjgah000110f8a5bs68gd", - folders: [], - requests: [ - { - id: "clx1grfir001510f8c4ttiazq", - collectionID: "clx1fk1cv000610f88kc3aupy", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-13-request", - request: - '{"v":"4","auth":{"key":"api-key","addTo":"HEADERS","value":"api-key-value","authType":"basic","password":"testpass","username":"testuser","authActive":true,"grantTypeInfo":{"token":"","isPKCE":true,"clientID":"sfasfa","password":"","username":"","grantType":"AUTHORIZATION_CODE","authEndpoint":"asfafs","clientSecret":"sfasfasf","tokenEndpoint":"asfa","codeVerifierMethod":"S256"}},"body":{"body":null,"contentType":null},"name":"folder-13-request","method":"GET","params":[],"headers":[{"key":"Custom-Header-Request-Level","value":"New custom header added at the folder-13-request level","active":true},{"key":"key","value":"Overriden at folder-13-request","active":true}],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits/overrides authorization/header set at the parent collection level with new header addition\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(\\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\\")\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-13\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n pw.expect(pw.response.body.headers[\\"Key\\"]).toBe(\\"Overriden at folder-13-request\\")\\n pw.expect(pw.response.body.headers[\\"Custom-Header-Request-Level\\"]).toBe(\\"New custom header added at the folder-13-request level\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - ], - requests: [ - { - id: "clx1gebpx000k10f8andzw36z", - collectionID: "clx1fjgah000110f8a5bs68gd", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-1-request", - request: - '{"v":"4","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-1-request","method":"GET","params":[],"headers":[],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(\\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\\")\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-1\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1fjk9o000210f8j0573pls", - data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-2","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-2", - parentID: "clx1f86hv000010f8szcfya0t", - folders: [ - { - id: "clx1fk516000710f87sfpw6bo", - data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-21","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-21", - parentID: "clx1fjk9o000210f8j0573pls", - folders: [], - requests: [ - { - id: "clx1hfegy001j10f8ywbozysk", - collectionID: "clx1fk516000710f87sfpw6bo", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-21-request", - request: - '{"v":"4","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-21-request","method":"GET","params":[],"headers":[],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(undefined)\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-2\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1fk72t000810f8gfwkpi5y", - data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-22","active":true},{"key":"key","value":"Set at folder-22","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-22", - parentID: "clx1fjk9o000210f8j0573pls", - folders: [], - requests: [ - { - id: "clx1ibfre002k10f86brcb2aa", - collectionID: "clx1fk72t000810f8gfwkpi5y", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-22-request", - request: - '{"v":"4","auth":{"authType":"none","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-22-request","method":"GET","params":[],"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-22-request","active":true},{"key":"key","value":"Overriden at folder-22-request","active":true}],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits/overrides authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(undefined)\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-22-request\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n pw.expect(pw.response.body.headers[\\"Key\\"]).toBe(\\"Overriden at folder-22-request\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1fk95g000910f8bunhaoo8", - data: '{"auth":{"token":"test-token","authType":"bearer","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-23","active":true},{"key":"key","value":"Set at folder-23","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-23", - parentID: "clx1fjk9o000210f8j0573pls", - folders: [], - requests: [ - { - id: "clx1if4w6002n10f8xe4gnf0w", - collectionID: "clx1fk95g000910f8bunhaoo8", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-23-request", - request: - '{"v":"4","auth":{"authType":"basic","password":"testpass","username":"testuser","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-23-request","method":"GET","params":[],"headers":[{"key":"Custom-Header-Request-Level","value":"New custom header added at the folder-23-request level","active":true},{"key":"key","value":"Overriden at folder-23-request","active":true}],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits/overrides authorization/header set at the parent collection level with new header addition\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(\\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\\")\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-23\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n pw.expect(pw.response.body.headers[\\"Key\\"]).toBe(\\"Overriden at folder-23-request\\")\\n pw.expect(pw.response.body.headers[\\"Custom-Header-Request-Level\\"]).toBe(\\"New custom header added at the folder-23-request level\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - ], - requests: [ - { - id: "clx1hbtdj001g10f8y71y869s", - collectionID: "clx1fjk9o000210f8j0573pls", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-2-request", - request: - '{"v":"4","auth":{"authType":"none","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-2-request","method":"GET","params":[],"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-2-request","active":true}],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits/overrides authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(undefined)\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-2-request\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1fjmlq000310f86o4d3w2o", - data: '{"auth":{"key":"testuser","addTo":"HEADERS","value":"testpass","authType":"basic","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-3","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-3", - parentID: "clx1f86hv000010f8szcfya0t", - folders: [ - { - id: "clx1iwq0p003e10f8u8zg0p85", - data: '{"auth":{"authType":"inherit","authActive":true},"headers":[{"key":"key","value":"Set at folder-31","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-31", - parentID: "clx1fjmlq000310f86o4d3w2o", - folders: [], - requests: [ - { - id: "clx1ixdiv003f10f8j6ni375m", - collectionID: "clx1iwq0p003e10f8u8zg0p85", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-31-request", - request: - '{"v":"4","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-31-request","method":"GET","params":[],"headers":[],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(\\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\\")\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-3\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1izut7003m10f894ip59zg", - data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-32","active":true},{"key":"key","value":"Set at folder-32","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-32", - parentID: "clx1fjmlq000310f86o4d3w2o", - folders: [], - requests: [ - { - id: "clx1j01dg003n10f8e34khl6v", - collectionID: "clx1izut7003m10f894ip59zg", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-32-request", - request: - '{"v":"4","auth":{"authType":"none","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-32-request","method":"GET","params":[],"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-32-request","active":true},{"key":"key","value":"Overriden at folder-32-request","active":true}],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits/overrides authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(undefined)\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-32-request\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n pw.expect(pw.response.body.headers[\\"Key\\"]).toBe(\\"Overriden at folder-32-request\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1j2ka9003q10f8cdbzpgpg", - data: '{"auth":{"token":"test-token","authType":"bearer","password":"testpass","username":"testuser","authActive":true},"headers":[{"key":"Custom-Header","value":"Custom header value overriden at folder-33","active":true},{"key":"key","value":"Set at folder-33","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-33", - parentID: "clx1fjmlq000310f86o4d3w2o", - folders: [], - requests: [ - { - id: "clx1j361a003r10f8oly5m2n6", - collectionID: "clx1j2ka9003q10f8cdbzpgpg", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-33-request", - request: - '{"v":"4","auth":{"authType":"basic","password":"testpass","username":"testuser","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-33-request","method":"GET","params":[],"headers":[{"key":"Custom-Header-Request-Level","value":"New custom header added at the folder-33-request level","active":true},{"key":"key","value":"Overriden at folder-33-request","active":true}],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits/overrides authorization/header set at the parent collection level with new header addition\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(\\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\\")\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-33\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n pw.expect(pw.response.body.headers[\\"Key\\"]).toBe(\\"Overriden at folder-33-request\\")\\n pw.expect(pw.response.body.headers[\\"Custom-Header-Request-Level\\"]).toBe(\\"New custom header added at the folder-33-request level\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - ], - requests: [ - { - id: "clx1jk1nq004y10f8fhtxvs02", - collectionID: "clx1fjmlq000310f86o4d3w2o", - teamID: "clws3hg58000011o8h07glsb1", - title: "folder-3-request", - request: - '{"v":"4","auth":{"authType":"basic","password":"testpass","username":"testuser","authActive":true},"body":{"body":null,"contentType":null},"name":"folder-3-request","method":"GET","params":[],"headers":[{"key":"Custom-Header-Request-Level","value":"New custom header added at the folder-3-request level","active":true},{"key":"key","value":"Set at folder-3-request","active":true}],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits/overrides authorization/header set at the parent collection level with new header addition\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(\\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\\")\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value overriden at folder-3\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n pw.expect(pw.response.body.headers[\\"Key\\"]).toBe(\\"Set at folder-3-request\\")\\n pw.expect(pw.response.body.headers[\\"Custom-Header-Request-Level\\"]).toBe(\\"New custom header added at the folder-3-request level\\")\\n})","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - ], - requests: [ - { - id: "clx1g2pnv000b10f80f0oyp79", - collectionID: "clx1f86hv000010f8szcfya0t", - teamID: "clws3hg58000011o8h07glsb1", - title: "root-collection-request", - request: `{"v":"${RESTReqSchemaVersion}","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"root-collection-request","method":"GET","params":[],"headers":[],"endpoint":"https://httpbin.org/get","testScript":"// Check status code is 200\\npw.test(\\"Status code is 200\\", ()=> {\\n pw.expect(pw.response.status).toBe(200);\\n});\\n\\npw.test(\\"Successfully inherits authorization/header set at the parent collection level\\", () => {\\n pw.expect(pw.response.body.headers[\\"Authorization\\"]).toBe(\\"Basic dGVzdHVzZXI6dGVzdHBhc3M=\\")\\n \\n pw.expect(pw.response.body.headers[\\"Custom-Header\\"]).toBe(\\"Custom header value set at the root collection\\")\\n pw.expect(pw.response.body.headers[\\"Inherited-Header\\"]).toBe(\\"Inherited header at all levels\\")\\n})","preRequestScript":"","requestVariables":[],"responses":{}, "description": ""}`, - }, - ], - }, - ]; - -export const TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK: HoppCollection[] = - [ - { - v: CollectionSchemaVersion, - id: "clx1f86hv000010f8szcfya0t", - name: "Multiple child collections with authorization, headers and variables set at each level", - folders: [ - { - v: CollectionSchemaVersion, - id: "clx1fjgah000110f8a5bs68gd", - name: "folder-1", - folders: [ - { - v: CollectionSchemaVersion, - id: "clx1fjwmm000410f8l1gkkr1a", - name: "folder-11", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "inherit", - password: "testpass", - username: "testuser", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-11-request", - method: "GET", - params: [], - headers: [], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe("Basic dGVzdHVzZXI6dGVzdHBhc3M=")\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-1")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [ - { - key: "key", - value: "Set at folder-11", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1fjyxm000510f8pv90dt43", - name: "folder-12", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "none", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-12-request", - method: "GET", - params: [], - headers: [ - { - key: "Custom-Header", - value: - "Custom header value overriden at folder-12-request", - active: true, - }, - { - key: "key", - value: "Overriden at folder-12-request", - active: true, - }, - ], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits/overrides authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-12-request")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n pw.expect(pw.response.body.headers["Key"]).toBe("Overriden at folder-12-request")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "none", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-12", - active: true, - description: "", - }, - { - key: "key", - value: "Set at folder-12", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1fk1cv000610f88kc3aupy", - name: "folder-13", - folders: [], - requests: [ - { - v: "4", - auth: { - key: "api-key", - addTo: "HEADERS", - value: "api-key-value", - authType: "basic", - password: "testpass", - username: "testuser", - authActive: true, - grantTypeInfo: { - token: "", - isPKCE: true, - clientID: "sfasfa", - password: "", - username: "", - grantType: "AUTHORIZATION_CODE", - authEndpoint: "asfafs", - clientSecret: "sfasfasf", - tokenEndpoint: "asfa", - codeVerifierMethod: "S256", - }, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-13-request", - method: "GET", - params: [], - headers: [ - { - key: "Custom-Header-Request-Level", - value: - "New custom header added at the folder-13-request level", - active: true, - }, - { - key: "key", - value: "Overriden at folder-13-request", - active: true, - }, - ], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits/overrides authorization/header set at the parent collection level with new header addition", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe("Basic dGVzdHVzZXI6dGVzdHBhc3M=")\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-13")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n pw.expect(pw.response.body.headers["Key"]).toBe("Overriden at folder-13-request")\n pw.expect(pw.response.body.headers["Custom-Header-Request-Level"]).toBe("New custom header added at the folder-13-request level")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - token: "test-token", - authType: "bearer", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-13", - active: true, - description: "", - }, - { - key: "key", - value: "Set at folder-13", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - ], - requests: [ - { - v: "4", - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-1-request", - method: "GET", - params: [], - headers: [], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe("Basic dGVzdHVzZXI6dGVzdHBhc3M=")\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-1")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-1", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1fjk9o000210f8j0573pls", - name: "folder-2", - folders: [ - { - v: CollectionSchemaVersion, - id: "clx1fk516000710f87sfpw6bo", - name: "folder-21", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-21-request", - method: "GET", - params: [], - headers: [], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-2")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [ - { - key: "key", - value: "Set at folder-21", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1fk72t000810f8gfwkpi5y", - name: "folder-22", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "none", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-22-request", - method: "GET", - params: [], - headers: [ - { - key: "Custom-Header", - value: - "Custom header value overriden at folder-22-request", - active: true, - }, - { - key: "key", - value: "Overriden at folder-22-request", - active: true, - }, - ], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits/overrides authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-22-request")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n pw.expect(pw.response.body.headers["Key"]).toBe("Overriden at folder-22-request")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "none", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-22", - active: true, - description: "", - }, - { - key: "key", - value: "Set at folder-22", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1fk95g000910f8bunhaoo8", - name: "folder-23", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "basic", - password: "testpass", - username: "testuser", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-23-request", - method: "GET", - params: [], - headers: [ - { - key: "Custom-Header-Request-Level", - value: - "New custom header added at the folder-23-request level", - active: true, - }, - { - key: "key", - value: "Overriden at folder-23-request", - active: true, - }, - ], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits/overrides authorization/header set at the parent collection level with new header addition", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe("Basic dGVzdHVzZXI6dGVzdHBhc3M=")\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-23")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n pw.expect(pw.response.body.headers["Key"]).toBe("Overriden at folder-23-request")\n pw.expect(pw.response.body.headers["Custom-Header-Request-Level"]).toBe("New custom header added at the folder-23-request level")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - token: "test-token", - authType: "bearer", - password: "testpass", - username: "testuser", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-23", - active: true, - description: "", - }, - { - key: "key", - value: "Set at folder-23", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - ], - requests: [ - { - v: "4", - auth: { - authType: "none", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-2-request", - method: "GET", - params: [], - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-2-request", - active: true, - }, - ], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits/overrides authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-2-request")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "none", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-2", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - - { - v: CollectionSchemaVersion, - id: "clx1fjmlq000310f86o4d3w2o", - name: "folder-3", - folders: [ - { - v: CollectionSchemaVersion, - id: "clx1iwq0p003e10f8u8zg0p85", - name: "folder-31", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-31-request", - method: "GET", - params: [], - headers: [], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe("Basic dGVzdHVzZXI6dGVzdHBhc3M=")\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-3")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [ - { - key: "key", - value: "Set at folder-31", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1izut7003m10f894ip59zg", - name: "folder-32", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "none", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-32-request", - method: "GET", - params: [], - headers: [ - { - key: "Custom-Header", - value: - "Custom header value overriden at folder-32-request", - active: true, - }, - { - key: "key", - value: "Overriden at folder-32-request", - active: true, - }, - ], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits/overrides authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe(undefined)\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-32-request")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n pw.expect(pw.response.body.headers["Key"]).toBe("Overriden at folder-32-request")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "none", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-32", - active: true, - description: "", - }, - { - key: "key", - value: "Set at folder-32", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1j2ka9003q10f8cdbzpgpg", - name: "folder-33", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "basic", - password: "testpass", - username: "testuser", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-33-request", - method: "GET", - params: [], - headers: [ - { - key: "Custom-Header-Request-Level", - value: - "New custom header added at the folder-33-request level", - active: true, - }, - { - key: "key", - value: "Overriden at folder-33-request", - active: true, - }, - ], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits/overrides authorization/header set at the parent collection level with new header addition", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe("Basic dGVzdHVzZXI6dGVzdHBhc3M=")\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-33")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n pw.expect(pw.response.body.headers["Key"]).toBe("Overriden at folder-33-request")\n pw.expect(pw.response.body.headers["Custom-Header-Request-Level"]).toBe("New custom header added at the folder-33-request level")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - token: "test-token", - authType: "bearer", - password: "testpass", - username: "testuser", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-33", - active: true, - description: "", - }, - { - key: "key", - value: "Set at folder-33", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - ], - requests: [ - { - v: "4", - auth: { - authType: "basic", - password: "testpass", - username: "testuser", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "folder-3-request", - method: "GET", - params: [], - headers: [ - { - key: "Custom-Header-Request-Level", - value: - "New custom header added at the folder-3-request level", - active: true, - }, - { - key: "key", - value: "Set at folder-3-request", - active: true, - }, - ], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits/overrides authorization/header set at the parent collection level with new header addition", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe("Basic dGVzdHVzZXI6dGVzdHBhc3M=")\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value overriden at folder-3")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n pw.expect(pw.response.body.headers["Key"]).toBe("Set at folder-3-request")\n pw.expect(pw.response.body.headers["Custom-Header-Request-Level"]).toBe("New custom header added at the folder-3-request level")\n})', - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - key: "testuser", - addTo: "HEADERS", - value: "testpass", - authType: "basic", - password: "testpass", - username: "testuser", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value overriden at folder-3", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - ], - requests: [ - { - v: RESTReqSchemaVersion, - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "root-collection-request", - method: "GET", - params: [], - headers: [], - endpoint: "https://httpbin.org/get", - testScript: - '// Check status code is 200\npw.test("Status code is 200", ()=> {\n pw.expect(pw.response.status).toBe(200);\n});\n\npw.test("Successfully inherits authorization/header set at the parent collection level", () => {\n pw.expect(pw.response.body.headers["Authorization"]).toBe("Basic dGVzdHVzZXI6dGVzdHBhc3M=")\n \n pw.expect(pw.response.body.headers["Custom-Header"]).toBe("Custom header value set at the root collection")\n pw.expect(pw.response.body.headers["Inherited-Header"]).toBe("Inherited header at all levels")\n})', - preRequestScript: "", - requestVariables: [], - responses: {}, - description: "", - }, - ], - auth: { - authType: "basic", - password: "testpass", - username: "testuser", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Custom header value set at the root collection", - active: true, - description: "", - }, - { - key: "Inherited-Header", - value: "Inherited header at all levels", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - ]; - -// Collections with `data` field set to `null` at certain levels -export const WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK: WorkspaceCollection[] = - [ - { - id: "clx1kxvao005m10f8luqivrf1", - data: null, - title: "Collection with no authorization/headers/variables set", - parentID: null, - folders: [ - { - id: "clx1kygjt005n10f8m1nkhjux", - data: null, - title: "folder-1", - parentID: "clx1kxvao005m10f8luqivrf1", - folders: [], - requests: [ - { - id: "clx1kz2gk005p10f8ll7ztbnj", - collectionID: "clx1kygjt005n10f8m1nkhjux", - teamID: "clws3hg58000011o8h07glsb1", - title: "req1", - request: - '{"v":"4","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"req1","method":"GET","params":[],"headers":[],"endpoint":"https://echo.hoppscotch.io","testScript":"","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1kym98005o10f8qg17t9o2", - data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Set at folder-2","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-2", - parentID: "clx1kxvao005m10f8luqivrf1", - folders: [], - requests: [ - { - id: "clx1kz3m7005q10f8lw3v09l4", - collectionID: "clx1kym98005o10f8qg17t9o2", - teamID: "clws3hg58000011o8h07glsb1", - title: "req2", - request: - '{"v":"4","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"req2","method":"GET","params":[],"headers":[],"endpoint":"https://echo.hoppscotch.io","testScript":"","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - { - id: "clx1l2bu6005r10f8daynohge", - data: null, - title: "folder-3", - parentID: "clx1kxvao005m10f8luqivrf1", - folders: [], - requests: [], - }, - { - id: "clx1l2eaz005s10f8loetbbeb", - data: '{"auth":{"authType":"none","authActive":true},"headers":[{"key":"Custom-Header","value":"Set at folder-4","active":true}],"variables":[{"key":"collection-variable","currentValue":"collection-variable-value","initialValue":"collection-variable-value","secret":false}]}', - title: "folder-4", - parentID: "clx1kxvao005m10f8luqivrf1", - folders: [], - requests: [], - }, - ], - requests: [], - }, - ]; - -export const TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK: HoppCollection[] = - [ - { - v: CollectionSchemaVersion, - id: "clx1kxvao005m10f8luqivrf1", - name: "Collection with no authorization/headers/variables set", - folders: [ - { - v: CollectionSchemaVersion, - id: "clx1kygjt005n10f8m1nkhjux", - name: "folder-1", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "req1", - method: "GET", - params: [], - headers: [], - endpoint: "https://echo.hoppscotch.io", - testScript: "", - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [], - variables: [], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1kym98005o10f8qg17t9o2", - name: "folder-2", - folders: [], - requests: [ - { - v: "4", - auth: { - authType: "inherit", - authActive: true, - }, - body: { - body: null, - contentType: null, - }, - name: "req2", - method: "GET", - params: [], - headers: [], - endpoint: "https://echo.hoppscotch.io", - testScript: "", - preRequestScript: "", - requestVariables: [], - }, - ], - auth: { - authType: "none", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Set at folder-2", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1l2bu6005r10f8daynohge", - name: "folder-3", - folders: [], - requests: [], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [], - variables: [], - description: null, - preRequestScript: "", - testScript: "", - }, - { - v: CollectionSchemaVersion, - id: "clx1l2eaz005s10f8loetbbeb", - name: "folder-4", - folders: [], - requests: [], - auth: { - authType: "none", - authActive: true, - }, - headers: [ - { - key: "Custom-Header", - value: "Set at folder-4", - active: true, - description: "", - }, - ], - variables: [ - { - key: "collection-variable", - currentValue: "collection-variable-value", - initialValue: "collection-variable-value", - secret: false, - }, - ], - description: null, - preRequestScript: "", - testScript: "", - }, - ], - requests: [], - auth: { - authType: "inherit", - authActive: true, - }, - headers: [], - variables: [], - description: null, - preRequestScript: "", - testScript: "", - }, - ]; - -export const WORKSPACE_ENVIRONMENT_V0_FORMAT_MOCK = { - id: "clwudd68q00079rufju8uo3om", - teamID: "clws3hg58000011o8h07glsb1", - name: "Workspace environment v0 format", - variables: [ - { - key: "firstName", - value: "John", - }, - { - key: "lastName", - value: "Doe", - }, - ], -}; - -export const TRANSFORMED_ENVIRONMENT_V0_FORMAT_MOCK: Environment = { - v: EnvironmentSchemaVersion, - id: "clwudd68q00079rufju8uo3om", - name: "Workspace environment v0 format", - variables: [ - { - key: "firstName", - initialValue: "John", - currentValue: "John", - secret: false, - }, - { - key: "lastName", - initialValue: "Doe", - currentValue: "Doe", - secret: false, - }, - ], -}; - -export const WORKSPACE_ENVIRONMENT_V1_FORMAT_MOCK = { - id: "clwudd68q00079rufju8uo3om", - teamID: "clws3hg58000011o8h07glsb1", - name: "Workspace environment v1 format", - variables: [ - { - key: "firstName", - value: "John", - secret: false, - }, - { - key: "lastName", - value: "Doe", - secret: false, - }, - ], -}; - -export const TRANSFORMED_ENVIRONMENT_V1_FORMAT_MOCK: Environment = { - v: EnvironmentSchemaVersion, - id: "clwudd68q00079rufju8uo3om", - name: "Workspace environment v1 format", - variables: [ - { - key: "firstName", - initialValue: "John", - currentValue: "John", - secret: false, - }, - { - key: "lastName", - initialValue: "Doe", - currentValue: "Doe", - secret: false, - }, - ], -}; - -export const WORKSPACE_ENVIRONMENT_V2_FORMAT_MOCK: WorkspaceEnvironment = { - id: "clwudd68q00079rufju8uo3on", - teamID: "clws3hg58000011o8h07glsb1", - name: "Response body sample", - variables: [ - { - key: "firstName", - initialValue: "John", - currentValue: "John", - secret: false, - }, - { - key: "lastName", - initialValue: "Doe", - currentValue: "Doe", - secret: false, - }, - { - key: "id", - initialValue: "7", - currentValue: "7", - secret: false, - }, - { - key: "fullName", - initialValue: "<> <>", - currentValue: "<> <>", - secret: false, - }, - { - key: "recursiveVarX", - initialValue: "<>", - currentValue: "<>", - secret: false, - }, - { - key: "recursiveVarY", - initialValue: "<>", - currentValue: "<>", - secret: false, - }, - { - key: "salutation", - initialValue: "Hello", - currentValue: "Hello", - secret: false, - }, - { - key: "greetText", - initialValue: "<> <>", - currentValue: "<> <>", - secret: false, - }, - ], -}; - -export const TRANSFORMED_ENVIRONMENT_V2_FORMAT_MOCK: Environment = { - v: EnvironmentSchemaVersion, - id: "clwudd68q00079rufju8uo3on", - name: "Response body sample", - variables: [ - { - key: "firstName", - initialValue: "John", - currentValue: "John", - secret: false, - }, - { - key: "lastName", - initialValue: "Doe", - currentValue: "Doe", - secret: false, - }, - { - key: "id", - initialValue: "7", - currentValue: "7", - secret: false, - }, - { - key: "fullName", - initialValue: "<> <>", - currentValue: "<> <>", - secret: false, - }, - { - key: "recursiveVarX", - initialValue: "<>", - currentValue: "<>", - secret: false, - }, - { - key: "recursiveVarY", - initialValue: "<>", - currentValue: "<>", - secret: false, - }, - { - key: "salutation", - initialValue: "Hello", - currentValue: "Hello", - secret: false, - }, - { - key: "greetText", - initialValue: "<> <>", - currentValue: "<> <>", - secret: false, - }, - ], -}; diff --git a/packages/hoppscotch-cli/src/__tests__/unit/getters.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/getters.spec.ts deleted file mode 100644 index 21304d5c..00000000 --- a/packages/hoppscotch-cli/src/__tests__/unit/getters.spec.ts +++ /dev/null @@ -1,507 +0,0 @@ -import axios, { AxiosError, AxiosResponse } from "axios"; -import fs from "fs/promises"; -import { describe, expect, test, vi } from "vitest"; - -import { - CollectionSchemaVersion, - HoppCollection, - getDefaultRESTRequest, -} from "@hoppscotch/data"; - -import { DEFAULT_DURATION_PRECISION } from "../../utils/constants"; -import { - getDurationInSeconds, - getEffectiveFinalMetaData, - getResolvedVariables, - getResourceContents, -} from "../../utils/getters"; -import * as mutators from "../../utils/mutators"; - -import * as workspaceAccessHelpers from "../../utils/workspace-access"; - -describe("getters", () => { - describe("getDurationInSeconds", () => { - const testDurations = [ - { end: [1, 111111111], precision: 1, expected: 1.1 }, - { end: [2, 333333333], precision: 2, expected: 2.33 }, - { - end: [3, 555555555], - precision: DEFAULT_DURATION_PRECISION, - expected: 3.556, - }, - { end: [4, 777777777], precision: 4, expected: 4.7778 }, - ]; - - test.each(testDurations)( - "($end.0 s + $end.1 ns) rounded-off to $expected", - ({ end, precision, expected }) => { - expect(getDurationInSeconds(end as [number, number], precision)).toBe( - expected - ); - } - ); - }); - - describe("getEffectiveFinalMetaData", () => { - const environmentVariables = [ - { - key: "PARAM", - initialValue: "parsed_param", - currentValue: "parsed_param", - secret: false, - }, - ]; - - test("Empty list of meta-data", () => { - expect( - getEffectiveFinalMetaData([], environmentVariables) - ).toSubsetEqualRight([]); - }); - - test("Non-empty active list of meta-data with unavailable ENV", () => { - expect( - getEffectiveFinalMetaData( - [ - { - active: true, - key: "<>", - value: "<>", - description: "", - }, - ], - environmentVariables - ) - ).toSubsetEqualRight([{ active: true, key: "", value: "" }]); - }); - - test("Inactive list of meta-data", () => { - expect( - getEffectiveFinalMetaData( - [{ active: false, key: "KEY", value: "<>", description: "" }], - environmentVariables - ) - ).toSubsetEqualRight([]); - }); - - test("Active list of meta-data", () => { - expect( - getEffectiveFinalMetaData( - [{ active: true, key: "PARAM", value: "<>", description: "" }], - environmentVariables - ) - ).toSubsetEqualRight([ - { active: true, key: "PARAM", value: "parsed_param" }, - ]); - }); - }); - - describe("getResourceContents", () => { - describe("Network call failure", () => { - const args = { - pathOrId: "test-collection-id-or-path", - resourceType: "collection" as const, - accessToken: "test-token", - serverUrl: "test-url", - }; - - const cases = [ - { - description: - "Promise rejects with the code `SERVER_CONNECTION_REFUSED` if the network call fails with the code `ECONNREFUSED`", - args, - axiosMock: { - code: "ECONNREFUSED", - }, - expected: { - code: "SERVER_CONNECTION_REFUSED", - data: args.serverUrl, - }, - }, - { - description: - "Promise rejects with the code `INVALID_SERVER_URL` if the network call fails with the code `ERR_INVALID_URL`", - args, - axiosMock: { - code: "ERR_INVALID_URL", - }, - expected: { - code: "INVALID_SERVER_URL", - data: args.serverUrl, - }, - }, - { - description: - "Promise rejects with the code `INVALID_SERVER_URL` if the network call fails with the code `ENOTFOUND`", - args, - axiosMock: { - code: "ENOTFOUND", - }, - expected: { - code: "INVALID_SERVER_URL", - data: args.serverUrl, - }, - }, - { - description: - "Promise rejects with the code `INVALID_SERVER_URL` if the network call returns a response with a status code of `404`", - args, - axiosMock: { - response: { - status: 404, - }, - }, - expected: { - code: "INVALID_SERVER_URL", - data: args.serverUrl, - }, - }, - { - description: - "Promise rejects with the code `TOKEN_EXPIRED` if the network call fails for the same reason", - args, - axiosMock: { - response: { - data: { - reason: "TOKEN_EXPIRED", - }, - }, - }, - expected: { - code: "TOKEN_EXPIRED", - data: args.accessToken, - }, - }, - { - description: - "Promise rejects with the code `TOKEN_INVALID` if the network call fails for the same reason", - args, - axiosMock: { - response: { - data: { - reason: "TOKEN_INVALID", - }, - }, - }, - expected: { - code: "TOKEN_INVALID", - data: args.accessToken, - }, - }, - { - description: - "Promise rejects with the code `INVALID_ID` if the network call fails for the same reason when the supplied collection ID or path is invalid", - args, - axiosMock: { - response: { - data: { - reason: "INVALID_ID", - }, - }, - }, - expected: { - code: "INVALID_ID", - data: args.pathOrId, - }, - }, - { - description: - "Promise rejects with the code `INVALID_ID` if the network call fails for the same reason when the supplied environment ID or path is invalid", - args: { - ...args, - pathOrId: "test-environment-id-or-path", - resourceType: "environment" as const, - }, - axiosMock: { - response: { - data: { - reason: "INVALID_ID", - }, - }, - }, - expected: { - code: "INVALID_ID", - data: "test-environment-id-or-path", - }, - }, - ]; - - test.each(cases)("$description", ({ args, axiosMock, expected }) => { - const { code, response } = axiosMock; - const axiosErrMessage = code ?? response?.data?.reason; - - vi.spyOn(axios, "get").mockImplementation(() => - Promise.reject( - new AxiosError( - axiosErrMessage, - code, - undefined, - undefined, - response as AxiosResponse - ) - ) - ); - - expect(getResourceContents(args)).rejects.toEqual(expected); - }); - - test("Promise rejects with the code `INVALID_SERVER_URL` if the network call succeeds and the received response content type is not `application/json`", () => { - const expected = { - code: "INVALID_SERVER_URL", - data: args.serverUrl, - }; - - vi.spyOn(axios, "get").mockImplementation(() => - Promise.resolve({ - data: "", - headers: { "content-type": "text/html; charset=UTF-8" }, - }) - ); - - expect(getResourceContents(args)).rejects.toEqual(expected); - }); - - test("Promise rejects with the code `UNKNOWN_ERROR` while encountering an error that is not an instance of `AxiosError`", () => { - const expected = { - code: "UNKNOWN_ERROR", - data: new Error("UNKNOWN_ERROR"), - }; - - vi.spyOn(axios, "get").mockImplementation(() => - Promise.reject(new Error("UNKNOWN_ERROR")) - ); - - expect(getResourceContents(args)).rejects.toEqual(expected); - }); - }); - - describe("Success", () => { - test("Proceeds with reading from the file system if the supplied file exists in the path", async () => { - fs.access = vi.fn().mockResolvedValueOnce(undefined); - - const sampleCollectionContents: HoppCollection = { - v: CollectionSchemaVersion, - id: "valid-collection-id", - name: "valid-collection-title", - folders: [], - requests: [], - headers: [], - auth: { - authType: "none", - authActive: false, - }, - }; - - axios.get = vi.fn(); - - vi.spyOn(mutators, "readJsonFile").mockImplementation(() => - Promise.resolve(sampleCollectionContents) - ); - - const pathOrId = "valid-collection-file-path"; - const resourceType = "collection"; - const accessToken = "valid-access-token"; - const serverUrl = "valid-url"; - - const contents = await getResourceContents({ - pathOrId, - accessToken, - serverUrl, - resourceType, - }); - - expect(fs.access).toHaveBeenCalledWith(pathOrId); - expect(axios.get).not.toBeCalled(); - expect(mutators.readJsonFile).toHaveBeenCalledWith(pathOrId, true); - - expect(contents).toEqual(sampleCollectionContents); - }); - - test("Proceeds with the network call if a value for the access token is specified and the supplied path/id is not a valid file path", async () => { - fs.access = vi.fn().mockRejectedValueOnce(undefined); - - const sampleCollectionContents: HoppCollection = { - v: CollectionSchemaVersion, - name: "test-coll", - folders: [], - requests: [getDefaultRESTRequest()], - headers: [], - auth: { - authType: "none", - authActive: false, - }, - }; - - axios.get = vi.fn().mockImplementation(() => - Promise.resolve({ - data: { - id: "clx06ik0o00028t6uwywwnxgg", - data: null, - title: "test-coll", - parentID: null, - folders: [], - requests: [ - { - id: "clx06imin00038t6uynt5vyk4", - collectionID: "clx06ik0o00028t6uwywwnxgg", - teamID: "clwt6r6j10031kc6pu0b08y6e", - title: "req1", - request: - '{"v":"4","auth":{"authType":"inherit","authActive":true},"body":{"body":null,"contentType":null},"name":"req1","method":"GET","params":[],"headers":[],"endpoint":"https://echo.hoppscotch.io","testScript":"","preRequestScript":"","requestVariables":[]}', - }, - ], - }, - headers: { - "content-type": "application/json", - }, - }) - ); - - const readJsonFileSpy = vi - .spyOn(mutators, "readJsonFile") - .mockImplementation(() => Promise.resolve(sampleCollectionContents)); - - vi.spyOn( - workspaceAccessHelpers, - "transformWorkspaceCollections" - ).mockImplementation(() => [sampleCollectionContents]); - - const pathOrId = "valid-collection-id"; - const resourceType = "collection"; - const accessToken = "valid-access-token"; - const serverUrl = "valid-url"; - - // Clear spy calls from setup - readJsonFileSpy.mockClear(); - - await getResourceContents({ - pathOrId, - accessToken, - serverUrl, - resourceType, - }); - - expect(fs.access).toHaveBeenCalledWith(pathOrId); - expect(axios.get).toBeCalledWith( - `${serverUrl}/v1/access-tokens/${resourceType}/${pathOrId}`, - { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - } - ); - expect( - workspaceAccessHelpers.transformWorkspaceCollections - ).toBeCalled(); - expect(readJsonFileSpy).not.toHaveBeenCalled(); - }); - }); - }); - - describe("getResolvedVariables", () => { - const requestVariables = [ - { - key: "SHARED_KEY_I", - value: "request-variable-shared-value-I", - active: true, - }, - { - key: "SHARED_KEY_II", - value: "", - active: true, - }, - { - key: "REQUEST_VAR_III", - value: "request-variable-value-III", - active: true, - }, - { - key: "REQUEST_VAR_IV", - value: "request-variable-value-IV", - active: false, - }, - { - key: "REQUEST_VAR_V", - value: "request-variable-value-V", - active: false, - }, - ]; - - const environmentVariables = [ - { - key: "SHARED_KEY_I", - initialValue: "environment-variable-shared-value-I", - currentValue: "environment-variable-shared-value-I", - secret: false, - }, - { - key: "SHARED_KEY_II", - initialValue: "environment-variable-shared-value-II", - currentValue: "environment-variable-shared-value-II", - secret: false, - }, - { - key: "ENV_VAR_III", - initialValue: "environment-variable-value-III", - currentValue: "environment-variable-value-III", - secret: false, - }, - { - key: "ENV_VAR_IV", - initialValue: "environment-variable-value-IV", - currentValue: "environment-variable-value-IV", - secret: false, - }, - { - key: "ENV_VAR_V", - initialValue: "environment-variable-value-V", - currentValue: "environment-variable-value-V", - secret: false, - }, - ]; - - test("Filters request variables by active status and value fields, then remove environment variables sharing the same keys", () => { - const expected = [ - { - key: "SHARED_KEY_I", - currentValue: "request-variable-shared-value-I", - initialValue: "request-variable-shared-value-I", - secret: false, - }, - { - key: "REQUEST_VAR_III", - currentValue: "request-variable-value-III", - initialValue: "request-variable-value-III", - secret: false, - }, - { - key: "SHARED_KEY_II", - currentValue: "environment-variable-shared-value-II", - initialValue: "environment-variable-shared-value-II", - secret: false, - }, - { - key: "ENV_VAR_III", - currentValue: "environment-variable-value-III", - initialValue: "environment-variable-value-III", - secret: false, - }, - { - key: "ENV_VAR_IV", - currentValue: "environment-variable-value-IV", - initialValue: "environment-variable-value-IV", - secret: false, - }, - { - key: "ENV_VAR_V", - currentValue: "environment-variable-value-V", - initialValue: "environment-variable-value-V", - secret: false, - }, - ]; - - expect( - getResolvedVariables(requestVariables, environmentVariables) - ).toEqual(expected); - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/unit/hopp-fetch.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/hopp-fetch.spec.ts deleted file mode 100644 index 5bf6bc2d..00000000 --- a/packages/hoppscotch-cli/src/__tests__/unit/hopp-fetch.spec.ts +++ /dev/null @@ -1,579 +0,0 @@ -import { describe, expect, it, vi, beforeEach } from "vitest" - -// Mock modules before imports - NO external variable references in factory -vi.mock("axios", () => ({ - default: { - create: vi.fn(), - isAxiosError: vi.fn(), - }, -})) - -vi.mock("axios-cookiejar-support", () => ({ - wrapper: (instance: any) => instance, -})) - -vi.mock("tough-cookie", () => ({ - CookieJar: vi.fn(), -})) - -import { createHoppFetchHook } from "../../utils/hopp-fetch" -import axios from "axios" - -// Get the mocked functions to use in tests -const mockAxios = axios as any -const mockIsAxiosError = mockAxios.isAxiosError as ReturnType - -// Create the axios instance mock that will be returned by create() -const mockAxiosInstance = vi.fn() - -describe("CLI hopp-fetch", () => { - beforeEach(() => { - vi.clearAllMocks() - - // Set up axios.create to return our mockAxiosInstance - mockAxios.create.mockReturnValue(mockAxiosInstance) - - // Default successful response - mockAxiosInstance.mockResolvedValue({ - status: 200, - statusText: "OK", - headers: { "content-type": "application/json" }, - data: new ArrayBuffer(0), - }) - - // Reset isAxiosError mock - mockIsAxiosError.mockReturnValue(false) - }) - - describe("Request object property extraction", () => { - it("should extract method from Request object", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data", { - method: "POST", - }) - - await hoppFetch(request) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - method: "POST", - }) - ) - }) - - it("should extract headers from Request object", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data", { - headers: { - "X-Custom-Header": "test-value", - Authorization: "Bearer token123", - }, - }) - - await hoppFetch(request) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - "x-custom-header": "test-value", - authorization: "Bearer token123", - }), - }) - ) - }) - - it("should extract body from Request object", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data", { - method: "POST", - body: JSON.stringify({ key: "value" }), - }) - - await hoppFetch(request) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - data: expect.any(ArrayBuffer), // Body is converted to ArrayBuffer - }) - ) - }) - - it("should prefer init options over Request properties (method)", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data", { - method: "POST", - }) - - // Init overrides Request method - await hoppFetch(request, { method: "PUT" }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - method: "PUT", - }) - ) - }) - - it("should prefer init headers over Request headers", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data", { - headers: { "X-Custom": "from-request" }, - }) - - // Init overrides Request headers - await hoppFetch(request, { - headers: { "X-Custom": "from-init" }, - }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - "X-Custom": "from-init", - }), - }) - ) - }) - - it("should merge Request headers with init headers", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data", { - headers: { "X-Request-Header": "value1" }, - }) - - await hoppFetch(request, { - headers: { "X-Init-Header": "value2" }, - }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - "x-request-header": "value1", - "X-Init-Header": "value2", - }), - }) - ) - }) - - it("should extract all properties from Request object", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data", { - method: "PATCH", - headers: { - "Content-Type": "application/json", - "X-API-Key": "secret", - }, - body: JSON.stringify({ update: true }), - }) - - await hoppFetch(request) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - url: "https://api.example.com/data", - method: "PATCH", - headers: expect.objectContaining({ - "content-type": "application/json", - "x-api-key": "secret", - }), - data: expect.any(ArrayBuffer), - }) - ) - }) - }) - - describe("Standard fetch patterns", () => { - it("should handle string URLs", async () => { - const hoppFetch = createHoppFetchHook() - - await hoppFetch("https://api.example.com/data") - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - url: "https://api.example.com/data", - method: "GET", - }) - ) - }) - - it("should handle URL objects", async () => { - const hoppFetch = createHoppFetchHook() - - const url = new URL("https://api.example.com/data") - await hoppFetch(url) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - url: "https://api.example.com/data", - }) - ) - }) - - it("should handle init options with string URL", async () => { - const hoppFetch = createHoppFetchHook() - - await hoppFetch("https://api.example.com/data", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ test: true }), - }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - url: "https://api.example.com/data", - method: "POST", - headers: expect.objectContaining({ - "Content-Type": "application/json", - }), - data: JSON.stringify({ test: true }), - }) - ) - }) - }) - - describe("Edge cases", () => { - it("should default to GET when no method specified", async () => { - const hoppFetch = createHoppFetchHook() - - await hoppFetch("https://api.example.com/data") - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - method: "GET", - }) - ) - }) - - it("should handle Request with no headers", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data") - - await hoppFetch(request) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - headers: {}, - }) - ) - }) - - it("should handle Request with no body", async () => { - const hoppFetch = createHoppFetchHook() - - const request = new Request("https://api.example.com/data") - - await hoppFetch(request) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - data: undefined, - }) - ) - }) - - it("should handle FormData body", async () => { - const hoppFetch = createHoppFetchHook() - - const formData = new FormData() - formData.append("key", "value") - - await hoppFetch("https://api.example.com/data", { - method: "POST", - body: formData, - }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - data: formData, - }) - ) - }) - - it("should handle Blob body", async () => { - const hoppFetch = createHoppFetchHook() - - const blob = new Blob(["test data"], { type: "text/plain" }) - - await hoppFetch("https://api.example.com/data", { - method: "POST", - body: blob, - }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - data: blob, - }) - ) - }) - - it("should handle ArrayBuffer body", async () => { - const hoppFetch = createHoppFetchHook() - - const buffer = new ArrayBuffer(8) - - await hoppFetch("https://api.example.com/data", { - method: "POST", - body: buffer, - }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - data: buffer, - }) - ) - }) - - it("should convert Headers object to plain object", async () => { - const hoppFetch = createHoppFetchHook() - - const headers = new Headers({ - "X-Custom": "value", - "Content-Type": "application/json", - }) - - await hoppFetch("https://api.example.com/data", { - headers, - }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - "x-custom": "value", - "content-type": "application/json", - }), - }) - ) - }) - - it("should convert headers array to plain object", async () => { - const hoppFetch = createHoppFetchHook() - - const headers: [string, string][] = [ - ["X-Custom", "value"], - ["Content-Type", "application/json"], - ] - - await hoppFetch("https://api.example.com/data", { - headers, - }) - - expect(mockAxiosInstance).toHaveBeenCalledWith( - expect.objectContaining({ - headers: expect.objectContaining({ - "X-Custom": "value", - "Content-Type": "application/json", - }), - }) - ) - }) - }) - - describe("Response handling", () => { - it("should return response with correct status and statusText", async () => { - const hoppFetch = createHoppFetchHook() - - mockAxiosInstance.mockResolvedValue({ - status: 201, - statusText: "Created", - headers: {}, - data: new ArrayBuffer(0), - }) - - const response = await hoppFetch("https://api.example.com/data") - - expect(response.status).toBe(201) - expect(response.statusText).toBe("Created") - }) - - it("should set ok to true for 2xx status codes", async () => { - const hoppFetch = createHoppFetchHook() - - mockAxiosInstance.mockResolvedValue({ - status: 200, - statusText: "OK", - headers: {}, - data: new ArrayBuffer(0), - }) - - const response = await hoppFetch("https://api.example.com/data") - - expect(response.ok).toBe(true) - }) - - it("should set ok to false for non-2xx status codes", async () => { - const hoppFetch = createHoppFetchHook() - - mockAxiosInstance.mockResolvedValue({ - status: 404, - statusText: "Not Found", - headers: {}, - data: new ArrayBuffer(0), - }) - - const response = await hoppFetch("https://api.example.com/data") - - expect(response.ok).toBe(false) - }) - - it("should convert response headers to serializable format", async () => { - const hoppFetch = createHoppFetchHook() - - mockAxiosInstance.mockResolvedValue({ - status: 200, - statusText: "OK", - headers: { - "content-type": "application/json", - "x-custom-header": "value", - }, - data: new ArrayBuffer(0), - }) - - const response = await hoppFetch("https://api.example.com/data") - - expect(response.headers.get("content-type")).toBe("application/json") - expect(response.headers.get("x-custom-header")).toBe("value") - }) - - it("should handle Set-Cookie headers as array", async () => { - const hoppFetch = createHoppFetchHook() - - mockAxiosInstance.mockResolvedValue({ - status: 200, - statusText: "OK", - headers: { - "set-cookie": ["session=abc123", "token=xyz789"], - }, - data: new ArrayBuffer(0), - }) - - const response = await hoppFetch("https://api.example.com/data") - - expect(response.headers.getSetCookie()).toEqual([ - "session=abc123", - "token=xyz789", - ]) - }) - - it("should handle single Set-Cookie header as string", async () => { - const hoppFetch = createHoppFetchHook() - - mockAxiosInstance.mockResolvedValue({ - status: 200, - statusText: "OK", - headers: { - "set-cookie": "session=abc123", - }, - data: new ArrayBuffer(0), - }) - - const response = await hoppFetch("https://api.example.com/data") - - expect(response.headers.getSetCookie()).toEqual(["session=abc123"]) - }) - - it("should convert response body ArrayBuffer to byte array", async () => { - const hoppFetch = createHoppFetchHook() - - const data = new Uint8Array([72, 101, 108, 108, 111]) // "Hello" - mockAxiosInstance.mockResolvedValue({ - status: 200, - statusText: "OK", - headers: {}, - data: data.buffer, - }) - - const response = await hoppFetch("https://api.example.com/data") - - expect((response as any)._bodyBytes).toEqual([72, 101, 108, 108, 111]) - }) - - it("should handle response body text conversion", async () => { - const hoppFetch = createHoppFetchHook() - - const data = new TextEncoder().encode("Hello World") - mockAxiosInstance.mockResolvedValue({ - status: 200, - statusText: "OK", - headers: {}, - data: data.buffer, - }) - - const response = await hoppFetch("https://api.example.com/data") - const text = await response.text() - - expect(text).toBe("Hello World") - }) - - it("should handle response body json conversion", async () => { - const hoppFetch = createHoppFetchHook() - - const jsonData = { message: "success" } - const data = new TextEncoder().encode(JSON.stringify(jsonData)) - mockAxiosInstance.mockResolvedValue({ - status: 200, - statusText: "OK", - headers: {}, - data: data.buffer, - }) - - const response = await hoppFetch("https://api.example.com/data") - const json = await response.json() - - expect(json).toEqual(jsonData) - }) - }) - - describe("Error handling", () => { - it("should handle axios error with response", async () => { - const hoppFetch = createHoppFetchHook() - - const errorResponse = { - status: 500, - statusText: "Internal Server Error", - headers: {}, - data: new ArrayBuffer(0), - } - - mockAxiosInstance.mockRejectedValue({ - response: errorResponse, - isAxiosError: true, - }) - mockIsAxiosError.mockReturnValue(true) - - const response = await hoppFetch("https://api.example.com/data") - - expect(response.status).toBe(500) - expect(response.statusText).toBe("Internal Server Error") - }) - - it("should throw error for network failure without response", async () => { - const hoppFetch = createHoppFetchHook() - - const networkError = new Error("Network Error") - mockAxiosInstance.mockRejectedValue(networkError) - mockIsAxiosError.mockReturnValue(false) - - await expect(hoppFetch("https://api.example.com/data")).rejects.toThrow( - "Fetch failed: Network Error" - ) - }) - - it("should throw error for non-Error exceptions", async () => { - const hoppFetch = createHoppFetchHook() - - mockAxiosInstance.mockRejectedValue("String error") - mockIsAxiosError.mockReturnValue(false) - - await expect(hoppFetch("https://api.example.com/data")).rejects.toThrow( - "Fetch failed: Unknown error" - ) - }) - }) -}) diff --git a/packages/hoppscotch-cli/src/__tests__/unit/jsonc.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/jsonc.spec.ts deleted file mode 100644 index 9b4fcd78..00000000 --- a/packages/hoppscotch-cli/src/__tests__/unit/jsonc.spec.ts +++ /dev/null @@ -1,151 +0,0 @@ -import { describe, expect, test } from "vitest"; -import { stripComments } from "../../utils/jsonc"; - -describe("stripComments", () => { - describe("handles inline comments", () => { - test("removes single inline comment", () => { - const input = '{"key": "value" // comment\n}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ key: "value" }); - }); - - test("removes multiple inline comments", () => { - const input = '{\n "key1": "value1", // comment1\n "key2": "value2" // comment2\n}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ key1: "value1", key2: "value2" }); - }); - }); - - describe("handles multiline comments", () => { - test("removes single multiline comment", () => { - const input = '{\n /* This is a comment */\n "key": "value"\n}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ key: "value" }); - }); - - test("removes multiline comment spanning multiple lines", () => { - const input = '{\n /* This is\n a multiline\n comment */\n "key": "value"\n}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ key: "value" }); - }); - }); - - describe("handles trailing commas", () => { - test("removes trailing comma in object", () => { - const input = '{"key": "value",}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ key: "value" }); - }); - - test("removes trailing comma in array", () => { - const input = '["item1", "item2",]'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual(["item1", "item2"]); - }); - - test("removes multiple trailing commas in nested structures", () => { - const input = '{"arr": ["a", "b",], "obj": {"key": "value",},}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ arr: ["a", "b"], obj: { key: "value" } }); - }); - }); - - describe("handles combined cases", () => { - test("removes both comments and trailing commas", () => { - const input = '{\n "key1": "value1", // inline comment\n /* block comment */\n "key2": "value2",\n}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ key1: "value1", key2: "value2" }); - }); - - test("handles nested objects with comments and trailing commas", () => { - const input = '{\n "outer": { // comment\n "inner": "value",\n },\n}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ outer: { inner: "value" } }); - }); - }); - - describe("handles edge cases", () => { - test("returns empty string unchanged", () => { - const input = ""; - const result = stripComments(input); - expect(result).toBe(""); - }); - - test("returns whitespace-only string unchanged", () => { - const input = " \n \t "; - const result = stripComments(input); - expect(result).toBe(input); - }); - - test("handles valid JSON without comments", () => { - const input = '{"key": "value"}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ key: "value" }); - }); - - test("preserves JSON strings containing comment-like sequences", () => { - const input = '{"url": "https://example.com//path"}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed.url).toBe("https://example.com//path"); - }); - - test("handles deeply nested structures", () => { - const input = '{\n "a": {\n "b": {\n "c": {\n "d": "value", // nested comment\n },\n },\n },\n}'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ a: { b: { c: { d: "value" } } } }); - }); - - test("handles arrays with mixed content", () => { - const input = '[\n "string",\n 123, // number\n true, // boolean\n null, // null\n {"nested": "object",}, // object\n]'; - const result = stripComments(input); - const parsed = JSON.parse(result); - expect(parsed).toEqual(["string", 123, true, null, { nested: "object" }]); - }); - }); - - describe("handles null return from stripComments_", () => { - test("gracefully handles potential null from jsonc-parser", () => { - const input = '{"key": "value"}'; - const result = stripComments(input); - expect(result).toBeTruthy(); - const parsed = JSON.parse(result); - expect(parsed).toEqual({ key: "value" }); - }); - }); - - describe("handles malformed JSON", () => { - test("attempts to parse malformed JSON and returns result", () => { - // jsonc-parser is lenient and tries to repair malformed JSON - const input = '{"key": "value"'; // missing closing brace - const result = stripComments(input); - // The parser will attempt to close the brace - expect(result).toBe('{"key":"value"}'); - }); - - test("gracefully handles completely invalid JSON", () => { - const input = 'this is not json at all {]}{]'; - const result = stripComments(input); - // jsonc-parser extracts what it can and returns an object (even if mostly empty) - expect(result).toBe('{}'); - }); - - test("handles JSON with syntax errors", () => { - const input = '{"key": undefined}'; // undefined is not valid JSON - const result = stripComments(input); - // Parser will handle this - exact behavior depends on jsonc-parser - expect(typeof result).toBe('string'); - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/unit/pre-request-inheritance.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/pre-request-inheritance.spec.ts deleted file mode 100644 index d101b44c..00000000 --- a/packages/hoppscotch-cli/src/__tests__/unit/pre-request-inheritance.spec.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { describe, expect, test } from "vitest"; -import { makeRESTRequest } from "@hoppscotch/data"; -import * as E from "fp-ts/Either"; - -import { preRequestScriptRunner } from "../../utils/pre-request"; -import { HoppEnvs } from "../../types/request"; - -const SAMPLE_ENVS: HoppEnvs = { - global: [], - selected: [], -}; - -const SAMPLE_REQUEST = makeRESTRequest({ - name: "request", - method: "GET", - endpoint: "https://example.com", - params: [], - headers: [], - preRequestScript: "", - testScript: "", - auth: { authActive: false, authType: "none" }, - body: { - contentType: null, - body: null, - }, - requestVariables: [], - description: null, - responses: {}, -}); - -describe("preRequestScriptRunner - inheritance", () => { - test("Inherited scripts execute in root → parent → request order", async () => { - const rootScript = `pw.env.set("ORDER", "root");`; - const parentScript = ` - const prev = pw.env.get("ORDER"); - pw.env.set("ORDER", prev + ",parent"); - `; - const request = makeRESTRequest({ - ...SAMPLE_REQUEST, - preRequestScript: ` - const prev = pw.env.get("ORDER"); - pw.env.set("ORDER", prev + ",request"); - `, - }); - - const result = await preRequestScriptRunner( - request, - SAMPLE_ENVS, - false, - undefined, - [rootScript, parentScript] - )(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const orderVar = result.right.updatedEnvs.selected.find( - (v) => v.key === "ORDER" - ); - expect(orderVar?.currentValue).toBe("root,parent,request"); - } - }); - - test("Inherited scripts set ENVs used in request endpoint resolution", async () => { - const rootScript = `pw.env.set("ENDPOINT", "https://example.com");`; - - const request = makeRESTRequest({ - ...SAMPLE_REQUEST, - endpoint: "<>", - preRequestScript: "", - }); - - const result = await preRequestScriptRunner( - request, - SAMPLE_ENVS, - false, - undefined, - [rootScript] - )(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - expect(result.right.effectiveRequest.effectiveFinalURL).toBe( - "https://example.com" - ); - } - }); - - test("Scripts with same local variable names do not collide (IIFE isolation)", async () => { - const rootScript = `const x = "root"; pw.env.set("ROOT_VAR", x);`; - const parentScript = `const x = "parent"; pw.env.set("PARENT_VAR", x);`; - - const request = makeRESTRequest({ - ...SAMPLE_REQUEST, - preRequestScript: `const x = "request"; pw.env.set("REQUEST_VAR", x);`, - }); - - const result = await preRequestScriptRunner( - request, - SAMPLE_ENVS, - false, - undefined, - [rootScript, parentScript] - )(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const envVars = result.right.updatedEnvs.selected; - expect(envVars.find((v) => v.key === "ROOT_VAR")?.currentValue).toBe( - "root" - ); - expect(envVars.find((v) => v.key === "PARENT_VAR")?.currentValue).toBe( - "parent" - ); - expect(envVars.find((v) => v.key === "REQUEST_VAR")?.currentValue).toBe( - "request" - ); - } - }); - - test("Empty inherited scripts are filtered out gracefully", async () => { - const validScript = `pw.env.set("ENDPOINT", "https://example.com");`; - - const request = makeRESTRequest({ - ...SAMPLE_REQUEST, - endpoint: "<>", - preRequestScript: "", - }); - - const result = await preRequestScriptRunner( - request, - SAMPLE_ENVS, - false, - undefined, - ["", " ", validScript, "\n"] - )(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - expect(result.right.effectiveRequest.effectiveFinalURL).toBe( - "https://example.com" - ); - } - }); - - test("Works correctly with no inherited scripts (backward compatibility)", async () => { - const request = makeRESTRequest({ - ...SAMPLE_REQUEST, - endpoint: "<>", - preRequestScript: `pw.env.set("ENDPOINT", "https://example.com");`, - }); - - const result = await preRequestScriptRunner( - request, - SAMPLE_ENVS, - false, - undefined, - [] - )(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - expect(result.right.effectiveRequest.effectiveFinalURL).toBe( - "https://example.com" - ); - } - }); - - // Regression: in the legacy (isolated-vm) sandbox, inherited scripts must - // execute sequentially in order. Pre-fix combineScriptsWithIIFE emitted an - // outer detached Promise that script.run did not await; sequential ordering - // was undefined. - // - // Note: the unit test exercises the sequential-ordering path. The - // post-`await` drop only surfaces with macrotask awaits (setTimeout) or - // cross-isolate Reference calls returning Promises — neither is exposed - // through the synchronous `pw.*` surface in node/legacy.ts, so it is not - // currently user-reachable in the CLI. The web worker path is where the - // post-`await` drop is user-reachable; covered by the smoke fixture in - // packages/hoppscotch-cli/src/__tests__/e2e/. - test("Legacy sandbox executes inherited scripts in order", async () => { - const rootScript = `pw.env.set("ORDER", "root");`; - const parentScript = ` - const prev = pw.env.get("ORDER"); - pw.env.set("ORDER", prev + ",parent"); - `; - const request = makeRESTRequest({ - ...SAMPLE_REQUEST, - preRequestScript: ` - const prev = pw.env.get("ORDER"); - pw.env.set("ORDER", prev + ",request"); - `, - }); - - const result = await preRequestScriptRunner( - request, - SAMPLE_ENVS, - true, - undefined, - [rootScript, parentScript] - )(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const orderVar = result.right.updatedEnvs.selected.find( - (v) => v.key === "ORDER" - ); - expect(orderVar?.currentValue).toBe("root,parent,request"); - } - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/unit/scripting.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/scripting.spec.ts deleted file mode 100644 index a2aa4d46..00000000 --- a/packages/hoppscotch-cli/src/__tests__/unit/scripting.spec.ts +++ /dev/null @@ -1,168 +0,0 @@ -import { describe, expect, test } from "vitest"; - -import { - combineScriptsWithIIFE, - stripModulePrefix, - MODULE_PREFIX, -} from "../../utils/scripting"; - -describe("scripting", () => { - describe("stripModulePrefix", () => { - test("strips 'export {};\\n' prefix", () => { - expect(stripModulePrefix("export {};\nconst x = 1;")).toBe( - "const x = 1;" - ); - }); - - test("strips 'export {};' prefix without newline", () => { - expect(stripModulePrefix("export {};const x = 1;")).toBe("const x = 1;"); - }); - - test("returns script unchanged if no prefix", () => { - expect(stripModulePrefix("const x = 1;")).toBe("const x = 1;"); - }); - - test("returns empty string unchanged", () => { - expect(stripModulePrefix("")).toBe(""); - }); - }); - - describe("combineScriptsWithIIFE", () => { - test("returns empty string for empty array", () => { - expect(combineScriptsWithIIFE([])).toBe(""); - }); - - test("returns empty string when all scripts are empty", () => { - expect(combineScriptsWithIIFE(["", " ", "\n"])).toBe(""); - }); - - test("wraps a single script in a sequential async IIFE", () => { - const result = combineScriptsWithIIFE(["const x = 1;"]); - - expect(result).toContain("async"); - expect(result).toContain("await"); - expect(result).toContain("const x = 1;"); - }); - - test("preserves script order (root → parent → child → request) for pre-request scripts", () => { - const rootScript = 'pw.env.set("token", "root");'; - const parentScript = 'pw.env.set("parent", "true");'; - const requestScript = 'pw.env.set("request", "true");'; - - const result = combineScriptsWithIIFE([ - rootScript, - parentScript, - requestScript, - ]); - - const rootIndex = result.indexOf(rootScript); - const parentIndex = result.indexOf(parentScript); - const requestIndex = result.indexOf(requestScript); - - expect(rootIndex).toBeLessThan(parentIndex); - expect(parentIndex).toBeLessThan(requestIndex); - }); - - test("preserves script order (request → child → parent → root) for test scripts", () => { - const requestScript = 'pw.test("request test", () => {});'; - const childScript = 'pw.test("child test", () => {});'; - const rootScript = 'pw.test("root test", () => {});'; - - // Simulates the reversal pattern used in test runner: - // combineScriptsWithIIFE([requestScript, ...inheritedTestScripts.slice().reverse()]) - const inheritedTestScripts = [rootScript, childScript]; - const result = combineScriptsWithIIFE([ - requestScript, - ...inheritedTestScripts.slice().reverse(), - ]); - - const requestIndex = result.indexOf(requestScript); - const childIndex = result.indexOf(childScript); - const rootIndex = result.indexOf(rootScript); - - expect(requestIndex).toBeLessThan(childIndex); - expect(childIndex).toBeLessThan(rootIndex); - }); - - test("filters out empty scripts while preserving non-empty ones", () => { - const script1 = "const a = 1;"; - const script2 = "const b = 2;"; - - const result = combineScriptsWithIIFE([script1, "", " ", script2]); - - expect(result).toContain(script1); - expect(result).toContain(script2); - - // Should only have 2 await statements (not 4) - const awaitCount = (result.match(/await/g) || []).length; - expect(awaitCount).toBe(2); - }); - - test("isolates variable scope between scripts (each wrapped in its own function)", () => { - const script1 = "const x = 1;"; - const script2 = "const x = 2;"; - - const result = combineScriptsWithIIFE([script1, script2]); - - // Both scripts should appear in separate async functions - const fnCount = (result.match(/async function\(\)/g) || []).length; - expect(fnCount).toBe(2); - }); - - test("strips module prefix from scripts before wrapping", () => { - const script = `${MODULE_PREFIX}const x = 1;`; - - const result = combineScriptsWithIIFE([script]); - - // The module prefix should be stripped - expect(result).not.toContain("export {};"); - expect(result).toContain("const x = 1;"); - }); - - test("experimental target generates sequential await chain wrapped in try/catch", () => { - const result = combineScriptsWithIIFE( - ["const a = 1;", "const b = 2;", "const c = 3;"], - "experimental" - ); - - // Outer wrapper captures the reporter lexically so user code that - // deletes the globalThis property cannot suppress error reporting. - expect(result).toMatch( - /^const __hoppReporter = globalThis\.__hoppReportScriptExecutionError;\s*try \{/ - ); - expect(result).toContain("await (async function() {"); - // Each script contributes one `await` in the body. - const awaitCount = (result.match(/\bawait\b/g) || []).length; - expect(awaitCount).toBe(3); - // Catch hands the error to the lexically captured reporter. - expect(result).toContain( - "} catch (__hoppScriptExecutionError) {" - ); - expect(result).toContain("__hoppReporter(__hoppScriptExecutionError);"); - }); - - test("legacy target generates sync IIFE chain with no await", () => { - const result = combineScriptsWithIIFE( - ["const a = 1;", "const b = 2;", "const c = 3;"], - "legacy" - ); - - // No `async` keyword, no `await` — legacy sandbox is sync-only. - expect(result).not.toContain("async"); - expect(result).not.toContain("await"); - // Leading `;` guards against ASI on the host script. - expect(result).toMatch(/^;\(function\(\) \{/); - // Each script wrapped in its own IIFE - const iifeCount = (result.match(/\.call\(this\);/g) || []).length; - expect(iifeCount).toBe(3); - }); - - test("default target is experimental (wrapped in try/catch)", () => { - const result = combineScriptsWithIIFE(["const x = 1;"]); - expect(result).toMatch( - /^const __hoppReporter = globalThis\.__hoppReportScriptExecutionError;\s*try \{/ - ); - expect(result).toContain("await (async function() {"); - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/unit/test-runner-inheritance.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/test-runner-inheritance.spec.ts deleted file mode 100644 index 9e371aa7..00000000 --- a/packages/hoppscotch-cli/src/__tests__/unit/test-runner-inheritance.spec.ts +++ /dev/null @@ -1,234 +0,0 @@ -import { describe, expect, test } from "vitest"; -import { makeRESTRequest } from "@hoppscotch/data"; -import * as E from "fp-ts/Either"; - -import { testRunner } from "../../utils/test"; -import { HoppEnvs } from "../../types/request"; - -const SAMPLE_ENVS: HoppEnvs = { - global: [], - selected: [], -}; - -const SAMPLE_RESPONSE = { - status: 200, - headers: [], - body: {}, - statusText: "OK", - responseTime: 100, -}; - -const SAMPLE_REQUEST = makeRESTRequest({ - name: "request", - method: "GET", - endpoint: "https://example.com", - params: [], - headers: [], - preRequestScript: "", - testScript: "", - auth: { authActive: false, authType: "none" }, - body: { - contentType: null, - body: null, - }, - requestVariables: [], - description: null, - responses: {}, -}); - -describe("testRunner - inheritance", () => { - test("Inherited test scripts are executed and register test cases", async () => { - const rootTestScript = ` - pw.test("Root collection test", () => { - pw.expect(pw.response.status).toBe(200); - }); - `; - - const result = await testRunner({ - request: makeRESTRequest({ - ...SAMPLE_REQUEST, - testScript: ` - pw.test("Request test", () => { - pw.expect(pw.response.status).toBe(200); - }); - `, - }), - envs: SAMPLE_ENVS, - response: SAMPLE_RESPONSE, - legacySandbox: false, - inheritedTestScripts: [rootTestScript], - })(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const { testsReport } = result.right; - const descriptors = testsReport.map((r) => r.descriptor); - - expect(descriptors).toContain("Request test"); - expect(descriptors).toContain("Root collection test"); - } - }); - - test("Inherited test scripts execute in request → child → parent → root order", async () => { - const rootTestScript = ` - const prev = pw.env.get("ORDER"); - pw.env.set("ORDER", prev + ",root"); - `; - const parentTestScript = ` - const prev = pw.env.get("ORDER"); - pw.env.set("ORDER", prev + ",parent"); - `; - - const result = await testRunner({ - request: makeRESTRequest({ - ...SAMPLE_REQUEST, - testScript: `pw.env.set("ORDER", "request");`, - }), - envs: SAMPLE_ENVS, - response: SAMPLE_RESPONSE, - legacySandbox: false, - // Stored as root → parent, reversed to parent → root during execution - inheritedTestScripts: [rootTestScript, parentTestScript], - })(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const orderVar = result.right.envs.selected.find( - (v) => v.key === "ORDER" - ); - expect(orderVar?.currentValue).toBe("request,parent,root"); - } - }); - - test("Scripts with same local variable names do not collide (IIFE isolation)", async () => { - const rootTestScript = `const x = "root"; pw.env.set("ROOT_VAR", x);`; - const parentTestScript = `const x = "parent"; pw.env.set("PARENT_VAR", x);`; - - const result = await testRunner({ - request: makeRESTRequest({ - ...SAMPLE_REQUEST, - testScript: `const x = "request"; pw.env.set("REQUEST_VAR", x);`, - }), - envs: SAMPLE_ENVS, - response: SAMPLE_RESPONSE, - legacySandbox: false, - inheritedTestScripts: [rootTestScript, parentTestScript], - })(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const envVars = result.right.envs.selected; - expect(envVars.find((v) => v.key === "ROOT_VAR")?.currentValue).toBe( - "root" - ); - expect(envVars.find((v) => v.key === "PARENT_VAR")?.currentValue).toBe( - "parent" - ); - expect(envVars.find((v) => v.key === "REQUEST_VAR")?.currentValue).toBe( - "request" - ); - } - }); - - test("Empty inherited test scripts are filtered out gracefully", async () => { - const validScript = ` - pw.test("Valid inherited test", () => { - pw.expect(pw.response.status).toBe(200); - }); - `; - - const result = await testRunner({ - request: makeRESTRequest({ - ...SAMPLE_REQUEST, - testScript: ` - pw.test("Request test", () => { - pw.expect(pw.response.status).toBe(200); - }); - `, - }), - envs: SAMPLE_ENVS, - response: SAMPLE_RESPONSE, - legacySandbox: false, - inheritedTestScripts: ["", " ", validScript, "\n"], - })(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const { testsReport } = result.right; - const descriptors = testsReport.map((r) => r.descriptor); - - expect(descriptors).toContain("Request test"); - expect(descriptors).toContain("Valid inherited test"); - } - }); - - test("Works correctly with no inherited test scripts (backward compatibility)", async () => { - const result = await testRunner({ - request: makeRESTRequest({ - ...SAMPLE_REQUEST, - testScript: ` - pw.test("Solo request test", () => { - pw.expect(pw.response.status).toBe(200); - }); - `, - }), - envs: SAMPLE_ENVS, - response: SAMPLE_RESPONSE, - legacySandbox: false, - inheritedTestScripts: [], - })(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const { testsReport } = result.right; - expect(testsReport.map((r) => r.descriptor)).toContain( - "Solo request test" - ); - } - }); - - // Regression: in the legacy (isolated-vm) sandbox, all `pw.test` blocks - // declared in inherited test scripts must register before the runner - // captures results. Pre-fix combineScriptsWithIIFE emitted an outer - // detached Promise so the registration order was undefined when multiple - // inherited scripts were present. - // - // Note: the post-`await` drop is not currently user-reachable here either - // (see pre-request-inheritance.spec.ts for context). User-facing coverage - // for the web worker async path is in packages/hoppscotch-cli/src/__tests__/e2e/. - test("Legacy sandbox registers inherited test scripts", async () => { - const rootTestScript = ` - pw.test("Root collection test", () => { - pw.expect(pw.response.status).toBe(200); - }); - `; - - const result = await testRunner({ - request: makeRESTRequest({ - ...SAMPLE_REQUEST, - testScript: ` - pw.test("Request test", () => { - pw.expect(pw.response.status).toBe(200); - }); - `, - }), - envs: SAMPLE_ENVS, - response: SAMPLE_RESPONSE, - legacySandbox: true, - inheritedTestScripts: [rootTestScript], - })(); - - expect(result).toBeRight(); - - if (E.isRight(result)) { - const descriptors = result.right.testsReport.map((r) => r.descriptor); - expect(descriptors).toContain("Request test"); - expect(descriptors).toContain("Root collection test"); - } - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/unit/workspace-access.spec.ts b/packages/hoppscotch-cli/src/__tests__/unit/workspace-access.spec.ts deleted file mode 100644 index 299eb3ba..00000000 --- a/packages/hoppscotch-cli/src/__tests__/unit/workspace-access.spec.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { describe, expect, test } from "vitest"; - -import { - transformWorkspaceCollections, - transformWorkspaceEnvironment, -} from "../../utils/workspace-access"; -import { - TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK, - TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK, - TRANSFORMED_ENVIRONMENT_V0_FORMAT_MOCK, - TRANSFORMED_ENVIRONMENT_V1_FORMAT_MOCK, - TRANSFORMED_ENVIRONMENT_V2_FORMAT_MOCK, - TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK, - WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK, - WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK, - WORKSPACE_ENVIRONMENT_V0_FORMAT_MOCK, - WORKSPACE_ENVIRONMENT_V1_FORMAT_MOCK, - WORKSPACE_ENVIRONMENT_V2_FORMAT_MOCK, - WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK, -} from "./fixtures/workspace-access.mock"; - -describe("workspace-access", () => { - describe("transformWorkspaceCollection", () => { - test("Successfully transforms collection data with deeply nested collections and authorization/headers set at each level to the `HoppCollection` format", () => { - expect( - transformWorkspaceCollections( - WORKSPACE_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK - ) - ).toEqual( - TRANSFORMED_DEEPLY_NESTED_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK - ); - }); - - test("Successfully transforms collection data with multiple child collections and authorization/headers set at each level to the `HoppCollection` format", () => { - expect( - transformWorkspaceCollections( - WORKSPACE_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_VARIABLES_MOCK - ) - ).toEqual(TRANSFORMED_MULTIPLE_CHILD_COLLECTIONS_WITH_AUTH_HEADERS_MOCK); - }); - - test("Adds the default value for `auth` & `header` fields while transforming collections without authorization/headers set at certain levels", () => { - expect( - transformWorkspaceCollections( - WORKSPACE_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK - ) - ).toEqual( - TRANSFORMED_COLLECTIONS_WITHOUT_AUTH_HEADERS_VARIABLES_AT_CERTAIN_LEVELS_MOCK - ); - }); - }); - - describe("transformWorkspaceEnvironment", () => { - test("Successfully transforms environment data conforming to the `v0` format received from the network call to the `HoppEnvironment` format", () => { - expect( - // @ts-expect-error: Testing legacy format transformation - transformWorkspaceEnvironment(WORKSPACE_ENVIRONMENT_V0_FORMAT_MOCK) - ).toEqual(TRANSFORMED_ENVIRONMENT_V0_FORMAT_MOCK); - }); - - test("Successfully transforms environment data conforming to the `v1` format received from the network call to the `HoppEnvironment` format", () => { - expect( - // @ts-expect-error: Testing legacy format transformation - transformWorkspaceEnvironment(WORKSPACE_ENVIRONMENT_V1_FORMAT_MOCK) - ).toEqual(TRANSFORMED_ENVIRONMENT_V1_FORMAT_MOCK); - }); - - test("Successfully transforms environment data conforming to the `v2` format received from the network call to the `HoppEnvironment` format", () => { - expect( - transformWorkspaceEnvironment(WORKSPACE_ENVIRONMENT_V2_FORMAT_MOCK) - ).toEqual(TRANSFORMED_ENVIRONMENT_V2_FORMAT_MOCK); - }); - }); -}); diff --git a/packages/hoppscotch-cli/src/__tests__/utils.ts b/packages/hoppscotch-cli/src/__tests__/utils.ts deleted file mode 100644 index 8d534d41..00000000 --- a/packages/hoppscotch-cli/src/__tests__/utils.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { exec } from "child_process"; -import { resolve } from "path"; - -import { ExecResponse } from "./types"; - -export const runCLI = (args: string, options = {}): Promise => { - const CLI_PATH = resolve(__dirname, "../../bin/hopp.js"); - const command = `node ${CLI_PATH} ${args}`; - - return new Promise((resolve) => - exec(command, options, (error, stdout, stderr) => - resolve({ error, stdout, stderr }) - ) - ); -}; - -export const trimAnsi = (target: string) => { - const ansiRegex = - /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; - - return target.replace(ansiRegex, ""); -}; - -export const getErrorCode = (out: string) => { - const ansiTrimmedStr = trimAnsi(out); - return ansiTrimmedStr.split(" ")[0]; -}; - -export const getTestJsonFilePath = ( - file: string, - kind: "collection" | "environment" -) => { - const kindDir = { - collection: "collections", - environment: "environments", - }[kind]; - - const filePath = resolve( - __dirname, - `../../src/__tests__/e2e/fixtures/${kindDir}/${file}` - ); - return filePath; -}; - -/** - * Runs CLI with automatic retry for transient infrastructure failures. - * - * IMPORTANT: Only use this for tests that EXPECT SUCCESS. - * For tests that intentionally test error scenarios (bad URLs, script errors, etc.), - * use plain `runCLI()` instead to avoid false skips. - * - * Retries on: - * - Low-level network errors (ECONNRESET, DNS timeouts, connection refused) - * - Service degradation (httpbin.org 5xx) - * - Response undefined errors from network failures - * - * Does NOT retry on: - * - REQUEST_ERROR alone (could be intentional bad URL) - * - TEST_SCRIPT_ERROR alone (could be intentional script error) - */ -export const runCLIWithNetworkRetry = async ( - args: string, - options = {}, - maxAttempts = 2 -) => { - for (let attempt = 0; attempt < maxAttempts; attempt++) { - const result = await runCLI(args, options); - const combinedOutput = `${result.stdout}\n${result.stderr}`; - - // Only detect low-level TCP/DNS errors - these are always transient - const hasLowLevelNetworkError = - /ECONNRESET|EAI_AGAIN|ENOTFOUND|ETIMEDOUT|ECONNREFUSED/i.test( - combinedOutput - ); - - // Special case: TEST_SCRIPT_ERROR when response is undefined due to REQUEST_ERROR - // This is the actual CI failure mode when external services go down - const hasTestScriptErrorFromNetworkFailure = - /TEST_SCRIPT_ERROR Script execution failed: TypeError: cannot read property/.test( - combinedOutput - ) && /REQUEST_ERROR/.test(combinedOutput); - - // Service degradation - const hasHttpbin5xx = - /httpbin\.org is down \(5xx\)|httpbin\.org is down \(503\)/i.test( - combinedOutput - ); - - // Success - return immediately - if (!result.error && !hasHttpbin5xx) { - return result; - } - - // Not a transient error - return immediately (don't mask real failures) - if ( - !hasLowLevelNetworkError && - !hasHttpbin5xx && - !hasTestScriptErrorFromNetworkFailure - ) { - return result; - } - - const extractErrorDetails = (output: string): string => { - if (/ECONNRESET/i.test(output)) return "ECONNRESET (connection reset)"; - if (/EAI_AGAIN/i.test(output)) return "EAI_AGAIN (DNS timeout)"; - if (/ENOTFOUND/i.test(output)) return "ENOTFOUND (DNS lookup failed)"; - if (/ETIMEDOUT/i.test(output)) return "ETIMEDOUT (connection timeout)"; - if (/ECONNREFUSED/i.test(output)) - return "ECONNREFUSED (connection refused)"; - if (/httpbin\.org is down/i.test(output)) - return "httpbin.org service degradation (5xx)"; - if (/TEST_SCRIPT_ERROR.*cannot read property/i.test(output)) - return "TEST_SCRIPT_ERROR (response undefined - likely REQUEST_ERROR)"; - return "Network failure"; - }; - - const errorDetail = extractErrorDetails(combinedOutput); - const argsPreview = - args.length > 100 ? `${args.substring(0, 100)}...` : args; - - const isLastAttempt = attempt === maxAttempts - 1; - if (!isLastAttempt) { - console.log( - `⚠️ Network error detected: ${errorDetail}\n Command: ${argsPreview}\n Retrying once...` - ); - await new Promise((resolve) => setTimeout(resolve, 2000)); - continue; - } - - console.warn( - `⚠️ Skipping test after retry exhausted\n` + - ` Error: ${errorDetail}\n` + - ` Command: ${argsPreview}\n` + - ` External services may be unavailable. Test will be skipped to avoid blocking CI.` - ); - return null; - } - - throw new Error("Unexpected: retry loop completed without returning"); -}; diff --git a/packages/hoppscotch-cli/src/commands/test.ts b/packages/hoppscotch-cli/src/commands/test.ts deleted file mode 100644 index 52fec8bc..00000000 --- a/packages/hoppscotch-cli/src/commands/test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import fs from "fs"; -import { isSafeInteger } from "lodash-es"; -import Papa from "papaparse"; -import path from "path"; - -import { handleError } from "../handlers/error"; -import { parseDelayOption } from "../options/test/delay"; -import { parseEnvsData } from "../options/test/env"; -import { IterationDataItem } from "../types/collections"; -import { TestCmdEnvironmentOptions, TestCmdOptions } from "../types/commands"; -import { error } from "../types/errors"; -import { HoppEnvs } from "../types/request"; -import { isHoppCLIError } from "../utils/checks"; -import { - collectionsRunner, - collectionsRunnerExit, - collectionsRunnerResult, -} from "../utils/collections"; -import { parseCollectionData } from "../utils/mutators"; - -export const test = (pathOrId: string, options: TestCmdOptions) => async () => { - try { - const { - delay, - env, - iterationCount, - iterationData, - reporterJunit, - legacySandbox, - } = options; - - if ( - iterationCount !== undefined && - (iterationCount < 1 || !isSafeInteger(iterationCount)) - ) { - throw error({ - code: "INVALID_ARGUMENT", - data: "The value must be a positive integer", - }); - } - - const resolvedDelay = delay ? parseDelayOption(delay) : 0; - - const envs = env - ? await parseEnvsData(options as TestCmdEnvironmentOptions) - : { global: [], selected: [] }; - - let parsedIterationData: unknown[] | null = null; - let transformedIterationData: IterationDataItem[][] | undefined; - - const collections = await parseCollectionData(pathOrId, options); - - if (iterationData) { - // Check file existence - if (!fs.existsSync(iterationData)) { - throw error({ code: "FILE_NOT_FOUND", path: iterationData }); - } - - // Check the file extension - if (path.extname(iterationData) !== ".csv") { - throw error({ - code: "INVALID_DATA_FILE_TYPE", - data: iterationData, - }); - } - - const csvData = fs.readFileSync(iterationData, "utf8"); - parsedIterationData = Papa.parse(csvData, { header: true }).data; - - // Transform data into the desired format - transformedIterationData = parsedIterationData - .map((item) => { - const iterationDataItem = item as Record; - const keys = Object.keys(iterationDataItem); - - return ( - keys - // Ignore keys with empty string values - .filter((key) => iterationDataItem[key] !== "") - .map( - (key) => - { - key: key, - initialValue: iterationDataItem[key], - currentValue: iterationDataItem[key], - secret: false, - } - ) - ); - }) - // Ignore items that result in an empty array - .filter((item) => item.length > 0); - } - - const resolvedLegacySandbox = Boolean(legacySandbox); - - const report = await collectionsRunner({ - collections, - envs, - delay: resolvedDelay, - iterationData: transformedIterationData, - iterationCount, - legacySandbox: resolvedLegacySandbox, - }); - const hasSucceeded = collectionsRunnerResult(report, reporterJunit); - - collectionsRunnerExit(hasSucceeded); - } catch (e) { - if (isHoppCLIError(e)) { - handleError(e); - process.exit(1); - } else throw e; - } -}; diff --git a/packages/hoppscotch-cli/src/handlers/error.ts b/packages/hoppscotch-cli/src/handlers/error.ts deleted file mode 100644 index 72be3acc..00000000 --- a/packages/hoppscotch-cli/src/handlers/error.ts +++ /dev/null @@ -1,112 +0,0 @@ -import * as S from "fp-ts/string"; -import { HoppError, HoppErrorCode } from "../types/errors"; -import { hasProperty, isSafeCommanderError } from "../utils/checks"; -import { parseErrorMessage } from "../utils/mutators"; -import { exceptionColors } from "../utils/getters"; -const { BG_FAIL } = exceptionColors; - -/** - * Parses unknown error data and narrows it to get information related to - * error in string format. - * @param e Error data to parse. - * @returns Information in string format appropriately parsed, based on error type. - */ -const parseErrorData = (e: unknown) => { - let parsedMsg: string; - - if (!!e && typeof e === "object") { - if (hasProperty(e, "message") && S.isString(e.message)) { - parsedMsg = e.message; - } else if (hasProperty(e, "data") && S.isString(e.data)) { - parsedMsg = e.data; - } else { - parsedMsg = JSON.stringify(e); - } - } else if (S.isString(e)) { - parsedMsg = e; - } else { - parsedMsg = JSON.stringify(e); - } - - return parsedMsg; -}; - -/** - * Handles HoppError to generate error messages based on data related - * to error code and exits program with exit code 1. - * @param error Error object with code of type HoppErrorCode. - */ -export const handleError = (error: HoppError) => { - const ERROR_CODE = BG_FAIL(error.code); - let ERROR_MSG; - - switch (error.code) { - case "FILE_NOT_FOUND": - ERROR_MSG = `File doesn't exist: ${error.path}`; - break; - case "UNKNOWN_COMMAND": - ERROR_MSG = `Unavailable command: ${error.command}`; - break; - case "MALFORMED_ENV_FILE": - ERROR_MSG = `The environment file is not of the correct format.`; - break; - case "BULK_ENV_FILE": - ERROR_MSG = `CLI doesn't support bulk environments export.`; - break; - case "MALFORMED_COLLECTION": - ERROR_MSG = `${error.path}\n${parseErrorData(error.data)}`; - break; - case "NO_FILE_PATH": - ERROR_MSG = `Please provide a hoppscotch-collection file path.`; - break; - case "PARSING_ERROR": - ERROR_MSG = `Unable to parse -\n${error.data}`; - break; - case "INVALID_FILE_TYPE": - ERROR_MSG = `Please provide file of extension type .json: ${error.data}`; - break; - case "INVALID_DATA_FILE_TYPE": - ERROR_MSG = `Please provide file of extension type .csv: ${error.data}`; - break; - case "REQUEST_ERROR": - case "TEST_SCRIPT_ERROR": - case "PRE_REQUEST_SCRIPT_ERROR": - ERROR_MSG = parseErrorData(error.data); - break; - case "INVALID_ARGUMENT": - case "UNKNOWN_ERROR": - case "SYNTAX_ERROR": - if (isSafeCommanderError(error.data)) { - ERROR_MSG = S.empty; - } else { - ERROR_MSG = parseErrorMessage(error.data); - } - break; - case "TESTS_FAILING": - ERROR_MSG = error.data; - break; - case "TOKEN_EXPIRED": - ERROR_MSG = `The specified access token is expired. Please provide a valid token: ${error.data}`; - break; - case "TOKEN_INVALID": - ERROR_MSG = `The specified access token is invalid. Please provide a valid token: ${error.data}`; - break; - case "INVALID_ID": - ERROR_MSG = `The specified collection/environment (ID or file path) is invalid or inaccessible. Please ensure the supplied ID or file path is correct: ${error.data}`; - break; - case "INVALID_SERVER_URL": - ERROR_MSG = `Please provide a valid SH instance server URL: ${error.data}`; - break; - case "SERVER_CONNECTION_REFUSED": - ERROR_MSG = `Unable to connect to the server. Please check your network connection or server instance URL and try again: ${error.data}`; - break; - case "REPORT_EXPORT_FAILED": - const moreInfo = error.data ? `: ${error.data}` : S.empty; - ERROR_MSG = `Failed to export the report at ${error.path}${moreInfo}`; - break; - } - - if (!S.isEmpty(ERROR_MSG)) { - console.error(ERROR_CODE, ERROR_MSG); - } -}; diff --git a/packages/hoppscotch-cli/src/index.ts b/packages/hoppscotch-cli/src/index.ts deleted file mode 100644 index 94d70ce3..00000000 --- a/packages/hoppscotch-cli/src/index.ts +++ /dev/null @@ -1,108 +0,0 @@ -import chalk from "chalk"; -import { Command } from "commander"; -import * as E from "fp-ts/Either"; - -import { version } from "../package.json"; -import { test } from "./commands/test"; -import { handleError } from "./handlers/error"; - -const accent = chalk.greenBright; - -/** - * * Program Default Configuration - */ -const CLI_BEFORE_ALL_TXT = `hopp: The ${accent( - "Hoppscotch" -)} CLI - Version ${version} (${accent( - "https://hoppscotch.io" -)}) ${chalk.black.bold.bgYellowBright(" ALPHA ")} \n`; - -const CLI_AFTER_ALL_TXT = `\nFor more help, head on to ${accent( - "https://docs.hoppscotch.io/documentation/clients/cli/overview" -)}`; - -const program = new Command(); - -program - .name("hopp") - .version(version, "-v, --ver", "see the current version of hopp-cli") - .usage("[options or commands] arguments") - .addHelpText("beforeAll", CLI_BEFORE_ALL_TXT) - .addHelpText("after", CLI_AFTER_ALL_TXT) - .configureHelp({ - optionTerm: (option) => accent(option.flags), - subcommandTerm: (cmd) => accent(cmd.name(), cmd.usage()), - argumentTerm: (arg) => accent(arg.name()), - }) - .addHelpCommand(false) - .showHelpAfterError(true); - -program.exitOverride().configureOutput({ - writeErr: (str) => program.help(), - outputError: (str, write) => - handleError({ code: "INVALID_ARGUMENT", data: E.toError(str) }), -}); - -/** - * * CLI Commands - */ -program - .command("test") - .argument( - "", - "path to a hoppscotch collection.json file or collection ID from a workspace for CI testing" - ) - .option( - "-e, --env ", - "path to an environment variables json file or environment ID from a workspace" - ) - .option( - "-d, --delay ", - "delay in milliseconds(ms) between consecutive requests within a collection" - ) - .option( - "--token ", - "personal access token to access collections/environments from a workspace" - ) - .option("--server ", "server URL for SH instance") - .option( - "--reporter-junit [path]", - "generate JUnit report optionally specifying the path" - ) - .option( - "--iteration-count ", - "number of iterations to run the test", - parseInt - ) - .option( - "--iteration-data ", - "path to a CSV file for data-driven testing" - ) - .option("--legacy-sandbox", "Opt out from the experimental scripting sandbox") - .allowExcessArguments(false) - .allowUnknownOption(false) - .description("running hoppscotch collection.json file") - .addHelpText( - "after", - `\nFor help, head on to ${accent( - "https://docs.hoppscotch.io/documentation/clients/cli/overview#commands" - )}` - ) - .action(async (pathOrId, options) => { - const overrides: Record = {}; - - // Choose `hopp-junit-report.xml` as the default value if `reporter-junit` flag is supplied without a value - if (options.reporterJunit === true) { - overrides.reporterJunit = "hopp-junit-report.xml"; - } - - const effectiveOptions = { ...options, ...overrides }; - - await test(pathOrId, effectiveOptions)(); - }); - -export const cli = async (args: string[]) => { - try { - await program.parseAsync(args); - } catch (e) {} -}; diff --git a/packages/hoppscotch-cli/src/interfaces/request.ts b/packages/hoppscotch-cli/src/interfaces/request.ts deleted file mode 100644 index 4aec5cbc..00000000 --- a/packages/hoppscotch-cli/src/interfaces/request.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { AxiosPromise, AxiosRequestConfig } from "axios"; -import { HoppRESTRequest } from "@hoppscotch/data"; - -/** - * Provides definition to object returned by createRequest. - * @property {function} request Axios request promise, executed to get axios - * response promise. - * @property {string} path Path of request within collection file. - * @property {string} name Name of request within collection - * @property {string} testScript Stringified hoppscotch testScript, used while - * running testRunner. - */ -export interface RequestStack { - request: () => AxiosPromise; - path: string; -} - -/** - * Provides definition to axios request promise's request parameter. - * @property {boolean} supported - Boolean check for supported or unsupported requests. - */ -export interface RequestConfig extends AxiosRequestConfig { - displayUrl?: string; -} - -export interface EffectiveHoppRESTRequest extends HoppRESTRequest { - /** - * The effective final URL. - * - * This contains path, params and environment variables all applied to it - */ - effectiveFinalURL: string; - effectiveFinalDisplayURL?: string; - effectiveFinalHeaders: { - key: string; - value: string; - active: boolean; - description: string; - }[]; - effectiveFinalParams: { - key: string; - value: string; - active: boolean; - description: string; - }[]; - effectiveFinalBody: FormData | string | File | null; -} diff --git a/packages/hoppscotch-cli/src/interfaces/response.ts b/packages/hoppscotch-cli/src/interfaces/response.ts deleted file mode 100644 index aa426af8..00000000 --- a/packages/hoppscotch-cli/src/interfaces/response.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { TestResponse } from "@hoppscotch/js-sandbox"; -import { Method } from "axios"; -import { ExpectResult } from "../types/response"; -import { HoppEnvs } from "../types/request"; -import { HoppRESTRequest } from "@hoppscotch/data"; - -/** - * Defines column headers for table stream used to write table - * data on stdout. - * @property {string} path Path of request within collection file. - * @property {string} endpoint Endpoint from response config.url. - * @property {Method} method Method from response headers. - * @property {string} statusCode Template string concatenating status & statusText. - */ -export interface TableResponse { - endpoint: string; - method: Method; - statusCode: string; -} - -/** - * Describes additional details of HTTP response returned from - * requestRunner. - * @property {string} path Path of request within collection file. - * @property {string} endpoint Endpoint from response config.url. - * @property {Method} method Method from HTTP response headers. - * @property {string} statusText HTTP response status text. - */ -export interface RequestRunnerResponse extends TestResponse { - endpoint: string; - method: Method; - statusText: string; - duration: number; -} - -/** - * Describes test script details. - * @property {HoppRESTRequest} request Supplied request. - * @property {TestResponse} response Response structure for test script runner. - * @property {HoppEnvs} envs Environment variables for test script runner. - * @property {boolean} legacySandbox Whether to use the legacy sandbox. - * @property {string[]} inheritedTestScripts Test scripts inherited from parent collections. - */ -export interface TestScriptParams { - request: HoppRESTRequest; - response: TestResponse; - envs: HoppEnvs; - legacySandbox: boolean; - inheritedTestScripts?: string[]; -} - -/** - * Describe properties of test-report generated from test-runner. - * @property {string} descriptor Test description. - * @property {ExpectResult[]} expectResults Expected results for each - * test-case. - * @property {number} failed Total failed test-cases. - * @property {number} passed Total passed test-cases; - */ -export interface TestReport { - descriptor: string; - expectResults: ExpectResult[]; - failed: number; - passed: number; -} - -/** - * Describes error pair for failed HTTP requests. - * @example { 501: "Request Not Supported" } - */ -export interface ResponseErrorPair { - [key: number]: string; -} diff --git a/packages/hoppscotch-cli/src/options/test/delay.ts b/packages/hoppscotch-cli/src/options/test/delay.ts deleted file mode 100644 index e9cf6537..00000000 --- a/packages/hoppscotch-cli/src/options/test/delay.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { error } from "../../types/errors"; - -export function parseDelayOption(delay: string): number { - const maybeInt = Number.parseInt(delay); - - if (!Number.isNaN(maybeInt)) { - return maybeInt; - } else { - throw error({ - code: "INVALID_ARGUMENT", - data: "Expected '-d, --delay' value to be number", - }); - } -} diff --git a/packages/hoppscotch-cli/src/options/test/env.ts b/packages/hoppscotch-cli/src/options/test/env.ts deleted file mode 100644 index 8bd3fa70..00000000 --- a/packages/hoppscotch-cli/src/options/test/env.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Environment, NonSecretEnvironment } from "@hoppscotch/data"; -import { entityReference } from "verzod"; -import { z } from "zod"; - -import { TestCmdEnvironmentOptions } from "../../types/commands"; -import { error } from "../../types/errors"; -import { - HoppEnvKeyPairObject, - HoppEnvPair, - HoppEnvs, -} from "../../types/request"; -import { getResourceContents } from "../../utils/getters"; - -/** - * Parses environment data from a given path or ID and returns the data conforming to the latest version of the `Environment` schema. - * - * @param {TestCmdEnvironmentOptions} options Supplied values for CLI flags. - * @param {string} options.env Path of the environment `.json` file to be parsed. - * @param {string} [options.token] Personal access token to fetch workspace environments. - * @param {string} [options.server] server URL for SH instance. - * @returns {Promise} A promise that resolves to the parsed environment object with global and selected environments. - */ -export async function parseEnvsData(options: TestCmdEnvironmentOptions) { - const { env: pathOrId, token: accessToken, server: serverUrl } = options; - - const contents = await getResourceContents({ - pathOrId, - accessToken, - serverUrl, - resourceType: "environment", - }); - - const envPairs: Array> = []; - - // The legacy key-value pair format that is still supported - const HoppEnvKeyPairResult = HoppEnvKeyPairObject.safeParse(contents); - - // Shape of the single environment export object that is exported from the app - const HoppEnvExportObjectResult = Environment.safeParse(contents); - - // Shape of the bulk environment export object that is exported from the app - const HoppBulkEnvExportObjectResult = z - .array(entityReference(Environment)) - .safeParse(contents); - - // CLI doesnt support bulk environments export - // Hence we check for this case and throw an error if it matches the format - if (HoppBulkEnvExportObjectResult.success) { - throw error({ code: "BULK_ENV_FILE", path: pathOrId, data: error }); - } - - // Checks if the environment file is of the correct format - // If it doesnt match either of them, we throw an error - if ( - !HoppEnvKeyPairResult.success && - HoppEnvExportObjectResult.type === "err" - ) { - throw error({ code: "MALFORMED_ENV_FILE", path: pathOrId, data: error }); - } - - if (HoppEnvKeyPairResult.success) { - for (const [key, value] of Object.entries(HoppEnvKeyPairResult.data)) { - envPairs.push({ - key, - initialValue: value, - currentValue: value, - secret: false, - }); - } - } else if (HoppEnvExportObjectResult.type === "ok") { - // Original environment variables from the supplied export file - const originalEnvVariables = (contents as Environment).variables; - - // Above environment variables conforming to the latest schema - // `value` fields if specified will be omitted for secret environment variables - const migratedEnvVariables = HoppEnvExportObjectResult.value.variables; - - // The values supplied for secret environment variables have to be considered in the CLI - // For each secret environment variable, include the value in case supplied - const resolvedEnvVariables = migratedEnvVariables.map((variable, idx) => { - if (variable.secret && originalEnvVariables[idx].initialValue) { - return { - ...variable, - initialValue: originalEnvVariables[idx].initialValue, - }; - } - - return variable; - }); - - envPairs.push(...resolvedEnvVariables); - } - - return { global: [], selected: envPairs }; -} diff --git a/packages/hoppscotch-cli/src/tsconfig.json b/packages/hoppscotch-cli/src/tsconfig.json deleted file mode 100644 index 78d41bed..00000000 --- a/packages/hoppscotch-cli/src/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ES6", - "module": "commonjs", - "outDir": "../dist", - "rootDir": ".", - "strict": true, - "moduleResolution": "node", - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true - }, - "references": [ - { - "path": "../" - } - ] -} diff --git a/packages/hoppscotch-cli/src/types/collections.ts b/packages/hoppscotch-cli/src/types/collections.ts deleted file mode 100644 index c3d67ebc..00000000 --- a/packages/hoppscotch-cli/src/types/collections.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { HoppCollection } from "@hoppscotch/data"; -import { HoppEnvPair, HoppEnvs } from "./request"; - -export type CollectionRunnerParam = { - collections: HoppCollection[]; - envs: HoppEnvs; - delay?: number; - iterationData?: IterationDataItem[][]; - iterationCount?: number; - legacySandbox: boolean; -}; - -export type HoppCollectionFileExt = "json"; - -// Indicates the shape each iteration data entry gets transformed into -export type IterationDataItem = Extract; diff --git a/packages/hoppscotch-cli/src/types/commands.ts b/packages/hoppscotch-cli/src/types/commands.ts deleted file mode 100644 index f53a1280..00000000 --- a/packages/hoppscotch-cli/src/types/commands.ts +++ /dev/null @@ -1,20 +0,0 @@ -export type TestCmdOptions = { - env?: string; - delay?: string; - token?: string; - server?: string; - reporterJunit?: string; - iterationCount?: number; - iterationData?: string; - legacySandbox?: boolean; -}; - -// Consumed in the collection `file_path_or_id` argument action handler -export type TestCmdCollectionOptions = Omit; - -// Consumed in the `--env, -e` flag action handler -export type TestCmdEnvironmentOptions = Omit & { - env: string; -}; - -export type HOPP_ENV_FILE_EXT = "json"; diff --git a/packages/hoppscotch-cli/src/types/errors.ts b/packages/hoppscotch-cli/src/types/errors.ts deleted file mode 100644 index 6122ff79..00000000 --- a/packages/hoppscotch-cli/src/types/errors.ts +++ /dev/null @@ -1,45 +0,0 @@ -type HoppErrorPath = { - path: string; -}; - -type HoppErrorCmd = { - command: string; -}; - -type HoppErrorData = { - data: any; -}; - -type HoppErrors = { - UNKNOWN_ERROR: HoppErrorData; - FILE_NOT_FOUND: HoppErrorPath; - UNKNOWN_COMMAND: HoppErrorCmd; - MALFORMED_COLLECTION: HoppErrorPath & HoppErrorData; - NO_FILE_PATH: {}; - PRE_REQUEST_SCRIPT_ERROR: HoppErrorData; - PARSING_ERROR: HoppErrorData; - TEST_SCRIPT_ERROR: HoppErrorData; - TESTS_FAILING: HoppErrorData; - SYNTAX_ERROR: HoppErrorData; - REQUEST_ERROR: HoppErrorData; - INVALID_ARGUMENT: HoppErrorData; - MALFORMED_ENV_FILE: HoppErrorPath & HoppErrorData; - BULK_ENV_FILE: HoppErrorPath & HoppErrorData; - INVALID_FILE_TYPE: HoppErrorData; - INVALID_DATA_FILE_TYPE: HoppErrorData; - TOKEN_EXPIRED: HoppErrorData; - TOKEN_INVALID: HoppErrorData; - INVALID_ID: HoppErrorData; - INVALID_SERVER_URL: HoppErrorData; - SERVER_CONNECTION_REFUSED: HoppErrorData; - REPORT_EXPORT_FAILED: HoppErrorPath & HoppErrorData; -}; - -export type HoppErrorCode = keyof HoppErrors; -export type HoppError = T extends null - ? { code: T } - : { code: T } & HoppErrors[T]; - -export const error = (error: HoppError) => error; -export type HoppCLIError = HoppError; -export type HoppErrnoException = NodeJS.ErrnoException; diff --git a/packages/hoppscotch-cli/src/types/request.ts b/packages/hoppscotch-cli/src/types/request.ts deleted file mode 100644 index 1aaca15c..00000000 --- a/packages/hoppscotch-cli/src/types/request.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { - Environment, - HoppCollection, - HoppCollectionVariable, - HoppRESTRequest, -} from "@hoppscotch/data"; -import { z } from "zod"; - -import { TestReport } from "../interfaces/response"; -import { HoppCLIError } from "./errors"; - -export type FormDataEntry = { - key: string; - value: string | Blob; - contentType?: string; -}; - -export type HoppEnvPair = Environment["variables"][number]; - -export const HoppEnvKeyPairObject = z.record(z.string(), z.string()); - -export type HoppEnvs = { - global: HoppEnvPair[]; - selected: HoppEnvPair[]; -}; - -export type CollectionQueue = { - path: string; - collection: HoppCollection; -}; - -export type RequestReport = { - path: string; - tests: TestReport[]; - errors: HoppCLIError[]; - result: boolean; - duration: { test: number; request: number; preRequest: number }; -}; - -export type ProcessRequestParams = { - request: HoppRESTRequest; - envs: HoppEnvs; - path: string; - delay: number; - legacySandbox?: boolean; - collectionVariables?: HoppCollectionVariable[]; - inheritedPreRequestScripts?: string[]; - inheritedTestScripts?: string[]; -}; diff --git a/packages/hoppscotch-cli/src/types/response.ts b/packages/hoppscotch-cli/src/types/response.ts deleted file mode 100644 index 126dca4d..00000000 --- a/packages/hoppscotch-cli/src/types/response.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { TestReport } from "../interfaces/response"; -import { HoppEnvs } from "./request"; - -/** - * The expectation failed (fail) or errored (error) - */ -export type ExpectResult = { - status: "pass" | "fail" | "error"; - message: string; -}; - -/** - * Stats describing number of failed and passed for test-cases/test-suites/ - * test-scripts/pre-request-scripts/request. - */ -export type Stats = { - failed: number; - passed: number; -}; - -export type PreRequestMetrics = { - /** - * Pre-request-script(s) failed and passed stats. - */ - scripts: Stats; - - /** - * Time taken (in seconds) to execute pre-request-script(s). - */ - duration: number; -}; - -export type RequestMetrics = { - /** - * Request(s) failed and passed stats. - */ - requests: Stats; - - /** - * Time taken (in seconds) to execute request(s). - */ - duration: number; -}; - -export type TestMetrics = { - /** - * Test-cases failed and passed stats. - */ - tests: Stats; - - /** - * Test-block(s)/test-suite(s) failed and passed stats. - */ - testSuites: Stats; - - /** - * Test script(s) execution failed and passed stats. - */ - scripts: Stats; - - /** - * Time taken (in seconds) to execute test-script(s). - */ - duration: number; -}; - -export type TestRunnerRes = { - /** - * Updated envs after running test-script. - */ - envs: HoppEnvs; - - /** - * Describes expected details for each test-suite. - */ - testsReport: TestReport[]; - - /** - * Time taken (in seconds) to execute the test-script. - */ - duration: number; -}; diff --git a/packages/hoppscotch-cli/src/utils/auth/digest.ts b/packages/hoppscotch-cli/src/utils/auth/digest.ts deleted file mode 100644 index 7c8d65dd..00000000 --- a/packages/hoppscotch-cli/src/utils/auth/digest.ts +++ /dev/null @@ -1,158 +0,0 @@ -import axios from "axios"; -import { md5 } from "js-md5"; - -import { exceptionColors } from "../getters"; - -export interface DigestAuthParams { - username: string; - password: string; - realm: string; - nonce: string; - endpoint: string; - method: string; - algorithm: string; - qop: string; - nc?: string; - opaque?: string; - cnonce?: string; // client nonce (optional but typically required in qop='auth') - reqBody?: string; -} - -export interface DigestAuthInfo { - realm: string; - nonce: string; - qop: string; - opaque?: string; - algorithm: string; -} - -// Utility function to parse Digest auth header values -const parseDigestAuthHeader = ( - header: string -): { [key: string]: string } | null => { - const matches = header.match(/([a-z0-9]+)="([^"]+)"/gi); - if (!matches) return null; - - const authParams: { [key: string]: string } = {}; - matches.forEach((match) => { - const parts = match.split("="); - authParams[parts[0]] = parts[1].replace(/"/g, ""); - }); - - return authParams; -}; - -// Function to generate Digest Auth Header -export const generateDigestAuthHeader = async (params: DigestAuthParams) => { - const { - username, - password, - realm, - nonce, - endpoint, - method, - algorithm = "MD5", - qop, - nc = "00000001", - opaque, - cnonce, - reqBody = "", - } = params; - - const url = new URL(endpoint); - const uri = url.pathname + url.search; - - // Generate client nonce if not provided - const generatedCnonce = cnonce || md5(`${Math.random()}`); - - // Step 1: Hash the username, realm, password and any additional fields based on the algorithm - const ha1 = - algorithm === "MD5-sess" - ? md5( - `${md5(`${username}:${realm}:${password}`)}:${nonce}:${generatedCnonce}` - ) - : md5(`${username}:${realm}:${password}`); - - // Step 2: Hash the method and URI - const ha2 = - qop === "auth-int" - ? md5(`${method}:${uri}:${md5(reqBody)}`) // Entity body hash for `auth-int` - : md5(`${method}:${uri}`); - - // Step 3: Compute the response hash - const response = md5( - `${ha1}:${nonce}:${nc}:${generatedCnonce}:${qop}:${ha2}` - ); - - // Build the Digest header - let authHeader = `Digest username="${username}", realm="${realm}", nonce="${nonce}", uri="${uri}", algorithm="${algorithm}", response="${response}", qop=${qop}, nc=${nc}, cnonce="${generatedCnonce}"`; - - if (opaque) { - authHeader += `, opaque="${opaque}"`; - } - - return authHeader; -}; - -export const fetchInitialDigestAuthInfo = async ( - url: string, - method: string, - disableRetry: boolean -): Promise => { - try { - const initialResponse = await axios.request({ - url, - method, - validateStatus: () => true, // Allow handling of all status codes - }); - - if (disableRetry) { - throw new Error( - `Received status: ${initialResponse.status}. Retry is disabled as specified, so no further attempts will be made.` - ); - } - - // Check if the response status is 401 (which is expected in Digest Auth flow) - if (initialResponse.status === 401) { - const authHeaderEntry = Object.keys(initialResponse.headers).find( - (header) => header.toLowerCase() === "www-authenticate" - ); - - const authHeader = authHeaderEntry - ? (initialResponse.headers[authHeaderEntry] ?? null) - : null; - - if (authHeader) { - const authParams = parseDigestAuthHeader(authHeader); - if ( - authParams && - authParams.realm && - authParams.nonce && - authParams.qop - ) { - return { - realm: authParams.realm, - nonce: authParams.nonce, - qop: authParams.qop, - opaque: authParams.opaque, - algorithm: authParams.algorithm, - }; - } - } - throw new Error( - "Failed to parse authentication parameters from WWW-Authenticate header" - ); - } - - throw new Error(`Unexpected response: ${initialResponse.status}`); - } catch (error) { - const errMsg = error instanceof Error ? error.message : error; - - console.error( - exceptionColors.FAIL( - `\n Error fetching initial digest auth info: ${errMsg} \n` - ) - ); - throw error; // Re-throw the error to handle it further up the chain if needed - } -}; diff --git a/packages/hoppscotch-cli/src/utils/checks.ts b/packages/hoppscotch-cli/src/utils/checks.ts deleted file mode 100644 index 083aab7f..00000000 --- a/packages/hoppscotch-cli/src/utils/checks.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { CommanderError } from "commander"; -import { HoppCLIError, HoppErrnoException } from "../types/errors"; - -/** - * Determines whether an object has a property with given name. - * @param target Object to be checked for given property. - * @param prop Property to be checked in target object. - * @returns True, if property exists in target object; False, otherwise. - */ -export const hasProperty =

( - target: object, - prop: P -): target is Record => prop in target; - -/** - * Checks if given error data is of type HoppCLIError, based on existence - * of code property. - * @param error Error data to check. - * @returns True, if unknown error validates to be HoppCLIError; - * False, otherwise. - */ -export const isHoppCLIError = (error: unknown): error is HoppCLIError => { - return ( - !!error && - typeof error === "object" && - hasProperty(error, "code") && - typeof error.code === "string" - ); -}; - -/** - * Checks if given error data is of type HoppErrnoException, based on existence - * of name property. - * @param error Error data to check. - * @returns True, if unknown error validates to be HoppErrnoException; - * False, otherwise. - */ -export const isHoppErrnoException = ( - error: unknown -): error is HoppErrnoException => { - return ( - !!error && - typeof error === "object" && - hasProperty(error, "name") && - typeof error.name === "string" - ); -}; - -/** - * Check whether given unknown error is instance of commander-error and - * has zero exit code (which we consider as safe error). - * @param error Error data to check. - * @returns True, if error data validates to be safe-commander-error; - * False, otherwise. - */ -export const isSafeCommanderError = ( - error: unknown -): error is CommanderError => { - return error instanceof CommanderError && error.exitCode === 0; -}; diff --git a/packages/hoppscotch-cli/src/utils/collections.ts b/packages/hoppscotch-cli/src/utils/collections.ts deleted file mode 100644 index 313e957e..00000000 --- a/packages/hoppscotch-cli/src/utils/collections.ts +++ /dev/null @@ -1,366 +0,0 @@ -import { HoppCollection, HoppRESTRequest } from "@hoppscotch/data"; -import chalk from "chalk"; -import { log } from "console"; -import * as A from "fp-ts/Array"; -import { pipe } from "fp-ts/function"; -import { round } from "lodash-es"; - -import { CollectionRunnerParam } from "../types/collections"; -import { - CollectionQueue, - HoppEnvs, - ProcessRequestParams, - RequestReport, -} from "../types/request"; -import { - PreRequestMetrics, - RequestMetrics, - TestMetrics, -} from "../types/response"; -import { DEFAULT_DURATION_PRECISION } from "./constants"; -import { - printErrorsReport, - printFailedTestsReport, - printPreRequestMetrics, - printRequestsMetrics, - printTestsMetrics, -} from "./display"; -import { exceptionColors } from "./getters"; -import { getPreRequestMetrics } from "./pre-request"; -import { buildJUnitReport, generateJUnitReportExport } from "./reporters/junit"; -import { - getRequestMetrics, - preProcessRequest, - processRequest, -} from "./request"; -import { getTestMetrics } from "./test"; -import { filterValidScripts } from "./scripting"; - -const { WARN, FAIL, INFO } = exceptionColors; - -/** - * Processes each requests within collections to prints details of subsequent requests, - * tests and to display complete errors-report, failed-tests-report and test-metrics. - * @param param Data of hopp-collection with hopp-requests, envs to be processed. - * @returns List of report for each processed request. - */ - -export const collectionsRunner = async ( - param: CollectionRunnerParam -): Promise => { - const { - collections, - envs, - delay, - iterationCount, - iterationData, - legacySandbox, - } = param; - - const resolvedDelay = delay ?? 0; - - const requestsReport: RequestReport[] = []; - const collectionQueue = getCollectionQueue(collections); - - // If iteration count is not supplied, it should be based on the size of iteration data if in scope - const resolvedIterationCount = iterationCount ?? iterationData?.length ?? 1; - - const originalSelectedEnvs = [...envs.selected]; - - for (let count = 0; count < resolvedIterationCount; count++) { - if (resolvedIterationCount > 1) { - log(INFO(`\nIteration: ${count + 1}/${resolvedIterationCount}`)); - } - - // Reset `envs` to the original value at the start of each iteration - envs.selected = [...originalSelectedEnvs]; - - if (iterationData) { - // Ensure last item is picked if the iteration count exceeds size of the iteration data - const iterationDataItem = - iterationData[Math.min(count, iterationData.length - 1)]; - - // Ensure iteration data takes priority over supplied environment variables - envs.selected = envs.selected - .filter( - (envPair) => - !iterationDataItem.some((dataPair) => dataPair.key === envPair.key) - ) - .concat(iterationDataItem); - } - - for (const { collection, path } of collectionQueue) { - await processCollection( - collection, - path, - envs, - resolvedDelay, - requestsReport, - legacySandbox - ); - } - } - - return requestsReport; -}; - -const processCollection = async ( - collection: HoppCollection, - path: string, - envs: HoppEnvs, - delay: number, - requestsReport: RequestReport[], - legacySandbox?: boolean, - ancestorPreRequestScripts: string[] = [], - ancestorTestScripts: string[] = [] -) => { - // Accumulate scripts from root -> current collection for inheritance - // filterValidScripts strips empty, whitespace-only, and module-prefix-only scripts - const inheritedPreRequestScripts = filterValidScripts([ - ...ancestorPreRequestScripts, - collection.preRequestScript, - ]); - const inheritedTestScripts = filterValidScripts([ - ...ancestorTestScripts, - collection.testScript, - ]); - - // Process each request in the collection - for (const request of collection.requests) { - const _request = preProcessRequest(request as HoppRESTRequest, collection); - const requestPath = `${path}/${_request.name}`; - - const collectionVariables = collection.variables.filter( - (variable) => variable.key && variable.key.trim() !== "" - ); - - const processRequestParams: ProcessRequestParams = { - path: requestPath, - request: _request, - envs, - delay, - legacySandbox, - collectionVariables, - inheritedPreRequestScripts, - inheritedTestScripts, - }; - - // Request processing initiated message. - log(WARN(`\nRunning: ${chalk.bold(requestPath)}`)); - - // Processing current request. - const result = await processRequest(processRequestParams)(); - - // Updating global & selected envs with new envs from processed-request output. - const { global, selected } = result.envs; - envs.global = global; - envs.selected = selected; - - // Storing current request's report. - const requestReport = result.report; - requestsReport.push(requestReport); - } - - // Process each folder in the collection - for (const folder of collection.folders) { - const updatedFolder: HoppCollection = { ...folder }; - - if (updatedFolder.auth.authType === "inherit") { - updatedFolder.auth = collection.auth; - } - - if (collection.headers.length) { - // Filter out header entries present in the parent collection under the same name - // This ensures the folder headers take precedence over the collection headers - const filteredHeaders = collection.headers.filter( - (collectionHeaderEntries) => { - return !updatedFolder.headers.some( - (folderHeaderEntries) => - folderHeaderEntries.key === collectionHeaderEntries.key - ); - } - ); - updatedFolder.headers.push(...filteredHeaders); - } - - // Inherit collection variables into folder, with folder variables taking precedence - if (collection.variables.length) { - // Filter out collection variables with same key as folder variables - const filteredVariables = collection.variables.filter( - (collectionVariableEntries) => { - return !updatedFolder.variables.some( - (folderVariableEntries) => - folderVariableEntries.key === collectionVariableEntries.key - ); - } - ); - - updatedFolder.variables.push(...filteredVariables); - } - - await processCollection( - updatedFolder, - `${path}/${updatedFolder.name}`, - envs, - delay, - requestsReport, - legacySandbox, - inheritedPreRequestScripts, - inheritedTestScripts - ); - } -}; -/** - * Transforms collections to generate collection-stack which describes each collection's - * path within collection & the collection itself. - * @param collections Hopp-collection objects to be mapped to collection-stack type. - * @returns Mapped collections to collection-stack. - */ -const getCollectionQueue = (collections: HoppCollection[]): CollectionQueue[] => - pipe( - collections, - A.map( - (collection) => { collection, path: collection.name } - ) - ); - -/** - * Prints collection-runner-report using test-metrics, request-metrics and - * pre-request-metrics data in pretty-format. - * @param requestsReport Provides data for each request-report which includes - * path of each request within collection-json file, failed-tests-report, errors, - * total execution duration for requests, pre-request-scripts, test-scripts. - * @returns True, if collection runner executed without any errors or failed test-cases. - * False, if errors occurred or test-cases failed. - */ -export const collectionsRunnerResult = ( - requestsReport: RequestReport[], - reporterJUnitExportPath?: string -): boolean => { - const overallTestMetrics = { - tests: { failed: 0, passed: 0 }, - testSuites: { failed: 0, passed: 0 }, - duration: 0, - scripts: { failed: 0, passed: 0 }, - }; - const overallRequestMetrics = { - requests: { failed: 0, passed: 0 }, - duration: 0, - }; - const overallPreRequestMetrics = { - scripts: { failed: 0, passed: 0 }, - duration: 0, - }; - let finalResult = true; - - let totalErroredTestCases = 0; - let totalFailedTestCases = 0; - - // Printing requests-report details of failed-tests and errors - for (const requestReport of requestsReport) { - const { path, tests, errors, result, duration } = requestReport; - const requestDuration = duration.request; - const testsDuration = duration.test; - const preRequestDuration = duration.preRequest; - - finalResult = finalResult && result; - - printFailedTestsReport(path, tests); - - printErrorsReport(path, errors); - - if (reporterJUnitExportPath) { - const { failedRequestTestCases, erroredRequestTestCases } = - buildJUnitReport({ - path, - tests, - errors, - duration: duration.test, - }); - - totalFailedTestCases += failedRequestTestCases; - totalErroredTestCases += erroredRequestTestCases; - } - - /** - * Extracting current request report's test-metrics and updating - * overall test-metrics. - */ - const testMetrics = getTestMetrics(tests, testsDuration, errors); - overallTestMetrics.duration += testMetrics.duration; - overallTestMetrics.testSuites.failed += testMetrics.testSuites.failed; - overallTestMetrics.testSuites.passed += testMetrics.testSuites.passed; - overallTestMetrics.tests.failed += testMetrics.tests.failed; - overallTestMetrics.tests.passed += testMetrics.tests.passed; - overallTestMetrics.scripts.failed += testMetrics.scripts.failed; - overallTestMetrics.scripts.passed += testMetrics.scripts.passed; - - /** - * Extracting current request report's request-metrics and updating - * overall request-metrics. - */ - const requestMetrics = getRequestMetrics(errors, requestDuration); - overallRequestMetrics.duration += requestMetrics.duration; - overallRequestMetrics.requests.failed += requestMetrics.requests.failed; - overallRequestMetrics.requests.passed += requestMetrics.requests.passed; - - /** - * Extracting current request report's pre-request-metrics and updating - * overall pre-request-metrics. - */ - const preRequestMetrics = getPreRequestMetrics(errors, preRequestDuration); - overallPreRequestMetrics.duration += preRequestMetrics.duration; - overallPreRequestMetrics.scripts.failed += preRequestMetrics.scripts.failed; - overallPreRequestMetrics.scripts.passed += preRequestMetrics.scripts.passed; - } - - const testMetricsDuration = overallTestMetrics.duration; - const requestMetricsDuration = overallRequestMetrics.duration; - - // Rounding-off overall test-metrics duration upto DEFAULT_DURATION_PRECISION. - overallTestMetrics.duration = round( - testMetricsDuration, - DEFAULT_DURATION_PRECISION - ); - - // Rounding-off overall request-metrics duration upto DEFAULT_DURATION_PRECISION. - overallRequestMetrics.duration = round( - requestMetricsDuration, - DEFAULT_DURATION_PRECISION - ); - - printTestsMetrics(overallTestMetrics); - printRequestsMetrics(overallRequestMetrics); - printPreRequestMetrics(overallPreRequestMetrics); - - if (reporterJUnitExportPath) { - const totalTestCases = - overallTestMetrics.tests.failed + overallTestMetrics.tests.passed; - - generateJUnitReportExport({ - totalTestCases, - totalFailedTestCases, - totalErroredTestCases, - testDuration: overallTestMetrics.duration, - reporterJUnitExportPath, - }); - } - - return finalResult; -}; - -/** - * Exiting hopp cli process with appropriate exit code depending on - * collections-runner result. - * If result is true, we exit the cli process with code 0. - * Else, exit with code 1. - * @param result Boolean defining the collections-runner result. - */ -export const collectionsRunnerExit = (result: boolean): never => { - if (!result) { - const EXIT_MSG = FAIL(`\nExited with code 1`); - process.stderr.write(EXIT_MSG); - process.exit(1); - } - process.exit(0); -}; diff --git a/packages/hoppscotch-cli/src/utils/constants.ts b/packages/hoppscotch-cli/src/utils/constants.ts deleted file mode 100644 index 16ca169d..00000000 --- a/packages/hoppscotch-cli/src/utils/constants.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { ResponseErrorPair } from "../interfaces/response"; - -export const responseErrors: ResponseErrorPair = { - 501: "REQUEST NOT SUPPORTED", - 408: "NETWORK TIMEOUT", - 400: "BAD REQUEST", -} as const; - -/** - * Default decimal precision to round-off calculated HRTime time in seconds. - */ -export const DEFAULT_DURATION_PRECISION: number = 3; diff --git a/packages/hoppscotch-cli/src/utils/display.ts b/packages/hoppscotch-cli/src/utils/display.ts deleted file mode 100644 index 564512fd..00000000 --- a/packages/hoppscotch-cli/src/utils/display.ts +++ /dev/null @@ -1,231 +0,0 @@ -import chalk from "chalk"; -import { groupEnd, group, log } from "console"; -import { handleError } from "../handlers/error"; -import { RequestConfig } from "../interfaces/request"; -import { RequestRunnerResponse, TestReport } from "../interfaces/response"; -import { HoppCLIError } from "../types/errors"; -import { - PreRequestMetrics, - RequestMetrics, - TestMetrics, -} from "../types/response"; -import { exceptionColors, getColorStatusCode } from "./getters"; -import { getFailedExpectedResults, getFailedTestsReport } from "./test"; - -const { FAIL, SUCCESS, BG_INFO, INFO_BRIGHT } = exceptionColors; - -/** - * Prints total failed and passed stats of executed pre-request-scripts. - * @param preRequestMetrics Provides data for total failed and passed - * stats of all executed pre-request-scripts. - */ -export const printPreRequestMetrics = ( - preRequestMetrics: PreRequestMetrics -) => { - const { - scripts: { failed, passed }, - } = preRequestMetrics; - - const failedPreRequestsOut = FAIL(`${failed} failed`); - const passedPreRequestsOut = SUCCESS(`${passed} passed`); - const preRequestsOut = `Pre-Request Scripts: ${failedPreRequestsOut} ${passedPreRequestsOut}\n`; - - const message = `\n${preRequestsOut}`; - process.stdout.write(message); -}; - -/** - * Prints total failed and passed stats, duration of executed request. - * @param requestsMetrics Provides data for total duration and total failed and - * passed stats of all executed requests. - */ -export const printRequestsMetrics = (requestsMetrics: RequestMetrics) => { - const { - requests: { failed, passed }, - duration, - } = requestsMetrics; - - const failedRequestsOut = FAIL(`${failed} failed`); - const passedRequestsOut = SUCCESS(`${passed} passed`); - const requestsOut = `Requests: ${failedRequestsOut} ${passedRequestsOut}\n`; - const requestsDurationOut = - duration > 0 ? `Requests Duration: ${INFO_BRIGHT(`${duration} s`)}\n` : ""; - - const message = `\n${requestsOut}${requestsDurationOut}`; - process.stdout.write(message); -}; - -/** - * Prints test-suites in pretty-way describing each test-suites failed/passed - * status and duration to execute the test-script. - * @param testsReport Providing details of each test-suites with tests-report. - * @param duration Time taken (in seconds) to execute the test-script. - */ -export const printTestSuitesReport = ( - testsReport: TestReport[], - duration: number -) => { - const durationMsg = - duration > 0 ? INFO_BRIGHT(`Ran tests in ${duration} s`) : ""; - - group(); - for (const testReport of testsReport) { - const { failed, descriptor } = testReport; - - if (failed > 0) { - log(`${FAIL("✖")} ${descriptor}`); - } else { - log(`${SUCCESS("✔")} ${descriptor}`); - } - } - log(durationMsg); - groupEnd(); -}; - -/** - * Prints total failed and passed stats for test-suites, test-cases, test-scripts, - * and total duration of executed test-scripts. - * @param testsMetrics Provides testSuites, testCases metrics, test-script - * execution duration and test-script passed/failed stats. - */ -export const printTestsMetrics = (testsMetrics: TestMetrics) => { - const { testSuites, tests, duration, scripts } = testsMetrics; - - const failedTestCasesOut = FAIL(`${tests.failed} failed`); - const passedTestCasesOut = SUCCESS(`${tests.passed} passed`); - const testCasesOut = `Test Cases: ${failedTestCasesOut} ${passedTestCasesOut}\n`; - - const failedTestSuitesOut = FAIL(`${testSuites.failed} failed`); - const passedTestSuitesOut = SUCCESS(`${testSuites.passed} passed`); - const testSuitesOut = `Test Suites: ${failedTestSuitesOut} ${passedTestSuitesOut}\n`; - - const failedTestScriptsOut = FAIL(`${scripts.failed} failed`); - const passedTestScriptsOut = SUCCESS(`${scripts.passed} passed`); - const testScriptsOut = `Test Scripts: ${failedTestScriptsOut} ${passedTestScriptsOut}\n`; - - const testsDurationOut = - duration > 0 ? `Tests Duration: ${INFO_BRIGHT(`${duration} s`)}\n` : ""; - - const message = `\n${testCasesOut}${testSuitesOut}${testScriptsOut}${testsDurationOut}`; - process.stdout.write(message); -}; - -/** - * Prints details of each reported error for a request with error code. - * @param path Request's path in collection for which errors occurred. - * @param errorsReport List of errors reported. - */ -export const printErrorsReport = ( - path: string, - errorsReport: HoppCLIError[] -) => { - if (errorsReport.length > 0) { - const REPORTED_ERRORS_TITLE = FAIL( - `\n${chalk.bold(path)} reported errors:` - ); - - group(REPORTED_ERRORS_TITLE); - for (const errorReport of errorsReport) { - handleError(errorReport); - } - groupEnd(); - } -}; - -/** - * Prints details of each failed tests for given request's path. - * @param path Request's path in collection for which tests-failed. - * @param testsReport Overall tests-report including failed-tests-report. - */ -export const printFailedTestsReport = ( - path: string, - testsReport: TestReport[] -) => { - const failedTestsReport = getFailedTestsReport(testsReport); - - // Only printing test-reports with failed test-cases. - if (failedTestsReport.length > 0) { - const FAILED_TESTS_PATH = FAIL(`\n${chalk.bold(path)} failed tests:`); - group(FAILED_TESTS_PATH); - - for (const failedTestReport of failedTestsReport) { - const { descriptor, expectResults } = failedTestReport; - const failedExpectResults = getFailedExpectedResults(expectResults); - - // Only printing failed expected-results. - if (failedExpectResults.length > 0) { - group("⦁", descriptor); - - for (const failedExpectResult of failedExpectResults) { - log(FAIL("-"), failedExpectResult.message); - } - - groupEnd(); - } - } - - groupEnd(); - } -}; - -/** - * Provides methods for printing request-runner's state messages. - */ -export const printRequestRunner = { - /** - * Request-runner starting message. - * @param requestConfig Provides request's method and url. - */ - start: (requestConfig: RequestConfig) => { - const METHOD = BG_INFO(` ${requestConfig.method} `); - const ENDPOINT = requestConfig.displayUrl || requestConfig.url; - - process.stdout.write(`${METHOD} ${ENDPOINT}`); - }, - - /** - * Prints response's status, when request-runner executes successfully. - * @param requestResponse Provides request's status and execution duration. - */ - success: (requestResponse: RequestRunnerResponse) => { - const { status, statusText, duration } = requestResponse; - const statusMsg = getColorStatusCode(status, statusText); - const durationMsg = duration > 0 ? INFO_BRIGHT(`(${duration} s)`) : ""; - - process.stdout.write(` ${statusMsg} ${durationMsg}\n`); - }, - - /** - * Prints error message, when request-runner fails to execute. - */ - fail: () => log(FAIL(" ERROR\n⚠ Error running request.")), -}; - -/** - * Provides methods for printing test-runner's state messages. - */ -export const printTestRunner = { - /** - * Prints test-runner failed message. - */ - fail: () => log(FAIL("⚠ Error running test-script.")), - - /** - * Prints test-runner success message including tests-report. - * @param testsReport List of expected result(s) and metrics for the executed - * test-script. - * @param duration Time taken to execute a test-script. - */ - success: (testsReport: TestReport[], duration: number) => - printTestSuitesReport(testsReport, duration), -}; - -/** - * Provides methods for printing pre-request-runner's state messages. - */ -export const printPreRequestRunner = { - /** - * Prints pre-request-runner failed message. - */ - fail: () => log(FAIL("⚠ Error running pre-request-script.")), -}; diff --git a/packages/hoppscotch-cli/src/utils/functions/array.ts b/packages/hoppscotch-cli/src/utils/functions/array.ts deleted file mode 100644 index f616d599..00000000 --- a/packages/hoppscotch-cli/src/utils/functions/array.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { clone } from "lodash-es"; - -/** - * Sorts the array based on the sort func. - * NOTE: Creates a new array, if you don't need ref - * to original array, use `arrayUnsafeSort` for better perf - * @param sortFunc Sort function to sort against - */ -export const arraySort = - (sortFunc: (a: T, b: T) => number) => - (arr: T[]) => { - const newArr = clone(arr); - - newArr.sort(sortFunc); - - return newArr; - }; - -/** - * Equivalent to `Array.prototype.flatMap`. - * @param mapFunc The map function. - * @returns Array formed by applying given mapFunc. - */ -export const arrayFlatMap = - (mapFunc: (value: T, index: number, arr: T[]) => U[]) => - (arr: T[]) => - arr.flatMap(mapFunc); - -export const tupleToRecord = < - KeyType extends string | number | symbol, - ValueType, ->( - tuples: [KeyType, ValueType][] -): Record => - tuples.length > 0 - ? (Object.assign as any)(...tuples.map(([key, val]) => ({ [key]: val }))) - : {}; diff --git a/packages/hoppscotch-cli/src/utils/getters.ts b/packages/hoppscotch-cli/src/utils/getters.ts deleted file mode 100644 index f87431dc..00000000 --- a/packages/hoppscotch-cli/src/utils/getters.ts +++ /dev/null @@ -1,335 +0,0 @@ -import { - EnvironmentVariable, - HoppCollectionVariable, - HoppRESTHeader, - HoppRESTParam, - HoppRESTRequestVariables, - parseTemplateStringE, -} from "@hoppscotch/data"; -import axios, { AxiosError } from "axios"; -import chalk from "chalk"; -import * as A from "fp-ts/Array"; -import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; -import { pipe } from "fp-ts/function"; -import * as S from "fp-ts/string"; -import fs from "fs/promises"; -import { round } from "lodash-es"; - -import { error } from "../types/errors"; -import { DEFAULT_DURATION_PRECISION } from "./constants"; -import { readJsonFile } from "./mutators"; -import { - WorkspaceCollection, - WorkspaceEnvironment, - transformWorkspaceCollections, - transformWorkspaceEnvironment, -} from "./workspace-access"; - -type GetResourceContentsParams = { - pathOrId: string; - accessToken?: string; - serverUrl?: string; - resourceType: "collection" | "environment"; -}; - -/** - * Generates template string (status + statusText) with specific color unicodes - * based on type of status. - * @param status Status code of a HTTP response. - * @param statusText Status text of a HTTP response. - * @returns Template string with related color unicodes. - */ -export const getColorStatusCode = ( - status: number | string, - statusText: string -): string => { - const statusCode = `${status == 0 ? "Error" : status} : ${statusText}`; - - if (status.toString().startsWith("2")) { - return chalk.greenBright(statusCode); - } else if (status.toString().startsWith("3")) { - return chalk.yellowBright(statusCode); - } - - return chalk.redBright(statusCode); -}; - -/** - * Replaces all template-string with their effective ENV values to generate effective - * request headers/parameters meta-data. - * @param metaData Headers/parameters on which ENVs will be applied. - * @param resolvedVariables Provides ENV variables for parsing template-string. - * @returns Active, non-empty-key, parsed headers/parameters pairs. - */ -export const getEffectiveFinalMetaData = ( - metaData: HoppRESTHeader[] | HoppRESTParam[], - resolvedVariables: EnvironmentVariable[] -) => - pipe( - metaData, - - /** - * Selecting only non-empty and active pairs. - */ - A.filter(({ key, active }) => !S.isEmpty(key) && active), - A.map(({ key, value, description }) => { - return { - active: true, - key: parseTemplateStringE(key, resolvedVariables), - value: parseTemplateStringE(value, resolvedVariables), - description, - }; - }), - E.fromPredicate( - /** - * Check if every key-value is right either. Else return HoppCLIError with - * appropriate reason. - */ - A.every(({ key, value }) => E.isRight(key) && E.isRight(value)), - (reason) => error({ code: "PARSING_ERROR", data: reason }) - ), - E.map( - /** - * Filtering and mapping only right-eithers for each key-value as [string, string]. - */ - A.filterMap(({ key, value, description }) => - E.isRight(key) && E.isRight(value) - ? O.some({ - active: true, - key: key.right, - value: value.right, - description, - }) - : O.none - ) - ) - ); - -/** - * Reduces array of HoppRESTParam or HoppRESTHeader to unique key-value - * pair. - * @param metaData Array of meta-data to reduce. - * @returns Object with unique key-value pair. - */ -export const getMetaDataPairs = ( - metaData: HoppRESTParam[] | HoppRESTHeader[] -) => - pipe( - metaData, - - // Excluding non-active & empty key request meta-data. - A.filter(({ active, key }) => active && !S.isEmpty(key)), - - // Reducing array of request-meta-data to key-value pair object. - A.reduce(>{}, (target, { key, value }) => - Object.assign(target, { [`${key}`]: value }) - ) - ); - -/** - * Object providing aliases for chalk color properties based on exceptions. - */ -export const exceptionColors = { - WARN: chalk.yellow, - INFO: chalk.blue, - FAIL: chalk.red, - SUCCESS: chalk.green, - INFO_BRIGHT: chalk.blueBright, - BG_WARN: chalk.bgYellow, - BG_FAIL: chalk.bgRed, - BG_INFO: chalk.bgBlue, - BG_SUCCESS: chalk.bgGreen, -}; - -/** - * Calculates duration in seconds for given end-HRTime of format [seconds, nanoseconds], - * which is rounded-off upto given decimal value. - * @param end Providing end-HRTime of format [seconds, nanoseconds]. - * @param precision Decimal precision to round-off float duration value (DEFAULT = 3). - * @returns Rounded duration in seconds for given decimal precision. - */ -export const getDurationInSeconds = ( - end: [number, number], - precision: number = DEFAULT_DURATION_PRECISION -) => { - const durationInSeconds = (end[0] * 1e9 + end[1]) / 1e9; - return round(durationInSeconds, precision); -}; - -export const roundDuration = ( - duration: number, - precision: number = DEFAULT_DURATION_PRECISION -) => round(duration, precision); - -/** - * Retrieves the contents of a resource (collection or environment) from a local file (export) or a remote server (workspaces). - * - * @param {GetResourceContentsParams} params - The parameters for retrieving resource contents. - * @param {string} params.pathOrId - The path to the local file or the ID for remote retrieval. - * @param {string} [params.accessToken] - The access token for authorizing remote retrieval. - * @param {string} [params.serverUrl] - The SH instance server URL for remote retrieval. Defaults to the cloud instance. - * @param {"collection" | "environment"} params.resourceType - The type of the resource to retrieve. - * @returns {Promise} A promise that resolves to the contents of the resource. - * @throws Will throw an error if the content type of the fetched resource is not `application/json`, - * if there is an issue with the access token, if the server connection is refused, - * or if the server URL is invalid. - */ -export const getResourceContents = async ( - params: GetResourceContentsParams -): Promise => { - const { pathOrId, accessToken, serverUrl, resourceType } = params; - - let contents: unknown | null = null; - let fileExistsInPath = false; - - try { - await fs.access(pathOrId); - fileExistsInPath = true; - } catch (e) { - fileExistsInPath = false; - } - - if (accessToken && !fileExistsInPath) { - const resolvedServerUrl = serverUrl || "https://api.hoppscotch.io"; - - try { - const separator = resolvedServerUrl.endsWith("/") ? "" : "/"; - const resourcePath = - resourceType === "collection" ? "collection" : "environment"; - - const url = `${resolvedServerUrl}${separator}v1/access-tokens/${resourcePath}/${pathOrId}`; - - const { data, headers } = await axios.get(url, { - headers: { - Authorization: `Bearer ${accessToken}`, - }, - }); - - if (!headers["content-type"].includes("application/json")) { - throw new AxiosError("INVALID_CONTENT_TYPE"); - } - - contents = - resourceType === "collection" - ? transformWorkspaceCollections([data] as WorkspaceCollection[])[0] - : transformWorkspaceEnvironment(data as WorkspaceEnvironment); - } catch (err) { - if (err instanceof AxiosError) { - const axiosErr: AxiosError<{ - reason?: "TOKEN_EXPIRED" | "TOKEN_INVALID" | "INVALID_ID"; - message: string; - statusCode: number; - }> = err; - - const errReason = axiosErr.response?.data?.reason; - - if (errReason) { - throw error({ - code: errReason, - data: ["TOKEN_EXPIRED", "TOKEN_INVALID"].includes(errReason) - ? accessToken - : pathOrId, - }); - } - - if (axiosErr.code === "ECONNREFUSED") { - throw error({ - code: "SERVER_CONNECTION_REFUSED", - data: resolvedServerUrl, - }); - } - - if ( - axiosErr.message === "INVALID_CONTENT_TYPE" || - axiosErr.code === "ERR_INVALID_URL" || - axiosErr.code === "ENOTFOUND" || - axiosErr.code === "ERR_BAD_REQUEST" || - axiosErr.response?.status === 404 - ) { - throw error({ code: "INVALID_SERVER_URL", data: resolvedServerUrl }); - } - } else { - throw error({ code: "UNKNOWN_ERROR", data: err }); - } - } - } - - // Fallback to reading from file if contents are not available - if (contents === null) { - contents = await readJsonFile(pathOrId, fileExistsInPath); - } - - return contents; -}; - -/** - * Processes incoming request variables and environment variables and returns a list - * where active request variables are picked and prioritised over the supplied environment variables. - * Falls back to environment variables for an empty request variable. - * - * @param {HoppRESTRequestVariables} requestVariables - Incoming request variables. - * @param {EnvironmentVariable[]} environmentVariables - Incoming environment variables. - * @param {HoppCollectionVariable[]} collectionVariables - Optional collection variables to be included. - * @returns {EnvironmentVariable[]} The resolved list of variables that conforms to the shape of environment variables. - */ -export const getResolvedVariables = ( - requestVariables: HoppRESTRequestVariables, - environmentVariables: EnvironmentVariable[], - collectionVariables: HoppCollectionVariable[] = [] -): EnvironmentVariable[] => { - // Transforming request variables to the shape of environment variables - const activeRequestVariables = requestVariables - .filter(({ active, value }) => active && value) - .map(({ key, value }) => ({ - key, - initialValue: value, - currentValue: value, - secret: false, - })); - - const requestVariableKeys = activeRequestVariables.map(({ key }) => key); - - // Request variables have higher priority, hence filtering out collection variables with the same keys - const filteredCollectionVariables = collectionVariables.filter( - ({ key }) => !requestVariableKeys.includes(key) - ); - - const collectionVariableKeys = filteredCollectionVariables.map( - ({ key }) => key - ); - - // Filtering out environment variables that have keys present in request or collection variables - const filteredEnvironmentVariables = environmentVariables.filter( - ({ key }) => - ![...requestVariableKeys, ...collectionVariableKeys].includes(key) - ); - - // Setting currentValue to initialValue for environment variables - // because the exported file might not have the currentValue field - const processedEnvironmentVariables = filteredEnvironmentVariables.map( - ({ key, initialValue, currentValue, secret }) => ({ - key, - initialValue, - currentValue: - currentValue && currentValue !== "" ? currentValue : initialValue, - secret, - }) - ); - - const processedCollectionVariables = filteredCollectionVariables.map( - ({ key, initialValue, currentValue, secret }) => ({ - key, - initialValue, - currentValue: - currentValue && currentValue !== "" ? currentValue : initialValue, - secret, - }) - ); - - return [ - ...activeRequestVariables, - ...processedCollectionVariables, - ...processedEnvironmentVariables, - ]; -}; diff --git a/packages/hoppscotch-cli/src/utils/hopp-fetch.ts b/packages/hoppscotch-cli/src/utils/hopp-fetch.ts deleted file mode 100644 index 652b6e1e..00000000 --- a/packages/hoppscotch-cli/src/utils/hopp-fetch.ts +++ /dev/null @@ -1,274 +0,0 @@ -import axios, { Method } from "axios"; -import type { HoppFetchHook } from "@hoppscotch/js-sandbox"; -import { wrapper as axiosCookieJarSupport } from "axios-cookiejar-support"; -import { CookieJar } from "tough-cookie"; - -/** - * Creates a hopp.fetch() hook implementation for CLI. - * Uses axios directly for network requests since CLI has no interceptor concept. - * - * @returns HoppFetchHook implementation - */ -export const createHoppFetchHook = (): HoppFetchHook => { - // Cookie jar maintains cookies across redirects (matches Postman behavior) - const jar = new CookieJar(); - const axiosWithCookies = axiosCookieJarSupport(axios.create()); - - return async (input, init) => { - // Extract URL from different input types - const urlStr = - typeof input === "string" - ? input - : input instanceof URL - ? input.href - : input.url; - - // Extract method from Request object if available (init takes precedence) - const requestMethod = input instanceof Request ? input.method : undefined; - const method = (init?.method || requestMethod || "GET") as Method; - - // Merge headers from Request object and init (init takes precedence) - const headers: Record = {}; - - // First, add headers from Request object if input is a Request - if (input instanceof Request) { - input.headers.forEach((value, key) => { - headers[key] = value; - }); - } - - // Then overlay with init.headers (takes precedence) - if (init?.headers) { - Object.assign(headers, headersToObject(init.headers)); - } - - // Extract body from Request object if available (init takes precedence) - // Note: Request.body is a ReadableStream which axios cannot handle, - // so we need to read it first - let body: BodyInit | null | undefined; - if (init?.body !== undefined) { - body = init.body; - } else if (input instanceof Request && input.body !== null) { - // Read the ReadableStream into an ArrayBuffer that axios can send - const clonedRequest = input.clone(); - body = await clonedRequest.arrayBuffer(); - } else { - body = undefined; - } - - // Convert Fetch API options to axios config - // Note: Using 'any' for config because axios-cookiejar-support extends AxiosRequestConfig - // with 'jar' property that isn't in standard types - const config: any = { - url: urlStr, - method, - headers: Object.keys(headers).length > 0 ? headers : {}, - data: body, - responseType: "arraybuffer", // Prevents binary corruption from string encoding - validateStatus: () => true, // Don't throw on any status code - jar, - withCredentials: true, // Required for cookie jar - }; - - // Handle AbortController signal if provided - if (init?.signal) { - config.signal = init.signal; - } - - try { - const axiosResponse = await axiosWithCookies(config); - - // Convert axios response to serializable response (with _bodyBytes) - // Native Response objects can't cross VM boundaries - return createSerializableResponse( - axiosResponse.status, - axiosResponse.statusText, - axiosResponse.headers, - axiosResponse.data - ); - } catch (error) { - // Handle axios errors - if (axios.isAxiosError(error) && error.response) { - // Return error response as serializable Response object - return createSerializableResponse( - error.response.status, - error.response.statusText, - error.response.headers, - error.response.data - ); - } - - // Network error or other failure - throw new Error( - `Fetch failed: ${error instanceof Error ? error.message : "Unknown error"}` - ); - } - }; -}; - -/** - * Creates a serializable Response-like object with _bodyBytes. - * - * Native Response objects can't cross the QuickJS boundary due to internal state. - * Returns a plain object with all data loaded upfront. - */ -function createSerializableResponse( - status: number, - statusText: string, - headers: any, - body: any -): Response { - const ok = status >= 200 && status < 300; - - // Convert headers to plain object (serializable) - // Set-Cookie headers kept separate - commas can appear in cookie values - const headersObj: Record = {}; - const setCookieHeaders: string[] = []; - - Object.entries(headers).forEach(([key, value]) => { - if (value !== undefined) { - if (key.toLowerCase() === "set-cookie") { - // Preserve Set-Cookie headers as array for getSetCookie() compatibility - if (Array.isArray(value)) { - setCookieHeaders.push(...value); - } else { - setCookieHeaders.push(String(value)); - } - // Also store first Set-Cookie in headersObj for backward compatibility - headersObj[key] = Array.isArray(value) ? value[0] : String(value); - } else { - // Other headers can be safely concatenated with commas - headersObj[key] = Array.isArray(value) - ? value.join(", ") - : String(value); - } - } - }); - - // Store body as plain number array for VM serialization - let bodyBytes: number[] = []; - - if (body) { - if (Array.isArray(body)) { - // Already an array - bodyBytes = body; - } else if (body instanceof ArrayBuffer) { - // ArrayBuffer (from axios) - convert to plain array - bodyBytes = Array.from(new Uint8Array(body)); - } else if (body instanceof Uint8Array) { - // Uint8Array - convert to plain array - bodyBytes = Array.from(body); - } else if (ArrayBuffer.isView(body)) { - // Other typed array - bodyBytes = Array.from(new Uint8Array(body.buffer)); - } else if (typeof body === "string") { - // String body - bodyBytes = Array.from(new TextEncoder().encode(body)); - } else if (typeof body === "object") { - // Check if it's a Buffer-like object with 'type' and 'data' properties - if ("type" in body && "data" in body && Array.isArray(body.data)) { - bodyBytes = body.data; - } else { - // Plain object with numeric keys (like {0: 72, 1: 101, ...}) - const keys = Object.keys(body) - .map(Number) - .filter((n) => !isNaN(n)) - .sort((a, b) => a - b); - bodyBytes = keys.map((k) => body[k]); - } - } - } - - // Create Response-like object with all methods implemented using stored data - const serializableResponse = { - status, - statusText, - ok, - // Store raw headers data for fetch module to use - _headersData: headersObj, - headers: { - get(name: string): string | null { - // Case-insensitive header lookup - const lowerName = name.toLowerCase(); - for (const [key, value] of Object.entries(headersObj)) { - if (key.toLowerCase() === lowerName) { - return value; - } - } - return null; - }, - has(name: string): boolean { - return this.get(name) !== null; - }, - entries(): IterableIterator<[string, string]> { - return Object.entries(headersObj)[Symbol.iterator](); - }, - keys(): IterableIterator { - return Object.keys(headersObj)[Symbol.iterator](); - }, - values(): IterableIterator { - return Object.values(headersObj)[Symbol.iterator](); - }, - forEach(callback: (value: string, key: string) => void) { - Object.entries(headersObj).forEach(([key, value]) => - callback(value, key) - ); - }, - // Returns all Set-Cookie headers as array - getSetCookie(): string[] { - return setCookieHeaders; - }, - }, - _bodyBytes: bodyBytes, - - // Body methods - will be overridden by custom fetch module with VM-native versions - async text(): Promise { - return new TextDecoder().decode(new Uint8Array(bodyBytes)); - }, - - async json(): Promise { - const text = await this.text(); - return JSON.parse(text); - }, - - async arrayBuffer(): Promise { - return new Uint8Array(bodyBytes).buffer; - }, - - async blob(): Promise { - return new Blob([new Uint8Array(bodyBytes)]); - }, - - // Required Response properties - type: "basic" as ResponseType, - url: "", - redirected: false, - bodyUsed: false, - }; - - // Cast to Response for type compatibility - return serializableResponse as unknown as Response; -} - -/** - * Converts Fetch API headers to plain object for axios - */ -function headersToObject(headers: HeadersInit): Record { - const result: Record = {}; - - if (headers instanceof Headers) { - headers.forEach((value, key) => { - result[key] = value; - }); - } else if (Array.isArray(headers)) { - headers.forEach(([key, value]) => { - result[key] = value; - }); - } else { - Object.entries(headers).forEach(([key, value]) => { - result[key] = value; - }); - } - - return result; -} diff --git a/packages/hoppscotch-cli/src/utils/jsonc.ts b/packages/hoppscotch-cli/src/utils/jsonc.ts deleted file mode 100644 index 00522036..00000000 --- a/packages/hoppscotch-cli/src/utils/jsonc.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Node, parseTree, stripComments as stripComments_ } from "jsonc-parser"; - -/** - * An internal error that is thrown when an invalid JSONC node configuration - * is encountered - */ -class InvalidJSONCNodeError extends Error { - constructor() { - super(); - this.message = "Invalid JSONC node"; - } -} - -// NOTE: If we choose to export this function, do refactor it to return a result discriminated union instead of throwing -/** - * @throws {InvalidJSONCNodeError} if the node is in an invalid configuration - * @returns The JSON string without comments and trailing commas - */ -function convertNodeToJSON(node: Node): string { - switch (node.type) { - case "string": - return JSON.stringify(node.value); - case "null": - return "null"; - case "array": - if (!node.children) { - throw new InvalidJSONCNodeError(); - } - - return `[${node.children - .map((child) => convertNodeToJSON(child)) - .join(",")}]`; - case "number": - return JSON.stringify(node.value); - case "boolean": - return JSON.stringify(node.value); - case "object": - if (!node.children) { - throw new InvalidJSONCNodeError(); - } - - return `{${node.children - .map((child) => convertNodeToJSON(child)) - .join(",")}}`; - case "property": - if (!node.children || node.children.length !== 2) { - throw new InvalidJSONCNodeError(); - } - - const [keyNode, valueNode] = node.children; - - // Use keyNode.value instead of keyNode to avoid circular references. - // Attempting to JSON.stringify(keyNode) directly would throw - // "Converting circular structure to JSON" error. - // If the valueNode configuration is wrong, this will return an error, which will propagate up - return `${JSON.stringify(keyNode.value)}:${convertNodeToJSON(valueNode)}`; - } -} - -function stripCommentsAndCommas(text: string): string { - const tree = parseTree(text, undefined, { - allowEmptyContent: true, - allowTrailingComma: true, - }); - - // If we couldn't parse the tree, return the original text - if (!tree) { - return text; - } - - // convertNodeToJSON can throw an error if the tree is invalid - try { - return convertNodeToJSON(tree); - } catch (_) { - return text; - } -} - -/** - * Removes comments and trailing commas from a JSONC string. - * This is needed because APIs like AWS Cognito expect valid JSON without comments, - * but Hoppscotch allows users to add comments to their request bodies. - * - * @param jsoncString The JSONC string with comments and/or trailing commas. - * @returns The clean JSON string without comments or trailing commas. - */ -export function stripComments(jsoncString: string): string { - return stripCommentsAndCommas(stripComments_(jsoncString) ?? jsoncString); -} diff --git a/packages/hoppscotch-cli/src/utils/mutators.ts b/packages/hoppscotch-cli/src/utils/mutators.ts deleted file mode 100644 index 245486cd..00000000 --- a/packages/hoppscotch-cli/src/utils/mutators.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { Environment, HoppCollection, HoppRESTRequest } from "@hoppscotch/data"; -import fs from "fs/promises"; -import { entityReference } from "verzod"; -import { z } from "zod"; - -import { TestCmdCollectionOptions } from "../types/commands"; -import { error } from "../types/errors"; -import { FormDataEntry } from "../types/request"; -import { isHoppErrnoException } from "./checks"; -import { getResourceContents } from "./getters"; - -// Re-export from the canonical implementation in scripting.ts -export { stripModulePrefix } from "./scripting"; - -const getValidRequests = ( - collections: HoppCollection[], - collectionFilePath: string -) => { - return collections.map((collection) => { - // Validate requests using zod schema - const requestSchemaParsedResult = z - .array(entityReference(HoppRESTRequest)) - .safeParse(collection.requests); - - // Handle validation errors - if (!requestSchemaParsedResult.success) { - throw error({ - code: "MALFORMED_COLLECTION", - path: collectionFilePath, - data: "Please check the collection data.", - }); - } - - // Recursively validate requests in nested folders - if (collection.folders.length > 0) { - collection.folders = getValidRequests( - collection.folders, - collectionFilePath - ); - } - - // Return validated collection - return { - ...collection, - requests: requestSchemaParsedResult.data, - }; - }); -}; - -/** - * Parses array of FormDataEntry to FormData. - * @param values Array of FormDataEntry. - * @returns FormData with key-value pair from FormDataEntry. - */ -export const toFormData = (values: FormDataEntry[]) => { - const formData = new FormData(); - - values.forEach(({ key, value, contentType }) => { - if (contentType) { - formData.append( - key, - new Blob([value], { - type: contentType, - }), - key - ); - - return; - } - - formData.append(key, value); - }); - - return formData; -}; - -/** - * Parses provided error message to maintain hopp-error messages. - * @param e Custom error data. - * @returns Parsed error message without extra spaces. - */ -export const parseErrorMessage = (e: unknown) => { - let msg: string; - if (isHoppErrnoException(e)) { - msg = e.message.replace(e.code! + ":", "").replace("error:", ""); - } else if (typeof e === "string") { - msg = e; - } else { - msg = JSON.stringify(e); - } - return msg.replace(/\n+$|\s{2,}/g, "").trim(); -}; - -/** - * Reads a JSON file from the specified path and returns the parsed content. - * - * @param {string} path - The path to the JSON file. - * @param {boolean} fileExistsInPath - Indicates whether the file exists in the specified path. - * @returns {Promise} A Promise that resolves to the parsed JSON contents. - * @throws {Error} If the file path does not end with `.json`. - * @throws {Error} If the file does not exist in the specified path. - * @throws {Error} If an unknown error occurs while reading or parsing the file. - */ -export async function readJsonFile( - path: string, - fileExistsInPath: boolean -): Promise { - if (!path.endsWith(".json")) { - throw error({ code: "INVALID_FILE_TYPE", data: path }); - } - - if (!fileExistsInPath) { - throw error({ code: "FILE_NOT_FOUND", path }); - } - - try { - return JSON.parse((await fs.readFile(path)).toString()); - } catch (e) { - throw error({ code: "UNKNOWN_ERROR", data: e }); - } -} - -/** - * Parses collection data from a given path or ID and returns the data conforming to the latest version of the `HoppCollection` schema. - * - * @param pathOrId Collection JSON file path/ID from a workspace. - * @param {TestCmdCollectionOptions} options Supplied values for CLI flags. - * @param {string} [options.token] Personal access token to fetch workspace environments. - * @param {string} [options.server] server URL for SH instance. - * @returns {Promise} A promise that resolves to an array of HoppCollection objects. - * @throws Throws an error if the collection data is malformed. - */ -export async function parseCollectionData( - pathOrId: string, - options: TestCmdCollectionOptions -): Promise { - const { token: accessToken, server: serverUrl } = options; - - const contents = await getResourceContents({ - pathOrId, - accessToken, - serverUrl, - resourceType: "collection", - }); - - const maybeArrayOfCollections: unknown[] = Array.isArray(contents) - ? contents - : [contents]; - - const collectionSchemaParsedResult = z - .array(entityReference(HoppCollection)) - .safeParse(maybeArrayOfCollections); - - if (!collectionSchemaParsedResult.success) { - throw error({ - code: "MALFORMED_COLLECTION", - path: pathOrId, - data: "Please check the collection data.", - }); - } - - return getValidRequests(collectionSchemaParsedResult.data, pathOrId); -} diff --git a/packages/hoppscotch-cli/src/utils/pre-request.ts b/packages/hoppscotch-cli/src/utils/pre-request.ts deleted file mode 100644 index 283f3721..00000000 --- a/packages/hoppscotch-cli/src/utils/pre-request.ts +++ /dev/null @@ -1,685 +0,0 @@ -import { - Environment, - EnvironmentVariable, - HoppCollectionVariable, - HoppRESTRequest, - calculateHawkHeader, - generateJWTToken, - parseBodyEnvVariablesE, - parseRawKeyValueEntriesE, - parseTemplateString, - parseTemplateStringE, -} from "@hoppscotch/data"; -import { runPreRequestScript } from "@hoppscotch/js-sandbox/node"; -import { AwsV4Signer } from "aws4fetch"; -import * as A from "fp-ts/Array"; -import * as E from "fp-ts/Either"; -import * as O from "fp-ts/Option"; -import * as RA from "fp-ts/ReadonlyArray"; -import * as TE from "fp-ts/TaskEither"; -import { flow, pipe } from "fp-ts/function"; -import * as S from "fp-ts/string"; -import qs from "qs"; -import { createHoppFetchHook } from "./hopp-fetch"; - -import { EffectiveHoppRESTRequest } from "../interfaces/request"; -import { HoppCLIError, error } from "../types/errors"; -import { HoppEnvs } from "../types/request"; -import { PreRequestMetrics } from "../types/response"; -import { - DigestAuthParams, - fetchInitialDigestAuthInfo, - generateDigestAuthHeader, -} from "./auth/digest"; -import { isHoppCLIError } from "./checks"; -import { arrayFlatMap, arraySort, tupleToRecord } from "./functions/array"; -import { getEffectiveFinalMetaData, getResolvedVariables } from "./getters"; -import { stripComments } from "./jsonc"; -import { toFormData } from "./mutators"; -import { combineScriptsWithIIFE, filterValidScripts } from "./scripting"; - -/** - * Runs pre-request-script runner over given request which extracts set ENVs and - * applies them on current request to generate updated request. - * @param request HoppRESTRequest to be converted to EffectiveHoppRESTRequest. - * @param envs Environment variables related to request. - * @param legacySandbox Whether to use the legacy sandbox. - * @param collectionVariables Collection variables to use. - * @param inheritedPreRequestScripts Pre-request scripts inherited from parent collections. - * @returns EffectiveHoppRESTRequest that includes parsed ENV variables with in - * request OR HoppCLIError with error code and related information. - */ -export const preRequestScriptRunner = ( - request: HoppRESTRequest, - envs: HoppEnvs, - legacySandbox: boolean, - collectionVariables?: HoppCollectionVariable[], - inheritedPreRequestScripts: string[] = [] -): TE.TaskEither< - HoppCLIError, - { effectiveRequest: EffectiveHoppRESTRequest } & { updatedEnvs: HoppEnvs } -> => { - const experimentalScriptingSandbox = !legacySandbox; - const hoppFetchHook = createHoppFetchHook(); - - // Pre-request order: root → request. - const combinedScript = combineScriptsWithIIFE( - filterValidScripts([ - ...inheritedPreRequestScripts, - request.preRequestScript, - ]), - experimentalScriptingSandbox ? "experimental" : "legacy" - ); - - return pipe( - TE.of(request), - TE.chain(() => - runPreRequestScript(combinedScript, { - envs, - experimentalScriptingSandbox, - request, - cookies: null, - hoppFetchHook, - }) - ), - TE.map(({ updatedEnvs, updatedRequest }) => { - const { selected, global } = updatedEnvs; - - return { - // Keep the original updatedEnvs with separate global and selected arrays - preRequestUpdatedEnvs: updatedEnvs, - // Create Environment format for getEffectiveRESTRequest - envForEffectiveRequest: { - name: "Env", - variables: [...(selected ?? []), ...(global ?? [])], - }, - updatedRequest: updatedRequest ?? {}, - }; - }), - TE.chainW( - ({ preRequestUpdatedEnvs, envForEffectiveRequest, updatedRequest }) => { - const finalRequest = { ...request, ...updatedRequest }; - - return TE.tryCatch( - async () => { - const result = await getEffectiveRESTRequest( - finalRequest, - envForEffectiveRequest, - collectionVariables - ); - // Replace the updatedEnvs from getEffectiveRESTRequest with the one from pre-request script - // This preserves the global/selected separation - if (E.isRight(result)) { - return E.right({ - ...result.right, - updatedEnvs: preRequestUpdatedEnvs, - }); - } - return result; - }, - (reason) => error({ code: "PRE_REQUEST_SCRIPT_ERROR", data: reason }) - ); - } - ), - TE.chainEitherKW((effectiveRequest) => effectiveRequest), - TE.mapLeft((reason) => - isHoppCLIError(reason) - ? reason - : error({ - code: "PRE_REQUEST_SCRIPT_ERROR", - data: reason, - }) - ) - ); -}; - -/** - * Outputs an executable request format with environment variables applied - * - * @param request The request to source from - * @param environment The environment to apply - * - * @returns An object with extra fields defining a complete request - */ -export async function getEffectiveRESTRequest( - request: HoppRESTRequest, - environment: Environment, - collectionVariables?: HoppCollectionVariable[] -): Promise< - E.Either< - HoppCLIError, - { effectiveRequest: EffectiveHoppRESTRequest } & { updatedEnvs: HoppEnvs } - > -> { - const envVariables = environment.variables; - - const resolvedVariables = getResolvedVariables( - request.requestVariables, - envVariables, - collectionVariables - ); - - // Parsing final headers with applied ENVs. - const _effectiveFinalHeaders = getEffectiveFinalMetaData( - request.headers, - resolvedVariables - ); - if (E.isLeft(_effectiveFinalHeaders)) { - return _effectiveFinalHeaders; - } - const effectiveFinalHeaders = _effectiveFinalHeaders.right; - - // Parsing final parameters with applied ENVs. - const _effectiveFinalParams = getEffectiveFinalMetaData( - request.params, - resolvedVariables - ); - if (E.isLeft(_effectiveFinalParams)) { - return _effectiveFinalParams; - } - const effectiveFinalParams = _effectiveFinalParams.right; - - // Parsing final-body with applied ENVs. - const _effectiveFinalBody = getFinalBodyFromRequest( - request, - resolvedVariables - ); - if (E.isLeft(_effectiveFinalBody)) { - return _effectiveFinalBody; - } - - // Authentication - if (request.auth.authActive) { - // TODO: Support a better b64 implementation than btoa ? - if (request.auth.authType === "basic") { - const username = parseTemplateString( - request.auth.username, - resolvedVariables - ); - const password = parseTemplateString( - request.auth.password, - resolvedVariables - ); - - effectiveFinalHeaders.push({ - active: true, - key: "Authorization", - value: `Basic ${btoa(`${username}:${password}`)}`, - description: "", - }); - } else if (request.auth.authType === "bearer") { - effectiveFinalHeaders.push({ - active: true, - key: "Authorization", - value: `Bearer ${parseTemplateString(request.auth.token, resolvedVariables)}`, - description: "", - }); - } else if (request.auth.authType === "oauth-2") { - const { addTo } = request.auth; - - if (addTo === "HEADERS") { - effectiveFinalHeaders.push({ - active: true, - key: "Authorization", - value: `Bearer ${parseTemplateString(request.auth.grantTypeInfo.token, resolvedVariables)}`, - description: "", - }); - } else if (addTo === "QUERY_PARAMS") { - effectiveFinalParams.push({ - active: true, - key: "access_token", - value: parseTemplateString( - request.auth.grantTypeInfo.token, - resolvedVariables - ), - description: "", - }); - } - } else if (request.auth.authType === "api-key") { - const { key, value, addTo } = request.auth; - if (addTo === "HEADERS") { - effectiveFinalHeaders.push({ - active: true, - key: parseTemplateString(key, resolvedVariables), - value: parseTemplateString(value, resolvedVariables), - description: "", - }); - } else if (addTo === "QUERY_PARAMS") { - effectiveFinalParams.push({ - active: true, - key: parseTemplateString(key, resolvedVariables), - value: parseTemplateString(value, resolvedVariables), - description: "", - }); - } - } else if (request.auth.authType === "aws-signature") { - const { addTo } = request.auth; - - const currentDate = new Date(); - const amzDate = currentDate.toISOString().replace(/[:-]|\.\d{3}/g, ""); - const { method, endpoint } = request; - - const body = getFinalBodyFromRequest(request, resolvedVariables); - - const signer = new AwsV4Signer({ - method, - body: E.isRight(body) ? body.right?.toString() : undefined, - datetime: amzDate, - signQuery: addTo === "QUERY_PARAMS", - accessKeyId: parseTemplateString( - request.auth.accessKey, - resolvedVariables - ), - secretAccessKey: parseTemplateString( - request.auth.secretKey, - resolvedVariables - ), - region: - parseTemplateString(request.auth.region, resolvedVariables) ?? - "us-east-1", - service: parseTemplateString( - request.auth.serviceName, - resolvedVariables - ), - url: parseTemplateString(endpoint, resolvedVariables), - sessionToken: - request.auth.serviceToken && - parseTemplateString(request.auth.serviceToken, resolvedVariables), - }); - - const sign = await signer.sign(); - - if (addTo === "HEADERS") { - sign.headers.forEach((value, key) => { - effectiveFinalHeaders.push({ - active: true, - key, - value, - description: "", - }); - }); - } else if (addTo === "QUERY_PARAMS") { - sign.url.searchParams.forEach((value, key) => { - effectiveFinalParams.push({ - active: true, - key, - value, - description: "", - }); - }); - } - } else if (request.auth.authType === "digest") { - const { method, endpoint } = request as HoppRESTRequest; - - // Step 1: Fetch the initial auth info (nonce, realm, etc.) - const authInfo = await fetchInitialDigestAuthInfo( - parseTemplateString(endpoint, resolvedVariables), - method, - request.auth.disableRetry - ); - - // Step 2: Set up the parameters for the digest authentication header - const digestAuthParams: DigestAuthParams = { - username: parseTemplateString(request.auth.username, resolvedVariables), - password: parseTemplateString(request.auth.password, resolvedVariables), - realm: request.auth.realm - ? parseTemplateString(request.auth.realm, resolvedVariables) - : authInfo.realm, - nonce: request.auth.nonce - ? parseTemplateString(authInfo.nonce, resolvedVariables) - : authInfo.nonce, - endpoint: parseTemplateString(endpoint, resolvedVariables), - method, - algorithm: request.auth.algorithm ?? authInfo.algorithm, - qop: request.auth.qop - ? parseTemplateString(request.auth.qop, resolvedVariables) - : authInfo.qop, - opaque: request.auth.opaque - ? parseTemplateString(request.auth.opaque, resolvedVariables) - : authInfo.opaque, - reqBody: typeof request.body.body === "string" ? request.body.body : "", - }; - - // Step 3: Generate the Authorization header - const authHeaderValue = await generateDigestAuthHeader(digestAuthParams); - - effectiveFinalHeaders.push({ - active: true, - key: "Authorization", - value: authHeaderValue, - description: "", - }); - } else if (request.auth.authType === "hawk") { - const { method, endpoint } = request; - - const hawkHeader = await calculateHawkHeader({ - url: parseTemplateString(endpoint, resolvedVariables), // URL - method: method, // HTTP method - id: parseTemplateString(request.auth.authId, resolvedVariables), - key: parseTemplateString(request.auth.authKey, resolvedVariables), - algorithm: request.auth.algorithm, - - // advanced parameters (optional) - includePayloadHash: request.auth.includePayloadHash, - nonce: request.auth.nonce - ? parseTemplateString(request.auth.nonce, resolvedVariables) - : undefined, - ext: request.auth.ext - ? parseTemplateString(request.auth.ext, resolvedVariables) - : undefined, - app: request.auth.app - ? parseTemplateString(request.auth.app, resolvedVariables) - : undefined, - dlg: request.auth.dlg - ? parseTemplateString(request.auth.dlg, resolvedVariables) - : undefined, - timestamp: request.auth.timestamp - ? parseInt( - parseTemplateString(request.auth.timestamp, resolvedVariables), - 10 - ) - : undefined, - }); - - effectiveFinalHeaders.push({ - active: true, - key: "Authorization", - value: hawkHeader, - description: "", - }); - } else if (request.auth.authType === "jwt") { - const { addTo } = request.auth; - - // Generate JWT token - const token = await generateJWTToken({ - algorithm: request.auth.algorithm || "HS256", - secret: parseTemplateString(request.auth.secret, resolvedVariables), - privateKey: parseTemplateString( - request.auth.privateKey, - resolvedVariables - ), - payload: parseTemplateString(request.auth.payload, resolvedVariables), - jwtHeaders: parseTemplateString( - request.auth.jwtHeaders, - resolvedVariables - ), - isSecretBase64Encoded: request.auth.isSecretBase64Encoded, - }); - - if (token) { - if (addTo === "HEADERS") { - const headerPrefix = - parseTemplateString(request.auth.headerPrefix, resolvedVariables) || - "Bearer "; - - effectiveFinalHeaders.push({ - active: true, - key: "Authorization", - value: `${headerPrefix}${token}`, - description: "", - }); - } else if (addTo === "QUERY_PARAMS") { - const paramName = - parseTemplateString(request.auth.paramName, resolvedVariables) || - "token"; - - effectiveFinalParams.push({ - active: true, - key: paramName, - value: token, - description: "", - }); - } - } - } - } - - const effectiveFinalBody = _effectiveFinalBody.right; - - if ( - request.body.contentType && - !effectiveFinalHeaders.some( - ({ key }) => key.toLowerCase() === "content-type" - ) - ) { - effectiveFinalHeaders.push({ - active: true, - key: "Content-Type", - value: request.body.contentType, - description: "", - }); - } - - // Parsing final-endpoint with applied ENVs (environment + request variables). - const _effectiveFinalURL = parseTemplateStringE( - request.endpoint, - resolvedVariables - ); - if (E.isLeft(_effectiveFinalURL)) { - return E.left( - error({ - code: "PARSING_ERROR", - data: `${request.endpoint} (${_effectiveFinalURL.left})`, - }) - ); - } - const effectiveFinalURL = _effectiveFinalURL.right; - - // Secret environment variables referenced in the request endpoint should be masked - let effectiveFinalDisplayURL; - if (envVariables.some(({ secret }) => secret)) { - const _effectiveFinalDisplayURL = parseTemplateStringE( - request.endpoint, - resolvedVariables, - true - ); - - if (E.isRight(_effectiveFinalDisplayURL)) { - effectiveFinalDisplayURL = _effectiveFinalDisplayURL.right; - } - } - - return E.right({ - effectiveRequest: { - ...request, - effectiveFinalURL, - effectiveFinalDisplayURL, - effectiveFinalHeaders, - effectiveFinalParams, - effectiveFinalBody, - }, - updatedEnvs: { global: [], selected: resolvedVariables }, - }); -} - -/** - * Replaces template variables in request's body from the given set of ENVs, - * to generate final request body without any template variables. - * @param request Provides request's body, on which ENVs has to be applied. - * @param resolvedVariables Provides set of key-value pairs (request + environment variables), - * used to parse-out template variables. - * @returns Final request body without any template variables as value. - * Or, HoppCLIError in case of error while parsing. - */ -function getFinalBodyFromRequest( - request: HoppRESTRequest, - resolvedVariables: EnvironmentVariable[] -): E.Either { - if (request.body.contentType === null) { - return E.right(null); - } - - if (request.body.contentType === "application/x-www-form-urlencoded") { - return pipe( - request.body.body, - parseRawKeyValueEntriesE, - E.map( - flow( - RA.toArray, - - /** - * Filtering out empty keys and non-active pairs. - */ - A.filter(({ active, key }) => active && !S.isEmpty(key)), - - /** - * Mapping each key-value to template-string-parser with either on array, - * which will be resolved in further steps. - */ - A.map(({ key, value }) => [ - parseTemplateStringE(key, resolvedVariables), - parseTemplateStringE(value, resolvedVariables), - ]), - - /** - * Filtering and mapping only right-eithers for each key-value as [string, string]. - */ - A.filterMap(([key, value]) => - E.isRight(key) && E.isRight(value) - ? O.some([key.right, value.right] as [string, string]) - : O.none - ), - tupleToRecord, - qs.stringify - ) - ), - E.mapLeft((e) => error({ code: "PARSING_ERROR", data: e.message })) - ); - } - - if (request.body.contentType === "multipart/form-data") { - return pipe( - request.body.body, - A.filter((x) => x.key !== "" && x.active), // Remove empty keys - - // Sort files down - arraySort((a, b) => { - if (a.isFile) return 1; - if (b.isFile) return -1; - return 0; - }), - - // FormData allows only a single blob in an entry, - // we split array blobs into separate entries (FormData will then join them together during exec) - arrayFlatMap((x) => - x.isFile - ? (x.value as (Blob | null)[]).map((v: Blob | null) => ({ - key: parseTemplateString(x.key, resolvedVariables), - value: v as string | Blob, - contentType: x.contentType, - })) - : [ - { - key: parseTemplateString(x.key, resolvedVariables), - value: parseTemplateString(x.value, resolvedVariables), - contentType: x.contentType, - }, - ] - ), - toFormData, - E.right - ); - } - - if (request.body.contentType === "application/octet-stream") { - const body = request.body.body; - - if (!body) { - return E.right(null); - } - - if (!(body instanceof File)) { - return E.right(null); - } - - return E.right(body); - } - - // For JSON content types, parse the string body into a JavaScript object - // so axios can properly serialize it. This includes standard application/json - // and vendor-specific JSON media types (for example those with a +json suffix - // or subtypes whose names end with "json" or "-json"). - if (request.body.contentType) { - const mimeType = request.body.contentType - .split(";")[0] - .trim() - .toLowerCase(); - - if ( - mimeType === "application/json" || - mimeType.endsWith("+json") || - mimeType.endsWith("/json") || - mimeType.endsWith("-json") - ) { - const envResult = parseBodyEnvVariablesE( - request.body.body, - resolvedVariables - ); - - if (E.isLeft(envResult)) { - return E.left( - error({ - code: "PARSING_ERROR", - data: `${request.body.body} (${envResult.left})`, - }) - ); - } - - const bodyString = envResult.right; - - // If the body string is empty or null, return null - if (!bodyString || S.isEmpty(bodyString.trim())) { - return E.right(null); - } - - // Strip comments and trailing commas from JSONC - // This ensures collections with comments work the same in CLI as in desktop app - const cleanedBody = stripComments(bodyString); - - // Try to parse the JSON body - try { - const parsedBody = JSON.parse(cleanedBody); - return E.right(JSON.stringify(parsedBody)); - } catch (err) { - // If parsing fails after stripping comments, return error to provide - // immediate feedback instead of sending invalid JSON to the API. - // Use original template string to avoid leaking secrets from env vars. - return E.left( - error({ - code: "PARSING_ERROR", - data: `${request.body.body} (Invalid JSON in request body: ${err instanceof Error ? err.message : String(err)})`, - }) - ); - } - } - } - return pipe( - parseBodyEnvVariablesE(request.body.body, resolvedVariables), - E.mapLeft((e) => - error({ - code: "PARSING_ERROR", - data: `${request.body.body} (${e})`, - }) - ) - ); -} - -/** - * Get pre-request-metrics (stats + duration) object based on existence of - * PRE_REQUEST_ERROR code in given hopp-error list. - * @param errors List of errors to check for PRE_REQUEST_ERROR code. - * @param duration Time taken (in seconds) to execute the pre-request-script. - * @returns Object containing details of pre-request-script's execution stats - * i.e., failed/passed data and duration. - */ -export const getPreRequestMetrics = ( - errors: HoppCLIError[], - duration: number -): PreRequestMetrics => - pipe( - errors, - A.some(({ code }) => code === "PRE_REQUEST_SCRIPT_ERROR"), - (hasPreReqErrors) => - hasPreReqErrors ? { failed: 1, passed: 0 } : { failed: 0, passed: 1 }, - (scripts) => { scripts, duration } - ); diff --git a/packages/hoppscotch-cli/src/utils/reporters/junit.ts b/packages/hoppscotch-cli/src/utils/reporters/junit.ts deleted file mode 100644 index a47fdf54..00000000 --- a/packages/hoppscotch-cli/src/utils/reporters/junit.ts +++ /dev/null @@ -1,178 +0,0 @@ -import { info, log } from "console"; -import fs from "fs"; -import path from "path"; - -import { create } from "xmlbuilder2"; -import { XMLBuilder } from "xmlbuilder2/lib/interfaces"; -import { TestReport } from "../../interfaces/response"; -import { error, HoppCLIError } from "../../types/errors"; -import { RequestReport } from "../../types/request"; -import { exceptionColors } from "../getters"; - -type BuildJUnitReportArgs = Omit & { - duration: RequestReport["duration"]["test"]; -}; - -type BuildJUnitReportResult = { - failedRequestTestCases: number; - erroredRequestTestCases: number; -}; - -type GenerateJUnitReportExportArgs = { - totalTestCases: number; - totalFailedTestCases: number; - totalErroredTestCases: number; - testDuration: number; - reporterJUnitExportPath: string; -}; - -const { INFO, SUCCESS } = exceptionColors; - -// Create the root XML element -const rootEl = create({ version: "1.0", encoding: "UTF-8" }).ele("testsuites"); - -/** - * Builds a JUnit report based on the provided request report. - * Creates a test suite at the request level populating the XML document structure. - * - * @param {BuildJUnitReportArgs} options - The options to build the JUnit report. - * @param {string} options.path - The path of the request. - * @param {TestReport[]} options.tests - The test suites for the request. - * @param {HoppCLIError[]} options.errors - The errors encountered during the request. - * @param {number} options.duration - Time taken to execute the test suite. - * @returns {BuildJUnitReportResult} An object containing the number of failed and errored test cases. - */ -export const buildJUnitReport = ({ - path, - tests: testSuites, - errors: requestTestSuiteErrors, - duration: testSuiteDuration, -}: BuildJUnitReportArgs): BuildJUnitReportResult => { - let requestTestSuiteError: XMLBuilder | null = null; - - // Create a test suite at the request level - const requestTestSuite = rootEl.ele("testsuite", { - name: path, - time: testSuiteDuration, - timestamp: new Date().toISOString(), - }); - - if (requestTestSuiteErrors.length > 0) { - requestTestSuiteError = requestTestSuite.ele("system-err"); - } - - let systemErrContent = ""; - - requestTestSuiteErrors.forEach((error) => { - let compiledError = error.code; - - if ("data" in error) { - compiledError += ` - ${error.data}`; - } - - // Append each error message with a newline for separation - systemErrContent += `\n${" ".repeat(6)}${compiledError}`; - }); - - // There'll be a single `CDATA` element compiling all the error messages - if (requestTestSuiteError) { - requestTestSuiteError.dat(systemErrContent); - } - - let requestTestCases = 0; - let erroredRequestTestCases = 0; - let failedRequestTestCases = 0; - - // Test suites correspond to `pw.test()` invocations - testSuites.forEach(({ descriptor, expectResults }) => { - requestTestCases += expectResults.length; - - expectResults.forEach(({ status, message }) => { - const testCase = requestTestSuite - .ele("testcase", { - name: `${descriptor} - ${message}`, - }) - .att("classname", path); - - if (status === "fail") { - failedRequestTestCases += 1; - - testCase - .ele("failure") - .att("type", "AssertionFailure") - .att("message", message); - } else if (status === "error") { - erroredRequestTestCases += 1; - - testCase.ele("error").att("message", message); - } - }); - }); - - requestTestSuite.att("tests", requestTestCases.toString()); - requestTestSuite.att("failures", failedRequestTestCases.toString()); - requestTestSuite.att("errors", erroredRequestTestCases.toString()); - - return { - failedRequestTestCases, - erroredRequestTestCases, - }; -}; - -/** - * Generates the built JUnit report export at the specified path. - * - * @param {GenerateJUnitReportExportArgs} options - The options to generate the JUnit report export. - * @param {number} options.totalTestCases - The total number of test cases. - * @param {number} options.totalFailedTestCases - The total number of failed test cases. - * @param {number} options.totalErroredTestCases - The total number of errored test cases. - * @param {number} options.testDuration - The total duration of test cases. - * @param {string} options.reporterJUnitExportPath - The path to export the JUnit report. - * @returns {void} - */ -export const generateJUnitReportExport = ({ - totalTestCases, - totalFailedTestCases, - totalErroredTestCases, - testDuration, - reporterJUnitExportPath, -}: GenerateJUnitReportExportArgs) => { - rootEl - .att("tests", totalTestCases.toString()) - .att("failures", totalFailedTestCases.toString()) - .att("errors", totalErroredTestCases.toString()) - .att("time", testDuration.toString()); - - // Convert the XML structure to a string - const xmlDocString = rootEl.end({ prettyPrint: true }); - - // Write the XML string to the specified path - try { - const resolvedExportPath = path.resolve(reporterJUnitExportPath); - - if (fs.existsSync(resolvedExportPath)) { - info( - INFO(`\nOverwriting the pre-existing path: ${reporterJUnitExportPath}.`) - ); - } - - fs.mkdirSync(path.dirname(resolvedExportPath), { - recursive: true, - }); - - fs.writeFileSync(resolvedExportPath, xmlDocString); - - log( - SUCCESS( - `\nSuccessfully exported the JUnit report to: ${reporterJUnitExportPath}.` - ) - ); - } catch (err) { - const data = err instanceof Error ? err.message : null; - throw error({ - code: "REPORT_EXPORT_FAILED", - data, - path: reporterJUnitExportPath, - }); - } -}; diff --git a/packages/hoppscotch-cli/src/utils/request.ts b/packages/hoppscotch-cli/src/utils/request.ts deleted file mode 100644 index 3c42dd38..00000000 --- a/packages/hoppscotch-cli/src/utils/request.ts +++ /dev/null @@ -1,490 +0,0 @@ -import { - Environment, - HoppCollection, - HoppRESTRequest, - RESTReqSchemaVersion, -} from "@hoppscotch/data"; -import axios, { Method } from "axios"; -import * as A from "fp-ts/Array"; -import * as E from "fp-ts/Either"; -import * as T from "fp-ts/Task"; -import * as TE from "fp-ts/TaskEither"; -import { pipe } from "fp-ts/function"; -import * as S from "fp-ts/string"; -import { hrtime } from "process"; -import { URL } from "url"; -import { EffectiveHoppRESTRequest, RequestConfig } from "../interfaces/request"; -import { RequestRunnerResponse } from "../interfaces/response"; -import { HoppCLIError, error } from "../types/errors"; -import { - HoppEnvs, - ProcessRequestParams, - RequestReport, -} from "../types/request"; -import { RequestMetrics } from "../types/response"; -import { responseErrors } from "./constants"; -import { - printPreRequestRunner, - printRequestRunner, - printTestRunner, -} from "./display"; -import { getDurationInSeconds, getMetaDataPairs } from "./getters"; -import { preRequestScriptRunner } from "./pre-request"; -import { getTestScriptParams, hasAllTestsPassed, testRunner } from "./test"; - -/** - * Processes given variable, which includes checking for secret variables - * and getting value from system environment - * @param variable Variable to be processed - * @returns Updated variable with value from system environment - */ -const processVariables = (variable: Environment["variables"][number]) => { - if (variable.secret) { - return { - ...variable, - currentValue: - "currentValue" in variable && variable.currentValue !== "" - ? variable.currentValue - : process.env[variable.key] || variable.initialValue, - }; - } - return variable; -}; - -/** - * Processes given envs, which includes processing each variable in global - * and selected envs - * @param envs Global + selected envs used by requests with in collection - * @returns Processed envs with each variable processed - */ -const processEnvs = (envs: Partial) => { - // This can take the shape `{ global: undefined, selected: undefined }` when no environment is supplied - const processedEnvs = { - global: envs.global?.map(processVariables) ?? [], - selected: envs.selected?.map(processVariables) ?? [], - }; - - return processedEnvs; -}; - -/** - * Transforms given request data to request-config used by request-runner to - * perform HTTP request. - * @param req Effective request data with parsed ENVs. - * @returns Request config with data related to HTTP request. - */ -export const createRequest = (req: EffectiveHoppRESTRequest): RequestConfig => { - const config: RequestConfig = { - displayUrl: req.effectiveFinalDisplayURL, - }; - - const { finalBody, finalEndpoint, finalHeaders, finalParams } = getRequest; - - const reqParams = finalParams(req); - const reqHeaders = finalHeaders(req); - - config.url = finalEndpoint(req); - config.method = req.method as Method; - config.params = getMetaDataPairs(reqParams); - config.headers = getMetaDataPairs(reqHeaders); - - config.data = finalBody(req); - - return config; -}; - -/** - * Performs http request using axios with given requestConfig axios - * parameters. - * @param requestConfig The axios request config. - * @returns If successfully ran, we get runner-response including HTTP response data. - * Else, HoppCLIError with appropriate error code & data. - */ -export const requestRunner = - ( - requestConfig: RequestConfig - ): TE.TaskEither => - async () => { - const start = hrtime(); - - try { - // NOTE: Temporary parsing check for request endpoint. - requestConfig.url = new URL(requestConfig.url ?? "").toString(); - - const baseResponse = await axios(requestConfig); - const { config } = baseResponse; - - const end = hrtime(start); - const duration = getDurationInSeconds(end); - const responseTime = duration * 1000; // Convert seconds to milliseconds - - // Transform axios headers to required format - const transformedHeaders: { key: string; value: string }[] = []; - if (baseResponse.headers) { - for (const [key, value] of Object.entries(baseResponse.headers)) { - if (value !== undefined) { - transformedHeaders.push({ - key, - value: Array.isArray(value) ? value.join(", ") : String(value), - }); - } - } - } - - const runnerResponse: RequestRunnerResponse = { - endpoint: getRequest.endpoint(config.url), - method: getRequest.method(config.method), - body: baseResponse.data, - responseTime, - duration: duration, - status: baseResponse.status, - statusText: baseResponse.statusText, - headers: transformedHeaders, - }; - - return E.right(runnerResponse); - } catch (e) { - const runnerResponse: RequestRunnerResponse = { - endpoint: "", - method: "GET", - body: {}, - statusText: responseErrors[400], - status: 400, - headers: [], - duration: 0, - responseTime: 0, - }; - - if (axios.isAxiosError(e)) { - runnerResponse.endpoint = e.config?.url ?? ""; - - if (e.response) { - const { data, status, statusText, headers } = e.response; - runnerResponse.body = data; - runnerResponse.statusText = statusText; - runnerResponse.status = status; - - // Transform axios headers to required format - const transformedHeaders: { key: string; value: string }[] = []; - if (headers) { - for (const [key, value] of Object.entries(headers)) { - if (value !== undefined) { - transformedHeaders.push({ - key, - value: Array.isArray(value) - ? value.join(", ") - : String(value), - }); - } - } - } - runnerResponse.headers = transformedHeaders; - } else if (e.request) { - return E.left(error({ code: "REQUEST_ERROR", data: E.toError(e) })); - } - - const end = hrtime(start); - const duration = getDurationInSeconds(end); - runnerResponse.duration = duration; - - return E.right(runnerResponse); - } - - return E.left(error({ code: "REQUEST_ERROR", data: E.toError(e) })); - } - }; - -/** - * Getter object methods for request-runner. - */ -const getRequest = { - method: (value: string | undefined) => - value ? (value.toUpperCase() as Method) : "GET", - - endpoint: (value: string | undefined): string => (value ? value : ""), - - finalEndpoint: (req: EffectiveHoppRESTRequest): string => - S.isEmpty(req.effectiveFinalURL) ? req.endpoint : req.effectiveFinalURL, - - finalHeaders: (req: EffectiveHoppRESTRequest) => - A.isNonEmpty(req.effectiveFinalHeaders) - ? req.effectiveFinalHeaders - : req.headers, - - finalParams: (req: EffectiveHoppRESTRequest) => - A.isNonEmpty(req.effectiveFinalParams) - ? req.effectiveFinalParams - : req.params, - - finalBody: (req: EffectiveHoppRESTRequest) => - req.effectiveFinalBody ? req.effectiveFinalBody : req.body.body, -}; - -/** - * Processes given request, which includes executing pre-request-script, - * running request & executing test-script. - * @param request Request to be processed. - * @param envs Global + selected envs used by requests with in collection. - * @returns Updated envs and current request's report. - */ -export const processRequest = - ( - params: ProcessRequestParams - ): T.Task<{ envs: HoppEnvs; report: RequestReport }> => - async () => { - const { - envs, - path, - request, - delay, - legacySandbox, - collectionVariables, - inheritedPreRequestScripts = [], - inheritedTestScripts = [], - } = params; - - // Initialising updatedEnvs with given parameter envs, will eventually get updated. - const result = { - envs: envs, - report: {}, - }; - - // Initial value for current request's report with default values for properties. - const report: RequestReport = { - path: path, - tests: [], - errors: [], - result: true, - duration: { test: 0, request: 0, preRequest: 0 }, - }; - - // Initial value for effective-request with default values for properties. - let effectiveRequest = { - ...request, - effectiveFinalBody: null, - effectiveFinalHeaders: [], - effectiveFinalParams: [], - effectiveFinalURL: "", - }; - - // Fetch values for secret environment variables from system environment - const processedEnvs = processEnvs(envs); - - // Default envs to the pre-script state so downstream consumers - // (test-runner, effectiveRequest builder) receive a well-shaped - // HoppEnvs even if the pre-request script fails. - let updatedEnvs: HoppEnvs = processedEnvs; - - const preRequestRes = await preRequestScriptRunner( - request, - processedEnvs, - legacySandbox ?? false, - collectionVariables, - inheritedPreRequestScripts - )(); - if (E.isLeft(preRequestRes)) { - printPreRequestRunner.fail(); - - // Updating report for errors & current result - report.errors.push(preRequestRes.left); - - // Ensure, the CLI fails with a non-zero exit code if there are any errors - report.result = false; - } else { - // Updating effective-request and consuming updated envs after pre-request script execution - ({ effectiveRequest, updatedEnvs } = preRequestRes.right); - } - - // Creating request-config for request-runner. - const requestConfig = createRequest(effectiveRequest); - - printRequestRunner.start(requestConfig); - - // Default value for request-runner's response. - let _requestRunnerRes: RequestRunnerResponse = { - endpoint: "", - method: "GET", - headers: [], - status: 400, - statusText: "", - responseTime: 0, - body: Object(null), - duration: 0, - }; - // Executing request-runner. - const requestRunnerRes = await delayPromiseFunction< - E.Either - >(requestRunner(requestConfig), delay); - if (E.isLeft(requestRunnerRes)) { - // Updating report for errors & current result - report.errors.push(requestRunnerRes.left); - - // Ensure, the CLI fails with a non-zero exit code if there are any errors - report.result = false; - - printRequestRunner.fail(); - } else { - _requestRunnerRes = requestRunnerRes.right; - report.duration.request = _requestRunnerRes.duration; - printRequestRunner.success(_requestRunnerRes); - } - - const testScriptParams = getTestScriptParams( - _requestRunnerRes, - effectiveRequest, - updatedEnvs, - legacySandbox ?? false, - inheritedTestScripts - ); - - // Executing test-runner. - const testRunnerRes = await testRunner(testScriptParams)(); - if (E.isLeft(testRunnerRes)) { - printTestRunner.fail(); - - // Updating report with current errors & result. - report.errors.push(testRunnerRes.left); - - // Ensure, the CLI fails with a non-zero exit code if there are any errors - report.result = false; - } else { - const { envs, testsReport, duration } = testRunnerRes.right; - const _allTestsPassed = hasAllTestsPassed(testsReport); - - // Check if any tests have uncaught runtime errors (e.g., ReferenceError, TypeError) - // Don't include validation errors (they're reported as individual testcases) - const testScriptErrors = testsReport.flatMap((testReport) => - testReport.expectResults - .filter( - (result) => - result.status === "error" && - /^(ReferenceError|TypeError|SyntaxError|RangeError|URIError|EvalError|AggregateError|InternalError|Error):/.test( - result.message - ) - ) - .map((result) => result.message) - ); - - // If there are runtime errors, add them to report.errors - if (testScriptErrors.length > 0) { - const errorMessages = testScriptErrors.join("; "); - - report.errors.push( - error({ - code: "TEST_SCRIPT_ERROR", - data: errorMessages, - }) - ); - - report.result = false; - } - - // Updating report with current tests, result and duration. - report.tests = testsReport; - report.result = report.result && _allTestsPassed; - report.duration.test = duration; - - // Updating resulting envs from test-runner. - result.envs = envs; - - // Printing tests-report, when test-runner executes successfully. - printTestRunner.success(testsReport, duration); - } - - result.report = report; - - return result; - }; - -/** - * Generates new request without any missing/invalid data using - * current request object. - * @param request Hopp rest request to be processed. - * @returns Updated request object free of invalid/missing data. - */ -export const preProcessRequest = ( - request: HoppRESTRequest, - collection: HoppCollection -): HoppRESTRequest => { - const tempRequest = Object.assign({}, request); - const { headers: parentHeaders, auth: parentAuth } = collection; - - if (!tempRequest.v) { - tempRequest.v = RESTReqSchemaVersion; - } - if (!tempRequest.name) { - tempRequest.name = "Untitled Request"; - } - if (!tempRequest.method) { - tempRequest.method = "GET"; - } - if (!tempRequest.endpoint) { - tempRequest.endpoint = ""; - } - if (!tempRequest.params) { - tempRequest.params = []; - } - - if (parentHeaders?.length) { - // Filter out header entries present in the parent (folder/collection) under the same name - // This ensures the child headers take precedence over the parent headers - const filteredEntries = parentHeaders.filter((parentHeaderEntries) => { - return !tempRequest.headers.some( - (reqHeaderEntries) => reqHeaderEntries.key === parentHeaderEntries.key - ); - }); - tempRequest.headers.push(...filteredEntries); - } else if (!tempRequest.headers) { - tempRequest.headers = []; - } - - if (!tempRequest.preRequestScript) { - tempRequest.preRequestScript = ""; - } - if (!tempRequest.testScript) { - tempRequest.testScript = ""; - } - - if (tempRequest.auth?.authType === "inherit") { - tempRequest.auth = parentAuth; - } else if (!tempRequest.auth) { - tempRequest.auth = { authActive: false, authType: "none" }; - } - - if (!tempRequest.body) { - tempRequest.body = { contentType: null, body: null }; - } - return tempRequest; -}; - -/** - * Get request-metrics object (stats+duration) based on existence of REQUEST_ERROR code - * in hopp-errors list. - * @param errors List of errors to check for REQUEST_ERROR. - * @param duration Time taken (in seconds) to execute the request. - * @returns Object containing details of request's execution stats i.e., failed/passed - * data and duration. - */ -export const getRequestMetrics = ( - errors: HoppCLIError[], - duration: number -): RequestMetrics => - pipe( - errors, - A.some(({ code }) => code === "REQUEST_ERROR"), - (hasReqErrors) => - hasReqErrors ? { failed: 1, passed: 0 } : { failed: 0, passed: 1 }, - (requests) => { requests, duration } - ); - -/** - * A function to execute promises with specific delay in milliseconds. - * @param func Function with promise with return type T. - * @param delay TIme in milliseconds to delay function. - * @returns Promise of type same as func. - */ -export const delayPromiseFunction = ( - func: () => Promise, - delay: number -): Promise => - new Promise((resolve) => setTimeout(() => resolve(func()), delay)); diff --git a/packages/hoppscotch-cli/src/utils/scripting.ts b/packages/hoppscotch-cli/src/utils/scripting.ts deleted file mode 100644 index 5b04271b..00000000 --- a/packages/hoppscotch-cli/src/utils/scripting.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Module prefix added by Monaco editor for TypeScript module mode. - * Enables IntelliSense and isolates variables across editor instances. - */ -export const MODULE_PREFIX = "export {};\n" as const; - -/** - * Strips `export {};` prefix (with or without newline) from scripts before execution - * (non-module context) or when exporting collections. - */ -export const stripModulePrefix = (script: string): string => { - if (script.startsWith(MODULE_PREFIX)) { - return script.slice(MODULE_PREFIX.length); - } - if (script.startsWith("export {};")) { - return script.slice("export {};".length); - } - return script; -}; - -export type CombineScriptsTarget = "experimental" | "legacy"; - -const wrapScript = (script: string, target: CombineScriptsTarget): string => { - const stripped = stripModulePrefix(script.trim()); - if (!stripped) return ""; - const asyncKeyword = target === "experimental" ? "async " : ""; - return `${asyncKeyword}function() {\n${stripped}\n}`; -}; - -/** - * Combines inherited scripts into a sequential chain. Each script runs in - * its own function for scope isolation. - * - * - `experimental`: `await (async function(){...})();` lines, evaluated in - * an async host context so each `await` settles before the next runs. - * - `legacy`: sync `(function(){...}).call(this);` lines. Top-level `await` - * is rejected at parse time. - */ -export const combineScriptsWithIIFE = ( - scripts: string[], - target: CombineScriptsTarget = "experimental" -): string => { - const fns = scripts.map((s) => wrapScript(s, target)).filter((s) => s); - if (fns.length === 0) return ""; - if (target === "experimental") { - // Wrap the awaited chain in try/catch so top-level throws / rejected - // awaits reach the host reporter; faraday-cage otherwise swallows - // async-boundary errors via its keepAlive loop. - const body = fns.map((fn) => `await (${fn})();`).join("\n"); - return [ - "const __hoppReporter = globalThis.__hoppReportScriptExecutionError;", - "try {", - body, - "} catch (__hoppScriptExecutionError) {", - " __hoppReporter(__hoppScriptExecutionError);", - "}", - ].join("\n"); - } - // Leading `;` guards against ASI: a prior `})` on the host line would - // otherwise be read as a call against our IIFE expression. - return fns.map((fn) => `;(${fn}).call(this);`).join("\n"); -}; - -export const filterValidScripts = ( - scripts: (string | undefined | null)[] -): string[] => - scripts.filter( - (script): script is string => - typeof script === "string" && - stripModulePrefix(script).trim().length > 0 - ); diff --git a/packages/hoppscotch-cli/src/utils/test.ts b/packages/hoppscotch-cli/src/utils/test.ts deleted file mode 100644 index d885b850..00000000 --- a/packages/hoppscotch-cli/src/utils/test.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { HoppRESTRequest } from "@hoppscotch/data"; -import { TestDescriptor } from "@hoppscotch/js-sandbox"; -import { runTestScript } from "@hoppscotch/js-sandbox/node"; -import * as A from "fp-ts/Array"; -import * as RA from "fp-ts/ReadonlyArray"; -import * as T from "fp-ts/Task"; -import * as TE from "fp-ts/TaskEither"; -import { flow, pipe } from "fp-ts/function"; -import { hrtime } from "process"; - -import { - RequestRunnerResponse, - TestReport, - TestScriptParams, -} from "../interfaces/response"; -import { HoppCLIError, error } from "../types/errors"; -import { HoppEnvs } from "../types/request"; -import { ExpectResult, TestMetrics, TestRunnerRes } from "../types/response"; -import { getDurationInSeconds } from "./getters"; -import { createHoppFetchHook } from "./hopp-fetch"; -import { combineScriptsWithIIFE, filterValidScripts } from "./scripting"; - -/** - * Executes test script and runs testDescriptorParser to generate test-report using - * expected-results, test-status & test-descriptor. - * @param testScriptData Parameters related to test-script function. - * @returns If executes successfully, we get TestRunnerRes(updated ENVs, test-reports, duration). - * Else, HoppCLIError with appropriate code & data. - */ -export const testRunner = ( - testScriptData: TestScriptParams -): TE.TaskEither => - pipe( - /** - * Executing test-script. - */ - TE.Do, - TE.bind("start", () => TE.of(hrtime())), - TE.bind("test_response", () => - pipe( - TE.of(testScriptData), - TE.chain( - ({ - request, - response, - envs, - legacySandbox, - inheritedTestScripts = [], - }) => { - const { status, statusText, headers, responseTime, body } = - response; - - const effectiveResponse = { - status, - statusText, - headers, - responseTime, - body, - }; - - const experimentalScriptingSandbox = !legacySandbox; - const hoppFetchHook = createHoppFetchHook(); - - // Test order: request → root (reverse of pre-request). - const combinedScript = combineScriptsWithIIFE( - filterValidScripts([ - request.testScript, - ...inheritedTestScripts.slice().reverse(), - ]), - experimentalScriptingSandbox ? "experimental" : "legacy" - ); - - return runTestScript(combinedScript, { - envs, - request, - response: effectiveResponse, - experimentalScriptingSandbox, - hoppFetchHook, - }); - } - ) - ) - ), - - /** - * Recursively parsing test-results using test-descriptor-parser - * to generate test-reports. - */ - TE.chainTaskK(({ test_response: { tests, envs }, start }) => - pipe( - tests, - A.map(testDescriptorParser), - T.sequenceArray, - T.map( - flow( - RA.flatten, - RA.toArray, - (testsReport) => - { - envs, - testsReport, - duration: pipe(start, hrtime, getDurationInSeconds), - } - ) - ) - ) - ), - TE.mapLeft((e) => - error({ - code: "TEST_SCRIPT_ERROR", - data: e, - }) - ) - ); -/** - * Recursive function to parse test-descriptor from nested-children and - * generate tests-report. - * @param testDescriptor Object with details of test-descriptor. - * @returns Flattened array of TestReport parsed from TestDescriptor. - */ -export const testDescriptorParser = ( - testDescriptor: TestDescriptor -): T.Task => - pipe( - /** - * Generate single TestReport from given testDescriptor. - * Skip "root" descriptor to avoid showing synthetic top-level test. - */ - testDescriptor, - ({ expectResults, descriptor }) => - A.isNonEmpty(expectResults) && descriptor !== "root" - ? pipe( - expectResults, - A.reduce({ failed: 0, passed: 0 }, (prev, { status }) => - /** - * Incrementing number of passed test-cases if status is "pass", - * else, incrementing number of failed test-cases. - */ - status === "pass" - ? { failed: prev.failed, passed: prev.passed + 1 } - : { failed: prev.failed + 1, passed: prev.passed } - ), - ({ failed, passed }) => - { - failed, - passed, - descriptor, - expectResults, - }, - Array.of - ) - : [], - T.of, - - /** - * Recursive call to testDescriptorParser on testDescriptor's children. - * The result is concated with previous testReport. - */ - T.chain((testReport) => - pipe( - testDescriptor.children, - A.map(testDescriptorParser), - T.sequenceArray, - T.map(flow(RA.flatten, RA.toArray, A.concat(testReport))) - ) - ) - ); - -/** - * Extracts parameter object from request-runner's response, request and envs - * for test-runner. - * @param reqRunnerRes Provides response data. - * @param request Provides test-script data. - * @param envs Current ENVs state with-in collections-runner. - * @returns Object to be passed as parameter for test-runner - */ -export const getTestScriptParams = ( - reqRunnerRes: RequestRunnerResponse, - request: HoppRESTRequest, - envs: HoppEnvs, - legacySandbox: boolean, - inheritedTestScripts: string[] = [] -) => { - const testScriptParams: TestScriptParams = { - request, - response: { - body: reqRunnerRes.body, - status: reqRunnerRes.status, - statusText: reqRunnerRes.statusText, - responseTime: reqRunnerRes.responseTime, - headers: reqRunnerRes.headers, - }, - envs, - legacySandbox, - inheritedTestScripts, - }; - return testScriptParams; -}; - -/** - * Combines quantitative details (test-cases passed/failed) of each test-report - * to generate TestMetrics object with total test-cases & total test-suites. - * @param testsReport Contains details of each test-report (failed/passed test-cases). - * @param testDuration Time taken (in seconds) to execute the test-script. - * @param errors List of HoppCLIErrors to check for TEST_SCRIPT_ERROR code. - * @returns Object containing details of total test-cases passed/failed and - * total test-suites passed/failed. - */ -export const getTestMetrics = ( - testsReport: TestReport[], - testDuration: number, - errors: HoppCLIError[] -): TestMetrics => - testsReport.reduce( - ({ testSuites, tests, duration, scripts }, testReport) => ({ - tests: { - failed: tests.failed + testReport.failed, - passed: tests.passed + testReport.passed, - }, - testSuites: { - failed: testSuites.failed + (testReport.failed > 0 ? 1 : 0), - passed: testSuites.passed + (testReport.failed === 0 ? 1 : 0), - }, - scripts: scripts, - duration: duration, - }), - { - tests: { failed: 0, passed: 0 }, - testSuites: { failed: 0, passed: 0 }, - duration: testDuration, - scripts: errors.some(({ code }) => code === "TEST_SCRIPT_ERROR") - ? { failed: 1, passed: 0 } - : { failed: 0, passed: 1 }, - } - ); - -/** - * Filters tests-report containing atleast one or more failed test-cases. - * @param testsReport Provides "failed" test-cases data. - * @returns Tests report with one or more test-cases failed. - */ -export const getFailedTestsReport = (testsReport: TestReport[]) => - pipe( - testsReport, - A.filter(({ failed }) => failed > 0) - ); - -/** - * Filters expected-results containing which has status as "fail" or "error". - * @param expectResults Provides "status" data for each expected result. - * @returns Expected results with "fail" or "error" status. - */ -export const getFailedExpectedResults = (expectResults: ExpectResult[]) => - pipe( - expectResults, - A.filter(({ status }) => status !== "pass") - ); - -/** - * Checks whether every test report has zero failed test cases. - * @param testsReport Provides "failed" test-cases data. - * @returns True, if all test-cases passed. False, otherwise. - */ -export const hasAllTestsPassed = (testsReport: TestReport[]) => - pipe( - testsReport, - A.every(({ failed }) => failed === 0) - ); diff --git a/packages/hoppscotch-cli/src/utils/workspace-access.ts b/packages/hoppscotch-cli/src/utils/workspace-access.ts deleted file mode 100644 index 2c9a947f..00000000 --- a/packages/hoppscotch-cli/src/utils/workspace-access.ts +++ /dev/null @@ -1,222 +0,0 @@ -import { - CollectionSchemaVersion, - Environment, - EnvironmentSchemaVersion, - HoppCollection, - HoppCollectionVariable, - HoppRESTAuth, - HoppRESTHeaders, - HoppRESTRequest, -} from "@hoppscotch/data"; - -import { HoppEnvPair } from "../types/request"; - -export interface WorkspaceEnvironment { - id: string; - teamID: string; - name: string; - variables: HoppEnvPair[]; -} - -export interface WorkspaceCollection { - id: string; - data: string | null; - title: string; - parentID: string | null; - folders: WorkspaceCollection[]; - requests: WorkspaceRequest[]; -} - -interface WorkspaceRequest { - id: string; - collectionID: string; - teamID: string; - title: string; - request: string; -} - -/** - * Transforms the incoming list of workspace requests by applying `JSON.parse` to the `request` field. - * It includes the `v` field indicating the schema version, but migration is handled already at the `parseCollectionData()` helper function. - * - * @param {WorkspaceRequest[]} requests - An array of workspace request objects to be transformed. - * @returns {HoppRESTRequest[]} The transformed array of requests conforming to the `HoppRESTRequest` type. - */ -const transformWorkspaceRequests = ( - requests: WorkspaceRequest[] -): HoppRESTRequest[] => requests.map(({ request }) => JSON.parse(request)); - -/** - * Apply relevant migrations for data conforming to older formats - * - * @param {HoppEnvPair} variable - The environment variable to normalize. - * @returns {HoppEnvPair} The normalized environment variable conforming to the `HoppEnvPair` type. - */ -const normalizeEnvironmentVariable = (variable: HoppEnvPair): HoppEnvPair => { - if ( - "secret" in variable && - "initialValue" in variable && - "currentValue" in variable - ) { - return variable; - } - - const envPair = variable as Partial & { - key: string; - value?: string; - }; - - const isSecret = !!envPair.secret; - const value = envPair.value ?? ""; - - return { - key: envPair.key, - secret: isSecret, - initialValue: isSecret ? "" : (envPair.initialValue ?? value), - currentValue: isSecret ? "" : (envPair.currentValue ?? value), - }; -}; - -/** - * Transforms the given `HoppRESTAuth` object to ensure it conforms to the latest - * OAuth 2.0 authentication structure. Depending on the `grantType` within the - * `grantTypeInfo` property, this function adds or initializes specific fields - * such as `clientAuthentication`, `authRequestParams`, `tokenRequestParams`, - * and `refreshRequestParams` to maintain compatibility with updated schema - * requirements. - * - * - For "CLIENT_CREDENTIALS" grant type, sets `clientAuthentication` to "IN_BODY" - * and initializes `tokenRequestParams` and `refreshRequestParams` as empty arrays. - * - For "AUTHORIZATION_CODE" grant type, initializes `authRequestParams`, - * `tokenRequestParams`, and `refreshRequestParams` as empty arrays. - * - For "PASSWORD" grant type, initializes `tokenRequestParams` and - * `refreshRequestParams` as empty arrays. - * - For "IMPLICIT" grant type, initializes `authRequestParams` and - * `refreshRequestParams` as empty arrays. - * - * If the `authType` is not "oauth-2", the original `auth` object is returned unchanged. - * - * @param {HoppRESTAuth} auth - The authentication object to transform. - * @returns {HoppRESTAuth} The transformed authentication object with updated grant type information. - */ -const transformAuth = (auth: HoppRESTAuth): HoppRESTAuth => { - if (auth.authType === "oauth-2") { - const oldGrantTypeInfo = auth.grantTypeInfo; - let newGrantTypeInfo = oldGrantTypeInfo; - - // Add clientAuthentication for CLIENT_CREDENTIALS - if (oldGrantTypeInfo.grantType === "CLIENT_CREDENTIALS") { - newGrantTypeInfo = { - ...oldGrantTypeInfo, - clientAuthentication: "IN_BODY", - tokenRequestParams: [], - refreshRequestParams: [], - }; - } else if (oldGrantTypeInfo.grantType === "AUTHORIZATION_CODE") { - newGrantTypeInfo = { - ...oldGrantTypeInfo, - authRequestParams: [], - tokenRequestParams: [], - refreshRequestParams: [], - }; - } else if (oldGrantTypeInfo.grantType === "PASSWORD") { - newGrantTypeInfo = { - ...oldGrantTypeInfo, - tokenRequestParams: [], - refreshRequestParams: [], - }; - } else if (oldGrantTypeInfo.grantType === "IMPLICIT") { - newGrantTypeInfo = { - ...oldGrantTypeInfo, - authRequestParams: [], - refreshRequestParams: [], - }; - } - - return { - ...auth, - grantTypeInfo: newGrantTypeInfo, - }; - } - - return auth; -}; - -/** - * Transforms workspace environment data to the `HoppEnvironment` format. - * - * @param {WorkspaceEnvironment} workspaceEnvironment - The workspace environment object to transform. - * @returns {Environment} The transformed environment object conforming to the `Environment` type. - */ -export const transformWorkspaceEnvironment = ( - workspaceEnvironment: WorkspaceEnvironment -): Environment => { - const { teamID, variables, ...rest } = workspaceEnvironment; - - // The response doesn't include a way to infer the schema version, so it's set to the latest version - // Any relevant migrations have to be accounted here - return { - v: EnvironmentSchemaVersion, - variables: variables.map(normalizeEnvironmentVariable), - ...rest, - }; -}; - -/** - * Transforms workspace collection data to the `HoppCollection` format. - * - * @param {WorkspaceCollection[]} collections - An array of workspace collection objects to be transformed. - * @returns {HoppCollection[]} The transformed array of collections conforming to the `HoppCollection` type. - */ -export const transformWorkspaceCollections = ( - collections: WorkspaceCollection[] -): HoppCollection[] => { - return collections.map((collection) => { - const { id, title, data, requests, folders } = collection; - - const parsedData: { - auth?: HoppRESTAuth; - headers?: HoppRESTHeaders; - variables: HoppCollectionVariable[]; - description: string | null; - preRequestScript?: string; - testScript?: string; - } = data ? JSON.parse(data) : {}; - - const { - auth = { authType: "inherit", authActive: true }, - headers = [], - variables = [], - description = null, - preRequestScript = "", - testScript = "", - } = parsedData; - - const transformedAuth = transformAuth(auth); - - const transformedHeaders = headers.map((header) => - header.description ? header : { ...header, description: "" } - ); - - const filteredCollectionVariables = variables.filter( - (variable) => variable.key.trim() !== "" - ); - - // The response doesn't include a way to infer the schema version, so it's set to the latest version - // Any relevant migrations have to be accounted here - // `ref_id` field isn't necessary being applicable only to personal workspace and asociates with syncing - return { - v: CollectionSchemaVersion, - id, - name: title, - folders: transformWorkspaceCollections(folders), - requests: transformWorkspaceRequests(requests), - auth: transformedAuth, - headers: transformedHeaders, - variables: filteredCollectionVariables, - description, - preRequestScript, - testScript, - }; - }); -}; diff --git a/packages/hoppscotch-cli/tsconfig.json b/packages/hoppscotch-cli/tsconfig.json deleted file mode 100644 index ce1cf678..00000000 --- a/packages/hoppscotch-cli/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "outDir": ".", - "rootDir": ".", - "strict": true, - "moduleResolution": "node", - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "composite": true, - "lib": ["ESNext", "DOM"] - }, - "files": ["package.json"] -} diff --git a/packages/hoppscotch-cli/tsup.config.ts b/packages/hoppscotch-cli/tsup.config.ts deleted file mode 100644 index d6e19c12..00000000 --- a/packages/hoppscotch-cli/tsup.config.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { defineConfig } from "tsup"; - -export default defineConfig({ - entry: ["./src/index.ts"], - outDir: "./dist/", - format: ["esm"], - platform: "node", - sourcemap: true, - bundle: true, - target: "esnext", - skipNodeModulesBundle: false, - esbuildOptions(options) { - options.bundle = true; - }, - clean: true, -}); diff --git a/packages/hoppscotch-cli/vitest.config.ts b/packages/hoppscotch-cli/vitest.config.ts deleted file mode 100644 index bac92a0e..00000000 --- a/packages/hoppscotch-cli/vitest.config.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: { - environment: "node", - setupFiles: ["./setupFiles.ts"], - include: ["**/src/__tests__/**/**/*.{test,spec}.ts"], - exclude: [ - "**/node_modules/**", - "**/dist/**", - "**/src/__tests__/functions/**/*.ts", - ], - }, -}); diff --git a/packages/hoppscotch-desktop/.gitignore b/packages/hoppscotch-desktop/.gitignore deleted file mode 100644 index f5e62d36..00000000 --- a/packages/hoppscotch-desktop/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -bundle.zip -manifest.json - -src-tauri/hopp_bundle.zip -src-tauri/hopp_manifest.json -src-tauri/hoppscotch-desktop-data -target - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? -# Devenv -.devenv* -devenv.local.nix - -# direnv -.direnv - -# pre-commit -.pre-commit-config.yaml diff --git a/packages/hoppscotch-desktop/README.md b/packages/hoppscotch-desktop/README.md deleted file mode 100644 index a6f5fcc1..00000000 --- a/packages/hoppscotch-desktop/README.md +++ /dev/null @@ -1,166 +0,0 @@ -# Hoppscotch Desktop App ALPHA - -

- -

Hoppscotch Desktop

-

- Download | - Official Docs -

-
- -
- -#### Hoppscotch Desktop App is a cross-platform [Hoppscotch](https://hoppscotch.io) app built with [Tauri V2](https://v2.tauri.app/) - -![Hoppscotch Desktop App](desktop-app.png) - -#### Now with the ability to connect to Self-Hosted instances - -![Hoppscotch Desktop App](connection-to-self-hosted-instance.png) - -## Installation - -1. [Download the latest version of Hoppscotch Desktop App](https://hoppscotch.com/download) -2. Open the downloaded file. -3. Follow the on-screen instructions to install Hoppscotch Desktop App. -4. Open Hoppscotch Desktop App. - -##### Using Homebrew - -You can use Homebrew (on macOS or Linux) to install Hoppscotch - -```bash -brew install --cask hoppscotch -``` - -## Access Options - -### Hoppscotch Cloud Edition for Individuals - -1. Open Hoppscotch Desktop App. -2. Click the Hoppscotch logo in the top-left corner. -3. Click "**HOPPSCOTCH CLOUD**". -4. Sign in with your Hoppscotch Cloud account to access your workspaces and collections. - -### Self-Hosted Edition (Community and Enterprise) - -> [!Note] -> To enable desktop app support for your self-hosted Hoppscotch instance, make sure to update the `WHITELISTED_ORIGINS` environment variable in your `.env` file with your deployment URL. -> -> e.g. to allow connection to `https://hoppscotch.mydomain.com` you need to add `app://hoppscotch_mydomain_com` (MacOS, Linux) and `http://app.hoppscotch_mydomain_com` (Windows) to the `WHITELISTED_ORIGINS` environment variable. -> ```bash -> WHITELISTED_ORIGINS=...existing_origins,app://hoppscotch_mydomain_com,http://app.hoppscotch_mydomain_com -> ``` - -To connect to your self-hosted (community or enterprise) instance: - -1. Open Hoppscotch Desktop App. -2. Click the Hoppscotch logo in the top-left corner. -3. Click "**Add an instance**". -4. Enter the URL of your self-hosted Hoppscotch instance. -5. Click "**Connect**". - -> [!Note] -> For docker setup, the desktop app uses a server at port `3200`, and it is part of the frontend container: -> -> ``` -> ❯ docker run -p 3000:3000 -p 3200:3200 hoppscotch/hoppscotch-frontend -> ``` -> -> Once the container is live, you can enter `[your-ip]:3200` or simply the base address of the instance if you are using [subpath access](https://docs.hoppscotch.io/guides/articles/self-host-hoppscotch-on-your-own-servers#4-subpath-access). - -## Building and Self-Hosting Hoppscotch Desktop - -You can also build Hoppscotch Desktop locally to self-host with on-prem infra: - -1. Install and generate the selfhost web app: - ```bash - cd ../hoppscotch-selfhost-web - pnpm install - pnpm generate - ``` -2. Build the `webapp-bundler`: - ```bash - cd crates/webapp-bundler - cargo build --release - ``` -3. Bundle the web app: - ```bash - cd target/release - ./webapp-bundler --input [path-to-dist-directory] --output [path-to-hoppscotch-desktop]/bundle.zip --manifest [path-to-hoppscotch-desktop]/manifest.json - ``` -4. Run the development server: - ```bash - cd hoppscotch-desktop - pnpm tauri dev - ``` - or the following for production build: - ```bash - cd src-tauri - pnpm tauri dev - ``` - -> [!Note] -> `[path-to-dist-directory]` should point to the `dist` directory created by the `pnpm generate` command in step 1. - -## Minimum System Requirements - -### Windows -- **OS Version**: Windows 10 1803+ or Windows 11 -- **Architecture**: x64 - -### macOS -- **OS Version**: macOS 10.15 (Catalina) or later -- **Architecture**: Intel x64 or Apple Silicon (ARM64) - -### Linux -- **Architecture**: x64 -- **Recommended OS**: Ubuntu 24.04 or newer (or similar flavor of distros) -- **Minimum**: Systems with GLIBC 2.38+ - -#### Why Ubuntu 24.04-like flavors or newer? - -Ubuntu 24.04-like flavors ships with the exact WebKit2GTK version (2.44.0-2) that is stable enough to correctly handle interaction between WebKit, UI libraries, Mesa drivers, and Wayland displays.[^1][^2][^3] - -> [!IMPORTANT] -> There may be some display oddities on Wayland systems caused by the interaction between WebKit and the underlying graphics drivers.[^4][^5][^6] -> -> **Workaround**: -> ```bash -> WEBKIT_DISABLE_COMPOSITING_MODE=1 hoppscotch -> # or -> WEBKIT_DISABLE_DMABUF_RENDERER=1 hoppscotch -> # or both together -> ``` - -### Misc. - -- **Older distributions**: The AppImage requires GLIBC 2.38+ [^1][^7] - - Users on older systems will see GLIBC version errors like "GLIBC_2.32' not found"[^8] -- **Tauri v2 dependency**: The desktop app requires libwebkit2gtk-4.1, which is only available by default in Ubuntu 22.04+ repositories[^9] -- **Build from source**: GitHub workflow for building from source[^10] - ---- - -### Sources - -[^1]: [WebKit version pinning and GLIBC explanation](https://github.com/hoppscotch/hoppscotch/issues/3543#issuecomment-2869628299) - Detailed explanation of why specific webkit2gtk 2.44.0-2 is used and GLIBC 2.38+ requirement - -[^2]: [WebKit 2.44.0-2 selection rationale](https://github.com/hoppscotch/hoppscotch/issues/4880#issuecomment-2014063000) - Why this specific version provides the best balance for Wayland support - -[^3]: [Ubuntu webkit2gtk package versions](https://packages.ubuntu.com/search?keywords=webkit2gtk&searchon=names) - Official Ubuntu package repositories showing version availability - -[^4]: [EGL/Mesa/Wayland bug report](https://bugs.launchpad.net/ubuntu/+source/webkit2gtk/+bug/1966418) - Comprehensive bug report about webkit apps showing blank screens on Wayland - -[^5]: [WebKit GTK Wayland compositing issue](https://bugs.webkit.org/show_bug.cgi?id=165246) - Upstream WebKit bug about compositing mode failures - -[^6]: [Mesa issue with webkit2gtk](https://gitlab.freedesktop.org/mesa/mesa/-/issues/6236) - Mesa driver interaction with webkit2gtk causing EGL initialization failures - -[^7]: [GLIBC compatibility matrix](https://github.com/hoppscotch/hoppscotch/issues/3543#issuecomment-1077225935) - User reports of specific GLIBC version errors - -[^8]: [Specific GLIBC error examples](https://github.com/hoppscotch/hoppscotch/issues/3543#issuecomment-1329816314) - User reports showing exact GLIBC version error messages - -[^9]: [Tauri v2 webkit requirements](https://github.com/tauri-apps/tauri/issues/8535#issuecomment-2162723242) - Tauri v2's dependency on libwebkit2gtk-4.1 - -[^10]: [Hoppscotch Desktop build workflow](https://github.com/hoppscotch/hoppscotch/blob/main/.github/workflows/build-hoppscotch-desktop.yml) - Official build workflow and instructions diff --git a/packages/hoppscotch-desktop/connection-to-self-hosted-instance.png b/packages/hoppscotch-desktop/connection-to-self-hosted-instance.png deleted file mode 100644 index 508610c9..00000000 Binary files a/packages/hoppscotch-desktop/connection-to-self-hosted-instance.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/crates/webapp-bundler/.gitignore b/packages/hoppscotch-desktop/crates/webapp-bundler/.gitignore deleted file mode 100644 index 6cf4d681..00000000 --- a/packages/hoppscotch-desktop/crates/webapp-bundler/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# Devenv -.devenv* -devenv.local.nix - -# direnv -.direnv - -# pre-commit -.pre-commit-config.yaml - -/target/ - -/gen/schemas - -.env - -bundles - -trust/ - -site/ diff --git a/packages/hoppscotch-desktop/crates/webapp-bundler/Cargo.lock b/packages/hoppscotch-desktop/crates/webapp-bundler/Cargo.lock deleted file mode 100644 index ccfe9de6..00000000 --- a/packages/hoppscotch-desktop/crates/webapp-bundler/Cargo.lock +++ /dev/null @@ -1,1169 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" -dependencies = [ - "anstyle", - "once_cell", - "windows-sys", -] - -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "blake3" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "serde", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cc" -version = "1.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "clap" -version = "4.5.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e77c3243bd94243c03672cb5154667347c457ca271254724f9f393aee1c05ff" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.5.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.5.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "clap_lex" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "deflate64" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "flate2" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "indexmap" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" -dependencies = [ - "equivalent", - "hashbrown", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.169" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" - -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - -[[package]] -name = "log" -version = "0.4.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" - -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder", - "crc", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" -dependencies = [ - "adler2", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.20.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro2" -version = "1.0.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "rustversion" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" - -[[package]] -name = "ryu" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "serde" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.217" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.138" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "syn" -version = "2.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "time" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-ident" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "webapp-bundler" -version = "0.1.0" -dependencies = [ - "base64", - "blake3", - "chrono", - "clap", - "mime_guess", - "rayon", - "serde", - "serde_json", - "thiserror", - "walkdir", - "zip", - "zstd", -] - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "zip" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45" -dependencies = [ - "aes", - "arbitrary", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "deflate64", - "displaydoc", - "flate2", - "hmac", - "indexmap", - "lzma-rs", - "memchr", - "pbkdf2", - "rand", - "sha1", - "thiserror", - "time", - "zeroize", - "zopfli", - "zstd", -] - -[[package]] -name = "zopfli" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" -dependencies = [ - "bumpalo", - "crc32fast", - "lockfree-object-pool", - "log", - "once_cell", - "simd-adler32", -] - -[[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/packages/hoppscotch-desktop/crates/webapp-bundler/Cargo.toml b/packages/hoppscotch-desktop/crates/webapp-bundler/Cargo.toml deleted file mode 100644 index 5bd7685c..00000000 --- a/packages/hoppscotch-desktop/crates/webapp-bundler/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "webapp-bundler" -version = "0.1.0" -authors = ["CuriousCorrelation"] -edition = "2024" -publish = false - -[dependencies] -base64 = "0.22.1" -blake3 = { version = "1.5.4", features = ["serde"] } -chrono = { version = "0.4.39", features = ["serde"] } -clap = { version = "4.5.28", features = ["derive"] } -mime_guess = "2.0.5" -rayon = "1.10.0" -serde = { version = "1.0.215", features = ["derive"] } -serde_json = "1.0.133" -thiserror = "2.0.3" -walkdir = "2.5.0" -zip = "2.2.0" -zstd = "0.13.2" diff --git a/packages/hoppscotch-desktop/crates/webapp-bundler/src/main.rs b/packages/hoppscotch-desktop/crates/webapp-bundler/src/main.rs deleted file mode 100644 index 05204fdb..00000000 --- a/packages/hoppscotch-desktop/crates/webapp-bundler/src/main.rs +++ /dev/null @@ -1,221 +0,0 @@ -/// This is just `webapp-server`'s bundler part as a CLI -use std::fs::File; -use std::io::{Cursor, Write}; -use std::path::PathBuf; - -use clap::Parser; -use rayon::prelude::*; -use thiserror::Error; -use walkdir::WalkDir; -use zip::{ZipWriter, write::SimpleFileOptions}; - -#[derive(Error, Debug)] -pub enum BundlerError { - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - - #[error("ZIP error: {0}")] - Zip(#[from] zip::result::ZipError), - - #[error("JSON error: {0}")] - Json(#[from] serde_json::Error), - - #[error("Invalid path: {0}")] - InvalidPath(String), - - #[error("Configuration error: {0}")] - Config(String), -} - -type Result = std::result::Result; - -#[derive(Parser, Debug)] -#[command(author, version, about = "Creates a bundle from a directory")] -struct Args { - /// Path to the directory to bundle - #[arg(short, long)] - input: PathBuf, - - /// Output path for the bundle - #[arg(short, long)] - output: PathBuf, - - /// Path to save the manifest file (optional) - #[arg(short, long)] - manifest: Option, - - /// Custom version for the bundle (defaults to CLI tool version) - #[arg(short, long)] - version: Option, -} - -#[derive(serde::Serialize)] -struct FileEntry { - path: String, - size: u64, - #[serde(with = "hash_serde")] - hash: blake3::Hash, - mime_type: Option, -} - -#[derive(serde::Serialize)] -struct Manifest { - files: Vec, - version: String, - created_at: chrono::DateTime, -} - -mod hash_serde { - use base64::{Engine, engine::general_purpose::STANDARD}; - use serde::Serializer; - - pub fn serialize(hash: &blake3::Hash, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&STANDARD.encode(hash.as_bytes())) - } -} - -struct BundleBuilder { - writer: ZipWriter>>, - files: Vec, -} - -impl BundleBuilder { - fn new>(input_path: P) -> Result { - let input_path = input_path.as_ref(); - - if !input_path.exists() { - return Err(BundlerError::Config(format!( - "Input path {} does not exist", - input_path.display() - ))); - } - - struct FileInfo { - relative_path: String, - content: Vec, - hash: blake3::Hash, - size: u64, - mime_type: Option, - } - - let file_infos: Vec = WalkDir::new(input_path) - .into_iter() - .filter_map(|entry| entry.ok()) - .filter(|entry| entry.file_type().is_file()) - .par_bridge() - .map(|entry| { - let path = entry.path(); - let relative_path = path - .strip_prefix(input_path) - .unwrap() - .components() - .map(|comp| comp.as_os_str().to_string_lossy()) - .collect::>() - .join("/"); - - let content = std::fs::read(path).map_err(|e| { - BundlerError::Config(format!("Failed to read file {}: {}", path.display(), e)) - })?; - - let hash = blake3::hash(&content); - let size = content.len() as u64; - - let mime_type = mime_guess::from_path(path) - .first() - .map(|mime| mime.to_string()); - - Ok(FileInfo { - relative_path, - content, - hash, - size, - mime_type, - }) - }) - .collect::>>()?; - - let mut builder = Self { - writer: ZipWriter::new(Cursor::new(Vec::new())), - files: Vec::with_capacity(file_infos.len()), - }; - - for file_info in file_infos { - let options = SimpleFileOptions::default().unix_permissions(0o644); - - builder - .writer - .start_file(&file_info.relative_path, options) - .map_err(|e| BundlerError::Config(format!("Failed to start file in zip: {}", e)))?; - - builder - .writer - .write_all(&file_info.content) - .map_err(|e| BundlerError::Config(format!("Failed to write file to zip: {}", e)))?; - - builder.files.push(FileEntry { - path: file_info.relative_path, - size: file_info.size, - hash: file_info.hash, - mime_type: file_info.mime_type, - }); - } - - Ok(builder) - } - - fn finish(self) -> Result<(Vec, Vec)> { - let writer = self - .writer - .finish() - .map_err(|e| BundlerError::Config(format!("Failed to finish zip archive: {}", e)))?; - - Ok((writer.into_inner(), self.files)) - } -} - -fn main() -> Result<()> { - let args = Args::parse(); - - if !args.input.exists() { - return Err(BundlerError::InvalidPath(format!( - "Input path does not exist: {}", - args.input.display() - ))); - } - - println!("Creating bundle from directory: {}", args.input.display()); - - let builder = BundleBuilder::new(&args.input)?; - let (content, files) = builder.finish()?; - - let version = args.version - .or_else(|| std::env::var("WEBAPP_BUNDLE_VERSION").ok()) - .unwrap_or_else(|| env!("CARGO_PKG_VERSION").to_string()); - println!("Using bundle version: {}", version); - - let mut output_file = File::create(&args.output)?; - output_file.write_all(&content)?; - println!("Bundle written to: {}", args.output.display()); - - let manifest = Manifest { - files, - version, - created_at: chrono::Utc::now(), - }; - - if let Some(manifest_path) = args.manifest { - let manifest_json = serde_json::to_string_pretty(&manifest)?; - std::fs::write(manifest_path.clone(), manifest_json)?; - println!("Manifest written to: {}", manifest_path.display()); - } - - println!( - "Bundle created successfully with {} files", - manifest.files.len() - ); - - Ok(()) -} diff --git a/packages/hoppscotch-desktop/desktop-app.png b/packages/hoppscotch-desktop/desktop-app.png deleted file mode 100644 index 38ab8e4d..00000000 Binary files a/packages/hoppscotch-desktop/desktop-app.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/eslint.config.mjs b/packages/hoppscotch-desktop/eslint.config.mjs deleted file mode 100644 index 8cd9a496..00000000 --- a/packages/hoppscotch-desktop/eslint.config.mjs +++ /dev/null @@ -1,79 +0,0 @@ -import pluginVue from "eslint-plugin-vue" -import { - defineConfigWithVueTs, - vueTsConfigs, -} from "@vue/eslint-config-typescript" -import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended" -import globals from "globals" - -export default defineConfigWithVueTs( - { - ignores: [ - "static/**", - "src/helpers/backend/graphql.ts", - "**/*.d.ts", - "types/**", - "dist/**", - "node_modules/**", - ], - }, - pluginVue.configs["flat/recommended"], - vueTsConfigs.recommended, - eslintPluginPrettierRecommended, - { - files: ["**/*.ts", "**/*.js", "**/*.vue"], - linterOptions: { - reportUnusedDisableDirectives: false, - }, - languageOptions: { - sourceType: "module", - ecmaVersion: "latest", - globals: { - ...globals.browser, - ...globals.node, - }, - parserOptions: { - requireConfigFile: false, - ecmaFeatures: { - jsx: false, - }, - }, - }, - rules: { - semi: [2, "never"], - "import/named": "off", - "no-console": "off", - "no-debugger": process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn", - "prettier/prettier": - process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn", - "vue/multi-word-component-names": "off", - "vue/no-side-effects-in-computed-properties": "off", - "import/no-named-as-default": "off", - "import/no-named-as-default-member": "off", - "@typescript-eslint/no-unused-vars": - process.env.HOPP_LINT_FOR_PROD === "true" ? "error" : "warn", - "@typescript-eslint/no-unused-expressions": "off", - "@typescript-eslint/no-non-null-assertion": "off", - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unsafe-function-type": "off", - "import/default": "off", - "no-undef": "off", - "no-restricted-globals": [ - "error", - { - name: "localStorage", - message: - "Do not use 'localStorage' directly. Please use the PersistenceService", - }, - ], - "no-restricted-syntax": [ - "error", - { - selector: "CallExpression[callee.object.property.name='localStorage']", - message: - "Do not use 'localStorage' directly. Please use the PersistenceService", - }, - ], - }, - } -) diff --git a/packages/hoppscotch-desktop/index.html b/packages/hoppscotch-desktop/index.html deleted file mode 100644 index 6baef121..00000000 --- a/packages/hoppscotch-desktop/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - Hoppscotch Desktop App - - - -
- - - diff --git a/packages/hoppscotch-desktop/package.json b/packages/hoppscotch-desktop/package.json deleted file mode 100644 index 18a2129b..00000000 --- a/packages/hoppscotch-desktop/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "hoppscotch-desktop", - "private": true, - "version": "26.4.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vue-tsc --noEmit && vite build", - "preview": "vite preview", - "tauri": "tauri", - "lint": "eslint src", - "lint:ts": "vue-tsc --noEmit", - "lintfix": "eslint --fix src", - "prod-lint": "cross-env HOPP_LINT_FOR_PROD=true pnpm run lint", - "do-lint": "pnpm run prod-lint", - "do-typecheck": "pnpm run lint:ts", - "do-lintfix": "pnpm run lintfix", - "prepare-web": "(cd ../hoppscotch-selfhost-web && pnpm install && pnpm generate) && (cd crates/webapp-bundler && cargo build --release && cd target/release && ./webapp-bundler --input ../../../../../hoppscotch-selfhost-web/dist --output ../../../../bundle.zip --manifest ../../../../manifest.json)", - "dev:full": "pnpm tauri dev", - "build:full": "pnpm tauri build", - "dev:portable": "pnpm tauri dev -- --no-default-features --features portable", - "build:portable": "pnpm tauri build -- --no-default-features --features portable" - }, - "dependencies": { - "@fontsource-variable/inter": "5.2.8", - "@fontsource-variable/material-symbols-rounded": "5.2.43", - "@fontsource-variable/roboto-mono": "5.2.8", - "@hoppscotch/common": "workspace:^", - "@hoppscotch/kernel": "workspace:^", - "@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload#0d58d53be2bc75aeb5916bd0d77794fd209426af", - "@hoppscotch/ui": "0.2.5", - "@tauri-apps/api": "2.1.1", - "@tauri-apps/plugin-fs": "2.0.2", - "@tauri-apps/plugin-process": "2.2.0", - "@tauri-apps/plugin-shell": "2.3.3", - "@tauri-apps/plugin-store": "2.4.1", - "@tauri-apps/plugin-updater": "2.9.0", - "fp-ts": "2.16.11", - "rxjs": "7.8.2", - "vue": "3.5.33", - "vue-router": "4.6.4", - "vue-tippy": "6.7.1", - "zod": "3.25.32" - }, - "devDependencies": { - "@eslint/eslintrc": "3.3.5", - "@eslint/js": "9.39.2", - "@iconify-json/lucide": "1.2.104", - "@rushstack/eslint-patch": "1.16.1", - "@tauri-apps/cli": "2.9.3", - "@typescript-eslint/eslint-plugin": "8.59.0", - "@typescript-eslint/parser": "8.59.0", - "@vitejs/plugin-vue": "6.0.6", - "@vue/eslint-config-typescript": "14.7.0", - "autoprefixer": "10.5.0", - "eslint": "9.39.2", - "eslint-plugin-prettier": "5.5.5", - "eslint-plugin-vue": "10.9.0", - "globals": "16.5.0", - "postcss": "8.5.10", - "sass": "1.99.0", - "tailwindcss": "3.4.16", - "typescript": "5.9.3", - "unplugin-icons": "22.5.0", - "unplugin-vue-components": "30.0.0", - "vite": "7.3.2", - "vue-tsc": "2.2.0" - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/.envrc b/packages/hoppscotch-desktop/plugin-workspace/relay/.envrc deleted file mode 100644 index 894571bf..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -source_url "https://raw.githubusercontent.com/cachix/devenv/82c0147677e510b247d8b9165c54f73d32dfd899/direnvrc" "sha256-7u4iDd1nZpxL4tCzmPG0dQgC5V+/44Ba+tHkPob1v2k=" - -use devenv diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/.gitignore b/packages/hoppscotch-desktop/plugin-workspace/relay/.gitignore deleted file mode 100644 index e6f42efb..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -/target -# Devenv -.devenv* -devenv.local.nix - -# direnv -.direnv - -# pre-commit -.pre-commit-config.yaml -# Devenv -.devenv* -devenv.local.nix - -# direnv -.direnv - -# pre-commit -.pre-commit-config.yaml diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/Cargo.lock b/packages/hoppscotch-desktop/plugin-workspace/relay/Cargo.lock deleted file mode 100644 index 097c7344..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/Cargo.lock +++ /dev/null @@ -1,1214 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys 0.59.0", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" -dependencies = [ - "serde", -] - -[[package]] -name = "cc" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "curl" -version = "0.4.47" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "socket2", -] - -[[package]] -name = "curl-sys" -version = "0.4.77+curl-8.10.1" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "windows-sys 0.52.0", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "env_filter" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "http" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-serde" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" -dependencies = [ - "http", - "serde", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "infer" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" -dependencies = [ - "cfb", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.167" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" - -[[package]] -name = "libz-sys" -version = "1.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "openssl" -version = "0.10.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.4.1+3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "relay" -version = "0.1.1" -dependencies = [ - "bytes", - "curl", - "dashmap", - "env_logger", - "http", - "http-serde", - "infer", - "lazy_static", - "log", - "mime", - "openssl", - "openssl-sys", - "serde", - "serde_json", - "strum", - "thiserror", - "time", - "tokio-util", - "tracing", - "url", - "url-escape", - "urlencoding", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustversion" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "serde" -version = "1.0.215" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.215" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.133" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - -[[package]] -name = "syn" -version = "2.0.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "time" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" -dependencies = [ - "backtrace", - "pin-project-lite", -] - -[[package]] -name = "tokio-util" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "url-escape" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e0ce4d1246d075ca5abec4b41d33e87a6054d08e2366b63205665e950db218" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/Cargo.toml b/packages/hoppscotch-desktop/plugin-workspace/relay/Cargo.toml deleted file mode 100644 index 95139862..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "relay" -version = "0.1.1" -description = "A HTTP request-response relay used by Hoppscotch Desktop and Hoppscotch Agent for more advanced request handling including custom headers, certificates, proxies, and local system integration." -authors = ["CuriousCorrelation"] -edition = "2021" - -[dependencies] -curl = { git = "https://github.com/CuriousCorrelation/curl-rust.git", features = ["ntlm"] } -tokio-util = "0.7.12" -lazy_static = "1.5.0" -time = { version = "0.3.37", features = ["serde"] } -openssl = { version = "0.10.66", features = ["vendored"] } -# NOTE: This crate follows `openssl-sys` from https://github.com/CuriousCorrelation/curl-rust.git -# to avoid issues from version mismatch when compiling from source. -openssl-sys = { version = "0.9.64", features = ["vendored"] } -log = "0.4.22" -env_logger = "0.11.5" -thiserror = "1.0.64" -http = "1.1.0" -http-serde = "2.1.1" -url-escape = "0.1.1" -serde = { version = "1", features = ["derive"] } -serde_json = "1" -urlencoding = "2.1.3" -dashmap = "6.1.0" -tracing = "0.1.41" -infer = "0.16.0" -strum = { version = "0.26.3", features = ["derive"] } -bytes = { version = "1.9.0", features = ["serde"] } -mime = "0.3.17" -url = "2.5.4" diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/LICENSE.md b/packages/hoppscotch-desktop/plugin-workspace/relay/LICENSE.md deleted file mode 100644 index 24bfc7fe..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 - CuriousCorrelation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/README.md b/packages/hoppscotch-desktop/plugin-workspace/relay/README.md deleted file mode 100644 index 5035fae2..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/README.md +++ /dev/null @@ -1,101 +0,0 @@ -# Relay - -A HTTP request-response relay used by Hoppscotch Desktop and Hoppscotch Agent for more advanced request handling including custom headers, certificates, proxies, and local system integration. - -> [!IMPORTANT] -> This crate is only available via GitHub and not published on crates.io right now. - -
- -![GitHub License MIT](https://img.shields.io/github/license/CuriousCorrelation/relay) -[![Rust](https://img.shields.io/badge/Rust-1.77.2+-orange)](https://www.rust-lang.org) - -
- -## Installation - -Add to your `Cargo.toml`: - -```toml -[dependencies] -relay = { git = "https://github.com/CuriousCorrelation/relay.git" } -``` - -## Features - -- 🦀 Blazingly fast! -- HTTP client built on libcurl -- HTTP/1.1, HTTP/2.0, HTTP/3.0 support -- Security with SSL/TLS certificate management -- Proxy support with authentication -- Multiple authentication methods (Basic, Bearer, Digest) -- Content handling (JSON, Form Data, Binary) -- Custom security configurations -- Async request execution with cancellation support - -## Usage - -```rust -use relay::{Request, Response, execute}; - -let request = Request { - id: 1, - url: "https://api.example.com".to_string(), - method: Method::Get, - version: Version::Http2, - // ... configure other options -}; - -let response = execute(request).await?; -``` - -> [!NOTE] -> All requests are executed asynchronously and can be cancelled using the `cancel(request_id)` function. - -## Security Features - -> [!TIP] -> You can configure certificate validation, host verification, and custom certificates: - -```rust -let security_config = SecurityConfig { - validate_certificates: Some(true), - verify_host: Some(true), - certificates: Some(CertificateConfig { - client: Some(CertificateType::Pem { - cert: cert_data, - key: key_data - }), - ca: Some(vec![ca_cert_data]) - }) -}; -``` - -## Error Handling - -The crate uses a custom error type `RelayError` that provides information about failures: - -```rust -#[derive(Error)] -pub enum RelayError { - Network { message: String, cause: Option }, - Certificate { message: String, cause: Option }, - Parse { message: String, cause: Option }, - // ... other variants -} -``` - -## Requirements - -- Rust 1.77.2 or later -- OpenSSL development libraries -- libcurl with SSL and HTTP/2.0 support - -> [!WARNING] -> This crate uses custom forks of some dependencies for NTLM support and consistent OpenSSL backend across platforms. - -## License - -Code: (c) 2024 - CuriousCorrelation - -MIT or MIT/Apache 2.0 where applicable. diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.lock b/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.lock deleted file mode 100644 index 74875226..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.lock +++ /dev/null @@ -1,153 +0,0 @@ -{ - "nodes": { - "devenv": { - "locked": { - "dir": "src/modules", - "lastModified": 1732585607, - "owner": "cachix", - "repo": "devenv", - "rev": "a520f05c40ebecaf5e17064b27e28ba8e70c49fb", - "type": "github" - }, - "original": { - "dir": "src/modules", - "owner": "cachix", - "repo": "devenv", - "type": "github" - } - }, - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src" - }, - "locked": { - "lastModified": 1732602776, - "owner": "nix-community", - "repo": "fenix", - "rev": "e0d44b70dcd2b98dd77857b4c5c7b1dc6b1ef56d", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1696426674, - "owner": "edolstra", - "repo": "flake-compat", - "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "pre-commit-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1709087332, - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "637db329424fd7e46cf4185293b9cc8c88c95394", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1732238832, - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "8edf06bea5bcbee082df1b7369ff973b91618b8d", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-stable": { - "locked": { - "lastModified": 1731797254, - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "e8c38b73aeb218e27163376a2d617e61a2ad9b59", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-24.05", - "repo": "nixpkgs", - "type": "github" - } - }, - "pre-commit-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ], - "nixpkgs-stable": "nixpkgs-stable" - }, - "locked": { - "lastModified": 1732021966, - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "rev": "3308484d1a443fc5bc92012435d79e80458fe43c", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "pre-commit-hooks.nix", - "type": "github" - } - }, - "root": { - "inputs": { - "devenv": "devenv", - "fenix": "fenix", - "nixpkgs": "nixpkgs", - "pre-commit-hooks": "pre-commit-hooks" - } - }, - "rust-analyzer-src": { - "flake": false, - "locked": { - "lastModified": 1732562640, - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "157c7d01149e9be7179c5724b89d8d073e923bd8", - "type": "github" - }, - "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.nix b/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.nix deleted file mode 100644 index 39176720..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.nix +++ /dev/null @@ -1,72 +0,0 @@ -{ pkgs, lib, config, inputs, ... }: - -let - rosettaPkgs = - if pkgs.stdenv.isDarwin && pkgs.stdenv.isAarch64 - then pkgs.pkgsx86_64Darwin - else pkgs; - - darwinPackages = with pkgs; [ - darwin.apple_sdk.frameworks.Security - darwin.apple_sdk.frameworks.CoreServices - darwin.apple_sdk.frameworks.CoreFoundation - darwin.apple_sdk.frameworks.Foundation - ]; - - linuxPackages = with pkgs; [ - ]; - -in { - packages = with pkgs; [ - git - cargo-edit - ] ++ lib.optionals pkgs.stdenv.isDarwin darwinPackages - ++ lib.optionals pkgs.stdenv.isLinux linuxPackages; - - env = { - APP_GREET = "Relay"; - } // lib.optionalAttrs pkgs.stdenv.isLinux { - LD_LIBRARY_PATH = lib.makeLibraryPath [ - ]; - } // lib.optionalAttrs pkgs.stdenv.isDarwin { - # Place to put macOS-specific environment variables - }; - - scripts = { - hello.exec = "echo hello from $APP_GREET"; - e.exec = "emacs"; - }; - - enterShell = '' - git --version - ${lib.optionalString pkgs.stdenv.isDarwin '' - # Place to put macOS-specific shell initialization - ''} - ${lib.optionalString pkgs.stdenv.isLinux '' - # Place to put Linux-specific shell initialization - ''} - ''; - - enterTest = '' - echo "Running tests" - ''; - - dotenv.enable = true; - - languages = { - rust = { - enable = true; - channel = "nightly"; - components = [ - "rustc" - "cargo" - "clippy" - "rustfmt" - "rust-analyzer" - "llvm-tools-preview" - "rust-src" - "rustc-codegen-cranelift-preview" - ]; - }; - }; -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.yaml b/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.yaml deleted file mode 100644 index 9ee9ba34..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/devenv.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json -inputs: - # For NodeJS-22 and above - nixpkgs: - url: github:NixOS/nixpkgs/nixpkgs-unstable - # nixpkgs: - # url: github:cachix/devenv-nixpkgs/rolling - fenix: - url: github:nix-community/fenix - inputs: - nixpkgs: - follows: nixpkgs - -# If you're using non-OSS software, you can set allowUnfree to true. -allowUnfree: true - -# If you're willing to use a package that's vulnerable -# permittedInsecurePackages: -# - "openssl-1.1.1w" - -# If you have more than one devenv you can merge them -#imports: -# - ./backend diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/auth.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/auth.rs deleted file mode 100644 index 147fb10f..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/auth.rs +++ /dev/null @@ -1,326 +0,0 @@ -use curl::easy::Easy; -use std::collections::HashMap; - -use crate::{ - error::{RelayError, Result}, - interop::{ApiKeyLocation, AuthType, GrantType, TokenResponse}, -}; - -pub(crate) struct AuthHandler<'a> { - handle: &'a mut Easy, - headers: &'a mut HashMap, -} - -impl<'a> AuthHandler<'a> { - pub(crate) fn new(handle: &'a mut Easy, headers: &'a mut HashMap) -> Self { - Self { handle, headers } - } - - #[tracing::instrument(skip(self), level = "debug")] - pub(crate) fn set_auth(&mut self, auth: &AuthType) -> Result<()> { - match auth { - AuthType::Basic { username, password } => { - tracing::info!(username = %username, "Setting basic auth"); - self.set_basic_auth(username, password) - } - AuthType::Bearer { token } => { - tracing::info!("Setting bearer auth"); - self.set_bearer_auth(token) - } - AuthType::Digest { - username, password, .. - } => { - tracing::info!(username = %username, "Setting digest auth"); - self.set_digest_auth(username, password) - } - AuthType::ApiKey { - key, - value, - location, - } => { - tracing::info!(key = %key, "Setting API key auth"); - self.set_apikey_auth(key, value, location) - } - AuthType::Aws { - access_key, - secret_key, - region, - service, - session_token, - location, - } => { - tracing::debug!("AWS SigV4 auth is handled at application level"); - self.set_aws_auth( - access_key, - secret_key, - region, - service, - session_token.as_deref(), - location, - ) - } - AuthType::OAuth2 { - grant_type, - access_token, - refresh_token, - } => { - if let Some(token) = access_token { - tracing::info!("Using existing OAuth2 access token"); - self.set_bearer_auth(token) - } else if let Some(refresh_token) = refresh_token { - tracing::info!("Refreshing OAuth2 token"); - self.refresh_oauth2_token(grant_type, refresh_token) - } else { - tracing::info!("Initiating OAuth2 flow"); - self.handle_oauth2_flow(grant_type) - } - } - AuthType::None => { - tracing::info!("No authentication required"); - Ok(()) - } - } - } - - fn set_basic_auth(&mut self, username: &str, password: &str) -> Result<()> { - tracing::debug!(username = %username, "Setting basic auth credentials"); - - self.handle.username(username).map_err(|e| { - tracing::error!(error = %e, "Failed to set username"); - RelayError::Network { - message: "Failed to set username".into(), - cause: Some(e.to_string()), - } - })?; - - self.handle.password(password).map_err(|e| { - tracing::error!(error = %e, "Failed to set password"); - RelayError::Network { - message: "Failed to set password".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Basic auth credentials set successfully"); - Ok(()) - } - - fn set_bearer_auth(&mut self, token: &str) -> Result<()> { - self.headers - .insert("Authorization".to_string(), format!("Bearer {}", token)); - Ok(()) - } - - fn set_apikey_auth(&mut self, key: &str, value: &str, location: &ApiKeyLocation) -> Result<()> { - tracing::debug!(key = %key, location = ?location, "Setting API key auth"); - - match location { - ApiKeyLocation::Header => { - tracing::debug!("Adding API key as header: {}", key); - self.headers.insert(key.to_string(), value.to_string()); - } - ApiKeyLocation::Query => { - // For query parameters, we don't need to do anything here - // This is handled in the request.rs file before setting the URL - tracing::debug!("API key will be added to query parameters in URL"); - } - } - - tracing::debug!("API key auth configured successfully"); - Ok(()) - } - - fn set_aws_auth( - &mut self, - _access_key: &str, - _secret_key: &str, - _region: &str, - _service: &str, - _session_token: Option<&str>, - _location: &ApiKeyLocation, - ) -> Result<()> { - tracing::debug!("AWS SigV4 auth is handled at application level"); - Ok(()) - } - - fn set_digest_auth(&mut self, username: &str, password: &str) -> Result<()> { - tracing::debug!("Setting up digest authentication"); - self.set_basic_auth(username, password)?; - - let mut auth = curl::easy::Auth::new(); - auth.digest(true); - - tracing::info!("Configuring digest auth mode"); - self.handle.http_auth(&auth).map_err(|e| { - tracing::error!(error = %e, "Failed to set digest authentication"); - RelayError::Network { - message: "Failed to set digest authentication".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Digest auth configured successfully"); - Ok(()) - } - - fn handle_oauth2_flow(&mut self, grant_type: &GrantType) -> Result<()> { - match grant_type { - GrantType::ClientCredentials { - token_endpoint, - client_id, - client_secret, - } => { - tracing::info!("Initiating client credentials flow"); - self.client_credentials_flow(token_endpoint, client_id, client_secret.as_deref()) - } - GrantType::Password { - token_endpoint, - username, - password, - } => { - tracing::info!("Initiating password flow"); - self.password_flow(token_endpoint, username, password) - } - GrantType::AuthorizationCode { .. } => { - tracing::warn!("Authorization Code flow not supported"); - Err(RelayError::UnsupportedFeature { - feature: "Authorization Code Grant".into(), - message: "Authorization Code flow requires browser interaction".into(), - relay: "curl".into(), - }) - } - GrantType::Implicit { .. } => { - tracing::warn!("Implicit flow not supported"); - Err(RelayError::UnsupportedFeature { - feature: "Implicit Grant".into(), - message: "Implicit flow requires browser interaction".into(), - relay: "curl".into(), - }) - } - } - } - - fn refresh_oauth2_token(&mut self, grant_type: &GrantType, refresh_token: &str) -> Result<()> { - let token_endpoint = match grant_type { - GrantType::ClientCredentials { token_endpoint, .. } - | GrantType::Password { token_endpoint, .. } - | GrantType::AuthorizationCode { token_endpoint, .. } => token_endpoint, - GrantType::Implicit { .. } => { - tracing::error!("Attempted to refresh token with implicit grant"); - return Err(RelayError::UnsupportedFeature { - feature: "Token Refresh".into(), - message: "Implicit grant does not support refresh tokens".into(), - relay: "curl".into(), - }); - } - }; - - let params = vec![ - ("grant_type", "refresh_token"), - ("refresh_token", refresh_token), - ]; - - self.request_token(token_endpoint, ¶ms) - } - - fn client_credentials_flow( - &mut self, - token_endpoint: &str, - client_id: &str, - client_secret: Option<&str>, - ) -> Result<()> { - tracing::info!("Performing client credentials flow"); - - let mut params = vec![ - ("grant_type", "client_credentials"), - ("client_id", client_id), - ]; - - if let Some(secret) = client_secret { - params.push(("client_secret", secret)); - } - - self.request_token(token_endpoint, ¶ms) - } - - fn password_flow( - &mut self, - token_endpoint: &str, - username: &str, - password: &str, - ) -> Result<()> { - tracing::info!("Performing password flow"); - - let params = vec![ - ("grant_type", "password"), - ("username", username), - ("password", password), - ]; - - self.request_token(token_endpoint, ¶ms) - } - - fn request_token(&mut self, token_endpoint: &str, params: &[(&str, &str)]) -> Result<()> { - let mut handle = Easy::new(); - tracing::debug!(endpoint = %token_endpoint, "Requesting OAuth2 token"); - - handle.url(token_endpoint).map_err(|e| { - tracing::error!(error = %e, "Failed to set token endpoint URL"); - RelayError::Network { - message: "Failed to set token endpoint URL".into(), - cause: Some(e.to_string()), - } - })?; - - let form_data: String = params - .iter() - .map(|(k, v)| format!("{}={}", urlencoding::encode(k), urlencoding::encode(v))) - .collect::>() - .join("&"); - - handle.post_fields_copy(form_data.as_bytes()).map_err(|e| { - tracing::error!(error = %e, "Failed to set form data"); - RelayError::Network { - message: "Failed to set form data".into(), - cause: Some(e.to_string()), - } - })?; - - let mut response = Vec::new(); - { - let mut transfer = handle.transfer(); - transfer - .write_function(|data| { - response.extend_from_slice(data); - Ok(data.len()) - }) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set write callback"); - RelayError::Network { - message: "Failed to set write callback".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Performing token request"); - transfer.perform().map_err(|e| { - tracing::error!(error = %e, "Failed to perform token request"); - RelayError::Network { - message: "Failed to perform token request".into(), - cause: Some(e.to_string()), - } - })?; - } - - let token_response: TokenResponse = serde_json::from_slice(&response).map_err(|e| { - tracing::error!(error = %e, "Failed to parse token response"); - RelayError::Parse { - message: "Failed to parse token response".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::info!("Successfully obtained OAuth2 token"); - self.set_bearer_auth(&token_response.access_token) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/content.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/content.rs deleted file mode 100644 index 1517bab4..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/content.rs +++ /dev/null @@ -1,306 +0,0 @@ -use curl::easy::Easy; -use http::HeaderName; -use std::{collections::HashMap, path::Path}; - -use crate::{ - error::{RelayError, Result}, - interop::{ContentType, FormValue, MediaType}, -}; - -pub(crate) struct ContentHandler<'a> { - handle: &'a mut Easy, - headers: &'a mut HashMap, -} - -impl<'a> ContentHandler<'a> { - pub(crate) fn new(handle: &'a mut Easy, headers: &'a mut HashMap) -> Self { - tracing::debug!("Creating new ContentHandler with headers: {:?}", headers); - Self { handle, headers } - } - - fn merge_headers(&mut self, new_headers: HashMap) { - tracing::info!( - original_headers = ?self.headers, - new_headers = ?new_headers, - "Merging headers" - ); - - for (key, value) in new_headers { - let key_lower = key.to_lowercase(); - - if !self - .headers - .iter() - .any(|(k, _)| k.to_lowercase() == key_lower) - { - let canonical_key = HeaderName::from_bytes(key.as_bytes()) - .map(|name| name.to_string()) - .unwrap_or_else(|_| key); - - tracing::debug!(key = %canonical_key, value = %value, "Adding header"); - self.headers.insert(canonical_key, value); - } else { - tracing::debug!(key = %key, "Skipping duplicate header (case-insensitive match exists)"); - } - } - - tracing::trace!(merged_headers = ?self.headers, "Headers after merge"); - } - - #[tracing::instrument(skip(self), level = "debug")] - pub(crate) fn set_content(&mut self, content: &ContentType) -> Result<()> { - match content { - ContentType::Text { - content, - media_type, - } => { - tracing::info!(content_length = content.len(), "Setting text content"); - self.set_text_content(content, media_type) - } - ContentType::Json { - content, - media_type, - } => { - tracing::info!("Setting JSON content"); - self.set_json_content(content, media_type) - } - ContentType::Form { - content, - media_type, - } => { - tracing::info!(field_count = content.len(), "Setting form content"); - self.set_form_content(content, media_type) - } - ContentType::Binary { - content, - media_type, - filename, - } => { - tracing::info!( - content_length = content.len(), - filename = ?filename, - "Setting binary content" - ); - self.set_binary_content(content, media_type, filename.as_deref()) - } - ContentType::Multipart { - content, - media_type, - } => { - tracing::info!(field_count = content.len(), "Setting multipart content"); - self.set_multipart_content(content, media_type) - } - ContentType::Xml { - content, - media_type, - } => { - tracing::info!("Setting XML content"); - self.set_text_content(content, media_type) - } - ContentType::Urlencoded { - content, - media_type, - } => { - tracing::info!(field_count = content.len(), "Setting URL-encoded content"); - self.set_urlencoded_content(content, media_type) - } - } - } - - fn set_text_content(&mut self, content: &str, media_type: &MediaType) -> Result<()> { - /* TODO: Look into reintroducing this when auth handling is done by kernel */ - // let mut headers = HashMap::new(); - // headers.insert("content-type".to_string(), media_type.to_string()); - // self.merge_headers(headers); - - self.handle - .post_fields_copy(content.as_bytes()) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set text content"); - RelayError::Network { - message: "Failed to set text content".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Text content set successfully"); - Ok(()) - } - - fn set_json_content( - &mut self, - content: &serde_json::Value, - media_type: &MediaType, - ) -> Result<()> { - let json_str = serde_json::to_string(content).map_err(|e| { - tracing::error!(error = %e, "Failed to serialize JSON"); - RelayError::Parse { - message: "Failed to serialize JSON".into(), - cause: Some(e.to_string()), - } - })?; - - /* TODO: Look into reintroducing this when auth handling is done by kernel */ - // let mut headers = HashMap::new(); - // headers.insert("content-type".to_string(), media_type.to_string()); - // self.merge_headers(headers); - - self.handle - .post_fields_copy(json_str.as_bytes()) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set JSON content"); - RelayError::Network { - message: "Failed to set JSON content".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("JSON content set successfully"); - Ok(()) - } - - fn set_binary_content( - &mut self, - content: &[u8], - media_type: &MediaType, - filename: Option<&str>, - ) -> Result<()> { - let mut headers = HashMap::new(); - - if let Some(name) = filename { - let safe_name = Path::new(name) - .file_name() - .and_then(|n| n.to_str()) - .unwrap_or(name); - - /* TODO: Look into reintroducing this when auth handling is done by kernel */ - // headers.insert("content-type".to_string(), media_type.to_string()); - headers.insert( - "Content-Disposition".to_string(), - format!("attachment; filename=\"{}\"", safe_name), - ); - } else { - /* TODO: Look into reintroducing this when auth handling is done by kernel */ - // headers.insert("content-type".to_string(), media_type.to_string()); - } - - // self.merge_headers(headers); - - self.handle.post_fields_copy(content).map_err(|e| { - tracing::error!(error = %e, "Failed to set binary content"); - RelayError::Network { - message: "Failed to set binary content".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Binary content set successfully"); - Ok(()) - } - - fn set_form_content( - &mut self, - content: &Vec<(String, Vec)>, - media_type: &MediaType, - ) -> Result<()> { - /* TODO: Look into reintroducing this when auth handling is done by kernel */ - // let mut headers = HashMap::new(); - // headers.insert("content-type".to_string(), media_type.to_string()); - // self.merge_headers(headers); - - let mut form = curl::easy::Form::new(); - - for (key, values) in content { - for value in values { - match value { - FormValue::Text { value: text } => { - tracing::debug!(key = %key, text_length = text.len(), "Adding form text field"); - form.part(key) - .contents(text.as_bytes()) - .add() - .map_err(|e| { - tracing::error!(error = %e, key = %key, "Failed to add form text field"); - RelayError::Network { - message: format!("Failed to add form text field: {}", key), - cause: Some(e.to_string()), - } - })?; - } - FormValue::File { - filename, - content_type, - data, - } => { - tracing::debug!( - key = %key, - filename = %filename, - content_type = ?content_type, - data_length = data.len(), - "Adding form file field" - ); - form.part(key) - .buffer(&filename, data.to_vec()) - .content_type(&content_type.to_string()) - .add() - .map_err(|e| { - tracing::error!( - error = %e, - key = %key, - filename = %filename, - "Failed to add form file field" - ); - RelayError::Network { - message: format!( - "Failed to add form file field: {} ({})", - key, filename - ), - cause: Some(e.to_string()), - } - })?; - } - } - } - } - - self.handle.httppost(form).map_err(|e| { - tracing::error!(error = %e, "Failed to set form data"); - RelayError::Network { - message: "Failed to set form data".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Form content set successfully"); - Ok(()) - } - - fn set_multipart_content( - &mut self, - content: &Vec<(String, Vec)>, - media_type: &MediaType, - ) -> Result<()> { - self.set_form_content(content, media_type) - } - - fn set_urlencoded_content(&mut self, content: &String, media_type: &MediaType) -> Result<()> { - /* TODO: Look into reintroducing this when auth handling is done by kernel */ - // let mut headers = HashMap::new(); - // headers.insert("content-type".to_string(), media_type.to_string()); - // self.merge_headers(headers); - - tracing::debug!(content_length = content.len(), "URL-encoded form data"); - - self.handle - .post_fields_copy(content.as_bytes()) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set urlencoded content"); - RelayError::Network { - message: "Failed to set urlencoded content".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("URL-encoded content set successfully"); - Ok(()) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/error.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/error.rs deleted file mode 100644 index 959b74a3..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/error.rs +++ /dev/null @@ -1,70 +0,0 @@ -use serde::{Deserialize, Serialize}; -use thiserror::Error; - -#[derive(Debug, Error, Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "snake_case")] -pub enum RelayError { - #[error("Unsupported feature '{feature}' in relay '{relay}': {message}")] - UnsupportedFeature { - feature: String, - message: String, - relay: String, - }, - - #[error("Network error: {message}")] - Network { - message: String, - #[serde(skip_serializing_if = "Option::is_none")] - cause: Option, - }, - - #[error("Request timed out during {}", .phase.as_ref().map_or("execution", TimeoutPhase::as_str))] - Timeout { - message: String, - phase: Option, - }, - - #[error("Certificate error: {message}")] - Certificate { - message: String, - #[serde(skip_serializing_if = "Option::is_none")] - cause: Option, - }, - - #[error("Failed to parse response: {message}")] - Parse { - message: String, - #[serde(skip_serializing_if = "Option::is_none")] - cause: Option, - }, - - #[error("Request aborted: {message}")] - Abort { message: String }, -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[serde(rename_all = "snake_case")] -pub enum TimeoutPhase { - Connect, - Tls, - Response, -} - -impl TimeoutPhase { - fn as_str(&self) -> &'static str { - match self { - TimeoutPhase::Connect => "connection establishment", - TimeoutPhase::Tls => "TLS handshake", - TimeoutPhase::Response => "response waiting", - } - } -} - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "kind", rename_all = "snake_case")] -pub enum RequestResult { - Success { response: T }, - Error { error: RelayError }, -} - -pub type Result = std::result::Result; diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/header.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/header.rs deleted file mode 100644 index b9a354de..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/header.rs +++ /dev/null @@ -1,69 +0,0 @@ -use std::collections::HashMap; -use std::str::FromStr; - -use curl::easy::{Easy, List}; -use http::{HeaderMap, HeaderName, HeaderValue}; - -use crate::error::{RelayError, Result}; - -pub(crate) struct HeadersBuilder<'a> { - handle: &'a mut Easy, -} - -impl<'a> HeadersBuilder<'a> { - pub(crate) fn new(handle: &'a mut Easy) -> Self { - Self { handle } - } - - #[tracing::instrument(skip(self), level = "debug")] - pub(crate) fn add_headers(&mut self, headers: Option<&HashMap>) -> Result<()> { - let Some(headers) = headers else { - tracing::debug!("No headers provided"); - return Ok(()); - }; - - let mut header_map = HeaderMap::new(); - for (key, value) in headers { - if let (Ok(name), Ok(val)) = (HeaderName::from_str(key), HeaderValue::from_str(value)) { - header_map.insert(name, val); - } - } - - let header_count = header_map.len(); - tracing::info!(header_count, "Building header list"); - - let list = header_map - .iter() - .map(|(key, value)| { - let key_str = key.as_str(); - let value_str = value.to_str().unwrap_or(""); - tracing::debug!( - key = ?key_str, - value_count = value_str.len(), - value = ?value_str, - "Processing headers" - ); - let header = format!("{}: {}", key_str, value_str); - tracing::debug!(%header, "Adding header"); - header - }) - .try_fold(List::new(), |mut list, header| { - list.append(&header).map_err(|e| { - tracing::error!(%e, "Failed to append header: {header}"); - RelayError::Network { - message: format!("Failed to append header: {header}"), - cause: Some(e.to_string()), - } - })?; - Ok(list) - })?; - - self.handle.http_headers(list).map_err(|e| { - tracing::error!(%e, "Failed to set headers"); - RelayError::Network { - message: "Failed to set headers".into(), - cause: Some(e.to_string()), - } - }) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/interop.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/interop.rs deleted file mode 100644 index 7f30ea7e..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/interop.rs +++ /dev/null @@ -1,421 +0,0 @@ -use std::collections::HashMap; - -use bytes::Bytes; -use http::{Method, StatusCode, Version}; -use serde::{Deserialize, Serialize}; -use strum::{Display, EnumString}; -use time::OffsetDateTime; - -#[derive(Debug, Serialize, Deserialize, Clone, Copy, PartialEq, Display, EnumString)] -pub enum MediaType { - // Text - #[serde(rename = "text/plain")] - #[strum(to_string = "text/plain")] - TextPlain, - #[serde(rename = "text/html")] - #[strum(to_string = "text/html")] - TextHtml, - #[serde(rename = "text/css")] - #[strum(to_string = "text/css")] - TextCss, - #[serde(rename = "text/csv")] - #[strum(to_string = "text/csv")] - TextCsv, - #[serde(rename = "text/xml")] - #[strum(to_string = "text/xml")] - TextXml, - - // Application - #[serde(rename = "application/json")] - #[strum(to_string = "application/json")] - Json, - #[serde(rename = "application/ld+json")] - #[strum(to_string = "application/ld+json")] - JsonLd, - #[serde(rename = "application/xml")] - #[strum(to_string = "application/xml")] - Xml, - #[serde(rename = "application/x-www-form-urlencoded")] - #[strum(to_string = "application/x-www-form-urlencoded")] - FormUrlEncoded, - #[serde(rename = "multipart/form-data")] - #[strum(to_string = "multipart/form-data")] - MultipartFormData, - #[serde(rename = "application/octet-stream")] - #[strum(to_string = "application/octet-stream")] - OctetStream, - #[serde(rename = "application/pdf")] - #[strum(to_string = "application/pdf")] - ApplicationPdf, - #[serde(rename = "application/zip")] - #[strum(to_string = "application/zip")] - ApplicationZip, - #[serde(rename = "application/javascript")] - #[strum(to_string = "application/javascript")] - ApplicationJavascript, - - // Audio - #[serde(rename = "audio/mpeg")] - #[strum(to_string = "audio/mpeg")] - AudioMpeg, - #[serde(rename = "audio/mp4")] - #[strum(to_string = "audio/mp4")] - AudioMp4, - #[serde(rename = "audio/x-m4a")] - #[strum(to_string = "audio/x-m4a")] - AudioXM4a, - #[serde(rename = "audio/wav")] - #[strum(to_string = "audio/wav")] - AudioWav, - #[serde(rename = "audio/ogg")] - #[strum(to_string = "audio/ogg")] - AudioOgg, - #[serde(rename = "audio/aac")] - #[strum(to_string = "audio/aac")] - AudioAac, - #[serde(rename = "audio/flac")] - #[strum(to_string = "audio/flac")] - AudioFlac, - - // Video - #[serde(rename = "video/mp4")] - #[strum(to_string = "video/mp4")] - VideoMp4, - #[serde(rename = "video/avi")] - #[strum(to_string = "video/avi")] - VideoAvi, - #[serde(rename = "video/quicktime")] - #[strum(to_string = "video/quicktime")] - VideoQuicktime, - #[serde(rename = "video/x-msvideo")] - #[strum(to_string = "video/x-msvideo")] - VideoXMsvideo, - #[serde(rename = "video/webm")] - #[strum(to_string = "video/webm")] - VideoWebm, - #[serde(rename = "video/x-flv")] - #[strum(to_string = "video/x-flv")] - VideoXFlv, - - // Image - #[serde(rename = "image/png")] - #[strum(to_string = "image/png")] - ImagePng, - #[serde(rename = "image/jpeg")] - #[strum(to_string = "image/jpeg")] - ImageJpeg, - #[serde(rename = "image/gif")] - #[strum(to_string = "image/gif")] - ImageGif, - #[serde(rename = "image/svg+xml")] - #[strum(to_string = "image/svg+xml")] - ImageSvgXml, - #[serde(rename = "image/webp")] - #[strum(to_string = "image/webp")] - ImageWebp, - #[serde(rename = "image/bmp")] - #[strum(to_string = "image/bmp")] - ImageBmp, - #[serde(rename = "image/x-icon")] - #[strum(to_string = "image/x-icon")] - ImageXIcon, - - // Fallback for unknown - #[serde(other)] - Other, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "kind", rename_all = "camelCase")] -pub enum FormValue { - #[serde(rename_all = "camelCase")] - Text { value: String }, - #[serde(rename_all = "camelCase")] - File { - filename: String, - content_type: MediaType, - data: Bytes, - }, -} - -pub type FormData = Vec<(String, Vec)>; - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "kind", rename_all = "camelCase")] -pub enum ContentType { - #[serde(rename_all = "camelCase")] - Text { - content: String, - media_type: MediaType, - }, - #[serde(rename_all = "camelCase")] - Json { - content: serde_json::Value, - media_type: MediaType, - }, - #[serde(rename_all = "camelCase")] - Xml { - content: String, - media_type: MediaType, - }, - #[serde(rename_all = "camelCase")] - Form { - content: FormData, - media_type: MediaType, - }, - #[serde(rename_all = "camelCase")] - Binary { - content: Bytes, - media_type: MediaType, - filename: Option, - }, - #[serde(rename_all = "camelCase")] - Multipart { - content: FormData, - media_type: MediaType, - }, - #[serde(rename_all = "camelCase")] - Urlencoded { - content: String, - media_type: MediaType, - }, -} - -#[derive(Debug, Serialize, Deserialize)] -pub struct TokenResponse { - pub access_token: String, - pub token_type: String, - pub expires_in: Option, - pub refresh_token: Option, - pub scope: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "kind", rename_all = "snake_case")] -pub enum GrantType { - #[serde(rename_all = "camelCase")] - AuthorizationCode { - auth_endpoint: String, - token_endpoint: String, - client_id: String, - client_secret: Option, - }, - #[serde(rename_all = "camelCase")] - ClientCredentials { - token_endpoint: String, - client_id: String, - client_secret: Option, - }, - #[serde(rename_all = "camelCase")] - Password { - token_endpoint: String, - username: String, - password: String, - }, - #[serde(rename_all = "camelCase")] - Implicit { - auth_endpoint: String, - client_id: String, - }, -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[serde(rename_all = "lowercase")] -pub enum ApiKeyLocation { - Header, - Query, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum AuthType { - None, - #[serde(rename_all = "camelCase")] - Basic { - username: String, - password: String, - }, - #[serde(rename_all = "camelCase")] - Bearer { - token: String, - }, - #[serde(rename_all = "camelCase")] - Digest { - username: String, - password: String, - realm: Option, - nonce: Option, - opaque: Option, - algorithm: Option, - qop: Option, - nc: Option, - cnonce: Option, - }, - #[serde(rename_all = "camelCase")] - ApiKey { - key: String, - value: String, - #[serde(rename = "in")] - location: ApiKeyLocation, - }, - #[serde(rename_all = "camelCase")] - OAuth2 { - grant_type: GrantType, - access_token: Option, - refresh_token: Option, - }, - #[serde(rename_all = "camelCase")] - Aws { - access_key: String, - secret_key: String, - region: String, - service: String, - session_token: Option, - #[serde(rename = "in")] - location: ApiKeyLocation, - }, -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[serde(rename_all = "SCREAMING-KEBAB-CASE")] -pub enum DigestAlgorithm { - Md5, - Sha256, - Sha512, -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -#[serde(rename_all = "kebab-case")] -pub enum DigestQop { - Auth, - AuthInt, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(tag = "kind", rename_all = "camelCase")] -pub enum CertificateType { - Pem { cert: Bytes, key: Bytes }, - Pfx { data: Bytes, password: String }, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct SecurityConfig { - pub certificates: Option, - #[serde(rename = "verifyHost")] - pub verify_host: Option, - #[serde(rename = "verifyPeer")] - pub verify_peer: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct CertificateConfig { - pub client: Option, - pub ca: Option>, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct RequestMeta { - pub options: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct RequestOptions { - pub timeout: Option, - pub follow_redirects: Option, - pub max_redirects: Option, - pub decompress: Option, - pub cookies: Option, - pub keep_alive: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Request { - pub id: i64, - pub url: String, - #[serde(with = "http_serde::method")] - pub method: Method, - #[serde(with = "http_serde::version")] - pub version: Version, - pub headers: Option>, - pub params: Option>, - pub content: Option, - pub auth: Option, - pub security: Option, - pub proxy: Option, - pub meta: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct ResponseBody { - pub body: Bytes, - pub media_type: MediaType, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Response { - pub id: i64, - #[serde(with = "http_serde::status_code")] - pub status: StatusCode, - #[serde(rename = "statusText")] - pub status_text: String, - #[serde(with = "http_serde::version")] - pub version: Version, - pub headers: HashMap, - pub cookies: Option>, - pub body: ResponseBody, - pub meta: ResponseMeta, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ProxyConfig { - pub url: String, - pub auth: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ProxyAuth { - pub username: String, - pub password: String, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct Cookie { - pub name: String, - pub value: String, - pub domain: Option, - pub path: Option, - pub expires: Option, - pub secure: Option, - #[serde(rename = "httpOnly")] - pub http_only: Option, - #[serde(rename = "sameSite")] - pub same_site: Option, -} - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] -pub enum SameSite { - Strict, - Lax, - None, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct ResponseMeta { - pub timing: TimingInfo, - pub size: SizeInfo, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct TimingInfo { - pub start: u64, - pub end: u64, -} - -#[derive(Debug, Serialize, Deserialize, Clone)] -pub struct SizeInfo { - pub headers: u64, - pub body: u64, - pub total: u64, -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/lib.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/lib.rs deleted file mode 100644 index 91270057..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -mod auth; -mod content; -pub mod error; -mod header; -mod interop; -mod relay; -mod request; -mod response; -mod security; -mod transfer; -mod util; - -pub use interop::{Request, Response}; -pub use relay::{cancel, execute}; diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/relay.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/relay.rs deleted file mode 100644 index 424a670c..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/relay.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::{ - sync::{ - atomic::{AtomicBool, Ordering}, - Arc, - }, - time::SystemTime, -}; - -use curl::easy::Easy; -use dashmap::DashMap; -use http::StatusCode; -use tokio_util::sync::CancellationToken; - -use crate::{ - error::{RelayError, Result}, - interop::{Request, Response}, - request::CurlRequest, - response::ResponseHandler, - transfer::TransferHandler, -}; - -lazy_static::lazy_static! { - static ref ACTIVE_REQUESTS: DashMap> = DashMap::new(); -} - -#[tracing::instrument(skip(request), fields(request_id = request.id), level = "debug")] -fn execute_request(request: &Request, cancel_token: &CancellationToken) -> Result { - tracing::info!( - method = %request.method, - url = %request.url, - "Executing request" - ); - - let id = request.id; - let mut handle = Easy::new(); - let start_time = SystemTime::now(); - - let mut curl_request = CurlRequest::new(&mut handle, request); - curl_request.prepare()?; - - tracing::debug!(request = ?request, "Full request details before sending"); - - handle.verbose(true).map_err(|e| RelayError::Network { - message: "Failed to set verbose mode".into(), - cause: Some(e.to_string()), - })?; - - handle - .debug_function(|info_type, data| { - if let Ok(s) = std::str::from_utf8(data) { - tracing::debug!(info_type = ?info_type, s = ?s, "cURL debug fn"); - } - }) - .map_err(|e| RelayError::Network { - message: "Failed to set debug function".into(), - cause: Some(e.to_string()), - })?; - - let mut transfer_handler = TransferHandler::new(); - transfer_handler.handle_transfer(&mut handle, cancel_token)?; - - let status = handle.response_code().map_err(|e| { - tracing::error!(error = %e, "Failed to get response code"); - RelayError::Network { - message: "Failed to get response code".into(), - cause: Some(e.to_string()), - } - })? as u16; - - let header_size = handle.header_size().map_err(|e| { - tracing::error!(error = %e, "Failed to get header size"); - RelayError::Network { - message: "Failed to get header size".into(), - cause: Some(e.to_string()), - } - })?; - - let (body, headers) = transfer_handler.into_parts(); - - tracing::info!( - status = status, - body_size = body.len(), - header_size = header_size, - "Request completed" - ); - - // NOTE: If this fails, something has gone very wrong. - let status_code = StatusCode::from_u16(status).unwrap(); - - ResponseHandler::new( - id, - headers, - body, - status_code, - header_size, - start_time, - SystemTime::now(), - request.version.clone(), - ) - .build() -} - -#[tracing::instrument(skip(request), fields(request_id = request.id), level = "debug")] -pub async fn execute(request: Request) -> Result { - let request_id = request.id; - let cancelled = Arc::new(AtomicBool::new(false)); - - tracing::info!( - method = %request.method, - url = %request.url, - "Starting request execution" - ); - - ACTIVE_REQUESTS.insert(request_id, Arc::clone(&cancelled)); - - let cancel_token = CancellationToken::new(); - let cancel_token_clone = cancel_token.clone(); - let cancelled_clone = Arc::clone(&cancelled); - - let handle = std::thread::spawn(move || { - let result = execute_request(&request, &cancel_token); - if cancel_token_clone.is_cancelled() { - cancelled_clone.store(true, Ordering::SeqCst); - } - result - }); - - let result = match handle.join() { - Ok(result) => { - if cancelled.load(Ordering::SeqCst) { - tracing::info!("Request was cancelled by user"); - Err(RelayError::Abort { - message: "Request cancelled by user".into(), - }) - } else { - tracing::debug!("Request completed normally"); - result - } - } - Err(_) => { - tracing::error!("Request thread panicked"); - Err(RelayError::Network { - message: "Request thread panicked".into(), - cause: None, - }) - } - }; - - ACTIVE_REQUESTS.remove(&request_id); - tracing::debug!("Request execution completed"); - - tracing::debug!("Result {:#?}", result); - - result -} - -#[tracing::instrument(level = "debug")] -pub async fn cancel(request_id: i64) -> Result<()> { - tracing::debug!(request_id = request_id, "Attempting to cancel request"); - - if let Some(cancelled) = ACTIVE_REQUESTS.get(&request_id) { - cancelled.store(true, Ordering::SeqCst); - tracing::info!(request_id = request_id, "Request cancelled successfully"); - Ok(()) - } else { - tracing::warn!( - request_id = request_id, - "Request not found for cancellation" - ); - Err(RelayError::Network { - message: "Request not found".into(), - cause: None, - }) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/request.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/request.rs deleted file mode 100644 index e9b55703..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/request.rs +++ /dev/null @@ -1,273 +0,0 @@ -use curl::easy::Easy; -use std::{collections::HashMap, ops::Not}; - -use crate::{ - auth::AuthHandler, - content::ContentHandler, - error::{RelayError, Result}, - header::HeadersBuilder, - interop::{ApiKeyLocation, AuthType, Request}, - security::SecurityHandler, - util::ToCurlVersion, -}; - -pub(crate) struct CurlRequest<'a> { - handle: &'a mut Easy, - request: &'a Request, -} - -impl<'a> CurlRequest<'a> { - pub(crate) fn new(handle: &'a mut Easy, request: &'a Request) -> Self { - tracing::debug!( - request_id = request.id, - url = %request.url, - method = %request.method, - "Creating new curl request" - ); - Self { handle, request } - } - - #[tracing::instrument(skip(self), fields(request_id = self.request.id), level = "debug")] - fn setup_basics(&mut self) -> Result<()> { - tracing::debug!("Setting up basic request parameters"); - - self.handle - .custom_request(&self.request.method.to_string()) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set request method"); - RelayError::Network { - message: "Failed to set request method".into(), - cause: Some(e.to_string()), - } - })?; - - self.handle.url(&self.request.url).map_err(|e| { - tracing::error!(error = %e, "Failed to set URL"); - RelayError::Network { - message: "Failed to set URL".into(), - cause: Some(e.to_string()), - } - })?; - - /* NOTE: Once auth handling is correctly migrated over, this is how query param should be handled - if let Some(AuthType::ApiKey { key, value, location }) = &self.request.auth { - if let ApiKeyLocation::Query = location { - tracing::debug!(key = %key, "Adding API key to query parameters"); - - let mut url = url::Url::parse(&self.request.url).map_err(|e| { - tracing::error!(error = %e, "Failed to parse URL for API key addition"); - RelayError::Parse { - message: "Failed to parse URL for API key addition".into(), - cause: Some(e.to_string()), - } - })?; - - url.query_pairs_mut().append_pair(key, value); - let updated_url = url.to_string(); - tracing::debug!(url = %updated_url, "Updated URL with API key in query parameters"); - - self.handle.url(&updated_url).map_err(|e| { - tracing::error!(error = %e, "Failed to set URL with API key"); - RelayError::Network { - message: "Failed to set URL with API key".into(), - cause: Some(e.to_string()), - } - })?; - } else { - self.handle.url(&self.request.url).map_err(|e| { - tracing::error!(error = %e, "Failed to set URL"); - RelayError::Network { - message: "Failed to set URL".into(), - cause: Some(e.to_string()), - } - })?; - } - } else { - self.handle.url(&self.request.url).map_err(|e| { - tracing::error!(error = %e, "Failed to set URL"); - RelayError::Network { - message: "Failed to set URL".into(), - cause: Some(e.to_string()), - } - })?; - } - */ - - self.handle - .http_version(self.request.version.to_curl_version()) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set HTTP version"); - RelayError::Network { - message: "Failed to set HTTP version".into(), - cause: Some(e.to_string()), - } - })?; - - // NOTE: `""` corresponds to accept all, - // see: https://curl.se/libcurl/c/CURLOPT_ACCEPT_ENCODING.html - self.handle.accept_encoding("").map_err(|e| { - tracing::error!(error = %e, "Failed to set accept-encoding"); - RelayError::Network { - message: "Failed to set accept-encoding".into(), - cause: Some(e.to_string()), - } - })?; - - let Some(ref meta) = self.request.meta else { - tracing::debug!("No meta configuration provided"); - return Ok(()); - }; - - let Some(ref options) = meta.options else { - tracing::debug!("No options in meta configuration"); - return Ok(()); - }; - - if let Some(follow) = options.follow_redirects { - tracing::debug!(follow_redirects = follow, "Setting redirect behavior"); - self.handle.follow_location(follow).map_err(|e| { - tracing::error!(error = %e, "Failed to set follow_location"); - RelayError::Network { - message: "Failed to set redirect behavior".into(), - cause: Some(e.to_string()), - } - })?; - } - - if let Some(max) = options.max_redirects { - tracing::debug!(max_redirects = max, "Setting maximum redirects"); - self.handle.max_redirections(max).map_err(|e| { - tracing::error!(error = %e, "Failed to set max_redirections"); - RelayError::Network { - message: "Failed to set maximum redirects".into(), - cause: Some(e.to_string()), - } - })?; - } - - if let Some(timeout_ms) = options.timeout { - tracing::debug!(timeout_ms = timeout_ms, "Setting request timeout"); - self.handle - .timeout(std::time::Duration::from_millis(timeout_ms)) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set timeout"); - RelayError::Network { - message: "Failed to set timeout".into(), - cause: Some(e.to_string()), - } - })?; - } - - if let Some(decompress) = options.decompress { - if !decompress { - tracing::debug!("Disabling automatic decompression"); - self.handle.accept_encoding("identity").map_err(|e| { - tracing::error!(error = %e, "Failed to disable decompression"); - RelayError::Network { - message: "Failed to disable decompression".into(), - cause: Some(e.to_string()), - } - })?; - } - } - - if let Some(enable_cookies) = options.cookies { - tracing::debug!(enable_cookies = enable_cookies, "Setting cookie handling"); - if enable_cookies { - self.handle.cookie_file("").map_err(|e| { - tracing::error!(error = %e, "Failed to enable cookies"); - RelayError::Network { - message: "Failed to enable cookie handling".into(), - cause: Some(e.to_string()), - } - })?; - } - } - - if let Some(keep_alive) = options.keep_alive { - tracing::debug!(keep_alive = keep_alive, "Setting keep-alive"); - self.handle.tcp_keepalive(keep_alive).map_err(|e| { - tracing::error!(error = %e, "Failed to set keep-alive"); - RelayError::Network { - message: "Failed to set keep-alive".into(), - cause: Some(e.to_string()), - } - })?; - } - - tracing::debug!("Basic request parameters set successfully"); - Ok(()) - } - - #[tracing::instrument(skip(self), fields(request_id = self.request.id), level = "debug")] - pub(crate) fn prepare(&mut self) -> Result<()> { - tracing::debug!("Preparing request"); - self.setup_basics()?; - - let mut headers = HashMap::new(); - - if let Some(ref content) = self.request.content { - tracing::trace!(content_type = ?content, "Setting request content"); - ContentHandler::new(self.handle, &mut headers).set_content(content)?; - } - - if let Some(ref auth) = self.request.auth { - tracing::trace!(auth_type = ?auth, "Configuring authentication"); - AuthHandler::new(self.handle, &mut headers).set_auth(auth)?; - } - - if let Some(ref security) = self.request.security { - tracing::trace!( - verify_peer = ?security.verify_peer, - verify_host = ?security.verify_host, - "Configuring security settings" - ); - SecurityHandler::new(self.handle).configure(security)?; - } - - if let Some(ref proxy) = self.request.proxy { - tracing::trace!(proxy_url = %proxy.url, "Setting up proxy"); - - self.handle - .proxy(&proxy.url) - .map_err(|e| RelayError::Network { - message: "Failed to set proxy".into(), - cause: Some(e.to_string()), - })?; - - self.handle - .proxy_auth(curl::easy::Auth::new().auto(true)) - .map_err(|e| RelayError::Network { - message: "Failed to set proxy authentication to auto".into(), - cause: Some(e.to_string()), - })?; - - if let Some(ref auth) = proxy.auth { - if (auth.username.trim().is_empty() || auth.password.trim().is_empty()).not() { - self.handle.proxy_username(&auth.username).map_err(|e| { - RelayError::Network { - message: "Failed to set proxy username".into(), - cause: Some(e.to_string()), - } - })?; - - self.handle.proxy_password(&auth.password).map_err(|e| { - RelayError::Network { - message: "Failed to set proxy password".into(), - cause: Some(e.to_string()), - } - })?; - } - } - } - - if let Some(ref request_headers) = self.request.headers { - headers.extend(request_headers.clone()); - HeadersBuilder::new(self.handle).add_headers(Some(&headers))?; - } else if !headers.is_empty() { - HeadersBuilder::new(self.handle).add_headers(Some(&headers))?; - } - - Ok(()) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/response.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/response.rs deleted file mode 100644 index a5c12d7e..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/response.rs +++ /dev/null @@ -1,159 +0,0 @@ -use std::{collections::HashMap, str::FromStr, time::SystemTime}; - -use bytes::Bytes; -use http::{StatusCode, Version}; -use mime::Mime; - -use crate::{ - error::{RelayError, Result}, - interop::{MediaType, Response, ResponseBody, ResponseMeta, SizeInfo, TimingInfo}, -}; - -pub(crate) struct ResponseHandler { - id: i64, - headers: HashMap, - body: Bytes, - status: StatusCode, - header_size: u64, - start_time: SystemTime, - end_time: SystemTime, - version: Version, -} - -impl ResponseHandler { - pub(crate) fn new( - id: i64, - headers: HashMap, - body: Bytes, - status: StatusCode, - header_size: u64, - start_time: SystemTime, - end_time: SystemTime, - version: Version, - ) -> Self { - Self { - id, - headers, - body, - status, - header_size, - start_time, - end_time, - version, - } - } - - #[tracing::instrument(skip(self), fields(request_id = self.id), level = "debug")] - pub(crate) fn build(self) -> Result { - tracing::debug!(status = %self.status, "Building response"); - let media_type = self.determine_media_type(); - let timing = self.calculate_timing()?; - let size = SizeInfo { - headers: self.header_size, - body: self.body.len() as u64, - total: self.header_size + self.body.len() as u64, - }; - - tracing::debug!( - status = ?self.status, - media_type = ?media_type, - body_size = size.body, - total_size = size.total, - version = ?self.version, - "Response built successfully" - ); - - let body = ResponseBody { - body: self.body, - media_type, - }; - - Ok(Response { - id: self.id, - status: self.status, - status_text: self.status.to_string(), - version: self.version, - headers: self.headers, - cookies: None, - meta: ResponseMeta { timing, size }, - body, - }) - } - - fn determine_media_type(&self) -> MediaType { - tracing::trace!("Determining response content type"); - - self.headers - .iter() - .find_map(|(k, v)| { - if k.to_lowercase() == "content-type" { - v.parse::() - .ok() - .and_then(|mime| match (mime.type_(), mime.subtype()) { - (mime::APPLICATION, mime::JSON) => Some(MediaType::Json), - (mime::APPLICATION, mime::XML) => Some(MediaType::Xml), - (mime::APPLICATION, mime::OCTET_STREAM) => Some(MediaType::OctetStream), - (mime::TEXT, mime::PLAIN) => Some(MediaType::TextPlain), - (mime::TEXT, mime::HTML) => Some(MediaType::TextHtml), - (mime::TEXT, mime::CSS) => Some(MediaType::TextCss), - (mime::TEXT, mime::CSV) => Some(MediaType::TextCsv), - (mime::TEXT, mime::XML) => Some(MediaType::TextXml), - (mime::APPLICATION, mime::WWW_FORM_URLENCODED) => { - Some(MediaType::FormUrlEncoded) - } - (mime::APPLICATION, name) if name == "ld+json" => { - Some(MediaType::JsonLd) - } - (mime::MULTIPART, name) if name == "form-data" => { - Some(MediaType::MultipartFormData) - } - _ => None, - }) - } else { - None - } - }) - .or(infer::get(&self.body) - .map(|kind| MediaType::from_str(kind.mime_type()).ok()) - .flatten()) - .unwrap_or(MediaType::TextPlain) - } - - fn calculate_timing(&self) -> Result { - let start_ms = self - .start_time - .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|e| { - tracing::error!(error = %e, "Failed to get start time"); - RelayError::Parse { - message: "Failed to get start time".into(), - cause: Some(e.to_string()), - } - })? - .as_millis() as u64; - - let end_ms = self - .end_time - .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|e| { - tracing::error!(error = %e, "Failed to get end time"); - RelayError::Parse { - message: "Failed to get end time".into(), - cause: Some(e.to_string()), - } - })? - .as_millis() as u64; - - tracing::trace!( - start_ms = start_ms, - end_ms = end_ms, - duration_ms = end_ms - start_ms, - "Calculated request timing" - ); - - Ok(TimingInfo { - start: start_ms, - end: end_ms, - }) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/security.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/security.rs deleted file mode 100644 index 6a2e4dec..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/security.rs +++ /dev/null @@ -1,173 +0,0 @@ -use bytes::Bytes; -use curl::easy::Easy; - -use openssl::pkcs12::Pkcs12; - -use crate::{ - error::{RelayError, Result}, - interop::{CertificateConfig, CertificateType, SecurityConfig}, -}; - -pub(crate) struct SecurityHandler<'a> { - handle: &'a mut Easy, -} - -impl<'a> SecurityHandler<'a> { - pub(crate) fn new(handle: &'a mut Easy) -> Self { - Self { handle } - } - - #[tracing::instrument(skip(self), level = "debug")] - pub(crate) fn configure(&mut self, security: &SecurityConfig) -> Result<()> { - tracing::info!("Configuring security settings"); - - if let Some(verify) = security.verify_peer { - tracing::debug!(verify = verify, "Setting SSL verify peer"); - self.handle.ssl_verify_peer(verify).map_err(|e| { - tracing::error!(error = %e, "Failed to set SSL verify peer"); - RelayError::Certificate { - message: "Failed to set SSL verify peer".into(), - cause: Some(e.to_string()), - } - })?; - } - - if let Some(verify) = security.verify_host { - tracing::debug!(verify = verify, "Setting SSL verify host"); - self.handle.ssl_verify_host(verify).map_err(|e| { - tracing::error!(error = %e, "Failed to set SSL verify host"); - RelayError::Certificate { - message: "Failed to set SSL verify host".into(), - cause: Some(e.to_string()), - } - })?; - } - - if let Some(ref certs) = security.certificates { - self.configure_certificates(certs)?; - } - - tracing::debug!("Security configuration complete"); - Ok(()) - } - - #[tracing::instrument(skip(self), level = "debug")] - fn configure_certificates(&mut self, certs: &CertificateConfig) -> Result<()> { - if let Some(ref client_cert) = certs.client { - match client_cert { - CertificateType::Pem { cert, key } => { - tracing::info!("Configuring PEM certificate"); - self.configure_pem_certificate(cert, key)?; - } - CertificateType::Pfx { data, password } => { - tracing::info!("Configuring PKCS#12 certificate"); - self.configure_pfx_certificate(data, password)?; - } - } - } - - if let Some(ref ca_certs) = certs.ca { - self.configure_ca_certificates(ca_certs)?; - } - - Ok(()) - } - - fn configure_pem_certificate(&mut self, cert: &[u8], key: &[u8]) -> Result<()> { - tracing::debug!("Setting PEM certificate type"); - self.handle.ssl_cert_type("PEM").map_err(|e| { - tracing::error!(error = %e, "Failed to set certificate type"); - RelayError::Certificate { - message: "Failed to set certificate type".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Setting PEM certificate data"); - self.handle.ssl_cert_blob(cert).map_err(|e| { - tracing::error!(error = %e, "Failed to set client certificate"); - RelayError::Certificate { - message: "Failed to set client certificate".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Setting PEM key type"); - self.handle.ssl_key_type("PEM").map_err(|e| { - tracing::error!(error = %e, "Failed to set key type"); - RelayError::Certificate { - message: "Failed to set key type".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Setting PEM key data"); - self.handle.ssl_key_blob(key).map_err(|e| { - tracing::error!(error = %e, "Failed to set client key"); - RelayError::Certificate { - message: "Failed to set client key".into(), - cause: Some(e.to_string()), - } - })?; - - Ok(()) - } - - fn configure_pfx_certificate(&mut self, data: &[u8], password: &str) -> Result<()> { - let pkcs12 = Pkcs12::from_der(data).map_err(|e| { - tracing::error!(error = %e, "Failed to parse PKCS#12 data"); - RelayError::Certificate { - message: "Failed to parse PKCS#12 data".into(), - cause: Some(e.to_string()), - } - })?; - - let parsed = pkcs12.parse2(password).map_err(|e| { - tracing::error!(error = %e, "Failed to parse PKCS#12 password"); - RelayError::Certificate { - message: "Failed to parse PKCS#12 password".into(), - cause: Some(e.to_string()), - } - })?; - - if let (Some(cert), Some(key)) = (parsed.cert, parsed.pkey) { - let cert_pem = cert.to_pem().map_err(|e| { - tracing::error!(error = %e, "Failed to convert certificate to PEM"); - RelayError::Certificate { - message: "Failed to convert certificate to PEM".into(), - cause: Some(e.to_string()), - } - })?; - - let key_pem = key.private_key_to_pem_pkcs8().map_err(|e| { - tracing::error!(error = %e, "Failed to convert private key to PEM"); - RelayError::Certificate { - message: "Failed to convert private key to PEM".into(), - cause: Some(e.to_string()), - } - })?; - - self.configure_pem_certificate(&cert_pem, &key_pem) - } else { - tracing::error!("PKCS#12 file missing certificate or private key"); - Err(RelayError::Certificate { - message: "PKCS#12 file missing certificate or private key".into(), - cause: None, - }) - } - } - - fn configure_ca_certificates(&mut self, ca_certs: &[Bytes]) -> Result<()> { - for (index, cert) in ca_certs.iter().enumerate() { - tracing::debug!(cert_index = index, "Setting CA certificate"); - self.handle.ssl_cainfo_blob(cert).map_err(|e| { - tracing::error!(error = %e, cert_index = index, "Failed to set CA certificate"); - RelayError::Certificate { - message: format!("Failed to set CA certificate at index {}", index), - cause: Some(e.to_string()), - } - })?; - } - Ok(()) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/transfer.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/transfer.rs deleted file mode 100644 index dde38d9c..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/transfer.rs +++ /dev/null @@ -1,116 +0,0 @@ -use std::collections::HashMap; - -use bytes::{Bytes, BytesMut}; -use curl::easy::Easy; -use tokio_util::sync::CancellationToken; - -use crate::error::{RelayError, Result}; - -pub(crate) struct TransferHandler { - body: BytesMut, - headers: HashMap, -} - -impl TransferHandler { - pub(crate) fn new() -> Self { - Self { - body: BytesMut::new(), - headers: HashMap::new(), - } - } - - #[tracing::instrument(skip(self, handle), level = "debug")] - pub(crate) fn handle_transfer( - &mut self, - handle: &mut Easy, - cancel_token: &CancellationToken, - ) -> Result<()> { - tracing::debug!("Setting up transfer handlers"); - let mut transfer = handle.transfer(); - - let body = &mut self.body; - let headers = &mut self.headers; - - transfer - .write_function(move |data| { - body.extend_from_slice(data); - tracing::trace!(bytes = data.len(), "Received response data chunk"); - Ok(data.len()) - }) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set write callback"); - RelayError::Network { - message: "Failed to set write callback".into(), - cause: Some(e.to_string()), - } - })?; - - transfer - .header_function(move |header| { - if let Ok(header_str) = String::from_utf8(header.to_vec()) { - if let Some(idx) = header_str.find(':') { - let (key, value) = header_str.split_at(idx); - let key = key.trim().to_string(); - let value = value[1..].trim().to_string(); - - if key.to_lowercase() == "set-cookie" { - // NOTE: Special handling workaround. - // Concatenate multiple `Set-Cookie` headers. - match headers.entry(key) { - std::collections::hash_map::Entry::Occupied(mut e) => { - let existing = e.get_mut(); - existing.push_str("\n"); - existing.push_str(&value); - } - std::collections::hash_map::Entry::Vacant(e) => { - e.insert(value); - } - } - } else { - headers.entry(key).or_insert(value); - } - } - } - true - }) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set header callback"); - RelayError::Network { - message: "Failed to set header callback".into(), - cause: Some(e.to_string()), - } - })?; - - transfer - .progress_function(|_, _, _, _| { - let cancelled = cancel_token.is_cancelled(); - if cancelled { - tracing::warn!("Request cancelled by user"); - } - !cancelled - }) - .map_err(|e| { - tracing::error!(error = %e, "Failed to set progress callback"); - RelayError::Network { - message: "Failed to set progress callback".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Starting transfer"); - transfer.perform().map_err(|e| { - tracing::error!(error = %e, "Failed to perform request"); - RelayError::Network { - message: "Failed to perform request".into(), - cause: Some(e.to_string()), - } - })?; - - tracing::debug!("Transfer completed successfully"); - Ok(()) - } - - pub(crate) fn into_parts(self) -> (Bytes, HashMap) { - (self.body.into(), self.headers) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/relay/src/util.rs b/packages/hoppscotch-desktop/plugin-workspace/relay/src/util.rs deleted file mode 100644 index 6e1c5ecb..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/relay/src/util.rs +++ /dev/null @@ -1,15 +0,0 @@ -pub trait ToCurlVersion { - fn to_curl_version(self) -> curl::easy::HttpVersion; -} - -impl ToCurlVersion for http::Version { - fn to_curl_version(self) -> curl::easy::HttpVersion { - match self { - http::Version::HTTP_10 => curl::easy::HttpVersion::V10, - http::Version::HTTP_11 => curl::easy::HttpVersion::V11, - http::Version::HTTP_2 => curl::easy::HttpVersion::V2, - http::Version::HTTP_3 => curl::easy::HttpVersion::V3, - _ => panic!("Unsupported"), - } - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/.envrc b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/.envrc deleted file mode 100644 index 894571bf..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -source_url "https://raw.githubusercontent.com/cachix/devenv/82c0147677e510b247d8b9165c54f73d32dfd899/direnvrc" "sha256-7u4iDd1nZpxL4tCzmPG0dQgC5V+/44Ba+tHkPob1v2k=" - -use devenv diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/.gitignore b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/.gitignore deleted file mode 100644 index c387dc9f..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/.gitignore +++ /dev/null @@ -1,22 +0,0 @@ -/.vs -.DS_Store -.Thumbs.db -*.sublime* -.idea/ -debug.log -package-lock.json -.vscode/settings.json -yarn.lock - -/.tauri -/target -node_modules/ -# Devenv -.devenv* -devenv.local.nix - -# direnv -.direnv - -# pre-commit -.pre-commit-config.yaml diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/Cargo.lock b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/Cargo.lock deleted file mode 100644 index 84f403ad..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/Cargo.lock +++ /dev/null @@ -1,5812 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "atk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" -dependencies = [ - "serde", -] - -[[package]] -name = "blake3" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "serde", -] - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -dependencies = [ - "objc2 0.5.2", -] - -[[package]] -name = "block2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" -dependencies = [ - "objc2 0.6.1", -] - -[[package]] -name = "bon" -version = "3.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced38439e7a86a4761f7f7d5ded5ff009135939ecb464a24452eaa4c1696af7d" -dependencies = [ - "bon-macros", - "rustversion", -] - -[[package]] -name = "bon-macros" -version = "3.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce61d2d3844c6b8d31b2353d9f66cf5e632b3e9549583fe3cac2f4f6136725e" -dependencies = [ - "darling", - "ident_case", - "prettyplease", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.101", -] - -[[package]] -name = "brotli" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a334ef7c9e23abf0ce748e8cd309037da93e606ad52eb372e4ce327a0dcfbdfd" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "bytemuck" -version = "1.23.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9134a6ef01ce4b366b50689c94f82c14bc72bc5d0386829828a2e2752ef7958c" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -dependencies = [ - "serde", -] - -[[package]] -name = "bzip2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ecfb22d906f800d4fe833b6282cf4dc1c298f5057ca0b5445e5c209735ca47" -dependencies = [ - "bzip2-sys", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.13+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.9.0", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror 2.0.12", -] - -[[package]] -name = "cargo_toml" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257" -dependencies = [ - "serde", - "toml", -] - -[[package]] -name = "cc" -version = "1.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-link", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "cocoa" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" -dependencies = [ - "bitflags 2.9.0", - "block", - "cocoa-foundation", - "core-foundation 0.10.0", - "core-graphics", - "foreign-types 0.5.0", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" -dependencies = [ - "bitflags 2.9.0", - "block", - "core-foundation 0.10.0", - "core-graphics-types", - "libc", - "objc", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "time", - "version_check", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", - "core-graphics-types", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.101", -] - -[[package]] -name = "ctor" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.101", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.101", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "deflate64" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" - -[[package]] -name = "der" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "derive_arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "derive_more" -version = "0.99.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.101", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.59.0", -] - -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "dispatch2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "dlopen2" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "dpi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" -dependencies = [ - "serde", -] - -[[package]] -name = "dtoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "serde", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core 0.6.4", - "serde", - "sha2", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "embed-resource" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml", - "vswhom", - "winreg", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "erased-serde" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" -dependencies = [ - "serde", - "typeid", -] - -[[package]] -name = "errno" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version", -] - -[[package]] -name = "flate2" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkx11" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" -dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps", - "x11", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", - "wasm-bindgen", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.9.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gtk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "h2" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9421a676d1b147b16b82c9225157dc629087ef8ec4d5e2960f9437a90dac0a5" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.9.0", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex_color" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37f101bf4c633f7ca2e4b5e136050314503dd198e78e325ea602c327c484ef0" -dependencies = [ - "rand 0.8.5", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.15", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "humantime" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" - -[[package]] -name = "humantime-serde" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" -dependencies = [ - "humantime", - "serde", -] - -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "itoa 1.0.15", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "libc", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core 0.61.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ico" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" -dependencies = [ - "byteorder", - "png", -] - -[[package]] -name = "icu_collections" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" -dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locale_core" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_normalizer" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" - -[[package]] -name = "icu_properties" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "potential_utf", - "zerotrie", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" - -[[package]] -name = "icu_provider" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" -dependencies = [ - "displaydoc", - "icu_locale_core", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" -dependencies = [ - "equivalent", - "hashbrown 0.15.3", - "serde", -] - -[[package]] -name = "infer" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" -dependencies = [ - "cfb", -] - -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" -dependencies = [ - "getrandom 0.3.3", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "json-patch" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" -dependencies = [ - "jsonptr", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "jsonptr" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.9.0", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "kuchikiki" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 1.9.3", - "matches", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.9.0", - "libc", -] - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "litemap" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.3", -] - -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder", - "crc", -] - -[[package]] -name = "lzma-sys" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime-infer" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91caed19dd472bc88bcd063571df18153529d49301a1918f4cf37f42332bee2e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", -] - -[[package]] -name = "muda" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492" -dependencies = [ - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc2 0.6.1", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "once_cell", - "png", - "serde", - "thiserror 2.0.12", - "windows-sys 0.59.0", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.9.0", - "jni-sys", - "log", - "ndk-sys", - "num_enum", - "raw-window-handle", - "thiserror 1.0.69", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.6.0+11769913" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "ntapi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" -dependencies = [ - "winapi", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys", - "objc2-encode", -] - -[[package]] -name = "objc2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551" -dependencies = [ - "objc2-encode", - "objc2-exception-helper", -] - -[[package]] -name = "objc2-app-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" -dependencies = [ - "bitflags 2.9.0", - "block2 0.6.1", - "libc", - "objc2 0.6.1", - "objc2-cloud-kit", - "objc2-core-data", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", - "objc2-foundation 0.3.1", - "objc2-quartz-core 0.3.1", -] - -[[package]] -name = "objc2-cloud-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17614fdcd9b411e6ff1117dfb1d0150f908ba83a7df81b1f118005fe0a8ea15d" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-core-data" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291fbbf7d29287518e8686417cf7239c74700fd4b607623140a7d4a3c834329d" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" -dependencies = [ - "bitflags 2.9.0", - "dispatch2", - "objc2 0.6.1", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" -dependencies = [ - "bitflags 2.9.0", - "dispatch2", - "objc2 0.6.1", - "objc2-core-foundation", - "objc2-io-surface", -] - -[[package]] -name = "objc2-core-image" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b3dc0cc4386b6ccf21c157591b34a7f44c8e75b064f85502901ab2188c007e" -dependencies = [ - "objc2 0.6.1", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-exception-helper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" -dependencies = [ - "cc", -] - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.9.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" -dependencies = [ - "bitflags 2.9.0", - "block2 0.6.1", - "libc", - "objc2 0.6.1", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-surface" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.9.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.9.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ffb6a0cd5f182dc964334388560b12a57f7b74b3e2dec5e2722aa2dfb2ccd5" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-ui-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-web-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" -dependencies = [ - "bitflags 2.9.0", - "block2 0.6.1", - "objc2 0.6.1", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "openssl" -version = "0.10.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" -dependencies = [ - "bitflags 2.9.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.108" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher 1.0.1", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "plist" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac26e981c03a6e53e0aee43c113e3202f5581d5360dae7bd2c70e800dd0451d" -dependencies = [ - "base64 0.22.1", - "indexmap 2.9.0", - "quick-xml", - "serde", - "time", -] - -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "potential_utf" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" -dependencies = [ - "zerovec", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "664ec5419c51e34154eec046ebcba56312d5a2fc3b09a06da188e1ad21afadf6" -dependencies = [ - "proc-macro2", - "syn 2.0.101", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - -[[package]] -name = "proc-macro-crate" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" -dependencies = [ - "toml_edit 0.22.26", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-xml" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "redox_users" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" -dependencies = [ - "getrandom 0.2.16", - "libredox", - "thiserror 2.0.12", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "reqwest" -version = "0.12.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" -dependencies = [ - "base64 0.22.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-util", - "tower", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "windows-registry", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.16", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" -dependencies = [ - "bitflags 2.9.0", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls" -version = "0.23.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" -dependencies = [ - "once_cell", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" -dependencies = [ - "zeroize", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "schemars" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" -dependencies = [ - "dyn-clone", - "indexmap 1.9.3", - "schemars_derive", - "serde", - "serde_json", - "url", - "uuid", -] - -[[package]] -name = "schemars_derive" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.101", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-untagged" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e" -dependencies = [ - "erased-serde", - "serde", - "typeid", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa 1.0.15", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa 1.0.15", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.9.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "serialize-to-javascript" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "rand_core 0.6.4", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" - -[[package]] -name = "socket2" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "softbuffer" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" -dependencies = [ - "bytemuck", - "cfg_aliases", - "core-graphics", - "foreign-types 0.5.0", - "js-sys", - "log", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", - "raw-window-handle", - "redox_syscall", - "wasm-bindgen", - "web-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "swift-rs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" -dependencies = [ - "base64 0.21.7", - "serde", - "serde_json", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "sysinfo" -version = "0.34.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2" -dependencies = [ - "libc", - "memchr", - "ntapi", - "objc2-core-foundation", - "windows 0.57.0", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "tao" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e59c1f38e657351a2e822eadf40d6a2ad4627b9c25557bc1180ec1b3295ef82" -dependencies = [ - "bitflags 2.9.0", - "core-foundation 0.10.0", - "core-graphics", - "crossbeam-channel", - "dispatch", - "dlopen2", - "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni", - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc2 0.6.1", - "objc2-app-kit", - "objc2-foundation 0.3.1", - "once_cell", - "parking_lot", - "raw-window-handle", - "scopeguard", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.61.1", - "windows-core 0.61.0", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "tauri" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7b0bc1aec81bda6bc455ea98fcaed26b3c98c1648c627ad6ff1c704e8bf8cbc" -dependencies = [ - "anyhow", - "bytes", - "dirs", - "dunce", - "embed_plist", - "futures-util", - "getrandom 0.2.16", - "glob", - "gtk", - "heck 0.5.0", - "http", - "jni", - "libc", - "log", - "mime", - "muda", - "objc2 0.6.1", - "objc2-app-kit", - "objc2-foundation 0.3.1", - "objc2-ui-kit", - "percent-encoding", - "plist", - "raw-window-handle", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "swift-rs", - "tauri-build", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "thiserror 2.0.12", - "tokio", - "tray-icon", - "url", - "urlpattern", - "webkit2gtk", - "webview2-com", - "window-vibrancy", - "windows 0.61.1", -] - -[[package]] -name = "tauri-build" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a0350f0df1db385ca5c02888a83e0e66655c245b7443db8b78a70da7d7f8fc" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs", - "glob", - "heck 0.5.0", - "json-patch", - "schemars", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml", - "walkdir", -] - -[[package]] -name = "tauri-codegen" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93f035551bf7b11b3f51ad9bc231ebbe5e085565527991c16cf326aa38cdf47" -dependencies = [ - "base64 0.22.1", - "brotli", - "ico", - "json-patch", - "plist", - "png", - "proc-macro2", - "quote", - "semver", - "serde", - "serde_json", - "sha2", - "syn 2.0.101", - "tauri-utils", - "thiserror 2.0.12", - "time", - "url", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-macros" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db4df25e2d9d45de0c4c910da61cd5500190da14ae4830749fee3466dddd112" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.101", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a5ebe6a610d1b78a94650896e6f7c9796323f408800cef436e0fa0539de601" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars", - "serde", - "serde_json", - "tauri-utils", - "toml", - "walkdir", -] - -[[package]] -name = "tauri-plugin-appload" -version = "0.1.0" -dependencies = [ - "base64 0.22.1", - "blake3", - "bon", - "chrono", - "cocoa", - "dashmap", - "dunce", - "ed25519-dalek", - "flate2", - "futures", - "hex", - "hex_color", - "humantime-serde", - "lru", - "mime-infer", - "mime_guess", - "objc", - "rand 0.8.5", - "rayon", - "regex", - "reqwest", - "serde", - "serde_json", - "sysinfo", - "tauri", - "tauri-plugin", - "thiserror 2.0.12", - "tokio", - "tracing", - "url", - "windows 0.58.0", - "winver", - "zip", -] - -[[package]] -name = "tauri-runtime" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f004905d549854069e6774533d742b03cacfd6f03deb08940a8677586cbe39" -dependencies = [ - "cookie", - "dpi", - "gtk", - "http", - "jni", - "objc2 0.6.1", - "objc2-ui-kit", - "raw-window-handle", - "serde", - "serde_json", - "tauri-utils", - "thiserror 2.0.12", - "url", - "windows 0.61.1", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f85d056f4d4b014fe874814034f3416d57114b617a493a4fe552580851a3f3a2" -dependencies = [ - "gtk", - "http", - "jni", - "log", - "objc2 0.6.1", - "objc2-app-kit", - "objc2-foundation 0.3.1", - "once_cell", - "percent-encoding", - "raw-window-handle", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.1", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2900399c239a471bcff7f15c4399eb1a8c4fe511ba2853e07c996d771a5e0a4" -dependencies = [ - "anyhow", - "brotli", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "html5ever", - "http", - "infer", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.3", - "proc-macro2", - "quote", - "regex", - "schemars", - "semver", - "serde", - "serde-untagged", - "serde_json", - "serde_with", - "swift-rs", - "thiserror 2.0.12", - "toml", - "url", - "urlpattern", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-winres" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8d321dbc6f998d825ab3f0d62673e810c861aac2d0de2cc2c395328f1d113b4" -dependencies = [ - "embed-resource", - "indexmap 2.9.0", - "toml", -] - -[[package]] -name = "tempfile" -version = "3.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" -dependencies = [ - "fastrand", - "getrandom 0.3.3", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "time" -version = "0.3.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" -dependencies = [ - "deranged", - "itoa 1.0.15", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" - -[[package]] -name = "time-macros" -version = "0.2.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.26", -] - -[[package]] -name = "toml_datetime" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.9.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.9.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" -dependencies = [ - "indexmap 2.9.0", - "serde", - "serde_spanned", - "toml_datetime", - "toml_write", - "winnow 0.7.10", -] - -[[package]] -name = "toml_write" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tray-icon" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7eee98ec5c90daf179d55c20a49d8c0d043054ce7c26336c09a24d31f14fa0" -dependencies = [ - "crossbeam-channel", - "dirs", - "libappindicator", - "muda", - "objc2 0.6.1", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.1", - "once_cell", - "png", - "serde", - "thiserror 2.0.12", - "windows-sys 0.59.0", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "urlpattern" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" -dependencies = [ - "regex", - "serde", - "unic-ucd-ident", - "url", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "uuid" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" -dependencies = [ - "getrandom 0.3.3", - "serde", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.101", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webkit2gtk" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps", -] - -[[package]] -name = "webview2-com" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b542b5cfbd9618c46c2784e4d41ba218c336ac70d44c55e47b251033e7d85601" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.61.1", - "windows-core 0.61.0", - "windows-implement 0.60.0", - "windows-interface 0.59.1", -] - -[[package]] -name = "webview2-com-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "webview2-com-sys" -version = "0.37.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae2d11c4a686e4409659d7891791254cf9286d3cfe0eef54df1523533d22295" -dependencies = [ - "thiserror 2.0.12", - "windows 0.61.1", - "windows-core 0.61.0", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "window-vibrancy" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" -dependencies = [ - "objc2 0.6.1", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "raw-window-handle", - "windows-sys 0.59.0", - "windows-version", -] - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.61.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419" -dependencies = [ - "windows-collections", - "windows-core 0.61.0", - "windows-future", - "windows-link", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.0", -] - -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.61.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" -dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", - "windows-link", - "windows-result 0.3.2", - "windows-strings 0.4.0", -] - -[[package]] -name = "windows-future" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32" -dependencies = [ - "windows-core 0.61.0", - "windows-link", -] - -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.0", - "windows-link", -] - -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result 0.3.2", - "windows-strings 0.3.1", - "windows-targets 0.53.0", -] - -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows-version" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04a5c6627e310a23ad2358483286c7df260c964eb2d003d8efd6d0f4e79265c" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "winver" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0e7162b9e282fd75a0a832cce93994bdb21208d848a418cd05a5fdd9b9ab33" -dependencies = [ - "windows 0.48.0", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "writeable" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" - -[[package]] -name = "wry" -version = "0.51.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c886a0a9d2a94fd90cfa1d929629b79cfefb1546e2c7430c63a47f0664c0e4e2" -dependencies = [ - "base64 0.22.1", - "block2 0.6.1", - "cookie", - "crossbeam-channel", - "dpi", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http", - "javascriptcore-rs", - "jni", - "kuchikiki", - "libc", - "ndk", - "objc2 0.6.1", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "objc2-ui-kit", - "objc2-web-kit", - "once_cell", - "percent-encoding", - "raw-window-handle", - "sha2", - "soup3", - "tao-macros", - "thiserror 2.0.12", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.61.1", - "windows-core 0.61.0", - "windows-version", - "x11-dl", -] - -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "xz2" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" -dependencies = [ - "lzma-sys", -] - -[[package]] -name = "yoke" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "zerotrie" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", -] - -[[package]] -name = "zerovec" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "zip" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dcb24d0152526ae49b9b96c1dcf71850ca1e0b882e4e28ed898a93c41334744" -dependencies = [ - "aes", - "arbitrary", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "deflate64", - "flate2", - "getrandom 0.3.3", - "hmac", - "indexmap 2.9.0", - "lzma-rs", - "memchr", - "pbkdf2", - "sha1", - "time", - "xz2", - "zeroize", - "zopfli", - "zstd", -] - -[[package]] -name = "zopfli" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfc5ee405f504cd4984ecc6f14d02d55cfda60fa4b689434ef4102aae150cd7" -dependencies = [ - "bumpalo", - "crc32fast", - "log", - "simd-adler32", -] - -[[package]] -name = "zstd" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" -dependencies = [ - "cc", - "pkg-config", -] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/Cargo.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/Cargo.toml deleted file mode 100644 index 89dd7a67..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -name = "tauri-plugin-appload" -version = "0.1.0" -authors = [ "CuriousCorrelation" ] -description = "A Tauri plugin to download and load web app into WebView" -edition = "2021" -rust-version = "1.77.2" -exclude = ["/examples", "/webview-dist", "/webview-src", "/node_modules"] -links = "tauri-plugin-appload" - -[dependencies] -tauri = { version = "2.0.6" } -serde = "1.0" -serde_json = { version = "1", features = [] } -thiserror = { version = "2.0.3", features = [] } -url = { version = "2.5.3", features = ["serde"] } -reqwest = { version = "0.12.9", features = ["json"] } -zip = { version = "2.2.0", features = [] } -tokio = { version = "1.41.1", features = [] } -mime-infer = { version = "3.0.0", features = [] } -regex = { version = "1.11.1", features = [] } -tracing = "0.1.41" -dashmap = { version = "6.1.0" } -flate2 = { version = "1.0.35" } -chrono = { version = "0.4.38", features = ["serde"] } -base64 = "0.22.1" -blake3 = { version = "1.5.4", features = ["serde"] } -ed25519-dalek = { version = "2.1.1", features = ["rand_core", "serde"] } -hex = "0.4.3" -lru = "0.12.5" -sysinfo = "0.34.2" -humantime-serde = "1.1.1" -futures = "0.3.31" -mime_guess = "2.0.5" -rayon = "1.10.0" -hex_color = "3.0.0" -dunce = "1.0.5" -bon = "3.6.3" - -[build-dependencies] -tauri-plugin = { version = "2.0.1", features = ["build"] } - -[target.'cfg(target_os = "macos")'.dependencies] -cocoa = "0.26.0" -objc = "0.2.7" -rand = "0.8.5" - -[target.'cfg(target_os = "windows")'.dependencies] -windows = { version = "0.58.0", features = [ - "Win32_Graphics_Dwm", - "Win32_Foundation", - "Win32_UI_Controls", -] } -winver = "1.0.0" diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/LICENSE.md b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/LICENSE.md deleted file mode 100644 index 2b0b5d59..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 - CuriousCorrelation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/README.md b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/README.md deleted file mode 100644 index 11fb364a..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# Tauri Plugin: AppLoad - -> A Tauri plugin for downloading and loading web app bundles into WebView. - -
- -![GitHub License MIT](https://img.shields.io/github/license/CuriousCorrelation/tauri-plugin-appload) -![Tauri 2.0](https://img.shields.io/badge/Tauri-2.0-blue) -[![Rust](https://img.shields.io/badge/Rust-1.77.2+-orange)](https://www.rust-lang.org) - -
- -## Features - -- 🦀 Blazingly fast! -- Download and load web app bundles from remote servers -- Secure verification using `ed25519` + `blake3` -- Caching with hot/cold storage strategy -- Custom URI scheme for isolated app loading - -## Installation - -> [!IMPORTANT] -> This plugin requires Tauri 2.0 or later. - -Add the plugin to your project by installing directly from GitHub: - -```toml -[dependencies] -tauri-plugin-appload = { git = "https://github.com/CuriousCorrelation/tauri-plugin-appload" } -``` - -``` json -"dependencies": { - "@CuriousCorrelation/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload" -} -``` - -## Quick Start - -### Rust - -```rust -fn main() { - tauri::Builder::default() - .plugin(tauri_plugin_appload::init()) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} -``` - -### JavaScript/TypeScript - -```typescript -import { download, load } from '@CuriousCorrelation/plugin-appload' - -// Download a bundle -const { bundleName } = await download({ - serverUrl: "https://example.com" -}) - -// Load the bundle in a new window -await load({ - bundleName, - window: { - title: "My App", - width: 800, - height: 600 - } -}) -``` - -## Configuration - -> [!NOTE] -> The plugin uses sensible defaults but can be customized via configuration. - -| Option | Description | Default | -|--------|-------------|---------| -| `api.serverUrl` | Bundle server URL | `http://localhost:3200` | -| `cache.maxSize` | Maximum cache size | `100MB` | -| `cache.filesTtl` | File time-to-live | `1 hour` | -| `storage.maxBundleSize` | Maximum bundle size | `50MB` | - -## Permissions - -The plugin defines the following permissions: - -- `allow-download`: Enable bundle downloads -- `allow-load`: Enable bundle loading -- `deny-download`: Disable bundle downloads -- `deny-load`: Disable bundle loading - -## Development - -Requirements: -- Rust 1.77.2 or later -- Node.js 18 or later -- pnpm - -## License - -Code: (c) 2025 - CuriousCorrelation - -MIT or MIT/Apache 2.0 where applicable. diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/build.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/build.rs deleted file mode 100644 index 3412832e..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -const COMMANDS: &[&str] = &["load", "download", "clear", "close", "remove"]; - -fn main() { - tauri_plugin::Builder::new(COMMANDS) - .android_path("android") - .ios_path("ios") - .build(); -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.lock b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.lock deleted file mode 100644 index 1ac717db..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.lock +++ /dev/null @@ -1,140 +0,0 @@ -{ - "nodes": { - "devenv": { - "locked": { - "dir": "src/modules", - "lastModified": 1733525154, - "owner": "cachix", - "repo": "devenv", - "rev": "d74232153d60ccdeba6f41eec8ce8b2be0b33ac6", - "type": "github" - }, - "original": { - "dir": "src/modules", - "owner": "cachix", - "repo": "devenv", - "type": "github" - } - }, - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src" - }, - "locked": { - "lastModified": 1733553297, - "owner": "nix-community", - "repo": "fenix", - "rev": "8519a70a1a81db2dd22316f94c25d7510218169e", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1765121682, - "owner": "edolstra", - "repo": "flake-compat", - "rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, - "git-hooks": { - "inputs": { - "flake-compat": "flake-compat", - "gitignore": "gitignore", - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1765911976, - "owner": "cachix", - "repo": "git-hooks.nix", - "rev": "b68b780b69702a090c8bb1b973bab13756cc7a27", - "type": "github" - }, - "original": { - "owner": "cachix", - "repo": "git-hooks.nix", - "type": "github" - } - }, - "gitignore": { - "inputs": { - "nixpkgs": [ - "git-hooks", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1762808025, - "owner": "hercules-ci", - "repo": "gitignore.nix", - "rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "gitignore.nix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1733330745, - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "2f9d395f057a50f8076f633c10519035fce8d773", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "devenv": "devenv", - "fenix": "fenix", - "git-hooks": "git-hooks", - "nixpkgs": "nixpkgs", - "pre-commit-hooks": [ - "git-hooks" - ] - } - }, - "rust-analyzer-src": { - "flake": false, - "locked": { - "lastModified": 1733499879, - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "17720acb90105cbd736d3e78d736eb5d41af89a5", - "type": "github" - }, - "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.nix b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.nix deleted file mode 100644 index 1e49dd78..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.nix +++ /dev/null @@ -1,90 +0,0 @@ -{ pkgs, lib, config, inputs, ... }: - -let - rosettaPkgs = - if pkgs.stdenv.isDarwin && pkgs.stdenv.isAarch64 - then pkgs.pkgsx86_64Darwin - else pkgs; - - darwinPackages = with pkgs; [ - darwin.apple_sdk.frameworks.Security - darwin.apple_sdk.frameworks.CoreServices - darwin.apple_sdk.frameworks.CoreFoundation - darwin.apple_sdk.frameworks.Foundation - darwin.apple_sdk.frameworks.AppKit - darwin.apple_sdk.frameworks.WebKit - ]; - - linuxPackages = with pkgs; [ - libsoup_3 - webkitgtk_4_1 - librsvg - libappindicator - libayatana-appindicator - ]; - -in { - packages = with pkgs; [ - git - nodejs_22 - nodePackages_latest.typescript-language-server - nodePackages_latest.vue-language-server - cargo-edit - ] ++ lib.optionals pkgs.stdenv.isDarwin darwinPackages - ++ lib.optionals pkgs.stdenv.isLinux linuxPackages; - - env = { - APP_GREET = "Hi!"; - } // lib.optionalAttrs pkgs.stdenv.isLinux { - LD_LIBRARY_PATH = lib.makeLibraryPath [ - pkgs.libappindicator - pkgs.libayatana-appindicator - ]; - } // lib.optionalAttrs pkgs.stdenv.isDarwin { - # Place to put macOS-specific environment variables - }; - - scripts = { - hello.exec = "echo hello from $APP_GREET"; - e.exec = "emacs"; - }; - - enterShell = '' - git --version - ${lib.optionalString pkgs.stdenv.isDarwin '' - # Place to put macOS-specific shell initialization - ''} - ${lib.optionalString pkgs.stdenv.isLinux '' - # Place to put Linux-specific shell initialization - ''} - ''; - - enterTest = '' - echo "Running tests" - ''; - - dotenv.enable = true; - - languages = { - typescript.enable = true; - javascript = { - enable = true; - pnpm.enable = true; - npm.enable = true; - }; - rust = { - enable = true; - channel = "nightly"; - components = [ - "rustc" - "cargo" - "clippy" - "rustfmt" - "rust-analyzer" - "llvm-tools-preview" - "rust-src" - "rustc-codegen-cranelift-preview" - ]; - }; - }; -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.yaml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.yaml deleted file mode 100644 index 9ee9ba34..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/devenv.yaml +++ /dev/null @@ -1,23 +0,0 @@ -# yaml-language-server: $schema=https://devenv.sh/devenv.schema.json -inputs: - # For NodeJS-22 and above - nixpkgs: - url: github:NixOS/nixpkgs/nixpkgs-unstable - # nixpkgs: - # url: github:cachix/devenv-nixpkgs/rolling - fenix: - url: github:nix-community/fenix - inputs: - nixpkgs: - follows: nixpkgs - -# If you're using non-OSS software, you can set allowUnfree to true. -allowUnfree: true - -# If you're willing to use a package that's vulnerable -# permittedInsecurePackages: -# - "openssl-1.1.1w" - -# If you have more than one devenv you can merge them -#imports: -# - ./backend diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.cjs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.cjs deleted file mode 100644 index aa575c49..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.cjs +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; - -var core = require('@tauri-apps/api/core'); - -async function download(options) { - return await core.invoke('plugin:appload|download', { options }); -} -async function load(options) { - return await core.invoke('plugin:appload|load', { options }); -} -async function close(options) { - return await core.invoke('plugin:appload|close', { options }); -} -async function remove(options) { - return await core.invoke('plugin:appload|remove', { options }); -} -async function clear() { - return await core.invoke('plugin:appload|clear'); -} - -exports.clear = clear; -exports.close = close; -exports.download = download; -exports.load = load; -exports.remove = remove; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.d.ts b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.d.ts deleted file mode 100644 index 1d2f6c2b..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.d.ts +++ /dev/null @@ -1,65 +0,0 @@ -export interface DownloadOptions { - serverUrl: string; -} -export interface DownloadResponse { - success: boolean; - bundleName: string; - serverUrl: string; - version: string; -} -export interface WindowOptions { - title?: string; - width?: number; - height?: number; - resizable?: boolean; -} -export interface LoadOptions { - bundleName: string; - /** - * Optional host override for the webview URL. On web, org context comes from - * window.location.hostname (acme.hoppscotch.io). On desktop, the webview URL is - * normally app://{bundleName}/ which always returns the same hostname. Passing a host - * creates the webview at app://{host}/ instead, so the JS can read - * window.location.hostname and get org context the same way. - * - * When provided, the webview will be loaded with `app://{host}/` instead of - * `app://{bundleName}/`. This enables cloud-for-orgs support where the same - * bundle serves multiple organization subdomains. - * - * The host will be sanitized (dots become underscores) for URL compatibility. - * The JavaScript bundle can read `window.location.hostname` to determine - * the organization context. - * - * @example - * // Load Hoppscotch bundle as acme.hoppscotch.io - * load({ bundleName: "Hoppscotch", host: "acme.hoppscotch.io" }) - * // Results in: window.location.hostname === "acme_hoppscotch_io" - */ - host?: string; - inline?: boolean; - window?: WindowOptions; -} -export interface LoadResponse { - success: boolean; - windowLabel: string; -} -export interface CloseOptions { - windowLabel: string; -} -export interface CloseResponse { - success: boolean; -} -export interface RemoveOptions { - bundleName: string; - serverUrl: string; -} -export interface RemoveResponse { - success: boolean; - bundleName: string; -} -export declare function download(options: DownloadOptions): Promise; -export declare function load(options: LoadOptions): Promise; -export declare function close(options: CloseOptions): Promise; -export declare function remove(options: RemoveOptions): Promise; -export declare function clear(): Promise; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.d.ts.map b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.d.ts.map deleted file mode 100644 index 3c7dafd9..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../guest-js/index.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB;;;;;;;;;;;;;;;;;;;OAmBG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAElF;AAED,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAEtE;AAED,wBAAsB,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAEzE;AAED,wBAAsB,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC,CAE5E;AAED,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3C"} \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.js b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.js deleted file mode 100644 index 5dbd5b7e..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/dist-js/index.js +++ /dev/null @@ -1,19 +0,0 @@ -import { invoke } from '@tauri-apps/api/core'; - -async function download(options) { - return await invoke('plugin:appload|download', { options }); -} -async function load(options) { - return await invoke('plugin:appload|load', { options }); -} -async function close(options) { - return await invoke('plugin:appload|close', { options }); -} -async function remove(options) { - return await invoke('plugin:appload|remove', { options }); -} -async function clear() { - return await invoke('plugin:appload|clear'); -} - -export { clear, close, download, load, remove }; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/.gitignore b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/.gitignore deleted file mode 100644 index a547bf36..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local - -# Editor directories and files -.vscode/* -!.vscode/extensions.json -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/.vscode/extensions.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/.vscode/extensions.json deleted file mode 100644 index 61343e9b..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/.vscode/extensions.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "recommendations": [ - "svelte.svelte-vscode", - "tauri-apps.tauri-vscode", - "rust-lang.rust-analyzer" - ] -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/README.md b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/README.md deleted file mode 100644 index 72726a1f..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Svelte + Vite - -This template should help get you started developing with Tauri and Svelte in Vite. - -## Recommended IDE Setup - -[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer). - diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/index.html b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/index.html deleted file mode 100644 index fad1c5d9..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - Tauri + Svelte - - - -
- - - diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/jsconfig.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/jsconfig.json deleted file mode 100644 index ee5e92f2..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/jsconfig.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "compilerOptions": { - "moduleResolution": "Node", - "target": "ESNext", - "module": "ESNext", - /** - * svelte-preprocess cannot figure out whether you have - * a value or a type, so tell TypeScript to enforce using - * `import type` instead of `import` for Types. - */ - "importsNotUsedAsValues": "error", - "isolatedModules": true, - "resolveJsonModule": true, - /** - * To have warnings / errors of the Svelte compiler at the - * correct position, enable source maps by default. - */ - "sourceMap": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "baseUrl": ".", - /** - * Typecheck JS in `.svelte` and `.js` files by default. - * Disable this if you'd like to use dynamic types. - */ - "checkJs": true - }, - /** - * Use global.d.ts instead of compilerOptions.types - * to avoid limiting type declarations. - */ - "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/package.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/package.json deleted file mode 100644 index f4d0dade..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "tauri-app", - "private": true, - "version": "0.1.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "vite build", - "preview": "vite preview", - "tauri": "tauri" - }, - "dependencies": { - "@tauri-apps/api": "2.1.1", - "tauri-plugin-appload-api": "file:../../" - }, - "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^1.0.1", - "svelte": "^3.49.0", - "vite": "^3.0.2", - "@tauri-apps/cli": "^2.0.0-alpha.17" - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/svelte.svg b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/svelte.svg deleted file mode 100644 index c5e08481..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/svelte.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/tauri.svg b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/tauri.svg deleted file mode 100644 index 31b62c92..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/tauri.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/vite.svg b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/vite.svg deleted file mode 100644 index e7b8dfb1..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/.gitignore b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/.gitignore deleted file mode 100644 index f4dfb82b..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ - diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/Cargo.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/Cargo.toml deleted file mode 100644 index 5672cb59..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "tauri-app" -version = "0.1.0" -description = "A Tauri App" -authors = ["you"] -license = "" -repository = "" -edition = "2021" -rust-version = "1.77.2" - -[lib] -name = "tauri_app_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[build-dependencies] -tauri-build = { version = "2.0.1", default-features = false } - -[dependencies] -tauri = { version = "2.0.6" } -tauri-plugin-appload = { path = "../../../" } - diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/build.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/build.rs deleted file mode 100644 index 795b9b7c..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/build.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - tauri_build::build() -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/capabilities/default.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/capabilities/default.json deleted file mode 100644 index 3076a249..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/capabilities/default.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "$schema": "../gen/schemas/desktop-schema.json", - "identifier": "default", - "description": "enables the default permissions", - "windows": [ - "main" - ], - "permissions": [ - "core:default", - "appload:default" - ] -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/128x128.png b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/128x128.png deleted file mode 100644 index 77e7d233..00000000 Binary files a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/128x128.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/128x128@2x.png b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/128x128@2x.png deleted file mode 100644 index 0f7976f1..00000000 Binary files a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/128x128@2x.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/32x32.png b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/32x32.png deleted file mode 100644 index 98fda06f..00000000 Binary files a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/32x32.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.icns b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.icns deleted file mode 100644 index 29d6685a..00000000 Binary files a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.icns and /dev/null differ diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.ico b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.ico deleted file mode 100644 index 06c23c82..00000000 Binary files a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.ico and /dev/null differ diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.png b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.png deleted file mode 100644 index d1756ce4..00000000 Binary files a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/icons/icon.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/src/lib.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/src/lib.rs deleted file mode 100644 index 2650a627..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands -#[tauri::command] -fn greet(name: &str) -> String { - format!("Hello, {}! You've been greeted from Rust!", name) -} - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - tauri::Builder::default() - .invoke_handler(tauri::generate_handler![greet]) - .plugin(tauri_plugin_appload::init()) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/src/main.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/src/main.rs deleted file mode 100644 index 455963ee..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/src/main.rs +++ /dev/null @@ -1,6 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -fn main() { - tauri_app_lib::run(); -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/tauri.conf.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/tauri.conf.json deleted file mode 100644 index 72ebf400..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src-tauri/tauri.conf.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "productName": "tauri-app", - "version": "0.1.0", - "identifier": "com.tauri.dev", - "build": { - "beforeDevCommand": "pnpm dev", - "beforeBuildCommand": "pnpm build", - "devUrl": "http://localhost:1420", - "frontendDist": "../dist" - }, - "app": { - "withGlobalTauri": false, - "security": { - "csp": null - }, - "windows": [ - { - "fullscreen": false, - "height": 600, - "resizable": true, - "title": "tauri-app", - "width": 800 - } - ] - }, - "bundle": { - "active": true, - "targets": "all", - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ] - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/App.svelte b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/App.svelte deleted file mode 100644 index 7e975903..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/App.svelte +++ /dev/null @@ -1,54 +0,0 @@ - - -
-

Welcome to Tauri!

- - - -

- Click on the Tauri, Vite, and Svelte logos to learn more. -

- -
- -
- -
- -
{@html response}
-
- -
- - diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/lib/Greet.svelte b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/lib/Greet.svelte deleted file mode 100644 index 41e901b5..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/lib/Greet.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - -
-
- - -
-

{greetMsg}

-
- diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/main.js b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/main.js deleted file mode 100644 index 6b4e1a96..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/main.js +++ /dev/null @@ -1,8 +0,0 @@ -import "./style.css"; -import App from "./App.svelte"; - -const app = new App({ - target: document.getElementById("app"), -}); - -export default app; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/style.css b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/style.css deleted file mode 100644 index c0f9e3bc..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/style.css +++ /dev/null @@ -1,102 +0,0 @@ -:root { - font-family: Inter, Avenir, Helvetica, Arial, sans-serif; - font-size: 16px; - line-height: 24px; - font-weight: 400; - - color: #0f0f0f; - background-color: #f6f6f6; - - font-synthesis: none; - text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - -webkit-text-size-adjust: 100%; -} - -.container { - margin: 0; - padding-top: 10vh; - display: flex; - flex-direction: column; - justify-content: center; - text-align: center; -} - -.logo { - height: 6em; - padding: 1.5em; - will-change: filter; - transition: 0.75s; -} - -.logo.tauri:hover { - filter: drop-shadow(0 0 2em #24c8db); -} - -.row { - display: flex; - justify-content: center; -} - -a { - font-weight: 500; - color: #646cff; - text-decoration: inherit; -} - -a:hover { - color: #535bf2; -} - -h1 { - text-align: center; -} - -input, -button { - border-radius: 8px; - border: 1px solid transparent; - padding: 0.6em 1.2em; - font-size: 1em; - font-weight: 500; - font-family: inherit; - color: #0f0f0f; - background-color: #ffffff; - transition: border-color 0.25s; - box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); -} - -button { - cursor: pointer; -} - -button:hover { - border-color: #396cd8; -} - -input, -button { - outline: none; -} - -#greet-input { - margin-right: 5px; -} - -@media (prefers-color-scheme: dark) { - :root { - color: #f6f6f6; - background-color: #2f2f2f; - } - - a:hover { - color: #24c8db; - } - - input, - button { - color: #ffffff; - background-color: #0f0f0f98; - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/vite-env.d.ts b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/vite-env.d.ts deleted file mode 100644 index 4078e747..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/src/vite-env.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -/// -/// diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/vite.config.js b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/vite.config.js deleted file mode 100644 index 3b85afb9..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app/vite.config.js +++ /dev/null @@ -1,24 +0,0 @@ -import { defineConfig } from "vite"; -import { svelte } from "@sveltejs/vite-plugin-svelte"; - -const host = process.env.TAURI_DEV_HOST; - -// https://vitejs.dev/config/ -export default defineConfig({ - plugins: [svelte()], - - // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` - // prevent vite from obscuring rust errors - clearScreen: false, - // tauri expects a fixed port, fail if that port is not available - server: { - host: host || false, - port: 1420, - strictPort: true, - hmr: host ? { - protocol: 'ws', - host, - port: 1421 - } : undefined, - }, -}) diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/guest-js/index.ts b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/guest-js/index.ts deleted file mode 100644 index 668513bd..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/guest-js/index.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { invoke } from '@tauri-apps/api/core' - -export interface DownloadOptions { - serverUrl: string -} - -export interface DownloadResponse { - success: boolean - bundleName: string - serverUrl: string - version: string -} - -export interface WindowOptions { - title?: string - width?: number - height?: number - resizable?: boolean -} - -export interface LoadOptions { - bundleName: string - /** - * Optional host override for the webview URL. On web, org context comes from - * window.location.hostname (acme.hoppscotch.io). On desktop, the webview URL is - * normally app://{bundleName}/ which always returns the same hostname. Passing a host - * creates the webview at app://{host}/ instead, so the JS can read - * window.location.hostname and get org context the same way. - * - * When provided, the webview will be loaded with `app://{host}/` instead of - * `app://{bundleName}/`. This enables cloud-for-orgs support where the same - * bundle serves multiple organization subdomains. - * - * The host will be sanitized (dots become underscores) for URL compatibility. - * The JavaScript bundle can read `window.location.hostname` to determine - * the organization context. - * - * @example - * // Load Hoppscotch bundle as acme.hoppscotch.io - * load({ bundleName: "Hoppscotch", host: "acme.hoppscotch.io" }) - * // Results in: window.location.hostname === "acme_hoppscotch_io" - */ - host?: string; - inline?: boolean; - window?: WindowOptions; -} - -export interface LoadResponse { - success: boolean - windowLabel: string -} - -export interface CloseOptions { - windowLabel: string -} - -export interface CloseResponse { - success: boolean -} - -export interface RemoveOptions { - bundleName: string - serverUrl: string -} - -export interface RemoveResponse { - success: boolean - bundleName: string -} - -export async function download(options: DownloadOptions): Promise { - return await invoke('plugin:appload|download', { options }) -} - -export async function load(options: LoadOptions): Promise { - return await invoke('plugin:appload|load', { options }) -} - -export async function close(options: CloseOptions): Promise { - return await invoke('plugin:appload|close', { options }) -} - -export async function remove(options: RemoveOptions): Promise { - return await invoke('plugin:appload|remove', { options }) -} - -export async function clear(): Promise { - return await invoke('plugin:appload|clear') -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/package.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/package.json deleted file mode 100644 index 44e167a5..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "@CuriousCorrelation/plugin-appload", - "version": "0.1.0", - "author": "CuriousCorrelation", - "description": "A Tauri plugin for downloading and loading web app bundles into WebView.", - "type": "module", - "types": "./dist-js/index.d.ts", - "main": "./dist-js/index.cjs", - "module": "./dist-js/index.js", - "exports": { - "types": "./dist-js/index.d.ts", - "import": "./dist-js/index.js", - "require": "./dist-js/index.cjs" - }, - "files": [ - "dist-js", - "README.md" - ], - "scripts": { - "build": "tsc && rollup -c", - "prepublishOnly": "pnpm build", - "pretest": "pnpm build" - }, - "dependencies": { - "@tauri-apps/api": "2.9.1" - }, - "devDependencies": { - "@rollup/plugin-typescript": "^12.3.0", - "rollup": "^4.59.0", - "tslib": "^2.8.1", - "typescript": "5.9.3" - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/clear.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/clear.toml deleted file mode 100644 index 83de1819..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/clear.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-clear" -description = "Enables the clear command without any pre-configured scope." -commands.allow = ["clear"] - -[[permission]] -identifier = "deny-clear" -description = "Denies the clear command without any pre-configured scope." -commands.deny = ["clear"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/close.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/close.toml deleted file mode 100644 index fad12d15..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/close.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-close" -description = "Enables the close command without any pre-configured scope." -commands.allow = ["close"] - -[[permission]] -identifier = "deny-close" -description = "Denies the close command without any pre-configured scope." -commands.deny = ["close"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/download.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/download.toml deleted file mode 100644 index 896b30ce..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/download.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-download" -description = "Enables the download command without any pre-configured scope." -commands.allow = ["download"] - -[[permission]] -identifier = "deny-download" -description = "Denies the download command without any pre-configured scope." -commands.deny = ["download"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/load.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/load.toml deleted file mode 100644 index f6e47ad8..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/load.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-load" -description = "Enables the load command without any pre-configured scope." -commands.allow = ["load"] - -[[permission]] -identifier = "deny-load" -description = "Denies the load command without any pre-configured scope." -commands.deny = ["load"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/ping.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/ping.toml deleted file mode 100644 index 1d135880..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/ping.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-ping" -description = "Enables the ping command without any pre-configured scope." -commands.allow = ["ping"] - -[[permission]] -identifier = "deny-ping" -description = "Denies the ping command without any pre-configured scope." -commands.deny = ["ping"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/remove.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/remove.toml deleted file mode 100644 index 9c9791eb..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/commands/remove.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-remove" -description = "Enables the remove command without any pre-configured scope." -commands.allow = ["remove"] - -[[permission]] -identifier = "deny-remove" -description = "Denies the remove command without any pre-configured scope." -commands.deny = ["remove"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/reference.md b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/reference.md deleted file mode 100644 index a62dce5c..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/autogenerated/reference.md +++ /dev/null @@ -1,177 +0,0 @@ -## Default Permission - -Default permissions for AppLoad plugin - -#### This default permission set includes the following: - -- `allow-load` -- `allow-download` -- `allow-clear` -- `allow-close` -- `allow-remove` - -## Permission Table - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IdentifierDescription
- -`appload:allow-clear` - - - -Enables the clear command without any pre-configured scope. - -
- -`appload:deny-clear` - - - -Denies the clear command without any pre-configured scope. - -
- -`appload:allow-close` - - - -Enables the close command without any pre-configured scope. - -
- -`appload:deny-close` - - - -Denies the close command without any pre-configured scope. - -
- -`appload:allow-download` - - - -Enables the download command without any pre-configured scope. - -
- -`appload:deny-download` - - - -Denies the download command without any pre-configured scope. - -
- -`appload:allow-load` - - - -Enables the load command without any pre-configured scope. - -
- -`appload:deny-load` - - - -Denies the load command without any pre-configured scope. - -
- -`appload:allow-ping` - - - -Enables the ping command without any pre-configured scope. - -
- -`appload:deny-ping` - - - -Denies the ping command without any pre-configured scope. - -
- -`appload:allow-remove` - - - -Enables the remove command without any pre-configured scope. - -
- -`appload:deny-remove` - - - -Denies the remove command without any pre-configured scope. - -
diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/default.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/default.toml deleted file mode 100644 index 2bb1ae22..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/default.toml +++ /dev/null @@ -1,3 +0,0 @@ -[default] -description = "Default permissions for AppLoad plugin" -permissions = ["allow-load", "allow-download", "allow-clear", "allow-close", "allow-remove"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/schemas/schema.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/schemas/schema.json deleted file mode 100644 index 4381a8e4..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/permissions/schemas/schema.json +++ /dev/null @@ -1,378 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "PermissionFile", - "description": "Permission file that can define a default permission, a set of permissions or a list of inlined permissions.", - "type": "object", - "properties": { - "default": { - "description": "The default permission set for the plugin", - "anyOf": [ - { - "$ref": "#/definitions/DefaultPermission" - }, - { - "type": "null" - } - ] - }, - "set": { - "description": "A list of permissions sets defined", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - } - }, - "definitions": { - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - }, - "description": { - "description": "Human-readable description of what the permission does. Tauri convention is to use `

` headings in markdown content for Tauri documentation generation purposes.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "description": { - "description": "Human-readable description of what the permission does. Tauri internal convention is to use `

` headings in markdown content for Tauri documentation generation purposes.", - "type": [ - "string", - "null" - ] - }, - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "platforms": { - "description": "Target platforms this permission applies. By default all platforms are affected by this permission.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Target" - } - } - } - }, - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", - "type": "object", - "properties": { - "allow": { - "description": "Allowed command.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "deny": { - "description": "Denied command, which takes priority.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "Scopes": { - "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```", - "type": "object", - "properties": { - "allow": { - "description": "Data that defines what is allowed by the scope.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - }, - "deny": { - "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "description": "Represents a null JSON value.", - "type": "null" - }, - { - "description": "Represents a [`bool`].", - "type": "boolean" - }, - { - "description": "Represents a valid ACL [`Number`].", - "allOf": [ - { - "$ref": "#/definitions/Number" - } - ] - }, - { - "description": "Represents a [`String`].", - "type": "string" - }, - { - "description": "Represents a list of other [`Value`]s.", - "type": "array", - "items": { - "$ref": "#/definitions/Value" - } - }, - { - "description": "Represents a map of [`String`] keys to [`Value`]s.", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Value" - } - } - ] - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Target": { - "description": "Platform target.", - "oneOf": [ - { - "description": "MacOS.", - "type": "string", - "enum": [ - "macOS" - ] - }, - { - "description": "Windows.", - "type": "string", - "enum": [ - "windows" - ] - }, - { - "description": "Linux.", - "type": "string", - "enum": [ - "linux" - ] - }, - { - "description": "Android.", - "type": "string", - "enum": [ - "android" - ] - }, - { - "description": "iOS.", - "type": "string", - "enum": [ - "iOS" - ] - } - ] - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "Enables the clear command without any pre-configured scope.", - "type": "string", - "const": "allow-clear", - "markdownDescription": "Enables the clear command without any pre-configured scope." - }, - { - "description": "Denies the clear command without any pre-configured scope.", - "type": "string", - "const": "deny-clear", - "markdownDescription": "Denies the clear command without any pre-configured scope." - }, - { - "description": "Enables the close command without any pre-configured scope.", - "type": "string", - "const": "allow-close", - "markdownDescription": "Enables the close command without any pre-configured scope." - }, - { - "description": "Denies the close command without any pre-configured scope.", - "type": "string", - "const": "deny-close", - "markdownDescription": "Denies the close command without any pre-configured scope." - }, - { - "description": "Enables the download command without any pre-configured scope.", - "type": "string", - "const": "allow-download", - "markdownDescription": "Enables the download command without any pre-configured scope." - }, - { - "description": "Denies the download command without any pre-configured scope.", - "type": "string", - "const": "deny-download", - "markdownDescription": "Denies the download command without any pre-configured scope." - }, - { - "description": "Enables the load command without any pre-configured scope.", - "type": "string", - "const": "allow-load", - "markdownDescription": "Enables the load command without any pre-configured scope." - }, - { - "description": "Denies the load command without any pre-configured scope.", - "type": "string", - "const": "deny-load", - "markdownDescription": "Denies the load command without any pre-configured scope." - }, - { - "description": "Enables the ping command without any pre-configured scope.", - "type": "string", - "const": "allow-ping", - "markdownDescription": "Enables the ping command without any pre-configured scope." - }, - { - "description": "Denies the ping command without any pre-configured scope.", - "type": "string", - "const": "deny-ping", - "markdownDescription": "Denies the ping command without any pre-configured scope." - }, - { - "description": "Enables the remove command without any pre-configured scope.", - "type": "string", - "const": "allow-remove", - "markdownDescription": "Enables the remove command without any pre-configured scope." - }, - { - "description": "Denies the remove command without any pre-configured scope.", - "type": "string", - "const": "deny-remove", - "markdownDescription": "Denies the remove command without any pre-configured scope." - }, - { - "description": "Default permissions for AppLoad plugin\n#### This default permission set includes:\n\n- `allow-load`\n- `allow-download`\n- `allow-clear`\n- `allow-close`\n- `allow-remove`", - "type": "string", - "const": "default", - "markdownDescription": "Default permissions for AppLoad plugin\n#### This default permission set includes:\n\n- `allow-load`\n- `allow-download`\n- `allow-clear`\n- `allow-close`\n- `allow-remove`" - } - ] - } - } -} \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/pnpm-lock.yaml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/pnpm-lock.yaml deleted file mode 100644 index 5cf88486..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/pnpm-lock.yaml +++ /dev/null @@ -1,362 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@tauri-apps/api': - specifier: 2.9.1 - version: 2.9.1 - devDependencies: - '@rollup/plugin-typescript': - specifier: ^12.3.0 - version: 12.3.0(rollup@4.54.0)(tslib@2.8.1)(typescript@5.9.3) - rollup: - specifier: ^4.54.0 - version: 4.54.0 - tslib: - specifier: ^2.8.1 - version: 2.8.1 - typescript: - specifier: 5.9.3 - version: 5.9.3 - -packages: - - '@rollup/plugin-typescript@12.3.0': - resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.14.0||^3.0.0||^4.0.0 - tslib: '*' - typescript: '>=3.7.0' - peerDependenciesMeta: - rollup: - optional: true - tslib: - optional: true - - '@rollup/pluginutils@5.3.0': - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/rollup-android-arm-eabi@4.54.0': - resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.54.0': - resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.54.0': - resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.54.0': - resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.54.0': - resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.54.0': - resolution: {integrity: sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.54.0': - resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.54.0': - resolution: {integrity: sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.54.0': - resolution: {integrity: sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.54.0': - resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.54.0': - resolution: {integrity: sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.54.0': - resolution: {integrity: sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.54.0': - resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.54.0': - resolution: {integrity: sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.54.0': - resolution: {integrity: sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.54.0': - resolution: {integrity: sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.54.0': - resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openharmony-arm64@4.54.0': - resolution: {integrity: sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.54.0': - resolution: {integrity: sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.54.0': - resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.54.0': - resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.54.0': - resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==} - cpu: [x64] - os: [win32] - - '@tauri-apps/api@2.9.1': - resolution: {integrity: sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - - rollup@4.54.0: - resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - -snapshots: - - '@rollup/plugin-typescript@12.3.0(rollup@4.54.0)(tslib@2.8.1)(typescript@5.9.3)': - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.54.0) - resolve: 1.22.11 - typescript: 5.9.3 - optionalDependencies: - rollup: 4.54.0 - tslib: 2.8.1 - - '@rollup/pluginutils@5.3.0(rollup@4.54.0)': - dependencies: - '@types/estree': 1.0.8 - estree-walker: 2.0.2 - picomatch: 4.0.3 - optionalDependencies: - rollup: 4.54.0 - - '@rollup/rollup-android-arm-eabi@4.54.0': - optional: true - - '@rollup/rollup-android-arm64@4.54.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.54.0': - optional: true - - '@rollup/rollup-darwin-x64@4.54.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.54.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.54.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.54.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.54.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.54.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.54.0': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.54.0': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.54.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.54.0': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.54.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.54.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.54.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.54.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.54.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.54.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.54.0': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.54.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.54.0': - optional: true - - '@tauri-apps/api@2.9.1': {} - - '@types/estree@1.0.8': {} - - estree-walker@2.0.2: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - path-parse@1.0.7: {} - - picomatch@4.0.3: {} - - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - rollup@4.54.0: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.54.0 - '@rollup/rollup-android-arm64': 4.54.0 - '@rollup/rollup-darwin-arm64': 4.54.0 - '@rollup/rollup-darwin-x64': 4.54.0 - '@rollup/rollup-freebsd-arm64': 4.54.0 - '@rollup/rollup-freebsd-x64': 4.54.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.54.0 - '@rollup/rollup-linux-arm-musleabihf': 4.54.0 - '@rollup/rollup-linux-arm64-gnu': 4.54.0 - '@rollup/rollup-linux-arm64-musl': 4.54.0 - '@rollup/rollup-linux-loong64-gnu': 4.54.0 - '@rollup/rollup-linux-ppc64-gnu': 4.54.0 - '@rollup/rollup-linux-riscv64-gnu': 4.54.0 - '@rollup/rollup-linux-riscv64-musl': 4.54.0 - '@rollup/rollup-linux-s390x-gnu': 4.54.0 - '@rollup/rollup-linux-x64-gnu': 4.54.0 - '@rollup/rollup-linux-x64-musl': 4.54.0 - '@rollup/rollup-openharmony-arm64': 4.54.0 - '@rollup/rollup-win32-arm64-msvc': 4.54.0 - '@rollup/rollup-win32-ia32-msvc': 4.54.0 - '@rollup/rollup-win32-x64-gnu': 4.54.0 - '@rollup/rollup-win32-x64-msvc': 4.54.0 - fsevents: 2.3.3 - - supports-preserve-symlinks-flag@1.0.0: {} - - tslib@2.8.1: {} - - typescript@5.9.3: {} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/rollup.config.js b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/rollup.config.js deleted file mode 100644 index f420bfd2..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/rollup.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import { readFileSync } from 'fs' -import { join } from 'path' -import { cwd } from 'process' -import typescript from '@rollup/plugin-typescript' - -const pkg = JSON.parse(readFileSync(join(cwd(), 'package.json'), 'utf8')) - -export default { - input: 'guest-js/index.ts', - output: [ - { - file: pkg.exports.import, - format: 'esm' - }, - { - file: pkg.exports.require, - format: 'cjs' - } - ], - plugins: [ - typescript({ - tsconfig: './tsconfig.json', - declaration: true, - declarationDir: './dist-js' - }) - ], - external: [ - /^@tauri-apps\/api/, - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.peerDependencies || {}) - ] -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/client.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/client.rs deleted file mode 100644 index f95ec3ba..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/client.rs +++ /dev/null @@ -1,136 +0,0 @@ -use std::time::Duration; - -use reqwest::{Client as HttpClient, StatusCode, Url}; -use serde::de::DeserializeOwned; - -use crate::{BundleMetadata, PublicKeyInfo}; - -use super::{ - error::{ApiError, Result}, - model::ApiResponse, - API_VERSION, -}; - -const DEFAULT_TIMEOUT: Duration = Duration::from_secs(30); - -#[derive(Debug, Clone)] -pub struct ApiClient { - client: HttpClient, - base_url: Url, -} - -impl ApiClient { - pub fn new(base_url: impl AsRef) -> Result { - tracing::info!( - "Initializing ApiClient with base URL: {}", - base_url.as_ref() - ); - - let client = HttpClient::builder() - .timeout(DEFAULT_TIMEOUT) - .user_agent(format!( - "{}/{}", - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_VERSION") - )) - .build() - .map_err(ApiError::RequestFailed)?; - - Ok(Self { - client, - base_url: base_url.as_ref().parse().map_err(ApiError::InvalidUrl)?, - }) - } - - pub async fn list_key(&self) -> Result { - self.get(&format!("/api/{API_VERSION}/key")).await - } - - // NOTE: Right now this is fetching whatever is listed, - // but if there are more than one bundle per SH instance, - // this is where the changes should be made. - pub async fn fetch_bundle_metadata(&self, name: &str) -> Result { - tracing::debug!(bundle_name = name, "Fetching metadata"); - self.get(&format!("/api/{API_VERSION}/manifest")).await - } - - pub async fn download_bundle(&self, name: &str) -> Result> { - tracing::debug!(bundle_name = name, "Downloading bundle"); - let url = self.build_url(&format!("/api/{API_VERSION}/bundle"))?; - - let download_client = HttpClient::builder() - .timeout(10 * DEFAULT_TIMEOUT) - .user_agent(format!( - "{}/{}", - env!("CARGO_PKG_NAME"), - env!("CARGO_PKG_VERSION") - )) - .build() - .map_err(ApiError::RequestFailed)?; - - let response = download_client.get(url).send().await.map_err(|e| { - tracing::error!(bundle_name = name, error = %e, "Download request failed"); - ApiError::RequestFailed(e) - })?; - - match response.status() { - StatusCode::OK => { - tracing::debug!(bundle_name = name, "Download successful"); - Ok(response.bytes().await?.to_vec()) - } - StatusCode::NOT_FOUND => { - tracing::warn!(bundle_name = name, "Bundle not found"); - Err(ApiError::BundleNotFound(name.to_string())) - } - status => { - let error_text = response.text().await.unwrap_or_default(); - tracing::error!(bundle_name = name, status = %status, error = %error_text, "Download failed"); - Err(ApiError::from_status(status.as_u16(), error_text)) - } - } - } - - async fn get(&self, path: &str) -> Result { - tracing::debug!(path, "Sending GET request"); - let url = self.build_url(path)?; - - let response = self.client.get(url).send().await.map_err(|e| { - tracing::error!(path, error = %e, "Request failed"); - ApiError::RequestFailed(e) - })?; - - match response.status() { - StatusCode::OK => { - let api_response: ApiResponse = response.json().await?; - if api_response.success { - Ok(api_response.data) - } else { - Err(ApiError::ServerError { - status: 200, - message: api_response.error.unwrap_or_else(|| "Unknown error".into()), - }) - } - } - StatusCode::NOT_FOUND => Err(ApiError::BundleNotFound(path.to_string())), - status => { - let error_text = response.text().await.unwrap_or_default(); - tracing::error!(path, status = %status, error = %error_text, "Request failed"); - Err(ApiError::from_status(status.as_u16(), error_text)) - } - } - } - - fn build_url(&self, path: &str) -> Result { - let path_to_join = path.trim_start_matches('/'); - - let mut base = self.base_url.clone(); - if !base.path().ends_with('/') { - base.set_path(&format!("{}/", base.path())); - } - - base.join(path_to_join).map_err(|e| { - tracing::error!(path, error = %e, "Invalid URL"); - ApiError::InvalidUrl(e) - }) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/error.rs deleted file mode 100644 index cc538898..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/error.rs +++ /dev/null @@ -1,50 +0,0 @@ -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum ApiError { - #[error("HTTP request failed: {0}")] - RequestFailed(#[from] reqwest::Error), - - #[error("Invalid server response: {0}")] - InvalidResponse(String), - - #[error("Bundle not found: {0}")] - BundleNotFound(String), - - #[error("File not found: {0}")] - FileNotFound(String), - - #[error("Bundle verification failed: {0}")] - VerificationFailed(String), - - #[error("API error {status}: {message}")] - ServerError { status: u16, message: String }, - - #[error("Failed to parse response: {0}")] - ParseError(#[from] serde_json::Error), - - #[error("Server connection failed: {0}")] - ConnectionFailed(String), - - #[error("Invalid URL: {0}")] - InvalidUrl(#[from] url::ParseError), -} - -impl ApiError { - pub fn is_not_found(&self) -> bool { - matches!(self, Self::BundleNotFound(_)) - } - - pub fn is_verification_error(&self) -> bool { - matches!(self, Self::VerificationFailed(_)) - } - - pub fn from_status(status: u16, message: impl Into) -> Self { - Self::ServerError { - status, - message: message.into(), - } - } -} - -pub type Result = std::result::Result; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/mod.rs deleted file mode 100644 index ae83b93c..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -mod client; -mod error; -mod model; - -pub use client::ApiClient; -pub use error::ApiError; - -pub const API_VERSION: &str = "v1"; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/model.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/model.rs deleted file mode 100644 index e24cbecd..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/api/model.rs +++ /dev/null @@ -1,9 +0,0 @@ -use serde::Deserialize; - -#[derive(Debug, Clone, Deserialize)] -pub struct ApiResponse { - pub success: bool, - #[serde(default)] - pub error: Option, - pub data: T, -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/error.rs deleted file mode 100644 index e374e30f..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/error.rs +++ /dev/null @@ -1,27 +0,0 @@ -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum BundleError { - #[error("File not found in bundle: {0}")] - FileNotFound(String), - - #[error("Invalid bundle format: {0}")] - InvalidFormat(String), - - #[error("Zip error: {0}")] - Zip(#[from] zip::result::ZipError), - - #[error("Storage error: {0}")] - Storage(#[from] crate::storage::StorageError), - - #[error("API error: {0}")] - Api(#[from] crate::api::ApiError), - - #[error("Cache error: {0}")] - Cache(#[from] crate::cache::CacheError), - - #[error("Verification error: {0}")] - Verification(#[from] crate::verification::VerificationError), -} - -pub type Result = std::result::Result; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/loader.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/loader.rs deleted file mode 100644 index 30b4c255..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/loader.rs +++ /dev/null @@ -1,184 +0,0 @@ -use std::sync::Arc; - -use super::{BundleError, Result, VerifiedBundle}; -use crate::{ - api::ApiClient, - cache::CacheManager, - storage::{StorageError, StorageManager}, - verification::{BundleVerifier, KeyManager}, -}; - -#[derive(Debug)] -struct BundleInfo { - name: String, - content: Vec, -} - -pub struct BundleLoader { - cache: Arc, - storage: Arc, -} - -impl BundleLoader { - pub fn new(cache: Arc, storage: Arc) -> Self { - Self { cache, storage } - } - - pub async fn load_bundle(&self, server_url: &str) -> Result<()> { - tracing::info!(%server_url, "Starting bundle loading process"); - - let api_client = self.create_api_client(server_url)?; - let verifier = self.init_bundle_verifier(&api_client).await?; - let metadata = self.fetch_metadata(&api_client, server_url).await?; - - let bundle_info = match self.get_bundle_info(server_url, &metadata).await? { - Some(info) => info, - None => { - self.download_and_verify_bundle(server_url, &api_client, &verifier, &metadata) - .await? - } - }; - - self.store_verified_bundle(server_url, bundle_info, &metadata) - .await?; - - tracing::info!(%server_url, "Bundle loading completed successfully"); - Ok(()) - } - - async fn get_bundle_info( - &self, - server_url: &str, - metadata: &crate::BundleMetadata, - ) -> Result> { - match self.storage.get_bundle_entry(server_url).await? { - Some(entry) if entry.version == metadata.version => { - tracing::info!(%server_url, "Bundle version matches, checking cached version"); - match self.load_existing_bundle(&entry.bundle_name).await { - Ok(bundle) => { - tracing::info!(%server_url, "Successfully loaded cached bundle"); - Ok(Some(bundle)) - } - Err(BundleError::Storage(StorageError::BundleNotFound(_))) => { - tracing::info!(%server_url, "Cached bundle not found, will download fresh copy"); - Ok(None) - } - Err(e) => Err(e), - } - } - Some(entry) => { - tracing::info!( - %server_url, - local_version = %entry.version, - remote_version = %metadata.version, - "Version mismatch, downloading new bundle" - ); - self.storage - .delete_bundle(&entry.bundle_name, server_url) - .await?; - Ok(None) - } - None => { - tracing::info!(%server_url, "No existing bundle found, downloading"); - Ok(None) - } - } - } - - async fn store_verified_bundle( - &self, - server_url: &str, - bundle_info: BundleInfo, - metadata: &crate::BundleMetadata, - ) -> Result<()> { - let verified = VerifiedBundle::new(bundle_info.content, metadata.clone())?; - - tracing::info!(%server_url, "Caching verified bundle"); - Ok(self - .cache - .cache_bundle(&bundle_info.name, &verified) - .await?) - } - - fn create_api_client(&self, server_url: &str) -> Result { - Ok(ApiClient::new(server_url).map_err(|e| { - tracing::error!(%server_url, %e, "Failed to create API client"); - e - })?) - } - - async fn init_bundle_verifier(&self, api_client: &ApiClient) -> Result { - let key_manager = KeyManager::new(api_client.clone()).await.map_err(|e| { - tracing::error!(%e, "Failed to initialize key manager"); - e - })?; - - Ok(BundleVerifier::new(key_manager)) - } - - async fn fetch_metadata( - &self, - api_client: &ApiClient, - server_url: &str, - ) -> Result { - Ok(api_client - .fetch_bundle_metadata("latest") - .await - .map_err(|e| { - tracing::error!(%server_url, %e, "Failed to fetch bundle metadata"); - e - })?) - } - - async fn load_existing_bundle(&self, bundle_name: &str) -> Result { - tracing::info!(%bundle_name, "Loading bundle from storage"); - let content = self.storage.load_bundle(bundle_name).await?; - Ok(BundleInfo { - name: bundle_name.to_string(), - content, - }) - } - - async fn download_and_verify_bundle( - &self, - server_url: &str, - api_client: &ApiClient, - verifier: &BundleVerifier, - metadata: &crate::BundleMetadata, - ) -> Result { - tracing::info!(%server_url, "Downloading bundle"); - let content = api_client.download_bundle("latest").await.map_err(|e| { - tracing::error!(%server_url, %e, "Failed to download bundle"); - e - })?; - - tracing::info!(%server_url, "Verifying bundle integrity"); - verifier.verify_bundle(&content, metadata).await?; - - let verified = VerifiedBundle::new(content.clone(), metadata.clone())?; - let name = self.generate_bundle_name(server_url); - - tracing::info!(%server_url, "Storing verified bundle"); - self.storage - .store_bundle(&name, server_url, &metadata.version, &verified) - .await?; - - Ok(BundleInfo { name, content }) - } - - fn generate_bundle_name(&self, server_url: &str) -> String { - server_url - // NOTE: This is to fix capitalized URL not being served properly on Windows - .to_lowercase() - .split("://") - .nth(1) - .unwrap_or("unknown") - // Extract only the hostname part by splitting at the first '/' and taking the first part - .split('/') - .next() - .unwrap_or("unknown") - .replace(['/', '.', ':', '-'], "_") - .trim_end_matches('_') - .to_string() - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/mod.rs deleted file mode 100644 index 4e9ac155..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -mod error; -mod loader; -mod verified; - -pub use error::{BundleError, Result}; -pub use loader::BundleLoader; -pub use verified::VerifiedBundle; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/verified.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/verified.rs deleted file mode 100644 index 1452c786..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/bundle/verified.rs +++ /dev/null @@ -1,175 +0,0 @@ -use std::collections::HashMap; -use std::io::Cursor; - -use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; -use zip::ZipArchive; - -use super::Result; -use crate::bundle::BundleError; -use crate::verification::FileVerifier; -use crate::{BundleMetadata, Manifest}; - -#[derive(Debug)] -pub struct VerifiedFile { - pub path: String, - pub content: Vec, -} - -#[derive(Debug)] -pub struct VerifiedBundle { - pub content: Vec, - pub files: HashMap, - pub total_size: usize, -} - -impl VerifiedBundle { - pub fn new(content: Vec, metadata: BundleMetadata) -> super::Result { - tracing::info!( - "Creating new verified bundle with {} files", - metadata.manifest.files.len() - ); - - let mut archive = ZipArchive::new(Cursor::new(&content)).map_err(|e| { - tracing::error!(error = %e, "Failed to read ZIP archive"); - super::BundleError::InvalidFormat(format!("Failed to read ZIP archive: {}", e)) - })?; - - tracing::debug!("Extracting all files from archive"); - let file_contents: HashMap> = metadata - .manifest - .files - .iter() - .map(|file_entry| { - let path = file_entry.path.clone(); - tracing::debug!(path = %path, "Extracting file from archive"); - let mut content = Vec::new(); - match archive.by_name(&path) { - Ok(mut file) => { - if let Err(e) = std::io::Read::read_to_end(&mut file, &mut content) { - tracing::error!(path = %path, error = %e, "Failed to read file"); - Err(super::BundleError::InvalidFormat(format!( - "Failed to read {}: {}", - path, e - ))) - } else { - Ok((path, content)) - } - } - Err(e) => { - tracing::error!(path = %path, error = %e, "File not found in archive"); - Err(super::BundleError::InvalidFormat(format!( - "File not found in archive: {}", - path - ))) - } - } - }) - .collect::>()?; - - tracing::debug!("Verifying files in parallel"); - let verified_files: Result> = metadata - .manifest - .files - .par_iter() - .map(|file_entry| { - let content = file_contents.get(&file_entry.path).ok_or_else(|| { - super::BundleError::InvalidFormat(format!("Missing content for {}", file_entry.path)) - })?; - - tracing::debug!(path = %file_entry.path, "Verifying file"); - FileVerifier::verify(content, &file_entry.hash).map_err(|e| { - tracing::error!(path = %file_entry.path, error = %e, "File verification failed"); - super::BundleError::Verification(e) - })?; - - Ok(( - file_entry.path.clone(), - VerifiedFile { - path: file_entry.path.clone(), - content: content.clone(), - }, - )) - }) - .collect(); - - let files: HashMap<_, _> = verified_files?.into_iter().collect(); - let total_size = files.values().map(|f| f.content.len()).sum(); - - tracing::info!( - "Successfully verified bundle with {} files, total size {}", - files.len(), - total_size - ); - - Ok(Self { - content, - files, - total_size, - }) - } - - pub fn trust(content: Vec, manifest: Manifest) -> Result { - tracing::info!( - "Creating trusted bundle with {} files", - manifest.files.len() - ); - - let mut archive = ZipArchive::new(Cursor::new(&content)).map_err(|e| { - tracing::error!(error = %e, "Failed to read ZIP archive"); - BundleError::InvalidFormat(format!("Failed to read ZIP archive: {}", e)) - })?; - - let mut files = HashMap::new(); - let mut total_size = 0; - - for file_entry in manifest.files.iter() { - let path = &file_entry.path; - tracing::debug!(path = %path, "Extracting file from archive"); - - match archive.by_name(path) { - Ok(mut file) => { - let mut content = Vec::new(); - if let Err(e) = std::io::Read::read_to_end(&mut file, &mut content) { - tracing::error!(path = %path, error = %e, "Failed to read file"); - return Err(BundleError::InvalidFormat(format!( - "Failed to read {}: {}", - path, e - ))); - } - - total_size += content.len(); - files.insert( - path.to_string(), - VerifiedFile { - path: path.to_string(), - content, - }, - ); - } - Err(e) => { - tracing::error!(path = %path, error = %e, "File not found in archive"); - return Err(BundleError::InvalidFormat(format!( - "File not found in archive: {}", - path - ))); - } - } - } - - tracing::info!( - "Successfully created trusted bundle with {} files, total size {}", - files.len(), - total_size - ); - - Ok(Self { - content, - files, - total_size, - }) - } - - pub fn iter_files(&self) -> impl Iterator { - self.files.values() - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/error.rs deleted file mode 100644 index 8be22aea..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/error.rs +++ /dev/null @@ -1,27 +0,0 @@ -use thiserror::Error; - -pub type Result = std::result::Result; - -#[derive(Debug, Error)] -pub enum CacheError { - #[error("Cache entry not found: {0}")] - NotFound(String), - - #[error("Cache entry expired: {0}")] - Expired(String), - - #[error("Cache full")] - CacheFull, - - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - - #[error("Verification error: {0}")] - Verification(#[from] crate::verification::VerificationError), - - #[error("Zip error: {0}")] - Zip(#[from] zip::result::ZipError), - - #[error("Invalid cache entry: {0}")] - InvalidEntry(String), -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/manager.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/manager.rs deleted file mode 100644 index 37e773d7..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/manager.rs +++ /dev/null @@ -1,80 +0,0 @@ -use std::path::PathBuf; -use std::sync::Arc; - -use rayon::prelude::*; -use tauri::Config; - -use super::{CacheError, CachePolicy, FileStore, Result}; -use crate::bundle::VerifiedBundle; - -const BATCH_SIZE: usize = 10; - -pub struct CacheManager { - store: Arc, - policy: CachePolicy, -} - -impl CacheManager { - pub fn new(cache_dir: PathBuf, policy: CachePolicy, config: Config) -> Self { - tracing::info!( - ?cache_dir, - max_size = policy.max_size, - "Initializing CacheManager" - ); - - let store = Arc::new(FileStore::new(cache_dir, policy.max_size, config)); - Self { store, policy } - } - - pub async fn get_file(&self, bundle_name: &str, file_path: &str) -> Result> { - let cache_key = format!("{}:{}", bundle_name, file_path); - tracing::info!(%bundle_name, %file_path, %cache_key, "Retrieving file"); - - tracing::debug!( - %bundle_name, - %file_path, - %cache_key, - thread_id = ?std::thread::current().id(), - "Cache lookup attempt" - ); - - self.store.get(&cache_key).await - } - - pub async fn cache_bundle(&self, name: &str, verified: &VerifiedBundle) -> Result<()> { - tracing::info!(%name, "Starting bundle caching process"); - - if verified.total_size > self.policy.max_size { - tracing::error!(%name, total_size = verified.total_size, max_size = self.policy.max_size, "Cache size limit exceeded"); - return Err(CacheError::CacheFull); - } - - tracing::info!(%name, "Clearing memory cache before caching bundle"); - self.clear_memory_cache().await; - - let store = self.store.clone(); - - verified - .iter_files() - .collect::>() - .par_chunks(BATCH_SIZE) - .try_for_each(|batch| { - batch.iter().try_for_each(|file| { - let cache_key = format!("{}:{}", name, file.path); - futures::executor::block_on(store.store(&cache_key, file.content.clone())) - .map_err(|e| { - tracing::error!(%name, path = %file.path, %e, "Cache storage failed"); - e - }) - }) - })?; - - tracing::info!(%name, "Bundle caching completed successfully"); - Ok(()) - } - - pub async fn clear_memory_cache(&self) { - tracing::info!("Forwarding clear cache request to FileStore"); - self.store.clear().await; - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/mod.rs deleted file mode 100644 index 1fbbf52a..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -mod error; -mod manager; -mod policy; -mod store; - -pub use error::{CacheError, Result}; -pub use manager::CacheManager; -pub use policy::CachePolicy; -pub use store::FileStore; - -pub const DEFAULT_CACHE_SIZE: usize = 1000 * 1024 * 1024; // 1000MB -pub const DEFAULT_FILE_TTL: u64 = 3600; // 1 hour diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/policy.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/policy.rs deleted file mode 100644 index 447f5e6e..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/policy.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::time::Duration; - -#[derive(Debug, Clone)] -pub struct CachePolicy { - pub max_size: usize, - pub file_ttl: Duration, - pub hot_ratio: f32, -} - -impl CachePolicy { - pub fn new(max_size: usize, file_ttl: Duration, hot_ratio: f32) -> Self { - Self { - max_size, - file_ttl, - hot_ratio: hot_ratio.clamp(0.0, 1.0), - } - } - - pub fn hot_cache_size(&self) -> usize { - (self.max_size as f32 * self.hot_ratio) as usize - } - - pub fn disk_cache_size(&self) -> usize { - self.max_size - self.hot_cache_size() - } -} - -impl Default for CachePolicy { - fn default() -> Self { - Self { - max_size: super::DEFAULT_CACHE_SIZE, - file_ttl: Duration::from_secs(super::DEFAULT_FILE_TTL), - hot_ratio: 0.9, - } - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/store.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/store.rs deleted file mode 100644 index 87f39397..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/cache/store.rs +++ /dev/null @@ -1,180 +0,0 @@ -use std::path::PathBuf; -use std::sync::Arc; -use std::time::Instant; - -use dashmap::DashMap; -use lru::LruCache; -use tauri::Config; -use tokio::sync::Mutex; - -use super::{CacheError, Result}; - -pub struct FileStore { - hot_cache: Arc>>, - disk_cache: Arc>, - cache_dir: PathBuf, - max_memory: usize, - config: Config, -} - -struct CacheEntry { - content: Vec, - last_accessed: Instant, - size: usize, -} - -impl FileStore { - pub fn new(cache_dir: PathBuf, max_memory: usize, config: Config) -> Self { - tracing::info!( - cache_dir = ?cache_dir, - max_memory, - "Initializing FileStore with cache directory and memory limit." - ); - Self { - hot_cache: Arc::new(Mutex::new(LruCache::new( - std::num::NonZeroUsize::new(1000).unwrap(), - ))), - disk_cache: Arc::new(DashMap::new()), - cache_dir, - max_memory, - config, - } - } - - pub async fn store(&self, key: &str, content: Vec) -> Result<()> { - let size = content.len(); - tracing::info!(key, size, "Storing file in cache."); - - let mut cache = self.hot_cache.lock().await; - let current_size = self.current_size(&cache); - - if current_size + size <= self.max_memory { - tracing::debug!(key, size, "File fits in memory; adding to hot cache."); - cache.put( - key.to_string(), - CacheEntry { - content, - last_accessed: Instant::now(), - size, - }, - ); - return Ok(()); - } - - if size > self.max_memory { - tracing::warn!( - key, - size, - "File size exceeds maximum memory. Writing directly to disk." - ); - let path = self.cache_dir.join(key); - tokio::fs::write(&path, &content).await.map_err(|e| { - tracing::error!(key, error = %e, "Failed to write file to disk."); - e - })?; - self.disk_cache.insert(key.to_string(), path); - return Ok(()); - } - - tracing::debug!( - key, - size, - current_size, - "Hot cache full; evicting files to make room." - ); - while cache.len() > 0 && self.current_size(&cache) + size > self.max_memory { - if let Some((evicted_key, entry)) = cache.pop_lru() { - let path = self.cache_dir.join(&evicted_key); - tracing::debug!(evicted_key, "Evicting file to disk."); - std::fs::write(&path, &entry.content).map_err(|e| { - tracing::error!( - evicted_key, - error = %e, - "Failed to write evicted file to disk." - ); - e - })?; - self.disk_cache.insert(evicted_key, path); - } - } - - tracing::debug!(key, "Adding file to hot cache after eviction."); - cache.put( - key.to_string(), - CacheEntry { - content, - last_accessed: Instant::now(), - size, - }, - ); - Ok(()) - } - - pub async fn get(&self, key: &str) -> Result> { - tracing::info!(key, "Retrieving file from cache."); - tracing::debug!( - key, - thread_id = ?std::thread::current().id(), - hot_cache_len = self.hot_cache.lock().await.len(), - disk_cache_len = self.disk_cache.len(), - "Cache access attempt details" - ); - - let mut guard = self.hot_cache.lock().await; - if let Some(entry) = guard.get(key) { - tracing::debug!(key, "File found in hot cache."); - return Ok(entry.content.clone()); - } - drop(guard); - - tracing::debug!(key, "File not found in hot cache. Checking disk cache."); - if let Some(path) = self.disk_cache.get(key) { - tracing::debug!(key, path = ?path, "File found in disk cache. Reading from disk."); - let content = tokio::fs::read(path.value()).await.map_err(|e| { - tracing::error!(key, error = %e, "Failed to read file from disk."); - e - })?; - self.store(key, content.clone()).await?; - return Ok(content); - } - - tracing::warn!(key, "File not found in cache."); - Err(CacheError::NotFound(key.to_string())) - } - - pub async fn clear_except_prefix(&self, prefix: &str) { - let mut cache = self.hot_cache.lock().await; - - let keys_to_keep: Vec<_> = cache - .iter() - .filter(|(key, _)| key.starts_with(prefix)) - .map(|(key, _)| key.clone()) - .collect(); - - let mut new_cache = LruCache::new(std::num::NonZeroUsize::new(1000).unwrap()); - for key in keys_to_keep { - if let Some(entry) = cache.pop(&key) { - new_cache.put(key, entry); - } - } - - *cache = new_cache; - } - - pub async fn clear(&self) { - tracing::info!("Clearing in-memory cache"); - let config = self.config.clone(); - let name = config - .product_name - .unwrap_or("unknown".to_string()) - .to_lowercase(); - self.clear_except_prefix(&name).await; - tracing::info!("In-memory cache cleared successfully"); - } - - fn current_size(&self, cache: &LruCache) -> usize { - let size = cache.iter().map(|(_, entry)| entry.size).sum(); - tracing::debug!(current_size = size, "Calculating current hot cache size."); - size - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/commands.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/commands.rs deleted file mode 100644 index 288c56f6..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/commands.rs +++ /dev/null @@ -1,416 +0,0 @@ -use std::sync::Arc; - -#[cfg(target_os = "macos")] -use tauri::TitleBarStyle; -use tauri::{ - command, AppHandle, LogicalPosition, Manager, Runtime, WebviewUrl, WebviewWindowBuilder, -}; - -use crate::{ - bundle::BundleLoader, - cache::CacheManager, - mapping::HostMapper, - models::{ - CloseOptions, CloseResponse, DownloadOptions, DownloadResponse, LoadOptions, LoadResponse, - }, - storage::{StorageError, StorageManager}, - ui, RemoveOptions, RemoveResponse, Result, -}; - -/// Writes a line to appload.diag.log for debugging window lifecycle events. -/// This runs at the Rust level so it captures events even when JS logging -/// fails (e.g. webview destroyed before JS can write). Best-effort: silently -/// ignores any IO errors. -/// -/// The log directory comes from `Config::log_dir`, set by the host app during -/// plugin initialization. If no log_dir was configured, this is a no-op. -fn diag_log(msg: &str) { - let Some(dir) = crate::DIAG_LOG_DIR.get() else { - return; - }; - let _ = std::fs::create_dir_all(dir); - let path = dir.join("appload.diag.log"); - let _ = std::fs::OpenOptions::new() - .create(true) - .append(true) - .open(&path) - .and_then(|mut f| { - use std::io::Write; - writeln!(f, "[{}] [RUST] {}", chrono::Utc::now().to_rfc3339(), msg) - }); -} - -/// Maximum length for window labels/hosts -const MAX_HOST_LENGTH: usize = 255; - -fn sanitize_window_label(input: &str) -> Result { - if input.is_empty() { - return Err(crate::Error::Config("Host cannot be empty".into())); - } - if input.len() > MAX_HOST_LENGTH { - return Err(crate::Error::Config(format!( - "Host exceeds maximum length of {} characters", - MAX_HOST_LENGTH - ))); - } - - Ok(input - .chars() - .map(|c| if c.is_alphanumeric() { c } else { '_' }) - .collect()) -} - -#[command] -pub async fn download( - app: AppHandle, - options: DownloadOptions, -) -> Result { - tracing::info!(?options, "Starting download process"); - let bundle_loader = app.state::>(); - tracing::debug!("Retrieved BundleLoader state"); - - tracing::info!(url = %options.server_url, "Attempting to load bundle"); - bundle_loader - .load_bundle(options.server_url.as_str()) - .await - .map_err(|e| { - tracing::error!(?e, url = %options.server_url, "Failed to load bundle"); - e - })?; - - let storage = app.state::>(); - tracing::debug!("Retrieved StorageManager state"); - - tracing::info!(url = %options.server_url, "Fetching bundle entry from storage"); - let entry = storage - .get_bundle_entry(options.server_url.as_str()) - .await - .map_err(|e| { - tracing::error!(?e, url = %options.server_url, "Failed to fetch bundle entry"); - e - })? - .ok_or_else(|| { - tracing::error!(url = %options.server_url, "Bundle not found after download"); - crate::Error::Config("Bundle not found after download".into()) - })?; - - let response = DownloadResponse { - success: true, - bundle_name: entry.bundle_name, - server_url: options.server_url, - version: entry.version, - }; - - tracing::info!(?response, "Download completed successfully"); - Ok(response) -} - -#[command] -pub async fn load(app: AppHandle, options: LoadOptions) -> Result { - let base_label = sanitize_window_label(&options.window.title)?; - let current_label = format!("{}-curr", base_label); - let alternate_label = format!("{}-next", base_label); - - let has_curr = app.get_webview_window(¤t_label).is_some(); - let has_next = app.get_webview_window(&alternate_label).is_some(); - let label = if has_curr { - alternate_label.clone() - } else { - current_label.clone() - }; - - // All webviews use the bundle name as the URL host so they share the same - // origin (app://{bundle_name}/). This is critical because Tauri v2's IPC - // validates the webview origin at runtime and rejects origins it doesn't - // recognize. Using different hosts per org (e.g. app://test_org_hoppscotch_io) - // would break all IPC communication in the org webview. - // - // For cloud-for-orgs, the org host is passed as a query parameter instead. - // The JS side reads window.location.search to get the org context, and the - // kernel store uses the query param to maintain per-org file isolation. - let sanitized_bundle = sanitize_window_label(&options.bundle_name)?; - - let url = match &options.host { - Some(host) => { - // pass the original host value as-is in the query param so the JS - // side can extract the org domain without reversing sanitization. - // URL query values don't need the same restrictions as hostnames - format!( - "app://{}/?org={}", - sanitized_bundle.to_lowercase(), - host.to_lowercase() - ) - } - None => format!("app://{}/", sanitized_bundle.to_lowercase()), - }; - - // list all existing webview windows so the diag log shows the full picture - let existing_windows: Vec = app - .webview_windows() - .keys() - .cloned() - .collect(); - - diag_log(&format!( - "LOAD called: bundle={}, host={:?}, title={}, url={}, label={}, has_curr={}, has_next={}, existing_windows={:?}", - options.bundle_name, - options.host, - options.window.title, - url, - label, - has_curr, - has_next, - existing_windows - )); - - tracing::info!( - ?options, - bundle = %options.bundle_name, - %url, - window_label = %label, - "Loading bundle" - ); - tracing::debug!(%url, "Generated app URL"); - - let host_mapper = app.state::>(); - host_mapper.register( - &sanitized_bundle.to_lowercase(), - &options.bundle_name.to_lowercase(), - ); - tracing::debug!( - host = %sanitized_bundle.to_lowercase(), - bundle = %options.bundle_name.to_lowercase(), - "Registered host mapping" - ); - - let sanitized_title = sanitize_window_label(&options.window.title)?; - - // Build the webview with the kernel init script. Org context is carried - // via the ?org= query param in the URL (set above) and preserved across - // Vue Router navigations by a beforeEach guard in modules/router.ts. - let builder = - WebviewWindowBuilder::new(&app, &label, WebviewUrl::App(url.parse().unwrap())) - .initialization_script(crate::KERNEL_JS) - .title(sanitized_title) - .inner_size(options.window.width, options.window.height) - .resizable(options.window.resizable) - .disable_drag_drop_handler(); - - let window = match builder.build() - { - Ok(window) => window, - Err(e) => { - tracing::error!( - ?e, - ?label, - "Failed to create window, cleaning up host mapping" - ); - host_mapper.unregister(&sanitized_bundle.to_lowercase()); - return Err(e.into()); - } - }; - - #[cfg(target_os = "macos")] - { - let window_clone = window.clone(); - window.run_on_main_thread(move || { - ui::macos::posit::setup_window(window_clone); - })?; - } - - #[cfg(target_os = "windows")] - { - let window_clone = window.clone(); - window.run_on_main_thread(move || { - ui::windows::posit::setup_window(window_clone); - })?; - } - - let is_visible = window.is_visible().unwrap_or(false); - let response = LoadResponse { - success: is_visible, - window_label: label.clone(), - }; - - diag_log(&format!( - "LOAD complete: label={}, visible={}, success={}", - label, is_visible, response.success - )); - - tracing::info!(?response, "Bundle loaded successfully"); - Ok(response) -} - -#[command] -pub async fn close(app: AppHandle, options: CloseOptions) -> Result { - tracing::info!(?options, "Starting window close process"); - - let existing_windows: Vec = app - .webview_windows() - .keys() - .cloned() - .collect(); - - diag_log(&format!( - "CLOSE called: window_label={}, existing_windows={:?}", - options.window_label, - existing_windows - )); - - let Some(window) = app.get_webview_window(&options.window_label) else { - diag_log(&format!( - "CLOSE: window {} not found or already closed", - options.window_label - )); - tracing::info!(window_label = %options.window_label, "Window not found or already closed"); - return Ok(CloseResponse { success: true }); - }; - - window.close().map_err(|e| { - diag_log(&format!( - "CLOSE: failed to close window {}: {:?}", - options.window_label, e - )); - tracing::error!(?e, window_label = %options.window_label, "Failed to close window"); - e - })?; - - let remaining_windows: Vec = app - .webview_windows() - .keys() - .cloned() - .collect(); - - diag_log(&format!( - "CLOSE complete: closed={}, remaining_windows={:?}", - options.window_label, - remaining_windows - )); - - let response = CloseResponse { success: true }; - - tracing::info!(?response, "Window close process completed"); - Ok(response) -} - -#[command] -pub async fn remove( - app: AppHandle, - options: RemoveOptions, -) -> Result { - tracing::info!(?options, "Starting instance removal process"); - let storage = app.state::>(); - let cache = app.state::>(); - let host_mapper = app.state::>(); - - tracing::debug!("Retrieved StorageManager, CacheManager, and HostMapper states"); - - storage - .delete_bundle(&options.bundle_name, &options.server_url) - .await - .map_err(|e| { - tracing::error!(?e, "Failed to delete bundle from storage"); - e - })?; - - cache.clear_memory_cache().await; - - // Clean up mappings that pointed to this bundle, otherwise they'd resolve to files - // that no longer exist. - host_mapper.remove_mappings_for_bundle(&options.bundle_name.to_lowercase()); - - let response = RemoveResponse { - success: true, - bundle_name: options.bundle_name, - }; - - tracing::info!(?response, "Instance removed successfully"); - Ok(response) -} - -#[command] -pub async fn clear(app: AppHandle) -> Result<()> { - tracing::info!("Starting bundle cleanup process"); - let storage = app.state::>(); - let host_mapper = app.state::>(); - - host_mapper.clear(); - tracing::debug!("Cleared host mappings"); - - let layout = storage.layout(); - - if layout.bundles_dir().exists() { - tracing::debug!("Clearing bundles directory"); - tokio::fs::remove_dir_all(layout.bundles_dir()) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to clear bundles directory"); - crate::Error::Storage(StorageError::Io(e)) - })?; - tokio::fs::create_dir(layout.bundles_dir()) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to recreate bundles directory"); - crate::Error::Storage(StorageError::Io(e)) - })?; - } - - if layout.cache_dir().exists() { - tracing::debug!("Clearing cache directory"); - tokio::fs::remove_dir_all(layout.cache_dir()) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to clear cache directory"); - crate::Error::Storage(StorageError::Io(e)) - })?; - tokio::fs::create_dir(layout.cache_dir()) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to recreate cache directory"); - crate::Error::Storage(StorageError::Io(e)) - })?; - } - - if layout.key_dir().exists() { - tracing::debug!("Clearing key directory"); - tokio::fs::remove_dir_all(layout.key_dir()) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to clear key directory"); - crate::Error::Storage(StorageError::Io(e)) - })?; - tokio::fs::create_dir(layout.key_dir()).await.map_err(|e| { - tracing::error!(error = %e, "Failed to recreate key directory"); - crate::Error::Storage(StorageError::Io(e)) - })?; - } - - if layout.temp_dir().exists() { - tracing::debug!("Clearing temp directory"); - tokio::fs::remove_dir_all(layout.temp_dir()) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to clear temp directory"); - crate::Error::Storage(StorageError::Io(e)) - })?; - tokio::fs::create_dir(layout.temp_dir()) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to recreate temp directory"); - crate::Error::Storage(StorageError::Io(e)) - })?; - } - - if layout.registry_path().exists() { - tracing::debug!("Removing registry.json"); - tokio::fs::remove_file(layout.registry_path()) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to remove registry.json"); - crate::Error::Storage(StorageError::Io(e)) - })?; - } - - tracing::info!("Bundle cleanup completed successfully"); - Ok(()) -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/config/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/config/mod.rs deleted file mode 100644 index 44859c36..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/config/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod model; - -pub use model::{ApiConfig, CacheConfig, Config, StorageConfig}; - -pub const DEFAULT_CONFIG_PATH: &str = "config.json"; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/config/model.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/config/model.rs deleted file mode 100644 index eca8dac7..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/config/model.rs +++ /dev/null @@ -1,75 +0,0 @@ -use bon::Builder; -use serde::{Deserialize, Serialize}; -use std::path::PathBuf; -use std::time::Duration; - -use crate::cache::DEFAULT_CACHE_SIZE; -use crate::vendor::VendorConfig; - -#[derive(Debug, Clone, Builder, Serialize, Deserialize)] -pub struct Config { - #[serde(default)] - pub api: ApiConfig, - #[serde(default)] - pub cache: CacheConfig, - #[serde(default)] - pub storage: StorageConfig, - #[serde(skip)] - pub vendor: VendorConfig, - // optional log directory for diagnostic logging from the plugin layer. - // when set, the plugin writes best-effort diag lines (window lifecycle - // events, etc.) to `appload.diag.log` inside this directory. the host - // app is responsible for passing its own log directory here so the - // plugin doesn't need to know about app-specific path conventions - #[serde(skip)] - pub log_dir: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ApiConfig { - pub server_url: String, - #[serde(with = "humantime_serde")] - pub timeout: Duration, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CacheConfig { - pub max_size: usize, - #[serde(with = "humantime_serde")] - pub file_ttl: Duration, - pub hot_ratio: f32, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct StorageConfig { - pub root_dir: PathBuf, - pub max_bundle_size: usize, -} - -impl Default for ApiConfig { - fn default() -> Self { - Self { - server_url: "http://localhost:3200".to_string(), - timeout: Duration::from_secs(30), - } - } -} - -impl Default for CacheConfig { - fn default() -> Self { - Self { - max_size: DEFAULT_CACHE_SIZE, - file_ttl: Duration::from_secs(3600), - hot_ratio: 0.9, - } - } -} - -impl Default for StorageConfig { - fn default() -> Self { - Self { - root_dir: PathBuf::from("data"), - max_bundle_size: 50 * 1024 * 1024, // 50MB - } - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/desktop.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/desktop.rs deleted file mode 100644 index a9da8300..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/desktop.rs +++ /dev/null @@ -1,36 +0,0 @@ -use std::sync::Arc; - -use serde::de::DeserializeOwned; -use tauri::{plugin::PluginApi, AppHandle, Runtime}; - -use crate::{ - bundle::BundleLoader, - models::{DownloadOptions, DownloadResponse, LoadOptions, LoadResponse}, - Result, -}; - -pub fn init( - app: &AppHandle, - api: PluginApi, - bundle_loader: Arc, -) -> Result> { - Ok(Appload { - app: app.clone(), - bundle_loader, - }) -} - -pub struct Appload { - app: AppHandle, - bundle_loader: Arc, -} - -impl Appload { - pub async fn download(&self, options: DownloadOptions) -> Result { - super::commands::download(self.app.clone(), options).await - } - - pub async fn load(&self, options: LoadOptions) -> Result { - super::commands::load(self.app.clone(), options).await - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/envvar.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/envvar.rs deleted file mode 100644 index 2f8437d9..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/envvar.rs +++ /dev/null @@ -1,8 +0,0 @@ -use std::{collections::HashMap, env}; - -/// Collect environment variables that should be exposed to the web app -pub(super) fn collect_env_vars() -> HashMap { - env::vars() - .filter(|(k, _)| k.starts_with("VITE_")) - .collect() -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/error.rs deleted file mode 100644 index b2227be1..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/error.rs +++ /dev/null @@ -1,40 +0,0 @@ -use serde::Serialize; -use thiserror::Error; - -pub type Result = std::result::Result; - -#[derive(Debug, Error)] -pub enum Error { - #[error(transparent)] - Api(#[from] crate::api::ApiError), - - #[error(transparent)] - Cache(#[from] crate::cache::CacheError), - - #[error(transparent)] - Storage(#[from] crate::storage::StorageError), - - #[error(transparent)] - Bundle(#[from] crate::bundle::BundleError), - - #[error(transparent)] - Verification(#[from] crate::verification::VerificationError), - - #[error(transparent)] - Tauri(#[from] tauri::Error), - - #[error("Window not found")] - WindowNotFound, - - #[error("Configuration error: {0}")] - Config(String), -} - -impl Serialize for Error { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: serde::Serializer, - { - serializer.serialize_str(self.to_string().as_ref()) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/global.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/global.rs deleted file mode 100644 index b4910dd1..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/global.rs +++ /dev/null @@ -1,4 +0,0 @@ -use std::time::Duration; - -pub(crate) const BUNDLE_CLEANUP_INTERVAL: Duration = Duration::from_secs(3600); // 1 hr -pub(crate) const BUNDLE_MAX_AGE: Duration = Duration::from_secs(86400); // 24 hrs diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/kernel.js b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/kernel.js deleted file mode 100644 index 747f2235..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/kernel.js +++ /dev/null @@ -1,40 +0,0 @@ -;(() => { - console.log("Setting desktop kernel mode") - window.__KERNEL_MODE__ = "desktop" - - // write bundle identity to the log file on disk so we can trace which - // webview is which across webkit relaunches (console logs get wiped). - // runs before any JS modules load, so we use the raw Tauri IPC channel - // instead of @tauri-apps/api. - // - // log webview identity to disk so we can trace which webview is which - // across webkit relaunches (console logs get wiped) - Promise.resolve().then(function () { - var params = new URLSearchParams(window.location.search) - var orgParam = params.get("org") - var tag = orgParam ? "org(" + orgParam + ")" : "vendored" - - var line = [ - "", - "========================================================================", - "WEBVIEW INIT " + new Date().toISOString(), - " tag : " + tag, - " ?org= : " + (orgParam || "(not set)"), - " href : " + window.location.href, - " hostname : " + window.location.hostname, - " origin : " + window.location.origin, - "========================================================================", - "", - ].join("\n") - - // __TAURI_INTERNALS__ is always present before initialization_scripts run - if (window.__TAURI_INTERNALS__) { - window.__TAURI_INTERNALS__.invoke("append_log", { - filename: "appload.diag.log", - content: line, - }).catch(function (err) { - console.warn("[kernel.js] Failed to write init log:", err) - }) - } - }) -})() diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/lib.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/lib.rs deleted file mode 100644 index 20a333e6..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/lib.rs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright 2025 CuriousCorrelation -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! app bundle loading plugin for Tauri. -//! This plugin handles downloading and loading external web app bundles in Tauri webviews. - -// TODO: Fix these. There are icons in the asset directory for the web app. -#![doc( - html_logo_url = "https://github.com///raw/main/packages/app/public/favicon.ico", - html_favicon_url = "https://github.com///raw/main/packages/app/public/favicon.ico" -)] - -use std::path::PathBuf; -use std::sync::{Arc, OnceLock}; -use tauri::{ - plugin::{Builder, Plugin, TauriPlugin}, - Manager, Runtime, -}; - -// log directory for the plugin-level diagnostic logger (commands::diag_log). -// set once during plugin init from Config::log_dir. a OnceLock because -// diag_log is a free function called from command handlers that don't -// carry the config around -static DIAG_LOG_DIR: OnceLock = OnceLock::new(); - -pub use config::Config; -pub use config::{ApiConfig, CacheConfig, StorageConfig}; -pub use models::*; - -#[cfg(desktop)] -mod desktop; -#[cfg(mobile)] -mod mobile; - -mod api; -mod bundle; -mod cache; -mod commands; -mod config; -mod envvar; -mod error; -mod global; -mod mapping; -mod models; -mod storage; -mod ui; -mod uri; -mod vendor; -mod verification; - -pub use error::{Error, Result}; -pub use mapping::HostMapper; -pub use vendor::VendorConfig; - -#[cfg(mobile)] -use mobile::Appload; - -const KERNEL_JS: &str = include_str!("kernel.js"); - -pub fn init(config: Config) -> TauriPlugin { - Builder::new("appload") - .setup(move |app, api| { - tracing::info!("Initializing appload plugin"); - - if let Some(log_dir) = &config.log_dir { - let _ = DIAG_LOG_DIR.set(log_dir.clone()); - } - - tracing::debug!("Using provided configuration settings."); - let storage_root = config.storage.root_dir.clone(); - - tracing::info!( - path = ?storage_root, - "Using configured storage root directory." - ); - - let storage = tauri::async_runtime::block_on(async { - let storage = storage::StorageManager::new(storage_root) - .await - .map_err(|e| { - tracing::error!(error = %e, "Failed to initialize storage manager"); - Error::Config(e.to_string()) - })?; - - storage.init().await.map_err(|e| { - tracing::error!(error = %e, "Failed to initialize storage directories"); - Error::Config(e.to_string()) - })?; - - Ok::<_, Error>(Arc::new(storage)) - })?; - - tracing::debug!("Setting up uri handler."); - let tauri_config = app.config().clone(); - - tracing::debug!("Initializing cache manager."); - let cache = Arc::new(cache::CacheManager::new( - storage.layout().cache_dir(), - cache::CachePolicy::new( - config.cache.max_size, - config.cache.file_ttl, - config.cache.hot_ratio, - ), - tauri_config.clone(), - )); - - tracing::debug!("Setting up bundle loader."); - let bundle_loader = Arc::new(bundle::BundleLoader::new(cache.clone(), storage.clone())); - - tracing::debug!("Initializing host mapper."); - let host_mapper = Arc::new(mapping::HostMapper::new()); - - tracing::debug!("Initializing uri handler."); - let uri_handler = Arc::new(uri::UriHandler::new( - cache.clone(), - tauri_config.clone(), - host_mapper.clone(), - )); - - { - let tauri_config = tauri_config.clone(); - let cache = cache.clone(); - let storage = storage.clone(); - tauri::async_runtime::block_on(async move { - if let Err(e) = config.vendor.initialize(tauri_config, cache, storage).await { - tracing::error!(error = %e, "Failed to initialize vendor."); - } - }); - } - - #[cfg(desktop)] - tracing::debug!("Initializing desktop-specific components."); - #[cfg(desktop)] - let view = desktop::init(app, api, bundle_loader.clone())?; - - #[cfg(mobile)] - tracing::debug!("Initializing mobile-specific components."); - #[cfg(mobile)] - let view = mobile::init(app, api, bundle_loader.clone())?; - - app.manage(bundle_loader); - app.manage(cache); - app.manage(storage); - app.manage(host_mapper); - app.manage(uri_handler); - app.manage(view); - - tracing::info!("appload plugin setup complete."); - Ok(()) - }) - .invoke_handler(tauri::generate_handler![ - commands::download, - commands::load, - commands::close, - commands::remove, - commands::clear - ]) - .register_uri_scheme_protocol("app", move |ctx, req| { - tracing::info!("Incoming URI request"); - - let app = ctx.app_handle(); - let uri = req.uri(); - - tracing::debug!( - url = %uri, - thread_id = ?std::thread::current().id(), - "Handling app URI scheme request." - ); - - let uri_handler = app.state::>(); - - tracing::info!("Got URI handler"); - - tauri::async_runtime::block_on(uri_handler.handle(uri)).unwrap() - }) - .build() -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/mapping.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/mapping.rs deleted file mode 100644 index 129085d2..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/mapping.rs +++ /dev/null @@ -1,246 +0,0 @@ -use dashmap::DashMap; -use std::sync::Arc; - -/// Maps virtual hosts to bundle names. -/// -/// This enables a single bundle to be served under multiple virtual hosts, -/// which is essential for cloud-for-orgs support where the same Hoppscotch -/// bundle needs to appear as different organization subdomains. -/// -/// Example: -/// - `load({ bundleName: "Hoppscotch", host: "acme.hoppscotch.io" })` -/// - Registers mapping: "acme_hoppscotch_io" -> "hoppscotch" -/// - Webview URL becomes: `app://acme_hoppscotch_io/` -/// - UriHandler resolves "acme_hoppscotch_io" -> "hoppscotch" for file lookups -/// -/// On web, org context comes from window.location.hostname (acme.hoppscotch.io), but on -/// desktop the webview URL is app://{bundle_name}/ which always returns the same hostname -/// regardless of which org the user is in. This mapper lets the same bundle files serve -/// under different virtual hostnames, so the JS can read window.location.hostname and get -/// the org context just like it does on web. -/// -/// The inner Arc is necessary because HostMapper derives Clone. When the struct -/// gets cloned (happens when passed across thread boundaries), both instances need to share -/// the same underlying map. Without the Arc, each clone gets its own DashMap and mappings -/// registered in one wouldn't be visible in the other. -#[derive(Debug, Clone, Default)] -pub struct HostMapper { - mappings: Arc>, -} - -impl HostMapper { - pub fn new() -> Self { - Self { - mappings: Arc::new(DashMap::new()), - } - } - - /// Register a host-to-bundle mapping. - /// - /// # Arguments - /// * `host` - The virtual host (e.g., "acme_hoppscotch_io") - /// * `bundle_name` - The actual bundle name (e.g., "hoppscotch") - pub fn register(&self, host: &str, bundle_name: &str) { - tracing::debug!(host = %host, bundle = %bundle_name, "Registering host to bundle mapping"); - self.mappings - .insert(host.to_string(), bundle_name.to_string()); - } - - /// Resolve a host to its bundle name. - /// - /// If no mapping exists, returns the host unchanged (passthrough). This is how backward - /// compatibility works: when loading without a host parameter, the bundle name itself - /// becomes the host, and since there's no explicit mapping for it, resolve just returns - /// it as-is. No special-casing needed. - /// - /// # Arguments - /// * `host` - The virtual host to resolve - /// - /// # Returns - /// The bundle name if a mapping exists, otherwise the host unchanged. - pub fn resolve(&self, host: &str) -> String { - let resolved = self - .mappings - .get(host) - .map(|v| v.clone()) - .unwrap_or_else(|| host.to_string()); - - tracing::debug!(host = %host, resolved = %resolved, "Resolved host mapping"); - resolved - } - - /// Remove a host mapping. - /// - /// # Arguments - /// * `host` - The virtual host to unregister - pub fn unregister(&self, host: &str) { - tracing::debug!(host = %host, "Unregistering host mapping"); - self.mappings.remove(host); - } - - pub fn has_mapping(&self, host: &str) -> bool { - self.mappings.contains_key(host) - } - - pub fn clear(&self) { - tracing::debug!("Clearing all host mappings"); - self.mappings.clear(); - } - - // Removes all mappings that point to a specific bundle. This gets called when a bundle - // is removed via the `remove` command. Without this cleanup, you'd end up with orphaned - // mappings where the virtual host still resolves to a bundle that no longer exists, - // causing confusing 404s on the next load attempt. - // - // Iterates all mappings which is O(n), but n is small in practice (number of orgs the - // user has loaded). Could add a reverse index if this ever becomes a problem. - pub fn remove_mappings_for_bundle(&self, bundle_name: &str) { - let hosts_to_remove: Vec = self - .mappings - .iter() - .filter(|entry| entry.value() == bundle_name) - .map(|entry| entry.key().clone()) - .collect(); - - for host in &hosts_to_remove { - tracing::debug!(host = %host, bundle = %bundle_name, "Removing orphaned host mapping"); - self.mappings.remove(host); - } - - if !hosts_to_remove.is_empty() { - tracing::info!( - count = hosts_to_remove.len(), - bundle = %bundle_name, - "Cleaned up host mappings for removed bundle" - ); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_register_and_resolve() { - let mapper = HostMapper::new(); - mapper.register("acme_hoppscotch_io", "hoppscotch"); - - assert_eq!(mapper.resolve("acme_hoppscotch_io"), "hoppscotch"); - } - - #[test] - fn test_resolve_passthrough() { - let mapper = HostMapper::new(); - - assert_eq!(mapper.resolve("hoppscotch"), "hoppscotch"); - } - - #[test] - fn test_unregister() { - let mapper = HostMapper::new(); - mapper.register("acme_hoppscotch_io", "hoppscotch"); - mapper.unregister("acme_hoppscotch_io"); - - assert_eq!(mapper.resolve("acme_hoppscotch_io"), "acme_hoppscotch_io"); - } - - #[test] - fn test_has_mapping() { - let mapper = HostMapper::new(); - assert!(!mapper.has_mapping("acme_hoppscotch_io")); - - mapper.register("acme_hoppscotch_io", "hoppscotch"); - assert!(mapper.has_mapping("acme_hoppscotch_io")); - } - - #[test] - fn test_empty_host_passthrough() { - let mapper = HostMapper::new(); - assert_eq!(mapper.resolve(""), ""); - } - - #[test] - fn test_case_sensitivity() { - let mapper = HostMapper::new(); - mapper.register("acme_hoppscotch_io", "hoppscotch"); - - assert_eq!(mapper.resolve("ACME_HOPPSCOTCH_IO"), "ACME_HOPPSCOTCH_IO"); - assert_eq!(mapper.resolve("acme_hoppscotch_io"), "hoppscotch"); - } - - #[test] - fn test_overwrite_mapping() { - let mapper = HostMapper::new(); - mapper.register("acme_hoppscotch_io", "hoppscotch"); - mapper.register("acme_hoppscotch_io", "different_bundle"); - - assert_eq!(mapper.resolve("acme_hoppscotch_io"), "different_bundle"); - } - - #[test] - fn test_clear() { - let mapper = HostMapper::new(); - mapper.register("acme_hoppscotch_io", "hoppscotch"); - mapper.register("beta_hoppscotch_io", "hoppscotch"); - mapper.clear(); - - assert!(!mapper.has_mapping("acme_hoppscotch_io")); - assert!(!mapper.has_mapping("beta_hoppscotch_io")); - assert_eq!(mapper.resolve("acme_hoppscotch_io"), "acme_hoppscotch_io"); - } - - #[test] - fn test_multiple_hosts_same_bundle() { - let mapper = HostMapper::new(); - mapper.register("acme_hoppscotch_io", "hoppscotch"); - mapper.register("beta_hoppscotch_io", "hoppscotch"); - mapper.register("gamma_hoppscotch_io", "hoppscotch"); - - assert_eq!(mapper.resolve("acme_hoppscotch_io"), "hoppscotch"); - assert_eq!(mapper.resolve("beta_hoppscotch_io"), "hoppscotch"); - assert_eq!(mapper.resolve("gamma_hoppscotch_io"), "hoppscotch"); - } - - #[test] - fn test_long_host_name() { - let mapper = HostMapper::new(); - let long_host = "a".repeat(253); // DNS max length - mapper.register(&long_host, "hoppscotch"); - - assert_eq!(mapper.resolve(&long_host), "hoppscotch"); - } - - #[test] - fn test_remove_mappings_for_bundle() { - let mapper = HostMapper::new(); - mapper.register("acme_hoppscotch_io", "hoppscotch"); - mapper.register("beta_hoppscotch_io", "hoppscotch"); - mapper.register("gamma_other_io", "other_bundle"); - - mapper.remove_mappings_for_bundle("hoppscotch"); - - // Both hoppscotch mappings should be gone, falling back to passthrough - assert!(!mapper.has_mapping("acme_hoppscotch_io")); - assert!(!mapper.has_mapping("beta_hoppscotch_io")); - assert_eq!(mapper.resolve("acme_hoppscotch_io"), "acme_hoppscotch_io"); - assert_eq!(mapper.resolve("beta_hoppscotch_io"), "beta_hoppscotch_io"); - - // other_bundle mapping should be untouched - assert!(mapper.has_mapping("gamma_other_io")); - assert_eq!(mapper.resolve("gamma_other_io"), "other_bundle"); - } - - #[test] - fn test_remove_mappings_for_nonexistent_bundle() { - let mapper = HostMapper::new(); - mapper.register("acme_hoppscotch_io", "hoppscotch"); - - // Should be a no-op, not panic or error - mapper.remove_mappings_for_bundle("nonexistent"); - - // Original mapping should still be there - assert!(mapper.has_mapping("acme_hoppscotch_io")); - assert_eq!(mapper.resolve("acme_hoppscotch_io"), "hoppscotch"); - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/mobile.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/mobile.rs deleted file mode 100644 index 3caec219..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/mobile.rs +++ /dev/null @@ -1,44 +0,0 @@ -use serde::de::DeserializeOwned; -use tauri::{ - plugin::{PluginApi, PluginHandle}, - AppHandle, Runtime, -}; - -use crate::{DownloadOptions, DownloadResponse, LoadOptions, LoadResponse}; - -#[cfg(target_os = "ios")] -tauri::ios_plugin_binding!(init_plugin_appload); - -#[cfg(target_os = "android")] -const PLUGIN_IDENTIFIER: &str = "app.tauri.appload"; - -/// Initialize plugin for mobile platforms -pub fn init( - _app: &AppHandle, - api: PluginApi, -) -> crate::Result> { - #[cfg(target_os = "android")] - let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "Appload")?; - #[cfg(target_os = "ios")] - let handle = api.register_ios_plugin(init_plugin_appload)?; - Ok(Appload(handle)) -} - -/// Mobile implementation of the app loading plugin -pub struct Appload(PluginHandle); - -impl Appload { - /// Download an app bundle - pub async fn download(&self, options: DownloadOptions) -> crate::Result { - self.0 - .run_mobile_plugin("download", options) - .map_err(Into::into) - } - - /// Load an app in a new window - pub async fn load(&self, options: LoadOptions) -> crate::Result { - self.0 - .run_mobile_plugin("load", options) - .map_err(Into::into) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/models.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/models.rs deleted file mode 100644 index fae0c3da..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/models.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::collections::HashMap; - -use blake3::Hash; -use chrono::{DateTime, Utc}; -use ed25519_dalek::Signature; -use serde::{Deserialize, Serialize}; -use url::Url; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct BundleMetadata { - pub version: String, - pub created_at: DateTime, - #[serde(with = "signature_serde")] - pub signature: Signature, - pub manifest: Manifest, - #[serde(default)] - pub properties: HashMap, -} - -mod signature_serde { - use super::*; - use base64::{engine::general_purpose::STANDARD, Engine}; - use serde::{de::Error, Deserializer, Serializer}; - - pub fn serialize(sig: &Signature, serializer: S) -> Result - where - S: Serializer, - { - serializer.serialize_str(&STANDARD.encode(sig.to_bytes())) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let s = String::deserialize(deserializer)?; - let bytes = STANDARD.decode(&s).map_err(D::Error::custom)?; - let bytes: [u8; 64] = bytes - .try_into() - .map_err(|_| D::Error::custom("invalid signature length"))?; - Ok(Signature::from_bytes(&bytes)) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct FileEntry { - pub path: String, - pub size: u64, - #[serde(with = "hash_serde")] - pub hash: Hash, - pub mime_type: Option, -} - -mod hash_serde { - use super::*; - use base64::{engine::general_purpose::STANDARD, Engine}; - use blake3::Hash; - - pub fn serialize(sig: &Hash, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_str(&STANDARD.encode(sig.as_bytes())) - } - - pub fn deserialize<'de, D>(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - use serde::de::Error; - let s = String::deserialize(deserializer)?; - let bytes = STANDARD.decode(&s).map_err(D::Error::custom)?; - let bytes: [u8; 32] = bytes - .try_into() - .map_err(|_| D::Error::custom("invalid signature length"))?; - Ok(Hash::from_bytes(bytes)) - } -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Manifest { - pub files: Vec, - #[serde(default)] - pub version: Option, -} - -impl Manifest { - pub fn total_size(&self) -> u64 { - self.files.iter().map(|f| f.size).sum() - } - - pub fn get_file(&self, path: &str) -> Option<&FileEntry> { - self.files.iter().find(|f| f.path == path) - } -} - -#[derive(Debug, Clone, Deserialize)] -pub struct ApiResponse { - pub success: bool, - #[serde(default)] - pub error: Option, - pub data: T, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct BundleList { - pub bundles: Vec, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct BundleSummary { - pub name: String, - pub version: String, - pub created_at: DateTime, - pub file_count: usize, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct VerificationResponse { - pub status: String, - pub created_at: DateTime, - pub version: String, - pub file_count: usize, -} - -#[derive(Debug, Clone, Deserialize)] -pub struct PublicKeyInfo { - pub key: String, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct DownloadOptions { - pub server_url: Url, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DownloadResponse { - pub success: bool, - pub bundle_name: String, - pub server_url: Url, - pub version: String, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct LoadOptions { - pub bundle_name: String, - /// Optional host override for the webview URL. - /// - /// When provided, the webview will be loaded with `app://{host}/` instead of - /// `app://{bundle_name}/`. This enables cloud-for-orgs support where the same - /// bundle serves multiple organization subdomains. - /// - /// Example: `host: "acme.hoppscotch.io"` will: - /// - Sanitize to "acme_hoppscotch_io" - /// - Create webview at `app://acme_hoppscotch_io/` - /// - Register mapping so file requests resolve to the correct bundle - #[serde(default)] - pub host: Option, - #[serde(default)] - pub inline: bool, - #[serde(default)] - pub window: WindowOptions, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct LoadResponse { - pub success: bool, - pub window_label: String, -} - -#[derive(Debug, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct CloseOptions { - pub window_label: String, -} - -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CloseResponse { - pub success: bool, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct RemoveOptions { - pub bundle_name: String, - pub server_url: String, -} - -#[derive(Debug, Clone, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RemoveResponse { - pub success: bool, - pub bundle_name: String, -} - -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct WindowOptions { - #[serde(default = "default_window_title")] - pub title: String, - #[serde(default = "default_window_width")] - pub width: f64, - #[serde(default = "default_window_height")] - pub height: f64, - #[serde(default = "default_resizable")] - pub resizable: bool, -} - -fn default_window_title() -> String { - "Appload".into() -} - -fn default_window_width() -> f64 { - 800.0 -} - -fn default_window_height() -> f64 { - 600.0 -} - -fn default_resizable() -> bool { - true -} - -impl Default for WindowOptions { - fn default() -> Self { - Self { - title: default_window_title(), - width: default_window_width(), - height: default_window_height(), - resizable: default_resizable(), - } - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/error.rs deleted file mode 100644 index b2f98b16..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/error.rs +++ /dev/null @@ -1,39 +0,0 @@ -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum StorageError { - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - - #[error("Bundle not found: {0}")] - BundleNotFound(String), - - #[error("Invalid path: {0}")] - InvalidPath(String), - - #[error("Disk not found: fatal error, unable to resolve user config storage disk")] - DiskNotFound, - - #[error("Storage full: required {required} bytes, available {available} bytes")] - StorageFull { required: u64, available: u64 }, - - #[error("Lock error: {0}")] - LockError(String), - - #[error("Registry error: {0}")] - Registry(String), - - #[error("Version mismatch: local {local}, remote {remote}")] - VersionMismatch { local: String, remote: String }, - - #[error("Invalid URL format: {0}")] - InvalidUrl(#[from] url::ParseError), - - #[error("Serialization error: {0}")] - Serialization(#[from] serde_json::Error), - - #[error("Other error: {0}")] - OtherError(String), -} - -pub type Result = std::result::Result; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/layout.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/layout.rs deleted file mode 100644 index a956665d..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/layout.rs +++ /dev/null @@ -1,35 +0,0 @@ -use std::path::PathBuf; - -pub struct StorageLayout { - pub(crate) root: PathBuf, -} - -impl StorageLayout { - pub fn new(root: PathBuf) -> Self { - Self { root } - } - - pub fn bundles_dir(&self) -> PathBuf { - self.root.join("bundles") - } - - pub fn bundle_path(&self, name: &str) -> PathBuf { - self.bundles_dir().join(format!("{}.zip", name)) - } - - pub fn cache_dir(&self) -> PathBuf { - self.root.join("cache") - } - - pub fn temp_dir(&self) -> PathBuf { - self.root.join("temp") - } - - pub fn key_dir(&self) -> PathBuf { - self.root.join("key") - } - - pub fn registry_path(&self) -> PathBuf { - self.root.join("registry.json") - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/manager.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/manager.rs deleted file mode 100644 index e7b99391..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/manager.rs +++ /dev/null @@ -1,207 +0,0 @@ -use std::path::PathBuf; -use std::sync::Arc; -use sysinfo::Disks; -use tokio::sync::RwLock; -use tracing; - -use super::{Registry, Result, ServerEntry, StorageError, StorageLayout}; -use crate::bundle::VerifiedBundle; - -pub struct StorageManager { - layout: Arc, - registry: Arc>, - locks: Arc>>, -} - -impl StorageManager { - pub async fn new(root: PathBuf) -> Result { - tracing::info!(root = ?root, "Initializing StorageManager with root directory"); - let layout = StorageLayout::new(root); - - let registry = Registry::load(&layout).await?; - - Ok(Self { - layout: Arc::new(layout), - registry: Arc::new(RwLock::new(registry)), - locks: Arc::new(RwLock::new(Vec::new())), - }) - } - - pub async fn init(&self) -> Result<()> { - tracing::info!("Initializing storage directories"); - let dirs = [ - self.layout.bundles_dir(), - self.layout.cache_dir(), - self.layout.temp_dir(), - self.layout.key_dir(), - ]; - - for dir in &dirs { - tracing::debug!(directory = ?dir, "Creating directory"); - tokio::fs::create_dir_all(dir).await?; - } - - tracing::info!("Storage directories initialized successfully"); - Ok(()) - } - - pub async fn store_bundle( - &self, - name: &str, - server_url: &str, - version: &str, - verified: &VerifiedBundle, - ) -> Result<()> { - tracing::info!(bundle_name = name, "Storing bundle"); - - let bundle_path = self.layout.bundle_path(name); - let temp_path = self.layout.temp_dir().join(format!("{}.tmp", name)); - - for path in [&bundle_path, &temp_path] { - if let Some(parent) = path.parent() { - tracing::debug!(path = ?parent, "Ensuring directory exists"); - tokio::fs::create_dir_all(parent).await?; - } - } - - tracing::debug!( - bundle_name = name, - temp_path = ?temp_path, - "Ensuring sufficient space for the bundle" - ); - self.ensure_space(verified.content.len()).await?; - - tracing::debug!( - bundle_name = name, - temp_path = ?temp_path, - "Writing bundle content to temporary file" - ); - tokio::fs::write(&temp_path, &verified.content).await?; - - tracing::debug!( - bundle_name = name, - temp_path = ?temp_path, - bundle_path = ?bundle_path, - "Renaming temporary file to final bundle path" - ); - tokio::fs::rename(temp_path, bundle_path).await?; - - let mut registry = self.registry.write().await; - registry.update_server_entry( - server_url, - ServerEntry { - bundle_name: name.to_string(), - version: version.to_string(), - created_at: chrono::Utc::now(), - last_accessed: chrono::Utc::now(), - }, - )?; - - registry.save(&self.layout).await?; - - tracing::info!(bundle_name = name, "Bundle stored successfully"); - Ok(()) - } - - pub async fn get_bundle_entry(&self, server_url: &str) -> Result> { - let registry = self.registry.read().await; - Ok(registry.get_bundle_for_server(server_url).cloned()) - } - - pub async fn load_bundle(&self, name: &str) -> Result> { - tracing::info!(bundle_name = name, "Loading bundle"); - - let bundle_path = self.layout.bundle_path(name); - - if !bundle_path.exists() { - tracing::warn!(bundle_name = name, "Bundle not found"); - return Err(StorageError::BundleNotFound(name.to_string())); - } - - tracing::debug!(bundle_name = name, bundle_path = ?bundle_path, "Reading bundle content"); - let content = tokio::fs::read(&bundle_path).await?; - - tracing::info!(bundle_name = name, "Bundle loaded successfully"); - Ok(content) - } - - pub async fn delete_bundle(&self, name: &str, server_url: &str) -> Result<()> { - tracing::info!(bundle_name = name, "Deleting bundle"); - - let bundle_path = self.layout.bundle_path(name); - - if bundle_path.exists() { - tracing::debug!(bundle_name = name, bundle_path = ?bundle_path, "Removing bundle file"); - tokio::fs::remove_file(bundle_path).await?; - } - - let mut registry = self.registry.write().await; - registry.remove_server_entry(server_url)?; - registry.save(&self.layout).await?; - - tracing::info!(bundle_name = name, "Bundle deleted successfully"); - Ok(()) - } - - async fn ensure_space(&self, required: usize) -> Result<()> { - tracing::debug!(required_space = required, "Checking available disk space"); - - let disks = Disks::new_with_refreshed_list(); - - let storage_path = self.layout.root.canonicalize().map_err(|e| { - tracing::error!(error = %e, "Failed to resolve storage path"); - StorageError::Io(e) - })?; - - // Convert both paths to the same format for comparison, Windows... - let normalized_storage = dunce::canonicalize(&storage_path).unwrap_or(storage_path.clone()); - - // NOTE: There cannot be more than one user config storage disk, - // although even if there is, defaulting to the first one we found - // is as good of a guess as any. - // Find the disk with the longest matching mount point - let disk = disks - .into_iter() - .filter_map(|disk| { - let normalized_disk = dunce::canonicalize(disk.mount_point()) - .unwrap_or_else(|_| disk.mount_point().to_path_buf()); - - normalized_storage - .starts_with(&normalized_disk) - .then_some((disk, normalized_disk)) - }) - .max_by_key(|(_, normalized_disk)| normalized_disk.as_os_str().len()) - .map(|(disk, _)| disk) - .ok_or_else(|| { - tracing::error!( - storage_path = %storage_path.display(), - "Fatal error, unable to resolve user config storage disk" - ); - StorageError::DiskNotFound - })?; - - let available = disk.available_space(); - - if (required as u64) > available { - tracing::warn!( - required_space = required, - available_space = available, - "Insufficient disk space" - ); - return Err(StorageError::StorageFull { - required: required as u64, - available, - }); - } - - tracing::debug!( - available_space = available, - "Sufficient disk space available" - ); - Ok(()) - } - - pub fn layout(&self) -> &StorageLayout { - &self.layout - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/mod.rs deleted file mode 100644 index 17872954..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -mod error; -mod layout; -mod manager; -mod registry; - -pub use error::{Result, StorageError}; -pub use layout::StorageLayout; -pub use manager::StorageManager; -pub use registry::{Registry, ServerEntry}; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/registry.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/registry.rs deleted file mode 100644 index 70383f22..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/storage/registry.rs +++ /dev/null @@ -1,72 +0,0 @@ -use chrono::{DateTime, Utc}; -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; -use url::Url; - -use super::error::Result; -use super::layout::StorageLayout; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Registry { - pub version: u32, - pub servers: HashMap, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ServerEntry { - pub bundle_name: String, - pub version: String, - pub created_at: DateTime, - pub last_accessed: DateTime, -} - -impl Registry { - pub async fn load(layout: &StorageLayout) -> Result { - if !layout.registry_path().exists() { - return Ok(Self { - version: 1, - servers: HashMap::new(), - }); - } - - let content = tokio::fs::read_to_string(layout.registry_path()).await?; - Ok(serde_json::from_str(&content)?) - } - - pub async fn save(&self, layout: &StorageLayout) -> Result<()> { - let content = serde_json::to_string_pretty(self)?; - let path = layout.registry_path(); - let temp_path = path.with_extension("json.tmp"); - - tokio::fs::write(&temp_path, &content).await?; - tokio::fs::rename(&temp_path, &path).await?; - - Ok(()) - } - - pub fn get_bundle_for_server(&self, server_url: &str) -> Option<&ServerEntry> { - let normalized_url = Self::normalize_url(server_url).ok()?; - self.servers.get(&normalized_url) - } - - pub fn update_server_entry(&mut self, server_url: &str, entry: ServerEntry) -> Result<()> { - let normalized_url = Self::normalize_url(server_url)?; - self.servers.insert(normalized_url, entry); - Ok(()) - } - - pub fn remove_server_entry(&mut self, server_url: &str) -> Result> { - let normalized_url = Self::normalize_url(server_url)?; - Ok(self.servers.remove(&normalized_url)) - } - - fn normalize_url(url: &str) -> Result { - let parsed = if !url.starts_with("http://") && !url.starts_with("https://") { - Url::parse(&format!("https://{}", url)) - } else { - Url::parse(url) - }?; - - Ok(parsed.to_string().trim_end_matches('/').to_string()) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/macos/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/macos/mod.rs deleted file mode 100644 index c5cba139..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/macos/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod posit; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/macos/posit.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/macos/posit.rs deleted file mode 100644 index ee19d7c6..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/macos/posit.rs +++ /dev/null @@ -1,429 +0,0 @@ -use cocoa::{ - appkit::{ - NSAppearance, NSAppearanceNameVibrantDark, NSAppearanceNameVibrantLight, NSView, NSWindow, - NSWindowButton, NSWindowTitleVisibility, - }, - base::{id, nil, BOOL, YES}, - delegate, - foundation::{NSRect, NSUInteger}, -}; -use hex_color::HexColor; -use objc::{ - msg_send, - runtime::{Object, Sel}, - sel, sel_impl, -}; -use rand::distributions::{Alphanumeric, DistString}; -use tauri::{Emitter, Listener, LogicalPosition, Runtime, WebviewWindow}; - -#[derive(Debug)] -pub struct MacosWindow { - window: WebviewWindow, - traffic_lights_inset: LogicalPosition, - ns_window: id, -} - -impl MacosWindow { - pub fn new(window: WebviewWindow, traffic_lights_inset: LogicalPosition) -> Self { - let ns_window = window.ns_window().expect("Failed to get NS window handle") as id; - unsafe { - ns_window.setTitlebarAppearsTransparent_(YES); - ns_window.setTitleVisibility_(NSWindowTitleVisibility::NSWindowTitleHidden); - } - Self { - window, - traffic_lights_inset, - ns_window, - } - } - - pub fn setup(&self) { - self.reposition_controls(); - self.setup_theme_listener(); - unsafe { - let delegate = self.create_window_delegate(); - self.ns_window.setDelegate_(delegate); - } - } - - pub fn update_theme(&self, color: HexColor) { - let brightness = (color.r as u64 + color.g as u64 + color.b as u64) / 3; - unsafe { - let window_handle = self.ns_window; - let appearance = if brightness >= 128 { - NSAppearance(NSAppearanceNameVibrantLight) - } else { - NSAppearance(NSAppearanceNameVibrantDark) - }; - NSWindow::setAppearance(window_handle, appearance); - self.reposition_controls(); - } - } - - fn setup_theme_listener(&self) { - let window = self.window.clone(); - self.window.listen("hopp-bg-changed", move |event| { - let color_str = event.payload(); - - if let Ok(color_str) = serde_json::from_str::<&str>(color_str) { - if let Ok(color) = HexColor::parse_rgb(color_str.trim()) { - let macos_window = - MacosWindow::new(window.clone(), LogicalPosition::new(15.0, 23.0)); - macos_window.update_theme(color); - } - } - }); - } - - fn reposition_controls(&self) { - unsafe { - let buttons = self.window_buttons(); - let title_bar = buttons.title_bar_container(); - - let frame_height = buttons.height() + self.traffic_lights_inset.y; - title_bar.adjust_frame(frame_height, self.window_height()); - - buttons.reposition(self.traffic_lights_inset.x); - } - } - - unsafe fn create_window_delegate(&self) -> id { - let current_delegate = self.ns_window.delegate(); - let state = Box::new(WindowState::new( - self.window.clone(), - self.traffic_lights_inset, - )); - let app_box = Box::into_raw(state) as *mut std::ffi::c_void; - - let delegate_name = format!( - "WindowDelegate_{}_{}", - self.window.label(), - Alphanumeric.sample_string(&mut rand::thread_rng(), 20) - ); - - delegate!(&delegate_name, { - window: id = self.ns_window, - app_box: *mut std::ffi::c_void = app_box, - toolbar: id = nil, - super_delegate: id = current_delegate, - - (windowShouldClose:) => WindowDelegate::window_should_close as extern fn(&Object, Sel, id) -> BOOL, - (windowWillClose:) => WindowDelegate::window_will_close as extern fn(&Object, Sel, id), - (windowDidResize:) => WindowDelegate::window_did_resize:: as extern fn(&Object, Sel, id), - (windowDidMove:) => WindowDelegate::window_did_move as extern fn(&Object, Sel, id), - - (windowDidChangeBackingProperties:) => WindowDelegate::window_did_change_backing_properties as extern fn(&Object, Sel, id), - - (windowDidBecomeKey:) => WindowDelegate::window_did_become_key as extern fn(&Object, Sel, id), - (windowDidResignKey:) => WindowDelegate::window_did_resign_key as extern fn(&Object, Sel, id), - - (draggingEntered:) => WindowDelegate::dragging_entered as extern fn(&Object, Sel, id) -> BOOL, - (prepareForDragOperation:) => WindowDelegate::prepare_for_drag_operation as extern fn(&Object, Sel, id) -> BOOL, - (performDragOperation:) => WindowDelegate::perform_drag_operation as extern fn(&Object, Sel, id) -> BOOL, - (concludeDragOperation:) => WindowDelegate::conclude_drag_operation as extern fn(&Object, Sel, id), - (draggingExited:) => WindowDelegate::dragging_exited as extern fn(&Object, Sel, id), - - (window:willUseFullScreenPresentationOptions:) => WindowDelegate::window_will_use_full_screen_presentation_options as extern fn(&Object, Sel, id, NSUInteger) -> NSUInteger, - (windowDidEnterFullScreen:) => WindowDelegate::window_did_enter_full_screen:: as extern fn(&Object, Sel, id), - (windowWillEnterFullScreen:) => WindowDelegate::window_will_enter_full_screen:: as extern fn(&Object, Sel, id), - (windowDidExitFullScreen:) => WindowDelegate::window_did_exit_full_screen:: as extern fn(&Object, Sel, id), - (windowDidEndLiveResize:) => WindowDelegate::window_did_end_live_resize:: as extern fn(&Object, Sel, id), - (windowWillExitFullScreen:) => WindowDelegate::window_will_exit_full_screen:: as extern fn(&Object, Sel, id), - (windowDidFailToEnterFullScreen:) => WindowDelegate::window_did_fail_to_enter_full_screen as extern fn(&Object, Sel, id), - - (effectiveAppearanceDidChange:) => WindowDelegate::effective_appearance_did_change as extern fn(&Object, Sel, id), - (effectiveAppearanceDidChangedOnMainThread:) => WindowDelegate::effective_appearance_did_change_on_main_thread as extern fn(&Object, Sel, id) - }) - } - - unsafe fn window_height(&self) -> f64 { - NSView::frame(self.ns_window).size.height - } - - unsafe fn window_buttons(&self) -> WindowButtons { - WindowButtons::new(self.ns_window) - } -} - -#[derive(Debug)] -struct WindowButtons { - close: id, - minimize: id, - zoom: id, -} - -impl WindowButtons { - unsafe fn new(window: id) -> Self { - Self { - close: window.standardWindowButton_(NSWindowButton::NSWindowCloseButton), - minimize: window.standardWindowButton_(NSWindowButton::NSWindowMiniaturizeButton), - zoom: window.standardWindowButton_(NSWindowButton::NSWindowZoomButton), - } - } - - unsafe fn height(&self) -> f64 { - let close_frame: NSRect = msg_send![self.close, frame]; - close_frame.size.height - } - - unsafe fn title_bar_container(&self) -> TitleBarContainer { - TitleBarContainer(self.close.superview().superview()) - } - - unsafe fn button_spacing(&self) -> f64 { - NSView::frame(self.minimize).origin.x - NSView::frame(self.close).origin.x - } - - unsafe fn reposition(&self, inset_x: f64) { - let spacing = self.button_spacing(); - for (i, button) in [self.close, self.minimize, self.zoom].iter().enumerate() { - let mut frame = NSView::frame(*button); - frame.origin.x = inset_x + (i as f64 * spacing); - frame.origin.y = 0.0; - button.setFrameOrigin(frame.origin); - } - } -} - -struct TitleBarContainer(id); - -impl TitleBarContainer { - unsafe fn adjust_frame(&self, height: f64, window_height: f64) { - let mut frame = NSView::frame(self.0); - frame.size.height = height; - frame.origin.y = window_height - height; - frame.origin.x = 0.0; - let _: () = msg_send![self.0, setFrame: frame]; - } -} - -#[derive(Debug)] -struct WindowState { - window: WebviewWindow, - traffic_lights_inset: LogicalPosition, -} - -impl WindowState { - fn new(window: WebviewWindow, traffic_lights_inset: LogicalPosition) -> Self { - Self { - window, - traffic_lights_inset, - } - } -} - -struct WindowDelegate; - -impl WindowDelegate { - extern "C" fn window_should_close(this: &Object, _: Sel, sender: id) -> BOOL { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - msg_send![super_del, windowShouldClose: sender] - } - } - - extern "C" fn window_will_close(this: &Object, _: Sel, notification: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowWillClose: notification]; - } - } - - extern "C" fn window_did_resize(this: &Object, _: Sel, notification: id) { - unsafe { - Self::with_window_state::(this, |state| { - let macos_window = - MacosWindow::new(state.window.clone(), state.traffic_lights_inset); - macos_window.reposition_controls(); - }); - - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowDidResize: notification]; - } - } - - extern "C" fn window_did_move(this: &Object, _: Sel, notification: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowDidMove: notification]; - } - } - - extern "C" fn window_did_change_backing_properties(this: &Object, _: Sel, notification: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowDidChangeBackingProperties: notification]; - } - } - - extern "C" fn window_did_become_key(this: &Object, _: Sel, notification: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowDidBecomeKey: notification]; - } - } - - extern "C" fn window_did_resign_key(this: &Object, _: Sel, notification: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowDidResignKey: notification]; - } - } - - extern "C" fn dragging_entered(this: &Object, _: Sel, notification: id) -> BOOL { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - msg_send![super_del, draggingEntered: notification] - } - } - - extern "C" fn prepare_for_drag_operation(this: &Object, _: Sel, notification: id) -> BOOL { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - msg_send![super_del, prepareForDragOperation: notification] - } - } - - extern "C" fn perform_drag_operation(this: &Object, _: Sel, sender: id) -> BOOL { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - msg_send![super_del, performDragOperation: sender] - } - } - - extern "C" fn conclude_drag_operation(this: &Object, _: Sel, notification: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, concludeDragOperation: notification]; - } - } - - extern "C" fn dragging_exited(this: &Object, _: Sel, notification: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, draggingExited: notification]; - } - } - - extern "C" fn window_will_use_full_screen_presentation_options( - this: &Object, - _: Sel, - window: id, - proposed_options: NSUInteger, - ) -> NSUInteger { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - msg_send![super_del, window: window willUseFullScreenPresentationOptions: proposed_options] - } - } - - extern "C" fn window_did_enter_full_screen( - this: &Object, - _: Sel, - notification: id, - ) { - unsafe { - Self::with_window_state::(this, |state| { - let _ = state.window.emit("did-enter-fullscreen", ()); - }); - - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowDidEnterFullScreen: notification]; - } - } - - extern "C" fn window_will_enter_full_screen( - this: &Object, - _: Sel, - notification: id, - ) { - unsafe { - Self::with_window_state::(this, |state| { - let _ = state.window.emit("will-enter-fullscreen", ()); - }); - - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowWillEnterFullScreen: notification]; - } - } - - extern "C" fn window_did_end_live_resize(this: &Object, _: Sel, _: id) { - unsafe { - Self::with_window_state::(this, |state| { - let macos_window = - MacosWindow::new(state.window.clone(), state.traffic_lights_inset); - macos_window.reposition_controls(); - }); - } - } - - extern "C" fn window_did_exit_full_screen(this: &Object, _: Sel, notification: id) { - unsafe { - Self::with_window_state::(this, |state| { - let _ = state.window.emit("did-exit-fullscreen", ()); - let macos_window = - MacosWindow::new(state.window.clone(), state.traffic_lights_inset); - macos_window.reposition_controls(); - }); - - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowDidExitFullScreen: notification]; - } - } - - extern "C" fn window_will_exit_full_screen( - this: &Object, - _: Sel, - notification: id, - ) { - unsafe { - Self::with_window_state::(this, |state| { - let _ = state.window.emit("will-exit-fullscreen", ()); - }); - - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowWillExitFullScreen: notification]; - } - } - - extern "C" fn window_did_fail_to_enter_full_screen(this: &Object, _: Sel, window: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, windowDidFailToEnterFullScreen: window]; - } - } - - extern "C" fn effective_appearance_did_change(this: &Object, _: Sel, notification: id) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = msg_send![super_del, effectiveAppearanceDidChange: notification]; - } - } - - extern "C" fn effective_appearance_did_change_on_main_thread( - this: &Object, - _: Sel, - notification: id, - ) { - unsafe { - let super_del: id = *this.get_ivar("super_delegate"); - let _: () = - msg_send![super_del, effectiveAppearanceDidChangedOnMainThread: notification]; - } - } - - unsafe fn with_window_state(this: &Object, f: F) - where - F: FnOnce(&mut WindowState), - { - let ptr: *mut std::ffi::c_void = *this.get_ivar("app_box"); - let state_ptr = ptr as *mut WindowState; - f(&mut *state_ptr); - } -} - -pub fn setup_window(window: WebviewWindow) { - let macos_window = MacosWindow::new(window, LogicalPosition::new(15.0, 16.0)); - macos_window.setup(); - macos_window.update_theme(HexColor::WHITE); -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/mod.rs deleted file mode 100644 index 06699251..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[cfg(target_os = "macos")] -pub mod macos; -#[cfg(target_os = "windows")] -pub mod windows; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/windows/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/windows/mod.rs deleted file mode 100644 index c5cba139..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/windows/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod posit; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/windows/posit.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/windows/posit.rs deleted file mode 100644 index 2d2ffe86..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/ui/windows/posit.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::{ffi::c_void, mem::size_of, mem::transmute, ptr}; - -use hex_color::HexColor; -use tauri::{Listener, Runtime, WebviewWindow}; -use windows::Win32::{ - Foundation::{BOOL, COLORREF, HWND}, - Graphics::Dwm::{DwmSetWindowAttribute, DWMWA_CAPTION_COLOR, DWMWA_USE_IMMERSIVE_DARK_MODE}, - UI::Controls::{ - SetWindowThemeAttribute, WTA_NONCLIENT, WTNCA_NODRAWCAPTION, WTNCA_NODRAWICON, - WTNCA_NOMIRRORHELP, WTNCA_NOSYSMENU, - }, -}; -use winver::WindowsVersion; - -// Windows 11 Build 22000 is the minimum version required for -// DWMWA_USE_IMMERSIVE_DARK_MODE and DWMWA_CAPTION_COLOR. -// -// According to Microsoft documentation: -// https://learn.microsoft.com/en-us/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -// -// "DWMWA_USE_IMMERSIVE_DARK_MODE: Use with DwmSetWindowAttribute. -// [...] This value is supported starting with Windows 11 Build 22000." -// -// "DWMWA_CAPTION_COLOR: Use with DwmSetWindowAttribute. -// [...] This value is supported starting with Windows 11 Build 22000." -const MIN_WIN11_BUILD: u32 = 22000; - -#[derive(Debug)] -pub struct WindowsWindow { - window: WebviewWindow, - hwnd: HWND, -} - -impl WindowsWindow { - pub fn new(window: WebviewWindow) -> Self { - let hwnd = window.hwnd().expect("Failed to get window handle"); - let hwnd = HWND(hwnd.0); - Self { window, hwnd } - } - - pub fn setup(&self) { - self.update_theme(HexColor::rgb(23, 23, 23)); - self.setup_theme_listener(); - } - - pub fn update_theme(&self, color: HexColor) { - self.set_dark_mode(); - self.set_caption_color(color); - self.set_theme_attributes(); - } - - fn setup_theme_listener(&self) { - let window = self.window.clone(); - self.window.listen("hopp-bg-changed", move |event| { - let color_str = event.payload(); - - if let Ok(color_str) = serde_json::from_str::<&str>(color_str) { - if let Ok(color) = HexColor::parse_rgb(color_str.trim()) { - let windows_window = WindowsWindow::new(window.clone()); - windows_window.update_theme(color); - } - } - }); - } - - fn set_dark_mode(&self) { - if let Some(version) = WindowsVersion::detect() { - if version.major >= 10 && version.build >= MIN_WIN11_BUILD { - unsafe { - let use_dark_mode = BOOL::from(true); - let _ = DwmSetWindowAttribute( - self.hwnd, - DWMWA_USE_IMMERSIVE_DARK_MODE, - ptr::addr_of!(use_dark_mode) as *const c_void, - size_of::().try_into().unwrap(), - ); - } - } - } - } - - fn set_caption_color(&self, color: HexColor) { - if let Some(version) = WindowsVersion::detect() { - if version.major >= 10 && version.build >= MIN_WIN11_BUILD { - unsafe { - let color_ref = self.hex_color_to_colorref(color); - let _ = DwmSetWindowAttribute( - self.hwnd, - DWMWA_CAPTION_COLOR, - ptr::addr_of!(color_ref) as *const c_void, - size_of::().try_into().unwrap(), - ); - } - } - } - } - - fn set_theme_attributes(&self) { - unsafe { - let theme_attributes = WinThemeAttribute::new(); - SetWindowThemeAttribute( - self.hwnd, - WTA_NONCLIENT, - ptr::addr_of!(theme_attributes) as *const c_void, - size_of::().try_into().unwrap(), - ) - .expect("Failed to set theme attributes"); - } - } - - fn hex_color_to_colorref(&self, color: HexColor) -> COLORREF { - unsafe { COLORREF(transmute::<[u8; 4], u32>([color.r, color.g, color.b, 0])) } - } -} - -#[derive(Debug)] -struct WinThemeAttribute { - flag: u32, - mask: u32, -} - -impl WinThemeAttribute { - fn new() -> Self { - let flag = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON; - let mask = WTNCA_NODRAWCAPTION | WTNCA_NODRAWICON | WTNCA_NOSYSMENU | WTNCA_NOMIRRORHELP; - Self { flag, mask } - } -} - -pub fn setup_window(window: WebviewWindow) { - let windows_window = WindowsWindow::new(window); - windows_window.setup(); -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/error.rs deleted file mode 100644 index c1c44c08..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/error.rs +++ /dev/null @@ -1,12 +0,0 @@ -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum UriError { - #[error("HTTP error: {0}")] - Http(#[from] tauri::http::Error), - - #[error("Cache error: {0}")] - Cache(#[from] crate::cache::CacheError), -} - -pub type Result = std::result::Result; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/handler.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/handler.rs deleted file mode 100644 index 65b4c1c8..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/handler.rs +++ /dev/null @@ -1,134 +0,0 @@ -use std::sync::Arc; - -use tauri::{ - http::{Response, Uri}, - Config, -}; - -use super::error::Result; -use crate::cache::CacheManager; -use crate::mapping::HostMapper; - -pub struct UriHandler { - cache: Arc, - mapper: Arc, - config: Config, -} - -impl UriHandler { - pub fn new(cache: Arc, config: Config, mapper: Arc) -> Self { - Self { - cache, - config, - mapper, - } - } - - async fn fetch_content(&self, host: &str, path: &str) -> Result> { - let file_path = if path.is_empty() { "index.html" } else { path }; - let bundle_name = self.mapper.resolve(host); - tracing::debug!( - host = %host, - bundle = %bundle_name, - path = %path, - resolved_path = %file_path, - "Fetching file content." - ); - Ok(self.cache.get_file(&bundle_name, file_path).await?) - } - - fn determine_mime(path: &str) -> &str { - if path.is_empty() || path == "index.html" { - "text/html; charset=utf-8" - } else { - mime_guess::from_path(path) - .first_raw() - .unwrap_or("application/octet-stream") - } - } - - pub async fn handle(&self, uri: &Uri) -> Result>> { - let host = uri.host().unwrap_or_default(); - let path = uri.path().trim_start_matches('/'); - - tracing::debug!(host = %host, path = %path, "Handling request"); - - // Try to fetch the requested path. If it fails and the path looks - // like a SPA route (no file extension), fall back to index.html so - // the client-side router can handle it. - let fetch_result = match self.fetch_content(host, path).await { - Ok(content) => Ok((content, path)), - Err(e) if !path.is_empty() && !path.contains('.') => { - tracing::info!( - host = %host, - path = %path, - "Path not found and has no extension, falling back to index.html for SPA routing" - ); - self.fetch_content(host, "") - .await - .map(|content| (content, "")) - .map_err(|_| e) - } - Err(e) => Err(e), - }; - - match fetch_result { - Ok((content, resolved_path)) => { - tracing::info!(host = %host, path = %path, content_length = %content.len(), "Successfully retrieved file content"); - - let mime_type = Self::determine_mime(resolved_path); - let csp = match self.config.app.security.csp.as_ref() { - Some(csp) => { - tracing::debug!("Using configured CSP"); - csp.to_string() - } - None => { - tracing::debug!("No CSP configured, using null"); - String::from("null") - } - }; - - tracing::info!( - status = 200, - host = %host, - path = %path, - mime = %mime_type, - csp = %csp, - content_length = %content.len(), - "Building response" - ); - - let response = Response::builder() - .status(200) - .header("content-type", mime_type) - .header("content-security-policy", csp) - .header("access-control-allow-credentials", "true") - .header("x-content-type-options", "nosniff") - .body(content); - - tracing::info!("Sending response"); - - response - } - Err(e) => { - tracing::error!( - error = %e, - host = %host, - path = %path, - "Failed to retrieve file content" - ); - - Response::builder().status(404).body(Vec::new()) - } - } - .map_err(|e| { - tracing::error!( - error = %e, - host = %host, - path = %path, - "Failed to build response" - ); - e.into() - }) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/mod.rs deleted file mode 100644 index c0ab89c8..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/uri/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod error; -pub mod handler; - -pub use handler::UriHandler; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/config.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/config.rs deleted file mode 100644 index b839ce79..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/config.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::fs; -use std::path::PathBuf; -use std::sync::Arc; - -use tauri::Config as TauriConfig; - -use crate::{ - bundle::VerifiedBundle, cache::CacheManager, storage::StorageManager, vendor::VendorError, - Manifest, -}; - -use super::Result; - -const VENDOR_SOURCE: &str = "vendor"; - -#[derive(Debug, Clone, Default)] -pub struct VendorConfig { - pub bundle_path: PathBuf, - pub manifest_path: PathBuf, -} - -impl VendorConfig { - pub async fn initialize( - &self, - config: TauriConfig, - cache: Arc, - storage: Arc, - ) -> Result<()> { - let content = fs::read(&self.bundle_path).map_err(|e| VendorError::Io(e))?; - - let manifest_str = - fs::read_to_string(&self.manifest_path).map_err(|e| VendorError::Io(e))?; - - let manifest: Manifest = - serde_json::from_str(&manifest_str).map_err(|e| VendorError::Json(e))?; - - let max_bundle_size = 100 * 1024 * 1024; - if content.len() > max_bundle_size { - return Err(VendorError::InvalidData(format!( - "Bundle too large: {} bytes (max: {} bytes)", - content.len(), - max_bundle_size - ))); - } - - let name = config - .product_name - .unwrap_or("unknown".to_string()) - .to_lowercase(); - let version = manifest - .version - .clone() - .unwrap_or_else(|| config.version.as_deref().unwrap_or("0.0.0").to_string()); - - tracing::info!( - name = %name, - version = %version, - size = content.len(), - "Initializing vendored bundle" - ); - - let verified = VerifiedBundle::trust(content, manifest)?; - - // NOTE: This is temporary, to make sure bundle verifier - // has required file at the location, - // won't be necessary after source refactor. - storage - .store_bundle(&name, VENDOR_SOURCE, &version, &verified) - .await?; - - cache.cache_bundle(&name, &verified).await?; - - tracing::info!( - name = %name, - "Vendored bundle initialized successfully" - ); - Ok(()) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/error.rs deleted file mode 100644 index 2c7f8eed..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/error.rs +++ /dev/null @@ -1,27 +0,0 @@ -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum VendorError { - #[error("Invalid vendor data: {0}")] - InvalidData(String), - - #[error("JSON error: {0}")] - Json(#[from] serde_json::Error), - - #[error("IO error: {0}")] - Io(#[from] std::io::Error), - - #[error("Zip error: {0}")] - Zip(#[from] zip::result::ZipError), - - #[error("Bundle error: {0}")] - Bundle(#[from] crate::bundle::BundleError), - - #[error("Storage error: {0}")] - Storage(#[from] crate::storage::StorageError), - - #[error("Cache error: {0}")] - Cache(#[from] crate::cache::CacheError), -} - -pub type Result = std::result::Result; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/mod.rs deleted file mode 100644 index 2e6dfc9d..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/vendor/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod config; -mod error; - -pub use config::VendorConfig; -pub use error::{Result, VendorError}; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/bundle.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/bundle.rs deleted file mode 100644 index 53eae098..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/bundle.rs +++ /dev/null @@ -1,32 +0,0 @@ -use super::error::Result; -use super::key::KeyManager; -use crate::BundleMetadata; - -#[derive(Debug, Clone)] -pub struct BundleVerifier { - key_manager: KeyManager, -} - -impl BundleVerifier { - pub fn new(key_manager: KeyManager) -> Self { - Self { key_manager } - } - - pub async fn verify_bundle(&self, content: &[u8], metadata: &BundleMetadata) -> Result<()> { - tracing::info!( - file_count = metadata.manifest.files.len(), - "Verifying bundle signature" - ); - - self.key_manager - .verify_signature(content, &metadata.signature) - .await - .map_err(|e| { - tracing::error!( - error = %e, - "Signature verification failed" - ); - e - }) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/error.rs deleted file mode 100644 index 60283b81..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/error.rs +++ /dev/null @@ -1,40 +0,0 @@ -use thiserror::Error; - -pub type Result = std::result::Result; - -#[derive(Debug, Error)] -pub enum VerificationError { - #[error("Invalid signature")] - InvalidSignature, - - #[error("Invalid file hash: expected {expected}, got {actual}")] - InvalidHash { expected: String, actual: String }, - - #[error("Key validation failed: {0}")] - KeyValidation(String), - - #[error("Invalid key format: {0}")] - InvalidKeyFormat(String), - - #[error("Invalid key length: {0}")] - InvalidKeyLength(String), - - #[error(transparent)] - Base64(#[from] base64::DecodeError), - - #[error(transparent)] - Ed25519(#[from] ed25519_dalek::SignatureError), - - #[error(transparent)] - Io(#[from] std::io::Error), -} - -impl VerificationError { - pub fn is_key_error(&self) -> bool { - matches!(self, Self::KeyValidation(_)) - } - - pub fn is_verification_error(&self) -> bool { - matches!(self, Self::InvalidSignature | Self::InvalidHash { .. }) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/file.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/file.rs deleted file mode 100644 index ad452b21..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/file.rs +++ /dev/null @@ -1,52 +0,0 @@ -use base64::{engine::general_purpose::STANDARD, Engine}; -use blake3::Hash; - -use super::error::{Result, VerificationError}; - -#[derive(Debug)] -pub struct FileVerifier; - -impl FileVerifier { - pub fn verify(data: &[u8], expected_hash: &Hash) -> Result<()> { - tracing::debug!("Starting hash verification of file data."); - let actual_hash = blake3::hash(data); - - if actual_hash != *expected_hash { - let expected_hash_b64 = STANDARD.encode(expected_hash.as_bytes()); - let actual_hash_b64 = STANDARD.encode(actual_hash.as_bytes()); - - tracing::error!( - expected_hash = %expected_hash_b64, - actual_hash = %actual_hash_b64, - "Hash verification failed." - ); - - return Err(VerificationError::InvalidHash { - expected: expected_hash_b64, - actual: actual_hash_b64, - }); - } - - tracing::debug!("Hash verification succeeded."); - Ok(()) - } - - pub fn hash(data: &[u8]) -> Hash { - tracing::debug!("Calculating hash for given data."); - blake3::hash(data) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_file_verification() { - let data = b"test data"; - let hash = FileVerifier::hash(data); - - assert!(FileVerifier::verify(data, &hash).is_ok()); - assert!(FileVerifier::verify(b"wrong data", &hash).is_err()); - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/key.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/key.rs deleted file mode 100644 index 6fb89806..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/key.rs +++ /dev/null @@ -1,57 +0,0 @@ -use base64::Engine; -use ed25519_dalek::{Signature, Verifier, VerifyingKey}; - -use super::error::{Result, VerificationError}; -use crate::api::ApiClient; - -#[derive(Debug, Clone)] -pub struct KeyManager { - verified_key: VerifyingKey, - api_client: ApiClient, -} - -impl KeyManager { - pub async fn new(api_client: ApiClient) -> Result { - tracing::info!("Initializing KeyManager"); - - tracing::debug!("Retrieving verified key"); - let server_key = api_client.list_key().await.map_err(|e| { - tracing::error!(error = %e, "Failed to fetch server keys"); - VerificationError::KeyValidation(e.to_string()) - })?; - - tracing::debug!("Decoding and verifying key bytes"); - let key_bytes = base64::engine::general_purpose::STANDARD - .decode(&server_key.key) - .map_err(|e| { - tracing::error!(error = %e, "Failed to decode key bytes"); - VerificationError::InvalidKeyFormat(e.to_string()) - })?; - - let key_bytes: [u8; 32] = key_bytes.try_into().map_err(|_| { - tracing::error!("Key length is invalid"); - VerificationError::InvalidKeyLength("Expected 32 bytes".to_string()) - })?; - - let verified_key = VerifyingKey::from_bytes(&key_bytes).map_err(|e| { - tracing::error!(error = %e, "Invalid key format"); - VerificationError::InvalidKeyFormat(e.to_string()) - })?; - - tracing::debug!("Key successfully retrieved"); - - Ok(Self { - verified_key, - api_client, - }) - } - - pub async fn verify_signature(&self, data: &[u8], signature: &Signature) -> Result<()> { - tracing::info!("Verifying signature"); - let verifying_key = self.verified_key; - verifying_key.verify(data, signature).map_err(|_| { - tracing::error!("Signature verification failed"); - VerificationError::InvalidSignature - }) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/mod.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/mod.rs deleted file mode 100644 index cc2808bb..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/src/verification/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -mod bundle; -mod error; -mod file; -mod key; - -pub use bundle::BundleVerifier; -pub use error::VerificationError; -pub use file::FileVerifier; -pub use key::KeyManager; - -pub const VERIFICATION_VERSION: &str = "1.0.0"; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/tsconfig.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/tsconfig.json deleted file mode 100644 index ce47298d..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "target": "es2021", - "module": "esnext", - "moduleResolution": "bundler", - "skipLibCheck": true, - "strict": true, - "noUnusedLocals": true, - "noImplicitAny": true, - "declaration": true, - "declarationMap": true, - "outDir": "dist-js" - }, - "include": ["guest-js/*.ts"], - "exclude": ["dist-js", "node_modules"] -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/.envrc b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/.envrc deleted file mode 100644 index 894571bf..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/.envrc +++ /dev/null @@ -1,3 +0,0 @@ -source_url "https://raw.githubusercontent.com/cachix/devenv/82c0147677e510b247d8b9165c54f73d32dfd899/direnvrc" "sha256-7u4iDd1nZpxL4tCzmPG0dQgC5V+/44Ba+tHkPob1v2k=" - -use devenv diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/.gitignore b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/.gitignore deleted file mode 100644 index e9acab98..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -/.vs -.DS_Store -.Thumbs.db -*.sublime* -.idea/ -debug.log -package-lock.json -.vscode/settings.json -yarn.lock - -/.tauri -/target -node_modules/ - -# Devenv -.devenv* -devenv.local.nix - -# direnv -.direnv - -# pre-commit -.pre-commit-config.yaml diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.lock b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.lock deleted file mode 100644 index 5db8192a..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.lock +++ /dev/null @@ -1,5206 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" -dependencies = [ - "anstyle", - "once_cell", - "windows-sys 0.59.0", -] - -[[package]] -name = "anyhow" -version = "1.0.97" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" - -[[package]] -name = "atk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" -dependencies = [ - "serde", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -dependencies = [ - "objc2 0.5.2", -] - -[[package]] -name = "block2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d59b4c170e16f0405a2e95aff44432a0d41aa97675f3d52623effe95792a037" -dependencies = [ - "objc2 0.6.0", -] - -[[package]] -name = "brotli" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - -[[package]] -name = "bytemuck" -version = "1.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" -dependencies = [ - "serde", -] - -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.9.0", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror 2.0.12", -] - -[[package]] -name = "cargo_toml" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fbd1fe9db3ebf71b89060adaf7b0504c2d6a425cf061313099547e382c2e472" -dependencies = [ - "serde", - "toml", -] - -[[package]] -name = "cc" -version = "1.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" -dependencies = [ - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "num-traits", - "serde", - "windows-link", -] - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "time", - "version_check", -] - -[[package]] -name = "core-foundation" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.9.0", - "core-foundation", - "core-graphics-types", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags 2.9.0", - "core-foundation", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.100", -] - -[[package]] -name = "ctor" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.100", -] - -[[package]] -name = "curl" -version = "0.4.47" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "socket2", -] - -[[package]] -name = "curl-sys" -version = "0.4.77+curl-8.10.1" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "windows-sys 0.52.0", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.100", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "derive_more" -version = "0.99.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da29a38df43d6f156149c9b43ded5e018ddff2a855cf2cfd62e8cd7d079c69f" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.100", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.59.0", -] - -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "dlopen2" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "dpi" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" -dependencies = [ - "serde", -] - -[[package]] -name = "dtoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" - -[[package]] -name = "embed-resource" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fbc6e0d8e0c03a655b53ca813f0463d2c956bc4db8138dbc89f120b066551e3" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml", - "vswhom", - "winreg", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - -[[package]] -name = "env_filter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "jiff", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "erased-serde" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e004d887f51fcb9fef17317a2f3525c887d8aa3f4f50fed920816a688284a5b7" -dependencies = [ - "serde", - "typeid", -] - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version", -] - -[[package]] -name = "flate2" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkx11" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" -dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps", - "x11", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.13.3+wasi-0.2.2", - "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.9.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gtk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "html5ever" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "http" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.15", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "http-serde" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" -dependencies = [ - "http", - "serde", -] - -[[package]] -name = "httparse" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" - -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "httparse", - "itoa 1.0.15", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots", -] - -[[package]] -name = "hyper-util" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ico" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" -dependencies = [ - "byteorder", - "png", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", - "serde", -] - -[[package]] -name = "infer" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" -dependencies = [ - "cfb", -] - -[[package]] -name = "infer" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" -dependencies = [ - "cfb", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "jiff" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d699bc6dfc879fb1bf9bdff0d4c56f0884fc6f0d0eb0fba397a6d00cd9a6b85e" -dependencies = [ - "jiff-static", - "log", - "portable-atomic", - "portable-atomic-util", - "serde", -] - -[[package]] -name = "jiff-static" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d16e75759ee0aa64c57a56acbf43916987b20c77373cb7e808979e02b93c9f9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "json-patch" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" -dependencies = [ - "jsonptr", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "jsonptr" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.9.0", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "kuchikiki" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 1.9.3", - "matches", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.171" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.9.0", - "libc", -] - -[[package]] -name = "libz-sys" -version = "1.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "markup5ever" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" -dependencies = [ - "log", - "phf 0.10.1", - "phf_codegen 0.10.0", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", -] - -[[package]] -name = "muda" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4de14a9b5d569ca68d7c891d613b390cf5ab4f851c77aaa2f9e435555d3d9492" -dependencies = [ - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc2 0.6.0", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.0", - "once_cell", - "png", - "serde", - "thiserror 2.0.12", - "windows-sys 0.59.0", -] - -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.9.0", - "jni-sys", - "log", - "ndk-sys", - "num_enum", - "raw-window-handle", - "thiserror 1.0.69", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.6.0+11769913" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys", - "objc2-encode", -] - -[[package]] -name = "objc2" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3531f65190d9cff863b77a99857e74c314dd16bf56c538c4b57c7cbc3f3a6e59" -dependencies = [ - "objc2-encode", - "objc2-exception-helper", -] - -[[package]] -name = "objc2-app-kit" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5906f93257178e2f7ae069efb89fbd6ee94f0592740b5f8a1512ca498814d0fb" -dependencies = [ - "bitflags 2.9.0", - "block2 0.6.0", - "libc", - "objc2 0.6.0", - "objc2-cloud-kit", - "objc2-core-data", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-core-image", - "objc2-foundation 0.3.0", - "objc2-quartz-core 0.3.0", -] - -[[package]] -name = "objc2-cloud-kit" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c1948a9be5f469deadbd6bcb86ad7ff9e47b4f632380139722f7d9840c0d42c" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", -] - -[[package]] -name = "objc2-core-data" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f860f8e841f6d32f754836f51e6bc7777cd7e7053cf18528233f6811d3eceb4" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dca602628b65356b6513290a21a6405b4d4027b8b250f0b98dddbb28b7de02" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-foundation", - "objc2-io-surface", -] - -[[package]] -name = "objc2-core-image" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ffa6bea72bf42c78b0b34e89c0bafac877d5f80bf91e159a5d96ea7f693ca56" -dependencies = [ - "objc2 0.6.0", - "objc2-foundation 0.3.0", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-exception-helper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" -dependencies = [ - "cc", -] - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.9.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a21c6c9014b82c39515db5b396f91645182611c97d24637cf56ac01e5f8d998" -dependencies = [ - "bitflags 2.9.0", - "block2 0.6.0", - "libc", - "objc2 0.6.0", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-surface" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "161a8b87e32610086e1a7a9e9ec39f84459db7b3a0881c1f16ca5a2605581c19" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.9.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.9.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb3794501bb1bee12f08dcad8c61f2a5875791ad1c6f47faa71a0f033f20071" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-foundation 0.3.0", -] - -[[package]] -name = "objc2-ui-kit" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777a571be14a42a3990d4ebedaeb8b54cd17377ec21b92e8200ac03797b3bee1" -dependencies = [ - "bitflags 2.9.0", - "objc2 0.6.0", - "objc2-core-foundation", - "objc2-foundation 0.3.0", -] - -[[package]] -name = "objc2-web-kit" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b717127e4014b0f9f3e8bba3d3f2acec81f1bde01f656823036e823ed2c94dce" -dependencies = [ - "bitflags 2.9.0", - "block2 0.6.0", - "objc2 0.6.0", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.0", -] - -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" - -[[package]] -name = "openssl" -version = "0.10.71" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" -dependencies = [ - "bitflags 2.9.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-src" -version = "300.4.2+3.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.106" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_shared 0.10.0", -] - -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher 0.3.11", -] - -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher 1.0.1", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "plist" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" -dependencies = [ - "base64 0.22.1", - "indexmap 2.8.0", - "quick-xml", - "serde", - "time", -] - -[[package]] -name = "png" -version = "0.17.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "portable-atomic" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.7", -] - -[[package]] -name = "proc-macro-crate" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" -dependencies = [ - "toml_edit 0.22.24", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quick-xml" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" -dependencies = [ - "memchr", -] - -[[package]] -name = "quinn" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" -dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.12", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "bytes", - "getrandom 0.3.1", - "lru-slab", - "rand 0.9.4", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.12", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.1", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[package]] -name = "redox_syscall" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "redox_users" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" -dependencies = [ - "getrandom 0.2.15", - "libredox", - "thiserror 2.0.12", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "relay" -version = "0.1.1" -source = "git+https://github.com/CuriousCorrelation/relay.git#ed2329e4ebb71bb984c4705aa950cb9c3f9ff931" -dependencies = [ - "bytes", - "curl", - "dashmap", - "env_logger", - "http", - "http-serde", - "infer 0.16.0", - "lazy_static", - "log", - "mime", - "openssl", - "openssl-sys", - "serde", - "serde_json", - "strum", - "thiserror 1.0.69", - "time", - "tokio-util", - "tracing", - "url", - "url-escape", - "urlencoding", -] - -[[package]] -name = "reqwest" -version = "0.12.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e327e510263980e231de548a33e63d34962d29ae61b467389a1a09627a254" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pemfile", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-rustls", - "tokio-util", - "tower", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "webpki-roots", - "windows-registry", -] - -[[package]] -name = "ring" -version = "0.17.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.15", - "libc", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustls" -version = "0.23.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" -dependencies = [ - "web-time", -] - -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schemars" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" -dependencies = [ - "dyn-clone", - "indexmap 1.9.3", - "schemars_derive", - "serde", - "serde_json", - "url", - "uuid", -] - -[[package]] -name = "schemars_derive" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e265784ad618884abaea0600a9adf15393368d840e0222d101a072f3f7534d" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.100", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "semver" -version = "1.0.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-untagged" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "299d9c19d7d466db4ab10addd5703e4c615dec2a5a16dbbafe191045e87ee66e" -dependencies = [ - "erased-serde", - "serde", - "typeid", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa 1.0.15", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa 1.0.15", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.8.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "serialize-to-javascript" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "siphasher" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" - -[[package]] -name = "socket2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "softbuffer" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" -dependencies = [ - "bytemuck", - "cfg_aliases", - "core-graphics", - "foreign-types 0.5.0", - "js-sys", - "log", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core 0.2.2", - "raw-window-handle", - "redox_syscall", - "wasm-bindgen", - "web-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "string_cache" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938d512196766101d333398efde81bc1f37b00cb42c2f8350e5df639f040bbbe" -dependencies = [ - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.11.3", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c711928715f1fe0fe509c53b43e993a9a557babc2d0a3567d0a3006f1ac931a0" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.100", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "swift-rs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" -dependencies = [ - "base64 0.21.7", - "serde", - "serde_json", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml", - "version-compare", -] - -[[package]] -name = "tao" -version = "0.32.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63c8b1020610b9138dd7b1e06cf259ae91aa05c30f3bd0d6b42a03997b92dec1" -dependencies = [ - "bitflags 2.9.0", - "core-foundation", - "core-graphics", - "crossbeam-channel", - "dispatch", - "dlopen2", - "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni", - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc2 0.6.0", - "objc2-app-kit", - "objc2-foundation 0.3.0", - "once_cell", - "parking_lot", - "raw-window-handle", - "scopeguard", - "tao-macros", - "unicode-segmentation", - "url", - "windows", - "windows-core 0.60.1", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "tauri" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be747b26bf28674977fac47bdf6963fd9c7578271c3fbeb25d8686de6596f35" -dependencies = [ - "anyhow", - "bytes", - "dirs", - "dunce", - "embed_plist", - "futures-util", - "getrandom 0.2.15", - "glob", - "gtk", - "heck 0.5.0", - "http", - "jni", - "libc", - "log", - "mime", - "muda", - "objc2 0.6.0", - "objc2-app-kit", - "objc2-foundation 0.3.0", - "percent-encoding", - "plist", - "raw-window-handle", - "reqwest", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "swift-rs", - "tauri-build", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "thiserror 2.0.12", - "tokio", - "tray-icon", - "url", - "urlpattern", - "webkit2gtk", - "webview2-com", - "window-vibrancy", - "windows", -] - -[[package]] -name = "tauri-build" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51a2e96f3c0baa0581656bb58e6fdd0f7c9c31eaf6721a0c08689d938fe85f2d" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs", - "glob", - "heck 0.5.0", - "json-patch", - "schemars", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml", - "walkdir", -] - -[[package]] -name = "tauri-codegen" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e357ec3daf8faad1029bc7109e7f5b308ceb63b6073d110d7388923a4cce5e55" -dependencies = [ - "base64 0.22.1", - "brotli", - "ico", - "json-patch", - "plist", - "png", - "proc-macro2", - "quote", - "semver", - "serde", - "serde_json", - "sha2", - "syn 2.0.100", - "tauri-utils", - "thiserror 2.0.12", - "time", - "url", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-macros" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447ee4dd94690d77f1422f2b57e783c654ba75c535ad6f6e727887330804fff2" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.100", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad3021d8e60ec7672f51ecb67c5e1a514a4d7a9a5ffc9d85090739378047502" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars", - "serde", - "serde_json", - "tauri-utils", - "toml", - "walkdir", -] - -[[package]] -name = "tauri-plugin-relay" -version = "0.1.0" -dependencies = [ - "relay", - "serde", - "tauri", - "tauri-plugin", - "thiserror 2.0.12", - "tracing", -] - -[[package]] -name = "tauri-runtime" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e758a405ab39e25f4d1235c5f06fe563f44b01ee18bbe38ddec5356d4f581908" -dependencies = [ - "dpi", - "gtk", - "http", - "jni", - "raw-window-handle", - "serde", - "serde_json", - "tauri-utils", - "thiserror 2.0.12", - "url", - "windows", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b2beb90decade4c71e8b09c9e4a9245837a8a97693f945b77e32baf13f51fec" -dependencies = [ - "gtk", - "http", - "jni", - "log", - "objc2 0.6.0", - "objc2-app-kit", - "objc2-foundation 0.3.0", - "once_cell", - "percent-encoding", - "raw-window-handle", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "url", - "webkit2gtk", - "webview2-com", - "windows", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "107a959dbd5ff53d89a98f6f2e3e987c611334141a43630caae1d80e79446dd6" -dependencies = [ - "brotli", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "html5ever", - "http", - "infer 0.19.0", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.3", - "proc-macro2", - "quote", - "regex", - "schemars", - "semver", - "serde", - "serde-untagged", - "serde_json", - "serde_with", - "swift-rs", - "thiserror 2.0.12", - "toml", - "url", - "urlpattern", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-winres" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56eaa45f707bedf34d19312c26d350bc0f3c59a47e58e8adbeecdc850d2c13a0" -dependencies = [ - "embed-resource", - "toml", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "time" -version = "0.3.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad298b01a40a23aac4580b67e3dbedb7cc8402f3592d7f49469de2ea4aecdd8" -dependencies = [ - "deranged", - "itoa 1.0.15", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" - -[[package]] -name = "time-macros" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.44.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit 0.22.24", -] - -[[package]] -name = "toml_datetime" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.8.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.20.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" -dependencies = [ - "indexmap 2.8.0", - "toml_datetime", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" -dependencies = [ - "indexmap 2.8.0", - "serde", - "serde_spanned", - "toml_datetime", - "winnow 0.7.4", -] - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tray-icon" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d433764348e7084bad2c5ea22c96c71b61b17afe3a11645710f533bd72b6a2b5" -dependencies = [ - "crossbeam-channel", - "dirs", - "libappindicator", - "muda", - "objc2 0.6.0", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.0", - "once_cell", - "png", - "serde", - "thiserror 2.0.12", - "windows-sys 0.59.0", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typeid" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7d623258602320d5c55d1bc22793b57daff0ec7efc270ea7d55ce1d5f5471c" - -[[package]] -name = "typenum" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "url-escape" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e0ce4d1246d075ca5abec4b41d33e87a6054d08e2366b63205665e950db218" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "urlpattern" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" -dependencies = [ - "regex", - "serde", - "unic-ucd-ident", - "url", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" -dependencies = [ - "getrandom 0.3.1", - "serde", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb067e4cbd1ff067d1df46c9194b5de0e98efd2810bbc95c5d5e5f25a3231150" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi" -version = "0.13.3+wasi-0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.100", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webkit2gtk" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps", -] - -[[package]] -name = "webpki-roots" -version = "0.26.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webview2-com" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d606f600e5272b514dbb66539dd068211cc20155be8d3958201b4b5bd79ed3" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows", - "windows-core 0.60.1", - "windows-implement", - "windows-interface", -] - -[[package]] -name = "webview2-com-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "webview2-com-sys" -version = "0.36.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfb27fccd3c27f68e9a6af1bcf48c2d82534b8675b83608a4d81446d095a17ac" -dependencies = [ - "thiserror 2.0.12", - "windows", - "windows-core 0.60.1", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.48.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "window-vibrancy" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" -dependencies = [ - "objc2 0.6.0", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.0", - "raw-window-handle", - "windows-sys 0.59.0", - "windows-version", -] - -[[package]] -name = "windows" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf874e74c7a99773e62b1c671427abf01a425e77c3d3fb9fb1e4883ea934529" -dependencies = [ - "windows-collections", - "windows-core 0.60.1", - "windows-future", - "windows-link", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5467f79cc1ba3f52ebb2ed41dbb459b8e7db636cc3429458d9a852e15bc24dec" -dependencies = [ - "windows-core 0.60.1", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.60.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca21a92a9cae9bf4ccae5cf8368dce0837100ddf6e6d57936749e85f152f6247" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-link", - "windows-result", - "windows-strings", -] - -[[package]] -name = "windows-future" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a787db4595e7eb80239b74ce8babfb1363d8e343ab072f2ffe901400c03349f0" -dependencies = [ - "windows-core 0.60.1", - "windows-link", -] - -[[package]] -name = "windows-implement" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-interface" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "windows-link" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" - -[[package]] -name = "windows-numerics" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "005dea54e2f6499f2cee279b8f703b3cf3b5734a2d8d21867c8f44003182eeed" -dependencies = [ - "windows-core 0.60.1", - "windows-link", -] - -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result", - "windows-strings", - "windows-targets 0.53.0", -] - -[[package]] -name = "windows-result" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows-version" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bfbcc4996dd183ff1376a20ade1242da0d2dcaff83cc76710a588d24fd4c5db" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" -dependencies = [ - "bitflags 2.9.0", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "wry" -version = "0.50.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "804a7d1613bd699beccaa60f3b3c679acee21cebba1945a693f5eab95c08d1fa" -dependencies = [ - "base64 0.22.1", - "block2 0.6.0", - "cookie", - "crossbeam-channel", - "dpi", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http", - "javascriptcore-rs", - "jni", - "kuchikiki", - "libc", - "ndk", - "objc2 0.6.0", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-foundation 0.3.0", - "objc2-ui-kit", - "objc2-web-kit", - "once_cell", - "percent-encoding", - "raw-window-handle", - "sha2", - "soup3", - "tao-macros", - "thiserror 2.0.12", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows", - "windows-core 0.60.1", - "windows-version", - "x11-dl", -] - -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "synstructure", -] - -[[package]] -name = "zerocopy" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] - -[[package]] -name = "zerofrom" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.100", -] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.toml deleted file mode 100644 index 8411c612..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "tauri-plugin-relay" -version = "0.1.0" -authors = [ "CuriousCorrelation" ] -description = "" -edition = "2021" -rust-version = "1.77.2" -exclude = ["/examples", "/webview-dist", "/webview-src", "/node_modules"] -links = "tauri-plugin-relay" - -[dependencies] -tauri = { version = "2.1.0" } -serde = "1.0" -thiserror = "2" -tracing = "0.1.41" -relay = { git = "https://github.com/CuriousCorrelation/relay.git" } - -[build-dependencies] -tauri-plugin = { version = "2.0.2", features = ["build"] } diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/LICENSE.md b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/LICENSE.md deleted file mode 100644 index 24bfc7fe..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 - CuriousCorrelation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/README.md b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/README.md deleted file mode 100644 index b0fba6ac..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/README.md +++ /dev/null @@ -1,129 +0,0 @@ -# Tauri Plugin: Relay - -> A HTTP request-response relay plugin for Tauri apps, providing advanced request handling capabilities including custom headers, certificates, proxies, and local system integration. - -
- -![GitHub License MIT](https://img.shields.io/github/license/CuriousCorrelation/tauri-plugin-relay) -![Tauri 2.0](https://img.shields.io/badge/Tauri-2.0-blue) -[![Rust](https://img.shields.io/badge/Rust-1.77.2+-orange)](https://www.rust-lang.org) - -
- -## Features - -- 🦀 Blazingly fast! -- HTTP client built on libcurl -- Security with SSL/TLS certificate management -- Proxy support -- Multiple authentication methods (Basic, Bearer, Digest) -- Content handling (JSON, Form Data, Binary) -- Async request execution with cancellation support - -## Installation - -> [!IMPORTANT] -> This plugin requires Tauri 2.0 or later. - -Add the plugin to your project by installing directly from GitHub: - -```toml -[dependencies] -tauri-plugin-relay = { git = "https://github.com/CuriousCorrelation/tauri-plugin-relay" } -``` -``` json -"dependencies": { - "@CuriousCorrelation/plugin-relay": "github:CuriousCorrelation/tauri-plugin-relay" -} -``` - -## Quick Start - -### Rust - -```rust -fn main() { - tauri::Builder::default() - .plugin(tauri_plugin_relay::init()) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); -} -``` - -### JavaScript/TypeScript - -```typescript -import { execute, cancel } from '@CuriousCorrelation/plugin-relay' - -// Execute a request -const result = await execute({ - id: 1, - url: "https://api.example.com/data", - method: "POST", - headers: { - "Content-Type": ["application/json"] - }, - content: { - kind: "json", - content: { hello: "world" } - } -}) - -// Cancel a request -await cancel(1) -``` - -## Content Types - -The plugin supports multiple content types for requests: - -| Type | Description | -|------|-------------| -| `text` | Plain text content | -| `json` | JSON data with automatic parsing | -| `form` | Multipart form data with file support | -| `binary` | Raw binary data with optional MIME type | -| `urlencoded` | URL-encoded form data | - -## Authentication - -Built-in support for various authentication methods: - -| Method | Description | -|--------|-------------| -| `basic` | Basic HTTP authentication | -| `bearer` | Bearer token authentication | -| `digest` | Digest authentication (MD5, SHA-256, SHA-512) | - -## Security - -The plugin provides extensive security options: - -- Client certificate support (PEM, PKCS#12) -- Custom CA certificates -- Certificate validation control -- Host verification settings - -## Development - -Requirements: -- Rust 1.77.2 or later -- Node.js 18 or later -- pnpm -- libcurl with SSL support - -## Error Handling - -The plugin provides detailed error information for: - -- Network failures -- Certificate issues -- Timeout scenarios -- Parse errors -- Request cancellations - -## License - -Code: (c) 2024 - CuriousCorrelation - -MIT or MIT/Apache 2.0 where applicable. diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/build.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/build.rs deleted file mode 100644 index 339053a6..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/build.rs +++ /dev/null @@ -1,8 +0,0 @@ -const COMMANDS: &[&str] = &["execute", "cancel", "subscribe"]; - -fn main() { - tauri_plugin::Builder::new(COMMANDS) - .android_path("android") - .ios_path("ios") - .build(); -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.lock b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.lock deleted file mode 100644 index 03df3f3b..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.lock +++ /dev/null @@ -1,105 +0,0 @@ -{ - "nodes": { - "devenv": { - "locked": { - "dir": "src/modules", - "lastModified": 1776802132, - "narHash": "sha256-2yO2SGA7zVFYKe0qyJjdg7WHuMOKNwTQmigL7ydD8hI=", - "owner": "cachix", - "repo": "devenv", - "rev": "91affc7a7b6646852a0079678eadf12ac5029d9d", - "type": "github" - }, - "original": { - "dir": "src/modules", - "owner": "cachix", - "repo": "devenv", - "type": "github" - } - }, - "fenix": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ], - "rust-analyzer-src": "rust-analyzer-src" - }, - "locked": { - "lastModified": 1776845169, - "narHash": "sha256-Ya6Ba5oC0+PK1TSU4Rkjpoca73mUp6FoHQV5QGnqbx0=", - "owner": "nix-community", - "repo": "fenix", - "rev": "f0b5be1fa2891221ba8b48784f8fded5ef15301f", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "fenix", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1776329215, - "narHash": "sha256-a8BYi3mzoJ/AcJP8UldOx8emoPRLeWqALZWu4ZvjPXw=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "b86751bc4085f48661017fa226dee99fab6c651b", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "devenv": "devenv", - "fenix": "fenix", - "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay" - } - }, - "rust-analyzer-src": { - "flake": false, - "locked": { - "lastModified": 1776800521, - "narHash": "sha256-f8YJfwAOsLFpIoqZuX3yF69UvMLrkx7iVzMH1pJU7cM=", - "owner": "rust-lang", - "repo": "rust-analyzer", - "rev": "8954b66d43225e62c92e8bbcc8500191b5cceb1e", - "type": "github" - }, - "original": { - "owner": "rust-lang", - "ref": "nightly", - "repo": "rust-analyzer", - "type": "github" - } - }, - "rust-overlay": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1776827647, - "narHash": "sha256-sYixYhp5V8jCajO8TRorE4fzs7IkL4MZdfLTKgkPQBk=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "40e6ccc06e1245a4837cbbd6bdda64e21cc67379", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.nix b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.nix deleted file mode 100644 index c6f1f7a1..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.nix +++ /dev/null @@ -1,85 +0,0 @@ -{ pkgs, lib, config, inputs, ... }: - -let - rosettaPkgs = - if pkgs.stdenv.isDarwin && pkgs.stdenv.isAarch64 - then pkgs.pkgsx86_64Darwin - else pkgs; - - darwinPackages = with pkgs; [ - apple-sdk - ]; - - linuxPackages = with pkgs; [ - libsoup_3 - webkitgtk_4_1 - librsvg - libappindicator - libayatana-appindicator - ]; - -in { - packages = with pkgs; [ - git - nodejs_22 - typescript-language-server - vue-language-server - cargo-edit - ] ++ lib.optionals pkgs.stdenv.isDarwin darwinPackages - ++ lib.optionals pkgs.stdenv.isLinux linuxPackages; - - env = { - APP_GREET = "Hi!"; - } // lib.optionalAttrs pkgs.stdenv.isLinux { - LD_LIBRARY_PATH = lib.makeLibraryPath [ - pkgs.libappindicator - pkgs.libayatana-appindicator - ]; - } // lib.optionalAttrs pkgs.stdenv.isDarwin { - # Place to put macOS-specific environment variables - }; - - scripts = { - hello.exec = "echo hello from $APP_GREET"; - e.exec = "emacs"; - }; - - enterShell = '' - git --version - ${lib.optionalString pkgs.stdenv.isDarwin '' - # Place to put macOS-specific shell initialization - ''} - ${lib.optionalString pkgs.stdenv.isLinux '' - # Place to put Linux-specific shell initialization - ''} - ''; - - enterTest = '' - echo "Running tests" - ''; - - dotenv.enable = true; - - languages = { - typescript.enable = true; - javascript = { - enable = true; - pnpm.enable = true; - npm.enable = true; - }; - rust = { - enable = true; - channel = "nightly"; - components = [ - "rustc" - "cargo" - "clippy" - "rustfmt" - "rust-analyzer" - "llvm-tools-preview" - "rust-src" - "rustc-codegen-cranelift-preview" - ]; - }; - }; -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.yaml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.yaml deleted file mode 100644 index d0169201..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/devenv.yaml +++ /dev/null @@ -1,14 +0,0 @@ -inputs: - fenix: - url: github:nix-community/fenix - inputs: - nixpkgs: - follows: nixpkgs - nixpkgs: - url: github:NixOS/nixpkgs/nixpkgs-unstable - rust-overlay: - url: github:oxalica/rust-overlay - inputs: - nixpkgs: - follows: nixpkgs -allowUnfree: true diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.cjs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.cjs deleted file mode 100644 index 06b05fc4..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.cjs +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -var core = require('@tauri-apps/api/core'); - -exports.MediaType = void 0; -(function (MediaType) { - MediaType["TEXT_PLAIN"] = "text/plain"; - MediaType["TEXT_HTML"] = "text/html"; - MediaType["TEXT_CSS"] = "text/css"; - MediaType["TEXT_CSV"] = "text/csv"; - MediaType["APPLICATION_JSON"] = "application/json"; - MediaType["APPLICATION_LD_JSON"] = "application/ld+json"; - MediaType["APPLICATION_XML"] = "application/xml"; - MediaType["TEXT_XML"] = "text/xml"; - MediaType["APPLICATION_FORM"] = "application/x-www-form-urlencoded"; - MediaType["APPLICATION_OCTET"] = "application/octet-stream"; - MediaType["MULTIPART_FORM"] = "multipart/form-data"; -})(exports.MediaType || (exports.MediaType = {})); -async function execute(request) { - return await core.invoke('plugin:relay|execute', { request }); -} -async function cancel(requestId) { - return await core.invoke('plugin:relay|cancel', { requestId }); -} - -exports.cancel = cancel; -exports.execute = execute; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.d.ts b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.d.ts deleted file mode 100644 index 4c3e5041..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.d.ts +++ /dev/null @@ -1,234 +0,0 @@ -export type Method = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS" | "CONNECT" | "TRACE"; -export type Version = "HTTP/1.0" | "HTTP/1.1" | "HTTP/2.0" | "HTTP/3.0"; -export type StatusCode = 100 | 101 | 102 | 103 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 226 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 421 | 422 | 423 | 424 | 425 | 426 | 428 | 429 | 431 | 451 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 510 | 511; -export type FormDataValue = { - kind: "text"; - value: string; -} | { - kind: "file"; - filename: string; - contentType: string; - data: Uint8Array; -}; -export type FormData = [string, FormDataValue[]][]; -export declare enum MediaType { - TEXT_PLAIN = "text/plain", - TEXT_HTML = "text/html", - TEXT_CSS = "text/css", - TEXT_CSV = "text/csv", - APPLICATION_JSON = "application/json", - APPLICATION_LD_JSON = "application/ld+json", - APPLICATION_XML = "application/xml", - TEXT_XML = "text/xml", - APPLICATION_FORM = "application/x-www-form-urlencoded", - APPLICATION_OCTET = "application/octet-stream", - MULTIPART_FORM = "multipart/form-data" -} -export type ContentType = { - kind: "text"; - content: string; - mediaType: MediaType.TEXT_PLAIN | MediaType.TEXT_HTML | MediaType.TEXT_CSS | MediaType.TEXT_CSV; -} | { - kind: "json"; - content: unknown; - mediaType: MediaType.APPLICATION_JSON | MediaType.APPLICATION_LD_JSON; -} | { - kind: "xml"; - content: string; - mediaType: MediaType.APPLICATION_XML | MediaType.TEXT_XML; -} | { - kind: "form"; - content: FormData; - mediaType: MediaType.APPLICATION_FORM; -} | { - kind: "binary"; - content: Uint8Array; - mediaType: MediaType.APPLICATION_OCTET | string; - filename?: string; -} | { - kind: "multipart"; - content: FormData; - mediaType: MediaType.MULTIPART_FORM; -} | { - kind: "urlencoded"; - content: string; - mediaType: MediaType.APPLICATION_FORM; -} | { - kind: "stream"; - content: ReadableStream; - mediaType: string; -}; -export interface ResponseBody { - body: Uint8Array; - mediaType: MediaType | string; -} -export type AuthType = { - kind: "none"; -} | { - kind: "basic"; - username: string; - password: string; -} | { - kind: "bearer"; - token: string; -} | { - kind: "digest"; - username: string; - password: string; - realm?: string; - nonce?: string; - opaque?: string; - algorithm?: "MD5" | "SHA-256" | "SHA-512"; - qop?: "auth" | "auth-int"; - nc?: string; - cnonce?: string; -} | { - kind: "oauth2"; - grantType: { - kind: "authorization_code"; - authEndpoint: string; - tokenEndpoint: string; - clientId: string; - clientSecret?: string; - } | { - kind: "client_credentials"; - tokenEndpoint: string; - clientId: string; - clientSecret?: string; - } | { - kind: "password"; - tokenEndpoint: string; - username: string; - password: string; - } | { - kind: "implicit"; - authEndpoint: string; - clientId: string; - }; - accessToken?: string; - refreshToken?: string; -} | { - kind: "apikey"; - key: string; - value: string; - in: "header" | "query"; -} | { - kind: "aws"; - accessKey: string; - secretKey: string; - region: string; - service: string; - sessionToken?: string; - in: "header" | "query"; -}; -export type CertificateType = { - kind: "pem"; - cert: Uint8Array; - key: Uint8Array; -} | { - kind: "pfx"; - data: Uint8Array; - password: string; -}; -export interface RequestOptions { - timeout?: number; - followRedirects?: boolean; - maxRedirects?: number; - decompress?: boolean; - cookies?: boolean; - keepAlive?: boolean; -} -export interface RequestMeta { - options?: RequestOptions; -} -export interface Request { - id: number; - url: string; - method: Method; - version: Version; - headers?: Record; - params?: Record; - content?: ContentType; - auth?: AuthType; - security?: { - certificates?: { - client?: CertificateType; - ca?: Array; - }; - verifyHost?: boolean; - verifyPeer?: boolean; - }; - proxy?: { - url: string; - auth?: { - username: string; - password: string; - }; - }; - meta?: RequestMeta; -} -export interface Response { - id: number; - status: StatusCode; - statusText: string; - version: Version; - headers: Record; - cookies?: Array<{ - name: string; - value: string; - domain?: string; - path?: string; - expires?: Date; - secure?: boolean; - httpOnly?: boolean; - sameSite?: 'Strict' | 'Lax' | 'None'; - }>; - body: ResponseBody; - meta: { - timing: { - start: number; - end: number; - }; - size: { - headers: number; - body: number; - total: number; - }; - }; -} -export type UnsupportedFeatureError = { - kind: "unsupported_feature"; - feature: string; - message: string; - relay: string; -}; -export type RelayError = UnsupportedFeatureError | { - kind: "network"; - message: string; - cause?: unknown; -} | { - kind: "timeout"; - message: string; - phase?: "connect" | "tls" | "response"; -} | { - kind: "certificate"; - message: string; - cause?: unknown; -} | { - kind: "parse"; - message: string; - cause?: unknown; -} | { - kind: "abort"; - message: string; -}; -export type RequestResult = { - kind: 'success'; - response: Response; -} | { - kind: 'error'; - error: RelayError; -}; -export declare function execute(request: Request): Promise; -export declare function cancel(requestId: number): Promise; -//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.d.ts.map b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.d.ts.map deleted file mode 100644 index d38851a2..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.d.ts.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["guest-js/index.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,MAAM,GACd,KAAK,GACL,MAAM,GACN,KAAK,GACL,QAAQ,GACR,OAAO,GACP,MAAM,GACN,SAAS,GACT,SAAS,GACT,OAAO,CAAA;AAEX,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAA;AAEvE,MAAM,MAAM,UAAU,GAChB,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,GACH,GAAG,CAAA;AAET,MAAM,MAAM,aAAa,GACnB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAA;AAE/E,MAAM,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,EAAE,CAAA;AAElD,oBAAY,SAAS;IACjB,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,gBAAgB,qBAAqB;IACrC,mBAAmB,wBAAwB;IAC3C,eAAe,oBAAoB;IACnC,QAAQ,aAAa;IACrB,gBAAgB,sCAAsC;IACtD,iBAAiB,6BAA6B;IAC9C,cAAc,wBAAwB;CACzC;AAED,MAAM,MAAM,WAAW,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,UAAU,GAAG,SAAS,CAAC,SAAS,GAAG,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,QAAQ,CAAA;CAAE,GAClI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,gBAAgB,GAAG,SAAS,CAAC,mBAAmB,CAAA;CAAE,GACzG;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,eAAe,GAAG,SAAS,CAAC,QAAQ,CAAA;CAAE,GAC3F;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,gBAAgB,CAAA;CAAE,GAC1E;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,iBAAiB,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3G;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,cAAc,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,SAAS,CAAC,gBAAgB,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAA;AAEpE,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,UAAU,CAAA;IAChB,SAAS,EAAE,SAAS,GAAG,MAAM,CAAA;CAChC;AAED,MAAM,MAAM,QAAQ,GACd;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IACE,IAAI,EAAE,QAAQ,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,KAAK,GAAG,SAAS,GAAG,SAAS,CAAA;IACzC,GAAG,CAAC,EAAE,MAAM,GAAG,UAAU,CAAA;IACzB,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;CAClB,GACC;IACE,IAAI,EAAE,QAAQ,CAAA;IACd,SAAS,EACP;QACE,IAAI,EAAE,oBAAoB,CAAA;QAC1B,YAAY,EAAE,MAAM,CAAA;QACpB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,EAAE,MAAM,CAAA;QAChB,YAAY,CAAC,EAAE,MAAM,CAAA;KACxB,GACC;QACE,IAAI,EAAE,oBAAoB,CAAA;QAC1B,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,EAAE,MAAM,CAAA;QAChB,YAAY,CAAC,EAAE,MAAM,CAAA;KACxB,GACC;QACE,IAAI,EAAE,UAAU,CAAA;QAChB,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,EAAE,MAAM,CAAA;QAChB,QAAQ,EAAE,MAAM,CAAA;KACnB,GACC;QACE,IAAI,EAAE,UAAU,CAAA;QAChB,YAAY,EAAE,MAAM,CAAA;QACpB,QAAQ,EAAE,MAAM,CAAA;KACnB,CAAA;IACD,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACxB,GACC;IACE,IAAI,EAAE,QAAQ,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAA;CACzB,GACC;IACE,IAAI,EAAE,KAAK,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAA;CACzB,CAAA;AAEL,MAAM,MAAM,eAAe,GACvB;IACA,IAAI,EAAE,KAAK,CAAA;IACX,IAAI,EAAE,UAAU,CAAA;IAChB,GAAG,EAAE,UAAU,CAAA;CAChB,GACC;IACA,IAAI,EAAE,KAAK,CAAA;IACX,IAAI,EAAE,UAAU,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAA;AAEH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,cAAc,CAAA;CACzB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,OAAO,CAAC,EAAE,WAAW,CAAA;IACrB,IAAI,CAAC,EAAE,QAAQ,CAAA;IAEf,QAAQ,CAAC,EAAE;QACT,YAAY,CAAC,EAAE;YACb,MAAM,CAAC,EAAE,eAAe,CAAA;YACxB,EAAE,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,CAAA;SACvB,CAAA;QACD,UAAU,CAAC,EAAE,OAAO,CAAA;QACpB,UAAU,CAAC,EAAE,OAAO,CAAA;KACrB,CAAA;IAED,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAA;QACX,IAAI,CAAC,EAAE;YACL,QAAQ,EAAE,MAAM,CAAA;YAChB,QAAQ,EAAE,MAAM,CAAA;SACjB,CAAA;KACF,CAAA;IAED,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,UAAU,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,IAAI,EAAE,MAAM,CAAA;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,OAAO,CAAC,EAAE,IAAI,CAAA;QACd,MAAM,CAAC,EAAE,OAAO,CAAA;QAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;QAClB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAA;KACrC,CAAC,CAAA;IACF,IAAI,EAAE,YAAY,CAAA;IAElB,IAAI,EAAE;QACJ,MAAM,EAAE;YACN,KAAK,EAAE,MAAM,CAAA;YACb,GAAG,EAAE,MAAM,CAAA;SACZ,CAAA;QACD,IAAI,EAAE;YACJ,OAAO,EAAE,MAAM,CAAA;YACf,IAAI,EAAE,MAAM,CAAA;YACZ,KAAK,EAAE,MAAM,CAAA;SACd,CAAA;KACF,CAAA;CACF;AAED,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,qBAAqB,CAAA;IAC3B,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;CACd,CAAA;AAED,MAAM,MAAM,UAAU,GAClB,uBAAuB,GACvB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,GAAG,KAAK,GAAG,UAAU,CAAA;CAAE,GAC5E;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACzD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACnD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAEtC,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAA;AAExC,wBAAsB,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,CAEtE;AAED,wBAAsB,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE7D"} \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.js b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.js deleted file mode 100644 index c5f0a1ab..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/dist-js/index.js +++ /dev/null @@ -1,24 +0,0 @@ -import { invoke } from '@tauri-apps/api/core'; - -var MediaType; -(function (MediaType) { - MediaType["TEXT_PLAIN"] = "text/plain"; - MediaType["TEXT_HTML"] = "text/html"; - MediaType["TEXT_CSS"] = "text/css"; - MediaType["TEXT_CSV"] = "text/csv"; - MediaType["APPLICATION_JSON"] = "application/json"; - MediaType["APPLICATION_LD_JSON"] = "application/ld+json"; - MediaType["APPLICATION_XML"] = "application/xml"; - MediaType["TEXT_XML"] = "text/xml"; - MediaType["APPLICATION_FORM"] = "application/x-www-form-urlencoded"; - MediaType["APPLICATION_OCTET"] = "application/octet-stream"; - MediaType["MULTIPART_FORM"] = "multipart/form-data"; -})(MediaType || (MediaType = {})); -async function execute(request) { - return await invoke('plugin:relay|execute', { request }); -} -async function cancel(requestId) { - return await invoke('plugin:relay|cancel', { requestId }); -} - -export { MediaType, cancel, execute }; diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/guest-js/index.ts b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/guest-js/index.ts deleted file mode 100644 index 1a7500ff..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/guest-js/index.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { invoke } from '@tauri-apps/api/core' - -export type Method = - | "GET" // Retrieve resource - | "POST" // Create resource - | "PUT" // Replace resource - | "DELETE" // Remove resource - | "PATCH" // Modify resource - | "HEAD" // GET without body - | "OPTIONS" // Get allowed methods - | "CONNECT" // Create tunnel - | "TRACE" // Loop-back test - -export type Version = "HTTP/1.0" | "HTTP/1.1" | "HTTP/2.0" | "HTTP/3.0" - -export type StatusCode = - | 100 // Continue - | 101 // Switching Protocols - | 102 // Processing - | 103 // Early Hints - | 200 // OK - | 201 // Created - | 202 // Accepted - | 203 // Non-Authoritative Info - | 204 // No Content - | 205 // Reset Content - | 206 // Partial Content - | 207 // Multi-Status - | 208 // Already Reported - | 226 // IM Used - | 300 // Multiple Choices - | 301 // Moved Permanently - | 302 // Found - | 303 // See Other - | 304 // Not Modified - | 305 // Use Proxy - | 306 // Switch Proxy - | 307 // Temporary Redirect - | 308 // Permanent Redirect - | 400 // Bad Request - | 401 // Unauthorized - | 402 // Payment Required - | 403 // Forbidden - | 404 // Not Found - | 405 // Method Not Allowed - | 406 // Not Acceptable - | 407 // Proxy Auth Required - | 408 // Request Timeout - | 409 // Conflict - | 410 // Gone - | 411 // Length Required - | 412 // Precondition Failed - | 413 // Payload Too Large - | 414 // URI Too Long - | 415 // Unsupported Media - | 416 // Range Not Satisfiable - | 417 // Expectation Failed - | 418 // I'm a teapot - | 421 // Misdirected Request - | 422 // Unprocessable Entity - | 423 // Locked - | 424 // Failed Dependency - | 425 // Too Early - | 426 // Upgrade Required - | 428 // Precondition Required - | 429 // Too Many Requests - | 431 // Headers Too Large - | 451 // Unavailable Legal - | 500 // Server Error - | 501 // Not Implemented - | 502 // Bad Gateway - | 503 // Service Unavailable - | 504 // Gateway Timeout - | 505 // HTTP Ver. Not Supported - | 506 // Variant Negotiates - | 507 // Insufficient Storage - | 508 // Loop Detected - | 510 // Not Extended - | 511 // Network Auth Required - -export type FormDataValue = - | { kind: "text"; value: string } - | { kind: "file"; filename: string; contentType: string; data: Uint8Array } - -export type FormData = [string, FormDataValue[]][] - -export enum MediaType { - TEXT_PLAIN = "text/plain", - TEXT_HTML = "text/html", - TEXT_CSS = "text/css", - TEXT_CSV = "text/csv", - APPLICATION_JSON = "application/json", - APPLICATION_LD_JSON = "application/ld+json", - APPLICATION_XML = "application/xml", - TEXT_XML = "text/xml", - APPLICATION_FORM = "application/x-www-form-urlencoded", - APPLICATION_OCTET = "application/octet-stream", - MULTIPART_FORM = "multipart/form-data" -} - -export type ContentType = - | { kind: "text"; content: string; mediaType: MediaType.TEXT_PLAIN | MediaType.TEXT_HTML | MediaType.TEXT_CSS | MediaType.TEXT_CSV } - | { kind: "json"; content: unknown; mediaType: MediaType.APPLICATION_JSON | MediaType.APPLICATION_LD_JSON } - | { kind: "xml"; content: string; mediaType: MediaType.APPLICATION_XML | MediaType.TEXT_XML } - | { kind: "form"; content: FormData; mediaType: MediaType.APPLICATION_FORM } - | { kind: "binary"; content: Uint8Array; mediaType: MediaType.APPLICATION_OCTET | string; filename?: string } - | { kind: "multipart"; content: FormData; mediaType: MediaType.MULTIPART_FORM } - | { kind: "urlencoded"; content: string; mediaType: MediaType.APPLICATION_FORM } - | { kind: "stream"; content: ReadableStream; mediaType: string } - -export interface ResponseBody { - body: Uint8Array - mediaType: MediaType | string -} - -export type AuthType = - | { kind: "none" } - | { kind: "basic"; username: string; password: string } - | { kind: "bearer"; token: string } - | { - kind: "digest" - username: string - password: string - realm?: string - nonce?: string - opaque?: string - algorithm?: "MD5" | "SHA-256" | "SHA-512" - qop?: "auth" | "auth-int" - nc?: string - cnonce?: string - } - | { - kind: "oauth2" - grantType: - | { - kind: "authorization_code" - authEndpoint: string - tokenEndpoint: string - clientId: string - clientSecret?: string - } - | { - kind: "client_credentials" - tokenEndpoint: string - clientId: string - clientSecret?: string - } - | { - kind: "password" - tokenEndpoint: string - username: string - password: string - } - | { - kind: "implicit" - authEndpoint: string - clientId: string - } - accessToken?: string - refreshToken?: string - } - | { - kind: "apikey" - key: string - value: string - in: "header" | "query" - } - | { - kind: "aws" - accessKey: string - secretKey: string - region: string - service: string - sessionToken?: string - in: "header" | "query" - } - -export type CertificateType = - | { - kind: "pem" - cert: Uint8Array - key: Uint8Array - } - | { - kind: "pfx" - data: Uint8Array - password: string - } - -export interface RequestOptions { - timeout?: number - followRedirects?: boolean - maxRedirects?: number - decompress?: boolean - cookies?: boolean - keepAlive?: boolean -} - -export interface RequestMeta { - options?: RequestOptions -} - -export interface Request { - id: number - url: string - method: Method - version: Version - headers?: Record - params?: Record - content?: ContentType - auth?: AuthType - - security?: { - certificates?: { - client?: CertificateType - ca?: Array - } - verifyHost?: boolean - verifyPeer?: boolean - } - - proxy?: { - url: string - auth?: { - username: string - password: string - } - } - - meta?: RequestMeta -} - -export interface Response { - id: number - status: StatusCode - statusText: string - version: Version - headers: Record - cookies?: Array<{ - name: string - value: string - domain?: string - path?: string - expires?: Date - secure?: boolean - httpOnly?: boolean - sameSite?: 'Strict' | 'Lax' | 'None' - }> - body: ResponseBody - - meta: { - timing: { - start: number - end: number - } - size: { - headers: number - body: number - total: number - } - } -} - -export type UnsupportedFeatureError = { - kind: "unsupported_feature" - feature: string - message: string - relay: string -} - -export type RelayError = - | UnsupportedFeatureError - | { kind: "network"; message: string; cause?: unknown } - | { kind: "timeout"; message: string; phase?: "connect" | "tls" | "response" } - | { kind: "certificate"; message: string; cause?: unknown } - | { kind: "parse"; message: string; cause?: unknown } - | { kind: "abort"; message: string } - -export type RequestResult = - | { kind: 'success'; response: Response } - | { kind: 'error'; error: RelayError } - -export async function execute(request: Request): Promise { - return await invoke('plugin:relay|execute', { request }) -} - -export async function cancel(requestId: number): Promise { - return await invoke('plugin:relay|cancel', { requestId }) -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/package.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/package.json deleted file mode 100644 index 853e474f..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "@CuriousCorrelation/plugin-relay", - "version": "0.1.0", - "author": "CuriousCorrelation", - "description": "An HTTP request-response relay plugin for Tauri apps.", - "type": "module", - "types": "./dist-js/index.d.ts", - "main": "./dist-js/index.cjs", - "module": "./dist-js/index.js", - "exports": { - "types": "./dist-js/index.d.ts", - "import": "./dist-js/index.js", - "require": "./dist-js/index.cjs" - }, - "files": [ - "dist-js", - "README.md" - ], - "scripts": { - "build": "tsc && rollup -c", - "prepublishOnly": "pnpm build", - "pretest": "pnpm build" - }, - "dependencies": { - "@tauri-apps/api": "2.1.1" - }, - "devDependencies": { - "@rollup/plugin-typescript": "^11.1.6", - "rollup": "^4.59.0", - "tslib": "^2.6.2", - "typescript": "5.9.2" - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/cancel.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/cancel.toml deleted file mode 100644 index 91efeaa0..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/cancel.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-cancel" -description = "Enables the cancel command without any pre-configured scope." -commands.allow = ["cancel"] - -[[permission]] -identifier = "deny-cancel" -description = "Denies the cancel command without any pre-configured scope." -commands.deny = ["cancel"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/execute.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/execute.toml deleted file mode 100644 index d98be899..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/execute.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-execute" -description = "Enables the execute command without any pre-configured scope." -commands.allow = ["execute"] - -[[permission]] -identifier = "deny-execute" -description = "Denies the execute command without any pre-configured scope." -commands.deny = ["execute"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/run.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/run.toml deleted file mode 100644 index 3f5afdec..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/run.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-run" -description = "Enables the run command without any pre-configured scope." -commands.allow = ["run"] - -[[permission]] -identifier = "deny-run" -description = "Denies the run command without any pre-configured scope." -commands.deny = ["run"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/subscribe.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/subscribe.toml deleted file mode 100644 index 0277f2ae..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/commands/subscribe.toml +++ /dev/null @@ -1,13 +0,0 @@ -# Automatically generated - DO NOT EDIT! - -"$schema" = "../../schemas/schema.json" - -[[permission]] -identifier = "allow-subscribe" -description = "Enables the subscribe command without any pre-configured scope." -commands.allow = ["subscribe"] - -[[permission]] -identifier = "deny-subscribe" -description = "Denies the subscribe command without any pre-configured scope." -commands.deny = ["subscribe"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/reference.md b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/reference.md deleted file mode 100644 index d2d880f2..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/autogenerated/reference.md +++ /dev/null @@ -1,120 +0,0 @@ -## Default Permission - -Default permissions for the plugin - -- `allow-execute` -- `allow-cancel` - -## Permission Table - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
IdentifierDescription
- -`relay:allow-cancel` - - - -Enables the cancel command without any pre-configured scope. - -
- -`relay:deny-cancel` - - - -Denies the cancel command without any pre-configured scope. - -
- -`relay:allow-execute` - - - -Enables the execute command without any pre-configured scope. - -
- -`relay:deny-execute` - - - -Denies the execute command without any pre-configured scope. - -
- -`relay:allow-run` - - - -Enables the run command without any pre-configured scope. - -
- -`relay:deny-run` - - - -Denies the run command without any pre-configured scope. - -
- -`relay:allow-subscribe` - - - -Enables the subscribe command without any pre-configured scope. - -
- -`relay:deny-subscribe` - - - -Denies the subscribe command without any pre-configured scope. - -
diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/default.toml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/default.toml deleted file mode 100644 index 0b8243f3..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/default.toml +++ /dev/null @@ -1,3 +0,0 @@ -[default] -description = "Default permissions for the plugin" -permissions = ["allow-execute", "allow-cancel"] diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/schemas/schema.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/schemas/schema.json deleted file mode 100644 index eceb0f61..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/permissions/schemas/schema.json +++ /dev/null @@ -1,345 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "PermissionFile", - "description": "Permission file that can define a default permission, a set of permissions or a list of inlined permissions.", - "type": "object", - "properties": { - "default": { - "description": "The default permission set for the plugin", - "anyOf": [ - { - "$ref": "#/definitions/DefaultPermission" - }, - { - "type": "null" - } - ] - }, - "set": { - "description": "A list of permissions sets defined", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - } - }, - "definitions": { - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - }, - "description": { - "description": "Human-readable description of what the permission does. Tauri convention is to use

headings in markdown content for Tauri documentation generation purposes.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "description": { - "description": "Human-readable description of what the permission does. Tauri internal convention is to use

headings in markdown content for Tauri documentation generation purposes.", - "type": [ - "string", - "null" - ] - }, - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "platforms": { - "description": "Target platforms this permission applies. By default all platforms are affected by this permission.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Target" - } - } - } - }, - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", - "type": "object", - "properties": { - "allow": { - "description": "Allowed command.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - }, - "deny": { - "description": "Denied command, which takes priority.", - "default": [], - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "Scopes": { - "description": "An argument for fine grained behavior control of Tauri commands.\n\nIt can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command. The configured scope is passed to the command and will be enforced by the command implementation.\n\n## Example\n\n```json { \"allow\": [{ \"path\": \"$HOME/**\" }], \"deny\": [{ \"path\": \"$HOME/secret.txt\" }] } ```", - "type": "object", - "properties": { - "allow": { - "description": "Data that defines what is allowed by the scope.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - }, - "deny": { - "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "description": "Represents a null JSON value.", - "type": "null" - }, - { - "description": "Represents a [`bool`].", - "type": "boolean" - }, - { - "description": "Represents a valid ACL [`Number`].", - "allOf": [ - { - "$ref": "#/definitions/Number" - } - ] - }, - { - "description": "Represents a [`String`].", - "type": "string" - }, - { - "description": "Represents a list of other [`Value`]s.", - "type": "array", - "items": { - "$ref": "#/definitions/Value" - } - }, - { - "description": "Represents a map of [`String`] keys to [`Value`]s.", - "type": "object", - "additionalProperties": { - "$ref": "#/definitions/Value" - } - } - ] - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Target": { - "description": "Platform target.", - "oneOf": [ - { - "description": "MacOS.", - "type": "string", - "enum": [ - "macOS" - ] - }, - { - "description": "Windows.", - "type": "string", - "enum": [ - "windows" - ] - }, - { - "description": "Linux.", - "type": "string", - "enum": [ - "linux" - ] - }, - { - "description": "Android.", - "type": "string", - "enum": [ - "android" - ] - }, - { - "description": "iOS.", - "type": "string", - "enum": [ - "iOS" - ] - } - ] - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "Enables the cancel command without any pre-configured scope.", - "type": "string", - "const": "allow-cancel" - }, - { - "description": "Denies the cancel command without any pre-configured scope.", - "type": "string", - "const": "deny-cancel" - }, - { - "description": "Enables the execute command without any pre-configured scope.", - "type": "string", - "const": "allow-execute" - }, - { - "description": "Denies the execute command without any pre-configured scope.", - "type": "string", - "const": "deny-execute" - }, - { - "description": "Enables the run command without any pre-configured scope.", - "type": "string", - "const": "allow-run" - }, - { - "description": "Denies the run command without any pre-configured scope.", - "type": "string", - "const": "deny-run" - }, - { - "description": "Enables the subscribe command without any pre-configured scope.", - "type": "string", - "const": "allow-subscribe" - }, - { - "description": "Denies the subscribe command without any pre-configured scope.", - "type": "string", - "const": "deny-subscribe" - }, - { - "description": "Default permissions for the plugin", - "type": "string", - "const": "default" - } - ] - } - } -} \ No newline at end of file diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/pnpm-lock.yaml b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/pnpm-lock.yaml deleted file mode 100644 index a33fd01b..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/pnpm-lock.yaml +++ /dev/null @@ -1,325 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@tauri-apps/api': - specifier: 2.1.1 - version: 2.1.1 - devDependencies: - '@rollup/plugin-typescript': - specifier: ^11.1.6 - version: 11.1.6(rollup@4.27.4)(tslib@2.8.1)(typescript@5.9.2) - rollup: - specifier: ^4.9.6 - version: 4.27.4 - tslib: - specifier: ^2.6.2 - version: 2.8.1 - typescript: - specifier: 5.9.2 - version: 5.9.2 - -packages: - - '@rollup/plugin-typescript@11.1.6': - resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.14.0||^3.0.0||^4.0.0 - tslib: '*' - typescript: '>=3.7.0' - peerDependenciesMeta: - rollup: - optional: true - tslib: - optional: true - - '@rollup/pluginutils@5.1.3': - resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 - peerDependenciesMeta: - rollup: - optional: true - - '@rollup/rollup-android-arm-eabi@4.27.4': - resolution: {integrity: sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.27.4': - resolution: {integrity: sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.27.4': - resolution: {integrity: sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.27.4': - resolution: {integrity: sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.27.4': - resolution: {integrity: sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.27.4': - resolution: {integrity: sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.27.4': - resolution: {integrity: sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.27.4': - resolution: {integrity: sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.27.4': - resolution: {integrity: sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.27.4': - resolution: {integrity: sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.27.4': - resolution: {integrity: sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.27.4': - resolution: {integrity: sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.27.4': - resolution: {integrity: sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.27.4': - resolution: {integrity: sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.27.4': - resolution: {integrity: sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.27.4': - resolution: {integrity: sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.27.4': - resolution: {integrity: sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.27.4': - resolution: {integrity: sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==} - cpu: [x64] - os: [win32] - - '@tauri-apps/api@2.1.1': - resolution: {integrity: sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A==} - - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - - estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - is-core-module@2.15.1: - resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} - engines: {node: '>= 0.4'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - - resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true - - rollup@4.27.4: - resolution: {integrity: sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} - engines: {node: '>=14.17'} - hasBin: true - -snapshots: - - '@rollup/plugin-typescript@11.1.6(rollup@4.27.4)(tslib@2.8.1)(typescript@5.9.2)': - dependencies: - '@rollup/pluginutils': 5.1.3(rollup@4.27.4) - resolve: 1.22.8 - typescript: 5.9.2 - optionalDependencies: - rollup: 4.27.4 - tslib: 2.8.1 - - '@rollup/pluginutils@5.1.3(rollup@4.27.4)': - dependencies: - '@types/estree': 1.0.6 - estree-walker: 2.0.2 - picomatch: 4.0.2 - optionalDependencies: - rollup: 4.27.4 - - '@rollup/rollup-android-arm-eabi@4.27.4': - optional: true - - '@rollup/rollup-android-arm64@4.27.4': - optional: true - - '@rollup/rollup-darwin-arm64@4.27.4': - optional: true - - '@rollup/rollup-darwin-x64@4.27.4': - optional: true - - '@rollup/rollup-freebsd-arm64@4.27.4': - optional: true - - '@rollup/rollup-freebsd-x64@4.27.4': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.27.4': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.27.4': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.27.4': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.27.4': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.27.4': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.27.4': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.27.4': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.27.4': - optional: true - - '@rollup/rollup-linux-x64-musl@4.27.4': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.27.4': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.27.4': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.27.4': - optional: true - - '@tauri-apps/api@2.1.1': {} - - '@types/estree@1.0.6': {} - - estree-walker@2.0.2: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - is-core-module@2.15.1: - dependencies: - hasown: 2.0.2 - - path-parse@1.0.7: {} - - picomatch@4.0.2: {} - - resolve@1.22.8: - dependencies: - is-core-module: 2.15.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - rollup@4.27.4: - dependencies: - '@types/estree': 1.0.6 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.27.4 - '@rollup/rollup-android-arm64': 4.27.4 - '@rollup/rollup-darwin-arm64': 4.27.4 - '@rollup/rollup-darwin-x64': 4.27.4 - '@rollup/rollup-freebsd-arm64': 4.27.4 - '@rollup/rollup-freebsd-x64': 4.27.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.27.4 - '@rollup/rollup-linux-arm-musleabihf': 4.27.4 - '@rollup/rollup-linux-arm64-gnu': 4.27.4 - '@rollup/rollup-linux-arm64-musl': 4.27.4 - '@rollup/rollup-linux-powerpc64le-gnu': 4.27.4 - '@rollup/rollup-linux-riscv64-gnu': 4.27.4 - '@rollup/rollup-linux-s390x-gnu': 4.27.4 - '@rollup/rollup-linux-x64-gnu': 4.27.4 - '@rollup/rollup-linux-x64-musl': 4.27.4 - '@rollup/rollup-win32-arm64-msvc': 4.27.4 - '@rollup/rollup-win32-ia32-msvc': 4.27.4 - '@rollup/rollup-win32-x64-msvc': 4.27.4 - fsevents: 2.3.3 - - supports-preserve-symlinks-flag@1.0.0: {} - - tslib@2.8.1: {} - - typescript@5.9.2: {} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/rollup.config.js b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/rollup.config.js deleted file mode 100644 index d8343635..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/rollup.config.js +++ /dev/null @@ -1,31 +0,0 @@ -import { readFileSync } from 'fs' -import { join } from 'path' -import { cwd } from 'process' -import typescript from '@rollup/plugin-typescript' - -const pkg = JSON.parse(readFileSync(join(cwd(), 'package.json'), 'utf8')) - -export default { - input: 'guest-js/index.ts', - output: [ - { - file: pkg.exports.import, - format: 'esm' - }, - { - file: pkg.exports.require, - format: 'cjs' - } - ], - plugins: [ - typescript({ - declaration: true, - declarationDir: `./${pkg.exports.import.split('/')[0]}` - }) - ], - external: [ - /^@tauri-apps\/api/, - ...Object.keys(pkg.dependencies || {}), - ...Object.keys(pkg.peerDependencies || {}) - ] -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/commands.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/commands.rs deleted file mode 100644 index 73da002e..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/commands.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::{models::*, RelayExt, Result}; -use tauri::{command, AppHandle, Runtime}; - -#[command] -pub(crate) async fn execute( - app: AppHandle, - request: RunRequest, -) -> Result { - tracing::debug!(?request, "Received execute command"); - let response = app.relay().execute(request).await; - - match &response { - Ok(_) => { - tracing::info!("Execute command completed successfully"); - } - Err(e) => { - tracing::error!(?e, "Execute command failed"); - } - } - - response -} - -#[command] -pub(crate) async fn cancel( - app: AppHandle, - request_id: CancelRequest, -) -> Result { - tracing::debug!(?request_id, "Received cancel command"); - let response = app.relay().cancel(request_id).await; - - match &response { - Ok(_) => tracing::info!("Cancel command completed successfully"), - Err(e) => tracing::error!(?e, "Cancel command failed"), - } - - response -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/desktop.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/desktop.rs deleted file mode 100644 index 25c597b3..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/desktop.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::{models::*, Result}; -use serde::de::DeserializeOwned; -use tauri::{plugin::PluginApi, AppHandle, Runtime}; - -pub fn init( - app: &AppHandle, - _api: PluginApi, -) -> Result> { - tracing::debug!("Initializing Relay for desktop platform"); - Ok(Relay(app.clone())) -} - -pub struct Relay(AppHandle); - -impl Relay { - pub async fn execute(&self, request: RunRequest) -> Result { - tracing::debug!(?request, "Executing request"); - - match relay::execute(request).await { - Ok(response) => { - tracing::debug!("Request executed successfully"); - Ok(ExecuteResponse::Success { response }) - } - Err(error) => { - tracing::error!(?error, "Request execution failed"); - Ok(ExecuteResponse::Error { error }) - } - } - } - - pub async fn cancel(&self, request_id: CancelRequest) -> Result { - tracing::debug!(?request_id, "Cancelling request"); - - if let Err(e) = relay::cancel(request_id).await { - tracing::error!(?e, "Request cancellation failed"); - return Err(e.into()); - } - - tracing::debug!("Request cancelled successfully"); - Ok(()) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/error.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/error.rs deleted file mode 100644 index 00cccbbf..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/error.rs +++ /dev/null @@ -1,24 +0,0 @@ -use serde::{ser::Serializer, Serialize}; - -pub type Result = std::result::Result; - -#[derive(Debug, thiserror::Error)] -pub enum Error { - #[error(transparent)] - Io(#[from] std::io::Error), - #[error(transparent)] - Relay(#[from] relay::error::RelayError), - #[cfg(mobile)] - #[error(transparent)] - PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError), -} - -impl Serialize for Error { - fn serialize(&self, serializer: S) -> std::result::Result - where - S: Serializer, - { - tracing::error!(?self, "Serializing error"); - serializer.serialize_str(self.to_string().as_ref()) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/lib.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/lib.rs deleted file mode 100644 index 9b88b83b..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/lib.rs +++ /dev/null @@ -1,66 +0,0 @@ -use tauri::{ - plugin::{Builder, TauriPlugin}, - Manager, Runtime, -}; - -pub use models::*; - -#[cfg(desktop)] -mod desktop; -#[cfg(mobile)] -mod mobile; - -mod commands; -mod error; -mod models; - -pub use error::{Error, Result}; - -#[cfg(desktop)] -use desktop::Relay; -#[cfg(mobile)] -use mobile::Relay; - -pub trait RelayExt { - fn relay(&self) -> &Relay; -} - -impl> crate::RelayExt for T { - fn relay(&self) -> &Relay { - tracing::trace!("Accessing Relay state"); - self.state::>().inner() - } -} - -pub fn init() -> TauriPlugin { - tracing::info!("Beginning relay plugin initialization"); - - Builder::new("relay") - .invoke_handler(tauri::generate_handler![ - commands::execute, - commands::cancel - ]) - .setup(|app, api| { - tracing::info!("Setting up relay plugin"); - - #[cfg(mobile)] - { - tracing::debug!("Initializing mobile-specific components"); - let relay = mobile::init(app, api)?; - tracing::debug!("Mobile components initialized successfully"); - app.manage(relay); - } - - #[cfg(desktop)] - { - tracing::debug!("Initializing desktop-specific components"); - let relay = desktop::init(app, api)?; - tracing::debug!("Desktop components initialized successfully"); - app.manage(relay); - } - - tracing::info!("relay plugin setup complete"); - Ok(()) - }) - .build() -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/mobile.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/mobile.rs deleted file mode 100644 index 07e38506..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/mobile.rs +++ /dev/null @@ -1,48 +0,0 @@ -use serde::de::DeserializeOwned; -use tauri::{ - plugin::{PluginApi, PluginHandle}, - AppHandle, Runtime, -}; - -use crate::models::*; - -#[cfg(target_os = "ios")] -tauri::ios_plugin_binding!(init_plugin_relay); - -pub fn init( - _app: &AppHandle, - api: PluginApi, -) -> crate::Result> { - tracing::debug!("Initializing Relay for mobile platform"); - - #[cfg(target_os = "android")] - let handle = { - tracing::debug!("Registering Android plugin"); - api.register_android_plugin("", "ExamplePlugin")? - }; - - #[cfg(target_os = "ios")] - let handle = { - tracing::debug!("Registering iOS plugin"); - api.register_ios_plugin(init_plugin_relay)? - }; - - tracing::info!("Mobile plugin initialization complete"); - Ok(Relay(handle)) -} - -pub struct Relay(PluginHandle); - -impl Relay { - pub fn run(&self, request: RunRequest) -> crate::Result { - tracing::debug!(?request, "Running mobile plugin"); - let result = self.0.run_mobile_plugin("run", request); - - match &result { - Ok(_) => tracing::debug!("Mobile plugin execution successful"), - Err(e) => tracing::error!(?e, "Mobile plugin execution failed"), - } - - result.map_err(Into::into) - } -} diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/models.rs b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/models.rs deleted file mode 100644 index 6e104afa..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/src/models.rs +++ /dev/null @@ -1,17 +0,0 @@ -use relay::{error::RelayError, Request as RelayRequest, Response as RelayResponse}; -use serde::{Deserialize, Serialize}; - -pub type RunRequest = RelayRequest; - -#[derive(Debug, Serialize, Deserialize)] -#[serde(tag = "kind")] -pub enum ExecuteResponse { - #[serde(rename = "success")] - Success { response: RelayResponse }, - #[serde(rename = "error")] - Error { error: RelayError }, -} - -pub type CancelRequest = i64; - -pub type CancelResponse = (); diff --git a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/tsconfig.json b/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/tsconfig.json deleted file mode 100644 index bee11eac..00000000 --- a/packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay/tsconfig.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "compilerOptions": { - "target": "es2021", - "module": "esnext", - "moduleResolution": "bundler", - "skipLibCheck": true, - "strict": true, - "noUnusedLocals": true, - "noImplicitAny": true, - "noEmit": true, - "declaration": true, - "declarationMap": true, - "outDir": "dist-js" - }, - "include": ["guest-js/*.ts"], - "exclude": ["dist-js", "node_modules"] -} diff --git a/packages/hoppscotch-desktop/postcss.config.js b/packages/hoppscotch-desktop/postcss.config.js deleted file mode 100644 index 2e7af2b7..00000000 --- a/packages/hoppscotch-desktop/postcss.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -} diff --git a/packages/hoppscotch-desktop/public/favicon.ico b/packages/hoppscotch-desktop/public/favicon.ico deleted file mode 100644 index 74118360..00000000 Binary files a/packages/hoppscotch-desktop/public/favicon.ico and /dev/null differ diff --git a/packages/hoppscotch-desktop/public/images/add_group.svg b/packages/hoppscotch-desktop/public/images/add_group.svg deleted file mode 100644 index 4350ea15..00000000 --- a/packages/hoppscotch-desktop/public/images/add_group.svg +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/hoppscotch-desktop/public/images/pack.svg b/packages/hoppscotch-desktop/public/images/pack.svg deleted file mode 100644 index 56a669ba..00000000 --- a/packages/hoppscotch-desktop/public/images/pack.svg +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/hoppscotch-desktop/public/images/youre_lost.svg b/packages/hoppscotch-desktop/public/images/youre_lost.svg deleted file mode 100644 index ea33353f..00000000 --- a/packages/hoppscotch-desktop/public/images/youre_lost.svg +++ /dev/null @@ -1,76 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/hoppscotch-desktop/public/logo.svg b/packages/hoppscotch-desktop/public/logo.svg deleted file mode 100644 index d78a86ba..00000000 --- a/packages/hoppscotch-desktop/public/logo.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/hoppscotch-desktop/public/tauri.svg b/packages/hoppscotch-desktop/public/tauri.svg deleted file mode 100644 index 31b62c92..00000000 --- a/packages/hoppscotch-desktop/public/tauri.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/packages/hoppscotch-desktop/public/vite.svg b/packages/hoppscotch-desktop/public/vite.svg deleted file mode 100644 index e7b8dfb1..00000000 --- a/packages/hoppscotch-desktop/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/hoppscotch-desktop/src-tauri/.gitignore b/packages/hoppscotch-desktop/src-tauri/.gitignore deleted file mode 100644 index b21bd681..00000000 --- a/packages/hoppscotch-desktop/src-tauri/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Generated by Cargo -# will have compiled files and executables -/target/ - -# Generated by Tauri -# will have schema files for capabilities auto-completion -/gen/schemas diff --git a/packages/hoppscotch-desktop/src-tauri/Cargo.lock b/packages/hoppscotch-desktop/src-tauri/Cargo.lock deleted file mode 100644 index 81fda23a..00000000 --- a/packages/hoppscotch-desktop/src-tauri/Cargo.lock +++ /dev/null @@ -1,8045 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anstream" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" - -[[package]] -name = "anstyle-parse" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" -dependencies = [ - "anstyle", - "windows-sys 0.59.0", -] - -[[package]] -name = "anyhow" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" - -[[package]] -name = "arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" -dependencies = [ - "derive_arbitrary", -] - -[[package]] -name = "arrayref" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" - -[[package]] -name = "arrayvec" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" - -[[package]] -name = "ascii" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" - -[[package]] -name = "ashpd" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d43c03d9e36dd40cab48435be0b09646da362c278223ca535493877b2c1dee9" -dependencies = [ - "enumflags2", - "futures-channel", - "futures-util", - "rand 0.8.5", - "raw-window-handle 0.6.2", - "serde", - "serde_repr", - "tokio", - "url", - "wayland-backend", - "wayland-client", - "wayland-protocols", - "zbus 4.0.1", -] - -[[package]] -name = "async-broadcast" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e" -dependencies = [ - "event-listener", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-channel" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" -dependencies = [ - "concurrent-queue", - "event-listener-strategy", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-compression" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddb939d66e4ae03cee6091612804ba446b12878410cfa17f785f4dd67d4014e8" -dependencies = [ - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "async-executor" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb812ffb58524bdd10860d7d974e2f01cc0950c2438a74ee5ec2e2280c6c4ffa" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "pin-project-lite", - "slab", -] - -[[package]] -name = "async-fs" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f7e37c0ed80b2a977691c47dae8625cfb21e205827106c64f7c588766b2e50" -dependencies = [ - "async-lock", - "blocking", - "futures-lite", -] - -[[package]] -name = "async-io" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a2b323ccce0a1d90b449fd71f2a06ca7faa7c54c2751f06c9bd851fc061059" -dependencies = [ - "async-lock", - "cfg-if", - "concurrent-queue", - "futures-io", - "futures-lite", - "parking", - "polling", - "rustix 0.38.42", - "slab", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-process" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63255f1dc2381611000436537bbedfe83183faa303a5a0edaf191edef06526bb" -dependencies = [ - "async-channel", - "async-io", - "async-lock", - "async-signal", - "async-task", - "blocking", - "cfg-if", - "event-listener", - "futures-lite", - "rustix 0.38.42", - "tracing", -] - -[[package]] -name = "async-recursion" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "async-signal" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e00349800c0bdf8bfc21ebbc0b6524abea702b0da4168ac00d070d0c0b9f3" -dependencies = [ - "async-io", - "async-lock", - "atomic-waker", - "cfg-if", - "futures-core", - "futures-io", - "rustix 0.38.42", - "signal-hook-registry", - "slab", - "windows-sys 0.59.0", -] - -[[package]] -name = "async-task" -version = "4.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" - -[[package]] -name = "async-trait" -version = "0.1.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "atk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241b621213072e993be4f6f3a9e4b45f65b7e6faad43001be957184b7bb1824b" -dependencies = [ - "atk-sys", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e48b684b0ca77d2bbadeef17424c2ea3c897d44d566a1617e7e8f30614d086" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "axum" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8" -dependencies = [ - "axum-core", - "bytes", - "form_urlencoded", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "itoa", - "matchit", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "rustversion", - "serde", - "serde_json", - "serde_path_to_error", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tower", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "axum-core" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733" -dependencies = [ - "bytes", - "futures-util", - "http", - "http-body", - "http-body-util", - "mime", - "pin-project-lite", - "rustversion", - "sync_wrapper", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "base64ct" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" -dependencies = [ - "serde", -] - -[[package]] -name = "blake3" -version = "1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "serde", -] - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array", -] - -[[package]] -name = "block2" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" -dependencies = [ - "objc2 0.5.2", -] - -[[package]] -name = "block2" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2" -dependencies = [ - "objc2 0.6.2", -] - -[[package]] -name = "blocking" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" -dependencies = [ - "async-channel", - "async-task", - "futures-io", - "futures-lite", - "piper", -] - -[[package]] -name = "bon" -version = "3.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "537c317ddf588aab15c695bf92cf55dec159b93221c074180ca3e0e5a94da415" -dependencies = [ - "bon-macros", - "rustversion", -] - -[[package]] -name = "bon-macros" -version = "3.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5abbf2d4a4c6896197c9de13d6d7cb7eff438c63dacde1dde980569cb00248" -dependencies = [ - "darling 0.21.2", - "ident_case", - "prettyplease", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.90", -] - -[[package]] -name = "brotli" -version = "8.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytemuck" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "bytes" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" -dependencies = [ - "serde", -] - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" -dependencies = [ - "cc", - "libc", - "pkg-config", -] - -[[package]] -name = "cairo-rs" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" -dependencies = [ - "bitflags 2.6.0", - "cairo-sys-rs", - "glib", - "libc", - "once_cell", - "thiserror 1.0.69", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "camino" -version = "1.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", - "thiserror 2.0.12", -] - -[[package]] -name = "cargo_toml" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" -dependencies = [ - "serde", - "toml 0.9.7", -] - -[[package]] -name = "cc" -version = "1.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf" -dependencies = [ - "jobserver", - "libc", - "shlex", -] - -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - -[[package]] -name = "cfb" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" -dependencies = [ - "byteorder", - "fnv", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" -dependencies = [ - "smallvec", - "target-lexicon", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" -dependencies = [ - "android-tzdata", - "iana-time-zone", - "js-sys", - "num-traits", - "serde", - "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - -[[package]] -name = "cocoa" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" -dependencies = [ - "bitflags 1.3.2", - "block", - "cocoa-foundation 0.1.2", - "core-foundation 0.9.4", - "core-graphics 0.23.2", - "foreign-types 0.5.0", - "libc", - "objc", -] - -[[package]] -name = "cocoa" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" -dependencies = [ - "bitflags 2.6.0", - "block", - "cocoa-foundation 0.2.0", - "core-foundation 0.10.0", - "core-graphics 0.24.0", - "foreign-types 0.5.0", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" -dependencies = [ - "bitflags 1.3.2", - "block", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" -dependencies = [ - "bitflags 2.6.0", - "block", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", - "libc", - "objc", -] - -[[package]] -name = "colorchoice" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "const-random" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" -dependencies = [ - "const-random-macro", -] - -[[package]] -name = "const-random-macro" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" -dependencies = [ - "getrandom 0.2.15", - "once_cell", - "tiny-keccak", -] - -[[package]] -name = "constant_time_eq" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "cookie_store" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" -dependencies = [ - "cookie", - "document-features", - "idna", - "log", - "publicsuffix", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - -[[package]] -name = "core-foundation" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" - -[[package]] -name = "core-graphics" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "core-graphics-types 0.1.3", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" -dependencies = [ - "bitflags 2.6.0", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97" -dependencies = [ - "bitflags 2.6.0", - "core-foundation 0.10.0", - "core-graphics-types 0.2.0", - "foreign-types 0.5.0", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation 0.9.4", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags 2.6.0", - "core-foundation 0.10.0", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" -dependencies = [ - "libc", -] - -[[package]] -name = "crc" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" -dependencies = [ - "crc-catalog", -] - -[[package]] -name = "crc-catalog" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" - -[[package]] -name = "crc32fast" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" -dependencies = [ - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.29.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d03419cb5950ccfd3daf3ff1c7a36ace64609a1a8746d493df1ca0afde0fa" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "matches", - "phf 0.10.1", - "proc-macro2", - "quote", - "smallvec", - "syn 1.0.109", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.90", -] - -[[package]] -name = "ctor" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" -dependencies = [ - "quote", - "syn 2.0.90", -] - -[[package]] -name = "curl" -version = "0.4.47" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "socket2 0.5.8", -] - -[[package]] -name = "curl-sys" -version = "0.4.77+curl-8.10.1" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "windows-sys 0.52.0", -] - -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "digest", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", -] - -[[package]] -name = "darling" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08440b3dd222c3d0433e63e097463969485f112baff337dfdaca043a0d760570" -dependencies = [ - "darling_core 0.21.2", - "darling_macro 0.21.2", -] - -[[package]] -name = "darling_core" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.90", -] - -[[package]] -name = "darling_core" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25b7912bc28a04ab1b7715a68ea03aaa15662b43a1a4b2c480531fd19f8bf7e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.90", -] - -[[package]] -name = "darling_macro" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" -dependencies = [ - "darling_core 0.20.10", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "darling_macro" -version = "0.21.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce154b9bea7fb0c8e8326e62d00354000c36e79770ff21b8c84e3aa267d9d531" -dependencies = [ - "darling_core 0.21.2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "data-url" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" - -[[package]] -name = "deflate64" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da692b8d1080ea3045efaab14434d40468c3d8657e42abddfffca87b428f4c1b" - -[[package]] -name = "der" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", - "serde", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_arbitrary" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.90", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" -dependencies = [ - "dirs-sys 0.4.1", -] - -[[package]] -name = "dirs" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys 0.5.0", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.4.6", - "windows-sys 0.48.0", -] - -[[package]] -name = "dirs-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" -dependencies = [ - "libc", - "option-ext", - "redox_users 0.5.0", - "windows-sys 0.60.2", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users 0.4.6", - "winapi", -] - -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "dispatch2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" -dependencies = [ - "bitflags 2.6.0", - "block2 0.6.1", - "libc", - "objc2 0.6.2", -] - -[[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "dlib" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" -dependencies = [ - "libloading 0.8.6", -] - -[[package]] -name = "dlopen2" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54f373ccf864bf587a89e880fb7610f8d73f3045f13580948ccbcaff26febff" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "dlv-list" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" -dependencies = [ - "const-random", -] - -[[package]] -name = "document-features" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" -dependencies = [ - "litrs", -] - -[[package]] -name = "downcast-rs" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" - -[[package]] -name = "dpi" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" -dependencies = [ - "serde", -] - -[[package]] -name = "dtoa" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" - -[[package]] -name = "ed25519" -version = "2.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" -dependencies = [ - "pkcs8", - "serde", - "signature", -] - -[[package]] -name = "ed25519-dalek" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" -dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core 0.6.4", - "serde", - "sha2", - "subtle", - "zeroize", -] - -[[package]] -name = "either" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" - -[[package]] -name = "embed-resource" -version = "3.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a075fc573c64510038d7ee9abc7990635863992f83ebc52c8b433b8411a02e" -dependencies = [ - "cc", - "memchr", - "rustc_version", - "toml 0.9.7", - "vswhom", - "winreg 0.55.0", -] - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - -[[package]] -name = "encoding_rs" -version = "0.8.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "endi" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" - -[[package]] -name = "enumflags2" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "env_filter" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "erased-serde" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" -dependencies = [ - "serde", - "typeid", -] - -[[package]] -name = "errno" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "event-listener" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" -dependencies = [ - "event-listener", - "pin-project-lite", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "field-offset" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" -dependencies = [ - "memoffset", - "rustc_version", -] - -[[package]] -name = "file-rotate" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8e2fa049328a1f3295991407a88585805d126dfaadf74b9fe8c194c730aafc" -dependencies = [ - "chrono", - "flate2", -] - -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - -[[package]] -name = "flate2" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foldhash" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - -[[package]] -name = "form_urlencoded" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-executor" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - -[[package]] -name = "futures-lite" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef40d21ae2c515b51041df9ed313ed21e572df340ea58a922a0aefe7e8891a1" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "parking", - "pin-project-lite", -] - -[[package]] -name = "futures-macro" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f245958c627ac99d8e529166f9823fb3b838d1d41fd2b297af3075093c2691" -dependencies = [ - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" -dependencies = [ - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", - "once_cell", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gdk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c2d13f38594ac1e66619e188c6d5a1adb98d11b2fcf7894fc416ad76aa2f3f7" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkwayland-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "140071d506d223f7572b9f09b5e155afbd77428cd5cc7af8f2694c41d98dfe69" -dependencies = [ - "gdk-sys", - "glib-sys", - "gobject-sys", - "libc", - "pkg-config", - "system-deps", -] - -[[package]] -name = "gdkx11" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3caa00e14351bebbc8183b3c36690327eb77c49abc2268dd4bd36b856db3fbfe" -dependencies = [ - "gdk", - "gdkx11-sys", - "gio", - "glib", - "libc", - "x11", -] - -[[package]] -name = "gdkx11-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e2e7445fe01ac26f11601db260dd8608fe172514eb63b3b5e261ea6b0f4428d" -dependencies = [ - "gdk-sys", - "glib-sys", - "libc", - "system-deps", - "x11", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", - "wasm-bindgen", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "gio" -version = "0.18.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-util", - "gio-sys", - "glib", - "libc", - "once_cell", - "pin-project-lite", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "gio-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", - "winapi", -] - -[[package]] -name = "glib" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" -dependencies = [ - "bitflags 2.6.0", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "futures-util", - "gio-sys", - "glib-macros", - "glib-sys", - "gobject-sys", - "libc", - "memchr", - "once_cell", - "smallvec", - "thiserror 1.0.69", -] - -[[package]] -name = "glib-macros" -version = "0.18.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" -dependencies = [ - "heck 0.4.1", - "proc-macro-crate 2.0.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "glib-sys" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" -dependencies = [ - "libc", - "system-deps", -] - -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - -[[package]] -name = "gobject-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" -dependencies = [ - "glib-sys", - "libc", - "system-deps", -] - -[[package]] -name = "gtk" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd56fb197bfc42bd5d2751f4f017d44ff59fbb58140c6b49f9b3b2bdab08506a" -dependencies = [ - "atk", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f29a1c21c59553eb7dd40e918be54dccd60c52b049b75119d5d96ce6b624414" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "pango-sys", - "system-deps", -] - -[[package]] -name = "gtk3-macros" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ff3c5b21f14f0736fed6dcfc0bfb4225ebf5725f3c0209edeec181e4d73e9d" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "h2" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap 2.11.4", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "heck" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" - -[[package]] -name = "hermit-abi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hex_color" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37f101bf4c633f7ca2e4b5e136050314503dd198e78e325ea602c327c484ef0" -dependencies = [ - "rand 0.8.5", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest", -] - -[[package]] -name = "home" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "hoppscotch-desktop" -version = "26.4.0" -dependencies = [ - "axum", - "dirs 6.0.0", - "file-rotate", - "native-dialog", - "random-port", - "semver", - "serde", - "serde_json", - "tauri", - "tauri-build", - "tauri-plugin-appload", - "tauri-plugin-deep-link", - "tauri-plugin-dialog", - "tauri-plugin-fs", - "tauri-plugin-http", - "tauri-plugin-opener", - "tauri-plugin-process", - "tauri-plugin-relay", - "tauri-plugin-shell", - "tauri-plugin-store", - "tauri-plugin-updater", - "tauri-plugin-window-state", - "tempfile", - "thiserror 2.0.12", - "tokio", - "tower-http", - "tracing", - "tracing-appender", - "tracing-subscriber", - "winreg 0.52.0", -] - -[[package]] -name = "html5ever" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7410cae13cbc75623c98ac4cbfd1f0bedddf3227afc24f370cf0f50a44a11c" -dependencies = [ - "log", - "mac", - "markup5ever", - "match_token", -] - -[[package]] -name = "http" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" -dependencies = [ - "bytes", - "futures-util", - "http", - "http-body", - "pin-project-lite", -] - -[[package]] -name = "http-serde" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f056c8559e3757392c8d091e796416e4649d8e49e88b8d76df6c002f05027fd" -dependencies = [ - "http", - "serde", -] - -[[package]] -name = "httparse" -version = "1.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" - -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "humantime-serde" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a3db5ea5923d99402c94e9feb261dc5ee9b4efa158b0315f788cf549cc200c" -dependencies = [ - "humantime", - "serde", -] - -[[package]] -name = "hyper" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" -dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" -dependencies = [ - "futures-util", - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", - "webpki-roots", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2 0.6.3", - "tokio", - "tower-service", - "tracing", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows-core 0.52.0", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ico" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" -dependencies = [ - "byteorder", - "png", -] - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec", -] - -[[package]] -name = "icu_normalizer_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections", - "icu_locid_transform", - "icu_properties_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_properties_data" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" - -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr", - "writeable", - "yoke", - "zerofrom", - "zerovec", -] - -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" -dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", -] - -[[package]] -name = "idna_adapter" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" -dependencies = [ - "icu_normalizer", - "icu_properties", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", - "serde", - "serde_core", -] - -[[package]] -name = "infer" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" -dependencies = [ - "cfb", -] - -[[package]] -name = "infer" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7" -dependencies = [ - "cfb", -] - -[[package]] -name = "inout" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "ipnet" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" - -[[package]] -name = "iri-string" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" -dependencies = [ - "memchr", - "serde", -] - -[[package]] -name = "is-docker" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928bae27f42bc99b60d9ac7334e3a21d10ad8f1835a4e12ec3ec0464765ed1b3" -dependencies = [ - "once_cell", -] - -[[package]] -name = "is-wsl" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "173609498df190136aa7dea1a91db051746d339e18476eed5ca40521f02d7aa5" -dependencies = [ - "is-docker", - "once_cell", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itertools" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" - -[[package]] -name = "javascriptcore-rs" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" -dependencies = [ - "bitflags 1.3.2", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "jni" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc4c90f45aa2e6eacbe8645f77fdea542ac97a494bcd117a67df9ff4d611f995" -dependencies = [ - "cfg-if", - "futures-util", - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "json-patch" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" -dependencies = [ - "jsonptr", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "jsonptr" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "keyboard-types" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" -dependencies = [ - "bitflags 2.6.0", - "serde", - "unicode-segmentation", -] - -[[package]] -name = "kuchikiki" -version = "0.8.8-speedreader" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" -dependencies = [ - "cssparser", - "html5ever", - "indexmap 2.11.4", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libappindicator" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" -dependencies = [ - "gtk-sys", - "libloading 0.7.4", - "once_cell", -] - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "libloading" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "libloading" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" -dependencies = [ - "cfg-if", - "windows-targets 0.48.5", -] - -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", - "redox_syscall", -] - -[[package]] -name = "libz-sys" -version = "1.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "linux-raw-sys" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" - -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - -[[package]] -name = "litemap" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" - -[[package]] -name = "litrs" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" - -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "lockfree-object-pool" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.2", -] - -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - -[[package]] -name = "lzma-rs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" -dependencies = [ - "byteorder", - "crc", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "markup5ever" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a7213d12e1864c0f002f52c2923d4556935a43dec5e71355c2760e0f6e7a18" -dependencies = [ - "log", - "phf 0.11.2", - "phf_codegen 0.11.3", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "match_token" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a9689d8d44bf9964484516275f5cd4c9b59457a6940c1d5d0ecbb94510a36b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - -[[package]] -name = "matchit" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime-infer" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91caed19dd472bc88bcd063571df18153529d49301a1918f4cf37f42332bee2e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "minisign-verify" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6367d84fb54d4242af283086402907277715b8fe46976963af5ebf173f8efba3" - -[[package]] -name = "miniz_oxide" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef2593ffb6958c941575cee70c8e257438749971869c4ae5acf6f91a168a61" -dependencies = [ - "adler2", - "simd-adler32", -] - -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", -] - -[[package]] -name = "muda" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a" -dependencies = [ - "crossbeam-channel", - "dpi", - "gtk", - "keyboard-types", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "once_cell", - "png", - "serde", - "thiserror 2.0.12", - "windows-sys 0.60.2", -] - -[[package]] -name = "native-dialog" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e7038885d2aeab236bd60da9e159a5967b47cde3292da3b15ff1bec27c039f" -dependencies = [ - "ascii", - "block", - "cocoa 0.25.0", - "core-foundation 0.9.4", - "dirs-next", - "objc", - "objc-foundation", - "objc_id", - "once_cell", - "raw-window-handle 0.5.2", - "thiserror 1.0.69", - "versions", - "wfd", - "which", - "winapi", -] - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "ndk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" -dependencies = [ - "bitflags 2.6.0", - "jni-sys", - "log", - "ndk-sys", - "num_enum", - "raw-window-handle 0.6.2", - "thiserror 1.0.69", -] - -[[package]] -name = "ndk-context" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" - -[[package]] -name = "ndk-sys" -version = "0.6.0+11769913" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "network-interface" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a43439bf756eed340bdf8feba761e2d50c7d47175d87545cd5cbe4a137c4d1" -dependencies = [ - "cc", - "libc", - "thiserror 1.0.69", - "winapi", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - -[[package]] -name = "nix" -version = "0.27.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "ntapi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" -dependencies = [ - "winapi", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_enum" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - -[[package]] -name = "objc-sys" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" - -[[package]] -name = "objc2" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" -dependencies = [ - "objc-sys", - "objc2-encode", -] - -[[package]] -name = "objc2" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" -dependencies = [ - "objc2-encode", - "objc2-exception-helper", -] - -[[package]] -name = "objc2-app-kit" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "libc", - "objc2 0.5.2", - "objc2-core-data", - "objc2-core-image", - "objc2-foundation 0.2.2", - "objc2-quartz-core", -] - -[[package]] -name = "objc2-app-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc" -dependencies = [ - "bitflags 2.6.0", - "block2 0.6.1", - "objc2 0.6.2", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-core-data" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166" -dependencies = [ - "bitflags 2.6.0", - "dispatch2", - "objc2 0.6.2", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4" -dependencies = [ - "bitflags 2.6.0", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-core-image" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" -dependencies = [ - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-exception-helper" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7a1c5fbb72d7735b076bb47b578523aedc40f3c439bea6dfd595c089d79d98a" -dependencies = [ - "cc", -] - -[[package]] -name = "objc2-foundation" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "dispatch", - "libc", - "objc2 0.5.2", -] - -[[package]] -name = "objc2-foundation" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" -dependencies = [ - "bitflags 2.6.0", - "block2 0.6.1", - "objc2 0.6.2", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-metal" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", -] - -[[package]] -name = "objc2-quartz-core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" -dependencies = [ - "bitflags 2.6.0", - "block2 0.5.1", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-metal", -] - -[[package]] -name = "objc2-ui-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25b1312ad7bc8a0e92adae17aa10f90aae1fb618832f9b993b022b591027daed" -dependencies = [ - "bitflags 2.6.0", - "objc2 0.6.2", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc2-web-kit" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91672909de8b1ce1c2252e95bbee8c1649c9ad9d14b9248b3d7b4c47903c47ad" -dependencies = [ - "bitflags 2.6.0", - "block2 0.6.1", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", -] - -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "open" -version = "5.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ecd52f0b8d15c40ce4820aa251ed5de032e5d91fab27f7db2f40d42a8bdf69c" -dependencies = [ - "is-wsl", - "libc", - "pathdiff", -] - -[[package]] -name = "openssl" -version = "0.10.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "foreign-types 0.3.2", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.4.1+3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "ordered-multimap" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49203cdcae0030493bad186b28da2fa25645fa276a51b6fec8010d281e02ef79" -dependencies = [ - "dlv-list", - "hashbrown 0.14.5", -] - -[[package]] -name = "ordered-stream" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" -dependencies = [ - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "os_pipe" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "pango" -version = "0.18.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" -dependencies = [ - "gio", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest", - "hmac", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_shared 0.8.0", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" -dependencies = [ - "phf_macros 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_codegen" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aef8048c789fa5e851558d709946d6d79a8ff88c0440c587967f8e94bfb1216a" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_generator" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" -dependencies = [ - "phf_shared 0.11.2", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "phf_macros" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" -dependencies = [ - "phf_generator 0.11.2", - "phf_shared 0.11.2", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "piper" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" -dependencies = [ - "atomic-waker", - "fastrand", - "futures-io", -] - -[[package]] -name = "pkcs8" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "plist" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" -dependencies = [ - "base64 0.22.1", - "indexmap 2.11.4", - "quick-xml 0.32.0", - "serde", - "time", -] - -[[package]] -name = "png" -version = "0.17.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d" -dependencies = [ - "bitflags 1.3.2", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - -[[package]] -name = "polling" -version = "3.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a604568c3202727d1507653cb121dbd627a58684eb09a820fd746bee38b4442f" -dependencies = [ - "cfg-if", - "concurrent-queue", - "hermit-abi", - "pin-project-lite", - "rustix 0.38.42", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" -dependencies = [ - "proc-macro2", - "syn 2.0.90", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit 0.19.15", -] - -[[package]] -name = "proc-macro-crate" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" -dependencies = [ - "toml_edit 0.20.2", -] - -[[package]] -name = "proc-macro-crate" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" -dependencies = [ - "toml_edit 0.22.27", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "psl-types" -version = "2.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33cb294fe86a74cbcf50d4445b37da762029549ebeea341421c7c70370f86cac" - -[[package]] -name = "publicsuffix" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42ea446cab60335f76979ec15e12619a2165b5ae2c12166bef27d283a9fadf" -dependencies = [ - "idna", - "psl-types", -] - -[[package]] -name = "quick-xml" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" -dependencies = [ - "memchr", -] - -[[package]] -name = "quick-xml" -version = "0.36.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" -dependencies = [ - "memchr", -] - -[[package]] -name = "quinn" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" -dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2 0.5.8", - "thiserror 2.0.12", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.11.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" -dependencies = [ - "bytes", - "getrandom 0.3.3", - "lru-slab", - "rand 0.9.4", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.12", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2 0.5.8", - "tracing", - "windows-sys 0.59.0", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - -[[package]] -name = "rand" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" -dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "rand_core" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" -dependencies = [ - "getrandom 0.3.3", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "random-port" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52b7d0e298a1b2f2f46c8d5da944c80ed1e5e6b032521cc44ee2b1dcbe2b94a" -dependencies = [ - "network-interface", - "rand 0.8.5", - "thiserror 1.0.69", -] - -[[package]] -name = "raw-window-handle" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" - -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - -[[package]] -name = "rayon" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "redox_users" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" -dependencies = [ - "getrandom 0.2.15", - "libredox", - "thiserror 1.0.69", -] - -[[package]] -name = "redox_users" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" -dependencies = [ - "getrandom 0.2.15", - "libredox", - "thiserror 2.0.12", -] - -[[package]] -name = "regex" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", -] - -[[package]] -name = "regex-automata" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", -] - -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "relay" -version = "0.1.1" -source = "git+https://github.com/CuriousCorrelation/relay.git#ed2329e4ebb71bb984c4705aa950cb9c3f9ff931" -dependencies = [ - "bytes", - "curl", - "dashmap", - "env_logger", - "http", - "http-serde", - "infer 0.16.0", - "lazy_static", - "log", - "mime", - "openssl", - "openssl-sys", - "serde", - "serde_json", - "strum", - "thiserror 1.0.69", - "time", - "tokio-util", - "tracing", - "url", - "url-escape", - "urlencoding", -] - -[[package]] -name = "reqwest" -version = "0.12.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" -dependencies = [ - "async-compression", - "base64 0.22.1", - "bytes", - "cookie", - "cookie_store", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "quinn", - "rustls", - "rustls-pemfile", - "rustls-pki-types", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tokio-rustls", - "tokio-util", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams 0.4.2", - "web-sys", - "webpki-roots", - "windows-registry 0.2.0", -] - -[[package]] -name = "reqwest" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3f43e3283ab1488b624b44b0e988d0acea0b3214e694730a055cb6b2efa801" -dependencies = [ - "base64 0.22.1", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-util", - "js-sys", - "log", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "sync_wrapper", - "tokio", - "tokio-util", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams 0.5.0", - "web-sys", -] - -[[package]] -name = "rfd" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8af382a047821a08aa6bfc09ab0d80ff48d45d8726f7cd8e44891f7cb4a4278e" -dependencies = [ - "ashpd", - "block2 0.5.1", - "glib-sys", - "gobject-sys", - "gtk-sys", - "js-sys", - "log", - "objc2 0.5.2", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", - "raw-window-handle 0.6.2", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "ring" -version = "0.17.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" -dependencies = [ - "cc", - "cfg-if", - "getrandom 0.2.15", - "libc", - "spin", - "untrusted", - "windows-sys 0.52.0", -] - -[[package]] -name = "rust-ini" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e310ef0e1b6eeb79169a1171daf9abcb87a2e17c03bee2c4bb100b55c75409f" -dependencies = [ - "cfg-if", - "ordered-multimap", - "trim-in-place", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "rustc-hash" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" - -[[package]] -name = "rustc_version" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.38.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys 0.4.14", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustix" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" -dependencies = [ - "bitflags 2.6.0", - "errno", - "libc", - "linux-raw-sys 0.9.4", - "windows-sys 0.60.2", -] - -[[package]] -name = "rustls" -version = "0.23.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" -dependencies = [ - "once_cell", - "ring", - "rustls-pki-types", - "rustls-webpki", - "subtle", - "zeroize", -] - -[[package]] -name = "rustls-pemfile" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "rustls-pki-types" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" -dependencies = [ - "web-time", -] - -[[package]] -name = "rustls-webpki" -version = "0.102.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" -dependencies = [ - "ring", - "rustls-pki-types", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "schemars" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" -dependencies = [ - "dyn-clone", - "indexmap 1.9.3", - "schemars_derive", - "serde", - "serde_json", - "url", - "uuid", -] - -[[package]] -name = "schemars_derive" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1eee588578aff73f856ab961cd2f79e36bc45d7ded33a7562adba4667aecc0e" -dependencies = [ - "proc-macro2", - "quote", - "serde_derive_internals", - "syn 2.0.90", -] - -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags 2.6.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c37578180969d00692904465fb7f6b3d50b9a2b952b87c23d0e2e5cb5013416" -dependencies = [ - "bitflags 1.3.2", - "cssparser", - "derive_more", - "fxhash", - "log", - "phf 0.8.0", - "phf_codegen 0.8.0", - "precomputed-hash", - "servo_arc", - "smallvec", -] - -[[package]] -name = "semver" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.226" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" -dependencies = [ - "serde_core", - "serde_derive", -] - -[[package]] -name = "serde-untagged" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2676ba99bd82f75cae5cbd2c8eda6fa0b8760f18978ea840e980dd5567b5c5b6" -dependencies = [ - "erased-serde", - "serde", - "typeid", -] - -[[package]] -name = "serde_core" -version = "1.0.226" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.226" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "serde_derive_internals" -version = "0.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "serde_json" -version = "1.0.133" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "serde_path_to_error" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" -dependencies = [ - "itoa", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "serde_spanned" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_spanned" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" -dependencies = [ - "serde_core", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.3", - "indexmap 2.11.4", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "3.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" -dependencies = [ - "darling 0.20.10", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "serialize-to-javascript" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f3666a07a197cdb77cdf306c32be9b7f598d7060d50cfd4d5aa04bfd92f6c5" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "772ee033c0916d670af7860b6e1ef7d658a4629a6d0b4c8c3e67f09b3765b75d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "servo_arc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52aa42f8fdf0fed91e5ce7f23d8138441002fa31dca008acf47e6fd4721f741" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shared_child" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" -dependencies = [ - "rand_core 0.6.4", -] - -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - -[[package]] -name = "siphasher" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" - -[[package]] -name = "socket2" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "softbuffer" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" -dependencies = [ - "bytemuck", - "cfg_aliases", - "core-graphics 0.24.0", - "foreign-types 0.5.0", - "js-sys", - "log", - "objc2 0.5.2", - "objc2-foundation 0.2.2", - "objc2-quartz-core", - "raw-window-handle 0.6.2", - "redox_syscall", - "wasm-bindgen", - "web-sys", - "windows-sys 0.59.0", -] - -[[package]] -name = "soup3" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" -dependencies = [ - "futures-channel", - "gio", - "glib", - "libc", - "soup3-sys", -] - -[[package]] -name = "soup3-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" -dependencies = [ - "gio-sys", - "glib-sys", - "gobject-sys", - "libc", - "system-deps", -] - -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "spki" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" -dependencies = [ - "new_debug_unreachable", - "once_cell", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.90", -] - -[[package]] -name = "subtle" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" - -[[package]] -name = "swift-rs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" -dependencies = [ - "base64 0.21.7", - "serde", - "serde_json", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - -[[package]] -name = "synstructure" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "sysinfo" -version = "0.34.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2" -dependencies = [ - "libc", - "memchr", - "ntapi", - "objc2-core-foundation", - "windows 0.57.0", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.6.0", - "core-foundation 0.9.4", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "system-deps" -version = "6.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" -dependencies = [ - "cfg-expr", - "heck 0.5.0", - "pkg-config", - "toml 0.8.2", - "version-compare", -] - -[[package]] -name = "tao" -version = "0.34.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9103edf55f2da3c82aea4c7fab7c4241032bfeea0e71fa557d98e00e7ce7cc20" -dependencies = [ - "bitflags 2.6.0", - "block2 0.6.1", - "core-foundation 0.10.0", - "core-graphics 0.25.0", - "crossbeam-channel", - "dispatch2", - "dlopen2", - "dpi", - "gdkwayland-sys", - "gdkx11-sys", - "gtk", - "jni", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-sys", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "once_cell", - "parking_lot", - "raw-window-handle 0.6.2", - "tao-macros", - "unicode-segmentation", - "url", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "tao-macros" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "tar" -version = "0.4.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c65998313f8e17d0d553d28f91a0df93e4dbbbf770279c7bc21ca0f09ea1a1f6" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "target-lexicon" -version = "0.12.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" - -[[package]] -name = "tauri" -version = "2.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da77cc00fb9028caf5b5d4650f75e31f1ef3693459dfca7f7e506d1ecef0ba2d" -dependencies = [ - "anyhow", - "bytes", - "cookie", - "dirs 6.0.0", - "dunce", - "embed_plist", - "getrandom 0.3.3", - "glob", - "gtk", - "heck 0.5.0", - "http", - "jni", - "libc", - "log", - "mime", - "muda", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-foundation 0.3.1", - "objc2-ui-kit", - "objc2-web-kit", - "percent-encoding", - "plist", - "raw-window-handle 0.6.2", - "reqwest 0.13.2", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "swift-rs", - "tauri-build", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "thiserror 2.0.12", - "tokio", - "tray-icon", - "url", - "webkit2gtk", - "webview2-com", - "window-vibrancy", - "windows 0.61.3", -] - -[[package]] -name = "tauri-build" -version = "2.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bbc990d1dbf57a8e1c7fa2327f2a614d8b757805603c1b9ba5c81bade09fd4d" -dependencies = [ - "anyhow", - "cargo_toml", - "dirs 6.0.0", - "glob", - "heck 0.5.0", - "json-patch", - "schemars", - "semver", - "serde", - "serde_json", - "tauri-utils", - "tauri-winres", - "toml 0.9.7", - "walkdir", -] - -[[package]] -name = "tauri-codegen" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a24476afd977c5d5d169f72425868613d82747916dd29e0a357c84c4bd6d29" -dependencies = [ - "base64 0.22.1", - "brotli", - "ico", - "json-patch", - "plist", - "png", - "proc-macro2", - "quote", - "semver", - "serde", - "serde_json", - "sha2", - "syn 2.0.90", - "tauri-utils", - "thiserror 2.0.12", - "time", - "url", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-macros" -version = "2.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39b349a98dadaffebb73f0a40dcd1f23c999211e5a2e744403db384d0c33de7" -dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.90", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-plugin" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddde7d51c907b940fb573006cdda9a642d6a7c8153657e88f8a5c3c9290cd4aa" -dependencies = [ - "anyhow", - "glob", - "plist", - "schemars", - "serde", - "serde_json", - "tauri-utils", - "toml 0.9.7", - "walkdir", -] - -[[package]] -name = "tauri-plugin-appload" -version = "0.1.0" -source = "git+https://github.com/CuriousCorrelation/tauri-plugin-appload?rev=0d58d53be2bc75aeb5916bd0d77794fd209426af#0d58d53be2bc75aeb5916bd0d77794fd209426af" -dependencies = [ - "base64 0.22.1", - "blake3", - "bon", - "chrono", - "cocoa 0.26.0", - "dashmap", - "dunce", - "ed25519-dalek", - "flate2", - "futures", - "hex", - "hex_color", - "humantime-serde", - "lru", - "mime-infer", - "mime_guess", - "objc", - "rand 0.8.5", - "rayon", - "regex", - "reqwest 0.12.9", - "serde", - "serde_json", - "sysinfo", - "tauri", - "tauri-plugin", - "thiserror 2.0.12", - "tokio", - "tracing", - "url", - "windows 0.58.0", - "winver", - "zip", -] - -[[package]] -name = "tauri-plugin-deep-link" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35d51ffd286073414d26353bcfc9e83e3cd63f96fa7f7a912f92f2118e5de5a6" -dependencies = [ - "dunce", - "rust-ini", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-utils", - "thiserror 2.0.12", - "tracing", - "url", - "windows-registry 0.3.0", - "windows-result 0.2.0", -] - -[[package]] -name = "tauri-plugin-dialog" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b59fd750551b1066744ab956a1cd6b1ea3e1b3763b0b9153ac27a044d596426" -dependencies = [ - "log", - "raw-window-handle 0.6.2", - "rfd", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror 2.0.12", - "url", -] - -[[package]] -name = "tauri-plugin-fs" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a1edf18000f02903a7c2e5997fb89aca455ecbc0acc15c6535afbb883be223" -dependencies = [ - "anyhow", - "dunce", - "glob", - "percent-encoding", - "schemars", - "serde", - "serde_json", - "serde_repr", - "tauri", - "tauri-plugin", - "tauri-utils", - "thiserror 2.0.12", - "toml 0.8.2", - "url", - "uuid", -] - -[[package]] -name = "tauri-plugin-http" -version = "2.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "696ef548befeee6c6c17b80ef73e7c41205b6c2204e87ef78ccc231212389a5c" -dependencies = [ - "data-url", - "http", - "regex", - "reqwest 0.12.9", - "schemars", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "tauri-plugin-fs", - "thiserror 2.0.12", - "tokio", - "url", - "urlpattern", -] - -[[package]] -name = "tauri-plugin-opener" -version = "2.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "635ed7c580dc3cdc61c94097d38ef517d749ffc0141c806d904e68e4b0cf1c2a" -dependencies = [ - "dunce", - "glob", - "objc2-app-kit 0.2.2", - "objc2-foundation 0.2.2", - "open", - "schemars", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.12", - "url", - "windows 0.58.0", - "zbus 5.4.0", -] - -[[package]] -name = "tauri-plugin-process" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40cc553ab29581c8c43dfa5fb0c9d5aee8ba962ad3b42908eea26c79610441b7" -dependencies = [ - "tauri", - "tauri-plugin", -] - -[[package]] -name = "tauri-plugin-relay" -version = "0.1.0" -source = "git+https://github.com/CuriousCorrelation/tauri-plugin-relay?rev=42f449e1c5657679fecf0374b0ce5047ad03c069#42f449e1c5657679fecf0374b0ce5047ad03c069" -dependencies = [ - "relay", - "serde", - "tauri", - "tauri-plugin", - "thiserror 2.0.12", - "tracing", -] - -[[package]] -name = "tauri-plugin-shell" -version = "2.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8457dbf9e2bab1edd8df22bb2c20857a59a9868e79cb3eac5ed639eec4d0c73b" -dependencies = [ - "encoding_rs", - "log", - "open", - "os_pipe", - "regex", - "schemars", - "serde", - "serde_json", - "shared_child", - "tauri", - "tauri-plugin", - "thiserror 2.0.12", - "tokio", -] - -[[package]] -name = "tauri-plugin-store" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c0c08fae6995909f5e9a0da6038273b750221319f2c0f3b526d6de1cde21505" -dependencies = [ - "dunce", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.12", - "tokio", - "tracing", -] - -[[package]] -name = "tauri-plugin-updater" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce2d39224390c41ba544f02b4f1721f42256320b3fb8c371e9425cbddeb4a68c" -dependencies = [ - "base64 0.22.1", - "dirs 5.0.1", - "flate2", - "futures-util", - "http", - "infer 0.16.0", - "minisign-verify", - "percent-encoding", - "reqwest 0.12.9", - "semver", - "serde", - "serde_json", - "tar", - "tauri", - "tauri-plugin", - "tempfile", - "thiserror 2.0.12", - "time", - "tokio", - "url", - "windows-sys 0.59.0", - "zip", -] - -[[package]] -name = "tauri-plugin-window-state" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e344b512b0d99d9d06225f235d87d6c66d89496a3bf323d9b578d940596e6c" -dependencies = [ - "bitflags 2.6.0", - "log", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.12", -] - -[[package]] -name = "tauri-runtime" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2826d79a3297ed08cd6ea7f412644ef58e32969504bc4fbd8d7dbeabc4445ea2" -dependencies = [ - "cookie", - "dpi", - "gtk", - "http", - "jni", - "objc2 0.6.2", - "objc2-ui-kit", - "objc2-web-kit", - "raw-window-handle 0.6.2", - "serde", - "serde_json", - "tauri-utils", - "thiserror 2.0.12", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.3", -] - -[[package]] -name = "tauri-runtime-wry" -version = "2.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e11ea2e6f801d275fdd890d6c9603736012742a1c33b96d0db788c9cdebf7f9e" -dependencies = [ - "gtk", - "http", - "jni", - "log", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "once_cell", - "percent-encoding", - "raw-window-handle 0.6.2", - "softbuffer", - "tao", - "tauri-runtime", - "tauri-utils", - "url", - "webkit2gtk", - "webview2-com", - "windows 0.61.3", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "2.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219a1f983a2af3653f75b5747f76733b0da7ff03069c7a41901a5eb3ace4557d" -dependencies = [ - "anyhow", - "brotli", - "cargo_metadata", - "ctor", - "dunce", - "glob", - "html5ever", - "http", - "infer 0.19.0", - "json-patch", - "kuchikiki", - "log", - "memchr", - "phf 0.11.2", - "proc-macro2", - "quote", - "regex", - "schemars", - "semver", - "serde", - "serde-untagged", - "serde_json", - "serde_with", - "swift-rs", - "thiserror 2.0.12", - "toml 0.9.7", - "url", - "urlpattern", - "uuid", - "walkdir", -] - -[[package]] -name = "tauri-winres" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd21509dd1fa9bd355dc29894a6ff10635880732396aa38c0066c1e6c1ab8074" -dependencies = [ - "embed-resource", - "toml 0.9.7", -] - -[[package]] -name = "tempfile" -version = "3.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b61f8f20e3a6f7e0649d825294eaf317edce30f82cf6026e7e4cb9222a7d1e" -dependencies = [ - "fastrand", - "getrandom 0.3.3", - "once_cell", - "rustix 1.0.8", - "windows-sys 0.60.2", -] - -[[package]] -name = "tendril" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl 2.0.12", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "time" -version = "0.3.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" -dependencies = [ - "num-conv", - "time-core", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec", -] - -[[package]] -name = "tinyvec" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.43.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" -dependencies = [ - "backtrace", - "bytes", - "libc", - "mio", - "pin-project-lite", - "signal-hook-registry", - "socket2 0.5.8", - "tokio-macros", - "tracing", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" -dependencies = [ - "rustls", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "toml" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" -dependencies = [ - "serde", - "serde_spanned 0.6.8", - "toml_datetime 0.6.11", - "toml_edit 0.20.2", -] - -[[package]] -name = "toml" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" -dependencies = [ - "indexmap 2.11.4", - "serde_core", - "serde_spanned 1.0.2", - "toml_datetime 0.7.2", - "toml_parser", - "toml_writer", - "winnow 0.7.13", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" -dependencies = [ - "serde_core", -] - -[[package]] -name = "toml_edit" -version = "0.19.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" -dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.6.11", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" -dependencies = [ - "indexmap 2.11.4", - "serde", - "serde_spanned 0.6.8", - "toml_datetime 0.6.11", - "winnow 0.5.40", -] - -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap 2.11.4", - "toml_datetime 0.6.11", - "winnow 0.7.13", -] - -[[package]] -name = "toml_parser" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" -dependencies = [ - "winnow 0.7.13", -] - -[[package]] -name = "toml_writer" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d163a63c116ce562a22cda521fcc4d79152e7aba014456fb5eb442f6d6a10109" - -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-http" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" -dependencies = [ - "bitflags 2.6.0", - "bytes", - "futures-util", - "http", - "http-body", - "iri-string", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "log", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-appender" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" -dependencies = [ - "crossbeam-channel", - "thiserror 1.0.69", - "time", - "tracing-subscriber", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "tray-icon" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2" -dependencies = [ - "crossbeam-channel", - "dirs 6.0.0", - "libappindicator", - "muda", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation 0.3.1", - "once_cell", - "png", - "serde", - "thiserror 2.0.12", - "windows-sys 0.59.0", -] - -[[package]] -name = "trim-in-place" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "343e926fc669bc8cde4fa3129ab681c63671bae288b1f1081ceee6d9d37904fc" - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - -[[package]] -name = "typeid" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "uds_windows" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" -dependencies = [ - "memoffset", - "tempfile", - "winapi", -] - -[[package]] -name = "unic-char-property" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" -dependencies = [ - "unic-char-range", -] - -[[package]] -name = "unic-char-range" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" - -[[package]] -name = "unic-common" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" - -[[package]] -name = "unic-ucd-ident" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" -dependencies = [ - "unic-char-property", - "unic-char-range", - "unic-ucd-version", -] - -[[package]] -name = "unic-ucd-version" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" -dependencies = [ - "unic-common", -] - -[[package]] -name = "unicase" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "untrusted" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" - -[[package]] -name = "url" -version = "2.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", - "serde", -] - -[[package]] -name = "url-escape" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e0ce4d1246d075ca5abec4b41d33e87a6054d08e2366b63205665e950db218" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "urlencoding" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" - -[[package]] -name = "urlpattern" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" -dependencies = [ - "regex", - "serde", - "unic-ucd-ident", - "url", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8_iter" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "uuid" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" -dependencies = [ - "getrandom 0.2.15", - "serde", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version-compare" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "versions" -version = "5.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c73a36bc44e3039f51fbee93e39f41225f6b17b380eb70cc2aab942df06b34dd" -dependencies = [ - "itertools", - "nom", -] - -[[package]] -name = "vswhom" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" -dependencies = [ - "libc", - "vswhom-sys", -] - -[[package]] -name = "vswhom-sys" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6523d69017b7633e396a89c5efab138161ed5aafcbc8d3e5c5a42ae38f50495a" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1faf851e778dfa54db7cd438b70758eba9755cb47403f3496edd7c8fc212f0" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3a6c758eb2f701ed3d052ff5737f5bfe6614326ea7f3bbac7156192dc32e67" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921de2737904886b52bcbb237301552d05969a6f9c40d261eb0533c8b055fedf" -dependencies = [ - "bumpalo", - "proc-macro2", - "quote", - "syn 2.0.90", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.115" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a93e946af942b58934c604527337bad9ae33ba1d5c6900bbb41c2c07c2364a93" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wasm-streams" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1ec4f6517c9e11ae630e200b2b65d193279042e28edd4a2cda233e46670bbb" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wayland-backend" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056535ced7a150d45159d3a8dc30f91a2e2d588ca0b23f70e56033622b8016f6" -dependencies = [ - "cc", - "downcast-rs", - "rustix 0.38.42", - "scoped-tls", - "smallvec", - "wayland-sys", -] - -[[package]] -name = "wayland-client" -version = "0.31.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66249d3fc69f76fd74c82cc319300faa554e9d865dab1f7cd66cc20db10b280" -dependencies = [ - "bitflags 2.6.0", - "rustix 0.38.42", - "wayland-backend", - "wayland-scanner", -] - -[[package]] -name = "wayland-protocols" -version = "0.32.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd0ade57c4e6e9a8952741325c30bf82f4246885dca8bf561898b86d0c1f58e" -dependencies = [ - "bitflags 2.6.0", - "wayland-backend", - "wayland-client", - "wayland-scanner", -] - -[[package]] -name = "wayland-scanner" -version = "0.31.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597f2001b2e5fc1121e3d5b9791d3e78f05ba6bfa4641053846248e3a13661c3" -dependencies = [ - "proc-macro2", - "quick-xml 0.36.2", - "quote", -] - -[[package]] -name = "wayland-sys" -version = "0.31.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efa8ac0d8e8ed3e3b5c9fc92c7881406a268e11555abe36493efabe649a29e09" -dependencies = [ - "dlib", - "log", - "pkg-config", -] - -[[package]] -name = "web-sys" -version = "0.3.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84cde8507f4d7cfcb1185b8cb5890c494ffea65edbe1ba82cfd63661c805ed94" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webkit2gtk" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" -dependencies = [ - "bitflags 1.3.2", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "soup3", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" -dependencies = [ - "bitflags 1.3.2", - "cairo-sys-rs", - "gdk-sys", - "gio-sys", - "glib-sys", - "gobject-sys", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pkg-config", - "soup3-sys", - "system-deps", -] - -[[package]] -name = "webpki-roots" -version = "0.26.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webview2-com" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4ba622a989277ef3886dd5afb3e280e3dd6d974b766118950a08f8f678ad6a4" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-implement 0.60.0", - "windows-interface 0.59.1", -] - -[[package]] -name = "webview2-com-macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "webview2-com-sys" -version = "0.38.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36695906a1b53a3bf5c4289621efedac12b73eeb0b89e7e1a89b517302d5d75c" -dependencies = [ - "thiserror 2.0.12", - "windows 0.61.3", - "windows-core 0.61.2", -] - -[[package]] -name = "wfd" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e713040b67aae5bf1a0ae3e1ebba8cc29ab2b90da9aa1bff6e09031a8a41d7a8" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.42", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "window-vibrancy" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c" -dependencies = [ - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "raw-window-handle 0.6.2", - "windows-sys 0.59.0", - "windows-version", -] - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" -dependencies = [ - "windows-core 0.57.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core 0.61.2", - "windows-future", - "windows-link", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" -dependencies = [ - "windows-implement 0.57.0", - "windows-interface 0.57.0", - "windows-result 0.1.2", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement 0.60.0", - "windows-interface 0.59.1", - "windows-link", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core 0.61.2", - "windows-link", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "windows-implement" -version = "0.60.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "windows-interface" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "windows-interface" -version = "0.59.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.2", - "windows-link", -] - -[[package]] -name = "windows-registry" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" -dependencies = [ - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-registry" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bafa604f2104cf5ae2cc2db1dee84b7e6a5d11b05f737b60def0ffdc398cbc0a" -dependencies = [ - "windows-result 0.2.0", - "windows-strings 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978d65aedf914c664c510d9de43c8fd85ca745eaff1ed53edf409b479e441663" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.3", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", -] - -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-version" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - -[[package]] -name = "winnow" -version = "0.5.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "0.7.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - -[[package]] -name = "winreg" -version = "0.55.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97" -dependencies = [ - "cfg-if", - "windows-sys 0.59.0", -] - -[[package]] -name = "winver" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0e7162b9e282fd75a0a832cce93994bdb21208d848a418cd05a5fdd9b9ab33" -dependencies = [ - "windows 0.48.0", -] - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.6.0", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" - -[[package]] -name = "wry" -version = "0.54.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb26159b420aa77684589a744ae9a9461a95395b848764ad12290a14d960a11a" -dependencies = [ - "base64 0.22.1", - "block2 0.6.1", - "cookie", - "crossbeam-channel", - "dirs 6.0.0", - "dpi", - "dunce", - "gdkx11", - "gtk", - "html5ever", - "http", - "javascriptcore-rs", - "jni", - "kuchikiki", - "libc", - "ndk", - "objc2 0.6.2", - "objc2-app-kit 0.3.1", - "objc2-core-foundation", - "objc2-foundation 0.3.1", - "objc2-ui-kit", - "objc2-web-kit", - "once_cell", - "percent-encoding", - "raw-window-handle 0.6.2", - "sha2", - "soup3", - "tao-macros", - "thiserror 2.0.12", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.61.3", - "windows-core 0.61.2", - "windows-version", - "x11-dl", -] - -[[package]] -name = "x11" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" -dependencies = [ - "libc", - "once_cell", - "pkg-config", -] - -[[package]] -name = "xattr" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" -dependencies = [ - "libc", - "linux-raw-sys 0.4.14", - "rustix 0.38.42", -] - -[[package]] -name = "xdg-home" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" -dependencies = [ - "libc", - "windows-sys 0.59.0", -] - -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive", - "zerofrom", -] - -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", - "synstructure", -] - -[[package]] -name = "zbus" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8e3d6ae3342792a6cc2340e4394334c7402f3d793b390d2c5494a4032b3030" -dependencies = [ - "async-broadcast", - "async-process", - "async-recursion", - "async-trait", - "derivative", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "nix 0.27.1", - "ordered-stream", - "rand 0.8.5", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "tokio", - "tracing", - "uds_windows", - "windows-sys 0.52.0", - "xdg-home", - "zbus_macros 4.0.1", - "zbus_names 3.0.0", - "zvariant 4.0.0", -] - -[[package]] -name = "zbus" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbddd8b6cb25d5d8ec1b23277b45299a98bfb220f1761ca11e186d5c702507f8" -dependencies = [ - "async-broadcast", - "async-executor", - "async-fs", - "async-io", - "async-lock", - "async-process", - "async-recursion", - "async-task", - "async-trait", - "blocking", - "enumflags2", - "event-listener", - "futures-core", - "futures-util", - "hex", - "nix 0.29.0", - "ordered-stream", - "serde", - "serde_repr", - "static_assertions", - "tracing", - "uds_windows", - "windows-sys 0.59.0", - "winnow 0.7.13", - "xdg-home", - "zbus_macros 5.4.0", - "zbus_names 4.2.0", - "zvariant 5.6.0", -] - -[[package]] -name = "zbus_macros" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7a3e850ff1e7217a3b7a07eba90d37fe9bb9e89a310f718afcde5885ca9b6d7" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", - "zvariant_utils 1.1.0", -] - -[[package]] -name = "zbus_macros" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac404d48b4e9cf193c8b49589f3280ceca5ff63519e7e64f55b4cf9c47ce146" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.90", - "zbus_names 4.2.0", - "zvariant 5.6.0", - "zvariant_utils 3.2.0", -] - -[[package]] -name = "zbus_names" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" -dependencies = [ - "serde", - "static_assertions", - "zvariant 4.0.0", -] - -[[package]] -name = "zbus_names" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7be68e64bf6ce8db94f63e72f0c7eb9a60d733f7e0499e628dfab0f84d6bcb97" -dependencies = [ - "serde", - "static_assertions", - "winnow 0.7.13", - "zvariant 5.6.0", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "byteorder", - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "zerofrom" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" -dependencies = [ - "zerofrom-derive", -] - -[[package]] -name = "zerofrom-derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", - "synstructure", -] - -[[package]] -name = "zeroize" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" -dependencies = [ - "zeroize_derive", -] - -[[package]] -name = "zeroize_derive" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke", - "zerofrom", - "zerovec-derive", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "zip" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45" -dependencies = [ - "aes", - "arbitrary", - "bzip2", - "constant_time_eq", - "crc32fast", - "crossbeam-utils", - "deflate64", - "displaydoc", - "flate2", - "hmac", - "indexmap 2.11.4", - "lzma-rs", - "memchr", - "pbkdf2", - "rand 0.8.5", - "sha1", - "thiserror 2.0.12", - "time", - "zeroize", - "zopfli", - "zstd", -] - -[[package]] -name = "zopfli" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" -dependencies = [ - "bumpalo", - "crc32fast", - "lockfree-object-pool", - "log", - "once_cell", - "simd-adler32", -] - -[[package]] -name = "zstd" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "7.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" -dependencies = [ - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" -dependencies = [ - "cc", - "pkg-config", -] - -[[package]] -name = "zvariant" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e09e8be97d44eeab994d752f341e67b3b0d80512a8b315a0671d47232ef1b65" -dependencies = [ - "endi", - "enumflags2", - "serde", - "static_assertions", - "url", - "zvariant_derive 4.0.0", -] - -[[package]] -name = "zvariant" -version = "5.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91b3680bb339216abd84714172b5138a4edac677e641ef17e1d8cb1b3ca6e6f" -dependencies = [ - "endi", - "enumflags2", - "serde", - "winnow 0.7.13", - "zvariant_derive 5.6.0", - "zvariant_utils 3.2.0", -] - -[[package]] -name = "zvariant_derive" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72a5857e2856435331636a9fbb415b09243df4521a267c5bedcd5289b4d5799e" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", - "zvariant_utils 1.1.0", -] - -[[package]] -name = "zvariant_derive" -version = "5.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8c68501be459a8dbfffbe5d792acdd23b4959940fc87785fb013b32edbc208" -dependencies = [ - "proc-macro-crate 3.3.0", - "proc-macro2", - "quote", - "syn 2.0.90", - "zvariant_utils 3.2.0", -] - -[[package]] -name = "zvariant_utils" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00bedb16a193cc12451873fee2a1bc6550225acece0e36f333e68326c73c8172" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "zvariant_utils" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16edfee43e5d7b553b77872d99bc36afdda75c223ca7ad5e3fbecd82ca5fc34" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "static_assertions", - "syn 2.0.90", - "winnow 0.7.13", -] diff --git a/packages/hoppscotch-desktop/src-tauri/Cargo.toml b/packages/hoppscotch-desktop/src-tauri/Cargo.toml deleted file mode 100644 index 611d3a32..00000000 --- a/packages/hoppscotch-desktop/src-tauri/Cargo.toml +++ /dev/null @@ -1,60 +0,0 @@ -[package] -name = "hoppscotch-desktop" -version = "26.4.0" -description = "Desktop App for hoppscotch.io" -authors = ["CuriousCorrelation"] -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[lib] -# The `_lib` suffix may seem redundant but it is necessary -# to make the lib name unique and wouldn't conflict with the bin name. -# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519 -name = "hoppscotch_desktop_lib" -crate-type = ["staticlib", "cdylib", "rlib"] - -[build-dependencies] -tauri-build = { version = "2", features = [] } - -[dependencies] -tauri = { version = "2", features = ["devtools"] } -tauri-plugin-shell = { version = "2.3.3", features = [] } -serde = { version = "1", features = ["derive"] } -serde_json = { version = "1", features = [] } -tracing = "0.1.41" -tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } -tracing-appender = { version = "0.2.3" } -tauri-plugin-store = "2.2.0" -tauri-plugin-dialog = "2.2.0" -tauri-plugin-fs = "2.2.0" -tauri-plugin-deep-link = "2.2.0" -tauri-plugin-appload = { git = "https://github.com/CuriousCorrelation/tauri-plugin-appload", rev = "0d58d53be2bc75aeb5916bd0d77794fd209426af" } -tauri-plugin-relay = { git = "https://github.com/CuriousCorrelation/tauri-plugin-relay", rev = "42f449e1c5657679fecf0374b0ce5047ad03c069" } -axum = "0.8.1" -tower-http = { version = "0.6.2", features = ["cors"] } -random-port = "0.1.1" -tokio = "1.43.0" -tauri-plugin-process = "2.2.0" -file-rotate = "0.8.0" -dirs = "6.0.0" -thiserror = "2.0.12" -native-dialog = { version = "0.7.0" } -tauri-plugin-http = { version = "2.0.1", features = ["gzip"] } -tauri-plugin-opener = "2" -semver = "1.0" - -[dev-dependencies] -tempfile = "3.20.0" - -[target.'cfg(windows)'.dependencies] -tempfile = { version = "3.13.0" } -winreg = { version = "0.52.0" } - -[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] -tauri-plugin-updater = "2.3.1" -tauri-plugin-window-state = "2.2.1" - -[features] -default = [] -portable = [] diff --git a/packages/hoppscotch-desktop/src-tauri/build.rs b/packages/hoppscotch-desktop/src-tauri/build.rs deleted file mode 100644 index 0d2e5906..00000000 --- a/packages/hoppscotch-desktop/src-tauri/build.rs +++ /dev/null @@ -1,20 +0,0 @@ -fn main() { - #[cfg(all(feature = "portable", target_os = "windows"))] - { - println!("cargo:rerun-if-changed=tauri.portable.windows.conf.json"); - println!("cargo:rustc-env=TAURI_CONFIG_FILE=tauri.portable.windows.conf.json"); - } - - #[cfg(all(feature = "portable", target_os = "macos"))] - { - println!("cargo:rerun-if-changed=tauri.portable.macos.conf.json"); - println!("cargo:rustc-env=TAURI_CONFIG_FILE=tauri.portable.macos.conf.json"); - } - - #[cfg(not(feature = "portable"))] - { - println!("cargo:rerun-if-changed=tauri.conf.json"); - } - - tauri_build::build() -} diff --git a/packages/hoppscotch-desktop/src-tauri/capabilities/README.md b/packages/hoppscotch-desktop/src-tauri/capabilities/README.md deleted file mode 100644 index aae26329..00000000 --- a/packages/hoppscotch-desktop/src-tauri/capabilities/README.md +++ /dev/null @@ -1,44 +0,0 @@ -# Capabilities Configuration - -## Why wildcards are used in default.json - -The `default.json` capability configuration uses wildcards for windows, webviews, and remote URLs: - -```json -{ - "windows": ["*"], - "webviews": ["*"], - "remote": { - "urls": ["app://*"] - } -} -``` - -### Rationale - -**Cloud for Orgs Support**: The desktop app supports multi-tenancy where organizations get their own isolated contexts via dynamic hostnames. When a user switches to organization "acme", a new webview is created with URL `app://acme_hoppscotch_io/`. Since organization names are dynamic and user-defined, we cannot enumerate all possible window/webview labels or `app://` origins at build time. - -**Security Considerations**: - -1. **`app://` protocol is sandboxed**: The `app://` protocol is entirely handled by the tauri-plugin-appload plugin. External websites cannot inject content into this namespace. Only content served from the local bundle cache is accessible via `app://` URLs. - -2. **No cross-origin access**: Each `app://` origin is isolated. A webview at `app://acme_hoppscotch_io/` cannot access content from `app://beta_hoppscotch_io/`. - -3. **IPC commands are validated**: Tauri commands validate their inputs. The wildcard permission allows IPC calls from any `app://` origin, but the commands themselves enforce authorization. - -**Alternatives Considered**: - -- **Explicit patterns like `Hoppscotch-*`**: Tauri's capability system doesn't support glob patterns for window names in all contexts. -- **Pattern matching like `app://*_hoppscotch_io`**: Would require maintaining a list of allowed suffixes and wouldn't handle custom deployments. - -### Previous Configuration - -Before cloud-for-orgs support, the configuration used explicit window names: - -```json -{ - "windows": ["main", "Hoppscotch-curr", "Hoppscotch-next"] -} -``` - -This was more restrictive but incompatible with dynamic organization subdomains. diff --git a/packages/hoppscotch-desktop/src-tauri/capabilities/default.json b/packages/hoppscotch-desktop/src-tauri/capabilities/default.json deleted file mode 100644 index 10ef8cdd..00000000 --- a/packages/hoppscotch-desktop/src-tauri/capabilities/default.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "../gen/schemas/desktop-schema.json", - "identifier": "default", - "description": "Capability for the main window and all app:// origins", - "windows": ["*"], - "webviews": ["*"], - "remote": { - "urls": ["app://*"] - }, - "permissions": [ - "core:default", - "core:window:default", - "core:window:allow-start-dragging", - "core:event:default", - "core:path:default", - "core:webview:default", - "shell:allow-open", - "store:default", - "dialog:default", - "process:default", - "updater:default", - "fs:allow-copy-file", - "fs:allow-remove", - "fs:allow-exists", - "fs:allow-read-file", - "fs:allow-read-dir", - "fs:allow-write-file", - "fs:allow-write-text-file", - { - "identifier": "fs:scope", - "allow": [ - { "path": "$APPCONFIG" }, - { "path": "$APPCONFIG/**" }, - { "path": "$APPDATA" }, - { "path": "$APPDATA/**" } - ] - }, - "deep-link:default", - "appload:default", - "relay:default" - ] -} diff --git a/packages/hoppscotch-desktop/src-tauri/capabilities/desktop.json b/packages/hoppscotch-desktop/src-tauri/capabilities/desktop.json deleted file mode 100644 index 71ca4a19..00000000 --- a/packages/hoppscotch-desktop/src-tauri/capabilities/desktop.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "identifier": "desktop-capability", - "platforms": [ - "macOS", - "windows", - "linux" - ], - "permissions": [ - "updater:default", - "window-state:default" - ] -} \ No newline at end of file diff --git a/packages/hoppscotch-desktop/src-tauri/icons/128x128.png b/packages/hoppscotch-desktop/src-tauri/icons/128x128.png deleted file mode 100644 index 823d9e73..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/128x128.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/128x128@2x.png b/packages/hoppscotch-desktop/src-tauri/icons/128x128@2x.png deleted file mode 100644 index 4a4eaed3..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/128x128@2x.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/32x32.png b/packages/hoppscotch-desktop/src-tauri/icons/32x32.png deleted file mode 100644 index 219f6600..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/32x32.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square107x107Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square107x107Logo.png deleted file mode 100644 index 8184c704..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square107x107Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square142x142Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square142x142Logo.png deleted file mode 100644 index ff628753..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square142x142Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square150x150Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square150x150Logo.png deleted file mode 100644 index ee3f87f1..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square150x150Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square284x284Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square284x284Logo.png deleted file mode 100644 index 94f6eebf..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square284x284Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square30x30Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square30x30Logo.png deleted file mode 100644 index d6a892a2..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square30x30Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square310x310Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square310x310Logo.png deleted file mode 100644 index cebe63f7..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square310x310Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square44x44Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square44x44Logo.png deleted file mode 100644 index 9f7a5c54..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square44x44Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square71x71Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square71x71Logo.png deleted file mode 100644 index 56f0613d..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square71x71Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/Square89x89Logo.png b/packages/hoppscotch-desktop/src-tauri/icons/Square89x89Logo.png deleted file mode 100644 index 11ebad09..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/Square89x89Logo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/StoreLogo.png b/packages/hoppscotch-desktop/src-tauri/icons/StoreLogo.png deleted file mode 100644 index 2b9ce6e0..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/StoreLogo.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/icon.icns b/packages/hoppscotch-desktop/src-tauri/icons/icon.icns deleted file mode 100644 index 11df6abc..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/icon.icns and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/icon.ico b/packages/hoppscotch-desktop/src-tauri/icons/icon.ico deleted file mode 100644 index cc9a3cf2..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/icon.ico and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/icons/icon.png b/packages/hoppscotch-desktop/src-tauri/icons/icon.png deleted file mode 100644 index 7209bbf4..00000000 Binary files a/packages/hoppscotch-desktop/src-tauri/icons/icon.png and /dev/null differ diff --git a/packages/hoppscotch-desktop/src-tauri/src/backup.rs b/packages/hoppscotch-desktop/src-tauri/src/backup.rs deleted file mode 100644 index eff75b0d..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/backup.rs +++ /dev/null @@ -1,425 +0,0 @@ -use std::fs; -use std::path::PathBuf; - -use semver::Version; -use tauri::{AppHandle, Runtime}; - -use crate::{error::HoppError, path}; - -const MAX_BACKUP_COUNT: usize = 3; - -#[tauri::command] -pub async fn check_and_backup_on_version_change( - app: AppHandle, -) -> Result<(), String> { - let handle = app.clone(); - match tauri::async_runtime::spawn_blocking(move || perform_version_check_and_backup(handle)) - .await - { - Ok(Ok(_)) => Ok(()), - Ok(Err(e)) => { - tracing::error!(error = %e, "Backup operation failed"); - Err(e.to_string()) - } - Err(e) => { - tracing::error!(error = %e, "Backup task panicked"); - Err("Backup operation panicked".to_string()) - } - } -} - -pub fn perform_version_check_and_backup(app: AppHandle) -> Result<(), HoppError> { - let current_version = get_current_app_version(&app)?; - - tracing::info!( - current_version = %current_version, - "Version check initiated" - ); - - if !backup_exists_for_version(¤t_version)? { - tracing::info!( - version = %current_version, - "No backup found for current version, creating backup" - ); - - backup_current_data(¤t_version)?; - cleanup_old_backups()?; - - tracing::info!("Backup operation completed successfully"); - } else { - tracing::debug!( - version = %current_version, - "Backup already exists for current version, skipping" - ); - } - - Ok(()) -} - -fn get_current_app_version(app: &AppHandle) -> Result { - let version_str = app.package_info().version.to_string(); - Version::parse(&version_str).map_err(|e| { - tracing::error!( - version_string = %version_str, - error = %e, - "Failed to parse current app version" - ); - HoppError::Io(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!("Invalid version format: {}", version_str), - )) - }) -} - -fn backup_exists_for_version(version: &Version) -> Result { - let backup_dir = path::backup_dir()?; - let version_backup_dir = backup_dir.join(format!("backup-by-v{}", version)); - - Ok(version_backup_dir.exists()) -} - -fn backup_current_data(current_version: &Version) -> Result<(), HoppError> { - let config_dir = path::config_dir()?; - let backup_dir = path::backup_dir()?; - let version_backup_dir = backup_dir.join(format!("backup-by-v{}", current_version)); - - if !config_dir.exists() { - tracing::warn!("Config directory doesn't exist, skipping backup"); - return Ok(()); - } - - tracing::info!( - source = %config_dir.display(), - target = %version_backup_dir.display(), - "Starting full config directory backup" - ); - - fs::create_dir_all(&version_backup_dir)?; - - // NOTE: This copies all contents of `config_dir` to `version_backup_dir`, - // but excludes the `backup` and `latest` directories to avoid infinite recursion - // and prevent backing up the current working data that might be in flux. - copy_directory_contents_excluding_special_dirs(&config_dir, &version_backup_dir, &backup_dir)?; - - tracing::info!( - target = %version_backup_dir.display(), - "Full config backup completed successfully" - ); - - Ok(()) -} - -fn copy_directory_contents_excluding_special_dirs( - src: &PathBuf, - dst: &PathBuf, - backup_dir: &PathBuf, -) -> Result<(), HoppError> { - if !src.exists() { - return Ok(()); - } - - let latest_dir = match path::latest_dir() { - Ok(dir) => Some(dir), - Err(e) => { - tracing::warn!(error = %e, "Failed to get latest directory path"); - None - } - }; - - for entry in fs::read_dir(src)? { - let entry = entry?; - let src_path = entry.path(); - let dst_path = dst.join(entry.file_name()); - - if src_path == *backup_dir { - tracing::debug!( - path = %src_path.display(), - "Skipping backup directory to avoid recursion" - ); - continue; - } - - if let Some(ref latest_dir) = latest_dir { - if src_path == *latest_dir { - tracing::debug!( - path = %src_path.display(), - "Skipping latest directory to avoid backing up current working data" - ); - continue; - } - } - - if src_path.is_dir() { - copy_directory_recursive(&src_path, &dst_path)?; - } else { - fs::copy(&src_path, &dst_path)?; - } - } - - Ok(()) -} - -fn copy_directory_recursive(src: &PathBuf, dst: &PathBuf) -> Result<(), HoppError> { - if !src.exists() { - return Ok(()); - } - - fs::create_dir_all(dst)?; - - for entry in fs::read_dir(src)? { - let entry = entry?; - let src_path = entry.path(); - let dst_path = dst.join(entry.file_name()); - - if src_path.is_dir() { - copy_directory_recursive(&src_path, &dst_path)?; - } else { - fs::copy(&src_path, &dst_path)?; - } - } - - Ok(()) -} - -fn parse_version_from_backup_dirname(dirname: &str) -> Option { - // Parse "backup-by-v1.2.3" format - if let Some(version_part) = dirname.strip_prefix("backup-by-v") { - Version::parse(version_part).ok() - } else { - None - } -} - -fn cleanup_old_backups() -> Result<(), HoppError> { - let backup_dir = path::backup_dir()?; - - if !backup_dir.exists() { - return Ok(()); - } - - let entries = fs::read_dir(&backup_dir)?; - let mut version_paths = Vec::new(); - - for entry in entries { - let entry = entry?; - let path = entry.path(); - - if path.is_dir() { - if let Some(dirname) = path.file_name().and_then(|n| n.to_str()) { - if let Some(version) = parse_version_from_backup_dirname(dirname) { - version_paths.push((version, path)); - } - } - } - } - - if version_paths.len() <= MAX_BACKUP_COUNT { - return Ok(()); - } - - version_paths.sort_by(|a, b| a.0.cmp(&b.0)); - - let to_remove_count = version_paths.len() - MAX_BACKUP_COUNT; - let to_remove = &version_paths[..to_remove_count]; - - for (version, path) in to_remove { - tracing::info!( - version = %version, - path = %path.display(), - "Removing old backup" - ); - - match fs::remove_dir_all(path) { - Ok(_) => { - tracing::debug!( - version = %version, - "Successfully removed old backup" - ); - } - Err(e) => { - tracing::warn!( - version = %version, - error = %e, - "Failed to remove old backup, continuing" - ); - } - } - } - - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - use tempfile::TempDir; - - #[test] - fn test_parse_version_from_backup_dirname() { - // Valid cases - assert_eq!( - parse_version_from_backup_dirname("backup-by-v1.2.3"), - Some(Version::new(1, 2, 3)) - ); - assert_eq!( - parse_version_from_backup_dirname("backup-by-v10.0.0"), - Some(Version::new(10, 0, 0)) - ); - assert_eq!( - parse_version_from_backup_dirname("backup-by-v2.1.0-beta.1"), - Version::parse("2.1.0-beta.1").ok() - ); - - // Invalid cases - assert_eq!(parse_version_from_backup_dirname("backup-v1.2.3"), None); - assert_eq!(parse_version_from_backup_dirname("v1.2.3"), None); - assert_eq!(parse_version_from_backup_dirname("backup-by-v"), None); - assert_eq!( - parse_version_from_backup_dirname("backup-by-vinvalid"), - None - ); - assert_eq!(parse_version_from_backup_dirname(""), None); - assert_eq!(parse_version_from_backup_dirname("random-dir"), None); - } - - #[test] - fn test_max_backup_count_constant() { - assert_eq!(MAX_BACKUP_COUNT, 3); - } - - #[test] - fn test_copy_directory_recursive_empty_dir() { - let temp_dir = TempDir::new().unwrap(); - let src = temp_dir.path().join("src"); - let dst = temp_dir.path().join("dst"); - - fs::create_dir_all(&src).unwrap(); - - let result = copy_directory_recursive(&src, &dst); - assert!(result.is_ok()); - assert!(dst.exists()); - assert!(dst.is_dir()); - } - - #[test] - fn test_copy_directory_recursive_with_files() { - let temp_dir = TempDir::new().unwrap(); - let src = temp_dir.path().join("src"); - let dst = temp_dir.path().join("dst"); - - fs::create_dir_all(&src).unwrap(); - fs::write(src.join("test.txt"), "test content").unwrap(); - fs::create_dir_all(src.join("subdir")).unwrap(); - fs::write(src.join("subdir").join("nested.txt"), "nested content").unwrap(); - - let result = copy_directory_recursive(&src, &dst); - assert!(result.is_ok()); - - assert!(dst.exists()); - assert!(dst.join("test.txt").exists()); - assert!(dst.join("subdir").exists()); - assert!(dst.join("subdir").join("nested.txt").exists()); - - let content = fs::read_to_string(dst.join("test.txt")).unwrap(); - assert_eq!(content, "test content"); - - let nested_content = fs::read_to_string(dst.join("subdir").join("nested.txt")).unwrap(); - assert_eq!(nested_content, "nested content"); - } - - #[test] - fn test_copy_directory_recursive_nonexistent_src() { - let temp_dir = TempDir::new().unwrap(); - let src = temp_dir.path().join("nonexistent"); - let dst = temp_dir.path().join("dst"); - - let result = copy_directory_recursive(&src, &dst); - assert!(result.is_ok()); // Should return Ok for nonexistent source - assert!(!dst.exists()); // Destination should not be created - } - - #[test] - fn test_version_sorting_in_cleanup() { - let versions = vec![ - Version::new(1, 0, 0), - Version::new(2, 1, 0), - Version::new(1, 5, 0), - Version::new(2, 0, 0), - ]; - - let mut version_paths: Vec<(Version, PathBuf)> = versions - .into_iter() - .map(|v| { - ( - v.clone(), - PathBuf::from(format!("backup-by-v{}", v.clone())), - ) - }) - .collect(); - - version_paths.sort_by(|a, b| a.0.cmp(&b.0)); - - // Should be sorted: 1.0.0, 1.5.0, 2.0.0, 2.1.0 - assert_eq!(version_paths[0].0, Version::new(1, 0, 0)); - assert_eq!(version_paths[1].0, Version::new(1, 5, 0)); - assert_eq!(version_paths[2].0, Version::new(2, 0, 0)); - assert_eq!(version_paths[3].0, Version::new(2, 1, 0)); - } - - #[test] - fn test_cleanup_old_backups_integration() { - let temp_dir = TempDir::new().unwrap(); - let backup_root = temp_dir.path(); - - let backup_dirs = vec![ - "backup-by-v1.0.0", - "backup-by-v1.1.0", - "backup-by-v1.2.0", - "backup-by-v2.0.0", - "backup-by-v2.1.0", // This should be kept (newest 3) - "backup-by-v2.2.0", // This should be kept - "backup-by-v3.0.0", // This should be kept - "not-a-backup-dir", // This should be ignored - ]; - - for dir in &backup_dirs { - fs::create_dir_all(backup_root.join(dir)).unwrap(); - } - - let entries = fs::read_dir(backup_root).unwrap(); - let mut version_paths = Vec::new(); - - for entry in entries { - let entry = entry.unwrap(); - let path = entry.path(); - - if path.is_dir() { - if let Some(dirname) = path.file_name().and_then(|n| n.to_str()) { - if let Some(version) = parse_version_from_backup_dirname(dirname) { - version_paths.push((version, path)); - } - } - } - } - - version_paths.sort_by(|a, b| a.0.cmp(&b.0)); - - // Should have 7 valid backup directories (excluding "not-a-backup-dir") - assert_eq!(version_paths.len(), 7); - - // If MAX_BACKUP_COUNT is 3, we should remove 4 directories - let should_remove = version_paths.len() > MAX_BACKUP_COUNT; - assert!(should_remove); - - if should_remove { - let to_remove_count = version_paths.len() - MAX_BACKUP_COUNT; - assert_eq!(to_remove_count, 4); - - // The oldest versions should be marked for removal - assert_eq!(version_paths[0].0, Version::new(1, 0, 0)); - assert_eq!(version_paths[1].0, Version::new(1, 1, 0)); - assert_eq!(version_paths[2].0, Version::new(1, 2, 0)); - assert_eq!(version_paths[3].0, Version::new(2, 0, 0)); - } - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/config.rs b/packages/hoppscotch-desktop/src-tauri/src/config.rs deleted file mode 100644 index c3b7aa48..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/config.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::{fs, path::PathBuf, sync::Mutex, time::Duration}; - -use serde::Deserialize; -use tauri_plugin_appload::{ApiConfig, CacheConfig, Config, StorageConfig, VendorConfig}; - -use crate::{error::HoppError, path}; - -// Appload plugin configuration. These constants are baked into the plugin -// config at startup via `HoppApploadConfig::build()`, before the webview -// exists, so they cannot be overridden by runtime user settings. A future -// user-facing connection timeout override will need a separate mechanism, -// either a startup-time store file read or a deferred appload init. -const API_SERVER_URL: &str = "http://localhost:3200"; -const API_TIMEOUT_SECS: u64 = 30; -const CACHE_MAX_SIZE_MB: usize = 1000; -const CACHE_FILE_TTL_SECS: u64 = 3600; -const CACHE_HOT_RATIO: f32 = 0.9; -const MAX_BUNDLE_SIZE_MB: usize = 50; - -pub struct HoppApploadConfig { - bundle_path: PathBuf, - manifest_path: PathBuf, - config_dir: PathBuf, -} - -impl HoppApploadConfig { - pub fn new() -> Result { - let config_dir = path::config_dir().unwrap_or_else(|e| { - tracing::error!(error = %e, "Failed to create config directory, using temp dir"); - std::env::temp_dir().join(path::APP_ID) - }); - - let bundle_path = path::bundle_path(); - let manifest_path = path::manifest_path(); - - Ok(Self { - bundle_path, - manifest_path, - config_dir, - }) - } - - pub fn write_vendored(&self) -> Result<(), HoppError> { - fs::write(&self.bundle_path, include_bytes!("../../bundle.zip"))?; - fs::write(&self.manifest_path, include_bytes!("../../manifest.json"))?; - Ok(()) - } - - pub fn build(&self) -> Config { - Config::builder() - .api(ApiConfig { - server_url: API_SERVER_URL.to_string(), - timeout: Duration::from_secs(API_TIMEOUT_SECS), - }) - .cache(CacheConfig { - max_size: CACHE_MAX_SIZE_MB * 1024 * 1024, - file_ttl: Duration::from_secs(CACHE_FILE_TTL_SECS), - hot_ratio: CACHE_HOT_RATIO, - }) - .storage(StorageConfig { - root_dir: self.config_dir.clone(), - max_bundle_size: MAX_BUNDLE_SIZE_MB * 1024 * 1024, - }) - .vendor(VendorConfig { - bundle_path: self.bundle_path.clone(), - manifest_path: self.manifest_path.clone(), - }) - .log_dir( - path::logs_dir().unwrap_or_else(|_| std::env::temp_dir()), - ) - .build() - } -} - -// Webview-pushed runtime settings bridge. -// -// The webview persists user settings (timeout, zoom, auto-reconnect, and so -// on) via `tauri-plugin-store`. The Tauri shell needs live access to some -// of those values, for example `connectionTimeoutMs` for the appload HTTP -// client. Rather than having Rust read the store file directly, which would -// couple this code to the plugin's on-disk format, the webview pushes the -// current settings to Rust via `set_desktop_config` at init and on change. -// -// The IPC plumbing is wired end-to-end but no Rust code reads -// `DESKTOP_CONFIG` yet. Consumers such as the appload connection timeout -// are future scope. -// -// The struct deliberately only deserializes fields Rust actually consumes. -// TS sends the full `DESKTOP_SETTINGS_SCHEMA` payload and serde drops the -// rest. Adding a new Rust consumer means adding a field here, not changing -// the IPC contract. - -/// Subset of the webview-side `DesktopSettings` that Rust services consume. -/// -/// Field names are snake_case with `rename_all = "camelCase"` so they line -/// up with what the TS store produces from `DESKTOP_SETTINGS_SCHEMA`. -#[derive(Debug, Clone, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct DesktopConfig { - /// Timeout (ms) for outbound HTTP requests in the appload client and - /// related connection paths. Mirrors `API_TIMEOUT_SECS` when the value - /// is 30_000. - pub connection_timeout_ms: u64, -} - -/// Live copy of the most recent settings pushed from the webview. -/// -/// `None` means the webview has not called `set_desktop_config` yet, which -/// is the case during the early Tauri startup path before the window loads -/// and for the whole of the pre-webview `PortableHome` and `StandardHome` -/// flow. Consumers must treat `None` as "no override, use the compile-time -/// default". -static DESKTOP_CONFIG: Mutex> = Mutex::new(None); - -/// Returns a clone of the most recent settings pushed from the webview, or -/// `None` if nothing has been pushed yet. -/// -/// Cloning keeps the lock scope short, which is cheap because -/// `DesktopConfig` is a small POD struct. -#[allow(dead_code)] // no Rust consumers yet, see module doc above. -pub fn current_desktop_config() -> Option { - DESKTOP_CONFIG - .lock() - .ok() - .and_then(|guard| guard.clone()) -} - -/// Tauri command invoked by the webview on init and whenever settings -/// change. Overwrites any previously-pushed config and is idempotent on -/// identical input. -#[tauri::command] -pub fn set_desktop_config(config: DesktopConfig) -> Result<(), String> { - tracing::debug!(?config, "Received desktop config from webview"); - let mut guard = DESKTOP_CONFIG - .lock() - .map_err(|e| format!("DESKTOP_CONFIG mutex poisoned: {}", e))?; - *guard = Some(config); - Ok(()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_constants() { - // NOTE: These are rather pointless tests, but are here just in case - // there are rebase/merge conflicts that rewrites the values - // (since there's been quite a lot of experimentation on that front) - // so this created on a new branch shall remain consistent. - assert_eq!(API_SERVER_URL, "http://localhost:3200"); - assert_eq!(API_TIMEOUT_SECS, 30); - assert_eq!(CACHE_MAX_SIZE_MB, 1000); - assert_eq!(CACHE_FILE_TTL_SECS, 3600); - assert_eq!(CACHE_HOT_RATIO, 0.9); - assert_eq!(MAX_BUNDLE_SIZE_MB, 50); - } - - #[test] - fn test_hopp_appload_config_new() { - let config = HoppApploadConfig::new(); - assert!(config.is_ok()); - - let config = config.unwrap(); - assert!(config - .bundle_path - .to_string_lossy() - .contains("hopp_bundle.zip")); - assert!(config - .manifest_path - .to_string_lossy() - .contains("hopp_manifest.json")); - assert!(!config.config_dir.as_os_str().is_empty()); - } - - #[test] - fn test_config_paths() { - let config = HoppApploadConfig::new().unwrap(); - - assert_eq!( - config.bundle_path.file_name().unwrap().to_str().unwrap(), - "hopp_bundle.zip" - ); - - assert_eq!( - config.manifest_path.file_name().unwrap().to_str().unwrap(), - "hopp_manifest.json" - ); - - assert!(!config.config_dir.as_os_str().is_empty()); - } - - // The roundtrip and overwrite assertions stay in one test because - // `DESKTOP_CONFIG` is process-wide shared state and cargo runs tests - // in parallel by default. Splitting them into two `#[test]` functions - // would race for the global mutex and produce flaky assertions - // depending on schedule. The other tests in this module exercise - // `DesktopConfig` deserialization in isolation and never touch - // `DESKTOP_CONFIG`, so they are safe to run alongside this one. - #[test] - fn set_desktop_config_roundtrip_and_overwrite() { - let result = set_desktop_config(DesktopConfig { - connection_timeout_ms: 45_000, - }); - assert!(result.is_ok()); - assert_eq!( - current_desktop_config().unwrap().connection_timeout_ms, - 45_000 - ); - - set_desktop_config(DesktopConfig { - connection_timeout_ms: 90_000, - }) - .unwrap(); - assert_eq!( - current_desktop_config().unwrap().connection_timeout_ms, - 90_000 - ); - } - - #[test] - fn desktop_config_deserializes_from_camel_case() { - let json = r#"{"connectionTimeoutMs": 60000}"#; - let cfg: DesktopConfig = serde_json::from_str(json).unwrap(); - assert_eq!(cfg.connection_timeout_ms, 60_000); - } - - #[test] - fn desktop_config_deserialize_ignores_extra_fields() { - // TS pushes the full `DESKTOP_SETTINGS_SCHEMA` so extras must drop. - let json = r#"{ - "connectionTimeoutMs": 30000, - "disableUpdateNotifications": true, - "zoomLevel": 1.25 - }"#; - let cfg: DesktopConfig = serde_json::from_str(json).unwrap(); - assert_eq!(cfg.connection_timeout_ms, 30_000); - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/dialog.rs b/packages/hoppscotch-desktop/src-tauri/src/dialog.rs deleted file mode 100644 index e4967b43..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/dialog.rs +++ /dev/null @@ -1,58 +0,0 @@ -use native_dialog::{MessageDialog, MessageType}; - -pub fn panic(msg: &str) { - const FATAL_ERROR: &str = "Fatal error"; - - MessageDialog::new() - .set_type(MessageType::Error) - .set_title(FATAL_ERROR) - .set_text(msg) - .show_alert() - .unwrap_or_default(); - - tracing::error!("{}: {}", FATAL_ERROR, msg); - - panic!("{}: {}", FATAL_ERROR, msg); -} - -pub fn info(msg: &str) { - tracing::info!("{}", msg); - - MessageDialog::new() - .set_type(MessageType::Info) - .set_title("Info") - .set_text(msg) - .show_alert() - .unwrap_or_default(); -} - -pub fn warn(msg: &str) { - tracing::warn!("{}", msg); - - MessageDialog::new() - .set_type(MessageType::Warning) - .set_title("Warning") - .set_text(msg) - .show_alert() - .unwrap_or_default(); -} - -pub fn error(msg: &str) { - tracing::error!("{}", msg); - - MessageDialog::new() - .set_type(MessageType::Error) - .set_title("Error") - .set_text(msg) - .show_alert() - .unwrap_or_default(); -} - -pub fn confirm(title: &str, msg: &str, icon: MessageType) -> bool { - MessageDialog::new() - .set_type(icon) - .set_title(title) - .set_text(msg) - .show_confirm() - .unwrap_or_default() -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/error.rs b/packages/hoppscotch-desktop/src-tauri/src/error.rs deleted file mode 100644 index 02474e03..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/error.rs +++ /dev/null @@ -1,18 +0,0 @@ -use std::io; - -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum HoppError { - #[error("IO error: {0}")] - Io(#[from] io::Error), - - #[error("Failed to initialize server port")] - ServerPortInitialization, - - #[error("Failed to emit event: {0}")] - EventEmission(String), - - #[error("Tauri error: {0}")] - Tauri(#[from] tauri::Error), -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/lib.rs b/packages/hoppscotch-desktop/src-tauri/src/lib.rs deleted file mode 100644 index db89d88f..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/lib.rs +++ /dev/null @@ -1,273 +0,0 @@ -pub mod backup; -pub mod config; -pub mod dialog; -pub mod error; -pub mod logger; -pub mod path; -pub mod server; -pub mod updater; -pub mod util; -pub mod webview; - -use std::sync::OnceLock; - -use tauri::Emitter; -use tauri_plugin_deep_link::DeepLinkExt; -use tauri_plugin_window_state::StateFlags; - -use random_port::{PortPicker, Protocol}; - -use config::HoppApploadConfig; -use error::HoppError; - -static SERVER_PORT: OnceLock = OnceLock::new(); - -#[tauri::command] -fn is_portable() -> bool { - cfg!(feature = "portable") -} - -#[tauri::command] -fn hopp_auth_port() -> u16 { - SERVER_PORT - .get() - .copied() - .expect("Server port not initialized") -} - -fn setup_deep_link_handler(app: &tauri::App) -> Result<(), HoppError> { - let handle = app.handle().clone(); - - app.deep_link().on_open_url(move |event| { - let urls = event.urls(); - tracing::info!( - urls = ?urls, - count = urls.len(), - "Processing deep link request" - ); - - if let Err(e) = handle.emit("scheme-request-received", urls) { - tracing::error!( - error.message = %e, - error.type = %std::any::type_name_of_val(&e), - "Deep link event emission failed" - ); - } - }); - - tracing::info!(app_name = %app.package_info().name, "Configured deep link handler"); - - Ok(()) -} - -fn setup_server(app: &tauri::App) -> Result { - let server_port: u16 = PortPicker::new() - .protocol(Protocol::Tcp) - .port_range(15000..=25000) - .pick() - .map_err(|_| HoppError::ServerPortInitialization)?; - - tracing::info!("Selected server port: {}", server_port); - SERVER_PORT - .set(server_port) - .map_err(|_| HoppError::ServerPortInitialization)?; - - let port = *SERVER_PORT - .get() - .ok_or(HoppError::ServerPortInitialization)?; - tracing::info!(port = port, "Initializing server with pre-selected port"); - - let port = server::init(port, app.handle().clone()); - tracing::info!(port = port, "Server initialization complete"); - - Ok(port) -} - -async fn setup_version_backup(app: &tauri::App) -> Result<(), HoppError> { - tracing::info!("Checking for version changes and performing backup if needed"); - - let handle = app.handle().clone(); - match tauri::async_runtime::spawn_blocking(move || { - backup::perform_version_check_and_backup(handle) - }) - .await - { - Ok(Ok(_)) => { - tracing::info!("Version backup check completed successfully"); - Ok(()) - } - Ok(Err(e)) => { - tracing::error!( - error = %e, - "Version backup check failed, but continuing with startup" - ); - Ok(()) - } - Err(e) => { - tracing::error!( - error = %e, - "Version backup task panicked, but continuing with startup" - ); - Ok(()) - } - } -} - -/// Gracefully quit the Hoppscotch Desktop -/// -/// This command is invoked from the frontend when the user triggers -/// the quit action (typically via Cmd+Q/Ctrl+Q keyboard shortcut). -/// -/// It performs a clean shutdown by logging the quit request -/// for debugging and then calling `app.exit(0)` which triggers -/// v2's graceful shutdown. -/// -/// It basically trigger `RunEvent::ExitRequested` -/// followed by `RunEvent::Exit` events. -/// See https://docs.rs/tauri/latest/tauri/struct.AppHandle.html#method.exit -#[tauri::command] -fn quit_app(app: tauri::AppHandle) -> Result<(), String> { - tracing::info!("Quit command received, shutting down application"); - app.exit(0); - Ok(()) -} - -#[cfg_attr(mobile, tauri::mobile_entry_point)] -pub fn run() { - let mode = if cfg!(feature = "portable") { - "portable" - } else { - "standard" - }; - tracing::info!(mode = mode, "Hoppscotch Desktop running in {} mode", mode); - - #[cfg(all(feature = "portable", windows))] - { - tracing::debug!("Checking WebView initialization for portable Windows variant"); - webview::init_webview(); - } - - let appload_config = match HoppApploadConfig::new() { - Ok(config) => config, - Err(e) => { - tracing::error!(error = %e, "Failed to initialize application configuration"); - return; - } - }; - - if let Err(e) = appload_config.write_vendored() { - tracing::error!(error = %e, "Failed to write bundled files"); - return; - } - - let appload_config = appload_config.build(); - - let app = tauri::Builder::default() - .setup(|app| { - // Set up native Edit menu to enable standard clipboard shortcuts (copy, paste, etc.) - // Required on Linux where webkit2gtk does not handle these without menu items - #[cfg(target_os = "linux")] - { - use tauri::menu::{Menu, PredefinedMenuItem, Submenu}; - - let result = (|| -> Result<(), Box> { - let handle = app.handle(); - let edit_menu = Submenu::with_items( - handle, - "Edit", - true, - &[ - &PredefinedMenuItem::undo(handle, None)?, - &PredefinedMenuItem::redo(handle, None)?, - &PredefinedMenuItem::separator(handle)?, - &PredefinedMenuItem::cut(handle, None)?, - &PredefinedMenuItem::copy(handle, None)?, - &PredefinedMenuItem::paste(handle, None)?, - &PredefinedMenuItem::separator(handle)?, - &PredefinedMenuItem::select_all(handle, None)?, - ], - )?; - // NOTE: This menu bar will be visible on Linux. Removing it or hiding it - // also removes the accelerator registrations and breaks clipboard shortcuts - // (webkit2gtk requires native menu items to recognise Ctrl+C/V/X etc.). - // See https://github.com/tauri-apps/tauri/issues/2397 - let menu = Menu::with_items(handle, &[&edit_menu])?; - app.set_menu(menu)?; - Ok(()) - })(); - - if let Err(e) = result { - tracing::warn!(error = %e, "Failed to set up native Edit menu; clipboard shortcuts may not work"); - } - } - - tauri::async_runtime::block_on(async { - if let Err(e) = setup_version_backup(app).await { - tracing::error!(error = %e, "Failed to setup version backup"); - return Err(e.into()); - } - - if let Err(e) = setup_server(app) { - tracing::error!(error = %e, "Failed to setup server"); - return Err(e.into()); - } - - if let Err(e) = setup_deep_link_handler(app) { - tracing::error!(error = %e, "Failed to setup deep link handler"); - return Err(e.into()); - } - - tracing::info!("Starting Hoppscotch Desktop v{}", env!("CARGO_PKG_VERSION")); - Ok(()) - }) - }) - .plugin( - tauri_plugin_window_state::Builder::new() - .with_state_flags( - StateFlags::SIZE - | StateFlags::POSITION - | StateFlags::MAXIMIZED - | StateFlags::FULLSCREEN, - ) - .with_denylist(&["main"]) - .build(), - ) - .plugin(tauri_plugin_process::init()) - .plugin(tauri_plugin_http::init()) - .plugin(tauri_plugin_opener::init()) - .plugin(tauri_plugin_updater::Builder::new().build()) - .plugin(tauri_plugin_store::Builder::new().build()) - .plugin(tauri_plugin_deep_link::init()) - .plugin(tauri_plugin_dialog::init()) - .plugin(tauri_plugin_shell::init()) - .plugin(tauri_plugin_fs::init()) - .plugin(tauri_plugin_appload::init(appload_config)) - .plugin(tauri_plugin_relay::init()) - .invoke_handler(tauri::generate_handler![ - is_portable, - hopp_auth_port, - quit_app, - backup::check_and_backup_on_version_change, - config::set_desktop_config, - updater::check_for_updates, - updater::download_and_install_update, - updater::restart_application, - updater::cancel_update, - updater::get_download_progress, - updater::is_portable_mode, - path::get_config_dir, - path::get_latest_dir, - path::get_instance_dir, - path::get_store_dir, - path::get_backup_dir, - path::get_logs_dir, - logger::append_log, - path::read_log, - path::get_appload_registry, - ]) - .run(tauri::generate_context!()); - - if let Err(e) = app { - tracing::error!(error = %e, "Error while running Hoppscotch Desktop"); - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/logger.rs b/packages/hoppscotch-desktop/src-tauri/src/logger.rs deleted file mode 100644 index 60f62381..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/logger.rs +++ /dev/null @@ -1,77 +0,0 @@ -use std::io::Write; -use std::path::PathBuf; - -use file_rotate::{compression::Compression, suffix::AppendCount, ContentLimit, FileRotate}; -use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; - -use crate::path; - -pub struct LogGuard(pub tracing_appender::non_blocking::WorkerGuard); - -pub fn setup(log_dir: &PathBuf) -> Result> { - std::fs::create_dir_all(log_dir)?; - - let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| "debug".into()); - - let log_file_path = path::log_file_path(); - tracing::info!(log_file_path =? &log_file_path); - - let file = FileRotate::new( - &log_file_path, - AppendCount::new(5), - ContentLimit::Bytes(10 * 1024 * 1024), - Compression::None, - None, - ); - - let (non_blocking, guard) = tracing_appender::non_blocking(file); - - let console_layer = fmt::layer() - .with_writer(std::io::stdout) - .with_thread_ids(true) - .with_thread_names(true) - .with_ansi(!cfg!(target_os = "windows")); - - let file_layer = fmt::layer() - .with_writer(non_blocking) - .with_ansi(false) - .with_thread_ids(true) - .with_thread_names(true); - - tracing_subscriber::registry() - .with(env_filter) - .with(file_layer) - .with(console_layer) - .init(); - - tracing::info!( - log_file = %log_file_path.display(), - "Logging initialized with rotating file" - ); - - Ok(LogGuard(guard)) -} - -// appends content to a log file inside `logs_dir()`. bypasses the Tauri -// fs plugin so the write isn't subject to the scope in capabilities.json. -// the filename is caller-controlled but confined to `logs_dir()` to -// prevent arbitrary file writes -#[tauri::command] -pub fn append_log(filename: String, content: String) -> Result<(), String> { - let dir = path::logs_dir().map_err(|e| e.to_string())?; - let path = dir.join(&filename); - - // safety: reject any path traversal attempts - if path.parent() != Some(&dir) { - return Err("invalid log filename".to_string()); - } - - let mut file = std::fs::OpenOptions::new() - .create(true) - .append(true) - .open(&path) - .map_err(|e| e.to_string())?; - - file.write_all(content.as_bytes()) - .map_err(|e| e.to_string()) -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/main.rs b/packages/hoppscotch-desktop/src-tauri/src/main.rs deleted file mode 100644 index 641b8464..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/main.rs +++ /dev/null @@ -1,65 +0,0 @@ -// Prevents additional console window on Windows in release, DO NOT REMOVE!! -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] - -use hoppscotch_desktop_lib::{ - logger::{self, LogGuard}, - path, -}; - -fn main() { - #[cfg(feature = "portable")] - println!("Starting Hoppscotch Desktop in PORTABLE mode"); - - #[cfg(not(feature = "portable"))] - println!("Starting Hoppscotch Desktop in STANDARD mode"); - - let log_dir = match path::logs_dir() { - Ok(dir) => { - println!("Log directory: {}", dir.display()); - dir - } - Err(e) => { - eprintln!("Failed to setup logging directory: {}", e); - println!("Starting Hoppscotch Desktop without logging..."); - return hoppscotch_desktop_lib::run(); - } - }; - - let Ok(LogGuard(guard)) = logger::setup(&log_dir) else { - eprintln!("Failed to setup logging!"); - println!("Starting Hoppscotch Desktop without logging..."); - return hoppscotch_desktop_lib::run(); - }; - - // This keeps the guard alive, this is scoped to `main` - // so it can only drop when the entire app exits, - // so safe to have it like this. - let _guard = guard; - - #[cfg(feature = "portable")] - { - tracing::info!( - "Hoppscotch Desktop v{} starting in PORTABLE mode", - env!("CARGO_PKG_VERSION") - ); - if let Ok(config_dir) = path::config_dir() { - tracing::info!("Config directory (portable): {}", config_dir.display()); - } - if let Ok(current_dir) = std::env::current_dir() { - tracing::info!("Current working directory: {}", current_dir.display()); - } - } - - #[cfg(not(feature = "portable"))] - { - tracing::info!( - "Hoppscotch Desktop v{} starting in STANDARD mode", - env!("CARGO_PKG_VERSION") - ); - if let Ok(config_dir) = path::config_dir() { - tracing::info!("Config directory (standard): {}", config_dir.display()); - } - } - - hoppscotch_desktop_lib::run() -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/path.rs b/packages/hoppscotch-desktop/src-tauri/src/path.rs deleted file mode 100644 index 2a37df87..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/path.rs +++ /dev/null @@ -1,350 +0,0 @@ -use std::io; -use std::path::PathBuf; - -/// App identifier (identical to `tauri.conf.json`) -/// used for various directories and configurations -pub const APP_ID: &str = "io.hoppscotch.desktop"; - -pub fn config_dir() -> io::Result { - let path = platform_config_dir(); - std::fs::create_dir_all(&path)?; - Ok(path) -} - -pub fn latest_dir() -> io::Result { - let path = config_dir()?.join("latest"); - std::fs::create_dir_all(&path)?; - Ok(path) -} - -pub fn instance_dir() -> io::Result { - let path = latest_dir()?.join("instance"); - std::fs::create_dir_all(&path)?; - Ok(path) -} - -pub fn store_dir() -> io::Result { - let path = latest_dir()?.join("store"); - std::fs::create_dir_all(&path)?; - Ok(path) -} - -pub fn get_versioned_backup_dir(version: &str) -> io::Result { - let backup_root = backup_dir()?; - let versioned_path = backup_root.join(format!("v{}", version)); - std::fs::create_dir_all(&versioned_path)?; - Ok(versioned_path) -} - -pub fn backup_dir() -> io::Result { - let path = config_dir()?.join("backup"); - std::fs::create_dir_all(&path)?; - Ok(path) -} - -pub fn logs_dir() -> io::Result { - let path = platform_logs_dir(); - std::fs::create_dir_all(&path)?; - Ok(path) -} - -#[tauri::command] -pub fn get_config_dir() -> Result { - config_dir() - .map(|path| path.to_string_lossy().to_string()) - .map_err(|err| err.to_string()) -} - -#[tauri::command] -pub fn get_latest_dir() -> Result { - latest_dir() - .map(|path| path.to_string_lossy().to_string()) - .map_err(|err| err.to_string()) -} - -#[tauri::command] -pub fn get_instance_dir() -> Result { - instance_dir() - .map(|path| path.to_string_lossy().to_string()) - .map_err(|err| err.to_string()) -} - -#[tauri::command] -pub fn get_store_dir() -> Result { - store_dir() - .map(|path| path.to_string_lossy().to_string()) - .map_err(|err| err.to_string()) -} - -#[tauri::command] -pub fn get_backup_dir() -> Result { - backup_dir() - .map(|path| path.to_string_lossy().to_string()) - .map_err(|err| err.to_string()) -} - -#[tauri::command] -pub fn get_logs_dir() -> Result { - logs_dir() - .map(|path| path.to_string_lossy().to_string()) - .map_err(|err| err.to_string()) -} - -// exposes the appload storage registry so the JS side can match the current -// webview's hostname back to the original server URL. this is needed because -// the app:// URL encoding is lossy (generate_bundle_name in appload replaces -// both dots and hyphens with underscores, so "test-org" and "test_org" would -// produce the same bundle name). returns an empty registry on fresh installs. -// -// FE-1140: the lossy encoding means two distinct org domains that differ only -// by hyphens vs underscores would collide at the bundle name level. DNS rules -// make this unlikely in practice but the encoding should be hardened later -#[tauri::command] -pub fn get_appload_registry() -> Result { - let registry_path = config_dir() - .map_err(|err| err.to_string())? - .join("registry.json"); - - if !registry_path.exists() { - return Ok(r#"{"version":1,"servers":{}}"#.to_string()); - } - - std::fs::read_to_string(®istry_path).map_err(|err| err.to_string()) -} - -// reads the contents of a log file inside `logs_dir()`. same scope -// bypass as `append_log` in logger.rs -#[tauri::command] -pub fn read_log(filename: String) -> Result { - let dir = logs_dir().map_err(|e| e.to_string())?; - let path = dir.join(&filename); - - if path.parent() != Some(&dir) { - return Err("invalid log filename".to_string()); - } - - std::fs::read_to_string(&path).map_err(|e| e.to_string()) -} - -pub fn log_file_path() -> PathBuf { - platform_logs_dir().join(format!("{}.log", APP_ID)) -} - -pub fn bundle_path() -> PathBuf { - if cfg!(feature = "portable") { - std::env::current_dir() - .unwrap_or_else(|_| std::env::temp_dir()) - .join("hopp_bundle.zip") - } else { - std::env::temp_dir().join("hopp_bundle.zip") - } -} - -pub fn manifest_path() -> PathBuf { - if cfg!(feature = "portable") { - std::env::current_dir() - .unwrap_or_else(|_| std::env::temp_dir()) - .join("hopp_manifest.json") - } else { - std::env::temp_dir().join("hopp_manifest.json") - } -} - -// Follows how `tauri` does this -// see: https://github.com/tauri-apps/tauri/blob/dev/crates/tauri/src/path/desktop.rs -fn platform_config_dir() -> PathBuf { - if cfg!(feature = "portable") { - return std::env::current_dir() - .unwrap_or_else(|_| std::env::temp_dir()) - .join("hoppscotch-desktop-data"); - } - - #[cfg(target_os = "macos")] - { - dirs::home_dir() - .map(|dir| dir.join("Library/Application Support").join(APP_ID)) - .unwrap_or_else(|| std::env::temp_dir().join(APP_ID)) - } - - #[cfg(target_os = "windows")] - { - dirs::config_dir() - .map(|dir| dir.join(APP_ID)) - .unwrap_or_else(|| std::env::temp_dir().join(APP_ID)) - } - - #[cfg(target_os = "linux")] - { - dirs::config_dir() - .map(|dir| dir.join(APP_ID)) - .unwrap_or_else(|| std::env::temp_dir().join(APP_ID)) - } - - // Fallback for others - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "linux")))] - { - std::env::temp_dir().join(APP_ID) - } -} - -// Follows how `tauri` does this -// see: https://github.com/tauri-apps/tauri/blob/dev/crates/tauri/src/path/desktop.rs -fn platform_logs_dir() -> PathBuf { - if cfg!(feature = "portable") { - return std::env::current_dir() - .unwrap_or_else(|_| std::env::temp_dir()) - .join("logs"); - } - - #[cfg(target_os = "macos")] - { - dirs::home_dir() - .map(|dir| dir.join("Library/Logs").join(APP_ID)) - .unwrap_or_else(|| std::env::temp_dir().join(APP_ID).join("logs")) - } - - // Also fallback for others - #[cfg(not(target_os = "macos"))] - { - dirs::data_local_dir() - .map(|dir| dir.join(APP_ID).join("logs")) - .unwrap_or_else(|| std::env::temp_dir().join(APP_ID).join("logs")) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_app_id_constant() { - assert_eq!(APP_ID, "io.hoppscotch.desktop"); - } - - #[test] - fn test_log_file_path() { - let path = log_file_path(); - assert!(path.to_string_lossy().contains("io.hoppscotch.desktop.log")); - } - - #[test] - fn test_manifest_path_portable() { - let path = manifest_path(); - assert!(path.to_string_lossy().ends_with("hopp_manifest.json")); - } - - #[test] - fn test_platform_config_dir_structure() { - let config_dir = platform_config_dir(); - - #[cfg(feature = "portable")] - { - assert!(config_dir - .to_string_lossy() - .contains("hoppscotch-desktop-data")); - } - - #[cfg(not(feature = "portable"))] - { - assert!(config_dir.to_string_lossy().contains(APP_ID)); - } - } - - #[test] - fn test_platform_logs_dir_structure() { - let logs_dir = platform_logs_dir(); - - #[cfg(feature = "portable")] - { - assert!(logs_dir.to_string_lossy().ends_with("logs")); - } - - #[cfg(not(feature = "portable"))] - { - assert!(logs_dir.to_string_lossy().contains(APP_ID)); - } - } - - #[test] - fn test_get_config_dir_command() { - let result = get_config_dir(); - assert!(result.is_ok()); - let path_str = result.unwrap(); - assert!(!path_str.is_empty()); - } - - #[test] - fn test_get_logs_dir_command() { - let result = get_logs_dir(); - assert!(result.is_ok()); - let path_str = result.unwrap(); - assert!(!path_str.is_empty()); - } -} - -#[cfg(test)] -mod portable_tests { - // NOTE: These tests should only run when - // the portable feature flag is enabled - #[cfg(feature = "portable")] - #[test] - fn test_portable_bundle_path() { - let path = bundle_path(); - assert!(path.file_name().unwrap() == "hopp_bundle.zip"); - } - - #[cfg(feature = "portable")] - #[test] - fn test_portable_manifest_path() { - let path = manifest_path(); - assert!(path.file_name().unwrap() == "hopp_manifest.json"); - } - - #[cfg(feature = "portable")] - #[test] - fn test_portable_config_dir_structure() { - let config_dir = platform_config_dir(); - assert!(config_dir - .to_string_lossy() - .contains("hoppscotch-desktop-data")); - } -} - -#[cfg(test)] -mod platform_tests { - use super::*; - - #[cfg(target_os = "macos")] - #[test] - fn test_macos_paths() { - let config_dir = platform_config_dir(); - if !cfg!(feature = "portable") { - assert!(config_dir - .to_string_lossy() - .contains("Library/Application Support")); - } - - let logs_dir = platform_logs_dir(); - if !cfg!(feature = "portable") { - assert!(logs_dir.to_string_lossy().contains("Library/Logs")); - } - } - - #[cfg(target_os = "windows")] - #[test] - fn test_windows_paths() { - let config_dir = platform_config_dir(); - if !cfg!(feature = "portable") { - assert!(config_dir.to_string_lossy().contains(APP_ID)); - } - } - - #[cfg(target_os = "linux")] - #[test] - fn test_linux_paths() { - let config_dir = platform_config_dir(); - if !cfg!(feature = "portable") { - assert!(config_dir.to_string_lossy().contains(APP_ID)); - } - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/server.rs b/packages/hoppscotch-desktop/src-tauri/src/server.rs deleted file mode 100644 index 65362bad..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/server.rs +++ /dev/null @@ -1,155 +0,0 @@ -use std::net::SocketAddr; - -use axum::{ - extract::Query, - http::StatusCode, - response::{IntoResponse, Response}, - routing::get, - Router, -}; -use serde::{Deserialize, Serialize}; -use tauri::{Emitter, Runtime}; -use tower_http::cors::CorsLayer; - -#[derive(Debug, Serialize, Deserialize)] -struct AuthTokensQuery { - access_token: String, - refresh_token: Option, -} - -async fn device_token( - Query(token_query): Query, - handle: tauri::AppHandle, -) -> Response { - tracing::info!("Processing device token request"); - - let serialized = match serde_json::to_value(token_query) { - Ok(val) => val, - Err(e) => { - tracing::error!("Failed to serialize tokens: {}", e); - return StatusCode::INTERNAL_SERVER_ERROR.into_response(); - } - }; - - match handle.emit("hopp_auth://token", serialized) { - Ok(_) => tracing::info!("Device token event emitted successfully"), - Err(e) => tracing::error!( - error.message = %e, - error.type = %std::any::type_name_of_val(&e), - "Failed to emit device token event" - ), - } - StatusCode::OK.into_response() -} - -pub(crate) fn init(port: u16, handle: tauri::AppHandle) -> u16 { - tracing::info!("Beginning server initialization"); - - let app = Router::new() - .route( - "/device-token", - get(move |query| device_token(query, handle.clone())), - ) - .layer(CorsLayer::very_permissive()); - - let addr = SocketAddr::from(([127, 0, 0, 1], port)); - - tauri::async_runtime::spawn(async move { - tracing::info!( - address = %addr, - port = port, - "Starting HTTP server" - ); - - let listener = match tokio::net::TcpListener::bind(addr).await { - Ok(l) => { - tracing::info!( - local_addr = %l.local_addr().unwrap_or(addr), - "Server bound successfully" - ); - l - } - Err(e) => { - tracing::error!( - error.message = %e, - error.kind = ?e.kind(), - attempted_address = %addr, - "Server bind failed" - ); - panic!("Could not bind to the unused port"); - } - }; - - tracing::info!("Server starting"); - if let Err(e) = axum::serve(listener, app).await { - tracing::error!( - error.message = %e, - error.type = %std::any::type_name_of_val(&e), - "Server crashed" - ); - } - }); - - port -} - -// `AuthTokensQuery` gets deserialized from query params on the `/device-token` -// endpoint. the desktop app receives auth tokens this way after the user does -// browser-based login and gets redirected back. `refresh_token` is optional -// because some auth flows (like the device code flow) don't always return one, -// and we don't wanna blow up if it's missing. -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_auth_tokens_query_deserialize_both_tokens() { - let json = r#"{"access_token":"abc123","refresh_token":"def456"}"#; - let query: AuthTokensQuery = serde_json::from_str(json).unwrap(); - - assert_eq!(query.access_token, "abc123"); - assert_eq!(query.refresh_token, Some("def456".to_string())); - } - - #[test] - fn test_auth_tokens_query_deserialize_without_refresh() { - let json = r#"{"access_token":"abc123"}"#; - let query: AuthTokensQuery = serde_json::from_str(json).unwrap(); - - assert_eq!(query.access_token, "abc123"); - assert_eq!(query.refresh_token, None); - } - - #[test] - fn test_auth_tokens_query_deserialize_fails_without_access_token() { - let json = r#"{"refresh_token":"def456"}"#; - let result: Result = serde_json::from_str(json); - - assert!(result.is_err()); - } - - #[test] - fn test_auth_tokens_query_roundtrip() { - let original = AuthTokensQuery { - access_token: "token_value".to_string(), - refresh_token: Some("refresh_value".to_string()), - }; - - let serialized = serde_json::to_value(&original).unwrap(); - assert_eq!(serialized["access_token"], "token_value"); - assert_eq!(serialized["refresh_token"], "refresh_value"); - - let deserialized: AuthTokensQuery = serde_json::from_value(serialized).unwrap(); - assert_eq!(deserialized.access_token, original.access_token); - assert_eq!(deserialized.refresh_token, original.refresh_token); - } - - #[test] - fn test_auth_tokens_query_null_refresh_token() { - let json = r#"{"access_token":"abc123","refresh_token":null}"#; - let query: AuthTokensQuery = serde_json::from_str(json).unwrap(); - - assert_eq!(query.access_token, "abc123"); - assert_eq!(query.refresh_token, None); - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/updater.rs b/packages/hoppscotch-desktop/src-tauri/src/updater.rs deleted file mode 100644 index 2a57f58b..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/updater.rs +++ /dev/null @@ -1,308 +0,0 @@ -use crate::{dialog, util}; -use native_dialog::MessageType; -use serde::{Deserialize, Serialize}; -use std::sync::Arc; -use tauri::{AppHandle, Emitter}; -use tauri_plugin_updater::{Update, UpdaterExt}; -use tokio::sync::Mutex; - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct UpdateInfo { - pub available: bool, - pub current_version: String, - pub latest_version: Option, - pub release_notes: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct DownloadProgress { - pub downloaded: u64, - pub total: Option, - pub percentage: f64, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(tag = "type")] -pub enum UpdateEvent { - CheckStarted, - CheckCompleted { - info: UpdateInfo, - }, - CheckFailed { - error: String, - }, - DownloadStarted { - #[serde(rename = "totalBytes")] - total_bytes: Option, - }, - DownloadProgress { - progress: DownloadProgress, - }, - DownloadCompleted, - InstallStarted, - InstallCompleted, - RestartRequired, - UpdateCancelled, - Error { - message: String, - }, -} - -// Global state for tracking update progress -// TODO: See if it's possible to let Tauri handle this state management -static UPDATE_STATE: std::sync::LazyLock>>> = - std::sync::LazyLock::new(|| Arc::new(Mutex::new(None))); - -static DOWNLOAD_STATE: std::sync::LazyLock>> = - std::sync::LazyLock::new(|| { - Arc::new(Mutex::new(DownloadProgress { - downloaded: 0, - total: None, - percentage: 0.0, - })) - }); - -/// Check for updates and returns basic information -/// For portable mode: Shows native dialog if update found -/// For standard mode: Just returns information, UI handles the rest -#[tauri::command] -pub async fn check_for_updates( - app: AppHandle, - show_native_dialog: bool, -) -> Result { - tracing::info!(portable_dialog = show_native_dialog, "Checking for updates"); - - let _ = app.emit("updater-event", UpdateEvent::CheckStarted); - - let updater = app.updater().map_err(|e| { - let error_msg = format!("Failed to initialize updater: {}", e); - tracing::error!("{}", error_msg); - let _ = app.emit( - "updater-event", - UpdateEvent::CheckFailed { - error: error_msg.clone(), - }, - ); - error_msg - })?; - - match updater.check().await { - Ok(Some(update)) => { - let current_version = app.package_info().version.to_string(); - let latest_version = update.version.to_string(); - let release_notes = update.body.clone(); - - tracing::info!(current_version, latest_version, "Update available"); - - { - let mut state = UPDATE_STATE.lock().await; - *state = Some(update); - } - - let update_info = UpdateInfo { - available: true, - current_version, - latest_version: Some(latest_version.clone()), - release_notes, - }; - - if show_native_dialog { - handle_portable_update_dialog(&app, &latest_version).await?; - } - - let _ = app.emit( - "updater-event", - UpdateEvent::CheckCompleted { - info: update_info.clone(), - }, - ); - - Ok(update_info) - } - Ok(None) => { - tracing::info!("No updates available"); - let update_info = UpdateInfo { - available: false, - current_version: app.package_info().version.to_string(), - latest_version: None, - release_notes: None, - }; - - let _ = app.emit( - "updater-event", - UpdateEvent::CheckCompleted { - info: update_info.clone(), - }, - ); - - Ok(update_info) - } - Err(e) => { - let error_msg = format!("Failed to check for updates: {}", e); - tracing::error!("{}", error_msg); - let _ = app.emit( - "updater-event", - UpdateEvent::CheckFailed { - error: error_msg.clone(), - }, - ); - Err(error_msg) - } - } -} - -/// Download and install update (for standard mode) -/// Emits progress events that the frontend can listen to -#[tauri::command] -pub async fn download_and_install_update(app: AppHandle) -> Result<(), String> { - tracing::info!("Starting update download and installation"); - - let update = { - let mut state = UPDATE_STATE.lock().await; - state.take().ok_or("No update available to install")? - }; - - let _ = app.emit( - "updater-event", - UpdateEvent::DownloadStarted { total_bytes: None }, - ); - - { - let mut download_state = DOWNLOAD_STATE.lock().await; - download_state.downloaded = 0; - download_state.total = None; - download_state.percentage = 0.0; - } - - let app_progress = app.clone(); - let app_callback = app.clone(); - - update - .download_and_install( - move |chunk_length, content_length| { - let app = app_progress.clone(); - tauri::async_runtime::spawn(async move { - let mut download_state = DOWNLOAD_STATE.lock().await; - - if let Some(total) = content_length { - if download_state.total.is_none() { - download_state.total = Some(total); - let _ = app.emit( - "updater-event", - UpdateEvent::DownloadStarted { - total_bytes: Some(total), - }, - ); - } - } - - download_state.downloaded += chunk_length as u64; - - if let Some(total) = download_state.total { - download_state.percentage = - (download_state.downloaded as f64 / total as f64) * 100.0; - } - - let progress = download_state.clone(); - // Release the lock before emitting - // TODO: See if it's possible to not have a lock at all - drop(download_state); - - let _ = app.emit("updater-event", UpdateEvent::DownloadProgress { progress }); - }); - }, - move || { - let app = app_callback.clone(); - tauri::async_runtime::spawn(async move { - let _ = app.emit("updater-event", UpdateEvent::DownloadCompleted); - let _ = app.emit("updater-event", UpdateEvent::InstallStarted); - let _ = app.emit("updater-event", UpdateEvent::RestartRequired); - }); - }, - ) - .await - .map_err(|e| { - let error_msg = format!("Failed to download and install update: {}", e); - let _ = app.emit( - "updater-event", - UpdateEvent::Error { - message: error_msg.clone(), - }, - ); - error_msg - })?; - - tracing::info!("Update download and installation completed successfully"); - Ok(()) -} - -/// Restart the application (for standard mode) -#[tauri::command] -pub async fn restart_application() -> Result<(), String> { - tracing::info!("Restarting application"); - tauri::process::restart(&tauri::Env::default()); - // This function never returns because the app restarts, - // so it's safe to allow `unreachable_code` here. - #[allow(unreachable_code)] - Ok(()) -} - -/// Cancel any ongoing update process -#[tauri::command] -pub async fn cancel_update(app: AppHandle) -> Result<(), String> { - tracing::info!("Cancelling update"); - - { - let mut state = UPDATE_STATE.lock().await; - *state = None; - } - - { - let mut download_state = DOWNLOAD_STATE.lock().await; - download_state.downloaded = 0; - download_state.total = None; - download_state.percentage = 0.0; - } - - let _ = app.emit("updater-event", UpdateEvent::UpdateCancelled); - Ok(()) -} - -/// Get current download progress (for polling if needed) -#[tauri::command] -pub async fn get_download_progress() -> Result { - let download_state = DOWNLOAD_STATE.lock().await; - Ok(download_state.clone()) -} - -/// Check if we're running in portable mode (for frontend convenience) -#[tauri::command] -pub fn is_portable_mode() -> bool { - cfg!(feature = "portable") -} - -/// Helper function to handle portable mode update dialog -async fn handle_portable_update_dialog( - _app: &AppHandle, - latest_version: &str, -) -> Result<(), String> { - let download_url = "https://hoppscotch.com/download"; - let message = format!( - "An update (version {}) is available for Hoppscotch Desktop (Portable).\n\nWould you like to download it now?\n\n• Yes = Download now\n• No = Remind me later", - latest_version - ); - - if dialog::confirm("Download Update", &message, MessageType::Info) { - if util::open_link(download_url).is_none() { - dialog::error(&format!( - "Failed to open download page. Please visit {}", - download_url - )); - return Err("Failed to open download URL".to_string()); - } - } - - Ok(()) -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/util.rs b/packages/hoppscotch-desktop/src-tauri/src/util.rs deleted file mode 100644 index 42abe788..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/util.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::process::{Command, Stdio}; - -pub fn open_link(link: &str) -> Option<()> { - let null = Stdio::null(); - - #[cfg(target_os = "windows")] - { - Command::new("rundll32") - .args(["url.dll,FileProtocolHandler", link]) - .stdout(null) - .spawn() - .ok() - .map(|_| ()) - } - - #[cfg(target_os = "macos")] - { - Command::new("open") - .arg(link) - .stdout(null) - .spawn() - .ok() - .map(|_| ()) - } - - #[cfg(target_os = "linux")] - { - Command::new("xdg-open") - .arg(link) - .stdout(null) - .spawn() - .ok() - .map(|_| ()) - } - - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - None - } -} - -#[cfg(test)] -mod tests { - use super::*; - - // NOTE: These tests won't actually open URLs in testing environments - // but these will test the command construction logic - #[test] - fn test_open_link_with_valid_url() { - let test_url = "https://example.com"; - - // The function should not panic and should return `Some(())` or `None` - // depending on whether the command can be spawned - let result = open_link(test_url); - - // This should return `Some(())` if the command exists, - // on unsupported platforms, this should return None - #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] - { - assert!(result.is_some() || result.is_none()); - } - - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - assert_eq!(result, None); - } - } - - #[test] - fn test_open_link_with_empty_string() { - let result = open_link(""); - - #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] - { - assert!(result.is_some() || result.is_none()); - } - - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - assert_eq!(result, None); - } - } - - #[test] - fn test_open_link_with_special_characters() { - let test_urls = vec![ - "https://example.com/path with spaces", - "https://example.com/path?query=value&other=test", - "https://example.com/path#fragment", - "file:///path/to/local/file.txt", - ]; - - for url in test_urls { - let result = open_link(url); - - #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] - { - assert!(result.is_some() || result.is_none()); - } - - #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))] - { - assert_eq!(result, None); - } - } - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/webview/error.rs b/packages/hoppscotch-desktop/src-tauri/src/webview/error.rs deleted file mode 100644 index 7bfeff52..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/webview/error.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::io; - -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum WebViewError { - #[error("Failed to open URL: {0}")] - UrlOpen(#[from] io::Error), - #[error("Failed to download WebView2 installer: {0}")] - Download(String), - #[error("WebView2 installation failed: {0}")] - Installation(String), - #[error("Failed during request: {0}")] - Request(#[from] tauri_plugin_http::reqwest::Error), -} diff --git a/packages/hoppscotch-desktop/src-tauri/src/webview/mod.rs b/packages/hoppscotch-desktop/src-tauri/src/webview/mod.rs deleted file mode 100644 index 02381545..00000000 --- a/packages/hoppscotch-desktop/src-tauri/src/webview/mod.rs +++ /dev/null @@ -1,212 +0,0 @@ -/// The WebView2 Runtime is a critical dependency for Tauri applications on Windows. -/// We need to check for its presence, see [Source: GitHub Issue #59 - Portable windows build](https://github.com/tauri-apps/tauri-action/issues/59#issuecomment-827142638) -/// -/// > "Tauri requires an installer if you define app resources, external binaries or running on environments that do not have Webview2 runtime installed. So I don't think it's a good idea to have a "portable" option since a Tauri binary itself isn't 100% portable." -/// -/// The approach for checking WebView2 installation is based on Microsoft's official documentation, which states: -/// -/// > ###### Detect if a WebView2 Runtime is already installed -/// > -/// > To verify that a WebView2 Runtime is installed, use one of the following approaches: -/// > -/// > * Approach 1: Inspect the `pv (REG_SZ)` regkey for the WebView2 Runtime at both of the following registry locations. The `HKEY_LOCAL_MACHINE` regkey is used for _per-machine_ install. The `HKEY_CURRENT_USER` regkey is used for _per-user_ install. -/// > -/// > For WebView2 applications, at least one of these regkeys must be present and defined with a version greater than 0.0.0.0. If neither regkey exists, or if only one of these regkeys exists but its value is `null`, an empty string, or 0.0.0.0, this means that the WebView2 Runtime isn't installed on the client. Inspect these regkeys to detect whether the WebView2 Runtime is installed, and to get the version of the WebView2 Runtime. Find `pv (REG_SZ)` at the following two locations. -/// > -/// > The two registry locations to inspect on 64-bit Windows: -/// > -/// > ```text -/// > HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5} -/// > -/// > HKEY_CURRENT_USER\Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5} -/// > ``` -/// > -/// > The two registry locations to inspect on 32-bit Windows: -/// > -/// > ```text -/// > HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5} -/// > -/// > HKEY_CURRENT_USER\Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5} -/// > ``` -/// > -/// > * Approach 2: Run [GetAvailableCoreWebView2BrowserVersionString](/microsoft-edge/webview2/reference/win32/webview2-idl#getavailablecorewebview2browserversionstring) and evaluate whether the `versionInfo` is `nullptr`. `nullptr` indicates that the WebView2 Runtime isn't installed. This API returns version information for the WebView2 Runtime or for any installed preview channels of Microsoft Edge (Beta, Dev, or Canary). -/// -/// See: https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution?tabs=dotnetcsharp#detect-if-a-webview2-runtime-is-already-installed -/// -/// Our implementation uses Approach 1, checking both the 32-bit (WOW6432Node) and 64-bit registry locations -/// to make sure we have critical dependency compatibility with different system architectures. -pub mod error; - -use std::{io, ops::Not}; - -use native_dialog::MessageType; - -use crate::{dialog, util}; -use error::WebViewError; - -#[cfg(windows)] -use { - std::io::Cursor, - std::process::Command, - tauri_plugin_http::reqwest, - tempfile::TempDir, - winreg::{ - enums::{HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE}, - RegKey, - }, -}; - -const TAURI_WEBVIEW_REF: &str = "https://v2.tauri.app/references/webview-versions/"; -const WINDOWS_WEBVIEW_REF: &str = - "https://developer.microsoft.com/microsoft-edge/webview2/#download-section"; - -fn is_available() -> bool { - #[cfg(windows)] - { - const KEY_WOW64: &str = r"SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"; - const KEY: &str = - r"SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}"; - - let hklm = RegKey::predef(HKEY_LOCAL_MACHINE); - let hkcu = RegKey::predef(HKEY_CURRENT_USER); - - [ - hklm.open_subkey(KEY_WOW64), - hkcu.open_subkey(KEY_WOW64), - hklm.open_subkey(KEY), - hkcu.open_subkey(KEY), - ] - .into_iter() - .any(|result| result.is_ok()) - } - - #[cfg(not(windows))] - { - true - } -} - -fn open_install_website() -> Result<(), WebViewError> { - let url = if cfg!(windows) { - WINDOWS_WEBVIEW_REF - } else { - TAURI_WEBVIEW_REF - }; - - util::open_link(url).map(|_| ()).ok_or_else(|| { - WebViewError::UrlOpen(io::Error::new( - io::ErrorKind::Other, - "Failed to open browser to WebView download section", - )) - }) -} - -#[cfg(windows)] -async fn install() -> Result<(), WebViewError> { - const WEBVIEW2_BOOTSTRAPPER_URL: &str = "https://go.microsoft.com/fwlink/p/?LinkId=2124703"; - const DEFAULT_FILENAME: &str = "MicrosoftEdgeWebview2Setup.exe"; - - let client = reqwest::Client::builder() - .user_agent("Hoppscotch Agent") - .gzip(true) - .build()?; - - let response = client.get(WEBVIEW2_BOOTSTRAPPER_URL).send().await?; - - if !response.status().is_success() { - return Err(WebViewError::Download(format!( - "Failed to download WebView2 bootstrapper. Status: {}", - response.status() - ))); - } - - let filename = - get_filename_from_response(&response).unwrap_or_else(|| DEFAULT_FILENAME.to_owned()); - - let tmp_dir = TempDir::with_prefix("WebView-setup-")?; - let installer_path = tmp_dir.path().join(filename); - - let content = response.bytes().await?; - { - let mut file = std::fs::File::create(&installer_path)?; - io::copy(&mut Cursor::new(content), &mut file)?; - } - - let status = Command::new(&installer_path).args(["/install"]).status()?; - - if !status.success() { - return Err(WebViewError::Installation(format!( - "Installer exited with code `{}`.", - status.code().unwrap_or(-1) - ))); - } - - Ok(()) -} - -#[cfg(windows)] -fn get_filename_from_response(response: &reqwest::Response) -> Option { - response - .headers() - .get("content-disposition") - .and_then(|value| value.to_str().ok()) - .and_then(|value| value.split("filename=").last()) - .map(|name| name.trim().replace('\"', "")) - .or_else(|| { - response - .url() - .path_segments() - .and_then(|segments| segments.last()) - .map(|name| name.to_string()) - }) - .filter(|name| !name.is_empty()) -} - -#[cfg(not(windows))] -async fn install() -> Result<(), WebViewError> { - Err(WebViewError::Installation( - "Unable to auto-install WebView. Please refer to https://v2.tauri.app/references/webview-versions/".to_string(), - )) -} - -pub fn init_webview() { - if is_available() { - return; - } - - if dialog::confirm( - "WebView Error", - "WebView is required for this application to work.\n\n\ - Do you want to install it?", - MessageType::Error, - ) - .not() - { - tracing::warn!("Declined to setup WebView."); - - std::process::exit(1); - } - - if let Err(e) = tauri::async_runtime::block_on(install()) { - dialog::error(&format!( - "Failed to install WebView: {}\n\n\ - Please install it manually from webpage that should open when you click 'Ok'.\n\n\ - If that doesn't work, please visit Microsoft Edge Webview2 download section.", - e - )); - - if let Err(e) = open_install_website() { - tracing::warn!("Failed to launch WebView website:\n{}", e); - } - - std::process::exit(1); - } - - if is_available().not() { - dialog::panic( - "Unable to setup WebView:\n\n\ - Please install it manually and relaunch the application.\n\ - https://developer.microsoft.com/microsoft-edge/webview2/#download-section", - ); - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/tauri.conf.json b/packages/hoppscotch-desktop/src-tauri/tauri.conf.json deleted file mode 100644 index 98208f21..00000000 --- a/packages/hoppscotch-desktop/src-tauri/tauri.conf.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "Hoppscotch", - "version": "26.4.0", - "identifier": "io.hoppscotch.desktop", - "build": { - "beforeDevCommand": "pnpm dev", - "devUrl": "http://127.0.0.1:1420", - "beforeBuildCommand": "pnpm build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "title": "main", - "width": 500, - "height": 700, - "decorations": false, - "alwaysOnTop": true, - "resizable": false - } - ], - "security": { - "csp": { - "default-src": "blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' customprotocol: asset:", - "script-src": "* 'self' 'unsafe-eval' 'wasm-unsafe-eval' 'unsafe-inline'", - "connect-src": "ipc: http://ipc.localhost https://api.hoppscotch.io data: *", - "font-src": "https://fonts.gstatic.com data: 'self' *", - "img-src": "'self' asset: http://asset.localhost blob: data: customprotocol: *", - "style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com data: asset: *", - "worker-src": "* 'self' data: 'unsafe-eval' blob:" - } - } - }, - "bundle": { - "active": true, - "targets": "all", - "createUpdaterArtifacts": true, - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ] - }, - "plugins": { - "deep-link": { - "desktop": { - "schemes": ["io.hoppscotch.desktop"] - } - }, - "updater": { - "active": true, - "endpoints": [ - "https://releases.hoppscotch.com/hoppscotch-selfhost-desktop.json" - ], - "dialog": true, - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDYwOURFNEY4RDRGMDQxNTgKUldSWVFmRFUrT1NkWUc1RDM0Z2ZjTHE2dG52Q3ZlYzg3ZXVpZU9KaENPWTBMd3MwY0hWa1lreDcK" - } - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/tauri.portable.macos.conf.json b/packages/hoppscotch-desktop/src-tauri/tauri.portable.macos.conf.json deleted file mode 100644 index 59a12e20..00000000 --- a/packages/hoppscotch-desktop/src-tauri/tauri.portable.macos.conf.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "Hoppscotch", - "version": "26.4.0", - "identifier": "io.hoppscotch.desktop", - "build": { - "beforeDevCommand": "pnpm dev", - "devUrl": "http://127.0.0.1:1420", - "beforeBuildCommand": "pnpm build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "title": "main", - "width": 500, - "height": 700, - "decorations": false, - "alwaysOnTop": true, - "resizable": false - } - ], - "security": { - "csp": { - "default-src": "blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' customprotocol: asset:", - "script-src": "* 'self' 'unsafe-eval' 'wasm-unsafe-eval' 'unsafe-inline'", - "connect-src": "ipc: http://ipc.localhost https://api.hoppscotch.io data: *", - "font-src": "https://fonts.gstatic.com data: 'self' *", - "img-src": "'self' asset: http://asset.localhost blob: data: customprotocol: *", - "style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com data: asset: *", - "worker-src": "* 'self' data: 'unsafe-eval' blob:" - } - } - }, - "bundle": { - "active": true, - "targets": "all", - "createUpdaterArtifacts": false, - "icon": [ - "icons/32x32.png", - "icons/128x128.png", - "icons/128x128@2x.png", - "icons/icon.icns", - "icons/icon.ico" - ] - }, - "plugins": { - "deep-link": { - "desktop": { - "schemes": ["io.hoppscotch.desktop"] - } - }, - "updater": { - "active": true, - "endpoints": [ - "https://releases.hoppscotch.com/hoppscotch-selfhost-desktop.json" - ], - "dialog": false, - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDYwOURFNEY4RDRGMDQxNTgKUldSWVFmRFUrT1NkWUc1RDM0Z2ZjTHE2dG52Q3ZlYzg3ZXVpZU9KaENPWTBMd3MwY0hWa1lreDcK" - } - } -} diff --git a/packages/hoppscotch-desktop/src-tauri/tauri.portable.windows.conf.json b/packages/hoppscotch-desktop/src-tauri/tauri.portable.windows.conf.json deleted file mode 100644 index c9afe9e9..00000000 --- a/packages/hoppscotch-desktop/src-tauri/tauri.portable.windows.conf.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "$schema": "https://schema.tauri.app/config/2", - "productName": "Hoppscotch", - "version": "26.4.0", - "identifier": "io.hoppscotch.desktop", - "build": { - "beforeDevCommand": "pnpm dev", - "devUrl": "http://127.0.0.1:1420", - "beforeBuildCommand": "pnpm build", - "frontendDist": "../dist" - }, - "app": { - "windows": [ - { - "title": "main", - "width": 500, - "height": 700, - "decorations": false, - "alwaysOnTop": true, - "resizable": false - } - ], - "security": { - "csp": { - "default-src": "blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' customprotocol: asset:", - "script-src": "* 'self' 'unsafe-eval' 'wasm-unsafe-eval' 'unsafe-inline'", - "connect-src": "ipc: http://ipc.localhost https://api.hoppscotch.io data: *", - "font-src": "https://fonts.gstatic.com data: 'self' *", - "img-src": "'self' asset: http://asset.localhost blob: data: customprotocol: *", - "style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com data: asset: *", - "worker-src": "* 'self' data: 'unsafe-eval' blob:" - } - } - }, - "bundle": { - "active": false, - "targets": "all", - "windows": { - "webviewInstallMode": { - "type": "skip" - } - }, - "createUpdaterArtifacts": false - }, - "plugins": { - "deep-link": { - "desktop": { - "schemes": ["io.hoppscotch.desktop"] - } - }, - "updater": { - "active": true, - "endpoints": [ - "https://releases.hoppscotch.com/hoppscotch-selfhost-desktop.json" - ], - "dialog": false, - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDYwOURFNEY4RDRGMDQxNTgKUldSWVFmRFUrT1NkWUc1RDM0Z2ZjTHE2dG52Q3ZlYzg3ZXVpZU9KaENPWTBMd3MwY0hWa1lreDcK" - } - } -} diff --git a/packages/hoppscotch-desktop/src/App.vue b/packages/hoppscotch-desktop/src/App.vue deleted file mode 100644 index 9a0fe289..00000000 --- a/packages/hoppscotch-desktop/src/App.vue +++ /dev/null @@ -1,18 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/assets/scss/styles.scss b/packages/hoppscotch-desktop/src/assets/scss/styles.scss deleted file mode 100644 index 24f5dbbd..00000000 --- a/packages/hoppscotch-desktop/src/assets/scss/styles.scss +++ /dev/null @@ -1,103 +0,0 @@ -@mixin base-theme { - --font-sans: 'Inter Variable', sans-serif; - --font-mono: 'Roboto Mono Variable', monospace; - --font-size-body: 0.75rem; - --font-size-tiny: 0.625rem; - --line-height-body: 1rem; -} - -@mixin dark-theme { - --primary-color: #181818; - --primary-light-color: #1c1c1e; - --primary-dark-color: #262626; - --primary-contrast-color: #171717; - - --secondary-color: #a3a3a3; - --secondary-light-color: #737373; - --secondary-dark-color: #fafafa; - - --divider-color: #262626; - --divider-light-color: #1f1f1f; - --divider-dark-color: #2d2d2d; - - --error-color: #292524; - --tooltip-color: #f5f5f5; - --popover-color: #1b1b1b; -} - -@mixin green-theme { - --accent-color: #10b981; - --accent-light-color: #34d399; - --accent-dark-color: #059669; - --accent-contrast-color: #fff; - --gradient-from-color: #a7f3d0; - --gradient-via-color: #34d399; - --gradient-to-color: #059669; -} - -:root { - @include base-theme; - @include dark-theme; - @include green-theme; -} - -:root.dark { - @include dark-theme; - color-scheme: dark; -} - -:root[data-accent='green'] { - @include green-theme; -} - -* { - backface-visibility: hidden; - -moz-backface-visibility: hidden; - -webkit-backface-visibility: hidden; - - &::before { - backface-visibility: hidden; - -moz-backface-visibility: hidden; - -webkit-backface-visibility: hidden; - } - - &::after { - backface-visibility: hidden; - -moz-backface-visibility: hidden; - -webkit-backface-visibility: hidden; - } - - @apply selection:bg-accentDark; - @apply selection:text-accentContrast; -} - -:root { - accent-color: var(--accent-color); - font-variant-ligatures: common-ligatures; - @apply antialiased; - @apply overscroll-none; -} - -input::placeholder, -textarea::placeholder { - @apply text-secondary; - @apply opacity-50 #{!important}; -} - -input, -textarea { - @apply text-secondaryDark; - @apply font-medium; -} - -body { - @apply bg-primary; - @apply text-body text-secondary; - @apply font-medium; - @apply select-none; - @apply overflow-x-hidden; - @apply leading-body #{!important}; - animation: fade 300ms forwards; - -webkit-tap-highlight-color: transparent; - -webkit-touch-callout: none; -} diff --git a/packages/hoppscotch-desktop/src/assets/scss/tailwind.scss b/packages/hoppscotch-desktop/src/assets/scss/tailwind.scss deleted file mode 100644 index b5c61c95..00000000 --- a/packages/hoppscotch-desktop/src/assets/scss/tailwind.scss +++ /dev/null @@ -1,3 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; diff --git a/packages/hoppscotch-desktop/src/assets/vue.svg b/packages/hoppscotch-desktop/src/assets/vue.svg deleted file mode 100644 index 770e9d33..00000000 --- a/packages/hoppscotch-desktop/src/assets/vue.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/packages/hoppscotch-desktop/src/components.d.ts b/packages/hoppscotch-desktop/src/components.d.ts deleted file mode 100644 index 9a351ff4..00000000 --- a/packages/hoppscotch-desktop/src/components.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable */ -// @ts-nocheck -// biome-ignore lint: disable -// oxlint-disable -// ------ -// Generated by unplugin-vue-components -// Read more: https://github.com/vuejs/core/pull/3399 - -export {} - -/* prettier-ignore */ -declare module 'vue' { - export interface GlobalComponents { - HoppButtonPrimary: typeof import('@hoppscotch/ui')['HoppButtonPrimary'] - HoppButtonSecondary: typeof import('@hoppscotch/ui')['HoppButtonSecondary'] - HoppSmartSpinner: typeof import('@hoppscotch/ui')['HoppSmartSpinner'] - LayoutHeader: typeof import('./components/layout/LayoutHeader.vue')['default'] - LayoutSidebar: typeof import('./components/layout/LayoutSidebar.vue')['default'] - Tippy: typeof import('vue-tippy')['Tippy'] - } -} diff --git a/packages/hoppscotch-desktop/src/components/layout/LayoutHeader.vue b/packages/hoppscotch-desktop/src/components/layout/LayoutHeader.vue deleted file mode 100644 index e7e6fbbf..00000000 --- a/packages/hoppscotch-desktop/src/components/layout/LayoutHeader.vue +++ /dev/null @@ -1,35 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/components/layout/LayoutSidebar.vue b/packages/hoppscotch-desktop/src/components/layout/LayoutSidebar.vue deleted file mode 100644 index 44a26918..00000000 --- a/packages/hoppscotch-desktop/src/components/layout/LayoutSidebar.vue +++ /dev/null @@ -1,65 +0,0 @@ - - - - - diff --git a/packages/hoppscotch-desktop/src/composables/useAppInitialization.ts b/packages/hoppscotch-desktop/src/composables/useAppInitialization.ts deleted file mode 100644 index addfa159..00000000 --- a/packages/hoppscotch-desktop/src/composables/useAppInitialization.ts +++ /dev/null @@ -1,409 +0,0 @@ -import { ref } from "vue" -import * as E from "fp-ts/Either" -import { load, download, close } from "@hoppscotch/plugin-appload" -import { getVersion } from "@tauri-apps/api/app" -import { invoke } from "@tauri-apps/api/core" - -import { DesktopPersistenceService } from "~/services/persistence.service" -import { InstanceStoreMigrationService } from "~/services/instance-store-migration.service" -import type { - Instance, - ConnectionState, -} from "@hoppscotch/common/platform/instance" -import { VENDORED_INSTANCE_CONFIG } from "@hoppscotch/common/platform/instance" - -// simple diag logger for the main window (runs before kernel log module is available) -function mainDiag(msg: string) { - const line = `[${new Date().toISOString()}] [MAIN] ${msg}\n` - if ((window as any).__TAURI_INTERNALS__) { - ;(window as any).__TAURI_INTERNALS__ - .invoke("append_log", { - filename: "io.hoppscotch.desktop.diag.log", - content: line, - }) - .catch(() => {}) - } -} - -export enum AppState { - LOADING = "loading", - UPDATE_AVAILABLE = "update_available", - UPDATE_IN_PROGRESS = "update_in_progress", - UPDATE_READY = "update_ready", - ERROR = "error", - LOADED = "loaded", -} - -export function useAppInitialization() { - const persistence = DesktopPersistenceService.getInstance() - const migration = InstanceStoreMigrationService.getInstance() - - const appState = ref(AppState.LOADING) - const error = ref("") - const statusMessage = ref("Initializing...") - const appVersion = ref("...") - - const saveConnectionState = async (state: ConnectionState) => { - try { - await persistence.connectionState.set(state) - } catch (err) { - console.error("Failed to save connection state:", err) - } - } - - const findMostRecentInstance = ( - instances: Instance[], - targetUrl: string - ): Instance | null => { - return ( - instances.find( - (instance) => - instance.serverUrl === targetUrl || - instance.serverUrl.includes(targetUrl) || - targetUrl.includes(instance.serverUrl) - ) || null - ) - } - - const loadVendoredInstance = async () => { - try { - statusMessage.value = "Loading Hoppscotch Desktop..." - - await saveConnectionState({ - status: "connected", - instance: VENDORED_INSTANCE_CONFIG, - }) - - mainDiag("loadVendoredInstance: calling load(bundleName=Hoppscotch)") - console.log("Loading vendored app...") - - const loadResp = await load({ - bundleName: VENDORED_INSTANCE_CONFIG.bundleName!, - window: { title: "Hoppscotch" }, - }) - - mainDiag( - `loadVendoredInstance: load result success=${loadResp.success}, label=${loadResp.windowLabel}` - ) - if (!loadResp.success) { - throw new Error("Failed to load Hoppscotch Vendored") - } - - console.log("Vendored app loaded successfully") - mainDiag("loadVendoredInstance: closing main window") - close({ windowLabel: "main" }) - } catch (err) { - const errorMessage = err instanceof Error ? err.message : String(err) - console.error("Error loading vendored app:", errorMessage) - error.value = errorMessage - - await saveConnectionState({ - status: "error", - target: "Vendored", - message: errorMessage, - }) - - appState.value = AppState.ERROR - } - } - - const loadVendoredIfMatches = async (instance: Instance) => { - mainDiag( - `loadVendoredIfMatches: kind=${instance.kind}, displayName=${instance.displayName}, bundleName=${instance.bundleName}` - ) - - // cloud-org instances share the same bundleName as vendored ("Hoppscotch") - // because they use the same app bundle, just loaded with a different org - // context via the host parameter. we must check kind, not bundleName, to - // distinguish them. without this, restarting the app after connecting to an - // org would incorrectly load vendored (no host param = no org context). - // "cloud" (default cloud, e.g. hoppscotch.io) also uses the vendored bundle - // and doesn't need a download step. - if (instance.kind === "vendored" || instance.kind === "cloud") { - mainDiag( - "loadVendoredIfMatches: matched vendored, calling loadVendoredInstance" - ) - await loadVendoredInstance() - } else if (instance.kind === "cloud-org") { - // cloud-org: uses the vendored bundle but needs the host parameter so the - // webview gets the org context (?org= query param). skip the download - // step since cloud-org shares the vendored bundle which is already - // available locally. - try { - statusMessage.value = `Loading ${instance.displayName}...` - - await saveConnectionState({ - status: "connecting", - target: instance.serverUrl, - }) - - mainDiag( - `loadVendoredIfMatches: loading cloud-org instance, bundle=${instance.bundleName}, host=${instance.serverUrl}` - ) - const loadResp = await load({ - bundleName: instance.bundleName!, - host: instance.serverUrl, - window: { title: "Hoppscotch" }, - }) - - mainDiag( - `loadVendoredIfMatches: load result success=${loadResp.success}, label=${loadResp.windowLabel}` - ) - if (!loadResp.success) { - throw new Error(`Failed to load ${instance.displayName}`) - } - - await saveConnectionState({ - status: "connected", - instance: instance, - }) - - console.log(`Successfully loaded instance: ${instance.displayName}`) - mainDiag("loadVendoredIfMatches: closing main window") - close({ windowLabel: "main" }) - } catch (err) { - const errorMessage = err instanceof Error ? err.message : String(err) - console.error( - `Failed to load cloud-org instance ${instance.displayName}:`, - errorMessage - ) - - await saveConnectionState({ - status: "error", - target: instance.serverUrl, - message: errorMessage, - }) - - mainDiag( - `loadVendoredIfMatches: FAILED to load cloud-org ${instance.displayName}, falling back to vendored. error=${errorMessage}` - ) - console.log("Falling back to vendored instance") - await loadVendoredInstance() - } - } else { - // self-hosted or other non-vendored instances: need to download the - // bundle from the server before loading - try { - statusMessage.value = `Loading ${instance.displayName}...` - - await saveConnectionState({ - status: "connecting", - target: instance.serverUrl, - }) - - await download({ serverUrl: instance.serverUrl }) - - mainDiag( - `loadVendoredIfMatches: loading non-vendored instance, bundle=${instance.bundleName}` - ) - const loadResp = await load({ - bundleName: instance.bundleName!, - window: { title: "Hoppscotch" }, - }) - - mainDiag( - `loadVendoredIfMatches: load result success=${loadResp.success}, label=${loadResp.windowLabel}` - ) - if (!loadResp.success) { - throw new Error(`Failed to load ${instance.displayName}`) - } - - await saveConnectionState({ - status: "connected", - instance: instance, - }) - - console.log(`Successfully loaded instance: ${instance.displayName}`) - mainDiag("loadVendoredIfMatches: closing main window") - close({ windowLabel: "main" }) - } catch (err) { - const errorMessage = err instanceof Error ? err.message : String(err) - console.error( - `Failed to load instance ${instance.displayName}:`, - errorMessage - ) - - await saveConnectionState({ - status: "error", - target: instance.serverUrl, - message: errorMessage, - }) - - mainDiag( - `loadVendoredIfMatches: FAILED to load ${instance.displayName}, falling back to vendored. error=${errorMessage}` - ) - console.log("Falling back to vendored instance") - await loadVendoredInstance() - } - } - } - - const loadRecent = async () => { - try { - statusMessage.value = "Loading application..." - - // Both the main window and the vendored webview's InstanceService - // share hoppscotch-unified.store for connection state and recent - // instances. The InstanceService's detectCurrentInstanceFromHostname - // persists the detected instance (including cloud-org) to this store, - // so on restart the main window can resume the correct instance. - const connectionState = await persistence.connectionState.get() - const recentInstances = await persistence.recentInstances.get() - - mainDiag(`loadRecent: connectionState=${JSON.stringify(connectionState)}`) - mainDiag( - `loadRecent: connectionState.status=${connectionState?.status ?? "(null)"}, instance.kind=${connectionState?.status === "connected" ? connectionState.instance?.kind : "(n/a)"}, instance.displayName=${connectionState?.status === "connected" ? connectionState.instance?.displayName : "(n/a)"}, recentInstances.length=${recentInstances.length}` - ) - mainDiag(`loadRecent: recentInstances=${JSON.stringify(recentInstances)}`) - console.log("Current connection state:", connectionState) - console.log("Recent instances:", recentInstances) - - if (connectionState) { - switch (connectionState.status) { - case "connected": - if (connectionState.instance) { - mainDiag( - `loadRecent: resuming connected instance: kind=${connectionState.instance.kind}, displayName=${connectionState.instance.displayName}` - ) - statusMessage.value = `Connecting to ${connectionState.instance.displayName}...` - try { - await loadVendoredIfMatches(connectionState.instance) - return - } catch (err) { - console.warn( - "Failed to load previously connected instance:", - err - ) - } - } - break - - case "connecting": - if (connectionState.target) { - statusMessage.value = `Resuming connection to ${connectionState.target}...` - const targetInstance = findMostRecentInstance( - recentInstances, - connectionState.target - ) - if (targetInstance) { - try { - await loadVendoredIfMatches(targetInstance) - return - } catch (err) { - console.warn("Failed to resume connection:", err) - } - } - } - break - - case "error": - console.warn("Previous connection failed:", connectionState.message) - break - - case "idle": - default: - break - } - } - - const mostRecentInstance = recentInstances[0] - - if (mostRecentInstance) { - statusMessage.value = `Connecting to ${mostRecentInstance.displayName}...` - try { - await loadVendoredIfMatches(mostRecentInstance) - return - } catch (err) { - console.warn("Failed to load most recent instance:", err) - } - } - - console.log("No recent instances found, loading vendored as fallback") - await loadVendoredInstance() - } catch (err) { - const errorMessage = err instanceof Error ? err.message : String(err) - console.error("Error in loadRecent:", errorMessage) - error.value = errorMessage - appState.value = AppState.ERROR - } - } - - const performBasicInitialization = async () => { - try { - appVersion.value = await getVersion() - } catch (error) { - console.error("Failed to get app version:", error) - appVersion.value = "unknown" - } - - statusMessage.value = "Checking for version changes..." - try { - await invoke("check_and_backup_on_version_change") - console.log("Version backup check completed") - } catch (err) { - console.warn("Version backup check failed:", err) - } - - statusMessage.value = "Running data migration..." - await migration.initialize() - - const migrationStatus = migration.getMigrationStatus() - if (migrationStatus.value.status === "failed") { - throw new Error( - `Migration failed: ${migration.getMigrationError().value}` - ) - } - - statusMessage.value = "Initializing stores..." - // `init` returns `Either` so callers can decide - // how to surface a failure. Branching to a thrown Error here lets - // the surrounding `initialize()` try/catch route the failure into - // `error.value` for the UI, the same way every other startup - // failure is reported, instead of letting init silently complete - // and leave the app running on defaults with no Rust sync. - const initResult = await persistence.init() - if (E.isLeft(initResult)) { - throw new Error( - `Persistence init failed: ${initResult.left.kind}: ${initResult.left.message}` - ) - } - } - - const initialize = async (customLogic?: () => Promise) => { - appState.value = AppState.LOADING - error.value = "" - - try { - await performBasicInitialization() - - if (customLogic) { - await customLogic() - } else { - await loadRecent() - } - } catch (err) { - const errorMessage = err instanceof Error ? err.message : String(err) - console.error("Initialization error:", errorMessage) - error.value = errorMessage - appState.value = AppState.ERROR - } - } - - return { - appState, - error, - statusMessage, - appVersion, - - persistence, - migration, - - saveConnectionState, - findMostRecentInstance, - loadVendoredInstance, - loadVendoredIfMatches, - loadRecent, - performBasicInitialization, - initialize, - } -} diff --git a/packages/hoppscotch-desktop/src/kernel/index.ts b/packages/hoppscotch-desktop/src/kernel/index.ts deleted file mode 100644 index 5d75abbc..00000000 --- a/packages/hoppscotch-desktop/src/kernel/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { KernelAPI } from "@hoppscotch/kernel" - -export { Io } from "./io" -export { Relay } from "./relay" -export { Store } from "./store" - -export const getModule = ( - name: K -): NonNullable => { - const kernel = window.__KERNEL__ - if (!kernel?.[name]) throw new Error(`Kernel ${String(name)} not initialized`) - return kernel[name] -} diff --git a/packages/hoppscotch-desktop/src/kernel/io.ts b/packages/hoppscotch-desktop/src/kernel/io.ts deleted file mode 100644 index bf55cf8d..00000000 --- a/packages/hoppscotch-desktop/src/kernel/io.ts +++ /dev/null @@ -1,34 +0,0 @@ -import type { - SaveFileWithDialogOptions, - OpenExternalLinkOptions, - SaveFileResponse, - OpenExternalLinkResponse, - EventCallback, - UnlistenFn, -} from "@hoppscotch/kernel" -import { getModule } from "." - -export const Io = (() => { - const module = () => getModule("io") - - return { - saveFileWithDialog: ( - opts: SaveFileWithDialogOptions - ): Promise => module().saveFileWithDialog(opts), - - openExternalLink: ( - opts: OpenExternalLinkOptions - ): Promise => module().openExternalLink(opts), - - listen: ( - event: string, - handler: EventCallback - ): Promise => module().listen(event, handler), - - once: (event: string, handler: EventCallback): Promise => - module().once(event, handler), - - emit: (event: string, payload?: unknown): Promise => - module().emit(event, payload), - } as const -})() diff --git a/packages/hoppscotch-desktop/src/kernel/relay.ts b/packages/hoppscotch-desktop/src/kernel/relay.ts deleted file mode 100644 index 46a8d4ea..00000000 --- a/packages/hoppscotch-desktop/src/kernel/relay.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { - RelayRequest, - RelayRequestEvents, - RelayError, - RelayResponse, - RelayEventEmitter, -} from "@hoppscotch/kernel" -import * as E from "fp-ts/Either" -import { getModule } from "." - -export const Relay = (() => { - const module = () => getModule("relay") - - return { - capabilities: () => module().capabilities, - canHandle: (request: RelayRequest): E.Either => - module().canHandle(request), - execute: ( - request: RelayRequest - ): { - cancel: () => Promise - emitter: RelayEventEmitter - response: Promise> - } => module().execute(request), - } as const -})() diff --git a/packages/hoppscotch-desktop/src/kernel/store-resource.ts b/packages/hoppscotch-desktop/src/kernel/store-resource.ts deleted file mode 100644 index 4bbcec3a..00000000 --- a/packages/hoppscotch-desktop/src/kernel/store-resource.ts +++ /dev/null @@ -1,120 +0,0 @@ -import * as E from "fp-ts/Either" -import type { z } from "zod" - -import { Log } from "@hoppscotch/common/kernel/log" - -import { Store } from "~/kernel/store" - -const LOG_TAG = "store-resource" - -/** - * A single schema-validated, namespaced, persistent value in the shared - * store. - * - * The persistence service holds several of these (desktop settings, - * update state, connection state, recent instances) which previously - * existed as bespoke `get*` / `set*` / `watch*` method pairs on the - * service class. Each pair was ~20 lines of near-identical plumbing - * that wrapped `Store.get` with a parse and a default fallback, - * wrapped `Store.set` with validation and a throw on failure, and - * wrapped `Store.watch` with an undefined filter and a parse on every - * incoming value. Extracting the pattern to a factory cuts the - * service down to a thin declarative layer where each resource is - * four lines. - * - * A resource is an ordinary value that can be passed around and composed. - * Compound operations (for example "add an instance to the recent list" - * which reads, transforms, and writes) become free functions over a - * resource rather than methods on a god class, which separates the data - * access concern (this factory) from the business rules (the free - * functions). - */ -export interface StoreResource { - /** - * Reads the current value from the store. Falls back to `defaults()` on - * any read error, missing key, or schema validation failure, so callers - * always receive a valid `T`. - */ - get(): Promise - - /** - * Writes a new value after validating through the schema. Throws on - * validation failure or store write failure. Callers that want silent - * best-effort semantics should wrap the call themselves. - */ - set(value: T): Promise - - /** - * Subscribes to external writes. The handler receives the parsed value - * whenever any writer (this process or another) updates the key. - * Resolves to an unsubscribe function. - */ - watch(handler: (value: T) => void): Promise<() => void> -} - -// Input type is deliberately `any` so this works with schemas whose parse -// input differs from output, most commonly `z.object` schemas that carry -// `.default()` on each field (input has optional fields, output has them -// required). Constraining input to `T` would reject every such schema. -export function createStoreResource( - namespace: string, - key: string, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - schema: z.ZodType, - defaults: () => T -): StoreResource { - return { - async get(): Promise { - const result = await Store.get(namespace, key) - if (E.isLeft(result) || result.right === undefined) { - return defaults() - } - const parsed = schema.safeParse(result.right) - if (!parsed.success) { - Log.warn( - LOG_TAG, - `${namespace}/${key} failed schema validation, falling back to defaults`, - parsed.error - ) - return defaults() - } - return parsed.data - }, - - async set(value: T): Promise { - const validated = schema.parse(value) - const result = await Store.set(namespace, key, validated) - if (E.isLeft(result)) { - // `StoreError` is a tagged union with `kind` and `message`. - // Interpolating the object directly stringifies to - // `[object Object]`, which is useless in logs and throws, so - // format it explicitly here. - const err = result.left - throw new Error( - `Failed to persist ${namespace}/${key}: ${err.kind}: ${err.message}` - ) - } - }, - - async watch(handler: (value: T) => void): Promise<() => void> { - const emitter = await Store.watch(namespace, key) - return emitter.on("change", ({ value }: { value?: unknown }) => { - if (value === undefined) return - const parsed = schema.safeParse(value) - if (parsed.success) { - handler(parsed.data) - return - } - // Mirrors the parse-failure log in `get()`. Without this, an - // external writer with a schema mismatch (for example a shell - // and webview temporarily out of sync after a migration) would - // stop delivering updates with no observable signal. - Log.warn( - LOG_TAG, - `${namespace}/${key} watch received invalid value, skipping`, - parsed.error - ) - }) - }, - } -} diff --git a/packages/hoppscotch-desktop/src/kernel/store.ts b/packages/hoppscotch-desktop/src/kernel/store.ts deleted file mode 100644 index 72168b12..00000000 --- a/packages/hoppscotch-desktop/src/kernel/store.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { - StorageOptions, - StoreError, - StoreEvents, - StoreEventEmitter, -} from "@hoppscotch/kernel" -import * as E from "fp-ts/Either" -import { getModule } from "." -import { invoke } from "@tauri-apps/api/core" -import { join } from "@tauri-apps/api/path" - -const STORE_PATH = "hoppscotch-unified.store" - -export const getConfigDir = async (): Promise => { - return invoke("get_config_dir") -} - -export const getBackupDir = async (): Promise => { - return invoke("get_backup_dir") -} - -export const getLatestDir = async (): Promise => { - return invoke("get_latest_dir") -} - -export const getStoreDir = async (): Promise => { - return invoke("get_store_dir") -} - -export const getInstanceDir = async (): Promise => { - return invoke("get_instance_dir") -} - -const getStorePath = async (): Promise => { - try { - const storeDir = await getStoreDir() - return join(storeDir, STORE_PATH) - } catch (error) { - console.error("Failed to get store directory:", error) - return "hoppscotch-unified.store" - } -} - -export const Store = (() => { - const module = () => getModule("store") - - return { - capabilities: () => module().capabilities, - - init: async () => { - const storePath = await getStorePath() - return module().init(storePath) - }, - - set: async ( - namespace: string, - key: string, - value: unknown, - options?: StorageOptions - ): Promise> => { - const storePath = await getStorePath() - return module().set(storePath, namespace, key, value, options) - }, - - get: async ( - namespace: string, - key: string - ): Promise> => { - const storePath = await getStorePath() - return module().get(storePath, namespace, key) - }, - - remove: async ( - namespace: string, - key: string - ): Promise> => { - const storePath = await getStorePath() - return module().remove(storePath, namespace, key) - }, - - clear: async (namespace?: string): Promise> => { - const storePath = await getStorePath() - return module().clear(storePath, namespace) - }, - - has: async ( - namespace: string, - key: string - ): Promise> => { - const storePath = await getStorePath() - return module().has(storePath, namespace, key) - }, - - listNamespaces: async (): Promise> => { - const storePath = await getStorePath() - return module().listNamespaces(storePath) - }, - - listKeys: async ( - namespace: string - ): Promise> => { - const storePath = await getStorePath() - return module().listKeys(storePath, namespace) - }, - - watch: async ( - namespace: string, - key: string - ): Promise> => { - const storePath = await getStorePath() - return module().watch(storePath, namespace, key) - }, - } as const -})() diff --git a/packages/hoppscotch-desktop/src/main.ts b/packages/hoppscotch-desktop/src/main.ts deleted file mode 100644 index 01fa7ea0..00000000 --- a/packages/hoppscotch-desktop/src/main.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { createApp } from "vue" -import App from "./App.vue" -import router from "./router" - -import "@hoppscotch/ui/style.css" -import "./assets/scss/styles.scss" -import "./assets/scss/tailwind.scss" -import "@fontsource-variable/inter" -import "@fontsource-variable/material-symbols-rounded" -import "@fontsource-variable/roboto-mono" - -import { initKernel } from "@hoppscotch/kernel" - -const app = createApp(App) -app.use(router) -app.mount("#app") - -initKernel("desktop") diff --git a/packages/hoppscotch-desktop/src/router.ts b/packages/hoppscotch-desktop/src/router.ts deleted file mode 100644 index 6b603f0a..00000000 --- a/packages/hoppscotch-desktop/src/router.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { createRouter, createWebHistory } from "vue-router" -import { invoke } from "@tauri-apps/api/core" - -const router = createRouter({ - history: createWebHistory(), - routes: [ - { - path: "/", - name: "home", - component: async () => { - try { - const isPortable = await invoke("is_portable_mode") - // Dynamic import because otherwise `updater` - // tends to experience weird race conditions, - // not sure how or why - return isPortable - ? import("./views/PortableHome.vue") - : import("./views/StandardHome.vue") - } catch (error) { - console.error( - "Failed to detect portable mode, defaulting to standard:", - error - ) - - return import("./views/StandardHome.vue") - } - }, - }, - ], -}) - -export default router diff --git a/packages/hoppscotch-desktop/src/services/instance-store-migration.service.ts b/packages/hoppscotch-desktop/src/services/instance-store-migration.service.ts deleted file mode 100644 index ec39bb88..00000000 --- a/packages/hoppscotch-desktop/src/services/instance-store-migration.service.ts +++ /dev/null @@ -1,431 +0,0 @@ -import { BehaviorSubject, Observable } from "rxjs" -import { computed } from "vue" -import { LazyStore } from "@tauri-apps/plugin-store" -import { - getInstanceDir, - getConfigDir, - getStoreDir, - getLatestDir, - Store, -} from "~/kernel/store" -import * as E from "fp-ts/Either" -import { join } from "@tauri-apps/api/path" -import { exists, copyFile, remove, readDir, mkdir } from "@tauri-apps/plugin-fs" - -const STORE_NAMESPACE = "hoppscotch-desktop.v1" -const MIGRATION_NAMESPACE = "migration.v1" -const CURRENT_STORE_VERSION = 1 - -type LegacyServerInstance = { - type: "server" - serverUrl: string - displayName: string - version: string - lastUsed: string - bundleName?: string -} - -type LegacyCloudInstance = { - type: "cloud" - displayName: string - version: string -} - -type LegacyInstanceKind = LegacyServerInstance | LegacyCloudInstance - -type LegacyConnectionState = - | { status: "idle" } - | { status: "connecting"; target: string } - | { status: "connected"; instance: LegacyInstanceKind } - | { status: "error"; target: string; message: string } - -type LegacyUpdateState = { - status: string - version?: string - message?: string - progress?: { - downloaded: number - total?: number - } -} - -export type InstanceKind = "on-prem" | "cloud" | "cloud-org" | "vendored" - -export type Instance = { - kind: InstanceKind - serverUrl: string - displayName: string - version: string - lastUsed: string - bundleName?: string -} - -export type ConnectionState = - | { status: "idle" } - | { status: "connecting"; target: string } - | { status: "connected"; instance: Instance } - | { status: "error"; target: string; message: string } - -export type MigrationStatus = - | { status: "pending" } - | { status: "in-progress" } - | { status: "completed" } - | { status: "failed"; error: string } - -export class InstanceStoreMigrationService { - private static instance: InstanceStoreMigrationService - private status$ = new BehaviorSubject({ status: "pending" }) - private migrationLock = false - - private constructor() {} - - public static getInstance(): InstanceStoreMigrationService { - if (!InstanceStoreMigrationService.instance) { - InstanceStoreMigrationService.instance = - new InstanceStoreMigrationService() - } - return InstanceStoreMigrationService.instance - } - - async initialize(): Promise { - if (this.migrationLock) { - console.log("Migration already in progress, skipping...") - return - } - - this.migrationLock = true - - try { - const initResult = await Store.init() - if (E.isLeft(initResult)) { - console.error(`Failed to initialize kernel store: ${initResult.left}`) - // Don't fail the migration, just log and continue, - // since there's a chance no services have started just yet, - // better to continue and fail with legitimate critical reasons, - // rather than failing here and not being able to see the actual cause. - } - - const isMigrated = await this.isMigrationComplete() - if (isMigrated) { - console.log("Migration already completed") - this.status$.next({ status: "completed" }) - return - } - - await this.performMigration() - } catch (error) { - console.error("Migration error:", error) - // Even if migration fails, mark as completed to prevent retry loops, - // so there won't be partial state from the "source". - // There's always a way to restart migration is the source is safe. - await this.markMigrationComplete() - this.status$.next({ status: "completed" }) - } finally { - this.migrationLock = false - } - } - - private async isMigrationComplete(): Promise { - try { - const versionResult = await Store.get( - MIGRATION_NAMESPACE, - "migrationVersion" - ) - const currentVersion = E.isRight(versionResult) - ? versionResult.right || 0 - : 0 - return currentVersion >= CURRENT_STORE_VERSION - } catch { - return false - } - } - - private async markMigrationComplete(): Promise { - try { - await Store.set( - MIGRATION_NAMESPACE, - "migrationVersion", - CURRENT_STORE_VERSION - ) - } catch (error) { - console.error("Failed to mark migration as complete:", error) - } - } - - private async performMigration(): Promise { - this.status$.next({ status: "in-progress" }) - - try { - // Ensure directory structure exists - // (shouldn't fail, but good to check just in case) - await this.ensureDirectoryStructure() - - // Migrate data from old stores. - // NOTE: This can fail if the store is using default path, - // and not the full specificed path. - // Remember to check that first. - await this.migrateDataSafely() - - // Move .hoppscotch.store files - // (shouldn't fail, but good to check just in case) - await this.migrateHoppscotchStoreFiles() - - // Mark migration as complete before cleanup - // (shouldn't fail, but good to check just in case) - await this.markMigrationComplete() - - // Clean up old files - // (best effort, don't fail if this fails) - await this.cleanupOldFilesSafely() - - this.status$.next({ status: "completed" }) - console.log("Migration completed successfully") - } catch (error) { - console.error("Migration failed:", error) - // Mark as completed anyway to prevent retry loops - // (same reasoning as in init) - await this.markMigrationComplete() - this.status$.next({ status: "completed" }) - } - } - - private async ensureDirectoryStructure(): Promise { - try { - const latestDir = await getLatestDir() - const storeDir = await getStoreDir() - const instanceDir = await getInstanceDir() - - // Create directories if they don't exist - for (const dir of [latestDir, storeDir, instanceDir]) { - try { - const dirExists = await exists(dir) - if (!dirExists) { - await mkdir(dir, { recursive: true }) - console.log(`Created directory: ${dir}`) - } - } catch (error) { - // Directory might already exist or parent might not exist - console.log(`Directory ${dir} might already exist:`, error) - } - } - } catch (error) { - console.error("Failed to ensure directory structure:", error) - // Continue anyway, directories might already exist - } - } - - private async migrateDataSafely(): Promise { - const configDir = await getConfigDir() - - const hoppStorePath = await join(configDir, "hopp.store.json") - const desktopStorePath = await join(configDir, "hoppscotch-desktop.store") - - let connectionState: ConnectionState = { status: "idle" } - let recentInstances: Instance[] = [] - let updateState: any = null - - // Read from hopp.store.json if it exists - try { - if (await exists(hoppStorePath)) { - const hoppStore = new LazyStore(hoppStorePath) - await hoppStore.init() - - const hoppState = - await hoppStore.get("connectionState") - if (hoppState && hoppState.status === "connected") { - connectionState = { - status: "connected", - instance: this.convertInstanceToNewFormat(hoppState.instance), - } - } - - const legacyInstances = - await hoppStore.get("recentInstances") - if (legacyInstances) { - recentInstances = legacyInstances.map((inst) => - this.convertInstanceToNewFormat(inst) - ) - } - } - } catch (error) { - console.log("Could not read hopp.store.json:", error) - } - - // Read from hoppscotch-desktop.store if it exists - try { - if (await exists(desktopStorePath)) { - const desktopStore = new LazyStore(desktopStorePath) - await desktopStore.init() - - // Only override connection state if we didn't get one from hopp.store - if (connectionState.status === "idle") { - const desktopState = - await desktopStore.get("connectionState") - if (desktopState && desktopState.status === "connected") { - connectionState = { - status: "connected", - instance: this.convertInstanceToNewFormat(desktopState.instance), - } - } - } - - updateState = await desktopStore.get("updateState") - } - } catch (error) { - console.log("Could not read hoppscotch-desktop.store:", error) - } - - try { - await Store.set(STORE_NAMESPACE, "connectionState", connectionState) - console.log("Migrated connection state") - } catch (error) { - console.error("Failed to save connection state:", error) - } - - try { - await Store.set(STORE_NAMESPACE, "recentInstances", recentInstances) - console.log(`Migrated ${recentInstances.length} recent instances`) - } catch (error) { - console.error("Failed to save recent instances:", error) - } - - if (updateState) { - try { - await Store.set(STORE_NAMESPACE, "updateState", updateState) - console.log("Migrated update state") - } catch (error) { - console.error("Failed to save update state:", error) - } - } - } - - private async migrateHoppscotchStoreFiles(): Promise { - try { - const configDir = await getConfigDir() - const storeDir = await getStoreDir() - - const entries = await readDir(configDir) - const storeFiles = entries - .filter( - (entry: any) => - !entry.isDirectory && entry.name.endsWith(".hoppscotch.store") - ) - .map((entry: any) => entry.name) - - for (const fileName of storeFiles) { - try { - const sourcePath = await join(configDir, fileName) - const targetPath = await join(storeDir, fileName) - - // Check if source still exists and target doesn't - const sourceExists = await exists(sourcePath) - const targetExists = await exists(targetPath) - - if (sourceExists && !targetExists) { - await copyFile(sourcePath, targetPath) - console.log(`Migrated ${fileName} to store directory`) - } else if (sourceExists && targetExists) { - console.log(`${fileName} already exists in target, skipping`) - } - } catch (error) { - console.error(`Failed to migrate ${fileName}:`, error) - // Continue with other files - } - } - } catch (error) { - console.error("Failed to migrate .hoppscotch.store files:", error) - // Non-critical, continue - } - } - - private async cleanupOldFilesSafely(): Promise { - const configDir = await getConfigDir() - - // List of files to potentially remove - const filesToClean = ["hopp.store.json", "hoppscotch-desktop.store"] - - for (const fileName of filesToClean) { - try { - const filePath = await join(configDir, fileName) - if (await exists(filePath)) { - await remove(filePath) - console.log(`Cleaned up old file: ${fileName}`) - } - } catch (error) { - console.log(`Could not remove ${fileName}:`, error) - // Non-critical, continue - } - } - - // Also clean up .hoppscotch.store files that were successfully migrated - try { - const storeDir = await getStoreDir() - const entries = await readDir(configDir) - const storeFiles = entries - .filter( - (entry: any) => - !entry.isDirectory && entry.name.endsWith(".hoppscotch.store") - ) - .map((entry: any) => entry.name) - - for (const fileName of storeFiles) { - try { - const sourcePath = await join(configDir, fileName) - const targetPath = await join(storeDir, fileName) - - // Only remove if successfully copied to target - if ((await exists(targetPath)) && (await exists(sourcePath))) { - await remove(sourcePath) - console.log(`Cleaned up migrated file: ${fileName}`) - } - } catch (error) { - console.log(`Could not remove ${fileName}:`, error) - } - } - } catch (error) { - console.log("Could not clean up .hoppscotch.store files:", error) - } - } - - private convertInstanceToNewFormat( - legacyInstance: LegacyInstanceKind - ): Instance { - if (legacyInstance.type === "cloud") { - return { - kind: "cloud", - serverUrl: "hoppscotch.io", - displayName: legacyInstance.displayName, - version: legacyInstance.version, - lastUsed: new Date().toISOString(), - } - } else { - return { - kind: "on-prem", - serverUrl: legacyInstance.serverUrl, - displayName: legacyInstance.displayName, - version: legacyInstance.version, - lastUsed: legacyInstance.lastUsed, - bundleName: legacyInstance.bundleName, - } - } - } - - public getMigrationStatusStream(): Observable { - return this.status$ - } - - public getMigrationStatus() { - return computed(() => this.status$.value) - } - - public isMigrationCompleted() { - return computed(() => this.status$.value.status === "completed") - } - - public getMigrationError() { - return computed(() => { - const status = this.status$.value - return status.status === "failed" ? status.error : null - }) - } -} diff --git a/packages/hoppscotch-desktop/src/services/persistence.service.ts b/packages/hoppscotch-desktop/src/services/persistence.service.ts deleted file mode 100644 index adbf4c25..00000000 --- a/packages/hoppscotch-desktop/src/services/persistence.service.ts +++ /dev/null @@ -1,406 +0,0 @@ -import * as E from "fp-ts/Either" -import { invoke } from "@tauri-apps/api/core" -import { z } from "zod" -import { StoreError } from "@hoppscotch/kernel" - -import { - DESKTOP_SETTINGS_SCHEMA, - DESKTOP_SETTINGS_STORE_KEY, - DESKTOP_SETTINGS_STORE_NAMESPACE, - type DesktopSettings, -} from "@hoppscotch/common/platform/desktop-settings" -import { - UPDATE_STATE_SCHEMA, - UPDATE_STATE_STORE_KEY, -} from "@hoppscotch/common/platform/update-state" -import type { Instance } from "@hoppscotch/common/platform/instance" -import { Log } from "@hoppscotch/common/kernel/log" - -import { Store } from "~/kernel/store" -import { - createStoreResource, - type StoreResource, -} from "~/kernel/store-resource" -import type { UpdateState } from "~/types" - -const LOG_TAG = "persistence" - -// Shared namespace for every desktop-local store resource. Individual keys -// live in `STORE_KEYS` below. Exported for the small handful of callers -// that still touch the store directly. -export const STORE_NAMESPACE = DESKTOP_SETTINGS_STORE_NAMESPACE - -export const STORE_KEYS = { - UPDATE_STATE: UPDATE_STATE_STORE_KEY, - CONNECTION_STATE: "connectionState", - RECENT_INSTANCES: "recentInstances", - SCHEMA_VERSION: "schema_version", - // Legacy key. Written by portable builds in schema v1. Read only by the - // v1 to v2 migration. All other code uses `DESKTOP_SETTINGS`. - PORTABLE_SETTINGS: "portableSettings", - DESKTOP_SETTINGS: DESKTOP_SETTINGS_STORE_KEY, -} as const - -// Runtime validator for `Instance` values read from the store. The type -// annotation pins the Zod output to the canonical `Instance` in common, -// so any drift between the definition stored here and the definition -// consumed by the webview's instance service would fail typecheck -// rather than silently producing a mismatched runtime value. -export const INSTANCE_SCHEMA: z.ZodType = z.object({ - kind: z.enum(["on-prem", "cloud", "cloud-org", "vendored"]), - serverUrl: z.string(), - displayName: z.string(), - version: z.string(), - lastUsed: z.string(), - bundleName: z.string().optional(), -}) - -// Runtime definition of the persisted connection state. NOTE: the -// canonical `ConnectionState` type in -// `@hoppscotch/common/platform/instance.ts` is a discriminated union, -// while the persisted form here is flat with optional fields per -// variant. The two are semi-compatible (the union serializes cleanly -// into this flat form), but the reader loses type narrowing. A later -// migration can switch the persisted form to a discriminated union so -// common's type becomes the single source of truth end-to-end. -export const PERSISTED_CONNECTION_STATE_SCHEMA = z.object({ - status: z.enum(["idle", "connecting", "connected", "error"]), - instance: INSTANCE_SCHEMA.optional(), - target: z.string().optional(), - message: z.string().optional(), -}) - -export type PersistedConnectionState = z.infer< - typeof PERSISTED_CONNECTION_STATE_SCHEMA -> - -// Re-exported for callers that import from this service. The canonical type -// lives in `@hoppscotch/common/platform/desktop-settings`. -export type { DesktopSettings } - -// Legacy `PortableSettings` interface. Kept as a local type (not -// exported, not re-exported from `~/types`) because the v2 migration -// is the only reader and no new code should produce this form. Once -// the migration is retired this type can be dropped entirely. -interface LegacyPortableSettings { - disableUpdateNotifications: boolean - autoSkipWelcome: boolean -} - -interface Migration { - version: number - // Each migration returns its result as an `Either` so the surrounding - // `runMigrations` loop, and in turn `init`, can propagate the - // `StoreError` contract without falling back to throws. - migrate: () => Promise> -} - -const migrations: Migration[] = [ - { - version: 1, - migrate: async () => E.right(undefined), - }, - { - // v1 to v2. Introduces `DesktopSettings` as the single source of truth - // for all desktop builds. Portable users had `portableSettings` with two - // fields, standard-build users had nothing. Both land in `desktopSettings` - // with full defaults for any field not carried over. - // - // Legacy `portableSettings` is intentionally left in place. The key - // is cheap to keep, it preserves a rollback path, and a later - // migration can prune it once the v2 definition has stabilized. - version: 2, - migrate: async () => { - // Decide whether to skip based on the existing `desktopSettings` - // payload. Two paths can re-run this migration after it succeeded - // once. A user downgrades to a pre-v2 build, which resets - // `SCHEMA_VERSION` to "1" because the older code does not - // recognize "2" and rolls it back. A re-upgrade then sees v1 - // again and tries to migrate. The other path is a corrupted - // `SCHEMA_VERSION` value, which the `runMigrations` parse-defense - // coerces to "1" so every migration reruns from scratch. In both - // cases, blindly running the legacy carry-forward would - // overwrite any user-set v2 fields with - // `disableUpdateNotifications` plus schema defaults, undoing the - // user's work. - // - // Three reachable cases here, each handled explicitly. A `Left` - // from `Store.get` means the store is degraded (file I/O - // failure, or not yet open) and there is no way to tell whether - // v2 already ran. Propagating the `Left` aborts the migration - // before `runMigrations` bumps `SCHEMA_VERSION`, so the next - // launch retries on a hopefully-recovered store. A `Right` with - // a present and schema-valid payload is the canonical "v2 - // already happened" signal, since the migration itself is what - // writes a valid payload, so a stored value implies the - // migration ran successfully at least once. A `Right` with - // either no payload (fresh install) or a malformed payload - // (partial object, wrong field types) falls through to the - // legacy carry-forward, which writes a fresh schema-defaults - // `desktopSettings` and self-heals the corruption. - const existingResult = await Store.get( - STORE_NAMESPACE, - STORE_KEYS.DESKTOP_SETTINGS - ) - if (E.isLeft(existingResult)) { - return existingResult - } - if ( - existingResult.right !== undefined && - DESKTOP_SETTINGS_SCHEMA.safeParse(existingResult.right).success - ) { - return E.right(undefined) - } - - const legacyResult = await Store.get>( - STORE_NAMESPACE, - STORE_KEYS.PORTABLE_SETTINGS - ) - const legacy = - E.isRight(legacyResult) && legacyResult.right - ? legacyResult.right - : undefined - - // Use `safeParse` with a defaults fallback. `Store.get` returns - // the raw JSON value cast to the generic without validation, so - // a corrupted legacy entry (for example a stringified boolean - // left behind by an older build) would throw from `.parse` and - // abort the full persistence init. Falling back to a fresh - // defaults parse keeps the migration progressing on bad data. - const parsed = DESKTOP_SETTINGS_SCHEMA.safeParse({ - disableUpdateNotifications: legacy?.disableUpdateNotifications, - autoSkipWelcome: legacy?.autoSkipWelcome, - }) - const migrated = parsed.success - ? parsed.data - : DESKTOP_SETTINGS_SCHEMA.parse({}) - - const writeResult = await Store.set( - STORE_NAMESPACE, - STORE_KEYS.DESKTOP_SETTINGS, - migrated - ) - if (E.isLeft(writeResult)) { - // Return Left so `runMigrations` aborts before recording the - // new `SCHEMA_VERSION`. Swallowing here would let the loop - // bump the version despite the failed write, and the next - // launch would treat the data as already migrated and never - // retry. - Log.error( - LOG_TAG, - "v2 migration failed to write desktopSettings", - writeResult.left - ) - return writeResult - } - return E.right(undefined) - }, - }, -] - -/** - * Facade over the desktop-local persistent store. - * - * Each persistent value is exposed as a `StoreResource`, which - * carries a uniform `{ get, set, watch }` API validated through a Zod - * schema. The service itself is a thin orchestrator. It runs - * schema-version migrations on init, subscribes once to the - * desktop-settings resource so the Rust mailbox stays in sync with any - * writer, and exposes the resources as readonly members. - * - * Callers move from `persistence.setFoo(value)` to `persistence.foo.set(value)` - * and likewise for `get` / `watch`. Compound operations (e.g. adding to the - * recent-instances list) live as free functions over the resource, below. - */ -export class DesktopPersistenceService { - private static instance: DesktopPersistenceService - - readonly desktopSettings: StoreResource - readonly updateState: StoreResource - readonly connectionState: StoreResource - readonly recentInstances: StoreResource - - private constructor() { - this.desktopSettings = createStoreResource( - STORE_NAMESPACE, - STORE_KEYS.DESKTOP_SETTINGS, - DESKTOP_SETTINGS_SCHEMA, - () => DESKTOP_SETTINGS_SCHEMA.parse({}) - ) - this.updateState = createStoreResource( - STORE_NAMESPACE, - STORE_KEYS.UPDATE_STATE, - UPDATE_STATE_SCHEMA.nullable(), - () => null - ) - this.connectionState = createStoreResource( - STORE_NAMESPACE, - STORE_KEYS.CONNECTION_STATE, - PERSISTED_CONNECTION_STATE_SCHEMA.nullable(), - () => null - ) - this.recentInstances = createStoreResource( - STORE_NAMESPACE, - STORE_KEYS.RECENT_INSTANCES, - z.array(INSTANCE_SCHEMA), - () => [] - ) - } - - public static getInstance(): DesktopPersistenceService { - if (!DesktopPersistenceService.instance) { - DesktopPersistenceService.instance = new DesktopPersistenceService() - } - return DesktopPersistenceService.instance - } - - async init(): Promise> { - const initResult = await Store.init() - if (E.isLeft(initResult)) { - Log.error(LOG_TAG, "Failed to initialize store", initResult.left) - return initResult - } - const migrationResult = await this.runMigrations() - if (E.isLeft(migrationResult)) { - return migrationResult - } - await this.setupRustSync() - return E.right(undefined) - } - - /** - * Keep the Rust-side `DESKTOP_CONFIG` mailbox (see - * `src-tauri/src/config.rs`) in sync with the desktop settings resource. - * - * Two triggers. An initial push so Rust has the current value - * before any consumer reads it. A subscription to the resource's - * `watch` so every subsequent write from any writer (this shell, - * the webview, another process) gets mirrored. The write-side code - * path stays pure persistence, and the sync is a cross-cutting - * concern handled here. - * - * Both paths swallow failures. Rust already has a compile-time default - * for every field Rust cares about, so a failed sync degrades to - * "Rust reads stale value" rather than a user-visible error. - */ - private async setupRustSync(): Promise { - try { - const initial = await this.desktopSettings.get() - await invoke("set_desktop_config", { config: initial }) - } catch (err) { - Log.warn(LOG_TAG, "Initial DesktopSettings sync to Rust failed", err) - } - - try { - await this.desktopSettings.watch((settings) => { - invoke("set_desktop_config", { config: settings }).catch((err) => { - Log.warn(LOG_TAG, "DesktopSettings sync to Rust failed", err) - }) - }) - } catch (err) { - Log.warn( - LOG_TAG, - "Failed to subscribe to DesktopSettings for Rust sync", - err - ) - } - } - - private async runMigrations(): Promise> { - const versionResult = await Store.get( - STORE_NAMESPACE, - STORE_KEYS.SCHEMA_VERSION - ) - const perhapsVersion = E.isRight(versionResult) ? versionResult.right : "1" - const rawVersion = perhapsVersion ?? "1" - // Coerce a corrupted or non-numeric stored value to the lowest known - // version. Without this, `parseInt("v2")` or `parseInt("")` would - // return NaN, every `migration.version > NaN` check below would - // evaluate to false, the loop would skip every migration, and the - // code would still write `SCHEMA_VERSION = "2"` at the end. That - // would mark migrations complete without ever running them. - // Falling back to "1" instead reruns every migration from scratch, - // which is safe because each migration is idempotent on a fresh - // store and a real fresh install lands here through the same path. - const parsedVersion = parseInt(rawVersion, 10) - const currentVersion = Number.isNaN(parsedVersion) ? "1" : rawVersion - const targetVersion = "2" - - if (currentVersion === targetVersion) { - return E.right(undefined) - } - - for (const migration of migrations) { - if (migration.version > parseInt(currentVersion, 10)) { - const result = await migration.migrate() - if (E.isLeft(result)) { - return result - } - } - } - - // Record the new version only when the write succeeds. A silent - // failure here would leave the stored version stale, and the next - // launch would re-run every migration on already-migrated data. - const versionWrite = await Store.set( - STORE_NAMESPACE, - STORE_KEYS.SCHEMA_VERSION, - targetVersion - ) - if (E.isLeft(versionWrite)) { - Log.error( - LOG_TAG, - "Failed to persist schema version after migrations", - versionWrite.left - ) - return versionWrite - } - return E.right(undefined) - } -} - -/** - * Adds an instance to the recent list, preserving the "most-recent-first, - * max 10, deduplicated by kind+serverUrl" invariants. Kept as a free - * function over the resource rather than a method on the service so the - * data-access concern (the resource) stays separate from the business - * rules (dedupe, sort, trim). - */ -export async function addRecentInstance( - recent: StoreResource, - instance: Instance -): Promise { - const current = await recent.get() - const now = new Date().toISOString() - const existingIndex = current.findIndex( - (i) => i.kind === instance.kind && i.serverUrl === instance.serverUrl - ) - - const merged = - existingIndex >= 0 - ? current.map((existing, index) => - index === existingIndex ? { ...instance, lastUsed: now } : existing - ) - : [{ ...instance, lastUsed: now }, ...current] - - const next = [...merged] - .sort( - (a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime() - ) - .slice(0, 10) - - await recent.set(next) -} - -/** - * Removes an instance from the recent list by `serverUrl`. Absent entries - * are silently ignored. - */ -export async function removeRecentInstance( - recent: StoreResource, - serverUrl: string -): Promise { - const current = await recent.get() - const filtered = current.filter((i) => i.serverUrl !== serverUrl) - await recent.set(filtered) -} diff --git a/packages/hoppscotch-desktop/src/services/updater.client.ts b/packages/hoppscotch-desktop/src/services/updater.client.ts deleted file mode 100644 index 45a26f9b..00000000 --- a/packages/hoppscotch-desktop/src/services/updater.client.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { invoke } from "@tauri-apps/api/core" -import { listen, type UnlistenFn } from "@tauri-apps/api/event" - -export interface UpdateInfo { - available: boolean - currentVersion: string - latestVersion?: string - releaseNotes?: string -} - -export interface DownloadProgress { - downloaded: number - total?: number - percentage: number -} - -// TODO: Type safety just like `persistence.serivce.ts`? -export type UpdateEvent = - | { type: "CheckStarted" } - | { type: "CheckCompleted"; info: UpdateInfo } - | { type: "CheckFailed"; error: string } - | { type: "DownloadStarted"; totalBytes?: number } - | { type: "DownloadProgress"; progress: DownloadProgress } - | { type: "DownloadCompleted" } - | { type: "InstallStarted" } - | { type: "InstallCompleted" } - | { type: "RestartRequired" } - | { type: "UpdateCancelled" } - | { type: "Error"; message: string } - -export class UpdaterClient { - private unlistenFn?: UnlistenFn - - async checkForUpdates(showNativeDialog = false): Promise { - return invoke("check_for_updates", { showNativeDialog }) - } - - async downloadAndInstall(): Promise { - return invoke("download_and_install_update") - } - - async restart(): Promise { - return invoke("restart_application") - } - - async cancel(): Promise { - return invoke("cancel_update") - } - - async getDownloadProgress(): Promise { - return invoke("get_download_progress") - } - - async isPortableMode(): Promise { - return invoke("is_portable_mode") - } - - async listenToUpdates( - callback: (event: UpdateEvent) => void - ): Promise { - this.unlistenFn = await listen("updater-event", (event) => { - callback(event.payload as UpdateEvent) - }) - return this.unlistenFn - } - - stopListening(): void { - if (this.unlistenFn) { - this.unlistenFn() - this.unlistenFn = undefined - } - } -} diff --git a/packages/hoppscotch-desktop/src/types/index.ts b/packages/hoppscotch-desktop/src/types/index.ts deleted file mode 100644 index 73945441..00000000 --- a/packages/hoppscotch-desktop/src/types/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Re-exports of types whose canonical definitions live in common. Listed -// here so in-package imports can keep using `~/types` without every caller -// needing to know the precise module path in common. New types that need to -// cross the shell/webview boundary belong in common directly. -export { - UpdateStatus, - type UpdateState, - type DownloadProgress, -} from "@hoppscotch/common/platform/update-state" - -// Not to be confused with `UpdateStatus`. `CheckResult` is the outcome of a -// single call to the updater's `checkForUpdates`, where `UpdateStatus` is -// the full state machine covering checking, downloading, installing, and -// restart. Only `checkForUpdates` returns this. -export enum CheckResult { - AVAILABLE, - NOT_AVAILABLE, - TIMEOUT, - ERROR, -} diff --git a/packages/hoppscotch-desktop/src/types/kernel.d.ts b/packages/hoppscotch-desktop/src/types/kernel.d.ts deleted file mode 100644 index a4c43a34..00000000 --- a/packages/hoppscotch-desktop/src/types/kernel.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { KernelAPI } from "@hoppscotch/kernel" - -declare global { - interface Window { - __KERNEL__?: KernelAPI - } -} - -export {} diff --git a/packages/hoppscotch-desktop/src/utils/updater.ts b/packages/hoppscotch-desktop/src/utils/updater.ts deleted file mode 100644 index c98276d3..00000000 --- a/packages/hoppscotch-desktop/src/utils/updater.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { check, type DownloadEvent } from "@tauri-apps/plugin-updater" -import { relaunch } from "@tauri-apps/plugin-process" -import { type LazyStore } from "@tauri-apps/plugin-store" -import { UpdateStatus, CheckResult, UpdateState } from "~/types" - -export class UpdaterService { - private currentProgress: { downloaded: number; total?: number } = { - downloaded: 0, - } - - constructor(private store: LazyStore) {} - - async initialize(): Promise { - await this.saveUpdateState({ - status: UpdateStatus.IDLE, - }) - } - - getCurrentProgress(): { downloaded: number; total?: number } { - return this.currentProgress - } - - async checkForUpdates(timeout = 5000): Promise { - try { - await this.saveUpdateState({ - status: UpdateStatus.CHECKING, - }) - - // This creats a timeout promise that is slightly longer than `check`'s internal timeout, - // this is just to make sure we don't keep checking for updates indefinitely. - // NOTE: `check` tends to hang indefinitely in dev mode, but works in build, - // so this is just in case this ever happens on prod. - const timeoutPromise = new Promise((resolve) => { - // Longer local timeout to make sure it only triggers - // if there's an issue with `check`'s built-in timeout. - const bufferTimeout = timeout + 1000 - setTimeout(() => { - console.log( - "Update check exceeded buffer timeout, likely hanging in check function" - ) - resolve(null) - }, bufferTimeout) - }) - - const updateResult = await Promise.race([ - check({ timeout }), - timeoutPromise, - ]) - - // If we got a timeout (null), we treat it as no update available - // NOTE: We could maybe show more info but for now this works fine - if (!updateResult) { - console.log("Update check timed out or no update available") - await this.saveUpdateState({ - status: UpdateStatus.NOT_AVAILABLE, - }) - return CheckResult.TIMEOUT - } - - const hasUpdates = updateResult.available - - await this.saveUpdateState( - hasUpdates - ? { - status: UpdateStatus.AVAILABLE, - version: updateResult.version, - message: updateResult.body, - } - : { - status: UpdateStatus.NOT_AVAILABLE, - } - ) - - console.log("Update check result:", { - available: updateResult.available, - currentVersion: updateResult.currentVersion, - version: updateResult.version, - }) - - return hasUpdates ? CheckResult.AVAILABLE : CheckResult.NOT_AVAILABLE - } catch (error) { - console.error("Error checking for updates:", error) - await this.saveUpdateState({ - status: UpdateStatus.ERROR, - message: String(error), - }) - return CheckResult.ERROR - } - } - - async downloadAndInstall(): Promise { - try { - const updateResult = await check() - - if (!updateResult) { - throw new Error("No update available to install") - } - - let totalBytes: number | undefined - let downloadedBytes = 0 - - await this.saveUpdateState({ - status: UpdateStatus.DOWNLOADING, - }) - - await updateResult.downloadAndInstall((event: DownloadEvent) => { - try { - if (event.event === "Started") { - totalBytes = event.data.contentLength - downloadedBytes = 0 - console.log(`Download started, total size: ${totalBytes} bytes`) - } else if (event.event === "Progress") { - downloadedBytes += event.data.chunkLength - console.log( - `Download progress: ${downloadedBytes}/${totalBytes} bytes` - ) - - this.currentProgress = { - downloaded: downloadedBytes, - total: totalBytes, - } - } else if (event.event === "Finished") { - console.log("Download finished, starting installation") - this.saveUpdateState({ - status: UpdateStatus.INSTALLING, - }) - } - } catch (error) { - console.warn("Progress tracking error:", error) - } - }) - - // If we reach here, it means the app hasn't restarted automatically - // Mark as ready to restart - await this.saveUpdateState({ - status: UpdateStatus.READY_TO_RESTART, - }) - } catch (error) { - console.error("Error installing updates:", error) - await this.saveUpdateState({ - status: UpdateStatus.ERROR, - message: String(error), - }) - throw error - } - } - - async restartApp(): Promise { - try { - await relaunch() - } catch (error) { - console.error("Failed to restart app:", error) - throw error - } - } - - private async saveUpdateState(state: UpdateState): Promise { - try { - await this.store.set("updateState", state) - await this.store.save() - } catch (error) { - console.error("Failed to save update state:", error) - } - } -} diff --git a/packages/hoppscotch-desktop/src/views/Home.vue b/packages/hoppscotch-desktop/src/views/Home.vue deleted file mode 100644 index 62200c7b..00000000 --- a/packages/hoppscotch-desktop/src/views/Home.vue +++ /dev/null @@ -1,409 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/views/PortableHome.vue b/packages/hoppscotch-desktop/src/views/PortableHome.vue deleted file mode 100644 index 83aadeda..00000000 --- a/packages/hoppscotch-desktop/src/views/PortableHome.vue +++ /dev/null @@ -1,294 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/views/StandardHome.vue b/packages/hoppscotch-desktop/src/views/StandardHome.vue deleted file mode 100644 index f43068f4..00000000 --- a/packages/hoppscotch-desktop/src/views/StandardHome.vue +++ /dev/null @@ -1,192 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/views/shared/AppHeader.vue b/packages/hoppscotch-desktop/src/views/shared/AppHeader.vue deleted file mode 100644 index b6a7a5af..00000000 --- a/packages/hoppscotch-desktop/src/views/shared/AppHeader.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/views/shared/ErrorState.vue b/packages/hoppscotch-desktop/src/views/shared/ErrorState.vue deleted file mode 100644 index fb1fdc65..00000000 --- a/packages/hoppscotch-desktop/src/views/shared/ErrorState.vue +++ /dev/null @@ -1,30 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/views/shared/LoadingState.vue b/packages/hoppscotch-desktop/src/views/shared/LoadingState.vue deleted file mode 100644 index 6fb4e2ee..00000000 --- a/packages/hoppscotch-desktop/src/views/shared/LoadingState.vue +++ /dev/null @@ -1,14 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/views/shared/UpdateFlow.vue b/packages/hoppscotch-desktop/src/views/shared/UpdateFlow.vue deleted file mode 100644 index 1359145f..00000000 --- a/packages/hoppscotch-desktop/src/views/shared/UpdateFlow.vue +++ /dev/null @@ -1,112 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/views/shared/VersionInfo.vue b/packages/hoppscotch-desktop/src/views/shared/VersionInfo.vue deleted file mode 100644 index 0406f85b..00000000 --- a/packages/hoppscotch-desktop/src/views/shared/VersionInfo.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/packages/hoppscotch-desktop/src/vite-env.d.ts b/packages/hoppscotch-desktop/src/vite-env.d.ts deleted file mode 100644 index fc812394..00000000 --- a/packages/hoppscotch-desktop/src/vite-env.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -/// - -declare module "*.vue" { - import type { DefineComponent } from "vue"; - const component: DefineComponent<{}, {}, any>; - export default component; -} diff --git a/packages/hoppscotch-desktop/tailwind.config.ts b/packages/hoppscotch-desktop/tailwind.config.ts deleted file mode 100644 index 90d7ff26..00000000 --- a/packages/hoppscotch-desktop/tailwind.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Config } from "tailwindcss" -import preset from "@hoppscotch/ui/ui-preset" - -export default { - content: ["src/**/*.{vue,html}"], - presets: [preset], -} satisfies Config diff --git a/packages/hoppscotch-desktop/tsconfig.json b/packages/hoppscotch-desktop/tsconfig.json deleted file mode 100644 index 1a0e5977..00000000 --- a/packages/hoppscotch-desktop/tsconfig.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "skipLibCheck": true, - - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "preserve", - - /* Linting */ - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true, - "paths": { - "~/*": ["./src/*"], - "@hoppscotch/common": ["../hoppscotch-common/src/index.ts"], - "@hoppscotch/common/*": ["../hoppscotch-common/src/*"], - "@composables/*": ["./src/composables/*"], - "@components/*": ["./src/components/*"], - "@helpers/*": ["./src/helpers/*"], - "@kernel/*": ["./src/kernel/*"], - "@modules/*": ["./src/modules/*"], - "@services/*": ["./src/services/*"], - "@workers/*": ["./src/workers/*"], - "@functional/*": ["./src/helpers/functional/*"] - }, - "types": [ - "vite/client", - "unplugin-icons/types/vue", - "./src/types/kernel.d.ts" - ] - }, - "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], - "references": [{ "path": "./tsconfig.node.json" }], - "vueCompilerOptions": { - "jsxTemplates": true, - "experimentalRfc436": true - } -} diff --git a/packages/hoppscotch-desktop/tsconfig.node.json b/packages/hoppscotch-desktop/tsconfig.node.json deleted file mode 100644 index 42872c59..00000000 --- a/packages/hoppscotch-desktop/tsconfig.node.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "skipLibCheck": true, - "module": "ESNext", - "moduleResolution": "bundler", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/packages/hoppscotch-desktop/vite.config.ts b/packages/hoppscotch-desktop/vite.config.ts deleted file mode 100644 index 75d2f1ef..00000000 --- a/packages/hoppscotch-desktop/vite.config.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { defineConfig } from "vite" -import vue from "@vitejs/plugin-vue" -import Icons from "unplugin-icons/vite" -import IconResolver from "unplugin-icons/resolver" -import Components from "unplugin-vue-components/vite" -import path from "path" - -// @ts-expect-error process is a nodejs global -const host = process.env.TAURI_DEV_HOST - -export default defineConfig(async () => ({ - plugins: [ - vue(), - Components({ - dts: "./src/components.d.ts", - resolvers: [ - IconResolver({ - prefix: "icon", - }), - (compName: string) => { - if (compName.startsWith("Hopp")) - return { name: compName, from: "@hoppscotch/ui" } - return undefined - }, - ], - types: [ - { - from: "vue-tippy", - names: ["Tippy"], - }, - ], - include: [/\.vue$/, /\.vue\?vue/], - dirs: ["src/components"], - }), - Icons({ - compiler: "vue3", - }), - ], - - resolve: { - alias: { - "~": path.resolve(__dirname, "src"), - "~/": path.resolve(__dirname, "src/"), - "@hoppscotch/common": "@hoppscotch/common/src", - }, - dedupe: ["vue"], - }, - - optimizeDeps: { - include: ["@hoppscotch/kernel"], - }, - - build: { - rollupOptions: { - output: { - manualChunks: { - kernel: ["@hoppscotch/kernel"], - ui: ["@hoppscotch/ui"], - }, - }, - }, - }, - - // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` - clearScreen: false, - server: { - port: 1420, - strictPort: true, - host: "127.0.0.1", - hmr: host - ? { - protocol: "ws", - host, - port: 1421, - } - : undefined, - watch: { - ignored: ["**/src-tauri/**"], - }, - }, -})) diff --git a/packages/hoppscotch-relay/.gitignore b/packages/hoppscotch-relay/.gitignore deleted file mode 100644 index 54bb18f2..00000000 --- a/packages/hoppscotch-relay/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -/target -# Devenv -.devenv* -devenv.local.nix - -# direnv -.direnv - -# pre-commit -.pre-commit-config.yaml diff --git a/packages/hoppscotch-relay/Cargo.lock b/packages/hoppscotch-relay/Cargo.lock deleted file mode 100644 index 99a6301f..00000000 --- a/packages/hoppscotch-relay/Cargo.lock +++ /dev/null @@ -1,644 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" - -[[package]] -name = "anstyle-parse" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" -dependencies = [ - "windows-sys", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" -dependencies = [ - "anstyle", - "windows-sys", -] - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets", -] - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bytes" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" - -[[package]] -name = "cc" -version = "1.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" -dependencies = [ - "shlex", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "colorchoice" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" - -[[package]] -name = "curl" -version = "0.4.47" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "socket2", -] - -[[package]] -name = "curl-sys" -version = "0.4.77+curl-8.10.1" -source = "git+https://github.com/CuriousCorrelation/curl-rust.git#1ec8079cf527b9cf47cc7a48c68b458affdae273" -dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "windows-sys", -] - -[[package]] -name = "env_filter" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" -dependencies = [ - "log", - "regex", -] - -[[package]] -name = "env_logger" -version = "0.11.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" -dependencies = [ - "anstream", - "anstyle", - "env_filter", - "humantime", - "log", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "hoppscotch-relay" -version = "0.1.1" -dependencies = [ - "curl", - "env_logger", - "http", - "log", - "openssl", - "openssl-sys", - "serde", - "serde_json", - "thiserror", - "tokio-util", - "url-escape", -] - -[[package]] -name = "http" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "itoa" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "libc" -version = "0.2.161" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" - -[[package]] -name = "libz-sys" -version = "1.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "miniz_oxide" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" -dependencies = [ - "adler2", -] - -[[package]] -name = "object" -version = "0.36.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "openssl" -version = "0.10.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-src" -version = "300.4.0+3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6" -dependencies = [ - "cc", -] - -[[package]] -name = "openssl-sys" -version = "0.9.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" -dependencies = [ - "cc", - "libc", - "openssl-src", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pin-project-lite" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" - -[[package]] -name = "pkg-config" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" - -[[package]] -name = "proc-macro2" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" - -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - -[[package]] -name = "ryu" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" - -[[package]] -name = "serde" -version = "1.0.213" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.213" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.132" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "socket2" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" -dependencies = [ - "libc", - "windows-sys", -] - -[[package]] -name = "syn" -version = "2.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "1.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio" -version = "1.41.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" -dependencies = [ - "backtrace", - "pin-project-lite", -] - -[[package]] -name = "tokio-util" -version = "0.7.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "unicode-ident" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" - -[[package]] -name = "url-escape" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44e0ce4d1246d075ca5abec4b41d33e87a6054d08e2366b63205665e950db218" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "windows-sys" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/packages/hoppscotch-relay/Cargo.toml b/packages/hoppscotch-relay/Cargo.toml deleted file mode 100644 index 4ac0ce9f..00000000 --- a/packages/hoppscotch-relay/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "hoppscotch-relay" -version = "0.1.1" -description = "A HTTP request-response relay used by Hoppscotch Desktop and Hoppscotch Agent for advanced request handling including custom headers, certificates, proxies, and local system integration." -authors = ["CuriousCorrelation"] -edition = "2021" - -[dependencies] -curl = { git = "https://github.com/CuriousCorrelation/curl-rust.git", features = ["ntlm"] } -tokio-util = "0.7.12" -openssl = { version = "0.10.66", features = ["vendored"] } -# NOTE: This crate follows `openssl-sys` from https://github.com/CuriousCorrelation/curl-rust.git -# to avoid issues from version mismatch when compiling from source. -openssl-sys = { version = "0.9.64", features = ["vendored"] } -log = "0.4.22" -env_logger = "0.11.5" -thiserror = "1.0.64" -http = "1.1.0" -url-escape = "0.1.1" -serde = { version = "1", features = ["derive"] } -serde_json = "1" diff --git a/packages/hoppscotch-relay/LICENSE.md b/packages/hoppscotch-relay/LICENSE.md deleted file mode 100644 index d91bdaf0..00000000 --- a/packages/hoppscotch-relay/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2024 CuriousCorrelation - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/hoppscotch-relay/README.md b/packages/hoppscotch-relay/README.md deleted file mode 100644 index 1fc53de2..00000000 --- a/packages/hoppscotch-relay/README.md +++ /dev/null @@ -1,201 +0,0 @@ -# Hoppscotch Relay - -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) - -A high-performance HTTP request-response relay used by Hoppscotch Desktop and Hoppscotch Agent for advanced request handling including CORS override, custom headers, certificates, proxies, and local system integration. It uses a custom fork of curl-rust with static OpenSSL builds for consistent SSL/TLS behavior across different platforms. - -## Features - -- 🚀 **Full HTTP Support**: Handle GET, POST, PUT, DELETE, and other HTTP methods -- 📦 **Multiple Body Types**: - - Raw text/JSON - - URL-encoded forms - - Multipart form data - - File uploads -- 🔒 **Security**: - - Client certificate authentication (PEM & PFX/PKCS#12) - - Custom root certificate bundles - - Certificate validation control -- 🌐 **Proxy Support**: - - HTTP/HTTPS proxy configuration - - Authentication support - - NTLM support -- ⚡ **Performance**: - - Async design - - Request cancellation support - - Progress logs -- 📊 **Detailed Metrics**: - - Response timing - - Status tracking - - Header parsing - -## Installation - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -hoppscotch-relay = "0.1.1" -``` - -## Usage - -### Basic Request - -```rust -use hoppscotch_relay::{RequestWithMetadata, KeyValuePair}; -use tokio_util::sync::CancellationToken; - -// Create a basic GET request -let request = RequestWithMetadata::new( - 1, // Request ID - "GET".to_string(), // Method - "https://api.example.com/data".to_string(), // Endpoint - vec![ // Headers - KeyValuePair { - key: "Accept".to_string(), - value: "application/json".to_string(), - } - ], - None, // Body - true, // Validate certificates - vec![], // Root certificate bundles - None, // Client certificate - None, // Proxy configuration -); - -// Execute the request with cancellation support -let cancel_token = CancellationToken::new(); -let response = hoppscotch_relay::run_request_task(&request, cancel_token)?; - -println!("Status: {} {}", response.status, response.status_text); -println!("Response time: {}ms", response.time_end_ms - response.time_start_ms); -``` - -### POST Request with JSON Body - -```rust -let mut request = RequestWithMetadata::new( - 2, - "POST".to_string(), - "https://api.example.com/users".to_string(), - vec![ - KeyValuePair { - key: "Content-Type".to_string(), - value: "application/json".to_string(), - } - ], - Some(BodyDef::Text(r#"{"name": "John Doe"}"#.to_string())), - true, - vec![], - None, - None, -); - -let response = hoppscotch_relay::run_request_task(&request, CancellationToken::new())?; -``` - -### File Upload with Form Data - -```rust -let form_data = vec![ - FormDataEntry { - key: "file".to_string(), - value: FormDataValue::File { - filename: "document.pdf".to_string(), - data: std::fs::read("document.pdf")?, - mime: "application/pdf".to_string(), - }, - }, - FormDataEntry { - key: "description".to_string(), - value: FormDataValue::Text("Important document".to_string()), - }, -]; - -let mut request = RequestWithMetadata::new( - 3, - "POST".to_string(), - "https://api.example.com/upload".to_string(), - vec![], - Some(BodyDef::FormData(form_data)), - true, - vec![], - None, - None, -); -``` - -### Client Certificate Authentication - -```rust -let client_cert = ClientCertDef::PEMCert { - certificate_pem: std::fs::read("client.crt")?, - key_pem: std::fs::read("client.key")?, -}; - -let mut request = RequestWithMetadata::new( - 4, - "GET".to_string(), - "https://secure-api.example.com".to_string(), - vec![], - None, - true, - vec![], - Some(client_cert), - None, -); -``` - -### Proxy Configuration - -```rust -let proxy_config = ProxyConfig { - url: "http://proxy.example.com:8080".to_string(), -}; - -let mut request = RequestWithMetadata::new( - 5, - "GET".to_string(), - "https://api.example.com".to_string(), - vec![], - None, - true, - vec![], - None, - Some(proxy_config), -); -``` - -## Request Cancellation - -The library supports request cancellation through Tokio's `CancellationToken`: - -```rust -use tokio_util::sync::CancellationToken; - -let cancel_token = CancellationToken::new(); -let cancel_token_clone = cancel_token.clone(); - -// Spawn the request in a separate task -let request_handle = tokio::spawn(async move { - hoppscotch_relay::run_request_task(&request, cancel_token_clone) -}); - -// Cancel the request after 5 seconds -tokio::time::sleep(Duration::from_secs(5)).await; -cancel_token.cancel(); -``` - -## Building from Source - -1. Clone the repository: -```bash -git clone https://github.com/hoppscotch/hoppscotch-relay -cd hoppscotch-relay -``` - -2. Build the project: -```bash -cargo build --release -``` diff --git a/packages/hoppscotch-relay/src/error.rs b/packages/hoppscotch-relay/src/error.rs deleted file mode 100644 index 10b0c9a5..00000000 --- a/packages/hoppscotch-relay/src/error.rs +++ /dev/null @@ -1,16 +0,0 @@ -use serde::Serialize; -use thiserror::Error; - -#[derive(Debug, Error, Serialize)] -pub enum RelayError { - #[error("Invalid method")] - InvalidMethod, - #[error("Invalid URL")] - InvalidUrl, - #[error("Invalid headers")] - InvalidHeaders, - #[error("Request run error: {0}")] - RequestRunError(String), -} - -pub type RelayResult = std::result::Result; diff --git a/packages/hoppscotch-relay/src/interop.rs b/packages/hoppscotch-relay/src/interop.rs deleted file mode 100644 index f893dcb2..00000000 --- a/packages/hoppscotch-relay/src/interop.rs +++ /dev/null @@ -1,96 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct KeyValuePair { - pub key: String, - pub value: String, -} - -#[derive(Debug, Deserialize)] -pub enum FormDataValue { - Text(String), - File { - filename: String, - data: Vec, - mime: String, - }, -} - -#[derive(Debug, Deserialize)] -pub struct FormDataEntry { - pub key: String, - pub value: FormDataValue, -} - -#[derive(Debug, Deserialize)] -pub enum BodyDef { - Text(String), - URLEncoded(Vec), - FormData(Vec), -} - -#[derive(Debug, Deserialize)] -pub struct RequestWithMetadata { - pub req_id: usize, - pub method: String, - pub endpoint: String, - pub headers: Vec, - pub body: Option, - pub validate_certs: bool, - pub root_cert_bundle_files: Vec>, - pub client_cert: Option, - pub proxy: Option, -} - -impl RequestWithMetadata { - pub fn new( - req_id: usize, - method: String, - endpoint: String, - headers: Vec, - body: Option, - validate_certs: bool, - root_cert_bundle_files: Vec>, - client_cert: Option, - proxy: Option, - ) -> Self { - Self { - req_id, - method, - endpoint, - headers, - body, - validate_certs, - root_cert_bundle_files, - client_cert, - proxy, - } - } -} - -#[derive(Debug, Deserialize)] -pub struct ProxyConfig { - pub url: String, -} - -#[derive(Debug, Deserialize)] -pub enum ClientCertDef { - PEMCert { - certificate_pem: Vec, - key_pem: Vec, - }, - PFXCert { - certificate_pfx: Vec, - password: String, - }, -} - -#[derive(Debug, Serialize)] -pub struct ResponseWithMetadata { - pub status: u16, - pub status_text: String, - pub headers: Vec, - pub data: Vec, - pub time_start_ms: u128, - pub time_end_ms: u128, -} diff --git a/packages/hoppscotch-relay/src/lib.rs b/packages/hoppscotch-relay/src/lib.rs deleted file mode 100644 index 621f1afb..00000000 --- a/packages/hoppscotch-relay/src/lib.rs +++ /dev/null @@ -1,23 +0,0 @@ -pub(crate) mod error; -pub(crate) mod interop; -pub(crate) mod relay; -pub(crate) mod util; - -pub use error::{RelayError, RelayResult}; -pub use interop::{RequestWithMetadata, ResponseWithMetadata}; -pub use relay::run_request_task; - -pub fn add(left: u64, right: u64) -> u64 { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/packages/hoppscotch-relay/src/relay.rs b/packages/hoppscotch-relay/src/relay.rs deleted file mode 100644 index b1bfdb5a..00000000 --- a/packages/hoppscotch-relay/src/relay.rs +++ /dev/null @@ -1,595 +0,0 @@ -use curl::easy::{Easy, List}; -use openssl::{pkcs12::Pkcs12, ssl::SslContextBuilder, x509::X509}; -use openssl_sys::SSL_CTX; -use std::time::SystemTime; -use tokio_util::sync::CancellationToken; - -use crate::{ - error::RelayError, - interop::{ - BodyDef, ClientCertDef, FormDataValue, KeyValuePair, RequestWithMetadata, - ResponseWithMetadata, - }, - util::get_status_text, -}; - -pub fn run_request_task( - req: &RequestWithMetadata, - cancel_token: CancellationToken, -) -> Result { - log::info!( - "Starting request task: [Method: {}] [URL: {}] [Validate Certs: {}] [Has Body: {}] [Proxy Enabled: {}]", - req.method, - req.endpoint, - req.validate_certs, - req.body.is_some(), - req.proxy.is_some() - ); - - let mut curl_handle = Easy::new(); - log::debug!("Initialized new curl handle with default settings"); - - match curl_handle.progress(true) { - Ok(_) => log::debug!("Progress tracking enabled for request monitoring"), - Err(err) => { - log::error!( - "Critical failure enabling progress tracking: {}\nError details: {:?}", - err, - err - ); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - } - - match curl_handle.custom_request(&req.method) { - Ok(_) => log::debug!("HTTP method set: {}", req.method), - Err(err) => { - log::error!("Failed to set HTTP method '{}'. Error: {}", req.method, err); - return Err(RelayError::InvalidMethod); - } - } - - match curl_handle.url(&req.endpoint) { - Ok(_) => log::debug!("Target URL configured: {}", req.endpoint), - Err(err) => { - log::error!( - "URL configuration failed for '{}'\nError: {}", - req.endpoint, - err - ); - return Err(RelayError::InvalidUrl); - } - } - - let headers = match get_headers_list(&req) { - Ok(headers) => { - log::debug!("Generated headers list"); - headers - } - Err(err) => { - log::error!("Header generation failed:\nError: {:?}", err); - return Err(err); - } - }; - - match curl_handle.http_headers(headers) { - Ok(_) => log::debug!("Successfully configured request headers"), - Err(err) => { - log::error!("Failed to set HTTP headers: {}", err); - return Err(RelayError::InvalidHeaders); - } - } - - if let Err(err) = apply_body_to_curl_handle(&mut curl_handle, &req) { - log::error!( - "Request body application failed:\nError: {:?}\nContent-Type: {:?}", - err, - req.headers - .iter() - .find(|h| h.key.to_lowercase() == "content-type") - .map(|h| &h.value) - ); - return Err(err); - } - log::debug!("Request body configured successfully"); - - match curl_handle.ssl_verify_peer(req.validate_certs) { - Ok(_) => log::debug!( - "SSL peer verification setting applied: {}", - req.validate_certs - ), - Err(err) => { - log::error!( - "SSL peer verification configuration failed: {}\nRequested setting: {}", - err, - req.validate_certs - ); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - } - - match curl_handle.ssl_verify_host(req.validate_certs) { - Ok(_) => log::debug!( - "SSL host verification setting applied: {}", - req.validate_certs - ), - Err(err) => { - log::error!( - "SSL host verification configuration failed: {}\nRequested setting: {}", - err, - req.validate_certs - ); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - } - - if let Err(err) = apply_client_cert_to_curl_handle(&mut curl_handle, &req) { - log::error!( - "Client certificate configuration failed:\nError: {:?}\nCert Info: {:#?}", - err, - req.client_cert.as_ref() - ); - return Err(err); - } - log::debug!("Client certificate configuration successful"); - - if let Err(err) = apply_proxy_config_to_curl_handle(&mut curl_handle, &req) { - log::error!( - "Proxy configuration failed:\nError: {:?}\nProxy Info: {:?}", - err, - req.proxy.as_ref() - ); - return Err(err); - } - log::debug!("Proxy configuration applied successfully"); - - let mut response_body = Vec::new(); - let mut response_headers = Vec::new(); - let (start_time_ms, end_time_ms) = { - let mut transfer = curl_handle.transfer(); - log::debug!("Created curl transfer object for request execution"); - - match transfer.ssl_ctx_function(|ssl_ctx_ptr| { - let cert_list = match get_x509_certs_from_root_cert_bundle_safe(&req) { - Ok(certs) => { - log::debug!("Found {} certificates in root bundle", certs.len()); - certs - } - Err(e) => { - log::error!("Failed to load certificates from bundle: {:?}", e); - return Ok(()); - } - }; - - if !cert_list.is_empty() { - let mut ssl_ctx_builder = - unsafe { SslContextBuilder::from_ptr(ssl_ctx_ptr as *mut SSL_CTX) }; - - let cert_store = ssl_ctx_builder.cert_store_mut(); - - for (index, cert) in cert_list.iter().enumerate() { - log::debug!( - "Processing certificate {}: Subject: {:?}, Not Before: {:?}, Not After: {:?}", - index, - cert.subject_name(), - cert.not_before(), - cert.not_after() - ); - - if let Err(e) = cert_store.add_cert(cert.clone()) { - log::warn!( - "Failed to add certificate {} to store\nError: {}\nCert details: {:?}", - index, - e, - cert.subject_name() - ); - } else { - log::debug!( - "Successfully added certificate {} to store\nSubject: {:?}", - index, - cert.subject_name() - ); - } - } - - // SAFETY: We need to prevent Rust from dropping the `SslContextBuilder` because - // the underlying `SSL_CTX` pointer is owned and managed by curl, not us. - // From curl docs: "libcurl does not guarantee the lifetime of the passed in - // object once this callback function has returned" - // and `SslContextBuilder` is just a safe wrapper around curl's `SSL_CTX` from - // `openssl_sys::SSL_CTX`. - // If dropped, Rust would try to free the `SSL_CTX` which curl still needs. - // - // This intentional "leak" is safe because: - // - We're only leaking the thin Rust wrapper - // - Curl manages the actual `SSL_CTX` memory - // - Curl will free the `SSL_CTX` during connection cleanup - // - // See: https://curl.se/libcurl/c/CURLOPT_SSL_CTX_FUNCTION.html - std::mem::forget(ssl_ctx_builder); - } - - Ok(()) - }) { - Ok(_) => log::debug!("SSL context function configured successfully"), - Err(err) => { - log::error!("SSL context function setup failed: {}", err); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - } - - match transfer.progress_function(|dltotal, dlnow, ultotal, ulnow| { - let cancelled = cancel_token.is_cancelled(); - if cancelled { - log::warn!( - "Request cancelled by user\nDownload: {}/{} bytes\nUpload: {}/{} bytes", - dlnow, - dltotal, - ulnow, - ultotal - ); - } else { - log::debug!( - "Progress - Download: {}/{} bytes, Upload: {}/{} bytes", - dlnow, - dltotal, - ulnow, - ultotal - ); - } - !cancelled - }) { - Ok(_) => log::debug!("Progress monitoring function configured"), - Err(err) => { - log::error!("Progress function setup failed: {}", err); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - } - - match transfer.header_function(|header| { - let header = String::from_utf8_lossy(header).into_owned(); - if let Some((key, value)) = header.split_once(':') { - log::debug!("Received header: [{}] = [{}]", key.trim(), value.trim()); - response_headers.push(KeyValuePair { - key: key.trim().to_string(), - value: value.trim().to_string(), - }); - } else { - log::debug!("Received header line (no key-value): {}", header.trim()); - } - true - }) { - Ok(_) => log::debug!("Header processing function configured"), - Err(err) => { - log::error!("Header function setup failed: {}", err); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - } - - match transfer.write_function(|data| { - let chunk_size = data.len(); - response_body.extend_from_slice(data); - log::debug!( - "Received response chunk: {} bytes (Total size so far: {} bytes)", - chunk_size, - response_body.len() - ); - Ok(chunk_size) - }) { - Ok(_) => log::debug!("Response body processing function configured"), - Err(err) => { - log::error!("Write function setup failed: {}", err); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - } - - let start_time_ms = SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis(); - log::info!( - "Initiating request transfer at timestamp: {}", - start_time_ms - ); - - if let Err(err) = transfer.perform() { - log::error!( - "Request transfer failed:\nError: {}\nTime elapsed: {}ms", - err, - SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis() - - start_time_ms, - ); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - - let end_time_ms = SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_millis(); - - log::info!( - "Request transfer completed:\nDuration: {}ms", - end_time_ms - start_time_ms, - ); - - (start_time_ms, end_time_ms) - }; - - let response_status = match curl_handle.response_code() { - Ok(status) => { - let status = status as u16; - log::info!( - "Response status code: {} ({})", - status, - get_status_text(status) - ); - status - } - Err(err) => { - log::error!("Failed to retrieve response code: {}", err); - return Err(RelayError::RequestRunError(err.description().to_string())); - } - }; - - let response_status_text = get_status_text(response_status).to_string(); - log::info!( - "Request completed successfully:\nStatus: {} ({})\nDuration: {}ms\n\ - Response size: {} bytes\nHeaders: {} received\nEndpoint: {}", - response_status, - response_status_text, - end_time_ms - start_time_ms, - response_body.len(), - response_headers.len(), - req.endpoint - ); - - Ok(ResponseWithMetadata { - status: response_status, - status_text: response_status_text, - headers: response_headers, - data: response_body, - time_start_ms: start_time_ms, - time_end_ms: end_time_ms, - }) -} - -fn get_headers_list(req: &RequestWithMetadata) -> Result { - let mut result = List::new(); - - for KeyValuePair { key, value } in &req.headers { - result - .append(&format!("{}: {}", key, value)) - .map_err(|err| RelayError::RequestRunError(err.description().to_string()))?; - } - - Ok(result) -} - -fn apply_body_to_curl_handle( - curl_handle: &mut Easy, - req: &RequestWithMetadata, -) -> Result<(), RelayError> { - match &req.body { - Some(BodyDef::Text(text)) => { - curl_handle - .post_fields_copy(text.as_bytes()) - .map_err(|err| { - RelayError::RequestRunError(format!( - "Error while setting body: {}", - err.description() - )) - })?; - } - Some(BodyDef::FormData(entries)) => { - let mut form = curl::easy::Form::new(); - - for entry in entries { - let mut part = form.part(&entry.key); - - match &entry.value { - FormDataValue::Text(data) => { - part.contents(data.as_bytes()); - } - FormDataValue::File { - filename, - data, - mime, - } => { - part.buffer(filename, data.clone()).content_type(mime); - } - }; - - part.add().map_err(|err| { - RelayError::RequestRunError(format!( - "Error while setting body: {}", - err.description() - )) - })?; - } - - curl_handle.httppost(form).map_err(|err| { - RelayError::RequestRunError(format!( - "Error while setting body: {}", - err.description() - )) - })?; - } - Some(BodyDef::URLEncoded(entries)) => { - let data = entries - .iter() - .map(|KeyValuePair { key, value }| { - format!( - "{}={}", - &url_escape::encode_www_form_urlencoded(key), - url_escape::encode_www_form_urlencoded(value) - ) - }) - .collect::>() - .join("&"); - - curl_handle - .post_fields_copy(data.as_bytes()) - .map_err(|err| { - RelayError::RequestRunError(format!( - "Error while setting body: {}", - err.description() - )) - })?; - } - None => {} - }; - - Ok(()) -} - -fn apply_client_cert_to_curl_handle( - handle: &mut Easy, - req: &RequestWithMetadata, -) -> Result<(), RelayError> { - match &req.client_cert { - Some(ClientCertDef::PEMCert { - certificate_pem, - key_pem, - }) => { - handle.ssl_cert_type("PEM").map_err(|err| { - RelayError::RequestRunError(format!( - "Failed setting PEM Cert Type: {}", - err.description() - )) - })?; - - handle.ssl_cert_blob(certificate_pem).map_err(|err| { - RelayError::RequestRunError(format!( - "Failed setting PEM Cert Blob: {}", - err.description() - )) - })?; - - handle.ssl_key_type("PEM").map_err(|err| { - RelayError::RequestRunError(format!( - "Failed setting PEM key type: {}", - err.description() - )) - })?; - - handle.ssl_key_blob(key_pem).map_err(|err| { - RelayError::RequestRunError(format!( - "Failed setting PEM Cert blob: {}", - err.description() - )) - })?; - } - Some(ClientCertDef::PFXCert { - certificate_pfx, - password, - }) => { - let pkcs12 = Pkcs12::from_der(&certificate_pfx).map_err(|err| { - RelayError::RequestRunError(format!( - "Failed to parse PFX certificate from DER: {}", - err - )) - })?; - - let parsed = pkcs12.parse2(password).map_err(|err| { - RelayError::RequestRunError(format!( - "Failed to parse PFX certificate with provided password: {}", - err - )) - })?; - - if let (Some(cert), Some(key)) = (parsed.cert, parsed.pkey) { - let certificate_pem = cert.to_pem().map_err(|err| { - RelayError::RequestRunError(format!( - "Failed to convert PFX certificate to PEM format: {}", - err - )) - })?; - - let key_pem = key.private_key_to_pem_pkcs8().map_err(|err| { - RelayError::RequestRunError(format!( - "Failed to convert PFX private key to PEM format: {}", - err - )) - })?; - - handle.ssl_cert_type("PEM").map_err(|err| { - RelayError::RequestRunError(format!( - "Failed setting PEM Cert Type for converted PFX: {}", - err.description() - )) - })?; - - handle.ssl_cert_blob(&certificate_pem).map_err(|err| { - RelayError::RequestRunError(format!( - "Failed setting PEM Cert Blob for converted PFX: {}", - err.description() - )) - })?; - - handle.ssl_key_type("PEM").map_err(|err| { - RelayError::RequestRunError(format!( - "Failed setting PEM key type for converted PFX: {}", - err.description() - )) - })?; - - handle.ssl_key_blob(&key_pem).map_err(|err| { - RelayError::RequestRunError(format!( - "Failed setting PEM key blob for converted PFX: {}", - err.description() - )) - })?; - } else { - return Err(RelayError::RequestRunError( - "PFX certificate parsing succeeded, but either cert or private key is missing" - .to_string(), - )); - } - } - None => {} - }; - - Ok(()) -} - -fn get_x509_certs_from_root_cert_bundle_safe( - req: &RequestWithMetadata, -) -> Result, openssl::error::ErrorStack> { - let mut certs = Vec::new(); - - for pem_bundle in &req.root_cert_bundle_files { - match openssl::x509::X509::stack_from_pem(pem_bundle) { - Ok(mut bundle_certs) => certs.append(&mut bundle_certs), - Err(e) => { - log::warn!("Failed to parse certificate bundle: {:?}", e); - } - } - } - - Ok(certs) -} - -fn apply_proxy_config_to_curl_handle( - handle: &mut Easy, - req: &RequestWithMetadata, -) -> Result<(), RelayError> { - if let Some(proxy_config) = &req.proxy { - handle - .proxy_auth(curl::easy::Auth::new().auto(true)) - .map_err(|err| { - RelayError::RequestRunError(format!( - "Failed to set proxy Auth Mode: {}", - err.description() - )) - })?; - - handle.proxy(&proxy_config.url).map_err(|err| { - RelayError::RequestRunError(format!("Failed to set proxy URL: {}", err.description())) - })?; - } - - Ok(()) -} diff --git a/packages/hoppscotch-relay/src/util.rs b/packages/hoppscotch-relay/src/util.rs deleted file mode 100644 index 877732c0..00000000 --- a/packages/hoppscotch-relay/src/util.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub fn get_status_text(status: u16) -> &'static str { - http::StatusCode::from_u16(status) - .map(|status| status.canonical_reason()) - .unwrap_or(Some("Unknown Status")) - .unwrap_or("Unknown Status") -} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5c7afa8..65257628 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -77,97 +77,6 @@ importers: specifier: 5.9.3 version: 5.9.3 - packages/hoppscotch-agent: - dependencies: - '@hoppscotch/ui': - specifier: 0.2.5 - version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) - '@tauri-apps/api': - specifier: 2.1.1 - version: 2.1.1 - '@tauri-apps/plugin-shell': - specifier: 2.3.3 - version: 2.3.3 - '@vueuse/core': - specifier: 14.2.1 - version: 14.2.1(vue@3.5.33(typescript@5.9.3)) - axios: - specifier: 1.15.2 - version: 1.15.2 - fp-ts: - specifier: 2.16.11 - version: 2.16.11 - lodash-es: - specifier: 4.18.1 - version: 4.18.1 - vue: - specifier: 3.5.33 - version: 3.5.33(typescript@5.9.3) - devDependencies: - '@iconify-json/lucide': - specifier: 1.2.104 - version: 1.2.104 - '@tauri-apps/cli': - specifier: 2.9.3 - version: 2.9.3 - '@types/lodash-es': - specifier: 4.17.12 - version: 4.17.12 - '@types/node': - specifier: 24.10.1 - version: 24.10.1 - '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@vitejs/plugin-vue': - specifier: 6.0.6 - version: 6.0.6(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) - '@vue/eslint-config-typescript': - specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - autoprefixer: - specifier: 10.5.0 - version: 10.5.0(postcss@8.5.10) - cross-env: - specifier: 10.1.0 - version: 10.1.0 - eslint: - specifier: 9.39.2 - version: 9.39.2(jiti@2.6.1) - eslint-plugin-prettier: - specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3) - eslint-plugin-vue: - specifier: 10.9.0 - version: 10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) - globals: - specifier: 16.5.0 - version: 16.5.0 - postcss: - specifier: 8.5.10 - version: 8.5.10 - tailwindcss: - specifier: 3.4.16 - version: 3.4.16(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) - typescript: - specifier: 5.9.3 - version: 5.9.3 - unplugin-icons: - specifier: 22.5.0 - version: 22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16) - unplugin-vue-components: - specifier: 30.0.0 - version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)) - vite: - specifier: 7.3.2 - version: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vue-tsc: - specifier: 2.2.0 - version: 2.2.0(typescript@5.9.3) - packages/hoppscotch-backend: dependencies: '@apollo/server': @@ -412,91 +321,6 @@ importers: specifier: 5.9.3 version: 5.9.3 - packages/hoppscotch-cli: - dependencies: - aws4fetch: - specifier: 1.0.20 - version: 1.0.20 - axios: - specifier: 1.15.2 - version: 1.15.2 - axios-cookiejar-support: - specifier: 6.0.5 - version: 6.0.5(axios@1.15.2)(tough-cookie@6.0.1) - chalk: - specifier: 5.6.2 - version: 5.6.2 - commander: - specifier: 14.0.3 - version: 14.0.3 - isolated-vm: - specifier: 6.1.2 - version: 6.1.2 - js-md5: - specifier: 0.8.3 - version: 0.8.3 - jsonc-parser: - specifier: 3.3.1 - version: 3.3.1 - lodash-es: - specifier: 4.18.1 - version: 4.18.1 - papaparse: - specifier: 5.5.3 - version: 5.5.3 - qs: - specifier: 6.15.1 - version: 6.15.1 - semver: - specifier: 7.7.4 - version: 7.7.4 - tough-cookie: - specifier: 6.0.1 - version: 6.0.1 - verzod: - specifier: 0.4.0 - version: 0.4.0(zod@3.25.32) - xmlbuilder2: - specifier: 4.0.3 - version: 4.0.3 - zod: - specifier: 3.25.32 - version: 3.25.32 - devDependencies: - '@hoppscotch/data': - specifier: workspace:^ - version: link:../hoppscotch-data - '@hoppscotch/js-sandbox': - specifier: workspace:^ - version: link:../hoppscotch-js-sandbox - '@relmify/jest-fp-ts': - specifier: 2.1.1 - version: 2.1.1(fp-ts@2.16.11)(io-ts@2.2.22(fp-ts@2.16.11)) - '@types/lodash-es': - specifier: 4.17.12 - version: 4.17.12 - '@types/papaparse': - specifier: 5.5.2 - version: 5.5.2 - '@types/qs': - specifier: 6.15.0 - version: 6.15.0 - fp-ts: - specifier: 2.16.11 - version: 2.16.11 - prettier: - specifier: 3.8.3 - version: 3.8.3 - tsup: - specifier: 8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.10)(typescript@5.9.3)(yaml@2.8.3) - typescript: - specifier: 5.9.3 - version: 5.9.3 - vitest: - specifier: 4.1.5 - version: 4.1.5(@types/node@25.6.0)(jsdom@27.4.0(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) - packages/hoppscotch-common: dependencies: '@apidevtools/swagger-parser': @@ -1036,193 +860,6 @@ importers: specifier: 7.3.2 version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - packages/hoppscotch-desktop: - dependencies: - '@fontsource-variable/inter': - specifier: 5.2.8 - version: 5.2.8 - '@fontsource-variable/material-symbols-rounded': - specifier: 5.2.43 - version: 5.2.43 - '@fontsource-variable/roboto-mono': - specifier: 5.2.8 - version: 5.2.8 - '@hoppscotch/common': - specifier: workspace:^ - version: link:../hoppscotch-common - '@hoppscotch/kernel': - specifier: workspace:^ - version: link:../hoppscotch-kernel - '@hoppscotch/plugin-appload': - specifier: github:CuriousCorrelation/tauri-plugin-appload#0d58d53be2bc75aeb5916bd0d77794fd209426af - version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/0d58d53be2bc75aeb5916bd0d77794fd209426af' - '@hoppscotch/ui': - specifier: 0.2.5 - version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) - '@tauri-apps/api': - specifier: 2.1.1 - version: 2.1.1 - '@tauri-apps/plugin-fs': - specifier: 2.0.2 - version: 2.0.2 - '@tauri-apps/plugin-process': - specifier: 2.2.0 - version: 2.2.0 - '@tauri-apps/plugin-shell': - specifier: 2.3.3 - version: 2.3.3 - '@tauri-apps/plugin-store': - specifier: 2.4.1 - version: 2.4.1 - '@tauri-apps/plugin-updater': - specifier: 2.9.0 - version: 2.9.0 - fp-ts: - specifier: 2.16.11 - version: 2.16.11 - rxjs: - specifier: 7.8.2 - version: 7.8.2 - vue: - specifier: 3.5.33 - version: 3.5.33(typescript@5.9.3) - vue-router: - specifier: 4.6.4 - version: 4.6.4(vue@3.5.33(typescript@5.9.3)) - vue-tippy: - specifier: 6.7.1 - version: 6.7.1(vue@3.5.33(typescript@5.9.3)) - zod: - specifier: 3.25.32 - version: 3.25.32 - devDependencies: - '@eslint/eslintrc': - specifier: 3.3.5 - version: 3.3.5 - '@eslint/js': - specifier: 9.39.2 - version: 9.39.2 - '@iconify-json/lucide': - specifier: 1.2.104 - version: 1.2.104 - '@rushstack/eslint-patch': - specifier: 1.16.1 - version: 1.16.1 - '@tauri-apps/cli': - specifier: 2.9.3 - version: 2.9.3 - '@typescript-eslint/eslint-plugin': - specifier: 8.59.0 - version: 8.59.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': - specifier: 8.59.0 - version: 8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@vitejs/plugin-vue': - specifier: 6.0.6 - version: 6.0.6(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) - '@vue/eslint-config-typescript': - specifier: 14.7.0 - version: 14.7.0(eslint-plugin-vue@10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - autoprefixer: - specifier: 10.5.0 - version: 10.5.0(postcss@8.5.10) - eslint: - specifier: 9.39.2 - version: 9.39.2(jiti@2.6.1) - eslint-plugin-prettier: - specifier: 5.5.5 - version: 5.5.5(@types/eslint@9.6.1)(eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)))(eslint@9.39.2(jiti@2.6.1))(prettier@3.8.3) - eslint-plugin-vue: - specifier: 10.9.0 - version: 10.9.0(@typescript-eslint/parser@8.59.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(vue-eslint-parser@10.4.0(eslint@9.39.2(jiti@2.6.1))) - globals: - specifier: 16.5.0 - version: 16.5.0 - postcss: - specifier: 8.5.10 - version: 8.5.10 - sass: - specifier: 1.99.0 - version: 1.99.0 - tailwindcss: - specifier: 3.4.16 - version: 3.4.16(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) - typescript: - specifier: 5.9.3 - version: 5.9.3 - unplugin-icons: - specifier: 22.5.0 - version: 22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16) - unplugin-vue-components: - specifier: 30.0.0 - version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)) - vite: - specifier: 7.3.2 - version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vue-tsc: - specifier: 2.2.0 - version: 2.2.0(typescript@5.9.3) - - packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload: - dependencies: - '@tauri-apps/api': - specifier: 2.9.1 - version: 2.9.1 - devDependencies: - '@rollup/plugin-typescript': - specifier: ^12.3.0 - version: 12.3.0(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.3) - rollup: - specifier: ^4.59.0 - version: 4.59.0 - tslib: - specifier: ^2.8.1 - version: 2.8.1 - typescript: - specifier: 5.9.3 - version: 5.9.3 - - packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload/examples/tauri-app: - dependencies: - '@tauri-apps/api': - specifier: 2.1.1 - version: 2.1.1 - tauri-plugin-appload-api: - specifier: file:../../ - version: link:../.. - devDependencies: - '@sveltejs/vite-plugin-svelte': - specifier: ^1.0.1 - version: 1.4.0(svelte@3.59.2)(vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1)) - '@tauri-apps/cli': - specifier: ^2.0.0-alpha.17 - version: 2.9.3 - svelte: - specifier: ^3.49.0 - version: 3.59.2 - vite: - specifier: ^3.0.2 - version: 3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1) - - packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay: - dependencies: - '@tauri-apps/api': - specifier: 2.1.1 - version: 2.1.1 - devDependencies: - '@rollup/plugin-typescript': - specifier: ^11.1.6 - version: 11.1.6(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.2) - rollup: - specifier: ^4.59.0 - version: 4.59.0 - tslib: - specifier: ^2.6.2 - version: 2.8.1 - typescript: - specifier: 5.9.2 - version: 5.9.2 - packages/hoppscotch-js-sandbox: dependencies: '@hoppscotch/data': @@ -1599,13 +1236,13 @@ importers: version: 3.2.0(graphql@16.13.2) '@hoppscotch/ui': specifier: 0.2.5 - version: 0.2.5(eslint@10.2.1(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) + version: 0.2.5(eslint@10.2.1(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@hoppscotch/vue-toasted': specifier: 0.1.0 version: 0.1.0(vue@3.5.33(typescript@5.9.3)) '@intlify/unplugin-vue-i18n': specifier: 11.1.2 - version: 11.1.2(@vue/compiler-dom@3.5.33)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) + version: 11.1.2(@vue/compiler-dom@3.5.33)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) '@types/cors': specifier: 2.8.19 version: 2.8.19 @@ -1650,13 +1287,13 @@ importers: version: 7.8.2 tailwindcss: specifier: 3.4.16 - version: 3.4.16(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3)) + version: 3.4.16(ts-node@10.9.2(@types/node@24.10.1)(typescript@5.9.3)) tippy.js: specifier: 6.3.7 version: 6.3.7 ts-node-dev: specifier: 2.0.0 - version: 2.0.0(@types/node@25.6.0)(typescript@5.9.3) + version: 2.0.0(@types/node@24.10.1)(typescript@5.9.3) unplugin-vue-components: specifier: 30.0.0 version: 30.0.0(@babel/parser@7.29.2)(vue@3.5.33(typescript@5.9.3)) @@ -1675,7 +1312,7 @@ importers: devDependencies: '@graphql-codegen/cli': specifier: 6.3.1 - version: 6.3.1(@parcel/watcher@2.5.6)(@types/node@25.6.0)(graphql@16.13.2)(typescript@5.9.3) + version: 6.3.1(@parcel/watcher@2.5.6)(@types/node@24.10.1)(graphql@16.13.2)(typescript@5.9.3) '@graphql-codegen/client-preset': specifier: 5.3.0 version: 5.3.0(graphql@16.13.2) @@ -1711,7 +1348,7 @@ importers: version: 4.17.12 '@vitejs/plugin-vue': specifier: 6.0.6 - version: 6.0.6(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) + version: 6.0.6(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3)) '@vue/compiler-sfc': specifier: 3.5.33 version: 3.5.33 @@ -1735,25 +1372,25 @@ importers: version: 1.99.0 ts-node: specifier: 10.9.2 - version: 10.9.2(@types/node@25.6.0)(typescript@5.9.3) + version: 10.9.2(@types/node@24.10.1)(typescript@5.9.3) typescript: specifier: 5.9.3 version: 5.9.3 unplugin-fonts: specifier: 1.4.0 - version: 1.4.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) + version: 1.4.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) unplugin-icons: specifier: 22.5.0 version: 22.5.0(@vue/compiler-sfc@3.5.33)(svelte@3.59.2)(vue-template-compiler@2.7.16) vite: specifier: 7.3.2 - version: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + version: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vite-plugin-pages: specifier: 0.33.2 - version: 0.33.2(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))) + version: 0.33.2(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))) vite-plugin-vue-layouts: specifier: 0.11.0 - version: 0.11.0(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) + version: 0.11.0(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3)) vue-tsc: specifier: 2.1.6 version: 2.1.6(typescript@5.9.3) @@ -2917,12 +2554,6 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.15.18': - resolution: {integrity: sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - '@esbuild/android-arm@0.17.19': resolution: {integrity: sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==} engines: {node: '>=12'} @@ -3085,12 +2716,6 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.15.18': - resolution: {integrity: sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - '@esbuild/linux-loong64@0.17.19': resolution: {integrity: sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==} engines: {node: '>=12'} @@ -4670,22 +4295,6 @@ packages: engines: {node: ^14.18.0 || >=16.10.0, npm: '>=5.10.0'} hasBin: true - '@oozcitak/dom@2.0.2': - resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==} - engines: {node: '>=20.0'} - - '@oozcitak/infra@2.0.2': - resolution: {integrity: sha512-2g+E7hoE2dgCz/APPOEK5s3rMhJvNxSMBrP+U+j1OWsIbtSpWxxlUjq1lU8RIsFJNYv7NMlnVsCuHcUzJW+8vA==} - engines: {node: '>=20.0'} - - '@oozcitak/url@3.0.0': - resolution: {integrity: sha512-ZKfET8Ak1wsLAiLWNfFkZc/BraDccuTJKR6svTYc7sVjbR+Iu0vtXdiDMY4o6jaFl5TW2TlS7jbLl4VovtAJWQ==} - engines: {node: '>=20.0'} - - '@oozcitak/util@10.0.0': - resolution: {integrity: sha512-hAX0pT/73190NLqBPPWSdBVGtbY6VOhWYK3qqHqtXQ1gK7kS2yz4+ivsN07hpJ6I3aeMtKP6J6npsEKOAzuTLA==} - engines: {node: '>=20.0'} - '@paralleldrive/cuid2@2.3.1': resolution: {integrity: sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw==} @@ -5037,19 +4646,6 @@ packages: rollup: optional: true - '@rollup/plugin-typescript@11.1.6': - resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.14.0||^3.0.0||^4.0.0 - tslib: '*' - typescript: '>=3.7.0' - peerDependenciesMeta: - rollup: - optional: true - tslib: - optional: true - '@rollup/plugin-typescript@12.1.4': resolution: {integrity: sha512-s5Hx+EtN60LMlDBvl5f04bEiFZmAepk27Q+mr85L/00zPDn1jtzlTV6FWn81MaIwqfWzKxmOJrBWHU6vtQyedQ==} engines: {node: '>=14.0.0'} @@ -5063,19 +4659,6 @@ packages: tslib: optional: true - '@rollup/plugin-typescript@12.3.0': - resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.14.0||^3.0.0||^4.0.0 - tslib: '*' - typescript: '>=3.7.0' - peerDependenciesMeta: - rollup: - optional: true - tslib: - optional: true - '@rollup/pluginutils@3.1.0': resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} engines: {node: '>= 8.0.0'} @@ -5415,113 +4998,24 @@ packages: '@surma/rollup-plugin-off-main-thread@2.2.3': resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} - '@sveltejs/vite-plugin-svelte@1.4.0': - resolution: {integrity: sha512-6QupI/jemMfK+yI2pMtJcu5iO2gtgTfcBdGwMZZt+lgbFELhszbDl6Qjh000HgAV8+XUA+8EY8DusOFk8WhOIg==} - engines: {node: ^14.18.0 || >= 16} - peerDependencies: - svelte: ^3.44.0 - vite: ^3.0.0 - '@tauri-apps/api@2.1.1': resolution: {integrity: sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A==} '@tauri-apps/api@2.9.1': resolution: {integrity: sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw==} - '@tauri-apps/cli-darwin-arm64@2.9.3': - resolution: {integrity: sha512-W8FQXZXQmQ0Fmj9UJXNrm2mLdIaLLriKVY7o/FzmizyIKTPIvHjfZALTNybbpTQRbJvKoGHLrW1DNzAWVDWJYg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@tauri-apps/cli-darwin-x64@2.9.3': - resolution: {integrity: sha512-zDwu40rlshijt3TU6aRvzPUyVpapsx1sNfOlreDMTaMelQLHl6YoQzSRpLHYwrHrhimxyX2uDqnKIiuGel0Lhg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@tauri-apps/cli-linux-arm-gnueabihf@2.9.3': - resolution: {integrity: sha512-+Oc2OfcTRwYtW93VJqd/HOk77buORwC9IToj/qsEvM7bTMq6Kda4alpZprzwrCHYANSw+zD8PgjJdljTpe4p+g==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@tauri-apps/cli-linux-arm64-gnu@2.9.3': - resolution: {integrity: sha512-59GqU/J1n9wFyAtleoQOaU0oVIo+kwQynEw4meFDoKRXszKGor6lTsbsS3r0QKLSPbc0o/yYGJhqqCtkYjb/eg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@tauri-apps/cli-linux-arm64-musl@2.9.3': - resolution: {integrity: sha512-fzvG+jEn5/iYGNH6Z2IRMheYFC4pJdXa19BR9fFm6Bdn2cuajRLDKdUcEME/DCtwqclphXtFZTrT4oezY5vI/A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@tauri-apps/cli-linux-riscv64-gnu@2.9.3': - resolution: {integrity: sha512-qV8DZXI/fZwawk6T3Th1g6smiNC2KeQTk7XFgKvqZ6btC01z3UTsQmNGvI602zwm3Ld1TBZb4+rEWu2QmQimmw==} - engines: {node: '>= 10'} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@tauri-apps/cli-linux-x64-gnu@2.9.3': - resolution: {integrity: sha512-tquyEONCNRfqEBWEe4eAHnxFN5yY5lFkCuD4w79XLIovUxVftQ684+xLp7zkhntkt4y20SMj2AgJa/+MOlx4Kg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@tauri-apps/cli-linux-x64-musl@2.9.3': - resolution: {integrity: sha512-v2cBIB/6ji8DL+aiL5QUykU3ZO8OoJGyx50/qv2HQVzkf85KdaYSis3D/oVRemN/pcDz+vyCnnL3XnzFnDl4JQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@tauri-apps/cli-win32-arm64-msvc@2.9.3': - resolution: {integrity: sha512-ZGvBy7nvrHPbE0HeKp/ioaiw8bNgAHxWnb7JRZ4/G0A+oFj0SeSFxl9k5uU6FKnM7bHM23Gd1oeaDex9g5Fceg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@tauri-apps/cli-win32-ia32-msvc@2.9.3': - resolution: {integrity: sha512-UsgIwOnpCoY9NK9/65QiwgmWVIE80LE7SwRYVblGtmlY9RYfsYvpbItwsovA/AcHMTiO+OCvS/q9yLeqS3m6Sg==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@tauri-apps/cli-win32-x64-msvc@2.9.3': - resolution: {integrity: sha512-fmw7NrrHE5m49idCvJAx9T9bsupjdJ0a3p3DPCNCZRGANU6R1tA1L+KTlVuUtdAldX2NqU/9UPo2SCslYKgJHQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@tauri-apps/cli@2.9.3': - resolution: {integrity: sha512-BQ7iLUXTQcyG1PpzLWeVSmBCedYDpnA/6Cm/kRFGtqjTf/eVUlyYO5S2ee07tLum3nWwDBWTGFZeruO8yEukfA==} - engines: {node: '>= 10'} - hasBin: true - '@tauri-apps/plugin-dialog@2.0.1': resolution: {integrity: sha512-fnUrNr6EfvTqdls/ufusU7h6UbNFzLKvHk/zTuOiBq01R3dTODqwctZlzakdbfSp/7pNwTKvgKTAgl/NAP/Z0Q==} '@tauri-apps/plugin-fs@2.0.2': resolution: {integrity: sha512-4YZaX2j7ta81M5/DL8aN10kTnpUkEpkPo1FTYPT8Dd0ImHe3azM8i8MrtjrDGoyBYLPO3zFv7df/mSCYF8oA0Q==} - '@tauri-apps/plugin-process@2.2.0': - resolution: {integrity: sha512-uypN2Crmyop9z+KRJr3zl71OyVFgTuvHFjsJ0UxxQ/J5212jVa5w4nPEYjIewcn8bUEXacRebwE6F7owgrbhSw==} - '@tauri-apps/plugin-shell@2.3.3': resolution: {integrity: sha512-Xod+pRcFxmOWFWEnqH5yZcA7qwAMuaaDkMR1Sply+F8VfBj++CGnj2xf5UoialmjZ2Cvd8qrvSCbU+7GgNVsKQ==} '@tauri-apps/plugin-store@2.4.1': resolution: {integrity: sha512-ckGSEzZ5Ii4Hf2D5x25Oqnm2Zf9MfDWAzR+volY0z/OOBz6aucPKEY0F649JvQ0Vupku6UJo7ugpGRDOFOunkA==} - '@tauri-apps/plugin-updater@2.9.0': - resolution: {integrity: sha512-j++sgY8XpeDvzImTrzWA08OqqGqgkNyxczLD7FjNJJx/uXxMZFz5nDcfkyoI/rCjYuj2101Tci/r/HFmOmoxCg==} - '@tokenizer/inflate@0.4.1': resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} engines: {node: '>=18'} @@ -5711,9 +5205,6 @@ packages: '@types/paho-mqtt@1.0.10': resolution: {integrity: sha512-xOEii1m7jw7mIKjufDkolpz7VlyqptUmm/YFPtLJCybrPCuLhN+WYgNpulQ/CXo7wtEW7x4uGon2v89+6g/pcA==} - '@types/papaparse@5.5.2': - resolution: {integrity: sha512-gFnFp/JMzLHCwRf7tQHrNnfhN4eYBVYYI897CGX4MY1tzY9l2aLkVyx2IlKZ/SAqDbB3I1AOZW5gTMGGsqWliA==} - '@types/passport-github2@1.2.9': resolution: {integrity: sha512-/nMfiPK2E6GKttwBzwj0Wjaot8eHrM57hnWxu52o6becr5/kXlH/4yE2v2rh234WGvSgEEzIII02Nc5oC5xEHA==} @@ -5992,6 +5483,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@unhead/vue@2.1.12': resolution: {integrity: sha512-zEWqg0nZM8acpuTZE40wkeUl8AhIe0tU0OkilVi1D4fmVjACrwoh5HP6aNqJ8kUnKsoy6D+R3Vi/O+fmdNGO7g==} @@ -6250,14 +5742,6 @@ packages: typescript: optional: true - '@vue/language-core@2.2.0': - resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - '@vue/reactivity@3.5.31': resolution: {integrity: sha512-DtKXxk9E/KuVvt8VxWu+6Luc9I9ETNcqR1T1oW1gf02nXaZ1kuAx58oVu7uX9XxJR0iJCro6fqBLw9oSBELo5g==} @@ -6508,9 +5992,6 @@ packages: resolution: {integrity: sha512-XppPf2S42nO2WhvKzlwzlfcApcXHzjlod30pKmcWjRgLOtqoe5DMuqdiYoM6AgyXksc6A6pV4v1L/WW217e57w==} engines: {node: '>=0.8.0'} - alien-signals@0.4.14: - resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} - ansi-align@3.0.1: resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} @@ -6564,6 +6045,7 @@ packages: apiconnect-wsdl@2.0.36: resolution: {integrity: sha512-jHXC6y/duZ+zzn756/znpfDeVM0hprt2Yk/4QfiIhzNG4YmJXt7NSCup4DFRCitBZVK85lM6UYRaa36fSWs3JQ==} engines: {node: '>=18.7.0 <21.0.0'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. append-field@1.0.0: resolution: {integrity: sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==} @@ -6658,13 +6140,6 @@ packages: aws4fetch@1.0.20: resolution: {integrity: sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==} - axios-cookiejar-support@6.0.5: - resolution: {integrity: sha512-ldPOQCJWB0ipugkTNVB8QRl/5L2UgfmVNVQtS9en1JQJ1wW588PqAmymnwmmgc12HLDzDtsJ28xE2ppj4rD4ng==} - engines: {node: '>=20.0.0'} - peerDependencies: - axios: '>=0.20.0' - tough-cookie: '>=4.0.0' - axios@1.15.2: resolution: {integrity: sha512-wLrXxPtcrPTsNlJmKjkPnNPK2Ihe0hn0wGSaTEiHRPxwjvJwT3hKmXF4dpqxmPO9SoNb2FsYXj/xEo0gHN+D5A==} @@ -6949,10 +6424,6 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - change-case-all@1.0.15: resolution: {integrity: sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ==} @@ -7820,131 +7291,6 @@ packages: es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} - esbuild-android-64@0.15.18: - resolution: {integrity: sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - esbuild-android-arm64@0.15.18: - resolution: {integrity: sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - esbuild-darwin-64@0.15.18: - resolution: {integrity: sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - esbuild-darwin-arm64@0.15.18: - resolution: {integrity: sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - esbuild-freebsd-64@0.15.18: - resolution: {integrity: sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - esbuild-freebsd-arm64@0.15.18: - resolution: {integrity: sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - esbuild-linux-32@0.15.18: - resolution: {integrity: sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - esbuild-linux-64@0.15.18: - resolution: {integrity: sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - esbuild-linux-arm64@0.15.18: - resolution: {integrity: sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - esbuild-linux-arm@0.15.18: - resolution: {integrity: sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - esbuild-linux-mips64le@0.15.18: - resolution: {integrity: sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - esbuild-linux-ppc64le@0.15.18: - resolution: {integrity: sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - esbuild-linux-riscv64@0.15.18: - resolution: {integrity: sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - esbuild-linux-s390x@0.15.18: - resolution: {integrity: sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - esbuild-netbsd-64@0.15.18: - resolution: {integrity: sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - esbuild-openbsd-64@0.15.18: - resolution: {integrity: sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - esbuild-sunos-64@0.15.18: - resolution: {integrity: sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - esbuild-windows-32@0.15.18: - resolution: {integrity: sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - esbuild-windows-64@0.15.18: - resolution: {integrity: sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - esbuild-windows-arm64@0.15.18: - resolution: {integrity: sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - esbuild@0.15.18: - resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==} - engines: {node: '>=12'} - hasBin: true - esbuild@0.17.19: resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} engines: {node: '>=12'} @@ -8747,16 +8093,6 @@ packages: htmlparser2@9.1.0: resolution: {integrity: sha512-5zfg6mHUoaer/97TxnGpxmbR7zJtPwIYFMZ/H5ucTlPZhKvtum05yiPK3Mgai3a0DyVxv7qYqoweaEd2nrYQzQ==} - http-cookie-agent@7.0.3: - resolution: {integrity: sha512-EeZo7CGhfqPW6R006rJa4QtZZUpBygDa2HZH3DJqsTzTjyRE6foDBVQIv/pjVsxHC8z2GIdbB1Hvn9SRorP3WQ==} - engines: {node: '>=20.0.0'} - peerDependencies: - tough-cookie: ^4.0.0 || ^5.0.0 || ^6.0.0 - undici: ^7.0.0 - peerDependenciesMeta: - undici: - optional: true - http-errors@2.0.1: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} @@ -9473,10 +8809,6 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - leac@0.6.0: resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} @@ -10302,9 +9634,6 @@ packages: pako@1.0.11: resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} - papaparse@5.5.3: - resolution: {integrity: sha512-5QvjGxYVjxO59MGU2lHVYpRWBBtKHnlIAcSe1uNFCkkptUh63NFRj0FJQm7nR67puEruUci/ZkjmEFrjCAyP4A==} - param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} @@ -11831,12 +11160,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svelte-hmr@0.15.3: - resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==} - engines: {node: ^12.20 || ^14.13.1 || >= 16} - peerDependencies: - svelte: ^3.19.0 || ^4.0.0 - svelte@3.59.2: resolution: {integrity: sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==} engines: {node: '>= 8'} @@ -12218,11 +11541,6 @@ packages: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.0.0' - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} - engines: {node: '>=14.17'} - hasBin: true - typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -12439,10 +11757,12 @@ packages: uuid@8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true uuid@9.0.1: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). hasBin: true v8-compile-cache-lib@3.0.1: @@ -12624,31 +11944,6 @@ packages: vue: 3.5.33 vue-router: ^4.0.11 - vite@3.2.11: - resolution: {integrity: sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==} - engines: {node: ^14.18.0 || >=16.0.0} - hasBin: true - peerDependencies: - '@types/node': '>= 14' - less: '*' - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - vite@7.3.2: resolution: {integrity: sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==} engines: {node: ^20.19.0 || >=22.12.0} @@ -12689,14 +11984,6 @@ packages: yaml: optional: true - vitefu@0.2.5: - resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - vite: - optional: true - vitest@4.1.5: resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} @@ -12810,12 +12097,6 @@ packages: peerDependencies: typescript: '>=5.0.0' - vue-tsc@2.2.0: - resolution: {integrity: sha512-gtmM1sUuJ8aSb0KoAFmK9yMxb8TxjewmxqTJ1aKphD5Cbu0rULFY6+UQT51zW7SpUcenfPUuflKyVwyx9Qdnxg==} - hasBin: true - peerDependencies: - typescript: '>=5.0.0' - vue@3.5.33: resolution: {integrity: sha512-1AgChhx5w3ALgT4oK3acm2Es/7jyZhWSVUfs3rOBlGQC0rjEDkS7G4lWlJJGGNQD+BV3reCwbQrOe1mPNwKHBQ==} peerDependencies: @@ -13081,10 +12362,6 @@ packages: resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} engines: {node: '>=4.0.0'} - xmlbuilder2@4.0.3: - resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==} - engines: {node: '>=20.0'} - xmlbuilder@11.0.1: resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} engines: {node: '>=4.0'} @@ -14622,9 +13899,6 @@ snapshots: '@esbuild/android-arm64@0.27.4': optional: true - '@esbuild/android-arm@0.15.18': - optional: true - '@esbuild/android-arm@0.17.19': optional: true @@ -14706,9 +13980,6 @@ snapshots: '@esbuild/linux-ia32@0.27.4': optional: true - '@esbuild/linux-loong64@0.15.18': - optional: true - '@esbuild/linux-loong64@0.17.19': optional: true @@ -15757,30 +15028,6 @@ snapshots: - typescript - vite - '@hoppscotch/ui@0.2.5(eslint@10.2.1(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3))': - dependencies: - '@boringer-avatars/vue3': 0.2.1(vue@3.5.33(typescript@5.9.3)) - '@fontsource-variable/inter': 5.2.8 - '@fontsource-variable/material-symbols-rounded': 5.2.38 - '@fontsource-variable/roboto-mono': 5.2.8 - '@hoppscotch/vue-sonner': 1.2.3 - '@hoppscotch/vue-toasted': 0.1.0(vue@3.5.33(typescript@5.9.3)) - '@vitejs/plugin-legacy': 2.3.1(terser@5.46.1)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) - '@vueuse/core': 8.9.4(vue@3.5.33(typescript@5.9.3)) - fp-ts: 2.16.11 - lodash-es: 4.18.1 - path: 0.12.7 - vite-plugin-eslint: 1.8.1(eslint@10.2.1(jiti@2.6.1))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) - vue: 3.5.33(typescript@5.9.3) - vue-promise-modals: 0.1.0(typescript@5.9.3) - vuedraggable-es: 4.1.1(vue@3.5.33(typescript@5.9.3)) - transitivePeerDependencies: - - '@vue/composition-api' - - eslint - - terser - - typescript - - vite - '@hoppscotch/ui@0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.46.1)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue@3.5.33(typescript@5.9.3))': dependencies: '@boringer-avatars/vue3': 0.2.1(vue@3.5.33(typescript@5.9.3)) @@ -16169,7 +15416,7 @@ snapshots: '@intlify/shared@11.4.0': {} - '@intlify/unplugin-vue-i18n@11.1.2(@vue/compiler-dom@3.5.33)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3))': + '@intlify/unplugin-vue-i18n@11.1.2(@vue/compiler-dom@3.5.33)(eslint@10.2.1(jiti@2.6.1))(rollup@4.60.2)(typescript@5.9.3)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3)))(vue@3.5.33(typescript@5.9.3))': dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) '@intlify/bundle-utils': 11.1.2(vue-i18n@11.4.0(vue@3.5.33(typescript@5.9.3))) @@ -16185,7 +15432,7 @@ snapshots: unplugin: 2.3.11 vue: 3.5.33(typescript@5.9.3) optionalDependencies: - vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) vue-i18n: 11.4.0(vue@3.5.33(typescript@5.9.3)) transitivePeerDependencies: - '@vue/compiler-dom' @@ -16875,23 +16122,6 @@ snapshots: dependencies: consola: 3.4.2 - '@oozcitak/dom@2.0.2': - dependencies: - '@oozcitak/infra': 2.0.2 - '@oozcitak/url': 3.0.0 - '@oozcitak/util': 10.0.0 - - '@oozcitak/infra@2.0.2': - dependencies: - '@oozcitak/util': 10.0.0 - - '@oozcitak/url@3.0.0': - dependencies: - '@oozcitak/infra': 2.0.2 - '@oozcitak/util': 10.0.0 - - '@oozcitak/util@10.0.0': {} - '@paralleldrive/cuid2@2.3.1': dependencies: '@noble/hashes': 1.8.0 @@ -17226,15 +16456,6 @@ snapshots: optionalDependencies: rollup: 2.80.0 - '@rollup/plugin-typescript@11.1.6(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.2)': - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) - resolve: 1.22.11 - typescript: 5.9.2 - optionalDependencies: - rollup: 4.59.0 - tslib: 2.8.1 - '@rollup/plugin-typescript@12.1.4(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.3)': dependencies: '@rollup/pluginutils': 5.3.0(rollup@4.59.0) @@ -17244,15 +16465,6 @@ snapshots: rollup: 4.59.0 tslib: 2.8.1 - '@rollup/plugin-typescript@12.3.0(rollup@4.59.0)(tslib@2.8.1)(typescript@5.9.3)': - dependencies: - '@rollup/pluginutils': 5.3.0(rollup@4.59.0) - resolve: 1.22.11 - typescript: 5.9.3 - optionalDependencies: - rollup: 4.59.0 - tslib: 2.8.1 - '@rollup/pluginutils@3.1.0(rollup@2.80.0)': dependencies: '@types/estree': 0.0.39 @@ -17485,70 +16697,10 @@ snapshots: magic-string: 0.25.9 string.prototype.matchall: 4.0.12 - '@sveltejs/vite-plugin-svelte@1.4.0(svelte@3.59.2)(vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1))': - dependencies: - debug: 4.4.3(supports-color@8.1.1) - deepmerge: 4.3.1 - kleur: 4.1.5 - magic-string: 0.26.7 - svelte: 3.59.2 - svelte-hmr: 0.15.3(svelte@3.59.2) - vite: 3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1) - vitefu: 0.2.5(vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1)) - transitivePeerDependencies: - - supports-color - '@tauri-apps/api@2.1.1': {} '@tauri-apps/api@2.9.1': {} - '@tauri-apps/cli-darwin-arm64@2.9.3': - optional: true - - '@tauri-apps/cli-darwin-x64@2.9.3': - optional: true - - '@tauri-apps/cli-linux-arm-gnueabihf@2.9.3': - optional: true - - '@tauri-apps/cli-linux-arm64-gnu@2.9.3': - optional: true - - '@tauri-apps/cli-linux-arm64-musl@2.9.3': - optional: true - - '@tauri-apps/cli-linux-riscv64-gnu@2.9.3': - optional: true - - '@tauri-apps/cli-linux-x64-gnu@2.9.3': - optional: true - - '@tauri-apps/cli-linux-x64-musl@2.9.3': - optional: true - - '@tauri-apps/cli-win32-arm64-msvc@2.9.3': - optional: true - - '@tauri-apps/cli-win32-ia32-msvc@2.9.3': - optional: true - - '@tauri-apps/cli-win32-x64-msvc@2.9.3': - optional: true - - '@tauri-apps/cli@2.9.3': - optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.9.3 - '@tauri-apps/cli-darwin-x64': 2.9.3 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.9.3 - '@tauri-apps/cli-linux-arm64-gnu': 2.9.3 - '@tauri-apps/cli-linux-arm64-musl': 2.9.3 - '@tauri-apps/cli-linux-riscv64-gnu': 2.9.3 - '@tauri-apps/cli-linux-x64-gnu': 2.9.3 - '@tauri-apps/cli-linux-x64-musl': 2.9.3 - '@tauri-apps/cli-win32-arm64-msvc': 2.9.3 - '@tauri-apps/cli-win32-ia32-msvc': 2.9.3 - '@tauri-apps/cli-win32-x64-msvc': 2.9.3 - '@tauri-apps/plugin-dialog@2.0.1': dependencies: '@tauri-apps/api': 2.9.1 @@ -17557,10 +16709,6 @@ snapshots: dependencies: '@tauri-apps/api': 2.9.1 - '@tauri-apps/plugin-process@2.2.0': - dependencies: - '@tauri-apps/api': 2.9.1 - '@tauri-apps/plugin-shell@2.3.3': dependencies: '@tauri-apps/api': 2.9.1 @@ -17569,10 +16717,6 @@ snapshots: dependencies: '@tauri-apps/api': 2.9.1 - '@tauri-apps/plugin-updater@2.9.0': - dependencies: - '@tauri-apps/api': 2.9.1 - '@tokenizer/inflate@0.4.1': dependencies: debug: 4.4.3(supports-color@8.1.1) @@ -17787,10 +16931,6 @@ snapshots: '@types/paho-mqtt@1.0.10': {} - '@types/papaparse@5.5.2': - dependencies: - '@types/node': 25.6.0 - '@types/passport-github2@1.2.9': dependencies: '@types/express': 5.0.6 @@ -18361,14 +17501,6 @@ snapshots: optionalDependencies: vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - '@vitest/mocker@4.1.5(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))': - dependencies: - '@vitest/spy': 4.1.5 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - '@vitest/pretty-format@4.1.5': dependencies: tinyrainbow: 3.1.0 @@ -18507,19 +17639,6 @@ snapshots: optionalDependencies: typescript: 5.9.3 - '@vue/language-core@2.2.0(typescript@5.9.3)': - dependencies: - '@volar/language-core': 2.4.28 - '@vue/compiler-dom': 3.5.31 - '@vue/compiler-vue2': 2.7.16 - '@vue/shared': 3.5.31 - alien-signals: 0.4.14 - minimatch: 9.0.9 - muggle-string: 0.4.1 - path-browserify: 1.0.1 - optionalDependencies: - typescript: 5.9.3 - '@vue/reactivity@3.5.31': dependencies: '@vue/shared': 3.5.31 @@ -18804,8 +17923,6 @@ snapshots: estraverse: 1.9.3 optional: true - alien-signals@0.4.14: {} - ansi-align@3.0.1: dependencies: string-width: 4.2.3 @@ -18947,14 +18064,6 @@ snapshots: aws4fetch@1.0.20: {} - axios-cookiejar-support@6.0.5(axios@1.15.2)(tough-cookie@6.0.1): - dependencies: - axios: 1.15.2 - http-cookie-agent: 7.0.3(tough-cookie@6.0.1) - tough-cookie: 6.0.1 - transitivePeerDependencies: - - undici - axios@1.15.2: dependencies: follow-redirects: 1.16.0 @@ -19331,8 +18440,6 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - chalk@5.6.2: {} - change-case-all@1.0.15: dependencies: change-case: 4.1.2 @@ -20325,91 +19432,6 @@ snapshots: es6-promise@3.3.1: {} - esbuild-android-64@0.15.18: - optional: true - - esbuild-android-arm64@0.15.18: - optional: true - - esbuild-darwin-64@0.15.18: - optional: true - - esbuild-darwin-arm64@0.15.18: - optional: true - - esbuild-freebsd-64@0.15.18: - optional: true - - esbuild-freebsd-arm64@0.15.18: - optional: true - - esbuild-linux-32@0.15.18: - optional: true - - esbuild-linux-64@0.15.18: - optional: true - - esbuild-linux-arm64@0.15.18: - optional: true - - esbuild-linux-arm@0.15.18: - optional: true - - esbuild-linux-mips64le@0.15.18: - optional: true - - esbuild-linux-ppc64le@0.15.18: - optional: true - - esbuild-linux-riscv64@0.15.18: - optional: true - - esbuild-linux-s390x@0.15.18: - optional: true - - esbuild-netbsd-64@0.15.18: - optional: true - - esbuild-openbsd-64@0.15.18: - optional: true - - esbuild-sunos-64@0.15.18: - optional: true - - esbuild-windows-32@0.15.18: - optional: true - - esbuild-windows-64@0.15.18: - optional: true - - esbuild-windows-arm64@0.15.18: - optional: true - - esbuild@0.15.18: - optionalDependencies: - '@esbuild/android-arm': 0.15.18 - '@esbuild/linux-loong64': 0.15.18 - esbuild-android-64: 0.15.18 - esbuild-android-arm64: 0.15.18 - esbuild-darwin-64: 0.15.18 - esbuild-darwin-arm64: 0.15.18 - esbuild-freebsd-64: 0.15.18 - esbuild-freebsd-arm64: 0.15.18 - esbuild-linux-32: 0.15.18 - esbuild-linux-64: 0.15.18 - esbuild-linux-arm: 0.15.18 - esbuild-linux-arm64: 0.15.18 - esbuild-linux-mips64le: 0.15.18 - esbuild-linux-ppc64le: 0.15.18 - esbuild-linux-riscv64: 0.15.18 - esbuild-linux-s390x: 0.15.18 - esbuild-netbsd-64: 0.15.18 - esbuild-openbsd-64: 0.15.18 - esbuild-sunos-64: 0.15.18 - esbuild-windows-32: 0.15.18 - esbuild-windows-64: 0.15.18 - esbuild-windows-arm64: 0.15.18 - esbuild@0.17.19: optionalDependencies: '@esbuild/android-arm': 0.17.19 @@ -21479,11 +20501,6 @@ snapshots: entities: 4.5.0 optional: true - http-cookie-agent@7.0.3(tough-cookie@6.0.1): - dependencies: - agent-base: 7.1.4 - tough-cookie: 6.0.1 - http-errors@2.0.1: dependencies: depd: 2.0.0 @@ -22439,8 +21456,6 @@ snapshots: dependencies: json-buffer: 3.0.1 - kleur@4.1.5: {} - leac@0.6.0: optional: true @@ -23682,8 +22697,6 @@ snapshots: pako@1.0.11: {} - papaparse@5.5.3: {} - param-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -25374,11 +24387,8 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svelte-hmr@0.15.3(svelte@3.59.2): - dependencies: - svelte: 3.59.2 - - svelte@3.59.2: {} + svelte@3.59.2: + optional: true svgo@4.0.1: dependencies: @@ -25677,7 +24687,7 @@ snapshots: ts-log@2.2.7: {} - ts-node-dev@2.0.0(@types/node@25.6.0)(typescript@5.9.3): + ts-node-dev@2.0.0(@types/node@24.10.1)(typescript@5.9.3): dependencies: chokidar: 3.6.0 dynamic-dedupe: 0.3.0 @@ -25687,7 +24697,7 @@ snapshots: rimraf: 2.7.1 source-map-support: 0.5.21 tree-kill: 1.2.2 - ts-node: 10.9.2(@types/node@25.6.0)(typescript@5.9.3) + ts-node: 10.9.2(@types/node@24.10.1)(typescript@5.9.3) tsconfig: 7.0.0 typescript: 5.9.3 transitivePeerDependencies: @@ -25712,7 +24722,6 @@ snapshots: typescript: 5.9.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - optional: true ts-node@10.9.2(@types/node@25.6.0)(typescript@5.9.3): dependencies: @@ -25855,8 +24864,6 @@ snapshots: transitivePeerDependencies: - supports-color - typescript@5.9.2: {} - typescript@5.9.3: {} ua-parser-js@1.0.41: {} @@ -26151,14 +25158,6 @@ snapshots: rollup: 2.80.0 vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-eslint@1.8.1(eslint@10.2.1(jiti@2.6.1))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): - dependencies: - '@rollup/pluginutils': 4.2.1 - '@types/eslint': 8.56.12 - eslint: 10.2.1(jiti@2.6.1) - rollup: 2.80.0 - vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - vite-plugin-eslint@1.8.1(eslint@9.39.2(jiti@2.6.1))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: '@rollup/pluginutils': 4.2.1 @@ -26213,7 +25212,7 @@ snapshots: sitemap: 8.0.3 xml-formatter: 3.7.0 - vite-plugin-pages@0.33.2(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))): + vite-plugin-pages@0.33.2(@vue/compiler-sfc@3.5.33)(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3))(vue-router@4.6.4(vue@3.5.33(typescript@5.9.3))): dependencies: '@types/debug': 4.1.13 debug: 4.4.3(supports-color@8.1.1) @@ -26224,7 +25223,7 @@ snapshots: micromatch: 4.0.8 picocolors: 1.1.1 tinyglobby: 0.2.15 - vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) + vite: 7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) yaml: 2.8.3 optionalDependencies: '@vue/compiler-sfc': 3.5.33 @@ -26320,18 +25319,6 @@ snapshots: transitivePeerDependencies: - supports-color - vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1): - dependencies: - esbuild: 0.15.18 - postcss: 8.5.10 - resolve: 1.22.11 - rollup: 2.80.0 - optionalDependencies: - '@types/node': 25.6.0 - fsevents: 2.3.3 - sass: 1.99.0 - terser: 5.46.1 - vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3): dependencies: esbuild: 0.27.4 @@ -26380,10 +25367,6 @@ snapshots: terser: 5.46.1 yaml: 2.8.3 - vitefu@0.2.5(vite@3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1)): - optionalDependencies: - vite: 3.2.11(@types/node@25.6.0)(sass@1.99.0)(terser@5.46.1) - vitest@4.1.5(@types/node@24.10.1)(jsdom@27.4.0(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@24.10.1)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): dependencies: '@vitest/expect': 4.1.5 @@ -26412,34 +25395,6 @@ snapshots: transitivePeerDependencies: - msw - vitest@4.1.5(@types/node@25.6.0)(jsdom@27.4.0(@noble/hashes@2.2.0))(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)): - dependencies: - '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(vite@7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3)) - '@vitest/pretty-format': 4.1.5 - '@vitest/runner': 4.1.5 - '@vitest/snapshot': 4.1.5 - '@vitest/spy': 4.1.5 - '@vitest/utils': 4.1.5 - es-module-lexer: 2.0.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.0.0 - tinybench: 2.9.0 - tinyexec: 1.0.4 - tinyglobby: 0.2.15 - tinyrainbow: 3.1.0 - vite: 7.3.2(@types/node@25.6.0)(jiti@2.6.1)(sass@1.99.0)(terser@5.46.1)(yaml@2.8.3) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 25.6.0 - jsdom: 27.4.0(@noble/hashes@2.2.0) - transitivePeerDependencies: - - msw - void-elements@3.1.0: optional: true @@ -26515,12 +25470,6 @@ snapshots: semver: 7.7.4 typescript: 5.9.3 - vue-tsc@2.2.0(typescript@5.9.3): - dependencies: - '@volar/typescript': 2.4.28 - '@vue/language-core': 2.2.0(typescript@5.9.3) - typescript: 5.9.3 - vue@3.5.33(typescript@5.9.3): dependencies: '@vue/compiler-dom': 3.5.33 @@ -26884,13 +25833,6 @@ snapshots: sax: 1.6.0 xmlbuilder: 11.0.1 - xmlbuilder2@4.0.3: - dependencies: - '@oozcitak/dom': 2.0.2 - '@oozcitak/infra': 2.0.2 - '@oozcitak/util': 10.0.0 - js-yaml: 4.1.1 - xmlbuilder@11.0.1: {} xmlchars@2.2.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index eccc335f..c5cba011 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,9 @@ packages: - - 'packages/**' \ No newline at end of file + - 'packages/codemirror-lang-graphql' + - 'packages/hoppscotch-backend' + - 'packages/hoppscotch-common' + - 'packages/hoppscotch-data' + - 'packages/hoppscotch-js-sandbox' + - 'packages/hoppscotch-kernel' + - 'packages/hoppscotch-selfhost-web' + - 'packages/hoppscotch-sh-admin' diff --git a/tailwind.config.ts b/tailwind.config.ts index 916a6217..982f22e5 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -4,7 +4,7 @@ export default { content: [ "packages/hoppscotch-common/src/**/*.{vue,html}", "packages/hoppscotch-sh-admin/src/**/*.{vue,html}", - "packages/hoppscotch-desktop/src/**/*.{vue,html}", + "packages/hoppscotch-selfhost-web/src/**/*.{vue,html}", ], presets: [preset], }