# How the `install_sidestore_operation` Flow Works in iloader

> Explore the three-stage install_sidestore_operation flow in iloader. Learn how TypeScript frontend, operation runner, and Rust backend deploy SideStore to iOS devices with real-time progress.

- Repository: [Nicholas Sharp/iloader](https://github.com/nab138/iloader)
- Tags: internals
- Published: 2026-09-13

---

**The `install_sidestore_operation` flow is a three-stage pipeline—download, install, and pairing—that coordinates between a TypeScript frontend definition, a generic operation runner, and a Rust backend command to deploy SideStore onto iOS devices while streaming real-time progress events.**

The `install_sidestore_operation` command serves as the primary deployment mechanism in the [nab138/iloader](https://github.com/nab138/iloader) repository for installing SideStore (and optionally LiveContainer) onto connected iOS hardware. This architecture separates concerns into a declarative UI layer, a generic orchestration handler, and a native Rust implementation that performs the actual sideloading work while emitting state updates through Tauri’s event system.

## Frontend Operation Definition

The flow begins with a static configuration object defined in [`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts). This **Operation** interface declares the metadata and sequential steps that the UI will render during execution.

```typescript
export const installSideStoreOperation: Operation = {
  id: "install_sidestore",
  titleKey: "operations.install_sidestore_title",
  successTitleKey: "operations.install_sidestore_success_title",
  successMessageKey: "operations.install_sidestore_success_message",
  steps: [
    { id: "download", titleKey: "operations.install_sidestore_step_download" },
    { id: "install",  titleKey: "operations.install_sidestore_step_install" },
    { id: "pairing", titleKey: "operations.install_sidestore_step_pairing" },
  ],
};

```

This object enumerates the three discrete phases—**download**, **install**, and **pairing**—that map directly to the backend’s execution stages. The `id` field `"install_sidestore"` serves as the root identifier for both the event channel name and the Tauri command invocation.

## Orchestrating the Flow with `startOperation`

When a user initiates installation, the frontend invokes the generic `startOperation` utility located in [`src/App.tsx`](https://github.com/nab138/iloader/blob/main/src/App.tsx). This function establishes the state management and event listening infrastructure before delegating to the Rust backend.

The orchestration follows three distinct phases:

1. **State Initialization** – Resets the operation state to track started, completed, and failed steps.
2. **Event Listener Registration** – Subscribes to Tauri events on the channel `operation_install_sidestore` using `listen<OperationUpdate>()`.
3. **Command Invocation** – Calls `invoke("install_sidestore_operation", params)` to trigger the Rust routine.

```typescript
<button
  onClick={() => {
    if (!ensuredLoggedIn() || !ensureSelectedDevice()) return;
    startOperation(installSideStoreOperation, {
      nightly: false,
      liveContainer: false,
    }).catch(e => console.error(e));
  }}
>
  {t("app.sidestore_stable")}
</button>

```

The `startOperation` handler accepts an `InstallParams` object containing boolean flags for `nightly` (determining which IPA variant to download) and `liveContainer` (controlling whether to bundle LiveContainer). These parameters pass through to the Rust command unchanged.

## Backend Command Implementation in Rust

The actual work occurs in [`src-tauri/src/sideload.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/sideload.rs) within the async function `install_sidestore_operation`. This command receives the **AppHandle** for event emission and the deserialized **InstallParams** struct.

```rust
pub async fn install_sidestore_operation(
    app: tauri::AppHandle,
    params: InstallParams,
) -> Result<(), String> {
    // 1. Download the SideStore IPA
    // 2. Sign and install on the device
    // 3. Copy the pairing file
    // Emitting events via app.emit_all() at each transition
}

```

The Rust implementation executes three sequential sub-tasks:

- **Download** – Fetches the appropriate SideStore IPA based on the `nightly` flag.
- **Install** – Handles code signing and deployment to the connected iOS device.
- **Pairing** – Transfers the pairing file required for subsequent device communication.

At each transition point, the backend emits structured events using `app.emit_all("operation_install_sidestore", OperationUpdate { ... })`. These payloads carry a status field (**started**, **finished**, or **failed**) and the step identifier, enabling the frontend to update progress bars and status messages reactively.

## Event-Driven State Synchronization

The frontend listener registered by `startOperation` processes the **OperationUpdate** events streaming from Rust. When an event arrives, the handler mutates the `operationState` to reflect the current step status, which drives the `<OperationView>` component’s rendered output.

This unidirectional data flow ensures that:
- UI progress indicators update immediately when a step starts.
- Completed steps accumulate in the `completed` array for visual checkmarks.
- Errors trigger the `failed` state, displaying the `AppError` payload to the user without manual polling.

## Practical Usage Example

To trigger the installation flow programmatically from a custom component:

```typescript
import { installSideStoreOperation } from './components/operations';
import { startOperation } from './App';

const deploySideStore = async (useNightly: boolean) => {
  if (!ensureSelectedDevice()) return;
  
  try {
    await startOperation(installSideStoreOperation, {
      nightly: useNightly,
      liveContainer: false,
    });
    console.log("Installation completed successfully");
  } catch (error) {
    console.error(`Deployment failed: ${error.message}`);
  }
};

```

This pattern leverages the same operation definition and backend command used by the built-in UI buttons, ensuring consistent behavior across the application.

## Summary

- **Operation Definition**: Declared in [`src/components/operations.ts`](https://github.com/nab138/iloader/blob/main/src/components/operations.ts) with three steps: download, install, and pairing.
- **Frontend Orchestration**: The `startOperation` function in [`src/App.tsx`](https://github.com/nab138/iloader/blob/main/src/App.tsx) initializes state, listens for `operation_install_sidestore` events, and invokes the Tauri command.
- **Backend Execution**: The `install_sidestore_operation` async function in [`src-tauri/src/sideload.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/sideload.rs) performs the actual device work and emits progress events.
- **Event Bridge**: Tauri’s `emit_all` and `listen` APIs synchronize state between Rust and TypeScript without polling.
- **Reusable Architecture**: The generic `Operation` interface and `startOperation` handler allow new installer flows to be added by defining a new operation object and corresponding Rust command.

## Frequently Asked Questions

### What parameters does `install_sidestore_operation` accept?

The command accepts an `InstallParams` object containing two boolean properties: `nightly` (determining whether to download the nightly or stable IPA build) and `liveContainer` (specifying whether to include LiveContainer in the installation bundle). These parameters originate in the UI and pass through to the Rust backend via Tauri's command invocation.

### How does the frontend track the installation progress?

The frontend registers a Tauri event listener for the channel `operation_install_sidestore` before invoking the command. The Rust backend emits `OperationUpdate` structs with `started`, `finished`, or `failed` statuses at each step transition. The frontend listener captures these payloads and updates the reactive `operationState`, which the `<OperationView>` component renders as progress indicators and step completions.

### Where is the IPA signing and installation logic implemented?

The actual device communication, code signing, and IPA installation occur in [`src-tauri/src/sideload.rs`](https://github.com/nab138/iloader/blob/main/src-tauri/src/sideload.rs) within the `install_sidestore_operation` function. This Rust code handles the low-level iOS deployment protocols, including transferring the binary to the device and installing the provisioning profile, while the TypeScript frontend remains responsible for UI state management.

### Can this flow be adapted to install applications other than SideStore?

Yes. The architecture uses a generic `Operation` interface and the reusable `startOperation` handler. To install a different application, define a new operation object in [`operations.ts`](https://github.com/nab138/iloader/blob/main/operations.ts) with the appropriate steps, implement a corresponding Tauri command in the Rust backend following the `install_sidestore_operation` pattern, and map the command ID to the operation ID. The event emission and state management infrastructure will work without modification.