Skip to content
214 linesCodeBlameRaw
1import type { AuditSurface } from "./audit";
2import type { User, Viewer } from "./identity";
3import type { Result } from "./result";
4
5/**
6 * The packages service: the registries a workspace publishes to and
7 * installs from, beside its code (docs.g1t.sh/guides/packages/).
8 * Container images first, on `g1t.sh/v2/`. Mirrors
9 * `crates/contracts/src/packages.rs`.
10 *
11 * A package linked to a repository has its visibility and, unless its
12 * admins turned inheriting off, its roles (Read pulls, Write publishes,
13 * Admin deletes and changes settings); an unlinked one is its workspace's:
14 * members by the base permission, owners administer. Roles given on the
15 * package itself, to people and teams, add to those. A workflow job's
16 * token reaches it from its linked repository, or one listed under Manage
17 * Actions access. Deleted packages and versions can be restored for
18 * `PACKAGE_RESTORE_DAYS`.
19 */
20
21/** How long a deleted package or version can be restored, in days. */
22export const PACKAGE_RESTORE_DAYS = 30;
23
24/** Which registry a package is in. */
25export const ECOSYSTEMS = ["container", "npm", "composer", "cargo", "go", "maven", "nuget", "rubygems"] as const;
26export type Ecosystem = (typeof ECOSYSTEMS)[number];
27
28export type PackageVisibility = "public" | "private";
29
30export type LinkedRepo = { id: string; namespace: string; name: string };
31
32/** A package as listings show it. */
33export type PackageSummary = {
34 id: string;
35 workspace: string;
36 ecosystem: Ecosystem;
37 /** Without the workspace: `web` for `g1t.sh/acme/web`. */
38 name: string;
39 /** What a client is given: `g1t.sh/acme/web` for a container image. */
40 address: string;
41 /** Linked packages follow their repository's visibility. */
42 visibility: PackageVisibility;
43 repo: LinkedRepo | null;
44 description: string | null;
45 versions: number;
46 /** The newest version's tag (`latest` when it has one) or version. */
47 latest: string | null;
48 /** Bytes its versions hold, each file counted once. */
49 size: number;
50 /** Pulls and installs, counted approximately. */
51 downloads: number;
52 created_at: string;
53 updated_at: string;
54 /** For a linked package: whether it takes its repository's roles. */
55 inherit_access?: boolean;
56 /** Set on a deleted package: when, by whom, and when it is purged. */
57 deleted_at?: string | null;
58 deleted_by?: string | null;
59 purge_at?: string | null;
60};
61
62/** One version: for a container image, one manifest, by digest. */
63export type PackageVersion = {
64 id: string;
65 version: string;
66 digest: string;
67 size: number;
68 media_type: string | null;
69 /** For an OCI artifact: what it is, such as a signature or an SBOM. */
70 artifact_type: string | null;
71 /** For an artifact attached to another version: that version's digest. */
72 subject: string | null;
73 /** For an image index: the platforms it holds, such as `linux/amd64`. */
74 platforms: string[];
75 tags: string[];
76 published_by: string | null;
77 published_at: string;
78 /** npm: why the version should no longer be used, when it is deprecated. */
79 deprecated?: string | null;
80 /** NuGet: whether a symbol package (`.snupkg`) was pushed for it. */
81 symbols?: boolean;
82 /** Its own pulls or downloads, counted approximately. */
83 downloads?: number | null;
84 /** Set on a deleted version: when, by whom, and when it is purged. */
85 deleted_at?: string | null;
86 deleted_by?: string | null;
87 purge_at?: string | null;
88};
89
90export type PackageTag = { tag: string; digest: string; updated_at: string };
91
92/**
93 * What the viewer may do with a package. `delete`: delete and restore it
94 * and its versions; `admin`: change its settings (access, Actions access,
95 * visibility, link).
96 */
97export type PackagePermissions = { pull: boolean; push: boolean; delete: boolean; admin: boolean };
98
99/** A role on a package: read pulls, write publishes, admin deletes and changes settings. */
100export const PACKAGE_ROLES = ["read", "write", "admin"] as const;
101export type PackageRole = (typeof PACKAGE_ROLES)[number];
102
103/** A person or a team with a role on a package itself. */
104export type PackageAccess = {
105 kind: "user" | "team";
106 id: string;
107 /** A username, or a team as `workspace/slug`. */
108 name: string;
109 role: PackageRole;
110 created_at: string;
111};
112
113/** A repository whose workflows may use a package; `linked` is its own repository, always write. */
114export type ActionsAccess = {
115 repo_id: string;
116 /** `owner/name`. */
117 repo: string;
118 role: "read" | "write";
119 linked: boolean;
120 created_at: string | null;
121};
122
123/** `package_settings`: what a package's admins see on its Settings tab. */
124export type PackageSettings = {
125 package: PackageSummary;
126 access: PackageAccess[];
127 actions_access: ActionsAccess[];
128 /** Deleted versions that can still be restored, newest first. */
129 deleted_versions: PackageVersion[];
130 permissions: PackagePermissions;
131};
132
133export type PackageDetail = {
134 package: PackageSummary;
135 /** Newest first. */
136 versions: PackageVersion[];
137 tags: PackageTag[];
138 permissions: PackagePermissions;
139 /** The package's README, as markdown: npm's, from its latest version. */
140 readme?: string | null;
141};
142
143/** What a workspace's packages hold, for billing: each file once, public when any public package uses it. */
144export type PackageStorage = { public_bytes: number; private_bytes: number };
145
146/** `storage_all`: every workspace with packages, by workspace, for billing's daily measure. */
147export type WorkspacePackageStorage = { workspace: string; public_bytes: number; private_bytes: number };
148
149export type PackageFilter = { ecosystem?: Ecosystem | null; repoId?: string | null; query?: string | null };
150
151export type PackageChange = {
152 visibility?: PackageVisibility;
153 /** A repository of the package's workspace, by name. */
154 link?: string;
155 /** Take the link away. */
156 unlink?: boolean;
157 /** For a linked package: whether it takes its repository's roles. */
158 inheritAccess?: boolean;
159};
160
161/** Who a change of access is for: a person by username, or a team by slug. */
162export type PackageGrantee = { user: string } | { team: string };
163
164export type PackagesApi = {
165 /** The workspace's packages the viewer may pull, newest first. */
166 list(workspace: string, viewer: Viewer, filter?: PackageFilter): Promise<Result<PackageSummary[]>>;
167 /** Not found when the viewer may not pull it. */
168 get(workspace: string, ecosystem: Ecosystem, name: string, viewer: Viewer): Promise<Result<PackageDetail>>;
169 /** A version by version, digest or tag; its tags go with it. */
170 deleteVersion(actor: User, workspace: string, ecosystem: Ecosystem, name: string, version: string, surface?: AuditSurface): Promise<Result<null>>;
171 deletePackage(actor: User, workspace: string, ecosystem: Ecosystem, name: string, surface?: AuditSurface): Promise<Result<null>>;
172 /** Needs Admin. A linked package's visibility is its repository's. */
173 set(actor: User, workspace: string, ecosystem: Ecosystem, name: string, change: PackageChange, surface?: AuditSurface): Promise<Result<PackageSummary>>;
174 /** Admins only: access, Actions access, deleted versions. Not found for anyone who may not pull it. */
175 settings(workspace: string, ecosystem: Ecosystem, name: string, viewer: Viewer): Promise<Result<PackageSettings>>;
176 /** A workspace's deleted packages the viewer administers that can still be restored. */
177 deleted(workspace: string, viewer: Viewer): Promise<Result<PackageSummary[]>>;
178 restorePackage(actor: User, workspace: string, ecosystem: Ecosystem, name: string, surface?: AuditSurface): Promise<Result<PackageSummary>>;
179 /** A deleted version, by its id or version. */
180 restoreVersion(actor: User, workspace: string, ecosystem: Ecosystem, name: string, version: string, surface?: AuditSurface): Promise<Result<PackageVersion>>;
181 setAccess(actor: User, workspace: string, ecosystem: Ecosystem, name: string, who: PackageGrantee, role: PackageRole, surface?: AuditSurface): Promise<Result<PackageAccess[]>>;
182 removeAccess(actor: User, workspace: string, ecosystem: Ecosystem, name: string, who: PackageGrantee, surface?: AuditSurface): Promise<Result<PackageAccess[]>>;
183 /** A repository of the workspace, by name or `owner/name`. */
184 setActionsAccess(actor: User, workspace: string, ecosystem: Ecosystem, name: string, repo: string, role: "read" | "write", surface?: AuditSurface): Promise<Result<ActionsAccess[]>>;
185 removeActionsAccess(actor: User, workspace: string, ecosystem: Ecosystem, name: string, repo: string, surface?: AuditSurface): Promise<Result<ActionsAccess[]>>;
186 /** For billing. */
187 storage(workspace: string): Promise<PackageStorage>;
188 /** For billing: every workspace with packages, from one query. */
189 storageAll(): Promise<WorkspacePackageStorage[]>;
190 /** Read a repository's Composer package again now, as a push would. Whether it is one. */
191 syncComposer(repoId: string): Promise<boolean>;
192};
193
194/** The RPC method behind each call, as the Rust service names them. */
195export const PACKAGES_METHODS = [
196 "list_packages",
197 "get_package",
198 "list_versions",
199 "get_version",
200 "delete_version",
201 "delete_package",
202 "restore_version",
203 "restore_package",
204 "deleted_packages",
205 "set_package",
206 "package_settings",
207 "set_package_access",
208 "remove_package_access",
209 "set_actions_access",
210 "remove_actions_access",
211 "storage",
212 "storage_all",
213 "sync_composer",
214] as const;