@seleniumbox/sbox-mcp 0.2.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.
Files changed (141) hide show
  1. package/PUBLISHING.md +115 -0
  2. package/README.md +134 -0
  3. package/dist/adapters/auth.adapter.d.ts +46 -0
  4. package/dist/adapters/auth.adapter.js +54 -0
  5. package/dist/adapters/browser.adapter.d.ts +43 -0
  6. package/dist/adapters/browser.adapter.js +39 -0
  7. package/dist/adapters/device.adapter.d.ts +60 -0
  8. package/dist/adapters/device.adapter.js +40 -0
  9. package/dist/adapters/diagnostics.adapter.d.ts +73 -0
  10. package/dist/adapters/diagnostics.adapter.js +89 -0
  11. package/dist/adapters/index.d.ts +16 -0
  12. package/dist/adapters/index.js +20 -0
  13. package/dist/adapters/project.adapter.d.ts +38 -0
  14. package/dist/adapters/project.adapter.js +39 -0
  15. package/dist/adapters/sbox-api.client.d.ts +31 -0
  16. package/dist/adapters/sbox-api.client.js +104 -0
  17. package/dist/adapters/session.adapter.d.ts +77 -0
  18. package/dist/adapters/session.adapter.js +95 -0
  19. package/dist/adapters/stats.adapter.d.ts +72 -0
  20. package/dist/adapters/stats.adapter.js +108 -0
  21. package/dist/adapters/upload.adapter.d.ts +16 -0
  22. package/dist/adapters/upload.adapter.js +25 -0
  23. package/dist/adapters/user.adapter.d.ts +24 -0
  24. package/dist/adapters/user.adapter.js +25 -0
  25. package/dist/app.d.ts +2 -0
  26. package/dist/app.js +16 -0
  27. package/dist/config/env.d.ts +21 -0
  28. package/dist/config/env.js +55 -0
  29. package/dist/config/index.d.ts +1 -0
  30. package/dist/config/index.js +8 -0
  31. package/dist/controllers/analytics.controller.d.ts +10 -0
  32. package/dist/controllers/analytics.controller.js +127 -0
  33. package/dist/controllers/auth-device.controller.d.ts +7 -0
  34. package/dist/controllers/auth-device.controller.js +60 -0
  35. package/dist/controllers/auth.controller.d.ts +5 -0
  36. package/dist/controllers/auth.controller.js +20 -0
  37. package/dist/controllers/browser.controller.d.ts +5 -0
  38. package/dist/controllers/browser.controller.js +23 -0
  39. package/dist/controllers/device.controller.d.ts +5 -0
  40. package/dist/controllers/device.controller.js +23 -0
  41. package/dist/controllers/index.d.ts +6 -0
  42. package/dist/controllers/index.js +28 -0
  43. package/dist/controllers/project-stats.controller.d.ts +5 -0
  44. package/dist/controllers/project-stats.controller.js +29 -0
  45. package/dist/controllers/session.controller.d.ts +9 -0
  46. package/dist/controllers/session.controller.js +120 -0
  47. package/dist/controllers/upload.controller.d.ts +5 -0
  48. package/dist/controllers/upload.controller.js +44 -0
  49. package/dist/controllers/user.controller.d.ts +5 -0
  50. package/dist/controllers/user.controller.js +29 -0
  51. package/dist/device-flow.store.d.ts +7 -0
  52. package/dist/device-flow.store.js +23 -0
  53. package/dist/dto/auth.dto.d.ts +26 -0
  54. package/dist/dto/auth.dto.js +9 -0
  55. package/dist/dto/browser.dto.d.ts +13 -0
  56. package/dist/dto/browser.dto.js +2 -0
  57. package/dist/dto/device.dto.d.ts +15 -0
  58. package/dist/dto/device.dto.js +2 -0
  59. package/dist/dto/index.d.ts +6 -0
  60. package/dist/dto/index.js +22 -0
  61. package/dist/dto/project-stats.dto.d.ts +8 -0
  62. package/dist/dto/project-stats.dto.js +2 -0
  63. package/dist/dto/session.dto.d.ts +50 -0
  64. package/dist/dto/session.dto.js +9 -0
  65. package/dist/dto/user.dto.d.ts +6 -0
  66. package/dist/dto/user.dto.js +2 -0
  67. package/dist/index.d.ts +6 -0
  68. package/dist/index.js +34 -0
  69. package/dist/mcp/tools/auth-tools.d.ts +5 -0
  70. package/dist/mcp/tools/auth-tools.js +132 -0
  71. package/dist/mcp/tools/helpers.d.ts +26 -0
  72. package/dist/mcp/tools/helpers.js +53 -0
  73. package/dist/mcp/tools/index.d.ts +5 -0
  74. package/dist/mcp/tools/index.js +12 -0
  75. package/dist/mcp/tools/rest-tools.d.ts +5 -0
  76. package/dist/mcp/tools/rest-tools.js +540 -0
  77. package/dist/mcp-server.d.ts +6 -0
  78. package/dist/mcp-server.js +28 -0
  79. package/dist/middleware/auth.middleware.d.ts +10 -0
  80. package/dist/middleware/auth.middleware.js +23 -0
  81. package/dist/middleware/debug-log.middleware.d.ts +6 -0
  82. package/dist/middleware/debug-log.middleware.js +84 -0
  83. package/dist/middleware/error.middleware.d.ts +8 -0
  84. package/dist/middleware/error.middleware.js +24 -0
  85. package/dist/middleware/validate.middleware.d.ts +7 -0
  86. package/dist/middleware/validate.middleware.js +42 -0
  87. package/dist/routes/analytics.routes.d.ts +1 -0
  88. package/dist/routes/analytics.routes.js +15 -0
  89. package/dist/routes/auth.routes.d.ts +1 -0
  90. package/dist/routes/auth.routes.js +15 -0
  91. package/dist/routes/browser.routes.d.ts +1 -0
  92. package/dist/routes/browser.routes.js +11 -0
  93. package/dist/routes/device.routes.d.ts +1 -0
  94. package/dist/routes/device.routes.js +11 -0
  95. package/dist/routes/index.d.ts +1 -0
  96. package/dist/routes/index.js +27 -0
  97. package/dist/routes/mcp.routes.d.ts +6 -0
  98. package/dist/routes/mcp.routes.js +70 -0
  99. package/dist/routes/project-stats.routes.d.ts +1 -0
  100. package/dist/routes/project-stats.routes.js +11 -0
  101. package/dist/routes/session.routes.d.ts +1 -0
  102. package/dist/routes/session.routes.js +23 -0
  103. package/dist/routes/upload.routes.d.ts +1 -0
  104. package/dist/routes/upload.routes.js +20 -0
  105. package/dist/routes/user.routes.d.ts +1 -0
  106. package/dist/routes/user.routes.js +11 -0
  107. package/dist/server.d.ts +1 -0
  108. package/dist/server.js +17 -0
  109. package/dist/services/analytics.service.d.ts +88 -0
  110. package/dist/services/analytics.service.js +98 -0
  111. package/dist/services/auth.service.d.ts +27 -0
  112. package/dist/services/auth.service.js +68 -0
  113. package/dist/services/browser.service.d.ts +25 -0
  114. package/dist/services/browser.service.js +43 -0
  115. package/dist/services/device.service.d.ts +18 -0
  116. package/dist/services/device.service.js +58 -0
  117. package/dist/services/diagnostics.service.d.ts +87 -0
  118. package/dist/services/diagnostics.service.js +92 -0
  119. package/dist/services/enrichment.service.d.ts +9 -0
  120. package/dist/services/enrichment.service.js +112 -0
  121. package/dist/services/index.d.ts +20 -0
  122. package/dist/services/index.js +31 -0
  123. package/dist/services/project.service.d.ts +22 -0
  124. package/dist/services/project.service.js +31 -0
  125. package/dist/services/session.service.d.ts +62 -0
  126. package/dist/services/session.service.js +104 -0
  127. package/dist/services/sessions-per-project.service.d.ts +18 -0
  128. package/dist/services/sessions-per-project.service.js +57 -0
  129. package/dist/services/upload.service.d.ts +20 -0
  130. package/dist/services/upload.service.js +29 -0
  131. package/dist/services/user.service.d.ts +17 -0
  132. package/dist/services/user.service.js +39 -0
  133. package/dist/token-cache.d.ts +12 -0
  134. package/dist/token-cache.js +37 -0
  135. package/dist/utils/logger.d.ts +10 -0
  136. package/dist/utils/logger.js +27 -0
  137. package/dist/utils/open-browser.d.ts +6 -0
  138. package/dist/utils/open-browser.js +23 -0
  139. package/dist/utils/time-range.d.ts +11 -0
  140. package/dist/utils/time-range.js +16 -0
  141. package/package.json +42 -0
