@humain/terminal 0.0.4-beta.1 → 0.0.5

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 (675) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1 -0
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  6. package/dist/bun/restore-sandbox-env.js.map +1 -1
  7. package/dist/cli/args.d.ts +1 -0
  8. package/dist/cli/args.d.ts.map +1 -1
  9. package/dist/cli/args.js +11 -0
  10. package/dist/cli/args.js.map +1 -1
  11. package/dist/cli/auth-check.d.ts.map +1 -1
  12. package/dist/cli/auth-check.js.map +1 -1
  13. package/dist/cli/auth-command.d.ts.map +1 -1
  14. package/dist/cli/auth-command.js.map +1 -1
  15. package/dist/cli/config-selector.d.ts.map +1 -1
  16. package/dist/cli/config-selector.js.map +1 -1
  17. package/dist/cli/credential-print.d.ts.map +1 -1
  18. package/dist/cli/credential-print.js.map +1 -1
  19. package/dist/cli/experimental/auth.d.ts.map +1 -1
  20. package/dist/cli/experimental/auth.js.map +1 -1
  21. package/dist/cli/experimental/cli.d.ts.map +1 -1
  22. package/dist/cli/experimental/command-options.d.ts.map +1 -1
  23. package/dist/cli/experimental/command-options.js.map +1 -1
  24. package/dist/cli/experimental/command.d.ts.map +1 -1
  25. package/dist/cli/experimental/command.js +2 -5
  26. package/dist/cli/experimental/command.js.map +1 -1
  27. package/dist/cli/experimental/commands/client.d.ts.map +1 -1
  28. package/dist/cli/experimental/commands/client.js.map +1 -1
  29. package/dist/cli/experimental/commands/pi.d.ts.map +1 -1
  30. package/dist/cli/experimental/commands/pi.js.map +1 -1
  31. package/dist/cli/experimental/commands/server.d.ts.map +1 -1
  32. package/dist/cli/experimental/commands/server.js.map +1 -1
  33. package/dist/cli/experimental/transport-address.d.ts.map +1 -1
  34. package/dist/cli/experimental/transport-address.js.map +1 -1
  35. package/dist/cli/file-processor.d.ts.map +1 -1
  36. package/dist/cli/file-processor.js.map +1 -1
  37. package/dist/cli/initial-message.d.ts +1 -1
  38. package/dist/cli/initial-message.d.ts.map +1 -1
  39. package/dist/cli/initial-message.js.map +1 -1
  40. package/dist/cli/list-models.d.ts.map +1 -1
  41. package/dist/cli/list-models.js.map +1 -1
  42. package/dist/cli/project-trust.d.ts.map +1 -1
  43. package/dist/cli/project-trust.js.map +1 -1
  44. package/dist/cli/session-picker.d.ts.map +1 -1
  45. package/dist/cli/session-picker.js.map +1 -1
  46. package/dist/cli/startup-ui.d.ts.map +1 -1
  47. package/dist/cli/startup-ui.js.map +1 -1
  48. package/dist/cli.d.ts.map +1 -1
  49. package/dist/cli.js.map +1 -1
  50. package/dist/client/index.d.ts.map +1 -1
  51. package/dist/client/remote-session.d.ts.map +1 -1
  52. package/dist/client/remote-session.js.map +1 -1
  53. package/dist/client/transcript.d.ts.map +1 -1
  54. package/dist/client/transcript.js +1 -1
  55. package/dist/client/transcript.js.map +1 -1
  56. package/dist/config.d.ts.map +1 -1
  57. package/dist/config.js.map +1 -1
  58. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  59. package/dist/core/agent-session-runtime.js +0 -8
  60. package/dist/core/agent-session-runtime.js.map +1 -1
  61. package/dist/core/agent-session-services.d.ts.map +1 -1
  62. package/dist/core/agent-session-services.js.map +1 -1
  63. package/dist/core/agent-session.d.ts +36 -2
  64. package/dist/core/agent-session.d.ts.map +1 -1
  65. package/dist/core/agent-session.js +100 -128
  66. package/dist/core/agent-session.js.map +1 -1
  67. package/dist/core/auth-guidance.d.ts.map +1 -1
  68. package/dist/core/auth-guidance.js.map +1 -1
  69. package/dist/core/auth-storage.d.ts.map +1 -1
  70. package/dist/core/auth-storage.js +3 -8
  71. package/dist/core/auth-storage.js.map +1 -1
  72. package/dist/core/bash-executor.d.ts.map +1 -1
  73. package/dist/core/bash-executor.js.map +1 -1
  74. package/dist/core/cache-stats.d.ts.map +1 -1
  75. package/dist/core/cache-stats.js.map +1 -1
  76. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  77. package/dist/core/compaction/branch-summarization.js.map +1 -1
  78. package/dist/core/compaction/compaction.d.ts.map +1 -1
  79. package/dist/core/compaction/compaction.js.map +1 -1
  80. package/dist/core/compaction/index.d.ts.map +1 -1
  81. package/dist/core/compaction/utils.d.ts.map +1 -1
  82. package/dist/core/compaction/utils.js.map +1 -1
  83. package/dist/core/defaults.d.ts.map +1 -1
  84. package/dist/core/diagnostics.d.ts.map +1 -1
  85. package/dist/core/event-bus.d.ts.map +1 -1
  86. package/dist/core/event-bus.js.map +1 -1
  87. package/dist/core/exec.d.ts.map +1 -1
  88. package/dist/core/exec.js.map +1 -1
  89. package/dist/core/experimental.d.ts +4 -0
  90. package/dist/core/experimental.d.ts.map +1 -1
  91. package/dist/core/experimental.js +4 -0
  92. package/dist/core/experimental.js.map +1 -1
  93. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  94. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  95. package/dist/core/export-html/index.d.ts.map +1 -1
  96. package/dist/core/export-html/index.js.map +1 -1
  97. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  98. package/dist/core/export-html/tool-renderer.js.map +1 -1
  99. package/dist/core/extensions/index.d.ts.map +1 -1
  100. package/dist/core/extensions/loader.d.ts.map +1 -1
  101. package/dist/core/extensions/loader.js.map +1 -1
  102. package/dist/core/extensions/runner.d.ts.map +1 -1
  103. package/dist/core/extensions/runner.js +22 -30
  104. package/dist/core/extensions/runner.js.map +1 -1
  105. package/dist/core/extensions/types.d.ts +4 -0
  106. package/dist/core/extensions/types.d.ts.map +1 -1
  107. package/dist/core/extensions/types.js.map +1 -1
  108. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  109. package/dist/core/extensions/wrapper.js.map +1 -1
  110. package/dist/core/footer-data-provider.d.ts.map +1 -1
  111. package/dist/core/footer-data-provider.js +17 -18
  112. package/dist/core/footer-data-provider.js.map +1 -1
  113. package/dist/core/http-dispatcher.d.ts.map +1 -1
  114. package/dist/core/http-dispatcher.js.map +1 -1
  115. package/dist/core/index.d.ts.map +1 -1
  116. package/dist/core/keybindings.d.ts +24 -0
  117. package/dist/core/keybindings.d.ts.map +1 -1
  118. package/dist/core/keybindings.js +0 -1
  119. package/dist/core/keybindings.js.map +1 -1
  120. package/dist/core/messages.d.ts.map +1 -1
  121. package/dist/core/messages.js.map +1 -1
  122. package/dist/core/model-config.d.ts +5 -0
  123. package/dist/core/model-config.d.ts.map +1 -1
  124. package/dist/core/model-config.js +1 -2
  125. package/dist/core/model-config.js.map +1 -1
  126. package/dist/core/model-registry.d.ts.map +1 -1
  127. package/dist/core/model-registry.js +0 -1
  128. package/dist/core/model-registry.js.map +1 -1
  129. package/dist/core/model-resolver.d.ts.map +1 -1
  130. package/dist/core/model-resolver.js.map +1 -1
  131. package/dist/core/model-runtime.d.ts.map +1 -1
  132. package/dist/core/model-runtime.js +15 -25
  133. package/dist/core/model-runtime.js.map +1 -1
  134. package/dist/core/models-store.d.ts.map +1 -1
  135. package/dist/core/models-store.js +3 -4
  136. package/dist/core/models-store.js.map +1 -1
  137. package/dist/core/output-guard.d.ts.map +1 -1
  138. package/dist/core/output-guard.js.map +1 -1
  139. package/dist/core/package-manager.d.ts.map +1 -1
  140. package/dist/core/package-manager.js +0 -7
  141. package/dist/core/package-manager.js.map +1 -1
  142. package/dist/core/pi-manifest.d.ts.map +1 -1
  143. package/dist/core/pi-manifest.js.map +1 -1
  144. package/dist/core/project-trust.d.ts.map +1 -1
  145. package/dist/core/project-trust.js.map +1 -1
  146. package/dist/core/prompt-templates.d.ts.map +1 -1
  147. package/dist/core/prompt-templates.js.map +1 -1
  148. package/dist/core/provider-attribution.d.ts.map +1 -1
  149. package/dist/core/provider-attribution.js.map +1 -1
  150. package/dist/core/provider-composer.d.ts.map +1 -1
  151. package/dist/core/provider-composer.js.map +1 -1
  152. package/dist/core/radius.d.ts.map +1 -1
  153. package/dist/core/remote-catalog-provider.d.ts.map +1 -1
  154. package/dist/core/remote-catalog-provider.js.map +1 -1
  155. package/dist/core/resolve-config-value.d.ts.map +1 -1
  156. package/dist/core/resolve-config-value.js.map +1 -1
  157. package/dist/core/resource-loader.d.ts.map +1 -1
  158. package/dist/core/resource-loader.js +0 -44
  159. package/dist/core/resource-loader.js.map +1 -1
  160. package/dist/core/runtime-credentials.d.ts.map +1 -1
  161. package/dist/core/runtime-credentials.js +1 -2
  162. package/dist/core/runtime-credentials.js.map +1 -1
  163. package/dist/core/sdk.d.ts +5 -3
  164. package/dist/core/sdk.d.ts.map +1 -1
  165. package/dist/core/sdk.js +2 -1
  166. package/dist/core/sdk.js.map +1 -1
  167. package/dist/core/session-cwd.d.ts.map +1 -1
  168. package/dist/core/session-cwd.js +0 -1
  169. package/dist/core/session-cwd.js.map +1 -1
  170. package/dist/core/session-manager.d.ts.map +1 -1
  171. package/dist/core/session-manager.js +9 -13
  172. package/dist/core/session-manager.js.map +1 -1
  173. package/dist/core/settings-manager.d.ts +6 -0
  174. package/dist/core/settings-manager.d.ts.map +1 -1
  175. package/dist/core/settings-manager.js +19 -17
  176. package/dist/core/settings-manager.js.map +1 -1
  177. package/dist/core/skills.d.ts.map +1 -1
  178. package/dist/core/skills.js.map +1 -1
  179. package/dist/core/slash-commands.d.ts.map +1 -1
  180. package/dist/core/source-info.d.ts.map +1 -1
  181. package/dist/core/source-info.js.map +1 -1
  182. package/dist/core/system-prompt.d.ts.map +1 -1
  183. package/dist/core/system-prompt.js +1 -1
  184. package/dist/core/system-prompt.js.map +1 -1
  185. package/dist/core/telemetry.d.ts.map +1 -1
  186. package/dist/core/telemetry.js.map +1 -1
  187. package/dist/core/timings.d.ts.map +1 -1
  188. package/dist/core/timings.js.map +1 -1
  189. package/dist/core/tools/bash.d.ts.map +1 -1
  190. package/dist/core/tools/bash.js +10 -5
  191. package/dist/core/tools/bash.js.map +1 -1
  192. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  193. package/dist/core/tools/edit-diff.js.map +1 -1
  194. package/dist/core/tools/edit.d.ts.map +1 -1
  195. package/dist/core/tools/edit.js +2 -0
  196. package/dist/core/tools/edit.js.map +1 -1
  197. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  198. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  199. package/dist/core/tools/find.d.ts +1 -1
  200. package/dist/core/tools/find.d.ts.map +1 -1
  201. package/dist/core/tools/find.js +1 -1
  202. package/dist/core/tools/find.js.map +1 -1
  203. package/dist/core/tools/grep.d.ts.map +1 -1
  204. package/dist/core/tools/grep.js +1 -1
  205. package/dist/core/tools/grep.js.map +1 -1
  206. package/dist/core/tools/index.d.ts.map +1 -1
  207. package/dist/core/tools/index.js.map +1 -1
  208. package/dist/core/tools/ls.d.ts.map +1 -1
  209. package/dist/core/tools/ls.js.map +1 -1
  210. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  211. package/dist/core/tools/output-accumulator.js +12 -18
  212. package/dist/core/tools/output-accumulator.js.map +1 -1
  213. package/dist/core/tools/path-utils.d.ts.map +1 -1
  214. package/dist/core/tools/path-utils.js.map +1 -1
  215. package/dist/core/tools/read.d.ts.map +1 -1
  216. package/dist/core/tools/read.js +2 -0
  217. package/dist/core/tools/read.js.map +1 -1
  218. package/dist/core/tools/render-utils.d.ts.map +1 -1
  219. package/dist/core/tools/render-utils.js.map +1 -1
  220. package/dist/core/tools/subagent.d.ts +3 -0
  221. package/dist/core/tools/subagent.d.ts.map +1 -1
  222. package/dist/core/tools/subagent.js +30 -9
  223. package/dist/core/tools/subagent.js.map +1 -1
  224. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  225. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  226. package/dist/core/tools/truncate.d.ts.map +1 -1
  227. package/dist/core/tools/truncate.js.map +1 -1
  228. package/dist/core/tools/write.d.ts.map +1 -1
  229. package/dist/core/tools/write.js +2 -1
  230. package/dist/core/tools/write.js.map +1 -1
  231. package/dist/core/trust-manager.d.ts.map +1 -1
  232. package/dist/core/trust-manager.js +0 -1
  233. package/dist/core/trust-manager.js.map +1 -1
  234. package/dist/core/usage-totals.d.ts.map +1 -1
  235. package/dist/core/usage-totals.js.map +1 -1
  236. package/dist/extensions/index.d.ts.map +1 -1
  237. package/dist/extensions/llama/client.d.ts.map +1 -1
  238. package/dist/extensions/llama/client.js +0 -2
  239. package/dist/extensions/llama/client.js.map +1 -1
  240. package/dist/extensions/llama/huggingface.d.ts.map +1 -1
  241. package/dist/extensions/llama/huggingface.js +0 -2
  242. package/dist/extensions/llama/huggingface.js.map +1 -1
  243. package/dist/extensions/llama/index.d.ts.map +1 -1
  244. package/dist/extensions/llama/index.js.map +1 -1
  245. package/dist/extensions/llama/provider.d.ts.map +1 -1
  246. package/dist/extensions/llama/provider.js.map +1 -1
  247. package/dist/extensions/llama/ui.d.ts.map +1 -1
  248. package/dist/extensions/llama/ui.js +12 -28
  249. package/dist/extensions/llama/ui.js.map +1 -1
  250. package/dist/humain/agent-execution-protocol.d.ts.map +1 -1
  251. package/dist/humain/agent-execution-protocol.js.map +1 -1
  252. package/dist/humain/agent-execution-runtime.d.ts.map +1 -1
  253. package/dist/humain/agent-execution-runtime.js.map +1 -1
  254. package/dist/humain/bedrock-provider/vendor/index.bundle.mjs +127 -7
  255. package/dist/humain/brand-logo.d.ts.map +1 -1
  256. package/dist/humain/index.d.ts.map +1 -1
  257. package/dist/humain/index.js.map +1 -1
  258. package/dist/humain/legacy-workflow-tiers.d.ts.map +1 -1
  259. package/dist/humain/legacy-workflow-tiers.js.map +1 -1
  260. package/dist/humain/mcp-adapter/vendor/package.json +3 -3
  261. package/dist/humain/mcp-adapter.d.ts.map +1 -1
  262. package/dist/humain/mcp-adapter.js.map +1 -1
  263. package/dist/humain/pi-agent-execution-host.d.ts.map +1 -1
  264. package/dist/humain/pi-agent-execution-host.js.map +1 -1
  265. package/dist/humain/web-access/host.d.ts.map +1 -1
  266. package/dist/humain/web-access/index.d.ts.map +1 -1
  267. package/dist/humain/web-access/index.js.map +1 -1
  268. package/dist/humain/web-access/vendor/activity.d.ts.map +1 -1
  269. package/dist/humain/web-access/vendor/activity.js +7 -5
  270. package/dist/humain/web-access/vendor/activity.js.map +1 -1
  271. package/dist/humain/web-access/vendor/anysearch.d.ts.map +1 -1
  272. package/dist/humain/web-access/vendor/anysearch.js.map +1 -1
  273. package/dist/humain/web-access/vendor/auth-fetch.d.ts.map +1 -1
  274. package/dist/humain/web-access/vendor/auth-fetch.js.map +1 -1
  275. package/dist/humain/web-access/vendor/bocha.d.ts.map +1 -1
  276. package/dist/humain/web-access/vendor/bocha.js.map +1 -1
  277. package/dist/humain/web-access/vendor/brave.d.ts.map +1 -1
  278. package/dist/humain/web-access/vendor/brave.js.map +1 -1
  279. package/dist/humain/web-access/vendor/brightdata-unlocker.d.ts.map +1 -1
  280. package/dist/humain/web-access/vendor/brightdata-unlocker.js.map +1 -1
  281. package/dist/humain/web-access/vendor/brightdata.d.ts.map +1 -1
  282. package/dist/humain/web-access/vendor/brightdata.js.map +1 -1
  283. package/dist/humain/web-access/vendor/chrome-cookies.d.ts.map +1 -1
  284. package/dist/humain/web-access/vendor/chrome-cookies.js +101 -19
  285. package/dist/humain/web-access/vendor/chrome-cookies.js.map +1 -1
  286. package/dist/humain/web-access/vendor/content-find.d.ts.map +1 -1
  287. package/dist/humain/web-access/vendor/content-find.js.map +1 -1
  288. package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -1
  289. package/dist/humain/web-access/vendor/credential-source.js +0 -2
  290. package/dist/humain/web-access/vendor/credential-source.js.map +1 -1
  291. package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
  292. package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
  293. package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
  294. package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
  295. package/dist/humain/web-access/vendor/data-uri-sanitize.d.ts +21 -0
  296. package/dist/humain/web-access/vendor/data-uri-sanitize.d.ts.map +1 -0
  297. package/dist/humain/web-access/vendor/data-uri-sanitize.js +373 -0
  298. package/dist/humain/web-access/vendor/data-uri-sanitize.js.map +1 -0
  299. package/dist/humain/web-access/vendor/datalab-pdf-extract.d.ts.map +1 -1
  300. package/dist/humain/web-access/vendor/datalab-pdf-extract.js.map +1 -1
  301. package/dist/humain/web-access/vendor/declared-web-links.d.ts.map +1 -1
  302. package/dist/humain/web-access/vendor/declared-web-links.js.map +1 -1
  303. package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -1
  304. package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -1
  305. package/dist/humain/web-access/vendor/exa.d.ts.map +1 -1
  306. package/dist/humain/web-access/vendor/exa.js.map +1 -1
  307. package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
  308. package/dist/humain/web-access/vendor/extract.js +14 -2
  309. package/dist/humain/web-access/vendor/extract.js.map +1 -1
  310. package/dist/humain/web-access/vendor/feature-config.d.ts.map +1 -1
  311. package/dist/humain/web-access/vendor/feature-config.js.map +1 -1
  312. package/dist/humain/web-access/vendor/fetch-params.d.ts.map +1 -1
  313. package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
  314. package/dist/humain/web-access/vendor/firecrawl.d.ts.map +1 -1
  315. package/dist/humain/web-access/vendor/firecrawl.js +15 -2
  316. package/dist/humain/web-access/vendor/firecrawl.js.map +1 -1
  317. package/dist/humain/web-access/vendor/gemini-api.d.ts.map +1 -1
  318. package/dist/humain/web-access/vendor/gemini-api.js.map +1 -1
  319. package/dist/humain/web-access/vendor/gemini-pdf-extract.d.ts.map +1 -1
  320. package/dist/humain/web-access/vendor/gemini-pdf-extract.js.map +1 -1
  321. package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
  322. package/dist/humain/web-access/vendor/gemini-search.js +30 -16
  323. package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
  324. package/dist/humain/web-access/vendor/gemini-url-context.d.ts.map +1 -1
  325. package/dist/humain/web-access/vendor/gemini-url-context.js.map +1 -1
  326. package/dist/humain/web-access/vendor/gemini-web-config.d.ts.map +1 -1
  327. package/dist/humain/web-access/vendor/gemini-web-config.js.map +1 -1
  328. package/dist/humain/web-access/vendor/gemini-web.d.ts.map +1 -1
  329. package/dist/humain/web-access/vendor/gemini-web.js.map +1 -1
  330. package/dist/humain/web-access/vendor/github-api.d.ts.map +1 -1
  331. package/dist/humain/web-access/vendor/github-api.js.map +1 -1
  332. package/dist/humain/web-access/vendor/github-extract.d.ts.map +1 -1
  333. package/dist/humain/web-access/vendor/github-extract.js +69 -35
  334. package/dist/humain/web-access/vendor/github-extract.js.map +1 -1
  335. package/dist/humain/web-access/vendor/index.d.ts +74 -1
  336. package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
  337. package/dist/humain/web-access/vendor/index.js +38 -15
  338. package/dist/humain/web-access/vendor/index.js.map +1 -1
  339. package/dist/humain/web-access/vendor/jina-search.d.ts.map +1 -1
  340. package/dist/humain/web-access/vendor/jina-search.js.map +1 -1
  341. package/dist/humain/web-access/vendor/kagi.d.ts.map +1 -1
  342. package/dist/humain/web-access/vendor/kagi.js.map +1 -1
  343. package/dist/humain/web-access/vendor/ollama.d.ts.map +1 -1
  344. package/dist/humain/web-access/vendor/ollama.js.map +1 -1
  345. package/dist/humain/web-access/vendor/openai-search.d.ts +1 -1
  346. package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
  347. package/dist/humain/web-access/vendor/openai-search.js +15 -5
  348. package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
  349. package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
  350. package/dist/humain/web-access/vendor/page-query.js.map +1 -1
  351. package/dist/humain/web-access/vendor/parallel-mcp.d.ts.map +1 -1
  352. package/dist/humain/web-access/vendor/parallel-mcp.js.map +1 -1
  353. package/dist/humain/web-access/vendor/parallel.d.ts.map +1 -1
  354. package/dist/humain/web-access/vendor/parallel.js.map +1 -1
  355. package/dist/humain/web-access/vendor/pdf-extract.d.ts +1 -0
  356. package/dist/humain/web-access/vendor/pdf-extract.d.ts.map +1 -1
  357. package/dist/humain/web-access/vendor/pdf-extract.js +15 -5
  358. package/dist/humain/web-access/vendor/pdf-extract.js.map +1 -1
  359. package/dist/humain/web-access/vendor/perplexity.d.ts.map +1 -1
  360. package/dist/humain/web-access/vendor/perplexity.js.map +1 -1
  361. package/dist/humain/web-access/vendor/querit.d.ts.map +1 -1
  362. package/dist/humain/web-access/vendor/querit.js.map +1 -1
  363. package/dist/humain/web-access/vendor/query-rewrite.d.ts.map +1 -1
  364. package/dist/humain/web-access/vendor/query-rewrite.js.map +1 -1
  365. package/dist/humain/web-access/vendor/render-search-error.d.ts.map +1 -1
  366. package/dist/humain/web-access/vendor/render-search-error.js.map +1 -1
  367. package/dist/humain/web-access/vendor/rsc-extract.d.ts.map +1 -1
  368. package/dist/humain/web-access/vendor/rsc-extract.js.map +1 -1
  369. package/dist/humain/web-access/vendor/search1api.d.ts.map +1 -1
  370. package/dist/humain/web-access/vendor/search1api.js.map +1 -1
  371. package/dist/humain/web-access/vendor/searchinfinity.d.ts.map +1 -1
  372. package/dist/humain/web-access/vendor/searchinfinity.js.map +1 -1
  373. package/dist/humain/web-access/vendor/searxng.d.ts.map +1 -1
  374. package/dist/humain/web-access/vendor/searxng.js.map +1 -1
  375. package/dist/humain/web-access/vendor/serpbase.d.ts.map +1 -1
  376. package/dist/humain/web-access/vendor/serpbase.js.map +1 -1
  377. package/dist/humain/web-access/vendor/serpdive.d.ts.map +1 -1
  378. package/dist/humain/web-access/vendor/serpdive.js.map +1 -1
  379. package/dist/humain/web-access/vendor/serper.d.ts.map +1 -1
  380. package/dist/humain/web-access/vendor/serper.js.map +1 -1
  381. package/dist/humain/web-access/vendor/source-check.d.ts.map +1 -1
  382. package/dist/humain/web-access/vendor/source-check.js.map +1 -1
  383. package/dist/humain/web-access/vendor/ssrf-protection.d.ts +2 -0
  384. package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -1
  385. package/dist/humain/web-access/vendor/ssrf-protection.js +11 -2
  386. package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -1
  387. package/dist/humain/web-access/vendor/storage.d.ts.map +1 -1
  388. package/dist/humain/web-access/vendor/storage.js.map +1 -1
  389. package/dist/humain/web-access/vendor/summary-model-scope.d.ts.map +1 -1
  390. package/dist/humain/web-access/vendor/summary-model-scope.js.map +1 -1
  391. package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
  392. package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
  393. package/dist/humain/web-access/vendor/tavily.d.ts.map +1 -1
  394. package/dist/humain/web-access/vendor/tavily.js.map +1 -1
  395. package/dist/humain/web-access/vendor/tinyfish.d.ts.map +1 -1
  396. package/dist/humain/web-access/vendor/tinyfish.js.map +1 -1
  397. package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
  398. package/dist/humain/web-access/vendor/utils.js.map +1 -1
  399. package/dist/humain/web-access/vendor/valyu.d.ts.map +1 -1
  400. package/dist/humain/web-access/vendor/valyu.js.map +1 -1
  401. package/dist/humain/web-access/vendor/video-extract.d.ts.map +1 -1
  402. package/dist/humain/web-access/vendor/video-extract.js.map +1 -1
  403. package/dist/humain/web-access/vendor/xai-search.d.ts.map +1 -1
  404. package/dist/humain/web-access/vendor/xai-search.js.map +1 -1
  405. package/dist/humain/web-access/vendor/youtube-extract.d.ts.map +1 -1
  406. package/dist/humain/web-access/vendor/youtube-extract.js.map +1 -1
  407. package/dist/index.d.ts +1 -1
  408. package/dist/index.d.ts.map +1 -1
  409. package/dist/index.js.map +1 -1
  410. package/dist/main.d.ts.map +1 -1
  411. package/dist/main.js +4 -0
  412. package/dist/main.js.map +1 -1
  413. package/dist/migrations.d.ts.map +1 -1
  414. package/dist/migrations.js.map +1 -1
  415. package/dist/modes/agent-exec-mode.d.ts.map +1 -1
  416. package/dist/modes/agent-exec-mode.js.map +1 -1
  417. package/dist/modes/index.d.ts.map +1 -1
  418. package/dist/modes/interactive/components/armin.d.ts.map +1 -1
  419. package/dist/modes/interactive/components/armin.js +6 -10
  420. package/dist/modes/interactive/components/armin.js.map +1 -1
  421. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  422. package/dist/modes/interactive/components/assistant-message.js +2 -9
  423. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  424. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  425. package/dist/modes/interactive/components/bash-execution.js +4 -9
  426. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  427. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  428. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  429. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  430. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  431. package/dist/modes/interactive/components/branch-summary-message.js +1 -3
  432. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  433. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  434. package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
  435. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  436. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  437. package/dist/modes/interactive/components/config-selector.js +5 -22
  438. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  439. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  440. package/dist/modes/interactive/components/countdown-timer.js +0 -5
  441. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  442. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  443. package/dist/modes/interactive/components/custom-editor.js +1 -8
  444. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  445. package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
  446. package/dist/modes/interactive/components/custom-entry.js +1 -4
  447. package/dist/modes/interactive/components/custom-entry.js.map +1 -1
  448. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  449. package/dist/modes/interactive/components/custom-message.js +1 -7
  450. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  451. package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
  452. package/dist/modes/interactive/components/daxnuts.js +6 -8
  453. package/dist/modes/interactive/components/daxnuts.js.map +1 -1
  454. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  455. package/dist/modes/interactive/components/diff.js +2 -2
  456. package/dist/modes/interactive/components/diff.js.map +1 -1
  457. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  458. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  459. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  460. package/dist/modes/interactive/components/earendil-announcement.d.ts.map +1 -1
  461. package/dist/modes/interactive/components/earendil-announcement.js.map +1 -1
  462. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  463. package/dist/modes/interactive/components/extension-editor.js +1 -7
  464. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  465. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  466. package/dist/modes/interactive/components/extension-input.js +2 -8
  467. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  468. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  469. package/dist/modes/interactive/components/extension-selector.js +1 -9
  470. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  471. package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
  472. package/dist/modes/interactive/components/first-time-setup.js +2 -4
  473. package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
  474. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  475. package/dist/modes/interactive/components/footer.js +1 -3
  476. package/dist/modes/interactive/components/footer.js.map +1 -1
  477. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  478. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  479. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  480. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  481. package/dist/modes/interactive/components/login-dialog.js +3 -9
  482. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  483. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
  484. package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
  485. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  486. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  487. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  488. package/dist/modes/interactive/components/model-selector.js +14 -26
  489. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  490. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  491. package/dist/modes/interactive/components/oauth-selector.js +3 -11
  492. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  493. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  494. package/dist/modes/interactive/components/scoped-models-selector.js +9 -14
  495. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  496. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  497. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  498. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  499. package/dist/modes/interactive/components/session-selector.js +33 -57
  500. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  501. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  502. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  503. package/dist/modes/interactive/components/settings-selector.js +10 -14
  504. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  505. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  506. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  507. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  508. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  509. package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
  510. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  511. package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  512. package/dist/modes/interactive/components/status-indicator.js +0 -2
  513. package/dist/modes/interactive/components/status-indicator.js.map +1 -1
  514. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  515. package/dist/modes/interactive/components/theme-selector.js +0 -2
  516. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  517. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  518. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  519. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  520. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  521. package/dist/modes/interactive/components/tool-execution.js +19 -25
  522. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  523. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  524. package/dist/modes/interactive/components/tree-selector.js +18 -34
  525. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  526. package/dist/modes/interactive/components/trust-selector.d.ts.map +1 -1
  527. package/dist/modes/interactive/components/trust-selector.js +0 -6
  528. package/dist/modes/interactive/components/trust-selector.js.map +1 -1
  529. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  530. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  531. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  532. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  533. package/dist/modes/interactive/components/user-message.js +0 -4
  534. package/dist/modes/interactive/components/user-message.js.map +1 -1
  535. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  536. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  537. package/dist/modes/interactive/external-editor.d.ts.map +1 -1
  538. package/dist/modes/interactive/external-editor.js.map +1 -1
  539. package/dist/modes/interactive/interactive-mode.d.ts +18 -2
  540. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  541. package/dist/modes/interactive/interactive-mode.js +147 -137
  542. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  543. package/dist/modes/interactive/model-catalog-refresh.d.ts +7 -0
  544. package/dist/modes/interactive/model-catalog-refresh.d.ts.map +1 -0
  545. package/dist/modes/interactive/model-catalog-refresh.js +36 -0
  546. package/dist/modes/interactive/model-catalog-refresh.js.map +1 -0
  547. package/dist/modes/interactive/model-search.d.ts.map +1 -1
  548. package/dist/modes/interactive/model-search.js.map +1 -1
  549. package/dist/modes/interactive/theme/dark.json +2 -0
  550. package/dist/modes/interactive/theme/light.json +2 -0
  551. package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
  552. package/dist/modes/interactive/theme/theme-controller.d.ts.map +1 -1
  553. package/dist/modes/interactive/theme/theme-controller.js +25 -18
  554. package/dist/modes/interactive/theme/theme-controller.js.map +1 -1
  555. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  556. package/dist/modes/interactive/theme/theme.d.ts +7 -5
  557. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  558. package/dist/modes/interactive/theme/theme.js +12 -8
  559. package/dist/modes/interactive/theme/theme.js.map +1 -1
  560. package/dist/modes/json-event.d.ts +4 -1
  561. package/dist/modes/json-event.d.ts.map +1 -1
  562. package/dist/modes/json-event.js +5 -2
  563. package/dist/modes/json-event.js.map +1 -1
  564. package/dist/modes/print-mode.d.ts.map +1 -1
  565. package/dist/modes/print-mode.js.map +1 -1
  566. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  567. package/dist/modes/rpc/jsonl.js.map +1 -1
  568. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  569. package/dist/modes/rpc/rpc-client.js +9 -10
  570. package/dist/modes/rpc/rpc-client.js.map +1 -1
  571. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  572. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  573. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  574. package/dist/package-manager-cli.d.ts.map +1 -1
  575. package/dist/package-manager-cli.js.map +1 -1
  576. package/dist/rpc-entry.d.ts.map +1 -1
  577. package/dist/rpc-entry.js.map +1 -1
  578. package/dist/server/create-harness.d.ts.map +1 -1
  579. package/dist/server/create-harness.js +2 -0
  580. package/dist/server/create-harness.js.map +1 -1
  581. package/dist/utils/abort.d.ts.map +1 -1
  582. package/dist/utils/abort.js.map +1 -1
  583. package/dist/utils/ansi.d.ts.map +1 -1
  584. package/dist/utils/ansi.js.map +1 -1
  585. package/dist/utils/changelog.d.ts.map +1 -1
  586. package/dist/utils/changelog.js.map +1 -1
  587. package/dist/utils/child-process.d.ts.map +1 -1
  588. package/dist/utils/child-process.js.map +1 -1
  589. package/dist/utils/clipboard-image.d.ts.map +1 -1
  590. package/dist/utils/clipboard-image.js +1 -1
  591. package/dist/utils/clipboard-image.js.map +1 -1
  592. package/dist/utils/clipboard-native.d.ts.map +1 -1
  593. package/dist/utils/clipboard-native.js.map +1 -1
  594. package/dist/utils/clipboard.d.ts.map +1 -1
  595. package/dist/utils/clipboard.js.map +1 -1
  596. package/dist/utils/deprecation.d.ts.map +1 -1
  597. package/dist/utils/deprecation.js.map +1 -1
  598. package/dist/utils/exif-orientation.d.ts.map +1 -1
  599. package/dist/utils/exif-orientation.js.map +1 -1
  600. package/dist/utils/frontmatter.d.ts.map +1 -1
  601. package/dist/utils/frontmatter.js.map +1 -1
  602. package/dist/utils/fs-watch.d.ts.map +1 -1
  603. package/dist/utils/fs-watch.js.map +1 -1
  604. package/dist/utils/git.d.ts.map +1 -1
  605. package/dist/utils/git.js.map +1 -1
  606. package/dist/utils/html.d.ts.map +1 -1
  607. package/dist/utils/html.js.map +1 -1
  608. package/dist/utils/image-convert.d.ts.map +1 -1
  609. package/dist/utils/image-convert.js.map +1 -1
  610. package/dist/utils/image-process.d.ts.map +1 -1
  611. package/dist/utils/image-process.js.map +1 -1
  612. package/dist/utils/image-resize-core.d.ts.map +1 -1
  613. package/dist/utils/image-resize-core.js.map +1 -1
  614. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  615. package/dist/utils/image-resize-worker.js.map +1 -1
  616. package/dist/utils/image-resize.d.ts.map +1 -1
  617. package/dist/utils/image-resize.js.map +1 -1
  618. package/dist/utils/json.d.ts.map +1 -1
  619. package/dist/utils/json.js.map +1 -1
  620. package/dist/utils/management-http.d.ts.map +1 -1
  621. package/dist/utils/management-http.js.map +1 -1
  622. package/dist/utils/mime.d.ts.map +1 -1
  623. package/dist/utils/mime.js.map +1 -1
  624. package/dist/utils/open-browser.d.ts.map +1 -1
  625. package/dist/utils/open-browser.js.map +1 -1
  626. package/dist/utils/paths.d.ts.map +1 -1
  627. package/dist/utils/paths.js.map +1 -1
  628. package/dist/utils/photon.d.ts.map +1 -1
  629. package/dist/utils/photon.js.map +1 -1
  630. package/dist/utils/pi-user-agent.d.ts.map +1 -1
  631. package/dist/utils/pi-user-agent.js.map +1 -1
  632. package/dist/utils/shell.d.ts.map +1 -1
  633. package/dist/utils/shell.js.map +1 -1
  634. package/dist/utils/sleep.d.ts.map +1 -1
  635. package/dist/utils/sleep.js.map +1 -1
  636. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  637. package/dist/utils/syntax-highlight.js +1 -1
  638. package/dist/utils/syntax-highlight.js.map +1 -1
  639. package/dist/utils/tool-result-images.d.ts.map +1 -1
  640. package/dist/utils/tool-result-images.js.map +1 -1
  641. package/dist/utils/tools-manager.d.ts +10 -1
  642. package/dist/utils/tools-manager.d.ts.map +1 -1
  643. package/dist/utils/tools-manager.js +14 -19
  644. package/dist/utils/tools-manager.js.map +1 -1
  645. package/dist/utils/version-check.d.ts.map +1 -1
  646. package/dist/utils/version-check.js.map +1 -1
  647. package/dist/utils/windows-self-update.d.ts.map +1 -1
  648. package/dist/utils/windows-self-update.js.map +1 -1
  649. package/docs/compaction.md +3 -3
  650. package/docs/custom-provider.md +1 -1
  651. package/docs/environment-variables.md +1 -0
  652. package/docs/extensions.md +4 -0
  653. package/docs/json.md +6 -4
  654. package/docs/keybindings.md +8 -2
  655. package/docs/rpc.md +15 -4
  656. package/docs/sdk.md +9 -0
  657. package/docs/settings.md +31 -0
  658. package/docs/terminal-setup.md +23 -2
  659. package/docs/themes.md +23 -3
  660. package/docs/tui.md +2 -2
  661. package/docs/usage.md +3 -2
  662. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  663. package/examples/extensions/custom-provider-anthropic/package.json +2 -2
  664. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  665. package/examples/extensions/gondolin/package-lock.json +2 -2
  666. package/examples/extensions/gondolin/package.json +1 -1
  667. package/examples/extensions/minimal-mode.ts +6 -6
  668. package/examples/extensions/sandbox/package-lock.json +2 -2
  669. package/examples/extensions/sandbox/package.json +2 -2
  670. package/examples/extensions/with-deps/package-lock.json +2 -2
  671. package/examples/extensions/with-deps/package.json +1 -1
  672. package/npm-shrinkwrap.json +853 -661
  673. package/package.json +33 -33
  674. package/src/humain/web-access/UPSTREAM.md +1 -1
  675. package/src/humain/web-access/upstream.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"brightdata.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/brightdata.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst BRIGHTDATA_API_URL = \"https://api.brightdata.com/request\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\n// Bright Data proxies a real Google SERP through a provisioned \"zone\" and bills\n// per successful request against it. A SERP zone (Bright Data zone type `serp`)\n// and a Web Unlocker zone (type `unblocker`) are separate products with separate\n// prices, so the zone used for search is its own required setting and is never\n// guessed: the wrong zone is either an opaque 400 or a charge against the wrong\n// line of the invoice. Pricing: https://brightdata.com/pricing\nconst ZONE_PATTERN = /^[A-Za-z0-9_-]+$/;\n\n// Google's own time filter, passed straight through in the proxied URL. Unlike a\n// query-text hint this is an engine-side filter, so results outside the window\n// are not returned at all.\nconst RECENCY_TBS: Record<string, string> = {\n\tday: \"qdr:d\",\n\tweek: \"qdr:w\",\n\tmonth: \"qdr:m\",\n\tyear: \"qdr:y\",\n};\n\ninterface WebSearchConfig {\n\tbrightdataApiKey?: unknown;\n\tbrightdataSerpZone?: unknown;\n}\n\ninterface BrightDataOrganicResult {\n\tlink?: unknown;\n\ttitle?: unknown;\n\tdescription?: unknown;\n}\n\ninterface BrightDataSerpResponse {\n\torganic?: BrightDataOrganicResult[];\n}\n\ninterface BrightDataSearchOptions extends SearchOptions {\n\t// Accepted for parity with the other providers and deliberately ignored: a\n\t// SERP zone returns ranked links, never page bodies, so there is nothing to\n\t// return inline and `inlineContent` is never set.\n\tincludeContent?: boolean;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\n// `web-search.json` is a credential store: its own text is the secret. V8 quotes a\n// window of the source it choked on back inside the `JSON.parse` message — with a\n// short file, the whole file — so `{\"brightdataApiKey\": bd-real-token}` (quotes\n// forgotten around a pasted token) produces\n// `Unexpected token 'b', \"{\"brightdataApiKey\": bd-real-token}\" is not valid JSON`.\n// There is no credential to redact against at this point, because the credential is\n// what the file was being read for, so the parser's text is dropped entirely and only\n// its position is kept. That position is also the only part that cannot carry a\n// status-shaped phrase into `providerErrorStatus`.\n//\n// This is a deliberate divergence from `serpdive.ts:59-62`, `brave.ts:33-36`,\n// `anysearch.ts:48-51` and `firecrawl.ts:50-53`, which all quote the parser message\n// verbatim. They have the same leak; fixing it for every provider is a separate\n// change, and this module is not going to copy the bug forward to justify symmetry.\nfunction configParseDetail(err: unknown): string {\n\tconst position = errorMessage(err).match(/at position \\d+(?: \\(line \\d+ column \\d+\\))?/i);\n\treturn position ? `not valid JSON, ${position[0]}` : \"not valid JSON\";\n}\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${configParseDetail(err)}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Bright Data\",\n\t\tconfiguredValue: loadConfig().brightdataApiKey,\n\t\tenvironmentValue: process.env.BRIGHTDATA_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Bright Data API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"brightdataApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set BRIGHTDATA_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://brightdata.com/cp/setting/users\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\n// A zone name is an account-scoped identifier, not a URL. Validating the charset\n// here keeps a stray value out of the request body, where Bright Data reports it\n// as a generic 400 that reads like a credential problem.\n//\n// Total by construction: an invalid zone is `null`, never a throw.\n// `isBrightDataAvailable()` reads this, and availability is evaluated outside its\n// callers' error handling — `gemini-search.ts` checks it before entering the\n// per-provider try/catch, and `index.ts` awaits `getProviderAvailability()` on the\n// `web_search` path with nothing around it. A throw here would therefore take\n// `web_search` down for Brave and OpenAI too, over one mistyped Bright Data\n// setting. The loud, actionable error belongs on the request path, in\n// `requireSerpZone()`, where only this provider is affected.\nfunction normalizeZone(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst trimmed = value.trim();\n\tif (!trimmed) return null;\n\treturn ZONE_PATTERN.test(trimmed) ? trimmed : null;\n}\n\ninterface ZoneSetting {\n\traw: string;\n\tlabel: string;\n}\n\n// Resolved by presence, not by validity: a `BRIGHTDATA_SERP_ZONE` that is set but\n// malformed must not silently hand the request to the config file's zone. The\n// setting the user actually filled in is the setting the error names.\nfunction serpZoneSetting(): ZoneSetting | null {\n\tconst fromEnv = process.env.BRIGHTDATA_SERP_ZONE;\n\tif (typeof fromEnv === \"string\" && fromEnv.trim()) {\n\t\treturn { raw: fromEnv.trim(), label: \"BRIGHTDATA_SERP_ZONE\" };\n\t}\n\tconst configured = loadConfig().brightdataSerpZone;\n\tif (typeof configured === \"string\" && configured.trim()) {\n\t\treturn { raw: configured.trim(), label: `brightdataSerpZone in ${CONFIG_PATH}` };\n\t}\n\treturn null;\n}\n\nfunction getSerpZone(): string | null {\n\tconst setting = serpZoneSetting();\n\treturn setting ? normalizeZone(setting.raw) : null;\n}\n\n// There is no safe default, and in particular no fallback to a Web Unlocker zone:\n// `serp` and `unblocker` are different Bright Data zone types, priced differently,\n// and an Unlocker zone does not return SERP JSON — substituting one buys a\n// confusing paid failure instead of a search. A missing or malformed SERP zone\n// fails loudly here, before anything billable happens.\nfunction requireSerpZone(): string {\n\tconst setting = serpZoneSetting();\n\tconst zone = setting ? normalizeZone(setting.raw) : null;\n\tif (zone) return zone;\n\tif (setting) {\n\t\tthrow new Error(\n\t\t\t`Bright Data SERP zone is invalid: ${setting.label} must be a zone name of letters, digits, \"-\", or \"_\" ` +\n\t\t\t`(got \"${untrustedText(setting.raw, 60)}\").\\n` +\n\t\t\t\"The zone must be of Bright Data type `serp`; a Web Unlocker zone (type `unblocker`) is a different product and does not return SERP JSON.\\n\" +\n\t\t\t\"Create or rename one at https://brightdata.com/cp/zones\",\n\t\t);\n\t}\n\tthrow new Error(\n\t\t\"Bright Data SERP zone is invalid or missing. Either:\\n\" +\n\t\t` 1. Create ${CONFIG_PATH} with { \"brightdataSerpZone\": \"your_serp_zone\" }\\n` +\n\t\t\" 2. Set BRIGHTDATA_SERP_ZONE environment variable\\n\" +\n\t\t\"The zone must be of Bright Data type `serp`; a Web Unlocker zone is a different product and does not return SERP JSON.\\n\" +\n\t\t\"Create one at https://brightdata.com/cp/zones\",\n\t);\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (!input) return null;\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\ninterface DomainFilters {\n\tinclude: string[];\n\texclude: string[];\n}\n\nfunction parseDomainFilter(domainFilter: string[] | undefined): DomainFilters {\n\tconst filters: DomainFilters = { include: [], exclude: [] };\n\tif (!domainFilter?.length) return filters;\n\tfor (const raw of domainFilter) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.exclude : filters.include;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn filters;\n}\n\n// Bright Data has no domain parameter, but the engine behind it is Google, so the\n// filter is expressed the way Google expresses it: as `site:` operators inside\n// the query. That asks the engine for the right pages instead of discarding the\n// wrong ones locally — the difference SERPdive documents as a limitation.\nfunction buildSearchQuery(query: string, filters: DomainFilters): string {\n\tconst parts = [query];\n\tif (filters.include.length === 1) {\n\t\tparts.push(`site:${filters.include[0]}`);\n\t} else if (filters.include.length > 1) {\n\t\tparts.push(filters.include.map((domain) => `site:${domain}`).join(\" OR \"));\n\t}\n\tfor (const domain of filters.exclude) {\n\t\tparts.push(`-site:${domain}`);\n\t}\n\treturn parts.join(\" \");\n}\n\nfunction buildSerpUrl(searchQuery: string, numResults: number, recencyFilter: SearchOptions[\"recencyFilter\"]): string {\n\tconst params = new URLSearchParams({ q: searchQuery });\n\t// One SERP request is billed once whatever `num` says, so asking for a little\n\t// headroom is free and leaves something to keep after local re-filtering.\n\tparams.set(\"num\", String(Math.min(numResults + 5, 20)));\n\tconst tbs = recencyFilter ? RECENCY_TBS[recencyFilter] : undefined;\n\tif (tbs) params.set(\"tbs\", tbs);\n\t// `brd_json=1` is what makes Bright Data return the SERP as JSON instead of\n\t// Google's HTML. Without it `data_format: \"parsed_light\"` has nothing to read.\n\tparams.set(\"brd_json\", \"1\");\n\treturn `https://www.google.com/search?${params.toString()}`;\n}\n\nfunction domainMatches(hostname: string, domain: string): boolean {\n\treturn hostname === domain || hostname.endsWith(`.${domain}`);\n}\n\n// `site:` narrows the SERP but does not guarantee it: Google still mixes in\n// related hosts, and an OR group is honoured loosely. The same filter is applied\n// again here so the contract holds on what is actually returned.\nfunction passesDomainFilters(url: string, filters: DomainFilters): boolean {\n\tif (filters.include.length === 0 && filters.exclude.length === 0) return true;\n\tlet hostname: string;\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tif (filters.exclude.some((domain) => domainMatches(hostname, domain))) return false;\n\tif (filters.include.length === 0) return true;\n\treturn filters.include.some((domain) => domainMatches(hostname, domain));\n}\n\nfunction requestSignal(signal?: AbortSignal): AbortSignal {\n\tconst timeout = AbortSignal.timeout(SEARCH_TIMEOUT_MS);\n\treturn signal ? AbortSignal.any([signal, timeout]) : timeout;\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\n// Text that did not originate here — a proxied response body, a `JSON.parse`\n// message quoting that body, a config value — is quoted into Error messages, and\n// `gemini-search.ts` classifies routing failures by reading a status back out of\n// the message text (`providerErrorStatus`, /\\b(?:error|status|http)\\s+(\\d{3})\\b/).\n// A proxied Google interstitial that merely mentions \"Error 503\" would otherwise\n// be read as *our* status and retried as a transient failure, when what actually\n// happened is that a 200 was billed and is unusable. Status-shaped phrases in\n// quoted text are rewritten to `upstream <code>`: the number is still reported,\n// but only this module's own wording can name the status we received.\nconst STATUS_SHAPED_PATTERN = /\\b(?:error|status|http)[\\s:=-]{1,4}(\\d{3})\\b/gi;\n\n// `providerErrorStatus` is not the only thing that reads our message.\n// `classifyProviderError` also matches bare keyword phrases, and its branch order\n// decides which ones can reach us: `searchRouting.fallbackOn` accepts only\n// `transient`, `quota` and `network`, and of those three only the `quota` branch\n// (/rate limit|quota|too many requests/) runs BEFORE the `invalid-response` branch\n// that this module's own wording always triggers. So a billed 200 whose body reads\n// \"You have exceeded your rate limit\" would classify as `quota`, and with\n// `fallbackOn: [\"quota\"]` the user is charged, silently served the next provider's\n// answer, and shown no diagnostic — the failure mode this module exists to prevent.\n// `transient` and `network` sit after `invalid-response` and are unreachable for the\n// same reason; the test suite pins that ordering assumption rather than trusting it.\n//\n// The phrase is replaced rather than removed: the reader still learns the upstream\n// page mentioned a rate limit, but no substring of the replacement matches any\n// classifier branch (\"rate-limit\" is hyphenated, so /rate limit/ cannot match).\nconst QUOTA_SHAPED_PATTERN = /rate limit|quota|too many requests/gi;\n\n// The complete inventory of places foreign text is quoted into a message or a log\n// line, and what each one is required to apply. Adding a fifth means adding it here:\n//\n// | site | redactCredential | untrustedText |\n// | ----------------------------------------------- | ---------------- | ------------- |\n// | non-2xx response body | yes | yes (300) |\n// | invalid-JSON raw body | yes | yes (300) |\n// | Bright Data's own 200 error envelope | yes | yes (200) |\n// | transport/abort error from `fetch` | yes | n/a — see (a) |\n// | rejected zone value | n/a — see (b) | yes (60) |\n// | `JSON.parse` message on a response body | n/a — see (c) | n/a — see (c) |\n// | `JSON.parse` failure on `web-search.json` | n/a — see (c) | n/a — see (c) |\n//\n// (a) That message is generated locally by undici or by `AbortSignal`, never by the\n// proxied page, and the abort branch below matches on it; collapsing and\n// truncating it would buy nothing and could break that match.\n// (b) The zone is resolved *before* the credential on purpose, so that a config\n// mistake never spawns a `!command` resolver. There is therefore no key to redact\n// against yet, and the value being echoed is the user's own zone setting.\n// (c) Neither parser message is quoted at all, so neither needs a filter or a cap. V8\n// embeds a *prefix* of the offending input in its message, and `redactCredential`\n// substitutes whole values, so a prefix cannot be redacted out of it. Dropping the\n// message removes the leak by construction — see `configParseDetail` and the\n// `JSON.parse` catch on the response path.\n\n// Truncation happens BEFORE the rewrite, and the order is the whole point.\n// `STATUS_SHAPED_PATTERN` requires `(\\d{3})\\b`, so `error 5031` is deliberately left\n// alone — it is not a status. Sanitising first and slicing second let the cut land on\n// the 4th digit and hand back a freshly forged `error 503`, which\n// `gemini-search.ts`'s `providerErrorStatus` then reads as *our* status: a billed 200\n// classified `transient` and silently re-run on the next provider. Slicing first means\n// the rewrite always sees the exact text that will be quoted.\n//\n// The rewrite runs last and is therefore allowed to push the result a few characters\n// past `limit` (\"error 503\" → \"upstream 503\"). `limit` bounds how much upstream text is\n// quoted, not the final string length; a second `slice()` after the rewrite would\n// re-open exactly the hole this ordering closes.\nfunction untrustedText(text: string, limit = 300): string {\n\treturn text\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim()\n\t\t.slice(0, limit)\n\t\t.replace(STATUS_SHAPED_PATTERN, \"upstream $1\")\n\t\t.replace(QUOTA_SHAPED_PATTERN, \"upstream rate-limit notice\");\n}\n\nfunction invalidResponse(zone: string, message: string): Error {\n\treturn new Error(`Bright Data API returned invalid response for zone ${zone}: ${message}`);\n}\n\n// Bright Data reports some failures inside a normal HTTP 200 body — e.g.\n// `{\"error\":\"zone not found\",\"code\":\"zone_missing\"}` — because `format: \"raw\"`\n// means the HTTP layer describes the proxy hop, not the outcome.\n//\n// The envelope is upstream text, so it gets the same two-step treatment as every other\n// quoted body: `redactCredential` first (an upstream \"token <yours> is not valid for\n// this zone\" must not reprint the token), then `untrustedText`.\nfunction envelopeError(envelope: Record<string, unknown>, apiKey: string | null): string | null {\n\tconst parts: string[] = [];\n\tconst { error, errors } = envelope;\n\tif (typeof error === \"string\" && error.trim()) parts.push(error.trim());\n\telse if (error && typeof error === \"object\") parts.push(JSON.stringify(error));\n\tif (Array.isArray(errors) && errors.length > 0) parts.push(JSON.stringify(errors));\n\telse if (typeof errors === \"string\" && errors.trim()) parts.push(errors.trim());\n\tif (parts.length === 0) return null;\n\tfor (const key of [\"code\", \"error_code\"]) {\n\t\tconst code = envelope[key];\n\t\tif (typeof code === \"string\" && code.trim()) parts.push(`${key} ${code.trim()}`);\n\t\telse if (typeof code === \"number\") parts.push(`${key} ${code}`);\n\t}\n\treturn untrustedText(redactCredential(parts.join(\", \"), apiKey), 200);\n}\n\n// The envelope is validated strictly — every branch below throws — because a\n// shape this provider cannot read means the request was billed for something\n// unusable, and returning `{ answer: \"\", results: [] }` would report a paid\n// failure as \"the web had no answer\". That includes the two shapes that are JSON\n// but not a SERP: Bright Data's own error envelope, and an envelope with no\n// `organic` array at all. anysearch.ts rejects the equivalent shape the same way.\n// Individual organic entries are the one deliberate exception: a real SERP mixes\n// in entries with no link, and one of those must not throw away a page of results\n// that was already paid for.\nfunction parseSerpResponse(value: unknown, zone: string, apiKey: string | null): BrightDataSerpResponse {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow invalidResponse(zone, \"expected an object envelope\");\n\t}\n\tconst envelope = value as Record<string, unknown>;\n\tconst upstreamError = envelopeError(envelope, apiKey);\n\tif (upstreamError) {\n\t\tthrow invalidResponse(zone, `Bright Data reported an error instead of a SERP: ${upstreamError}`);\n\t}\n\tif (envelope.organic === undefined || envelope.organic === null) {\n\t\tthrow invalidResponse(\n\t\t\tzone,\n\t\t\t\"expected an organic array and the envelope carried none. A `serp` zone queried with brd_json=1 \" +\n\t\t\t\"returns { organic: [...] }; a zone of type `unblocker`, or a missing brd_json=1, is the usual cause\",\n\t\t);\n\t}\n\tif (!Array.isArray(envelope.organic)) throw invalidResponse(zone, \"expected organic array\");\n\tconst organic: BrightDataOrganicResult[] = [];\n\tfor (const [index, entry] of envelope.organic.entries()) {\n\t\tif (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n\t\t\tthrow invalidResponse(zone, `expected organic[${index}] object`);\n\t\t}\n\t\torganic.push(entry as BrightDataOrganicResult);\n\t}\n\treturn { organic };\n}\n\nfunction mapResults(\n\torganic: BrightDataOrganicResult[] | undefined,\n\tnumResults: number,\n\tfilters: DomainFilters,\n): SearchResponse[\"results\"] {\n\tif (!Array.isArray(organic)) return [];\n\tconst mapped: SearchResponse[\"results\"] = [];\n\tfor (const item of organic) {\n\t\tconst url = typeof item.link === \"string\" ? item.link.trim() : \"\";\n\t\tif (!url || !passesDomainFilters(url, filters)) continue;\n\t\tconst title = typeof item.title === \"string\" ? item.title.trim() : \"\";\n\t\tmapped.push({\n\t\t\ttitle: title || `Source ${mapped.length + 1}`,\n\t\t\turl,\n\t\t\tsnippet: typeof item.description === \"string\" ? item.description.replace(/\\s+/g, \" \").trim() : \"\",\n\t\t});\n\t\tif (mapped.length >= numResults) break;\n\t}\n\treturn mapped;\n}\n\n// A SERP zone returns ranked links, never a synthesized answer, so one is\n// assembled from the sources — the same shape brave.ts and searxng.ts produce.\nfunction buildAnswer(results: SearchResponse[\"results\"]): string {\n\treturn results\n\t\t.map((result) => result.snippet\n\t\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t\t: `Source: ${result.title} (${result.url})`)\n\t\t.join(\"\\n\\n\");\n}\n\n// Both halves are required: a token with no zone cannot make a request, and a\n// zone with no token cannot either. Availability therefore checks the config this\n// surface actually needs rather than merely a key, the way firecrawl.ts's\n// `isFirecrawlAvailable()` checks its required base URL. Reporting \"unavailable\"\n// for a half-finished setup keeps the incomplete case out of provider selection\n// instead of turning it into a failed search.\n//\n// It is also a pure predicate that cannot throw. Callers evaluate it outside\n// their error handling — `gemini-search.ts` before the per-provider try/catch,\n// `index.ts` in the uncaught `getProviderAvailability()` await on the `web_search`\n// path — so any throw from a malformed Bright Data setting or an unparseable\n// config file would break search for every other provider too. Misconfiguration\n// makes this provider unavailable here; the request path reports it in detail.\nexport function isBrightDataAvailable(): boolean {\n\ttry {\n\t\tif (getSerpZone() === null) return false;\n\t\treturn hasCredentialSource({\n\t\t\tprovider: \"Bright Data\",\n\t\t\tconfiguredValue: loadConfig().brightdataApiKey,\n\t\t\tenvironmentValue: process.env.BRIGHTDATA_API_KEY,\n\t\t});\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function searchWithBrightData(query: string, options: BrightDataSearchOptions = {}): Promise<SearchResponse> {\n\t// Zone before key: a config mistake must not spawn a `!command` credential\n\t// resolver, and must not reach a billable endpoint.\n\tconst zone = requireSerpZone();\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst filters = parseDomainFilter(options.domainFilter);\n\tconst searchQuery = buildSearchQuery(query, filters);\n\tconst body: Record<string, unknown> = {\n\t\turl: buildSerpUrl(searchQuery, numResults, options.recencyFilter),\n\t\tzone,\n\t\t// `format: \"raw\"` returns the proxied body verbatim; `data_format` selects\n\t\t// Bright Data's own parsing of it. `parsed_light` is the SERP shape —\n\t\t// { organic: [{ link, title, description }] } — and carries no page bodies.\n\t\tformat: \"raw\",\n\t\tdata_format: \"parsed_light\",\n\t};\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query: searchQuery });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(BRIGHTDATA_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Authorization\": `Bearer ${apiKey}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(body),\n\t\t\tsignal: requestSignal(options.signal),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\n\t// Every thrown message names the zone the request was billed against: with two\n\t// Bright Data zone types in play, \"which zone did I pay on\" is the first thing\n\t// a paid failure has to answer.\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = untrustedText(redactCredential(await response.text(), apiKey));\n\t\tthrow new Error(`Bright Data API error ${response.status} for zone ${zone}: ${errorText}`);\n\t}\n\n\t// The body is read as text before parsing on purpose. `format: \"raw\"` means a\n\t// 200 can still carry an upstream interstitial instead of SERP JSON, and a\n\t// bare parser error (\"Unexpected token <\") hides a request that was billed.\n\t// Quoting the body is the only way the user learns what they paid for.\n\tconst raw = await response.text();\n\tif (!raw.trim()) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Bright Data API returned empty response for zone ${zone}`);\n\t}\n\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = JSON.parse(raw);\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\t// The parser's own message is deliberately NOT quoted here. V8 embeds a short\n\t\t// window of the offending input in it (`Unexpected token 'x', \"xxxxxxxx-x\"...`),\n\t\t// and that window is a *prefix* of the body — so when the body starts with the\n\t\t// credential, `redactCredential` cannot match it: it replaces the whole key, and\n\t\t// a 10-character prefix is not the whole key. Redacting the detail half therefore\n\t\t// still printed 10 cleartext characters of the token. The detail also adds nothing\n\t\t// this message does not already carry: the wording names the failure and the body\n\t\t// below shows what arrived, filtered. Dropping it removes the leak by construction\n\t\t// rather than by pattern-matching.\n\t\tconst body = untrustedText(redactCredential(raw, apiKey));\n\t\tthrow new Error(`Bright Data API returned invalid JSON for zone ${zone}: ${body}`);\n\t}\n\n\tlet data: BrightDataSerpResponse;\n\ttry {\n\t\tdata = parseSerpResponse(rawData, zone, apiKey);\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow err;\n\t}\n\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = mapResults(data.organic, numResults, filters);\n\treturn { answer: buildAnswer(results), results };\n}\n"]}
