@things-factory/shell 9.0.25 → 9.0.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-server/process-cleaner.d.ts +33 -0
- package/dist-server/process-cleaner.js +70 -75
- package/dist-server/process-cleaner.js.map +1 -1
- package/dist-server/pubsub.js +0 -23
- package/dist-server/pubsub.js.map +1 -1
- package/dist-server/server-dev.js +1 -0
- package/dist-server/server-dev.js.map +1 -1
- package/dist-server/server.js +1 -0
- package/dist-server/server.js.map +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/dist-server/utils/headless-pool/browser-factory.d.ts +27 -0
- package/dist-server/utils/headless-pool/browser-factory.js +144 -0
- package/dist-server/utils/headless-pool/browser-factory.js.map +1 -0
- package/dist-server/utils/headless-pool/config.d.ts +25 -0
- package/dist-server/utils/headless-pool/config.js +72 -0
- package/dist-server/utils/headless-pool/config.js.map +1 -0
- package/dist-server/utils/headless-pool/index.d.ts +98 -0
- package/dist-server/utils/headless-pool/index.js +131 -0
- package/dist-server/utils/headless-pool/index.js.map +1 -0
- package/dist-server/utils/headless-pool/pool-manager.d.ts +59 -0
- package/dist-server/utils/headless-pool/pool-manager.js +212 -0
- package/dist-server/utils/headless-pool/pool-manager.js.map +1 -0
- package/dist-server/utils/headless-pool/pool-stats.d.ts +29 -0
- package/dist-server/utils/headless-pool/pool-stats.js +80 -0
- package/dist-server/utils/headless-pool/pool-stats.js.map +1 -0
- package/dist-server/utils/index.d.ts +1 -0
- package/dist-server/utils/index.js +1 -0
- package/dist-server/utils/index.js.map +1 -1
- package/package.json +8 -6
@@ -0,0 +1,27 @@
|
|
1
|
+
import { HeadlessPoolConfig } from './config';
|
2
|
+
/**
|
3
|
+
* Browser Factory for creating and managing browser instances
|
4
|
+
*/
|
5
|
+
export declare class BrowserFactory {
|
6
|
+
/**
|
7
|
+
* Create a new browser instance
|
8
|
+
*/
|
9
|
+
static createBrowser(poolConfig: HeadlessPoolConfig): Promise<any>;
|
10
|
+
/**
|
11
|
+
* Validate browser instance
|
12
|
+
*/
|
13
|
+
static validateBrowser(browser: any): Promise<boolean>;
|
14
|
+
/**
|
15
|
+
* Safely destroy browser instance with multiple cleanup strategies
|
16
|
+
*/
|
17
|
+
static destroyBrowser(browser: any): Promise<void>;
|
18
|
+
private static gracefulDestroy;
|
19
|
+
/**
|
20
|
+
* Create browser with custom setup (for special cases like label pool)
|
21
|
+
*/
|
22
|
+
static createBrowserWithSetup(poolConfig: HeadlessPoolConfig, customSetup: (browser: any) => Promise<any>): Promise<any>;
|
23
|
+
private static getLaunchSettings;
|
24
|
+
private static closeAllPages;
|
25
|
+
private static killBrowserProcess;
|
26
|
+
private static forceKillProcess;
|
27
|
+
}
|
@@ -0,0 +1,144 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.BrowserFactory = void 0;
|
4
|
+
const env_1 = require("@things-factory/env");
|
5
|
+
// Dynamic puppeteer loading with error handling
|
6
|
+
let puppeteer;
|
7
|
+
try {
|
8
|
+
puppeteer = require('puppeteer');
|
9
|
+
}
|
10
|
+
catch (err) {
|
11
|
+
env_1.logger.warn('Puppeteer not available:', err);
|
12
|
+
}
|
13
|
+
/**
|
14
|
+
* Browser Factory for creating and managing browser instances
|
15
|
+
*/
|
16
|
+
class BrowserFactory {
|
17
|
+
/**
|
18
|
+
* Create a new browser instance
|
19
|
+
*/
|
20
|
+
static async createBrowser(poolConfig) {
|
21
|
+
if (!puppeteer) {
|
22
|
+
throw new Error('Puppeteer is not available');
|
23
|
+
}
|
24
|
+
const launchSettings = this.getLaunchSettings(poolConfig);
|
25
|
+
try {
|
26
|
+
const browser = await puppeteer.launch(launchSettings);
|
27
|
+
env_1.logger.info(`Browser instance created with headless: ${launchSettings.headless}`);
|
28
|
+
return browser;
|
29
|
+
}
|
30
|
+
catch (error) {
|
31
|
+
env_1.logger.error('Failed to create browser instance:', error);
|
32
|
+
throw error;
|
33
|
+
}
|
34
|
+
}
|
35
|
+
/**
|
36
|
+
* Validate browser instance
|
37
|
+
*/
|
38
|
+
static validateBrowser(browser) {
|
39
|
+
return Promise.race([
|
40
|
+
new Promise(resolve => setTimeout(() => resolve(false), 1500)),
|
41
|
+
browser
|
42
|
+
.version()
|
43
|
+
.then(() => true)
|
44
|
+
.catch(() => false)
|
45
|
+
]);
|
46
|
+
}
|
47
|
+
/**
|
48
|
+
* Safely destroy browser instance with multiple cleanup strategies
|
49
|
+
*/
|
50
|
+
static async destroyBrowser(browser) {
|
51
|
+
const timeout = 5000; // 5 second timeout
|
52
|
+
try {
|
53
|
+
await Promise.race([
|
54
|
+
this.gracefulDestroy(browser),
|
55
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Browser destruction timeout')), timeout))
|
56
|
+
]);
|
57
|
+
env_1.logger.info('🗑️ Browser instance destroyed successfully');
|
58
|
+
}
|
59
|
+
catch (error) {
|
60
|
+
env_1.logger.warn('⚠️ Error destroying browser instance:', error);
|
61
|
+
// Force kill as last resort
|
62
|
+
await this.forceKillProcess(browser);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
static async gracefulDestroy(browser) {
|
66
|
+
// Step 1: Close all pages
|
67
|
+
await this.closeAllPages(browser);
|
68
|
+
// Step 2: Standard close
|
69
|
+
await browser.close();
|
70
|
+
// Step 3: Kill browser process if still running
|
71
|
+
await this.killBrowserProcess(browser);
|
72
|
+
}
|
73
|
+
/**
|
74
|
+
* Create browser with custom setup (for special cases like label pool)
|
75
|
+
*/
|
76
|
+
static async createBrowserWithSetup(poolConfig, customSetup) {
|
77
|
+
const browser = await this.createBrowser(poolConfig);
|
78
|
+
try {
|
79
|
+
const result = await customSetup(browser);
|
80
|
+
return result;
|
81
|
+
}
|
82
|
+
catch (error) {
|
83
|
+
// If setup fails, cleanup the browser
|
84
|
+
await this.destroyBrowser(browser);
|
85
|
+
throw error;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
static getLaunchSettings(poolConfig) {
|
89
|
+
const settings = {
|
90
|
+
headless: poolConfig.headless || 'shell',
|
91
|
+
args: [...(poolConfig.args || [])],
|
92
|
+
handleSIGINT: false, // ★ 기본 핸들러 해제
|
93
|
+
handleSIGTERM: false,
|
94
|
+
handleSIGHUP: false
|
95
|
+
};
|
96
|
+
// Add executable path if specified in config or environment
|
97
|
+
const executablePath = poolConfig.executablePath || env_1.config.get('CHROMIUM_PATH');
|
98
|
+
if (executablePath) {
|
99
|
+
settings.executablePath = executablePath;
|
100
|
+
}
|
101
|
+
return settings;
|
102
|
+
}
|
103
|
+
static async closeAllPages(browser) {
|
104
|
+
try {
|
105
|
+
const pages = await browser.pages();
|
106
|
+
await Promise.all(pages.map((page) => page.close().catch(() => { })));
|
107
|
+
}
|
108
|
+
catch (error) {
|
109
|
+
env_1.logger.warn('Failed to close pages:', error);
|
110
|
+
}
|
111
|
+
}
|
112
|
+
static async killBrowserProcess(browser) {
|
113
|
+
try {
|
114
|
+
const process = browser.process();
|
115
|
+
if (process && !process.killed) {
|
116
|
+
// Try graceful termination first
|
117
|
+
process.kill('SIGTERM');
|
118
|
+
// Wait a bit, then force kill if still alive
|
119
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
120
|
+
if (!process.killed) {
|
121
|
+
process.kill('SIGKILL');
|
122
|
+
env_1.logger.info('🔪 Browser process force killed');
|
123
|
+
}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
catch (error) {
|
127
|
+
env_1.logger.warn('Failed to kill browser process:', error);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
static async forceKillProcess(browser) {
|
131
|
+
try {
|
132
|
+
const process = browser.process();
|
133
|
+
if (process && !process.killed) {
|
134
|
+
process.kill('SIGKILL');
|
135
|
+
env_1.logger.info('💀 Browser process force killed');
|
136
|
+
}
|
137
|
+
}
|
138
|
+
catch (killError) {
|
139
|
+
env_1.logger.error('💀 Failed to force kill browser process:', killError);
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
exports.BrowserFactory = BrowserFactory;
|
144
|
+
//# sourceMappingURL=browser-factory.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"browser-factory.js","sourceRoot":"","sources":["../../../server/utils/headless-pool/browser-factory.ts"],"names":[],"mappings":"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","sourcesContent":["import { config, logger } from '@things-factory/env'\nimport { HeadlessPoolConfig } from './config'\n\n// Dynamic puppeteer loading with error handling\nlet puppeteer: any\ntry {\n puppeteer = require('puppeteer')\n} catch (err) {\n logger.warn('Puppeteer not available:', err)\n}\n\n/**\n * Browser Factory for creating and managing browser instances\n */\nexport class BrowserFactory {\n /**\n * Create a new browser instance\n */\n static async createBrowser(poolConfig: HeadlessPoolConfig): Promise<any> {\n if (!puppeteer) {\n throw new Error('Puppeteer is not available')\n }\n\n const launchSettings = this.getLaunchSettings(poolConfig)\n\n try {\n const browser = await puppeteer.launch(launchSettings)\n logger.info(`Browser instance created with headless: ${launchSettings.headless}`)\n return browser\n } catch (error) {\n logger.error('Failed to create browser instance:', error)\n throw error\n }\n }\n\n /**\n * Validate browser instance\n */\n static validateBrowser(browser: any): Promise<boolean> {\n return Promise.race([\n new Promise<boolean>(resolve => setTimeout(() => resolve(false), 1500)),\n browser\n .version()\n .then(() => true)\n .catch(() => false)\n ])\n }\n\n /**\n * Safely destroy browser instance with multiple cleanup strategies\n */\n static async destroyBrowser(browser: any): Promise<void> {\n const timeout = 5000 // 5 second timeout\n\n try {\n await Promise.race([\n this.gracefulDestroy(browser),\n new Promise((_, reject) => setTimeout(() => reject(new Error('Browser destruction timeout')), timeout))\n ])\n\n logger.info('🗑️ Browser instance destroyed successfully')\n } catch (error) {\n logger.warn('⚠️ Error destroying browser instance:', error)\n\n // Force kill as last resort\n await this.forceKillProcess(browser)\n }\n }\n\n private static async gracefulDestroy(browser: any): Promise<void> {\n // Step 1: Close all pages\n await this.closeAllPages(browser)\n\n // Step 2: Standard close\n await browser.close()\n\n // Step 3: Kill browser process if still running\n await this.killBrowserProcess(browser)\n }\n\n /**\n * Create browser with custom setup (for special cases like label pool)\n */\n static async createBrowserWithSetup(\n poolConfig: HeadlessPoolConfig,\n customSetup: (browser: any) => Promise<any>\n ): Promise<any> {\n const browser = await this.createBrowser(poolConfig)\n\n try {\n const result = await customSetup(browser)\n return result\n } catch (error) {\n // If setup fails, cleanup the browser\n await this.destroyBrowser(browser)\n throw error\n }\n }\n\n private static getLaunchSettings(poolConfig: HeadlessPoolConfig) {\n const settings: any = {\n headless: poolConfig.headless || 'shell',\n args: [...(poolConfig.args || [])],\n handleSIGINT: false, // ★ 기본 핸들러 해제\n handleSIGTERM: false,\n handleSIGHUP: false\n }\n\n // Add executable path if specified in config or environment\n const executablePath = poolConfig.executablePath || config.get('CHROMIUM_PATH')\n if (executablePath) {\n settings.executablePath = executablePath\n }\n\n return settings\n }\n\n private static async closeAllPages(browser: any): Promise<void> {\n try {\n const pages = await browser.pages()\n await Promise.all(pages.map((page: any) => page.close().catch(() => {})))\n } catch (error) {\n logger.warn('Failed to close pages:', error)\n }\n }\n\n private static async killBrowserProcess(browser: any): Promise<void> {\n try {\n const process = browser.process()\n if (process && !process.killed) {\n // Try graceful termination first\n process.kill('SIGTERM')\n\n // Wait a bit, then force kill if still alive\n await new Promise(resolve => setTimeout(resolve, 1000))\n\n if (!process.killed) {\n process.kill('SIGKILL')\n logger.info('🔪 Browser process force killed')\n }\n }\n } catch (error) {\n logger.warn('Failed to kill browser process:', error)\n }\n }\n\n private static async forceKillProcess(browser: any): Promise<void> {\n try {\n const process = browser.process()\n if (process && !process.killed) {\n process.kill('SIGKILL')\n logger.info('💀 Browser process force killed')\n }\n } catch (killError) {\n logger.error('💀 Failed to force kill browser process:', killError)\n }\n }\n}\n"]}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/**
|
2
|
+
* Headless Pool Configuration
|
3
|
+
*/
|
4
|
+
export type HeadlessMode = 'shell' | 'new' | boolean;
|
5
|
+
export interface HeadlessPoolConfig {
|
6
|
+
min?: number;
|
7
|
+
max?: number;
|
8
|
+
acquireTimeoutMillis?: number;
|
9
|
+
idleTimeoutMillis?: number;
|
10
|
+
testOnBorrow?: boolean;
|
11
|
+
headless?: HeadlessMode;
|
12
|
+
args?: string[];
|
13
|
+
executablePath?: string;
|
14
|
+
enableStats?: boolean;
|
15
|
+
enableRecovery?: boolean;
|
16
|
+
enableCleanup?: boolean;
|
17
|
+
customSetup?: (browser: any) => Promise<any>;
|
18
|
+
}
|
19
|
+
export declare const DEFAULT_POOL_CONFIG: Required<Omit<HeadlessPoolConfig, 'customSetup'>>;
|
20
|
+
export declare const HEADLESS_POOL_ARGUMENT_SETS: {
|
21
|
+
basic: string[];
|
22
|
+
keychain_safe: string[];
|
23
|
+
security_enhanced: string[];
|
24
|
+
};
|
25
|
+
export declare function mergeConfig(base: HeadlessPoolConfig, override?: HeadlessPoolConfig): HeadlessPoolConfig;
|
@@ -0,0 +1,72 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* Headless Pool Configuration
|
4
|
+
*/
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.HEADLESS_POOL_ARGUMENT_SETS = exports.DEFAULT_POOL_CONFIG = void 0;
|
7
|
+
exports.mergeConfig = mergeConfig;
|
8
|
+
// Default configurations
|
9
|
+
exports.DEFAULT_POOL_CONFIG = {
|
10
|
+
// Pool defaults
|
11
|
+
min: 2,
|
12
|
+
max: 10,
|
13
|
+
acquireTimeoutMillis: 15000,
|
14
|
+
idleTimeoutMillis: 300000, // 5 minutes
|
15
|
+
testOnBorrow: true,
|
16
|
+
// Browser defaults
|
17
|
+
headless: 'shell',
|
18
|
+
args: [
|
19
|
+
'--hide-scrollbars',
|
20
|
+
'--mute-audio',
|
21
|
+
'--no-sandbox',
|
22
|
+
'--use-gl=egl',
|
23
|
+
'--use-mock-keychain',
|
24
|
+
'--disable-password-manager-reauthentication',
|
25
|
+
'--disable-keychain-reauthorization',
|
26
|
+
'--disable-web-security',
|
27
|
+
'--disable-site-isolation-trials',
|
28
|
+
'--disable-extensions',
|
29
|
+
'--disable-default-apps',
|
30
|
+
'--disable-component-extensions-with-background-pages',
|
31
|
+
'--disable-background-timer-throttling',
|
32
|
+
'--disable-background-networking',
|
33
|
+
'--disable-sync',
|
34
|
+
'--disable-features=TranslateUI',
|
35
|
+
'--disable-ipc-flooding-protection'
|
36
|
+
],
|
37
|
+
executablePath: '',
|
38
|
+
// Feature defaults
|
39
|
+
enableStats: false,
|
40
|
+
enableRecovery: false,
|
41
|
+
enableCleanup: true
|
42
|
+
};
|
43
|
+
// Common argument sets
|
44
|
+
exports.HEADLESS_POOL_ARGUMENT_SETS = {
|
45
|
+
basic: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],
|
46
|
+
keychain_safe: [
|
47
|
+
'--use-mock-keychain',
|
48
|
+
'--disable-password-manager-reauthentication',
|
49
|
+
'--disable-keychain-reauthorization',
|
50
|
+
'--disable-web-security',
|
51
|
+
'--disable-site-isolation-trials',
|
52
|
+
'--disable-extensions',
|
53
|
+
'--disable-default-apps',
|
54
|
+
'--disable-component-extensions-with-background-pages',
|
55
|
+
'--disable-background-timer-throttling',
|
56
|
+
'--disable-background-networking',
|
57
|
+
'--disable-sync',
|
58
|
+
'--disable-features=TranslateUI',
|
59
|
+
'--disable-ipc-flooding-protection'
|
60
|
+
],
|
61
|
+
security_enhanced: ['--disable-setuid-sandbox', '--disable-dev-shm-usage']
|
62
|
+
};
|
63
|
+
// Helper function to merge configs
|
64
|
+
function mergeConfig(base, override = {}) {
|
65
|
+
return {
|
66
|
+
...exports.DEFAULT_POOL_CONFIG,
|
67
|
+
...base,
|
68
|
+
...override,
|
69
|
+
args: [...(base.args || exports.DEFAULT_POOL_CONFIG.args), ...(override.args || [])]
|
70
|
+
};
|
71
|
+
}
|
72
|
+
//# sourceMappingURL=config.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../server/utils/headless-pool/config.ts"],"names":[],"mappings":";AAAA;;GAEG;;;AAwFH,kCAOC;AArED,yBAAyB;AACZ,QAAA,mBAAmB,GAAsD;IACpF,gBAAgB;IAChB,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,EAAE;IACP,oBAAoB,EAAE,KAAK;IAC3B,iBAAiB,EAAE,MAAM,EAAE,YAAY;IACvC,YAAY,EAAE,IAAI;IAElB,mBAAmB;IACnB,QAAQ,EAAE,OAAO;IACjB,IAAI,EAAE;QACJ,mBAAmB;QACnB,cAAc;QACd,cAAc;QACd,cAAc;QACd,qBAAqB;QACrB,6CAA6C;QAC7C,oCAAoC;QACpC,wBAAwB;QACxB,iCAAiC;QACjC,sBAAsB;QACtB,wBAAwB;QACxB,sDAAsD;QACtD,uCAAuC;QACvC,iCAAiC;QACjC,gBAAgB;QAChB,gCAAgC;QAChC,mCAAmC;KACpC;IACD,cAAc,EAAE,EAAE;IAElB,mBAAmB;IACnB,WAAW,EAAE,KAAK;IAClB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,IAAI;CACpB,CAAA;AAED,uBAAuB;AACV,QAAA,2BAA2B,GAAG;IACzC,KAAK,EAAE,CAAC,mBAAmB,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,CAAC;IAE5E,aAAa,EAAE;QACb,qBAAqB;QACrB,6CAA6C;QAC7C,oCAAoC;QACpC,wBAAwB;QACxB,iCAAiC;QACjC,sBAAsB;QACtB,wBAAwB;QACxB,sDAAsD;QACtD,uCAAuC;QACvC,iCAAiC;QACjC,gBAAgB;QAChB,gCAAgC;QAChC,mCAAmC;KACpC;IAED,iBAAiB,EAAE,CAAC,0BAA0B,EAAE,yBAAyB,CAAC;CAC3E,CAAA;AAED,mCAAmC;AACnC,SAAgB,WAAW,CAAC,IAAwB,EAAE,WAA+B,EAAE;IACrF,OAAO;QACL,GAAG,2BAAmB;QACtB,GAAG,IAAI;QACP,GAAG,QAAQ;QACX,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,2BAAmB,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC;KAC7E,CAAA;AACH,CAAC","sourcesContent":["/**\n * Headless Pool Configuration\n */\n\nexport type HeadlessMode = 'shell' | 'new' | boolean\n\nexport interface HeadlessPoolConfig {\n // Pool settings\n min?: number\n max?: number\n acquireTimeoutMillis?: number\n idleTimeoutMillis?: number\n testOnBorrow?: boolean\n\n // Browser launch settings\n headless?: HeadlessMode\n args?: string[]\n executablePath?: string\n\n // Features\n enableStats?: boolean\n enableRecovery?: boolean\n enableCleanup?: boolean\n\n // Custom setup function for special cases (like label pool)\n customSetup?: (browser: any) => Promise<any>\n}\n\n// Default configurations\nexport const DEFAULT_POOL_CONFIG: Required<Omit<HeadlessPoolConfig, 'customSetup'>> = {\n // Pool defaults\n min: 2,\n max: 10,\n acquireTimeoutMillis: 15000,\n idleTimeoutMillis: 300000, // 5 minutes\n testOnBorrow: true,\n\n // Browser defaults\n headless: 'shell',\n args: [\n '--hide-scrollbars',\n '--mute-audio',\n '--no-sandbox',\n '--use-gl=egl',\n '--use-mock-keychain',\n '--disable-password-manager-reauthentication',\n '--disable-keychain-reauthorization',\n '--disable-web-security',\n '--disable-site-isolation-trials',\n '--disable-extensions',\n '--disable-default-apps',\n '--disable-component-extensions-with-background-pages',\n '--disable-background-timer-throttling',\n '--disable-background-networking',\n '--disable-sync',\n '--disable-features=TranslateUI',\n '--disable-ipc-flooding-protection'\n ],\n executablePath: '',\n\n // Feature defaults\n enableStats: false,\n enableRecovery: false,\n enableCleanup: true\n}\n\n// Common argument sets\nexport const HEADLESS_POOL_ARGUMENT_SETS = {\n basic: ['--hide-scrollbars', '--mute-audio', '--no-sandbox', '--use-gl=egl'],\n\n keychain_safe: [\n '--use-mock-keychain',\n '--disable-password-manager-reauthentication',\n '--disable-keychain-reauthorization',\n '--disable-web-security',\n '--disable-site-isolation-trials',\n '--disable-extensions',\n '--disable-default-apps',\n '--disable-component-extensions-with-background-pages',\n '--disable-background-timer-throttling',\n '--disable-background-networking',\n '--disable-sync',\n '--disable-features=TranslateUI',\n '--disable-ipc-flooding-protection'\n ],\n\n security_enhanced: ['--disable-setuid-sandbox', '--disable-dev-shm-usage']\n}\n\n// Helper function to merge configs\nexport function mergeConfig(base: HeadlessPoolConfig, override: HeadlessPoolConfig = {}): HeadlessPoolConfig {\n return {\n ...DEFAULT_POOL_CONFIG,\n ...base,\n ...override,\n args: [...(base.args || DEFAULT_POOL_CONFIG.args), ...(override.args || [])]\n }\n}\n"]}
|
@@ -0,0 +1,98 @@
|
|
1
|
+
/**
|
2
|
+
* Unified Headless Pool System for Things Factory
|
3
|
+
*
|
4
|
+
* This module provides a centralized headless browser pool system
|
5
|
+
* that can be used across all Things Factory packages.
|
6
|
+
*/
|
7
|
+
import { HeadlessPool } from './pool-manager';
|
8
|
+
import { HeadlessPoolConfig } from './config';
|
9
|
+
export { HeadlessPoolConfig, HEADLESS_POOL_ARGUMENT_SETS } from './config';
|
10
|
+
export { HeadlessPool, HeadlessPoolManager } from './pool-manager';
|
11
|
+
export { PoolStats } from './pool-stats';
|
12
|
+
export { BrowserFactory } from './browser-factory';
|
13
|
+
/**
|
14
|
+
* Create a new headless browser pool
|
15
|
+
*
|
16
|
+
* @param name - Unique name for the pool
|
17
|
+
* @param config - Pool configuration options
|
18
|
+
* @returns HeadlessPool instance
|
19
|
+
*
|
20
|
+
* @example
|
21
|
+
* // Create integration pool with advanced features
|
22
|
+
* const integrationPool = createHeadlessPool('integration', {
|
23
|
+
* min: 2, max: 20,
|
24
|
+
* args: [...HEADLESS_POOL_ARGUMENT_SETS.basic, ...HEADLESS_POOL_ARGUMENT_SETS.keychain_safe],
|
25
|
+
* enableStats: true,
|
26
|
+
* enableRecovery: true
|
27
|
+
* })
|
28
|
+
*
|
29
|
+
* @example
|
30
|
+
* // Create simple pool
|
31
|
+
* const myPool = createHeadlessPool('my-pool', {
|
32
|
+
* min: 1, max: 5
|
33
|
+
* })
|
34
|
+
*/
|
35
|
+
export declare function createHeadlessPool(name: string, config?: HeadlessPoolConfig): HeadlessPool;
|
36
|
+
/**
|
37
|
+
* Get existing headless browser pool by name
|
38
|
+
*
|
39
|
+
* @param name - Pool name
|
40
|
+
* @returns HeadlessPool instance
|
41
|
+
* @throws Error if pool doesn't exist
|
42
|
+
*/
|
43
|
+
export declare function getHeadlessPool(name: string): HeadlessPool;
|
44
|
+
/**
|
45
|
+
* Get or create headless browser pool
|
46
|
+
* If pool exists, returns it. If not, creates with provided config.
|
47
|
+
*
|
48
|
+
* @param name - Pool name
|
49
|
+
* @param config - Pool configuration (used only if creating new pool)
|
50
|
+
* @returns HeadlessPool instance
|
51
|
+
*/
|
52
|
+
export declare function getOrCreateHeadlessPool(name: string, config?: HeadlessPoolConfig): HeadlessPool;
|
53
|
+
/**
|
54
|
+
* Check if pool exists
|
55
|
+
*
|
56
|
+
* @param name - Pool name
|
57
|
+
* @returns boolean
|
58
|
+
*/
|
59
|
+
export declare function hasHeadlessPool(name: string): boolean;
|
60
|
+
/**
|
61
|
+
* Get statistics for all pools
|
62
|
+
*
|
63
|
+
* @returns Object containing stats for all pools
|
64
|
+
*/
|
65
|
+
export declare function getAllPoolStats(): Record<string, any>;
|
66
|
+
/**
|
67
|
+
* Clean up all headless browser pools
|
68
|
+
* Typically called during application shutdown
|
69
|
+
*/
|
70
|
+
export declare function cleanupAllPools(): Promise<void>;
|
71
|
+
/**
|
72
|
+
* Reset a specific pool (cleanup and recreate)
|
73
|
+
*
|
74
|
+
* @param name - Pool name
|
75
|
+
*/
|
76
|
+
export declare function resetPool(name: string): Promise<void>;
|
77
|
+
/**
|
78
|
+
* Remove pool from registry
|
79
|
+
*
|
80
|
+
* @param name - Pool name
|
81
|
+
*/
|
82
|
+
export declare function removePool(name: string): void;
|
83
|
+
declare const _default: {
|
84
|
+
createHeadlessPool: typeof createHeadlessPool;
|
85
|
+
getHeadlessPool: typeof getHeadlessPool;
|
86
|
+
getOrCreateHeadlessPool: typeof getOrCreateHeadlessPool;
|
87
|
+
hasHeadlessPool: typeof hasHeadlessPool;
|
88
|
+
getAllPoolStats: typeof getAllPoolStats;
|
89
|
+
cleanupAllPools: typeof cleanupAllPools;
|
90
|
+
resetPool: typeof resetPool;
|
91
|
+
removePool: typeof removePool;
|
92
|
+
HEADLESS_POOL_ARGUMENT_SETS: {
|
93
|
+
basic: string[];
|
94
|
+
keychain_safe: string[];
|
95
|
+
security_enhanced: string[];
|
96
|
+
};
|
97
|
+
};
|
98
|
+
export default _default;
|
@@ -0,0 +1,131 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* Unified Headless Pool System for Things Factory
|
4
|
+
*
|
5
|
+
* This module provides a centralized headless browser pool system
|
6
|
+
* that can be used across all Things Factory packages.
|
7
|
+
*/
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.BrowserFactory = exports.PoolStats = exports.HeadlessPoolManager = exports.HeadlessPool = exports.HEADLESS_POOL_ARGUMENT_SETS = void 0;
|
10
|
+
exports.createHeadlessPool = createHeadlessPool;
|
11
|
+
exports.getHeadlessPool = getHeadlessPool;
|
12
|
+
exports.getOrCreateHeadlessPool = getOrCreateHeadlessPool;
|
13
|
+
exports.hasHeadlessPool = hasHeadlessPool;
|
14
|
+
exports.getAllPoolStats = getAllPoolStats;
|
15
|
+
exports.cleanupAllPools = cleanupAllPools;
|
16
|
+
exports.resetPool = resetPool;
|
17
|
+
exports.removePool = removePool;
|
18
|
+
const pool_manager_1 = require("./pool-manager");
|
19
|
+
const config_1 = require("./config");
|
20
|
+
// Re-export types and utilities
|
21
|
+
var config_2 = require("./config");
|
22
|
+
Object.defineProperty(exports, "HEADLESS_POOL_ARGUMENT_SETS", { enumerable: true, get: function () { return config_2.HEADLESS_POOL_ARGUMENT_SETS; } });
|
23
|
+
var pool_manager_2 = require("./pool-manager");
|
24
|
+
Object.defineProperty(exports, "HeadlessPool", { enumerable: true, get: function () { return pool_manager_2.HeadlessPool; } });
|
25
|
+
Object.defineProperty(exports, "HeadlessPoolManager", { enumerable: true, get: function () { return pool_manager_2.HeadlessPoolManager; } });
|
26
|
+
var pool_stats_1 = require("./pool-stats");
|
27
|
+
Object.defineProperty(exports, "PoolStats", { enumerable: true, get: function () { return pool_stats_1.PoolStats; } });
|
28
|
+
var browser_factory_1 = require("./browser-factory");
|
29
|
+
Object.defineProperty(exports, "BrowserFactory", { enumerable: true, get: function () { return browser_factory_1.BrowserFactory; } });
|
30
|
+
/**
|
31
|
+
* Create a new headless browser pool
|
32
|
+
*
|
33
|
+
* @param name - Unique name for the pool
|
34
|
+
* @param config - Pool configuration options
|
35
|
+
* @returns HeadlessPool instance
|
36
|
+
*
|
37
|
+
* @example
|
38
|
+
* // Create integration pool with advanced features
|
39
|
+
* const integrationPool = createHeadlessPool('integration', {
|
40
|
+
* min: 2, max: 20,
|
41
|
+
* args: [...HEADLESS_POOL_ARGUMENT_SETS.basic, ...HEADLESS_POOL_ARGUMENT_SETS.keychain_safe],
|
42
|
+
* enableStats: true,
|
43
|
+
* enableRecovery: true
|
44
|
+
* })
|
45
|
+
*
|
46
|
+
* @example
|
47
|
+
* // Create simple pool
|
48
|
+
* const myPool = createHeadlessPool('my-pool', {
|
49
|
+
* min: 1, max: 5
|
50
|
+
* })
|
51
|
+
*/
|
52
|
+
function createHeadlessPool(name, config = {}) {
|
53
|
+
return pool_manager_1.HeadlessPoolManager.createPool(name, config);
|
54
|
+
}
|
55
|
+
/**
|
56
|
+
* Get existing headless browser pool by name
|
57
|
+
*
|
58
|
+
* @param name - Pool name
|
59
|
+
* @returns HeadlessPool instance
|
60
|
+
* @throws Error if pool doesn't exist
|
61
|
+
*/
|
62
|
+
function getHeadlessPool(name) {
|
63
|
+
return pool_manager_1.HeadlessPoolManager.getPool(name);
|
64
|
+
}
|
65
|
+
/**
|
66
|
+
* Get or create headless browser pool
|
67
|
+
* If pool exists, returns it. If not, creates with provided config.
|
68
|
+
*
|
69
|
+
* @param name - Pool name
|
70
|
+
* @param config - Pool configuration (used only if creating new pool)
|
71
|
+
* @returns HeadlessPool instance
|
72
|
+
*/
|
73
|
+
function getOrCreateHeadlessPool(name, config = {}) {
|
74
|
+
if (pool_manager_1.HeadlessPoolManager.hasPool(name)) {
|
75
|
+
return pool_manager_1.HeadlessPoolManager.getPool(name);
|
76
|
+
}
|
77
|
+
return pool_manager_1.HeadlessPoolManager.createPool(name, config);
|
78
|
+
}
|
79
|
+
/**
|
80
|
+
* Check if pool exists
|
81
|
+
*
|
82
|
+
* @param name - Pool name
|
83
|
+
* @returns boolean
|
84
|
+
*/
|
85
|
+
function hasHeadlessPool(name) {
|
86
|
+
return pool_manager_1.HeadlessPoolManager.hasPool(name);
|
87
|
+
}
|
88
|
+
/**
|
89
|
+
* Get statistics for all pools
|
90
|
+
*
|
91
|
+
* @returns Object containing stats for all pools
|
92
|
+
*/
|
93
|
+
function getAllPoolStats() {
|
94
|
+
return pool_manager_1.HeadlessPoolManager.getAllPoolStats();
|
95
|
+
}
|
96
|
+
/**
|
97
|
+
* Clean up all headless browser pools
|
98
|
+
* Typically called during application shutdown
|
99
|
+
*/
|
100
|
+
function cleanupAllPools() {
|
101
|
+
return pool_manager_1.HeadlessPoolManager.cleanupAll();
|
102
|
+
}
|
103
|
+
/**
|
104
|
+
* Reset a specific pool (cleanup and recreate)
|
105
|
+
*
|
106
|
+
* @param name - Pool name
|
107
|
+
*/
|
108
|
+
function resetPool(name) {
|
109
|
+
return pool_manager_1.HeadlessPoolManager.resetPool(name);
|
110
|
+
}
|
111
|
+
/**
|
112
|
+
* Remove pool from registry
|
113
|
+
*
|
114
|
+
* @param name - Pool name
|
115
|
+
*/
|
116
|
+
function removePool(name) {
|
117
|
+
return pool_manager_1.HeadlessPoolManager.removePool(name);
|
118
|
+
}
|
119
|
+
// Default export
|
120
|
+
exports.default = {
|
121
|
+
createHeadlessPool,
|
122
|
+
getHeadlessPool,
|
123
|
+
getOrCreateHeadlessPool,
|
124
|
+
hasHeadlessPool,
|
125
|
+
getAllPoolStats,
|
126
|
+
cleanupAllPools,
|
127
|
+
resetPool,
|
128
|
+
removePool,
|
129
|
+
HEADLESS_POOL_ARGUMENT_SETS: config_1.HEADLESS_POOL_ARGUMENT_SETS
|
130
|
+
};
|
131
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/utils/headless-pool/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAiCH,gDAEC;AASD,0CAEC;AAUD,0DAKC;AAQD,0CAEC;AAOD,0CAEC;AAMD,0CAEC;AAOD,8BAEC;AAOD,gCAEC;AAxGD,iDAAkE;AAClE,qCAA0E;AAE1E,gCAAgC;AAChC,mCAA0E;AAA7C,qHAAA,2BAA2B,OAAA;AACxD,+CAAkE;AAAzD,4GAAA,YAAY,OAAA;AAAE,mHAAA,mBAAmB,OAAA;AAC1C,2CAAwC;AAA/B,uGAAA,SAAS,OAAA;AAClB,qDAAkD;AAAzC,iHAAA,cAAc,OAAA;AAEvB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,SAAgB,kBAAkB,CAAC,IAAY,EAAE,SAA6B,EAAE;IAC9E,OAAO,kCAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,eAAe,CAAC,IAAY;IAC1C,OAAO,kCAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAC1C,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,uBAAuB,CAAC,IAAY,EAAE,SAA6B,EAAE;IACnF,IAAI,kCAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACtC,OAAO,kCAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1C,CAAC;IACD,OAAO,kCAAmB,CAAC,UAAU,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,IAAY;IAC1C,OAAO,kCAAmB,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;AAC1C,CAAC;AAED;;;;GAIG;AACH,SAAgB,eAAe;IAC7B,OAAO,kCAAmB,CAAC,eAAe,EAAE,CAAA;AAC9C,CAAC;AAED;;;GAGG;AACH,SAAgB,eAAe;IAC7B,OAAO,kCAAmB,CAAC,UAAU,EAAE,CAAA;AACzC,CAAC;AAED;;;;GAIG;AACH,SAAgB,SAAS,CAAC,IAAY;IACpC,OAAO,kCAAmB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;AAC5C,CAAC;AAED;;;;GAIG;AACH,SAAgB,UAAU,CAAC,IAAY;IACrC,OAAO,kCAAmB,CAAC,UAAU,CAAC,IAAI,CAAC,CAAA;AAC7C,CAAC;AAGD,iBAAiB;AACjB,kBAAe;IACb,kBAAkB;IAClB,eAAe;IACf,uBAAuB;IACvB,eAAe;IACf,eAAe;IACf,eAAe;IACf,SAAS;IACT,UAAU;IACV,2BAA2B,EAA3B,oCAA2B;CAC5B,CAAA","sourcesContent":["/**\n * Unified Headless Pool System for Things Factory\n * \n * This module provides a centralized headless browser pool system\n * that can be used across all Things Factory packages.\n */\n\nimport { HeadlessPoolManager, HeadlessPool } from './pool-manager'\nimport { HeadlessPoolConfig, HEADLESS_POOL_ARGUMENT_SETS } from './config'\n\n// Re-export types and utilities\nexport { HeadlessPoolConfig, HEADLESS_POOL_ARGUMENT_SETS } from './config'\nexport { HeadlessPool, HeadlessPoolManager } from './pool-manager'\nexport { PoolStats } from './pool-stats'\nexport { BrowserFactory } from './browser-factory'\n\n/**\n * Create a new headless browser pool\n * \n * @param name - Unique name for the pool\n * @param config - Pool configuration options\n * @returns HeadlessPool instance\n * \n * @example\n * // Create integration pool with advanced features\n * const integrationPool = createHeadlessPool('integration', {\n * min: 2, max: 20,\n * args: [...HEADLESS_POOL_ARGUMENT_SETS.basic, ...HEADLESS_POOL_ARGUMENT_SETS.keychain_safe],\n * enableStats: true,\n * enableRecovery: true\n * })\n * \n * @example \n * // Create simple pool\n * const myPool = createHeadlessPool('my-pool', {\n * min: 1, max: 5\n * })\n */\nexport function createHeadlessPool(name: string, config: HeadlessPoolConfig = {}): HeadlessPool {\n return HeadlessPoolManager.createPool(name, config)\n}\n\n/**\n * Get existing headless browser pool by name\n * \n * @param name - Pool name\n * @returns HeadlessPool instance\n * @throws Error if pool doesn't exist\n */\nexport function getHeadlessPool(name: string): HeadlessPool {\n return HeadlessPoolManager.getPool(name)\n}\n\n/**\n * Get or create headless browser pool\n * If pool exists, returns it. If not, creates with provided config.\n * \n * @param name - Pool name\n * @param config - Pool configuration (used only if creating new pool)\n * @returns HeadlessPool instance\n */\nexport function getOrCreateHeadlessPool(name: string, config: HeadlessPoolConfig = {}): HeadlessPool {\n if (HeadlessPoolManager.hasPool(name)) {\n return HeadlessPoolManager.getPool(name)\n }\n return HeadlessPoolManager.createPool(name, config)\n}\n\n/**\n * Check if pool exists\n * \n * @param name - Pool name\n * @returns boolean\n */\nexport function hasHeadlessPool(name: string): boolean {\n return HeadlessPoolManager.hasPool(name)\n}\n\n/**\n * Get statistics for all pools\n * \n * @returns Object containing stats for all pools\n */\nexport function getAllPoolStats() {\n return HeadlessPoolManager.getAllPoolStats()\n}\n\n/**\n * Clean up all headless browser pools\n * Typically called during application shutdown\n */\nexport function cleanupAllPools(): Promise<void> {\n return HeadlessPoolManager.cleanupAll()\n}\n\n/**\n * Reset a specific pool (cleanup and recreate)\n * \n * @param name - Pool name\n */\nexport function resetPool(name: string): Promise<void> {\n return HeadlessPoolManager.resetPool(name)\n}\n\n/**\n * Remove pool from registry\n * \n * @param name - Pool name\n */\nexport function removePool(name: string): void {\n return HeadlessPoolManager.removePool(name)\n}\n\n\n// Default export\nexport default {\n createHeadlessPool,\n getHeadlessPool,\n getOrCreateHeadlessPool,\n hasHeadlessPool,\n getAllPoolStats,\n cleanupAllPools,\n resetPool,\n removePool,\n HEADLESS_POOL_ARGUMENT_SETS\n}"]}
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import { HeadlessPoolConfig } from './config';
|
2
|
+
/**
|
3
|
+
* Individual Pool Instance
|
4
|
+
*/
|
5
|
+
export declare class HeadlessPool {
|
6
|
+
private pool;
|
7
|
+
private stats?;
|
8
|
+
private config;
|
9
|
+
private name;
|
10
|
+
constructor(name: string, config: HeadlessPoolConfig);
|
11
|
+
private createPool;
|
12
|
+
private createResource;
|
13
|
+
private validateResource;
|
14
|
+
private destroyResource;
|
15
|
+
private addMonitoring;
|
16
|
+
acquire(): Promise<any>;
|
17
|
+
release(resource: any): Promise<void>;
|
18
|
+
getStats(): {
|
19
|
+
poolStatus: {
|
20
|
+
utilizationRate: string;
|
21
|
+
size: number;
|
22
|
+
available: number;
|
23
|
+
borrowed: number;
|
24
|
+
pending: number;
|
25
|
+
max: number;
|
26
|
+
min: number;
|
27
|
+
};
|
28
|
+
statistics: {
|
29
|
+
averageAcquisitionTime: string;
|
30
|
+
totalCreated: number;
|
31
|
+
totalDestroyed: number;
|
32
|
+
totalAcquired: number;
|
33
|
+
totalReleased: number;
|
34
|
+
currentlyAcquired: number;
|
35
|
+
acquisitionTimes: number[];
|
36
|
+
lastActivity: string | null;
|
37
|
+
};
|
38
|
+
health: {
|
39
|
+
status: string;
|
40
|
+
message: string;
|
41
|
+
leakDetection: string;
|
42
|
+
};
|
43
|
+
};
|
44
|
+
cleanup(): Promise<void>;
|
45
|
+
reset(): Promise<void>;
|
46
|
+
}
|
47
|
+
/**
|
48
|
+
* Global Pool Manager/Registry
|
49
|
+
*/
|
50
|
+
export declare class HeadlessPoolManager {
|
51
|
+
private static pools;
|
52
|
+
static createPool(name: string, config?: HeadlessPoolConfig): HeadlessPool;
|
53
|
+
static getPool(name: string): HeadlessPool;
|
54
|
+
static hasPool(name: string): boolean;
|
55
|
+
static getAllPoolStats(): Record<string, any>;
|
56
|
+
static cleanupAll(): Promise<void>;
|
57
|
+
static resetPool(name: string): Promise<void>;
|
58
|
+
static removePool(name: string): void;
|
59
|
+
}
|