TREK 插件发布完全指南:从 GitHub 仓库到官方注册表的完整流水线
2026/9/15 10:58:26 网站建设 项目流程

TREK 插件发布完全指南:从 GitHub 仓库到官方注册表的完整流水线

【免费下载链接】TREKA self-hosted travel/trip planner with real-time collaboration, interactive maps, PWA support, SSO, budgets, packing lists, and more.项目地址: https://gitcode.com/GitHub_Trending/nomad22/TREK

插件是 TREK 生态的扩展单元,而发布则是把它们交给全世界 TREK 实例的方式。本文基于 TREK 仓库的官方文档(wiki/Plugin-Publishing.md)与trek-plugin-sdk的真实源码,系统讲解 TREK 插件从本地开发、离线校验、打包、创建 GitHub Release、生成注册表条目到提交 PR 的完整发布流水线——你只需维护一个公开 GitHub 仓库和一行publish命令,其余全部由 SDK 自动完成。读完本文,你将掌握trek-pluginCLI 的五个发布步骤、所有离线/网络检查闸门、签名机制与更新策略,能够独立发布一个可被发现、可被更新、可被验证的 TREK 插件。

TREK 插件的分发不走传统的上传服务器模式:它基于一个静态注册表——TREK-Plugins GitHub 仓库。没有上传服务器,没有账户体系。插件作者把代码托管在自己的公开 GitHub 仓库,把构建好的plugin.zip挂到 Release 上,再通过一个 Pull Request 把条目登记进注册表。trek-plugin-sdk包内置的trek-pluginCLI 几乎承包了所有机械性工作——你几乎不需要手写 hash、大小、commit 或任何 JSON 字段。

一、发布模型:静态注册表 + 不可变 Release

理解 TREK 插件发布,先要理解它的两条根本约束:

  • GitHub Release 实质上是不可变的。注册表为每个版本的插件固定记录其 sha256,一旦你覆盖已发布的 Release 字节,就会破坏所有已安装该版本实例的校验和。这正是publish命令中步骤顺序的由来(下文详述)。
  • 注册表只存放元数据。TREK 实例从你的 GitHub Release 下载plugin.zip,用注册表条目中的sha256和可选签名验证字节后再安装。注册表本身(registry/plugins/<id>.json)只是这些元数据的集合。

你唯一需要的外部依赖是git和一个已认证gh(GitHub CLI)。SDK 内部的 fork、release 创建、PR 提交全部通过gh完成(见 plugin-sdk/src/cli/submit.ts 中的gh('repo','fork', ...)gh('pr','create', ...)等调用)。

二、一步发布:publish的五个步骤与顺序哲学

最简单的发布路径是单条命令:

npx trek-plugin-sdk publish --repo you/trek-plugin-flight-tracker --tag v1.0.0

publish严格顺序执行整个发布流程,共五步(对应源码 plugin-sdk/src/cli/publish.ts 中[1/5][5/5]的日志标记):

  1. check—— 在本地跑全部注册表闸门;
  2. pack—— 构建plugin.zip
  3. release—— git tag、push、用gh release create创建带附件的 GitHub Release;
  4. preflight—— 运行需要 tag 和 Release 已存在的网络闸门;
  5. submit—— 向注册表打开 PR。

顺序本身就是重点。早期版本是 pack → release → preflight → submit,意味着"README 没写"这类问题是在 GitHub Release 已创建之后才被发现——Release 不可变,作者为此烧掉了v1.0.0这个 tag,只能弃掉重来一个只改了 README 的v1.0.1。现在的实现把能在工作区回答的闸门全部放到第 1 步:任一失败,就什么都不会打包、打 tag、推送或发布,修好之后可以对着同一版本号重跑。

命令末尾会打印 PR 链接。在交互式终端中,它会主动提议签名(没有密钥时自动创建);脚本和 CI 环境不会被提示,需显式传--sign。两个逃生舱口:

  • --no-checks:跳过第 1 步(重跑时用);
  • --no-preflight:跳过第 4 步(重跑时用)。

它们只是重跑时的出口,首次发布不要使用。此外,publish在打出 Release 前会做签名状态断言(plugin-sdk/src/cli/signing.ts 的assertSigningAllowed):如果插件此前是以签名形式发布的,未签名的发布会在第 1 步直接被拒绝,避免在不可变的 Release 上浪费 tag。

如果你希望分步手工执行,release(pack → GitHub Release → entry)、preflightsubmit(开 PR)三个子命令仍然独立存在。

三、第一步:托管并构建你的插件

