wayBetter Store

(FOSS) Ein Pull Request ist eine Einreichung

Veröffentliche dein eigenes.

Ein Theme ist eine JSON-Datei. Ein Plugin ist eine JavaScript-Datei. Bau es, probier es in der App aus und füg es dann dem Store hinzu: ein Ordner in einem Pull Request, oder die Datei in einem Issue, wenn du kein git nutzt. Beides braucht ein kostenloses Konto auf git.crt.fyi, sonst nichts.

1

Bau es

Starte mit einer funktionierenden Datei. Das Gerüst-Werkzeug schreibt dir eine; der Bereich Erstellen in der App selbst (wayBetter → Erstellen) hat Beispiele und die aktuellen Theme-Werte.

Ein Theme

Farben, Schriften, Ecken, Dichte, Layout, Hintergrund, Effekte. Drei Farben genügen; der Rest wird abgeleitet, und Text bleibt lesbar.

Oder bau es in der App: Darstellung → Theme-Builder → Exportieren. THEMES.md listet alles auf, was ein Theme festlegen kann.

Ein Plugin

Eine Klasse mit start() und stop() und ein Header, der sagt, wer es gemacht hat und was es nutzt.

Füg --ts für ein TypeScript-Projekt hinzu. PLUGINS.md beschreibt die API, die Berechtigungen und das Live-Neuladen.

hide-trends.plugin.js
/**
 * @name Hide Trends
 * @description Hides the trends box in the right column, so the timeline is the only thing moving.
 * @version 1.0.0
 * @author you
 * @permissions network:none
 */
module.exports = class HideTrends {
  start() { wayBetter.api.injectCSS('hide-trends', '[data-testid="sidebarColumn"] section { display: none }'); }
  stop()  { wayBetter.api.clearCSS('hide-trends'); }
};

Der Store liest Name, Autor, Version, Beschreibung und Berechtigungen eines Plugins aus diesem Header und Name, Autor und Beschreibung eines Themes aus dessen JSON. Der Installationsbildschirm zeigt dieselben Werte, die beiden können also nie voneinander abweichen.

2

Probier es aus

Der Store ist optional. Eine Datei, die funktioniert, lässt sich schon teilen.

  • Zieh die Datei auf das wayBetter-Fenster. Du bekommst denselben Installationsbildschirm wie bei einem Store-Eintrag: Name, Autor, Version, SHA-256, Berechtigungen, der Code.
  • Schalte den Entwicklermodus ein (Einstellungen → Entwickler), während du arbeitest: Ein gespeichertes Plugin, eine Theme-Datei oder custom.css lädt in allen Tabs gleichzeitig neu.
  • Teile es ohne den Store. Schick die Datei oder einen waybetter://install-Link auf eine https-URL bei waybetter.fyi, cdn1.crt.fyi oder eine Rohdatei auf git.crt.fyi. Ohne den Installationsbildschirm wird es nie installiert.
3

Füg einen Ordner hinzu

Jeder Store-Eintrag ist ein Ordner unter store/<app>/ im Repository. Der Ordnername ist die Id des Eintrags und seine Adresse hier: /store/plugins/<id>/.

store/x/ — die Einträge von wayBetter for X
store/x/plugins/hide-trends/
  hide-trends.plugin.js   the plugin, exactly as it installs
  item.json               { "category": "focus", "tags": ["trends", "sidebar"] }
  preview.svg             optional, 640×400 (.svg or .png); drawn for you without one

store/x/themes/midnight-mint/
  theme.json              the theme, as Appearance → Export writes it
  item.json               { "version": "1.0.0" }
  preview.svg             optional; drawn from the theme without one
category
Plugins: reading, writing, filters, focus oder tools. Themes: dark oder light, aus dem mode des Themes übernommen, wenn du es weglässt.
tags
Bis zu 12 Wörter, nach denen Leute suchen würden.
version
Nur bei Themes (die eines Plugins steht in seinem Header). Erhöhe sie, wenn du die Datei änderst.
Beschreibung
Ein oder zwei Sätze, die sagen, was es tut, mindestens 50 Zeichen. Die ersten 160 werden zur Suchmaschinen-Beschreibung seiner Seite.

Das ist die ganze Einreichung. Seite, Karte, Sucheintrag, Link-Vorschau, strukturierte Daten und Sitemap-Eintrag entstehen beim Bauen der Website aus dem signierten Katalog. store/README.md enthält alle Regeln.

4

Führ die Prüfungen aus

Es gibt kein gehostetes CI. Die Prüfungen sind Befehle, die du vor dem Senden ausführst und die ein Maintainer vor dem Merge noch einmal ausführt.

