@@ -65,9 +65,38 @@ export class CaipStream extends Duplex {
6565export const createCaipStream = ( portStream : Duplex ) : Duplex => {
6666 const caipStream = new CaipStream ( ) ;
6767
68- pipeline ( portStream , caipStream , portStream , ( err : Error ) => {
69- caipStream . substream . destroy ( ) ;
70- console . log ( 'MetaMask CAIP stream' , err ) ;
68+ /** Cleanly end the CAIP side if the port goes away. */
69+ const handlePortGone = ( ) => {
70+ // End only once
71+ if (
72+ ! caipStream . substream . destroyed &&
73+ ! caipStream . substream . writableEnded
74+ ) {
75+ caipStream . substream . end ( ) ;
76+ }
77+ } ;
78+
79+ /* ---------- 1. Listen for tab / iframe shutdown signals ---------- */
80+
81+ // a. Node-style streams emit 'close' and/or 'end'
82+ portStream . once ?.( 'close' , handlePortGone ) ;
83+ portStream . once ?.( 'end' , handlePortGone ) ;
84+
85+ // b. chrome.runtime.Port exposes onDisconnect
86+ // (ExtensionPortStream exposes the raw Port at `._port`)
87+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
88+ const rawPort : chrome . runtime . Port | undefined = ( portStream as any ) ?. _port ;
89+ rawPort ?. onDisconnect ?. addListener ( handlePortGone ) ;
90+
91+ /* ---------- 2. Wire up the full duplex pipeline ---------- */
92+
93+ pipeline ( portStream , caipStream , portStream , ( err : Error | null ) => {
94+ caipStream . substream . destroy ( ) ; // full cleanup
95+
96+ // Ignore the normal premature-close that used to spam the console
97+ if ( err && err . message !== 'Premature close' ) {
98+ console . error ( 'MetaMask CAIP stream error:' , err ) ;
99+ }
71100 } ) ;
72101
73102 return caipStream . substream ;
0 commit comments