unbrowse 3.6.0 → 3.7.0-preview.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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.6.0", BUILD_GIT_SHA = "d598e34517f7", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy42LjAiLCJnaXRfc2hhIjoiZDU5OGUzNDUxN2Y3IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUBkNTk4ZTM0NTE3ZjciLCJpc3N1ZWRfYXQiOiIyMDI2LTA0LTA5VDIyOjU0OjE2LjkyNVoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "QYlGIFDhKbCtaXoeeGCG8eJde-VnRFlXyNOJanZJ1Mk", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
34
+ var BUILD_RELEASE_VERSION = "3.7.0-preview.2", BUILD_GIT_SHA = "c3b7d2a563b0", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy43LjAtcHJldmlldy4yIiwiZ2l0X3NoYSI6ImMzYjdkMmE1NjNiMCIsImNvZGVfaGFzaCI6IjVkOWViZjYxOWM2MSIsInRyYWNlX3ZlcnNpb24iOiI1ZDllYmY2MTljNjFAYzNiN2QyYTU2M2IwIiwiaXNzdWVkX2F0IjoiMjAyNi0wNC0xMFQwNTo0OTo0OS45OTBaIn0", BUILD_RELEASE_MANIFEST_SIGNATURE = "Y_s0r-BxEwdCh5t91laYK58bdu_st2vyzaQdPhhepGY", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
35
35
 
36
36
  // ../../src/version.ts
37
37
  import { createHash } from "crypto";
package/dist/mcp.js CHANGED
@@ -225,11 +225,11 @@ 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.6.0";
229
- var BUILD_GIT_SHA = "d598e34517f7";
228
+ var BUILD_RELEASE_VERSION = "3.7.0-preview.2";
229
+ var BUILD_GIT_SHA = "c3b7d2a563b0";
230
230
  var BUILD_CODE_HASH = "5d9ebf619c61";
231
- var BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy42LjAiLCJnaXRfc2hhIjoiZDU5OGUzNDUxN2Y3IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUBkNTk4ZTM0NTE3ZjciLCJpc3N1ZWRfYXQiOiIyMDI2LTA0LTA5VDIyOjU0OjE2LjkyNVoifQ";
232
- var BUILD_RELEASE_MANIFEST_SIGNATURE = "QYlGIFDhKbCtaXoeeGCG8eJde-VnRFlXyNOJanZJ1Mk";
231
+ var BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy43LjAtcHJldmlldy4yIiwiZ2l0X3NoYSI6ImMzYjdkMmE1NjNiMCIsImNvZGVfaGFzaCI6IjVkOWViZjYxOWM2MSIsInRyYWNlX3ZlcnNpb24iOiI1ZDllYmY2MTljNjFAYzNiN2QyYTU2M2IwIiwiaXNzdWVkX2F0IjoiMjAyNi0wNC0xMFQwNTo0OTo0OS45OTBaIn0";
232
+ var BUILD_RELEASE_MANIFEST_SIGNATURE = "Y_s0r-BxEwdCh5t91laYK58bdu_st2vyzaQdPhhepGY";
233
233
  var BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
234
234
 
235
235
  // ../../src/version.ts
package/dist/server.js CHANGED
@@ -1910,6 +1910,22 @@ function deriveTemplateParamsFromContextUrl(urlTemplate, contextUrl) {
1910
1910
  const actualValue = actualUrl.searchParams.get(key);
1911
1911
  if (actualValue != null && actualValue !== "") {
1912
1912
  out[placeholder] = actualValue;
1913
+ continue;
1914
+ }
1915
+ const byPlaceholderName = actualUrl.searchParams.get(placeholder);
1916
+ if (byPlaceholderName != null && byPlaceholderName !== "") {
1917
+ out[placeholder] = byPlaceholderName;
1918
+ continue;
1919
+ }
1920
+ const lowerPlaceholder = placeholder.toLowerCase();
1921
+ if (/^(q|query|search|text|keyword|keywords|term|terms)$/.test(lowerPlaceholder)) {
1922
+ for (const alias of ["q", "query", "search", "text", "keyword", "keywords", "term"]) {
1923
+ const v = actualUrl.searchParams.get(alias);
1924
+ if (v != null && v !== "") {
1925
+ out[placeholder] = v;
1926
+ break;
1927
+ }
1928
+ }
1913
1929
  }
1914
1930
  }
1915
1931
  return out;
@@ -3827,6 +3843,13 @@ __export(exports_reverse_engineer, {
3827
3843
  extractAuthHeaders: () => extractAuthHeaders
3828
3844
  });