in deinem Klon
git submodule update --init
bun install --frozen-lockfile
bun run check:store      # your folder, against the Store's rules
bun run test             # everything else, including the site's SEO test
  • Ids und NamenOrdner-Id (a-z 0-9 -, bis zu 40), name.plugin.js, keine Duplikate innerhalb einer App
  • GrößeEintragsdateien bis 2 MiB, Vorschauen bis 300 KB im Format 16:10
  • Der Header@name, @version, eine Beschreibung und eine @permissions-Zeile, die network oder network:none nennt
  • Ehrliche Berechtigungennetwork:none wird abgelehnt, wenn der Code fetch, XMLHttpRequest, WebSocket, EventSource oder sendBeacon aufruft; Aufrufe der geschützten API müssen angegeben sein
  • Kein Remote-Codekein eval, new Function oder import(); keine Skripte oder fremden Dateien in einer Vorschau; kein @import und keine fremden URLs im CSS eines Themes
  • Der Katalogdie Einträge ergeben einen Katalog, den die Apps akzeptieren (die Regeln des Frameworks selbst), und der veröffentlichte Katalog passt weiter zu seiner Signatur und seinen Hashes
  • Suche und TeilenSeitentitel bis 60 Zeichen, Beschreibung 50 bis 160, beide eindeutig
5

Schick es ab

Zwei Wege hinein. Beide brauchen ein kostenloses git.crt.fyi-Konto: Jeder kann sich registrieren, und ein Maintainer gibt jedes neue Konto von Hand frei.

Pull Request

  1. Forke das Repository auf git.crt.fyi.
  2. Füg deinen Ordner auf einem Branch hinzu und führ die Prüfungen aus.
  3. Eröffne den Pull Request. Die Vorlage fragt, was es tut und was es nutzt.

Kein git? Eröffne ein Issue

  1. Wähl die Vorlage Theme oder Plugin.
  2. Häng die Datei an (und eine Vorschau, wenn du eine hast).
  3. Ein Maintainer legt den Ordner für dich an.

Dann signiert ein Maintainer

Der Signaturschlüssel des Stores ist absichtlich offline, ein Merge ist also noch keine Veröffentlichung. Nach dem Merge liest ein Maintainer den Code, führt waybetter store build und waybetter store sign auf dem Rechner mit dem Schlüssel aus und pusht. Die Website wird neu gebaut, dein Eintrag bekommt seine Seite, und jede App sieht ihn, sobald sie den signierten Katalog das nächste Mal liest.

Für alles im signierten Katalog bürgt dieser Schlüssel; deshalb liest ein Mensch jedes Plugin, bevor es signiert wird.

{ }

Das Katalogformat

Eine Datei für alle wayBetter-Apps. Du bearbeitest sie nie von Hand: Sie wird aus den Ordnern gebaut.

catalog.json (Format 2)Offen
{ "format": 2, "name": "wayBetter Store", "generatedAt": "2026-09-30T…Z", "items": [
  { "apps": ["x"], "kind": "plugin", "id": "thread-reader", "name": "Thread Reader",
    "author": "wayBetter", "version": "1.2.0", "description": "…",
    "category": "reading", "tags": ["threads"],
    "url": "https://waybetter.fyi/store/plugins/bt-thread-reader.plugin.js",
    "file": "bt-thread-reader.plugin.js", "sha256": "<64 hex>", "size": 10961,
    "preview": "https://waybetter.fyi/store/previews/plugin-thread-reader.svg",
    "permissions": ["ui", "clipboard", "commands", "network:none"] }
] }
  • Signiert. catalog.json.sig ist eine Ed25519-Signatur über die exakten Bytes von catalog.json. Apps prüfen sie mit dem einkompilierten öffentlichen Schlüssel und danach Größe und SHA-256 jedes Downloads.
  • Streng. Unbekannte Felder, mehr als 500 Einträge oder eine Datei über 1 MiB lassen den ganzen Katalog scheitern. store-catalog.schema.json ist das JSON Schema; STORE.md im Framework enthält jede Regel.
  • Geteilt. Jeder Eintrag nennt seine apps. Eine App prüft die ganze Datei und behält nur ihre eigenen Einträge.
Aa

Sprachen

Keine Store-Einträge: Alle 51 Sprachen sind in die App eingebaut und werden bei Bedarf geladen.

  • Korrigiere oder vervollständige eine Übersetzung in apps/desktop/locales/<tag>.json, per Pull Request oder per Issue mit der geänderten Datei im Anhang.
  • Prüf sie mit bun run i18n:check: Schlüssel, Platzhalter, Pluralformen, kein Markup. Die Ausgabe muss 0 error(s) lauten.
  • Sie kommt mit dem nächsten App-Update, nicht über den Store. TRANSLATING.md erklärt die Syntax der Meldungen und wie du deine Wörter in der App siehst.

Sieh dir an, was schon da ist.

Jeder Eintrag im Store zeigt seinen Code. Die mitgelieferten Plugins sind die besten Beispiele dafür, wie man die API gut nutzt.