mcp-scraper 0.18.0 → 0.20.0

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 (59) hide show
  1. package/README.md +2 -2
  2. package/dist/bin/api-server.cjs +635 -109
  3. package/dist/bin/api-server.cjs.map +1 -1
  4. package/dist/bin/api-server.js +3 -3
  5. package/dist/bin/mcp-scraper-cli.cjs +1 -1
  6. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  7. package/dist/bin/mcp-scraper-cli.js +1 -1
  8. package/dist/bin/mcp-scraper-install.cjs +2 -2
  9. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  10. package/dist/bin/mcp-scraper-install.js +2 -2
  11. package/dist/bin/mcp-stdio-server.cjs +2228 -1783
  12. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  13. package/dist/bin/mcp-stdio-server.js +5 -4
  14. package/dist/bin/mcp-stdio-server.js.map +1 -1
  15. package/dist/bin/paa-harvest.cjs.map +1 -1
  16. package/dist/bin/paa-harvest.js +3 -3
  17. package/dist/{chunk-GL4BW4CP.js → chunk-22VEGGTW.js} +21 -9
  18. package/dist/{chunk-GL4BW4CP.js.map → chunk-22VEGGTW.js.map} +1 -1
  19. package/dist/{chunk-RUGJE5EB.js → chunk-EJK25QOW.js} +2 -2
  20. package/dist/chunk-JWIE5NCR.js +284 -0
  21. package/dist/chunk-JWIE5NCR.js.map +1 -0
  22. package/dist/{chunk-FMEDPBIV.js → chunk-KE7KE2Q2.js} +482 -35
  23. package/dist/chunk-KE7KE2Q2.js.map +1 -0
  24. package/dist/chunk-PZB3TJWK.js +7 -0
  25. package/dist/chunk-PZB3TJWK.js.map +1 -0
  26. package/dist/{chunk-BX5RCOG5.js → chunk-Q44DN6T2.js} +2 -2
  27. package/dist/{chunk-BX5RCOG5.js.map → chunk-Q44DN6T2.js.map} +1 -1
  28. package/dist/chunk-UN7VMHZL.js +244 -0
  29. package/dist/chunk-UN7VMHZL.js.map +1 -0
  30. package/dist/{chunk-RMPPYKUV.js → chunk-XDFSLSSH.js} +7 -218
  31. package/dist/chunk-XDFSLSSH.js.map +1 -0
  32. package/dist/{chunk-HE2LQPJ2.js → chunk-ZRKFW5FB.js} +2 -2
  33. package/dist/{db-LIOTIWVN.js → db-YHZYG7D2.js} +2 -2
  34. package/dist/{extract-bundle-U4D5LW5W.js → extract-bundle-OSUPAHCE.js} +58 -5
  35. package/dist/extract-bundle-OSUPAHCE.js.map +1 -0
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.js +5 -4
  38. package/dist/index.js.map +1 -1
  39. package/dist/{server-MQDCAR6I.js → server-VDWIPV7F.js} +100 -363
  40. package/dist/server-VDWIPV7F.js.map +1 -0
  41. package/dist/{site-extract-repository-NVSZH35Y.js → site-extract-repository-GWKGK46Z.js} +3 -3
  42. package/dist/{worker-JQTS437L.js → worker-O5PZTTPY.js} +8 -8
  43. package/docs/mcp-tool-manifest.generated.json +564 -30
  44. package/docs/specs/meta-ad-creative-media-resolution-spec.md +31 -0
  45. package/docs/specs/unified-credit-and-scheduled-execution-billing-spec.md +1007 -0
  46. package/package.json +1 -1
  47. package/dist/chunk-FMEDPBIV.js.map +0 -1
  48. package/dist/chunk-HPV4VOQX.js +0 -27
  49. package/dist/chunk-HPV4VOQX.js.map +0 -1
  50. package/dist/chunk-RLWCHLV3.js +0 -7
  51. package/dist/chunk-RLWCHLV3.js.map +0 -1
  52. package/dist/chunk-RMPPYKUV.js.map +0 -1
  53. package/dist/extract-bundle-U4D5LW5W.js.map +0 -1
  54. package/dist/server-MQDCAR6I.js.map +0 -1
  55. /package/dist/{chunk-RUGJE5EB.js.map → chunk-EJK25QOW.js.map} +0 -0
  56. /package/dist/{chunk-HE2LQPJ2.js.map → chunk-ZRKFW5FB.js.map} +0 -0
  57. /package/dist/{db-LIOTIWVN.js.map → db-YHZYG7D2.js.map} +0 -0
  58. /package/dist/{site-extract-repository-NVSZH35Y.js.map → site-extract-repository-GWKGK46Z.js.map} +0 -0
  59. /package/dist/{worker-JQTS437L.js.map → worker-O5PZTTPY.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ // src/version.ts
2
+ var PACKAGE_VERSION = "0.20.0";
3
+
4
+ export {
5
+ PACKAGE_VERSION
6
+ };
7
+ //# sourceMappingURL=chunk-PZB3TJWK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/version.ts"],"sourcesContent":["export const PACKAGE_VERSION = '0.20.0'\n"],"mappings":";AAAO,IAAM,kBAAkB;","names":[]}
@@ -50,7 +50,7 @@ function renderInstallTerminal(options) {
50
50
  "1/1 install surfaces ready",
51
51
  colorize("Newest: any approved connection read can become an indexed Memory snapshot in one call. OAuth stays tenant-isolated and provider content is redacted and marked untrusted.", "lime", color),
52
52
  "",
53
- `${colorize("Tools", "cyan", color)} ${colorize("(157 MCP tools)", "muted", color)}`,
53
+ `${colorize("Tools", "cyan", color)} ${colorize("(158 MCP tools)", "muted", color)}`,
54
54
  toolRow("search", ["harvest_paa", "search_serp", "maps_search", "maps_place_intel"], color),
55
55
  toolRow("extract", ["extract_url", "map_site_urls", "extract_site", "audit_site", "directory_workflow"], color),
56
56
  toolRow("build", ["rank_tracker_workflow", "cron plan", "database prompt"], color),
@@ -105,4 +105,4 @@ function renderInstallTerminal(options) {
105
105
  export {
106
106
  renderInstallTerminal
107
107
  };
108
- //# sourceMappingURL=chunk-BX5RCOG5.js.map
108
+ //# sourceMappingURL=chunk-Q44DN6T2.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/install-terminal.ts"],"sourcesContent":["export interface InstallTerminalOptions {\n color?: boolean\n version: string\n apiKeyConfigured?: boolean\n}\n\ntype Tone = 'cyan' | 'lime' | 'amber' | 'red' | 'muted' | 'bold'\n\nconst CODES: Record<Tone | 'reset', string> = {\n reset: '\\x1b[0m',\n cyan: '\\x1b[36m',\n lime: '\\x1b[32m',\n amber: '\\x1b[33m',\n red: '\\x1b[31m',\n muted: '\\x1b[90m',\n bold: '\\x1b[1m',\n}\n\nfunction colorize(value: string, tone: Tone, enabled: boolean): string {\n if (!enabled) return value\n return `${CODES[tone]}${value}${CODES.reset}`\n}\n\nfunction toolRow(label: string, tools: string[], enabled: boolean): string {\n const padded = label.padEnd(9, ' ')\n return ` ${colorize(padded, 'muted', enabled)} ${tools.join(colorize(' . ', 'muted', enabled))}`\n}\n\nexport function renderInstallTerminal(options: InstallTerminalOptions): string {\n const color = options.color ?? true\n const apiKeyValue = options.apiKeyConfigured ? '$MCP_SCRAPER_API_KEY' : 'sk_live_your_key'\n const ascii = String.raw`\n __ __ ____ ____ \n| \\/ |/ ___| _ \\\n| |\\/| | | | |_) |\n| | | | |___| __/\n|_| |_|\\____|_|\n\n ____ ____ ____ _ ____ _____ ____\n/ ___| / ___| _ \\ / \\ | _ \\| ____| _ \\\n\\___ \\| | | |_) | / _ \\ | |_) | _| | |_) |\n ___) | |___| _ < / ___ \\| __/| |___| _ <\n|____/ \\____|_| \\_\\/_/ \\_\\_| |_____|_| \\_\\\n`\n\n const claudeCommand = [\n `MCP_SCRAPER_API_KEY=${apiKeyValue} npx -y -p mcp-scraper@latest \\\\`,\n ' mcp-scraper-cli agent install claude --apply',\n ].join('\\n')\n\n const codexConfig = [\n '[mcp_servers.mcp-scraper]',\n 'command = \"npx\"',\n 'args = [\"-y\", \"-p\", \"mcp-scraper@latest\", \"mcp-scraper\"]',\n `env = { MCP_SCRAPER_API_KEY = \"${apiKeyValue}\" }`,\n ].join('\\n')\n\n return [\n colorize(`mcp-scraper v${options.version}`, 'bold', color),\n colorize('> mcp-scraper-install', 'muted', color),\n colorize(ascii, 'amber', color),\n `${colorize('MCP Scraper Agent', 'cyan', color)} . v${options.version} . mcpscraper.dev`,\n '1/1 install surfaces ready',\n colorize('Newest: any approved connection read can become an indexed Memory snapshot in one call. OAuth stays tenant-isolated and provider content is redacted and marked untrusted.', 'lime', color),\n '',\n `${colorize('Tools', 'cyan', color)} ${colorize('(157 MCP tools)', 'muted', color)}`,\n toolRow('search', ['harvest_paa', 'search_serp', 'maps_search', 'maps_place_intel'], color),\n toolRow('extract', ['extract_url', 'map_site_urls', 'extract_site', 'audit_site', 'directory_workflow'], color),\n toolRow('build', ['rank_tracker_workflow', 'cron plan', 'database prompt'], color),\n toolRow('media', ['youtube_harvest', 'youtube_transcribe', 'facebook_ad_search', 'facebook_page_intel', 'facebook_ad_transcribe', 'facebook_video_transcribe', 'instagram_profile_content', 'instagram_media_download', 'reddit_thread'], color),\n toolRow('browser', ['browser_open', 'browser_profile_connect', 'browser_profile_list', 'browser_close', 'browser_screenshot', 'browser_read', 'browser_locate', 'browser_replay_mark', 'browser_replay_annotate'], color),\n toolRow('connect', ['list_service_connections', 'describe_service_connection_tool', 'import_service_connection_to_memory', 'export_connected_service_data', 'renew_connected_data_download', 'read_service_connection', 'call_service_connection_action'], color),\n toolRow('account', ['credits_info', 'reports', 'MCP resources'], color),\n toolRow('memory', ['memory-put', 'memory-get', 'memory-search', 'list-vaults', 'record-fact', 'list-scheduled-actions'], color),\n `${colorize('Workflows', 'cyan', color)} ${colorize('(MCP + CLI + API)', 'muted', color)}`,\n toolRow('route', ['workflow_list', 'workflow_suggest', 'workflow_run', 'workflow_step', 'workflow_status', 'workflow_artifact_read'], color),\n toolRow('seo', ['directory', 'agent-packet', 'competitive audit', 'map/serp comparison', 'PAA/AIO briefs', 'scheduled runs'], color),\n '',\n colorize('Usage tips:', 'amber', color),\n 'Run mcp-scraper-install for this visible card. Run mcp-scraper-cli for setup utilities and subcommands.',\n 'Run mcp-scraper in a human terminal to print this card; MCP clients get the same command as a silent stdio server.',\n 'Explicit card command: npx -y -p mcp-scraper@latest mcp-scraper-install',\n 'Hosted browser sessions use direct/no-proxy egress by default.',\n 'Customer auth setup: run browser_profile_connect, send the watch_url, let the user sign in, then call browser_profile_list until AUTHENTICATED.',\n 'Connected account ranges: call export_connected_service_data once. It handles Gmail, Calendar, Zoom, and Resend pagination; do not loop read_service_connection over individual records.',\n 'Connected account RAG: call import_service_connection_to_memory for one bounded approved read. It writes a redacted, untrusted snapshot to a stable Memory path and embeds it for search.',\n 'Stack logins / reconnect: run browser_profile_connect again with the same profile name and another domain to add accounts or refresh a login.',\n 'Start with workflow_suggest for broad jobs like market analysis, ICP research, CRO audits, brand briefs, content gaps, and AI visibility.',\n 'For MCP clients, use mcp-scraper so one install can mix SERP, Maps, browser, reports, and saved MCP resources.',\n 'If you hit the concurrency limit, add an extra slot for $5/month with mcp-scraper-cli billing concurrency checkout.',\n '',\n `${colorize('Ready.', 'lime', color)} Install the combined MCP server with one command:`,\n '',\n colorize('Setup doctor', 'amber', color),\n 'npx -y -p mcp-scraper@latest mcp-scraper-cli doctor',\n '',\n colorize('Hosted profile setup', 'amber', color),\n 'In your MCP client, call browser_profile_connect with email=\"seo@example.com\" and domain=\"chatgpt.com\".',\n 'Give the returned watch_url to the user. After they sign in, call browser_profile_list, then browser_open with the returned profile. Add more logins by calling browser_profile_connect again with the same profile and a new domain.',\n '',\n colorize('Claude Code one-command setup', 'amber', color),\n claudeCommand,\n 'Then fully exit Claude Code and open a new Claude terminal. Check with: claude mcp list',\n '',\n colorize('Codex config', 'amber', color),\n codexConfig,\n '',\n colorize('Claude Desktop Extension', 'amber', color),\n 'Download: https://mcpscraper.dev/downloads/mcp-scraper.mcpb',\n '',\n colorize('Safety note:', 'muted', color),\n 'mcp-scraper prints this card only when stdin/stdout are an interactive TTY. In MCP clients it writes only JSON-RPC to stdout.',\n 'Use --stdio or MCP_SCRAPER_FORCE_STDIO=1 to force server mode from a terminal.',\n '',\n ].join('\\n')\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/install-terminal.ts"],"sourcesContent":["export interface InstallTerminalOptions {\n color?: boolean\n version: string\n apiKeyConfigured?: boolean\n}\n\ntype Tone = 'cyan' | 'lime' | 'amber' | 'red' | 'muted' | 'bold'\n\nconst CODES: Record<Tone | 'reset', string> = {\n reset: '\\x1b[0m',\n cyan: '\\x1b[36m',\n lime: '\\x1b[32m',\n amber: '\\x1b[33m',\n red: '\\x1b[31m',\n muted: '\\x1b[90m',\n bold: '\\x1b[1m',\n}\n\nfunction colorize(value: string, tone: Tone, enabled: boolean): string {\n if (!enabled) return value\n return `${CODES[tone]}${value}${CODES.reset}`\n}\n\nfunction toolRow(label: string, tools: string[], enabled: boolean): string {\n const padded = label.padEnd(9, ' ')\n return ` ${colorize(padded, 'muted', enabled)} ${tools.join(colorize(' . ', 'muted', enabled))}`\n}\n\nexport function renderInstallTerminal(options: InstallTerminalOptions): string {\n const color = options.color ?? true\n const apiKeyValue = options.apiKeyConfigured ? '$MCP_SCRAPER_API_KEY' : 'sk_live_your_key'\n const ascii = String.raw`\n __ __ ____ ____ \n| \\/ |/ ___| _ \\\n| |\\/| | | | |_) |\n| | | | |___| __/\n|_| |_|\\____|_|\n\n ____ ____ ____ _ ____ _____ ____\n/ ___| / ___| _ \\ / \\ | _ \\| ____| _ \\\n\\___ \\| | | |_) | / _ \\ | |_) | _| | |_) |\n ___) | |___| _ < / ___ \\| __/| |___| _ <\n|____/ \\____|_| \\_\\/_/ \\_\\_| |_____|_| \\_\\\n`\n\n const claudeCommand = [\n `MCP_SCRAPER_API_KEY=${apiKeyValue} npx -y -p mcp-scraper@latest \\\\`,\n ' mcp-scraper-cli agent install claude --apply',\n ].join('\\n')\n\n const codexConfig = [\n '[mcp_servers.mcp-scraper]',\n 'command = \"npx\"',\n 'args = [\"-y\", \"-p\", \"mcp-scraper@latest\", \"mcp-scraper\"]',\n `env = { MCP_SCRAPER_API_KEY = \"${apiKeyValue}\" }`,\n ].join('\\n')\n\n return [\n colorize(`mcp-scraper v${options.version}`, 'bold', color),\n colorize('> mcp-scraper-install', 'muted', color),\n colorize(ascii, 'amber', color),\n `${colorize('MCP Scraper Agent', 'cyan', color)} . v${options.version} . mcpscraper.dev`,\n '1/1 install surfaces ready',\n colorize('Newest: any approved connection read can become an indexed Memory snapshot in one call. OAuth stays tenant-isolated and provider content is redacted and marked untrusted.', 'lime', color),\n '',\n `${colorize('Tools', 'cyan', color)} ${colorize('(158 MCP tools)', 'muted', color)}`,\n toolRow('search', ['harvest_paa', 'search_serp', 'maps_search', 'maps_place_intel'], color),\n toolRow('extract', ['extract_url', 'map_site_urls', 'extract_site', 'audit_site', 'directory_workflow'], color),\n toolRow('build', ['rank_tracker_workflow', 'cron plan', 'database prompt'], color),\n toolRow('media', ['youtube_harvest', 'youtube_transcribe', 'facebook_ad_search', 'facebook_page_intel', 'facebook_ad_transcribe', 'facebook_video_transcribe', 'instagram_profile_content', 'instagram_media_download', 'reddit_thread'], color),\n toolRow('browser', ['browser_open', 'browser_profile_connect', 'browser_profile_list', 'browser_close', 'browser_screenshot', 'browser_read', 'browser_locate', 'browser_replay_mark', 'browser_replay_annotate'], color),\n toolRow('connect', ['list_service_connections', 'describe_service_connection_tool', 'import_service_connection_to_memory', 'export_connected_service_data', 'renew_connected_data_download', 'read_service_connection', 'call_service_connection_action'], color),\n toolRow('account', ['credits_info', 'reports', 'MCP resources'], color),\n toolRow('memory', ['memory-put', 'memory-get', 'memory-search', 'list-vaults', 'record-fact', 'list-scheduled-actions'], color),\n `${colorize('Workflows', 'cyan', color)} ${colorize('(MCP + CLI + API)', 'muted', color)}`,\n toolRow('route', ['workflow_list', 'workflow_suggest', 'workflow_run', 'workflow_step', 'workflow_status', 'workflow_artifact_read'], color),\n toolRow('seo', ['directory', 'agent-packet', 'competitive audit', 'map/serp comparison', 'PAA/AIO briefs', 'scheduled runs'], color),\n '',\n colorize('Usage tips:', 'amber', color),\n 'Run mcp-scraper-install for this visible card. Run mcp-scraper-cli for setup utilities and subcommands.',\n 'Run mcp-scraper in a human terminal to print this card; MCP clients get the same command as a silent stdio server.',\n 'Explicit card command: npx -y -p mcp-scraper@latest mcp-scraper-install',\n 'Hosted browser sessions use direct/no-proxy egress by default.',\n 'Customer auth setup: run browser_profile_connect, send the watch_url, let the user sign in, then call browser_profile_list until AUTHENTICATED.',\n 'Connected account ranges: call export_connected_service_data once. It handles Gmail, Calendar, Zoom, and Resend pagination; do not loop read_service_connection over individual records.',\n 'Connected account RAG: call import_service_connection_to_memory for one bounded approved read. It writes a redacted, untrusted snapshot to a stable Memory path and embeds it for search.',\n 'Stack logins / reconnect: run browser_profile_connect again with the same profile name and another domain to add accounts or refresh a login.',\n 'Start with workflow_suggest for broad jobs like market analysis, ICP research, CRO audits, brand briefs, content gaps, and AI visibility.',\n 'For MCP clients, use mcp-scraper so one install can mix SERP, Maps, browser, reports, and saved MCP resources.',\n 'If you hit the concurrency limit, add an extra slot for $5/month with mcp-scraper-cli billing concurrency checkout.',\n '',\n `${colorize('Ready.', 'lime', color)} Install the combined MCP server with one command:`,\n '',\n colorize('Setup doctor', 'amber', color),\n 'npx -y -p mcp-scraper@latest mcp-scraper-cli doctor',\n '',\n colorize('Hosted profile setup', 'amber', color),\n 'In your MCP client, call browser_profile_connect with email=\"seo@example.com\" and domain=\"chatgpt.com\".',\n 'Give the returned watch_url to the user. After they sign in, call browser_profile_list, then browser_open with the returned profile. Add more logins by calling browser_profile_connect again with the same profile and a new domain.',\n '',\n colorize('Claude Code one-command setup', 'amber', color),\n claudeCommand,\n 'Then fully exit Claude Code and open a new Claude terminal. Check with: claude mcp list',\n '',\n colorize('Codex config', 'amber', color),\n codexConfig,\n '',\n colorize('Claude Desktop Extension', 'amber', color),\n 'Download: https://mcpscraper.dev/downloads/mcp-scraper.mcpb',\n '',\n colorize('Safety note:', 'muted', color),\n 'mcp-scraper prints this card only when stdin/stdout are an interactive TTY. In MCP clients it writes only JSON-RPC to stdout.',\n 'Use --stdio or MCP_SCRAPER_FORCE_STDIO=1 to force server mode from a terminal.',\n '',\n ].join('\\n')\n}\n"],"mappings":";AAQA,IAAM,QAAwC;AAAA,EAC5C,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AAAA,EACP,KAAK;AAAA,EACL,OAAO;AAAA,EACP,MAAM;AACR;AAEA,SAAS,SAAS,OAAe,MAAY,SAA0B;AACrE,MAAI,CAAC,QAAS,QAAO;AACrB,SAAO,GAAG,MAAM,IAAI,CAAC,GAAG,KAAK,GAAG,MAAM,KAAK;AAC7C;AAEA,SAAS,QAAQ,OAAe,OAAiB,SAA0B;AACzE,QAAM,SAAS,MAAM,OAAO,GAAG,GAAG;AAClC,SAAO,KAAK,SAAS,QAAQ,SAAS,OAAO,CAAC,IAAI,MAAM,KAAK,SAAS,SAAS,SAAS,OAAO,CAAC,CAAC;AACnG;AAEO,SAAS,sBAAsB,SAAyC;AAC7E,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,cAAc,QAAQ,mBAAmB,yBAAyB;AACxE,QAAM,QAAQ,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAcrB,QAAM,gBAAgB;AAAA,IACpB,uBAAuB,WAAW;AAAA,IAClC;AAAA,EACF,EAAE,KAAK,IAAI;AAEX,QAAM,cAAc;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA,kCAAkC,WAAW;AAAA,EAC/C,EAAE,KAAK,IAAI;AAEX,SAAO;AAAA,IACL,SAAS,gBAAgB,QAAQ,OAAO,IAAI,QAAQ,KAAK;AAAA,IACzD,SAAS,yBAAyB,SAAS,KAAK;AAAA,IAChD,SAAS,OAAO,SAAS,KAAK;AAAA,IAC9B,GAAG,SAAS,qBAAqB,QAAQ,KAAK,CAAC,SAAS,QAAQ,OAAO;AAAA,IACvE;AAAA,IACA,SAAS,8KAA8K,QAAQ,KAAK;AAAA,IACpM;AAAA,IACA,GAAG,SAAS,SAAS,QAAQ,KAAK,CAAC,KAAK,SAAS,mBAAmB,SAAS,KAAK,CAAC;AAAA,IACnF,QAAQ,UAAU,CAAC,eAAe,eAAe,eAAe,kBAAkB,GAAG,KAAK;AAAA,IAC1F,QAAQ,WAAW,CAAC,eAAe,iBAAiB,gBAAgB,cAAc,oBAAoB,GAAG,KAAK;AAAA,IAC9G,QAAQ,SAAS,CAAC,yBAAyB,aAAa,iBAAiB,GAAG,KAAK;AAAA,IACjF,QAAQ,SAAS,CAAC,mBAAmB,sBAAsB,sBAAsB,uBAAuB,0BAA0B,6BAA6B,6BAA6B,4BAA4B,eAAe,GAAG,KAAK;AAAA,IAC/O,QAAQ,WAAW,CAAC,gBAAgB,2BAA2B,wBAAwB,iBAAiB,sBAAsB,gBAAgB,kBAAkB,uBAAuB,yBAAyB,GAAG,KAAK;AAAA,IACxN,QAAQ,WAAW,CAAC,4BAA4B,oCAAoC,uCAAuC,iCAAiC,iCAAiC,2BAA2B,gCAAgC,GAAG,KAAK;AAAA,IAChQ,QAAQ,WAAW,CAAC,gBAAgB,WAAW,eAAe,GAAG,KAAK;AAAA,IACtE,QAAQ,UAAU,CAAC,cAAc,cAAc,iBAAiB,eAAe,eAAe,wBAAwB,GAAG,KAAK;AAAA,IAC9H,GAAG,SAAS,aAAa,QAAQ,KAAK,CAAC,KAAK,SAAS,qBAAqB,SAAS,KAAK,CAAC;AAAA,IACzF,QAAQ,SAAS,CAAC,iBAAiB,oBAAoB,gBAAgB,iBAAiB,mBAAmB,wBAAwB,GAAG,KAAK;AAAA,IAC3I,QAAQ,OAAO,CAAC,aAAa,gBAAgB,qBAAqB,uBAAuB,kBAAkB,gBAAgB,GAAG,KAAK;AAAA,IACnI;AAAA,IACA,SAAS,eAAe,SAAS,KAAK;AAAA,IACtC;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG,SAAS,UAAU,QAAQ,KAAK,CAAC;AAAA,IACpC;AAAA,IACA,SAAS,gBAAgB,SAAS,KAAK;AAAA,IACvC;AAAA,IACA;AAAA,IACA,SAAS,wBAAwB,SAAS,KAAK;AAAA,IAC/C;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,iCAAiC,SAAS,KAAK;AAAA,IACxD;AAAA,IACA;AAAA,IACA;AAAA,IACA,SAAS,gBAAgB,SAAS,KAAK;AAAA,IACvC;AAAA,IACA;AAAA,IACA,SAAS,4BAA4B,SAAS,KAAK;AAAA,IACnD;AAAA,IACA;AAAA,IACA,SAAS,gBAAgB,SAAS,KAAK;AAAA,IACvC;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,IAAI;AACb;","names":[]}
@@ -0,0 +1,244 @@
1
+ import {
2
+ getDb
3
+ } from "./chunk-22VEGGTW.js";
4
+
5
+ // src/lib/browser-service-env.ts
6
+ function browserServiceApiKey() {
7
+ const value = (process.env.BROWSER_SERVICE_API_KEY ?? process.env.KERNEL_API_KEY)?.trim();
8
+ return value || void 0;
9
+ }
10
+ function browserServiceProxyId() {
11
+ return void 0;
12
+ }
13
+ function browserServiceProfileName() {
14
+ const value = (process.env.BROWSER_AGENT_PROFILE_NAME ?? process.env.BROWSER_SERVICE_PROFILE_NAME ?? process.env.KERNEL_BROWSER_PROFILE_NAME ?? process.env.KERNEL_PROFILE_NAME)?.trim();
15
+ return value || void 0;
16
+ }
17
+ function browserServiceProfileSaveChanges() {
18
+ const value = (process.env.BROWSER_AGENT_PROFILE_SAVE_CHANGES ?? process.env.BROWSER_SERVICE_PROFILE_SAVE_CHANGES ?? process.env.KERNEL_BROWSER_PROFILE_SAVE_CHANGES ?? process.env.KERNEL_PROFILE_SAVE_CHANGES)?.trim().toLowerCase();
19
+ if (!value) return void 0;
20
+ if (["1", "true", "yes", "on"].includes(value)) return true;
21
+ if (["0", "false", "no", "off"].includes(value)) return false;
22
+ return void 0;
23
+ }
24
+
25
+ // src/api/cost-context.ts
26
+ import { AsyncLocalStorage } from "async_hooks";
27
+ var storage = new AsyncLocalStorage();
28
+ function runWithCostContext(ctx, fn) {
29
+ return storage.run(ctx, fn);
30
+ }
31
+ function currentCostContext() {
32
+ return storage.getStore();
33
+ }
34
+
35
+ // src/api/cost-telemetry.ts
36
+ import { randomUUID } from "crypto";
37
+
38
+ // src/api/cost-rates.ts
39
+ var KERNEL_HEADLESS_USD_PER_SEC = 166667e-10;
40
+ var KERNEL_HEADFUL_USD_PER_SEC = 1333336e-10;
41
+ var HEADLESS_OPS = /* @__PURE__ */ new Set(["serp", "maps_search", "yt_channel", "yt_transcription", "fb_search", "fb_ad", "instagram"]);
42
+ var FAL_WIZPER_USD_PER_COMPUTE_SEC = 111e-5;
43
+ var FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR = 4;
44
+ var DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS = 4e-4;
45
+ function kernelCostUsd(ms, headful) {
46
+ const sec = Math.max(0, ms) / 1e3;
47
+ return sec * (headful ? KERNEL_HEADFUL_USD_PER_SEC : KERNEL_HEADLESS_USD_PER_SEC);
48
+ }
49
+ function vendorCostUsd(vendor, units) {
50
+ if (vendor === "fal_wizper") {
51
+ const estimatedComputeSec = Math.max(0, units) / FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR;
52
+ return estimatedComputeSec * FAL_WIZPER_USD_PER_COMPUTE_SEC;
53
+ }
54
+ if (vendor === "deepinfra_qwen") return Math.max(0, units) / 1e3 * DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS;
55
+ if (vendor === "openrouter") return Math.max(0, units);
56
+ if (vendor === "mcp_memory_video") return Math.max(0, units);
57
+ if (vendor === "mcp_memory_ai") return Math.max(0, units);
58
+ return 0;
59
+ }
60
+
61
+ // src/api/cost-telemetry.ts
62
+ var _ready = false;
63
+ async function migrateCostTelemetry() {
64
+ if (_ready) return;
65
+ const db = getDb();
66
+ await db.execute(`
67
+ CREATE TABLE IF NOT EXISTS kernel_session_log (
68
+ id TEXT PRIMARY KEY,
69
+ kernel_session_id TEXT,
70
+ op TEXT,
71
+ source TEXT NOT NULL,
72
+ probe_run_id TEXT,
73
+ user_id INTEGER,
74
+ stealth INTEGER,
75
+ headless_sent INTEGER,
76
+ proxy_used INTEGER,
77
+ fallback INTEGER NOT NULL DEFAULT 0,
78
+ opened_at TEXT,
79
+ closed_at TEXT,
80
+ duration_ms INTEGER NOT NULL DEFAULT 0,
81
+ est_cost_usd_headless REAL NOT NULL DEFAULT 0,
82
+ est_cost_usd_headful REAL NOT NULL DEFAULT 0,
83
+ error TEXT,
84
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
85
+ )
86
+ `);
87
+ await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_op ON kernel_session_log(op)`);
88
+ await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_probe ON kernel_session_log(probe_run_id)`);
89
+ await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_created ON kernel_session_log(created_at)`);
90
+ try {
91
+ await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_source TEXT`);
92
+ } catch {
93
+ }
94
+ try {
95
+ await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_type TEXT`);
96
+ } catch {
97
+ }
98
+ try {
99
+ await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN method TEXT`);
100
+ } catch {
101
+ }
102
+ await db.execute(`
103
+ CREATE TABLE IF NOT EXISTS vendor_usage_log (
104
+ id TEXT PRIMARY KEY,
105
+ op TEXT,
106
+ probe_run_id TEXT,
107
+ user_id INTEGER,
108
+ vendor TEXT NOT NULL,
109
+ model TEXT,
110
+ units REAL NOT NULL DEFAULT 0,
111
+ unit_type TEXT,
112
+ est_cost_usd REAL NOT NULL DEFAULT 0,
113
+ error TEXT,
114
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
115
+ )
116
+ `);
117
+ await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_op ON vendor_usage_log(op)`);
118
+ await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_probe ON vendor_usage_log(probe_run_id)`);
119
+ await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_created ON vendor_usage_log(created_at)`);
120
+ try {
121
+ await db.execute(`ALTER TABLE vendor_usage_log ADD COLUMN method TEXT`);
122
+ } catch {
123
+ }
124
+ await db.execute(`
125
+ CREATE TABLE IF NOT EXISTS cost_probe_runs (
126
+ id TEXT PRIMARY KEY,
127
+ tool TEXT NOT NULL,
128
+ target TEXT,
129
+ started_at TEXT NOT NULL DEFAULT (datetime('now')),
130
+ wall_ms INTEGER NOT NULL DEFAULT 0,
131
+ success INTEGER NOT NULL DEFAULT 0,
132
+ error TEXT,
133
+ http_only INTEGER NOT NULL DEFAULT 0,
134
+ kernel_used INTEGER NOT NULL DEFAULT 0,
135
+ kernel_sessions INTEGER NOT NULL DEFAULT 0,
136
+ kernel_seconds_total REAL NOT NULL DEFAULT 0,
137
+ kernel_tier_observed TEXT,
138
+ est_kernel_cost_usd_headless REAL NOT NULL DEFAULT 0,
139
+ est_kernel_cost_usd_headful REAL NOT NULL DEFAULT 0,
140
+ vendor_cost_usd REAL NOT NULL DEFAULT 0,
141
+ charged_credits REAL NOT NULL DEFAULT 0,
142
+ margin_usd_headless_starter REAL NOT NULL DEFAULT 0,
143
+ margin_usd_headful_starter REAL NOT NULL DEFAULT 0,
144
+ notes TEXT
145
+ )
146
+ `);
147
+ await db.execute(`CREATE INDEX IF NOT EXISTS cost_probe_runs_tool ON cost_probe_runs(tool)`);
148
+ try {
149
+ await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN units REAL`);
150
+ } catch {
151
+ }
152
+ try {
153
+ await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN unit_type TEXT`);
154
+ } catch {
155
+ }
156
+ try {
157
+ await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN mode TEXT`);
158
+ } catch {
159
+ }
160
+ _ready = true;
161
+ }
162
+ async function recordKernelSession(r) {
163
+ try {
164
+ await migrateCostTelemetry();
165
+ const ctx = currentCostContext();
166
+ const durationMs = Math.max(0, r.closedAtMs - r.openedAtMs);
167
+ const db = getDb();
168
+ await db.execute({
169
+ sql: `INSERT INTO kernel_session_log
170
+ (id, kernel_session_id, op, source, probe_run_id, user_id, stealth, headless_sent, proxy_used, proxy_source, proxy_type, fallback, opened_at, closed_at, duration_ms, est_cost_usd_headless, est_cost_usd_headful, error, method)
171
+ VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
172
+ args: [
173
+ randomUUID(),
174
+ r.kernelSessionId ?? null,
175
+ ctx?.op ?? null,
176
+ r.source,
177
+ ctx?.probeRunId ?? null,
178
+ ctx?.userId ?? null,
179
+ boolToInt(r.stealth),
180
+ boolToInt(r.headlessSent),
181
+ boolToInt(r.proxyUsed),
182
+ r.proxySource ?? null,
183
+ r.proxyType ?? null,
184
+ r.fallback ? 1 : 0,
185
+ new Date(r.openedAtMs).toISOString(),
186
+ new Date(r.closedAtMs).toISOString(),
187
+ durationMs,
188
+ kernelCostUsd(durationMs, false),
189
+ kernelCostUsd(durationMs, true),
190
+ r.error ?? null,
191
+ ctx?.subOp ?? null
192
+ ]
193
+ });
194
+ } catch (err) {
195
+ console.warn("[cost-telemetry] recordKernelSession failed:", err instanceof Error ? err.message : String(err));
196
+ }
197
+ }
198
+ async function recordVendorUsage(r) {
199
+ try {
200
+ await migrateCostTelemetry();
201
+ const ctx = currentCostContext();
202
+ const db = getDb();
203
+ await db.execute({
204
+ sql: `INSERT INTO vendor_usage_log
205
+ (id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error, method)
206
+ VALUES (?,?,?,?,?,?,?,?,?,?,?)`,
207
+ args: [
208
+ randomUUID(),
209
+ ctx?.op ?? null,
210
+ ctx?.probeRunId ?? null,
211
+ ctx?.userId ?? null,
212
+ r.vendor,
213
+ r.model ?? null,
214
+ r.units,
215
+ r.unitType,
216
+ vendorCostUsd(r.vendor, r.units),
217
+ r.error ?? null,
218
+ ctx?.subOp ?? null
219
+ ]
220
+ });
221
+ } catch (err) {
222
+ console.warn("[cost-telemetry] recordVendorUsage failed:", err instanceof Error ? err.message : String(err));
223
+ }
224
+ }
225
+ function boolToInt(v) {
226
+ if (v === null || v === void 0) return null;
227
+ return v ? 1 : 0;
228
+ }
229
+
230
+ export {
231
+ browserServiceApiKey,
232
+ browserServiceProxyId,
233
+ browserServiceProfileName,
234
+ browserServiceProfileSaveChanges,
235
+ runWithCostContext,
236
+ currentCostContext,
237
+ HEADLESS_OPS,
238
+ kernelCostUsd,
239
+ vendorCostUsd,
240
+ migrateCostTelemetry,
241
+ recordKernelSession,
242
+ recordVendorUsage
243
+ };
244
+ //# sourceMappingURL=chunk-UN7VMHZL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/browser-service-env.ts","../src/api/cost-context.ts","../src/api/cost-telemetry.ts","../src/api/cost-rates.ts"],"sourcesContent":["export function browserServiceApiKey(): string | undefined {\n const value = (process.env.BROWSER_SERVICE_API_KEY ?? process.env.KERNEL_API_KEY)?.trim()\n return value || undefined\n}\n\nexport function browserServiceProxyId(): string | undefined {\n return undefined\n}\n\nexport function browserServiceProfileName(): string | undefined {\n const value = (\n process.env.BROWSER_AGENT_PROFILE_NAME ??\n process.env.BROWSER_SERVICE_PROFILE_NAME ??\n process.env.KERNEL_BROWSER_PROFILE_NAME ??\n process.env.KERNEL_PROFILE_NAME\n )?.trim()\n return value || undefined\n}\n\nexport function browserServiceProfileSaveChanges(): boolean | undefined {\n const value = (\n process.env.BROWSER_AGENT_PROFILE_SAVE_CHANGES ??\n process.env.BROWSER_SERVICE_PROFILE_SAVE_CHANGES ??\n process.env.KERNEL_BROWSER_PROFILE_SAVE_CHANGES ??\n process.env.KERNEL_PROFILE_SAVE_CHANGES\n )?.trim().toLowerCase()\n if (!value) return undefined\n if (['1', 'true', 'yes', 'on'].includes(value)) return true\n if (['0', 'false', 'no', 'off'].includes(value)) return false\n return undefined\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\n\nexport interface CostContext {\n op: string\n probeRunId?: string | null\n userId?: number | null\n forceHeadless?: boolean\n forceHeadful?: boolean\n subOp?: string | null\n}\n\nconst storage = new AsyncLocalStorage<CostContext>()\n\nexport function runWithCostContext<T>(ctx: CostContext, fn: () => T): T {\n return storage.run(ctx, fn)\n}\n\nexport function currentCostContext(): CostContext | undefined {\n return storage.getStore()\n}\n","import { randomUUID } from 'node:crypto'\nimport { getDb } from './db.js'\nimport { currentCostContext } from './cost-context.js'\nimport { kernelCostUsd, vendorCostUsd } from './cost-rates.js'\n\nlet _ready = false\n\nexport async function migrateCostTelemetry(): Promise<void> {\n if (_ready) return\n const db = getDb()\n await db.execute(`\n CREATE TABLE IF NOT EXISTS kernel_session_log (\n id TEXT PRIMARY KEY,\n kernel_session_id TEXT,\n op TEXT,\n source TEXT NOT NULL,\n probe_run_id TEXT,\n user_id INTEGER,\n stealth INTEGER,\n headless_sent INTEGER,\n proxy_used INTEGER,\n fallback INTEGER NOT NULL DEFAULT 0,\n opened_at TEXT,\n closed_at TEXT,\n duration_ms INTEGER NOT NULL DEFAULT 0,\n est_cost_usd_headless REAL NOT NULL DEFAULT 0,\n est_cost_usd_headful REAL NOT NULL DEFAULT 0,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_op ON kernel_session_log(op)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_probe ON kernel_session_log(probe_run_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_created ON kernel_session_log(created_at)`)\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_source TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_type TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN method TEXT`) } catch { void 0 }\n await db.execute(`\n CREATE TABLE IF NOT EXISTS vendor_usage_log (\n id TEXT PRIMARY KEY,\n op TEXT,\n probe_run_id TEXT,\n user_id INTEGER,\n vendor TEXT NOT NULL,\n model TEXT,\n units REAL NOT NULL DEFAULT 0,\n unit_type TEXT,\n est_cost_usd REAL NOT NULL DEFAULT 0,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_op ON vendor_usage_log(op)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_probe ON vendor_usage_log(probe_run_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_created ON vendor_usage_log(created_at)`)\n try { await db.execute(`ALTER TABLE vendor_usage_log ADD COLUMN method TEXT`) } catch { void 0 }\n await db.execute(`\n CREATE TABLE IF NOT EXISTS cost_probe_runs (\n id TEXT PRIMARY KEY,\n tool TEXT NOT NULL,\n target TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n wall_ms INTEGER NOT NULL DEFAULT 0,\n success INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n http_only INTEGER NOT NULL DEFAULT 0,\n kernel_used INTEGER NOT NULL DEFAULT 0,\n kernel_sessions INTEGER NOT NULL DEFAULT 0,\n kernel_seconds_total REAL NOT NULL DEFAULT 0,\n kernel_tier_observed TEXT,\n est_kernel_cost_usd_headless REAL NOT NULL DEFAULT 0,\n est_kernel_cost_usd_headful REAL NOT NULL DEFAULT 0,\n vendor_cost_usd REAL NOT NULL DEFAULT 0,\n charged_credits REAL NOT NULL DEFAULT 0,\n margin_usd_headless_starter REAL NOT NULL DEFAULT 0,\n margin_usd_headful_starter REAL NOT NULL DEFAULT 0,\n notes TEXT\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS cost_probe_runs_tool ON cost_probe_runs(tool)`)\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN units REAL`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN unit_type TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN mode TEXT`) } catch { void 0 }\n _ready = true\n}\n\nexport interface KernelSessionRecord {\n kernelSessionId?: string | null\n source: string\n stealth?: boolean | null\n headlessSent?: boolean | null\n proxyUsed?: boolean | null\n proxySource?: string | null\n proxyType?: string | null\n fallback?: boolean\n openedAtMs: number\n closedAtMs: number\n error?: string | null\n}\n\nexport async function recordKernelSession(r: KernelSessionRecord): Promise<void> {\n try {\n await migrateCostTelemetry()\n const ctx = currentCostContext()\n const durationMs = Math.max(0, r.closedAtMs - r.openedAtMs)\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO kernel_session_log\n (id, kernel_session_id, op, source, probe_run_id, user_id, stealth, headless_sent, proxy_used, proxy_source, proxy_type, fallback, opened_at, closed_at, duration_ms, est_cost_usd_headless, est_cost_usd_headful, error, method)\n VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n randomUUID(),\n r.kernelSessionId ?? null,\n ctx?.op ?? null,\n r.source,\n ctx?.probeRunId ?? null,\n ctx?.userId ?? null,\n boolToInt(r.stealth),\n boolToInt(r.headlessSent),\n boolToInt(r.proxyUsed),\n r.proxySource ?? null,\n r.proxyType ?? null,\n r.fallback ? 1 : 0,\n new Date(r.openedAtMs).toISOString(),\n new Date(r.closedAtMs).toISOString(),\n durationMs,\n kernelCostUsd(durationMs, false),\n kernelCostUsd(durationMs, true),\n r.error ?? null,\n ctx?.subOp ?? null,\n ],\n })\n } catch (err) {\n console.warn('[cost-telemetry] recordKernelSession failed:', err instanceof Error ? err.message : String(err))\n }\n}\n\nexport interface VendorUsageRecord {\n vendor: string\n model?: string | null\n units: number\n unitType: string\n error?: string | null\n}\n\nexport async function recordVendorUsage(r: VendorUsageRecord): Promise<void> {\n try {\n await migrateCostTelemetry()\n const ctx = currentCostContext()\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO vendor_usage_log\n (id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error, method)\n VALUES (?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n randomUUID(),\n ctx?.op ?? null,\n ctx?.probeRunId ?? null,\n ctx?.userId ?? null,\n r.vendor,\n r.model ?? null,\n r.units,\n r.unitType,\n vendorCostUsd(r.vendor, r.units),\n r.error ?? null,\n ctx?.subOp ?? null,\n ],\n })\n } catch (err) {\n console.warn('[cost-telemetry] recordVendorUsage failed:', err instanceof Error ? err.message : String(err))\n }\n}\n\nexport interface ProbeRunRecord {\n id: string\n tool: string\n target?: string | null\n wallMs: number\n success: boolean\n error?: string | null\n httpOnly: boolean\n kernelUsed: boolean\n kernelSessions: number\n kernelSecondsTotal: number\n kernelTierObserved?: string | null\n estKernelCostUsdHeadless: number\n estKernelCostUsdHeadful: number\n vendorCostUsd: number\n chargedCredits: number\n marginUsdHeadlessStarter: number\n marginUsdHeadfulStarter: number\n units?: number | null\n unitType?: string | null\n mode?: string | null\n notes?: string | null\n}\n\nexport async function recordProbeRun(r: ProbeRunRecord): Promise<void> {\n await migrateCostTelemetry()\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO cost_probe_runs\n (id, tool, target, wall_ms, success, error, http_only, kernel_used, kernel_sessions, kernel_seconds_total, kernel_tier_observed, est_kernel_cost_usd_headless, est_kernel_cost_usd_headful, vendor_cost_usd, charged_credits, margin_usd_headless_starter, margin_usd_headful_starter, units, unit_type, mode, notes)\n VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n r.id, r.tool, r.target ?? null, r.wallMs, r.success ? 1 : 0, r.error ?? null,\n r.httpOnly ? 1 : 0, r.kernelUsed ? 1 : 0, r.kernelSessions, r.kernelSecondsTotal,\n r.kernelTierObserved ?? null, r.estKernelCostUsdHeadless, r.estKernelCostUsdHeadful,\n r.vendorCostUsd, r.chargedCredits, r.marginUsdHeadlessStarter, r.marginUsdHeadfulStarter,\n r.units ?? null, r.unitType ?? null, r.mode ?? null, r.notes ?? null,\n ],\n })\n}\n\nfunction boolToInt(v: boolean | null | undefined): number | null {\n if (v === null || v === undefined) return null\n return v ? 1 : 0\n}\n","export const KERNEL_HEADLESS_USD_PER_SEC = 0.0000166667\nexport const KERNEL_HEADFUL_USD_PER_SEC = 0.0001333336\n\nexport const HEADLESS_OPS = new Set<string>(['serp', 'maps_search', 'yt_channel', 'yt_transcription', 'fb_search', 'fb_ad', 'instagram'])\n\nexport const FAL_WIZPER_USD_PER_COMPUTE_SEC = 0.00111\nexport const FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR = 4 // calibrated from 2 real Fal invoices (4.36x, 6.18x wall-clock vs actual)\nexport const DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS = 0.0004\n\nexport function kernelCostUsd(ms: number, headful: boolean): number {\n const sec = Math.max(0, ms) / 1000\n return sec * (headful ? KERNEL_HEADFUL_USD_PER_SEC : KERNEL_HEADLESS_USD_PER_SEC)\n}\n\nexport function vendorCostUsd(vendor: string, units: number): number {\n if (vendor === 'fal_wizper') {\n const estimatedComputeSec = Math.max(0, units) / FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR\n return estimatedComputeSec * FAL_WIZPER_USD_PER_COMPUTE_SEC\n }\n if (vendor === 'deepinfra_qwen') return (Math.max(0, units) / 1000) * DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS\n if (vendor === 'openrouter') return Math.max(0, units) // units IS the real USD cost OpenRouter reported, not a rate-multiplied estimate\n if (vendor === 'mcp_memory_video') return Math.max(0, units) // units IS the real costUsd mcp-memory's video pipeline reported (OpenRouter + transcription)\n if (vendor === 'mcp_memory_ai') return Math.max(0, units) // units IS the real costUsd mcp-memory reported via /ai-debit\n return 0\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,11 @@
1
1
  import {
2
+ HEADLESS_OPS,
2
3
  browserServiceApiKey,
3
- browserServiceProxyId
4
- } from "./chunk-HPV4VOQX.js";
4
+ browserServiceProxyId,
5
+ currentCostContext,
6
+ recordKernelSession,
7
+ runWithCostContext
8
+ } from "./chunk-UN7VMHZL.js";
5
9
  import {
6
10
  postToMemoryLibrary
7
11
  } from "./chunk-K443GQY5.js";
@@ -18,214 +22,6 @@ import {
18
22
  RequestAbortedError,
19
23
  sanitizeVendorName
20
24
  } from "./chunk-M2S27J6Z.js";
21
- import {
22
- getDb
23
- } from "./chunk-GL4BW4CP.js";
24
-
25
- // src/api/cost-context.ts
26
- import { AsyncLocalStorage } from "async_hooks";
27
- var storage = new AsyncLocalStorage();
28
- function runWithCostContext(ctx, fn) {
29
- return storage.run(ctx, fn);
30
- }
31
- function currentCostContext() {
32
- return storage.getStore();
33
- }
34
-
35
- // src/api/cost-telemetry.ts
36
- import { randomUUID } from "crypto";
37
-
38
- // src/api/cost-rates.ts
39
- var KERNEL_HEADLESS_USD_PER_SEC = 166667e-10;
40
- var KERNEL_HEADFUL_USD_PER_SEC = 1333336e-10;
41
- var HEADLESS_OPS = /* @__PURE__ */ new Set(["serp", "maps_search", "yt_channel", "yt_transcription", "fb_search", "fb_ad", "instagram"]);
42
- var FAL_WIZPER_USD_PER_COMPUTE_SEC = 111e-5;
43
- var FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR = 4;
44
- var DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS = 4e-4;
45
- function kernelCostUsd(ms, headful) {
46
- const sec = Math.max(0, ms) / 1e3;
47
- return sec * (headful ? KERNEL_HEADFUL_USD_PER_SEC : KERNEL_HEADLESS_USD_PER_SEC);
48
- }
49
- function vendorCostUsd(vendor, units) {
50
- if (vendor === "fal_wizper") {
51
- const estimatedComputeSec = Math.max(0, units) / FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR;
52
- return estimatedComputeSec * FAL_WIZPER_USD_PER_COMPUTE_SEC;
53
- }
54
- if (vendor === "deepinfra_qwen") return Math.max(0, units) / 1e3 * DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS;
55
- if (vendor === "openrouter") return Math.max(0, units);
56
- if (vendor === "mcp_memory_video") return Math.max(0, units);
57
- if (vendor === "mcp_memory_ai") return Math.max(0, units);
58
- return 0;
59
- }
60
-
61
- // src/api/cost-telemetry.ts
62
- var _ready = false;
63
- async function migrateCostTelemetry() {
64
- if (_ready) return;
65
- const db = getDb();
66
- await db.execute(`
67
- CREATE TABLE IF NOT EXISTS kernel_session_log (
68
- id TEXT PRIMARY KEY,
69
- kernel_session_id TEXT,
70
- op TEXT,
71
- source TEXT NOT NULL,
72
- probe_run_id TEXT,
73
- user_id INTEGER,
74
- stealth INTEGER,
75
- headless_sent INTEGER,
76
- proxy_used INTEGER,
77
- fallback INTEGER NOT NULL DEFAULT 0,
78
- opened_at TEXT,
79
- closed_at TEXT,
80
- duration_ms INTEGER NOT NULL DEFAULT 0,
81
- est_cost_usd_headless REAL NOT NULL DEFAULT 0,
82
- est_cost_usd_headful REAL NOT NULL DEFAULT 0,
83
- error TEXT,
84
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
85
- )
86
- `);
87
- await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_op ON kernel_session_log(op)`);
88
- await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_probe ON kernel_session_log(probe_run_id)`);
89
- await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_created ON kernel_session_log(created_at)`);
90
- try {
91
- await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_source TEXT`);
92
- } catch {
93
- }
94
- try {
95
- await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_type TEXT`);
96
- } catch {
97
- }
98
- try {
99
- await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN method TEXT`);
100
- } catch {
101
- }
102
- await db.execute(`
103
- CREATE TABLE IF NOT EXISTS vendor_usage_log (
104
- id TEXT PRIMARY KEY,
105
- op TEXT,
106
- probe_run_id TEXT,
107
- user_id INTEGER,
108
- vendor TEXT NOT NULL,
109
- model TEXT,
110
- units REAL NOT NULL DEFAULT 0,
111
- unit_type TEXT,
112
- est_cost_usd REAL NOT NULL DEFAULT 0,
113
- error TEXT,
114
- created_at TEXT NOT NULL DEFAULT (datetime('now'))
115
- )
116
- `);
117
- await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_op ON vendor_usage_log(op)`);
118
- await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_probe ON vendor_usage_log(probe_run_id)`);
119
- await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_created ON vendor_usage_log(created_at)`);
120
- try {
121
- await db.execute(`ALTER TABLE vendor_usage_log ADD COLUMN method TEXT`);
122
- } catch {
123
- }
124
- await db.execute(`
125
- CREATE TABLE IF NOT EXISTS cost_probe_runs (
126
- id TEXT PRIMARY KEY,
127
- tool TEXT NOT NULL,
128
- target TEXT,
129
- started_at TEXT NOT NULL DEFAULT (datetime('now')),
130
- wall_ms INTEGER NOT NULL DEFAULT 0,
131
- success INTEGER NOT NULL DEFAULT 0,
132
- error TEXT,
133
- http_only INTEGER NOT NULL DEFAULT 0,
134
- kernel_used INTEGER NOT NULL DEFAULT 0,
135
- kernel_sessions INTEGER NOT NULL DEFAULT 0,
136
- kernel_seconds_total REAL NOT NULL DEFAULT 0,
137
- kernel_tier_observed TEXT,
138
- est_kernel_cost_usd_headless REAL NOT NULL DEFAULT 0,
139
- est_kernel_cost_usd_headful REAL NOT NULL DEFAULT 0,
140
- vendor_cost_usd REAL NOT NULL DEFAULT 0,
141
- charged_credits REAL NOT NULL DEFAULT 0,
142
- margin_usd_headless_starter REAL NOT NULL DEFAULT 0,
143
- margin_usd_headful_starter REAL NOT NULL DEFAULT 0,
144
- notes TEXT
145
- )
146
- `);
147
- await db.execute(`CREATE INDEX IF NOT EXISTS cost_probe_runs_tool ON cost_probe_runs(tool)`);
148
- try {
149
- await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN units REAL`);
150
- } catch {
151
- }
152
- try {
153
- await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN unit_type TEXT`);
154
- } catch {
155
- }
156
- try {
157
- await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN mode TEXT`);
158
- } catch {
159
- }
160
- _ready = true;
161
- }
162
- async function recordKernelSession(r) {
163
- try {
164
- await migrateCostTelemetry();
165
- const ctx = currentCostContext();
166
- const durationMs = Math.max(0, r.closedAtMs - r.openedAtMs);
167
- const db = getDb();
168
- await db.execute({
169
- sql: `INSERT INTO kernel_session_log
170
- (id, kernel_session_id, op, source, probe_run_id, user_id, stealth, headless_sent, proxy_used, proxy_source, proxy_type, fallback, opened_at, closed_at, duration_ms, est_cost_usd_headless, est_cost_usd_headful, error, method)
171
- VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
172
- args: [
173
- randomUUID(),
174
- r.kernelSessionId ?? null,
175
- ctx?.op ?? null,
176
- r.source,
177
- ctx?.probeRunId ?? null,
178
- ctx?.userId ?? null,
179
- boolToInt(r.stealth),
180
- boolToInt(r.headlessSent),
181
- boolToInt(r.proxyUsed),
182
- r.proxySource ?? null,
183
- r.proxyType ?? null,
184
- r.fallback ? 1 : 0,
185
- new Date(r.openedAtMs).toISOString(),
186
- new Date(r.closedAtMs).toISOString(),
187
- durationMs,
188
- kernelCostUsd(durationMs, false),
189
- kernelCostUsd(durationMs, true),
190
- r.error ?? null,
191
- ctx?.subOp ?? null
192
- ]
193
- });
194
- } catch (err) {
195
- console.warn("[cost-telemetry] recordKernelSession failed:", err instanceof Error ? err.message : String(err));
196
- }
197
- }
198
- async function recordVendorUsage(r) {
199
- try {
200
- await migrateCostTelemetry();
201
- const ctx = currentCostContext();
202
- const db = getDb();
203
- await db.execute({
204
- sql: `INSERT INTO vendor_usage_log
205
- (id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error, method)
206
- VALUES (?,?,?,?,?,?,?,?,?,?,?)`,
207
- args: [
208
- randomUUID(),
209
- ctx?.op ?? null,
210
- ctx?.probeRunId ?? null,
211
- ctx?.userId ?? null,
212
- r.vendor,
213
- r.model ?? null,
214
- r.units,
215
- r.unitType,
216
- vendorCostUsd(r.vendor, r.units),
217
- r.error ?? null,
218
- ctx?.subOp ?? null
219
- ]
220
- });
221
- } catch (err) {
222
- console.warn("[cost-telemetry] recordVendorUsage failed:", err instanceof Error ? err.message : String(err));
223
- }
224
- }
225
- function boolToInt(v) {
226
- if (v === null || v === void 0) return null;
227
- return v ? 1 : 0;
228
- }
229
25
 
230
26
  // src/driver/BrowserDriver.ts
231
27
  import { chromium } from "playwright-extra";
@@ -3356,17 +3152,10 @@ async function harvest(rawOptions) {
3356
3152
 
3357
3153
  export {
3358
3154
  MapsSelectors,
3359
- runWithCostContext,
3360
- currentCostContext,
3361
- kernelCostUsd,
3362
- vendorCostUsd,
3363
- migrateCostTelemetry,
3364
- recordKernelSession,
3365
- recordVendorUsage,
3366
3155
  buildYouTubeChannelVideosUrl,
3367
3156
  BrowserDriver,
3368
3157
  deleteKernelProxyId,
3369
3158
  resolveKernelProxyId,
3370
3159
  harvest
3371
3160
  };
3372
- //# sourceMappingURL=chunk-RMPPYKUV.js.map
3161
+ //# sourceMappingURL=chunk-XDFSLSSH.js.map