@matane-anime/extension-cli
v0.1.1
Published
ma-ext: create, build, test and benchmark Matane Anime extensions
Maintainers
Readme
@matane-anime/extension-cli
ma-ext: create, build, test and benchmark extensions for Matane Anime.
Install
Requires Node 22 or newer:
npm install --save-dev @matane-anime/extension-cli @matane-anime/extension-sdkOr start from a scaffold, which has both set up:
npx @matane-anime/extension-cli create my-site --name "My Site" --lang en
cd my-site
npm installCommands
| Command | What it does |
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
| ma-ext create <id> | Scaffolds ./<id> (--name, --lang, --dir): manifest, src/index.ts, tsconfig and package.json |
| ma-ext build [dir] | Bundles src/index.ts into dist/index.js (+ manifest.json and icon.png), checking it loads in the sandbox |
| ma-ext test [dir] | Runs popular → search → details → episodes → streams against the real site, with the app's checks |
| ma-ext bench [dir] | Times each call in the sandbox (--source, --pref, --runs <n>); --synthetic runs the built-in worst cases only |
| ma-ext repo keygen, repo build, repo verify | Creates, signs and checks extension repositories (below) |
test takes --source <key>, --query <text>, --pref key=value (repeatable) and -v/--verbose for the extension's
log output. Exit code is non-zero when a step fails.
Repositories
An extension repository is a static folder (host it anywhere): index.json, index.json.sig, one
<id>-<version>.zip per extension and its <id>.png icon. The app checks the index signature, then the SHA-256 and
size of everything it downloads.
ma-ext repo keygen --out ./keys # repo-key.pem (private, mode 600) + repo-key.pub
ma-ext build my-site # repo build reads the built dist/, it never builds
ma-ext repo build my-site other-site --out ./repo --name "My repository" --key ./keys/repo-key.pem
ma-ext repo verify ./repo --key "$(cat ./keys/repo-key.pub)"
ma-ext repo verify https://example.com/repo/ # a folder URL or the URL of index.jsonkeygen [--out dir]refuses to overwrite existing keys. Keeprepo-key.pemsecret and never commit it; publish the public key (and its fingerprint, which the app shows) so users can compare.build <extensionDir...> --out <dir> --name <name>needs--key <pem>(the private key ofkeygen), or--unsignedto publish without a signature (users then see "Unverified repository"). Every extension needsdist/fromma-ext buildand anicon.png(at most 512 KB) next to itsmanifest.json. The new index lists exactly the extensions given, withserialone higher than the index already in--out(or--serial <n>; apps refuse a lower one for a repository they trust). Files of older versions and unrelated files in--outare left alone.--base-url <url>writes absolutearchiveandiconURLs.verify <dirOrUrl> [--key ed25519:…] [--json]checks the signature, every archive (size, SHA-256, contents, manifest against its index entry) and icon. With--keyit also requires that key to be the signer; without it, it only reports the announced key. Exit code 0 when clean, 1 otherwise.
The dist/ folder can be loaded in the app in developer mode (Settings → Advanced → Developer mode, then Extensions →
Load from folder). The format, trust rules and what users see are in
docs/repositories.md.
Use from code
The package also exports what the commands are made of, for tests that run an extension the way the app does (since 0.1.1):
import { buildExtension } from '@matane-anime/extension-cli';
import { loadSource } from '@matane-anime/extension-cli/run';
const built = await buildExtension('.', { write: false }); // { manifest, code, warnings, ... } without touching dist/
const { client, runtime, call } = await loadSource('.', { prefs: [] }); // talks to the real site through a Node hostLicense
MIT