1
+ {"version":3,"file":"brightdata.js","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/brightdata.ts"],"names":[],"mappings":"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","sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { activityMonitor } from \"./activity.ts\";\nimport type { SearchOptions, SearchResponse } from \"./perplexity.ts\";\nimport { hasCredentialSource, redactCredential, resolveCredential } from \"./credential-source.ts\";\nimport { getWebSearchConfigPath } from \"./utils.ts\";\n\nconst BRIGHTDATA_API_URL = \"https://api.brightdata.com/request\";\nconst CONFIG_PATH = getWebSearchConfigPath();\nconst SEARCH_TIMEOUT_MS = 60_000;\n\n// Bright Data proxies a real Google SERP through a provisioned \"zone\" and bills\n// per successful request against it. A SERP zone (Bright Data zone type `serp`)\n// and a Web Unlocker zone (type `unblocker`) are separate products with separate\n// prices, so the zone used for search is its own required setting and is never\n// guessed: the wrong zone is either an opaque 400 or a charge against the wrong\n// line of the invoice. Pricing: https://brightdata.com/pricing\nconst ZONE_PATTERN = /^[A-Za-z0-9_-]+$/;\n\n// Google's own time filter, passed straight through in the proxied URL. Unlike a\n// query-text hint this is an engine-side filter, so results outside the window\n// are not returned at all.\nconst RECENCY_TBS: Record<string, string> = {\n\tday: \"qdr:d\",\n\tweek: \"qdr:w\",\n\tmonth: \"qdr:m\",\n\tyear: \"qdr:y\",\n};\n\ninterface WebSearchConfig {\n\tbrightdataApiKey?: unknown;\n\tbrightdataSerpZone?: unknown;\n}\n\ninterface BrightDataOrganicResult {\n\tlink?: unknown;\n\ttitle?: unknown;\n\tdescription?: unknown;\n}\n\ninterface BrightDataSerpResponse {\n\torganic?: BrightDataOrganicResult[];\n}\n\ninterface BrightDataSearchOptions extends SearchOptions {\n\t// Accepted for parity with the other providers and deliberately ignored: a\n\t// SERP zone returns ranked links, never page bodies, so there is nothing to\n\t// return inline and `inlineContent` is never set.\n\tincludeContent?: boolean;\n}\n\nlet cachedConfig: WebSearchConfig | null = null;\n\n// `web-search.json` is a credential store: its own text is the secret. V8 quotes a\n// window of the source it choked on back inside the `JSON.parse` message — with a\n// short file, the whole file — so `{\"brightdataApiKey\": bd-real-token}` (quotes\n// forgotten around a pasted token) produces\n// `Unexpected token 'b', \"{\"brightdataApiKey\": bd-real-token}\" is not valid JSON`.\n// There is no credential to redact against at this point, because the credential is\n// what the file was being read for, so the parser's text is dropped entirely and only\n// its position is kept. That position is also the only part that cannot carry a\n// status-shaped phrase into `providerErrorStatus`.\n//\n// This is a deliberate divergence from `serpdive.ts:59-62`, `brave.ts:33-36`,\n// `anysearch.ts:48-51` and `firecrawl.ts:50-53`, which all quote the parser message\n// verbatim. They have the same leak; fixing it for every provider is a separate\n// change, and this module is not going to copy the bug forward to justify symmetry.\nfunction configParseDetail(err: unknown): string {\n\tconst position = errorMessage(err).match(/at position \\d+(?: \\(line \\d+ column \\d+\\))?/i);\n\treturn position ? `not valid JSON, ${position[0]}` : \"not valid JSON\";\n}\n\nfunction loadConfig(): WebSearchConfig {\n\tif (cachedConfig) return cachedConfig;\n\tif (!existsSync(CONFIG_PATH)) {\n\t\tcachedConfig = {};\n\t\treturn cachedConfig;\n\t}\n\n\tconst raw = readFileSync(CONFIG_PATH, \"utf-8\");\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = JSON.parse(raw);\n\t} catch (err) {\n\t\tthrow new Error(`Failed to parse ${CONFIG_PATH}: ${configParseDetail(err)}`);\n\t}\n\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\tthrow new Error(`Invalid config in ${CONFIG_PATH}: expected a JSON object`);\n\t}\n\tcachedConfig = parsed as WebSearchConfig;\n\treturn cachedConfig;\n}\n\nasync function getApiKey(signal?: AbortSignal): Promise<string | null> {\n\treturn resolveCredential({\n\t\tprovider: \"Bright Data\",\n\t\tconfiguredValue: loadConfig().brightdataApiKey,\n\t\tenvironmentValue: process.env.BRIGHTDATA_API_KEY,\n\t\tsignal,\n\t});\n}\n\nasync function requireApiKey(signal?: AbortSignal): Promise<string> {\n\tconst apiKey = await getApiKey(signal);\n\tif (!apiKey) {\n\t\tthrow new Error(\n\t\t\t\"Bright Data API key not found. Either:\\n\" +\n\t\t\t` 1. Create ${CONFIG_PATH} with { \"brightdataApiKey\": \"your-key\" }\\n` +\n\t\t\t\" 2. Set BRIGHTDATA_API_KEY environment variable\\n\" +\n\t\t\t\"Get a key at https://brightdata.com/cp/setting/users\",\n\t\t);\n\t}\n\treturn apiKey;\n}\n\n// A zone name is an account-scoped identifier, not a URL. Validating the charset\n// here keeps a stray value out of the request body, where Bright Data reports it\n// as a generic 400 that reads like a credential problem.\n//\n// Total by construction: an invalid zone is `null`, never a throw.\n// `isBrightDataAvailable()` reads this, and availability is evaluated outside its\n// callers' error handling — `gemini-search.ts` checks it before entering the\n// per-provider try/catch, and `index.ts` awaits `getProviderAvailability()` on the\n// `web_search` path with nothing around it. A throw here would therefore take\n// `web_search` down for Brave and OpenAI too, over one mistyped Bright Data\n// setting. The loud, actionable error belongs on the request path, in\n// `requireSerpZone()`, where only this provider is affected.\nfunction normalizeZone(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst trimmed = value.trim();\n\tif (!trimmed) return null;\n\treturn ZONE_PATTERN.test(trimmed) ? trimmed : null;\n}\n\ninterface ZoneSetting {\n\traw: string;\n\tlabel: string;\n}\n\n// Resolved by presence, not by validity: a `BRIGHTDATA_SERP_ZONE` that is set but\n// malformed must not silently hand the request to the config file's zone. The\n// setting the user actually filled in is the setting the error names.\nfunction serpZoneSetting(): ZoneSetting | null {\n\tconst fromEnv = process.env.BRIGHTDATA_SERP_ZONE;\n\tif (typeof fromEnv === \"string\" && fromEnv.trim()) {\n\t\treturn { raw: fromEnv.trim(), label: \"BRIGHTDATA_SERP_ZONE\" };\n\t}\n\tconst configured = loadConfig().brightdataSerpZone;\n\tif (typeof configured === \"string\" && configured.trim()) {\n\t\treturn { raw: configured.trim(), label: `brightdataSerpZone in ${CONFIG_PATH}` };\n\t}\n\treturn null;\n}\n\nfunction getSerpZone(): string | null {\n\tconst setting = serpZoneSetting();\n\treturn setting ? normalizeZone(setting.raw) : null;\n}\n\n// There is no safe default, and in particular no fallback to a Web Unlocker zone:\n// `serp` and `unblocker` are different Bright Data zone types, priced differently,\n// and an Unlocker zone does not return SERP JSON — substituting one buys a\n// confusing paid failure instead of a search. A missing or malformed SERP zone\n// fails loudly here, before anything billable happens.\nfunction requireSerpZone(): string {\n\tconst setting = serpZoneSetting();\n\tconst zone = setting ? normalizeZone(setting.raw) : null;\n\tif (zone) return zone;\n\tif (setting) {\n\t\tthrow new Error(\n\t\t\t`Bright Data SERP zone is invalid: ${setting.label} must be a zone name of letters, digits, \"-\", or \"_\" ` +\n\t\t\t`(got \"${untrustedText(setting.raw, 60)}\").\\n` +\n\t\t\t\"The zone must be of Bright Data type `serp`; a Web Unlocker zone (type `unblocker`) is a different product and does not return SERP JSON.\\n\" +\n\t\t\t\"Create or rename one at https://brightdata.com/cp/zones\",\n\t\t);\n\t}\n\tthrow new Error(\n\t\t\"Bright Data SERP zone is invalid or missing. Either:\\n\" +\n\t\t` 1. Create ${CONFIG_PATH} with { \"brightdataSerpZone\": \"your_serp_zone\" }\\n` +\n\t\t\" 2. Set BRIGHTDATA_SERP_ZONE environment variable\\n\" +\n\t\t\"The zone must be of Bright Data type `serp`; a Web Unlocker zone is a different product and does not return SERP JSON.\\n\" +\n\t\t\"Create one at https://brightdata.com/cp/zones\",\n\t);\n}\n\nfunction normalizeCount(value: number | undefined): number {\n\tif (typeof value !== \"number\" || !Number.isFinite(value)) return 5;\n\treturn Math.max(1, Math.min(Math.floor(value), 20));\n}\n\nfunction normalizeDomain(value: string): string | null {\n\tlet input = value.trim().toLowerCase();\n\tif (!input) return null;\n\tif (input.startsWith(\"-\")) input = input.slice(1).trim();\n\tif (!input) return null;\n\ttry {\n\t\tconst parsed = input.includes(\"://\") ? new URL(input) : new URL(`https://${input}`);\n\t\tinput = parsed.hostname;\n\t} catch {\n\t\tinput = input.split(\"/\")[0]?.split(\":\")[0] ?? \"\";\n\t}\n\tinput = input.replace(/^\\.+|\\.+$/g, \"\");\n\treturn /^[a-z0-9][a-z0-9.-]*\\.[a-z]{2,}$/i.test(input) ? input : null;\n}\n\ninterface DomainFilters {\n\tinclude: string[];\n\texclude: string[];\n}\n\nfunction parseDomainFilter(domainFilter: string[] | undefined): DomainFilters {\n\tconst filters: DomainFilters = { include: [], exclude: [] };\n\tif (!domainFilter?.length) return filters;\n\tfor (const raw of domainFilter) {\n\t\tconst domain = normalizeDomain(raw);\n\t\tif (!domain) continue;\n\t\tconst target = raw.trim().startsWith(\"-\") ? filters.exclude : filters.include;\n\t\tif (!target.includes(domain)) target.push(domain);\n\t}\n\treturn filters;\n}\n\n// Bright Data has no domain parameter, but the engine behind it is Google, so the\n// filter is expressed the way Google expresses it: as `site:` operators inside\n// the query. That asks the engine for the right pages instead of discarding the\n// wrong ones locally — the difference SERPdive documents as a limitation.\nfunction buildSearchQuery(query: string, filters: DomainFilters): string {\n\tconst parts = [query];\n\tif (filters.include.length === 1) {\n\t\tparts.push(`site:${filters.include[0]}`);\n\t} else if (filters.include.length > 1) {\n\t\tparts.push(filters.include.map((domain) => `site:${domain}`).join(\" OR \"));\n\t}\n\tfor (const domain of filters.exclude) {\n\t\tparts.push(`-site:${domain}`);\n\t}\n\treturn parts.join(\" \");\n}\n\nfunction buildSerpUrl(searchQuery: string, numResults: number, recencyFilter: SearchOptions[\"recencyFilter\"]): string {\n\tconst params = new URLSearchParams({ q: searchQuery });\n\t// One SERP request is billed once whatever `num` says, so asking for a little\n\t// headroom is free and leaves something to keep after local re-filtering.\n\tparams.set(\"num\", String(Math.min(numResults + 5, 20)));\n\tconst tbs = recencyFilter ? RECENCY_TBS[recencyFilter] : undefined;\n\tif (tbs) params.set(\"tbs\", tbs);\n\t// `brd_json=1` is what makes Bright Data return the SERP as JSON instead of\n\t// Google's HTML. Without it `data_format: \"parsed_light\"` has nothing to read.\n\tparams.set(\"brd_json\", \"1\");\n\treturn `https://www.google.com/search?${params.toString()}`;\n}\n\nfunction domainMatches(hostname: string, domain: string): boolean {\n\treturn hostname === domain || hostname.endsWith(`.${domain}`);\n}\n\n// `site:` narrows the SERP but does not guarantee it: Google still mixes in\n// related hosts, and an OR group is honoured loosely. The same filter is applied\n// again here so the contract holds on what is actually returned.\nfunction passesDomainFilters(url: string, filters: DomainFilters): boolean {\n\tif (filters.include.length === 0 && filters.exclude.length === 0) return true;\n\tlet hostname: string;\n\ttry {\n\t\thostname = new URL(url).hostname.toLowerCase();\n\t} catch {\n\t\treturn false;\n\t}\n\tif (filters.exclude.some((domain) => domainMatches(hostname, domain))) return false;\n\tif (filters.include.length === 0) return true;\n\treturn filters.include.some((domain) => domainMatches(hostname, domain));\n}\n\nfunction requestSignal(signal?: AbortSignal): AbortSignal {\n\tconst timeout = AbortSignal.timeout(SEARCH_TIMEOUT_MS);\n\treturn signal ? AbortSignal.any([signal, timeout]) : timeout;\n}\n\nfunction errorMessage(err: unknown): string {\n\treturn err instanceof Error ? err.message : String(err);\n}\n\n// Text that did not originate here — a proxied response body, a `JSON.parse`\n// message quoting that body, a config value — is quoted into Error messages, and\n// `gemini-search.ts` classifies routing failures by reading a status back out of\n// the message text (`providerErrorStatus`, /\\b(?:error|status|http)\\s+(\\d{3})\\b/).\n// A proxied Google interstitial that merely mentions \"Error 503\" would otherwise\n// be read as *our* status and retried as a transient failure, when what actually\n// happened is that a 200 was billed and is unusable. Status-shaped phrases in\n// quoted text are rewritten to `upstream <code>`: the number is still reported,\n// but only this module's own wording can name the status we received.\nconst STATUS_SHAPED_PATTERN = /\\b(?:error|status|http)[\\s:=-]{1,4}(\\d{3})\\b/gi;\n\n// `providerErrorStatus` is not the only thing that reads our message.\n// `classifyProviderError` also matches bare keyword phrases, and its branch order\n// decides which ones can reach us: `searchRouting.fallbackOn` accepts only\n// `transient`, `quota` and `network`, and of those three only the `quota` branch\n// (/rate limit|quota|too many requests/) runs BEFORE the `invalid-response` branch\n// that this module's own wording always triggers. So a billed 200 whose body reads\n// \"You have exceeded your rate limit\" would classify as `quota`, and with\n// `fallbackOn: [\"quota\"]` the user is charged, silently served the next provider's\n// answer, and shown no diagnostic — the failure mode this module exists to prevent.\n// `transient` and `network` sit after `invalid-response` and are unreachable for the\n// same reason; the test suite pins that ordering assumption rather than trusting it.\n//\n// The phrase is replaced rather than removed: the reader still learns the upstream\n// page mentioned a rate limit, but no substring of the replacement matches any\n// classifier branch (\"rate-limit\" is hyphenated, so /rate limit/ cannot match).\nconst QUOTA_SHAPED_PATTERN = /rate limit|quota|too many requests/gi;\n\n// The complete inventory of places foreign text is quoted into a message or a log\n// line, and what each one is required to apply. Adding a fifth means adding it here:\n//\n// | site | redactCredential | untrustedText |\n// | ----------------------------------------------- | ---------------- | ------------- |\n// | non-2xx response body | yes | yes (300) |\n// | invalid-JSON raw body | yes | yes (300) |\n// | Bright Data's own 200 error envelope | yes | yes (200) |\n// | transport/abort error from `fetch` | yes | n/a — see (a) |\n// | rejected zone value | n/a — see (b) | yes (60) |\n// | `JSON.parse` message on a response body | n/a — see (c) | n/a — see (c) |\n// | `JSON.parse` failure on `web-search.json` | n/a — see (c) | n/a — see (c) |\n//\n// (a) That message is generated locally by undici or by `AbortSignal`, never by the\n// proxied page, and the abort branch below matches on it; collapsing and\n// truncating it would buy nothing and could break that match.\n// (b) The zone is resolved *before* the credential on purpose, so that a config\n// mistake never spawns a `!command` resolver. There is therefore no key to redact\n// against yet, and the value being echoed is the user's own zone setting.\n// (c) Neither parser message is quoted at all, so neither needs a filter or a cap. V8\n// embeds a *prefix* of the offending input in its message, and `redactCredential`\n// substitutes whole values, so a prefix cannot be redacted out of it. Dropping the\n// message removes the leak by construction — see `configParseDetail` and the\n// `JSON.parse` catch on the response path.\n\n// Truncation happens BEFORE the rewrite, and the order is the whole point.\n// `STATUS_SHAPED_PATTERN` requires `(\\d{3})\\b`, so `error 5031` is deliberately left\n// alone — it is not a status. Sanitising first and slicing second let the cut land on\n// the 4th digit and hand back a freshly forged `error 503`, which\n// `gemini-search.ts`'s `providerErrorStatus` then reads as *our* status: a billed 200\n// classified `transient` and silently re-run on the next provider. Slicing first means\n// the rewrite always sees the exact text that will be quoted.\n//\n// The rewrite runs last and is therefore allowed to push the result a few characters\n// past `limit` (\"error 503\" → \"upstream 503\"). `limit` bounds how much upstream text is\n// quoted, not the final string length; a second `slice()` after the rewrite would\n// re-open exactly the hole this ordering closes.\nfunction untrustedText(text: string, limit = 300): string {\n\treturn text\n\t\t.replace(/\\s+/g, \" \")\n\t\t.trim()\n\t\t.slice(0, limit)\n\t\t.replace(STATUS_SHAPED_PATTERN, \"upstream $1\")\n\t\t.replace(QUOTA_SHAPED_PATTERN, \"upstream rate-limit notice\");\n}\n\nfunction invalidResponse(zone: string, message: string): Error {\n\treturn new Error(`Bright Data API returned invalid response for zone ${zone}: ${message}`);\n}\n\n// Bright Data reports some failures inside a normal HTTP 200 body — e.g.\n// `{\"error\":\"zone not found\",\"code\":\"zone_missing\"}` — because `format: \"raw\"`\n// means the HTTP layer describes the proxy hop, not the outcome.\n//\n// The envelope is upstream text, so it gets the same two-step treatment as every other\n// quoted body: `redactCredential` first (an upstream \"token <yours> is not valid for\n// this zone\" must not reprint the token), then `untrustedText`.\nfunction envelopeError(envelope: Record<string, unknown>, apiKey: string | null): string | null {\n\tconst parts: string[] = [];\n\tconst { error, errors } = envelope;\n\tif (typeof error === \"string\" && error.trim()) parts.push(error.trim());\n\telse if (error && typeof error === \"object\") parts.push(JSON.stringify(error));\n\tif (Array.isArray(errors) && errors.length > 0) parts.push(JSON.stringify(errors));\n\telse if (typeof errors === \"string\" && errors.trim()) parts.push(errors.trim());\n\tif (parts.length === 0) return null;\n\tfor (const key of [\"code\", \"error_code\"]) {\n\t\tconst code = envelope[key];\n\t\tif (typeof code === \"string\" && code.trim()) parts.push(`${key} ${code.trim()}`);\n\t\telse if (typeof code === \"number\") parts.push(`${key} ${code}`);\n\t}\n\treturn untrustedText(redactCredential(parts.join(\", \"), apiKey), 200);\n}\n\n// The envelope is validated strictly — every branch below throws — because a\n// shape this provider cannot read means the request was billed for something\n// unusable, and returning `{ answer: \"\", results: [] }` would report a paid\n// failure as \"the web had no answer\". That includes the two shapes that are JSON\n// but not a SERP: Bright Data's own error envelope, and an envelope with no\n// `organic` array at all. anysearch.ts rejects the equivalent shape the same way.\n// Individual organic entries are the one deliberate exception: a real SERP mixes\n// in entries with no link, and one of those must not throw away a page of results\n// that was already paid for.\nfunction parseSerpResponse(value: unknown, zone: string, apiKey: string | null): BrightDataSerpResponse {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow invalidResponse(zone, \"expected an object envelope\");\n\t}\n\tconst envelope = value as Record<string, unknown>;\n\tconst upstreamError = envelopeError(envelope, apiKey);\n\tif (upstreamError) {\n\t\tthrow invalidResponse(zone, `Bright Data reported an error instead of a SERP: ${upstreamError}`);\n\t}\n\tif (envelope.organic === undefined || envelope.organic === null) {\n\t\tthrow invalidResponse(\n\t\t\tzone,\n\t\t\t\"expected an organic array and the envelope carried none. A `serp` zone queried with brd_json=1 \" +\n\t\t\t\"returns { organic: [...] }; a zone of type `unblocker`, or a missing brd_json=1, is the usual cause\",\n\t\t);\n\t}\n\tif (!Array.isArray(envelope.organic)) throw invalidResponse(zone, \"expected organic array\");\n\tconst organic: BrightDataOrganicResult[] = [];\n\tfor (const [index, entry] of envelope.organic.entries()) {\n\t\tif (!entry || typeof entry !== \"object\" || Array.isArray(entry)) {\n\t\t\tthrow invalidResponse(zone, `expected organic[${index}] object`);\n\t\t}\n\t\torganic.push(entry as BrightDataOrganicResult);\n\t}\n\treturn { organic };\n}\n\nfunction mapResults(\n\torganic: BrightDataOrganicResult[] | undefined,\n\tnumResults: number,\n\tfilters: DomainFilters,\n): SearchResponse[\"results\"] {\n\tif (!Array.isArray(organic)) return [];\n\tconst mapped: SearchResponse[\"results\"] = [];\n\tfor (const item of organic) {\n\t\tconst url = typeof item.link === \"string\" ? item.link.trim() : \"\";\n\t\tif (!url || !passesDomainFilters(url, filters)) continue;\n\t\tconst title = typeof item.title === \"string\" ? item.title.trim() : \"\";\n\t\tmapped.push({\n\t\t\ttitle: title || `Source ${mapped.length + 1}`,\n\t\t\turl,\n\t\t\tsnippet: typeof item.description === \"string\" ? item.description.replace(/\\s+/g, \" \").trim() : \"\",\n\t\t});\n\t\tif (mapped.length >= numResults) break;\n\t}\n\treturn mapped;\n}\n\n// A SERP zone returns ranked links, never a synthesized answer, so one is\n// assembled from the sources — the same shape brave.ts and searxng.ts produce.\nfunction buildAnswer(results: SearchResponse[\"results\"]): string {\n\treturn results\n\t\t.map((result) => result.snippet\n\t\t\t? `${result.snippet}\\nSource: ${result.title} (${result.url})`\n\t\t\t: `Source: ${result.title} (${result.url})`)\n\t\t.join(\"\\n\\n\");\n}\n\n// Both halves are required: a token with no zone cannot make a request, and a\n// zone with no token cannot either. Availability therefore checks the config this\n// surface actually needs rather than merely a key, the way firecrawl.ts's\n// `isFirecrawlAvailable()` checks its required base URL. Reporting \"unavailable\"\n// for a half-finished setup keeps the incomplete case out of provider selection\n// instead of turning it into a failed search.\n//\n// It is also a pure predicate that cannot throw. Callers evaluate it outside\n// their error handling — `gemini-search.ts` before the per-provider try/catch,\n// `index.ts` in the uncaught `getProviderAvailability()` await on the `web_search`\n// path — so any throw from a malformed Bright Data setting or an unparseable\n// config file would break search for every other provider too. Misconfiguration\n// makes this provider unavailable here; the request path reports it in detail.\nexport function isBrightDataAvailable(): boolean {\n\ttry {\n\t\tif (getSerpZone() === null) return false;\n\t\treturn hasCredentialSource({\n\t\t\tprovider: \"Bright Data\",\n\t\t\tconfiguredValue: loadConfig().brightdataApiKey,\n\t\t\tenvironmentValue: process.env.BRIGHTDATA_API_KEY,\n\t\t});\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function searchWithBrightData(query: string, options: BrightDataSearchOptions = {}): Promise<SearchResponse> {\n\t// Zone before key: a config mistake must not spawn a `!command` credential\n\t// resolver, and must not reach a billable endpoint.\n\tconst zone = requireSerpZone();\n\tconst apiKey = await requireApiKey(options.signal);\n\tconst numResults = normalizeCount(options.numResults);\n\tconst filters = parseDomainFilter(options.domainFilter);\n\tconst searchQuery = buildSearchQuery(query, filters);\n\tconst body: Record<string, unknown> = {\n\t\turl: buildSerpUrl(searchQuery, numResults, options.recencyFilter),\n\t\tzone,\n\t\t// `format: \"raw\"` returns the proxied body verbatim; `data_format` selects\n\t\t// Bright Data's own parsing of it. `parsed_light` is the SERP shape —\n\t\t// { organic: [{ link, title, description }] } — and carries no page bodies.\n\t\tformat: \"raw\",\n\t\tdata_format: \"parsed_light\",\n\t};\n\n\tconst activityId = activityMonitor.logStart({ type: \"api\", query: searchQuery });\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(BRIGHTDATA_API_URL, {\n\t\t\tmethod: \"POST\",\n\t\t\theaders: {\n\t\t\t\t\"Authorization\": `Bearer ${apiKey}`,\n\t\t\t\t\"Content-Type\": \"application/json\",\n\t\t\t},\n\t\t\tbody: JSON.stringify(body),\n\t\t\tsignal: requestSignal(options.signal),\n\t\t});\n\t} catch (err) {\n\t\tconst message = errorMessage(err);\n\t\tconst redactedMessage = redactCredential(message, apiKey);\n\t\tif (redactedMessage.toLowerCase().includes(\"abort\")) activityMonitor.logComplete(activityId, 0);\n\t\telse activityMonitor.logError(activityId, redactedMessage);\n\t\tif (redactedMessage === message) throw err;\n\t\tconst redactedError = new Error(redactedMessage);\n\t\tif (err instanceof Error) redactedError.name = err.name;\n\t\tthrow redactedError;\n\t}\n\n\t// Every thrown message names the zone the request was billed against: with two\n\t// Bright Data zone types in play, \"which zone did I pay on\" is the first thing\n\t// a paid failure has to answer.\n\tif (!response.ok) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tconst errorText = untrustedText(redactCredential(await response.text(), apiKey));\n\t\tthrow new Error(`Bright Data API error ${response.status} for zone ${zone}: ${errorText}`);\n\t}\n\n\t// The body is read as text before parsing on purpose. `format: \"raw\"` means a\n\t// 200 can still carry an upstream interstitial instead of SERP JSON, and a\n\t// bare parser error (\"Unexpected token <\") hides a request that was billed.\n\t// Quoting the body is the only way the user learns what they paid for.\n\tconst raw = await response.text();\n\tif (!raw.trim()) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow new Error(`Bright Data API returned empty response for zone ${zone}`);\n\t}\n\n\tlet rawData: unknown;\n\ttry {\n\t\trawData = JSON.parse(raw);\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\t// The parser's own message is deliberately NOT quoted here. V8 embeds a short\n\t\t// window of the offending input in it (`Unexpected token 'x', \"xxxxxxxx-x\"...`),\n\t\t// and that window is a *prefix* of the body — so when the body starts with the\n\t\t// credential, `redactCredential` cannot match it: it replaces the whole key, and\n\t\t// a 10-character prefix is not the whole key. Redacting the detail half therefore\n\t\t// still printed 10 cleartext characters of the token. The detail also adds nothing\n\t\t// this message does not already carry: the wording names the failure and the body\n\t\t// below shows what arrived, filtered. Dropping it removes the leak by construction\n\t\t// rather than by pattern-matching.\n\t\tconst body = untrustedText(redactCredential(raw, apiKey));\n\t\tthrow new Error(`Bright Data API returned invalid JSON for zone ${zone}: ${body}`);\n\t}\n\n\tlet data: BrightDataSerpResponse;\n\ttry {\n\t\tdata = parseSerpResponse(rawData, zone, apiKey);\n\t} catch (err) {\n\t\tactivityMonitor.logComplete(activityId, response.status);\n\t\tthrow err;\n\t}\n\n\tactivityMonitor.logComplete(activityId, response.status);\n\tconst results = mapResults(data.organic, numResults, filters);\n\treturn { answer: buildAnswer(results), results };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"chrome-cookies.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/chrome-cookies.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAgD/C,wBAAgB,6BAA6B,IAAI,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAgB,8BAA8B,IAAI,MAAM,GAAG,IAAI,CAE9D;AAED,wBAAsB,gBAAgB,CACrC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACxD,OAAO,CAAC;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CAQ5D;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,CAAA;CAAE,GAClJ,OAAO,CAAC;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAiInF","sourcesContent":["import { execFile } from \"node:child_process\";\nimport { pbkdf2Sync, createDecipheriv } from \"node:crypto\";\nimport { copyFileSync, existsSync, mkdtempSync, readdirSync, realpathSync, rmSync } from \"node:fs\";\nimport { tmpdir, homedir } from \"node:os\";\nimport { isAbsolute, join, sep } from \"node:path\";\nimport { isBrowserCookieAccessAllowed } from \"./gemini-web-config.ts\";\n\nexport type CookieMap = Record<string, string>;\n\ninterface BrowserConfig {\n\tname: string;\n\tbaseDir: string;\n\tkeychainService?: string;\n\tkeychainAccount?: string;\n\tsecretToolApp?: string;\n}\n\ntype SqliteRow = Record<string, unknown>;\ntype SqliteFailure = \"unavailable\" | \"query\";\n\ninterface BrowserCookieEntry {\n\tname: string;\n\tvalue: string;\n\tpath: string;\n}\n\nconst GOOGLE_ORIGINS = [\n\t\"https://gemini.google.com\",\n\t\"https://accounts.google.com\",\n\t\"https://www.google.com\",\n];\n\nconst ALL_COOKIE_NAMES = new Set([\n\t\"__Secure-1PSID\", \"__Secure-1PSIDTS\", \"__Secure-1PSIDCC\", \"__Secure-1PAPISID\", \"NID\", \"AEC\", \"SOCS\",\n\t\"__Secure-BUCKET\", \"__Secure-ENID\", \"SID\", \"HSID\", \"SSID\", \"APISID\", \"SAPISID\", \"__Secure-3PSID\",\n\t\"__Secure-3PSIDTS\", \"__Secure-3PAPISID\", \"SIDCC\",\n]);\n\nconst MACOS_BROWSER_CONFIGS: BrowserConfig[] = [\n\t{ name: \"Helium\", baseDir: \"Library/Application Support/net.imput.helium\", keychainService: \"Helium Storage Key\", keychainAccount: \"Helium\" },\n\t{ name: \"Chrome\", baseDir: \"Library/Application Support/Google/Chrome\", keychainService: \"Chrome Safe Storage\", keychainAccount: \"Chrome\" },\n\t{ name: \"Brave\", baseDir: \"Library/Application Support/BraveSoftware/Brave-Browser\", keychainService: \"Brave Safe Storage\", keychainAccount: \"Brave\" },\n\t{ name: \"Arc\", baseDir: \"Library/Application Support/Arc/User Data\", keychainService: \"Arc Safe Storage\", keychainAccount: \"Arc\" },\n];\n\nconst LINUX_BROWSER_CONFIGS: BrowserConfig[] = [\n\t{ name: \"Chromium\", baseDir: \".config/chromium\", secretToolApp: \"chromium\" },\n\t{ name: \"Chrome\", baseDir: \".config/google-chrome\", secretToolApp: \"chrome\" },\n];\n\nconst browserPasswordCache = new Map<string, Promise<string | null>>();\nlet lastCookieDiagnostic: string | null = null;\nlet sqliteModule: typeof import(\"node:sqlite\") | null = null;\nlet sqliteImportAttempted = false;\n\nexport function getLastGoogleCookieDiagnostic(): string | null {\n\treturn lastCookieDiagnostic;\n}\n\nexport function getLastBrowserCookieDiagnostic(): string | null {\n\treturn lastCookieDiagnostic;\n}\n\nexport async function getGoogleCookies(\n\toptions?: { profile?: string; requiredCookies?: string[] },\n): Promise<{ cookies: CookieMap; warnings: string[] } | null> {\n\treturn getBrowserCookiesForHosts({\n\t\thosts: GOOGLE_ORIGINS.map((origin) => new URL(origin).hostname),\n\t\tprofile: options?.profile,\n\t\trequiredCookies: options?.requiredCookies,\n\t\tcookieNames: ALL_COOKIE_NAMES,\n\t\trequiredLabel: \"Gemini\",\n\t});\n}\n\nexport async function getBrowserCookiesForHosts(\n\toptions: { hosts: string[]; profile?: string; requiredCookies?: string[]; cookieNames?: Iterable<string>; requiredLabel?: string; requestUrl?: URL },\n): Promise<{ cookies: CookieMap; warnings: string[]; cookieHeader?: string } | null> {\n\tlastCookieDiagnostic = null;\n\tif (!isBrowserCookieAccessAllowed()) {\n\t\tlastCookieDiagnostic = \"Browser cookie access is disabled; enable allowBrowserCookies to use browser cookies.\";\n\t\treturn null;\n\t}\n\n\tconst currentPlatform = process.platform;\n\tconst configs = currentPlatform === \"darwin\" ? MACOS_BROWSER_CONFIGS : currentPlatform === \"linux\" ? LINUX_BROWSER_CONFIGS : [];\n\tif (configs.length === 0) {\n\t\tlastCookieDiagnostic = \"Chromium cookie extraction is unsupported on this platform.\";\n\t\treturn null;\n\t}\n\n\tconst warningSet = new Set<string>();\n\tconst rawProfile = typeof options.profile === \"string\" ? options.profile.trim() : \"\";\n\tconst requestedProfile = normalizeProfileName(options.profile);\n\tif (rawProfile && !requestedProfile) {\n\t\tlastCookieDiagnostic = \"Configured Chromium profile must be a profile directory name, not a path.\";\n\t\treturn null;\n\t}\n\tconst requiredCookies = normalizeCookieNames(options.requiredCookies);\n\tconst cookieNames = normalizeCookieNames(options.cookieNames ? [...options.cookieNames] : undefined);\n\tconst hosts = normalizeHosts(options.hosts);\n\tif (hosts.length === 0) {\n\t\tlastCookieDiagnostic = \"No valid cookie hosts were requested.\";\n\t\treturn null;\n\t}\n\tconst home = homedir();\n\tlet sawCookieDatabase = false;\n\tlet sawRequiredCookies = false;\n\tlet sawAnyHostCookie = false;\n\tlet sawBackendFailure: SqliteFailure | undefined;\n\tlet sawUnsafeProfilePath = false;\n\n\tfor (const config of configs) {\n\t\tconst profiles = requestedProfile ? [requestedProfile] : listBrowserProfiles(home, config);\n\t\tfor (const profile of profiles) {\n\t\t\tconst profilePath = resolveProfilePath(home, config, profile);\n\t\t\tif (profilePath === \"outside-root\") {\n\t\t\t\tsawUnsafeProfilePath = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!profilePath) continue;\n\t\t\tconst cookiesPath = join(profilePath, \"Cookies\");\n\t\t\tsawCookieDatabase = true;\n\n\t\t\tconst tempDir = mkdtempSync(join(tmpdir(), \"pi-chrome-cookies-\"));\n\t\t\ttry {\n\t\t\t\tconst tempDb = join(tempDir, \"Cookies\");\n\t\t\t\tcopyFileSync(cookiesPath, tempDb);\n\t\t\t\tcopySidecar(cookiesPath, tempDb, \"-wal\");\n\t\t\t\tcopySidecar(cookiesPath, tempDb, \"-shm\");\n\n\t\t\t\tif (requiredCookies?.length) {\n\t\t\t\t\tconst preflight = await hasCookieNames(tempDb, hosts, requiredCookies);\n\t\t\t\t\tif (preflight.failure) sawBackendFailure = preflight.failure;\n\t\t\t\t\tif (!preflight.present) continue;\n\t\t\t\t\tsawRequiredCookies = true;\n\t\t\t\t}\n\n\t\t\t\tconst password = await readBrowserPassword(config, currentPlatform);\n\t\t\t\tif (!password) {\n\t\t\t\t\twarningSet.add(`Could not read ${config.name} cookie encryption password`);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst key = pbkdf2Sync(password, \"saltysalt\", currentPlatform === \"darwin\" ? 1003 : 1, 16, \"sha1\");\n\t\t\t\tconst metaVersion = await readMetaVersion(tempDb);\n\t\t\t\tif (metaVersion.failure) sawBackendFailure = metaVersion.failure;\n\t\t\t\tif (metaVersion.value === null) continue;\n\t\t\t\tconst rowsResult = await queryCookieRows(tempDb, hosts, cookieNames ?? null, Boolean(options.requestUrl));\n\t\t\t\tif (rowsResult.status === \"failure\") {\n\t\t\t\t\tsawBackendFailure = rowsResult.failure;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst entries: BrowserCookieEntry[] = [];\n\t\t\t\tconst cookies: CookieMap = {};\n\t\t\t\tfor (const row of rowsResult.rows) {\n\t\t\t\t\tconst name = typeof row.name === \"string\" ? row.name : \"\";\n\t\t\t\t\tif (!name) continue;\n\t\t\t\t\tlet value = typeof row.value === \"string\" && row.value.length > 0 ? row.value : null;\n\t\t\t\t\tif (!value && typeof row.encrypted_value_hex === \"string\" && /^[0-9a-f]*$/i.test(row.encrypted_value_hex)) {\n\t\t\t\t\t\tvalue = decryptCookieValue(Buffer.from(row.encrypted_value_hex, \"hex\"), key, metaVersion.value >= 24);\n\t\t\t\t\t}\n\t\t\t\t\tif (!value) continue;\n\t\t\t\t\tconst path = typeof row.path === \"string\" && row.path.startsWith(\"/\") ? row.path : \"/\";\n\t\t\t\t\tif (options.requestUrl && !pathMatches(options.requestUrl.pathname || \"/\", path)) continue;\n\t\t\t\t\tentries.push({ name, value, path });\n\t\t\t\t\tif (!cookies[name]) cookies[name] = value;\n\t\t\t\t}\n\n\t\t\t\tif (entries.length > 0) sawAnyHostCookie = true;\n\t\t\t\tif (requiredCookies?.length && !requiredCookies.every((name) => Boolean(cookies[name]))) continue;\n\t\t\t\tif (entries.length === 0) continue;\n\t\t\t\treturn {\n\t\t\t\t\tcookies,\n\t\t\t\t\twarnings: [...warningSet],\n\t\t\t\t\t...(options.requestUrl ? { cookieHeader: buildCookieHeader(entries) } : {}),\n\t\t\t\t};\n\t\t\t} finally {\n\t\t\t\trmSync(tempDir, { recursive: true, force: true });\n\t\t\t}\n\t\t}\n\t}\n\n\tif (sawBackendFailure === \"unavailable\") {\n\t\tlastCookieDiagnostic = \"SQLite backend unavailable: install sqlite3 or use a runtime with SQLite support.\";\n\t} else if (sawBackendFailure === \"query\") {\n\t\tlastCookieDiagnostic = \"SQLite query failed while reading the copied Chromium cookie database.\";\n\t} else if (sawUnsafeProfilePath) {\n\t\tlastCookieDiagnostic = \"Configured Chromium profile must resolve inside the browser profile root.\";\n\t} else if (!sawCookieDatabase) {\n\t\tlastCookieDiagnostic = requestedProfile\n\t\t\t? `Chromium profile '${requestedProfile}' does not contain a cookie database.`\n\t\t\t: \"No detected Chromium profile contains a cookie database.\";\n\t} else if (requiredCookies?.length && !sawRequiredCookies) {\n\t\tlastCookieDiagnostic = `No detected Chromium profile contains the required ${options.requiredLabel ?? \"browser\"} cookies.`;\n\t} else if (!sawAnyHostCookie) {\n\t\tlastCookieDiagnostic = options.requestUrl\n\t\t\t? \"No detected Chromium profile contains cookies for the requested URL.\"\n\t\t\t: \"No detected Chromium profile contains cookies for the requested host.\";\n\t} else if (warningSet.size > 0) {\n\t\tlastCookieDiagnostic = [...warningSet][0];\n\t} else {\n\t\tlastCookieDiagnostic = \"Required Gemini cookies were not available or could not be decrypted.\";\n\t}\n\treturn null;\n}\n\nfunction normalizeProfileName(value: string | undefined): string | undefined {\n\tif (typeof value !== \"string\") return undefined;\n\tconst normalized = value.trim();\n\tif (!normalized) return undefined;\n\tif (isAbsolute(normalized) || normalized === \".\" || normalized === \"..\" || normalized.includes(\"/\") || normalized.includes(\"\\\\\")) {\n\t\treturn undefined;\n\t}\n\treturn normalized;\n}\n\nfunction resolveProfilePath(home: string, config: BrowserConfig, profile: string): string | \"outside-root\" | null {\n\tconst basePath = join(home, config.baseDir);\n\tconst profilePath = join(basePath, profile);\n\tconst cookiesPath = join(profilePath, \"Cookies\");\n\tif (!existsSync(cookiesPath)) return null;\n\ttry {\n\t\tconst baseRealPath = realpathSync(basePath);\n\t\tconst profileRealPath = realpathSync(profilePath);\n\t\tif (profileRealPath !== baseRealPath && !profileRealPath.startsWith(`${baseRealPath}${sep}`)) return \"outside-root\";\n\t\treturn profileRealPath;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction normalizeCookieNames(names: string[] | undefined): string[] | undefined {\n\tif (!names?.length) return undefined;\n\tconst normalized = names.filter((name): name is string => typeof name === \"string\").map((name) => name.trim()).filter(Boolean);\n\treturn normalized.length > 0 ? [...new Set(normalized)] : undefined;\n}\n\nfunction normalizeHosts(hosts: string[]): string[] {\n\treturn [...new Set(hosts.map(host => host.trim().toLowerCase().replace(/^\\[|\\]$/g, \"\").replace(/\\.$/, \"\")).filter(Boolean))];\n}\n\nfunction listBrowserProfiles(home: string, config: BrowserConfig): string[] {\n\tconst basePath = join(home, config.baseDir);\n\tif (!existsSync(basePath)) return [\"Default\"];\n\tconst profiles = new Set<string>();\n\ttry {\n\t\tfor (const entry of readdirSync(basePath, { withFileTypes: true })) {\n\t\t\tif (entry.isDirectory() && existsSync(join(basePath, entry.name, \"Cookies\"))) profiles.add(entry.name);\n\t\t}\n\t} catch {\n\t}\n\tif (profiles.size === 0) return [\"Default\"];\n\treturn [...profiles].sort(compareProfileNames);\n}\n\nfunction compareProfileNames(a: string, b: string): number {\n\tconst key = (name: string): [number, number] => {\n\t\tif (name === \"Default\") return [0, 0];\n\t\tconst profile = /^Profile\\s+(\\d+)$/i.exec(name);\n\t\tif (profile) return [1, Number(profile[1])];\n\t\tconst person = /^Person\\s+(\\d+)$/i.exec(name);\n\t\tif (person) return [2, Number(person[1])];\n\t\treturn [3, Number.MAX_SAFE_INTEGER];\n\t};\n\tconst [ap, ai] = key(a);\n\tconst [bp, bi] = key(b);\n\treturn ap - bp || ai - bi || a.localeCompare(b, undefined, { sensitivity: \"base\", numeric: true });\n}\n\nfunction decryptCookieValue(encrypted: Uint8Array, key: Buffer, stripHash: boolean): string | null {\n\tconst buf = Buffer.from(encrypted);\n\tif (buf.length < 3 || !/^v\\d\\d$/.test(buf.subarray(0, 3).toString(\"utf8\"))) return null;\n\tconst ciphertext = buf.subarray(3);\n\tif (!ciphertext.length) return \"\";\n\ttry {\n\t\tconst decipher = createDecipheriv(\"aes-128-cbc\", key, Buffer.alloc(16, 0x20));\n\t\tdecipher.setAutoPadding(false);\n\t\tconst unpadded = removePkcs7Padding(Buffer.concat([decipher.update(ciphertext), decipher.final()]));\n\t\tconst bytes = stripHash && unpadded.length >= 32 ? unpadded.subarray(32) : unpadded;\n\t\tconst decoded = new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes);\n\t\tlet i = 0;\n\t\twhile (i < decoded.length && decoded.charCodeAt(i) < 0x20) i++;\n\t\treturn decoded.slice(i);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction removePkcs7Padding(buf: Buffer): Buffer {\n\tif (!buf.length) return buf;\n\tconst padding = buf[buf.length - 1];\n\treturn !padding || padding > 16 ? buf : buf.subarray(0, buf.length - padding);\n}\n\nfunction readBrowserPassword(config: BrowserConfig, currentPlatform: typeof process.platform): Promise<string | null> {\n\tconst cacheKey = `${currentPlatform}:${config.name}`;\n\tconst cached = browserPasswordCache.get(cacheKey);\n\tif (cached) return cached;\n\tconst passwordResult = currentPlatform === \"darwin\"\n\t\t? config.keychainAccount && config.keychainService\n\t\t\t? readKeychainPassword(config.keychainAccount, config.keychainService).then(password => ({ password, cacheable: Boolean(password) }))\n\t\t\t: Promise.resolve({ password: null, cacheable: false })\n\t\t: currentPlatform === \"linux\"\n\t\t\t? readLinuxPassword(config.secretToolApp)\n\t\t\t: Promise.resolve({ password: null, cacheable: false });\n\tconst passwordPromise = passwordResult.then(({ password, cacheable }) => {\n\t\tif (!cacheable) browserPasswordCache.delete(cacheKey);\n\t\treturn password;\n\t}, (error) => {\n\t\tbrowserPasswordCache.delete(cacheKey);\n\t\tthrow error;\n\t});\n\tbrowserPasswordCache.set(cacheKey, passwordPromise);\n\treturn passwordPromise;\n}\n\nfunction readKeychainPassword(account: string, service: string): Promise<string | null> {\n\treturn new Promise((resolve) => {\n\t\texecFile(\"security\", [\"find-generic-password\", \"-w\", \"-a\", account, \"-s\", service], { timeout: 5000 }, (err, stdout) => {\n\t\t\tif (err) { resolve(null); return; }\n\t\t\tresolve(stdout.trim() || null);\n\t\t});\n\t});\n}\n\nfunction readLinuxPassword(secretToolApp: string | undefined): Promise<{ password: string; cacheable: boolean }> {\n\tif (!secretToolApp) return Promise.resolve({ password: \"peanuts\", cacheable: true });\n\treturn new Promise((resolve) => {\n\t\texecFile(\"secret-tool\", [\"lookup\", \"application\", secretToolApp], { timeout: 5000 }, (err, stdout) => {\n\t\t\tif (err) { resolve({ password: \"peanuts\", cacheable: false }); return; }\n\t\t\tconst password = stdout.trim();\n\t\t\tresolve(password ? { password, cacheable: true } : { password: \"peanuts\", cacheable: false });\n\t\t});\n\t});\n}\n\nasync function importSqlite(): Promise<typeof import(\"node:sqlite\") | null> {\n\tif (process.env.PI_WEB_ACCESS_DISABLE_NODE_SQLITE === \"1\") return null;\n\tif (sqliteImportAttempted) return sqliteModule;\n\tsqliteImportAttempted = true;\n\tconst orig = process.emitWarning.bind(process);\n\tprocess.emitWarning = ((warning: string | Error, ...args: unknown[]) => {\n\t\tconst msg = typeof warning === \"string\" ? warning : warning?.message ?? \"\";\n\t\tif (msg.includes(\"SQLite is an experimental feature\")) return;\n\t\treturn (orig as Function)(warning, ...args);\n\t}) as typeof process.emitWarning;\n\ttry {\n\t\tsqliteModule = await import(\"node:sqlite\");\n\t} catch {\n\t\tsqliteModule = null;\n\t} finally {\n\t\tprocess.emitWarning = orig;\n\t}\n\treturn sqliteModule;\n}\n\ntype QueryResult =\n\t| { status: \"success\"; rows: SqliteRow[] }\n\t| { status: \"failure\"; failure: SqliteFailure };\n\nasync function runSqliteQuery(dbPath: string, sql: string): Promise<QueryResult> {\n\tconst sqlite = await importSqlite();\n\tlet queryFailed = false;\n\tif (sqlite) {\n\t\ttry {\n\t\t\tconst db = new sqlite.DatabaseSync(dbPath, { readOnly: true });\n\t\t\ttry {\n\t\t\t\treturn { status: \"success\", rows: db.prepare(sql).all() as SqliteRow[] };\n\t\t\t} finally {\n\t\t\t\tdb.close();\n\t\t\t}\n\t\t} catch {\n\t\t\tqueryFailed = true;\n\t\t}\n\t}\n\n\tconst cli = await runSqliteCli(dbPath, sql);\n\tif (cli.status === \"success\") return cli;\n\tif (cli.failure === \"query\") queryFailed = true;\n\tconst python = await runPythonSqlite(dbPath, sql);\n\tif (python.status === \"success\") return python;\n\tif (python.failure === \"query\") queryFailed = true;\n\treturn { status: \"failure\", failure: queryFailed ? \"query\" : \"unavailable\" };\n}\n\nfunction runSqliteCli(dbPath: string, sql: string): Promise<QueryResult> {\n\treturn new Promise((resolve) => {\n\t\texecFile(\"sqlite3\", [\"-readonly\", \"-json\", dbPath, sql], { timeout: 5000, maxBuffer: 1024 * 1024 }, (err, stdout) => {\n\t\t\tif (err) { resolve({ status: \"failure\", failure: err.code === \"ENOENT\" ? \"unavailable\" : \"query\" }); return; }\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(stdout || \"[]\");\n\t\t\t\tresolve(Array.isArray(parsed) ? { status: \"success\", rows: parsed as SqliteRow[] } : { status: \"failure\", failure: \"query\" });\n\t\t\t} catch {\n\t\t\t\tresolve({ status: \"failure\", failure: \"query\" });\n\t\t\t}\n\t\t});\n\t});\n}\n\nfunction runPythonSqlite(dbPath: string, sql: string): Promise<QueryResult> {\n\tconst script = \"import json,sqlite3,sys\\ntry:\\n c=sqlite3.connect('file:'+sys.argv[1]+'?mode=ro',uri=True)\\n c.row_factory=sqlite3.Row\\n print(json.dumps([dict(r) for r in c.execute(sys.argv[2]).fetchall()]))\\nexcept Exception:\\n sys.exit(1)\";\n\treturn new Promise((resolve) => {\n\t\texecFile(\"python3\", [\"-c\", script, dbPath, sql], { timeout: 5000, maxBuffer: 1024 * 1024 }, (err, stdout) => {\n\t\t\tif (err) { resolve({ status: \"failure\", failure: err.code === \"ENOENT\" ? \"unavailable\" : \"query\" }); return; }\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(stdout || \"[]\");\n\t\t\t\tresolve(Array.isArray(parsed) ? { status: \"success\", rows: parsed as SqliteRow[] } : { status: \"failure\", failure: \"query\" });\n\t\t\t} catch {\n\t\t\t\tresolve({ status: \"failure\", failure: \"query\" });\n\t\t\t}\n\t\t});\n\t});\n}\n\nasync function readMetaVersion(dbPath: string): Promise<{ value: number | null; failure?: SqliteFailure }> {\n\tconst result = await runSqliteQuery(dbPath, \"SELECT value FROM meta WHERE key = 'version'\");\n\tif (result.status === \"failure\") {\n\t\treturn result.failure === \"unavailable\"\n\t\t\t? { value: null, failure: result.failure }\n\t\t\t: { value: 0 };\n\t}\n\tconst value = result.rows[0]?.value;\n\tif (typeof value === \"number\") return { value: Math.floor(value) };\n\tif (typeof value === \"string\") return { value: parseInt(value, 10) || 0 };\n\treturn { value: 0 };\n}\n\nasync function hasCookieNames(dbPath: string, hosts: string[], names: string[]): Promise<{ present: boolean; failure?: SqliteFailure }> {\n\tconst result = await runSqliteQuery(dbPath, `SELECT DISTINCT name FROM cookies WHERE ${buildCookieWhere(hosts, names)}`);\n\tif (result.status === \"failure\") return { present: false, failure: result.failure };\n\tconst present = new Set(result.rows.map((row) => typeof row.name === \"string\" ? row.name : \"\"));\n\treturn { present: names.every((name) => present.has(name)) };\n}\n\nasync function queryCookieRows(dbPath: string, hosts: string[], names: Iterable<string> | null, filterExpired: boolean): Promise<QueryResult> {\n\tconst columns = await readCookieColumns(dbPath);\n\tif (columns.status === \"failure\") return columns;\n\tconst pathExpr = columns.columns.has(\"path\") ? \"path\" : \"'/' AS path\";\n\tconst expiresExpr = columns.columns.has(\"expires_utc\") ? \"expires_utc\" : \"0 AS expires_utc\";\n\tconst expiryFilter = filterExpired && columns.columns.has(\"expires_utc\") ? ` AND (expires_utc = 0 OR expires_utc > ${chromeExpiryNowMicros()})` : \"\";\n\tconst partitionFilter = filterExpired ? unpartitionedCookieFilter(columns.columns) : \"\";\n\treturn runSqliteQuery(dbPath, `SELECT name, value, host_key, ${pathExpr}, ${expiresExpr}, hex(encrypted_value) AS encrypted_value_hex FROM cookies WHERE ${buildCookieWhere(hosts, names ?? undefined)}${expiryFilter}${partitionFilter} ORDER BY length(path) DESC, expires_utc ASC`);\n}\n\nasync function readCookieColumns(dbPath: string): Promise<{ status: \"success\"; columns: Set<string> } | { status: \"failure\"; failure: SqliteFailure }> {\n\tconst result = await runSqliteQuery(dbPath, \"PRAGMA table_info(cookies)\");\n\tif (result.status === \"failure\") return result;\n\treturn { status: \"success\", columns: new Set(result.rows.map(row => typeof row.name === \"string\" ? row.name : \"\")) };\n}\n\nfunction chromeExpiryNowMicros(): number {\n\treturn (Date.now() + 11644473600000) * 1000;\n}\n\nfunction unpartitionedCookieFilter(columns: Set<string>): string {\n\tconst clauses: string[] = [];\n\tif (columns.has(\"top_frame_site_key\")) clauses.push(\"(top_frame_site_key IS NULL OR top_frame_site_key = '')\");\n\tif (columns.has(\"partition_key\")) clauses.push(\"(partition_key IS NULL OR partition_key = '')\");\n\tif (columns.has(\"is_partitioned\")) clauses.push(\"(is_partitioned IS NULL OR is_partitioned = 0)\");\n\treturn clauses.length > 0 ? ` AND ${clauses.join(\" AND \")}` : \"\";\n}\n\nfunction buildCookieHeader(entries: BrowserCookieEntry[]): string {\n\treturn entries\n\t\t.sort((a, b) => b.path.length - a.path.length)\n\t\t.map(({ name, value }) => `${name}=${value}`)\n\t\t.join(\"; \");\n}\n\nfunction pathMatches(requestPath: string, cookiePath: string): boolean {\n\tif (requestPath === cookiePath) return true;\n\tif (!requestPath.startsWith(cookiePath)) return false;\n\tif (cookiePath.endsWith(\"/\")) return true;\n\treturn requestPath[cookiePath.length] === \"/\";\n}\n\nfunction buildCookieWhere(hosts: string[], cookieNames?: Iterable<string>): string {\n\tconst hostClauses: string[] = [];\n\tfor (const host of hosts) {\n\t\tconst escapedHost = escapeSqlString(host);\n\t\thostClauses.push(`host_key = '${escapedHost}'`);\n\t\tfor (const candidate of domainCookieHosts(host)) {\n\t\t\thostClauses.push(`host_key = '.${escapeSqlString(candidate)}'`);\n\t\t}\n\t}\n\tlet where = `(${[...new Set(hostClauses)].join(\" OR \")})`;\n\tconst names = cookieNames ? [...cookieNames].filter(Boolean) : [];\n\tif (names.length) where += ` AND name IN (${names.map((name) => `'${escapeSqlString(name)}'`).join(\", \")})`;\n\treturn where;\n}\n\nfunction escapeSqlString(value: string): string {\n\treturn value.replaceAll(\"'\", \"''\");\n}\n\nfunction domainCookieHosts(host: string): string[] {\n\tconst parts = host.split(\".\").filter(Boolean);\n\tif (parts.length <= 1) return [];\n\tconst candidates = new Set<string>();\n\tfor (let i = 0; i <= parts.length - 2; i++) candidates.add(parts.slice(i).join(\".\"));\n\treturn [...candidates];\n}\n\nfunction copySidecar(srcDb: string, targetDb: string, suffix: string): void {\n\tconst sidecar = `${srcDb}${suffix}`;\n\tif (!existsSync(sidecar)) return;\n\ttry {\n\t\tcopyFileSync(sidecar, `${targetDb}${suffix}`);\n\t} catch {\n\t}\n}\n"]}
1
+ {"version":3,"file":"chrome-cookies.d.ts","sourceRoot":"","sources":["../../../../src/humain/web-access/vendor/chrome-cookies.ts"],"names":[],"mappings":"AAOA,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAsD/C,wBAAgB,6BAA6B,IAAI,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAgB,8BAA8B,IAAI,MAAM,GAAG,IAAI,CAE9D;AAED,wBAAsB,gBAAgB,CACrC,OAAO,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GACxD,OAAO,CAAC;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAAC,CAQ5D;AAED,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,GAAG,CAAA;CAAE,GAClJ,OAAO,CAAC;IAAE,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CA2InF"}
@@ -1,6 +1,6 @@
1
1
  import { execFile } from "node:child_process";
