Search

Results include substring matches and semantically similar vals. Learn more
sarahxc avatar
convertRelativeDateToString
@sarahxc
An interactive, runnable TypeScript val by sarahxc
HTTP
export async function convertRelativeDateToString({
relativeDate = "0 days ago", // Default search if no query is provided
relativeDate?: string;
all avatar
textStorage
@all
* This program creates a text storage and management application. * It uses Val Town's SQLite for persistence and React for the UI. * The app allows users to add, view, edit, and delete text entries with titles, tags, and categories. * It includes a header with navigation, search bar, filters, a tabbed template page with 100 templates, * a categories section, and a new history tab that logs all edits.
HTTP
timestamp: string;
function App() {
const [texts, setTexts] = useState<TextEntry[]>([]);
</div>
function client() {
createRoot(document.getElementById("root")!).render(<App />);
client();
async function server(request: Request): Promise<Response> {
const { sqlite } = await import("https://esm.town/v/stevekrouse/sqlite");
arfan avatar
FileViewer
@arfan
@jsxImportSource https://esm.sh/react@18.2.0
HTTP
* Main App component that handles file viewing and management
function App() {
const [files, setFiles] = useState([]);
* Initializes the React app on the client side
function client() {
createRoot(document.getElementById("root")).render(<App />);
* @returns {Promise<Response>} The HTML response
export default async function server(request: Request): Promise<Response> {
return new Response(
stevekrouse avatar
compress_response
@stevekrouse
Compress Response Isn't it cool that browsers can natively decompress stuff? There are a couple of supported compression algorithms: gzip (used below), compress , deflate , br . Learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding If you don't add the content-encoding header, the gzip result looks like: ��������� �� �.���� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������YDA��"�� Which is incredibly short for a 500kb string! (Which shouldn't be surprising because it's just "hi" 250k times)
HTTP
import { gzip } from "npm:pako";
export default async function(req: Request): Promise<Response> {
return new Response(await gzip("hi".repeat(250_000)), {
headers: {
ibodev avatar
extractValInfo
@ibodev
Extract vals infos (author, name, version) from a val url (either from esm.town or val.town ). Example usage: const {author, name} = extractValInfo(import.meta.url) Also returns a unique slug for the val: <author>/<name>
Script
export function extractValInfo(url: string | URL) {
const { pathname, search } = new URL(url);
const [author, filename] = pathname.split("/").slice(-2);
vyatka avatar
TodoList
@vyatka
@jsxImportSource https://esm.sh/react@18.2.0
HTTP
function TaskBoard() {
function loadUserPreferences() {
function updateAppStyle(font, size) {
function saveUserPreferences() {
async function fetchTasks() {
async function addNewTask() {
async function handleTaskMove(result) {
async function removeTask(taskId, column) {
async function moveTaskForward(task, currentColumn) {
function toggleDarkMode() {
rwev avatar
handleSavePageForm
@rwev
An interactive, runnable TypeScript val by rwev
HTTP
import { blob } from "https://esm.town/v/std/blob?v=11";
import { email } from "https://esm.town/v/std/email?v=11";
export async function handleSavePageForm(req: Request) {
const formData = await req.formData();
const text = formData.get("text");
mattx avatar
parse_cookies
@mattx
parse_cookies Parses Cookie headers into objects. jar : Value of the Cookie header decoder : Function to run on all cookie names and values. This is to get around character limitations (see RFC 6265 ). There is no formal standard, but as most sites prefer URL encoding, it is the default. x => x can be used as a way to disable decoding.
Script
- `jar`: Value of the Cookie header
- `decoder`: Function to run on all cookie names and values. This is to get around character limitations (see [RFC 6265](http
export function parse_cookies(
jar: String,
decoder: (data: string) => string = decodeURIComponent,
geraldo avatar
tootLatestPosts
@geraldo
Auto-tooting anniversary posts from https://crimenesdeodio.info/ to remember hate crimes in Spain between 1990-2020.
Cron
import { postToMastodon } from "https://esm.town/v/sebdd/postToMastodon";
import { newRSSItems } from "https://esm.town/v/stevekrouse/newRSSItems?v=6";
export async function tootLatestPosts({ lastRunAt }: Interval) {
return Promise.all(
(await newRSSItems({
octref avatar
updateISBNFile
@octref
An interactive, runnable TypeScript val by octref
Script
import { updateGHContent } from "https://esm.town/v/octref/updateGHContent";
import { ghContent } from "https://esm.town/v/octref/ghContent";
export async function updateISBNFile(isbn: string) {
const ISBN_PATH = "data/mine/books-isbn.json";
const content = await ghContent(ISBN_PATH);
willthereader avatar
ThankYouNoteGenerator
@willthereader
An interactive, runnable TypeScript val by willthereader
HTTP
import { createRoot } from "https://esm.sh/react-dom/client";
function ThankYouCard({ note, theme, font, recipientName, senderName }) {
const [firstHalf, secondHalf] = splitNote(note);
</div>
function splitNote(note) {
const words = note.split(" ");
words.slice(midpoint).join(" "),
function capitalizeName(name) {
if (!name) return "";
.join(" ");
function App() {
const [recipientName, setRecipientName] = useState("");
</div>
function client() {
createRoot(document.getElementById("root")).render(<App />);
client();
export default async function server(request: Request): Promise<Response> {
console.log(`Received ${request.method} request to ${request.url}`);
const { OpenAI } = await import("https://esm.town/v/std/openai");
const { sqlite } = await import("https://esm.town/v/stevekrouse/sqlite");
const openai = new OpenAI();
const url = new URL(request.url);
console.log("Generated prompt:", prompt);
const completion = await openai.chat.completions.create({
messages: [{ role: "user", content: prompt }],
hanbzu avatar
uniqBy
@hanbzu
An interactive, runnable TypeScript val by hanbzu
Script
export function uniqBy(array, fn) {
const keys = [];
return array.filter((item) => {
hrbrmstr avatar
cronJobToCheckCISAKEV
@hrbrmstr
Check KEV For New Updates Run a script M-F, 0800-2100, every 10 minutes. If you're on the free tier, dial that back to every 15.
Cron
const KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json";
const BLOB_KEY = "seen_cves";
async function checkNewVulnerabilities() {
const response = await fetch(KEV_URL);
const data = await response.json();
return newCVEs.join("; ");
return "";
export default async function kevCron() {
return await checkNewVulnerabilities();
squirals avatar
pollRSSFeeds
@squirals
Poll RSS feeds This val periodically polls specified RSS feeds and send the author an email with new items. It checks each feed defined in rssFeeds for new content since the last run and sends an email with the details of the new items. Usage Fork @stevekrouse/rssFeeds and update it with your desired RSS feeds; Fork this val and replace the https://esm.town/v/stevekrouse/rssFeeds import with your newly forked val; Enjoy RSS updates on your email!
Cron
import { email } from "https://esm.town/v/std/email?v=9";
import { newRSSItems } from "https://esm.town/v/stevekrouse/newRSSItems";
export async function pollRSSFeeds({ lastRunAt }: Interval) {
return Promise.all(
Object.entries(rssFeeds).map(async ([name, url]) => {
saolsen avatar
gameplay_games
@saolsen
gameplay_games This is a val.town mirror of gameplay/games . Click the link to see docs.
Script
* The type of a game.
* A game is defined by these functions
* @template ARGS The type of the game arguments.
kind: GameKind;
* Function for creating a new game.
* Takes the arguments for creating a new game.
) => [STATE, Status] | ERROR;
* Function for checking if an action is valid.
* Takes the current game state, the player making the action,
) => null | ERROR;
* Function for applying an action to the game state.
* It should mutate the passed in game state.
) => Status | ERROR;
* Function for getting a view of the game state
* for a particular player.