@boxline/sdk 1.1.0 → 1.3.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.
package/CHANGELOG.md CHANGED
@@ -2,7 +2,99 @@
2
2
 
3
3
  All notable changes to `@boxline/sdk`. The SDK follows [semantic versioning](https://semver.org).
4
4
 
5
- ## 1.1.0 (not published yet)
5
+ ## 1.3.0 (2026-10-03)
6
+
7
+ ### Added
8
+
9
+ - **Time limits that fit the server.** `session.login`, `typeCredential` with `field: "otp"` and plain-English steps that use `%NAME.otp%` or
10
+ `%NAME.link%` wait as long as the server may (up to 24 minutes for `login`, 16 for a code), instead of the
11
+ default 120 s that cut off a login waiting for a pushed code.
12
+
13
+ - **Codes from your own system.** A password credential's `codeSource` is `"totp"` (the authenticator key,
14
+ `totpSecret`; `totpSecret` alone still means this), `"push"` or `"url"`, or null for no 2FA; with `"push"` or
15
+ `"url"` a run, action or `boxline-otp` that needs a code (or a sign-in link) waits for a fresh one, up to
16
+ `codeTimeoutSeconds` (5 to 900, default 300). `credentials.create` and `credentials.update` take `codeSource`,
17
+ `codeUrl` (a public HTTPS endpoint the platform asks with a signed POST) and `codeTimeoutSeconds`; a `PasswordCredential`
18
+ shows `codeSource`, `codeUrl` and `codeTimeoutSeconds`. Changing `codeSource` or `codeUrl` needs the `password` again
19
+ (400 `invalid_request`, 409 `conflict` on a race). With a `codeUrl` the answer has `codeUrlSecret` once (type
20
+ `CredentialWritten`). Types `CredentialCodeSource` and `CredentialWritten`.
21
+ - **`credentials.pushCode(name, {code} | {link})`**: sends the code or sign-in link the site emailed or texted to a wait
22
+ in progress (used once, kept sealed for 10 minutes; a link must be on one of the credential's sites). Types
23
+ `CredentialCodePush` and `CredentialCodeAccepted`. Not retried by the SDK.
24
+ - **`credentials.rotateCodeUrlSecret(name)`**: a new `codeUrlSecret` for the requests to `codeUrl` (check them with
25
+ `verifyWebhook`).
26
+ - **`session.login(credential?, {url?, allowWithExtensions?})`** and the `login` action: signs the browser in with a
27
+ password credential in one call (a short browser-only agent run with that one credential and its sites). Resolves to
28
+ `{url, title, runId}` (`LoginValue`); an `ActionResult` of a failed `login` has `runId` and a `code`.
29
+ - Errors `CredentialCodeTimeoutError` (`credential_code_timeout`: no code or link in time), `CredentialLinkWrongSiteError`
30
+ (`credential_link_wrong_site`), `CredentialLoginFailedError` (`credential_login_failed`, with `runId`),
31
+ `CredentialLoginTimeoutError` (`credential_login_timeout`: the login ran out of time, 15 steps plus the credential's
32
+ `codeTimeoutSeconds` for a pushed or asked code, and its run was canceled; a kind of `CredentialLoginFailedError`) and
33
+ `CodeUrlNotAllowedError` (`code_url_not_allowed`), and the matching `ErrorCode` values.
34
+ - `session.login` resolves to the page's origin only (`value.url`) when the page is the one a sign-in link opened, since
35
+ such a link can keep its token in the path.
36
+ - The webhook event `credential.code_needed` (`WebhookCredentialCodeNeededData`: `credential`, `type`, `sessionId`,
37
+ `runId`): a run waits for a code or link, so forward the site's email or SMS now. Never a code or link.
38
+ - The credentials audit has `action: "code"` for a pushed code or link (never its value).
39
+ - An agent run's steps (and `agent.stream` events) have `type: "code"` while it waits for a code or link: `state`
40
+ `"waiting"` (push it now), then `"received"` or `"timeout"`, with `credential` and `kind`; never the value.
41
+
42
+ ## 1.2.0 (2026-10-03)
43
+
44
+ ### Added
45
+
46
+ - **Credentials**: `bx.credentials.list/create/get/update/delete/audit` (`/v1/credentials`), one place for what the AI
47
+ types and the shell uses, with a typed union per type: a **password** (`origins`, `username`, `password`, optional
48
+ `totpSecret`; shown as `PasswordCredential` with `username` and `hasTotp`) and a **secret** (`value`, optional
49
+ `origins`; shown as `SecretCredential` with `preview`). `credentials.create` returns the matching type; `scope`,
50
+ `shell`, `description` and the write-only rules are as for secrets. Types `Credential`, `CredentialType`,
51
+ `CredentialScope`, `CredentialField`, `PasswordCredential`, `SecretCredential`, `CredentialCreateParams`,
52
+ `PasswordCredentialCreateParams`, `SecretCredentialCreateParams`, `CredentialUpdateParams`,
53
+ `CredentialAuditEntry` (with `type`, and the new `usedBy` kinds `action` and `otp`) and `CredentialAuditParams`.
54
+ Passwords need the plan's `loginDetails`; `PlanLimit` is `maxCredentials`.
55
+ - `credentials.update` that makes an AI-only credential readable by shells (`scope` to `"shell"` or `"all"`, or
56
+ `shell: true`) needs the values again in the same call, like a new site (the API answers 400 `invalid_request`
57
+ otherwise, 409 `conflict` when the sites, scope or `shell` changed meanwhile).
58
+ - **`credentials: ["NAME"]`** where the API takes them: `sessions.create` (exported into the shell: a secret as `$NAME`,
59
+ a password as `$NAME_USERNAME` and `$NAME_PASSWORD`; `boxline-otp NAME` prints its 2FA code), `exec` and `execStream`,
60
+ `agent.run` and `session.step()` and the step action (placeholders `%NAME%`, `%NAME.username%`, `%NAME.password%`,
61
+ `%NAME.otp%`), `runScript`, and `tasks.create` / `tasks.update` (a task shows its `credentials`). A `Session` lists
62
+ the exported `credentials`.
63
+ - **`session.typeCredential(name, {field, selector, allowWithExtensions})`** and the `type` action with `credential`
64
+ (and `field`: `"username"`, `"password"` or `"otp"`): a credential's value typed into a field without passing
65
+ through your code, only on the credential's sites.
66
+ - **`profiles.update(id, {name?, credential?})`**: rename a profile and/or link the password credential it signs in
67
+ with (`credential: null` unlinks it). A `Profile` has `credential`; sessions with the profile, and the agent runs,
68
+ task runs and steps in them, get that credential as if it were listed.
69
+ - Errors `CredentialExistsError` (409 `credential_exists`), `CredentialNotAllowedError` (400 `credential_not_for_ai`
70
+ / `credential_not_for_shell`), `TooManyCredentialValuesError` (409 `too_many_credential_values`) and
71
+ `ErrorCode.credentialNotFound` (404 `credential_not_found`, a `NotFoundError`). The webhook event `credential.changed`
72
+ (`WebhookCredentialChangedData`: `name`, `action`, `type`, `by`, `changed`).
73
+ - `examples/credentials.ts`.
74
+
75
+ ### Changed (breaking)
76
+
77
+ Nothing above shipped before, so these old names are gone with no aliases.
78
+
79
+ - **Secrets and profile login details became credentials.** `bx.secrets` is `bx.credentials`; `secrets` on
80
+ `sessions.create`, `exec`, `agent.run`, steps, `runScript` and tasks is `credentials` (`Session.secrets` is
81
+ `Session.credentials`, `Task.secrets` is `Task.credentials`); `login: true` on `runScript` is gone (list the
82
+ credential); `profiles.setLogin`, `updateLogin` and `deleteLogin`, `Profile.login`, `LoginDetails`,
83
+ `LoginDetailsUpdate` and the placeholders `%login.username%`, `%login.password%` and `%login.otp%` are gone: create a
84
+ password credential and link it with `profiles.update(id, {credential})`. Types `Secret`, `SecretScope`,
85
+ `SecretCreateParams`, `SecretUpdateParams`, `SecretAuditEntry` and `SecretAuditParams` are replaced by the credential
86
+ types above; `SecretExistsError`, `SecretNotAllowedError` and `TooManySecretValuesError` by `CredentialExistsError`,
87
+ `CredentialNotAllowedError` and `TooManyCredentialValuesError`; the plan field `maxSecrets` is `maxCredentials`; the
88
+ webhook event `secret.changed` is `credential.changed`.
89
+ - **Saved logins (contexts) are now browser profiles.** `bx.contexts` is `bx.profiles` (`create`, `get`, `list`,
90
+ `update`, `delete`; the routes are `/v1/profiles`; `contexts.rename` is `profiles.update(id, {name})`). Sessions and
91
+ agent runs take `profile: {id, persist?}` instead of `context`; tasks take `profile` instead of `savedLogin` (and
92
+ show it); a `Session` has `profileId` and `profilePersist` instead of `contextId` and `contextPersist`; the plan
93
+ fields are `maxProfiles` and `maxProfileBytes`, the plan feature is `"profiles"`, and the error code is
94
+ `ErrorCode.profileTooLarge` (`profile_too_large`). Types: `Profile` (was `ContextInfo`) and `TaskProfile`; the class
95
+ `Contexts` is `Profiles`. New profiles have ids starting with `prof_`. The old names are gone.
96
+
97
+ ## 1.1.0 (2026-10-02)
6
98
 
7
99
  ### Added
8
100
 
package/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # Boxline Node SDK
2
2
 
3
- Cloud browsers and shell sandboxes for AI agents. Each session is an isolated machine with a real Chrome and, if you
3
+ **Give your AI agents the infrastructure they need: browsers, shells, storage and isolated machines.**
4
+
5
+ Each session is an isolated machine with a real Chrome and, if you
4
6
  ask for it, a bash shell with Python and Node, sharing one `/workspace` disk.
5
7
 
6
8
  ```bash
@@ -22,7 +24,7 @@ instead of an API key, on the platform's own sites.
22
24
  - [An agent run with variables](#an-agent-run-with-variables)
23
25
  - [Limits, Continue and messages](#limits-continue-and-messages)
24
26
  - [Tasks and structured output](#tasks-and-structured-output)
25
- - [Secrets and saved login details](#secrets-and-saved-login-details)
27
+ - [Credentials and browser profiles](#credentials-and-browser-profiles)
26
28
  - [A script with useModel](#a-script-with-usemodel)
27
29
  - [CAPTCHAs](#captchas)
28
30
  - [Browser settings and extensions](#browser-settings-and-extensions)
@@ -204,7 +206,7 @@ await bx.agent.sendMessage(run.id, "Also open page C and include its heading in
204
206
 
205
207
  ## Tasks and structured output
206
208
 
207
- A task is a saved agent run: an instruction with `%name%` variables, an output schema, browser settings, a saved login,
209
+ A task is a saved agent run: an instruction with `%name%` variables, an output schema, browser settings, a profile,
208
210
  a model and, if you like, a schedule. Run it by hand or on its schedule; every run is an agent run.
209
211
 
210
212
  ```ts
@@ -239,45 +241,100 @@ await bx.tasks.update(task.id, { schedule: { enabled: true } }); // null remove
239
241
  - **Variables**: plain ones are written into the instruction (and kept with the run); `{ name, secret: true, origins }`
240
242
  is never stored, must come with every run, and is typed without the model seeing it. A task with a secret variable
241
243
  cannot have a schedule. A run missing a value throws `MissingVariablesError`.
244
+ - **Credentials**: `credentials: ["SHOP"]` on `tasks.create` gives every run the saved credentials' placeholders (see
245
+ [Credentials and browser profiles](#credentials-and-browser-profiles)); a scheduled task may use them, and the task
246
+ keeps the names only.
242
247
  - **Schedules**: five-field cron (at most every 5 minutes) read in `timezone`. A scheduled run is `queued` until it
243
248
  starts; a time that comes while a run is still going is `skipped`, and times the platform was down for are `missed`
244
249
  (`reason`, `missedCount`). The plan limits tasks and schedules switched on (`PlanLimitError`).
245
250
  - `waitForRun` takes the run from `run()` or `(taskId, taskRunId)`, with `{pollMs, timeoutMs}`; there is no GET for
246
251
  one task run, so it watches the task's unfinished runs.
247
252
 
248
- ## Secrets and saved login details
253
+ ## Credentials and browser profiles
249
254
 
250
- Project secrets are write-only: the value is sealed when stored and never returned or shown. Each secret's `scope` says
251
- where it may be used: `"agent"` (the default: only the AI, as `%NAME%`), `"shell"` (only as `$NAME` in shells) or `"all"`.
255
+ Credentials are write-only: the value is sealed when stored and never returned or shown. There are two types, a website
256
+ **password** (sites, user name, password and an optional 2FA key) and a **secret** (one value, such as an API token).
257
+ The name is the handle: the AI's placeholder (`%GITHUB_TOKEN%`, `%SHOP.password%`) and the shell variable
258
+ (`$GITHUB_TOKEN`, `$SHOP_PASSWORD`). Each credential's `scope` says where it may be used: `"agent"` (the default: only
259
+ the AI), `"shell"` (only as variables in shells) or `"all"`.
252
260
 
253
261
  ```ts
254
- await bx.secrets.create({ name: "GITHUB_TOKEN", value: process.env.GITHUB_TOKEN!, scope: "shell" });
255
- await bx.secrets.create({ name: "SITE_PASSWORD", value: process.env.SITE_PASSWORD!, origins: ["https://example.com"] });
262
+ await bx.credentials.create({ name: "GITHUB_TOKEN", type: "secret", value: process.env.GITHUB_TOKEN!, scope: "shell" });
263
+ const shop = await bx.credentials.create({
264
+ name: "SHOP",
265
+ type: "password",
266
+ origins: ["https://shop.example.com"], // the only site the AI may type it on
267
+ username: "ops@example.com",
268
+ password: process.env.SHOP_PASSWORD!,
269
+ totpSecret: process.env.SHOP_2FA_KEY, // optional: %SHOP.otp% is the current code
270
+ });
271
+ console.log(shop.type, shop.username, shop.hasTotp); // narrowed to PasswordCredential; no value anywhere
256
272
 
257
- // In a shell: exported as $GITHUB_TOKEN, and shown as %GITHUB_TOKEN% wherever it appears in the output.
258
- const s = await bx.sessions.create({ shell: true, env: { REGION: "eu" }, secrets: ["GITHUB_TOKEN"] });
273
+ // In a shell: $GITHUB_TOKEN, shown as %GITHUB_TOKEN% wherever it appears in the output.
274
+ const s = await bx.sessions.create({ shell: true, env: { REGION: "eu" }, credentials: ["GITHUB_TOKEN"] });
259
275
  await s.exec("gh repo list --limit 3");
260
- await s.exec("./deploy.sh", { secrets: ["DEPLOY_KEY"] }); // this one command only
276
+ await s.exec("./deploy.sh", { credentials: ["DEPLOY_KEY"] }); // this one command only
277
+
278
+ // For the AI: typed only on the credential's sites, never shown to the model.
279
+ await s.step("sign in with %SHOP.username% and %SHOP.password%", { credentials: ["SHOP"] });
280
+ await bx.agent.run({ task: "Sign in to https://shop.example.com with %SHOP.username% and %SHOP.password%", credentials: ["SHOP"] });
281
+ // Or type one field yourself without seeing it (the field's own frame must be on one of the credential's sites):
282
+ await s.typeCredential("SHOP", { field: "password", selector: "#password" });
261
283
 
262
- // For the AI: typed as %SITE_PASSWORD% only on its sites, never shown to the model.
263
- await s.step("type %SITE_PASSWORD% into the password field", { secrets: ["SITE_PASSWORD"] });
264
- await bx.agent.run({ task: "Sign in to https://example.com with %SITE_PASSWORD%", secrets: ["SITE_PASSWORD"] });
284
+ // A profile keeps cookies; link a password and the AI can sign in again when they expire.
285
+ await bx.profiles.update(profile.id, { credential: "SHOP" });
286
+
287
+ for await (const e of bx.credentials.audit({ name: "SHOP" })) console.log(e.at, e.action, e.actor, e.usedBy?.type);
288
+ ```
289
+
290
+ - **Exported credentials can be read by anything that runs in the shell**, including an agent's commands that a web
291
+ page tries to steer. Export only what you accept that for; keep website passwords at scope `"agent"` with `origins`.
292
+ Hiding values in output is a guard against accidents, not a boundary. A 2FA key never enters the machine:
293
+ `boxline-otp SHOP` in the shell asks the platform for the current code.
294
+ - `credentials.update` changes the fields you send; a new site needs the sensitive values again in the same call, and
295
+ so does a change of where the codes come from (`codeSource`, `codeUrl`: the `password` again).
296
+ - `runScript(code, { credentials })` lets the script's `step()` calls use credentials (the values never enter the
297
+ machine). In a session with Chrome extensions, steps, scripts and the `type` action with credentials need
298
+ `allowWithExtensions: true`, as agent runs with variables do.
299
+ - Errors: `CredentialExistsError` (use `update`), `CredentialNotAllowedError` (the scope does not allow that use),
300
+ `NotFoundError` (`credential_not_found`), `TooManyCredentialValuesError` (the session hides as many values as it can:
301
+ start a new one), `FeatureNotInPlanError` (a password needs the plan's `loginDetails`), `MachineTooOldError` (during
302
+ a deploy), `PlanLimitError` (beyond the plan's `maxCredentials`), `CredentialCodeTimeoutError` (no code or link came
303
+ in time), `CredentialLinkWrongSiteError` (a sign-in link not on the credential's sites), `CredentialLoginFailedError`
304
+ (`session.login` could not sign in; `runId` is the run that tried), `CodeUrlNotAllowedError` (a `codeUrl` that is not a
305
+ public HTTPS address).
306
+ - The `credential.changed` webhook event says a credential was created, changed (or linked to a profile) or deleted,
307
+ never a value.
308
+
309
+ ### Codes sent by email or SMS, and signing in in one call
310
+
311
+ A password's 2FA codes can come from an authenticator key (`codeSource: "totp"`, what `totpSecret` alone means), from
312
+ **your system** (`"push"`) or from **an endpoint of yours** (`"url"`). The site's email or SMS goes to you; the AI
313
+ never sees the code or a sign-in ("magic") link.
314
+
315
+ ```ts
316
+ await bx.credentials.create({
317
+ name: "SHOP", type: "password", origins: ["https://shop.example.com"], username: "ops@example.com",
318
+ password: process.env.SHOP_PASSWORD!,
319
+ codeSource: "push", // or "url" with codeUrl: "https://ops.example.com/boxline-codes"
320
+ codeTimeoutSeconds: 300, // how long a run waits for a code (5 to 900)
321
+ });
265
322
 
266
- // A saved login's details with 2FA: %login.username%, %login.password% and %login.otp% in sessions started with it.
267
- await bx.contexts.setLogin(context.id, { origin: "https://example.com", username: "ada@example.com", password, totpSecret });
323
+ // A run, an action or `boxline-otp SHOP` that needs a code waits for a fresh one. The webhook credential.code_needed
324
+ // ({credential, type: "code" | "link", sessionId, runId}) says when; then push what the site sent:
325
+ await bx.credentials.pushCode("SHOP", { code: "482913" }); // a 2FA code
326
+ await bx.credentials.pushCode("SHOP", { link: "https://shop.example.com/magic?t=…" }); // or a sign-in link
268
327
 
269
- for await (const e of bx.secrets.audit({ name: "GITHUB_TOKEN" })) console.log(e.at, e.action, e.actor, e.usedBy?.type);
328
+ // Sign in in one call: a short browser-only run with this one credential (default: the session's profile's).
329
+ const page = await s.login("SHOP", { url: "https://shop.example.com/login" }); // {url, title, runId}
270
330
  ```
271
331
 
272
- - **Exported secrets can be read by anything that runs in the shell**, including an agent's commands that a web page
273
- tries to steer. Export only what you accept that for; keep passwords at scope `"agent"` with `origins`. Hiding
274
- values in output is a guard against accidents, not a boundary.
275
- - `runScript(code, { secrets, login: true })` lets the script's `step()` calls use secrets and the saved login's
276
- details (the values never enter the machine). In a session with Chrome extensions, steps and scripts with secrets
277
- need `allowWithExtensions: true`, as agent runs with variables do.
278
- - Errors: `SecretExistsError` (use `update`), `SecretNotAllowedError` (the scope does not allow that use),
279
- `TooManySecretValuesError` (the session hides as many values as it can: start a new one), `MachineTooOldError`
280
- (during a deploy), `PlanLimitError` (beyond the plan's `maxSecrets`).
332
+ - A pushed code or link is used once, by a wait that began before it arrived, and kept sealed for 10 minutes. A link must
333
+ be on one of the credential's sites. `pushCode` is not retried by the SDK (a second push is a second code).
334
+ - With `codeSource: "url"` the platform asks your `codeUrl` every 5 s while a run waits (a signed POST; check it with
335
+ `verifyWebhook` and the `codeUrlSecret` that `create` and `update` return once; `credentials.rotateCodeUrlSecret(name)`
336
+ makes a new one). Answer `{code}` or `{link}`, or 204 for "not yet".
337
+ - Without a code in time a step, action or `login` throws `CredentialCodeTimeoutError`.
281
338
 
282
339
  ## A script with useModel
283
340
 
@@ -397,8 +454,8 @@ for await (const e of session.events({ types: ["console", "error"] })) console.l
397
454
  for await (const p of page.iterPages()) console.log(p.data.length);
398
455
  ```
399
456
 
400
- Lists: `sessions.list`, `sessions.events`, `sessions.pages`, `contexts.list`, `apiKeys.list`, `agent.list`,
401
- `crawl.list`, `extensions.list`, `tasks.list`, `tasks.runs`, `secrets.list`, `secrets.audit`, and a crawl's pages (`crawl.get(id, {after})`, or
457
+ Lists: `sessions.list`, `sessions.events`, `sessions.pages`, `profiles.list`, `apiKeys.list`, `agent.list`,
458
+ `crawl.list`, `extensions.list`, `tasks.list`, `tasks.runs`, `credentials.list`, `credentials.audit`, and a crawl's pages (`crawl.get(id, {after})`, or
402
459
  `for await (const p of bx.crawl.pages(id))`).
403
460
 
404
461
  ## Errors, retries and time limits
@@ -411,13 +468,14 @@ Lists: `sessions.list`, `sessions.events`, `sessions.pages`, `contexts.list`, `a
411
468
  `OutOfViewportError`, `WebhookUrlNotAllowedError`, `WebhooksUnavailableError`, `WebhookDisabledError`,
412
469
  `PayloadExpiredError`, `WebhookSignatureError` (from verifyWebhook), `VariablesWithExtensionsError`,
413
470
  `InvalidExtensionError`, `PayloadTooLargeError`, `LimitReachedError`, `ExtensionDeniedError`, `CrossSiteRequestError`,
414
- `MissingVariablesError`, `PlanLimitError`, `SecretExistsError`, `SecretNotAllowedError`, `TooManySecretValuesError`,
471
+ `MissingVariablesError`, `PlanLimitError`, `CredentialExistsError`, `CredentialNotAllowedError`, `TooManyCredentialValuesError`,
472
+ `CredentialCodeTimeoutError`, `CredentialLinkWrongSiteError`, `CredentialLoginFailedError`, `CodeUrlNotAllowedError`,
415
473
  `MachineTooOldError`, `NotContinuableError`, `TooManyMessagesError`, `SessionNotRunningError`, `AuthenticationError`,
416
474
  `NotFoundError`, and
417
475
  `BoxlineConnectionError` /
418
476
  `BoxlineTimeoutError` when no answer came back. `ErrorCode` has the codes.
419
477
  - **Retries.** GETs, and the calls that create or start something (sessions, bulk, agent runs, continued runs, messages
420
- to runs, crawls, API keys, contexts, extension uploads, tasks, task runs), are retried after a network error, a time-out, 429 and 5xx: 2 retries by default, exponential backoff
478
+ to runs, crawls, API keys, profiles, extension uploads, tasks, task runs), are retried after a network error, a time-out, 429 and 5xx: 2 retries by default, exponential backoff
421
479
  from 0.5 s to 8 s with jitter, or what `Retry-After` / `RateLimit-Reset` say (up to 60 s; longer waits go to you as a
422
480
  `RateLimitError`). Other POSTs (exec, actions, fetch…) are never retried: they could run twice.
423
481
  - **Idempotency keys.** The SDK sends a new `Idempotency-Key` with every create, and the same one on its retries, so a
@@ -446,12 +504,12 @@ same methods without it (`session.pause()`).
446
504
  | Account | `me`, `hasFeature`, `auth.signup`, `auth.login`, `auth.logout`, `project.trajectories`, `project.setTrajectories`, `project.settings`, `project.setSettings`, `apiKeys.list`, `apiKeys.create`, `apiKeys.revoke` |
447
505
  | Webhooks | `webhooks.create`, `list`, `get`, `update`, `delete`, `rotateSecret`, `test`, `deliveries`, `retryDelivery`; `verifyWebhook` (no request) |
448
506
  | Sessions | `sessions.create`, `get`, `list`, `update`, `release`, `pause`, `resume`, `move`, `extend`, `rotateProxy`, `rotateUrls`, `live`, `bulk` |
449
- | Browser | `sessions.actions`, `sessions.computer`; on a session: `goto`, `click`, `hover`, `fill`, `type`, `press`, `scroll`, `wait`, `select`, `elements`, `evaluate`, `content`, `screenshot`, `cursor`, `upload`, `tabs`, `newTab`, `switchTab`, `closeTab`, `back`, `forward`, `reload`, `step`, `extract`, `exportCookies`, `computer`, `mouse.move`/`moveBy`/`click`/`down`/`up`/`drag`, `keyboard.key`/`type`/`press` |
507
+ | Browser | `sessions.actions`, `sessions.computer`; on a session: `goto`, `click`, `hover`, `fill`, `type`, `typeCredential`, `press`, `scroll`, `wait`, `select`, `elements`, `evaluate`, `content`, `screenshot`, `cursor`, `upload`, `tabs`, `newTab`, `switchTab`, `closeTab`, `back`, `forward`, `reload`, `step`, `extract`, `exportCookies`, `computer`, `mouse.move`/`moveBy`/`click`/`down`/`up`/`drag`, `keyboard.key`/`type`/`press` |
450
508
  | Shell and scripts | `sessions.exec`, `execStream`, `runScript`, `restartShell` |
451
509
  | Files | `sessions.files.list`, `read`, `readText`, `write`, `delete`, `waitFor` |
452
510
  | Logs | `sessions.events`, `streamEvents`, `pages`, `recording`, `recordingFrame`; on a session: `waitForHuman`, `onCaptcha` |
453
- | Saved logins | `contexts.create`, `get`, `list`, `rename`, `delete`, `setLogin`, `deleteLogin` |
454
- | Secrets | `secrets.create`, `list`, `get`, `update`, `delete`, `audit` |
511
+ | Browser profiles | `profiles.create`, `get`, `list`, `update`, `delete` |
512
+ | Credentials | `credentials.create`, `list`, `get`, `update`, `delete`, `audit`, `pushCode`, `rotateCodeUrlSecret`; on a session: `typeCredential`, `login` |
455
513
  | Extensions | `extensions.upload`, `list`, `get`, `delete` |
456
514
  | Web | `fetch`, `screenshot`, `pdf`, `extract`, `search`, `crawl.start`, `get`, `list`, `cancel`, `pages`, `wait` |
457
515
  | Agent | `agent.models`, `run`, `get`, `list`, `takeover`, `handBack`, `cancel`, `continueRun`, `sendMessage`, `stream`, `wait` |
@@ -477,7 +535,7 @@ reach, so run them with `BOXLINE_API_URL=http://localhost:8080`; `search.ts` and
477
535
  | `webhooks.ts` | endpoints, deliveries and their history, re-sending, rotating the secret, a test event |
478
536
  | `agent-variables.ts` | an agent run with `%email%` / `%password%` limited to one site |
479
537
  | `tasks.ts` | a task with an output schema on a demo shop: run with a variable, waited for, its history, changed, deleted; an agent run with `output` |
480
- | `secrets.ts` | a secret exported into a shell (its length checked, its value hidden in output), changed, audited, deleted; login details on a saved login |
538
+ | `credentials.ts` | a secret exported into a shell (its length checked, its value hidden in output), changed, audited, deleted; a password with 2FA linked to a profile |
481
539
  | `script-use-model.ts` | `useModel`, `step()` and `extract()` in a script |
482
540
  | `captcha.ts` | noticing a CAPTCHA and handing it to a person |
483
541
  | `block-ads.ts` | a session that blocks ads and trackers, and its `blockedRequests` count |
package/dist/client.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { type CoreConfig, type Query, type RequestOptions, type SendInit } from "./core.js";
2
2
  import { Page, PagePromise } from "./pagination.js";
3
3
  import { Session } from "./session.js";
4
- import type { ActionItem, ActionResult, AgentMessageSent, AgentModelCatalog, AgentRun, AgentRunEvent, AgentRunParams, AgentRunStarted, ContinueRunParams, ApiKeyInfo, BulkResult, ComputerAction, ComputerOptions, ComputerResult, ContextInfo, LoginDetails, LoginDetailsUpdate, MoveShell, Secret, SecretAuditEntry, SecretAuditParams, SecretCreateParams, SecretUpdateParams, CrawlGetParams, CrawlJob, CrawlPage, CrawlParams, CreateSessionParams, ExecExit, ExecOptions, ExecResult, ExtensionInfo, ExtractParams, ExtractResult, FetchParams, FetchResult, FileList, FileRef, ListParams, LoginResponse, Me, MoveTimings, NewApiKey, NewWebhookEndpoint, ProjectSettings as ProjectSettingsData, AgentProvider, ModelKey, ModelKeyParams, CaptchaMode, WebhookCreateParams, WebhookDelivery, WebhookDeliveryListParams, WebhookEndpoint, WebhookEventType, WebhookEventTypeList, WebhookUpdateParams, PdfParams, PlanFeature, Pricing, Recording, RunScriptOptions, ScreenshotParams, ScriptResult, SearchParams, SearchResponse, SessionEvent, SessionEventsParams, SessionListParams, SessionUrls, SignupResponse, Stats, Task, TaskCreateParams, TaskRun, TaskRunListParams, TaskRunParams, TaskUpdateParams, TrajectoriesSetting, UpdateSessionParams, Usage, VisitedPage } from "./types.js";
4
+ import type { ActionItem, ActionResult, AgentMessageSent, AgentModelCatalog, AgentRun, AgentRunEvent, AgentRunParams, AgentRunStarted, ContinueRunParams, ApiKeyInfo, BulkResult, ComputerAction, ComputerOptions, ComputerResult, Profile, ProfileUpdateParams, MoveShell, Credential, CredentialAuditEntry, CredentialCodeAccepted, CredentialCodePush, CredentialAuditParams, CredentialCreateParams, CredentialUpdateParams, CredentialWritten, PasswordCredential, PasswordCredentialCreateParams, SecretCredential, SecretCredentialCreateParams, CrawlGetParams, CrawlJob, CrawlPage, CrawlParams, CreateSessionParams, ExecExit, ExecOptions, ExecResult, ExtensionInfo, ExtractParams, ExtractResult, FetchParams, FetchResult, FileList, FileRef, ListParams, LoginResponse, Me, MoveTimings, NewApiKey, NewWebhookEndpoint, ProjectSettings as ProjectSettingsData, AgentProvider, ModelKey, ModelKeyParams, CaptchaMode, WebhookCreateParams, WebhookDelivery, WebhookDeliveryListParams, WebhookEndpoint, WebhookEventType, WebhookEventTypeList, WebhookUpdateParams, PdfParams, PlanFeature, Pricing, Recording, RunScriptOptions, ScreenshotParams, ScriptResult, SearchParams, SearchResponse, SessionEvent, SessionEventsParams, SessionListParams, SessionUrls, SignupResponse, Stats, Task, TaskCreateParams, TaskRun, TaskRunListParams, TaskRunParams, TaskUpdateParams, TrajectoriesSetting, UpdateSessionParams, Usage, VisitedPage } from "./types.js";
5
5
  export interface BoxlineOptions {
6
6
  /** Defaults to the BOXLINE_API_KEY environment variable. */
7
7
  apiKey?: string;
@@ -34,11 +34,11 @@ export declare class Boxline {
34
34
  readonly project: ProjectSettings;
35
35
  readonly apiKeys: ApiKeys;
36
36
  readonly sessions: Sessions;
37
- readonly contexts: Contexts;
37
+ readonly profiles: Profiles;
38
38
  readonly crawl: Crawl;
39
39
  readonly agent: Agent;
40
40
  readonly tasks: Tasks;
41
- readonly secrets: Secrets;
41
+ readonly credentials: Credentials;
42
42
  readonly webhooks: Webhooks;
43
43
  readonly extensions: Extensions;
44
44
  /** @internal */
@@ -284,70 +284,92 @@ export declare class SessionFiles {
284
284
  /** Waits for a file matching a glob (e.g. `downloads/*.csv`) that has finished writing. */
285
285
  waitFor(id: string, pattern: string, timeoutMs?: number, options?: RequestOptions): Promise<FileRef>;
286
286
  }
287
- /** Saved logins: cookies and local storage to start sessions with (`context: {id, persist: true}` fills one). */
288
- export declare class Contexts {
287
+ /** Browser profiles: cookies and local storage to start sessions with (`profile: {id, persist: true}` fills one). */
288
+ export declare class Profiles {
289
289
  private readonly client;
290
290
  constructor(client: Boxline);
291
291
  /**
292
- * A new saved login: empty, or with `fromSession` holding that working session's current cookies and site storage
292
+ * A new profile: empty, or with `fromSession` holding that working session's current cookies and site storage
293
293
  * (sign in there first, e.g. in its live view). `attach: true` also makes the session save to it from now on (at its
294
- * checkpoints and when it ends); a session that already has a saved login refuses that (409 `conflict`). 413
295
- * `context_too_large` over 16 MB; PlanLimitError (402) past the plan's `maxContexts` or `maxContextBytes`.
294
+ * checkpoints and when it ends); a session that already has a profile refuses that (409 `conflict`). 413
295
+ * `profile_too_large` over 16 MB; PlanLimitError (402) past the plan's `maxProfiles` or `maxProfileBytes`.
296
296
  */
297
297
  create(params?: {
298
298
  name?: string;
299
299
  fromSession?: string;
300
300
  attach?: boolean;
301
- }, options?: RequestOptions): Promise<ContextInfo>;
302
- get(id: string, options?: RequestOptions): Promise<ContextInfo>;
301
+ }, options?: RequestOptions): Promise<Profile>;
302
+ get(id: string, options?: RequestOptions): Promise<Profile>;
303
303
  /** Newest first; the first page's `total` counts them all. */
304
- list(params?: ListParams, options?: RequestOptions): PagePromise<ContextInfo, Page<ContextInfo> & {
304
+ list(params?: ListParams, options?: RequestOptions): PagePromise<Profile, Page<Profile> & {
305
305
  total: number;
306
306
  }>;
307
- rename(id: string, name: string, options?: RequestOptions): Promise<ContextInfo>;
308
- delete(id: string, options?: RequestOptions): Promise<void>;
309
- /**
310
- * Keeps sign-in details on the saved login (plan feature `loginDetails`), replacing earlier ones: the site, user name,
311
- * password and optionally the 2FA setup key, sealed like secrets. Returns the context, whose `login` shows
312
- * `{origin, username, hasPassword, hasTotp}`, never the password or the 2FA secret.
313
- */
314
- setLogin(id: string, details: LoginDetails, options?: RequestOptions): Promise<ContextInfo>;
315
307
  /**
316
- * Changes some of the login details and keeps the rest (setLogin replaces them all); `totpSecret: null` removes 2FA.
317
- * A password never moves to another site on its own: a new `origin` needs `password` in the same call, and
318
- * `totpSecret` (a new one or null) when the login has 2FA (400 otherwise). A BoxlineError with code `conflict` (409)
319
- * when the login changed meanwhile: send it again.
308
+ * Changes the name and/or the password credential the profile signs in with: `credential: "SHOP"` links a password
309
+ * credential (see `credentials`), so sessions with this profile, and agent runs, task runs and steps in them, get it
310
+ * as if it were listed in their `credentials` and the AI can sign in again when the cookies have expired; `null`
311
+ * unlinks it. NotFoundError (404 `credential_not_found`) for a name the project does not have, a 400 BoxlineError
312
+ * for a secret (only passwords sign in), FeatureNotInPlanError (402) without the plan's `loginDetails`.
320
313
  */
321
- updateLogin(id: string, changes: LoginDetailsUpdate, options?: RequestOptions): Promise<ContextInfo>;
322
- /** Removes the login details (the saved cookies and storage stay). */
323
- deleteLogin(id: string, options?: RequestOptions): Promise<void>;
314
+ update(id: string, changes: ProfileUpdateParams, options?: RequestOptions): Promise<Profile>;
315
+ delete(id: string, options?: RequestOptions): Promise<void>;
324
316
  }
325
317
  /**
326
- * Project secrets: write-only values the AI uses as %NAME% placeholders (`secrets` on agent runs, steps and scripts) and
327
- * shells get as environment variables (`secrets` on sessions.create and exec), depending on each secret's `scope`. The
328
- * value is never returned, logged or shown; every change and use is audited.
318
+ * Credentials: write-only website passwords (with an optional 2FA key) and secrets. The AI uses them as placeholders
319
+ * (`%NAME%`, `%SHOP.password%`) with `credentials` on agent runs, steps, scripts, tasks and `Session.typeCredential`;
320
+ * shells get them as environment variables (`credentials` on sessions.create and exec), depending on each
321
+ * credential's `scope`. A value is never returned, logged or shown; every change and use is audited.
329
322
  */
330
- export declare class Secrets {
323
+ export declare class Credentials {
331
324
  private readonly client;
332
325
  constructor(client: Boxline);
333
- /** The project's secrets, in name order, without their values. */
334
- list(params?: ListParams, options?: RequestOptions): PagePromise<Secret>;
326
+ /** The project's credentials, in name order, without their values. */
327
+ list(params?: ListParams, options?: RequestOptions): PagePromise<Credential>;
335
328
  /**
336
- * Stores a secret, sealed; the answer never has the value. SecretExistsError for a name the project has (change it
337
- * with update), PlanLimitError beyond the plan's `maxSecrets`. Not retried by the SDK (the API takes no
338
- * Idempotency-Key here): a retry after a lost answer may meet SecretExistsError.
329
+ * Stores a credential, sealed; the answer never has a value. `type: "password"` takes `origins`, `username`,
330
+ * `password` and optionally where its 2FA codes come from: `codeSource: "totp"` with `totpSecret`, `"push"` (send
331
+ * each code or sign-in link with `pushCode`) or `"url"` with `codeUrl` (needs the plan's `loginDetails`:
332
+ * FeatureNotInPlanError); `type: "secret"` takes `value`. CredentialExistsError for a name the project has (change it
333
+ * with update), PlanLimitError beyond the plan's `maxCredentials`; 400 `code_url_not_allowed` for a `codeUrl` that is
334
+ * not a public HTTPS address. With `codeUrl` the answer has `codeUrlSecret`, the key that signs the platform's
335
+ * requests, shown this once. Not retried by the SDK (the API takes no Idempotency-Key here): a retry after a lost
336
+ * answer may meet CredentialExistsError.
339
337
  */
340
- create(params: SecretCreateParams, options?: RequestOptions): Promise<Secret>;
341
- get(name: string, options?: RequestOptions): Promise<Secret>;
338
+ create(params: PasswordCredentialCreateParams, options?: RequestOptions): Promise<CredentialWritten<PasswordCredential>>;
339
+ create(params: SecretCredentialCreateParams, options?: RequestOptions): Promise<CredentialWritten<SecretCredential>>;
340
+ create(params: CredentialCreateParams, options?: RequestOptions): Promise<CredentialWritten>;
341
+ get(name: string, options?: RequestOptions): Promise<Credential>;
342
342
  /**
343
- * Changes the fields you send. A running agent run keeps the value it started with; a session that exports the secret
344
- * gets the new value on its next machine (move, resume, recovery).
343
+ * Changes the fields you send (the type cannot change: delete it and create it again). A new site, or a `scope`
344
+ * or `shell` that makes an AI-only credential readable by shells, needs the sensitive values again in the same call
345
+ * (a secret's `value`; a password's `password`, and `totpSecret` when it has 2FA), else a 400 `invalid_request`; so
346
+ * does a change of where a password's codes come from (`codeSource`, removing 2FA included, or `codeUrl`: the
347
+ * `password` again). A 409 `conflict` when the sites, scope, `shell`, `codeSource` or `codeUrl` changed meanwhile
348
+ * (send it again). A new `codeUrl` answers with a new `codeUrlSecret`, shown once. A running agent run keeps the
349
+ * values it started with; a session that exports the credential gets the new ones on its next machine (move,
350
+ * resume, recovery).
345
351
  */
346
- update(name: string, patch: SecretUpdateParams, options?: RequestOptions): Promise<Secret>;
347
- /** Deletes it; sessions that exported it no longer get it on their next machine. */
352
+ update(name: string, patch: CredentialUpdateParams, options?: RequestOptions): Promise<CredentialWritten>;
353
+ /** Deletes it; profiles that link it are unlinked, and sessions that exported it no longer get it on their next machine. */
348
354
  delete(name: string, options?: RequestOptions): Promise<void>;
349
- /** Changes to secrets and saved login details, and each use (once per session, command, run or script), newest first. */
350
- audit(params?: SecretAuditParams, options?: RequestOptions): PagePromise<SecretAuditEntry>;
355
+ /**
356
+ * For a password with `codeSource: "push"`: sends the code (`{code}`) or the sign-in link (`{link}`) the site emailed
357
+ * or texted, for a run, action or `boxline-otp` that waits for it (the webhook `credential.code_needed` says when).
358
+ * It is kept sealed for up to 10 minutes and used once, by a wait that began before it arrived. A link must be on one of
359
+ * the credential's sites (400 `credential_link_wrong_site`). 400 `invalid_request` for a credential whose source is
360
+ * not "push"; NotFoundError for one the project does not have. Not retried by the SDK (a second push is a second
361
+ * code). The value is never logged or returned.
362
+ */
363
+ pushCode(name: string, code: CredentialCodePush, options?: RequestOptions): Promise<CredentialCodeAccepted>;
364
+ /**
365
+ * For a password with `codeSource: "url"`: a new `codeUrlSecret` (`whsec_…`, shown this once). Requests to `codeUrl` are
366
+ * signed with it from now on (check them with `verifyWebhook`); the old one stops at once.
367
+ */
368
+ rotateCodeUrlSecret(name: string, options?: RequestOptions): Promise<{
369
+ codeUrlSecret: string;
370
+ }>;
371
+ /** Changes to credentials and each use (once per session, command, run, script, task run, typed field or 2FA code) and pushed codes, newest first. */
372
+ audit(params?: CredentialAuditParams, options?: RequestOptions): PagePromise<CredentialAuditEntry>;
351
373
  }
352
374
  /** Crawls: follow links from a start URL in the background (robots.txt respected); poll with get() or wait(). */
353
375
  export declare class Crawl {
@@ -496,8 +518,8 @@ export declare class Agent {
496
518
  cancel(id: string, options?: RequestOptions): Promise<AgentRun>;
497
519
  /**
498
520
  * Continues a run that stopped at one of its limits (errorCode max_steps, max_cost, too_many_errors or no_progress)
499
- * while its `continuable` is set: a new run in the same session, with the same model, mode, output schema, secrets
500
- * and saved login, and a compact record of what the previous run did. Returns the new run (`continuedFrom` links
521
+ * while its `continuable` is set: a new run in the same session, with the same model, mode, output schema, credentials
522
+ * and profile, and a compact record of what the previous run did. Returns the new run (`continuedFrom` links
501
523
  * back); wait for it with `wait(run.id)` or `stream(run.id)` like any run. A run that had `variables` needs them again
502
524
  * (MissingVariablesError otherwise). NotContinuableError: it did not stop at a limit, was continued already, or its
503
525
  * window passed. An Idempotency-Key is sent, so a retry never starts a second run.