Macotron

Globals

Plugins run in QuickJS, not in a browser or Node. A few web-style globals exist so that common code works. Everything else comes from macotron.*.

const last = localStorage.getItem("lastRun");
console.log("loaded, last run", last);
localStorage.setItem("lastRun", new Date().toISOString());

setTimeout(() => console.log("one second later"), 1000);

console

Each call joins its arguments with spaces and writes one line to the macOS log under subsystem io.statico.macotron and category plugin, with the plugin's file name in front. Objects go through JSON.stringify, so an Error prints as {}; log e.message instead.

console.log(...args: any[]): void

Writes at info level. The same as macotron.log.

console.info(...args: any[]): void

Writes at info level, like log. console.debug does the same.

console.warn(...args: any[]): void

Writes at notice level, which the system log keeps by default.

console.error(...args: any[]): void

Writes at error level.

There is no console.table, console.time, or console.assert. Info lines only show when you ask for them:

// In Terminal:
// log stream --level info --style compact --predicate 'subsystem == "io.statico.macotron" AND category == "plugin"'

Timers

Timers run on the main thread. Macotron cancels every timer when plugins reload. Each callback has 5 seconds to return before Macotron interrupts it.

setTimeout(callback: () => void, ms?: number): number

Runs callback once after ms milliseconds, and returns an id. The delay is rounded down to a whole number and is at least 1 ms. Extra arguments are not passed to the callback; use a closure.

setInterval(callback: () => void, ms: number): number

Runs callback every ms milliseconds, and returns an id. ms is required.

clearTimeout(id: number): void

clearInterval(id: number): void

Cancels a timer. The two are the same function, so either one cancels either kind of timer.

For schedules such as "every 5 minutes on the clock" or "at 07:30 on weekdays", use macotron.every and macotron.at. They also catch up after the Mac sleeps.

localStorage

A string key-value store that survives restarts. It is saved to data/localStorage.json in the Macotron folder after every change. All plugins share one store, so put a prefix on your keys, such as "layouts:work".

getItem(key: string): string | null

The stored string, or null when the key is absent.

setItem(key: string, value: string): void

Stores value as a string. Store objects with JSON.stringify and read them back with JSON.parse.

removeItem(key: string): void

Deletes one key.

clear(): void

Deletes every key, including the keys of other plugins.

Dialogs

alert(message?: any): void

confirm(message?: any): boolean

prompt(message?: any, defaultValue?: string): string | null

Browser-style dialogs, shown as a standard macOS alert. They block every plugin until the user answers. confirm returns true for OK. prompt returns the text for OK and null for Cancel. They are the same functions as macotron.alert, macotron.confirm, and macotron.prompt; see macotron (core).

Built into the JavaScript engine

QuickJS supplies the standard language: Promise and async/await, JSON, Map, Set, WeakRef, typed arrays, Proxy, RegExp, and Date. It also adds queueMicrotask, atob and btoa, and performance.now().

What is missing, and what to use instead

You might expectUse instead
fetch, XMLHttpRequestmacotron.http (get, post, put, delete, each a promise)
Node fs, pathmacotron.fs
Node child_processmacotron.shell.run
require, npm packagesNot available. Keep a plugin's code in its own file.
document, window, the DOMmacotron.panel, which hosts a real web page
Notificationmacotron.notify
Clipboard APImacotron.clipboard
Secret storagemacotron.keychain, or a "password" option in macotron.plugin()

There is also no process, Buffer, TextEncoder, TextDecoder, URL, crypto, structuredClone, or Intl.

See also