3829
3845
  import { nanoid as nanoid2 } from "nanoid";
3846
+ import { createHash } from "node:crypto";
3847
+ function stableEndpointId(method, urlTemplate) {
3848
+ if (!method || !urlTemplate)
3849
+ return nanoid2();
3850
+ const hash = createHash("sha256").update(`${method}:${urlTemplate}`).digest("base64url");
3851
+ return hash.slice(0, 21);
3852
+ }
3830
3853
  function extractGraphQLOperationName(url, requestBody) {
3831
3854
  const urlMatch = url.match(/\/graphql\/[^/]+\/(\w+)/);
3832
3855
  if (urlMatch)
@@ -4447,10 +4470,11 @@ function extractEndpoints(requests, wsMessages, context) {
4447
4470
  });
4448
4471
  const csrfPlan = inferCsrfPlan(req, parsedRequestBody);
4449
4472
  const endpointGraphqlOp = /graphql/i.test(req.url) ? extractGraphQLOperationName(req.url, req.request_body) : undefined;
4473
+ const computedUrlTemplate = qTemplateStr ? `${pathTemplate}${pathTemplate.includes("?") ? "&" : "?"}${qTemplateStr}` : pathTemplate;
4450
4474
  let endpoint = {
4451
- endpoint_id: nanoid2(),
4475
+ endpoint_id: stableEndpointId(req.method, computedUrlTemplate),
4452
4476
  method: req.method,
4453
- url_template: qTemplateStr ? `${pathTemplate}${pathTemplate.includes("?") ? "&" : "?"}${qTemplateStr}` : pathTemplate,
4477
+ url_template: computedUrlTemplate,
4454
4478
  description: buildEndpointDescription(req, sampleRequest, sampleResponse),
4455
4479
  headers_template: sanitizeHeaders(req.request_headers),
4456
4480
  query: sanitizedQParams,
@@ -4541,7 +4565,7 @@ function extractEndpoints(requests, wsMessages, context) {
4541
4565
  response_schema = inferSchema(jsonSamples);
4542
4566
  }
4543
4567
  const endpoint = {
4544
- endpoint_id: nanoid2(),
4568
+ endpoint_id: stableEndpointId("WS", wsUrl),
4545
4569
  method: "WS",
4546
4570
  url_template: wsUrl,
4547
4571
  idempotency: "safe",
@@ -7096,10 +7120,10 @@ var init_capture = __esm(async () => {
7096
7120
  });
7097
7121
 
7098
7122
  // ../../src/build-info.generated.ts
7099
- var BUILD_RELEASE_VERSION = "3.6.0", BUILD_GIT_SHA = "d598e34517f7", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy42LjAiLCJnaXRfc2hhIjoiZDU5OGUzNDUxN2Y3IiwiY29kZV9oYXNoIjoiNWQ5ZWJmNjE5YzYxIiwidHJhY2VfdmVyc2lvbiI6IjVkOWViZjYxOWM2MUBkNTk4ZTM0NTE3ZjciLCJpc3N1ZWRfYXQiOiIyMDI2LTA0LTA5VDIyOjU0OjE2LjkyNVoifQ", BUILD_RELEASE_MANIFEST_SIGNATURE = "QYlGIFDhKbCtaXoeeGCG8eJde-VnRFlXyNOJanZJ1Mk", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
7123
+ var BUILD_RELEASE_VERSION = "3.7.0-preview.2", BUILD_GIT_SHA = "c3b7d2a563b0", BUILD_CODE_HASH = "5d9ebf619c61", BUILD_RELEASE_MANIFEST_BASE64 = "eyJzY2hlbWFfdmVyc2lvbiI6MSwicmVsZWFzZV92ZXJzaW9uIjoiMy43LjAtcHJldmlldy4yIiwiZ2l0X3NoYSI6ImMzYjdkMmE1NjNiMCIsImNvZGVfaGFzaCI6IjVkOWViZjYxOWM2MSIsInRyYWNlX3ZlcnNpb24iOiI1ZDllYmY2MTljNjFAYzNiN2QyYTU2M2IwIiwiaXNzdWVkX2F0IjoiMjAyNi0wNC0xMFQwNTo0OTo0OS45OTBaIn0", BUILD_RELEASE_MANIFEST_SIGNATURE = "Y_s0r-BxEwdCh5t91laYK58bdu_st2vyzaQdPhhepGY", BUILD_DEFAULT_BACKEND_URL = "https://beta-api.unbrowse.ai";
7100
7124
 
7101
7125
  // ../../src/version.ts
7102
- import { createHash } from "crypto";
7126
+ import { createHash as createHash2 } from "crypto";
7103
7127
  import { existsSync as existsSync4, readFileSync as readFileSync2, readdirSync } from "fs";
7104
7128
  import { dirname, join as join3, parse } from "path";
7105
7129
  import { fileURLToPath as fileURLToPath2 } from "url";
@@ -7116,7 +7140,7 @@ function collectTsFiles(dir) {
7116
7140
  return results;
7117
7141
  }
7118
7142
  function hashFiles(srcDir, files) {
7119
- const hash = createHash("sha256");
7143
+ const hash = createHash2("sha256");
7120
7144
  for (const file of files) {
7121
7145
  hash.update(file.slice(srcDir.length));
7122
7146
  hash.update(readFileSync2(file, "utf-8"));
@@ -7156,7 +7180,7 @@ function computeCodeHash() {
7156
7180
  } catch {}
7157
7181
  const pkgVersion = getPackageVersion();
7158
7182
  if (pkgVersion !== "unknown") {
7159
- return createHash("sha256").update(`package:${pkgVersion}`).digest("hex").slice(0, 12);
7183
+ return createHash2("sha256").update(`package:${pkgVersion}`).digest("hex").slice(0, 12);
7160
7184
  }
7161
7185
  return "compiled";
7162
7186
  }
@@ -7210,13 +7234,13 @@ var init_version = __esm(() => {
7210
7234
  });
7211
7235
 
7212
7236
  // ../../src/payments/cascade.ts
7213
- import { createHash as createHash2 } from "crypto";
7237
+ import { createHash as createHash3 } from "crypto";
7214
7238
  import bs58 from "bs58";
7215
7239
  function payableContributors(skill) {
7216
7240
  return (skill.contributors ?? []).filter((c) => !!c.wallet_address?.trim());
7217
7241
  }
7218
7242
  function cascadeLabel(skillId) {
7219
- const digest = createHash2("sha256").update(skillId).digest("hex");
7243
+ const digest = createHash3("sha256").update(skillId).digest("hex");
7220
7244
  return `ubr-${digest.slice(0, 23)}`;
7221
7245
  }
7222
7246
  function decodeSecretKey(raw) {
@@ -7610,7 +7634,7 @@ __export(exports_client2, {
7610
7634
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync4, readdirSync as readdirSync2, unlinkSync } from "fs";
7611
7635
  import { join as join6 } from "path";
7612
7636
  import { homedir as homedir4, hostname, release as osRelease } from "os";
7613
- import { randomBytes as randomBytes2, createHash as createHash3 } from "crypto";
7637
+ import { randomBytes as randomBytes2, createHash as createHash4 } from "crypto";
7614
7638
  import { createInterface } from "readline";
7615
7639
  import { execSync } from "child_process";
7616
7640
  function buildReleaseAttestationHeaders(manifestBase64, signature) {
@@ -7887,7 +7911,7 @@ function getApiKey() {
7887
7911
  function hashApiKey(key) {
7888
7912
  if (!key || key === "local-only")
7889
7913
  return "";
7890
- return createHash3("sha256").update(key).digest("hex");
7914
+ return createHash4("sha256").update(key).digest("hex");
7891
7915
  }
7892
7916
  function getAgentId() {
7893
7917
  const config = loadConfig();
@@ -9069,7 +9093,7 @@ var init_publish_admission = __esm(() => {
9069
9093
  });
9070
9094
 
9071
9095
  // ../../src/telemetry.ts
9072
- import { createHash as createHash4 } from "node:crypto";
9096
+ import { createHash as createHash5 } from "node:crypto";
9073
9097
  import { existsSync as existsSync8, mkdirSync as mkdirSync5, writeFileSync as writeFileSync4 } from "node:fs";
9074
9098
  import { join as join7 } from "node:path";
9075
9099
  function getTraceDir() {
@@ -9079,7 +9103,7 @@ function isTracingEnabled() {
9079
9103
  return process.env.UNBROWSE_DISABLE_TRACES !== "1";
9080
9104
  }
9081
9105
  function hashValue(value) {
9082
- return createHash4("sha256").update(value).digest("hex").slice(0, 16);
9106
+ return createHash5("sha256").update(value).digest("hex").slice(0, 16);
9083
9107
  }
9084
9108
  function isSensitiveName(name) {
9085
9109
  return SENSITIVE_PATTERNS.some((re) => re.test(name));
@@ -9097,7 +9121,7 @@ function anonymizeUrl(url) {
9097
9121
  }
9098
9122
  function hashResponseBody(result) {
9099
9123
  const str = typeof result === "string" ? result : JSON.stringify(result ?? "");
9100
- return createHash4("sha256").update(str).digest("hex").slice(0, 32);
9124
+ return createHash5("sha256").update(str).digest("hex").slice(0, 32);
9101
9125
  }
9102
9126
  function classifyFailure(error) {
9103
9127
  if (!error)
@@ -15495,7 +15519,12 @@ __export(exports_execution, {
15495
15519
  buildCanonicalDocumentEndpoint: () => buildCanonicalDocumentEndpoint
15496
15520
  });
15497
15521
  import { nanoid as nanoid6 } from "nanoid";
15498
- import { createHash as createHash5 } from "node:crypto";
15522
+ import { createHash as createHash6 } from "node:crypto";
15523
+ function stableEndpointId2(method, urlTemplate) {
15524
+ if (!method || !urlTemplate)
15525
+ return nanoid6();
15526
+ return createHash6("sha256").update(`${method}:${urlTemplate}`).digest("base64url").slice(0, 21);
15527
+ }
15499
15528
  function stampTrace(trace) {
15500
15529
  trace.trace_version = TRACE_VERSION;
15501
15530
  return trace;
@@ -16039,10 +16068,11 @@ function buildPageArtifactCapture(url, intent, html, authRequired = false) {
16039
16068
  const searchForms = detectSearchForms(html);
16040
16069
  const validSearchForm = searchForms.find((spec) => isStructuredSearchForm(spec));
16041
16070
  const response_schema = inferSchema([extracted.data]);
16071
+ const computedTemplate = templatizeQueryParams(url);
16042
16072
  const endpoint = {
16043
- endpoint_id: nanoid6(),
16073
+ endpoint_id: stableEndpointId2("GET", computedTemplate),
16044
16074
  method: "GET",
16045
- url_template: templatizeQueryParams(url),
16075
+ url_template: computedTemplate,
16046
16076
  idempotency: "safe",
16047
16077
  verification_status: "verified",
16048
16078
  reliability_score: extracted.confidence,
@@ -16090,7 +16120,7 @@ function buildCanonicalDocumentEndpoint(url, intent, authRequired = false) {
16090
16120
  const replayTemplate = deriveStructuredDataReplayTemplate(url);
16091
16121
  if (replayUrl === url && replayTemplate === url)
16092
16122
  return;
16093
- const canonicalId = createHash5("sha1").update(replayTemplate !== url ? replayTemplate : replayUrl).digest("base64url").slice(0, 21);
16123
+ const canonicalId = createHash6("sha1").update(replayTemplate !== url ? replayTemplate : replayUrl).digest("base64url").slice(0, 21);
16094
16124
  const endpoint = {
16095
16125
  endpoint_id: canonicalId,
16096
16126
  method: "GET",
@@ -16595,7 +16625,7 @@ async function executeBrowserCapture(skill, params, options) {
16595
16625
  epUrl = `${route.url}?${qStr}`;
16596
16626
  }
16597
16627
  endpoints.push({
16598
- endpoint_id: nanoid6(),
16628
+ endpoint_id: stableEndpointId2("GET", epUrl),
16599
16629
  method: "GET",
16600
16630
  url_template: epUrl,
16601
16631
  query: epQuery,
@@ -19117,10 +19147,10 @@ var init_timing_economics = __esm(() => {
19117
19147
  });
19118
19148
 
19119
19149
  // ../../src/routing-telemetry.ts
19120
- import { createHash as createHash6 } from "node:crypto";
19150
+ import { createHash as createHash7 } from "node:crypto";
19121
19151
  import { nanoid as nanoid8 } from "nanoid";
19122
19152
  function stableHash(value) {
19123
- return createHash6("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 24);
19153
+ return createHash7("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 24);
19124
19154
  }
19125
19155
  function sanitizeScalar(value) {
19126
19156
  if (value == null)
@@ -19474,7 +19504,7 @@ function applyVerificationResults(skill, verification) {
19474
19504
  import { nanoid as nanoid9 } from "nanoid";
19475
19505
  import { existsSync as existsSync13, writeFileSync as writeFileSync8, readFileSync as readFileSync8, mkdirSync as mkdirSync9, readdirSync as readdirSync6 } from "node:fs";
19476
19506
  import { dirname as dirname2, join as join12 } from "node:path";
19477
- import { createHash as createHash7 } from "node:crypto";
19507
+ import { createHash as createHash8 } from "node:crypto";
19478
19508
  function summarizeSchema(schema, maxDepth = 3) {
19479
19509
  function walk(s, depth) {
19480
19510
  if (depth <= 0)
@@ -19602,7 +19632,7 @@ function scopedResolveCacheKeys(scope, key) {
19602
19632
  return scope === "global" ? [scopedCacheKey("global", key)] : [scopedCacheKey(scope, key), scopedCacheKey("global", key)];
19603
19633
  }
19604
19634
  function snapshotPathForCacheKey(cacheKey) {
19605
- const digest = createHash7("sha1").update(cacheKey).digest("hex");
19635
+ const digest = createHash8("sha1").update(cacheKey).digest("hex");
19606
19636
  return join12(SKILL_SNAPSHOT_DIR, `${digest}.json`);
19607
19637
  }
19608
19638
  function writeSkillSnapshot(cacheKey, skill) {
@@ -19928,7 +19958,12 @@ function withContextReplayEndpoint(skill, intent, contextUrl) {
19928
19958
  ...skill,
19929
19959
  endpoints: [canonical, ...skill.endpoints]
19930
19960
  };
19931
- cachePublishedSkill(augmented);
19961
+ try {
19962
+ const existing = findExistingSkillForDomain(skill.domain);
19963
+ if (!existing || !existing.endpoints.some((ep) => ep.endpoint_id === canonical.endpoint_id)) {
19964
+ cachePublishedSkill(augmented);
19965
+ }
19966
+ } catch {}
19932
19967
  return augmented;
19933
19968
  }
19934
19969
  function isSearchLikeIntent(intent, contextUrl) {
@@ -19948,7 +19983,7 @@ function buildLocalCanonicalReplaySkill(intent, contextUrl) {
19948
19983
  const domain = new URL(contextUrl).hostname.replace(/^www\./, "");
19949
19984
  const now = new Date().toISOString();
19950
19985
  const skill = {
19951
- skill_id: `canonical-${createHash7("sha1").update(contextUrl).digest("hex").slice(0, 12)}`,
19986
+ skill_id: `canonical-${createHash8("sha1").update(contextUrl).digest("hex").slice(0, 12)}`,
19952
19987
  version: "1.0.0",
19953
19988
  schema_version: "1",
19954
19989
  name: `Canonical replay for ${domain}`,
@@ -22152,7 +22187,15 @@ async function resolveAndExecute(intent, params = {}, context, projection, optio
22152
22187
  continue;
22153
22188
  let endpointId = extractEndpointId(c.metadata) ?? undefined;
22154
22189
  if (endpointId && !skill.endpoints.some((ep) => ep.endpoint_id === endpointId)) {
22155
- endpointId = undefined;
22190
+ const vecUrl = c.metadata?.url_template;
22191
+ const urlMatch = vecUrl ? skill.endpoints.find((ep) => ep.url_template === vecUrl) : undefined;
22192
+ if (urlMatch) {
22193
+ console.log(`[marketplace] vecdb endpoint ${endpointId} stale → recovered via URL match: ${urlMatch.endpoint_id}`);
22194
+ endpointId = urlMatch.endpoint_id;
22195
+ } else {
22196
+ console.log(`[marketplace] vecdb endpoint ${endpointId} not found on skill ${skillId} — dropping to skill-level match`);
22197
+ endpointId = undefined;
22198
+ }
22156
22199
  }
22157
22200
  ranked.push({
22158
22201
  candidate: c,
@@ -24194,7 +24237,13 @@ var init_browse_session = __esm(() => {
24194
24237
 
24195
24238
  // ../../src/api/browse-index.ts
24196
24239
  import { nanoid as nanoid10 } from "nanoid";
24240
+ import { createHash as createHash9 } from "node:crypto";
24197
24241
  import { readFileSync as readFileSync12 } from "node:fs";
24242
+ function stableEndpointId3(method, urlTemplate) {
24243
+ if (!method || !urlTemplate)
24244
+ return nanoid10();
24245
+ return createHash9("sha256").update(`${method}:${urlTemplate}`).digest("base64url").slice(0, 21);
24246
+ }
24198
24247
  function normalizeBrowseUrl(url, baseUrl) {
24199
24248
  if (!url)
24200
24249
  return url;
@@ -24372,7 +24421,7 @@ async function cacheBrowseRequests(params) {
24372
24421
  return { domain, indexed: false, mode: "none", skill: null };
24373
24422
  const urlTemplate = templatizeQueryParams2(sessionUrl);
24374
24423
  const endpoint = {
24375
- endpoint_id: nanoid10(),
24424
+ endpoint_id: stableEndpointId3("GET", urlTemplate),
24376
24425
  method: "GET",
24377
24426
  url_template: urlTemplate,
24378
24427
  idempotency: "safe",
@@ -26678,7 +26727,28 @@ async function registerRoutes(app) {
26678
26727
  ...context_url && typeof params?.url !== "string" ? { url: context_url } : {}
26679
26728
  };
26680
26729
  try {
26681
- const execResult = await executeSkill(skill, execParams, projection, { confirm_unsafe, confirm_third_party_terms, dry_run, skip_robots_check, intent, contextUrl: context_url, client_scope: clientScope });
26730
+ let execResult = await executeSkill(skill, execParams, projection, { confirm_unsafe, confirm_third_party_terms, dry_run, skip_robots_check, intent, contextUrl: context_url, client_scope: clientScope });
26731
+ if (!execResult.trace.success && execResult.result?.error === "endpoint_not_found" && typeof execParams.endpoint_id === "string") {
26732
+ let recovered = false;
26733
+ const freshSkill = await getSkill2(skill_id, clientScope);
26734
+ if (freshSkill && freshSkill.endpoints.some((e) => e.endpoint_id === execParams.endpoint_id)) {
26735
+ console.log(`[exec] endpoint ${execParams.endpoint_id} found in fresh marketplace skill — retrying`);
26736
+ skill = freshSkill;
26737
+ recovered = true;
26738
+ }
26739
+ if (!recovered && context_url) {
26740
+ const { buildCanonicalDocumentEndpoint: buildCanonicalDocumentEndpoint2 } = await init_execution().then(() => exports_execution);
26741
+ const canonical = buildCanonicalDocumentEndpoint2(context_url, intent ?? "", false);
26742
+ if (canonical && canonical.endpoint_id === execParams.endpoint_id) {
26743
+ console.log(`[exec] endpoint ${execParams.endpoint_id} is a canonical replay — injecting into skill`);
26744
+ skill = { ...skill, endpoints: [canonical, ...skill.endpoints] };
26745
+ recovered = true;
26746
+ }
26747
+ }
26748
+ if (recovered) {
26749
+ execResult = await executeSkill(skill, execParams, projection, { confirm_unsafe, confirm_third_party_terms, dry_run, skip_robots_check, intent, contextUrl: context_url, client_scope: clientScope });
26750
+ }
26751
+ }
26682
26752
  saveTrace(execResult.trace);
26683
26753
  if (execResult.trace.endpoint_id) {
26684
26754
  recordExecution(skill.skill_id, execResult.trace.endpoint_id, execResult.trace, skill).catch(() => {});
@@ -27584,7 +27654,7 @@ var init_routes = __esm(async () => {
27584
27654
  ]);
27585
27655
  BETA_API_URL = process.env.UNBROWSE_BACKEND_URL || DEFAULT_BACKEND_URL;
27586
27656
  TRACES_DIR = process.env.TRACES_DIR ?? join17(process.cwd(), "traces");
27587
- BROWSE_BROKER_MAX = Math.max(1, Number(process.env.KURI_MULTI_BROKER_MAX ?? "2"));
27657
+ BROWSE_BROKER_MAX = Math.max(1, Number(process.env.KURI_MULTI_BROKER_MAX ?? "1"));
27588
27658
  BROWSE_BROKER_BASE_PORT = Number(process.env.KURI_PORT ?? "7700");
27589
27659
  browseSessions = new Map;
27590
27660
  STATS_CACHE_TTL = 5 * 60 * 1000;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unbrowse",
3
- "version": "3.6.0",
3
+ "version": "3.7.0-preview.2",
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": {
@@ -29,6 +29,8 @@
29
29
  "@fastify/rate-limit": "^10.3.0",
30
30
  "@cascade-fyi/splits-sdk": "^0.11.1",
31
31
  "@solana/kit": "^6.6.0",
32
+ "@x402/fetch": "^2.9.0",
33
+ "agentmail": "^0.4.18",
32
34
  "bs58": "^6.0.0",
33
35
  "cheerio": "^1.2.0",
34
36
  "dotenv": "^17.3.1",