Skip to main content

Parsing plugins with the Sandbox Runtime

Advanced feature for private plugins with large payloads.

Ryan Kulp avatar
Written by Ryan Kulp
Updated today

Private plugins enforce a maximum 100 kilobyte blob of data from external resources. Endpoints that respond with a larger payload will be rejected.

But it's not always possible to reduce a payload with request parameters alone. Introducing the transformer sandbox runtime.

Join the Beta

This feature is currently behind a feature flag. To give it a spin,

  1. Join TRMNL's Developer-only Discord (link on your Account tab).

  2. Add your Discord username to your Account > Discord field.

  3. Navigate to Discord > #plugins channel > Sandbox Beta thread.

Example use case

Create a private plugin that sometimes yields a large JSON object. As is, this plugin will soon go into a degraded state when the response is too large (> 100 kb).

Visit the Markup Editor > Transform tab and filter the payload with JavaScript (Node v22), returning a new object.

Wrap your logic with the transform() function like so:

function transform(input) {
return {
// parsed payload goes here
}
}

The input variable contains the complete original payload.

Trigger a force refresh from the plugin settings screen, then find your new payload object back inside the Markup Editor.

Benefits of using this sandbox

In addition to making otherwise disallowed plugin endpoints possible, the transformer() strategy can enhance your developer experience overall.

Cleaner code

If your plugin needs just a few bits of data but you find yourself traversing deeply nested nodes to find it, surfacing those values as top level JSON objects can simplify your plugin's markup.

Deeper functionality

TRMNL is committed to making Liquid templating a formidable tool in plugin development. But let's not pretend JavaScript isn't a lot more powerful. As plugins become more advanced we hope to reduce the learning curve with data parsing inside this sandbox versus alongside your markup.

Usage notes

  • The Node.js runtime lives inside an isolated-vm.

  • Execution timeout is capped at 1 second.

  • Internet access is disallowed -- sorry, no Underscore.js.

Troubleshooting

How to access other variables, e.g. {{ trmnl }} form field values?

The trmnl global variable node is available as input.trmnl. To leverage a custom form field value with keyname genre, for example:

function transform(input) {
let userFilter = input.trmnl.plugin_settings.custom_fields_values.genre;

return {
// parsed payload that leverages userFilter goes here
}
}

How can I debug my JavaScript?

We suggest retrieving a (large, realistic) payload independently of the TRMNL platform, then writing a parser separately. Enable debug logs for lightweight hints at what may be causing issues, for example a missing semi-colon. In the future we hope to expose more native JavaScript exceptions.

(JavaScript) Examples

Limiting the Size of an Array of Objects

Data

Inside Your Variables you have {{ actions }} (seen below), a top-level key in the JSON you are polling; it is an array of objects. There are other top-level keys in the JSON as well, but we only want to Transform this one and leave the rest untouched.

[
{
actionId: 1000
...
},
{
actionId: 1001
...
},
...
]

Transform

  • data is the name of the new object that will be present after the transform, aka {{ data }}.

  • ...input makes sure to include all other key:value pairs.

  • input.actions.slice(0, 30) returns only the first 30 entries in the array.

function transform(input) {
return {
data: {
...input,
actions: input.actions.slice(0, 30)
}
};
}

Removing a Property

Data

We want to Transform by removing the top-level property synonyms.

{
id: 12345,
word: "payload",
definition: {...},
examples: [{...},{...},{...}],
synonyms: [{...},{...},{...}],
metadata: {...}
}

Transform

  • data is the name of the new object that will be present after the transform, aka {{ data }}.

  • synonyms is extracted as its own variable, which is ignored.

  • ...newInput variable contains the remaining properties.

function transform(input) {
const {synonyms, ...newInput} = input;
return {
data: newInput
};
}

What's next?

JavaScript is the lingua franca of web development. Still you may prefer Ruby, its little brother Python, or Java. TRMNL is open to extending this sandbox to more runtimes (languages) to make plugin development feel native to developers of all technical backgrounds.

Did this answer your question?