Fork of dabit3/vending-machine, rebranded for Cafe Compute / Cerebras and hosted by Arca Computer.
Production Worker: vending at https://vending.arca.computer. This repo does not deploy. Chercán creates the D1 database and attaches secrets at deploy time.
A vending machine for Cafe Compute event credits. Admins create events with an eligible-email list and a pool of unique codes; attendees visit /<slug>, sign in, and receive a code if their email is on the list (idempotent — the same email always gets the same code).
- Astro 7 with
@astrojs/cloudflare(output: 'server') - Cloudflare Worker assets + on-demand routes (claim + admin)
- D1 (
vending) — schema inmigrations/ - No Convex, no Clerk, no Next.js, no KV/R2/Queues/Images bindings
House pattern matches arcacomputer/oss and clueside/site (workers_dev: false, preview_urls: false, custom domain outside auto workers.dev). Those sites are static; this app is not — claim and admin run on the Worker. / is also on-demand (not prerendered) so it can merge the live Luma calendar with D1 events.
/— Cerebras Cafe Compute directory (live Luma calendar + D1 events; Santiago is always listed)/santiago— Cafe Compute Meetup: Santiago claim page (Luma: https://luma.com/cafecomputechile, 12 Sep 2026, host Luis Felipe Abarca / Felirami, venue TBA, approval-required)/<slug>— claim page for an admin-created event/sign-in— attendee or admin sign-in/admin— create/list events/admin/events/<id>— emails, codes, flagged review, stats/admin/blacklist— app-wide email blacklist/admin/admins— admin allowlist
Sessions are a signed httpOnly cookie. SESSION_SECRET is required (Worker secret / .dev.vars).
Attendee sign-in, in order:
- Email OTP if
RESEND_API_KEYandMAIL_FROMare set — a one-time code is emailed. - Else allowlist + Turnstile if
TURNSTILE_SITE_KEYandTURNSTILE_SECRET_KEYare set — the email must already be on the event allowlist, and Turnstile must pass. This does not prove mailbox ownership (weaker threat model). - Else allowlist-only (dev) — documented as unsafe for production. Set an email provider or Turnstile before going live.
Admin: D1 admins table. Empty list is bootstrap (first successful /admin sign-in becomes admin). After that, only listed emails get an admin session.
Copy .env.example to .dev.vars for local Wrangler. Do not commit secrets.
| Name | Required | Purpose |
|---|---|---|
SESSION_SECRET |
yes (prod) | HMAC key for session cookies |
RESEND_API_KEY |
no | Send login codes via Resend |
MAIL_FROM |
with Resend | Verified from-address |
TURNSTILE_SITE_KEY |
no | Turnstile widget |
TURNSTILE_SECRET_KEY |
with site key | Turnstile verify |
D1 is a binding (DB), not an env var. wrangler.jsonc has database_name: "vending" and a placeholder database_id. Replace the placeholder at deploy — do not create D1 from this PR.
npm install
# optional: echo 'SESSION_SECRET=dev-only-not-for-prod' > .dev.vars
npm run dev # astro dev (UI; D1 binding needs wrangler)
npx wrangler d1 migrations apply vending --local
npm run cf:dev # wrangler dev — Worker + local D1
npm run build
npm run cf:dry-run- Sign in at
/admin(bootstrap if the admins table is empty). - Create an event with a short slug (e.g.
toronto) and optional Luma URL. - Paste eligible emails and codes.
- Share
https://vending.arca.computer/<slug>.
Santiago is seeded in migrations/0001_init.sql as slug santiago.
wrangler.jsonc: Worker name vending, compatibility_date 2026-08-26, workers_dev / preview_urls false, assets ./dist, D1 binding DB, route vending.arca.computer as a custom domain. No KV, R2, queues, or Images.