tcpip 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/chunk-DVPTIOIV.cjs +2 -0
- package/dist/chunk-DVPTIOIV.cjs.map +1 -0
- package/dist/chunk-T54CGJHW.js +2 -0
- package/dist/chunk-T54CGJHW.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -121
- package/dist/index.d.ts +20 -121
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/types.cjs +2 -0
- package/dist/types.cjs.map +1 -0
- package/dist/types.d.cts +120 -0
- package/dist/types.d.ts +120 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +32 -23
- package/tcpip.wasm +0 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});var d=(b,o)=>(o=Symbol[b])?o:Symbol.for("Symbol."+b),t=b=>{throw TypeError(b)};var a=(b,o,e)=>{if(o!=null){typeof o!="object"&&typeof o!="function"&&t("Object expected");var i,l;e&&(i=o[d("asyncDispose")]),i===void 0&&(i=o[d("dispose")],e&&(l=i)),typeof i!="function"&&t("Object not disposable"),l&&(i=function(){try{l.call(this)}catch(m){return Promise.reject(m)}}),b.push([e,i,o])}else e&&b.push([e]);return o},c= exports.b =(b,o,e)=>{var i=typeof SuppressedError=="function"?SuppressedError:function(s,S,p,y){return y=Error(p),y.name="SuppressedError",y.error=s,y.suppressed=S,y},l=s=>o=e?new i(s,o,"An error was suppressed during disposal"):(e=!0,s),m=s=>{for(;s=b.pop();)try{var S=s[1]&&s[1].call(s[2]);if(s[0])return Promise.resolve(S).then(m,p=>(l(p),m()))}catch(p){l(p)}if(e)throw o};return m()};var r="dispose"in Symbol?Symbol.dispose:Symbol.for("Symbol.dispose");exports.a = a; exports.b = c; exports.c = r;
|
|
2
|
+
//# sourceMappingURL=chunk-DVPTIOIV.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/tcpip.js/tcpip.js/packages/tcpip/dist/chunk-DVPTIOIV.cjs","../polyfills/disposable.ts"],"names":["DisposeSymbol"],"mappings":"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","file":"/home/runner/work/tcpip.js/tcpip.js/packages/tcpip/dist/chunk-DVPTIOIV.cjs","sourcesContent":[null,"/**\n * Scoped polyfill for `Symbol.dispose` without polluting the global scope.\n * Required for the `using` keyword which we use internally.\n *\n * We export this symbol as 'Symbol.dispose' which tells ESBuild to inject\n * it into the output bundle.\n *\n * The below works because Typescript's `using` implementation falls back to\n * `Symbol.for(\"Symbol.dispose\")` if the built-in `Symbol.dispose` is not available.\n */\n\nconst DisposeSymbol =\n 'dispose' in (Symbol as object)\n ? Symbol.dispose\n : Symbol.for('Symbol.dispose');\n\nexport { DisposeSymbol as 'Symbol.dispose' };\n"]}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var d=(b,o)=>(o=Symbol[b])?o:Symbol.for("Symbol."+b),t=b=>{throw TypeError(b)};var a=(b,o,e)=>{if(o!=null){typeof o!="object"&&typeof o!="function"&&t("Object expected");var i,l;e&&(i=o[d("asyncDispose")]),i===void 0&&(i=o[d("dispose")],e&&(l=i)),typeof i!="function"&&t("Object not disposable"),l&&(i=function(){try{l.call(this)}catch(m){return Promise.reject(m)}}),b.push([e,i,o])}else e&&b.push([e]);return o},c=(b,o,e)=>{var i=typeof SuppressedError=="function"?SuppressedError:function(s,S,p,y){return y=Error(p),y.name="SuppressedError",y.error=s,y.suppressed=S,y},l=s=>o=e?new i(s,o,"An error was suppressed during disposal"):(e=!0,s),m=s=>{for(;s=b.pop();)try{var S=s[1]&&s[1].call(s[2]);if(s[0])return Promise.resolve(S).then(m,p=>(l(p),m()))}catch(p){l(p)}if(e)throw o};return m()};var r="dispose"in Symbol?Symbol.dispose:Symbol.for("Symbol.dispose");export{a,c as b,r as c};
|
|
2
|
+
//# sourceMappingURL=chunk-T54CGJHW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../polyfills/disposable.ts"],"sourcesContent":["/**\n * Scoped polyfill for `Symbol.dispose` without polluting the global scope.\n * Required for the `using` keyword which we use internally.\n *\n * We export this symbol as 'Symbol.dispose' which tells ESBuild to inject\n * it into the output bundle.\n *\n * The below works because Typescript's `using` implementation falls back to\n * `Symbol.for(\"Symbol.dispose\")` if the built-in `Symbol.dispose` is not available.\n */\n\nconst DisposeSymbol =\n 'dispose' in (Symbol as object)\n ? Symbol.dispose\n : Symbol.for('Symbol.dispose');\n\nexport { DisposeSymbol as 'Symbol.dispose' };\n"],"mappings":"wxBAWA,IAAMA,EACJ,YAAc,OACV,OAAO,QACP,OAAO,IAAI,gBAAgB","names":["DisposeSymbol"]}
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10;var Y=(o,e)=>(e=Symbol[o])?e:Symbol.for("Symbol."+o),J=o=>{throw TypeError(o)};var p=(o,e,r)=>{if(e!=null){typeof e!="object"&&typeof e!="function"&&J("Object expected");var t,n;r&&(t=e[Y("asyncDispose")]),t===void 0&&(t=e[Y("dispose")],r&&(n=t)),typeof t!="function"&&J("Object not disposable"),n&&(t=function(){try{n.call(this)}catch(s){return Promise.reject(s)}}),o.push([r,t,e])}else r&&o.push([r]);return e},f=(o,e,r)=>{var t=typeof SuppressedError=="function"?SuppressedError:function(a,i,c,d){return d=Error(c),d.name="SuppressedError",d.error=a,d.suppressed=i,d},n=a=>e=r?new t(a,e,"An error was suppressed during disposal"):(r=!0,a),s=a=>{for(;a=o.pop();)try{var i=a[1]&&a[1].call(a[2]);if(a[0])return Promise.resolve(i).then(s,c=>(n(c),s()))}catch(c){n(c)}if(r)throw e};return s()};var y="dispose"in Symbol?Symbol.dispose:Symbol.for("Symbol.dispose");var _browser_wasi_shim = require('@bjorn3/browser_wasi_shim');var _dns = require('@tcpip/dns');var _wire = require('@tcpip/wire');var l=class{#e=new WeakMap;#t=new WeakMap;setOuter(e,r){this.#e.set(e,r)}setInner(e,r){this.#t.set(e,r)}getOuter(e){let r=this.#e.get(e);if(!r)throw new Error(`outer hooks not set for ${e}`);return r}getInner(e){let r=this.#t.get(e);if(!r)throw new Error(`inner hooks not set for ${e}`);return r}},R=class extends Number{constructor(e,r){super(e),this.free=r}[y](){this.free(this.valueOf())}},P=class extends Map{#e=new Map;wait(e){return new Promise(r=>{let t=_nullishCoalesce(this.#e.get(e), () => (new Set));t.add(r),this.#e.set(e,t)})}set(e,r){super.set(e,r);let t=this.#e.get(e);if(t)for(let n of t)n(r),t.delete(n);return this}};function w(o,e){let r=o.getReader();return ie(r,e)}async function*ie(o,e){try{for(;;){let{done:r,value:t}=await o.read();if(r)return t;yield t}}finally{_optionalChain([e, 'optionalAccess', _2 => _2.preventCancel])||await o.cancel(),o.releaseLock()}}var T=class extends ReadableStream{#e;constructor({lock:e,...r},t){super(r,t),this.#e=e}getReader(){let e=super.getReader();return this.locked&&_optionalChain([this, 'access', _3 => _3.#e, 'optionalCall', _4 => _4()]),e}pipeThrough(e,r){let t=super.pipeThrough(e,r);return this.locked&&_optionalChain([this, 'access', _5 => _5.#e, 'optionalCall', _6 => _6()]),t}pipeTo(e,r){let t=super.pipeTo(e,r);return this.locked&&_optionalChain([this, 'access', _7 => _7.#e, 'optionalCall', _8 => _8()]),t}tee(){let[e,r]=super.tee();return this.locked&&_optionalChain([this, 'access', _9 => _9.#e, 'optionalCall', _10 => _10()]),[e,r]}};async function g(){return await new Promise(o=>queueMicrotask(o))}var u=class{#e;get exports(){if(!this.#e)throw new Error("exports were not registered");return this.#e}register(e){this.#e=e}smartMalloc(e){return new R(this.exports.malloc(e),this.exports.free)}copyToMemory(e){let r=new Uint8Array(e),t=r.length,n=this.smartMalloc(t);return new Uint8Array(this.exports.memory.buffer,n.valueOf(),t).set(r),n}copyFromMemory(e,r){let t=this.exports.memory.buffer.slice(Number(e),Number(e)+r);return new Uint8Array(t)}viewFromMemory(e,r){return new Uint8Array(this.exports.memory.buffer,Number(e),r)}};var A={ERR_OK:0,ERR_MEM:-1,ERR_BUF:-2,ERR_TIMEOUT:-3,ERR_RTE:-4,ERR_INPROGRESS:-5,ERR_VAL:-6,ERR_WOULDBLOCK:-7,ERR_USE:-8,ERR_ALREADY:-9,ERR_ISCONN:-10,ERR_CONN:-11,ERR_IF:-12,ERR_ABRT:-13,ERR_RST:-14,ERR_CLSD:-15,ERR_ARG:-16};var k=new l,O= (_class =class extends u{constructor(...args) { super(...args); _class.prototype.__init.call(this);_class.prototype.__init2.call(this); }__init() {this.interfaces=new Map}__init2() {this.imports={register_tap_interface:e=>{let r=new F;k.setOuter(r,{handle:e,sendFrame:t=>{let n=this.copyToMemory(t),s=this.exports.send_tap_interface(e,n,t.length);if(s!==A.ERR_OK)throw new Error(`failed to send frame: ${s}`)},getMacAddress:()=>{let t=this.exports.get_interface_mac_address(e),n=this.viewFromMemory(t,6);return _wire.parseMacAddress.call(void 0, n)},getIPv4Address:()=>{let t=this.exports.get_interface_ip4_address(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)},getIPv4Netmask:()=>{let t=this.exports.get_interface_ip4_netmask(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)}}),this.interfaces.set(e,r)},receive_frame:async(e,r,t)=>{let n=this.copyFromMemory(r,t);await g();let s=this.interfaces.get(e);if(!s){console.error("received frame on unknown tap interface");return}k.getInner(s).receiveFrame(new Uint8Array(n))}}}async create(e){var m=[];try{let r=e.mac?_wire.serializeMacAddress.call(void 0, e.mac):_wire.generateMacAddress.call(void 0, );let{ipAddress:t,netmask:n}=e.ip?_wire.serializeIPv4Cidr.call(void 0, e.ip):{};let s=p(m,this.copyToMemory(r));let a=p(m,t?this.copyToMemory(t):void 0);let i=p(m,n?this.copyToMemory(n):void 0);let c=this.exports.create_tap_interface(s,_nullishCoalesce(a, () => (0)),_nullishCoalesce(i, () => (0)));let d=this.interfaces.get(c);if(!d)throw new Error("tap interface failed to register");return d}catch(h){var b=h,_=!0}finally{f(m,b,_)}}async remove(e){for(let[r,t]of this.interfaces.entries())if(t===e){this.exports.remove_tap_interface(r),this.interfaces.delete(r);return}}}, _class),F= (_class2 =class{#e;#t=!1;__init3() {this.type="tap"}get mac(){return k.getOuter(this).getMacAddress()}get ip(){return k.getOuter(this).getIPv4Address()}get netmask(){return k.getOuter(this).getIPv4Netmask()}constructor(){;_class2.prototype.__init3.call(this);k.setInner(this,{receiveFrame:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");this.#e.enqueue(e)}}}),this.readable=new T({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{try{k.getOuter(this).sendFrame(e)}catch(r){console.error("tap interface send failed",r)}}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return w(this.readable)}[Symbol.asyncIterator](){return this.listen()}}, _class2);var U=new l,E= (_class3 =class extends u{constructor(...args2) { super(...args2); _class3.prototype.__init4.call(this);_class3.prototype.__init5.call(this); }__init4() {this.interfaces=new Map}__init5() {this.imports={}}async create(e){var b=[];try{let r=e.mac?_wire.serializeMacAddress.call(void 0, e.mac):_wire.generateMacAddress.call(void 0, );let{ipAddress:t,netmask:n}=e.ip?_wire.serializeIPv4Cidr.call(void 0, e.ip):{};let s=p(b,this.copyToMemory(r));let a=p(b,t?this.copyToMemory(t):void 0);let i=p(b,n?this.copyToMemory(n):void 0);let c=new Uint32Array(e.ports.map(I=>Number(k.getOuter(I).handle)));let d=p(b,this.copyToMemory(c.buffer));let m=this.exports.create_bridge_interface(s,_nullishCoalesce(a, () => (0)),_nullishCoalesce(i, () => (0)),d,e.ports.length);let h=new j;U.setOuter(h,{handle:m,getMacAddress:()=>{let I=this.exports.get_interface_mac_address(m),S=this.viewFromMemory(I,6);return _wire.parseMacAddress.call(void 0, S)},getIPv4Address:()=>{let I=this.exports.get_interface_ip4_address(m);if(I===0)return;let S=this.viewFromMemory(I,4);return _wire.parseIPv4Address.call(void 0, S)},getIPv4Netmask:()=>{let I=this.exports.get_interface_ip4_netmask(m);if(I===0)return;let S=this.viewFromMemory(I,4);return _wire.parseIPv4Address.call(void 0, S)}});this.interfaces.set(m,h);return h}catch(_){var W=_,D=!0}finally{f(b,W,D)}}async remove(e){for(let[r,t]of this.interfaces.entries())if(t===e){this.exports.remove_bridge_interface(r),this.interfaces.delete(r);return}}}, _class3),j= (_class4 =class{constructor() { _class4.prototype.__init6.call(this); }__init6() {this.type="bridge"}get mac(){return U.getOuter(this).getMacAddress()}get ip(){return U.getOuter(this).getIPv4Address()}get netmask(){return U.getOuter(this).getIPv4Netmask()}}, _class4);var z=new l,C= (_class5 =class extends u{constructor(...args3) { super(...args3); _class5.prototype.__init7.call(this);_class5.prototype.__init8.call(this); }__init7() {this.interfaces=new Map}__init8() {this.imports={register_loopback_interface:e=>{let r=new K;z.setOuter(r,{handle:e,getIPv4Address:()=>{let t=this.exports.get_interface_ip4_address(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)},getIPv4Netmask:()=>{let t=this.exports.get_interface_ip4_netmask(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)}}),this.interfaces.set(e,r)}}}async create(e){var c=[];try{let{ipAddress:r,netmask:t}=e.ip?_wire.serializeIPv4Cidr.call(void 0, e.ip):{};let n=p(c,r?this.copyToMemory(r):void 0);let s=p(c,t?this.copyToMemory(t):void 0);let a=this.exports.create_loopback_interface(_nullishCoalesce(n, () => (0)),_nullishCoalesce(s, () => (0)));let i=this.interfaces.get(a);if(!i)throw new Error("loopback interface failed to register");return i}catch(d){var m=d,h=!0}finally{f(c,m,h)}}async remove(e){for(let[r,t]of this.interfaces.entries())if(t===e){this.exports.remove_loopback_interface(r),this.interfaces.delete(r);return}}}, _class5),K= (_class6 =class{constructor() { _class6.prototype.__init9.call(this); }__init9() {this.type="loopback"}get ip(){return z.getOuter(this).getIPv4Address()}get netmask(){return z.getOuter(this).getIPv4Netmask()}}, _class6);var q=new l,v=new l,G=1460,at=G*4,it=G*4,Ie=G,M= (_class7 =class extends u{#e=new Map;#t=new P;#r=new Map;#n;async#s(e){try{return _wire.serializeIPv4Address.call(void 0, e)}catch (e2){let t=await this.#n.lookup(e);return _wire.serializeIPv4Address.call(void 0, t)}}constructor(e){super();_class7.prototype.__init10.call(this);,this.#n=e}__init10() {this.imports={accept_tcp_connection:async(e,r)=>{let t=this.#e.get(e);if(!t){console.error("new tcp connection to unknown listener");return}await g();let n=new L;v.setOuter(n,{send:async s=>{let a=Number(this.copyToMemory(s)),i=this.exports.send_tcp_chunk(r,a,s.length);for(;i<s.length;){await new Promise(d=>{this.#r.set(r,d)});let c=s.length-i;i+=this.exports.send_tcp_chunk(r,a+i,c)}},updateReceiveBuffer:s=>{this.exports.update_tcp_receive_buffer(r,s)},close:async()=>{let s=this.exports.close_tcp_connection(r);if(s!==A.ERR_OK)throw new Error(`failed to close tcp connection: ${s}`)}}),this.#t.set(r,n),q.getInner(t).accept(n)},connected_tcp_connection:async e=>{await g();let r=new L;v.setOuter(r,{send:async t=>{let n=Number(this.copyToMemory(t)),s=this.exports.send_tcp_chunk(e,n,t.length);for(;s<t.length;){await new Promise(i=>{this.#r.set(e,i)});let a=t.length-s;s+=this.exports.send_tcp_chunk(e,n+s,a)}},updateReceiveBuffer:t=>{this.exports.update_tcp_receive_buffer(e,t)},close:async()=>{this.exports.close_tcp_connection(e)}}),this.#t.set(e,r)},closed_tcp_connection:async e=>{let r=this.#t.get(e);if(!r){console.error("received close on unknown tcp connection");return}await v.getInner(r).close()},receive_tcp_chunk:async(e,r,t)=>{let n=this.copyFromMemory(r,t),s=this.#t.get(e);if(!s){console.error("received chunk on unknown tcp connection");return}await g(),v.getInner(s).receive(new Uint8Array(n))},sent_tcp_chunk:(e,r)=>{let t=this.#r.get(e);this.#r.delete(e),_optionalChain([t, 'optionalCall', _12 => _12(r)])}}}async listen(e){var s=[];try{let r=p(s,e.host?this.copyToMemory(await this.#s(e.host)):null);let t=this.exports.create_tcp_listener(r,e.port);let n=new $;q.setOuter(n,{});this.#e.set(t,n);return n}catch(a){var i=a,c=!0}finally{f(s,i,c)}}async connect(e){var s=[];try{let r=p(s,this.copyToMemory(await this.#s(e.host)));let t=this.exports.create_tcp_connection(r,e.port);let n=await this.#t.wait(t);if(!n)throw new Error("tcp failed to connect");return n}catch(a){var i=a,c=!0}finally{f(s,i,c)}}}, _class7),$=class{#e=[];#t;constructor(){q.setInner(this,{accept:async e=>{this.#e.push(e),_optionalChain([this, 'access', _13 => _13.#t, 'optionalCall', _14 => _14()])}})}async*[Symbol.asyncIterator](){for(;;)await new Promise(e=>{this.#t=e}),yield*this.#e,this.#e=[]}},L=class{#e=[];#t;#r;constructor(){v.setInner(this,{receive:async e=>{this.#e.push(e),this.#n()},close:async()=>{this.close()}}),this.readable=new ReadableStream({start:e=>{this.#t=e},pull:()=>{this.#n()}},{highWaterMark:Ie,size:e=>e.byteLength}),this.writable=new WritableStream({start:e=>{this.#r=e},write:async e=>{await v.getOuter(this).send(e)}},{highWaterMark:0})}#n(){if(!_optionalChain([this, 'access', _15 => _15.#t, 'optionalAccess', _16 => _16.desiredSize]))return;let e=0;for(;this.#e.length>0;){let r=this.#e[0].length;if(e+r>this.#t.desiredSize)break;let t=this.#e.shift();this.#t.enqueue(t),e+=t.length}e>0&&v.getOuter(this).updateReceiveBuffer(e)}async close(){await v.getOuter(this).close(),_optionalChain([this, 'access', _17 => _17.#t, 'optionalAccess', _18 => _18.error, 'call', _19 => _19(new Error("tcp connection closed"))]),_optionalChain([this, 'access', _20 => _20.#r, 'optionalAccess', _21 => _21.error, 'call', _22 => _22(new Error("tcp connection closed"))])}[Symbol.asyncIterator](){if(this.readable.locked)throw new Error("readable stream already locked");return w(this.readable)}};var x=new l,B= (_class8 =class extends u{constructor(...args4) { super(...args4); _class8.prototype.__init11.call(this);_class8.prototype.__init12.call(this); }__init11() {this.interfaces=new Map}__init12() {this.imports={register_tun_interface:e=>{let r=new Q;x.setOuter(r,{handle:e,sendPacket:t=>{let n=this.copyToMemory(t);this.exports.send_tun_interface(e,n,t.length)},getIPv4Address:()=>{let t=this.exports.get_interface_ip4_address(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)},getIPv4Netmask:()=>{let t=this.exports.get_interface_ip4_netmask(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)}}),this.interfaces.set(e,r)},receive_packet:async(e,r,t)=>{let n=this.copyFromMemory(r,t);await g();let s=this.interfaces.get(e);if(!s){console.error("received packet on unknown tun interface");return}x.getInner(s).receivePacket(new Uint8Array(n))}}}async create(e){var c=[];try{let{ipAddress:r,netmask:t}=e.ip?_wire.serializeIPv4Cidr.call(void 0, e.ip):{};let n=p(c,r?this.copyToMemory(r):void 0);let s=p(c,t?this.copyToMemory(t):void 0);let a=this.exports.create_tun_interface(_nullishCoalesce(n, () => (0)),_nullishCoalesce(s, () => (0)));let i=this.interfaces.get(a);if(!i)throw new Error("tun interface failed to register");return i}catch(d){var m=d,h=!0}finally{f(c,m,h)}}async remove(e){for(let[r,t]of this.interfaces.entries())if(t===e){this.exports.remove_tun_interface(r),this.interfaces.delete(r);return}}}, _class8),Q= (_class9 =class{#e;#t=!1;__init13() {this.type="tun"}get ip(){return x.getOuter(this).getIPv4Address()}get netmask(){return x.getOuter(this).getIPv4Netmask()}constructor(){;_class9.prototype.__init13.call(this);x.setInner(this,{receivePacket:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");_optionalChain([this, 'access', _23 => _23.#e, 'optionalAccess', _24 => _24.enqueue, 'call', _25 => _25(e)])}}}),this.readable=new T({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{x.getOuter(this).sendPacket(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return w(this.readable)}[Symbol.asyncIterator](){return this.listen()}}, _class9);var H=new l,N= (_class10 =class extends u{#e=new P;#t;async#r(e){try{return _wire.serializeIPv4Address.call(void 0, e)}catch (e3){let t=await this.#t.lookup(e);return _wire.serializeIPv4Address.call(void 0, t)}}constructor(e){super();_class10.prototype.__init14.call(this);,this.#t=e}__init14() {this.imports={receive_udp_datagram:async(e,r,t,n,s)=>{let a=this.copyFromMemory(r,4),i=this.copyFromMemory(n,s),c=this.#e.get(e);if(!c){console.error("received datagram on unknown udp socket");return}await g(),H.getInner(c).receive({host:_wire.parseIPv4Address.call(void 0, a),port:t,data:i})}}}async open(e){var s=[];try{let r=p(s,e.host?this.copyToMemory(await this.#r(e.host)):null);let t=this.exports.open_udp_socket(r,_nullishCoalesce(e.port, () => (0)));if(Number(t)===0)throw new Error("failed to open udp socket");let n=new Z;H.setOuter(n,{send:async d=>{var _=[];try{let m=p(_,this.copyToMemory(await this.#r(d.host)));let h=p(_,this.copyToMemory(d.data));let b=this.exports.send_udp_datagram(t,m,d.port,h,d.data.length);if(b!==A.ERR_OK)throw new Error(`failed to send udp datagram: ${b}`)}catch(W){var D=W,I=!0}finally{f(_,D,I)}},close:async()=>{this.exports.close_udp_socket(t),this.#e.delete(t)}});this.#e.set(t,n);return n}catch(a){var i=a,c=!0}finally{f(s,i,c)}}}, _class10),Z=class{#e;#t;constructor(){H.setInner(this,{receive:async e=>{if(!this.#e)throw new Error("readable controller not initialized");this.#e.enqueue(e)}}),this.readable=new ReadableStream({start:e=>{this.#e=e}}),this.writable=new WritableStream({start:e=>{this.#t=e},write:async e=>{await H.getOuter(this).send(e)}})}async close(){await H.getOuter(this).close(),_optionalChain([this, 'access', _26 => _26.#e, 'optionalAccess', _27 => _27.error, 'call', _28 => _28(new Error("udp socket closed"))]),_optionalChain([this, 'access', _29 => _29.#t, 'optionalAccess', _30 => _30.error, 'call', _31 => _31(new Error("udp socket closed"))])}[Symbol.asyncIterator](){if(this.readable.locked)throw new Error("readable stream already locked");return w(this.readable)}};var ke=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";async function oe(o,e){return ke?we(o,e):fetch(o)}async function we(o,e){let r=await Promise.resolve().then(() => _interopRequireWildcard(require("fs"))),{Readable:t}=await Promise.resolve().then(() => _interopRequireWildcard(require("stream"))),n=r.createReadStream(o),s=t.toWeb(n);return new Response(s,{headers:{"Content-Type":e}})}async function Ae(o){let e=new X(o);return await e.ready,e}var X=class{#e;#t;#r;#n;#s;#o;#a;#i;#c;get interfaces(){return this.#d()}constructor(e={}){this.#e={...e,initializeLoopback:_nullishCoalesce(e.initializeLoopback, () => (!0))},this.#r=new (0, _dns.DnsClient)(this,{nameServer:_nullishCoalesce(e.nameServer, () => ({ip:"127.0.0.1",port:53}))}),this.#n=new C,this.#s=new B,this.#o=new O,this.#a=new E,this.#i=new M(this.#r),this.#c=new N(this.#r),this.ready=this.#p(),this.ready.then(async()=>{this.#e.initializeLoopback&&await this.createLoopbackInterface({ip:"127.0.0.1/8"})})}async#p(){let e=new (0, _browser_wasi_shim.WASI)([],[],[new (0, _browser_wasi_shim.OpenFile)(new (0, _browser_wasi_shim.File)([])),_browser_wasi_shim.ConsoleStdout.lineBuffered(s=>console.log(`[WASI stdout] ${s}`)),_browser_wasi_shim.ConsoleStdout.lineBuffered(s=>console.warn(`[WASI stderr] ${s}`))]),r=oe(new URL("../tcpip.wasm",import.meta.url),"application/wasm"),{instance:t}=await WebAssembly.instantiateStreaming(r,{wasi_snapshot_preview1:e.wasiImport,env:{...this.#n.imports,...this.#s.imports,...this.#o.imports,...this.#a.imports,...this.#i.imports,...this.#c.imports}}),n=t;this.#n.register(n.exports),this.#s.register(n.exports),this.#o.register(n.exports),this.#a.register(n.exports),this.#i.register(n.exports),this.#c.register(n.exports),e.initialize(n),this.#t=Number(setInterval(()=>{n.exports.process_queued_packets(),n.exports.process_timeouts()},100))}*#d(){yield*this.#n.interfaces.values(),yield*this.#s.interfaces.values(),yield*this.#o.interfaces.values(),yield*this.#a.interfaces.values()}async createLoopbackInterface(e){return await this.ready,this.#n.create(e)}async createTunInterface(e){return await this.ready,this.#s.create(e)}async createTapInterface(e={}){return await this.ready,this.#o.create(e)}async createBridgeInterface(e){return await this.ready,this.#a.create(e)}async removeInterface(e){switch(await this.ready,e.type){case"loopback":return this.#n.remove(e);case"tun":return this.#s.remove(e);case"tap":return this.#o.remove(e);case"bridge":return this.#a.remove(e);default:throw new Error("unknown interface type")}}async listenTcp(e){return await this.ready,this.#i.listen(e)}async connectTcp(e){return await this.ready,this.#i.connect(e)}async openUdp(e={}){return await this.ready,this.#c.open(e)}};exports.createStack = Ae;
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6; var _class7; var _class8; var _class9; var _class10;var _chunkDVPTIOIVcjs = require('./chunk-DVPTIOIV.cjs');var _browser_wasi_shim = require('@bjorn3/browser_wasi_shim');var _dns = require('@tcpip/dns');var _wire = require('@tcpip/wire');var l=class{#e=new WeakMap;#t=new WeakMap;setOuter(e,r){this.#e.set(e,r)}setInner(e,r){this.#t.set(e,r)}getOuter(e){let r=this.#e.get(e);if(!r)throw new Error(`outer hooks not set for ${e}`);return r}getInner(e){let r=this.#t.get(e);if(!r)throw new Error(`inner hooks not set for ${e}`);return r}},R=class extends Number{constructor(e,r){super(e),this.free=r}[_chunkDVPTIOIVcjs.c](){this.free(this.valueOf())}},T=class extends Map{#e=new Map;wait(e){return new Promise(r=>{let t=_nullishCoalesce(this.#e.get(e), () => (new Set));t.add(r),this.#e.set(e,t)})}set(e,r){super.set(e,r);let t=this.#e.get(e);if(t)for(let n of t)n(r),t.delete(n);return this}};function w(o,e){let r=o.getReader();return oe(r,e)}async function*oe(o,e){try{for(;;){let{done:r,value:t}=await o.read();if(r)return t;yield t}}finally{_optionalChain([e, 'optionalAccess', _2 => _2.preventCancel])||await o.cancel(),o.releaseLock()}}var P=class extends ReadableStream{#e;constructor({lock:e,...r},t){super(r,t),this.#e=e}getReader(){let e=super.getReader();return this.locked&&_optionalChain([this, 'access', _3 => _3.#e, 'optionalCall', _4 => _4()]),e}pipeThrough(e,r){let t=super.pipeThrough(e,r);return this.locked&&_optionalChain([this, 'access', _5 => _5.#e, 'optionalCall', _6 => _6()]),t}pipeTo(e,r){let t=super.pipeTo(e,r);return this.locked&&_optionalChain([this, 'access', _7 => _7.#e, 'optionalCall', _8 => _8()]),t}tee(){let[e,r]=super.tee();return this.locked&&_optionalChain([this, 'access', _9 => _9.#e, 'optionalCall', _10 => _10()]),[e,r]}};async function g(){return await new Promise(o=>queueMicrotask(o))}function ie(o,e,{transformAtoB:r,transformBtoA:t}={}){let n=r?o.readable.pipeThrough(new TransformStream({transform(c,a){try{let i=r(c);a.enqueue(i)}catch(i){console.warn("Error transforming A to B",i)}}})):o.readable,s=t?e.readable.pipeThrough(new TransformStream({transform(c,a){try{let i=t(c);a.enqueue(i)}catch(i){console.warn("Error transforming B to A",i)}}})):e.readable;n.pipeTo(e.writable),s.pipeTo(o.writable)}var f=class{#e;get exports(){if(!this.#e)throw new Error("exports were not registered");return this.#e}register(e){this.#e=e}smartMalloc(e){return new R(this.exports.malloc(e),this.exports.free)}copyToMemory(e){let r=e.length,t=this.smartMalloc(r);return new Uint8Array(this.exports.memory.buffer,t.valueOf(),r).set(e),t}copyFromMemory(e,r){let t=this.exports.memory.buffer.slice(Number(e),Number(e)+r);return new Uint8Array(t)}viewFromMemory(e,r){return new Uint8Array(this.exports.memory.buffer,Number(e),r)}};var A={ERR_OK:0,ERR_MEM:-1,ERR_BUF:-2,ERR_TIMEOUT:-3,ERR_RTE:-4,ERR_INPROGRESS:-5,ERR_VAL:-6,ERR_WOULDBLOCK:-7,ERR_USE:-8,ERR_ALREADY:-9,ERR_ISCONN:-10,ERR_CONN:-11,ERR_IF:-12,ERR_ABRT:-13,ERR_RST:-14,ERR_CLSD:-15,ERR_ARG:-16};var b=new l,O= (_class =class extends f{constructor(...args) { super(...args); _class.prototype.__init.call(this);_class.prototype.__init2.call(this); }__init() {this.interfaces=new Map}__init2() {this.imports={register_tap_interface:e=>{let r=new W;b.setOuter(r,{handle:e,sendFrame:t=>{let n=this.copyToMemory(t),s=this.exports.send_tap_interface(e,n,t.length);if(s!==A.ERR_OK)throw new Error(`failed to send frame: ${s}`)},getMacAddress:()=>{let t=this.exports.get_interface_mac_address(e),n=this.viewFromMemory(t,6);return _wire.parseMacAddress.call(void 0, n)},getIPv4Address:()=>{let t=this.exports.get_interface_ip4_address(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)},getIPv4Netmask:()=>{let t=this.exports.get_interface_ip4_netmask(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)}}),this.interfaces.set(e,r)},receive_frame:async(e,r,t)=>{let n=this.copyFromMemory(r,t);await g();let s=this.interfaces.get(e);if(!s){console.error("received frame on unknown tap interface");return}b.getInner(s).receiveFrame(new Uint8Array(n))}}}async create(e){var d=[];try{let r=e.mac?_wire.serializeMacAddress.call(void 0, e.mac):_wire.generateMacAddress.call(void 0, );let{ipAddress:t,netmask:n}=e.ip?_wire.serializeIPv4Cidr.call(void 0, e.ip):{};let s=_chunkDVPTIOIVcjs.a.call(void 0, d,this.copyToMemory(r));let c=_chunkDVPTIOIVcjs.a.call(void 0, d,t?this.copyToMemory(t):void 0);let a=_chunkDVPTIOIVcjs.a.call(void 0, d,n?this.copyToMemory(n):void 0);let i=this.exports.create_tap_interface(s,_nullishCoalesce(c, () => (0)),_nullishCoalesce(a, () => (0)));let m=this.interfaces.get(i);if(!m)throw new Error("tap interface failed to register");return m}catch(y){var I=y,v=!0}finally{_chunkDVPTIOIVcjs.b.call(void 0, d,I,v)}}async remove(e){for(let[r,t]of this.interfaces.entries())if(t===e){this.exports.remove_tap_interface(r),this.interfaces.delete(r);return}}}, _class),W= (_class2 =class{#e;#t=!1;__init3() {this.type="tap"}get mac(){return b.getOuter(this).getMacAddress()}get ip(){return b.getOuter(this).getIPv4Address()}get netmask(){return b.getOuter(this).getIPv4Netmask()}constructor(){;_class2.prototype.__init3.call(this);b.setInner(this,{receiveFrame:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");this.#e.enqueue(e)}}}),this.readable=new P({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{try{b.getOuter(this).sendFrame(e)}catch(r){console.error("tap interface send failed",r)}}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return w(this.readable)}[Symbol.asyncIterator](){return this.listen()}}, _class2);var E=new l,U= (_class3 =class extends f{constructor(...args2) { super(...args2); _class3.prototype.__init4.call(this);_class3.prototype.__init5.call(this); }__init4() {this.interfaces=new Map}__init5() {this.imports={}}async create(e){var I=[];try{let r=e.mac?_wire.serializeMacAddress.call(void 0, e.mac):_wire.generateMacAddress.call(void 0, );let{ipAddress:t,netmask:n}=e.ip?_wire.serializeIPv4Cidr.call(void 0, e.ip):{};let s=_chunkDVPTIOIVcjs.a.call(void 0, I,this.copyToMemory(r));let c=_chunkDVPTIOIVcjs.a.call(void 0, I,t?this.copyToMemory(t):void 0);let a=_chunkDVPTIOIVcjs.a.call(void 0, I,n?this.copyToMemory(n):void 0);let i=new Uint32Array(e.ports.map(k=>Number(b.getOuter(k).handle)));let m=_chunkDVPTIOIVcjs.a.call(void 0, I,this.copyToMemory(new Uint8Array(i.buffer)));let d=this.exports.create_bridge_interface(s,_nullishCoalesce(c, () => (0)),_nullishCoalesce(a, () => (0)),m,e.ports.length);let y=new j;E.setOuter(y,{handle:d,getMacAddress:()=>{let k=this.exports.get_interface_mac_address(d),S=this.viewFromMemory(k,6);return _wire.parseMacAddress.call(void 0, S)},getIPv4Address:()=>{let k=this.exports.get_interface_ip4_address(d);if(k===0)return;let S=this.viewFromMemory(k,4);return _wire.parseIPv4Address.call(void 0, S)},getIPv4Netmask:()=>{let k=this.exports.get_interface_ip4_netmask(d);if(k===0)return;let S=this.viewFromMemory(k,4);return _wire.parseIPv4Address.call(void 0, S)}});this.interfaces.set(d,y);return y}catch(v){var D=v,F=!0}finally{_chunkDVPTIOIVcjs.b.call(void 0, I,D,F)}}async remove(e){for(let[r,t]of this.interfaces.entries())if(t===e){this.exports.remove_bridge_interface(r),this.interfaces.delete(r);return}}}, _class3),j= (_class4 =class{constructor() { _class4.prototype.__init6.call(this); }__init6() {this.type="bridge"}get mac(){return E.getOuter(this).getMacAddress()}get ip(){return E.getOuter(this).getIPv4Address()}get netmask(){return E.getOuter(this).getIPv4Netmask()}}, _class4);var z=new l,C= (_class5 =class extends f{constructor(...args3) { super(...args3); _class5.prototype.__init7.call(this);_class5.prototype.__init8.call(this); }__init7() {this.interfaces=new Map}__init8() {this.imports={register_loopback_interface:e=>{let r=new K;z.setOuter(r,{handle:e,getIPv4Address:()=>{let t=this.exports.get_interface_ip4_address(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)},getIPv4Netmask:()=>{let t=this.exports.get_interface_ip4_netmask(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)}}),this.interfaces.set(e,r)}}}async create(e){var i=[];try{let{ipAddress:r,netmask:t}=e.ip?_wire.serializeIPv4Cidr.call(void 0, e.ip):{};let n=_chunkDVPTIOIVcjs.a.call(void 0, i,r?this.copyToMemory(r):void 0);let s=_chunkDVPTIOIVcjs.a.call(void 0, i,t?this.copyToMemory(t):void 0);let c=this.exports.create_loopback_interface(_nullishCoalesce(n, () => (0)),_nullishCoalesce(s, () => (0)));let a=this.interfaces.get(c);if(!a)throw new Error("loopback interface failed to register");return a}catch(m){var d=m,y=!0}finally{_chunkDVPTIOIVcjs.b.call(void 0, i,d,y)}}async remove(e){for(let[r,t]of this.interfaces.entries())if(t===e){this.exports.remove_loopback_interface(r),this.interfaces.delete(r);return}}}, _class5),K= (_class6 =class{constructor() { _class6.prototype.__init9.call(this); }__init9() {this.type="loopback"}get ip(){return z.getOuter(this).getIPv4Address()}get netmask(){return z.getOuter(this).getIPv4Netmask()}}, _class6);var q=new l,_=new l,G=1448,nt=G*4,st=G*4,ye=G,M= (_class7 =class extends f{#e=new Map;#t=new T;#r=new Map;#n;async#s(e){try{return _wire.serializeIPv4Address.call(void 0, e)}catch (e2){let t=await this.#n.lookup(e);return _wire.serializeIPv4Address.call(void 0, t)}}constructor(e){super();_class7.prototype.__init10.call(this);,this.#n=e}__init10() {this.imports={accept_tcp_connection:async(e,r)=>{let t=this.#e.get(e);if(!t){console.error("new tcp connection to unknown listener");return}await g();let n=new L;_.setOuter(n,{send:async s=>{let c=Number(this.copyToMemory(s)),a=this.exports.send_tcp_chunk(r,c,s.length);for(;a<s.length;){await new Promise(m=>{this.#r.set(r,m)});let i=s.length-a;a+=this.exports.send_tcp_chunk(r,c+a,i)}},updateReceiveBuffer:s=>{this.exports.update_tcp_receive_buffer(r,s)},close:async()=>{let s=this.exports.close_tcp_connection(r);if(s!==A.ERR_OK)throw new Error(`failed to close tcp connection: ${s}`)}}),this.#t.set(r,n),q.getInner(t).accept(n)},connected_tcp_connection:async e=>{await g();let r=new L;_.setOuter(r,{send:async t=>{let n=Number(this.copyToMemory(t)),s=this.exports.send_tcp_chunk(e,n,t.length);for(;s<t.length;){await new Promise(a=>{this.#r.set(e,a)});let c=t.length-s;s+=this.exports.send_tcp_chunk(e,n+s,c)}},updateReceiveBuffer:t=>{this.exports.update_tcp_receive_buffer(e,t)},close:async()=>{this.exports.close_tcp_connection(e)}}),this.#t.set(e,r)},closed_tcp_connection:async e=>{let r=this.#t.get(e);if(!r){console.error("received close on unknown tcp connection");return}await _.getInner(r).close()},receive_tcp_chunk:async(e,r,t)=>{let n=this.copyFromMemory(r,t),s=this.#t.get(e);if(!s){console.error("received chunk on unknown tcp connection");return}await g(),_.getInner(s).receive(new Uint8Array(n))},sent_tcp_chunk:(e,r)=>{let t=this.#r.get(e);this.#r.delete(e),_optionalChain([t, 'optionalCall', _12 => _12(r)])}}}async listen(e){var s=[];try{let r=_chunkDVPTIOIVcjs.a.call(void 0, s,e.host?this.copyToMemory(await this.#s(e.host)):null);let t=this.exports.create_tcp_listener(r,e.port);let n=new $;q.setOuter(n,{});this.#e.set(t,n);return n}catch(c){var a=c,i=!0}finally{_chunkDVPTIOIVcjs.b.call(void 0, s,a,i)}}async connect(e){var s=[];try{let r=_chunkDVPTIOIVcjs.a.call(void 0, s,this.copyToMemory(await this.#s(e.host)));let t=this.exports.create_tcp_connection(r,e.port);let n=await this.#t.wait(t);if(!n)throw new Error("tcp failed to connect");return n}catch(c){var a=c,i=!0}finally{_chunkDVPTIOIVcjs.b.call(void 0, s,a,i)}}}, _class7),$=class{#e=[];#t;constructor(){q.setInner(this,{accept:async e=>{this.#e.push(e),_optionalChain([this, 'access', _13 => _13.#t, 'optionalCall', _14 => _14()])}})}async*[Symbol.asyncIterator](){for(;;)await new Promise(e=>{this.#t=e}),yield*this.#e,this.#e=[]}},L=class{#e=[];#t;#r;constructor(){_.setInner(this,{receive:async e=>{this.#e.push(e),this.#n()},close:async()=>{this.close()}}),this.readable=new ReadableStream({start:e=>{this.#t=e},pull:()=>{this.#n()}},{highWaterMark:ye,size:e=>e.byteLength}),this.writable=new WritableStream({start:e=>{this.#r=e},write:async e=>{await _.getOuter(this).send(e)}},{highWaterMark:0})}#n(){if(!(_optionalChain([this, 'access', _15 => _15.#t, 'optionalAccess', _16 => _16.desiredSize])>0))return;let e=0;for(;this.#e.length>0;){let r=this.#e[0].length;if(e>0&&e+r>this.#t.desiredSize)break;let t=this.#e.shift();this.#t.enqueue(t),e+=t.length}e>0&&_.getOuter(this).updateReceiveBuffer(e)}async close(){await _.getOuter(this).close(),_optionalChain([this, 'access', _17 => _17.#t, 'optionalAccess', _18 => _18.error, 'call', _19 => _19(new Error("tcp connection closed"))]),_optionalChain([this, 'access', _20 => _20.#r, 'optionalAccess', _21 => _21.error, 'call', _22 => _22(new Error("tcp connection closed"))])}[Symbol.asyncIterator](){if(this.readable.locked)throw new Error("readable stream already locked");return w(this.readable)}};var x=new l,B= (_class8 =class extends f{constructor(...args4) { super(...args4); _class8.prototype.__init11.call(this);_class8.prototype.__init12.call(this); }__init11() {this.interfaces=new Map}__init12() {this.imports={register_tun_interface:e=>{let r=new Q;x.setOuter(r,{handle:e,sendPacket:t=>{let n=this.copyToMemory(t);this.exports.send_tun_interface(e,n,t.length)},getIPv4Address:()=>{let t=this.exports.get_interface_ip4_address(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)},getIPv4Netmask:()=>{let t=this.exports.get_interface_ip4_netmask(e);if(t===0)return;let n=this.viewFromMemory(t,4);return _wire.parseIPv4Address.call(void 0, n)}}),this.interfaces.set(e,r)},receive_packet:async(e,r,t)=>{let n=this.copyFromMemory(r,t);await g();let s=this.interfaces.get(e);if(!s){console.error("received packet on unknown tun interface");return}x.getInner(s).receivePacket(new Uint8Array(n))}}}async create(e){var i=[];try{let{ipAddress:r,netmask:t}=e.ip?_wire.serializeIPv4Cidr.call(void 0, e.ip):{};let n=_chunkDVPTIOIVcjs.a.call(void 0, i,r?this.copyToMemory(r):void 0);let s=_chunkDVPTIOIVcjs.a.call(void 0, i,t?this.copyToMemory(t):void 0);let c=this.exports.create_tun_interface(_nullishCoalesce(n, () => (0)),_nullishCoalesce(s, () => (0)));let a=this.interfaces.get(c);if(!a)throw new Error("tun interface failed to register");return a}catch(m){var d=m,y=!0}finally{_chunkDVPTIOIVcjs.b.call(void 0, i,d,y)}}async remove(e){for(let[r,t]of this.interfaces.entries())if(t===e){this.exports.remove_tun_interface(r),this.interfaces.delete(r);return}}}, _class8),Q= (_class9 =class{#e;#t=!1;__init13() {this.type="tun"}get ip(){return x.getOuter(this).getIPv4Address()}get netmask(){return x.getOuter(this).getIPv4Netmask()}constructor(){;_class9.prototype.__init13.call(this);x.setInner(this,{receivePacket:async e=>{if(this.#t){if(!this.#e)throw new Error("readable stream not initialized");_optionalChain([this, 'access', _23 => _23.#e, 'optionalAccess', _24 => _24.enqueue, 'call', _25 => _25(e)])}}}),this.readable=new P({start:e=>{this.#e=e},lock:()=>{this.#t=!0}}),this.writable=new WritableStream({write:e=>{x.getOuter(this).sendPacket(e)}})}listen(){if(this.readable.locked)throw new Error("readable stream already locked");return w(this.readable)}[Symbol.asyncIterator](){return this.listen()}}, _class9);var H=new l,N= (_class10 =class extends f{#e=new T;#t;async#r(e){try{return _wire.serializeIPv4Address.call(void 0, e)}catch (e3){let t=await this.#t.lookup(e);return _wire.serializeIPv4Address.call(void 0, t)}}constructor(e){super();_class10.prototype.__init14.call(this);,this.#t=e}__init14() {this.imports={receive_udp_datagram:async(e,r,t,n,s)=>{let c=this.copyFromMemory(r,4),a=this.copyFromMemory(n,s),i=this.#e.get(e);if(!i){console.error("received datagram on unknown udp socket");return}await g(),H.getInner(i).receive({host:_wire.parseIPv4Address.call(void 0, c),port:t,data:a})}}}async open(e){var s=[];try{let r=_chunkDVPTIOIVcjs.a.call(void 0, s,e.host?this.copyToMemory(await this.#r(e.host)):null);let t=this.exports.open_udp_socket(r,_nullishCoalesce(e.port, () => (0)));if(Number(t)===0)throw new Error("failed to open udp socket");let n=new Z;H.setOuter(n,{send:async m=>{var v=[];try{let d=_chunkDVPTIOIVcjs.a.call(void 0, v,this.copyToMemory(await this.#r(m.host)));let y=_chunkDVPTIOIVcjs.a.call(void 0, v,this.copyToMemory(m.data));let I=this.exports.send_udp_datagram(t,d,m.port,y,m.data.length);if(I!==A.ERR_OK)throw new Error(`failed to send udp datagram: ${I}`)}catch(D){var F=D,k=!0}finally{_chunkDVPTIOIVcjs.b.call(void 0, v,F,k)}},close:async()=>{this.exports.close_udp_socket(t),this.#e.delete(t)}});this.#e.set(t,n);return n}catch(c){var a=c,i=!0}finally{_chunkDVPTIOIVcjs.b.call(void 0, s,a,i)}}}, _class10),Z=class{#e;#t;constructor(){H.setInner(this,{receive:async e=>{if(!this.#e)throw new Error("readable controller not initialized");this.#e.enqueue(e)}}),this.readable=new ReadableStream({start:e=>{this.#e=e}}),this.writable=new WritableStream({start:e=>{this.#t=e},write:async e=>{await H.getOuter(this).send(e)}})}async close(){await H.getOuter(this).close(),_optionalChain([this, 'access', _26 => _26.#e, 'optionalAccess', _27 => _27.error, 'call', _28 => _28(new Error("udp socket closed"))]),_optionalChain([this, 'access', _29 => _29.#t, 'optionalAccess', _30 => _30.error, 'call', _31 => _31(new Error("udp socket closed"))])}[Symbol.asyncIterator](){if(this.readable.locked)throw new Error("readable stream already locked");return w(this.readable)}};var ge=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";async function ne(o,e){return ge?be(o,e):fetch(o)}async function be(o,e){let r=await Promise.resolve().then(() => _interopRequireWildcard(require("fs"))),{Readable:t}=await Promise.resolve().then(() => _interopRequireWildcard(require("stream"))),n=r.createReadStream(o),s=t.toWeb(n);return new Response(s,{headers:{"Content-Type":e}})}async function Pe(o){let e=new X(o);return await e.ready,e}var X=class{#e;#t;#r;#n;#s;#o;#i;#a;#c;get interfaces(){return this.#d()}constructor(e={}){this.#e={...e,initializeLoopback:_nullishCoalesce(e.initializeLoopback, () => (!0))},this.#r=new (0, _dns.DnsClient)(this,{nameServer:_nullishCoalesce(e.nameServer, () => ({ip:"127.0.0.1",port:53}))}),this.#n=new C,this.#s=new B,this.#o=new O,this.#i=new U,this.#a=new M(this.#r),this.#c=new N(this.#r),this.ready=this.#p(),this.ready.then(async()=>{this.#e.initializeLoopback&&await this.createLoopbackInterface({ip:"127.0.0.1/8"})})}async#p(){let e=new (0, _browser_wasi_shim.WASI)([],[],[new (0, _browser_wasi_shim.OpenFile)(new (0, _browser_wasi_shim.File)([])),_browser_wasi_shim.ConsoleStdout.lineBuffered(s=>console.log(`[WASI stdout] ${s}`)),_browser_wasi_shim.ConsoleStdout.lineBuffered(s=>console.warn(`[WASI stderr] ${s}`))]),r=ne(new URL("../tcpip.wasm",import.meta.url),"application/wasm"),{instance:t}=await WebAssembly.instantiateStreaming(r,{wasi_snapshot_preview1:e.wasiImport,env:{...this.#n.imports,...this.#s.imports,...this.#o.imports,...this.#i.imports,...this.#a.imports,...this.#c.imports}}),n=t;this.#n.register(n.exports),this.#s.register(n.exports),this.#o.register(n.exports),this.#i.register(n.exports),this.#a.register(n.exports),this.#c.register(n.exports),e.initialize(n),this.#t=Number(setInterval(()=>{n.exports.process_queued_packets(),n.exports.process_timeouts()},100))}*#d(){yield*this.#n.interfaces.values(),yield*this.#s.interfaces.values(),yield*this.#o.interfaces.values(),yield*this.#i.interfaces.values()}async createLoopbackInterface(e){return await this.ready,this.#n.create(e)}async createTunInterface(e){return await this.ready,this.#s.create(e)}async createTapInterface(e={}){return await this.ready,this.#o.create(e)}async createBridgeInterface(e){return await this.ready,this.#i.create(e)}async removeInterface(e){switch(await this.ready,e.type){case"loopback":return this.#n.remove(e);case"tun":return this.#s.remove(e);case"tap":return this.#o.remove(e);case"bridge":return this.#i.remove(e);default:throw new Error("unknown interface type")}}async listenTcp(e){return await this.ready,this.#a.listen(e)}async connectTcp(e){return await this.ready,this.#a.connect(e)}async openUdp(e={}){return await this.ready,this.#c.open(e)}};exports.connectStreams = ie; exports.createStack = Pe;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/grichardson/Documents/dev/tcpip.js/packages/tcpip/dist/index.cjs","../polyfills/disposable.ts","../src/stack.ts","../src/bindings/bridge-interface.ts","../src/util.ts"],"names":["DisposeSymbol","Hooks","#outerHooks","#innerHooks","key","hooks"],"mappings":"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","file":"/Users/grichardson/Documents/dev/tcpip.js/packages/tcpip/dist/index.cjs","sourcesContent":[null,"/**\n * Scoped polyfill for `Symbol.dispose` without polluting the global scope.\n * Required for the `using` keyword which we use internally.\n * \n * We export this symbol as 'Symbol.dispose' which tells ESBuild to inject\n * it into the output bundle.\n * \n * The below works because Typescript's `using` implementation falls back to\n * `Symbol.for(\"Symbol.dispose\")` if the built-in `Symbol.dispose` is not available.\n */\n\nconst DisposeSymbol = 'dispose' in (Symbol as object) ? Symbol.dispose : Symbol.for('Symbol.dispose');\n\nexport {\n DisposeSymbol as 'Symbol.dispose'\n};\n","import { ConsoleStdout, File, OpenFile, WASI } from '@bjorn3/browser_wasi_shim';\nimport { DnsClient, type NameServer } from '@tcpip/dns';\nimport {\n BridgeBindings,\n type BridgeInterface,\n type BridgeInterfaceOptions,\n} from './bindings/bridge-interface.js';\nimport {\n LoopbackBindings,\n type LoopbackInterface,\n type LoopbackInterfaceOptions,\n} from './bindings/loopback-interface.js';\nimport {\n TapBindings,\n type TapInterface,\n type TapInterfaceOptions,\n} from './bindings/tap-interface.js';\nimport {\n TcpBindings,\n type TcpConnection,\n type TcpConnectionOptions,\n type TcpListener,\n type TcpListenerOptions,\n} from './bindings/tcp.js';\nimport {\n TunBindings,\n type TunInterface,\n type TunInterfaceOptions,\n} from './bindings/tun-interface.js';\nimport {\n UdpBindings,\n type UdpSocket,\n type UdpSocketOptions,\n} from './bindings/udp.js';\nimport { fetchFile } from './fetch-file.js';\nimport type { NetworkInterface, WasmInstance } from './types.js';\n\nexport async function createStack(\n options?: NetworkStackOptions\n): Promise<NetworkStack> {\n const stack = new VirtualNetworkStack(options);\n await stack.ready;\n return stack;\n}\n\nexport type NetworkStackOptions = {\n /**\n * Whether to initialize a loopback interface on startup.\n *\n * @default true\n */\n initializeLoopback?: boolean;\n\n /**\n * Name server used for DNS resolution.\n *\n * @default { ip: '127.0.0.1', port: 53 }\n */\n nameServer?: NameServer;\n};\n\nexport type NetworkStack = {\n readonly ready: Promise<void>;\n readonly interfaces: Iterable<NetworkInterface>;\n\n createLoopbackInterface(\n options: LoopbackInterfaceOptions\n ): Promise<LoopbackInterface>;\n createTunInterface(options: TunInterfaceOptions): Promise<TunInterface>;\n createTapInterface(options?: TapInterfaceOptions): Promise<TapInterface>;\n createBridgeInterface(\n options: BridgeInterfaceOptions\n ): Promise<BridgeInterface>;\n removeInterface(\n netInterface: LoopbackInterface | TunInterface | TapInterface\n ): Promise<void>;\n /**\n * Listens for incoming TCP connections on the specified host/port.\n */\n listenTcp(options: TcpListenerOptions): Promise<TcpListener>;\n /**\n * Establishes an outbound TCP connection to a remote host/port.\n */\n connectTcp(options: TcpConnectionOptions): Promise<TcpConnection>;\n /**\n * Opens a UDP socket for sending and receiving datagrams.\n *\n * If no local host is provided, the socket will bind to all available interfaces.\n * If no local port is provided, the socket will bind to a random port.\n */\n openUdp(options?: UdpSocketOptions): Promise<UdpSocket>;\n};\n\nexport class VirtualNetworkStack implements NetworkStack {\n #options: NetworkStackOptions;\n #loopIntervalId?: number;\n #dnsClient: DnsClient;\n\n #loopbackBindings: LoopbackBindings;\n #tunBindings: TunBindings;\n #tapBindings: TapBindings;\n #bridgeBindings: BridgeBindings;\n #tcpBindings: TcpBindings;\n #udpBindings: UdpBindings;\n\n ready: Promise<void>;\n get interfaces() {\n return this.#listInterfaces();\n }\n\n constructor(options: NetworkStackOptions = {}) {\n this.#options = {\n ...options,\n initializeLoopback: options.initializeLoopback ?? true,\n };\n\n this.#dnsClient = new DnsClient(this, {\n nameServer: options.nameServer ?? { ip: '127.0.0.1', port: 53 },\n });\n\n // Initialize bindings\n this.#loopbackBindings = new LoopbackBindings();\n this.#tunBindings = new TunBindings();\n this.#tapBindings = new TapBindings();\n this.#bridgeBindings = new BridgeBindings();\n this.#tcpBindings = new TcpBindings(this.#dnsClient);\n this.#udpBindings = new UdpBindings(this.#dnsClient);\n\n // Initialize the stack\n this.ready = this.#init();\n\n // Post-init setup\n this.ready.then(async () => {\n if (this.#options.initializeLoopback) {\n await this.createLoopbackInterface({\n ip: '127.0.0.1/8',\n });\n }\n });\n }\n\n async #init() {\n const wasi = new WASI(\n [],\n [],\n [\n new OpenFile(new File([])), // stdin\n ConsoleStdout.lineBuffered((msg) =>\n console.log(`[WASI stdout] ${msg}`)\n ),\n ConsoleStdout.lineBuffered((msg) =>\n console.warn(`[WASI stderr] ${msg}`)\n ),\n ]\n );\n\n const source = fetchFile(\n new URL('../tcpip.wasm', import.meta.url),\n 'application/wasm'\n );\n\n // Instantiate with both WASI and custom imports\n const { instance } = await WebAssembly.instantiateStreaming(source, {\n wasi_snapshot_preview1: wasi.wasiImport,\n env: {\n ...this.#loopbackBindings.imports,\n ...this.#tunBindings.imports,\n ...this.#tapBindings.imports,\n ...this.#bridgeBindings.imports,\n ...this.#tcpBindings.imports,\n ...this.#udpBindings.imports,\n },\n });\n\n const wasmInstance = instance as WasmInstance;\n\n this.#loopbackBindings.register(wasmInstance.exports);\n this.#tunBindings.register(wasmInstance.exports);\n this.#tapBindings.register(wasmInstance.exports);\n this.#bridgeBindings.register(wasmInstance.exports);\n this.#tcpBindings.register(wasmInstance.exports);\n this.#udpBindings.register(wasmInstance.exports);\n\n // Our WASM binary is a WASI reactor module (ie. a lib),\n // so we call `initialize()` instead of `start()`.\n wasi.initialize(wasmInstance);\n\n // Call lwIP's main loop regularly (required in NO_SYS mode)\n // Used to process queued packets (eg. loopback) and expired timeouts\n this.#loopIntervalId = Number(\n setInterval(() => {\n wasmInstance.exports.process_queued_packets();\n wasmInstance.exports.process_timeouts();\n }, 100)\n );\n }\n\n *#listInterfaces(): Iterable<NetworkInterface> {\n yield* this.#loopbackBindings.interfaces.values();\n yield* this.#tunBindings.interfaces.values();\n yield* this.#tapBindings.interfaces.values();\n yield* this.#bridgeBindings.interfaces.values();\n }\n\n async createLoopbackInterface(\n options: LoopbackInterfaceOptions\n ): Promise<LoopbackInterface> {\n await this.ready;\n return this.#loopbackBindings.create(options);\n }\n\n async createTunInterface(\n options: TunInterfaceOptions\n ): Promise<TunInterface> {\n await this.ready;\n return this.#tunBindings.create(options);\n }\n\n async createTapInterface(\n options: TapInterfaceOptions = {}\n ): Promise<TapInterface> {\n await this.ready;\n return this.#tapBindings.create(options);\n }\n\n async createBridgeInterface(options: BridgeInterfaceOptions) {\n await this.ready;\n return this.#bridgeBindings.create(options);\n }\n\n async removeInterface(netInterface: NetworkInterface) {\n await this.ready;\n\n switch (netInterface.type) {\n case 'loopback':\n return this.#loopbackBindings.remove(netInterface);\n case 'tun':\n return this.#tunBindings.remove(netInterface);\n case 'tap':\n return this.#tapBindings.remove(netInterface);\n case 'bridge':\n return this.#bridgeBindings.remove(netInterface);\n default:\n throw new Error('unknown interface type');\n }\n }\n\n /**\n * Listens for incoming TCP connections on the specified host/port.\n */\n async listenTcp(options: TcpListenerOptions) {\n await this.ready;\n return this.#tcpBindings.listen(options);\n }\n\n /**\n * Establishes an outbound TCP connection to a remote host/port.\n */\n async connectTcp(options: TcpConnectionOptions) {\n await this.ready;\n return this.#tcpBindings.connect(options);\n }\n\n /**\n * Opens a UDP socket for sending and receiving datagrams.\n *\n * If no local host is provided, the socket will bind to all available interfaces.\n * If no local port is provided, the socket will bind to a random port.\n */\n async openUdp(options: UdpSocketOptions = {}) {\n await this.ready;\n return this.#udpBindings.open(options);\n }\n}\n","import {\n generateMacAddress,\n parseIPv4Address,\n parseMacAddress,\n serializeIPv4Cidr,\n serializeMacAddress,\n type IPv4Address,\n type IPv4Cidr,\n type MacAddress,\n} from '@tcpip/wire';\nimport type { Pointer } from '../types.js';\nimport { Hooks } from '../util.js';\nimport { Bindings } from './base.js';\nimport { tapInterfaceHooks, type TapInterface } from './tap-interface.js';\n\ntype BridgeInterfaceHandle = Pointer;\n\ntype BridgeInterfaceOuterHooks = {\n handle: BridgeInterfaceHandle;\n getMacAddress(): MacAddress;\n getIPv4Address(): IPv4Address | undefined;\n getIPv4Netmask(): IPv4Address | undefined;\n};\n\ntype BridgeInterfaceInnerHooks = {};\n\nexport const bridgeInterfaceHooks = new Hooks<\n BridgeInterface,\n BridgeInterfaceOuterHooks,\n BridgeInterfaceInnerHooks\n>();\n\nexport type BridgeImports = {};\n\nexport type BridgeExports = {\n create_bridge_interface(\n macAddress: Pointer,\n ipAddress: Pointer,\n netmask: Pointer,\n ports: Pointer,\n ports_length: number\n ): BridgeInterfaceHandle;\n remove_bridge_interface(handle: BridgeInterfaceHandle): void;\n};\n\nexport class BridgeBindings extends Bindings<BridgeImports, BridgeExports> {\n interfaces = new Map<BridgeInterfaceHandle, BridgeInterface>();\n\n imports = {};\n\n async create(options: BridgeInterfaceOptions) {\n const macAddress = options.mac\n ? serializeMacAddress(options.mac)\n : generateMacAddress();\n\n const { ipAddress, netmask } = options.ip\n ? serializeIPv4Cidr(options.ip)\n : {};\n\n using macAddressPtr = this.copyToMemory(macAddress);\n using ipAddressPtr = ipAddress ? this.copyToMemory(ipAddress) : undefined;\n using netmaskPtr = netmask ? this.copyToMemory(netmask) : undefined;\n const portHandles = new Uint32Array(\n options.ports.map((port) =>\n Number(tapInterfaceHooks.getOuter(port).handle)\n )\n );\n\n using portHandlesPtr = this.copyToMemory(portHandles.buffer);\n\n const handle = this.exports.create_bridge_interface(\n macAddressPtr,\n ipAddressPtr ?? 0,\n netmaskPtr ?? 0,\n portHandlesPtr,\n options.ports.length\n );\n\n const bridgeInterface = new VirtualBridgeInterface();\n\n bridgeInterfaceHooks.setOuter(bridgeInterface, {\n handle,\n getMacAddress: () => {\n const macPtr = this.exports.get_interface_mac_address(handle);\n\n const macBytes = this.viewFromMemory(macPtr, 6);\n return parseMacAddress(macBytes);\n },\n getIPv4Address: () => {\n const ipPtr = this.exports.get_interface_ip4_address(handle);\n\n if (ipPtr === 0) {\n return;\n }\n\n const ipBytes = this.viewFromMemory(ipPtr, 4);\n return parseIPv4Address(ipBytes);\n },\n getIPv4Netmask: () => {\n const netmaskPtr = this.exports.get_interface_ip4_netmask(handle);\n\n if (netmaskPtr === 0) {\n return;\n }\n\n const netmaskBytes = this.viewFromMemory(netmaskPtr, 4);\n return parseIPv4Address(netmaskBytes);\n },\n });\n\n this.interfaces.set(handle, bridgeInterface);\n\n return bridgeInterface;\n }\n\n async remove(bridgeInterface: BridgeInterface) {\n for (const [handle, loopback] of this.interfaces.entries()) {\n if (loopback === bridgeInterface) {\n this.exports.remove_bridge_interface(handle);\n this.interfaces.delete(handle);\n return;\n }\n }\n }\n}\n\nexport type BridgeInterfaceOptions = {\n ports: TapInterface[];\n mac?: MacAddress;\n ip?: IPv4Cidr;\n};\n\nexport type BridgeInterface = {\n readonly type: 'bridge';\n readonly mac: MacAddress;\n readonly ip?: IPv4Address;\n readonly netmask?: IPv4Address;\n};\n\nexport class VirtualBridgeInterface implements BridgeInterface {\n readonly type = 'bridge';\n get mac(): MacAddress {\n return bridgeInterfaceHooks.getOuter(this).getMacAddress();\n }\n get ip(): IPv4Address | undefined {\n return bridgeInterfaceHooks.getOuter(this).getIPv4Address();\n }\n get netmask(): IPv4Address | undefined {\n return bridgeInterfaceHooks.getOuter(this).getIPv4Netmask();\n }\n}\n","/**\n * Utility class to facilitate internal communication\n * between bindings and JS instances.\n * Hooks are created for both the outer (bindings) and\n * inner (JS instance) sides of the communication.\n *\n * Uses `WeakMap` to map each JS instance to a set of\n * hooks while avoiding memory leaks.\n */\nexport class Hooks<K extends WeakKey, O, I> {\n #outerHooks = new WeakMap<K, O>();\n #innerHooks = new WeakMap<K, I>();\n\n setOuter(key: K, hooks: O) {\n this.#outerHooks.set(key, hooks);\n }\n\n setInner(key: K, hooks: I) {\n this.#innerHooks.set(key, hooks);\n }\n\n getOuter(key: K) {\n const hooks = this.#outerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`outer hooks not set for ${key}`);\n }\n\n return hooks;\n }\n\n getInner(key: K) {\n const hooks = this.#innerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`inner hooks not set for ${key}`);\n }\n\n return hooks;\n }\n}\n\nexport class UniquePointer extends Number {\n free: (ptr: number) => void;\n\n /**\n * A unique pointer that will automatically free virtual memory when\n * it is disposed. Named after the C++ concept of a unique pointer.\n *\n * Should be used with the `using` keyword to ensure that the pointer is\n * freed (via dispose function) when it is no longer in scope.\n *\n * Useful with WASM modules that require allocating and freeing memory.\n *\n * @example\n * ```ts\n * using ptr = new UniquePointer(wasmBridge.malloc(10), wasmBridge.free);\n * ```\n *\n * @param address The address of the pointer\n * @param free The function to call to free the pointer\n */\n constructor(address: number, free: (ptr: number) => void) {\n super(address);\n this.free = free;\n }\n\n [Symbol.dispose]() {\n this.free(this.valueOf());\n }\n}\n\n/**\n * Map that allows waiting for changes to values.\n */\nexport class EventMap<K, V> extends Map<K, V> {\n #listeners = new Map<K, Set<(value: V) => void>>();\n\n /**\n * Waits for the next `set()` call on the given key.\n */\n wait(key: K): Promise<V> {\n return new Promise((resolve) => {\n const listeners = this.#listeners.get(key) ?? new Set();\n listeners.add(resolve);\n this.#listeners.set(key, listeners);\n });\n }\n\n override set(key: K, value: V) {\n super.set(key, value);\n\n const listeners = this.#listeners.get(key);\n\n if (listeners) {\n for (const listener of listeners) {\n listener(value);\n listeners.delete(listener);\n }\n }\n\n return this;\n }\n}\n\n/**\n * Converts a `ReadableStream` into an `AsyncIterableIterator`.\n *\n * Allows you to use ReadableStreams in a `for await ... of` loop.\n */\nexport function fromReadable<R>(\n readable: ReadableStream<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n const reader = readable.getReader();\n return fromReader(reader, options);\n}\n\n/**\n * Converts a `ReadableStreamDefaultReader` into an `AsyncIterableIterator`.\n *\n * Allows you to use Readers in a `for await ... of` loop.\n */\nexport async function* fromReader<R>(\n reader: ReadableStreamDefaultReader<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return value;\n }\n yield value;\n }\n } finally {\n if (!options?.preventCancel) {\n await reader.cancel();\n }\n reader.releaseLock();\n }\n}\n\nexport type UnderlyingSourceLockCallback = () => void;\n\n/**\n * `ReadableStream` with an optional lock callback.\n */\nexport class ExtendedReadableStream<R> extends ReadableStream<R> {\n #notifyLock?: () => void;\n\n constructor(\n {\n lock,\n ...underlyingSource\n }: UnderlyingSource & { lock?: UnderlyingSourceLockCallback },\n strategy?: QueuingStrategy<R>\n ) {\n super(underlyingSource, strategy);\n this.#notifyLock = lock;\n }\n\n override getReader() {\n const reader = super.getReader() as any;\n if (this.locked) {\n this.#notifyLock?.();\n }\n return reader;\n }\n\n override pipeThrough<T>(\n transform: ReadableWritablePair<T, R>,\n options?: StreamPipeOptions\n ): ReadableStream<T> {\n const stream = super.pipeThrough(transform, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return stream;\n }\n\n override pipeTo(\n dest: WritableStream<R>,\n options?: StreamPipeOptions\n ): Promise<void> {\n const promise = super.pipeTo(dest, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return promise;\n }\n\n override tee(): [ReadableStream<R>, ReadableStream<R>] {\n const [a, b] = super.tee();\n if (this.locked) {\n this.#notifyLock?.();\n }\n return [a, b];\n }\n}\n\n/**\n * Queues a microtask and returns a promise that resolves when\n * the microtask is executed.\n *\n * Microtasks are executed after the current task has completed,\n * but before the next task begins (tasks are the main unit of\n * work in the event loop).\n *\n * Useful when you want synchronous code from the current task to\n * complete before executing asynchronous code.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\n */\nexport async function nextMicrotask() {\n return await new Promise<void>((resolve) => queueMicrotask(resolve));\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/tcpip.js/tcpip.js/packages/tcpip/dist/index.cjs","../src/stack.ts","../src/bindings/bridge-interface.ts","../src/util.ts"],"names":["Hooks","#outerHooks","#innerHooks","key","hooks"],"mappings":"AAAA,6nCAAsD,8DCAF,iCACT,mCCOpC,ICGMA,CAAAA,CAAN,KAAqC,CAC1CC,CAAAA,CAAAA,CAAc,IAAI,OAAA,CAClBC,CAAAA,CAAAA,CAAc,IAAI,OAAA,CAElB,QAAA,CAASC,CAAAA,CAAQC,CAAAA,CAAU,CACzB,IAAA,CAAKH,CAAAA,CAAAA,CAAY,GAAA,CAAIE,CAAAA,CAAKC,CAAK,CACjC,CAEA,QAAA,CAASD,CAAAA,CAAQC,CAAAA,CAAU,CACzB,IAAA,CAAKF,CAAAA,CAAAA,CAAY,GAAA,CAAIC,CAAAA,CAAKC,CAAK,CACjC,CAEA,QAAA,CAASD,CAAAA,CAAQ,CACf,IAAMC,CAAAA,CAAQ,IAAA,CAAKH,CAAAA,CAAAA,CAAY,GAAA,CAAIE,CAAG,CAAA,CAEtC,EAAA,CAAI,CAACC,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,CAAA,wBAAA,EAA2BD,CAAG,CAAA,CAAA","file":"/home/runner/work/tcpip.js/tcpip.js/packages/tcpip/dist/index.cjs","sourcesContent":[null,"import { ConsoleStdout, File, OpenFile, WASI } from '@bjorn3/browser_wasi_shim';\nimport { DnsClient, type NameServer } from '@tcpip/dns';\nimport { BridgeBindings } from './bindings/bridge-interface.js';\nimport { LoopbackBindings } from './bindings/loopback-interface.js';\nimport { TapBindings } from './bindings/tap-interface.js';\nimport { TcpBindings } from './bindings/tcp.js';\nimport { TunBindings } from './bindings/tun-interface.js';\nimport type { WasmInstance } from './bindings/types.js';\nimport { UdpBindings } from './bindings/udp.js';\nimport { fetchFile } from './fetch-file.js';\nimport type {\n BridgeInterfaceOptions,\n LoopbackInterface,\n LoopbackInterfaceOptions,\n NetworkInterface,\n NetworkStack,\n TapInterface,\n TapInterfaceOptions,\n TcpConnectionOptions,\n TcpListenerOptions,\n TunInterface,\n TunInterfaceOptions,\n UdpSocketOptions,\n} from './types.js';\n\nexport async function createStack(\n options?: NetworkStackOptions\n): Promise<NetworkStack> {\n const stack = new VirtualNetworkStack(options);\n await stack.ready;\n return stack;\n}\n\nexport type NetworkStackOptions = {\n /**\n * Whether to initialize a loopback interface on startup.\n *\n * @default true\n */\n initializeLoopback?: boolean;\n\n /**\n * Name server used for DNS resolution.\n *\n * @default { ip: '127.0.0.1', port: 53 }\n */\n nameServer?: NameServer;\n};\n\nexport class VirtualNetworkStack implements NetworkStack {\n #options: NetworkStackOptions;\n #loopIntervalId?: number;\n #dnsClient: DnsClient;\n\n #loopbackBindings: LoopbackBindings;\n #tunBindings: TunBindings;\n #tapBindings: TapBindings;\n #bridgeBindings: BridgeBindings;\n #tcpBindings: TcpBindings;\n #udpBindings: UdpBindings;\n\n ready: Promise<void>;\n get interfaces() {\n return this.#listInterfaces();\n }\n\n constructor(options: NetworkStackOptions = {}) {\n this.#options = {\n ...options,\n initializeLoopback: options.initializeLoopback ?? true,\n };\n\n this.#dnsClient = new DnsClient(this, {\n nameServer: options.nameServer ?? { ip: '127.0.0.1', port: 53 },\n });\n\n // Initialize bindings\n this.#loopbackBindings = new LoopbackBindings();\n this.#tunBindings = new TunBindings();\n this.#tapBindings = new TapBindings();\n this.#bridgeBindings = new BridgeBindings();\n this.#tcpBindings = new TcpBindings(this.#dnsClient);\n this.#udpBindings = new UdpBindings(this.#dnsClient);\n\n // Initialize the stack\n this.ready = this.#init();\n\n // Post-init setup\n this.ready.then(async () => {\n if (this.#options.initializeLoopback) {\n await this.createLoopbackInterface({\n ip: '127.0.0.1/8',\n });\n }\n });\n }\n\n async #init() {\n const wasi = new WASI(\n [],\n [],\n [\n new OpenFile(new File([])), // stdin\n ConsoleStdout.lineBuffered((msg) =>\n console.log(`[WASI stdout] ${msg}`)\n ),\n ConsoleStdout.lineBuffered((msg) =>\n console.warn(`[WASI stderr] ${msg}`)\n ),\n ]\n );\n\n const source = fetchFile(\n new URL('../tcpip.wasm', import.meta.url),\n 'application/wasm'\n );\n\n // Instantiate with both WASI and custom imports\n const { instance } = await WebAssembly.instantiateStreaming(source, {\n wasi_snapshot_preview1: wasi.wasiImport,\n env: {\n ...this.#loopbackBindings.imports,\n ...this.#tunBindings.imports,\n ...this.#tapBindings.imports,\n ...this.#bridgeBindings.imports,\n ...this.#tcpBindings.imports,\n ...this.#udpBindings.imports,\n },\n });\n\n const wasmInstance = instance as WasmInstance;\n\n this.#loopbackBindings.register(wasmInstance.exports);\n this.#tunBindings.register(wasmInstance.exports);\n this.#tapBindings.register(wasmInstance.exports);\n this.#bridgeBindings.register(wasmInstance.exports);\n this.#tcpBindings.register(wasmInstance.exports);\n this.#udpBindings.register(wasmInstance.exports);\n\n // Our WASM binary is a WASI reactor module (ie. a lib),\n // so we call `initialize()` instead of `start()`.\n wasi.initialize(wasmInstance);\n\n // Call lwIP's main loop regularly (required in NO_SYS mode)\n // Used to process queued packets (eg. loopback) and expired timeouts\n this.#loopIntervalId = Number(\n setInterval(() => {\n wasmInstance.exports.process_queued_packets();\n wasmInstance.exports.process_timeouts();\n }, 100)\n );\n }\n\n *#listInterfaces(): Iterable<NetworkInterface> {\n yield* this.#loopbackBindings.interfaces.values();\n yield* this.#tunBindings.interfaces.values();\n yield* this.#tapBindings.interfaces.values();\n yield* this.#bridgeBindings.interfaces.values();\n }\n\n async createLoopbackInterface(\n options: LoopbackInterfaceOptions\n ): Promise<LoopbackInterface> {\n await this.ready;\n return this.#loopbackBindings.create(options);\n }\n\n async createTunInterface(\n options: TunInterfaceOptions\n ): Promise<TunInterface> {\n await this.ready;\n return this.#tunBindings.create(options);\n }\n\n async createTapInterface(\n options: TapInterfaceOptions = {}\n ): Promise<TapInterface> {\n await this.ready;\n return this.#tapBindings.create(options);\n }\n\n async createBridgeInterface(options: BridgeInterfaceOptions) {\n await this.ready;\n return this.#bridgeBindings.create(options);\n }\n\n async removeInterface(netInterface: NetworkInterface) {\n await this.ready;\n\n switch (netInterface.type) {\n case 'loopback':\n return this.#loopbackBindings.remove(netInterface);\n case 'tun':\n return this.#tunBindings.remove(netInterface);\n case 'tap':\n return this.#tapBindings.remove(netInterface);\n case 'bridge':\n return this.#bridgeBindings.remove(netInterface);\n default:\n throw new Error('unknown interface type');\n }\n }\n\n /**\n * Listens for incoming TCP connections on the specified host/port.\n */\n async listenTcp(options: TcpListenerOptions) {\n await this.ready;\n return this.#tcpBindings.listen(options);\n }\n\n /**\n * Establishes an outbound TCP connection to a remote host/port.\n */\n async connectTcp(options: TcpConnectionOptions) {\n await this.ready;\n return this.#tcpBindings.connect(options);\n }\n\n /**\n * Opens a UDP socket for sending and receiving datagrams.\n *\n * If no local host is provided, the socket will bind to all available interfaces.\n * If no local port is provided, the socket will bind to a random port.\n */\n async openUdp(options: UdpSocketOptions = {}) {\n await this.ready;\n return this.#udpBindings.open(options);\n }\n}\n","import {\n type IPv4Address,\n type MacAddress,\n generateMacAddress,\n parseIPv4Address,\n parseMacAddress,\n serializeIPv4Cidr,\n serializeMacAddress,\n} from '@tcpip/wire';\nimport type { BridgeInterface, BridgeInterfaceOptions } from '../types.js';\nimport { Hooks } from '../util.js';\nimport { Bindings } from './base.js';\nimport { tapInterfaceHooks } from './tap-interface.js';\nimport type { Pointer } from './types.js';\n\ntype BridgeInterfaceHandle = Pointer;\n\ntype BridgeInterfaceOuterHooks = {\n handle: BridgeInterfaceHandle;\n getMacAddress(): MacAddress;\n getIPv4Address(): IPv4Address | undefined;\n getIPv4Netmask(): IPv4Address | undefined;\n};\n\n// biome-ignore lint/complexity/noBannedTypes: intentionally empty hook type\ntype BridgeInterfaceInnerHooks = {};\n\nexport const bridgeInterfaceHooks = new Hooks<\n BridgeInterface,\n BridgeInterfaceOuterHooks,\n BridgeInterfaceInnerHooks\n>();\n\n// biome-ignore lint/complexity/noBannedTypes: intentionally empty imports type\nexport type BridgeImports = {};\n\nexport type BridgeExports = {\n create_bridge_interface(\n macAddress: Pointer,\n ipAddress: Pointer,\n netmask: Pointer,\n ports: Pointer,\n ports_length: number\n ): BridgeInterfaceHandle;\n remove_bridge_interface(handle: BridgeInterfaceHandle): void;\n};\n\nexport class BridgeBindings extends Bindings<BridgeImports, BridgeExports> {\n interfaces = new Map<BridgeInterfaceHandle, BridgeInterface>();\n\n imports = {};\n\n async create(options: BridgeInterfaceOptions) {\n const macAddress = options.mac\n ? serializeMacAddress(options.mac)\n : generateMacAddress();\n\n const { ipAddress, netmask } = options.ip\n ? serializeIPv4Cidr(options.ip)\n : {};\n\n using macAddressPtr = this.copyToMemory(macAddress);\n using ipAddressPtr = ipAddress ? this.copyToMemory(ipAddress) : undefined;\n using netmaskPtr = netmask ? this.copyToMemory(netmask) : undefined;\n const portHandles = new Uint32Array(\n options.ports.map((port) =>\n Number(tapInterfaceHooks.getOuter(port).handle)\n )\n );\n\n using portHandlesPtr = this.copyToMemory(\n new Uint8Array(portHandles.buffer)\n );\n\n const handle = this.exports.create_bridge_interface(\n macAddressPtr,\n ipAddressPtr ?? 0,\n netmaskPtr ?? 0,\n portHandlesPtr,\n options.ports.length\n );\n\n const bridgeInterface = new VirtualBridgeInterface();\n\n bridgeInterfaceHooks.setOuter(bridgeInterface, {\n handle,\n getMacAddress: () => {\n const macPtr = this.exports.get_interface_mac_address(handle);\n\n const macBytes = this.viewFromMemory(macPtr, 6);\n return parseMacAddress(macBytes);\n },\n getIPv4Address: () => {\n const ipPtr = this.exports.get_interface_ip4_address(handle);\n\n if (ipPtr === 0) {\n return;\n }\n\n const ipBytes = this.viewFromMemory(ipPtr, 4);\n return parseIPv4Address(ipBytes);\n },\n getIPv4Netmask: () => {\n const netmaskPtr = this.exports.get_interface_ip4_netmask(handle);\n\n if (netmaskPtr === 0) {\n return;\n }\n\n const netmaskBytes = this.viewFromMemory(netmaskPtr, 4);\n return parseIPv4Address(netmaskBytes);\n },\n });\n\n this.interfaces.set(handle, bridgeInterface);\n\n return bridgeInterface;\n }\n\n async remove(bridgeInterface: BridgeInterface) {\n for (const [handle, loopback] of this.interfaces.entries()) {\n if (loopback === bridgeInterface) {\n this.exports.remove_bridge_interface(handle);\n this.interfaces.delete(handle);\n return;\n }\n }\n }\n}\n\nexport class VirtualBridgeInterface implements BridgeInterface {\n readonly type = 'bridge';\n get mac(): MacAddress {\n return bridgeInterfaceHooks.getOuter(this).getMacAddress();\n }\n get ip(): IPv4Address | undefined {\n return bridgeInterfaceHooks.getOuter(this).getIPv4Address();\n }\n get netmask(): IPv4Address | undefined {\n return bridgeInterfaceHooks.getOuter(this).getIPv4Netmask();\n }\n}\n","import type { DuplexStream } from './types.js';\n\n/**\n * Utility class to facilitate internal communication\n * between bindings and JS instances.\n * Hooks are created for both the outer (bindings) and\n * inner (JS instance) sides of the communication.\n *\n * Uses `WeakMap` to map each JS instance to a set of\n * hooks while avoiding memory leaks.\n */\nexport class Hooks<K extends WeakKey, O, I> {\n #outerHooks = new WeakMap<K, O>();\n #innerHooks = new WeakMap<K, I>();\n\n setOuter(key: K, hooks: O) {\n this.#outerHooks.set(key, hooks);\n }\n\n setInner(key: K, hooks: I) {\n this.#innerHooks.set(key, hooks);\n }\n\n getOuter(key: K) {\n const hooks = this.#outerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`outer hooks not set for ${key}`);\n }\n\n return hooks;\n }\n\n getInner(key: K) {\n const hooks = this.#innerHooks.get(key);\n\n if (!hooks) {\n throw new Error(`inner hooks not set for ${key}`);\n }\n\n return hooks;\n }\n}\n\nexport class UniquePointer extends Number {\n free: (ptr: number) => void;\n\n /**\n * A unique pointer that will automatically free virtual memory when\n * it is disposed. Named after the C++ concept of a unique pointer.\n *\n * Should be used with the `using` keyword to ensure that the pointer is\n * freed (via dispose function) when it is no longer in scope.\n *\n * Useful with WASM modules that require allocating and freeing memory.\n *\n * @example\n * ```ts\n * using ptr = new UniquePointer(wasmBridge.malloc(10), wasmBridge.free);\n * ```\n *\n * @param address The address of the pointer\n * @param free The function to call to free the pointer\n */\n constructor(address: number, free: (ptr: number) => void) {\n super(address);\n this.free = free;\n }\n\n [Symbol.dispose]() {\n this.free(this.valueOf());\n }\n}\n\n/**\n * Map that allows waiting for changes to values.\n */\nexport class EventMap<K, V> extends Map<K, V> {\n #listeners = new Map<K, Set<(value: V) => void>>();\n\n /**\n * Waits for the next `set()` call on the given key.\n */\n wait(key: K): Promise<V> {\n return new Promise((resolve) => {\n const listeners = this.#listeners.get(key) ?? new Set();\n listeners.add(resolve);\n this.#listeners.set(key, listeners);\n });\n }\n\n override set(key: K, value: V) {\n super.set(key, value);\n\n const listeners = this.#listeners.get(key);\n\n if (listeners) {\n for (const listener of listeners) {\n listener(value);\n listeners.delete(listener);\n }\n }\n\n return this;\n }\n}\n\n/**\n * Converts a `ReadableStream` into an `AsyncIterableIterator`.\n *\n * Allows you to use ReadableStreams in a `for await ... of` loop.\n */\nexport function fromReadable<R>(\n readable: ReadableStream<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n const reader = readable.getReader();\n return fromReader(reader, options);\n}\n\n/**\n * Converts a `ReadableStreamDefaultReader` into an `AsyncIterableIterator`.\n *\n * Allows you to use Readers in a `for await ... of` loop.\n */\nexport async function* fromReader<R>(\n reader: ReadableStreamDefaultReader<R>,\n options?: { preventCancel?: boolean }\n): AsyncIterableIterator<R> {\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n return value;\n }\n yield value;\n }\n } finally {\n if (!options?.preventCancel) {\n await reader.cancel();\n }\n reader.releaseLock();\n }\n}\n\nexport type UnderlyingSourceLockCallback = () => void;\n\n/**\n * `ReadableStream` with an optional lock callback.\n */\nexport class ExtendedReadableStream<R> extends ReadableStream<R> {\n #notifyLock?: () => void;\n\n constructor(\n {\n lock,\n ...underlyingSource\n }: UnderlyingSource & { lock?: UnderlyingSourceLockCallback },\n strategy?: QueuingStrategy<R>\n ) {\n super(underlyingSource, strategy);\n this.#notifyLock = lock;\n }\n\n override getReader() {\n // biome-ignore lint/suspicious/noExplicitAny: ReadableStream types don't expose internal reader methods\n const reader = super.getReader() as any;\n if (this.locked) {\n this.#notifyLock?.();\n }\n return reader;\n }\n\n override pipeThrough<T>(\n transform: ReadableWritablePair<T, R>,\n options?: StreamPipeOptions\n ): ReadableStream<T> {\n const stream = super.pipeThrough(transform, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return stream;\n }\n\n override pipeTo(\n dest: WritableStream<R>,\n options?: StreamPipeOptions\n ): Promise<void> {\n const promise = super.pipeTo(dest, options);\n if (this.locked) {\n this.#notifyLock?.();\n }\n return promise;\n }\n\n override tee(): [ReadableStream<R>, ReadableStream<R>] {\n const [a, b] = super.tee();\n if (this.locked) {\n this.#notifyLock?.();\n }\n return [a, b];\n }\n}\n\n/**\n * Queues a microtask and returns a promise that resolves when\n * the microtask is executed.\n *\n * Microtasks are executed after the current task has completed,\n * but before the next task begins (tasks are the main unit of\n * work in the event loop).\n *\n * Useful when you want synchronous code from the current task to\n * complete before executing asynchronous code.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/HTML_DOM_API/Microtask_guide\n */\nexport async function nextMicrotask() {\n return await new Promise<void>((resolve) => queueMicrotask(resolve));\n}\n\nexport type ConnectInterfacesOptions = {\n transformAtoB?: (chunk: Uint8Array) => Uint8Array;\n transformBtoA?: (chunk: Uint8Array) => Uint8Array;\n};\n\n/**\n * Connects two duplex streams by piping each stream's `readable`\n * to the other's `writable`.\n *\n * This is useful for connecting two network interfaces together\n * (e.g. a tap interface and a v86 network interface).\n *\n * Optionally supports transforming the data as it is passed\n * between the two streams. Use this to log or modify the data.\n */\nexport function connectStreams(\n interfaceA: DuplexStream<Uint8Array>,\n interfaceB: DuplexStream<Uint8Array>,\n { transformAtoB, transformBtoA }: ConnectInterfacesOptions = {}\n) {\n const streamA = transformAtoB\n ? interfaceA.readable.pipeThrough(\n new TransformStream<Uint8Array>({\n transform(chunk, controller) {\n try {\n const transformedChunk = transformAtoB(chunk);\n controller.enqueue(transformedChunk);\n } catch (error) {\n console.warn('Error transforming A to B', error);\n }\n },\n })\n )\n : interfaceA.readable;\n\n const streamB = transformBtoA\n ? interfaceB.readable.pipeThrough(\n new TransformStream<Uint8Array>({\n transform(chunk, controller) {\n try {\n const transformedChunk = transformBtoA(chunk);\n controller.enqueue(transformedChunk);\n } catch (error) {\n console.warn('Error transforming B to A', error);\n }\n },\n })\n )\n : interfaceB.readable;\n\n streamA.pipeTo(interfaceB.writable);\n streamB.pipeTo(interfaceA.writable);\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,100 +1,23 @@
|
|
|
1
|
-
import { MacAddress, IPv4Cidr, IPv4Address } from '@tcpip/wire';
|
|
2
1
|
import { NameServer } from '@tcpip/dns';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
ip?: IPv4Cidr;
|
|
23
|
-
};
|
|
24
|
-
type BridgeInterface = {
|
|
25
|
-
readonly type: 'bridge';
|
|
26
|
-
readonly mac: MacAddress;
|
|
27
|
-
readonly ip?: IPv4Address;
|
|
28
|
-
readonly netmask?: IPv4Address;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type LoopbackInterfaceOptions = {
|
|
32
|
-
ip?: IPv4Cidr;
|
|
33
|
-
};
|
|
34
|
-
type LoopbackInterface = {
|
|
35
|
-
readonly type: 'loopback';
|
|
36
|
-
readonly ip?: IPv4Address;
|
|
37
|
-
readonly netmask?: IPv4Address;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
type TcpListenerOptions = {
|
|
41
|
-
host?: string;
|
|
42
|
-
port: number;
|
|
43
|
-
};
|
|
44
|
-
type TcpListener = {
|
|
45
|
-
[Symbol.asyncIterator](): AsyncIterableIterator<TcpConnection>;
|
|
46
|
-
};
|
|
47
|
-
type TcpConnectionOptions = {
|
|
48
|
-
host: string;
|
|
49
|
-
port: number;
|
|
50
|
-
};
|
|
51
|
-
type TcpConnection = {
|
|
52
|
-
readable: ReadableStream<Uint8Array>;
|
|
53
|
-
writable: WritableStream<Uint8Array>;
|
|
54
|
-
close(): Promise<void>;
|
|
55
|
-
[Symbol.asyncIterator](): AsyncIterator<Uint8Array>;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
type TunInterfaceOptions = {
|
|
59
|
-
ip?: IPv4Cidr;
|
|
60
|
-
};
|
|
61
|
-
type TunInterface = {
|
|
62
|
-
readonly type: 'tun';
|
|
63
|
-
readonly ip?: IPv4Address;
|
|
64
|
-
readonly netmask?: IPv4Address;
|
|
65
|
-
readable: ReadableStream<Uint8Array>;
|
|
66
|
-
writable: WritableStream<Uint8Array>;
|
|
67
|
-
listen(): AsyncIterableIterator<Uint8Array>;
|
|
68
|
-
[Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array>;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
type NetworkInterface = LoopbackInterface | TunInterface | TapInterface | BridgeInterface;
|
|
72
|
-
|
|
73
|
-
type UdpDatagram = {
|
|
74
|
-
host: string;
|
|
75
|
-
port: number;
|
|
76
|
-
data: Uint8Array;
|
|
77
|
-
};
|
|
78
|
-
type UdpSocketOptions = {
|
|
79
|
-
/**
|
|
80
|
-
* The local host to bind to.
|
|
81
|
-
*
|
|
82
|
-
* If not provided, the socket will bind to all available interfaces.
|
|
83
|
-
*/
|
|
84
|
-
host?: string;
|
|
85
|
-
/**
|
|
86
|
-
* The local port to bind to.
|
|
87
|
-
*
|
|
88
|
-
* If not provided, the socket will bind to a random port.
|
|
89
|
-
*/
|
|
90
|
-
port?: number;
|
|
91
|
-
};
|
|
92
|
-
type UdpSocket = {
|
|
93
|
-
readable: ReadableStream<UdpDatagram>;
|
|
94
|
-
writable: WritableStream<UdpDatagram>;
|
|
95
|
-
close(): Promise<void>;
|
|
96
|
-
[Symbol.asyncIterator](): AsyncIterator<UdpDatagram>;
|
|
97
|
-
};
|
|
2
|
+
import { DuplexStream, NetworkStack } from './types.cjs';
|
|
3
|
+
export { BridgeInterface, BridgeInterfaceOptions, LoopbackInterface, LoopbackInterfaceOptions, NetworkInterface, TapInterface, TapInterfaceOptions, TcpConnection, TcpConnectionOptions, TcpListener, TcpListenerOptions, TunInterface, TunInterfaceOptions, UdpDatagram, UdpSocket, UdpSocketOptions } from './types.cjs';
|
|
4
|
+
import '@tcpip/wire';
|
|
5
|
+
|
|
6
|
+
type ConnectInterfacesOptions = {
|
|
7
|
+
transformAtoB?: (chunk: Uint8Array) => Uint8Array;
|
|
8
|
+
transformBtoA?: (chunk: Uint8Array) => Uint8Array;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Connects two duplex streams by piping each stream's `readable`
|
|
12
|
+
* to the other's `writable`.
|
|
13
|
+
*
|
|
14
|
+
* This is useful for connecting two network interfaces together
|
|
15
|
+
* (e.g. a tap interface and a v86 network interface).
|
|
16
|
+
*
|
|
17
|
+
* Optionally supports transforming the data as it is passed
|
|
18
|
+
* between the two streams. Use this to log or modify the data.
|
|
19
|
+
*/
|
|
20
|
+
declare function connectStreams(interfaceA: DuplexStream<Uint8Array>, interfaceB: DuplexStream<Uint8Array>, { transformAtoB, transformBtoA }?: ConnectInterfacesOptions): void;
|
|
98
21
|
|
|
99
22
|
declare function createStack(options?: NetworkStackOptions): Promise<NetworkStack>;
|
|
100
23
|
type NetworkStackOptions = {
|
|
@@ -111,29 +34,5 @@ type NetworkStackOptions = {
|
|
|
111
34
|
*/
|
|
112
35
|
nameServer?: NameServer;
|
|
113
36
|
};
|
|
114
|
-
type NetworkStack = {
|
|
115
|
-
readonly ready: Promise<void>;
|
|
116
|
-
readonly interfaces: Iterable<NetworkInterface>;
|
|
117
|
-
createLoopbackInterface(options: LoopbackInterfaceOptions): Promise<LoopbackInterface>;
|
|
118
|
-
createTunInterface(options: TunInterfaceOptions): Promise<TunInterface>;
|
|
119
|
-
createTapInterface(options?: TapInterfaceOptions): Promise<TapInterface>;
|
|
120
|
-
createBridgeInterface(options: BridgeInterfaceOptions): Promise<BridgeInterface>;
|
|
121
|
-
removeInterface(netInterface: LoopbackInterface | TunInterface | TapInterface): Promise<void>;
|
|
122
|
-
/**
|
|
123
|
-
* Listens for incoming TCP connections on the specified host/port.
|
|
124
|
-
*/
|
|
125
|
-
listenTcp(options: TcpListenerOptions): Promise<TcpListener>;
|
|
126
|
-
/**
|
|
127
|
-
* Establishes an outbound TCP connection to a remote host/port.
|
|
128
|
-
*/
|
|
129
|
-
connectTcp(options: TcpConnectionOptions): Promise<TcpConnection>;
|
|
130
|
-
/**
|
|
131
|
-
* Opens a UDP socket for sending and receiving datagrams.
|
|
132
|
-
*
|
|
133
|
-
* If no local host is provided, the socket will bind to all available interfaces.
|
|
134
|
-
* If no local port is provided, the socket will bind to a random port.
|
|
135
|
-
*/
|
|
136
|
-
openUdp(options?: UdpSocketOptions): Promise<UdpSocket>;
|
|
137
|
-
};
|
|
138
37
|
|
|
139
|
-
export {
|
|
38
|
+
export { DuplexStream, NetworkStack, connectStreams, createStack };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,100 +1,23 @@
|
|
|
1
|
-
import { MacAddress, IPv4Cidr, IPv4Address } from '@tcpip/wire';
|
|
2
1
|
import { NameServer } from '@tcpip/dns';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
ip?: IPv4Cidr;
|
|
23
|
-
};
|
|
24
|
-
type BridgeInterface = {
|
|
25
|
-
readonly type: 'bridge';
|
|
26
|
-
readonly mac: MacAddress;
|
|
27
|
-
readonly ip?: IPv4Address;
|
|
28
|
-
readonly netmask?: IPv4Address;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
type LoopbackInterfaceOptions = {
|
|
32
|
-
ip?: IPv4Cidr;
|
|
33
|
-
};
|
|
34
|
-
type LoopbackInterface = {
|
|
35
|
-
readonly type: 'loopback';
|
|
36
|
-
readonly ip?: IPv4Address;
|
|
37
|
-
readonly netmask?: IPv4Address;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
type TcpListenerOptions = {
|
|
41
|
-
host?: string;
|
|
42
|
-
port: number;
|
|
43
|
-
};
|
|
44
|
-
type TcpListener = {
|
|
45
|
-
[Symbol.asyncIterator](): AsyncIterableIterator<TcpConnection>;
|
|
46
|
-
};
|
|
47
|
-
type TcpConnectionOptions = {
|
|
48
|
-
host: string;
|
|
49
|
-
port: number;
|
|
50
|
-
};
|
|
51
|
-
type TcpConnection = {
|
|
52
|
-
readable: ReadableStream<Uint8Array>;
|
|
53
|
-
writable: WritableStream<Uint8Array>;
|
|
54
|
-
close(): Promise<void>;
|
|
55
|
-
[Symbol.asyncIterator](): AsyncIterator<Uint8Array>;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
type TunInterfaceOptions = {
|
|
59
|
-
ip?: IPv4Cidr;
|
|
60
|
-
};
|
|
61
|
-
type TunInterface = {
|
|
62
|
-
readonly type: 'tun';
|
|
63
|
-
readonly ip?: IPv4Address;
|
|
64
|
-
readonly netmask?: IPv4Address;
|
|
65
|
-
readable: ReadableStream<Uint8Array>;
|
|
66
|
-
writable: WritableStream<Uint8Array>;
|
|
67
|
-
listen(): AsyncIterableIterator<Uint8Array>;
|
|
68
|
-
[Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array>;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
type NetworkInterface = LoopbackInterface | TunInterface | TapInterface | BridgeInterface;
|
|
72
|
-
|
|
73
|
-
type UdpDatagram = {
|
|
74
|
-
host: string;
|
|
75
|
-
port: number;
|
|
76
|
-
data: Uint8Array;
|
|
77
|
-
};
|
|
78
|
-
type UdpSocketOptions = {
|
|
79
|
-
/**
|
|
80
|
-
* The local host to bind to.
|
|
81
|
-
*
|
|
82
|
-
* If not provided, the socket will bind to all available interfaces.
|
|
83
|
-
*/
|
|
84
|
-
host?: string;
|
|
85
|
-
/**
|
|
86
|
-
* The local port to bind to.
|
|
87
|
-
*
|
|
88
|
-
* If not provided, the socket will bind to a random port.
|
|
89
|
-
*/
|
|
90
|
-
port?: number;
|
|
91
|
-
};
|
|
92
|
-
type UdpSocket = {
|
|
93
|
-
readable: ReadableStream<UdpDatagram>;
|
|
94
|
-
writable: WritableStream<UdpDatagram>;
|
|
95
|
-
close(): Promise<void>;
|
|
96
|
-
[Symbol.asyncIterator](): AsyncIterator<UdpDatagram>;
|
|
97
|
-
};
|
|
2
|
+
import { DuplexStream, NetworkStack } from './types.js';
|
|
3
|
+
export { BridgeInterface, BridgeInterfaceOptions, LoopbackInterface, LoopbackInterfaceOptions, NetworkInterface, TapInterface, TapInterfaceOptions, TcpConnection, TcpConnectionOptions, TcpListener, TcpListenerOptions, TunInterface, TunInterfaceOptions, UdpDatagram, UdpSocket, UdpSocketOptions } from './types.js';
|
|
4
|
+
import '@tcpip/wire';
|
|
5
|
+
|
|
6
|
+
type ConnectInterfacesOptions = {
|
|
7
|
+
transformAtoB?: (chunk: Uint8Array) => Uint8Array;
|
|
8
|
+
transformBtoA?: (chunk: Uint8Array) => Uint8Array;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Connects two duplex streams by piping each stream's `readable`
|
|
12
|
+
* to the other's `writable`.
|
|
13
|
+
*
|
|
14
|
+
* This is useful for connecting two network interfaces together
|
|
15
|
+
* (e.g. a tap interface and a v86 network interface).
|
|
16
|
+
*
|
|
17
|
+
* Optionally supports transforming the data as it is passed
|
|
18
|
+
* between the two streams. Use this to log or modify the data.
|
|
19
|
+
*/
|
|
20
|
+
declare function connectStreams(interfaceA: DuplexStream<Uint8Array>, interfaceB: DuplexStream<Uint8Array>, { transformAtoB, transformBtoA }?: ConnectInterfacesOptions): void;
|
|
98
21
|
|
|
99
22
|
declare function createStack(options?: NetworkStackOptions): Promise<NetworkStack>;
|
|
100
23
|
type NetworkStackOptions = {
|
|
@@ -111,29 +34,5 @@ type NetworkStackOptions = {
|
|
|
111
34
|
*/
|
|
112
35
|
nameServer?: NameServer;
|
|
113
36
|
};
|
|
114
|
-
type NetworkStack = {
|
|
115
|
-
readonly ready: Promise<void>;
|
|
116
|
-
readonly interfaces: Iterable<NetworkInterface>;
|
|
117
|
-
createLoopbackInterface(options: LoopbackInterfaceOptions): Promise<LoopbackInterface>;
|
|
118
|
-
createTunInterface(options: TunInterfaceOptions): Promise<TunInterface>;
|
|
119
|
-
createTapInterface(options?: TapInterfaceOptions): Promise<TapInterface>;
|
|
120
|
-
createBridgeInterface(options: BridgeInterfaceOptions): Promise<BridgeInterface>;
|
|
121
|
-
removeInterface(netInterface: LoopbackInterface | TunInterface | TapInterface): Promise<void>;
|
|
122
|
-
/**
|
|
123
|
-
* Listens for incoming TCP connections on the specified host/port.
|
|
124
|
-
*/
|
|
125
|
-
listenTcp(options: TcpListenerOptions): Promise<TcpListener>;
|
|
126
|
-
/**
|
|
127
|
-
* Establishes an outbound TCP connection to a remote host/port.
|
|
128
|
-
*/
|
|
129
|
-
connectTcp(options: TcpConnectionOptions): Promise<TcpConnection>;
|
|
130
|
-
/**
|
|
131
|
-
* Opens a UDP socket for sending and receiving datagrams.
|
|
132
|
-
*
|
|
133
|
-
* If no local host is provided, the socket will bind to all available interfaces.
|
|
134
|
-
* If no local port is provided, the socket will bind to a random port.
|
|
135
|
-
*/
|
|
136
|
-
openUdp(options?: UdpSocketOptions): Promise<UdpSocket>;
|
|
137
|
-
};
|
|
138
37
|
|
|
139
|
-
export {
|
|
38
|
+
export { DuplexStream, NetworkStack, connectStreams, createStack };
|