fix cookie routing
68 unmodified lines6970717273737475767726 unmodified lines10410510610710810911011110810911011111211311411565 unmodified lines68 unmodified lines id: Bun.env.NODE_ENV !== 'production' ? undefined : null, }, cookie: { secrets: cookieSecret, sign: true sign: ['did'] } }) // Observability middleware .onBeforeHandle(observabilityMiddleware('main-app').beforeHandle)26 unmodified lines }) .onError(observabilityMiddleware('main-app').onError) .use(csrfProtection()) .use(authRoutes(client, cookieSecret)) .use(wispRoutes(client)) .use(domainRoutes(client)) .use(userRoutes(client)) .use(siteRoutes(client)) .use(wispRoutes(client, cookieSecret)) .use(domainRoutes(client, cookieSecret)) .use(userRoutes(client, cookieSecret)) .use(siteRoutes(client, cookieSecret)) .use(adminRoutes(cookieSecret)) .use( await staticPlugin({ prefix: '/'65 unmodified lines3 unmodified lines4567889101112131415161760 unmodified lines78798081777879808182838283848517 unmodified lines10310410510610911011111211311411510710810911011 unmodified lines1221231241251351361371381391401411263 unmodified linesimport { syncSitesFromPDS } from '../lib/sync-sites'import { authenticateRequest } from '../lib/wisp-auth'import { logger } from '../lib/observability'
export const authRoutes = (client: NodeOAuthClient, cookieSecret: string) => new Elysia()export const authRoutes = (client: NodeOAuthClient, cookieSecret: string) => new Elysia({ cookie: { secrets: cookieSecret, sign: ['did'] } }) .post('/api/auth/signin', async (c) => { let handle = 'unknown' try { const body = c.body as { handle: string }60 unmodified lines logger.error('[Auth] OAuth callback error', err) c.cookie.did.remove() return c.redirect('/?error=auth_failed') } }, { cookie: t.Cookie({ did: t.Optional(t.String()) }, { secrets: cookieSecret, sign: ['did'] }) }) .post('/api/auth/logout', async (c) => { try { const cookieSession = c.cookie17 unmodified lines } catch (err) { logger.error('[Auth] Logout error', err) return { error: 'Logout failed' } } }, { cookie: t.Cookie({ did: t.Optional(t.String()) }, { secrets: cookieSecret, sign: ['did'] }) }) .get('/api/auth/status', async (c) => { try { const auth = await authenticateRequest(client, c.cookie)11 unmodified lines logger.error('[Auth] Status check error', err) c.cookie.did.remove() return { authenticated: false } } }, { cookie: t.Cookie({ did: t.Optional(t.String()) }, { secrets: cookieSecret, sign: ['did'] }) })22 unmodified lines232425262728272829303132333435363738359 unmodified linesExpand all22 unmodified linesimport { createHash } from 'crypto'import { verifyCustomDomain } from '../lib/dns-verify'import { logger } from '../lib/logger'
export const domainRoutes = (client: NodeOAuthClient) => new Elysia({ prefix: '/api/domain' })export const domainRoutes = (client: NodeOAuthClient, cookieSecret: string) => new Elysia({ prefix: '/api/domain', cookie: { secrets: cookieSecret, sign: ['did'] } }) // Public endpoints (no auth required) .get('/check', async ({ query }) => { try { const handle = (query.handle || "")359 unmodified linesExpand all3 unmodified lines456789891011121314151617181947 unmodified lines3 unmodified linesimport { Agent } from '@atproto/api'import { deleteSite } from '../lib/db'import { logger } from '../lib/logger'
export const siteRoutes = (client: NodeOAuthClient) => new Elysia({ prefix: '/api/site' })export const siteRoutes = (client: NodeOAuthClient, cookieSecret: string) => new Elysia({ prefix: '/api/site', cookie: { secrets: cookieSecret, sign: ['did'] } }) .derive(async ({ cookie }) => { const auth = await requireAuth(client, cookie) return { auth } })47 unmodified lines11234567891091011121314151617181920100 unmodified linesimport { Elysia } from 'elysia'import { Elysia, t } from 'elysia'import { requireAuth } from '../lib/wisp-auth'import { NodeOAuthClient } from '@atproto/oauth-client-node'import { Agent } from '@atproto/api'import { getSitesByDid, getDomainByDid, getCustomDomainsByDid, getWispDomainInfo, getDomainsBySite, getAllWispDomains } from '../lib/db'import { syncSitesFromPDS } from '../lib/sync-sites'import { logger } from '../lib/logger'
export const userRoutes = (client: NodeOAuthClient) => new Elysia({ prefix: '/api/user' })export const userRoutes = (client: NodeOAuthClient, cookieSecret: string) => new Elysia({ prefix: '/api/user', cookie: { secrets: cookieSecret, sign: ['did'] } }) .derive(async ({ cookie }) => { const auth = await requireAuth(client, cookie) return { auth } })100 unmodified lines35 unmodified lines363738394041404142434445464748495051382 unmodified linesExpand all35 unmodified lines
return true;}
export const wispRoutes = (client: NodeOAuthClient) => new Elysia({ prefix: '/wisp' })export const wispRoutes = (client: NodeOAuthClient, cookieSecret: string) => new Elysia({ prefix: '/wisp', cookie: { secrets: cookieSecret, sign: ['did'] } }) .derive(async ({ cookie }) => { const auth = await requireAuth(client, cookie) return { auth } })382 unmodified linesExpand all14 unmodified lines151617181919202122237 unmodified lines313233343535363738394041424344454647394849505152535455564857585960615 unmodified lines676869706271727374755 unmodified lines818283847685868788899091929394959697989910010110210310410583106107108868710911011189901121131149211511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716841 unmodified lines21021121221315021421521621721854 unmodified lines27327427527621327727827928028141 unmodified lines14 unmodified lines <Card> <CardHeader> <div className="flex items-center gap-2 mb-2"> <CardTitle>Wisp CLI Tool</CardTitle> <Badge variant="secondary" className="text-xs">v0.1.0</Badge> <Badge variant="secondary" className="text-xs">v0.2.0</Badge> <Badge variant="outline" className="text-xs">Alpha</Badge> </div> <CardDescription> Deploy static sites directly from your terminal7 unmodified lines </p> </div>
<div className="space-y-3"> <h3 className="text-sm font-semibold">Download CLI</h3> <h3 className="text-sm font-semibold">Features</h3> <ul className="text-sm text-muted-foreground space-y-2 list-disc list-inside"> <li><strong>Deploy:</strong> Push static sites directly from your terminal</li> <li><strong>Pull:</strong> Download sites from the PDS for development or backup</li> <li><strong>Serve:</strong> Run a local server with real-time firehose updates</li> </ul> </div>
<div className="space-y-3"> <h3 className="text-sm font-semibold">Download v0.2.0</h3> <div className="grid gap-2"> <div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border"> <a href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-macos-arm64" href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-darwin" target="_blank" rel="noopener noreferrer" className="flex items-center justify-between mb-2" > <span className="font-mono text-sm">macOS (Apple Silicon)</span> <ExternalLink className="w-4 h-4 text-muted-foreground" /> </a> <div className="text-xs text-muted-foreground"> <span className="font-mono">SHA256: 637e325d9668ca745e01493d80dfc72447ef0a889b313e28913ca65c94c7aaae</span> <span className="font-mono">SHA-1: a8c27ea41c5e2672bfecb3476ece1c801741d759</span> </div> </div> <div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border"> <a5 unmodified lines <span className="font-mono text-sm">Linux (ARM64)</span> <ExternalLink className="w-4 h-4 text-muted-foreground" /> </a> <div className="text-xs text-muted-foreground"> <span className="font-mono">SHA256: 01561656b64826f95b39f13c65c97da8bcc63ecd9f4d7e4e369c8ba8c903c22a</span> <span className="font-mono">SHA-1: fd7ee689c7600fc953179ea755b0357c8481a622</span> </div> </div> <div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border"> <a5 unmodified lines <span className="font-mono text-sm">Linux (x86_64)</span> <ExternalLink className="w-4 h-4 text-muted-foreground" /> </a> <div className="text-xs text-muted-foreground"> <span className="font-mono">SHA256: 1ff485b9bcf89bc5721a862863c4843cf4530cbcd2489cf200cb24a44f7865a2</span> <span className="font-mono">SHA-1: 8bca6992559e19e1d29ab3d2fcc6d09b28e5a485</span> </div> </div> <div className="p-3 bg-muted/50 hover:bg-muted rounded-lg transition-colors border border-border"> <a href="https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-windows.exe" target="_blank" rel="noopener noreferrer" className="flex items-center justify-between mb-2" > <span className="font-mono text-sm">Windows (x86_64)</span> <ExternalLink className="w-4 h-4 text-muted-foreground" /> </a> <div className="text-xs text-muted-foreground"> <span className="font-mono">SHA-1: 90ea3987a06597fa6c42e1df9009e9758e92dd54</span> </div> </div> </div> </div>
<div className="space-y-3"> <h3 className="text-sm font-semibold">Basic Usage</h3> <h3 className="text-sm font-semibold">Deploy a Site</h3> <CodeBlock code={`# Download and make executablecurl -O https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-macos-arm64chmod +x wisp-cli-macos-arm64curl -O https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-aarch64-darwinchmod +x wisp-cli-aarch64-darwin
# Deploy your site (will use OAuth)./wisp-cli-macos-arm64 your-handle.bsky.social \\# Deploy your site./wisp-cli-aarch64-darwin deploy your-handle.bsky.social \\ --path ./dist \\ --site my-site --site my-site \\ --password your-app-password
# Your site will be available at:# https://sites.wisp.place/your-handle/my-site`} language="bash" /> </div>
<div className="space-y-3"> <h3 className="text-sm font-semibold">Pull a Site from PDS</h3> <p className="text-xs text-muted-foreground"> Download a site from the PDS to your local machine (uses OAuth authentication): </p> <CodeBlock code={`# Pull a site to a specific directorywisp-cli pull your-handle.bsky.social \\ --site my-site \\ --output ./my-site
# Pull to current directorywisp-cli pull your-handle.bsky.social \\ --site my-site
# Opens browser for OAuth authentication on first run`} language="bash" /> </div>
<div className="space-y-3"> <h3 className="text-sm font-semibold">Serve a Site Locally with Real-Time Updates</h3> <p className="text-xs text-muted-foreground"> Run a local server that monitors the firehose for real-time updates (uses OAuth authentication): </p> <CodeBlock code={`# Serve on http://localhost:8080 (default)wisp-cli serve your-handle.bsky.social \\ --site my-site
# Serve on a custom portwisp-cli serve your-handle.bsky.social \\ --site my-site \\ --port 3000
# Downloads site, serves it, and watches firehose for live updates!`} language="bash" /> </div>
<div className="space-y-3"> <h3 className="text-sm font-semibold">CI/CD with Tangled Spindle</h3> <p className="text-xs text-muted-foreground"> Deploy automatically on every push using{' '} <a41 unmodified lines curl https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux -o wisp-cli chmod +x wisp-cli
# Deploy to Wisp ./wisp-cli \\ ./wisp-cli deploy \\ "$WISP_HANDLE" \\ --path "$SITE_PATH" \\ --site "$SITE_NAME" \\ --password "$WISP_APP_PASSWORD"54 unmodified lines curl https://sites.wisp.place/nekomimi.pet/wisp-cli-binaries/wisp-cli-x86_64-linux -o wisp-cli chmod +x wisp-cli
# Deploy to Wisp ./wisp-cli \\ ./wisp-cli deploy \\ "$WISP_HANDLE" \\ --path "$SITE_PATH" \\ --site "$SITE_NAME" \\ --password "$WISP_APP_PASSWORD"`}41 unmodified lines