@optima-chat/browser-cli 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +46 -21
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -174,10 +174,9 @@ async function requestBinary(path) {
|
|
|
174
174
|
return Buffer.from(arrayBuffer);
|
|
175
175
|
}
|
|
176
176
|
var BrowserAPI = class {
|
|
177
|
-
async createSession(url,
|
|
177
|
+
async createSession(url, force, connector, ziniaoProfileId, bitbrowserProfileId) {
|
|
178
178
|
const body = {};
|
|
179
179
|
if (url) body.url = url;
|
|
180
|
-
if (profileId) body.profile_id = profileId;
|
|
181
180
|
if (force) body.force = true;
|
|
182
181
|
if (connector) body.connector = connector;
|
|
183
182
|
if (ziniaoProfileId) body.ziniao_profile_id = ziniaoProfileId;
|
|
@@ -258,22 +257,29 @@ var BrowserAPI = class {
|
|
|
258
257
|
async getScreenshot(sessionId) {
|
|
259
258
|
return requestBinary(`/api/sessions/${sessionId}/screenshot`);
|
|
260
259
|
}
|
|
261
|
-
async runRecipeScript(name, params, pollMs = 2e3) {
|
|
260
|
+
async runRecipeScript(name, params, pollMs = 2e3, timeoutMs = 36e4) {
|
|
262
261
|
const started = await request(`/api/scripts/${name}/run`, {
|
|
263
262
|
method: "POST",
|
|
264
263
|
body: JSON.stringify({ params })
|
|
265
264
|
});
|
|
265
|
+
const deadline = Date.now() + timeoutMs;
|
|
266
266
|
for (; ; ) {
|
|
267
|
-
const task = await request(
|
|
268
|
-
`/api/script-tasks/${started.id}`
|
|
269
|
-
);
|
|
267
|
+
const task = await request(`/api/script-tasks/${started.id}`);
|
|
270
268
|
if (task.status === "completed") return task.output;
|
|
271
269
|
if (task.status === "failed" || task.status === "needs_fallback") {
|
|
272
|
-
throw new Error(task.error || `recipe ${task.status}`);
|
|
270
|
+
throw new Error(task.error || task.output?.error || `recipe ${task.status}`);
|
|
271
|
+
}
|
|
272
|
+
if (Date.now() >= deadline) {
|
|
273
|
+
throw new Error(
|
|
274
|
+
`recipe ${name} did not finish within ${Math.round(timeoutMs / 1e3)}s (task ${started.id})`
|
|
275
|
+
);
|
|
273
276
|
}
|
|
274
277
|
await new Promise((r) => setTimeout(r, pollMs));
|
|
275
278
|
}
|
|
276
279
|
}
|
|
280
|
+
async fetchArtifact(artifactPath) {
|
|
281
|
+
return requestBinary(artifactPath);
|
|
282
|
+
}
|
|
277
283
|
async search(sessionId, pattern) {
|
|
278
284
|
return request(`/api/sessions/${sessionId}/search`, {
|
|
279
285
|
method: "POST",
|
|
@@ -328,10 +334,10 @@ var BrowserAPI = class {
|
|
|
328
334
|
async deleteScript(name) {
|
|
329
335
|
await request(`/api/scripts/${encodeURIComponent(name)}`, { method: "DELETE" });
|
|
330
336
|
}
|
|
331
|
-
async runScript(scriptName, params = {},
|
|
337
|
+
async runScript(scriptName, params = {}, connector, ziniaoProfileId, bitbrowserProfileId) {
|
|
332
338
|
const payload = { params };
|
|
333
|
-
if (profileId) payload.profile_id = profileId;
|
|
334
339
|
if (connector) payload.connector = connector;
|
|
340
|
+
if (ziniaoProfileId) payload.ziniao_profile_id = ziniaoProfileId;
|
|
335
341
|
if (bitbrowserProfileId) payload.bitbrowser_profile_id = bitbrowserProfileId;
|
|
336
342
|
return request(`/api/scripts/${encodeURIComponent(scriptName)}/run`, {
|
|
337
343
|
method: "POST",
|
|
@@ -463,9 +469,9 @@ function formatProfileDelete(profileId) {
|
|
|
463
469
|
|
|
464
470
|
// src/commands/lifecycle.ts
|
|
465
471
|
function registerLifecycleCommands(program2) {
|
|
466
|
-
program2.command("launch").description("Launch a browser session").option("--url <url>", "Navigate to URL after launch").option("--
|
|
472
|
+
program2.command("launch").description("Launch a browser session").option("--url <url>", "Navigate to URL after launch").option("--force", "Close existing session before launching").option("--connector <type>", "Browser connector: chrome, ziniao, or bitbrowser").option("--ziniao-profile <id>", "ZiNiao browser profile ID").option("--bitbrowser-profile <id>", "BitBrowser profile ID").action(async (opts) => {
|
|
467
473
|
try {
|
|
468
|
-
const state = await api.createSession(opts.url, opts.
|
|
474
|
+
const state = await api.createSession(opts.url, opts.force, opts.connector, opts.ziniaoProfile, opts.bitbrowserProfile);
|
|
469
475
|
saveSessionId(state.session_id);
|
|
470
476
|
console.log(formatLaunch(state));
|
|
471
477
|
} catch (err) {
|
|
@@ -781,7 +787,7 @@ function registerScriptCommands(program2) {
|
|
|
781
787
|
process.exit(1);
|
|
782
788
|
}
|
|
783
789
|
});
|
|
784
|
-
program2.command("runscript").argument("<name>", "Script name").description("Run a script (polls until complete)").option("--param <params...>", "Parameters as key=value").option("--
|
|
790
|
+
program2.command("runscript").argument("<name>", "Script name").description("Run a script (polls until complete)").option("--param <params...>", "Parameters as key=value").option("--connector <type>", "Browser connector: chrome, ziniao, or bitbrowser").option("--ziniao-profile <id>", "ZiNiao browser profile ID (with --connector ziniao)").option("--bitbrowser-profile <id>", "BitBrowser profile ID (with --connector bitbrowser)").option("--no-poll", "Return immediately without polling").action(async (name, opts) => {
|
|
785
791
|
try {
|
|
786
792
|
const params = {};
|
|
787
793
|
if (opts.param) {
|
|
@@ -791,7 +797,7 @@ function registerScriptCommands(program2) {
|
|
|
791
797
|
}
|
|
792
798
|
}
|
|
793
799
|
clearSessionId();
|
|
794
|
-
const task = await api.runScript(name, params, opts.
|
|
800
|
+
const task = await api.runScript(name, params, opts.connector, opts.ziniaoProfile, opts.bitbrowserProfile);
|
|
795
801
|
console.log(`Script started (task: ${task.id})`);
|
|
796
802
|
if (!opts.poll) {
|
|
797
803
|
console.log(`Poll with: browser-cli script-task ${task.id}`);
|
|
@@ -828,7 +834,7 @@ function registerScriptCommands(program2) {
|
|
|
828
834
|
});
|
|
829
835
|
}
|
|
830
836
|
function sleep(ms) {
|
|
831
|
-
return new Promise((
|
|
837
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
832
838
|
}
|
|
833
839
|
|
|
834
840
|
// src/commands/profile.ts
|
|
@@ -999,7 +1005,8 @@ function registerZiNiaoCommands(program2) {
|
|
|
999
1005
|
console.log(`ZiNiao profiles (${result.profiles.length}):
|
|
1000
1006
|
`);
|
|
1001
1007
|
for (const p of result.profiles) {
|
|
1002
|
-
|
|
1008
|
+
const site = p.platform_name ? ` [${p.platform_name}]` : "";
|
|
1009
|
+
console.log(` ${p.id} ${p.name}${site}`);
|
|
1003
1010
|
}
|
|
1004
1011
|
console.log("\nUse: browser-cli launch --connector ziniao --ziniao-profile <id> --url <url>");
|
|
1005
1012
|
} catch (err) {
|
|
@@ -1027,14 +1034,32 @@ function registerZiNiaoCommands(program2) {
|
|
|
1027
1034
|
|
|
1028
1035
|
// src/commands/recipes.ts
|
|
1029
1036
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
1037
|
+
import { resolve } from "path";
|
|
1038
|
+
async function runExport(script, params, out, timeoutMs) {
|
|
1039
|
+
const outPath = resolve(out);
|
|
1040
|
+
const result = await api.runRecipeScript(script, { ...params, out_path: outPath }, 2e3, timeoutMs);
|
|
1041
|
+
if (!result.path) {
|
|
1042
|
+
writeFileSync3(outPath, await api.fetchArtifact(result.artifact_path));
|
|
1043
|
+
}
|
|
1044
|
+
console.log(`Saved ${result.filename} -> ${outPath} (${result.size} bytes)`);
|
|
1045
|
+
}
|
|
1030
1046
|
function registerRecipeCommands(program2) {
|
|
1031
|
-
program2.command("export-ad-report").description("Export TikTok Shop last-7-days video ad data into the session workspace").requiredOption("--ziniao-profile <id>", "ZiNiao browser profile ID").option("--out <path>", "Output CSV path", "./tt_video_ad_7d.csv").action(async (opts) => {
|
|
1047
|
+
program2.command("export-ad-report").description("Export TikTok Shop last-7-days video ad data into the session workspace").requiredOption("--ziniao-profile <id>", "ZiNiao browser profile ID").option("--report-url <url>", "Ad dashboard URL (default: TikTok Shop MY local site)").option("--out <path>", "Output CSV path", "./tt_video_ad_7d.csv").action(async (opts) => {
|
|
1032
1048
|
try {
|
|
1033
|
-
const
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
console.
|
|
1049
|
+
const params = { ziniao_profile_id: opts.ziniaoProfile };
|
|
1050
|
+
if (opts.reportUrl) params.report_url = opts.reportUrl;
|
|
1051
|
+
await runExport("tiktok_video_ad_export", params, opts.out, 36e4);
|
|
1052
|
+
} catch (err) {
|
|
1053
|
+
console.error(formatError(err));
|
|
1054
|
+
process.exit(1);
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
program2.command("export-order-report").description("Export TikTok Shop order data into the session workspace").requiredOption("--ziniao-profile <id>", "ZiNiao browser profile ID").option("--report-url <url>", "Order list URL (default: TikTok Shop MY local site)").option("--days <n>", "Export the last N days (default: 7, max 365)").option("--out <path>", "Output CSV path", "./tt_orders.csv").action(async (opts) => {
|
|
1058
|
+
try {
|
|
1059
|
+
const params = { ziniao_profile_id: opts.ziniaoProfile };
|
|
1060
|
+
if (opts.reportUrl) params.report_url = opts.reportUrl;
|
|
1061
|
+
if (opts.days) params.days = opts.days;
|
|
1062
|
+
await runExport("tiktok_order_export", params, opts.out, 54e4);
|
|
1038
1063
|
} catch (err) {
|
|
1039
1064
|
console.error(formatError(err));
|
|
1040
1065
|
process.exit(1);
|