39}, []);
40
41export function encode(data: Uint8Array): string {
42 return data.reduce((p, c) => {
43 p += alphabetBytesToChars[c];
46}
47
48export function decode(str: string): Uint8Array {
49 const byts = [];
50 for (const char of str) {
8## Example Projects
9
10- You have an HTTP val that is just for you, because it accesses your sqlite or blob storage or any other sensitive function. Install the [@postpostscript/authMiddleware.authMiddlewareCookie](https://postpostscript-modulehighlightvaluelink.web.val.run/?module=@postpostscript/authMiddleware&name=authMiddlewareCookie) middleware for zero-config authentication that makes executing the endpoint exclusive to you. Example: [@postpostscript/authIdExampleCookiePrivate](https://val.town/v/postpostscript/authIdExampleCookiePrivate)
11- You have an HTTP val and you want to gate a feature behind a login form while letting anyone access the site. Use that same middleware but disable the token issuer (`iss`) requirement and set the `optional` option to `true`. Example: [@postpostscript/authIdExampleComments](https://val.town/v/postpostscript/authIdExampleComments) 
12- You have an API and you want to lock it down, with specific scopes giving you access to specific endpoints. Use the [authMiddlewareToken](https://postpostscript-modulehighlightvaluelink.web.val.run/?module=@postpostscript/authMiddleware&name=authMiddlewareToken) middleware with the additional middleware [@postpostscript/pathAsScope](https://val.town/v/postpostscript/pathAsScope). Example: [@postpostscript/apiProxy](https://val.town/v/postpostscript/apiProxy)
15const name = getValNameFromUrl(import.meta.url);
16
17async function createPage(content: unknown) {
18 const [
19 footer,
7const USERNAME = extractValInfo(import.meta.url).author;
8
9export async function MyFooter(logo = valTownLogoAuto) {
10 const recommendation = rootValRef().handle === USERNAME
11 ? html`<span class="recommends">${await recommends()}</span>`
35}
36
37export default async function(req) {
38 const { Layout } = await import("https://esm.town/v/postpostscript/Layout");
39 return htmlResponse`${Layout`
5const ENDPOINT = getValEndpointFromUrl(import.meta.url);
6
7export function profileImageUrl(username: string) {
8 return `${ENDPOINT}/${username}`;
9}
10
11export function ProfileImage(
12 username: string,
13 className = "profile-image",
16}
17
18export function Profile(username: string) {
19 return html`
20 <span
34}
35
36export default async function(req: Request) {
37 const { pathname } = new URL(req.url);
38 if (pathname.length <= 1) {
3
4type Index = { x: number; y: number };
5function next_i(i: Index): Index | null {
6 if (i.x === COLS - 1 && i.y === ROWS - 1) {
7 return null;
13}
14
15function valid_row(sudoku: Sudoku, i: Index): boolean {
16 const seen = new Set();
17 for (let col = 0; col < COLS; col++) {
27}
28
29function valid_col(sudoku: Sudoku, i: Index): boolean {
30 const seen = new Set();
31 for (let row = 0; row < ROWS; row++) {
41}
42
43function valid_square(sudoku: Sudoku, i: Index): boolean {
44 const col_offset = Math.floor(i.x / 3) * 3;
45 const row_offset = Math.floor(i.y / 3) * 3;
60}
61
62export function solve(sudoku: Sudoku): Sudoku | null {
63 sudoku = Sudoku.parse(sudoku);
64
12};
13
14export function pathAsScope({ val = rootValRef(), basePath = "/", log = false }: PathAsScopeOptions = {}) {
15 const { handle, name } = val;
16 const valName = `@${handle}/${name}`;
56}
57
58export function pathMatches(path: string, matchString: string) {
59 const pathParts = ("/" + path.replace(/^\/|\/$/g, "")).split("/");
60 const matchParts = ("/" + matchString.replace(/^\/|\/$/g, "")).split("/");
5};
6
7export function basicAuth(next: (Request) => Response | Promise<Response>, options: BasicAuthOptions) {
8 return async (req: Request) => {
9 if (req.headers.get("referer") == "https://www.val.town/") {
33}
34
35function extractCredentials(authorization): { username: string; password: string } {
36 const parts = authorization.split(" ");
37 if (parts[0] != "Basic") {
47}
48
49async function isRequestAuthenticated(req, userTable: string) {
50 if (!req.headers.has("authorization")) {
51 return false;
4import {Scrypt, generateId} from "npm:lucia"
5
6export async function createTables(userTable: string, sessionTable: string) {
7 return sqlite.batch([
8 `CREATE TABLE ${userTable} (
20}
21
22export async function createUser(table: string, username: string, password: string) {
23 if (
24 username.length < 3
43}
44
45export async function getUser(
46 table: string,
47 username: string,
56}
57
58export async function verifyPassword(hashed_password: string, password: string): Promise<boolean> {
59 return new Scrypt().verify(hashed_password, password);
60}
127}
128
129function transformIntoDatabaseSession(raw: SessionSchema): DatabaseSession {
130 const { id, user_id: userId, expires_at: expiresAtUnix, ...attributes } = raw;
131 return {
137}
138
139function transformIntoDatabaseUser(raw: UserSchema): DatabaseUser {
140 const { id, ...attributes } = raw;
141 return {
145}
146
147function escapeName(val: string): string {
148 return "`" + val + "`";
149}