Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.
wisp.place
1import app from './server';
2import { serve } from '@hono/node-server';
3import { FirehoseWorker } from './lib/firehose';
4import { logger } from './lib/observability';
5import { mkdirSync, existsSync } from 'fs';
6import { backfillCache } from './lib/backfill';
7import { startDomainCacheCleanup, stopDomainCacheCleanup, setCacheOnlyMode } from './lib/db';
8
9const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3001;
10const CACHE_DIR = process.env.CACHE_DIR || './cache/sites';
11
12// Parse CLI arguments
13const args = process.argv.slice(2);
14const hasBackfillFlag = args.includes('--backfill');
15const backfillOnStartup = hasBackfillFlag || process.env.BACKFILL_ON_STARTUP === 'true';
16
17// Cache-only mode: service will only cache files locally, no DB writes
18const hasCacheOnlyFlag = args.includes('--cache-only');
19export const CACHE_ONLY_MODE = hasCacheOnlyFlag || process.env.CACHE_ONLY_MODE === 'true';
20
21// Configure cache-only mode in database module
22if (CACHE_ONLY_MODE) {
23 setCacheOnlyMode(true);
24}
25
26// Ensure cache directory exists
27if (!existsSync(CACHE_DIR)) {
28 mkdirSync(CACHE_DIR, { recursive: true });
29 console.log('Created cache directory:', CACHE_DIR);
30}
31
32// Start domain cache cleanup
33startDomainCacheCleanup();
34
35// Start firehose worker with observability logger
36const firehose = new FirehoseWorker((msg, data) => {
37 logger.info(msg, data);
38});
39
40firehose.start();
41
42// Run backfill if requested
43if (backfillOnStartup) {
44 console.log('🔄 Backfill requested, starting cache backfill...');
45 backfillCache({
46 skipExisting: true,
47 concurrency: 3,
48 }).then((stats) => {
49 console.log('✅ Cache backfill completed');
50 }).catch((err) => {
51 console.error('❌ Cache backfill error:', err);
52 });
53}
54
55// Add health check endpoint
56app.get('/health', (c) => {
57 const firehoseHealth = firehose.getHealth();
58 return c.json({
59 status: 'ok',
60 firehose: firehoseHealth,
61 });
62});
63
64// Start HTTP server with Node.js adapter
65const server = serve({
66 fetch: app.fetch,
67 port: PORT,
68});
69
70console.log(`
71Wisp Hosting Service
72
73Server: http://localhost:${PORT}
74Health: http://localhost:${PORT}/health
75Cache: ${CACHE_DIR}
76Firehose: Connected to Firehose
77Cache-Only: ${CACHE_ONLY_MODE ? 'ENABLED (no DB writes)' : 'DISABLED'}
78`);
79
80// Graceful shutdown
81process.on('SIGINT', async () => {
82 console.log('\n🛑 Shutting down...');
83 firehose.stop();
84 stopDomainCacheCleanup();
85 server.close();
86 process.exit(0);
87});
88
89process.on('SIGTERM', async () => {
90 console.log('\n🛑 Shutting down...');
91 firehose.stop();
92 stopDomainCacheCleanup();
93 server.close();
94 process.exit(0);
95});