wayBetter Store

(FOSS) pull request ก็คือการส่งผลงาน

เผยแพร่ ของคุณเอง

ธีมคือไฟล์ JSON หนึ่งไฟล์ ปลั๊กอินคือไฟล์ JavaScript หนึ่งไฟล์ สร้างขึ้นมา ลองในแอป แล้วเพิ่มเข้าร้านค้า: โฟลเดอร์เดียวใน pull request เดียว หรือแนบไฟล์ใน issue ถ้าคุณไม่ใช้ git ทั้งสองทางต้องมีบัญชี git.crt.fyi ที่สมัครฟรี และไม่ต้องใช้อย่างอื่นอีก

1

สร้าง

เริ่มจากไฟล์ที่ใช้งานได้ ตัวสร้างโครงจะเขียนให้หนึ่งไฟล์ ส่วนหัวข้อสร้างในแอปเอง (wayBetter → สร้าง) มีตัวอย่างและค่าธีมปัจจุบันให้ดู

ธีม

สี ฟอนต์ มุม ความหนาแน่น เลย์เอาต์ พื้นหลัง เอฟเฟกต์ สามสีก็เพียงพอ ที่เหลือระบบคำนวณให้ และข้อความยังอ่านง่าย

หรือสร้างในแอป: รูปลักษณ์ → ตัวสร้างธีม → ส่งออก THEMES.md มีรายการทุกอย่างที่ธีมกำหนดได้

ปลั๊กอิน

คลาสที่มี start() และ stop() พร้อมส่วนหัวที่บอกว่าใครสร้างและใช้อะไรบ้าง

เพิ่ม --ts สำหรับโปรเจกต์ TypeScript PLUGINS.md มีรายละเอียด API สิทธิ์ และการรีโหลดสด

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'); }
};

ร้านค้าอ่านชื่อ ผู้เขียน เวอร์ชัน คำอธิบาย และสิทธิ์ของปลั๊กอินจากส่วนหัวนี้ และอ่านชื่อ ผู้เขียน และคำอธิบายของธีมจาก JSON ของธีม หน้าจอติดตั้งแสดงค่าเดียวกัน ทั้งสองที่จึงไม่มีทางไม่ตรงกัน

2

ลองใช้

ร้านค้าเป็นทางเลือก ไฟล์ที่ใช้งานได้ก็แชร์ได้เลย

  • ลากไฟล์ไปวางบนหน้าต่าง wayBetter คุณจะได้หน้าจอติดตั้งแบบเดียวกับรายการในร้านค้า: ชื่อ ผู้เขียน เวอร์ชัน SHA-256 สิทธิ์ และโค้ด
  • เปิดโหมดนักพัฒนา (การตั้งค่า → นักพัฒนา) ระหว่างทำงาน: ปลั๊กอิน ไฟล์ธีม หรือ custom.css ที่บันทึกแล้วจะรีโหลดในทุกแท็บพร้อมกัน
  • แชร์โดยไม่ต้องผ่านร้านค้า ส่งไฟล์ หรือส่งลิงก์ waybetter://install ที่ชี้ไปยัง URL แบบ https บน waybetter.fyi, cdn1.crt.fyi หรือไฟล์ดิบบน git.crt.fyi จะไม่มีการติดตั้งโดยไม่ผ่านหน้าจอติดตั้งเด็ดขาด
3

เพิ่มหนึ่งโฟลเดอร์

ทุกรายการในร้านค้าคือโฟลเดอร์ภายใต้ store/<app>/ ในรีโพซิทอรี ชื่อโฟลเดอร์คือ id ของรายการ และเป็นที่อยู่ของมันที่นี่: /store/plugins/<id>/

store/x/ — รายการของ 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
ปลั๊กอิน: reading, writing, filters, focus หรือ tools ธีม: dark หรือ light ซึ่งจะใช้ค่าจาก mode ของธีมถ้าคุณไม่ได้ระบุ
tags
คำที่คนน่าจะใช้ค้นหา ได้สูงสุด 12 คำ
version
เฉพาะธีม (ของปลั๊กอินอยู่ในส่วนหัว) เพิ่มค่าเมื่อคุณเปลี่ยนไฟล์
คำอธิบาย
หนึ่งหรือสองประโยคที่บอกว่ามันทำอะไร ยาว 50 อักขระขึ้นไป 160 อักขระแรกจะกลายเป็นคำอธิบายของหน้าในเสิร์ชเอนจิน

การส่งผลงานมีเท่านี้ หน้า การ์ด รายการค้นหา ตัวอย่างลิงก์ ข้อมูลแบบมีโครงสร้าง และรายการในไซต์แมป ถูกสร้างจากแคตตาล็อกที่ลงนามเมื่อเว็บไซต์ถูกบิลด์ store/README.md มีกฎทั้งหมด

4

รันการตรวจสอบ

ไม่มี CI ที่โฮสต์ไว้ การตรวจสอบคือคำสั่งที่คุณรันก่อนส่ง และผู้ดูแลจะรันอีกครั้งก่อน merge

