@hasna/browser 0.3.2 → 0.3.4

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.
Files changed (225) hide show
  1. package/dist/cli/index.js +999 -299
  2. package/dist/index.js +75 -22
  3. package/dist/mcp/index.js +1086 -338
  4. package/dist/server/index.js +90 -40
  5. package/package.json +1 -1
  6. package/dashboard/dist/assets/index-Cy4XUbL1.js +0 -40
  7. package/dashboard/dist/index.html +0 -16
  8. package/dist/cli/commands/browse.d.ts +0 -3
  9. package/dist/cli/commands/browse.d.ts.map +0 -1
  10. package/dist/cli/commands/script.d.ts +0 -3
  11. package/dist/cli/commands/script.d.ts.map +0 -1
  12. package/dist/cli/commands/session.d.ts +0 -3
  13. package/dist/cli/commands/session.d.ts.map +0 -1
  14. package/dist/cli/commands/tools.d.ts +0 -3
  15. package/dist/cli/commands/tools.d.ts.map +0 -1
  16. package/dist/cli/index.d.ts +0 -3
  17. package/dist/cli/index.d.ts.map +0 -1
  18. package/dist/cli/index.test.d.ts +0 -2
  19. package/dist/cli/index.test.d.ts.map +0 -1
  20. package/dist/db/agents.d.ts +0 -16
  21. package/dist/db/agents.d.ts.map +0 -1
  22. package/dist/db/agents.test.d.ts +0 -2
  23. package/dist/db/agents.test.d.ts.map +0 -1
  24. package/dist/db/console-log.d.ts +0 -6
  25. package/dist/db/console-log.d.ts.map +0 -1
  26. package/dist/db/crawl-results.d.ts +0 -6
  27. package/dist/db/crawl-results.d.ts.map +0 -1
  28. package/dist/db/gallery.d.ts +0 -26
  29. package/dist/db/gallery.d.ts.map +0 -1
  30. package/dist/db/gallery.test.d.ts +0 -2
  31. package/dist/db/gallery.test.d.ts.map +0 -1
  32. package/dist/db/heartbeats.d.ts +0 -6
  33. package/dist/db/heartbeats.d.ts.map +0 -1
  34. package/dist/db/network-log.d.ts +0 -7
  35. package/dist/db/network-log.d.ts.map +0 -1
  36. package/dist/db/projects.d.ts +0 -9
  37. package/dist/db/projects.d.ts.map +0 -1
  38. package/dist/db/projects.test.d.ts +0 -2
  39. package/dist/db/projects.test.d.ts.map +0 -1
  40. package/dist/db/recordings.d.ts +0 -11
  41. package/dist/db/recordings.d.ts.map +0 -1
  42. package/dist/db/recordings.test.d.ts +0 -2
  43. package/dist/db/recordings.test.d.ts.map +0 -1
  44. package/dist/db/schema.d.ts +0 -5
  45. package/dist/db/schema.d.ts.map +0 -1
  46. package/dist/db/schema.test.d.ts +0 -2
  47. package/dist/db/schema.test.d.ts.map +0 -1
  48. package/dist/db/scripts.d.ts +0 -84
  49. package/dist/db/scripts.d.ts.map +0 -1
  50. package/dist/db/sessions.d.ts +0 -35
  51. package/dist/db/sessions.d.ts.map +0 -1
  52. package/dist/db/sessions.test.d.ts +0 -2
  53. package/dist/db/sessions.test.d.ts.map +0 -1
  54. package/dist/db/snapshots.d.ts +0 -7
  55. package/dist/db/snapshots.d.ts.map +0 -1
  56. package/dist/db/timeline.d.ts +0 -11
  57. package/dist/db/timeline.d.ts.map +0 -1
  58. package/dist/engines/bun-webview.d.ts +0 -147
  59. package/dist/engines/bun-webview.d.ts.map +0 -1
  60. package/dist/engines/bun-webview.test.d.ts +0 -2
  61. package/dist/engines/bun-webview.test.d.ts.map +0 -1
  62. package/dist/engines/cdp.d.ts +0 -27
  63. package/dist/engines/cdp.d.ts.map +0 -1
  64. package/dist/engines/lightpanda.d.ts +0 -25
  65. package/dist/engines/lightpanda.d.ts.map +0 -1
  66. package/dist/engines/playwright.d.ts +0 -27
  67. package/dist/engines/playwright.d.ts.map +0 -1
  68. package/dist/engines/selector.d.ts +0 -17
  69. package/dist/engines/selector.d.ts.map +0 -1
  70. package/dist/engines/selector.test.d.ts +0 -2
  71. package/dist/engines/selector.test.d.ts.map +0 -1
  72. package/dist/index.d.ts +0 -28
  73. package/dist/index.d.ts.map +0 -1
  74. package/dist/lib/actions-ref.test.d.ts +0 -2
  75. package/dist/lib/actions-ref.test.d.ts.map +0 -1
  76. package/dist/lib/actions.d.ts +0 -91
  77. package/dist/lib/actions.d.ts.map +0 -1
  78. package/dist/lib/actions.test.d.ts +0 -2
  79. package/dist/lib/actions.test.d.ts.map +0 -1
  80. package/dist/lib/agents.d.ts +0 -9
  81. package/dist/lib/agents.d.ts.map +0 -1
  82. package/dist/lib/agents.test.d.ts +0 -2
  83. package/dist/lib/agents.test.d.ts.map +0 -1
  84. package/dist/lib/ai-inference.d.ts +0 -21
  85. package/dist/lib/ai-inference.d.ts.map +0 -1
  86. package/dist/lib/ai-task.d.ts +0 -23
  87. package/dist/lib/ai-task.d.ts.map +0 -1
  88. package/dist/lib/annotate.d.ts +0 -18
  89. package/dist/lib/annotate.d.ts.map +0 -1
  90. package/dist/lib/annotate.test.d.ts +0 -2
  91. package/dist/lib/annotate.test.d.ts.map +0 -1
  92. package/dist/lib/api-detector.d.ts +0 -17
  93. package/dist/lib/api-detector.d.ts.map +0 -1
  94. package/dist/lib/auth-flow.d.ts +0 -43
  95. package/dist/lib/auth-flow.d.ts.map +0 -1
  96. package/dist/lib/auth.d.ts +0 -28
  97. package/dist/lib/auth.d.ts.map +0 -1
  98. package/dist/lib/console.d.ts +0 -6
  99. package/dist/lib/console.d.ts.map +0 -1
  100. package/dist/lib/coordination.d.ts +0 -12
  101. package/dist/lib/coordination.d.ts.map +0 -1
  102. package/dist/lib/crawler.d.ts +0 -3
  103. package/dist/lib/crawler.d.ts.map +0 -1
  104. package/dist/lib/cron-manager.d.ts +0 -43
  105. package/dist/lib/cron-manager.d.ts.map +0 -1
  106. package/dist/lib/daemon-client.d.ts +0 -16
  107. package/dist/lib/daemon-client.d.ts.map +0 -1
  108. package/dist/lib/datasets.d.ts +0 -33
  109. package/dist/lib/datasets.d.ts.map +0 -1
  110. package/dist/lib/deep-performance.d.ts +0 -49
  111. package/dist/lib/deep-performance.d.ts.map +0 -1
  112. package/dist/lib/dialogs.d.ts +0 -15
  113. package/dist/lib/dialogs.d.ts.map +0 -1
  114. package/dist/lib/downloads.d.ts +0 -15
  115. package/dist/lib/downloads.d.ts.map +0 -1
  116. package/dist/lib/downloads.test.d.ts +0 -2
  117. package/dist/lib/downloads.test.d.ts.map +0 -1
  118. package/dist/lib/env-detector.d.ts +0 -12
  119. package/dist/lib/env-detector.d.ts.map +0 -1
  120. package/dist/lib/extractor.d.ts +0 -22
  121. package/dist/lib/extractor.d.ts.map +0 -1
  122. package/dist/lib/extractor.test.d.ts +0 -2
  123. package/dist/lib/extractor.test.d.ts.map +0 -1
  124. package/dist/lib/files-integration.d.ts +0 -13
  125. package/dist/lib/files-integration.d.ts.map +0 -1
  126. package/dist/lib/gallery-diff.d.ts +0 -3
  127. package/dist/lib/gallery-diff.d.ts.map +0 -1
  128. package/dist/lib/integrations.test.d.ts +0 -2
  129. package/dist/lib/integrations.test.d.ts.map +0 -1
  130. package/dist/lib/login-scripts.d.ts +0 -89
  131. package/dist/lib/login-scripts.d.ts.map +0 -1
  132. package/dist/lib/network.d.ts +0 -11
  133. package/dist/lib/network.d.ts.map +0 -1
  134. package/dist/lib/network.test.d.ts +0 -2
  135. package/dist/lib/network.test.d.ts.map +0 -1
  136. package/dist/lib/page-memory.d.ts +0 -14
  137. package/dist/lib/page-memory.d.ts.map +0 -1
  138. package/dist/lib/performance.d.ts +0 -13
  139. package/dist/lib/performance.d.ts.map +0 -1
  140. package/dist/lib/profiles.d.ts +0 -23
  141. package/dist/lib/profiles.d.ts.map +0 -1
  142. package/dist/lib/qol.test.d.ts +0 -2
  143. package/dist/lib/qol.test.d.ts.map +0 -1
  144. package/dist/lib/recorder.d.ts +0 -11
  145. package/dist/lib/recorder.d.ts.map +0 -1
  146. package/dist/lib/recorder.test.d.ts +0 -2
  147. package/dist/lib/recorder.test.d.ts.map +0 -1
  148. package/dist/lib/ref-cache.d.ts +0 -9
  149. package/dist/lib/ref-cache.d.ts.map +0 -1
  150. package/dist/lib/sanitize.d.ts +0 -21
  151. package/dist/lib/sanitize.d.ts.map +0 -1
  152. package/dist/lib/screenshot-v4.test.d.ts +0 -2
  153. package/dist/lib/screenshot-v4.test.d.ts.map +0 -1
  154. package/dist/lib/screenshot.d.ts +0 -11
  155. package/dist/lib/screenshot.d.ts.map +0 -1
  156. package/dist/lib/screenshot.test.d.ts +0 -2
  157. package/dist/lib/screenshot.test.d.ts.map +0 -1
  158. package/dist/lib/script-engine.d.ts +0 -28
  159. package/dist/lib/script-engine.d.ts.map +0 -1
  160. package/dist/lib/self-heal.d.ts +0 -18
  161. package/dist/lib/self-heal.d.ts.map +0 -1
  162. package/dist/lib/session-v3.test.d.ts +0 -2
  163. package/dist/lib/session-v3.test.d.ts.map +0 -1
  164. package/dist/lib/session.d.ts +0 -38
  165. package/dist/lib/session.d.ts.map +0 -1
  166. package/dist/lib/skills-runner.d.ts +0 -14
  167. package/dist/lib/skills-runner.d.ts.map +0 -1
  168. package/dist/lib/snapshot-diff.test.d.ts +0 -2
  169. package/dist/lib/snapshot-diff.test.d.ts.map +0 -1
  170. package/dist/lib/snapshot.d.ts +0 -34
  171. package/dist/lib/snapshot.d.ts.map +0 -1
  172. package/dist/lib/snapshot.test.d.ts +0 -2
  173. package/dist/lib/snapshot.test.d.ts.map +0 -1
  174. package/dist/lib/stealth.d.ts +0 -5
  175. package/dist/lib/stealth.d.ts.map +0 -1
  176. package/dist/lib/stealth.test.d.ts +0 -2
  177. package/dist/lib/stealth.test.d.ts.map +0 -1
  178. package/dist/lib/storage-state.d.ts +0 -15
  179. package/dist/lib/storage-state.d.ts.map +0 -1
  180. package/dist/lib/storage.d.ts +0 -19
  181. package/dist/lib/storage.d.ts.map +0 -1
  182. package/dist/lib/structured-extract.d.ts +0 -26
  183. package/dist/lib/structured-extract.d.ts.map +0 -1
  184. package/dist/lib/tabs.d.ts +0 -18
  185. package/dist/lib/tabs.d.ts.map +0 -1
  186. package/dist/lib/task-queue.d.ts +0 -21
  187. package/dist/lib/task-queue.d.ts.map +0 -1
  188. package/dist/lib/url-watcher.d.ts +0 -33
  189. package/dist/lib/url-watcher.d.ts.map +0 -1
  190. package/dist/lib/vision-fallback.d.ts +0 -29
  191. package/dist/lib/vision-fallback.d.ts.map +0 -1
  192. package/dist/lib/workflows.d.ts +0 -46
  193. package/dist/lib/workflows.d.ts.map +0 -1
  194. package/dist/mcp/actions.d.ts +0 -3
  195. package/dist/mcp/actions.d.ts.map +0 -1
  196. package/dist/mcp/capture.d.ts +0 -3
  197. package/dist/mcp/capture.d.ts.map +0 -1
  198. package/dist/mcp/data.d.ts +0 -3
  199. package/dist/mcp/data.d.ts.map +0 -1
  200. package/dist/mcp/gallery.test.d.ts +0 -2
  201. package/dist/mcp/gallery.test.d.ts.map +0 -1
  202. package/dist/mcp/helpers.d.ts +0 -55
  203. package/dist/mcp/helpers.d.ts.map +0 -1
  204. package/dist/mcp/index.d.ts +0 -3
  205. package/dist/mcp/index.d.ts.map +0 -1
  206. package/dist/mcp/index.test.d.ts +0 -2
  207. package/dist/mcp/index.test.d.ts.map +0 -1
  208. package/dist/mcp/meta.d.ts +0 -3
  209. package/dist/mcp/meta.d.ts.map +0 -1
  210. package/dist/mcp/network.d.ts +0 -3
  211. package/dist/mcp/network.d.ts.map +0 -1
  212. package/dist/mcp/recordings.d.ts +0 -3
  213. package/dist/mcp/recordings.d.ts.map +0 -1
  214. package/dist/mcp/scripts.d.ts +0 -3
  215. package/dist/mcp/scripts.d.ts.map +0 -1
  216. package/dist/mcp/sessions.d.ts +0 -3
  217. package/dist/mcp/sessions.d.ts.map +0 -1
  218. package/dist/mcp/v4.test.d.ts +0 -2
  219. package/dist/mcp/v4.test.d.ts.map +0 -1
  220. package/dist/server/index.d.ts +0 -2
  221. package/dist/server/index.d.ts.map +0 -1
  222. package/dist/server/index.test.d.ts +0 -2
  223. package/dist/server/index.test.d.ts.map +0 -1
  224. package/dist/types/index.d.ts +0 -425
  225. package/dist/types/index.d.ts.map +0 -1
