@agentmatrix.pro/browser-sdk 0.1.0-rc.1 → 0.1.0-rc.2

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.0-rc.2
4
+
5
+ _Release prepared 2026-10-30 for the official npm `next` channel._
6
+
7
+ Requires Platform `0.160.0`. The matching API contract is deployed in AgentMatrix
8
+ `release-2026-10-30.3`; Guest/profile/Worker enablement and real takeover
9
+ qualification remain pending. This package stays a prerelease.
10
+
11
+ - Support backend owner-bound API keys for get/acquire/release without UserJWT or CSRF (Platform 0.160.0).
12
+ - Add one-use `BrowserViewer.takeAccess()` and `createBrowserViewer()` for authenticated backend-to-frontend capability transfer; keep API keys off the frontend.
13
+ - Preserve Workspace authentication, single-attempt transport, explicit handback, and unknown-result readback.
14
+
3
15
  ## 0.1.0-rc.1
4
16
 
5
17
  First AgentMatrix browser SDK prerelease, prepared for the official npm `next`
package/README.md CHANGED
@@ -1,77 +1,136 @@
1
1
  # AgentMatrix browser control
2
2
 
3
- Human-authorized control of an existing Agent browser. The `0.1.0-rc.1`
4
- prerelease targets the `next` channel for integration work:
3
+ Owner-authorized control of an existing Agent browser. Applications can use an
4
+ owner-bound data-plane API key on their backend; users do not need a separate
5
+ AgentMatrix login. Existing Workspace JWT + selected key ID + CSRF calls remain
6
+ supported.
7
+
8
+ This source targets **Platform 0.160.0**. The API-key path and capability transfer
9
+ are introduced in `@agentmatrix.pro/browser-sdk@0.1.0-rc.2`; the earlier
10
+ `0.1.0-rc.1` does not include them. Install that exact prerelease for integration:
5
11
 
6
12
  ```bash
7
- npm install @agentmatrix.pro/browser-sdk@0.1.0-rc.1
13
+ npm install @agentmatrix.pro/browser-sdk@0.1.0-rc.2
8
14
  ```
9
15
 
10
- It requires Platform `0.159.1` with browser control enabled and the calling
11
- Workspace origin explicitly allowed by its Preview owner. Real Identity/Guest
12
- enablement qualification remains pending; installing this package does not
13
- enable browser control on the server.
16
+ The deployment must enable browser control and approve the frontend's exact
17
+ parent origin in both Guest and Preview configuration. Installing the SDK does
18
+ not enable the server feature or exit Q0. This remains a prerelease while real
19
+ Identity/Guest enablement qualification is pending.
20
+
21
+ ## Backend with an API key
14
22
 
15
- This package uses the current signed-in user's JWT, selected tenant/namespace and
16
- owned API-key **ID**, plus the Gateway's existing CSRF cookie/header pair. It does
17
- not accept an API key as human authorization, sign users in, refresh credentials,
18
- create browsers or establish cross-origin cookie/CORS policy.
23
+ Keep the key on your server. It must belong to the Session owner, include
24
+ `session.full`, and permit the selected namespace. Tenant and owner are derived
25
+ from the verified key; do not supply a JWT, tenant ID, key ID or CSRF token.
19
26
 
20
27
  ```ts
21
28
  import { BrowserControlClient } from "@agentmatrix.pro/browser-sdk";
22
29
 
23
30
  const control = new BrowserControlClient({ baseURL: gatewayOrigin });
24
- // Take a fresh snapshot from your application's authenticated user/scope owner.
25
- const context = { userJWT, tenantId, namespaceId, apiKeyId, sessionId, csrfToken };
31
+ const context = { apiKey: serverSecret, sessionId, namespaceId: "default" };
26
32
  const current = await control.get(context);
33
+ // In your endpoint, authorize the application's own user for this Session first.
34
+ // Only continue for an explicit takeover action. Persist/reuse its operation ID.
27
35
  if (current.data.allowed_actions.includes("acquire") && current.data.control_id) {
28
36
  const result = await control.acquire(context, {
29
- operation_id: crypto.randomUUID(), // one new explicit user action
37
+ operation_id: operationId,
30
38
  expected_control_id: current.data.control_id,
31
39
  expected_revision: current.data.revision,
32
40
  });
33
- if (result.viewer) {
34
- result.viewer.attach(iframe);
35
- // Keep this handle in memory. Its deadline is result.viewer.expiresAt.
36
- }
41
+ const response = {
42
+ data: result.data,
43
+ viewer_access: result.viewer?.takeAccess(),
44
+ };
45
+ // Return response only to that authenticated user over HTTPS, Cache-Control: no-store.
46
+ // It contains a short-lived secret: never log, cache or persist it.
37
47
  }
38
48
  ```
