Public vals
18
zackoverflow
minizod
Script
minizod Tiny Zod implementation. Why Zod is a dense library, and its module structure (or lack thereof) makes it difficult for bundlers to tree-shake unused modules . Additionally, using Zod in vals requires the await import syntax which means having to wrap every schema in a Promise and awaiting it. This is extremely annoying. So this is a lil-tiny-smol Zod meant for use in vals. A noteworthy use-case is using minizod to generate tyep-safe API calls to run vals outside of Val Town (such as client-side). Type-safe API call example We can use minizod to create type safe HTTP handlers and generate the corresponding code to call them using Val Town's API, all in a type-safe manner. First, create a schema for a function. The following example defines a schema for a function that takes a { name: string } parameter and returns a Promise<{ text: string }> . const minizodExampleSchema = () =>
@zackoverflow.minizod().chain((z) =>
z
.func()
.args(z.tuple().item(z.object({ name: z.string() })))
.ret(z.promise().return(z.object({ text: z.string() })))
); With a function schema, you can then create an implementation and export it as a val: const minizodExample = @me.minizodExampleSchema().impl(async (
{ name },
) => ({ text: `Hello, ${name}!` })).json() In the above example, we call .impl() on a function schema and pass in a closure which implements the actual body of the function. Here, we simply return a greeting to the name passed in. We can call this val, and it will automatically parse and validate the args we give it: // Errors at compile time and runtime for us!
const response = @me.minizodExample({ name: 420 }) Alternatively, we can use the .json() function to use it as a JSON HTTP handler: const minizodExample = @me.minizodExampleSchema().impl(async (
{ name },
) => ({ text: `Hello, ${name}!` })).json() // <-- this part We can now call minizodExample through Val Town's API. Since we defined a schema for it, we know exactly the types of its arguments and return, which means we can generate type-safe code to call the API: let generatedApiCode =
@zackoverflow.minizodFunctionGenerateTypescript(
// put your username here
"zackoverflow",
"minizodExample",
// put your auth token here
"my auth token",
@me.minizodExampleSchema(),
); This generates the following the code: export const fetchMinizodExample = async (
...args: [{ name: string }]
): Promise<Awaited<Promise<{ text: string }>>> =>
await fetch(`https://api.val.town/v1/run/zackoverflow.minizodExample`, {
method: "POST",
body: JSON.stringify({
args: [...args],
}),
headers: {
Authorization: "Bearer ksafajslfkjal;kjf;laksjl;fajsdf",
},
}).then((res) => res.json());
5
zackoverflow
pollRssAndEmail
Script
Subscribe to RSS feeds with e-mail notifications This lets you subscribe to RSS feeds. It checks periodically for any new posts from any of your RSS feed subscriptions, and then sends you an e-mail with the link to the any new posts. Getting started 1. Generate auth keys Follow this to get your auth keys, and export your public keys. This will be used to e-mail yourself since @std.email is preferred over console.email 2. Create a @me.rssEmail val You can do that by clicking this link and hitting 'Run'. Or you can copy-paste this code into a new val: const rssEmail = "you@youremail.com" 3. Fork this val Hit 'Fork' on this val and run it. Then you can schedule the val to run every hour or whatever duration you'd like. 4. Add RSS feeds to @me.rssFeeds If you look at your vals, you should find a new one called rssFeeds . It should look similar to this: let rssFeeds = [
"https://cprimozic.net/rss.xml",
"https://matklad.github.io/feed.xml",
"https://journal.stuffwithstuff.com/rss.xml",
"https://lexi-lambda.github.io/feeds/all.rss.xml",
]; This is supposed to be an array containing the links of each RSS feed you'd like to subscribe to (in the form of JS strings). To add RSS feeds, you can update this val by adding a new string containing the new RSS link. Resetting the cache If for any reason you would like to reset the cache, you can clear the keys of rssCache or use this convenience function to do so. @zackoverflow.rssResetCache(@me.rssCache)
2
zackoverflow
lisp
Script
Lispaas (lisp as a service) A mini lisp interpreter How to use: To execute code: const result = @zackoverflow.lisp(" (+ 1 2)") To just parse and return the AST: const ast = @zackoverflow.lisp("(+ 1 2)", true) The value returned is the last expression of the program, for example: const lispResult = @zackoverflow.lisp("(+ 1 2) (+ 400 20)")
console.log('Val', lispResult.val === 420) Example: Compute Fibonacci sequence let result = @zackoverflow.lisp(`
(defun fib (x)
(if (<= x 1)
x
(defun impl (i n-1 n-2)
(if (= x i)
(+ n-1 n-2)
(impl (+ i 1) (+ n-1 n-2) n-1)))
(impl 2 1 0)))
(assert-eq 0 (fib 0))
(assert-eq 1 (fib 1))
(assert-eq 1 (fib 2))
(assert-eq 2 (fib 3))
(assert-eq 3 (fib 4))
(assert-eq 5 (fib 5))
(assert-eq 8 (fib 6))
(assert-eq 13 (fib 7))
`); Documentation Functions You can define a function like so: (defun hello (x) (print x)) Rest/variadic arguments are also supported (defun variable-amount-of-args (...args) (print args))
(variable-amount-of-args "Hello" "World!") Lists Define a list like so: (let ((my-list (list 1 2 3 4)))
(print my-list)
(print (list-get my-list 1))) Internally, a list is just a Javascript array. So indexing is O(1), but that does mean cdr requires copying (vs the linked list implementation). Plists Property lists, or records. Internally these are Javascript objects. Create a plist like so: (set null :key "Value") TODO
2