diff --git a/changelog.md b/changelog.md index 14f6d1f..5456967 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,12 @@ # Changelog +## 2026-04-30 - 4.2.2 - fix(smartpdf) +clean up SmartNetwork instances during port selection and shutdown + +- stores the temporary SmartNetwork instance used for port discovery so it can be stopped reliably +- wraps port availability checks and free-port lookup in a finally block to ensure cleanup on success or failure +- extends shutdown logic to stop any remaining SmartNetwork instance alongside the SmartServe server + ## 2026-04-30 - 4.2.1 - fix(smartpdf) harden browser lifecycle, port handling, and PDF result metadata diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 991eff1..a5cb3e8 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@push.rocks/smartpdf', - version: '4.2.1', + version: '4.2.2', description: 'A library for creating PDFs dynamically from HTML or websites with additional features like merging PDFs.' } diff --git a/ts/smartpdf.classes.smartpdf.ts b/ts/smartpdf.classes.smartpdf.ts index 22832dc..b742279 100644 --- a/ts/smartpdf.classes.smartpdf.ts +++ b/ts/smartpdf.classes.smartpdf.ts @@ -32,6 +32,7 @@ export class SmartPdf { // INSTANCE private smartserveInstance: plugins.smartserve.SmartServe | null = null; + private smartnetworkInstance: plugins.smartnetwork.SmartNetwork | null = null; serverPort: number = 0; headlessBrowser: plugins.smartpuppeteer.puppeteer.Browser | null = null; externalBrowserBool: boolean = false; @@ -71,35 +72,43 @@ export class SmartPdf { // Find an available port BEFORE creating server const smartnetworkInstance = new plugins.smartnetwork.SmartNetwork(); + this.smartnetworkInstance = smartnetworkInstance; - if (this._options.port) { - // If a specific port is requested, check if it's available - const isPortAvailable = await smartnetworkInstance.isLocalPortUnused(this._options.port); - if (isPortAvailable) { - this.serverPort = this._options.port; + try { + if (this._options.port) { + // If a specific port is requested, check if it's available + const isPortAvailable = await smartnetworkInstance.isLocalPortUnused(this._options.port); + if (isPortAvailable) { + this.serverPort = this._options.port; + } else { + // Clean up browser if we created one + if (!this.externalBrowserBool && this.headlessBrowser) { + await this.headlessBrowser.close(); + this.headlessBrowser = null; + } + throw new Error(`Requested port ${this._options.port} is already in use`); + } } else { - // Clean up browser if we created one - if (!this.externalBrowserBool && this.headlessBrowser) { - await this.headlessBrowser.close(); - this.headlessBrowser = null; + // Find a free port in the specified range + const freePort = await smartnetworkInstance.findFreePort( + this._options.portRangeStart, + this._options.portRangeEnd + ); + if (!freePort) { + // Clean up browser if we created one + if (!this.externalBrowserBool && this.headlessBrowser) { + await this.headlessBrowser.close(); + this.headlessBrowser = null; + } + throw new Error(`No free ports available in range ${this._options.portRangeStart}-${this._options.portRangeEnd}`); } - throw new Error(`Requested port ${this._options.port} is already in use`); + this.serverPort = freePort; } - } else { - // Find a free port in the specified range - const freePort = await smartnetworkInstance.findFreePort( - this._options.portRangeStart, - this._options.portRangeEnd - ); - if (!freePort) { - // Clean up browser if we created one - if (!this.externalBrowserBool && this.headlessBrowser) { - await this.headlessBrowser.close(); - this.headlessBrowser = null; - } - throw new Error(`No free ports available in range ${this._options.portRangeStart}-${this._options.portRangeEnd}`); + } finally { + await smartnetworkInstance.stop(); + if (this.smartnetworkInstance === smartnetworkInstance) { + this.smartnetworkInstance = null; } - this.serverPort = freePort; } // Now setup server using smartserve @@ -150,6 +159,11 @@ export class SmartPdf { this.smartserveInstance = null; } + if (this.smartnetworkInstance) { + await this.smartnetworkInstance.stop(); + this.smartnetworkInstance = null; + } + // Clear any remaining candidates this._candidates = {}; }