2
2
  import { pbkdf2Sync, createDecipheriv } from "node:crypto";
3
- import { copyFileSync, existsSync, mkdtempSync, readdirSync, realpathSync, rmSync } from "node:fs";
3
+ import { copyFileSync, existsSync, mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync } from "node:fs";
4
4
  import { tmpdir, homedir } from "node:os";
5
5
  import { isAbsolute, join, sep } from "node:path";
6
6
  import { isBrowserCookieAccessAllowed } from "./gemini-web-config.js";
@@ -24,6 +24,10 @@ const LINUX_BROWSER_CONFIGS = [
24
24
  { name: "Chromium", baseDir: ".config/chromium", secretToolApp: "chromium" },
25
25
  { name: "Chrome", baseDir: ".config/google-chrome", secretToolApp: "chrome" },
26
26
  ];
27
+ const WINDOWS_BROWSER_CONFIGS = [
28
+ { name: "Chrome", baseDir: "Google/Chrome/User Data", usesLocalAppData: true },
29
+ { name: "Edge", baseDir: "Microsoft/Edge/User Data", usesLocalAppData: true },
30
+ ];
27
31
  const browserPasswordCache = new Map();
28
32
  let lastCookieDiagnostic = null;
29
33
  let sqliteModule = null;
@@ -50,7 +54,7 @@ export async function getBrowserCookiesForHosts(options) {
50
54
  return null;
51
55
  }
