Skip to content
ShiftPane
Documentation

Collectors

Code that runs on the PC on a timer, in a sandbox, and returns JSON.

A collector is the part of a widget that runs on the PC. The app calls it on a timer, and whatever JSON it returns goes to the phone for the view to draw. Widgets that only show PC data don't need one.

JavaScript
// collector.js: "is my PC busy?", from two sources and one config value
import { defineCollector } from '@shiftpane/widget-sdk'

export default defineCollector(({ sources, config }) => {
  const cpu = sources.cpu.percent ?? 0
  const memory = sources.memory.percent ?? 0
  return { busy: cpu > config.threshold || memory > config.threshold, cpu, memory }
})

What it gets

FieldWhat it is
sourcesA read-only snapshot of the system sources it declared
configThe user's settings for this widget
secretsThe secrets it declared, such as GITHUB_TOKEN
fetchA fetch that reaches only the hosts it declared
signalAborted when the run times out or the widget is removed
logWrites a line to the widget’s log

It returns plain JSON, which has to match what the view binds and is checked before it goes to the phone.

The sandbox

Collectors run in QuickJS compiled to WebAssembly, not in Node. There is no require, no file system, no processes, and no Electron.

LimitPer run
MemoryAbout 32 MB
Time10 seconds
Computing without a pause250 ms
Requests16
Output64 KB of JSON
A response it fetches2 MB, after at most 3 redirects

fetch is the app's, not the browser's:

  • A host has to match permissions.network, over HTTPS, or exactly match a permissions.local address and port.
  • For internet hosts, the app resolves the name first and refuses anything that lands on your own network: loopback, private, link-local and carrier-grade NAT addresses. A widget can't reach your router by pointing a public name at it.
  • Each redirect is checked again, as if the widget had asked for it.

Secrets are kept encrypted on the PC and only given to the widget that declared them.

One file, readable

collector.js is one ES module, at most 256 KB, and not minified, so a reviewer reads exactly what runs. The only thing it can import is defineCollector from @shiftpane/widget-sdk.