Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Manifest and payload format

These are the common crate types that describe what an installer carries. They are serialized to JSON, signed, and embedded as resources. Field documentation lives in common/src/model/.

What is embedded in the installer .exe

ResourceIdContents
RT_RCDATA2SignedPayload JSON: the manifest and metadata, plus the signature.
RT_RCDATA3The uninstaller .exe.
RT_RCDATA4The payload length, a little-endian u64.
RT_RCDATA5The optional header banner PNG. Not signed; see Branding.
RT_RCDATA6The optional dark-theme header banner PNG, shown by the WinUI wizard in dark mode. Not signed; see Branding.
PE overlayA magic marker followed by the payload archive, appended after all resource passes.

SignedPayload

#![allow(unused)]
fn main() {
struct SignedPayload {
    payload_json: String,   // exact UTF-8 bytes the signature was computed over
    signature_hex: String,  // Ed25519 signature of payload_json
}
}

The verifier checks the signature against the raw payload_json bytes, then parses InstallerPayload from them. Signing the exact bytes avoids any serializer-determinism trap.

InstallerPayload

FieldTypeNotes
kindFull or Patch
productStringDisplay name.
product_idStringRegistry-safe id: Uninstall key, ProgIDs, data folder, upgrade detection.
publisherStringUninstall data folder and the Apps “Publisher” field.
hintway_tenant_idOption<String>Hintway tenant UUID configured at pack time.
from_versionOption<String>Set for patches; pins the target version.
to_versionString
min_installer_versionStringMinimum stub version allowed to run this payload. Default 1.0.0.
payload_blake3StringBLAKE3 of the payload archive, re-verified before extraction.
created_at_unixi64
manifestManifestThe per-file table; see below.
license_textOption<String>UTF-8 EULA source rendered as CommonMark on the License page.
license_textsBTreeMap<String, String>CommonMark EULA translations by UI language code; picked over license_text for that language.
associationsVec<FileAssoc>File types to register under Software\Classes. Each has ext, description, and optional icon (token template, empty means the main exe) and icon_index (>= 0 an index, < 0 a negated resource id; default 0).
pluginsVec<PluginEntry>Bundled plugins and their phases.
shortcutsVec<ShortcutEntry>Shortcuts to create. dir, name, target, and args are token templates. None are created unless declared.
registryVec<RegistryEntry>Free-form registry entries. Key and value are token templates.
force_reinstallboolDev: rewrite all, remove orphans, skip the from-version check.
purge_unknown_filesboolFull installs: remove unknown or leftover files. Ignored for patches.
skip_license, skip_pathboolTrim the wizard.
allow_force_path_window_stateboolThe runtime --force-show-path-window flag may show the page hidden by skip_path. Default false.
install_dir_restrictionEnforce, DefaultDirOnly, or BypassWhether a fresh interactive install may target a non-empty folder. Default Enforce.
uninstall_dir_policyPurge or TrackedWhat the uninstaller removes from the install folder. Default Purge.
default_install_dirOption<String>Proposed path; %VAR% tokens are expanded.
launch_optionChecked, Unchecked, or HiddenThe final-page “launch now” checkbox.
upgrade_minimal_uiboolUpgrades use the minimal UI; a first install always gets the wizard.
show_uninstall_completeboolShow the “uninstall complete” message box. Off by default.

Manifest, FileEntry, and PatchInfo

#![allow(unused)]
fn main() {
struct Manifest {
    version: String,
    exe: Option<String>,               // main exe, relative to the install root
    files: HashMap<String, FileEntry>, // keyed by relative path
    deleted_files: Vec<String>,        // removed at install time (patches)
    full_size: u64,
    total_patch_size: u64,
    features: Vec<String>,             // declared feature-pack ids
    default_features: Vec<String>,     // subset enabled by default on a fresh install
    feature_mode: FeatureMode,         // upgrade base: "sticky" (default) or "override"
}

struct FileEntry {
    hash: String,            // BLAKE3, checked after each write or patch
    size: u64,
    patch: Option<PatchInfo>,
    feature: Option<String>, // feature pack this file belongs to; None = base
}

struct PatchInfo {
    file: String,   // archive path: patches/<blake3(rel)>.patch
    size: u64,
}
}

Payload archive layout

The payload is a PakLib archive: independent zstd blocks of up to 64 MiB (level 20) that never span two files, so the installer decodes files in parallel straight from the memory-mapped exe. Already-compressed media and HDiffPatch patches are stored raw, as is any block that zstd shrinks by less than 2%.

Full files live under full/<rel>; binary patches under patches/<blake3(rel)>.patch. The installer reads PatchInfo.file verbatim as the archive path, so the name in the manifest and the actual entry name are produced by one function in the builder; they always match. Unchanged files in a patch have no entry, only their recorded hash.

Cargo builds PakLib from the vendor/PakLib submodule with CMake and vcpkg, both part of the Visual Studio C++ workload, and links it statically: the installer stays a single exe. PAKLIB_BUILD_DIR points at an existing windows-static preset build instead.

Installers built before PakLib payloads carried a ZIP instead. The formats do not mix: each installer only reads the payload it was packed with, and pack self-verifies that pairing at build time.

InstallInfo

Persisted to <data-dir>\installer_info.json by the installer and read by the uninstaller. It holds product, product_id, publisher, hintway_tenant_id, version, install_dir, installed_at_unix, registry_key (equal to product_id), exe, the associations, the resolved shortcuts, the resolved registry entries to remove, requires_admin (which drives the HKLM and %ProgramData% versus HKCU and %LOCALAPPDATA% choice), features, the active feature packs, uninstall_dir_policy, and created_dirs, the absolute paths of the folders the installer created. The next upgrade reads features to clean up dropped features and, under feature_mode = "sticky", to seed its base. See Feature packs. created_dirs is kept across upgrades into the same folder; see Uninstall.

In the payload, registry and shortcuts hold token templates. In installer_info.json they hold the resolved entries actually written, with absolute paths, so the uninstaller matches and removes exactly those.

Records written before the product/id split have no product_id; readers fall back to registry_key and a sanitized product.

Backward compatibility

New fields use #[serde(default)], so installers can read JSON written by older versions; missing fields take sensible defaults. The round-trip is covered by tests in the model modules.