@oya-ai/cli 1.0.107 → 1.0.110

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.
Files changed (3) hide show
  1. package/README.md +18 -0
  2. package/dist/index.js +69 -1
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -102,6 +102,24 @@ oya personas edit <id> --max 4 --geo US
102
102
  oya personas rm <id>
103
103
  ```
104
104
 
105
+ ### Moving logins (`oya cookies`)
106
+
107
+ A persona's cookie jar is its logins. Sign in once, then carry the session to wherever it is needed:
108
+
109
+ ```bash
110
+ # Save a persona's logins to a file (owner-readable only: it holds live sessions)
111
+ oya cookies export <persona> --out logins.json
112
+
113
+ # The same, shaped for Playwright's context.addCookies()
114
+ oya cookies export <persona> --format playwright --out pw-cookies.json
115
+
116
+ # Bring logins in from a file: an export, or any JSON list of cookies
117
+ oya cookies import <persona> logins.json
118
+
119
+ # Give one persona another persona's logins (each keeps its own device)
120
+ oya cookies copy <from-persona> <to-persona>
121
+ ```
122
+
105
123
  ### Human-in-the-Loop Takeover
106
124
 
107
125
  When automation encounters hardware 2FA, phone biometric approvals, or complex verification:
package/dist/index.js CHANGED
@@ -1270,6 +1270,7 @@ var ARGV_SKIP = 2;
1270
1270
  var JSON_INDENT2 = 2;
1271
1271
  var DEFAULT_BASE_URL = "https://oyabrowser.com";
1272
1272
  var CONFIG_FILE_MODE = 384;
1273
+ var PRIVATE_FILE_MODE = 384;
1273
1274
  var LsColumns = {
1274
1275
  /** Provider name. */
1275
1276
  PROVIDER: 14,
@@ -2009,11 +2010,28 @@ var loginCalls = (http) => ({
2009
2010
  await http().request("DELETE", `/api/personas/${id}/credentials?domain=${encodeURIComponent(domain)}`);
2010
2011
  }
2011
2012
  });
2013
+ var jarPath = (id) => `/api/pool/cookies?persona=${encodeURIComponent(id)}`;
2014
+ var jarCalls = (http) => ({
2015
+ /** Every cookie in the jar; `format: 'playwright'` is ready for `context.addCookies()`. */
2016
+ cookies: async (id, format = "json") => (await http().request("GET", `${jarPath(id)}&format=${format}`)).cookies,
2017
+ /** Merge cookies into the jar. The persona's browsers pick them up on their next visit to each site. */
2018
+ importCookies: (id, list2) => http().request("PUT", jarPath(id), { cookies: list2 })
2019
+ });
2020
+ var cookieCalls = (http) => ({
2021
+ ...jarCalls(http),
2022
+ /** Copy every login of persona `from` into persona `to`, which keeps its own device. */
2023
+ copyCookies: async (from, to) => jarCalls(http).importCookies(to, await jarCalls(http).cookies(from)),
2024
+ /** Forget every cookie in the jar: signs the persona out everywhere. */
2025
+ clearCookies: async (id) => {
2026
+ await http().request("DELETE", jarPath(id));
2027
+ }
2028
+ });
2012
2029
  var personaApi = (http) => ({
2013
2030
  ...identityCalls(http),
2014
2031
  ...deviceCalls(http),
2015
2032
  ...mfaCalls(http),
2016
- ...loginCalls(http)
2033
+ ...loginCalls(http),
2034
+ ...cookieCalls(http)
2017
2035
  });
2018
2036
  var configApi = (http) => ({
2019
2037
  /** This key's settings. Secrets read back masked. */
@@ -2389,6 +2407,52 @@ async function cmdPersonas(args2, flags2) {
2389
2407
  await run2(oya, rest, flags2);
2390
2408
  }
2391
2409
 
2410
+ // src/commands/cookies.ts
2411
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync5 } from "fs";
2412
+ var USAGE = `Usage: oya cookies export <persona> [--format json|playwright] [--out <file>]
2413
+ oya cookies import <persona> <file.json>
2414
+ oya cookies copy <from-persona> <to-persona>
2415
+ oya cookies clear <persona>`;
2416
+ var exportJar = async (oya, rest, flags2) => {
2417
+ if (!rest[0]) throw new Error("Usage: oya cookies export <persona> [--format json|playwright] [--out <file>]");
2418
+ const cookies = await oya.personas.cookies(rest[0], flagStr(flags2, "format") || "json");
2419
+ const file = flagStr(flags2, "out");
2420
+ if (!file) return console.log(JSON.stringify(cookies, null, JSON_INDENT2));
2421
+ writeFileSync5(file, JSON.stringify(cookies, null, JSON_INDENT2) + "\n", { mode: PRIVATE_FILE_MODE });
2422
+ console.log(`\u2705 ${cookies.length} cookie${cookies.length === 1 ? "" : "s"} written to ${file}`);
2423
+ };
2424
+ function cookiesIn(file) {
2425
+ const parsed = JSON.parse(readFileSync4(file, "utf8"));
2426
+ const list2 = Array.isArray(parsed) ? parsed : parsed?.cookies;
2427
+ if (!Array.isArray(list2)) throw new Error(`${file} holds no list of cookies`);
2428
+ return list2;
2429
+ }
2430
+ var importJar = async (oya, rest, flags2) => {
2431
+ if (!rest[0] || !rest[1]) throw new Error("Usage: oya cookies import <persona> <file.json>");
2432
+ const done = await oya.personas.importCookies(rest[0], cookiesIn(rest[1]));
2433
+ out(
2434
+ flags2,
2435
+ done,
2436
+ () => console.log(`\u2705 ${done.imported} imported, ${done.skipped} skipped, ${done.total} in the jar`)
2437
+ );
2438
+ };
2439
+ var copy = async (oya, rest, flags2) => {
2440
+ if (!rest[0] || !rest[1]) throw new Error("Usage: oya cookies copy <from-persona> <to-persona>");
2441
+ const done = await oya.personas.copyCookies(rest[0], rest[1]);
2442
+ out(flags2, done, () => console.log(`\u2705 ${done.imported} copied to ${rest[1]}, ${done.total} in its jar`));
2443
+ };
2444
+ var clear = async (oya, rest) => {
2445
+ if (!rest[0]) throw new Error("Usage: oya cookies clear <persona>");
2446
+ await oya.personas.clearCookies(rest[0]);
2447
+ console.log(`\u2705 cleared ${rest[0]}`);
2448
+ };
2449
+ var SUBCOMMANDS2 = { export: exportJar, import: importJar, copy, clear };
2450
+ async function cmdCookies(args2, flags2) {
2451
+ const [sub, ...rest] = args2;
2452
+ if (sub === void 0 || !Object.hasOwn(SUBCOMMANDS2, sub)) throw new Error(USAGE);
2453
+ await SUBCOMMANDS2[sub](client(flags2), rest, flags2);
2454
+ }
2455
+
2392
2456
  // src/commands/settings.ts
2393
2457
  function parsePairs(args2) {
2394
2458
  const updates = {};
@@ -2511,6 +2575,9 @@ var HELP = `oya, thousands of browsers, one API
2511
2575
  oya personas new [name] --platform Win32|MacIntel|Linux --tz <zone> --locale <l> --max <n>
2512
2576
  oya personas edit <id> --name <n> --max <n> --geo <cc>
2513
2577
  oya personas clone|rm <id> A new device of the same kind \xB7 delete
2578
+ oya cookies export <persona> Logins to stdout or --out <file>; --format playwright for addCookies()
2579
+ oya cookies import <persona> <file> Logins from a JSON file
2580
+ oya cookies copy <from> <to> One persona's logins into another
2514
2581
  oya status [--id <id>] Health, counters and what it has been doing
2515
2582
  oya open [--id <id>] Open the live view in your browser
2516
2583
  oya config [key=value ...] Show or change this key's settings
@@ -2554,6 +2621,7 @@ var COMMANDS2 = {
2554
2621
  rm: cmdRm,
2555
2622
  stop: cmdRm,
2556
2623
  personas: cmdPersonas,
2624
+ cookies: cmdCookies,
2557
2625
  open: (_args, flags2) => cmdOpen(flags2),
2558
2626
  config: cmdConfig,
2559
2627
  usage: (_args, flags2) => cmdUsage(flags2),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oya-ai/cli",
3
- "version": "1.0.107",
3
+ "version": "1.0.110",
4
4
  "description": "Command line for the Oya browser control plane.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://oyabrowser.com",
@@ -39,7 +39,7 @@
39
39
  "access": "public"
40
40
  },
41
41
  "devDependencies": {
42
- "@oya-ai/browser": "1.0.107",
42
+ "@oya-ai/browser": "1.0.110",
43
43
  "@types/node": "^20.19.43",
44
44
  "tsup": "^8.0.0",
45
45
  "typescript": "^5.4.0"