diff --git a/system/netlify/functions/index.mjs b/system/netlify/functions/index.mjs index 554e2a8bcd..18cad743a6 100644 --- a/system/netlify/functions/index.mjs +++ b/system/netlify/functions/index.mjs @@ -7,20 +7,22 @@ import { URLSearchParams } 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 { 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"; +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 { 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}$/; // Fire-and-forget piece hit tracking (don't await, don't block page load) -async function trackPieceHit(piece, type) { +async function trackPieceHit(piece, type) { try { const baseUrl = dev ? "https://localhost:8888" : "https://aesthetic.computer"; const { got } = await import("got"); @@ -35,7 +37,39 @@ async function trackPieceHit(piece, type) { // Silent fail - don't let tracking break page loads 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(); @@ -728,7 +762,7 @@ async function fun(event, context) { } } } - } else if (parsed.source) { + } else if (parsed.source) { // Handle inline kidlisp code that doesn't need file loading console.log("[kidlisp] Using inline kidlisp source for metadata"); @@ -745,9 +779,14 @@ async function fun(event, context) { if (title) { meta = { ...meta, title, standaloneTitle: true }; } - } - } - } catch (err) { + } + } + + if (statusCode === 404 && !sourceCode && !fromHandle && await findBareKidlispCode(slug)) { + console.log(`[kidlisp] Converting bare /${slug} to /$${slug} and redirecting`); + return redirectToKidlispCode(event, slug); + } + } catch (err) { // If either module doesn't load, then we can fallback to the main route. console.log("🔴 Error loading module:", err, sourceCode); return redirect; diff --git a/system/public/aesthetic.computer/disks/prompt.mjs b/system/public/aesthetic.computer/disks/prompt.mjs index 21337ef2a5..9a1c99998e 100644 --- a/system/public/aesthetic.computer/disks/prompt.mjs +++ b/system/public/aesthetic.computer/disks/prompt.mjs @@ -79,6 +79,7 @@ const forgetful = true; const TYPO_REPLY = ` Use Aesthetic Computer by entering a correct word.\n\nEnter "list" for some available words.\n\nEnter "chat" for help.\n\nText 1-508-728-4043 for tips.\n\n - @jeffrey`.trim(); +const BARE_KIDLISP_CODE = /^[0-9A-Za-z]{3,64}$/; import { Android, MetaBrowser, iOS } from "../lib/platform.mjs"; import { validateHandle } from "../lib/text.mjs"; @@ -4140,6 +4141,11 @@ async function halt($, text) { } else { body = parse(trimmed); loaded = await load(body); // Execute the current command. + + // Bare code fallback: let `duv` resolve to `$duv` when no disk named `duv` exists. + if (!loaded && BARE_KIDLISP_CODE.test(trimmed) && !trimmed.startsWith("$")) { + loaded = await load(parse(`$${trimmed}`)); + } } // console.log("Loaded:", loaded);