Started documenting code

This commit is contained in:
Kevin FEDYNA
2025-01-22 00:54:43 +01:00
parent 54f4a83590
commit 3ce1273455
9 changed files with 72 additions and 24 deletions
+9 -1
View File
@@ -1,6 +1,14 @@
import { Database } from "@db/sqlite"; 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<void> {
await Deno.mkdir("databases/data", { recursive: true }); await Deno.mkdir("databases/data", { recursive: true });
for await (const file of Deno.readDir("databases/init")) { for await (const file of Deno.readDir("databases/init")) {
+9
View File
@@ -1,4 +1,10 @@
import { type RegularTagNode, type TextNode } from "@melvdouc/xml-parser"; 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 { export interface AppProperties {
name: string; name: string;
@@ -48,3 +54,6 @@ export interface LoginJWT {
} }
export type EmptyObject = Record<string | number | symbol, never>; export type EmptyObject = Record<string | number | symbol, never>;
// deno-lint-ignore no-explicit-any
export type Route = AsyncRoute<any, State>;
+14 -4
View File
@@ -1,12 +1,22 @@
import { FreshContext } from "$fresh/server.ts"; 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( return async function Index(
request: Request, request: Request,
context: FreshContext<State>, context: FreshContext<State>,
) { ): Promise<ComponentChildren | Response> {
const index = (await import(`${basePath}/partials/index.tsx`)).Index; const index: Route = (await import(`${basePath}/partials/index.tsx`)).Index;
return index(request, context); return index(request, context);
}; };
} }
+20 -7
View File
@@ -1,8 +1,12 @@
import { JSX } from "preact"; import { JSX } from "preact";
import { Partial } from "$fresh/runtime.ts"; import { Partial } from "$fresh/runtime.ts";
import { FreshContext, RouteConfig } from "$fresh/server.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 { export function getPartialsConfig(): RouteConfig {
return { return {
skipAppWrapper: true, skipAppWrapper: true,
@@ -10,12 +14,21 @@ export function getPartialsConfig(): RouteConfig {
}; };
} }
export function makePartials( /**
page: ( * Partialize the given page for optimized rendering.
request: Request, * @param page The partial `Route` object to partialize.
context: FreshContext<State>, * @returns The partialized version of `page`.
) => Promise<JSX.Element>, * @example
) { * // Page defintion...
* async function Page(_request: Request, context: FreshContext<State>) {
* return <h2>My super page!</h2>;
* }
*
* // 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( return async function WrappedElements(
request: Request, request: Request,
context: FreshContext<State>, context: FreshContext<State>,
+1 -1
View File
@@ -1,6 +1,6 @@
import { FreshContext } from "$fresh/server.ts"; import { FreshContext } from "$fresh/server.ts";
import { Partial } from "$fresh/runtime.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 { AppProperties } from "$root/defaults/interfaces.ts";
import Navbar from "$root/routes/(_islands)/Navbar.tsx"; import Navbar from "$root/routes/(_islands)/Navbar.tsx";
+1 -1
View File
@@ -1,5 +1,5 @@
import { FreshContext } from "$fresh/server.ts"; 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 Header from "$root/routes/(_components)/Header.tsx";
import Footer from "$root/routes/(_components)/Footer.tsx"; import Footer from "$root/routes/(_components)/Footer.tsx";
+16 -8
View File
@@ -1,7 +1,7 @@
import { FreshContext } from "$fresh/server.ts"; import { FreshContext } from "$fresh/server.ts";
import { getCookies } from "$std/http/cookie.ts"; import { getCookies } from "$std/http/cookie.ts";
import { getJwtPayload, isJwtValid } from "@popov/jwt"; 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 = [ const PUBLIC_ROUTES = [
"/", "/",
@@ -13,21 +13,29 @@ const PUBLIC_ROUTES = [
]; ];
const jwtKeyCache: Record<string, string> = {}; const jwtKeyCache: Record<string, string> = {};
const deleteKey = (user: string) => delete jwtKeyCache[user];
export interface State { /**
isAuthenticated: boolean; * Checks if the given route is public.
session: CasContent; * @param route The route to check.
} * @returns `true` if the route is public, `false` otherwise.
*/
function isRoutePublic(route: string) { function isRoutePublic(route: string): boolean {
return PUBLIC_ROUTES.includes(route) || route.match(/\..+$/); 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 { export function getKey(user: string): string {
if (!jwtKeyCache[user]) { if (!jwtKeyCache[user]) {
const keyBuffer = new Uint8Array(32); const keyBuffer = new Uint8Array(32);
crypto.getRandomValues(keyBuffer); crypto.getRandomValues(keyBuffer);
jwtKeyCache[user] = new TextDecoder().decode(keyBuffer); jwtKeyCache[user] = new TextDecoder().decode(keyBuffer);
setTimeout(deleteKey, 0x75300, user);
} }
return jwtKeyCache[user]; return jwtKeyCache[user];
+1 -1
View File
@@ -1,5 +1,5 @@
import { Handlers } from "$fresh/server.ts"; 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 { parse, type RegularTagNode } from "@melvdouc/xml-parser";
import { import {
CasContent, CasContent,
+1 -1
View File
@@ -1,5 +1,5 @@
import { Handlers } from "$fresh/server.ts"; 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"; import { deleteCookie } from "$std/http/cookie.ts";
const CAS = "https://ident.univ-amu.fr/cas"; const CAS = "https://ident.univ-amu.fr/cas";