插件必须放在一个公开 GitHub 仓库中(约定命名trek-plugin-<id>)。用create-trek-plugin脚手架生成项目布局:

npx trek-plugin-sdk create flight-tracker --type widget # integration | page | widget | trip-page

一个可发布的插件,仓库根目录必须包含:

  • trek-plugin.json—— 清单文件,详见 Plugin Development;
  • package.json—— 必须带 CommonJS 标记("type": "commonjs"),SDK 最多只能作为 devDependency;
  • server/index.js—— 构建后的服务端入口(必需,即使是纯 UI 插件也从这里经definePlugin()加载,见 plugin-sdk/src/cli/checks/offline.ts 的codeServerEntry检查);
  • client/—— 构建后的前端(仅page/widget/trip-page类型需要);
  • README.md—— 填写完整,且包含真实截图(质量闸门很严格,见下文);
  • docs/screenshot.png—— 商店卡片图,必须提交到仓库。

需要特别提醒:create生成的项目能跑、能打包,但过不了validate——README 还是模板,也没有截图。这两件事只能由你自己完成。

四、本地验证:statusvalidate

npx trek-plugin-sdk status # 我在哪?还差什么?——永不失败 npx trek-plugin-sdk validate . # 同样的检查,但失败时以非零码退出

statusvalidate运行的是同一套注册表闸门,只是深度不同(plugin-sdk/src/cli/checks/index.ts 中二者共享runOffline):status把它们按阶段(Manifest / Code / Docs / Release / Repo)分组打印成清单,并提示下一步该执行哪条命令,用于定位,因此永不失败;validate是闸门本身——同样的检查、同样的退出码,是脚本和 CI 应使用的形式。

离线就能抓到几乎所有注册表拒绝项(完整清单见 plugin-sdk/src/cli/checks/offline.ts):

  • icon不是真实的 lucide 名称——TREK 会静默回退到Blocks图标,本地打字错误看不出来,但 CI 会拒绝;
  • README 缺少四个必需章节中的任何一个、还残留脚手架占位符、或真实正文不足 400 个字符MIN_PROSE_CHARS = 400,统计时剔除标题、代码、图片、表格,见 plugin-sdk/src/cli/checks/readme.ts);
  • 截图不能解析为磁盘上真实存在的文件(仅 README 里有链接不算,文件必须存在);
  • 清单声明了某个权限但 README 从未解释它(每个权限字符串必须原样出现在 README 中);
  • name/description/author超出注册表长度限制,或名称混用拉丁字母与西里尔/希腊同形字(homoglyph 仿冒攻击);description缺省会以空字符串进入条目,触发注册表 schema 的 minLength 检查;
  • egress[]中的主机没有对应的http:outbound:<host>权限——TREK 的网络允许列表与 iframe CSP 只从http:outbound权限构建,运行期从不读取egress[],因此这样的主机在运行时会被静默拦截(源码注释中称其为 "the egress trap");
  • name/description中出现 emoji(TREK 渲染时会剥离 emoji);
  • trek版本范围无界(如">=3.0.0"),无法阻止插件在从未测试过的主机版本上运行。

真正需要网络的闸门只有四个,且都要求 Release 已存在:tag 是否解析到条目固定的 commit、已发布的工件能否下载且哈希与固定的 sha256 一致(并能用你的密钥验证)、插件 id 是否已被其他 GitHub 所有者绑定、以及更新是否丢弃或轮换了已发布过的签名密钥。这些都在preflightpublish的第 4 步)中运行。

截图的获取

npm i -D playwright && npx playwright install chromium # 一次性安装——不是 SDK 的依赖 npx trek-plugin-sdk shot # 加 --dark 渲染暗色主题

shot会启动 dev server,在与 TREK 相同的主题化沙箱框架(/preview)中渲染你的插件,输出 1600×900 的docs/screenshot.png(plugin-sdk/src/cli/shot.ts)。Playwright 约 300MB,因此不是 SDK 的依赖,被按需惰性加载,缺少时会提示安装命令。integration类型插件没有 UI 可渲染,shot帮不上忙——此时应截图你的插件所改变的 TREK 界面。

务必提交截图。注册表在固定的 commit上解析它,只存在于工作区、未提交的图片在 CI 中必然失败,哪怕本地status是绿的。

五、打包:pack

npx trek-plugin-sdk pack . # 生成 ./plugin.zip npx trek-plugin-sdk pack . --out dist.zip # 自定义输出路径 npx trek-plugin-sdk pack . --json # 机器可读结果

