@bctrl/sdk 1.0.1

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 (260) hide show
  1. package/README.md +75 -0
  2. package/dist/agents/browser-use/index.d.ts +1 -0
  3. package/dist/agents/browser-use/index.js +9 -0
  4. package/dist/agents/browser-use/namespace.d.ts +39 -0
  5. package/dist/agents/browser-use/namespace.js +93 -0
  6. package/dist/agents/index.d.ts +2 -0
  7. package/dist/agents/index.js +17 -0
  8. package/dist/agents/stagehand/core.d.ts +93 -0
  9. package/dist/agents/stagehand/core.js +144 -0
  10. package/dist/agents/stagehand/index.d.ts +3 -0
  11. package/dist/agents/stagehand/index.js +24 -0
  12. package/dist/agents/stagehand/namespace.d.ts +51 -0
  13. package/dist/agents/stagehand/namespace.js +65 -0
  14. package/dist/ai-credentials/client.d.ts +12 -0
  15. package/dist/ai-credentials/client.js +70 -0
  16. package/dist/ai-credentials/index.d.ts +1 -0
  17. package/dist/ai-credentials/index.js +1 -0
  18. package/dist/base/event-binding.d.ts +7 -0
  19. package/dist/base/event-binding.js +23 -0
  20. package/dist/base/types.d.ts +109 -0
  21. package/dist/base/types.js +4 -0
  22. package/dist/bctrl.d.ts +37 -0
  23. package/dist/bctrl.js +77 -0
  24. package/dist/browser-extensions/client.d.ts +15 -0
  25. package/dist/browser-extensions/client.js +72 -0
  26. package/dist/browser-extensions/index.d.ts +2 -0
  27. package/dist/browser-extensions/index.js +1 -0
  28. package/dist/browser-profiles/client.d.ts +11 -0
  29. package/dist/browser-profiles/client.js +63 -0
  30. package/dist/browser-profiles/index.d.ts +1 -0
  31. package/dist/browser-profiles/index.js +1 -0
  32. package/dist/captcha/index.d.ts +1 -0
  33. package/dist/captcha/index.js +1 -0
  34. package/dist/captcha/namespace.d.ts +34 -0
  35. package/dist/captcha/namespace.js +41 -0
  36. package/dist/client/index.d.ts +1 -0
  37. package/dist/client/index.js +1 -0
  38. package/dist/client/rpc.d.ts +83 -0
  39. package/dist/client/rpc.js +354 -0
  40. package/dist/config.d.ts +5 -0
  41. package/dist/config.js +28 -0
  42. package/dist/constants/browser.d.ts +2 -0
  43. package/dist/constants/browser.js +1 -0
  44. package/dist/contracts/agent-tools.d.ts +45 -0
  45. package/dist/contracts/agent-tools.js +31 -0
  46. package/dist/contracts/automation.d.ts +265 -0
  47. package/dist/contracts/automation.js +109 -0
  48. package/dist/contracts/browser-management.d.ts +179 -0
  49. package/dist/contracts/browser-management.js +95 -0
  50. package/dist/contracts/browser-use.d.ts +136 -0
  51. package/dist/contracts/browser-use.js +93 -0
  52. package/dist/contracts/captcha.d.ts +114 -0
  53. package/dist/contracts/captcha.js +40 -0
  54. package/dist/contracts/desktop.d.ts +223 -0
  55. package/dist/contracts/desktop.js +121 -0
  56. package/dist/contracts/drivers/playwright.d.ts +2008 -0
  57. package/dist/contracts/drivers/playwright.js +2033 -0
  58. package/dist/contracts/drivers/puppeteer.d.ts +1221 -0
  59. package/dist/contracts/drivers/puppeteer.js +941 -0
  60. package/dist/contracts/drivers/selenium.d.ts +156 -0
  61. package/dist/contracts/drivers/selenium.js +61 -0
  62. package/dist/contracts/drivers/stagehand.d.ts +155 -0
  63. package/dist/contracts/drivers/stagehand.js +7 -0
  64. package/dist/contracts/extensions.d.ts +13 -0
  65. package/dist/contracts/extensions.js +9 -0
  66. package/dist/contracts/index.d.ts +13 -0
  67. package/dist/contracts/index.js +13 -0
  68. package/dist/contracts/public-api.d.ts +360 -0
  69. package/dist/contracts/public-api.js +17 -0
  70. package/dist/contracts/runtime.d.ts +81 -0
  71. package/dist/contracts/runtime.js +16 -0
  72. package/dist/contracts/stagehand.d.ts +253 -0
  73. package/dist/contracts/stagehand.js +145 -0
  74. package/dist/contracts/storage.d.ts +51 -0
  75. package/dist/contracts/storage.js +56 -0
  76. package/dist/contracts/vault.d.ts +119 -0
  77. package/dist/contracts/vault.js +112 -0
  78. package/dist/contracts/version.d.ts +3 -0
  79. package/dist/contracts/version.js +16 -0
  80. package/dist/desktop.d.ts +2 -0
  81. package/dist/desktop.js +3 -0
  82. package/dist/drivers/desktop/index.d.ts +65 -0
  83. package/dist/drivers/desktop/index.js +68 -0
  84. package/dist/drivers/desktop/session.d.ts +313 -0
  85. package/dist/drivers/desktop/session.js +432 -0
  86. package/dist/drivers/playwright/event-emitter.d.ts +160 -0
  87. package/dist/drivers/playwright/event-emitter.js +297 -0
  88. package/dist/drivers/playwright/generated/api-request-context.d.ts +137 -0
  89. package/dist/drivers/playwright/generated/api-request-context.js +154 -0
  90. package/dist/drivers/playwright/generated/api-response.d.ts +119 -0
  91. package/dist/drivers/playwright/generated/api-response.js +123 -0
  92. package/dist/drivers/playwright/generated/browser-context.d.ts +284 -0
  93. package/dist/drivers/playwright/generated/browser-context.js +458 -0
  94. package/dist/drivers/playwright/generated/browser.d.ts +120 -0
  95. package/dist/drivers/playwright/generated/browser.js +151 -0
  96. package/dist/drivers/playwright/generated/clock.d.ts +80 -0
  97. package/dist/drivers/playwright/generated/clock.js +94 -0
  98. package/dist/drivers/playwright/generated/console-message.d.ts +94 -0
  99. package/dist/drivers/playwright/generated/console-message.js +89 -0
  100. package/dist/drivers/playwright/generated/coverage.d.ts +57 -0
  101. package/dist/drivers/playwright/generated/coverage.js +66 -0
  102. package/dist/drivers/playwright/generated/dialog.d.ts +79 -0
  103. package/dist/drivers/playwright/generated/dialog.js +80 -0
  104. package/dist/drivers/playwright/generated/element-handle.d.ts +399 -0
  105. package/dist/drivers/playwright/generated/element-handle.js +501 -0
  106. package/dist/drivers/playwright/generated/frame-locator.d.ts +34 -0
  107. package/dist/drivers/playwright/generated/frame-locator.js +63 -0
  108. package/dist/drivers/playwright/generated/frame.d.ts +557 -0
  109. package/dist/drivers/playwright/generated/frame.js +634 -0
  110. package/dist/drivers/playwright/generated/js-handle.d.ts +72 -0
  111. package/dist/drivers/playwright/generated/js-handle.js +92 -0
  112. package/dist/drivers/playwright/generated/keyboard.d.ts +103 -0
  113. package/dist/drivers/playwright/generated/keyboard.js +113 -0
  114. package/dist/drivers/playwright/generated/locator.d.ts +795 -0
  115. package/dist/drivers/playwright/generated/locator.js +974 -0
  116. package/dist/drivers/playwright/generated/mouse.d.ts +97 -0
  117. package/dist/drivers/playwright/generated/mouse.js +109 -0
  118. package/dist/drivers/playwright/generated/page.d.ts +762 -0
  119. package/dist/drivers/playwright/generated/page.js +988 -0
  120. package/dist/drivers/playwright/generated/touchscreen.d.ts +34 -0
  121. package/dist/drivers/playwright/generated/touchscreen.js +37 -0
  122. package/dist/drivers/playwright/generated/tracing.d.ts +78 -0
  123. package/dist/drivers/playwright/generated/tracing.js +80 -0
  124. package/dist/drivers/playwright/generated/worker.d.ts +53 -0
  125. package/dist/drivers/playwright/generated/worker.js +59 -0
  126. package/dist/drivers/playwright/index.d.ts +19 -0
  127. package/dist/drivers/playwright/index.js +20 -0
  128. package/dist/drivers/playwright/remote-base.d.ts +62 -0
  129. package/dist/drivers/playwright/remote-base.js +86 -0
  130. package/dist/drivers/playwright/types.d.ts +148 -0
  131. package/dist/drivers/playwright/types.js +8 -0
  132. package/dist/drivers/puppeteer/errors.d.ts +50 -0
  133. package/dist/drivers/puppeteer/errors.js +71 -0
  134. package/dist/drivers/puppeteer/event-emitter.d.ts +145 -0
  135. package/dist/drivers/puppeteer/event-emitter.js +259 -0
  136. package/dist/drivers/puppeteer/generated/accessibility.d.ts +77 -0
  137. package/dist/drivers/puppeteer/generated/accessibility.js +74 -0
  138. package/dist/drivers/puppeteer/generated/browser-context.d.ts +116 -0
  139. package/dist/drivers/puppeteer/generated/browser-context.js +168 -0
  140. package/dist/drivers/puppeteer/generated/browser.d.ts +169 -0
  141. package/dist/drivers/puppeteer/generated/browser.js +246 -0
  142. package/dist/drivers/puppeteer/generated/console-message.d.ts +54 -0
  143. package/dist/drivers/puppeteer/generated/console-message.js +69 -0
  144. package/dist/drivers/puppeteer/generated/coverage.d.ts +49 -0
  145. package/dist/drivers/puppeteer/generated/coverage.js +57 -0
  146. package/dist/drivers/puppeteer/generated/dialog.d.ts +46 -0
  147. package/dist/drivers/puppeteer/generated/dialog.js +60 -0
  148. package/dist/drivers/puppeteer/generated/element-handle.d.ts +261 -0
  149. package/dist/drivers/puppeteer/generated/element-handle.js +341 -0
  150. package/dist/drivers/puppeteer/generated/file-chooser.d.ts +34 -0
  151. package/dist/drivers/puppeteer/generated/file-chooser.js +43 -0
  152. package/dist/drivers/puppeteer/generated/frame.d.ts +221 -0
  153. package/dist/drivers/puppeteer/generated/frame.js +302 -0
  154. package/dist/drivers/puppeteer/generated/http-request.d.ts +195 -0
  155. package/dist/drivers/puppeteer/generated/http-request.js +243 -0
  156. package/dist/drivers/puppeteer/generated/http-response.d.ts +142 -0
  157. package/dist/drivers/puppeteer/generated/http-response.js +169 -0
  158. package/dist/drivers/puppeteer/generated/js-handle.d.ts +104 -0
  159. package/dist/drivers/puppeteer/generated/js-handle.js +125 -0
  160. package/dist/drivers/puppeteer/generated/keyboard.d.ts +79 -0
  161. package/dist/drivers/puppeteer/generated/keyboard.js +89 -0
  162. package/dist/drivers/puppeteer/generated/locator.d.ts +141 -0
  163. package/dist/drivers/puppeteer/generated/locator.js +164 -0
  164. package/dist/drivers/puppeteer/generated/mouse.d.ts +74 -0
  165. package/dist/drivers/puppeteer/generated/mouse.js +94 -0
  166. package/dist/drivers/puppeteer/generated/page.d.ts +604 -0
  167. package/dist/drivers/puppeteer/generated/page.js +776 -0
  168. package/dist/drivers/puppeteer/generated/target.d.ts +105 -0
  169. package/dist/drivers/puppeteer/generated/target.js +123 -0
  170. package/dist/drivers/puppeteer/generated/touchscreen.d.ts +87 -0
  171. package/dist/drivers/puppeteer/generated/touchscreen.js +103 -0
  172. package/dist/drivers/puppeteer/generated/tracing.d.ts +38 -0
  173. package/dist/drivers/puppeteer/generated/tracing.js +43 -0
  174. package/dist/drivers/puppeteer/generated/web-worker.d.ts +63 -0
  175. package/dist/drivers/puppeteer/generated/web-worker.js +73 -0
  176. package/dist/drivers/puppeteer/index.d.ts +21 -0
  177. package/dist/drivers/puppeteer/index.js +23 -0
  178. package/dist/drivers/puppeteer/remote-base.d.ts +57 -0
  179. package/dist/drivers/puppeteer/remote-base.js +79 -0
  180. package/dist/drivers/puppeteer/types.d.ts +178 -0
  181. package/dist/drivers/puppeteer/types.js +8 -0
  182. package/dist/drivers/selenium/driver.d.ts +28 -0
  183. package/dist/drivers/selenium/driver.js +169 -0
  184. package/dist/drivers/selenium/element.d.ts +34 -0
  185. package/dist/drivers/selenium/element.js +73 -0
  186. package/dist/drivers/selenium/index.d.ts +3 -0
  187. package/dist/drivers/selenium/index.js +5 -0
  188. package/dist/drivers/selenium/types.d.ts +2 -0
  189. package/dist/drivers/selenium/types.js +12 -0
  190. package/dist/drivers/stagehand/generated/context.d.ts +127 -0
  191. package/dist/drivers/stagehand/generated/context.js +153 -0
  192. package/dist/drivers/stagehand/generated/locator.d.ts +324 -0
  193. package/dist/drivers/stagehand/generated/locator.js +368 -0
  194. package/dist/drivers/stagehand/generated/page.d.ts +377 -0
  195. package/dist/drivers/stagehand/generated/page.js +439 -0
  196. package/dist/drivers/stagehand/generated/response.d.ts +197 -0
  197. package/dist/drivers/stagehand/generated/response.js +232 -0
  198. package/dist/drivers/stagehand/index.d.ts +5 -0
  199. package/dist/drivers/stagehand/index.js +8 -0
  200. package/dist/drivers/stagehand/types.d.ts +1 -0
  201. package/dist/drivers/stagehand/types.js +7 -0
  202. package/dist/errors.d.ts +47 -0
  203. package/dist/errors.js +157 -0
  204. package/dist/extensions/client.d.ts +47 -0
  205. package/dist/extensions/client.js +154 -0
  206. package/dist/extensions/index.d.ts +1 -0
  207. package/dist/extensions/index.js +1 -0
  208. package/dist/index.d.ts +12 -0
  209. package/dist/index.js +23 -0
  210. package/dist/internal/dev-client.d.ts +5 -0
  211. package/dist/internal/dev-client.js +9 -0
  212. package/dist/internal/rpc-targets.d.ts +17 -0
  213. package/dist/internal/rpc-targets.js +58 -0
  214. package/dist/internal/serialization.d.ts +32 -0
  215. package/dist/internal/serialization.js +42 -0
  216. package/dist/internal/transport.d.ts +24 -0
  217. package/dist/internal/transport.js +29 -0
  218. package/dist/playwright.d.ts +1 -0
  219. package/dist/playwright.js +2 -0
  220. package/dist/puppeteer.d.ts +1 -0
  221. package/dist/puppeteer.js +2 -0
  222. package/dist/selenium.d.ts +1 -0
  223. package/dist/selenium.js +2 -0
  224. package/dist/stagehand.d.ts +1 -0
  225. package/dist/stagehand.js +2 -0
  226. package/dist/storage/client.d.ts +151 -0
  227. package/dist/storage/client.js +329 -0
  228. package/dist/storage/index.d.ts +2 -0
  229. package/dist/storage/index.js +4 -0
  230. package/dist/telemetry.d.ts +18 -0
  231. package/dist/telemetry.js +93 -0
  232. package/dist/updates/client.d.ts +8 -0
  233. package/dist/updates/client.js +128 -0
  234. package/dist/updates/index.d.ts +1 -0
  235. package/dist/updates/index.js +1 -0
  236. package/dist/utils/http.d.ts +39 -0
  237. package/dist/utils/http.js +88 -0
  238. package/dist/utils/index.d.ts +4 -0
  239. package/dist/utils/index.js +4 -0
  240. package/dist/utils/logger.d.ts +27 -0
  241. package/dist/utils/logger.js +74 -0
  242. package/dist/utils/schema.d.ts +17 -0
  243. package/dist/utils/schema.js +31 -0
  244. package/dist/utils/url.d.ts +5 -0
  245. package/dist/utils/url.js +7 -0
  246. package/dist/vault/client.d.ts +43 -0
  247. package/dist/vault/client.js +123 -0
  248. package/dist/vault/index.d.ts +1 -0
  249. package/dist/vault/index.js +1 -0
  250. package/dist/version.d.ts +1 -0
  251. package/dist/version.js +4 -0
  252. package/dist/workspaces/browser-runtime.d.ts +251 -0
  253. package/dist/workspaces/browser-runtime.js +1025 -0
  254. package/dist/workspaces/client.d.ts +48 -0
  255. package/dist/workspaces/client.js +222 -0
  256. package/dist/workspaces/index.d.ts +2 -0
  257. package/dist/workspaces/index.js +2 -0
  258. package/dist/workspaces/runtime-event-pump.d.ts +65 -0
  259. package/dist/workspaces/runtime-event-pump.js +716 -0
  260. package/package.json +56 -0
