Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions .dev.vars.example
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,25 @@ CF_ACCOUNT=
CF_KV_UUID=
# 具有 KV 读写权限的 API Token
CF_API_KEY=

# ── 缓存(文件树缓存 / 下载链接缓存)────────────────────────────────────────
# 默认【只向数据库启用】:缓存与业务数据同后端(DB_DRIVER 解析结果)。
# 想要改用 / 额外启用 KV、Blob 等专用后端,必须显式设置 CACHE_DRIVER
# (不会自动探测、不会自动回退)。详见 README「缓存配置」。
#
# 总开关,默认 true
# CACHE_ENABLED=true
# 缓存后端,默认 db;可选 db / kv / blob / cfkv / do / memory / none,
# 支持逗号分隔多后端(读按顺序命中、写全部铺开),如 db,kv
# CACHE_DRIVER=db
# 分级开关,默认 true
# CACHE_FILE_TREE=true
# CACHE_DOWNLOAD_LINK=true
# 文件树缓存时长(分钟),0 = 跟随存储级 cache_expiration(默认 30)
# CACHE_TTL=0
# 下载链接缓存时长(分钟),直链自带有效期,取值需保守(默认 5)
# CACHE_LINK_TTL=5
# 不参与缓存的驱动(纯本地计算型)
# CACHE_EXCLUDE_DRIVERS=virtual,alias,url_tree,strm,chunk
# 缓存键前缀(与业务数据键隔离)
# CACHE_PREFIX=openlist_cache
22 changes: 22 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,25 @@ CF_ACCOUNT=
CF_KV_UUID=
# 具有 KV 读写权限的 API Token
CF_API_KEY=

# ── 缓存(文件树缓存 / 下载链接缓存)────────────────────────────────────────
# 默认【只向数据库启用】:缓存与业务数据同后端(DB_DRIVER 解析结果)。
# 想要改用 / 额外启用 KV、Blob 等专用后端,必须显式设置 CACHE_DRIVER
# (不会自动探测、不会自动回退)。详见 README「缓存配置」。
#
# 总开关,默认 true
# CACHE_ENABLED=true
# 缓存后端,默认 db;可选 db / kv / blob / cfkv / do / memory / none,
# 支持逗号分隔多后端(读按顺序命中、写全部铺开),如 db,kv
# CACHE_DRIVER=db
# 分级开关,默认 true
# CACHE_FILE_TREE=true
# CACHE_DOWNLOAD_LINK=true
# 文件树缓存时长(分钟),0 = 跟随存储级 cache_expiration(默认 30)
# CACHE_TTL=0
# 下载链接缓存时长(分钟),直链自带有效期,取值需保守(默认 5)
# CACHE_LINK_TTL=5
# 不参与缓存的驱动(纯本地计算型)
# CACHE_EXCLUDE_DRIVERS=virtual,alias,url_tree,strm,chunk
# 缓存键前缀(与业务数据键隔离)
# CACHE_PREFIX=openlist_cache
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public_data
.idea
.test
.codebuddy
.workbuddy-ai
.vscode
.env
.env.local
Expand Down
68 changes: 68 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,74 @@ CF_API_KEY=your_api_token

前缀固定为 `x_`(与 Go 后端默认值一致)。要与 Go 后端共享同一物理数据库,无需额外配置。

#### 缓存配置

