@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.mjs
CHANGED
|
@@ -125,9 +125,9 @@ async function handleApiError(res) {
|
|
|
125
125
|
// src/platform/client.ts
|
|
126
126
|
var segment = (value) => encodeURIComponent(value);
|
|
127
127
|
function query(path, values) {
|
|
128
|
-
const
|
|
129
|
-
for (const [key, value] of Object.entries(values)) if (value !== void 0)
|
|
130
|
-
return
|
|
128
|
+
const qs2 = new URLSearchParams();
|
|
129
|
+
for (const [key, value] of Object.entries(values)) if (value !== void 0) qs2.set(key, String(value));
|
|
130
|
+
return qs2.size ? `${path}?${qs2}` : path;
|
|
131
131
|
}
|
|
132
132
|
var PlatformClient = class {
|
|
133
133
|
constructor(opts) {
|
|
@@ -481,6 +481,525 @@ var GitHubAPI = class {
|
|
|
481
481
|
}
|
|
482
482
|
};
|
|
483
483
|
|
|
484
|
+
// src/platform/git.ts
|
|
485
|
+
var DEFAULT_GIT_URL = "https://git.lizard.build";
|
|
486
|
+
var seg = encodeURIComponent;
|
|
487
|
+
function qs(path, values) {
|
|
488
|
+
const q = new URLSearchParams();
|
|
489
|
+
for (const [k, v] of Object.entries(values)) if (v !== void 0 && v !== "") q.set(k, String(v));
|
|
490
|
+
return q.size ? `${path}?${q}` : path;
|
|
491
|
+
}
|
|
492
|
+
function repoPath(repo) {
|
|
493
|
+
const m = /^([^/\s]+)\/([^/\s]+?)(\.git)?$/.exec(repo);
|
|
494
|
+
if (!m) throw new Error(`repository must be "owner/name", got "${repo}"`);
|
|
495
|
+
return `/api/repos/${seg(m[1])}/${seg(m[2])}`;
|
|
496
|
+
}
|
|
497
|
+
var GitClient = class {
|
|
498
|
+
constructor(config, url) {
|
|
499
|
+
this.config = config;
|
|
500
|
+
this.url = (url ?? process.env.LIZARD_GIT_URL ?? DEFAULT_GIT_URL).replace(/\/+$/, "");
|
|
501
|
+
}
|
|
502
|
+
async raw(method, path, body, headers = {}) {
|
|
503
|
+
const res = await fetch(this.url + path, {
|
|
504
|
+
method,
|
|
505
|
+
body,
|
|
506
|
+
headers: { "X-API-Key": this.config.apiKey, ...headers },
|
|
507
|
+
signal: AbortSignal.timeout(this.config.requestTimeoutMs)
|
|
508
|
+
});
|
|
509
|
+
if (!res.ok) await handleApiError(res);
|
|
510
|
+
return res;
|
|
511
|
+
}
|
|
512
|
+
async request(method, path, body, headers = {}) {
|
|
513
|
+
const res = await this.raw(
|
|
514
|
+
method,
|
|
515
|
+
path,
|
|
516
|
+
body === void 0 ? void 0 : JSON.stringify(body),
|
|
517
|
+
body === void 0 ? headers : { "Content-Type": "application/json", ...headers }
|
|
518
|
+
);
|
|
519
|
+
const text = res.status === 204 ? "" : await res.text();
|
|
520
|
+
return text ? JSON.parse(text) : void 0;
|
|
521
|
+
}
|
|
522
|
+
get(path) {
|
|
523
|
+
return this.request("GET", path);
|
|
524
|
+
}
|
|
525
|
+
post(path, body) {
|
|
526
|
+
return this.request("POST", path, body ?? {});
|
|
527
|
+
}
|
|
528
|
+
put(path, body) {
|
|
529
|
+
return this.request("PUT", path, body ?? {});
|
|
530
|
+
}
|
|
531
|
+
patch(path, body) {
|
|
532
|
+
return this.request("PATCH", path, body);
|
|
533
|
+
}
|
|
534
|
+
delete(path) {
|
|
535
|
+
return this.request("DELETE", path);
|
|
536
|
+
}
|
|
537
|
+
async bytes(path) {
|
|
538
|
+
return new Uint8Array(await (await this.raw("GET", path)).arrayBuffer());
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
var GitReposAPI = class {
|
|
542
|
+
constructor(c) {
|
|
543
|
+
this.c = c;
|
|
544
|
+
}
|
|
545
|
+
/** Yours and the ones you collaborate on by default; `owner`, `q`, `starred` narrow it. */
|
|
546
|
+
list(opts = {}) {
|
|
547
|
+
return this.c.get(qs("/api/repos", opts));
|
|
548
|
+
}
|
|
549
|
+
/** Answers the new repository's `owner` and `name`. */
|
|
550
|
+
create(opts) {
|
|
551
|
+
return this.c.post("/api/repos", opts);
|
|
552
|
+
}
|
|
553
|
+
get(repo) {
|
|
554
|
+
return this.c.get(repoPath(repo));
|
|
555
|
+
}
|
|
556
|
+
update(repo, opts) {
|
|
557
|
+
return this.c.patch(repoPath(repo), opts);
|
|
558
|
+
}
|
|
559
|
+
delete(repo) {
|
|
560
|
+
return this.c.delete(repoPath(repo));
|
|
561
|
+
}
|
|
562
|
+
star(repo) {
|
|
563
|
+
return this.c.put(`${repoPath(repo)}/star`);
|
|
564
|
+
}
|
|
565
|
+
unstar(repo) {
|
|
566
|
+
return this.c.delete(`${repoPath(repo)}/star`);
|
|
567
|
+
}
|
|
568
|
+
/** Fork into your account (`name` defaults to the same name). */
|
|
569
|
+
fork(repo, opts = {}) {
|
|
570
|
+
return this.c.post(`${repoPath(repo)}/forks`, opts);
|
|
571
|
+
}
|
|
572
|
+
forks(repo) {
|
|
573
|
+
return this.c.get(`${repoPath(repo)}/forks`);
|
|
574
|
+
}
|
|
575
|
+
/** Branches and tags. */
|
|
576
|
+
refs(repo) {
|
|
577
|
+
return this.c.get(`${repoPath(repo)}/refs`);
|
|
578
|
+
}
|
|
579
|
+
createBranch(repo, name, from) {
|
|
580
|
+
return this.c.post(`${repoPath(repo)}/branches`, { name, from });
|
|
581
|
+
}
|
|
582
|
+
deleteBranch(repo, name) {
|
|
583
|
+
return this.c.delete(`${repoPath(repo)}/branches/${name.split("/").map(seg).join("/")}`);
|
|
584
|
+
}
|
|
585
|
+
tree(repo, opts = {}) {
|
|
586
|
+
return this.c.get(qs(`${repoPath(repo)}/tree`, opts));
|
|
587
|
+
}
|
|
588
|
+
/** A file as JSON (text in `content`). */
|
|
589
|
+
file(repo, path, ref) {
|
|
590
|
+
return this.c.get(qs(`${repoPath(repo)}/blob`, { path, ref }));
|
|
591
|
+
}
|
|
592
|
+
/** A file's bytes, whatever its size or type. */
|
|
593
|
+
raw(repo, path, ref) {
|
|
594
|
+
const [owner, name] = repo.split("/");
|
|
595
|
+
return this.c.bytes(`/raw/${seg(owner)}/${seg(name)}/${ref.split("/").map(seg).join("/")}/${path.split("/").map(seg).join("/")}`);
|
|
596
|
+
}
|
|
597
|
+
/** Every file path at a ref. */
|
|
598
|
+
files(repo, ref) {
|
|
599
|
+
return this.c.get(qs(`${repoPath(repo)}/files`, { ref }));
|
|
600
|
+
}
|
|
601
|
+
search(repo, q, ref) {
|
|
602
|
+
return this.c.get(qs(`${repoPath(repo)}/search`, { q, ref }));
|
|
603
|
+
}
|
|
604
|
+
commits(repo, opts = {}) {
|
|
605
|
+
return this.c.get(qs(`${repoPath(repo)}/commits`, opts));
|
|
606
|
+
}
|
|
607
|
+
commit(repo, sha) {
|
|
608
|
+
return this.c.get(`${repoPath(repo)}/commits/${seg(sha)}`);
|
|
609
|
+
}
|
|
610
|
+
compare(repo, base, head) {
|
|
611
|
+
return this.c.get(qs(`${repoPath(repo)}/compare`, { base, head }));
|
|
612
|
+
}
|
|
613
|
+
/** Commit files on the server: no clone, no push. Answers 409 when `expect` no longer matches. */
|
|
614
|
+
commitFiles(repo, opts) {
|
|
615
|
+
const { idempotencyKey, ...body } = opts;
|
|
616
|
+
return this.c.request("POST", `${repoPath(repo)}/commits`, body, idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {});
|
|
617
|
+
}
|
|
618
|
+
/** Rebase `head` (branch or commit) onto `onto` on the server and move `onto` there; retried on races. */
|
|
619
|
+
land(repo, opts) {
|
|
620
|
+
return this.c.post(`${repoPath(repo)}/land`, opts);
|
|
621
|
+
}
|
|
622
|
+
/** Who moved which branch, when. */
|
|
623
|
+
reflog(repo, ref) {
|
|
624
|
+
return this.c.get(qs(`${repoPath(repo)}/reflog`, { ref }));
|
|
625
|
+
}
|
|
626
|
+
archive(repo, ref, format = "tar.gz") {
|
|
627
|
+
return this.c.bytes(`${repoPath(repo)}/archive/${seg(ref)}.${format}`);
|
|
628
|
+
}
|
|
629
|
+
/** The HTTPS clone URL. With `withKey`, it carries the API key, so plain `git clone` works without a helper. */
|
|
630
|
+
cloneUrl(repo, opts = {}) {
|
|
631
|
+
repoPath(repo);
|
|
632
|
+
const u = new URL(`${this.c.url}/${repo.replace(/\.git$/, "")}.git`);
|
|
633
|
+
if (opts.withKey) {
|
|
634
|
+
u.username = "lizard";
|
|
635
|
+
u.password = this.c.config.apiKey;
|
|
636
|
+
}
|
|
637
|
+
return u.toString();
|
|
638
|
+
}
|
|
639
|
+
};
|
|
640
|
+
var GitIssuesAPI = class {
|
|
641
|
+
constructor(c, pulls = false) {
|
|
642
|
+
this.c = c;
|
|
643
|
+
this.pulls = pulls;
|
|
644
|
+
}
|
|
645
|
+
base(repo) {
|
|
646
|
+
return `${repoPath(repo)}/issues`;
|
|
647
|
+
}
|
|
648
|
+
list(repo, opts = {}) {
|
|
649
|
+
return this.c.get(qs(this.base(repo), { ...opts, pulls: this.pulls ? 1 : void 0 }));
|
|
650
|
+
}
|
|
651
|
+
get(repo, number) {
|
|
652
|
+
return this.c.get(`${this.base(repo)}/${number}`);
|
|
653
|
+
}
|
|
654
|
+
update(repo, number, opts) {
|
|
655
|
+
return this.c.patch(`${this.base(repo)}/${number}`, opts);
|
|
656
|
+
}
|
|
657
|
+
comment(repo, number, body) {
|
|
658
|
+
return this.c.post(`${this.base(repo)}/${number}/comments`, { body });
|
|
659
|
+
}
|
|
660
|
+
close(repo, number) {
|
|
661
|
+
return this.update(repo, number, { state: "closed" });
|
|
662
|
+
}
|
|
663
|
+
reopen(repo, number) {
|
|
664
|
+
return this.update(repo, number, { state: "open" });
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
var GitIssuesOnlyAPI = class extends GitIssuesAPI {
|
|
668
|
+
constructor(c) {
|
|
669
|
+
super(c, false);
|
|
670
|
+
}
|
|
671
|
+
create(repo, opts) {
|
|
672
|
+
return this.c.post(this.base(repo), opts);
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
var GitPullsAPI = class extends GitIssuesAPI {
|
|
676
|
+
constructor(c) {
|
|
677
|
+
super(c, true);
|
|
678
|
+
}
|
|
679
|
+
create(repo, opts) {
|
|
680
|
+
return this.c.post(this.base(repo), opts);
|
|
681
|
+
}
|
|
682
|
+
/** Mark a draft ready for review. */
|
|
683
|
+
ready(repo, number) {
|
|
684
|
+
return this.update(repo, number, { draft: false });
|
|
685
|
+
}
|
|
686
|
+
merge(repo, number, opts = {}) {
|
|
687
|
+
return this.c.post(`${repoPath(repo)}/pulls/${number}/merge`, opts);
|
|
688
|
+
}
|
|
689
|
+
diff(repo, number) {
|
|
690
|
+
return this.c.get(`${repoPath(repo)}/pulls/${number}/diff`);
|
|
691
|
+
}
|
|
692
|
+
commits(repo, number) {
|
|
693
|
+
return this.c.get(`${repoPath(repo)}/pulls/${number}/commits`);
|
|
694
|
+
}
|
|
695
|
+
reviews(repo, number) {
|
|
696
|
+
return this.c.get(`${repoPath(repo)}/pulls/${number}/reviews`);
|
|
697
|
+
}
|
|
698
|
+
review(repo, number, opts) {
|
|
699
|
+
return this.c.post(`${repoPath(repo)}/pulls/${number}/reviews`, opts);
|
|
700
|
+
}
|
|
701
|
+
approve(repo, number, body = "") {
|
|
702
|
+
return this.review(repo, number, { event: "APPROVE", body });
|
|
703
|
+
}
|
|
704
|
+
requestChanges(repo, number, body) {
|
|
705
|
+
return this.review(repo, number, { event: "REQUEST_CHANGES", body });
|
|
706
|
+
}
|
|
707
|
+
lineComment(repo, number, c) {
|
|
708
|
+
return this.c.post(`${repoPath(repo)}/pulls/${number}/comments`, c);
|
|
709
|
+
}
|
|
710
|
+
deleteLineComment(repo, number, id) {
|
|
711
|
+
return this.c.delete(`${repoPath(repo)}/pulls/${number}/comments/${id}`);
|
|
712
|
+
}
|
|
713
|
+
/** The combined commit status of the pull request's head (CI and external checks). */
|
|
714
|
+
async checks(repo, number) {
|
|
715
|
+
const { pull } = await this.get(repo, number);
|
|
716
|
+
if (!pull?.headSha) throw new Error(`pull request #${number} has no head commit`);
|
|
717
|
+
return this.c.get(`${repoPath(repo)}/commits/${pull.headSha}/status`);
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
var GitSecretsAPI = class {
|
|
721
|
+
constructor(c) {
|
|
722
|
+
this.c = c;
|
|
723
|
+
}
|
|
724
|
+
list(repo) {
|
|
725
|
+
return this.c.get(`${repoPath(repo)}/actions/secrets`);
|
|
726
|
+
}
|
|
727
|
+
set(repo, name, value) {
|
|
728
|
+
return this.c.put(`${repoPath(repo)}/actions/secrets/${seg(name)}`, { value });
|
|
729
|
+
}
|
|
730
|
+
delete(repo, name) {
|
|
731
|
+
return this.c.delete(`${repoPath(repo)}/actions/secrets/${seg(name)}`);
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
var GitActionsAPI = class {
|
|
735
|
+
constructor(c) {
|
|
736
|
+
this.c = c;
|
|
737
|
+
this.secrets = new GitSecretsAPI(c);
|
|
738
|
+
}
|
|
739
|
+
runs(repo, opts = {}) {
|
|
740
|
+
return this.c.get(qs(`${repoPath(repo)}/actions/runs`, { ...opts }));
|
|
741
|
+
}
|
|
742
|
+
run(repo, number) {
|
|
743
|
+
return this.c.get(`${repoPath(repo)}/actions/runs/${number}`);
|
|
744
|
+
}
|
|
745
|
+
cancel(repo, number) {
|
|
746
|
+
return this.c.post(`${repoPath(repo)}/actions/runs/${number}/cancel`);
|
|
747
|
+
}
|
|
748
|
+
/** Run the same workflow at the same commit again (a new run). */
|
|
749
|
+
rerun(repo, number) {
|
|
750
|
+
return this.c.post(`${repoPath(repo)}/actions/runs/${number}/rerun`);
|
|
751
|
+
}
|
|
752
|
+
/** Let a run from a fork's pull request start (it waits for someone with write access). */
|
|
753
|
+
approve(repo, number) {
|
|
754
|
+
return this.c.post(`${repoPath(repo)}/actions/runs/${number}/approve`);
|
|
755
|
+
}
|
|
756
|
+
/** Part of a job's log from `offset`; follow `next` until `done`. */
|
|
757
|
+
log(repo, jobId, offset = 0) {
|
|
758
|
+
return this.c.get(qs(`${repoPath(repo)}/actions/jobs/${jobId}/log`, { offset }));
|
|
759
|
+
}
|
|
760
|
+
async fullLog(repo, jobId) {
|
|
761
|
+
return new TextDecoder().decode(await this.c.bytes(`${repoPath(repo)}/actions/jobs/${jobId}/log.txt`));
|
|
762
|
+
}
|
|
763
|
+
/** Each new piece of the log as it's written, until the job ends. */
|
|
764
|
+
async *followLog(repo, jobId, opts = {}) {
|
|
765
|
+
let offset = 0;
|
|
766
|
+
while (!opts.signal?.aborted) {
|
|
767
|
+
const chunk = await this.log(repo, jobId, offset);
|
|
768
|
+
if (chunk.text) yield chunk.text;
|
|
769
|
+
offset = chunk.next;
|
|
770
|
+
if (chunk.done && offset >= chunk.size) return;
|
|
771
|
+
if (!chunk.text) await new Promise((r) => setTimeout(r, opts.intervalMs ?? 1500));
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
/** Wait until the run ends (success, failure, cancelled, ...). */
|
|
775
|
+
async wait(repo, number, opts = {}) {
|
|
776
|
+
const until = Date.now() + (opts.timeoutMs ?? 30 * 6e4);
|
|
777
|
+
for (; ; ) {
|
|
778
|
+
const run = await this.run(repo, number);
|
|
779
|
+
if (!["queued", "running", "waiting", "pending"].includes(run.status)) return run;
|
|
780
|
+
if (Date.now() > until) throw new Error(`run ${number} is still ${run.status}`);
|
|
781
|
+
await new Promise((r) => setTimeout(r, opts.intervalMs ?? 3e3));
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
artifacts(repo, number) {
|
|
785
|
+
return this.c.get(`${repoPath(repo)}/actions/runs/${number}/artifacts`);
|
|
786
|
+
}
|
|
787
|
+
/** An artifact as a .tar.gz. */
|
|
788
|
+
downloadArtifact(repo, number, name) {
|
|
789
|
+
return this.c.bytes(`${repoPath(repo)}/actions/runs/${number}/artifacts/${seg(name)}`);
|
|
790
|
+
}
|
|
791
|
+
workflows(repo) {
|
|
792
|
+
return this.c.get(`${repoPath(repo)}/actions/workflows`);
|
|
793
|
+
}
|
|
794
|
+
/** Start a workflow that has `on: workflow_dispatch`. */
|
|
795
|
+
dispatch(repo, opts) {
|
|
796
|
+
return this.c.post(`${repoPath(repo)}/actions/workflows/dispatch`, opts);
|
|
797
|
+
}
|
|
798
|
+
/** Latest run status per commit, for the given commits. */
|
|
799
|
+
status(repo, shas) {
|
|
800
|
+
return this.c.get(qs(`${repoPath(repo)}/actions/status`, { shas: shas.join(",") }));
|
|
801
|
+
}
|
|
802
|
+
};
|
|
803
|
+
var GitCollaboratorsAPI = class {
|
|
804
|
+
constructor(c) {
|
|
805
|
+
this.c = c;
|
|
806
|
+
}
|
|
807
|
+
list(repo) {
|
|
808
|
+
return this.c.get(`${repoPath(repo)}/collaborators`);
|
|
809
|
+
}
|
|
810
|
+
/** Invite someone with a Lizard Git account (they sign in once first); they're in once they accept. */
|
|
811
|
+
invite(repo, login, role = "write") {
|
|
812
|
+
return this.c.post(`${repoPath(repo)}/collaborators`, { login, role });
|
|
813
|
+
}
|
|
814
|
+
setRole(repo, login, role) {
|
|
815
|
+
return this.c.patch(`${repoPath(repo)}/collaborators/${seg(login)}`, { role });
|
|
816
|
+
}
|
|
817
|
+
/** Remove someone (or yourself: leave). */
|
|
818
|
+
remove(repo, login) {
|
|
819
|
+
return this.c.delete(`${repoPath(repo)}/collaborators/${seg(login)}`);
|
|
820
|
+
}
|
|
821
|
+
cancelInvitation(repo, id) {
|
|
822
|
+
return this.c.delete(`${repoPath(repo)}/invitations/${id}`);
|
|
823
|
+
}
|
|
824
|
+
/** Invitations waiting for you. */
|
|
825
|
+
invitations() {
|
|
826
|
+
return this.c.get("/api/user/invitations");
|
|
827
|
+
}
|
|
828
|
+
accept(id) {
|
|
829
|
+
return this.c.post(`/api/user/invitations/${id}/accept`);
|
|
830
|
+
}
|
|
831
|
+
decline(id) {
|
|
832
|
+
return this.c.post(`/api/user/invitations/${id}/decline`);
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
var GitWebhooksAPI = class {
|
|
836
|
+
constructor(c) {
|
|
837
|
+
this.c = c;
|
|
838
|
+
}
|
|
839
|
+
list(repo) {
|
|
840
|
+
return this.c.get(`${repoPath(repo)}/hooks`);
|
|
841
|
+
}
|
|
842
|
+
/** GitHub-style payloads, signed with `X-Hub-Signature-256` when there's a secret. */
|
|
843
|
+
create(repo, opts) {
|
|
844
|
+
return this.c.post(`${repoPath(repo)}/hooks`, opts);
|
|
845
|
+
}
|
|
846
|
+
get(repo, id) {
|
|
847
|
+
return this.c.get(`${repoPath(repo)}/hooks/${id}`);
|
|
848
|
+
}
|
|
849
|
+
update(repo, id, opts) {
|
|
850
|
+
return this.c.patch(`${repoPath(repo)}/hooks/${id}`, opts);
|
|
851
|
+
}
|
|
852
|
+
delete(repo, id) {
|
|
853
|
+
return this.c.delete(`${repoPath(repo)}/hooks/${id}`);
|
|
854
|
+
}
|
|
855
|
+
ping(repo, id) {
|
|
856
|
+
return this.c.post(`${repoPath(repo)}/hooks/${id}/pings`);
|
|
857
|
+
}
|
|
858
|
+
deliveries(repo, id) {
|
|
859
|
+
return this.c.get(`${repoPath(repo)}/hooks/${id}/deliveries`);
|
|
860
|
+
}
|
|
861
|
+
delivery(repo, id, deliveryId) {
|
|
862
|
+
return this.c.get(`${repoPath(repo)}/hooks/${id}/deliveries/${deliveryId}`);
|
|
863
|
+
}
|
|
864
|
+
redeliver(repo, id, deliveryId) {
|
|
865
|
+
return this.c.post(`${repoPath(repo)}/hooks/${id}/deliveries/${deliveryId}/redeliver`);
|
|
866
|
+
}
|
|
867
|
+
};
|
|
868
|
+
var GitBranchRulesAPI = class {
|
|
869
|
+
constructor(c) {
|
|
870
|
+
this.c = c;
|
|
871
|
+
}
|
|
872
|
+
list(repo) {
|
|
873
|
+
return this.c.get(`${repoPath(repo)}/branch-rules`);
|
|
874
|
+
}
|
|
875
|
+
create(repo, opts) {
|
|
876
|
+
return this.c.post(`${repoPath(repo)}/branch-rules`, opts);
|
|
877
|
+
}
|
|
878
|
+
update(repo, id, opts) {
|
|
879
|
+
return this.c.patch(`${repoPath(repo)}/branch-rules/${id}`, opts);
|
|
880
|
+
}
|
|
881
|
+
delete(repo, id) {
|
|
882
|
+
return this.c.delete(`${repoPath(repo)}/branch-rules/${id}`);
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
var GitLabelsAPI = class {
|
|
886
|
+
constructor(c) {
|
|
887
|
+
this.c = c;
|
|
888
|
+
}
|
|
889
|
+
list(repo) {
|
|
890
|
+
return this.c.get(`${repoPath(repo)}/labels`);
|
|
891
|
+
}
|
|
892
|
+
create(repo, opts) {
|
|
893
|
+
return this.c.post(`${repoPath(repo)}/labels`, opts);
|
|
894
|
+
}
|
|
895
|
+
update(repo, name, opts) {
|
|
896
|
+
return this.c.patch(`${repoPath(repo)}/labels/${seg(name)}`, opts);
|
|
897
|
+
}
|
|
898
|
+
delete(repo, name) {
|
|
899
|
+
return this.c.delete(`${repoPath(repo)}/labels/${seg(name)}`);
|
|
900
|
+
}
|
|
901
|
+
};
|
|
902
|
+
var GitReleasesAPI = class {
|
|
903
|
+
constructor(c) {
|
|
904
|
+
this.c = c;
|
|
905
|
+
}
|
|
906
|
+
list(repo) {
|
|
907
|
+
return this.c.get(`${repoPath(repo)}/releases`);
|
|
908
|
+
}
|
|
909
|
+
/** Creates the tag too when it doesn't exist (at `target`, default branch by default). */
|
|
910
|
+
create(repo, opts) {
|
|
911
|
+
return this.c.post(`${repoPath(repo)}/releases`, opts);
|
|
912
|
+
}
|
|
913
|
+
get(repo, id) {
|
|
914
|
+
return this.c.get(`${repoPath(repo)}/releases/${id}`);
|
|
915
|
+
}
|
|
916
|
+
getByTag(repo, tag) {
|
|
917
|
+
return this.c.get(`${repoPath(repo)}/releases/tags/${seg(tag)}`);
|
|
918
|
+
}
|
|
919
|
+
update(repo, id, opts) {
|
|
920
|
+
return this.c.patch(`${repoPath(repo)}/releases/${id}`, opts);
|
|
921
|
+
}
|
|
922
|
+
delete(repo, id) {
|
|
923
|
+
return this.c.delete(`${repoPath(repo)}/releases/${id}`);
|
|
924
|
+
}
|
|
925
|
+
async uploadAsset(repo, id, name, data, contentType = "application/octet-stream") {
|
|
926
|
+
const body = typeof data === "string" || data instanceof Blob ? data : new Blob([new Uint8Array(data)]);
|
|
927
|
+
const res = await this.c.raw("POST", qs(`${repoPath(repo)}/releases/${id}/assets`, { name }), body, { "Content-Type": contentType });
|
|
928
|
+
return res.json();
|
|
929
|
+
}
|
|
930
|
+
downloadAsset(repo, id, assetId) {
|
|
931
|
+
return this.c.bytes(`${repoPath(repo)}/releases/${id}/assets/${assetId}`);
|
|
932
|
+
}
|
|
933
|
+
deleteAsset(repo, id, assetId) {
|
|
934
|
+
return this.c.delete(`${repoPath(repo)}/releases/${id}/assets/${assetId}`);
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
var GitStatusesAPI = class {
|
|
938
|
+
constructor(c) {
|
|
939
|
+
this.c = c;
|
|
940
|
+
}
|
|
941
|
+
/** Report a check on a commit (what required checks in branch rules wait for). */
|
|
942
|
+
create(repo, sha, status) {
|
|
943
|
+
return this.c.post(`${repoPath(repo)}/statuses/${seg(sha)}`, status);
|
|
944
|
+
}
|
|
945
|
+
list(repo, ref) {
|
|
946
|
+
return this.c.get(`${repoPath(repo)}/commits/${seg(ref)}/statuses`);
|
|
947
|
+
}
|
|
948
|
+
combined(repo, ref) {
|
|
949
|
+
return this.c.get(`${repoPath(repo)}/commits/${seg(ref)}/status`);
|
|
950
|
+
}
|
|
951
|
+
};
|
|
952
|
+
var GitNotificationsAPI = class {
|
|
953
|
+
constructor(c) {
|
|
954
|
+
this.c = c;
|
|
955
|
+
}
|
|
956
|
+
list(opts = {}) {
|
|
957
|
+
return this.c.get(qs("/api/notifications", { all: opts.all ? 1 : void 0 }));
|
|
958
|
+
}
|
|
959
|
+
markRead(ids) {
|
|
960
|
+
return this.c.post("/api/notifications/read", ids?.length ? { ids } : { all: true });
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
var GitTokensAPI = class {
|
|
964
|
+
constructor(c) {
|
|
965
|
+
this.c = c;
|
|
966
|
+
}
|
|
967
|
+
list() {
|
|
968
|
+
return this.c.get("/api/user/tokens");
|
|
969
|
+
}
|
|
970
|
+
/** A Lizard Git token (lzg_...), optionally limited to repos, refs, paths, or read-only. The secret is in `token`, once. */
|
|
971
|
+
create(opts) {
|
|
972
|
+
return this.c.post("/api/user/tokens", opts);
|
|
973
|
+
}
|
|
974
|
+
delete(id) {
|
|
975
|
+
return this.c.delete(`/api/user/tokens/${id}`);
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
var GitAPI = class {
|
|
979
|
+
constructor(config, url) {
|
|
980
|
+
const c = this.client = new GitClient(config, url);
|
|
981
|
+
this.repos = new GitReposAPI(c);
|
|
982
|
+
this.issues = new GitIssuesOnlyAPI(c);
|
|
983
|
+
this.pulls = new GitPullsAPI(c);
|
|
984
|
+
this.actions = new GitActionsAPI(c);
|
|
985
|
+
this.collaborators = new GitCollaboratorsAPI(c);
|
|
986
|
+
this.webhooks = new GitWebhooksAPI(c);
|
|
987
|
+
this.branchRules = new GitBranchRulesAPI(c);
|
|
988
|
+
this.labels = new GitLabelsAPI(c);
|
|
989
|
+
this.releases = new GitReleasesAPI(c);
|
|
990
|
+
this.statuses = new GitStatusesAPI(c);
|
|
991
|
+
this.notifications = new GitNotificationsAPI(c);
|
|
992
|
+
this.tokens = new GitTokensAPI(c);
|
|
993
|
+
}
|
|
994
|
+
/** Who the key signs in as on Lizard Git. */
|
|
995
|
+
me() {
|
|
996
|
+
return this.client.get("/api/session");
|
|
997
|
+
}
|
|
998
|
+
user(login) {
|
|
999
|
+
return this.client.get(`/api/users/${seg(login)}`);
|
|
1000
|
+
}
|
|
1001
|
+
};
|
|
1002
|
+
|
|
484
1003
|
// src/project.ts
|
|
485
1004
|
import { createHash } from "crypto";
|
|
486
1005
|
var projectIdCache = /* @__PURE__ */ new Map();
|
|
@@ -812,7 +1331,7 @@ var Fs = class {
|
|
|
812
1331
|
* }, 1000)
|
|
813
1332
|
* ```
|
|
814
1333
|
*
|
|
815
|
-
* Not available
|
|
1334
|
+
* Not available yet: the call throws `LizardError` (501).
|
|
816
1335
|
*/
|
|
817
1336
|
async watch(path, opts) {
|
|
818
1337
|
const res = await fetch(`${this.config.apiUrl}/api/sandboxes/${this.sandboxId}/files/watch`, {
|
|
@@ -1277,7 +1796,7 @@ var Sandbox = class extends SandboxClient {
|
|
|
1277
1796
|
* snapshot. A Firecracker snapshot is `ready` as soon as this returns: about 2 s, up to
|
|
1278
1797
|
* a few minutes for a sandbox that filled most of its memory (its memory is uploaded
|
|
1279
1798
|
* first), so the call waits up to 11 minutes. Start copies of it with {@link Sandbox.restore}
|
|
1280
|
-
* (about 0.4 s each). The source keeps running.
|
|
1799
|
+
* (about 0.4 s each). The source keeps running. Firecracker snapshots ignore `poolSize`.
|
|
1281
1800
|
*/
|
|
1282
1801
|
snapshot(name = `Snapshot ${this.sandboxId}`, opts = {}) {
|
|
1283
1802
|
return new PlatformClient(this.resolveOpts()).post(`/api/sandboxes/${this.sandboxId}/snapshot`, { name, poolSize: opts.poolSize ?? 5, scope: opts.scope }, SNAPSHOT_TIMEOUT_MS);
|
|
@@ -1285,7 +1804,7 @@ var Sandbox = class extends SandboxClient {
|
|
|
1285
1804
|
unexpose(port) {
|
|
1286
1805
|
return new PlatformClient(this.resolveOpts()).delete(`/api/sandboxes/${this.sandboxId}/expose/${port}`);
|
|
1287
1806
|
}
|
|
1288
|
-
/** Stream the sandbox's logs. Not available
|
|
1807
|
+
/** Stream the sandbox's logs. Not available yet (`LizardError`, 501). */
|
|
1289
1808
|
logs(opts = {}) {
|
|
1290
1809
|
return new PlatformClient(this.resolveOpts()).events(query(`/api/sandboxes/${this.sandboxId}/logs`, { tail: opts.tail }), { signal: opts.signal });
|
|
1291
1810
|
}
|
|
@@ -1324,7 +1843,7 @@ var Sandbox = class extends SandboxClient {
|
|
|
1324
1843
|
static setSnapshotWarmPool(snapshotId, poolSize, opts) {
|
|
1325
1844
|
return new PlatformClient(opts ?? {}).patch(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}`, { poolSize });
|
|
1326
1845
|
}
|
|
1327
|
-
/** Release idle warm copies
|
|
1846
|
+
/** Release idle warm copies of an older snapshot; retain saved state and existing claimed sandboxes. Firecracker snapshots have no warm copies. */
|
|
1328
1847
|
static pauseSnapshot(snapshotId, opts) {
|
|
1329
1848
|
return new PlatformClient(opts ?? {}).post(`/api/sandbox-snapshots/${encodeURIComponent(snapshotId)}/pause`, {});
|
|
1330
1849
|
}
|
|
@@ -1360,8 +1879,8 @@ var ProjectsAPI = class {
|
|
|
1360
1879
|
}
|
|
1361
1880
|
/** List all projects the API key can access. */
|
|
1362
1881
|
list(opts) {
|
|
1363
|
-
const
|
|
1364
|
-
return this.client.get(`/api/projects${
|
|
1882
|
+
const qs2 = opts?.workspaceId ? `?workspaceId=${opts.workspaceId}` : "";
|
|
1883
|
+
return this.client.get(`/api/projects${qs2}`);
|
|
1365
1884
|
}
|
|
1366
1885
|
/** Get a project by ID. */
|
|
1367
1886
|
get(id) {
|
|
@@ -1754,8 +2273,8 @@ var WorkspacesAPI = class {
|
|
|
1754
2273
|
* volumes and snapshots first.
|
|
1755
2274
|
*/
|
|
1756
2275
|
delete(id, opts) {
|
|
1757
|
-
const
|
|
1758
|
-
return this.client.delete(`/api/workspaces/${id}${
|
|
2276
|
+
const qs2 = opts?.force ? "" : "?requireEmpty=true";
|
|
2277
|
+
return this.client.delete(`/api/workspaces/${id}${qs2}`);
|
|
1759
2278
|
}
|
|
1760
2279
|
/**
|
|
1761
2280
|
* Find a workspace by name, slug, or id, or `null` if there is no such workspace.
|
|
@@ -1945,13 +2464,11 @@ var Volume = class _Volume {
|
|
|
1945
2464
|
/**
|
|
1946
2465
|
* Resize a volume, by name or by id, to `sizeGb`.
|
|
1947
2466
|
*
|
|
1948
|
-
* A
|
|
1949
|
-
*
|
|
1950
|
-
*
|
|
2467
|
+
* A volume grows in place and online: a sandbox with the volume attached keeps
|
|
2468
|
+
* running and sees the new size. A smaller size throws `LizardError` (400) with
|
|
2469
|
+
* `code: 'volume_shrink_unsupported'`.
|
|
1951
2470
|
*
|
|
1952
|
-
*
|
|
1953
|
-
* so no data is copied and a mounted sandbox sees the new size immediately. Both
|
|
1954
|
-
* growing and shrinking are allowed, but a shrink must leave at least 10% of the
|
|
2471
|
+
* An older volume can also shrink, but the shrink must leave at least 10% of the
|
|
1955
2472
|
* new size free — otherwise it throws `ConflictError` with
|
|
1956
2473
|
* `code: 'volume_too_full_to_shrink'`.
|
|
1957
2474
|
*
|
|
@@ -1961,7 +2478,7 @@ var Volume = class _Volume {
|
|
|
1961
2478
|
* `volume_capacity_unavailable`, and `volume_resize_timeout` (a `TimeoutError`;
|
|
1962
2479
|
* the size is left unchanged).
|
|
1963
2480
|
*
|
|
1964
|
-
* @returns The volume's updated info, including `sizeEnforced` for
|
|
2481
|
+
* @returns The volume's updated info, including `sizeEnforced` for an older volume.
|
|
1965
2482
|
*/
|
|
1966
2483
|
static async resize(projectId, nameOrId, sizeGb, opts) {
|
|
1967
2484
|
const config = new ConnectionConfig(opts);
|
|
@@ -2039,6 +2556,7 @@ var Lizard = class {
|
|
|
2039
2556
|
this.metrics = new MetricsAPI(platform);
|
|
2040
2557
|
this.storage = new StorageAPI(platform);
|
|
2041
2558
|
this.github = new GitHubAPI(platform);
|
|
2559
|
+
this.git = new GitAPI(this.config, opts.gitUrl);
|
|
2042
2560
|
}
|
|
2043
2561
|
// ── Sandbox convenience methods (backward-compatible) ──────────────────
|
|
2044
2562
|
/** Resolve the client's project reference to a stable project ID (cached). */
|
|
@@ -2650,10 +3168,26 @@ export {
|
|
|
2650
3168
|
CodeSandbox,
|
|
2651
3169
|
ConfigApplyError,
|
|
2652
3170
|
ConflictError,
|
|
3171
|
+
DEFAULT_GIT_URL,
|
|
2653
3172
|
DeployHandle,
|
|
2654
3173
|
Desktop,
|
|
2655
3174
|
DomainsAPI,
|
|
3175
|
+
GitAPI,
|
|
3176
|
+
GitActionsAPI,
|
|
3177
|
+
GitBranchRulesAPI,
|
|
3178
|
+
GitClient,
|
|
3179
|
+
GitCollaboratorsAPI,
|
|
2656
3180
|
GitHubAPI,
|
|
3181
|
+
GitIssuesOnlyAPI,
|
|
3182
|
+
GitLabelsAPI,
|
|
3183
|
+
GitNotificationsAPI,
|
|
3184
|
+
GitPullsAPI,
|
|
3185
|
+
GitReleasesAPI,
|
|
3186
|
+
GitReposAPI,
|
|
3187
|
+
GitSecretsAPI,
|
|
3188
|
+
GitStatusesAPI,
|
|
3189
|
+
GitTokensAPI,
|
|
3190
|
+
GitWebhooksAPI,
|
|
2657
3191
|
LimitExceededError,
|
|
2658
3192
|
Lizard,
|
|
2659
3193
|
LizardCLI,
|
package/package.json
CHANGED