39
49
 
40
- `get`, `acquire` and `release` make one HTTP attempt each. They do not retry,
41
- refresh authentication, generate IDs or poll. Read defaults to a 15-second total
42
- deadline; mutations default to 200 seconds to cover the server's drain budget.
43
- Per-call `{ signal, timeoutMs }` bounds headers and the complete response body.
44
- An injected `fetch` must also make one attempt without hidden refresh/retry.
45
-
46
- On explicit handback, first call `viewer.stopInput()`. Read a fresh status, then
47
- call `release(context, { operation_id, expected_control_id, expected_revision,
48
- lease_id })` using that observation. Retain the iframe while the response is
49
- 202 or state remains revoking: it must receive the Guest's real clear challenge.
50
- After confirmed Agent handback, call `viewer.dispose()`. When allowed actions
51
- contain `release`, offer an explicit **Continue handback** action using the latest
52
- observation and a new user intent. Do not automatically change IDs or resend.
53
-
54
- `BrowserControlError` contains only a code, optional HTTP status and bounded
55
- reason. A lost/aborted/timed-out response after dispatch has `replyUnproven: true`;
56
- read status before offering another action. A known refusal does not clear any
57
- earlier responsibility. Neither HTTP 202, expiry, iframe closure nor native
58
- browser closure proves handback. Replay responses never reconstruct a viewer.
59
-
60
- `BrowserViewer` is a TypeScript interface for a returned handle, not a runtime
61
- constructor. Obtain it from a fresh `acquire` response; do not use `new` or
62
- `instanceof`. Calling `stopInput()` before attachment permanently prevents that
63
- handle from attaching.
64
-
65
- The viewer helper permits the embedded page's forms, validates both message
66
- source and exact origin, and burns its token after one delivery. Expiry stops
67
- input and hides the frame while leaving its cleanup connection alive. Call
68
- `stopInput()` on stale/unknown status and before handback. On user/tenant/Session
69
- changes, cancel outstanding calls, discard late replies, and dispose the old
70
- viewer; the server retains any unresolved responsibility. Never log tokens,
71
- Preview URLs, page data or form input; do not store a viewer in persistent state.
72
- Grant serialization/Node inspection is redacted, but application memory and the
73
- authorized iframe are intentionally within the trusted user's boundary.
74
-
75
- Ordinary API-key users can only query status through
76
- `AgentMatrix.sessions.browserControl.get(sessionId)` in the data-plane package.
77
- No API-key method acquires human control.
50
+ Omitting `namespaceId` uses the deployment's ordinary API-key default namespace.
51
+ The SDK sends only Bearer authentication, the contract version and the optional
52
+ namespace, with `credentials: omit`. It never exchanges the key for a user JWT.
53
+ A key authorizes its owner, not arbitrary users of your application: your backend
54
+ must enforce its own Session access checks before returning a viewer capability.
55
+
56
+ ## Frontend with the transferred capability
57
+
58
+ ```ts
59
+ import { createBrowserViewer } from "@agentmatrix.pro/browser-sdk";
60
+
61
+ // Received from your authenticated backend; never contains the API key.
62
+ const viewer = createBrowserViewer(response.viewer_access);
63
+ viewer.attach(iframe); // once, on a deployment-approved parent origin
64
+ // Keep viewer and the original control_id in memory for handback.
65
+ ```
66
+
67
+ `takeAccess()` consumes an unused handle once and returns `{ url, token,
68
+ expires_at }`. The returned object intentionally contains secrets; ordinary
69
+ handle serialization and Node inspection remain redacted. After transfer, the
70
+ original handle can neither attach nor export again. `createBrowserViewer`
71
+ validates and copies that capability; it does not mint, renew, reacquire or prove
72
+ server authorization. Do not duplicate it for multiple clients or put it in a
73
+ URL, log, localStorage, sessionStorage or persistent application state.
74
+
75
+ The helper binds both message source and exact viewer origin, delivers the token
76
+ once, and keeps it out of the iframe URL. The Preview URL itself is sensitive.
77
+ Grant expiry stops input and hides the frame while leaving the cleanup connection
78
+ alive. Use `viewer.expiresAt`, together with the latest lease, for local input
79
+ expiry. On unknown/stale state, also call `stopInput()`.
80
+
81
+ ## Existing Workspace authentication
82
+
83
+ Workspace applications can continue to call the same client directly with their
84
+ current authenticated user/scope context:
85
+
86
+ ```ts
87
+ const context = { userJWT, tenantId, namespaceId, apiKeyId, sessionId, csrfToken };
88
+ const current = await control.get(context);
89
+ // acquire/release use the same intent fields as the backend API-key example.
90
+ ```
91
+
92
+ This selects the Workspace routes with `credentials: include`. The key **ID** is
93
+ not a key secret; mutations require the existing matching CSRF cookie/header.
94
+ The SDK does not sign users in, refresh credentials, select tenants/keys, create
95
+ browsers or configure CORS/cookies. Mixing API-key and JWT context fields is
96
+ rejected before transport.
97
+
98
+ ## Handback and failed replies
99
+
100
+ On explicit handback, first call `viewer.stopInput()` on the frontend. Keep the
101
+ iframe mounted. Your backend reads a fresh status for the **original control_id**
102
+ and calls `release(context, { operation_id, expected_control_id,
103
+ expected_revision, lease_id })` using that observation. If the control changed,
104
+ discard the old intent rather than switching it to another browser.
105
+
106
+ A `202` or `revoking` state retains responsibility: the iframe must receive the
107
+ Guest's real clear challenge. After confirmed Agent handback, call
108
+ `viewer.dispose()`. When `allowed_actions` includes `release`, offer an explicit
109
+ **Continue handback** action using a fresh observation and a new user intent.
110
+ Do not automatically change operation IDs or resend mutations. A replay never
111
+ reconstructs a viewer; `takeAccess()` cannot recover a lost response.
112
+
113
+ Each `get`, `acquire` or `release` makes one HTTP attempt, with no implicit retry,
114
+ authentication refresh, polling or generated operation ID. Defaults are a
115
+ 15-second read and 200-second mutation total deadline; per-call
116
+ `{ signal, timeoutMs }` includes headers and the complete body. An injected
117
+ `fetch` must also avoid hidden retries. A proxy in your application must allow
118
+ this mutation budget.
119
+
120
+ `BrowserControlError` exposes only a bounded code, optional status and reason.
121
+ After dispatch, a lost, timed-out or cancelled reply has `replyUnproven: true`:
122
+ read state before offering another action. A refusal cannot clear earlier debt.
123
+ The legacy reason `browser_control_human_required` also covers insufficient
124
+ API-key owner/scope/current authority; it does not require an API-key caller to log in.
125
+ HTTP 202, expiry, iframe closure and native browser closure do not prove handback.
126
+
127
+ `BrowserViewer` is a TypeScript interface, with no runtime constructor or
128
+ `instanceof` value. `stopInput()` before attachment permanently prevents that
129
+ handle from attaching or transferring. `dispose()` is local teardown, not server
130
+ cleanup proof. On user, tenant or Session changes, cancel calls, discard late
131
+ replies and dispose the old viewer; the server retains unresolved responsibility.
132
+
133
+ The root data-plane SDK still provides the convenient read-only
134
+ `AgentMatrix.sessions.browserControl.get(sessionId)`. Use this separate browser package
135
+ for API-key or Workspace control and iframe handling; Tenant Management grants
136
+ no browser control.
package/dist/index.d.ts CHANGED
@@ -123,6 +123,8 @@ type components = {
123
123
  };