本项目实现了两级持久缓存(参考 [OpenList.ts](https://github.com/Wudarensheng/OpenList.ts)):

- **文件树缓存**:`/api/fs/list`、`/api/fs/get`、`/api/fs/dirs` 优先从缓存读取目录树,
只有缓存未命中(或已过期)才会去请求网盘 / 对象存储;
- **下载链接缓存**:`/d`、`/p` 等下载链路复用驱动换取的直链,
重复下载 / 预览时不再重新签名或重新换链(网盘换链通常最贵、最易被限流)。

**默认只向数据库启用**:缓存与业务数据走同一条存储链路(即 `DB_DRIVER` 指向的
后端),因此「什么都不配」就等于「用数据库做缓存」。想要改用 / 额外启用 KV、
Blob 等专用后端,**必须显式添加环境变量**(不会自动探测、不会自动回退):

**CACHE_ENABLED**(总开关)
- `true`(默认):启用两级缓存
- `false`:完全关闭(等同于 `CACHE_DRIVER=none`)

**CACHE_DRIVER**(缓存后端)
- `db`(默认):与业务数据同一个后端(`DB_DRIVER` 解析结果,如 D1 / KV / Blob / MySQL)
- `kv`:Cloudflare KV 或 EdgeOne KV(binding 名固定为 `KV`)
- `blob`:EdgeOne Blob SDK / ESA Blob
- `cfkv`:Cloudflare KV REST API(需 `CF_ACCOUNT`、`CF_KV_UUID`、`CF_API_KEY`)
- `do`:Cloudflare Durable Objects
- `memory`:进程内存(仅本地调试,重启即失)
- `none`:关闭缓存
- 支持逗号分隔的多后端(**读按顺序命中,写全部铺开**),例如:
- `db,kv` —— 数据库 + KV 双写,读优先命中 KV
- `kv,blob` —— 只用两个专用后端
- 显式配置但该后端不可用时:**跳过并告警,不会悄悄换成别的后端**;
若最终一个都不剩,缓存自动降级为「不缓存」(请求照常走真实存储)。

**CACHE_FILE_TREE** / **CACHE_DOWNLOAD_LINK**(分级开关)
- 均为 `true`(默认);设为 `false` 可单独关闭文件树缓存或下载链接缓存

**CACHE_TTL**(文件树缓存时长,分钟)
- `0`(默认):跟随存储级 `cache_expiration`(默认 30 分钟,
可被该存储的 `custom_cache_policies` 按路径覆盖)
- `>0`:全局覆盖所有存储的文件树缓存时长
- 存储级 `cache_expiration=0` 或路径级策略命中 `0` 时,该目录**永不缓存**

**CACHE_LINK_TTL**(下载链接缓存时长,分钟)
- 默认 `5`。直链通常自带有效期,取值需保守:缓存过久会把已失效的链接
交给浏览器(表现为 403/404)。设为 `0` 可关闭链接缓存。

**CACHE_EXCLUDE_DRIVERS**(不参与缓存的驱动)
- 默认 `virtual,alias,url_tree,strm,chunk` —— 这些驱动不产生远程 IO,
缓存没有收益且只会让结果变陈旧
- 传空字符串表示不排除任何驱动

**CACHE_PREFIX**(缓存键前缀)
- 默认 `openlist_cache`,用于与业务数据键(`openlist_config`、`users_1` 等)隔离

**失效与一致性:**
- 写操作(mkdir / rename / remove / move / copy / put)会**立即失效**受影响的
路径与其父目录缓存;
- 存储配置变更(更新 / 启用 / 禁用 / 删除)会清空该存储的全部缓存;
- 缓存只存「驱动层结果」,权限、meta 密码、隐藏规则、下载签名都在请求时
实时计算,因此**缓存不会造成越权**。

**管理接口:**
- `GET /api/admin/cache/status` —— 生效配置、实际后端、各级缓存条目数
- `POST /api/admin/cache/clear` —— body `{ type?: "file_tree" | "download_link", storage_id?: number }`
- `POST /api/admin/storage/refresh` —— 刷新(清空)全部存储的文件树缓存
- `POST /api/admin/storage/refresh_one?id=<id>` —— 刷新单个存储的文件树缓存

> 缓存状态也会回显在 `/api/public/env_check` 的 `cache` 字段中,
> 便于确认「缓存实际落在哪个后端」。

#### 安全配置

- `JWT_SECRET`:JWT 令牌签名密钥(必填),**同时用作可选的字段加密密钥**与定时任务鉴权
Expand Down
27 changes: 26 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,30 @@
},
"DB_CIPHER": {
"description": "At-rest cipher for sensitive fields (drive credentials, 2FA secrets, password hashes): `none` (default, no encryption), `aes-256-gcm` (HKDF-derived AES-256-GCM key — the `enc:v2:` envelope written by existing encrypted deployments, recommended), `aes-256-gcm-pbkdf2` (legacy `enc:v1:` envelope, PBKDF2 per field, slow), `aes-256-cbc-hmac` (`enc:v3:`), `chacha20-poly1305` (`enc:v4:`, RFC 8439, pure-JS implementation), `des-cbc-hmac` / `3des-cbc-hmac` (`enc:v5:`/`enc:v6:`, compatibility only — single DES is 56-bit and 3DES is deprecated, do not use for real data). Ciphertexts carry an `enc:vN:` prefix and are decrypted by prefix on read, so switching back to `none` (or changing algorithms) never makes existing data unreadable — it only changes how newly written data is stored (legacy ciphertext is migrated to plaintext on the next save). Key derivation is cached per isolate, and unchanged fields are not re-encrypted on save. This setting does NOT affect the shared secret: with `none`, a secret is still generated and persisted during setup when JWT_SECRET is not provided, because JWT signing needs it."
},
"CACHE_ENABLED": {
"description": "Optional. Master switch for the file-tree cache and the download-link cache. Defaults to `true`. Set to `false` to disable both."
},
"CACHE_DRIVER": {
"description": "Optional. Where the caches are stored. Defaults to `db`, meaning the same backend as DB_DRIVER (D1/KV/Blob/MySQL) — i.e. only the database is used unless you opt in explicitly. Comma-separated list to add dedicated backends: `kv`, `blob`, `cfkv`, `do`, `memory`, or `none` to disable. Example: `db,kv` (read prefers KV) or `kv` (KV only). Dedicated backends are never auto-detected or auto-substituted."
},
"CACHE_FILE_TREE": {
"description": "Optional. Toggle the file-tree cache (directory listings). Defaults to `true`. Listings are cached per storage+path; only admin writes invalidate them."
},
"CACHE_DOWNLOAD_LINK": {
"description": "Optional. Toggle the download-link cache (presigned/raw download URLs returned by drivers). Defaults to `true`. Reuses the link instead of re-signing on every download."
},
"CACHE_TTL": {
"description": "Optional. File-tree cache lifetime in minutes. Defaults to `0`, which means 'follow the per-storage cache_expiration' (30 minutes, overridable per path by custom_cache_policies). Set to 0 to never cache a storage whose cache_expiration is 0."
},
"CACHE_LINK_TTL": {
"description": "Optional. Download-link cache lifetime in minutes. Defaults to `5`. Keep it conservative: raw URLs usually carry their own expiry, and a stale link is served to the browser as 403/404."
},
"CACHE_EXCLUDE_DRIVERS": {
"description": "Optional. Comma-separated drivers excluded from caching. Defaults to `virtual,alias,url_tree,strm,chunk` (locally computed drivers where caching only adds staleness)."
},
"CACHE_PREFIX": {
"description": "Optional. Key prefix used to isolate cache entries from business data. Defaults to `openlist_cache`."
}
}
},
Expand Down Expand Up @@ -55,10 +79,11 @@
"test:server": "tsx --test \"src/backend/server/*.test.ts\"",
"test:store": "tsx --test src/backend/internal/model/store/store.test.ts",
"test:model": "tsx --test \"src/backend/internal/model/*.test.ts\"",
"test:cache": "tsx --test \"src/backend/internal/cache/*.test.ts\"",
"test:regress": "tsx scripts/_regress.mjs",
"test:deploy": "node scripts/test-deploy.js",
"env:check": "tsx scripts/env-check.mjs",
"test:all": "npm run test:189 && npm run test:drivers && npm run test:server && npm run test:store && npm run test:model && npm run test:regress",
"test:all": "npm run test:189 && npm run test:drivers && npm run test:server && npm run test:store && npm run test:model && npm run test:cache && npm run test:regress",
"sls:deploy": "serverless deploy",
"sls:package": "serverless package",
"sls:info": "serverless info",
Expand Down
Loading
Loading