文档

卡片 CLI 命令

查找卡片类型,创建卡片,设置参数和实时数据,预览效果,并通过签名 webhook 从外部系统更新数据。

这里的每个命令都按 CLI 参考所述运行:全局标志、JSON 输出、退出代码、修订和重试。

卡片

浏览卡片类型,创建实例并更新其实时数据。播放列表放置返回的卡片 ID。

screenrig cards list --category ops
screenrig cards show gauge
screenrig card create --type gauge --file gauge-params.json
screenrig card list
screenrig card show crd_01EXAMPLEGAUGE000000000
screenrig card params crd_01EXAMPLEGAUGE000000000 --file gauge-params.json
screenrig card data get crd_01EXAMPLEGAUGE000000000
screenrig card data put crd_01EXAMPLEGAUGE000000000 --file gauge-data.json --ttl 30m --expect-rev 1
screenrig card preview crd_01EXAMPLEGAUGE000000000 --output gauge.png
screenrig card delete crd_01EXAMPLEGAUGE000000000
参数类型必填默认备注
cards list --tag TAGstring否无匹配目录标签。
cards list --category CATEGORYstring否无匹配目录类别。与 --tag 同用时,卡片必须同时匹配两者。
cards show <id>string是无来自 cards list 的目录卡片 ID,例如 gauge。
card create --type IDstring是无来自 cards list 的目录卡片 ID。
card create --major Ninteger否当前主版本固定目录的某个主版本。
card create --file FILE路径是无静态参数,最大 1 MiB 的 JSON 对象,或用 - 从 stdin 读取。
<id>string是无card show、card params、card delete 和 card data 接受的 crd_ 卡片 ID。
card params --file FILE路径是无新的静态参数,读取方式同 card create。它们立即替换旧参数。
card data put --file FILE路径是无数据文档,JSON 对象,或用 - 从 stdin 读取。它会替换整个文档。
card data put --ttl DURATIONstring否无经过这么长时间后清空数据,离线屏幕也包括在内:30m、12h 或 1d,范围从 1s 到 365d。不能与 --expires-at 同时使用。
card data put --expires-at INSTANTstring否无在此 ISO 8601 时间戳(带时区)清空数据。两个选项都不带的写入会清除原有的过期时间。
card data put --expect-rev REVISIONstring否无仅当数据仍处于此版本(由 card data get 显示)时才写入。过期的值会返回 revision_conflict(退出码 6)。
card preview <type|id>string是无目录中的卡片 ID,或 crd_ 卡片 ID,用于以该实例自己的参数和数据绘制它。
card preview --output FILE路径是无把 PNG 写到这里。会自动创建父目录。
card preview --params FILE路径否无静态属性,JSON 对象。
card preview --data FILE路径否无动态文档,JSON 对象。
card preview --feed FILE路径否无主机 feed 文档,JSON 对象。卡片需要而您省略的 feed 会被报告。
card preview --width PX / --height PXinteger否1920 / 1080图像尺寸,1 到 8192。
card preview --layout LAYOUTstring否fullfull、free、center、wide、header、footer、corner、chip 或 strip:要绘制的布局。
card preview --anchor ANCHORstring否无corner 或 chip 布局的角,或 strip 的边。
card preview --now ISOstring否当前时间将时钟冻结在此 ISO 8601 时刻。
card preview --timezone ZONEstring否本机的按此 IANA 时区绘制,例如 America/Vancouver。

cards show 会显示卡片的 params_schema 和 data_schema、静态与动态属性、层级、布局、feed,以及可复制到播放列表页面的示例。card create 返回实例的 crd_ ID;响应丢失后重新运行相同命令,会重用已保存的幂等键。

card data put 会立即替换文档,无需重新发布播放列表。卡片自身的校验会拒绝它无法显示的文档(card_data_invalid),到期后,若无人续期,所有屏幕上的数据都会清空。card delete 会删除该实例及其数据,只要有播放列表放置了它,就返回 resource_conflict(退出码 5)。

card preview 在本地 Chromium 或 Chrome 中绘制卡片并写出 PNG,不会发布任何内容。如果没有安装常见浏览器,请把 SCREENRIG_BROWSER 设为浏览器的路径。data.file 是写出的路径,data.unrendered 列出预览无法绘制的内容,例如您没有提供的主机 feed。发布前请先打开图片查看。内置卡片介绍每张卡片的布局、属性和 feed。

