příklady / plánované úlohy

Záznamník směnných kurzů

Naplánovaný skript bez webového endpointu: stáhnout, uložit, hotovo.

cronscriptlibsql

Ne všechno potřebuje URL. Tato služba nemá default export, takže přes HTTP nic neservíruje - platforma to pozná a služba prostě žádný veřejný endpoint nemá. Probouzí se jen podle hodinového plánu, stáhne referenční kurzy ECB pro EUR vůči USD, CZK a GBP z bezplatného API Frankfurter a připíše je do své vestavěné databáze.

Plán je jeden řádek kódu (export const crons) a stejná funkce run() napojuje i tlačítko Run, takže první záznam pořídíte hned po nasazení. Řádky sledujte v záložce Database a každé spuštění v záložce Runs.

kód
main.ts
import { createClient } from "npm:@libsql/client@0.14.0/web";

// A scheduled script with NO web endpoint. There is no default export, so this
// service serves nothing over HTTP - it only wakes up to do its job:
//   - the crons export registers an hourly schedule,
//   - each firing runs run() below (so does the Run button in the editor),
//   - results land in the service's built-in database, browsable in the
//     Database tab, with every run visible in the Runs tab.

export const crons = { "fetch-rates": "0 * * * *" };

// Every service gets its own libsql database as DATABASE_URL, no setup needed.
const db = createClient({ url: Deno.env.get("DATABASE_URL")! });

async function ensureSchema(): Promise<void> {
  await db.execute(
    `CREATE TABLE IF NOT EXISTS rates (
       id      INTEGER PRIMARY KEY AUTOINCREMENT,
       base    TEXT NOT NULL,
       symbol  TEXT NOT NULL,
       rate    REAL NOT NULL,
       day     TEXT NOT NULL,
       seen_at TEXT NOT NULL DEFAULT (datetime('now'))
     )`,
  );
}

// Frankfurter is a free, keyless exchange-rate API published by the ECB.
export async function run(): Promise<string> {
  await ensureSchema();
  const res = await fetch("https://api.frankfurter.app/latest?from=EUR&to=USD,CZK,GBP");
  if (!res.ok) {
    console.error(`rate fetch failed: HTTP ${res.status}`);
    return `rate fetch failed: HTTP ${res.status}`;
  }
  const data = (await res.json()) as { date: string; rates: Record<string, number> };
  for (const [symbol, rate] of Object.entries(data.rates)) {
    await db.execute({
      sql: "INSERT INTO rates (base, symbol, rate, day) VALUES (?, ?, ?, ?)",
      args: ["EUR", symbol, rate, data.date],
    });
    console.log(`EUR/${symbol} = ${rate}`);
  }
  return `recorded ${Object.keys(data.rates).length} rates for ${data.date}`;
}

Go beyond what seems possible.