diff --git a/.github/actions/download-native-binaries/action.yml b/.github/actions/download-native-binaries/action.yml
new file mode 100644
index 00000000..e6935f11
--- /dev/null
+++ b/.github/actions/download-native-binaries/action.yml
@@ -0,0 +1,123 @@
+name: Download Native Binaries
+description: Download, normalize, and verify native build artifacts for testing or release workflows
+
+inputs:
+ artifact-type:
+ description: Artifact naming mode
+ required: true
+ default: testing
+ target-root:
+ description: Root path where normalized native artifacts should be written
+ required: false
+ default: ""
+
+runs:
+ using: composite
+ steps:
+ - name: Resolve Native Artifact Settings
+ id: resolve-native-artifact-settings
+ shell: bash
+ run: |
+ set -euo pipefail
+
+ artifact_type="${{ inputs.artifact-type }}"
+ input_root="${{ inputs.target-root }}"
+
+ case "$artifact_type" in
+ testing)
+ pattern="native-testing-*"
+ ;;
+ release)
+ pattern="native-*"
+ ;;
+ *)
+ echo "Unsupported artifact-type: $artifact_type"
+ exit 1
+ ;;
+ esac
+
+ if [ -n "$input_root" ]; then
+ root="$input_root"
+ elif [ "$artifact_type" = "testing" ]; then
+ root="src/InfiniFrame.NativeBridge/artifacts/native"
+ else
+ root="artifacts/native"
+ fi
+
+ echo "pattern=$pattern" >> "$GITHUB_OUTPUT"
+ echo "root=$root" >> "$GITHUB_OUTPUT"
+
+ - name: Download Native Build Artifacts
+ uses: actions/download-artifact@v8
+ with:
+ path: artifacts/native
+ pattern: ${{ steps.resolve-native-artifact-settings.outputs.pattern }}
+
+ - name: Normalize Native Artifacts
+ shell: bash
+ run: |
+ set -euo pipefail
+
+ ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}"
+ artifact_type="${{ inputs.artifact-type }}"
+
+ mkdir -p "$ROOT/windows/x64/Release" "$ROOT/windows/arm64/Release"
+ mkdir -p "$ROOT/linux/x64/Release" "$ROOT/linux/arm64/Release"
+ mkdir -p "$ROOT/osx/x64/Release" "$ROOT/osx/arm64/Release"
+
+ copy_artifact() {
+ src_name="$1"
+ dest_dir="$2"
+ src="artifacts/native/$src_name"
+ if [ -d "$src" ]; then
+ cp -R "$src"/. "$dest_dir"/
+ fi
+ }
+
+ if [ "$artifact_type" = "testing" ]; then
+ copy_artifact "native-testing-windows-x64" "$ROOT/windows/x64/Release"
+ copy_artifact "native-testing-windows-arm64" "$ROOT/windows/arm64/Release"
+ copy_artifact "native-testing-linux-x64" "$ROOT/linux/x64/Release"
+ copy_artifact "native-testing-linux-arm64" "$ROOT/linux/arm64/Release"
+ copy_artifact "native-testing-osx-x64" "$ROOT/osx/x64/Release"
+ copy_artifact "native-testing-osx-arm64" "$ROOT/osx/arm64/Release"
+ else
+ copy_artifact "native-windows-x64" "$ROOT/windows/x64/Release"
+ copy_artifact "native-windows-arm64" "$ROOT/windows/arm64/Release"
+ copy_artifact "native-linux-x64" "$ROOT/linux/x64/Release"
+ copy_artifact "native-linux-arm64" "$ROOT/linux/arm64/Release"
+ copy_artifact "native-osx-x64" "$ROOT/osx/x64/Release"
+ copy_artifact "native-osx-arm64" "$ROOT/osx/arm64/Release"
+ fi
+
+ - name: Verify Native Artifacts
+ shell: bash
+ run: |
+ set -euo pipefail
+
+ ROOT="${{ steps.resolve-native-artifact-settings.outputs.root }}"
+ EXPECTED=(
+ "$ROOT/windows/x64/Release/InfiniFrame.Native.dll"
+ "$ROOT/windows/x64/Release/WebView2Loader.dll"
+ "$ROOT/windows/arm64/Release/InfiniFrame.Native.dll"
+ "$ROOT/windows/arm64/Release/WebView2Loader.dll"
+ "$ROOT/linux/x64/Release/InfiniFrame.Native.so"
+ "$ROOT/linux/arm64/Release/InfiniFrame.Native.so"
+ "$ROOT/osx/x64/Release/InfiniFrame.Native.dylib"
+ "$ROOT/osx/arm64/Release/InfiniFrame.Native.dylib"
+ )
+
+ missing=0
+ for file in "${EXPECTED[@]}"; do
+ if [ ! -f "$file" ]; then
+ echo "Missing native artifact: $file"
+ missing=$((missing+1))
+ fi
+ done
+
+ if [ "$missing" -gt 0 ]; then
+ echo "Missing $missing native artifact(s)."
+ exit 1
+ fi
+
+ echo "All native artifacts downloaded and verified."
diff --git a/.github/actions/setup-dependencies-native/action.yml b/.github/actions/setup-dependencies-native/action.yml
index 8d1b680c..ead308bc 100644
--- a/.github/actions/setup-dependencies-native/action.yml
+++ b/.github/actions/setup-dependencies-native/action.yml
@@ -2,10 +2,6 @@ name: Setup Native Dependencies
description: Install and cache Native related dependencies for Linux/macOS runners.
inputs:
- apt-cache-version:
- description: Version token for apt package cache invalidation
- required: false
- default: "1.0"
brew-cache-key:
description: Full Homebrew cache key for macOS runners
required: false
@@ -29,31 +25,52 @@ runs:
uses: awalsh128/cache-apt-pkgs-action@latest
with:
packages: >
- pkg-config
- xvfb
- openbox
- x11-utils
- x11-xserver-utils
- dbus-x11
at-spi2-core
+ dbus-x11
+ fonts-liberation
gsettings-desktop-schemas
- libnotify4
- libnotify-dev
- libwebkit2gtk-4.1-dev
- libgtk-3-dev
- libglib2.0-dev
- libgdk-pixbuf2.0-dev
- libpango1.0-dev
libatk1.0-dev
- libharfbuzz-dev
+ libegl1
libepoxy-dev
- libx11-dev
+ libgdk-pixbuf2.0-dev
libgl1-mesa-dri
- libegl1
+ libglib2.0-dev
+ libgtk-3-dev
+ libharfbuzz-dev
+ libnotify-dev
+ libnotify4
+ libpango1.0-dev
+ libwebkit2gtk-4.1-dev
+ libx11-dev
mesa-utils
- fonts-liberation
+ openbox
+ pkg-config
+ x11-utils
+ x11-xserver-utils
xfonts-base
- version: ${{ inputs['apt-cache-version'] }}
+ xvfb
+ version: 2.0
+
+ - name: Verify GTK3 Deps (Linux)
+ if: runner.os == 'Linux'
+ shell: bash
+ run: |
+ set -euo pipefail
+
+ if pkg-config --exists gtk+-3.0; then
+ echo "gtk+-3.0 detected via pkg-config."
+ exit 0
+ fi
+
+ echo "gtk+-3.0 not found after cached apt step; running fallback apt install."
+ sudo apt-get update
+ sudo apt-get install -y --no-install-recommends \
+ libgtk-3-dev \
+ libwebkit2gtk-4.1-dev \
+ pkg-config
+
+ pkg-config --exists gtk+-3.0
+ echo "gtk+-3.0 is now available."
- name: Cache Homebrew
if: runner.os == 'macOS'
@@ -69,9 +86,13 @@ runs:
restore-keys: |
${{ inputs['brew-restore-key'] }}
- - name: Install GTK3 (macOS)
+ - name: Install GTK3 and PowerShell (macOS)
if: runner.os == 'macOS'
shell: bash
run: |
brew list gtk+3 >/dev/null 2>&1 || brew install gtk+3
brew list pkg-config >/dev/null 2>&1 || brew install pkg-config
+
+ if ! command -v pwsh >/dev/null 2>&1; then
+ brew list --cask powershell >/dev/null 2>&1 || brew install --cask powershell
+ fi
diff --git a/.github/actions/setup-dependencies/action.yml b/.github/actions/setup-dependencies/action.yml
new file mode 100644
index 00000000..d8af95b9
--- /dev/null
+++ b/.github/actions/setup-dependencies/action.yml
@@ -0,0 +1,38 @@
+name: Setup Dependencies
+description: Install and cache related dependencies.
+
+inputs:
+ cache-dotnet:
+ description: Whether to cache .NET dependencies
+ required: false
+ default: true
+
+runs:
+ using: composite
+ steps:
+ - name: Setup Node
+ uses: actions/setup-node@v6
+ with:
+ node-version: 24
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ **/package-lock.json
+
+ - name: Setup Python
+ uses: actions/setup-python@v6
+ with:
+ python-version: '3.x'
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: |
+ 8.x
+ 9.x
+ 10.x
+ cache: ${{ inputs['cache-dotnet'] }}
+ cache-dependency-path: |
+ **/*.csproj
+ **/*.props
+ **/Directory.Packages.props
\ No newline at end of file
diff --git a/.github/actions/sync-check/action.yml b/.github/actions/sync-check/action.yml
index 615599a2..68a9f7b7 100644
--- a/.github/actions/sync-check/action.yml
+++ b/.github/actions/sync-check/action.yml
@@ -52,7 +52,13 @@ inputs:
runs:
using: composite
steps:
+ - name: Skip status/check sync in local mode
+ if: ${{ env.LOCAL_GHA_SKIP_STATUS == '1' }}
+ shell: bash
+ run: echo "LOCAL_GHA_SKIP_STATUS=1, skipping GitHub status/check sync."
+
- name: Sync status/check
+ if: ${{ env.LOCAL_GHA_SKIP_STATUS != '1' }}
shell: pwsh
run: |
$argsList = @(
diff --git a/.github/actions/validate-native-test-binaries/action.yml b/.github/actions/validate-native-test-binaries/action.yml
deleted file mode 100644
index bf3474d8..00000000
--- a/.github/actions/validate-native-test-binaries/action.yml
+++ /dev/null
@@ -1,84 +0,0 @@
-name: Validate Native Test Binaries
-description: Resolve test project target framework(s) and verify expected native binaries exist for the current runner OS.
-
-inputs:
- project-path:
- description: Path to the test project file used to resolve TargetFramework(s)
- required: false
- default: tests/InfiniFrameTests/InfiniFrameTests.csproj
- configuration:
- description: Build configuration used in output paths
- required: false
- default: Release
- output-root:
- description: Root output path before configuration/framework segments
- required: false
- default: tests/InfiniFrameTests/bin
- frameworks:
- description: Optional semicolon-separated target frameworks to validate (for single-target CI jobs)
- required: false
- default: ""
- include-webview2-windows:
- description: Validate WebView2Loader.dll on Windows
- required: false
- default: "true"
-
-runs:
- using: composite
- steps:
- - name: Validate native binaries
- shell: pwsh
- run: |
- $projectPath = "${{ inputs['project-path'] }}"
- $configuration = "${{ inputs['configuration'] }}"
- $outputRoot = "${{ inputs['output-root'] }}"
- $frameworksInput = "${{ inputs['frameworks'] }}"
- $includeWebView2 = "${{ inputs['include-webview2-windows'] }}" -eq "true"
-
- if (-not [string]::IsNullOrWhiteSpace($frameworksInput)) {
- $targetFrameworks = $frameworksInput
- } else {
- $targetFrameworks = (dotnet msbuild $projectPath -nologo -getProperty:TargetFrameworks).Trim()
- if ([string]::IsNullOrWhiteSpace($targetFrameworks)) {
- $targetFrameworks = (dotnet msbuild $projectPath -nologo -getProperty:TargetFramework).Trim()
- }
- }
-
- if ([string]::IsNullOrWhiteSpace($targetFrameworks)) {
- throw "Unable to resolve TargetFramework(s) for '$projectPath'."
- }
-
- $frameworks = $targetFrameworks -split ";" | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" }
- if ($frameworks.Count -eq 0) {
- throw "No valid framework values were resolved from '$projectPath'."
- }
-
- $requiredFiles = switch ($env:RUNNER_OS) {
- "Windows" {
- $files = @("InfiniFrame.Native.dll")
- if ($includeWebView2) { $files += "WebView2Loader.dll" }
- $files
- }
- "Linux" { @("InfiniFrame.Native.so") }
- "macOS" { @("InfiniFrame.Native.dylib") }
- default { throw "Unsupported RUNNER_OS '$env:RUNNER_OS'." }
- }
-
- $missing = @()
- foreach ($framework in $frameworks) {
- $frameworkDir = Join-Path $outputRoot "$configuration/$framework"
- foreach ($file in $requiredFiles) {
- $path = Join-Path $frameworkDir $file
- if (-not (Test-Path $path)) {
- $missing += $path
- }
- }
- }
-
- if ($missing.Count -gt 0) {
- Write-Host "Missing native binaries:"
- $missing | ForEach-Object { Write-Host " - $_" }
- throw "Native binary validation failed."
- }
-
- Write-Host "Native binaries validated for frameworks: $($frameworks -join ', ')"
diff --git a/.github/scripts/sync_github_checks.py b/.github/scripts/sync_github_checks.py
index b043cee0..b23529c7 100644
--- a/.github/scripts/sync_github_checks.py
+++ b/.github/scripts/sync_github_checks.py
@@ -190,6 +190,7 @@ def complete_matching_check_runs(args: Args, token: str) -> bool:
for run in check_runs
if run.get("name") == args.context
and run.get("status") in ("queued", "in_progress")
+ and run.get("details_url") == args.target_url
and isinstance(run.get("id"), int)
]
diff --git a/.github/scripts/test_sync_github_checks.py b/.github/scripts/test_sync_github_checks.py
index 94c0d9bc..2f61d4af 100644
--- a/.github/scripts/test_sync_github_checks.py
+++ b/.github/scripts/test_sync_github_checks.py
@@ -58,6 +58,27 @@ def test_complete_matching_check_runs_returns_false_when_no_matches(monkeypatch:
assert sgc.complete_matching_check_runs(make_args(), "token") is False
+def test_complete_matching_check_runs_ignores_other_target_urls(monkeypatch: pytest.MonkeyPatch) -> None:
+ monkeypatch.setattr(
+ sgc,
+ "request_json",
+ lambda method, url, token, payload=None: (
+ 200,
+ {
+ "check_runs": [
+ {
+ "id": 99,
+ "name": "CI Testing - Linux/x64",
+ "status": "queued",
+ "details_url": "https://example.invalid/run/other",
+ }
+ ]
+ },
+ ),
+ )
+ assert sgc.complete_matching_check_runs(make_args(), "token") is False
+
+
def test_complete_matching_check_runs_creates_when_no_matches_and_enabled(
monkeypatch: pytest.MonkeyPatch,
) -> None:
@@ -102,8 +123,24 @@ def fake_request(
{
"check_runs": [
{"id": 3, "name": "Other", "status": "queued"},
- {"id": 2, "name": "CI Testing - Linux/x64", "status": "in_progress"},
- {"id": 1, "name": "CI Testing - Linux/x64", "status": "queued"},
+ {
+ "id": 2,
+ "name": "CI Testing - Linux/x64",
+ "status": "in_progress",
+ "details_url": "https://example.invalid/run/1",
+ },
+ {
+ "id": 1,
+ "name": "CI Testing - Linux/x64",
+ "status": "queued",
+ "details_url": "https://example.invalid/run/1",
+ },
+ {
+ "id": 6,
+ "name": "CI Testing - Linux/x64",
+ "status": "queued",
+ "details_url": "https://example.invalid/run/2",
+ },
{"id": 4, "name": "CI Testing - Linux/x64", "status": "completed"},
]
},
diff --git a/.github/workflows/ci-codeql.yml b/.github/workflows/ci-codeql.yml
index 0dba4b09..ff402c48 100644
--- a/.github/workflows/ci-codeql.yml
+++ b/.github/workflows/ci-codeql.yml
@@ -7,7 +7,7 @@ concurrency:
on:
push:
branches: [ "core" ]
-
+
pull_request:
branches: [ "core" ]
types: [ opened, synchronize, reopened, ready_for_review ]
@@ -16,7 +16,7 @@ on:
- 'docs/**'
- '.github/ISSUE_TEMPLATE/**'
- '.github/*.md'
-
+
workflow_dispatch:
inputs:
full_scan:
@@ -32,15 +32,17 @@ jobs:
changes:
name: Detect Changed Areas
runs-on: ubuntu-latest
- if: github.event_name != 'workflow_dispatch' || github.event.inputs.full_scan != 'true'
+
permissions:
contents: read
+
outputs:
actions: ${{ steps.filter.outputs.actions }}
csharp: ${{ steps.filter.outputs.csharp }}
cpp: ${{ steps.filter.outputs.cpp }}
javascript_typescript: ${{ steps.filter.outputs.javascript_typescript }}
python: ${{ steps.filter.outputs.python }}
+
steps:
- name: Checkout
uses: actions/checkout@v6
@@ -57,6 +59,7 @@ jobs:
- '.github/actions/**'
- '.github/dependabot.yml'
- '.github/codeql-config.yml'
+
csharp:
- 'src/**/*.cs'
- 'src/**/*.csproj'
@@ -66,6 +69,9 @@ jobs:
- 'src/**/*.razor.css'
- 'Directory.Packages.props'
- 'global.json'
+ - '.github/workflows/ci-codeql.yml'
+ - '.github/codeql-config.yml'
+
cpp:
- 'src/InfiniFrame.Native/**'
- 'native-vendor-deps.json'
@@ -73,6 +79,7 @@ jobs:
- '.github/actions/setup-dependencies-native/**'
- '.github/workflows/ci-codeql.yml'
- '.github/codeql-config.yml'
+
javascript_typescript:
- 'src/**/*.js'
- 'src/**/*.jsx'
@@ -88,10 +95,9 @@ jobs:
- 'src/**/vite.config.*'
- 'src/**/webpack.config.*'
- 'src/**/eslint.config.*'
- - '.github/actions/**/*.js'
- - '.github/actions/**/*.ts'
- '.github/workflows/ci-codeql.yml'
- '.github/codeql-config.yml'
+
python:
- '.github/scripts/**/*.py'
- '.github/scripts/**/*.pyi'
@@ -111,22 +117,60 @@ jobs:
- 'scripts/**/setup.cfg'
- '.github/workflows/ci-codeql.yml'
- '.github/codeql-config.yml'
-
- analyze:
- name: Analyze (${{ matrix.language }} on ${{ matrix.os }})
+
+ analyze-actions:
+ name: Analyze Actions
needs: changes
- runs-on: ${{ matrix.os }}
- timeout-minutes: 90
-
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
if: >
- always() && (
- needs.changes.result == 'success' ||
- (github.event_name == 'workflow_dispatch' && github.event.inputs.full_scan == 'true')
- ) && (
- github.event_name != 'pull_request' ||
- github.event.pull_request.draft == false
+ (
+ github.event_name == 'workflow_dispatch' &&
+ github.event.inputs.full_scan == 'true'
+ ) || (
+ needs.changes.outputs.actions == 'true'
)
+
+ permissions:
+ contents: read
+ security-events: write
+ actions: read
+ packages: read
+ pull-requests: write
+ checks: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v4
+ with:
+ languages: actions
+ build-mode: none
+ queries: security-extended,security-and-quality
+ config-file: ./.github/codeql-config.yml
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v4
+ with:
+ category: "/language:actions"
+
+ analyze-csharp:
+ name: Analyze C#
+ needs: changes
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+
+ if: >
+ (
+ github.event_name == 'workflow_dispatch' &&
+ github.event.inputs.full_scan == 'true'
+ ) || (
+ needs.changes.outputs.csharp == 'true'
+ )
+
permissions:
contents: read
security-events: write
@@ -134,114 +178,192 @@ jobs:
packages: read
pull-requests: write
checks: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
+ with:
+ cache-dotnet: false
+
+ - name: Setup Native Dependencies
+ uses: ./.github/actions/setup-dependencies-native
+ with:
+ brew-cache-key: ${{ runner.os }}-brew-codeql-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-macos.yml') }}
+ brew-restore-key: ${{ runner.os }}-brew-codeql-
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v4
+ with:
+ languages: csharp
+ build-mode: manual
+ queries: security-extended,security-and-quality
+ config-file: ./.github/codeql-config.yml
+
+ - name: Restore Dotnet
+ run: |
+ dotnet restore
+
+ - name: Build Dotnet
+ shell: pwsh
+ run: |
+ dotnet build InfiniFrame.GitHubActions.Release.slnf `
+ --configuration Release `
+ --no-restore `
+ /p:SolutionDir=$env:GITHUB_WORKSPACE/
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v4
+ with:
+ category: "/language:csharp"
+
+ analyze-cpp:
+ name: Analyze C/C++ (${{ matrix.os }})
+ needs: changes
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 90
+
+ if: >
+ (
+ github.event_name == 'workflow_dispatch' &&
+ github.event.inputs.full_scan == 'true'
+ ) || (
+ needs.changes.outputs.cpp == 'true'
+ )
+
strategy:
fail-fast: false
matrix:
- include:
- - language: actions
- os: ubuntu-latest
- build-mode: none
- - language: c-cpp
- os: ubuntu-latest
- build-mode: manual
- - language: c-cpp
- os: windows-latest
- build-mode: manual
- - language: csharp
- os: ubuntu-latest
- build-mode: none
- - language: javascript-typescript
- os: ubuntu-latest
- build-mode: none
- - language: python
- os: ubuntu-latest
- build-mode: none
-
+ os:
+ - ubuntu-latest
+ - windows-latest
+ # - macos-latest # support is currently experimental and requires additional setup
+
+ permissions:
+ contents: read
+ security-events: write
+ actions: read
+ packages: read
+ pull-requests: write
+ checks: write
+
steps:
- - name: Decide Whether to Analyze
- id: should_analyze
- shell: bash
- env:
- FULL_SCAN: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.full_scan == 'true' }}
- LANGUAGE: ${{ matrix.language }}
- ACTIONS_CHANGED: ${{ needs.changes.outputs.actions }}
- CSHARP_CHANGED: ${{ needs.changes.outputs.csharp }}
- CPP_CHANGED: ${{ needs.changes.outputs.cpp }}
- JAVASCRIPT_TYPESCRIPT_CHANGED: ${{ needs.changes.outputs.javascript_typescript }}
- PYTHON_CHANGED: ${{ needs.changes.outputs.python }}
- run: |
- should_run=false
-
- if [[ "$FULL_SCAN" == "true" ]]; then should_run=true
- elif [[ "$LANGUAGE" == "actions" && "$ACTIONS_CHANGED" == "true" ]]; then should_run=true
- elif [[ "$LANGUAGE" == "csharp" && "$CSHARP_CHANGED" == "true" ]]; then should_run=true
- elif [[ "$LANGUAGE" == "c-cpp" && "$CPP_CHANGED" == "true" ]]; then should_run=true
- elif [[ "$LANGUAGE" == "javascript-typescript" && "$JAVASCRIPT_TYPESCRIPT_CHANGED" == "true" ]]; then should_run=true
- elif [[ "$LANGUAGE" == "python" && "$PYTHON_CHANGED" == "true" ]]; then should_run=true
- fi
-
- echo "run=$should_run" >> "$GITHUB_OUTPUT"
-
- name: Checkout
uses: actions/checkout@v6
- with:
- fetch-depth: 1
- - name: Setup .NET
- uses: actions/setup-dotnet@v5
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
with:
- dotnet-version: |
- 8.x
- 9.x
- 10.x
- cache: true
- cache-dependency-path: |
- **/*.csproj
- **/*.props
- **/Directory.Packages.props
-
- - name: Setup CMake
- if: steps.should_analyze.outputs.run == 'true' && matrix.language == 'c-cpp'
- uses: lukka/get-cmake@latest
+ cache-dotnet: false
- - name: Setup Native dependencies
- if: steps.should_analyze.outputs.run == 'true' && matrix.language == 'c-cpp'
- # noinspection UndefinedAction
+ - name: Setup Native Dependencies
uses: ./.github/actions/setup-dependencies-native
- # noinspection UndefinedParamsPresent
with:
- apt-cache-version: 1.0
- brew-cache-key: ${{ runner.os }}-${{ matrix.language }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/codeql.yml') }}
- brew-restore-key: ${{ runner.os }}-${{ matrix.language }}-brew-native-
+ brew-cache-key: ${{ runner.os }}-brew-codeql-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-macos.yml') }}
+ brew-restore-key: ${{ runner.os }}-brew-codeql-
- name: Initialize CodeQL
- if: steps.should_analyze.outputs.run == 'true'
uses: github/codeql-action/init@v4
with:
- languages: ${{ matrix.language }}
- build-mode: ${{ matrix.build-mode }}
+ languages: c-cpp
+ build-mode: manual
queries: security-extended,security-and-quality
config-file: ./.github/codeql-config.yml
- - name: Restore C# (.slnx)
- if: steps.should_analyze.outputs.run == 'true' && matrix.language == 'csharp' && matrix.build-mode == 'manual'
+ - name: Restore NativeBridge
run: |
- dotnet restore InfiniFrame.slnx /p:NoWarn=NU1503
+ dotnet restore src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj /p:NoWarn=NU1503
- - name: Build Native (CodeQL)
- if: steps.should_analyze.outputs.run == 'true' && matrix.language == 'c-cpp'
+ - name: Build NativeBridge
shell: pwsh
run: |
- dotnet build src/InfiniFrame.Native/InfiniFrame.Native.proj --configuration Release --no-restore -p:SolutionDir="${{ github.workspace }}/" -p:Platform=x64
+ dotnet build src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj `
+ --configuration Release `
+ --no-restore `
+ -p:SolutionDir="${{ github.workspace }}/" `
+ -p:Platform=x64
- - name: Build C# (.slnx)
- if: steps.should_analyze.outputs.run == 'true' && matrix.language == 'csharp' && matrix.build-mode == 'manual'
- run: |
- dotnet build InfiniFrame.slnx --no-restore --configuration Release -p:InfiniFramePackAfterBuild=false
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v4
+ with:
+ category: "/language:c-cpp"
+
+ analyze-javascript-typescript:
+ name: Analyze JavaScript / TypeScript
+ needs: changes
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+
+ if: >
+ (
+ github.event_name == 'workflow_dispatch' &&
+ github.event.inputs.full_scan == 'true'
+ ) || (
+ needs.changes.outputs.javascript_typescript == 'true'
+ )
+
+ permissions:
+ contents: read
+ security-events: write
+ actions: read
+ packages: read
+ pull-requests: write
+ checks: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v4
+ with:
+ languages: javascript-typescript
+ build-mode: none
+ queries: security-extended,security-and-quality
+ config-file: ./.github/codeql-config.yml
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v4
+ with:
+ category: "/language:javascript-typescript"
+
+ analyze-python:
+ name: Analyze Python
+ needs: changes
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+
+ if: >
+ (
+ github.event_name == 'workflow_dispatch' &&
+ github.event.inputs.full_scan == 'true'
+ ) || (
+ needs.changes.outputs.python == 'true'
+ )
+
+ permissions:
+ contents: read
+ security-events: write
+ actions: read
+ packages: read
+ pull-requests: write
+ checks: write
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v4
+ with:
+ languages: python
+ build-mode: none
+ queries: security-extended,security-and-quality
+ config-file: ./.github/codeql-config.yml
- name: Perform CodeQL Analysis
- if: steps.should_analyze.outputs.run == 'true'
uses: github/codeql-action/analyze@v4
with:
- category: "/language:${{ matrix.language }}"
+ category: "/language:python"
diff --git a/.github/workflows/ci-update-native-vendor-deps.yml b/.github/workflows/ci-update-native-vendor-deps.yml
index 85300273..446755bc 100644
--- a/.github/workflows/ci-update-native-vendor-deps.yml
+++ b/.github/workflows/ci-update-native-vendor-deps.yml
@@ -1,56 +1,56 @@
name: "CI: Update Native Vendor Deps"
on:
- schedule:
- - cron: "0 5 * * 1"
- workflow_dispatch:
+ schedule:
+ - cron: "0 5 * * 1"
+ workflow_dispatch:
permissions:
- contents: write
- pull-requests: write
+ contents: write
+ pull-requests: write
jobs:
- update-native-vendor-deps:
- runs-on: ubuntu-latest
-
- steps:
- - name: Checkout
- uses: actions/checkout@v6
-
- - name: Setup Python
- uses: actions/setup-python@v6
- with:
- python-version: '3.x'
-
- - name: Update vendored native dependencies
- env:
- GITHUB_TOKEN: ${{ github.token }}
- run: python .github/scripts/update_native_vendor_deps.py
-
- - name: Detect changes
- id: detect_changes
- shell: bash
- run: |
- if git diff --quiet; then
- echo "has_changes=false" >> "$GITHUB_OUTPUT"
- else
- echo "has_changes=true" >> "$GITHUB_OUTPUT"
- fi
-
- - name: Create pull request
- if: steps.detect_changes.outputs.has_changes == 'true'
- uses: peter-evans/create-pull-request@v8
- with:
- # Prefer a PAT/App token if org policy blocks PR creation by GITHUB_TOKEN.
- token: ${{ secrets.INFINI_BOT_TOKEN || github.token }}
- commit-message: "chore(native): update simdjson/simdutf vendor deps"
- title: "chore(native): update simdjson/simdutf vendor deps"
- body: |
- Automated weekly refresh of vendored native dependencies in `InfiniFrame.Native`.
-
- Updated by `.github/scripts/update_native_vendor_deps.py` from latest GitHub releases.
- branch: "chore/update-native-vendor-deps"
- delete-branch: true
- labels: |
- dependencies
- InfiniFrame.Native
+ update-native-vendor-deps:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+
+ - name: Setup Python
+ uses: actions/setup-python@v6
+ with:
+ python-version: '3.x'
+
+ - name: Update vendored native dependencies
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ run: python .github/scripts/update_native_vendor_deps.py
+
+ - name: Detect changes
+ id: detect_changes
+ shell: bash
+ run: |
+ if git diff --quiet; then
+ echo "has_changes=false" >> "$GITHUB_OUTPUT"
+ else
+ echo "has_changes=true" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: Create pull request
+ if: steps.detect_changes.outputs.has_changes == 'true'
+ uses: peter-evans/create-pull-request@v8
+ with:
+ # Prefer a PAT/App token if org policy blocks PR creation by GITHUB_TOKEN.
+ token: ${{ secrets.INFINI_BOT_TOKEN || github.token }}
+ commit-message: "chore(native): update simdjson/simdutf vendor deps"
+ title: "chore(native): update simdjson/simdutf vendor deps"
+ body: |
+ Automated weekly refresh of vendored native dependencies in `InfiniFrame.Native`.
+
+ Updated by `.github/scripts/update_native_vendor_deps.py` from latest GitHub releases.
+ branch: "chore/update-native-vendor-deps"
+ delete-branch: true
+ labels: |
+ dependencies
+ InfiniFrame.Native
diff --git a/.github/workflows/shared-release-build.yml b/.github/workflows/shared-release-build.yml
index cc61be26..3a8dbe3e 100644
--- a/.github/workflows/shared-release-build.yml
+++ b/.github/workflows/shared-release-build.yml
@@ -55,20 +55,19 @@ jobs:
8.x
9.x
10.x
-
+
- name: Setup Native dependencies
# noinspection UndefinedAction
uses: ./.github/actions/setup-dependencies-native
# noinspection UndefinedParamsPresent
with:
- apt-cache-version: 1.0
brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-release-build.yml') }}
brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-
- name: Build Native
shell: bash
run: |
- dotnet build "src/InfiniFrame.Native/InfiniFrame.Native.proj" \
+ dotnet build "src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj" \
--configuration Release \
--no-restore \
-p:SolutionDir="${{ github.workspace }}/" \
diff --git a/.github/workflows/shared-release-publish-docs.yml b/.github/workflows/shared-release-publish-docs.yml
index 9746f494..494bd81d 100644
--- a/.github/workflows/shared-release-publish-docs.yml
+++ b/.github/workflows/shared-release-publish-docs.yml
@@ -17,7 +17,7 @@ concurrency:
group: pages
cancel-in-progress: true
-jobs:
+jobs:
build:
name: Build Docs
runs-on: ubuntu-latest
diff --git a/.github/workflows/shared-release-publish.yml b/.github/workflows/shared-release-publish.yml
index cc9671f3..061dc29f 100644
--- a/.github/workflows/shared-release-publish.yml
+++ b/.github/workflows/shared-release-publish.yml
@@ -54,41 +54,13 @@ jobs:
uses: ./.github/actions/setup-dependencies-native
# noinspection UndefinedParamsPresent
with:
- apt-cache-version: 1.0
brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-release-publish.yml') }}
brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-
- - name: Download Build Artifacts
- uses: actions/download-artifact@v8
+ - name: Download Release Native Build Artifacts
+ uses: ./.github/actions/download-native-binaries
with:
- path: artifacts/native
-
- - name: Normalize Artifacts
- run: |
- set -e
-
- mkdir -p artifacts/native/windows/x64/Release
- mkdir -p artifacts/native/windows/arm64/Release
- mkdir -p artifacts/native/linux/x64/Release
- mkdir -p artifacts/native/linux/arm64/Release
- mkdir -p artifacts/native/osx/x64/Release
- mkdir -p artifacts/native/osx/arm64/Release
-
- declare -A MAP
- MAP["native-windows-x64"]="artifacts/native/windows/x64/Release"
- MAP["native-windows-arm64"]="artifacts/native/windows/arm64/Release"
- MAP["native-linux-x64"]="artifacts/native/linux/x64/Release"
- MAP["native-linux-arm64"]="artifacts/native/linux/arm64/Release"
- MAP["native-osx-x64"]="artifacts/native/osx/x64/Release"
- MAP["native-osx-arm64"]="artifacts/native/osx/arm64/Release"
-
- for key in "${!MAP[@]}"; do
- src="artifacts/native/$key"
- dest="${MAP[$key]}"
- if [ -d "$src" ]; then
- mv "$src"/* "$dest"/ 2>/dev/null || true
- fi
- done
+ artifact-type: release
- name: Verify Artifacts
run: |
diff --git a/.github/workflows/shared-testing-build.yml b/.github/workflows/shared-testing-build.yml
new file mode 100644
index 00000000..a5735591
--- /dev/null
+++ b/.github/workflows/shared-testing-build.yml
@@ -0,0 +1,77 @@
+name: "Shared: Testing Build"
+on:
+ workflow_call:
+ inputs:
+ pr_number:
+ description: 'PR number to test. Leave empty to test the current trigger commit (github.sha).'
+ type: string
+ required: true
+ checkout_ref:
+ description: 'Explicit git ref to checkout.'
+ type: string
+ required: false
+ default: ''
+ target_sha:
+ description: 'Resolved commit SHA used by testing workflows.'
+ type: string
+ required: true
+
+permissions:
+ contents: read
+
+jobs:
+ build:
+ name: Build Testing Native (${{ matrix.os }}/${{ matrix.arch }})
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - os: ubuntu-latest
+ arch: x64
+ libName: linux
+ - os: ubuntu-24.04-arm
+ arch: arm64
+ libName: linux
+ - os: windows-latest
+ arch: x64
+ libName: windows
+ - os: windows-11-arm
+ arch: arm64
+ libName: windows
+ - os: macos-26-intel
+ arch: x64
+ libName: osx
+ - os: macos-latest
+ arch: arm64
+ libName: osx
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v6
+ with:
+ ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || (inputs.pr_number != '' && inputs.pr_number != null && format('refs/pull/{0}/merge', inputs.pr_number) || inputs.target_sha) }}
+ fetch-depth: 1
+
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
+ with:
+ cache-dotnet: false
+
+ - name: Setup Native dependencies
+ uses: ./.github/actions/setup-dependencies-native
+ with:
+ brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-build.yml') }}
+ brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-
+
+ - name: Build Native
+ shell: pwsh
+ run: |
+ ./src/InfiniFrame.NativeBridge/native-build.ps1 `
+ "Release" `
+ "${{ matrix.arch }}"
+
+ - name: Upload Build Artifact
+ uses: actions/upload-artifact@v7
+ with:
+ name: native-testing-${{ matrix.libName }}-${{ matrix.arch }}
+ path: ${{ github.workspace }}/src/InfiniFrame.NativeBridge/artifacts/native/${{ matrix.libName }}/${{ matrix.arch }}/Release/**
diff --git a/.github/workflows/shared-testing-docs.yml b/.github/workflows/shared-testing-docs.yml
index a91879ad..8585f0d9 100644
--- a/.github/workflows/shared-testing-docs.yml
+++ b/.github/workflows/shared-testing-docs.yml
@@ -30,7 +30,7 @@ jobs:
uses: actions/checkout@v6
with:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || env.TARGET_SHA }}
-
+
- name: Setup Node
uses: actions/setup-node@v6
with:
@@ -42,7 +42,7 @@ jobs:
- name: Install Docusaurus Dependencies
shell: bash
run: npm ci --prefix docs
-
+
- name: Set Docs Pending
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -57,11 +57,11 @@ jobs:
status-description: Docs validation in progress
target-url: ${{ format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}
allow-status-422: 'true'
-
+
- name: Build Docusaurus Docs
shell: bash
run: npm --prefix docs run build
-
+
- name: Complete Docs Check
if: always()
env:
diff --git a/.github/workflows/shared-testing-dotnetpack.yml b/.github/workflows/shared-testing-dotnetpack.yml
index 8f024bf4..feaa5112 100644
--- a/.github/workflows/shared-testing-dotnetpack.yml
+++ b/.github/workflows/shared-testing-dotnetpack.yml
@@ -31,11 +31,11 @@ jobs:
with:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || env.TARGET_SHA }}
fetch-depth: 1
-
- - name: Setup Node
- uses: actions/setup-node@v6
+
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
with:
- node-version: 24
+ cache-dotnet: false
- name: Set Dotnet Pack Check Pending
env:
@@ -52,50 +52,67 @@ jobs:
target-url: ${{ format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}
allow-status-422: 'true'
- - name: Setup .NET
- uses: actions/setup-dotnet@v5
- with:
- dotnet-version: |
- 8.x
- 9.x
- 10.x
- cache: true
- cache-dependency-path: |
- **/*.csproj
- **/*.props
- **/Directory.Packages.props
-
- - name: Setup Native dependencies
- # noinspection UndefinedAction
- uses: ./.github/actions/setup-dependencies-native
- # noinspection UndefinedParamsPresent
+ - name: Download Testing Native Build Artifacts
+ uses: ./.github/actions/download-native-binaries
with:
- apt-cache-version: 1.0
- brew-cache-key: ${{ runner.os }}-x64-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-dotnetpack.yml') }}
- brew-restore-key: ${{ runner.os }}-x64-brew-native-
+ artifact-type: testing
- name: Restore
run: dotnet restore InfiniFrame.GitHubActions.Release.slnf /p:NoWarn=NU1503
- name: Build Release
run: |
- dotnet build src/InfiniFrame.Native/InfiniFrame.Native.proj \
- --configuration Release \
- --no-restore \
- /p:SolutionDir="${{ github.workspace }}/" \
- /p:Platform=x64
-
dotnet build InfiniFrame.GitHubActions.Release.slnf \
--configuration Release \
--no-restore \
- /p:SolutionDir=${{ github.workspace }}/
+ /p:SolutionDir=${{ github.workspace }}/ \
+ /p:InfiniFrameSkipNativeBuild=true
- name: Pack
run: |
dotnet pack InfiniFrame.GitHubActions.Release.slnf \
--configuration Release \
+ --no-build \
+ /p:InfiniFrameSkipNativeBuild=true \
-o ./release
-
+
+ - name: Verify NativeBridge Package Natives
+ run: |
+ PACKAGE=$(ls ./release/InfiniLore.InfiniFrame.NativeBridge.*.nupkg 2>/dev/null | grep -v '\.symbols\.nupkg$' | head -n 1 || true)
+
+ if [ -z "$PACKAGE" ]; then
+ echo "❌ No InfiniFrame.NativeBridge package found in ./release"
+ exit 1
+ fi
+
+ echo "Inspecting package: $PACKAGE"
+
+ EXPECTED=(
+ "runtimes/win-x64/native/InfiniFrame.Native.dll"
+ "runtimes/win-x64/native/WebView2Loader.dll"
+ "runtimes/win-arm64/native/InfiniFrame.Native.dll"
+ "runtimes/win-arm64/native/WebView2Loader.dll"
+ "runtimes/linux-x64/native/InfiniFrame.Native.so"
+ "runtimes/linux-arm64/native/InfiniFrame.Native.so"
+ "runtimes/osx-x64/native/InfiniFrame.Native.dylib"
+ "runtimes/osx-arm64/native/InfiniFrame.Native.dylib"
+ )
+
+ MISSING=0
+ for f in "${EXPECTED[@]}"; do
+ if ! unzip -l "$PACKAGE" | grep -q "$f"; then
+ echo "❌ Missing $f in $PACKAGE"
+ MISSING=$((MISSING+1))
+ else
+ echo "✅ Found $f"
+ fi
+ done
+
+ if [ $MISSING -gt 0 ]; then
+ echo "❌ $MISSING native file(s) missing in NativeBridge package"
+ exit 1
+ fi
+
- name: Complete Dotnet Pack Check
if: always()
env:
diff --git a/.github/workflows/shared-testing-js.yml b/.github/workflows/shared-testing-js.yml
index 02f89b3f..22134c3a 100644
--- a/.github/workflows/shared-testing-js.yml
+++ b/.github/workflows/shared-testing-js.yml
@@ -30,7 +30,7 @@ jobs:
uses: actions/checkout@v6
with:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || env.TARGET_SHA }}
-
+
- name: Setup Node
uses: actions/setup-node@v6
with:
@@ -50,7 +50,7 @@ jobs:
shell: bash
working-directory: src/InfiniFrame.Js
run: npm run test
-
+
- name: Complete Js Check
if: always()
env:
diff --git a/.github/workflows/shared-testing-linux.yml b/.github/workflows/shared-testing-linux.yml
index 282296ad..4fab3a85 100644
--- a/.github/workflows/shared-testing-linux.yml
+++ b/.github/workflows/shared-testing-linux.yml
@@ -45,6 +45,14 @@ jobs:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || (inputs.pr_number != '' && inputs.pr_number != null && format('refs/pull/{0}/merge', inputs.pr_number) || github.ref) }}
fetch-depth: 1
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
+ with:
+ cache-dotnet: false
+
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies-native
+
- name: Set Linux Check Pending
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -60,27 +68,10 @@ jobs:
target-url: ${{ inputs.workflow_url }}
allow-status-422: 'true'
- - name: Setup .NET
- uses: actions/setup-dotnet@v5
- with:
- dotnet-version: |
- 8.x
- 9.x
- 10.x
- cache: true
- cache-dependency-path: |
- **/*.csproj
- **/*.props
- **/Directory.Packages.props
-
- - name: Setup Native dependencies
- # noinspection UndefinedAction
- uses: ./.github/actions/setup-dependencies-native
- # noinspection UndefinedParamsPresent
+ - name: Download Testing Native Build Artifacts
+ uses: ./.github/actions/download-native-binaries
with:
- apt-cache-version: 1.0
- brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-linux.yml') }}
- brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-
+ artifact-type: testing
- name: Compile GSettings schemas
run: sudo glib-compile-schemas /usr/share/glib-2.0/schemas/
@@ -90,19 +81,12 @@ jobs:
- name: Build Release
run: |
- dotnet build src/InfiniFrame.Native/InfiniFrame.Native.proj \
- --configuration Release \
- --no-restore \
- /p:SolutionDir="${{ github.workspace }}/" \
- /p:Platform=${{ matrix.arch }}
-
dotnet build InfiniFrame.GitHubActions.Testing.slnf \
--configuration Release \
- --no-restore
-
- - name: Verify Native Binaries
- # noinspection UndefinedAction
- uses: ./.github/actions/validate-native-test-binaries
+ --no-restore \
+ -p:SolutionDir=${{ github.workspace }}/ \
+ -p:CMakePlatform=${{ matrix.arch }} \
+ -p:InfiniFrameSkipNativeBuild=true
- name: Export Actions Runtime
uses: actions/github-script@v9
@@ -183,10 +167,11 @@ jobs:
dotnet test --solution InfiniFrame.GitHubActions.Testing.slnf \
--configuration Release \
--no-build \
- --no-restore
+ --no-restore \
+ -p:CMakePlatform=${{ matrix.arch }} \
+ -p:InfiniFrameSkipNativeBuild=true
- name: Pack Tool E2E
- if: always()
# noinspection UndefinedAction
uses: ./.github/actions/packtool-e2e
# noinspection UndefinedParamsPresent
diff --git a/.github/workflows/shared-testing-macos.yml b/.github/workflows/shared-testing-macos.yml
index 8f6cb9e4..8c2db0dd 100644
--- a/.github/workflows/shared-testing-macos.yml
+++ b/.github/workflows/shared-testing-macos.yml
@@ -47,6 +47,17 @@ jobs:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || (inputs.pr_number != '' && inputs.pr_number != null && format('refs/pull/{0}/merge', inputs.pr_number) || github.ref) }}
fetch-depth: 1
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
+ with:
+ cache-dotnet: false
+
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies-native
+ with:
+ brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-macos.yml') }}
+ brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-
+
- name: Set macOS Check Pending
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -62,45 +73,22 @@ jobs:
target-url: ${{ inputs.workflow_url }}
allow-status-422: 'true'
- - name: Setup .NET
- uses: actions/setup-dotnet@v5
- with:
- dotnet-version: |
- 8.x
- 9.x
- 10.x
- cache: true
- cache-dependency-path: |
- **/*.csproj
- **/*.props
- **/Directory.Packages.props
-
- - name: Setup Native dependencies
- # noinspection UndefinedAction
- uses: ./.github/actions/setup-dependencies-native
- # noinspection UndefinedParamsPresent
+ - name: Download Testing Native Build Artifacts
+ uses: ./.github/actions/download-native-binaries
with:
- apt-cache-version: 1.0
- brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-macos.yml') }}
- brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-
+ artifact-type: testing
- name: Restore
run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503
- - name: Build Native
+ - name: Build Release
run: |
- dotnet build src/InfiniFrame.Native/InfiniFrame.Native.proj \
+ dotnet build InfiniFrame.GitHubActions.Testing.slnf \
--configuration Release \
--no-restore \
- /p:SolutionDir="${{ github.workspace }}/" \
- /p:Platform=${{ matrix.arch }}
-
- - name: Build Release
- run: dotnet build InfiniFrame.GitHubActions.Testing.slnf --configuration Release --no-restore
-
- - name: Verify Native Binaries
- # noinspection UndefinedAction
- uses: ./.github/actions/validate-native-test-binaries
+ -p:SolutionDir=${{ github.workspace }}/ \
+ -p:CMakePlatform=${{ matrix.arch }} \
+ -p:InfiniFrameSkipNativeBuild=true
- name: Export Actions Runtime
uses: actions/github-script@v9
@@ -126,10 +114,11 @@ jobs:
dotnet test --solution InfiniFrame.GitHubActions.Testing.slnf \
--configuration Release \
--no-build \
- --no-restore
+ --no-restore \
+ -p:CMakePlatform=${{ matrix.arch }} \
+ -p:InfiniFrameSkipNativeBuild=true
- name: Pack Tool E2E
- if: always()
# noinspection UndefinedAction
uses: ./.github/actions/packtool-e2e
# noinspection UndefinedParamsPresent
diff --git a/.github/workflows/shared-testing-python.yml b/.github/workflows/shared-testing-python.yml
index 64c44c5f..8dcc64b4 100644
--- a/.github/workflows/shared-testing-python.yml
+++ b/.github/workflows/shared-testing-python.yml
@@ -25,9 +25,9 @@ jobs:
- name: Run Pytest
run: python -m pytest .github/scripts -q
-
- - name: Run Validations
- run: |
- python .github/scripts/validate_package_id_prefix.py \
- --slnf InfiniFrame.GitHubActions.Release.slnf \
- --prefix InfiniLore
\ No newline at end of file
+
+ - name: Run Validations
+ run: |
+ python .github/scripts/validate_package_id_prefix.py \
+ --slnf InfiniFrame.GitHubActions.Release.slnf \
+ --prefix InfiniLore
\ No newline at end of file
diff --git a/.github/workflows/shared-testing-windows-playwright.yml b/.github/workflows/shared-testing-windows-playwright.yml
index 4c120b90..97b457aa 100644
--- a/.github/workflows/shared-testing-windows-playwright.yml
+++ b/.github/workflows/shared-testing-windows-playwright.yml
@@ -34,7 +34,7 @@ jobs:
with:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || (inputs.pr_number != '' && format('refs/pull/{0}/merge', inputs.pr_number) || github.ref) }}
fetch-depth: 1
-
+
- name: Set Playwright Check Pending
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -59,7 +59,7 @@ jobs:
strategy:
fail-fast: false
- matrix:
+ matrix:
project:
- name: WebApp Vue
path: InfiniFrameTests.Playwright.WebApp.Vue
@@ -87,6 +87,14 @@ jobs:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || (inputs.pr_number != '' && format('refs/pull/{0}/merge', inputs.pr_number) || github.ref) }}
fetch-depth: 1
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
+ with:
+ cache-dotnet: false
+
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies-native
+
- name: Set Playwright Check Pending
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -102,54 +110,11 @@ jobs:
target-url: ${{ inputs.workflow_url }}
allow-status-422: 'true'
- - name: Setup .NET
- uses: actions/setup-dotnet@v5
+ - name: Download Testing Native Build Artifacts
+ uses: ./.github/actions/download-native-binaries
with:
- dotnet-version: |
- 8.x
- 9.x
- 10.x
- cache: true
- cache-dependency-path: |
- **/*.csproj
- **/*.props
- **/Directory.Packages.props
+ artifact-type: testing
- - name: Setup Native dependencies
- # noinspection UndefinedAction
- uses: ./.github/actions/setup-dependencies-native
- # noinspection UndefinedParamsPresent
- with:
- apt-cache-version: 1.0
- brew-cache-key: ${{ runner.os }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml') }}
- brew-restore-key: ${{ runner.os }}-brew-native-
-
- - name: Setup Node
- uses: actions/setup-node@v6
- with:
- node-version: 20
- cache: 'npm'
- cache-dependency-path: '**/package-lock.json'
-
- - name: Prepare WebView2 Cache Directory
- shell: pwsh
- run: New-Item -ItemType Directory -Path ".cache\webview2" -Force | Out-Null
-
- - name: Cache WebView2
- uses: actions/cache@v5
- with:
- path: .cache\webview2
- key: webview2-installer-${{ runner.os }}-v1
-
- - name: Install WebView2 Runtime
- shell: pwsh
- run: |
- $installer = "$PWD\.cache\webview2\MicrosoftEdgeWebview2Setup.exe"
- if (-Not (Test-Path $installer)) {
- Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/p/?LinkId=2124703" -OutFile $installer
- }
- Start-Process -FilePath $installer -ArgumentList "/silent", "/install" -Wait
-
- name: NPM Install
if: ${{ matrix.project.sourceFolder != '' }}
shell: pwsh
@@ -175,32 +140,13 @@ jobs:
dotnet restore InfiniFrame.GitHubActions.Testing.Playwright.slnf `
/p:NoWarn=NU1503
- - name: Build Native
- run: |
- dotnet build src/InfiniFrame.Native/InfiniFrame.Native.proj `
- --configuration Release `
- --no-restore `
- /p:SolutionDir=$GITHUB_WORKSPACE/
-
- name: Build Tests
run: |
dotnet build tests/${{ matrix.project.path }}/${{ matrix.project.path }}.csproj `
--configuration Release `
--no-restore `
- --framework net8.0 `
- /p:SolutionDir=$GITHUB_WORKSPACE/
-
- dotnet build tests/${{ matrix.project.path }}/${{ matrix.project.path }}.csproj `
- --configuration Release `
- --no-restore `
- --framework net9.0 `
- /p:SolutionDir=$GITHUB_WORKSPACE/
-
- dotnet build tests/${{ matrix.project.path }}/${{ matrix.project.path }}.csproj `
- --configuration Release `
- --no-restore `
- --framework net10.0 `
- /p:SolutionDir=$GITHUB_WORKSPACE/
+ /p:SolutionDir=$env:GITHUB_WORKSPACE/ `
+ /p:InfiniFrameSkipNativeBuild=true
- name: Install Playwright Browsers
shell: pwsh
@@ -210,19 +156,19 @@ jobs:
if (-not (Test-Path $script)) {
throw "Playwright script not found: $script"
}
-
pwsh $script install
- name: Verify Native Binaries
shell: pwsh
run: |
$binPath = "tests/${{ matrix.project.path }}/bin/Release/net10.0"
-
- foreach ($dll in @("InfiniFrame.Native.dll", "WebView2Loader.dll")) {
- $fullPath = Join-Path $binPath $dll
- if (-Not (Test-Path $fullPath)) {
- throw "$dll missing in $binPath"
- }
+ $dlls = @("InfiniFrame.Native.dll", "WebView2Loader.dll")
+
+ foreach ($dll in $dlls) {
+ $fullPath = Join-Path $binPath $dll
+ if (-Not (Test-Path $fullPath)) {
+ throw "$dll missing in $binPath"
+ }
}
- name: Export Actions Runtime
@@ -240,7 +186,8 @@ jobs:
--configuration Release `
--no-build `
--no-restore `
- --framework net8.0
+ --framework net8.0 `
+ /p:InfiniFrameSkipNativeBuild=true
- name: Run Playwright tests NET 9.0
shell: pwsh
@@ -250,7 +197,8 @@ jobs:
--configuration Release `
--no-build `
--no-restore `
- --framework net9.0
+ --framework net9.0 `
+ /p:InfiniFrameSkipNativeBuild=true
- name: Run Playwright tests NET 10.0
shell: pwsh
@@ -260,7 +208,8 @@ jobs:
--configuration Release `
--no-build `
--no-restore `
- --framework net10.0
+ --framework net10.0 `
+ /p:InfiniFrameSkipNativeBuild=true
- name: Update Playwright Check
if: always()
@@ -292,7 +241,7 @@ jobs:
with:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || (inputs.pr_number != '' && format('refs/pull/{0}/merge', inputs.pr_number) || github.ref) }}
fetch-depth: 1
-
+
- name: Set Playwright Check Final Status
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/shared-testing-windows-trim-aot.yml b/.github/workflows/shared-testing-windows-trim-aot.yml
index 7c3b3235..d102b3ff 100644
--- a/.github/workflows/shared-testing-windows-trim-aot.yml
+++ b/.github/workflows/shared-testing-windows-trim-aot.yml
@@ -31,18 +31,13 @@ jobs:
with:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || env.TARGET_SHA }}
- - name: Setup .NET
- uses: actions/setup-dotnet@v5
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
with:
- dotnet-version: |
- 8.x
- 9.x
- 10.x
- cache: true
- cache-dependency-path: |
- **/*.csproj
- **/*.props
- **/Directory.Packages.props
+ cache-dotnet: false
+
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies-native
- name: Set Trim/AOT Check Pending
env:
@@ -64,15 +59,22 @@ jobs:
uses: ./.github/actions/setup-dependencies-native
# noinspection UndefinedParamsPresent
with:
- apt-cache-version: 1.0
- brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-windows-trim-aot.yml') }}
- brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-
+ brew-cache-key: ${{ runner.os }}-x64-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-windows-trim-aot.yml') }}
+ brew-restore-key: ${{ runner.os }}-x64-brew-native-
+
+ - name: Download Testing Native Build Artifacts
+ uses: ./.github/actions/download-native-binaries
+ with:
+ artifact-type: testing
- name: Trim Analyzer Builds
run: |
dotnet build src/InfiniFrame.Shared/InfiniFrame.Shared.csproj `
--configuration Release `
--framework net10.0 `
+ -p:SolutionDir=$env:GITHUB_WORKSPACE/ `
+ -p:Platform=x64 `
+ -p:InfiniFrameSkipNativeBuild=true `
-p:EnableTrimAnalyzer=true `
-p:EnableAotAnalyzer=true `
-p:GeneratePackageOnBuild=false
@@ -80,6 +82,9 @@ jobs:
dotnet build src/InfiniFrame.BlazorWebView/InfiniFrame.BlazorWebView.csproj `
--configuration Release `
--framework net10.0 `
+ -p:SolutionDir=$env:GITHUB_WORKSPACE/ `
+ -p:Platform=x64 `
+ -p:InfiniFrameSkipNativeBuild=true `
-p:EnableTrimAnalyzer=true `
-p:EnableAotAnalyzer=true `
-p:GeneratePackageOnBuild=false `
@@ -88,6 +93,9 @@ jobs:
dotnet build src/InfiniFrame.WebServer/InfiniFrame.WebServer.csproj `
--configuration Release `
--framework net10.0 `
+ -p:SolutionDir=$env:GITHUB_WORKSPACE/ `
+ -p:Platform=x64 `
+ -p:InfiniFrameSkipNativeBuild=true `
-p:EnableTrimAnalyzer=true `
-p:EnableAotAnalyzer=true `
-p:GeneratePackageOnBuild=false `
@@ -99,22 +107,38 @@ jobs:
--configuration Release `
--framework net10.0 `
--runtime win-x64 `
+ -p:SolutionDir=$env:GITHUB_WORKSPACE/ `
+ -p:Platform=x64 `
+ -p:InfiniFrameSkipNativeBuild=true `
-p:GeneratePackageOnBuild=false `
-p:SkipTypeScriptBuild=true
- name: Validate NativeAOT Output
run: |
- $publishDir = "examples/InfiniFrameExample.TrimAotSmoke/bin/Release/net10.0/win-x64/publish"
- $output = Join-Path $publishDir "InfiniFrameExample.TrimAotSmoke.exe"
+ $publishDirs = @(
+ "examples/InfiniFrameExample.TrimAotSmoke/bin/x64/Release/net10.0/win-x64/publish",
+ "examples/InfiniFrameExample.TrimAotSmoke/bin/Release/net10.0/win-x64/publish"
+ )
+ $outputName = "InfiniFrameExample.TrimAotSmoke.exe"
- if (Test-Path $output) {
- Write-Host "✅ NativeAOT smoke output validated: $output"
- Exit 0
+ foreach ($publishDir in $publishDirs) {
+ $output = Join-Path $publishDir $outputName
+ if (Test-Path $output) {
+ Write-Host "✅ NativeAOT smoke output validated: $output"
+ Exit 0
+ }
}
- $availableExeNames = Get-ChildItem -Path $publishDir -Filter *.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name
- Write-Host "❌ Expected NativeAOT output not found: $output"
- Write-Host "Available *.exe in publish dir: $($availableExeNames -join ', ')"
+ Write-Host "❌ Expected NativeAOT output not found. Checked:"
+ foreach ($publishDir in $publishDirs) {
+ Write-Host " - $publishDir"
+ if (Test-Path $publishDir) {
+ $availableExeNames = Get-ChildItem -Path $publishDir -Filter *.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name
+ Write-Host " Available *.exe: $($availableExeNames -join ', ')"
+ } else {
+ Write-Host " Directory does not exist."
+ }
+ }
Exit 1
- name: Complete Trim/AOT Check
diff --git a/.github/workflows/shared-testing-windows.yml b/.github/workflows/shared-testing-windows.yml
index ec414cb4..36dca79f 100644
--- a/.github/workflows/shared-testing-windows.yml
+++ b/.github/workflows/shared-testing-windows.yml
@@ -47,6 +47,14 @@ jobs:
ref: ${{ inputs.checkout_ref != '' && inputs.checkout_ref || (inputs.pr_number != '' && inputs.pr_number != null && format('refs/pull/{0}/merge', inputs.pr_number) || github.ref) }}
fetch-depth: 1
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies
+ with:
+ cache-dotnet: false
+
+ - name: Setup dependencies
+ uses: ./.github/actions/setup-dependencies-native
+
- name: Set Windows Check Pending
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -62,52 +70,23 @@ jobs:
target-url: ${{ inputs.workflow_url }}
allow-status-422: 'true'
- - name: Setup .NET
- uses: actions/setup-dotnet@v5
- with:
- dotnet-version: |
- 8.x
- 9.x
- 10.x
- cache: true
- cache-dependency-path: |
- **/*.csproj
- **/*.props
- **/Directory.Packages.props
-
- - name: Setup Node
- uses: actions/setup-node@v6
- with:
- node-version: 24
- architecture: ${{ matrix.arch }}
-
- - name: Setup Native dependencies
- # noinspection UndefinedAction
- uses: ./.github/actions/setup-dependencies-native
- # noinspection UndefinedParamsPresent
+ - name: Download Testing Native Build Artifacts
+ uses: ./.github/actions/download-native-binaries
with:
- apt-cache-version: 1.0
- brew-cache-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-${{ hashFiles('.github/actions/setup-dependencies-native/action.yml', '.github/workflows/shared-testing-windows.yml') }}
- brew-restore-key: ${{ matrix.os }}-${{ matrix.arch }}-brew-native-
+ artifact-type: testing
- name: Restore
run: dotnet restore InfiniFrame.GitHubActions.Testing.slnf /p:NoWarn=NU1503
- name: Build Release
+ shell: pwsh
run: |
- dotnet build src/InfiniFrame.Native/InfiniFrame.Native.proj `
- --configuration Release `
- --no-restore `
- -p:SolutionDir="${{ github.workspace }}/" `
- -p:Platform=${{ matrix.arch }}
-
dotnet build InfiniFrame.GitHubActions.Testing.slnf `
--configuration Release `
- --no-restore
-
- - name: Verify Native Binaries
- # noinspection UndefinedAction
- uses: ./.github/actions/validate-native-test-binaries
+ --no-restore `
+ /p:SolutionDir=$env:GITHUB_WORKSPACE/ `
+ /p:CMakePlatform=${{ matrix.arch }} `
+ /p:InfiniFrameSkipNativeBuild=true
- name: Prepare ARM64 Crash Diagnostics
if: matrix.arch == 'arm64'
@@ -175,63 +154,65 @@ jobs:
script: |
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env['ACTIONS_RUNTIME_TOKEN']);
core.exportVariable('ACTIONS_RESULTS_URL', process.env['ACTIONS_RESULTS_URL']);
-
-# - name: Run InfiniFrameTests Project (ARM64 Diagnostics)
-# if: matrix.arch == 'arm64'
-# env:
-# INFINIFRAME_TRACE_TEARDOWN: 1
-# run: |
-# echo "Running ParentChildWindowTests diagnostics on Windows ARM64..."
-# dotnet test --project tests/InfiniFrameTests/InfiniFrameTests.csproj `
-# --configuration Release `
-# --no-build `
-# --no-restore `
-# --results-directory artifacts/testresults/arm64-infiniframetests `
-# --output Detailed `
-# --show-stderr All `
-# --show-stdout All `
-# --diagnostic `
-# --diagnostic-output-directory artifacts/testdiag/arm64-infiniframetests `
-# --treenode-filter "/*/*/ParentChildWindowTests/*" `
-# --minimum-expected-tests 1
-#
-# - name: Run Tests (ARM64)
-# if: matrix.arch == 'arm64'
-# env:
-# INFINIFRAME_TRACE_TEARDOWN: 1
-# run: |
-# echo "Running full tests on Windows ARM64..."
-# dotnet test --solution InfiniFrame.GitHubActions.Testing.slnf `
-# --configuration Release `
-# --no-build `
-# --no-restore `
-# --results-directory artifacts/testresults/arm64-full `
-# --output Normal `
-# --show-stderr All `
-# --show-stdout Failed `
-# --diagnostic `
-# --diagnostic-output-directory artifacts/testdiag/arm64-full
+
+ # - name: Run InfiniFrameTests Project (ARM64 Diagnostics)
+ # if: matrix.arch == 'arm64'
+ # env:
+ # INFINIFRAME_TRACE_TEARDOWN: 1
+ # run: |
+ # echo "Running ParentChildWindowTests diagnostics on Windows ARM64..."
+ # dotnet test --project tests/InfiniFrameTests/InfiniFrameTests.csproj `
+ # --configuration Release `
+ # --no-build `
+ # --no-restore `
+ # --results-directory artifacts/testresults/arm64-infiniframetests `
+ # --output Detailed `
+ # --show-stderr All `
+ # --show-stdout All `
+ # --diagnostic `
+ # --diagnostic-output-directory artifacts/testdiag/arm64-infiniframetests `
+ # --treenode-filter "/*/*/ParentChildWindowTests/*" `
+ # --minimum-expected-tests 1
+ #
+ # - name: Run Tests (ARM64)
+ # if: matrix.arch == 'arm64'
+ # env:
+ # INFINIFRAME_TRACE_TEARDOWN: 1
+ # run: |
+ # echo "Running full tests on Windows ARM64..."
+ # dotnet test --solution InfiniFrame.GitHubActions.Testing.slnf `
+ # --configuration Release `
+ # --no-build `
+ # --no-restore `
+ # --results-directory artifacts/testresults/arm64-full `
+ # --output Normal `
+ # --show-stderr All `
+ # --show-stdout Failed `
+ # --diagnostic `
+ # --diagnostic-output-directory artifacts/testdiag/arm64-full
- name: Run Tests (x64)
-# if: matrix.arch != 'arm64'
+ # if: matrix.arch != 'arm64'
run: |
echo "Running tests on Windows..."
dotnet test --solution InfiniFrame.GitHubActions.Testing.slnf `
--configuration Release `
--no-build `
- --no-restore
-
-# - name: Upload ARM64 Crash Diagnostics
-# if: always() && matrix.arch == 'arm64'
-# uses: actions/upload-artifact@v7
-# with:
-# name: windows-arm64-crash-diagnostics
-# if-no-files-found: warn
-# retention-days: 14
-# path: |
-# artifacts/crashdumps/**
-# artifacts/testdiag/**
-# artifacts/testresults/**
+ --no-restore `
+ /p:CMakePlatform=${{ matrix.arch }} `
+ /p:InfiniFrameSkipNativeBuild=true
+
+ # - name: Upload ARM64 Crash Diagnostics
+ # if: always() && matrix.arch == 'arm64'
+ # uses: actions/upload-artifact@v7
+ # with:
+ # name: windows-arm64-crash-diagnostics
+ # if-no-files-found: warn
+ # retention-days: 14
+ # path: |
+ # artifacts/crashdumps/**
+ # artifacts/testdiag/**
+ # artifacts/testresults/**
- name: Pack Tool E2E
# noinspection UndefinedAction
diff --git a/.github/workflows/shared-testing.yml b/.github/workflows/shared-testing.yml
index 44de1695..dd0627ef 100644
--- a/.github/workflows/shared-testing.yml
+++ b/.github/workflows/shared-testing.yml
@@ -81,31 +81,31 @@ jobs:
checkout_ref: ${{ inputs.checkout_ref }}
target_sha: ${{ needs.prepare.outputs.sha }}
secrets: inherit
-
+
# noinspection UndefinedAction, UndefinedParamsPresent
js-validation:
name: Validate JS
needs: [ prepare ]
uses: ./.github/workflows/shared-testing-js.yml
with:
- checkout_ref: ${{ inputs.checkout_ref }}
- target_sha: ${{ needs.prepare.outputs.sha }}
-
+ checkout_ref: ${{ inputs.checkout_ref }}
+ target_sha: ${{ needs.prepare.outputs.sha }}
+
# noinspection UndefinedAction, UndefinedParamsPresent
- dotnetpack-validation:
- name: Validate Dotnet Pack
+ native-build:
+ name: Build Native Artifacts
needs: [ prepare ]
- uses: ./.github/workflows/shared-testing-dotnetpack.yml
+ uses: ./.github/workflows/shared-testing-build.yml
with:
+ pr_number: ${{ inputs.pr_number }}
checkout_ref: ${{ inputs.checkout_ref }}
target_sha: ${{ needs.prepare.outputs.sha }}
-
+
# noinspection UndefinedAction, UndefinedParamsPresent
- windows-trim-aot:
- name: Validate Trim/AOT
- if: ${{ inputs.run_trim_aot == true }}
- needs: [ prepare ]
- uses: ./.github/workflows/shared-testing-windows-trim-aot.yml
+ dotnetpack-validation:
+ name: Validate Dotnet Pack
+ needs: [ prepare, native-build ]
+ uses: ./.github/workflows/shared-testing-dotnetpack.yml
with:
checkout_ref: ${{ inputs.checkout_ref }}
target_sha: ${{ needs.prepare.outputs.sha }}
@@ -114,7 +114,7 @@ jobs:
linux:
name: Linux Tests
if: ${{ inputs.run_linux == true }}
- needs: [ prepare ]
+ needs: [ prepare, native-build ]
uses: ./.github/workflows/shared-testing-linux.yml
with:
pr_number: ${{ inputs.pr_number }}
@@ -123,11 +123,24 @@ jobs:
workflow_url: ${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}
secrets: inherit
+ # noinspection UndefinedAction, UndefinedParamsPresent
+ macos:
+ name: macOS Tests
+ if: ${{ inputs.run_macos == true }}
+ needs: [ prepare, native-build ]
+ uses: ./.github/workflows/shared-testing-macos.yml
+ with:
+ pr_number: ${{ inputs.pr_number }}
+ checkout_ref: ${{ inputs.checkout_ref }}
+ target_sha: ${{ needs.prepare.outputs.sha }}
+ workflow_url: ${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}
+ secrets: inherit
+
# noinspection UndefinedAction, UndefinedParamsPresent
windows:
name: Windows Tests
if: ${{ inputs.run_windows == true }}
- needs: [ prepare ]
+ needs: [ prepare, native-build ]
uses: ./.github/workflows/shared-testing-windows.yml
with:
pr_number: ${{ inputs.pr_number }}
@@ -140,7 +153,7 @@ jobs:
windows-playwright:
name: Windows Playwright Tests
if: ${{ inputs.run_windows_playwright == true }}
- needs: [ prepare ]
+ needs: [ prepare, native-build ]
uses: ./.github/workflows/shared-testing-windows-playwright.yml
with:
pr_number: ${{ inputs.pr_number }}
@@ -150,14 +163,11 @@ jobs:
secrets: inherit
# noinspection UndefinedAction, UndefinedParamsPresent
- macos:
- name: macOS Tests
- if: ${{ inputs.run_macos == true }}
- needs: [ prepare ]
- uses: ./.github/workflows/shared-testing-macos.yml
+ windows-trim-aot:
+ name: Validate Trim/AOT
+ if: ${{ inputs.run_trim_aot == true }}
+ needs: [ prepare, native-build ]
+ uses: ./.github/workflows/shared-testing-windows-trim-aot.yml
with:
- pr_number: ${{ inputs.pr_number }}
checkout_ref: ${{ inputs.checkout_ref }}
target_sha: ${{ needs.prepare.outputs.sha }}
- workflow_url: ${{ format('https://github.com/{0}/actions/runs/{1}', github.repository, github.run_id) }}
- secrets: inherit
diff --git a/.gitignore b/.gitignore
index 5794344d..6845edc8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -343,12 +343,14 @@ healthchecksdb
.DS_Store
# InfiniFrame.Native
-/src/InfiniFrame.Native/build/
-/src/InfiniFrame.Native/packages/
-/src/InfiniFrame.Native/cmake-build-debug/
-/src/InfiniFrame.Native/cmake-build-debug-linux/
-/src/InfiniFrame.Native/cmake-build-debug-windows/
-/src/InfiniFrame.Native/Embedded/InfiniFrameJs/InfiniFrameJs.cpp
+/src/InfiniFrame.NativeBridge/artifacts/
+/src/InfiniFrame.NativeBridge/build/
+/src/InfiniFrame.NativeBridge/Native/build/
+/src/InfiniFrame.NativeBridge/Native/packages/
+/src/InfiniFrame.NativeBridge/Native/cmake-build-debug/
+/src/InfiniFrame.NativeBridge/Native/cmake-build-debug-linux/
+/src/InfiniFrame.NativeBridge/Native/cmake-build-debug-windows/
+/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.cpp
# wwwroot folders from js web based projects
/examples/InfiniFrameExample.WebApp.React/wwwroot/
@@ -364,7 +366,7 @@ healthchecksdb
# Local test/runner virtualenv
/.run/.venv/
-
src/InfiniFrame.Js/wwwroot/InfiniFrame.js
src/InfiniFrame.Js/wwwroot/InfiniFrame.dev.js
-src/InfiniFrame.Js/wwwroot/InfiniFrame.dev.js.map
\ No newline at end of file
+src/InfiniFrame.Js/wwwroot/InfiniFrame.dev.js.map
+
diff --git a/.run/docker-compose-linux.sh.run.xml b/.run/docker-compose-linux.sh.run.xml
deleted file mode 100644
index b190ed4a..00000000
--- a/.run/docker-compose-linux.sh.run.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/docker-linux-arm64-compose.sh.run.xml b/.run/docker-linux-arm64-compose.sh.run.xml
deleted file mode 100644
index ec8a8731..00000000
--- a/.run/docker-linux-arm64-compose.sh.run.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/docker-linux-run-blazorwebview.sh.run.xml b/.run/docker-linux-run-blazorwebview.sh.run.xml
deleted file mode 100644
index 5cfd5c72..00000000
--- a/.run/docker-linux-run-blazorwebview.sh.run.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/docker-linux-run-playwright.sh.run.xml b/.run/docker-linux-run-playwright.sh.run.xml
deleted file mode 100644
index 759f838e..00000000
--- a/.run/docker-linux-run-playwright.sh.run.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/docker-linux-run-tests.sh.run.xml b/.run/docker-linux-run-tests.sh.run.xml
deleted file mode 100644
index a441b66e..00000000
--- a/.run/docker-linux-run-tests.sh.run.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/docker-linux-wayland-compose.sh.run.xml b/.run/docker-linux-wayland-compose.sh.run.xml
deleted file mode 100644
index c77a5e55..00000000
--- a/.run/docker-linux-wayland-compose.sh.run.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/docker-linux-wayland-run-blazorwebview.sh.run.xml b/.run/docker-linux-wayland-run-blazorwebview.sh.run.xml
deleted file mode 100644
index a4994438..00000000
--- a/.run/docker-linux-wayland-run-blazorwebview.sh.run.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.run/example-blazorwebview.sh.run.xml b/.run/example-blazorwebview.sh.run.xml
deleted file mode 100644
index b7fc988d..00000000
--- a/.run/example-blazorwebview.sh.run.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/Directory.Packages.props b/Directory.Packages.props
index cd0ba5a9..08a46edd 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -33,9 +33,9 @@
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/InfiniFrame.GitHubActions.Release.slnf b/InfiniFrame.GitHubActions.Release.slnf
index 9b60f072..fa9085dd 100644
--- a/InfiniFrame.GitHubActions.Release.slnf
+++ b/InfiniFrame.GitHubActions.Release.slnf
@@ -3,9 +3,10 @@
"path": "InfiniFrame.slnx",
"projects": [
"src\\InfiniFrame\\InfiniFrame.csproj",
- "src\\InfiniFrame.Blazor\\InfiniFrame.Blazor.csproj",
"src\\InfiniFrame.BlazorWebView\\InfiniFrame.BlazorWebView.csproj",
+ "src\\InfiniFrame.Blazor\\InfiniFrame.Blazor.csproj",
"src\\InfiniFrame.Js\\InfiniFrame.Js.csproj",
+ "src\\InfiniFrame.NativeBridge\\InfiniFrame.NativeBridge.csproj",
"src\\InfiniFrame.Shared\\InfiniFrame.Shared.csproj",
"src\\InfiniFrame.Tools.Pack\\InfiniFrame.Tools.Pack.csproj",
"src\\InfiniFrame.WebServer\\InfiniFrame.WebServer.csproj"
diff --git a/InfiniFrame.GitHubActions.Testing.Playwright.slnf b/InfiniFrame.GitHubActions.Testing.Playwright.slnf
index a764320c..818509dd 100644
--- a/InfiniFrame.GitHubActions.Testing.Playwright.slnf
+++ b/InfiniFrame.GitHubActions.Testing.Playwright.slnf
@@ -3,10 +3,12 @@
"path": "InfiniFrame.slnx",
"projects": [
"src\\InfiniFrame\\InfiniFrame.csproj",
- "src\\InfiniFrame.Blazor\\InfiniFrame.Blazor.csproj",
"src\\InfiniFrame.BlazorWebView\\InfiniFrame.BlazorWebView.csproj",
+ "src\\InfiniFrame.Blazor\\InfiniFrame.Blazor.csproj",
"src\\InfiniFrame.Js\\InfiniFrame.Js.csproj",
+ "src\\InfiniFrame.NativeBridge\\InfiniFrame.NativeBridge.csproj",
"src\\InfiniFrame.Shared\\InfiniFrame.Shared.csproj",
+ "src\\InfiniFrame.Tools.Pack\\InfiniFrame.Tools.Pack.csproj",
"src\\InfiniFrame.WebServer\\InfiniFrame.WebServer.csproj",
"tests\\InfiniFrameTests.Shared\\InfiniFrameTests.Shared.csproj",
diff --git a/InfiniFrame.GitHubActions.Testing.slnf b/InfiniFrame.GitHubActions.Testing.slnf
index 25673977..c8eef36a 100644
--- a/InfiniFrame.GitHubActions.Testing.slnf
+++ b/InfiniFrame.GitHubActions.Testing.slnf
@@ -3,9 +3,10 @@
"path": "InfiniFrame.slnx",
"projects": [
"src\\InfiniFrame\\InfiniFrame.csproj",
- "src\\InfiniFrame.Blazor\\InfiniFrame.Blazor.csproj",
"src\\InfiniFrame.BlazorWebView\\InfiniFrame.BlazorWebView.csproj",
+ "src\\InfiniFrame.Blazor\\InfiniFrame.Blazor.csproj",
"src\\InfiniFrame.Js\\InfiniFrame.Js.csproj",
+ "src\\InfiniFrame.NativeBridge\\InfiniFrame.NativeBridge.csproj",
"src\\InfiniFrame.Shared\\InfiniFrame.Shared.csproj",
"src\\InfiniFrame.Tools.Pack\\InfiniFrame.Tools.Pack.csproj",
"src\\InfiniFrame.WebServer\\InfiniFrame.WebServer.csproj",
diff --git a/InfiniFrame.GitHubActions.slnf b/InfiniFrame.GitHubActions.slnf
index 5c225a3c..24c209b5 100644
--- a/InfiniFrame.GitHubActions.slnf
+++ b/InfiniFrame.GitHubActions.slnf
@@ -3,13 +3,14 @@
"path": "InfiniFrame.slnx",
"projects": [
"src\\InfiniFrame\\InfiniFrame.csproj",
- "src\\InfiniFrame.Blazor\\InfiniFrame.Blazor.csproj",
"src\\InfiniFrame.BlazorWebView\\InfiniFrame.BlazorWebView.csproj",
+ "src\\InfiniFrame.Blazor\\InfiniFrame.Blazor.csproj",
"src\\InfiniFrame.Js\\InfiniFrame.Js.csproj",
+ "src\\InfiniFrame.NativeBridge\\InfiniFrame.NativeBridge.csproj",
"src\\InfiniFrame.Shared\\InfiniFrame.Shared.csproj",
"src\\InfiniFrame.Tools.Pack\\InfiniFrame.Tools.Pack.csproj",
"src\\InfiniFrame.WebServer\\InfiniFrame.WebServer.csproj",
- "src\\InfiniFrame.Native\\InfiniFrame.Native.proj",
+
"tests\\InfiniFrameTests\\InfiniFrameTests.csproj",
"tests\\InfiniFrameTests.Playwright.WebApp.React\\InfiniFrameTests.Playwright.WebApp.React.csproj",
"tests\\InfiniFrameTests.Playwright.WebApp.Vue\\InfiniFrameTests.Playwright.WebApp.Vue.csproj",
diff --git a/InfiniFrame.slnx b/InfiniFrame.slnx
index f8a9b189..85f47935 100644
--- a/InfiniFrame.slnx
+++ b/InfiniFrame.slnx
@@ -14,11 +14,18 @@
+
+
+
+
+
+
+
@@ -49,44 +56,52 @@
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
@@ -114,6 +129,7 @@
+
@@ -127,6 +143,7 @@
+
@@ -147,7 +164,7 @@
-
+
diff --git a/README.md b/README.md
index ff62a377..174aa63c 100644
--- a/README.md
+++ b/README.md
@@ -224,6 +224,46 @@ Additional compose targets and wrappers are available for local matrix validatio
- `docker/compose/infiniframe-linux-wayland.yml` + `docker/scripts/docker-linux-wayland-*.sh`
- `docker/compose/infiniframe-windows.yml` + `docker/scripts/docker-windows-*.ps1`
+## Local GitHub Actions Harness
+
+You can run a local CI harness with a dedicated `act` runner image:
+
+- `docker/compose/infiniframe-gha-local.yml`
+- `docker/gha-local/Dockerfile`
+- `docker/scripts/docker-gha-local-*.sh`
+
+Build the local runner image:
+
+```bash
+bash docker/scripts/docker-gha-local-compose.sh
+```
+
+```powershell
+.\docker\scripts\docker-gha-local-compose.ps1
+```
+
+Run Linux GitHub Actions test workflow locally with `act`:
+
+```bash
+bash docker/scripts/docker-gha-local-run-linux-actions.sh
+```
+
+```powershell
+.\docker\scripts\docker-gha-local-run-linux-actions.ps1
+```
+
+Run Windows workflow-equivalent validations in local Windows containers:
+
+```powershell
+.\docker\scripts\docker-windows-compose.ps1
+.\docker\scripts\docker-gha-local-run-windows-actions.ps1
+```
+
+Notes:
+
+- `act` cannot run native `runs-on: windows-*` jobs directly. Use the Windows Docker wrappers for local Windows parity.
+- By default local runs set `LOCAL_GHA_SKIP_STATUS=1` to skip GitHub status/check API updates.
+
## Repo History
This repo was originally forked from [Photino.NET](https://github.com/tryphotino/photino.NET) and then the history of
diff --git a/docker/compose/infiniframe-gha-local.yml b/docker/compose/infiniframe-gha-local.yml
new file mode 100644
index 00000000..71c57bdf
--- /dev/null
+++ b/docker/compose/infiniframe-gha-local.yml
@@ -0,0 +1,18 @@
+name: infiniframe-gha-local
+
+services:
+ gha-local:
+ image: infiniframe/gha-local:latest
+ build:
+ context: ../..
+ dockerfile: docker/gha-local/Dockerfile
+ working_dir: /workspace
+ volumes:
+ - ../../:/workspace
+ - /var/run/docker.sock:/var/run/docker.sock
+ environment:
+ - GITHUB_TOKEN=${GITHUB_TOKEN:-}
+ - ACT_CACHE_DIR=/workspace/.act/cache
+ entrypoint: ["/bin/bash", "-lc"]
+ command:
+ - "sleep infinity"
diff --git a/docker/compose/infiniframe-windows.yml b/docker/compose/infiniframe-windows.yml
index 5b441daa..26515a43 100644
--- a/docker/compose/infiniframe-windows.yml
+++ b/docker/compose/infiniframe-windows.yml
@@ -58,8 +58,27 @@ services:
entrypoint: ["powershell", "-NoLogo", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command"]
command:
- "& C:/src/docker/infiniframe-windows/bootstrap-workspace.ps1 -Source C:/src -Destination C:/work; & C:/work/docker/infiniframe-windows/example-blazorwebview.ps1"
+
+ windows-trim-aot:
+ image: infiniframe/windows:latest
+ build:
+ context: ../..
+ dockerfile: docker/infiniframe-windows/Dockerfile
+ working_dir: C:\work
+ volumes:
+ - ../../:C:\src:ro
+ - infiniframe_windows_trim_aot_work:C:\work
+ environment:
+ - CONFIGURATION=Release
+ - NATIVE_PLATFORM=x64
+ - SKIP_NATIVE_BUILD=1
+ - NUGET_PACKAGES=C:\.nuget\packages
+ entrypoint: ["powershell", "-NoLogo", "-NoProfile", "-ExecutionPolicy", "Bypass", "-Command"]
+ command:
+ - "& C:/src/docker/infiniframe-windows/bootstrap-workspace.ps1 -Source C:/src -Destination C:/work; & C:/work/docker/infiniframe-windows/trim-aot.ps1"
volumes:
infiniframe_windows_tests_work:
infiniframe_windows_playwright_work:
infiniframe_windows_examples_work:
+ infiniframe_windows_trim_aot_work:
diff --git a/docker/gha-local/Dockerfile b/docker/gha-local/Dockerfile
new file mode 100644
index 00000000..c23e1ac4
--- /dev/null
+++ b/docker/gha-local/Dockerfile
@@ -0,0 +1,48 @@
+FROM catthehacker/ubuntu:act-latest
+
+ENV DEBIAN_FRONTEND=noninteractive
+ENV DOTNET_ROOT=/opt/dotnet
+ENV PATH=/opt/dotnet:/usr/local/bin:${PATH}
+ENV ACT_VERSION=0.2.88
+ENV NODE_VERSION=24
+
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ ca-certificates \
+ clang \
+ cmake \
+ curl \
+ git \
+ jq \
+ ninja-build \
+ openjdk-21-jdk \
+ python3 \
+ python3-pip \
+ unzip \
+ vulkan-tools \
+ libvulkan1 \
+ wget \
+ zip \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install .NET SDKs
+RUN curl -fsSL https://dot.net/v1/dotnet-install.sh -o /tmp/dotnet-install.sh \
+ && bash /tmp/dotnet-install.sh --channel 8.0 --install-dir /opt/dotnet \
+ && bash /tmp/dotnet-install.sh --channel 9.0 --install-dir /opt/dotnet \
+ && bash /tmp/dotnet-install.sh --channel 10.0 --install-dir /opt/dotnet \
+ && rm -f /tmp/dotnet-install.sh
+
+# Install Node.js 24
+RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
+ && apt-get update \
+ && apt-get install -y --no-install-recommends nodejs \
+ && npm install -g npm@latest \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install act
+RUN curl -fsSL https://raw.githubusercontent.com/nektos/act/master/install.sh \
+ | bash -s -- -b /usr/local/bin "v${ACT_VERSION}"
+
+WORKDIR /workspace
+
+CMD ["bash", "-lc", "sleep infinity"]
\ No newline at end of file
diff --git a/docker/gha-local/events/ci-testing-linux.json b/docker/gha-local/events/ci-testing-linux.json
new file mode 100644
index 00000000..21e62df5
--- /dev/null
+++ b/docker/gha-local/events/ci-testing-linux.json
@@ -0,0 +1,11 @@
+{
+ "inputs": {
+ "pr_number": "",
+ "run_windows": false,
+ "run_windows_playwright": false,
+ "run_linux": true,
+ "run_macos": false,
+ "run_docs": true,
+ "run_trim_aot": false
+ }
+}
diff --git a/docker/infiniframe-windows/trim-aot.ps1 b/docker/infiniframe-windows/trim-aot.ps1
new file mode 100644
index 00000000..6a1299a1
--- /dev/null
+++ b/docker/infiniframe-windows/trim-aot.ps1
@@ -0,0 +1,60 @@
+$ErrorActionPreference = "Stop"
+. "C:\work\docker\infiniframe-windows\common.ps1"
+
+Initialize-CommonDefaults
+
+$dotnetProps = @(
+ "/p:DisableImplicitNuGetFallbackFolder=true",
+ "/p:RestoreFallbackFolders=",
+ "/p:RestoreAdditionalProjectFallbackFolders=",
+ "/p:GeneratePackageOnBuild=false",
+ "/p:SkipTypeScriptBuild=true"
+)
+
+dotnet restore InfiniFrame.GitHubActions.Release.slnf `
+ --force `
+ --force-evaluate `
+ --configfile $script:NuGetConfigFile `
+ --packages $script:NuGetPackages `
+ /p:NoWarn=NU1503 `
+ $dotnetProps
+
+dotnet build src/InfiniFrame.Shared/InfiniFrame.Shared.csproj `
+ --configuration $script:Configuration `
+ --framework net10.0 `
+ -p:EnableTrimAnalyzer=true `
+ -p:EnableAotAnalyzer=true `
+ $dotnetProps
+
+dotnet build src/InfiniFrame.BlazorWebView/InfiniFrame.BlazorWebView.csproj `
+ --configuration $script:Configuration `
+ --framework net10.0 `
+ -p:EnableTrimAnalyzer=true `
+ -p:EnableAotAnalyzer=true `
+ $dotnetProps
+
+dotnet build src/InfiniFrame.WebServer/InfiniFrame.WebServer.csproj `
+ --configuration $script:Configuration `
+ --framework net10.0 `
+ -p:EnableTrimAnalyzer=true `
+ -p:EnableAotAnalyzer=true `
+ $dotnetProps
+
+dotnet publish examples/InfiniFrameExample.TrimAotSmoke/InfiniFrameExample.TrimAotSmoke.csproj `
+ --configuration $script:Configuration `
+ --framework net10.0 `
+ --runtime win-x64 `
+ $dotnetProps
+
+$publishDir = "examples/InfiniFrameExample.TrimAotSmoke/bin/${script:Configuration}/net10.0/win-x64/publish"
+$output = Join-Path $publishDir "InfiniFrameExample.TrimAotSmoke.exe"
+
+if (Test-Path $output) {
+ Write-Host "NativeAOT smoke output validated: $output"
+ exit 0
+}
+
+$availableExeNames = Get-ChildItem -Path $publishDir -Filter *.exe -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Name
+Write-Host "Expected NativeAOT output not found: $output"
+Write-Host "Available *.exe in publish dir: $($availableExeNames -join ', ')"
+exit 1
diff --git a/docker/scripts/docker-gha-local-compose.ps1 b/docker/scripts/docker-gha-local-compose.ps1
new file mode 100644
index 00000000..939da689
--- /dev/null
+++ b/docker/scripts/docker-gha-local-compose.ps1
@@ -0,0 +1,5 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-gha-local.yml"
+
+docker compose -f $composeFile build --no-cache gha-local
diff --git a/docker/scripts/docker-gha-local-run-linux-actions.ps1 b/docker/scripts/docker-gha-local-run-linux-actions.ps1
new file mode 100644
index 00000000..887884a0
--- /dev/null
+++ b/docker/scripts/docker-gha-local-run-linux-actions.ps1
@@ -0,0 +1,16 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-gha-local.yml"
+$eventFile = "docker/gha-local/events/ci-testing-linux.json"
+
+if (-not $env:LOCAL_GHA_SKIP_STATUS) {
+ $env:LOCAL_GHA_SKIP_STATUS = "1"
+}
+
+$actArgs = if ($env:ACT_EXTRA_ARGS) { $env:ACT_EXTRA_ARGS } else { "" }
+
+docker compose -f $composeFile run --rm `
+ -e LOCAL_GHA_SKIP_STATUS=$env:LOCAL_GHA_SKIP_STATUS `
+ -e GITHUB_TOKEN=$env:GITHUB_TOKEN `
+ gha-local `
+ "act workflow_dispatch -W .github/workflows/ci-testing.yml -e $eventFile --container-architecture linux/amd64 $actArgs"
diff --git a/docker/scripts/docker-gha-local-run-windows-actions.ps1 b/docker/scripts/docker-gha-local-run-windows-actions.ps1
new file mode 100644
index 00000000..60643934
--- /dev/null
+++ b/docker/scripts/docker-gha-local-run-windows-actions.ps1
@@ -0,0 +1,6 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+
+& (Join-Path $scriptDir "docker-windows-run-tests.ps1")
+& (Join-Path $scriptDir "docker-windows-run-playwrighttests.ps1")
+& (Join-Path $scriptDir "docker-windows-run-trim-aot.ps1")
diff --git a/docker/scripts/docker-linux-arm64-compose.ps1 b/docker/scripts/docker-linux-arm64-compose.ps1
new file mode 100644
index 00000000..9add2d03
--- /dev/null
+++ b/docker/scripts/docker-linux-arm64-compose.ps1
@@ -0,0 +1,8 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux-arm64.yml"
+
+docker compose -f $composeFile build --no-cache `
+ linux-arm64-tests `
+ linux-arm64-tests-playwright `
+ linux-arm64-example-blazorwebview
diff --git a/docker/scripts/docker-linux-arm64-compose.sh b/docker/scripts/docker-linux-arm64-compose.sh
deleted file mode 100644
index b0e9d218..00000000
--- a/docker/scripts/docker-linux-arm64-compose.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="$SCRIPT_DIR/../compose/infiniframe-linux-arm64.yml"
-
-docker compose -f "$COMPOSE_FILE" build --no-cache \
- linux-arm64-tests \
- linux-arm64-tests-playwright \
- linux-arm64-example-blazorwebview
diff --git a/docker/scripts/docker-linux-arm64-run-blazorwebview.ps1 b/docker/scripts/docker-linux-arm64-run-blazorwebview.ps1
new file mode 100644
index 00000000..9303c5e4
--- /dev/null
+++ b/docker/scripts/docker-linux-arm64-run-blazorwebview.ps1
@@ -0,0 +1,11 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux-arm64.yml"
+
+$displayValue = if ($env:DISPLAY) { $env:DISPLAY } else { ":0" }
+
+docker compose -f $composeFile run --rm `
+ -e USE_HOST_DISPLAY=1 `
+ -e DISPLAY=$displayValue `
+ -v /tmp/.X11-unix:/tmp/.X11-unix `
+ linux-arm64-example-blazorwebview
diff --git a/docker/scripts/docker-linux-arm64-run-blazorwebview.sh b/docker/scripts/docker-linux-arm64-run-blazorwebview.sh
deleted file mode 100644
index 011e8e86..00000000
--- a/docker/scripts/docker-linux-arm64-run-blazorwebview.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux-arm64.yml"
-
-DISPLAY_VALUE="${DISPLAY:-:0}"
-
-docker compose -f "${COMPOSE_FILE}" run --rm \
- -e USE_HOST_DISPLAY=1 \
- -e DISPLAY="${DISPLAY_VALUE}" \
- -v /tmp/.X11-unix:/tmp/.X11-unix \
- linux-arm64-example-blazorwebview
diff --git a/docker/scripts/docker-linux-arm64-run-playwrighttests.ps1 b/docker/scripts/docker-linux-arm64-run-playwrighttests.ps1
new file mode 100644
index 00000000..f5c4868e
--- /dev/null
+++ b/docker/scripts/docker-linux-arm64-run-playwrighttests.ps1
@@ -0,0 +1,15 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux-arm64.yml"
+
+$displayValue = if ($env:DISPLAY) { $env:DISPLAY } else { ":0" }
+$playwrightVisibleDebugValue = if ($env:PLAYWRIGHT_VISIBLE_DEBUG) { $env:PLAYWRIGHT_VISIBLE_DEBUG } else { "0" }
+$playwrightVisibleDebugSecondsValue = if ($env:PLAYWRIGHT_VISIBLE_DEBUG_SECONDS) { $env:PLAYWRIGHT_VISIBLE_DEBUG_SECONDS } else { "8" }
+
+docker compose -f $composeFile run --rm `
+ -e USE_HOST_DISPLAY=1 `
+ -e DISPLAY=$displayValue `
+ -e PLAYWRIGHT_VISIBLE_DEBUG=$playwrightVisibleDebugValue `
+ -e PLAYWRIGHT_VISIBLE_DEBUG_SECONDS=$playwrightVisibleDebugSecondsValue `
+ -v /tmp/.X11-unix:/tmp/.X11-unix `
+ linux-arm64-tests-playwright
diff --git a/docker/scripts/docker-linux-arm64-run-playwrighttests.sh b/docker/scripts/docker-linux-arm64-run-playwrighttests.sh
deleted file mode 100644
index e32c0210..00000000
--- a/docker/scripts/docker-linux-arm64-run-playwrighttests.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux-arm64.yml"
-
-DISPLAY_VALUE="${DISPLAY:-:0}"
-PLAYWRIGHT_VISIBLE_DEBUG_VALUE="${PLAYWRIGHT_VISIBLE_DEBUG:-0}"
-PLAYWRIGHT_VISIBLE_DEBUG_SECONDS_VALUE="${PLAYWRIGHT_VISIBLE_DEBUG_SECONDS:-8}"
-
-docker compose -f "${COMPOSE_FILE}" run --rm \
- -e USE_HOST_DISPLAY=1 \
- -e DISPLAY="${DISPLAY_VALUE}" \
- -e PLAYWRIGHT_VISIBLE_DEBUG="${PLAYWRIGHT_VISIBLE_DEBUG_VALUE}" \
- -e PLAYWRIGHT_VISIBLE_DEBUG_SECONDS="${PLAYWRIGHT_VISIBLE_DEBUG_SECONDS_VALUE}" \
- -v /tmp/.X11-unix:/tmp/.X11-unix \
- linux-arm64-tests-playwright
diff --git a/docker/scripts/docker-linux-arm64-run-tests.ps1 b/docker/scripts/docker-linux-arm64-run-tests.ps1
new file mode 100644
index 00000000..860dc414
--- /dev/null
+++ b/docker/scripts/docker-linux-arm64-run-tests.ps1
@@ -0,0 +1,11 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux-arm64.yml"
+
+$displayValue = if ($env:DISPLAY) { $env:DISPLAY } else { ":0" }
+
+docker compose -f $composeFile run --rm `
+ -e USE_HOST_DISPLAY=1 `
+ -e DISPLAY=$displayValue `
+ -v /tmp/.X11-unix:/tmp/.X11-unix `
+ linux-arm64-tests
diff --git a/docker/scripts/docker-linux-arm64-run-tests.sh b/docker/scripts/docker-linux-arm64-run-tests.sh
deleted file mode 100644
index ebafd4ec..00000000
--- a/docker/scripts/docker-linux-arm64-run-tests.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux-arm64.yml"
-
-DISPLAY_VALUE="${DISPLAY:-:0}"
-
-docker compose -f "${COMPOSE_FILE}" run --rm \
- -e USE_HOST_DISPLAY=1 \
- -e DISPLAY="${DISPLAY_VALUE}" \
- -v /tmp/.X11-unix:/tmp/.X11-unix \
- linux-arm64-tests
diff --git a/docker/scripts/docker-linux-compose.ps1 b/docker/scripts/docker-linux-compose.ps1
new file mode 100644
index 00000000..4792b7ad
--- /dev/null
+++ b/docker/scripts/docker-linux-compose.ps1
@@ -0,0 +1,8 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux.yml"
+
+docker compose -f $composeFile build --no-cache `
+ linux-tests `
+ linux-tests-playwright `
+ linux-example-blazorwebview
diff --git a/docker/scripts/docker-linux-compose.sh b/docker/scripts/docker-linux-compose.sh
deleted file mode 100644
index 7ce96e94..00000000
--- a/docker/scripts/docker-linux-compose.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="$SCRIPT_DIR/../compose/infiniframe-linux.yml"
-
-docker compose -f "$COMPOSE_FILE" build --no-cache \
- linux-tests \
- linux-tests-playwright \
- linux-example-blazorwebview
diff --git a/docker/scripts/docker-linux-run-blazorwebview.ps1 b/docker/scripts/docker-linux-run-blazorwebview.ps1
new file mode 100644
index 00000000..1de435e6
--- /dev/null
+++ b/docker/scripts/docker-linux-run-blazorwebview.ps1
@@ -0,0 +1,11 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux.yml"
+
+$displayValue = if ($env:DISPLAY) { $env:DISPLAY } else { ":0" }
+
+docker compose -f $composeFile run --rm `
+ -e USE_HOST_DISPLAY=1 `
+ -e DISPLAY=$displayValue `
+ -v /tmp/.X11-unix:/tmp/.X11-unix `
+ linux-example-blazorwebview
diff --git a/docker/scripts/docker-linux-run-blazorwebview.sh b/docker/scripts/docker-linux-run-blazorwebview.sh
deleted file mode 100644
index 3577b443..00000000
--- a/docker/scripts/docker-linux-run-blazorwebview.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux.yml"
-
-DISPLAY_VALUE="${DISPLAY:-:0}"
-
-docker compose -f "${COMPOSE_FILE}" run --rm \
- -e USE_HOST_DISPLAY=1 \
- -e DISPLAY="${DISPLAY_VALUE}" \
- -v /tmp/.X11-unix:/tmp/.X11-unix \
- linux-example-blazorwebview
diff --git a/docker/scripts/docker-linux-run-playwrighttests.ps1 b/docker/scripts/docker-linux-run-playwrighttests.ps1
new file mode 100644
index 00000000..998f307b
--- /dev/null
+++ b/docker/scripts/docker-linux-run-playwrighttests.ps1
@@ -0,0 +1,15 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux.yml"
+
+$displayValue = if ($env:DISPLAY) { $env:DISPLAY } else { ":0" }
+$playwrightVisibleDebugValue = if ($env:PLAYWRIGHT_VISIBLE_DEBUG) { $env:PLAYWRIGHT_VISIBLE_DEBUG } else { "0" }
+$playwrightVisibleDebugSecondsValue = if ($env:PLAYWRIGHT_VISIBLE_DEBUG_SECONDS) { $env:PLAYWRIGHT_VISIBLE_DEBUG_SECONDS } else { "8" }
+
+docker compose -f $composeFile run --rm `
+ -e USE_HOST_DISPLAY=1 `
+ -e DISPLAY=$displayValue `
+ -e PLAYWRIGHT_VISIBLE_DEBUG=$playwrightVisibleDebugValue `
+ -e PLAYWRIGHT_VISIBLE_DEBUG_SECONDS=$playwrightVisibleDebugSecondsValue `
+ -v /tmp/.X11-unix:/tmp/.X11-unix `
+ linux-tests-playwright
diff --git a/docker/scripts/docker-linux-run-playwrighttests.sh b/docker/scripts/docker-linux-run-playwrighttests.sh
deleted file mode 100644
index 894f1e7c..00000000
--- a/docker/scripts/docker-linux-run-playwrighttests.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux.yml"
-
-DISPLAY_VALUE="${DISPLAY:-:0}"
-PLAYWRIGHT_VISIBLE_DEBUG_VALUE="${PLAYWRIGHT_VISIBLE_DEBUG:-0}"
-PLAYWRIGHT_VISIBLE_DEBUG_SECONDS_VALUE="${PLAYWRIGHT_VISIBLE_DEBUG_SECONDS:-8}"
-
-docker compose -f "${COMPOSE_FILE}" run --rm \
- -e USE_HOST_DISPLAY=1 \
- -e DISPLAY="${DISPLAY_VALUE}" \
- -e PLAYWRIGHT_VISIBLE_DEBUG="${PLAYWRIGHT_VISIBLE_DEBUG_VALUE}" \
- -e PLAYWRIGHT_VISIBLE_DEBUG_SECONDS="${PLAYWRIGHT_VISIBLE_DEBUG_SECONDS_VALUE}" \
- -v /tmp/.X11-unix:/tmp/.X11-unix \
- linux-tests-playwright
diff --git a/docker/scripts/docker-linux-run-tests.ps1 b/docker/scripts/docker-linux-run-tests.ps1
new file mode 100644
index 00000000..2762814e
--- /dev/null
+++ b/docker/scripts/docker-linux-run-tests.ps1
@@ -0,0 +1,11 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux.yml"
+
+$displayValue = if ($env:DISPLAY) { $env:DISPLAY } else { ":0" }
+
+docker compose -f $composeFile run --rm `
+ -e USE_HOST_DISPLAY=1 `
+ -e DISPLAY=$displayValue `
+ -v /tmp/.X11-unix:/tmp/.X11-unix `
+ linux-tests
diff --git a/docker/scripts/docker-linux-run-tests.sh b/docker/scripts/docker-linux-run-tests.sh
deleted file mode 100644
index ffa41ebb..00000000
--- a/docker/scripts/docker-linux-run-tests.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux.yml"
-
-DISPLAY_VALUE="${DISPLAY:-:0}"
-
-docker compose -f "${COMPOSE_FILE}" run --rm \
- -e USE_HOST_DISPLAY=1 \
- -e DISPLAY="${DISPLAY_VALUE}" \
- -v /tmp/.X11-unix:/tmp/.X11-unix \
- linux-tests
diff --git a/docker/scripts/docker-linux-wayland-compose.ps1 b/docker/scripts/docker-linux-wayland-compose.ps1
new file mode 100644
index 00000000..cf337cb3
--- /dev/null
+++ b/docker/scripts/docker-linux-wayland-compose.ps1
@@ -0,0 +1,8 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux-wayland.yml"
+
+docker compose -f $composeFile build --no-cache `
+ linux-wayland-tests `
+ linux-wayland-tests-playwright `
+ linux-wayland-example-blazorwebview
diff --git a/docker/scripts/docker-linux-wayland-compose.sh b/docker/scripts/docker-linux-wayland-compose.sh
deleted file mode 100644
index 309f7b47..00000000
--- a/docker/scripts/docker-linux-wayland-compose.sh
+++ /dev/null
@@ -1,10 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="$SCRIPT_DIR/../compose/infiniframe-linux-wayland.yml"
-
-docker compose -f "$COMPOSE_FILE" build --no-cache \
- linux-wayland-tests \
- linux-wayland-tests-playwright \
- linux-wayland-example-blazorwebview
diff --git a/docker/scripts/docker-linux-wayland-run-blazorwebview.ps1 b/docker/scripts/docker-linux-wayland-run-blazorwebview.ps1
new file mode 100644
index 00000000..9cfec10f
--- /dev/null
+++ b/docker/scripts/docker-linux-wayland-run-blazorwebview.ps1
@@ -0,0 +1,57 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux-wayland.yml"
+
+$waylandDisplayValue = if ($env:WAYLAND_DISPLAY) { $env:WAYLAND_DISPLAY } else { "wayland-0" }
+if ($env:XDG_RUNTIME_DIR) {
+ $xdgRuntimeDirValue = $env:XDG_RUNTIME_DIR.TrimEnd('/')
+}
+else {
+ $uid = "1000"
+ try {
+ $uid = (id -u).Trim()
+ }
+ catch {
+ $uid = "1000"
+ }
+ $xdgRuntimeDirValue = "/run/user/$uid"
+}
+$useHostDisplayValue = if ($env:USE_HOST_DISPLAY) { $env:USE_HOST_DISPLAY } else { "0" }
+$waylandSocketPath = "$xdgRuntimeDirValue/$waylandDisplayValue"
+$displayValue = if ($env:DISPLAY) { $env:DISPLAY } else { ":0" }
+$useXrunnerValue = if ($env:USE_XRUNNER) { $env:USE_XRUNNER } else { "1" }
+$serviceName = "linux-wayland-example-blazorwebview"
+$runArgs = @("run", "--rm")
+
+if ($useHostDisplayValue -eq "1") {
+ Write-Host "Using host Wayland mode."
+ if (-not (Test-Path $waylandSocketPath)) {
+ Write-Host "Host Wayland socket not found: $waylandSocketPath"
+ Write-Host "Set USE_HOST_DISPLAY=0 to use internal Weston mode."
+ exit 1
+ }
+ $runArgs += @(
+ "-e", "USE_HOST_DISPLAY=1",
+ "-e", "WAYLAND_DISPLAY=$waylandDisplayValue",
+ "-e", "XDG_RUNTIME_DIR=$xdgRuntimeDirValue",
+ "-e", "GDK_BACKEND=wayland",
+ "-e", "QT_QPA_PLATFORM=wayland",
+ "-e", "XDG_SESSION_TYPE=wayland",
+ "-v", "${xdgRuntimeDirValue}:$xdgRuntimeDirValue"
+ )
+}
+else {
+ Write-Host "Using internal Weston Wayland mode."
+ $runArgs += @("-e", "USE_HOST_DISPLAY=0")
+ if ($useXrunnerValue -eq "1") {
+ Write-Host "Rendering Weston to host X runner via DISPLAY=$displayValue."
+ $runArgs += @(
+ "-e", "WESTON_BACKEND=x11-backend.so",
+ "-e", "WESTON_ENABLE_XWAYLAND=0",
+ "-e", "DISPLAY=$displayValue",
+ "-v", "/tmp/.X11-unix:/tmp/.X11-unix"
+ )
+ }
+}
+
+docker compose -f $composeFile @runArgs $serviceName
diff --git a/docker/scripts/docker-linux-wayland-run-blazorwebview.sh b/docker/scripts/docker-linux-wayland-run-blazorwebview.sh
deleted file mode 100644
index c4ffd2fe..00000000
--- a/docker/scripts/docker-linux-wayland-run-blazorwebview.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux-wayland.yml"
-
-WAYLAND_DISPLAY_VALUE="${WAYLAND_DISPLAY:-wayland-0}"
-XDG_RUNTIME_DIR_VALUE="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
-XDG_RUNTIME_DIR_VALUE="${XDG_RUNTIME_DIR_VALUE%/}"
-USE_HOST_DISPLAY_VALUE="${USE_HOST_DISPLAY:-0}"
-WAYLAND_SOCKET_PATH="${XDG_RUNTIME_DIR_VALUE}/${WAYLAND_DISPLAY_VALUE}"
-DISPLAY_VALUE="${DISPLAY:-:0}"
-USE_XRUNNER_VALUE="${USE_XRUNNER:-1}"
-RUN_ARGS=(run --rm)
-SERVICE_NAME="linux-wayland-example-blazorwebview"
-
-if [[ "${USE_HOST_DISPLAY_VALUE}" == "1" ]]; then
- echo "Using host Wayland mode."
- if [[ ! -S "${WAYLAND_SOCKET_PATH}" ]]; then
- echo "Host Wayland socket not found: ${WAYLAND_SOCKET_PATH}"
- echo "Set USE_HOST_DISPLAY=0 to use internal Weston mode."
- exit 1
- fi
- RUN_ARGS+=(
- -e USE_HOST_DISPLAY=1
- -e WAYLAND_DISPLAY="${WAYLAND_DISPLAY_VALUE}"
- -e XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR_VALUE}"
- -e GDK_BACKEND=wayland
- -e QT_QPA_PLATFORM=wayland
- -e XDG_SESSION_TYPE=wayland
- -v "${XDG_RUNTIME_DIR_VALUE}:${XDG_RUNTIME_DIR_VALUE}"
- )
-else
- echo "Using internal Weston Wayland mode."
- RUN_ARGS+=(
- -e USE_HOST_DISPLAY=0
- )
- if [[ "${USE_XRUNNER_VALUE}" == "1" ]]; then
- echo "Rendering Weston to host X runner via DISPLAY=${DISPLAY_VALUE}."
- RUN_ARGS+=(
- -e WESTON_BACKEND=x11-backend.so
- -e WESTON_ENABLE_XWAYLAND=0
- -e DISPLAY="${DISPLAY_VALUE}"
- -v /tmp/.X11-unix:/tmp/.X11-unix
- )
- fi
-fi
-
-docker compose -f "${COMPOSE_FILE}" "${RUN_ARGS[@]}" "${SERVICE_NAME}"
diff --git a/docker/scripts/docker-linux-wayland-run-playwrighttests.ps1 b/docker/scripts/docker-linux-wayland-run-playwrighttests.ps1
new file mode 100644
index 00000000..b041e8ca
--- /dev/null
+++ b/docker/scripts/docker-linux-wayland-run-playwrighttests.ps1
@@ -0,0 +1,53 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux-wayland.yml"
+
+$waylandDisplayValue = if ($env:WAYLAND_DISPLAY) { $env:WAYLAND_DISPLAY } else { "wayland-0" }
+if ($env:XDG_RUNTIME_DIR) {
+ $xdgRuntimeDirValue = $env:XDG_RUNTIME_DIR.TrimEnd('/')
+}
+else {
+ $uid = "1000"
+ try {
+ $uid = (id -u).Trim()
+ }
+ catch {
+ $uid = "1000"
+ }
+ $xdgRuntimeDirValue = "/run/user/$uid"
+}
+$playwrightVisibleDebugValue = if ($env:PLAYWRIGHT_VISIBLE_DEBUG) { $env:PLAYWRIGHT_VISIBLE_DEBUG } else { "0" }
+$playwrightVisibleDebugSecondsValue = if ($env:PLAYWRIGHT_VISIBLE_DEBUG_SECONDS) { $env:PLAYWRIGHT_VISIBLE_DEBUG_SECONDS } else { "8" }
+$useHostDisplayValue = if ($env:USE_HOST_DISPLAY) { $env:USE_HOST_DISPLAY } else { "0" }
+$waylandSocketPath = "$xdgRuntimeDirValue/$waylandDisplayValue"
+$serviceName = "linux-wayland-tests-playwright"
+$runArgs = @("run", "--rm")
+
+if ($useHostDisplayValue -eq "1") {
+ Write-Host "Using host Wayland mode."
+ if (-not (Test-Path $waylandSocketPath)) {
+ Write-Host "Host Wayland socket not found: $waylandSocketPath"
+ Write-Host "Set USE_HOST_DISPLAY=0 to use internal Weston mode."
+ exit 1
+ }
+ $runArgs += @(
+ "-e", "USE_HOST_DISPLAY=1",
+ "-e", "WAYLAND_DISPLAY=$waylandDisplayValue",
+ "-e", "XDG_RUNTIME_DIR=$xdgRuntimeDirValue",
+ "-e", "GDK_BACKEND=wayland",
+ "-e", "QT_QPA_PLATFORM=wayland",
+ "-e", "XDG_SESSION_TYPE=wayland",
+ "-v", "${xdgRuntimeDirValue}:$xdgRuntimeDirValue"
+ )
+}
+else {
+ Write-Host "Using internal Weston Wayland mode."
+ $runArgs += @("-e", "USE_HOST_DISPLAY=0")
+}
+
+$runArgs += @(
+ "-e", "PLAYWRIGHT_VISIBLE_DEBUG=$playwrightVisibleDebugValue",
+ "-e", "PLAYWRIGHT_VISIBLE_DEBUG_SECONDS=$playwrightVisibleDebugSecondsValue"
+)
+
+docker compose -f $composeFile @runArgs $serviceName
diff --git a/docker/scripts/docker-linux-wayland-run-playwrighttests.sh b/docker/scripts/docker-linux-wayland-run-playwrighttests.sh
deleted file mode 100644
index 38eb10e8..00000000
--- a/docker/scripts/docker-linux-wayland-run-playwrighttests.sh
+++ /dev/null
@@ -1,45 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux-wayland.yml"
-
-WAYLAND_DISPLAY_VALUE="${WAYLAND_DISPLAY:-wayland-0}"
-XDG_RUNTIME_DIR_VALUE="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
-XDG_RUNTIME_DIR_VALUE="${XDG_RUNTIME_DIR_VALUE%/}"
-PLAYWRIGHT_VISIBLE_DEBUG_VALUE="${PLAYWRIGHT_VISIBLE_DEBUG:-0}"
-PLAYWRIGHT_VISIBLE_DEBUG_SECONDS_VALUE="${PLAYWRIGHT_VISIBLE_DEBUG_SECONDS:-8}"
-USE_HOST_DISPLAY_VALUE="${USE_HOST_DISPLAY:-0}"
-WAYLAND_SOCKET_PATH="${XDG_RUNTIME_DIR_VALUE}/${WAYLAND_DISPLAY_VALUE}"
-RUN_ARGS=(run --rm)
-SERVICE_NAME="linux-wayland-tests-playwright"
-
-if [[ "${USE_HOST_DISPLAY_VALUE}" == "1" ]]; then
- echo "Using host Wayland mode."
- if [[ ! -S "${WAYLAND_SOCKET_PATH}" ]]; then
- echo "Host Wayland socket not found: ${WAYLAND_SOCKET_PATH}"
- echo "Set USE_HOST_DISPLAY=0 to use internal Weston mode."
- exit 1
- fi
- RUN_ARGS+=(
- -e USE_HOST_DISPLAY=1
- -e WAYLAND_DISPLAY="${WAYLAND_DISPLAY_VALUE}"
- -e XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR_VALUE}"
- -e GDK_BACKEND=wayland
- -e QT_QPA_PLATFORM=wayland
- -e XDG_SESSION_TYPE=wayland
- -v "${XDG_RUNTIME_DIR_VALUE}:${XDG_RUNTIME_DIR_VALUE}"
- )
-else
- echo "Using internal Weston Wayland mode."
- RUN_ARGS+=(
- -e USE_HOST_DISPLAY=0
- )
-fi
-
-RUN_ARGS+=(
- -e PLAYWRIGHT_VISIBLE_DEBUG="${PLAYWRIGHT_VISIBLE_DEBUG_VALUE}"
- -e PLAYWRIGHT_VISIBLE_DEBUG_SECONDS="${PLAYWRIGHT_VISIBLE_DEBUG_SECONDS_VALUE}"
-)
-
-docker compose -f "${COMPOSE_FILE}" "${RUN_ARGS[@]}" "${SERVICE_NAME}"
diff --git a/docker/scripts/docker-linux-wayland-run-tests.ps1 b/docker/scripts/docker-linux-wayland-run-tests.ps1
new file mode 100644
index 00000000..92b6e28a
--- /dev/null
+++ b/docker/scripts/docker-linux-wayland-run-tests.ps1
@@ -0,0 +1,46 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-linux-wayland.yml"
+
+$waylandDisplayValue = if ($env:WAYLAND_DISPLAY) { $env:WAYLAND_DISPLAY } else { "wayland-0" }
+if ($env:XDG_RUNTIME_DIR) {
+ $xdgRuntimeDirValue = $env:XDG_RUNTIME_DIR.TrimEnd('/')
+}
+else {
+ $uid = "1000"
+ try {
+ $uid = (id -u).Trim()
+ }
+ catch {
+ $uid = "1000"
+ }
+ $xdgRuntimeDirValue = "/run/user/$uid"
+}
+$useHostDisplayValue = if ($env:USE_HOST_DISPLAY) { $env:USE_HOST_DISPLAY } else { "0" }
+$waylandSocketPath = "$xdgRuntimeDirValue/$waylandDisplayValue"
+$serviceName = "linux-wayland-tests"
+$runArgs = @("run", "--rm")
+
+if ($useHostDisplayValue -eq "1") {
+ Write-Host "Using host Wayland mode."
+ if (-not (Test-Path $waylandSocketPath)) {
+ Write-Host "Host Wayland socket not found: $waylandSocketPath"
+ Write-Host "Set USE_HOST_DISPLAY=0 to use internal Weston mode."
+ exit 1
+ }
+ $runArgs += @(
+ "-e", "USE_HOST_DISPLAY=1",
+ "-e", "WAYLAND_DISPLAY=$waylandDisplayValue",
+ "-e", "XDG_RUNTIME_DIR=$xdgRuntimeDirValue",
+ "-e", "GDK_BACKEND=wayland",
+ "-e", "QT_QPA_PLATFORM=wayland",
+ "-e", "XDG_SESSION_TYPE=wayland",
+ "-v", "${xdgRuntimeDirValue}:$xdgRuntimeDirValue"
+ )
+}
+else {
+ Write-Host "Using internal Weston Wayland mode."
+ $runArgs += @("-e", "USE_HOST_DISPLAY=0")
+}
+
+docker compose -f $composeFile @runArgs $serviceName
diff --git a/docker/scripts/docker-linux-wayland-run-tests.sh b/docker/scripts/docker-linux-wayland-run-tests.sh
deleted file mode 100644
index 6cbaebc3..00000000
--- a/docker/scripts/docker-linux-wayland-run-tests.sh
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env bash
-set -euo pipefail
-
-SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
-COMPOSE_FILE="${SCRIPT_DIR}/../compose/infiniframe-linux-wayland.yml"
-
-WAYLAND_DISPLAY_VALUE="${WAYLAND_DISPLAY:-wayland-0}"
-XDG_RUNTIME_DIR_VALUE="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
-XDG_RUNTIME_DIR_VALUE="${XDG_RUNTIME_DIR_VALUE%/}"
-USE_HOST_DISPLAY_VALUE="${USE_HOST_DISPLAY:-0}"
-WAYLAND_SOCKET_PATH="${XDG_RUNTIME_DIR_VALUE}/${WAYLAND_DISPLAY_VALUE}"
-RUN_ARGS=(run --rm)
-SERVICE_NAME="linux-wayland-tests"
-
-if [[ "${USE_HOST_DISPLAY_VALUE}" == "1" ]]; then
- echo "Using host Wayland mode."
- if [[ ! -S "${WAYLAND_SOCKET_PATH}" ]]; then
- echo "Host Wayland socket not found: ${WAYLAND_SOCKET_PATH}"
- echo "Set USE_HOST_DISPLAY=0 to use internal Weston mode."
- exit 1
- fi
- RUN_ARGS+=(
- -e USE_HOST_DISPLAY=1
- -e WAYLAND_DISPLAY="${WAYLAND_DISPLAY_VALUE}"
- -e XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR_VALUE}"
- -e GDK_BACKEND=wayland
- -e QT_QPA_PLATFORM=wayland
- -e XDG_SESSION_TYPE=wayland
- -v "${XDG_RUNTIME_DIR_VALUE}:${XDG_RUNTIME_DIR_VALUE}"
- )
-else
- echo "Using internal Weston Wayland mode."
- RUN_ARGS+=(
- -e USE_HOST_DISPLAY=0
- )
-fi
-
-docker compose -f "${COMPOSE_FILE}" "${RUN_ARGS[@]}" "${SERVICE_NAME}"
diff --git a/docker/scripts/docker-windows-compose.ps1 b/docker/scripts/docker-windows-compose.ps1
index 4162cae6..9dd0ef9e 100644
--- a/docker/scripts/docker-windows-compose.ps1
+++ b/docker/scripts/docker-windows-compose.ps1
@@ -7,4 +7,5 @@ $env:COMPOSE_DOCKER_CLI_BUILD = "0"
docker compose -f $composeFile build --no-cache `
windows-tests `
windows-tests-playwright `
- windows-example-blazorwebview
+ windows-example-blazorwebview `
+ windows-trim-aot
diff --git a/docker/scripts/docker-windows-run-trim-aot.ps1 b/docker/scripts/docker-windows-run-trim-aot.ps1
new file mode 100644
index 00000000..131359a7
--- /dev/null
+++ b/docker/scripts/docker-windows-run-trim-aot.ps1
@@ -0,0 +1,5 @@
+$ErrorActionPreference = "Stop"
+$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$composeFile = Join-Path $scriptDir "..\compose\infiniframe-windows.yml"
+
+docker compose -f $composeFile run --rm windows-trim-aot
diff --git a/examples/InfiniFrameExample.WebApp.Vue/InfiniFrameExample.WebApp.Vue.csproj b/examples/InfiniFrameExample.WebApp.Vue/InfiniFrameExample.WebApp.Vue.csproj
index a24bf847..352280b9 100644
--- a/examples/InfiniFrameExample.WebApp.Vue/InfiniFrameExample.WebApp.Vue.csproj
+++ b/examples/InfiniFrameExample.WebApp.Vue/InfiniFrameExample.WebApp.Vue.csproj
@@ -1,4 +1,9 @@
-
+
+
+
+ $(MSBuildProjectDirectory)/Source/InfiniFrame.Vue
+ $(FrontendDirectory)/package-lock.json
+
@@ -12,14 +17,19 @@
-
+
-
-
-
-
+
+
+
+
+
diff --git a/native-vendor-deps.json b/native-vendor-deps.json
index 56c17204..e9d736af 100644
--- a/native-vendor-deps.json
+++ b/native-vendor-deps.json
@@ -7,18 +7,18 @@
"assets": [
{
"asset": "simdjson.h",
- "destination": "src/InfiniFrame.Native/Dependencies/simdjson/simdjson.h"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/simdjson.h"
},
{
"asset": "simdjson.cpp",
- "destination": "src/InfiniFrame.Native/Dependencies/simdjson/simdjson.cpp"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/simdjson.cpp"
}
],
"source_files": [],
"license_files": [
{
"source": "https://raw.githubusercontent.com/simdjson/simdjson/{tag}/LICENSE",
- "destination": "src/InfiniFrame.Native/Dependencies/simdjson/LICENSE"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/LICENSE"
}
]
},
@@ -29,26 +29,26 @@
"assets": [
{
"asset": "simdutf.h",
- "destination": "src/InfiniFrame.Native/Dependencies/simdutf/simdutf.h"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h"
},
{
"asset": "simdutf.cpp",
- "destination": "src/InfiniFrame.Native/Dependencies/simdutf/simdutf.cpp"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.cpp"
},
{
"asset": "simdutf_c.h",
- "destination": "src/InfiniFrame.Native/Dependencies/simdutf/simdutf_c.h"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf_c.h"
}
],
"source_files": [],
"license_files": [
{
"source": "https://raw.githubusercontent.com/simdutf/simdutf/{tag}/LICENSE-MIT",
- "destination": "src/InfiniFrame.Native/Dependencies/simdutf/LICENSE-MIT"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/LICENSE-MIT"
},
{
"source": "https://raw.githubusercontent.com/simdutf/simdutf/{tag}/LICENSE-APACHE",
- "destination": "src/InfiniFrame.Native/Dependencies/simdutf/LICENSE-APACHE"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/LICENSE-APACHE"
}
]
},
@@ -60,17 +60,17 @@
"source_files": [
{
"source": "https://raw.githubusercontent.com/mohabouje/WinToast/{tag}/include/wintoastlib.h",
- "destination": "src/InfiniFrame.Native/Dependencies/wintoastlib/wintoastlib.h"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/wintoastlib.h"
},
{
"source": "https://raw.githubusercontent.com/mohabouje/WinToast/{tag}/src/wintoastlib.cpp",
- "destination": "src/InfiniFrame.Native/Dependencies/wintoastlib/wintoastlib.cpp"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/wintoastlib.cpp"
}
],
"license_files": [
{
"source": "https://raw.githubusercontent.com/mohabouje/WinToast/{tag}/LICENSE.txt",
- "destination": "src/InfiniFrame.Native/Dependencies/wintoastlib/LICENSE.txt"
+ "destination": "src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/LICENSE.txt"
}
]
}
diff --git a/scripts/BuildFrontend.mjs b/scripts/BuildFrontend.mjs
index 3f99bc99..9e7207a3 100644
--- a/scripts/BuildFrontend.mjs
+++ b/scripts/BuildFrontend.mjs
@@ -37,24 +37,29 @@ function isProcessRunning(processId) {
try {
process.kill(processId, 0);
return true;
- } catch {
- return false;
+ } catch (error) {
+ return error?.code === 'EPERM';
}
}
function shouldRemoveExistingLock() {
const ownerFile = path.join(lockDirectory, 'owner.txt');
+ const staleLockThresholdMilliseconds = 10 * 60 * 1000;
if (existsSync(ownerFile)) {
const ownerProcessId = Number.parseInt(readFileSync(ownerFile, 'utf8'), 10);
- if (!isProcessRunning(ownerProcessId)) {
+ if (Number.isInteger(ownerProcessId) && !isProcessRunning(ownerProcessId)) {
return true;
}
+
+ if (Number.isInteger(ownerProcessId)) {
+ return false;
+ }
}
try {
const lockAgeMilliseconds = Date.now() - statSync(lockDirectory).mtimeMs;
- return lockAgeMilliseconds > 60 * 1000;
+ return lockAgeMilliseconds > staleLockThresholdMilliseconds;
} catch (error) {
if (error?.code === 'ENOENT') {
return false;
diff --git a/scripts/clean.ps1 b/scripts/clean.ps1
new file mode 100644
index 00000000..b15dede1
--- /dev/null
+++ b/scripts/clean.ps1
@@ -0,0 +1,13 @@
+$Root = Join-Path $PSScriptRoot ".."
+
+Get-Process dotnet,MSBuild,vstest,playwright,node -ErrorAction SilentlyContinue |
+ Stop-Process -Force -ErrorAction SilentlyContinue
+
+Get-ChildItem -Path $Root -Directory -Recurse |
+ Where-Object { $_.Name -in @('bin', 'obj') } |
+ ForEach-Object {
+ Write-Host "Deleting $($_.FullName)"
+ Remove-Item $_.FullName -Recurse -Force -ErrorAction SilentlyContinue
+ }
+
+Write-Host "Done cleaning bin/obj folders."
\ No newline at end of file
diff --git a/src/InfiniFrame.Blazor/Components/InfiniFrameWindowDragArea.razor b/src/InfiniFrame.Blazor/Components/InfiniFrameWindowDragArea.razor
index 70034cf7..73a73a8b 100644
--- a/src/InfiniFrame.Blazor/Components/InfiniFrameWindowDragArea.razor
+++ b/src/InfiniFrame.Blazor/Components/InfiniFrameWindowDragArea.razor
@@ -1,7 +1,7 @@
@* ------------------------------------------------------------------------------------------------------------------ *@
@* Imports
@* ------------------------------------------------------------------------------------------------------------------ *@
-@using InfiniFrame.Native
+@using InfiniFrame.NativeBridge
@using Microsoft.AspNetCore.Components.Web
@using System.Drawing
diff --git a/src/InfiniFrame.Native/.idea/cmake.xml b/src/InfiniFrame.Native/.idea/cmake.xml
deleted file mode 100644
index 9d6dce12..00000000
--- a/src/InfiniFrame.Native/.idea/cmake.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/InfiniFrame.Native/InfiniFrame.Native.proj b/src/InfiniFrame.Native/InfiniFrame.Native.proj
deleted file mode 100644
index 6f220fc0..00000000
--- a/src/InfiniFrame.Native/InfiniFrame.Native.proj
+++ /dev/null
@@ -1,117 +0,0 @@
-
-
-
-
-
- None
-
- $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))
- $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))
- $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))
-
- $(Platform)
- x64
-
-
- x64
- arm64
-
-
- x64
-
-
- x86_64
- arm64
-
- build/$(CMakeArch)/$(Configuration)
- windows
- linux
- osx
-
-
- $(SolutionDir)artifacts/native/$(CMakeOSDir)/$(CMakeArch)/$(Configuration)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/InfiniFrame.Native/cmake/Build.InfiniFrameJs.Impl.cmake b/src/InfiniFrame.Native/cmake/Build.InfiniFrameJs.Impl.cmake
deleted file mode 100644
index 205b3907..00000000
--- a/src/InfiniFrame.Native/cmake/Build.InfiniFrameJs.Impl.cmake
+++ /dev/null
@@ -1,39 +0,0 @@
-foreach(required_var NPM_EXECUTABLE JS_PROJECT_DIR JS_OUTPUT)
- if(NOT DEFINED ${required_var} OR "${${required_var}}" STREQUAL "")
- message(FATAL_ERROR "${required_var} is required")
- endif()
-endforeach()
-
-function(run_npm result_var)
- if(WIN32)
- execute_process(
- COMMAND cmd.exe /D /C call "${NPM_EXECUTABLE}" ${ARGN}
- WORKING_DIRECTORY "${JS_PROJECT_DIR}"
- RESULT_VARIABLE local_result
- )
- else()
- execute_process(
- COMMAND "${NPM_EXECUTABLE}" ${ARGN}
- WORKING_DIRECTORY "${JS_PROJECT_DIR}"
- RESULT_VARIABLE local_result
- )
- endif()
-
- set(${result_var} "${local_result}" PARENT_SCOPE)
-endfunction()
-
-run_npm(npm_ci_result ci)
-
-if(NOT npm_ci_result EQUAL 0)
- message(FATAL_ERROR "npm ci failed with exit code ${npm_ci_result}")
-endif()
-
-run_npm(npm_build_result run build)
-
-if(NOT npm_build_result EQUAL 0)
- message(FATAL_ERROR "npm run build failed with exit code ${npm_build_result}")
-endif()
-
-if(NOT EXISTS "${JS_OUTPUT}")
- message(FATAL_ERROR "JS build completed but did not create expected output: ${JS_OUTPUT}")
-endif()
diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj
new file mode 100644
index 00000000..0423a296
--- /dev/null
+++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj
@@ -0,0 +1,205 @@
+
+
+
+ InfiniLore.InfiniFrame.NativeBridge
+ Library
+
+ true
+
+ x64
+ $(Platform)
+
+ windows
+ linux
+ osx
+
+
+ $(MSBuildThisFileDirectory)artifacts\native\$(NativePlatform)\$(NativeArch)\$(Configuration)\.build.stamp
+
+ $(MSBuildThisFileDirectory)artifacts\native
+ false
+
+ $(NativeOutputRoot)\windows\x64\$(Configuration)
+ $(NativeOutputRoot)\windows\arm64\$(Configuration)
+ $(NativeOutputRoot)\linux\x64\$(Configuration)
+ $(NativeOutputRoot)\linux\arm64\$(Configuration)
+ $(NativeOutputRoot)\osx\x64\$(Configuration)
+ $(NativeOutputRoot)\osx\arm64\$(Configuration)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj.DotSettings b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj.DotSettings
new file mode 100644
index 00000000..fd1a4a53
--- /dev/null
+++ b/src/InfiniFrame.NativeBridge/InfiniFrame.NativeBridge.csproj.DotSettings
@@ -0,0 +1,3 @@
+
+ True
+ True
\ No newline at end of file
diff --git a/src/InfiniFrame.Shared/Native/InfiniFrameNativeArtifactManifest.cs b/src/InfiniFrame.NativeBridge/Managed/ArtifactManifest.cs
similarity index 84%
rename from src/InfiniFrame.Shared/Native/InfiniFrameNativeArtifactManifest.cs
rename to src/InfiniFrame.NativeBridge/Managed/ArtifactManifest.cs
index 462c7d33..9c69401d 100644
--- a/src/InfiniFrame.Shared/Native/InfiniFrameNativeArtifactManifest.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/ArtifactManifest.cs
@@ -3,29 +3,21 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-// ReSharper disable once CheckNamespace
-namespace InfiniFrame;
+namespace InfiniFrame.NativeBridge;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
///
/// Shared manifest for native artifact filenames used by pack and bootstrap flows.
///
-public static class InfiniFrameNativeArtifactManifest {
- // ReSharper disable once UnusedMember.Global
+public static class ArtifactManifest {
public const string NativeLibraryName = "InfiniFrame.Native";
- // ReSharper disable once UnusedMember.Global
public const string WindowsNativeFileName = "InfiniFrame.Native.dll";
- // ReSharper disable once UnusedMember.Global
public const string WindowsLoaderLibraryName = "WebView2Loader";
- // ReSharper disable once UnusedMember.Global
public const string WindowsLoaderFileName = "WebView2Loader.dll";
- // ReSharper disable once UnusedMember.Global
public const string LinuxNativeFileName = "InfiniFrame.Native.so";
- // ReSharper disable once UnusedMember.Global
public const string OsxNativeFileName = "InfiniFrame.Native.dylib";
- // ReSharper disable once UnusedMember.Global
public static readonly NativeRidArtifact[] RidArtifacts = [
new("win-", WindowsNativeFileName),
new("win-", WindowsLoaderFileName),
@@ -33,7 +25,6 @@ public static class InfiniFrameNativeArtifactManifest {
new("osx-", OsxNativeFileName)
];
- // ReSharper disable once UnusedMember.Global
public static readonly string[] AllFileNames = [
WindowsNativeFileName,
WindowsLoaderFileName,
@@ -41,7 +32,7 @@ public static class InfiniFrameNativeArtifactManifest {
OsxNativeFileName
];
- // ReSharper disable once ConvertIfStatementToReturnStatement, UnusedMember.Global
+ // ReSharper disable once ConvertIfStatementToReturnStatement
public static string[] RequiredFileNamesForRid(string rid) {
if (rid.StartsWith("win-", StringComparison.OrdinalIgnoreCase)) return [WindowsNativeFileName, WindowsLoaderFileName];
if (rid.StartsWith("linux-", StringComparison.OrdinalIgnoreCase)) return [LinuxNativeFileName];
@@ -50,7 +41,7 @@ public static string[] RequiredFileNamesForRid(string rid) {
throw new InvalidOperationException($"Unsupported RID for native artifact validation: {rid}");
}
- // ReSharper disable once ConvertIfStatementToReturnStatement, UnusedMember.Global
+ // ReSharper disable once ConvertIfStatementToReturnStatement
public static string ResolveNativeLibraryFileNameForCurrentPlatform() {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return WindowsNativeFileName;
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return LinuxNativeFileName;
@@ -59,7 +50,7 @@ public static string ResolveNativeLibraryFileNameForCurrentPlatform() {
throw new PlatformNotSupportedException("Unsupported OS for native bootstrap.");
}
- // ReSharper disable once ConvertIfStatementToReturnStatement, UnusedMember.Global
+ // ReSharper disable once ConvertIfStatementToReturnStatement
public static string[] RequiredFileNamesForCurrentPlatform() {
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return [WindowsNativeFileName, WindowsLoaderFileName];
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return [LinuxNativeFileName];
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppClosedDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppClosedDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppClosedDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppClosedDelegate.cs
index a3d5be63..bad31d11 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppClosedDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppClosedDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppClosingDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppClosingDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppClosingDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppClosingDelegate.cs
index 1d7241f5..f74f22e2 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppClosingDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppClosingDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppFocusInDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppFocusInDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppFocusInDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppFocusInDelegate.cs
index 27e6599e..f47d4c3c 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppFocusInDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppFocusInDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppFocusOutDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppFocusOutDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppFocusOutDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppFocusOutDelegate.cs
index 6dc52c2b..7fec8e2f 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppFocusOutDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppFocusOutDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppGetAllMonitorsDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppGetAllMonitorsDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppGetAllMonitorsDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppGetAllMonitorsDelegate.cs
index 853d7ba3..ee6744a8 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppGetAllMonitorsDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppGetAllMonitorsDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppMaximizedDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppMaximizedDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppMaximizedDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppMaximizedDelegate.cs
index 8bc06f14..8c39c020 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppMaximizedDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppMaximizedDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppMinimizedDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppMinimizedDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppMinimizedDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppMinimizedDelegate.cs
index 03819251..45a7be46 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppMinimizedDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppMinimizedDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppMovedDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppMovedDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppMovedDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppMovedDelegate.cs
index df235b02..5a869192 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppMovedDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppMovedDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppResizedDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppResizedDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppResizedDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppResizedDelegate.cs
index b264d2de..0462dbd5 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppResizedDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppResizedDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppRestoredDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppRestoredDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppRestoredDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppRestoredDelegate.cs
index 52613489..f9f3ae9c 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppRestoredDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppRestoredDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppWebMessageReceivedDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppWebMessageReceivedDelegate.cs
similarity index 93%
rename from src/InfiniFrame.Shared/Native/Delegates/CppWebMessageReceivedDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppWebMessageReceivedDelegate.cs
index df9127e4..1c9659f9 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppWebMessageReceivedDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppWebMessageReceivedDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/Delegates/CppWebResourceRequestedDelegate.cs b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppWebResourceRequestedDelegate.cs
similarity index 94%
rename from src/InfiniFrame.Shared/Native/Delegates/CppWebResourceRequestedDelegate.cs
rename to src/InfiniFrame.NativeBridge/Managed/Delegates/CppWebResourceRequestedDelegate.cs
index d5843df0..978e150a 100644
--- a/src/InfiniFrame.Shared/Native/Delegates/CppWebResourceRequestedDelegate.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Delegates/CppWebResourceRequestedDelegate.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native.Delegates;
+namespace InfiniFrame.NativeBridge.Delegates;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Enums/InfiniFrameDialogButtons.cs b/src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogButtons.cs
similarity index 96%
rename from src/InfiniFrame.Shared/Enums/InfiniFrameDialogButtons.cs
rename to src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogButtons.cs
index 6a0b05da..16335920 100644
--- a/src/InfiniFrame.Shared/Enums/InfiniFrameDialogButtons.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogButtons.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-namespace InfiniFrame;
+namespace InfiniFrame.NativeBridge.Dialogs;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Enums/InfiniFrameDialogIcon.cs b/src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogIcon.cs
similarity index 95%
rename from src/InfiniFrame.Shared/Enums/InfiniFrameDialogIcon.cs
rename to src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogIcon.cs
index aa552c45..75c22192 100644
--- a/src/InfiniFrame.Shared/Enums/InfiniFrameDialogIcon.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogIcon.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-namespace InfiniFrame;
+namespace InfiniFrame.NativeBridge.Dialogs;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Enums/InfiniFrameDialogOptions.cs b/src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogOptions.cs
similarity index 96%
rename from src/InfiniFrame.Shared/Enums/InfiniFrameDialogOptions.cs
rename to src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogOptions.cs
index ad9bf98c..8dfbd3e2 100644
--- a/src/InfiniFrame.Shared/Enums/InfiniFrameDialogOptions.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogOptions.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-namespace InfiniFrame;
+namespace InfiniFrame.NativeBridge.Dialogs;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Enums/InfiniFrameDialogResult.cs b/src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogResult.cs
similarity index 96%
rename from src/InfiniFrame.Shared/Enums/InfiniFrameDialogResult.cs
rename to src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogResult.cs
index 5bf732ca..21909b99 100644
--- a/src/InfiniFrame.Shared/Enums/InfiniFrameDialogResult.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Dialogs/InfiniFrameDialogResult.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-namespace InfiniFrame;
+namespace InfiniFrame.NativeBridge.Dialogs;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/InfiniFrameNative.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs
similarity index 50%
rename from src/InfiniFrame.Shared/Native/InfiniFrameNative.cs
rename to src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs
index 8e6b6f99..e6e3732c 100644
--- a/src/InfiniFrame.Shared/Native/InfiniFrameNative.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNative.cs
@@ -1,240 +1,242 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native.Delegates;
+using InfiniFrame.NativeBridge.Delegates;
+using InfiniFrame.NativeBridge.Dialogs;
+using InfiniFrame.NativeBridge.Parameters;
using System.Drawing;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-using static InfiniFrame.Native.NativeDll;
+using static InfiniFrame.NativeBridge.ArtifactManifest;
-namespace InfiniFrame.Native;
+namespace InfiniFrame.NativeBridge;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
public static partial class InfiniFrameNative {
#region MARSHAL CALLS FROM Non-UI Thread to UI Thread
- [LibraryImport(DllName, EntryPoint = InfiniFrame_Invoke, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Invoke", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void Invoke(IntPtr instance, Action callback);
#endregion
#region Register
// ReSharper disable once UnusedMethodReturnValue.Local
- [LibraryImport(DllName, EntryPoint = InfiniFrame_register_win32, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_register_win32", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void RegisterWin32(IntPtr hInstance);
// ReSharper disable once UnusedMethodReturnValue.Local
- [LibraryImport(DllName, EntryPoint = InfiniFrame_register_mac, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_register_mac", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void RegisterMac();
#endregion
#region CTOR-DTOR
- [LibraryImport(DllName, EntryPoint = InfiniFrame_ctor, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ctor", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial IntPtr Constructor([MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))] in InfiniFrameNativeParameters parameters);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_dtor), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_dtor"), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void Destructor(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_AddCustomSchemeName, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_AddCustomSchemeName", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void AddCustomSchemeName(IntPtr instance, string scheme);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_Close, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Close", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void Close(IntPtr instance);
#endregion
#region Get
- [LibraryImport(DllName, EntryPoint = InfiniFrame_getHwnd_win32, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_getHwnd_win32", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial IntPtr GetWindowHandlerWin32(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetAllMonitors, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetAllMonitors", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetAllMonitors(IntPtr instance, CppGetAllMonitorsDelegate callback);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetTransparentEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTransparentEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetContextMenuEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetContextMenuEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetDevToolsEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetDevToolsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetFullScreen, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFullScreen", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool fullScreen);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetGrantBrowserPermissions, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetGrantBrowserPermissions", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetGrantBrowserPermissions(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool grant);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetUserAgent, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetUserAgent", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial IntPtr GetUserAgent(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetMediaAutoplayEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMediaAutoplayEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetMediaAutoplayEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetFileSystemAccessEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFileSystemAccessEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetFileSystemAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetWebSecurityEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetWebSecurityEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetWebSecurityEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetJavascriptClipboardAccessEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetJavascriptClipboardAccessEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetJavascriptClipboardAccessEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetMediaStreamEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMediaStreamEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetMediaStreamEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetSmoothScrollingEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetSmoothScrollingEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetSmoothScrollingEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetIgnoreCertificateErrorsEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetIgnoreCertificateErrorsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetIgnoreCertificateErrorsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetNotificationsEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetNotificationsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetNotificationsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetPosition, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetPosition", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetPosition(IntPtr instance, out int x, out int y);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetResizable, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetResizable", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool resizable);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetScreenDpi, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetScreenDpi", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial uint GetScreenDpi(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetSize, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetSize(IntPtr instance, out int width, out int height);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetMaxSize, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMaxSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetMaxSize(IntPtr instance, out int maxWidth, out int maxHeight);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetMinSize, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMinSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetMinSize(IntPtr instance, out int minWidth, out int minHeight);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetTitle, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTitle", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial IntPtr GetTitle(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetTopmost, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetTopmost", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool topmost);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetZoom, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetZoom", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetZoom(IntPtr instance, out int zoom);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetMaximized, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMaximized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool maximized);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetMinimized, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetMinimized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool minimized);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetZoomEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetZoomEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool zoomEnabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetIconFileName, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetIconFileName", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial IntPtr GetIconFileName(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_GetFocused, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_GetFocused", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void GetFocused(IntPtr instance, [MarshalAs(UnmanagedType.I1)] out bool isFocused);
#endregion
#region Navigate
- [LibraryImport(DllName, EntryPoint = InfiniFrame_NavigateToString, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_NavigateToString", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void NavigateToString(IntPtr instance, string content);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_NavigateToUrl, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_NavigateToUrl", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void NavigateToUrl(IntPtr instance, string url);
#endregion
#region Set
- [LibraryImport(DllName, EntryPoint = InfiniFrame_setWebView2RuntimePath_win32, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_setWebView2RuntimePath_win32", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetWebView2RuntimePath_win32(IntPtr instance, string webView2RuntimePath);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetTransparentEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTransparentEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetTransparentEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetContextMenuEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetContextMenuEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetContextMenuEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetDevToolsEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetDevToolsEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetDevToolsEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool enabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetFullScreen, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetFullScreen", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetFullScreen(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool fullScreen);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetMaximized, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMaximized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetMaximized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool maximized);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetMaxSize, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMaxSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetMaxSize(IntPtr instance, int maxWidth, int maxHeight);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetMinimized, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMinimized", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetMinimized(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool minimized);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetMinSize, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetMinSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetMinSize(IntPtr instance, int minWidth, int minHeight);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetResizable, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetResizable", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetResizable(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool resizable);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetPosition, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetPosition", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetPosition(IntPtr instance, int x, int y);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetSize, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetSize", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetSize(IntPtr instance, int width, int height);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetTitle, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTitle", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetTitle(IntPtr instance, string? title);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetTopmost, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetTopmost", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetTopmost(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool topmost);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetIconFile, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetIconFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetIconFile(IntPtr instance, string filename);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetZoom, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetZoom", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetZoom(IntPtr instance, int zoom);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetZoomEnabled, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetZoomEnabled", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetZoomEnabled(IntPtr instance, [MarshalAs(UnmanagedType.I1)] bool zoomEnabled);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SetFocused, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SetFocused", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SetFocused(IntPtr instance);
#endregion
#region Misc
- [LibraryImport(DllName, EntryPoint = InfiniFrame_Center, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Center", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void Center(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_Restore, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_Restore", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void Restore(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_ClearBrowserAutoFill, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ClearBrowserAutoFill", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void ClearBrowserAutoFill(IntPtr instance);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_SendWebMessage, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_SendWebMessage", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void SendWebMessage(IntPtr instance, string message);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_ShowNotification, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowNotification", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void ShowNotification(IntPtr instance, string title, string body);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_WaitForExit, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_WaitForExit", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void WaitForExit(IntPtr instance);
#endregion
#region Dialog
- [LibraryImport(DllName, EntryPoint = InfiniFrame_ShowOpenFile, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowOpenFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial IntPtr ShowOpenFile(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, string[] filters, int filtersCount, out int resultCount);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_ShowOpenFolder, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowOpenFolder", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial IntPtr ShowOpenFolder(IntPtr inst, string title, string defaultPath, [MarshalAs(UnmanagedType.I1)] bool multiSelect, out int resultCount);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_ShowSaveFile, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowSaveFile", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial IntPtr ShowSaveFile(IntPtr inst, string title, string defaultPath, string[] filters, int filtersCount, string? defaultFileName);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_ShowMessage, SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_ShowMessage", SetLastError = true, StringMarshalling = StringMarshalling.Utf8), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial InfiniFrameDialogResult ShowMessage(IntPtr inst, string title, string text, InfiniFrameDialogButtons buttons, InfiniFrameDialogIcon icon);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_FreeString, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_FreeString", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void FreeString(IntPtr value);
- [LibraryImport(DllName, EntryPoint = InfiniFrame_FreeStringArray, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniFrame_FreeStringArray", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
internal static partial void FreeStringArray(IntPtr values, int count);
#endregion
diff --git a/src/InfiniFrame.Shared/Native/InfiniWindowNative.cs b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs
similarity index 78%
rename from src/InfiniFrame.Shared/Native/InfiniWindowNative.cs
rename to src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs
index 4af1d128..1eb40820 100644
--- a/src/InfiniFrame.Shared/Native/InfiniWindowNative.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/LibraryImports/InfiniFrameNativeTesting.cs
@@ -1,24 +1,25 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
+using InfiniFrame.NativeBridge.Parameters;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-using static InfiniFrame.Native.NativeDll;
+using static InfiniFrame.NativeBridge.ArtifactManifest;
-namespace InfiniFrame.Native;
+namespace InfiniFrame.NativeBridge;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
-public static partial class InfiniWindowNative {
- [LibraryImport(DllName, EntryPoint = InfiniWindowTests_NativeParametersReturnAsIs, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+public static partial class InfiniFrameNativeTesting {
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniWindowTests_NativeParametersReturnAsIs", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
private static partial void NativeParametersReturnAsIsNative(
[MarshalUsing(typeof(InfiniFrameNativeParametersMarshaller))]
in InfiniFrameNativeParameters parameters,
out IntPtr newParameters
);
- [LibraryImport(DllName, EntryPoint = InfiniWindowTests_FreeInitParams, SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
+ [LibraryImport(NativeLibraryName, EntryPoint = "InfiniWindowTests_FreeInitParams", SetLastError = true), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
private static partial void FreeInitParamsNative(IntPtr parameters);
///
diff --git a/src/InfiniFrame.Shared/Native/NativeMonitor.cs b/src/InfiniFrame.NativeBridge/Managed/NativeMonitor.cs
similarity index 96%
rename from src/InfiniFrame.Shared/Native/NativeMonitor.cs
rename to src/InfiniFrame.NativeBridge/Managed/NativeMonitor.cs
index 34e7898f..091e2dee 100644
--- a/src/InfiniFrame.Shared/Native/NativeMonitor.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/NativeMonitor.cs
@@ -4,7 +4,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native;
+namespace InfiniFrame.NativeBridge;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/NativeRect.cs b/src/InfiniFrame.NativeBridge/Managed/NativeRect.cs
similarity index 96%
rename from src/InfiniFrame.Shared/Native/NativeRect.cs
rename to src/InfiniFrame.NativeBridge/Managed/NativeRect.cs
index 46dbb79d..500b647b 100644
--- a/src/InfiniFrame.Shared/Native/NativeRect.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/NativeRect.cs
@@ -4,7 +4,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native;
+namespace InfiniFrame.NativeBridge;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/CustomSchemeNameMemory.cs b/src/InfiniFrame.NativeBridge/Managed/Parameters/CustomSchemeNameMemory.cs
similarity index 97%
rename from src/InfiniFrame.Shared/Native/CustomSchemeNameMemory.cs
rename to src/InfiniFrame.NativeBridge/Managed/Parameters/CustomSchemeNameMemory.cs
index 15f95c88..66ca98a3 100644
--- a/src/InfiniFrame.Shared/Native/CustomSchemeNameMemory.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Parameters/CustomSchemeNameMemory.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native;
+namespace InfiniFrame.NativeBridge.Parameters;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/InfiniFrameNativeParameters.cs b/src/InfiniFrame.NativeBridge/Managed/Parameters/InfiniFrameNativeParameters.cs
similarity index 99%
rename from src/InfiniFrame.Shared/Native/InfiniFrameNativeParameters.cs
rename to src/InfiniFrame.NativeBridge/Managed/Parameters/InfiniFrameNativeParameters.cs
index 229b88bf..d45e08fe 100644
--- a/src/InfiniFrame.Shared/Native/InfiniFrameNativeParameters.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Parameters/InfiniFrameNativeParameters.cs
@@ -1,10 +1,10 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native.Delegates;
+using InfiniFrame.NativeBridge.Delegates;
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native;
+namespace InfiniFrame.NativeBridge.Parameters;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Native/InfiniFrameNativeParametersMarshaller.cs b/src/InfiniFrame.NativeBridge/Managed/Parameters/InfiniFrameNativeParametersMarshaller.cs
similarity index 99%
rename from src/InfiniFrame.Shared/Native/InfiniFrameNativeParametersMarshaller.cs
rename to src/InfiniFrame.NativeBridge/Managed/Parameters/InfiniFrameNativeParametersMarshaller.cs
index 86f419ee..52c90f78 100644
--- a/src/InfiniFrame.Shared/Native/InfiniFrameNativeParametersMarshaller.cs
+++ b/src/InfiniFrame.NativeBridge/Managed/Parameters/InfiniFrameNativeParametersMarshaller.cs
@@ -1,11 +1,11 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native.Delegates;
+using InfiniFrame.NativeBridge.Delegates;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
-namespace InfiniFrame.Native;
+namespace InfiniFrame.NativeBridge.Parameters;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Native/.clang-tidy b/src/InfiniFrame.NativeBridge/Native/.clang-tidy
similarity index 100%
rename from src/InfiniFrame.Native/.clang-tidy
rename to src/InfiniFrame.NativeBridge/Native/.clang-tidy
diff --git a/src/InfiniFrame.NativeBridge/Native/.cmake/Build.InfiniFrameJs.Impl.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Build.InfiniFrameJs.Impl.cmake
new file mode 100644
index 00000000..6123bb33
--- /dev/null
+++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Build.InfiniFrameJs.Impl.cmake
@@ -0,0 +1,19 @@
+foreach(required_var NODE_EXECUTABLE FRONTEND_BUILD_SCRIPT JS_PROJECT_DIR JS_STAMP_FILE JS_OUTPUT)
+ if(NOT DEFINED ${required_var} OR "${${required_var}}" STREQUAL "")
+ message(FATAL_ERROR "${required_var} is required")
+ endif()
+endforeach()
+
+execute_process(
+ COMMAND "${NODE_EXECUTABLE}" "${FRONTEND_BUILD_SCRIPT}" "${JS_PROJECT_DIR}" "${JS_STAMP_FILE}" "${JS_OUTPUT}"
+ WORKING_DIRECTORY "${JS_PROJECT_DIR}"
+ RESULT_VARIABLE frontend_build_result
+)
+
+if(NOT frontend_build_result EQUAL 0)
+ message(FATAL_ERROR "Frontend build failed with exit code ${frontend_build_result}")
+endif()
+
+if(NOT EXISTS "${JS_OUTPUT}")
+ message(FATAL_ERROR "JS build completed but did not create expected output: ${JS_OUTPUT}")
+endif()
diff --git a/src/InfiniFrame.Native/cmake/Embed.InfiniFrameJs.Impl.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake
similarity index 83%
rename from src/InfiniFrame.Native/cmake/Embed.InfiniFrameJs.Impl.cmake
rename to src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake
index 8e6be6da..0ea2fbf0 100644
--- a/src/InfiniFrame.Native/cmake/Embed.InfiniFrameJs.Impl.cmake
+++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.Impl.cmake
@@ -4,7 +4,6 @@ string(LENGTH "${JS_CONTENT}" LEN)
math(EXPR LAST "${LEN} - 2")
set(BYTES "")
-set(COUNT 0)
foreach(i RANGE 0 ${LAST} 2)
string(SUBSTRING "${JS_CONTENT}" ${i} 2 BYTE)
@@ -14,13 +13,6 @@ foreach(i RANGE 0 ${LAST} 2)
else()
string(APPEND BYTES "0x${BYTE},")
endif()
-
- math(EXPR COUNT "${COUNT} + 1")
-
- if(COUNT EQUAL 16)
- string(APPEND BYTES "\n")
- set(COUNT 0)
- endif()
endforeach()
# Generate timestamp
@@ -43,9 +35,7 @@ file(WRITE "${OUTPUT_SOURCE}" "#include \"InfiniFrameJs.h\"
// Generated at: ${GENERATED_AT}
// -----------------------------------------------------------------------------
-alignas(16) const unsigned char g_infiniframe_js_data[] = {
-${BYTES}
-};
+alignas(16) const unsigned char g_infiniframe_js_data[] = {${BYTES}};
const size_t g_infiniframe_js_size = sizeof(g_infiniframe_js_data);
")
\ No newline at end of file
diff --git a/src/InfiniFrame.Native/cmake/Embed.InfiniFrameJs.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.cmake
similarity index 54%
rename from src/InfiniFrame.Native/cmake/Embed.InfiniFrameJs.cmake
rename to src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.cmake
index 35c069ca..c070b48e 100644
--- a/src/InfiniFrame.Native/cmake/Embed.InfiniFrameJs.cmake
+++ b/src/InfiniFrame.NativeBridge/Native/.cmake/Embed.InfiniFrameJs.cmake
@@ -1,6 +1,20 @@
function(infiniframe_setup_embed_js target_name)
- # Allow override from parent projects
- set(js_project_dir "${CMAKE_SOURCE_DIR}/../InfiniFrame.Js" CACHE PATH "Path to InfiniFrame JS project")
+ get_filename_component(native_dir "${CMAKE_CURRENT_FUNCTION_LIST_DIR}/.." ABSOLUTE)
+ get_filename_component(native_bridge_dir "${native_dir}/.." ABSOLUTE)
+ get_filename_component(src_dir "${native_bridge_dir}/.." ABSOLUTE)
+
+ set(default_js_project_dir "${src_dir}/InfiniFrame.Js")
+ set(INFINIFRAME_JS_PROJECT_DIR "${default_js_project_dir}" CACHE PATH "Path to InfiniFrame JS project")
+ set(js_project_dir "${INFINIFRAME_JS_PROJECT_DIR}")
+
+ if(NOT EXISTS "${js_project_dir}/package.json" OR NOT EXISTS "${js_project_dir}/package-lock.json")
+ message(FATAL_ERROR
+ "INFINIFRAME_JS_PROJECT_DIR must point to the InfiniFrame.Js project directory "
+ "containing package.json and package-lock.json. Current value: ${js_project_dir}. "
+ "Default value: ${default_js_project_dir}. If this was cached incorrectly, clear the "
+ "CMake build directory or reconfigure with -DINFINIFRAME_JS_PROJECT_DIR=${default_js_project_dir}."
+ )
+ endif()
set(js_input "${js_project_dir}/wwwroot/InfiniFrame.js")
@@ -11,8 +25,12 @@
# Ensure output directory exists
file(MAKE_DIRECTORY "${embed_dir}")
- # Locate npm (works on Windows/Linux/macOS)
- find_program(NPM_EXECUTABLE NAMES npm npm.cmd REQUIRED)
+ # Locate node (used by scripts/BuildFrontend.mjs)
+ find_program(NODE_EXECUTABLE NAMES node REQUIRED)
+
+ get_filename_component(repository_root "${src_dir}/.." ABSOLUTE)
+ set(frontend_build_script "${repository_root}/scripts/BuildFrontend.mjs")
+ set(js_stamp_file "${js_project_dir}/obj/frontend-build.stamp")
# Track TS sources
file(GLOB_RECURSE js_sources CONFIGURE_DEPENDS
@@ -23,10 +41,12 @@
add_custom_command(
OUTPUT "${js_input}"
COMMAND "${CMAKE_COMMAND}"
- "-DNPM_EXECUTABLE=${NPM_EXECUTABLE}"
+ "-DNODE_EXECUTABLE=${NODE_EXECUTABLE}"
+ "-DFRONTEND_BUILD_SCRIPT=${frontend_build_script}"
"-DJS_PROJECT_DIR=${js_project_dir}"
+ "-DJS_STAMP_FILE=${js_stamp_file}"
"-DJS_OUTPUT=${js_input}"
- -P "${CMAKE_SOURCE_DIR}/cmake/Build.InfiniFrameJs.Impl.cmake"
+ -P "${CMAKE_SOURCE_DIR}/.cmake/Build.InfiniFrameJs.Impl.cmake"
DEPENDS
${js_sources}
"${js_project_dir}/package.json"
@@ -34,7 +54,8 @@
"${js_project_dir}/tsconfig.json"
"${js_project_dir}/vite.config.dev.ts"
"${js_project_dir}/vite.config.prod.ts"
- "${CMAKE_SOURCE_DIR}/cmake/Build.InfiniFrameJs.Impl.cmake"
+ "${frontend_build_script}"
+ "${CMAKE_SOURCE_DIR}/.cmake/Build.InfiniFrameJs.Impl.cmake"
COMMENT "Building JS: ${js_input}"
VERBATIM
)
@@ -52,10 +73,10 @@
-DINPUT=${js_input}
-DOUTPUT_HEADER=${header_output}
-DOUTPUT_SOURCE=${source_output}
- -P ${CMAKE_SOURCE_DIR}/cmake/Embed.InfiniFrameJs.Impl.cmake
+ -P ${CMAKE_SOURCE_DIR}/.cmake/Embed.InfiniFrameJs.Impl.cmake
DEPENDS
${js_input}
- ${CMAKE_SOURCE_DIR}/cmake/Embed.InfiniFrameJs.Impl.cmake
+ ${CMAKE_SOURCE_DIR}/.cmake/Embed.InfiniFrameJs.Impl.cmake
COMMENT "Embedding JS: ${js_input}"
VERBATIM
)
diff --git a/src/InfiniFrame.Native/cmake/NativeDependencies.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/NativeDependencies.cmake
similarity index 100%
rename from src/InfiniFrame.Native/cmake/NativeDependencies.cmake
rename to src/InfiniFrame.NativeBridge/Native/.cmake/NativeDependencies.cmake
diff --git a/src/InfiniFrame.Native/cmake/Platform.Linux.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.Linux.cmake
similarity index 100%
rename from src/InfiniFrame.Native/cmake/Platform.Linux.cmake
rename to src/InfiniFrame.NativeBridge/Native/.cmake/Platform.Linux.cmake
diff --git a/src/InfiniFrame.Native/cmake/Platform.MacOS.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake
similarity index 100%
rename from src/InfiniFrame.Native/cmake/Platform.MacOS.cmake
rename to src/InfiniFrame.NativeBridge/Native/.cmake/Platform.MacOS.cmake
diff --git a/src/InfiniFrame.Native/cmake/Platform.Windows.cmake b/src/InfiniFrame.NativeBridge/Native/.cmake/Platform.Windows.cmake
similarity index 100%
rename from src/InfiniFrame.Native/cmake/Platform.Windows.cmake
rename to src/InfiniFrame.NativeBridge/Native/.cmake/Platform.Windows.cmake
diff --git a/src/InfiniFrame.Native/CMakeLists.txt b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt
similarity index 93%
rename from src/InfiniFrame.Native/CMakeLists.txt
rename to src/InfiniFrame.NativeBridge/Native/CMakeLists.txt
index 76d5c28c..bf0790ce 100644
--- a/src/InfiniFrame.Native/CMakeLists.txt
+++ b/src/InfiniFrame.NativeBridge/Native/CMakeLists.txt
@@ -18,12 +18,12 @@ endif ()
# ----------------------------------------------------------------------------------------------------------------------
# Dependencies
# ----------------------------------------------------------------------------------------------------------------------
-include("${CMAKE_SOURCE_DIR}/cmake/NativeDependencies.cmake")
-include("${CMAKE_SOURCE_DIR}/cmake/Embed.InfiniFrameJs.cmake")
+include("${CMAKE_SOURCE_DIR}/.cmake/NativeDependencies.cmake")
+include("${CMAKE_SOURCE_DIR}/.cmake/Embed.InfiniFrameJs.cmake")
-include("${CMAKE_SOURCE_DIR}/cmake/Platform.Windows.cmake")
-include("${CMAKE_SOURCE_DIR}/cmake/Platform.MacOS.cmake")
-include("${CMAKE_SOURCE_DIR}/cmake/Platform.Linux.cmake")
+include("${CMAKE_SOURCE_DIR}/.cmake/Platform.Windows.cmake")
+include("${CMAKE_SOURCE_DIR}/.cmake/Platform.MacOS.cmake")
+include("${CMAKE_SOURCE_DIR}/.cmake/Platform.Linux.cmake")
infiniframe_setup_dependencies()
diff --git a/src/InfiniFrame.Native/Core/InfiniFrame.h b/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrame.h
similarity index 100%
rename from src/InfiniFrame.Native/Core/InfiniFrame.h
rename to src/InfiniFrame.NativeBridge/Native/Core/InfiniFrame.h
diff --git a/src/InfiniFrame.Native/Core/InfiniFrameDialog.h b/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameDialog.h
similarity index 100%
rename from src/InfiniFrame.Native/Core/InfiniFrameDialog.h
rename to src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameDialog.h
diff --git a/src/InfiniFrame.Native/Core/InfiniFrameInitParams.h b/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameInitParams.h
similarity index 100%
rename from src/InfiniFrame.Native/Core/InfiniFrameInitParams.h
rename to src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameInitParams.h
diff --git a/src/InfiniFrame.Native/Core/InfiniFrameWindow.h b/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameWindow.h
similarity index 100%
rename from src/InfiniFrame.Native/Core/InfiniFrameWindow.h
rename to src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameWindow.h
diff --git a/src/InfiniFrame.Native/Core/InfiniFrameWindowImpl.h b/src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameWindowImpl.h
similarity index 100%
rename from src/InfiniFrame.Native/Core/InfiniFrameWindowImpl.h
rename to src/InfiniFrame.NativeBridge/Native/Core/InfiniFrameWindowImpl.h
diff --git a/src/InfiniFrame.Native/Dependencies/VENDORING.md b/src/InfiniFrame.NativeBridge/Native/Dependencies/VENDORING.md
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/VENDORING.md
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/VENDORING.md
diff --git a/src/InfiniFrame.Native/Dependencies/simdjson/LICENSE b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/LICENSE
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/simdjson/LICENSE
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/LICENSE
diff --git a/src/InfiniFrame.Native/Dependencies/simdjson/simdjson.cpp b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/simdjson.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/simdjson/simdjson.cpp
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/simdjson.cpp
diff --git a/src/InfiniFrame.Native/Dependencies/simdjson/simdjson.h b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/simdjson.h
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/simdjson/simdjson.h
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/simdjson/simdjson.h
diff --git a/src/InfiniFrame.Native/Dependencies/simdutf/LICENSE-APACHE b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/LICENSE-APACHE
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/simdutf/LICENSE-APACHE
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/LICENSE-APACHE
diff --git a/src/InfiniFrame.Native/Dependencies/simdutf/LICENSE-MIT b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/LICENSE-MIT
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/simdutf/LICENSE-MIT
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/LICENSE-MIT
diff --git a/src/InfiniFrame.Native/Dependencies/simdutf/simdutf.cpp b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/simdutf/simdutf.cpp
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.cpp
diff --git a/src/InfiniFrame.Native/Dependencies/simdutf/simdutf.h b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/simdutf/simdutf.h
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf.h
diff --git a/src/InfiniFrame.Native/Dependencies/simdutf/simdutf_c.h b/src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf_c.h
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/simdutf/simdutf_c.h
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/simdutf/simdutf_c.h
diff --git a/src/InfiniFrame.Native/Dependencies/wintoastlib/LICENSE.txt b/src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/LICENSE.txt
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/wintoastlib/LICENSE.txt
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/LICENSE.txt
diff --git a/src/InfiniFrame.Native/Dependencies/wintoastlib/wintoastlib.cpp b/src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/wintoastlib.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/wintoastlib/wintoastlib.cpp
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/wintoastlib.cpp
diff --git a/src/InfiniFrame.Native/Dependencies/wintoastlib/wintoastlib.h b/src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/wintoastlib.h
similarity index 100%
rename from src/InfiniFrame.Native/Dependencies/wintoastlib/wintoastlib.h
rename to src/InfiniFrame.NativeBridge/Native/Dependencies/wintoastlib/wintoastlib.h
diff --git a/src/InfiniFrame.Native/Embedded/Embedded.h b/src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h
similarity index 100%
rename from src/InfiniFrame.Native/Embedded/Embedded.h
rename to src/InfiniFrame.NativeBridge/Native/Embedded/Embedded.h
diff --git a/src/InfiniFrame.Native/Embedded/InfiniFrameJs/InfiniFrameJs.h b/src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h
similarity index 100%
rename from src/InfiniFrame.Native/Embedded/InfiniFrameJs/InfiniFrameJs.h
rename to src/InfiniFrame.NativeBridge/Native/Embedded/InfiniFrameJs/InfiniFrameJs.h
diff --git a/src/InfiniFrame.Native/Exports.Tests.cpp b/src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Exports.Tests.cpp
rename to src/InfiniFrame.NativeBridge/Native/Exports.Tests.cpp
diff --git a/src/InfiniFrame.Native/Exports.cpp b/src/InfiniFrame.NativeBridge/Native/Exports.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Exports.cpp
rename to src/InfiniFrame.NativeBridge/Native/Exports.cpp
diff --git a/src/InfiniFrame.Native/Platform/Linux/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Linux/Dialog.cpp
rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Dialog.cpp
diff --git a/src/InfiniFrame.Native/Platform/Linux/Window.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Linux/Window.cpp
rename to src/InfiniFrame.NativeBridge/Native/Platform/Linux/Window.cpp
diff --git a/src/InfiniFrame.Native/Platform/Mac/AppDelegate.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/AppDelegate.h
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/AppDelegate.h
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/AppDelegate.h
diff --git a/src/InfiniFrame.Native/Platform/Mac/AppDelegate.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/AppDelegate.mm
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/AppDelegate.mm
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/AppDelegate.mm
diff --git a/src/InfiniFrame.Native/Platform/Mac/Dialog.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Dialog.mm
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/Dialog.mm
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/Dialog.mm
diff --git a/src/InfiniFrame.Native/Platform/Mac/NSWindowBorderless.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NSWindowBorderless.h
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/NSWindowBorderless.h
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/NSWindowBorderless.h
diff --git a/src/InfiniFrame.Native/Platform/Mac/NSWindowBorderless.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NSWindowBorderless.mm
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/NSWindowBorderless.mm
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/NSWindowBorderless.mm
diff --git a/src/InfiniFrame.Native/Platform/Mac/NavigationDelegate.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NavigationDelegate.h
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/NavigationDelegate.h
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/NavigationDelegate.h
diff --git a/src/InfiniFrame.Native/Platform/Mac/NavigationDelegate.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/NavigationDelegate.mm
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/NavigationDelegate.mm
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/NavigationDelegate.mm
diff --git a/src/InfiniFrame.Native/Platform/Mac/UiDelegate.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.h
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/UiDelegate.h
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.h
diff --git a/src/InfiniFrame.Native/Platform/Mac/UiDelegate.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.mm
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/UiDelegate.mm
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/UiDelegate.mm
diff --git a/src/InfiniFrame.Native/Platform/Mac/UrlSchemeHandler.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UrlSchemeHandler.h
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/UrlSchemeHandler.h
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/UrlSchemeHandler.h
diff --git a/src/InfiniFrame.Native/Platform/Mac/UrlSchemeHandler.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/UrlSchemeHandler.mm
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/UrlSchemeHandler.mm
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/UrlSchemeHandler.mm
diff --git a/src/InfiniFrame.Native/Platform/Mac/Window.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/Window.mm
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/Window.mm
diff --git a/src/InfiniFrame.Native/Platform/Mac/WindowDelegate.h b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowDelegate.h
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/WindowDelegate.h
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowDelegate.h
diff --git a/src/InfiniFrame.Native/Platform/Mac/WindowDelegate.mm b/src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowDelegate.mm
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Mac/WindowDelegate.mm
rename to src/InfiniFrame.NativeBridge/Native/Platform/Mac/WindowDelegate.mm
diff --git a/src/InfiniFrame.Native/Platform/Windows/DarkMode.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Windows/DarkMode.cpp
rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.cpp
diff --git a/src/InfiniFrame.Native/Platform/Windows/DarkMode.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Windows/DarkMode.h
rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/DarkMode.h
diff --git a/src/InfiniFrame.Native/Platform/Windows/Dialog.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Windows/Dialog.cpp
rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Dialog.cpp
diff --git a/src/InfiniFrame.Native/Platform/Windows/ToastHandler.h b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h
similarity index 100%
rename from src/InfiniFrame.Native/Platform/Windows/ToastHandler.h
rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/ToastHandler.h
diff --git a/src/InfiniFrame.Native/Platform/Windows/Window.cpp b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp
similarity index 98%
rename from src/InfiniFrame.Native/Platform/Windows/Window.cpp
rename to src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp
index 12bdd436..df8950b6 100644
--- a/src/InfiniFrame.Native/Platform/Windows/Window.cpp
+++ b/src/InfiniFrame.NativeBridge/Native/Platform/Windows/Window.cpp
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -183,6 +184,39 @@ namespace {
return utf8;
}
+ bool EnsureDirectoryWritable(const std::wstring& directoryPath) {
+ if (directoryPath.empty())
+ return false;
+
+ std::error_code createError;
+ std::filesystem::create_directories(directoryPath, createError);
+ if (createError)
+ return false;
+
+ const std::wstring probePath = std::format(
+ L"{}\\{}.tmp",
+ directoryPath,
+ std::format(L".infiniframe-wv2-write-check-{}-{}-{}", GetCurrentProcessId(), GetCurrentThreadId(), GetTickCount64())
+ );
+
+ HANDLE probeHandle = CreateFileW(
+ probePath.c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ nullptr,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_TEMPORARY,
+ nullptr
+ );
+
+ if (probeHandle == INVALID_HANDLE_VALUE)
+ return false;
+
+ CloseHandle(probeHandle);
+ DeleteFileW(probePath.c_str());
+ return true;
+ }
+
InfiniFrameWindow* LookupWindowInstance(const HWND hwnd) {
return reinterpret_cast(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
@@ -1452,11 +1486,20 @@ void InfiniFrameWindow::AttachWebView() {
return;
}
+ PCWSTR userDataPath = nullptr;
+ if (!m_impl->_temporaryFilesPath.empty()) {
+ if (EnsureDirectoryWritable(m_impl->_temporaryFilesPath))
+ userDataPath = m_impl->_temporaryFilesPath.c_str();
+ else
+ TraceTeardown(
+ L"AttachWebView: temporary user-data path is not writable. Falling back to default path. path=%ls",
+ m_impl->_temporaryFilesPath.c_str()
+ );
+ }
+
HRESULT envResult = CreateCoreWebView2EnvironmentWithOptions(
runtimePath,
- m_impl->_temporaryFilesPath.empty()
- ? nullptr
- : m_impl->_temporaryFilesPath.c_str(),
+ userDataPath,
options.Get(),
Callback<
ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
diff --git a/src/InfiniFrame.Native/Types/Basic.h b/src/InfiniFrame.NativeBridge/Native/Types/Basic.h
similarity index 100%
rename from src/InfiniFrame.Native/Types/Basic.h
rename to src/InfiniFrame.NativeBridge/Native/Types/Basic.h
diff --git a/src/InfiniFrame.Native/Types/Callbacks.h b/src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h
similarity index 100%
rename from src/InfiniFrame.Native/Types/Callbacks.h
rename to src/InfiniFrame.NativeBridge/Native/Types/Callbacks.h
diff --git a/src/InfiniFrame.Native/Types/Dialog.h b/src/InfiniFrame.NativeBridge/Native/Types/Dialog.h
similarity index 100%
rename from src/InfiniFrame.Native/Types/Dialog.h
rename to src/InfiniFrame.NativeBridge/Native/Types/Dialog.h
diff --git a/src/InfiniFrame.Native/Utils/Common.h b/src/InfiniFrame.NativeBridge/Native/Utils/Common.h
similarity index 100%
rename from src/InfiniFrame.Native/Utils/Common.h
rename to src/InfiniFrame.NativeBridge/Native/Utils/Common.h
diff --git a/src/InfiniFrame.Native/Utils/Event.h b/src/InfiniFrame.NativeBridge/Native/Utils/Event.h
similarity index 100%
rename from src/InfiniFrame.Native/Utils/Event.h
rename to src/InfiniFrame.NativeBridge/Native/Utils/Event.h
diff --git a/src/InfiniFrame.Native/packages.config b/src/InfiniFrame.NativeBridge/Native/packages.config
similarity index 100%
rename from src/InfiniFrame.Native/packages.config
rename to src/InfiniFrame.NativeBridge/Native/packages.config
diff --git a/src/InfiniFrame.NativeBridge/native-build.ps1 b/src/InfiniFrame.NativeBridge/native-build.ps1
new file mode 100644
index 00000000..91fb8f8a
--- /dev/null
+++ b/src/InfiniFrame.NativeBridge/native-build.ps1
@@ -0,0 +1,114 @@
+param(
+ [string]$Configuration = "Debug",
+ [string]$Arch = "x64"
+)
+
+$ErrorActionPreference = "Stop"
+
+# -----------------------------------------------------------------------------------------------------------------
+# PATH SETUP
+# -----------------------------------------------------------------------------------------------------------------
+$RootDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+
+$NativeDir = Join-Path $RootDir "Native"
+$BuildDir = Join-Path $RootDir "build/$Arch/$Configuration"
+$ArtifactsDir = Join-Path $RootDir "artifacts/native"
+
+# -----------------------------------------------------------------------------------------------------------------
+# ENSURE DIRECTORIES EXIST
+# -----------------------------------------------------------------------------------------------------------------
+New-Item -ItemType Directory -Force -Path $NativeDir | Out-Null
+New-Item -ItemType Directory -Force -Path $BuildDir | Out-Null
+New-Item -ItemType Directory -Force -Path $ArtifactsDir | Out-Null
+
+$Platform = if ($IsWindows) { "windows" }
+elseif ($IsLinux) { "linux" }
+else { "osx" }
+
+New-Item -ItemType Directory -Force -Path "$ArtifactsDir/$Platform/$Arch/$Configuration" | Out-Null
+
+# -----------------------------------------------------------------------------------------------------------------
+# LOCK (blocking, CI-safe, race-free)
+# -----------------------------------------------------------------------------------------------------------------
+$LockFile = Join-Path $ArtifactsDir ".build.lock"
+
+$LockStream = $null
+
+try {
+
+ # Wait until lock becomes available (prevents crash)
+ while ($true) {
+ try {
+ $LockStream = New-Object System.IO.FileStream(
+ $LockFile,
+ [System.IO.FileMode]::OpenOrCreate,
+ [System.IO.FileAccess]::ReadWrite,
+ [System.IO.FileShare]::None
+ )
+ break
+ }
+ catch {
+ Start-Sleep -Milliseconds 200
+ }
+ }
+
+ # -----------------------------------------------------------------------------------------------------------------
+ # INFO
+ # -----------------------------------------------------------------------------------------------------------------
+ Write-Host "========================================="
+ Write-Host "Building InfiniFrame.Native"
+ Write-Host "Configuration: $Configuration"
+ Write-Host "Architecture : $Arch"
+ Write-Host "Platform : $Platform"
+ Write-Host "========================================="
+
+ # -----------------------------------------------------------------------------------------------------------------
+ # CMAKE CONFIG
+ # -----------------------------------------------------------------------------------------------------------------
+ $CMakeArgs = @()
+
+ if ($Platform -eq "osx") {
+ if ($Arch -eq "arm64") {
+ $CMakeArgs += "-DCMAKE_OSX_ARCHITECTURES=arm64"
+ } else {
+ $CMakeArgs += "-DCMAKE_OSX_ARCHITECTURES=x86_64"
+ }
+ }
+
+ if ($Platform -eq "windows") {
+ if ($Arch -eq "arm64") {
+ $CMakeArgs += "-A"
+ $CMakeArgs += "ARM64"
+ }
+ elseif ($Arch -eq "x64") {
+ $CMakeArgs += "-A"
+ $CMakeArgs += "x64"
+ }
+ else {
+ throw "Unsupported Windows architecture '$Arch'. Expected 'x64' or 'arm64'."
+ }
+ }
+
+ cmake -B $BuildDir -S $NativeDir @CMakeArgs
+ if ($LASTEXITCODE -ne 0) {
+ throw "CMake configure failed with exit code $LASTEXITCODE."
+ }
+
+ cmake --build $BuildDir --config $Configuration --parallel
+ if ($LASTEXITCODE -ne 0) {
+ throw "CMake build failed with exit code $LASTEXITCODE."
+ }
+
+ # -----------------------------------------------------------------------------------------------------------------
+ # COPY OUTPUTS
+ # -----------------------------------------------------------------------------------------------------------------
+ Get-ChildItem $BuildDir -Recurse -Include *.dll,*.so,*.dylib -ErrorAction SilentlyContinue |
+ Copy-Item -Destination "$ArtifactsDir/$Platform/$Arch/$Configuration" -Force
+
+ Write-Host "Native build complete."
+}
+finally {
+ if ($LockStream) {
+ $LockStream.Dispose()
+ }
+}
diff --git a/src/InfiniFrame.NativeBridge/native-clean.ps1 b/src/InfiniFrame.NativeBridge/native-clean.ps1
new file mode 100644
index 00000000..54231597
--- /dev/null
+++ b/src/InfiniFrame.NativeBridge/native-clean.ps1
@@ -0,0 +1,8 @@
+$RootDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+
+Write-Host "Cleaning native build directories..."
+
+Remove-Item -Recurse -Force "$RootDir/build" -ErrorAction SilentlyContinue
+Remove-Item -Recurse -Force "$RootDir/artifacts" -ErrorAction SilentlyContinue
+
+Write-Host "Native clean complete."
\ No newline at end of file
diff --git a/src/InfiniFrame.Shared/Configuration/IInfiniFrameOptions.cs b/src/InfiniFrame.Shared/Configuration/IInfiniFrameOptions.cs
index 665bc0f3..e75545ed 100644
--- a/src/InfiniFrame.Shared/Configuration/IInfiniFrameOptions.cs
+++ b/src/InfiniFrame.Shared/Configuration/IInfiniFrameOptions.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
namespace InfiniFrame;
diff --git a/src/InfiniFrame.Shared/Configuration/IInfiniFrameOptionsBuilder.cs b/src/InfiniFrame.Shared/Configuration/IInfiniFrameOptionsBuilder.cs
index 3b500411..d8ec9675 100644
--- a/src/InfiniFrame.Shared/Configuration/IInfiniFrameOptionsBuilder.cs
+++ b/src/InfiniFrame.Shared/Configuration/IInfiniFrameOptionsBuilder.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
namespace InfiniFrame;
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/src/InfiniFrame.Shared/Events/HasInfiniFrameEventsStoreExtensions.cs b/src/InfiniFrame.Shared/Events/HasInfiniFrameEventsStoreExtensions.cs
index fdf72d9a..b1994060 100644
--- a/src/InfiniFrame.Shared/Events/HasInfiniFrameEventsStoreExtensions.cs
+++ b/src/InfiniFrame.Shared/Events/HasInfiniFrameEventsStoreExtensions.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge;
using System.Drawing;
namespace InfiniFrame;
diff --git a/src/InfiniFrame.Shared/InfiniFrame.Shared.csproj b/src/InfiniFrame.Shared/InfiniFrame.Shared.csproj
index 3a7a3aaf..ad0d0edd 100644
--- a/src/InfiniFrame.Shared/InfiniFrame.Shared.csproj
+++ b/src/InfiniFrame.Shared/InfiniFrame.Shared.csproj
@@ -3,38 +3,6 @@
InfiniFrame
InfiniLore.InfiniFrame.Shared
Library
- $(MSBuildThisFileDirectory)../../
-
- $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))
- $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Linux)))
- $([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::OSX)))
-
- $(Platform)
- x64
-
-
- x64
- arm64
-
-
- x64
-
- build/$(CMakeArch)/$(Configuration)
- windows
- linux
- osx
-
-
- $(SolutionDir)artifacts/native/$(CMakeOSDir)/$(CMakeArch)/$(Configuration)
-
- $(SolutionDir)artifacts/native/linux/x64/$(Configuration)/
- $(SolutionDir)artifacts/native/linux/arm64/$(Configuration)/
- $(SolutionDir)artifacts/native/osx/x64/$(Configuration)/
- $(SolutionDir)artifacts/native/osx/arm64/$(Configuration)/
- $(SolutionDir)artifacts/native/windows/x64/$(Configuration)/
- $(SolutionDir)artifacts/native/windows/arm64/$(Configuration)/
-
- $(DefineConstants);WINDOWS
@@ -46,145 +14,8 @@
-
-
-
-
-
-
-
- Always
- runtimes/win-x64/native/InfiniFrame.Native.dll
- InfiniFrame.Native.dll
-
-
-
- Always
- runtimes/win-x64/native/WebView2Loader.dll
- WebView2Loader.dll
-
-
-
-
-
- Always
- runtimes/win-arm64/native/InfiniFrame.Native.dll
- InfiniFrame.Native.dll
-
-
-
- Always
- runtimes/win-arm64/native/WebView2Loader.dll
- WebView2Loader.dll
-
-
-
-
-
-
- Always
- false
-
-
-
-
-
- Always
- false
-
-
-
-
-
-
- Always
- false
-
-
-
-
-
- Always
- false
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/InfiniFrame.Shared/Native/InfiniFrameNativeParametersValidator.cs b/src/InfiniFrame.Shared/InfiniFrameNativeParametersValidator.cs
similarity index 73%
rename from src/InfiniFrame.Shared/Native/InfiniFrameNativeParametersValidator.cs
rename to src/InfiniFrame.Shared/InfiniFrameNativeParametersValidator.cs
index f12cc4d8..bc1dbf1f 100644
--- a/src/InfiniFrame.Shared/Native/InfiniFrameNativeParametersValidator.cs
+++ b/src/InfiniFrame.Shared/InfiniFrameNativeParametersValidator.cs
@@ -1,11 +1,12 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrame.Utilities;
using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices;
-namespace InfiniFrame.Native;
+namespace InfiniFrame;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
@@ -16,6 +17,7 @@ public static bool Validate(InfiniFrameNativeParameters parameters, ILogger logg
string? startUrl = parameters.StartUrl;
string? startString = parameters.StartString;
string? windowIconFile = parameters.WindowIconFile;
+ string? temporaryFilesPath = parameters.TemporaryFilesPath;
bool result = true;
if (string.IsNullOrWhiteSpace(startUrl) && string.IsNullOrWhiteSpace(startString)) {
@@ -49,6 +51,25 @@ public static bool Validate(InfiniFrameNativeParameters parameters, ILogger logg
// Not a breaking validation because it will run, just not as expected
}
+ if (!string.IsNullOrWhiteSpace(temporaryFilesPath) && !CanAccessTemporaryFilesPath(temporaryFilesPath, logger)) {
+ result = false;
+ }
+
return result;
}
+
+ private static bool CanAccessTemporaryFilesPath(string path, ILogger logger) {
+ try {
+ Directory.CreateDirectory(path);
+
+ string probeFile = Path.Join(path, $".infiniframe-write-check-{Guid.NewGuid():N}.tmp");
+ File.WriteAllText(probeFile, "ok");
+ File.Delete(probeFile);
+ return true;
+ }
+ catch (Exception ex) when (ex is IOException or UnauthorizedAccessException or ArgumentException or NotSupportedException or PathTooLongException) {
+ logger.LogError(ex, "TemporaryFilesPath '{TemporaryFilesPath}' is not writable.", path);
+ return false;
+ }
+ }
}
diff --git a/src/InfiniFrame.Shared/InfiniMonitor.cs b/src/InfiniFrame.Shared/InfiniMonitor.cs
index 6f6bb1aa..7dfecca8 100644
--- a/src/InfiniFrame.Shared/InfiniMonitor.cs
+++ b/src/InfiniFrame.Shared/InfiniMonitor.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge;
using System.Drawing;
namespace InfiniFrame;
diff --git a/src/InfiniFrame.Shared/Native/NativeDll.cs b/src/InfiniFrame.Shared/Native/NativeDll.cs
deleted file mode 100644
index bec2695f..00000000
--- a/src/InfiniFrame.Shared/Native/NativeDll.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-// ---------------------------------------------------------------------------------------------------------------------
-// Imports
-// ---------------------------------------------------------------------------------------------------------------------
-namespace InfiniFrame.Native;
-// ---------------------------------------------------------------------------------------------------------------------
-// Code
-// ---------------------------------------------------------------------------------------------------------------------
-internal static class NativeDll {
- internal const string DllName = "InfiniFrame.Native";
-
- #region InfiniFrame
- // ReSharper disable InconsistentNaming
- internal const string InfiniFrame_register_win32 = nameof(InfiniFrame_register_win32);
- internal const string InfiniFrame_register_mac = nameof(InfiniFrame_register_mac);
- internal const string InfiniFrame_ctor = nameof(InfiniFrame_ctor);
- internal const string InfiniFrame_dtor = nameof(InfiniFrame_dtor);
- internal const string InfiniFrame_AddCustomSchemeName = nameof(InfiniFrame_AddCustomSchemeName);
- internal const string InfiniFrame_Close = nameof(InfiniFrame_Close);
- internal const string InfiniFrame_getHwnd_win32 = nameof(InfiniFrame_getHwnd_win32);
- internal const string InfiniFrame_GetAllMonitors = nameof(InfiniFrame_GetAllMonitors);
- internal const string InfiniFrame_GetTransparentEnabled = nameof(InfiniFrame_GetTransparentEnabled);
- internal const string InfiniFrame_GetContextMenuEnabled = nameof(InfiniFrame_GetContextMenuEnabled);
- internal const string InfiniFrame_GetDevToolsEnabled = nameof(InfiniFrame_GetDevToolsEnabled);
- internal const string InfiniFrame_GetFullScreen = nameof(InfiniFrame_GetFullScreen);
- internal const string InfiniFrame_GetGrantBrowserPermissions = nameof(InfiniFrame_GetGrantBrowserPermissions);
- internal const string InfiniFrame_GetUserAgent = nameof(InfiniFrame_GetUserAgent);
- internal const string InfiniFrame_GetMediaAutoplayEnabled = nameof(InfiniFrame_GetMediaAutoplayEnabled);
- internal const string InfiniFrame_GetFileSystemAccessEnabled = nameof(InfiniFrame_GetFileSystemAccessEnabled);
- internal const string InfiniFrame_GetWebSecurityEnabled = nameof(InfiniFrame_GetWebSecurityEnabled);
- internal const string InfiniFrame_GetJavascriptClipboardAccessEnabled = nameof(InfiniFrame_GetJavascriptClipboardAccessEnabled);
- internal const string InfiniFrame_GetMediaStreamEnabled = nameof(InfiniFrame_GetMediaStreamEnabled);
- internal const string InfiniFrame_GetSmoothScrollingEnabled = nameof(InfiniFrame_GetSmoothScrollingEnabled);
- internal const string InfiniFrame_GetIgnoreCertificateErrorsEnabled = nameof(InfiniFrame_GetIgnoreCertificateErrorsEnabled);
- internal const string InfiniFrame_GetNotificationsEnabled = nameof(InfiniFrame_GetNotificationsEnabled);
- internal const string InfiniFrame_GetPosition = nameof(InfiniFrame_GetPosition);
- internal const string InfiniFrame_GetResizable = nameof(InfiniFrame_GetResizable);
- internal const string InfiniFrame_GetScreenDpi = nameof(InfiniFrame_GetScreenDpi);
- internal const string InfiniFrame_GetSize = nameof(InfiniFrame_GetSize);
- internal const string InfiniFrame_GetMaxSize = nameof(InfiniFrame_GetMaxSize);
- internal const string InfiniFrame_GetMinSize = nameof(InfiniFrame_GetMinSize);
- internal const string InfiniFrame_GetTitle = nameof(InfiniFrame_GetTitle);
- internal const string InfiniFrame_GetTopmost = nameof(InfiniFrame_GetTopmost);
- internal const string InfiniFrame_GetZoom = nameof(InfiniFrame_GetZoom);
- internal const string InfiniFrame_GetMaximized = nameof(InfiniFrame_GetMaximized);
- internal const string InfiniFrame_GetMinimized = nameof(InfiniFrame_GetMinimized);
- internal const string InfiniFrame_Invoke = nameof(InfiniFrame_Invoke);
- internal const string InfiniFrame_NavigateToString = nameof(InfiniFrame_NavigateToString);
- internal const string InfiniFrame_NavigateToUrl = nameof(InfiniFrame_NavigateToUrl);
- internal const string InfiniFrame_setWebView2RuntimePath_win32 = nameof(InfiniFrame_setWebView2RuntimePath_win32);
- internal const string InfiniFrame_SetTransparentEnabled = nameof(InfiniFrame_SetTransparentEnabled);
- internal const string InfiniFrame_SetContextMenuEnabled = nameof(InfiniFrame_SetContextMenuEnabled);
- internal const string InfiniFrame_SetDevToolsEnabled = nameof(InfiniFrame_SetDevToolsEnabled);
- internal const string InfiniFrame_SetFullScreen = nameof(InfiniFrame_SetFullScreen);
- internal const string InfiniFrame_SetMaximized = nameof(InfiniFrame_SetMaximized);
- internal const string InfiniFrame_SetMaxSize = nameof(InfiniFrame_SetMaxSize);
- internal const string InfiniFrame_SetMinimized = nameof(InfiniFrame_SetMinimized);
- internal const string InfiniFrame_SetMinSize = nameof(InfiniFrame_SetMinSize);
- internal const string InfiniFrame_SetResizable = nameof(InfiniFrame_SetResizable);
- internal const string InfiniFrame_SetPosition = nameof(InfiniFrame_SetPosition);
- internal const string InfiniFrame_SetSize = nameof(InfiniFrame_SetSize);
- internal const string InfiniFrame_SetTitle = nameof(InfiniFrame_SetTitle);
- internal const string InfiniFrame_SetTopmost = nameof(InfiniFrame_SetTopmost);
- internal const string InfiniFrame_SetIconFile = nameof(InfiniFrame_SetIconFile);
- internal const string InfiniFrame_GetIconFileName = nameof(InfiniFrame_GetIconFileName);
- internal const string InfiniFrame_SetZoom = nameof(InfiniFrame_SetZoom);
- internal const string InfiniFrame_Center = nameof(InfiniFrame_Center);
- internal const string InfiniFrame_ClearBrowserAutoFill = nameof(InfiniFrame_ClearBrowserAutoFill);
- internal const string InfiniFrame_SendWebMessage = nameof(InfiniFrame_SendWebMessage);
- internal const string InfiniFrame_ShowNotification = nameof(InfiniFrame_ShowNotification);
- internal const string InfiniFrame_WaitForExit = nameof(InfiniFrame_WaitForExit);
- internal const string InfiniFrame_ShowOpenFile = nameof(InfiniFrame_ShowOpenFile);
- internal const string InfiniFrame_ShowOpenFolder = nameof(InfiniFrame_ShowOpenFolder);
- internal const string InfiniFrame_ShowSaveFile = nameof(InfiniFrame_ShowSaveFile);
- internal const string InfiniFrame_ShowMessage = nameof(InfiniFrame_ShowMessage);
- internal const string InfiniFrame_GetZoomEnabled = nameof(InfiniFrame_GetZoomEnabled);
- internal const string InfiniFrame_SetZoomEnabled = nameof(InfiniFrame_SetZoomEnabled);
- internal const string InfiniFrame_FreeString = nameof(InfiniFrame_FreeString);
- internal const string InfiniFrame_FreeStringArray = nameof(InfiniFrame_FreeStringArray);
- internal const string InfiniFrame_SetFocused = nameof(InfiniFrame_SetFocused);
- internal const string InfiniFrame_GetFocused = nameof(InfiniFrame_GetFocused);
- internal const string InfiniFrame_Restore = nameof(InfiniFrame_Restore);
- // ReSharper restore InconsistentNaming
- #endregion
-
- #region InfiniWindowTests
- // ReSharper disable InconsistentNaming
- internal const string InfiniWindowTests_NativeParametersReturnAsIs = nameof(InfiniWindowTests_NativeParametersReturnAsIs);
- internal const string InfiniWindowTests_FreeInitParams = nameof(InfiniWindowTests_FreeInitParams);
- // ReSharper restore InconsistentNaming
- #endregion
-}
diff --git a/src/InfiniFrame.Shared/Utilities/MonitorsUtility.cs b/src/InfiniFrame.Shared/Utilities/MonitorsUtility.cs
index 32ccdceb..9d1a769e 100644
--- a/src/InfiniFrame.Shared/Utilities/MonitorsUtility.cs
+++ b/src/InfiniFrame.Shared/Utilities/MonitorsUtility.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge;
using System.Collections.Immutable;
using System.Drawing;
diff --git a/src/InfiniFrame.Shared/Window/IInfiniFrameWindow.cs b/src/InfiniFrame.Shared/Window/IInfiniFrameWindow.cs
index 888eeb2e..80b7055f 100644
--- a/src/InfiniFrame.Shared/Window/IInfiniFrameWindow.cs
+++ b/src/InfiniFrame.Shared/Window/IInfiniFrameWindow.cs
@@ -1,6 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
+using InfiniFrame.NativeBridge.Dialogs;
using Microsoft.Extensions.Logging;
using System.Collections.Immutable;
using System.Drawing;
diff --git a/src/InfiniFrame.Shared/Window/InfiniFrameWindowBuilderSnapshot.cs b/src/InfiniFrame.Shared/Window/InfiniFrameWindowBuilderSnapshot.cs
index cd902919..5fc20b22 100644
--- a/src/InfiniFrame.Shared/Window/InfiniFrameWindowBuilderSnapshot.cs
+++ b/src/InfiniFrame.Shared/Window/InfiniFrameWindowBuilderSnapshot.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrame.Security;
namespace InfiniFrame;
diff --git a/src/InfiniFrame.Tools.Pack/CommandLine.cs b/src/InfiniFrame.Tools.Pack/CommandLine.cs
index c84598b3..70e426f6 100644
--- a/src/InfiniFrame.Tools.Pack/CommandLine.cs
+++ b/src/InfiniFrame.Tools.Pack/CommandLine.cs
@@ -3,15 +3,13 @@
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame.Tools.Pack.Services;
using Serilog;
+using System.Globalization;
namespace InfiniFrame.Tools.Pack;
// -----------------------------------------------------------------------------------------------------------------
// Methods
// -----------------------------------------------------------------------------------------------------------------
internal static class CommandLine {
- private const string NativeArtifactsFallbackPathEnvVar = "INFINIFRAME_PACK_NATIVE_ARTIFACTS_FALLBACK";
- private const string AllowStaleNativeFallbackEnvVar = "INFINIFRAME_PACK_ALLOW_STALE_NATIVE_FALLBACK";
-
private static readonly ILogger Logger = Log.ForContext(typeof(CommandLine));
///
@@ -58,15 +56,8 @@ public static void PrintUsage() {
Logger.Information(" --output Publish output directory");
Logger.Information(" --no-restore Skip restore");
Logger.Information(" --verbose Verbose publish output");
+ Logger.Information(" --timeout Per-process timeout (e.g. 600, 90s, 5m, 00:10:00). Default: 10m, max: 30m");
Logger.Information(" --force-clean-output Allow deleting non-default output directories");
- Logger.Information(" --native-artifacts-fallback ");
- Logger.Information(" Explicit fallback directory for native artifacts");
- Logger.Information(" --allow-stale-native-fallback");
- Logger.Information(" Allow using fallback artifacts when preflight fails validation");
- Logger.Information("");
- Logger.Information("Environment overrides:");
- Logger.Information(" {FallbackEnvVar}=", NativeArtifactsFallbackPathEnvVar);
- Logger.Information(" {AllowStaleEnvVar}=true|false", AllowStaleNativeFallbackEnvVar);
}
private static bool IsHelp(string value) => value is "-h" or "--help" or "help";
@@ -76,9 +67,7 @@ private static PublishOptions ParsePublishOptions(string[] args) {
ProjectPath = string.Empty,
Rid = "auto",
Configuration = "Release",
- SelfContained = true,
- NativeArtifactsFallbackPath = Environment.GetEnvironmentVariable(NativeArtifactsFallbackPathEnvVar),
- AllowStaleNativeArtifactsFallback = ParseBooleanEnvironmentVariable(AllowStaleNativeFallbackEnvVar)
+ SelfContained = true
};
int index = 0;
@@ -117,25 +106,21 @@ private static PublishOptions ParsePublishOptions(string[] args) {
options.Verbose = true;
index++;
break;
+ case "--timeout":
+ options.ProcessTimeout = ParseTimeout(ReadValue(args, ref index, token));
+ break;
case "--force-clean-output":
options.ForceCleanOutput = true;
index++;
break;
- case "--native-artifacts-fallback":
- options.NativeArtifactsFallbackPath = ReadValue(args, ref index, token);
- break;
- case "--allow-stale-native-fallback":
- options.AllowStaleNativeArtifactsFallback = true;
- index++;
- break;
default:
throw new InvalidOperationException($"Unknown option '{token}'.");
}
}
- return !string.IsNullOrWhiteSpace(options.ProjectPath)
- ? options
- : throw new InvalidOperationException("Missing project path.");
+ if (string.IsNullOrWhiteSpace(options.ProjectPath)) throw new InvalidOperationException("Missing project path.");
+ ValidateProcessTimeout(options.ProcessTimeout);
+ return options;
}
private static string ReadValue(string[] args, ref int index, string option) {
@@ -147,12 +132,47 @@ private static string ReadValue(string[] args, ref int index, string option) {
return value;
}
- private static bool ParseBooleanEnvironmentVariable(string variableName) {
- string? value = Environment.GetEnvironmentVariable(variableName);
- if (string.IsNullOrWhiteSpace(value)) return false;
+ private static TimeSpan ParseTimeout(string value) {
+ if (string.IsNullOrWhiteSpace(value)) throw new FormatException("Timeout value cannot be empty.");
+
+ if (int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int seconds) && seconds > 0) {
+ return TimeSpan.FromSeconds(seconds);
+ }
+
+ if (TryParseUnitTimeout(value, out TimeSpan unitTimeout)) return unitTimeout;
+ if (TimeSpan.TryParse(value, CultureInfo.InvariantCulture, out TimeSpan timeSpan) && timeSpan > TimeSpan.Zero) return timeSpan;
+
+ throw new FormatException($"Invalid timeout value '{value}'. Use a positive value like '600', '90s', '5m', or '00:10:00'.");
+ }
+
+ private static bool TryParseUnitTimeout(string value, out TimeSpan timeout) {
+ timeout = default;
+ if (value.Length < 2) return false;
+
+ char unit = char.ToLowerInvariant(value[^1]);
+ string numberPart = value[..^1];
+ if (!double.TryParse(numberPart, NumberStyles.Float, CultureInfo.InvariantCulture, out double quantity) || quantity <= 0) {
+ return false;
+ }
+
+ timeout = unit switch {
+ 's' => TimeSpan.FromSeconds(quantity),
+ 'm' => TimeSpan.FromMinutes(quantity),
+ 'h' => TimeSpan.FromHours(quantity),
+ _ => default
+ };
+
+ return timeout > TimeSpan.Zero;
+ }
+
+ private static void ValidateProcessTimeout(TimeSpan timeout) {
+ if (timeout <= TimeSpan.Zero) {
+ throw new FormatException($"Timeout must be greater than zero. Received '{timeout}'.");
+ }
- return bool.TryParse(value, out bool parsedValue)
- ? parsedValue
- : throw new FormatException($"Environment variable '{variableName}' must be 'true' or 'false'.");
+ if (timeout > PublishOptions.MaxProcessTimeout) {
+ throw new FormatException(
+ $"Timeout '{timeout}' exceeds the maximum supported value of '{PublishOptions.MaxProcessTimeout}'.");
+ }
}
}
diff --git a/src/InfiniFrame.Tools.Pack/Program.cs b/src/InfiniFrame.Tools.Pack/Program.cs
index eb330fc2..c6e8e645 100644
--- a/src/InfiniFrame.Tools.Pack/Program.cs
+++ b/src/InfiniFrame.Tools.Pack/Program.cs
@@ -19,6 +19,14 @@ internal static class Program {
/// 0 when usage is shown successfully or publish completes successfully; otherwise, a non-zero exit code.
///
public static async Task Main(string[] args) {
+ using var cts = new CancellationTokenSource();
+ ConsoleCancelEventHandler cancelHandler = (_, e) => {
+ e.Cancel = true;
+ // ReSharper disable once AccessToDisposedClosure
+ cts.Cancel();
+ };
+ Console.CancelKeyPress += cancelHandler;
+
bool verbose = args.Any(arg => string.Equals(arg, "--verbose", StringComparison.OrdinalIgnoreCase));
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Is(verbose ? LogEventLevel.Debug : LogEventLevel.Information)
@@ -35,9 +43,13 @@ public static async Task Main(string[] args) {
return parse.ExitCode;
}
- return await PublishService.PublishAsync(parse.Options);
+ return await PublishService.PublishAsync(parse.Options, cts.Token);
}
+ catch (OperationCanceledException) {
+ Log.Warning("Operation canceled.");
+ return ExitCodes.GenericFailure;
+ }
catch (NativeDependencyNotFoundException ex) {
Log.Error(ex, "ERROR: {Message}", ex.Message);
return ExitCodes.NativeDependencyMissing;
@@ -47,6 +59,7 @@ public static async Task Main(string[] args) {
return ExitCodes.GenericFailure;
}
finally {
+ Console.CancelKeyPress -= cancelHandler;
await Log.CloseAndFlushAsync();
}
}
diff --git a/src/InfiniFrame.Tools.Pack/PublishOptions.cs b/src/InfiniFrame.Tools.Pack/PublishOptions.cs
index 2b385021..699f2a4c 100644
--- a/src/InfiniFrame.Tools.Pack/PublishOptions.cs
+++ b/src/InfiniFrame.Tools.Pack/PublishOptions.cs
@@ -9,6 +9,9 @@ namespace InfiniFrame.Tools.Pack;
/// Represents publish options accepted by the publish command.
///
internal sealed class PublishOptions {
+ public static readonly TimeSpan DefaultProcessTimeout = TimeSpan.FromMinutes(10);
+ public static readonly TimeSpan MaxProcessTimeout = TimeSpan.FromMinutes(30);
+
///
/// Gets or sets the path to the project file to publish.
///
@@ -50,18 +53,13 @@ internal sealed class PublishOptions {
public bool Verbose { get; set; }
///
- /// Gets or sets whether the tool may recursively delete a non-default output directory before publish.
+ /// Gets or sets the timeout applied to each external dotnet invocation.
///
- public bool ForceCleanOutput { get; set; }
+ public TimeSpan ProcessTimeout { get; set; } = DefaultProcessTimeout;
///
- /// Gets or sets an explicit native artifacts directory to use as fallback when preflight publish cannot provide valid
- /// artifacts.
+ /// Gets or sets whether the tool may recursively delete a non-default output directory before publish.
///
- public string? NativeArtifactsFallbackPath { get; set; }
+ public bool ForceCleanOutput { get; set; }
- ///
- /// Gets or sets whether potentially stale fallback native artifacts may be used.
- ///
- public bool AllowStaleNativeArtifactsFallback { get; set; }
}
diff --git a/src/InfiniFrame.Tools.Pack/README.md b/src/InfiniFrame.Tools.Pack/README.md
index 3cf45f2b..c828a397 100644
--- a/src/InfiniFrame.Tools.Pack/README.md
+++ b/src/InfiniFrame.Tools.Pack/README.md
@@ -44,19 +44,10 @@ Options:
- `--output `
- `--no-restore`
- `--verbose`
+- `--timeout ` (per-process timeout; examples: `600`, `90s`, `5m`, `00:10:00`; default `10m`, max `30m`)
- `--force-clean-output` (warning: allows recursive deletion of non-default output directories)
-- `--native-artifacts-fallback ` (explicit fallback native artifacts directory; opt-in only)
-- `--allow-stale-native-fallback` (required to permit fallback use when preflight fails)
-Environment overrides:
+Preflight behavior:
-- `INFINIFRAME_PACK_NATIVE_ARTIFACTS_FALLBACK=`
-- `INFINIFRAME_PACK_ALLOW_STALE_NATIVE_FALLBACK=true|false`
-
-Fallback behavior:
-
-- Preflight publish validation is required by default.
-- No repository parent-directory fallback discovery is performed.
-- Fallback artifacts are only used when an explicit path is provided and stale fallback is explicitly allowed.
-- Without `--allow-stale-native-fallback` (or `INFINIFRAME_PACK_ALLOW_STALE_NATIVE_FALLBACK=true`), fallback
- configuration still results in a hard failure.
+- Preflight publish validation is required.
+- Native artifacts must come from the project publish output for the selected RID.
diff --git a/src/InfiniFrame.Tools.Pack/Resolvers/MsBuildPropertyResolver.cs b/src/InfiniFrame.Tools.Pack/Resolvers/MsBuildPropertyResolver.cs
index a5039494..bbe5f9cb 100644
--- a/src/InfiniFrame.Tools.Pack/Resolvers/MsBuildPropertyResolver.cs
+++ b/src/InfiniFrame.Tools.Pack/Resolvers/MsBuildPropertyResolver.cs
@@ -8,7 +8,15 @@ namespace InfiniFrame.Tools.Pack.Resolvers;
// Code
// ---------------------------------------------------------------------------------------------------------------------
internal static class MsBuildPropertyResolver {
- public static string? TryGetProperty(string projectPath, string propertyName) {
+ public static async Task TryGetPropertyAsync(
+ string projectPath,
+ string propertyName,
+ TimeSpan? timeout = null,
+ CancellationToken cancellationToken = default
+ ) {
+ TimeSpan effectiveTimeout = timeout ?? TimeSpan.FromMinutes(2);
+ if (effectiveTimeout <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(timeout), "Timeout must be greater than zero.");
+
var startInfo = new ProcessStartInfo("dotnet") {
UseShellExecute = false,
RedirectStandardOutput = true,
@@ -27,11 +35,27 @@ internal static class MsBuildPropertyResolver {
if (!process.Start()) return null;
- Task stdOutTask = process.StandardOutput.ReadToEndAsync();
- Task stdErrTask = process.StandardError.ReadToEndAsync();
- process.WaitForExit();
- string stdOut = stdOutTask.GetAwaiter().GetResult().Trim();
- _ = stdErrTask.GetAwaiter().GetResult();
+ Task stdOutTask = process.StandardOutput.ReadToEndAsync(cancellationToken);
+ Task stdErrTask = process.StandardError.ReadToEndAsync(cancellationToken);
+ using var timeoutCts = new CancellationTokenSource(effectiveTimeout);
+ using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
+ try {
+ await process.WaitForExitAsync(linkedCts.Token);
+ }
+ catch (OperationCanceledException) when (timeoutCts.IsCancellationRequested) {
+ try {
+ if (!process.HasExited) process.Kill(entireProcessTree: true);
+ }
+ catch (InvalidOperationException) {
+ // best effort
+ }
+
+ throw new TimeoutException(
+ $"Timed out after {effectiveTimeout} while evaluating MSBuild property '{propertyName}' for '{projectPath}'.");
+ }
+
+ string stdOut = (await stdOutTask).Trim();
+ _ = await stdErrTask;
if (process.ExitCode != 0 || string.IsNullOrWhiteSpace(stdOut)) return null;
diff --git a/src/InfiniFrame.Tools.Pack/Resolvers/ProjectInfoResolver.cs b/src/InfiniFrame.Tools.Pack/Resolvers/ProjectInfoResolver.cs
index d931e145..339a88c1 100644
--- a/src/InfiniFrame.Tools.Pack/Resolvers/ProjectInfoResolver.cs
+++ b/src/InfiniFrame.Tools.Pack/Resolvers/ProjectInfoResolver.cs
@@ -7,20 +7,39 @@ namespace InfiniFrame.Tools.Pack.Resolvers;
// ---------------------------------------------------------------------------------------------------------------------
internal static class ProjectInfoResolver {
///
- /// Resolves the target framework from evaluated MSBuild properties.
+ /// Resolves the target framework from evaluated MSBuild properties.
///
- /// Path to a project file.
+ /// Path to the project file.
+ ///
+ /// An optional timeout specifying the maximum duration for resolving properties.
+ /// If not provided, the default timeout is used.
+ ///
+ ///
+ /// A token that allows the operation to be cancelled.
+ ///
///
- /// The value of TargetFramework, or the first framework from TargetFrameworks when multi-targeted.
+ /// The value of TargetFramework, or the first framework from TargetFrameworks when multi-targeted.
///
///
- /// Thrown when no framework can be resolved from evaluated project properties.
+ /// Thrown when no framework can be resolved from the evaluated project properties.
///
- public static string ResolveFramework(string projectPath) {
- string? targetFramework = MsBuildPropertyResolver.TryGetProperty(projectPath, "TargetFramework");
+ public static async Task ResolveFrameworkAsync(
+ string projectPath,
+ TimeSpan? timeout = null,
+ CancellationToken cancellationToken = default
+ ) {
+ string? targetFramework = await MsBuildPropertyResolver.TryGetPropertyAsync(
+ projectPath,
+ "TargetFramework",
+ timeout,
+ cancellationToken);
if (!string.IsNullOrWhiteSpace(targetFramework)) return targetFramework;
- string? targetFrameworks = MsBuildPropertyResolver.TryGetProperty(projectPath, "TargetFrameworks");
+ string? targetFrameworks = await MsBuildPropertyResolver.TryGetPropertyAsync(
+ projectPath,
+ "TargetFrameworks",
+ timeout,
+ cancellationToken);
// ReSharper disable once ConvertIfStatementToReturnStatement
if (string.IsNullOrWhiteSpace(targetFrameworks)) {
@@ -31,14 +50,28 @@ public static string ResolveFramework(string projectPath) {
}
///
- /// Resolves the assembly name using evaluated MSBuild properties.
+ /// Resolves the assembly name using evaluated MSBuild properties.
///
/// Path to a project file.
+ ///
+ /// Optional timeout value for the operation. If null, a default timeout is used.
+ ///
+ ///
+ /// A token to monitor for cancellation requests.
+ ///
///
- /// The AssemblyName value when present; otherwise the project file name without extension.
+ /// The AssemblyName value when present; otherwise the project file name without extension.
///
- public static string ResolveAssemblyName(string projectPath) {
- string? assemblyName = MsBuildPropertyResolver.TryGetProperty(projectPath, "AssemblyName");
+ public static async Task ResolveAssemblyNameAsync(
+ string projectPath,
+ TimeSpan? timeout = null,
+ CancellationToken cancellationToken = default
+ ) {
+ string? assemblyName = await MsBuildPropertyResolver.TryGetPropertyAsync(
+ projectPath,
+ "AssemblyName",
+ timeout,
+ cancellationToken);
return string.IsNullOrWhiteSpace(assemblyName) ? Path.GetFileNameWithoutExtension(projectPath) : assemblyName;
}
}
diff --git a/src/InfiniFrame.Tools.Pack/Services/ProcessRunner.cs b/src/InfiniFrame.Tools.Pack/Services/ProcessRunner.cs
index 83f0f988..f0d4401f 100644
--- a/src/InfiniFrame.Tools.Pack/Services/ProcessRunner.cs
+++ b/src/InfiniFrame.Tools.Pack/Services/ProcessRunner.cs
@@ -9,31 +9,71 @@ namespace InfiniFrame.Tools.Pack.Services;
// ---------------------------------------------------------------------------------------------------------------------
// Code
// ---------------------------------------------------------------------------------------------------------------------
+///
+/// Provides functionality for running and managing external processes asynchronously.
+///
internal static class ProcessRunner {
+ ///
+ /// Represents the default timeout duration for processes executed using the ProcessRunner class.
+ /// This timeout is used to cancel the process if it exceeds the specified duration.
+ /// By default, the timeout is set to 10 minutes.
+ ///
+ public static readonly TimeSpan DefaultProcessTimeout = TimeSpan.FromMinutes(10);
+ ///
+ /// Represents a logger instance used for capturing and logging process-related information
+ /// such as standard output, standard error, and other diagnostic messages.
+ ///
+ ///
+ /// This logger instance is specifically scoped for the ProcessRunner class
+ /// and is intended to provide detailed logging of process execution activities,
+ /// including informational messages and error handling.
+ ///
private static readonly ILogger Logger = Log.ForContext(typeof(ProcessRunner));
///
- /// Runs an external process, streams stdout/stderr to the current console, and returns the process exit code.
+ /// Asynchronously executes an external process using the specified parameters and returns the exit code upon completion.
///
- /// Executable name or path.
- /// Arguments passed as discrete tokens.
- /// Optional process working directory.
- /// The exit code reported by the process.
- /// Thrown when the process fails to start.
- public static async Task RunAsync(string fileName, IReadOnlyList arguments, string? workingDirectory = null) {
- ProcessRunResult result = await RunWithOutputAsync(fileName, arguments, workingDirectory);
+ /// The name or full path of the executable file to run.
+ /// The command-line arguments to pass to the executable.
+ /// The working directory for the process, or null to use the current directory.
+ /// The maximum amount of time to allow the process to run before it is terminated, or null for no timeout.
+ /// A token to monitor for cancellation requests.
+ /// The exit code of the process upon its completion.
+ /// Thrown if the process fails to start or encounters an unexpected error during execution.
+ /// Thrown if the process is aborted due to exceeding the specified timeout or cancellation token.
+ public static async Task RunAsync(
+ string fileName,
+ IReadOnlyList arguments,
+ string? workingDirectory = null,
+ TimeSpan? timeout = null,
+ CancellationToken cancellationToken = default
+ ) {
+ ProcessRunResult result = await RunWithOutputAsync(fileName, arguments, workingDirectory, timeout, cancellationToken);
return result.ExitCode;
}
///
- /// Runs an external process, streams stdout/stderr to the current console, and returns exit code and captured output.
+ /// Runs an external process asynchronously, captures stdout/stderr, streams output to the current console, and returns the exit code along with the captured output.
///
- /// Executable name or path.
- /// Arguments passed as discrete tokens.
- /// Optional process working directory.
- /// Exit code and captured stdout/stderr.
+ /// The name or path of the executable to run.
+ /// The arguments to pass to the executable as discrete tokens.
+ /// The optional working directory for the process. Defaults to null.
+ /// The optional timeout duration for the process execution. Defaults to null, resulting in a predefined timeout being used.
+ /// Token to monitor for cancellation requests.
+ /// A struct containing the process exit code, captured standard output, and captured standard error.
/// Thrown when the process fails to start.
- public static async Task RunWithOutputAsync(string fileName, IReadOnlyList arguments, string? workingDirectory = null) {
+ /// Thrown when the specified timeout duration is zero or negative.
+ /// Thrown when the operation is canceled or the timeout elapses before the process completes.
+ public static async Task RunWithOutputAsync(
+ string fileName,
+ IReadOnlyList arguments,
+ string? workingDirectory = null,
+ TimeSpan? timeout = null,
+ CancellationToken cancellationToken = default
+ ) {
+ TimeSpan effectiveTimeout = timeout ?? DefaultProcessTimeout;
+ if (effectiveTimeout <= TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(timeout), "Timeout must be greater than zero.");
+
var startInfo = new ProcessStartInfo(fileName) {
UseShellExecute = false,
RedirectStandardOutput = true,
@@ -81,7 +121,31 @@ public static async Task RunWithOutputAsync(string fileName, I
process.BeginOutputReadLine();
process.BeginErrorReadLine();
- await process.WaitForExitAsync();
+ using var timeoutCts = new CancellationTokenSource(effectiveTimeout);
+ using var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutCts.Token);
+ try {
+ await process.WaitForExitAsync(linkedCts.Token);
+ }
+ catch (OperationCanceledException) when (timeoutCts.IsCancellationRequested) {
+ try {
+ if (!process.HasExited) process.Kill(entireProcessTree: true);
+ }
+ catch (InvalidOperationException) {
+ // best effort
+ }
+
+ throw new TimeoutException($"Timed out after {effectiveTimeout} while running '{fileName}'.");
+ }
+ catch (OperationCanceledException) {
+ try {
+ if (!process.HasExited) process.Kill(entireProcessTree: true);
+ }
+ catch (InvalidOperationException) {
+ // best effort
+ }
+
+ throw;
+ }
string capturedStandardOutput;
string capturedStandardError;
@@ -96,5 +160,12 @@ public static async Task RunWithOutputAsync(string fileName, I
return new ProcessRunResult(process.ExitCode, capturedStandardOutput, capturedStandardError);
}
+ ///
+ /// Represents the result of a process execution.
+ ///
+ ///
+ /// This type provides information about the outcome of a process that was executed using the ProcessRunner utility,
+ /// including the exit code, captured standard output, and captured standard error.
+ ///
internal readonly record struct ProcessRunResult(int ExitCode, string StandardOutput, string StandardError);
}
diff --git a/src/InfiniFrame.Tools.Pack/Services/PublishService.cs b/src/InfiniFrame.Tools.Pack/Services/PublishService.cs
index b3a01f92..9aaf4188 100644
--- a/src/InfiniFrame.Tools.Pack/Services/PublishService.cs
+++ b/src/InfiniFrame.Tools.Pack/Services/PublishService.cs
@@ -4,6 +4,7 @@
using InfiniFrame.Tools.Pack.Exceptions;
using InfiniFrame.Tools.Pack.Resolvers;
using Serilog;
+using System.Diagnostics;
namespace InfiniFrame.Tools.Pack.Services;
// ---------------------------------------------------------------------------------------------------------------------
@@ -11,7 +12,6 @@ namespace InfiniFrame.Tools.Pack.Services;
// ---------------------------------------------------------------------------------------------------------------------
internal static class PublishService {
private const string DotNet = "dotnet";
- private const string AllowStaleNativeFallbackEnvVar = "INFINIFRAME_PACK_ALLOW_STALE_NATIVE_FALLBACK";
private static readonly StringComparison PathComparison =
OperatingSystem.IsWindows() ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal;
private static readonly ILogger Logger = Log.ForContext(typeof(PublishService));
@@ -21,25 +21,30 @@ internal static class PublishService {
// -----------------------------------------------------------------------------------------------------------------
///
- /// Executes the full InfiniFrame publish pipeline for a project.
+ /// Executes the full InfiniFrame publish pipeline for a project.
///
- /// Publish options parsed from the command line.
+ /// The publish options parsed from the command line.
+ /// A token to observe for cooperative cancellation of the publish operation.
/// The process exit code of the publish operation.
/// Thrown when the target project file does not exist.
///
- /// Thrown when native build fails, fallback policy is violated, or required artifacts are missing.
+ /// Thrown when native build fails or required artifacts are missing.
///
- public static async Task PublishAsync(PublishOptions options) {
+ public static async Task PublishAsync(PublishOptions options, CancellationToken cancellationToken = default) {
+ var totalPublishStopwatch = Stopwatch.StartNew();
+ ValidateProcessTimeout(options.ProcessTimeout);
string projectPath = Path.GetFullPath(options.ProjectPath);
if (!File.Exists(projectPath)) throw new FileNotFoundException("Project file not found", projectPath);
string projectDirectory = Path.GetDirectoryName(projectPath) ?? throw new InvalidOperationException("Unable to resolve project directory.");
- string framework = string.IsNullOrWhiteSpace(options.Framework) ? ProjectInfoResolver.ResolveFramework(projectPath) : options.Framework!;
+ string framework = string.IsNullOrWhiteSpace(options.Framework)
+ ? await ProjectInfoResolver.ResolveFrameworkAsync(projectPath, options.ProcessTimeout, cancellationToken)
+ : options.Framework!;
string rid = RuntimeResolver.ResolveRid(options.Rid);
string output = ResolveOutputPath(options, projectDirectory, framework, rid);
- string assemblyName = ProjectInfoResolver.ResolveAssemblyName(projectPath);
+ string assemblyName = await ProjectInfoResolver.ResolveAssemblyNameAsync(projectPath, options.ProcessTimeout, cancellationToken);
- ResolvedNativeArtifacts nativeArtifacts = await ResolveNativeArtifactsAsync(options, projectPath, framework, rid);
+ ResolvedNativeArtifacts nativeArtifacts = await ResolveNativeArtifactsAsync(options, projectPath, framework, rid, cancellationToken);
PublishValidator.PreflightValidate(
projectDirectory,
@@ -65,10 +70,14 @@ public static async Task PublishAsync(PublishOptions options) {
rid,
output,
nativeArtifacts.Directory,
- tempTargets.Path
+ tempTargets.Path,
+ noRestore: true
);
- int exitCode = await ProcessRunner.RunAsync(DotNet, publishArgs);
+ var publishStopwatch = Stopwatch.StartNew();
+ int exitCode = await ProcessRunner.RunAsync(DotNet, publishArgs, timeout: options.ProcessTimeout, cancellationToken: cancellationToken);
+ publishStopwatch.Stop();
+ Logger.Information("Final publish finished in {ElapsedSeconds}s.", Math.Round(publishStopwatch.Elapsed.TotalSeconds, 2));
if (exitCode != 0) return exitCode;
string[] cleanupWarnings = PublishOutputCleaner.Cleanup(output);
@@ -85,6 +94,9 @@ public static async Task PublishAsync(PublishOptions options) {
return validation.UnexpectedEntries.Length == 0 ? ExitCodes.Success : ExitCodes.UnexpectedOutputShape;
}
finally {
+ totalPublishStopwatch.Stop();
+ Logger.Information("Pack pipeline completed in {ElapsedSeconds}s.", Math.Round(totalPublishStopwatch.Elapsed.TotalSeconds, 2));
+
if (nativeArtifacts.DeleteWhenDone && Directory.Exists(nativeArtifacts.Directory)) {
Directory.Delete(nativeArtifacts.Directory, true);
}
@@ -159,24 +171,26 @@ private static async Task ResolveNativeArtifactsAsync(
PublishOptions options,
string projectPath,
string framework,
- string rid
+ string rid,
+ CancellationToken cancellationToken
) {
string preflightDirectory = Path.Join(Path.GetTempPath(), $"infiniframe-pack-native-{Guid.NewGuid():N}");
Directory.CreateDirectory(preflightDirectory);
bool preflightValidated = false;
try {
- List preflightArgs = BuildPublishArguments(options, projectPath, framework, rid, preflightDirectory, isPreflight: true);
- ProcessRunner.ProcessRunResult preflightResult = await ProcessRunner.RunWithOutputAsync(DotNet, preflightArgs);
+ List preflightArgs = BuildPublishArguments(options, projectPath, framework, rid, preflightDirectory, noRestore: options.NoRestore, isPreflight: true);
+ var preflightStopwatch = Stopwatch.StartNew();
+ ProcessRunner.ProcessRunResult preflightResult = await ProcessRunner.RunWithOutputAsync(
+ DotNet,
+ preflightArgs,
+ timeout: options.ProcessTimeout,
+ cancellationToken: cancellationToken);
+ preflightStopwatch.Stop();
+ Logger.Information("Preflight publish finished in {ElapsedSeconds}s.", Math.Round(preflightStopwatch.Elapsed.TotalSeconds, 2));
int preflightExitCode = preflightResult.ExitCode;
if (preflightExitCode != 0) {
- string preflightFailureReason =
- $"Preflight publish failed with exit code {preflightExitCode}.";
- ResolvedNativeArtifacts? fallbackArtifacts =
- TryResolveConfiguredFallbackNativeArtifacts(options, rid, preflightFailureReason);
- if (fallbackArtifacts is not null) return fallbackArtifacts;
-
throw new InvalidOperationException(
$"Preflight publish failed with exit code {preflightExitCode}. Command: {DotNet} {string.Join(' ', preflightArgs)}" +
$"{FormatPreflightOutputForException(preflightResult)}");
@@ -188,10 +202,12 @@ string rid
return new ResolvedNativeArtifacts(preflightDirectory, true);
}
catch (InvalidOperationException preflightValidationError) {
- const string validationFailureReason = "Preflight publish did not contain valid native artifacts.";
- ResolvedNativeArtifacts? fallbackArtifacts =
- TryResolveConfiguredFallbackNativeArtifacts(options, rid, validationFailureReason, preflightValidationError);
- if (fallbackArtifacts is not null) return fallbackArtifacts;
+ string? nativeArtifactsDirectory = TryResolveNativeArtifactsFromPublishLayout(preflightDirectory, rid, options.Configuration);
+ if (!string.IsNullOrWhiteSpace(nativeArtifactsDirectory)) {
+ PublishValidator.ValidateNativeArtifacts(nativeArtifactsDirectory, rid);
+ preflightValidated = true;
+ return new ResolvedNativeArtifacts(nativeArtifactsDirectory, true);
+ }
throw new NativeDependencyNotFoundException(
"Could not resolve required InfiniFrame native artifacts from project publish output. " +
@@ -206,45 +222,25 @@ string rid
}
}
- private static ResolvedNativeArtifacts? TryResolveConfiguredFallbackNativeArtifacts(
- PublishOptions options,
- string rid,
- string failureReason,
- Exception? validationError = null
- ) {
- if (string.IsNullOrWhiteSpace(options.NativeArtifactsFallbackPath)) return null;
-
- string fallbackArtifactsDirectory = Path.GetFullPath(options.NativeArtifactsFallbackPath);
- PublishValidator.ValidateNativeArtifacts(fallbackArtifactsDirectory, rid);
-
- if (!options.AllowStaleNativeArtifactsFallback) {
- throw new InvalidOperationException(
- $"{failureReason} Native artifacts fallback was configured at '{fallbackArtifactsDirectory}', " +
- "but fallback artifacts are treated as potentially stale by default. " +
- "Re-run with '--allow-stale-native-fallback' (or set " +
- $"{AllowStaleNativeFallbackEnvVar}=true) to opt in."
- );
- }
-
- if (validationError is null) {
- Logger.Warning(
- "[InfiniFrame.Pack] {FailureReason} Using explicitly configured native fallback artifacts at: {NativeArtifactsDirectory}. " +
- "This bypasses preflight freshness checks and was explicitly allowed.",
- failureReason,
- fallbackArtifactsDirectory
- );
- }
- else {
- Logger.Warning(
- validationError,
- "[InfiniFrame.Pack] {FailureReason} Using explicitly configured native fallback artifacts at: {NativeArtifactsDirectory}. " +
- "This bypasses preflight freshness checks and was explicitly allowed.",
- failureReason,
- fallbackArtifactsDirectory
- );
- }
-
- return new ResolvedNativeArtifacts(fallbackArtifactsDirectory, false);
+ private static string? TryResolveNativeArtifactsFromPublishLayout(string publishDirectory, string rid, string configuration) {
+ string[] ridParts = rid.Split('-', StringSplitOptions.RemoveEmptyEntries);
+ if (ridParts.Length != 2) return null;
+
+ string platform = ridParts[0].ToLowerInvariant() switch {
+ "win" => "windows",
+ "linux" => "linux",
+ "osx" => "osx",
+ _ => string.Empty
+ };
+ string architecture = ridParts[1].ToLowerInvariant() switch {
+ "x64" => "x64",
+ "arm64" => "arm64",
+ _ => string.Empty
+ };
+ if (string.IsNullOrWhiteSpace(platform) || string.IsNullOrWhiteSpace(architecture)) return null;
+
+ string candidateDirectory = Path.Join(publishDirectory, "artifacts", "native", platform, architecture, configuration);
+ return Directory.Exists(candidateDirectory) ? candidateDirectory : null;
}
private static string FormatPreflightOutputForException(ProcessRunner.ProcessRunResult preflightResult) {
@@ -293,6 +289,7 @@ private static List BuildPublishArguments(
string output,
string? nativeArtifactsDir = null,
string? customTargetsPath = null,
+ bool noRestore = false,
bool isPreflight = false
) {
bool selfContained = !isPreflight && options.SelfContained;
@@ -326,10 +323,21 @@ private static List BuildPublishArguments(
]);
}
- if (options.NoRestore) args.Add("--no-restore");
+ if (noRestore) args.Add("--no-restore");
return args;
}
+ private static void ValidateProcessTimeout(TimeSpan timeout) {
+ if (timeout <= TimeSpan.Zero) {
+ throw new InvalidOperationException($"Process timeout must be greater than zero. Received '{timeout}'.");
+ }
+
+ if (timeout > PublishOptions.MaxProcessTimeout) {
+ throw new InvalidOperationException(
+ $"Process timeout '{timeout}' exceeds the maximum supported value of '{PublishOptions.MaxProcessTimeout}'.");
+ }
+ }
+
internal readonly record struct OutputShapeValidation(bool FoundMainOutput, string[] UnexpectedEntries);
}
diff --git a/src/InfiniFrame.Tools.Pack/Services/PublishValidator.cs b/src/InfiniFrame.Tools.Pack/Services/PublishValidator.cs
index ac689c97..8435d873 100644
--- a/src/InfiniFrame.Tools.Pack/Services/PublishValidator.cs
+++ b/src/InfiniFrame.Tools.Pack/Services/PublishValidator.cs
@@ -91,12 +91,12 @@ string rid
throw new InvalidOperationException($"Required native artifact was not found: {missingPath}");
}
- foreach (string path in requiredPaths) {
- if (!rid.StartsWith("win-", StringComparison.OrdinalIgnoreCase)) return;
+ if (!rid.StartsWith("win-", StringComparison.OrdinalIgnoreCase)) return;
- ushort expectedMachine = ExpectedPeMachineForRid(rid);
+ ushort expectedMachine = ExpectedPeMachineForRid(rid);
+ foreach (string path in requiredPaths) {
ushort actualMachine = ReadPeMachine(path);
- if (actualMachine == expectedMachine) return;
+ if (actualMachine == expectedMachine) continue;
throw new InvalidOperationException(
$"Native artifact architecture mismatch for '{path}'. " +
diff --git a/src/InfiniFrame/Configuration/InfiniFrameOptions.cs b/src/InfiniFrame/Configuration/InfiniFrameOptions.cs
index 4bcf3360..67434176 100644
--- a/src/InfiniFrame/Configuration/InfiniFrameOptions.cs
+++ b/src/InfiniFrame/Configuration/InfiniFrameOptions.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
namespace InfiniFrame;
diff --git a/src/InfiniFrame/Configuration/InfiniFrameOptionsBuilder.cs b/src/InfiniFrame/Configuration/InfiniFrameOptionsBuilder.cs
index 8f2bc424..8a40f9c6 100644
--- a/src/InfiniFrame/Configuration/InfiniFrameOptionsBuilder.cs
+++ b/src/InfiniFrame/Configuration/InfiniFrameOptionsBuilder.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrame.Utilities;
using System.Runtime.InteropServices;
@@ -39,7 +39,10 @@ public class InfiniFrameOptionsBuilder : IInfiniFrameOptionsBuilder {
public bool SmoothScrollingEnabled { get; set; } = true;
public string? StartString { get; set; }
public string? StartUrl { get; set; }
- public string? TemporaryFilesPath { get; set; } = Path.Join(Path.GetTempPath(), "infiniframe");
+ public string? TemporaryFilesPath { get; set; } = Path.Join(
+ Path.GetTempPath(),
+ "infiniframe",
+ Environment.ProcessId.ToString());
private string? _title = TitleStringHelper.DefaultTitle;
public string? Title {
diff --git a/src/InfiniFrame/Events/InfiniFrameEvents.CustomScheme.cs b/src/InfiniFrame/Events/InfiniFrameEvents.CustomScheme.cs
index fc0c71a8..1b88906a 100644
--- a/src/InfiniFrame/Events/InfiniFrameEvents.CustomScheme.cs
+++ b/src/InfiniFrame/Events/InfiniFrameEvents.CustomScheme.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using Microsoft.Extensions.Logging;
using System.Runtime.InteropServices;
diff --git a/src/InfiniFrame/Events/InfiniFrameEvents.cs b/src/InfiniFrame/Events/InfiniFrameEvents.cs
index 7e4a51bb..8320d8df 100644
--- a/src/InfiniFrame/Events/InfiniFrameEvents.cs
+++ b/src/InfiniFrame/Events/InfiniFrameEvents.cs
@@ -1,8 +1,8 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
-using InfiniFrame.Native.Delegates;
+using InfiniFrame.NativeBridge.Delegates;
+using InfiniFrame.NativeBridge.Parameters;
using System.Drawing;
namespace InfiniFrame;
diff --git a/src/InfiniFrame/InfiniFrameSingleFileBootstrap.cs b/src/InfiniFrame/InfiniFrameSingleFileBootstrap.cs
index 1761d70e..41718864 100644
--- a/src/InfiniFrame/InfiniFrameSingleFileBootstrap.cs
+++ b/src/InfiniFrame/InfiniFrameSingleFileBootstrap.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge;
using System.Reflection;
using System.Runtime.InteropServices;
@@ -19,7 +19,7 @@ namespace InfiniFrame;
/// single-file/native outputs that embed InfiniFrame.Native and platform loader dependencies.
///
public static class InfiniFrameSingleFileBootstrap {
- private const string WebView2LoaderLibraryName = InfiniFrameNativeArtifactManifest.WindowsLoaderLibraryName;
+ private const string WebView2LoaderLibraryName = ArtifactManifest.WindowsLoaderLibraryName;
#if NET9_0_OR_GREATER
private static readonly Lock InitLock = new();
@@ -53,7 +53,7 @@ public static void Initialize() {
try {
Directory.CreateDirectory(_nativeDir);
ExtractEmbeddedNative(entryAssembly, rid, GetNativeFileNamesForCurrentPlatform());
- NativeLibrary.SetDllImportResolver(typeof(InfiniFrameNative).Assembly, ResolveNativeLibrary);
+ NativeLibrary.SetDllImportResolver(typeof(InfiniFrameNativeTesting).Assembly, ResolveNativeLibrary);
AppDomain.CurrentDomain.ProcessExit += (_, _) => TryCleanupNativeDirectory();
_initialized = 1;
@@ -66,11 +66,11 @@ public static void Initialize() {
}
private static IntPtr ResolveNativeLibrary(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) {
- if (_nativeDir is null || libraryName is not NativeDll.DllName and not WebView2LoaderLibraryName) return IntPtr.Zero;
+ if (_nativeDir is null || libraryName is not ArtifactManifest.NativeLibraryName and not WebView2LoaderLibraryName) return IntPtr.Zero;
string fileName = libraryName switch {
- NativeDll.DllName => InfiniFrameNativeArtifactManifest.ResolveNativeLibraryFileNameForCurrentPlatform(),
- WebView2LoaderLibraryName => InfiniFrameNativeArtifactManifest.WindowsLoaderFileName,
+ ArtifactManifest.NativeLibraryName => ArtifactManifest.ResolveNativeLibraryFileNameForCurrentPlatform(),
+ WebView2LoaderLibraryName => ArtifactManifest.WindowsLoaderFileName,
_ => string.Empty
};
@@ -79,8 +79,8 @@ private static IntPtr ResolveNativeLibrary(string libraryName, Assembly assembly
string fullPath = Path.Join(_nativeDir, fileName);
if (!File.Exists(fullPath)) return IntPtr.Zero;
- if (libraryName == NativeDll.DllName && OperatingSystem.IsWindows()) {
- TryPreloadDependency(InfiniFrameNativeArtifactManifest.WindowsLoaderFileName);
+ if (libraryName == ArtifactManifest.NativeLibraryName && OperatingSystem.IsWindows()) {
+ TryPreloadDependency(ArtifactManifest.WindowsLoaderFileName);
}
return NativeLibrary.Load(fullPath);
@@ -144,7 +144,7 @@ private static string GetRuntimeIdentifier() {
throw new PlatformNotSupportedException("Unsupported OS for native bootstrap.");
}
- private static string[] GetNativeFileNamesForCurrentPlatform() => InfiniFrameNativeArtifactManifest.RequiredFileNamesForCurrentPlatform();
+ private static string[] GetNativeFileNamesForCurrentPlatform() => ArtifactManifest.RequiredFileNamesForCurrentPlatform();
private static void TryCleanupNativeDirectory() {
if (string.IsNullOrWhiteSpace(_nativeDir)) return;
diff --git a/src/InfiniFrame/Window/InfiniFrameWindow.cs b/src/InfiniFrame/Window/InfiniFrameWindow.cs
index e992d727..b8529a46 100644
--- a/src/InfiniFrame/Window/InfiniFrameWindow.cs
+++ b/src/InfiniFrame/Window/InfiniFrameWindow.cs
@@ -1,7 +1,9 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge;
+using InfiniFrame.NativeBridge.Dialogs;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrame.StaticAssets;
using InfiniFrame.Utilities;
using Microsoft.Extensions.Logging;
diff --git a/src/InfiniFrame/Window/InfiniFrameWindowBuilder.cs b/src/InfiniFrame/Window/InfiniFrameWindowBuilder.cs
index 036eba86..4a70cdbf 100644
--- a/src/InfiniFrame/Window/InfiniFrameWindowBuilder.cs
+++ b/src/InfiniFrame/Window/InfiniFrameWindowBuilder.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrame.Security;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
diff --git a/src/InfiniFrame/Window/InfiniFrameWindowExtensions.cs b/src/InfiniFrame/Window/InfiniFrameWindowExtensions.cs
index 498b604b..80a4fa25 100644
--- a/src/InfiniFrame/Window/InfiniFrameWindowExtensions.cs
+++ b/src/InfiniFrame/Window/InfiniFrameWindowExtensions.cs
@@ -1,7 +1,7 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge;
using InfiniFrame.Security;
using InfiniFrame.Utilities;
using Microsoft.Extensions.Logging;
diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props
index d94004f2..a0a3273a 100644
--- a/tests/Directory.Build.props
+++ b/tests/Directory.Build.props
@@ -30,7 +30,11 @@
$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\'))
$(SolutionDir)
$(RepoRootDir)
- $(ResolvedSolutionDir)artifacts/native/$(CMakeOSDir)/$(CMakeArch)/$(Configuration)
+ $(ResolvedSolutionDir)src/InfiniFrame.NativeBridge/artifacts/native
+ $(ResolvedSolutionDir)artifacts/native
+ $(NativeBridgeArtifactsRoot)
+ $(LegacyNativeArtifactsRoot)
+ $(NativeArtifactsRoot)/$(CMakeOSDir)/$(CMakeArch)/$(Configuration)
$(DefineConstants);WINDOWS
diff --git a/tests/InfiniFrameTests.Playwright/TestUtility/BlazorPlaywrightContextBase.cs b/tests/InfiniFrameTests.Playwright/TestUtility/BlazorPlaywrightContextBase.cs
index 7c16b0bb..da5888f3 100644
--- a/tests/InfiniFrameTests.Playwright/TestUtility/BlazorPlaywrightContextBase.cs
+++ b/tests/InfiniFrameTests.Playwright/TestUtility/BlazorPlaywrightContextBase.cs
@@ -3,7 +3,6 @@
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
using InfiniFrame.BlazorWebView;
-using InfiniFrameTests.Shared;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.DependencyInjection;
@@ -20,7 +19,6 @@ public abstract class BlazorPlaywrightContextBase(string documen
private IInfiniFrameWindow? _window;
private Thread? _appThread;
private readonly int _playwrightDevtoolsPort = PlaywrightConnectionUtility.GetAvailablePort();
- private readonly string _webViewUserDataPath = PlaywrightConnectionUtility.CreateUniqueWebViewUserDataPath(typeof(TRootComponent).FullName ?? typeof(TRootComponent).Name);
// -----------------------------------------------------------------------------------------------------------------
// Methods
@@ -36,7 +34,6 @@ protected async Task BeforeAllAsync() {
}
protected void AfterAll() {
- string? tempFolder = _window?.TemporaryFilesPath;
BeforeAssemblyTeardown();
CloseWindowSafely();
@@ -45,9 +42,6 @@ protected void AfterAll() {
_app = null;
_window = null;
_appThread = null;
-
- PlaywrightConnectionUtility.DeleteDirectorySafely(_webViewUserDataPath);
- if (tempFolder is not null) FileUtility.SafeDeleteDirectory(tempFolder);
}
protected override Uri CreatePlaywrightConnectionUri(string relativeUrl)
@@ -60,7 +54,6 @@ protected virtual void ConfigureRootComponents(IInfiniFrameRootComponentList roo
protected virtual void ConfigureWindowBuilder(IInfiniFrameWindowBuilder windowBuilder, int playwrightDevtoolsPort) {
windowBuilder
.SetTitle(DefaultDocumentTitle)
- .SetTemporaryFilesPath(_webViewUserDataPath)
.SetBrowserControlInitParameters($"--remote-debugging-port={playwrightDevtoolsPort}")
.RegisterWindowManagementWebMessageHandler()
.RegisterFullScreenWebMessageHandler()
diff --git a/tests/InfiniFrameTests.Playwright/TestUtility/ServerPlaywrightContextBase.cs b/tests/InfiniFrameTests.Playwright/TestUtility/ServerPlaywrightContextBase.cs
index 8af971ab..e896c443 100644
--- a/tests/InfiniFrameTests.Playwright/TestUtility/ServerPlaywrightContextBase.cs
+++ b/tests/InfiniFrameTests.Playwright/TestUtility/ServerPlaywrightContextBase.cs
@@ -18,7 +18,6 @@ public abstract class ServerPlaywrightContextBase(string documentTitle) : Playwr
private InfiniFrameServerTestUtility? _utility;
private int _serverPort;
private int _playwrightDevtoolsPort;
- private string? _webViewUserDataPath;
private string ServerUrl => $"http://127.0.0.1:{_serverPort}";
private string PlaywrightConnectionString => $"http://127.0.0.1:{_playwrightDevtoolsPort}";
@@ -30,18 +29,12 @@ protected void BeforeAll()
=> StartUtilityWithFreshPorts();
protected async ValueTask AfterAllAsync() {
- string? tempFolder = _utility?.Window.TemporaryFilesPath;
BeforeAssemblyTeardown();
if (_utility is not null) {
await _utility.DisposeAsync();
}
_utility = null;
-
- PlaywrightConnectionUtility.DeleteDirectorySafely(_webViewUserDataPath);
- _webViewUserDataPath = null;
-
- if (tempFolder is not null) FileUtility.SafeDeleteDirectory(tempFolder);
}
protected override Uri CreatePlaywrightConnectionUri(string relativeUrl)
@@ -50,7 +43,6 @@ protected override Uri CreatePlaywrightConnectionUri(string relativeUrl)
private void StartUtilityWithFreshPorts() {
_serverPort = PlaywrightConnectionUtility.GetAvailablePort();
_playwrightDevtoolsPort = PlaywrightConnectionUtility.GetAvailablePort();
- _webViewUserDataPath = PlaywrightConnectionUtility.CreateUniqueWebViewUserDataPath(GetType().FullName ?? GetType().Name);
using var startupCancellation = new CancellationTokenSource(TimeSpan.FromSeconds(90));
@@ -60,7 +52,6 @@ private void StartUtilityWithFreshPorts() {
windowBuilder: windowBuilder => windowBuilder
.SetStartUrl(ServerUrl)
.SetTitle(DefaultDocumentTitle)
- .SetTemporaryFilesPath(_webViewUserDataPath)
.SetBrowserControlInitParameters($"--remote-debugging-port={_playwrightDevtoolsPort}")
.RegisterWindowManagementWebMessageHandler()
.RegisterFullScreenWebMessageHandler()
diff --git a/tests/InfiniFrameTests.Playwright/Tests/InfiniFramePlaywrightTestBase.cs b/tests/InfiniFrameTests.Playwright/Tests/InfiniFramePlaywrightTestBase.cs
index cdb99d94..af3b4904 100644
--- a/tests/InfiniFrameTests.Playwright/Tests/InfiniFramePlaywrightTestBase.cs
+++ b/tests/InfiniFrameTests.Playwright/Tests/InfiniFramePlaywrightTestBase.cs
@@ -14,6 +14,8 @@ public abstract class InfiniFramePlaywrightTestBase {
private const int NavigationRetryCount = 5;
private const int NavigationRetryDelayMs = 150;
private const int InfiniFrameReadyTimeoutMs = 20_000;
+ private const int BrowserContextReadyTimeoutMs = 20_000;
+ private const int BrowserContextReadyPollDelayMs = 100;
// -----------------------------------------------------------------------------------------------------------------
// Methods
@@ -32,7 +34,7 @@ await EvaluateWhenPageReadyAsync(
protected async Task GetPageAsync(string relativeUrl) {
IBrowserContext context = await GetContextAsync(relativeUrl);
- IPage page = context.Pages[0];
+ IPage page = await WaitForPageAsync(context);
await WaitForInfiniFrameReadyAsync(page);
return page;
}
@@ -42,7 +44,7 @@ protected Task GetRootPageAsync()
protected async Task GetContextAsync(string relativeUrl) {
IBrowser browser = await GetBrowserAsync(relativeUrl);
- return browser.Contexts[0];
+ return await WaitForContextAsync(browser);
}
protected Task GetRootContextAsync()
@@ -158,6 +160,38 @@ await page.WaitForFunctionAsync(
Fail.Test("InfiniFrame JavaScript interop readiness was not acknowledged.");
}
+
+ private static async Task WaitForContextAsync(IBrowser browser) {
+ DateTime timeoutAt = DateTime.UtcNow.AddMilliseconds(BrowserContextReadyTimeoutMs);
+
+ while (DateTime.UtcNow < timeoutAt) {
+ IBrowserContext? context = browser.Contexts.FirstOrDefault();
+ if (context is not null) {
+ return context;
+ }
+
+ await Task.Delay(BrowserContextReadyPollDelayMs);
+ }
+
+ Fail.Test("Timed out waiting for browser context.");
+ return null!;
+ }
+
+ private static async Task WaitForPageAsync(IBrowserContext context) {
+ DateTime timeoutAt = DateTime.UtcNow.AddMilliseconds(BrowserContextReadyTimeoutMs);
+
+ while (DateTime.UtcNow < timeoutAt) {
+ IPage? page = context.Pages.FirstOrDefault();
+ if (page is not null) {
+ return page;
+ }
+
+ await Task.Delay(BrowserContextReadyPollDelayMs);
+ }
+
+ Fail.Test("Timed out waiting for browser page.");
+ return null!;
+ }
private static bool IsExecutionContextDestroyedByNavigation(PlaywrightException exception)
=> exception.Message.Contains("Execution context was destroyed", StringComparison.OrdinalIgnoreCase);
diff --git a/tests/InfiniFrameTests.Shared/InfiniFrameServerTestUtility.cs b/tests/InfiniFrameTests.Shared/InfiniFrameServerTestUtility.cs
index b26154c5..baa52785 100644
--- a/tests/InfiniFrameTests.Shared/InfiniFrameServerTestUtility.cs
+++ b/tests/InfiniFrameTests.Shared/InfiniFrameServerTestUtility.cs
@@ -40,8 +40,6 @@ public static InfiniFrameServerTestUtility Create(
builder.WebApp.WebHost.UseStaticWebAssets();
appBuilder?.Invoke(builder.WebApp);
-
- builder.WindowBuilder.SetTemporaryFilesPath(Path.Combine(Path.GetTempPath(), "InfiniFrameServerTests"));
windowBuilder?.Invoke(builder.WindowBuilder);
InfiniFrameWebApplication app = builder.Build();
@@ -88,8 +86,6 @@ public static InfiniFrameServerTestUtility Create(
// -----------------------------------------------------------------------------------------------------------------
public async ValueTask DisposeAsync() {
if (Interlocked.Exchange(ref _disposed, 1) != 0) return;
-
- string? tempFolder = Window.TemporaryFilesPath;
try {
await Window.CloseAsync();
@@ -111,18 +107,6 @@ public async ValueTask DisposeAsync() {
// ignored
}
- if (tempFolder is not null) {
- try {
- FileUtility.SafeDeleteDirectory(tempFolder);
- }
- catch (ApplicationException) {
- // ignored
- }
- catch (OperationCanceledException) {
- // ignored
- }
- }
-
bool stoppedInTime = _thread.Join(TimeSpan.FromSeconds(5));
if (!stoppedInTime) {
Console.WriteLine(
@@ -130,7 +114,6 @@ public async ValueTask DisposeAsync() {
$"ThreadId={_thread.ManagedThreadId}, State={_thread.ThreadState}. Interrupting thread.");
_thread.Interrupt();
}
-
-
+
}
}
diff --git a/tests/InfiniFrameTests.Shared/InfiniFrameWindowTestUtility.cs b/tests/InfiniFrameTests.Shared/InfiniFrameWindowTestUtility.cs
index a88fb545..7d420919 100644
--- a/tests/InfiniFrameTests.Shared/InfiniFrameWindowTestUtility.cs
+++ b/tests/InfiniFrameTests.Shared/InfiniFrameWindowTestUtility.cs
@@ -47,7 +47,6 @@ public static InfiniFrameWindowTestUtility Create(
var windowBuilder = InfiniFrameWindowBuilder.Create();
windowBuilder.SetStartString(StartString);
- windowBuilder.SetTemporaryFilesPath(CreateUniqueTemporaryFilesPath());
builder?.Invoke(windowBuilder);
// Windows: WebView2 requires STA thread for COM initialization
@@ -115,19 +114,12 @@ InfiniFrameWindowBuilder windowBuilder
return utility;
}
- private static string CreateUniqueTemporaryFilesPath() {
- string uniqueSuffix = $"{Environment.ProcessId}-{Environment.CurrentManagedThreadId}-{Guid.NewGuid():N}";
- return Path.Combine(Path.GetTempPath(), "InfiniFrameTests", uniqueSuffix);
- }
-
// -----------------------------------------------------------------------------------------------------------------
// Methods
// ----------------------------------------------------------------------------------------------------------------
public void Dispose() {
if (Interlocked.Exchange(ref _disposed, 1) != 0) return;
- string? tempFolder = Window.TemporaryFilesPath;
-
try {
Window.Close();
}
@@ -138,50 +130,38 @@ public void Dispose() {
// ignored
}
- if (_windowThread is not null) {
- try {
- // Keep test disposal bounded so per-test timeout policies remain reliable.
- TimeSpan firstJoinTimeout = OperatingSystem.IsWindows()
- && RuntimeInformation.ProcessArchitecture == Architecture.Arm64
+ if (_windowThread is null) return;
+
+ try {
+ // Keep test disposal bounded so per-test timeout policies remain reliable.
+ TimeSpan firstJoinTimeout = OperatingSystem.IsWindows()
+ && RuntimeInformation.ProcessArchitecture == Architecture.Arm64
? TimeSpan.FromSeconds(2)
: TimeSpan.FromSeconds(3);
- if (!_windowThread.Join(firstJoinTimeout)) {
- try {
- Window.Close();
- }
- catch (ApplicationException) {
- // ignored
- }
- catch (ObjectDisposedException) {
- // ignored
- }
-
- _windowThread.Join(TimeSpan.FromSeconds(2));
+ if (!_windowThread.Join(firstJoinTimeout)) {
+ try {
+ Window.Close();
+ }
+ catch (ApplicationException) {
+ // ignored
+ }
+ catch (ObjectDisposedException) {
+ // ignored
}
- }
- catch (ThreadInterruptedException) {
- // ignored
- }
- catch (ThreadStateException) {
- // ignored
- }
- catch (ObjectDisposedException) {
- // ignored
- }
- }
- // ReSharper disable once InvertIf
- if (tempFolder is not null) {
- try {
- FileUtility.SafeDeleteDirectory(tempFolder);
- }
- catch (ApplicationException) {
- // ignored
- }
- catch (OperationCanceledException) {
- // ignored
+ _windowThread.Join(TimeSpan.FromSeconds(2));
}
}
+ catch (ThreadInterruptedException) {
+ // ignored
+ }
+ catch (ThreadStateException) {
+ // ignored
+ }
+ catch (ObjectDisposedException) {
+ // ignored
+ }
+
}
}
diff --git a/tests/InfiniFrameTests.Tools.Pack/CommandLineTests.cs b/tests/InfiniFrameTests.Tools.Pack/CommandLineTests.cs
index a01d38bf..5d9634e0 100644
--- a/tests/InfiniFrameTests.Tools.Pack/CommandLineTests.cs
+++ b/tests/InfiniFrameTests.Tools.Pack/CommandLineTests.cs
@@ -83,6 +83,7 @@ public async Task Parse_ReturnsDefaultPublishOptions_WhenOnlyProjectPathIsProvid
await Assert.That(result.Options.Output).IsNull();
await Assert.That(result.Options.NoRestore).IsFalse();
await Assert.That(result.Options.Verbose).IsFalse();
+ await Assert.That(result.Options.ProcessTimeout).IsEqualTo(TimeSpan.FromMinutes(10));
await Assert.That(result.Options.ForceCleanOutput).IsFalse();
}
@@ -99,6 +100,7 @@ public async Task Parse_ReturnsConfiguredPublishOptions_WhenAllOptionsAreProvide
"--output", "out",
"--no-restore",
"--verbose",
+ "--timeout", "7m",
"--force-clean-output"
];
@@ -116,6 +118,7 @@ public async Task Parse_ReturnsConfiguredPublishOptions_WhenAllOptionsAreProvide
await Assert.That(result.Options.Output).IsEqualTo("out");
await Assert.That(result.Options.NoRestore).IsTrue();
await Assert.That(result.Options.Verbose).IsTrue();
+ await Assert.That(result.Options.ProcessTimeout).IsEqualTo(TimeSpan.FromMinutes(7));
await Assert.That(result.Options.ForceCleanOutput).IsTrue();
}
@@ -179,6 +182,30 @@ await Assert.ThrowsAsync(() => {
});
}
+ [Test]
+ public async Task Parse_Throws_WhenTimeoutValueIsInvalid() {
+ // Arrange
+ string[] args = ["publish", "MyApp.csproj", "--timeout", "0"];
+
+ // Act & Assert
+ await Assert.ThrowsAsync(() => {
+ CommandLine.Parse(args);
+ return Task.CompletedTask;
+ }).WithMessage("Invalid timeout value '0'. Use a positive value like '600', '90s', '5m', or '00:10:00'.");
+ }
+
+ [Test]
+ public async Task Parse_Throws_WhenTimeoutValueExceedsMaximum() {
+ // Arrange
+ string[] args = ["publish", "MyApp.csproj", "--timeout", "31m"];
+
+ // Act & Assert
+ await Assert.ThrowsAsync(() => {
+ CommandLine.Parse(args);
+ return Task.CompletedTask;
+ }).WithMessage("Timeout '00:31:00' exceeds the maximum supported value of '00:30:00'.");
+ }
+
[Test]
public async Task PrintUsage_ExecutesWithoutThrowing() {
// Arrange
diff --git a/tests/InfiniFrameTests.Tools.Pack/Resolvers/MsBuildPropertyResolverTests.cs b/tests/InfiniFrameTests.Tools.Pack/Resolvers/MsBuildPropertyResolverTests.cs
index 7d640132..5fad1c11 100644
--- a/tests/InfiniFrameTests.Tools.Pack/Resolvers/MsBuildPropertyResolverTests.cs
+++ b/tests/InfiniFrameTests.Tools.Pack/Resolvers/MsBuildPropertyResolverTests.cs
@@ -41,7 +41,7 @@ await File.WriteAllTextAsync(projectPath, """
""");
// Act
- string? value = MsBuildPropertyResolver.TryGetProperty(projectPath, "TargetFramework");
+ string? value = await MsBuildPropertyResolver.TryGetPropertyAsync(projectPath, "TargetFramework");
// Assert
await Assert.That(value).IsEqualTo("net10.0");
@@ -60,7 +60,7 @@ await File.WriteAllTextAsync(projectPath, """
""");
// Act
- string? value = MsBuildPropertyResolver.TryGetProperty(projectPath, "PropertyThatDoesNotExist");
+ string? value = await MsBuildPropertyResolver.TryGetPropertyAsync(projectPath, "PropertyThatDoesNotExist");
// Assert
await Assert.That(value).IsNull();
@@ -72,7 +72,7 @@ public async Task TryGetProperty_ReturnsNull_WhenProjectCannotBeEvaluated() {
string missingProjectPath = Path.Join(TemporaryDirectory.Path, "missing.csproj");
// Act
- string? value = MsBuildPropertyResolver.TryGetProperty(missingProjectPath, "TargetFramework");
+ string? value = await MsBuildPropertyResolver.TryGetPropertyAsync(missingProjectPath, "TargetFramework");
// Assert
await Assert.That(value).IsNull();
diff --git a/tests/InfiniFrameTests.Tools.Pack/Resolvers/ProjectInfoResolverTests.cs b/tests/InfiniFrameTests.Tools.Pack/Resolvers/ProjectInfoResolverTests.cs
index 86ddcf6d..9d34db55 100644
--- a/tests/InfiniFrameTests.Tools.Pack/Resolvers/ProjectInfoResolverTests.cs
+++ b/tests/InfiniFrameTests.Tools.Pack/Resolvers/ProjectInfoResolverTests.cs
@@ -41,7 +41,7 @@ await File.WriteAllTextAsync(projectPath, """
""");
// Act
- string framework = ProjectInfoResolver.ResolveFramework(projectPath);
+ string framework = await ProjectInfoResolver.ResolveFrameworkAsync(projectPath);
// Assert
await Assert.That(framework).IsEqualTo("net10.0");
@@ -60,7 +60,7 @@ await File.WriteAllTextAsync(projectPath, """
""");
// Act
- string framework = ProjectInfoResolver.ResolveFramework(projectPath);
+ string framework = await ProjectInfoResolver.ResolveFrameworkAsync(projectPath);
// Assert
await Assert.That(framework).IsEqualTo("net8.0");
@@ -79,9 +79,8 @@ await File.WriteAllTextAsync(projectPath, """
""");
// Act & Assert
- await Assert.ThrowsAsync(() => {
- ProjectInfoResolver.ResolveFramework(projectPath);
- return Task.CompletedTask;
+ await Assert.ThrowsAsync(async () => {
+ _ = await ProjectInfoResolver.ResolveFrameworkAsync(projectPath);
})
.WithMessage("Could not resolve target framework from project evaluation. Use --framework.");
}
@@ -99,7 +98,7 @@ await File.WriteAllTextAsync(projectPath, """
""");
// Act
- string assemblyName = ProjectInfoResolver.ResolveAssemblyName(projectPath);
+ string assemblyName = await ProjectInfoResolver.ResolveAssemblyNameAsync(projectPath);
// Assert
await Assert.That(assemblyName).IsEqualTo("CustomName");
@@ -118,7 +117,7 @@ await File.WriteAllTextAsync(projectPath, """
""");
// Act
- string assemblyName = ProjectInfoResolver.ResolveAssemblyName(projectPath);
+ string assemblyName = await ProjectInfoResolver.ResolveAssemblyNameAsync(projectPath);
// Assert
await Assert.That(assemblyName).IsEqualTo("MyApp");
diff --git a/tests/InfiniFrameTests.Tools.Pack/Services/ProcessRunnerTests.cs b/tests/InfiniFrameTests.Tools.Pack/Services/ProcessRunnerTests.cs
index 871ff0a7..911cc9f6 100644
--- a/tests/InfiniFrameTests.Tools.Pack/Services/ProcessRunnerTests.cs
+++ b/tests/InfiniFrameTests.Tools.Pack/Services/ProcessRunnerTests.cs
@@ -59,4 +59,26 @@ public async Task RunWithOutputAsync_CapturesStandardError_ForFailingCommand() {
await Assert.That(result.ExitCode).IsNotEqualTo(0);
await Assert.That(string.IsNullOrWhiteSpace(result.StandardOutput) && string.IsNullOrWhiteSpace(result.StandardError)).IsFalse();
}
+
+ [Test]
+ public async Task RunAsync_ThrowsTimeoutException_WhenProcessExceedsTimeout() {
+ // Arrange
+ (string fileName, string[] arguments) = BuildLongRunningCommand();
+
+ // Act & Assert
+ TimeoutException? ex = await Assert.ThrowsAsync(async () => {
+ await ProcessRunner.RunAsync(fileName, arguments, timeout: TimeSpan.FromMilliseconds(250));
+ });
+
+ await Assert.That(ex).IsNotNull();
+ await Assert.That(ex!.Message).Contains("Timed out after");
+ }
+
+ private static (string FileName, string[] Arguments) BuildLongRunningCommand() {
+ if (OperatingSystem.IsWindows()) {
+ return ("powershell", ["-NoProfile", "-Command", "Start-Sleep -Seconds 5"]);
+ }
+
+ return ("sh", ["-c", "sleep 5"]);
+ }
}
diff --git a/tests/InfiniFrameTests.Tools.Pack/Services/PublishServiceTests.cs b/tests/InfiniFrameTests.Tools.Pack/Services/PublishServiceTests.cs
index 1fd9085a..8648f8cb 100644
--- a/tests/InfiniFrameTests.Tools.Pack/Services/PublishServiceTests.cs
+++ b/tests/InfiniFrameTests.Tools.Pack/Services/PublishServiceTests.cs
@@ -15,6 +15,12 @@ namespace InfiniFrameTests.Tools.Pack.Services;
// ---------------------------------------------------------------------------------------------------------------------
public class PublishServiceTests {
private static readonly SemaphoreSlim PublishTestLock = new(1, 1);
+ private static readonly TimeSpan PublishTimeout = IsCiEnvironment()
+ ? TimeSpan.FromMinutes(8)
+ : TimeSpan.FromMinutes(3);
+ private static readonly TimeSpan ProcessTimeout = TimeSpan.FromSeconds(45);
+ private static readonly Lock SharedFixtureLock = new();
+ private static Task? _sharedPublishFixtureTask;
private TemporaryDirectory TemporaryDirectory { get; set; } = null!;
@@ -63,7 +69,7 @@ public async Task PublishAsync_ThrowsKnownFailure_WhenNativeDependencyIsMissingF
// Arrange
string repoRoot = TemporaryDirectory.Path;
- string nativeProjectPath = Path.Join(repoRoot, "src", "InfiniFrame.Native", "InfiniFrame.Native.proj");
+ string nativeProjectPath = Path.Join(repoRoot, "src", "InfiniFrame.NativeBridge", "InfiniFrame.NativeBridge.csproj");
Directory.CreateDirectory(Path.GetDirectoryName(nativeProjectPath)!);
await File.WriteAllTextAsync(nativeProjectPath, "");
@@ -95,7 +101,10 @@ await File.WriteAllTextAsync(appProjectPath, """
NativeDependencyNotFoundException? exception;
try {
exception = await Assert.ThrowsAsync(async () => {
- await PublishService.PublishAsync(options);
+ await ExecuteWithTimeout(
+ PublishService.PublishAsync(options),
+ PublishTimeout,
+ "PublishAsync_ThrowsKnownFailure_WhenNativeDependencyIsMissingFromPublishOutput");
});
}
finally {
@@ -110,123 +119,30 @@ await File.WriteAllTextAsync(appProjectPath, """
[Test]
[SkipUtility.SkipOnMacOs("4 Hours lost on trying to fix this on macOs... too much time to spent on this.")]
public async Task PublishAsync_ReturnsSuccessAndSingleFileOutput_WhenProjectIncludesInfiniFrame() {
- // Arrange
- string repoRoot = FindRepoRoot();
- string appDirectory = Path.Join(TemporaryDirectory.Path, "minimal-app");
- Directory.CreateDirectory(appDirectory);
-
- string appProjectPath = Path.Join(appDirectory, "MinimalPublishApp.csproj");
- string infiniFrameProjectPath = Path.Join(repoRoot, "src", "InfiniFrame", "InfiniFrame.csproj");
-
- await File.WriteAllTextAsync(appProjectPath, $$"""
-
-
- Exe
- net10.0
- enable
- enable
-
-
-
-
-
- """);
-
- await File.WriteAllTextAsync(Path.Join(appDirectory, "Program.cs"), """
- Console.WriteLine("InfiniFrame pack integration test");
- """);
-
- string outputPath = Path.Join(TemporaryDirectory.Path, "publish-output");
- string rid = RuntimeResolver.ResolveRid("auto");
- string expectedMainOutput = Path.Join(outputPath, rid.StartsWith("win-", StringComparison.OrdinalIgnoreCase) ? "MinimalPublishApp.exe" : "MinimalPublishApp");
-
- var options = new PublishOptions {
- ProjectPath = appProjectPath,
- Rid = rid,
- Configuration = Configuration,
- Framework = "net10.0",
- SelfContained = true,
- Output = outputPath
- };
-
- // Act
- await PublishTestLock.WaitAsync();
- int exitCode;
- try {
- exitCode = await PublishService.PublishAsync(options);
- }
- finally {
- PublishTestLock.Release();
- }
+ SharedPublishFixture fixture = await ExecuteWithTimeout(
+ GetOrCreateSharedPublishFixtureAsync(),
+ PublishTimeout,
+ "PublishAsync_ReturnsSuccessAndSingleFileOutput_WhenProjectIncludesInfiniFrame");
// Assert
- await Assert.That(exitCode).IsEqualTo(ExitCodes.Success);
- await Assert.That(File.Exists(expectedMainOutput)).IsTrue();
- await Assert.That(Directory.GetFileSystemEntries(outputPath, "*", SearchOption.TopDirectoryOnly).Length).IsEqualTo(1);
+ await Assert.That(fixture.PublishExitCode).IsEqualTo(ExitCodes.Success);
+ await Assert.That(File.Exists(fixture.PublishedExecutable)).IsTrue();
+ await Assert.That(Directory.GetFileSystemEntries(fixture.OutputPath, "*", SearchOption.TopDirectoryOnly).Length).IsEqualTo(1);
}
[Test]
[SkipUtility.SkipOnMacOs("4 Hours lost on trying to fix this on macOs... too much time to spent on this.")]
public async Task PublishAsync_LaunchedPackedApp_InitializesBootstrapAndExitsSuccessfully() {
- // Arrange
- string repoRoot = FindRepoRoot();
- string appDirectory = Path.Join(TemporaryDirectory.Path, "launch-smoke-app");
- Directory.CreateDirectory(appDirectory);
-
- string appProjectPath = Path.Join(appDirectory, "LaunchSmokeApp.csproj");
- string infiniFrameProjectPath = Path.Join(repoRoot, "src", "InfiniFrame", "InfiniFrame.csproj");
- const string startupMarker = "BOOTSTRAP_SMOKE_OK";
-
- await File.WriteAllTextAsync(appProjectPath, $$"""
-
-
- Exe
- net10.0
- enable
- enable
-
-
-
-
-
- """);
-
- await File.WriteAllTextAsync(Path.Join(appDirectory, "Program.cs"), $$"""
- using InfiniFrame;
-
- InfiniFrameSingleFileBootstrap.Initialize();
- Console.WriteLine("{{startupMarker}}");
- return 0;
- """);
-
- string outputPath = Path.Join(TemporaryDirectory.Path, "launch-smoke-publish-output");
- string rid = RuntimeResolver.ResolveRid("auto");
- string publishedExecutable = Path.Join(outputPath, rid.StartsWith("win-", StringComparison.OrdinalIgnoreCase) ? "LaunchSmokeApp.exe" : "LaunchSmokeApp");
-
- var options = new PublishOptions {
- ProjectPath = appProjectPath,
- Rid = rid,
- Configuration = Configuration,
- Framework = "net10.0",
- SelfContained = true,
- Output = outputPath
- };
-
- // Act
- await PublishTestLock.WaitAsync();
- int publishExitCode;
- try {
- publishExitCode = await PublishService.PublishAsync(options);
- }
- finally {
- PublishTestLock.Release();
- }
- ProcessResult runResult = await RunProcessAndCaptureAsync(publishedExecutable, appDirectory);
+ SharedPublishFixture fixture = await ExecuteWithTimeout(
+ GetOrCreateSharedPublishFixtureAsync(),
+ PublishTimeout,
+ "PublishAsync_LaunchedPackedApp_InitializesBootstrapAndExitsSuccessfully");
+ ProcessResult runResult = await RunProcessAndCaptureAsync(fixture.PublishedExecutable, fixture.AppDirectory, ProcessTimeout);
// Assert
- await Assert.That(publishExitCode).IsEqualTo(ExitCodes.Success);
+ await Assert.That(fixture.PublishExitCode).IsEqualTo(ExitCodes.Success);
await Assert.That(runResult.ExitCode).IsEqualTo(0);
- await Assert.That(runResult.StandardOutput.Contains(startupMarker, StringComparison.Ordinal)).IsTrue();
+ await Assert.That(runResult.StandardOutput.Contains(fixture.StartupMarker, StringComparison.Ordinal)).IsTrue();
}
[Test]
@@ -279,7 +195,7 @@ private static string FindRepoRoot() {
throw new DirectoryNotFoundException("Could not locate repository root containing InfiniFrame.slnx.");
}
- private static async Task RunProcessAndCaptureAsync(string fileName, string workingDirectory) {
+ private static async Task RunProcessAndCaptureAsync(string fileName, string workingDirectory, TimeSpan timeout) {
var startInfo = new ProcessStartInfo(fileName) {
WorkingDirectory = workingDirectory,
UseShellExecute = false,
@@ -294,13 +210,114 @@ private static async Task RunProcessAndCaptureAsync(string fileNa
Task standardOutputTask = process.StandardOutput.ReadToEndAsync();
Task standardErrorTask = process.StandardError.ReadToEndAsync();
- await process.WaitForExitAsync();
+ using var timeoutCts = new CancellationTokenSource(timeout);
+ try {
+ await process.WaitForExitAsync(timeoutCts.Token);
+ }
+ catch (OperationCanceledException) {
+ try {
+ if (!process.HasExited) process.Kill(entireProcessTree: true);
+ }
+ catch (InvalidOperationException) {
+ // best effort
+ }
+ throw new TimeoutException($"Timed out after {timeout} while running '{fileName}'.");
+ }
+
string standardOutput = await standardOutputTask;
string standardError = await standardErrorTask;
return new ProcessResult(process.ExitCode, standardOutput, standardError);
}
+ private static async Task ExecuteWithTimeout(Task task, TimeSpan timeout, string operationName) {
+ Task completed = await Task.WhenAny(task, Task.Delay(timeout));
+ if (!ReferenceEquals(completed, task)) {
+ throw new TimeoutException($"Timed out after {timeout} while executing '{operationName}'.");
+ }
+
+ return await task;
+ }
+
+ private static bool IsCiEnvironment() =>
+ string.Equals(Environment.GetEnvironmentVariable("CI"), "true", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(Environment.GetEnvironmentVariable("GITHUB_ACTIONS"), "true", StringComparison.OrdinalIgnoreCase);
+
+ private static Task GetOrCreateSharedPublishFixtureAsync() {
+ lock (SharedFixtureLock) {
+ _sharedPublishFixtureTask ??= CreateSharedPublishFixtureAsync();
+ return _sharedPublishFixtureTask;
+ }
+ }
+
+ private static async Task CreateSharedPublishFixtureAsync() {
+ string repoRoot = FindRepoRoot();
+ string root = Path.Join(Path.GetTempPath(), $"infiniframe-pack-shared-{Guid.NewGuid():N}");
+ string appDirectory = Path.Join(root, "app");
+ Directory.CreateDirectory(appDirectory);
+
+ string appProjectPath = Path.Join(appDirectory, "SharedSmokeApp.csproj");
+ string infiniFrameProjectPath = Path.Join(repoRoot, "src", "InfiniFrame", "InfiniFrame.csproj");
+ const string startupMarker = "BOOTSTRAP_SMOKE_OK";
+
+ await File.WriteAllTextAsync(appProjectPath, $$"""
+
+
+ Exe
+ net10.0
+ enable
+ enable
+
+
+
+
+
+ """);
+
+ await File.WriteAllTextAsync(Path.Join(appDirectory, "Program.cs"), $$"""
+ using InfiniFrame;
+
+ InfiniFrameSingleFileBootstrap.Initialize();
+ Console.WriteLine("{{startupMarker}}");
+ return 0;
+ """);
+
+ string outputPath = Path.Join(root, "publish-output");
+ string rid = RuntimeResolver.ResolveRid("auto");
+ string publishedExecutable = Path.Join(outputPath, rid.StartsWith("win-", StringComparison.OrdinalIgnoreCase) ? "SharedSmokeApp.exe" : "SharedSmokeApp");
+
+ var options = new PublishOptions {
+ ProjectPath = appProjectPath,
+ Rid = rid,
+ Configuration = Configuration,
+ Framework = "net10.0",
+ SelfContained = true,
+ Output = outputPath
+ };
+
+ await PublishTestLock.WaitAsync();
+ int publishExitCode;
+ try {
+ publishExitCode = await ExecuteWithTimeout(
+ PublishService.PublishAsync(options),
+ PublishTimeout,
+ "CreateSharedPublishFixtureAsync");
+ }
+ finally {
+ PublishTestLock.Release();
+ }
+
+ return new SharedPublishFixture(publishExitCode, appDirectory, outputPath, publishedExecutable, startupMarker);
+ }
+
+ private sealed record SharedPublishFixture(
+ int PublishExitCode,
+ string AppDirectory,
+ string OutputPath,
+ string PublishedExecutable,
+ string StartupMarker
+ );
+
// ReSharper disable once NotAccessedPositionalProperty.Local
private sealed record ProcessResult(int ExitCode, string StandardOutput, string StandardError);
}
diff --git a/tests/InfiniFrameTests.Tools.Pack/Services/PublishValidatorTests.cs b/tests/InfiniFrameTests.Tools.Pack/Services/PublishValidatorTests.cs
index fa0b8e46..85868444 100644
--- a/tests/InfiniFrameTests.Tools.Pack/Services/PublishValidatorTests.cs
+++ b/tests/InfiniFrameTests.Tools.Pack/Services/PublishValidatorTests.cs
@@ -126,6 +126,26 @@ public async Task ValidateNativeArtifacts_Throws_WhenWindowsArtifactArchitecture
await Assert.That(ex.Message).Contains("found arm64");
}
+ [Test]
+ public async Task ValidateNativeArtifacts_Throws_WhenSecondWindowsArtifactArchitectureMismatchesRid() {
+ // Arrange
+ string artifactsDirectory = TemporaryDirectory.Path;
+ string nativeDll = Path.Join(artifactsDirectory, InfiniFramePackNativeArtifactManifest.WindowsNativeFileName);
+ string loaderDll = Path.Join(artifactsDirectory, InfiniFramePackNativeArtifactManifest.WindowsLoaderFileName);
+ WriteMinimalPeBinary(nativeDll, ImageFileMachineAmd64);
+ WriteMinimalPeBinary(loaderDll, ImageFileMachineArm64);
+
+ // Act & Assert
+ InvalidOperationException ex = await Assert.ThrowsAsync(() => {
+ PublishValidator.ValidateNativeArtifacts(artifactsDirectory, "win-x64");
+ return Task.CompletedTask;
+ }) ?? throw new InvalidOperationException("Expected exception was not thrown.");
+
+ await Assert.That(ex.Message).Contains(InfiniFramePackNativeArtifactManifest.WindowsLoaderFileName);
+ await Assert.That(ex.Message).Contains("Expected x64");
+ await Assert.That(ex.Message).Contains("found arm64");
+ }
+
[Test]
public async Task ValidateNativeArtifacts_DoesNotThrow_ForLinuxWhenRequiredArtifactExists() {
// Arrange
diff --git a/tests/InfiniFrameTests/InfiniFrameNativeParameterTests.cs b/tests/InfiniFrameTests/InfiniFrameNativeParameterTests.cs
index 0ab9ef66..04939902 100644
--- a/tests/InfiniFrameTests/InfiniFrameNativeParameterTests.cs
+++ b/tests/InfiniFrameTests/InfiniFrameNativeParameterTests.cs
@@ -1,7 +1,8 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge;
+using InfiniFrame.NativeBridge.Parameters;
using System.Runtime.InteropServices;
namespace InfiniFrameTests;
@@ -88,7 +89,7 @@ public async Task ReturnAsIsIsValid(CancellationToken ct = default) {
};
// Act
- newParametersPtr = InfiniWindowNative.NativeParametersReturnAsIsPtr(ref parameters);
+ newParametersPtr = InfiniFrameNativeTesting.NativeParametersReturnAsIsPtr(ref parameters);
var newParameters = Marshal.PtrToStructure(newParametersPtr);
// Assert
@@ -149,7 +150,7 @@ public async Task ReturnAsIsIsValid(CancellationToken ct = default) {
if (namePtr != IntPtr.Zero) Marshal.FreeHGlobal(namePtr);
// Native allocates returned init params; managed side must free.
- InfiniWindowNative.FreeInitParams(newParametersPtr);
+ InfiniFrameNativeTesting.FreeInitParams(newParametersPtr);
}
}
}
diff --git a/tests/InfiniFrameTests/Interop/RegisterWindowCreatedUtilityTests.cs b/tests/InfiniFrameTests/Interop/RegisterWindowCreatedUtilityTests.cs
index 3e4dfee5..23e340de 100644
--- a/tests/InfiniFrameTests/Interop/RegisterWindowCreatedUtilityTests.cs
+++ b/tests/InfiniFrameTests/Interop/RegisterWindowCreatedUtilityTests.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
using InfiniFrame.Interop;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared.TestDoubles;
namespace InfiniFrameTests.Interop;
diff --git a/tests/InfiniFrameTests/MessageHandlers/GetMessageWebMessageHandlerTests.cs b/tests/InfiniFrameTests/MessageHandlers/GetMessageWebMessageHandlerTests.cs
index 725365a8..4f9da00b 100644
--- a/tests/InfiniFrameTests/MessageHandlers/GetMessageWebMessageHandlerTests.cs
+++ b/tests/InfiniFrameTests/MessageHandlers/GetMessageWebMessageHandlerTests.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
using InfiniFrame.Interop;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared.TestDoubles;
using NSubstitute;
using System.Text.Json;
diff --git a/tests/InfiniFrameTests/MessageHandlers/MessageHandlersTests.cs b/tests/InfiniFrameTests/MessageHandlers/MessageHandlersTests.cs
index c4bd9b34..976f45a5 100644
--- a/tests/InfiniFrameTests/MessageHandlers/MessageHandlersTests.cs
+++ b/tests/InfiniFrameTests/MessageHandlers/MessageHandlersTests.cs
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
using InfiniFrame.Interop;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrame.Security;
using InfiniFrameTests.Shared.TestDoubles;
using Microsoft.Extensions.Logging;
diff --git a/tests/InfiniFrameTests/Utilities/InfiniFrameNativeParametersValidatorTests.cs b/tests/InfiniFrameTests/Utilities/InfiniFrameNativeParametersValidatorTests.cs
index 747731d4..0e124c2b 100644
--- a/tests/InfiniFrameTests/Utilities/InfiniFrameNativeParametersValidatorTests.cs
+++ b/tests/InfiniFrameTests/Utilities/InfiniFrameNativeParametersValidatorTests.cs
@@ -1,7 +1,8 @@
// ---------------------------------------------------------------------------------------------------------------------
// Imports
// ---------------------------------------------------------------------------------------------------------------------
-using InfiniFrame.Native;
+using InfiniFrame;
+using InfiniFrame.NativeBridge.Parameters;
using Microsoft.Extensions.Logging.Abstractions;
namespace InfiniFrameTests.Utilities;
@@ -44,4 +45,41 @@ public async Task Validate_AcceptsRelativeIconPathFromAppBaseDirectory(Cancellat
// Assert
await Assert.That(valid).IsTrue();
}
-}
\ No newline at end of file
+
+ [Test]
+ public async Task Validate_CreatesAndAcceptsWritableTemporaryFilesPath(CancellationToken ct = default) {
+ // Arrange
+ string path = Path.Join(Path.GetTempPath(), "InfiniFrameTests", $"validator-{Guid.NewGuid():N}");
+ if (Directory.Exists(path))
+ Directory.Delete(path, recursive: true);
+
+ var parameters = new InfiniFrameNativeParameters {
+ StartUrl = "https://example.com",
+ TemporaryFilesPath = path
+ };
+
+ // Act
+ bool valid = InfiniFrameNativeParametersValidator.Validate(parameters, NullLogger.Instance);
+
+ // Assert
+ await Assert.That(valid).IsTrue();
+ await Assert.That(Directory.Exists(path)).IsTrue();
+
+ Directory.Delete(path, recursive: true);
+ }
+
+ [Test]
+ public async Task Validate_RejectsInvalidTemporaryFilesPath(CancellationToken ct = default) {
+ // Arrange
+ var parameters = new InfiniFrameNativeParameters {
+ StartUrl = "https://example.com",
+ TemporaryFilesPath = $"invalid-{Guid.NewGuid():N}\0path"
+ };
+
+ // Act
+ bool valid = InfiniFrameNativeParametersValidator.Validate(parameters, NullLogger.Instance);
+
+ // Assert
+ await Assert.That(valid).IsFalse();
+ }
+}
diff --git a/tests/InfiniFrameTests/Utilities/OrderedEventTests.cs b/tests/InfiniFrameTests/Utilities/OrderedEventTests.cs
index a79c7cf9..39035ba7 100644
--- a/tests/InfiniFrameTests/Utilities/OrderedEventTests.cs
+++ b/tests/InfiniFrameTests/Utilities/OrderedEventTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
using System.Collections.Immutable;
diff --git a/tests/InfiniFrameTests/WebMessageContextTests.cs b/tests/InfiniFrameTests/WebMessageContextTests.cs
index fae7145c..361b0158 100644
--- a/tests/InfiniFrameTests/WebMessageContextTests.cs
+++ b/tests/InfiniFrameTests/WebMessageContextTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared.TestDoubles;
using System.Text.Json;
diff --git a/tests/InfiniFrameTests/WebMessageReceivedHandlerTests.cs b/tests/InfiniFrameTests/WebMessageReceivedHandlerTests.cs
index 7efefaaa..2376db6f 100644
--- a/tests/InfiniFrameTests/WebMessageReceivedHandlerTests.cs
+++ b/tests/InfiniFrameTests/WebMessageReceivedHandlerTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using Microsoft.Extensions.Logging.Abstractions;
using NSubstitute;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/BrowserControlInitParametersTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/BrowserControlInitParametersTests.cs
index 8a9b3177..f2ce954c 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/BrowserControlInitParametersTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/BrowserControlInitParametersTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/CenterTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/CenterTests.cs
index 281596a2..c7297b94 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/CenterTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/CenterTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrame.Utilities;
using InfiniFrameTests.Shared;
using System.Drawing;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/ContextMenuTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/ContextMenuTests.cs
index d5346396..80caca53 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/ContextMenuTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/ContextMenuTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/DevToolsTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/DevToolsTests.cs
index 9e2914fd..5e6393e3 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/DevToolsTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/DevToolsTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/FullscreenTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/FullscreenTests.cs
index 33daee13..d21d973f 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/FullscreenTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/FullscreenTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/HeightTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/HeightTests.cs
index 12212040..fbab12a9 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/HeightTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/HeightTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/LeftTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/LeftTests.cs
index 82afe2ec..bccc995e 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/LeftTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/LeftTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/LocationTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/LocationTests.cs
index d9729590..1701b96a 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/LocationTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/LocationTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
using System.Drawing;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/MaxHeightTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/MaxHeightTests.cs
index ca5fd035..cb1fd218 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/MaxHeightTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/MaxHeightTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/MaxSizeTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/MaxSizeTests.cs
index 3dfd16f0..94f9b935 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/MaxSizeTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/MaxSizeTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
using System.Drawing;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/MaxWidthTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/MaxWidthTests.cs
index 2ba58291..2a857f21 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/MaxWidthTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/MaxWidthTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/MaximizeTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/MaximizeTests.cs
index b4493dc2..c2c7049b 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/MaximizeTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/MaximizeTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/MinHeightTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/MinHeightTests.cs
index d769fc36..94dca9ad 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/MinHeightTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/MinHeightTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/MinSizeTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/MinSizeTests.cs
index 7e6150e9..716b9028 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/MinSizeTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/MinSizeTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
using System.Drawing;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/MinWidthTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/MinWidthTests.cs
index eee4f441..3a3b3209 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/MinWidthTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/MinWidthTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/MinimizeTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/MinimizeTests.cs
index 19c5b119..c7d4d36c 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/MinimizeTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/MinimizeTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/RegisterCustomSchemeHandlerTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/RegisterCustomSchemeHandlerTests.cs
index a312464f..94bc5f17 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/RegisterCustomSchemeHandlerTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/RegisterCustomSchemeHandlerTests.cs
@@ -5,7 +5,7 @@
using InfiniFrameTests.Shared;
using InfiniFrameTests.Shared.TestDoubles;
using System.Runtime.InteropServices;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
namespace InfiniFrameTests.WindowFunctionalities;
// ---------------------------------------------------------------------------------------------------------------------
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/ResizableTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/ResizableTests.cs
index 343e170a..eca0b82f 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/ResizableTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/ResizableTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/SizeTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/SizeTests.cs
index 63f1cf20..59378e45 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/SizeTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/SizeTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
using System.Drawing;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/TitleTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/TitleTests.cs
index bba45f40..8ecdab6b 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/TitleTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/TitleTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/TopMostTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/TopMostTests.cs
index f94f8edc..afa70124 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/TopMostTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/TopMostTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/TopTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/TopTests.cs
index 946167e4..d58f24ff 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/TopTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/TopTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/TransparentTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/TransparentTests.cs
index 298a1e10..a918f9e7 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/TransparentTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/TransparentTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/WidthTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/WidthTests.cs
index b10cd450..47c7f04c 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/WidthTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/WidthTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;
diff --git a/tests/InfiniFrameTests/WindowFunctionalities/ZoomTests.cs b/tests/InfiniFrameTests/WindowFunctionalities/ZoomTests.cs
index 0fc576af..5671fb6e 100644
--- a/tests/InfiniFrameTests/WindowFunctionalities/ZoomTests.cs
+++ b/tests/InfiniFrameTests/WindowFunctionalities/ZoomTests.cs
@@ -2,7 +2,7 @@
// Imports
// ---------------------------------------------------------------------------------------------------------------------
using InfiniFrame;
-using InfiniFrame.Native;
+using InfiniFrame.NativeBridge.Parameters;
using InfiniFrameTests.Shared;
namespace InfiniFrameTests.WindowFunctionalities;