← 返回列表
未验证
DeepSeek HarnessDSHweb 插件:在 dsh-better-sidebar…
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/2 · 已提供中文文档
DSH Web 插件:通过自托管的 ONLYOFFICE 文档服务器在 better-sidebar 编辑器中打开并编辑 .docx/.xlsx/.pptx 文件(JWT 签名的配置、原子化回写保存、AI 编辑时实时刷新)
综合分
28.3
GitHub 分
28.3
用户评分
—
★ Stars
0
周下载量
—
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add chendefine/dsh-sidebar-onlyoffice该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/18(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-client-runtime@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-settings-plugins@deepseek-ai/dsh-client-ui-slots用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-sidebar-onlyoffice
English · npm · GitHub
DeepSeek Harness(DSH)web 插件:在 dsh-better-sidebar 的文件侧边栏中,用自部署的 ONLYOFFICE Document Server 打开并编辑 .docx / .xlsx / .pptx —— 配置经 JWT 签名、保存原子写回磁盘,并且 AI 修改已打开的文件时编辑器实时刷新。
npm license node CI stars
功能
- 真正的办公编辑 —— better-sidebar viewer 内嵌完整的 ONLYOFFICE 编辑器(文字/表格/演示),不是静态预览;保存自动写回磁盘文件。
- 同源反代(常开) —— DS 的整套浏览器界面(api.js、编辑器 iframe、静态资源、协同 socket)由 dsh web 自身在 /sidebar/onlyoffice/ds 反代,浏览器无需访问到 DS 的服务地址,DS 可完全留在内网。
- 默认签名与围栏 —— 配置密钥后编辑器配置整体 HS256 JWT 签名;文件下载一律凭短时效 HMAC 令牌;浏览器侧路由在 dsh web 信任围栏之内;会话工作目录之外的文件一律拒绝。
- AI 修改实时可见 —— agent 修改编辑器中打开的文件时,viewer 约 1 秒内经 refreshFile 换到新版本,页面不重载、api.js 不重载。脏编辑器绝不自动刷新(改为横幅提示手动重载)。
- 原子保存 + 自保存抑制 —— 回调下载保存字节后以临时文件 + rename 原子替换,同 key 串行化;插件自身写入被监听枢纽吸收,用户保存不会回环触发刷新。
- 内网直连拉取保存文档 —— DS 上报的保存 URL 会改写到 documentServerUrl(容器间直连),避免绕公网反代回环。
- 与 office 预览插件共存 —— viewer id onlyoffice:docx|xlsx|pptx(priority 10)与 @huanlin/dsh-plugin-better-sidebar-plugin-office 的 docx/xlsx/pptx(priority 0)不冲突;侧边卡片设置页可分别禁用。
工作原理
| 半 | 位置 | 职责 |
| --- | --- | --- |
| Node(服务端)| src/ | 在 dsh web 的 webServer 上注册四个路由,实现 ONLYOFFICE 官方集成文档中的 "document storage service" 角色。 |
| 浏览器(客户端)| src/client/ | 注册三个 better-sidebar 文件 viewer;按需加载 DS api.js、挂载 DocsAPI.DocEditor、订阅 SSE watch 流。 |
better-sidebar viewer (onlyoffice:docx|xlsx|pptx)
├─ GET /sidebar/onlyoffice/config (浏览器端,信任围栏内)
│ → 编辑器配置 + JWT + api.js 地址 + HMAC 文件令牌
├─ GET /sidebar/onlyoffice/file (Document Server;HMAC 令牌即鉴权)
├─ POST /sidebar/onlyoffice/callback (Document Server;status 2/6 → 原子写回)
├─ GET /sidebar/onlyoffice/watch (浏览器端 SSE;inotify 磁盘变更)
│ → change → 重取 config → docEditor.refreshFile(config) [不重载]
└─ /sidebar/onlyoffice/ds/** (浏览器 ↔ Document Server,同源)
→ api.js + 编辑器 iframe + 静态资源 + socket.io(WS 按文档即时路由,失败降级轮询)
- Node 半 —— config 路由对会话 cwd 内的绝对路径生成编辑器配置(documentType 映射、内容寻址 key = sha256(host+path+size+mtime)),整体 HS256 JWT 签名,登记 key→文件 映射并签发短时效 HMAC 文件令牌。file 路由向 DS 提供文件字节。callback 路由(JWT 校验)在 status 2/6 时下载保存字节并临时文件+rename 原子写回,status 4 清除映射,应答 {"error":0}。watch 路由以 SSE 推送磁盘变更,由 inotify 监听枢纽供给(fs.watch 同时盯文件与其所在目录,防抖后按同一内容寻址 key 做签名过滤)。
- 浏览器半 —— 按 URL 仅一次加载 DS api.js,挂载编辑器,卸载时 destroyEditor();失败时展示错误面板 +「下载文件」回退链接(复用 better-sidebar 的 /sidebar/file 路由)。挂载期间订阅 watch 流,发现外部(通常是 AI)修改后重取 config 并调用 docEditor.refreshFile(config)。
AI 修改的实时可见
agent 修改了编辑器中打开的文件时,viewer 约 1 秒内感知:inotify → SSE change 事件 → 重取 config(内容寻址 key 随文件而变)→ refreshFile。编辑器 iframe 本体被复用——页面不重载、api.js 不重载,DS 以全新会话打开新版本(旧 key 以 status 4 关闭)。护栏:
- 脏编辑器绝不自动刷新 —— refreshFile 无条件丢弃未保存修改(集成方调用路径上没有 isDocumentModified 守卫,已在 DS 源码中核实)。此时改为展示横幅(「文件已被外部修改——重新加载将丢弃未保存的修改」)+ 手动「重新加载」按钮,点击即视为用户确认。
- DS 自发的 onRequestRefreshFile(断线重连 / 同 key 保存时触发,仅在非脏状态)走同一条刷新路径。
- 插件自身的回调保存在服务端被抑制(noteSelfSave 记录刚写入的签名),用户保存不会回环刷新、重置光标。
- 文件被删除推 removed 提示;重新出现推 change。
环境要求
- DSH web profile(dsh web),Node.js ≥ 20,并已安装 dsh-better-sidebar 插件。
- 自部署的 ONLYOFFICE Document Server(已在 9.4 社区版实测),网络可达 dsh web 服务器;浏览器无需能访问它(反代挂载点是唯一的浏览器侧 DS 入口)。
- JWT 启用时(DS 默认),插件的 jwtSecret 必须与 DS 的 JWT_SECRET 一致。
- document.url / callbackUrl 为私网地址时,DS 需要 ALLOW_PRIVATE_IP_ADDRESS=true(DS 默认拒绝)。
安装
从 npm 源安装(预构建 —— 无需构建权限):
dsh plugin --profile web add dsh-sidebar-onlyoffice
从 GitHub 仓库安装(源码 —— pnpm 会执行 prepare 构建;若 pnpm 拦截构建脚本,请在 profiles/web/pnpm-workspace.yaml 里放行):
dsh plugin --profile web add github:chendefine/dsh-sidebar-onlyoffice
也可以通过 DSH 插件市场(设置 → DSH插件市场)—— 仓库带 dsh-plugin topic,会被自动索引。
bundle 插件加入 profile 层栈后,把配置写进 profile 的 cordis.patch.yml 手编层(见下),重启 dsh web,浏览器硬刷新(Ctrl+Shift+R)。卸载:dsh plugin --profile web remove dsh-sidebar-onlyoffice 后再重启。
配置
所有键均可选;由 profile 的 cordis.patch.yml 层承载:
- id: dsh-sidebar-onlyoffice
config:
jwtSecret: "" # 空 = 不签名(仅 JWT_ENABLED=false 的 DS)
documentServerUrl: http://onlyoffice-documentserver # dsh web 直连的 DS 入口(其自带 nginx)
internalBaseUrl: http://172.31.255.4:3080 # DS 回连 dsh web 的基址;空 = 自动探测
publicBaseUrl: https://work.example.com # 网关改写 Host 时的浏览器可见源;空 = 按请求 Origin
defaultMode: edit # edit | view
username: User # 编辑器右上角显示的协作用户名
fileLimitMb: 100
tokenTtlSec: 600
| 字段 | 默认值 | 说明 |
| --- | --- | --- |
| jwtSecret | '' | 与 Document Server 共享的密钥(其 JWT_SECRET)。设置后编辑器配置与回调均 JWT 签名/校验;为空仅适用于 JWT_ENABLED=false 的 DS。 |
| documentServerUrl | '' | 唯一的 Document Server 地址:dsh web 自身直连的 DS 入口——docker 网络上 DS 容器自带的 nginx(http://onlyoffice-documentserver)或发布到宿主的端口。同时充当反代上游与保存字节拉取基址。 |
| internalBaseUrl | (自动探测) | DS 回连本 dsh web 服务器的基址(文档下载 + 回调)。空 = 自动探测本机非环回 IPv4 + web 端口。 |
| publicBaseUrl | (请求 Origin) | 浏览器可见源(协议://主机[:端口]),用于铸造 X-Forwarded-Host/Proto 和匹配 DS 上报的保存 URL。dsh web 前面的网关会改写 Host 时必须设置;空 = 按每个请求的 Origin 推导。 |
| defaultMode | edit | 新标签页的默认打开模式(edit/view)。 |
| username | User | 编辑器右上角显示的协作用户名(editorConfig.user.name);留空恢复为 User。修改后重新打开文件生效。 |
| fileLimitMb | 100 | 提供与写回的最大文件体积(MB)。 |
| tokenTtlSec | 600 | 签名 URL 令牌的有效期(秒)。 |
0.2.0 之前的旧键(proxy、proxyUpstream、internalDocumentServerUrl、proxyPublicBase、documentServerPort)启动时映射一次——proxyUpstream/internalDocumentServerUrl 映射到 documentServerUrl,proxyPublicBase 映射到 publicBaseUrl——并打一条警告;请尽快迁移到新名称。
图形化配置(设置卡片)
组合装载了 DSH settings 服务时(标准 dsh web bundle 均装载),插件会注册 dsh-sidebar-onlyoffice 设置命名空间,Web 客户端的 设置 → 插件 标签页会为它渲染一张配置卡片——八个字段全部可视化,中英文案,暂存式编辑 + 保存/放弃。提交的修改写入部署的用户配置(/settings.yaml),叠加在组合层之上,无需重启即生效:路由闭包与反向代理都按实时配置读取(jwt/mode/username/limit/token/URL 在下一次编辑器配置请求生效;documentServerUrl 变更则立即切换代理上游——已发现的版本化前缀会重置并重新探测,通过卡片首次配置出的地址会即刻认领挂载点)。因此部署可以带空的组合层条目启动,完全通过卡片完成配置。
字段优先级:卡片/用户层 → 组合层(cordis.patch.yml 的 config: 块)→ schema 默认值。在卡片上点"恢复默认"即回落组合层;直接手编 settings.yaml 同样实时生效。
保存 URL 改写(内网直连拉取)
两个方向各自独立配置:DS → 本插件用 internalBaseUrl(文档下载 + 回调);本插件 → DS 拉取回调上报的保存字节。DS 是按反代转发的浏览器可见基址(publicBaseUrl,否则请求 Origin)铸造这些保存 URL 的——反代部署下会绕公网回环(DNS + TLS + 终结器 + 网关)。插件把铸造前缀改写到 documentServerUrl(如 http://onlyoffice-documentserver,docker 网络容器名直连)——路径后缀与查询串原样保留,实现容器间直连。
安全性已实测验证(DS 9.4):/cache/files 的鉴权是 nginx secure_link 的 md5(expires + 请求路径 + 服务端secret),其中"请求路径"是剥掉子路径前缀后的路径,主机名与前缀都不在签名材料内,因此改写主机并剥前缀后仍返回 200。URL 不在公网基址之下时不改写、按原样请求并记一条 warn。
同源反代
本插件是纯反代架构:始终把 DS 的整套浏览器界面通过 dsh web 端口反代到 /sidebar/onlyoffice/ds。config 路由直接下发挂载点的 api.js 地址,编辑器其后加载的一切——iframe、sdkjs/web-apps 静态资源、字体、协同 socket、导出与下载——都经 dsh web 回流。浏览器完全不需要访问到 DS 的服务地址:把 documentServerUrl 指向 DS 容器入口,DS 可以留在内网。顺带消除混合内容坑:https 的 GUI 可透明反代只支持 http 的 DS。
与 DS(9.x,即本插件目标同代)的协作机制:
- api.js 从自身脚本地址推导 DS 基址,编辑器从 iframe 地址推导 socket 路径——两者都天然落在挂载点之内。
- 代理按官方「virtual path」形态发送 X-Forwarded-Host: /sidebar/onlyoffice/ds,DS 自行铸造的 URL(版本化脚本缓存 302、保存/下载链接)因此指回挂载点;绝对 Location 响应头还会被额外改写为挂载点相对形式。同样的转发头也随 WebSocket 升级腿转发——DS 在该连接上推导 /cache/files 文档数据基址。
- 编辑器的 socket.io 路径为 /~/doc//c,其中 正是本插件的内容寻址文档 key。代理按打开的文档即时注册该精确 WebSocket 升级路由(DS status-4 关闭时注销、LRU 上限、DS 升级换版本前缀时自动重发现)。偶发漏注册则平滑降级:编辑器回落到 socket.io 轮询(普通 HTTP,走挂载点前缀路由),编辑不中断。
- 两条代理腿(HTTP 与升级)都在与其他插件路由相同的浏览器信任围栏之内(同源编辑器放行;跨站页面拒绝)。
注意与边界:
- 需要 9.x 一代的 DS(子路径 URL 铸造能力)。
- 每次保存都会更换 key(内容寻址),升级路由随保存而更替——关闭即注销、有上限,实践中无感。
- 若 dsh web 前面的网关会改写 Host(例如改成 127.0.0.1:3080),DS 响应体内铸造的 URL 会携带该浏览器不可达的主机:此时设置 publicBaseUrl 为浏览器可见源。
- 安全取舍:DS 界面与 DSH 页面同源运行,DS 被攻破时可脚本化 dsh 源。围栏仍拦截跨站调用;请保持 DS 可信。
- 静态资源走两跳(浏览器 → dsh web → DS);版本化不可变缓存可穿越该跳,但外层网关若要最佳性能,需把 /sidebar/onlyoffice/ds/** 纳入其缓存策略映射。
部署形态
典型部署:Document Server 容器与 dsh web 同一 docker 网络(容器名可解析,如 onlyoffice-documentserver——即 documentServerUrl),JWT 启用固定密钥,DS 容器加 ALLOW_PRIVATE_IP_ADDRESS=true。DS 完全不需要对外发布浏览器可达的端口。
排错:编辑器报 errorCode:-4「下载失败」
-4 是 DS 下载 document.url 失败。诊断入口是 DS 容器日志里 error downloadFile:url=... 的目标 URL:
- URL 指向 DS 自己 → internalBaseUrl 配错成了 DS 地址。它必须是 DS 回连 dsh web 的地址(两者同网络时用容器名);改 profile 的 cordis.patch.yml 后 Cordis HMR 自动热生效,无需重启。
- 404 → 路由不在(配错 host);403 → token 过期/签名不符(重启 dsh web 后重开文件);连接被拒/超时 → 网络不通(确认两个容器同网络,DS 需 ALLOW_PRIVATE_IP_ADDRESS=true)。
- 快速自测(不开浏览器):带 Host: localhost 请求 config 路由拿到 document.url,再 docker exec onlyoffice-documentserver curl -v ,应当 200。
已知边界
- 保存是整文件覆盖:与 agent 并发写同一文件时最后写入者胜。实时刷新收窄了该窗口——干净的编辑器约 1 秒内被推到最新版本——但脏编辑器在 AI 修改后再保存仍会覆盖之;保存完成时横幅随之清除(覆盖已解决分歧)。
- 自保存抑制存在毫秒级竞态:恰落在插件保存与其 noteSelfSave stat 之间的外部写入可能被误吸收(漏推一次刷新事件;下一次变更即恢复)。实践中可忽略。
- onRequestRefreshFile 事件需要 ONLYOFFICE Docs ≥ 8.3;refreshFile 本身已在 Document Server 9.4 社区版实测可用。
- DS 需为 9.x 一代(子路径 URL 铸造);WebSocket 腿依赖按文档即时注册路由,漏注册时静默降级为 socket.io 轮询(老版本 DS 或路由冲突场景)。
- key→文件 注册表持久化在 /plugins/dsh-sidebar-onlyoffice/registry.json(最新 128 条),dsh web 重启后 DS 重投的保存回调仍能落盘。watch 流会自动重连(EventSource retry: 3000);跨重启保持打开的 viewer 在下次交互时重取配置。
安全
服务端半只会提供与写入会话工作目录之内的文件,浏览器侧路由位于 dsh web 信任围栏之内,DS 的每次下载都凭 config 请求时签发的短时效 HMAC 令牌。Document Server 由用户自行部署与配置——请将其部署在可信网络。完整立场与威胁模型见 SECURITY.md。
开发
pnpm install
pnpm run typecheck # 类型门禁
pnpm test # vitest(JWT/key/令牌、路由围栏与回调落盘、保存 URL 内网改写、同源 ds 反代、settings 接线、viewer 描述符、inotify 监听枢纽 + SSE 路由)
pnpm run build # lib/index.js(Node 半)+ lib/client.js(ModuleLoader 包裹的浏览器半)
仓库结构:
src/
├── index.ts # 宿主入口:webServer 四路由(含 dsProxy 接线)
├── dsProxy.ts # 同源 DS 反代:挂载、转发头、即时 WS 路由
├── config.ts # schemastery schema、基址推导/探测
├── settings.ts # 设置区接线(图形化配置卡片的宿主半)
├── onlyoffice.ts # 编辑器配置、JWT 载荷、文件令牌、保存 URL 改写
├── jwt.ts # 极简 HS256 签名/校验(零依赖)
├── registry.ts # key→文件 映射、原子写回、持久化
├── watch.ts # inotify 监听枢纽(防抖、签名过滤、自保存吸收)
├── trust-fence.ts # 浏览器请求信任校验(host/origin)
├── paths.ts # 绝对路径 + 包含关系工具
├── wire.ts # JSON body/错误工具
└── client/ # 浏览器半:viewer、编辑器挂载、i18n、设置卡片
许可
MIT扫码进群