@georgestagg/webr
Version:
The statistical programming langauge R compiled into WASM for use in a web browser and node.
1,531 lines (1,519 loc) • 80.3 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJS = (cb, mod) => function __require() {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod));
var __accessCheck = (obj, member, msg) => {
if (!member.has(obj))
throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
__accessCheck(obj, member, "read from private field");
return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
if (member.has(obj))
throw TypeError("Cannot add the same private member more than once");
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};
var __privateSet = (obj, member, value, setter) => {
__accessCheck(obj, member, "write to private field");
setter ? setter.call(obj, value) : member.set(obj, value);
return value;
};
var __privateMethod = (obj, member, method) => {
__accessCheck(obj, member, "access private method");
return method;
};
// node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js
var require_XMLHttpRequest = __commonJS({
"node_modules/xmlhttprequest-ssl/lib/XMLHttpRequest.js"(exports, module2) {
var fs = require("fs");
var Url = require("url");
var spawn = require("child_process").spawn;
module2.exports = XMLHttpRequest2;
XMLHttpRequest2.XMLHttpRequest = XMLHttpRequest2;
function XMLHttpRequest2(opts) {
"use strict";
opts = opts || {};
var self = this;
var http = require("http");
var https = require("https");
var request;
var response;
var settings = {};
var disableHeaderCheck = false;
var defaultHeaders = {
"User-Agent": "node-XMLHttpRequest",
"Accept": "*/*"
};
var headers = Object.assign({}, defaultHeaders);
var forbiddenRequestHeaders = [
"accept-charset",
"accept-encoding",
"access-control-request-headers",
"access-control-request-method",
"connection",
"content-length",
"content-transfer-encoding",
"cookie",
"cookie2",
"date",
"expect",
"host",
"keep-alive",
"origin",
"referer",
"te",
"trailer",
"transfer-encoding",
"upgrade",
"via"
];
var forbiddenRequestMethods = [
"TRACE",
"TRACK",
"CONNECT"
];
var sendFlag = false;
var errorFlag = false;
var abortedFlag = false;
var listeners = {};
this.UNSENT = 0;
this.OPENED = 1;
this.HEADERS_RECEIVED = 2;
this.LOADING = 3;
this.DONE = 4;
this.readyState = this.UNSENT;
this.onreadystatechange = null;
this.responseText = "";
this.responseXML = "";
this.response = Buffer.alloc(0);
this.status = null;
this.statusText = null;
var isAllowedHttpHeader = function(header) {
return disableHeaderCheck || header && forbiddenRequestHeaders.indexOf(header.toLowerCase()) === -1;
};
var isAllowedHttpMethod = function(method) {
return method && forbiddenRequestMethods.indexOf(method) === -1;
};
this.open = function(method, url, async, user, password) {
this.abort();
errorFlag = false;
abortedFlag = false;
if (!isAllowedHttpMethod(method)) {
throw new Error("SecurityError: Request method not allowed");
}
settings = {
"method": method,
"url": url.toString(),
"async": typeof async !== "boolean" ? true : async,
"user": user || null,
"password": password || null
};
setState(this.OPENED);
};
this.setDisableHeaderCheck = function(state) {
disableHeaderCheck = state;
};
this.setRequestHeader = function(header, value) {
if (this.readyState != this.OPENED) {
throw new Error("INVALID_STATE_ERR: setRequestHeader can only be called when state is OPEN");
}
if (!isAllowedHttpHeader(header)) {
console.warn('Refused to set unsafe header "' + header + '"');
return false;
}
if (sendFlag) {
throw new Error("INVALID_STATE_ERR: send flag is true");
}
headers[header] = value;
return true;
};
this.getResponseHeader = function(header) {
if (typeof header === "string" && this.readyState > this.OPENED && response.headers[header.toLowerCase()] && !errorFlag) {
return response.headers[header.toLowerCase()];
}
return null;
};
this.getAllResponseHeaders = function() {
if (this.readyState < this.HEADERS_RECEIVED || errorFlag) {
return "";
}
var result = "";
for (var i in response.headers) {
if (i !== "set-cookie" && i !== "set-cookie2") {
result += i + ": " + response.headers[i] + "\r\n";
}
}
return result.substr(0, result.length - 2);
};
this.getRequestHeader = function(name) {
if (typeof name === "string" && headers[name]) {
return headers[name];
}
return "";
};
this.send = function(data) {
if (this.readyState != this.OPENED) {
throw new Error("INVALID_STATE_ERR: connection must be opened before send() is called");
}
if (sendFlag) {
throw new Error("INVALID_STATE_ERR: send has already been called");
}
var ssl = false, local = false;
var url = Url.parse(settings.url);
var host;
switch (url.protocol) {
case "https:":
ssl = true;
case "http:":
host = url.hostname;
break;
case "file:":
local = true;
break;
case void 0:
case "":
host = "localhost";
break;
default:
throw new Error("Protocol not supported.");
}
if (local) {
if (settings.method !== "GET") {
throw new Error("XMLHttpRequest: Only GET method is supported");
}
if (settings.async) {
fs.readFile(unescape(url.pathname), function(error, data2) {
if (error) {
self.handleError(error, error.errno || -1);
} else {
self.status = 200;
self.responseText = data2.toString("utf8");
self.response = data2;
setState(self.DONE);
}
});
} else {
try {
this.response = fs.readFileSync(unescape(url.pathname));
this.responseText = this.response.toString("utf8");
this.status = 200;
setState(self.DONE);
} catch (e) {
this.handleError(e, e.errno || -1);
}
}
return;
}
var port = url.port || (ssl ? 443 : 80);
var uri = url.pathname + (url.search ? url.search : "");
headers["Host"] = host;
if (!(ssl && port === 443 || port === 80)) {
headers["Host"] += ":" + url.port;
}
if (settings.user) {
if (typeof settings.password == "undefined") {
settings.password = "";
}
var authBuf = new Buffer(settings.user + ":" + settings.password);
headers["Authorization"] = "Basic " + authBuf.toString("base64");
}
if (settings.method === "GET" || settings.method === "HEAD") {
data = null;
} else if (data) {
headers["Content-Length"] = Buffer.isBuffer(data) ? data.length : Buffer.byteLength(data);
if (!headers["Content-Type"]) {
headers["Content-Type"] = "text/plain;charset=UTF-8";
}
} else if (settings.method === "POST") {
headers["Content-Length"] = 0;
}
var agent = opts.agent || false;
var options = {
host,
port,
path: uri,
method: settings.method,
headers,
agent
};
if (ssl) {
options.pfx = opts.pfx;
options.key = opts.key;
options.passphrase = opts.passphrase;
options.cert = opts.cert;
options.ca = opts.ca;
options.ciphers = opts.ciphers;
options.rejectUnauthorized = opts.rejectUnauthorized === false ? false : true;
}
errorFlag = false;
if (settings.async) {
var doRequest = ssl ? https.request : http.request;
sendFlag = true;
self.dispatchEvent("readystatechange");
var responseHandler = function(resp2) {
response = resp2;
if (response.statusCode === 302 || response.statusCode === 303 || response.statusCode === 307) {
settings.url = response.headers.location;
var url2 = Url.parse(settings.url);
host = url2.hostname;
var newOptions = {
hostname: url2.hostname,
port: url2.port,
path: url2.path,
method: response.statusCode === 303 ? "GET" : settings.method,
headers
};
if (ssl) {
newOptions.pfx = opts.pfx;
newOptions.key = opts.key;
newOptions.passphrase = opts.passphrase;
newOptions.cert = opts.cert;
newOptions.ca = opts.ca;
newOptions.ciphers = opts.ciphers;
newOptions.rejectUnauthorized = opts.rejectUnauthorized === false ? false : true;
}
request = doRequest(newOptions, responseHandler).on("error", errorHandler);
request.end();
return;
}
setState(self.HEADERS_RECEIVED);
self.status = response.statusCode;
response.on("data", function(chunk) {
if (chunk) {
var data2 = Buffer.from(chunk);
self.responseText += data2.toString("utf8");
self.response = Buffer.concat([self.response, data2]);
}
if (sendFlag) {
setState(self.LOADING);
}
});
response.on("end", function() {
if (sendFlag) {
sendFlag = false;
setState(self.DONE);
}
});
response.on("error", function(error) {
self.handleError(error);
});
};
var errorHandler = function(error) {
self.handleError(error);
};
request = doRequest(options, responseHandler).on("error", errorHandler);
if (opts.autoUnref) {
request.on("socket", (socket) => {
socket.unref();
});
}
if (data) {
request.write(data);
}
request.end();
self.dispatchEvent("loadstart");
} else {
var contentFile = ".node-xmlhttprequest-content-" + process.pid;
var syncFile = ".node-xmlhttprequest-sync-" + process.pid;
fs.writeFileSync(syncFile, "", "utf8");
var execString = "var http = require('http'), https = require('https'), fs = require('fs');var doRequest = http" + (ssl ? "s" : "") + ".request;var options = " + JSON.stringify(options) + ";var responseText = '';var responseData = Buffer.alloc(0);var req = doRequest(options, function(response) {response.on('data', function(chunk) { var data = Buffer.from(chunk); responseText += data.toString('utf8'); responseData = Buffer.concat([responseData, data]);});response.on('end', function() {fs.writeFileSync('" + contentFile + "', JSON.stringify({err: null, data: {statusCode: response.statusCode, headers: response.headers, text: responseText, data: responseData.toString('base64')}}), 'utf8');fs.unlinkSync('" + syncFile + "');});response.on('error', function(error) {fs.writeFileSync('" + contentFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('" + syncFile + "');});}).on('error', function(error) {fs.writeFileSync('" + contentFile + "', 'NODE-XMLHTTPREQUEST-ERROR:' + JSON.stringify(error), 'utf8');fs.unlinkSync('" + syncFile + "');});" + (data ? "req.write('" + JSON.stringify(data).slice(1, -1).replace(/'/g, "\\'") + "');" : "") + "req.end();";
var syncProc = spawn(process.argv[0], ["-e", execString]);
var statusText;
while (fs.existsSync(syncFile)) {
}
self.responseText = fs.readFileSync(contentFile, "utf8");
syncProc.stdin.end();
fs.unlinkSync(contentFile);
if (self.responseText.match(/^NODE-XMLHTTPREQUEST-ERROR:/)) {
var errorObj = JSON.parse(self.responseText.replace(/^NODE-XMLHTTPREQUEST-ERROR:/, ""));
self.handleError(errorObj, 503);
} else {
self.status = self.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:([0-9]*),.*/, "$1");
var resp = JSON.parse(self.responseText.replace(/^NODE-XMLHTTPREQUEST-STATUS:[0-9]*,(.*)/, "$1"));
response = {
statusCode: self.status,
headers: resp.data.headers
};
self.responseText = resp.data.text;
self.response = Buffer.from(resp.data.data, "base64");
setState(self.DONE, true);
}
}
};
this.handleError = function(error, status) {
this.status = status || 0;
this.statusText = error;
this.responseText = error.stack;
errorFlag = true;
setState(this.DONE);
};
this.abort = function() {
if (request) {
request.abort();
request = null;
}
headers = Object.assign({}, defaultHeaders);
this.responseText = "";
this.responseXML = "";
this.response = Buffer.alloc(0);
errorFlag = abortedFlag = true;
if (this.readyState !== this.UNSENT && (this.readyState !== this.OPENED || sendFlag) && this.readyState !== this.DONE) {
sendFlag = false;
setState(this.DONE);
}
this.readyState = this.UNSENT;
};
this.addEventListener = function(event, callback) {
if (!(event in listeners)) {
listeners[event] = [];
}
listeners[event].push(callback);
};
this.removeEventListener = function(event, callback) {
if (event in listeners) {
listeners[event] = listeners[event].filter(function(ev) {
return ev !== callback;
});
}
};
this.dispatchEvent = function(event) {
if (typeof self["on" + event] === "function") {
if (this.readyState === this.DONE && settings.async)
setImmediate(function() {
self["on" + event]();
});
else
self["on" + event]();
}
if (event in listeners) {
for (let i = 0, len = listeners[event].length; i < len; i++) {
if (this.readyState === this.DONE)
setImmediate(function() {
listeners[event][i].call(self);
});
else
listeners[event][i].call(self);
}
}
};
var setState = function(state) {
if (self.readyState === state || self.readyState === self.UNSENT && abortedFlag)
return;
self.readyState = state;
if (settings.async || self.readyState < self.OPENED || self.readyState === self.DONE) {
self.dispatchEvent("readystatechange");
}
if (self.readyState === self.DONE) {
let fire;
if (abortedFlag)
fire = "abort";
else if (errorFlag)
fire = "error";
else
fire = "load";
self.dispatchEvent(fire);
self.dispatchEvent("loadend");
}
};
}
}
});
// webR/compat.ts
var IN_NODE = typeof process !== "undefined" && process.release && process.release.name === "node" && typeof process.browser === "undefined";
var loadScript;
if (globalThis.document) {
loadScript = (url) => new Promise((resolve, reject) => {
const script = document.createElement("script");
script.src = url;
script.onload = () => resolve();
script.onerror = reject;
document.head.appendChild(script);
});
} else if (globalThis.importScripts) {
loadScript = async (url) => {
try {
globalThis.importScripts(url);
} catch (e) {
if (e instanceof TypeError) {
await Promise.resolve().then(() => __toESM(require(url)));
} else {
throw e;
}
}
};
} else if (IN_NODE) {
loadScript = async (url) => {
const nodePathMod = (await Promise.resolve().then(() => __toESM(require("path")))).default;
await Promise.resolve().then(() => __toESM(require(nodePathMod.resolve(url))));
};
} else {
throw new Error("Cannot determine runtime environment");
}
// webR/chan/queue.ts
var _promises, _resolvers, _add, add_fn;
var AsyncQueue = class {
constructor() {
__privateAdd(this, _add);
__privateAdd(this, _promises, void 0);
__privateAdd(this, _resolvers, void 0);
__privateSet(this, _resolvers, []);
__privateSet(this, _promises, []);
}
put(t) {
if (!__privateGet(this, _resolvers).length) {
__privateMethod(this, _add, add_fn).call(this);
}
const resolve = __privateGet(this, _resolvers).shift();
resolve(t);
}
async get() {
if (!__privateGet(this, _promises).length) {
__privateMethod(this, _add, add_fn).call(this);
}
const promise = __privateGet(this, _promises).shift();
return promise;
}
isEmpty() {
return !__privateGet(this, _promises).length;
}
isBlocked() {
return !!__privateGet(this, _resolvers).length;
}
get length() {
return __privateGet(this, _promises).length - __privateGet(this, _resolvers).length;
}
};
_promises = new WeakMap();
_resolvers = new WeakMap();
_add = new WeakSet();
add_fn = function() {
__privateGet(this, _promises).push(new Promise((resolve) => {
__privateGet(this, _resolvers).push(resolve);
}));
};
// webR/utils.ts
function promiseHandles() {
const out = {
resolve: (_value) => {
},
reject: (_reason) => {
},
promise: null
};
const promise = new Promise((resolve, reject) => {
out.resolve = resolve;
out.reject = reject;
});
out.promise = promise;
return out;
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
function replaceInObject(obj, test, replacer, ...replacerArgs) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (test(obj)) {
return replacer(obj, ...replacerArgs);
}
if (Array.isArray(obj) || ArrayBuffer.isView(obj)) {
return obj.map((v) => replaceInObject(v, test, replacer, ...replacerArgs));
}
return Object.fromEntries(Object.entries(obj).map(([k, v], i) => [k, replaceInObject(v, test, replacer, ...replacerArgs)]));
}
function newCrossOriginWorker(url, cb) {
const req = new XMLHttpRequest();
req.open("get", url, true);
req.onload = () => {
const worker = new Worker(URL.createObjectURL(new Blob([req.responseText])));
cb(worker);
};
req.send();
}
function isCrossOrigin(urlString) {
if (IN_NODE)
return false;
const url1 = new URL(location.href);
const url2 = new URL(urlString, location.origin);
if (url1.host === url2.host && url1.port === url2.port && url1.protocol === url2.protocol) {
return false;
}
return true;
}
// webR/chan/task-common.ts
var SZ_BUF_DOESNT_FIT = 0;
var SZ_BUF_FITS_IDX = 1;
var SZ_BUF_SIZE_IDX = 0;
var transferCache = /* @__PURE__ */ new WeakMap();
function transfer(obj, transfers) {
transferCache.set(obj, transfers);
return obj;
}
var UUID_LENGTH = 63;
function generateUUID() {
const result = Array.from({ length: 4 }, randomSegment).join("-");
if (result.length !== UUID_LENGTH) {
throw new Error("comlink internal error: UUID has the wrong length");
}
return result;
}
function randomSegment() {
let result = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16);
const pad = 15 - result.length;
if (pad > 0) {
result = Array.from({ length: pad }, () => 0).join("") + result;
}
return result;
}
// webR/chan/message.ts
function newRequest(msg, transferables) {
return newRequestResponseMessage({
type: "request",
data: {
uuid: generateUUID(),
msg
}
}, transferables);
}
function newResponse(uuid, resp, transferables) {
return newRequestResponseMessage({
type: "response",
data: {
uuid,
resp
}
}, transferables);
}
function newRequestResponseMessage(msg, transferables) {
if (transferables) {
transfer(msg, transferables);
}
return msg;
}
function newSyncRequest(msg, data) {
return {
type: "sync-request",
data: { msg, reqData: data }
};
}
var encoder = new TextEncoder();
var decoder = new TextDecoder("utf-8");
function encodeData(data) {
return encoder.encode(JSON.stringify(data));
}
function decodeData(data) {
return JSON.parse(decoder.decode(data));
}
// webR/chan/task-main.ts
var encoder2 = new TextEncoder();
async function syncResponse(endpoint, data, response) {
try {
let { taskId, sizeBuffer, dataBuffer, signalBuffer } = data;
const bytes = encodeData(response);
const fits = bytes.length <= dataBuffer.length;
Atomics.store(sizeBuffer, SZ_BUF_SIZE_IDX, bytes.length);
Atomics.store(sizeBuffer, SZ_BUF_FITS_IDX, +fits);
if (!fits) {
const [uuid, dataPromise] = requestResponseMessage(endpoint);
dataBuffer.set(encoder2.encode(uuid));
await signalRequester(signalBuffer, taskId);
dataBuffer = (await dataPromise).dataBuffer;
}
dataBuffer.set(bytes);
Atomics.store(sizeBuffer, SZ_BUF_FITS_IDX, 1);
await signalRequester(signalBuffer, taskId);
} catch (e) {
console.warn(e);
}
}
function requestResponseMessage(ep) {
const id = generateUUID();
return [
id,
new Promise((resolve) => {
if (IN_NODE) {
ep.once("message", (message) => {
if (!message.id || message.id !== id) {
return;
}
resolve(message);
});
} else {
ep.addEventListener("message", function l(ev) {
if (!ev.data || !ev.data.id || ev.data.id !== id) {
return;
}
ep.removeEventListener("message", l);
resolve(ev.data);
});
}
if (ep.start) {
ep.start();
}
})
];
}
async function signalRequester(signalBuffer, taskId) {
const index = (taskId >> 1) % 32;
let sleepTime = 1;
while (Atomics.compareExchange(signalBuffer, index + 1, 0, taskId) !== 0) {
await sleep(sleepTime);
if (sleepTime < 32) {
sleepTime *= 2;
}
}
Atomics.or(signalBuffer, 0, 1 << index);
Atomics.notify(signalBuffer, 0);
}
// webR/chan/task-worker.ts
var decoder2 = new TextDecoder("utf-8");
var _scheduled, _resolved, _result, _exception, _syncGen;
var SyncTask = class {
constructor(endpoint, msg, transfers = []) {
__privateAdd(this, _scheduled, false);
__privateAdd(this, _resolved, void 0);
__privateAdd(this, _result, void 0);
__privateAdd(this, _exception, void 0);
__privateAdd(this, _syncGen, void 0);
this.syncifier = new _Syncifier();
this.endpoint = endpoint;
this.msg = msg;
this.transfers = transfers;
__privateSet(this, _resolved, false);
}
scheduleSync() {
if (__privateGet(this, _scheduled)) {
return;
}
__privateSet(this, _scheduled, true);
this.syncifier.scheduleTask(this);
__privateSet(this, _syncGen, this.doSync());
__privateGet(this, _syncGen).next();
return this;
}
poll() {
if (!__privateGet(this, _scheduled)) {
throw new Error("Task not synchronously scheduled");
}
const { done, value } = __privateGet(this, _syncGen).next();
if (!done) {
return false;
}
__privateSet(this, _resolved, true);
__privateSet(this, _result, value);
return true;
}
*doSync() {
const { endpoint, msg, transfers } = this;
const sizeBuffer = new Int32Array(new SharedArrayBuffer(8));
const signalBuffer = this.signalBuffer;
const taskId = this.taskId;
let dataBuffer = acquireDataBuffer(UUID_LENGTH);
const syncMsg = newSyncRequest(msg, {
sizeBuffer,
dataBuffer,
signalBuffer,
taskId
});
endpoint.postMessage(syncMsg, transfers);
yield;
if (Atomics.load(sizeBuffer, SZ_BUF_FITS_IDX) === SZ_BUF_DOESNT_FIT) {
const id = decoder2.decode(dataBuffer.slice(0, UUID_LENGTH));
releaseDataBuffer(dataBuffer);
const size2 = Atomics.load(sizeBuffer, SZ_BUF_SIZE_IDX);
dataBuffer = acquireDataBuffer(size2);
endpoint.postMessage({ id, dataBuffer });
yield;
}
const size = Atomics.load(sizeBuffer, SZ_BUF_SIZE_IDX);
return decodeData(dataBuffer.slice(0, size));
}
get result() {
if (__privateGet(this, _exception)) {
throw __privateGet(this, _exception);
}
if (__privateGet(this, _resolved)) {
return __privateGet(this, _result);
}
throw new Error("Not ready.");
}
syncify() {
this.scheduleSync();
this.syncifier.syncifyTask(this);
return this.result;
}
};
_scheduled = new WeakMap();
_resolved = new WeakMap();
_result = new WeakMap();
_exception = new WeakMap();
_syncGen = new WeakMap();
var _Syncifier = class {
constructor() {
this.nextTaskId = new Int32Array([1]);
this.signalBuffer = new Int32Array(new SharedArrayBuffer(32 * 4 + 4));
this.tasks = /* @__PURE__ */ new Map();
}
scheduleTask(task) {
task.taskId = this.nextTaskId[0];
this.nextTaskId[0] += 2;
task.signalBuffer = this.signalBuffer;
this.tasks.set(task.taskId, task);
}
waitOnSignalBuffer() {
const timeout = 50;
for (; ; ) {
const status = Atomics.wait(this.signalBuffer, 0, 0, timeout);
switch (status) {
case "ok":
case "not-equal":
return;
case "timed-out":
if (interruptBuffer[0] !== 0) {
handleInterrupt();
}
break;
default:
throw new Error("Unreachable");
}
}
}
*tasksIdsToWakeup() {
const flag = Atomics.load(this.signalBuffer, 0);
for (let i = 0; i < 32; i++) {
const bit = 1 << i;
if (flag & bit) {
Atomics.and(this.signalBuffer, 0, ~bit);
const wokenTask = Atomics.exchange(this.signalBuffer, i + 1, 0);
yield wokenTask;
}
}
}
pollTasks(task) {
let result = false;
for (const wokenTaskId of this.tasksIdsToWakeup()) {
const wokenTask = this.tasks.get(wokenTaskId);
if (!wokenTask) {
throw new Error(`Assertion error: unknown taskId ${wokenTaskId}.`);
}
if (wokenTask.poll()) {
this.tasks.delete(wokenTaskId);
if (wokenTask === task) {
result = true;
}
}
}
return result;
}
syncifyTask(task) {
for (; ; ) {
this.waitOnSignalBuffer();
if (this.pollTasks(task)) {
return;
}
}
}
};
var dataBuffers = [];
function acquireDataBuffer(size) {
const powerof2 = Math.ceil(Math.log2(size));
if (!dataBuffers[powerof2]) {
dataBuffers[powerof2] = [];
}
const result = dataBuffers[powerof2].pop();
if (result) {
result.fill(0);
return result;
}
return new Uint8Array(new SharedArrayBuffer(2 ** powerof2));
}
function releaseDataBuffer(buffer) {
const powerof2 = Math.ceil(Math.log2(buffer.byteLength));
dataBuffers[powerof2].push(buffer);
}
var interruptBuffer = new Int32Array(new ArrayBuffer(4));
var handleInterrupt = () => {
interruptBuffer[0] = 0;
throw new Error("Interrupted!");
};
function setInterruptHandler(handler) {
handleInterrupt = handler;
}
function setInterruptBuffer(buffer) {
interruptBuffer = new Int32Array(buffer);
}
// webR/chan/channel-shared.ts
if (IN_NODE) {
globalThis.Worker = require("worker_threads").Worker;
}
var _interruptBuffer, _parked, _resolveResponse, resolveResponse_fn, _handleEventsFromWorker, handleEventsFromWorker_fn, _onMessageFromWorker;
var SharedBufferChannelMain = class {
constructor(config) {
__privateAdd(this, _resolveResponse);
__privateAdd(this, _handleEventsFromWorker);
this.inputQueue = new AsyncQueue();
this.outputQueue = new AsyncQueue();
__privateAdd(this, _interruptBuffer, void 0);
this.close = () => {
};
__privateAdd(this, _parked, /* @__PURE__ */ new Map());
__privateAdd(this, _onMessageFromWorker, async (worker, message) => {
if (!message || !message.type) {
return;
}
switch (message.type) {
case "resolve":
__privateSet(this, _interruptBuffer, new Int32Array(message.data));
this.resolve();
return;
case "response":
__privateMethod(this, _resolveResponse, resolveResponse_fn).call(this, message);
return;
default:
this.outputQueue.put(message);
return;
case "sync-request": {
const msg = message;
const payload = msg.data.msg;
const reqData = msg.data.reqData;
switch (payload.type) {
case "read": {
const response = await this.inputQueue.get();
await syncResponse(worker, reqData, response);
break;
}
default:
throw new TypeError(`Unsupported request type '${payload.type}'.`);
}
return;
}
case "request":
throw new TypeError("Can't send messages of type 'request' from a worker. Please Use 'sync-request' instead.");
}
});
const initWorker = (worker) => {
__privateMethod(this, _handleEventsFromWorker, handleEventsFromWorker_fn).call(this, worker);
this.close = () => worker.terminate();
const msg = {
type: "init",
data: { config, channelType: ChannelType.SharedArrayBuffer }
};
worker.postMessage(msg);
};
if (isCrossOrigin(config.WEBR_URL)) {
newCrossOriginWorker(`${config.WEBR_URL}webr-worker.js`, (worker) => initWorker(worker));
} else {
const worker = new Worker(`${config.WEBR_URL}webr-worker.js`);
initWorker(worker);
}
({ resolve: this.resolve, promise: this.initialised } = promiseHandles());
}
async read() {
return await this.outputQueue.get();
}
async flush() {
const msg = [];
while (!this.outputQueue.isEmpty()) {
msg.push(await this.read());
}
return msg;
}
interrupt() {
if (!__privateGet(this, _interruptBuffer)) {
throw new Error("Failed attempt to interrupt before initialising interruptBuffer");
}
__privateGet(this, _interruptBuffer)[0] = 1;
}
write(msg) {
this.inputQueue.put(msg);
}
async request(msg, transferables) {
const req = newRequest(msg, transferables);
const { resolve, promise: prom } = promiseHandles();
__privateGet(this, _parked).set(req.data.uuid, resolve);
this.write(req);
return prom;
}
};
_interruptBuffer = new WeakMap();
_parked = new WeakMap();
_resolveResponse = new WeakSet();
resolveResponse_fn = function(msg) {
const uuid = msg.data.uuid;
const resolve = __privateGet(this, _parked).get(uuid);
if (resolve) {
__privateGet(this, _parked).delete(uuid);
resolve(msg.data.resp);
} else {
console.warn("Can't find request.");
}
};
_handleEventsFromWorker = new WeakSet();
handleEventsFromWorker_fn = function(worker) {
if (IN_NODE) {
worker.on("message", (message) => {
__privateGet(this, _onMessageFromWorker).call(this, worker, message);
});
} else {
worker.onmessage = (ev) => __privateGet(this, _onMessageFromWorker).call(this, worker, ev.data);
}
};
_onMessageFromWorker = new WeakMap();
var _ep, _dispatch, _interruptBuffer2, _interrupt;
var SharedBufferChannelWorker = class {
constructor() {
__privateAdd(this, _ep, void 0);
__privateAdd(this, _dispatch, () => 0);
__privateAdd(this, _interruptBuffer2, new Int32Array(new SharedArrayBuffer(4)));
__privateAdd(this, _interrupt, () => {
});
__privateSet(this, _ep, IN_NODE ? require("worker_threads").parentPort : globalThis);
setInterruptBuffer(__privateGet(this, _interruptBuffer2).buffer);
setInterruptHandler(() => this.handleInterrupt());
}
resolve() {
this.write({ type: "resolve", data: __privateGet(this, _interruptBuffer2).buffer });
}
write(msg, transfer2) {
__privateGet(this, _ep).postMessage(msg, transfer2);
}
read() {
const msg = { type: "read" };
const task = new SyncTask(__privateGet(this, _ep), msg);
return task.syncify();
}
inputOrDispatch() {
for (; ; ) {
const msg = this.read();
if (msg.type === "stdin") {
return Module.allocateUTF8(msg.data);
}
__privateGet(this, _dispatch).call(this, msg);
}
}
run(args) {
Module.callMain(args);
}
setInterrupt(interrupt) {
__privateSet(this, _interrupt, interrupt);
}
handleInterrupt() {
if (__privateGet(this, _interruptBuffer2)[0] !== 0) {
__privateGet(this, _interruptBuffer2)[0] = 0;
__privateGet(this, _interrupt).call(this);
}
}
setDispatchHandler(dispatch2) {
__privateSet(this, _dispatch, dispatch2);
}
};
_ep = new WeakMap();
_dispatch = new WeakMap();
_interruptBuffer2 = new WeakMap();
_interrupt = new WeakMap();
// webR/chan/channel-service.ts
if (IN_NODE) {
globalThis.Worker = require("worker_threads").Worker;
}
var _parked2, _syncMessageCache, _registration, _interrupted, _registerServiceWorker, registerServiceWorker_fn, _onMessageFromServiceWorker, onMessageFromServiceWorker_fn, _resolveResponse2, resolveResponse_fn2, _handleEventsFromWorker2, handleEventsFromWorker_fn2, _onMessageFromWorker2;
var ServiceWorkerChannelMain = class {
constructor(config) {
__privateAdd(this, _registerServiceWorker);
__privateAdd(this, _onMessageFromServiceWorker);
__privateAdd(this, _resolveResponse2);
__privateAdd(this, _handleEventsFromWorker2);
this.inputQueue = new AsyncQueue();
this.outputQueue = new AsyncQueue();
this.close = () => {
};
__privateAdd(this, _parked2, /* @__PURE__ */ new Map());
__privateAdd(this, _syncMessageCache, /* @__PURE__ */ new Map());
__privateAdd(this, _registration, void 0);
__privateAdd(this, _interrupted, false);
__privateAdd(this, _onMessageFromWorker2, async (worker, message) => {
if (!message || !message.type) {
return;
}
switch (message.type) {
case "resolve":
this.resolve();
return;
case "response":
__privateMethod(this, _resolveResponse2, resolveResponse_fn2).call(this, message);
return;
default:
this.outputQueue.put(message);
return;
case "sync-request": {
const request = message.data;
__privateGet(this, _syncMessageCache).set(request.data.uuid, request.data.msg);
return;
}
case "request":
throw new TypeError("Can't send messages of type 'request' from a worker.Use service worker fetch request instead.");
}
});
const initWorker = (worker) => {
__privateMethod(this, _handleEventsFromWorker2, handleEventsFromWorker_fn2).call(this, worker);
this.close = () => worker.terminate();
__privateMethod(this, _registerServiceWorker, registerServiceWorker_fn).call(this, `${config.SW_URL}webr-serviceworker.js`).then((clientId) => {
const msg = {
type: "init",
data: {
config,
channelType: ChannelType.ServiceWorker,
clientId,
location: window.location.href
}
};
worker.postMessage(msg);
});
};
if (isCrossOrigin(config.SW_URL)) {
newCrossOriginWorker(`${config.SW_URL}webr-worker.js`, (worker) => initWorker(worker));
} else {
const worker = new Worker(`${config.SW_URL}webr-worker.js`);
initWorker(worker);
}
({ resolve: this.resolve, promise: this.initialised } = promiseHandles());
}
activeRegistration() {
var _a;
if (!((_a = __privateGet(this, _registration)) == null ? void 0 : _a.active)) {
throw new Error("Attempted to obtain a non-existent active registration.");
}
return __privateGet(this, _registration).active;
}
async read() {
return await this.outputQueue.get();
}
async flush() {
const msg = [];
while (!this.outputQueue.isEmpty()) {
msg.push(await this.read());
}
return msg;
}
interrupt() {
__privateSet(this, _interrupted, true);
}
write(msg) {
this.inputQueue.put(msg);
}
async request(msg, transferables) {
const req = newRequest(msg, transferables);
const { resolve, promise: prom } = promiseHandles();
__privateGet(this, _parked2).set(req.data.uuid, resolve);
this.write(req);
return prom;
}
};
_parked2 = new WeakMap();
_syncMessageCache = new WeakMap();
_registration = new WeakMap();
_interrupted = new WeakMap();
_registerServiceWorker = new WeakSet();
registerServiceWorker_fn = async function(url) {
__privateSet(this, _registration, await navigator.serviceWorker.register(url));
await navigator.serviceWorker.ready;
window.addEventListener("beforeunload", () => {
var _a;
(_a = __privateGet(this, _registration)) == null ? void 0 : _a.unregister();
});
const clientId = await new Promise((resolve) => {
navigator.serviceWorker.addEventListener("message", function listener(event) {
if (event.data.type === "registration-successful") {
navigator.serviceWorker.removeEventListener("message", listener);
resolve(event.data.clientId);
}
});
this.activeRegistration().postMessage({ type: "register-client-main" });
});
navigator.serviceWorker.addEventListener("message", (event) => {
__privateMethod(this, _onMessageFromServiceWorker, onMessageFromServiceWorker_fn).call(this, event);
});
return clientId;
};
_onMessageFromServiceWorker = new WeakSet();
onMessageFromServiceWorker_fn = async function(event) {
if (event.data.type === "request") {
const uuid = event.data.data;
const message = __privateGet(this, _syncMessageCache).get(uuid);
if (!message) {
throw new Error("Request not found during service worker XHR request");
}
__privateGet(this, _syncMessageCache).delete(uuid);
switch (message.type) {
case "read": {
const response = await this.inputQueue.get();
this.activeRegistration().postMessage({
type: "wasm-webr-fetch-response",
uuid,
response: newResponse(uuid, response)
});
break;
}
case "interrupt": {
const response = __privateGet(this, _interrupted);
this.activeRegistration().postMessage({
type: "wasm-webr-fetch-response",
uuid,
response: newResponse(uuid, response)
});
__privateSet(this, _interrupted, false);
break;
}
default:
throw new TypeError(`Unsupported request type '${message.type}'.`);
}
return;
}
};
_resolveResponse2 = new WeakSet();
resolveResponse_fn2 = function(msg) {
const uuid = msg.data.uuid;
const resolve = __privateGet(this, _parked2).get(uuid);
if (resolve) {
__privateGet(this, _parked2).delete(uuid);
resolve(msg.data.resp);
} else {
console.warn("Can't find request.");
}
};
_handleEventsFromWorker2 = new WeakSet();
handleEventsFromWorker_fn2 = function(worker) {
if (IN_NODE) {
worker.on("message", (message) => {
__privateGet(this, _onMessageFromWorker2).call(this, worker, message);
});
} else {
worker.onmessage = (ev) => __privateGet(this, _onMessageFromWorker2).call(this, worker, ev.data);
}
};
_onMessageFromWorker2 = new WeakMap();
var _ep2, _mainThreadId, _location, _dispatch2, _interrupt2;
var ServiceWorkerChannelWorker = class {
constructor(data) {
__privateAdd(this, _ep2, void 0);
__privateAdd(this, _mainThreadId, void 0);
__privateAdd(this, _location, void 0);
__privateAdd(this, _dispatch2, () => 0);
__privateAdd(this, _interrupt2, () => {
});
this.onMessageFromMainThread = () => {
};
if (!data.clientId || !data.location) {
throw Error("Unable to start service worker channel");
}
__privateSet(this, _mainThreadId, data.clientId);
__privateSet(this, _location, data.location);
__privateSet(this, _ep2, IN_NODE ? require("worker_threads").parentPort : globalThis);
}
resolve() {
this.write({ type: "resolve" });
}
write(msg, transfer2) {
__privateGet(this, _ep2).postMessage(msg, transfer2);
}
syncRequest(message) {
const request = newRequest(message);
this.write({ type: "sync-request", data: request });
let retryCount = 0;
for (; ; ) {
try {
const url = new URL("__wasm__/webr-fetch-request/", __privateGet(this, _location));
const xhr = new XMLHttpRequest();
xhr.timeout = 6e4;
xhr.responseType = "arraybuffer";
xhr.open("POST", url, false);
const fetchReqBody = {
clientId: __privateGet(this, _mainThreadId),
uuid: request.data.uuid
};
xhr.send(encodeData(fetchReqBody));
return decodeData(new Uint8Array(xhr.response));
} catch (e) {
if (e instanceof DOMException && retryCount++ < 1e3) {
console.log("Service worker request failed - resending request");
} else {
throw e;
}
}
}
}
read() {
const response = this.syncRequest({ type: "read" });
return response.data.resp;
}
inputOrDispatch() {
for (; ; ) {
const msg = this.read();
if (msg.type === "stdin") {
return Module.allocateUTF8(msg.data);
}
__privateGet(this, _dispatch2).call(this, msg);
}
}
run(args) {
Module.callMain(args);
}
setInterrupt(interrupt) {
__privateSet(this, _interrupt2, interrupt);
}
handleInterrupt() {
const response = this.syncRequest({ type: "interrupt" });
const interrupted = response.data.resp;
if (interrupted) {
__privateGet(this, _interrupt2).call(this);
}
}
setDispatchHandler(dispatch2) {
__privateSet(this, _dispatch2, dispatch2);
}
};
_ep2 = new WeakMap();
_mainThreadId = new WeakMap();
_location = new WeakMap();
_dispatch2 = new WeakMap();
_interrupt2 = new WeakMap();
// webR/chan/channel.ts
var ChannelType = {
Automatic: 0,
SharedArrayBuffer: 1,
ServiceWorker: 2
};
function newChannelWorker(msg) {
switch (msg.data.channelType) {
case ChannelType.SharedArrayBuffer:
return new SharedBufferChannelWorker();
case ChannelType.ServiceWorker:
return new ServiceWorkerChannelWorker(msg.data);
default:
throw new Error("Unknown worker channel type recieved");
}
}
// webR/robj.ts
var RTypeMap = {
null: 0,
symbol: 1,
pairlist: 2,
closure: 3,
environment: 4,
promise: 5,
call: 6,
special: 7,
builtin: 8,
string: 9,
logical: 10,
integer: 13,
double: 14,
complex: 15,
character: 16,
dots: 17,
any: 18,
list: 19,
expression: 20,
bytecode: 21,
pointer: 22,
weakref: 23,
raw: 24,
s4: 25,
new: 30,
free: 31,
function: 99
};
function newRObjFromTarget(target) {
const obj = target.obj;
if (isRObjectTree(obj)) {
return new (getRObjClass(RTypeMap[obj.type]))(obj);
}
if (obj && typeof obj === "object" && "type" in obj && obj.type === "null") {
return new RObjNull();
}
if (obj === null) {
return new RObjLogical({ type: "logical", names: null, values: [null] });
}
if (typeof obj === "boolean") {
return new RObjLogical(obj);
}
if (typeof obj === "number") {
return new RObjDouble(obj);
}
if (typeof obj === "object" && "re" in obj && "im" in obj) {
return new RObjComplex(obj);
}
if (typeof obj === "string") {
return new RObjCharacter(obj);
}
if (Array.isArray(obj)) {
const objs = obj.map((el) => newRObjFromTarget({ targetType: "raw", obj: el }));
const cString = Module.allocateUTF8("c");
const call = RObjImpl.protect(RObjImpl.wrap(Module._Rf_allocVector(RTypeMap.call, objs.length + 1)));
call.setcar(RObjImpl.wrap(Module._Rf_install(cString)));
let next = call.cdr();
let i = 0;
while (!next.isNull()) {
next.setcar(objs[i++]);
next = next.cdr();
}
const res = RObjImpl.wrap(Module._Rf_eval(call.ptr, RObjImpl.baseEnv.ptr));
RObjImpl.unprotect(1);
Module._free(cString);
return res;
}
throw new Error("Robj construction for this JS object is not yet supported");
}
var RObjImpl = class {
constructor(target) {
this.ptr = 0;
if (isRTargetObj(target)) {
if (target.targetType === "ptr") {
this.ptr = target.obj.ptr;
return this;
}
if (target.targetType === "raw") {
return newRObjFromTarget(target);
}
}
return newRObjFromTarget({ targetType: "raw", obj: target });
}
get [Symbol.toStringTag]() {
return `RObj:${this.type()}`;
}
type() {
const typeNumber = Module._TYPEOF(this.ptr);
const type = Object.keys(RTypeMap).find((typeName) => RTypeMap[typeName] === typeNumber);
return type;
}
protect() {
this.ptr = Module._Rf_protect(this.ptr);
}
unprotect() {
Module._Rf_unprotect_ptr(this.ptr);
}
preserve() {
Module._R_PreserveObject(this.ptr);
}
release() {
Module._R_ReleaseObject(this.ptr);
}
isNull() {
return Module._TYPEOF(this.ptr) === RTypeMap.null;
}
isUnbound() {
return this.ptr === RObjImpl.unboundValue.ptr;
}
attrs() {
return RObjImpl.wrap(Module._ATTRIB(this.ptr));
}
setNames(values) {
let namesObj;
if (values === null) {
namesObj = RObjImpl.null;
RObjImpl.protect(namesObj);
} else if (Array.isArray(values) && values.every((v) => typeof v === "string" || v === null)) {
namesObj = new RObjCharacter(values);
} else {
throw new Error("Argument to setNames must be null or an Array of strings or null");
}
Module._Rf_setAttrib(this.ptr, RObjImpl.namesSymbol.ptr, namesObj.ptr);
RObjImpl.unprotect(1);
return this;
}
names() {
const names = RObjImpl.wrap(Module._Rf_protect(Module._Rf_getAttrib(this.ptr, RObjImpl.namesSymbol.ptr)));
if (names.isNull()) {
return null;
}
return names.toArray();
}
includes(name) {
const names = this.names();
return names && names.includes(name);
}
toTree(options = { depth: 0 }, depth = 1) {
throw new Error("This R object cannot be converted to JS");
}
toJs() {
return this.toTree();
}
subset(prop) {
let idx;
let char = 0;
if (typeof prop === "number") {
idx = Module._Rf_protect(Module._Rf_ScalarInteger(prop));
} else {
char = Module.allocateUTF8(prop);
idx = Module._Rf_protect(Module._Rf_mkString(char));
}
const call = Module._Rf_protect(Module._Rf_lang3(RObjImpl.bracketSymbol.ptr, this.ptr, idx));
const sub = RObjImpl.wrap(Module._Rf_eval(call, RObjImpl.baseEnv.ptr));
Module._Rf_unprotect(2);
if (char)
Module._free(char);
return sub;
}
get(prop) {
let idx;
let char = 0;
if (typeof prop === "number") {
idx = Module._Rf_protect(Module._Rf_ScalarInteger(prop));
} else {
char = Module.allocateUTF8(prop);
idx = Module._Rf_protect(Module._Rf_mkString(char));
}
const call = Module._Rf_protect(Module._Rf_lang3(RObjImpl.bracket2Symbol.ptr, this.ptr, idx));
const sub = RObjImpl.wrap(Module._Rf_eval(call, RObjImpl.baseEnv.ptr));
Module._Rf_unprotect(2);
if (char)
Module._free(char);
return sub;
}
getDollar(prop) {
const char = Module.allocateUTF8(prop);
const idx = Module._Rf_protect(Module._Rf_mkString(char));
const call = Module._Rf_protect(Module._Rf_lang3(RObjImpl.dollarSymbol.ptr, this.ptr, idx));
const sub = RObjImpl.wrap(Module._Rf_eval(call, RObjImpl.baseEnv.ptr));
Module._Rf_unprotect(2);
Module._free(char);
return sub;
}
pluck(...path) {
try {
const result = path.reduce((obj, prop) => obj.get(prop), this);
return result.isNull() ? void 0 : result;
} catch (err) {
if (err === Infinity) {
return void 0;
}
throw err;
}
}
set(prop, value) {
let idx;
let char = 0;
if (typeof prop === "number") {
idx = Module._Rf_protect(Module._Rf_ScalarInteger(prop));
} else {
char = Module.allocateUTF8(prop);
idx = Module._Rf_protect(Module._Rf_mkString(char));
}
const valueObj = isRObjImpl(value) ? value : new RObjImpl({ obj: value, targetType: "raw" });
const assign = Module.alloc