@@ -11,9 +11,8 @@ import {
1111 RemoteConnector
1212} from '@powersync/common' ;
1313import { BSON } from 'bson' ;
14- import Agent from 'proxy-agent' ;
15- import { EnvHttpProxyAgent , Dispatcher } from 'undici' ;
16- import { WebSocket } from 'ws' ;
14+ import { Dispatcher , EnvHttpProxyAgent , ErrorEvent , WebSocket as UndiciWebSocket } from 'undici' ;
15+ import { ErrorRecordingDispatcher } from './ErrorRecordingDispatcher.js' ;
1716
1817export const STREAMING_POST_TIMEOUT_MS = 30_000 ;
1918
@@ -23,11 +22,21 @@ class NodeFetchProvider extends FetchImplementationProvider {
2322 }
2423}
2524
26- export type NodeRemoteOptions = AbstractRemoteOptions & {
25+ export type NodeCustomConnectionOptions = {
26+ /**
27+ * Optional custom dispatcher for HTTP or WEB_SOCKET connections.
28+ *
29+ * This can be used to customize proxy usage (using undici ProxyAgent),
30+ * or other connection options.
31+ */
2732 dispatcher ?: Dispatcher ;
2833} ;
2934
35+ export type NodeRemoteOptions = AbstractRemoteOptions & NodeCustomConnectionOptions ;
36+
3037export class NodeRemote extends AbstractRemote {
38+ private dispatcher : Dispatcher ;
39+
3140 constructor (
3241 protected connector : RemoteConnector ,
3342 protected logger : ILogger = DEFAULT_REMOTE_LOGGER ,
@@ -43,16 +52,34 @@ export class NodeRemote extends AbstractRemote {
4352 } ,
4453 ...( options ?? { } )
4554 } ) ;
55+
56+ this . dispatcher = dispatcher ;
4657 }
4758
4859 protected createSocket ( url : string ) : globalThis . WebSocket {
49- return new WebSocket ( url , {
50- // Automatically uses relevant env vars for web sockets
51- agent : new Agent . ProxyAgent ( ) ,
60+ // Create dedicated dispatcher for this WebSocket
61+ let ws : UndiciWebSocket | undefined ;
62+ const onError = ( error : Error ) => {
63+ // When we receive an error from the Dispatcher, emit the event on the websocket.
64+ // This will take precedence over the WebSocket's own error event, giving more details on what went wrong.
65+ const event = new ErrorEvent ( 'error' , {
66+ error,
67+ message : error . message
68+ } ) ;
69+ ws ?. dispatchEvent ( event ) ;
70+ } ;
71+
72+ const errorRecordingDispatcher = new ErrorRecordingDispatcher ( this . dispatcher , onError ) ;
73+
74+ // Create WebSocket with dedicated dispatcher
75+ ws = new UndiciWebSocket ( url , {
76+ dispatcher : errorRecordingDispatcher ,
5277 headers : {
5378 'User-Agent' : this . getUserAgent ( )
5479 }
55- } ) as any as globalThis . WebSocket ; // This is compatible in Node environments
80+ } ) ;
81+
82+ return ws as globalThis . WebSocket ;
5683 }
5784
5885 getUserAgent ( ) : string {
0 commit comments