Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@mercuryworkshop/bare-mux

Package Overview
Dependencies
Maintainers
0
Versions
33
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@mercuryworkshop/bare-mux - npm Package Compare versions

Comparing version 1.1.4 to 2.0.0

dist/baretypes.d.ts

16

dist/index.d.ts

@@ -1,11 +0,9 @@

export * from './BareTypes';
export * from './BareClient';
export * from './Switcher';
export * from './RemoteClient';
export { BareClient as default } from './BareClient';
export * from './baretypes';
export * from './client';
export * from './connection';
export { BareClient as default } from './client';
export { WebSocketFields } from "./snapshot";
export type * from './BareTypes';
export type * from './BareClient';
export type * from './Switcher';
export type * from './RemoteClient';
export type * from './baretypes';
export type * from './client';
export type * from './connection';
export type * from "./snapshot";

@@ -1,405 +0,423 @@

import { v4 } from 'uuid';
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.BareMux = {}));
})(this, (function (exports) { 'use strict';
const maxRedirects = 20;
const maxRedirects = 20;
// The user likely has overwritten all networking functions after importing bare-client
// It is our responsibility to make sure components of Bare-Client are using native networking functions
const fetch = globalThis.fetch;
const WebSocket = globalThis.WebSocket;
const Request = globalThis.Request;
const Response = globalThis.Response;
const WebSocketFields = {
prototype: {
send: WebSocket.prototype.send,
},
CLOSED: WebSocket.CLOSED,
CLOSING: WebSocket.CLOSING,
CONNECTING: WebSocket.CONNECTING,
OPEN: WebSocket.OPEN,
};
// The user likely has overwritten all networking functions after importing bare-client
// It is our responsibility to make sure components of Bare-Client are using native networking functions
const fetch = globalThis.fetch;
const WebSocket = globalThis.WebSocket;
const Request = globalThis.Request;
const Response = globalThis.Response;
const WebSocketFields = {
prototype: {
send: WebSocket.prototype.send,
},
CLOSED: WebSocket.CLOSED,
CLOSING: WebSocket.CLOSING,
CONNECTING: WebSocket.CONNECTING,
OPEN: WebSocket.OPEN,
};
/// <reference lib="WebWorker" />
function registerRemoteListener(channel) {
navigator.serviceWorker.addEventListener("message", async ({ data }) => {
if (data.type === "request") {
const { remote, method, body, headers } = data;
let response = await findSwitcher().active?.request(new URL(remote), method, body, headers, undefined).catch((err) => {
let error = { id: data.id, type: "error", error: err };
console.error(err);
channel.postMessage(error);
});
if (response) {
let transferred = [];
if (response.body instanceof ArrayBuffer || response.body instanceof Blob || response.body instanceof ReadableStream) {
transferred.push(response.body);
}
response.id = data.id;
response.type = "response";
channel.postMessage(response, transferred);
}
}
});
}
let remote;
if ("ServiceWorkerGlobalScope" in self) {
addEventListener("message", async ({ data }) => {
if (data.type === "response") {
let promise = remote.promises.get(data.id);
if (promise.resolve) {
promise.resolve(data);
remote.promises.delete(data.id);
}
}
else if (data.type === "error") {
let promise = remote.promises.get(data.id);
if (promise.reject) {
promise.reject(data.error);
remote.promises.delete(data.id);
}
}
});
}
class RemoteTransport {
canstart = true;
ready = false;
promises = new Map();
constructor() {
if (!("ServiceWorkerGlobalScope" in self)) {
throw new TypeError("Attempt to construct RemoteClient from outside a service worker");
}
}
async init() {
remote = this;
this.ready = true;
}
async meta() { }
async request(remote, method, body, headers, signal) {
let id = v4();
const clients = await self.clients.matchAll();
if (clients.length < 1)
throw new Error("no available clients");
for (const client of clients) {
client.postMessage({
type: "request",
id,
remote: remote.toString(),
method,
body,
headers
});
}
return await new Promise((resolve, reject) => {
this.promises.set(id, { resolve, reject });
});
}
connect(url, origin, protocols, requestHeaders, onopen, onmessage, onclose, onerror) {
throw "why are you calling connect from remoteclient";
}
}
async function searchForPort() {
// @ts-expect-error
const clients = await self.clients.matchAll({ type: "window", includeUncontrolled: true });
const promise = Promise.race([...clients.map((x) => tryGetPort(x)), new Promise((_, reject) => setTimeout(reject, 1000, new Error("")))]);
try {
return await promise;
}
catch {
console.warn("bare-mux: failed to get a bare-mux SharedWorker MessagePort within 1s, retrying");
return await searchForPort();
}
}
function tryGetPort(client) {
let channel = new MessageChannel();
return new Promise(resolve => {
client.postMessage({ type: "getPort", port: channel.port2 }, [channel.port2]);
channel.port1.onmessage = event => {
resolve(event.data);
};
});
}
function createPort(path, channel, registerHandlers) {
const worker = new SharedWorker(path, "bare-mux-worker");
if (registerHandlers) {
// uv removes navigator.serviceWorker so this errors
if (navigator.serviceWorker) {
navigator.serviceWorker.addEventListener("message", event => {
if (event.data.type === "getPort" && event.data.port) {
console.debug("bare-mux: recieved request for port from sw");
const worker = new SharedWorker(path, "bare-mux-worker");
event.data.port.postMessage(worker.port, [worker.port]);
}
});
}
channel.onmessage = (event) => {
if (event.data.type === "getPath") {
console.debug("bare-mux: recieved request for worker path from broadcast channel");
channel.postMessage({ type: "path", path: path });
}
};
}
return worker.port;
}
class WorkerConnection {
constructor(workerPath) {
this.channel = new BroadcastChannel("bare-mux");
this.createChannel(workerPath, true);
}
createChannel(workerPath, inInit) {
// @ts-expect-error
if (self.clients) {
// running in a ServiceWorker
// ask a window for the worker port, register for refreshPort
this.port = searchForPort();
this.channel.onmessage = (event) => {
if (event.data.type === "refreshPort") {
this.port = searchForPort();
}
};
}
else if (workerPath && SharedWorker) {
// running in a window, was passed a workerPath
// create the SharedWorker and help other bare-mux clients get the workerPath
if (!workerPath.startsWith("/") && !workerPath.includes("://"))
throw new Error("Invalid URL. Must be absolute or start at the root.");
this.port = createPort(workerPath, this.channel, inInit);
}
else if (SharedWorker) {
// running in a window, was not passed a workerPath
// ask other bare-mux clients for the workerPath
this.port = new Promise(resolve => {
this.channel.onmessage = (event) => {
if (event.data.type === "path") {
resolve(createPort(event.data.path, this.channel, inInit));
}
};
this.channel.postMessage({ type: "getPath" });
});
}
else {
// SharedWorker does not exist
throw new Error("Unable to get a channel to the SharedWorker.");
}
}
async sendMessage(message, transferable) {
if (this.port instanceof Promise)
this.port = await this.port;
const pingChannel = new MessageChannel();
const pingPromise = new Promise((resolve, reject) => {
pingChannel.port1.onmessage = event => {
if (event.data.type === "pong") {
resolve();
}
};
setTimeout(reject, 1500);
});
this.port.postMessage({ message: { type: "ping" }, port: pingChannel.port2 }, [pingChannel.port2]);
try {
await pingPromise;
}
catch {
console.warn("bare-mux: Failed to get a ping response from the worker within 1.5s. Assuming port is dead.");
this.createChannel();
return await this.sendMessage(message, transferable);
}
const channel = new MessageChannel();
const toTransfer = [channel.port2, ...(transferable || [])];
const promise = new Promise((resolve, reject) => {
channel.port1.onmessage = event => {
const message = event.data;
if (message.type === "error") {
reject(message.error);
}
else {
resolve(message);
}
};
});
this.port.postMessage({ message: message, port: channel.port2 }, toTransfer);
return await promise;
}
}
//@ts-expect-error not installing node types for this one thing
self.BCC_VERSION = "1.1.4";
console.debug("BARE_MUX_VERSION: " + self.BCC_VERSION);
function initTransport(name, config) {
let cl = new ((0, eval)(name))(...config);
cl.initpromise = cl.init();
return cl;
}
class Switcher {
active = null;
channel = new BroadcastChannel("bare-mux");
data = null;
constructor() {
this.channel.addEventListener("message", ({ data: { type, data } }) => {
console.log(`bare-mux: ${type}`, data, `${"ServiceWorker" in globalThis}`);
switch (type) {
case "setremote":
this.active = new RemoteTransport;
break;
case "set":
const { name, config } = data;
this.active = initTransport(name, config);
break;
case "find":
if (this.data) {
this.channel.postMessage(this.data);
}
break;
}
});
}
}
function findSwitcher() {
if ("ServiceWorkerGlobalScope" in globalThis && globalThis.gSwitcher && !globalThis.gSwitcher.active) {
globalThis.gSwitcher.channel.postMessage({ type: "find" });
}
if (globalThis.gSwitcher)
return globalThis.gSwitcher;
if ("ServiceWorkerGlobalScope" in globalThis) {
globalThis.gSwitcher = new Switcher;
globalThis.gSwitcher.channel.postMessage({ type: "find" });
return globalThis.gSwitcher;
}
let _parent = window;
for (let i = 0; i < 20; i++) {
try {
if (_parent == _parent.parent) {
globalThis.gSwitcher = new Switcher;
return globalThis.gSwitcher;
}
_parent = _parent.parent;
if (_parent && _parent["gSwitcher"]) {
console.debug("Found implementation on parent");
globalThis.gSwitcher = _parent["gSwitcher"];
return _parent["gSwitcher"];
}
}
catch (e) {
globalThis.gSwitcher = new Switcher;
globalThis.gSwitcher.channel.postMessage({ type: "find" });
return globalThis.gSwitcher;
}
}
throw "unreachable";
}
findSwitcher();
function SetTransport(name, ...config) {
let switcher = findSwitcher();
switcher.active = initTransport(name, config);
switcher.data = { type: "set", data: { name, config } };
switcher.channel.postMessage(switcher.data);
}
async function SetSingletonTransport(client) {
let switcher = findSwitcher();
await client.init();
switcher.active = client;
switcher.data = { type: "setremote", data: { name: client.constructor.name } };
switcher.channel.postMessage(switcher.data);
}
const validChars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
function validProtocol(protocol) {
for (let i = 0; i < protocol.length; i++) {
const char = protocol[i];
if (!validChars.includes(char)) {
return false;
}
}
return true;
}
// get the unhooked value
Object.getOwnPropertyDescriptor(WebSocket.prototype, 'readyState').get;
const wsProtocols = ['ws:', 'wss:'];
const statusEmpty = [101, 204, 205, 304];
const statusRedirect = [301, 302, 303, 307, 308];
class BareMuxConnection {
constructor(workerPath) {
this.worker = new WorkerConnection(workerPath);
}
async getTransport() {
return (await this.worker.sendMessage({ type: "get" })).name;
}
async setTransport(path, options) {
await this.setManualTransport(`
const { default: BareTransport } = await import("${path}");
return [new BareTransport(${options.map(x => JSON.stringify(x)).join(", ")}), "${path}"];
`);
}
async setManualTransport(functionBody) {
await this.worker.sendMessage({
type: "set",
client: functionBody,
});
}
}
class BareClient {
/**
* Create a BareClient. Calls to fetch and connect will wait for an implementation to be ready.
*/
constructor(workerPath) {
this.worker = new WorkerConnection(workerPath);
}
createWebSocket(remote, protocols = [], webSocketImpl, requestHeaders, arrayBufferImpl) {
try {
remote = new URL(remote);
}
catch (err) {
throw new DOMException(`Faiiled to construct 'WebSocket': The URL '${remote}' is invalid.`);
}
if (!wsProtocols.includes(remote.protocol))
throw new DOMException(`Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss'. '${remote.protocol}' is not allowed.`);
if (!Array.isArray(protocols))
protocols = [protocols];
protocols = protocols.map(String);
for (const proto of protocols)
if (!validProtocol(proto))
throw new DOMException(`Failed to construct 'WebSocket': The subprotocol '${proto}' is invalid.`);
let wsImpl = (webSocketImpl || WebSocket);
const socket = new wsImpl("ws://127.0.0.1:1", protocols);
let fakeProtocol = '';
let fakeReadyState = WebSocketFields.CONNECTING;
let initialErrorHappened = false;
socket.addEventListener("error", (e) => {
if (!initialErrorHappened) {
fakeReadyState = WebSocket.CONNECTING;
e.stopImmediatePropagation();
initialErrorHappened = true;
}
});
let initialCloseHappened = false;
socket.addEventListener("close", (e) => {
if (!initialCloseHappened) {
e.stopImmediatePropagation();
initialCloseHappened = true;
}
});
// TODO socket onerror will be broken
arrayBufferImpl = arrayBufferImpl || wsImpl.constructor.constructor("return ArrayBuffer")().prototype;
requestHeaders = requestHeaders || {};
requestHeaders['Host'] = (new URL(remote)).host;
// requestHeaders['Origin'] = origin;
requestHeaders['Pragma'] = 'no-cache';
requestHeaders['Cache-Control'] = 'no-cache';
requestHeaders['Upgrade'] = 'websocket';
// requestHeaders['User-Agent'] = navigator.userAgent;
requestHeaders['Connection'] = 'Upgrade';
const onopen = (protocol) => {
fakeReadyState = WebSocketFields.OPEN;
fakeProtocol = protocol;
socket.meta = {
headers: {
"sec-websocket-protocol": protocol,
}
}; // what the fuck is a meta
socket.dispatchEvent(new Event("open"));
};
const onmessage = async (payload) => {
if (typeof payload === "string") {
socket.dispatchEvent(new MessageEvent("message", { data: payload }));
}
else if ("byteLength" in payload) {
if (socket.binaryType === "blob") {
payload = new Blob([payload]);
}
else {
Object.setPrototypeOf(payload, arrayBufferImpl);
}
socket.dispatchEvent(new MessageEvent("message", { data: payload }));
}
else if ("arrayBuffer" in payload) {
if (socket.binaryType === "arraybuffer") {
payload = await payload.arrayBuffer();
Object.setPrototypeOf(payload, arrayBufferImpl);
}
socket.dispatchEvent(new MessageEvent("message", { data: payload }));
}
};
const onclose = (code, reason) => {
fakeReadyState = WebSocketFields.CLOSED;
socket.dispatchEvent(new CloseEvent("close", { code, reason }));
};
const onerror = () => {
fakeReadyState = WebSocketFields.CLOSED;
socket.dispatchEvent(new Event("error"));
};
const channel = new MessageChannel();
channel.port1.onmessage = event => {
if (event.data.type === "open") {
onopen(event.data.args[0]);
}
else if (event.data.type === "message") {
onmessage(event.data.args[0]);
}
else if (event.data.type === "close") {
onclose(event.data.args[0], event.data.args[1]);
}
else if (event.data.type === "error") {
onerror( /* event.data.args[0] */);
}
};
this.worker.sendMessage({
type: "websocket",
websocket: {
url: remote.toString(),
origin: origin,
protocols: protocols,
requestHeaders: requestHeaders,
channel: channel.port2,
},
}, [channel.port2]);
// protocol is always an empty before connecting
// updated when we receive the metadata
// this value doesn't change when it's CLOSING or CLOSED etc
const getReadyState = () => fakeReadyState;
// we have to hook .readyState ourselves
Object.defineProperty(socket, 'readyState', {
get: getReadyState,
configurable: true,
enumerable: true,
});
/**
* @returns The error that should be thrown if send() were to be called on this socket according to the fake readyState value
*/
const getSendError = () => {
const readyState = getReadyState();
if (readyState === WebSocketFields.CONNECTING)
return new DOMException("Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.");
};
// we have to hook .send ourselves
// use ...args to avoid giving the number of args a quantity
// no arguments will trip the following error: TypeError: Failed to execute 'send' on 'WebSocket': 1 argument required, but only 0 present.
socket.send = function (...args) {
const error = getSendError();
if (error)
throw error;
let data = args[0];
// @ts-expect-error idk why it errors?
if (data.buffer)
data = data.buffer;
channel.port1.postMessage({ type: "data", data: data }, data instanceof ArrayBuffer ? [data] : []);
};
socket.close = function (code, reason) {
channel.port1.postMessage({ type: "close", closeCode: code, closeReason: reason });
};
Object.defineProperty(socket, 'url', {
get: () => remote.toString(),
configurable: true,
enumerable: true,
});
const getProtocol = () => fakeProtocol;
Object.defineProperty(socket, 'protocol', {
get: getProtocol,
configurable: true,
enumerable: true,
});
return socket;
}
async fetch(url, init) {
// Only create an instance of Request to parse certain parameters of init such as method, headers, redirect
// But use init values whenever possible
const req = new Request(url, init);
// try to use init.headers because it may contain capitalized headers
// furthermore, important headers on the Request class are blocked...
// we should try to preserve the capitalization due to quirks with earlier servers
const inputHeaders = init?.headers || req.headers;
const headers = inputHeaders instanceof Headers
? Object.fromEntries(inputHeaders)
: inputHeaders;
const body = req.body;
let urlO = new URL(req.url);
if (urlO.protocol.startsWith('blob:')) {
const response = await fetch(urlO);
const result = new Response(response.body, response);
result.rawHeaders = Object.fromEntries(response.headers);
result.rawResponse = response;
return result;
}
for (let i = 0;; i++) {
if ('host' in headers)
headers.host = urlO.host;
else
headers.Host = urlO.host;
let resp = (await this.worker.sendMessage({
type: "fetch",
fetch: {
remote: urlO.toString(),
method: req.method,
headers: headers,
body: body || undefined,
},
}, body ? [body] : [])).fetch;
let responseobj = new Response(statusEmpty.includes(resp.status) ? undefined : resp.body, {
headers: new Headers(resp.headers),
status: resp.status,
statusText: resp.statusText,
});
responseobj.rawHeaders = resp.headers;
responseobj.rawResponse = new Response(resp.body);
responseobj.finalURL = urlO.toString();
const redirect = init?.redirect || req.redirect;
if (statusRedirect.includes(responseobj.status)) {
switch (redirect) {
case 'follow': {
const location = responseobj.headers.get('location');
if (maxRedirects > i && location !== null) {
urlO = new URL(location, urlO);
continue;
}
else
throw new TypeError('Failed to fetch');
}
case 'error':
throw new TypeError('Failed to fetch');
case 'manual':
return responseobj;
}
}
else {
return responseobj;
}
}
}
}
/*
* WebSocket helpers
*/
const validChars = "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
function validProtocol(protocol) {
for (let i = 0; i < protocol.length; i++) {
const char = protocol[i];
if (!validChars.includes(char)) {
return false;
}
}
return true;
}
exports.BareClient = BareClient;
exports.BareMuxConnection = BareMuxConnection;
exports.WebSocketFields = WebSocketFields;
exports.WorkerConnection = WorkerConnection;
exports.default = BareClient;
exports.maxRedirects = maxRedirects;
exports.validProtocol = validProtocol;
// get the unhooked value
Object.getOwnPropertyDescriptor(WebSocket.prototype, 'readyState').get;
const wsProtocols = ['ws:', 'wss:'];
const statusEmpty = [101, 204, 205, 304];
const statusRedirect = [301, 302, 303, 307, 308];
class BareClient {
/**
* Create a BareClient. Calls to fetch and connect will wait for an implementation to be ready.
*/
constructor() { }
createWebSocket(remote, protocols = [], webSocketImpl, requestHeaders, arrayBufferImpl) {
let switcher = findSwitcher();
let client = switcher.active;
if (!client)
throw "there are no bare clients";
if (!client.ready)
throw new TypeError('You need to wait for the client to finish fetching the manifest before creating any WebSockets. Try caching the manifest data before making this request.');
try {
remote = new URL(remote);
}
catch (err) {
throw new DOMException(`Faiiled to construct 'WebSocket': The URL '${remote}' is invalid.`);
}
if (!wsProtocols.includes(remote.protocol))
throw new DOMException(`Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss'. '${remote.protocol}' is not allowed.`);
if (!Array.isArray(protocols))
protocols = [protocols];
protocols = protocols.map(String);
for (const proto of protocols)
if (!validProtocol(proto))
throw new DOMException(`Failed to construct 'WebSocket': The subprotocol '${proto}' is invalid.`);
let wsImpl = (webSocketImpl || WebSocket);
const socket = new wsImpl("ws://127.0.0.1:1", protocols);
let fakeProtocol = '';
let fakeReadyState = WebSocketFields.CONNECTING;
let initialErrorHappened = false;
socket.addEventListener("error", (e) => {
if (!initialErrorHappened) {
fakeReadyState = WebSocket.CONNECTING;
e.stopImmediatePropagation();
initialErrorHappened = true;
}
});
let initialCloseHappened = false;
socket.addEventListener("close", (e) => {
if (!initialCloseHappened) {
e.stopImmediatePropagation();
initialCloseHappened = true;
}
});
// TODO socket onerror will be broken
arrayBufferImpl = arrayBufferImpl || webSocketImpl.constructor.constructor("return ArrayBuffer")().prototype;
requestHeaders['Host'] = (new URL(remote)).host;
// requestHeaders['Origin'] = origin;
requestHeaders['Pragma'] = 'no-cache';
requestHeaders['Cache-Control'] = 'no-cache';
requestHeaders['Upgrade'] = 'websocket';
// requestHeaders['User-Agent'] = navigator.userAgent;
requestHeaders['Connection'] = 'Upgrade';
const websocket = client.connect(remote, origin, protocols, requestHeaders, (protocol) => {
fakeReadyState = WebSocketFields.OPEN;
fakeProtocol = protocol;
socket.meta = {
headers: {
"sec-websocket-protocol": protocol,
}
}; // what the fuck is a meta
socket.dispatchEvent(new Event("open"));
}, async (payload) => {
if (typeof payload === "string") {
socket.dispatchEvent(new MessageEvent("message", { data: payload }));
}
else if ("byteLength" in payload) {
if (socket.binaryType === "blob") {
payload = new Blob([payload]);
}
else {
Object.setPrototypeOf(payload, arrayBufferImpl);
}
socket.dispatchEvent(new MessageEvent("message", { data: payload }));
}
else if ("arrayBuffer" in payload) {
if (socket.binaryType === "arraybuffer") {
payload = await payload.arrayBuffer();
Object.setPrototypeOf(payload, arrayBufferImpl);
}
socket.dispatchEvent(new MessageEvent("message", { data: payload }));
}
}, (code, reason) => {
fakeReadyState = WebSocketFields.CLOSED;
socket.dispatchEvent(new CloseEvent("close", { code, reason }));
}, () => {
fakeReadyState = WebSocketFields.CLOSED;
socket.dispatchEvent(new Event("error"));
});
const sendData = websocket[0];
const close = websocket[1];
// protocol is always an empty before connecting
// updated when we receive the metadata
// this value doesn't change when it's CLOSING or CLOSED etc
const getReadyState = () => fakeReadyState;
// we have to hook .readyState ourselves
Object.defineProperty(socket, 'readyState', {
get: getReadyState,
configurable: true,
enumerable: true,
});
/**
* @returns The error that should be thrown if send() were to be called on this socket according to the fake readyState value
*/
const getSendError = () => {
const readyState = getReadyState();
if (readyState === WebSocketFields.CONNECTING)
return new DOMException("Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.");
};
// we have to hook .send ourselves
// use ...args to avoid giving the number of args a quantity
// no arguments will trip the following error: TypeError: Failed to execute 'send' on 'WebSocket': 1 argument required, but only 0 present.
socket.send = function (...args) {
const error = getSendError();
if (error)
throw error;
sendData(args[0]);
};
socket.close = function (code, reason) {
close(code, reason);
};
Object.defineProperty(socket, 'url', {
get: () => remote.toString(),
configurable: true,
enumerable: true,
});
const getProtocol = () => fakeProtocol;
Object.defineProperty(socket, 'protocol', {
get: getProtocol,
configurable: true,
enumerable: true,
});
return socket;
}
async fetch(url, init) {
// Only create an instance of Request to parse certain parameters of init such as method, headers, redirect
// But use init values whenever possible
const req = new Request(url, init);
// try to use init.headers because it may contain capitalized headers
// furthermore, important headers on the Request class are blocked...
// we should try to preserve the capitalization due to quirks with earlier servers
const inputHeaders = init?.headers || req.headers;
const headers = inputHeaders instanceof Headers
? Object.fromEntries(inputHeaders)
: inputHeaders;
const body = init?.body || req.body;
let urlO = new URL(req.url);
if (urlO.protocol.startsWith('blob:')) {
const response = await fetch(urlO);
const result = new Response(response.body, response);
result.rawHeaders = Object.fromEntries(response.headers);
result.rawResponse = response;
return result;
}
let switcher = findSwitcher();
if (!switcher.active) {
// in race conditions we trust
await new Promise(r => setTimeout(r, 1000));
switcher = findSwitcher();
}
if (!switcher.active)
throw "there are no bare clients";
const client = switcher.active;
if (!client.ready)
await client.init();
for (let i = 0;; i++) {
if ('host' in headers)
headers.host = urlO.host;
else
headers.Host = urlO.host;
let resp = await client.request(urlO, req.method, body, headers, req.signal);
let responseobj = new Response(statusEmpty.includes(resp.status) ? undefined : resp.body, {
headers: new Headers(resp.headers),
status: resp.status,
statusText: resp.statusText,
});
responseobj.rawHeaders = resp.headers;
responseobj.rawResponse = new Response(resp.body);
responseobj.finalURL = urlO.toString();
const redirect = init?.redirect || req.redirect;
if (statusRedirect.includes(responseobj.status)) {
switch (redirect) {
case 'follow': {
const location = responseobj.headers.get('location');
if (maxRedirects > i && location !== null) {
urlO = new URL(location, urlO);
continue;
}
else
throw new TypeError('Failed to fetch');
}
case 'error':
throw new TypeError('Failed to fetch');
case 'manual':
return responseobj;
}
}
else {
return responseobj;
}
}
}
}
Object.defineProperty(exports, '__esModule', { value: true });
export { BareClient, SetSingletonTransport, SetTransport, WebSocketFields, BareClient as default, findSwitcher, maxRedirects, registerRemoteListener };
}));
//# sourceMappingURL=index.js.map

