browsermation 0.0.89 → 0.0.91

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 (2) hide show
  1. package/dist/bin/cli.js +229 -16
  2. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -18419,8 +18419,8 @@ var require_graceful_fs = __commonJS({
18419
18419
  fs2.createReadStream = createReadStream;
18420
18420
  fs2.createWriteStream = createWriteStream3;
18421
18421
  var fs$readFile = fs2.readFile;
18422
- fs2.readFile = readFile;
18423
- function readFile(path2, options, cb) {
18422
+ fs2.readFile = readFile2;
18423
+ function readFile2(path2, options, cb) {
18424
18424
  if (typeof options === "function")
18425
18425
  cb = options, options = null;
18426
18426
  return go$readFile(path2, options, cb);
@@ -18436,8 +18436,8 @@ var require_graceful_fs = __commonJS({
18436
18436
  }
18437
18437
  }
18438
18438
  var fs$writeFile = fs2.writeFile;
18439
- fs2.writeFile = writeFile2;
18440
- function writeFile2(path2, data, options, cb) {
18439
+ fs2.writeFile = writeFile3;
18440
+ function writeFile3(path2, data, options, cb) {
18441
18441
  if (typeof options === "function")
18442
18442
  cb = options, options = null;
18443
18443
  return go$writeFile(path2, data, options, cb);
@@ -18998,7 +18998,7 @@ var require_BufferList = __commonJS({
18998
18998
  this.head = this.tail = null;
18999
18999
  this.length = 0;
19000
19000
  };
19001
- BufferList.prototype.join = function join3(s) {
19001
+ BufferList.prototype.join = function join4(s) {
19002
19002
  if (this.length === 0) return "";
19003
19003
  var p = this.head;
19004
19004
  var ret = "" + p.data;
@@ -40603,7 +40603,7 @@ var {
40603
40603
  // package.json
40604
40604
  var package_default = {
40605
40605
  name: "browsermation",
40606
- version: "0.0.89",
40606
+ version: "0.0.91",
40607
40607
  description: "The testing platform for Playwright by Browsermation.",
40608
40608
  main: "./dist/index.js",
40609
40609
  types: "./dist/index.d.ts",
@@ -46895,8 +46895,126 @@ async function zipFolderToBuffer(folder, testFiles) {
46895
46895
  }
46896
46896
 
46897
46897
  // src/core.ts
46898
+ var import_promises2 = require("node:fs/promises");
46899
+ var import_node_fs2 = require("node:fs");
46900
+
46901
+ // src/auth.ts
46902
+ var import_node_os2 = require("node:os");
46903
+ var import_node_path = require("node:path");
46898
46904
  var import_promises = require("node:fs/promises");
46899
46905
  var import_node_fs = require("node:fs");
46906
+ var API_BASE = "https://browsermation.com";
46907
+ var CREDENTIALS_DIR = (0, import_node_path.join)((0, import_node_os2.homedir)(), ".browsermation");
46908
+ var CREDENTIALS_FILE = (0, import_node_path.join)(CREDENTIALS_DIR, "credentials");
46909
+ async function requestDeviceCode() {
46910
+ const response = await axios_default.post(
46911
+ `${API_BASE}/api/device/code`,
46912
+ {},
46913
+ {
46914
+ headers: {
46915
+ "Content-Type": "application/json",
46916
+ Accept: "application/json"
46917
+ }
46918
+ }
46919
+ );
46920
+ return response.data;
46921
+ }
46922
+ async function pollForToken(deviceCode, interval, expiresIn) {
46923
+ const startTime = Date.now();
46924
+ const expiresAt = startTime + expiresIn * 1e3;
46925
+ while (Date.now() < expiresAt) {
46926
+ await sleep(interval * 1e3);
46927
+ try {
46928
+ const response = await axios_default.post(
46929
+ `${API_BASE}/api/device/token`,
46930
+ { device_code: deviceCode },
46931
+ {
46932
+ headers: {
46933
+ "Content-Type": "application/json",
46934
+ Accept: "application/json"
46935
+ }
46936
+ }
46937
+ );
46938
+ if (response.data.access_token) {
46939
+ return {
46940
+ token: response.data.access_token,
46941
+ user: response.data.user
46942
+ };
46943
+ }
46944
+ if (response.data.error === "authorization_pending") {
46945
+ continue;
46946
+ }
46947
+ if (response.data.error === "expired_token") {
46948
+ throw new Error("Authentication request expired. Please try again.");
46949
+ }
46950
+ if (response.data.error) {
46951
+ throw new Error(`Authentication failed: ${response.data.error}`);
46952
+ }
46953
+ } catch (error2) {
46954
+ if (axios_default.isAxiosError(error2)) {
46955
+ const data = error2.response?.data;
46956
+ if (data?.error === "authorization_pending") {
46957
+ continue;
46958
+ }
46959
+ if (data?.error === "expired_token") {
46960
+ throw new Error("Authentication request expired. Please try again.");
46961
+ }
46962
+ if (error2.response?.status === 400 && data?.error) {
46963
+ throw new Error(`Authentication failed: ${data.error}`);
46964
+ }
46965
+ }
46966
+ throw error2;
46967
+ }
46968
+ }
46969
+ throw new Error("Authentication timed out. Please try again.");
46970
+ }
46971
+ async function saveCredentials(credentials) {
46972
+ if (!(0, import_node_fs.existsSync)(CREDENTIALS_DIR)) {
46973
+ await (0, import_promises.mkdir)(CREDENTIALS_DIR, { recursive: true, mode: 448 });
46974
+ }
46975
+ await (0, import_promises.writeFile)(CREDENTIALS_FILE, JSON.stringify(credentials, null, 2), {
46976
+ mode: 384
46977
+ });
46978
+ }
46979
+ async function loadCredentials() {
46980
+ if (!(0, import_node_fs.existsSync)(CREDENTIALS_FILE)) {
46981
+ return null;
46982
+ }
46983
+ try {
46984
+ const content = await (0, import_promises.readFile)(CREDENTIALS_FILE, "utf-8");
46985
+ return JSON.parse(content);
46986
+ } catch {
46987
+ return null;
46988
+ }
46989
+ }
46990
+ async function clearCredentials() {
46991
+ if ((0, import_node_fs.existsSync)(CREDENTIALS_FILE)) {
46992
+ await (0, import_promises.unlink)(CREDENTIALS_FILE);
46993
+ }
46994
+ }
46995
+ function getToken() {
46996
+ if (process.env.BM_API_TOKEN) {
46997
+ return process.env.BM_API_TOKEN;
46998
+ }
46999
+ if (!(0, import_node_fs.existsSync)(CREDENTIALS_FILE)) {
47000
+ return null;
47001
+ }
47002
+ try {
47003
+ const content = require("fs").readFileSync(CREDENTIALS_FILE, "utf-8");
47004
+ const credentials = JSON.parse(content);
47005
+ return credentials.token || null;
47006
+ } catch {
47007
+ return null;
47008
+ }
47009
+ }
47010
+ function getCredentialsPath() {
47011
+ return CREDENTIALS_FILE;
47012
+ }
47013
+ function sleep(ms) {
47014
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
47015
+ }
47016
+
47017
+ // src/core.ts
46900
47018
  async function uploadZip(zipBuffer, shardNumber, totalShards, playwrightConfig, options = {}, eventStream) {
46901
47019
  if (!process.env.API_URL) {
46902
47020
  console.error(source_default.red("Error: API_URL environment variable is not set."));
@@ -46912,9 +47030,18 @@ async function uploadZip(zipBuffer, shardNumber, totalShards, playwrightConfig,
46912
47030
  if (options?.project) {
46913
47031
  formData.append("project", options.project);
46914
47032
  }
47033
+ const token = getToken();
47034
+ if (!token) {
47035
+ console.error(
47036
+ source_default.red(
47037
+ "Error: Not authenticated. Run 'browsermation login' or set BM_API_TOKEN environment variable."
47038
+ )
47039
+ );
47040
+ process.exit(1);
47041
+ }
46915
47042
  const headers = {
46916
47043
  "Content-Type": "multipart/form-data",
46917
- Authorization: `Bearer ${process.env.BM_API_TOKEN}`
47044
+ Authorization: `Bearer ${token}`
46918
47045
  };
46919
47046
  const response = await axios_default.post(process.env.API_URL, formData, {
46920
47047
  responseType: "stream",
@@ -46939,7 +47066,7 @@ async function uploadZip(zipBuffer, shardNumber, totalShards, playwrightConfig,
46939
47066
  async function zip(folder, testFiles) {
46940
47067
  console.log("zipping", folder);
46941
47068
  const sourceDir = path.resolve(folder);
46942
- if (!(0, import_node_fs.existsSync)(sourceDir)) {
47069
+ if (!(0, import_node_fs2.existsSync)(sourceDir)) {
46943
47070
  console.error(
46944
47071
  source_default.red(`Error: The directory "${sourceDir}" does not exist.`)
46945
47072
  );
@@ -46961,7 +47088,7 @@ async function zip(folder, testFiles) {
46961
47088
  }
46962
47089
  zipSpinner.stop();
46963
47090
  const tmpZipPath = path.join("/tmp", `project-${Date.now()}.zip`);
46964
- await (0, import_promises.writeFile)(tmpZipPath, zipBuffer);
47091
+ await (0, import_promises2.writeFile)(tmpZipPath, zipBuffer);
46965
47092
  console.log(`Zipped project folder to ${tmpZipPath}`);
46966
47093
  return zipBuffer;
46967
47094
  }
@@ -47006,10 +47133,11 @@ async function upload(zipBuffer, shardNumber, totalShards, playwrightConfig, opt
47006
47133
  // src/tunnel.ts
47007
47134
  var import_node_child_process = require("node:child_process");
47008
47135
  function startTunnel(tunnelProcess, options) {
47009
- if (!process.env.BM_API_TOKEN) {
47136
+ const token = getToken();
47137
+ if (!token) {
47010
47138
  console.error(
47011
47139
  source_default.red.bold(
47012
- "\u274C Error: BM_API_TOKEN environment variable is not set. Please set it to your tunnel token."
47140
+ "\u274C Error: Not authenticated. Run 'browsermation login' or set BM_API_TOKEN environment variable."
47013
47141
  )
47014
47142
  );
47015
47143
  process.exit(1);
@@ -47035,7 +47163,7 @@ function startTunnel(tunnelProcess, options) {
47035
47163
  "2200",
47036
47164
  "http",
47037
47165
  "--user",
47038
- process.env.BM_API_TOKEN || ""
47166
+ token
47039
47167
  ];
47040
47168
  if (options.host) {
47041
47169
  args.push("--host-header-rewrite", options.host);
@@ -47084,10 +47212,10 @@ function startTunnel(tunnelProcess, options) {
47084
47212
  var import_node_stream = __toESM(require("node:stream"));
47085
47213
 
47086
47214
  // src/http.ts
47087
- var import_node_fs2 = require("node:fs");
47088
- var import_promises2 = require("node:fs/promises");
47215
+ var import_node_fs3 = require("node:fs");
47216
+ var import_promises3 = require("node:fs/promises");
47089
47217
  async function downloadFile(fileUrl, outputLocationPath) {
47090
- const writer = (0, import_node_fs2.createWriteStream)(outputLocationPath);
47218
+ const writer = (0, import_node_fs3.createWriteStream)(outputLocationPath);
47091
47219
  console.log(`Downloading file from ${fileUrl}...`);
47092
47220
  try {
47093
47221
  const response = await axios_default({
@@ -47104,7 +47232,7 @@ async function downloadFile(fileUrl, outputLocationPath) {
47104
47232
  });
47105
47233
  writer.on("error", async (err) => {
47106
47234
  console.error("Error writing file to disk:", err);
47107
- await (0, import_promises2.unlink)(outputLocationPath);
47235
+ await (0, import_promises3.unlink)(outputLocationPath);
47108
47236
  });
47109
47237
  });
47110
47238
  } catch (err) {
@@ -47209,6 +47337,91 @@ program2.command("test").option("-t, --tunnel <port>").option("-p, --proxy").opt
47209
47337
  process.exit(1);
47210
47338
  }
47211
47339
  });
47340
+ program2.command("login").description("Authenticate with BrowserMation").action(async () => {
47341
+ try {
47342
+ const existingCreds = await loadCredentials();
47343
+ if (existingCreds?.user) {
47344
+ console.log(
47345
+ source_default.yellow(
47346
+ `Already logged in as ${existingCreds.user.email}. Run 'browsermation logout' first to switch accounts.`
47347
+ )
47348
+ );
47349
+ return;
47350
+ }
47351
+ const spinner = ora("Requesting authentication code...").start();
47352
+ const deviceCode = await requestDeviceCode();
47353
+ spinner.stop();
47354
+ console.log("\nTo authenticate, visit:");
47355
+ console.log(source_default.cyan.bold(` ${deviceCode.verification_uri}`));
47356
+ console.log("\nAnd enter code:");
47357
+ console.log(source_default.green.bold(` ${deviceCode.user_code}`));
47358
+ console.log("");
47359
+ const pollSpinner = ora("Waiting for authentication...").start();
47360
+ const credentials = await pollForToken(
47361
+ deviceCode.device_code,
47362
+ deviceCode.interval,
47363
+ deviceCode.expires_in
47364
+ );
47365
+ await saveCredentials(credentials);
47366
+ pollSpinner.succeed(source_default.green("Authentication successful!"));
47367
+ if (credentials.user) {
47368
+ console.log(source_default.green(`Logged in as ${credentials.user.email}`));
47369
+ }
47370
+ console.log(
47371
+ source_default.dim(`Token saved to ${getCredentialsPath()}`)
47372
+ );
47373
+ } catch (error2) {
47374
+ if (error2 instanceof Error) {
47375
+ console.error(source_default.red(`Login failed: ${error2.message}`));
47376
+ } else {
47377
+ console.error(source_default.red("Login failed: An unknown error occurred"));
47378
+ }
47379
+ process.exit(1);
47380
+ }
47381
+ });
47382
+ program2.command("logout").description("Remove stored credentials").action(async () => {
47383
+ try {
47384
+ const creds = await loadCredentials();
47385
+ if (!creds) {
47386
+ console.log(source_default.yellow("Not currently logged in."));
47387
+ return;
47388
+ }
47389
+ await clearCredentials();
47390
+ console.log(source_default.green("Logged out successfully."));
47391
+ } catch (error2) {
47392
+ if (error2 instanceof Error) {
47393
+ console.error(source_default.red(`Logout failed: ${error2.message}`));
47394
+ } else {
47395
+ console.error(source_default.red("Logout failed: An unknown error occurred"));
47396
+ }
47397
+ process.exit(1);
47398
+ }
47399
+ });
47400
+ program2.command("whoami").description("Display current authenticated user").action(async () => {
47401
+ try {
47402
+ const creds = await loadCredentials();
47403
+ if (creds?.user) {
47404
+ console.log(`Logged in as: ${source_default.green(creds.user.email)}`);
47405
+ if (creds.user.name) {
47406
+ console.log(`Name: ${creds.user.name}`);
47407
+ }
47408
+ } else if (creds?.token) {
47409
+ console.log(source_default.yellow("Logged in (user info not available)"));
47410
+ } else if (process.env.BM_API_TOKEN) {
47411
+ console.log(source_default.yellow("Using BM_API_TOKEN environment variable"));
47412
+ } else {
47413
+ console.log(source_default.red("Not logged in."));
47414
+ console.log(
47415
+ source_default.dim("Run 'browsermation login' to authenticate.")
47416
+ );
47417
+ }
47418
+ } catch (error2) {
47419
+ if (error2 instanceof Error) {
47420
+ console.error(source_default.red(`Error: ${error2.message}`));
47421
+ }
47422
+ process.exit(1);
47423
+ }
47424
+ });
47212
47425
  program2.parse(process.argv);
47213
47426
  /*! Bundled license information:
47214
47427
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "browsermation",
3
- "version": "0.0.89",
3
+ "version": "0.0.91",
4
4
  "description": "The testing platform for Playwright by Browsermation.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",