Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place

docker changes as well as oauth respects system theme

+25 -38
+11 -17
apps/hosting-service/Dockerfile
··· 1 1 # Build from monorepo root: docker build -f apps/hosting-service/Dockerfile . 2 2 3 - # Stage 1: Build 3 + # Stage 1: Compile to standalone binary 4 4 FROM oven/bun:1-alpine AS builder 5 5 6 6 WORKDIR /app 7 7 8 8 # Copy workspace configuration files 9 - COPY package.json bun.lock ./ 10 - COPY tsconfig.json ./ 9 + COPY package.json bun.lock tsconfig.json ./ 11 10 12 11 # Copy all workspace packages (needed for workspace: dependencies) 13 12 COPY packages ./packages ··· 19 18 # Install dependencies 20 19 RUN bun install --frozen-lockfile 21 20 22 - # Build the hosting service 23 - WORKDIR /app/apps/hosting-service 24 - RUN bun run build 21 + # Compile to a single binary 22 + RUN bun build --compile --minify apps/hosting-service/src/index.ts --outfile /app/hosting 25 23 26 - # Stage 2: Production 27 - FROM node:22-alpine AS production 24 + # Stage 2: Minimal runtime 25 + FROM alpine:3.22 28 26 29 - WORKDIR /app 27 + RUN apk add --no-cache libstdc++ libgcc 30 28 31 - # Copy only the built file 32 - COPY --from=builder /app/apps/hosting-service/dist/index.js ./index.js 29 + COPY --from=builder /app/hosting /usr/local/bin/hosting 33 30 34 31 # Create cache directory 35 - RUN mkdir -p ./cache/sites 32 + RUN mkdir -p /cache/sites 36 33 37 - # Set environment variables 38 34 ENV PORT=3001 39 35 ENV NODE_ENV=production 36 + ENV CACHE_DIR=/cache/sites 40 37 41 - # Expose the application port 42 38 EXPOSE 3001 43 39 44 - # Health check 45 40 HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ 46 41 CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1 47 42 48 - # Start the application 49 - CMD ["node", "index.js"] 43 + CMD ["hosting"]
+1 -1
apps/hosting-service/build.ts
··· 3 3 const result = await Bun.build({ 4 4 entrypoints: ['./src/index.ts'], 5 5 outdir: './dist', 6 - target: 'node', 6 + target: 'bun', 7 7 format: 'esm', 8 8 minify: process.env.NODE_ENV === 'production', 9 9 sourcemap: 'external',
+2 -5
apps/hosting-service/package.json
··· 3 3 "version": "1.0.0", 4 4 "type": "module", 5 5 "scripts": { 6 - "dev": "NODE_OPTIONS='--max-old-space-size=2048' tsx --env-file=.env src/index.ts", 6 + "dev": "bun --env-file=.env src/index.ts", 7 7 "build": "bun run build.ts", 8 - "start": "NODE_OPTIONS='--max-old-space-size=2048' tsx src/index.ts", 8 + "start": "bun src/index.ts", 9 9 "check": "tsc --noEmit" 10 10 }, 11 11 "dependencies": { ··· 14 14 "@atproto/lexicon": "^0.5.2", 15 15 "@atproto/sync": "^0.1.36", 16 16 "@atproto/xrpc": "^0.7.5", 17 - "@hono/node-server": "^1.19.6", 18 17 "@wispplace/atproto-utils": "workspace:*", 19 18 "@wispplace/constants": "workspace:*", 20 19 "@wispplace/database": "workspace:*", ··· 32 31 "devDependencies": { 33 32 "@types/bun": "^1.3.1", 34 33 "@types/mime-types": "^2.1.4", 35 - "@types/node": "^22.10.5", 36 - "tsx": "^4.19.2", 37 34 "typescript": "^5.9.3" 38 35 } 39 36 }
+4 -5
apps/hosting-service/src/index.ts
··· 1 1 import app from './server'; 2 - import { serve } from '@hono/node-server'; 3 2 import { initializeGrafanaExporters, createLogger } from '@wispplace/observability'; 4 3 import { mkdirSync, existsSync } from 'fs'; 5 4 import { closeDatabase, CACHE_ONLY } from './lib/db'; ··· 56 55 }); 57 56 }); 58 57 59 - // Start HTTP server with Node.js adapter 60 - const server = serve({ 58 + // Start HTTP server with Bun's native server 59 + const server = Bun.serve({ 61 60 fetch: app.fetch, 62 61 port: PORT, 63 62 }); ··· 92 91 await stopCacheInvalidationSubscriber(); 93 92 await closeRevalidateQueue(); 94 93 await closeDatabase(); 95 - server.close(); 94 + server.stop(true); 96 95 process.exit(0); 97 96 }); 98 97 ··· 102 101 await stopCacheInvalidationSubscriber(); 103 102 await closeRevalidateQueue(); 104 103 await closeDatabase(); 105 - server.close(); 104 + server.stop(true); 106 105 process.exit(0); 107 106 });
+1 -10
bun.lock
··· 51 51 "@atproto/lexicon": "^0.5.2", 52 52 "@atproto/sync": "^0.1.36", 53 53 "@atproto/xrpc": "^0.7.5", 54 - "@hono/node-server": "^1.19.6", 55 54 "@wispplace/atproto-utils": "workspace:*", 56 55 "@wispplace/constants": "workspace:*", 57 56 "@wispplace/database": "workspace:*", ··· 69 68 "devDependencies": { 70 69 "@types/bun": "^1.3.1", 71 70 "@types/mime-types": "^2.1.4", 72 - "@types/node": "^22.10.5", 73 - "tsx": "^4.19.2", 74 71 "typescript": "^5.9.3", 75 72 }, 76 73 }, ··· 2026 2023 2027 2024 "wisp-hosting-service/@atproto/lexicon": ["@atproto/lexicon@0.5.2", "", { "dependencies": { "@atproto/common-web": "^0.4.4", "@atproto/syntax": "^0.4.1", "iso-datestring-validator": "^2.2.2", "multiformats": "^9.9.0", "zod": "^3.23.8" } }, "sha512-lRmJgMA8f5j7VB5Iu5cp188ald5FuI4FlmZ7nn6EBrk1dgOstWVrI5Ft6K3z2vjyLZRG6nzknlsw+tDP63p7bQ=="], 2028 2025 2029 - "wisp-hosting-service/@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="], 2026 + "wisp-hosting-service/@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="], 2030 2027 2031 2028 "wisp-hosting-service/@types/mime-types": ["@types/mime-types@2.1.4", "", {}, "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w=="], 2032 - 2033 - "wisp-hosting-service/@types/node": ["@types/node@22.19.7", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw=="], 2034 2029 2035 2030 "wisp-hosting-service/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], 2036 2031 ··· 2271 2266 "wisp-hosting-service/@atproto/api/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 2272 2267 2273 2268 "wisp-hosting-service/@atproto/lexicon/multiformats": ["multiformats@9.9.0", "", {}, "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg=="], 2274 - 2275 - "wisp-hosting-service/@types/bun/bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], 2276 - 2277 - "wisp-hosting-service/@types/node/undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], 2278 2269 2279 2270 "wisp-hosting-service/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], 2280 2271
+6
cli/README.md
··· 6 6 bun run index.ts --help 7 7 ``` 8 8 9 + Deploying a site 10 + ```bash 11 + bun run index.ts deploy alice.bsky.social --path . --site my-blog 12 + bun run index.ts alice.bsky.social --path . --site my-blog 13 + ``` 14 + 9 15 List domains for an account: 10 16 11 17 ```bash