Skip to content

Publish and security

Terminal window
yonto-plugin bundle

Builds the publishable file, dist/<id>-<version>.js, and a zip of it, dist/<id>-<version>.zip, and prints the zip’s size and its SHA-256. The zip holds one entry, the same file, compressed.

Put the zip anywhere that serves it over HTTPS, such as a GitHub release. A viewer installs it with Settings, Plugins, Install from URL.

Once a version is public, never replace the file at its address. A repo pins each plugin by its SHA-256, so a file that changed under the same address is refused, correctly. Fix a plugin by raising version, bundling again, and publishing a new address.

A repo is one address that lists many plugins, so a viewer adds all of them at once. Put your plugins in one directory, one folder each, and run:

Terminal window
yonto-plugin index plugins --base-url https://plugins.example.com > index.json

It bundles each plugin and writes the index: for each, an entry whose address is <base-url>/<id>/<id>-<version>.zip#sha256=…. Upload the zips where the addresses say, and index.json at the address you will give viewers.

Then check what you published, from the outside, as a viewer’s Yonto will:

Terminal window
yonto-plugin index --check https://plugins.example.com/index.json

It downloads the index and every plugin it lists, and holds each to its SHA-256, manifest and the rules above. It reports every problem, not just the first.

A viewer adds the repo under Settings, Repos, Add a repo.

The install dialog shows a plugin’s name, its version and where it can reach, which comes from the manifest. So the manifest is the plugin’s promise, and the viewer is the one who agrees to it.

  • Reach as few hosts as you can, and write them as exact hosts. A wildcard that covers a host you do not need asks the viewer to trust more.
  • A plugin that sets hostsFromConfig asks the viewer a further question, and Yonto does not run it before the answer. Only the kind of plugin that reads addresses the viewer supplies can justify one.
  • Never send a viewer’s key, token or typed text to a host the viewer did not choose.
  • A plugin can never reach a private address on its own, such as localhost, 192.168.x.x or *.local. Only an address the viewer typed into a url field is allowed. That is how a plugin for a server on the viewer’s own network works at all, and why allowedHosts for it is empty.

Plugins are code, and they run in a sandbox with no files, no sockets and no timers, which is why the only way out is yonto.fetch. A viewer should still only install one from an address they trust, and you should write yours so that one who did not read it could not be hurt by it.

  1. lint and doctor --replay are green.
  2. contractVersion is what lint asks for, and no more.
  3. allowedHosts is as small as it can be.
  4. Every reason you throw names the part that failed, in one sentence, and the logs hold no URL, key or query.
  5. doctor.json and fixtures/ contain no key and no cookie.
  6. version is new.