pack按安装器要求的精确布局构建plugin.zip,并打印手工计算麻烦的sha256size。它拒绝打包无法加载的插件——清单损坏、缺少server/index.js、包含原生二进制——但故意强制发布闸门(没写 README、缺截图也可以打包),因为打包同样是向本地 TREK 侧载(sideload)试用插件的方式,文档只需在真正发布时齐全(对应源码 plugin-sdk/src/cli/pack.ts 中blocking(runOffline(...), 'artifact')只取blocks: 'artifact'的阻断项)。

打包只包含运行时需要的文件——trek-plugin.jsonREADME.mdLICENSEpackage.json以及server/client/目录树——并剔除node_modules.git、source map(.map)和.ts源码。它拒绝原生二进制.nodebinding.gypprebuilds/),并强制执行与安装器相同的体积上限:

限制项上限
单文件25 MB
归档总大小50 MB
条目数4000

docs/故意不随包发布。商店直接从固定 commit 处的仓库拉取docs/screenshot.png,因此请把图片提交到 GitHub 但留在 zip 之外——pack会自动处理。

pack产出的plugin.zip同时也是侧载的工件:把它交给实例管理员(或直接拖到Admin → Plugins),即可完全绕过注册表安装——无需 PR、无需审查、无需 SHA-256/签名固定。侧载插件会被标记,且永不自动更新,因此下面的注册表 PR 仍是让插件可被发现、可更新的正途。更多背景见 Plugins。

六、创建 GitHub Release

tag 采用vX.Y.Z格式,其中X.Y.Z必须等于清单中的version,并把打包好的plugin.zip作为 Release 资产上传:

gh release create v1.0.0 plugin.zip --repo you/trek-plugin-flight-tracker

优先上传plugin.zip资产——它就是你打包时的原始字节,注册表会固定其哈希。不要依赖 GitHub 自动生成的源码归档(source archives),它们不是安装器布局,字节也不稳定。

七、生成注册表条目:entry

npx trek-plugin-sdk entry \ --repo you/trek-plugin-flight-tracker \ --tag v1.0.0 \ --out registry/plugins/flight-tracker.json

entry读取你的清单和plugin.zip,生成完整条目(plugin-sdk/src/cli/entry.ts),自动推导:

  • commitSha—— 通过git rev-parse <tag>^{commit}解析(^{commit}会对带注释的 tag 解引用到实际 commit,见resolveCommit);
  • downloadUrl—— 由 repo、tag 和资产名拼出;
  • sha256—— 对plugin.zip的字节做 SHA-256;
  • size—— 字节数;
  • apiVersion—— 默认 1,可从清单覆盖;
  • trek—— 清单中的版本范围,原样照抄

trek范围是条目中唯一的兼容性字段,TREK 用它闸控安装与激活。旧的minTrekVersion/maxTrekVersion已被弃用且不再生成:前者只是重复了范围的下界,后者是包含语义、无法表达<4.0.0。注册表仍接受在trek字段出现之前发布的旧条目携带这两个字段,但不会为新条目生成它们。entry会拒绝为没有可用trek范围的清单生成条目——因为 TREK 本来就会拒绝安装它。

可用旗标:--zip(默认plugin.zip)、--commit <sha>(覆盖 commit 解析)、--asset(指定不同名字的 Release 资产)、--merge(更新场景,见下文)、--out(写出文件)。

buildEntry还会把清单中的requiredAddonspluginDependenciesoperatorEgress镜像到条目(仅非空时生成,保持普通条目字节不变)。这一点至关重要:TREK 在下载工件之前就从注册表索引解析依赖,条目遗漏它们会让 CI 报 "manifest requiredAddons != entry requiredAddons"——而这在早期版本中确实发生过(release 已创建、字节已固定之后才发现)。

一条命令:release

npx trek-plugin-sdk release . --repo you/trek-plugin-flight-tracker --tag v1.0.0

release一步完成pack →gh release create→ entry,并把条目打印到 stdout。接受--out--notes--commit--merge(需要已认证的ghCLI)。

八、Preflight:需要 Release 存在的检查

在打开 PR 之前,先对已推送的 Release 运行注册表剩余的 CI 检查,避免一次审查往返:

npx trek-plugin-sdk preflight --repo you/trek-plugin-flight-tracker --tag v1.0.0

