mobile bluesky app made with flutter lazurite.stormlightlabs.org/
mobile bluesky flutter
at main 212 lines 7.6 kB view raw view rendered
1# Developer Tooling 2 3Lazurite includes two developer-focused features: an internal debug overlay for development 4and user-facing ATProto DevTools similar to [pdsls.dev](https://pdsls.dev/). 5 6## Overview 7 8| Feature | Availability | Purpose | 9| ---------------- | --------------- | ------------------------------------------------------ | 10| Debug Overlay | kDebugMode only | System diagnostics, network inspection, session info | 11| ATProto DevTools | All builds | Repository exploration, record inspection, JSON viewer | 12 13Both features share database tables but serve different audiences. The debug overlay helps 14developers diagnose issues during development. DevTools let power users explore their 15ATProto repository data. 16 17## Debug Overlay (Internal) 18 19### Activation 20 21Available only in Flutter debug builds (`kDebugMode == true`). 22 23- **Desktop:** ALT+F12 24- **Mobile:** 2-finger long-press for 2 seconds 25 26The overlay appears as a sliding drawer from the right edge. 27 28### Architecture 29 30**DebugOverlayHost** (`lib/src/features/debug/presentation/debug_overlay_host.dart`) 31wraps the entire app when in debug mode. It listens for activation gestures and renders 32the overlay as a Stack layer above the main content. 33 34**DebugOverlayController** (`lib/src/features/debug/application/debug_overlay_controller.dart`) 35manages visibility state and active tab selection via Riverpod StateNotifier. 36 37### Tabs 38 39**System Info** - Flutter version, platform, screen dimensions, memory usage 40 41**ATProto Session** - Current DID, handle, PDS host, session validity (tokens never shown) 42 43**Network Inspector** - Recent XRPC calls with method, status, duration. Captured by 44`DebugNetworkInterceptor` attached to Dio. Logs stored in `dev_network_logs` table with 45LRU eviction at 1000 entries. 46 47### Network Interception 48 49The interceptor (`lib/src/features/debug/infrastructure/debug_network_interceptor.dart`) 50captures all Dio requests/responses and persists them to the database. 51 52Security: Authorization headers must be redacted before storage. The interceptor should 53replace token values with `Bearer ***` to prevent accidental exposure. 54 55## ATProto DevTools (User-Facing) 56 57### Purpose 58 59Provide transparency into the user's ATProto repository. Users can browse collections, 60inspect records, and understand the underlying data structure. Read-only by default. 61 62### Access Control 63 64Gated by Settings toggle (stored in `dev_settings` table): 65 66- **Enable Developer Tools** - Shows DevTools in navigation 67- **Allow viewing other repos** - Enables browsing public DIDs beyond own repo 68- **Enable record editing** - Triple-gated write mode (deferred to parking lot) 69 70### Routes 71 72```text 73/devtools → DevToolsHomePage 74/devtools/collections → CollectionsPage 75/devtools/:collection → RecordsPage 76/devtools/:collection/:rkey → RecordDetailPage 77``` 78 79All routes check the enabled toggle before rendering content. 80 81### Feature Structure 82 83```sh 84lib/src/features/developer_tools/ 85├── application/ 86│ ├── devtools_providers.dart # Riverpod providers 87│ └── dev_settings_providers.dart # Settings state 88├── domain/ 89│ ├── repo_collection.dart # Collection model 90│ └── repo_record.dart # Record model with AT URI parsing 91├── infrastructure/ 92│ └── devtools_repository.dart # ATProto API calls 93└── presentation/screens/ 94 ├── dev_tools_home_page.dart # Entry point, DID display 95 ├── collections_page.dart # Collection browser with search 96 ├── records_page.dart # Paginated record list 97 └── record_detail_page.dart # JSON tree viewer 98``` 99 100### Providers 101 102**devtoolsRepositoryProvider** - Repository wrapping XrpcClient for ATProto calls 103 104**collectionsProvider** - Fetches collections via `com.atproto.repo.describeRepo` 105 106**recordsProvider** - AsyncNotifierFamily for paginated records with cursor support 107 108**recordDetailProvider** - Fetches single record by collection + rkey 109 110**pinnedUrisProvider** - Streams pinned collections and records from database 111 112### Repository Methods 113 114`DevtoolsRepository` (`lib/src/features/developer_tools/infrastructure/devtools_repository.dart`) 115calls the user's PDS directly without the `atproto-proxy` header: 116 117- `describeRepo(did)` - List collections for a DID 118- `listRecords(repo, collection, limit, cursor)` - Paginated record list 119- `getRecord(repo, collection, rkey)` - Single record fetch 120 121Write methods (`createRecord`, `putRecord`, `deleteRecord`) exist in the spec but are 122not implemented pending write mode feature. 123 124### UI Components 125 126**CollectionsPage** - Searchable list with pin/unpin toggle. Tapping navigates to records. 127 128**RecordsPage** - Infinite scroll with cursor pagination. Rich previews for known types 129(posts, profiles, follows, likes). Pin button per record. 130 131**RecordDetailPage** - Metadata card (AT URI, CID, indexedAt) with copy buttons. JSON tree 132viewer using `flutter_json` package. Blob detection shows thumbnail previews for images. 133 134### Rich Previews 135 136Records are displayed with type-specific previews: 137 138- `app.bsky.feed.post` - Text content and createdAt timestamp 139- `app.bsky.actor.profile` - Display name and description 140- `app.bsky.graph.follow` - Target subject DID 141- `app.bsky.feed.like` - Liked subject URI 142- Unknown types - Fallback to generic JSON snippet 143 144## Database Schema 145 146Four tables in `lib/src/infrastructure/db/tables.dart`: 147 148**DevSettings** - Key-value store for feature toggles (enabled, allowOtherRepos, 149enableRecordEditing, maxCachedJsonBytes) 150 151**DevNetworkLogs** - Network request/response capture with uuid, method, url, statusCode, 152durationMs, headers, body, timestamp 153 154**DevPins** - Pinned collections and records with uri, label, type, createdAt 155 156**DevRecentRecords** - Recently viewed records with uri, cid, viewedAt (schema expansion 157planned for JSON caching) 158 159### DAO 160 161`DevToolsDao` (`lib/src/infrastructure/db/daos/dev_tools_dao.dart`) provides: 162 163- Settings: `getSetting()`, `setSetting()` 164- Network logs: `logRequest()`, `watchLogs()`, `clearLogs()`, `pruneLogs()` 165- Pins: `savePin()`, `deletePin()`, `watchPins()` 166- Recent records: `addRecentRecord()`, `watchRecentRecords()`, `pruneRecentRecords()` 167 168## Security Boundaries 169 170### Secrets Protection 171 172Never display or log: 173 174- Access tokens or refresh tokens 175- DPoP private keys 176- Secure storage keys 177 178Network logs must redact Authorization header values. 179 180### Other DID Inspection 181 182When viewing other users' repos: 183 184- Read-only operations only (describeRepo, listRecords, getRecord) 185- Display banner indicating public data view 186- Never call write endpoints for other DIDs 187 188### Defensive JSON Rendering 189 190Records may contain hostile or malformed JSON: 191 192- Limit tree depth to 50 levels 193- Truncate long strings in preview (1000 chars) 194- Handle deeply nested objects gracefully 195- Escape HTML entities in string values 196 197## Remaining Work (as of 2026-01-26) 198 199- Performance metrics tab in debug overlay 200- Settings toggle UI exposure 201- Other DID inspection feature 202- DevRecentRecords schema enhancement 203- Filter/sort controls in records list 204- File export functionality 205- Authorization header redaction 206 207## References 208 209- [pdsls.dev](https://pdsls.dev/) - ATProto explorer by @juli.ee 210- [com.atproto.repo.listRecords](https://docs.bsky.app/docs/api/com-atproto-repo-list-records) 211- [com.atproto.repo.getRecord](https://docs.bsky.app/docs/api/com-atproto-repo-get-record) 212- [AT Protocol Repository Spec](https://atproto.com/specs/repository)