- Add bunker-worker.js Web Worker for NIP-46 signing
- Update rollup to build worker as separate bundle
- Move bunker state to stores.js for persistence across tab switches
- Worker maintains WebSocket connection independently of UI lifecycle
Files modified:
- app/web/src/bunker-worker.js: New Web Worker implementation
- app/web/src/stores.js: Added bunker worker state management
- app/web/src/BunkerView.svelte: Use worker instead of inline service
- app/web/rollup.config.js: Build worker bundle separately
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add guard to prevent duplicate service starts
- Fix stale variable references in error handler
- Show token list even when WebSocket temporarily disconnects
- Add logging for bunker service status changes
Files modified:
- app/web/src/BunkerView.svelte: UI state fixes
- app/web/dist/bundle.js: Rebuilt web UI
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add FileStore implementation for keyset persistence
- Keysets now survive server restarts
- Store keysets in JSON file at $ORLY_DATA_DIR/cashu-keysets.json
- Tokens issued before restart remain valid
Files modified:
- pkg/cashu/keyset/file_store.go: New file-based keyset store
- app/main.go: Use FileStore instead of MemoryStore
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Each client device now gets its own CAT token
- Tokens can be individually named (editable, defaults to cute names like "jolly-jellyfish")
- Tokens can be individually revoked
- Expandable table rows show QR code and full bunker URL per token
- Separate service token for ORLY's own relay connection
- Add Token button to create additional client tokens
Files modified:
- app/web/src/BunkerView.svelte: Token list UI with expandable details
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add automatic Cashu issuer/verifier initialization when ACL mode is not 'none'
- Use memory store for keyset management with proper TTL configuration
- Import cashuiface package for AllowAllChecker implementation
- ACL handles authorization; CAT provides token-based authentication
Files modified:
- app/main.go: Add Cashu system initialization when ACL active
- pkg/version/version: Bump to v0.44.2
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix binary pubkey/event ID values not being detected by tag.Marshal
- Compact event decoder now returns 33-byte values with null terminator
- This allows tag.Marshal to detect and hex-encode binary values correctly
- Fixes "Could not decode a text frame as UTF-8" WebSocket errors
Files modified:
- pkg/database/compact_event.go: Return 33-byte binary with null terminator
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update handleFavicon to serve /favicon.png instead of non-existent orly-favicon.png
- Remove orly-favicon.png from rollup copy targets
- Update release command to include setcap before restart
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add web app manifest for standalone installation
- Add service worker with offline-first caching for static assets
- Add network-first caching with fallback for API calls
- Generate PWA icons (192x192, 512x512) from favicon
- Add Apple PWA meta tags for iOS support
- Update rollup config to copy PWA files to dist
Files modified:
- app/web/public/manifest.json: New PWA manifest
- app/web/public/sw.js: New service worker
- app/web/public/icon-192.png: New PWA icon
- app/web/public/icon-512.png: New PWA icon
- app/web/public/index.html: Add manifest link, meta tags, SW registration
- app/web/rollup.config.js: Add PWA files to copy targets
- pkg/version/version: Bump to v0.43.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Enforce Cashu access token for kind 24133 events when Cashu is enabled and ACL is active
- Reject NIP-46 events without valid token with "restricted: NIP-46 requires Cashu access token"
- Verify token scope is NIP-46 or RELAY
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add BunkerView with two QR codes: client (bunker://) and signer (nostr+connect://)
- Add click-to-copy functionality on QR codes with visual "Copied!" feedback
- Add CAT requirement warning (only shows when ACL mode is active)
- Remove WireGuard dependencies from bunker page
- Add /api/bunker/info public endpoint for relay URL, ACL mode, CAT status
- Add Cashu token verification for WebSocket connections
- Add kind permission checking for Cashu token scopes
- Add cashuToken field to Listener for connection-level token tracking
Files modified:
- app/handle-bunker.go: New bunker info endpoint (without WireGuard)
- app/handle-event.go: Add Cashu token kind permission check
- app/handle-websocket.go: Extract and verify Cashu token on WS upgrade
- app/listener.go: Add cashuToken field
- app/server.go: Register bunker info endpoint
- app/web/src/BunkerView.svelte: Complete rewrite with QR codes
- app/web/src/api.js: Add getBunkerInfo() function
- pkg/version/version: Bump to v0.41.0
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update release command to push to git.mleku.dev using gitmlekudev SSH key
- Add release process documentation to README.md
Files modified:
- .claude/commands/release.md: Add GIT_SSH_COMMAND push to git.mleku.dev
- README.md: Document release process and SSH key configuration
- pkg/version/version: Bump to v0.40.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add embedded WireGuard VPN server using wireguard-go + netstack
- Implement deterministic /31 subnet allocation from seed + sequence
- Use Badger's built-in Sequence for atomic counter allocation
- Add NIP-46 bunker server for remote signing over VPN
- Add revoked key tracking and access audit logging for users
- Add Bunker tab to web UI with WireGuard/bunker QR codes
- Support key regeneration with old keypair archiving
New environment variables:
- ORLY_WG_ENABLED: Enable WireGuard VPN server
- ORLY_WG_PORT: UDP port for WireGuard (default 51820)
- ORLY_WG_ENDPOINT: Public endpoint for WireGuard
- ORLY_WG_NETWORK: Base network for subnet pool (default 10.0.0.0/8)
- ORLY_BUNKER_ENABLED: Enable NIP-46 bunker
- ORLY_BUNKER_PORT: WebSocket port for bunker (default 3335)
Files added:
- pkg/wireguard/: WireGuard server, keygen, subnet pool, errors
- pkg/bunker/: NIP-46 bunker server and session handling
- pkg/database/wireguard.go: Peer storage with audit logging
- app/handle-wireguard.go: API endpoints for config/regenerate/audit
- app/wireguard-helpers.go: Key derivation helpers
- app/web/src/BunkerView.svelte: Bunker UI with QR codes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix base64 encoding to use URL-safe format (- instead of +, _ instead of /)
- Remove padding characters (=) from base64 output
- Apply fix to LogView, BlossomView, and api.js
Files modified:
- app/web/src/LogView.svelte: URL-safe base64 for NIP-98 auth
- app/web/src/BlossomView.svelte: URL-safe base64 for Blossom auth
- app/web/src/api.js: URL-safe base64 for NIP-98 auth
- pkg/version/version: Bump to v0.39.2
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Include query parameters in signed NIP-98 auth URL
- Auth event URL must match actual request URL including ?offset=&limit=
Files modified:
- app/web/src/LogView.svelte: Fix auth URL to include query params
- pkg/version/version: Bump to v0.39.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The lol library outputs logs in format:
1703500000000000ℹ️ message /path/to/file.go:123
Where:
- Timestamp is Unix microseconds
- Level is emoji (☠️🚨⚠️ℹ️🔎👻)
- Message text
- File:line location
Updated parser to correctly parse this format.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Reinitialize lol loggers after wrapping Writer with BufferedWriter
- The lol.Main logger was initialized in init() with os.Stderr directly,
bypassing the Writer variable, so we now recreate it with the wrapped Writer
- Log level changes now properly affect both the buffer and syslog output
Files modified:
- app/config/config.go: Reinitialize loggers after BufferedWriter setup
- pkg/logbuffer/writer.go: Remove unused stub function
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Show full npub on screens > 720px, truncated on smaller screens
- Make admin users list extend to full width
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use box-sizing instead of explicit width to fix right edge overflow
Files modified:
- pkg/version/version: Bump to v0.37.1
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Make Blossom view use full available width
- Add "Upload new files" label with Select Files button on right
- Show image/video thumbnails in file list (48x48px)
- Add emoji icons for audio (🎵) and documents (📄)
- Show full hash on screens > 720px, truncated on smaller
Files modified:
- app/web/src/BlossomView.svelte: UI layout and thumbnail changes
- app/web/dist/*: Rebuilt bundle
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Track bundle.js, bundle.css, and all dist assets in git
- Previously only index.html was tracked, breaking VPS deployments
- Remove debug logging from BlossomView
Files modified:
- app/web/dist/*: Add all build assets to git tracking
- app/web/src/BlossomView.svelte: Remove debug code
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add console.log to trace currentEffectiveRole value in BlossomView
- Add HTML comment showing role and isAdmin values for debugging
Files modified:
- app/web/src/BlossomView.svelte: Add debug logging for role detection
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update deploy command to build to ~/.local/bin/next.orly.dev
- Service uses this path, not ./orly in project directory
Files modified:
- .claude/commands/release.md: Fixed binary output path for VPS deploy
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Change version link color from muted to readable text color
- Add background color hover effect matching tab styling
- Replace Gitea icon with mug-and-leaf icon
- Rename CSS class from gitea-icon to version-icon
Files modified:
- app/web/src/Sidebar.svelte: Updated version link styling and icon
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add version footer to sidebar bottom-left with Gitea icon link
- Fetch relay version from NIP-11 relay info document
- Link opens https://next.orly.dev in new tab
- Responsive design hides version text on medium screens
Files modified:
- app/web/src/api.js: Add fetchRelayInfo() function
- app/web/src/Sidebar.svelte: Add version display with Gitea SVG icon
- app/web/src/App.svelte: Add relayVersion state and fetch on init
- pkg/version/version: Bump to v0.36.18
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add generic LRUCache[K, V] implementation using container/list for O(1) ops
- Replace random 50% eviction with proper LRU eviction in SerialCache
- Cache now starts empty and grows on demand up to configured limits
- Use [32]byte keys instead of string([]byte) to avoid allocation overhead
- Single-entry eviction at capacity instead of 50% bulk clearing
- Add comprehensive unit tests and benchmarks for LRUCache
- Benchmarks show ~32-34 ns/op with 0 allocations for Get/Put
Files modified:
- pkg/database/lrucache.go: New generic LRU cache implementation
- pkg/database/lrucache_test.go: Unit tests and benchmarks
- pkg/database/serial_cache.go: Refactored to use LRUCache
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add buffer pool (pkg/database/bufpool) with SmallPool (64B) and MediumPool (1KB)
for reusing bytes.Buffer instances on hot paths
- Fix escape analysis in index types (uint40, letter, word) by using fixed-size
arrays instead of make() calls that escape to heap
- Add handler concurrency limiter (ORLY_MAX_HANDLERS_PER_CONN, default 100) to
prevent unbounded goroutine growth under WebSocket load
- Add pre-allocation hints to Uint40s.Union/Intersection/Difference methods
- Update compact_event.go, save-event.go, serial_cache.go, and
get-indexes-for-event.go to use pooled buffers
Files modified:
- app/config/config.go: Add MaxHandlersPerConnection config
- app/handle-websocket.go: Initialize handler semaphore
- app/listener.go: Add semaphore acquire/release in messageProcessor
- pkg/database/bufpool/pool.go: New buffer pool package
- pkg/database/compact_event.go: Use buffer pool, fix escape analysis
- pkg/database/get-indexes-for-event.go: Reuse single buffer for all indexes
- pkg/database/indexes/types/letter.go: Fixed array in UnmarshalRead
- pkg/database/indexes/types/uint40.go: Fixed arrays, pre-allocation hints
- pkg/database/indexes/types/word.go: Fixed array in UnmarshalRead
- pkg/database/save-event.go: Use buffer pool for key encoding
- pkg/database/serial_cache.go: Use buffer pool for lookups
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace tea CLI with direct Gitea API calls
- Add release ID extraction and validation
- Upload assets via API with proper error handling
- Add release verification step
Files modified:
- .gitea/workflows/go.yml: Direct API release creation
- pkg/version/version: Bump to v0.36.14
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add set -e to all steps to fail fast on errors
- Add debug output for environment variables in checkout step
- Log more context to help diagnose CI failures
Files modified:
- .gitea/workflows/go.yml: Comprehensive error handling
- pkg/version/version: Bump to v0.36.13
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add set -e to exit on any error
- Validate GITEA_TOKEN secret is set before proceeding
- Verify release binaries exist before upload attempt
- Remove error-suppressing || echo patterns
- Add login verification step
Files modified:
- .gitea/workflows/go.yml: Proper error handling for release creation
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add proper CORS headers for Blossom endpoints including X-SHA-256,
X-Content-Length, X-Content-Type headers required by blossom-client-sdk
- Add root-level Blossom routes (/upload, /media, /mirror, /report, /list/)
for clients like Jumble that expect Blossom at root
- Export BaseURLKey from pkg/blossom for use by app handlers
- Make blossomRootHandler return URLs with /blossom prefix so blob
downloads work via the registered /blossom/ route
- Remove Access-Control-Allow-Credentials header (not needed for * origin)
- Add Access-Control-Expose-Headers for X-Reason and other response headers
Files modified:
- app/blossom.go: Add blossomRootHandler, use exported BaseURLKey
- app/server.go: Add CORS handling for blossom paths, register root routes
- pkg/blossom/server.go: Fix CORS headers, export BaseURLKey
- pkg/blossom/utils.go: Minor formatting
- pkg/version/version: Bump to v0.36.12
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add unicode_normalize.go with mappings for small caps and fraktur
- Map 77 decorative unicode characters to ASCII equivalents:
- Small caps (25 chars): ᴅᴇᴀᴛʜ → death
- Fraktur lowercase (26 chars): 𝔡𝔢𝔞𝔱𝔥 → death
- Fraktur uppercase (26 chars): 𝔇𝔈𝔄𝔗ℌ → death
- Fix broken utf8DecodeRuneInString() that failed on multi-byte UTF-8
- Add migration v7 to rebuild word indexes with normalization
- Add comprehensive unit tests for all character mappings
Files modified:
- pkg/database/unicode_normalize.go: New - character mapping tables
- pkg/database/unicode_normalize_test.go: New - unit tests
- pkg/database/tokenize.go: Integrate normalizeRune(), fix UTF-8 decoder
- pkg/database/migrations.go: Add version 7 migration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove redundant permission entries from .claude/settings.local.json
- Bump version to v0.36.8
Files modified:
- .claude/settings.local.json: Cleanup old permissions
- pkg/version/version: v0.36.7 -> v0.36.8
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>