Avatar

zarutian

Val Town status: Currently migrating unused and older versions of my vals to Github Gists. Other status: working on an open source project.
6 public vals
Joined January 1, 2023
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { fetch } from "https://esm.town/v/std/fetch";
import { fetchText } from "https://esm.town/v/stevekrouse/fetchText?v=5";
export const ocaps_ink = async (req, res) => {
try {
const valvers = 200;
const [ink_js_src, story_ink, visitors_info_txt] = await Promise.all([
fetchText(
// "https://raw.githubusercontent.com/y-lohse/inkjs/master/templates/browser_serverless/ink.js",
"https://unpkg.com/inkjs@2.2.1/dist/ink-full.js",
),
fetchText(
"https://gist.githubusercontent.com/zarutian/ec15de4eb4780ae6e6c8f7ad1d2d49f6/raw/ocaps.ink",
{
cache: "no-store",
},
),
fetchText(
"https://zarutian-ocaps_ink_visitors.express.val.run",
{
cache: "no-store",
},
),
]);
const mainForBrowser_src = (() => {
var _inkStory;
var errorHandlerForAll;
var load_save;
var localStorage;
var storyContainer;
var save;
var wipe_save;
var document;
var URL;
var window;
var isAnimationEnabled;
var showAfter;
var setTimeout;
var scrollToBottom;
var requestAnimationFrame;
var continueStory;
var inkjs;
var story_version;
var prompt;
const mainForBrowser = () => {
load_save = () => {
const save_json = localStorage.getItem("ocaps_ink_story_save");
// var save_json = null;
// const t1 = document.location.hash;
// if (t1 != "") {
// save_json = decodeURIComponent(t1);
// }
if (save_json != null) {
_inkStory.state.LoadJson(save_json);
const txtSoFar = localStorage.getItem("ocaps_ink_story_text");
// const txtSoFar = JSON.parse(save_json).txtSoFar;
if (
(txtSoFar != undefined) && (txtSoFar != "") && (txtSoFar != null)
) {
storyContainer.innerHTML = txtSoFar;
var delay = 0.0;
storyContainer.querySelectorAll("p").forEach((c) => {
showAfter(delay, c);
delay += 50.0;
});
storyContainer.querySelectorAll("p.choice").forEach((c) => {
c.parentNode.removeChild(c);
});
}
}
};
save = () => {
const save_json = _inkStory.state.ToJson();
// var save_obj = JSON.parse(ink_save_json);
// save_obj.
const txtSoFar = storyContainer.innerHTML;
// const save_json = JSON.stringify(save_obj);
document.getElementById("save_json").innerText = save_json;
document.getElementById("save_text").innerText = txtSoFar;
localStorage.setItem("ocaps_ink_story_save", save_json);
localStorage.setItem("ocaps_ink_story_text", txtSoFar);
// document.location.hash = encodeURIComponent(save_json);
};
wipe_save = () => {
localStorage.removeItem("ocaps_ink_story_save");
localStorage.removeItem("ocaps_ink_story_text");
// document.location.hash = "";
};
document.getElementById("restart").addEventListener(
"click",
(event) => {
try {
event.preventDefault();
wipe_save();
const t1 = new URL(document.location);
const t2 = t1.searchParams.get("restarts");
const t3 = (t2 == null) ? "0" : t2;
const t4 = parseInt(t3, 10) + 1;
t1.search = "?".concat(
"restarts=",
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// @ts-check js
import { fetchText } from "https://esm.town/v/stevekrouse/fetchText?v=5";
/*
* @param {express.Request} req
* @param {express.Response} res
* @return {void}
*/
export const gardland = async (req, res) => {
const page = {};
page["heroimg"] = await fetchText(
"https://gist.githubusercontent.com/zarutian/f48745853a6ebf4819038a88e180efb0/raw/9de6ffc5b2e5814f9ed1ce46ac15de9919ce5286/gardland_data.txt",
);
page["index.html"] = "".concat(
'<html lang="is">',
"<head>",
"<title>Garðland 24B</title>",
'<meta charset="utf-8"/>',
'<link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGwAAABsCAMAAAC4uKf/AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAACKFBMVEVHcExWjhJhpQ5mrBFjpRRajx5hpBBmrBB5q0BprxRiliZUlAhjqgxjqg1XlwprpyVZmwlprx
"</head>",
"<body>",
'<img src="',
page["heroimg"],
'" />',
"<pre>\n",
"Garðland 24B.\n",
"----- 2023-07-29T17:50:00 -----\n",
"Fór niður í kartöflugarð og ætlaði að bera blákorn á en vegna magns\n",
"illgresis og arfa þá reitti ég frekar en að bera á. Þegar það var búið\n",
"þá orkaði ég bara að vökva. Sé til með á mánudeginum hvort ég hef orku í að bera á.\n",
"-Zarutian\n",
"\n",
"----- 2023-07-21T14:15:00 -----\n",
"Hafði ekkert litið á garðinn í rúma viku vegna hálsbólguveikinda.\n",
"Við mæðgin fórum og athuguðum og þurfti að vökva sem var lítið verk og fljótt afgreitt.\n",
"Þurfti ekki einu sinni að fara í verkfærakistuna til að ná í framlenginarslöngubút.\n",
"En það þarf verulega að reita arfa og illgresi, sé til um helgina hversu frískur ég verði þá.\n",
"-Zarutian\n",
"\n",
"----- 2023-07-17T16:05:00 -----\n",
"Reitti arfa og illgresi frá kartöflugrösum í dag.\n",
"Þurfti að vökva almennilega í fyrsta skipti síðastliðinn þriðjudag.\n",
"Lýtur út fyrir að þessi gullrótartilrun hafi algerlega farið forgörðum.\n",
"-Zarutian\n",
"\n",
"----- 2023-06-27T16:13:00 -----\n",
"Hafði tekið QR-kóðadæmið til baka þar sem vatn hafði komist inn í plastumslagið og límbandið sem hélt því á skiltisstakun hafði gefið sig.\n",
"Það var um síðustu helgi. Þurfti hvort sem er að skipta því út því að e-r nýtti sér SameOriginPolicy veikleikann í api.val.town.\n",
"Leit á kartöflugrösin í dag og reitt frá sumum þeirra arfa sem var orðin of ágengur.\n",
"Þessi grös virðast dafna bara fjandi vel verð ég bara að segja.\n",
"Gulrótardæmið er bara búið að drukna í illgresi ef það kom e-ð af þeim upp.\n",
"-Zarutian\n",
"\n",
"----- 2023-06-20T14:44:00 -----\n",
"Athugaði með QR-kóðadæmið í gær og það er í fínu lagi.\n",
"Kartöflugrösin spretta og eiginlega öll komin upp.\n",
"Mér sýnist að það sé bara arfi og illgresi þar sem ég sáði\n",
"gulrótunum en ég ætla að leyfa þeirri röð að vera allveg í friði.\n",
"-Zarutian\n",
"\n",
"----- 2023-06-18T18:00:00 -----\n",
"Tja það er allaveganna nægileg rigning og þessi raða aðferð mín hefur komið í veg fyrir að kartöflugrösin drukni hingað til.\n",
"Athuga á mánudeginum hvernig QR-kóða hattinum á garðholunúmerskiltinu reiðir af.\n",
"-Zarutian\n",
"\n",
"----- 2023-06-17T13:00:00 -----\n",
"Gleðilega sautjánda júní!\n",
"Loftraki þægilega hár og því held ég að plöntunar spjari sig.\n",
"Athuga með á morgun ef það verður e-r úrkoma.\n",
"-Zarutian\n",
"\n",
"----- 2023-06-16T15:54:23 -----\n",
"Fór og reitti illgresi frá þeim kartöflugrasaknoppum sem voru komnir upp í svo handspannar þvermál í kringum þá.\n",
"Þeir voru all fleiri en í gær.\n",
"Sá að topp centimetra lagið var frekar þurrt svo ég vætti í öllum röðunum með einni og hálfri stórri garðkönnu af vatni.\n",
"Þessi gulrótartilraun gæti verið farinn út um þúfur en ég ætla að gefa þeim séns.\n",
"Ef það verður knasþurrt á þjóðhátíðardaginn þá kem ég með garðslönguna.\n",
"-Zarutian\n",
"\n",
"----- 2023-06-15T16:00:00 -----\n",
"Sá fyrstu kartöflugrösin pota sínu littlu kímblaðaknoppum upp í dag!\n",
"Býst við að sjá meira af þeim á morgun.\n",
"Enn bólar ekkert á gulrótarplöntunum.\n",
"-Zarutian\n",
"\n",
"----- 2023-06-06T16:05:00 -----\n",
"Ekkert ennþá komið upp, allaveganna af kartöflugrösum sem er skiljanlegt.\n",
"En ég veit eigi með gulrótarplöntunar því ég þekki ekki kímblöð þeirra.\n",
"Kemur í ljós í næstu viku kanske.\n",
"-Zarutian\n",
"\n",
"----- 2023-06-05T10:00:00 -----\n",
"Hér er ég að rækta Helga Gullauga í sex beðum fjær skikaskiltinu\n",
"og tvær tegundir af gulrótum í sjöunda beðinu næst áðurnefndu skilti.\n",
"Gulrótunum var sáð síðasta föstudeginum í maí.\n",
"Kartöflunar voru settar niður þann 3. júní síðastliðinn.\n",
"\n",
"Síða enn í vinnslu...\n",
"-Zarutian\n",
"</pre>",

RPC

Turn any function into an API! This lets you call a function in Val Town without manually handling a Request or Response object.

This val can be used as a replacement for the Run API, which implicitly did something similar.

Create an API from your function:

This is how you can expose a function as an API:

  1. Create an HTTP handler val
  2. Import this val
  3. Call rpc with your function as an argument

Here's an example from @std/rpc_example:

Create valimport { rpc } from "https://esm.town/v/std/rpc?v=6"; export const rpc_example = rpc(async (a: number, b: number) => { return a + b; });

And here is how you do it for one of your already existing private val, say floobie,

Create valimport { rpc } from "https://esm.town/v/std/rpc?v=6"; import { floobie } from "https://esm.town/v/stevekrouse/floobie"; export const rpced_floobie = rpc(floobie, true);

Send a request to your val

You can invoke that function from your client or your local machine with an HTTP request. You can either use a GET or a POST request, passing arguments in the query parameters or the body respectively. Make sure your val's privacy is set to Unlisted or Public.

GET request

Create valconst res = await fetch("https://std-rpc_example.web.val.run/?args=[2,3]"); console.log(await res.json()); // 5

POST request

Create valconst res = await fetch("https://std-rpc_example.web.val.run/", { method: "POST", body: JSON.stringify({ args: [2, 3] }) }); console.log(await res.json()); // 5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { parseRPCArgs } from "https://esm.town/v/std/parseRPCArgs";
const VALTOWN_TOKEN = Deno.env.get("valtown");
export function rpc(fn: Function, isPrivate: boolean = false) {
return async (req: Request): Promise<Response> => {
if (isPrivate) {
if (req.headers.get("Authorization") != `Bearer ${VALTOWN_TOKEN}`) {
return Response.json("Unauthorized", {
status: 401,
statusText: "unauthorized, val is private"
})
}
}
try {
const args = await parseRPCArgs(req);
const result = await fn.apply(null, args);
return Response.json(result);
} catch (e) {
if (e instanceof Response) {
return e;
}
console.error(e);
return Response.json("Error", { status: 500 });
}
};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export const postponeForTime = async (delay, func, ...args) => {
return new Promise(
(resolve, reject) => {
setTimeout(() => {
try {
resolve(func(...args));
} catch (err) {
reject(err);
}
}, delay);
},
);
};
export default {
postponeForTime,
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// @ts-check
import { API_URL } from "https://esm.town/v/std/API_URL";
const VALTOWN_API_URL = API_URL.concat("/v1");
// const VALTOWN_API_URL = "https://api.val.town/v1";
/**
* @returns {Promise<string>} the uuid of the user as an string
**/
export const getMyValTownUserUUID = async () => {
return (await (await fetch(`${VALTOWN_API_URL}/me`, {
headers: {
Authorization: `Bearer ${Deno.env.get("valtown")}`,
Accept: "application/json",
},
})).json()).id;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// @ts-check js
import { API_URL } from "https://esm.town/v/std/API_URL";
const VALTOWN_API_URL = API_URL.concat("/v1");
import { getMyValTownUserUUID } from "https://esm.town/v/zarutian/getMyValTownUserUUID";
import { getAllValsOfUser } from "https://esm.town/v/zarutian/getAllValsOfUser";
import { blob } from "https://esm.town/v/std/blob";
const add = (a, b) => (a + b);
/**
* @param {string=} prefix - prefix of blob keys
* @returns {Promise<number>} - how many bytes used by those blobs
**/
export const getAllUsedByBlobs = async (prefix = "") => {
return (await blob.list(prefix)).map((item) => item.size).reduce(add, 0);
};
/**
* @callback privacyCallbackFilterFn
* @param {"private" | "unlisted" | "public"} kind
* @returns {boolean}
**/
/**
* @param {string=} prefix - prefix of val names
* @param {privacyCallbackFilterFn=} privacyCallbackFn
* @returns {Promise<number>} - how many bytes used by those vals
**/
export const getAllUsedByVals = async (prefix = "", privacyCallbackFn = (_) => true) => {
const myUserUUID = await getMyValTownUserUUID();
const allMyVals = await getAllValsOfUser(myUserUUID);
return allMyVals.filter(
(item) => (privacyCallbackFn(item.privacy) && item.name.startsWith(prefix))
).map((item) => (item.code.length)).reduce(add, 0);
};
/**
* @returns {Promise<number>}
**/
export const getAllUsed = async () => {
return (await Promise.all([
getAllUsedByBlobs(),
getAllUsedByVals(),
])).reduce(add, 0);
};
Next