关于 sharepoint-html
sharepoint-html 是用于制作并发布自包含 HTML 文件的技能,使其可在 SharePoint 的 OneUp 查看器中呈现。内容涵盖查看器限制、实时 SharePoint 数据,以及通过 Microsoft Graph 或 SharePoint Vroom API 发布。
主要功能
- 01编写适用于 OneUp 沙盒的 HTML
- 02通过 LiveData 清单读取 SharePoint 内容
- 03使用内置仪表板模板
- 04预检 HTML 并检查目标文件冲突
- 05通过 Microsoft Graph 或 SharePoint Vroom 发布
适用场景
- 01发布自包含的状态仪表板
- 02展示实时 SharePoint 文件或列表数据
- 03从 OneDrive 或 SharePoint 打开呈现后的 HTML 页面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ sharepoint/ sharepoint-html --skill sharepoint-html安装后在 Claude Code 中输入/sharepoint-html确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSE.gitignoreREADME.mdinstall.shassets/templates/README.mddashboard.htmllivedata-list-dashboard.htmllivedata-dashboard.htmlreferences/contract.mdapi.mdlive-data.mdscripts/preflight.shpublish-to-folder.shpublish-graph.sh详细介绍
向 SharePoint 发布 HTML(OneUp HTML 查看器)
SharePoint 已支持托管 HTML:将 .html 文件保存到 OneDrive 或 SharePoint 并打开,即可在 OneUp HTML 查看器中呈现——该查看器使用受严格 Content-Security-Policy 约束的沙盒 <iframe>。无需配置单独的托管服务;发布只需以已登录用户的身份将 .html 文件写入其云盘,然后打开该文件的 webUrl。
本技能教会 Agent 两件事:
- 编写能正常呈现的 HTML——OneUp 的 CSP 和沙盒会静默失败,因此不符合要求的 HTML 会显示为空白或部分损坏,且不会报错。遵循以下规范即可正常运行。
- 发布 HTML——使用 Microsoft Graph(首选)或 SharePoint Vroom API(
_api/v2.0,适用于已持有 SharePoint 令牌的 Agent)上传文件,然后将返回的webUrl提供给用户。
规范的、始终保持最新的编写要求位于租户的发现端点:https://<your-sharepoint-host>/_html(人类可读页面)、/_html/llms.txt(Agent 文本)和 /_html/help.json(结构化信息)。如有疑问,请获取 /_html/llms.txt——它由当前的查看器源代码生成。
⚠️ 发布前须知:你正在写入用户的真实云盘
使用此技能发布会以用户身份进行身份验证,并在其自己的 OneDrive / SharePoint 中创建或覆盖文件。这不是临时沙盒。
- 文件不会自动公开。 文件对用户保持私有,除非用户明确共享。但它确实是其云盘中的真实文档。
- 每次上传和每次覆盖之前,都必须征得用户的明确确认。 告知用户确切的目标位置(云盘、文件夹、文件名),以及此操作是创建新文件还是替换现有文件,然后等待用户确认。请参阅写入前确认。
- 覆盖操作具有破坏性。 对现有路径执行
PUT .../content会替换文件内容。请确认路径,并确认用户确实希望覆盖。
编写规范(让 HTML 在 OneUp 中正常渲染)
你的 HTML 会在 <iframe sandbox="allow-scripts"> 中运行,并受严格的 CSP 限制;违反规则时不会显示错误。请遵守以下规则,否则页面会空白或只显示部分内容,且不会报错。
应用于你的 HTML 的内容安全策略:
default-src 'none';
script-src 'unsafe-inline' 'unsafe-eval';
style-src 'unsafe-inline';
img-src data: blob:;
font-src data: blob:;
connect-src 'none';
worker-src 'none';
object-src 'none';
base-uri 'none';
form-action 'none';
外层 iframe 还会额外应用 frame-src 'none'。
不可妥协的规则:
- 禁止使用外部资源。 不得使用
<script src>、<link href>、<img src=https://…>、@import、url(https://…)、远程字体或 CDN。所有内容均须内嵌,或使用data:/blob:URI。 - 所有脚本都必须内嵌在
<script>块中。不得导入模块,不得使用import(),也不得使用<script src>。 - 所有样式都必须内嵌在
<style>或style="…"中。不得使用<link rel="stylesheet">。 - 运行时禁止联网——
fetch、XMLHttpRequest、WebSocket、sendBeacon、EventSource均会被阻止(connect-src 'none')。如需在查看时读取 SharePoint 文件数据,请使用 LiveData 清单(见下文)——这是唯一获准的数据路径。 - 禁止使用存储机制——
localStorage、sessionStorage、indexedDB、document.cookie(不透明源沙箱)。如需跨重新加载保留状态,请直接设置location.hash(例如location.hash = '#slide=3')。不得使用history.pushState/replaceState——沙箱化文档的基础 URL 继承自包装器的blob:源,因此任何url参数(即使只是#hash)都会抛出SecurityError。 - 禁止顶层导航、弹出窗口、表单提交、工作线程或插件。
alert/confirm/prompt均为空操作。 - 内嵌的
on*=处理程序可以正常工作(它们会被改写为带 nonce 的脚本),但如果将不可信数据模板化到其中,就会造成 XSS 漏洞——处理计算得出或来自用户/获取的数据时,优先使用addEventListener。 - 保存为 UTF-8(以下文件创建 API 会以 UTF-8 写入;如果手动编写且非 ASCII 内容显示异常,请添加 BOM)。
链接:<a href> 仅会打开同一租户的 SharePoint 主机或外部允许列表中的地址;javascript: / vbscript: / data: href 会被拒绝。
实时 SharePoint 数据(唯一的运行时数据源)
运行时 fetch 会被阻止。要显示实时 SharePoint 文件内容,请嵌入 LiveData 清单——主机使用查看者的凭据在服务器端预取每个项目,并在脚本运行前注入结果:
<script type="application/json" class="ka-livedata-manifest">
[{ "spItemUrl": "https://contoso.sharepoint.com/_api/v2.0/drives/{driveId}/items/{itemId}", "fileName": "data.csv" }]
</script>
在脚本运行前,主机会设置 window.__LD_RESULTS__,并以准确的 spItemUrl 为键。每个值的格式为 { format, content, error?, metadata }——读取 content(字符串),并检查 error。
需要特别注意但至关重要的事项:
- 每个项目都必须包含
fileName(含扩展名)——主机会据此选择csv/xlsx-sheets/text解码器。若缺少该字段,.xlsx文件将无法读取,.csv文件也不会按 csv 解析。 spItemUrl必须包含/drives/{driveId}/items/{itemId}(来源站点会被忽略,并根据查看者会话重新构建)。解析文件以获取这些 ID:GET /shares/{u!token}/driveItem→parentReference.driveId+id。- 刷新会重新加载你的 iframe,并提供最新数据——
postMessage({type:'ka-html-viewer-refresh'}, '*')(防抖 5 秒)。没有可供监听的传入“已更新”事件。 - 将内容视为不可信数据——使用
textContent构建 DOM,绝不要将其写入innerHTML。 - 限制:每页 32 个项目(超出限制时会丢弃所有结果),每个项目 50 MB;支持的格式:text、csv、xlsx-sheets、rows。
SharePoint 列表——清单项目也可以指向列表(kind:"list",包含 webUrl + listId,并可选填 select 指定内部列名称)。主机会在服务器端渲染该列表,并以 format:"rows" 注入——content 是 JSON 字符串 { headers, rows }(已扁平化;最多 100,000 行,截断时会设置非阻塞的 warning)。请在创作时通过 GET {webUrl}/_api/web/lists/getbytitle('{Name}')/fields?$select=InternalName,Title,TypeAsString(或 Graph /sites/{site-id}/lists/{list-id}/columns)解析 listId + 内部列名称。内部名称可能与显示标题不同(例如,“City” → Ciity)。参见 references/live-data.md。
完整协议 + 完整示例仪表板: references/live-data.md(也镜像在租户的 /_html/llms.txt 中)。仅含表格的入门模板:
assets/templates/livedata-dashboard.html。
还没有 HTML?从模板开始
如果用户想发布内容但还没有 HTML,请使用 assets/templates/ 中现成且符合 CSP 的模板,而不是手动编写:
| 模板 | 适用场景 |
|---|---|
dashboard.html | …构建独立的指标/状态仪表板(无外部数据)。 |
livedata-dashboard.html | …通过 LiveData 清单呈现实时 SharePoint 文件数据(csv/xlsx/text)。 |
livedata-list-dashboard.html | …呈现实时 SharePoint 列表(kind:"list" → format:"rows")——KPI、类别图表、表格。 |
读取选定的文件,将其中的 `` 占位内容替换为用户的实际内容,根据上述约定进行验证,然后发布。
第 1 步 — 编写(或填充)符合规范的 HTML
生成一个符合约定的独立 .html 文档。所有内容均内嵌;不引用外部内容;如需 SharePoint 数据,则添加 LiveData 清单。
步骤 2 — 获取访问令牌
发布时以用户身份进行身份验证。你需要一个 OAuth 2.0 bearer token(Azure AD)。
首选 — Microsoft Graph:
- 范围(委托):
Files.ReadWrite(写入用户自己的云端硬盘)。若要写入用户有权访问的其他库/站点,请使用Files.ReadWrite.All或Sites.ReadWrite.All。 - **获取方式:**通过 MSAL 使用用户身份获取(交互式、设备代码或现有的登录会话)。不要编造或硬编码令牌。如果你还没有 Graph 令牌,请运行 MSAL 流程 — 参见
references/api.md。
替代方案 — SharePoint Vroom(当 Agent 已通过 SharePoint OAuth 令牌完成接入时使用,例如加载项 / SPFx / on-behalf-of 流程):令牌的受众为 SharePoint 资源(https://{tenant}.sharepoint.com 或 -my.sharepoint.com),范围为 AllSites.Write / MyFiles.Write。使用相同的 driveItem 调用,但基 URL 不同。
完整的令牌流程、范围和许可说明见 references/api.md。
步骤 3 — 确认,然后发布
写入前先确认
首先对 HTML 运行 预检 — 运行 scripts/preflight.sh <file>;该脚本会搜索被禁止的 API,并检查 LiveData 清单项(文件项需要 spItemUrl + fileName;kind:"list" 项需要 spItemUrl + webUrl + listId)(最常见的问题是“无错误但页面空白”)。然后列出目标文件夹(GET …/children),检查是否有名称冲突,以便准确告知用户这是新建还是覆盖。
调用上传接口前,明确告知用户具体操作,并征得同意:
About to publish to SharePoint/OneDrive:
Account: [email protected]
Location: OneDrive › Documents/Agent HTML/
File: sales-dashboard.html
Action: Create new file (or: Overwrite existing file — REPLACES its contents)
Renders at: <webUrl>?web=1 (?web=1 opens the OneUp viewer; the bare webUrl downloads)
Proceed?
只有在用户明确同意后才能继续。覆盖时,必须明确说明此操作具有破坏性。
通过 Microsoft Graph 发布(首选)
简单上传(文件 ≤ 4 MB — 对内嵌 HTML 来说绰绰有余)。按路径创建新文件:
PUT https://graph.microsoft.com/v1.0/me/drive/root:/Agent HTML/<name>.html:/content
Authorization: Bearer <token>
Content-Type: text/html
<!DOCTYPE html> … your document …
响应 201 Created(新建)/ 200 OK(替换)→ 一个 driveItem。读取 webUrl,然后向用户提供 <webUrl>?web=1 — ?web=1 会在 OneUp 查看器中打开文件;单独的 webUrl 则会下载 .html 文件:
{
"id": "01ABC…",
"name": "sales-dashboard.html",
"size": 84213,
"webUrl": "https://contoso-my.sharepoint.com/personal/user_contoso_com/Documents/Agent%20HTML/sales-dashboard.html",
"file": { "mimeType": "text/html" }
}
对于 > 4 MB 的文件,请使用上传会话(createUploadSession)— 参见
references/api.md。
通过 SharePoint Vroom 发布(替代方案)
使用相同的请求格式、SharePoint 基 URL 和面向 SharePoint 的令牌。当你已有 SharePoint OAuth 令牌(SPFx / 加载项 / on-behalf-of)或想直接指定特定 SharePoint 主机或站点时,请使用此方式。(graph.microsoft.com 已会将个人云端硬盘上传请求路由到调用者所在的场区 — 包括 *.sharepoint-df.com 等内部测试环 — 因此通常只用 Graph 就足够了。)
PUT https://{tenant}-my.sharepoint.com/_api/v2.0/me/drive/root:/Agent HTML/<name>.html:/content
Authorization: Bearer <sharepoint-token>
Content-Type: text/html
<!DOCTYPE html> … your document …
返回相同的 driveItem(读取 webUrl)。完整详情(包括站点云端硬盘路径 /_api/v2.0/drives/{driveId}/items/{itemId}/content)见 references/api.md。
发布到 SharePoint 站点库(而不是 OneDrive)
对站点云端硬盘进行相同调用。使用 Graph(范围 Sites.ReadWrite.All):
PUT https://graph.microsoft.com/v1.0/sites/{site-id}/drive/root:/Agent HTML/<name>.html:/content
或使用 Vroom 针对站点主机调用:
PUT {siteUrl}/_api/v2.0/drive/root:/Agent HTML/<name>.html:/content
站点云端硬盘的根目录是其默认文档库(“Shared Documents”),因此路径应相对于根目录。使用 GET /sites/{host}:/sites/{path}(或 /teams/{path})解析 {site-id}。
通过文件夹 URL 发布 — 最少调用次数(Shares API)
如果你只有目标文件夹的 URL,可以跳过解析 drive/site ID 的步骤——将 URL 编码为共享令牌,然后直接上传到该文件夹:
- 编码:
u!+ 文件夹 URL 的无填充 base64url(base64,去掉=,将/替换为_,将+替换为-)。 GET /shares/{u!token}/driveItem→ 获取文件夹的id和parentReference.driveId(一次调用)。PUT /drives/{driveId}/items/{folderId}:/<name>.html:/content→ 上传。
总共调用 2 次,适用于任何 OneDrive、站点或库。详情请见
references/api.md;现成脚本:scripts/publish-to-folder.sh。
第 4 步 — 打开文件
向用户提供 <webUrl>?web=1(在响应中的 webUrl 后附加 ?web=1)。?web=1 会在 OneUp 查看器中渲染 HTML;直接使用 webUrl 则会下载 .html 文件。
webUrl 在更新后保持不变,因此修改文件后链接仍然有效。
更新 / 修改你创建的资源
要更改已发布的文件,请覆盖它——使用相同路径(或项目 ID)和相同调用:
PUT https://graph.microsoft.com/v1.0/me/drive/items/{item-id}/content
Authorization: Bearer <token>
Content-Type: text/html
<!DOCTYPE html> … updated document …
也可以按路径操作:PUT /me/drive/root:/Agent HTML/<name>.html:/content。
覆盖会替换文件内容——请先向用户确认(展示目标文件,并说明这会替换现有文件)。webUrl 保持不变。Vroom 的行为相同,只需使用其基础 URL。若要重命名 / 移动文件,而非替换内容,请使用 PATCH …/items/{item-id}
(请参见 references/api.md)。
错误代码
| 代码 | 含义 | 操作 |
|---|---|---|
401 | 未授权 | 令牌缺失 / 过期,或受众错误(Graph 与 SharePoint 不匹配)。使用正确的 scope 重新获取令牌。 |
403 | 禁止访问 | 令牌缺少写入 scope(Files.ReadWrite),或用户无权写入该位置。 |
404 | 未找到 | drive / 项目 / 路径错误,或父文件夹不存在(请先创建)。 |
413 | 负载过大 | 简单上传的文件超过 4 MB——请使用上传会话。 |
423 | 已锁定 | 项目已签出 / 锁定。 |
507 | 存储空间不足 | 用户的 drive 已满。 |
打开后页面空白 / 仅部分渲染 → 违反了创作约定(通常是使用了外部资源或运行时 fetch)。请重新检查约定。
参考资料
references/api.md— 完整的 Graph + Vroom 端点参考: 身份验证与 scope、令牌获取、请求 / 响应架构、上传会话、元数据更新,以及 driveItem 结构。references/contract.md— 完整的 OneUp 创作约定。assets/templates/— 可直接使用且符合 CSP 的模板。- 在线文档(权威版本,因租户而异):
https://<your-sharepoint-host>/_html,/_html/llms.txt、/_html/help.json。