卡片 webhook

卡片 webhook 是写入一张卡片数据文档的 URL,因此 CMS、销售点或脚本等外部系统只需一次 HTTP POST 即可向卡片推送数据。kv webhook create、list、rotate-secret 和 delete 用 --card CARD_ID 代替 --app-id,二者不能同时使用;下方的 update 和 deliveries 仅适用于卡片。每张卡片最多有 20 个 webhook。

kv webhook create --card CARD_ID [--description TEXT] [--map FILE|-] [--key-template TEMPLATE] [--signing]
                  [--verify VENDOR [--verify-secret-file FILE|-] [--verify-header NAME] [--verify-encoding hex|base64]
                   [--verify-timestamp-header NAME] [--verify-tolerance SECONDS]] [--handshake VENDOR]
kv webhook list --card CARD_ID
kv webhook rotate-secret <webhook_id> --card CARD_ID [--signing]
kv webhook delete <webhook_id> --card CARD_ID

创建卡片 webhook 不需要键。--map FILE(或用于 stdin 的 -)是映射,--key-template 写入按键存储的文档,--signing 开启签名,--verify 和 --handshake 接受服务商自己的请求(服务商签名和握手)。响应包含 data.secret,如果 webhook 签名,还包含 data.signing_secret,各仅显示一次。

发送方的认证方式与应用 webhook 相同:使用 srkw_… 密钥的 Authorization: Bearer <secret>,或以 webhook ID 为用户名的 HTTP Basic,因此 https://kvw_ID:srkw_…@api.screenrig.ai/… 适合只能填写 URL 的发送方。请求体最大 1 MiB,为 JSON 或 application/x-www-form-urlencoded;重复的表单名会变成数组。没有映射时,发送的对象就是卡片的数据文档。

映射是一个 JSON 模板,用于根据请求体构建文档。包含占位符(如 {{body.alert.title}} 或 {{body.items[0].name}})的字符串是文本,恰好只有一个占位符的字符串会保留值的类型。路径以 body 或 query(URL 的查询参数)开头,不含任何内容的路径在文本中为空,单独出现时会省略该值。$each 映射数组,并提供 item 和 index,$group 配合 $by 按首次出现的顺序分组,$number 读取 1,234.50、$3.50、3,50 € 或 12%(逗号作小数点时添加 "$decimal": ","),$bool 读取 true、yes、y、1 和 x,$text 配合 $max 截断文本。模板在保存时检查:invalid_request 会指出失败的位置。

{
  "title": "{{body.alert.title}}",
  "body": "{{body.alert.message}}",
  "items": { "$each": "{{body.items}}", "$limit": 20, "$template": { "text": "{{item.name}}" } }
}
curl https://api.screenrig.ai/api/cards/crd_01EXAMPLEBOARD0000000000/kv-webhooks/kvw_01EXAMPLEWEBHOOK00000/write \
  -H "Authorization: Bearer $CARD_WEBHOOK_SECRET" \
  -H "Content-Type: application/json" \
  --data '{"alert":{"title":"Fire drill","message":"Leave by the east door"},"items":[{"name":"Floor 2"}]}'

--key-template TEMPLATE 以按键存储的文档取代卡片自己的文档。模板是带有 {screen.field.NAME} 令牌的卡片数据键,例如 room-{screen.field.room};映射后的对象(没有映射时为提交的正文)只包含由 {fields, document} 对象组成的 documents 数组:每个 fields 对象填充模板,每个 document 写入它所生成的键下。把同一模板作为 data 的页面项会让每个屏幕显示自己字段对应的文档。所有文档在写入任何一个之前都会先检查,重复的键会被拒绝。存储故障可能使一批文档只写入一部分:请用相同的正文和相同的 Idempotency-Key 重试。请求中省略的键保留原有数据,webhook 不设置过期时间。按键存储的文档展示了一个映射。

每次投递都会按卡片自己的数据检查:card_data_invalid 指出路径,且不写入任何内容。与卡片当前内容相同的文档会返回 unchanged 且不写入,因此不会唤醒任何屏幕。被接受的投递不计入智能体请求上限,一个 webhook 每分钟最多接受 120 次投递,Idempotency-Key 标头会对发送方的重试去重 24 小时。

错误的地址、错误或缺失的密钥、已停用的 webhook、缺失或错误的签名以及每个 GET 都得到相同的 404 响应,因此链接预览或猜测不会泄露任何信息。kv webhook deliveries 会说明原因。

