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.
PE overlayA magic marker followed by the payload zip, 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 zip, re-verified before extraction.
created_at_unixi64
manifestManifestThe per-file table; see below.
license_textOption<String>EULA shown on the License page.
associationsVec<FileAssoc>File types to register under Software\Classes.
pluginsVec<PluginEntry>Bundled plugins and their phases.
shortcutsVec<ShortcutEntry>Shortcuts to create. dir, 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.
install_dir_restrictionEnforce, DefaultDirOnly, or BypassWhether a fresh interactive install may target a non-empty folder. Default Enforce.
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,   // in-zip path: patches/<blake3(rel)>.patch
    size: u64,
}
}

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

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), and features, the active feature packs. The next upgrade reads features to clean up dropped features and, under feature_mode = "sticky", to seed its base. See Feature packs.

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.