Skip to content
Twig docs Open Twig MenuClose

The marketplace

5 built in

The Plugins screen: what a card tells you, what Install does, how a plugin from elsewhere is pinned to the code the owner approved, and how to get yours listed.

What a listing shows

Word countinstalledTwig · Panel · v2.0.0local only

Words, blocks and reading time for the page you are on. Updates as you type.

What it reads and changes
Reads
The blocks of the page you are on
Changes
Nothing, unless you run its Insert word count command, which puts the page’s word count into a block (refreshed when that block is edited)
Network
Nothing leaves this device
numbers need the server
sign in to rate
The Word count card as the Plugins screen draws it, installed.
  1. The name, with installed in the accent once it is on this device, or off while it is switched off.
  2. Who made it, its kind (Panel, Action, Block or View) and its version.
  3. local only, or uses the network when its Network line names something.
  4. The blurb: two sentences at most for a built-in, up to 1000 characters for a plugin listed by URL, and clamped to two lines at 833px and narrower.
  5. What it reads, changes and sends, in the author’s words, there to open before Install.
  6. Installs and the rating, from the sync server: no numbers yet while the server has none for it, the last numbers it saw when offline, and numbers need the server before this device has heard from the server at all.
  7. The switch: off keeps the plugin and its place, and undoes everything it registered.
  8. Install, or Remove once it is installed.
  9. The stars, once it is installed. Rating needs a signed-in account on the server’s list; rating again replaces yours.

The catalog is src/plugins/catalogue.ts, and it is data. Each entry is built to /plugins/<id>.js with its dependencies bundled in, and the service worker keeps every one, so the whole catalog installs offline. Translate and Summarize install offline too, but their first run downloads a runtime and a model (Translate, a model for each language pair), which needs the network and is kept in the browser’s cache, not by the service worker.

Install, switch off, remove

YouWhat happensWhat the server hears
InstallTwig imports the module and calls its default export. It runs now and at every launch.The plugin’s id and nothing else: no account, no device, no graph.
Install, and it failsIt stays listed, switched on, with the error beside it; fixing the URL means removing it and adding it again.Nothing: a plugin that did not load was not installed.
Switch offEverything it registered is undone. It stays installed, in its place.Nothing.
Switch onIt is imported and started again.Nothing.
RemoveSwitched off and taken off this device’s list.Nothing.
Another device installs itWith Sync installed plugins on, this device installs it to match.Nothing: only an install by hand is counted.
Delete local dataEvery plugin is switched off, and Sync installed plugins turns off on this device; the list stays, so nothing has to be found again.Nothing.

Local only, or uses the network

LineSaysLeft empty
ReadsWhat it looks at.Not stated by its author, on a plugin listed by URL.
ChangesWhat it writes, adds or navigates to.Not stated by its author, on a plugin listed by URL.
NetworkWhat leaves the device, and where it goes.Nothing leaves this device, and the card says local only.

Review and pinning

A plugin that lives somewhere else is listed from the office, the owner’s console at /office. Listing it pins it: from then on every device runs the exact bytes the owner approved, or nothing.

  1. The owner gives a name and an author (60 characters each), a kind, a version (32), the https URL of the module, a blurb, and the Reads, Changes and Network lines (1000 characters each).
  2. The id is the name in lowercase with hyphens behind x-: at most 50 characters with the prefix. No built-in id may start with x-, so a future built-in can never take an added plugin’s place.
  3. The server refuses a URL that is not https, a URL another plugin is listed at or ever was, and a name whose id is taken, by a live plugin or a removed one.
  4. It fetches the module once, following no redirects, within 10 seconds and 5 MB, and keeps its SHA-384.
  5. The card is in every marketplace at its next look at the listing, and counts installs and takes ratings like any other.
