website

#astro#js#html#css

git clone https://git.pyrossh.dev/website

木 Personal website of pyrossh. Built with astrojs, shiki, vite.


f1725a0pyrossh 2026-07-07T12:08:37+05:30
feat: add repo files workers
packages/workers/repos/files/blame/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "@pyrossh/repos-files-blame",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "src/index.tsx",
7
+ "types": "src/index.tsx",
8
+ "dependencies": {
9
+ "@pyrossh/config": "workspace:*",
10
+ "@pyrossh/core": "workspace:*",
11
+ "@pyrossh/types": "workspace:*",
12
+ "@pyrossh/ui": "workspace:*"
13
+ }
14
+ }
packages/workers/repos/files/blame/src/index.tsx ADDED
@@ -0,0 +1,31 @@
1
+ import { FileLayout } from "@pyrossh/ui";
2
+ import { getRepo, getFiles } from "@pyrossh/core";
3
+ import type { Env } from "@pyrossh/types";
4
+
5
+ export default {
6
+ async fetch(request: Request, env: Env): Promise<Response> {
7
+ const url = new URL(request.url);
8
+ const parts = url.pathname.split("/").filter(Boolean);
9
+ const repoId = parts[1];
10
+ const filePath = parts.slice(3, -1).join("/");
11
+
12
+ const repo = getRepo(repoId);
13
+ if (!repo) return Response.redirect(`${url.origin}/404`, 302);
14
+
15
+ const files = await getFiles(env.REPOS, repo.id);
16
+ const file = files.find((f) => f.absolutePath === filePath);
17
+ if (!file) return Response.redirect(`${url.origin}/repos/${repo.id}/files`, 302);
18
+
19
+ return new Response(
20
+ <FileLayout repo={repo} file={file} request={request}>
21
+ <p>WIP: Work in Progress...</p>
22
+ </FileLayout>,
23
+ {
24
+ headers: {
25
+ "Content-Type": "text/html",
26
+ "Cache-Control": "public, max-age=300, s-maxage=3600",
27
+ },
28
+ },
29
+ );
30
+ },
31
+ };
packages/workers/repos/files/blame/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json",
3
+ "include": ["src"]
4
+ }
packages/workers/repos/files/blame/wrangler.jsonc ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema.json",
3
+ "name": "pyrossh-repos-files-blame",
4
+ "main": "src/index.tsx",
5
+ "compatibility_date": "2026-07-07",
6
+ "compatibility_flags": ["nodejs_compat"],
7
+ "workers_dev": false,
8
+ "routes": [{ "pattern": "pyrossh.dev/repos/*/files/*/blame", "custom_domain": true }],
9
+ "r2_buckets": [{ "binding": "REPOS", "bucket_name": "pyrossh-repos-prd" }],
10
+ }
packages/workers/repos/files/detail/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "@pyrossh/repos-files-detail",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "src/index.tsx",
7
+ "types": "src/index.tsx",
8
+ "dependencies": {
9
+ "@pyrossh/config": "workspace:*",
10
+ "@pyrossh/core": "workspace:*",
11
+ "@pyrossh/types": "workspace:*",
12
+ "@pyrossh/ui": "workspace:*"
13
+ }
14
+ }
packages/workers/repos/files/detail/src/index.tsx ADDED
@@ -0,0 +1,63 @@
1
+ import { FileLayout } from "@pyrossh/ui";
2
+ import { getRepo, getFiles, getFileContentData } from "@pyrossh/core";
3
+ import type { Env } from "@pyrossh/types";
4
+
5
+ const BINARY_EXTS = ["apk", "dex", "ap_", "jar", "fnt"];
6
+ const IMAGE_EXTS = ["png", "jpg", "jpeg", "gif", "svg", "webp", "ico", "icns", "curve", "atlas"];
7
+ const LARGE_SIZE = 1024 * 512;
8
+
9
+ const toBase64 = (data: Uint8Array) => {
10
+ let binary = "";
11
+ for (let i = 0; i < data.length; i++) {
12
+ binary += String.fromCharCode(data[i]);
13
+ }
14
+ return btoa(binary);
15
+ };
16
+
17
+ export default {
18
+ async fetch(request: Request, env: Env): Promise<Response> {
19
+ const url = new URL(request.url);
20
+ const parts = url.pathname.split("/").filter(Boolean);
21
+ const repoId = parts[1];
22
+ const filePath = parts.slice(3).join("/");
23
+
24
+ const repo = getRepo(repoId);
25
+ if (!repo) return Response.redirect(`${url.origin}/404`, 302);
26
+
27
+ const files = await getFiles(env.REPOS, repo.id);
28
+ const file = files.find((f) => f.absolutePath === filePath);
29
+ if (!file) return Response.redirect(`${url.origin}/repos/${repo.id}/files`, 302);
30
+
31
+ const contentBuffer = await getFileContentData(env.REPOS, repo.id, file.absolutePath);
32
+ const isBinary = BINARY_EXTS.includes(file.ext);
33
+ const isLarge = file.size > LARGE_SIZE;
34
+ const isImage = IMAGE_EXTS.includes(file.ext);
35
+
36
+ let content: any;
37
+ if (isBinary || isLarge) {
38
+ content = <p>The file is too large to be displayed ({file.size} bytes).</p>;
39
+ } else if (isImage && contentBuffer) {
40
+ content = (
41
+ <img src={`data:image/${file.ext};base64,${toBase64(contentBuffer)}`} alt={file.path} />
42
+ );
43
+ } else if (contentBuffer) {
44
+ const text =
45
+ new TextDecoder("utf-8").decode(contentBuffer).trim() || "No content to display.";
46
+ content = <pre>{text}</pre>;
47
+ } else {
48
+ content = <p>Unable to load file content.</p>;
49
+ }
50
+
51
+ return new Response(
52
+ <FileLayout repo={repo} file={file} request={request}>
53
+ {content}
54
+ </FileLayout>,
55
+ {
56
+ headers: {
57
+ "Content-Type": "text/html",
58
+ "Cache-Control": "public, max-age=300, s-maxage=3600",
59
+ },
60
+ },
61
+ );
62
+ },
63
+ };
packages/workers/repos/files/detail/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json",
3
+ "include": ["src"]
4
+ }
packages/workers/repos/files/detail/wrangler.jsonc ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema.json",
3
+ "name": "pyrossh-repos-files-detail",
4
+ "main": "src/index.tsx",
5
+ "compatibility_date": "2026-07-07",
6
+ "compatibility_flags": ["nodejs_compat"],
7
+ "workers_dev": false,
8
+ "routes": [{ "pattern": "pyrossh.dev/repos/*/files/*", "custom_domain": true }],
9
+ "r2_buckets": [{ "binding": "REPOS", "bucket_name": "pyrossh-repos-prd" }],
10
+ }
packages/workers/repos/files/history/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "@pyrossh/repos-files-history",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "src/index.tsx",
7
+ "types": "src/index.tsx",
8
+ "dependencies": {
9
+ "@pyrossh/config": "workspace:*",
10
+ "@pyrossh/core": "workspace:*",
11
+ "@pyrossh/types": "workspace:*",
12
+ "@pyrossh/ui": "workspace:*"
13
+ }
14
+ }
packages/workers/repos/files/history/src/index.tsx ADDED
@@ -0,0 +1,35 @@
1
+ import { FileLayout, CommitEntry } from "@pyrossh/ui";
2
+ import { getRepo, getFiles, getFileHistory } from "@pyrossh/core";
3
+ import type { Env } from "@pyrossh/types";
4
+
5
+ export default {
6
+ async fetch(request: Request, env: Env): Promise<Response> {
7
+ const url = new URL(request.url);
8
+ const parts = url.pathname.split("/").filter(Boolean);
9
+ const repoId = parts[1];
10
+ const filePath = parts.slice(3, -1).join("/");
11
+
12
+ const repo = getRepo(repoId);
13
+ if (!repo) return Response.redirect(`${url.origin}/404`, 302);
14
+
15
+ const files = await getFiles(env.REPOS, repo.id);
16
+ const file = files.find((f) => f.absolutePath === filePath);
17
+ if (!file) return Response.redirect(`${url.origin}/repos/${repo.id}/files`, 302);
18
+
19
+ const history = await getFileHistory(env.REPOS, repo.id, file.absolutePath);
20
+
21
+ return new Response(
22
+ <FileLayout repo={repo} file={file} request={request}>
23
+ {history.map((commit) => (
24
+ <CommitEntry repoId={repo.id} commit={commit} />
25
+ ))}
26
+ </FileLayout>,
27
+ {
28
+ headers: {
29
+ "Content-Type": "text/html",
30
+ "Cache-Control": "public, max-age=300, s-maxage=3600",
31
+ },
32
+ },
33
+ );
34
+ },
35
+ };
packages/workers/repos/files/history/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json",
3
+ "include": ["src"]
4
+ }
packages/workers/repos/files/history/wrangler.jsonc ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema.json",
3
+ "name": "pyrossh-repos-files-history",
4
+ "main": "src/index.tsx",
5
+ "compatibility_date": "2026-07-07",
6
+ "compatibility_flags": ["nodejs_compat"],
7
+ "workers_dev": false,
8
+ "routes": [{ "pattern": "pyrossh.dev/repos/*/files/*/history", "custom_domain": true }],
9
+ "r2_buckets": [{ "binding": "REPOS", "bucket_name": "pyrossh-repos-prd" }],
10
+ }
packages/workers/repos/files/index/package.json ADDED
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "@pyrossh/repos-files-index",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "main": "src/index.tsx",
7
+ "types": "src/index.tsx",
8
+ "dependencies": {
9
+ "@pyrossh/config": "workspace:*",
10
+ "@pyrossh/core": "workspace:*",
11
+ "@pyrossh/types": "workspace:*",
12
+ "@pyrossh/ui": "workspace:*"
13
+ }
14
+ }
packages/workers/repos/files/index/src/index.tsx ADDED
@@ -0,0 +1,28 @@
1
+ import { RepoLayout, FileTree } from "@pyrossh/ui";
2
+ import { getRepo, getFiles, buildFileTree, sortChildren } from "@pyrossh/core";
3
+ import type { Env } from "@pyrossh/types";
4
+
5
+ export default {
6
+ async fetch(request: Request, env: Env): Promise<Response> {
7
+ const url = new URL(request.url);
8
+ const parts = url.pathname.split("/").filter(Boolean);
9
+ const repoId = parts[1];
10
+ const repo = getRepo(repoId);
11
+ if (!repo) return Response.redirect(`${url.origin}/404`, 302);
12
+
13
+ const files = await getFiles(env.REPOS, repo.id);
14
+ const sortedFiles = sortChildren(buildFileTree(files));
15
+
16
+ return new Response(
17
+ <RepoLayout repo={repo} request={request} currentTab="Files">
18
+ <FileTree nodes={sortedFiles} repoId={repo.id} />
19
+ </RepoLayout>,
20
+ {
21
+ headers: {
22
+ "Content-Type": "text/html",
23
+ "Cache-Control": "public, max-age=300, s-maxage=3600",
24
+ },
25
+ },
26
+ );
27
+ },
28
+ };
packages/workers/repos/files/index/tsconfig.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json",
3
+ "include": ["src"]
4
+ }
packages/workers/repos/files/index/wrangler.jsonc ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema.json",
3
+ "name": "pyrossh-repos-files-index",
4
+ "main": "src/index.tsx",
5
+ "compatibility_date": "2026-07-07",
6
+ "compatibility_flags": ["nodejs_compat"],
7
+ "workers_dev": false,
8
+ "routes": [{ "pattern": "pyrossh.dev/repos/*/files", "custom_domain": true }],
9
+ "r2_buckets": [{ "binding": "REPOS", "bucket_name": "pyrossh-repos-prd" }],
10
+ }