unbrowse 2.8.0 → 2.8.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
@@ -6116,6 +6116,10 @@ async function interactiveLogin(url, domain) {
6116
6116
  const vaultKey = `auth:${getRegistrableDomain(targetDomain)}`;
6117
6117
  await storeCredential(vaultKey, JSON.stringify({ cookies: storableCookies }));
6118
6118
  log("auth", `stored ${storableCookies.length} cookies under ${vaultKey}`);
6119
+ try {
6120
+ await authProfileSave(tabId, targetDomain.replace(/^www\./, ""));
6121
+ log("auth", `saved Kuri auth profile for ${targetDomain}`);
6122
+ } catch {}
6119
6123
  return { success: true, domain: targetDomain, cookies_stored: storableCookies.length };
6120
6124
  } finally {
6121
6125
  if (prevHeadless !== undefined)
@@ -17109,7 +17113,20 @@ async function registerRoutes(app) {
17109
17113
  const rawEndpoints = extractEndpoints(allRequests, undefined, { pageUrl: session.url, finalUrl: session.url });
17110
17114
  if (rawEndpoints.length > 0) {
17111
17115
  const existingSkill = findExistingSkillForDomain(domain);
17112
- const mergedEps = existingSkill ? mergeEndpoints(existingSkill.endpoints, rawEndpoints) : rawEndpoints;
17116
+ let allExisting = existingSkill?.endpoints ?? [];
17117
+ const domainKey = getDomainReuseKey(session.url ?? domain);
17118
+ if (domainKey) {
17119
+ const cached = domainSkillCache.get(domainKey);
17120
+ if (cached?.localSkillPath) {
17121
+ try {
17122
+ const snapshot2 = JSON.parse(__require("fs").readFileSync(cached.localSkillPath, "utf-8"));
17123
+ if (snapshot2?.endpoints?.length > 0) {
17124
+ allExisting = mergeEndpoints(allExisting, snapshot2.endpoints);
17125
+ }
17126
+ } catch {}
17127
+ }
17128
+ }
17129
+ const mergedEps = allExisting.length > 0 ? mergeEndpoints(allExisting, rawEndpoints) : rawEndpoints;
17113
17130
  if (!existingSkill || mergedEps.length >= existingSkill.endpoints.length) {
17114
17131
  for (const ep of mergedEps) {
17115
17132
  if (!ep.description)
@@ -17134,9 +17151,9 @@ async function registerRoutes(app) {
17134
17151
  const cacheKey = buildResolveCacheKey(domain, `browse ${domain}`, session.url);
17135
17152
  const scopedKey = scopedCacheKey("global", cacheKey);
17136
17153
  writeSkillSnapshot(scopedKey, quickSkill);
17137
- const domainKey = getDomainReuseKey(session.url ?? domain);
17138
- if (domainKey) {
17139
- domainSkillCache.set(domainKey, {
17154
+ const domainKey2 = getDomainReuseKey(session.url ?? domain);
17155
+ if (domainKey2) {
17156
+ domainSkillCache.set(domainKey2, {
17140
17157
  skillId: quickSkill.skill_id,
17141
17158
  localSkillPath: snapshotPathForCacheKey(scopedKey),
17142
17159
  ts: Date.now()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unbrowse",
3
- "version": "2.8.0",
3
+ "version": "2.8.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": {
@@ -897,8 +897,23 @@ export async function registerRoutes(app: FastifyInstance) {
897
897
  try { domain = new URL(session.url).hostname; } catch { domain = session.domain; }
898
898
  const rawEndpoints = extractEndpoints(allRequests, undefined, { pageUrl: session.url, finalUrl: session.url });
899
899
  if (rawEndpoints.length > 0) {
900
+ // Merge with ALL known endpoints for this domain (local skill + domain cache snapshot)
900
901
  const existingSkill = findExistingSkillForDomain(domain);
901
- const mergedEps = existingSkill ? mergeEndpoints(existingSkill.endpoints, rawEndpoints) : rawEndpoints;
902
+ let allExisting = existingSkill?.endpoints ?? [];
903
+ // Also check domain cache snapshot for additional endpoints from prior captures
904
+ const domainKey = getDomainReuseKey(session.url ?? domain);
905
+ if (domainKey) {
906
+ const cached = domainSkillCache.get(domainKey);
907
+ if (cached?.localSkillPath) {
908
+ try {
909
+ const snapshot = JSON.parse(require("fs").readFileSync(cached.localSkillPath, "utf-8"));
910
+ if (snapshot?.endpoints?.length > 0) {
911
+ allExisting = mergeEndpoints(allExisting, snapshot.endpoints);
912
+ }
913
+ } catch { /* snapshot read failed */ }
914
+ }
915
+ }
916
+ const mergedEps = allExisting.length > 0 ? mergeEndpoints(allExisting, rawEndpoints) : rawEndpoints;
902
917
  if (!existingSkill || mergedEps.length >= existingSkill.endpoints.length) {
903
918
  for (const ep of mergedEps) { if (!ep.description) ep.description = generateLocalDescription(ep); }
904
919
  const quickSkill: SkillManifest = {
@@ -142,6 +142,12 @@ export async function interactiveLogin(
142
142
  await storeCredential(vaultKey, JSON.stringify({ cookies: storableCookies }));
143
143
  log("auth", `stored ${storableCookies.length} cookies under ${vaultKey}`);
144
144
 
145
+ // Also save as Kuri auth profile so browse commands (go/snap/click) have auth
146
+ try {
147
+ await kuri.authProfileSave(tabId, targetDomain.replace(/^www\./, ""));
148
+ log("auth", `saved Kuri auth profile for ${targetDomain}`);
149
+ } catch { /* non-fatal — Kuri auth profile save is best-effort */ }
150
+
145
151
  return { success: true, domain: targetDomain, cookies_stored: storableCookies.length };
146
152
  } finally {
147
153
  // Restore headless setting so subsequent captures run headless