使用 --signing 时,每次发送还必须携带 ScreenRig-Signature: t=<unix seconds>,v1=<hex>,其中 v1 是 t、一个点和原始请求体在签名密钥 whsec_… 下的 HMAC-SHA256,且 t 必须在服务器时钟的五分钟以内。这是 screenRIG 自身 webhook 签名的格式。

服务商签名和握手

服务商各自用自己的方式给请求签名,有些根本无法发送您的密钥。卡片 webhook 可以用服务商的签名代替密钥来验证,并响应服务商的设置握手,因此 GitHub、Stripe、Shopify、Slack、Linear、Vercel、Asana、Microsoft Graph、monday.com、Trello 和 Azure Event Grid 可以直接向它发送,无需中转。其他任何用 HMAC 签名的发送方同样可用。用 kv webhook create 配合 --verify 和 --handshake 进行设置,用 kv webhook update 进行更改。

  • --verify VENDOR 接受服务商自己的签名,--verify-secret-file FILE(用于 stdin 时为 -,不能作为参数)保存服务商显示的密钥。对于 generic_hmac,--verify-header NAME 指定携带签名的请求头,--verify-encoding 为 hex(默认)或 base64,--verify-timestamp-header NAME 指定携带 Unix 时间的请求头,--verify-tolerance SECONDS 表示该时间与服务器时钟的最大偏差(默认 300)。带有服务商有效签名的请求会被接受,无需 webhook 自己的 srkw_ 密钥,该密钥仍可并行使用。服务商密钥加密封存,只显示为 set 和其最后四个字符的 hint。在 kv webhook update 中,不带 --verify-secret-file 的 --verify 会在服务商不变时保留已存储的密钥,--clear-verify 会移除验证及其密钥。--verify 和 --signing 互相排斥。
  • --handshake VENDOR 是 microsoft_graph、monday、trello 或 azure_event_grid,--clear-handshake 会将其移除。Slack 和 Asana 通过 --verify 响应各自的握手。
--verify标题签名的内容时间戳
githubX-Hub-Signature-256正文的 HMAC-SHA256无
stripeStripe-Signature时间戳、一个点和正文的 HMAC-SHA256;任何一个 v1 匹配即可5 分钟
shopifyX-Shopify-Hmac-Sha256正文的 HMAC-SHA256,base64 编码无
slackX-Slack-Signaturev0:、时间戳、一个冒号和正文的 HMAC-SHA256X-Slack-Request-Timestamp,5 分钟
linearLinear-Signature正文的 HMAC-SHA256正文中的 webhookTimestamp,1 分钟
vercelx-vercel-signature正文的 HMAC-SHA1无
asanaX-Hook-Signature以握手的 X-Hook-Secret 为密钥的正文 HMAC-SHA256无
generic_hmac您指定的 --verify-header正文的 HMAC-SHA256;设置了 --verify-timestamp-header 时则是时间戳、一个点和正文的 HMAC-SHA256--verify-tolerance

每个 HMAC 的密钥都是服务商所显示的密钥文本(Stripe 的包含 whsec_)。签名按正文到达时的原样以恒定时间验证,并在请求消耗写入额度之前完成,而且先于其时间戳进行判断:timestamp_stale 始终表示密钥是正确的。正文可以是 JSON、表单或 multipart/form-data,其中文本字段为 body.FIELD,文件只计数、不读取。

服务商screenRIG 的响应后续请求
Slack(--verify slack)带有其 challenge 的已签名 url_verification;用 curl 测试的人可以改为发送 webhook 的密钥用签名密钥签名
Asana(--verify asana)握手的 X-Hook-Secret,它会加密封存并作为每个 X-Hook-Signature 的密钥。再次收到相同的密钥视为重试;不同的密钥会被拒绝,并返回 handshake_invalidX-Hook-Signature
Microsoft Graph(--handshake microsoft_graph)将解码后的 ?validationToken= 作为 text/plain 返回携带 webhook 的密钥
monday.com(--handshake monday)它发送的 challenge,以 JSON 原样返回携带 webhook 的密钥
Trello(--handshake trello)HEAD 检查仅针对此 webhook,返回 200 且不带正文携带 webhook 的密钥
Azure Event Grid(--handshake azure_event_grid){"validationResponse": "CODE"}携带 webhook 的密钥