ในโคลนของคุณ
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
  • id และชื่อid ของโฟลเดอร์ (a-z 0-9 - ไม่เกิน 40) name.plugin.js ไม่ซ้ำกันในแอปเดียวกัน
  • ขนาดไฟล์ของรายการไม่เกิน 2 MiB ภาพตัวอย่างไม่เกิน 300 KB ที่อัตราส่วน 16:10
  • ส่วนหัว@name, @version, คำอธิบาย และบรรทัด @permissions ที่ระบุ network หรือ network:none
  • สิทธิ์ที่ตรงไปตรงมาnetwork:none จะถูกปฏิเสธเมื่อโค้ดเรียก fetch, XMLHttpRequest, WebSocket, EventSource หรือ sendBeacon การเรียก API ที่ถูกจำกัดต้องประกาศไว้
  • ไม่มีโค้ดจากระยะไกลไม่มี eval, new Function หรือ import() ไม่มีสคริปต์หรือไฟล์ภายนอกในภาพตัวอย่าง ไม่มี @import หรือ URL ภายนอกใน CSS ของธีม
  • แคตตาล็อกรายการต่าง ๆ บิลด์ออกมาเป็นแคตตาล็อกที่แอปยอมรับ (ตามกฎของเฟรมเวิร์กเอง) และแคตตาล็อกที่เผยแพร่ยังตรงกับลายเซ็นและแฮชของมัน
  • การค้นหาและการแชร์ชื่อหน้าไม่เกิน 60 อักขระ คำอธิบาย 50 ถึง 160 อักขระ และต้องไม่ซ้ำกันทั้งคู่
5

ส่ง

มีสองทาง ทั้งสองต้องมีบัญชี git.crt.fyiฟรี: ใครก็สมัครได้ และผู้ดูแลจะอนุมัติบัญชีใหม่ทีละบัญชีด้วยตนเอง

Pull request

  1. ฟอร์กรีโพซิทอรีบน git.crt.fyi
  2. เพิ่มโฟลเดอร์ของคุณในบรานช์ แล้วรันการตรวจสอบ
  3. เปิด pull request เทมเพลตจะถามว่ามันทำอะไรและใช้อะไรบ้าง

ไม่ใช้ git ใช่ไหม เปิด issue ได้

  1. เลือกเทมเพลตธีมหรือปลั๊กอิน
  2. แนบไฟล์ (และภาพตัวอย่าง ถ้ามี)
  3. ผู้ดูแลจะเพิ่มโฟลเดอร์ให้คุณ

จากนั้นผู้ดูแลจะลงนาม

คีย์ลงนามของร้านค้าถูกเก็บออฟไลน์โดยตั้งใจ การ merge จึงยังไม่ใช่การเผยแพร่ หลัง merge ผู้ดูแลจะอ่านโค้ด รัน waybetter store build และ waybetter store sign บนเครื่องที่เก็บคีย์ แล้ว push เว็บไซต์จะถูกบิลด์ใหม่ รายการของคุณจะมีหน้าของตัวเอง และทุกแอปจะเห็นมันเมื่ออ่านแคตตาล็อกที่ลงนามครั้งถัดไป

ทุกอย่างในแคตตาล็อกที่ลงนามได้รับการรับรองด้วยคีย์นั้น จึงต้องมีคนอ่านปลั๊กอินทุกตัวก่อนลงนาม

{ }

รูปแบบแคตตาล็อก

ไฟล์เดียวสำหรับแอป wayBetter ทุกตัว คุณไม่ต้องแก้ไขด้วยมือ เพราะมันถูกบิลด์จากโฟลเดอร์

catalog.json (รูปแบบ 2)เปิดกว้าง
{ "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"] }
] }
  • ลงนามแล้ว catalog.json.sig คือลายเซ็น Ed25519 ของไบต์ทั้งหมดใน catalog.json แอปตรวจสอบด้วยคีย์สาธารณะที่คอมไพล์ไว้ในตัว แล้วตรวจขนาดและ SHA-256 ของทุกไฟล์ที่ดาวน์โหลด
  • เข้มงวด ฟิลด์ที่ไม่รู้จัก รายการเกิน 500 หรือไฟล์ที่ใหญ่เกิน 1 MiB จะทำให้ทั้งแคตตาล็อกถูกปฏิเสธ store-catalog.schema.json คือ JSON Schema ส่วน STORE.md ในเฟรมเวิร์กมีกฎทุกข้อ
  • ใช้ร่วมกัน แต่ละรายการระบุ apps ของตัวเอง แอปจะตรวจสอบทั้งไฟล์และเก็บไว้เฉพาะรายการของตัวเอง
Aa

ภาษา

ไม่ใช่รายการในร้านค้า: ทั้ง 51 ภาษามีอยู่ในแอปแล้ว และโหลดเมื่อต้องใช้

  • แก้ไขหรือทำคำแปลให้เสร็จ ใน apps/desktop/locales/<tag>.json ผ่าน pull request หรือ issue ที่แนบไฟล์ที่แก้แล้ว
  • ตรวจสอบ ด้วย bun run i18n:check: คีย์ ตัวยึดตำแหน่ง รูปพหูพจน์ และต้องไม่มีมาร์กอัป ผลลัพธ์ต้องเป็น 0 error(s)
  • มาพร้อมกับการอัปเดตแอปครั้งถัดไป ไม่ได้ผ่านร้านค้า TRANSLATING.md มีไวยากรณ์ของข้อความและวิธีดูคำแปลของคุณในแอป

ดูสิ่งที่ มีอยู่แล้ว

ทุกรายการในร้านค้าแสดงโค้ดของตัวเอง ปลั๊กอินที่มาพร้อมแอปคือตัวอย่างที่ดีที่สุดของการใช้ API อย่างเหมาะสม