plugin

Install plugin

Install a new plugin. The request body is a pluginInfo.json structure with branch and sha fields added to specify which branch and commit to install. The structure is NOT validated against a schema here, on purpose. FPP reads the keys it knows (repoName, srcURL, versions, dependencies, privacy, ...) and carries everything else through untouched, so a pluginInfo.json written for a newer FPP -- a key this release has never heard of, an unknown key inside privacy -- installs on this one. The Plugins page renders the parts it understands and ignores the rest (the full block is still shown as written). Strict validation lives in the fpp-data listing check (.github/schema/pluginInfo.schema.json), where a mistake is a rejected pull request rather than a plugin nobody can install. Keep it that way: any check added here must be on a key FPP acts on, never on the set of keys. privacyAccepted (optional, null allowed) is the privacy block the caller showed the operator, the same field POST /plugin/{RepoName}/upgrade takes. After the clone, before any dependency or the plugin's own install script, it is compared with the cloned copy's block (sends, collects, sensors, remoteAccess, systemChanges, closedCode): when they differ -- the listing is behind the repository, or the selected version pins an older commit -- the install is refused, the clone removed, and the reply carries Code: "PrivacyMismatch" and pending (the cloned block) so the caller can show it and post again with it as privacyAccepted. A body without the field is compared with the block recorded for that plugin from an earlier install, if there is one (the record survives an uninstall), and refused the same way when they differ; with no record either, it installs and records nothing, so the next update check reports privacyChanged. The block is recorded once the dependencies are in place, just before the plugin's own install script runs. dependencyPrivacyAccepted (optional) is a map repoName -> block or null for the dependency plugins the dialog also showed; each is gated and recorded the same way when that plugin is installed as a dependency of this one, and a dependency not in the map -- declared only in the cloned copy -- is refused before it is cloned (pending is then its listed block). Without the map, dependencies are installed as before.

post/api/plugin

Request body

object required

Response

Plugin installed

object required

Changes