fix(smartpdf): clean up SmartNetwork instances during port selection and shutdown

This commit is contained in:
2026-04-30 11:50:38 +00:00
parent d26608b4fa
commit 34aeaf7f1b
3 changed files with 46 additions and 25 deletions
+7
View File
@@ -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
+1 -1
View File
@@ -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.'
}
+38 -24
View File
@@ -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 = {};
}