package/PUBLISHING.md ADDED
@@ -0,0 +1,115 @@
1
+ # Publishing @seleniumbox/sbox-mcp
2
+
3
+ Guide for publishing the package to npm.
4
+
5
+ ## Prerequisites
6
+
7
+ - npm account with access to the **@seleniumbox** scope.
8
+ - Node.js 18+.
9
+
10
+ ## Step 1: Log in to npm
11
+
12
+ ```bash
13
+ npm login
14
+ ```
15
+
16
+ Use your npm credentials. For 2FA, have your one-time password ready if enabled.
17
+
18
+ ## Step 2: Bump version
19
+
20
+ From the **modules/mcp** directory:
21
+
22
+ ```bash
23
+ npm version patch # 0.1.0 → 0.1.1 (bug fixes)
24
+ npm version minor # 0.1.0 → 0.2.0 (new features, backward compatible)
25
+ npm version major # 0.1.0 → 1.0.0 (breaking changes)
26
+ ```
27
+
28
+ This updates `package.json` and creates a git commit and tag (e.g. `v0.1.1`).
29
+
30
+ ## Step 3: Publish to npm
31
+
32
+ Build a clean dist (includes shebang in the bin entry for npx):
33
+
34
+ ```bash
35
+ npm run rebuild
36
+ npm publish --access public
37
+ ```
38
+
39
+ **Scoped packages** (`@seleniumbox/sbox-mcp`) are private by default. `--access public` makes the package visible to everyone.
40
+
41
+ **First-time publish** for this package:
42
+
43
+ - Ensure `package.json` has `"name": "@seleniumbox/sbox-mcp"`, `version`, `description`, `license`, and `repository`.
44
+ - Run `npm publish --access public` once; subsequent publishes do not require `--access` unless you change visibility.
45
+
46
+ ## Step 4: Tag release in Git
47
+
48
+ If you use a monorepo and want a tag that includes the module path:
49
+
50
+ ```bash
51
+ git tag -a sbox-mcp/v0.1.1 -m "sbox-mcp 0.1.1"
52
+ git push origin sbox-mcp/v0.1.1
53
+ ```
54
+
55
+ Or rely on the default tag created by `npm version` (e.g. `v0.1.1`) and push it:
56
+
57
+ ```bash
58
+ git push origin v0.1.1
59
+ ```
60
+
61
+ ## Step 5: Update changelog
62
+
63
+ - Add an entry under a new version heading (e.g. `## [0.1.1]`) in the repo’s main `CHANGELOG.md` or in `modules/mcp/CHANGELOG.md` if you keep one for this package.
64
+ - Include: date, list of changes (fixes, features, breaking changes).
65
+
66
+ ## Testing locally before publishing
67
+
68
+ ### Using `npm link`
69
+
70
+ From **modules/mcp**:
71
+
72
+ ```bash
73
+ npm run build
74
+ npm link
75
+ ```
76
+
77
+ From another project or a test directory:
78
+
79
+ ```bash
80
+ npm link @seleniumbox/sbox-mcp
81
+ npx sbox-mcp
82
+ ```
83
+
84
+ Or run the linked binary directly:
85
+
86
+ ```bash
87
+ sbox-mcp
88
+ ```
89
+
90
+ (Ensure the global `node_modules/.bin` is in your `PATH`.)
91
+
92
+ ### Using `npx` with the local directory
93
+
94
+ From the repo root or any directory that can see the built package:
95
+
96
+ ```bash
97
+ cd modules/mcp && npm run build && npx .
98
+ ```
99
+
100
+ Or from **modules/mcp** after `npm run build`:
101
+
102
+ ```bash
103
+ npx .
104
+ ```
105
+
106
+ This runs the local `dist/index.js` as the MCP server so you can verify behavior before publishing.
107
+
108
+ ## Summary checklist
109
+
110
+ 1. `npm login`
111
+ 2. `npm version patch|minor|major`
112
+ 3. `npm publish --access public`
113
+ 4. `git push` (and push tags if desired)
114
+ 5. Update changelog
115
+ 6. Optionally test with `npx -y @seleniumbox/sbox-mcp@latest` after publish
package/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # @seleniumbox/sbox-mcp
2
+
3
+ Model Context Protocol (MCP) server for **Selenium Box (SBOX)**. Exposes SBOX APIs to AI-assisted IDEs (Cursor, Windsurf, IntelliJ) as MCP tools. Runs **locally** on your machine via `npx`—no Docker required.
4
+
5
+ ## Installation
6
+
7
+ No install step. Your IDE runs the server via **npx** (same pattern as TestingBot MCP):
8
+
9
+ ```bash
10
+ npx -y @seleniumbox/sbox-mcp@latest
11
+ ```
12
+
13
+ ## IDE configuration
14
+
15
+ ### Cursor / Windsurf
16
+
17
+ Add to your MCP settings (e.g. `.cursor/mcp.json` or Cursor Settings → MCP):
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "sbox": {
23
+ "command": "npx",
24
+ "args": ["-y", "@seleniumbox/sbox-mcp@latest"],
25
+ "env": {
26
+ "SBOX_API": "http://localhost:4444"
27
+ }
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ - **SBOX_API** – Base URL of your SBOX hub (no trailing slash). Default: `http://localhost:4444`.
34
+
35
+ **If you see `sbox-mcp: command not found`** (some IDEs use a minimal PATH), install in your project and run with `node` instead:
36
+
37
+ ```bash
38
+ npm install @seleniumbox/sbox-mcp
39
+ ```
40
+
41
+ Then use:
42
+
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "sbox": {
47
+ "command": "node",
48
+ "args": ["node_modules/@seleniumbox/sbox-mcp/dist/index.js"],
49
+ "env": {
50
+ "SBOX_API": "http://localhost:4444"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ Open Cursor from the directory that contains `node_modules`.
58
+
59
+ ## Required environment variables
60
+
61
+ | Variable | Default | Description |
62
+ |------------|---------------------------|--------------------------------------|
63
+ | `SBOX_API` | `http://localhost:4444` | Base URL of the SBOX hub (no slash). |
64
+
65
+ Optional:
66
+
67
+ | Variable | Default | Description |
68
+ |-------------------------|---------|--------------------------------------------|
69
+ | `PORT` / `MCP_PORT` | `3344` | Only used when running the REST server. |
70
+ | `MCP_DEBUG` / `DEBUG` | off | Set to `1` or `true` for request logging. |
71
+ | `MCP_REQUEST_TIMEOUT_MS`| `30000` | Timeout for outbound SBOX API requests. |
72
+
73
+ ## Authentication flow
74
+
75
+ 1. User asks the AI to log in to SBOX (e.g. “authenticate with SBOX”).
76
+ 2. The **sbox_open_login** tool runs:
77
+ - Checks that the MCP add-on is enabled on the hub (`GET /e34/api/mcp/enabled`).
78
+ - Generates a `poll_id`, opens the login URL in your default browser (or returns `auth_url` so the IDE can open it).
79
+ 3. You sign in on the SBOX hub (local, LDAP, or OIDC).
80
+ 4. The hub stores the token by `poll_id`; MCP polls for it and caches it.
81
+ 5. Subsequent SBOX tools use the cached token automatically.
82
+
83
+ **Device + Poll**: No callback server on your machine. The hub holds the token and MCP retrieves it by polling. Same contract as before; only distribution is local.
84
+
85
+ ## SBOX_API usage
86
+
87
+ - All MCP tools that call the hub use `SBOX_API` (or `SBOX_API_BASE_URL`) to build URLs, e.g. `{SBOX_API}/e34/api/...`.
88
+ - The login URL shown to you is `{SBOX_API}/ui/login?mcp_poll_id=...`. Use the same base URL in your browser as the hub (e.g. `http://localhost:4444` for a local hub).
89
+
90
+ ## Local development
91
+
92
+ ```bash
93
+ cd modules/mcp
94
+ npm ci
95
+ npm run build
96
+ ```
97
+
98
+ - **Run MCP (stdio, for IDE):**
99
+ `npm start` or `node dist/index.js`
100
+ - **Run REST server (optional):**
101
+ `npm run server` or `node dist/server.js` (listens on `PORT`/`MCP_PORT`, default 3344)
102
+
103
+ Development with auto-reload:
104
+
105
+ ```bash
106
+ npm run dev # stdio MCP
107
+ npm run dev:server # REST server
108
+ ```
109
+
110
+ ## Build
111
+
112
+ ```bash
113
+ npm run build
114
+ ```
115
+
116
+ Output is in `dist/`. The CLI entrypoint is `dist/index.js` (used by the `sbox-mcp` bin).
117
+
118
+ ## Publish
119
+
120
+ See **[PUBLISHING.md](./PUBLISHING.md)** for:
121
+
122
+ - `npm login`, `npm version`, `npm publish --access public`
123
+ - Scoped package and first-time publish
124
+ - Testing locally with `npm link` and `npx .`
125
+
126
+ ## Hub requirements
127
+
128
+ - **MCP add-on** enabled (license flag `E34_MCP`).
129
+ - Endpoints: `GET/POST /e34/api/mcp/poll`, `GET /e34/api/mcp/enabled`.
130
+ - No change to the Hub contract or `poll_id` mechanism; only distribution is now npm/npx.
131
+
132
+ ## License
133
+
134
+ Apache-2.0
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Adapter for SBOX authentication. Calls POST /authenticate and GET /user/session.
3
+ * No business logic; no password hashing (handled by backend).
4
+ */
5
+ export interface CredentialPayload {
6
+ username: string;
7
+ password: string;
8
+ }
9
+ export interface UserSessionApi {
10
+ token: string;
11
+ principal: {
12
+ userId?: string;
13
+ fullname?: string;
14
+ realm?: {
15
+ id?: string;
16
+ };
17
+ };
18
+ }
19
+ export interface McpPollResponse {
20
+ token?: string;
21
+ }
22
+ export interface McpEnabledResponse {
23
+ enabled?: boolean;
24
+ }
25
+ export interface AuthAdapter {
26
+ isMcpAddonEnabled(): Promise<boolean>;
27
+ login(payload: CredentialPayload): Promise<{
28
+ status: number;
29
+ data: UserSessionApi | {
30
+ success: false;
31
+ message: string;
32
+ };
33
+ }>;
34
+ validateSession(token: string): Promise<{
35
+ status: number;
36
+ data: UserSessionApi | {
37
+ success: false;
38
+ message: string;
39
+ };
40
+ }>;
41
+ pollToken(pollId: string): Promise<{
42
+ status: number;
43
+ data: McpPollResponse;
44
+ }>;
45
+ }
46
+ export declare const authAdapter: AuthAdapter;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ /**
3
+ * Adapter for SBOX authentication. Calls POST /authenticate and GET /user/session.
4
+ * No business logic; no password hashing (handled by backend).
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.authAdapter = void 0;
8
+ const sbox_api_client_1 = require("./sbox-api.client");
9
+ const config_1 = require("../config");
10
+ const logger_1 = require("../utils/logger");
11
+ async function isMcpAddonEnabled() {
12
+ const url = `${config_1.config.sboxApiBaseUrl}${config_1.config.sboxApiPrefix}/mcp/enabled`;
13
+ logger_1.logger.info("MCP add-on check: requesting", { url });
14
+ try {
15
+ const { data, status } = await (0, sbox_api_client_1.getPublic)("mcp/enabled");
16
+ const enabled = status === 200 && typeof data?.enabled === "boolean" && data.enabled === true;
17
+ if (!enabled) {
18
+ logger_1.logger.warn("MCP add-on check: hub did not return enabled=true", {
19
+ url,
20
+ status,
21
+ responseBody: typeof data === "object" ? data : String(data),
22
+ });
23
+ }
24
+ return enabled;
25
+ }
26
+ catch (err) {
27
+ logger_1.logger.error("MCP add-on check: request failed", {
28
+ url,
29
+ error: err instanceof Error ? err.message : String(err),
30
+ });
31
+ return false;
32
+ }
33
+ }
34
+ async function login(payload) {
35
+ const { data, status } = await (0, sbox_api_client_1.post)("authenticate", payload);
36
+ if (status !== 200) {
37
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Login failed";
38
+ return { status, data: { success: false, message: msg } };
39
+ }
40
+ return { status, data: data };
41
+ }
42
+ async function validateSession(token) {
43
+ const { data, status } = await (0, sbox_api_client_1.get)("user/session", token);
44
+ if (status !== 200) {
45
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Invalid or expired token";
46
+ return { status, data: { success: false, message: msg } };
47
+ }
48
+ return { status, data: data };
49
+ }
50
+ async function pollToken(pollId) {
51
+ const { data, status } = await (0, sbox_api_client_1.get)("mcp/poll?poll_id=" + encodeURIComponent(pollId), null);
52
+ return { status, data: data ?? {} };
53
+ }
54
+ exports.authAdapter = { isMcpAddonEnabled, login, validateSession, pollToken };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Adapter for SBOX browser APIs. Calls /browser/details, /executors, /playwright.
3
+ * No business logic; only HTTP and response typing.
4
+ */
5
+ export interface ImageInfoRaw {
6
+ name?: string;
7
+ tags?: string[];
8
+ }
9
+ export interface ExecutorDtoRaw {
10
+ id?: string;
11
+ type?: string;
12
+ capabilities?: Record<string, unknown>;
13
+ [key: string]: unknown;
14
+ }
15
+ /** GET /e34/api/playwright returns list of { version, chromium, webkit, firefox } */
16
+ export interface PlaywrightVersionRaw {
17
+ version?: string;
18
+ chromium?: string;
19
+ webkit?: string;
20
+ firefox?: string;
21
+ [key: string]: unknown;
22
+ }
23
+ export interface BrowserAdapter {
24
+ getBrowserVersions(name: string, token: string): Promise<{
25
+ status: number;
26
+ name: string;
27
+ versions: string[];
28
+ error?: string;
29
+ }>;
30
+ getExecutors(token: string): Promise<{
31
+ status: number;
32
+ executors: ExecutorDtoRaw[];
33
+ error?: string;
34
+ }>;
35
+ getPlaywrightVersions(token: string): Promise<{
36
+ status: number;
37
+ versions: PlaywrightVersionRaw[];
38
+ error?: string;
39
+ }>;
40
+ }
41
+ declare const BROWSER_NAMES: string[];
42
+ export declare const browserAdapter: BrowserAdapter;
43
+ export { BROWSER_NAMES };
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * Adapter for SBOX browser APIs. Calls /browser/details, /executors, /playwright.
4
+ * No business logic; only HTTP and response typing.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.BROWSER_NAMES = exports.browserAdapter = void 0;
8
+ const sbox_api_client_1 = require("./sbox-api.client");
9
+ const BROWSER_NAMES = ["chrome", "firefox", "firefox-esr", "MicrosoftEdge", "internet explorer", "safari", "webkit"];
10
+ exports.BROWSER_NAMES = BROWSER_NAMES;
11
+ async function getBrowserVersions(name, token) {
12
+ const { data, status } = await (0, sbox_api_client_1.get)(`browser/details?name=${encodeURIComponent(name)}`, token);
13
+ if (status !== 200) {
14
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get browser versions";
15
+ return { status, name, versions: [], error: msg };
16
+ }
17
+ const raw = data;
18
+ const tags = Array.isArray(raw.tags) ? raw.tags : [];
19
+ return { status, name: raw.name ?? name, versions: tags };
20
+ }
21
+ async function getExecutors(token) {
22
+ const { data, status } = await (0, sbox_api_client_1.get)("executors", token);
23
+ if (status !== 200) {
24
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get executors";
25
+ return { status, executors: [], error: msg };
26
+ }
27
+ const list = Array.isArray(data) ? data : [];
28
+ return { status, executors: list };
29
+ }
30
+ async function getPlaywrightVersions(token) {
31
+ const { data, status } = await (0, sbox_api_client_1.get)("playwright", token);
32
+ if (status !== 200) {
33
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Playwright is not enabled or failed to get versions";
34
+ return { status, versions: [], error: msg };
35
+ }
36
+ const list = Array.isArray(data) ? data : [];
37
+ return { status, versions: list };
38
+ }
39
+ exports.browserAdapter = { getBrowserVersions, getExecutors, getPlaywrightVersions };
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Adapter for SBOX device APIs. Calls mobile/ios/devices, mobile/android/devices, mobileweb/devices.
3
+ * No business logic; only HTTP and response typing.
4
+ */
5
+ /** Android API: GET /e34/api/mobile/android/devices */
6
+ export interface AndroidDeviceRaw {
7
+ avdName?: string;
8
+ deviceName?: string;
9
+ completeDeviceName?: string;
10
+ supportedPlatformVersions?: string[];
11
+ [key: string]: unknown;
12
+ }
13
+ /** iOS API: GET /e34/api/mobile/ios/devices (IOSDeviceAPI: deviceName + getIOSSDK list) */
14
+ export interface IOSDeviceRaw {
15
+ deviceName?: string;
16
+ /** List of supported SDKs (each has name, safariVersion). Backend may serialize as iosSDK, iossdks, or IOSSDK. */
17
+ iosSDK?: Array<{
18
+ name?: string;
19
+ safariVersion?: string;
20
+ }>;
21
+ iossdks?: Array<{
22
+ name?: string;
23
+ safariVersion?: string;
24
+ }>;
25
+ IOSSDK?: Array<{
26
+ name?: string;
27
+ safariVersion?: string;
28
+ }>;
29
+ [key: string]: unknown;
30
+ }
31
+ /** Generic device raw (mobile web may use name, os, version) */
32
+ export interface DeviceRaw {
33
+ name?: string;
34
+ deviceName?: string;
35
+ completeDeviceName?: string;
36
+ avdName?: string;
37
+ supportedPlatformVersions?: string[];
38
+ os?: string;
39
+ version?: string;
40
+ available?: boolean;
41
+ [key: string]: unknown;
42
+ }
43
+ export interface DeviceAdapter {
44
+ getIosDevices(token: string): Promise<{
45
+ status: number;
46
+ devices: IOSDeviceRaw[];
47
+ error?: string;
48
+ }>;
49
+ getAndroidDevices(token: string): Promise<{
50
+ status: number;
51
+ devices: AndroidDeviceRaw[];
52
+ error?: string;
53
+ }>;
54
+ getMobileWebDevices(token: string): Promise<{
55
+ status: number;
56
+ devices: DeviceRaw[];
57
+ error?: string;
58
+ }>;
59
+ }
60
+ export declare const deviceAdapter: DeviceAdapter;
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ /**
3
+ * Adapter for SBOX device APIs. Calls mobile/ios/devices, mobile/android/devices, mobileweb/devices.
4
+ * No business logic; only HTTP and response typing.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.deviceAdapter = void 0;
8
+ const sbox_api_client_1 = require("./sbox-api.client");
9
+ async function getIosDevices(token) {
10
+ const { data, status } = await (0, sbox_api_client_1.get)("mobile/ios/devices", token);
11
+ if (status !== 200) {
12
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get iOS devices";
13
+ return { status, devices: [], error: msg };
14
+ }
15
+ const list = Array.isArray(data) ? data : [];
16
+ return { status, devices: list };
17
+ }
18
+ async function getAndroidDevices(token) {
19
+ const { data, status } = await (0, sbox_api_client_1.get)("mobile/android/devices", token);
20
+ if (status !== 200) {
21
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get Android devices";
22
+ return { status, devices: [], error: msg };
23
+ }
24
+ const list = Array.isArray(data) ? data : [];
25
+ return { status, devices: list };
26
+ }
27
+ async function getMobileWebDevices(token) {
28
+ const { data, status } = await (0, sbox_api_client_1.get)("mobileweb/devices", token);
29
+ if (status !== 200) {
30
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get mobile web devices";
31
+ return { status, devices: [], error: msg };
32
+ }
33
+ const list = Array.isArray(data) ? data : [];
34
+ return { status, devices: list };
35
+ }
36
+ exports.deviceAdapter = {
37
+ getIosDevices,
38
+ getAndroidDevices,
39
+ getMobileWebDevices,
40
+ };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Adapter for SBOX Diagnostics Dashboard APIs.
3
+ * Endpoints: cpu-usage-per-node, tests/queued/hourly, nodes/active-tests, queue/waiting-time, tests-active-graph, tests/starting/stats, executors.
4
+ */
5
+ export interface CpuUsagePerNodeRaw {
6
+ node?: string;
7
+ avg_cpu?: number;
8
+ timestamp?: string;
9
+ }
10
+ export interface TestsQueuedHourlyRaw {
11
+ timestamp?: string;
12
+ avg_total?: number;
13
+ max_total?: number;
14
+ }
15
+ export interface NodesActiveTestsRaw {
16
+ timestamp?: string;
17
+ average_total?: number;
18
+ }
19
+ export interface QueueWaitingTimeRaw {
20
+ timestamp?: string;
21
+ browsers?: Array<{
22
+ avg_duration?: number;
23
+ max_duration?: number;
24
+ }>;
25
+ }
26
+ export interface TestsActiveGraphRaw {
27
+ timestamp?: string;
28
+ avg_total?: number;
29
+ node?: string;
30
+ }
31
+ export interface TestsStartingStatsRaw {
32
+ timestamp?: string;
33
+ node?: string;
34
+ avg_total?: number;
35
+ }
36
+ export interface DiagnosticsAdapter {
37
+ getExecutorsCount(token: string): Promise<{
38
+ status: number;
39
+ count: number;
40
+ error?: string;
41
+ }>;
42
+ getCpuUsagePerNode(token: string, days: number): Promise<{
43
+ status: number;
44
+ items: CpuUsagePerNodeRaw[];
45
+ error?: string;
46
+ }>;
47
+ getTestsQueuedHourly(token: string, days: number): Promise<{
48
+ status: number;
49
+ items: TestsQueuedHourlyRaw[];
50
+ error?: string;
51
+ }>;
52
+ getNodesActiveTests(token: string, days: number): Promise<{
53
+ status: number;
54
+ items: NodesActiveTestsRaw[];
55
+ error?: string;
56
+ }>;
57
+ getQueueWaitingTime(token: string, days: number): Promise<{
58
+ status: number;
59
+ items: QueueWaitingTimeRaw[];
60
+ error?: string;
61
+ }>;
62
+ getTestsActiveGraph(token: string, days: number): Promise<{
63
+ status: number;
64
+ items: TestsActiveGraphRaw[];
65
+ error?: string;
66
+ }>;
67
+ getTestsStartingStats(token: string, days: number): Promise<{
68
+ status: number;
69
+ items: TestsStartingStatsRaw[];
70
+ error?: string;
71
+ }>;
72
+ }
73
+ export declare const diagnosticsAdapter: DiagnosticsAdapter;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ /**
3
+ * Adapter for SBOX Diagnostics Dashboard APIs.
4
+ * Endpoints: cpu-usage-per-node, tests/queued/hourly, nodes/active-tests, queue/waiting-time, tests-active-graph, tests/starting/stats, executors.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.diagnosticsAdapter = void 0;
8
+ const sbox_api_client_1 = require("./sbox-api.client");
9
+ function clampDays(days) {
10
+ return Math.max(7, Math.min(365, days));
11
+ }
12
+ async function getExecutorsCount(token) {
13
+ const { data, status } = await (0, sbox_api_client_1.get)("executors", token);
14
+ if (status !== 200) {
15
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get executors";
16
+ return { status, count: 0, error: msg };
17
+ }
18
+ const list = Array.isArray(data) ? data : [];
19
+ return { status, count: list.length };
20
+ }
21
+ async function getCpuUsagePerNode(token, days) {
22
+ const d = clampDays(days);
23
+ const path = `cpu-usage-per-node?days=${d}`;
24
+ const { data, status } = await (0, sbox_api_client_1.get)(path, token);
25
+ if (status !== 200) {
26
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get CPU usage per node";
27
+ return { status, items: [], error: msg };
28
+ }
29
+ return { status, items: Array.isArray(data) ? data : [] };
30
+ }
31
+ async function getTestsQueuedHourly(token, days) {
32
+ const d = clampDays(days);
33
+ const path = `tests/queued/hourly?days=${d}`;
34
+ const { data, status } = await (0, sbox_api_client_1.get)(path, token);
35
+ if (status !== 200) {
36
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get tests queued hourly";
37
+ return { status, items: [], error: msg };
38
+ }
39
+ return { status, items: Array.isArray(data) ? data : [] };
40
+ }
41
+ async function getNodesActiveTests(token, days) {
42
+ const d = clampDays(days);
43
+ const path = `nodes/active-tests?days=${d}`;
44
+ const { data, status } = await (0, sbox_api_client_1.get)(path, token);
45
+ if (status !== 200) {
46
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get nodes active tests";
47
+ return { status, items: [], error: msg };
48
+ }
49
+ return { status, items: Array.isArray(data) ? data : [] };
50
+ }
51
+ async function getQueueWaitingTime(token, days) {
52
+ const d = clampDays(days);
53
+ const path = `queue/waiting-time?days=${d}`;
54
+ const { data, status } = await (0, sbox_api_client_1.get)(path, token);
55
+ if (status !== 200) {
56
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get queue waiting time";
57
+ return { status, items: [], error: msg };
58
+ }
59
+ return { status, items: Array.isArray(data) ? data : [] };
60
+ }
61
+ async function getTestsActiveGraph(token, days) {
62
+ const d = clampDays(days);
63
+ const path = `tests-active-graph?days=${d}`;
64
+ const { data, status } = await (0, sbox_api_client_1.get)(path, token);
65
+ if (status !== 200) {
66
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get tests active graph";
67
+ return { status, items: [], error: msg };
68
+ }
69
+ return { status, items: Array.isArray(data) ? data : [] };
70
+ }
71
+ async function getTestsStartingStats(token, days) {
72
+ const d = clampDays(days);
73
+ const path = `tests/starting/stats?days=${d}`;
74
+ const { data, status } = await (0, sbox_api_client_1.get)(path, token);
75
+ if (status !== 200) {
76
+ const msg = (0, sbox_api_client_1.isSboxError)(data) ? data.message : "Failed to get tests starting stats";
77
+ return { status, items: [], error: msg };
78
+ }
79
+ return { status, items: Array.isArray(data) ? data : [] };
80
+ }
81
+ exports.diagnosticsAdapter = {
82
+ getExecutorsCount,
83
+ getCpuUsagePerNode,
84
+ getTestsQueuedHourly,
85
+ getNodesActiveTests,
86
+ getQueueWaitingTime,
87
+ getTestsActiveGraph,
88
+ getTestsStartingStats,
89
+ };