Skip to content

Commit ff11e62

Browse files
Merge pull request #1 from ruturaj-browserstack/main
Sync with Develop
2 parents f09d9e7 + 0a432b3 commit ff11e62

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+808
-261
lines changed

.github/workflows/mcp-ci.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ on:
44
pull_request_review:
55
types: [submitted]
66

7-
87
jobs:
98
test:
109
if: github.event.pull_request.base.ref == 'main' && github.event.review.state == 'approved'

jest.config.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/index.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,18 @@
22

33
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
44
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5-
import packageJson from "../package.json";
5+
import packageJson from "../package.json" with { type: "json" };
66
import "dotenv/config";
7-
import logger from "./logger";
8-
import addSDKTools from "./tools/bstack-sdk";
9-
import addAppLiveTools from "./tools/applive";
10-
import addObservabilityTools from "./tools/observability";
11-
import addBrowserLiveTools from "./tools/live";
12-
import addAccessibilityTools from "./tools/accessibility";
13-
import addAutomateTools from "./tools/automate";
14-
import addTestManagementTools from "./tools/testmanagement";
15-
import { trackMCP } from "./lib/instrumentation";
7+
import logger from "./logger.js";
8+
import addSDKTools from "./tools/bstack-sdk.js";
9+
import addAppLiveTools from "./tools/applive.js";
10+
import addObservabilityTools from "./tools/observability.js";
11+
import addBrowserLiveTools from "./tools/live.js";
12+
import addAccessibilityTools from "./tools/accessibility.js";
13+
import addAutomateTools from "./tools/automate.js";
14+
import addTestManagementTools from "./tools/testmanagement.js";
15+
import addAppAutomationTools from "./tools/appautomate.js";
16+
import { trackMCP } from "./lib/instrumentation.js";
1617

