{"version":3,"file":"SocketClientTransport.cjs","names":[],"sources":["../../src/SocketClientTransport.ts"],"sourcesContent":["/**\n * A client-side transport for BRC-103 using Socket.IO client.\n *\n * The BRC-103 `Peer` uses `transport.send()` to send an `AuthMessage`,\n * which is forwarded via `this.socket.emit('authMessage', message)`.\n *\n * This class also listens for `'authMessage'` events from the server.\n */\nimport { Socket as IoClientSocket } from 'socket.io-client'\nimport { AuthMessage, Transport } from '@bsv/sdk'\n\nconst DEFAULT_MAX_PENDING_MESSAGES = 32\n\nexport interface SocketClientTransportOptions {\n  /** Maximum authentication messages that may be processed concurrently per socket. */\n  maxPendingMessages?: number\n  /** Receives contained authentication failures. The hook is never allowed to throw outward. */\n  onError?: (error: unknown) => void | Promise<void>\n}\n\nexport class SocketClientTransport implements Transport {\n  private onDataCallback?: (message: AuthMessage) => Promise<void>\n  private readonly maxPendingMessages: number\n  private readonly onError?: (error: unknown) => void | Promise<void>\n  private pendingMessages = 0\n  private failed = false\n\n  constructor(\n    private readonly socket: IoClientSocket,\n    options: SocketClientTransportOptions = {}\n  ) {\n    const maxPendingMessages = options.maxPendingMessages ?? DEFAULT_MAX_PENDING_MESSAGES\n    if (!Number.isSafeInteger(maxPendingMessages) || maxPendingMessages < 1) {\n      throw new RangeError('maxPendingMessages must be a positive safe integer')\n    }\n    this.maxPendingMessages = maxPendingMessages\n    this.onError = options.onError\n\n    // Subscribe to the 'authMessage' event from the server\n    this.socket.on('authMessage', (msg: AuthMessage) => {\n      return this.processMessage(msg)\n    })\n  }\n\n  /**\n   * Send an AuthMessage to the server.\n   */\n  async send(message: AuthMessage): Promise<void> {\n    this.socket.emit('authMessage', message)\n  }\n\n  /**\n   * Register a callback to handle incoming AuthMessages.\n   */\n  async onData(callback: (message: AuthMessage) => Promise<void>): Promise<void> {\n    this.onDataCallback = callback\n  }\n\n  private async processMessage(message: AuthMessage): Promise<void> {\n    if (this.failed || this.onDataCallback === undefined) return\n    if (this.pendingMessages >= this.maxPendingMessages) {\n      this.fail(new Error('Authentication message concurrency limit exceeded'))\n      return\n    }\n\n    this.pendingMessages += 1\n    try {\n      await this.onDataCallback(message)\n    } catch (error) {\n      this.fail(error)\n    } finally {\n      this.pendingMessages -= 1\n    }\n  }\n\n  private fail(error: unknown): void {\n    if (this.failed) return\n    this.failed = true\n    void Promise.resolve()\n      .then(async () => await this.onError?.(error))\n      .catch(() => {})\n    try {\n      this.socket.disconnect()\n    } catch {\n      // A transport failure is already contained; disconnect errors are non-actionable here.\n    }\n  }\n}\n"],"mappings":";AAWA,MAAM,+BAA+B;AASrC,IAAa,wBAAb,MAAwD;CAQnC;CAPnB;CACA;CACA;CACA,kBAA0B;CAC1B,SAAiB;CAEjB,YACE,QACA,UAAwC,CAAC,GACzC;EAFiB,KAAA,SAAA;EAGjB,MAAM,qBAAqB,QAAQ,sBAAsB;EACzD,IAAI,CAAC,OAAO,cAAc,kBAAkB,KAAK,qBAAqB,GACpE,MAAM,IAAI,WAAW,oDAAoD;EAE3E,KAAK,qBAAqB;EAC1B,KAAK,UAAU,QAAQ;EAGvB,KAAK,OAAO,GAAG,gBAAgB,QAAqB;GAClD,OAAO,KAAK,eAAe,GAAG;EAChC,CAAC;CACH;;;;CAKA,MAAM,KAAK,SAAqC;EAC9C,KAAK,OAAO,KAAK,eAAe,OAAO;CACzC;;;;CAKA,MAAM,OAAO,UAAkE;EAC7E,KAAK,iBAAiB;CACxB;CAEA,MAAc,eAAe,SAAqC;EAChE,IAAI,KAAK,UAAU,KAAK,mBAAmB,KAAA,GAAW;EACtD,IAAI,KAAK,mBAAmB,KAAK,oBAAoB;GACnD,KAAK,qBAAK,IAAI,MAAM,mDAAmD,CAAC;GACxE;EACF;EAEA,KAAK,mBAAmB;EACxB,IAAI;GACF,MAAM,KAAK,eAAe,OAAO;EACnC,SAAS,OAAO;GACd,KAAK,KAAK,KAAK;EACjB,UAAU;GACR,KAAK,mBAAmB;EAC1B;CACF;CAEA,KAAa,OAAsB;EACjC,IAAI,KAAK,QAAQ;EACjB,KAAK,SAAS;EACd,QAAa,QAAQ,CAAC,CACnB,KAAK,YAAY,MAAM,KAAK,UAAU,KAAK,CAAC,CAAC,CAC7C,YAAY,CAAC,CAAC;EACjB,IAAI;GACF,KAAK,OAAO,WAAW;EACzB,QAAQ,CAER;CACF;AACF"}