A scheduled script with no web endpoint: fetch, store, done.
Not everything needs a URL. This service has no default export, so it serves nothing over HTTP - the platform detects that and the service simply has no public endpoint. It only wakes up on its hourly schedule, fetches the ECB reference rates for EUR against USD, CZK and GBP from the free Frankfurter API, and appends them to its built-in database.
The schedule is one line of code (export const crons), and the same run() function also powers the Run button, so you can record a data point the moment you deploy. Watch the rows arrive in the Database tab and every execution in the Runs tab.
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.