From 3ce127345568fe36c0f45988a83140fbc097db41 Mon Sep 17 00:00:00 2001 From: Kevin FEDYNA Date: Wed, 22 Jan 2025 00:54:43 +0100 Subject: [PATCH] Started documenting code --- databases/ensure.ts | 10 +++++++++- defaults/interfaces.ts | 9 +++++++++ defaults/makeIndex.ts | 18 ++++++++++++++---- defaults/makePartials.tsx | 27 ++++++++++++++++++++------- routes/(apps)/_layout.tsx | 2 +- routes/_app.tsx | 2 +- routes/_middleware.ts | 24 ++++++++++++++++-------- routes/login.tsx | 2 +- routes/logout.tsx | 2 +- 9 files changed, 72 insertions(+), 24 deletions(-) diff --git a/databases/ensure.ts b/databases/ensure.ts index 1c56375..c1cde16 100644 --- a/databases/ensure.ts +++ b/databases/ensure.ts @@ -1,6 +1,14 @@ import { Database } from "@db/sqlite"; -export default async function ensureDatabases() { +/** + * Ensure database file creation on new server start. + * + * Read all SQL files in init directory and create + * associated SQLite database file. + * + * **Must not be used out of statup use-case.** + */ +export default async function ensureDatabases(): Promise { await Deno.mkdir("databases/data", { recursive: true }); for await (const file of Deno.readDir("databases/init")) { diff --git a/defaults/interfaces.ts b/defaults/interfaces.ts index 3189dfe..24a5076 100644 --- a/defaults/interfaces.ts +++ b/defaults/interfaces.ts @@ -1,4 +1,10 @@ import { type RegularTagNode, type TextNode } from "@melvdouc/xml-parser"; +import { AsyncRoute } from "$fresh/src/server/types.ts"; + +export interface State { + isAuthenticated: boolean; + session: CasContent; +} export interface AppProperties { name: string; @@ -48,3 +54,6 @@ export interface LoginJWT { } export type EmptyObject = Record; + +// deno-lint-ignore no-explicit-any +export type Route = AsyncRoute; \ No newline at end of file diff --git a/defaults/makeIndex.ts b/defaults/makeIndex.ts index f4ebd11..19ebc91 100644 --- a/defaults/makeIndex.ts +++ b/defaults/makeIndex.ts @@ -1,12 +1,22 @@ import { FreshContext } from "$fresh/server.ts"; -import { State } from "$root/routes/_middleware.ts"; +import { Route, State } from "$root/defaults/interfaces.ts"; +import { ComponentChildren } from "preact"; -export default function makeIndex(basePath: string) { +/** + * Generates index file based on `Index` fresh partial to avoid code duplication. + * @param basePath The base path of the module, should be `import.meta.url!`. + * @returns The `Index` fresh partial that will be displayed by default. + * + * @example + * import makeIndex from "$root/defaults/makeIndex.ts"; + * export default makeIndex(import.meta.dirname!); + */ +export default function makeIndex(basePath: string): Route { return async function Index( request: Request, context: FreshContext, - ) { - const index = (await import(`${basePath}/partials/index.tsx`)).Index; + ): Promise { + const index: Route = (await import(`${basePath}/partials/index.tsx`)).Index; return index(request, context); }; } diff --git a/defaults/makePartials.tsx b/defaults/makePartials.tsx index e6b81af..5df6916 100644 --- a/defaults/makePartials.tsx +++ b/defaults/makePartials.tsx @@ -1,8 +1,12 @@ import { JSX } from "preact"; import { Partial } from "$fresh/runtime.ts"; import { FreshContext, RouteConfig } from "$fresh/server.ts"; -import { State } from "$root/routes/_middleware.ts"; +import { Route, State } from "$root/defaults/interfaces.ts"; +/** + * Gets the `RouteConfig` config object for partial pages. + * @returns The partials config object. + */ export function getPartialsConfig(): RouteConfig { return { skipAppWrapper: true, @@ -10,12 +14,21 @@ export function getPartialsConfig(): RouteConfig { }; } -export function makePartials( - page: ( - request: Request, - context: FreshContext, - ) => Promise, -) { +/** + * Partialize the given page for optimized rendering. + * @param page The partial `Route` object to partialize. + * @returns The partialized version of `page`. + * @example + * // Page defintion... + * async function Page(_request: Request, context: FreshContext) { + * return

My super page!

; + * } + * + * // Partial code that should be at each file's end. + * export const config = getPartialsConfig(); + * export default makePartials(Page); + */ +export function makePartials(page: Route) { return async function WrappedElements( request: Request, context: FreshContext, diff --git a/routes/(apps)/_layout.tsx b/routes/(apps)/_layout.tsx index 0fe56fa..ee3b43e 100644 --- a/routes/(apps)/_layout.tsx +++ b/routes/(apps)/_layout.tsx @@ -1,6 +1,6 @@ import { FreshContext } from "$fresh/server.ts"; import { Partial } from "$fresh/runtime.ts"; -import { State } from "$root/routes/_middleware.ts"; +import { State } from "$root/defaults/interfaces.ts"; import { AppProperties } from "$root/defaults/interfaces.ts"; import Navbar from "$root/routes/(_islands)/Navbar.tsx"; diff --git a/routes/_app.tsx b/routes/_app.tsx index 7025b97..8b253b8 100644 --- a/routes/_app.tsx +++ b/routes/_app.tsx @@ -1,5 +1,5 @@ import { FreshContext } from "$fresh/server.ts"; -import { State } from "$root/routes/_middleware.ts"; +import { State } from "$root/defaults/interfaces.ts"; import Header from "$root/routes/(_components)/Header.tsx"; import Footer from "$root/routes/(_components)/Footer.tsx"; diff --git a/routes/_middleware.ts b/routes/_middleware.ts index 3601da1..fbaca27 100644 --- a/routes/_middleware.ts +++ b/routes/_middleware.ts @@ -1,7 +1,7 @@ import { FreshContext } from "$fresh/server.ts"; import { getCookies } from "$std/http/cookie.ts"; import { getJwtPayload, isJwtValid } from "@popov/jwt"; -import { CasContent, LoginJWT } from "$root/defaults/interfaces.ts"; +import { CasContent, LoginJWT, State } from "$root/defaults/interfaces.ts"; const PUBLIC_ROUTES = [ "/", @@ -13,21 +13,29 @@ const PUBLIC_ROUTES = [ ]; const jwtKeyCache: Record = {}; +const deleteKey = (user: string) => delete jwtKeyCache[user]; -export interface State { - isAuthenticated: boolean; - session: CasContent; -} - -function isRoutePublic(route: string) { - return PUBLIC_ROUTES.includes(route) || route.match(/\..+$/); +/** + * Checks if the given route is public. + * @param route The route to check. + * @returns `true` if the route is public, `false` otherwise. + */ +function isRoutePublic(route: string): boolean { + return PUBLIC_ROUTES.includes(route) || + !!(route.match(/\..+$/)?.[0] ?? false); } +/** + * Get the given user's key, creating it if not already existing. + * @param user The key's user. + * @returns The user's key. + */ export function getKey(user: string): string { if (!jwtKeyCache[user]) { const keyBuffer = new Uint8Array(32); crypto.getRandomValues(keyBuffer); jwtKeyCache[user] = new TextDecoder().decode(keyBuffer); + setTimeout(deleteKey, 0x75300, user); } return jwtKeyCache[user]; diff --git a/routes/login.tsx b/routes/login.tsx index dbaa622..4bbd1c7 100644 --- a/routes/login.tsx +++ b/routes/login.tsx @@ -1,5 +1,5 @@ import { Handlers } from "$fresh/server.ts"; -import { State } from "$root/routes/_middleware.ts"; +import { State } from "$root/defaults/interfaces.ts"; import { parse, type RegularTagNode } from "@melvdouc/xml-parser"; import { CasContent, diff --git a/routes/logout.tsx b/routes/logout.tsx index 6111c62..8ebc21b 100644 --- a/routes/logout.tsx +++ b/routes/logout.tsx @@ -1,5 +1,5 @@ import { Handlers } from "$fresh/server.ts"; -import { State } from "$root/routes/_middleware.ts"; +import { State } from "$root/defaults/interfaces.ts"; import { deleteCookie } from "$std/http/cookie.ts"; const CAS = "https://ident.univ-amu.fr/cas";