static-anthology 1.0.0

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 ADDED
@@ -0,0 +1,54 @@
1
+ # GitHub Project Web Server
2
+
3
+ This project allows the user to easily host multiple github web projects on a
4
+ single website. After running a single command, all public webapps on a
5
+ github account will be statically rendered and hosted in the static/ directory,
6
+ which then can be hosted on a static web server.
7
+
8
+
9
+ ## Detecting Projects: Static Web App Manifests
10
+
11
+ In order to determine if a project is a static web app, each repository should have
12
+ a file, `swa_manifest.json` in the root directory. This `json` file must contain
13
+ the following fields:
14
+ ```json
15
+ {
16
+ "title":"The title of the web app",
17
+ "root":"The root directory of the repository containing static content",
18
+ "directory": "The output directory of the static subpage"
19
+ }
20
+ ```
21
+
22
+ Additionally, tile images for each site are loaded from `swa_tile.png` if present.
23
+
24
+ ## Static Resources
25
+
26
+ Static resources may be added to `static_src`. These will be copied as-is into
27
+ the root of the output directory. This is a good location for styles, images,
28
+ and any other root-level web assets.
29
+
30
+ ## Templates
31
+
32
+ The rendering process uses three template files:
33
+ - index.njk - determines the base landing page. Contains multiple tiles.
34
+ - folder.njk - folders store multiple tiles.
35
+ - tile.njk - a single tile. One tile is produced per web app.
36
+
37
+ ## Configuration
38
+
39
+ Configuration is best done by adding a `config.json` to the root directory.
40
+ At a minimum, configure a GitHub username and a PAT:
41
+
42
+ ```json
43
+ {
44
+ "username":"github username",
45
+ "github_token": "******" // personal access token with repo access
46
+ }
47
+ ```
48
+
49
+ ## Running the Compiler
50
+
51
+ Once configured, run
52
+ ```
53
+ npm run start
54
+ ```
package/dist/cli.js ADDED
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import yargs from "yargs";
5
+ import { hideBin } from "yargs/helpers";
6
+ import fs3 from "fs-extra";
7
+ import path from "path";
8
+
9
+ // src/repoProcessor.ts
10
+ import fs2 from "fs-extra";
11
+ import nunjucks from "nunjucks";
12
+
13
+ // src/utils.ts
14
+ import fs from "fs-extra";
15
+ async function emptyDirectory(path2) {
16
+ await fs.emptyDir(path2);
17
+ }
18
+ function titleToDirectory(title) {
19
+ return title.split("").filter((l) => /\w/.test(l)).join("");
20
+ }
21
+
22
+ // src/githubApi.ts
23
+ import axios from "axios";
24
+ import simpleGit from "simple-git";
25
+ function sleep(ms) {
26
+ return new Promise((resolve) => {
27
+ setTimeout(resolve, ms);
28
+ });
29
+ }
30
+ function getHeaders(githubToken) {
31
+ const headers = {};
32
+ if (githubToken) {
33
+ headers["Authorization"] = `token ${githubToken}`;
34
+ }
35
+ return headers;
36
+ }
37
+ async function getRepos(username, githubToken) {
38
+ await sleep(1e3);
39
+ const repos_response = await axios.get(
40
+ `https://api.github.com/users/${username}/repos`,
41
+ { headers: getHeaders(githubToken) }
42
+ );
43
+ return repos_response.data;
44
+ }
45
+ async function isStaticWebApp(repo, githubToken) {
46
+ try {
47
+ await sleep(100);
48
+ const manifest = (await axios.get(repo.url + "/contents/swa_manifest.json", {
49
+ headers: getHeaders(githubToken)
50
+ })).data;
51
+ return true;
52
+ } catch (error) {
53
+ if (error.response && error.response.status === 404) {
54
+ return false;
55
+ } else {
56
+ throw error;
57
+ }
58
+ }
59
+ }
60
+ async function clone(clone_url, githubToken) {
61
+ const tmpDir = "./tmp";
62
+ await emptyDirectory(tmpDir);
63
+ const git = simpleGit();
64
+ if (githubToken) {
65
+ const remote = `https://${githubToken}@${clone_url.substring(
66
+ "https://".length
67
+ )}`;
68
+ await git.clone(remote, tmpDir);
69
+ } else {
70
+ await git.clone(clone_url, tmpDir);
71
+ }
72
+ }
73
+
74
+ // src/repoProcessor.ts
75
+ function repoComparator(r1, r2) {
76
+ const r1_time = new Date(r1.updated_at).getTime();
77
+ const r2_time = new Date(r2.updated_at).getTime();
78
+ return r1_time - r2_time;
79
+ }
80
+ var RepoProcessor = class {
81
+ users;
82
+ repos;
83
+ pages;
84
+ outputDir;
85
+ githubToken;
86
+ constructor(views, staticDir, outputDir, githubToken) {
87
+ this.outputDir = outputDir;
88
+ this.githubToken = githubToken;
89
+ nunjucks.configure(views, {
90
+ autoescape: true
91
+ });
92
+ emptyDirectory(this.outputDir);
93
+ fs2.copySync(staticDir, this.outputDir);
94
+ this.users = [];
95
+ this.repos = [];
96
+ this.pages = [];
97
+ }
98
+ async addUsers(...users) {
99
+ this.users.push(...users);
100
+ }
101
+ async processUsers() {
102
+ while (this.users.length) {
103
+ const username = this.users.pop();
104
+ if (!username) continue;
105
+ const repos = await getRepos(username, this.githubToken);
106
+ for (let i = 0; i < repos.length; i++) {
107
+ const repo = repos[i];
108
+ console.log(`Testing repo: ${repo.name}`);
109
+ if (await isStaticWebApp(repo, this.githubToken)) {
110
+ this.repos.push(repo);
111
+ }
112
+ }
113
+ }
114
+ }
115
+ async processRepos() {
116
+ this.repos.sort(repoComparator).reverse();
117
+ for (const repo of this.repos) {
118
+ await this.processRepo(repo);
119
+ }
120
+ this.repos = [];
121
+ }
122
+ async processRepo(repo_info) {
123
+ console.log(`Processing ${repo_info.name}`);
124
+ await clone(repo_info.clone_url, this.githubToken);
125
+ const manifest = JSON.parse(
126
+ fs2.readFileSync("./tmp/swa_manifest.json", "utf8")
127
+ );
128
+ const { title, root } = manifest;
129
+ const directory = manifest.directory ?? titleToDirectory(title);
130
+ fs2.mkdirSync(`${this.outputDir}/${directory}`);
131
+ fs2.copySync(`./tmp/${root}`, `${this.outputDir}/${directory}`);
132
+ let tile;
133
+ if (fs2.existsSync("./tmp/swa_tile.png")) {
134
+ tile = titleToDirectory(title) + ".png";
135
+ fs2.copySync("./tmp/swa_tile.png", `${this.outputDir}/tiles/${tile}`);
136
+ } else {
137
+ tile = "default.png";
138
+ }
139
+ this.pages.push({
140
+ title,
141
+ directory,
142
+ tile
143
+ });
144
+ }
145
+ processPages() {
146
+ const indexHtml = nunjucks.render("index.njk", { tiles: this.pages });
147
+ fs2.writeFileSync(`${this.outputDir}/index.html`, indexHtml, "utf8");
148
+ }
149
+ async process() {
150
+ await this.processUsers();
151
+ await this.processRepos();
152
+ this.processPages();
153
+ }
154
+ };
155
+
156
+ // src/cli.ts
157
+ async function main() {
158
+ try {
159
+ const argv = await yargs(hideBin(process.argv)).scriptName("static-anthology").usage("Usage: $0 [options]").config("config", (configPath) => {
160
+ const resolvedPath = path.resolve(configPath);
161
+ if (!fs3.existsSync(resolvedPath)) {
162
+ throw new Error(`Config file not found: ${resolvedPath}`);
163
+ }
164
+ return fs3.readJsonSync(resolvedPath);
165
+ }).default("config", "config.json").option("username", {
166
+ alias: "u",
167
+ type: "string",
168
+ description: "GitHub username to process (can also be set in config)"
169
+ }).option("views", {
170
+ type: "string",
171
+ default: "./views",
172
+ description: "Directory containing Nunjucks templates/views",
173
+ normalize: true
174
+ }).option("static", {
175
+ type: "string",
176
+ default: "./static_src",
177
+ description: "Directory of static assets to copy",
178
+ normalize: true
179
+ }).option("output", {
180
+ alias: "o",
181
+ type: "string",
182
+ default: "./static",
183
+ description: "Output/build directory",
184
+ normalize: true
185
+ }).option("github_token", {
186
+ type: "string",
187
+ description: "GitHub personal access token (also readable from GITHUB_TOKEN env)",
188
+ implies: "username"
189
+ }).env("GITHUB").demandOption(["username"], "You must provide a GitHub username (or use config)").help().alias("help", "h").version().epilogue("For more info, check the README: https://github.com/yourusername/github-web-server").argv;
190
+ const token = argv.github_token || process.env.GITHUB_TOKEN;
191
+ if (!token && argv.username) {
192
+ console.warn("\u26A0\uFE0F No GitHub token provided \u2014 API rate limit will be very low (60 req/h)");
193
+ }
194
+ const processor = new RepoProcessor(
195
+ path.resolve(argv.views),
196
+ path.resolve(argv.static),
197
+ path.resolve(argv.output),
198
+ token
199
+ );
200
+ if (argv.username) {
201
+ await processor.addUsers(argv.username);
202
+ }
203
+ console.log("Starting processing...");
204
+ await processor.process();
205
+ console.log("Done! Output is in:", argv.output);
206
+ } catch (error) {
207
+ console.error("Error:", error instanceof Error ? error.message : String(error));
208
+ process.exitCode = 1;
209
+ }
210
+ }
211
+ main().catch((err) => {
212
+ console.error("Unexpected error:", err);
213
+ process.exit(1);
214
+ });
215
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts","../src/repoProcessor.ts","../src/utils.ts","../src/githubApi.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport { hideBin } from 'yargs/helpers';\nimport fs from 'fs-extra';\nimport path from 'path';\nimport RepoProcessor from './repoProcessor.js'; // adjust path if needed\n\ninterface CliArgs {\n config?: string;\n username?: string;\n views: string;\n static: string;\n output: string;\n github_token?: string;\n help?: boolean;\n}\n\nasync function main() {\n try {\n const argv = await yargs(hideBin(process.argv))\n .scriptName('static-anthology')\n .usage('Usage: $0 [options]')\n .config('config', (configPath: string) => {\n const resolvedPath = path.resolve(configPath);\n if (!fs.existsSync(resolvedPath)) {\n throw new Error(`Config file not found: ${resolvedPath}`);\n }\n return fs.readJsonSync(resolvedPath);\n })\n .default('config', 'config.json')\n .option('username', {\n alias: 'u',\n type: 'string',\n description: 'GitHub username to process (can also be set in config)',\n })\n .option('views', {\n type: 'string',\n default: './views',\n description: 'Directory containing Nunjucks templates/views',\n normalize: true,\n })\n .option('static', {\n type: 'string',\n default: './static_src',\n description: 'Directory of static assets to copy',\n normalize: true,\n })\n .option('output', {\n alias: 'o',\n type: 'string',\n default: './static',\n description: 'Output/build directory',\n normalize: true,\n })\n .option('github_token', {\n type: 'string',\n description: 'GitHub personal access token (also readable from GITHUB_TOKEN env)',\n implies: 'username',\n })\n .env('GITHUB') // automatically reads GITHUB_TOKEN from environment\n .demandOption(['username'], 'You must provide a GitHub username (or use config)')\n .help()\n .alias('help', 'h')\n .version()\n .epilogue('For more info, check the README: https://github.com/yourusername/github-web-server')\n .argv as unknown as CliArgs;\n\n // Final token resolution: CLI > config > env\n const token = argv.github_token || process.env.GITHUB_TOKEN;\n\n if (!token && argv.username) {\n console.warn('⚠️ No GitHub token provided — API rate limit will be very low (60 req/h)');\n }\n\n const processor = new RepoProcessor(\n path.resolve(argv.views),\n path.resolve(argv.static),\n path.resolve(argv.output),\n token\n );\n\n if (argv.username) {\n await processor.addUsers(argv.username);\n }\n\n console.log('Starting processing...');\n await processor.process();\n console.log('Done! Output is in:', argv.output);\n\n } catch (error) {\n console.error('Error:', error instanceof Error ? error.message : String(error));\n process.exitCode = 1;\n }\n}\n\nmain().catch((err) => {\n console.error('Unexpected error:', err);\n process.exit(1);\n});","import fs from 'fs-extra';\nimport nunjucks from 'nunjucks';\n\nimport { getRepos, isStaticWebApp, clone } from './githubApi.js';\nimport { emptyDirectory, titleToDirectory } from './utils.js';\nimport { Repo } from './types/github.js';\nimport { PageInfo } from './types/page.js';\nimport { Manifest } from './types/manifest.js';\n\nfunction repoComparator(r1: Repo, r2: Repo) {\n const r1_time = new Date(r1.updated_at).getTime();\n const r2_time = new Date(r2.updated_at).getTime();\n return r1_time - r2_time;\n}\n\nexport default class RepoProcessor {\n users: string[];\n repos: Repo[];\n pages: PageInfo[];\n outputDir: string;\n githubToken?: string;\n\n constructor(\n views: string,\n staticDir: string,\n outputDir: string,\n githubToken?: string,\n ) {\n this.outputDir = outputDir;\n this.githubToken = githubToken;\n nunjucks.configure(views, {\n autoescape: true,\n });\n emptyDirectory(this.outputDir);\n fs.copySync(staticDir, this.outputDir);\n this.users = [];\n this.repos = [];\n this.pages = [];\n }\n\n async addUsers(...users: string[]) {\n this.users.push(...users);\n }\n\n async processUsers() {\n while (this.users.length) {\n const username = this.users.pop();\n if (!username) continue;\n const repos = await getRepos(username, this.githubToken);\n for (let i = 0; i < repos.length; i++) {\n const repo = repos[i];\n console.log(`Testing repo: ${repo.name}`);\n if (await isStaticWebApp(repo, this.githubToken)) {\n this.repos.push(repo);\n }\n }\n }\n }\n\n async processRepos() {\n this.repos.sort(repoComparator).reverse(); // Sort from newest to oldest\n for (const repo of this.repos) {\n await this.processRepo(repo);\n }\n this.repos = []; // Prevent repeated processing\n }\n\n async processRepo(repo_info: Repo) {\n console.log(`Processing ${repo_info.name}`);\n\n await clone(repo_info.clone_url, this.githubToken);\n // Now we have a local copy of the repo. Read the manifest.\n const manifest: Manifest = JSON.parse(\n fs.readFileSync('./tmp/swa_manifest.json', 'utf8'),\n );\n const { title, root } = manifest;\n const directory = manifest.directory ?? titleToDirectory(title);\n\n fs.mkdirSync(`${this.outputDir}/${directory}`);\n fs.copySync(`./tmp/${root}`, `${this.outputDir}/${directory}`);\n\n let tile;\n if (fs.existsSync('./tmp/swa_tile.png')) {\n tile = titleToDirectory(title) + '.png';\n fs.copySync('./tmp/swa_tile.png', `${this.outputDir}/tiles/${tile}`);\n } else {\n tile = 'default.png';\n }\n\n this.pages.push({\n title,\n directory,\n tile,\n });\n }\n\n processPages() {\n // We want to render index.html to contain all tiles.\n const indexHtml = nunjucks.render('index.njk', { tiles: this.pages });\n fs.writeFileSync(`${this.outputDir}/index.html`, indexHtml, 'utf8');\n }\n\n async process() {\n await this.processUsers();\n await this.processRepos();\n this.processPages();\n }\n}\n","import fs from 'fs-extra';\n\nexport async function emptyDirectory(path: string) {\n await fs.emptyDir(path);\n}\n\nexport function titleToDirectory(title: string) {\n return title\n .split('')\n .filter((l) => /\\w/.test(l))\n .join('');\n}\n","import { emptyDirectory } from './utils.js';\nimport axios from 'axios';\nimport simpleGit from 'simple-git';\nimport { Repo } from './types/github.js';\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\nfunction getHeaders(githubToken?: string) {\n const headers: any = {};\n if (githubToken) {\n headers['Authorization'] = `token ${githubToken}`;\n }\n return headers;\n}\n\nexport async function getRepos(\n username: string,\n githubToken?: string,\n): Promise<Repo[]> {\n await sleep(1000);\n const repos_response = await axios.get(\n `https://api.github.com/users/${username}/repos`,\n { headers: getHeaders(githubToken) },\n );\n return repos_response.data;\n}\n\nexport async function isStaticWebApp(repo: any, githubToken?: string) {\n try {\n await sleep(100);\n const manifest = (\n await axios.get(repo.url + '/contents/swa_manifest.json', {\n headers: getHeaders(githubToken),\n })\n ).data;\n return true;\n } catch (error: any) {\n if (error.response && error.response.status === 404) {\n return false;\n } else {\n throw error;\n }\n }\n}\n\nexport async function clone(clone_url: string, githubToken?: string) {\n const tmpDir = './tmp';\n await emptyDirectory(tmpDir);\n //@ts-ignore\n const git = simpleGit();\n\n if (githubToken) {\n const remote = `https://${githubToken}@${clone_url.substring(\n 'https://'.length,\n )}`;\n await git.clone(remote, tmpDir);\n } else {\n await git.clone(clone_url, tmpDir);\n }\n}\n"],"mappings":"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","names":["fs","fs","path","fs","fs"]}
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "static-anthology",
3
+ "version": "1.0.0",
4
+ "description": "Static site renderer for project showcases",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "github-web-server": "./dist/cli.js"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ],
15
+ "scripts": {
16
+ "dev": "tsx src/cli.ts",
17
+ "build": "tsup",
18
+ "start": "node dist/cli.js",
19
+ "format": "prettier --write src",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "dependencies": {
23
+ "axios": "^1.13.2",
24
+ "fs-extra": "^11.2.0",
25
+ "nunjucks": "^3.2.4",
26
+ "simple-git": "^3.24.0",
27
+ "yargs": "^18.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/fs-extra": "^11.0.4",
31
+ "@types/nunjucks": "^3.2.6",
32
+ "@types/yargs": "^17.0.35",
33
+ "prettier": "^3.8.0",
34
+ "tsup": "^8.3.5",
35
+ "tsx": "^4.21.0",
36
+ "typescript": "^5.6.3"
37
+ }
38
+ }