握手只会针对为该服务商设置的 webhook 响应,在要求任何凭据之前,针对属于该握手的请求,并且已停用的 webhook 绝不会响应。它不写入任何内容,从不计费,也不消耗速率额度。Microsoft Graph、monday.com、Trello 和 Azure Event Grid 不发送 screenRIG 验证的请求头,因此它们的投递只有携带 webhook 的密钥才会被接受。Azure Event Grid 把它作为标记为机密的静态投递头 Authorization: Bearer srkw_… 携带,其事件以数组形式到达,所以映射读取 body[0]。

服务商在服务商的设置中
GitHubSettings、Webhooks、Add webhook:Payload URL 填 webhook 的 url,内容类型填 application/json,密钥相同。GitHub 的 ping 带有签名,会被接受
StripeWorkbench、Webhooks:添加 url 并显示其签名密钥。Stripe 轮换密钥期间会为每个密钥发送一个 v1,任一个都会被接受;之后用 kv webhook update --verify stripe --verify-secret-file FILE 替换已存储的密钥
Shopify用 url 以 JSON 格式订阅。密钥是应用的客户端密钥
SlackEvents API 的 Request URL 是 url,密钥是应用的签名密钥。斜杠命令会发送表单:{{body.text}}、{{body.user_name}}
Linear在 API 设置中用 url 创建 webhook,并复制其签名密钥。正文中的 webhookTimestamp 必须与服务器时钟相差不超过一分钟
VercelTeam settings、Webhooks:用 url 创建一个。Vercel 只会显示一次密钥
Asana用 --verify asana 创建 webhook:它还没有密钥,会以 secret_pending 拒绝事件。然后创建 Asana webhook,把 target 设为 url,握手会设置密钥。要换用新密钥,先带 --clear-verify 运行 kv webhook update,再用 --verify asana 重新设置
Microsoft Graph创建订阅,把 notificationUrl 设为 url
monday.com用 url 运行 create_webhook
TrelloPOST /1/webhooks,把 callbackURL 设为 url
Azure Event Grid创建事件订阅,把 url 作为其 webhook 端点,并添加上面的投递头
echo '{"title":"{{body.repository.full_name}}","body":"{{body.head_commit.message}}"}' |
  screenrig kv webhook create --card crd_01EXAMPLEBOARD0000000000 --description "Pushes" \
    --verify github --verify-secret-file github.secret --map -

用自己的 HMAC 签名的发送方,需要指定请求头、编码,如果签名时间戳,还要指定时间戳请求头:

echo '{"title":"{{body.sensor}}","body":"{{body.state}}"}' |
  screenrig kv webhook create --card crd_01EXAMPLEBOARD0000000000 --verify generic_hmac --verify-secret-file acme.secret \
    --verify-header X-Acme-Signature --verify-encoding base64 --verify-timestamp-header X-Acme-Time --verify-tolerance 120 \
    --map -
ts=$(date +%s); body='{"sensor":"door","state":"open"}'
sig=$(printf '%s.%s' "$ts" "$body" | openssl dgst -sha256 -hmac "$SECRET" -binary | openssl base64 -A)
curl "$URL" -H "Content-Type: application/json" -H "X-Acme-Time: $ts" -H "X-Acme-Signature: $sig" -d "$body"

每次失败都和其他任何拒绝返回相同的 404。kv webhook deliveries 会显示原因,握手的结果显示为 handshake:

原因含义
signature_missing已设置服务商验证,而请求既没有携带密钥,也没有携带服务商的请求头
signature_invalid请求头格式错误,或与正文不匹配
timestamp_missing签名需要时间戳,而请求没有携带
timestamp_stale签名有效,但其时间戳超出时间窗口
secret_pendingAsana 的验证仍在等待其握手
handshake_invalid该请求是某个服务商的握手,无法响应

kv webhook update#

更改卡片 webhook:其描述、映射、按键存储的文档、启用状态、签名、服务商验证或握手。

kv webhook update <webhook_id> --card CARD_ID [--description TEXT] [--map FILE|-] [--clear-map]
                   [--key-template TEMPLATE] [--clear-key-template] [--enable|--disable] [--signing|--no-signing]
                   [--verify VENDOR [--verify-secret-file FILE|-] [--verify-header NAME] [--verify-encoding hex|base64]
                    [--verify-timestamp-header NAME] [--verify-tolerance SECONDS]] [--clear-verify]
                   [--handshake VENDOR] [--clear-handshake]
