Alia 模组空间 https://mods.alia.0832.ink
  • JavaScript 100%
Find a file
2026-10-05 21:16:14 +08:00
lib 更新接口&Web测试 2026-10-05 21:16:14 +08:00
server 全部采用[模组空间](https://mods.alia.0832.ink) 2026-08-22 23:00:38 +08:00
Tests 更新接口&Web测试 2026-10-05 21:16:14 +08:00
.gitignore 使用Alia重写(半自举!) 2026-10-03 10:54:52 +08:00
config.json 使用Alia重写(半自举!) 2026-10-03 10:54:52 +08:00
main.alia 使用Alia重写(半自举!) 2026-10-03 10:54:52 +08:00
README.md 更新接口&Web测试 2026-10-05 21:16:14 +08:00

ModSpace

Alia Mods Space 桌面客户端与 ModServer 服务端。客户端基于 gtk-alia(GTK4 + libadwaita), 整体以 Alia 语言编写;服务端基于 Express(server/),共同对接 alia CLI 工作流。

功能

  • 浏览 / 搜索 / 排序模组(标题栏统一搜索栏)
  • 模组详情(crates.io 风格:描述 / 文档 / 文件 / 版本 / 依赖 页签,Markdown 渲染 README)
  • 注册、登录、退出
  • 桌面端发布模组(选择本地 .aliam 上传)

项目结构

main.alia                应用入口:装配外壳并运行 GTK 主循环
lib/
  api.alia               REST 客户端(列表 / 详情 / README / 文件 / 依赖 / 认证 / 发布)
  json.alia              JSON 解析与序列化(点路径扁平模型)
  markdown.alia          Markdown → HTML / 纯文本,体积与日期格式化
  models.alia            ModInfo / ModFile 数据模型与访问器
  store.alia             键值存储抽象(桌面端 ~/.alia/config.json / Web 端浏览器存储)
  theme.alia             libadwaita 配色策略与组件 CSS
  nav.alia               页面栈导航、轻提示、剪贴板与外链
  account.alia           账户菜单(登录 / 注册 / 退出)
  shell.alia             窗口外壳:AdwToolbarView + AdwHeaderBar + 页面注册
  widgets/
    status.alia          空态 / 加载态 / 错误重试态
    mod_card.alia        模组卡片
    markdown_view.alia   Markdown 渲染视图(WebKit 优先,纯文本回退)
  pages/
    browse.alia          浏览页
    detail.alia          详情页与文件查看页
    publish.alia         发布页
    auth.alia            登录 / 注册页
Tests/                   测试(api / json / markdown / store / ui / web)
server/                  ModServer(Express REST API)

本地开发

桌面客户端

依赖系统安装 GTK4(libgtk-4.so.1)与 libadwaita(libadwaita-1.so.0); README / 文档渲染优先使用 WebKitGTK(libwebkitgtk-6.0.so),缺失时自动回退为纯文本视图。

alia add gtk-alia                 ~ 首次拉取依赖
alia start                        ~ 解释模式运行(FFI 直连系统 GTK4,无编译产物)
alia run                          ~ 编译并运行(node-gtk 原生桌面)
alia build                        ~ 仅编译,产物位于 build/nodejs
MODSPACE_API=http://localhost:3000/ alia run   ~ 指向本地 ModServer

窗口外壳使用 gtk.adwWindowNew + gtk.adwWindowSetContent:AdwWindow 会把内容里的 AdwHeaderBar 提升为窗口标题栏,若改用 gtk.windowNew + gtk.windowSetChild 会出现双顶栏; 顶栏内容必须走 gtk.adwHeaderBarPackStart/PackEnd/SetTitleWidget,混用 GTK 版 gtk.headerBarPack* 会静默失效并写坏内存。

API 基址优先级:URL 查询参数 ?api=(Web)> 环境变量 MODSPACE_API > ~/.alia/config.json 的 spaceUrl > 默认 https://mods.alia.0832.ink。 凭据由 lib/store.alia 托管:桌面端与 alia CLI 共享 ~/.alia/config.json(token / username), Web 端落浏览器存储(宿主提供的 web.storage*)。宿主形态由能力探测决定,Alia 侧不对具体运行时做特化判断。

Web 目标

客户端可作为纯前端站点运行(nodejs 编译产物 + --target:web,由 gtk-alia 的 Web 后端桥接 命令式 GTK API 到 GTK.js / React)。浏览、搜索、排序、详情、README、文件树与文件查看、 注册、登录、退出均可用;发布依赖 curl 与本地文件系统,故 Web 宿主下发布页给出桌面端 替代指引。

alia build --lang:nodejs --target:web        ~ 产出 build/nodejs-web/web/dist
node ../Base/Manager/index.js build --lang:nodejs --target:web
cd build/nodejs-web/web && npx vite --host    ~ 本地预览(默认 http://localhost:5173)

部署时将 build/nodejs-web/web/dist 作为静态站点发布,并把 /api/ 反向代理到 ModServer:

alia build --lang:nodejs --target:web && cd build/nodejs-web/web && npx vite build
# dist/ 即可托管;?api=https://mods.example.ink/ 可在不改代码的情况下切换 API 基址

Web 目标约束:

  • web.httpRequest 在浏览器侧为同步 XHR(语言层 await 编译为 join() 阻塞语义),因此 ModServer 必须开启 CORS(默认已开启);请求期间主线程被阻塞。
  • Web 宿主无进程与文件系统,apiCanPublish 返回 false。
  • 外链通过宿主 web.openUrl 打开,桌面端仍走 xdg-open。
  • README / 文档在 Web 宿主下由 iframe 承载 WebKit 视图(与桌面端同一套 Alia 代码路径)。
  • gtk-alia 的 Web 后端需要包含 backends/web-gtk.js 与 backends/web-build.js 的版本; alia add gtk-alia 拉取的已发布版本若不含这些文件,需改用本地检出(见 gtk-alia 仓库)。

ModServer

cd server
npm install
npm start

默认监听 3000 端口。

构建

alia build
cd build/nodejs && node main.js

alia run 等价于编译后启动,编译产物使用 node-gtk 驱动原生 GTK4。

测试

alia check                         ~ 全项目静态检查(类型 / 未使用变量)
node ../Base/Executor/Tests/stdin_runner.js Tests/api.alia test
node ../Base/Executor/Tests/stdin_runner.js Tests/json.alia test
node ../Base/Executor/Tests/stdin_runner.js Tests/markdown.alia test
node ../Base/Executor/Tests/stdin_runner.js Tests/store.alia test
xvfb-run -a node ../Base/Executor/Tests/stdin_runner.js Tests/ui.alia run
node Tests/web.js                  ~ Web 目标端到端验收(无头 Chrome)

cd server
npm test

Tests/web.js 覆盖 Web 目标的真实浏览器行为:构建 nodejs-web 产物、在临时端口拉起 ModServer 并植入固定模组、再用无头 Chrome(CDP)逐项断言浏览 / 搜索 / 排序 / 详情五页签 / README iframe 渲染 / 文件树与文件查看 / 返回 / 注册 / 登录 / 刷新保持 / 退出 / 空态 / 窄屏无横向溢出 / 无未知控件占位 / 控制台无警告,最后回归解释器测试与 alia check。

node Tests/web.js                          # 完整流程(含构建)
node Tests/web.js --skip:build             # 复用已有 build/nodejs-web
node Tests/web.js --api:http://127.0.0.1:3000   ~ 对接既有 ModServer
node Tests/web.js --shots:./shots          # 保留各步骤截图

--api: 指向的 ModServer 需允许跨域(默认 CORS 已开启)。Web 目标在浏览器侧的宿主能力由 entry.jsx 的 shimModules 兜底:内存 fs、同步 XHR 的 web.httpRequest、 web.storage*(浏览器存储)、web.pageUrl、web.openUrl。

ModServer 部署指南

ModServer 是 Alia Mods Space 的 REST API 服务端,源码位于本仓库 server/,数据默认持久化于 server/data/(已被 .gitignore 忽略)。

环境要求

  • Node.js ≥ 18
  • 可选:Nginx(生产反向代理与静态托管)

配置

通过环境变量配置:

变量 默认值 说明
PORT 3000 监听端口
ALIA_SPACE_DATA server/data 数据目录(users.json、registry.json、mods/、secret)
ALIA_SPACE_SECRET 自动生成 JWT 签名密钥

数据目录结构:

server/data/
├── users.json      # 用户(bcrypt 密码哈希)
├── registry.json   # 模组元数据注册表(描述/标签/主页/版本/依赖/下载统计)
├── secret          # 自动生成的 JWT 密钥
├── mods/           # 已发布包 <name>@<version>.aliam
└── extracted/      # 解包内容 <name>@<version>/(README/文档/文件浏览)

本地运行

cd server
npm install
npm start

验证:

curl http://localhost:3000/api/mods

生产部署(Nginx + systemd)

推荐架构(单域名,API 由 Nginx 反代):

  • mods.alia.0832.ink → /api/ 路径由 Nginx 反向代理到本机 127.0.0.1:3000 的 ModServer;桌面客户端直接指向该域名

1. 安装 ModServer 依赖并创建 systemd 服务

cd server
npm install --omit=dev
sudo mkdir -p /opt/mods-space
sudo cp -r . /opt/mods-space/

创建 /etc/systemd/system/modserver.service:

[Unit]
Description=Alia Mods Space Server
After=network.target

[Service]
Type=simple
User=www-data
WorkingDirectory=/opt/mods-space
ExecStart=/usr/bin/node index.js
Environment=PORT=3000
Environment=ALIA_SPACE_DATA=/opt/mods-space/data
Restart=always

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now modserver

2. Nginx 配置

站点静态产物来自 alia build --lang:nodejs --target:web 的 build/nodejs-web/web/dist, 复制到 /var/www/mods.alia.0832.ink;/api/ 反向代理到本机 ModServer:

cd /path/to/ModSpace
alia build --lang:nodejs --target:web
sudo mkdir -p /var/www/mods.alia.0832.ink
sudo cp -r build/nodejs-web/web/dist/. /var/www/mods.alia.0832.ink/

/etc/nginx/sites-available/mods.alia.0832.ink.conf:

server {
    listen 80;
    server_name mods.alia.0832.ink;

    root /var/www/mods.alia.0832.ink;
    index index.html;

    location /api/ {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        client_max_body_size 50m;
    }

    location / {
        try_files $uri $uri/ /index.html;
    }
}
sudo ln -s /etc/nginx/sites-available/mods.alia.0832.ink.conf /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

3. HTTPS

使用 certbot 为域名签发证书:

sudo certbot --nginx -d mods.alia.0832.ink

证书续期由 certbot 的 timer 自动处理。

客户端对接

alia CLI 与桌面客户端通过 alia space <url> 或 MODSPACE_API 指向部署地址:

alia space https://mods.alia.0832.ink/
alia login
alia publish

Web 客户端默认使用同域 /api/,无需额外配置;如需指向其它 ModServer,追加查询参数 ?api=https://<host>/ 即可(同域部署时可省略)。

接口一览

方法 路径 说明
POST /api/register 注册用户({ username, password })
POST /api/login 登录,返回 JWT
POST /api/logout 退出登录
POST /api/publish 发布包(multipart file,需 Authorization: Bearer <token>)
GET /api/mods/:name/latest 查询最新版本号
GET /api/mods/:name@:version.aliam 下载指定版本
GET /api/mods 模组列表,可选 ?q=<关键词> 与 `?sort=updated
GET /api/mods/:name 单模组详情(含全部版本与元数据)
GET /api/mods/:name/versions 版本列表
GET /api/mods/:name/readme?version= README 内容
GET /api/mods/:name/files?version= 包内文件树
GET /api/mods/:name/file?version=&path= 单个文件内容
GET /api/mods/:name/dependencies?version= 指定版本的依赖表

服务端依赖

桌面客户端与 Web 客户端均依赖 ModServer 的 /api/mods 系列接口(列表 / 详情 / 版本 / README / 文件 / 依赖)与 register / login / logout;publish 仅桌面端使用(Web 端无进程与文件系统)。发布时服务端从包内 config.json(含可选 author/description/tags/homepage)提取元数据写入 registry.json,并将解包内容持久化到 data/extracted/。