@seleniumbox/sbox-mcp 1.0.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 +79 -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 +166 -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 +23 -0
  28. package/dist/config/env.js +64 -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 +35 -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 +545 -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 +13 -0
  134. package/dist/token-cache.js +114 -0
  135. package/dist/utils/logger.d.ts +11 -0
  136. package/dist/utils/logger.js +31 -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,79 @@
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
+ Then restart Cursor or reload MCP.
36
+
37
+ ## Required environment variables
38
+
39
+ | Variable | Default | Description |
40
+ |------------|---------------------------|--------------------------------------|
41
+ | `SBOX_API` | `http://localhost:4444` | Base URL of the SBOX hub (no slash). |
42
+
43
+ Optional:
44
+
45
+ | Variable | Default | Description |
46
+ |-------------------------|-------------|-----------------------------------------------------------------------------|
47
+ | `MCP_DEBUG` or `DEBUG` | — | Set to `1` or `true` to log incoming MCP and outbound SBOX API request/response (sensitive fields redacted). |
48
+ | `MCP_REQUEST_TIMEOUT_MS`| `30000` | Timeout for outbound SBOX API requests. |
49
+ | `SBOX_MCP_TOKEN_FILE` | see below | Override path for the persisted session token file (default: `~/.sbox-mcp/token`). |
50
+ | `SBOX_ALLOW_INSECURE_SSL` | (default: skip verification) | Set to `0` or `false` to verify TLS certificates; unset or `1`/`true` skips verification (default). |
51
+
52
+ ## Token cache
53
+
54
+ After you log in via **sbox_open_login**, the session token is stored in memory and **on disk** so it survives MCP process restarts (e.g. when the IDE starts a new process per prompt). Default location: `~/.sbox-mcp/token`. The cache directory is created with mode `0700` and the token file with `0600`. Set `SBOX_MCP_TOKEN_FILE` to use a different path (only the token file; the directory is inferred for `last_poll_id`). If an API call returns 401 or “invalid token”, the cache is cleared so the next run will prompt for login again.
55
+
56
+ ## Authentication flow
57
+
58
+ 1. User asks the AI to log in to SBOX (e.g. “authenticate with SBOX”).
59
+ 2. The **sbox_open_login** tool runs:
60
+ - Checks that the MCP add-on is enabled on the hub.
61
+ - Generates a unique session id, opens the login URL in your default browser (or returns `auth_url` so the IDE can open it).
62
+ 3. You sign in on the SBOX hub (local, LDAP, or OIDC).
63
+ 4. The hub stores the token by session id; MCP polls for it and caches it.
64
+ 5. Subsequent SBOX tools use the cached token automatically.
65
+
66
+ **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.
67
+
68
+ ## SBOX_API usage
69
+
70
+ - All MCP tools that call the hub use `SBOX_API` (or `SBOX_API_BASE_URL`) to build URLs, e.g. `{SBOX_API}/e34/api/...`.
71
+ - 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).
72
+
73
+ ## Hub requirements
74
+
75
+ - **MCP add-on** enabled (license flag `E34_MCP`).
76
+
77
+ ## License
78
+
79
+ 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.info("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
+ };
@@ -0,0 +1,16 @@
1
+ export { authAdapter } from "./auth.adapter";
2
+ export type { AuthAdapter, UserSessionApi } from "./auth.adapter";
3
+ export { sessionAdapter } from "./session.adapter";
4
+ export type { SessionAdapter, ESSessionDataRaw } from "./session.adapter";
5
+ export { browserAdapter, BROWSER_NAMES } from "./browser.adapter";
6
+ export type { BrowserAdapter } from "./browser.adapter";
7
+ export { deviceAdapter } from "./device.adapter";
8
+ export type { DeviceAdapter } from "./device.adapter";
9
+ export { projectAdapter } from "./project.adapter";
10
+ export type { ProjectAdapter } from "./project.adapter";
11
+ export { userAdapter } from "./user.adapter";
12
+ export type { UserAdapter } from "./user.adapter";
13
+ export { statsAdapter } from "./stats.adapter";
14
+ export type { StatsAdapter } from "./stats.adapter";
15
+ export { uploadAdapter } from "./upload.adapter";
16
+ export type { UploadAdapter } from "./upload.adapter";
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uploadAdapter = exports.statsAdapter = exports.userAdapter = exports.projectAdapter = exports.deviceAdapter = exports.BROWSER_NAMES = exports.browserAdapter = exports.sessionAdapter = exports.authAdapter = void 0;
4
+ var auth_adapter_1 = require("./auth.adapter");
5
+ Object.defineProperty(exports, "authAdapter", { enumerable: true, get: function () { return auth_adapter_1.authAdapter; } });
6
+ var session_adapter_1 = require("./session.adapter");
7
+ Object.defineProperty(exports, "sessionAdapter", { enumerable: true, get: function () { return session_adapter_1.sessionAdapter; } });
8
+ var browser_adapter_1 = require("./browser.adapter");
9
+ Object.defineProperty(exports, "browserAdapter", { enumerable: true, get: function () { return browser_adapter_1.browserAdapter; } });
10
+ Object.defineProperty(exports, "BROWSER_NAMES", { enumerable: true, get: function () { return browser_adapter_1.BROWSER_NAMES; } });
11
+ var device_adapter_1 = require("./device.adapter");
12
+ Object.defineProperty(exports, "deviceAdapter", { enumerable: true, get: function () { return device_adapter_1.deviceAdapter; } });
13
+ var project_adapter_1 = require("./project.adapter");
14
+ Object.defineProperty(exports, "projectAdapter", { enumerable: true, get: function () { return project_adapter_1.projectAdapter; } });
15
+ var user_adapter_1 = require("./user.adapter");
16
+ Object.defineProperty(exports, "userAdapter", { enumerable: true, get: function () { return user_adapter_1.userAdapter; } });
17
+ var stats_adapter_1 = require("./stats.adapter");
18
+ Object.defineProperty(exports, "statsAdapter", { enumerable: true, get: function () { return stats_adapter_1.statsAdapter; } });
19
+ var upload_adapter_1 = require("./upload.adapter");
20
+ Object.defineProperty(exports, "uploadAdapter", { enumerable: true, get: function () { return upload_adapter_1.uploadAdapter; } });