UNPKG

wasmrs-js

Version:

A JavaScript implementation of the RSocket protocol over WebAssembly.

1,181 lines (1,083 loc) 31.5 kB
'use strict'; 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