// Serves HTML from a template for every landing route on aesthetic.computer.
import https from "https";
import path from "path";
import { promises as fs } from "fs";
import { URLSearchParams, fileURLToPath } from "url";
import he from "he";
const { encode } = he;
import * as num from "../../public/aesthetic.computer/lib/num.mjs";
import {
parse,
metadata,
inferTitleDesc,
updateCode,
} from "../../public/aesthetic.computer/lib/parse.mjs";
import { respond } from "../../backend/http.mjs";
import { handleFromPermahandle } from "../../backend/authorization.mjs";
import { connect } from "../../backend/database.mjs";
import { recordPieceHit, looksAutomated } from "../../backend/piece-hits.mjs";
import { bootPreloads, workerBundleFilename, builtinPieceUrl } from "../../backend/boot-preloads.mjs";
import { defaultTemplateStringProcessor as html } from "../../public/aesthetic.computer/lib/helpers.mjs";
import { networkInterfaces } from "os";
const dev = process.env.CONTEXT === "dev" || process.env.NETLIFY_DEV === "true";
const BARE_KIDLISP_CODE = /^[0-9A-Za-z]{3,64}$/;
const POSTHOG_CLOUD_HOSTS = new Set([
"https://us.i.posthog.com",
"https://eu.i.posthog.com",
]);
function postHogBrowserConfig() {
const projectToken = process.env.POSTHOG_PROJECT_TOKEN?.trim();
const apiHost = process.env.POSTHOG_API_HOST?.trim() || "https://us.i.posthog.com";
if (!projectToken?.startsWith("phc_") || !POSTHOG_CLOUD_HOSTS.has(apiHost)) {
return null;
}
return {
projectToken,
apiHost,
uiHost: apiHost.startsWith("https://eu.")
? "https://eu.posthog.com"
: "https://us.posthog.com",
};
}
function serializeBrowserConfig(config) {
return JSON.stringify(config).replaceAll("<", "\\u003c");
}
// Record a piece hit against the database we are already connected to. This
// used to POST to our own public API โ out through the CDN and back into a
// second function invocation โ which is why half the landing page's latency
// was spent telling ourselves something we already knew.
async function trackPieceHit(piece, type) {
try {
const database = await connect();
await recordPieceHit(database.db, { piece, type });
await database.disconnect();
} catch (e) {
// Silent fail โ counting a read must never cost the reader the page.
if (dev) console.log("๐ Hit tracking failed:", e.message);
}
}
async function findBareKidlispCode(slug) {
if (!BARE_KIDLISP_CODE.test(slug)) return false;
try {
const database = await connect();
const record = await database.db.collection("kidlisp").findOne(
{ code: slug },
{ projection: { _id: 1 } },
);
await database.disconnect();
return !!record;
} catch (err) {
console.log(`[kidlisp] Bare /${slug} lookup failed:`, err?.message || err);
return false;
}
}
function redirectToKidlispCode(event, code) {
const query = new URLSearchParams(event.queryStringParameters || {});
const suffix = query.toString() ? `?${query.toString()}` : "";
const location = `/$${code}${suffix}`;
return respond(
302,
`Redirecting to ${location}`,
{
"Content-Type": "text/html",
Location: location,
},
);
}
async function fun(event, context) {
const _startTime = Date.now();
// ๐ DEBUG: Log the actual path resolution for troubleshooting
console.log(`๐ DEBUG index.mjs: path=${event.path}, dev=${dev}, __dirname=${typeof __dirname !== 'undefined' ? __dirname : 'N/A'}`);
try {
// TODO: Return a 500 or 404 for everything that does not exist...
// - [] Like for example if the below import fails...
// ๐ A WebSocket handshake is not a page. Stale clients โ cached service
// workers and old installed builds from before the loader moved to
// session-server.aesthetic.computer โ still try to upgrade against the
// root host, and every failed attempt was being answered with the full
// ~120KB landing page and counted as a piece hit. Refuse cheaply instead;
// they retry forever either way, but now it costs a header, not a page.
if ((event.headers["upgrade"] || "").toLowerCase() === "websocket") {
return {
statusCode: 426,
headers: {
"Content-Type": "text/plain; charset=utf-8",
Connection: "close",
},
body: "Upgrade Required โ the module loader lives at wss://session-server.aesthetic.computer",
};
}
if (event.path === "/favicon.ico") {
return {
statusCode: 302,
headers: {
"Cache-Control": "public, max-age=86400",
"Content-Type": "text/plain; charset=utf-8",
Location: "/purple-pals.svg",
},
body: "",
};
}
if (event.path === "/requestProvider.js.map") {
return {
statusCode: 404,
headers: { "Content-Type": "text/plain; charset=utf-8" },
body: "Not found",
};
}
// Serve system .mjs files directly as static assets
// These get caught by the catch-all redirect but shouldn't go through piece loading
if (event.path.endsWith(".mjs") && !event.path.startsWith("/disks/")) {
try {
// On Netlify, with base="system", files are at /var/task/ (not /var/task/system/)
const baseDir = dev ? process.cwd() : "/var/task";
const filePath = path.join(baseDir, "public/aesthetic.computer", event.path.slice(1));
const content = await fs.readFile(filePath, "utf8");
return {
statusCode: 200,
headers: {
"Content-Type": "application/javascript",
"Cache-Control": "public, max-age=60"
},
body: content,
};
} catch (err) {
console.log(`โก System .mjs file not found: ${event.path}, tried: ${path.join(dev ? process.cwd() : "/var/task", "public/aesthetic.computer", event.path.slice(1))}`);
return { statusCode: 404, body: `File not found: ${event.path}` };
}
}
if (event.headers["host"] === "sotce.local:8888") {
return respond(
302,
'https://localhost:8888/sotce-net',
{
"Content-Type": "text/html",
Location: "https://localhost:8888/sotce-net",
},
);
}
// Serve top.kidlisp.com with dynamic meta tags for social previews / iMessage
// event.path check handles local dev (localhost:8888/top.kidlisp.com via catch-all)
// host header check handles production (top.kidlisp.com domain โ function proxy)
if (event.path.startsWith("/top.kidlisp.com") || event.headers["host"] === "top.kidlisp.com") {
try {
const pathParts = event.path.split("/").filter((p) => p);
// In local dev: pathParts[0] = "top.kidlisp.com", pathParts[1] = "@handle"
// In production: pathParts[0] = "@handle" (event.path is the original request path)
const startsWithDomain = event.path.startsWith("/top.kidlisp.com");
const handleIdx = startsWithDomain ? 1 : 0;
const handle = pathParts[handleIdx]?.startsWith("@") ? pathParts[handleIdx] : null;
const title = handle
? `KidLisp Top 100 ยท ${handle}`
: "KidLisp Top 100";
const desc = handle
? `Top KidLisp pieces by ${handle}`
: "The top 100 KidLisp pieces";
const ogImage = "https://oven.aesthetic.computer/kidlisp-og.png";
const baseUrl = dev ? "http://localhost:8888" : "https://aesthetic.computer";
const res = await fetch(`${baseUrl}/kidlisp.com/device.html`);
if (!res.ok) throw new Error(`fetch device.html: ${res.status}`);
let htmlContent = await res.text();
// Replace title and static OG/Twitter tags with dynamic versions
htmlContent = htmlContent.replace(
/
KidLisp\.com ยท Device<\/title>[\s\S]*?]*\/>/,
`${encode(title)}
`,
);
return {
statusCode: 200,
headers: { "Content-Type": "text/html" },
body: htmlContent,
};
} catch (err) {
console.error("โ Error serving top.kidlisp.com:", err);
return respond(500, "Error loading top.kidlisp.com");
}
}
// Serve calm.kidlisp.com with dynamic meta tags for social previews
if (event.path.startsWith("/calm.kidlisp.com") || event.headers["host"] === "calm.kidlisp.com") {
try {
const title = "KidLisp Calm";
const desc = "A hand-curated selection of calming KidLisp pieces";
const ogImage = "https://oven.aesthetic.computer/kidlisp-og.png";
const baseUrl = dev ? "http://localhost:8888" : "https://aesthetic.computer";
const res = await fetch(`${baseUrl}/kidlisp.com/device.html`);
if (!res.ok) throw new Error(`fetch device.html: ${res.status}`);
let htmlContent = await res.text();
htmlContent = htmlContent.replace(
/KidLisp\.com ยท Device<\/title>[\s\S]*?]*\/>/,
`${encode(title)}
`,
);
return {
statusCode: 200,
headers: { "Content-Type": "text/html" },
body: htmlContent,
};
} catch (err) {
console.error("โ Error serving calm.kidlisp.com:", err);
return respond(500, "Error loading calm.kidlisp.com");
}
}
// Serve keep.kidlisp.com locally
if (event.path.startsWith("/keep.kidlisp.com")) {
try {
let htmlContent = await fs.readFile(
path.join(process.cwd(), "public/kidlisp.com/keeps.html"),
"utf8"
);
if (dev) {
htmlContent = htmlContent.replace("
${encode(title)}
${encode(desc)}
Aesthetic Computer is an open creative computing platform for making art, games, and tools in the browser using JavaScript and KidLisp. Navigate by typing a piece name (e.g. "painting", "line", "wand", "prompt") into the command prompt and pressing Enter. See llms.txt for full documentation: https://aesthetic.computer/llms.txt