@@ -0,0 +1,83 @@
1
+ import type { RpcTarget } from '../internal/transport.js';
2
+ import type { BrowserDriver } from '../contracts/runtime.js';
3
+ import type { VaultSessionPolicy } from '../contracts/vault.js';
4
+ import type { SessionStoragePolicy } from '../contracts/storage.js';
5
+ /**
6
+ * RPC call to control-plane
7
+ * @param endpoint - Full URL of the endpoint
8
+ * @param body - Request body
9
+ * @param timeout - Optional timeout in milliseconds (default: DEFAULT_TIMEOUT_MS)
10
+ */
11
+ export declare function rpc<T>(endpoint: string, body: Record<string, unknown>, timeout?: number): Promise<T>;
12
+ /**
13
+ * Start an ephemeral browser session through the API gateway (no driver connected).
14
+ * @param baseUrl - Versioned API base URL of the gateway (e.g., 'http://localhost:8787/v1')
15
+ * @param options - Session start options
16
+ */
17
+ export declare function startSession(baseUrl: string, options?: {
18
+ apiKey?: string;
19
+ humanize?: boolean;
20
+ humanizePersonaId?: number;
21
+ proxy?: {
22
+ type: 'http' | 'socks5';
23
+ host: string;
24
+ port: number;
25
+ username?: string;
26
+ password?: string;
27
+ } | null;
28
+ storage?: SessionStoragePolicy;
29
+ solveCaptchas?: boolean;
30
+ vault?: VaultSessionPolicy;
31
+ }): Promise<{
32
+ id: string;
33
+ status: 'active' | 'stopped';
34
+ storageWorkspace?: string;
35
+ }>;
36
+ /**
37
+ * Connect a driver to an existing started session on the control-plane.
38
+ */
39
+ export declare function connectSessionDriver(baseUrl: string, sessionId: string, driver: BrowserDriver, apiKey?: string): Promise<{
40
+ id: string;
41
+ currentDriver: BrowserDriver;
42
+ defaultContextId?: string;
43
+ defaultPageId?: string;
44
+ storageWorkspace?: string;
45
+ }>;
46
+ /**
47
+ * Stop a session on the control-plane
48
+ * @param baseUrl - Versioned API base URL of the control-plane
49
+ * @param sessionId - Session ID to stop
50
+ * @param apiKey - Optional API key
51
+ */
52
+ export declare function stopSession(baseUrl: string, sessionId: string, apiKey?: string): Promise<void>;
53
+ /**
54
+ * Send RPC/EXECUTE command through the canonical automation endpoint.
55
+ * @param baseUrl - Versioned API base URL of the control-plane
56
+ * @param sessionId - Session ID
57
+ * @param command - RPC or EXECUTE command
58
+ * @param timeout - Optional timeout in milliseconds
59
+ */
60
+ type SendCommandInput = {
61
+ type: 'RPC';
62
+ correlationId?: string;
63
+ target: RpcTarget;
64
+ method: string;
65
+ args: unknown[];
66
+ contextId?: string;
67
+ pageId?: string;
68
+ handleId?: string;
69
+ } | {
70
+ type: 'EXECUTE';
71
+ correlationId?: string;
72
+ code: string;
73
+ args?: Record<string, unknown>;
74
+ pageId?: string;
75
+ options?: {
76
+ timeoutMs?: number;
77
+ logs?: 'off' | 'capture';
78
+ scriptId?: string;
79
+ scriptName?: string;
80
+ };
81
+ };
82
+ export declare function sendCommand<T>(baseUrl: string, sessionId: string, command: SendCommandInput, apiKey?: string, timeout?: number): Promise<T>;
83
+ export {};
@@ -0,0 +1,354 @@
1
+ // ============================================================================
2
+ // RPC Client - HTTP calls to control-plane
3
+ // ============================================================================
4
+ import { parseJsonResponse, fetchWithTimeout, DEFAULT_TIMEOUT_MS, LONG_TIMEOUT_MS, } from '../utils/http.js';
5
+ import { fromErrorResponse, AuthenticationError, SessionError, TimeoutError, } from '../errors.js';
6
+ import * as telemetry from '../telemetry.js';
7
+ import { SDK_VERSION } from '../version.js';
8
+ import { CONTEXT_REF_TARGETS, HANDLE_TARGETS, PAGE_REF_TARGETS, } from '../internal/rpc-targets.js';
9
+ /**
10
+ * Map an HTTP status code + response text to a typed BctrlError.
11
+ */
12
+ function httpStatusToError(status, text, fallbackMessage) {
13
+ if (status === 401 || status === 403)
14
+ return new AuthenticationError(`Authentication failed: ${text}`);
15
+ if (status === 404)
16
+ return new SessionError(`Not found: ${text}`, 'NOT_FOUND');
17
+ if (status === 504)
18
+ return new TimeoutError(`Gateway timeout: ${text}`);
19
+ if (status === 503)
20
+ return new SessionError(`Service unavailable: ${text}`, 'CONNECTION_ERROR');
21
+ return fromErrorResponse(fallbackMessage ?? `HTTP ${status}: ${text}`);
22
+ }
23
+ /**
24
+ * Extract timeout (ms) from an RPC method options argument if present.
25
+ * Many automation APIs use the last arg as an options object with `timeout`.
26
+ */
27
+ function getRpcOptionsTimeoutMs(args) {
28
+ if (!Array.isArray(args) || args.length === 0)
29
+ return undefined;
30
+ const lastArg = args[args.length - 1];
31
+ if (!lastArg || typeof lastArg !== 'object' || Array.isArray(lastArg))
32
+ return undefined;
33
+ const timeoutRaw = lastArg.timeout;
34
+ if (typeof timeoutRaw !== 'number' || !Number.isFinite(timeoutRaw) || timeoutRaw <= 0) {
35
+ return undefined;
36
+ }
37
+ return Math.floor(timeoutRaw);
38
+ }
39
+ /**
40
+ * Methods that are expected to wait on browser state and may run longer than 30s.
41
+ */
42
+ function isLongRunningRpcMethod(method) {
43
+ return (method.startsWith('wait') ||
44
+ method === 'goto' ||
45
+ method === 'reload' ||
46
+ method === 'setContent');
47
+ }
48
+ const AGENT_RPC_TIMEOUT_MS = 5 * 60 * 1000;
49
+ function isLongRunningAgentRpc(target, method) {
50
+ if (target === 'browserUse') {
51
+ return method === 'agent.execute' || method === 'codeAgent.execute';
52
+ }
53
+ if (target === 'stagehand') {
54
+ return method === 'agent.execute';
55
+ }
56
+ return false;
57
+ }
58
+ function trimTrailingUndefined(args) {
59
+ if (!Array.isArray(args))
60
+ return args;
61
+ let end = args.length;
62
+ while (end > 0 && args[end - 1] === undefined) {
63
+ end -= 1;
64
+ }
65
+ return end === args.length ? args : args.slice(0, end);
66
+ }
67
+ function parseAutomationEnvelope(text) {
68
+ if (!text)
69
+ return null;
70
+ try {
71
+ const parsed = JSON.parse(text);
72
+ return parsed && typeof parsed === 'object' ? parsed : null;
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ function buildAutomationError(error, fallbackMessage) {
79
+ const message = error?.message || fallbackMessage;
80
+ const hint = error?.hint;
81
+ const diagnostic = error?.diagnostic;
82
+ const context = {};
83
+ if (hint)
84
+ context.hint = hint;
85
+ if (diagnostic)
86
+ context.diagnostic = diagnostic;
87
+ return fromErrorResponse(hint ? `${message} (${hint})` : message, error?.code, Object.keys(context).length > 0 ? context : undefined);
88
+ }
89
+ /**
90
+ * RPC call to control-plane
91
+ * @param endpoint - Full URL of the endpoint
92
+ * @param body - Request body
93
+ * @param timeout - Optional timeout in milliseconds (default: DEFAULT_TIMEOUT_MS)
94
+ */
95
+ export async function rpc(endpoint, body, timeout) {
96
+ const response = await fetchWithTimeout(endpoint, {
97
+ method: 'POST',
98
+ headers: {
99
+ 'Content-Type': 'application/json',
100
+ 'x-sdk-version': SDK_VERSION,
101
+ },
102
+ body: JSON.stringify(body),
103
+ }, timeout ?? DEFAULT_TIMEOUT_MS);
104
+ // Read request ID from response for error context
105
+ const requestId = response.headers.get('x-request-id') ?? undefined;
106
+ if (!response.ok) {
107
+ const text = await response.text();
108
+ const err = httpStatusToError(response.status, text);
109
+ telemetry.captureError(err, {
110
+ endpoint,
111
+ method: 'POST',
112
+ statusCode: response.status,
113
+ errorCode: err.code,
114
+ requestId,
115
+ });
116
+ throw err;
117
+ }
118
+ const data = await parseJsonResponse(response, `RPC ${endpoint}`);
119
+ if (data.status === 'error') {
120
+ const err = fromErrorResponse(data.error || 'Unknown error', data.errorCode, data.errorContext);
121
+ telemetry.captureError(err, {
122
+ endpoint,
123
+ method: 'POST',
124
+ statusCode: response.status,
125
+ errorCode: data.errorCode,
126
+ requestId,
127
+ });
128
+ throw err;
129
+ }
130
+ return data.result;
131
+ }
132
+ /**
133
+ * Start an ephemeral browser session through the API gateway (no driver connected).
134
+ * @param baseUrl - Versioned API base URL of the gateway (e.g., 'http://localhost:8787/v1')
135
+ * @param options - Session start options
136
+ */
137
+ export async function startSession(baseUrl, options = {}) {
138
+ const headers = {
139
+ 'Content-Type': 'application/json',
140
+ 'x-sdk-version': SDK_VERSION,
141
+ };
142
+ if (options.apiKey) {
143
+ headers['Authorization'] = `Bearer ${options.apiKey}`;
144
+ }
145
+ const response = await fetchWithTimeout(`${baseUrl}/sessions`, {
146
+ method: 'POST',
147
+ headers,
148
+ body: JSON.stringify({
149
+ humanize: options.humanize,
150
+ humanizePersonaId: options.humanizePersonaId,
151
+ proxy: options.proxy,
152
+ storage: options.storage,
153
+ solveCaptchas: options.solveCaptchas,
154
+ vault: options.vault,
155
+ }),
156
+ });
157
+ if (!response.ok) {
158
+ const text = await response.text();
159
+ const requestId = response.headers.get('x-request-id') ?? undefined;
160
+ const err = httpStatusToError(response.status, text, `Failed to start session: ${text}`);
161
+ telemetry.captureError(err, {
162
+ endpoint: `${baseUrl}/sessions`,
163
+ method: 'POST',
164
+ statusCode: response.status,
165
+ errorCode: err.code,
166
+ requestId,
167
+ });
168
+ throw err;
169
+ }
170
+ const data = await parseJsonResponse(response, 'Start session');
171
+ return {
172
+ id: data.id,
173
+ status: data.status,
174
+ storageWorkspace: data.storageWorkspace,
175
+ };
176
+ }
177
+ /**
178
+ * Connect a driver to an existing started session on the control-plane.
179
+ */
180
+ export async function connectSessionDriver(baseUrl, sessionId, driver, apiKey) {
181
+ const headers = {
182
+ 'Content-Type': 'application/json',
183
+ 'x-sdk-version': SDK_VERSION,
184
+ };
185
+ if (apiKey) {
186
+ headers['Authorization'] = `Bearer ${apiKey}`;
187
+ }
188
+ const response = await fetchWithTimeout(`${baseUrl}/sessions/${sessionId}/connect`, {
189
+ method: 'POST',
190
+ headers,
191
+ body: JSON.stringify({ driver }),
192
+ });
193
+ if (!response.ok) {
194
+ const text = await response.text();
195
+ const requestId = response.headers.get('x-request-id') ?? undefined;
196
+ const err = httpStatusToError(response.status, text, `Failed to connect session driver: ${text}`);
197
+ telemetry.captureError(err, {
198
+ endpoint: `${baseUrl}/sessions/${sessionId}/connect`,
199
+ method: 'POST',
200
+ statusCode: response.status,
201
+ errorCode: err.code,
202
+ requestId,
203
+ });
204
+ throw err;
205
+ }
206
+ return parseJsonResponse(response, 'Connect session driver');
207
+ }
208
+ /**
209
+ * Stop a session on the control-plane
210
+ * @param baseUrl - Versioned API base URL of the control-plane
211
+ * @param sessionId - Session ID to stop
212
+ * @param apiKey - Optional API key
213
+ */
214
+ export async function stopSession(baseUrl, sessionId, apiKey) {
215
+ const headers = {
216
+ 'Content-Type': 'application/json',
217
+ 'x-sdk-version': SDK_VERSION,
218
+ };
219
+ if (apiKey) {
220
+ headers['Authorization'] = `Bearer ${apiKey}`;
221
+ }
222
+ const response = await fetchWithTimeout(`${baseUrl}/sessions/${sessionId}/stop`, {
223
+ method: 'POST',
224
+ headers,
225
+ body: JSON.stringify({}),
226
+ });
227
+ if (!response.ok) {
228
+ const text = await response.text();
229
+ const requestId = response.headers.get('x-request-id') ?? undefined;
230
+ const err = httpStatusToError(response.status, text, `Failed to stop session: ${text}`);
231
+ telemetry.captureError(err, {
232
+ endpoint: `${baseUrl}/sessions/${sessionId}/stop`,
233
+ method: 'POST',
234
+ statusCode: response.status,
235
+ errorCode: err.code,
236
+ requestId,
237
+ });
238
+ throw err;
239
+ }
240
+ }
241
+ async function sendCommandInternal(baseUrl, sessionId, command, apiKey, timeout) {
242
+ const executeTimeoutMs = command.type === 'EXECUTE' &&
243
+ typeof command.options?.timeoutMs === 'number' &&
244
+ Number.isFinite(command.options.timeoutMs) &&
245
+ command.options.timeoutMs > 0
246
+ ? Math.floor(command.options.timeoutMs)
247
+ : undefined;
248
+ const rpcOptionsTimeoutMs = command.type === 'RPC'
249
+ ? getRpcOptionsTimeoutMs(command.args)
250
+ : undefined;
251
+ const rpcTimeoutHint = command.type === 'RPC'
252
+ ? rpcOptionsTimeoutMs !== undefined
253
+ ? Math.max(DEFAULT_TIMEOUT_MS, rpcOptionsTimeoutMs + 5000)
254
+ : isLongRunningRpcMethod(command.method)
255
+ ? LONG_TIMEOUT_MS
256
+ : undefined
257
+ : undefined;
258
+ const aiRpcTimeoutHint = command.type === 'RPC' &&
259
+ 'target' in command &&
260
+ (command.target === 'stagehand' || command.target === 'browserUse') &&
261
+ rpcOptionsTimeoutMs !== undefined
262
+ ? Math.max(isLongRunningAgentRpc(command.target, command.method) ? AGENT_RPC_TIMEOUT_MS : LONG_TIMEOUT_MS, rpcOptionsTimeoutMs + 5000)
263
+ : undefined;
264
+ // Use longer timeout for potentially slow AI operations (stagehand, browserUse, execute)
265
+ const defaultTimeout = command.type === 'EXECUTE' ||
266
+ ('target' in command && (command.target === 'stagehand' || command.target === 'browserUse'))
267
+ ? command.type === 'EXECUTE' && executeTimeoutMs !== undefined
268
+ ? Math.max(LONG_TIMEOUT_MS, executeTimeoutMs + 5000)
269
+ : (aiRpcTimeoutHint ??
270
+ ('target' in command && isLongRunningAgentRpc(command.target, command.method)
271
+ ? AGENT_RPC_TIMEOUT_MS
272
+ : LONG_TIMEOUT_MS))
273
+ : (rpcTimeoutHint ?? DEFAULT_TIMEOUT_MS);
274
+ let call;
275
+ let ref;
276
+ let args;
277
+ let options;
278
+ if (command.type === 'RPC') {
279
+ call = `${command.target}.${command.method}`;
280
+ args = trimTrailingUndefined(command.args);
281
+ if (HANDLE_TARGETS.has(command.target)) {
282
+ ref = command.handleId;
283
+ }
284
+ else if (CONTEXT_REF_TARGETS.has(command.target)) {
285
+ ref = command.contextId;
286
+ }
287
+ else if (PAGE_REF_TARGETS.has(command.target)) {
288
+ ref = command.pageId;
289
+ }
290
+ if (rpcOptionsTimeoutMs !== undefined) {
291
+ options = { timeoutMs: rpcOptionsTimeoutMs };
292
+ }
293
+ }
294
+ else {
295
+ call = 'execute';
296
+ args = [command.code];
297
+ if (command.args !== undefined) {
298
+ args.push(command.args);
299
+ }
300
+ ref = command.pageId;
301
+ options = command.options;
302
+ }
303
+ const endpoint = `${baseUrl}/sessions/${encodeURIComponent(sessionId)}/automation`;
304
+ const response = await fetchWithTimeout(endpoint, {
305
+ method: 'POST',
306
+ headers: {
307
+ 'Content-Type': 'application/json',
308
+ 'x-sdk-version': SDK_VERSION,
309
+ ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
310
+ },
311
+ body: JSON.stringify({
312
+ call,
313
+ ...(ref ? { ref } : {}),
314
+ ...(args ? { args } : {}),
315
+ ...(options ? { options } : {}),
316
+ }),
317
+ }, timeout ?? defaultTimeout);
318
+ const requestId = response.headers.get('x-request-id') ?? undefined;
319
+ if (!response.ok) {
320
+ const text = await response.text();
321
+ const parsed = parseAutomationEnvelope(text);
322
+ const err = parsed && parsed.ok === false
323
+ ? buildAutomationError(parsed.error, text || `Automation ${call} failed`)
324
+ : httpStatusToError(response.status, text);
325
+ const telemetryErrorCode = parsed?.error?.code ||
326
+ err.code;
327
+ telemetry.captureError(err, {
328
+ endpoint,
329
+ method: 'POST',
330
+ statusCode: response.status,
331
+ errorCode: telemetryErrorCode,
332
+ commandType: command.type,
333
+ requestId,
334
+ });
335
+ throw err;
336
+ }
337
+ const data = await parseJsonResponse(response, `Automation ${call}`);
338
+ if (data.ok !== true) {
339
+ const err = buildAutomationError(data.error, 'Unknown error');
340
+ telemetry.captureError(err, {
341
+ endpoint,
342
+ method: 'POST',
343
+ statusCode: response.status,
344
+ errorCode: data.error?.code,
345
+ commandType: command.type,
346
+ requestId,
347
+ });
348
+ throw err;
349
+ }
350
+ return data.result;
351
+ }
352
+ export async function sendCommand(baseUrl, sessionId, command, apiKey, timeout) {
353
+ return sendCommandInternal(baseUrl, sessionId, command, apiKey, timeout);
354
+ }
@@ -0,0 +1,5 @@
1
+ export declare const BCTRL_PRODUCTION_ORIGIN = "https://api.bctrl.ai";
2
+ export declare const BCTRL_DEVELOPMENT_ORIGIN = "http://localhost:8787";
3
+ export declare function resolveProductionApiBaseUrl(): string;
4
+ export declare function resolveInternalApiBaseUrl(originOrApiBase?: string): string;
5
+ export declare function resolveApiKey(apiKey: string): string;
package/dist/config.js ADDED
@@ -0,0 +1,28 @@
1
+ import { PUBLIC_API_PREFIX } from './contracts/version.js';
2
+ import { stripTrailingSlash } from './utils/url.js';
3
+ export const BCTRL_PRODUCTION_ORIGIN = 'https://api.bctrl.ai';
4
+ export const BCTRL_DEVELOPMENT_ORIGIN = 'http://localhost:8787';
5
+ function toApiBaseUrl(originOrApiBase) {
6
+ const normalized = stripTrailingSlash(originOrApiBase);
7
+ return normalized.endsWith(PUBLIC_API_PREFIX)
8
+ ? normalized
9
+ : `${normalized}${PUBLIC_API_PREFIX}`;
10
+ }
11
+ export function resolveProductionApiBaseUrl() {
12
+ return toApiBaseUrl(BCTRL_PRODUCTION_ORIGIN);
13
+ }
14
+ export function resolveInternalApiBaseUrl(originOrApiBase) {
15
+ if (originOrApiBase === undefined) {
16
+ return toApiBaseUrl(BCTRL_DEVELOPMENT_ORIGIN);
17
+ }
18
+ if (typeof originOrApiBase !== 'string' || originOrApiBase.trim() === '') {
19
+ throw new Error('Internal Bctrl apiOrigin must be a non-empty string when provided');
20
+ }
21
+ return toApiBaseUrl(originOrApiBase.trim());
22
+ }
23
+ export function resolveApiKey(apiKey) {
24
+ if (typeof apiKey !== 'string' || apiKey.trim() === '') {
25
+ throw new Error('Bctrl apiKey is required');
26
+ }
27
+ return apiKey.trim();
28
+ }
@@ -0,0 +1,2 @@
1
+ import type { BrowserDriver } from '../contracts/runtime.js';
2
+ export declare const DEFAULT_BROWSER_DRIVER: BrowserDriver;
@@ -0,0 +1 @@
1
+ export const DEFAULT_BROWSER_DRIVER = 'playwright';
@@ -0,0 +1,45 @@
1
+ import { z } from 'zod';
2
+ export declare const AgentStorageToolConfigSchema: z.ZodObject<{
3
+ enabled: z.ZodOptional<z.ZodBoolean>;
4
+ prefix: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodString>>>;
5
+ inputFiles: z.ZodOptional<z.ZodArray<z.ZodString>>;
6
+ }, z.core.$strict>;
7
+ export type AgentStorageToolConfig = z.infer<typeof AgentStorageToolConfigSchema>;
8
+ export declare const AgentVaultToolConfigSchema: z.ZodObject<{
9
+ toolPrefix: z.ZodOptional<z.ZodString>;
10
+ defaultListFilter: z.ZodOptional<z.ZodObject<{
11
+ prefix: z.ZodOptional<z.ZodString>;
12
+ origin: z.ZodOptional<z.ZodString>;
13
+ limit: z.ZodOptional<z.ZodNumber>;
14
+ }, z.core.$strip>>;
15
+ allowRawReads: z.ZodOptional<z.ZodBoolean>;
16
+ enabled: z.ZodOptional<z.ZodBoolean>;
17
+ }, z.core.$strict>;
18
+ export type AgentVaultToolConfig = z.infer<typeof AgentVaultToolConfigSchema>;
19
+ export declare const AgentCaptchaToolConfigSchema: z.ZodObject<{
20
+ enabled: z.ZodOptional<z.ZodBoolean>;
21
+ pageId: z.ZodOptional<z.ZodUUID>;
22
+ }, z.core.$strict>;
23
+ export type AgentCaptchaToolConfig = z.infer<typeof AgentCaptchaToolConfigSchema>;
24
+ export declare const AgentInvocationToolsSchema: z.ZodObject<{
25
+ storage: z.ZodOptional<z.ZodObject<{
26
+ enabled: z.ZodOptional<z.ZodBoolean>;
27
+ prefix: z.ZodOptional<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodOptional<z.ZodString>>>;
28
+ inputFiles: z.ZodOptional<z.ZodArray<z.ZodString>>;
29
+ }, z.core.$strict>>;
30
+ vault: z.ZodOptional<z.ZodObject<{
31
+ toolPrefix: z.ZodOptional<z.ZodString>;
32
+ defaultListFilter: z.ZodOptional<z.ZodObject<{
33
+ prefix: z.ZodOptional<z.ZodString>;
34
+ origin: z.ZodOptional<z.ZodString>;
35
+ limit: z.ZodOptional<z.ZodNumber>;
36
+ }, z.core.$strip>>;
37
+ allowRawReads: z.ZodOptional<z.ZodBoolean>;
38
+ enabled: z.ZodOptional<z.ZodBoolean>;
39
+ }, z.core.$strict>>;
40
+ captcha: z.ZodOptional<z.ZodObject<{
41
+ enabled: z.ZodOptional<z.ZodBoolean>;
42
+ pageId: z.ZodOptional<z.ZodUUID>;
43
+ }, z.core.$strict>>;
44
+ }, z.core.$strict>;
45
+ export type AgentInvocationTools = z.infer<typeof AgentInvocationToolsSchema>;
@@ -0,0 +1,31 @@
1
+ import { z } from 'zod';
2
+ import { VaultAgentAdapterConfigSchema } from './vault.js';
3
+ const OptionalTrimmedStringSchema = z.preprocess((value) => {
4
+ if (typeof value !== 'string')
5
+ return value;
6
+ const trimmed = value.trim();
7
+ return trimmed.length > 0 ? trimmed : undefined;
8
+ }, z.string().optional());
9
+ export const AgentStorageToolConfigSchema = z
10
+ .object({
11
+ enabled: z.boolean().optional(),
12
+ prefix: OptionalTrimmedStringSchema.optional(),
13
+ inputFiles: z.array(z.string().min(1)).optional(),
14
+ })
15
+ .strict();
16
+ export const AgentVaultToolConfigSchema = VaultAgentAdapterConfigSchema.extend({
17
+ enabled: z.boolean().optional(),
18
+ }).strict();
19
+ export const AgentCaptchaToolConfigSchema = z
20
+ .object({
21
+ enabled: z.boolean().optional(),
22
+ pageId: z.uuid().optional(),
23
+ })
24
+ .strict();
25
+ export const AgentInvocationToolsSchema = z
26
+ .object({
27
+ storage: AgentStorageToolConfigSchema.optional(),
28
+ vault: AgentVaultToolConfigSchema.optional(),
29
+ captcha: AgentCaptchaToolConfigSchema.optional(),
30
+ })
31
+ .strict();