livelink v0.1.1 Released - Braced Expressions in Positron, Safer Decoding, and webR’s Link Format

livelink 0.1.1 fixes braced expressions run from Positron’s editor panel, stops a decoded link from writing outside the directory you named, and writes webR links as msgpack, the form webR’s own share button uses. Links you have already shared keep working.
software-releases
r-package
Author

James Balamuta

Published

August 1, 2026

livelink hex logo: a stack of code lines receding into the distance with an outbound arrow

livelink hex logo: a stack of code lines receding into the distance with an outbound arrow

livelink (GitHub, documentation) turns R code into a URL that runs it in the browser. There is no compute server. A static host still serves the page, webr.r-wasm.org or a localhost preview if you run your own, but nothing at the far end executes R. The reader’s browser does that, and the code travels in the part of the URL that browsers never send anywhere.

Version 0.1.1 is on CRAN, a week after 0.1.0. Three changes account for most of it:

Nothing already shared stops working. Links made by 0.1.0 still open, and still decode.

Positron names an unsaved buffer differently

Braced expressions failed in Positron. Not everywhere in Positron, which is what made it worth chasing. Put the code in an editor panel, press Run, and it failed outright:

link <- webr_repl_link({
  data(mtcars)
  plot(mtcars$mpg, mtcars$wt)
})
#> Error in if (grepl("^\\s*#", rescue_me)) ... : argument is of length zero

Type the same thing at the console and it worked.

Braces are the nicest way to hand code to livelink. No quotes to balance, no newlines to escape, and your editor keeps highlighting the code. They work because R attaches a source reference to whatever it parses, a note saying where the code came from, so the text can be read back later with the comments still in it.

That note is what differs between the two paths. Console code arrives with its text attached, so there is always something to read back. Editor code arrives with a name instead, and Positron calls an unsaved buffer untitled:Untitled-1. That is not a path. So the reference pointed at nothing readable, livelink asked for the source regardless, and got an error where it expected code. RStudio sends the text along with the reference, which is why the question never came up there.

Fixing that turned up three more ways a reference can outlive its source. A file shorter than the block it was parsed from. An empty { }. A file edited since the expression was read. All four now fall back to rebuilding the code from the expression itself, which loses the comments but never the code.

Smaller fixes

One theme runs through most of the rest. A link that looked fine when you built it and did nothing when you opened it is a miserable thing to debug from the far side of a URL, so the checks moved earlier. Several file paths handed to a single script, a file that is not valid UTF-8 or holds an embedded NUL, NA, and empty input now stop you where you build the link rather than where somebody else opens it.

The remainder, briefly:

  • A binary file in a link is written back as it was, not as text listing its byte values.
  • shinylive_directory() includes the .css and .js an app needs.
  • Links built against a webR site you host yourself can be read back, which the URL check used to refuse.
  • Several error messages name the value at fault instead of failing with missing value where TRUE/FALSE needed.

The news entry below has all of it, and every line that changed is in the v0.1.0 to v0.1.1 comparison.

Acknowledgements

Thanks to George Stagg for webR and its browser REPL, and to Winston Chang for the Shinylive share-URL feature. livelink writes the formats they built and opens in the runtimes they maintain. The msgpack change in this release is livelink catching up to what webR was already doing.

livelink news file entry for version 0.1.1

Security

  • decode_webr_link() and decode_shinylive_link() now refuse file names that escape output_dir, such as ../../.Rprofile. Names holding a subdirectory, like R/helpers.R, are unaffected.

Encoding

  • webR links now use msgpack rather than JSON, so a link ends in mz where it used to end in jz. This is the same form the webR share button writes. A one-line snippet comes out about 11% shorter, and links you have already shared keep working, since both forms still decode.

Bug fixes

  • webr_repl_link() now handles a braced expression whose code cannot be read back, which failed in an unsaved buffer in Positron, when the file was shorter than the expression, and when the block was empty. Where the code can be read its comments survive, and where it cannot the code is rebuilt without them.

  • webr_repl_link() and webr_repl_project() now refuse input that cannot become a script, rather than building a link that will not open. That covers several file paths given to a single script, a file that is not valid UTF-8 or holds an embedded NUL, NA, and empty input.

  • webr_repl_project() now warns when autorun_files names a file webR cannot run on opening, and print() marks the files that really do run.

  • decode_webr_link() writes a binary file back exactly as it was, rather than as text listing its byte values.

  • decode_webr_link() and preview_webr_link() now read links built against a webR site you host yourself, and report a malformed link when the ending of the link does not describe the code inside it.

  • shinylive_directory() now includes the .css and .js files an app needs, leaves out only files that cannot be read as text, and checks app_file.

  • link.only = TRUE no longer leaves an empty code block above the link.

Error messages

  • webr_repl_project() and shinylive_project() now explain a missing input instead of reporting the name of an internal variable.

  • Errors about an invalid argument now name the value at fault. NA given to version, panels, or mode failed with missing value where TRUE/FALSE needed, an invalid panels did not say which component was wrong, and NULL left a blank You provided: line.

  • preview_webr_link() and preview_shinylive_link() now keep the explanation from the underlying error rather than replacing it.

Documentation

  • Every help page now lists what a returned object holds, one entry at a time, rather than describing it only as an object with metadata.

References