unbrowse 12.1.0 → 12.1.1
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 +68 -3
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -98,6 +98,43 @@ class Unbrowse {
|
|
|
98
98
|
cancel(runId) {
|
|
99
99
|
return this.req(`/runs/${runId}/cancel`, { method: "POST" });
|
|
100
100
|
}
|
|
101
|
+
async runOnClient(request, opts = {}) {
|
|
102
|
+
const send = opts.fetch ?? ((...a) => globalThis.fetch(...a));
|
|
103
|
+
const deadline = Date.now() + (opts.timeoutMs ?? 600000);
|
|
104
|
+
let step = await this.run({ ...request, egress: "client" });
|
|
105
|
+
while (isEgressStep(step)) {
|
|
106
|
+
if (Date.now() > deadline) {
|
|
107
|
+
await this.closeEgress(step.egressId).catch(() => {
|
|
108
|
+
return;
|
|
109
|
+
});
|
|
110
|
+
throw new UnbrowseError("client-egress run did not finish in time", 408, "timeout");
|
|
111
|
+
}
|
|
112
|
+
const { egressId } = step;
|
|
113
|
+
for (const req of step.requests) {
|
|
114
|
+
let answer;
|
|
115
|
+
try {
|
|
116
|
+
if (await opts.onRequest?.(req) === false)
|
|
117
|
+
throw new Error("refused by onRequest");
|
|
118
|
+
answer = { response: await sendEgress(send, req) };
|
|
119
|
+
} catch (err) {
|
|
120
|
+
answer = { error: err instanceof Error ? err.message : String(err) };
|
|
121
|
+
}
|
|
122
|
+
step = await this.answerEgress(egressId, req.id, answer);
|
|
123
|
+
if (!isEgressStep(step))
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return step;
|
|
128
|
+
}
|
|
129
|
+
egress(egressId) {
|
|
130
|
+
return this.req(`/egress/${egressId}`);
|
|
131
|
+
}
|
|
132
|
+
answerEgress(egressId, requestId, answer) {
|
|
133
|
+
return this.post(`/egress/${egressId}`, { requestId, ...answer });
|
|
134
|
+
}
|
|
135
|
+
closeEgress(egressId) {
|
|
136
|
+
return this.req(`/egress/${egressId}`, { method: "DELETE" });
|
|
137
|
+
}
|
|
101
138
|
discover(query) {
|
|
102
139
|
return this.post("/capabilities/search", { query });
|
|
103
140
|
}
|
|
@@ -159,6 +196,32 @@ function normalizeHost(site) {
|
|
|
159
196
|
host = new URL(host).hostname;
|
|
160
197
|
return host.replace(/\/.*$/, "").replace(/^www\./, "");
|
|
161
198
|
}
|
|
199
|
+
function isEgressStep(v) {
|
|
200
|
+
return !!v && typeof v === "object" && v.status === "egress_required";
|
|
201
|
+
}
|
|
202
|
+
async function sendEgress(send, req) {
|
|
203
|
+
const body = req.body === undefined ? undefined : req.bodyEncoding === "base64" ? base64ToBytes(req.body) : req.body;
|
|
204
|
+
const res = await send(req.url, { method: req.method, headers: req.headers, redirect: req.redirect, ...body !== undefined ? { body } : {} });
|
|
205
|
+
const headers = [];
|
|
206
|
+
res.headers.forEach((value, name) => headers.push([name, value]));
|
|
207
|
+
const cookies = res.headers.getSetCookie?.();
|
|
208
|
+
const pairs = cookies?.length ? [...headers.filter(([n]) => n.toLowerCase() !== "set-cookie"), ...cookies.map((c) => ["set-cookie", c])] : headers;
|
|
209
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
210
|
+
return { status: res.status, headers: pairs, body: bytesToBase64(bytes), bodyEncoding: "base64", ...res.url ? { url: res.url } : {} };
|
|
211
|
+
}
|
|
212
|
+
function base64ToBytes(b64) {
|
|
213
|
+
const bin = atob(b64);
|
|
214
|
+
const out = new Uint8Array(bin.length);
|
|
215
|
+
for (let i = 0;i < bin.length; i++)
|
|
216
|
+
out[i] = bin.charCodeAt(i);
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
function bytesToBase64(bytes) {
|
|
220
|
+
let bin = "";
|
|
221
|
+
for (let i = 0;i < bytes.length; i += 32768)
|
|
222
|
+
bin += String.fromCharCode(...bytes.subarray(i, i + 32768));
|
|
223
|
+
return btoa(bin);
|
|
224
|
+
}
|
|
162
225
|
var DEFAULT_BASE_URL = "https://unbrowse.ai/api/v1", UnbrowseError, env = (name) => (typeof process !== "undefined" ? process.env?.[name] : undefined) || undefined;
|
|
163
226
|
var init_client = __esm(() => {
|
|
164
227
|
UnbrowseError = class UnbrowseError extends Error {
|
|
@@ -493,7 +556,7 @@ ${url.toString()}`);
|
|
|
493
556
|
|
|
494
557
|
// src/cli.ts
|
|
495
558
|
init_src();
|
|
496
|
-
var VERSION = "12.1.
|
|
559
|
+
var VERSION = "12.1.1";
|
|
497
560
|
var DEFAULT_ORIGIN = "https://unbrowse.ai";
|
|
498
561
|
var HELP = `unbrowse ${VERSION} — call websites as APIs through the Unbrowse API
|
|
499
562
|
|
|
@@ -505,6 +568,7 @@ var HELP = `unbrowse ${VERSION} — call websites as APIs through the Unbrowse A
|
|
|
505
568
|
discover <query> Your capabilities first, then the public registry
|
|
506
569
|
run <task…> Run a task and wait for a verified result
|
|
507
570
|
[--capability ID] [--url URL] [--set key=value]… [--input JSON] [--unattended] [--no-wait]
|
|
571
|
+
[--from-here] send the site requests from this machine (your IP); Unbrowse decides and reads them
|
|
508
572
|
inspect <runId> A run's status, requirements and result
|
|
509
573
|
resume <runId> key=value… Answer open requirements on the same run
|
|
510
574
|
cancel <runId> Stop a run; prints the effect receipt
|
|
@@ -609,14 +673,15 @@ async function main(argv, io = stdio) {
|
|
|
609
673
|
if (!task && !capability)
|
|
610
674
|
throw new UsageError("usage: unbrowse run <task…> | --capability ID");
|
|
611
675
|
const input = { ...flag("input") ? JSON.parse(flag("input")) : {}, ...mapValues(args.sets) };
|
|
612
|
-
const
|
|
676
|
+
const request = {
|
|
613
677
|
...task ? { task } : {},
|
|
614
678
|
...capability ? { capability } : {},
|
|
615
679
|
...flag("url") ? { targetUrl: flag("url") } : {},
|
|
616
680
|
...Object.keys(input).length ? { input } : {},
|
|
617
681
|
...args.flags.unattended ? { interactionMode: "unattended" } : {},
|
|
618
682
|
idempotencyKey: flag("idempotency-key") ?? randomUUID()
|
|
619
|
-
}
|
|
683
|
+
};
|
|
684
|
+
const view = args.flags["from-here"] ? await ub.runOnClient(request, { onRequest: (r) => void io.err(`→ ${r.method} ${r.url}`) }) : await ub.run(request);
|
|
620
685
|
return settle(ub, view, args, io, print);
|
|
621
686
|
}
|
|
622
687
|
case "inspect":
|