124
124
  };
125
125
  parameters: {
126
+ /** @example ssn_01HX... */
127
+ SessionId: string;
126
128
  /** @description Tenant selected in the User Dashboard resource URL. Identity verifies that the authenticated user has an active membership in this tenant before forwarding to canonical data-plane APIs. */
127
129
  WorkspaceTenantId: string;
128
130
  /** @example default */
@@ -145,6 +147,10 @@ type components = {
145
147
  pathItems: never;
146
148
  };
147
149
 
150
+ /** Sensitive short-lived capability. Deliver only to your authenticated frontend; never log or store it. */
151
+ type BrowserViewerAccess = components["schemas"]["BrowserViewerAccess"];
152
+ /** Import a capability delivered by your own trusted backend, without exposing its API key. */
153
+ declare function createBrowserViewer(access: BrowserViewerAccess): BrowserViewer;
148
154
  /** Structural DOM types keep Node clients importable without a DOM global or shim. */
149
155
  interface BrowserViewerMessage {
150
156
  source: unknown;
@@ -173,6 +179,8 @@ interface BrowserViewerFrame {
173
179
  /** Acquired handle only; no public constructor or runtime BrowserViewer export. */
174
180
  interface BrowserViewer {
175
181
  readonly expiresAt: string;
182
+ /** Consume once for an authenticated backend-to-frontend response. The returned value contains secrets. */
183
+ takeAccess(): BrowserViewerAccess;
176
184
  /** Attach once, before the iframe loads. */
177
185
  attach(frame: BrowserViewerFrame): void;
178
186
  /** Stop local input while retaining the iframe for the Guest's actual clear ACK. */
@@ -201,6 +209,17 @@ interface BrowserControlMutationContext extends BrowserControlContext {
201
209
  /** Must match the browser's ariadra_csrf_token cookie on the Gateway origin. */
202
210
  csrfToken: string;
203
211
  }
212
+ /** Server-side API-key context. Never pass this credential to a user browser. */
213
+ interface BrowserControlAPIKeyContext {
214
+ apiKey: string;
215
+ sessionId: string;
216
+ /** Omission uses the key's default namespace routing. */
217
+ namespaceId?: string;
218
+ userJWT?: never;
219
+ tenantId?: never;
220
+ apiKeyId?: never;
221
+ csrfToken?: never;
222
+ }
204
223
  interface BrowserControlRequestOptions {
205
224
  signal?: AbortSignal;
206
225
  /** Total budget including the complete response body. Defaults to 15s read / 200s mutation. */
@@ -223,13 +242,13 @@ interface BrowserControlClientOptions {
223
242
  fetch?: typeof globalThis.fetch;
224
243
  }
225
244
 
226
- /** Thin user-authorized client. No cached context, automatic reads, retries, grants or operation IDs. */
245
+ /** Owner-authorized client. No cached context, automatic reads, retries, grants or operation IDs. */
227
246
  declare class BrowserControlClient {
228
247
  #private;
229
248
  constructor(options: BrowserControlClientOptions);
230
- get(context: BrowserControlContext, options?: BrowserControlRequestOptions): Promise<BrowserControlResult>;
231
- acquire(context: BrowserControlMutationContext, intent: AcquireBrowserControlRequest, options?: BrowserControlRequestOptions): Promise<BrowserControlAcquisition>;
232
- release(context: BrowserControlMutationContext, intent: ReleaseBrowserControlRequest, options?: BrowserControlRequestOptions): Promise<BrowserControlResult>;
249
+ get(context: BrowserControlContext | BrowserControlAPIKeyContext, options?: BrowserControlRequestOptions): Promise<BrowserControlResult>;
250
+ acquire(context: BrowserControlMutationContext | BrowserControlAPIKeyContext, intent: AcquireBrowserControlRequest, options?: BrowserControlRequestOptions): Promise<BrowserControlAcquisition>;
251
+ release(context: BrowserControlMutationContext | BrowserControlAPIKeyContext, intent: ReleaseBrowserControlRequest, options?: BrowserControlRequestOptions): Promise<BrowserControlResult>;
233
252
  }
234
253
 
235
254
  type BrowserControlFailure = "invalid_input" | "aborted" | "timeout" | "transport_unproven" | "response_unproven" | "refused";
@@ -246,8 +265,8 @@ declare class BrowserControlError extends Error {
246
265
  constructor(code: BrowserControlFailure, replyUnproven: boolean, status?: number | undefined, reason?: BrowserControlErrorReason | undefined);
247
266
  }
248
267
 
249
- declare const CONTRACT_VERSION = "0.159.1";
268
+ declare const CONTRACT_VERSION = "0.160.0";
250
269
 
251
- declare const BROWSER_SDK_VERSION = "0.1.0-rc.1";
270
+ declare const BROWSER_SDK_VERSION = "0.1.0-rc.2";
252
271
 
253
- export { type AcquireBrowserControlRequest, BROWSER_SDK_VERSION, type BrowserControlAcquisition, type BrowserControlAction, BrowserControlClient, type BrowserControlClientOptions, type BrowserControlContext, BrowserControlError, type BrowserControlErrorReason, type BrowserControlFailure, type BrowserControlMutationContext, type BrowserControlReason, type BrowserControlRequestOptions, type BrowserControlResult, type BrowserControlState, type BrowserControlStatus, type BrowserViewer, type BrowserViewerFrame, type BrowserViewerMessage, type BrowserViewerWindow, CONTRACT_VERSION, type ReleaseBrowserControlRequest };
272
+ export { type AcquireBrowserControlRequest, BROWSER_SDK_VERSION, type BrowserControlAPIKeyContext, type BrowserControlAcquisition, type BrowserControlAction, BrowserControlClient, type BrowserControlClientOptions, type BrowserControlContext, BrowserControlError, type BrowserControlErrorReason, type BrowserControlFailure, type BrowserControlMutationContext, type BrowserControlReason, type BrowserControlRequestOptions, type BrowserControlResult, type BrowserControlState, type BrowserControlStatus, type BrowserViewer, type BrowserViewerAccess, type BrowserViewerFrame, type BrowserViewerMessage, type BrowserViewerWindow, CONTRACT_VERSION, type ReleaseBrowserControlRequest, createBrowserViewer };
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ var BrowserControlError = class extends Error {
15
15
  };
16
16
 
17
17
  // ../../packages/browser-sdk/src/generated/contract-version.ts
18
- var CONTRACT_VERSION = "0.159.1";
18
+ var CONTRACT_VERSION = "0.160.0";
19
19
 
20
20
  // ../../packages/browser-sdk/src/validation.ts
21
21
  var identifier = /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/;
@@ -55,10 +55,27 @@ function secret(v, max) {
55
55
  return typeof v === "string" && v.length > 0 && v.length <= max && /^[\x21-\x7e]+$/.test(v);
56
56
  }
57
57
  function contextPath(c, mutation) {
58
+ if (record(c) && "apiKey" in c) {
59
+ if (!keys(c, ["apiKey", "sessionId", "namespaceId"]) || !secret(c.apiKey, 8192) || !id(c.sessionId) || c.namespaceId !== void 0 && (typeof c.namespaceId !== "string" || c.namespaceId.length > 63 || !/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(c.namespaceId)))
60
+ invalidInput();
61
+ return `/v1/sessions/${encodeURIComponent(c.sessionId)}/browser-control`;
62
+ }
58
63
  if (!record(c) || !secret(c.userJWT, 8192) || typeof c.tenantId !== "string" || !/^tnt_[0-9A-HJKMNP-TV-Z]{26}$/.test(c.tenantId) || typeof c.apiKeyId !== "string" || !/^ak_[0-9A-HJKMNP-TV-Z]{26}$/.test(c.apiKeyId) || typeof c.namespaceId !== "string" || c.namespaceId.length > 63 || !/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(c.namespaceId) || !id(c.sessionId) || mutation && !secret(c.csrfToken, 8192))
59
64
  invalidInput();
60
65
  return `/v1/users/me/resources/t/${encodeURIComponent(c.tenantId)}/n/${encodeURIComponent(c.namespaceId)}/sessions/${encodeURIComponent(c.sessionId)}/browser-control`;
61
66
  }
67
+ function validateViewerAccess(value) {
68
+ if (!record(value) || !keys(value, ["url", "token", "expires_at"]) || typeof value.url !== "string" || value.url.length > 8192 || typeof value.token !== "string" || !/^[a-f0-9]{64}$/.test(value.token) || !date(value.expires_at) || Date.parse(value.expires_at) <= Date.now())
69
+ invalidInput();
70
+ try {
71
+ const url = new URL(value.url);
72
+ if (!safeURL(url) || url.hash || decodeURIComponent(value.url).includes(value.token))
73
+ invalidInput();
74
+ } catch {
75
+ invalidInput();
76
+ }
77
+ return { url: value.url, token: value.token, expires_at: value.expires_at };
78
+ }
62
79
  function validateIntent(value, release) {
63
80
  if (!record(value) || !keys(value, [
64
81
  "operation_id",
@@ -143,6 +160,9 @@ function safeURL(url) {
143
160
  }
144
161
 
145
162
  // ../../packages/browser-sdk/src/viewer.ts
163
+ function createBrowserViewer(access) {
164
+ return new BrowserViewerHandle(validateViewerAccess(access));
165
+ }
146
166
  var BrowserViewerHandle = class {
147
167
  expiresAt;
148
168
  #url;
@@ -157,6 +177,19 @@ var BrowserViewerHandle = class {
157
177
  this.#url = access.url;
158
178
  this.#token = access.token;
159
179
  }
180
+ takeAccess() {
181
+ if (this.#used || !this.#token || Date.parse(this.expiresAt) <= Date.now())
182
+ throw new BrowserControlError("invalid_input", false);
183
+ const access = {
184
+ url: this.#url,
185
+ token: this.#token,
186
+ expires_at: this.expiresAt
187
+ };
188
+ this.#used = true;
189
+ this.#url = "";
190
+ this.#token = void 0;
191
+ return access;
192
+ }
160
193
  /** Attach once, before the iframe loads. Use the exact Workspace origin approved by the deployment. */
161
194
  attach(frame) {
162
195
  if (this.#used || !frame.ownerDocument.defaultView || Date.parse(this.expiresAt) <= Date.now()) {
@@ -265,20 +298,25 @@ var BrowserControlClient = class {
265
298
  if (options.signal?.aborted)
266
299
  throw new BrowserControlError("aborted", false);
267
300
  const sessionId = context.sessionId;
301
+ const apiKey = "apiKey" in context;
268
302
  const headers = new Headers({
269
303
  accept: "application/json",
270
- authorization: `Bearer ${context.userJWT}`,
271
- "x-ariadra-api-version": CONTRACT_VERSION,
272
- "x-ariadra-current-tenant-id": context.tenantId,
273
- "x-ariadra-namespace-id": context.namespaceId,
274
- "x-ariadra-dashboard-api-key-id": context.apiKeyId
304
+ authorization: `Bearer ${apiKey ? context.apiKey : context.userJWT}`,
305
+ "x-ariadra-api-version": CONTRACT_VERSION
275
306
  });
307
+ if (context.namespaceId !== void 0)
308
+ headers.set("x-ariadra-namespace-id", context.namespaceId);
309
+ if (!apiKey) {
310
+ headers.set("x-ariadra-current-tenant-id", context.tenantId);
311
+ headers.set("x-ariadra-dashboard-api-key-id", context.apiKeyId);
312
+ }
276
313
  if (mutation) {
277
314
  headers.set("content-type", "application/json");
278
- headers.set(
279
- "x-csrf-token",
280
- context.csrfToken
281
- );
315
+ if (!apiKey)
316
+ headers.set(
317
+ "x-csrf-token",
318
+ context.csrfToken
319
+ );
282
320
  }
283
321
  const body = frozenIntent ? JSON.stringify(frozenIntent) : void 0;
284
322
  const expectedControl = frozenIntent?.expected_control_id;
@@ -306,7 +344,7 @@ var BrowserControlClient = class {
306
344
  headers,
307
345
  ...body === void 0 ? {} : { body },
308
346
  cache: "no-store",
309
- credentials: "include",
347
+ credentials: apiKey ? "omit" : "include",
310
348
  redirect: "error",
311
349
  signal: controller.signal
312
350
  };
@@ -399,6 +437,6 @@ async function readBody(response, signal) {
399
437
  }
400
438
 
401
439
  // src/version.ts
402
- var BROWSER_SDK_VERSION = "0.1.0-rc.1";
440
+ var BROWSER_SDK_VERSION = "0.1.0-rc.2";
403
441
 
404
- export { BROWSER_SDK_VERSION, BrowserControlClient, BrowserControlError, CONTRACT_VERSION };
442
+ export { BROWSER_SDK_VERSION, BrowserControlClient, BrowserControlError, CONTRACT_VERSION, createBrowserViewer };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentmatrix.pro/browser-sdk",
3
- "version": "0.1.0-rc.1",
3
+ "version": "0.1.0-rc.2",
4
4
  "description": "Human-authorized browser control client for AgentMatrix.",
5
5
  "homepage": "https://agentmatrix.pro",
6
6
  "license": "Apache-2.0",