@lizard-build/sdk 0.1.72 → 0.1.74

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.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 qs = new URLSearchParams();
129
- for (const [key, value] of Object.entries(values)) if (value !== void 0) qs.set(key, String(value));
130
- return qs.size ? `${path}?${qs}` : path;
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,537 @@ 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 segs(p) {
493
+ const parts = p.split("/");
494
+ if (parts.some((x) => x === "" || x === "." || x === "..")) throw new Error(`bad path: "${p}"`);
495
+ return parts.map(seg).join("/");
496
+ }
497
+ function repoPath(repo) {
498
+ const m = /^([^/\s]+)\/([^/\s]+?)(\.git)?$/.exec(repo);
499
+ if (!m || [m[1], m[2]].some((x) => x === "." || x === "..")) throw new Error(`repository must be "owner/name", got "${repo}"`);
500
+ return `/api/repos/${seg(m[1])}/${seg(m[2])}`;
501
+ }
502
+ var GitClient = class {
503
+ constructor(config, url) {
504
+ this.config = config;
505
+ this.url = (url ?? process.env.LIZARD_GIT_URL ?? DEFAULT_GIT_URL).replace(/\/+$/, "");
506
+ }
507
+ async raw(method, path, body, headers = {}) {
508
+ const res = await fetch(this.url + path, {
509
+ method,
510
+ body,
511
+ headers: { "X-API-Key": this.config.apiKey, ...headers },
512
+ redirect: "error",
513
+ // a redirect would carry the key to wherever it points
514
+ signal: AbortSignal.timeout(this.config.requestTimeoutMs)
515
+ });
516
+ if (!res.ok) await handleApiError(res);
517
+ return res;
518
+ }
519
+ async request(method, path, body, headers = {}) {
520
+ const res = await this.raw(
521
+ method,
522
+ path,
523
+ body === void 0 ? void 0 : JSON.stringify(body),
524
+ body === void 0 ? headers : { "Content-Type": "application/json", ...headers }
525
+ );
526
+ const text = res.status === 204 ? "" : await res.text();
527
+ return text ? JSON.parse(text) : void 0;
528
+ }
529
+ get(path) {
530
+ return this.request("GET", path);
531
+ }
532
+ post(path, body) {
533
+ return this.request("POST", path, body ?? {});
534
+ }
535
+ put(path, body) {
536
+ return this.request("PUT", path, body ?? {});
537
+ }
538
+ patch(path, body) {
539
+ return this.request("PATCH", path, body);
540
+ }
541
+ delete(path) {
542
+ return this.request("DELETE", path);
543
+ }
544
+ async bytes(path) {
545
+ return new Uint8Array(await (await this.raw("GET", path)).arrayBuffer());
546
+ }
547
+ };
548
+ var GitReposAPI = class {
549
+ constructor(c) {
550
+ this.c = c;
551
+ }
552
+ /** Yours and the ones you collaborate on by default; `owner`, `q`, `starred` narrow it. */
553
+ list(opts = {}) {
554
+ return this.c.get(qs("/api/repos", opts));
555
+ }
556
+ /** Answers the new repository's `owner` and `name`. */
557
+ create(opts) {
558
+ return this.c.post("/api/repos", opts);
559
+ }
560
+ get(repo) {
561
+ return this.c.get(repoPath(repo));
562
+ }
563
+ update(repo, opts) {
564
+ return this.c.patch(repoPath(repo), opts);
565
+ }
566
+ delete(repo) {
567
+ return this.c.delete(repoPath(repo));
568
+ }
569
+ star(repo) {
570
+ return this.c.put(`${repoPath(repo)}/star`);
571
+ }
572
+ unstar(repo) {
573
+ return this.c.delete(`${repoPath(repo)}/star`);
574
+ }
575
+ /** Fork into your account (`name` defaults to the same name). */
576
+ fork(repo, opts = {}) {
577
+ return this.c.post(`${repoPath(repo)}/forks`, opts);
578
+ }
579
+ forks(repo) {
580
+ return this.c.get(`${repoPath(repo)}/forks`);
581
+ }
582
+ /** Branches and tags. */
583
+ refs(repo) {
584
+ return this.c.get(`${repoPath(repo)}/refs`);
585
+ }
586
+ createBranch(repo, name, from) {
587
+ return this.c.post(`${repoPath(repo)}/branches`, { name, from });
588
+ }
589
+ deleteBranch(repo, name) {
590
+ return this.c.delete(`${repoPath(repo)}/branches/${segs(name)}`);
591
+ }
592
+ tree(repo, opts = {}) {
593
+ return this.c.get(qs(`${repoPath(repo)}/tree`, opts));
594
+ }
595
+ /** A file as JSON (text in `content`). */
596
+ file(repo, path, ref) {
597
+ return this.c.get(qs(`${repoPath(repo)}/blob`, { path, ref }));
598
+ }
599
+ /** A file's bytes, whatever its size or type. */
600
+ raw(repo, path, ref) {
601
+ repoPath(repo);
602
+ const [owner, name] = repo.split("/");
603
+ return this.c.bytes(`/raw/${seg(owner)}/${seg(name)}/${segs(ref)}/${segs(path)}`);
604
+ }
605
+ /** Every file path at a ref. */
606
+ files(repo, ref) {
607
+ return this.c.get(qs(`${repoPath(repo)}/files`, { ref }));
608
+ }
609
+ search(repo, q, ref) {
610
+ return this.c.get(qs(`${repoPath(repo)}/search`, { q, ref }));
611
+ }
612
+ commits(repo, opts = {}) {
613
+ return this.c.get(qs(`${repoPath(repo)}/commits`, opts));
614
+ }
615
+ commit(repo, sha) {
616
+ return this.c.get(`${repoPath(repo)}/commits/${seg(sha)}`);
617
+ }
618
+ compare(repo, base, head) {
619
+ return this.c.get(qs(`${repoPath(repo)}/compare`, { base, head }));
620
+ }
621
+ /** Commit files on the server: no clone, no push. Answers 409 when `expect` no longer matches. */
622
+ commitFiles(repo, opts) {
623
+ const { idempotencyKey, ...body } = opts;
624
+ return this.c.request("POST", `${repoPath(repo)}/commits`, body, idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {});
625
+ }
626
+ /** Rebase `head` (branch or commit) onto `onto` on the server and move `onto` there; retried on races. */
627
+ land(repo, opts) {
628
+ return this.c.post(`${repoPath(repo)}/land`, opts);
629
+ }
630
+ /** Who moved which branch, when. */
631
+ reflog(repo, ref) {
632
+ return this.c.get(qs(`${repoPath(repo)}/reflog`, { ref }));
633
+ }
634
+ archive(repo, ref, format = "tar.gz") {
635
+ return this.c.bytes(`${repoPath(repo)}/archive/${seg(ref)}.${format}`);
636
+ }
637
+ /**
638
+ * The HTTPS clone URL. With `withKey`, it carries the API key, so plain `git clone` works
639
+ * without a helper; git then keeps it in .git/config. For anything shared or logged, use a
640
+ * limited Lizard Git token (`tokens.create`) as `apiKey` instead of the account's key.
641
+ */
642
+ cloneUrl(repo, opts = {}) {
643
+ repoPath(repo);
644
+ const u = new URL(`${this.c.url}/${repo.replace(/\.git$/, "")}.git`);
645
+ if (opts.withKey) {
646
+ u.username = "lizard";
647
+ u.password = this.c.config.apiKey;
648
+ }
649
+ return u.toString();
650
+ }
651
+ };
652
+ var GitIssuesAPI = class {
653
+ constructor(c, pulls = false) {
654
+ this.c = c;
655
+ this.pulls = pulls;
656
+ }
657
+ base(repo) {
658
+ return `${repoPath(repo)}/issues`;
659
+ }
660
+ list(repo, opts = {}) {
661
+ return this.c.get(qs(this.base(repo), { ...opts, pulls: this.pulls ? 1 : void 0 }));
662
+ }
663
+ get(repo, number) {
664
+ return this.c.get(`${this.base(repo)}/${number}`);
665
+ }
666
+ update(repo, number, opts) {
667
+ return this.c.patch(`${this.base(repo)}/${number}`, opts);
668
+ }
669
+ comment(repo, number, body) {
670
+ return this.c.post(`${this.base(repo)}/${number}/comments`, { body });
671
+ }
672
+ close(repo, number) {
673
+ return this.update(repo, number, { state: "closed" });
674
+ }
675
+ reopen(repo, number) {
676
+ return this.update(repo, number, { state: "open" });
677
+ }
678
+ };
679
+ var GitIssuesOnlyAPI = class extends GitIssuesAPI {
680
+ constructor(c) {
681
+ super(c, false);
682
+ }
683
+ create(repo, opts) {
684
+ return this.c.post(this.base(repo), opts);
685
+ }
686
+ };
687
+ var GitPullsAPI = class extends GitIssuesAPI {
688
+ constructor(c) {
689
+ super(c, true);
690
+ }
691
+ create(repo, opts) {
692
+ return this.c.post(this.base(repo), opts);
693
+ }
694
+ /** Mark a draft ready for review. */
695
+ ready(repo, number) {
696
+ return this.update(repo, number, { draft: false });
697
+ }
698
+ merge(repo, number, opts = {}) {
699
+ return this.c.post(`${repoPath(repo)}/pulls/${number}/merge`, opts);
700
+ }
701
+ diff(repo, number) {
702
+ return this.c.get(`${repoPath(repo)}/pulls/${number}/diff`);
703
+ }
704
+ commits(repo, number) {
705
+ return this.c.get(`${repoPath(repo)}/pulls/${number}/commits`);
706
+ }
707
+ reviews(repo, number) {
708
+ return this.c.get(`${repoPath(repo)}/pulls/${number}/reviews`);
709
+ }
710
+ review(repo, number, opts) {
711
+ return this.c.post(`${repoPath(repo)}/pulls/${number}/reviews`, opts);
712
+ }
713
+ approve(repo, number, body = "") {
714
+ return this.review(repo, number, { event: "APPROVE", body });
715
+ }
716
+ requestChanges(repo, number, body) {
717
+ return this.review(repo, number, { event: "REQUEST_CHANGES", body });
718
+ }
719
+ lineComment(repo, number, c) {
720
+ return this.c.post(`${repoPath(repo)}/pulls/${number}/comments`, c);
721
+ }
722
+ deleteLineComment(repo, number, id) {
723
+ return this.c.delete(`${repoPath(repo)}/pulls/${number}/comments/${id}`);
724
+ }
725
+ /** The combined commit status of the pull request's head (CI and external checks). */
726
+ async checks(repo, number) {
727
+ const { pull } = await this.get(repo, number);
728
+ if (!pull?.headSha) throw new Error(`pull request #${number} has no head commit`);
729
+ return this.c.get(`${repoPath(repo)}/commits/${pull.headSha}/status`);
730
+ }
731
+ };
732
+ var GitSecretsAPI = class {
733
+ constructor(c) {
734
+ this.c = c;
735
+ }
736
+ list(repo) {
737
+ return this.c.get(`${repoPath(repo)}/actions/secrets`);
738
+ }
739
+ set(repo, name, value) {
740
+ return this.c.put(`${repoPath(repo)}/actions/secrets/${seg(name)}`, { value });
741
+ }
742
+ delete(repo, name) {
743
+ return this.c.delete(`${repoPath(repo)}/actions/secrets/${seg(name)}`);
744
+ }
745
+ };
746
+ var GitActionsAPI = class {
747
+ constructor(c) {
748
+ this.c = c;
749
+ this.secrets = new GitSecretsAPI(c);
750
+ }
751
+ runs(repo, opts = {}) {
752
+ return this.c.get(qs(`${repoPath(repo)}/actions/runs`, { ...opts }));
753
+ }
754
+ run(repo, number) {
755
+ return this.c.get(`${repoPath(repo)}/actions/runs/${number}`);
756
+ }
757
+ cancel(repo, number) {
758
+ return this.c.post(`${repoPath(repo)}/actions/runs/${number}/cancel`);
759
+ }
760
+ /** Run the same workflow at the same commit again (a new run). */
761
+ rerun(repo, number) {
762
+ return this.c.post(`${repoPath(repo)}/actions/runs/${number}/rerun`);
763
+ }
764
+ /** Let a run from a fork's pull request start (it waits for someone with write access). */
765
+ approve(repo, number) {
766
+ return this.c.post(`${repoPath(repo)}/actions/runs/${number}/approve`);
767
+ }
768
+ /** Part of a job's log from `offset`; follow `next` until `done`. */
769
+ log(repo, jobId, offset = 0) {
770
+ return this.c.get(qs(`${repoPath(repo)}/actions/jobs/${jobId}/log`, { offset }));
771
+ }
772
+ async fullLog(repo, jobId) {
773
+ return new TextDecoder().decode(await this.c.bytes(`${repoPath(repo)}/actions/jobs/${jobId}/log.txt`));
774
+ }
775
+ /** Each new piece of the log as it's written, until the job ends. */
776
+ async *followLog(repo, jobId, opts = {}) {
777
+ let offset = 0;
778
+ while (!opts.signal?.aborted) {
779
+ const chunk = await this.log(repo, jobId, offset);
780
+ if (chunk.text) yield chunk.text;
781
+ offset = chunk.next;
782
+ if (chunk.done && offset >= chunk.size) return;
783
+ if (!chunk.text) await new Promise((r) => setTimeout(r, opts.intervalMs ?? 1500));
784
+ }
785
+ }
786
+ /** Wait until the run ends (success, failure, cancelled, ...). */
787
+ async wait(repo, number, opts = {}) {
788
+ const until = Date.now() + (opts.timeoutMs ?? 30 * 6e4);
789
+ for (; ; ) {
790
+ const run = await this.run(repo, number);
791
+ if (!["queued", "running", "waiting", "pending"].includes(run.status)) return run;
792
+ if (Date.now() > until) throw new Error(`run ${number} is still ${run.status}`);
793
+ await new Promise((r) => setTimeout(r, opts.intervalMs ?? 3e3));
794
+ }
795
+ }
796
+ artifacts(repo, number) {
797
+ return this.c.get(`${repoPath(repo)}/actions/runs/${number}/artifacts`);
798
+ }
799
+ /** An artifact as a .tar.gz. */
800
+ downloadArtifact(repo, number, name) {
801
+ return this.c.bytes(`${repoPath(repo)}/actions/runs/${number}/artifacts/${seg(name)}`);
802
+ }
803
+ workflows(repo) {
804
+ return this.c.get(`${repoPath(repo)}/actions/workflows`);
805
+ }
806
+ /** Start a workflow that has `on: workflow_dispatch`. */
807
+ dispatch(repo, opts) {
808
+ return this.c.post(`${repoPath(repo)}/actions/workflows/dispatch`, opts);
809
+ }
810
+ /** Latest run status per commit, for the given commits. */
811
+ status(repo, shas) {
812
+ return this.c.get(qs(`${repoPath(repo)}/actions/status`, { shas: shas.join(",") }));
813
+ }
814
+ };
815
+ var GitCollaboratorsAPI = class {
816
+ constructor(c) {
817
+ this.c = c;
818
+ }
819
+ list(repo) {
820
+ return this.c.get(`${repoPath(repo)}/collaborators`);
821
+ }
822
+ /** Invite someone with a Lizard Git account (they sign in once first); they're in once they accept. */
823
+ invite(repo, login, role = "write") {
824
+ return this.c.post(`${repoPath(repo)}/collaborators`, { login, role });
825
+ }
826
+ setRole(repo, login, role) {
827
+ return this.c.patch(`${repoPath(repo)}/collaborators/${seg(login)}`, { role });
828
+ }
829
+ /** Remove someone (or yourself: leave). */
830
+ remove(repo, login) {
831
+ return this.c.delete(`${repoPath(repo)}/collaborators/${seg(login)}`);
832
+ }
833
+ cancelInvitation(repo, id) {
834
+ return this.c.delete(`${repoPath(repo)}/invitations/${id}`);
835
+ }
836
+ /** Invitations waiting for you. */
837
+ invitations() {
838
+ return this.c.get("/api/user/invitations");
839
+ }
840
+ accept(id) {
841
+ return this.c.post(`/api/user/invitations/${id}/accept`);
842
+ }
843
+ decline(id) {
844
+ return this.c.post(`/api/user/invitations/${id}/decline`);
845
+ }
846
+ };
847
+ var GitWebhooksAPI = class {
848
+ constructor(c) {
849
+ this.c = c;
850
+ }
851
+ list(repo) {
852
+ return this.c.get(`${repoPath(repo)}/hooks`);
853
+ }
854
+ /** GitHub-style payloads, signed with `X-Hub-Signature-256` when there's a secret. */
855
+ create(repo, opts) {
856
+ return this.c.post(`${repoPath(repo)}/hooks`, opts);
857
+ }
858
+ get(repo, id) {
859
+ return this.c.get(`${repoPath(repo)}/hooks/${id}`);
860
+ }
861
+ update(repo, id, opts) {
862
+ return this.c.patch(`${repoPath(repo)}/hooks/${id}`, opts);
863
+ }
864
+ delete(repo, id) {
865
+ return this.c.delete(`${repoPath(repo)}/hooks/${id}`);
866
+ }
867
+ ping(repo, id) {
868
+ return this.c.post(`${repoPath(repo)}/hooks/${id}/pings`);
869
+ }
870
+ deliveries(repo, id) {
871
+ return this.c.get(`${repoPath(repo)}/hooks/${id}/deliveries`);
872
+ }
873
+ delivery(repo, id, deliveryId) {
874
+ return this.c.get(`${repoPath(repo)}/hooks/${id}/deliveries/${deliveryId}`);
875
+ }
876
+ redeliver(repo, id, deliveryId) {
877
+ return this.c.post(`${repoPath(repo)}/hooks/${id}/deliveries/${deliveryId}/redeliver`);
878
+ }
879
+ };
880
+ var GitBranchRulesAPI = class {
881
+ constructor(c) {
882
+ this.c = c;
883
+ }
884
+ list(repo) {
885
+ return this.c.get(`${repoPath(repo)}/branch-rules`);
886
+ }
887
+ create(repo, opts) {
888
+ return this.c.post(`${repoPath(repo)}/branch-rules`, opts);
889
+ }
890
+ update(repo, id, opts) {
891
+ return this.c.patch(`${repoPath(repo)}/branch-rules/${id}`, opts);
892
+ }
893
+ delete(repo, id) {
894
+ return this.c.delete(`${repoPath(repo)}/branch-rules/${id}`);
895
+ }
896
+ };
897
+ var GitLabelsAPI = class {
898
+ constructor(c) {
899
+ this.c = c;
900
+ }
901
+ list(repo) {
902
+ return this.c.get(`${repoPath(repo)}/labels`);
903
+ }
904
+ create(repo, opts) {
905
+ return this.c.post(`${repoPath(repo)}/labels`, opts);
906
+ }
907
+ update(repo, name, opts) {
908
+ return this.c.patch(`${repoPath(repo)}/labels/${seg(name)}`, opts);
909
+ }
910
+ delete(repo, name) {
911
+ return this.c.delete(`${repoPath(repo)}/labels/${seg(name)}`);
912
+ }
913
+ };
914
+ var GitReleasesAPI = class {
915
+ constructor(c) {
916
+ this.c = c;
917
+ }
918
+ list(repo) {
919
+ return this.c.get(`${repoPath(repo)}/releases`);
920
+ }
921
+ /** Creates the tag too when it doesn't exist (at `target`, default branch by default). */
922
+ create(repo, opts) {
923
+ return this.c.post(`${repoPath(repo)}/releases`, opts);
924
+ }
925
+ get(repo, id) {
926
+ return this.c.get(`${repoPath(repo)}/releases/${id}`);
927
+ }
928
+ getByTag(repo, tag) {
929
+ return this.c.get(`${repoPath(repo)}/releases/tags/${seg(tag)}`);
930
+ }
931
+ update(repo, id, opts) {
932
+ return this.c.patch(`${repoPath(repo)}/releases/${id}`, opts);
933
+ }
934
+ delete(repo, id) {
935
+ return this.c.delete(`${repoPath(repo)}/releases/${id}`);
936
+ }
937
+ async uploadAsset(repo, id, name, data, contentType = "application/octet-stream") {
938
+ const body = typeof data === "string" || data instanceof Blob ? data : new Blob([new Uint8Array(data)]);
939
+ const res = await this.c.raw("POST", qs(`${repoPath(repo)}/releases/${id}/assets`, { name }), body, { "Content-Type": contentType });
940
+ return res.json();
941
+ }
942
+ downloadAsset(repo, id, assetId) {
943
+ return this.c.bytes(`${repoPath(repo)}/releases/${id}/assets/${assetId}`);
944
+ }
945
+ deleteAsset(repo, id, assetId) {
946
+ return this.c.delete(`${repoPath(repo)}/releases/${id}/assets/${assetId}`);
947
+ }
948
+ };
949
+ var GitStatusesAPI = class {
950
+ constructor(c) {
951
+ this.c = c;
952
+ }
953
+ /** Report a check on a commit (what required checks in branch rules wait for). */
954
+ create(repo, sha, status) {
955
+ return this.c.post(`${repoPath(repo)}/statuses/${seg(sha)}`, status);
956
+ }
957
+ list(repo, ref) {
958
+ return this.c.get(`${repoPath(repo)}/commits/${seg(ref)}/statuses`);
959
+ }
960
+ combined(repo, ref) {
961
+ return this.c.get(`${repoPath(repo)}/commits/${seg(ref)}/status`);
962
+ }
963
+ };
964
+ var GitNotificationsAPI = class {
965
+ constructor(c) {
966
+ this.c = c;
967
+ }
968
+ list(opts = {}) {
969
+ return this.c.get(qs("/api/notifications", { all: opts.all ? 1 : void 0 }));
970
+ }
971
+ markRead(ids) {
972
+ return this.c.post("/api/notifications/read", ids?.length ? { ids } : { all: true });
973
+ }
974
+ };
975
+ var GitTokensAPI = class {
976
+ constructor(c) {
977
+ this.c = c;
978
+ }
979
+ list() {
980
+ return this.c.get("/api/user/tokens");
981
+ }
982
+ /** A Lizard Git token (lzg_...), optionally limited to repos, refs, paths, or read-only. The secret is in `token`, once. */
983
+ create(opts) {
984
+ return this.c.post("/api/user/tokens", opts);
985
+ }
986
+ delete(id) {
987
+ return this.c.delete(`/api/user/tokens/${id}`);
988
+ }
989
+ };
990
+ var GitAPI = class {
991
+ constructor(config, url) {
992
+ const c = this.client = new GitClient(config, url);
993
+ this.repos = new GitReposAPI(c);
994
+ this.issues = new GitIssuesOnlyAPI(c);
995
+ this.pulls = new GitPullsAPI(c);
996
+ this.actions = new GitActionsAPI(c);
997
+ this.collaborators = new GitCollaboratorsAPI(c);
998
+ this.webhooks = new GitWebhooksAPI(c);
999
+ this.branchRules = new GitBranchRulesAPI(c);
1000
+ this.labels = new GitLabelsAPI(c);
1001
+ this.releases = new GitReleasesAPI(c);
1002
+ this.statuses = new GitStatusesAPI(c);
1003
+ this.notifications = new GitNotificationsAPI(c);
1004
+ this.tokens = new GitTokensAPI(c);
1005
+ }
1006
+ /** Who the key signs in as on Lizard Git. */
1007
+ me() {
1008
+ return this.client.get("/api/session");
1009
+ }
1010
+ user(login) {
1011
+ return this.client.get(`/api/users/${seg(login)}`);
1012
+ }
1013
+ };
1014
+
484
1015
  // src/project.ts
