@lizard-build/sdk 0.1.71 → 0.1.73
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 +4 -2
- package/dist/index.d.mts +815 -17
- package/dist/index.d.ts +815 -17
- package/dist/index.js +568 -18
- package/dist/index.mjs +552 -18
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -27,10 +27,26 @@ __export(index_exports, {
|
|
|
27
27
|
CodeSandbox: () => CodeSandbox,
|
|
28
28
|
ConfigApplyError: () => ConfigApplyError,
|
|
29
29
|
ConflictError: () => ConflictError,
|
|
30
|
+
DEFAULT_GIT_URL: () => DEFAULT_GIT_URL,
|
|
30
31
|
DeployHandle: () => DeployHandle,
|
|
31
32
|
Desktop: () => Desktop,
|
|
32
33
|
DomainsAPI: () => DomainsAPI,
|
|
34
|
+
GitAPI: () => GitAPI,
|
|
35
|
+
GitActionsAPI: () => GitActionsAPI,
|
|
36
|
+
GitBranchRulesAPI: () => GitBranchRulesAPI,
|
|
37
|
+
GitClient: () => GitClient,
|
|
38
|
+
GitCollaboratorsAPI: () => GitCollaboratorsAPI,
|
|
33
39
|
GitHubAPI: () => GitHubAPI,
|
|
40
|
+
GitIssuesOnlyAPI: () => GitIssuesOnlyAPI,
|
|
41
|
+
GitLabelsAPI: () => GitLabelsAPI,
|
|
42
|
+
GitNotificationsAPI: () => GitNotificationsAPI,
|
|
43
|
+
GitPullsAPI: () => GitPullsAPI,
|
|
44
|
+
GitReleasesAPI: () => GitReleasesAPI,
|
|
45
|
+
GitReposAPI: () => GitReposAPI,
|
|
46
|
+
GitSecretsAPI: () => GitSecretsAPI,
|
|
47
|
+
GitStatusesAPI: () => GitStatusesAPI,
|
|
48
|
+
GitTokensAPI: () => GitTokensAPI,
|
|
49
|
+
GitWebhooksAPI: () => GitWebhooksAPI,
|
|
34
50
|
LimitExceededError: () => LimitExceededError,
|
|
35
51
|
Lizard: () => Lizard,
|
|
36
52
|
LizardCLI: () => LizardCLI,
|
|
@@ -179,9 +195,9 @@ async function handleApiError(res) {
|
|
|
179
195
|
// src/platform/client.ts
|
|
180
196
|
var segment = (value) => encodeURIComponent(value);
|
|
181
197
|
function query(path, values) {
|
|
182
|
-
const
|
|
183
|
-
for (const [key, value] of Object.entries(values)) if (value !== void 0)
|
|
184
|
-
return
|
|
198
|
+
const qs2 = new URLSearchParams();
|
|
199
|
+
for (const [key, value] of Object.entries(values)) if (value !== void 0) qs2.set(key, String(value));
|
|
200
|
+
return qs2.size ? `${path}?${qs2}` : path;
|
|
185
201
|
}
|
|
186
202
|
var PlatformClient = class {
|
|
187
203
|
constructor(opts) {
|
|
@@ -535,6 +551,525 @@ var GitHubAPI = class {
|
|
|
535
551
|
}
|
|
536
552
|
};
|
|
537
553
|
|
|
554
|
+
// src/platform/git.ts
|
|
555
|
+
var DEFAULT_GIT_URL = "https://git.lizard.build";
|
|
556
|
+
var seg = encodeURIComponent;
|
|
557
|
+
function qs(path, values) {
|
|
558
|
+
const q = new URLSearchParams();
|
|
559
|
+
for (const [k, v] of Object.entries(values)) if (v !== void 0 && v !== "") q.set(k, String(v));
|
|
560
|
+
return q.size ? `${path}?${q}` : path;
|
|
561
|
+
}
|
|
562
|
+
function repoPath(repo) {
|
|
563
|
+
const m = /^([^/\s]+)\/([^/\s]+?)(\.git)?$/.exec(repo);
|
|
564
|
+
if (!m) throw new Error(`repository must be "owner/name", got "${repo}"`);
|
|
565
|
+
return `/api/repos/${seg(m[1])}/${seg(m[2])}`;
|
|
566
|
+
}
|
|
567
|
+
var GitClient = class {
|
|
568
|
+
constructor(config, url) {
|
|
569
|
+
this.config = config;
|
|
570
|
+
this.url = (url ?? process.env.LIZARD_GIT_URL ?? DEFAULT_GIT_URL).replace(/\/+$/, "");
|
|
571
|
+
}
|
|
572
|
+
async raw(method, path, body, headers = {}) {
|
|
573
|
+
const res = await fetch(this.url + path, {
|
|
574
|
+
method,
|
|
575
|
+
body,
|
|
576
|
+
headers: { "X-API-Key": this.config.apiKey, ...headers },
|
|
577
|
+
signal: AbortSignal.timeout(this.config.requestTimeoutMs)
|
|
578
|
+
});
|
|
579
|
+
if (!res.ok) await handleApiError(res);
|
|
580
|
+
return res;
|
|
581
|
+
}
|
|
582
|
+
async request(method, path, body, headers = {}) {
|
|
583
|
+
const res = await this.raw(
|
|
584
|
+
method,
|
|
585
|
+
path,
|
|
586
|
+
body === void 0 ? void 0 : JSON.stringify(body),
|
|
587
|
+
body === void 0 ? headers : { "Content-Type": "application/json", ...headers }
|
|
588
|
+
);
|
|
589
|
+
const text = res.status === 204 ? "" : await res.text();
|
|
590
|
+
return text ? JSON.parse(text) : void 0;
|
|
591
|
+
}
|
|
592
|
+
get(path) {
|
|
593
|
+
return this.request("GET", path);
|
|
594
|
+
}
|
|
595
|
+
post(path, body) {
|
|
596
|
+
return this.request("POST", path, body ?? {});
|
|
597
|
+
}
|
|
598
|
+
put(path, body) {
|
|
599
|
+
return this.request("PUT", path, body ?? {});
|
|
600
|
+
}
|
|
601
|
+
patch(path, body) {
|
|
602
|
+
return this.request("PATCH", path, body);
|
|
603
|
+
}
|
|
604
|
+
delete(path) {
|
|
605
|
+
return this.request("DELETE", path);
|
|
606
|
+
}
|
|
607
|
+
async bytes(path) {
|
|
608
|
+
return new Uint8Array(await (await this.raw("GET", path)).arrayBuffer());
|
|
609
|
+
}
|
|
610
|
+
};
|
|
611
|
+
var GitReposAPI = class {
|
|
612
|
+
constructor(c) {
|
|
613
|
+
this.c = c;
|
|
614
|
+
}
|
|
615
|
+
/** Yours and the ones you collaborate on by default; `owner`, `q`, `starred` narrow it. */
|
|
616
|
+
list(opts = {}) {
|
|
617
|
+
return this.c.get(qs("/api/repos", opts));
|
|
618
|
+
}
|
|
619
|
+
/** Answers the new repository's `owner` and `name`. */
|
|
620
|
+
create(opts) {
|
|
621
|
+
return this.c.post("/api/repos", opts);
|
|
622
|
+
}
|
|
623
|
+
get(repo) {
|
|
624
|
+
return this.c.get(repoPath(repo));
|
|
625
|
+
}
|
|
626
|
+
update(repo, opts) {
|
|
627
|
+
return this.c.patch(repoPath(repo), opts);
|
|
628
|
+
}
|
|
629
|
+
delete(repo) {
|
|
630
|
+
return this.c.delete(repoPath(repo));
|
|
631
|
+
}
|
|
632
|
+
star(repo) {
|
|
633
|
+
return this.c.put(`${repoPath(repo)}/star`);
|
|
634
|
+
}
|
|
635
|
+
unstar(repo) {
|
|
636
|
+
return this.c.delete(`${repoPath(repo)}/star`);
|
|
637
|
+
}
|
|
638
|
+
/** Fork into your account (`name` defaults to the same name). */
|
|
639
|
+
fork(repo, opts = {}) {
|
|
640
|
+
return this.c.post(`${repoPath(repo)}/forks`, opts);
|
|
641
|
+
}
|
|
642
|
+
forks(repo) {
|
|
643
|
+
return this.c.get(`${repoPath(repo)}/forks`);
|
|
644
|
+
}
|
|
645
|
+
/** Branches and tags. */
|
|
646
|
+
refs(repo) {
|
|
647
|
+
return this.c.get(`${repoPath(repo)}/refs`);
|
|
648
|
+
}
|
|
649
|
+
createBranch(repo, name, from) {
|
|
650
|
+
return this.c.post(`${repoPath(repo)}/branches`, { name, from });
|
|
651
|
+
}
|
|
652
|
+
deleteBranch(repo, name) {
|
|
653
|
+
return this.c.delete(`${repoPath(repo)}/branches/${name.split("/").map(seg).join("/")}`);
|
|
654
|
+
}
|
|
655
|
+
tree(repo, opts = {}) {
|
|
656
|
+
return this.c.get(qs(`${repoPath(repo)}/tree`, opts));
|
|
657
|
+
}
|
|
658
|
+
/** A file as JSON (text in `content`). */
|
|
659
|
+
file(repo, path, ref) {
|
|
660
|
+
return this.c.get(qs(`${repoPath(repo)}/blob`, { path, ref }));
|
|
661
|
+
}
|
|
662
|
+
/** A file's bytes, whatever its size or type. */
|
|
663
|
+
raw(repo, path, ref) {
|
|
664
|
+
const [owner, name] = repo.split("/");
|
|
665
|
+
return this.c.bytes(`/raw/${seg(owner)}/${seg(name)}/${ref.split("/").map(seg).join("/")}/${path.split("/").map(seg).join("/")}`);
|
|
666
|
+
}
|
|
667
|
+
/** Every file path at a ref. */
|
|
668
|
+
files(repo, ref) {
|
|
669
|
+
return this.c.get(qs(`${repoPath(repo)}/files`, { ref }));
|
|
670
|
+
}
|
|
671
|
+
search(repo, q, ref) {
|
|
672
|
+
return this.c.get(qs(`${repoPath(repo)}/search`, { q, ref }));
|
|
673
|
+
}
|
|
674
|
+
commits(repo, opts = {}) {
|
|
675
|
+
return this.c.get(qs(`${repoPath(repo)}/commits`, opts));
|
|
676
|
+
}
|
|
677
|
+
commit(repo, sha) {
|
|
678
|
+
return this.c.get(`${repoPath(repo)}/commits/${seg(sha)}`);
|
|
679
|
+
}
|
|
680
|
+
compare(repo, base, head) {
|
|
681
|
+
return this.c.get(qs(`${repoPath(repo)}/compare`, { base, head }));
|
|
682
|
+
}
|
|
683
|
+
/** Commit files on the server: no clone, no push. Answers 409 when `expect` no longer matches. */
|
|
684
|
+
commitFiles(repo, opts) {
|
|
685
|
+
const { idempotencyKey, ...body } = opts;
|
|
686
|
+
return this.c.request("POST", `${repoPath(repo)}/commits`, body, idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {});
|
|
687
|
+
}
|
|
688
|
+
/** Rebase `head` (branch or commit) onto `onto` on the server and move `onto` there; retried on races. */
|
|
689
|
+
land(repo, opts) {
|
|
690
|
+
return this.c.post(`${repoPath(repo)}/land`, opts);
|
|
691
|
+
}
|
|
692
|
+
/** Who moved which branch, when. */
|
|
693
|
+
reflog(repo, ref) {
|
|
694
|
+
return this.c.get(qs(`${repoPath(repo)}/reflog`, { ref }));
|
|
695
|
+
}
|
|
696
|
+
archive(repo, ref, format = "tar.gz") {
|
|
697
|
+
return this.c.bytes(`${repoPath(repo)}/archive/${seg(ref)}.${format}`);
|
|
698
|
+
}
|
|
699
|
+
/** The HTTPS clone URL. With `withKey`, it carries the API key, so plain `git clone` works without a helper. */
|
|
700
|
+
cloneUrl(repo, opts = {}) {
|
|
701
|
+
repoPath(repo);
|
|
702
|
+
const u = new URL(`${this.c.url}/${repo.replace(/\.git$/, "")}.git`);
|
|
703
|
+
if (opts.withKey) {
|
|
704
|
+
u.username = "lizard";
|
|
705
|
+
u.password = this.c.config.apiKey;
|
|
706
|
+
}
|
|
707
|
+
return u.toString();
|
|
708
|
+
}
|
|
709
|
+
};
|
|
710
|
+
var GitIssuesAPI = class {
|
|
711
|
+
constructor(c, pulls = false) {
|
|
712
|
+
this.c = c;
|
|
713
|
+
this.pulls = pulls;
|
|
714
|
+
}
|
|
715
|
+
base(repo) {
|
|
716
|
+
return `${repoPath(repo)}/issues`;
|
|
717
|
+
}
|
|
718
|
+
list(repo, opts = {}) {
|
|
719
|
+
return this.c.get(qs(this.base(repo), { ...opts, pulls: this.pulls ? 1 : void 0 }));
|
|
720
|
+
}
|
|
721
|
+
get(repo, number) {
|
|
722
|
+
return this.c.get(`${this.base(repo)}/${number}`);
|
|
723
|
+
}
|
|
724
|
+
update(repo, number, opts) {
|
|
725
|
+
return this.c.patch(`${this.base(repo)}/${number}`, opts);
|
|
726
|
+
}
|
|
727
|
+
comment(repo, number, body) {
|
|
728
|
+
return this.c.post(`${this.base(repo)}/${number}/comments`, { body });
|
|
729
|
+
}
|
|
730
|
+
close(repo, number) {
|
|
731
|
+
return this.update(repo, number, { state: "closed" });
|
|
732
|
+
}
|
|
733
|
+
reopen(repo, number) {
|
|
734
|
+
return this.update(repo, number, { state: "open" });
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
var GitIssuesOnlyAPI = class extends GitIssuesAPI {
|
|
738
|
+
constructor(c) {
|
|
739
|
+
super(c, false);
|
|
740
|
+
}
|
|
741
|
+
create(repo, opts) {
|
|
742
|
+
return this.c.post(this.base(repo), opts);
|
|
743
|
+
}
|
|
744
|
+
};
|
|
745
|
+
var GitPullsAPI = class extends GitIssuesAPI {
|
|
746
|
+
constructor(c) {
|
|
747
|
+
super(c, true);
|
|
748
|
+
}
|
|
749
|
+
create(repo, opts) {
|
|
750
|
+
return this.c.post(this.base(repo), opts);
|
|
751
|
+
}
|
|
752
|
+
/** Mark a draft ready for review. */
|
|
753
|
+
ready(repo, number) {
|
|
754
|
+
return this.update(repo, number, { draft: false });
|
|
755
|
+
}
|
|
756
|
+
merge(repo, number, opts = {}) {
|
|
757
|
+
return this.c.post(`${repoPath(repo)}/pulls/${number}/merge`, opts);
|
|
758
|
+
}
|
|
759
|
+
diff(repo, number) {
|
|
760
|
+
return this.c.get(`${repoPath(repo)}/pulls/${number}/diff`);
|
|
761
|
+
}
|
|
762
|
+
commits(repo, number) {
|
|
763
|
+
return this.c.get(`${repoPath(repo)}/pulls/${number}/commits`);
|
|
764
|
+
}
|
|
765
|
+
reviews(repo, number) {
|
|
766
|
+
return this.c.get(`${repoPath(repo)}/pulls/${number}/reviews`);
|
|
767
|
+
}
|
|
768
|
+
review(repo, number, opts) {
|
|
769
|
+
return this.c.post(`${repoPath(repo)}/pulls/${number}/reviews`, opts);
|
|
770
|
+
}
|
|
771
|
+
approve(repo, number, body = "") {
|
|
772
|
+
return this.review(repo, number, { event: "APPROVE", body });
|
|
773
|
+
}
|
|
774
|
+
requestChanges(repo, number, body) {
|
|
775
|
+
return this.review(repo, number, { event: "REQUEST_CHANGES", body });
|
|
776
|
+
}
|
|
777
|
+
lineComment(repo, number, c) {
|
|
778
|
+
return this.c.post(`${repoPath(repo)}/pulls/${number}/comments`, c);
|
|
779
|
+
}
|
|
780
|
+
deleteLineComment(repo, number, id) {
|
|
781
|
+
return this.c.delete(`${repoPath(repo)}/pulls/${number}/comments/${id}`);
|
|
782
|
+
}
|
|
783
|
+
/** The combined commit status of the pull request's head (CI and external checks). */
|
|
784
|
+
async checks(repo, number) {
|
|
785
|
+
const { pull } = await this.get(repo, number);
|
|
786
|
+
if (!pull?.headSha) throw new Error(`pull request #${number} has no head commit`);
|
|
787
|
+
return this.c.get(`${repoPath(repo)}/commits/${pull.headSha}/status`);
|
|
788
|
+
}
|
|
789
|
+
};
|
|
790
|
+
var GitSecretsAPI = class {
|
|
791
|
+
constructor(c) {
|
|
792
|
+
this.c = c;
|
|
793
|
+
}
|
|
794
|
+
list(repo) {
|
|
795
|
+
return this.c.get(`${repoPath(repo)}/actions/secrets`);
|
|
796
|
+
}
|
|
797
|
+
set(repo, name, value) {
|
|
798
|
+
return this.c.put(`${repoPath(repo)}/actions/secrets/${seg(name)}`, { value });
|
|
799
|
+
}
|
|
800
|
+
delete(repo, name) {
|
|
801
|
+
return this.c.delete(`${repoPath(repo)}/actions/secrets/${seg(name)}`);
|
|
802
|
+
}
|
|
803
|
+
};
|
|
804
|
+
var GitActionsAPI = class {
|
|
805
|
+
constructor(c) {
|
|
806
|
+
this.c = c;
|
|
807
|
+
this.secrets = new GitSecretsAPI(c);
|
|
808
|
+
}
|
|
809
|
+
runs(repo, opts = {}) {
|
|
810
|
+
return this.c.get(qs(`${repoPath(repo)}/actions/runs`, { ...opts }));
|
|
811
|
+
}
|
|
812
|
+
run(repo, number) {
|
|
813
|
+
return this.c.get(`${repoPath(repo)}/actions/runs/${number}`);
|
|
814
|
+
}
|
|
815
|
+
cancel(repo, number) {
|
|
816
|
+
return this.c.post(`${repoPath(repo)}/actions/runs/${number}/cancel`);
|
|
817
|
+
}
|
|
818
|
+
/** Run the same workflow at the same commit again (a new run). */
|
|
819
|
+
rerun(repo, number) {
|
|
820
|
+
return this.c.post(`${repoPath(repo)}/actions/runs/${number}/rerun`);
|
|
821
|
+
}
|
|
822
|
+
/** Let a run from a fork's pull request start (it waits for someone with write access). */
|
|
823
|
+
approve(repo, number) {
|
|
824
|
+
return this.c.post(`${repoPath(repo)}/actions/runs/${number}/approve`);
|
|
825
|
+
}
|
|
826
|
+
/** Part of a job's log from `offset`; follow `next` until `done`. */
|
|
827
|
+
log(repo, jobId, offset = 0) {
|
|
828
|
+
return this.c.get(qs(`${repoPath(repo)}/actions/jobs/${jobId}/log`, { offset }));
|
|
829
|
+
}
|
|
830
|
+
async fullLog(repo, jobId) {
|
|
831
|
+
return new TextDecoder().decode(await this.c.bytes(`${repoPath(repo)}/actions/jobs/${jobId}/log.txt`));
|
|
832
|
+
}
|
|
833
|
+
/** Each new piece of the log as it's written, until the job ends. */
|
|
834
|
+
async *followLog(repo, jobId, opts = {}) {
|
|
835
|
+
let offset = 0;
|
|
836
|
+
while (!opts.signal?.aborted) {
|
|
837
|
+
const chunk = await this.log(repo, jobId, offset);
|
|
838
|
+
if (chunk.text) yield chunk.text;
|
|
839
|
+
offset = chunk.next;
|
|
840
|
+
if (chunk.done && offset >= chunk.size) return;
|
|
841
|
+
if (!chunk.text) await new Promise((r) => setTimeout(r, opts.intervalMs ?? 1500));
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
/** Wait until the run ends (success, failure, cancelled, ...). */
|
|
845
|
+
async wait(repo, number, opts = {}) {
|
|
846
|
+
const until = Date.now() + (opts.timeoutMs ?? 30 * 6e4);
|
|
847
|
+
for (; ; ) {
|
|
848
|
+
const run = await this.run(repo, number);
|
|
849
|
+
if (!["queued", "running", "waiting", "pending"].includes(run.status)) return run;
|
|
850
|
+
if (Date.now() > until) throw new Error(`run ${number} is still ${run.status}`);
|
|
851
|
+
await new Promise((r) => setTimeout(r, opts.intervalMs ?? 3e3));
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
artifacts(repo, number) {
|
|
855
|
+
return this.c.get(`${repoPath(repo)}/actions/runs/${number}/artifacts`);
|
|
856
|
+
}
|
|
857
|
+
/** An artifact as a .tar.gz. */
|
|
858
|
+
downloadArtifact(repo, number, name) {
|
|
859
|
+
return this.c.bytes(`${repoPath(repo)}/actions/runs/${number}/artifacts/${seg(name)}`);
|
|
860
|
+
}
|
|
861
|
+
workflows(repo) {
|
|
862
|
+
return this.c.get(`${repoPath(repo)}/actions/workflows`);
|
|
863
|
+
}
|
|
864
|
+
/** Start a workflow that has `on: workflow_dispatch`. */
|
|
865
|
+
dispatch(repo, opts) {
|
|
866
|
+
return this.c.post(`${repoPath(repo)}/actions/workflows/dispatch`, opts);
|
|
867
|
+
}
|
|
868
|
+
/** Latest run status per commit, for the given commits. */
|
|
869
|
+
status(repo, shas) {
|
|
870
|
+
return this.c.get(qs(`${repoPath(repo)}/actions/status`, { shas: shas.join(",") }));
|
|
871
|
+
}
|
|
872
|
+
};
|
|
873
|
+
var GitCollaboratorsAPI = class {
|
|
874
|
+
constructor(c) {
|
|
875
|
+
this.c = c;
|
|
876
|
+
}
|
|
877
|
+
list(repo) {
|
|
878
|
+
return this.c.get(`${repoPath(repo)}/collaborators`);
|
|
879
|
+
}
|
|
880
|
+
/** Invite someone with a Lizard Git account (they sign in once first); they're in once they accept. */
|
|
881
|
+
invite(repo, login, role = "write") {
|
|
882
|
+
return this.c.post(`${repoPath(repo)}/collaborators`, { login, role });
|
|
883
|
+
}
|
|
884
|
+
setRole(repo, login, role) {
|
|
885
|
+
return this.c.patch(`${repoPath(repo)}/collaborators/${seg(login)}`, { role });
|
|
886
|
+
}
|
|
887
|
+
/** Remove someone (or yourself: leave). */
|
|
888
|
+
remove(repo, login) {
|
|
889
|
+
return this.c.delete(`${repoPath(repo)}/collaborators/${seg(login)}`);
|
|
890
|
+
}
|
|
891
|
+
cancelInvitation(repo, id) {
|
|
892
|
+
return this.c.delete(`${repoPath(repo)}/invitations/${id}`);
|
|
893
|
+
}
|
|
894
|
+
/** Invitations waiting for you. */
|
|
895
|
+
invitations() {
|
|
896
|
+
return this.c.get("/api/user/invitations");
|
|
897
|
+
}
|
|
898
|
+
accept(id) {
|
|
899
|
+
return this.c.post(`/api/user/invitations/${id}/accept`);
|
|
900
|
+
}
|
|
901
|
+
decline(id) {
|
|
902
|
+
return this.c.post(`/api/user/invitations/${id}/decline`);
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
var GitWebhooksAPI = class {
|
|
906
|
+
constructor(c) {
|
|
907
|
+
this.c = c;
|
|
908
|
+
}
|
|
909
|
+
list(repo) {
|
|
910
|
+
return this.c.get(`${repoPath(repo)}/hooks`);
|
|
911
|
+
}
|
|
912
|
+
/** GitHub-style payloads, signed with `X-Hub-Signature-256` when there's a secret. */
|
|
913
|
+
create(repo, opts) {
|
|
914
|
+
return this.c.post(`${repoPath(repo)}/hooks`, opts);
|
|
915
|
+
}
|
|
916
|
+
get(repo, id) {
|
|
917
|
+
return this.c.get(`${repoPath(repo)}/hooks/${id}`);
|
|
918
|
+
}
|
|
919
|
+
update(repo, id, opts) {
|
|
920
|
+
return this.c.patch(`${repoPath(repo)}/hooks/${id}`, opts);
|
|
921
|
+
}
|
|
922
|
+
delete(repo, id) {
|
|
923
|
+
return this.c.delete(`${repoPath(repo)}/hooks/${id}`);
|
|
924
|
+
}
|
|
925
|
+
ping(repo, id) {
|
|
926
|
+
return this.c.post(`${repoPath(repo)}/hooks/${id}/pings`);
|
|
927
|
+
}
|
|
928
|
+
deliveries(repo, id) {
|
|
929
|
+
return this.c.get(`${repoPath(repo)}/hooks/${id}/deliveries`);
|
|
930
|
+
}
|
|
931
|
+
delivery(repo, id, deliveryId) {
|
|
932
|
+
return this.c.get(`${repoPath(repo)}/hooks/${id}/deliveries/${deliveryId}`);
|
|
933
|
+
}
|
|
934
|
+
redeliver(repo, id, deliveryId) {
|
|
935
|
+
return this.c.post(`${repoPath(repo)}/hooks/${id}/deliveries/${deliveryId}/redeliver`);
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
var GitBranchRulesAPI = class {
|
|
939
|
+
constructor(c) {
|
|
940
|
+
this.c = c;
|
|
941
|
+
}
|
|
942
|
+
list(repo) {
|
|
943
|
+
return this.c.get(`${repoPath(repo)}/branch-rules`);
|
|
944
|
+
}
|
|
945
|
+
create(repo, opts) {
|
|
946
|
+
return this.c.post(`${repoPath(repo)}/branch-rules`, opts);
|
|
947
|
+
}
|
|
948
|
+
update(repo, id, opts) {
|
|
949
|
+
return this.c.patch(`${repoPath(repo)}/branch-rules/${id}`, opts);
|
|
950
|
+
}
|
|
951
|
+
delete(repo, id) {
|
|
952
|
+
return this.c.delete(`${repoPath(repo)}/branch-rules/${id}`);
|
|
953
|
+
}
|
|
954
|
+
};
|
|
955
|
+
var GitLabelsAPI = class {
|
|
956
|
+
constructor(c) {
|
|
957
|
+
this.c = c;
|
|
958
|
+
}
|
|
959
|
+
list(repo) {
|
|
960
|
+
return this.c.get(`${repoPath(repo)}/labels`);
|
|
961
|
+
}
|
|
962
|
+
create(repo, opts) {
|
|
963
|
+
return this.c.post(`${repoPath(repo)}/labels`, opts);
|
|
964
|
+
}
|
|
965
|
+
update(repo, name, opts) {
|
|
966
|
+
return this.c.patch(`${repoPath(repo)}/labels/${seg(name)}`, opts);
|
|
967
|
+
}
|
|
968
|
+
delete(repo, name) {
|
|
969
|
+
return this.c.delete(`${repoPath(repo)}/labels/${seg(name)}`);
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
var GitReleasesAPI = class {
|
|
973
|
+
constructor(c) {
|
|
974
|
+
this.c = c;
|
|
975
|
+
}
|
|
976
|
+
list(repo) {
|
|
977
|
+
return this.c.get(`${repoPath(repo)}/releases`);
|
|
978
|
+
}
|
|
979
|
+
/** Creates the tag too when it doesn't exist (at `target`, default branch by default). */
|
|
980
|
+
create(repo, opts) {
|
|
981
|
+
return this.c.post(`${repoPath(repo)}/releases`, opts);
|
|
982
|
+
}
|
|
983
|
+
get(repo, id) {
|
|
984
|
+
return this.c.get(`${repoPath(repo)}/releases/${id}`);
|
|
985
|
+
}
|
|
986
|
+
getByTag(repo, tag) {
|
|
987
|
+
return this.c.get(`${repoPath(repo)}/releases/tags/${seg(tag)}`);
|
|
988
|
+
}
|
|
989
|
+
update(repo, id, opts) {
|
|
990
|
+
return this.c.patch(`${repoPath(repo)}/releases/${id}`, opts);
|
|
991
|
+
}
|
|
992
|
+
delete(repo, id) {
|
|
993
|
+
return this.c.delete(`${repoPath(repo)}/releases/${id}`);
|
|
994
|
+
}
|
|
995
|
+
async uploadAsset(repo, id, name, data, contentType = "application/octet-stream") {
|
|
996
|
+
const body = typeof data === "string" || data instanceof Blob ? data : new Blob([new Uint8Array(data)]);
|
|
997
|
+
const res = await this.c.raw("POST", qs(`${repoPath(repo)}/releases/${id}/assets`, { name }), body, { "Content-Type": contentType });
|
|
998
|
+
return res.json();
|
|
999
|
+
}
|
|
1000
|
+
downloadAsset(repo, id, assetId) {
|
|
1001
|
+
return this.c.bytes(`${repoPath(repo)}/releases/${id}/assets/${assetId}`);
|
|
1002
|
+
}
|
|
1003
|
+
deleteAsset(repo, id, assetId) {
|
|
1004
|
+
return this.c.delete(`${repoPath(repo)}/releases/${id}/assets/${assetId}`);
|
|
1005
|
+
}
|
|
1006
|
+
};
|
|
1007
|
+
var GitStatusesAPI = class {
|
|
1008
|
+
constructor(c) {
|
|
1009
|
+
this.c = c;
|
|
1010
|
+
}
|
|
1011
|
+
/** Report a check on a commit (what required checks in branch rules wait for). */
|
|
1012
|
+
create(repo, sha, status) {
|
|
1013
|
+
return this.c.post(`${repoPath(repo)}/statuses/${seg(sha)}`, status);
|
|
1014
|
+
}
|
|
1015
|
+
list(repo, ref) {
|
|
1016
|
+
return this.c.get(`${repoPath(repo)}/commits/${seg(ref)}/statuses`);
|
|
1017
|
+
}
|
|
1018
|
+
combined(repo, ref) {
|
|
1019
|
+
return this.c.get(`${repoPath(repo)}/commits/${seg(ref)}/status`);
|
|
1020
|
+
}
|
|
1021
|
+
};
|
|
1022
|
+
var GitNotificationsAPI = class {
|
|
1023
|
+
constructor(c) {
|
|
1024
|
+
this.c = c;
|
|
1025
|
+
}
|
|
1026
|
+
list(opts = {}) {
|
|
1027
|
+
return this.c.get(qs("/api/notifications", { all: opts.all ? 1 : void 0 }));
|
|
1028
|
+
}
|
|
1029
|
+
markRead(ids) {
|
|
1030
|
+
return this.c.post("/api/notifications/read", ids?.length ? { ids } : { all: true });
|
|
1031
|
+
}
|
|
1032
|
+
};
|
|
1033
|
+
var GitTokensAPI = class {
|
|
1034
|
+
constructor(c) {
|
|
1035
|
+
this.c = c;
|
|
1036
|
+
}
|
|
1037
|
+
list() {
|
|
1038
|
+
return this.c.get("/api/user/tokens");
|
|
1039
|
+
}
|
|
1040
|
+
/** A Lizard Git token (lzg_...), optionally limited to repos, refs, paths, or read-only. The secret is in `token`, once. */
|
|
1041
|
+
create(opts) {
|
|
1042
|
+
return this.c.post("/api/user/tokens", opts);
|
|
1043
|
+
}
|
|
1044
|
+
delete(id) {
|
|
1045
|
+
return this.c.delete(`/api/user/tokens/${id}`);
|
|
1046
|
+
}
|
|
1047
|
+
};
|
|
1048
|
+
var GitAPI = class {
|
|
1049
|
+
constructor(config, url) {
|
|
1050
|
+
const c = this.client = new GitClient(config, url);
|
|
1051
|
+
this.repos = new GitReposAPI(c);
|
|
1052
|
+
this.issues = new GitIssuesOnlyAPI(c);
|
|
1053
|
+
this.pulls = new GitPullsAPI(c);
|
|
1054
|
+
this.actions = new GitActionsAPI(c);
|
|
1055
|
+
this.collaborators = new GitCollaboratorsAPI(c);
|
|
1056
|
+
this.webhooks = new GitWebhooksAPI(c);
|
|
1057
|
+
this.branchRules = new GitBranchRulesAPI(c);
|
|
1058
|
+
this.labels = new GitLabelsAPI(c);
|
|
1059
|
+
this.releases = new GitReleasesAPI(c);
|
|
1060
|
+
this.statuses = new GitStatusesAPI(c);
|
|
1061
|
+
this.notifications = new GitNotificationsAPI(c);
|
|
1062
|
+
this.tokens = new GitTokensAPI(c);
|
|
1063
|
+
}
|
|
1064
|
+
/** Who the key signs in as on Lizard Git. */
|
|
1065
|
+
me() {
|
|
1066
|
+
return this.client.get("/api/session");
|
|
1067
|
+
}
|
|
1068
|
+
user(login) {
|
|
1069
|
+
return this.client.get(`/api/users/${seg(login)}`);
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1072
|
+
|
|
538
1073
|
// src/project.ts
|
|
539
1074
|
var import_node_crypto = require("crypto");
|
|
540
1075
|
var projectIdCache = /* @__PURE__ */ new Map();
|
|
@@ -866,7 +1401,7 @@ var Fs = class {
|
|
|
866
1401
|
* }, 1000)
|
|
867
1402
|
* ```
|
|
868
1403
|
*
|
|
869
|
-
* Not available
|
|
1404
|
+
* Not available yet: the call throws `LizardError` (501).
|
|
870
1405
|
*/
|
|
871
1406
|
async watch(path, opts) {
|
|
872
1407
|
const res = await fetch(`${this.config.apiUrl}/api/sandboxes/${this.sandboxId}/files/watch`, {
|
|
@@ -1331,7 +1866,7 @@ var Sandbox = class extends SandboxClient {
|
|
|
1331
1866
|
* snapshot. A Firecracker snapshot is `ready` as soon as this returns: about 2 s, up to
|
|
1332
1867
|
* a few minutes for a sandbox that filled most of its memory (its memory is uploaded
|
|
1333
1868
|
* first), so the call waits up to 11 minutes. Start copies of it with {@link Sandbox.restore}
|
|
1334
|
-
* (about 0.4 s each). The source keeps running.
|
|
1869
|
+
* (about 0.4 s each). The source keeps running. Firecracker snapshots ignore `poolSize`.
|
|
1335
1870
|
*/
|
|
1336
1871
|
snapshot(name = `Snapshot ${this.sandboxId}`, opts = {}) {
|
|
1337
1872
|
return new PlatformClient(this.resolveOpts()).post(`/api/sandboxes/${this.sandboxId}/snapshot`, { name, poolSize: opts.poolSize ?? 5, scope: opts.scope }, SNAPSHOT_TIMEOUT_MS);
|
|
@@ -1339,7 +1874,7 @@ var Sandbox = class extends SandboxClient {
|
|
|
1339
1874
|
unexpose(port) {
|
|
1340
1875
|
return new PlatformClient(this.resolveOpts()).delete(`/api/sandboxes/${this.sandboxId}/expose/${port}`);
|
|
1341
1876
|
}
|
|
1342
|
-
/** Stream the sandbox's logs. Not available
|
|
1877
|
+
/** Stream the sandbox's logs. Not available yet (`LizardError`, 501). */
|
|
1343
1878
|
logs(opts = {}) {
|
|
1344
1879
|
return new PlatformClient(this.resolveOpts()).events(query(`/api/sandboxes/${this.sandboxId}/logs`, { tail: opts.tail }), { signal: opts.signal });
|
|
1345
1880
|
}
|
|
@@ -1378,7 +1913,7 @@ var Sandbox = class extends SandboxClient {
|
|
|
1378
1913
|
static setSnapshotWarmPool(snapshotId, poolSize, opts) {
|
|
1379
1914
|
return new PlatformClient(opts ?? {}).patch(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}`, { poolSize });
|
|
1380
1915
|
}
|
|
1381
|
-
/** Release idle warm copies
|
|
1916
|
+
/** Release idle warm copies of an older snapshot; retain saved state and existing claimed sandboxes. Firecracker snapshots have no warm copies. */
|
|
1382
1917
|
static pauseSnapshot(snapshotId, opts) {
|
|
1383
1918
|
return new PlatformClient(opts ?? {}).post(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}/pause`, {});
|
|
1384
1919
|
}
|
|
@@ -1414,8 +1949,8 @@ var ProjectsAPI = class {
|
|
|
1414
1949
|
}
|
|
1415
1950
|
/** List all projects the API key can access. */
|
|
1416
1951
|
list(opts) {
|
|
1417
|
-
const
|
|
1418
|
-
return this.client.get(`/api/projects${
|
|
1952
|
+
const qs2 = opts?.workspaceId ? `?workspaceId=${opts.workspaceId}` : "";
|
|
1953
|
+
return this.client.get(`/api/projects${qs2}`);
|
|
1419
1954
|
}
|
|
1420
1955
|
/** Get a project by ID. */
|
|
1421
1956
|
get(id) {
|
|
@@ -1808,8 +2343,8 @@ var WorkspacesAPI = class {
|
|
|
1808
2343
|
* volumes and snapshots first.
|
|
1809
2344
|
*/
|
|
1810
2345
|
delete(id, opts) {
|
|
1811
|
-
const
|
|
1812
|
-
return this.client.delete(`/api/workspaces/${id}${
|
|
2346
|
+
const qs2 = opts?.force ? "" : "?requireEmpty=true";
|
|
2347
|
+
return this.client.delete(`/api/workspaces/${id}${qs2}`);
|
|
1813
2348
|
}
|
|
1814
2349
|
/**
|
|
1815
2350
|
* Find a workspace by name, slug, or id, or `null` if there is no such workspace.
|
|
@@ -1999,13 +2534,11 @@ var Volume = class _Volume {
|
|
|
1999
2534
|
/**
|
|
2000
2535
|
* Resize a volume, by name or by id, to `sizeGb`.
|
|
2001
2536
|
*
|
|
2002
|
-
* A
|
|
2003
|
-
*
|
|
2004
|
-
*
|
|
2537
|
+
* A volume grows in place and online: a sandbox with the volume attached keeps
|
|
2538
|
+
* running and sees the new size. A smaller size throws `LizardError` (400) with
|
|
2539
|
+
* `code: 'volume_shrink_unsupported'`.
|
|
2005
2540
|
*
|
|
2006
|
-
*
|
|
2007
|
-
* so no data is copied and a mounted sandbox sees the new size immediately. Both
|
|
2008
|
-
* growing and shrinking are allowed, but a shrink must leave at least 10% of the
|
|
2541
|
+
* An older volume can also shrink, but the shrink must leave at least 10% of the
|
|
2009
2542
|
* new size free — otherwise it throws `ConflictError` with
|
|
2010
2543
|
* `code: 'volume_too_full_to_shrink'`.
|
|
2011
2544
|
*
|
|
@@ -2015,7 +2548,7 @@ var Volume = class _Volume {
|
|
|
2015
2548
|
* `volume_capacity_unavailable`, and `volume_resize_timeout` (a `TimeoutError`;
|
|
2016
2549
|
* the size is left unchanged).
|
|
2017
2550
|
*
|
|
2018
|
-
* @returns The volume's updated info, including `sizeEnforced` for
|
|
2551
|
+
* @returns The volume's updated info, including `sizeEnforced` for an older volume.
|
|
2019
2552
|
*/
|
|
2020
2553
|
static async resize(projectId, nameOrId, sizeGb, opts) {
|
|
2021
2554
|
const config = new ConnectionConfig(opts);
|
|
@@ -2093,6 +2626,7 @@ var Lizard = class {
|
|
|
2093
2626
|
this.metrics = new MetricsAPI(platform);
|
|
2094
2627
|
this.storage = new StorageAPI(platform);
|
|
2095
2628
|
this.github = new GitHubAPI(platform);
|
|
2629
|
+
this.git = new GitAPI(this.config, opts.gitUrl);
|
|
2096
2630
|
}
|
|
2097
2631
|
// ── Sandbox convenience methods (backward-compatible) ──────────────────
|
|
2098
2632
|
/** Resolve the client's project reference to a stable project ID (cached). */
|
|
@@ -2705,10 +3239,26 @@ var LizardCLI = class {
|
|
|
2705
3239
|
CodeSandbox,
|
|
2706
3240
|
ConfigApplyError,
|
|
2707
3241
|
ConflictError,
|
|
3242
|
+
DEFAULT_GIT_URL,
|
|
2708
3243
|
DeployHandle,
|
|
2709
3244
|
Desktop,
|
|
2710
3245
|
DomainsAPI,
|
|
3246
|
+
GitAPI,
|
|
3247
|
+
GitActionsAPI,
|
|
3248
|
+
GitBranchRulesAPI,
|
|
3249
|
+
GitClient,
|
|
3250
|
+
GitCollaboratorsAPI,
|
|
2711
3251
|
GitHubAPI,
|
|
3252
|
+
GitIssuesOnlyAPI,
|
|
3253
|
+
GitLabelsAPI,
|
|
3254
|
+
GitNotificationsAPI,
|
|
3255
|
+
GitPullsAPI,
|
|
3256
|
+
GitReleasesAPI,
|
|
3257
|
+
GitReposAPI,
|
|
3258
|
+
GitSecretsAPI,
|
|
3259
|
+
GitStatusesAPI,
|
|
3260
|
+
GitTokensAPI,
|
|
3261
|
+
GitWebhooksAPI,
|
|
2712
3262
|
LimitExceededError,
|
|
2713
3263
|
Lizard,
|
|
2714
3264
|
LizardCLI,
|