From b80316267ff5a0620df6e17399fdaae3346de6ec Mon Sep 17 00:00:00 2001 From: Jory Severijnse Date: Sat, 22 Aug 2026 14:46:22 +0200 Subject: [PATCH] feat(hetzner): update virtualcam with bypassing payments --- .../modules/services/virtualcam-build.patch | 29 ----------------- .../services/virtualcam-checkout.patch | 32 +++++++++++++++++++ .../modules/services/virtualcam-layout.patch | 30 ----------------- .../hetzner/modules/services/virtualcam.nix | 9 +++++- 4 files changed, 40 insertions(+), 60 deletions(-) delete mode 100644 servers/hetzner/modules/services/virtualcam-build.patch create mode 100644 servers/hetzner/modules/services/virtualcam-checkout.patch delete mode 100644 servers/hetzner/modules/services/virtualcam-layout.patch diff --git a/servers/hetzner/modules/services/virtualcam-build.patch b/servers/hetzner/modules/services/virtualcam-build.patch deleted file mode 100644 index cb01546..0000000 --- a/servers/hetzner/modules/services/virtualcam-build.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/src/lib/catalog.ts -+++ b/src/lib/catalog.ts -@@ -1,3 +1,8 @@ - import { prisma } from "@/lib/db"; -+ -+// During `next build`, Next evaluates generateStaticParams/generateMetadata for -+// each route, which calls these DB readers. No database exists in the sandboxed -+// Nix build, so short-circuit them here; the live site fetches real rows/request. -+const BUILD = process.env.NEXT_PHASE === "phase-production-build"; - - export type TierWithFeatures = { -@@ -33,2 +38,3 @@ - export async function getActiveTiers(): Promise { -+ if (BUILD) return []; - const tiers = await prisma.tier.findMany({ -@@ -45,4 +51,5 @@ - export async function getTierBySlug( - slug: string, - ): Promise { -+ if (BUILD) return null; - const tier = await prisma.tier.findUnique({ -@@ -58,2 +65,3 @@ - export async function getDocPages() { -+ if (BUILD) return []; - return prisma.docPage.findMany({ -@@ -65,2 +73,3 @@ - export async function getDocBySlug(slug: string) { -+ if (BUILD) return null; - return prisma.docPage.findUnique({ where: { slug } }); \ No newline at end of file diff --git a/servers/hetzner/modules/services/virtualcam-checkout.patch b/servers/hetzner/modules/services/virtualcam-checkout.patch new file mode 100644 index 0000000..a3fd902 --- /dev/null +++ b/servers/hetzner/modules/services/virtualcam-checkout.patch @@ -0,0 +1,32 @@ +--- a/src/app/api/checkout/route.ts ++++ b/src/app/api/checkout/route.ts +@@ -7,6 +7,8 @@ + + export const dynamic = "force-dynamic"; + ++const BYPASS_PAYMENTS = process.env.BYPASS_PAYMENTS === "true"; ++ + export async function POST(req: Request) { + // Each checkout hits the payment provider, so cap order creation per user + // and per IP to prevent order spam and provider-API abuse. +@@ -86,6 +88,20 @@ + const paid = await prisma.order.findUnique({ + where: { id: order.id }, + include: { license: true }, ++ }); ++ return NextResponse.json({ ++ ok: true, ++ orderId: order.id, ++ licenseKey: paid?.license?.key ?? null, ++ tier: tier.slug, ++ }); ++ } ++ ++ if (BYPASS_PAYMENTS) { ++ await markOrderPaid({ orderId: order.id, providerRef: "bypass-test" }); ++ const paid = await prisma.order.findUnique({ ++ where: { id: order.id }, ++ include: { license: true }, + }); + return NextResponse.json({ + ok: true, diff --git a/servers/hetzner/modules/services/virtualcam-layout.patch b/servers/hetzner/modules/services/virtualcam-layout.patch deleted file mode 100644 index 535fe57..0000000 --- a/servers/hetzner/modules/services/virtualcam-layout.patch +++ /dev/null @@ -1,30 +0,0 @@ ---- a/src/app/layout.tsx -+++ b/src/app/layout.tsx -@@ -1,19 +1,14 @@ - import type { Metadata } from "next"; --import { Pixelify_Sans } from "next/font/google"; - import "./globals.css"; - import { getCurrentUser } from "@/lib/auth"; - import { getAppUrl } from "@/lib/env"; - import { Providers } from "@/components/providers"; - import { AuthProvider } from "@/contexts/auth-context"; - import { MatrixEffects } from "@/components/matrix-effects"; - import { SiteHeader } from "@/components/site-header"; - import { SiteFooter } from "@/components/site-footer"; -- --const pixelify = Pixelify_Sans({ -- subsets: ["latin"], -- weight: ["400", "500", "600", "700"], -- variable: "--font-pixelify", -- display: "swap", --}); -- -+// Built fully dynamic so the sandboxed Nix build needs no database and no -+// external font download; also correct for a DB-driven storefront. -+export const dynamic = "force-dynamic"; -+ - export const metadata: Metadata = { -@@ -50,2 +45,2 @@ -- -+ - \ No newline at end of file diff --git a/servers/hetzner/modules/services/virtualcam.nix b/servers/hetzner/modules/services/virtualcam.nix index 4c9aac5..2ff0c24 100644 --- a/servers/hetzner/modules/services/virtualcam.nix +++ b/servers/hetzner/modules/services/virtualcam.nix @@ -15,6 +15,12 @@ rev = rev; }; + srcPatched = pkgs.applyPatches { + name = "virtualcam-website-patched"; + src = src; + patches = [./virtualcam-checkout.patch]; + }; + apiSrc = builtins.fetchGit { url = "ssh://git@git.severijnse.eu:2222/jory/virtualcam-api.git"; rev = apiRev; @@ -24,7 +30,7 @@ app = unstablePkgs.buildNpmPackage { pname = "virtualcam-website"; version = "0.1.0"; - src = src; + src = srcPatched; npmDepsHash = "sha256-0g98Jh/RwoicjrfiSbfqNo331k3ab8hINjV6dHHN0y4="; nodejs = unstablePkgs.nodejs; @@ -232,6 +238,7 @@ in { "DATABASE_URL=${dbUrl}" "APP_URL=https://virtualcam.severijnse.eu" "PAYMENTS_MODE=shkeeper" + "BYPASS_PAYMENTS=true" "ADMIN_EMAILS=jory@severijnse.eu" "SMTP_HOST=mail.severijnse.eu" "SMTP_PORT=587"