wasmrs-js
Version:
A JavaScript implementation of the RSocket protocol over WebAssembly.
1,181 lines (1,083 loc) • 31.5 kB
JavaScript
;
var wasi = require('wasi');
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var browser = {exports: {}};
/**
* Helpers.
*/
var ms;
var hasRequiredMs;
function requireMs () {
if (hasRequiredMs) return ms;
hasRequiredMs = 1;
var s = 1000;
var m = s * 60;
var h = m * 60;
var d = h * 24;
var w = d * 7;
var y = d * 365.25;
/**
* Parse or format the given `val`.
*
* Options:
*
* - `long` verbose formatting [false]
*
* @param {String|Number} val
* @param {Object} [options]
* @throws {Error} throw an error if val is not a non-empty string or a number
* @return {String|Number}
* @api public
*/
ms = function(val, options) {
options = options || {};
var type = typeof val;
if (type === 'string' && val.length > 0) {
return parse(val);
} else if (type === 'number' && isFinite(val)) {
return options.long ? fmtLong(val) : fmtShort(val);
}
throw new Error(
'val is not a non-empty string or a valid number. val=' +
JSON.stringify(val)
);
};
/**
* Parse the given `str` and return milliseconds.
*
* @param {String} str
* @return {Number}
* @api private
*/
function parse(str) {
str = String(str);
if (str.length > 100) {
return;
}
var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(
str
);
if (!match) {
return;
}
var n = parseFloat(match[1]);
var type = (match[2] || 'ms').toLowerCase();
switch (type) {
case 'years':
case 'year':
case 'yrs':
case 'yr':
case 'y':
return n * y;
case 'weeks':
case 'week':
case 'w':
return n * w;
case 'days':
case 'day':
case 'd':
return n * d;
case 'hours':
case 'hour':
case 'hrs':
case 'hr':
case 'h':
return n * h;
case 'minutes':
case 'minute':
case 'mins':
case 'min':
case 'm':
return n * m;
case 'seconds':
case 'second':
case 'secs':
case 'sec':
case 's':
return n * s;
case 'milliseconds':
case 'millisecond':
case 'msecs':
case 'msec':
case 'ms':
return n;
default:
return undefined;
}
}
/**
* Short format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtShort(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return Math.round(ms / d) + 'd';
}
if (msAbs >= h) {
return Math.round(ms / h) + 'h';
}
if (msAbs >= m) {
return Math.round(ms / m) + 'm';
}
if (msAbs >= s) {
return Math.round(ms / s) + 's';
}
return ms + 'ms';
}
/**
* Long format for `ms`.
*
* @param {Number} ms
* @return {String}
* @api private
*/
function fmtLong(ms) {
var msAbs = Math.abs(ms);
if (msAbs >= d) {
return plural(ms, msAbs, d, 'day');
}
if (msAbs >= h) {
return plural(ms, msAbs, h, 'hour');
}
if (msAbs >= m) {
return plural(ms, msAbs, m, 'minute');
}
if (msAbs >= s) {
return plural(ms, msAbs, s, 'second');
}
return ms + ' ms';
}
/**
* Pluralization helper.
*/
function plural(ms, msAbs, n, name) {
var isPlural = msAbs >= n * 1.5;
return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
}
return ms;
}
/**
* This is the common logic for both the Node.js and web browser
* implementations of `debug()`.
*/
function setup(env) {
createDebug.debug = createDebug;
createDebug.default = createDebug;
createDebug.coerce = coerce;
createDebug.disable = disable;
createDebug.enable = enable;
createDebug.enabled = enabled;
createDebug.humanize = requireMs();
createDebug.destroy = destroy;
Object.keys(env).forEach(key => {
createDebug[key] = env[key];
});
/**
* The currently active debug mode names, and names to skip.
*/
createDebug.names = [];
createDebug.skips = [];
/**
* Map of special "%n" handling functions, for the debug "format" argument.
*
* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
*/
createDebug.formatters = {};
/**
* Selects a color for a debug namespace
* @param {String} namespace The namespace string for the debug instance to be colored
* @return {Number|String} An ANSI color code for the given namespace
* @api private
*/
function selectColor(namespace) {
let hash = 0;
for (let i = 0; i < namespace.length; i++) {
hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
hash |= 0; // Convert to 32bit integer
}
return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
}
createDebug.selectColor = selectColor;
/**
* Create a debugger with the given `namespace`.
*
* @param {String} namespace
* @return {Function}
* @api public
*/
function createDebug(namespace) {
let prevTime;
let enableOverride = null;
let namespacesCache;
let enabledCache;
function debug(...args) {
// Disabled?
if (!debug.enabled) {
return;
}
const self = debug;
// Set `diff` timestamp
const curr = Number(new Date());
const ms = curr - (prevTime || curr);
self.diff = ms;
self.prev = prevTime;
self.curr = curr;
prevTime = curr;
args[0] = createDebug.coerce(args[0]);
if (typeof args[0] !== 'string') {
// Anything else let's inspect with %O
args.unshift('%O');
}
// Apply any `formatters` transformations
let index = 0;
args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
// If we encounter an escaped % then don't increase the array index
if (match === '%%') {
return '%';
}
index++;
const formatter = createDebug.formatters[format];
if (typeof formatter === 'function') {
const val = args[index];
match = formatter.call(self, val);
// Now we need to remove `args[index]` since it's inlined in the `format`
args.splice(index, 1);
index--;
}
return match;
});
// Apply env-specific formatting (colors, etc.)
createDebug.formatArgs.call(self, args);
const logFn = self.log || createDebug.log;
logFn.apply(self, args);
}
debug.namespace = namespace;
debug.useColors = createDebug.useColors();
debug.color = createDebug.selectColor(namespace);
debug.extend = extend;
debug.destroy = createDebug.destroy; // XXX Temporary. Will be removed in the next major release.
Object.defineProperty(debug, 'enabled', {
enumerable: true,
configurable: false,
get: () => {
if (enableOverride !== null) {
return enableOverride;
}
if (namespacesCache !== createDebug.namespaces) {
namespacesCache = createDebug.namespaces;
enabledCache = createDebug.enabled(namespace);
}
return enabledCache;
},
set: v => {
enableOverride = v;
}
});
// Env-specific initialization logic for debug instances
if (typeof createDebug.init === 'function') {
createDebug.init(debug);
}
return debug;
}
function extend(namespace, delimiter) {
const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
newDebug.log = this.log;
return newDebug;
}
/**
* Enables a debug mode by namespaces. This can include modes
* separated by a colon and wildcards.
*
* @param {String} namespaces
* @api public
*/
function enable(namespaces) {
createDebug.save(namespaces);
createDebug.namespaces = namespaces;
createDebug.names = [];
createDebug.skips = [];
let i;
const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
const len = split.length;
for (i = 0; i < len; i++) {
if (!split[i]) {
// ignore empty strings
continue;
}
namespaces = split[i].replace(/\*/g, '.*?');
if (namespaces[0] === '-') {
createDebug.skips.push(new RegExp('^' + namespaces.slice(1) + '$'));
} else {
createDebug.names.push(new RegExp('^' + namespaces + '$'));
}
}
}
/**
* Disable debug output.
*
* @return {String} namespaces
* @api public
*/
function disable() {
const namespaces = [
...createDebug.names.map(toNamespace),
...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
].join(',');
createDebug.enable('');
return namespaces;
}
/**
* Returns true if the given mode name is enabled, false otherwise.
*
* @param {String} name
* @return {Boolean}
* @api public
*/
function enabled(name) {
if (name[name.length - 1] === '*') {
return true;
}
let i;
let len;
for (i = 0, len = createDebug.skips.length; i < len; i++) {
if (createDebug.skips[i].test(name)) {
return false;
}
}
for (i = 0, len = createDebug.names.length; i < len; i++) {
if (createDebug.names[i].test(name)) {
return true;
}
}
return false;
}
/**
* Convert regexp to namespace
*
* @param {RegExp} regxep
* @return {String} namespace
* @api private
*/
function toNamespace(regexp) {
return regexp.toString()
.substring(2, regexp.toString().length - 2)
.replace(/\.\*\?$/, '*');
}
/**
* Coerce `val`.
*
* @param {Mixed} val
* @return {Mixed}
* @api private
*/
function coerce(val) {
if (val instanceof Error) {
return val.stack || val.message;
}
return val;
}
/**
* XXX DO NOT USE. This is a temporary stub function.
* XXX It WILL be removed in the next major release.
*/
function destroy() {
console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
}
createDebug.enable(createDebug.load());
return createDebug;
}
var common = setup;
/* eslint-env browser */
(function (module, exports) {
/**
* This is the web browser implementation of `debug()`.
*/
exports.formatArgs = formatArgs;
exports.save = save;
exports.load = load;
exports.useColors = useColors;
exports.storage = localstorage();
exports.destroy = (() => {
let warned = false;
return () => {
if (!warned) {
warned = true;
console.warn('Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.');
}
};
})();
/**
* Colors.
*/
exports.colors = [
'#0000CC',
'#0000FF',
'#0033CC',
'#0033FF',
'#0066CC',
'#0066FF',
'#0099CC',
'#0099FF',
'#00CC00',
'#00CC33',
'#00CC66',
'#00CC99',
'#00CCCC',
'#00CCFF',
'#3300CC',
'#3300FF',
'#3333CC',
'#3333FF',
'#3366CC',
'#3366FF',
'#3399CC',
'#3399FF',
'#33CC00',
'#33CC33',
'#33CC66',
'#33CC99',
'#33CCCC',
'#33CCFF',
'#6600CC',
'#6600FF',
'#6633CC',
'#6633FF',
'#66CC00',
'#66CC33',
'#9900CC',
'#9900FF',
'#9933CC',
'#9933FF',
'#99CC00',
'#99CC33',
'#CC0000',
'#CC0033',
'#CC0066',
'#CC0099',
'#CC00CC',
'#CC00FF',
'#CC3300',
'#CC3333',
'#CC3366',
'#CC3399',
'#CC33CC',
'#CC33FF',
'#CC6600',
'#CC6633',
'#CC9900',
'#CC9933',
'#CCCC00',
'#CCCC33',
'#FF0000',
'#FF0033',
'#FF0066',
'#FF0099',
'#FF00CC',
'#FF00FF',
'#FF3300',
'#FF3333',
'#FF3366',
'#FF3399',
'#FF33CC',
'#FF33FF',
'#FF6600',
'#FF6633',
'#FF9900',
'#FF9933',
'#FFCC00',
'#FFCC33'
];
/**
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
* and the Firebug extension (any Firefox version) are known
* to support "%c" CSS customizations.
*
* TODO: add a `localStorage` variable to explicitly enable/disable colors
*/
// eslint-disable-next-line complexity
function useColors() {
// NB: In an Electron preload script, document will be defined but not fully
// initialized. Since we know we're in Chrome, we'll just detect this case
// explicitly
if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
return true;
}
// Internet Explorer and Edge do not support colors.
if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
return false;
}
// Is webkit? http://stackoverflow.com/a/16459606/376773
// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
// Is firebug? http://stackoverflow.com/a/398120/376773
(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
// Is firefox >= v31?
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
// Double check webkit in userAgent just in case we are in a worker
(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
}
/**
* Colorize log arguments if enabled.
*
* @api public
*/
function formatArgs(args) {
args[0] = (this.useColors ? '%c' : '') +
this.namespace +
(this.useColors ? ' %c' : ' ') +
args[0] +
(this.useColors ? '%c ' : ' ') +
'+' + module.exports.humanize(this.diff);
if (!this.useColors) {
return;
}
const c = 'color: ' + this.color;
args.splice(1, 0, c, 'color: inherit');
// The final "%c" is somewhat tricky, because there could be other
// arguments passed either before or after the %c, so we need to
// figure out the correct index to insert the CSS into
let index = 0;
let lastC = 0;
args[0].replace(/%[a-zA-Z%]/g, match => {
if (match === '%%') {
return;
}
index++;
if (match === '%c') {
// We only are interested in the *last* %c
// (the user may have provided their own)
lastC = index;
}
});
args.splice(lastC, 0, c);
}
/**
* Invokes `console.debug()` when available.
* No-op when `console.debug` is not a "function".
* If `console.debug` is not available, falls back
* to `console.log`.
*
* @api public
*/
exports.log = console.debug || console.log || (() => {});
/**
* Save `namespaces`.
*
* @param {String} namespaces
* @api private
*/
function save(namespaces) {
try {
if (namespaces) {
exports.storage.setItem('debug', namespaces);
} else {
exports.storage.removeItem('debug');
}
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
}
}
/**
* Load `namespaces`.
*
* @return {String} returns the previously persisted debug modes
* @api private
*/
function load() {
let r;
try {
r = exports.storage.getItem('debug');
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
}
// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
if (!r && typeof process !== 'undefined' && 'env' in process) {
r = process.env.DEBUG;
}
return r;
}
/**
* Localstorage attempts to return the localstorage.
*
* This is necessary because safari throws
* when a user disables cookies/localstorage
* and you attempt to access it.
*
* @return {LocalStorage}
* @api private
*/
function localstorage() {
try {
// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
// The Browser also has localStorage in the global context.
return localStorage;
} catch (error) {
// Swallow
// XXX (@Qix-) should we be logging these?
}
}
module.exports = common(exports);
const {formatters} = module.exports;
/**
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
*/
formatters.j = function (v) {
try {
return JSON.stringify(v);
} catch (error) {
return '[UnexpectedJSONParseError]: ' + error.message;
}
};
} (browser, browser.exports));
var browserExports = browser.exports;
var DEBUG = /*@__PURE__*/getDefaultExportFromCjs(browserExports);
const debug$1 = DEBUG('wasmrs');
class TestableError extends Error {
matcher() {
return new RegExp(this.toString().replace(/^Error: /, ''));
}
}
class HostCallNotImplementedError extends TestableError {
constructor(binding, namespace, operation) {
super(`Host call not implemented. Guest called host with binding = '${binding}', namespace = '${namespace}', & operation = '${operation}'`);
}
}
var HostProtocolMethods;
(function (HostProtocolMethods) {
HostProtocolMethods["OP_LIST"] = "__op_list";
HostProtocolMethods["INIT_BUFFERS"] = "__init_buffers";
HostProtocolMethods["CONSOLE_LOG"] = "__console_log";
HostProtocolMethods["SEND"] = "__send";
})(HostProtocolMethods || (HostProtocolMethods = {}));
var GuestProtocolMethods;
(function (GuestProtocolMethods) {
GuestProtocolMethods["START"] = "_start";
GuestProtocolMethods["OP_LIST_REQUEST"] = "__wasmrs_op_list_request";
GuestProtocolMethods["INIT"] = "__wasmrs_init";
GuestProtocolMethods["SEND"] = "__wasmrs_send";
})(GuestProtocolMethods || (GuestProtocolMethods = {}));
function fromU32Bytes(bytes) {
return (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
}
function toU32Bytes(num) {
const result = new Uint8Array(4);
result[0] = (num >> 24) % 256;
result[1] = (num >> 16) % 256;
result[2] = (num >> 8) % 256;
result[3] = num % 256;
return result;
}
function toU24Bytes(num) {
const result = new Uint8Array(3);
result[0] = (num >> 8) >> 8 % 256;
result[1] = num >> 8 % 256;
result[2] = num % 256;
return result;
}
function fromU24Bytes(bytes) {
return (bytes[0] << 16) | (bytes[1] << 8) | bytes[2];
}
function fromU16Bytes(bytes) {
return (bytes[0] << 8) | bytes[1];
}
class ModuleState {
guestRequest;
guestResponse;
hostResponse;
guestError;
hostError;
hostCallback;
writer;
constructor(hostCall, writer) {
this.hostCallback =
hostCall ||
((binding, namespace, operation) => {
throw new HostCallNotImplementedError(binding, namespace, operation);
});
this.writer = writer || (() => undefined);
}
}
let WASI$1 = undefined;
class WasmRsModule {
module;
constructor(module) {
this.module = module;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static from(any) {
if (any instanceof WasmRsModule) {
return any;
}
if (any instanceof WebAssembly.Module) {
return new WasmRsModule(any);
}
if ('module' in any && any.module instanceof WebAssembly.Module) {
return new WasmRsModule(any.module);
}
throw new Error(`cannot convert ${any} to WasmRsModule`);
}
static async compile(source) {
const mod = WebAssembly.compile(source);
return new WasmRsModule(await mod);
}
static async compileStreaming(source) {
if (!WebAssembly.compileStreaming) {
console.warn('WebAssembly.compileStreaming is not supported on this browser, wasm execution will be impacted.');
const bytes = new Uint8Array(await (await source).arrayBuffer());
return WasmRsModule.compile(bytes);
}
const mod = WebAssembly.compileStreaming(source);
return new WasmRsModule(await mod);
}
async instantiate(options = {}) {
const host = new WasmRsInstance(options);
let wasi = undefined;
if (options.wasi) {
if (!WASI$1) {
throw new Error('Wasi options provided but no WASI implementation found');
}
wasi = await WASI$1.create(options.wasi);
}
const imports = linkImports(host, wasi);
debug$1('instantiating wasm module');
const instance = await WebAssembly.instantiate(this.module, imports);
if (wasi) {
wasi.initialize(instance);
}
await host.initialize(instance);
return host;
}
}
class WasmRsInstance extends EventTarget {
guestBufferStart = 0;
hostBufferStart = 0;
state;
guestSend;
guestOpListRequest;
textEncoder;
textDecoder;
instance;
operations = new OperationList([], []);
constructor(options = {}) {
super();
this.state = new ModuleState(options.hostCall, options.writer);
this.textEncoder = new TextEncoder();
this.textDecoder = new TextDecoder('utf-8');
this.guestSend = () => undefined;
this.guestOpListRequest = () => undefined;
}
static setWasi(wasi) {
WASI$1 = wasi;
}
initialize(instance) {
this.instance = instance;
const start = this.instance.exports[GuestProtocolMethods.START];
if (start != null) {
debug$1(`>>>`, `${GuestProtocolMethods.START}()`);
start([]);
}
const init = this.getProtocolExport(GuestProtocolMethods.INIT);
const size = 512 * 1024;
debug$1(`>>>`, `${GuestProtocolMethods.INIT}(${size},${size},${size})`);
init(size, size, size);
const opList = this.getProtocolExport(GuestProtocolMethods.OP_LIST_REQUEST);
if (opList != null) {
debug$1(`>>>`, `${GuestProtocolMethods.OP_LIST_REQUEST}()`);
opList();
}
this.guestSend = this.getProtocolExport(GuestProtocolMethods.SEND);
this.guestOpListRequest = this.getProtocolExport(GuestProtocolMethods.OP_LIST_REQUEST);
debug$1('initialized wasm module');
}
getProtocolExport(name) {
const fn = this.instance.exports[name];
if (fn == null) {
throw new Error(`WebAssembly module does not export ${name}`);
}
return fn;
}
send(payload) {
const memory = this.getCallerMemory();
const buffer = new Uint8Array(memory.buffer);
debug$1(`writing ${payload.length} bytes to guest memory buffer`, payload, this.guestBufferStart);
buffer.set(toU24Bytes(payload.length), this.guestBufferStart);
buffer.set(payload, this.guestBufferStart + 3);
debug$1(`>>>`, ` ${GuestProtocolMethods.SEND}(${payload.length})`);
this.guestSend(payload.length);
}
getCallerMemory() {
return this.instance.exports.memory;
}
close() {
//
}
}
function linkImports(instance, wasi) {
if (wasi) {
debug$1('enabling wasi');
// This looks like a broken types issue in the wasi module.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return {
wasi_snapshot_preview1: wasi.getImports(),
wasmrs: linkHostExports(instance),
};
}
else {
debug$1('disabling wasi');
return {
wasmrs: linkHostExports(instance),
};
}
}
class FrameEvent extends Event {
payload;
constructor(type, payload) {
super(type);
this.payload = payload;
}
}
function linkHostExports(instance) {
return {
[HostProtocolMethods.CONSOLE_LOG](ptr, len) {
debug$1('<<< __console_log %o bytes @ %o', len, ptr);
const buffer = new Uint8Array(instance.getCallerMemory().buffer);
const bytes = buffer.slice(ptr, ptr + len);
console.log(instance.textDecoder.decode(bytes));
},
[HostProtocolMethods.INIT_BUFFERS](guestBufferPtr, hostBufferPtr) {
debug$1('<<< __init_buffers(%o, %o)', guestBufferPtr, hostBufferPtr);
instance.guestBufferStart = guestBufferPtr;
instance.hostBufferStart = hostBufferPtr;
},
[HostProtocolMethods.SEND](length) {
debug$1('<<< __send(%o)', length);
const buffer = new Uint8Array(instance.getCallerMemory().buffer);
const bytes = buffer.slice(instance.hostBufferStart, instance.hostBufferStart + length);
debug$1(`'frame' event: ${bytes.length} bytes`, Array.from(bytes)
.map((n) => {
if (n > 16 && n < 127) {
return String.fromCharCode(n);
}
else {
return `\\x${n.toString(16)}`;
}
})
.join(''));
let done = false;
let index = 0;
while (!done) {
const len = fromU24Bytes(bytes.slice(index, 3));
const frame = bytes.slice(index + 3, index + 3 + len);
instance.dispatchEvent(new FrameEvent('frame', frame));
index += 3 + len;
done = index >= bytes.length;
}
},
[HostProtocolMethods.OP_LIST](ptr, length) {
debug$1('<<< __op_list(%o,%o)', ptr, length);
const buffer = new Uint8Array(instance.getCallerMemory().buffer);
const bytes = buffer.slice(ptr, ptr + length);
if (length === 0) {
return;
}
if (bytes.slice(0, 4).toString() !== OP_MAGIC_BYTES.toString()) {
throw new Error('invalid op_list magic bytes');
}
const version = fromU16Bytes(bytes.slice(4, 6));
debug$1(`op_list bytes: %o`, bytes);
if (version == 1) {
const ops = decodeV1Operations(bytes.slice(6), instance.textDecoder);
debug$1('module operations: %o', ops);
instance.operations = ops;
}
},
};
}
function decodeV1Operations(buffer, decoder) {
const imports = [];
const exports = [];
let numOps = fromU32Bytes(buffer.slice(0, 4));
debug$1(`decoding %o operations`, numOps);
let index = 4;
while (numOps > 0) {
const kind = buffer[index++];
const dir = buffer[index++];
const opIndex = fromU32Bytes(buffer.slice(index, index + 4));
index += 4;
const nsLen = fromU16Bytes(buffer.slice(index, index + 2));
index += 2;
const namespace = decoder.decode(buffer.slice(index, index + nsLen));
index += nsLen;
const opLen = fromU16Bytes(buffer.slice(index, index + 2));
index += 2;
const operation = decoder.decode(buffer.slice(index, index + opLen));
index += opLen;
const reservedLen = fromU16Bytes(buffer.slice(index, index + 2));
index += 2 + reservedLen;
const op = new Operation(opIndex, kind, namespace, operation);
if (dir === 1) {
exports.push(op);
}
else {
imports.push(op);
}
numOps--;
}
return new OperationList(imports, exports);
}
class OperationList {
imports;
exports;
constructor(imports, exports) {
this.imports = imports;
this.exports = exports;
}
getExport(namespace, operation) {
const op = this.exports.find((op) => op.namespace === namespace && op.operation === operation);
if (!op) {
throw new Error(`operation ${namespace}::${operation} not found in exports`);
}
return op;
}
getImport(namespace, operation) {
const op = this.imports.find((op) => op.namespace === namespace && op.operation === operation);
if (!op) {
throw new Error(`operation ${namespace}::${operation} not found in imports`);
}
return op;
}
}
class Operation {
index;
kind;
namespace;
operation;
constructor(index, kind, namespace, operation) {
this.index = index;
this.kind = kind;
this.namespace = namespace;
this.operation = operation;
}
asEncoded() {
const index = toU32Bytes(this.index);
const encoded = new Uint8Array(index.length + 4);
encoded.set(index);
encoded.set(toU32Bytes(0), index.length);
return encoded;
}
}
var OperationType;
(function (OperationType) {
OperationType[OperationType["RR"] = 0] = "RR";
OperationType[OperationType["FNF"] = 1] = "FNF";
OperationType[OperationType["RS"] = 2] = "RS";
OperationType[OperationType["RC"] = 3] = "RC";
})(OperationType || (OperationType = {}));
/*
fn decode_v1(mut buf: Bytes) -> Result<Self, Error> {
let num_ops = from_u32_bytes(&buf.split_to(4));
let mut imports = Vec::new();
let mut exports = Vec::new();
for _ in 0..num_ops {
let kind = buf.split_to(1)[0];
let kind: OperationType = kind.into();
let dir = buf.split_to(1)[0];
let index = from_u32_bytes(&buf.split_to(4));
let ns_len = from_u16_bytes(&buf.split_to(2));
let namespace = String::from_utf8(buf.split_to(ns_len as _).to_vec())?;
let op_len = from_u16_bytes(&buf.split_to(2));
let operation = String::from_utf8(buf.split_to(op_len as _).to_vec())?;
let _reserved_len = from_u16_bytes(&buf.split_to(2));
let op = Operation {
index,
kind,
namespace,
operation,
};
if dir == 1 {
exports.push(op);
} else {
imports.push(op);
}
}
Ok(Self { imports, exports })
}
*/
const OP_MAGIC_BYTES = Uint8Array.from([0x00, 0x77, 0x72, 0x73]);
class WASI {
wasi;
constructor(options) {
this.wasi = new wasi.WASI(options);
}
static create(options) {
return Promise.resolve(new WASI(options));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
start(instance) {
this.wasi.start(instance);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
initialize(instance) {
this.wasi.initialize(instance);
}
getImports() {
return this.wasi.wasiImport;
}
}
/* eslint-disable @typescript-eslint/no-explicit-any */
const debug = DEBUG('wasmrs:worker');
class WorkerInstance {
instance;
constructor(instance, scope) {
this.instance = instance;
scope.addEventListener('message', (msg) => {
this.handleMessage(msg);
});
instance.addEventListener('frame', (e) => {
const msg = e;
scope.postMessage(msg.payload);
});
const setupResponse = {
success: true,
operations: instance.operations,
};
debug('started');
scope.postMessage(setupResponse);
}
handleMessage(msg) {
debug('received frame ');
this.instance.send(msg.data);
}
}
function main$1(scope) {
DEBUG.enabled('wasmrs:worker*');
// using {once:true} is inconsistent between node and browser so we need
// to manually add and remove our bound init listener.
const init = async (msg) => {
scope.removeEventListener('message', init);
debug('received init message %o', { wasi: msg.data.wasi });
const mod = WasmRsModule.from(msg.data.module);
const instance = await mod.instantiate({ wasi: msg.data.wasi });
new WorkerInstance(instance, scope);
};
debug('starting');
scope.addEventListener('message', init);
}
WasmRsInstance.setWasi(WASI);
const main = () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
main$1(self);
};
WasmRsInstance.setWasi(WASI);
main();
//# sourceMappingURL=worker-node.js.map