Files
SoftwareX/worker/src/index.ts
T
User ad0c936ccd Deploy: Add Cloudflare Worker, D1 database integration, and updated README
- Add complete Cloudflare Worker implementation with waitlist API endpoints
- Integrate Cloudflare D1 SQLite database for production waitlist storage
- Add wrangler configuration for Worker deployment and D1 binding
- Rewrite README with comprehensive deployment and architecture documentation
- Update environment configuration and build setup
- Add waitlist utility functions and API client
- Update project dependencies and Vite configuration
- Deploy live to https://react-example.white-glade-ab2c.workers.dev
2026-08-31 08:24:47 +02:00

138 lines
4.0 KiB
TypeScript

interface Env {
DB: D1Database;
}
const BASE_WAITLIST_OFFSET = 2870;
const CORS_HEADERS = {
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
};
function json(data: unknown, status = 200) {
return new Response(JSON.stringify(data), {
status,
headers: CORS_HEADERS
});
}
function makeReferralCode() {
return `SX-${crypto.randomUUID().replace(/-/g, '').slice(0, 5).toUpperCase()}`;
}
async function getStats(env: Env) {
const row = await env.DB.prepare(
'SELECT total_registered, total_funded_amount FROM waitlist_stats WHERE id = ?'
)
.bind('waitlist')
.first<{ total_registered: number; total_funded_amount: number }>();
const registered = Number(row?.total_registered ?? 0);
return {
totalCount: BASE_WAITLIST_OFFSET + registered,
totalFundedAmount: Number(row?.total_funded_amount ?? 142500),
recentRegistrationsCount: registered
};
}
async function register(request: Request, env: Env) {
const body = await request.json() as {
email?: string;
fullName?: string;
tier?: string;
investmentAmount?: number;
referredBy?: string;
};
const email = body.email?.trim().toLowerCase();
if (!email) return json({ error: 'A valid email is required.' }, 400);
const fullName = body.fullName?.trim() || 'BM Connect Member';
const tier = body.tier || 'Supporter';
const investmentAmount = Number(body.investmentAmount) || 25;
const referredBy = body.referredBy?.trim() || null;
const id = crypto.randomUUID();
const referralCode = makeReferralCode();
const result = await env.DB.batch([
env.DB.prepare(
`UPDATE waitlist_stats
SET total_registered = total_registered + 1,
total_funded_amount = total_funded_amount + ?,
updated_at = CURRENT_TIMESTAMP
WHERE id = ?`
).bind(investmentAmount, 'waitlist'),
env.DB.prepare(
`INSERT INTO waitlist_entries
(id, email, full_name, tier, investment_amount, position, referral_code, referred_by)
SELECT ?, ?, ?, ?, ?, ? + total_registered, ?, ?
FROM waitlist_stats
WHERE id = ?`
).bind(
id,
email,
fullName,
tier,
investmentAmount,
BASE_WAITLIST_OFFSET,
referralCode,
referredBy,
'waitlist'
)
]);
if (!result[1].success) {
throw new Error('The waitlist entry could not be created.');
}
const entry = await env.DB.prepare(
`SELECT id, email, full_name, tier, investment_amount, position, referral_code, referred_by, created_at
FROM waitlist_entries WHERE id = ?`
).bind(id).first();
return json({
id,
email,
fullName,
tier,
investmentAmount,
position: Number(entry?.position ?? BASE_WAITLIST_OFFSET),
referralCode,
totalRegistered: Number(entry?.position ?? BASE_WAITLIST_OFFSET),
referredBy,
createdAt: entry?.created_at
}, 201);
}
async function listEntries(env: Env) {
const { results } = await env.DB.prepare(
`SELECT id, email, full_name, tier, investment_amount, position, referral_code, referred_by, created_at
FROM waitlist_entries ORDER BY created_at DESC`
).all();
return json(results);
}
export default {
async fetch(request: Request, env: Env): Promise<Response> {
if (request.method === 'OPTIONS') return new Response(null, { headers: CORS_HEADERS });
const url = new URL(request.url);
try {
if (request.method === 'GET' && url.pathname === '/api/waitlist/stats') {
return json(await getStats(env));
}
if (request.method === 'POST' && url.pathname === '/api/waitlist') {
return register(request, env);
}
if (request.method === 'GET' && url.pathname === '/api/waitlist/entries') {
return listEntries(env);
}
return json({ error: 'Not found' }, 404);
} catch (error) {
console.error(error);
return json({ error: 'Unable to complete the waitlist request.' }, 500);
}
}
};