Phone photo -> composited postcard (canvas templates, stamp corner, EXIF-aware date/location, self-hosted handwriting font) with a small server for share links, day-context caption drafting off goonk's day-summary API, and Nominatim reverse geocoding. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
29 lines
930 B
JavaScript
29 lines
930 B
JavaScript
import express from 'express'
|
|
import path from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { config } from './config.js'
|
|
import { apiRouter, imageRouter } from './routes.js'
|
|
import { sweepExpiredPostcards, startCleanupJob } from './cleanup.js'
|
|
|
|
const app = express()
|
|
|
|
// Deployed behind a reverse proxy in production — needed for accurate
|
|
// req.ip in the rate limiter.
|
|
app.set('trust proxy', true)
|
|
|
|
// Mounted before the static frontend and before any body parser: the
|
|
// upload route reads the raw request stream itself and must not have it
|
|
// consumed by express.json()/express.raw() first.
|
|
app.use('/api', apiRouter)
|
|
app.use('/', imageRouter)
|
|
|
|
const staticRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..')
|
|
app.use(express.static(staticRoot))
|
|
|
|
sweepExpiredPostcards()
|
|
startCleanupJob()
|
|
|
|
app.listen(config.port, () => {
|
|
console.log(`postcard server listening on :${config.port}`)
|
|
})
|