v1.4 push.

This commit is contained in:
stan44 2026-03-01 20:52:56 -06:00
commit 214c52f556
250 changed files with 43393 additions and 0 deletions

View File

@ -0,0 +1,58 @@
name: reliability-matrix
on:
workflow_dispatch:
push:
branches: [ main ]
pull_request:
jobs:
matrix:
name: ${{ matrix.os }} / .NET tests
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 10.0.x
- name: Restore
run: dotnet restore DevTool.csproj
- name: Build
run: dotnet build DevTool.csproj -c Release --no-restore
- name: Test
run: dotnet test tests/DevTool.Tests/DevTool.Tests.csproj -c Release --no-build --logger "trx;LogFileName=test-results.trx"
- name: Generate matrix summary
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path artifacts | Out-Null
@"
{
"os": "${{ matrix.os }}",
"commit": "${{ github.sha }}",
"workflow": "${{ github.workflow }}",
"runId": "${{ github.run_id }}",
"runNumber": "${{ github.run_number }}",
"status": "passed"
}
"@ | Set-Content artifacts/reliability-${{ matrix.os }}.json -Encoding UTF8
- name: Upload test artifacts
uses: actions/upload-artifact@v4
with:
name: reliability-${{ matrix.os }}
path: |
**/test-results.trx
artifacts/reliability-${{ matrix.os }}.json

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
bin/
obj/
__pycache__/
.cache/
.vscode/
.idea/
.vs/
.git/
.pip
.tmp
.venv
.dotnet_home
.nuget
publish-test/

44
DevTool.csproj Normal file
View File

@ -0,0 +1,44 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<AssemblyName>sdt</AssemblyName>
<RootNamespace>Sdt</RootNamespace>
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Spectre.Console" Version="0.49.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="src\\DevTool.Engine\\DevTool.Engine.csproj" />
<ProjectReference Include="src\\DevTool.Runtime\\DevTool.Runtime.csproj" />
<ProjectReference Include="src\\DevTool.Host.Tui\\DevTool.Host.Tui.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Remove="src\\**\\*.cs" />
<Compile Remove="tests\**\*.cs" />
<None Include="tests\**\*" />
</ItemGroup>
<ItemGroup>
<Content Include="scripts\*.py">
<Link>scripts\%(Filename)%(Extension)</Link>
<TargetPath>scripts\%(Filename)%(Extension)</TargetPath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
<Content Include="scripts\dev-shell.ps1;scripts\dev-shell.sh;scripts\dev-shell.cmd;scripts\_pwsh-python-shim.ps1">
<Link>scripts\%(Filename)%(Extension)</Link>
<TargetPath>scripts\%(Filename)%(Extension)</TargetPath>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
</Content>
</ItemGroup>
</Project>

11
DevTool.slnx Normal file
View File

@ -0,0 +1,11 @@
<Solution>
<Folder Name="/src/">
<Project Path="src/DevTool.Engine/DevTool.Engine.csproj" />
<Project Path="src/DevTool.Host.Tui/DevTool.Host.Tui.csproj" />
<Project Path="src/DevTool.Runtime/DevTool.Runtime.csproj" />
</Folder>
<Folder Name="/tests/">
<Project Path="tests/DevTool.Tests/DevTool.Tests.csproj" />
</Folder>
<Project Path="DevTool.csproj" />
</Solution>

329
Program.cs Normal file
View File

@ -0,0 +1,329 @@
using Sdt.Config;
using Sdt.Core;
using Sdt.Tui;
using Spectre.Console;
try
{
var cliArgs = Environment.GetCommandLineArgs().Skip(1).ToArray();
if (TryGetWorkspaceCommand(cliArgs, out var workspaceCommand))
return RunWorkspaceCommand(cliArgs, workspaceCommand);
if (TryGetHeadlessCommand(cliArgs, out var headlessKind))
{
var exit = await RunHeadlessAsync(cliArgs, headlessKind);
return exit;
}
// ── Workspace + project discovery ────────────────────────────────────────
var workspaceResult = WorkspaceLoader.FindAndLoad();
var projectResult = ConfigLoader.FindAndLoad();
var forceInit = cliArgs.Any(a => string.Equals(a, "init", StringComparison.OrdinalIgnoreCase) ||
string.Equals(a, "--init", StringComparison.OrdinalIgnoreCase));
if (forceInit)
{
var scan = ConfigBootstrapper.Scan(Directory.GetCurrentDirectory());
var generated = ConfigBootstrapper.BuildDefaultConfig(scan);
var path = ConfigBootstrapper.WriteDefaultConfig(scan.ProjectRoot, generated, overwrite: false);
AnsiConsole.MarkupLine(Theme.Ok($"Initialized config at {path}"));
projectResult = ConfigLoader.FindAndLoad(scan.ProjectRoot);
}
if (projectResult is null)
{
AnsiConsole.MarkupLine($"[bold {Theme.Red}]SDT:[/] [{Theme.Amber}]No devtool.json found[/] in current directory or any parent.");
var bootstrap = AnsiConsole.Confirm(
$"[{Theme.Amber}]Generate a default devtool.json for this project now?[/]",
defaultValue: true);
if (!bootstrap)
{
AnsiConsole.MarkupLine(Theme.Faint("Create a devtool.json in your project root to get started."));
return 1;
}
var scan = ConfigBootstrapper.Scan(Directory.GetCurrentDirectory());
AnsiConsole.MarkupLine(Theme.Faint($"Detected project root: {scan.ProjectRoot}"));
if (scan.ToolFamilies.Count > 0)
AnsiConsole.MarkupLine(Theme.Faint($"Detected tool families: {string.Join(", ", scan.ToolFamilies)}"));
var generated = ConfigBootstrapper.BuildDefaultConfig(scan);
var preview = ConfigBootstrapper.ToJson(generated);
AnsiConsole.Write(new Panel(Markup.Escape(preview)).Header("Generated devtool.json preview").BorderStyle(Theme.DimStyle));
var confirmWrite = AnsiConsole.Confirm(
$"[{Theme.Amber}]Write generated devtool.json to {scan.ProjectRoot}?[/]",
defaultValue: true);
if (!confirmWrite)
return 1;
var path = ConfigBootstrapper.WriteDefaultConfig(scan.ProjectRoot, generated, overwrite: false);
AnsiConsole.MarkupLine(Theme.Ok($"Created {path}"));
projectResult = ConfigLoader.FindAndLoad(scan.ProjectRoot);
if (projectResult is null)
{
AnsiConsole.MarkupLine(Theme.Fail("Generated config could not be reloaded."));
return 1;
}
}
// ── Main run loop (handles workspace project switching) ────────────────
var currentLoaded = projectResult;
var (workspace, workspaceRoot) = workspaceResult.HasValue
? (workspaceResult.Value.Config, workspaceResult.Value.WorkspaceRoot)
: ((WorkspaceConfig?)null, (string?)null);
string? pendingWorkflowId = null;
while (true)
{
var app = new App(
currentLoaded.Config,
currentLoaded.ProjectRoot,
currentLoaded.Warnings,
workspace,
workspaceRoot,
pendingWorkflowId);
pendingWorkflowId = null;
var result = await app.RunAsync();
if (result.Reason == AppExitReason.Quit)
break;
if (result.Reason == AppExitReason.SwitchProject && result.NewProjectRoot is not null)
{
LoadedProjectConfig? loaded;
try
{
loaded = ConfigLoader.FindAndLoad(result.NewProjectRoot);
}
catch (Exception ex)
{
AnsiConsole.MarkupLine(Theme.Fail(ex.Message));
AnsiConsole.MarkupLine(Theme.Faint("Press any key to stay on current project..."));
Console.ReadKey(intercept: true);
continue;
}
if (loaded is null)
{
AnsiConsole.MarkupLine(Theme.Fail($"No devtool.json found at: {result.NewProjectRoot}"));
AnsiConsole.MarkupLine(Theme.Faint("Press any key to stay on current project..."));
Console.ReadKey(intercept: true);
continue;
}
currentLoaded = loaded;
pendingWorkflowId = result.RunWorkflowId;
}
}
return 0;
}
catch (Exception ex)
{
var message = ex.Message;
var isExpectedMigrationError =
ex is InvalidOperationException &&
message.Contains("Legacy targets-only config detected", StringComparison.OrdinalIgnoreCase);
AnsiConsole.MarkupLine(Theme.Fail($"Fatal: {message}"));
if (isExpectedMigrationError)
{
var configPath = ConfigLoader.FindConfigPath();
if (!string.IsNullOrWhiteSpace(configPath))
{
var migrate = AnsiConsole.Confirm(
$"[{Theme.Amber}]Apply automatic migration now (creates backup + converts targets -> workflows)?[/]",
defaultValue: true);
if (migrate)
{
var result = ConfigLoader.ApplyLegacyTargetMigration(configPath, createBackup: true);
if (result.Success)
{
AnsiConsole.MarkupLine(Theme.Ok("Migration applied successfully."));
if (!string.IsNullOrWhiteSpace(result.BackupPath))
AnsiConsole.MarkupLine(Theme.Faint($"Backup: {result.BackupPath}"));
AnsiConsole.MarkupLine(Theme.Faint("Run sdt.exe again in strict mode."));
}
else
{
AnsiConsole.MarkupLine(Theme.Fail($"Migration failed: {result.Message}"));
}
}
}
}
if (!isExpectedMigrationError)
AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything);
return 1;
}
static bool TryGetHeadlessCommand(IReadOnlyList<string> cliArgs, out string kind)
{
kind = "";
if (cliArgs.Count == 0)
return false;
if (string.Equals(cliArgs[0], "run", StringComparison.OrdinalIgnoreCase))
{
kind = "run";
return true;
}
if (string.Equals(cliArgs[0], "debug", StringComparison.OrdinalIgnoreCase))
{
kind = "debug";
return true;
}
return false;
}
static bool TryGetWorkspaceCommand(IReadOnlyList<string> cliArgs, out string command)
{
command = "";
if (cliArgs.Count < 2)
return false;
if (!string.Equals(cliArgs[0], "workspace", StringComparison.OrdinalIgnoreCase))
return false;
if (string.Equals(cliArgs[1], "scan", StringComparison.OrdinalIgnoreCase))
{
command = "scan";
return true;
}
return false;
}
static int RunWorkspaceCommand(IReadOnlyList<string> cliArgs, string command)
{
if (!string.Equals(command, "scan", StringComparison.OrdinalIgnoreCase))
return ExitCodeMapper.FromResult(false, ExecutionStopReason.ValidationFailed);
var options = ParseOptions(cliArgs.Skip(2).ToArray(), out _);
var startDir = options.TryGetValue("--project-root", out var root) && !string.IsNullOrWhiteSpace(root)
? root
: Directory.GetCurrentDirectory();
var asJson = options.ContainsKey("--json");
var workspaceLoaded = WorkspaceLoader.FindAndLoad(startDir);
if (workspaceLoaded is null)
{
var payload = new { success = false, message = "No workspace could be discovered." };
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(payload));
return ExitCodeMapper.FromResult(false, ExecutionStopReason.ValidationFailed);
}
var (workspace, workspaceRoot) = workspaceLoaded.Value;
var currentRoot = ConfigLoader.FindAndLoad(startDir)?.ProjectRoot ?? startDir;
var scan = WorkspaceLoader.ScanInventory(workspaceRoot, currentRoot, workspace);
if (asJson)
{
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize(scan, new System.Text.Json.JsonSerializerOptions
{
PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase,
WriteIndented = true
}.WithEnumStrings()));
}
else
{
Console.WriteLine($"Workspace root: {scan.WorkspaceRoot}");
Console.WriteLine($"Known projects: {scan.KnownProjects.Count}");
Console.WriteLine($"Candidates: {scan.Candidates.Count}");
foreach (var item in scan.Candidates)
Console.WriteLine($" - {item.DisplayName} [{item.PrimaryKind}] {item.RootPath}");
}
return 0;
}
static async Task<int> RunHeadlessAsync(IReadOnlyList<string> cliArgs, string kind)
{
var options = ParseOptions(cliArgs.Skip(1).ToArray(), out var positional);
var json = options.ContainsKey("--json");
var startDir = options.TryGetValue("--project-root", out var projectRootOpt)
? projectRootOpt
: Directory.GetCurrentDirectory();
var envProfile = options.TryGetValue("--env-profile", out var profile) ? profile : null;
var nonInteractive = options.ContainsKey("--non-interactive") || RuntimePolicy.IsNonInteractive();
var loaded = ConfigLoader.FindAndLoad(startDir);
if (loaded is null)
{
Console.WriteLine("{\"success\":false,\"message\":\"No devtool.json found for headless command.\"}");
return ExitCodeMapper.FromResult(false, ExecutionStopReason.ValidationFailed);
}
var service = new HeadlessExecutionService();
if (kind == "run")
{
if (positional.Count == 0)
{
Console.WriteLine("{\"success\":false,\"message\":\"Missing workflow id. Usage: sdt run <workflowId> [--json] [--project-root <path>] [--env-profile <id>] [--non-interactive]\"}");
return ExitCodeMapper.FromResult(false, ExecutionStopReason.ValidationFailed);
}
return await service.RunWorkflowAsync(
loaded,
new HeadlessRunRequest(
WorkflowId: positional[0],
ProjectRoot: loaded.ProjectRoot,
EnvProfile: envProfile,
NonInteractive: nonInteractive,
JsonOutput: json));
}
if (positional.Count == 0)
{
Console.WriteLine("{\"success\":false,\"message\":\"Missing debug profile id. Usage: sdt debug <profileId> [--json] [--project-root <path>] [--env-profile <id>] [--non-interactive]\"}");
return ExitCodeMapper.FromResult(false, ExecutionStopReason.ValidationFailed);
}
return await service.RunDebugAsync(
loaded,
new HeadlessDebugRequest(
ProfileId: positional[0],
ProjectRoot: loaded.ProjectRoot,
EnvProfile: envProfile,
NonInteractive: nonInteractive,
JsonOutput: json));
}
static Dictionary<string, string?> ParseOptions(string[] args, out List<string> positional)
{
var options = new Dictionary<string, string?>(StringComparer.OrdinalIgnoreCase);
positional = [];
for (var i = 0; i < args.Length; i++)
{
var token = args[i];
if (!token.StartsWith("-", StringComparison.Ordinal))
{
positional.Add(token);
continue;
}
if (i + 1 < args.Length && !args[i + 1].StartsWith("-", StringComparison.Ordinal))
{
options[token] = args[i + 1];
i++;
}
else
{
options[token] = null;
}
}
return options;
}
static class JsonOptionsExtensions
{
public static System.Text.Json.JsonSerializerOptions WithEnumStrings(this System.Text.Json.JsonSerializerOptions options)
{
options.Converters.Add(new System.Text.Json.Serialization.JsonStringEnumConverter());
return options;
}
}

267
README.md Normal file
View File

@ -0,0 +1,267 @@
# SDT (Stan's Dev Tools)
Cross-platform terminal orchestrator for project workflows, toolchain checks, and prerequisite gating.
## Current State
- Standalone `.NET` TUI app (`net10.0`)
- Domain-separated source projects under `src/`:
- `DevTool.Engine` (workflow/config/orchestration services)
- `DevTool.Runtime` (process/command execution primitives)
- `DevTool.Host.Tui` (terminal UI host surface)
- Workflow-first config model in `devtool.json`
- Strict-by-default legacy migration (`targets`-only configs fail unless compat mode is enabled)
- Python-first diagnostics/build script layer under `scripts/`
- Fail-fast execution with install prompt gating for missing prerequisites
- Debug profiles with attach metadata and diagnostics bundle generation
- Workspace-first project switching with support for external project paths
- Workspace-level defaults layering via `sdt-defaults.json` (ancestor defaults merged, project config wins)
- Project status tracking is maintained in `ROADMAP.md`
- Core run-event stream (`RunEvent`) shared by workflow + debug execution (TUI consumes it; GUI-ready)
- Run events are persisted to JSONL at `.sdt/events/` for external tooling/GUI consumers
- Run events now include versioned contract fields: `run_event_version`, `run_id`, `project_root`, `env_profile`, `timestamp_utc`, `event_type`
- TUI includes `SYSTEM -> View run events` to inspect persisted JSONL event logs
- `SYSTEM -> Run config doctor` can apply common autofixes (missing working dirs, legacy migration)
- `SYSTEM -> Keybinding help` provides normalized cross-platform shortcut guidance
- `SYSTEM -> Run history` supports rerun from prior execution context
- First-run projects are prompted to run a setup wizard (doctor + autofix + optional toolchain setup)
- Toolchain management now includes toolchain doctor + auto-fix flow with installer prompts and post-install verification
- Env profiles (`envProfiles`) support deterministic inheritance (`dev`/`ci`/`release`) and runtime profile selection from `SYSTEM -> Select env profile`
- Diagnostics bundles include managed secret redaction policy (env-key pattern redaction + output token redaction)
- Workspace quick actions/favorites can run workflows across projects (auto switch-and-run)
- Quick-action pinning is supported from workflow run results and events viewer
- Bootstrap detects additional project stacks (`go`, `maven`, `gradle`) and sets `project.type` (`dotnet`, `node`, `python`, `rust`, `go`, `java`, `tauri`, `polyglot`, `generic`)
- Headless execution mode is available for workflow/debug automation with JSON output
- Terminal capability fallback modes supported via `NO_COLOR`/`SDT_NO_COLOR` and `SDT_NO_UNICODE`
## Run
```powershell
dotnet run --project DevTool.csproj
```
Run from any subdirectory inside a project; SDT walks up to find `devtool.json`.
If `devtool.json` is missing, SDT now offers to scan the repo and generate a default config.
Explicit bootstrap command:
```powershell
dotnet run --project DevTool.csproj -- init
```
Headless workflow/debug commands:
```powershell
sdt run <workflowId> --json [--project-root <path>] [--env-profile <id>] [--non-interactive]
sdt debug <profileId> --json [--project-root <path>] [--env-profile <id>] [--non-interactive]
```
Workspace inventory scan (GUI/TUI shared discovery contract):
```powershell
sdt workspace scan --json [--project-root <path>]
```
`SDT_NONINTERACTIVE=1` globally enables non-interactive behavior for install prompts.
Bootstrap detects common stacks (`dotnet`, `npm/node`, `python`, `cargo/tauri`, `go`, `maven/gradle`, `git`, `docker`) and generates:
- default workflows
- toolchain/tooling defaults
- debug profiles + diagnostics defaults
## Config Model
SDT supports both:
- `workflows` (preferred)
- `targets` (legacy; compat mode only)
### Legacy Migration Mode (v1.2)
- Default: strict mode
- Behavior: `targets`-only config fails early with migration instructions
- Preview file: SDT writes `devtool.generated.workflows.json` for migration help
- Temporary rollback: set `SDT_LEGACY_MODE=compat`
Permanent fix (recommended):
1. Open `devtool.generated.workflows.json`
2. Copy its `workflows` into `devtool.json`
3. Remove or empty legacy `targets`
4. Run `sdt.exe` again in strict mode
### Workflow shape (preferred)
```json
{
"id": "build",
"label": "Build",
"description": "Build project",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "dotnet-build",
"label": "dotnet build",
"action": "dotnet-build",
"actionArgs": [],
"workingDir": ".",
"requires": [
{ "tool": "dotnet", "installPolicy": "Prompt" }
]
}
]
}
```
### Extra sections
- `tooling.tools[].preferredInstallCommands`: preferred install commands per tool
- `tooling.tools[].executables`: explicit executable candidates for non-standard PATH setups
- `project.rootHints`: files/folders that identify project root
- `env`: session-level environment variable editor values
- `debug.profiles[]`: run/attach debug profiles
- `debug.diagnostics`: diagnostics bundle policy (`.sdt/debug` by default)
- secure default: allowlist-only environment capture
- set `includeAllEnv=true` to opt into full environment capture
### Workspace Defaults Layering
If SDT finds `sdt-defaults.json` in the project directory tree (current project root or an ancestor), it merges it into the effective config before runtime:
- base layer: `sdt-defaults.json`
- override layer: project `devtool.json` (project values win)
Merge behavior:
- objects merge recursively
- arrays/scalars are replaced when project provides the property
This is useful for shared defaults like toolchains, diagnostics policies, and baseline env definitions across multiple projects in one workspace.
## Execution Behavior
For each workflow step:
1. Resolve dependencies (topological order)
2. Probe required tools
3. If missing, show install commands and prompt (`Prompt` policy)
4. On decline/install failure/step failure, stop immediately
5. Render step summary table with exit code + elapsed time
6. On workflow/debug failure, generate diagnostics bundle when enabled
Installer command precedence:
1. `tooling.tools[].preferredInstallCommands`
2. `scripts/diag.py install-plan`
3. built-in C# fallback templates (used automatically if script planning fails)
When a tool probe fails, SDT now prints probe diagnostics (including command resolution source/path) in run output before prompting for installs.
Headless exit code contract:
- `0` success
- `10` missing prerequisite
- `11` install failed
- `12` command failed
- `13` validation/config error
- `14` user-declined / non-interactive prompt refusal
## Scripts
See [scripts/README.md](/e:/stansshit/csharp/DevTool-master/scripts/README.md).
Primary Python entrypoints:
- `scripts/diag.py`
- `scripts/build.py`
- `scripts/dotnet-min.py`
- `scripts/pip-min.py`
- `scripts/publish-*.py`
## Workspace Support
- Uses `sdt-workspace.json` when present
- If missing, can auto-discover nearby projects containing `devtool.json`
- Workspace screen can add external project roots (absolute paths supported)
- `projects[].disabled`, `projects[].tags`, and `projects[].toolFamilies` are supported
- Hybrid inventory model discovers marker-only candidates (`.slnx/.sln/.csproj`) without silently mutating workspace config
- TUI workspace screen supports:
- `Add candidate`
- `Add + initialize devtool.json`
- `Ignore for now` (session-only)
- Inventory snapshot is cached at `.sdt/workspace-inventory.json` for GUI-readiness
## GUI Direction
- Planned GUI stack for current phase: **Tauri-first**
- Avalonia is deferred for re-evaluation after first GUI milestone ships on top of the same headless contracts
- GUI workspace scaffold: [TauriShell README](/e:/stansshit/csharp/DevTool-master/src/DevTool.Host.Gui/TauriShell/README.md)
- First command bridge shipped in scaffold: `sdt workspace scan --json`
- Second command bridge shipped in scaffold: `sdt run <workflowId> --json` with live stream panel
- GUI will consume:
- `sdt workspace scan --json` inventory payload
- `run/debug --json` summaries
- persisted run events from `.sdt/events/*.jsonl`
## Dev Shell Bootstrap
Python-first cross-shell dev environment bootstrap:
```powershell
# PowerShell
. ./scripts/dev-shell.ps1
# cmd
scripts\dev-shell.cmd
```
```bash
# bash/zsh
source ./scripts/dev-shell.sh
```
Underlying implementation is `scripts/dev_shell.py`:
- `python scripts/dev_shell.py export --shell pwsh --json`
- `python scripts/dev_shell.py doctor`
## Legacy PowerShell Compatibility
Legacy `.ps1` scripts remain for migration compatibility only. New functionality is implemented in Python scripts first. `script-common.ps1` is legacy-only.
Legacy runtime behavior in v1.2:
- strict mode rejects `targets`-only configs by default
- compat mode (`SDT_LEGACY_MODE=compat`) temporarily allows legacy execution
- TUI `SYSTEM` includes `Migrate legacy targets -> workflows` to apply migration in place (with backup)
- Python reroute is authoritative for legacy `pwsh -File ...ps1` targets
- `.ps1` fallback is opt-in only: set `SDT_PWSH_LEGACY_FALLBACK=1` for temporary compatibility
Deprecation target:
- v1.x: compatibility only (no new behavior guarantees)
- v2.0: remove legacy `.ps1` scripts from default SDT workflows and docs
## Testing
Run unit/integration tests:
```powershell
dotnet test tests/DevTool.Tests/DevTool.Tests.csproj
```
Run Python script smoke checks:
```powershell
python -m py_compile scripts/*.py
```
## Reliability Matrix
- CI matrix workflow: [reliability-matrix.yml](/e:/stansshit/csharp/DevTool-master/.github/workflows/reliability-matrix.yml)
- Runbook: [reliability-matrix-runbook.md](/e:/stansshit/csharp/DevTool-master/docs/reliability-matrix-runbook.md)
- Results log: [reliability-matrix-results.md](/e:/stansshit/csharp/DevTool-master/docs/reliability-matrix-results.md)
- Milestone status (Windows/Linux shipped, macOS delegated): [matrix-status.md](/e:/stansshit/csharp/DevTool-master/docs/matrix-status.md)

102
ROADMAP.md Normal file
View File

@ -0,0 +1,102 @@
# SDT Roadmap / Kanban
## Done (v1.2 Stabilization)
- [x] Python-first runtime for diagnostics/build wrappers
- [x] Config bootstrap generator for missing `devtool.json`
- [x] Workflow-first execution + dual schema support
- [x] Strict legacy mode default (`targets`-only blocked)
- [x] Compatibility escape hatch (`SDT_LEGACY_MODE=compat`)
- [x] Auto-generated migration preview (`devtool.generated.workflows.json`)
- [x] In-app migration action: `Migrate legacy targets -> workflows`
- [x] Centralized requirement inference (`RequirementResolver`)
- [x] Installer planning precedence + fallback resilience
- [x] Windows resolver hardening (`%VAR%` PATH expansion)
- [x] Resolver tracing surfaced in probe details
- [x] Secure diagnostics default (allowlist-only env capture)
- [x] Workspace external project add flow
- [x] Shared run event stream (`RunEvent`) across workflow + debug execution
- [x] TUI event rendering layer wired on top of core run events (GUI-readiness slice)
- [x] Persist run-event stream to JSONL for external GUI/client consumption (`.sdt/events/*.jsonl`)
- [x] TUI events viewer for persisted run-event logs (`SYSTEM -> View run events`)
- [x] Config doctor (`SYSTEM -> Run config doctor`)
- [x] Doctor autofix actions (create missing working dirs + invoke legacy migration)
- [x] Rich probe diagnostics panel in workflow failure summary
- [x] Enhanced Tauri fallback guidance (Windows/macOS/Linux package manager aware)
- [x] First-run setup wizard + completion state marker (`.sdt/setup-state.json`)
- [x] Toolchain hardening: probe diagnostics + toolchain doctor + auto-fix missing tools
- [x] Workspace-level defaults file layering (`sdt-defaults.json`) above per-project `devtool.json`
- [x] Add dedicated TUI "Events" viewer for last run
- [x] Add doctor autofix actions for common issues (missing dirs, legacy schema migration)
- [x] Env profiles (`dev`, `ci`, `release`) with deterministic merge order and runtime selection
- [x] Managed secrets redaction policy for diagnostics bundles (env + output patterns)
- [x] Setup wizard for first run (bootstrap + tool fixes)
- [x] Improve setup wizard to handle more edge cases and missing tools for projects
- [x] Add support for more project types
- [x] Add support for more tool types
- [x] Add support for more environment types
- [x] Add support for more environment variables
- [x] Favorites/quick actions across projects
- [x] Legacy PowerShell fallback made opt-in (`SDT_PWSH_LEGACY_FALLBACK=1`), Python reroute remains default
- [x] Bootstrap now resolves dotnet working directory from nearest `.slnx/.sln/.csproj` in multi-project roots
- [x] Bootstrap filters node/npm detection to runnable package scripts (avoids dependency-only `package.json` false positives)
- [x] Action layer now skips non-applicable stacks (`npm`/`cargo`/`tauri`/`dotnet`) instead of hard-failing
- [x] `publish-output.py` now auto-skips non-detected sidecar/web/gateway/tauri stacks in generic repos
## In Progress (next focus)
- [ ] Execute full OS matrix verification on Windows/Linux/macOS runners
- [ ] Native GUI shell over headless core services (Tauri-first in v1.x; Avalonia re-evaluate later)
- [x] Create dedicated `src/DevTool.Host.Gui/TauriShell` scaffold to keep GUI work isolated from TUI/core
- [x] Bootstrap first Tauri command bridge: `sdt workspace scan --json`
- [x] Structural refactor to domain-separated projects under `src/` (`DevTool.Engine`, `DevTool.Runtime`, `DevTool.Host.Tui`)
- [x] Add second Tauri bridge command: `sdt run <workflowId> --json` with live stream panel
- [ ] Remove legacy PowerShell wrappers in v2
- [x] Add workspace project inventory model (all `.slnx/.sln/.csproj`) for GUI/TUI multi-project selector
## Next Sprint (v1.3 UX Foundation)
- [x] Define stable event contract version (`run_event_version`) and publish schema docs
- [x] Add `--json`/headless execution mode for workflow/debug runs (machine-readable progress + result)
- [x] Add TUI command palette (`Ctrl+K`) for quick action/run/switch project
- [x] Add unified failure card: `What failed`, `Why`, `Exact fix command`, `Retry action`
- [x] Add non-interactive install mode for CI/headless (`SDT_NONINTERACTIVE=1`)
- [x] Add per-run execution context block in TUI (`project`, `envProfile`, `cwd`, `tool resolution source`)
- [x] Add cross-platform keybinding help screen (`?`) and normalize shortcuts across Windows/macOS/Linux terminals
- [x] Add terminal capability fallback modes (no color/no unicode/no emoji safe rendering)
- [x] Add workspace quick-action pinning from run results and events viewer
- [x] Add run history browser with re-run from prior execution context
## v1.3 Reliability Matrix
- [x] Add project-type matrix coverage tests (`dotnet`, `node/npm`, `tauri/cargo`)
- [x] Add deterministic headless stop-reason/exit-code tests
- [ ] Execute full OS matrix verification on Windows/Linux/macOS runners
- [x] Publish reliability matrix runbook + results artifact in docs
- Blocked in current local workspace: no `.git` repo context and no `gh` CLI/auth; execute from Git-connected checkout.
- v1.4 policy: ship Windows/Linux, macOS delegated with checklist in `docs/matrix-status.md`.
## Cross-Platform UX Principles
- [x] One mental model for all surfaces: `Plan -> Probe -> Prompt -> Execute -> Diagnose`
- [x] Every failure must include a copy-pastable remediation command
- [x] No blocking hidden prompts from package managers (always explicit/non-interactive flags where possible)
- [x] Keep TUI and future GUI on the same core events/state, not duplicated execution logic
- [x] Preserve deterministic behavior across shell/env differences via explicit working directory + env profile display
- [ ] Remove legacy PowerShell wrappers in v2
## Current Milestone Status
- v1.1 expansion items shipped partially (debug profiles + diagnostics + workspace add external)
- Robustness Sprint v1.2: **complete**
- v1.3 workstreams A/B/C: **complete**
- v1.3 workstream D: **in progress** (matrix test suite implemented; cross-OS execution pending)
- v1.3 UX foundation backlog items: **complete**
- Remaining gaps for broader AIO vision are GUI shell, cross-OS matrix run completion, and advanced orchestration scale.
## GUI Decision Record
- [x] GUI runtime direction locked for current phase: **Tauri-first now**
- [x] Keep headless core + JSON/event contracts as the shared backend authority
- [x] Defer Avalonia shell implementation to a re-evaluation checkpoint after Tauri shell proves workflow/debug/event parity
- [ ] Avalonia re-evaluation gate criteria documented and reviewed after first Tauri shell milestone

487
devtool.json Normal file
View File

@ -0,0 +1,487 @@
{
"name": "DevTool-master",
"version": "0.1.0",
"targets": [],
"workflows": [
{
"id": "sidecar",
"label": "Publish Sidecar",
"description": "Publish sidecar service",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "sidecar:run",
"label": "python scripts/publish-sidecar.py",
"command": "python",
"args": [
"scripts/publish-sidecar.py"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "web",
"label": "Build Web UI",
"description": "Build frontend assets",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "web:run",
"label": "python scripts/publish-app.py --target web",
"command": "python",
"args": [
"scripts/publish-app.py",
"--target",
"web"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "tauri",
"label": "Build Tauri Desktop App",
"description": "Build desktop binary",
"group": "Build",
"dependsOn": [
"sidecar"
],
"steps": [
{
"id": "tauri:run",
"label": "python scripts/publish-app.py --target tauri --tauri-bundles none",
"command": "python",
"args": [
"scripts/publish-app.py",
"--target",
"tauri",
"--tauri-bundles",
"none"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "webgateway",
"label": "Publish WebGateway",
"description": "Publish ASP.NET gateway",
"group": "Build",
"dependsOn": [
"web"
],
"steps": [
{
"id": "webgateway:run",
"label": "python scripts/publish-webgateway.py",
"command": "python",
"args": [
"scripts/publish-webgateway.py"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "sync-output",
"label": "Sync Output",
"description": "Sync newest artifacts to output",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "sync-output:run",
"label": "python scripts/sync-output.py",
"command": "python",
"args": [
"scripts/sync-output.py"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "stage-output",
"label": "Stage Output Bundle",
"description": "Publish and stage distributable output",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "stage-output:run",
"label": "python scripts/publish-output.py",
"command": "python",
"args": [
"scripts/publish-output.py"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "run-gateway-dev",
"label": "Run WebGateway Server (Dev)",
"description": "Run gateway in development mode",
"group": "Dev",
"dependsOn": [],
"steps": [
{
"id": "run-gateway-dev:run",
"label": "python scripts/run-webgateway.py --mode Dev",
"command": "python",
"args": [
"scripts/run-webgateway.py",
"--mode",
"Dev"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "build",
"label": "Build",
"description": "Build detected project stacks",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "dotnet-build",
"label": "dotnet build",
"command": null,
"args": [],
"workingDir": ".",
"action": "dotnet-build",
"actionArgs": [],
"requires": []
},
{
"id": "npm-build",
"label": "npm run build",
"command": null,
"args": [],
"workingDir": ".",
"action": "npm-build",
"actionArgs": [],
"requires": []
}
]
},
{
"id": "deps-refresh",
"label": "Refresh Dependencies",
"description": "Restore/install dependency stacks",
"group": "Deps",
"dependsOn": [],
"steps": [
{
"id": "dotnet-restore",
"label": "dotnet restore",
"command": null,
"args": [],
"workingDir": ".",
"action": "dotnet-restore",
"actionArgs": [],
"requires": []
},
{
"id": "npm-ci",
"label": "npm ci",
"command": null,
"args": [],
"workingDir": ".",
"action": "npm-ci",
"actionArgs": [],
"requires": []
}
]
},
{
"id": "test",
"label": "Run Tests",
"description": "Run detected test stacks",
"group": "Test",
"dependsOn": [],
"steps": [
{
"id": "dotnet-test",
"label": "dotnet test",
"command": null,
"args": [],
"workingDir": ".",
"action": "dotnet-test",
"actionArgs": [],
"requires": []
},
{
"id": "npm-test",
"label": "npm test",
"command": null,
"args": [],
"workingDir": ".",
"action": "npm-test",
"actionArgs": [],
"requires": []
},
{
"id": "python-pytest",
"label": "python -m pytest",
"command": null,
"args": [],
"workingDir": ".",
"action": "python-pytest",
"actionArgs": [],
"requires": []
}
]
}
],
"env": [
{
"key": "SDT_LOG_LEVEL",
"description": "CLI log verbosity",
"default": "information",
"options": [
"trace",
"debug",
"information",
"warning",
"error",
"critical"
]
},
{
"key": "SDT_ENV_PROFILE",
"description": "Active SDT runtime environment profile",
"default": "dev",
"options": [
"dev",
"ci",
"release"
]
}
],
"envProfiles": {
"active": "dev",
"profiles": [
{
"id": "dev",
"description": "Local development defaults",
"inherits": [],
"values": {
"SDT_ENV_PROFILE": "dev",
"SDT_LOG_LEVEL": "information"
}
},
{
"id": "ci",
"description": "Continuous integration defaults",
"inherits": [
"dev"
],
"values": {
"SDT_ENV_PROFILE": "ci",
"CI": "true",
"SDT_LOG_LEVEL": "warning"
}
},
{
"id": "release",
"description": "Release build defaults",
"inherits": [
"dev"
],
"values": {
"SDT_ENV_PROFILE": "release",
"SDT_LOG_LEVEL": "warning"
}
}
]
},
"toolchains": {
"python": {
"executable": "python",
"windowsExecutable": "py",
"launcherVersion": null,
"venvDir": ".venv",
"profiles": [],
"pipScript": null
},
"node": {
"packageManager": "npm",
"workingDir": "."
}
},
"tooling": {
"tools": [
{
"tool": "dotnet",
"preferredInstallCommands": [],
"executables": []
},
{
"tool": "node",
"preferredInstallCommands": [],
"executables": []
},
{
"tool": "npm",
"preferredInstallCommands": [],
"executables": []
},
{
"tool": "python",
"preferredInstallCommands": [],
"executables": []
}
]
},
"project": {
"type": "polyglot",
"rootHints": [
"*.sln",
"package.json",
"scripts"
],
"artifacts": [
"bin",
"obj",
".sdt/debug"
]
},
"debug": {
"profiles": [
{
"id": "dotnet-run",
"label": "Run .NET app",
"type": "dotnet",
"command": "dotnet",
"args": [
"run"
],
"workingDir": ".",
"env": {},
"requires": [
{
"tool": "dotnet",
"installPolicy": "Prompt"
}
],
"attach": {
"kind": "manual",
"port": null,
"processName": null,
"note": "Attach your IDE debugger to the running dotnet process."
}
},
{
"id": "npm-dev",
"label": "Run npm dev server",
"type": "node",
"command": "npm",
"args": [
"run",
"dev"
],
"workingDir": ".",
"env": {},
"requires": [
{
"tool": "node",
"installPolicy": "Prompt"
},
{
"tool": "npm",
"installPolicy": "Prompt"
}
],
"attach": null
}
],
"diagnostics": {
"enabled": true,
"outputDir": ".sdt/debug",
"includeAllEnv": false,
"captureEnvKeys": [
"SDT_LOG_LEVEL",
"DOTNET_CLI_HOME",
"NUGET_PACKAGES",
"PIP_CACHE_DIR",
"NVM_HOME",
"NVM_SYMLINK"
],
"redactSensitive": true,
"sensitiveKeyPatterns": [
"TOKEN",
"SECRET",
"PASSWORD",
"PWD",
"CREDENTIAL",
"API_KEY",
"ACCESS_KEY",
"PRIVATE_KEY"
],
"redactionAllowKeys": [],
"bundleOnFailure": true
}
}
}

View File

@ -0,0 +1,477 @@
{
"name": "DevTool-master",
"version": "0.1.0",
"targets": [],
"workflows": [
{
"id": "sidecar",
"label": "Publish Sidecar",
"description": "Publish sidecar service",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "sidecar:run",
"label": "python scripts/publish-sidecar.py",
"command": "python",
"args": [
"scripts/publish-sidecar.py"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "web",
"label": "Build Web UI",
"description": "Build frontend assets",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "web:run",
"label": "python scripts/publish-app.py --target web",
"command": "python",
"args": [
"scripts/publish-app.py",
"--target",
"web"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "tauri",
"label": "Build Tauri Desktop App",
"description": "Build desktop binary",
"group": "Build",
"dependsOn": [
"sidecar"
],
"steps": [
{
"id": "tauri:run",
"label": "python scripts/publish-app.py --target tauri --tauri-bundles none",
"command": "python",
"args": [
"scripts/publish-app.py",
"--target",
"tauri",
"--tauri-bundles",
"none"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "webgateway",
"label": "Publish WebGateway",
"description": "Publish ASP.NET gateway",
"group": "Build",
"dependsOn": [
"web"
],
"steps": [
{
"id": "webgateway:run",
"label": "python scripts/publish-webgateway.py",
"command": "python",
"args": [
"scripts/publish-webgateway.py"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "sync-output",
"label": "Sync Output",
"description": "Sync newest artifacts to output",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "sync-output:run",
"label": "python scripts/sync-output.py",
"command": "python",
"args": [
"scripts/sync-output.py"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "stage-output",
"label": "Stage Output Bundle",
"description": "Publish and stage distributable output",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "stage-output:run",
"label": "python scripts/publish-output.py",
"command": "python",
"args": [
"scripts/publish-output.py"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "run-gateway-dev",
"label": "Run WebGateway Server (Dev)",
"description": "Run gateway in development mode",
"group": "Dev",
"dependsOn": [],
"steps": [
{
"id": "run-gateway-dev:run",
"label": "python scripts/run-webgateway.py --mode Dev",
"command": "python",
"args": [
"scripts/run-webgateway.py",
"--mode",
"Dev"
],
"workingDir": ".",
"action": null,
"actionArgs": [],
"requires": [
{
"tool": "python",
"installPolicy": "Prompt"
}
]
}
]
},
{
"id": "build",
"label": "Build",
"description": "Build detected project stacks",
"group": "Build",
"dependsOn": [],
"steps": [
{
"id": "dotnet-build",
"label": "dotnet build",
"command": null,
"args": [],
"workingDir": ".",
"action": "dotnet-build",
"actionArgs": [],
"requires": []
},
{
"id": "npm-build",
"label": "npm run build",
"command": null,
"args": [],
"workingDir": ".",
"action": "npm-build",
"actionArgs": [],
"requires": []
}
]
},
{
"id": "deps-refresh",
"label": "Refresh Dependencies",
"description": "Restore/install dependency stacks",
"group": "Deps",
"dependsOn": [],
"steps": [
{
"id": "dotnet-restore",
"label": "dotnet restore",
"command": null,
"args": [],
"workingDir": ".",
"action": "dotnet-restore",
"actionArgs": [],
"requires": []
},
{
"id": "npm-ci",
"label": "npm ci",
"command": null,
"args": [],
"workingDir": ".",
"action": "npm-ci",
"actionArgs": [],
"requires": []
}
]
},
{
"id": "test",
"label": "Run Tests",
"description": "Run detected test stacks",
"group": "Test",
"dependsOn": [],
"steps": [
{
"id": "dotnet-test",
"label": "dotnet test",
"command": null,
"args": [],
"workingDir": ".",
"action": "dotnet-test",
"actionArgs": [],
"requires": []
},
{
"id": "npm-test",
"label": "npm test",
"command": null,
"args": [],
"workingDir": ".",
"action": "npm-test",
"actionArgs": [],
"requires": []
},
{
"id": "python-pytest",
"label": "python -m pytest",
"command": null,
"args": [],
"workingDir": ".",
"action": "python-pytest",
"actionArgs": [],
"requires": []
}
]
}
],
"env": [
{
"key": "SDT_LOG_LEVEL",
"description": "CLI log verbosity",
"default": "information",
"options": [
"trace",
"debug",
"information",
"warning",
"error",
"critical"
]
}
],
"envProfiles": {
"active": "dev",
"profiles": [
{
"id": "dev",
"description": "Local development defaults",
"inherits": [],
"values": {
"SDT_ENV_PROFILE": "dev",
"SDT_LOG_LEVEL": "information"
}
},
{
"id": "ci",
"description": "Continuous integration defaults",
"inherits": [
"dev"
],
"values": {
"SDT_ENV_PROFILE": "ci",
"CI": "true",
"SDT_LOG_LEVEL": "warning"
}
},
{
"id": "release",
"description": "Release build defaults",
"inherits": [
"dev"
],
"values": {
"SDT_ENV_PROFILE": "release",
"SDT_LOG_LEVEL": "warning"
}
}
]
},
"toolchains": {
"python": {
"executable": "python",
"windowsExecutable": "py",
"launcherVersion": null,
"venvDir": ".venv",
"profiles": [],
"pipScript": null
},
"node": {
"packageManager": "npm",
"workingDir": "."
}
},
"tooling": {
"tools": [
{
"tool": "dotnet",
"preferredInstallCommands": [],
"executables": []
},
{
"tool": "node",
"preferredInstallCommands": [],
"executables": []
},
{
"tool": "npm",
"preferredInstallCommands": [],
"executables": []
},
{
"tool": "python",
"preferredInstallCommands": [],
"executables": []
}
]
},
"project": {
"type": "polyglot",
"rootHints": [
"*.sln",
"package.json",
"scripts"
],
"artifacts": [
"bin",
"obj",
".sdt/debug"
]
},
"debug": {
"profiles": [
{
"id": "dotnet-run",
"label": "Run .NET app",
"type": "dotnet",
"command": "dotnet",
"args": [
"run"
],
"workingDir": ".",
"env": {},
"requires": [
{
"tool": "dotnet",
"installPolicy": "Prompt"
}
],
"attach": {
"kind": "manual",
"port": null,
"processName": null,
"note": "Attach your IDE debugger to the running dotnet process."
}
},
{
"id": "npm-dev",
"label": "Run npm dev server",
"type": "node",
"command": "npm",
"args": [
"run",
"dev"
],
"workingDir": ".",
"env": {},
"requires": [
{
"tool": "node",
"installPolicy": "Prompt"
},
{
"tool": "npm",
"installPolicy": "Prompt"
}
],
"attach": null
}
],
"diagnostics": {
"enabled": true,
"outputDir": ".sdt/debug",
"includeAllEnv": false,
"captureEnvKeys": [
"SDT_LOG_LEVEL",
"DOTNET_CLI_HOME",
"NUGET_PACKAGES",
"PIP_CACHE_DIR",
"NVM_HOME",
"NVM_SYMLINK"
],
"redactSensitive": true,
"sensitiveKeyPatterns": [
"TOKEN",
"SECRET",
"PASSWORD",
"PWD",
"CREDENTIAL",
"API_KEY",
"ACCESS_KEY",
"PRIVATE_KEY"
],
"redactionAllowKeys": [],
"bundleOnFailure": true
}
}
}

33
docs/matrix-status.md Normal file
View File

@ -0,0 +1,33 @@
# SDT Matrix Status (v1.4)
## Scope
- Required for this milestone: Windows, Linux
- Delegated/blocked: macOS
## Current Status
- Windows: local verification expected by maintainer
- Linux: local/native verification expected by maintainer
- macOS: delegated to collaborator (pending)
## macOS Delegation Checklist
1. Build and run SDT from a clean checkout.
2. Execute representative workflows for:
- dotnet
- node/npm
- cargo/tauri (if available)
3. Capture and submit artifacts:
- `.sdt/events/*.jsonl`
- `.sdt/debug/*/summary.json`
- `.sdt/debug/*/tools.json`
- pass/fail table by workflow
4. Record any path, resolver, or install-plan differences.
## Artifact Format
- `events`: run timeline and lifecycle transitions
- `summary`: stop reason / exit code contract validation
- `tools`: probe and resolver trace validation
- `results`: markdown table with workflow, status, and notes

View File

@ -0,0 +1,19 @@
# SDT Reliability Matrix Results
## Latest Baseline
- Status: pending first full CI matrix run
- Workflow: `.github/workflows/reliability-matrix.yml`
- Last updated: 2026-03-01
## Results Log
| Date (UTC) | Commit | Run ID | Windows | Linux | macOS | Notes |
|---|---|---|---|---|---|---|
| 2026-03-01 | pending | pending | pending | pending | pending | Initial v1.3 matrix workflow added; awaiting first run. |
## Notes
- A result row should only be marked `pass` when both tests and artifact generation succeed for that OS.
- Any flaky behavior should be recorded in Notes with a link/reference to the failing artifact.

View File

@ -0,0 +1,69 @@
# SDT Reliability Matrix Runbook
## Purpose
Run and track SDT reliability verification across:
- Windows
- Linux
- macOS
with deterministic pass/fail outcomes for core orchestration flows.
## Matrix Scope
### Project-Type Coverage
- `dotnet`
- `node/npm`
- `tauri/cargo`
### Validation Categories
- workflow planning/execution determinism
- prerequisite probe/install gating behavior
- versioned event JSON contract validity
- diagnostics bundle generation on failure
- deterministic stop reason and exit-code mapping
## Execution Paths
### CI (Preferred)
Use the GitHub Actions workflow:
- `.github/workflows/reliability-matrix.yml`
Triggers:
- pull requests
- pushes to `main`
- manual `workflow_dispatch`
Expected artifacts per OS:
- `test-results.trx`
- `reliability-<os>.json`
### Local Spot Checks
Run:
```powershell
dotnet build DevTool.csproj -c Release
dotnet test tests/DevTool.Tests/DevTool.Tests.csproj -c Release
```
## Result Recording
After each CI matrix run:
1. Collect uploaded artifacts for all OS jobs.
2. Update `docs/reliability-matrix-results.md` with:
- commit SHA
- run id
- per-OS status
- notes on failures/flakes
3. If any OS fails:
- open/attach issue with failing artifact references
- do not mark matrix item complete in `ROADMAP.md`
## Completion Criteria
Matrix verification is considered complete when:
1. A full CI run passes on all three OS runners.
2. Results are logged in `docs/reliability-matrix-results.md`.
3. `ROADMAP.md` matrix checkboxes are updated accordingly.

26
node_modules/.package-lock.json generated vendored Normal file
View File

@ -0,0 +1,26 @@
{
"name": "DevTool-master",
"lockfileVersion": 3,
"requires": true,
"packages": {
"node_modules/@tauri-apps/api": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz",
"integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==",
"license": "Apache-2.0 OR MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tauri"
}
},
"node_modules/tauri-plugin-mic-recorder-api": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tauri-plugin-mic-recorder-api/-/tauri-plugin-mic-recorder-api-2.0.0.tgz",
"integrity": "sha512-04wqYCX4WIlYd6KUY7aS3+W4B5RtnSoVczaQCBSXKpQkEx9XdaaBN05XCee2unxGva0btSXBItFqQSdosnS4jQ==",
"license": "MIT",
"dependencies": {
"@tauri-apps/api": ">=2.0.0-beta.6"
}
}
}
}

1
node_modules/.sdt-deps.sha256 generated vendored Normal file
View File

@ -0,0 +1 @@
9241cd740a6b6aa9ccbad93df22cafe05a801f777e6113df8118981c3a438e58

1041
node_modules/@tauri-apps/api/CHANGELOG.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

177
node_modules/@tauri-apps/api/LICENSE_APACHE-2.0 generated vendored Normal file
View File

@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

21
node_modules/@tauri-apps/api/LICENSE_MIT generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 - Present Tauri Apps Contributors
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.

52
node_modules/@tauri-apps/api/README.md generated vendored Normal file
View File

@ -0,0 +1,52 @@
# @tauri-apps/api
<img align="right" src="https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" height="128" width="128">
[![status](https://img.shields.io/badge/status-stable-blue.svg)](https://github.com/tauri-apps/tauri/tree/dev)
[![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg)](https://opencollective.com/tauri)
[![lint js](https://img.shields.io/github/actions/workflow/status/tauri-apps/tauri/lint-js.yml?label=lint%20js&logo=github)](https://github.com/tauri-apps/tauri/actions/workflows/lint-js.yml)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri?ref=badge_shield)
[![Chat Server](https://img.shields.io/badge/chat-discord-7289da.svg)](https://discord.gg/SpmNs4S)
[![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app)
[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation)
[![support](https://img.shields.io/badge/sponsor-Open%20Collective-blue.svg)](https://opencollective.com/tauri)
| Component | Version |
| --------------- | ----------------------------------------------------- |
| @tauri-apps/api | ![](https://img.shields.io/npm/v/@tauri-apps/api.svg) |
## About Tauri
Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily.
Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task.
## This module
This is a typescript library that creates `cjs` and `esm` JavaScript endpoints for you to import into your Frontend framework so that the Webview can call and listen to backend activity. We also ship the pure typescript, because for some frameworks this is more optimal. It uses the message passing of webviews to their hosts.
To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document.
## Installation
The preferred method is to install this module locally as a dependency:
```
$ pnpm add @tauri-apps/api
$ yarn add @tauri-apps/api
$ npm add @tauri-apps/api
```
## Semver
**tauri** is following [Semantic Versioning 2.0](https://semver.org/).
## Licenses
Code: (c) 2019 - 2021 - The Tauri Programme within The Commons Conservancy.
MIT or MIT/Apache 2.0 where applicable.
Logo: CC-BY-NC-ND
- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum)

235
node_modules/@tauri-apps/api/app.cjs generated vendored Normal file
View File

@ -0,0 +1,235 @@
'use strict';
var core = require('./core.cjs');
var image = require('./image.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Bundle type of the current application.
*/
exports.BundleType = void 0;
(function (BundleType) {
/** Windows NSIS */
BundleType["Nsis"] = "nsis";
/** Windows MSI */
BundleType["Msi"] = "msi";
/** Linux Debian package */
BundleType["Deb"] = "deb";
/** Linux RPM */
BundleType["Rpm"] = "rpm";
/** Linux AppImage */
BundleType["AppImage"] = "appimage";
/** macOS app bundle */
BundleType["App"] = "app";
})(exports.BundleType || (exports.BundleType = {}));
/**
* Application metadata and related APIs.
*
* @module
*/
/**
* Gets the application version.
* @example
* ```typescript
* import { getVersion } from '@tauri-apps/api/app';
* const appVersion = await getVersion();
* ```
*
* @since 1.0.0
*/
async function getVersion() {
return core.invoke('plugin:app|version');
}
/**
* Gets the application name.
* @example
* ```typescript
* import { getName } from '@tauri-apps/api/app';
* const appName = await getName();
* ```
*
* @since 1.0.0
*/
async function getName() {
return core.invoke('plugin:app|name');
}
/**
* Gets the Tauri framework version used by this application.
*
* @example
* ```typescript
* import { getTauriVersion } from '@tauri-apps/api/app';
* const tauriVersion = await getTauriVersion();
* ```
*
* @since 1.0.0
*/
async function getTauriVersion() {
return core.invoke('plugin:app|tauri_version');
}
/**
* Gets the application identifier.
* @example
* ```typescript
* import { getIdentifier } from '@tauri-apps/api/app';
* const identifier = await getIdentifier();
* ```
*
* @returns The application identifier as configured in `tauri.conf.json`.
*
* @since 2.4.0
*/
async function getIdentifier() {
return core.invoke('plugin:app|identifier');
}
/**
* Shows the application on macOS. This function does not automatically
* focus any specific app window.
*
* @example
* ```typescript
* import { show } from '@tauri-apps/api/app';
* await show();
* ```
*
* @since 1.2.0
*/
async function show() {
return core.invoke('plugin:app|app_show');
}
/**
* Hides the application on macOS.
*
* @example
* ```typescript
* import { hide } from '@tauri-apps/api/app';
* await hide();
* ```
*
* @since 1.2.0
*/
async function hide() {
return core.invoke('plugin:app|app_hide');
}
/**
* Fetches the data store identifiers on macOS and iOS.
*
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
*
* @example
* ```typescript
* import { fetchDataStoreIdentifiers } from '@tauri-apps/api/app';
* const ids = await fetchDataStoreIdentifiers();
* ```
*
* @since 2.4.0
*/
async function fetchDataStoreIdentifiers() {
return core.invoke('plugin:app|fetch_data_store_identifiers');
}
/**
* Removes the data store with the given identifier.
*
* Note that any webview using this data store should be closed before running this API.
*
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
*
* @example
* ```typescript
* import { fetchDataStoreIdentifiers, removeDataStore } from '@tauri-apps/api/app';
* for (const id of (await fetchDataStoreIdentifiers())) {
* await removeDataStore(id);
* }
* ```
*
* @since 2.4.0
*/
async function removeDataStore(uuid) {
return core.invoke('plugin:app|remove_data_store', { uuid });
}
/**
* Gets the default window icon.
*
* @example
* ```typescript
* import { defaultWindowIcon } from '@tauri-apps/api/app';
* const icon = await defaultWindowIcon();
* ```
*
* @since 2.0.0
*/
async function defaultWindowIcon() {
return core.invoke('plugin:app|default_window_icon').then((rid) => rid ? new image.Image(rid) : null);
}
/**
* Sets the application's theme. Pass in `null` or `undefined` to follow
* the system theme.
*
* @example
* ```typescript
* import { setTheme } from '@tauri-apps/api/app';
* await setTheme('dark');
* ```
*
* #### Platform-specific
*
* - **iOS / Android:** Unsupported.
*
* @since 2.0.0
*/
async function setTheme(theme) {
return core.invoke('plugin:app|set_app_theme', { theme });
}
/**
* Sets the dock visibility for the application on macOS.
*
* @param visible - Whether the dock should be visible or not.
*
* @example
* ```typescript
* import { setDockVisibility } from '@tauri-apps/api/app';
* await setDockVisibility(false);
* ```
*
* @since 2.5.0
*/
async function setDockVisibility(visible) {
return core.invoke('plugin:app|set_dock_visibility', { visible });
}
/**
* Gets the application bundle type.
*
* @example
* ```typescript
* import { getBundleType } from '@tauri-apps/api/app';
* const type = await getBundleType();
* ```
*
* @since 2.5.0
*/
async function getBundleType() {
return core.invoke('plugin:app|bundle_type');
}
/**
* Listens to the backButton event on Android.
* @param handler
*/
async function onBackButtonPress(handler) {
return core.addPluginListener('app', 'back-button', handler);
}
exports.defaultWindowIcon = defaultWindowIcon;
exports.fetchDataStoreIdentifiers = fetchDataStoreIdentifiers;
exports.getBundleType = getBundleType;
exports.getIdentifier = getIdentifier;
exports.getName = getName;
exports.getTauriVersion = getTauriVersion;
exports.getVersion = getVersion;
exports.hide = hide;
exports.onBackButtonPress = onBackButtonPress;
exports.removeDataStore = removeDataStore;
exports.setDockVisibility = setDockVisibility;
exports.setTheme = setTheme;
exports.show = show;

220
node_modules/@tauri-apps/api/app.d.ts generated vendored Normal file
View File

@ -0,0 +1,220 @@
import { PluginListener } from './core';
import { Image } from './image';
import { Theme } from './window';
/**
* Identifier type used for data stores on macOS and iOS.
*
* Represents a 128-bit identifier, commonly expressed as a 16-byte UUID.
*/
export type DataStoreIdentifier = [
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number,
number
];
/**
* Bundle type of the current application.
*/
export declare enum BundleType {
/** Windows NSIS */
Nsis = "nsis",
/** Windows MSI */
Msi = "msi",
/** Linux Debian package */
Deb = "deb",
/** Linux RPM */
Rpm = "rpm",
/** Linux AppImage */
AppImage = "appimage",
/** macOS app bundle */
App = "app"
}
/**
* Application metadata and related APIs.
*
* @module
*/
/**
* Gets the application version.
* @example
* ```typescript
* import { getVersion } from '@tauri-apps/api/app';
* const appVersion = await getVersion();
* ```
*
* @since 1.0.0
*/
declare function getVersion(): Promise<string>;
/**
* Gets the application name.
* @example
* ```typescript
* import { getName } from '@tauri-apps/api/app';
* const appName = await getName();
* ```
*
* @since 1.0.0
*/
declare function getName(): Promise<string>;
/**
* Gets the Tauri framework version used by this application.
*
* @example
* ```typescript
* import { getTauriVersion } from '@tauri-apps/api/app';
* const tauriVersion = await getTauriVersion();
* ```
*
* @since 1.0.0
*/
declare function getTauriVersion(): Promise<string>;
/**
* Gets the application identifier.
* @example
* ```typescript
* import { getIdentifier } from '@tauri-apps/api/app';
* const identifier = await getIdentifier();
* ```
*
* @returns The application identifier as configured in `tauri.conf.json`.
*
* @since 2.4.0
*/
declare function getIdentifier(): Promise<string>;
/**
* Shows the application on macOS. This function does not automatically
* focus any specific app window.
*
* @example
* ```typescript
* import { show } from '@tauri-apps/api/app';
* await show();
* ```
*
* @since 1.2.0
*/
declare function show(): Promise<void>;
/**
* Hides the application on macOS.
*
* @example
* ```typescript
* import { hide } from '@tauri-apps/api/app';
* await hide();
* ```
*
* @since 1.2.0
*/
declare function hide(): Promise<void>;
/**
* Fetches the data store identifiers on macOS and iOS.
*
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
*
* @example
* ```typescript
* import { fetchDataStoreIdentifiers } from '@tauri-apps/api/app';
* const ids = await fetchDataStoreIdentifiers();
* ```
*
* @since 2.4.0
*/
declare function fetchDataStoreIdentifiers(): Promise<DataStoreIdentifier[]>;
/**
* Removes the data store with the given identifier.
*
* Note that any webview using this data store should be closed before running this API.
*
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
*
* @example
* ```typescript
* import { fetchDataStoreIdentifiers, removeDataStore } from '@tauri-apps/api/app';
* for (const id of (await fetchDataStoreIdentifiers())) {
* await removeDataStore(id);
* }
* ```
*
* @since 2.4.0
*/
declare function removeDataStore(uuid: DataStoreIdentifier): Promise<void>;
/**
* Gets the default window icon.
*
* @example
* ```typescript
* import { defaultWindowIcon } from '@tauri-apps/api/app';
* const icon = await defaultWindowIcon();
* ```
*
* @since 2.0.0
*/
declare function defaultWindowIcon(): Promise<Image | null>;
/**
* Sets the application's theme. Pass in `null` or `undefined` to follow
* the system theme.
*
* @example
* ```typescript
* import { setTheme } from '@tauri-apps/api/app';
* await setTheme('dark');
* ```
*
* #### Platform-specific
*
* - **iOS / Android:** Unsupported.
*
* @since 2.0.0
*/
declare function setTheme(theme?: Theme | null): Promise<void>;
/**
* Sets the dock visibility for the application on macOS.
*
* @param visible - Whether the dock should be visible or not.
*
* @example
* ```typescript
* import { setDockVisibility } from '@tauri-apps/api/app';
* await setDockVisibility(false);
* ```
*
* @since 2.5.0
*/
declare function setDockVisibility(visible: boolean): Promise<void>;
/**
* Gets the application bundle type.
*
* @example
* ```typescript
* import { getBundleType } from '@tauri-apps/api/app';
* const type = await getBundleType();
* ```
*
* @since 2.5.0
*/
declare function getBundleType(): Promise<BundleType>;
/**
* Payload for the onBackButtonPress event.
*/
type OnBackButtonPressPayload = {
/** Whether the webview canGoBack property is true. */
canGoBack: boolean;
};
/**
* Listens to the backButton event on Android.
* @param handler
*/
declare function onBackButtonPress(handler: (payload: OnBackButtonPressPayload) => void): Promise<PluginListener>;
export { getName, getVersion, getTauriVersion, getIdentifier, show, hide, defaultWindowIcon, setTheme, fetchDataStoreIdentifiers, removeDataStore, setDockVisibility, getBundleType, type OnBackButtonPressPayload, onBackButtonPress };

221
node_modules/@tauri-apps/api/app.js generated vendored Normal file
View File

@ -0,0 +1,221 @@
import { invoke, addPluginListener } from './core.js';
import { Image } from './image.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Bundle type of the current application.
*/
var BundleType;
(function (BundleType) {
/** Windows NSIS */
BundleType["Nsis"] = "nsis";
/** Windows MSI */
BundleType["Msi"] = "msi";
/** Linux Debian package */
BundleType["Deb"] = "deb";
/** Linux RPM */
BundleType["Rpm"] = "rpm";
/** Linux AppImage */
BundleType["AppImage"] = "appimage";
/** macOS app bundle */
BundleType["App"] = "app";
})(BundleType || (BundleType = {}));
/**
* Application metadata and related APIs.
*
* @module
*/
/**
* Gets the application version.
* @example
* ```typescript
* import { getVersion } from '@tauri-apps/api/app';
* const appVersion = await getVersion();
* ```
*
* @since 1.0.0
*/
async function getVersion() {
return invoke('plugin:app|version');
}
/**
* Gets the application name.
* @example
* ```typescript
* import { getName } from '@tauri-apps/api/app';
* const appName = await getName();
* ```
*
* @since 1.0.0
*/
async function getName() {
return invoke('plugin:app|name');
}
/**
* Gets the Tauri framework version used by this application.
*
* @example
* ```typescript
* import { getTauriVersion } from '@tauri-apps/api/app';
* const tauriVersion = await getTauriVersion();
* ```
*
* @since 1.0.0
*/
async function getTauriVersion() {
return invoke('plugin:app|tauri_version');
}
/**
* Gets the application identifier.
* @example
* ```typescript
* import { getIdentifier } from '@tauri-apps/api/app';
* const identifier = await getIdentifier();
* ```
*
* @returns The application identifier as configured in `tauri.conf.json`.
*
* @since 2.4.0
*/
async function getIdentifier() {
return invoke('plugin:app|identifier');
}
/**
* Shows the application on macOS. This function does not automatically
* focus any specific app window.
*
* @example
* ```typescript
* import { show } from '@tauri-apps/api/app';
* await show();
* ```
*
* @since 1.2.0
*/
async function show() {
return invoke('plugin:app|app_show');
}
/**
* Hides the application on macOS.
*
* @example
* ```typescript
* import { hide } from '@tauri-apps/api/app';
* await hide();
* ```
*
* @since 1.2.0
*/
async function hide() {
return invoke('plugin:app|app_hide');
}
/**
* Fetches the data store identifiers on macOS and iOS.
*
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
*
* @example
* ```typescript
* import { fetchDataStoreIdentifiers } from '@tauri-apps/api/app';
* const ids = await fetchDataStoreIdentifiers();
* ```
*
* @since 2.4.0
*/
async function fetchDataStoreIdentifiers() {
return invoke('plugin:app|fetch_data_store_identifiers');
}
/**
* Removes the data store with the given identifier.
*
* Note that any webview using this data store should be closed before running this API.
*
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore for more information.
*
* @example
* ```typescript
* import { fetchDataStoreIdentifiers, removeDataStore } from '@tauri-apps/api/app';
* for (const id of (await fetchDataStoreIdentifiers())) {
* await removeDataStore(id);
* }
* ```
*
* @since 2.4.0
*/
async function removeDataStore(uuid) {
return invoke('plugin:app|remove_data_store', { uuid });
}
/**
* Gets the default window icon.
*
* @example
* ```typescript
* import { defaultWindowIcon } from '@tauri-apps/api/app';
* const icon = await defaultWindowIcon();
* ```
*
* @since 2.0.0
*/
async function defaultWindowIcon() {
return invoke('plugin:app|default_window_icon').then((rid) => rid ? new Image(rid) : null);
}
/**
* Sets the application's theme. Pass in `null` or `undefined` to follow
* the system theme.
*
* @example
* ```typescript
* import { setTheme } from '@tauri-apps/api/app';
* await setTheme('dark');
* ```
*
* #### Platform-specific
*
* - **iOS / Android:** Unsupported.
*
* @since 2.0.0
*/
async function setTheme(theme) {
return invoke('plugin:app|set_app_theme', { theme });
}
/**
* Sets the dock visibility for the application on macOS.
*
* @param visible - Whether the dock should be visible or not.
*
* @example
* ```typescript
* import { setDockVisibility } from '@tauri-apps/api/app';
* await setDockVisibility(false);
* ```
*
* @since 2.5.0
*/
async function setDockVisibility(visible) {
return invoke('plugin:app|set_dock_visibility', { visible });
}
/**
* Gets the application bundle type.
*
* @example
* ```typescript
* import { getBundleType } from '@tauri-apps/api/app';
* const type = await getBundleType();
* ```
*
* @since 2.5.0
*/
async function getBundleType() {
return invoke('plugin:app|bundle_type');
}
/**
* Listens to the backButton event on Android.
* @param handler
*/
async function onBackButtonPress(handler) {
return addPluginListener('app', 'back-button', handler);
}
export { BundleType, defaultWindowIcon, fetchDataStoreIdentifiers, getBundleType, getIdentifier, getName, getTauriVersion, getVersion, hide, onBackButtonPress, removeDataStore, setDockVisibility, setTheme, show };

295
node_modules/@tauri-apps/api/core.cjs generated vendored Normal file
View File

@ -0,0 +1,295 @@
'use strict';
var tslib_es6 = require('./external/tslib/tslib.es6.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
var _Channel_onmessage, _Channel_nextMessageIndex, _Channel_pendingMessages, _Channel_messageEndIndex, _Resource_rid;
/**
* Invoke your custom commands.
*
* This package is also accessible with `window.__TAURI__.core` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/
/**
* A key to be used to implement a special function
* on your types that define how your type should be serialized
* when passing across the IPC.
* @example
* Given a type in Rust that looks like this
* ```rs
* #[derive(serde::Serialize, serde::Deserialize)
* enum UserId {
* String(String),
* Number(u32),
* }
* ```
* `UserId::String("id")` would be serialized into `{ String: "id" }`
* and so we need to pass the same structure back to Rust
* ```ts
* import { SERIALIZE_TO_IPC_FN } from "@tauri-apps/api/core"
*
* class UserIdString {
* id
* constructor(id) {
* this.id = id
* }
*
* [SERIALIZE_TO_IPC_FN]() {
* return { String: this.id }
* }
* }
*
* class UserIdNumber {
* id
* constructor(id) {
* this.id = id
* }
*
* [SERIALIZE_TO_IPC_FN]() {
* return { Number: this.id }
* }
* }
*
* type UserId = UserIdString | UserIdNumber
* ```
*
*/
// if this value changes, make sure to update it in:
// 1. ipc.js
// 2. process-ipc-message-fn.js
const SERIALIZE_TO_IPC_FN = '__TAURI_TO_IPC_KEY__';
/**
* Stores the callback in a known location, and returns an identifier that can be passed to the backend.
* The backend uses the identifier to `eval()` the callback.
*
* @return An unique identifier associated with the callback function.
*
* @since 1.0.0
*/
function transformCallback(
// TODO: Make this not optional in v3
callback, once = false) {
return window.__TAURI_INTERNALS__.transformCallback(callback, once);
}
class Channel {
constructor(onmessage) {
_Channel_onmessage.set(this, void 0);
// the index is used as a mechanism to preserve message order
_Channel_nextMessageIndex.set(this, 0);
_Channel_pendingMessages.set(this, []);
_Channel_messageEndIndex.set(this, void 0);
tslib_es6.__classPrivateFieldSet(this, _Channel_onmessage, onmessage || (() => { }), "f");
this.id = transformCallback((rawMessage) => {
const index = rawMessage.index;
if ('end' in rawMessage) {
if (index == tslib_es6.__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f")) {
this.cleanupCallback();
}
else {
tslib_es6.__classPrivateFieldSet(this, _Channel_messageEndIndex, index, "f");
}
return;
}
const message = rawMessage.message;
// Process the message if we're at the right order
if (index == tslib_es6.__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f")) {
tslib_es6.__classPrivateFieldGet(this, _Channel_onmessage, "f").call(this, message);
tslib_es6.__classPrivateFieldSet(this, _Channel_nextMessageIndex, tslib_es6.__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f") + 1, "f");
// process pending messages
while (tslib_es6.__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f") in tslib_es6.__classPrivateFieldGet(this, _Channel_pendingMessages, "f")) {
const message = tslib_es6.__classPrivateFieldGet(this, _Channel_pendingMessages, "f")[tslib_es6.__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f")];
tslib_es6.__classPrivateFieldGet(this, _Channel_onmessage, "f").call(this, message);
// eslint-disable-next-line @typescript-eslint/no-array-delete
delete tslib_es6.__classPrivateFieldGet(this, _Channel_pendingMessages, "f")[tslib_es6.__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f")];
tslib_es6.__classPrivateFieldSet(this, _Channel_nextMessageIndex, tslib_es6.__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f") + 1, "f");
}
if (tslib_es6.__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f") === tslib_es6.__classPrivateFieldGet(this, _Channel_messageEndIndex, "f")) {
this.cleanupCallback();
}
}
// Queue the message if we're not
else {
// eslint-disable-next-line security/detect-object-injection
tslib_es6.__classPrivateFieldGet(this, _Channel_pendingMessages, "f")[index] = message;
}
});
}
cleanupCallback() {
window.__TAURI_INTERNALS__.unregisterCallback(this.id);
}
set onmessage(handler) {
tslib_es6.__classPrivateFieldSet(this, _Channel_onmessage, handler, "f");
}
get onmessage() {
return tslib_es6.__classPrivateFieldGet(this, _Channel_onmessage, "f");
}
[(_Channel_onmessage = new WeakMap(), _Channel_nextMessageIndex = new WeakMap(), _Channel_pendingMessages = new WeakMap(), _Channel_messageEndIndex = new WeakMap(), SERIALIZE_TO_IPC_FN)]() {
return `__CHANNEL__:${this.id}`;
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[SERIALIZE_TO_IPC_FN]();
}
}
class PluginListener {
constructor(plugin, event, channelId) {
this.plugin = plugin;
this.event = event;
this.channelId = channelId;
}
async unregister() {
return invoke(`plugin:${this.plugin}|remove_listener`, {
event: this.event,
channelId: this.channelId
});
}
}
/**
* Adds a listener to a plugin event.
*
* @returns The listener object to stop listening to the events.
*
* @since 2.0.0
*/
async function addPluginListener(plugin, event, cb) {
const handler = new Channel(cb);
try {
await invoke(`plugin:${plugin}|register_listener`, {
event,
handler
});
return new PluginListener(plugin, event, handler.id);
}
catch {
// TODO(v3): remove this fallback
// note: we must try with camelCase here for backwards compatibility
await invoke(`plugin:${plugin}|registerListener`, { event, handler });
return new PluginListener(plugin, event, handler.id);
}
}
/**
* Get permission state for a plugin.
*
* This should be used by plugin authors to wrap their actual implementation.
*/
async function checkPermissions(plugin) {
return invoke(`plugin:${plugin}|check_permissions`);
}
/**
* Request permissions.
*
* This should be used by plugin authors to wrap their actual implementation.
*/
async function requestPermissions(plugin) {
return invoke(`plugin:${plugin}|request_permissions`);
}
/**
* Sends a message to the backend.
* @example
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* await invoke('login', { user: 'tauri', password: 'poiwe3h4r5ip3yrhtew9ty' });
* ```
*
* @param cmd The command name.
* @param args The optional arguments to pass to the command.
* @param options The request options.
* @return A promise resolving or rejecting to the backend response.
*
* @since 1.0.0
*/
async function invoke(cmd, args = {}, options) {
return window.__TAURI_INTERNALS__.invoke(cmd, args, options);
}
/**
* Convert a device file path to an URL that can be loaded by the webview.
* Note that `asset:` and `http://asset.localhost` must be added to [`app.security.csp`](https://v2.tauri.app/reference/config/#csp-1) in `tauri.conf.json`.
* Example CSP value: `"csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost"` to use the asset protocol on image sources.
*
* Additionally, `"enable" : "true"` must be added to [`app.security.assetProtocol`](https://v2.tauri.app/reference/config/#assetprotocolconfig)
* in `tauri.conf.json` and its access scope must be defined on the `scope` array on the same `assetProtocol` object.
*
* @param filePath The file path.
* @param protocol The protocol to use. Defaults to `asset`. You only need to set this when using a custom protocol.
* @example
* ```typescript
* import { appDataDir, join } from '@tauri-apps/api/path';
* import { convertFileSrc } from '@tauri-apps/api/core';
* const appDataDirPath = await appDataDir();
* const filePath = await join(appDataDirPath, 'assets/video.mp4');
* const assetUrl = convertFileSrc(filePath);
*
* const video = document.getElementById('my-video');
* const source = document.createElement('source');
* source.type = 'video/mp4';
* source.src = assetUrl;
* video.appendChild(source);
* video.load();
* ```
*
* @return the URL that can be used as source on the webview.
*
* @since 1.0.0
*/
function convertFileSrc(filePath, protocol = 'asset') {
return window.__TAURI_INTERNALS__.convertFileSrc(filePath, protocol);
}
/**
* A rust-backed resource stored through `tauri::Manager::resources_table` API.
*
* The resource lives in the main process and does not exist
* in the Javascript world, and thus will not be cleaned up automatically
* except on application exit. If you want to clean it up early, call {@linkcode Resource.close}
*
* @example
* ```typescript
* import { Resource, invoke } from '@tauri-apps/api/core';
* export class DatabaseHandle extends Resource {
* static async open(path: string): Promise<DatabaseHandle> {
* const rid: number = await invoke('open_db', { path });
* return new DatabaseHandle(rid);
* }
*
* async execute(sql: string): Promise<void> {
* await invoke('execute_sql', { rid: this.rid, sql });
* }
* }
* ```
*/
class Resource {
get rid() {
return tslib_es6.__classPrivateFieldGet(this, _Resource_rid, "f");
}
constructor(rid) {
_Resource_rid.set(this, void 0);
tslib_es6.__classPrivateFieldSet(this, _Resource_rid, rid, "f");
}
/**
* Destroys and cleans up this resource from memory.
* **You should not call any method on this object anymore and should drop any reference to it.**
*/
async close() {
return invoke('plugin:resources|close', {
rid: this.rid
});
}
}
_Resource_rid = new WeakMap();
function isTauri() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
return !!(globalThis || window).isTauri;
}
exports.Channel = Channel;
exports.PluginListener = PluginListener;
exports.Resource = Resource;
exports.SERIALIZE_TO_IPC_FN = SERIALIZE_TO_IPC_FN;
exports.addPluginListener = addPluginListener;
exports.checkPermissions = checkPermissions;
exports.convertFileSrc = convertFileSrc;
exports.invoke = invoke;
exports.isTauri = isTauri;
exports.requestPermissions = requestPermissions;
exports.transformCallback = transformCallback;

193
node_modules/@tauri-apps/api/core.d.ts generated vendored Normal file
View File

@ -0,0 +1,193 @@
/**
* Invoke your custom commands.
*
* This package is also accessible with `window.__TAURI__.core` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/
/**
* A key to be used to implement a special function
* on your types that define how your type should be serialized
* when passing across the IPC.
* @example
* Given a type in Rust that looks like this
* ```rs
* #[derive(serde::Serialize, serde::Deserialize)
* enum UserId {
* String(String),
* Number(u32),
* }
* ```
* `UserId::String("id")` would be serialized into `{ String: "id" }`
* and so we need to pass the same structure back to Rust
* ```ts
* import { SERIALIZE_TO_IPC_FN } from "@tauri-apps/api/core"
*
* class UserIdString {
* id
* constructor(id) {
* this.id = id
* }
*
* [SERIALIZE_TO_IPC_FN]() {
* return { String: this.id }
* }
* }
*
* class UserIdNumber {
* id
* constructor(id) {
* this.id = id
* }
*
* [SERIALIZE_TO_IPC_FN]() {
* return { Number: this.id }
* }
* }
*
* type UserId = UserIdString | UserIdNumber
* ```
*
*/
export declare const SERIALIZE_TO_IPC_FN = "__TAURI_TO_IPC_KEY__";
/**
* Stores the callback in a known location, and returns an identifier that can be passed to the backend.
* The backend uses the identifier to `eval()` the callback.
*
* @return An unique identifier associated with the callback function.
*
* @since 1.0.0
*/
declare function transformCallback<T = unknown>(callback?: (response: T) => void, once?: boolean): number;
declare class Channel<T = unknown> {
#private;
/** The callback id returned from {@linkcode transformCallback} */
id: number;
constructor(onmessage?: (response: T) => void);
private cleanupCallback;
set onmessage(handler: (response: T) => void);
get onmessage(): (response: T) => void;
[SERIALIZE_TO_IPC_FN](): string;
toJSON(): string;
}
declare class PluginListener {
plugin: string;
event: string;
channelId: number;
constructor(plugin: string, event: string, channelId: number);
unregister(): Promise<void>;
}
/**
* Adds a listener to a plugin event.
*
* @returns The listener object to stop listening to the events.
*
* @since 2.0.0
*/
declare function addPluginListener<T>(plugin: string, event: string, cb: (payload: T) => void): Promise<PluginListener>;
type PermissionState = 'granted' | 'denied' | 'prompt' | 'prompt-with-rationale';
/**
* Get permission state for a plugin.
*
* This should be used by plugin authors to wrap their actual implementation.
*/
declare function checkPermissions<T>(plugin: string): Promise<T>;
/**
* Request permissions.
*
* This should be used by plugin authors to wrap their actual implementation.
*/
declare function requestPermissions<T>(plugin: string): Promise<T>;
/**
* Command arguments.
*
* @since 1.0.0
*/
type InvokeArgs = Record<string, unknown> | number[] | ArrayBuffer | Uint8Array;
/**
* @since 2.0.0
*/
interface InvokeOptions {
headers: HeadersInit;
}
/**
* Sends a message to the backend.
* @example
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* await invoke('login', { user: 'tauri', password: 'poiwe3h4r5ip3yrhtew9ty' });
* ```
*
* @param cmd The command name.
* @param args The optional arguments to pass to the command.
* @param options The request options.
* @return A promise resolving or rejecting to the backend response.
*
* @since 1.0.0
*/
declare function invoke<T>(cmd: string, args?: InvokeArgs, options?: InvokeOptions): Promise<T>;
/**
* Convert a device file path to an URL that can be loaded by the webview.
* Note that `asset:` and `http://asset.localhost` must be added to [`app.security.csp`](https://v2.tauri.app/reference/config/#csp-1) in `tauri.conf.json`.
* Example CSP value: `"csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost"` to use the asset protocol on image sources.
*
* Additionally, `"enable" : "true"` must be added to [`app.security.assetProtocol`](https://v2.tauri.app/reference/config/#assetprotocolconfig)
* in `tauri.conf.json` and its access scope must be defined on the `scope` array on the same `assetProtocol` object.
*
* @param filePath The file path.
* @param protocol The protocol to use. Defaults to `asset`. You only need to set this when using a custom protocol.
* @example
* ```typescript
* import { appDataDir, join } from '@tauri-apps/api/path';
* import { convertFileSrc } from '@tauri-apps/api/core';
* const appDataDirPath = await appDataDir();
* const filePath = await join(appDataDirPath, 'assets/video.mp4');
* const assetUrl = convertFileSrc(filePath);
*
* const video = document.getElementById('my-video');
* const source = document.createElement('source');
* source.type = 'video/mp4';
* source.src = assetUrl;
* video.appendChild(source);
* video.load();
* ```
*
* @return the URL that can be used as source on the webview.
*
* @since 1.0.0
*/
declare function convertFileSrc(filePath: string, protocol?: string): string;
/**
* A rust-backed resource stored through `tauri::Manager::resources_table` API.
*
* The resource lives in the main process and does not exist
* in the Javascript world, and thus will not be cleaned up automatically
* except on application exit. If you want to clean it up early, call {@linkcode Resource.close}
*
* @example
* ```typescript
* import { Resource, invoke } from '@tauri-apps/api/core';
* export class DatabaseHandle extends Resource {
* static async open(path: string): Promise<DatabaseHandle> {
* const rid: number = await invoke('open_db', { path });
* return new DatabaseHandle(rid);
* }
*
* async execute(sql: string): Promise<void> {
* await invoke('execute_sql', { rid: this.rid, sql });
* }
* }
* ```
*/
export declare class Resource {
#private;
get rid(): number;
constructor(rid: number);
/**
* Destroys and cleans up this resource from memory.
* **You should not call any method on this object anymore and should drop any reference to it.**
*/
close(): Promise<void>;
}
declare function isTauri(): boolean;
export type { InvokeArgs, InvokeOptions };
export { transformCallback, Channel, PluginListener, addPluginListener, PermissionState, checkPermissions, requestPermissions, invoke, convertFileSrc, isTauri };

283
node_modules/@tauri-apps/api/core.js generated vendored Normal file
View File

@ -0,0 +1,283 @@
import { __classPrivateFieldSet, __classPrivateFieldGet } from './external/tslib/tslib.es6.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
var _Channel_onmessage, _Channel_nextMessageIndex, _Channel_pendingMessages, _Channel_messageEndIndex, _Resource_rid;
/**
* Invoke your custom commands.
*
* This package is also accessible with `window.__TAURI__.core` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/
/**
* A key to be used to implement a special function
* on your types that define how your type should be serialized
* when passing across the IPC.
* @example
* Given a type in Rust that looks like this
* ```rs
* #[derive(serde::Serialize, serde::Deserialize)
* enum UserId {
* String(String),
* Number(u32),
* }
* ```
* `UserId::String("id")` would be serialized into `{ String: "id" }`
* and so we need to pass the same structure back to Rust
* ```ts
* import { SERIALIZE_TO_IPC_FN } from "@tauri-apps/api/core"
*
* class UserIdString {
* id
* constructor(id) {
* this.id = id
* }
*
* [SERIALIZE_TO_IPC_FN]() {
* return { String: this.id }
* }
* }
*
* class UserIdNumber {
* id
* constructor(id) {
* this.id = id
* }
*
* [SERIALIZE_TO_IPC_FN]() {
* return { Number: this.id }
* }
* }
*
* type UserId = UserIdString | UserIdNumber
* ```
*
*/
// if this value changes, make sure to update it in:
// 1. ipc.js
// 2. process-ipc-message-fn.js
const SERIALIZE_TO_IPC_FN = '__TAURI_TO_IPC_KEY__';
/**
* Stores the callback in a known location, and returns an identifier that can be passed to the backend.
* The backend uses the identifier to `eval()` the callback.
*
* @return An unique identifier associated with the callback function.
*
* @since 1.0.0
*/
function transformCallback(
// TODO: Make this not optional in v3
callback, once = false) {
return window.__TAURI_INTERNALS__.transformCallback(callback, once);
}
class Channel {
constructor(onmessage) {
_Channel_onmessage.set(this, void 0);
// the index is used as a mechanism to preserve message order
_Channel_nextMessageIndex.set(this, 0);
_Channel_pendingMessages.set(this, []);
_Channel_messageEndIndex.set(this, void 0);
__classPrivateFieldSet(this, _Channel_onmessage, onmessage || (() => { }), "f");
this.id = transformCallback((rawMessage) => {
const index = rawMessage.index;
if ('end' in rawMessage) {
if (index == __classPrivateFieldGet(this, _Channel_nextMessageIndex, "f")) {
this.cleanupCallback();
}
else {
__classPrivateFieldSet(this, _Channel_messageEndIndex, index, "f");
}
return;
}
const message = rawMessage.message;
// Process the message if we're at the right order
if (index == __classPrivateFieldGet(this, _Channel_nextMessageIndex, "f")) {
__classPrivateFieldGet(this, _Channel_onmessage, "f").call(this, message);
__classPrivateFieldSet(this, _Channel_nextMessageIndex, __classPrivateFieldGet(this, _Channel_nextMessageIndex, "f") + 1, "f");
// process pending messages
while (__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f") in __classPrivateFieldGet(this, _Channel_pendingMessages, "f")) {
const message = __classPrivateFieldGet(this, _Channel_pendingMessages, "f")[__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f")];
__classPrivateFieldGet(this, _Channel_onmessage, "f").call(this, message);
// eslint-disable-next-line @typescript-eslint/no-array-delete
delete __classPrivateFieldGet(this, _Channel_pendingMessages, "f")[__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f")];
__classPrivateFieldSet(this, _Channel_nextMessageIndex, __classPrivateFieldGet(this, _Channel_nextMessageIndex, "f") + 1, "f");
}
if (__classPrivateFieldGet(this, _Channel_nextMessageIndex, "f") === __classPrivateFieldGet(this, _Channel_messageEndIndex, "f")) {
this.cleanupCallback();
}
}
// Queue the message if we're not
else {
// eslint-disable-next-line security/detect-object-injection
__classPrivateFieldGet(this, _Channel_pendingMessages, "f")[index] = message;
}
});
}
cleanupCallback() {
window.__TAURI_INTERNALS__.unregisterCallback(this.id);
}
set onmessage(handler) {
__classPrivateFieldSet(this, _Channel_onmessage, handler, "f");
}
get onmessage() {
return __classPrivateFieldGet(this, _Channel_onmessage, "f");
}
[(_Channel_onmessage = new WeakMap(), _Channel_nextMessageIndex = new WeakMap(), _Channel_pendingMessages = new WeakMap(), _Channel_messageEndIndex = new WeakMap(), SERIALIZE_TO_IPC_FN)]() {
return `__CHANNEL__:${this.id}`;
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[SERIALIZE_TO_IPC_FN]();
}
}
class PluginListener {
constructor(plugin, event, channelId) {
this.plugin = plugin;
this.event = event;
this.channelId = channelId;
}
async unregister() {
return invoke(`plugin:${this.plugin}|remove_listener`, {
event: this.event,
channelId: this.channelId
});
}
}
/**
* Adds a listener to a plugin event.
*
* @returns The listener object to stop listening to the events.
*
* @since 2.0.0
*/
async function addPluginListener(plugin, event, cb) {
const handler = new Channel(cb);
try {
await invoke(`plugin:${plugin}|register_listener`, {
event,
handler
});
return new PluginListener(plugin, event, handler.id);
}
catch {
// TODO(v3): remove this fallback
// note: we must try with camelCase here for backwards compatibility
await invoke(`plugin:${plugin}|registerListener`, { event, handler });
return new PluginListener(plugin, event, handler.id);
}
}
/**
* Get permission state for a plugin.
*
* This should be used by plugin authors to wrap their actual implementation.
*/
async function checkPermissions(plugin) {
return invoke(`plugin:${plugin}|check_permissions`);
}
/**
* Request permissions.
*
* This should be used by plugin authors to wrap their actual implementation.
*/
async function requestPermissions(plugin) {
return invoke(`plugin:${plugin}|request_permissions`);
}
/**
* Sends a message to the backend.
* @example
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* await invoke('login', { user: 'tauri', password: 'poiwe3h4r5ip3yrhtew9ty' });
* ```
*
* @param cmd The command name.
* @param args The optional arguments to pass to the command.
* @param options The request options.
* @return A promise resolving or rejecting to the backend response.
*
* @since 1.0.0
*/
async function invoke(cmd, args = {}, options) {
return window.__TAURI_INTERNALS__.invoke(cmd, args, options);
}
/**
* Convert a device file path to an URL that can be loaded by the webview.
* Note that `asset:` and `http://asset.localhost` must be added to [`app.security.csp`](https://v2.tauri.app/reference/config/#csp-1) in `tauri.conf.json`.
* Example CSP value: `"csp": "default-src 'self' ipc: http://ipc.localhost; img-src 'self' asset: http://asset.localhost"` to use the asset protocol on image sources.
*
* Additionally, `"enable" : "true"` must be added to [`app.security.assetProtocol`](https://v2.tauri.app/reference/config/#assetprotocolconfig)
* in `tauri.conf.json` and its access scope must be defined on the `scope` array on the same `assetProtocol` object.
*
* @param filePath The file path.
* @param protocol The protocol to use. Defaults to `asset`. You only need to set this when using a custom protocol.
* @example
* ```typescript
* import { appDataDir, join } from '@tauri-apps/api/path';
* import { convertFileSrc } from '@tauri-apps/api/core';
* const appDataDirPath = await appDataDir();
* const filePath = await join(appDataDirPath, 'assets/video.mp4');
* const assetUrl = convertFileSrc(filePath);
*
* const video = document.getElementById('my-video');
* const source = document.createElement('source');
* source.type = 'video/mp4';
* source.src = assetUrl;
* video.appendChild(source);
* video.load();
* ```
*
* @return the URL that can be used as source on the webview.
*
* @since 1.0.0
*/
function convertFileSrc(filePath, protocol = 'asset') {
return window.__TAURI_INTERNALS__.convertFileSrc(filePath, protocol);
}
/**
* A rust-backed resource stored through `tauri::Manager::resources_table` API.
*
* The resource lives in the main process and does not exist
* in the Javascript world, and thus will not be cleaned up automatically
* except on application exit. If you want to clean it up early, call {@linkcode Resource.close}
*
* @example
* ```typescript
* import { Resource, invoke } from '@tauri-apps/api/core';
* export class DatabaseHandle extends Resource {
* static async open(path: string): Promise<DatabaseHandle> {
* const rid: number = await invoke('open_db', { path });
* return new DatabaseHandle(rid);
* }
*
* async execute(sql: string): Promise<void> {
* await invoke('execute_sql', { rid: this.rid, sql });
* }
* }
* ```
*/
class Resource {
get rid() {
return __classPrivateFieldGet(this, _Resource_rid, "f");
}
constructor(rid) {
_Resource_rid.set(this, void 0);
__classPrivateFieldSet(this, _Resource_rid, rid, "f");
}
/**
* Destroys and cleans up this resource from memory.
* **You should not call any method on this object anymore and should drop any reference to it.**
*/
async close() {
return invoke('plugin:resources|close', {
rid: this.rid
});
}
}
_Resource_rid = new WeakMap();
function isTauri() {
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
return !!(globalThis || window).isTauri;
}
export { Channel, PluginListener, Resource, SERIALIZE_TO_IPC_FN, addPluginListener, checkPermissions, convertFileSrc, invoke, isTauri, requestPermissions, transformCallback };

347
node_modules/@tauri-apps/api/dpi.cjs generated vendored Normal file
View File

@ -0,0 +1,347 @@
'use strict';
var core = require('./core.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* A size represented in logical pixels.
* Logical pixels are scaled according to the window's DPI scale.
* Most browser APIs (i.e. `MouseEvent`'s `clientX`) will return logical pixels.
*
* For logical-pixel-based position, see {@linkcode LogicalPosition}.
*
* @since 2.0.0
*/
class LogicalSize {
constructor(...args) {
this.type = 'Logical';
if (args.length === 1) {
if ('Logical' in args[0]) {
this.width = args[0].Logical.width;
this.height = args[0].Logical.height;
}
else {
this.width = args[0].width;
this.height = args[0].height;
}
}
else {
this.width = args[0];
this.height = args[1];
}
}
/**
* Converts the logical size to a physical one.
* @example
* ```typescript
* import { LogicalSize } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const size = new LogicalSize(400, 500);
* const physical = size.toPhysical(factor);
* ```
*
* @since 2.0.0
*/
toPhysical(scaleFactor) {
return new PhysicalSize(this.width * scaleFactor, this.height * scaleFactor);
}
[core.SERIALIZE_TO_IPC_FN]() {
return {
width: this.width,
height: this.height
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[core.SERIALIZE_TO_IPC_FN]();
}
}
/**
* A size represented in physical pixels.
*
* Physical pixels represent actual screen pixels, and are DPI-independent.
* For high-DPI windows, this means that any point in the window on the screen
* will have a different position in logical pixels {@linkcode LogicalSize}.
*
* For physical-pixel-based position, see {@linkcode PhysicalPosition}.
*
* @since 2.0.0
*/
class PhysicalSize {
constructor(...args) {
this.type = 'Physical';
if (args.length === 1) {
if ('Physical' in args[0]) {
this.width = args[0].Physical.width;
this.height = args[0].Physical.height;
}
else {
this.width = args[0].width;
this.height = args[0].height;
}
}
else {
this.width = args[0];
this.height = args[1];
}
}
/**
* Converts the physical size to a logical one.
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const size = await appWindow.innerSize(); // PhysicalSize
* const logical = size.toLogical(factor);
* ```
*/
toLogical(scaleFactor) {
return new LogicalSize(this.width / scaleFactor, this.height / scaleFactor);
}
[core.SERIALIZE_TO_IPC_FN]() {
return {
width: this.width,
height: this.height
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[core.SERIALIZE_TO_IPC_FN]();
}
}
/**
* A size represented either in physical or in logical pixels.
*
* This type is basically a union type of {@linkcode LogicalSize} and {@linkcode PhysicalSize}
* but comes in handy when using `tauri::Size` in Rust as an argument to a command, as this class
* automatically serializes into a valid format so it can be deserialized correctly into `tauri::Size`
*
* So instead of
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalSize, PhysicalSize } from '@tauri-apps/api/dpi';
*
* const size: LogicalSize | PhysicalSize = someFunction(); // where someFunction returns either LogicalSize or PhysicalSize
* const validSize = size instanceof LogicalSize
* ? { Logical: { width: size.width, height: size.height } }
* : { Physical: { width: size.width, height: size.height } }
* await invoke("do_something_with_size", { size: validSize });
* ```
*
* You can just use {@linkcode Size}
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalSize, PhysicalSize, Size } from '@tauri-apps/api/dpi';
*
* const size: LogicalSize | PhysicalSize = someFunction(); // where someFunction returns either LogicalSize or PhysicalSize
* const validSize = new Size(size);
* await invoke("do_something_with_size", { size: validSize });
* ```
*
* @since 2.1.0
*/
class Size {
constructor(size) {
this.size = size;
}
toLogical(scaleFactor) {
return this.size instanceof LogicalSize
? this.size
: this.size.toLogical(scaleFactor);
}
toPhysical(scaleFactor) {
return this.size instanceof PhysicalSize
? this.size
: this.size.toPhysical(scaleFactor);
}
[core.SERIALIZE_TO_IPC_FN]() {
return {
[`${this.size.type}`]: {
width: this.size.width,
height: this.size.height
}
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[core.SERIALIZE_TO_IPC_FN]();
}
}
/**
* A position represented in logical pixels.
* For an explanation of what logical pixels are, see description of {@linkcode LogicalSize}.
*
* @since 2.0.0
*/
class LogicalPosition {
constructor(...args) {
this.type = 'Logical';
if (args.length === 1) {
if ('Logical' in args[0]) {
this.x = args[0].Logical.x;
this.y = args[0].Logical.y;
}
else {
this.x = args[0].x;
this.y = args[0].y;
}
}
else {
this.x = args[0];
this.y = args[1];
}
}
/**
* Converts the logical position to a physical one.
* @example
* ```typescript
* import { LogicalPosition } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const position = new LogicalPosition(400, 500);
* const physical = position.toPhysical(factor);
* ```
*
* @since 2.0.0
*/
toPhysical(scaleFactor) {
return new PhysicalPosition(this.x * scaleFactor, this.y * scaleFactor);
}
[core.SERIALIZE_TO_IPC_FN]() {
return {
x: this.x,
y: this.y
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[core.SERIALIZE_TO_IPC_FN]();
}
}
/**
* A position represented in physical pixels.
*
* For an explanation of what physical pixels are, see description of {@linkcode PhysicalSize}.
*
* @since 2.0.0
*/
class PhysicalPosition {
constructor(...args) {
this.type = 'Physical';
if (args.length === 1) {
if ('Physical' in args[0]) {
this.x = args[0].Physical.x;
this.y = args[0].Physical.y;
}
else {
this.x = args[0].x;
this.y = args[0].y;
}
}
else {
this.x = args[0];
this.y = args[1];
}
}
/**
* Converts the physical position to a logical one.
* @example
* ```typescript
* import { PhysicalPosition } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const position = new PhysicalPosition(400, 500);
* const physical = position.toLogical(factor);
* ```
*
* @since 2.0.0
*/
toLogical(scaleFactor) {
return new LogicalPosition(this.x / scaleFactor, this.y / scaleFactor);
}
[core.SERIALIZE_TO_IPC_FN]() {
return {
x: this.x,
y: this.y
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[core.SERIALIZE_TO_IPC_FN]();
}
}
/**
* A position represented either in physical or in logical pixels.
*
* This type is basically a union type of {@linkcode LogicalSize} and {@linkcode PhysicalSize}
* but comes in handy when using `tauri::Position` in Rust as an argument to a command, as this class
* automatically serializes into a valid format so it can be deserialized correctly into `tauri::Position`
*
* So instead of
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalPosition, PhysicalPosition } from '@tauri-apps/api/dpi';
*
* const position: LogicalPosition | PhysicalPosition = someFunction(); // where someFunction returns either LogicalPosition or PhysicalPosition
* const validPosition = position instanceof LogicalPosition
* ? { Logical: { x: position.x, y: position.y } }
* : { Physical: { x: position.x, y: position.y } }
* await invoke("do_something_with_position", { position: validPosition });
* ```
*
* You can just use {@linkcode Position}
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalPosition, PhysicalPosition, Position } from '@tauri-apps/api/dpi';
*
* const position: LogicalPosition | PhysicalPosition = someFunction(); // where someFunction returns either LogicalPosition or PhysicalPosition
* const validPosition = new Position(position);
* await invoke("do_something_with_position", { position: validPosition });
* ```
*
* @since 2.1.0
*/
class Position {
constructor(position) {
this.position = position;
}
toLogical(scaleFactor) {
return this.position instanceof LogicalPosition
? this.position
: this.position.toLogical(scaleFactor);
}
toPhysical(scaleFactor) {
return this.position instanceof PhysicalPosition
? this.position
: this.position.toPhysical(scaleFactor);
}
[core.SERIALIZE_TO_IPC_FN]() {
return {
[`${this.position.type}`]: {
x: this.position.x,
y: this.position.y
}
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[core.SERIALIZE_TO_IPC_FN]();
}
}
exports.LogicalPosition = LogicalPosition;
exports.LogicalSize = LogicalSize;
exports.PhysicalPosition = PhysicalPosition;
exports.PhysicalSize = PhysicalSize;
exports.Position = Position;
exports.Size = Size;

289
node_modules/@tauri-apps/api/dpi.d.ts generated vendored Normal file
View File

@ -0,0 +1,289 @@
import { SERIALIZE_TO_IPC_FN } from './core';
/**
* A size represented in logical pixels.
* Logical pixels are scaled according to the window's DPI scale.
* Most browser APIs (i.e. `MouseEvent`'s `clientX`) will return logical pixels.
*
* For logical-pixel-based position, see {@linkcode LogicalPosition}.
*
* @since 2.0.0
*/
declare class LogicalSize {
readonly type = "Logical";
width: number;
height: number;
constructor(width: number, height: number);
constructor(object: {
Logical: {
width: number;
height: number;
};
});
constructor(object: {
width: number;
height: number;
});
/**
* Converts the logical size to a physical one.
* @example
* ```typescript
* import { LogicalSize } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const size = new LogicalSize(400, 500);
* const physical = size.toPhysical(factor);
* ```
*
* @since 2.0.0
*/
toPhysical(scaleFactor: number): PhysicalSize;
[SERIALIZE_TO_IPC_FN](): {
width: number;
height: number;
};
toJSON(): {
width: number;
height: number;
};
}
/**
* A size represented in physical pixels.
*
* Physical pixels represent actual screen pixels, and are DPI-independent.
* For high-DPI windows, this means that any point in the window on the screen
* will have a different position in logical pixels {@linkcode LogicalSize}.
*
* For physical-pixel-based position, see {@linkcode PhysicalPosition}.
*
* @since 2.0.0
*/
declare class PhysicalSize {
readonly type = "Physical";
width: number;
height: number;
constructor(width: number, height: number);
constructor(object: {
Physical: {
width: number;
height: number;
};
});
constructor(object: {
width: number;
height: number;
});
/**
* Converts the physical size to a logical one.
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const size = await appWindow.innerSize(); // PhysicalSize
* const logical = size.toLogical(factor);
* ```
*/
toLogical(scaleFactor: number): LogicalSize;
[SERIALIZE_TO_IPC_FN](): {
width: number;
height: number;
};
toJSON(): {
width: number;
height: number;
};
}
/**
* A size represented either in physical or in logical pixels.
*
* This type is basically a union type of {@linkcode LogicalSize} and {@linkcode PhysicalSize}
* but comes in handy when using `tauri::Size` in Rust as an argument to a command, as this class
* automatically serializes into a valid format so it can be deserialized correctly into `tauri::Size`
*
* So instead of
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalSize, PhysicalSize } from '@tauri-apps/api/dpi';
*
* const size: LogicalSize | PhysicalSize = someFunction(); // where someFunction returns either LogicalSize or PhysicalSize
* const validSize = size instanceof LogicalSize
* ? { Logical: { width: size.width, height: size.height } }
* : { Physical: { width: size.width, height: size.height } }
* await invoke("do_something_with_size", { size: validSize });
* ```
*
* You can just use {@linkcode Size}
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalSize, PhysicalSize, Size } from '@tauri-apps/api/dpi';
*
* const size: LogicalSize | PhysicalSize = someFunction(); // where someFunction returns either LogicalSize or PhysicalSize
* const validSize = new Size(size);
* await invoke("do_something_with_size", { size: validSize });
* ```
*
* @since 2.1.0
*/
declare class Size {
size: LogicalSize | PhysicalSize;
constructor(size: LogicalSize | PhysicalSize);
toLogical(scaleFactor: number): LogicalSize;
toPhysical(scaleFactor: number): PhysicalSize;
[SERIALIZE_TO_IPC_FN](): {
[x: string]: {
width: number;
height: number;
};
};
toJSON(): {
[x: string]: {
width: number;
height: number;
};
};
}
/**
* A position represented in logical pixels.
* For an explanation of what logical pixels are, see description of {@linkcode LogicalSize}.
*
* @since 2.0.0
*/
declare class LogicalPosition {
readonly type = "Logical";
x: number;
y: number;
constructor(x: number, y: number);
constructor(object: {
Logical: {
x: number;
y: number;
};
});
constructor(object: {
x: number;
y: number;
});
/**
* Converts the logical position to a physical one.
* @example
* ```typescript
* import { LogicalPosition } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const position = new LogicalPosition(400, 500);
* const physical = position.toPhysical(factor);
* ```
*
* @since 2.0.0
*/
toPhysical(scaleFactor: number): PhysicalPosition;
[SERIALIZE_TO_IPC_FN](): {
x: number;
y: number;
};
toJSON(): {
x: number;
y: number;
};
}
/**
* A position represented in physical pixels.
*
* For an explanation of what physical pixels are, see description of {@linkcode PhysicalSize}.
*
* @since 2.0.0
*/
declare class PhysicalPosition {
readonly type = "Physical";
x: number;
y: number;
constructor(x: number, y: number);
constructor(object: {
Physical: {
x: number;
y: number;
};
});
constructor(object: {
x: number;
y: number;
});
/**
* Converts the physical position to a logical one.
* @example
* ```typescript
* import { PhysicalPosition } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const position = new PhysicalPosition(400, 500);
* const physical = position.toLogical(factor);
* ```
*
* @since 2.0.0
*/
toLogical(scaleFactor: number): LogicalPosition;
[SERIALIZE_TO_IPC_FN](): {
x: number;
y: number;
};
toJSON(): {
x: number;
y: number;
};
}
/**
* A position represented either in physical or in logical pixels.
*
* This type is basically a union type of {@linkcode LogicalSize} and {@linkcode PhysicalSize}
* but comes in handy when using `tauri::Position` in Rust as an argument to a command, as this class
* automatically serializes into a valid format so it can be deserialized correctly into `tauri::Position`
*
* So instead of
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalPosition, PhysicalPosition } from '@tauri-apps/api/dpi';
*
* const position: LogicalPosition | PhysicalPosition = someFunction(); // where someFunction returns either LogicalPosition or PhysicalPosition
* const validPosition = position instanceof LogicalPosition
* ? { Logical: { x: position.x, y: position.y } }
* : { Physical: { x: position.x, y: position.y } }
* await invoke("do_something_with_position", { position: validPosition });
* ```
*
* You can just use {@linkcode Position}
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalPosition, PhysicalPosition, Position } from '@tauri-apps/api/dpi';
*
* const position: LogicalPosition | PhysicalPosition = someFunction(); // where someFunction returns either LogicalPosition or PhysicalPosition
* const validPosition = new Position(position);
* await invoke("do_something_with_position", { position: validPosition });
* ```
*
* @since 2.1.0
*/
declare class Position {
position: LogicalPosition | PhysicalPosition;
constructor(position: LogicalPosition | PhysicalPosition);
toLogical(scaleFactor: number): LogicalPosition;
toPhysical(scaleFactor: number): PhysicalPosition;
[SERIALIZE_TO_IPC_FN](): {
[x: string]: {
x: number;
y: number;
};
};
toJSON(): {
[x: string]: {
x: number;
y: number;
};
};
}
export { LogicalPosition, LogicalSize, Size, PhysicalPosition, PhysicalSize, Position };

340
node_modules/@tauri-apps/api/dpi.js generated vendored Normal file
View File

@ -0,0 +1,340 @@
import { SERIALIZE_TO_IPC_FN } from './core.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* A size represented in logical pixels.
* Logical pixels are scaled according to the window's DPI scale.
* Most browser APIs (i.e. `MouseEvent`'s `clientX`) will return logical pixels.
*
* For logical-pixel-based position, see {@linkcode LogicalPosition}.
*
* @since 2.0.0
*/
class LogicalSize {
constructor(...args) {
this.type = 'Logical';
if (args.length === 1) {
if ('Logical' in args[0]) {
this.width = args[0].Logical.width;
this.height = args[0].Logical.height;
}
else {
this.width = args[0].width;
this.height = args[0].height;
}
}
else {
this.width = args[0];
this.height = args[1];
}
}
/**
* Converts the logical size to a physical one.
* @example
* ```typescript
* import { LogicalSize } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const size = new LogicalSize(400, 500);
* const physical = size.toPhysical(factor);
* ```
*
* @since 2.0.0
*/
toPhysical(scaleFactor) {
return new PhysicalSize(this.width * scaleFactor, this.height * scaleFactor);
}
[SERIALIZE_TO_IPC_FN]() {
return {
width: this.width,
height: this.height
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[SERIALIZE_TO_IPC_FN]();
}
}
/**
* A size represented in physical pixels.
*
* Physical pixels represent actual screen pixels, and are DPI-independent.
* For high-DPI windows, this means that any point in the window on the screen
* will have a different position in logical pixels {@linkcode LogicalSize}.
*
* For physical-pixel-based position, see {@linkcode PhysicalPosition}.
*
* @since 2.0.0
*/
class PhysicalSize {
constructor(...args) {
this.type = 'Physical';
if (args.length === 1) {
if ('Physical' in args[0]) {
this.width = args[0].Physical.width;
this.height = args[0].Physical.height;
}
else {
this.width = args[0].width;
this.height = args[0].height;
}
}
else {
this.width = args[0];
this.height = args[1];
}
}
/**
* Converts the physical size to a logical one.
* @example
* ```typescript
* import { getCurrentWindow } from '@tauri-apps/api/window';
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const size = await appWindow.innerSize(); // PhysicalSize
* const logical = size.toLogical(factor);
* ```
*/
toLogical(scaleFactor) {
return new LogicalSize(this.width / scaleFactor, this.height / scaleFactor);
}
[SERIALIZE_TO_IPC_FN]() {
return {
width: this.width,
height: this.height
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[SERIALIZE_TO_IPC_FN]();
}
}
/**
* A size represented either in physical or in logical pixels.
*
* This type is basically a union type of {@linkcode LogicalSize} and {@linkcode PhysicalSize}
* but comes in handy when using `tauri::Size` in Rust as an argument to a command, as this class
* automatically serializes into a valid format so it can be deserialized correctly into `tauri::Size`
*
* So instead of
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalSize, PhysicalSize } from '@tauri-apps/api/dpi';
*
* const size: LogicalSize | PhysicalSize = someFunction(); // where someFunction returns either LogicalSize or PhysicalSize
* const validSize = size instanceof LogicalSize
* ? { Logical: { width: size.width, height: size.height } }
* : { Physical: { width: size.width, height: size.height } }
* await invoke("do_something_with_size", { size: validSize });
* ```
*
* You can just use {@linkcode Size}
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalSize, PhysicalSize, Size } from '@tauri-apps/api/dpi';
*
* const size: LogicalSize | PhysicalSize = someFunction(); // where someFunction returns either LogicalSize or PhysicalSize
* const validSize = new Size(size);
* await invoke("do_something_with_size", { size: validSize });
* ```
*
* @since 2.1.0
*/
class Size {
constructor(size) {
this.size = size;
}
toLogical(scaleFactor) {
return this.size instanceof LogicalSize
? this.size
: this.size.toLogical(scaleFactor);
}
toPhysical(scaleFactor) {
return this.size instanceof PhysicalSize
? this.size
: this.size.toPhysical(scaleFactor);
}
[SERIALIZE_TO_IPC_FN]() {
return {
[`${this.size.type}`]: {
width: this.size.width,
height: this.size.height
}
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[SERIALIZE_TO_IPC_FN]();
}
}
/**
* A position represented in logical pixels.
* For an explanation of what logical pixels are, see description of {@linkcode LogicalSize}.
*
* @since 2.0.0
*/
class LogicalPosition {
constructor(...args) {
this.type = 'Logical';
if (args.length === 1) {
if ('Logical' in args[0]) {
this.x = args[0].Logical.x;
this.y = args[0].Logical.y;
}
else {
this.x = args[0].x;
this.y = args[0].y;
}
}
else {
this.x = args[0];
this.y = args[1];
}
}
/**
* Converts the logical position to a physical one.
* @example
* ```typescript
* import { LogicalPosition } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const position = new LogicalPosition(400, 500);
* const physical = position.toPhysical(factor);
* ```
*
* @since 2.0.0
*/
toPhysical(scaleFactor) {
return new PhysicalPosition(this.x * scaleFactor, this.y * scaleFactor);
}
[SERIALIZE_TO_IPC_FN]() {
return {
x: this.x,
y: this.y
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[SERIALIZE_TO_IPC_FN]();
}
}
/**
* A position represented in physical pixels.
*
* For an explanation of what physical pixels are, see description of {@linkcode PhysicalSize}.
*
* @since 2.0.0
*/
class PhysicalPosition {
constructor(...args) {
this.type = 'Physical';
if (args.length === 1) {
if ('Physical' in args[0]) {
this.x = args[0].Physical.x;
this.y = args[0].Physical.y;
}
else {
this.x = args[0].x;
this.y = args[0].y;
}
}
else {
this.x = args[0];
this.y = args[1];
}
}
/**
* Converts the physical position to a logical one.
* @example
* ```typescript
* import { PhysicalPosition } from '@tauri-apps/api/dpi';
* import { getCurrentWindow } from '@tauri-apps/api/window';
*
* const appWindow = getCurrentWindow();
* const factor = await appWindow.scaleFactor();
* const position = new PhysicalPosition(400, 500);
* const physical = position.toLogical(factor);
* ```
*
* @since 2.0.0
*/
toLogical(scaleFactor) {
return new LogicalPosition(this.x / scaleFactor, this.y / scaleFactor);
}
[SERIALIZE_TO_IPC_FN]() {
return {
x: this.x,
y: this.y
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[SERIALIZE_TO_IPC_FN]();
}
}
/**
* A position represented either in physical or in logical pixels.
*
* This type is basically a union type of {@linkcode LogicalSize} and {@linkcode PhysicalSize}
* but comes in handy when using `tauri::Position` in Rust as an argument to a command, as this class
* automatically serializes into a valid format so it can be deserialized correctly into `tauri::Position`
*
* So instead of
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalPosition, PhysicalPosition } from '@tauri-apps/api/dpi';
*
* const position: LogicalPosition | PhysicalPosition = someFunction(); // where someFunction returns either LogicalPosition or PhysicalPosition
* const validPosition = position instanceof LogicalPosition
* ? { Logical: { x: position.x, y: position.y } }
* : { Physical: { x: position.x, y: position.y } }
* await invoke("do_something_with_position", { position: validPosition });
* ```
*
* You can just use {@linkcode Position}
* ```typescript
* import { invoke } from '@tauri-apps/api/core';
* import { LogicalPosition, PhysicalPosition, Position } from '@tauri-apps/api/dpi';
*
* const position: LogicalPosition | PhysicalPosition = someFunction(); // where someFunction returns either LogicalPosition or PhysicalPosition
* const validPosition = new Position(position);
* await invoke("do_something_with_position", { position: validPosition });
* ```
*
* @since 2.1.0
*/
class Position {
constructor(position) {
this.position = position;
}
toLogical(scaleFactor) {
return this.position instanceof LogicalPosition
? this.position
: this.position.toLogical(scaleFactor);
}
toPhysical(scaleFactor) {
return this.position instanceof PhysicalPosition
? this.position
: this.position.toPhysical(scaleFactor);
}
[SERIALIZE_TO_IPC_FN]() {
return {
[`${this.position.type}`]: {
x: this.position.x,
y: this.position.y
}
};
}
toJSON() {
// eslint-disable-next-line security/detect-object-injection
return this[SERIALIZE_TO_IPC_FN]();
}
}
export { LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size };

163
node_modules/@tauri-apps/api/event.cjs generated vendored Normal file
View File

@ -0,0 +1,163 @@
'use strict';
var core = require('./core.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* The event system allows you to emit events to the backend and listen to events from it.
*
* This package is also accessible with `window.__TAURI__.event` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/
/**
* @since 1.1.0
*/
exports.TauriEvent = void 0;
(function (TauriEvent) {
TauriEvent["WINDOW_RESIZED"] = "tauri://resize";
TauriEvent["WINDOW_MOVED"] = "tauri://move";
TauriEvent["WINDOW_CLOSE_REQUESTED"] = "tauri://close-requested";
TauriEvent["WINDOW_DESTROYED"] = "tauri://destroyed";
TauriEvent["WINDOW_FOCUS"] = "tauri://focus";
TauriEvent["WINDOW_BLUR"] = "tauri://blur";
TauriEvent["WINDOW_SCALE_FACTOR_CHANGED"] = "tauri://scale-change";
TauriEvent["WINDOW_THEME_CHANGED"] = "tauri://theme-changed";
TauriEvent["WINDOW_CREATED"] = "tauri://window-created";
TauriEvent["WEBVIEW_CREATED"] = "tauri://webview-created";
TauriEvent["DRAG_ENTER"] = "tauri://drag-enter";
TauriEvent["DRAG_OVER"] = "tauri://drag-over";
TauriEvent["DRAG_DROP"] = "tauri://drag-drop";
TauriEvent["DRAG_LEAVE"] = "tauri://drag-leave";
})(exports.TauriEvent || (exports.TauriEvent = {}));
/**
* Unregister the event listener associated with the given name and id.
*
* @ignore
* @param event The event name
* @param eventId Event identifier
* @returns
*/
async function _unlisten(event, eventId) {
window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener(event, eventId);
await core.invoke('plugin:event|unlisten', {
event,
eventId
});
}
/**
* Listen to an emitted event to any {@link EventTarget|target}.
*
* @example
* ```typescript
* import { listen } from '@tauri-apps/api/event';
* const unlisten = await listen<string>('error', (event) => {
* console.log(`Got error, payload: ${event.payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler callback.
* @param options Event listening options.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*
* @since 1.0.0
*/
async function listen(event, handler, options) {
var _a;
const target = typeof (options === null || options === void 0 ? void 0 : options.target) === 'string'
? { kind: 'AnyLabel', label: options.target }
: ((_a = options === null || options === void 0 ? void 0 : options.target) !== null && _a !== void 0 ? _a : { kind: 'Any' });
return core.invoke('plugin:event|listen', {
event,
target,
handler: core.transformCallback(handler)
}).then((eventId) => {
return async () => _unlisten(event, eventId);
});
}
/**
* Listens once to an emitted event to any {@link EventTarget|target}.
*
* @example
* ```typescript
* import { once } from '@tauri-apps/api/event';
* interface LoadedPayload {
* loggedIn: boolean,
* token: string
* }
* const unlisten = await once<LoadedPayload>('loaded', (event) => {
* console.log(`App is loaded, loggedIn: ${event.payload.loggedIn}, token: ${event.payload.token}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler callback.
* @param options Event listening options.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*
* @since 1.0.0
*/
async function once(event, handler, options) {
return listen(event, (eventData) => {
void _unlisten(event, eventData.id);
handler(eventData);
}, options);
}
/**
* Emits an event to all {@link EventTarget|targets}.
*
* @example
* ```typescript
* import { emit } from '@tauri-apps/api/event';
* await emit('frontend-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*
* @since 1.0.0
*/
async function emit(event, payload) {
await core.invoke('plugin:event|emit', {
event,
payload
});
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* @example
* ```typescript
* import { emitTo } from '@tauri-apps/api/event';
* await emitTo('main', 'frontend-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*
* @since 2.0.0
*/
async function emitTo(target, event, payload) {
const eventTarget = typeof target === 'string' ? { kind: 'AnyLabel', label: target } : target;
await core.invoke('plugin:event|emit_to', {
target: eventTarget,
event,
payload
});
}
exports.emit = emit;
exports.emitTo = emitTo;
exports.listen = listen;
exports.once = once;

145
node_modules/@tauri-apps/api/event.d.ts generated vendored Normal file
View File

@ -0,0 +1,145 @@
declare global {
interface Window {
__TAURI_EVENT_PLUGIN_INTERNALS__: {
unregisterListener: (event: string, eventId: number) => void;
};
}
}
type EventTarget = {
kind: 'Any';
} | {
kind: 'AnyLabel';
label: string;
} | {
kind: 'App';
} | {
kind: 'Window';
label: string;
} | {
kind: 'Webview';
label: string;
} | {
kind: 'WebviewWindow';
label: string;
};
interface Event<T> {
/** Event name */
event: EventName;
/** Event identifier used to unlisten */
id: number;
/** Event payload */
payload: T;
}
type EventCallback<T> = (event: Event<T>) => void;
type UnlistenFn = () => void;
type EventName = `${TauriEvent}` | (string & Record<never, never>);
interface Options {
/**
* The event target to listen to, defaults to `{ kind: 'Any' }`, see {@link EventTarget}.
*
* If a string is provided, {@link EventTarget.AnyLabel} is used.
*/
target?: string | EventTarget;
}
/**
* @since 1.1.0
*/
declare enum TauriEvent {
WINDOW_RESIZED = "tauri://resize",
WINDOW_MOVED = "tauri://move",
WINDOW_CLOSE_REQUESTED = "tauri://close-requested",
WINDOW_DESTROYED = "tauri://destroyed",
WINDOW_FOCUS = "tauri://focus",
WINDOW_BLUR = "tauri://blur",
WINDOW_SCALE_FACTOR_CHANGED = "tauri://scale-change",
WINDOW_THEME_CHANGED = "tauri://theme-changed",
WINDOW_CREATED = "tauri://window-created",
WEBVIEW_CREATED = "tauri://webview-created",
DRAG_ENTER = "tauri://drag-enter",
DRAG_OVER = "tauri://drag-over",
DRAG_DROP = "tauri://drag-drop",
DRAG_LEAVE = "tauri://drag-leave"
}
/**
* Listen to an emitted event to any {@link EventTarget|target}.
*
* @example
* ```typescript
* import { listen } from '@tauri-apps/api/event';
* const unlisten = await listen<string>('error', (event) => {
* console.log(`Got error, payload: ${event.payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler callback.
* @param options Event listening options.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*
* @since 1.0.0
*/
declare function listen<T>(event: EventName, handler: EventCallback<T>, options?: Options): Promise<UnlistenFn>;
/**
* Listens once to an emitted event to any {@link EventTarget|target}.
*
* @example
* ```typescript
* import { once } from '@tauri-apps/api/event';
* interface LoadedPayload {
* loggedIn: boolean,
* token: string
* }
* const unlisten = await once<LoadedPayload>('loaded', (event) => {
* console.log(`App is loaded, loggedIn: ${event.payload.loggedIn}, token: ${event.payload.token}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler callback.
* @param options Event listening options.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*
* @since 1.0.0
*/
declare function once<T>(event: EventName, handler: EventCallback<T>, options?: Options): Promise<UnlistenFn>;
/**
* Emits an event to all {@link EventTarget|targets}.
*
* @example
* ```typescript
* import { emit } from '@tauri-apps/api/event';
* await emit('frontend-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*
* @since 1.0.0
*/
declare function emit<T>(event: string, payload?: T): Promise<void>;
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* @example
* ```typescript
* import { emitTo } from '@tauri-apps/api/event';
* await emitTo('main', 'frontend-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*
* @since 2.0.0
*/
declare function emitTo<T>(target: EventTarget | string, event: string, payload?: T): Promise<void>;
export type { Event, EventTarget, EventCallback, UnlistenFn, EventName, Options };
export { listen, once, emit, emitTo, TauriEvent };

158
node_modules/@tauri-apps/api/event.js generated vendored Normal file
View File

@ -0,0 +1,158 @@
import { invoke, transformCallback } from './core.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* The event system allows you to emit events to the backend and listen to events from it.
*
* This package is also accessible with `window.__TAURI__.event` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/
/**
* @since 1.1.0
*/
var TauriEvent;
(function (TauriEvent) {
TauriEvent["WINDOW_RESIZED"] = "tauri://resize";
TauriEvent["WINDOW_MOVED"] = "tauri://move";
TauriEvent["WINDOW_CLOSE_REQUESTED"] = "tauri://close-requested";
TauriEvent["WINDOW_DESTROYED"] = "tauri://destroyed";
TauriEvent["WINDOW_FOCUS"] = "tauri://focus";
TauriEvent["WINDOW_BLUR"] = "tauri://blur";
TauriEvent["WINDOW_SCALE_FACTOR_CHANGED"] = "tauri://scale-change";
TauriEvent["WINDOW_THEME_CHANGED"] = "tauri://theme-changed";
TauriEvent["WINDOW_CREATED"] = "tauri://window-created";
TauriEvent["WEBVIEW_CREATED"] = "tauri://webview-created";
TauriEvent["DRAG_ENTER"] = "tauri://drag-enter";
TauriEvent["DRAG_OVER"] = "tauri://drag-over";
TauriEvent["DRAG_DROP"] = "tauri://drag-drop";
TauriEvent["DRAG_LEAVE"] = "tauri://drag-leave";
})(TauriEvent || (TauriEvent = {}));
/**
* Unregister the event listener associated with the given name and id.
*
* @ignore
* @param event The event name
* @param eventId Event identifier
* @returns
*/
async function _unlisten(event, eventId) {
window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener(event, eventId);
await invoke('plugin:event|unlisten', {
event,
eventId
});
}
/**
* Listen to an emitted event to any {@link EventTarget|target}.
*
* @example
* ```typescript
* import { listen } from '@tauri-apps/api/event';
* const unlisten = await listen<string>('error', (event) => {
* console.log(`Got error, payload: ${event.payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler callback.
* @param options Event listening options.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*
* @since 1.0.0
*/
async function listen(event, handler, options) {
var _a;
const target = typeof (options === null || options === void 0 ? void 0 : options.target) === 'string'
? { kind: 'AnyLabel', label: options.target }
: ((_a = options === null || options === void 0 ? void 0 : options.target) !== null && _a !== void 0 ? _a : { kind: 'Any' });
return invoke('plugin:event|listen', {
event,
target,
handler: transformCallback(handler)
}).then((eventId) => {
return async () => _unlisten(event, eventId);
});
}
/**
* Listens once to an emitted event to any {@link EventTarget|target}.
*
* @example
* ```typescript
* import { once } from '@tauri-apps/api/event';
* interface LoadedPayload {
* loggedIn: boolean,
* token: string
* }
* const unlisten = await once<LoadedPayload>('loaded', (event) => {
* console.log(`App is loaded, loggedIn: ${event.payload.loggedIn}, token: ${event.payload.token}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler callback.
* @param options Event listening options.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*
* @since 1.0.0
*/
async function once(event, handler, options) {
return listen(event, (eventData) => {
void _unlisten(event, eventData.id);
handler(eventData);
}, options);
}
/**
* Emits an event to all {@link EventTarget|targets}.
*
* @example
* ```typescript
* import { emit } from '@tauri-apps/api/event';
* await emit('frontend-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*
* @since 1.0.0
*/
async function emit(event, payload) {
await invoke('plugin:event|emit', {
event,
payload
});
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* @example
* ```typescript
* import { emitTo } from '@tauri-apps/api/event';
* await emitTo('main', 'frontend-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*
* @since 2.0.0
*/
async function emitTo(target, event, payload) {
const eventTarget = typeof target === 'string' ? { kind: 'AnyLabel', label: target } : target;
await invoke('plugin:event|emit_to', {
target: eventTarget,
event,
payload
});
}
export { TauriEvent, emit, emitTo, listen, once };

View File

@ -0,0 +1,39 @@
'use strict';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
function __classPrivateFieldGet(receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
}
function __classPrivateFieldSet(receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
exports.__classPrivateFieldGet = __classPrivateFieldGet;
exports.__classPrivateFieldSet = __classPrivateFieldSet;

View File

@ -0,0 +1,36 @@
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
function __classPrivateFieldGet(receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
}
function __classPrivateFieldSet(receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
export { __classPrivateFieldGet, __classPrivateFieldSet };

88
node_modules/@tauri-apps/api/image.cjs generated vendored Normal file
View File

@ -0,0 +1,88 @@
'use strict';
var core = require('./core.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** An RGBA Image in row-major order from top to bottom. */
class Image extends core.Resource {
/**
* Creates an Image from a resource ID. For internal use only.
*
* @ignore
*/
constructor(rid) {
super(rid);
}
/** Creates a new Image using RGBA data, in row-major order from top to bottom, and with specified width and height. */
static async new(rgba, width, height) {
return core.invoke('plugin:image|new', {
rgba: transformImage(rgba),
width,
height
}).then((rid) => new Image(rid));
}
/**
* Creates a new image using the provided bytes by inferring the file format.
* If the format is known, prefer [@link Image.fromPngBytes] or [@link Image.fromIcoBytes].
*
* Only `ico` and `png` are supported (based on activated feature flag).
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
static async fromBytes(bytes) {
return core.invoke('plugin:image|from_bytes', {
bytes: transformImage(bytes)
}).then((rid) => new Image(rid));
}
/**
* Creates a new image using the provided path.
*
* Only `ico` and `png` are supported (based on activated feature flag).
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
static async fromPath(path) {
return core.invoke('plugin:image|from_path', { path }).then((rid) => new Image(rid));
}
/** Returns the RGBA data for this image, in row-major order from top to bottom. */
async rgba() {
return core.invoke('plugin:image|rgba', {
rid: this.rid
}).then((buffer) => new Uint8Array(buffer));
}
/** Returns the size of this image. */
async size() {
return core.invoke('plugin:image|size', { rid: this.rid });
}
}
/**
* Transforms image from various types into a type acceptable by Rust.
*
* See [tauri::image::JsImage](https://docs.rs/tauri/2/tauri/image/enum.JsImage.html) for more information.
* Note the API signature is not stable and might change.
*/
function transformImage(image) {
const ret = image == null
? null
: typeof image === 'string'
? image
: image instanceof Image
? image.rid
: image;
return ret;
}
exports.Image = Image;
exports.transformImage = transformImage;

57
node_modules/@tauri-apps/api/image.d.ts generated vendored Normal file
View File

@ -0,0 +1,57 @@
import { Resource } from './core';
import { NativeIcon } from './menu/iconMenuItem';
export interface ImageSize {
width: number;
height: number;
}
/** A type that represents an icon that can be used in menu items. */
export type MenuIcon = NativeIcon | string | Image | Uint8Array | ArrayBuffer | number[];
/** An RGBA Image in row-major order from top to bottom. */
export declare class Image extends Resource {
/**
* Creates an Image from a resource ID. For internal use only.
*
* @ignore
*/
constructor(rid: number);
/** Creates a new Image using RGBA data, in row-major order from top to bottom, and with specified width and height. */
static new(rgba: number[] | Uint8Array | ArrayBuffer, width: number, height: number): Promise<Image>;
/**
* Creates a new image using the provided bytes by inferring the file format.
* If the format is known, prefer [@link Image.fromPngBytes] or [@link Image.fromIcoBytes].
*
* Only `ico` and `png` are supported (based on activated feature flag).
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
static fromBytes(bytes: number[] | Uint8Array | ArrayBuffer): Promise<Image>;
/**
* Creates a new image using the provided path.
*
* Only `ico` and `png` are supported (based on activated feature flag).
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
static fromPath(path: string): Promise<Image>;
/** Returns the RGBA data for this image, in row-major order from top to bottom. */
rgba(): Promise<Uint8Array>;
/** Returns the size of this image. */
size(): Promise<ImageSize>;
}
/**
* Transforms image from various types into a type acceptable by Rust.
*
* See [tauri::image::JsImage](https://docs.rs/tauri/2/tauri/image/enum.JsImage.html) for more information.
* Note the API signature is not stable and might change.
*/
export declare function transformImage<T>(image: string | Image | Uint8Array | ArrayBuffer | number[] | null): T;

85
node_modules/@tauri-apps/api/image.js generated vendored Normal file
View File

@ -0,0 +1,85 @@
import { Resource, invoke } from './core.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** An RGBA Image in row-major order from top to bottom. */
class Image extends Resource {
/**
* Creates an Image from a resource ID. For internal use only.
*
* @ignore
*/
constructor(rid) {
super(rid);
}
/** Creates a new Image using RGBA data, in row-major order from top to bottom, and with specified width and height. */
static async new(rgba, width, height) {
return invoke('plugin:image|new', {
rgba: transformImage(rgba),
width,
height
}).then((rid) => new Image(rid));
}
/**
* Creates a new image using the provided bytes by inferring the file format.
* If the format is known, prefer [@link Image.fromPngBytes] or [@link Image.fromIcoBytes].
*
* Only `ico` and `png` are supported (based on activated feature flag).
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
static async fromBytes(bytes) {
return invoke('plugin:image|from_bytes', {
bytes: transformImage(bytes)
}).then((rid) => new Image(rid));
}
/**
* Creates a new image using the provided path.
*
* Only `ico` and `png` are supported (based on activated feature flag).
*
* Note that you need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
static async fromPath(path) {
return invoke('plugin:image|from_path', { path }).then((rid) => new Image(rid));
}
/** Returns the RGBA data for this image, in row-major order from top to bottom. */
async rgba() {
return invoke('plugin:image|rgba', {
rid: this.rid
}).then((buffer) => new Uint8Array(buffer));
}
/** Returns the size of this image. */
async size() {
return invoke('plugin:image|size', { rid: this.rid });
}
}
/**
* Transforms image from various types into a type acceptable by Rust.
*
* See [tauri::image::JsImage](https://docs.rs/tauri/2/tauri/image/enum.JsImage.html) for more information.
* Note the API signature is not stable and might change.
*/
function transformImage(image) {
const ret = image == null
? null
: typeof image === 'string'
? image
: image instanceof Image
? image.rid
: image;
return ret;
}
export { Image, transformImage };

29
node_modules/@tauri-apps/api/index.cjs generated vendored Normal file
View File

@ -0,0 +1,29 @@
'use strict';
var app = require('./app.cjs');
var core = require('./core.cjs');
var dpi = require('./dpi.cjs');
var event = require('./event.cjs');
var image = require('./image.cjs');
var menu = require('./menu.cjs');
var mocks = require('./mocks.cjs');
var path = require('./path.cjs');
var tray = require('./tray.cjs');
var webview = require('./webview.cjs');
var webviewWindow = require('./webviewWindow.cjs');
var window = require('./window.cjs');
exports.app = app;
exports.core = core;
exports.dpi = dpi;
exports.event = event;
exports.image = image;
exports.menu = menu;
exports.mocks = mocks;
exports.path = path;
exports.tray = tray;
exports.webview = webview;
exports.webviewWindow = webviewWindow;
exports.window = window;

33
node_modules/@tauri-apps/api/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,33 @@
/**
* The Tauri API allows you to interface with the backend layer.
*
* This module exposes all other modules as an object where the key is the module name, and the value is the module exports.
* @example
* ```typescript
* import { event, window, path } from '@tauri-apps/api'
* ```
*
* ### Vanilla JS API
*
* The above import syntax is for JavaScript/TypeScript with a bundler. If you're using vanilla JavaScript, you can use the global `window.__TAURI__` object instead. It requires `app.withGlobalTauri` configuration option enabled.
*
* @example
* ```js
* const { event, window: tauriWindow, path } = window.__TAURI__;
* ```
*
* @module
*/
import * as app from './app';
import * as core from './core';
import * as dpi from './dpi';
import * as event from './event';
import * as image from './image';
import * as menu from './menu';
import * as mocks from './mocks';
import * as path from './path';
import * as tray from './tray';
import * as webview from './webview';
import * as webviewWindow from './webviewWindow';
import * as window from './window';
export { app, core, dpi, event, image, menu, mocks, path, tray, webview, webviewWindow, window };

24
node_modules/@tauri-apps/api/index.js generated vendored Normal file
View File

@ -0,0 +1,24 @@
import * as app from './app.js';
export { app };
import * as core from './core.js';
export { core };
import * as dpi from './dpi.js';
export { dpi };
import * as event from './event.js';
export { event };
import * as image from './image.js';
export { image };
import * as menu from './menu.js';
export { menu };
import * as mocks from './mocks.js';
export { mocks };
import * as path from './path.js';
export { path };
import * as tray from './tray.js';
export { tray };
import * as webview from './webview.js';
export { webview };
import * as webviewWindow from './webviewWindow.js';
export { webviewWindow };
import * as window from './window.js';
export { window };

30
node_modules/@tauri-apps/api/menu.cjs generated vendored Normal file
View File

@ -0,0 +1,30 @@
'use strict';
var submenu = require('./menu/submenu.cjs');
var menuItem = require('./menu/menuItem.cjs');
var menu = require('./menu/menu.cjs');
var checkMenuItem = require('./menu/checkMenuItem.cjs');
var iconMenuItem = require('./menu/iconMenuItem.cjs');
var predefinedMenuItem = require('./menu/predefinedMenuItem.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Menu types and utilities.
*
* This package is also accessible with `window.__TAURI__.menu` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/
exports.Submenu = submenu.Submenu;
exports.itemFromKind = submenu.itemFromKind;
exports.MenuItem = menuItem.MenuItem;
exports.Menu = menu.Menu;
exports.CheckMenuItem = checkMenuItem.CheckMenuItem;
exports.IconMenuItem = iconMenuItem.IconMenuItem;
Object.defineProperty(exports, "NativeIcon", {
enumerable: true,
get: function () { return iconMenuItem.NativeIcon; }
});
exports.PredefinedMenuItem = predefinedMenuItem.PredefinedMenuItem;

12
node_modules/@tauri-apps/api/menu.d.ts generated vendored Normal file
View File

@ -0,0 +1,12 @@
export * from './menu/submenu';
export * from './menu/menuItem';
export * from './menu/menu';
export * from './menu/checkMenuItem';
export * from './menu/iconMenuItem';
export * from './menu/predefinedMenuItem';
/**
* Menu types and utilities.
*
* This package is also accessible with `window.__TAURI__.menu` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/

16
node_modules/@tauri-apps/api/menu.js generated vendored Normal file
View File

@ -0,0 +1,16 @@
export { Submenu, itemFromKind } from './menu/submenu.js';
export { MenuItem } from './menu/menuItem.js';
export { Menu } from './menu/menu.js';
export { CheckMenuItem } from './menu/checkMenuItem.js';
export { IconMenuItem, NativeIcon } from './menu/iconMenuItem.js';
export { PredefinedMenuItem } from './menu/predefinedMenuItem.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Menu types and utilities.
*
* This package is also accessible with `window.__TAURI__.menu` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/

100
node_modules/@tauri-apps/api/menu/base.cjs generated vendored Normal file
View File

@ -0,0 +1,100 @@
'use strict';
var tslib_es6 = require('../external/tslib/tslib.es6.cjs');
var core = require('../core.cjs');
var image = require('../image.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
var _MenuItemBase_id, _MenuItemBase_kind;
function injectChannel(i) {
var _a;
if ('items' in i) {
i.items = (_a = i.items) === null || _a === void 0 ? void 0 : _a.map((item) => 'rid' in item ? item : injectChannel(item));
}
else if ('action' in i && i.action) {
const handler = new core.Channel();
handler.onmessage = i.action;
delete i.action;
return { ...i, handler };
}
return i;
}
async function newMenu(kind, opts) {
const handler = new core.Channel();
if (opts && typeof opts === 'object') {
if ('action' in opts && opts.action) {
handler.onmessage = opts.action;
delete opts.action;
}
// about predefined menu item icon
if ('item' in opts
&& opts.item
&& typeof opts.item === 'object'
&& 'About' in opts.item
&& opts.item.About
&& typeof opts.item.About === 'object'
&& 'icon' in opts.item.About
&& opts.item.About.icon) {
opts.item.About.icon = image.transformImage(opts.item.About.icon);
}
// icon menu item icon
if ('icon' in opts && opts.icon) {
opts.icon = image.transformImage(opts.icon);
}
// submenu items
if ('items' in opts && opts.items) {
function prepareItem(i) {
var _a;
if ('rid' in i) {
return [i.rid, i.kind];
}
if ('item' in i && typeof i.item === 'object' && ((_a = i.item.About) === null || _a === void 0 ? void 0 : _a.icon)) {
i.item.About.icon = image.transformImage(i.item.About.icon);
}
if ('icon' in i && i.icon) {
i.icon = image.transformImage(i.icon);
}
if ('items' in i && i.items) {
// @ts-expect-error the `prepareItem` return doesn't exactly match
// this is fine, because the difference is in `[number, string]` variant
i.items = i.items.map(prepareItem);
}
return injectChannel(i);
}
// @ts-expect-error the `prepareItem` return doesn't exactly match
// this is fine, because the difference is in `[number, string]` variant
opts.items = opts.items.map(prepareItem);
}
}
return core.invoke('plugin:menu|new', {
kind,
options: opts,
handler
});
}
class MenuItemBase extends core.Resource {
/** The id of this item. */
get id() {
return tslib_es6.__classPrivateFieldGet(this, _MenuItemBase_id, "f");
}
/** @ignore */
get kind() {
return tslib_es6.__classPrivateFieldGet(this, _MenuItemBase_kind, "f");
}
/** @ignore */
constructor(rid, id, kind) {
super(rid);
/** @ignore */
_MenuItemBase_id.set(this, void 0);
/** @ignore */
_MenuItemBase_kind.set(this, void 0);
tslib_es6.__classPrivateFieldSet(this, _MenuItemBase_id, id, "f");
tslib_es6.__classPrivateFieldSet(this, _MenuItemBase_kind, kind, "f");
}
}
_MenuItemBase_id = new WeakMap(), _MenuItemBase_kind = new WeakMap();
exports.MenuItemBase = MenuItemBase;
exports.newMenu = newMenu;

18
node_modules/@tauri-apps/api/menu/base.d.ts generated vendored Normal file
View File

@ -0,0 +1,18 @@
import { Resource } from '../core';
import { CheckMenuItemOptions } from './checkMenuItem';
import { IconMenuItemOptions } from './iconMenuItem';
import { MenuOptions } from './menu';
import { MenuItemOptions } from './menuItem';
import { PredefinedMenuItemOptions } from './predefinedMenuItem';
import { SubmenuOptions } from './submenu';
export type ItemKind = 'MenuItem' | 'Predefined' | 'Check' | 'Icon' | 'Submenu' | 'Menu';
export declare function newMenu(kind: ItemKind, opts?: MenuOptions | MenuItemOptions | SubmenuOptions | PredefinedMenuItemOptions | CheckMenuItemOptions | IconMenuItemOptions): Promise<[number, string]>;
export declare class MenuItemBase extends Resource {
#private;
/** The id of this item. */
get id(): string;
/** @ignore */
get kind(): string;
/** @ignore */
protected constructor(rid: number, id: string, kind: ItemKind);
}

97
node_modules/@tauri-apps/api/menu/base.js generated vendored Normal file
View File

@ -0,0 +1,97 @@
import { __classPrivateFieldGet, __classPrivateFieldSet } from '../external/tslib/tslib.es6.js';
import { Resource, Channel, invoke } from '../core.js';
import { transformImage } from '../image.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
var _MenuItemBase_id, _MenuItemBase_kind;
function injectChannel(i) {
var _a;
if ('items' in i) {
i.items = (_a = i.items) === null || _a === void 0 ? void 0 : _a.map((item) => 'rid' in item ? item : injectChannel(item));
}
else if ('action' in i && i.action) {
const handler = new Channel();
handler.onmessage = i.action;
delete i.action;
return { ...i, handler };
}
return i;
}
async function newMenu(kind, opts) {
const handler = new Channel();
if (opts && typeof opts === 'object') {
if ('action' in opts && opts.action) {
handler.onmessage = opts.action;
delete opts.action;
}
// about predefined menu item icon
if ('item' in opts
&& opts.item
&& typeof opts.item === 'object'
&& 'About' in opts.item
&& opts.item.About
&& typeof opts.item.About === 'object'
&& 'icon' in opts.item.About
&& opts.item.About.icon) {
opts.item.About.icon = transformImage(opts.item.About.icon);
}
// icon menu item icon
if ('icon' in opts && opts.icon) {
opts.icon = transformImage(opts.icon);
}
// submenu items
if ('items' in opts && opts.items) {
function prepareItem(i) {
var _a;
if ('rid' in i) {
return [i.rid, i.kind];
}
if ('item' in i && typeof i.item === 'object' && ((_a = i.item.About) === null || _a === void 0 ? void 0 : _a.icon)) {
i.item.About.icon = transformImage(i.item.About.icon);
}
if ('icon' in i && i.icon) {
i.icon = transformImage(i.icon);
}
if ('items' in i && i.items) {
// @ts-expect-error the `prepareItem` return doesn't exactly match
// this is fine, because the difference is in `[number, string]` variant
i.items = i.items.map(prepareItem);
}
return injectChannel(i);
}
// @ts-expect-error the `prepareItem` return doesn't exactly match
// this is fine, because the difference is in `[number, string]` variant
opts.items = opts.items.map(prepareItem);
}
}
return invoke('plugin:menu|new', {
kind,
options: opts,
handler
});
}
class MenuItemBase extends Resource {
/** The id of this item. */
get id() {
return __classPrivateFieldGet(this, _MenuItemBase_id, "f");
}
/** @ignore */
get kind() {
return __classPrivateFieldGet(this, _MenuItemBase_kind, "f");
}
/** @ignore */
constructor(rid, id, kind) {
super(rid);
/** @ignore */
_MenuItemBase_id.set(this, void 0);
/** @ignore */
_MenuItemBase_kind.set(this, void 0);
__classPrivateFieldSet(this, _MenuItemBase_id, id, "f");
__classPrivateFieldSet(this, _MenuItemBase_kind, kind, "f");
}
}
_MenuItemBase_id = new WeakMap(), _MenuItemBase_kind = new WeakMap();
export { MenuItemBase, newMenu };

68
node_modules/@tauri-apps/api/menu/checkMenuItem.cjs generated vendored Normal file
View File

@ -0,0 +1,68 @@
'use strict';
var base = require('./base.cjs');
var core = require('../core.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* A check menu item inside a {@linkcode Menu} or {@linkcode Submenu}
* and usually contains a text and a check mark or a similar toggle
* that corresponds to a checked and unchecked states.
*/
class CheckMenuItem extends base.MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Check');
}
/** Create a new check menu item. */
static async new(opts) {
return base.newMenu('Check', opts).then(([rid, id]) => new CheckMenuItem(rid, id));
}
/** Returns the text of this check menu item. */
async text() {
return core.invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this check menu item. */
async setText(text) {
return core.invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
/** Returns whether this check menu item is enabled or not. */
async isEnabled() {
return core.invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind });
}
/** Sets whether this check menu item is enabled or not. */
async setEnabled(enabled) {
return core.invoke('plugin:menu|set_enabled', {
rid: this.rid,
kind: this.kind,
enabled
});
}
/** Sets the accelerator for this check menu item. */
async setAccelerator(accelerator) {
return core.invoke('plugin:menu|set_accelerator', {
rid: this.rid,
kind: this.kind,
accelerator
});
}
/** Returns whether this check menu item is checked or not. */
async isChecked() {
return core.invoke('plugin:menu|is_checked', { rid: this.rid });
}
/** Sets whether this check menu item is checked or not. */
async setChecked(checked) {
return core.invoke('plugin:menu|set_checked', {
rid: this.rid,
checked
});
}
}
exports.CheckMenuItem = CheckMenuItem;

32
node_modules/@tauri-apps/api/menu/checkMenuItem.d.ts generated vendored Normal file
View File

@ -0,0 +1,32 @@
import { MenuItemBase } from './base';
import { type MenuItemOptions } from '../menu';
/** Options for creating a new check menu item. */
export interface CheckMenuItemOptions extends MenuItemOptions {
/** Whether the new check menu item is enabled or not. */
checked?: boolean;
}
/**
* A check menu item inside a {@linkcode Menu} or {@linkcode Submenu}
* and usually contains a text and a check mark or a similar toggle
* that corresponds to a checked and unchecked states.
*/
export declare class CheckMenuItem extends MenuItemBase {
/** @ignore */
protected constructor(rid: number, id: string);
/** Create a new check menu item. */
static new(opts: CheckMenuItemOptions): Promise<CheckMenuItem>;
/** Returns the text of this check menu item. */
text(): Promise<string>;
/** Sets the text for this check menu item. */
setText(text: string): Promise<void>;
/** Returns whether this check menu item is enabled or not. */
isEnabled(): Promise<boolean>;
/** Sets whether this check menu item is enabled or not. */
setEnabled(enabled: boolean): Promise<void>;
/** Sets the accelerator for this check menu item. */
setAccelerator(accelerator: string | null): Promise<void>;
/** Returns whether this check menu item is checked or not. */
isChecked(): Promise<boolean>;
/** Sets whether this check menu item is checked or not. */
setChecked(checked: boolean): Promise<void>;
}

66
node_modules/@tauri-apps/api/menu/checkMenuItem.js generated vendored Normal file
View File

@ -0,0 +1,66 @@
import { MenuItemBase, newMenu } from './base.js';
import { invoke } from '../core.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* A check menu item inside a {@linkcode Menu} or {@linkcode Submenu}
* and usually contains a text and a check mark or a similar toggle
* that corresponds to a checked and unchecked states.
*/
class CheckMenuItem extends MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Check');
}
/** Create a new check menu item. */
static async new(opts) {
return newMenu('Check', opts).then(([rid, id]) => new CheckMenuItem(rid, id));
}
/** Returns the text of this check menu item. */
async text() {
return invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this check menu item. */
async setText(text) {
return invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
/** Returns whether this check menu item is enabled or not. */
async isEnabled() {
return invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind });
}
/** Sets whether this check menu item is enabled or not. */
async setEnabled(enabled) {
return invoke('plugin:menu|set_enabled', {
rid: this.rid,
kind: this.kind,
enabled
});
}
/** Sets the accelerator for this check menu item. */
async setAccelerator(accelerator) {
return invoke('plugin:menu|set_accelerator', {
rid: this.rid,
kind: this.kind,
accelerator
});
}
/** Returns whether this check menu item is checked or not. */
async isChecked() {
return invoke('plugin:menu|is_checked', { rid: this.rid });
}
/** Sets whether this check menu item is checked or not. */
async setChecked(checked) {
return invoke('plugin:menu|set_checked', {
rid: this.rid,
checked
});
}
}
export { CheckMenuItem };

187
node_modules/@tauri-apps/api/menu/iconMenuItem.cjs generated vendored Normal file
View File

@ -0,0 +1,187 @@
'use strict';
var base = require('./base.cjs');
var core = require('../core.cjs');
var image = require('../image.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* A native Icon to be used for the menu item
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
exports.NativeIcon = void 0;
(function (NativeIcon) {
/** An add item template image. */
NativeIcon["Add"] = "Add";
/** Advanced preferences toolbar icon for the preferences window. */
NativeIcon["Advanced"] = "Advanced";
/** A Bluetooth template image. */
NativeIcon["Bluetooth"] = "Bluetooth";
/** Bookmarks image suitable for a template. */
NativeIcon["Bookmarks"] = "Bookmarks";
/** A caution image. */
NativeIcon["Caution"] = "Caution";
/** A color panel toolbar icon. */
NativeIcon["ColorPanel"] = "ColorPanel";
/** A column view mode template image. */
NativeIcon["ColumnView"] = "ColumnView";
/** A computer icon. */
NativeIcon["Computer"] = "Computer";
/** An enter full-screen mode template image. */
NativeIcon["EnterFullScreen"] = "EnterFullScreen";
/** Permissions for all users. */
NativeIcon["Everyone"] = "Everyone";
/** An exit full-screen mode template image. */
NativeIcon["ExitFullScreen"] = "ExitFullScreen";
/** A cover flow view mode template image. */
NativeIcon["FlowView"] = "FlowView";
/** A folder image. */
NativeIcon["Folder"] = "Folder";
/** A burnable folder icon. */
NativeIcon["FolderBurnable"] = "FolderBurnable";
/** A smart folder icon. */
NativeIcon["FolderSmart"] = "FolderSmart";
/** A link template image. */
NativeIcon["FollowLinkFreestanding"] = "FollowLinkFreestanding";
/** A font panel toolbar icon. */
NativeIcon["FontPanel"] = "FontPanel";
/** A `go back` template image. */
NativeIcon["GoLeft"] = "GoLeft";
/** A `go forward` template image. */
NativeIcon["GoRight"] = "GoRight";
/** Home image suitable for a template. */
NativeIcon["Home"] = "Home";
/** An iChat Theater template image. */
NativeIcon["IChatTheater"] = "IChatTheater";
/** An icon view mode template image. */
NativeIcon["IconView"] = "IconView";
/** An information toolbar icon. */
NativeIcon["Info"] = "Info";
/** A template image used to denote invalid data. */
NativeIcon["InvalidDataFreestanding"] = "InvalidDataFreestanding";
/** A generic left-facing triangle template image. */
NativeIcon["LeftFacingTriangle"] = "LeftFacingTriangle";
/** A list view mode template image. */
NativeIcon["ListView"] = "ListView";
/** A locked padlock template image. */
NativeIcon["LockLocked"] = "LockLocked";
/** An unlocked padlock template image. */
NativeIcon["LockUnlocked"] = "LockUnlocked";
/** A horizontal dash, for use in menus. */
NativeIcon["MenuMixedState"] = "MenuMixedState";
/** A check mark template image, for use in menus. */
NativeIcon["MenuOnState"] = "MenuOnState";
/** A MobileMe icon. */
NativeIcon["MobileMe"] = "MobileMe";
/** A drag image for multiple items. */
NativeIcon["MultipleDocuments"] = "MultipleDocuments";
/** A network icon. */
NativeIcon["Network"] = "Network";
/** A path button template image. */
NativeIcon["Path"] = "Path";
/** General preferences toolbar icon for the preferences window. */
NativeIcon["PreferencesGeneral"] = "PreferencesGeneral";
/** A Quick Look template image. */
NativeIcon["QuickLook"] = "QuickLook";
/** A refresh template image. */
NativeIcon["RefreshFreestanding"] = "RefreshFreestanding";
/** A refresh template image. */
NativeIcon["Refresh"] = "Refresh";
/** A remove item template image. */
NativeIcon["Remove"] = "Remove";
/** A reveal contents template image. */
NativeIcon["RevealFreestanding"] = "RevealFreestanding";
/** A generic right-facing triangle template image. */
NativeIcon["RightFacingTriangle"] = "RightFacingTriangle";
/** A share view template image. */
NativeIcon["Share"] = "Share";
/** A slideshow template image. */
NativeIcon["Slideshow"] = "Slideshow";
/** A badge for a `smart` item. */
NativeIcon["SmartBadge"] = "SmartBadge";
/** Small green indicator, similar to iChat's available image. */
NativeIcon["StatusAvailable"] = "StatusAvailable";
/** Small clear indicator. */
NativeIcon["StatusNone"] = "StatusNone";
/** Small yellow indicator, similar to iChat's idle image. */
NativeIcon["StatusPartiallyAvailable"] = "StatusPartiallyAvailable";
/** Small red indicator, similar to iChat's unavailable image. */
NativeIcon["StatusUnavailable"] = "StatusUnavailable";
/** A stop progress template image. */
NativeIcon["StopProgressFreestanding"] = "StopProgressFreestanding";
/** A stop progress button template image. */
NativeIcon["StopProgress"] = "StopProgress";
/** An image of the empty trash can. */
NativeIcon["TrashEmpty"] = "TrashEmpty";
/** An image of the full trash can. */
NativeIcon["TrashFull"] = "TrashFull";
/** Permissions for a single user. */
NativeIcon["User"] = "User";
/** User account toolbar icon for the preferences window. */
NativeIcon["UserAccounts"] = "UserAccounts";
/** Permissions for a group of users. */
NativeIcon["UserGroup"] = "UserGroup";
/** Permissions for guests. */
NativeIcon["UserGuest"] = "UserGuest";
})(exports.NativeIcon || (exports.NativeIcon = {}));
/**
* An icon menu item inside a {@linkcode Menu} or {@linkcode Submenu}
* and usually contains an icon and a text.
*/
class IconMenuItem extends base.MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Icon');
}
/** Create a new icon menu item. */
static async new(opts) {
return base.newMenu('Icon', opts).then(([rid, id]) => new IconMenuItem(rid, id));
}
/** Returns the text of this icon menu item. */
async text() {
return core.invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this icon menu item. */
async setText(text) {
return core.invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
/** Returns whether this icon menu item is enabled or not. */
async isEnabled() {
return core.invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind });
}
/** Sets whether this icon menu item is enabled or not. */
async setEnabled(enabled) {
return core.invoke('plugin:menu|set_enabled', {
rid: this.rid,
kind: this.kind,
enabled
});
}
/** Sets the accelerator for this icon menu item. */
async setAccelerator(accelerator) {
return core.invoke('plugin:menu|set_accelerator', {
rid: this.rid,
kind: this.kind,
accelerator
});
}
/** Sets an icon for this icon menu item */
async setIcon(icon) {
return core.invoke('plugin:menu|set_icon', {
rid: this.rid,
kind: this.kind,
icon: image.transformImage(icon)
});
}
}
exports.IconMenuItem = IconMenuItem;

160
node_modules/@tauri-apps/api/menu/iconMenuItem.d.ts generated vendored Normal file
View File

@ -0,0 +1,160 @@
import { MenuItemBase } from './base';
import { type MenuItemOptions } from '../menu';
import { MenuIcon } from '../image';
/**
* A native Icon to be used for the menu item
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
export declare enum NativeIcon {
/** An add item template image. */
Add = "Add",
/** Advanced preferences toolbar icon for the preferences window. */
Advanced = "Advanced",
/** A Bluetooth template image. */
Bluetooth = "Bluetooth",
/** Bookmarks image suitable for a template. */
Bookmarks = "Bookmarks",
/** A caution image. */
Caution = "Caution",
/** A color panel toolbar icon. */
ColorPanel = "ColorPanel",
/** A column view mode template image. */
ColumnView = "ColumnView",
/** A computer icon. */
Computer = "Computer",
/** An enter full-screen mode template image. */
EnterFullScreen = "EnterFullScreen",
/** Permissions for all users. */
Everyone = "Everyone",
/** An exit full-screen mode template image. */
ExitFullScreen = "ExitFullScreen",
/** A cover flow view mode template image. */
FlowView = "FlowView",
/** A folder image. */
Folder = "Folder",
/** A burnable folder icon. */
FolderBurnable = "FolderBurnable",
/** A smart folder icon. */
FolderSmart = "FolderSmart",
/** A link template image. */
FollowLinkFreestanding = "FollowLinkFreestanding",
/** A font panel toolbar icon. */
FontPanel = "FontPanel",
/** A `go back` template image. */
GoLeft = "GoLeft",
/** A `go forward` template image. */
GoRight = "GoRight",
/** Home image suitable for a template. */
Home = "Home",
/** An iChat Theater template image. */
IChatTheater = "IChatTheater",
/** An icon view mode template image. */
IconView = "IconView",
/** An information toolbar icon. */
Info = "Info",
/** A template image used to denote invalid data. */
InvalidDataFreestanding = "InvalidDataFreestanding",
/** A generic left-facing triangle template image. */
LeftFacingTriangle = "LeftFacingTriangle",
/** A list view mode template image. */
ListView = "ListView",
/** A locked padlock template image. */
LockLocked = "LockLocked",
/** An unlocked padlock template image. */
LockUnlocked = "LockUnlocked",
/** A horizontal dash, for use in menus. */
MenuMixedState = "MenuMixedState",
/** A check mark template image, for use in menus. */
MenuOnState = "MenuOnState",
/** A MobileMe icon. */
MobileMe = "MobileMe",
/** A drag image for multiple items. */
MultipleDocuments = "MultipleDocuments",
/** A network icon. */
Network = "Network",
/** A path button template image. */
Path = "Path",
/** General preferences toolbar icon for the preferences window. */
PreferencesGeneral = "PreferencesGeneral",
/** A Quick Look template image. */
QuickLook = "QuickLook",
/** A refresh template image. */
RefreshFreestanding = "RefreshFreestanding",
/** A refresh template image. */
Refresh = "Refresh",
/** A remove item template image. */
Remove = "Remove",
/** A reveal contents template image. */
RevealFreestanding = "RevealFreestanding",
/** A generic right-facing triangle template image. */
RightFacingTriangle = "RightFacingTriangle",
/** A share view template image. */
Share = "Share",
/** A slideshow template image. */
Slideshow = "Slideshow",
/** A badge for a `smart` item. */
SmartBadge = "SmartBadge",
/** Small green indicator, similar to iChat's available image. */
StatusAvailable = "StatusAvailable",
/** Small clear indicator. */
StatusNone = "StatusNone",
/** Small yellow indicator, similar to iChat's idle image. */
StatusPartiallyAvailable = "StatusPartiallyAvailable",
/** Small red indicator, similar to iChat's unavailable image. */
StatusUnavailable = "StatusUnavailable",
/** A stop progress template image. */
StopProgressFreestanding = "StopProgressFreestanding",
/** A stop progress button template image. */
StopProgress = "StopProgress",
/** An image of the empty trash can. */
TrashEmpty = "TrashEmpty",
/** An image of the full trash can. */
TrashFull = "TrashFull",
/** Permissions for a single user. */
User = "User",
/** User account toolbar icon for the preferences window. */
UserAccounts = "UserAccounts",
/** Permissions for a group of users. */
UserGroup = "UserGroup",
/** Permissions for guests. */
UserGuest = "UserGuest"
}
/** Options for creating a new icon menu item. */
export interface IconMenuItemOptions extends MenuItemOptions {
/**
* Icon to be used for the new icon menu item.
*
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
icon?: MenuIcon;
}
/**
* An icon menu item inside a {@linkcode Menu} or {@linkcode Submenu}
* and usually contains an icon and a text.
*/
export declare class IconMenuItem extends MenuItemBase {
/** @ignore */
protected constructor(rid: number, id: string);
/** Create a new icon menu item. */
static new(opts: IconMenuItemOptions): Promise<IconMenuItem>;
/** Returns the text of this icon menu item. */
text(): Promise<string>;
/** Sets the text for this icon menu item. */
setText(text: string): Promise<void>;
/** Returns whether this icon menu item is enabled or not. */
isEnabled(): Promise<boolean>;
/** Sets whether this icon menu item is enabled or not. */
setEnabled(enabled: boolean): Promise<void>;
/** Sets the accelerator for this icon menu item. */
setAccelerator(accelerator: string | null): Promise<void>;
/** Sets an icon for this icon menu item */
setIcon(icon: MenuIcon | null): Promise<void>;
}

185
node_modules/@tauri-apps/api/menu/iconMenuItem.js generated vendored Normal file
View File

@ -0,0 +1,185 @@
import { MenuItemBase, newMenu } from './base.js';
import { invoke } from '../core.js';
import { transformImage } from '../image.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* A native Icon to be used for the menu item
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
var NativeIcon;
(function (NativeIcon) {
/** An add item template image. */
NativeIcon["Add"] = "Add";
/** Advanced preferences toolbar icon for the preferences window. */
NativeIcon["Advanced"] = "Advanced";
/** A Bluetooth template image. */
NativeIcon["Bluetooth"] = "Bluetooth";
/** Bookmarks image suitable for a template. */
NativeIcon["Bookmarks"] = "Bookmarks";
/** A caution image. */
NativeIcon["Caution"] = "Caution";
/** A color panel toolbar icon. */
NativeIcon["ColorPanel"] = "ColorPanel";
/** A column view mode template image. */
NativeIcon["ColumnView"] = "ColumnView";
/** A computer icon. */
NativeIcon["Computer"] = "Computer";
/** An enter full-screen mode template image. */
NativeIcon["EnterFullScreen"] = "EnterFullScreen";
/** Permissions for all users. */
NativeIcon["Everyone"] = "Everyone";
/** An exit full-screen mode template image. */
NativeIcon["ExitFullScreen"] = "ExitFullScreen";
/** A cover flow view mode template image. */
NativeIcon["FlowView"] = "FlowView";
/** A folder image. */
NativeIcon["Folder"] = "Folder";
/** A burnable folder icon. */
NativeIcon["FolderBurnable"] = "FolderBurnable";
/** A smart folder icon. */
NativeIcon["FolderSmart"] = "FolderSmart";
/** A link template image. */
NativeIcon["FollowLinkFreestanding"] = "FollowLinkFreestanding";
/** A font panel toolbar icon. */
NativeIcon["FontPanel"] = "FontPanel";
/** A `go back` template image. */
NativeIcon["GoLeft"] = "GoLeft";
/** A `go forward` template image. */
NativeIcon["GoRight"] = "GoRight";
/** Home image suitable for a template. */
NativeIcon["Home"] = "Home";
/** An iChat Theater template image. */
NativeIcon["IChatTheater"] = "IChatTheater";
/** An icon view mode template image. */
NativeIcon["IconView"] = "IconView";
/** An information toolbar icon. */
NativeIcon["Info"] = "Info";
/** A template image used to denote invalid data. */
NativeIcon["InvalidDataFreestanding"] = "InvalidDataFreestanding";
/** A generic left-facing triangle template image. */
NativeIcon["LeftFacingTriangle"] = "LeftFacingTriangle";
/** A list view mode template image. */
NativeIcon["ListView"] = "ListView";
/** A locked padlock template image. */
NativeIcon["LockLocked"] = "LockLocked";
/** An unlocked padlock template image. */
NativeIcon["LockUnlocked"] = "LockUnlocked";
/** A horizontal dash, for use in menus. */
NativeIcon["MenuMixedState"] = "MenuMixedState";
/** A check mark template image, for use in menus. */
NativeIcon["MenuOnState"] = "MenuOnState";
/** A MobileMe icon. */
NativeIcon["MobileMe"] = "MobileMe";
/** A drag image for multiple items. */
NativeIcon["MultipleDocuments"] = "MultipleDocuments";
/** A network icon. */
NativeIcon["Network"] = "Network";
/** A path button template image. */
NativeIcon["Path"] = "Path";
/** General preferences toolbar icon for the preferences window. */
NativeIcon["PreferencesGeneral"] = "PreferencesGeneral";
/** A Quick Look template image. */
NativeIcon["QuickLook"] = "QuickLook";
/** A refresh template image. */
NativeIcon["RefreshFreestanding"] = "RefreshFreestanding";
/** A refresh template image. */
NativeIcon["Refresh"] = "Refresh";
/** A remove item template image. */
NativeIcon["Remove"] = "Remove";
/** A reveal contents template image. */
NativeIcon["RevealFreestanding"] = "RevealFreestanding";
/** A generic right-facing triangle template image. */
NativeIcon["RightFacingTriangle"] = "RightFacingTriangle";
/** A share view template image. */
NativeIcon["Share"] = "Share";
/** A slideshow template image. */
NativeIcon["Slideshow"] = "Slideshow";
/** A badge for a `smart` item. */
NativeIcon["SmartBadge"] = "SmartBadge";
/** Small green indicator, similar to iChat's available image. */
NativeIcon["StatusAvailable"] = "StatusAvailable";
/** Small clear indicator. */
NativeIcon["StatusNone"] = "StatusNone";
/** Small yellow indicator, similar to iChat's idle image. */
NativeIcon["StatusPartiallyAvailable"] = "StatusPartiallyAvailable";
/** Small red indicator, similar to iChat's unavailable image. */
NativeIcon["StatusUnavailable"] = "StatusUnavailable";
/** A stop progress template image. */
NativeIcon["StopProgressFreestanding"] = "StopProgressFreestanding";
/** A stop progress button template image. */
NativeIcon["StopProgress"] = "StopProgress";
/** An image of the empty trash can. */
NativeIcon["TrashEmpty"] = "TrashEmpty";
/** An image of the full trash can. */
NativeIcon["TrashFull"] = "TrashFull";
/** Permissions for a single user. */
NativeIcon["User"] = "User";
/** User account toolbar icon for the preferences window. */
NativeIcon["UserAccounts"] = "UserAccounts";
/** Permissions for a group of users. */
NativeIcon["UserGroup"] = "UserGroup";
/** Permissions for guests. */
NativeIcon["UserGuest"] = "UserGuest";
})(NativeIcon || (NativeIcon = {}));
/**
* An icon menu item inside a {@linkcode Menu} or {@linkcode Submenu}
* and usually contains an icon and a text.
*/
class IconMenuItem extends MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Icon');
}
/** Create a new icon menu item. */
static async new(opts) {
return newMenu('Icon', opts).then(([rid, id]) => new IconMenuItem(rid, id));
}
/** Returns the text of this icon menu item. */
async text() {
return invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this icon menu item. */
async setText(text) {
return invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
/** Returns whether this icon menu item is enabled or not. */
async isEnabled() {
return invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind });
}
/** Sets whether this icon menu item is enabled or not. */
async setEnabled(enabled) {
return invoke('plugin:menu|set_enabled', {
rid: this.rid,
kind: this.kind,
enabled
});
}
/** Sets the accelerator for this icon menu item. */
async setAccelerator(accelerator) {
return invoke('plugin:menu|set_accelerator', {
rid: this.rid,
kind: this.kind,
accelerator
});
}
/** Sets an icon for this icon menu item */
async setIcon(icon) {
return invoke('plugin:menu|set_icon', {
rid: this.rid,
kind: this.kind,
icon: transformImage(icon)
});
}
}
export { IconMenuItem, NativeIcon };

148
node_modules/@tauri-apps/api/menu/menu.cjs generated vendored Normal file
View File

@ -0,0 +1,148 @@
'use strict';
var submenu = require('./submenu.cjs');
var dpi = require('../dpi.cjs');
var core = require('../core.cjs');
var base = require('./base.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** A type that is either a menu bar on the window
* on Windows and Linux or as a global menu in the menubar on macOS.
*
* #### Platform-specific:
*
* - **macOS**: if using {@linkcode Menu} for the global menubar, it can only contain {@linkcode Submenu}s.
*/
class Menu extends base.MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Menu');
}
/** Create a new menu. */
static async new(opts) {
return base.newMenu('Menu', opts).then(([rid, id]) => new Menu(rid, id));
}
/** Create a default menu. */
static async default() {
return core.invoke('plugin:menu|create_default').then(([rid, id]) => new Menu(rid, id));
}
/**
* Add a menu item to the end of this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async append(items) {
return core.invoke('plugin:menu|append', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i)
});
}
/**
* Add a menu item to the beginning of this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async prepend(items) {
return core.invoke('plugin:menu|prepend', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i)
});
}
/**
* Add a menu item to the specified position in this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async insert(items, position) {
return core.invoke('plugin:menu|insert', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i),
position
});
}
/** Remove a menu item from this menu. */
async remove(item) {
return core.invoke('plugin:menu|remove', {
rid: this.rid,
kind: this.kind,
item: [item.rid, item.kind]
});
}
/** Remove a menu item from this menu at the specified position. */
async removeAt(position) {
return core.invoke('plugin:menu|remove_at', {
rid: this.rid,
kind: this.kind,
position
}).then(submenu.itemFromKind);
}
/** Returns a list of menu items that has been added to this menu. */
async items() {
return core.invoke('plugin:menu|items', {
rid: this.rid,
kind: this.kind
}).then((i) => i.map(submenu.itemFromKind));
}
/** Retrieves the menu item matching the given identifier. */
async get(id) {
return core.invoke('plugin:menu|get', {
rid: this.rid,
kind: this.kind,
id
}).then((r) => (r ? submenu.itemFromKind(r) : null));
}
/**
* Popup this menu as a context menu on the specified window.
*
* @param at If a position is provided, it is relative to the window's top-left corner.
* If there isn't one provided, the menu will pop up at the current location of the mouse.
*/
async popup(at, window) {
var _a;
return core.invoke('plugin:menu|popup', {
rid: this.rid,
kind: this.kind,
window: (_a = window === null || window === void 0 ? void 0 : window.label) !== null && _a !== void 0 ? _a : null,
at: at instanceof dpi.Position ? at : at ? new dpi.Position(at) : null
});
}
/**
* Sets the app-wide menu and returns the previous one.
*
* If a window was not created with an explicit menu or had one set explicitly,
* this menu will be assigned to it.
*/
async setAsAppMenu() {
return core.invoke('plugin:menu|set_as_app_menu', {
rid: this.rid
}).then((r) => (r ? new Menu(r[0], r[1]) : null));
}
/**
* Sets the window menu and returns the previous one.
*
* #### Platform-specific:
*
* - **macOS:** Unsupported. The menu on macOS is app-wide and not specific to one
* window, if you need to set it, use {@linkcode Menu.setAsAppMenu} instead.
*/
async setAsWindowMenu(window) {
var _a;
return core.invoke('plugin:menu|set_as_window_menu', {
rid: this.rid,
window: (_a = window === null || window === void 0 ? void 0 : window.label) !== null && _a !== void 0 ? _a : null
}).then((r) => (r ? new Menu(r[0], r[1]) : null));
}
}
exports.Menu = Menu;

86
node_modules/@tauri-apps/api/menu/menu.d.ts generated vendored Normal file
View File

@ -0,0 +1,86 @@
import { MenuItemOptions, SubmenuOptions, IconMenuItemOptions, PredefinedMenuItemOptions, CheckMenuItemOptions } from '../menu';
import { MenuItem } from './menuItem';
import { CheckMenuItem } from './checkMenuItem';
import { IconMenuItem } from './iconMenuItem';
import { PredefinedMenuItem } from './predefinedMenuItem';
import { Submenu } from './submenu';
import { type LogicalPosition, PhysicalPosition, Position } from '../dpi';
import { type Window } from '../window';
import { MenuItemBase } from './base';
/** Options for creating a new menu. */
export interface MenuOptions {
/** Specify an id to use for the new menu. */
id?: string;
/** List of items to add to the new menu. */
items?: Array<Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | MenuItemOptions | SubmenuOptions | IconMenuItemOptions | PredefinedMenuItemOptions | CheckMenuItemOptions>;
}
/** A type that is either a menu bar on the window
* on Windows and Linux or as a global menu in the menubar on macOS.
*
* #### Platform-specific:
*
* - **macOS**: if using {@linkcode Menu} for the global menubar, it can only contain {@linkcode Submenu}s.
*/
export declare class Menu extends MenuItemBase {
/** @ignore */
protected constructor(rid: number, id: string);
/** Create a new menu. */
static new(opts?: MenuOptions): Promise<Menu>;
/** Create a default menu. */
static default(): Promise<Menu>;
/**
* Add a menu item to the end of this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
append<T extends Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | MenuItemOptions | SubmenuOptions | IconMenuItemOptions | PredefinedMenuItemOptions | CheckMenuItemOptions>(items: T | T[]): Promise<void>;
/**
* Add a menu item to the beginning of this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
prepend<T extends Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | MenuItemOptions | SubmenuOptions | IconMenuItemOptions | PredefinedMenuItemOptions | CheckMenuItemOptions>(items: T | T[]): Promise<void>;
/**
* Add a menu item to the specified position in this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
insert<T extends Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | MenuItemOptions | SubmenuOptions | IconMenuItemOptions | PredefinedMenuItemOptions | CheckMenuItemOptions>(items: T | T[], position: number): Promise<void>;
/** Remove a menu item from this menu. */
remove(item: Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem): Promise<void>;
/** Remove a menu item from this menu at the specified position. */
removeAt(position: number): Promise<Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | null>;
/** Returns a list of menu items that has been added to this menu. */
items(): Promise<Array<Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem>>;
/** Retrieves the menu item matching the given identifier. */
get(id: string): Promise<Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | null>;
/**
* Popup this menu as a context menu on the specified window.
*
* @param at If a position is provided, it is relative to the window's top-left corner.
* If there isn't one provided, the menu will pop up at the current location of the mouse.
*/
popup(at?: PhysicalPosition | LogicalPosition | Position, window?: Window): Promise<void>;
/**
* Sets the app-wide menu and returns the previous one.
*
* If a window was not created with an explicit menu or had one set explicitly,
* this menu will be assigned to it.
*/
setAsAppMenu(): Promise<Menu | null>;
/**
* Sets the window menu and returns the previous one.
*
* #### Platform-specific:
*
* - **macOS:** Unsupported. The menu on macOS is app-wide and not specific to one
* window, if you need to set it, use {@linkcode Menu.setAsAppMenu} instead.
*/
setAsWindowMenu(window?: Window): Promise<Menu | null>;
}

146
node_modules/@tauri-apps/api/menu/menu.js generated vendored Normal file
View File

@ -0,0 +1,146 @@
import { itemFromKind } from './submenu.js';
import { Position } from '../dpi.js';
import { invoke } from '../core.js';
import { MenuItemBase, newMenu } from './base.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** A type that is either a menu bar on the window
* on Windows and Linux or as a global menu in the menubar on macOS.
*
* #### Platform-specific:
*
* - **macOS**: if using {@linkcode Menu} for the global menubar, it can only contain {@linkcode Submenu}s.
*/
class Menu extends MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Menu');
}
/** Create a new menu. */
static async new(opts) {
return newMenu('Menu', opts).then(([rid, id]) => new Menu(rid, id));
}
/** Create a default menu. */
static async default() {
return invoke('plugin:menu|create_default').then(([rid, id]) => new Menu(rid, id));
}
/**
* Add a menu item to the end of this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async append(items) {
return invoke('plugin:menu|append', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i)
});
}
/**
* Add a menu item to the beginning of this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async prepend(items) {
return invoke('plugin:menu|prepend', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i)
});
}
/**
* Add a menu item to the specified position in this menu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async insert(items, position) {
return invoke('plugin:menu|insert', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i),
position
});
}
/** Remove a menu item from this menu. */
async remove(item) {
return invoke('plugin:menu|remove', {
rid: this.rid,
kind: this.kind,
item: [item.rid, item.kind]
});
}
/** Remove a menu item from this menu at the specified position. */
async removeAt(position) {
return invoke('plugin:menu|remove_at', {
rid: this.rid,
kind: this.kind,
position
}).then(itemFromKind);
}
/** Returns a list of menu items that has been added to this menu. */
async items() {
return invoke('plugin:menu|items', {
rid: this.rid,
kind: this.kind
}).then((i) => i.map(itemFromKind));
}
/** Retrieves the menu item matching the given identifier. */
async get(id) {
return invoke('plugin:menu|get', {
rid: this.rid,
kind: this.kind,
id
}).then((r) => (r ? itemFromKind(r) : null));
}
/**
* Popup this menu as a context menu on the specified window.
*
* @param at If a position is provided, it is relative to the window's top-left corner.
* If there isn't one provided, the menu will pop up at the current location of the mouse.
*/
async popup(at, window) {
var _a;
return invoke('plugin:menu|popup', {
rid: this.rid,
kind: this.kind,
window: (_a = window === null || window === void 0 ? void 0 : window.label) !== null && _a !== void 0 ? _a : null,
at: at instanceof Position ? at : at ? new Position(at) : null
});
}
/**
* Sets the app-wide menu and returns the previous one.
*
* If a window was not created with an explicit menu or had one set explicitly,
* this menu will be assigned to it.
*/
async setAsAppMenu() {
return invoke('plugin:menu|set_as_app_menu', {
rid: this.rid
}).then((r) => (r ? new Menu(r[0], r[1]) : null));
}
/**
* Sets the window menu and returns the previous one.
*
* #### Platform-specific:
*
* - **macOS:** Unsupported. The menu on macOS is app-wide and not specific to one
* window, if you need to set it, use {@linkcode Menu.setAsAppMenu} instead.
*/
async setAsWindowMenu(window) {
var _a;
return invoke('plugin:menu|set_as_window_menu', {
rid: this.rid,
window: (_a = window === null || window === void 0 ? void 0 : window.label) !== null && _a !== void 0 ? _a : null
}).then((r) => (r ? new Menu(r[0], r[1]) : null));
}
}
export { Menu };

53
node_modules/@tauri-apps/api/menu/menuItem.cjs generated vendored Normal file
View File

@ -0,0 +1,53 @@
'use strict';
var base = require('./base.cjs');
var core = require('../core.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** A menu item inside a {@linkcode Menu} or {@linkcode Submenu} and contains only text. */
class MenuItem extends base.MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'MenuItem');
}
/** Create a new menu item. */
static async new(opts) {
return base.newMenu('MenuItem', opts).then(([rid, id]) => new MenuItem(rid, id));
}
/** Returns the text of this menu item. */
async text() {
return core.invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this menu item. */
async setText(text) {
return core.invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
/** Returns whether this menu item is enabled or not. */
async isEnabled() {
return core.invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind });
}
/** Sets whether this menu item is enabled or not. */
async setEnabled(enabled) {
return core.invoke('plugin:menu|set_enabled', {
rid: this.rid,
kind: this.kind,
enabled
});
}
/** Sets the accelerator for this menu item. */
async setAccelerator(accelerator) {
return core.invoke('plugin:menu|set_accelerator', {
rid: this.rid,
kind: this.kind,
accelerator
});
}
}
exports.MenuItem = MenuItem;

31
node_modules/@tauri-apps/api/menu/menuItem.d.ts generated vendored Normal file
View File

@ -0,0 +1,31 @@
import { MenuItemBase } from './base';
/** Options for creating a new menu item. */
export interface MenuItemOptions {
/** Specify an id to use for the new menu item. */
id?: string;
/** The text of the new menu item. */
text: string;
/** Whether the new menu item is enabled or not. */
enabled?: boolean;
/** Specify an accelerator for the new menu item. */
accelerator?: string;
/** Specify a handler to be called when this menu item is activated. */
action?: (id: string) => void;
}
/** A menu item inside a {@linkcode Menu} or {@linkcode Submenu} and contains only text. */
export declare class MenuItem extends MenuItemBase {
/** @ignore */
protected constructor(rid: number, id: string);
/** Create a new menu item. */
static new(opts: MenuItemOptions): Promise<MenuItem>;
/** Returns the text of this menu item. */
text(): Promise<string>;
/** Sets the text for this menu item. */
setText(text: string): Promise<void>;
/** Returns whether this menu item is enabled or not. */
isEnabled(): Promise<boolean>;
/** Sets whether this menu item is enabled or not. */
setEnabled(enabled: boolean): Promise<void>;
/** Sets the accelerator for this menu item. */
setAccelerator(accelerator: string | null): Promise<void>;
}

51
node_modules/@tauri-apps/api/menu/menuItem.js generated vendored Normal file
View File

@ -0,0 +1,51 @@
import { MenuItemBase, newMenu } from './base.js';
import { invoke } from '../core.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** A menu item inside a {@linkcode Menu} or {@linkcode Submenu} and contains only text. */
class MenuItem extends MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'MenuItem');
}
/** Create a new menu item. */
static async new(opts) {
return newMenu('MenuItem', opts).then(([rid, id]) => new MenuItem(rid, id));
}
/** Returns the text of this menu item. */
async text() {
return invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this menu item. */
async setText(text) {
return invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
/** Returns whether this menu item is enabled or not. */
async isEnabled() {
return invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind });
}
/** Sets whether this menu item is enabled or not. */
async setEnabled(enabled) {
return invoke('plugin:menu|set_enabled', {
rid: this.rid,
kind: this.kind,
enabled
});
}
/** Sets the accelerator for this menu item. */
async setAccelerator(accelerator) {
return invoke('plugin:menu|set_accelerator', {
rid: this.rid,
kind: this.kind,
accelerator
});
}
}
export { MenuItem };

View File

@ -0,0 +1,33 @@
'use strict';
var base = require('./base.cjs');
var core = require('../core.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** A predefined (native) menu item which has a predefined behavior by the OS or by tauri. */
class PredefinedMenuItem extends base.MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Predefined');
}
/** Create a new predefined menu item. */
static async new(opts) {
return base.newMenu('Predefined', opts).then(([rid, id]) => new PredefinedMenuItem(rid, id));
}
/** Returns the text of this predefined menu item. */
async text() {
return core.invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this predefined menu item. */
async setText(text) {
return core.invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
}
exports.PredefinedMenuItem = PredefinedMenuItem;

View File

@ -0,0 +1,95 @@
import { MenuItemBase } from './base';
import { Image } from '../image';
/** A metadata for the about predefined menu item. */
export interface AboutMetadata {
/** Sets the application name. */
name?: string;
/** The application version. */
version?: string;
/**
* The short version, e.g. "1.0".
*
* #### Platform-specific
*
* - **Windows / Linux:** Appended to the end of `version` in parentheses.
*/
shortVersion?: string;
/**
* The authors of the application.
*
* #### Platform-specific
*
* - **macOS:** Unsupported.
*/
authors?: string[];
/**
* Application comments.
*
* #### Platform-specific
*
* - **macOS:** Unsupported.
*/
comments?: string;
/** The copyright of the application. */
copyright?: string;
/**
* The license of the application.
*
* #### Platform-specific
*
* - **macOS:** Unsupported.
*/
license?: string;
/**
* The application website.
*
* #### Platform-specific
*
* - **macOS:** Unsupported.
*/
website?: string;
/**
* The website label.
*
* #### Platform-specific
*
* - **macOS:** Unsupported.
*/
websiteLabel?: string;
/**
* The credits.
*
* #### Platform-specific
*
* - **Windows / Linux:** Unsupported.
*/
credits?: string;
/**
* The application icon.
*
* #### Platform-specific
*
* - **Windows:** Unsupported.
*/
icon?: string | Uint8Array | ArrayBuffer | number[] | Image;
}
/** Options for creating a new predefined menu item. */
export interface PredefinedMenuItemOptions {
/** The text of the new predefined menu item. */
text?: string;
/** The predefined item type */
item: 'Separator' | 'Copy' | 'Cut' | 'Paste' | 'SelectAll' | 'Undo' | 'Redo' | 'Minimize' | 'Maximize' | 'Fullscreen' | 'Hide' | 'HideOthers' | 'ShowAll' | 'CloseWindow' | 'Quit' | 'Services' | {
About: AboutMetadata | null;
};
}
/** A predefined (native) menu item which has a predefined behavior by the OS or by tauri. */
export declare class PredefinedMenuItem extends MenuItemBase {
/** @ignore */
protected constructor(rid: number, id: string);
/** Create a new predefined menu item. */
static new(opts?: PredefinedMenuItemOptions): Promise<PredefinedMenuItem>;
/** Returns the text of this predefined menu item. */
text(): Promise<string>;
/** Sets the text for this predefined menu item. */
setText(text: string): Promise<void>;
}

View File

@ -0,0 +1,31 @@
import { MenuItemBase, newMenu } from './base.js';
import { invoke } from '../core.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** A predefined (native) menu item which has a predefined behavior by the OS or by tauri. */
class PredefinedMenuItem extends MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Predefined');
}
/** Create a new predefined menu item. */
static async new(opts) {
return newMenu('Predefined', opts).then(([rid, id]) => new PredefinedMenuItem(rid, id));
}
/** Returns the text of this predefined menu item. */
async text() {
return invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this predefined menu item. */
async setText(text) {
return invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
}
export { PredefinedMenuItem };

203
node_modules/@tauri-apps/api/menu/submenu.cjs generated vendored Normal file
View File

@ -0,0 +1,203 @@
'use strict';
var menuItem = require('./menuItem.cjs');
var checkMenuItem = require('./checkMenuItem.cjs');
var iconMenuItem = require('./iconMenuItem.cjs');
var predefinedMenuItem = require('./predefinedMenuItem.cjs');
var core = require('../core.cjs');
var base = require('./base.cjs');
var dpi = require('../dpi.cjs');
var image = require('../image.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** @ignore */
function itemFromKind([rid, id, kind]) {
/* eslint-disable @typescript-eslint/no-unsafe-return */
switch (kind) {
case 'Submenu':
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new Submenu(rid, id);
case 'Predefined':
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new predefinedMenuItem.PredefinedMenuItem(rid, id);
case 'Check':
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new checkMenuItem.CheckMenuItem(rid, id);
case 'Icon':
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new iconMenuItem.IconMenuItem(rid, id);
case 'MenuItem':
default:
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new menuItem.MenuItem(rid, id);
}
/* eslint-enable @typescript-eslint/no-unsafe-return */
}
/** A type that is a submenu inside a {@linkcode Menu} or {@linkcode Submenu}. */
class Submenu extends base.MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Submenu');
}
/** Create a new submenu. */
static async new(opts) {
return base.newMenu('Submenu', opts).then(([rid, id]) => new Submenu(rid, id));
}
/** Returns the text of this submenu. */
async text() {
return core.invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this submenu. */
async setText(text) {
return core.invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
/** Returns whether this submenu is enabled or not. */
async isEnabled() {
return core.invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind });
}
/** Sets whether this submenu is enabled or not. */
async setEnabled(enabled) {
return core.invoke('plugin:menu|set_enabled', {
rid: this.rid,
kind: this.kind,
enabled
});
}
/**
* Add a menu item to the end of this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async append(items) {
return core.invoke('plugin:menu|append', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i)
});
}
/**
* Add a menu item to the beginning of this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async prepend(items) {
return core.invoke('plugin:menu|prepend', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i)
});
}
/**
* Add a menu item to the specified position in this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async insert(items, position) {
return core.invoke('plugin:menu|insert', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i),
position
});
}
/** Remove a menu item from this submenu. */
async remove(item) {
return core.invoke('plugin:menu|remove', {
rid: this.rid,
kind: this.kind,
item: [item.rid, item.kind]
});
}
/** Remove a menu item from this submenu at the specified position. */
async removeAt(position) {
return core.invoke('plugin:menu|remove_at', {
rid: this.rid,
kind: this.kind,
position
}).then(itemFromKind);
}
/** Returns a list of menu items that has been added to this submenu. */
async items() {
return core.invoke('plugin:menu|items', {
rid: this.rid,
kind: this.kind
}).then((i) => i.map(itemFromKind));
}
/** Retrieves the menu item matching the given identifier. */
async get(id) {
return core.invoke('plugin:menu|get', {
rid: this.rid,
kind: this.kind,
id
}).then((r) => (r ? itemFromKind(r) : null));
}
/**
* Popup this submenu as a context menu on the specified window.
*
* If the position, is provided, it is relative to the window's top-left corner.
*/
async popup(at, window) {
var _a;
return core.invoke('plugin:menu|popup', {
rid: this.rid,
kind: this.kind,
window: (_a = window === null || window === void 0 ? void 0 : window.label) !== null && _a !== void 0 ? _a : null,
at: at instanceof dpi.Position ? at : at ? new dpi.Position(at) : null
});
}
/**
* Set this submenu as the Window menu for the application on macOS.
*
* This will cause macOS to automatically add window-switching items and
* certain other items to the menu.
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
async setAsWindowsMenuForNSApp() {
return core.invoke('plugin:menu|set_as_windows_menu_for_nsapp', {
rid: this.rid
});
}
/**
* Set this submenu as the Help menu for the application on macOS.
*
* This will cause macOS to automatically add a search box to the menu.
*
* If no menu is set as the Help menu, macOS will automatically use any menu
* which has a title matching the localized word "Help".
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
async setAsHelpMenuForNSApp() {
return core.invoke('plugin:menu|set_as_help_menu_for_nsapp', {
rid: this.rid
});
}
/** Sets an icon for this submenu */
async setIcon(icon) {
return core.invoke('plugin:menu|set_icon', {
rid: this.rid,
kind: this.kind,
icon: image.transformImage(icon)
});
}
}
exports.Submenu = Submenu;
exports.itemFromKind = itemFromKind;

97
node_modules/@tauri-apps/api/menu/submenu.d.ts generated vendored Normal file
View File

@ -0,0 +1,97 @@
import { IconMenuItemOptions, PredefinedMenuItemOptions, CheckMenuItemOptions } from '../menu';
import { MenuItem, type MenuItemOptions } from './menuItem';
import { CheckMenuItem } from './checkMenuItem';
import { IconMenuItem } from './iconMenuItem';
import { PredefinedMenuItem } from './predefinedMenuItem';
import { type LogicalPosition, PhysicalPosition, type Window } from '../window';
import { type ItemKind, MenuItemBase } from './base';
import { type MenuOptions } from './menu';
import { MenuIcon } from '../image';
/** @ignore */
export declare function itemFromKind([rid, id, kind]: [number, string, ItemKind]): Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem;
export type SubmenuOptions = (Omit<MenuItemOptions, 'accelerator' | 'action'> & MenuOptions) & {
/**
* Icon to be used for the submenu.
* Note: you may need the `image-ico` or `image-png` Cargo features to use this API.
*/
icon?: MenuIcon;
};
/** A type that is a submenu inside a {@linkcode Menu} or {@linkcode Submenu}. */
export declare class Submenu extends MenuItemBase {
/** @ignore */
protected constructor(rid: number, id: string);
/** Create a new submenu. */
static new(opts: SubmenuOptions): Promise<Submenu>;
/** Returns the text of this submenu. */
text(): Promise<string>;
/** Sets the text for this submenu. */
setText(text: string): Promise<void>;
/** Returns whether this submenu is enabled or not. */
isEnabled(): Promise<boolean>;
/** Sets whether this submenu is enabled or not. */
setEnabled(enabled: boolean): Promise<void>;
/**
* Add a menu item to the end of this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
append<T extends Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | MenuItemOptions | SubmenuOptions | IconMenuItemOptions | PredefinedMenuItemOptions | CheckMenuItemOptions>(items: T | T[]): Promise<void>;
/**
* Add a menu item to the beginning of this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
prepend<T extends Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | MenuItemOptions | SubmenuOptions | IconMenuItemOptions | PredefinedMenuItemOptions | CheckMenuItemOptions>(items: T | T[]): Promise<void>;
/**
* Add a menu item to the specified position in this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
insert<T extends Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | MenuItemOptions | SubmenuOptions | IconMenuItemOptions | PredefinedMenuItemOptions | CheckMenuItemOptions>(items: T | T[], position: number): Promise<void>;
/** Remove a menu item from this submenu. */
remove(item: Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem): Promise<void>;
/** Remove a menu item from this submenu at the specified position. */
removeAt(position: number): Promise<Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | null>;
/** Returns a list of menu items that has been added to this submenu. */
items(): Promise<Array<Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem>>;
/** Retrieves the menu item matching the given identifier. */
get(id: string): Promise<Submenu | MenuItem | PredefinedMenuItem | CheckMenuItem | IconMenuItem | null>;
/**
* Popup this submenu as a context menu on the specified window.
*
* If the position, is provided, it is relative to the window's top-left corner.
*/
popup(at?: PhysicalPosition | LogicalPosition, window?: Window): Promise<void>;
/**
* Set this submenu as the Window menu for the application on macOS.
*
* This will cause macOS to automatically add window-switching items and
* certain other items to the menu.
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
setAsWindowsMenuForNSApp(): Promise<void>;
/**
* Set this submenu as the Help menu for the application on macOS.
*
* This will cause macOS to automatically add a search box to the menu.
*
* If no menu is set as the Help menu, macOS will automatically use any menu
* which has a title matching the localized word "Help".
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
setAsHelpMenuForNSApp(): Promise<void>;
/** Sets an icon for this submenu */
setIcon(icon: MenuIcon | null): Promise<void>;
}

200
node_modules/@tauri-apps/api/menu/submenu.js generated vendored Normal file
View File

@ -0,0 +1,200 @@
import { MenuItem } from './menuItem.js';
import { CheckMenuItem } from './checkMenuItem.js';
import { IconMenuItem } from './iconMenuItem.js';
import { PredefinedMenuItem } from './predefinedMenuItem.js';
import { invoke } from '../core.js';
import { MenuItemBase, newMenu } from './base.js';
import { Position } from '../dpi.js';
import { transformImage } from '../image.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/** @ignore */
function itemFromKind([rid, id, kind]) {
/* eslint-disable @typescript-eslint/no-unsafe-return */
switch (kind) {
case 'Submenu':
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new Submenu(rid, id);
case 'Predefined':
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new PredefinedMenuItem(rid, id);
case 'Check':
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new CheckMenuItem(rid, id);
case 'Icon':
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new IconMenuItem(rid, id);
case 'MenuItem':
default:
// @ts-expect-error constructor is protected for external usage only, safe for us to use
return new MenuItem(rid, id);
}
/* eslint-enable @typescript-eslint/no-unsafe-return */
}
/** A type that is a submenu inside a {@linkcode Menu} or {@linkcode Submenu}. */
class Submenu extends MenuItemBase {
/** @ignore */
constructor(rid, id) {
super(rid, id, 'Submenu');
}
/** Create a new submenu. */
static async new(opts) {
return newMenu('Submenu', opts).then(([rid, id]) => new Submenu(rid, id));
}
/** Returns the text of this submenu. */
async text() {
return invoke('plugin:menu|text', { rid: this.rid, kind: this.kind });
}
/** Sets the text for this submenu. */
async setText(text) {
return invoke('plugin:menu|set_text', {
rid: this.rid,
kind: this.kind,
text
});
}
/** Returns whether this submenu is enabled or not. */
async isEnabled() {
return invoke('plugin:menu|is_enabled', { rid: this.rid, kind: this.kind });
}
/** Sets whether this submenu is enabled or not. */
async setEnabled(enabled) {
return invoke('plugin:menu|set_enabled', {
rid: this.rid,
kind: this.kind,
enabled
});
}
/**
* Add a menu item to the end of this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async append(items) {
return invoke('plugin:menu|append', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i)
});
}
/**
* Add a menu item to the beginning of this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async prepend(items) {
return invoke('plugin:menu|prepend', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i)
});
}
/**
* Add a menu item to the specified position in this submenu.
*
* #### Platform-specific:
*
* - **macOS:** Only {@linkcode Submenu}s can be added to a {@linkcode Menu}.
*/
async insert(items, position) {
return invoke('plugin:menu|insert', {
rid: this.rid,
kind: this.kind,
items: (Array.isArray(items) ? items : [items]).map((i) => 'rid' in i ? [i.rid, i.kind] : i),
position
});
}
/** Remove a menu item from this submenu. */
async remove(item) {
return invoke('plugin:menu|remove', {
rid: this.rid,
kind: this.kind,
item: [item.rid, item.kind]
});
}
/** Remove a menu item from this submenu at the specified position. */
async removeAt(position) {
return invoke('plugin:menu|remove_at', {
rid: this.rid,
kind: this.kind,
position
}).then(itemFromKind);
}
/** Returns a list of menu items that has been added to this submenu. */
async items() {
return invoke('plugin:menu|items', {
rid: this.rid,
kind: this.kind
}).then((i) => i.map(itemFromKind));
}
/** Retrieves the menu item matching the given identifier. */
async get(id) {
return invoke('plugin:menu|get', {
rid: this.rid,
kind: this.kind,
id
}).then((r) => (r ? itemFromKind(r) : null));
}
/**
* Popup this submenu as a context menu on the specified window.
*
* If the position, is provided, it is relative to the window's top-left corner.
*/
async popup(at, window) {
var _a;
return invoke('plugin:menu|popup', {
rid: this.rid,
kind: this.kind,
window: (_a = window === null || window === void 0 ? void 0 : window.label) !== null && _a !== void 0 ? _a : null,
at: at instanceof Position ? at : at ? new Position(at) : null
});
}
/**
* Set this submenu as the Window menu for the application on macOS.
*
* This will cause macOS to automatically add window-switching items and
* certain other items to the menu.
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
async setAsWindowsMenuForNSApp() {
return invoke('plugin:menu|set_as_windows_menu_for_nsapp', {
rid: this.rid
});
}
/**
* Set this submenu as the Help menu for the application on macOS.
*
* This will cause macOS to automatically add a search box to the menu.
*
* If no menu is set as the Help menu, macOS will automatically use any menu
* which has a title matching the localized word "Help".
*
* #### Platform-specific:
*
* - **Windows / Linux**: Unsupported.
*/
async setAsHelpMenuForNSApp() {
return invoke('plugin:menu|set_as_help_menu_for_nsapp', {
rid: this.rid
});
}
/** Sets an icon for this submenu */
async setIcon(icon) {
return invoke('plugin:menu|set_icon', {
rid: this.rid,
kind: this.kind,
icon: transformImage(icon)
});
}
}
export { Submenu, itemFromKind };

297
node_modules/@tauri-apps/api/mocks.cjs generated vendored Normal file
View File

@ -0,0 +1,297 @@
'use strict';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
function mockInternals() {
var _a, _b;
window.__TAURI_INTERNALS__ = (_a = window.__TAURI_INTERNALS__) !== null && _a !== void 0 ? _a : {};
window.__TAURI_EVENT_PLUGIN_INTERNALS__ =
(_b = window.__TAURI_EVENT_PLUGIN_INTERNALS__) !== null && _b !== void 0 ? _b : {};
}
/**
* Intercepts all IPC requests with the given mock handler.
*
* This function can be used when testing tauri frontend applications or when running the frontend in a Node.js context during static site generation.
*
* # Examples
*
* Testing setup using Vitest:
* ```ts
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { invoke } from "@tauri-apps/api/core"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked command", () => {
* mockIPC((cmd, payload) => {
* switch (cmd) {
* case "add":
* return (payload.a as number) + (payload.b as number);
* default:
* break;
* }
* });
*
* expect(invoke('add', { a: 12, b: 15 })).resolves.toBe(27);
* })
* ```
*
* The callback function can also return a Promise:
* ```js
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { invoke } from "@tauri-apps/api/core"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked command", () => {
* mockIPC((cmd, payload) => {
* if(cmd === "get_data") {
* return fetch("https://example.com/data.json")
* .then((response) => response.json())
* }
* });
*
* expect(invoke('get_data')).resolves.toBe({ foo: 'bar' });
* })
* ```
*
* `listen` can also be mocked with direct calls to the `emit` function. This functionality is opt-in via the `shouldMockEvents` option:
* ```js
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { emit, listen } from "@tauri-apps/api/event"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked event", () => {
* mockIPC(() => {}, { shouldMockEvents: true }); // enable event mocking
*
* const eventHandler = vi.fn();
* listen('test-event', eventHandler); // typically in component setup or similar
*
* emit('test-event', { foo: 'bar' });
* expect(eventHandler).toHaveBeenCalledWith({
* event: 'test-event',
* payload: { foo: 'bar' }
* });
* })
* ```
* `emitTo` is currently **not** supported by this mock implementation.
*
* @since 1.0.0
*/
function mockIPC(cb, options) {
mockInternals();
function isEventPluginInvoke(cmd) {
return cmd.startsWith('plugin:event|');
}
function handleEventPlugin(cmd, args) {
switch (cmd) {
case 'plugin:event|listen':
return handleListen(args);
case 'plugin:event|emit':
return handleEmit(args);
case 'plugin:event|unlisten':
return handleRemoveListener(args);
}
}
const listeners = new Map();
function handleListen(args) {
if (!listeners.has(args.event)) {
listeners.set(args.event, []);
}
listeners.get(args.event).push(args.handler);
return args.handler;
}
function handleEmit(args) {
const eventListeners = listeners.get(args.event) || [];
for (const handler of eventListeners) {
runCallback(handler, args);
}
return null;
}
function handleRemoveListener(args) {
const eventListeners = listeners.get(args.event);
if (eventListeners) {
const index = eventListeners.indexOf(args.id);
if (index !== -1) {
eventListeners.splice(index, 1);
}
}
}
// eslint-disable-next-line @typescript-eslint/require-await
async function invoke(cmd, args, _options) {
if ((options === null || options === void 0 ? void 0 : options.shouldMockEvents) && isEventPluginInvoke(cmd)) {
return handleEventPlugin(cmd, args);
}
return cb(cmd, args);
}
const callbacks = new Map();
function registerCallback(callback, once = false) {
const identifier = window.crypto.getRandomValues(new Uint32Array(1))[0];
callbacks.set(identifier, (data) => {
if (once) {
unregisterCallback(identifier);
}
return callback && callback(data);
});
return identifier;
}
function unregisterCallback(id) {
callbacks.delete(id);
}
function runCallback(id, data) {
const callback = callbacks.get(id);
if (callback) {
callback(data);
}
else {
// eslint-disable-next-line no-console
console.warn(`[TAURI] Couldn't find callback id ${id}. This might happen when the app is reloaded while Rust is running an asynchronous operation.`);
}
}
function unregisterListener(event, id) {
unregisterCallback(id);
}
window.__TAURI_INTERNALS__.invoke = invoke;
window.__TAURI_INTERNALS__.transformCallback = registerCallback;
window.__TAURI_INTERNALS__.unregisterCallback = unregisterCallback;
window.__TAURI_INTERNALS__.runCallback = runCallback;
window.__TAURI_INTERNALS__.callbacks = callbacks;
window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener =
unregisterListener;
}
/**
* Mocks one or many window labels.
* In non-tauri context it is required to call this function *before* using the `@tauri-apps/api/window` module.
*
* This function only mocks the *presence* of windows,
* window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function.
*
* # Examples
*
* ```js
* import { mockWindows } from "@tauri-apps/api/mocks";
* import { getCurrentWindow } from "@tauri-apps/api/window";
*
* mockWindows("main", "second", "third");
*
* const win = getCurrentWindow();
*
* win.label // "main"
* ```
*
* ```js
* import { mockWindows } from "@tauri-apps/api/mocks";
*
* mockWindows("main", "second", "third");
*
* mockIPC((cmd, args) => {
* if (cmd === "plugin:event|emit") {
* console.log('emit event', args?.event, args?.payload);
* }
* });
*
* const { emit } = await import("@tauri-apps/api/event");
* await emit('loaded'); // this will cause the mocked IPC handler to log to the console.
* ```
*
* @param current Label of window this JavaScript context is running in.
*
* @since 1.0.0
*/
function mockWindows(current, ..._additionalWindows) {
mockInternals();
window.__TAURI_INTERNALS__.metadata = {
currentWindow: { label: current },
currentWebview: { windowLabel: current, label: current }
};
}
/**
* Mock `convertFileSrc` function
*
*
* @example
* ```js
* import { mockConvertFileSrc } from "@tauri-apps/api/mocks";
* import { convertFileSrc } from "@tauri-apps/api/core";
*
* mockConvertFileSrc("windows")
*
* const url = convertFileSrc("C:\\Users\\user\\file.txt")
* ```
*
* @param osName The operating system to mock, can be one of linux, macos, or windows
*
* @since 1.6.0
*/
function mockConvertFileSrc(osName) {
mockInternals();
window.__TAURI_INTERNALS__.convertFileSrc = function (filePath, protocol = 'asset') {
const path = encodeURIComponent(filePath);
return osName === 'windows'
? `http://${protocol}.localhost/${path}`
: `${protocol}://localhost/${path}`;
};
}
/**
* Clears mocked functions/data injected by the other functions in this module.
* When using a test runner that doesn't provide a fresh window object for each test, calling this function will reset tauri specific properties.
*
* # Example
*
* ```js
* import { mockWindows, clearMocks } from "@tauri-apps/api/mocks"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked windows", () => {
* mockWindows("main", "second", "third");
*
* expect(window.__TAURI_INTERNALS__).toHaveProperty("metadata")
* })
*
* test("no mocked windows", () => {
* expect(window.__TAURI_INTERNALS__).not.toHaveProperty("metadata")
* })
* ```
*
* @since 1.0.0
*/
function clearMocks() {
if (typeof window.__TAURI_INTERNALS__ !== 'object') {
return;
}
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.invoke;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.transformCallback;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.unregisterCallback;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.runCallback;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.callbacks;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.convertFileSrc;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.metadata;
if (typeof window.__TAURI_EVENT_PLUGIN_INTERNALS__ !== 'object') {
return;
}
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener;
}
exports.clearMocks = clearMocks;
exports.mockConvertFileSrc = mockConvertFileSrc;
exports.mockIPC = mockIPC;
exports.mockWindows = mockWindows;

177
node_modules/@tauri-apps/api/mocks.d.ts generated vendored Normal file
View File

@ -0,0 +1,177 @@
import type { InvokeArgs } from './core';
/**
* Options for `mockIPC`.
*
* # Options
* `shouldMockEvents`: If true, the `listen` and `emit` functions will be mocked, allowing you to test event handling without a real backend.
* **This will consume any events emitted with the `plugin:event` prefix.**
*
* @since 2.7.0
*/
export interface MockIPCOptions {
shouldMockEvents?: boolean;
}
/**
* Intercepts all IPC requests with the given mock handler.
*
* This function can be used when testing tauri frontend applications or when running the frontend in a Node.js context during static site generation.
*
* # Examples
*
* Testing setup using Vitest:
* ```ts
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { invoke } from "@tauri-apps/api/core"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked command", () => {
* mockIPC((cmd, payload) => {
* switch (cmd) {
* case "add":
* return (payload.a as number) + (payload.b as number);
* default:
* break;
* }
* });
*
* expect(invoke('add', { a: 12, b: 15 })).resolves.toBe(27);
* })
* ```
*
* The callback function can also return a Promise:
* ```js
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { invoke } from "@tauri-apps/api/core"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked command", () => {
* mockIPC((cmd, payload) => {
* if(cmd === "get_data") {
* return fetch("https://example.com/data.json")
* .then((response) => response.json())
* }
* });
*
* expect(invoke('get_data')).resolves.toBe({ foo: 'bar' });
* })
* ```
*
* `listen` can also be mocked with direct calls to the `emit` function. This functionality is opt-in via the `shouldMockEvents` option:
* ```js
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { emit, listen } from "@tauri-apps/api/event"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked event", () => {
* mockIPC(() => {}, { shouldMockEvents: true }); // enable event mocking
*
* const eventHandler = vi.fn();
* listen('test-event', eventHandler); // typically in component setup or similar
*
* emit('test-event', { foo: 'bar' });
* expect(eventHandler).toHaveBeenCalledWith({
* event: 'test-event',
* payload: { foo: 'bar' }
* });
* })
* ```
* `emitTo` is currently **not** supported by this mock implementation.
*
* @since 1.0.0
*/
export declare function mockIPC(cb: (cmd: string, payload?: InvokeArgs) => unknown, options?: MockIPCOptions): void;
/**
* Mocks one or many window labels.
* In non-tauri context it is required to call this function *before* using the `@tauri-apps/api/window` module.
*
* This function only mocks the *presence* of windows,
* window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function.
*
* # Examples
*
* ```js
* import { mockWindows } from "@tauri-apps/api/mocks";
* import { getCurrentWindow } from "@tauri-apps/api/window";
*
* mockWindows("main", "second", "third");
*
* const win = getCurrentWindow();
*
* win.label // "main"
* ```
*
* ```js
* import { mockWindows } from "@tauri-apps/api/mocks";
*
* mockWindows("main", "second", "third");
*
* mockIPC((cmd, args) => {
* if (cmd === "plugin:event|emit") {
* console.log('emit event', args?.event, args?.payload);
* }
* });
*
* const { emit } = await import("@tauri-apps/api/event");
* await emit('loaded'); // this will cause the mocked IPC handler to log to the console.
* ```
*
* @param current Label of window this JavaScript context is running in.
*
* @since 1.0.0
*/
export declare function mockWindows(current: string, ..._additionalWindows: string[]): void;
/**
* Mock `convertFileSrc` function
*
*
* @example
* ```js
* import { mockConvertFileSrc } from "@tauri-apps/api/mocks";
* import { convertFileSrc } from "@tauri-apps/api/core";
*
* mockConvertFileSrc("windows")
*
* const url = convertFileSrc("C:\\Users\\user\\file.txt")
* ```
*
* @param osName The operating system to mock, can be one of linux, macos, or windows
*
* @since 1.6.0
*/
export declare function mockConvertFileSrc(osName: string): void;
/**
* Clears mocked functions/data injected by the other functions in this module.
* When using a test runner that doesn't provide a fresh window object for each test, calling this function will reset tauri specific properties.
*
* # Example
*
* ```js
* import { mockWindows, clearMocks } from "@tauri-apps/api/mocks"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked windows", () => {
* mockWindows("main", "second", "third");
*
* expect(window.__TAURI_INTERNALS__).toHaveProperty("metadata")
* })
*
* test("no mocked windows", () => {
* expect(window.__TAURI_INTERNALS__).not.toHaveProperty("metadata")
* })
* ```
*
* @since 1.0.0
*/
export declare function clearMocks(): void;

292
node_modules/@tauri-apps/api/mocks.js generated vendored Normal file
View File

@ -0,0 +1,292 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
function mockInternals() {
var _a, _b;
window.__TAURI_INTERNALS__ = (_a = window.__TAURI_INTERNALS__) !== null && _a !== void 0 ? _a : {};
window.__TAURI_EVENT_PLUGIN_INTERNALS__ =
(_b = window.__TAURI_EVENT_PLUGIN_INTERNALS__) !== null && _b !== void 0 ? _b : {};
}
/**
* Intercepts all IPC requests with the given mock handler.
*
* This function can be used when testing tauri frontend applications or when running the frontend in a Node.js context during static site generation.
*
* # Examples
*
* Testing setup using Vitest:
* ```ts
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { invoke } from "@tauri-apps/api/core"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked command", () => {
* mockIPC((cmd, payload) => {
* switch (cmd) {
* case "add":
* return (payload.a as number) + (payload.b as number);
* default:
* break;
* }
* });
*
* expect(invoke('add', { a: 12, b: 15 })).resolves.toBe(27);
* })
* ```
*
* The callback function can also return a Promise:
* ```js
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { invoke } from "@tauri-apps/api/core"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked command", () => {
* mockIPC((cmd, payload) => {
* if(cmd === "get_data") {
* return fetch("https://example.com/data.json")
* .then((response) => response.json())
* }
* });
*
* expect(invoke('get_data')).resolves.toBe({ foo: 'bar' });
* })
* ```
*
* `listen` can also be mocked with direct calls to the `emit` function. This functionality is opt-in via the `shouldMockEvents` option:
* ```js
* import { mockIPC, clearMocks } from "@tauri-apps/api/mocks"
* import { emit, listen } from "@tauri-apps/api/event"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked event", () => {
* mockIPC(() => {}, { shouldMockEvents: true }); // enable event mocking
*
* const eventHandler = vi.fn();
* listen('test-event', eventHandler); // typically in component setup or similar
*
* emit('test-event', { foo: 'bar' });
* expect(eventHandler).toHaveBeenCalledWith({
* event: 'test-event',
* payload: { foo: 'bar' }
* });
* })
* ```
* `emitTo` is currently **not** supported by this mock implementation.
*
* @since 1.0.0
*/
function mockIPC(cb, options) {
mockInternals();
function isEventPluginInvoke(cmd) {
return cmd.startsWith('plugin:event|');
}
function handleEventPlugin(cmd, args) {
switch (cmd) {
case 'plugin:event|listen':
return handleListen(args);
case 'plugin:event|emit':
return handleEmit(args);
case 'plugin:event|unlisten':
return handleRemoveListener(args);
}
}
const listeners = new Map();
function handleListen(args) {
if (!listeners.has(args.event)) {
listeners.set(args.event, []);
}
listeners.get(args.event).push(args.handler);
return args.handler;
}
function handleEmit(args) {
const eventListeners = listeners.get(args.event) || [];
for (const handler of eventListeners) {
runCallback(handler, args);
}
return null;
}
function handleRemoveListener(args) {
const eventListeners = listeners.get(args.event);
if (eventListeners) {
const index = eventListeners.indexOf(args.id);
if (index !== -1) {
eventListeners.splice(index, 1);
}
}
}
// eslint-disable-next-line @typescript-eslint/require-await
async function invoke(cmd, args, _options) {
if ((options === null || options === void 0 ? void 0 : options.shouldMockEvents) && isEventPluginInvoke(cmd)) {
return handleEventPlugin(cmd, args);
}
return cb(cmd, args);
}
const callbacks = new Map();
function registerCallback(callback, once = false) {
const identifier = window.crypto.getRandomValues(new Uint32Array(1))[0];
callbacks.set(identifier, (data) => {
if (once) {
unregisterCallback(identifier);
}
return callback && callback(data);
});
return identifier;
}
function unregisterCallback(id) {
callbacks.delete(id);
}
function runCallback(id, data) {
const callback = callbacks.get(id);
if (callback) {
callback(data);
}
else {
// eslint-disable-next-line no-console
console.warn(`[TAURI] Couldn't find callback id ${id}. This might happen when the app is reloaded while Rust is running an asynchronous operation.`);
}
}
function unregisterListener(event, id) {
unregisterCallback(id);
}
window.__TAURI_INTERNALS__.invoke = invoke;
window.__TAURI_INTERNALS__.transformCallback = registerCallback;
window.__TAURI_INTERNALS__.unregisterCallback = unregisterCallback;
window.__TAURI_INTERNALS__.runCallback = runCallback;
window.__TAURI_INTERNALS__.callbacks = callbacks;
window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener =
unregisterListener;
}
/**
* Mocks one or many window labels.
* In non-tauri context it is required to call this function *before* using the `@tauri-apps/api/window` module.
*
* This function only mocks the *presence* of windows,
* window properties (e.g. width and height) can be mocked like regular IPC calls using the `mockIPC` function.
*
* # Examples
*
* ```js
* import { mockWindows } from "@tauri-apps/api/mocks";
* import { getCurrentWindow } from "@tauri-apps/api/window";
*
* mockWindows("main", "second", "third");
*
* const win = getCurrentWindow();
*
* win.label // "main"
* ```
*
* ```js
* import { mockWindows } from "@tauri-apps/api/mocks";
*
* mockWindows("main", "second", "third");
*
* mockIPC((cmd, args) => {
* if (cmd === "plugin:event|emit") {
* console.log('emit event', args?.event, args?.payload);
* }
* });
*
* const { emit } = await import("@tauri-apps/api/event");
* await emit('loaded'); // this will cause the mocked IPC handler to log to the console.
* ```
*
* @param current Label of window this JavaScript context is running in.
*
* @since 1.0.0
*/
function mockWindows(current, ..._additionalWindows) {
mockInternals();
window.__TAURI_INTERNALS__.metadata = {
currentWindow: { label: current },
currentWebview: { windowLabel: current, label: current }
};
}
/**
* Mock `convertFileSrc` function
*
*
* @example
* ```js
* import { mockConvertFileSrc } from "@tauri-apps/api/mocks";
* import { convertFileSrc } from "@tauri-apps/api/core";
*
* mockConvertFileSrc("windows")
*
* const url = convertFileSrc("C:\\Users\\user\\file.txt")
* ```
*
* @param osName The operating system to mock, can be one of linux, macos, or windows
*
* @since 1.6.0
*/
function mockConvertFileSrc(osName) {
mockInternals();
window.__TAURI_INTERNALS__.convertFileSrc = function (filePath, protocol = 'asset') {
const path = encodeURIComponent(filePath);
return osName === 'windows'
? `http://${protocol}.localhost/${path}`
: `${protocol}://localhost/${path}`;
};
}
/**
* Clears mocked functions/data injected by the other functions in this module.
* When using a test runner that doesn't provide a fresh window object for each test, calling this function will reset tauri specific properties.
*
* # Example
*
* ```js
* import { mockWindows, clearMocks } from "@tauri-apps/api/mocks"
*
* afterEach(() => {
* clearMocks()
* })
*
* test("mocked windows", () => {
* mockWindows("main", "second", "third");
*
* expect(window.__TAURI_INTERNALS__).toHaveProperty("metadata")
* })
*
* test("no mocked windows", () => {
* expect(window.__TAURI_INTERNALS__).not.toHaveProperty("metadata")
* })
* ```
*
* @since 1.0.0
*/
function clearMocks() {
if (typeof window.__TAURI_INTERNALS__ !== 'object') {
return;
}
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.invoke;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.transformCallback;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.unregisterCallback;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.runCallback;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.callbacks;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.convertFileSrc;
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_INTERNALS__.metadata;
if (typeof window.__TAURI_EVENT_PLUGIN_INTERNALS__ !== 'object') {
return;
}
// @ts-expect-error "The operand of a 'delete' operator must be optional." does not matter in this case
delete window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener;
}
export { clearMocks, mockConvertFileSrc, mockIPC, mockWindows };

63
node_modules/@tauri-apps/api/package.json generated vendored Normal file
View File

@ -0,0 +1,63 @@
{
"name": "@tauri-apps/api",
"version": "2.10.1",
"description": "Tauri API definitions",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tauri"
},
"repository": {
"type": "git",
"url": "git+https://github.com/tauri-apps/tauri.git"
},
"contributors": [
"Tauri Programme within The Commons Conservancy"
],
"license": "Apache-2.0 OR MIT",
"bugs": {
"url": "https://github.com/tauri-apps/tauri/issues"
},
"homepage": "https://github.com/tauri-apps/tauri#readme",
"type": "module",
"main": "./index.cjs",
"module": "./index.js",
"types": "./index.d.ts",
"exports": {
".": {
"import": "./index.js",
"require": "./index.cjs",
"types": "./index.d.ts"
},
"./*": {
"import": "./*.js",
"require": "./*.cjs",
"types": "./*.d.ts"
},
"./package.json": "./package.json"
},
"devDependencies": {
"@eslint/js": "^9.29.0",
"@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-typescript": "12.3.0",
"@types/eslint": "^9.6.1",
"@types/node": "^24.0.0",
"eslint": "^9.29.0",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-security": "3.0.1",
"fast-glob": "3.3.3",
"globals": "^17.0.0",
"rollup": "4.57.0",
"tslib": "^2.8.1",
"typescript": "^5.8.3",
"typescript-eslint": "^8.34.1"
},
"scripts": {
"build": "rollup -c --configPlugin typescript",
"build:debug": "rollup -c --configPlugin typescript",
"npm-pack": "pnpm build && cd ./dist && npm pack",
"npm-publish": "pnpm build && cd ./dist && pnpm publish --access public --loglevel silly --no-git-checks",
"ts:check": "tsc --noEmit",
"eslint:check": "eslint src/**/*.ts",
"eslint:fix": "eslint src/**/*.ts --fix"
}
}

753
node_modules/@tauri-apps/api/path.cjs generated vendored Normal file
View File

@ -0,0 +1,753 @@
'use strict';
var core = require('./core.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* The path module provides utilities for working with file and directory paths.
*
* This package is also accessible with `window.__TAURI__.path` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
*
* It is recommended to allowlist only the APIs you use for optimal bundle size and security.
* @module
*/
/**
* @since 2.0.0
*/
exports.BaseDirectory = void 0;
(function (BaseDirectory) {
/**
* @see {@link audioDir} for more information.
*/
BaseDirectory[BaseDirectory["Audio"] = 1] = "Audio";
/**
* @see {@link cacheDir} for more information.
*/
BaseDirectory[BaseDirectory["Cache"] = 2] = "Cache";
/**
* @see {@link configDir} for more information.
*/
BaseDirectory[BaseDirectory["Config"] = 3] = "Config";
/**
* @see {@link dataDir} for more information.
*/
BaseDirectory[BaseDirectory["Data"] = 4] = "Data";
/**
* @see {@link localDataDir} for more information.
*/
BaseDirectory[BaseDirectory["LocalData"] = 5] = "LocalData";
/**
* @see {@link documentDir} for more information.
*/
BaseDirectory[BaseDirectory["Document"] = 6] = "Document";
/**
* @see {@link downloadDir} for more information.
*/
BaseDirectory[BaseDirectory["Download"] = 7] = "Download";
/**
* @see {@link pictureDir} for more information.
*/
BaseDirectory[BaseDirectory["Picture"] = 8] = "Picture";
/**
* @see {@link publicDir} for more information.
*/
BaseDirectory[BaseDirectory["Public"] = 9] = "Public";
/**
* @see {@link videoDir} for more information.
*/
BaseDirectory[BaseDirectory["Video"] = 10] = "Video";
/**
* @see {@link resourceDir} for more information.
*/
BaseDirectory[BaseDirectory["Resource"] = 11] = "Resource";
/**
* @see {@link tempDir} for more information.
*/
BaseDirectory[BaseDirectory["Temp"] = 12] = "Temp";
/**
* @see {@link appConfigDir} for more information.
*/
BaseDirectory[BaseDirectory["AppConfig"] = 13] = "AppConfig";
/**
* @see {@link appDataDir} for more information.
*/
BaseDirectory[BaseDirectory["AppData"] = 14] = "AppData";
/**
* @see {@link appLocalDataDir} for more information.
*/
BaseDirectory[BaseDirectory["AppLocalData"] = 15] = "AppLocalData";
/**
* @see {@link appCacheDir} for more information.
*/
BaseDirectory[BaseDirectory["AppCache"] = 16] = "AppCache";
/**
* @see {@link appLogDir} for more information.
*/
BaseDirectory[BaseDirectory["AppLog"] = 17] = "AppLog";
/**
* @see {@link desktopDir} for more information.
*/
BaseDirectory[BaseDirectory["Desktop"] = 18] = "Desktop";
/**
* @see {@link executableDir} for more information.
*/
BaseDirectory[BaseDirectory["Executable"] = 19] = "Executable";
/**
* @see {@link fontDir} for more information.
*/
BaseDirectory[BaseDirectory["Font"] = 20] = "Font";
/**
* @see {@link homeDir} for more information.
*/
BaseDirectory[BaseDirectory["Home"] = 21] = "Home";
/**
* @see {@link runtimeDir} for more information.
*/
BaseDirectory[BaseDirectory["Runtime"] = 22] = "Runtime";
/**
* @see {@link templateDir} for more information.
*/
BaseDirectory[BaseDirectory["Template"] = 23] = "Template";
})(exports.BaseDirectory || (exports.BaseDirectory = {}));
/**
* Returns the path to the suggested directory for your app's config files.
* Resolves to `${configDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appConfigDir } from '@tauri-apps/api/path';
* const appConfigDirPath = await appConfigDir();
* ```
*
* @since 1.2.0
*/
async function appConfigDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.AppConfig
});
}
/**
* Returns the path to the suggested directory for your app's data files.
* Resolves to `${dataDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* ```
*
* @since 1.2.0
*/
async function appDataDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.AppData
});
}
/**
* Returns the path to the suggested directory for your app's local data files.
* Resolves to `${localDataDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appLocalDataDir } from '@tauri-apps/api/path';
* const appLocalDataDirPath = await appLocalDataDir();
* ```
*
* @since 1.2.0
*/
async function appLocalDataDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.AppLocalData
});
}
/**
* Returns the path to the suggested directory for your app's cache files.
* Resolves to `${cacheDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appCacheDir } from '@tauri-apps/api/path';
* const appCacheDirPath = await appCacheDir();
* ```
*
* @since 1.2.0
*/
async function appCacheDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.AppCache
});
}
/**
* Returns the path to the user's audio directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_MUSIC_DIR`.
* - **macOS:** Resolves to `$HOME/Music`.
* - **Windows:** Resolves to `{FOLDERID_Music}`.
* @example
* ```typescript
* import { audioDir } from '@tauri-apps/api/path';
* const audioDirPath = await audioDir();
* ```
*
* @since 1.0.0
*/
async function audioDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Audio
});
}
/**
* Returns the path to the user's cache directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_CACHE_HOME` or `$HOME/.cache`.
* - **macOS:** Resolves to `$HOME/Library/Caches`.
* - **Windows:** Resolves to `{FOLDERID_LocalAppData}`.
* @example
* ```typescript
* import { cacheDir } from '@tauri-apps/api/path';
* const cacheDirPath = await cacheDir();
* ```
*
* @since 1.0.0
*/
async function cacheDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Cache
});
}
/**
* Returns the path to the user's config directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_CONFIG_HOME` or `$HOME/.config`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
* @example
* ```typescript
* import { configDir } from '@tauri-apps/api/path';
* const configDirPath = await configDir();
* ```
*
* @since 1.0.0
*/
async function configDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Config
});
}
/**
* Returns the path to the user's data directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
* @example
* ```typescript
* import { dataDir } from '@tauri-apps/api/path';
* const dataDirPath = await dataDir();
* ```
*
* @since 1.0.0
*/
async function dataDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Data
});
}
/**
* Returns the path to the user's desktop directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DESKTOP_DIR`.
* - **macOS:** Resolves to `$HOME/Desktop`.
* - **Windows:** Resolves to `{FOLDERID_Desktop}`.
* @example
* ```typescript
* import { desktopDir } from '@tauri-apps/api/path';
* const desktopPath = await desktopDir();
* ```
*
* @since 1.0.0
*/
async function desktopDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Desktop
});
}
/**
* Returns the path to the user's document directory.
* @example
* ```typescript
* import { documentDir } from '@tauri-apps/api/path';
* const documentDirPath = await documentDir();
* ```
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DOCUMENTS_DIR`.
* - **macOS:** Resolves to `$HOME/Documents`.
* - **Windows:** Resolves to `{FOLDERID_Documents}`.
*
* @since 1.0.0
*/
async function documentDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Document
});
}
/**
* Returns the path to the user's download directory.
*
* #### Platform-specific
*
* - **Linux**: Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DOWNLOAD_DIR`.
* - **macOS**: Resolves to `$HOME/Downloads`.
* - **Windows**: Resolves to `{FOLDERID_Downloads}`.
* @example
* ```typescript
* import { downloadDir } from '@tauri-apps/api/path';
* const downloadDirPath = await downloadDir();
* ```
*
* @since 1.0.0
*/
async function downloadDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Download
});
}
/**
* Returns the path to the user's executable directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_BIN_HOME/../bin` or `$XDG_DATA_HOME/../bin` or `$HOME/.local/bin`.
* - **macOS:** Not supported.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { executableDir } from '@tauri-apps/api/path';
* const executableDirPath = await executableDir();
* ```
*
* @since 1.0.0
*/
async function executableDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Executable
});
}
/**
* Returns the path to the user's font directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME/fonts` or `$HOME/.local/share/fonts`.
* - **macOS:** Resolves to `$HOME/Library/Fonts`.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { fontDir } from '@tauri-apps/api/path';
* const fontDirPath = await fontDir();
* ```
*
* @since 1.0.0
*/
async function fontDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Font
});
}
/**
* Returns the path to the user's home directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$HOME`.
* - **macOS:** Resolves to `$HOME`.
* - **Windows:** Resolves to `{FOLDERID_Profile}`.
* @example
* ```typescript
* import { homeDir } from '@tauri-apps/api/path';
* const homeDirPath = await homeDir();
* ```
*
* @since 1.0.0
*/
async function homeDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Home
});
}
/**
* Returns the path to the user's local data directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_LocalAppData}`.
* @example
* ```typescript
* import { localDataDir } from '@tauri-apps/api/path';
* const localDataDirPath = await localDataDir();
* ```
*
* @since 1.0.0
*/
async function localDataDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.LocalData
});
}
/**
* Returns the path to the user's picture directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_PICTURES_DIR`.
* - **macOS:** Resolves to `$HOME/Pictures`.
* - **Windows:** Resolves to `{FOLDERID_Pictures}`.
* @example
* ```typescript
* import { pictureDir } from '@tauri-apps/api/path';
* const pictureDirPath = await pictureDir();
* ```
*
* @since 1.0.0
*/
async function pictureDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Picture
});
}
/**
* Returns the path to the user's public directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_PUBLICSHARE_DIR`.
* - **macOS:** Resolves to `$HOME/Public`.
* - **Windows:** Resolves to `{FOLDERID_Public}`.
* @example
* ```typescript
* import { publicDir } from '@tauri-apps/api/path';
* const publicDirPath = await publicDir();
* ```
*
* @since 1.0.0
*/
async function publicDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Public
});
}
/**
* Returns the path to the application's resource directory.
* To resolve a resource path, see {@linkcode resolveResource}.
*
* ## Platform-specific
*
* Although we provide the exact path where this function resolves to,
* this is not a contract and things might change in the future
*
* - **Windows:** Resolves to the directory that contains the main executable.
* - **Linux:** When running in an AppImage, the `APPDIR` variable will be set to
* the mounted location of the app, and the resource dir will be `${APPDIR}/usr/lib/${exe_name}`.
* If not running in an AppImage, the path is `/usr/lib/${exe_name}`.
* When running the app from `src-tauri/target/(debug|release)/`, the path is `${exe_dir}/../lib/${exe_name}`.
* - **macOS:** Resolves to `${exe_dir}/../Resources` (inside .app).
* - **iOS:** Resolves to `${exe_dir}/assets`.
* - **Android:** Currently the resources are stored in the APK as assets so it's not a normal file system path,
* we return a special URI prefix `asset://localhost/` here that can be used with the [file system plugin](https://tauri.app/plugin/file-system/),
*
* @example
* ```typescript
* import { resourceDir } from '@tauri-apps/api/path';
* const resourceDirPath = await resourceDir();
* ```
*
* @since 1.0.0
*/
async function resourceDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Resource
});
}
/**
* Resolve the path to a resource file.
* @example
* ```typescript
* import { resolveResource } from '@tauri-apps/api/path';
* const resourcePath = await resolveResource('script.sh');
* ```
*
* @param resourcePath The path to the resource.
* Must follow the same syntax as defined in `tauri.conf.json > bundle > resources`, i.e. keeping subfolders and parent dir components (`../`).
* @returns The full path to the resource.
*
* @since 1.0.0
*/
async function resolveResource(resourcePath) {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Resource,
path: resourcePath
});
}
/**
* Returns the path to the user's runtime directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_RUNTIME_DIR`.
* - **macOS:** Not supported.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { runtimeDir } from '@tauri-apps/api/path';
* const runtimeDirPath = await runtimeDir();
* ```
*
* @since 1.0.0
*/
async function runtimeDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Runtime
});
}
/**
* Returns the path to the user's template directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_TEMPLATES_DIR`.
* - **macOS:** Not supported.
* - **Windows:** Resolves to `{FOLDERID_Templates}`.
* @example
* ```typescript
* import { templateDir } from '@tauri-apps/api/path';
* const templateDirPath = await templateDir();
* ```
*
* @since 1.0.0
*/
async function templateDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Template
});
}
/**
* Returns the path to the user's video directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_VIDEOS_DIR`.
* - **macOS:** Resolves to `$HOME/Movies`.
* - **Windows:** Resolves to `{FOLDERID_Videos}`.
* @example
* ```typescript
* import { videoDir } from '@tauri-apps/api/path';
* const videoDirPath = await videoDir();
* ```
*
* @since 1.0.0
*/
async function videoDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Video
});
}
/**
* Returns the path to the suggested directory for your app's log files.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `${configDir}/${bundleIdentifier}/logs`.
* - **macOS:** Resolves to `${homeDir}/Library/Logs/{bundleIdentifier}`
* - **Windows:** Resolves to `${configDir}/${bundleIdentifier}/logs`.
* @example
* ```typescript
* import { appLogDir } from '@tauri-apps/api/path';
* const appLogDirPath = await appLogDir();
* ```
*
* @since 1.2.0
*/
async function appLogDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.AppLog
});
}
/**
* Returns a temporary directory.
* @example
* ```typescript
* import { tempDir } from '@tauri-apps/api/path';
* const temp = await tempDir();
* ```
*
* @since 2.0.0
*/
async function tempDir() {
return core.invoke('plugin:path|resolve_directory', {
directory: exports.BaseDirectory.Temp
});
}
/**
* Returns the platform-specific path segment separator:
* - `\` on Windows
* - `/` on POSIX
*
* @since 2.0.0
*/
function sep() {
return window.__TAURI_INTERNALS__.plugins.path.sep;
}
/**
* Returns the platform-specific path segment delimiter:
* - `;` on Windows
* - `:` on POSIX
*
* @since 2.0.0
*/
function delimiter() {
return window.__TAURI_INTERNALS__.plugins.path.delimiter;
}
/**
* Resolves a sequence of `paths` or `path` segments into an absolute path.
* @example
* ```typescript
* import { resolve, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await resolve(appDataDirPath, '..', 'users', 'tauri', 'avatar.png');
* ```
*
* @since 1.0.0
*/
async function resolve(...paths) {
return core.invoke('plugin:path|resolve', { paths });
}
/**
* Normalizes the given `path`, resolving `'..'` and `'.'` segments and resolve symbolic links.
* @example
* ```typescript
* import { normalize, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await normalize(`${appDataDirPath}/../users/tauri/avatar.png`);
* ```
*
* @since 1.0.0
*/
async function normalize(path) {
return core.invoke('plugin:path|normalize', { path });
}
/**
* Joins all given `path` segments together using the platform-specific separator as a delimiter, then normalizes the resulting path.
* @example
* ```typescript
* import { join, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await join(appDataDirPath, 'users', 'tauri', 'avatar.png');
* ```
*
* @since 1.0.0
*/
async function join(...paths) {
return core.invoke('plugin:path|join', { paths });
}
/**
* Returns the parent directory of a given `path`. Trailing directory separators are ignored.
* @example
* ```typescript
* import { dirname } from '@tauri-apps/api/path';
* const dir = await dirname('/path/to/somedir/');
* assert(dir === '/path/to');
* ```
*
* @since 1.0.0
*/
async function dirname(path) {
return core.invoke('plugin:path|dirname', { path });
}
/**
* Returns the extension of the `path`.
* @example
* ```typescript
* import { extname } from '@tauri-apps/api/path';
* const ext = await extname('/path/to/file.html');
* assert(ext === 'html');
* ```
*
* @since 1.0.0
*/
async function extname(path) {
return core.invoke('plugin:path|extname', { path });
}
/**
* Returns the last portion of a `path`. Trailing directory separators are ignored.
* @example
* ```typescript
* import { basename } from '@tauri-apps/api/path';
* const base = await basename('path/to/app.conf');
* assert(base === 'app.conf');
* ```
* @param ext An optional file extension to be removed from the returned path.
*
* @since 1.0.0
*/
async function basename(path, ext) {
return core.invoke('plugin:path|basename', { path, ext });
}
/**
* Returns whether the path is absolute or not.
* @example
* ```typescript
* import { isAbsolute } from '@tauri-apps/api/path';
* assert(await isAbsolute('/home/tauri'));
* ```
*
* @since 1.0.0
*/
async function isAbsolute(path) {
return core.invoke('plugin:path|is_absolute', { path });
}
exports.appCacheDir = appCacheDir;
exports.appConfigDir = appConfigDir;
exports.appDataDir = appDataDir;
exports.appLocalDataDir = appLocalDataDir;
exports.appLogDir = appLogDir;
exports.audioDir = audioDir;
exports.basename = basename;
exports.cacheDir = cacheDir;
exports.configDir = configDir;
exports.dataDir = dataDir;
exports.delimiter = delimiter;
exports.desktopDir = desktopDir;
exports.dirname = dirname;
exports.documentDir = documentDir;
exports.downloadDir = downloadDir;
exports.executableDir = executableDir;
exports.extname = extname;
exports.fontDir = fontDir;
exports.homeDir = homeDir;
exports.isAbsolute = isAbsolute;
exports.join = join;
exports.localDataDir = localDataDir;
exports.normalize = normalize;
exports.pictureDir = pictureDir;
exports.publicDir = publicDir;
exports.resolve = resolve;
exports.resolveResource = resolveResource;
exports.resourceDir = resourceDir;
exports.runtimeDir = runtimeDir;
exports.sep = sep;
exports.tempDir = tempDir;
exports.templateDir = templateDir;
exports.videoDir = videoDir;

589
node_modules/@tauri-apps/api/path.d.ts generated vendored Normal file
View File

@ -0,0 +1,589 @@
/**
* @since 2.0.0
*/
declare enum BaseDirectory {
/**
* @see {@link audioDir} for more information.
*/
Audio = 1,
/**
* @see {@link cacheDir} for more information.
*/
Cache = 2,
/**
* @see {@link configDir} for more information.
*/
Config = 3,
/**
* @see {@link dataDir} for more information.
*/
Data = 4,
/**
* @see {@link localDataDir} for more information.
*/
LocalData = 5,
/**
* @see {@link documentDir} for more information.
*/
Document = 6,
/**
* @see {@link downloadDir} for more information.
*/
Download = 7,
/**
* @see {@link pictureDir} for more information.
*/
Picture = 8,
/**
* @see {@link publicDir} for more information.
*/
Public = 9,
/**
* @see {@link videoDir} for more information.
*/
Video = 10,
/**
* @see {@link resourceDir} for more information.
*/
Resource = 11,
/**
* @see {@link tempDir} for more information.
*/
Temp = 12,
/**
* @see {@link appConfigDir} for more information.
*/
AppConfig = 13,
/**
* @see {@link appDataDir} for more information.
*/
AppData = 14,
/**
* @see {@link appLocalDataDir} for more information.
*/
AppLocalData = 15,
/**
* @see {@link appCacheDir} for more information.
*/
AppCache = 16,
/**
* @see {@link appLogDir} for more information.
*/
AppLog = 17,
/**
* @see {@link desktopDir} for more information.
*/
Desktop = 18,
/**
* @see {@link executableDir} for more information.
*/
Executable = 19,
/**
* @see {@link fontDir} for more information.
*/
Font = 20,
/**
* @see {@link homeDir} for more information.
*/
Home = 21,
/**
* @see {@link runtimeDir} for more information.
*/
Runtime = 22,
/**
* @see {@link templateDir} for more information.
*/
Template = 23
}
/**
* Returns the path to the suggested directory for your app's config files.
* Resolves to `${configDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appConfigDir } from '@tauri-apps/api/path';
* const appConfigDirPath = await appConfigDir();
* ```
*
* @since 1.2.0
*/
declare function appConfigDir(): Promise<string>;
/**
* Returns the path to the suggested directory for your app's data files.
* Resolves to `${dataDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* ```
*
* @since 1.2.0
*/
declare function appDataDir(): Promise<string>;
/**
* Returns the path to the suggested directory for your app's local data files.
* Resolves to `${localDataDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appLocalDataDir } from '@tauri-apps/api/path';
* const appLocalDataDirPath = await appLocalDataDir();
* ```
*
* @since 1.2.0
*/
declare function appLocalDataDir(): Promise<string>;
/**
* Returns the path to the suggested directory for your app's cache files.
* Resolves to `${cacheDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appCacheDir } from '@tauri-apps/api/path';
* const appCacheDirPath = await appCacheDir();
* ```
*
* @since 1.2.0
*/
declare function appCacheDir(): Promise<string>;
/**
* Returns the path to the user's audio directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_MUSIC_DIR`.
* - **macOS:** Resolves to `$HOME/Music`.
* - **Windows:** Resolves to `{FOLDERID_Music}`.
* @example
* ```typescript
* import { audioDir } from '@tauri-apps/api/path';
* const audioDirPath = await audioDir();
* ```
*
* @since 1.0.0
*/
declare function audioDir(): Promise<string>;
/**
* Returns the path to the user's cache directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_CACHE_HOME` or `$HOME/.cache`.
* - **macOS:** Resolves to `$HOME/Library/Caches`.
* - **Windows:** Resolves to `{FOLDERID_LocalAppData}`.
* @example
* ```typescript
* import { cacheDir } from '@tauri-apps/api/path';
* const cacheDirPath = await cacheDir();
* ```
*
* @since 1.0.0
*/
declare function cacheDir(): Promise<string>;
/**
* Returns the path to the user's config directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_CONFIG_HOME` or `$HOME/.config`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
* @example
* ```typescript
* import { configDir } from '@tauri-apps/api/path';
* const configDirPath = await configDir();
* ```
*
* @since 1.0.0
*/
declare function configDir(): Promise<string>;
/**
* Returns the path to the user's data directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
* @example
* ```typescript
* import { dataDir } from '@tauri-apps/api/path';
* const dataDirPath = await dataDir();
* ```
*
* @since 1.0.0
*/
declare function dataDir(): Promise<string>;
/**
* Returns the path to the user's desktop directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DESKTOP_DIR`.
* - **macOS:** Resolves to `$HOME/Desktop`.
* - **Windows:** Resolves to `{FOLDERID_Desktop}`.
* @example
* ```typescript
* import { desktopDir } from '@tauri-apps/api/path';
* const desktopPath = await desktopDir();
* ```
*
* @since 1.0.0
*/
declare function desktopDir(): Promise<string>;
/**
* Returns the path to the user's document directory.
* @example
* ```typescript
* import { documentDir } from '@tauri-apps/api/path';
* const documentDirPath = await documentDir();
* ```
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DOCUMENTS_DIR`.
* - **macOS:** Resolves to `$HOME/Documents`.
* - **Windows:** Resolves to `{FOLDERID_Documents}`.
*
* @since 1.0.0
*/
declare function documentDir(): Promise<string>;
/**
* Returns the path to the user's download directory.
*
* #### Platform-specific
*
* - **Linux**: Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DOWNLOAD_DIR`.
* - **macOS**: Resolves to `$HOME/Downloads`.
* - **Windows**: Resolves to `{FOLDERID_Downloads}`.
* @example
* ```typescript
* import { downloadDir } from '@tauri-apps/api/path';
* const downloadDirPath = await downloadDir();
* ```
*
* @since 1.0.0
*/
declare function downloadDir(): Promise<string>;
/**
* Returns the path to the user's executable directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_BIN_HOME/../bin` or `$XDG_DATA_HOME/../bin` or `$HOME/.local/bin`.
* - **macOS:** Not supported.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { executableDir } from '@tauri-apps/api/path';
* const executableDirPath = await executableDir();
* ```
*
* @since 1.0.0
*/
declare function executableDir(): Promise<string>;
/**
* Returns the path to the user's font directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME/fonts` or `$HOME/.local/share/fonts`.
* - **macOS:** Resolves to `$HOME/Library/Fonts`.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { fontDir } from '@tauri-apps/api/path';
* const fontDirPath = await fontDir();
* ```
*
* @since 1.0.0
*/
declare function fontDir(): Promise<string>;
/**
* Returns the path to the user's home directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$HOME`.
* - **macOS:** Resolves to `$HOME`.
* - **Windows:** Resolves to `{FOLDERID_Profile}`.
* @example
* ```typescript
* import { homeDir } from '@tauri-apps/api/path';
* const homeDirPath = await homeDir();
* ```
*
* @since 1.0.0
*/
declare function homeDir(): Promise<string>;
/**
* Returns the path to the user's local data directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_LocalAppData}`.
* @example
* ```typescript
* import { localDataDir } from '@tauri-apps/api/path';
* const localDataDirPath = await localDataDir();
* ```
*
* @since 1.0.0
*/
declare function localDataDir(): Promise<string>;
/**
* Returns the path to the user's picture directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_PICTURES_DIR`.
* - **macOS:** Resolves to `$HOME/Pictures`.
* - **Windows:** Resolves to `{FOLDERID_Pictures}`.
* @example
* ```typescript
* import { pictureDir } from '@tauri-apps/api/path';
* const pictureDirPath = await pictureDir();
* ```
*
* @since 1.0.0
*/
declare function pictureDir(): Promise<string>;
/**
* Returns the path to the user's public directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_PUBLICSHARE_DIR`.
* - **macOS:** Resolves to `$HOME/Public`.
* - **Windows:** Resolves to `{FOLDERID_Public}`.
* @example
* ```typescript
* import { publicDir } from '@tauri-apps/api/path';
* const publicDirPath = await publicDir();
* ```
*
* @since 1.0.0
*/
declare function publicDir(): Promise<string>;
/**
* Returns the path to the application's resource directory.
* To resolve a resource path, see {@linkcode resolveResource}.
*
* ## Platform-specific
*
* Although we provide the exact path where this function resolves to,
* this is not a contract and things might change in the future
*
* - **Windows:** Resolves to the directory that contains the main executable.
* - **Linux:** When running in an AppImage, the `APPDIR` variable will be set to
* the mounted location of the app, and the resource dir will be `${APPDIR}/usr/lib/${exe_name}`.
* If not running in an AppImage, the path is `/usr/lib/${exe_name}`.
* When running the app from `src-tauri/target/(debug|release)/`, the path is `${exe_dir}/../lib/${exe_name}`.
* - **macOS:** Resolves to `${exe_dir}/../Resources` (inside .app).
* - **iOS:** Resolves to `${exe_dir}/assets`.
* - **Android:** Currently the resources are stored in the APK as assets so it's not a normal file system path,
* we return a special URI prefix `asset://localhost/` here that can be used with the [file system plugin](https://tauri.app/plugin/file-system/),
*
* @example
* ```typescript
* import { resourceDir } from '@tauri-apps/api/path';
* const resourceDirPath = await resourceDir();
* ```
*
* @since 1.0.0
*/
declare function resourceDir(): Promise<string>;
/**
* Resolve the path to a resource file.
* @example
* ```typescript
* import { resolveResource } from '@tauri-apps/api/path';
* const resourcePath = await resolveResource('script.sh');
* ```
*
* @param resourcePath The path to the resource.
* Must follow the same syntax as defined in `tauri.conf.json > bundle > resources`, i.e. keeping subfolders and parent dir components (`../`).
* @returns The full path to the resource.
*
* @since 1.0.0
*/
declare function resolveResource(resourcePath: string): Promise<string>;
/**
* Returns the path to the user's runtime directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_RUNTIME_DIR`.
* - **macOS:** Not supported.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { runtimeDir } from '@tauri-apps/api/path';
* const runtimeDirPath = await runtimeDir();
* ```
*
* @since 1.0.0
*/
declare function runtimeDir(): Promise<string>;
/**
* Returns the path to the user's template directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_TEMPLATES_DIR`.
* - **macOS:** Not supported.
* - **Windows:** Resolves to `{FOLDERID_Templates}`.
* @example
* ```typescript
* import { templateDir } from '@tauri-apps/api/path';
* const templateDirPath = await templateDir();
* ```
*
* @since 1.0.0
*/
declare function templateDir(): Promise<string>;
/**
* Returns the path to the user's video directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_VIDEOS_DIR`.
* - **macOS:** Resolves to `$HOME/Movies`.
* - **Windows:** Resolves to `{FOLDERID_Videos}`.
* @example
* ```typescript
* import { videoDir } from '@tauri-apps/api/path';
* const videoDirPath = await videoDir();
* ```
*
* @since 1.0.0
*/
declare function videoDir(): Promise<string>;
/**
* Returns the path to the suggested directory for your app's log files.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `${configDir}/${bundleIdentifier}/logs`.
* - **macOS:** Resolves to `${homeDir}/Library/Logs/{bundleIdentifier}`
* - **Windows:** Resolves to `${configDir}/${bundleIdentifier}/logs`.
* @example
* ```typescript
* import { appLogDir } from '@tauri-apps/api/path';
* const appLogDirPath = await appLogDir();
* ```
*
* @since 1.2.0
*/
declare function appLogDir(): Promise<string>;
/**
* Returns a temporary directory.
* @example
* ```typescript
* import { tempDir } from '@tauri-apps/api/path';
* const temp = await tempDir();
* ```
*
* @since 2.0.0
*/
declare function tempDir(): Promise<string>;
/**
* Returns the platform-specific path segment separator:
* - `\` on Windows
* - `/` on POSIX
*
* @since 2.0.0
*/
declare function sep(): string;
/**
* Returns the platform-specific path segment delimiter:
* - `;` on Windows
* - `:` on POSIX
*
* @since 2.0.0
*/
declare function delimiter(): string;
/**
* Resolves a sequence of `paths` or `path` segments into an absolute path.
* @example
* ```typescript
* import { resolve, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await resolve(appDataDirPath, '..', 'users', 'tauri', 'avatar.png');
* ```
*
* @since 1.0.0
*/
declare function resolve(...paths: string[]): Promise<string>;
/**
* Normalizes the given `path`, resolving `'..'` and `'.'` segments and resolve symbolic links.
* @example
* ```typescript
* import { normalize, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await normalize(`${appDataDirPath}/../users/tauri/avatar.png`);
* ```
*
* @since 1.0.0
*/
declare function normalize(path: string): Promise<string>;
/**
* Joins all given `path` segments together using the platform-specific separator as a delimiter, then normalizes the resulting path.
* @example
* ```typescript
* import { join, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await join(appDataDirPath, 'users', 'tauri', 'avatar.png');
* ```
*
* @since 1.0.0
*/
declare function join(...paths: string[]): Promise<string>;
/**
* Returns the parent directory of a given `path`. Trailing directory separators are ignored.
* @example
* ```typescript
* import { dirname } from '@tauri-apps/api/path';
* const dir = await dirname('/path/to/somedir/');
* assert(dir === '/path/to');
* ```
*
* @since 1.0.0
*/
declare function dirname(path: string): Promise<string>;
/**
* Returns the extension of the `path`.
* @example
* ```typescript
* import { extname } from '@tauri-apps/api/path';
* const ext = await extname('/path/to/file.html');
* assert(ext === 'html');
* ```
*
* @since 1.0.0
*/
declare function extname(path: string): Promise<string>;
/**
* Returns the last portion of a `path`. Trailing directory separators are ignored.
* @example
* ```typescript
* import { basename } from '@tauri-apps/api/path';
* const base = await basename('path/to/app.conf');
* assert(base === 'app.conf');
* ```
* @param ext An optional file extension to be removed from the returned path.
*
* @since 1.0.0
*/
declare function basename(path: string, ext?: string): Promise<string>;
/**
* Returns whether the path is absolute or not.
* @example
* ```typescript
* import { isAbsolute } from '@tauri-apps/api/path';
* assert(await isAbsolute('/home/tauri'));
* ```
*
* @since 1.0.0
*/
declare function isAbsolute(path: string): Promise<boolean>;
export { BaseDirectory, appConfigDir, appDataDir, appLocalDataDir, appCacheDir, appLogDir, audioDir, cacheDir, configDir, dataDir, desktopDir, documentDir, downloadDir, executableDir, fontDir, homeDir, localDataDir, pictureDir, publicDir, resourceDir, resolveResource, runtimeDir, templateDir, videoDir, sep, delimiter, resolve, normalize, join, dirname, extname, basename, isAbsolute, tempDir };

719
node_modules/@tauri-apps/api/path.js generated vendored Normal file
View File

@ -0,0 +1,719 @@
import { invoke } from './core.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* The path module provides utilities for working with file and directory paths.
*
* This package is also accessible with `window.__TAURI__.path` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
*
* It is recommended to allowlist only the APIs you use for optimal bundle size and security.
* @module
*/
/**
* @since 2.0.0
*/
var BaseDirectory;
(function (BaseDirectory) {
/**
* @see {@link audioDir} for more information.
*/
BaseDirectory[BaseDirectory["Audio"] = 1] = "Audio";
/**
* @see {@link cacheDir} for more information.
*/
BaseDirectory[BaseDirectory["Cache"] = 2] = "Cache";
/**
* @see {@link configDir} for more information.
*/
BaseDirectory[BaseDirectory["Config"] = 3] = "Config";
/**
* @see {@link dataDir} for more information.
*/
BaseDirectory[BaseDirectory["Data"] = 4] = "Data";
/**
* @see {@link localDataDir} for more information.
*/
BaseDirectory[BaseDirectory["LocalData"] = 5] = "LocalData";
/**
* @see {@link documentDir} for more information.
*/
BaseDirectory[BaseDirectory["Document"] = 6] = "Document";
/**
* @see {@link downloadDir} for more information.
*/
BaseDirectory[BaseDirectory["Download"] = 7] = "Download";
/**
* @see {@link pictureDir} for more information.
*/
BaseDirectory[BaseDirectory["Picture"] = 8] = "Picture";
/**
* @see {@link publicDir} for more information.
*/
BaseDirectory[BaseDirectory["Public"] = 9] = "Public";
/**
* @see {@link videoDir} for more information.
*/
BaseDirectory[BaseDirectory["Video"] = 10] = "Video";
/**
* @see {@link resourceDir} for more information.
*/
BaseDirectory[BaseDirectory["Resource"] = 11] = "Resource";
/**
* @see {@link tempDir} for more information.
*/
BaseDirectory[BaseDirectory["Temp"] = 12] = "Temp";
/**
* @see {@link appConfigDir} for more information.
*/
BaseDirectory[BaseDirectory["AppConfig"] = 13] = "AppConfig";
/**
* @see {@link appDataDir} for more information.
*/
BaseDirectory[BaseDirectory["AppData"] = 14] = "AppData";
/**
* @see {@link appLocalDataDir} for more information.
*/
BaseDirectory[BaseDirectory["AppLocalData"] = 15] = "AppLocalData";
/**
* @see {@link appCacheDir} for more information.
*/
BaseDirectory[BaseDirectory["AppCache"] = 16] = "AppCache";
/**
* @see {@link appLogDir} for more information.
*/
BaseDirectory[BaseDirectory["AppLog"] = 17] = "AppLog";
/**
* @see {@link desktopDir} for more information.
*/
BaseDirectory[BaseDirectory["Desktop"] = 18] = "Desktop";
/**
* @see {@link executableDir} for more information.
*/
BaseDirectory[BaseDirectory["Executable"] = 19] = "Executable";
/**
* @see {@link fontDir} for more information.
*/
BaseDirectory[BaseDirectory["Font"] = 20] = "Font";
/**
* @see {@link homeDir} for more information.
*/
BaseDirectory[BaseDirectory["Home"] = 21] = "Home";
/**
* @see {@link runtimeDir} for more information.
*/
BaseDirectory[BaseDirectory["Runtime"] = 22] = "Runtime";
/**
* @see {@link templateDir} for more information.
*/
BaseDirectory[BaseDirectory["Template"] = 23] = "Template";
})(BaseDirectory || (BaseDirectory = {}));
/**
* Returns the path to the suggested directory for your app's config files.
* Resolves to `${configDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appConfigDir } from '@tauri-apps/api/path';
* const appConfigDirPath = await appConfigDir();
* ```
*
* @since 1.2.0
*/
async function appConfigDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.AppConfig
});
}
/**
* Returns the path to the suggested directory for your app's data files.
* Resolves to `${dataDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* ```
*
* @since 1.2.0
*/
async function appDataDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.AppData
});
}
/**
* Returns the path to the suggested directory for your app's local data files.
* Resolves to `${localDataDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appLocalDataDir } from '@tauri-apps/api/path';
* const appLocalDataDirPath = await appLocalDataDir();
* ```
*
* @since 1.2.0
*/
async function appLocalDataDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.AppLocalData
});
}
/**
* Returns the path to the suggested directory for your app's cache files.
* Resolves to `${cacheDir}/${bundleIdentifier}`, where `bundleIdentifier` is the [`identifier`](https://v2.tauri.app/reference/config/#identifier) value configured in `tauri.conf.json`.
* @example
* ```typescript
* import { appCacheDir } from '@tauri-apps/api/path';
* const appCacheDirPath = await appCacheDir();
* ```
*
* @since 1.2.0
*/
async function appCacheDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.AppCache
});
}
/**
* Returns the path to the user's audio directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_MUSIC_DIR`.
* - **macOS:** Resolves to `$HOME/Music`.
* - **Windows:** Resolves to `{FOLDERID_Music}`.
* @example
* ```typescript
* import { audioDir } from '@tauri-apps/api/path';
* const audioDirPath = await audioDir();
* ```
*
* @since 1.0.0
*/
async function audioDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Audio
});
}
/**
* Returns the path to the user's cache directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_CACHE_HOME` or `$HOME/.cache`.
* - **macOS:** Resolves to `$HOME/Library/Caches`.
* - **Windows:** Resolves to `{FOLDERID_LocalAppData}`.
* @example
* ```typescript
* import { cacheDir } from '@tauri-apps/api/path';
* const cacheDirPath = await cacheDir();
* ```
*
* @since 1.0.0
*/
async function cacheDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Cache
});
}
/**
* Returns the path to the user's config directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_CONFIG_HOME` or `$HOME/.config`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
* @example
* ```typescript
* import { configDir } from '@tauri-apps/api/path';
* const configDirPath = await configDir();
* ```
*
* @since 1.0.0
*/
async function configDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Config
});
}
/**
* Returns the path to the user's data directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_RoamingAppData}`.
* @example
* ```typescript
* import { dataDir } from '@tauri-apps/api/path';
* const dataDirPath = await dataDir();
* ```
*
* @since 1.0.0
*/
async function dataDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Data
});
}
/**
* Returns the path to the user's desktop directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DESKTOP_DIR`.
* - **macOS:** Resolves to `$HOME/Desktop`.
* - **Windows:** Resolves to `{FOLDERID_Desktop}`.
* @example
* ```typescript
* import { desktopDir } from '@tauri-apps/api/path';
* const desktopPath = await desktopDir();
* ```
*
* @since 1.0.0
*/
async function desktopDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Desktop
});
}
/**
* Returns the path to the user's document directory.
* @example
* ```typescript
* import { documentDir } from '@tauri-apps/api/path';
* const documentDirPath = await documentDir();
* ```
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DOCUMENTS_DIR`.
* - **macOS:** Resolves to `$HOME/Documents`.
* - **Windows:** Resolves to `{FOLDERID_Documents}`.
*
* @since 1.0.0
*/
async function documentDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Document
});
}
/**
* Returns the path to the user's download directory.
*
* #### Platform-specific
*
* - **Linux**: Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_DOWNLOAD_DIR`.
* - **macOS**: Resolves to `$HOME/Downloads`.
* - **Windows**: Resolves to `{FOLDERID_Downloads}`.
* @example
* ```typescript
* import { downloadDir } from '@tauri-apps/api/path';
* const downloadDirPath = await downloadDir();
* ```
*
* @since 1.0.0
*/
async function downloadDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Download
});
}
/**
* Returns the path to the user's executable directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_BIN_HOME/../bin` or `$XDG_DATA_HOME/../bin` or `$HOME/.local/bin`.
* - **macOS:** Not supported.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { executableDir } from '@tauri-apps/api/path';
* const executableDirPath = await executableDir();
* ```
*
* @since 1.0.0
*/
async function executableDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Executable
});
}
/**
* Returns the path to the user's font directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME/fonts` or `$HOME/.local/share/fonts`.
* - **macOS:** Resolves to `$HOME/Library/Fonts`.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { fontDir } from '@tauri-apps/api/path';
* const fontDirPath = await fontDir();
* ```
*
* @since 1.0.0
*/
async function fontDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Font
});
}
/**
* Returns the path to the user's home directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$HOME`.
* - **macOS:** Resolves to `$HOME`.
* - **Windows:** Resolves to `{FOLDERID_Profile}`.
* @example
* ```typescript
* import { homeDir } from '@tauri-apps/api/path';
* const homeDirPath = await homeDir();
* ```
*
* @since 1.0.0
*/
async function homeDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Home
});
}
/**
* Returns the path to the user's local data directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_DATA_HOME` or `$HOME/.local/share`.
* - **macOS:** Resolves to `$HOME/Library/Application Support`.
* - **Windows:** Resolves to `{FOLDERID_LocalAppData}`.
* @example
* ```typescript
* import { localDataDir } from '@tauri-apps/api/path';
* const localDataDirPath = await localDataDir();
* ```
*
* @since 1.0.0
*/
async function localDataDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.LocalData
});
}
/**
* Returns the path to the user's picture directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_PICTURES_DIR`.
* - **macOS:** Resolves to `$HOME/Pictures`.
* - **Windows:** Resolves to `{FOLDERID_Pictures}`.
* @example
* ```typescript
* import { pictureDir } from '@tauri-apps/api/path';
* const pictureDirPath = await pictureDir();
* ```
*
* @since 1.0.0
*/
async function pictureDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Picture
});
}
/**
* Returns the path to the user's public directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_PUBLICSHARE_DIR`.
* - **macOS:** Resolves to `$HOME/Public`.
* - **Windows:** Resolves to `{FOLDERID_Public}`.
* @example
* ```typescript
* import { publicDir } from '@tauri-apps/api/path';
* const publicDirPath = await publicDir();
* ```
*
* @since 1.0.0
*/
async function publicDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Public
});
}
/**
* Returns the path to the application's resource directory.
* To resolve a resource path, see {@linkcode resolveResource}.
*
* ## Platform-specific
*
* Although we provide the exact path where this function resolves to,
* this is not a contract and things might change in the future
*
* - **Windows:** Resolves to the directory that contains the main executable.
* - **Linux:** When running in an AppImage, the `APPDIR` variable will be set to
* the mounted location of the app, and the resource dir will be `${APPDIR}/usr/lib/${exe_name}`.
* If not running in an AppImage, the path is `/usr/lib/${exe_name}`.
* When running the app from `src-tauri/target/(debug|release)/`, the path is `${exe_dir}/../lib/${exe_name}`.
* - **macOS:** Resolves to `${exe_dir}/../Resources` (inside .app).
* - **iOS:** Resolves to `${exe_dir}/assets`.
* - **Android:** Currently the resources are stored in the APK as assets so it's not a normal file system path,
* we return a special URI prefix `asset://localhost/` here that can be used with the [file system plugin](https://tauri.app/plugin/file-system/),
*
* @example
* ```typescript
* import { resourceDir } from '@tauri-apps/api/path';
* const resourceDirPath = await resourceDir();
* ```
*
* @since 1.0.0
*/
async function resourceDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Resource
});
}
/**
* Resolve the path to a resource file.
* @example
* ```typescript
* import { resolveResource } from '@tauri-apps/api/path';
* const resourcePath = await resolveResource('script.sh');
* ```
*
* @param resourcePath The path to the resource.
* Must follow the same syntax as defined in `tauri.conf.json > bundle > resources`, i.e. keeping subfolders and parent dir components (`../`).
* @returns The full path to the resource.
*
* @since 1.0.0
*/
async function resolveResource(resourcePath) {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Resource,
path: resourcePath
});
}
/**
* Returns the path to the user's runtime directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `$XDG_RUNTIME_DIR`.
* - **macOS:** Not supported.
* - **Windows:** Not supported.
* @example
* ```typescript
* import { runtimeDir } from '@tauri-apps/api/path';
* const runtimeDirPath = await runtimeDir();
* ```
*
* @since 1.0.0
*/
async function runtimeDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Runtime
});
}
/**
* Returns the path to the user's template directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_TEMPLATES_DIR`.
* - **macOS:** Not supported.
* - **Windows:** Resolves to `{FOLDERID_Templates}`.
* @example
* ```typescript
* import { templateDir } from '@tauri-apps/api/path';
* const templateDirPath = await templateDir();
* ```
*
* @since 1.0.0
*/
async function templateDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Template
});
}
/**
* Returns the path to the user's video directory.
*
* #### Platform-specific
*
* - **Linux:** Resolves to [`xdg-user-dirs`](https://www.freedesktop.org/wiki/Software/xdg-user-dirs/)' `XDG_VIDEOS_DIR`.
* - **macOS:** Resolves to `$HOME/Movies`.
* - **Windows:** Resolves to `{FOLDERID_Videos}`.
* @example
* ```typescript
* import { videoDir } from '@tauri-apps/api/path';
* const videoDirPath = await videoDir();
* ```
*
* @since 1.0.0
*/
async function videoDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Video
});
}
/**
* Returns the path to the suggested directory for your app's log files.
*
* #### Platform-specific
*
* - **Linux:** Resolves to `${configDir}/${bundleIdentifier}/logs`.
* - **macOS:** Resolves to `${homeDir}/Library/Logs/{bundleIdentifier}`
* - **Windows:** Resolves to `${configDir}/${bundleIdentifier}/logs`.
* @example
* ```typescript
* import { appLogDir } from '@tauri-apps/api/path';
* const appLogDirPath = await appLogDir();
* ```
*
* @since 1.2.0
*/
async function appLogDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.AppLog
});
}
/**
* Returns a temporary directory.
* @example
* ```typescript
* import { tempDir } from '@tauri-apps/api/path';
* const temp = await tempDir();
* ```
*
* @since 2.0.0
*/
async function tempDir() {
return invoke('plugin:path|resolve_directory', {
directory: BaseDirectory.Temp
});
}
/**
* Returns the platform-specific path segment separator:
* - `\` on Windows
* - `/` on POSIX
*
* @since 2.0.0
*/
function sep() {
return window.__TAURI_INTERNALS__.plugins.path.sep;
}
/**
* Returns the platform-specific path segment delimiter:
* - `;` on Windows
* - `:` on POSIX
*
* @since 2.0.0
*/
function delimiter() {
return window.__TAURI_INTERNALS__.plugins.path.delimiter;
}
/**
* Resolves a sequence of `paths` or `path` segments into an absolute path.
* @example
* ```typescript
* import { resolve, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await resolve(appDataDirPath, '..', 'users', 'tauri', 'avatar.png');
* ```
*
* @since 1.0.0
*/
async function resolve(...paths) {
return invoke('plugin:path|resolve', { paths });
}
/**
* Normalizes the given `path`, resolving `'..'` and `'.'` segments and resolve symbolic links.
* @example
* ```typescript
* import { normalize, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await normalize(`${appDataDirPath}/../users/tauri/avatar.png`);
* ```
*
* @since 1.0.0
*/
async function normalize(path) {
return invoke('plugin:path|normalize', { path });
}
/**
* Joins all given `path` segments together using the platform-specific separator as a delimiter, then normalizes the resulting path.
* @example
* ```typescript
* import { join, appDataDir } from '@tauri-apps/api/path';
* const appDataDirPath = await appDataDir();
* const path = await join(appDataDirPath, 'users', 'tauri', 'avatar.png');
* ```
*
* @since 1.0.0
*/
async function join(...paths) {
return invoke('plugin:path|join', { paths });
}
/**
* Returns the parent directory of a given `path`. Trailing directory separators are ignored.
* @example
* ```typescript
* import { dirname } from '@tauri-apps/api/path';
* const dir = await dirname('/path/to/somedir/');
* assert(dir === '/path/to');
* ```
*
* @since 1.0.0
*/
async function dirname(path) {
return invoke('plugin:path|dirname', { path });
}
/**
* Returns the extension of the `path`.
* @example
* ```typescript
* import { extname } from '@tauri-apps/api/path';
* const ext = await extname('/path/to/file.html');
* assert(ext === 'html');
* ```
*
* @since 1.0.0
*/
async function extname(path) {
return invoke('plugin:path|extname', { path });
}
/**
* Returns the last portion of a `path`. Trailing directory separators are ignored.
* @example
* ```typescript
* import { basename } from '@tauri-apps/api/path';
* const base = await basename('path/to/app.conf');
* assert(base === 'app.conf');
* ```
* @param ext An optional file extension to be removed from the returned path.
*
* @since 1.0.0
*/
async function basename(path, ext) {
return invoke('plugin:path|basename', { path, ext });
}
/**
* Returns whether the path is absolute or not.
* @example
* ```typescript
* import { isAbsolute } from '@tauri-apps/api/path';
* assert(await isAbsolute('/home/tauri'));
* ```
*
* @since 1.0.0
*/
async function isAbsolute(path) {
return invoke('plugin:path|is_absolute', { path });
}
export { BaseDirectory, appCacheDir, appConfigDir, appDataDir, appLocalDataDir, appLogDir, audioDir, basename, cacheDir, configDir, dataDir, delimiter, desktopDir, dirname, documentDir, downloadDir, executableDir, extname, fontDir, homeDir, isAbsolute, join, localDataDir, normalize, pictureDir, publicDir, resolve, resolveResource, resourceDir, runtimeDir, sep, tempDir, templateDir, videoDir };

188
node_modules/@tauri-apps/api/tray.cjs generated vendored Normal file
View File

@ -0,0 +1,188 @@
'use strict';
var core = require('./core.cjs');
var image = require('./image.cjs');
var dpi = require('./dpi.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Tray icon class and associated methods. This type constructor is private,
* instead, you should use the static method {@linkcode TrayIcon.new}.
*
* #### Warning
*
* Unlike Rust, javascript does not have any way to run cleanup code
* when an object is being removed by garbage collection, but this tray icon
* will be cleaned up when the tauri app exists, however if you want to cleanup
* this object early, you need to call {@linkcode TrayIcon.close}.
*
* @example
* ```ts
* import { TrayIcon } from '@tauri-apps/api/tray';
* const tray = await TrayIcon.new({ tooltip: 'awesome tray tooltip' });
* tray.set_tooltip('new tooltip');
* ```
*/
class TrayIcon extends core.Resource {
constructor(rid, id) {
super(rid);
this.id = id;
}
/** Gets a tray icon using the provided id. */
static async getById(id) {
return core.invoke('plugin:tray|get_by_id', { id }).then((rid) => rid ? new TrayIcon(rid, id) : null);
}
/**
* Removes a tray icon using the provided id from tauri's internal state.
*
* Note that this may cause the tray icon to disappear
* if it wasn't cloned somewhere else or referenced by JS.
*/
static async removeById(id) {
return core.invoke('plugin:tray|remove_by_id', { id });
}
/**
* Creates a new {@linkcode TrayIcon}
*
* #### Platform-specific:
*
* - **Linux:** Sometimes the icon won't be visible unless a menu is set.
* Setting an empty {@linkcode Menu} is enough.
*/
static async new(options) {
if (options === null || options === void 0 ? void 0 : options.menu) {
// @ts-expect-error we only need the rid and kind
options.menu = [options.menu.rid, options.menu.kind];
}
if (options === null || options === void 0 ? void 0 : options.icon) {
options.icon = image.transformImage(options.icon);
}
const handler = new core.Channel();
if (options === null || options === void 0 ? void 0 : options.action) {
const action = options.action;
handler.onmessage = (e) => action(mapEvent(e));
delete options.action;
}
return core.invoke('plugin:tray|new', {
options: options !== null && options !== void 0 ? options : {},
handler
}).then(([rid, id]) => new TrayIcon(rid, id));
}
/**
* Sets a new tray icon. If `null` is provided, it will remove the icon.
*
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
async setIcon(icon) {
let trayIcon = null;
if (icon) {
trayIcon = image.transformImage(icon);
}
return core.invoke('plugin:tray|set_icon', { rid: this.rid, icon: trayIcon });
}
/**
* Sets a new tray menu.
*
* #### Platform-specific:
*
* - **Linux**: once a menu is set it cannot be removed so `null` has no effect
*/
async setMenu(menu) {
if (menu) {
// @ts-expect-error we only need the rid and kind
menu = [menu.rid, menu.kind];
}
return core.invoke('plugin:tray|set_menu', { rid: this.rid, menu });
}
/**
* Sets the tooltip for this tray icon.
*
* #### Platform-specific:
*
* - **Linux:** Unsupported
*/
async setTooltip(tooltip) {
return core.invoke('plugin:tray|set_tooltip', { rid: this.rid, tooltip });
}
/**
* Sets the tooltip for this tray icon.
*
* #### Platform-specific:
*
* - **Linux:** The title will not be shown unless there is an icon
* as well. The title is useful for numerical and other frequently
* updated information. In general, it shouldn't be shown unless a
* user requests it as it can take up a significant amount of space
* on the user's panel. This may not be shown in all visualizations.
* - **Windows:** Unsupported
*/
async setTitle(title) {
return core.invoke('plugin:tray|set_title', { rid: this.rid, title });
}
/** Show or hide this tray icon. */
async setVisible(visible) {
return core.invoke('plugin:tray|set_visible', { rid: this.rid, visible });
}
/**
* Sets the tray icon temp dir path. **Linux only**.
*
* On Linux, we need to write the icon to the disk and usually it will
* be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
*/
async setTempDirPath(path) {
return core.invoke('plugin:tray|set_temp_dir_path', { rid: this.rid, path });
}
/** Sets the current icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only** */
async setIconAsTemplate(asTemplate) {
return core.invoke('plugin:tray|set_icon_as_template', {
rid: this.rid,
asTemplate
});
}
/**
* Disable or enable showing the tray menu on left click.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported.
*
* @deprecated use {@linkcode TrayIcon.setShowMenuOnLeftClick} instead.
*/
async setMenuOnLeftClick(onLeft) {
return core.invoke('plugin:tray|set_show_menu_on_left_click', {
rid: this.rid,
onLeft
});
}
/**
* Disable or enable showing the tray menu on left click.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported.
*
* @since 2.2.0
*/
async setShowMenuOnLeftClick(onLeft) {
return core.invoke('plugin:tray|set_show_menu_on_left_click', {
rid: this.rid,
onLeft
});
}
}
function mapEvent(e) {
const out = e;
out.position = new dpi.PhysicalPosition(e.position);
out.rect.position = new dpi.PhysicalPosition(e.rect.position);
out.rect.size = new dpi.PhysicalSize(e.rect.size);
return out;
}
exports.TrayIcon = TrayIcon;

219
node_modules/@tauri-apps/api/tray.d.ts generated vendored Normal file
View File

@ -0,0 +1,219 @@
import type { Menu, Submenu } from './menu';
import { Resource } from './core';
import { Image } from './image';
import { PhysicalPosition, PhysicalSize } from './dpi';
export type MouseButtonState = 'Up' | 'Down';
export type MouseButton = 'Left' | 'Right' | 'Middle';
export type TrayIconEventType = 'Click' | 'DoubleClick' | 'Enter' | 'Move' | 'Leave';
export type TrayIconEventBase<T extends TrayIconEventType> = {
/** The tray icon event type */
type: T;
/** Id of the tray icon which triggered this event. */
id: string;
/** Physical position of the click the triggered this event. */
position: PhysicalPosition;
/** Position and size of the tray icon. */
rect: {
position: PhysicalPosition;
size: PhysicalSize;
};
};
export type TrayIconClickEvent = {
/** Mouse button that triggered this event. */
button: MouseButton;
/** Mouse button state when this event was triggered. */
buttonState: MouseButtonState;
};
/**
* Describes a tray icon event.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported. The event is not emitted even though the icon is shown,
* the icon will still show a context menu on right click.
*/
export type TrayIconEvent = (TrayIconEventBase<'Click'> & TrayIconClickEvent) | (TrayIconEventBase<'DoubleClick'> & Omit<TrayIconClickEvent, 'buttonState'>) | TrayIconEventBase<'Enter'> | TrayIconEventBase<'Move'> | TrayIconEventBase<'Leave'>;
/**
* Tray icon types and utilities.
*
* This package is also accessible with `window.__TAURI__.tray` when [`app.withGlobalTauri`](https://v2.tauri.app/reference/config/#withglobaltauri) in `tauri.conf.json` is set to `true`.
* @module
*/
/** {@link TrayIcon.new|`TrayIcon`} creation options */
export interface TrayIconOptions {
/** The tray icon id. If undefined, a random one will be assigned */
id?: string;
/** The tray icon menu */
menu?: Menu | Submenu;
/**
* The tray icon which could be icon bytes or path to the icon file.
*
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
icon?: string | Uint8Array | ArrayBuffer | number[] | Image;
/** The tray icon tooltip */
tooltip?: string;
/**
* The tray title
*
* #### Platform-specific
*
* - **Linux:** The title will not be shown unless there is an icon
* as well. The title is useful for numerical and other frequently
* updated information. In general, it shouldn't be shown unless a
* user requests it as it can take up a significant amount of space
* on the user's panel. This may not be shown in all visualizations.
* - **Windows:** Unsupported.
*/
title?: string;
/**
* The tray icon temp dir path. **Linux only**.
*
* On Linux, we need to write the icon to the disk and usually it will
* be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
*/
tempDirPath?: string;
/**
* Use the icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only**.
*/
iconAsTemplate?: boolean;
/**
* Whether to show the tray menu on left click or not, default is `true`.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported.
*
* @deprecated use {@linkcode TrayIconOptions.showMenuOnLeftClick} instead.
*/
menuOnLeftClick?: boolean;
/**
* Whether to show the tray menu on left click or not, default is `true`.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported.
*
* @since 2.2.0
*/
showMenuOnLeftClick?: boolean;
/** A handler for an event on the tray icon. */
action?: (event: TrayIconEvent) => void;
}
/**
* Tray icon class and associated methods. This type constructor is private,
* instead, you should use the static method {@linkcode TrayIcon.new}.
*
* #### Warning
*
* Unlike Rust, javascript does not have any way to run cleanup code
* when an object is being removed by garbage collection, but this tray icon
* will be cleaned up when the tauri app exists, however if you want to cleanup
* this object early, you need to call {@linkcode TrayIcon.close}.
*
* @example
* ```ts
* import { TrayIcon } from '@tauri-apps/api/tray';
* const tray = await TrayIcon.new({ tooltip: 'awesome tray tooltip' });
* tray.set_tooltip('new tooltip');
* ```
*/
export declare class TrayIcon extends Resource {
/** The id associated with this tray icon. */
id: string;
private constructor();
/** Gets a tray icon using the provided id. */
static getById(id: string): Promise<TrayIcon | null>;
/**
* Removes a tray icon using the provided id from tauri's internal state.
*
* Note that this may cause the tray icon to disappear
* if it wasn't cloned somewhere else or referenced by JS.
*/
static removeById(id: string): Promise<void>;
/**
* Creates a new {@linkcode TrayIcon}
*
* #### Platform-specific:
*
* - **Linux:** Sometimes the icon won't be visible unless a menu is set.
* Setting an empty {@linkcode Menu} is enough.
*/
static new(options?: TrayIconOptions): Promise<TrayIcon>;
/**
* Sets a new tray icon. If `null` is provided, it will remove the icon.
*
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
setIcon(icon: string | Image | Uint8Array | ArrayBuffer | number[] | null): Promise<void>;
/**
* Sets a new tray menu.
*
* #### Platform-specific:
*
* - **Linux**: once a menu is set it cannot be removed so `null` has no effect
*/
setMenu(menu: Menu | Submenu | null): Promise<void>;
/**
* Sets the tooltip for this tray icon.
*
* #### Platform-specific:
*
* - **Linux:** Unsupported
*/
setTooltip(tooltip: string | null): Promise<void>;
/**
* Sets the tooltip for this tray icon.
*
* #### Platform-specific:
*
* - **Linux:** The title will not be shown unless there is an icon
* as well. The title is useful for numerical and other frequently
* updated information. In general, it shouldn't be shown unless a
* user requests it as it can take up a significant amount of space
* on the user's panel. This may not be shown in all visualizations.
* - **Windows:** Unsupported
*/
setTitle(title: string | null): Promise<void>;
/** Show or hide this tray icon. */
setVisible(visible: boolean): Promise<void>;
/**
* Sets the tray icon temp dir path. **Linux only**.
*
* On Linux, we need to write the icon to the disk and usually it will
* be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
*/
setTempDirPath(path: string | null): Promise<void>;
/** Sets the current icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only** */
setIconAsTemplate(asTemplate: boolean): Promise<void>;
/**
* Disable or enable showing the tray menu on left click.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported.
*
* @deprecated use {@linkcode TrayIcon.setShowMenuOnLeftClick} instead.
*/
setMenuOnLeftClick(onLeft: boolean): Promise<void>;
/**
* Disable or enable showing the tray menu on left click.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported.
*
* @since 2.2.0
*/
setShowMenuOnLeftClick(onLeft: boolean): Promise<void>;
}

186
node_modules/@tauri-apps/api/tray.js generated vendored Normal file
View File

@ -0,0 +1,186 @@
import { Resource, invoke, Channel } from './core.js';
import { transformImage } from './image.js';
import { PhysicalPosition, PhysicalSize } from './dpi.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Tray icon class and associated methods. This type constructor is private,
* instead, you should use the static method {@linkcode TrayIcon.new}.
*
* #### Warning
*
* Unlike Rust, javascript does not have any way to run cleanup code
* when an object is being removed by garbage collection, but this tray icon
* will be cleaned up when the tauri app exists, however if you want to cleanup
* this object early, you need to call {@linkcode TrayIcon.close}.
*
* @example
* ```ts
* import { TrayIcon } from '@tauri-apps/api/tray';
* const tray = await TrayIcon.new({ tooltip: 'awesome tray tooltip' });
* tray.set_tooltip('new tooltip');
* ```
*/
class TrayIcon extends Resource {
constructor(rid, id) {
super(rid);
this.id = id;
}
/** Gets a tray icon using the provided id. */
static async getById(id) {
return invoke('plugin:tray|get_by_id', { id }).then((rid) => rid ? new TrayIcon(rid, id) : null);
}
/**
* Removes a tray icon using the provided id from tauri's internal state.
*
* Note that this may cause the tray icon to disappear
* if it wasn't cloned somewhere else or referenced by JS.
*/
static async removeById(id) {
return invoke('plugin:tray|remove_by_id', { id });
}
/**
* Creates a new {@linkcode TrayIcon}
*
* #### Platform-specific:
*
* - **Linux:** Sometimes the icon won't be visible unless a menu is set.
* Setting an empty {@linkcode Menu} is enough.
*/
static async new(options) {
if (options === null || options === void 0 ? void 0 : options.menu) {
// @ts-expect-error we only need the rid and kind
options.menu = [options.menu.rid, options.menu.kind];
}
if (options === null || options === void 0 ? void 0 : options.icon) {
options.icon = transformImage(options.icon);
}
const handler = new Channel();
if (options === null || options === void 0 ? void 0 : options.action) {
const action = options.action;
handler.onmessage = (e) => action(mapEvent(e));
delete options.action;
}
return invoke('plugin:tray|new', {
options: options !== null && options !== void 0 ? options : {},
handler
}).then(([rid, id]) => new TrayIcon(rid, id));
}
/**
* Sets a new tray icon. If `null` is provided, it will remove the icon.
*
* Note that you may need the `image-ico` or `image-png` Cargo features to use this API.
* To enable it, change your Cargo.toml file:
* ```toml
* [dependencies]
* tauri = { version = "...", features = ["...", "image-png"] }
* ```
*/
async setIcon(icon) {
let trayIcon = null;
if (icon) {
trayIcon = transformImage(icon);
}
return invoke('plugin:tray|set_icon', { rid: this.rid, icon: trayIcon });
}
/**
* Sets a new tray menu.
*
* #### Platform-specific:
*
* - **Linux**: once a menu is set it cannot be removed so `null` has no effect
*/
async setMenu(menu) {
if (menu) {
// @ts-expect-error we only need the rid and kind
menu = [menu.rid, menu.kind];
}
return invoke('plugin:tray|set_menu', { rid: this.rid, menu });
}
/**
* Sets the tooltip for this tray icon.
*
* #### Platform-specific:
*
* - **Linux:** Unsupported
*/
async setTooltip(tooltip) {
return invoke('plugin:tray|set_tooltip', { rid: this.rid, tooltip });
}
/**
* Sets the tooltip for this tray icon.
*
* #### Platform-specific:
*
* - **Linux:** The title will not be shown unless there is an icon
* as well. The title is useful for numerical and other frequently
* updated information. In general, it shouldn't be shown unless a
* user requests it as it can take up a significant amount of space
* on the user's panel. This may not be shown in all visualizations.
* - **Windows:** Unsupported
*/
async setTitle(title) {
return invoke('plugin:tray|set_title', { rid: this.rid, title });
}
/** Show or hide this tray icon. */
async setVisible(visible) {
return invoke('plugin:tray|set_visible', { rid: this.rid, visible });
}
/**
* Sets the tray icon temp dir path. **Linux only**.
*
* On Linux, we need to write the icon to the disk and usually it will
* be `$XDG_RUNTIME_DIR/tray-icon` or `$TEMP/tray-icon`.
*/
async setTempDirPath(path) {
return invoke('plugin:tray|set_temp_dir_path', { rid: this.rid, path });
}
/** Sets the current icon as a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc). **macOS only** */
async setIconAsTemplate(asTemplate) {
return invoke('plugin:tray|set_icon_as_template', {
rid: this.rid,
asTemplate
});
}
/**
* Disable or enable showing the tray menu on left click.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported.
*
* @deprecated use {@linkcode TrayIcon.setShowMenuOnLeftClick} instead.
*/
async setMenuOnLeftClick(onLeft) {
return invoke('plugin:tray|set_show_menu_on_left_click', {
rid: this.rid,
onLeft
});
}
/**
* Disable or enable showing the tray menu on left click.
*
* #### Platform-specific:
*
* - **Linux**: Unsupported.
*
* @since 2.2.0
*/
async setShowMenuOnLeftClick(onLeft) {
return invoke('plugin:tray|set_show_menu_on_left_click', {
rid: this.rid,
onLeft
});
}
}
function mapEvent(e) {
const out = e;
out.position = new PhysicalPosition(e.position);
out.rect.position = new PhysicalPosition(e.rect.position);
out.rect.size = new PhysicalSize(e.rect.size);
return out;
}
export { TrayIcon };

594
node_modules/@tauri-apps/api/webview.cjs generated vendored Normal file
View File

@ -0,0 +1,594 @@
'use strict';
var dpi = require('./dpi.cjs');
var event = require('./event.cjs');
var core = require('./core.cjs');
var window$1 = require('./window.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Provides APIs to create webviews, communicate with other webviews and manipulate the current webview.
*
* #### Webview events
*
* Events can be listened to using {@link Webview.listen}:
* ```typescript
* import { getCurrentWebview } from "@tauri-apps/api/webview";
* getCurrentWebview().listen("my-webview-event", ({ event, payload }) => { });
* ```
*
* @module
*/
/**
* Get an instance of `Webview` for the current webview.
*
* @since 2.0.0
*/
function getCurrentWebview() {
return new Webview(window$1.getCurrentWindow(), window.__TAURI_INTERNALS__.metadata.currentWebview.label, {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
skip: true
});
}
/**
* Gets a list of instances of `Webview` for all available webviews.
*
* @since 2.0.0
*/
async function getAllWebviews() {
return core.invoke('plugin:webview|get_all_webviews').then((webviews) => webviews.map((w) => new Webview(new window$1.Window(w.windowLabel, {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
skip: true
}), w.label, {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
skip: true
})));
}
/** @ignore */
// events that are emitted right here instead of by the created webview
const localTauriEvents = ['tauri://created', 'tauri://error'];
/**
* Create new webview or get a handle to an existing one.
*
* Webviews are identified by a *label* a unique identifier that can be used to reference it later.
* It may only contain alphanumeric characters `a-zA-Z` plus the following special characters `-`, `/`, `:` and `_`.
*
* @example
* ```typescript
* import { Window } from "@tauri-apps/api/window"
* import { Webview } from "@tauri-apps/api/webview"
*
* const appWindow = new Window('uniqueLabel');
*
* appWindow.once('tauri://created', async function () {
* // `new Webview` Should be called after the window is successfully created,
* // or webview may not be attached to the window since window is not created yet.
*
* // loading embedded asset:
* const webview = new Webview(appWindow, 'theUniqueLabel', {
* url: 'path/to/page.html',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
* // alternatively, load a remote URL:
* const webview = new Webview(appWindow, 'theUniqueLabel', {
* url: 'https://github.com/tauri-apps/tauri',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
*
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
*
*
* // emit an event to the backend
* await webview.emit("some-event", "data");
* // listen to an event from the backend
* const unlisten = await webview.listen("event-name", e => { });
* unlisten();
* });
* ```
*
* @since 2.0.0
*/
class Webview {
/**
* Creates a new Webview.
* @example
* ```typescript
* import { Window } from '@tauri-apps/api/window'
* import { Webview } from '@tauri-apps/api/webview'
* const appWindow = new Window('my-label')
*
* appWindow.once('tauri://created', async function() {
* const webview = new Webview(appWindow, 'my-label', {
* url: 'https://github.com/tauri-apps/tauri',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
*
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
* });
* ```
*
* @param window the window to add this webview to.
* @param label The unique webview label. Must be alphanumeric: `a-zA-Z-/:_`.
* @returns The {@link Webview} instance to communicate with the webview.
*/
constructor(window, label, options) {
this.window = window;
this.label = label;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.listeners = Object.create(null);
// @ts-expect-error `skip` is not a public API so it is not defined in WebviewOptions
if (!(options === null || options === void 0 ? void 0 : options.skip)) {
core.invoke('plugin:webview|create_webview', {
windowLabel: window.label,
options: {
...options,
label
}
})
.then(async () => this.emit('tauri://created'))
.catch(async (e) => this.emit('tauri://error', e));
}
}
/**
* Gets the Webview for the webview associated with the given label.
* @example
* ```typescript
* import { Webview } from '@tauri-apps/api/webview';
* const mainWebview = Webview.getByLabel('main');
* ```
*
* @param label The webview label.
* @returns The Webview instance to communicate with the webview or null if the webview doesn't exist.
*/
static async getByLabel(label) {
var _a;
return (_a = (await getAllWebviews()).find((w) => w.label === label)) !== null && _a !== void 0 ? _a : null;
}
/**
* Get an instance of `Webview` for the current webview.
*/
static getCurrent() {
return getCurrentWebview();
}
/**
* Gets a list of instances of `Webview` for all available webviews.
*/
static async getAll() {
return getAllWebviews();
}
/**
* Listen to an emitted event on this webview.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const unlisten = await getCurrentWebview().listen<string>('state-changed', (event) => {
* console.log(`Got error: ${payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async listen(event$1, handler) {
if (this._handleTauriEvent(event$1, handler)) {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event$1];
listeners.splice(listeners.indexOf(handler), 1);
};
}
return event.listen(event$1, handler, {
target: { kind: 'Webview', label: this.label }
});
}
/**
* Listen to an emitted event on this webview only once.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const unlisten = await getCurrent().once<null>('initialized', (event) => {
* console.log(`Webview initialized!`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async once(event$1, handler) {
if (this._handleTauriEvent(event$1, handler)) {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event$1];
listeners.splice(listeners.indexOf(handler), 1);
};
}
return event.once(event$1, handler, {
target: { kind: 'Webview', label: this.label }
});
}
/**
* Emits an event to all {@link EventTarget|targets}.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().emit('webview-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
async emit(event$1, payload) {
if (localTauriEvents.includes(event$1)) {
// eslint-disable-next-line
for (const handler of this.listeners[event$1] || []) {
handler({
event: event$1,
id: -1,
payload
});
}
return;
}
return event.emit(event$1, payload);
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().emitTo('main', 'webview-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
async emitTo(target, event$1, payload) {
if (localTauriEvents.includes(event$1)) {
// eslint-disable-next-line
for (const handler of this.listeners[event$1] || []) {
handler({
event: event$1,
id: -1,
payload
});
}
return;
}
return event.emitTo(target, event$1, payload);
}
/** @ignore */
_handleTauriEvent(event, handler) {
if (localTauriEvents.includes(event)) {
if (!(event in this.listeners)) {
// eslint-disable-next-line security/detect-object-injection
this.listeners[event] = [handler];
}
else {
// eslint-disable-next-line security/detect-object-injection
this.listeners[event].push(handler);
}
return true;
}
return false;
}
// Getters
/**
* The position of the top-left hand corner of the webview's client area relative to the top-left hand corner of the desktop.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const position = await getCurrentWebview().position();
* ```
*
* @returns The webview's position.
*/
async position() {
return core.invoke('plugin:webview|webview_position', {
label: this.label
}).then((p) => new dpi.PhysicalPosition(p));
}
/**
* The physical size of the webview's client area.
* The client area is the content of the webview, excluding the title bar and borders.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const size = await getCurrentWebview().size();
* ```
*
* @returns The webview's size.
*/
async size() {
return core.invoke('plugin:webview|webview_size', {
label: this.label
}).then((s) => new dpi.PhysicalSize(s));
}
// Setters
/**
* Closes the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().close();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async close() {
return core.invoke('plugin:webview|webview_close', {
label: this.label
});
}
/**
* Resizes the webview.
* @example
* ```typescript
* import { getCurrent, LogicalSize } from '@tauri-apps/api/webview';
* await getCurrentWebview().setSize(new LogicalSize(600, 500));
* ```
*
* @param size The logical or physical size.
* @returns A promise indicating the success or failure of the operation.
*/
async setSize(size) {
return core.invoke('plugin:webview|set_webview_size', {
label: this.label,
value: size instanceof dpi.Size ? size : new dpi.Size(size)
});
}
/**
* Sets the webview position.
* @example
* ```typescript
* import { getCurrent, LogicalPosition } from '@tauri-apps/api/webview';
* await getCurrentWebview().setPosition(new LogicalPosition(600, 500));
* ```
*
* @param position The new position, in logical or physical pixels.
* @returns A promise indicating the success or failure of the operation.
*/
async setPosition(position) {
return core.invoke('plugin:webview|set_webview_position', {
label: this.label,
value: position instanceof dpi.Position ? position : new dpi.Position(position)
});
}
/**
* Bring the webview to front and focus.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setFocus();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async setFocus() {
return core.invoke('plugin:webview|set_webview_focus', {
label: this.label
});
}
/**
* Sets whether the webview should automatically grow and shrink its size and position when the parent window resizes.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setAutoResize(true);
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async setAutoResize(autoResize) {
return core.invoke('plugin:webview|set_webview_auto_resize', {
label: this.label,
value: autoResize
});
}
/**
* Hide the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().hide();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async hide() {
return core.invoke('plugin:webview|webview_hide', {
label: this.label
});
}
/**
* Show the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().show();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async show() {
return core.invoke('plugin:webview|webview_show', {
label: this.label
});
}
/**
* Set webview zoom level.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setZoom(1.5);
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async setZoom(scaleFactor) {
return core.invoke('plugin:webview|set_webview_zoom', {
label: this.label,
value: scaleFactor
});
}
/**
* Moves this webview to the given label.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().reparent('other-window');
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async reparent(window) {
return core.invoke('plugin:webview|reparent', {
label: this.label,
window: typeof window === 'string' ? window : window.label
});
}
/**
* Clears all browsing data for this webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().clearAllBrowsingData();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async clearAllBrowsingData() {
return core.invoke('plugin:webview|clear_all_browsing_data');
}
/**
* Specify the webview background color.
*
* #### Platfrom-specific:
*
* - **macOS / iOS**: Not implemented.
* - **Windows**:
* - On Windows 7, transparency is not supported and the alpha value will be ignored.
* - On Windows higher than 7: translucent colors are not supported so any alpha value other than `0` will be replaced by `255`
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.1.0
*/
async setBackgroundColor(color) {
return core.invoke('plugin:webview|set_webview_background_color', { color });
}
// Listeners
/**
* Listen to a file drop event.
* The listener is triggered when the user hovers the selected files on the webview,
* drops the files or cancels the operation.
*
* @example
* ```typescript
* import { getCurrentWebview } from "@tauri-apps/api/webview";
* const unlisten = await getCurrentWebview().onDragDropEvent((event) => {
* if (event.payload.type === 'over') {
* console.log('User hovering', event.payload.position);
* } else if (event.payload.type === 'drop') {
* console.log('User dropped', event.payload.paths);
* } else {
* console.log('File drop cancelled');
* }
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* When the debugger panel is open, the drop position of this event may be inaccurate due to a known limitation.
* To retrieve the correct drop position, please detach the debugger.
*
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async onDragDropEvent(handler) {
const unlistenDragEnter = await this.listen(event.TauriEvent.DRAG_ENTER, (event) => {
handler({
...event,
payload: {
type: 'enter',
paths: event.payload.paths,
position: new dpi.PhysicalPosition(event.payload.position)
}
});
});
const unlistenDragOver = await this.listen(event.TauriEvent.DRAG_OVER, (event) => {
handler({
...event,
payload: {
type: 'over',
position: new dpi.PhysicalPosition(event.payload.position)
}
});
});
const unlistenDragDrop = await this.listen(event.TauriEvent.DRAG_DROP, (event) => {
handler({
...event,
payload: {
type: 'drop',
paths: event.payload.paths,
position: new dpi.PhysicalPosition(event.payload.position)
}
});
});
const unlistenDragLeave = await this.listen(event.TauriEvent.DRAG_LEAVE, (event) => {
handler({ ...event, payload: { type: 'leave' } });
});
return () => {
unlistenDragEnter();
unlistenDragDrop();
unlistenDragOver();
unlistenDragLeave();
};
}
}
exports.Webview = Webview;
exports.getAllWebviews = getAllWebviews;
exports.getCurrentWebview = getCurrentWebview;

612
node_modules/@tauri-apps/api/webview.d.ts generated vendored Normal file
View File

@ -0,0 +1,612 @@
/**
* Provides APIs to create webviews, communicate with other webviews and manipulate the current webview.
*
* #### Webview events
*
* Events can be listened to using {@link Webview.listen}:
* ```typescript
* import { getCurrentWebview } from "@tauri-apps/api/webview";
* getCurrentWebview().listen("my-webview-event", ({ event, payload }) => { });
* ```
*
* @module
*/
import { PhysicalPosition, PhysicalSize } from './dpi';
import type { LogicalPosition, LogicalSize } from './dpi';
import { Position, Size } from './dpi';
import type { EventName, EventCallback, UnlistenFn } from './event';
import { type EventTarget } from './event';
import { BackgroundThrottlingPolicy, ScrollBarStyle, Color, Window } from './window';
import { WebviewWindow } from './webviewWindow';
/** The drag and drop event types. */
type DragDropEvent = {
type: 'enter';
paths: string[];
position: PhysicalPosition;
} | {
type: 'over';
position: PhysicalPosition;
} | {
type: 'drop';
paths: string[];
position: PhysicalPosition;
} | {
type: 'leave';
};
/**
* Get an instance of `Webview` for the current webview.
*
* @since 2.0.0
*/
declare function getCurrentWebview(): Webview;
/**
* Gets a list of instances of `Webview` for all available webviews.
*
* @since 2.0.0
*/
declare function getAllWebviews(): Promise<Webview[]>;
/** @ignore */
export type WebviewLabel = string;
/**
* Create new webview or get a handle to an existing one.
*
* Webviews are identified by a *label* a unique identifier that can be used to reference it later.
* It may only contain alphanumeric characters `a-zA-Z` plus the following special characters `-`, `/`, `:` and `_`.
*
* @example
* ```typescript
* import { Window } from "@tauri-apps/api/window"
* import { Webview } from "@tauri-apps/api/webview"
*
* const appWindow = new Window('uniqueLabel');
*
* appWindow.once('tauri://created', async function () {
* // `new Webview` Should be called after the window is successfully created,
* // or webview may not be attached to the window since window is not created yet.
*
* // loading embedded asset:
* const webview = new Webview(appWindow, 'theUniqueLabel', {
* url: 'path/to/page.html',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
* // alternatively, load a remote URL:
* const webview = new Webview(appWindow, 'theUniqueLabel', {
* url: 'https://github.com/tauri-apps/tauri',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
*
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
*
*
* // emit an event to the backend
* await webview.emit("some-event", "data");
* // listen to an event from the backend
* const unlisten = await webview.listen("event-name", e => { });
* unlisten();
* });
* ```
*
* @since 2.0.0
*/
declare class Webview {
/** The webview label. It is a unique identifier for the webview, can be used to reference it later. */
label: WebviewLabel;
/** The window hosting this webview. */
window: Window;
/** Local event listeners. */
listeners: Record<string, Array<EventCallback<any>>>;
/**
* Creates a new Webview.
* @example
* ```typescript
* import { Window } from '@tauri-apps/api/window'
* import { Webview } from '@tauri-apps/api/webview'
* const appWindow = new Window('my-label')
*
* appWindow.once('tauri://created', async function() {
* const webview = new Webview(appWindow, 'my-label', {
* url: 'https://github.com/tauri-apps/tauri',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
*
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
* });
* ```
*
* @param window the window to add this webview to.
* @param label The unique webview label. Must be alphanumeric: `a-zA-Z-/:_`.
* @returns The {@link Webview} instance to communicate with the webview.
*/
constructor(window: Window, label: WebviewLabel, options: WebviewOptions);
/**
* Gets the Webview for the webview associated with the given label.
* @example
* ```typescript
* import { Webview } from '@tauri-apps/api/webview';
* const mainWebview = Webview.getByLabel('main');
* ```
*
* @param label The webview label.
* @returns The Webview instance to communicate with the webview or null if the webview doesn't exist.
*/
static getByLabel(label: string): Promise<Webview | null>;
/**
* Get an instance of `Webview` for the current webview.
*/
static getCurrent(): Webview;
/**
* Gets a list of instances of `Webview` for all available webviews.
*/
static getAll(): Promise<Webview[]>;
/**
* Listen to an emitted event on this webview.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const unlisten = await getCurrentWebview().listen<string>('state-changed', (event) => {
* console.log(`Got error: ${payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
listen<T>(event: EventName, handler: EventCallback<T>): Promise<UnlistenFn>;
/**
* Listen to an emitted event on this webview only once.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const unlisten = await getCurrent().once<null>('initialized', (event) => {
* console.log(`Webview initialized!`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
once<T>(event: EventName, handler: EventCallback<T>): Promise<UnlistenFn>;
/**
* Emits an event to all {@link EventTarget|targets}.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().emit('webview-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
emit<T>(event: string, payload?: T): Promise<void>;
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().emitTo('main', 'webview-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
emitTo<T>(target: string | EventTarget, event: string, payload?: T): Promise<void>;
/** @ignore */
_handleTauriEvent<T>(event: string, handler: EventCallback<T>): boolean;
/**
* The position of the top-left hand corner of the webview's client area relative to the top-left hand corner of the desktop.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const position = await getCurrentWebview().position();
* ```
*
* @returns The webview's position.
*/
position(): Promise<PhysicalPosition>;
/**
* The physical size of the webview's client area.
* The client area is the content of the webview, excluding the title bar and borders.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const size = await getCurrentWebview().size();
* ```
*
* @returns The webview's size.
*/
size(): Promise<PhysicalSize>;
/**
* Closes the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().close();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
close(): Promise<void>;
/**
* Resizes the webview.
* @example
* ```typescript
* import { getCurrent, LogicalSize } from '@tauri-apps/api/webview';
* await getCurrentWebview().setSize(new LogicalSize(600, 500));
* ```
*
* @param size The logical or physical size.
* @returns A promise indicating the success or failure of the operation.
*/
setSize(size: LogicalSize | PhysicalSize | Size): Promise<void>;
/**
* Sets the webview position.
* @example
* ```typescript
* import { getCurrent, LogicalPosition } from '@tauri-apps/api/webview';
* await getCurrentWebview().setPosition(new LogicalPosition(600, 500));
* ```
*
* @param position The new position, in logical or physical pixels.
* @returns A promise indicating the success or failure of the operation.
*/
setPosition(position: LogicalPosition | PhysicalPosition | Position): Promise<void>;
/**
* Bring the webview to front and focus.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setFocus();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
setFocus(): Promise<void>;
/**
* Sets whether the webview should automatically grow and shrink its size and position when the parent window resizes.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setAutoResize(true);
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
setAutoResize(autoResize: boolean): Promise<void>;
/**
* Hide the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().hide();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
hide(): Promise<void>;
/**
* Show the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().show();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
show(): Promise<void>;
/**
* Set webview zoom level.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setZoom(1.5);
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
setZoom(scaleFactor: number): Promise<void>;
/**
* Moves this webview to the given label.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().reparent('other-window');
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
reparent(window: Window | WebviewWindow | string): Promise<void>;
/**
* Clears all browsing data for this webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().clearAllBrowsingData();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
clearAllBrowsingData(): Promise<void>;
/**
* Specify the webview background color.
*
* #### Platfrom-specific:
*
* - **macOS / iOS**: Not implemented.
* - **Windows**:
* - On Windows 7, transparency is not supported and the alpha value will be ignored.
* - On Windows higher than 7: translucent colors are not supported so any alpha value other than `0` will be replaced by `255`
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.1.0
*/
setBackgroundColor(color: Color | null): Promise<void>;
/**
* Listen to a file drop event.
* The listener is triggered when the user hovers the selected files on the webview,
* drops the files or cancels the operation.
*
* @example
* ```typescript
* import { getCurrentWebview } from "@tauri-apps/api/webview";
* const unlisten = await getCurrentWebview().onDragDropEvent((event) => {
* if (event.payload.type === 'over') {
* console.log('User hovering', event.payload.position);
* } else if (event.payload.type === 'drop') {
* console.log('User dropped', event.payload.paths);
* } else {
* console.log('File drop cancelled');
* }
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* When the debugger panel is open, the drop position of this event may be inaccurate due to a known limitation.
* To retrieve the correct drop position, please detach the debugger.
*
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
onDragDropEvent(handler: EventCallback<DragDropEvent>): Promise<UnlistenFn>;
}
/**
* Configuration for the webview to create.
*
* @since 2.0.0
*/
interface WebviewOptions {
/**
* Remote URL or local file path to open.
*
* - URL such as `https://github.com/tauri-apps` is opened directly on a Tauri webview.
* - data: URL such as `data:text/html,<html>...` is only supported with the `webview-data-url` Cargo feature for the `tauri` dependency.
* - local file path or route such as `/path/to/page.html` or `/users` is appended to the application URL (the devServer URL on development, or `tauri://localhost/` and `https://tauri.localhost/` on production).
*/
url?: string;
/** The initial vertical position in logical pixels. */
x: number;
/** The initial horizontal position in logical pixels. */
y: number;
/** The initial width in logical pixels. */
width: number;
/** The initial height in logical pixels. */
height: number;
/**
* Whether the webview is transparent or not.
* Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri.conf.json > app > macOSPrivateApi`.
* WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.
*/
transparent?: boolean;
/**
* Whether the webview should have focus or not
*
* @since 2.1.0
*/
focus?: boolean;
/**
* Whether the drag and drop is enabled or not on the webview. By default it is enabled.
*
* Disabling it is required to use HTML5 drag and drop on the frontend on Windows.
*/
dragDropEnabled?: boolean;
/**
* Whether clicking an inactive webview also clicks through to the webview on macOS.
*/
acceptFirstMouse?: boolean;
/**
* The user agent for the webview.
*/
userAgent?: string;
/**
* Whether or not the webview should be launched in incognito mode.
*
* #### Platform-specific
*
* - **Android:** Unsupported.
*/
incognito?: boolean;
/**
* The proxy URL for the WebView for all network requests.
*
* Must be either a `http://` or a `socks5://` URL.
*
* #### Platform-specific
*
* - **macOS**: Requires the `macos-proxy` feature flag and only compiles for macOS 14+.
* */
proxyUrl?: string;
/**
* Whether page zooming by hotkeys is enabled
*
* #### Platform-specific:
*
* - **Windows**: Controls WebView2's [`IsZoomControlEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings?view=webview2-winrt-1.0.2420.47#iszoomcontrolenabled) setting.
* - **MacOS / Linux**: Injects a polyfill that zooms in and out with `ctrl/command` + `-/=`,
* 20% in each step, ranging from 20% to 1000%. Requires `webview:allow-set-webview-zoom` permission
*
* - **Android / iOS**: Unsupported.
*/
zoomHotkeysEnabled?: boolean;
/**
* Sets whether the custom protocols should use `https://<scheme>.localhost` instead of the default `http://<scheme>.localhost` on Windows and Android. Defaults to `false`.
*
* #### Note
*
* Using a `https` scheme will NOT allow mixed content when trying to fetch `http` endpoints and therefore will not match the behavior of the `<scheme>://localhost` protocols used on macOS and Linux.
*
* #### Warning
*
* Changing this value between releases will change the IndexedDB, cookies and localstorage location and your app will not be able to access them.
*
* @since 2.1.0
*/
useHttpsScheme?: boolean;
/**
* Whether web inspector, which is usually called browser devtools, is enabled or not. Enabled by default.
*
* This API works in **debug** builds, but requires `devtools` feature flag to enable it in **release** builds.
*
* #### Platform-specific
*
* - macOS: This will call private functions on **macOS**.
* - Android: Open `chrome://inspect/#devices` in Chrome to get the devtools window. Wry's `WebView` devtools API isn't supported on Android.
* - iOS: Open Safari > Develop > [Your Device Name] > [Your WebView] to get the devtools window.
*
* @since 2.1.0
*/
devtools?: boolean;
/**
* Set the window and webview background color.
*
* #### Platform-specific:
*
* - **macOS / iOS**: Not implemented.
* - **Windows**:
* - On Windows 7, alpha channel is ignored.
* - On Windows 8 and newer, if alpha channel is not `0`, it will be ignored.
*
* @since 2.1.0
*/
backgroundColor?: Color;
/** Change the default background throttling behaviour.
*
* By default, browsers use a suspend policy that will throttle timers and even unload
* the whole tab (view) to free resources after roughly 5 minutes when a view became
* minimized or hidden. This will pause all tasks until the documents visibility state
* changes back from hidden to visible by bringing the view back to the foreground.
*
* ## Platform-specific
*
* - **Linux / Windows / Android**: Unsupported. Workarounds like a pending WebLock transaction might suffice.
* - **iOS**: Supported since version 17.0+.
* - **macOS**: Supported since version 14.0+.
*
* see https://github.com/tauri-apps/tauri/issues/5250#issuecomment-2569380578
*
* @since 2.3.0
*/
backgroundThrottling?: BackgroundThrottlingPolicy;
/**
* Whether we should disable JavaScript code execution on the webview or not.
*/
javascriptDisabled?: boolean;
/**
* on macOS and iOS there is a link preview on long pressing links, this is enabled by default.
* see https://docs.rs/objc2-web-kit/latest/objc2_web_kit/struct.WKWebView.html#method.allowsLinkPreview
*/
allowLinkPreview?: boolean;
/**
* Allows disabling the input accessory view on iOS.
*
* The accessory view is the view that appears above the keyboard when a text input element is focused.
* It usually displays a view with "Done", "Next" buttons.
*/
disableInputAccessoryView?: boolean;
/**
* Set a custom path for the webview's data directory (localStorage, cache, etc.) **relative to [`appDataDir()`]/${label}**.
* For security reasons, paths outside of that location can only be configured on the Rust side.
*
* #### Platform-specific:
*
* - **Windows**: WebViews with different values for settings like `additionalBrowserArgs`, `browserExtensionsEnabled` or `scrollBarStyle` must have different data directories.
* - **macOS / iOS**: Unsupported, use `dataStoreIdentifier` instead.
* - **Android**: Unsupported.
*
* @since 2.9.0
*/
dataDirectory?: string;
/**
* Initialize the WebView with a custom data store identifier. This can be seen as a replacement for `dataDirectory` which is unavailable in WKWebView.
* See https://developer.apple.com/documentation/webkit/wkwebsitedatastore/init(foridentifier:)?language=objc
*
* The array must contain 16 u8 numbers.
*
* #### Platform-specific:
*
* - **macOS / iOS**: Available on macOS >= 14 and iOS >= 17
* - **Windows / Linux / Android**: Unsupported.
*
* @since 2.9.0
*/
dataStoreIdentifier?: number[];
/**
* Specifies the native scrollbar style to use with the webview.
* CSS styles that modify the scrollbar are applied on top of the native appearance configured here.
*
* Defaults to `default`, which is the browser default.
*
* ## Platform-specific
*
* - **Windows**:
* - `fluentOverlay` requires WebView2 Runtime version 125.0.2535.41 or higher, and does nothing
* on older versions.
* - This option must be given the same value for all webviews.
* - **Linux / Android / iOS / macOS**: Unsupported. Only supports `Default` and performs no operation.
*/
scrollBarStyle?: ScrollBarStyle;
}
export { Webview, getCurrentWebview, getAllWebviews };
export type { DragDropEvent, WebviewOptions, Color };

590
node_modules/@tauri-apps/api/webview.js generated vendored Normal file
View File

@ -0,0 +1,590 @@
import { PhysicalPosition, PhysicalSize, Size, Position } from './dpi.js';
import { listen, once, emit, emitTo, TauriEvent } from './event.js';
import { invoke } from './core.js';
import { Window, getCurrentWindow } from './window.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Provides APIs to create webviews, communicate with other webviews and manipulate the current webview.
*
* #### Webview events
*
* Events can be listened to using {@link Webview.listen}:
* ```typescript
* import { getCurrentWebview } from "@tauri-apps/api/webview";
* getCurrentWebview().listen("my-webview-event", ({ event, payload }) => { });
* ```
*
* @module
*/
/**
* Get an instance of `Webview` for the current webview.
*
* @since 2.0.0
*/
function getCurrentWebview() {
return new Webview(getCurrentWindow(), window.__TAURI_INTERNALS__.metadata.currentWebview.label, {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
skip: true
});
}
/**
* Gets a list of instances of `Webview` for all available webviews.
*
* @since 2.0.0
*/
async function getAllWebviews() {
return invoke('plugin:webview|get_all_webviews').then((webviews) => webviews.map((w) => new Webview(new Window(w.windowLabel, {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
skip: true
}), w.label, {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
skip: true
})));
}
/** @ignore */
// events that are emitted right here instead of by the created webview
const localTauriEvents = ['tauri://created', 'tauri://error'];
/**
* Create new webview or get a handle to an existing one.
*
* Webviews are identified by a *label* a unique identifier that can be used to reference it later.
* It may only contain alphanumeric characters `a-zA-Z` plus the following special characters `-`, `/`, `:` and `_`.
*
* @example
* ```typescript
* import { Window } from "@tauri-apps/api/window"
* import { Webview } from "@tauri-apps/api/webview"
*
* const appWindow = new Window('uniqueLabel');
*
* appWindow.once('tauri://created', async function () {
* // `new Webview` Should be called after the window is successfully created,
* // or webview may not be attached to the window since window is not created yet.
*
* // loading embedded asset:
* const webview = new Webview(appWindow, 'theUniqueLabel', {
* url: 'path/to/page.html',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
* // alternatively, load a remote URL:
* const webview = new Webview(appWindow, 'theUniqueLabel', {
* url: 'https://github.com/tauri-apps/tauri',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
*
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
*
*
* // emit an event to the backend
* await webview.emit("some-event", "data");
* // listen to an event from the backend
* const unlisten = await webview.listen("event-name", e => { });
* unlisten();
* });
* ```
*
* @since 2.0.0
*/
class Webview {
/**
* Creates a new Webview.
* @example
* ```typescript
* import { Window } from '@tauri-apps/api/window'
* import { Webview } from '@tauri-apps/api/webview'
* const appWindow = new Window('my-label')
*
* appWindow.once('tauri://created', async function() {
* const webview = new Webview(appWindow, 'my-label', {
* url: 'https://github.com/tauri-apps/tauri',
*
* // create a webview with specific logical position and size
* x: 0,
* y: 0,
* width: 800,
* height: 600,
* });
*
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
* });
* ```
*
* @param window the window to add this webview to.
* @param label The unique webview label. Must be alphanumeric: `a-zA-Z-/:_`.
* @returns The {@link Webview} instance to communicate with the webview.
*/
constructor(window, label, options) {
this.window = window;
this.label = label;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.listeners = Object.create(null);
// @ts-expect-error `skip` is not a public API so it is not defined in WebviewOptions
if (!(options === null || options === void 0 ? void 0 : options.skip)) {
invoke('plugin:webview|create_webview', {
windowLabel: window.label,
options: {
...options,
label
}
})
.then(async () => this.emit('tauri://created'))
.catch(async (e) => this.emit('tauri://error', e));
}
}
/**
* Gets the Webview for the webview associated with the given label.
* @example
* ```typescript
* import { Webview } from '@tauri-apps/api/webview';
* const mainWebview = Webview.getByLabel('main');
* ```
*
* @param label The webview label.
* @returns The Webview instance to communicate with the webview or null if the webview doesn't exist.
*/
static async getByLabel(label) {
var _a;
return (_a = (await getAllWebviews()).find((w) => w.label === label)) !== null && _a !== void 0 ? _a : null;
}
/**
* Get an instance of `Webview` for the current webview.
*/
static getCurrent() {
return getCurrentWebview();
}
/**
* Gets a list of instances of `Webview` for all available webviews.
*/
static async getAll() {
return getAllWebviews();
}
/**
* Listen to an emitted event on this webview.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const unlisten = await getCurrentWebview().listen<string>('state-changed', (event) => {
* console.log(`Got error: ${payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async listen(event, handler) {
if (this._handleTauriEvent(event, handler)) {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event];
listeners.splice(listeners.indexOf(handler), 1);
};
}
return listen(event, handler, {
target: { kind: 'Webview', label: this.label }
});
}
/**
* Listen to an emitted event on this webview only once.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const unlisten = await getCurrent().once<null>('initialized', (event) => {
* console.log(`Webview initialized!`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async once(event, handler) {
if (this._handleTauriEvent(event, handler)) {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event];
listeners.splice(listeners.indexOf(handler), 1);
};
}
return once(event, handler, {
target: { kind: 'Webview', label: this.label }
});
}
/**
* Emits an event to all {@link EventTarget|targets}.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().emit('webview-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
async emit(event, payload) {
if (localTauriEvents.includes(event)) {
// eslint-disable-next-line
for (const handler of this.listeners[event] || []) {
handler({
event,
id: -1,
payload
});
}
return;
}
return emit(event, payload);
}
/**
* Emits an event to all {@link EventTarget|targets} matching the given target.
*
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().emitTo('main', 'webview-loaded', { loggedIn: true, token: 'authToken' });
* ```
*
* @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object.
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param payload Event payload.
*/
async emitTo(target, event, payload) {
if (localTauriEvents.includes(event)) {
// eslint-disable-next-line
for (const handler of this.listeners[event] || []) {
handler({
event,
id: -1,
payload
});
}
return;
}
return emitTo(target, event, payload);
}
/** @ignore */
_handleTauriEvent(event, handler) {
if (localTauriEvents.includes(event)) {
if (!(event in this.listeners)) {
// eslint-disable-next-line security/detect-object-injection
this.listeners[event] = [handler];
}
else {
// eslint-disable-next-line security/detect-object-injection
this.listeners[event].push(handler);
}
return true;
}
return false;
}
// Getters
/**
* The position of the top-left hand corner of the webview's client area relative to the top-left hand corner of the desktop.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const position = await getCurrentWebview().position();
* ```
*
* @returns The webview's position.
*/
async position() {
return invoke('plugin:webview|webview_position', {
label: this.label
}).then((p) => new PhysicalPosition(p));
}
/**
* The physical size of the webview's client area.
* The client area is the content of the webview, excluding the title bar and borders.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* const size = await getCurrentWebview().size();
* ```
*
* @returns The webview's size.
*/
async size() {
return invoke('plugin:webview|webview_size', {
label: this.label
}).then((s) => new PhysicalSize(s));
}
// Setters
/**
* Closes the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().close();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async close() {
return invoke('plugin:webview|webview_close', {
label: this.label
});
}
/**
* Resizes the webview.
* @example
* ```typescript
* import { getCurrent, LogicalSize } from '@tauri-apps/api/webview';
* await getCurrentWebview().setSize(new LogicalSize(600, 500));
* ```
*
* @param size The logical or physical size.
* @returns A promise indicating the success or failure of the operation.
*/
async setSize(size) {
return invoke('plugin:webview|set_webview_size', {
label: this.label,
value: size instanceof Size ? size : new Size(size)
});
}
/**
* Sets the webview position.
* @example
* ```typescript
* import { getCurrent, LogicalPosition } from '@tauri-apps/api/webview';
* await getCurrentWebview().setPosition(new LogicalPosition(600, 500));
* ```
*
* @param position The new position, in logical or physical pixels.
* @returns A promise indicating the success or failure of the operation.
*/
async setPosition(position) {
return invoke('plugin:webview|set_webview_position', {
label: this.label,
value: position instanceof Position ? position : new Position(position)
});
}
/**
* Bring the webview to front and focus.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setFocus();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async setFocus() {
return invoke('plugin:webview|set_webview_focus', {
label: this.label
});
}
/**
* Sets whether the webview should automatically grow and shrink its size and position when the parent window resizes.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setAutoResize(true);
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async setAutoResize(autoResize) {
return invoke('plugin:webview|set_webview_auto_resize', {
label: this.label,
value: autoResize
});
}
/**
* Hide the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().hide();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async hide() {
return invoke('plugin:webview|webview_hide', {
label: this.label
});
}
/**
* Show the webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().show();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async show() {
return invoke('plugin:webview|webview_show', {
label: this.label
});
}
/**
* Set webview zoom level.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().setZoom(1.5);
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async setZoom(scaleFactor) {
return invoke('plugin:webview|set_webview_zoom', {
label: this.label,
value: scaleFactor
});
}
/**
* Moves this webview to the given label.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().reparent('other-window');
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async reparent(window) {
return invoke('plugin:webview|reparent', {
label: this.label,
window: typeof window === 'string' ? window : window.label
});
}
/**
* Clears all browsing data for this webview.
* @example
* ```typescript
* import { getCurrentWebview } from '@tauri-apps/api/webview';
* await getCurrentWebview().clearAllBrowsingData();
* ```
*
* @returns A promise indicating the success or failure of the operation.
*/
async clearAllBrowsingData() {
return invoke('plugin:webview|clear_all_browsing_data');
}
/**
* Specify the webview background color.
*
* #### Platfrom-specific:
*
* - **macOS / iOS**: Not implemented.
* - **Windows**:
* - On Windows 7, transparency is not supported and the alpha value will be ignored.
* - On Windows higher than 7: translucent colors are not supported so any alpha value other than `0` will be replaced by `255`
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.1.0
*/
async setBackgroundColor(color) {
return invoke('plugin:webview|set_webview_background_color', { color });
}
// Listeners
/**
* Listen to a file drop event.
* The listener is triggered when the user hovers the selected files on the webview,
* drops the files or cancels the operation.
*
* @example
* ```typescript
* import { getCurrentWebview } from "@tauri-apps/api/webview";
* const unlisten = await getCurrentWebview().onDragDropEvent((event) => {
* if (event.payload.type === 'over') {
* console.log('User hovering', event.payload.position);
* } else if (event.payload.type === 'drop') {
* console.log('User dropped', event.payload.paths);
* } else {
* console.log('File drop cancelled');
* }
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* When the debugger panel is open, the drop position of this event may be inaccurate due to a known limitation.
* To retrieve the correct drop position, please detach the debugger.
*
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async onDragDropEvent(handler) {
const unlistenDragEnter = await this.listen(TauriEvent.DRAG_ENTER, (event) => {
handler({
...event,
payload: {
type: 'enter',
paths: event.payload.paths,
position: new PhysicalPosition(event.payload.position)
}
});
});
const unlistenDragOver = await this.listen(TauriEvent.DRAG_OVER, (event) => {
handler({
...event,
payload: {
type: 'over',
position: new PhysicalPosition(event.payload.position)
}
});
});
const unlistenDragDrop = await this.listen(TauriEvent.DRAG_DROP, (event) => {
handler({
...event,
payload: {
type: 'drop',
paths: event.payload.paths,
position: new PhysicalPosition(event.payload.position)
}
});
});
const unlistenDragLeave = await this.listen(TauriEvent.DRAG_LEAVE, (event) => {
handler({ ...event, payload: { type: 'leave' } });
});
return () => {
unlistenDragEnter();
unlistenDragDrop();
unlistenDragOver();
unlistenDragLeave();
};
}
}
export { Webview, getAllWebviews, getCurrentWebview };

211
node_modules/@tauri-apps/api/webviewWindow.cjs generated vendored Normal file
View File

@ -0,0 +1,211 @@
'use strict';
var webview = require('./webview.cjs');
var window = require('./window.cjs');
var event = require('./event.cjs');
var core = require('./core.cjs');
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Get an instance of `Webview` for the current webview window.
*
* @since 2.0.0
*/
function getCurrentWebviewWindow() {
const webview$1 = webview.getCurrentWebview();
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
return new WebviewWindow(webview$1.label, { skip: true });
}
/**
* Gets a list of instances of `Webview` for all available webview windows.
*
* @since 2.0.0
*/
async function getAllWebviewWindows() {
return core.invoke('plugin:window|get_all_windows').then((windows) => windows.map((w) => new WebviewWindow(w, {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
skip: true
})));
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
class WebviewWindow {
/**
* Creates a new {@link Window} hosting a {@link Webview}.
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
* const webview = new WebviewWindow('my-label', {
* url: 'https://github.com/tauri-apps/tauri'
* });
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
* ```
*
* @param label The unique webview label. Must be alphanumeric: `a-zA-Z-/:_`.
* @returns The {@link WebviewWindow} instance to communicate with the window and webview.
*/
constructor(label, options = {}) {
var _a;
this.label = label;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.listeners = Object.create(null);
// @ts-expect-error `skip` is not a public API so it is not defined in WebviewOptions
if (!(options === null || options === void 0 ? void 0 : options.skip)) {
core.invoke('plugin:webview|create_webview_window', {
options: {
...options,
parent: typeof options.parent === 'string'
? options.parent
: (_a = options.parent) === null || _a === void 0 ? void 0 : _a.label,
label
}
})
.then(async () => this.emit('tauri://created'))
.catch(async (e) => this.emit('tauri://error', e));
}
}
/**
* Gets the Webview for the webview associated with the given label.
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const mainWebview = WebviewWindow.getByLabel('main');
* ```
*
* @param label The webview label.
* @returns The Webview instance to communicate with the webview or null if the webview doesn't exist.
*/
static async getByLabel(label) {
var _a;
const webview = (_a = (await getAllWebviewWindows()).find((w) => w.label === label)) !== null && _a !== void 0 ? _a : null;
if (webview) {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
return new WebviewWindow(webview.label, { skip: true });
}
return null;
}
/**
* Get an instance of `Webview` for the current webview.
*/
static getCurrent() {
return getCurrentWebviewWindow();
}
/**
* Gets a list of instances of `Webview` for all available webviews.
*/
static async getAll() {
return getAllWebviewWindows();
}
/**
* Listen to an emitted event on this webview window.
*
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const unlisten = await WebviewWindow.getCurrent().listen<string>('state-changed', (event) => {
* console.log(`Got error: ${payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async listen(event$1, handler) {
if (this._handleTauriEvent(event$1, handler)) {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event$1];
listeners.splice(listeners.indexOf(handler), 1);
};
}
return event.listen(event$1, handler, {
target: { kind: 'WebviewWindow', label: this.label }
});
}
/**
* Listen to an emitted event on this webview window only once.
*
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const unlisten = await WebviewWindow.getCurrent().once<null>('initialized', (event) => {
* console.log(`Webview initialized!`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async once(event$1, handler) {
if (this._handleTauriEvent(event$1, handler)) {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event$1];
listeners.splice(listeners.indexOf(handler), 1);
};
}
return event.once(event$1, handler, {
target: { kind: 'WebviewWindow', label: this.label }
});
}
/**
* Set the window and webview background color.
*
* #### Platform-specific:
*
* - **Android / iOS:** Unsupported for the window layer.
* - **macOS / iOS**: Not implemented for the webview layer.
* - **Windows**:
* - alpha channel is ignored for the window layer.
* - On Windows 7, alpha channel is ignored for the webview layer.
* - On Windows 8 and newer, if alpha channel is not `0`, it will be ignored.
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.1.0
*/
async setBackgroundColor(color) {
return core.invoke('plugin:window|set_background_color', { color }).then(() => {
return core.invoke('plugin:webview|set_webview_background_color', { color });
});
}
}
// Order matters, we use window APIs by default
applyMixins(WebviewWindow, [window.Window, webview.Webview]);
/** Extends a base class by other specified classes, without overriding existing properties */
function applyMixins(baseClass, extendedClasses) {
(Array.isArray(extendedClasses)
? extendedClasses
: [extendedClasses]).forEach((extendedClass) => {
Object.getOwnPropertyNames(extendedClass.prototype).forEach((name) => {
var _a;
if (typeof baseClass.prototype === 'object'
&& baseClass.prototype
&& name in baseClass.prototype)
return;
Object.defineProperty(baseClass.prototype, name,
// eslint-disable-next-line
(_a = Object.getOwnPropertyDescriptor(extendedClass.prototype, name)) !== null && _a !== void 0 ? _a : Object.create(null));
});
});
}
exports.WebviewWindow = WebviewWindow;
exports.getAllWebviewWindows = getAllWebviewWindows;
exports.getCurrentWebviewWindow = getCurrentWebviewWindow;

123
node_modules/@tauri-apps/api/webviewWindow.d.ts generated vendored Normal file
View File

@ -0,0 +1,123 @@
import { Webview, WebviewLabel, WebviewOptions } from './webview';
import type { WindowOptions } from './window';
import { Window } from './window';
import type { EventName, EventCallback, UnlistenFn } from './event';
import type { Color, DragDropEvent } from './webview';
/**
* Get an instance of `Webview` for the current webview window.
*
* @since 2.0.0
*/
declare function getCurrentWebviewWindow(): WebviewWindow;
/**
* Gets a list of instances of `Webview` for all available webview windows.
*
* @since 2.0.0
*/
declare function getAllWebviewWindows(): Promise<WebviewWindow[]>;
interface WebviewWindow extends Webview, Window {
}
declare class WebviewWindow {
label: string;
/** Local event listeners. */
listeners: Record<string, Array<EventCallback<any>>>;
/**
* Creates a new {@link Window} hosting a {@link Webview}.
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
* const webview = new WebviewWindow('my-label', {
* url: 'https://github.com/tauri-apps/tauri'
* });
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
* ```
*
* @param label The unique webview label. Must be alphanumeric: `a-zA-Z-/:_`.
* @returns The {@link WebviewWindow} instance to communicate with the window and webview.
*/
constructor(label: WebviewLabel, options?: Omit<WebviewOptions, 'x' | 'y' | 'width' | 'height'> & WindowOptions);
/**
* Gets the Webview for the webview associated with the given label.
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const mainWebview = WebviewWindow.getByLabel('main');
* ```
*
* @param label The webview label.
* @returns The Webview instance to communicate with the webview or null if the webview doesn't exist.
*/
static getByLabel(label: string): Promise<WebviewWindow | null>;
/**
* Get an instance of `Webview` for the current webview.
*/
static getCurrent(): WebviewWindow;
/**
* Gets a list of instances of `Webview` for all available webviews.
*/
static getAll(): Promise<WebviewWindow[]>;
/**
* Listen to an emitted event on this webview window.
*
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const unlisten = await WebviewWindow.getCurrent().listen<string>('state-changed', (event) => {
* console.log(`Got error: ${payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
listen<T>(event: EventName, handler: EventCallback<T>): Promise<UnlistenFn>;
/**
* Listen to an emitted event on this webview window only once.
*
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const unlisten = await WebviewWindow.getCurrent().once<null>('initialized', (event) => {
* console.log(`Webview initialized!`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
once<T>(event: EventName, handler: EventCallback<T>): Promise<UnlistenFn>;
/**
* Set the window and webview background color.
*
* #### Platform-specific:
*
* - **Android / iOS:** Unsupported for the window layer.
* - **macOS / iOS**: Not implemented for the webview layer.
* - **Windows**:
* - alpha channel is ignored for the window layer.
* - On Windows 7, alpha channel is ignored for the webview layer.
* - On Windows 8 and newer, if alpha channel is not `0`, it will be ignored.
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.1.0
*/
setBackgroundColor(color: Color): Promise<void>;
}
export { WebviewWindow, getCurrentWebviewWindow, getAllWebviewWindows };
export type { DragDropEvent, Color };

207
node_modules/@tauri-apps/api/webviewWindow.js generated vendored Normal file
View File

@ -0,0 +1,207 @@
import { getCurrentWebview, Webview } from './webview.js';
import { Window } from './window.js';
import { listen, once } from './event.js';
import { invoke } from './core.js';
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/**
* Get an instance of `Webview` for the current webview window.
*
* @since 2.0.0
*/
function getCurrentWebviewWindow() {
const webview = getCurrentWebview();
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
return new WebviewWindow(webview.label, { skip: true });
}
/**
* Gets a list of instances of `Webview` for all available webview windows.
*
* @since 2.0.0
*/
async function getAllWebviewWindows() {
return invoke('plugin:window|get_all_windows').then((windows) => windows.map((w) => new WebviewWindow(w, {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
skip: true
})));
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging
class WebviewWindow {
/**
* Creates a new {@link Window} hosting a {@link Webview}.
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
* const webview = new WebviewWindow('my-label', {
* url: 'https://github.com/tauri-apps/tauri'
* });
* webview.once('tauri://created', function () {
* // webview successfully created
* });
* webview.once('tauri://error', function (e) {
* // an error happened creating the webview
* });
* ```
*
* @param label The unique webview label. Must be alphanumeric: `a-zA-Z-/:_`.
* @returns The {@link WebviewWindow} instance to communicate with the window and webview.
*/
constructor(label, options = {}) {
var _a;
this.label = label;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.listeners = Object.create(null);
// @ts-expect-error `skip` is not a public API so it is not defined in WebviewOptions
if (!(options === null || options === void 0 ? void 0 : options.skip)) {
invoke('plugin:webview|create_webview_window', {
options: {
...options,
parent: typeof options.parent === 'string'
? options.parent
: (_a = options.parent) === null || _a === void 0 ? void 0 : _a.label,
label
}
})
.then(async () => this.emit('tauri://created'))
.catch(async (e) => this.emit('tauri://error', e));
}
}
/**
* Gets the Webview for the webview associated with the given label.
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const mainWebview = WebviewWindow.getByLabel('main');
* ```
*
* @param label The webview label.
* @returns The Webview instance to communicate with the webview or null if the webview doesn't exist.
*/
static async getByLabel(label) {
var _a;
const webview = (_a = (await getAllWebviewWindows()).find((w) => w.label === label)) !== null && _a !== void 0 ? _a : null;
if (webview) {
// @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor
return new WebviewWindow(webview.label, { skip: true });
}
return null;
}
/**
* Get an instance of `Webview` for the current webview.
*/
static getCurrent() {
return getCurrentWebviewWindow();
}
/**
* Gets a list of instances of `Webview` for all available webviews.
*/
static async getAll() {
return getAllWebviewWindows();
}
/**
* Listen to an emitted event on this webview window.
*
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const unlisten = await WebviewWindow.getCurrent().listen<string>('state-changed', (event) => {
* console.log(`Got error: ${payload}`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async listen(event, handler) {
if (this._handleTauriEvent(event, handler)) {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event];
listeners.splice(listeners.indexOf(handler), 1);
};
}
return listen(event, handler, {
target: { kind: 'WebviewWindow', label: this.label }
});
}
/**
* Listen to an emitted event on this webview window only once.
*
* @example
* ```typescript
* import { WebviewWindow } from '@tauri-apps/api/webviewWindow';
* const unlisten = await WebviewWindow.getCurrent().once<null>('initialized', (event) => {
* console.log(`Webview initialized!`);
* });
*
* // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted
* unlisten();
* ```
*
* @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`.
* @param handler Event handler.
* @returns A promise resolving to a function to unlisten to the event.
* Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted.
*/
async once(event, handler) {
if (this._handleTauriEvent(event, handler)) {
return () => {
// eslint-disable-next-line security/detect-object-injection
const listeners = this.listeners[event];
listeners.splice(listeners.indexOf(handler), 1);
};
}
return once(event, handler, {
target: { kind: 'WebviewWindow', label: this.label }
});
}
/**
* Set the window and webview background color.
*
* #### Platform-specific:
*
* - **Android / iOS:** Unsupported for the window layer.
* - **macOS / iOS**: Not implemented for the webview layer.
* - **Windows**:
* - alpha channel is ignored for the window layer.
* - On Windows 7, alpha channel is ignored for the webview layer.
* - On Windows 8 and newer, if alpha channel is not `0`, it will be ignored.
*
* @returns A promise indicating the success or failure of the operation.
*
* @since 2.1.0
*/
async setBackgroundColor(color) {
return invoke('plugin:window|set_background_color', { color }).then(() => {
return invoke('plugin:webview|set_webview_background_color', { color });
});
}
}
// Order matters, we use window APIs by default
applyMixins(WebviewWindow, [Window, Webview]);
/** Extends a base class by other specified classes, without overriding existing properties */
function applyMixins(baseClass, extendedClasses) {
(Array.isArray(extendedClasses)
? extendedClasses
: [extendedClasses]).forEach((extendedClass) => {
Object.getOwnPropertyNames(extendedClass.prototype).forEach((name) => {
var _a;
if (typeof baseClass.prototype === 'object'
&& baseClass.prototype
&& name in baseClass.prototype)
return;
Object.defineProperty(baseClass.prototype, name,
// eslint-disable-next-line
(_a = Object.getOwnPropertyDescriptor(extendedClass.prototype, name)) !== null && _a !== void 0 ? _a : Object.create(null));
});
});
}
export { WebviewWindow, getAllWebviewWindows, getCurrentWebviewWindow };

2051
node_modules/@tauri-apps/api/window.cjs generated vendored Normal file

File diff suppressed because it is too large Load Diff

1803
node_modules/@tauri-apps/api/window.d.ts generated vendored Normal file

File diff suppressed because it is too large Load Diff

2038
node_modules/@tauri-apps/api/window.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

21
node_modules/tauri-plugin-mic-recorder-api/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 ayangweb
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.

95
node_modules/tauri-plugin-mic-recorder-api/README.md generated vendored Normal file
View File

@ -0,0 +1,95 @@
# tauri-plugin-mic-recorder
> This plugin only works on tauri v2, if you need the v1 plugin, feel free to submit a PR!
Supports recording audio using a microphone and saving the recorded data as a file.
https://github.com/user-attachments/assets/7c6f1df4-96e6-4cac-806b-098e8bccc1f7
## Platform Support
| Platform | Supported |
| -------- | --------- |
| Windows | ✅ |
| macOS | ✅ |
| Linux | ✅ |
| Android | ✅ |
| iOS | ✅ |
## Install
```shell
cargo add tauri-plugin-mic-recorder
```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
```shell
pnpm add tauri-plugin-mic-recorder-api
```
## Usage
`src-tauri/src/lib.rs`
```diff
pub fn run() {
tauri::Builder::default()
+ .plugin(tauri_plugin_mic_recorder::init())
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
`src-tauri/capabilities/default.json`
```diff
{
...
"permissions": [
...
+ "mic-recorder:default"
]
}
```
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
```ts
import { startRecording } from "tauri-plugin-mic-recorder-api";
startRecording();
```
## Methods
| Method | Description |
| ---------------- | ----------------------- |
| `startRecording` | Starts recording audio. |
| `stopRecording` | Stops recording audio. |
## Example
```shell
git clone https://github.com/ayangweb/tauri-plugin-mic-recorder.git
```
```shell
pnpm install
pnpm build
cd examples/tauri-app
pnpm install
pnpm dev
```
## Thanks
- Use [cpal](https://github.com/RustAudio/cpal) and [hound](https://github.com/ruuda/hound) record and generate wav files.
## Who's Use It
- [Coco AI](https://github.com/infinilabs/coco-app) - Search, Connect, Collaborate, Your Personal AI Search and Assistant, all in one space.

View File

@ -0,0 +1,43 @@
'use strict';
var core = require('@tauri-apps/api/core');
const COMMAND = {
START_RECORDING: "plugin:mic-recorder|start_recording",
STOP_RECORDING: "plugin:mic-recorder|stop_recording",
};
/**
* Starts recording audio.
*
* @example
* ```
* import { startRecording } from 'tauri-plugin-mic-recorder-api';
*
* startRecording().then(() => {
* console.log("Recording started");
* });
* ```
*/
const startRecording = () => {
return core.invoke(COMMAND.START_RECORDING);
};
/**
* Stops recording audio.
*
* @returns Returns the path where the recording file is stored.
*
* @example
* ```
* import { stopRecording } from 'tauri-plugin-mic-recorder-api';
*
* const savePath = await stopRecording();
* console.log("Recording saved at:", savePath);
* ```
*/
const stopRecording = () => {
return core.invoke(COMMAND.STOP_RECORDING);
};
exports.COMMAND = COMMAND;
exports.startRecording = startRecording;
exports.stopRecording = stopRecording;

View File

@ -0,0 +1,31 @@
export declare const COMMAND: {
START_RECORDING: string;
STOP_RECORDING: string;
};
/**
* Starts recording audio.
*
* @example
* ```
* import { startRecording } from 'tauri-plugin-mic-recorder-api';
*
* startRecording().then(() => {
* console.log("Recording started");
* });
* ```
*/
export declare const startRecording: () => Promise<unknown>;
/**
* Stops recording audio.
*
* @returns Returns the path where the recording file is stored.
*
* @example
* ```
* import { stopRecording } from 'tauri-plugin-mic-recorder-api';
*
* const savePath = await stopRecording();
* console.log("Recording saved at:", savePath);
* ```
*/
export declare const stopRecording: () => Promise<string>;

View File

@ -0,0 +1,39 @@
import { invoke } from '@tauri-apps/api/core';
const COMMAND = {
START_RECORDING: "plugin:mic-recorder|start_recording",
STOP_RECORDING: "plugin:mic-recorder|stop_recording",
};
/**
* Starts recording audio.
*
* @example
* ```
* import { startRecording } from 'tauri-plugin-mic-recorder-api';
*
* startRecording().then(() => {
* console.log("Recording started");
* });
* ```
*/
const startRecording = () => {
return invoke(COMMAND.START_RECORDING);
};
/**
* Stops recording audio.
*
* @returns Returns the path where the recording file is stored.
*
* @example
* ```
* import { stopRecording } from 'tauri-plugin-mic-recorder-api';
*
* const savePath = await stopRecording();
* console.log("Recording saved at:", savePath);
* ```
*/
const stopRecording = () => {
return invoke(COMMAND.STOP_RECORDING);
};
export { COMMAND, startRecording, stopRecording };

View File

@ -0,0 +1,48 @@
{
"name": "tauri-plugin-mic-recorder-api",
"version": "2.0.0",
"author": "ayangweb",
"description": "Supports recording audio using a microphone and saving the recorded data as a file.",
"keywords": [
"audio-recording",
"microphone-recording",
"tauri",
"tauri-plugin"
],
"repository": {
"type": "git",
"url": "git+https://github.com/ayangweb/tauri-plugin-mic-recorder.git"
},
"homepage": "https://github.com/ayangweb/tauri-plugin-mic-recorder#readme",
"bugs": "https://github.com/ayangweb/tauri-plugin-mic-recorder/issues",
"license": "MIT",
"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": "rollup -c",
"prepublishOnly": "pnpm build",
"pretest": "pnpm build",
"release": "release-it"
},
"dependencies": {
"@tauri-apps/api": ">=2.0.0-beta.6"
},
"devDependencies": {
"@rollup/plugin-typescript": "^11.1.6",
"release-it": "^18.1.2",
"rollup": "^4.9.6",
"tslib": "^2.6.2",
"typescript": "^5.3.3"
}
}

31
package-lock.json generated Normal file
View File

@ -0,0 +1,31 @@
{
"name": "DevTool-master",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"tauri-plugin-mic-recorder-api": "^2.0.0"
}
},
"node_modules/@tauri-apps/api": {
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.10.1.tgz",
"integrity": "sha512-hKL/jWf293UDSUN09rR69hrToyIXBb8CjGaWC7gfinvnQrBVvnLr08FeFi38gxtugAVyVcTa5/FD/Xnkb1siBw==",
"license": "Apache-2.0 OR MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tauri"
}
},
"node_modules/tauri-plugin-mic-recorder-api": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tauri-plugin-mic-recorder-api/-/tauri-plugin-mic-recorder-api-2.0.0.tgz",
"integrity": "sha512-04wqYCX4WIlYd6KUY7aS3+W4B5RtnSoVczaQCBSXKpQkEx9XdaaBN05XCee2unxGva0btSXBItFqQSdosnS4jQ==",
"license": "MIT",
"dependencies": {
"@tauri-apps/api": ">=2.0.0-beta.6"
}
}
}
}

5
package.json Normal file
View File

@ -0,0 +1,5 @@
{
"dependencies": {
"tauri-plugin-mic-recorder-api": "^2.0.0"
}
}

63
scripts/README.md Normal file
View File

@ -0,0 +1,63 @@
# Scripts (Python-first, cross-platform)
This folder now uses Python as the default runtime for orchestration and diagnostics.
## Preferred scripts
- `diag.py`: tool probing and install-plan generation (`dotnet`, `python`, `node`, `npm`, `cargo`, `tauri`)
- `build.py`: normalized build actions used by SDT workflows
- `dev_shell.py`: cross-platform shell bootstrap export/doctor helper
- `dotnet-min.py`: resilient `dotnet` wrapper with local cache env
- `pip-min.py`: resilient `pip` wrapper with local cache env and repo-local target default
- `npm-clean.py`: remove `node_modules` cross-platform
- `migration-gate.py`: build/test quality gate
- `nuget-export-cache.py`: archive `.nuget` cache
- `nuget-import-cache.py`: restore `.nuget` cache from archive
- `publish-app.py`: build web or tauri app (cross-platform)
- `publish-sidecar.py`: publish sidecar .NET service
- `publish-webgateway.py`: publish gateway .NET service and optional web assets
- `run-webgateway.py`: run gateway in dev or published-output mode
- `publish-output.py`: orchestrate sidecar/web/gateway/desktop publish steps
- `sync-output.py`: sweep newest build artifacts into `output/`
- `script_common.py`: shared helpers (repo root resolution, env shaping, command runner)
- `project.rootHints` supports glob markers (for example `*.sln`) and directory/file markers (`.git`, `package.json`)
- Windows PATH token expansion (`%NVM_HOME%`, `%NVM_SYMLINK%`, etc.) is applied during command resolution
## Shell bootstrap wrappers
- `dev-shell.ps1`: PowerShell wrapper over `dev_shell.py`
- `dev-shell.sh`: bash/zsh wrapper over `dev_shell.py`
- `dev-shell.cmd`: cmd wrapper over `dev_shell.py`
## Legacy scripts
Existing `.ps1` entrypoints are now compatibility wrappers that forward to Python scripts.
`script-common.ps1` is legacy-only compatibility and not used by active SDT workflows.
Original PowerShell implementations are archived under `scripts/legacy/` as `*.legacy.ps1` for reference during transition.
## Root Hint Semantics
`project.rootHints` is evaluated in this order:
1. Exact marker exists at candidate root (file or directory)
2. Root-level glob match (`glob`)
3. Recursive glob match (`rglob`)
Examples:
- `"*.sln"`
- `".git"`
- `"package.json"`
- `"src-tauri/tauri.conf.json"`
## Quick usage
```powershell
python scripts/diag.py probe --tool dotnet --json
python scripts/dotnet-min.py build
python scripts/migration-gate.py
python scripts/nuget-export-cache.py --output-zip nuget-cache-export.zip
python scripts/nuget-import-cache.py --input-zip nuget-cache-export.zip
python scripts/npm-clean.py --working-dir .
python scripts/dev_shell.py export --shell pwsh --json
python scripts/dev_shell.py doctor
```

57
scripts/WORKFLOWS.md Normal file
View File

@ -0,0 +1,57 @@
# Cross-Platform Script Workflows
## 1) Probe toolchain availability
```powershell
python scripts/diag.py probe --tool dotnet --json
python scripts/diag.py probe --tool python --json
python scripts/diag.py probe --tool node --json
python scripts/diag.py probe --tool npm --json
python scripts/diag.py probe --tool cargo --json
python scripts/diag.py probe --tool tauri --json
python scripts/diag.py probe --tool git --json
python scripts/diag.py probe --tool docker --json
```
## Shell bootstrap (cross-platform)
```powershell
python scripts/dev_shell.py export --shell pwsh --json
python scripts/dev_shell.py doctor
```
## 2) Build and run SDT
```powershell
python scripts/dotnet-min.py build
dotnet run --project DevTool.csproj
```
## 3) Run migration gate
```powershell
python scripts/migration-gate.py
```
## 4) Manage NuGet cache
```powershell
python scripts/nuget-export-cache.py --output-zip nuget-cache-export.zip
python scripts/nuget-import-cache.py --input-zip nuget-cache-export.zip
```
## 5) Clean Node modules
```powershell
python scripts/npm-clean.py --working-dir .
```
## 6) Build app/gateway bundles
```powershell
python scripts/publish-app.py --target web
python scripts/publish-sidecar.py --project path/to/sidecar.csproj
python scripts/publish-webgateway.py --project path/to/gateway.csproj --skip-web-assets
python scripts/publish-output.py --dry-run
python scripts/sync-output.py
```

View File

@ -0,0 +1,47 @@
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Test-SdtIsWindows {
if (Get-Variable -Name IsWindows -Scope Global -ErrorAction SilentlyContinue) {
return [bool]$global:IsWindows
}
return $env:OS -eq 'Windows_NT'
}
function Resolve-SdtPython {
$candidates = @('python')
if (Test-SdtIsWindows) { $candidates += 'py' } else { $candidates += 'python3' }
foreach ($c in $candidates) {
try {
& $c --version *> $null
if ($LASTEXITCODE -eq 0) { return $c }
} catch {}
}
return 'python'
}
function Resolve-SdtScriptPath {
param([Parameter(Mandatory=$true)][string]$ScriptName)
$bundled = Join-Path $PSScriptRoot $ScriptName
if (Test-Path $bundled) { return $bundled }
$project = Join-Path (Join-Path $PSScriptRoot '..') ('scripts\\' + $ScriptName)
if (Test-Path $project) { return (Resolve-Path $project).Path }
throw "Python helper script not found: $ScriptName"
}
function Invoke-SdtPythonScript {
param(
[Parameter(Mandatory=$true)][string]$ScriptName,
[string[]]$ForwardArgs = @()
)
$python = Resolve-SdtPython
$scriptPath = Resolve-SdtScriptPath -ScriptName $ScriptName
& $python $scriptPath @ForwardArgs
exit $LASTEXITCODE
}

597
scripts/build.py Normal file
View File

@ -0,0 +1,597 @@
#!/usr/bin/env python3
import argparse
import hashlib
import json
import os
import pathlib
import shutil
import subprocess
import sys
import time
from script_common import resolve_command
def run_step(command, args, cwd):
resolved = resolve_command(command)
if shutil.which(resolved) is None and not pathlib.Path(resolved).exists():
return {
"command": resolved,
"args": args,
"cwd": cwd,
"exit_code": 127,
"elapsed_seconds": 0.0,
"status": "failed",
"failure_reason": f"command_not_found:{resolved}",
}
started = time.time()
proc = subprocess.run([resolved, *args], cwd=cwd, check=False)
elapsed = round(time.time() - started, 3)
return {
"command": resolved,
"args": args,
"cwd": cwd,
"exit_code": proc.returncode,
"elapsed_seconds": elapsed,
"status": "ok" if proc.returncode == 0 else "failed",
"failure_reason": None if proc.returncode == 0 else f"non_zero_exit:{proc.returncode}",
}
def resolve_python_executable():
candidates = ["py", "python"] if os.name == "nt" else ["python3", "python"]
for c in candidates:
if shutil.which(c):
return c
return "python"
def parse_common(parser):
parser.add_argument("--project-root", required=True)
parser.add_argument("--working-dir", default=".")
parser.add_argument("--json", action="store_true")
def resolve_cwd(project_root, working_dir):
return os.path.abspath(os.path.join(project_root, working_dir))
EXCLUDED_SCAN_DIRS = {".git", "node_modules", "bin", "obj", ".venv", "venv", ".sdt", "dist", "build"}
def discover_dotnet_target(project_root: str, cwd: str):
# Prefer local solution first (.slnx, then .sln), then csproj, then bounded scan from project root.
local_slnx = sorted(pathlib.Path(cwd).glob("*.slnx"))
if len(local_slnx) == 1:
return str(local_slnx[0])
local_sln = sorted(pathlib.Path(cwd).glob("*.sln"))
if len(local_sln) == 1:
return str(local_sln[0])
local_csproj = sorted(pathlib.Path(cwd).glob("*.csproj"))
if len(local_csproj) == 1:
return str(local_csproj[0])
slnx_hits = bounded_find_files(project_root, ".slnx", max_depth=4)
if len(slnx_hits) == 1:
return slnx_hits[0]
sln_hits = bounded_find_files(project_root, ".sln", max_depth=4)
if len(sln_hits) == 1:
return sln_hits[0]
csproj_hits = bounded_find_files(project_root, ".csproj", max_depth=4)
if len(csproj_hits) == 1:
return csproj_hits[0]
return None
def bounded_find_files(root: str, extension: str, max_depth: int):
root_path = pathlib.Path(root).resolve()
results = []
for current_root, dirs, files in os.walk(root_path):
rel = pathlib.Path(current_root).resolve().relative_to(root_path)
depth = len(rel.parts)
dirs[:] = [d for d in dirs if d not in EXCLUDED_SCAN_DIRS]
if depth > max_depth:
dirs[:] = []
continue
for name in files:
if name.lower().endswith(extension.lower()):
results.append(str(pathlib.Path(current_root) / name))
return sorted(results)
def run_dotnet_action(project_root, working_dir, verb):
cwd = resolve_cwd(project_root, working_dir)
target = discover_dotnet_target(project_root, cwd)
if not target:
return 0, {
"command": "dotnet",
"args": [verb],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_dotnet_target",
"message": "No .slnx/.sln/.csproj found for this step. Skipping dotnet action.",
}
args = [verb, target]
step = run_step("dotnet", args, cwd)
step["resolved_target"] = target
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def _deps_hash(app_root):
h = hashlib.sha256()
for name in ("package.json", "package-lock.json"):
p = pathlib.Path(app_root) / name
if p.exists():
h.update(p.read_bytes())
return h.hexdigest()
def ensure_npm_dependencies(app_root):
package_json = pathlib.Path(app_root) / "package.json"
if not package_json.exists():
return {"installed": False, "reason": "not_applicable"}
node_modules = pathlib.Path(app_root) / "node_modules"
deps_hash_file = node_modules / ".sdt-deps.sha256"
expected = _deps_hash(app_root)
should_install = not node_modules.exists()
if not should_install:
if not deps_hash_file.exists():
should_install = True
else:
current = deps_hash_file.read_text(encoding="utf-8").strip()
should_install = current != expected
if not should_install:
return {"installed": False, "reason": "deps_unchanged"}
lock_exists = (pathlib.Path(app_root) / "package-lock.json").exists()
install_args = ["ci", "--no-audit", "--fund=false"] if lock_exists else ["install", "--no-audit", "--fund=false"]
install_step = run_step("npm", install_args, app_root)
if install_step["exit_code"] != 0:
if lock_exists and install_args[0] == "ci":
fallback = run_step("npm", ["install", "--no-audit", "--fund=false"], app_root)
if fallback["exit_code"] != 0:
fallback["failure_reason"] = "deps_install_failed_after_ci_fallback"
return {"installed": True, "reason": "install_failed", "step": fallback}
install_step = fallback
else:
return {"installed": True, "reason": "install_failed", "step": install_step}
node_modules.mkdir(parents=True, exist_ok=True)
deps_hash_file.write_text(expected, encoding="utf-8")
return {"installed": True, "reason": "installed", "step": install_step}
def read_package_json(cwd: str):
package_json = pathlib.Path(cwd) / "package.json"
if not package_json.exists():
return None
try:
return json.loads(package_json.read_text(encoding="utf-8"))
except Exception:
return None
def has_npm_script(cwd: str, script_name: str) -> bool:
data = read_package_json(cwd)
if not isinstance(data, dict):
return False
scripts = data.get("scripts")
if not isinstance(scripts, dict):
return False
return script_name in scripts and isinstance(scripts.get(script_name), str)
def action_dotnet_build(args):
return run_dotnet_action(args.project_root, args.working_dir, "build")
def action_dotnet_restore(args):
return run_dotnet_action(args.project_root, args.working_dir, "restore")
def action_dotnet_test(args):
return run_dotnet_action(args.project_root, args.working_dir, "test")
def action_dotnet_publish(args):
return run_dotnet_action(args.project_root, args.working_dir, "publish")
def action_npm_install(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
if not (pathlib.Path(cwd) / "package.json").exists():
return 0, {
"command": "npm",
"args": ["install"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_package_json",
}
step = run_step("npm", ["install"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_npm_ci(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
if not (pathlib.Path(cwd) / "package.json").exists():
return 0, {
"command": "npm",
"args": ["ci"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_package_json",
}
step = run_step("npm", ["ci"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_npm_build(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
if not (pathlib.Path(cwd) / "package.json").exists():
return 0, {
"command": "npm",
"args": ["run", "build"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_package_json",
}
if not has_npm_script(cwd, "build"):
return 0, {
"command": "npm",
"args": ["run", "build"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_missing_build_script",
}
deps = ensure_npm_dependencies(cwd)
if deps.get("reason") == "not_applicable":
return 0, {
"command": "npm",
"args": ["run", "build"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_package_json",
}
if deps.get("reason") == "install_failed":
step = deps["step"]
step["failure_reason"] = "deps_install_failed"
return step["exit_code"], step
step = run_step("npm", ["run", "build"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_npm_test(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
if not (pathlib.Path(cwd) / "package.json").exists():
return 0, {
"command": "npm",
"args": ["test"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_package_json",
}
if not has_npm_script(cwd, "test"):
return 0, {
"command": "npm",
"args": ["test"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_missing_test_script",
}
deps = ensure_npm_dependencies(cwd)
if deps.get("reason") == "not_applicable":
return 0, {
"command": "npm",
"args": ["test"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_package_json",
}
if deps.get("reason") == "install_failed":
step = deps["step"]
step["failure_reason"] = "deps_install_failed"
return step["exit_code"], step
step = run_step("npm", ["test"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_npm_audit(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
if not (pathlib.Path(cwd) / "package.json").exists():
return 0, {
"command": "npm",
"args": ["audit"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_package_json",
}
step = run_step("npm", ["audit"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_python_venv_create(args):
cwd = resolve_cwd(args.project_root, ".")
venv_dir = args.venv_dir or ".venv"
step = run_step(resolve_python_executable(), ["-m", "venv", venv_dir], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_python_pip_install(args):
cwd = resolve_cwd(args.project_root, ".")
req = args.requirements
step = run_step(resolve_python_executable(), ["-m", "pip", "install", "-r", req], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_python_pip_sync(args):
cwd = resolve_cwd(args.project_root, ".")
req = args.requirements
step = run_step(resolve_python_executable(), ["-m", "pip", "install", "-r", req], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_python_pytest(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
step = run_step(resolve_python_executable(), ["-m", "pytest"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_cargo_build(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
if not (pathlib.Path(cwd) / "Cargo.toml").exists():
return 0, {
"command": "cargo",
"args": ["build"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_cargo_toml",
}
step = run_step("cargo", ["build"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_cargo_test(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
if not (pathlib.Path(cwd) / "Cargo.toml").exists():
return 0, {
"command": "cargo",
"args": ["test"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_cargo_toml",
}
step = run_step("cargo", ["test"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_tauri_build(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
tauri_conf = pathlib.Path(cwd) / "src-tauri" / "tauri.conf.json"
if not tauri_conf.exists():
tauri_conf = pathlib.Path(cwd) / "tauri.conf.json"
if not tauri_conf.exists() or not (pathlib.Path(cwd) / "package.json").exists():
return 0, {
"command": "npm",
"args": ["run", "tauri", "build"],
"cwd": cwd,
"exit_code": 0,
"elapsed_seconds": 0.0,
"status": "skipped",
"failure_reason": None,
"skip_reason": "not_applicable_no_tauri_project",
}
deps = ensure_npm_dependencies(cwd)
if deps.get("reason") == "install_failed":
step = deps["step"]
step["failure_reason"] = "deps_install_failed"
return step["exit_code"], step
tauri_args = ["run", "tauri", "build"]
if args.no_bundle:
tauri_args.extend(["--", "--no-bundle"])
step = run_step("npm", tauri_args, cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_git_status(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
step = run_step("git", ["status"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_git_fetch(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
step = run_step("git", ["fetch"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_git_pull(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
step = run_step("git", ["pull"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_git_clean(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
step = run_step("git", ["clean", "-fd"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_docker_build(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
step = run_step("docker", ["build", "."], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_docker_compose_up(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
step = run_step("docker", ["compose", "up", "-d"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def action_docker_compose_down(args):
cwd = resolve_cwd(args.project_root, args.working_dir)
step = run_step("docker", ["compose", "down"], cwd)
return 0 if step["exit_code"] == 0 else step["exit_code"], step
def main():
parser = argparse.ArgumentParser(description="SDT normalized build actions")
sub = parser.add_subparsers(dest="action", required=True)
p0 = sub.add_parser("dotnet-restore")
parse_common(p0)
p1 = sub.add_parser("dotnet-build")
parse_common(p1)
p1b = sub.add_parser("dotnet-test")
parse_common(p1b)
p1c = sub.add_parser("dotnet-publish")
parse_common(p1c)
p2 = sub.add_parser("npm-install")
parse_common(p2)
p2b = sub.add_parser("npm-ci")
parse_common(p2b)
p3 = sub.add_parser("npm-build")
parse_common(p3)
p3b = sub.add_parser("npm-test")
parse_common(p3b)
p3c = sub.add_parser("npm-audit")
parse_common(p3c)
p4 = sub.add_parser("python-venv-create")
parse_common(p4)
p4.add_argument("--venv-dir", default=".venv")
p5 = sub.add_parser("python-pip-install")
parse_common(p5)
p5.add_argument("--requirements", required=True)
p5b = sub.add_parser("python-pip-sync")
parse_common(p5b)
p5b.add_argument("--requirements", required=True)
p5c = sub.add_parser("python-pytest")
parse_common(p5c)
p6 = sub.add_parser("cargo-build")
parse_common(p6)
p6b = sub.add_parser("cargo-test")
parse_common(p6b)
p7 = sub.add_parser("tauri-build")
parse_common(p7)
p7.add_argument("--no-bundle", action="store_true")
p8 = sub.add_parser("git-status")
parse_common(p8)
p9 = sub.add_parser("git-fetch")
parse_common(p9)
p10 = sub.add_parser("git-pull")
parse_common(p10)
p11 = sub.add_parser("git-clean")
parse_common(p11)
p12 = sub.add_parser("docker-build")
parse_common(p12)
p13 = sub.add_parser("docker-compose-up")
parse_common(p13)
p14 = sub.add_parser("docker-compose-down")
parse_common(p14)
args = parser.parse_args()
handlers = {
"dotnet-restore": action_dotnet_restore,
"dotnet-build": action_dotnet_build,
"dotnet-test": action_dotnet_test,
"dotnet-publish": action_dotnet_publish,
"npm-install": action_npm_install,
"npm-ci": action_npm_ci,
"npm-build": action_npm_build,
"npm-test": action_npm_test,
"npm-audit": action_npm_audit,
"python-venv-create": action_python_venv_create,
"python-pip-install": action_python_pip_install,
"python-pip-sync": action_python_pip_sync,
"python-pytest": action_python_pytest,
"cargo-build": action_cargo_build,
"cargo-test": action_cargo_test,
"tauri-build": action_tauri_build,
"git-status": action_git_status,
"git-fetch": action_git_fetch,
"git-pull": action_git_pull,
"git-clean": action_git_clean,
"docker-build": action_docker_build,
"docker-compose-up": action_docker_compose_up,
"docker-compose-down": action_docker_compose_down,
}
code, summary = handlers[args.action](args)
if args.json:
print(json.dumps(summary))
return code
if __name__ == "__main__":
sys.exit(main())

17
scripts/dev-shell.cmd Normal file
View File

@ -0,0 +1,17 @@
@echo off
set "SCRIPT_DIR=%~dp0"
where py >nul 2>nul
if %ERRORLEVEL%==0 (
set "PYEXE=py"
) else (
where python >nul 2>nul
if not %ERRORLEVEL%==0 (
echo python not found.
exit /b 1
)
set "PYEXE=python"
)
for /f "usebackq delims=" %%L in (`"%PYEXE%" "%SCRIPT_DIR%dev_shell.py" export --shell cmd`) do %%L
echo Development shell initialized from Python bootstrap script.

21
scripts/dev-shell.ps1 Normal file
View File

@ -0,0 +1,21 @@
# Run this in PowerShell before development commands:
# . ./scripts/dev-shell.ps1
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
. (Join-Path $PSScriptRoot '_pwsh-python-shim.ps1')
$scriptPath = Resolve-SdtScriptPath -ScriptName 'dev_shell.py'
$python = Resolve-SdtPython
$lines = & $python $scriptPath export --shell pwsh
if ($LASTEXITCODE -ne 0) {
throw "Failed to initialize development shell via dev_shell.py"
}
foreach ($line in $lines) {
Invoke-Expression $line
}
Write-Host "Development shell initialized from Python bootstrap script."

16
scripts/dev-shell.sh Normal file
View File

@ -0,0 +1,16 @@
#!/usr/bin/env sh
set -eu
SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
if command -v python3 >/dev/null 2>&1; then
PYTHON_EXE="python3"
elif command -v python >/dev/null 2>&1; then
PYTHON_EXE="python"
else
echo "python3/python not found." >&2
exit 1
fi
eval "$("$PYTHON_EXE" "$SCRIPT_DIR/dev_shell.py" export --shell bash)"
echo "Development shell initialized from Python bootstrap script."

148
scripts/dev_shell.py Normal file
View File

@ -0,0 +1,148 @@
#!/usr/bin/env python3
import argparse
import json
import pathlib
import sys
from script_common import PROXY_VARS, clean_proxy_env, dotnet_env, ensure_dirs, pip_env, resolve_repo_root
def huggingface_env(repo_root: pathlib.Path) -> dict[str, str]:
env = {}
hf_home = repo_root / ".cache" / "huggingface"
hf_hub_cache = hf_home / "hub"
ensure_dirs([hf_hub_cache])
env["HF_HOME"] = str(hf_home)
env["HUGGINGFACE_HUB_CACHE"] = str(hf_hub_cache)
env["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1"
return env
def resolved_env(repo_root: pathlib.Path) -> dict[str, str]:
env = {}
dotnet = dotnet_env(repo_root)
pip = pip_env(repo_root)
hf = huggingface_env(repo_root)
dotnet_keys = [
"DOTNET_CLI_HOME",
"NUGET_PACKAGES",
"NUGET_HTTP_CACHE_PATH",
"DOTNET_SKIP_FIRST_TIME_EXPERIENCE",
"DOTNET_ADD_GLOBAL_TOOLS_TO_PATH",
"DOTNET_GENERATE_ASPNET_CERTIFICATE",
"DOTNET_CLI_TELEMETRY_OPTOUT",
"NUGET_CERT_REVOCATION_MODE",
]
pip_keys = [
"PIP_CACHE_DIR",
"PIP_DISABLE_PIP_VERSION_CHECK",
"PIP_DEFAULT_TIMEOUT",
"PIP_RETRIES",
"TEMP",
"TMP",
]
for key in dotnet_keys:
env[key] = dotnet[key]
for key in pip_keys:
env[key] = pip[key]
env.update(hf)
clean_proxy_env(env)
return env
def export_lines(shell: str, env_map: dict[str, str]) -> list[str]:
def sh_quote(value: str) -> str:
return "'" + value.replace("'", "'\"'\"'") + "'"
if shell == "pwsh":
lines = [f"Remove-Item Env:{k} -ErrorAction SilentlyContinue" for k in PROXY_VARS]
lines.extend(f"$env:{k} = \"{v.replace('\"', '`\"')}\"" for k, v in env_map.items())
return lines
if shell in ("bash", "zsh"):
lines = [f"unset {k}" for k in PROXY_VARS]
lines.extend(f"export {k}={sh_quote(v)}" for k, v in env_map.items())
return lines
if shell == "cmd":
lines = [f"set {k}=" for k in PROXY_VARS]
lines.extend(f"set {k}={v}" for k, v in env_map.items())
return lines
raise ValueError(shell)
def cmd_export(args):
try:
repo_root = resolve_repo_root(args.project_root)
except Exception as ex:
print(f"Failed to resolve project root: {ex}", file=sys.stderr)
return 2
env_map = resolved_env(repo_root)
payload = {
"projectRoot": str(repo_root),
"env": env_map,
"createdDirs": [
str(repo_root / ".dotnet_home"),
str(repo_root / ".nuget" / "packages"),
str(repo_root / ".nuget" / "http-cache"),
str(repo_root / ".pip" / "cache"),
str(repo_root / ".tmp" / "pip-temp"),
str(repo_root / ".cache" / "huggingface" / "hub"),
],
"warnings": [],
}
try:
lines = export_lines(args.shell, env_map)
except ValueError:
print(f"Unsupported shell target: {args.shell}", file=sys.stderr)
return 3
if args.json:
print(json.dumps(payload))
else:
for line in lines:
print(line)
return 0
def cmd_doctor(args):
try:
repo_root = resolve_repo_root(args.project_root)
except Exception as ex:
print(f"Failed to resolve project root: {ex}", file=sys.stderr)
return 2
env_map = resolved_env(repo_root)
checks = {
"repo_root": str(repo_root),
"dotnet_home_exists": (repo_root / ".dotnet_home").exists(),
"nuget_cache_exists": (repo_root / ".nuget" / "packages").exists(),
"pip_cache_exists": (repo_root / ".pip" / "cache").exists(),
"hf_cache_exists": (repo_root / ".cache" / "huggingface" / "hub").exists(),
"env_count": len(env_map),
}
print(json.dumps(checks))
return 0
def main():
parser = argparse.ArgumentParser(description="SDT cross-platform shell bootstrap helper")
sub = parser.add_subparsers(dest="command", required=True)
p_export = sub.add_parser("export", help="Print env exports for a shell")
p_export.add_argument("--shell", required=True)
p_export.add_argument("--project-root")
p_export.add_argument("--json", action="store_true")
p_doctor = sub.add_parser("doctor", help="Validate env bootstrap paths")
p_doctor.add_argument("--project-root")
args = parser.parse_args()
if args.command == "export":
return cmd_export(args)
return cmd_doctor(args)
if __name__ == "__main__":
sys.exit(main())

128
scripts/diag.py Normal file
View File

@ -0,0 +1,128 @@
#!/usr/bin/env python3
import argparse
import json
import os
import platform
import shutil
import subprocess
import sys
from script_common import resolve_command
def run_capture(cmd):
try:
proc = subprocess.run(cmd, capture_output=True, text=True, check=False)
out = (proc.stdout or "").strip()
err = (proc.stderr or "").strip()
text = out if out else err
return proc.returncode == 0, text
except Exception as ex:
return False, str(ex)
def probe_tool(tool):
mapping = {
"dotnet": ["dotnet", "--version"],
"node": ["node", "--version"],
"npm": ["npm", "--version"],
"python": ["python", "--version"],
"cargo": ["cargo", "--version"],
"tauri": ["tauri", "--version"],
"git": ["git", "--version"],
"docker": ["docker", "--version"],
}
cmd = mapping.get(tool, [tool, "--version"])
resolved = resolve_command(cmd[0])
if shutil.which(resolved) is None and not os.path.exists(resolved):
return {"tool": tool, "available": False, "version": None, "details": f"{cmd[0]} not found in PATH"}
cmd = [resolved, *cmd[1:]]
ok, text = run_capture(cmd)
return {"tool": tool, "available": ok, "version": text if ok else None, "details": None if ok else text}
def install_plan(tool):
is_windows = platform.system().lower().startswith("win")
if is_windows:
plans = {
"dotnet": [("winget", ["install", "Microsoft.DotNet.SDK.10"])],
"node": [("winget", ["install", "OpenJS.NodeJS.LTS"])],
"npm": [("winget", ["install", "OpenJS.NodeJS.LTS"])],
"python": [("winget", ["install", "Python.Python.3.12"])],
"cargo": [("winget", ["install", "Rustlang.Rustup"])],
"tauri": [("npm", ["install", "-g", "@tauri-apps/cli"])],
"git": [("winget", ["install", "Git.Git"])],
"docker": [("winget", ["install", "Docker.DockerDesktop"])],
}
else:
plans = {
"dotnet": [("sh", ["-c", "echo install dotnet sdk with your package manager"])],
"node": [("sh", ["-c", "echo install nodejs with your package manager"])],
"npm": [("sh", ["-c", "echo install npm with your package manager"])],
"python": [("sh", ["-c", "echo install python3 with your package manager"])],
"cargo": [("sh", ["-c", "curl https://sh.rustup.rs -sSf | sh"])],
"tauri": [("npm", ["install", "-g", "@tauri-apps/cli"])],
"git": [("sh", ["-c", "echo install git with your package manager"])],
"docker": [("sh", ["-c", "echo install docker with your package manager"])],
}
cmds = plans.get(tool, [])
return {
"tool": tool,
"supported": len(cmds) > 0,
"summary": f"Install plan for {tool} on {platform.system()}",
"commands": [{"command": c, "args": a} for c, a in cmds],
}
def run_install(tool):
plan = install_plan(tool)
if not plan["supported"]:
return 2
for cmd in plan["commands"]:
proc = subprocess.run([cmd["command"], *cmd["args"]], check=False)
if proc.returncode != 0:
return proc.returncode
return 0
def main():
parser = argparse.ArgumentParser(description="SDT diagnostics and install planner")
sub = parser.add_subparsers(dest="cmd", required=True)
p_probe = sub.add_parser("probe")
p_probe.add_argument("--tool", required=True)
p_probe.add_argument("--json", action="store_true")
p_plan = sub.add_parser("install-plan")
p_plan.add_argument("--tool", required=True)
p_plan.add_argument("--json", action="store_true")
p_run = sub.add_parser("install-run")
p_run.add_argument("--tool", required=True)
args = parser.parse_args()
if args.cmd == "probe":
result = probe_tool(args.tool.lower())
if args.json:
print(json.dumps(result))
else:
print(result)
return 0 if result["available"] else 1
if args.cmd == "install-plan":
result = install_plan(args.tool.lower())
if args.json:
print(json.dumps(result))
else:
print(result)
return 0 if result["supported"] else 2
if args.cmd == "install-run":
return run_install(args.tool.lower())
return 1
if __name__ == "__main__":
sys.exit(main())

34
scripts/dotnet-min.py Normal file
View File

@ -0,0 +1,34 @@
#!/usr/bin/env python3
import argparse
import sys
from script_common import dotnet_env, resolve_repo_root, run
DOTNET_SAFE_CMDS = {"restore", "build", "run", "test", "publish", "pack"}
def main() -> int:
parser = argparse.ArgumentParser(description="Cross-platform minimal dotnet wrapper")
parser.add_argument("dotnet_args", nargs=argparse.REMAINDER)
parser.add_argument("--repo-root", default=None)
args = parser.parse_args()
if not args.dotnet_args:
print("Usage: python scripts/dotnet-min.py <dotnet args>", file=sys.stderr)
return 2
repo_root = resolve_repo_root(args.repo_root)
dotnet_args = list(args.dotnet_args)
cmd = dotnet_args[0].lower()
if cmd in DOTNET_SAFE_CMDS:
dotnet_args.extend(["-p:RestoreIgnoreFailedSources=true", "-p:NuGetAudit=false"])
if cmd == "restore":
dotnet_args.append("--ignore-failed-sources")
return run("dotnet", dotnet_args, repo_root, env=dotnet_env(repo_root))
if __name__ == "__main__":
raise SystemExit(main())

View File

@ -0,0 +1,62 @@
param(
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$DotnetArgs
)
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path
# Keep dotnet and NuGet artifacts local to the repo for easy cleanup.
$env:DOTNET_CLI_HOME = Join-Path $repoRoot ".dotnet_home"
$env:NUGET_PACKAGES = Join-Path $repoRoot ".nuget\packages"
$env:NUGET_HTTP_CACHE_PATH = Join-Path $repoRoot ".nuget\http-cache"
# Keep setup minimal and non-interactive.
$env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = "1"
$env:DOTNET_ADD_GLOBAL_TOOLS_TO_PATH = "0"
$env:DOTNET_GENERATE_ASPNET_CERTIFICATE = "0"
$env:DOTNET_CLI_TELEMETRY_OPTOUT = "1"
# Clear proxy env vars for this process. The host machine currently points them
# to 127.0.0.1:9, which breaks NuGet restore.
Remove-Item Env:HTTP_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:HTTPS_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:ALL_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:http_proxy -ErrorAction SilentlyContinue
Remove-Item Env:https_proxy -ErrorAction SilentlyContinue
Remove-Item Env:all_proxy -ErrorAction SilentlyContinue
Remove-Item Env:GIT_HTTP_PROXY -ErrorAction SilentlyContinue
Remove-Item Env:GIT_HTTPS_PROXY -ErrorAction SilentlyContinue
# Prefer offline cert revocation checks to reduce flaky TLS behavior on constrained hosts.
$env:NUGET_CERT_REVOCATION_MODE = "offline"
New-Item -ItemType Directory -Force -Path $env:DOTNET_CLI_HOME | Out-Null
New-Item -ItemType Directory -Force -Path $env:NUGET_PACKAGES | Out-Null
New-Item -ItemType Directory -Force -Path $env:NUGET_HTTP_CACHE_PATH | Out-Null
if (-not $DotnetArgs -or $DotnetArgs.Count -eq 0) {
Write-Host "Usage: ./scripts/dotnet-min.ps1 <dotnet args>"
Write-Host "Example: ./scripts/dotnet-min.ps1 build Journal.Sidecar/Journal.Sidecar.csproj"
exit 2
}
$firstArg = $DotnetArgs[0].ToLowerInvariant()
$effectiveArgs = @($DotnetArgs)
if ($firstArg -in @("restore", "build", "run", "test", "publish", "pack")) {
if (-not ($effectiveArgs -contains "-p:RestoreIgnoreFailedSources=true")) {
$effectiveArgs += "-p:RestoreIgnoreFailedSources=true"
}
if (-not ($effectiveArgs -contains "-p:NuGetAudit=false")) {
$effectiveArgs += "-p:NuGetAudit=false"
}
}
if ($firstArg -eq "restore") {
if (-not ($effectiveArgs -contains "--ignore-failed-sources")) {
$effectiveArgs += "--ignore-failed-sources"
}
}
& dotnet @effectiveArgs
exit $LASTEXITCODE

Some files were not shown because too many files have changed in this diff Show More