# ScriptForge 设计文档 ## 概述 脚本快速转运行链接服务。用户粘贴脚本内容,选择运行环境,生成一个短链。在终端执行 `curl URL | ` 即可运行脚本。 - 前端:Next.js (App Router + Tailwind CSS + TypeScript) - 后端:Go (Gin + GORM + SQLite) - 部署:Go embed 前端静态文件,单二进制部署 - CI/CD:Gitea Actions ## 核心流程 1. 用户打开首页 `/` 2. 粘贴脚本内容(上限 16KB) 3. 选择运行环境(bash / zsh / sh / fish / python3 / node / ruby / php) 4. 选择过期时间(1小时 / 24小时 / 7天 / 30天) 5. 提交 → 后端存入 SQLite → 返回短链 ID 6. 页面展示生成的命令:`curl https://example.com/raw/xK8mPq | bash` 7. 用户可以复制命令到终端执行 ## API 设计 ### POST /api/scripts — 创建脚本 请求体: ```json { "content": "#!/bin/bash\necho hello", "runtime": "bash", "expires_in": "24h" } ``` 响应: ```json { "id": "xK8mPq", "admin_token": "dGhpcyBpcyBhIHRva2Vu", "url": "https://example.com/raw/xK8mPq", "command": "curl https://example.com/raw/xK8mPq | bash", "runtime": "bash", "expires_at": "2026-05-29T16:27:00Z" } ``` ### GET /api/scripts/:id — 获取脚本元数据 响应: ```json { "id": "xK8mPq", "runtime": "bash", "content_length": 25, "created_at": "2026-05-28T16:27:00Z", "expires_at": "2026-05-29T16:27:00Z", "expired": false } ``` > 注意:此接口不返回脚本原始内容(内容通过 `/raw/:id` 获取),避免前端二次暴露。 ### GET /raw/:id — 获取脚本纯文本内容 - 响应头 `Content-Type`: 根据 runtime 设置对应 MIME(见运行时配置表) - 响应头 `Content-Disposition`: `attachment; filename="script."`(根据 runtime 设置扩展名) - 响应体:脚本纯文本内容 - 如脚本已过期,返回 404 ### DELETE /api/scripts/:id?token=xxx — 删除脚本 - 需要 `admin_token` 参数 - 成功返回 204 ## 数据模型 ```go type Script struct { ID string `gorm:"primaryKey;size:8"` Content string `gorm:"type:text;not null"` Runtime string `gorm:"size:16;not null;index"` AdminToken string `gorm:"size:64;not null"` ExpiresAt time.Time `gorm:"not null;index"` CreatedAt time.Time `gorm:"not null"` } ``` ## 运行时配置 | Runtime | 扩展名 | MIME 类型 | 命令模板 | |---------|--------|-----------|----------| | bash | `.sh` | `text/x-shellscript` | `curl {url} \| bash` | | zsh | `.zsh` | `text/x-shellscript` | `curl {url} \| zsh` | | sh | `.sh` | `text/x-shellscript` | `curl {url} \| sh` | | fish | `.fish` | `text/x-shellscript` | `curl {url} \| fish` | | python3 | `.py` | `text/x-python` | `curl {url} \| python3` | | node | `.js` | `text/javascript` | `curl {url} \| node` | | ruby | `.rb` | `text/x-ruby` | `curl {url} \| ruby` | | php | `.php` | `text/x-php` | `curl {url} \| php` | 运行环境列表在 Go 后端定义为常量数组,用于校验请求中的 runtime 字段。 ## 过期策略 - 用户保存时选择:1小时 / 24小时 / 7天 / 30天 - 后端定时任务(每分钟扫描一次),删除过期记录 - 过期后 `/raw/:id` 返回 404,详情页标记为已过期 ## 限流策略 - 创建接口:10 次/分钟/IP - 其他接口:60 次/分钟/IP - 请求体上限:17KB ## 安全设计 - 完全公开,无需注册/登录 - 创建时返回 `admin_token`(随机 64 位字符串),持有者可删除脚本 - 无内容过滤,靠过期机制和限流控制风险 - 编辑功能:无(`admin_token` 仅用于删除,不能改内容。设计上 script 是一次性的,编辑会带来版本管理等复杂问题) ## 前端路由 | 路由 | 页面 | 说明 | |------|------|------| | `/` | 首页 | 粘贴脚本 + 选择运行环境/过期时间 + 提交 + 结果展示 | | `/s/[id]` | 脚本详情页 | 展示脚本内容(语法高亮)、元数据、curl 命令卡片 | | `/s/[id]/delete` | 删除确认页 | 输入 admin_token 确认删除 | ## 项目目录结构 ``` scriptforge/ ├── frontend/ # Next.js 项目 │ ├── src/ │ │ ├── app/ │ │ │ ├── page.tsx # 首页 │ │ │ ├── layout.tsx # 根布局 │ │ │ └── s/[id]/ │ │ │ ├── page.tsx # 脚本详情页 │ │ │ └── delete/ │ │ │ └── page.tsx # 删除确认页 │ │ ├── components/ │ │ │ ├── ScriptForm.tsx # 脚本提交表单 │ │ │ ├── ResultCard.tsx # 结果展示卡(含复制按钮) │ │ │ ├── ScriptViewer.tsx # 脚本内容展示(语法高亮) │ │ │ └── CommandCard.tsx # curl 命令展示卡 │ │ └── lib/ │ │ └── api.ts # API 调用封装 │ ├── package.json │ └── next.config.js ├── backend/ # Go 项目 │ ├── cmd/ │ │ └── server/ │ │ └── main.go # 入口 │ ├── internal/ │ │ ├── handler/ │ │ │ ├── script.go # 脚本 CRUD handlers │ │ │ └── raw.go # 原始内容 handler │ │ ├── model/ │ │ │ └── script.go # GORM model │ │ ├── service/ │ │ │ └── script.go # 业务逻辑 │ │ ├── middleware/ │ │ │ └── ratelimit.go # 限流中间件 │ │ └── config/ │ │ └── runtime.go # 运行时配置列表 │ ├── go.mod │ └── go.sum ├── .gitea/ │ └── workflows/ │ └── deploy.yml # Gitea Actions 部署流程 ├── Makefile # 统一构建命令 ├── DESIGN.md # 本设计文档 └── README.md ``` ## CI/CD 部署流程(Gitea Actions) 1. 触发条件:push 到 `main` 分支 2. 构建步骤: - `cd frontend && npm ci && npm run build` → 输出 `out/` - `cd backend && cp -r ../frontend/out ./internal/embed && go build -o server ./cmd/server` 3. 部署步骤: - `scp` 二进制到服务器 - `ssh` 执行 `systemctl restart scriptforge` ## 后续可扩展方向 - 大模型集成:根据脚本内容自动推荐运行环境 - 更多运行时:dockerfile、powershell、deno、bun 等 - 脚本版本管理(不基于 admin_token,需要真正的用户系统) - 统计数据:脚本执行次数、来源 IP 等(需要跟踪 curl 请求) - WebSocket 实时执行输出流