preflight运行validate的全部检查,外加四个真正需要网络的闸门(plugin-sdk/src/cli/checks/network.ts):

  1. tag 解析到固定的commitShanetwork.tag-resolves,带注释的 tag 会被解引用到 commit 再比对);
  2. 该 commit 处的清单和 README 与条目一致且通过质量闸门network.manifest-at-commitnetwork.readme-at-commit);
  3. 发布的工件可下载、哈希等于固定的 sha256、不含原生二进制、能用你的密钥验证network.artifact,大小允许 4096 字节的 GitHub 资产填充余量;签名会做 Ed25519 校验);
  4. 插件 id 未被绑定到其他 GitHub 所有者network.owner-binding,读取注册表的OWNERS.json),且更新不会丢弃或轮换已发布的签名密钥network.signing-downgrade)。

在固定 commit 上重新评定清单和 README 并非与本地通过的重复:作者写完 README 却忘记提交,就会出现"绿树红 tag"——而 CI 评分的正是 tag 指向的版本。--entry <file.json>可检查手写条目,--all检查所有版本而非仅最新版。一次全绿的 preflight 意味着 CI 也会绿。SDK 的 plugin-sdk/test/checks-parity.test.ts 专门守护这一承诺——注册表有而 SDK 没有的闸门就是"假绿",这是被禁止的。

九、打开注册表 PR

最快捷的路径——submit代劳 fork/branch/commit/PR 全程:

npx trek-plugin-sdk submit --repo you/trek-plugin-flight-tracker --tag v1.0.0

它会 fork TREK-Plugins(只 fork 一次),基于当前上游main开分支,写入(更新时合并进)registry/plugins/<id>.json,推送并打开 PR,最后打印 PR 链接(plugin-sdk/src/cli/submit.ts)。加--draft创建草稿 PR,--registry <owner/name>指定镜像仓库(需要已认证的gh)。

手工方式:fork 注册表,把生成的文件添加为registry/plugins/<id>.json,向main开 PR。只添加这一个文件——dist/在合并时自动生成,CI 会拒绝手工修改它。

条目遵循注册表的schema/plugin-entry.schema.jsonschema/example-entry.json是标准形状。size必填的(常被遗漏),commitShadownloadUrlsha256trekapiVersion以及每个版本上的nativeModules: false也都是必填项——全部由trek-plugin entry代填。CI 会拒绝trek与固定 commit 处清单不一致的条目(对仍携带minTrekVersion的旧条目,还会检查其下限与范围一致)。

十、CI 到底强制什么

