Function bodies 165 total
handleRecover function · typescript · L337-L390 (54 LOC)packages/server/src/api.ts
export async function handleRecover(request: Request, env: Env): Promise<Response> {
const body = await readJson(request);
const email = typeof body.email === "string" ? body.email.trim().toLowerCase() : "";
if (!email || !email.includes("@")) {
return json({ error: "Please enter a valid email address." }, 400);
}
// Look up token by email
const row = await env.DB.prepare(
`SELECT token FROM licenses WHERE LOWER(email) = ? LIMIT 1`
)
.bind(email)
.first<{ token: string }>();
// Always return success to prevent email enumeration
if (!row) {
return json({ ok: true, message: "If a license exists for that email, you'll receive it shortly." });
}
// Send email via Resend
try {
const resp = await fetch("https://api.resend.com/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${env.RESEND_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
from: "negative-supporthandlePrice function · typescript · L392-L406 (15 LOC)packages/server/src/api.ts
export async function handlePrice(env: Env): Promise<Response> {
const resp = await fetch(`${STRIPE_API}/prices/${env.STRIPE_PRICE_ID}`, {
headers: { Authorization: `Bearer ${env.STRIPE_SECRET_KEY}` },
});
if (!resp.ok) {
return json({ error: "Failed to fetch price" }, 500);
}
const price = (await resp.json()) as { unit_amount?: number; currency?: string };
return json({
amount: (price.unit_amount ?? 0) / 100,
currency: price.currency ?? "usd",
});
}handleCheckout function · typescript · L408-L451 (44 LOC)packages/server/src/api.ts
export async function handleCheckout(request: Request, env: Env): Promise<Response> {
// Lazy import to avoid circular dep
const { getSessionUser } = await import("./auth");
const body = await readJson(request);
const machineId = isValidMachineId(body.machine_id) ? body.machine_id : undefined;
const params = new URLSearchParams({
mode: "payment",
"line_items[0][price]": env.STRIPE_PRICE_ID,
"line_items[0][quantity]": "1",
success_url: SUCCESS_URL,
cancel_url: CANCEL_URL,
});
if (machineId) {
params.set("metadata[machine_id]", machineId);
}
// If logged in, attach user_id and prefill email
const user = await getSessionUser(request, env);
if (user) {
params.set("metadata[user_id]", String(user.id));
if (user.email) {
params.set("customer_email", user.email);
}
}
const resp = await fetch(`${STRIPE_API}/checkout/sessions`, {
method: "POST",
headers: {
Authorization: `Bearer ${env.STRIPE_SECRET_KEY}`,
json function · typescript · L24-L32 (9 LOC)packages/server/src/auth.ts
function json(data: unknown, status = 200, headers: Record<string, string> = {}): Response {
return new Response(JSON.stringify(data), {
status,
headers: {
"Content-Type": "application/json",
...headers,
},
});
}randomHex function · typescript · L34-L38 (5 LOC)packages/server/src/auth.ts
function randomHex(bytes: number): string {
const buf = new Uint8Array(bytes);
crypto.getRandomValues(buf);
return Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join("");
}generateToken function · typescript · L40-L42 (3 LOC)packages/server/src/auth.ts
function generateToken(): string {
return `ns_live_${randomHex(16)}`;
}now function · typescript · L44-L46 (3 LOC)packages/server/src/auth.ts
function now(): string {
return new Date().toISOString();
}Repobility's GitHub App fixes findings like these · https://github.com/apps/repobility-bot
cookieHeader function · typescript · L48-L50 (3 LOC)packages/server/src/auth.ts
function cookieHeader(name: string, value: string, maxAge: number): string {
return `${name}=${value}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=${maxAge}`;
}getSessionUser function · typescript · L62-L86 (25 LOC)packages/server/src/auth.ts
export async function getSessionUser(request: Request, env: Env): Promise<SessionUser | null> {
const cookie = request.headers.get("Cookie") || "";
const match = cookie.match(/(?:^|;\s*)session=([a-f0-9]{64})/);
if (!match) return null;
const sessionId = match[1];
const row = await env.DB.prepare(
`SELECT u.id, u.github_id, u.github_login, u.email, u.avatar_url, s.expires_at
FROM sessions s JOIN users u ON s.user_id = u.id
WHERE s.session_id = ?`
)
.bind(sessionId)
.first<{ id: number; github_id: number; github_login: string; email: string | null; avatar_url: string | null; expires_at: string }>();
if (!row) return null;
// Check expiry
if (new Date(row.expires_at) < new Date()) {
// Lazily delete expired session
await env.DB.prepare(`DELETE FROM sessions WHERE session_id = ?`).bind(sessionId).run();
return null;
}
return { id: row.id, github_id: row.github_id, github_login: row.github_login, email: row.email, avatar_url: row.handleGitHubLogin function · typescript · L90-L108 (19 LOC)packages/server/src/auth.ts
export async function handleGitHubLogin(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const state = randomHex(16);
const redirectUri = `${url.origin}/api/auth/github/callback`;
const authUrl = new URL(GITHUB_AUTHORIZE);
authUrl.searchParams.set("client_id", env.GITHUB_CLIENT_ID);
authUrl.searchParams.set("redirect_uri", redirectUri);
authUrl.searchParams.set("scope", "read:user user:email");
authUrl.searchParams.set("state", state);
return new Response(null, {
status: 302,
headers: {
Location: authUrl.toString(),
"Set-Cookie": cookieHeader("oauth_state", state, 600), // 10 min
},
});
}handleGitHubCallback function · typescript · L112-L232 (121 LOC)packages/server/src/auth.ts
export async function handleGitHubCallback(request: Request, env: Env): Promise<Response> {
const url = new URL(request.url);
const code = url.searchParams.get("code");
const state = url.searchParams.get("state");
// Verify state
const cookie = request.headers.get("Cookie") || "";
const stateMatch = cookie.match(/(?:^|;\s*)oauth_state=([a-f0-9]{32})/);
if (!code || !state || !stateMatch || stateMatch[1] !== state) {
return new Response("Invalid OAuth state", { status: 400 });
}
// Exchange code for access token
const tokenResp = await fetch(GITHUB_TOKEN, {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
body: JSON.stringify({
client_id: env.GITHUB_CLIENT_ID,
client_secret: env.GITHUB_CLIENT_SECRET,
code,
}),
});
const tokenData = (await tokenResp.json()) as { access_token?: string; error?: string };
if (!tokenData.access_token) {
return new Response(`GitHuhandleMe function · typescript · L236-L266 (31 LOC)packages/server/src/auth.ts
export async function handleMe(request: Request, env: Env): Promise<Response> {
const user = await getSessionUser(request, env);
if (!user) {
return json({ user: null });
}
// Get license info
const license = await env.DB.prepare(
`SELECT token, plan, runs_used FROM licenses WHERE user_id = ? LIMIT 1`
)
.bind(user.id)
.first<{ token: string; plan: string; runs_used: number }>();
const freeRemaining = license
? license.plan === "lifetime"
? -1 // unlimited
: Math.max(0, FREE_RUNS - license.runs_used)
: 0;
return json({
user: {
login: user.github_login,
email: user.email,
avatar_url: user.avatar_url,
},
license: license
? { token: license.token, plan: license.plan, runs_used: license.runs_used }
: null,
freeRemaining,
});
}handleLogout function · typescript · L270-L284 (15 LOC)packages/server/src/auth.ts
export async function handleLogout(request: Request, env: Env): Promise<Response> {
const cookie = request.headers.get("Cookie") || "";
const match = cookie.match(/(?:^|;\s*)session=([a-f0-9]{64})/);
if (match) {
await env.DB.prepare(`DELETE FROM sessions WHERE session_id = ?`).bind(match[1]).run();
}
return new Response(JSON.stringify({ ok: true }), {
status: 200,
headers: {
"Content-Type": "application/json",
"Set-Cookie": cookieHeader("session", "", 0),
},
});
}corsResponse function · typescript · L34-L45 (12 LOC)packages/server/src/index.ts
function corsResponse(request: Request): Response {
const origin = new URL(request.url).origin;
return new Response(null, {
status: 204,
headers: {
"Access-Control-Allow-Origin": origin,
"Access-Control-Allow-Methods": "GET, POST, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type",
"Access-Control-Allow-Credentials": "true",
},
});
}notFound function · typescript · L47-L52 (6 LOC)packages/server/src/index.ts
function notFound(): Response {
return new Response(JSON.stringify({ error: "Not found" }), {
status: 404,
headers: { "Content-Type": "application/json" },
});
}‹ prevpage 4 / 4