@scalebrowser/sdk 0.4.1 → 0.6.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.cjs +367 -5
- package/dist/index.d.cts +905 -8
- package/dist/index.d.ts +905 -8
- package/dist/index.js +367 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25,7 +25,13 @@ var ErrorCode = {
|
|
|
25
25
|
* Distinct from ConcurrencyLimit (4008 = the plan is full, buy more or free any
|
|
26
26
|
* browser): the caller's move here costs nothing. Close it on that machine, or
|
|
27
27
|
* take it over from the app running there. */
|
|
28
|
-
ProfileInUse: 4012
|
|
28
|
+
ProfileInUse: 4012,
|
|
29
|
+
/** The exit address this start drew belongs to another profile (DEC-017).
|
|
30
|
+
* Distinct from ProxyGeo (4002 = wrong country or wrong kind of exit, so change
|
|
31
|
+
* the proxy): here the proxy is fine and the address is simply spoken for. Wait
|
|
32
|
+
* for a term to run out, let the daemon draw again, or turn exclusivity off for
|
|
33
|
+
* this profile. */
|
|
34
|
+
ExitAddressTaken: 4013
|
|
29
35
|
};
|
|
30
36
|
var CODE_LABELS = {
|
|
31
37
|
4001: "Not found",
|
|
@@ -37,7 +43,8 @@ var CODE_LABELS = {
|
|
|
37
43
|
4008: "Concurrent-browser limit reached (subscription-wide)",
|
|
38
44
|
4010: "Unauthorized",
|
|
39
45
|
4011: "No account connected to this machine",
|
|
40
|
-
4012: "This profile is open on another machine"
|
|
46
|
+
4012: "This profile is open on another machine",
|
|
47
|
+
4013: "This exit address belongs to another profile"
|
|
41
48
|
};
|
|
42
49
|
var ScalebrowserError = class extends Error {
|
|
43
50
|
constructor(message) {
|
|
@@ -248,7 +255,7 @@ var ControlApi = class extends ClientCore {
|
|
|
248
255
|
/**
|
|
249
256
|
* Hand the daemon a file so `interact action=upload` has something to attach.
|
|
250
257
|
*
|
|
251
|
-
* The bytes are bound to the PROFILE, not to a
|
|
258
|
+
* The bytes are bound to the PROFILE, not to a lease: set a file up
|
|
252
259
|
* before leasing, and a lease released mid-task does not destroy it.
|
|
253
260
|
*/
|
|
254
261
|
putArtifact(profileId, bytes, name) {
|
|
@@ -566,6 +573,83 @@ var IdentityApi = class extends ClientCore {
|
|
|
566
573
|
}
|
|
567
574
|
};
|
|
568
575
|
|
|
576
|
+
// src/client-tasks.ts
|
|
577
|
+
var TasksApi = class extends ClientCore {
|
|
578
|
+
// -- Tasks ------------------------------------------------------------------
|
|
579
|
+
//
|
|
580
|
+
// Fleet-wide by default, and deliberately so: the question this surface exists
|
|
581
|
+
// for is "what is outstanding across my twenty accounts", and a per-profile
|
|
582
|
+
// route would make a client ask it twenty times and sort the answers itself.
|
|
583
|
+
//
|
|
584
|
+
// None of these starts a browser. A task is a row, so reading the whole fleet's
|
|
585
|
+
// list costs nothing from the plan's concurrent-browser allowance. Reserve only
|
|
586
|
+
// the profiles that turn out to have work.
|
|
587
|
+
/**
|
|
588
|
+
* What is still to be done. No filter means every task of every profile.
|
|
589
|
+
*
|
|
590
|
+
* Pass `state: 'open'` for what is outstanding; without it, tasks finished
|
|
591
|
+
* within the last day are included too.
|
|
592
|
+
*/
|
|
593
|
+
listTasks(params, signal) {
|
|
594
|
+
return this.request("GET", "/v1/tasks", void 0, {
|
|
595
|
+
query: { ...params },
|
|
596
|
+
signal
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
/**
|
|
600
|
+
* Put the same task on one or many profiles, one row each.
|
|
601
|
+
*
|
|
602
|
+
* A task is a LINE, not a document: name the work and leave the material where
|
|
603
|
+
* it lives. `due_at` is a deadline, not a trigger; nothing runs by itself.
|
|
604
|
+
*
|
|
605
|
+
* Profiles that no longer exist come back in `missing` instead of failing the
|
|
606
|
+
* whole call.
|
|
607
|
+
*/
|
|
608
|
+
createTasks(body) {
|
|
609
|
+
return this.request("POST", "/v1/tasks", body);
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Call a task off.
|
|
613
|
+
*
|
|
614
|
+
* Only a task nobody has claimed can be cancelled here. One an agent is working
|
|
615
|
+
* on right now is stopped by telling that agent, which is a channel that already
|
|
616
|
+
* reaches it; this surface answers `409` for it rather than pretending.
|
|
617
|
+
*/
|
|
618
|
+
cancelTask(id) {
|
|
619
|
+
return this.request("PATCH", `/v1/tasks/${enc(id)}`, { state: "cancelled" });
|
|
620
|
+
}
|
|
621
|
+
/** Remove a task outright. */
|
|
622
|
+
deleteTask(id) {
|
|
623
|
+
return this.request("DELETE", `/v1/tasks/${enc(id)}`);
|
|
624
|
+
}
|
|
625
|
+
// -- Profile memory ---------------------------------------------------------
|
|
626
|
+
/**
|
|
627
|
+
* A profile's durable memory, the `PROFILE.md` at the top of its directory.
|
|
628
|
+
*
|
|
629
|
+
* `content` is `null` while nobody has written one: a profile starts with no
|
|
630
|
+
* file, not with an empty one.
|
|
631
|
+
*/
|
|
632
|
+
getProfileMemory(profileId, signal) {
|
|
633
|
+
return this.request("GET", `/v1/profiles/${enc(profileId)}/memory`, void 0, {
|
|
634
|
+
signal
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Replace a profile's memory.
|
|
639
|
+
*
|
|
640
|
+
* Stored verbatim: no trimming, no appended newline, no line-ending
|
|
641
|
+
* translation. The last write wins and nothing warns, exactly as with a file
|
|
642
|
+
* two people can open.
|
|
643
|
+
*/
|
|
644
|
+
putProfileMemory(profileId, content) {
|
|
645
|
+
return this.request("PUT", `/v1/profiles/${enc(profileId)}/memory`, { content });
|
|
646
|
+
}
|
|
647
|
+
/** Remove a profile's memory. Removing one that is not there is not an error. */
|
|
648
|
+
deleteProfileMemory(profileId) {
|
|
649
|
+
return this.request("DELETE", `/v1/profiles/${enc(profileId)}/memory`);
|
|
650
|
+
}
|
|
651
|
+
};
|
|
652
|
+
|
|
569
653
|
// src/client-runs.ts
|
|
570
654
|
var RunsApi = class extends ClientCore {
|
|
571
655
|
// ── Agent runs ─────────────────────────────────────────────────────────────
|
|
@@ -602,6 +686,205 @@ var RunsApi = class extends ClientCore {
|
|
|
602
686
|
}
|
|
603
687
|
};
|
|
604
688
|
|
|
689
|
+
// src/client-videos.ts
|
|
690
|
+
var VideosApi = class extends ClientCore {
|
|
691
|
+
// ── Videos ────────────────────────────────────────────────────────────────
|
|
692
|
+
/** One gallery page, newest first. Running renders are videos too. */
|
|
693
|
+
listVideos(params = {}, signal) {
|
|
694
|
+
return this.request("GET", "/v1/videos", void 0, {
|
|
695
|
+
query: {
|
|
696
|
+
q: params.q,
|
|
697
|
+
profile_id: params.profile_id,
|
|
698
|
+
run_id: params.run_id,
|
|
699
|
+
kind: params.kind,
|
|
700
|
+
preset: params.preset,
|
|
701
|
+
state: params.state,
|
|
702
|
+
page: params.page
|
|
703
|
+
},
|
|
704
|
+
signal
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
/** One video row, progress included while it renders. */
|
|
708
|
+
getVideo(videoId, signal) {
|
|
709
|
+
return this.request("GET", `/v1/videos/${enc(videoId)}`, void 0, { signal });
|
|
710
|
+
}
|
|
711
|
+
/** Rename. The title also lands in the MP4's metadata on the NEXT render. */
|
|
712
|
+
renameVideo(videoId, title, signal) {
|
|
713
|
+
return this.request("PATCH", `/v1/videos/${enc(videoId)}`, { title }, { signal });
|
|
714
|
+
}
|
|
715
|
+
/**
|
|
716
|
+
* Delete a video (`raw: true` also purges its recording's raw material).
|
|
717
|
+
* A live share link is revoked first; 409 `job_running` while it renders.
|
|
718
|
+
*/
|
|
719
|
+
deleteVideo(videoId, opts = {}, signal) {
|
|
720
|
+
return this.request("DELETE", `/v1/videos/${enc(videoId)}`, void 0, {
|
|
721
|
+
query: { raw: opts.raw },
|
|
722
|
+
signal
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
/** Cancel a queued or rendering video. `done` stays done (409). */
|
|
726
|
+
cancelVideo(videoId, signal) {
|
|
727
|
+
return this.request("POST", `/v1/videos/${enc(videoId)}/cancel`, void 0, {
|
|
728
|
+
signal
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
/** Render a failed or cancelled video again: same id, new job. */
|
|
732
|
+
rerenderVideo(videoId, body = {}, signal) {
|
|
733
|
+
return this.request("POST", `/v1/videos/${enc(videoId)}/renders`, body, { signal });
|
|
734
|
+
}
|
|
735
|
+
/** A short-lived fetchable address for one asset (default the video). */
|
|
736
|
+
videoAccess(videoId, asset, signal) {
|
|
737
|
+
return this.request(
|
|
738
|
+
"POST",
|
|
739
|
+
`/v1/videos/${enc(videoId)}/access`,
|
|
740
|
+
asset ? { asset } : {},
|
|
741
|
+
{ signal }
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
/** One asset's bytes, through a freshly minted grant. */
|
|
745
|
+
async downloadVideoFile(videoId, asset = "video", signal) {
|
|
746
|
+
const grant = await this.videoAccess(videoId, asset, signal);
|
|
747
|
+
const grantParam = new URL(grant.url, "http://x").searchParams.get("grant") ?? "";
|
|
748
|
+
return this.requestBytes("GET", `/v1/videos/${enc(videoId)}/file`, {
|
|
749
|
+
query: { asset, grant: grantParam },
|
|
750
|
+
signal
|
|
751
|
+
});
|
|
752
|
+
}
|
|
753
|
+
/** What recordings and videos cost on disk, plus the caps. */
|
|
754
|
+
videosStorage(signal) {
|
|
755
|
+
return this.request("GET", "/v1/videos/storage", void 0, { signal });
|
|
756
|
+
}
|
|
757
|
+
// ── Recordings ────────────────────────────────────────────────────────────
|
|
758
|
+
/** Recordings, newest first. The row outlives its raw bytes. */
|
|
759
|
+
listRecordings(params = {}, signal) {
|
|
760
|
+
return this.request("GET", "/v1/recordings", void 0, {
|
|
761
|
+
query: { profile_id: params.profile_id },
|
|
762
|
+
signal
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
getRecording(recordingId, signal) {
|
|
766
|
+
return this.request("GET", `/v1/recordings/${enc(recordingId)}`, void 0, {
|
|
767
|
+
signal
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Purge a recording's RAW material; the row stays forever
|
|
772
|
+
* (`raw_purged_at`). 409 `job_running` while a render of it is open.
|
|
773
|
+
*/
|
|
774
|
+
deleteRecordingRaw(recordingId, signal) {
|
|
775
|
+
return this.request("DELETE", `/v1/recordings/${enc(recordingId)}`, void 0, {
|
|
776
|
+
signal
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
/** A NEW video from this recording (the same body the `video` tool takes). */
|
|
780
|
+
renderRecording(recordingId, body = {}, signal) {
|
|
781
|
+
return this.request("POST", `/v1/recordings/${enc(recordingId)}/renders`, body, {
|
|
782
|
+
signal
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
// ── Codecs ────────────────────────────────────────────────────────────────
|
|
786
|
+
/** What this machine can encode with. The hardware list is PROBED, not read
|
|
787
|
+
* off the binary: `h264_nvenc` is always listed and fails without a driver. */
|
|
788
|
+
getCodecs(signal) {
|
|
789
|
+
return this.request("GET", "/v1/codecs", void 0, { signal });
|
|
790
|
+
}
|
|
791
|
+
/** Turn Cisco's OpenH264 on or off. The hardware encoders are not switchable. */
|
|
792
|
+
setCodecEnabled(codec, enabled, signal) {
|
|
793
|
+
return this.request("PUT", `/v1/codecs/${enc(codec)}`, { enabled }, { signal });
|
|
794
|
+
}
|
|
795
|
+
// -- Sharing ----------------------------------------------------------------
|
|
796
|
+
/** Make a finished video public. Measures every file, asks the control plane
|
|
797
|
+
* for permission, uploads, and has the result confirmed. */
|
|
798
|
+
share(videoId, body = {}, signal) {
|
|
799
|
+
return this.request("POST", `/v1/videos/${enc(videoId)}/share`, body, {
|
|
800
|
+
signal
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
/** The share ORDER as this machine knows it. How many people watched and
|
|
804
|
+
* whether the link still lives is read from the control plane, not from
|
|
805
|
+
* here: a number carried along would be wrong the moment another machine
|
|
806
|
+
* revoked. */
|
|
807
|
+
shareStatus(videoId, signal) {
|
|
808
|
+
return this.request(
|
|
809
|
+
"GET",
|
|
810
|
+
`/v1/videos/${enc(videoId)}/share`,
|
|
811
|
+
void 0,
|
|
812
|
+
{ signal }
|
|
813
|
+
);
|
|
814
|
+
}
|
|
815
|
+
/** Revoke the link. The files fall at once; the order stays until the control
|
|
816
|
+
* plane confirms. */
|
|
817
|
+
revokeShare(videoId, signal) {
|
|
818
|
+
return this.request("DELETE", `/v1/videos/${enc(videoId)}/share`, void 0, {
|
|
819
|
+
signal
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
// -- Media ------------------------------------------------------------------
|
|
823
|
+
/** Files a preset points at: background image, music bed, subtitle font. */
|
|
824
|
+
listMedia(kind, signal) {
|
|
825
|
+
return this.request("GET", "/v1/media", void 0, {
|
|
826
|
+
query: { kind },
|
|
827
|
+
signal
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
/** Upload one file. The body IS the file; `name` and `mime` ride in the query. */
|
|
831
|
+
uploadMedia(kind, name, mime, bytes, signal) {
|
|
832
|
+
return this.request("POST", "/v1/media", bytes, {
|
|
833
|
+
query: { kind, name, mime },
|
|
834
|
+
signal
|
|
835
|
+
});
|
|
836
|
+
}
|
|
837
|
+
/** Remove a file. Refuses with 409 while a preset still points at it. */
|
|
838
|
+
deleteMedia(id, signal) {
|
|
839
|
+
return this.request("DELETE", `/v1/media/${enc(id)}`, void 0, { signal });
|
|
840
|
+
}
|
|
841
|
+
/** The file itself. */
|
|
842
|
+
mediaFile(id, signal) {
|
|
843
|
+
return this.requestBytes("GET", `/v1/media/${enc(id)}/file`, { signal });
|
|
844
|
+
}
|
|
845
|
+
// -- Voice providers --------------------------------------------------------
|
|
846
|
+
/** Which speech providers have a key. The key itself never comes back: the
|
|
847
|
+
* answer carries a hint, and that is on purpose. */
|
|
848
|
+
listTtsProviders(signal) {
|
|
849
|
+
return this.request("GET", "/v1/tts-providers", void 0, { signal });
|
|
850
|
+
}
|
|
851
|
+
/** Store a key, or rename one. Leaving `apiKey` out keeps the stored key.
|
|
852
|
+
*
|
|
853
|
+
* `apiKey` may also be a secret reference (`{{sb:...}}`), which is what an
|
|
854
|
+
* agent gets back after fetching a key from the provider's own site: it is
|
|
855
|
+
* not allowed to read the value. A reference needs `profileId`, because the
|
|
856
|
+
* value belongs to one profile and there is nothing to open without it.
|
|
857
|
+
*/
|
|
858
|
+
putTtsProvider(provider, body, signal) {
|
|
859
|
+
return this.request(
|
|
860
|
+
"PUT",
|
|
861
|
+
`/v1/tts-providers/${enc(provider)}`,
|
|
862
|
+
{ api_key: body.apiKey, label: body.label, profile_id: body.profileId },
|
|
863
|
+
{ signal }
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
/** Call the provider once for real, and record that the key works.
|
|
867
|
+
*
|
|
868
|
+
* Costs one short sentence of the account's own quota. Until this runs, a
|
|
869
|
+
* provider row says `verified_at: null`, which means untested rather than
|
|
870
|
+
* broken.
|
|
871
|
+
*/
|
|
872
|
+
verifyTtsProvider(provider, signal) {
|
|
873
|
+
return this.request(
|
|
874
|
+
"POST",
|
|
875
|
+
`/v1/tts-providers/${enc(provider)}/verify`,
|
|
876
|
+
void 0,
|
|
877
|
+
{ signal }
|
|
878
|
+
);
|
|
879
|
+
}
|
|
880
|
+
/** Forget a provider's key. */
|
|
881
|
+
deleteTtsProvider(provider, signal) {
|
|
882
|
+
return this.request("DELETE", `/v1/tts-providers/${enc(provider)}`, void 0, {
|
|
883
|
+
signal
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
|
|
605
888
|
// src/events.ts
|
|
606
889
|
var MAX_BACKOFF_MS = 15e3;
|
|
607
890
|
function subscribeEvents(params, handlers) {
|
|
@@ -1105,6 +1388,15 @@ var ScalebrowserClient = class extends ClientCore {
|
|
|
1105
1388
|
stopProfile(id) {
|
|
1106
1389
|
return this.request("POST", `/v1/profiles/${enc(id)}/stop`, {});
|
|
1107
1390
|
}
|
|
1391
|
+
/** Drop the profile's lease, the operator's way out.
|
|
1392
|
+
*
|
|
1393
|
+
* An agent releases with its handle; this call needs none. The daemon stops
|
|
1394
|
+
* the browser first when one is still up, then lets the lease go, so a dead
|
|
1395
|
+
* session cannot park the profile until its TTL runs out. `released: false`
|
|
1396
|
+
* is an honest no-op: there was nothing to let go. */
|
|
1397
|
+
releaseProfile(id) {
|
|
1398
|
+
return this.request("POST", `/v1/profiles/${enc(id)}/release`, {});
|
|
1399
|
+
}
|
|
1108
1400
|
/** Ask for a profile that is open on another machine of this account.
|
|
1109
1401
|
*
|
|
1110
1402
|
* Closes nothing here and nothing there: the control plane revokes the holder's
|
|
@@ -1176,6 +1468,42 @@ var ScalebrowserClient = class extends ClientCore {
|
|
|
1176
1468
|
deletePreset(id) {
|
|
1177
1469
|
return this.request("DELETE", `/v1/presets/${enc(id)}`);
|
|
1178
1470
|
}
|
|
1471
|
+
// ── Video presets ──────────────────────────────────────────────────────────
|
|
1472
|
+
listVideoPresets(signal) {
|
|
1473
|
+
return this.request("GET", "/v1/video-presets", void 0, { signal });
|
|
1474
|
+
}
|
|
1475
|
+
getVideoPreset(id, signal) {
|
|
1476
|
+
return this.request("GET", `/v1/video-presets/${enc(id)}`, void 0, { signal });
|
|
1477
|
+
}
|
|
1478
|
+
/** The daemon validates `config` strictly and names the failing field path. */
|
|
1479
|
+
createVideoPreset(body) {
|
|
1480
|
+
return this.request("POST", "/v1/video-presets", body);
|
|
1481
|
+
}
|
|
1482
|
+
/** A built-in preset refuses edits. Duplicate it and edit the copy. */
|
|
1483
|
+
updateVideoPreset(id, body) {
|
|
1484
|
+
return this.request("PATCH", `/v1/video-presets/${enc(id)}`, body);
|
|
1485
|
+
}
|
|
1486
|
+
/** The only way to make a built-in preset yours: copy, then edit the copy. */
|
|
1487
|
+
duplicateVideoPreset(id, body = {}) {
|
|
1488
|
+
return this.request("POST", `/v1/video-presets/${enc(id)}/duplicate`, body);
|
|
1489
|
+
}
|
|
1490
|
+
deleteVideoPreset(id) {
|
|
1491
|
+
return this.request("DELETE", `/v1/video-presets/${enc(id)}`);
|
|
1492
|
+
}
|
|
1493
|
+
/** One still of the sample film under an UNSAVED config, drawn by the daemon's own renderer.
|
|
1494
|
+
* `moment` wins over `frame`; both absent means the daemon's default moment. */
|
|
1495
|
+
previewVideoPreset(body, signal) {
|
|
1496
|
+
return this.request("POST", "/v1/video-presets/preview", body, { signal });
|
|
1497
|
+
}
|
|
1498
|
+
/** A clip of the sample film, blocking until it is encoded (the editor uses the SSE form of the
|
|
1499
|
+
* same route; a script waits). Fetch the bytes with `downloadVideoPresetClip`. */
|
|
1500
|
+
previewVideoPresetClip(body, signal) {
|
|
1501
|
+
return this.request("POST", "/v1/video-presets/preview/clip", body, { signal });
|
|
1502
|
+
}
|
|
1503
|
+
/** The clip's MP4 bytes. */
|
|
1504
|
+
downloadVideoPresetClip(id, signal) {
|
|
1505
|
+
return this.requestBytes("GET", `/v1/video-presets/preview/clip/${enc(id)}`, { signal });
|
|
1506
|
+
}
|
|
1179
1507
|
/**
|
|
1180
1508
|
* The values a preset's `constraints` may take. Ask rather than hardcode: the
|
|
1181
1509
|
* region list comes from the daemon's embedded persona model, so a pinned copy
|
|
@@ -1232,6 +1560,18 @@ var ScalebrowserClient = class extends ClientCore {
|
|
|
1232
1560
|
signal
|
|
1233
1561
|
});
|
|
1234
1562
|
}
|
|
1563
|
+
// ── Exit-address exclusivity (DEC-017) ──────────────────────────────────────
|
|
1564
|
+
/** Which exit addresses this profile owns, and how far the rule reaches.
|
|
1565
|
+
*
|
|
1566
|
+
* `scope` is `'machine'` while this computer has no account key. That is the
|
|
1567
|
+
* ordinary state of a second machine until sync is unlocked there once, and it is
|
|
1568
|
+
* reported rather than hidden: believing the rule spans three machines when it
|
|
1569
|
+
* spans one is worse than knowing. */
|
|
1570
|
+
getExitStatus(profileId, signal) {
|
|
1571
|
+
return this.request("GET", `/v1/profiles/${enc(profileId)}/exit`, void 0, {
|
|
1572
|
+
signal
|
|
1573
|
+
});
|
|
1574
|
+
}
|
|
1235
1575
|
// ── Session bundles (AC-ST-002/003) ─────────────────────────────────────────
|
|
1236
1576
|
exportSession(profileId, body) {
|
|
1237
1577
|
return this.request("POST", `/v1/profiles/${enc(profileId)}/session/export`, body);
|
|
@@ -1254,6 +1594,21 @@ var ScalebrowserClient = class extends ClientCore {
|
|
|
1254
1594
|
throw err;
|
|
1255
1595
|
}
|
|
1256
1596
|
}
|
|
1597
|
+
// ── Remote access (the machine's own switch) ────────────────────────────────
|
|
1598
|
+
/**
|
|
1599
|
+
* Is remote access on for this machine?
|
|
1600
|
+
*
|
|
1601
|
+
* The switch is deliberately local: a chat service reaches this browser only
|
|
1602
|
+
* once somebody at the machine has turned it on. On a headless install there
|
|
1603
|
+
* is no UI to click, which is why it is here as well.
|
|
1604
|
+
*/
|
|
1605
|
+
async getRemoteAccess(signal) {
|
|
1606
|
+
return this.request("GET", "/v1/remote", void 0, { signal });
|
|
1607
|
+
}
|
|
1608
|
+
/** Turn remote access on or off for this machine. */
|
|
1609
|
+
async setRemoteAccess(enabled, signal) {
|
|
1610
|
+
return this.request("PUT", "/v1/remote", { enabled }, { signal });
|
|
1611
|
+
}
|
|
1257
1612
|
// ── Events (SSE) ───────────────────────────────────────────────────────────
|
|
1258
1613
|
/** Subscribe to lifecycle events. Returns an unsubscribe function. */
|
|
1259
1614
|
subscribeEvents(handlers) {
|
|
@@ -1311,7 +1666,14 @@ function deriveMetricsFromProfiles(profiles) {
|
|
|
1311
1666
|
profiles: []
|
|
1312
1667
|
};
|
|
1313
1668
|
}
|
|
1314
|
-
applyMixins(ScalebrowserClient, [
|
|
1669
|
+
applyMixins(ScalebrowserClient, [
|
|
1670
|
+
IdentityApi,
|
|
1671
|
+
RunsApi,
|
|
1672
|
+
VideosApi,
|
|
1673
|
+
ControlApi,
|
|
1674
|
+
ExtensionsApi,
|
|
1675
|
+
TasksApi
|
|
1676
|
+
]);
|
|
1315
1677
|
|
|
1316
1678
|
// src/types.ts
|
|
1317
1679
|
var RUNTIME_STATES = ["stopped", "starting", "running", "crashed"];
|
|
@@ -1321,6 +1683,6 @@ var PROXY_KINDS = ["http", "socks5", "gateway"];
|
|
|
1321
1683
|
var ROTATIONS = ["sticky", "rotating"];
|
|
1322
1684
|
|
|
1323
1685
|
// src/index.ts
|
|
1324
|
-
var VERSION = "0.
|
|
1686
|
+
var VERSION = "0.6.0";
|
|
1325
1687
|
|
|
1326
1688
|
export { ApiError, CdpError, CdpSession, DEFAULT_CAPACITY, ErrorCode, GEO_MODES, HOST_MODES, NetworkError, PROXY_KINDS, ROTATIONS, RUNTIME_STATES, ScalebrowserClient, ScalebrowserError, VERSION, deriveMetricsFromProfiles, errorMessage, eventStream, openCdpSession, parseSseFrame, subscribeEvents };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scalebrowser/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Official Node/TypeScript SDK for the Scalebrowser daemon — typed REST client + direct-CDP driver plane (nodriver-style, not Playwright).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|