@@ -30,8 +30,9 @@ export declare const fetch: typeof globalThis.fetch;

};
export declare const SharedWorker: {
new (scriptURL: string | URL, options?: string | WorkerOptions): SharedWorker;
prototype: SharedWorker;
};
export declare const WebSocketFields: {
prototype: {
send: {
(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;
(data: string | ArrayBufferLike | Blob | ArrayBufferView): void;
};
send: (data: string | ArrayBufferLike | Blob | ArrayBufferView) => void;
};

@@ -38,0 +39,0 @@ CLOSED: 3;

declare const baremuxPath: string;
export { baremuxPath };
export { baremuxPath };
{
"name": "@mercuryworkshop/bare-mux",
"version": "1.1.4",
"version": "2.0.0",
"description": "",
"type": "module",
"author": "",
"main": "dist/index.cjs",
"types": "dist/index.d.ts",
"files": [
"dist",
"lib"
],
"exports": {
".": {
"import": "./dist/index.js",
"require": "./dist/bare.cjs",
"import": "./dist/module.js",
"require": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./node": {
"types": "./lib/index.d.ts",
"import": "./lib/index.cjs",
"require": "./lib/index.cjs"
"require": "./lib/index.cjs",
"types": "./lib/index.d.ts"
}
},
"files": [
"dist",
"lib"
],
"devDependencies": {
"@rollup/plugin-inject": "^5.0.5",
"esbuild": "^0.19.11",
"esbuild-plugin-d.ts": "^1.2.2",
"@rollup/plugin-replace": "^5.0.5",
"rollup": "^4.9.6",
"rollup-plugin-typescript2": "^0.36.0",
"@rollup/plugin-replace": "^5.0.5"
"rollup-plugin-typescript2": "^0.36.0"
},
"dependencies": {
"@types/uuid": "^9.0.8",
"uuid": "^9.0.1"
},
"scripts": {
"build": "rollup -c"
"build": "rollup -c",
"watch": "rollup -cw"
}
}

@@ -40,10 +40,19 @@ # Bare-Mux

To switch between transports, use the `SetTransport` function.
Here is an example of using bare-mux:
```js
import { SetTransport } from '@mercuryworkshop/bare-mux';
/// As an end-user
import { BareMuxConnection } from "@mercuryworkshop/bare-mux";
const conn = new BareMuxConnection("/bare-mux/worker.js");
SetTransport("EpxMod.EpoxyClient", { wisp: "wss://wisp.mercurywork.shop" });
SetTransport("BareMod.BareClient", "https://some-bare-server.com");
// Set Bare-Client transport
// If your transport is an ES module and exports the class as the default export
await conn.setTransport("/bare-mux/transport-module.js", ["arg1", "ws://localhost:4000"]);
/// As a proxy developer
import { BareClient } from "@mercuryworkshop/bare-mux";
const client = new BareClient();
// Fetch
const resp = await client.fetch("https://example.com");
// Create websocket
const ws = client.createWebSocket("wss://echo.websocket.events");
```
If not using a bundler, extract the npm package in releases, and include the `bare.cjs` file and call `BareMux.SetTransport`.

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc