npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

maestrostack

v0.2.0

Published

Config-driven CLI for running Maestro mobile tests on BrowserStack App Automate.

Readme

MaestroStack

MaestroStack is a config-driven CLI for running Maestro mobile tests on BrowserStack App Automate.

It packages Maestro flow folders, uploads app and test artifacts, and starts BrowserStack Maestro builds across one or more real devices from a single command:

maestrostack run

Under the hood BrowserStack's Maestro workflow is several manual REST calls: upload the app, upload a zipped suite, copy the returned URLs, hand-build a JSON payload with the right devices and execute paths, and POST to the correct Android or iOS build endpoint. MaestroStack turns that into one repeatable command you can run locally or in CI.

Install

npm install -g maestrostack

Requires Node.js 18+. Works on macOS, Linux and Windows.

Quick start

The fastest way to see it work is the clone-and-run example. The maestrostack-demo repo ships a config, flows and a sample app, so a dry run needs no credentials:

git clone https://github.com/RohanImmanuel/maestrostack-demo
cd maestrostack-demo
npm install -g maestrostack
maestrostack run --dry-run   # preview the payload, no credentials needed
maestrostack run             # the real build (needs BrowserStack credentials)

Or start from scratch in your own project:

# 1. Scaffold a config
maestrostack init --android

# 2. Provide BrowserStack credentials (see Authentication below)
export BROWSERSTACK_USERNAME=...
export BROWSERSTACK_ACCESS_KEY=...

# 3. Check everything before touching the network
maestrostack validate
maestrostack run --dry-run

# 4. Run on BrowserStack
maestrostack run

Project layout

MaestroStack encourages this structure:

mobile-tests/
├── maestrostack.config.yml   # tool config (NOT a Maestro flow)
├── smoke/
│   ├── login.yml             # Maestro flow
│   └── signup.yml
├── regression/
│   └── checkout.yml
└── apps/
    └── app-release.apk

Keep your config out of the suite, and your flows in subfolders. BrowserStack runs everything in the uploaded zip as your Maestro suite, so the tool config must not be packaged with it. MaestroStack keeps config files out of the package automatically: name yours *.config.yml (for example maestrostack.config.yml) to make its role explicit. Any *.config.yml file and any root-level .yml/.yaml is excluded from the suite, so a plain maestrostack.yml works too.

Configuration

maestrostack init writes a starter maestrostack.config.yml (a plain maestrostack.yml is also recognized). A full example:

version: 1

auth:
  username: ${BROWSERSTACK_USERNAME}
  accessKey: ${BROWSERSTACK_ACCESS_KEY}

platform: android            # android | ios

app:
  source: upload             # upload | app_url
  path: ./apps/app-release.apk
  customId: SampleApp

suite:
  root: .
  packageName: Flows.zip
  customId: SampleTest
  include:
    - smoke/**/*.yml
    - regression/**/*.yml
  exclude:
    - apps/**

run:
  project: Maestro_Test
  devices:
    - Samsung Galaxy S20-10.0
    - Google Pixel 7-13.0
  executeMode: explicit      # explicit | main
  execute:
    - smoke/login.yml
    - smoke/signup.yml
    - regression/checkout.yml
  options:
    networkLogs: true
    deviceLogs: true

App source

| app.source | Required fields | Notes | |---|---|---| | upload | path | Uploads a local .apk (Android) / .ipa (iOS). | | app_url | appUrl | Reuses an existing bs:// app reference. | | custom_id | customId | References the latest app uploaded with that custom id; no upload. |

Execute modes

  • explicit (recommended): list flow files in run.execute. MaestroStack sends them as the BrowserStack execute array - no root main.yaml needed.
  • main: omit run.execute and provide a main.yaml at the suite root. BrowserStack runs it as the entrypoint.

Parallel execution

Set run.maxParallel to cap how many of your listed devices run at once. MaestroStack splits run.devices into sequential batches of at most maxParallel devices, submits one build per batch, and waits for each build to finish before starting the next:

run:
  maxParallel: 2
  devices:
    - Samsung Galaxy S20-10.0
    - Google Pixel 7-13.0
    - iPhone 15-17.0
    - OnePlus 9-11.0

With four devices and maxParallel: 2, that runs two builds of two devices each, one after the other.

  • Every device runs the full suite; nothing is assigned randomly.
  • BrowserStack has no native per-build concurrency cap, so MaestroStack enforces it by submitting batched builds sequentially (polling each build's status until it completes).
  • How many sessions can actually run at once still depends on your BrowserStack plan's parallel limit. maxParallel lets you cap concurrency at or below that; if a batch is bigger than your available parallels, BrowserStack queues the extra sessions until a slot frees up.
  • Because it waits for completion, a batched run is long-running (it blocks until every batch finishes). Without maxParallel, run submits a single build and returns immediately as before.
  • Override per run with --max-parallel <n>.

Authentication

Credentials are read from environment variables referenced as ${VAR} in the config. MaestroStack loads a .env file from the working directory if present:

BROWSERSTACK_USERNAME=my_username
BROWSERSTACK_ACCESS_KEY=my_access_key

If a referenced variable is missing, MaestroStack fails before any upload. Secrets are never printed.

Commands

| Command | Description | |---|---| | maestrostack init | Create a starter config (--android, --ios, --force). | | maestrostack validate | Validate config, suite structure, app and devices. | | maestrostack package | Discover flows and build the suite zip (no upload). | | maestrostack upload-app | Upload only the app; print its app_url. | | maestrostack upload-suite | Package and upload only the suite; print its test_suite_url. | | maestrostack run | Package, upload and trigger a build. |

Global options

  • -c, --config <path> - use a specific config file (e.g. maestrostack.staging.config.yml).
  • --debug - verbose logging.

run options

  • --dry-run - validate, show the files that would be zipped and the exact BrowserStack payload + endpoint, without making any API calls.
  • --device <name> - override run.devices (repeatable).
  • --execute <path> - override run.execute (repeatable; forces explicit mode).
  • --max-parallel <n> - override run.maxParallel (run at most N listed devices at once).
maestrostack run -c maestrostack.android.smoke.yml
maestrostack run --device "Google Pixel 7-13.0" --device "Samsung Galaxy S20-10.0"
maestrostack run --execute smoke/login.yml --dry-run

How it works

maestrostack run:

  1. Loads .env and the config, substitutes ${VAR} tokens, validates everything.
  2. Discovers flow files (ignoring *.config.yml, root-level YAML, node_modules, .git).
  3. Zips the suite under a Flows/ prefix preserving folder structure.
  4. Resolves the app (uploads the local binary or uses an existing bs:// URL).
  5. Uploads the suite zip.
  6. POSTs the build to .../maestro/v2/{android|ios}/build and prints the build id plus its BrowserStack dashboard URL.

Example output:

MaestroStack run started

Project: Maestro_Test
Platform: android
Devices:
- Samsung Galaxy S20-10.0
- Google Pixel 7-13.0

App: bs://...
Test suite: bs://...
Build ID: 5c5ab4338cec13aeb78f7a6977344556ac00bccd6
Build URL: https://app-automate.browserstack.com/dashboard/v2/builds/5c5ab4338cec13aeb78f7a6977344556ac00bccd6

Development

npm install
npm run build       # bundle with tsup -> dist/cli.js
npm run typecheck   # tsc --noEmit
npm test            # vitest

The BrowserStack integration is covered by tests with mocked HTTP, so the full package to payload path runs without a live account.

Acknowledgements

This project is tested with BrowserStack.

License

MIT