app
Resend Studio
Public Made by Adomby adom
A local editor for Resend email templates: paste your API key, then edit, preview, lint, test-send, and publish templates without Resend's dashboard. Also imports SendGrid dynamic templates and converts their Handlebars to Resend's variable syntax.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
mod cli;
mod convert;
mod output;
mod resend;
mod sendgrid;
mod server;
mod settings;
mod store;
use std::sync::Arc;
use clap::Parser;
use cli::{Cli, Command};
fn main() {
let cli = Cli::parse();
match cli.command {
Command::Serve { port, dev, open_tab } => {
if let Err(e) = serve(port, dev, open_tab) {
output::err(e);
std::process::exit(1);
}
}
Command::Health { port } => health(port),
Command::Install => {
output::ok(format!("adom-resend-studio v{} installed", env!("CARGO_PKG_VERSION")));
}
}
}
fn serve(port: u16, dev: bool, open_tab: bool) -> anyhow::Result<()> {
let dir = settings::data_dir();
let settings = settings::Settings::load(&dir)?;
if settings.resend_key().0.is_none() {
output::hint("No Resend API key yet: open the studio and add one in Settings (or set RESEND_API_KEY).");
}
let db_path = std::env::var("RESEND_STUDIO_DB")
.unwrap_or_else(|_| dir.join("resend-studio.db").display().to_string());
let state = Arc::new(server::AppState::new(dev, port, &db_path, settings)?);
if open_tab {
open_hydrogen_tab(port);
}
server::run(port, state)
}
fn health(port: u16) {
match ureq::get(&format!("http://127.0.0.1:{port}/health")).call() {
Ok(resp) => {
let body: serde_json::Value = resp.into_json().unwrap_or_default();
output::ok(format!(
"adom-resend-studio is reachable on port {port} (version {}).",
body.get("version").and_then(|v| v.as_str()).unwrap_or("unknown")
));
}
Err(e) => {
output::err(format!("Cannot reach adom-resend-studio on port {port}: {e}"));
output::hint(format!("Start it with `adom-resend-studio serve --port {port} &`"));
std::process::exit(1);
}
}
}
/// Opens the app in a NEW Hydrogen pane (split off the first panel) rather
/// than as a tab inside whatever is focused, which is usually the editor.
fn open_hydrogen_tab(port: u16) {
let proxy_url = match std::env::var("VSCODE_PROXY_URI") {
Ok(template) => template.replace("{{port}}", &port.to_string()),
Err(_) => format!("http://127.0.0.1:{port}/"),
};
let icon = server::icon_data_url();
let restart = format!("adom-resend-studio serve --port {port}");
let status = std::process::Command::new("adom-cli")
.args([
"hydrogen",
"webview",
"open-or-refresh",
"--name",
"Resend Studio",
"--url",
&proxy_url,
"--display-icon",
&icon,
"--reason",
"Resend email template editor",
"--restart",
&restart,
])
.status();
match status {
Ok(s) if s.success() => output::ok("opened Resend Studio in a Hydrogen webview tab"),
_ => output::hint(format!("couldn't open the webview tab automatically; open {proxy_url} manually.")),
}
}