485
1016
  import { createHash } from "crypto";
486
1017
  var projectIdCache = /* @__PURE__ */ new Map();
@@ -1360,8 +1891,8 @@ var ProjectsAPI = class {
1360
1891
  }
1361
1892
  /** List all projects the API key can access. */
1362
1893
  list(opts) {
1363
- const qs = opts?.workspaceId ? `?workspaceId=${opts.workspaceId}` : "";
1364
- return this.client.get(`/api/projects${qs}`);
1894
+ const qs2 = opts?.workspaceId ? `?workspaceId=${opts.workspaceId}` : "";
1895
+ return this.client.get(`/api/projects${qs2}`);
1365
1896
  }
1366
1897
  /** Get a project by ID. */
1367
1898
  get(id) {
@@ -1754,8 +2285,8 @@ var WorkspacesAPI = class {
1754
2285
  * volumes and snapshots first.
1755
2286
  */
1756
2287
  delete(id, opts) {
1757
- const qs = opts?.force ? "" : "?requireEmpty=true";
1758
- return this.client.delete(`/api/workspaces/${id}${qs}`);
2288
+ const qs2 = opts?.force ? "" : "?requireEmpty=true";
2289
+ return this.client.delete(`/api/workspaces/${id}${qs2}`);
1759
2290
  }
1760
2291
  /**
1761
2292
  * Find a workspace by name, slug, or id, or `null` if there is no such workspace.
@@ -2037,6 +2568,7 @@ var Lizard = class {
2037
2568
  this.metrics = new MetricsAPI(platform);
2038
2569
  this.storage = new StorageAPI(platform);
2039
2570
  this.github = new GitHubAPI(platform);
2571
+ this.git = new GitAPI(this.config, opts.gitUrl);
2040
2572
  }
2041
2573
  // ── Sandbox convenience methods (backward-compatible) ──────────────────
2042
2574
  /** Resolve the client's project reference to a stable project ID (cached). */
@@ -2648,10 +3180,26 @@ export {
2648
3180
  CodeSandbox,
2649
3181
  ConfigApplyError,
2650
3182
  ConflictError,
3183
+ DEFAULT_GIT_URL,
2651
3184
  DeployHandle,
2652
3185
  Desktop,
2653
3186
  DomainsAPI,
3187
+ GitAPI,
3188
+ GitActionsAPI,
3189
+ GitBranchRulesAPI,
3190
+ GitClient,
3191
+ GitCollaboratorsAPI,
2654
3192
  GitHubAPI,
3193
+ GitIssuesOnlyAPI,
3194
+ GitLabelsAPI,
3195
+ GitNotificationsAPI,
3196
+ GitPullsAPI,
3197
+ GitReleasesAPI,
3198
+ GitReposAPI,
3199
+ GitSecretsAPI,
3200
+ GitStatusesAPI,
3201
+ GitTokensAPI,
3202
+ GitWebhooksAPI,
2655
3203
  LimitExceededError,
2656
3204
  Lizard,
2657
3205
  LizardCLI,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lizard-build/sdk",
3
- "version": "0.1.72",
3
+ "version": "0.1.74",
4
4
  "description": "TypeScript SDK for Lizard: Firecracker microVM sandboxes, code execution and cloud apps.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",