diff --git a/README.md b/README.md index 6e8dc81..65ce0b1 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,9 @@ npm run deploy - [ ] use nested renderer to render multiple components - [ ] use `useRequestContext` to have conditional render - [ ] implement Swagger with API - - [ ] add "Browse API" in addition to "Browse GitHub repositories" + - [x] add "Browse API" in addition to "Browse GitHub repositories" + - [ ] fix UI on `Welcome` + - [x] get rid of `Error` - [ ] Define unit tests - [ ] Fix interfaces and type definitions - [ ] Setup GitHub Actions diff --git a/package-lock.json b/package-lock.json index 4102bb3..7a00178 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,14 +9,14 @@ "version": "0.6.1", "license": "MIT", "dependencies": { - "hono": "^4.4.10", + "hono": "^4.4.11", "octokit": "^4.0.2" }, "devDependencies": { "@cloudflare/workers-types": "^4.20240620.0", "@hono/vite-cloudflare-pages": "^0.4.1", "@hono/vite-dev-server": "^0.12.2", - "vite": "^5.3.2", + "vite": "^5.3.3", "vitest": "^1.6.0", "wrangler": "^3.62.0" } @@ -1757,9 +1757,9 @@ } }, "node_modules/hono": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.4.10.tgz", - "integrity": "sha512-z6918u9rXRU5CCisMHd2uUVoQXcNyUrUMmYY7VH10v4HJG7+hqgMK/G8YNTd13C6s4rBfzF09iz8VpOip9qG3A==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.4.11.tgz", + "integrity": "sha512-R5RADpjoRsR3/VsnFovpsYNLPnC1f+FgdfsePk3qIgjb4D41Sg7uW5QCj41kzEOwXCjBg0sVvOZMvUNZ0DKB7g==", "engines": { "node": ">=16.0.0" } @@ -2190,9 +2190,9 @@ } }, "node_modules/postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", "dev": true, "funding": [ { @@ -2210,7 +2210,7 @@ ], "dependencies": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "source-map-js": "^1.2.0" }, "engines": { @@ -2613,13 +2613,13 @@ "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" }, "node_modules/vite": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.2.tgz", - "integrity": "sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.3.tgz", + "integrity": "sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==", "dev": true, "dependencies": { "esbuild": "^0.21.3", - "postcss": "^8.4.38", + "postcss": "^8.4.39", "rollup": "^4.13.0" }, "bin": { @@ -4413,9 +4413,9 @@ } }, "hono": { - "version": "4.4.10", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.4.10.tgz", - "integrity": "sha512-z6918u9rXRU5CCisMHd2uUVoQXcNyUrUMmYY7VH10v4HJG7+hqgMK/G8YNTd13C6s4rBfzF09iz8VpOip9qG3A==" + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.4.11.tgz", + "integrity": "sha512-R5RADpjoRsR3/VsnFovpsYNLPnC1f+FgdfsePk3qIgjb4D41Sg7uW5QCj41kzEOwXCjBg0sVvOZMvUNZ0DKB7g==" }, "human-signals": { "version": "5.0.0", @@ -4719,13 +4719,13 @@ } }, "postcss": { - "version": "8.4.38", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", - "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", + "version": "8.4.39", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", + "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", "dev": true, "requires": { "nanoid": "^3.3.7", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "source-map-js": "^1.2.0" } }, @@ -5047,14 +5047,14 @@ "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==" }, "vite": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.2.tgz", - "integrity": "sha512-6lA7OBHBlXUxiJxbO5aAY2fsHHzDr1q7DvXYnyZycRs2Dz+dXBWuhpWHvmljTRTpQC2uvGmUFFkSHF2vGo90MA==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.3.tgz", + "integrity": "sha512-NPQdeCU0Dv2z5fu+ULotpuq5yfCS1BzKUIPhNbP3YBfAMGJXbt2nS+sbTFu+qchaqWTD+H3JK++nRwr6XIcp6A==", "dev": true, "requires": { "esbuild": "^0.21.3", "fsevents": "~2.3.3", - "postcss": "^8.4.38", + "postcss": "^8.4.39", "rollup": "^4.13.0" } }, diff --git a/package.json b/package.json index cca5e75..bc825fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "petithub", - "version": "0.6.1", + "version": "0.6.2", "private": false, "description": "PetitHub - Explore obscure GitHub repositories", "author": { @@ -30,14 +30,14 @@ "deploy": "$npm_execpath run build && wrangler pages deploy" }, "dependencies": { - "hono": "^4.4.10", + "hono": "^4.4.11", "octokit": "^4.0.2" }, "devDependencies": { "@cloudflare/workers-types": "^4.20240620.0", "@hono/vite-cloudflare-pages": "^0.4.1", "@hono/vite-dev-server": "^0.12.2", - "vite": "^5.3.2", + "vite": "^5.3.3", "vitest": "^1.6.0", "wrangler": "^3.62.0" } diff --git a/public/static/script.js b/public/static/script.js index cbd7e00..b6fa07e 100644 --- a/public/static/script.js +++ b/public/static/script.js @@ -5,4 +5,11 @@ function getCookie(name) { const maxIdCookie = getCookie(`__Secure-max_id`); if (!maxIdCookie) { fetch("/id"); +} else { + const now = new Date().getTime(); + const { timestamp } = JSON.parse(decodeURIComponent(maxIdCookie)); + if (now > timestamp + 86400000) { + /* more than 1 day */ + fetch("/id"); + } } diff --git a/public/static/style.css b/public/static/style.css index 076328d..0102c31 100644 --- a/public/static/style.css +++ b/public/static/style.css @@ -65,6 +65,9 @@ body { cursor: pointer; filter: var(--svg-icon-color); } +.header button { + margin: 0 1rem; +} .header .title { font-size: 2rem; font-weight: 600; diff --git a/src/index.tsx b/src/index.tsx index fba2b70..90efb54 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -2,17 +2,15 @@ import { Context, Hono } from "hono"; import { Suspense } from "hono/jsx"; import { logger } from "hono/logger"; -import { renderer, Loader, RepositoryContainer, Login } from "./utils/renderer"; -import { getOctokitInstance } from "./utils/octokit"; -import { handleMaxId, handleTokens } from "./utils/cookie"; -import { generateState, handleState } from "./utils/state"; +import { renderer, Loader, RepositoryContainer } from "./utils/renderer"; +import { getOctokitInstance, handleMaxId } from "./utils/octokit"; +import { handleTokens, refreshToken } from "./utils/tokens"; import api from "./routes/api"; -import id from "./routes/id"; -import template from "./routes/template"; -import petithub from "./routes/petithub"; import github from "./routes/github"; import welcome from "./routes/welcome"; +import template from "./routes/template"; +import id from "./routes/id"; /* TYPES */ export type Bindings = { @@ -22,10 +20,10 @@ export type Bindings = { }; export type Variables = { - max_id: number; + max_id: { id: number; timestamp: number }; access_token?: string; refresh_token?: string; - state?: string; + state: string; }; /* APP */ @@ -34,42 +32,16 @@ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); /* MIDDLEWARES */ app.use(logger()); app.use(renderer); -app.use(handleMaxId()); -app.use(handleTokens()); -app.use("/", async (c, next) => { - const { access_token, refresh_token } = c.var; - console.log(access_token, refresh_token); - if (!access_token) { - // TODO allow some use without access_token and only redirect when out of free API usage - if (!refresh_token) { - // return c.redirect("/login", 302); - } else { - return c.redirect( - `/github/access_token?refresh_token=${refresh_token}&callback_url=/` - ); - } - } - await next(); -}); // TODO handle token verification -app.use("/github/login", generateState()); -app.use("/github/callback", handleState()); +app.use("/", handleMaxId()); +app.use("/", handleTokens()); +app.use("/", refreshToken()); /* ROUTES */ app.route("/api", api); -app.route("/id", id); -app.route("/template", template); -app.route("/petithub", petithub); app.route("/github", github); app.route("/welcome", welcome); - -app.get( - "/login", - (c: Context<{ Bindings: Bindings; Variables: Variables }>): Response => { - return c.render(, { - title: "PetitHub - login", - }); - } -); // TODO suppress login route and add specific button to login +app.route("/template", template); +app.route("/id", id); /* ROOT */ app.get( @@ -81,7 +53,7 @@ app.get( const { max_id } = c.var; return c.render( }> - + , { title: "PetitHub" } // TODO change this title dynamically ); diff --git a/src/routes/api.tsx b/src/routes/api.tsx index ee32c17..1778ef3 100644 --- a/src/routes/api.tsx +++ b/src/routes/api.tsx @@ -4,6 +4,8 @@ import { prettyJSON } from "hono/pretty-json"; import { cors } from "hono/cors"; import { Bindings, Variables } from ".."; +import { handleMaxId } from "../utils/octokit"; +import { handleTokens, refreshToken } from "../utils/tokens"; import { apiAuth, getOctokitInstance, @@ -11,9 +13,13 @@ import { getRepository, } from "../utils/octokit"; +/* APP */ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); /* MIDDLEWARES */ +app.use(handleMaxId()); +app.use(handleTokens()); +app.use(refreshToken()); app.use(apiAuth()); app.use(poweredBy()); app.use(prettyJSON()); @@ -21,27 +27,34 @@ app.use(cors({ origin: "*", allowMethods: ["GET"], credentials: true })); /* ENDPOINTS */ app.get( - "", + "/", + async (c: Context<{ Bindings: Bindings; Variables: Variables }>) => { + c.redirect("/api/random"); + } +); // TODO display Swagger + +app.get( + "/random", async ( c: Context<{ Bindings: Bindings; Variables: Variables }> ): Promise => { const octokit = getOctokitInstance(c); const { max_id } = c.var; try { - const repository = await getRandomRepository(octokit, max_id); + const repository = await getRandomRepository(octokit, max_id.id); return c.json(repository); } catch (error: any) { return c.json({ error: "Failed to fetch repository data" }, 500); } } -); // TODO fix request to "/api" that redirects to "/" +); app.get( "/:id", async ( c: Context<{ Bindings: Bindings; Variables: Variables }> ): Promise => { - const id = c.req.param("id"); + const { id } = c.req.param(); const octokit = getOctokitInstance(c); try { const repository = await getRepository(octokit, Number(id)); diff --git a/src/routes/github.tsx b/src/routes/github.tsx index 039f3bb..ad9849a 100644 --- a/src/routes/github.tsx +++ b/src/routes/github.tsx @@ -1,10 +1,19 @@ import { Context, Hono } from "hono"; import { Bindings, Variables } from ".."; -import { setCookieToken } from "../utils/cookie"; +import { generateState, handleState } from "../utils/state"; +import { handleAccess, handleRefresh } from "../utils/tokens"; +/* APP */ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); +/* MIDDLEWARES */ +app.use("/login", generateState()); +app.use("/callback", handleState()); +app.use("/callback", handleRefresh()); +app.use("/access_token", handleAccess()); + +/* ENDPOINTS */ app.get( "/login", async ( @@ -12,11 +21,15 @@ app.get( ): Promise => { const { CLIENT_ID } = c.env; const { state } = c.var; - const redirect_url = new URL(c.req.url); + const { url } = c.req; + const redirect_url = new URL(url); redirect_url.pathname = "/github/callback"; - const redirect_uri = redirect_url.toString(); + const searchParams = new URLSearchParams(); + searchParams.append("client_id", CLIENT_ID); + searchParams.append("redirect_uri", redirect_url.toString()); + searchParams.append("state", state); return c.redirect( - `https://github.com/login/oauth/authorize?client_id=${CLIENT_ID}&redirect_uri=${redirect_uri}&state=${state}`, + `https://github.com/login/oauth/authorize?${searchParams.toString()}`, 302 ); } @@ -25,82 +38,21 @@ app.get( app.get( "/callback", async (c: Context<{ Bindings: Bindings; Variables: Variables }>) => { - const { CLIENT_ID, CLIENT_SECRET } = c.env; - const { state: secret } = c.var; - const code = c.req.query("code"); - const state = c.req.query("state"); - if (state === secret) { - const response = await fetch( - `https://github.com/login/oauth/access_token?client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&code=${code}`, - { method: "POST" } - ); - const tokens = await response.text(); - const responseParams = new URLSearchParams(tokens); - const error = responseParams.get("error"); - const refreshToken = responseParams.get("refresh_token"); - const refreshTokenExpiresIn = responseParams.get( - "refresh_token_expires_in" - ); - if (refreshToken && refreshTokenExpiresIn) { - setCookieToken( - c, - "refresh_token", - refreshToken, - Number(refreshTokenExpiresIn) - ); - } else if (error) { - const errorDescription = responseParams.get("error_description"); - console.error(error, errorDescription); - } - return c.redirect( - `/github/access_token?${tokens}&callback_url=/welcome`, - 302 - ); - } else { - console.error( - `State mismatched: expected ${secret} and received ${state}` - ); - return c.text(`State mismatched`, 500); - } + const { refresh_token, access_token } = c.var; + const searchParams = new URLSearchParams(); + refresh_token && searchParams.append("refresh_token", refresh_token); + access_token && searchParams.append("access_token", access_token); + access_token && searchParams.append("expires_in", `28800`); + searchParams.append("callback_url", "/welcome"); + return c.redirect(`/github/access_token?${searchParams.toString()}`, 302); } -); // TODO fix oauth workflow (send tokens in a new URL as query params) +); app.get( "/access_token", async (c: Context<{ Bindings: Bindings; Variables: Variables }>) => { - const { CLIENT_ID, CLIENT_SECRET } = c.env; - const callbackUrl = c.req.query("callback_url"); - const refreshToken = c.req.query("refresh_token"); - const accessToken = c.req.query("access_token"); - const expiresIn = c.req.query("expires_in"); - if (accessToken) { - setCookieToken(c, "access_token", accessToken, Number(expiresIn)); - } else if (refreshToken) { - const response = await fetch( - `https://github.com/login/oauth/access_token?client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&refresh_token=${refreshToken}&grant_type=refresh_token`, - { method: "POST" } - ); - const tokens = await response.text(); - const responseParams = new URLSearchParams(tokens); - const error = responseParams.get("error"); - const refreshedAccessToken = responseParams.get("access_token"); - const refreshedExpiresIn = responseParams.get("expires_in"); - if (refreshedAccessToken) { - setCookieToken( - c, - "access_token", - refreshedAccessToken, - Number(refreshedExpiresIn) - ); - } else if (error) { - const errorDescription = responseParams.get("error_description"); - console.error(error, errorDescription); - } - return c.redirect("/github/login", 302); - } else { - return c.redirect("/login", 302); - } - return c.redirect(callbackUrl ? callbackUrl : "/welcome", 302); // TODO redirect with access_token to display account on /welcome + const { callback_url } = c.req.query(); + return c.redirect(callback_url || "/welcome", 302); } ); diff --git a/src/routes/id.tsx b/src/routes/id.tsx index 500bb55..bc9ca27 100644 --- a/src/routes/id.tsx +++ b/src/routes/id.tsx @@ -1,29 +1,39 @@ import { Context, Hono } from "hono"; import { Bindings, Variables } from ".."; +import { handleTokens, refreshToken } from "../utils/tokens"; import { getMaxId, getOctokitInstance } from "../utils/octokit"; import { setCookie } from "hono/cookie"; +/* APP */ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); +/* MIDDLEWARES */ +app.use(handleTokens()); +app.use(refreshToken()); + +/* ENDPOINTS */ app.get( "/", async ( c: Context<{ Bindings: Bindings; Variables: Variables }> ): Promise => { - const { max_id, access_token } = c.var; + const { + max_id: { id, timestamp: old }, + access_token, + } = c.var; const octokit = getOctokitInstance(c); - const now = new Date().getTime(); - const id = access_token ? await getMaxId(octokit, max_id) : max_id; - setCookie(c, "max_id", `${id}`, { + const update = access_token ? await getMaxId(octokit, id) : id; + const timestamp = access_token ? new Date().getTime() : old; + setCookie(c, "max_id", `{ "id": ${update}, "timestamp": ${timestamp} }`, { path: "/", secure: true, - httpOnly: false /* true */, - maxAge: access_token ? 86400 : 600, + httpOnly: false, // true + maxAge: 31557600, sameSite: "Strict", prefix: "secure", }); - return c.json({ id, timestamp: now }); + return c.json({ id: update, timestamp: timestamp }); } ); diff --git a/src/routes/petithub.tsx b/src/routes/petithub.tsx deleted file mode 100644 index 327c84f..0000000 --- a/src/routes/petithub.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Context, Hono } from "hono"; -import { Suspense } from "hono/jsx"; - -import { Bindings, Variables } from ".."; -import { Loader, Container } from "../utils/renderer"; -import { getOctokitInstance, getRepos } from "../utils/octokit"; - -const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); - -app.get( - "/", - async ( - c: Context<{ Bindings: Bindings; Variables: Variables }> - ): Promise => { - const octokit = getOctokitInstance(c); - const owner = "cletqui"; - const repo = "petithub"; - const { data: repository } = await getRepos(octokit, owner, repo); - return c.render( - }> - - , - { title: `PetitHub - ${owner}/${repo}` } - ); - } -); - -export default app; diff --git a/src/routes/template.tsx b/src/routes/template.tsx index afc73f2..b2e64a9 100644 --- a/src/routes/template.tsx +++ b/src/routes/template.tsx @@ -2,19 +2,26 @@ import { Context, Hono } from "hono"; import { Suspense } from "hono/jsx"; import { Bindings, Variables } from ".."; +import { handleTokens, refreshToken } from "../utils/tokens"; import { Loader, Container } from "../utils/renderer"; import { getOctokitInstance, getRepos } from "../utils/octokit"; +/* APP */ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); +/* MIDDLEWARES */ +app.use(handleTokens()); +app.use(refreshToken()); + +/* ENDPOINTS */ app.get( "/", async ( c: Context<{ Bindings: Bindings; Variables: Variables }> ): Promise => { const octokit = getOctokitInstance(c); - const owner = "octocat"; - const repo = "Hello-World"; + const owner = "cletqui"; + const repo = "petithub"; const { data: repository } = await getRepos(octokit, owner, repo); return c.render( }> diff --git a/src/routes/welcome.tsx b/src/routes/welcome.tsx index 25955da..968eb00 100644 --- a/src/routes/welcome.tsx +++ b/src/routes/welcome.tsx @@ -3,16 +3,18 @@ import { Context, Hono } from "hono"; import { Bindings, Variables } from ".."; import { Welcome } from "../utils/renderer"; +/* APP */ const app = new Hono<{ Bindings: Bindings; Variables: Variables }>(); +/* ENDPOINTS */ app.get( - "/welcome", + "/", (c: Context<{ Bindings: Bindings; Variables: Variables }>): Response => { // deleteCookie(c, "state", stateCookieOptions); // TODO fix cookie storage/deletion return c.render(, { title: "PetitHub - welcome", }); } -); +); // TODO improve UI export default app; diff --git a/src/utils/cookie.tsx b/src/utils/cookie.tsx deleted file mode 100644 index 293a0e2..0000000 --- a/src/utils/cookie.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Context, MiddlewareHandler, Next } from "hono"; -import { setCookie, getCookie } from "hono/cookie"; -import { CookieOptions } from "hono/utils/cookie"; - -import { Bindings, Variables } from ".."; - -export const handleMaxId = (): MiddlewareHandler => { - return async function handleMaxId( - c: Context<{ Bindings: Bindings; Variables: Variables }>, - next: Next - ) { - const max_id = getCookie(c, "max_id", "secure"); - const MAX_ID = 822080279; // TODO TBU - c.set("max_id", Number(max_id) || MAX_ID); - await next(); - }; -}; - -export const handleTokens = (): MiddlewareHandler => { - return async function handleTokens( - c: Context<{ Bindings: Bindings; Variables: Variables }>, - next: Next - ) { - const accessToken = getCookie(c, "access_token", "secure"); - const refreshToken = getCookie(c, "refresh_token", "secure"); - c.set("access_token", accessToken); - c.set("refresh_token", refreshToken); - await next(); - }; -}; - -export const setCookieToken = ( - c: Context, - name: string, - value: string, - expires: number -): void => { - setCookie(c, name, value, { - path: "/", - secure: true, - httpOnly: true, - maxAge: expires, - sameSite: "Strict", - prefix: "secure", - }); -}; - -export const stateCookieOptions: CookieOptions = { - path: "/github", - secure: true, - httpOnly: true, - maxAge: 600, - sameSite: "none", - prefix: "secure", -}; diff --git a/src/utils/octokit.tsx b/src/utils/octokit.tsx index b6ace82..bce6e7b 100644 --- a/src/utils/octokit.tsx +++ b/src/utils/octokit.tsx @@ -1,4 +1,5 @@ import { Context, MiddlewareHandler, Next } from "hono"; +import { getCookie } from "hono/cookie"; import { Octokit } from "@octokit/core"; import { OctokitResponse } from "@octokit/types"; @@ -13,10 +14,8 @@ export const apiAuth = (): MiddlewareHandler => { ) { const { access_token } = c.var; const accessToken = access_token || c.req.header("Authorization"); - if (accessToken) { - if (await verifyToken(accessToken, c)) { - await next(); - } + if (accessToken && (await verifyToken(accessToken, c))) { + await next(); } return c.text("Unauthorized", 401); }; @@ -139,6 +138,18 @@ export const getRandomRepository = async ( } }; +export const handleMaxId = (): MiddlewareHandler => { + return async function handleMaxId( + c: Context<{ Bindings: Bindings; Variables: Variables }>, + next: Next + ) { + const max_id = getCookie(c, "max_id", "secure"); + const MAX_ID = 822080279; // TODO TBU + c.set("max_id", max_id ? JSON.parse(max_id) : { id: MAX_ID, timestamp: 0 }); + await next(); + }; +}; + export const getMaxId = async ( octokit: Octokit, id: number diff --git a/src/utils/renderer.tsx b/src/utils/renderer.tsx index eb0a654..c277e90 100644 --- a/src/utils/renderer.tsx +++ b/src/utils/renderer.tsx @@ -68,6 +68,7 @@ export const RepositoryContainer = async ({ if (status && status === 403) { return ; } else { + console.error(status, message); return ; } } @@ -82,7 +83,7 @@ export const Loader = (): JSX.Element => { ); }; -export const Login = ({ message }: { message: string }): JSX.Element => { +const Login = ({ message }: { message: string }): JSX.Element => { return ( {"Login"} @@ -92,18 +93,22 @@ export const Login = ({ message }: { message: string }): JSX.Element => { ); -}; // TODO implement Demo/Github login +}; // TODO fix UI export const Welcome = ({}): JSX.Element => { return ( - {"Welcome"} + {"Welcome to PetitHub"} + {"You are now connected"} {"Browse random GitHub repositories"} + + {"Browse API"} + ); -}; // TODO implement Demo/Github login +}; // TODO fix UI export const Container = ({ repository, @@ -224,7 +229,6 @@ export const Container = ({ src={avatar_url} alt="avatar_url" /> - {login} @@ -444,24 +448,15 @@ export const renderer = jsxRenderer( - - - + {"PetitHub"} - - - {"Login"} - - - + + {"Login"} + {children}
{"You are now connected"}