@scalebrowser/sdk 0.2.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/README.md +29 -23
- package/dist/index.cjs +109 -22
- package/dist/index.d.cts +272 -116
- package/dist/index.d.ts +272 -116
- package/dist/index.js +109 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -59,50 +59,50 @@ try {
|
|
|
59
59
|
|
|
60
60
|
Every `/v1` endpoint is a typed method on `ScalebrowserClient`:
|
|
61
61
|
|
|
62
|
-
- **Profiles
|
|
62
|
+
- **Profiles**: `listProfiles`, `getProfile`, `createProfile`, `updateProfile`,
|
|
63
63
|
`deleteProfile`, `startProfile`, `stopProfile`
|
|
64
|
-
- **Bulk
|
|
64
|
+
- **Bulk**: `bulkCreateProfiles`, `bulkStart`, `bulkStop`, `bulkDelete`,
|
|
65
65
|
`bulkAssignProxy`
|
|
66
|
-
- **Groups / Presets
|
|
66
|
+
- **Groups / Presets**: `listGroups`/`createGroup`/`getGroup`/`updateGroup`/`deleteGroup`,
|
|
67
67
|
`listPresets`/`createPreset`/`getPreset`/`updatePreset`/`deletePreset`,
|
|
68
68
|
`getPersonaConstraints`. A preset is `config` (what the profiles do:
|
|
69
69
|
`geo_mode`, `proxy_id`, …) plus `constraints` (what they are: `country`, which
|
|
70
70
|
pins the persona's language, timezone and voices). Both are typed and the daemon
|
|
71
|
-
refuses an unknown key with a 400
|
|
71
|
+
refuses an unknown key with a 400, so read the valid regions from
|
|
72
72
|
`getPersonaConstraints()` rather than hardcoding them.
|
|
73
|
-
- **Proxies
|
|
73
|
+
- **Proxies**: `listProxies`, `createProxy`, `getProxy`, `updateProxy`,
|
|
74
74
|
`deleteProxy`, `checkProxy`, `checkProxyConfig` (probe a config before you save
|
|
75
|
-
it; pass `id` to reuse an existing proxy's stored credentials)
|
|
75
|
+
it; pass `id` to reuse an existing proxy's stored credentials). Credentials
|
|
76
76
|
are write-only, never returned
|
|
77
|
-
- **Extensions
|
|
77
|
+
- **Extensions**: `listExtensions`, `attachExtension`, `detachExtension`, plus
|
|
78
78
|
the daemon-wide library (`uploadExtension`, `getLibraryExtension`,
|
|
79
79
|
`deleteLibraryExtension`). An attached package IS loaded into the browser at
|
|
80
80
|
launch, under the canonical Web-Store id its own key derives
|
|
81
|
-
- **Credentials
|
|
81
|
+
- **Credentials**: `listCredentials`, `putCredential`, `revealCredential`
|
|
82
82
|
(needs the vault password), `exportCredentials`, `importCredentials`
|
|
83
|
-
- **Cookies
|
|
83
|
+
- **Cookies**: `revealCookies`, the one route a cookie VALUE leaves through,
|
|
84
84
|
behind the same vault password
|
|
85
|
-
- **Sessions
|
|
86
|
-
- **Mailboxes
|
|
87
|
-
`getInboxBindings`, `bindInbox`, `unbindInbox
|
|
85
|
+
- **Sessions**: `exportSession`, `importSession`
|
|
86
|
+
- **Mailboxes**: `listInboxes`, `createInbox`, `updateInbox`, `deleteInbox`,
|
|
87
|
+
`getInboxBindings`, `bindInbox`, `unbindInbox`, which is where a profile's
|
|
88
88
|
confirmation codes arrive
|
|
89
|
-
- **Passkeys
|
|
89
|
+
- **Passkeys**: `listPasskeys`, `deletePasskey`. Metadata only: the private key
|
|
90
90
|
has no field and no endpoint
|
|
91
|
-
- **Agent runs
|
|
91
|
+
- **Agent runs**: `listRuns`, `getRun`, `listRunSteps`, `getRunShot`,
|
|
92
92
|
`getActivity`. Read-only, all of it
|
|
93
|
-
- **Interruptions
|
|
94
|
-
`listInterruptionRules`, `setInterruptionRule`, `deleteInterruptionRule
|
|
93
|
+
- **Interruptions**: `listInterruptionLocks`, `setInterruptionLock`,
|
|
94
|
+
`listInterruptionRules`, `setInterruptionRule`, `deleteInterruptionRule`: who
|
|
95
95
|
may answer when the browser asks something
|
|
96
|
-
- **Artifacts
|
|
96
|
+
- **Artifacts**: `putArtifact` (hand the daemon a file to upload later),
|
|
97
97
|
`getArtifact` (fetch a screenshot, download or saved PDF as bytes)
|
|
98
|
-
- **Input
|
|
99
|
-
- **Metrics / Account / Health
|
|
98
|
+
- **Input**: `sendInput`
|
|
99
|
+
- **Metrics / Account / Health**: `getMetrics`, `getAccount`, `health`, `ready`.
|
|
100
100
|
The first two answer 404 on a daemon without them, which the SDK treats as
|
|
101
101
|
information rather than as an error: metrics are then derived from profile
|
|
102
102
|
state, and the account reads `licensed: false`, which is what "self-hosted, no
|
|
103
103
|
control plane" means
|
|
104
104
|
|
|
105
|
-
Errors map to typed exceptions carrying the daemon's numeric code (4001–
|
|
105
|
+
Errors map to typed exceptions carrying the daemon's numeric code (4001–4012):
|
|
106
106
|
|
|
107
107
|
```ts
|
|
108
108
|
import { ApiError, ErrorCode } from '@scalebrowser/sdk';
|
|
@@ -111,7 +111,7 @@ try {
|
|
|
111
111
|
await sb.startProfile(id);
|
|
112
112
|
} catch (err) {
|
|
113
113
|
if (err instanceof ApiError && err.code === ErrorCode.Capacity) {
|
|
114
|
-
// 4003
|
|
114
|
+
// 4003: capacity exceeded
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
```
|
|
@@ -136,11 +136,11 @@ for await (const e of sb.events()) {
|
|
|
136
136
|
|
|
137
137
|
`CdpSession` (returned by `connectCdp` / `launch`) gives you:
|
|
138
138
|
|
|
139
|
-
- `send<T>(method, params?)
|
|
139
|
+
- `send<T>(method, params?)`: raw CDP command, awaited by id (concurrent-safe)
|
|
140
140
|
- `navigate(url, { wait, timeout })`, `evaluate<T>(expr, { isolated })`
|
|
141
141
|
- `createIsolatedWorld(frameId?, worldName?)`
|
|
142
142
|
- `attachToPage({ targetId?, create?, url? })`
|
|
143
|
-
- `on(method, cb)` / `events()
|
|
143
|
+
- `on(method, cb)` / `events()`: CDP event subscription scoped to the session
|
|
144
144
|
- `humanizeMove` / `humanizeClick` / `humanizeType` / `humanizeScroll`
|
|
145
145
|
- `close()`
|
|
146
146
|
|
|
@@ -149,6 +149,12 @@ for await (const e of sb.events()) {
|
|
|
149
149
|
- Bearer token is sent on every request and the SSE/CDP handshakes; it is
|
|
150
150
|
**never logged** (the client's inspect output masks it).
|
|
151
151
|
- Proxy credentials are injected by the daemon and never travel over CDP.
|
|
152
|
+
- **The CDP endpoint is guarded by the OS user, not by that token.** The engine's
|
|
153
|
+
DevTools port has no authentication of its own: it answers a bogus bearer with
|
|
154
|
+
`200`, measured, so the engine drops any connection whose peer process runs as
|
|
155
|
+
a different user. Nothing to configure and nothing to pass: your process is the
|
|
156
|
+
one that started the profile, so it is on the allowed side. A helper running as
|
|
157
|
+
another account will not get in, by design.
|
|
152
158
|
|
|
153
159
|
## Develop
|
|
154
160
|
|
package/dist/index.cjs
CHANGED
|
@@ -21,7 +21,17 @@ var ErrorCode = {
|
|
|
21
21
|
* Distinct from Capacity (4003 = this machine is full, wait): the caller's move
|
|
22
22
|
* is to stop a running browser anywhere or upgrade the plan. */
|
|
23
23
|
ConcurrencyLimit: 4008,
|
|
24
|
-
Unauthorized: 4010
|
|
24
|
+
Unauthorized: 4010,
|
|
25
|
+
/** No account is connected to this machine, so nothing may run (DEC-014).
|
|
26
|
+
* Distinct from Unauthorized (4010 = the daemon's own bearer token is wrong, so
|
|
27
|
+
* re-read the token): 4011 means the machine needs to be signed in, and no token
|
|
28
|
+
* a client holds can substitute for that. Connect it in the desktop app. */
|
|
29
|
+
NotSignedIn: 4011,
|
|
30
|
+
/** This ONE profile is open on another machine of the same account (DEC-015).
|
|
31
|
+
* Distinct from ConcurrencyLimit (4008 = the plan is full, buy more or free any
|
|
32
|
+
* browser): the caller's move here costs nothing. Close it on that machine, or
|
|
33
|
+
* take it over from the app running there. */
|
|
34
|
+
ProfileInUse: 4012
|
|
25
35
|
};
|
|
26
36
|
var CODE_LABELS = {
|
|
27
37
|
4001: "Not found",
|
|
@@ -31,7 +41,9 @@ var CODE_LABELS = {
|
|
|
31
41
|
4005: "Launch preflight failed",
|
|
32
42
|
4006: "Profile already running",
|
|
33
43
|
4008: "Concurrent-browser limit reached (subscription-wide)",
|
|
34
|
-
4010: "Unauthorized"
|
|
44
|
+
4010: "Unauthorized",
|
|
45
|
+
4011: "No account connected to this machine",
|
|
46
|
+
4012: "This profile is open on another machine"
|
|
35
47
|
};
|
|
36
48
|
var ScalebrowserError = class extends Error {
|
|
37
49
|
constructor(message) {
|
|
@@ -133,7 +145,7 @@ var ClientCore = class {
|
|
|
133
145
|
return text ? JSON.parse(text) : void 0;
|
|
134
146
|
}
|
|
135
147
|
/**
|
|
136
|
-
* A route that answers with bytes, not JSON
|
|
148
|
+
* A route that answers with bytes, not JSON: artifacts and run stills.
|
|
137
149
|
*
|
|
138
150
|
* Separate from {@link ClientCore.request} rather than a flag on it, because the two
|
|
139
151
|
* differ in the error path as well: a failed byte fetch still answers JSON,
|
|
@@ -209,11 +221,12 @@ function enc(id) {
|
|
|
209
221
|
}
|
|
210
222
|
|
|
211
223
|
// src/client-control.ts
|
|
212
|
-
var
|
|
224
|
+
var NO_ACCOUNT = {
|
|
213
225
|
licensed: false,
|
|
226
|
+
signed_in: false,
|
|
214
227
|
running_local: 0,
|
|
215
228
|
profiles_local: 0,
|
|
216
|
-
permits_launch:
|
|
229
|
+
permits_launch: false
|
|
217
230
|
};
|
|
218
231
|
var ControlApi = class extends ClientCore {
|
|
219
232
|
// ── Interruptions ──────────────────────────────────────────────────────────
|
|
@@ -250,7 +263,7 @@ var ControlApi = class extends ClientCore {
|
|
|
250
263
|
});
|
|
251
264
|
}
|
|
252
265
|
/**
|
|
253
|
-
* Fetch one artifact's bytes
|
|
266
|
+
* Fetch one artifact's bytes: a screenshot, a download, a saved PDF.
|
|
254
267
|
*
|
|
255
268
|
* A miss is a plain 404 whether the id never existed, expired, or belonged to
|
|
256
269
|
* a released lease: the caller's next move is the same in all three cases.
|
|
@@ -263,14 +276,14 @@ var ControlApi = class extends ClientCore {
|
|
|
263
276
|
* Licence state for display. The launch gate stays the authority on starts.
|
|
264
277
|
*
|
|
265
278
|
* A daemon predating the route answers 404, and that is not an error worth
|
|
266
|
-
* throwing
|
|
267
|
-
*
|
|
279
|
+
* throwing, but it is read pessimistically: nothing can be shown to be
|
|
280
|
+
* connected or permitted. Same shape of tolerance as {@link getMetrics}.
|
|
268
281
|
*/
|
|
269
282
|
async getAccount(signal) {
|
|
270
283
|
try {
|
|
271
284
|
return await this.request("GET", "/v1/account", void 0, { signal });
|
|
272
285
|
} catch (err) {
|
|
273
|
-
if (err instanceof ApiError && err.status === 404) return { ...
|
|
286
|
+
if (err instanceof ApiError && err.status === 404) return { ...NO_ACCOUNT };
|
|
274
287
|
throw err;
|
|
275
288
|
}
|
|
276
289
|
}
|
|
@@ -278,7 +291,7 @@ var ControlApi = class extends ClientCore {
|
|
|
278
291
|
health(signal) {
|
|
279
292
|
return this.request("GET", "/health", void 0, { signal });
|
|
280
293
|
}
|
|
281
|
-
/** "Can it serve?" Local facts only
|
|
294
|
+
/** "Can it serve?" Local facts only; the control plane is deliberately not consulted. */
|
|
282
295
|
ready(signal) {
|
|
283
296
|
return this.request("GET", "/health/ready", void 0, { signal });
|
|
284
297
|
}
|
|
@@ -290,7 +303,7 @@ var ExtensionsApi = class extends ClientCore {
|
|
|
290
303
|
//
|
|
291
304
|
// Upload a `.crx`; the daemon lifts its public key out of the CRX header and
|
|
292
305
|
// writes it into the unpacked `manifest.json`, so every profile loads the
|
|
293
|
-
// package under its CANONICAL Web-Store id. A key-less package is refused
|
|
306
|
+
// package under its CANONICAL Web-Store id. A key-less package is refused, since it
|
|
294
307
|
// would take a path-derived id, identical across the fleet.
|
|
295
308
|
/** The library, newest first. */
|
|
296
309
|
listLibraryExtensions(signal) {
|
|
@@ -303,7 +316,7 @@ var ExtensionsApi = class extends ClientCore {
|
|
|
303
316
|
uploadExtension(crx) {
|
|
304
317
|
return this.request("POST", "/v1/extensions", crx);
|
|
305
318
|
}
|
|
306
|
-
/** One library entry
|
|
319
|
+
/** One library entry: the most recently added version. */
|
|
307
320
|
getLibraryExtension(id, signal) {
|
|
308
321
|
return this.request("GET", `/v1/extensions/${enc(id)}`, void 0, { signal });
|
|
309
322
|
}
|
|
@@ -314,7 +327,7 @@ var ExtensionsApi = class extends ClientCore {
|
|
|
314
327
|
/**
|
|
315
328
|
* Remove ONE stocked version.
|
|
316
329
|
*
|
|
317
|
-
* Assignments survive
|
|
330
|
+
* Assignments survive, because they name the extension and not the version, unless this
|
|
318
331
|
* was the last version, in which case they go with it.
|
|
319
332
|
*/
|
|
320
333
|
deleteLibraryExtensionVersion(id, version) {
|
|
@@ -353,14 +366,14 @@ var IdentityApi = class extends ClientCore {
|
|
|
353
366
|
// ── Platform credentials ────────────────────────────────────────────────────
|
|
354
367
|
//
|
|
355
368
|
// Stored logins, so an agent can sign a profile into a platform WITHOUT ever
|
|
356
|
-
// holding the password
|
|
369
|
+
// holding the password: the daemon decrypts and types it. Only `revealCredential`
|
|
357
370
|
// and the bundle calls return plaintext, and every one of them needs the vault
|
|
358
371
|
// password: the bearer token alone is not enough, because the MCP agent layer
|
|
359
372
|
// authenticates with exactly the same one.
|
|
360
373
|
//
|
|
361
374
|
// `platform` is whatever you have: the service's domain ("discord.com"), its
|
|
362
375
|
// name ("Discord") or a host under it ("www.discord.com"). The daemon resolves
|
|
363
|
-
// all of them to ONE key
|
|
376
|
+
// all of them to ONE key (the registrable domain), and every response echoes
|
|
364
377
|
// that key, so `listCredentials` and a later `deleteCredential` agree. Pass a
|
|
365
378
|
// whole sign-in URL only to the MCP tools: here the platform is a path segment,
|
|
366
379
|
// and a `/` in it is refused rather than read as a path.
|
|
@@ -376,7 +389,7 @@ var IdentityApi = class extends ClientCore {
|
|
|
376
389
|
/**
|
|
377
390
|
* Store or update one login.
|
|
378
391
|
*
|
|
379
|
-
* An omitted secret keeps its stored value rather than clearing it
|
|
392
|
+
* An omitted secret keeps its stored value rather than clearing it, because an edit form
|
|
380
393
|
* never saw the password in the clear, so it cannot resend one; delete the row to
|
|
381
394
|
* remove a credential. `totp_secret` may be pasted exactly as a site presents it
|
|
382
395
|
* (grouped, lower case): it is normalised and test-decoded by the daemon, so a
|
|
@@ -409,7 +422,7 @@ var IdentityApi = class extends ClientCore {
|
|
|
409
422
|
*
|
|
410
423
|
* `password` is deliberately separate from the vault password: a backup gets
|
|
411
424
|
* handed to another machine, and that must not also hand over daemon access. This
|
|
412
|
-
* is the answer to a lost master key
|
|
425
|
+
* is the answer to a lost master key: a daemon-generated password exists nowhere
|
|
413
426
|
* else.
|
|
414
427
|
*/
|
|
415
428
|
exportCredentials(profileId, vaultPassword, password) {
|
|
@@ -481,6 +494,72 @@ var IdentityApi = class extends ClientCore {
|
|
|
481
494
|
deletePasskey(profileId, credentialId) {
|
|
482
495
|
return this.request("DELETE", `/v1/profiles/${enc(profileId)}/passkeys/${enc(credentialId)}`);
|
|
483
496
|
}
|
|
497
|
+
// ── Secret Layer ───────────────────────────────────────────────────────────
|
|
498
|
+
//
|
|
499
|
+
// Values a profile holds that no agent ever reads. Nothing here returns a
|
|
500
|
+
// value, and that is not an oversight: the wrapper below starts the command
|
|
501
|
+
// INSIDE the daemon precisely so that no route has to hand plaintext out.
|
|
502
|
+
/** The entries this profile keeps, with the placeholder that stands for each. */
|
|
503
|
+
listSecrets(profileId, signal) {
|
|
504
|
+
return this.request(
|
|
505
|
+
"GET",
|
|
506
|
+
`/v1/profiles/${enc(profileId)}/secrets`,
|
|
507
|
+
void 0,
|
|
508
|
+
{ signal }
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
/** Change a title, a binding, or the state. Never the label. */
|
|
512
|
+
updateSecret(profileId, secretId, body) {
|
|
513
|
+
return this.request(
|
|
514
|
+
"PATCH",
|
|
515
|
+
`/v1/profiles/${enc(profileId)}/secrets/${enc(secretId)}`,
|
|
516
|
+
body
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
/** Delete an entry. The reply names the runs it appeared in. */
|
|
520
|
+
deleteSecret(profileId, secretId) {
|
|
521
|
+
return this.request(
|
|
522
|
+
"DELETE",
|
|
523
|
+
`/v1/profiles/${enc(profileId)}/secrets/${enc(secretId)}`
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Filter a text you hold against this profile's values.
|
|
528
|
+
*
|
|
529
|
+
* The SDK path exists because censoring only makes sense where a MODEL is
|
|
530
|
+
* reading: your own code is not, and a placeholder in the middle of it would
|
|
531
|
+
* break parsing. So the daemon offers the filter as a call rather than
|
|
532
|
+
* applying it to a channel it does not own.
|
|
533
|
+
*/
|
|
534
|
+
scrubText(profileId, text) {
|
|
535
|
+
return this.request(
|
|
536
|
+
"POST",
|
|
537
|
+
`/v1/profiles/${enc(profileId)}/secrets/scrub`,
|
|
538
|
+
{ text }
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Run a command with named values in its environment.
|
|
543
|
+
*
|
|
544
|
+
* The daemon starts the child, so no value crosses a socket. At least one
|
|
545
|
+
* `env` entry is required: without the rule an `npm publish` would carry every
|
|
546
|
+
* value of the profile.
|
|
547
|
+
*/
|
|
548
|
+
runWithSecrets(profileId, body) {
|
|
549
|
+
return this.request(
|
|
550
|
+
"POST",
|
|
551
|
+
`/v1/profiles/${enc(profileId)}/secrets/run`,
|
|
552
|
+
body
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
/** Is the secret layer on? It is by default. */
|
|
556
|
+
getSecretLayer(signal) {
|
|
557
|
+
return this.request("GET", "/v1/secret-layer", void 0, { signal });
|
|
558
|
+
}
|
|
559
|
+
/** Turn the secret layer on or off for the whole daemon. */
|
|
560
|
+
setSecretLayer(enabled) {
|
|
561
|
+
return this.request("POST", "/v1/secret-layer", { enabled });
|
|
562
|
+
}
|
|
484
563
|
// ── Cookies ────────────────────────────────────────────────────────────────
|
|
485
564
|
/**
|
|
486
565
|
* The one door a cookie VALUE leaves through, and it needs the vault password.
|
|
@@ -507,7 +586,7 @@ var RunsApi = class extends ClientCore {
|
|
|
507
586
|
getRun(runId, signal) {
|
|
508
587
|
return this.request("GET", `/v1/runs/${enc(runId)}`, void 0, { signal });
|
|
509
588
|
}
|
|
510
|
-
/** A run's steps, oldest first
|
|
589
|
+
/** A run's steps, oldest first: the order they happened in. */
|
|
511
590
|
listRunSteps(runId, params = {}, signal) {
|
|
512
591
|
return this.request("GET", `/v1/runs/${enc(runId)}/steps`, void 0, {
|
|
513
592
|
query: { limit: params.limit, offset: params.offset },
|
|
@@ -712,7 +791,7 @@ var CdpConnection = class {
|
|
|
712
791
|
return () => this.#subscribers.delete(cb);
|
|
713
792
|
}
|
|
714
793
|
/** Register a callback fired once when the connection closes (immediately if
|
|
715
|
-
* it already has)
|
|
794
|
+
* it already has); event streams use this to end instead of hanging. */
|
|
716
795
|
onClose(cb) {
|
|
717
796
|
if (this.#closeReason) {
|
|
718
797
|
cb();
|
|
@@ -996,7 +1075,7 @@ var ScalebrowserClient = class extends ClientCore {
|
|
|
996
1075
|
});
|
|
997
1076
|
}
|
|
998
1077
|
/**
|
|
999
|
-
* Every id matching `params`, unpaged
|
|
1078
|
+
* Every id matching `params`, unpaged: what "act on all matches" needs.
|
|
1000
1079
|
*
|
|
1001
1080
|
* `listProfiles` is paged, so acting on "everything" from it only ever covers the
|
|
1002
1081
|
* page you fetched. Asking for ids costs one request and no persona payloads.
|
|
@@ -1032,6 +1111,14 @@ var ScalebrowserClient = class extends ClientCore {
|
|
|
1032
1111
|
stopProfile(id) {
|
|
1033
1112
|
return this.request("POST", `/v1/profiles/${enc(id)}/stop`, {});
|
|
1034
1113
|
}
|
|
1114
|
+
/** Ask for a profile that is open on another machine of this account.
|
|
1115
|
+
*
|
|
1116
|
+
* Closes nothing here and nothing there: the control plane revokes the holder's
|
|
1117
|
+
* right, the holder closes its own browser at its next heartbeat. Start only
|
|
1118
|
+
* after this answered `free`. Errors: 4012 when it is held elsewhere. */
|
|
1119
|
+
takeoverProfile(id) {
|
|
1120
|
+
return this.request("POST", `/v1/profiles/${enc(id)}/takeover`, {});
|
|
1121
|
+
}
|
|
1035
1122
|
// ── Bulk (PRD §D2) ───────────────────────────────────────────────────────
|
|
1036
1123
|
bulkCreateProfiles(body) {
|
|
1037
1124
|
return this.request("POST", "/v1/bulk/profiles", body);
|
|
@@ -1129,7 +1216,7 @@ var ScalebrowserClient = class extends ClientCore {
|
|
|
1129
1216
|
return this.request("POST", `/v1/proxies/${enc(id)}/check`, {});
|
|
1130
1217
|
}
|
|
1131
1218
|
/**
|
|
1132
|
-
* Probe a proxy config WITHOUT persisting it
|
|
1219
|
+
* Probe a proxy config WITHOUT persisting it: validate before you commit.
|
|
1133
1220
|
* Pass `id` (and omit the credentials) to probe an existing proxy's stored,
|
|
1134
1221
|
* write-only credentials in an edit form.
|
|
1135
1222
|
*/
|
|
@@ -1240,7 +1327,7 @@ var PROXY_KINDS = ["http", "socks5", "gateway"];
|
|
|
1240
1327
|
var ROTATIONS = ["sticky", "rotating"];
|
|
1241
1328
|
|
|
1242
1329
|
// src/index.ts
|
|
1243
|
-
var VERSION = "0.
|
|
1330
|
+
var VERSION = "0.3.0";
|
|
1244
1331
|
|
|
1245
1332
|
exports.ApiError = ApiError;
|
|
1246
1333
|
exports.CdpError = CdpError;
|