# cloud-artifacts > **生产出口**:`https://cloud-artifacts.claude-code-best.win` > > 服务端(CLI / RCS 后台)通过单一 bearer token 上传 HTML,得到一个公开可访问的 URL。 > 文件到期由 R2 lifecycle rule 自动删除(默认 7 天,最长 30 天)。 ## Quickstart ```bash # 上传一份 html(默认随机 ID + 7 天 TTL) echo '
" }`,状态码见下):
| 状态码(直连) | error code | 触发条件 |
|--------|------------|----------|
| 400 | `invalid_ttl` | `ttl` 非 7 或 30 |
| 400 | `invalid_hash` | `hash` 不匹配 `^[A-Za-z0-9_-]{1,128}$` |
| 401 | `unauthorized` | 缺 Authorization / token 不匹配 |
| 404 | `not_found` | 非 `/upload` 路径或 GET 路径不匹配 `/<7d\|30d>/.html` |
| 413 | `payload_too_large` | body > 10MB |
| 415 | `unsupported_media_type` | Content-Type 非 `text/html` |
> **经 Deno Deploy 代理时**:以上所有错误状态码统一返回 **200**,但 body 仍是上表中的 `{error: ...}` JSON。客户端解析逻辑应以 body 的 `error` 字段为准。
### `GET //.html`
`ttl-prefix` 只能是 `7d` 或 `30d`(其他路径返回 404/not_found)。返回 `text/html; charset=utf-8` + `Cache-Control: public, max-age=86400`。任何人拿到 URL 都可访问,hash 即秘密。
## 示例
```bash
# 默认随机 ID + 7 天
curl -X POST "https://cloud-artifacts.claude-code-best.win/upload" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: text/html" \
--data-binary @/tmp/t.html
# 自定义 hash + 30 天(再次上传同 hash 覆盖)
curl -X POST "https://cloud-artifacts.claude-code-best.win/upload?ttl=30&hash=my-report" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: text/html" \
--data-binary @/tmp/report.html
# 访问
curl "https://cloud-artifacts.claude-code-best.win/7d/V1StGXR8_Z5jdHi6B-myT.html"
```
## 覆盖语义
指定 `?hash=` 时:
1. 校验 hash 字符集(`^[A-Za-z0-9_-]{1,128}$`)
2. 删除 `7d/.html` 和 `30d/.html` 两个 key(R2 delete 不存在的 key 不报错,零成本)
3. 按 `?ttl=` 写入新 key
4. 返回新的 `expiresAt`
不指定 `?hash=` 时:用 `nanoid(21)` 随机 ID,几乎不可能碰撞,不做碰撞检查。
## 部署
前置:本机已 `npx wrangler login` 登录目标 Cloudflare 账号。Deno Deploy 代理层由部署者另配(CNAME `cloud-artifacts.` → `alias.deno.net`,并在 Deno Deploy 项目里把上游设为 `https://..workers.dev`)。
```bash
cd packages/cloud-artifacts
bun install # 在 monorepo 根执行也行(workspace 自动识别)
cp .dev.vars.example .dev.vars # 填本地 dev 用的 TOKEN(仅 wrangler dev 读)
bun run setup # 创建 bucket + 加 lifecycle rule + 设生产 TOKEN secret
# 绑 Worker custom domain(如要在 Cloudflare 直连域名上访问):
# Dashboard: Workers & Pages > cloud-artifacts > Settings > Domains & Routes > Add > Custom Domain
# 改 wrangler.toml 中 [vars] PUBLIC_URL 为对外出口域名(生产用 https://cloud-artifacts.claude-code-best.win)
bun run deploy
```
## 测试
`scripts/test.sh` 覆盖 7 个错误用例 + 3 个成功用例 + R2 写入验证。**支持双模式**:直连 Worker 时按 HTTP status code 断言;经 Deno Deploy 代理(status 抹平为 200)时自动按 body 的 `error` 字段断言(标记 `[via body]`)。
```bash
WORKER_URL=https://cloud-artifacts.claude-code-best.win \
TOKEN= \
bash scripts/test.sh
```
## 本地开发
```bash
cp .dev.vars.example .dev.vars
# 编辑 .dev.vars 填 TOKEN
bun run dev # wrangler dev,启动本地 Miniflare + 本地 R2 模拟
curl -X POST "http://localhost:8787/upload" \
-H "Authorization: Bearer " \
-H "Content-Type: text/html" \
--data-binary @/tmp/t.html
```
## 安全注意事项
- **TOKEN 是上传侧唯一鉴权**:值泄露后任何人可上传/覆盖。生产应使用 ≥32 字符的随机串,定期轮换(`wrangler secret put TOKEN` 即时生效,无需 redeploy)。
- **GET 完全公开**:URL 形如 `//.html`,hash(21 字符 nanoId)即唯一秘密。不要把 URL 贴到公开频道再期望它"私密"。
- **覆盖即写**:知道 hash 的任何持 token 者都能覆盖该 ID 的内容。若需要"创建后不可改"语义,应在客户端自行约束(不传 `?hash=`)。
- **不校验 HTML 内容**:上传的 html 会被原样返回,浏览器渲染时会执行其中的 `