参数类型必填默认备注
<webhook_id>string是无kvw_ Webhook ID。
--card CARD_IDstring是无crd_ 卡片 ID。
--description TEXTstring否无向它发送内容的系统,最多 200 字节。不得包含凭证。
--map FILE路径否无用从文件读取的 JSON 对象替换映射,或用 - 从 stdin 读取。不能与 --clear-map 同时使用。
--clear-mapboolean否关闭移除映射:发送的对象即成为文档。
--key-template TEMPLATEstring否无设置为文档生成键的键模板,例如 room-{screen.field.room}。不能与 --clear-key-template 同时使用。
--clear-key-templateboolean否关闭恢复为写入卡片自己的文档。
--enable / --disableboolean否关闭在使用 --enable 之前,--disable 对每次发送的响应都与错误密钥相同。
--signing / --no-signingboolean否关闭--signing 要求带签名请求头,并仅显示一次签名密钥;已经签名的 webhook 保留其密钥,用 kv webhook rotate-secret --signing 替换。--no-signing 不再要求。不能与 --verify 同时使用。
--verify VENDORstring否无替换服务商验证:github、stripe、shopify、slack、linear、vercel、asana 或 generic_hmac。不带 --verify-secret-file 时,若服务商不变则保留已存储的密钥,因此可单独更改请求头或时间窗口;换用其他服务商则需提供它自己的密钥。不能与 --clear-verify 同时使用。
--verify-secret-file FILE路径否已存储的密钥从文件读取服务商的密钥,或用 - 从 stdin 读取(不能作为参数)。asana 不需要密钥。只有一个选项可以读取 stdin。
--verify-header NAMEstring配合 generic_hmac无携带签名的请求头,1 到 100 个字母、数字、- 或 _。
--verify-encoding ENCODINGstring否hex配合 generic_hmac:hex 或 base64;可以以 sha256= 开头。
--verify-timestamp-header NAMEstring否无配合 generic_hmac:携带 Unix 时间的请求头,单位为秒,或为 13 位数字的毫秒。
--verify-tolerance SECONDSinteger否300配合 --verify-timestamp-header:时间戳与服务器时钟的最大偏差,1 到 86400。
--clear-verifyboolean否关闭不再接受服务商的签名,并清除其密钥。Asana 验证只有在先 --clear-verify、再次 --verify asana 之后才会接受新的握手。
--handshake VENDORstring否无设置 URL 所响应的握手:microsoft_graph、monday、trello 或 azure_event_grid。不能与 --clear-handshake 同时使用。
--clear-handshakeboolean否关闭不再响应服务商的握手。

至少需要一项更改。

screenrig kv webhook update kvw_01EXAMPLEWEBHOOK00000 --card crd_01EXAMPLEBOARD0000000000 --map alert-map.json
screenrig kv webhook update kvw_01EXAMPLEWEBHOOK00000 --card crd_01EXAMPLEBOARD0000000000 --verify stripe --verify-secret-file stripe.secret
screenrig kv webhook update kvw_01EXAMPLEWEBHOOK00000 --card crd_01EXAMPLEBOARD0000000000 --clear-verify

信封就是该 webhook。data.signing_secret 只在开启签名的那次响应中出现一次。更新被中断或结果不明时,请再次运行相同的命令:它会重用已保存的幂等键。

kv webhook deliveries#

读取卡片 webhook 过去七天的投递日志,最新的在前。

kv webhook deliveries <webhook_id> --card CARD_ID [--limit N]
参数类型必填默认备注
<webhook_id>string是无kvw_ Webhook ID。
--card CARD_IDstring是无crd_ 卡片 ID。
--limit Nnumber否100返回多少条投递记录,1 到 100。
screenrig kv webhook deliveries kvw_01EXAMPLEWEBHOOK00000 --card crd_01EXAMPLEBOARD0000000000

每一项包含 at、outcome(written、unchanged、refused、invalid 或 handshake)、reason(credentials、signature(表示 ScreenRig-Signature 失败)、disabled、body、mapping、card_data_invalid、rate_limited、internal,或上表中的服务商原因)、detail、status、bytes、files(multipart 请求中的文件部分,会被忽略)、revision 和 request_id。不会存储正文、请求头或凭据,向错误地址发送的请求不会留下任何记录。

其他命令组