@askjo/camofox-browser 1.5.1 → 1.5.2

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.
@@ -2,7 +2,7 @@
2
2
  "id": "camofox-browser",
3
3
  "name": "Camofox Browser",
4
4
  "description": "Anti-detection browser automation for AI agents using Camoufox (Firefox-based)",
5
- "version": "1.5.1",
5
+ "version": "1.5.2",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "properties": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askjo/camofox-browser",
3
- "version": "1.5.1",
3
+ "version": "1.5.2",
4
4
  "description": "Headless browser automation server and OpenClaw plugin for AI agents - anti-detection, element refs, and session isolation",
5
5
  "type": "module",
6
6
  "main": "server.js",
package/plugin.ts CHANGED
@@ -399,6 +399,13 @@ export default function register(api: PluginApi) {
399
399
  const text = await res.text();
400
400
  throw new Error(`${res.status}: ${text}`);
401
401
  }
402
+ // Guard: if server returns JSON/text instead of image (e.g. error with 200),
403
+ // return as text to avoid crashing the client with base64-encoded JSON.
404
+ const contentType = res.headers.get('content-type') || '';
405
+ if (!contentType.startsWith('image/')) {
406
+ const text = await res.text();
407
+ return { content: [{ type: "text", text: `Screenshot failed: ${text}` }] };
408
+ }
402
409
  const arrayBuffer = await res.arrayBuffer();
403
410
  const base64 = Buffer.from(arrayBuffer).toString("base64");
404
411
  return {
@@ -406,7 +413,7 @@ export default function register(api: PluginApi) {
406
413
  {
407
414
  type: "image",
408
415
  data: base64,
409
- mimeType: "image/png",
416
+ mimeType: contentType || "image/png",
410
417
  },
411
418
  ],
412
419
  };
package/server.js CHANGED
@@ -2675,7 +2675,17 @@ setInterval(() => {
2675
2675
  session.tabGroups.delete(listItemId);
2676
2676
  }
2677
2677
  }
2678
+ // Clean up sessions with zero tabs remaining — free browser context memory
2679
+ if (session.tabGroups.size === 0) {
2680
+ log('info', 'session empty after tab reaper, closing', { userId });
2681
+ clearSessionDownloads(session).catch(() => {});
2682
+ session.context.close().catch(() => {});
2683
+ sessions.delete(userId);
2684
+ sessionsExpiredTotal.inc();
2685
+ refreshActiveTabsGauge();
2686
+ }
2678
2687
  }
2688
+ if (sessions.size === 0) scheduleBrowserIdleShutdown();
2679
2689
  }, 60_000);
2680
2690
 
2681
2691
  // =============================================================================