52
56
  const currentPlatform = process.platform;
53
- const configs = currentPlatform === "darwin" ? MACOS_BROWSER_CONFIGS : currentPlatform === "linux" ? LINUX_BROWSER_CONFIGS : [];
57
+ const configs = currentPlatform === "darwin" ? MACOS_BROWSER_CONFIGS : currentPlatform === "linux" ? LINUX_BROWSER_CONFIGS : currentPlatform === "win32" ? WINDOWS_BROWSER_CONFIGS : [];
54
58
  if (configs.length === 0) {
55
59
  lastCookieDiagnostic = "Chromium cookie extraction is unsupported on this platform.";
56
60
  return null;
@@ -69,12 +73,13 @@ export async function getBrowserCookiesForHosts(options) {
69
73
  lastCookieDiagnostic = "No valid cookie hosts were requested.";
70
74
  return null;
71
75
  }
72
- const home = homedir();
76
+ const home = currentPlatform === "win32" ? process.env.USERPROFILE || homedir() : homedir();
73
77
  let sawCookieDatabase = false;
74
78
  let sawRequiredCookies = false;
75
79
  let sawAnyHostCookie = false;
76
80
  let sawBackendFailure;
77
81
  let sawUnsafeProfilePath = false;
82
+ let sawWindowsAppBoundCookie = false;
78
83
  for (const config of configs) {
79
84
  const profiles = requestedProfile ? [requestedProfile] : listBrowserProfiles(home, config);
80
85
  for (const profile of profiles) {
@@ -85,7 +90,9 @@ export async function getBrowserCookiesForHosts(options) {
85
90
  }
86
91
  if (!profilePath)
87
92
  continue;
88
- const cookiesPath = join(profilePath, "Cookies");
93
+ const cookiesPath = cookieDatabasePath(profilePath, config);
94
+ if (!cookiesPath)
95
+ continue;
89
96
  sawCookieDatabase = true;
90
97
  const tempDir = mkdtempSync(join(tmpdir(), "pi-chrome-cookies-"));
91
98
  try {
@@ -101,12 +108,15 @@ export async function getBrowserCookiesForHosts(options) {
101
108
  continue;
102
109
  sawRequiredCookies = true;
103
110
  }
104
- const password = await readBrowserPassword(config, currentPlatform);
105
- if (!password) {
106
- warningSet.add(`Could not read ${config.name} cookie encryption password`);
111
+ const key = currentPlatform === "win32"
112
+ ? await readWindowsEncryptionKey(config, home)
113
+ : await readBrowserPassword(config, currentPlatform).then((password) => password ? pbkdf2Sync(password, "saltysalt", currentPlatform === "darwin" ? 1003 : 1, 16, "sha1") : null);
114
+ if (!key) {
115
+ warningSet.add(currentPlatform === "win32"
116
+ ? `Could not read ${config.name} Windows cookie encryption key`
117
+ : `Could not read ${config.name} cookie encryption password`);
107
118
  continue;
108
119
  }
109
- const key = pbkdf2Sync(password, "saltysalt", currentPlatform === "darwin" ? 1003 : 1, 16, "sha1");
110
120
  const metaVersion = await readMetaVersion(tempDb);
111
121
  if (metaVersion.failure)
112
122
  sawBackendFailure = metaVersion.failure;
@@ -125,7 +135,12 @@ export async function getBrowserCookiesForHosts(options) {
125
135
  continue;
126
136
  let value = typeof row.value === "string" && row.value.length > 0 ? row.value : null;
127
137
  if (!value && typeof row.encrypted_value_hex === "string" && /^[0-9a-f]*$/i.test(row.encrypted_value_hex)) {
128
- value = decryptCookieValue(Buffer.from(row.encrypted_value_hex, "hex"), key, metaVersion.value >= 24);
138
+ const encrypted = Buffer.from(row.encrypted_value_hex, "hex");
139
+ if (currentPlatform === "win32" && encrypted.subarray(0, 3).toString("utf8") === "v20")
140
+ sawWindowsAppBoundCookie = true;
141
+ value = currentPlatform === "win32"
142
+ ? decryptWindowsCookieValue(encrypted, key, metaVersion.value >= 24)
143
+ : decryptCookieValue(encrypted, key, metaVersion.value >= 24);
129
144
  }
130
145
  if (!value)
131
146
  continue;
@@ -170,6 +185,9 @@ export async function getBrowserCookiesForHosts(options) {
170
185
  else if (requiredCookies?.length && !sawRequiredCookies) {
171
186
  lastCookieDiagnostic = `No detected Chromium profile contains the required ${options.requiredLabel ?? "browser"} cookies.`;
172
187
  }
188
+ else if (sawWindowsAppBoundCookie) {
189
+ lastCookieDiagnostic = "Windows Chromium v20 app-bound cookies are not supported.";
190
+ }
173
191
  else if (!sawAnyHostCookie) {
174
192
  lastCookieDiagnostic = options.requestUrl
175
193
  ? "No detected Chromium profile contains cookies for the requested URL."
@@ -195,10 +213,9 @@ function normalizeProfileName(value) {
195
213
  return normalized;
196
214
  }
197
215
  function resolveProfilePath(home, config, profile) {
198
- const basePath = join(home, config.baseDir);
216
+ const basePath = browserBasePath(home, config);
199
217
  const profilePath = join(basePath, profile);
200
- const cookiesPath = join(profilePath, "Cookies");
201
- if (!existsSync(cookiesPath))
218
+ if (!cookieDatabasePath(profilePath, config))
202
219
  return null;
203
220
  try {
204
221
  const baseRealPath = realpathSync(basePath);
@@ -211,6 +228,18 @@ function resolveProfilePath(home, config, profile) {
211
228
  return null;
212
229
  }
213
230
  }
231
+ function cookieDatabasePath(profilePath, config) {
232
+ const networkCookies = join(profilePath, "Network", "Cookies");
233
+ if (config.usesLocalAppData && existsSync(networkCookies))
234
+ return networkCookies;
235
+ const legacyCookies = join(profilePath, "Cookies");
236
+ return existsSync(legacyCookies) ? legacyCookies : null;
237
+ }
238
+ function browserBasePath(home, config) {
239
+ return config.usesLocalAppData
240
+ ? join(process.env.LOCALAPPDATA || join(home, "AppData", "Local"), config.baseDir)
241
+ : join(home, config.baseDir);
242
+ }
214
243
  function normalizeCookieNames(names) {
215
244
  if (!names?.length)
216
245
  return undefined;
@@ -221,13 +250,13 @@ function normalizeHosts(hosts) {
221
250
  return [...new Set(hosts.map(host => host.trim().toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "")).filter(Boolean))];
222
251
  }
223
252
  function listBrowserProfiles(home, config) {
224
- const basePath = join(home, config.baseDir);
253
+ const basePath = browserBasePath(home, config);
225
254
  if (!existsSync(basePath))
226
255
  return ["Default"];
227
256
  const profiles = new Set();
228
257
  try {
229
258
  for (const entry of readdirSync(basePath, { withFileTypes: true })) {
230
- if (entry.isDirectory() && existsSync(join(basePath, entry.name, "Cookies")))
259
+ if (entry.isDirectory() && cookieDatabasePath(join(basePath, entry.name), config))
231
260
  profiles.add(entry.name);
232
261
  }
233
262
  }
@@ -275,6 +304,22 @@ function decryptCookieValue(encrypted, key, stripHash) {
275
304
  return null;
276
305
  }
277
306
  }
307
+ function decryptWindowsCookieValue(encrypted, key, stripHash) {
308
+ const buf = Buffer.from(encrypted);
309
+ if (buf.subarray(0, 3).toString("utf8") !== "v10" || buf.length < 3 + 12 + 16)
310
+ return null;
311
+ try {
312
+ const nonce = buf.subarray(3, 15);
313
+ const ciphertext = buf.subarray(15, -16);
314
+ const decipher = createDecipheriv("aes-256-gcm", key, nonce);
315
+ decipher.setAuthTag(buf.subarray(-16));
316
+ const plaintext = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
317
+ return new TextDecoder("utf-8", { fatal: true }).decode(stripHash && plaintext.length >= 32 ? plaintext.subarray(32) : plaintext);
318
+ }
319
+ catch {
320
+ return null;
321
+ }
322
+ }
278
323
  function removePkcs7Padding(buf) {
279
324
  if (!buf.length)
280
325
  return buf;
@@ -304,6 +349,40 @@ function readBrowserPassword(config, currentPlatform) {
304
349
  browserPasswordCache.set(cacheKey, passwordPromise);
305
350
  return passwordPromise;
306
351
  }
352
+ async function readWindowsEncryptionKey(config, home) {
353
+ try {
354
+ const localState = JSON.parse(readFileSync(join(browserBasePath(home, config), "Local State"), "utf8"));
355
+ const encodedKey = localState.os_crypt?.encrypted_key;
356
+ if (typeof encodedKey !== "string")
357
+ return null;
358
+ const protectedKey = Buffer.from(encodedKey, "base64");
359
+ if (protectedKey.subarray(0, 5).toString("utf8") !== "DPAPI")
360
+ return null;
361
+ const decrypted = await unprotectWindowsData(protectedKey.subarray(5));
362
+ return decrypted?.length === 32 ? decrypted : null;
363
+ }
364
+ catch {
365
+ return null;
366
+ }
367
+ }
368
+ function unprotectWindowsData(protectedData) {
369
+ return new Promise((resolve) => {
370
+ const script = "Add-Type -AssemblyName System.Security;$data=[Convert]::FromBase64String($env:PIWA_PROTECTED);$clear=[System.Security.Cryptography.ProtectedData]::Unprotect($data,$null,[System.Security.Cryptography.DataProtectionScope]::CurrentUser);[Console]::Write([Convert]::ToBase64String($clear))";
371
+ const encoded = Buffer.from(script, "utf16le").toString("base64");
372
+ execFile("powershell.exe", ["-NoProfile", "-NonInteractive", "-EncodedCommand", encoded], { timeout: 5000, maxBuffer: 1024 * 1024, env: { ...process.env, PIWA_PROTECTED: protectedData.toString("base64") } }, (err, stdout) => {
373
+ if (err) {
374
+ resolve(null);
375
+ return;
376
+ }
377
+ try {
378
+ resolve(Buffer.from(stdout.trim(), "base64"));
379
+ }
380
+ catch {
381
+ resolve(null);
382
+ }
383
+ });
384
+ });
385
+ }
307
386
  function readKeychainPassword(account, service) {
308
387
  return new Promise((resolve) => {
309
388
  execFile("security", ["find-generic-password", "-w", "-a", account, "-s", service], { timeout: 5000 }, (err, stdout) => {
@@ -443,10 +522,10 @@ async function queryCookieRows(dbPath, hosts, names, filterExpired) {
443
522
  if (columns.status === "failure")
444
523
  return columns;
445
524
  const pathExpr = columns.columns.has("path") ? "path" : "'/' AS path";
446
- const expiresExpr = columns.columns.has("expires_utc") ? "expires_utc" : "0 AS expires_utc";
447
- const expiryFilter = filterExpired && columns.columns.has("expires_utc") ? ` AND (expires_utc = 0 OR expires_utc > ${chromeExpiryNowMicros()})` : "";
525
+ const expiresExpr = columns.columns.has("expires_utc") ? chromeExpiryMillisExpr() : "0";
526
+ const expiryFilter = filterExpired && columns.columns.has("expires_utc") ? ` AND (${expiresExpr} = 0 OR ${expiresExpr} > ${chromeExpiryNowMillis()})` : "";
448
527
  const partitionFilter = filterExpired ? unpartitionedCookieFilter(columns.columns) : "";
449
- return runSqliteQuery(dbPath, `SELECT name, value, host_key, ${pathExpr}, ${expiresExpr}, hex(encrypted_value) AS encrypted_value_hex FROM cookies WHERE ${buildCookieWhere(hosts, names ?? undefined)}${expiryFilter}${partitionFilter} ORDER BY length(path) DESC, expires_utc ASC`);
528
+ return runSqliteQuery(dbPath, `SELECT name, value, host_key, ${pathExpr}, ${expiresExpr} AS expires_utc, hex(encrypted_value) AS encrypted_value_hex FROM cookies WHERE ${buildCookieWhere(hosts, names ?? undefined)}${expiryFilter}${partitionFilter} ORDER BY length(path) DESC, ${expiresExpr} ASC`);
450
529
  }
451
530
  async function readCookieColumns(dbPath) {
452
531
  const result = await runSqliteQuery(dbPath, "PRAGMA table_info(cookies)");
@@ -454,8 +533,11 @@ async function readCookieColumns(dbPath) {
454
533
  return result;
455
534
  return { status: "success", columns: new Set(result.rows.map(row => typeof row.name === "string" ? row.name : "")) };
456
535
  }
457
- function chromeExpiryNowMicros() {
458
- return (Date.now() + 11644473600000) * 1000;
536
+ function chromeExpiryMillisExpr() {
537
+ return "CASE WHEN expires_utc = 0 THEN 0 ELSE CAST(expires_utc / 1000 AS INTEGER) + CASE WHEN expires_utc % 1000 = 0 THEN 0 ELSE 1 END END";
538
+ }
539
+ function chromeExpiryNowMillis() {
540
+ return Date.now() + 11644473600000;
459
541
  }
460
542
  function unpartitionedCookieFilter(columns) {
461
543
  const clauses = [];