feat(desktop): host mapping infra for cloud orgs (#5795)

This commit is contained in:
Shreyas 2026-01-23 15:07:44 +05:30 committed by GitHub
parent 65046526f0
commit c64928885f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 1156 additions and 488 deletions

View file

@ -40,7 +40,7 @@
"@hoppscotch/httpsnippet": "3.0.9",
"@hoppscotch/js-sandbox": "workspace:^",
"@hoppscotch/kernel": "workspace:^",
"@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload#52744a8f35bf81b039410522efd4168bd06d4f35",
"@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload#168ff9533258a56de184fb69ad32f8a7f61bae0d",
"@hoppscotch/ui": "0.2.5",
"@hoppscotch/vue-toasted": "0.1.0",
"@lezer/highlight": "1.2.1",

View file

@ -46,6 +46,13 @@ export type InstancePlatformDef = {
*/
customInstanceSwitcherComponent?: Component
/**
* Component to render additional entries before the instances list.
* Desktop injects the "Hoppscotch Cloud" entry here, which resolves
* to the user's last-used org.
*/
additionalEntriesComponent?: Component
/**
* Returns an observable stream of the current connection state
*/

View file

@ -27,7 +27,7 @@
"@fontsource-variable/roboto-mono": "5.2.8",
"@hoppscotch/common": "workspace:^",
"@hoppscotch/kernel": "workspace:^",
"@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload#52744a8f35bf81b039410522efd4168bd06d4f35",
"@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload#168ff9533258a56de184fb69ad32f8a7f61bae0d",
"@hoppscotch/ui": "0.2.5",
"@tauri-apps/api": "2.1.1",
"@tauri-apps/plugin-fs": "2.0.2",

View file

@ -39,10 +39,10 @@
"flake-compat": {
"flake": false,
"locked": {
"lastModified": 1733328505,
"lastModified": 1765121682,
"owner": "edolstra",
"repo": "flake-compat",
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
"rev": "65f23138d8d09a92e30f1e5c87611b23ef451bf3",
"type": "github"
},
"original": {
@ -51,18 +51,39 @@
"type": "github"
}
},
"gitignore": {
"git-hooks": {
"inputs": {
"flake-compat": "flake-compat",
"gitignore": "gitignore",
"nixpkgs": [
"pre-commit-hooks",
"nixpkgs"
]
},
"locked": {
"lastModified": 1709087332,
"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": "637db329424fd7e46cf4185293b9cc8c88c95394",
"rev": "cb5e3fdca1de58ccbc3ef53de65bd372b48f567c",
"type": "github"
},
"original": {
@ -86,49 +107,15 @@
"type": "github"
}
},
"nixpkgs-stable": {
"locked": {
"lastModified": 1733384649,
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "190c31a89e5eec80dd6604d7f9e5af3802a58a13",
"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": 1733318908,
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"rev": "6f4e2a2112050951a314d2733a994fbab94864c6",
"type": "github"
},
"original": {
"owner": "cachix",
"repo": "pre-commit-hooks.nix",
"type": "github"
}
},
"root": {
"inputs": {
"devenv": "devenv",
"fenix": "fenix",
"git-hooks": "git-hooks",
"nixpkgs": "nixpkgs",
"pre-commit-hooks": "pre-commit-hooks"
"pre-commit-hooks": [
"git-hooks"
]
}
},
"rust-analyzer-src": {

View file

@ -15,6 +15,27 @@ export interface WindowOptions {
}
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;
}

View file

@ -1 +1 @@
{"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,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,MAAM,CAAC,EAAE,aAAa,CAAA;CACvB;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"}
{"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"}

View file

@ -1,22 +1,19 @@
import { invoke } from "@tauri-apps/api/core"
import { invoke } from '@tauri-apps/api/core';
async function download(options) {
return await invoke("plugin:appload|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 })
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 })
return await invoke('plugin:appload|remove', { options });
}
async function clear() {
return await invoke("plugin:appload|clear")
return await invoke('plugin:appload|clear');
}
export { clear, close, download, load, remove };

View file

@ -15,8 +15,8 @@
},
"devDependencies": {
"@sveltejs/vite-plugin-svelte": "^1.0.1",
"@tauri-apps/cli": "^2.0.0-alpha.17",
"svelte": "^3.49.0",
"vite": "^7.3.1"
"vite": "^3.0.2",
"@tauri-apps/cli": "^2.0.0-alpha.17"
}
}

View file

@ -1,8 +1,8 @@
import "./style.css"
import App from "./App.svelte"
import "./style.css";
import App from "./App.svelte";
const app = new App({
target: document.getElementById("app"),
})
});
export default app
export default app;

View file

