chore: modernize setup, dependencies, and project docs

This commit is contained in:
Young Lee
2026-02-05 22:34:13 -08:00
parent 6e546d31a0
commit daf54a0fc0
10 changed files with 476 additions and 420 deletions
+112 -139
View File
@@ -1,29 +1,34 @@
#!/bin/bash
#!/usr/bin/env bash
# Email to RSS setup script
set -euo pipefail
echo "🚀 Setting up Email to RSS service..."
# Check if npm and npx are installed
if ! command -v npm &> /dev/null || ! command -v npx &> /dev/null; then
echo "❌ Error: npm and npx are required but not found."
echo "Please install Node.js from https://nodejs.org/en/download/"
if ! command -v npm >/dev/null 2>&1 || ! command -v npx >/dev/null 2>&1 || ! command -v node >/dev/null 2>&1; then
echo "❌ Error: Node.js (with npm and npx) is required but not found."
echo "Install Node.js from https://nodejs.org/en/download/ and run setup again."
exit 1
fi
# Check if wrangler-example.toml exists early
if [ ! -f "wrangler-example.toml" ]; then
echo "❌ Error: wrangler-example.toml not found."
exit 1
fi
# Install dependencies
WORKER_NAME="$(grep -E '^name = "' wrangler-example.toml | head -1 | cut -d'"' -f2)"
if [ -z "$WORKER_NAME" ]; then
WORKER_NAME="email-to-rss"
fi
echo "📦 Installing dependencies..."
npm install
# Check if user is logged in to Cloudflare
echo "🔒 Checking Cloudflare authentication..."
if ! npx wrangler whoami &>/dev/null; then
set +e
WHOAMI_OUTPUT="$(npx wrangler whoami 2>&1)"
WHOAMI_STATUS=$?
set -e
if [ "$WHOAMI_STATUS" -ne 0 ] || echo "$WHOAMI_OUTPUT" | grep -qi "not authenticated"; then
echo "❌ You are not logged in to Cloudflare. Please run:"
echo "npx wrangler login"
echo "After login completes, run this setup script again."
@@ -31,162 +36,130 @@ if ! npx wrangler whoami &>/dev/null; then
fi
echo "✅ Cloudflare authentication verified"
# Function to get KV namespace IDs
extract_namespace_ids_from_json() {
local worker_name="$1"
node - "$worker_name" <<'NODE'
const fs = require("node:fs");
const workerName = process.argv[2];
let namespaces;
try {
namespaces = JSON.parse(fs.readFileSync(0, "utf8"));
} catch {
process.exit(0);
}
if (!Array.isArray(namespaces)) {
process.exit(0);
}
const findByTitle = (title) => {
const match = namespaces.find((namespace) => namespace?.title === title && typeof namespace?.id === "string");
return match?.id ?? "";
};
const mainId = findByTitle(`${workerName}-EMAIL_STORAGE`);
const previewId = findByTitle(`${workerName}-EMAIL_STORAGE_preview`);
process.stdout.write(`${mainId}\n${previewId}`);
NODE
}
get_kv_namespace_ids() {
echo " Retrieving KV namespace IDs..."
# Get the complete KV namespace list
echo "🔍 Retrieving KV namespace IDs..."
local output
output=$(npx wrangler kv:namespace list 2>/dev/null)
if [ $? -ne 0 ]; then
if ! output="$(npx wrangler kv namespace list --json 2>/dev/null)"; then
echo "❌ Error listing KV namespaces. Please check your Cloudflare authentication."
return 1
fi
# Try the direct approach first (most reliable)
MAIN_ID=$(echo "$output" | grep -o '"id": *"[^"]*"' | head -1 | cut -d'"' -f4)
PREVIEW_ID=$(echo "$output" | grep -o '"id": *"[^"]*"' | head -2 | tail -1 | cut -d'"' -f4)
# If the direct approach failed, try to match by namespace title
local ids
ids="$(printf '%s' "$output" | extract_namespace_ids_from_json "$WORKER_NAME")"
MAIN_ID="$(printf '%s\n' "$ids" | sed -n '1p')"
PREVIEW_ID="$(printf '%s\n' "$ids" | sed -n '2p')"
if [ -z "$MAIN_ID" ] || [ -z "$PREVIEW_ID" ]; then
# Save the output to a file for more complex processing
local temp_file=$(mktemp)
echo "$output" > "$temp_file"
# Try with different patterns
if [ -z "$MAIN_ID" ]; then
MAIN_ID=$(grep -A3 "email-to-rss-EMAIL_STORAGE\"" "$temp_file" | grep -o '"id": "[^"]*"' | head -1 | cut -d'"' -f4)
if [ -z "$MAIN_ID" ]; then
MAIN_ID=$(grep -A3 "email-to-rss-EMAIL_STORAGE\"" "$temp_file" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
fi
fi
if [ -z "$PREVIEW_ID" ]; then
PREVIEW_ID=$(grep -A3 "email-to-rss-EMAIL_STORAGE_preview\"" "$temp_file" | grep -o '"id": "[^"]*"' | head -1 | cut -d'"' -f4)
if [ -z "$PREVIEW_ID" ]; then
PREVIEW_ID=$(grep -A3 "email-to-rss-EMAIL_STORAGE_preview\"" "$temp_file" | grep -o '"id":"[^"]*"' | head -1 | cut -d'"' -f4)
fi
fi
# Clean up
rm -f "$temp_file"
MAIN_ID="$(echo "$output" | grep -o '"id": *"[^"]*"' | head -1 | cut -d'"' -f4)"
PREVIEW_ID="$(echo "$output" | grep -o '"id": *"[^"]*"' | head -2 | tail -1 | cut -d'"' -f4)"
fi
# Check if we found both IDs
if [ -z "$MAIN_ID" ] || [ -z "$PREVIEW_ID" ]; then
echo "❌ Failed to extract KV namespace IDs. Please run manually:"
echo "npx wrangler kv:namespace list"
echo "npx wrangler kv namespace list"
echo "And update the IDs in wrangler.toml"
return 1
fi
return 0
}
# Create KV namespaces (suppressing output)
echo "🗄️ Creating KV namespaces..."
npx wrangler kv:namespace create EMAIL_STORAGE > /dev/null 2>&1 || true
npx wrangler kv:namespace create EMAIL_STORAGE --preview > /dev/null 2>&1 || true
npx wrangler kv namespace create EMAIL_STORAGE >/dev/null 2>&1 || true
npx wrangler kv namespace create EMAIL_STORAGE --preview >/dev/null 2>&1 || true
# Get KV namespace IDs
get_kv_namespace_ids
if [ $? -ne 0 ]; then
echo "⚠️ Will continue without KV namespace IDs"
KV_ID=""
KV_PREVIEW_ID=""
else
KV_ID="$MAIN_ID"
KV_PREVIEW_ID="$PREVIEW_ID"
fi
# Summarize KV namespace status
echo "📊 KV Namespace Status:"
if [ -z "$KV_ID" ]; then
echo " ❌ Main KV namespace ID: Not found"
SETUP_SUCCESS=false
else
echo " ✅ Main KV namespace ID: $KV_ID"
SETUP_SUCCESS=true
fi
if [ -z "$KV_PREVIEW_ID" ]; then
echo " ❌ Preview KV namespace ID: Not found"
SETUP_SUCCESS=false
else
echo " ✅ Preview KV namespace ID: $KV_PREVIEW_ID"
fi
# Set up admin password
echo "🔐 Setting up admin password..."
read -p "Enter admin password: " admin_password
echo "Setting admin password for production environment..."
# Initialize SETUP_SUCCESS if not already set
if [ -z "$SETUP_SUCCESS" ]; then
SETUP_SUCCESS=true
fi
# Try to set the secret without redirecting stderr to see any errors
if [ -z "$admin_password" ]; then
echo "⚠️ No admin password provided. Skipping secret creation."
else
# Run the command and capture its output
SECRET_OUTPUT=$(echo "$admin_password" | npx wrangler secret put ADMIN_PASSWORD --env production --name email-to-rss 2>&1)
SECRET_STATUS=$?
if [ $SECRET_STATUS -ne 0 ]; then
echo "⚠️ Failed to set admin password for production environment"
echo "Error: $SECRET_OUTPUT"
SETUP_SUCCESS=false
else
echo "✅ Admin password set for production environment"
fi
fi
# Prompt for domain
read -p "Enter your domain (e.g., yourdomain.com): " domain
if [ -z "$domain" ]; then
echo "❌ No domain provided. Cannot continue."
SETUP_SUCCESS=false
else
echo "✅ Domain: $domain"
fi
# Create and update wrangler.toml only if everything is successful
if [ "$SETUP_SUCCESS" = false ]; then
echo "⚠️ Some parts of the setup failed. Will not create wrangler.toml."
echo "Please fix the issues and run the script again."
if ! get_kv_namespace_ids; then
echo "❌ Setup cannot continue without KV namespace IDs."
exit 1
fi
# Create and configure wrangler.toml
echo "📊 KV Namespace Status:"
echo " ✅ Main KV namespace ID: $MAIN_ID"
echo " ✅ Preview KV namespace ID: $PREVIEW_ID"
echo "🔐 Setting up admin password..."
read -r -p "Enter admin password: " admin_password
if [ -z "$admin_password" ]; then
echo "❌ No admin password provided."
exit 1
fi
set +e
SECRET_OUTPUT="$(printf '%s' "$admin_password" | npx wrangler secret put ADMIN_PASSWORD --env production --name "$WORKER_NAME" 2>&1)"
SECRET_STATUS=$?
set -e
if [ "$SECRET_STATUS" -ne 0 ]; then
echo "❌ Failed to set admin password for production environment"
echo "Error: $SECRET_OUTPUT"
exit 1
fi
echo "✅ Admin password set for production environment"
read -r -p "Enter your domain (e.g., yourdomain.com): " domain
domain="${domain#https://}"
domain="${domain#http://}"
domain="${domain%%/*}"
if [ -z "$domain" ]; then
echo "❌ No domain provided. Cannot continue."
exit 1
fi
echo "✅ Domain: $domain"
escape_sed_replacement() {
printf '%s' "$1" | sed -e 's/[\/&]/\\&/g'
}
KV_ID_ESCAPED="$(escape_sed_replacement "$MAIN_ID")"
KV_PREVIEW_ID_ESCAPED="$(escape_sed_replacement "$PREVIEW_ID")"
DOMAIN_ESCAPED="$(escape_sed_replacement "$domain")"
COMPATIBILITY_DATE_ESCAPED="$(escape_sed_replacement "$(date +%F)")"
echo "📝 Creating and configuring wrangler.toml..."
cp wrangler-example.toml wrangler.toml
# Update wrangler.toml with domain and KV IDs
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS requires empty string for -i
sed -i '' "s/REPLACE_WITH_YOUR_DOMAIN/$domain/g" wrangler.toml
if [ ! -z "$KV_ID" ]; then
sed -i '' "s/REPLACE_WITH_YOUR_KV_NAMESPACE_ID/$KV_ID/g" wrangler.toml
fi
if [ ! -z "$KV_PREVIEW_ID" ]; then
sed -i '' "s/REPLACE_WITH_YOUR_PREVIEW_KV_NAMESPACE_ID/$KV_PREVIEW_ID/g" wrangler.toml
fi
sed -i '' "s/REPLACE_WITH_YOUR_DOMAIN/$DOMAIN_ESCAPED/g" wrangler.toml
sed -i '' "s/REPLACE_WITH_YOUR_KV_NAMESPACE_ID/$KV_ID_ESCAPED/g" wrangler.toml
sed -i '' "s/REPLACE_WITH_YOUR_PREVIEW_KV_NAMESPACE_ID/$KV_PREVIEW_ID_ESCAPED/g" wrangler.toml
sed -i '' "s/REPLACE_WITH_COMPATIBILITY_DATE/$COMPATIBILITY_DATE_ESCAPED/g" wrangler.toml
else
# Linux and others
sed -i "s/REPLACE_WITH_YOUR_DOMAIN/$domain/g" wrangler.toml
if [ ! -z "$KV_ID" ]; then
sed -i "s/REPLACE_WITH_YOUR_KV_NAMESPACE_ID/$KV_ID/g" wrangler.toml
fi
if [ ! -z "$KV_PREVIEW_ID" ]; then
sed -i "s/REPLACE_WITH_YOUR_PREVIEW_KV_NAMESPACE_ID/$KV_PREVIEW_ID/g" wrangler.toml
fi
sed -i "s/REPLACE_WITH_YOUR_DOMAIN/$DOMAIN_ESCAPED/g" wrangler.toml
sed -i "s/REPLACE_WITH_YOUR_KV_NAMESPACE_ID/$KV_ID_ESCAPED/g" wrangler.toml
sed -i "s/REPLACE_WITH_YOUR_PREVIEW_KV_NAMESPACE_ID/$KV_PREVIEW_ID_ESCAPED/g" wrangler.toml
sed -i "s/REPLACE_WITH_COMPATIBILITY_DATE/$COMPATIBILITY_DATE_ESCAPED/g" wrangler.toml
fi
echo "✅ wrangler.toml has been created and configured successfully!"
echo ""
echo "✅ Setup complete! Next steps:"
echo "1. Set up MX records for your domain with ForwardEmail.net (see README for more details)"
echo "2. Deploy with 'npm run deploy'"
echo "1. Set up MX records for your domain with ForwardEmail.net (see README for details)"
echo "2. Deploy with 'npm run deploy'"