g1t/apps/web/app/lib/packages.ts

160 lines6,305 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member1/**
2 * Words and commands for the Packages pages: sizes, digests, and how each
3 * registry's own tool logs in and installs.
4 */
5import type { Ecosystem, PackageSummary } from "@g1t/contracts";
6
7/** What each registry is called on the pages. */
8export const ECOSYSTEM_LABEL: Record<Ecosystem, string> = {
9 container: "Container",
10 npm: "npm",
11 composer: "Composer",
12 cargo: "Cargo",
13 go: "Go",
14};
15
Packages lists like a registry: Type, search, Visibility and Sort in one bar, richer rows, and a registry to choose from to start16/**
17 * Each registry as the Packages page introduces it: what it is for, the
18 * command that starts one, its guide, and whether it is open yet.
19 */
20export const REGISTRIES: { ecosystem: Ecosystem; blurb: string; start: string; guide: string; ready: boolean }[] = [
21 {
22 ecosystem: "container",
23 blurb: "Docker and OCI images, signatures and attestations, pulled by anyone the image's repository lets read it.",
24 start: "docker push g1t.sh/<workspace>/<name>:<tag>",
25 guide: "/guides/containers/",
26 ready: true,
27 },
28 {
29 ecosystem: "npm",
30 blurb: "JavaScript and TypeScript packages under the workspace's scope, installed with npm, pnpm or yarn.",
31 start: "npm publish",
32 guide: "/guides/npm/",
33 ready: true,
34 },
35 {
36 ecosystem: "composer",
37 blurb: "PHP packages straight from the workspace's repositories: each tag is a version, nothing to upload.",
38 start: "git tag v1.0.0 && git push --tags",
39 guide: "/guides/composer/",
40 ready: true,
41 },
42 {
Cargo on g1t.sh: a sparse registry per workspace, cargo publish/add/yank/search with a g1t token; npm rows show their version43 ecosystem: "cargo",
44 blurb: "Rust crates in a sparse registry of the workspace's own, published with cargo publish and added with cargo add.",
45 start: "cargo publish --registry <workspace>",
46 guide: "/guides/cargo/",
47 ready: true,
48 },
49 {
Packages lists like a registry: Type, search, Visibility and Sort in one bar, richer rows, and a registry to choose from to start50 ecosystem: "go",
51 blurb: "Go modules fetched from the repositories themselves with go get, private ones with a token.",
52 start: "go get g1t.sh/<workspace>/<repo>",
53 guide: "/guides/go/",
54 ready: true,
55 },
56];
57
58export type PackageSort = "updated" | "downloads" | "name";
59export type VisibilityFilter = "all" | "public" | "private";
60
61export const SORT_LABEL: Record<PackageSort, string> = {
62 updated: "Recently updated",
63 downloads: "Most downloads",
64 name: "Name",
65};
66
67export const VISIBILITY_LABEL: Record<VisibilityFilter, string> = { all: "All", public: "Public", private: "Private" };
68
69/** The packages to list: those of the visibility asked for, in the order asked for. */
70export function arrange<T extends Pick<PackageSummary, "visibility" | "updated_at" | "downloads" | "name">>(
71 list: T[],
72 visibility: VisibilityFilter,
73 sort: PackageSort,
74): T[] {
75 const shown = visibility === "all" ? [...list] : list.filter((pkg) => pkg.visibility === visibility);
76 const byName = (a: T, b: T) => a.name.localeCompare(b.name);
77 if (sort === "name") return shown.sort(byName);
78 if (sort === "downloads") return shown.sort((a, b) => b.downloads - a.downloads || byName(a, b));
79 return shown.sort((a, b) => b.updated_at.localeCompare(a.updated_at) || byName(a, b));
80}
81
82/** "940", "16.1k", "2.3M": download counts, short. */
83export function shortCount(n: number): string {
84 if (n >= 1_000_000) return `${Number((n / 1_000_000).toFixed(1))}M`;
85 if (n >= 1_000) return `${Number((n / 1_000).toFixed(1))}k`;
86 return String(Math.max(0, Math.round(n)));
87}
88
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member89/** "0 B", "812 KB", "12.3 MB", "1.4 GB", in powers of 1,000 as registries show them. */
90export function formatBytes(bytes: number): string {
91 if (!Number.isFinite(bytes) || bytes <= 0) return "0 B";
92 const units = ["B", "KB", "MB", "GB", "TB"];
93 let value = bytes;
94 let unit = 0;
95 while (value >= 1000 && unit < units.length - 1) {
96 value /= 1000;
97 unit++;
98 }
99 const shown = unit === 0 || value >= 100 ? Math.round(value) : Number(value.toFixed(1));
100 return `${shown} ${units[unit]}`;
101}
102
103/** `sha256:3f2a…` shortened to `3f2a9c1b7d0e` for lists. */
104export function shortDigest(digest: string): string {
105 return digest.replace(/^sha256:/, "").slice(0, 12);
106}
107
108/** The host packages are published to and installed from. */
109export function registryHost(address: string): string {
110 return address.split("/")[0] || "g1t.sh";
111}
112
113/**
114 * How to log in and install `pkg` at `version` (a tag or version) with its
115 * tool. `you` stands in the username a login takes.
116 */
npm on g1t.sh: publish and install @<workspace>/<name> with the npm CLI and a g1t token117export function installCommands(
118 pkg: Pick<PackageSummary, "ecosystem" | "address" | "name" | "workspace">,
119 version: string | null,
120 you: string,
121): { login: string; install: string; registry?: string } {
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member122 const host = registryHost(pkg.address);
123 switch (pkg.ecosystem) {
124 case "container":
125 return {
126 login: `docker login ${host} -u ${you}`,
127 install: `docker pull ${pkg.address}${version ? `:${version}` : ""}`,
128 };
129 case "npm":
npm on g1t.sh: publish and install @<workspace>/<name> with the npm CLI and a g1t token130 // The scope's registry (in .npmrc, needed for any install), then the
131 // token a private package also needs.
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member132 return {
npm on g1t.sh: publish and install @<workspace>/<name> with the npm CLI and a g1t token133 registry: `npm config set @${pkg.workspace}:registry=https://${host}/-/npm/`,
134 login: `npm config set //${host}/-/npm/:_authToken=YOUR_TOKEN`,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member135 install: `npm install @${pkg.workspace}/${pkg.name}${version ? `@${version}` : ""}`,
136 };
137 case "composer":
Composer from the workspace's own repositories, and go get from g1t.sh138 // The workspace's repository (in composer.json, needed for any
139 // install), then the credentials a private package also needs.
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member140 return {
Composer from the workspace's own repositories, and go get from g1t.sh141 registry: `composer config repositories.${pkg.workspace} composer https://${host}/-/composer/${pkg.workspace}/`,
142 login: `composer config --global --auth http-basic.${host} ${you} YOUR_TOKEN`,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member143 install: `composer require ${pkg.name}${version ? `:${version}` : ""}`,
144 };
145 case "cargo":
Cargo on g1t.sh: a sparse registry per workspace, cargo publish/add/yank/search with a g1t token; npm rows show their version146 // The workspace's registry (in .cargo/config.toml, needed for any
147 // install), then the token a private crate also needs, which cargo
148 // login asks for.
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member149 return {
Cargo on g1t.sh: a sparse registry per workspace, cargo publish/add/yank/search with a g1t token; npm rows show their version150 registry: `mkdir -p .cargo && printf '[registries.${pkg.workspace}]\\nindex = "sparse+https://${host}/-/cargo/${pkg.workspace}/index/"\\ncredential-provider = "cargo:token"\\n' >> .cargo/config.toml`,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member151 login: `cargo login --registry ${pkg.workspace}`,
Cargo on g1t.sh: a sparse registry per workspace, cargo publish/add/yank/search with a g1t token; npm rows show their version152 install: `cargo add ${pkg.name}${version ? `@${version}` : ""} --registry ${pkg.workspace}`,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member153 };
154 case "go":
155 return {
156 login: `go env -w GOPRIVATE=${host}/${pkg.workspace}`,
157 install: `go get ${pkg.address}${version ? `@${version}` : ""}`,
158 };
159 }
160}