Repository navigation
votes-api: minimal Vercel entry (hono/vercel) + vercel.json #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| // Vercel entrypoint for the votes API (Hono). The long-running Node server lives in | ||
| // src/index.ts (PM2/nginx path) and is untouched; this file only adapts the same app | ||
| // factory to Vercel's fetch handler. Config comes from env vars (DATABASE_URL, | ||
| // VOTES_HMAC_PEPPER, TURNSTILE_SECRET_KEY, ...) exactly as in src/index.ts. If they are not | ||
| // set, config.ts falls back to local-dev defaults and DB-backed routes return errors | ||
| // (/api/v1/health reports db: down) instead of crashing the function at import time. | ||
| import { handle } from 'hono/vercel'; | ||
| import { createApp } from '../src/app.js'; | ||
| import { loadConfig } from '../src/config.js'; | ||
| import { connect } from '../src/db/client.js'; | ||
| import { createLogger } from '../src/logger.js'; | ||
| import { SlugRegistry } from '../src/slug/registry.js'; | ||
| import { createTurnstileVerifier } from '../src/turnstile.js'; | ||
| import { LiveTemplateManifest } from '../src/submissions/live-manifest.js'; | ||
| import { createShareLinkVerifier } from '../src/submissions/share-link.js'; | ||
|
|
||
| const cfg = loadConfig(); | ||
| const logger = createLogger(cfg.logLevel); | ||
| // Serverless: keep the pool tiny; each instance handles few concurrent requests. | ||
| const db = connect(cfg.databaseUrl, 1); | ||
| const slugRegistry = new SlugRegistry({ | ||
| contentDir: cfg.useCaseContentDir, | ||
| slugsFile: cfg.slugsFile, | ||
| slugsUrl: cfg.slugsUrl, | ||
| refreshMs: cfg.slugRefreshMs, | ||
| }); | ||
|
|
||
| const app = createApp({ | ||
| db, | ||
| slugRegistry, | ||
| turnstileVerifier: createTurnstileVerifier(cfg.turnstileSecret), | ||
| shareLinkVerifier: createShareLinkVerifier(cfg.shareLinkTimeoutMs), | ||
| liveManifest: new LiveTemplateManifest({ | ||
| file: cfg.submissionsManifestFile, | ||
| url: cfg.submissionsManifestUrl, | ||
| ttlMs: cfg.submissionsManifestTtlMs, | ||
| }), | ||
| pepper: cfg.pepper, | ||
| logger, | ||
| }); | ||
|
|
||
| export const GET = handle(app); | ||
| export const POST = handle(app); | ||
| export const PUT = handle(app); | ||
| export const PATCH = handle(app); | ||
| export const DELETE = handle(app); | ||
| export const OPTIONS = handle(app); | ||
| export const HEAD = handle(app); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| votes-api |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "$schema": "https://openapi.vercel.sh/vercel.json", | ||
| "framework": null, | ||
| "installCommand": "npm install", | ||
| "buildCommand": "", | ||
| "outputDirectory": "public", | ||
| "rewrites": [{ "source": "/(.*)", "destination": "/api" }] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Locally, This file also never packs the slug sources the registry actually reads. Defaults are |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the right factory, and
GET /api/v1/healthdoes return 503db: downwithout crashing import. Two holes vssrc/index.ts+ vs a public Vercel host:loadConfig()still fail-opens toVOTES_HMAC_PEPPER=local-dev-only-replace-meandTURNSTILE_SECRET_KEY=1x0000000000000000000000000000000AA. I posted{"turnstileToken":"x"}to this handler; Turnstile did not 403 (test secret + Cloudflare always-pass) and the handler proceeded toinsert into identities(then 500 onECONNREFUSED). If Vercel Auth is off and those env vars are missing, this is a public signer.export const config = { runtime: 'nodejs' }. This graph usesnode:fs,postgresTCP, andnode:crypto. Hono's Vercel guide sets Node explicitly so the function cannot land on Edge.src/index.tsalsoawait slugRegistry.load(true)before serve. Lazyhas()is fine on serverless, but the first vote/counts call will throwno use-case slugs loadedunless content/dist orSLUGS_URLis actually in the bundle (seevercel.json).