1718
function registerTools(server: McpServer) {
1819
addSDKTools(server);
@@ -22,6 +23,7 @@ function registerTools(server: McpServer) {
2223
addAccessibilityTools(server);
2324
addAutomateTools(server);
2425
addTestManagementTools(server);
26+
addAppAutomationTools(server);
2527
}
2628

2729
// Create an MCP server

src/lib/api.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import config from "../config";
2-
import { HarEntry, HarFile } from "./utils";
1+
import config from "../config.js";
2+
import { HarEntry, HarFile } from "./utils.js";
33

44
export async function getLatestO11YBuildInfo(
55
buildName: string,

src/lib/device-cache.ts

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,26 @@ const CACHE_DIR = path.join(os.homedir(), ".browserstack", "combined_cache");
66
const CACHE_FILE = path.join(CACHE_DIR, "data.json");
77
const TTL_MS = 24 * 60 * 60 * 1000; // 1 day
88

9-
const URLS = {
10-
live: "https://www.browserstack.com/list-of-browsers-and-platforms/live.json",
11-
app_live:
9+
export enum BrowserStackProducts {
10+
LIVE = "live",
11+
APP_LIVE = "app_live",
12+
APP_AUTOMATE = "app_automate",
13+
}
14+
15+
const URLS: Record<BrowserStackProducts, string> = {
16+
[BrowserStackProducts.LIVE]:
17+
"https://www.browserstack.com/list-of-browsers-and-platforms/live.json",
18+
[BrowserStackProducts.APP_LIVE]:
1219
"https://www.browserstack.com/list-of-browsers-and-platforms/app_live.json",
20+
[BrowserStackProducts.APP_AUTOMATE]:
21+
"https://www.browserstack.com/list-of-browsers-and-platforms/app_automate.json",
1322
};
1423

1524
/**
16-
* Fetches and caches both BrowserStack datasets (live + app_live) with a shared TTL.
25+
* Fetches and caches BrowserStack datasets (live + app_live + app_automate) with a shared TTL.
1726
*/
1827
export async function getDevicesAndBrowsers(
19-
type: "live" | "app_live",
28+
type: BrowserStackProducts,
2029
): Promise<any> {
2130
if (!fs.existsSync(CACHE_DIR)) {
2231
fs.mkdirSync(CACHE_DIR, { recursive: true });
@@ -29,31 +38,29 @@ export async function getDevicesAndBrowsers(
2938
if (Date.now() - stats.mtimeMs < TTL_MS) {
3039
try {
3140
cache = JSON.parse(fs.readFileSync(CACHE_FILE, "utf8"));
32-
return cache[type];
41+
if (cache[type]) {
42+
return cache[type];
43+
}
3344
} catch (error) {
3445
console.error("Error parsing cache file:", error);
3546
// Continue with fetching fresh data
3647
}
3748
}
3849
}
3950

40-
const [liveRes, appLiveRes] = await Promise.all([
41-
fetch(URLS.live),
42-
fetch(URLS.app_live),
43-
]);
51+
const liveRes = await fetch(URLS[type]);
4452

45-
if (!liveRes.ok || !appLiveRes.ok) {
53+
if (!liveRes.ok) {
4654
throw new Error(
47-
`Failed to fetch configuration from BrowserStack : live=${liveRes.statusText}, app_live=${appLiveRes.statusText}`,
55+
`Failed to fetch configuration from BrowserStack : ${type}=${liveRes.statusText}`,
4856
);
4957
}
5058

51-
const [liveData, appLiveData] = await Promise.all([
52-
liveRes.json(),
53-
appLiveRes.json(),
54-
]);
59+
const data = await liveRes.json();
5560

56-
cache = { live: liveData, app_live: appLiveData };
61+
cache = {
62+
[type]: data,
63+
};
5764
fs.writeFileSync(CACHE_FILE, JSON.stringify(cache), "utf8");
5865

5966
return cache[type];

src/lib/instrumentation.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import logger from "../logger";
2-
import config from "../config";
3-
import packageJson from "../../package.json";
1+
import logger from "../logger.js";
2+
import config from "../config.js";
3+
import packageJson from "../../package.json" with { type: "json" };
44
import axios from "axios";
55

66
interface MCPEventPayload {

src/lib/local.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import logger from "../logger";
1+
import logger from "../logger.js";
22
import { execSync } from "child_process";
33
import { Local } from "browserstack-local";
4-
import config from "../config";
4+
import config from "../config.js";
55

66
async function isBrowserStackLocalRunning() {
77
// Check if BrowserStackLocal binary is already running

src/lib/utils.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import sharp from "sharp";
2+
13
export function sanitizeUrlParam(param: string): string {
24
// Remove any characters that could be used for command injection
35
return param.replace(/[;&|`$(){}[\]<>]/g, "");
@@ -24,3 +26,22 @@ export interface HarEntry {
2426
serverIPAddress?: string;
2527
time?: number;
2628
}
29+
30+
/**
31+
* Compresses a base64 image intelligently to keep it under 1 MB if needed.
32+
*/
33+
export async function maybeCompressBase64(base64: string): Promise<string> {
34+
const buffer = Buffer.from(base64, "base64");
35+
36+
if (buffer.length <= 1048576) {
37+
return base64;
38+
}
39+
40+
const sizeRatio = 1048576 / buffer.length;
41+
const estimatedQuality = Math.floor(sizeRatio * 100);
42+
const quality = Math.min(95, Math.max(30, estimatedQuality));
43+
44+
const compressedBuffer = await sharp(buffer).png({ quality }).toBuffer();
45+
46+
return compressedBuffer.toString("base64");
47+
}

src/logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import pino from "pino";
1+
import { pino } from "pino";
22

33
let logger: pino.Logger;
44

src/tools/accessibility.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
44
import {
55
startAccessibilityScan,
66
AccessibilityScanResponse,
7-
} from "./accessiblity-utils/accessibility";
8-
import { trackMCP } from "../lib/instrumentation";
7+
} from "./accessiblity-utils/accessibility.js";
8+
import { trackMCP } from "../lib/instrumentation.js";
99

1010
async function runAccessibilityScan(
1111
name: string,

0 commit comments

Comments
 (0)