FleekSiteFLEEKSITE
On this section
Plugins and the runtime

Building a plugin.

A plugin exports one function per hook. Inside those functions it uses the fs object to log, fetch, read and write data, or schedule work. This page is the shape of the code, the tools around it, and the rules the sandbox enforces.

The shape of the code

Export a handler for each hook the plugin declares. A handler takes the hook input and returns the value the pipeline expects (see Hooks).

module.exports = {
  pre_render: async (input) => {
    // read the site's three newest events and expose them to the template
    const res = await fs.collection('events').list({ limit: 3, order: 'inserted_at desc' })
    return { upcoming_events: res.items }
  },

  post_render: (input) => {
    // add a banner to the finished page
    return input.html.replace('', '
Open late Friday
'
) } }

The host APIs

CallNotes
fs.log(level, msg, meta)Writes to the server log. Shows up in the plugin's invocation logs.
fs.fetch(url, init)An outbound request. The host must be on allowed_hosts; internal and metadata addresses are blocked; the timeout is five seconds.
fs.collection(name).list(params)Reads records, the same sources and filters as the collection tag.
fs.collection(name).get(uid)Reads one record.
fs.collection(name).create / update / delete / actionWrites, gated by the matching grant and the plugin's role.
fs.schedule.at / cancel / listSchedules a later callback, for a plugin on the scheduled hook.

Each data call is checked against the plugin's grants and role cap. A call the plugin is not allowed to make fails rather than silently doing nothing.

Limits and the sandbox rules

  • Each run has a time budget (timeout_ms, default 200, up to 5000) and a memory cap (memory_mb, default 32, up to 256).
  • The code may not contain eval, the Function constructor, setTimeout, setInterval, require, process or reflection into the global constructor. Saving such code is rejected.
  • There is no ambient network, filesystem or process access. Only the fs object.
  • Inputs are plain serialisable data; a handler cannot reach back into the request through them.

Testing and logs

Two endpoints help you develop, both requiring role 3 or higher on the site (see Authentication and roles):

EndpointPurpose
POST /api/v1/plugins/:uid/testRuns one hook against a sample input and returns { ok, result, error, duration_ms, timed_out }.
GET /api/v1/plugins/:uid/logsThe recent invocations (up to fifty) and a derived health summary.

The test endpoint runs the real plugin, not a mock. If your handler calls fs.collection(...).create or .update, testing it writes to real data. Test read-only paths freely; be deliberate with writes.

Versioning

A plugin has a version that bumps whenever you change anything that affects how it runs: the code, its hooks, its allowed hosts, its permissions, its role cap, its enabled state, or its limits. Renaming it does not bump the version. The bump matters because the platform runs on more than one server, each caching the compiled sandbox by version. Bumping the version is what makes every server pick up the change at once, so a revoked grant or a disabled plugin takes effect everywhere immediately. The management API handles this for you; you do not set the version by hand.