import { Hono } from 'hono'; import { cors } from 'hono/cors'; import { manifestRoute } from './routes/manifest.ts'; import { healthRoute } from './routes/health.ts'; import { decksRouter } from './routes/decks.ts'; import { cardsRouter } from './routes/cards.ts'; import { reviewsRouter } from './routes/reviews.ts'; import { shareRouter } from './routes/share.ts'; import { toolsRouter } from './routes/tools.ts'; import { searchRouter } from './routes/search.ts'; import { dsgvoRouter } from './routes/dsgvo.ts'; import { meRouter } from './routes/me.ts'; import { mediaRouter } from './routes/media.ts'; import { decksGenerateRouter } from './routes/decks-generate.ts'; import { decksFromImageRouter } from './routes/decks-from-image.ts'; import { authorsRouter as marketplaceAuthorsRouter } from './routes/marketplace/authors.ts'; import { marketplaceDecksRouter } from './routes/marketplace/decks.ts'; import { exploreRouter as marketplaceExploreRouter } from './routes/marketplace/explore.ts'; import { engagementRouter as marketplaceEngagementRouter } from './routes/marketplace/engagement.ts'; import { subscriptionsRouter as marketplaceSubscriptionsRouter } from './routes/marketplace/subscriptions.ts'; import { forkRouter as marketplaceForkRouter } from './routes/marketplace/fork.ts'; import { pullRequestsRouter as marketplacePullRequestsRouter } from './routes/marketplace/pull-requests.ts'; import { discussionsRouter as marketplaceDiscussionsRouter } from './routes/marketplace/discussions.ts'; const app = new Hono(); app.use( '*', cors({ origin: (origin) => { if (!origin) return origin; // Dev: localhost-Ports erlaubt. Prod: explizite Whitelist. if (/^https?:\/\/localhost(:\d+)?$/.test(origin)) return origin; if (/^https?:\/\/127\.0\.0\.1(:\d+)?$/.test(origin)) return origin; if (origin === 'https://cardecky.mana.how') return origin; return null; }, allowHeaders: ['Content-Type', 'X-User-Id', 'Authorization', 'X-Service-Key'], allowMethods: ['GET', 'POST', 'PATCH', 'DELETE', 'OPTIONS'], credentials: true, }) ); app.route('/', healthRoute); app.route('/.well-known/mana-app.json', manifestRoute); app.route('/api/v1/decks', decksRouter()); app.route('/api/v1/cards', cardsRouter()); app.route('/api/v1/reviews', reviewsRouter()); app.route('/api/v1/share', shareRouter()); app.route('/api/v1/tools', toolsRouter()); app.route('/api/v1/search', searchRouter()); app.route('/api/v1/dsgvo', dsgvoRouter()); app.route('/api/v1/me', meRouter()); app.route('/api/v1/media', mediaRouter()); app.route('/api/v1/decks/generate', decksGenerateRouter()); app.route('/api/v1/decks/from-image', decksFromImageRouter()); // Marketplace (Phase 12). Eigenes pgSchema, additive Routen unter /v1/marketplace/*. // Plan: docs/playbooks/MARKETPLACE_RESTORE.md. // // Mount-Reihenfolge ist signifikant: spezifischere Routes vor /authors // und /decks, damit z.B. /marketplace/me/subscriptions nicht zu authors // oder decks geroutet wird. app.route('/api/v1/marketplace', marketplaceExploreRouter()); app.route('/api/v1/marketplace', marketplaceEngagementRouter()); app.route('/api/v1/marketplace', marketplaceSubscriptionsRouter()); app.route('/api/v1/marketplace', marketplaceForkRouter()); app.route('/api/v1/marketplace', marketplacePullRequestsRouter()); app.route('/api/v1/marketplace', marketplaceDiscussionsRouter()); app.route('/api/v1/marketplace/authors', marketplaceAuthorsRouter()); app.route('/api/v1/marketplace/decks', marketplaceDecksRouter()); app.get('/', (c) => c.json({ app: 'cards', version: process.env.CARDS_API_VERSION ?? '0.0.0', see: '/.well-known/mana-app.json', }) ); const port = Number(process.env.CARDS_API_PORT ?? 3081); console.log(`[cards-api] listening on http://localhost:${port}`); export default { port, fetch: app.fetch, };