注册表 CI 对每个变更的registry/plugins/*.json运行scripts/validate-entry.mjsscripts/check-readme.mjs。几乎所有规则都是你的trek-plugin.jsonREADME.md的纯函数,因此trek-plugin validate在打任何 tag 之前就能离线检查——你永远不该从 CI 那里第一次听说这些规则

条目检查validate-entry.mjs):schema 合法 ·id与文件名一致且匹配 slug 模式^[a-z][a-z0-9-]{2,39}$· 首次注册时id绑定到你的 GitHub 所有者,之后任何人无法改指(所有权变更需要维护者覆盖)· homoglyph/混合脚本名称检查 · Release tag 存在且解析到commitSha· 该 commit 处清单对齐(idversiontypeapiVersionnativeModules不得为true)·下载工件的 SHA-256 与固定值一致且大小在界内 · 归档内无原生二进制· 声明http:outboundegress[]必须存在(且不能是裸*)。任何唯一 slug 都可用,registryinstallrescan除外——安装加载器会拒绝它们(与 admin API 路由段冲突)。

README 检查check-readme.mjs,在固定 commit 处获取):仓库根目录必须存在 · 包含What it does / Screenshots / Permissions / Setup四个章节 · 至少有一张能解析为真实图片的截图(相对路径docs/screenshot.png相对该 commit 解析)· 真实正文 ≥ 400 字符(剔除标题/代码/图片/表格后)· 无残留脚手架占位符 ·解释清单声明的每个权限

十一、出处与完整性

  • commitSha固定了维护者审查的确切源码(git tag 是可移动的);
  • sha256固定了 TREK 将要运行的确切工件字节(Release 资产是可变的)。

TREK 安装时会将下载字节与sha256比对,不匹配则拒绝安装。条目上的reviewedAt日期表示维护者查看了那个确切 commit——它不是持续保证。reviewedAtboundOwner由 CI 在合并时维护,不要自行设置

十二、签名你的 Release(可选,但推荐)

sha256证明字节是注册表担保的那些字节;作者签名则额外证明字节是签的——即使注册表被攻破,也无法以你的名义分发攻击者代码。条目 schema 允许两个可选字段:条目上的authorPublicKey和每个版本上的signature。TREK 离线验证签名(minisign / Ed25519,不依赖外部服务),并在首次安装时固定你的密钥(信任首次使用,TOFU):之后用不同密钥签名的版本会被拒绝,直到管理员重新信任。

最省事的方式:让 SDK 代劳

SDK 内置无依赖的 Ed25519 实现,不需要 minisign。在终端中,publish主动提议签名:解释利弊、没有密钥时自动创建、然后签名。脚本和 CI 不会被提示,直接传--sign

npx trek-plugin-sdk publish --repo you/repo --tag v1.2.0 --sign

--sign对确切工件字节签名,并同时填好authorPublicKey(条目级)和signature(版本级)。若插件此前以签名形式发布,publish会在第 1 步拒绝未签名的 Release——在任何打包、打 tag、发布之前——因为 GitHub Release 不可变,到第 4 步才发现问题就浪费了 tag。请备份~/.trek-plugin/signing.key——丢失它意味着你再也无法发布签名的更新。

手工 minisign 方式

minisign -G # 生成 minisign.key(保密)+ minisign.pub

minisign.pub中的 base64 载荷行放入条目作为authorPublicKey(跨版本稳定),然后每个版本执行:

minisign -Sm plugin.zip # 生成 plugin.zip.minisig

plugin.zip.minisig中的 base64 行作为该版本的signature,放在其sha256旁边:

{ "id": "flight-tracker", "authorPublicKey": "RWQ…base64 minisign public key…", "versions": [{ "version": "1.2.0", "sha256": "3b2a…", "signature": "RUR…base64 .minisig payload…" }] }

签名是可选的,而且是一扇可以晚些时候再走、但永远回不来的单向门。没有authorPublicKey/signature的条目只靠sha256安装;从"未签名"到"签名"不会破坏任何人——因为在有签名版本安装之前,没有任何东西被固定,在 v1.4.0 才加密钥是真实可行的选择。但反过来永远不行:插件一旦以签名形式发布,未签名的更新会在所有已安装实例上被拒绝(SIGNATURE_MISSING),密钥轮换需要注册表维护者覆盖(allow-key-change)加每个实例的管理员重新信任。所以——随时可以签名,但请把密钥备份好。

十三、更新你的插件

修改清单中的version,提交,然后用新 tag 再次运行publish——它会检测到已有条目并把新版本前插,保持最新在前。手工方式:重新pack,打新的vX.Y.ZRelease,再用--merge把新版本折叠到既有条目上:

npx trek-plugin-sdk entry --repo you/trek-plugin-flight-tracker --tag v1.1.0 \ --merge registry/plugins/flight-tracker.json \ --out registry/plugins/flight-tracker.json

--merge前插新版本(数组保持最新在前)并保留条目其余部分,且会校验签名一致性——签名密钥与已发布的不同、或已签名插件发未签名更新都会被拒绝(见 plugin-sdk/src/cli/entry.ts 的mergePath分支)。然后把更新后的文件提 PR。各实例在下一次注册表轮询时看到更新;是否应用始终是管理员的显式操作,若新版本申请了更多权限,管理员必须重新批准——详见 Plugin Permissions。

小结:发布核对清单

  1. 公开 GitHub 仓库,仓库根目录含trek-plugin.jsonpackage.json(CommonJS 标记)、构建后的server/index.js、需要的client/、写好的README.md、已提交的docs/screenshot.png
  2. trek-plugin status/validate全绿(离线,含 README ≥ 400 字符、四章节齐全、截图可解析、权限全部解释);
  3. trek-plugin pack生成plugin.zip(sha256 / size 由此得到);
  4. 打 tagvX.Y.Z(等于清单version)并gh release create上传plugin.zip
  5. trek-plugin entry生成条目(或release一步完成);
  6. trek-plugin preflight验证 tag、commit、工件哈希、所有者绑定、签名状态;
  7. trek-plugin submit开 PR(或手工 fork + PR)。

整个流程的核心设计是:先在本地、后动远端,先校验、后发布。任何能被工作区回答的问题都不该等到 GitHub Release 创建之后才发现——这既是publish五步顺序的由来,也是validate/preflight/CI 三级闸门存在的意义。遵循这份指南,你的插件就能以可验证、可更新、可信赖的方式进入 TREK 的官方注册表。

【免费下载链接】TREKA self-hosted travel/trip planner with real-time collaboration, interactive maps, PWA support, SSO, budgets, packing lists, and more.项目地址: https://gitcode.com/GitHub_Trending/nomad22/TREK

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询