Mini apps
Server code
Keep your app's logic, private data and rules on the server with server.js — code that runs on Rudder.chat's servers and is never sent to the browser.
Server code
Everything in your app's page — index.html and the scripts and styles it loads — is sent to the browser of every person who opens it, and anyone can read it there. That is how every web page works.
server.js is different. It sits at the top of your app's folder, runs on Rudder.chat's servers, and is never sent to anyone. Only what its functions return leaves the server. Put there whatever is the value of your app or must not be seen or changed by the people using it:
- the app's rules and scoring, and anything a player must not be able to fake;
- answers, solutions and hidden game state;
- prices, formulas and other logic that took you work;
- the questions your app asks the AI, and what it does with the answers;
- calls to other services on the internet.
What needs no protecting — drawing the screen, animations, talking to the AI with th.chat.send — stays in the page.
Write a function
server.js is a JavaScript module. Each function the page can call is exported:
// server.js
export async function checkAnswer(args, ctx) {
const found = await ctx.db.list("$answers", { where: { question: args.question } });
const right = found.items.length > 0 && found.items[0].value.answer === args.answer;
if (right) await ctx.db.add("scores", { player: ctx.user.id, points: 10 });
return { right };
}
Call it from the page
const { right } = await th.server.call("checkAnswer", { question: "q1", answer: "Paris" });
args and what the function returns are JSON. When the function throws, th.server.call rejects with an Error carrying the same message — say why in your message, and the page can show it.
What a function gets
args | What the page sent. Never trust it to say who is asking. |
ctx.user.id | The caller's id in your app — the same id th.ready() gives the page. This one comes from Rudder.chat, so it can be trusted. |
ctx.user.builder | true for you and the people building the app with you. |
ctx.db | Your app's database, as the app's server: add, get, list, count, update, remove, the same as th.db. |
ctx.ai | The AI, asked from the server: await ctx.ai({ text, system, json }) → { text, json }. See below. |
fetch | The internet, as in any JavaScript server. |
Asking the AI from the server
export async function judge(args, ctx) {
const { json } = await ctx.ai({
system: "You judge riddle answers. Reply {\"right\": true|false}.",
text: `Riddle: ${args.riddle}\nAnswer: ${args.answer}`,
json: true,
});
return { right: json?.right === true };
}
What you ask and what comes back pass between Rudder.chat's servers only — the page sees only what your function returns. system is optional: without it the AI follows your app's instructions. With json: true the reply comes back read in json (null if it was not JSON). It is free for your app, like th.chat.send, and counted against the person using the app: up to 30 questions a minute each, and 300 a minute for the whole app. Text up to 32,000 characters. Pictures and files are sent with th.chat.send from the page.
Private data
A collection whose name starts with $ — $answers, $deck, $rules — is read and written only by server.js. The page cannot read it with th.db, even yours.
A collection whose name starts with @ — @board, @firsts — is read by everyone and written only by server.js. Nobody using the app can add to it, change it or remove from it, not even you from the page. Put there whatever must be true for everyone: a leaderboard written after checking the score, the first person to make something, results everyone shares. The page reads and watches it with th.db as usual. A record's mine is never true there (server.js wrote it): store the person's id (ctx.user.id) in the record and compare it with the id th.ready() gives the page.
Test and live
While you build, your preview runs the server code you are working on, with the app's test data. Once the app is approved and published, people using it run the published server code, with its live data. Publishing reviews server.js with the rest of the app.
Limits
- One file, at most 200 KB. No
importof other files and no npm packages: write what you need in the file. - Per call: 100 ms of computing, 20 requests to the internet, 30 seconds in all; 64 KB sent to it and 1 MB returned.
- Up to 120 calls a minute per person.
server.jsfollows the same rules as the rest of the app: it may not send people's data elsewhere, attack or spam other sites, or do work that has nothing to do with the app.