@scalebrowser/sdk 0.3.0 → 0.4.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/dist/index.d.cts CHANGED
@@ -1,10 +1,11 @@
1
1
  import WebSocket from 'ws';
2
2
 
3
3
  /**
4
- * Error model — stable numeric API error codes (SPEC §5,
4
+ * Error model: stable numeric API error codes (SPEC §5,
5
5
  * `crates/core/src/error.rs`) and the typed exceptions the SDK throws.
6
6
  */
7
- /** Stable numeric API error codes (4001–4010). */
7
+ /** Stable numeric API error codes (4001–4012, append-only: a retired code stays
8
+ * reserved rather than being reused). */
8
9
  declare const ErrorCode: {
9
10
  readonly NotFound: 4001;
10
11
  readonly ProxyGeo: 4002;
@@ -20,6 +21,16 @@ declare const ErrorCode: {
20
21
  * is to stop a running browser anywhere or upgrade the plan. */
21
22
  readonly ConcurrencyLimit: 4008;
22
23
  readonly Unauthorized: 4010;
24
+ /** No account is connected to this machine, so nothing may run (DEC-014).
25
+ * Distinct from Unauthorized (4010 = the daemon's own bearer token is wrong, so
26
+ * re-read the token): 4011 means the machine needs to be signed in, and no token
27
+ * a client holds can substitute for that. Connect it in the desktop app. */
28
+ readonly NotSignedIn: 4011;
29
+ /** This ONE profile is open on another machine of the same account (DEC-015).
30
+ * Distinct from ConcurrencyLimit (4008 = the plan is full, buy more or free any
31
+ * browser): the caller's move here costs nothing. Close it on that machine, or
32
+ * take it over from the app running there. */
33
+ readonly ProfileInUse: 4012;
23
34
  };
24
35
  type ErrorCodeValue = (typeof ErrorCode)[keyof typeof ErrorCode];
25
36
  /** Error body shape: `{ code, message }` (docs/features/api.md). */
@@ -27,13 +38,13 @@ interface ApiErrorBody {
27
38
  code?: number;
28
39
  message?: string;
29
40
  }
30
- /** Base class for every error this SDK throws — lets callers `catch` one type. */
41
+ /** Base class for every error this SDK throws, so callers can `catch` one type. */
31
42
  declare class ScalebrowserError extends Error {
32
43
  constructor(message: string);
33
44
  }
34
45
  /**
35
46
  * A typed transport/contract error. Carries the HTTP `status` and the daemon's
36
- * numeric `code` so callers (and the auth layer) can react — e.g. 401 / code
47
+ * numeric `code` so callers (and the auth layer) can react, e.g. 401 / code
37
48
  * 4010 → re-authenticate.
38
49
  */
39
50
  declare class ApiError extends ScalebrowserError {
@@ -167,14 +178,14 @@ interface Persona {
167
178
  }
168
179
 
169
180
  /**
170
- * Wire types — a 1:1 mirror of the daemon's serialized domain model
181
+ * Wire types: a 1:1 mirror of the daemon's serialized domain model
171
182
  * (`crates/core/src/model.rs`, `persona.rs`, `events.rs`) and the endpoint
172
183
  * contract in `docs/features/api.md`. Mirrored against `web-ui/src/api/types/`
173
184
  * (a directory of split files behind the `web-ui/src/api/types.ts` barrel), and
174
185
  * that mirror is ENFORCED: `web-ui/src/test/sdk-type-mirror.test.ts` compares
175
186
  * every shared exported declaration and goes red on drift. The Python SDK
176
187
  * (`sdks/python/src/scalebrowser/models*.py`) carries the same shapes by hand,
177
- * deliberately without a gate — a TS↔pydantic comparator is its own tool.
188
+ * deliberately without a gate; a TS↔pydantic comparator is its own tool.
178
189
  *
179
190
  * All Rust enums serialize `snake_case` (serde `rename_all`). Timestamps are
180
191
  * unix seconds (`number`, Rust `i64`). The truth for any disagreement is the
@@ -200,7 +211,7 @@ declare const ROTATIONS: readonly Rotation[];
200
211
  type SessionKind = 'cookies' | 'local_storage' | 'indexed_db' | 'service_worker';
201
212
  type OsFamily = 'windows' | 'macos' | 'linux';
202
213
  /** How protected a profile is right now, decided by the daemon WITHOUT starting a
203
- * browser — it runs the same gates the launch runs. `blocked` means the launch
214
+ * browser: it runs the same gates the launch runs. `blocked` means the launch
204
215
  * will refuse this profile; `warn` means it starts but something measurably
205
216
  * weakens it (most often a missing proxy). */
206
217
  type ProtectionLevel = 'ok' | 'warn' | 'blocked';
@@ -235,7 +246,7 @@ interface Profile {
235
246
  protection?: ProtectionStatus;
236
247
  /**
237
248
  * Platform slugs this profile has a stored login for, sorted by the daemon.
238
- * Additive — a daemon predating the credential vault simply omits it.
249
+ * Additive; a daemon predating the credential vault simply omits it.
239
250
  */
240
251
  platforms?: string[];
241
252
  }
@@ -247,7 +258,7 @@ interface Group {
247
258
  /**
248
259
  * Operating config: what the created profiles DO. Every key mirrors a
249
260
  * `POST /v1/profiles` body field. The daemon refuses an unknown key with a 400
250
- * rather than dropping it — a preset makes up to 1000 profiles, so a swallowed
261
+ * rather than dropping it, because a preset makes up to 1000 profiles, so a swallowed
251
262
  * key is a thousand wrong ones.
252
263
  */
253
264
  interface PresetConfig {
@@ -255,12 +266,12 @@ interface PresetConfig {
255
266
  engine_version?: string | null;
256
267
  host_mode?: HostMode | null;
257
268
  geo_mode?: GeoMode | null;
258
- /** The geo GATE's expectation — not the persona's drawn region. */
269
+ /** The geo GATE's expectation, not the persona's drawn region. */
259
270
  expected_country?: string | null;
260
271
  group_id?: string | null;
261
272
  proxy_id?: string | null;
262
273
  /**
263
- * Library ids every profile of the batch is created with. Empty is normal —
274
+ * Library ids every profile of the batch is created with. Empty is normal, since
264
275
  * about half of real Chrome users carry no extension.
265
276
  *
266
277
  * An id the library no longer holds refuses the whole batch: a thousand profiles
@@ -271,7 +282,7 @@ interface PresetConfig {
271
282
  /**
272
283
  * Generator constraints: what the created profiles ARE. Exactly one axis,
273
284
  * because an axis is only honest here if the daemon does not overwrite it at
274
- * launch — the GPU, screen, DPR and Chrome version all are.
285
+ * launch; the GPU, screen, DPR and Chrome version all are.
275
286
  */
276
287
  interface PresetConstraints {
277
288
  /**
@@ -287,11 +298,11 @@ interface Preset {
287
298
  config: PresetConfig;
288
299
  created_at: number;
289
300
  }
290
- /** `GET /v1/persona/constraints` — the values a preset may constrain to. */
301
+ /** `GET /v1/persona/constraints`: the values a preset may constrain to. */
291
302
  interface PersonaConstraintOptions {
292
303
  countries: string[];
293
304
  }
294
- /** Proxy — credentials are write-only (`#[serde(skip_serializing)]`); never returned. */
305
+ /** Proxy; credentials are write-only (`#[serde(skip_serializing)]`) and never returned. */
295
306
  interface Proxy {
296
307
  id: string;
297
308
  kind: ProxyKind;
@@ -323,7 +334,7 @@ interface AuditStatus {
323
334
  state: 'idle' | 'running' | 'finished';
324
335
  started_at?: number;
325
336
  finished_at?: number;
326
- /** Why the RUN failed — distinct from a detector's own `skip`. */
337
+ /** Why the RUN failed, distinct from a detector's own `skip`. */
327
338
  error?: string;
328
339
  report?: AuditReport;
329
340
  }
@@ -418,7 +429,7 @@ interface RunStep {
418
429
  /** Path of the still under the runs API; the image is fetched separately. */
419
430
  shot_path: string | null;
420
431
  /**
421
- * What the call produced, in one line — "3 blocks, 122 characters",
432
+ * What the call produced, in one line: "3 blocks, 122 characters",
422
433
  * "no visible change · 14 elements".
423
434
  *
424
435
  * `summary` says what the agent asked for, this says what came back. A step
@@ -495,7 +506,7 @@ type LifecycleEvent = {
495
506
  goal: string;
496
507
  at: number;
497
508
  }
498
- /** One tool call was appended to a run's trail — the whole stored step. */
509
+ /** One tool call was appended to a run's trail: the whole stored step. */
499
510
  | {
500
511
  type: 'run_step';
501
512
  run_id: string;
@@ -533,7 +544,7 @@ type LifecycleEvent = {
533
544
  /**
534
545
  * An event as it arrives, with its position in this connection's stream.
535
546
  *
536
- * The daemon numbers every frame, starting at 1. A jump means frames were lost —
547
+ * The daemon numbers every frame, starting at 1. A jump means frames were lost, and
537
548
  * the only way to tell "nothing happened" from "something happened and I did not
538
549
  * get it". Optional so a daemon predating the numbering still type-checks.
539
550
  */
@@ -544,13 +555,13 @@ type StreamedEvent = LifecycleEvent & {
544
555
  /**
545
556
  * Live lifecycle event stream (`GET /v1/events`, AC-API-003).
546
557
  *
547
- * Read as `text/event-stream` over `fetch` (so the Bearer header is attached —
558
+ * Read as `text/event-stream` over `fetch` (so the Bearer header is attached, which
548
559
  * the browser `EventSource` cannot do that) and reconnect with backoff. A
549
560
  * `/v1/ws` websocket carries the same events; SSE is sufficient for one-way
550
561
  * fan-out. Mirrors `web-ui/src/api/events.ts`.
551
562
  */
552
563
 
553
- /** Injectable `fetch` — defaults to the global at call time. */
564
+ /** Injectable `fetch`; defaults to the global at call time. */
554
565
  type FetchLike = typeof globalThis.fetch;
555
566
  type StreamStatus = 'connecting' | 'open' | 'closed';
556
567
  interface StreamParams {
@@ -597,7 +608,7 @@ declare function eventStream(params: StreamParams): AsyncIterableIterator<Lifecy
597
608
  /** What an operator has taken out of an agent's hands. */
598
609
  type InterruptionLock = 'always_block' | 'always_allow' | 'agent_decides';
599
610
  /**
600
- * One answer, in the browser's OWN vocabulary — hence `allowOnce` in camelCase
611
+ * One answer, in the browser's OWN vocabulary, hence `allowOnce` in camelCase
601
612
  * while everything else in this API is snake_case. The daemon's enum is
602
613
  * `#[serde(rename_all = "camelCase")]`; sending `allow_once` is a 400.
603
614
  */
@@ -636,7 +647,7 @@ interface InterruptionRuleRow {
636
647
  origin: string;
637
648
  kind: string;
638
649
  choice: InterruptionChoice;
639
- /** Who wrote it — an agent must not be able to widen what the operator allowed. */
650
+ /** Who wrote it: an agent must not be able to widen what the operator allowed. */
640
651
  author: 'operator' | 'agent';
641
652
  profile_id: string | null;
642
653
  }
@@ -668,13 +679,13 @@ interface ArtifactBytes {
668
679
  * Licence state, for display.
669
680
  *
670
681
  * The daemon decides on every launch whether a start is allowed; this never
671
- * gets a say in it. Never gate your own code on it — a green light on a profile
682
+ * gets a say in it. Never gate your own code on it: a green light on a profile
672
683
  * the launch gate refuses is worse than no light.
673
684
  */
674
685
  interface Account {
675
686
  /** Whether an entitlement snapshot has arrived. Also `false` in the seconds
676
687
  * between signing in and the first refresh, so it never answers "is this
677
- * machine connected to an account" — `signed_in` does. */
688
+ * machine connected to an account"; `signed_in` does. */
678
689
  licensed: boolean;
679
690
  /** Whether an account is connected to this machine. One without an account
680
691
  * starts no browser (DEC-014). */
@@ -731,7 +742,7 @@ declare class ClientCore {
731
742
  setToken(token: string | null): void;
732
743
  protected request<T>(method: string, path: string, body?: unknown, opts?: RequestOptions): Promise<T>;
733
744
  /**
734
- * A route that answers with bytes, not JSON — artifacts and run stills.
745
+ * A route that answers with bytes, not JSON: artifacts and run stills.
735
746
  *
736
747
  * Separate from {@link ClientCore.request} rather than a flag on it, because the two
737
748
  * differ in the error path as well: a failed byte fetch still answers JSON,
@@ -758,7 +769,7 @@ declare class ControlApi extends ClientCore {
758
769
  */
759
770
  putArtifact(profileId: string, bytes: Uint8Array | ArrayBuffer, name?: string): Promise<ArtifactPutResult>;
760
771
  /**
761
- * Fetch one artifact's bytes — a screenshot, a download, a saved PDF.
772
+ * Fetch one artifact's bytes: a screenshot, a download, a saved PDF.
762
773
  *
763
774
  * A miss is a plain 404 whether the id never existed, expired, or belonged to
764
775
  * a released lease: the caller's next move is the same in all three cases.
@@ -768,13 +779,13 @@ declare class ControlApi extends ClientCore {
768
779
  * Licence state for display. The launch gate stays the authority on starts.
769
780
  *
770
781
  * A daemon predating the route answers 404, and that is not an error worth
771
- * throwing — but it is read pessimistically: nothing can be shown to be
782
+ * throwing, but it is read pessimistically: nothing can be shown to be
772
783
  * connected or permitted. Same shape of tolerance as {@link getMetrics}.
773
784
  */
774
785
  getAccount(signal?: AbortSignal): Promise<Account>;
775
786
  /** "Is the daemon alive?" Public, needs no token. */
776
787
  health(signal?: AbortSignal): Promise<HealthStatus>;
777
- /** "Can it serve?" Local facts only — the control plane is deliberately not consulted. */
788
+ /** "Can it serve?" Local facts only; the control plane is deliberately not consulted. */
778
789
  ready(signal?: AbortSignal): Promise<ReadyStatus>;
779
790
  }
780
791
 
@@ -782,12 +793,12 @@ declare class ControlApi extends ClientCore {
782
793
  * a paged fleet while looking authoritative, so ordering is a server parameter. */
783
794
  type ProfileSort = 'created_at' | 'name' | 'runtime_state' | 'last_open_at';
784
795
  type SortOrder = 'asc' | 'desc';
785
- /** `GET /v1/profiles/ids` — every id matching the same filters, unpaged. */
796
+ /** `GET /v1/profiles/ids`: every id matching the same filters, unpaged. */
786
797
  interface ProfileIdsResult {
787
798
  count: number;
788
799
  ids: string[];
789
800
  }
790
- /** `POST /v1/bulk/start` — per-id results plus what the batch as a whole did. */
801
+ /** `POST /v1/bulk/start`: per-id results plus what the batch as a whole did. */
791
802
  interface BulkStartResult {
792
803
  results: {
793
804
  id: string;
@@ -818,7 +829,7 @@ interface CreateProfileBody {
818
829
  proxy_id?: string | null;
819
830
  }
820
831
  /**
821
- * PATCH — all mutable fields optional. `host_mode` and `seed` are fixed at create
832
+ * PATCH, all mutable fields optional. `host_mode` and `seed` are fixed at create
822
833
  * time (C4/C5): a DIFFERING `host_mode` is refused with 400, an unchanged echo is
823
834
  * accepted. Changing a tier requires delete + recreate.
824
835
  */
@@ -836,6 +847,17 @@ interface StartProfileResult {
836
847
  pid: number | null;
837
848
  started_at: number;
838
849
  }
850
+ /** What a takeover request answered.
851
+ *
852
+ * `free` means the profile is yours to start now; `pending` means the machine that
853
+ * held it has been told and is closing its browser, so ask again in a moment.
854
+ * Never start on `pending`: two machines on one identity is what a site reads as
855
+ * a cloned account. */
856
+ interface TakeoverResult {
857
+ state: 'free' | 'pending';
858
+ /** The holder as a person reads it: its label, else a short machine id. */
859
+ holder?: string | null;
860
+ }
839
861
  interface StopProfileResult {
840
862
  stopped: boolean;
841
863
  }
@@ -875,11 +897,11 @@ interface ProxyCheckResult {
875
897
  ja4t_mismatch?: boolean;
876
898
  warnings?: string[];
877
899
  checked_at?: number;
878
- /** Round-trip RTT — `null` on an unreachable exit (a timeout is not a latency). */
900
+ /** Round-trip RTT, `null` on an unreachable exit (a timeout is not a latency). */
879
901
  latency_ms?: number | null;
880
902
  }
881
903
  /**
882
- * Body of `POST /v1/proxies/check` — probe a proxy config that is NOT persisted
904
+ * Body of `POST /v1/proxies/check`: probe a proxy config that is NOT persisted
883
905
  * (health + geo before you commit it).
884
906
  *
885
907
  * Edit-mode: pass the `id` of an existing proxy and omit `username`/`password`
@@ -893,7 +915,7 @@ interface CheckProxyConfigBody {
893
915
  username?: string | null;
894
916
  password?: string | null;
895
917
  rotation?: Rotation;
896
- /** Existing proxy id — enables the stored-credential fallback. */
918
+ /** Existing proxy id; enables the stored-credential fallback. */
897
919
  id?: string | null;
898
920
  }
899
921
  /**
@@ -913,7 +935,7 @@ interface Extension {
913
935
  * dir does not leave every row pointing at nothing.
914
936
  */
915
937
  dir: string;
916
- /** SHA-256 of the unpacked tree — names the CONTENT of this version. */
938
+ /** SHA-256 of the unpacked tree; it names the CONTENT of this version. */
917
939
  content_hash: string;
918
940
  added_at: number;
919
941
  }
@@ -922,7 +944,7 @@ interface Extension {
922
944
  * extensions response; `engine_switches` is what the launch actually emits.
923
945
  *
924
946
  * `id_model` is `"canonical"`: the id comes from the package's key and is the same
925
- * for every profile — deliberately, since it is the id millions of real users
947
+ * for every profile, deliberately, since it is the id millions of real users
926
948
  * report. Only the FILES are per-profile (`delivery: "per_profile_copy"`).
927
949
  */
928
950
  interface ExtensionPolicy {
@@ -937,7 +959,7 @@ interface ExtensionsResult {
937
959
  /** Assigned library ids, as an idempotent set. */
938
960
  extensions: string[];
939
961
  /**
940
- * The set this profile actually loads — ONE version per extension, drawn from the
962
+ * The set this profile actually loads: ONE version per extension, drawn from the
941
963
  * profile's seed over what the library stocks. Shorter than `extensions` when an id
942
964
  * no longer resolves.
943
965
  */
@@ -945,7 +967,7 @@ interface ExtensionsResult {
945
967
  policy: ExtensionPolicy;
946
968
  /**
947
969
  * What is worth knowing about THIS set, judged by the daemon with the same
948
- * function the launch gate uses. Empty for an unremarkable set — including an
970
+ * function the launch gate uses. Empty for an unremarkable set, including an
949
971
  * empty one, since about half of real Chrome users carry no extension.
950
972
  *
951
973
  * Never recompute it client-side: a second opinion could contradict the gate.
@@ -954,7 +976,7 @@ interface ExtensionsResult {
954
976
  }
955
977
  /** One finding about a profile's extension set. */
956
978
  interface ExtensionAdvice {
957
- /** `warn` — a launch is never blocked by an extension. */
979
+ /** `warn`: a launch is never blocked by an extension. */
958
980
  level: string;
959
981
  message: string;
960
982
  }
@@ -967,14 +989,14 @@ declare class ExtensionsApi extends ClientCore {
967
989
  * existing ones (profiles draw their own); re-uploading the same version replaces it.
968
990
  */
969
991
  uploadExtension(crx: Uint8Array | ArrayBuffer): Promise<Extension>;
970
- /** One library entry — the most recently added version. */
992
+ /** One library entry: the most recently added version. */
971
993
  getLibraryExtension(id: string, signal?: AbortSignal): Promise<Extension>;
972
994
  /** Remove EVERY version of a package, its files and every profile's assignment of it. */
973
995
  deleteLibraryExtension(id: string): Promise<unknown>;
974
996
  /**
975
997
  * Remove ONE stocked version.
976
998
  *
977
- * Assignments survive — they name the extension, not the version — unless this
999
+ * Assignments survive, because they name the extension and not the version, unless this
978
1000
  * was the last version, in which case they go with it.
979
1001
  */
980
1002
  deleteLibraryExtensionVersion(id: string, version: string): Promise<unknown>;
@@ -986,58 +1008,6 @@ declare class ExtensionsApi extends ClientCore {
986
1008
  detachExtension(profileId: string, extRef: string): Promise<ExtensionsResult>;
987
1009
  }
988
1010
 
989
- /**
990
- * One stored platform login — everything about it EXCEPT the secrets.
991
- *
992
- * The username IS returned: it is the account's display identity, not a secret on
993
- * any platform, and without it two stored accounts are indistinguishable. The
994
- * password and two-factor key travel only through `revealCredential`, which needs
995
- * the vault password.
996
- */
997
- interface CredentialMeta {
998
- platform: string;
999
- username: string | null;
1000
- login_url: string | null;
1001
- has_password: boolean;
1002
- has_totp: boolean;
1003
- /** Typed into a sign-up form but never confirmed — the account may not exist. */
1004
- pending?: boolean;
1005
- created_at: number;
1006
- updated_at: number;
1007
- last_used_at: number | null;
1008
- /** No longer opens with the current master key: listable, deletable, unusable. */
1009
- secrets_unreadable?: boolean;
1010
- }
1011
- /** An omitted secret means "leave it unchanged", not "delete it". */
1012
- interface PutCredentialBody {
1013
- username?: string | null;
1014
- password?: string | null;
1015
- /** Base32 setup key. Grouped, lower-case input is normalised by the daemon. */
1016
- totp_secret?: string | null;
1017
- login_url?: string | null;
1018
- }
1019
- /** The only shape in this SDK that carries a password. */
1020
- interface RevealedCredential {
1021
- platform: string;
1022
- username: string | null;
1023
- password: string | null;
1024
- totp_secret: string | null;
1025
- }
1026
- /** A passphrase-sealed backup of one profile's logins. */
1027
- interface CredentialBundle {
1028
- bundle: string;
1029
- count: number;
1030
- }
1031
- interface CredentialImportResult {
1032
- /** Boolean, like the session import — the number is in `count`. */
1033
- imported: boolean;
1034
- count: number;
1035
- platforms: string[];
1036
- }
1037
- interface VaultStatus {
1038
- configured: boolean;
1039
- }
1040
-
1041
1011
  /**
1042
1012
  * The account layer: mailboxes, passkeys and the one door a cookie value leaves
1043
1013
  * through.
@@ -1064,7 +1034,7 @@ interface Inbox {
1064
1034
  address_domain: string | null;
1065
1035
  created_at: number;
1066
1036
  /**
1067
- * The stored password could not be decrypted — a restored database without
1037
+ * The stored password could not be decrypted: a restored database without
1068
1038
  * its key. The row stays visible and deletable; every use of it fails closed.
1069
1039
  */
1070
1040
  credentials_unreadable?: boolean;
@@ -1106,7 +1076,7 @@ interface InboxBindings {
1106
1076
  bindings: InboxBinding[];
1107
1077
  }
1108
1078
  /**
1109
- * One passkey of a profile — a login that needs no password.
1079
+ * One passkey of a profile: a login that needs no password.
1110
1080
  *
1111
1081
  * `credential_id` names the row for deletion and nothing else. The private key
1112
1082
  * has no field here and no endpoint: it IS the account, and it could not be
@@ -1120,7 +1090,7 @@ interface PasskeyRow {
1120
1090
  user_display: string | null;
1121
1091
  created_at: number;
1122
1092
  last_used_at: number | null;
1123
- /** True when a stored secret cannot be decrypted — the sign-in WILL fail. */
1093
+ /** True when a stored secret cannot be decrypted; the sign-in WILL fail. */
1124
1094
  secrets_unreadable: boolean;
1125
1095
  /**
1126
1096
  * When the key stopped being usable, if it has. A retired key is never loaded
@@ -1131,7 +1101,7 @@ interface PasskeyRow {
1131
1101
  retired_at: number | null;
1132
1102
  /**
1133
1103
  * `unknown` is a reason this build cannot name, and it deliberately claims
1134
- * nothing — reading it as `operator` would tell you that you had deleted
1104
+ * nothing, because reading it as `operator` would tell you that you had deleted
1135
1105
  * something you never touched.
1136
1106
  */
1137
1107
  retired_reason: 'operator' | 'agent' | 'site_revoked' | 'unknown' | null;
@@ -1154,6 +1124,150 @@ interface RevealCookiesResult {
1154
1124
  domain: string;
1155
1125
  cookies: RevealedCookie[];
1156
1126
  }
1127
+ /** What a stored value is. */
1128
+ type SecretKind = 'api_token' | 'password' | 'recovery_code' | 'totp_seed' | 'private_key' | 'unknown';
1129
+ /** How the layer came to know it. The first three are the honest origins. */
1130
+ type SecretOrigin = 'generated' | 'stored' | 'typed' | 'captured';
1131
+ /** How narrowly it is bound to where it may be used. */
1132
+ type SecretBindingMode = 'domain' | 'host' | 'prefix' | 'exact' | 'off';
1133
+ /** Where it stands between "just seen" and "known good". */
1134
+ type SecretState = 'quarantined' | 'confirmed' | 'doubtful' | 'released';
1135
+ interface SecretRow {
1136
+ id: string;
1137
+ /** The immutable name inside the placeholder. Renaming changes the title. */
1138
+ label: string;
1139
+ display_title?: string | null;
1140
+ /** The placeholder for THIS daemon run. A new run draws a new session part. */
1141
+ secret_ref?: string;
1142
+ kind: SecretKind;
1143
+ origin: SecretOrigin;
1144
+ detected_by?: string | null;
1145
+ binding_mode: SecretBindingMode;
1146
+ binding_value?: string | null;
1147
+ field_bound: boolean;
1148
+ state: SecretState;
1149
+ sole_copy: boolean;
1150
+ /** Only present where the length is the FORMAT's rather than the value's. */
1151
+ length?: number | null;
1152
+ expires_at?: number | null;
1153
+ created_at: number;
1154
+ updated_at: number;
1155
+ last_used_at?: number | null;
1156
+ value_unreadable?: boolean;
1157
+ }
1158
+ interface SecretListResult {
1159
+ secrets: SecretRow[];
1160
+ /** Values still being censored that have no entry, because the list is full. */
1161
+ withheld_without_an_entry: number;
1162
+ layer_enabled: boolean;
1163
+ }
1164
+ /** What may be changed about one entry. The label is deliberately absent. */
1165
+ interface SecretPatchBody {
1166
+ display_title?: string;
1167
+ binding_mode?: SecretBindingMode;
1168
+ binding_value?: string;
1169
+ clear_binding_value?: boolean;
1170
+ field_bound?: boolean;
1171
+ state?: SecretState;
1172
+ expires_at?: number;
1173
+ clear_expires_at?: boolean;
1174
+ }
1175
+ interface SecretRunMention {
1176
+ run_id: string;
1177
+ goal: string;
1178
+ started_at: number;
1179
+ steps: number;
1180
+ }
1181
+ interface SecretDeleteResult {
1182
+ deleted: string;
1183
+ label: string;
1184
+ /** The runs this entry appeared in, so nothing is removed blind. */
1185
+ appeared_in_runs: SecretRunMention[];
1186
+ }
1187
+ interface SecretScrubResult {
1188
+ text: string;
1189
+ /** Which entries were replaced, by label. Never a value. */
1190
+ replaced: string[];
1191
+ }
1192
+ interface SecretRunBody {
1193
+ /** `NAME=<label>` pairs. At least one is required. */
1194
+ env: string[];
1195
+ /** The command and its arguments, already split. Never a shell line. */
1196
+ command: string[];
1197
+ cwd?: string;
1198
+ timeout_secs?: number;
1199
+ }
1200
+ interface SecretRunResult {
1201
+ command: string;
1202
+ exit_code: number | null;
1203
+ stdout: string;
1204
+ stderr: string;
1205
+ values_supplied: string[];
1206
+ }
1207
+
1208
+ /**
1209
+ * One stored platform login: everything about it EXCEPT the secrets.
1210
+ *
1211
+ * The username IS returned: it is the account's display identity, not a secret on
1212
+ * any platform, and without it two stored accounts are indistinguishable. The
1213
+ * password and two-factor key travel only through `revealCredential`, which needs
1214
+ * the vault password.
1215
+ */
1216
+ interface CredentialMeta {
1217
+ platform: string;
1218
+ username: string | null;
1219
+ login_url: string | null;
1220
+ has_password: boolean;
1221
+ has_totp: boolean;
1222
+ /** Typed into a sign-up form but never confirmed, so the account may not exist. */
1223
+ pending?: boolean;
1224
+ created_at: number;
1225
+ updated_at: number;
1226
+ last_used_at: number | null;
1227
+ /** No longer opens with the current master key: listable, deletable, unusable. */
1228
+ secrets_unreadable?: boolean;
1229
+ /** Where this login may be typed (Secret Layer). */
1230
+ binding_mode: SecretBindingMode;
1231
+ binding_value?: string | null;
1232
+ /** Is the field-kind check on for this login? */
1233
+ field_bound: boolean;
1234
+ }
1235
+ /** An omitted secret means "leave it unchanged", not "delete it". */
1236
+ interface PutCredentialBody {
1237
+ username?: string | null;
1238
+ password?: string | null;
1239
+ /** Base32 setup key. Grouped, lower-case input is normalised by the daemon. */
1240
+ totp_secret?: string | null;
1241
+ login_url?: string | null;
1242
+ /**
1243
+ * Where this login may be typed. Absent leaves it as it is, so changing a
1244
+ * password never silently widens a binding.
1245
+ */
1246
+ binding_mode?: SecretBindingMode;
1247
+ binding_value?: string;
1248
+ field_bound?: boolean;
1249
+ }
1250
+ /** The only shape in this SDK that carries a password. */
1251
+ interface RevealedCredential {
1252
+ platform: string;
1253
+ username: string | null;
1254
+ password: string | null;
1255
+ totp_secret: string | null;
1256
+ }
1257
+ /** A passphrase-sealed backup of one profile's logins. */
1258
+ interface CredentialBundle {
1259
+ bundle: string;
1260
+ count: number;
1261
+ }
1262
+ interface CredentialImportResult {
1263
+ /** Boolean, like the session import; the number is in `count`. */
1264
+ imported: boolean;
1265
+ count: number;
1266
+ platforms: string[];
1267
+ }
1268
+ interface VaultStatus {
1269
+ configured: boolean;
1270
+ }
1157
1271
 
1158
1272
  declare class IdentityApi extends ClientCore {
1159
1273
  /** Which platforms this profile can log into. Never carries a secret. */
@@ -1161,7 +1275,7 @@ declare class IdentityApi extends ClientCore {
1161
1275
  /**
1162
1276
  * Store or update one login.
1163
1277
  *
1164
- * An omitted secret keeps its stored value rather than clearing it — an edit form
1278
+ * An omitted secret keeps its stored value rather than clearing it, because an edit form
1165
1279
  * never saw the password in the clear, so it cannot resend one; delete the row to
1166
1280
  * remove a credential. `totp_secret` may be pasted exactly as a site presents it
1167
1281
  * (grouped, lower case): it is normalised and test-decoded by the daemon, so a
@@ -1177,7 +1291,7 @@ declare class IdentityApi extends ClientCore {
1177
1291
  *
1178
1292
  * `password` is deliberately separate from the vault password: a backup gets
1179
1293
  * handed to another machine, and that must not also hand over daemon access. This
1180
- * is the answer to a lost master key — a daemon-generated password exists nowhere
1294
+ * is the answer to a lost master key: a daemon-generated password exists nowhere
1181
1295
  * else.
1182
1296
  */
1183
1297
  exportCredentials(profileId: string, vaultPassword: string, password: string): Promise<CredentialBundle>;
@@ -1206,6 +1320,37 @@ declare class IdentityApi extends ClientCore {
1206
1320
  * a headstone, the second clears the headstone for good.
1207
1321
  */
1208
1322
  deletePasskey(profileId: string, credentialId: string): Promise<unknown>;
1323
+ /** The entries this profile keeps, with the placeholder that stands for each. */
1324
+ listSecrets(profileId: string, signal?: AbortSignal): Promise<SecretListResult>;
1325
+ /** Change a title, a binding, or the state. Never the label. */
1326
+ updateSecret(profileId: string, secretId: string, body: SecretPatchBody): Promise<SecretRow>;
1327
+ /** Delete an entry. The reply names the runs it appeared in. */
1328
+ deleteSecret(profileId: string, secretId: string): Promise<SecretDeleteResult>;
1329
+ /**
1330
+ * Filter a text you hold against this profile's values.
1331
+ *
1332
+ * The SDK path exists because censoring only makes sense where a MODEL is
1333
+ * reading: your own code is not, and a placeholder in the middle of it would
1334
+ * break parsing. So the daemon offers the filter as a call rather than
1335
+ * applying it to a channel it does not own.
1336
+ */
1337
+ scrubText(profileId: string, text: string): Promise<SecretScrubResult>;
1338
+ /**
1339
+ * Run a command with named values in its environment.
1340
+ *
1341
+ * The daemon starts the child, so no value crosses a socket. At least one
1342
+ * `env` entry is required: without the rule an `npm publish` would carry every
1343
+ * value of the profile.
1344
+ */
1345
+ runWithSecrets(profileId: string, body: SecretRunBody): Promise<SecretRunResult>;
1346
+ /** Is the secret layer on? It is by default. */
1347
+ getSecretLayer(signal?: AbortSignal): Promise<{
1348
+ enabled: boolean;
1349
+ }>;
1350
+ /** Turn the secret layer on or off for the whole daemon. */
1351
+ setSecretLayer(enabled: boolean): Promise<{
1352
+ enabled: boolean;
1353
+ }>;
1209
1354
  /**
1210
1355
  * The one door a cookie VALUE leaves through, and it needs the vault password.
1211
1356
  *
@@ -1221,7 +1366,7 @@ declare class IdentityApi extends ClientCore {
1221
1366
  * All of it is display: nothing here starts, stops or changes anything.
1222
1367
  *
1223
1368
  * `RunActor`, `RunOutcome`, `StepKind`, `StepTarget`, `RunStep` and
1224
- * `ProfileActivity` are NOT redeclared here — they live in `types.ts` because
1369
+ * `ProfileActivity` are NOT redeclared here; they live in `types.ts` because
1225
1370
  * the live event stream carries them, and the run list describes the same rows.
1226
1371
  * A second copy would let the two drift apart while both looked right.
1227
1372
  *
@@ -1239,7 +1384,7 @@ interface AgentRun {
1239
1384
  profile_id: string;
1240
1385
  profile_name: string;
1241
1386
  actor: RunActor;
1242
- /** Never empty — described when it was not declared (see `goal_source`). */
1387
+ /** Never empty; described when it was not declared (see `goal_source`). */
1243
1388
  goal: string;
1244
1389
  goal_source: GoalSource;
1245
1390
  /**
@@ -1280,7 +1425,7 @@ declare class RunsApi extends ClientCore {
1280
1425
  listRuns(params?: ListRunsParams, signal?: AbortSignal): Promise<AgentRun[]>;
1281
1426
  /** One run. */
1282
1427
  getRun(runId: string, signal?: AbortSignal): Promise<AgentRun>;
1283
- /** A run's steps, oldest first — the order they happened in. */
1428
+ /** A run's steps, oldest first: the order they happened in. */
1284
1429
  listRunSteps(runId: string, params?: ListStepsParams, signal?: AbortSignal): Promise<RunStep[]>;
1285
1430
  /**
1286
1431
  * The still taken at one step, as JPEG bytes.
@@ -1294,7 +1439,7 @@ declare class RunsApi extends ClientCore {
1294
1439
  }
1295
1440
 
1296
1441
  /**
1297
- * Direct-CDP driver (DEC-006, AC-FP-005) — a minimal, nodriver-style Chrome
1442
+ * Direct-CDP driver (DEC-006, AC-FP-005): a minimal, nodriver-style Chrome
1298
1443
  * DevTools Protocol client over a raw websocket. This is the recommended SDK
1299
1444
  * driver plane: it is NOT the Playwright/Puppeteer control plane (which is a
1300
1445
  * detection vector independent of patch quality). We never call `Runtime.enable`
@@ -1328,7 +1473,7 @@ declare class CdpConnection {
1328
1473
  request<T>(method: string, params?: Record<string, unknown>, sessionId?: string): Promise<T>;
1329
1474
  subscribe(cb: (event: CdpEvent) => void): () => void;
1330
1475
  /** Register a callback fired once when the connection closes (immediately if
1331
- * it already has) — event streams use this to end instead of hanging. */
1476
+ * it already has); event streams use this to end instead of hanging. */
1332
1477
  onClose(cb: () => void): () => void;
1333
1478
  close(): void;
1334
1479
  get closed(): boolean;
@@ -1357,7 +1502,7 @@ interface ClickOptions {
1357
1502
  button?: string;
1358
1503
  clickCount?: number;
1359
1504
  /**
1360
- * B5: element-relative targeting — the effective target width (an element's
1505
+ * B5: element-relative targeting. The effective target width (an element's
1361
1506
  * bounding-box size). The daemon's Fitts-law approach lands within the element
1362
1507
  * instead of on a fixed corner. Prefer {@link CdpSession.humanizeClickElement}.
1363
1508
  */
@@ -1472,7 +1617,7 @@ interface Metrics {
1472
1617
  availability?: MetricsAvailability;
1473
1618
  profiles?: ProfileResource[];
1474
1619
  /**
1475
- * Launchable host memory (MiB) — the capacity gate's own reading. "How many
1620
+ * Launchable host memory (MiB), the capacity gate's own reading. "How many
1476
1621
  * more browsers fit" derives from THIS; `ram_budget_mb − ram_used_mb` does
1477
1622
  * not subtract (used is host-wide, the budget is the daemon's own ceiling).
1478
1623
  */
@@ -1480,11 +1625,11 @@ interface Metrics {
1480
1625
  }
1481
1626
 
1482
1627
  /**
1483
- * `ScalebrowserClient` — the one typed HTTP surface every REST call goes
1628
+ * `ScalebrowserClient`: the one typed HTTP surface every REST call goes
1484
1629
  * through. It centralises the base URL, Bearer auth, query-string building, JSON
1485
1630
  * (de)serialisation and error mapping (`{ code, message }` → {@link ApiError}).
1486
1631
  * Backend endpoint drift is a change in THIS file (paths) plus `types.ts`
1487
- * (shapes) — nowhere else.
1632
+ * (shapes), nowhere else.
1488
1633
  */
1489
1634
 
1490
1635
  /** Mirrors `CapacityConfig::default()` (`crates/core/src/config.rs`). */
@@ -1501,7 +1646,7 @@ interface LaunchHandle {
1501
1646
  readonly result: StartProfileResult;
1502
1647
  /** Close the CDP connection and stop the profile. */
1503
1648
  stop(): Promise<void>;
1504
- /** `await using` support — calls {@link stop}. */
1649
+ /** `await using` support; calls {@link stop}. */
1505
1650
  [Symbol.asyncDispose](): Promise<void>;
1506
1651
  }
1507
1652
  /** Fallback: compute what we can purely from profile runtime states. */
@@ -1509,7 +1654,7 @@ declare function deriveMetricsFromProfiles(profiles: Profile[]): Metrics;
1509
1654
  declare class ScalebrowserClient extends ClientCore {
1510
1655
  listProfiles(params?: ListProfilesParams, signal?: AbortSignal): Promise<Profile[]>;
1511
1656
  /**
1512
- * Every id matching `params`, unpaged — what "act on all matches" needs.
1657
+ * Every id matching `params`, unpaged: what "act on all matches" needs.
1513
1658
  *
1514
1659
  * `listProfiles` is paged, so acting on "everything" from it only ever covers the
1515
1660
  * page you fetched. Asking for ids costs one request and no persona payloads.
@@ -1522,6 +1667,12 @@ declare class ScalebrowserClient extends ClientCore {
1522
1667
  /** Start a profile → CDP ws endpoint. Errors: 4002/4003/4005/4006/4008. */
1523
1668
  startProfile(id: string, body?: StartProfileBody): Promise<StartProfileResult>;
1524
1669
  stopProfile(id: string): Promise<StopProfileResult>;
1670
+ /** Ask for a profile that is open on another machine of this account.
1671
+ *
1672
+ * Closes nothing here and nothing there: the control plane revokes the holder's
1673
+ * right, the holder closes its own browser at its next heartbeat. Start only
1674
+ * after this answered `free`. Errors: 4012 when it is held elsewhere. */
1675
+ takeoverProfile(id: string): Promise<TakeoverResult>;
1525
1676
  bulkCreateProfiles(body: BulkCreateBody): Promise<Profile[]>;
1526
1677
  /**
1527
1678
  * Start a batch. `headless` is the ONE visibility decision for the run; omitted
@@ -1565,7 +1716,7 @@ declare class ScalebrowserClient extends ClientCore {
1565
1716
  /** Health + geo check (exit-ip/country/healthy + JA4↔JA4T verdict). */
1566
1717
  checkProxy(id: string): Promise<ProxyCheckResult>;
1567
1718
  /**
1568
- * Probe a proxy config WITHOUT persisting it — validate before you commit.
1719
+ * Probe a proxy config WITHOUT persisting it: validate before you commit.
1569
1720
  * Pass `id` (and omit the credentials) to probe an existing proxy's stored,
1570
1721
  * write-only credentials in an edit form.
1571
1722
  */
@@ -1597,9 +1748,9 @@ interface ScalebrowserClient extends IdentityApi, RunsApi, ControlApi, Extension
1597
1748
  }
1598
1749
 
1599
1750
  /**
1600
- * `@scalebrowser/sdk` — the official Node/TypeScript SDK for the Scalebrowser
1751
+ * `@scalebrowser/sdk`: the official Node/TypeScript SDK for the Scalebrowser
1601
1752
  * daemon. A typed REST client plus a direct-CDP driver plane (nodriver-style,
1602
- * NOT Playwright — DEC-006).
1753
+ * NOT Playwright, DEC-006).
1603
1754
  *
1604
1755
  * ```ts
1605
1756
  * import { ScalebrowserClient } from '@scalebrowser/sdk';
@@ -1615,4 +1766,4 @@ interface ScalebrowserClient extends IdentityApi, RunsApi, ControlApi, Extension
1615
1766
 
1616
1767
  declare const VERSION = "0.3.0";
1617
1768
 
1618
- export { type Account, type ActivitySnapshot, type AgentRun, ApiError, type ApiErrorBody, type ArtifactBytes, type ArtifactPutResult, type AttachOptions, type AuditDetectorReport, type AuditReport, type AuditStatus, type AuditVerdict, type BindInboxBody, type CdpConnectOptions, CdpError, type CdpEvent, CdpSession, type ClickOptions, type CreateGroupBody, type CreateInboxBody, type CreatePresetBody, DEFAULT_CAPACITY, type DeleteInterruptionRuleParams, type EffectiveInterruptionLock, ErrorCode, type ErrorCodeValue, type EvaluateOptions, type FetchLike, GEO_MODES, type GeoMode, type GoalSource, type Group, HOST_MODES, type HealthStatus, type HostMode, type Inbox, type InboxBinding, type InboxBindings, type InboxChannel, type InputClient, type InterruptionChoice, type InterruptionLock, type InterruptionLockRow, type InterruptionLockView, type InterruptionRuleRow, type LaunchHandle, type ListRunsParams, type ListStepsParams, type NavigateOptions, NetworkError, type OsFamily, type OutcomeSource, PROXY_KINDS, type PasskeyRow, type PersonaConstraintOptions, type Preset, type PresetConfig, type PresetConstraints, type Profile, type ProfileActivity, type ProtectionLevel, type ProtectionStatus, type Proxy, type ProxyKind, ROTATIONS, RUNTIME_STATES, type ReadyStatus, type RevealCookiesBody, type RevealCookiesResult, type RevealedCookie, type Rotation, type RunActor, type RunOutcome, type RunStep, type RuntimeState, ScalebrowserClient, type ScalebrowserClientOptions, ScalebrowserError, type ScrollOptions, type SessionExportBody, type SessionExportResult, type SessionImportBody, type SessionKind, type SetInterruptionLockBody, type SetInterruptionRuleBody, type StepKind, type StepTarget, type StreamHandlers, type StreamParams, type StreamStatus, type TrustedInputBody, type UpdateGroupBody, type UpdateInboxBody, type UpdatePresetBody, VERSION, deriveMetricsFromProfiles, errorMessage, eventStream, openCdpSession, parseSseFrame, subscribeEvents };
1769
+ export { type Account, type ActivitySnapshot, type AgentRun, ApiError, type ApiErrorBody, type ArtifactBytes, type ArtifactPutResult, type AttachOptions, type AuditDetectorReport, type AuditReport, type AuditStatus, type AuditVerdict, type BindInboxBody, type CdpConnectOptions, CdpError, type CdpEvent, CdpSession, type ClickOptions, type CreateGroupBody, type CreateInboxBody, type CreatePresetBody, DEFAULT_CAPACITY, type DeleteInterruptionRuleParams, type EffectiveInterruptionLock, ErrorCode, type ErrorCodeValue, type EvaluateOptions, type FetchLike, GEO_MODES, type GeoMode, type GoalSource, type Group, HOST_MODES, type HealthStatus, type HostMode, type Inbox, type InboxBinding, type InboxBindings, type InboxChannel, type InputClient, type InterruptionChoice, type InterruptionLock, type InterruptionLockRow, type InterruptionLockView, type InterruptionRuleRow, type LaunchHandle, type ListRunsParams, type ListStepsParams, type NavigateOptions, NetworkError, type OsFamily, type OutcomeSource, PROXY_KINDS, type PasskeyRow, type PersonaConstraintOptions, type Preset, type PresetConfig, type PresetConstraints, type Profile, type ProfileActivity, type ProtectionLevel, type ProtectionStatus, type Proxy, type ProxyKind, ROTATIONS, RUNTIME_STATES, type ReadyStatus, type RevealCookiesBody, type RevealCookiesResult, type RevealedCookie, type Rotation, type RunActor, type RunOutcome, type RunStep, type RuntimeState, ScalebrowserClient, type ScalebrowserClientOptions, ScalebrowserError, type ScrollOptions, type SecretBindingMode, type SecretDeleteResult, type SecretKind, type SecretListResult, type SecretOrigin, type SecretPatchBody, type SecretRow, type SecretRunBody, type SecretRunMention, type SecretRunResult, type SecretScrubResult, type SecretState, type SessionExportBody, type SessionExportResult, type SessionImportBody, type SessionKind, type SetInterruptionLockBody, type SetInterruptionRuleBody, type StepKind, type StepTarget, type StreamHandlers, type StreamParams, type StreamStatus, type TrustedInputBody, type UpdateGroupBody, type UpdateInboxBody, type UpdatePresetBody, VERSION, deriveMetricsFromProfiles, errorMessage, eventStream, openCdpSession, parseSseFrame, subscribeEvents };