Build extensions / Concepts
Extension settings
An extension’s settings are declared in package.json, and OrbTorrent draws them on the extension’s page. You don’t build any interface.
{ "preferences": [ { "name": "apiKey", "type": "password", "title": "API key", "description": "Your free VirusTotal API key.", "placeholder": "64 letters and digits", "required": true }, { "name": "scope", "type": "dropdown", "title": "Files to check", "default": "risky", "data": [ { "title": "Programs, archives and documents", "value": "risky" }, { "title": "All files", "value": "all" } ] }, { "name": "uploadUnknown", "type": "checkbox", "title": "Files VirusTotal hasn't seen", "label": "Upload them to be scanned (up to 32 MB each)", "default": false } ]}| Type | Value | Draws |
|---|---|---|
textfield |
Text | A text field. |
password |
Text | A secure field, with Save and Remove. The value is kept in the macOS Keychain, never in a file, and hidden in logs. It can’t have a default. |
checkbox |
true or false |
A checkbox, with label beside it. |
dropdown |
One of data’s values |
A menu of data’s titles. |
Every setting has a name (letters, digits and underscores, starting with a letter), a type and a title, and can have a description, a placeholder, a default, and required. Manifest has the rules.
Read them
Section titled “Read them”import { Download, Result, getPreferenceValues } from "@orbtorrent/api";
export default async function scan(download: Download): Promise<Result> { const { apiKey, scope, uploadUnknown } = getPreferenceValues(); // …}Every setting has a value when a hook runs: what the user chose, or its default, or else "", false, or a dropdown’s first option. You never need to check for undefined.
They’re typed. orb build writes orb-env.d.ts from package.json, so getPreferenceValues() knows each setting’s name and type, and a dropdown’s values:
// Generated by `orb build` from package.json. Don't edit: change package.json instead.
declare global { interface OrbPreferences { /** Your free VirusTotal API key. */ apiKey: string; scope: "risky" | "all"; uploadUnknown: boolean; }}
export {};Leave orb-env.d.ts out of version control: the template’s .gitignore already does.
Required settings
Section titled “Required settings”While a required setting is empty, the extension shows Needs setup on the Extensions page, and its hooks are skipped rather than run. Its page says which settings to add. Use required for anything the extension can’t work without, such as an API key.
Help the user set it up
Section titled “Help the user set it up”Put the steps to set your extension up, such as how to get an API key, in help.md next to package.json. OrbTorrent shows it beside the settings, under How to Set It Up.
### Get a free API key
1. Sign up or sign in at [virustotal.com](https://www.virustotal.com).2. Open your profile menu and choose **API key**.3. Copy the key into **API key** here and press **Verify**.Check them with verify
Section titled “Check them with verify”To check settings when the user presses Verify, such as that an API key works, name a file in verify:
{ "verify": "verify" }Its default export gets the settings, and says whether they’re right:
import { VerifyResult, fetch } from "@orbtorrent/api";
/** The EICAR test file, which every antivirus engine knows. */const knownFile = "275a021bbfb6489e54d471899f7db9d1663fc695ec2fe2a2c4538aabf651fd0f";
export default async function verify(preferences: OrbPreferences): Promise<VerifyResult> { const key = preferences.apiKey.trim(); if (!key) return { ok: false, message: "Enter your API key." }; const response = await fetch(`https://www.virustotal.com/api/v3/files/${knownFile}`, { headers: { "x-apikey": key, accept: "application/json" }, }); switch (response.status) { case 200: return { ok: true, message: "The key works." }; case 401: case 403: return { ok: false, message: "VirusTotal didn't accept this key. Copy it again from your VirusTotal profile." }; default: return { ok: false, message: `VirusTotal answered with status ${response.status}. Try again in a moment.` }; }}This is shortened from VirusTotal Scan’s own, which looks up a file every antivirus engine knows.
- Return
{ ok: true }, with an optionalmessage, or{ ok: false, message }. The message shows under the settings. verifyhas the same permissions as the hooks, and the same limits as abeforeStarthook: 15 seconds, of which 10 of CPU.- Test it with
"verify": truein a test file.
When settings change
Section titled “When settings change”Settings are read fresh for every run, so a hook always sees the latest. Removing an extension deletes its settings, including passwords in the Keychain.