@@ -4,25 +4,43 @@ var __getProtoOf = Object.getPrototypeOf;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
7
12
  var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
8
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
9
21
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
22
  for (let key of __getOwnPropNames(mod))
11
23
  if (!__hasOwnProp.call(to, key))
12
24
  __defProp(to, key, {
13
- get: () => mod[key],
25
+ get: __accessProp.bind(mod, key),
14
26
  enumerable: true
15
27
  });
28
+ if (canCache)
29
+ cache.set(mod, to);
16
30
  return to;
17
31
  };
18
32
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
33
+ var __returnValue = (v) => v;
34
+ function __exportSetter(name, newValue) {
35
+ this[name] = __returnValue.bind(null, newValue);
36
+ }
19
37
  var __export = (target, all) => {
20
38
  for (var name in all)
21
39
  __defProp(target, name, {
22
40
  get: all[name],
23
41
  enumerable: true,
24
42
  configurable: true,
25
- set: (newValue) => all[name] = () => newValue
43
+ set: __exportSetter.bind(all, name)
26
44
  });
27
45
  };
28
46
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -88,10 +106,30 @@ var init_types = __esm(() => {
88
106
  // src/db/schema.ts
89
107
  import { Database } from "bun:sqlite";
90
108
  import { join } from "path";
91
- import { mkdirSync } from "fs";
109
+ import { mkdirSync, existsSync, readdirSync, copyFileSync, statSync } from "fs";
92
110
  import { homedir } from "os";
93
111
  function getDataDir() {
94
- return process.env["BROWSER_DATA_DIR"] ?? join(homedir(), ".browser");
112
+ if (process.env["BROWSER_DATA_DIR"])
113
+ return process.env["BROWSER_DATA_DIR"];
114
+ const home = process.env["HOME"] || process.env["USERPROFILE"] || homedir();
115
+ const newDir = join(home, ".hasna", "browser");
116
+ const oldDir = join(home, ".browser");
117
+ if (existsSync(oldDir) && !existsSync(newDir)) {
118
+ mkdirSync(newDir, { recursive: true });
119
+ try {
120
+ for (const file of readdirSync(oldDir)) {
121
+ const oldPath = join(oldDir, file);
122
+ const newPath = join(newDir, file);
123
+ try {
124
+ if (statSync(oldPath).isFile()) {
125
+ copyFileSync(oldPath, newPath);
126
+ }
127
+ } catch {}
128
+ }
129
+ } catch {}
130
+ }
131
+ mkdirSync(newDir, { recursive: true });
132
+ return newDir;
95
133
  }
96
134
  function getDatabase(path) {
97
135
  const resolvedPath = path ?? process.env["BROWSER_DB_PATH"] ?? join(getDataDir(), "browser.db");
@@ -583,9 +621,8 @@ __export(exports_storage_state, {
583
621
  listStates: () => listStates,
584
622
  deleteState: () => deleteState
585
623
  });
586
- import { mkdirSync as mkdirSync3, existsSync, readdirSync, unlinkSync } from "fs";
624
+ import { mkdirSync as mkdirSync3, existsSync as existsSync2, readdirSync as readdirSync2, unlinkSync } from "fs";
587
625
  import { join as join3 } from "path";
588
- import { homedir as homedir3 } from "os";
589
626
  function ensureDir() {
590
627
  mkdirSync3(STATES_DIR, { recursive: true });
591
628
  }
@@ -603,11 +640,11 @@ async function saveStateFromPage(page, name) {
603
640
  }
604
641
  function loadStatePath(name) {
605
642
  const path = statePath(name);
606
- return existsSync(path) ? path : null;
643
+ return existsSync2(path) ? path : null;
607
644
  }
608
645
  function listStates() {
609
646
  ensureDir();
610
- return readdirSync(STATES_DIR).filter((f) => f.endsWith(".json")).map((f) => {
647
+ return readdirSync2(STATES_DIR).filter((f) => f.endsWith(".json")).map((f) => {
611
648
  const path = join3(STATES_DIR, f);
612
649
  const stat = Bun.file(path);
613
650
  return {
@@ -619,7 +656,7 @@ function listStates() {
619
656
  }
620
657
  function deleteState(name) {
621
658
  const path = statePath(name);
622
- if (existsSync(path)) {
659
+ if (existsSync2(path)) {
623
660
  unlinkSync(path);
624
661
  return true;
625
662
  }
@@ -627,7 +664,8 @@ function deleteState(name) {
627
664
  }
628
665
  var STATES_DIR;
629
666
  var init_storage_state = __esm(() => {
630
- STATES_DIR = join3(process.env["BROWSER_DATA_DIR"] ?? join3(homedir3(), ".browser"), "states");
667
+ init_schema();
668
+ STATES_DIR = join3(getDataDir(), "states");
631
669
  });
632
670
 
633
671
  // node_modules/sharp/lib/is.js
@@ -7225,7 +7263,7 @@ var init_snapshots = __esm(() => {
7225
7263
 
7226
7264
  // src/server/index.ts
7227
7265
  import { join as join7 } from "path";
7228
- import { existsSync as existsSync4 } from "fs";
7266
+ import { existsSync as existsSync5 } from "fs";
7229
7267
 
7230
7268
  // src/lib/session.ts
7231
7269
  init_types();
@@ -7323,10 +7361,15 @@ class BrowserPool {
7323
7361
  this.pool.push({ browser, inUse: true, createdAt: Date.now() });
7324
7362
  return browser;
7325
7363
  }
7326
- return new Promise((resolve) => {
7364
+ return new Promise((resolve, reject) => {
7365
+ const timeout = setTimeout(() => {
7366
+ clearInterval(interval);
7367
+ reject(new BrowserError("Browser pool exhausted \u2014 no browser became available within 30s", "POOL_TIMEOUT", true));
7368
+ }, 30000);
7327
7369
  const interval = setInterval(() => {
7328
7370
  const free = this.pool.find((e) => !e.inUse);
7329
7371
  if (free) {
7372
+ clearTimeout(timeout);
7330
7373
  clearInterval(interval);
7331
7374
  free.inUse = true;
7332
7375
  resolve(free.browser);
@@ -7365,7 +7408,7 @@ function isLightpandaAvailable() {
7365
7408
  const paths = [
7366
7409
  "/usr/local/bin/lightpanda",
7367
7410
  "/usr/bin/lightpanda",
7368
- `${process.env["HOME"]}/.browser/bin/lightpanda`
7411
+ `${process.env["HOME"]}/.hasna/browser/bin/lightpanda`
7369
7412
  ];
7370
7413
  return paths.some((p) => {
7371
7414
  try {
@@ -7384,7 +7427,7 @@ function getLightpandaBinaryPath() {
7384
7427
  "lightpanda",
7385
7428
  "/usr/local/bin/lightpanda",
7386
7429
  "/usr/bin/lightpanda",
7387
- `${process.env["HOME"]}/.browser/bin/lightpanda`
7430
+ `${process.env["HOME"]}/.hasna/browser/bin/lightpanda`
7388
7431
  ];
7389
7432
  for (const p of paths) {
7390
7433
  try {
@@ -7452,14 +7495,14 @@ async function connectLightpanda(port) {
7452
7495
  }
7453
7496
 
7454
7497
  // src/engines/bun-webview.ts
7498
+ init_schema();
7455
7499
  import { join as join2 } from "path";
7456
7500
  import { mkdirSync as mkdirSync2 } from "fs";
7457
- import { homedir as homedir2 } from "os";
7458
7501
  function isBunWebViewAvailable() {
7459
7502
  return typeof globalThis.Bun !== "undefined" && typeof globalThis.Bun.WebView !== "undefined";
7460
7503
  }
7461
7504
  function getProfileDir(profileName) {
7462
- const base = process.env["BROWSER_DATA_DIR"] ?? join2(homedir2(), ".browser");
7505
+ const base = getDataDir();
7463
7506
  const dir = join2(base, "profiles", profileName);
7464
7507
  mkdirSync2(dir, { recursive: true });
7465
7508
  return dir;
@@ -7918,6 +7961,7 @@ function enableNetworkLogging(page, sessionId) {
7918
7961
  };
7919
7962
  const onResponse = (res) => {
7920
7963
  const start = requestStart.get(res.url()) ?? Date.now();
7964
+ requestStart.delete(res.url());
7921
7965
  const duration = Date.now() - start;
7922
7966
  const req = res.request();
7923
7967
  try {
@@ -7934,11 +7978,17 @@ function enableNetworkLogging(page, sessionId) {
7934
7978
  });
7935
7979
  } catch {}
7936
7980
  };
7981
+ const onRequestFailed = (req) => {
7982
+ requestStart.delete(req.url());
7983
+ };
7937
7984
  page.on("request", onRequest);
7938
7985
  page.on("response", onResponse);
7986
+ page.on("requestfailed", onRequestFailed);
7939
7987
  return () => {
7940
7988
  page.off("request", onRequest);
7941
7989
  page.off("response", onResponse);
7990
+ page.off("requestfailed", onRequestFailed);
7991
+ requestStart.clear();
7942
7992
  };
7943
7993
  }
7944
7994
  function startHAR(page) {
@@ -7957,6 +8007,7 @@ function startHAR(page) {
7957
8007
  const start = requestStart.get(key);
7958
8008
  if (!start)
7959
8009
  return;
8010
+ requestStart.delete(key);
7960
8011
  const duration = Date.now() - start.time;
7961
8012
  const entry = {
7962
8013
  startedDateTime: new Date(start.time).toISOString(),
@@ -7979,15 +8030,20 @@ function startHAR(page) {
7979
8030
  timings: { send: 0, wait: duration, receive: 0 }
7980
8031
  };
7981
8032
  entries.push(entry);
7982
- requestStart.delete(key);
8033
+ };
8034
+ const onRequestFailed = (req) => {
8035
+ requestStart.delete(req.url() + req.method());
7983
8036
  };
7984
8037
  page.on("request", onRequest);
7985
8038
  page.on("response", onResponse);
8039
+ page.on("requestfailed", onRequestFailed);
7986
8040
  return {
7987
8041
  entries,
7988
8042
  stop: () => {
7989
8043
  page.off("request", onRequest);
7990
8044
  page.off("response", onResponse);
8045
+ page.off("requestfailed", onRequestFailed);
8046
+ requestStart.clear();
7991
8047
  return {
7992
8048
  log: {
7993
8049
  version: "1.2",
@@ -8549,7 +8605,6 @@ init_types();
8549
8605
  var import_sharp = __toESM(require_lib(), 1);
8550
8606
  import { join as join4 } from "path";
8551
8607
  import { mkdirSync as mkdirSync4 } from "fs";
8552
- import { homedir as homedir4 } from "os";
8553
8608
 
8554
8609
  // src/db/gallery.ts
8555
8610
  init_schema();
@@ -8678,11 +8733,9 @@ function getGalleryStats(projectId) {
8678
8733
  }
8679
8734
 
8680
8735
  // src/lib/screenshot.ts
8681
- function getDataDir2() {
8682
- return process.env["BROWSER_DATA_DIR"] ?? join4(homedir4(), ".browser");
8683
- }
8736
+ init_schema();
8684
8737
  function getScreenshotDir(projectId) {
8685
- const base = join4(getDataDir2(), "screenshots");
8738
+ const base = join4(getDataDir(), "screenshots");
8686
8739
  const date = new Date().toISOString().split("T")[0];
8687
8740
  const dir = projectId ? join4(base, projectId, date) : join4(base, date);
8688
8741
  mkdirSync4(dir, { recursive: true });
@@ -9050,14 +9103,11 @@ init_console_log();
9050
9103
  init_recordings();
9051
9104
 
9052
9105
  // src/lib/downloads.ts
9106
+ init_schema();
9053
9107
  import { join as join5, basename, extname } from "path";
9054
- import { mkdirSync as mkdirSync5, existsSync as existsSync2, readdirSync as readdirSync2, statSync, unlinkSync as unlinkSync2, copyFileSync, writeFileSync, readFileSync } from "fs";
9055
- import { homedir as homedir5 } from "os";
9056
- function getDataDir3() {
9057
- return process.env["BROWSER_DATA_DIR"] ?? join5(homedir5(), ".browser");
9058
- }
9108
+ import { mkdirSync as mkdirSync5, existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync2, copyFileSync as copyFileSync2, writeFileSync, readFileSync } from "fs";
9059
9109
  function getDownloadsDir(sessionId) {
9060
- const base = join5(getDataDir3(), "downloads");
9110
+ const base = join5(getDataDir(), "downloads");
9061
9111
  const dir = sessionId ? join5(base, sessionId) : base;
9062
9112
  mkdirSync5(dir, { recursive: true });
9063
9113
  return dir;
@@ -9069,20 +9119,20 @@ function listDownloads(sessionId) {
9069
9119
  const dir = getDownloadsDir(sessionId);
9070
9120
  const results = [];
9071
9121
  function scanDir(d) {
9072
- if (!existsSync2(d))
9122
+ if (!existsSync3(d))
9073
9123
  return;
9074
- const entries = readdirSync2(d);
9124
+ const entries = readdirSync3(d);
9075
9125
  for (const entry of entries) {
9076
9126
  if (entry.endsWith(".meta.json"))
9077
9127
  continue;
9078
9128
  const full = join5(d, entry);
9079
- const stat = statSync(full);
9129
+ const stat = statSync2(full);
9080
9130
  if (stat.isDirectory()) {
9081
9131
  scanDir(full);
9082
9132
  continue;
9083
9133
  }
9084
9134
  const mpath = metaPath(full);
9085
- if (!existsSync2(mpath))
9135
+ if (!existsSync3(mpath))
9086
9136
  continue;
9087
9137
  try {
9088
9138
  const meta = JSON.parse(readFileSync(mpath, "utf8"));
@@ -9113,7 +9163,7 @@ function deleteDownload(id, sessionId) {
9113
9163
  return false;
9114
9164
  try {
9115
9165
  unlinkSync2(file.path);
9116
- if (existsSync2(file.meta_path))
9166
+ if (existsSync3(file.meta_path))
9117
9167
  unlinkSync2(file.meta_path);
9118
9168
  return true;
9119
9169
  } catch {
@@ -9135,10 +9185,10 @@ function cleanStaleDownloads(olderThanDays = 7) {
9135
9185
  }
9136
9186
 
9137
9187
  // src/lib/gallery-diff.ts
9188
+ init_schema();
9138
9189
  var import_sharp2 = __toESM(require_lib(), 1);
9139
9190
  import { join as join6 } from "path";
9140
9191
  import { mkdirSync as mkdirSync6 } from "fs";
9141
- import { homedir as homedir6 } from "os";
9142
9192
  async function diffImages(path1, path2) {
9143
9193
  const img1 = import_sharp2.default(path1);
9144
9194
  const img2 = import_sharp2.default(path2);
@@ -9169,7 +9219,7 @@ async function diffImages(path1, path2) {
9169
9219
  diffBuffer[i + 2] = Math.round(raw1[i + 2] * 0.4);
9170
9220
  }
9171
9221
  }
9172
- const dataDir = process.env["BROWSER_DATA_DIR"] ?? join6(homedir6(), ".browser");
9222
+ const dataDir = getDataDir();
9173
9223
  const diffDir = join6(dataDir, "diffs");
9174
9224
  mkdirSync6(diffDir, { recursive: true });
9175
9225
  const diffPath = join6(diffDir, `diff-${Date.now()}.webp`);
@@ -9425,14 +9475,14 @@ var server = Bun.serve({
9425
9475
  if (path.match(/^\/api\/gallery\/([^/]+)\/thumbnail$/) && method === "GET") {
9426
9476
  const id = path.split("/")[3];
9427
9477
  const entry = getEntry(id);
9428
- if (!entry?.thumbnail_path || !existsSync4(entry.thumbnail_path))
9478
+ if (!entry?.thumbnail_path || !existsSync5(entry.thumbnail_path))
9429
9479
  return notFound("Thumbnail not found");
9430
9480
  return new Response(Bun.file(entry.thumbnail_path), { headers: { ...CORS_HEADERS } });
9431
9481
  }
9432
9482
  if (path.match(/^\/api\/gallery\/([^/]+)\/image$/) && method === "GET") {
9433
9483
  const id = path.split("/")[3];
9434
9484
  const entry = getEntry(id);
9435
- if (!entry?.path || !existsSync4(entry.path))
9485
+ if (!entry?.path || !existsSync5(entry.path))
9436
9486
  return notFound("Image not found");
9437
9487
  return new Response(Bun.file(entry.path), { headers: { ...CORS_HEADERS } });
9438
9488
  }
@@ -9460,7 +9510,7 @@ var server = Bun.serve({
9460
9510
  if (path.match(/^\/api\/downloads\/([^/]+)\/raw$/) && method === "GET") {
9461
9511
  const id = path.split("/")[3];
9462
9512
  const file = getDownload(id);
9463
- if (!file || !existsSync4(file.path))
9513
+ if (!file || !existsSync5(file.path))
9464
9514
  return notFound("Download not found");
9465
9515
  return new Response(Bun.file(file.path), { headers: { ...CORS_HEADERS } });
9466
9516
  }
@@ -9469,9 +9519,9 @@ var server = Bun.serve({
9469
9519
  return ok({ deleted: deleteDownload(id) });
9470
9520
  }
9471
9521
  const dashboardDist = join7(import.meta.dir, "../../dashboard/dist");
9472
- if (existsSync4(dashboardDist)) {
9522
+ if (existsSync5(dashboardDist)) {
9473
9523
  const filePath = path === "/" ? join7(dashboardDist, "index.html") : join7(dashboardDist, path);
9474
- if (existsSync4(filePath)) {
9524
+ if (existsSync5(filePath)) {
9475
9525
  return new Response(Bun.file(filePath), { headers: CORS_HEADERS });
9476
9526
  }
9477
9527
  return new Response(Bun.file(join7(dashboardDist, "index.html")), { headers: CORS_HEADERS });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/browser",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "General-purpose browser agent toolkit — Playwright, Chrome DevTools Protocol, Lightpanda with auto engine selection. CLI + MCP + REST + SDK.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",