The fetcher, fetch.mjs
On this page (6)
Kanboombo starts node fetch.mjs in your folder, writes the run context to its standard input, and reads records from its standard output. That is the whole protocol: files in, records out. The quickstart writes one in twenty lines.
The run context
Use today, the date in your zone, not now, the moment in UTC. Read each source at the path sources gives (under /sources/ on the Server, your fixture under check); never build one. Under check, now and today come from fixtures/context.json, and each fixtures/runs/<case> runs with backfill false.
PluginRunContext
What the fetcher reads on stdin. sources maps each declared source's name to a file it may read.
PluginSeriesContext
What is stored for one series before this run.
The rules it lives by
- •Date by today, never new Date(); nothing after it but a scheduled event.
- •Records on stdout, everything else on stderr, which readers never see; a failed run's last stderr line (at most 300 characters) is its reason.
- •Exit 0 when the file reads as expected, even with nothing new; exit 2 when it is not what you know (a renamed sheet, a missing column, a new status), with one line saying why. Nothing is written, and readers see it could not refresh: nothing beats something wrong.
- •Print the whole truth for your snapshot windows: a record you stop printing inside one is withdrawn after three runs. More costs only time; Kanboombo writes only what changed.
- •The same files give the same bytes: sort, and print no timestamps or random numbers. The Server runs your fixtures twice.
- •Stay in your folder. Import only your own files and node: modules. No network, database, keys or environment beyond the locale; only the files the digest covers are there. A run stops at 120 seconds and 256 MB, or your lower limits.
The publishing portal takes no dependencies: copy what you need into your folder as readable .mjs. (A plug-in in Kanboombo's own release may declare them in package.json with a package-lock.json.)
How far back to print
On the first run, print what backfillFrom allows; the first date is yours to keep. After that, print at least each series' snapshot window, and further back when its newest stored record is older, so days missed while runs failed are filled:
Read CSV, JSON and XLSX
Both examples carry their readers, MIT-0, to copy. Whatever the format, find columns by name, never position; stop on what you do not know; and convert nothing you need not: a date written 2026-10-01 stays that string, never passed through new Date().
- •CSV: Harbour Almanac's csv.mjs reads quotes, line breaks inside them, CRLF or LF and a byte-order mark, keys each row by its header, and refuses a file without the columns you need. Convert a decimal comma (1.234,5) or another encoding (new TextDecoder("windows-1252")) on purpose, and fail on what will not convert.
- •JSON: JSON.parse reads; check the shape before you trust it, and map the source's words to the contract's in one table (held to happened), failing on any word you have never seen.
- •XLSX: a workbook is a ZIP of XML. DOP Economy's xlsx.mjs reads the ZIP's directory, inflates the parts it needs with node:zlib, and returns one sheet as rows.
For a large file (up to 20 MB): read it once, keep only what you print, and print as you go.