RuleWhat it means
Listing id and hashInstalling from the card records which listing it is and the approved hash on the device’s entry, and in the synced list. The device finds it again after the office moves its URL, and can check it before it has the listing at all.
SHA-384, every startThe device fetches the module, hashes it, and imports those bytes and nothing else. It keeps a copy by hash, so the plugin also starts offline, checked again.
Nothing to check, no startAn entry with no approved hash does not start, and neither does one whose listing id the listing no longer has.
Other code at the URLThe plugin does not start, and its card says This plugin’s code changed since it was approved.
One bundled fileA relative import cannot resolve from the checked bytes. An import from an absolute URL is fetched as it is, and is not checked.
The same bytes for everyoneThe module must serve every client the same file. A CDN that builds per browser (esm.sh, for one) cannot be pinned, and an address that redirects (an unversioned jsDelivr or unpkg link) is refused: list the versioned one.
5 MBA module over 5 MB is refused, whether its Content-Length says so or it is counted as it arrives.
Previous URLsA URL the office moves a plugin away from stays with that plugin: devices that installed it there still find it, and no other plugin can be listed there.
Removal is a kill switchRemoving leaves a tombstone. Every device that has the plugin turns it off at its next look at the listing — at launch, on opening Plugins, or when its window comes back into view, at most once a minute — and says Removed from the marketplace by its owner. Its installs and ratings stay, it takes no new ones, and its name and URL stay taken. Restore brings it back, numbers and all, but a device that turned it off leaves it off until someone switches it on there.

Changing a listed plugin

  1. Check code asks the URL for the module again. If it serves other code, the office shows Code changed and the hash it found. The public listing carries that flag too, but devices do not act on it: they go on checking against the approved hash, and refusing anything else.
  2. Re-approve pins the hash the check found. The server fetches the module once more and refuses if the URL now serves anything else: it approves the code that was read, never whatever the URL serves by the time the button is pressed.
  3. A new URL or a new version fetches and pins again, and devices that installed it at the old URL follow.
The office canBuilt-inListed by URL
Hide: out of the marketplace, still working and listed on a device that has itYesYes
Feature: listed firstYesYes
Reword the blurb and the three lines. Emptied on a built-in, a line goes back to the plugin’s own wordsYesYes
Change the URL or the versionNoYes, pinning again
Remove, leaving a tombstoneNo: hide it insteadYes

The office is for the accounts named in TWIG_ADMIN_EMAILS that are also on TWIG_ALLOWED_EMAILS. Until the first is set, every account on the second is an admin, so it has to be set before that list holds anyone but the owner. It is reached at /office, and from a row in Settings that only admins see; the server answers 401 without a sign-in and 403 to anyone else. The marketplace fetches the listing with the numbers and remembers it; a device that has never reached the server shows the catalog alone.

Getting yours listed

DoorHowWhat you get
The catalogA pull request: a directory under src/plugins/catalogue/ with an index.ts whose default export is the plugin, and one more entry in src/plugins/catalogue.ts with its name, kind, blurb and the three lines.Built with every release, served from Twig’s own address, installable offline. Not pinned, because it is Twig’s own code.
The officePublish one bundled ES module with a default export over https, allowed by CORS, the same bytes to every client, under 5 MB, at an address that does not redirect. Send the owner its URL, a name, the kind, the version, a blurb and the three lines.A card like any other, pinned to the code the owner read.

Ship a change at a new URL or version, or ask the owner to re-approve; until then devices keep refusing the new code. There is no review queue: listing is the owner’s choice, and the office can vouch for a plugin no more than the catalog can.

The numbers

By URL

The field at the bottom of the screen takes any ES module served over https, or from this site. It is brought in with a dynamic import, so it has to be reachable, served as JavaScript, and allowed by CORS. Nothing added there is counted or rated; it is between you and wherever it came from. A module the office has listed is the exception: added from its card, at its URL, or at a URL the office moved it from, it is that card’s plugin, checked against its approved hash like one installed from the card. A built-in’s own path, /plugins/<id>.js, is that built-in’s card.