@things-factory/integration-base 10.1.116 → 10.1.117

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.
@@ -9,16 +9,35 @@ exports.default = getHeadlessPool;
9
9
  exports.getPoolStats = getPoolStats;
10
10
  exports.forceCleanupPool = forceCleanupPool;
11
11
  const shell_1 = require("@things-factory/shell");
12
- // Create or get the integration pool instance
13
- const integrationPool = (0, shell_1.getOrCreateHeadlessPool)('integration', {
14
- min: 2,
15
- max: 20,
16
- args: [...shell_1.HEADLESS_POOL_ARGUMENT_SETS.basic, ...shell_1.HEADLESS_POOL_ARGUMENT_SETS.keychain_safe],
17
- acquireTimeoutMillis: 15000,
18
- testOnBorrow: true,
19
- enableStats: true,
20
- enableRecovery: true,
21
- enableCleanup: true
12
+ /*
13
+ * ── The pool is made when the application boots, not when this module is loaded (2026-10-04) ──
14
+ * It used to be made at import, with `min: 2`, so loading this module launched two headless Chromes. The shell's
15
+ * module loader loads every things-factory module in an application's dependency tree, so **any** process that
16
+ * loaded the shell — every DB test of operato-warehouse among them — launched two browsers it never used. Their
17
+ * sockets keep the event loop alive, and the shell's cleanup waits for `beforeExit`, which never comes while
18
+ * they are open: the test file passed in half a second and its process did not end (measured: warehouse
19
+ * `master-change-approval.db.test.cjs`, two chrome-headless-shell children and two TCP sockets to 127.0.0.1).
20
+ *
21
+ * Now it is made on `bootstrap-module-start`, as board-service's label pool is — an application still has two
22
+ * warm browsers from boot — or on first use, whichever comes first. A process that never boots an application
23
+ * and never acquires launches nothing.
24
+ */
25
+ let integrationPool;
26
+ function pool() {
27
+ integrationPool ??= (0, shell_1.getOrCreateHeadlessPool)('integration', {
28
+ min: 2,
29
+ max: 20,
30
+ args: [...shell_1.HEADLESS_POOL_ARGUMENT_SETS.basic, ...shell_1.HEADLESS_POOL_ARGUMENT_SETS.keychain_safe],
31
+ acquireTimeoutMillis: 15000,
32
+ testOnBorrow: true,
33
+ enableStats: true,
34
+ enableRecovery: true,
35
+ enableCleanup: true
36
+ });
37
+ return integrationPool;
38
+ }
39
+ (0, shell_1.onHook)('bootstrap-module-start', () => {
40
+ pool();
22
41
  });
23
42
  /**
24
43
  * Get the integration headless pool
@@ -26,8 +45,8 @@ const integrationPool = (0, shell_1.getOrCreateHeadlessPool)('integration', {
26
45
  */
27
46
  function getHeadlessPool() {
28
47
  return {
29
- acquire: () => integrationPool.acquire(),
30
- release: (resource) => integrationPool.release(resource),
48
+ acquire: () => pool().acquire(),
49
+ release: (resource) => pool().release(resource),
31
50
  size: 0, // These will be dynamically calculated if needed
32
51
  available: 0,
33
52
  borrowed: 0,
@@ -74,6 +93,7 @@ function getPoolStats() {
74
93
  * @returns Promise<void>
75
94
  */
76
95
  function forceCleanupPool() {
77
- return integrationPool.reset();
96
+ /* Nothing made yet is nothing to clean. */
97
+ return integrationPool ? integrationPool.reset() : Promise.resolve();
78
98
  }
79
99
  //# sourceMappingURL=headless-pool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"headless-pool.js","sourceRoot":"","sources":["../../../server/engine/resource-pool/headless-pool.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAoBH,0CAWC;AA+C2B,kCAAO;AAzCnC,oCA8BC;AAMD,4CAEC;AAzED,iDAA6G;AAE7G,8CAA8C;AAC9C,MAAM,eAAe,GAAG,IAAA,+BAAuB,EAAC,aAAa,EAAE;IAC7D,GAAG,EAAE,CAAC;IACN,GAAG,EAAE,EAAE;IACP,IAAI,EAAE,CAAC,GAAG,mCAA2B,CAAC,KAAK,EAAE,GAAG,mCAA2B,CAAC,aAAa,CAAC;IAC1F,oBAAoB,EAAE,KAAK;IAC3B,YAAY,EAAE,IAAI;IAClB,WAAW,EAAE,IAAI;IACjB,cAAc,EAAE,IAAI;IACpB,aAAa,EAAE,IAAI;CACpB,CAAC,CAAA;AAEF;;;GAGG;AACH,SAAgB,eAAe;IAC7B,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE;QACxC,OAAO,EAAE,CAAC,QAAa,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC;QAC7D,IAAI,EAAE,CAAC,EAAE,iDAAiD;QAC1D,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;QACV,GAAG,EAAE,EAAE;QACP,GAAG,EAAE,CAAC;KACP,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY;IAC1B,MAAM,QAAQ,GAAG,IAAA,uBAAe,GAAE,CAAA;IAClC,MAAM,gBAAgB,GAAG,QAAQ,CAAC,WAAW,CAAA;IAE7C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO;YACL,IAAI,EAAE,CAAC;YACP,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;YACV,GAAG,EAAE,EAAE;YACP,GAAG,EAAE,CAAC;YACN,YAAY,EAAE,CAAC;YACf,cAAc,EAAE,CAAC;YACjB,aAAa,EAAE,CAAC;YAChB,aAAa,EAAE,CAAC;YAChB,iBAAiB,EAAE,CAAC;YACpB,sBAAsB,EAAE,CAAC;YACzB,eAAe,EAAE,GAAG;YACpB,YAAY,EAAE,IAAI;SACnB,CAAA;IACH,CAAC;IAED,8CAA8C;IAC9C,OAAO;QACL,GAAG,gBAAgB,CAAC,UAAU;QAC9B,GAAG,gBAAgB,CAAC,UAAU;QAC9B,sBAAsB,EAAE,QAAQ,CAAC,gBAAgB,CAAC,UAAU,CAAC,sBAAsB,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;QAC3G,eAAe,EAAE,gBAAgB,CAAC,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;KAC9E,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB;IAC9B,OAAO,eAAe,CAAC,KAAK,EAAE,CAAA;AAChC,CAAC","sourcesContent":["/**\n * Integration Base Headless Pool\n * Using the unified headless pool system from @things-factory/shell\n */\n\nimport { getOrCreateHeadlessPool, getAllPoolStats, HEADLESS_POOL_ARGUMENT_SETS } from '@things-factory/shell'\n\n// Create or get the integration pool instance\nconst integrationPool = getOrCreateHeadlessPool('integration', {\n min: 2,\n max: 20,\n args: [...HEADLESS_POOL_ARGUMENT_SETS.basic, ...HEADLESS_POOL_ARGUMENT_SETS.keychain_safe],\n acquireTimeoutMillis: 15000,\n testOnBorrow: true,\n enableStats: true,\n enableRecovery: true,\n enableCleanup: true\n})\n\n/**\n * Get the integration headless pool\n * @returns Pool instance with acquire/release methods\n */\nexport function getHeadlessPool() {\n return {\n acquire: () => integrationPool.acquire(),\n release: (resource: any) => integrationPool.release(resource),\n size: 0, // These will be dynamically calculated if needed\n available: 0,\n borrowed: 0,\n pending: 0,\n max: 20,\n min: 2\n }\n}\n\n/**\n * Get pool statistics\n * @returns Detailed pool statistics\n */\nexport function getPoolStats() {\n const allStats = getAllPoolStats()\n const integrationStats = allStats.integration\n\n if (!integrationStats) {\n return {\n size: 0,\n available: 0,\n borrowed: 0,\n pending: 0,\n max: 20,\n min: 2,\n totalCreated: 0,\n totalDestroyed: 0,\n totalAcquired: 0,\n totalReleased: 0,\n currentlyAcquired: 0,\n averageAcquisitionTime: 0,\n utilizationRate: '0',\n lastActivity: null\n }\n }\n\n // Convert to format expected by existing code\n return {\n ...integrationStats.poolStatus,\n ...integrationStats.statistics,\n averageAcquisitionTime: parseInt(integrationStats.statistics.averageAcquisitionTime.replace('ms', '')) || 0,\n utilizationRate: integrationStats.poolStatus.utilizationRate.replace('%', '')\n }\n}\n\n/**\n * Force cleanup pool - delegates to unified system\n * @returns Promise<void>\n */\nexport function forceCleanupPool(): Promise<void> {\n return integrationPool.reset()\n}\n\n// Legacy compatibility - re-export the main function\nexport { getHeadlessPool as default }\n"]}
1
+ {"version":3,"file":"headless-pool.js","sourceRoot":"","sources":["../../../server/engine/resource-pool/headless-pool.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAyCH,0CAWC;AAgD2B,kCAAO;AA1CnC,oCA8BC;AAMD,4CAGC;AA/FD,iDAAqH;AAErH;;;;;;;;;;;;GAYG;AACH,IAAI,eAAuE,CAAA;AAE3E,SAAS,IAAI;IACX,eAAe,KAAK,IAAA,+BAAuB,EAAC,aAAa,EAAE;QACzD,GAAG,EAAE,CAAC;QACN,GAAG,EAAE,EAAE;QACP,IAAI,EAAE,CAAC,GAAG,mCAA2B,CAAC,KAAK,EAAE,GAAG,mCAA2B,CAAC,aAAa,CAAC;QAC1F,oBAAoB,EAAE,KAAK;QAC3B,YAAY,EAAE,IAAI;QAClB,WAAW,EAAE,IAAI;QACjB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;KACpB,CAAC,CAAA;IACF,OAAO,eAAe,CAAA;AACxB,CAAC;AAED,IAAA,cAAM,EAAC,wBAAwB,EAAE,GAAG,EAAE;IACpC,IAAI,EAAE,CAAA;AACR,CAAC,CAAC,CAAA;AAEF;;;GAGG;AACH,SAAgB,eAAe;IAC7B,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE;QAC/B,OAAO,EAAE,CAAC,QAAa,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;QACpD,IAAI,EAAE,CAAC,EAAE,iDAAiD;QAC1D,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,CAAC;QACX,OAAO,EAAE,CAAC;QACV,GAAG,EAAE,EAAE;QACP,GAAG,EAAE,CAAC;KACP,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,YAAY;IAC1B,MAAM,QAAQ,GAAG,IAAA,uBAAe,GAAE,CAAA;IAClC,MAAM,gBAAgB,GAAG,QAAQ,CAAC,WAAW,CAAA;IAE7C,IAAI,CAAC,gBAAgB,EAAE,CAAC;QACtB,OAAO;YACL,IAAI,EAAE,CAAC;YACP,SAAS,EAAE,CAAC;YACZ,QAAQ,EAAE,CAAC;YACX,OAAO,EAAE,CAAC;YACV,GAAG,EAAE,EAAE;YACP,GAAG,EAAE,CAAC;YACN,YAAY,EAAE,CAAC;YACf,cAAc,EAAE,CAAC;YACjB,aAAa,EAAE,CAAC;YAChB,aAAa,EAAE,CAAC;YAChB,iBAAiB,EAAE,CAAC;YACpB,sBAAsB,EAAE,CAAC;YACzB,eAAe,EAAE,GAAG;YACpB,YAAY,EAAE,IAAI;SACnB,CAAA;IACH,CAAC;IAED,8CAA8C;IAC9C,OAAO;QACL,GAAG,gBAAgB,CAAC,UAAU;QAC9B,GAAG,gBAAgB,CAAC,UAAU;QAC9B,sBAAsB,EAAE,QAAQ,CAAC,gBAAgB,CAAC,UAAU,CAAC,sBAAsB,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;QAC3G,eAAe,EAAE,gBAAgB,CAAC,UAAU,CAAC,eAAe,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;KAC9E,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,SAAgB,gBAAgB;IAC9B,2CAA2C;IAC3C,OAAO,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,CAAA;AACtE,CAAC","sourcesContent":["/**\n * Integration Base Headless Pool\n * Using the unified headless pool system from @things-factory/shell\n */\n\nimport { getAllPoolStats, getOrCreateHeadlessPool, HEADLESS_POOL_ARGUMENT_SETS, onHook } from '@things-factory/shell'\n\n/*\n * ── The pool is made when the application boots, not when this module is loaded (2026-10-04) ──\n * It used to be made at import, with `min: 2`, so loading this module launched two headless Chromes. The shell's\n * module loader loads every things-factory module in an application's dependency tree, so **any** process that\n * loaded the shell — every DB test of operato-warehouse among them — launched two browsers it never used. Their\n * sockets keep the event loop alive, and the shell's cleanup waits for `beforeExit`, which never comes while\n * they are open: the test file passed in half a second and its process did not end (measured: warehouse\n * `master-change-approval.db.test.cjs`, two chrome-headless-shell children and two TCP sockets to 127.0.0.1).\n *\n * Now it is made on `bootstrap-module-start`, as board-service's label pool is — an application still has two\n * warm browsers from boot — or on first use, whichever comes first. A process that never boots an application\n * and never acquires launches nothing.\n */\nlet integrationPool: ReturnType<typeof getOrCreateHeadlessPool> | undefined\n\nfunction pool() {\n integrationPool ??= getOrCreateHeadlessPool('integration', {\n min: 2,\n max: 20,\n args: [...HEADLESS_POOL_ARGUMENT_SETS.basic, ...HEADLESS_POOL_ARGUMENT_SETS.keychain_safe],\n acquireTimeoutMillis: 15000,\n testOnBorrow: true,\n enableStats: true,\n enableRecovery: true,\n enableCleanup: true\n })\n return integrationPool\n}\n\nonHook('bootstrap-module-start', () => {\n pool()\n})\n\n/**\n * Get the integration headless pool\n * @returns Pool instance with acquire/release methods\n */\nexport function getHeadlessPool() {\n return {\n acquire: () => pool().acquire(),\n release: (resource: any) => pool().release(resource),\n size: 0, // These will be dynamically calculated if needed\n available: 0,\n borrowed: 0,\n pending: 0,\n max: 20,\n min: 2\n }\n}\n\n/**\n * Get pool statistics\n * @returns Detailed pool statistics\n */\nexport function getPoolStats() {\n const allStats = getAllPoolStats()\n const integrationStats = allStats.integration\n\n if (!integrationStats) {\n return {\n size: 0,\n available: 0,\n borrowed: 0,\n pending: 0,\n max: 20,\n min: 2,\n totalCreated: 0,\n totalDestroyed: 0,\n totalAcquired: 0,\n totalReleased: 0,\n currentlyAcquired: 0,\n averageAcquisitionTime: 0,\n utilizationRate: '0',\n lastActivity: null\n }\n }\n\n // Convert to format expected by existing code\n return {\n ...integrationStats.poolStatus,\n ...integrationStats.statistics,\n averageAcquisitionTime: parseInt(integrationStats.statistics.averageAcquisitionTime.replace('ms', '')) || 0,\n utilizationRate: integrationStats.poolStatus.utilizationRate.replace('%', '')\n }\n}\n\n/**\n * Force cleanup pool - delegates to unified system\n * @returns Promise<void>\n */\nexport function forceCleanupPool(): Promise<void> {\n /* Nothing made yet is nothing to clean. */\n return integrationPool ? integrationPool.reset() : Promise.resolve()\n}\n\n// Legacy compatibility - re-export the main function\nexport { getHeadlessPool as default }\n"]}