@ -1,7 +1,7 @@
import { defineConfig } from "vite"
import { svelte } from "@sveltejs/vite-plugin-svelte"
import { defineConfig } from "vite";
import { svelte } from "@sveltejs/vite-plugin-svelte";
const host = process.env.TAURI_DEV_HOST
const host = process.env.TAURI_DEV_HOST;
// https://vitejs.dev/config/
export default defineConfig({
@ -15,12 +15,10 @@ export default defineConfig({
host: host || false,
port: 1420,
strictPort: true,
hmr: host
? {
protocol: "ws",
host,
port: 1421,
}
: undefined,
hmr: host ? {
protocol: 'ws',
host,
port: 1421
} : undefined,
},
})

View file

@ -1,4 +1,4 @@
import { invoke } from "@tauri-apps/api/core"
import { invoke } from '@tauri-apps/api/core'
export interface DownloadOptions {
serverUrl: string
@ -20,8 +20,29 @@ export interface WindowOptions {
export interface LoadOptions {
bundleName: string
inline?: boolean
window?: WindowOptions
/**
* 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 {
@ -47,24 +68,22 @@ export interface RemoveResponse {
bundleName: string
}
export async function download(
options: DownloadOptions
): Promise<DownloadResponse> {
return await invoke<DownloadResponse>("plugin:appload|download", { options })
export async function download(options: DownloadOptions): Promise<DownloadResponse> {
return await invoke<DownloadResponse>('plugin:appload|download', { options })
}
export async function load(options: LoadOptions): Promise<LoadResponse> {
return await invoke<LoadResponse>("plugin:appload|load", { options })
return await invoke<LoadResponse>('plugin:appload|load', { options })
}
export async function close(options: CloseOptions): Promise<CloseResponse> {
return await invoke<CloseResponse>("plugin:appload|close", { options })
return await invoke<CloseResponse>('plugin:appload|close', { options })
}
export async function remove(options: RemoveOptions): Promise<RemoveResponse> {
return await invoke<RemoveResponse>("plugin:appload|remove", { options })
return await invoke<RemoveResponse>('plugin:appload|remove', { options })
}
export async function clear(): Promise<void> {
return await invoke("plugin:appload|clear")
return await invoke('plugin:appload|clear')
}

View file

@ -22,12 +22,12 @@
"pretest": "pnpm build"
},
"dependencies": {
"@tauri-apps/api": "2.1.1"
"@tauri-apps/api": "2.9.1"
},
"devDependencies": {
"@rollup/plugin-typescript": "^12.3.0",
"rollup": "^4.55.3",
"tslib": "^2.6.2",
"rollup": "^4.54.0",
"tslib": "^2.8.1",
"typescript": "5.9.3"
}
}

View file

@ -318,16 +318,6 @@
"const": "deny-close",
"markdownDescription": "Denies the close command without any pre-configured scope."
},
{
"description": "Enables the close command without any pre-configured scope.",
"type": "string",
"const": "allow-close"
},
{
"description": "Denies the close command without any pre-configured scope.",
"type": "string",
"const": "deny-close"
},
{
"description": "Enables the download command without any pre-configured scope.",
"type": "string",

View file

@ -9,26 +9,26 @@ importers:
.:
dependencies:
'@tauri-apps/api':
specifier: 2.1.1
version: 2.1.1
specifier: 2.9.1
version: 2.9.1
devDependencies:
'@rollup/plugin-typescript':
specifier: ^11.1.6
version: 11.1.6(rollup@4.28.0)(tslib@2.8.1)(typescript@5.9.2)
specifier: ^12.3.0
version: 12.3.0(rollup@4.54.0)(tslib@2.8.1)(typescript@5.9.3)
rollup:
specifier: ^4.9.6
version: 4.28.0
specifier: ^4.54.0
version: 4.54.0
tslib:
specifier: ^2.6.2
specifier: ^2.8.1
version: 2.8.1
typescript:
specifier: 5.9.2
version: 5.9.2
specifier: 5.9.3
version: 5.9.3
packages:
'@rollup/plugin-typescript@11.1.6':
resolution: {integrity: sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==}
'@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
@ -40,8 +40,8 @@ packages:
tslib:
optional: true
'@rollup/pluginutils@5.1.3':
resolution: {integrity: sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==}
'@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
@ -49,101 +49,121 @@ packages:
rollup:
optional: true
'@rollup/rollup-android-arm-eabi@4.28.0':
resolution: {integrity: sha512-wLJuPLT6grGZsy34g4N1yRfYeouklTgPhH1gWXCYspenKYD0s3cR99ZevOGw5BexMNywkbV3UkjADisozBmpPQ==}
'@rollup/rollup-android-arm-eabi@4.54.0':
resolution: {integrity: sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==}
cpu: [arm]
os: [android]
'@rollup/rollup-android-arm64@4.28.0':
resolution: {integrity: sha512-eiNkznlo0dLmVG/6wf+Ifi/v78G4d4QxRhuUl+s8EWZpDewgk7PX3ZyECUXU0Zq/Ca+8nU8cQpNC4Xgn2gFNDA==}
'@rollup/rollup-android-arm64@4.54.0':
resolution: {integrity: sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==}
cpu: [arm64]
os: [android]
'@rollup/rollup-darwin-arm64@4.28.0':
resolution: {integrity: sha512-lmKx9yHsppblnLQZOGxdO66gT77bvdBtr/0P+TPOseowE7D9AJoBw8ZDULRasXRWf1Z86/gcOdpBrV6VDUY36Q==}
'@rollup/rollup-darwin-arm64@4.54.0':
resolution: {integrity: sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==}
cpu: [arm64]
os: [darwin]
'@rollup/rollup-darwin-x64@4.28.0':
resolution: {integrity: sha512-8hxgfReVs7k9Js1uAIhS6zq3I+wKQETInnWQtgzt8JfGx51R1N6DRVy3F4o0lQwumbErRz52YqwjfvuwRxGv1w==}
'@rollup/rollup-darwin-x64@4.54.0':
resolution: {integrity: sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==}
cpu: [x64]
os: [darwin]
'@rollup/rollup-freebsd-arm64@4.28.0':
resolution: {integrity: sha512-lA1zZB3bFx5oxu9fYud4+g1mt+lYXCoch0M0V/xhqLoGatbzVse0wlSQ1UYOWKpuSu3gyN4qEc0Dxf/DII1bhQ==}
'@rollup/rollup-freebsd-arm64@4.54.0':
resolution: {integrity: sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==}
cpu: [arm64]
os: [freebsd]
'@rollup/rollup-freebsd-x64@4.28.0':
resolution: {integrity: sha512-aI2plavbUDjCQB/sRbeUZWX9qp12GfYkYSJOrdYTL/C5D53bsE2/nBPuoiJKoWp5SN78v2Vr8ZPnB+/VbQ2pFA==}
'@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.28.0':
resolution: {integrity: sha512-WXveUPKtfqtaNvpf0iOb0M6xC64GzUX/OowbqfiCSXTdi/jLlOmH0Ba94/OkiY2yTGTwteo4/dsHRfh5bDCZ+w==}
'@rollup/rollup-linux-arm-gnueabihf@4.54.0':
resolution: {integrity: sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==}
cpu: [arm]
os: [linux]
'@rollup/rollup-linux-arm-musleabihf@4.28.0':
resolution: {integrity: sha512-yLc3O2NtOQR67lI79zsSc7lk31xjwcaocvdD1twL64PK1yNaIqCeWI9L5B4MFPAVGEVjH5k1oWSGuYX1Wutxpg==}
'@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.28.0':
resolution: {integrity: sha512-+P9G9hjEpHucHRXqesY+3X9hD2wh0iNnJXX/QhS/J5vTdG6VhNYMxJ2rJkQOxRUd17u5mbMLHM7yWGZdAASfcg==}
'@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.28.0':
resolution: {integrity: sha512-1xsm2rCKSTpKzi5/ypT5wfc+4bOGa/9yI/eaOLW0oMs7qpC542APWhl4A37AENGZ6St6GBMWhCCMM6tXgTIplw==}
'@rollup/rollup-linux-arm64-musl@4.54.0':
resolution: {integrity: sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==}
cpu: [arm64]
os: [linux]
'@rollup/rollup-linux-powerpc64le-gnu@4.28.0':
resolution: {integrity: sha512-zgWxMq8neVQeXL+ouSf6S7DoNeo6EPgi1eeqHXVKQxqPy1B2NvTbaOUWPn/7CfMKL7xvhV0/+fq/Z/J69g1WAQ==}
'@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.28.0':
resolution: {integrity: sha512-VEdVYacLniRxbRJLNtzwGt5vwS0ycYshofI7cWAfj7Vg5asqj+pt+Q6x4n+AONSZW/kVm+5nklde0qs2EUwU2g==}
'@rollup/rollup-linux-riscv64-gnu@4.54.0':
resolution: {integrity: sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==}
cpu: [riscv64]
os: [linux]
'@rollup/rollup-linux-s390x-gnu@4.28.0':
resolution: {integrity: sha512-LQlP5t2hcDJh8HV8RELD9/xlYtEzJkm/aWGsauvdO2ulfl3QYRjqrKW+mGAIWP5kdNCBheqqqYIGElSRCaXfpw==}
'@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.28.0':
resolution: {integrity: sha512-Nl4KIzteVEKE9BdAvYoTkW19pa7LR/RBrT6F1dJCV/3pbjwDcaOq+edkP0LXuJ9kflW/xOK414X78r+K84+msw==}
'@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.28.0':
resolution: {integrity: sha512-eKpJr4vBDOi4goT75MvW+0dXcNUqisK4jvibY9vDdlgLx+yekxSm55StsHbxUsRxSTt3JEQvlr3cGDkzcSP8bw==}
'@rollup/rollup-linux-x64-musl@4.54.0':
resolution: {integrity: sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==}
cpu: [x64]
os: [linux]
'@rollup/rollup-win32-arm64-msvc@4.28.0':
resolution: {integrity: sha512-Vi+WR62xWGsE/Oj+mD0FNAPY2MEox3cfyG0zLpotZdehPFXwz6lypkGs5y38Jd/NVSbOD02aVad6q6QYF7i8Bg==}
'@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.28.0':
resolution: {integrity: sha512-kN/Vpip8emMLn/eOza+4JwqDZBL6MPNpkdaEsgUtW1NYN3DZvZqSQrbKzJcTL6hd8YNmFTn7XGWMwccOcJBL0A==}
'@rollup/rollup-win32-ia32-msvc@4.54.0':
resolution: {integrity: sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==}
cpu: [ia32]
os: [win32]
'@rollup/rollup-win32-x64-msvc@4.28.0':
resolution: {integrity: sha512-Bvno2/aZT6usSa7lRDL2+hMjVAGjuqaymF1ApZm31JXzniR/hvr14jpU+/z4X6Gt5BPlzosscyJZGUvguXIqeQ==}
'@rollup/rollup-win32-x64-gnu@4.54.0':
resolution: {integrity: sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==}
cpu: [x64]
os: [win32]
'@tauri-apps/api@2.1.1':
resolution: {integrity: sha512-fzUfFFKo4lknXGJq8qrCidkUcKcH2UHhfaaCNt4GzgzGaW2iS26uFOg4tS3H4P8D6ZEeUxtiD5z0nwFF0UN30A==}
'@rollup/rollup-win32-x64-msvc@4.54.0':
resolution: {integrity: sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==}
cpu: [x64]
os: [win32]
'@types/estree@1.0.6':
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
'@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==}
@ -160,23 +180,24 @@ packages:
resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
engines: {node: '>= 0.4'}
is-core-module@2.15.1:
resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==}
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.2:
resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==}
picomatch@4.0.3:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'}
resolve@1.22.8:
resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==}
resolve@1.22.11:
resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
engines: {node: '>= 0.4'}
hasBin: true
rollup@4.28.0:
resolution: {integrity: sha512-G9GOrmgWHBma4YfCcX8PjH0qhXSdH8B4HDE2o4/jaxj93S4DPCIDoLcXz99eWMji4hB29UFCEd7B2gwGJDR9cQ==}
rollup@4.54.0:
resolution: {integrity: sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==}
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
@ -187,87 +208,99 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
typescript@5.9.2:
resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==}
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
hasBin: true
snapshots:
'@rollup/plugin-typescript@11.1.6(rollup@4.28.0)(tslib@2.8.1)(typescript@5.9.2)':
'@rollup/plugin-typescript@12.3.0(rollup@4.54.0)(tslib@2.8.1)(typescript@5.9.3)':
dependencies:
'@rollup/pluginutils': 5.1.3(rollup@4.28.0)
resolve: 1.22.8
typescript: 5.9.2
'@rollup/pluginutils': 5.3.0(rollup@4.54.0)
resolve: 1.22.11
typescript: 5.9.3
optionalDependencies:
rollup: 4.28.0
rollup: 4.54.0
tslib: 2.8.1
'@rollup/pluginutils@5.1.3(rollup@4.28.0)':
'@rollup/pluginutils@5.3.0(rollup@4.54.0)':
dependencies:
'@types/estree': 1.0.6
'@types/estree': 1.0.8
estree-walker: 2.0.2
picomatch: 4.0.2
picomatch: 4.0.3
optionalDependencies:
rollup: 4.28.0
rollup: 4.54.0
'@rollup/rollup-android-arm-eabi@4.28.0':
'@rollup/rollup-android-arm-eabi@4.54.0':
optional: true
'@rollup/rollup-android-arm64@4.28.0':
'@rollup/rollup-android-arm64@4.54.0':
optional: true
'@rollup/rollup-darwin-arm64@4.28.0':
'@rollup/rollup-darwin-arm64@4.54.0':
optional: true
'@rollup/rollup-darwin-x64@4.28.0':
'@rollup/rollup-darwin-x64@4.54.0':
optional: true
'@rollup/rollup-freebsd-arm64@4.28.0':
'@rollup/rollup-freebsd-arm64@4.54.0':
optional: true
'@rollup/rollup-freebsd-x64@4.28.0':
'@rollup/rollup-freebsd-x64@4.54.0':
optional: true
'@rollup/rollup-linux-arm-gnueabihf@4.28.0':
'@rollup/rollup-linux-arm-gnueabihf@4.54.0':
optional: true
'@rollup/rollup-linux-arm-musleabihf@4.28.0':
'@rollup/rollup-linux-arm-musleabihf@4.54.0':
optional: true
'@rollup/rollup-linux-arm64-gnu@4.28.0':
'@rollup/rollup-linux-arm64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-arm64-musl@4.28.0':
'@rollup/rollup-linux-arm64-musl@4.54.0':
optional: true
'@rollup/rollup-linux-powerpc64le-gnu@4.28.0':
'@rollup/rollup-linux-loong64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-riscv64-gnu@4.28.0':
'@rollup/rollup-linux-ppc64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-s390x-gnu@4.28.0':
'@rollup/rollup-linux-riscv64-gnu@4.54.0':
optional: true
'@rollup/rollup-linux-x64-gnu@4.28.0':
'@rollup/rollup-linux-riscv64-musl@4.54.0':
optional: true
'@rollup/rollup-linux-x64-musl@4.28.0':
'@rollup/rollup-linux-s390x-gnu@4.54.0':
optional: true
'@rollup/rollup-win32-arm64-msvc@4.28.0':
'@rollup/rollup-linux-x64-gnu@4.54.0':
optional: true
'@rollup/rollup-win32-ia32-msvc@4.28.0':
'@rollup/rollup-linux-x64-musl@4.54.0':
optional: true
'@rollup/rollup-win32-x64-msvc@4.28.0':
'@rollup/rollup-openharmony-arm64@4.54.0':
optional: true
'@tauri-apps/api@2.1.1': {}
'@rollup/rollup-win32-arm64-msvc@4.54.0':
optional: true
'@types/estree@1.0.6': {}
'@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: {}
@ -280,46 +313,50 @@ snapshots:
dependencies:
function-bind: 1.1.2
is-core-module@2.15.1:
is-core-module@2.16.1:
dependencies:
hasown: 2.0.2
path-parse@1.0.7: {}
picomatch@4.0.2: {}
picomatch@4.0.3: {}
resolve@1.22.8:
resolve@1.22.11:
dependencies:
is-core-module: 2.15.1
is-core-module: 2.16.1
path-parse: 1.0.7
supports-preserve-symlinks-flag: 1.0.0
rollup@4.28.0:
rollup@4.54.0:
dependencies:
'@types/estree': 1.0.6
'@types/estree': 1.0.8
optionalDependencies:
'@rollup/rollup-android-arm-eabi': 4.28.0
'@rollup/rollup-android-arm64': 4.28.0
'@rollup/rollup-darwin-arm64': 4.28.0
'@rollup/rollup-darwin-x64': 4.28.0
'@rollup/rollup-freebsd-arm64': 4.28.0
'@rollup/rollup-freebsd-x64': 4.28.0
'@rollup/rollup-linux-arm-gnueabihf': 4.28.0
'@rollup/rollup-linux-arm-musleabihf': 4.28.0
'@rollup/rollup-linux-arm64-gnu': 4.28.0
'@rollup/rollup-linux-arm64-musl': 4.28.0
'@rollup/rollup-linux-powerpc64le-gnu': 4.28.0
'@rollup/rollup-linux-riscv64-gnu': 4.28.0
'@rollup/rollup-linux-s390x-gnu': 4.28.0
'@rollup/rollup-linux-x64-gnu': 4.28.0
'@rollup/rollup-linux-x64-musl': 4.28.0
'@rollup/rollup-win32-arm64-msvc': 4.28.0
'@rollup/rollup-win32-ia32-msvc': 4.28.0
'@rollup/rollup-win32-x64-msvc': 4.28.0
'@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.2: {}
typescript@5.9.3: {}

View file

@ -1,31 +1,32 @@
import { readFileSync } from "fs"
import { join } from "path"
import { cwd } from "process"
import typescript from "@rollup/plugin-typescript"
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"))
const pkg = JSON.parse(readFileSync(join(cwd(), 'package.json'), 'utf8'))
export default {
input: "guest-js/index.ts",
input: 'guest-js/index.ts',
output: [
{
file: pkg.exports.import,
format: "esm",
format: 'esm'
},
{
file: pkg.exports.require,
format: "cjs",
},
format: 'cjs'
}
],
plugins: [
typescript({
tsconfig: './tsconfig.json',
declaration: true,
declarationDir: `./${pkg.exports.import.split("/")[0]}`,
}),
declarationDir: './dist-js'
})
],
external: [
/^@tauri-apps\/api/,
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
],
...Object.keys(pkg.peerDependencies || {})
]
}

View file

@ -9,6 +9,7 @@ use tauri::{
use crate::{
bundle::BundleLoader,
cache::CacheManager,
mapping::HostMapper,
models::{
CloseOptions, CloseResponse, DownloadOptions, DownloadResponse, LoadOptions, LoadResponse,
},
@ -16,11 +17,24 @@ use crate::{
ui, RemoveOptions, RemoveResponse, Result,
};
fn sanitize_window_label(input: &str) -> String {
input
/// Maximum length for window labels/hosts
const MAX_HOST_LENGTH: usize = 255;
fn sanitize_window_label(input: &str) -> Result<String> {
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()
.collect())
}
#[command]
@ -70,7 +84,7 @@ pub async fn download<R: Runtime>(
#[command]
pub async fn load<R: Runtime>(app: AppHandle<R>, options: LoadOptions) -> Result<LoadResponse> {
let base_label = sanitize_window_label(&options.window.title);
let base_label = sanitize_window_label(&options.window.title)?;
let current_label = format!("{}-curr", base_label);
let alternate_label = format!("{}-next", base_label);
@ -80,22 +94,59 @@ pub async fn load<R: Runtime>(app: AppHandle<R>, options: LoadOptions) -> Result
current_label
};
tracing::info!(?options, bundle = %options.bundle_name, window_label = %label, "Loading bundle");
// Determine the webview host:
// - If `host` is provided, use it (for cloud-for-orgs support)
// - Otherwise, use the bundle name
let window_host = options
.host
.clone()
.unwrap_or_else(|| options.bundle_name.clone());
let sanitized_host = sanitize_window_label(&window_host)?;
let url = format!("app://{}/", options.bundle_name.to_lowercase());
tracing::info!(
?options,
bundle = %options.bundle_name,
host = %sanitized_host,
window_label = %label,
"Loading bundle"
);
let url = format!("app://{}/", sanitized_host.to_lowercase());
tracing::debug!(%url, "Generated app URL");
let window = WebviewWindowBuilder::new(&app, &label, WebviewUrl::App(url.parse().unwrap()))
.initialization_script(crate::KERNEL_JS)
.title(sanitize_window_label(&options.window.title))
.inner_size(options.window.width, options.window.height)
.resizable(options.window.resizable)
.disable_drag_drop_handler()
.build()
.map_err(|e| {
tracing::error!(?e, ?label, "Failed to create window");
e
})?;
let host_mapper = app.state::<Arc<HostMapper>>();
host_mapper.register(
&sanitized_host.to_lowercase(),
&options.bundle_name.to_lowercase(),
);
tracing::debug!(
host = %sanitized_host.to_lowercase(),
bundle = %options.bundle_name.to_lowercase(),
"Registered host mapping"
);
let sanitized_title = sanitize_window_label(&options.window.title)?;
let window =
match 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()
.build()
{
Ok(window) => window,
Err(e) => {
tracing::error!(
?e,
?label,
"Failed to create window, cleaning up host mapping"
);
host_mapper.unregister(&sanitized_host.to_lowercase());
return Err(e.into());
}
};
#[cfg(target_os = "macos")]
{
@ -150,8 +201,9 @@ pub async fn remove<R: Runtime>(
tracing::info!(?options, "Starting instance removal process");
let storage = app.state::<Arc<StorageManager>>();
let cache = app.state::<Arc<CacheManager>>();
let host_mapper = app.state::<Arc<HostMapper>>();
tracing::debug!("Retrieved StorageManager and CacheManager states");
tracing::debug!("Retrieved StorageManager, CacheManager, and HostMapper states");
storage
.delete_bundle(&options.bundle_name, &options.server_url)
@ -163,6 +215,10 @@ pub async fn remove<R: Runtime>(
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,
@ -176,6 +232,10 @@ pub async fn remove<R: Runtime>(
pub async fn clear<R: Runtime>(app: AppHandle<R>) -> Result<()> {
tracing::info!("Starting bundle cleanup process");
let storage = app.state::<Arc<StorageManager>>();
let host_mapper = app.state::<Arc<HostMapper>>();
host_mapper.clear();
tracing::debug!("Cleared host mappings");
let layout = storage.layout();

View file

@ -34,6 +34,7 @@ mod config;
mod envvar;
mod error;
mod global;
mod mapping;
mod models;
mod storage;
mod ui;
@ -42,6 +43,7 @@ mod vendor;
mod verification;
pub use error::{Error, Result};
pub use mapping::HostMapper;
pub use vendor::VendorConfig;
#[cfg(mobile)]
@ -95,7 +97,15 @@ pub fn init<R: Runtime>(config: Config) -> TauriPlugin<R> {
tracing::debug!("Setting up bundle loader.");
let bundle_loader = Arc::new(bundle::BundleLoader::new(cache.clone(), storage.clone()));
let uri_handler = Arc::new(uri::UriHandler::new(cache.clone(), tauri_config.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();
@ -121,6 +131,7 @@ pub fn init<R: Runtime>(config: Config) -> TauriPlugin<R> {
app.manage(bundle_loader);
app.manage(cache);
app.manage(storage);
app.manage(host_mapper);
app.manage(uri_handler);
app.manage(view);

View file

@ -0,0 +1,246 @@
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<DashMap> 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<DashMap<String, String>>,
}
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<String> = 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");
}
}

View file

@ -147,6 +147,18 @@ pub struct DownloadResponse {
#[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<String>,
#[serde(default)]
pub inline: bool,
#[serde(default)]

View file

@ -7,21 +7,34 @@ use tauri::{
use super::error::Result;
use crate::cache::CacheManager;
use crate::mapping::HostMapper;
pub struct UriHandler {
cache: Arc<CacheManager>,
mapper: Arc<HostMapper>,
config: Config,
}
impl UriHandler {
pub fn new(cache: Arc<CacheManager>, config: Config) -> Self {
Self { cache, config }
pub fn new(cache: Arc<CacheManager>, config: Config, mapper: Arc<HostMapper>) -> Self {
Self {
cache,
config,
mapper,
}
}
async fn fetch_content(&self, host: &str, path: &str) -> Result<Vec<u8>> {
let file_path = if path.is_empty() { "index.html" } else { path };
tracing::debug!(host = %host, path = %path, resolved_path = %file_path, "Fetching file content.");
Ok(self.cache.get_file(host, file_path).await?)
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 {

View file

@ -7,7 +7,6 @@
"strict": true,
"noUnusedLocals": true,
"noImplicitAny": true,
"noEmit": true,
"declaration": true,
"declarationMap": true,
"outDir": "dist-js"

View file

@ -1,24 +1,24 @@
import { invoke } from "@tauri-apps/api/core"
import { invoke } from '@tauri-apps/api/core';
let 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 = {}))
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 })
return await invoke('plugin:relay|execute', { request });
}
async function cancel(requestId) {
return await invoke("plugin:relay|cancel", { requestId })
return await invoke('plugin:relay|cancel', { requestId });
}
export { MediaType, cancel, execute }
export { MediaType, cancel, execute };

View file

@ -1,220 +1,191 @@
import { invoke } from "@tauri-apps/api/core"
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
| "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
| "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
| 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 }
| { 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",
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 }
| { 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
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: "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: "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
}
accessToken?: string
refreshToken?: string
}
| {
kind: "apikey"
key: string
value: string
in: "header" | "query"
| {
kind: "apikey"
key: string
value: string
in: "header" | "query"
}
| {
kind: "aws"
accessKey: string
secretKey: string
region: string
service: string
sessionToken?: 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: "pem"
cert: Uint8Array
key: Uint8Array
}
| {
kind: "pfx"
data: Uint8Array
password: string
}
kind: "pfx"
data: Uint8Array
password: string
}
export interface RequestOptions {
timeout?: number
@ -273,7 +244,7 @@ export interface Response {
expires?: Date
secure?: boolean
httpOnly?: boolean
sameSite?: "Strict" | "Lax" | "None"
sameSite?: 'Strict' | 'Lax' | 'None'
}>
body: ResponseBody
@ -306,13 +277,13 @@ export type RelayError =
| { kind: "abort"; message: string }
export type RequestResult =
| { kind: "success"; response: Response }
| { kind: "error"; error: RelayError }
| { kind: 'success'; response: Response }
| { kind: 'error'; error: RelayError }
export async function execute(request: Request): Promise<RequestResult> {
return await invoke<RequestResult>("plugin:relay|execute", { request })
return await invoke<RequestResult>('plugin:relay|execute', { request })
}
export async function cancel(requestId: number): Promise<void> {
return await invoke<void>("plugin:relay|cancel", { requestId })
return await invoke<void>('plugin:relay|cancel', { requestId })
}

View file

@ -25,9 +25,9 @@
"@tauri-apps/api": "2.1.1"
},
"devDependencies": {
"@rollup/plugin-typescript": "^12.3.0",
"rollup": "^4.55.3",
"tslib": "^2.6.2",
"typescript": "5.9.3"
"@rollup/plugin-typescript": "^11.1.6",
"rollup": "^4.9.6",
"typescript": "5.9.2",
"tslib": "^2.6.2"
}
}

View file

@ -1,31 +1,31 @@
import { readFileSync } from "fs"
import { join } from "path"
import { cwd } from "process"
import typescript from "@rollup/plugin-typescript"
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"))
const pkg = JSON.parse(readFileSync(join(cwd(), 'package.json'), 'utf8'))
export default {
input: "guest-js/index.ts",
input: 'guest-js/index.ts',
output: [
{
file: pkg.exports.import,
format: "esm",
format: 'esm'
},
{
file: pkg.exports.require,
format: "cjs",
},
format: 'cjs'
}
],
plugins: [
typescript({
declaration: true,
declarationDir: `./${pkg.exports.import.split("/")[0]}`,
}),
declarationDir: `./${pkg.exports.import.split('/')[0]}`
})
],
external: [
/^@tauri-apps\/api/,
...Object.keys(pkg.dependencies || {}),
...Object.keys(pkg.peerDependencies || {}),
],
...Object.keys(pkg.peerDependencies || {})
]
}

View file

@ -5541,7 +5541,7 @@ dependencies = [
[[package]]
name = "tauri-plugin-appload"
version = "0.1.0"
source = "git+https://github.com/CuriousCorrelation/tauri-plugin-appload?rev=52744a8f35bf81b039410522efd4168bd06d4f35#52744a8f35bf81b039410522efd4168bd06d4f35"
source = "git+https://github.com/CuriousCorrelation/tauri-plugin-appload?rev=168ff9533258a56de184fb69ad32f8a7f61bae0d#168ff9533258a56de184fb69ad32f8a7f61bae0d"
dependencies = [
"base64 0.22.1",
"blake3",

View file

@ -29,7 +29,7 @@ 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 = "52744a8f35bf81b039410522efd4168bd06d4f35" }
tauri-plugin-appload = { git = "https://github.com/CuriousCorrelation/tauri-plugin-appload", rev = "168ff9533258a56de184fb69ad32f8a7f61bae0d" }
tauri-plugin-relay = { git = "https://github.com/CuriousCorrelation/tauri-plugin-relay", rev = "7cf09c1ad31e228758738c2f4e1c8fe9cc141291" }
axum = "0.8.1"
tower-http = { version = "0.6.2", features = ["cors"] }

View file

@ -29,7 +29,7 @@
"@hoppscotch/common": "workspace:^",
"@hoppscotch/data": "workspace:^",
"@hoppscotch/kernel": "workspace:^",
"@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload#52744a8f35bf81b039410522efd4168bd06d4f35",
"@hoppscotch/plugin-appload": "github:CuriousCorrelation/tauri-plugin-appload#168ff9533258a56de184fb69ad32f8a7f61bae0d",
"@hoppscotch/ui": "0.2.5",
"@import-meta-env/unplugin": "0.6.3",
"@tauri-apps/api": "2.1.1",

View file

@ -563,8 +563,8 @@ importers:
specifier: workspace:^
version: link:../hoppscotch-kernel
'@hoppscotch/plugin-appload':
specifier: github:CuriousCorrelation/tauri-plugin-appload#52744a8f35bf81b039410522efd4168bd06d4f35
version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/52744a8f35bf81b039410522efd4168bd06d4f35'
specifier: github:CuriousCorrelation/tauri-plugin-appload#168ff9533258a56de184fb69ad32f8a7f61bae0d
version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/168ff9533258a56de184fb69ad32f8a7f61bae0d'
'@hoppscotch/ui':
specifier: 0.2.5
version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))
@ -1060,8 +1060,8 @@ importers:
specifier: workspace:^
version: link:../hoppscotch-kernel
'@hoppscotch/plugin-appload':
specifier: github:CuriousCorrelation/tauri-plugin-appload#52744a8f35bf81b039410522efd4168bd06d4f35
version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/52744a8f35bf81b039410522efd4168bd06d4f35'
specifier: github:CuriousCorrelation/tauri-plugin-appload#168ff9533258a56de184fb69ad32f8a7f61bae0d
version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/168ff9533258a56de184fb69ad32f8a7f61bae0d'
'@hoppscotch/ui':
specifier: 0.2.5
version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))
@ -1172,17 +1172,17 @@ importers:
packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-appload:
dependencies:
'@tauri-apps/api':
specifier: 2.1.1
version: 2.1.1
specifier: 2.9.1
version: 2.9.1
devDependencies:
'@rollup/plugin-typescript':
specifier: ^12.3.0
version: 12.3.0(rollup@4.55.3)(tslib@2.8.1)(typescript@5.9.3)
rollup:
specifier: ^4.55.3
specifier: ^4.54.0
version: 4.55.3
tslib:
specifier: ^2.6.2
specifier: ^2.8.1
version: 2.8.1
typescript:
specifier: 5.9.3
@ -1199,7 +1199,7 @@ importers:
devDependencies:
'@sveltejs/vite-plugin-svelte':
specifier: ^1.0.1
version: 1.4.0(svelte@3.59.2)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2))
version: 1.4.0(svelte@3.59.2)(vite@3.2.11(@types/node@25.0.9)(sass@1.97.2)(terser@5.44.1))
'@tauri-apps/cli':
specifier: ^2.0.0-alpha.17
version: 2.9.4
@ -1207,8 +1207,8 @@ importers:
specifier: ^3.49.0
version: 3.59.2
vite:
specifier: ^7.3.1
version: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2)
specifier: ^3.0.2
version: 3.2.11(@types/node@25.0.9)(sass@1.97.2)(terser@5.44.1)
packages/hoppscotch-desktop/plugin-workspace/tauri-plugin-relay:
dependencies:
@ -1217,17 +1217,17 @@ importers:
version: 2.1.1
devDependencies:
'@rollup/plugin-typescript':
specifier: ^12.3.0
version: 12.3.0(rollup@4.55.3)(tslib@2.8.1)(typescript@5.9.3)
specifier: ^11.1.6
version: 11.1.6(rollup@4.55.3)(tslib@2.8.1)(typescript@5.9.2)
rollup:
specifier: ^4.55.3
specifier: ^4.9.6
version: 4.55.3
tslib:
specifier: ^2.6.2
version: 2.8.1
typescript:
specifier: 5.9.3
version: 5.9.3
specifier: 5.9.2
version: 5.9.2
packages/hoppscotch-js-sandbox:
dependencies:
@ -1399,8 +1399,8 @@ importers:
specifier: workspace:^
version: link:../hoppscotch-kernel
'@hoppscotch/plugin-appload':
specifier: github:CuriousCorrelation/tauri-plugin-appload#52744a8f35bf81b039410522efd4168bd06d4f35
version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/52744a8f35bf81b039410522efd4168bd06d4f35'
specifier: github:CuriousCorrelation/tauri-plugin-appload#168ff9533258a56de184fb69ad32f8a7f61bae0d
version: '@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/168ff9533258a56de184fb69ad32f8a7f61bae0d'
'@hoppscotch/ui':
specifier: 0.2.5
version: 0.2.5(eslint@9.39.2(jiti@2.6.1))(terser@5.44.1)(typescript@5.9.3)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2))(vue@3.5.27(typescript@5.9.3))
@ -1774,8 +1774,8 @@ packages:
graphql:
optional: true
'@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/52744a8f35bf81b039410522efd4168bd06d4f35':
resolution: {tarball: https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/52744a8f35bf81b039410522efd4168bd06d4f35}
'@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/168ff9533258a56de184fb69ad32f8a7f61bae0d':
resolution: {tarball: https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/168ff9533258a56de184fb69ad32f8a7f61bae0d}
version: 0.1.0
'@CuriousCorrelation/plugin-relay@https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/7cf09c1ad31e228758738c2f4e1c8fe9cc141291':
@ -3318,6 +3318,12 @@ 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'}
@ -3534,6 +3540,12 @@ 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'}
@ -5494,6 +5506,19 @@ 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'}
@ -5888,6 +5913,9 @@ packages:
'@tauri-apps/api@2.9.0':
resolution: {integrity: sha512-qD5tMjh7utwBk9/5PrTA/aGr3i5QaJ/Mlt7p8NilQ45WgbifUNPyKWsA63iQ8YfQq6R8ajMapU+/Q8nMcPRLNw==}
'@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'}
@ -8239,6 +8267,131 @@ 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'}
@ -12522,6 +12675,11 @@ packages:
eslint: ^8.57.0 || ^9.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'}
@ -12916,6 +13074,31 @@ packages:
vue: 3.5.27
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.1:
resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==}
engines: {node: ^20.19.0 || >=22.12.0}
@ -13468,9 +13651,9 @@ snapshots:
optionalDependencies:
graphql: 16.12.0
'@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/52744a8f35bf81b039410522efd4168bd06d4f35':
'@CuriousCorrelation/plugin-appload@https://codeload.github.com/CuriousCorrelation/tauri-plugin-appload/tar.gz/168ff9533258a56de184fb69ad32f8a7f61bae0d':
dependencies:
'@tauri-apps/api': 2.1.1
'@tauri-apps/api': 2.9.1
'@CuriousCorrelation/plugin-relay@https://codeload.github.com/CuriousCorrelation/tauri-plugin-relay/tar.gz/7cf09c1ad31e228758738c2f4e1c8fe9cc141291':
dependencies:
@ -15969,6 +16152,9 @@ snapshots:
'@esbuild/android-arm64@0.27.2':
optional: true
'@esbuild/android-arm@0.15.18':
optional: true
'@esbuild/android-arm@0.17.19':
optional: true
@ -16077,6 +16263,9 @@ snapshots:
'@esbuild/linux-ia32@0.27.2':
optional: true
'@esbuild/linux-loong64@0.15.18':
optional: true
'@esbuild/linux-loong64@0.17.19':
optional: true
@ -18631,6 +18820,15 @@ snapshots:
optionalDependencies:
rollup: 2.79.2
'@rollup/plugin-typescript@11.1.6(rollup@4.55.3)(tslib@2.8.1)(typescript@5.9.2)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.55.3)
resolve: 1.22.11
typescript: 5.9.2
optionalDependencies:
rollup: 4.55.3
tslib: 2.8.1
'@rollup/plugin-typescript@12.1.4(rollup@4.55.3)(tslib@2.8.1)(typescript@5.9.3)':
dependencies:
'@rollup/pluginutils': 5.3.0(rollup@4.55.3)
@ -19068,7 +19266,7 @@ snapshots:
magic-string: 0.25.9
string.prototype.matchall: 4.0.12
'@sveltejs/vite-plugin-svelte@1.4.0(svelte@3.59.2)(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2))':
'@sveltejs/vite-plugin-svelte@1.4.0(svelte@3.59.2)(vite@3.2.11(@types/node@25.0.9)(sass@1.97.2)(terser@5.44.1))':
dependencies:
debug: 4.4.3(supports-color@8.1.1)
deepmerge: 4.3.1
@ -19076,8 +19274,8 @@ snapshots:
magic-string: 0.26.7
svelte: 3.59.2
svelte-hmr: 0.15.3(svelte@3.59.2)
vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2)
vitefu: 0.2.5(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2))
vite: 3.2.11(@types/node@25.0.9)(sass@1.97.2)(terser@5.44.1)
vitefu: 0.2.5(vite@3.2.11(@types/node@25.0.9)(sass@1.97.2)(terser@5.44.1))
transitivePeerDependencies:
- supports-color
@ -19085,6 +19283,8 @@ snapshots:
'@tauri-apps/api@2.9.0': {}
'@tauri-apps/api@2.9.1': {}
'@tauri-apps/cli-darwin-arm64@2.9.3':
optional: true
@ -19181,7 +19381,7 @@ snapshots:
'@tauri-apps/plugin-dialog@2.0.1':
dependencies:
'@tauri-apps/api': 2.1.1
'@tauri-apps/api': 2.9.1
'@tauri-apps/plugin-fs@2.0.2':
dependencies:
@ -19193,7 +19393,7 @@ snapshots:
'@tauri-apps/plugin-shell@2.2.1':
dependencies:
'@tauri-apps/api': 2.1.1
'@tauri-apps/api': 2.9.1
'@tauri-apps/plugin-shell@2.3.3':
dependencies:
@ -21828,6 +22028,91 @@ 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
@ -27306,6 +27591,8 @@ snapshots:
transitivePeerDependencies:
- supports-color
typescript@5.9.2: {}
typescript@5.9.3: {}
ua-parser-js@1.0.41: {}
@ -27738,6 +28025,18 @@ snapshots:
transitivePeerDependencies:
- supports-color
vite@3.2.11(@types/node@25.0.9)(sass@1.97.2)(terser@5.44.1):
dependencies:
esbuild: 0.15.18
postcss: 8.5.6
resolve: 1.22.11
rollup: 2.79.2
optionalDependencies:
'@types/node': 25.0.9
fsevents: 2.3.3
sass: 1.97.2
terser: 5.44.1
vite@7.3.1(@types/node@24.10.1)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2):
dependencies:
esbuild: 0.27.2
@ -27786,9 +28085,9 @@ snapshots:
terser: 5.44.1
yaml: 2.8.2
vitefu@0.2.5(vite@7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2)):
vitefu@0.2.5(vite@3.2.11(@types/node@25.0.9)(sass@1.97.2)(terser@5.44.1)):
optionalDependencies:
vite: 7.3.1(@types/node@25.0.9)(jiti@2.6.1)(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2)
vite: 3.2.11(@types/node@25.0.9)(sass@1.97.2)(terser@5.44.1)
vitest@4.0.17(@types/node@24.10.1)(jiti@2.6.1)(jsdom@27.4.0(@noble/hashes@2.0.1))(sass@1.97.2)(terser@5.44.1)(yaml@2.8.2):
dependencies: