unbrowse 3.2.2 → 3.2.3-experiments.8932456

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.
package/dist/cli.js CHANGED
@@ -31,7 +31,7 @@ var __promiseAll = (args) => Promise.all(args);
31
31
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
32
32
 
33
33
  // ../../src/build-info.generated.ts
34
- var BUILD_RELEASE_VERSION = "3.2.2", BUILD_GIT_SHA = "150cce0d751e", BUILD_CODE_HASH = "1488fc1d92b7", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy4yLjIiLCJnaXRfc2hhIjoiMTUwY2NlMGQ3NTFlIiwiY29kZV9oYXNoIjoiMTQ4OGZjMWQ5MmI3IiwidHJhY2VfdmVyc2lvbiI6IjE0ODhmYzFkOTJiN0AxNTBjY2UwZDc1MWUiLCJpc3N1ZWRfYXQiOiIyMDI2LTA0LTA2VDA4OjQ2OjM5LjIwNVoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "ZS7C10DGuwyn1m02shMHyz6cN5UbTHfa8yqnkELg_L8", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
34
+ var BUILD_RELEASE_VERSION = "3.2.3-experiments.8932456", BUILD_GIT_SHA = "8932456cbb1b", BUILD_CODE_HASH = "1488fc1d92b7", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy4yLjMtZXhwZXJpbWVudHMuODkzMjQ1NiIsImdpdF9zaGEiOiI4OTMyNDU2Y2JiMWIiLCJjb2RlX2hhc2giOiIxNDg4ZmMxZDkyYjciLCJ0cmFjZV92ZXJzaW9uIjoiMTQ4OGZjMWQ5MmI3QDg5MzI0NTZjYmIxYiIsImlzc3VlZF9hdCI6IjIwMjYtMDQtMDZUMTQ6NTk6MjUuNDA0WiJ9", BUILD_RELEASE_MANIFEST_SIGNATURE = "_zjmqCbUpLNUj6AhAJLMM2G5AAA35LhChNY_EgKZmM8", BUILD_DEFAULT_BACKEND_URL = "https://unbrowse-backend-experiments.lewis-6d8.workers.dev";
35
35
 
36
36
  // ../../src/version.ts
37
37
  import { createHash } from "crypto";
@@ -679,23 +679,6 @@ var init_telemetry = __esm(() => {
679
679
  autoFiledKeys = new Set;
680
680
  });
681
681
 
682
- // ../../src/runtime/browser-access.ts
683
- var init_browser_access = () => {};
684
-
685
- // ../../src/capture/index.ts
686
- import { nanoid as nanoid2 } from "nanoid";
687
- var activeTabRegistry, interceptorInjectedTabs, cdpDocStartTabs, cdpCapturedHeaders;
688
- var init_capture = __esm(() => {
689
- init_client2();
690
- init_domain();
691
- init_logger();
692
- init_browser_access();
693
- activeTabRegistry = new Set;
694
- interceptorInjectedTabs = new Set;
695
- cdpDocStartTabs = new Set;
696
- cdpCapturedHeaders = new Map;
697
- });
698
-
699
682
  // ../../src/transform/index.ts
700
683
  var EPHEMERAL_KEYS;
701
684
  var init_transform = __esm(() => {
@@ -704,7 +687,7 @@ var init_transform = __esm(() => {
704
687
 
705
688
  // ../../src/debug-trace.ts
706
689
  import { join as join6 } from "node:path";
707
- import { nanoid as nanoid3 } from "nanoid";
690
+ import { nanoid as nanoid2 } from "nanoid";
708
691
  var TRACE_DIR;
709
692
  var init_debug_trace = __esm(() => {
710
693
  TRACE_DIR = process.env.TRACES_DIR ?? join6(process.cwd(), "traces");
@@ -719,7 +702,7 @@ var init_description_prompt = __esm(() => {
719
702
  init_sanitize();
720
703
  });
721
704
  // ../../src/reverse-engineer/index.ts
722
- import { nanoid as nanoid4 } from "nanoid";
705
+ import { nanoid as nanoid3 } from "nanoid";
723
706
  var ALLOWED_METHODS, STRIP_HEADERS, REPLAY_HEADER_EXACT, SAFE_HEADERS, AD_SCHEMA_KEYS;
724
707
  var init_reverse_engineer = __esm(() => {
725
708
  init_transform();
@@ -791,19 +774,6 @@ var init_reverse_engineer = __esm(() => {
791
774
  ]);
792
775
  });
793
776
 
794
- // ../../src/reverse-engineer/bundle-scanner.ts
795
- var init_bundle_scanner = __esm(() => {
796
- init_logger();
797
- });
798
-
799
- // ../../src/reverse-engineer/token-sources.ts
800
- var init_token_sources = () => {};
801
-
802
- // ../../src/execution/token-resolver.ts
803
- var init_token_resolver = __esm(() => {
804
- init_token_sources();
805
- });
806
-
807
777
  // ../../src/vault/index.ts
808
778
  import { join as join7 } from "path";
809
779
  import { homedir as homedir5 } from "os";
@@ -834,6 +804,38 @@ var init_vault = __esm(async () => {
834
804
  vaultLock = Promise.resolve();
835
805
  });
836
806
 
807
+ // ../../src/runtime/browser-access.ts
808
+ var init_browser_access = () => {};
809
+
810
+ // ../../src/capture/index.ts
811
+ import { nanoid as nanoid4 } from "nanoid";
812
+ var activeTabRegistry, interceptorInjectedTabs, cdpDocStartTabs, cdpCapturedHeaders;
813
+ var init_capture = __esm(async () => {
814
+ init_client2();
815
+ init_domain();
816
+ init_logger();
817
+ init_reverse_engineer();
818
+ init_browser_access();
819
+ await init_vault();
820
+ activeTabRegistry = new Set;
821
+ interceptorInjectedTabs = new Set;
822
+ cdpDocStartTabs = new Set;
823
+ cdpCapturedHeaders = new Map;
824
+ });
825
+
826
+ // ../../src/reverse-engineer/bundle-scanner.ts
827
+ var init_bundle_scanner = __esm(() => {
828
+ init_logger();
829
+ });
830
+
831
+ // ../../src/reverse-engineer/token-sources.ts
832
+ var init_token_sources = () => {};
833
+
834
+ // ../../src/execution/token-resolver.ts
835
+ var init_token_resolver = __esm(() => {
836
+ init_token_sources();
837
+ });
838
+
837
839
  // ../../src/auth/index.ts
838
840
  var init_auth = __esm(async () => {
839
841
  init_client2();
@@ -1018,8 +1020,6 @@ var init_compile = () => {};
1018
1020
  import { nanoid as nanoid6 } from "nanoid";
1019
1021
  var VALID_VERIFICATION_STATUSES, STOPWORDS;
1020
1022
  var init_execution = __esm(async () => {
1021
- init_capture();
1022
- init_capture();
1023
1023
  init_reverse_engineer();
1024
1024
  init_bundle_scanner();
1025
1025
  init_token_resolver();
@@ -1043,6 +1043,8 @@ var init_execution = __esm(async () => {
1043
1043
  init_compile();
1044
1044
  init_publish();
1045
1045
  await __promiseAll([
1046
+ init_capture(),
1047
+ init_capture(),
1046
1048
  init_vault(),
1047
1049
  init_auth(),
1048
1050
  init_indexer(),
package/dist/mcp.js CHANGED
@@ -225,12 +225,12 @@ import { dirname, join, parse } from "path";
225
225
  import { fileURLToPath as fileURLToPath2 } from "url";
226
226
 
227
227
  // ../../src/build-info.generated.ts
228
- var BUILD_RELEASE_VERSION = "3.2.2";
229
- var BUILD_GIT_SHA = "150cce0d751e";
228
+ var BUILD_RELEASE_VERSION = "3.2.3-experiments.8932456";
229
+ var BUILD_GIT_SHA = "8932456cbb1b";
230
230
  var BUILD_CODE_HASH = "1488fc1d92b7";
231
- var BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy4yLjIiLCJnaXRfc2hhIjoiMTUwY2NlMGQ3NTFlIiwiY29kZV9oYXNoIjoiMTQ4OGZjMWQ5MmI3IiwidHJhY2VfdmVyc2lvbiI6IjE0ODhmYzFkOTJiN0AxNTBjY2UwZDc1MWUiLCJpc3N1ZWRfYXQiOiIyMDI2LTA0LTA2VDA4OjQ2OjM5LjIwNVoifQ";
232
- var BUILD_RELEASE_MANIFEST_SIGNATURE = "ZS7C10DGuwyn1m02shMHyz6cN5UbTHfa8yqnkELg_L8";
233
- var BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
231
+ var BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy4yLjMtZXhwZXJpbWVudHMuODkzMjQ1NiIsImdpdF9zaGEiOiI4OTMyNDU2Y2JiMWIiLCJjb2RlX2hhc2giOiIxNDg4ZmMxZDkyYjciLCJ0cmFjZV92ZXJzaW9uIjoiMTQ4OGZjMWQ5MmI3QDg5MzI0NTZjYmIxYiIsImlzc3VlZF9hdCI6IjIwMjYtMDQtMDZUMTQ6NTk6MjUuNDA0WiJ9";
232
+ var BUILD_RELEASE_MANIFEST_SIGNATURE = "_zjmqCbUpLNUj6AhAJLMM2G5AAA35LhChNY_EgKZmM8";
233
+ var BUILD_DEFAULT_BACKEND_URL = "https://unbrowse-backend-experiments.lewis-6d8.workers.dev";
234
234
 
235
235
  // ../../src/version.ts
236
236
  var MODULE_DIR = dirname(fileURLToPath2(import.meta.url));
package/dist/server.js CHANGED
@@ -4299,7 +4299,12 @@ function extractEndpoints(requests, wsMessages, context) {
4299
4299
  const sanitizedQParams = isGet ? sanitizeQueryParams(extractQueryParams(req.url)) : undefined;
4300
4300
  let pathTemplate = sanitizeUrlTemplate(normalized);
4301
4301
  const qBindings = sanitizedQParams ? buildQueryBindingMap(Object.keys(sanitizedQParams)) : {};
4302
- const qTemplateStr = sanitizedQParams && Object.keys(sanitizedQParams).length > 0 ? Object.keys(sanitizedQParams).map((k) => `${encodeURIComponent(k)}={${qBindings[k] ?? k}}`).join("&") : null;
4302
+ const existingQKeys = new Set;
4303
+ try {
4304
+ for (const k of new URL(pathTemplate).searchParams.keys())
4305
+ existingQKeys.add(k.toLowerCase());
4306
+ } catch {}
4307
+ const qTemplateStr = sanitizedQParams && Object.keys(sanitizedQParams).length > 0 ? Object.keys(sanitizedQParams).filter((k) => !existingQKeys.has(k.toLowerCase())).map((k) => `${encodeURIComponent(k)}={${qBindings[k] ?? k}}`).join("&") || null : null;
4303
4308
  const { url: templatizedPath, pathParams, pathBindingCandidates } = templatizePathSegments(pathTemplate, req.url, context);
4304
4309
  pathTemplate = templatizedPath;
4305
4310
  const parsedRequestBody = !isGet && req.request_body ? tryParseBody(req.request_body) : undefined;
@@ -4315,7 +4320,7 @@ function extractEndpoints(requests, wsMessages, context) {
4315
4320
  let endpoint = {
4316
4321
  endpoint_id: nanoid2(),
4317
4322
  method: req.method,
4318
- url_template: qTemplateStr ? `${pathTemplate}?${qTemplateStr}` : pathTemplate,
4323
+ url_template: qTemplateStr ? `${pathTemplate}${pathTemplate.includes("?") ? "&" : "?"}${qTemplateStr}` : pathTemplate,
4319
4324
  description: buildEndpointDescription(req, sampleRequest, sampleResponse),
4320
4325
  headers_template: sanitizeHeaders(req.request_headers),
4321
4326
  query: sanitizedQParams,
@@ -5027,6 +5032,179 @@ var init_reverse_engineer = __esm(() => {
5027
5032
  ON_DOMAIN_NOISE = /\/(recaptcha|captcha|update-recaptcha|csrf|consent|data-protection|badge|drawer|header-action|geolocation|onboarding|wana\/bids|prebid|bids\/request|ads\/|pixel|beacon|collect|impression|click-tracking|heartbeat|webConfig|config\.json|manifest\.json|service-worker|sw\.js|favicon|robots\.txt|sitemap|opensearch|partial\/[a-zA-Z]+\/mod-|logging|csp-report|gen_204|generate_204|sodar|__webpack|__next|devvit-|user-drawer|action-item)/i;
5028
5033
  });
5029
5034
 
5035
+ // ../../src/vault/index.ts
5036
+ var exports_vault = {};
5037
+ __export(exports_vault, {
5038
+ storeCredential: () => storeCredential,
5039
+ setKeytarClientForTests: () => setKeytarClientForTests,
5040
+ resetKeytarClientForTests: () => resetKeytarClientForTests,
5041
+ normalizeKeytarModule: () => normalizeKeytarModule,
5042
+ getCredential: () => getCredential,
5043
+ deleteCredential: () => deleteCredential
5044
+ });
5045
+ import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
5046
+ import { existsSync as existsSync3, mkdirSync as mkdirSync3, readFileSync, writeFileSync as writeFileSync2 } from "fs";
5047
+ import { join as join2 } from "path";
5048
+ import { homedir } from "os";
5049
+ function normalizeKeytarModule(mod) {
5050
+ let candidate = mod;
5051
+ for (let depth = 0;depth < 3; depth++) {
5052
+ if (!candidate || typeof candidate !== "object" || !("default" in candidate))
5053
+ break;
5054
+ candidate = candidate.default;
5055
+ }
5056
+ if (!candidate)
5057
+ return null;
5058
+ if (typeof candidate.setPassword === "function" && typeof candidate.getPassword === "function" && typeof candidate.deletePassword === "function") {
5059
+ return candidate;
5060
+ }
5061
+ return null;
5062
+ }
5063
+ function isKeytarBindingError(error) {
5064
+ const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
5065
+ return KEYTAR_BINDING_ERROR_RE.test(message);
5066
+ }
5067
+ function disableKeytar(error) {
5068
+ keytar = null;
5069
+ if (keytarFallbackLogged)
5070
+ return;
5071
+ const summary = error instanceof Error ? error.message : String(error);
5072
+ log("vault", `keytar runtime unavailable (${summary}); using encrypted file fallback`);
5073
+ keytarFallbackLogged = true;
5074
+ }
5075
+ async function callKeytar(op) {
5076
+ if (!keytar)
5077
+ return KEYTAR_UNAVAILABLE;
5078
+ try {
5079
+ return await op(keytar);
5080
+ } catch (error) {
5081
+ if (!isKeytarBindingError(error))
5082
+ throw error;
5083
+ disableKeytar(error);
5084
+ return KEYTAR_UNAVAILABLE;
5085
+ }
5086
+ }
5087
+ function setKeytarClientForTests(client) {
5088
+ keytar = client;
5089
+ keytarFallbackLogged = false;
5090
+ }
5091
+ function resetKeytarClientForTests() {
5092
+ keytar = importedKeytar;
5093
+ keytarFallbackLogged = false;
5094
+ }
5095
+ function getOrCreateKey() {
5096
+ if (!existsSync3(VAULT_DIR))
5097
+ mkdirSync3(VAULT_DIR, { recursive: true, mode: 448 });
5098
+ if (existsSync3(KEY_FILE))
5099
+ return readFileSync(KEY_FILE);
5100
+ const key = randomBytes(32);
5101
+ writeFileSync2(KEY_FILE, key, { mode: 384 });
5102
+ return key;
5103
+ }
5104
+ function withVaultLock(fn) {
5105
+ const prev = vaultLock;
5106
+ let release;
5107
+ vaultLock = new Promise((r) => {
5108
+ release = r;
5109
+ });
5110
+ return prev.then(fn).finally(() => release());
5111
+ }
5112
+ function readVaultFile() {
5113
+ if (!existsSync3(VAULT_FILE))
5114
+ return {};
5115
+ try {
5116
+ const key = getOrCreateKey();
5117
+ const raw = readFileSync(VAULT_FILE);
5118
+ const iv = raw.subarray(0, 16);
5119
+ const enc = raw.subarray(16);
5120
+ const decipher = createDecipheriv("aes-256-cbc", key, iv);
5121
+ const dec = Buffer.concat([decipher.update(enc), decipher.final()]);
5122
+ return JSON.parse(dec.toString("utf8"));
5123
+ } catch {
5124
+ return {};
5125
+ }
5126
+ }
5127
+ function writeVaultFile(data) {
5128
+ const key = getOrCreateKey();
5129
+ const iv = randomBytes(16);
5130
+ const cipher = createCipheriv("aes-256-cbc", key, iv);
5131
+ const enc = Buffer.concat([cipher.update(JSON.stringify(data), "utf8"), cipher.final()]);
5132
+ writeFileSync2(VAULT_FILE, Buffer.concat([iv, enc]), { mode: 384 });
5133
+ }
5134
+ async function storeCredential(account, value, opts) {
5135
+ const wrapped = {
5136
+ value,
5137
+ stored_at: new Date().toISOString(),
5138
+ expires_at: opts?.expires_at,
5139
+ max_age_ms: opts?.max_age_ms
5140
+ };
5141
+ const serialized = JSON.stringify(wrapped);
5142
+ const keytarResult = await callKeytar((client) => client.setPassword(SERVICE, account, serialized));
5143
+ if (keytarResult !== KEYTAR_UNAVAILABLE)
5144
+ return;
5145
+ await withVaultLock(() => {
5146
+ const data = readVaultFile();
5147
+ data[account] = serialized;
5148
+ writeVaultFile(data);
5149
+ });
5150
+ }
5151
+ function isExpired(cred) {
5152
+ if (cred.expires_at) {
5153
+ return new Date(cred.expires_at).getTime() <= Date.now();
5154
+ }
5155
+ if (cred.max_age_ms) {
5156
+ return new Date(cred.stored_at).getTime() + cred.max_age_ms <= Date.now();
5157
+ }
5158
+ return false;
5159
+ }
5160
+ async function getCredential(account) {
5161
+ let raw;
5162
+ const keytarResult = await callKeytar((client) => client.getPassword(SERVICE, account));
5163
+ if (keytarResult !== KEYTAR_UNAVAILABLE) {
5164
+ raw = keytarResult;
5165
+ } else {
5166
+ const data = readVaultFile();
5167
+ raw = data[account] ?? null;
5168
+ }
5169
+ if (!raw)
5170
+ return null;
5171
+ try {
5172
+ const parsed = JSON.parse(raw);
5173
+ if (parsed.value && parsed.stored_at) {
5174
+ if (isExpired(parsed)) {
5175
+ await deleteCredential(account);
5176
+ return null;
5177
+ }
5178
+ return parsed.value;
5179
+ }
5180
+ } catch {}
5181
+ return raw;
5182
+ }
5183
+ async function deleteCredential(account) {
5184
+ const keytarResult = await callKeytar((client) => client.deletePassword(SERVICE, account));
5185
+ if (keytarResult !== KEYTAR_UNAVAILABLE)
5186
+ return;
5187
+ await withVaultLock(() => {
5188
+ const data = readVaultFile();
5189
+ delete data[account];
5190
+ writeVaultFile(data);
5191
+ });
5192
+ }
5193
+ var KEYTAR_UNAVAILABLE, KEYTAR_BINDING_ERROR_RE, keytar = null, importedKeytar, keytarFallbackLogged = false, SERVICE = "unbrowse", VAULT_DIR, VAULT_FILE, KEY_FILE, vaultLock;
5194
+ var init_vault = __esm(async () => {
5195
+ init_logger();
5196
+ KEYTAR_UNAVAILABLE = Symbol("KEYTAR_UNAVAILABLE");
5197
+ KEYTAR_BINDING_ERROR_RE = /(keytar(?:\.node)?|native bindings?|bindings file|no native build was found|could not locate the bindings file|module did not self-register|err_dlopen_failed|dlopen\(|compiled against a different node\.js version|cannot find module .*keytar|wasm is not supported on this platform|(set|get|delete)password is not a function)/i;
5198
+ try {
5199
+ keytar = normalizeKeytarModule(await import("keytar"));
5200
+ } catch {}
5201
+ importedKeytar = keytar;
5202
+ VAULT_DIR = join2(homedir(), ".unbrowse", "vault");
5203
+ VAULT_FILE = join2(VAULT_DIR, "credentials.enc");
5204
+ KEY_FILE = join2(VAULT_DIR, ".key");
5205
+ vaultLock = Promise.resolve();
5206
+ });
5207
+
5030
5208
  // ../../src/runtime/browser-access.ts
5031
5209
  var DEFAULT_BROWSER_ACCESS;
5032
5210
  var init_browser_access = __esm(() => {
@@ -5477,7 +5655,12 @@ function normalizeCapturedUrl(url, baseUrl) {
5477
5655
  if (!url)
5478
5656
  return url;
5479
5657
  try {
5480
- return new URL(url).toString();
5658
+ const parsed = new URL(url);
5659
+ if (baseUrl && (parsed.hostname === "127.0.0.1" || parsed.hostname === "localhost")) {
5660
+ const pageOrigin = new URL(baseUrl).origin;
5661
+ return `${pageOrigin}${parsed.pathname}${parsed.search}`;
5662
+ }
5663
+ return parsed.toString();
5481
5664
  } catch {
5482
5665
  if (!baseUrl)
5483
5666
  return url;
@@ -5878,7 +6061,76 @@ async function captureSession(url, authHeaders, cookies, intent, options) {
5878
6061
  log("capture", "scriptInject unavailable — falling back to evaluate injection");
5879
6062
  }
5880
6063
  }
5881
- await phase("harStart", () => harStart(tabId));
6064
+ try {
6065
+ await phase("harStart", () => harStart(tabId));
6066
+ } catch {}
6067
+ const cdpNetworkEntries = [];
6068
+ const cdpRequestMap = new Map;
6069
+ const cdpResponseMeta = new Map;
6070
+ const cdpFinishedRequests = new Set;
6071
+ let cdpWs = null;
6072
+ let cdpMsgId = 10;
6073
+ const cdpPendingBodies = new Map;
6074
+ const cdpResolvedBodies = new Map;
6075
+ const API_URL_PATTERN = /\/api\/|\/graphql|voyager|youtubei|\/v\d+\//i;
6076
+ try {
6077
+ const cdpPort = getCdpPort();
6078
+ if (cdpPort) {
6079
+ const tabsResp = await fetch(`http://127.0.0.1:${cdpPort}/json`);
6080
+ const tabs = await tabsResp.json();
6081
+ const cdpTab = tabs.find((t) => t.id === tabId) ?? tabs.find((t) => t.type === "page");
6082
+ if (cdpTab?.webSocketDebuggerUrl) {
6083
+ cdpWs = new WebSocket(cdpTab.webSocketDebuggerUrl);
6084
+ await new Promise((resolve, reject) => {
6085
+ cdpWs.onopen = () => resolve();
6086
+ cdpWs.onerror = () => reject(new Error("CDP WS failed"));
6087
+ setTimeout(() => reject(new Error("CDP WS timeout")), 3000);
6088
+ });
6089
+ cdpWs.onmessage = (ev) => {
6090
+ try {
6091
+ const msg = JSON.parse(String(ev.data));
6092
+ if (msg.method === "Network.requestWillBeSent") {
6093
+ const p = msg.params;
6094
+ const reqHeaders = Object.entries(p.request?.headers ?? {}).map(([name, value]) => ({ name, value: String(value) }));
6095
+ cdpRequestMap.set(p.requestId, {
6096
+ method: p.request?.method ?? "GET",
6097
+ url: p.request?.url ?? "",
6098
+ headers: reqHeaders,
6099
+ postData: p.request?.postData
6100
+ });
6101
+ } else if (msg.method === "Network.responseReceived") {
6102
+ const p = msg.params;
6103
+ const respHeaders = Object.entries(p.response?.headers ?? {}).map(([name, value]) => ({ name, value: String(value) }));
6104
+ cdpResponseMeta.set(p.requestId, {
6105
+ status: p.response?.status ?? 0,
6106
+ headers: respHeaders,
6107
+ mimeType: p.response?.mimeType ?? ""
6108
+ });
6109
+ } else if (msg.method === "Network.loadingFinished") {
6110
+ const requestId = msg.params?.requestId;
6111
+ cdpFinishedRequests.add(requestId);
6112
+ const req = cdpRequestMap.get(requestId);
6113
+ const resp = cdpResponseMeta.get(requestId);
6114
+ if (req && resp && API_URL_PATTERN.test(req.url) && (resp.mimeType.includes("json") || resp.mimeType.includes("text"))) {
6115
+ const id = ++cdpMsgId;
6116
+ cdpPendingBodies.set(id, req.url);
6117
+ cdpWs.send(JSON.stringify({ id, method: "Network.getResponseBody", params: { requestId } }));
6118
+ }
6119
+ } else if (msg.id && cdpPendingBodies.has(msg.id)) {
6120
+ const reqUrl = cdpPendingBodies.get(msg.id);
6121
+ cdpPendingBodies.delete(msg.id);
6122
+ if (msg.result?.body) {
6123
+ cdpResolvedBodies.set(reqUrl, msg.result.body);
6124
+ }
6125
+ }
6126
+ } catch {}
6127
+ };
6128
+ cdpWs.send(JSON.stringify({ id: 1, method: "Network.enable", params: {} }));
6129
+ await new Promise((r) => setTimeout(r, 200));
6130
+ log("capture", "CDP network capture enabled (direct websocket)");
6131
+ }
6132
+ }
6133
+ } catch {}
5882
6134
  let pageDomain;
5883
6135
  try {
5884
6136
  pageDomain = getRegistrableDomain(new URL(url).hostname);
@@ -5932,11 +6184,85 @@ async function captureSession(url, authHeaders, cookies, intent, options) {
5932
6184
  const perfEntries = await phase("evaluate:perf", () => collectPerformanceResourceEntries(tabId));
5933
6185
  performanceUrls = await phase("replay-fetch", () => replayPerformanceApiResponses(tabId, perfEntries, responseBodies, url, intent));
5934
6186
  } catch {}
6187
+ if (cdpRequestMap.size > 0) {
6188
+ try {
6189
+ const cdpRawReqs = [...cdpRequestMap.values()].map((r) => ({
6190
+ url: r.url,
6191
+ method: r.method,
6192
+ request_headers: Object.fromEntries(r.headers.map((h) => [h.name.toLowerCase(), h.value])),
6193
+ response_status: 200,
6194
+ response_headers: {},
6195
+ response_body: undefined,
6196
+ timestamp: ""
6197
+ }));
6198
+ const authHeaders2 = extractAuthHeaders(cdpRawReqs);
6199
+ if (Object.keys(authHeaders2).length > 0) {
6200
+ const rawKey = `${domain}-session`;
6201
+ const { getCredential: getCredential2 } = await init_vault().then(() => exports_vault);
6202
+ let existing = {};
6203
+ try {
6204
+ const stored = await getCredential2(rawKey);
6205
+ if (stored)
6206
+ existing = JSON.parse(stored);
6207
+ } catch {}
6208
+ if (!existing.cookies || existing.cookies.length === 0) {
6209
+ try {
6210
+ const loginKey = `auth:${getRegistrableDomain(domain)}`;
6211
+ const loginStored = await getCredential2(loginKey);
6212
+ if (loginStored) {
6213
+ const loginData = JSON.parse(loginStored);
6214
+ if (loginData.cookies?.length)
6215
+ existing.cookies = loginData.cookies;
6216
+ }
6217
+ } catch {}
6218
+ }
6219
+ await storeCredential(rawKey, JSON.stringify({
6220
+ ...existing,
6221
+ headers: { ...existing.headers ?? {}, ...authHeaders2 }
6222
+ }));
6223
+ log("capture", `early auth store: ${Object.keys(authHeaders2).join(", ")} for ${domain}`);
6224
+ }
6225
+ } catch (e) {
6226
+ log("capture", `early auth store failed: ${e instanceof Error ? e.message : String(e)}`);
6227
+ }
6228
+ }
5935
6229
  let harEntries = [];
5936
6230
  try {
5937
- const harResult = await phase("harStop", () => harStop(tabId));
5938
- harEntries = harResult.entries;
6231
+ const harPromise = harStop(tabId);
6232
+ const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({ entries: [] }), 5000));
6233
+ const harResult = await Promise.race([harPromise, timeoutPromise]);
6234
+ harEntries = harResult.entries ?? [];
5939
6235
  } catch {}
6236
+ if (cdpPendingBodies.size > 0) {
6237
+ await new Promise((r) => setTimeout(r, 1500));
6238
+ }
6239
+ if (cdpWs) {
6240
+ try {
6241
+ cdpWs.close();
6242
+ } catch {}
6243
+ }
6244
+ const harUrls = new Set(harEntries.map((e) => e.request?.url).filter(Boolean));
6245
+ let cdpAdded = 0;
6246
+ for (const [requestId, req] of cdpRequestMap) {
6247
+ if (harUrls.has(req.url))
6248
+ continue;
6249
+ const resp = cdpResponseMeta.get(requestId);
6250
+ if (!resp)
6251
+ continue;
6252
+ const body = cdpResolvedBodies.get(req.url);
6253
+ harEntries.push({
6254
+ startedDateTime: new Date().toISOString(),
6255
+ request: { method: req.method, url: req.url, headers: req.headers, postData: req.postData ? { text: req.postData } : undefined },
6256
+ response: { status: resp.status, headers: resp.headers, content: body ? { text: body, mimeType: resp.mimeType } : {} }
6257
+ });
6258
+ if (body && body.length > 0 && !responseBodies.has(req.url)) {
6259
+ responseBodies.set(req.url, body);
6260
+ }
6261
+ cdpAdded++;
6262
+ }
6263
+ if (cdpAdded > 0) {
6264
+ log("capture", `CDP direct capture added ${cdpAdded} entries (${cdpResolvedBodies.size} with bodies, ${harEntries.length} total HAR)`);
6265
+ }
5940
6266
  const HAR_REPLAY_CT2 = /application\/json|text\/plain|\+json/i;
5941
6267
  let harReplayCount = 0;
5942
6268
  for (const entry of harEntries) {
@@ -5960,7 +6286,7 @@ async function captureSession(url, authHeaders, cookies, intent, options) {
5960
6286
  const postData = method !== "GET" ? entry.request?.postData?.text : undefined;
5961
6287
  const replayScript = method === "GET" || !postData ? `(function(){var x=new XMLHttpRequest();x.open('GET','${harUrl.replace(/'/g, "\\'")}',false);x.send();return x.status>=200&&x.status<400?x.responseText:''})()` : `(function(){var x=new XMLHttpRequest();x.open('${method}','${harUrl.replace(/'/g, "\\'")}',false);x.setRequestHeader('Content-Type','application/json');x.send(${JSON.stringify(postData)});return x.status>=200&&x.status<400?x.responseText:''})()`;
5962
6288
  const body = await phase("har-replay", () => evaluate(tabId, replayScript));
5963
- if (typeof body === "string" && body.length > 0 && body.length < 512 * 1024) {
6289
+ if (typeof body === "string" && body.length > 0 && body.length < 524288) {
5964
6290
  responseBodies.set(harUrl, body);
5965
6291
  harReplayCount++;
5966
6292
  log("capture", `har-replay-fetched ${harUrl.substring(0, 80)} (${body.length}B)`);
@@ -5988,7 +6314,7 @@ async function captureSession(url, authHeaders, cookies, intent, options) {
5988
6314
  html = await phase("getPageHtml", () => getPageHtml(tabId));
5989
6315
  } catch {}
5990
6316
  const SSR_DATA_EXTRACTORS = [
5991
- { name: "ytmusic", script: `(function(){try{var d=ytcfg.get('YTMUSIC_INITIAL_DATA');if(!d||!d.length)return null;var out={};d.forEach(function(x){if(x.path&&x.data)out[x.path]=x.data});return JSON.stringify(out)}catch(e){return null}})()` },
6317
+ { name: "ytmusic", script: `(function(){try{var d=ytcfg.get('YTMUSIC_INITIAL_DATA');if(!d||!d.length)return null;var out={};d.forEach(function(x){if(x.path&&x.data)out[x.path]=x.data});out.__apiKey=ytcfg.get('INNERTUBE_API_KEY')||'';out.__context=ytcfg.get('INNERTUBE_CONTEXT')||null;return JSON.stringify(out)}catch(e){return null}})()` },
5992
6318
  { name: "youtube", script: `(function(){try{return typeof ytInitialData!=='undefined'?JSON.stringify(ytInitialData):null}catch(e){return null}})()` },
5993
6319
  { name: "nextjs", script: `(function(){try{return window.__NEXT_DATA__?JSON.stringify(window.__NEXT_DATA__):null}catch(e){return null}})()` },
5994
6320
  { name: "nuxt", script: `(function(){try{return window.__NUXT__?JSON.stringify(window.__NUXT__):null}catch(e){return null}})()` }
@@ -6000,8 +6326,12 @@ async function captureSession(url, authHeaders, cookies, intent, options) {
6000
6326
  if (typeof raw !== "string" || !raw || raw === "null")
6001
6327
  continue;
6002
6328
  if (extractor.name === "ytmusic") {
6003
- const paths = JSON.parse(raw);
6004
- for (const [path4, data] of Object.entries(paths)) {
6329
+ const parsed = JSON.parse(raw);
6330
+ const apiKey = parsed.__apiKey || "";
6331
+ const innertubeContext = parsed.__context;
6332
+ delete parsed.__apiKey;
6333
+ delete parsed.__context;
6334
+ for (const [path4, data] of Object.entries(parsed)) {
6005
6335
  if (!data || typeof data !== "object")
6006
6336
  continue;
6007
6337
  const cleaned = { ...data };
@@ -6022,12 +6352,15 @@ async function captureSession(url, authHeaders, cookies, intent, options) {
6022
6352
  continue;
6023
6353
  const origin = new URL(url).origin;
6024
6354
  const contextParams = new URL(url).searchParams;
6025
- const queryStr = path4.includes("search") && contextParams.toString() ? `?${contextParams.toString()}&prettyPrint=false` : "?prettyPrint=false";
6355
+ const keyParam = apiKey ? `key=${apiKey}&` : "";
6356
+ const queryStr = path4.includes("search") && contextParams.toString() ? `?${keyParam}${contextParams.toString()}&prettyPrint=false` : `?${keyParam}prettyPrint=false`;
6026
6357
  const syntheticUrl = `${origin}/youtubei/v1${path4}${queryStr}`;
6027
6358
  responseBodies.set(syntheticUrl, bodyStr);
6359
+ const queryValue = contextParams.get("q") ?? "";
6360
+ const postBody = path4.includes("search") && innertubeContext ? JSON.stringify({ context: innertubeContext, query: queryValue }) : path4.includes("browse") && innertubeContext ? JSON.stringify({ context: innertubeContext, browseId: "FEmusic_liked_videos" }) : JSON.stringify({ context: innertubeContext ?? {} });
6028
6361
  harEntries.push({
6029
6362
  startedDateTime: new Date().toISOString(),
6030
- request: { method: "POST", url: syntheticUrl, headers: [{ name: "content-type", value: "application/json" }], postData: { text: "{}" } },
6363
+ request: { method: "POST", url: syntheticUrl, headers: [{ name: "content-type", value: "application/json" }], postData: { text: postBody } },
6031
6364
  response: { status: 200, headers: [{ name: "content-type", value: "application/json" }], content: { text: bodyStr, mimeType: "application/json" } }
6032
6365
  });
6033
6366
  embeddedDataCount++;
@@ -6523,11 +6856,13 @@ var MAX_CONCURRENT_TABS = 3, activeTabs = 0, waitQueue, activeTabRegistry, inter
6523
6856
  return origSend.apply(this, arguments);
6524
6857
  };
6525
6858
  })()`, REPLAY_SKIP, HAR_REPLAY_CT;
6526
- var init_capture = __esm(() => {
6859
+ var init_capture = __esm(async () => {
6527
6860
  init_client();
6528
6861
  init_domain();
6529
6862
  init_logger();
6863
+ init_reverse_engineer();
6530
6864
  init_browser_access();
6865
+ await init_vault();
6531
6866
  waitQueue = [];
6532
6867
  activeTabRegistry = new Set;
6533
6868
  interceptorInjectedTabs = new Set;
@@ -6544,17 +6879,17 @@ var init_capture = __esm(() => {
6544
6879
  });
6545
6880
 
6546
6881
  // ../../src/build-info.generated.ts
6547
- var BUILD_RELEASE_VERSION = "3.2.2", BUILD_GIT_SHA = "150cce0d751e", BUILD_CODE_HASH = "1488fc1d92b7", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy4yLjIiLCJnaXRfc2hhIjoiMTUwY2NlMGQ3NTFlIiwiY29kZV9oYXNoIjoiMTQ4OGZjMWQ5MmI3IiwidHJhY2VfdmVyc2lvbiI6IjE0ODhmYzFkOTJiN0AxNTBjY2UwZDc1MWUiLCJpc3N1ZWRfYXQiOiIyMDI2LTA0LTA2VDA4OjQ2OjM5LjIwNVoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "ZS7C10DGuwyn1m02shMHyz6cN5UbTHfa8yqnkELg_L8", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
6882
+ var BUILD_RELEASE_VERSION = "3.2.3-experiments.8932456", BUILD_GIT_SHA = "8932456cbb1b", BUILD_CODE_HASH = "1488fc1d92b7", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy4yLjMtZXhwZXJpbWVudHMuODkzMjQ1NiIsImdpdF9zaGEiOiI4OTMyNDU2Y2JiMWIiLCJjb2RlX2hhc2giOiIxNDg4ZmMxZDkyYjciLCJ0cmFjZV92ZXJzaW9uIjoiMTQ4OGZjMWQ5MmI3QDg5MzI0NTZjYmIxYiIsImlzc3VlZF9hdCI6IjIwMjYtMDQtMDZUMTQ6NTk6MjUuNDA0WiJ9", BUILD_RELEASE_MANIFEST_SIGNATURE = "_zjmqCbUpLNUj6AhAJLMM2G5AAA35LhChNY_EgKZmM8", BUILD_DEFAULT_BACKEND_URL = "https://unbrowse-backend-experiments.lewis-6d8.workers.dev";
6548
6883
 
6549
6884
  // ../../src/version.ts
6550
6885
  import { createHash } from "crypto";
6551
- import { existsSync as existsSync3, readFileSync, readdirSync } from "fs";
6552
- import { dirname, join as join2, parse } from "path";
6886
+ import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync } from "fs";
6887
+ import { dirname, join as join3, parse } from "path";
6553
6888
  import { fileURLToPath as fileURLToPath2 } from "url";
6554
6889
  function collectTsFiles(dir) {
6555
6890
  const results = [];
6556
6891
  for (const entry of readdirSync(dir, { withFileTypes: true })) {
6557
- const full = join2(dir, entry.name);
6892
+ const full = join3(dir, entry.name);
6558
6893
  if (entry.isDirectory() && entry.name !== "node_modules") {
6559
6894
  results.push(...collectTsFiles(full));
6560
6895
  } else if (entry.name.endsWith(".ts")) {
@@ -6567,21 +6902,21 @@ function hashFiles(srcDir, files) {
6567
6902
  const hash = createHash("sha256");
6568
6903
  for (const file of files) {
6569
6904
  hash.update(file.slice(srcDir.length));
6570
- hash.update(readFileSync(file, "utf-8"));
6905
+ hash.update(readFileSync2(file, "utf-8"));
6571
6906
  }
6572
6907
  return hash.digest("hex").slice(0, 12);
6573
6908
  }
6574
6909
  function resolveCodeHashSourceDir(moduleDir) {
6575
6910
  const candidates = [
6576
6911
  moduleDir,
6577
- join2(moduleDir, "runtime-src"),
6578
- join2(moduleDir, "..", "runtime-src"),
6579
- join2(moduleDir, "src"),
6580
- join2(moduleDir, "..", "src")
6912
+ join3(moduleDir, "runtime-src"),
6913
+ join3(moduleDir, "..", "runtime-src"),
6914
+ join3(moduleDir, "src"),
6915
+ join3(moduleDir, "..", "src")
6581
6916
  ];
6582
6917
  for (const candidate of candidates) {
6583
6918
  try {
6584
- if (!existsSync3(candidate))
6919
+ if (!existsSync4(candidate))
6585
6920
  continue;
6586
6921
  const files = collectTsFiles(candidate);
6587
6922
  if (files.length > 0)
@@ -6631,7 +6966,7 @@ function getPackageVersionForModuleDir(moduleDir) {
6631
6966
  const root = parse(dir).root;
6632
6967
  while (true) {
6633
6968
  try {
6634
- const pkg = JSON.parse(readFileSync(join2(dir, "package.json"), "utf-8"));
6969
+ const pkg = JSON.parse(readFileSync2(join3(dir, "package.json"), "utf-8"));
6635
6970
  return typeof pkg.version === "string" ? pkg.version : "unknown";
6636
6971
  } catch {}
6637
6972
  if (dir === root)
@@ -6735,18 +7070,18 @@ async function ensureCascadeSplitForSkill(skill, deps = {}) {
6735
7070
  var init_cascade = () => {};
6736
7071
 
6737
7072
  // ../../src/payments/wallet.ts
6738
- import { existsSync as existsSync4, readFileSync as readFileSync2 } from "node:fs";
6739
- import { homedir } from "node:os";
6740
- import { join as join3 } from "node:path";
7073
+ import { existsSync as existsSync5, readFileSync as readFileSync3 } from "node:fs";
7074
+ import { homedir as homedir2 } from "node:os";
7075
+ import { join as join4 } from "node:path";
6741
7076
  function asNonEmptyString(value) {
6742
7077
  return typeof value === "string" && value.trim() ? value.trim() : undefined;
6743
7078
  }
6744
7079
  function getLobsterWalletFromLocalConfig() {
6745
- const agentsPath = join3(process.env.HOME || homedir(), ".lobster", "agents.json");
6746
- if (!existsSync4(agentsPath))
7080
+ const agentsPath = join4(process.env.HOME || homedir2(), ".lobster", "agents.json");
7081
+ if (!existsSync5(agentsPath))
6747
7082
  return;
6748
7083
  try {
6749
- const raw = JSON.parse(readFileSync2(agentsPath, "utf8"));
7084
+ const raw = JSON.parse(readFileSync3(agentsPath, "utf8"));
6750
7085
  const activeAgentId = asNonEmptyString(raw.activeAgentId);
6751
7086
  const activeAgent = Array.isArray(raw.agents) ? raw.agents.find((agent) => asNonEmptyString(agent.id) === activeAgentId) : activeAgentId ? raw.agents?.[activeAgentId] : undefined;
6752
7087
  return asNonEmptyString(activeAgent?.authorizedWallets?.solana) ?? asNonEmptyString(activeAgent?.walletAddress) ?? asNonEmptyString(activeAgent?.wallet_address);
@@ -6897,9 +7232,9 @@ __export(exports_lobster_pay, {
6897
7232
  isLobsterAvailable: () => isLobsterAvailable
6898
7233
  });
6899
7234
  import { execFile, execFileSync as execFileSync2 } from "node:child_process";
6900
- import { existsSync as existsSync5 } from "node:fs";
6901
- import { homedir as homedir2 } from "node:os";
6902
- import { join as join4 } from "node:path";
7235
+ import { existsSync as existsSync6 } from "node:fs";
7236
+ import { homedir as homedir3 } from "node:os";
7237
+ import { join as join5 } from "node:path";
6903
7238
  function getLobsterCommand() {
6904
7239
  try {
6905
7240
  execFileSync2("lobstercash", ["--version"], { stdio: "ignore", timeout: 3000 });
@@ -6907,8 +7242,8 @@ function getLobsterCommand() {
6907
7242
  } catch (_e) {}
6908
7243
  try {
6909
7244
  const npmPrefix = execFileSync2("npm", ["config", "get", "prefix"], { encoding: "utf8", timeout: 5000 }).trim();
6910
- const lobsterPath = join4(npmPrefix, "bin", "lobstercash");
6911
- if (existsSync5(lobsterPath)) {
7245
+ const lobsterPath = join5(npmPrefix, "bin", "lobstercash");
7246
+ if (existsSync6(lobsterPath)) {
6912
7247
  execFileSync2(lobsterPath, ["--version"], { stdio: "ignore", timeout: 3000 });
6913
7248
  return { cmd: lobsterPath, prefix: [] };
6914
7249
  }
@@ -6921,8 +7256,8 @@ function lobsterCmd() {
6921
7256
  return cachedCommand;
6922
7257
  }
6923
7258
  function isLobsterAvailable() {
6924
- const agentsPath = join4(process.env.HOME || homedir2(), ".lobster", "agents.json");
6925
- return existsSync5(agentsPath);
7259
+ const agentsPath = join5(process.env.HOME || homedir3(), ".lobster", "agents.json");
7260
+ return existsSync6(agentsPath);
6926
7261
  }
6927
7262
  function lobsterX402Fetch(url, options) {
6928
7263
  return new Promise((resolve) => {
@@ -7054,10 +7389,10 @@ __export(exports_client2, {
7054
7389
  buildDefaultAgentName: () => buildDefaultAgentName,
7055
7390
  autoFileIssue: () => autoFileIssue
7056
7391
  });
7057
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3, readdirSync as readdirSync2 } from "fs";
7058
- import { join as join5 } from "path";
7059
- import { homedir as homedir3, hostname, release as osRelease } from "os";
7060
- import { randomBytes, createHash as createHash3 } from "crypto";
7392
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync as readdirSync2 } from "fs";
7393
+ import { join as join6 } from "path";
7394
+ import { homedir as homedir4, hostname, release as osRelease } from "os";
7395
+ import { randomBytes as randomBytes2, createHash as createHash3 } from "crypto";
7061
7396
  import { createInterface } from "readline";
7062
7397
  function buildReleaseAttestationHeaders(manifestBase64, signature) {
7063
7398
  const manifest = manifestBase64.trim();
@@ -7091,18 +7426,18 @@ function scopedSkillKey(skillId, scopeId) {
7091
7426
  return scopeId ? `${scopeId}:${skillId}` : skillId;
7092
7427
  }
7093
7428
  function getSkillCacheDir() {
7094
- return process.env.UNBROWSE_SKILL_CACHE_DIR || join5(getConfigDir(), "skill-cache");
7429
+ return process.env.UNBROWSE_SKILL_CACHE_DIR || join6(getConfigDir(), "skill-cache");
7095
7430
  }
7096
7431
  function getConfigDir() {
7097
7432
  if (process.env.UNBROWSE_CONFIG_DIR)
7098
7433
  return process.env.UNBROWSE_CONFIG_DIR;
7099
- return PROFILE_NAME ? join5(homedir3(), ".unbrowse", "profiles", PROFILE_NAME) : join5(homedir3(), ".unbrowse");
7434
+ return PROFILE_NAME ? join6(homedir4(), ".unbrowse", "profiles", PROFILE_NAME) : join6(homedir4(), ".unbrowse");
7100
7435
  }
7101
7436
  function getConfigPath() {
7102
- return join5(getConfigDir(), "config.json");
7437
+ return join6(getConfigDir(), "config.json");
7103
7438
  }
7104
7439
  function getInstallTelemetryPath() {
7105
- return join5(getConfigDir(), "install-state.json");
7440
+ return join6(getConfigDir(), "install-state.json");
7106
7441
  }
7107
7442
  function getLandingToken() {
7108
7443
  const token = process.env.UNBROWSE_LANDING_TOKEN?.trim();
@@ -7120,8 +7455,8 @@ function isLocalOnlyMode() {
7120
7455
  function loadConfig() {
7121
7456
  try {
7122
7457
  const configPath = getConfigPath();
7123
- if (existsSync6(configPath)) {
7124
- return JSON.parse(readFileSync3(configPath, "utf-8"));
7458
+ if (existsSync7(configPath)) {
7459
+ return JSON.parse(readFileSync4(configPath, "utf-8"));
7125
7460
  }
7126
7461
  } catch {}
7127
7462
  return null;
@@ -7129,15 +7464,15 @@ function loadConfig() {
7129
7464
  function saveConfig(config) {
7130
7465
  const configDir = getConfigDir();
7131
7466
  const configPath = getConfigPath();
7132
- if (!existsSync6(configDir))
7133
- mkdirSync3(configDir, { recursive: true });
7134
- writeFileSync2(configPath, JSON.stringify(config, null, 2), { mode: 384 });
7467
+ if (!existsSync7(configDir))
7468
+ mkdirSync4(configDir, { recursive: true });
7469
+ writeFileSync3(configPath, JSON.stringify(config, null, 2), { mode: 384 });
7135
7470
  }
7136
7471
  function loadInstallTelemetryState() {
7137
7472
  try {
7138
7473
  const statePath = getInstallTelemetryPath();
7139
- if (existsSync6(statePath)) {
7140
- return JSON.parse(readFileSync3(statePath, "utf-8"));
7474
+ if (existsSync7(statePath)) {
7475
+ return JSON.parse(readFileSync4(statePath, "utf-8"));
7141
7476
  }
7142
7477
  } catch {}
7143
7478
  return null;
@@ -7145,13 +7480,13 @@ function loadInstallTelemetryState() {
7145
7480
  function saveInstallTelemetryState(state) {
7146
7481
  const configDir = getConfigDir();
7147
7482
  const statePath = getInstallTelemetryPath();
7148
- if (!existsSync6(configDir))
7149
- mkdirSync3(configDir, { recursive: true });
7150
- writeFileSync2(statePath, JSON.stringify(state, null, 2), { mode: 384 });
7483
+ if (!existsSync7(configDir))
7484
+ mkdirSync4(configDir, { recursive: true });
7485
+ writeFileSync3(statePath, JSON.stringify(state, null, 2), { mode: 384 });
7151
7486
  }
7152
7487
  function createInstallTelemetryState() {
7153
7488
  return {
7154
- install_id: `install_${randomBytes(8).toString("hex")}`,
7489
+ install_id: `install_${randomBytes2(8).toString("hex")}`,
7155
7490
  first_seen_at: new Date().toISOString()
7156
7491
  };
7157
7492
  }
@@ -7291,7 +7626,7 @@ function isValidAgentEmail(value) {
7291
7626
  return EMAIL_RE.test(normalizeAgentEmail(value));
7292
7627
  }
7293
7628
  function buildDefaultAgentName() {
7294
- return `${hostname()}-${randomBytes(3).toString("hex")}`;
7629
+ return `${hostname()}-${randomBytes2(3).toString("hex")}`;
7295
7630
  }
7296
7631
  function resolveAgentName(preferredEmail, fallbackName) {
7297
7632
  const normalized = normalizeAgentEmail(preferredEmail ?? "");
@@ -7646,11 +7981,11 @@ async function waitForBackgroundRegistration(timeoutMs = 0) {
7646
7981
  ]);
7647
7982
  }
7648
7983
  function skillCachePath(skillId) {
7649
- return join5(getSkillCacheDir(), `${skillId}.json`);
7984
+ return join6(getSkillCacheDir(), `${skillId}.json`);
7650
7985
  }
7651
7986
  function readSkillCache(skillId) {
7652
7987
  try {
7653
- const raw = readFileSync3(skillCachePath(skillId), "utf-8");
7988
+ const raw = readFileSync4(skillCachePath(skillId), "utf-8");
7654
7989
  return JSON.parse(raw);
7655
7990
  } catch {
7656
7991
  return null;
@@ -7660,8 +7995,8 @@ function writeSkillCache(skill, scopeId) {
7660
7995
  try {
7661
7996
  recentLocalSkills.set(scopedSkillKey(skill.skill_id, scopeId), skill);
7662
7997
  const skillCacheDir = getSkillCacheDir();
7663
- if (!existsSync6(skillCacheDir))
7664
- mkdirSync3(skillCacheDir, { recursive: true });
7998
+ if (!existsSync7(skillCacheDir))
7999
+ mkdirSync4(skillCacheDir, { recursive: true });
7665
8000
  const existing = readSkillCache(skill.skill_id);
7666
8001
  if (existing) {
7667
8002
  for (const ep of skill.endpoints) {
@@ -7677,7 +8012,7 @@ function writeSkillCache(skill, scopeId) {
7677
8012
  const hasStrategy = skill.endpoints.some((e) => e.exec_strategy);
7678
8013
  if (hasStrategy)
7679
8014
  console.log(`[cache] writing skill ${skill.skill_id} with exec_strategy`);
7680
- writeFileSync2(skillCachePath(skill.skill_id), JSON.stringify(skill), "utf-8");
8015
+ writeFileSync3(skillCachePath(skill.skill_id), JSON.stringify(skill), "utf-8");
7681
8016
  } catch {}
7682
8017
  }
7683
8018
  function cachePublishedSkill(skill, scopeId) {
@@ -7712,7 +8047,7 @@ function isIntentCompatible(lhs, rhs) {
7712
8047
  function findExistingSkillForDomain(domain, intent) {
7713
8048
  try {
7714
8049
  const skillCacheDir = getSkillCacheDir();
7715
- if (!existsSync6(skillCacheDir))
8050
+ if (!existsSync7(skillCacheDir))
7716
8051
  return null;
7717
8052
  const files = readdirSync2(skillCacheDir);
7718
8053
  let compatible = null;
@@ -7721,7 +8056,7 @@ function findExistingSkillForDomain(domain, intent) {
7721
8056
  if (!f.endsWith(".json") || f === "browser-capture.json")
7722
8057
  continue;
7723
8058
  try {
7724
- const raw = readFileSync3(join5(skillCacheDir, f), "utf-8");
8059
+ const raw = readFileSync4(join6(skillCacheDir, f), "utf-8");
7725
8060
  const skill = JSON.parse(raw);
7726
8061
  if (skill.domain === domain && skill.execution_type === "http") {
7727
8062
  if (!fallback)
@@ -7771,11 +8106,11 @@ async function getSkillChunk2(skillId, opts) {
7771
8106
  async function listSkills() {
7772
8107
  if (LOCAL_ONLY) {
7773
8108
  try {
7774
- if (!existsSync6(SKILL_CACHE_DIR))
8109
+ if (!existsSync7(SKILL_CACHE_DIR))
7775
8110
  return [];
7776
8111
  return readdirSync2(SKILL_CACHE_DIR).filter((file) => file.endsWith(".json")).map((file) => {
7777
8112
  try {
7778
- return JSON.parse(readFileSync3(join5(SKILL_CACHE_DIR, file), "utf-8"));
8113
+ return JSON.parse(readFileSync4(join6(SKILL_CACHE_DIR, file), "utf-8"));
7779
8114
  } catch {
7780
8115
  return null;
7781
8116
  }
@@ -8467,10 +8802,10 @@ var init_publish_admission = __esm(() => {
8467
8802
 
8468
8803
  // ../../src/telemetry.ts
8469
8804
  import { createHash as createHash4 } from "node:crypto";
8470
- import { existsSync as existsSync7, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "node:fs";
8471
- import { join as join6 } from "node:path";
8805
+ import { existsSync as existsSync8, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
8806
+ import { join as join7 } from "node:path";
8472
8807
  function getTraceDir() {
8473
- return process.env.UNBROWSE_TRACES_DIR ?? join6(process.env.HOME ?? "/tmp", ".unbrowse", "traces");
8808
+ return process.env.UNBROWSE_TRACES_DIR ?? join7(process.env.HOME ?? "/tmp", ".unbrowse", "traces");
8474
8809
  }
8475
8810
  function isTracingEnabled() {
8476
8811
  return process.env.UNBROWSE_DISABLE_TRACES !== "1";
@@ -8544,11 +8879,11 @@ function emitRouteTrace(params) {
8544
8879
  };
8545
8880
  try {
8546
8881
  const traceDir = getTraceDir();
8547
- if (!existsSync7(traceDir))
8548
- mkdirSync4(traceDir, { recursive: true });
8882
+ if (!existsSync8(traceDir))
8883
+ mkdirSync5(traceDir, { recursive: true });
8549
8884
  const stamp = params.started_at.replace(/[:.]/g, "-");
8550
- const file = join6(traceDir, `${stamp}-${params.outcome}-${params.trace_id}.json`);
8551
- writeFileSync3(file, JSON.stringify(artifact, null, 2), "utf-8");
8885
+ const file = join7(traceDir, `${stamp}-${params.outcome}-${params.trace_id}.json`);
8886
+ writeFileSync4(file, JSON.stringify(artifact, null, 2), "utf-8");
8552
8887
  return file;
8553
8888
  } catch {
8554
8889
  return null;
@@ -9184,161 +9519,6 @@ var init_token_resolver = __esm(() => {
9184
9519
  init_token_sources();
9185
9520
  });
9186
9521
 
9187
- // ../../src/vault/index.ts
9188
- import { createCipheriv, createDecipheriv, randomBytes as randomBytes2 } from "crypto";
9189
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync4 } from "fs";
9190
- import { join as join7 } from "path";
9191
- import { homedir as homedir4 } from "os";
9192
- function normalizeKeytarModule(mod) {
9193
- let candidate = mod;
9194
- for (let depth = 0;depth < 3; depth++) {
9195
- if (!candidate || typeof candidate !== "object" || !("default" in candidate))
9196
- break;
9197
- candidate = candidate.default;
9198
- }
9199
- if (!candidate)
9200
- return null;
9201
- if (typeof candidate.setPassword === "function" && typeof candidate.getPassword === "function" && typeof candidate.deletePassword === "function") {
9202
- return candidate;
9203
- }
9204
- return null;
9205
- }
9206
- function isKeytarBindingError(error) {
9207
- const message = error instanceof Error ? `${error.name}: ${error.message}` : String(error);
9208
- return KEYTAR_BINDING_ERROR_RE.test(message);
9209
- }
9210
- function disableKeytar(error) {
9211
- keytar = null;
9212
- if (keytarFallbackLogged)
9213
- return;
9214
- const summary = error instanceof Error ? error.message : String(error);
9215
- log("vault", `keytar runtime unavailable (${summary}); using encrypted file fallback`);
9216
- keytarFallbackLogged = true;
9217
- }
9218
- async function callKeytar(op) {
9219
- if (!keytar)
9220
- return KEYTAR_UNAVAILABLE;
9221
- try {
9222
- return await op(keytar);
9223
- } catch (error) {
9224
- if (!isKeytarBindingError(error))
9225
- throw error;
9226
- disableKeytar(error);
9227
- return KEYTAR_UNAVAILABLE;
9228
- }
9229
- }
9230
- function getOrCreateKey() {
9231
- if (!existsSync8(VAULT_DIR))
9232
- mkdirSync5(VAULT_DIR, { recursive: true, mode: 448 });
9233
- if (existsSync8(KEY_FILE))
9234
- return readFileSync4(KEY_FILE);
9235
- const key = randomBytes2(32);
9236
- writeFileSync4(KEY_FILE, key, { mode: 384 });
9237
- return key;
9238
- }
9239
- function withVaultLock(fn) {
9240
- const prev = vaultLock;
9241
- let release;
9242
- vaultLock = new Promise((r) => {
9243
- release = r;
9244
- });
9245
- return prev.then(fn).finally(() => release());
9246
- }
9247
- function readVaultFile() {
9248
- if (!existsSync8(VAULT_FILE))
9249
- return {};
9250
- try {
9251
- const key = getOrCreateKey();
9252
- const raw = readFileSync4(VAULT_FILE);
9253
- const iv = raw.subarray(0, 16);
9254
- const enc = raw.subarray(16);
9255
- const decipher = createDecipheriv("aes-256-cbc", key, iv);
9256
- const dec = Buffer.concat([decipher.update(enc), decipher.final()]);
9257
- return JSON.parse(dec.toString("utf8"));
9258
- } catch {
9259
- return {};
9260
- }
9261
- }
9262
- function writeVaultFile(data) {
9263
- const key = getOrCreateKey();
9264
- const iv = randomBytes2(16);
9265
- const cipher = createCipheriv("aes-256-cbc", key, iv);
9266
- const enc = Buffer.concat([cipher.update(JSON.stringify(data), "utf8"), cipher.final()]);
9267
- writeFileSync4(VAULT_FILE, Buffer.concat([iv, enc]), { mode: 384 });
9268
- }
9269
- async function storeCredential(account, value, opts) {
9270
- const wrapped = {
9271
- value,
9272
- stored_at: new Date().toISOString(),
9273
- expires_at: opts?.expires_at,
9274
- max_age_ms: opts?.max_age_ms
9275
- };
9276
- const serialized = JSON.stringify(wrapped);
9277
- const keytarResult = await callKeytar((client) => client.setPassword(SERVICE, account, serialized));
9278
- if (keytarResult !== KEYTAR_UNAVAILABLE)
9279
- return;
9280
- await withVaultLock(() => {
9281
- const data = readVaultFile();
9282
- data[account] = serialized;
9283
- writeVaultFile(data);
9284
- });
9285
- }
9286
- function isExpired(cred) {
9287
- if (cred.expires_at) {
9288
- return new Date(cred.expires_at).getTime() <= Date.now();
9289
- }
9290
- if (cred.max_age_ms) {
9291
- return new Date(cred.stored_at).getTime() + cred.max_age_ms <= Date.now();
9292
- }
9293
- return false;
9294
- }
9295
- async function getCredential(account) {
9296
- let raw;
9297
- const keytarResult = await callKeytar((client) => client.getPassword(SERVICE, account));
9298
- if (keytarResult !== KEYTAR_UNAVAILABLE) {
9299
- raw = keytarResult;
9300
- } else {
9301
- const data = readVaultFile();
9302
- raw = data[account] ?? null;
9303
- }
9304
- if (!raw)
9305
- return null;
9306
- try {
9307
- const parsed = JSON.parse(raw);
9308
- if (parsed.value && parsed.stored_at) {
9309
- if (isExpired(parsed)) {
9310
- await deleteCredential(account);
9311
- return null;
9312
- }
9313
- return parsed.value;
9314
- }
9315
- } catch {}
9316
- return raw;
9317
- }
9318
- async function deleteCredential(account) {
9319
- const keytarResult = await callKeytar((client) => client.deletePassword(SERVICE, account));
9320
- if (keytarResult !== KEYTAR_UNAVAILABLE)
9321
- return;
9322
- await withVaultLock(() => {
9323
- const data = readVaultFile();
9324
- delete data[account];
9325
- writeVaultFile(data);
9326
- });
9327
- }
9328
- var KEYTAR_UNAVAILABLE, KEYTAR_BINDING_ERROR_RE, keytar = null, keytarFallbackLogged = false, SERVICE = "unbrowse", VAULT_DIR, VAULT_FILE, KEY_FILE, vaultLock;
9329
- var init_vault = __esm(async () => {
9330
- init_logger();
9331
- KEYTAR_UNAVAILABLE = Symbol("KEYTAR_UNAVAILABLE");
9332
- KEYTAR_BINDING_ERROR_RE = /(keytar(?:\.node)?|native bindings?|bindings file|no native build was found|could not locate the bindings file|module did not self-register|err_dlopen_failed|dlopen\(|compiled against a different node\.js version|cannot find module .*keytar|wasm is not supported on this platform|(set|get|delete)password is not a function)/i;
9333
- try {
9334
- keytar = normalizeKeytarModule(await import("keytar"));
9335
- } catch {}
9336
- VAULT_DIR = join7(homedir4(), ".unbrowse", "vault");
9337
- VAULT_FILE = join7(VAULT_DIR, "credentials.enc");
9338
- KEY_FILE = join7(VAULT_DIR, ".key");
9339
- vaultLock = Promise.resolve();
9340
- });
9341
-
9342
9522
  // ../../src/runtime/supervisor.ts
9343
9523
  function getDefaultLoginConfig(headless) {
9344
9524
  return {
@@ -14010,6 +14190,10 @@ function validateWorkflowReplayParams(recipe, params) {
14010
14190
  continue;
14011
14191
  const value = valueForSpec(spec, params);
14012
14192
  if (spec.required && (value == null || value === "")) {
14193
+ if (spec.default_value != null && spec.default_value !== "")
14194
+ continue;
14195
+ if (spec.example_value != null && spec.example_value !== "")
14196
+ continue;
14013
14197
  errors.push({ name: spec.name, reason: "required" });
14014
14198
  continue;
14015
14199
  }
@@ -14304,18 +14488,27 @@ async function reloadExecutionAuthState(skill, epDomain, authHeaders, cookies) {
14304
14488
  cookies.push(...resolved);
14305
14489
  } catch {}
14306
14490
  }
14307
- if (Object.keys(authHeaders).length === 0) {
14308
- try {
14309
- const sessionKey = `${getRegistrableDomain(epDomain)}-session`;
14310
- const sessionData = await getCredential(sessionKey);
14311
- if (sessionData) {
14312
- const parsed = JSON.parse(sessionData);
14313
- if (parsed.headers)
14314
- Object.assign(authHeaders, parsed.headers);
14315
- if (parsed.cookies && cookies.length === 0)
14316
- cookies.push(...parsed.cookies);
14317
- }
14318
- } catch {}
14491
+ {
14492
+ for (const sessionKey of [`${epDomain}-session`, `${getRegistrableDomain(epDomain)}-session`]) {
14493
+ try {
14494
+ const sessionData = await getCredential(sessionKey);
14495
+ if (sessionData) {
14496
+ const parsed = JSON.parse(sessionData);
14497
+ if (parsed.headers)
14498
+ Object.assign(authHeaders, parsed.headers);
14499
+ if (parsed.cookies && cookies.length === 0)
14500
+ cookies.push(...parsed.cookies);
14501
+ if (Object.keys(authHeaders).length > 0)
14502
+ break;
14503
+ }
14504
+ } catch {}
14505
+ }
14506
+ }
14507
+ if (cookies.length > 0 && authHeaders["csrf-token"]) {
14508
+ const jsessionId = cookies.find((c) => c.name === "JSESSIONID");
14509
+ if (jsessionId) {
14510
+ authHeaders["csrf-token"] = jsessionId.value.replace(/"/g, "");
14511
+ }
14319
14512
  }
14320
14513
  }
14321
14514
  function persistWorkflowArtifactForCapture(artifactSkill, captured, capturedAuthHeaders) {
@@ -15336,10 +15529,13 @@ async function executeBrowserCapture(skill, params, options) {
15336
15529
  }));
15337
15530
  }
15338
15531
  if (!auth_profile_ref) {
15339
- const vaultKey = `auth:${targetDomain}`;
15340
- const hasStoredAuth = await getCredential(vaultKey) != null;
15341
- if (hasStoredAuth)
15342
- auth_profile_ref = vaultKey;
15532
+ for (const vaultKey of [`auth:${targetDomain}`, `${domain}-session`, `${targetDomain}-session`]) {
15533
+ const hasStoredAuth = await getCredential(vaultKey) != null;
15534
+ if (hasStoredAuth) {
15535
+ auth_profile_ref = vaultKey;
15536
+ break;
15537
+ }
15538
+ }
15343
15539
  }
15344
15540
  const authBackedCapture = usedStoredAuth || !!auth_profile_ref;
15345
15541
  if (authBackedCapture) {
@@ -15920,7 +16116,7 @@ async function executeEndpoint(skill, endpoint, params = {}, projection, options
15920
16116
  u.searchParams.set(k, String(v));
15921
16117
  }
15922
16118
  }
15923
- urlTemplate = restoreTemplatePlaceholderEncoding(u.toString());
16119
+ urlTemplate = restoreTemplatePlaceholderEncoding(u.toString()).replace(/%28/gi, "(").replace(/%29/gi, ")").replace(/%2C/gi, ",").replace(/%3A/gi, ":");
15924
16120
  } catch {}
15925
16121
  }
15926
16122
  let url = interpolate(urlTemplate, mergedParams);
@@ -16056,7 +16252,7 @@ async function executeEndpoint(skill, endpoint, params = {}, projection, options
16056
16252
  let last = { data: null, status: 0 };
16057
16253
  for (const replayUrl of replayUrls) {
16058
16254
  const replayHeaders = buildStructuredReplayHeaders(url, replayUrl, headers);
16059
- log("exec", `server-fetch: ${endpoint.method} ${replayUrl.substring(0, 80)} auth=${(replayHeaders["authorization"] || "none").substring(0, 50)} csrf=${replayHeaders["x-csrf-token"]?.substring(0, 10)}... cookies=${replayHeaders["cookie"]?.length ?? 0}chars`);
16255
+ log("exec", `server-fetch: ${endpoint.method} ${replayUrl.substring(0, 200)} csrf-token=${(replayHeaders["csrf-token"] || "none").substring(0, 20)}... hdrs=${Object.keys(replayHeaders).length} cookies=${replayHeaders["cookie"]?.length ?? 0}chars`);
16060
16256
  const res = await fetch(replayUrl, {
16061
16257
  method: endpoint.method,
16062
16258
  headers: replayHeaders,
@@ -16460,7 +16656,12 @@ function interpolate(template, params) {
16460
16656
  const base = template.substring(0, qIdx);
16461
16657
  const query = template.substring(qIdx + 1);
16462
16658
  const interpolatedBase = base.replace(/\{(\w+)\}/g, (_, k) => params[k] != null ? String(params[k]) : `{${k}}`);
16463
- const interpolatedQuery = query.replace(/\{(\w+)\}/g, (_, k) => params[k] != null ? encodeURIComponent(String(params[k])) : `{${k}}`);
16659
+ const interpolatedQuery = query.replace(/\{(\w+)\}/g, (_, k) => {
16660
+ if (params[k] == null)
16661
+ return `{${k}}`;
16662
+ const val = String(params[k]);
16663
+ return val.replace(/[#&=\s]/g, (ch) => encodeURIComponent(ch));
16664
+ });
16464
16665
  return `${interpolatedBase}?${interpolatedQuery}`;
16465
16666
  }
16466
16667
  function interpolateObj(obj, params) {
@@ -17020,8 +17221,6 @@ function isSpaShell(html) {
17020
17221
  }
17021
17222
  var DEFAULT_BROWSER_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36", VALID_VERIFICATION_STATUSES, BM25_K1 = 1.2, BM25_B = 0.75, STOPWORDS, SYNONYMS;
17022
17223
  var init_execution = __esm(async () => {
17023
- init_capture();
17024
- init_capture();
17025
17224
  init_reverse_engineer();
17026
17225
  init_bundle_scanner();
17027
17226
  init_token_resolver();
@@ -17045,6 +17244,8 @@ var init_execution = __esm(async () => {
17045
17244
  init_compile();
17046
17245
  init_publish();
17047
17246
  await __promiseAll([
17247
+ init_capture(),
17248
+ init_capture(),
17048
17249
  init_vault(),
17049
17250
  init_auth(),
17050
17251
  init_indexer(),
@@ -19694,7 +19895,7 @@ async function resolveAndExecute(intent, params = {}, context, projection, optio
19694
19895
  for (const cookie of cookies)
19695
19896
  await setCookie(handoffTabId, cookie).catch(() => {});
19696
19897
  } catch {}
19697
- await evaluate(handoffTabId, (await Promise.resolve().then(() => (init_capture(), exports_capture))).INTERCEPTOR_SCRIPT).catch(() => {});
19898
+ await evaluate(handoffTabId, (await init_capture().then(() => exports_capture)).INTERCEPTOR_SCRIPT).catch(() => {});
19698
19899
  await harStart(handoffTabId).catch(() => {});
19699
19900
  try {
19700
19901
  const routesModule = await init_routes().then(() => exports_routes);
@@ -24195,13 +24396,13 @@ function schedulePeriodicVerification() {
24195
24396
  }, VERIFICATION_INTERVAL_MS);
24196
24397
  }
24197
24398
  var VERIFICATION_INTERVAL_MS, VERIFY_ENDPOINT_BATCH_SIZE;
24198
- var init_verification = __esm(() => {
24199
- init_capture();
24399
+ var init_verification = __esm(async () => {
24200
24400
  init_marketplace();
24201
24401
  init_marketplace();
24202
24402
  init_drift();
24203
24403
  init_matrix();
24204
24404
  init_candidates();
24405
+ await init_capture();
24205
24406
  VERIFICATION_INTERVAL_MS = 6 * 60 * 60 * 1000;
24206
24407
  VERIFY_ENDPOINT_BATCH_SIZE = Math.max(1, Number(process.env.UNBROWSE_VERIFY_ENDPOINT_BATCH_SIZE ?? 3));
24207
24408
  });
@@ -24308,9 +24509,11 @@ function schedulePeriodicStaleCleanup() {
24308
24509
  var VERIFY_TIMEOUT_MS, CLEANUP_INTERVAL_MS, CLEANUP_BATCH_SIZE, CLEANUP_VERIFY_ENDPOINT_LIMIT;
24309
24510
  var init_stale_cleanup_runner = __esm(async () => {
24310
24511
  init_marketplace();
24311
- init_verification();
24312
24512
  init_candidates();
24313
- await init_orchestrator();
24513
+ await __promiseAll([
24514
+ init_verification(),
24515
+ init_orchestrator()
24516
+ ]);
24314
24517
  VERIFY_TIMEOUT_MS = Math.max(5000, Number(process.env.UNBROWSE_STALE_VERIFY_TIMEOUT_MS ?? 15000));
24315
24518
  CLEANUP_INTERVAL_MS = Math.max(30 * 60 * 1000, Number(process.env.UNBROWSE_STALE_CLEANUP_INTERVAL_MS ?? 6 * 60 * 60 * 1000));
24316
24519
  CLEANUP_BATCH_SIZE = Math.max(1, Number(process.env.UNBROWSE_STALE_CLEANUP_BATCH_SIZE ?? 25));
@@ -25352,7 +25555,7 @@ async function registerRoutes(app) {
25352
25555
  if (!skill)
25353
25556
  return reply.code(404).send({ error: "Skill not found" });
25354
25557
  try {
25355
- const { verifySkill: verifySkill2 } = await Promise.resolve().then(() => (init_verification(), exports_verification));
25558
+ const { verifySkill: verifySkill2 } = await init_verification().then(() => exports_verification);
25356
25559
  const results = await verifySkill2(skill);
25357
25560
  return reply.send({ skill_id, verification: results });
25358
25561
  } catch (err) {
@@ -25945,7 +26148,6 @@ var BETA_API_URL, TRACES_DIR, BROWSE_BROKER_MAX, BROWSE_BROKER_BASE_PORT, browse
25945
26148
  var init_routes = __esm(async () => {
25946
26149
  init_client();
25947
26150
  init_reverse_engineer();
25948
- init_capture();
25949
26151
  init_marketplace();
25950
26152
  init_graph();
25951
26153
  init_client2();
@@ -25964,6 +26166,7 @@ var init_routes = __esm(async () => {
25964
26166
  init_schema_review();
25965
26167
  init_artifact();
25966
26168
  await __promiseAll([
26169
+ init_capture(),
25967
26170
  init_indexer(),
25968
26171
  init_vault(),
25969
26172
  init_orchestrator(),
@@ -25986,12 +26189,12 @@ import { config as loadEnv } from "dotenv";
25986
26189
 
25987
26190
  // ../../src/server.ts
25988
26191
  init_ratelimit();
25989
- init_verification();
25990
26192
  init_client2();
25991
- init_capture();
25992
26193
  init_version();
25993
26194
  await __promiseAll([
25994
26195
  init_routes(),
26196
+ init_verification(),
26197
+ init_capture(),
25995
26198
  init_stale_cleanup_runner()
25996
26199
  ]);
25997
26200
  import { execSync as execSync2 } from "node:child_process";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unbrowse",
3
- "version": "3.2.2",
3
+ "version": "3.2.3-experiments.8932456",
4
4
  "description": "Reverse-engineer any website into reusable API skills. Zero-dep single binary with embedded browser engine.",
5
5
  "type": "module",
6
6
  "bin": {