# jsjiami 在线 JS 加密 API

统一入口：`https://jsjiami.xueyuanpie.com/api.php?act=<动作>`
响应：`{"code":"1"|"-1", "info":"<提示>", "data":{...}}`（与 sgapi 完全一致，`code=1` 成功）

引擎：**cerk-jsenc**（自研字节码 VM + 控制流平坦化 + AI 对抗），**本机离线加密**，无上游云端、无 license。
产物是 JS：浏览器 `<script>` / Node `require` 直接跑，目标机不需要 Loader、不需要 Node。

鉴权：`js.upload` / `js.submit` / `download` 需要卡密令牌。
先用 `auth.verify` 换取 `token`，随后以 `auth_token` 字段或 `X-Auth-Token` 请求头携带（24 小时有效）。

---

## auth.verify — 卡密验证

```
POST /api.php?act=auth.verify
card_key=<卡密>
```
```json
{"code":"1","info":"卡密验证成功","data":{
  "token":"eyJjYXJkX2lkIjox...",
  "card_info":{"card_key":"JSJ4…","name":"panel","max_files_per_encrypt":20,
               "max_encrypt_times":0,"used_encrypt_times":0,"remaining_times":"无限制","expire_time":null}
}}
```

## auth.info — 查询当前令牌 / 卡密信息

```
GET /api.php?act=auth.info&auth_token=<token>
```

## js.versions — 引擎能力（公开，无需令牌）

```
GET /api.php?act=js.versions
```
```json
{"code":"1","info":"ok","data":{
  "engine":"cerk-jsenc","version":"1.0.0","mode":"service","available":true,
  "defaults":{"seed":0,"engine":"vm","blobFormat":"base64","scriptGlobals":true,
              "junk":0.06,"mba":0.25,"junkBlocks":4,"opaque":0.35,
              "hard":false,"antiDebug":true,"antiFormat":true,"antiFeed":true,"encryptCode":true},
  "limits":{"max_upload_mb":10,"max_js_files":200,"max_single_kb":4096}
}}
```

## js.upload — 上传待加密源码

```
POST /api.php?act=js.upload
file=@app.js 或 file=@project.zip        （.js / .mjs / .cjs / .zip）
auth_token=<token>
```
```json
{"code":"1","info":"上传成功","data":{
  "space":"65f3e22e71f9778792652dbb8c3f673f","file":"project.zip","file_count":4,
  "price":0.4,"balance":100000,"engine":"1.0.0"
}}
```

限制：≤ 10MB；单次 ≤ 200 个 JS 文件；ZIP 内非 JS 文件会被忽略，**目录结构保留**。

## js.submit — 执行加密（同步返回）

```
POST /api.php?act=js.submit
space=<space>&auth_token=<token>
seed=20261014        # 0/省略 = 每次形态随机；>0 可复现，批量按 seed,seed+1… 派生
engine=vm            # vm（默认，纯 VM 不需要 eval）/ auto / pack
blobFormat=base64    # base64 / hex
junk=0.06&mba=0.25&opaque=0.35&junkBlocks=4
antiDebug=1&antiFormat=1&antiFeed=1&encryptCode=1
scriptGlobals=1&hard=0&banner=
```
```json
{"code":"1","info":"加密完成","data":{
  "space":"65f3e2…",
  "stats":{"total":4,"encoded":3,"failed":1,"bytes":130846,"ms":669},
  "zip":"65f3e2….zip",
  "engine":"1.0.0","mode":"service",
  "seeds":{"app.js":20261014,"lib/util.js":20261017},
  "requires_unsafe_eval":true,
  "detail":[
    {"file":"app.js","ok":true,"in":60,"out":43700,"ms":330,"seed":20261014,"vmFunctions":2,"fallbacks":0},
    {"file":"esm/mod.mjs","ok":false,"error":"Fallback: 模块语法 ExportNamedDeclaration…"}
  ]
}}
```

> `requires_unsafe_eval=true` 表示至少一段产物含降级函数（async/generator/私有字段等），
> 那段产物运行时需要 `unsafe-eval`；严格 CSP 页面请用 `engine=vm` 并消除触发降级的语法。

## download — 下载产物

```
GET /api.php?act=download&type=js&space=<space>&auth_token=<token>
```

- 单文件任务 → 直接回加密后的 JS（下载名 `<原名>.enc.js`）
- 多文件任务 → 回 ZIP（目录结构与上传一致）

---

## 典型报错

| info | 处理 |
| --- | --- |
| `鉴权失败：请先验证卡密` | 重新 `auth.verify` 并带上 `auth_token` |
| `ZIP 中没有 JS 文件！` | 压缩包里没有 `.js/.mjs/.cjs` |
| `Fallback: 模块语法 ExportNamedDeclaration…` | ESM 顶层 import/export：改 `engine=auto`，或先打包成单文件 |
| `Fallback: 严格降级函数需要捕获外层变量…` | 该文件用了 VM 暂不支持的语法且无法安全降级：改 `engine=auto` |
| `文件数量超限，当前卡密单次最多支持 N 个文件！` | 拆包或换卡密 |

## 边界

- 加密在本机完成，源码不出服务器。
- 保护的是**静态可读性与自动化逆向成本**，不是「无法破解」，也不防内存 dump。
- 引擎会解析（不可信的）JS 源码，**不要把它当沙箱**；对外务必保持卡密鉴权并限制来源。
