|
| 1 | +# AGENTS.md |
| 2 | + |
| 3 | +This file provides guidance to the agents when working with code in this repository. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +This is a monorepo for the Supabase Flutter SDK, managed by [Melos](https://melos.invertase.dev/). It contains multiple independently versioned packages that provide Flutter and Dart clients for Supabase services. |
| 8 | + |
| 9 | +## Package Architecture |
| 10 | + |
| 11 | +The repository follows a layered dependency structure: |
| 12 | + |
| 13 | +- **supabase_flutter**: Flutter-specific wrapper with platform integrations (deep links, local storage, app lifecycle) |
| 14 | +- **supabase**: Core Dart client that orchestrates all service clients |
| 15 | +- **gotrue**: Authentication client (sessions, JWT, OAuth) |
| 16 | +- **postgrest**: Database query client with ORM-style API |
| 17 | +- **realtime_client**: WebSocket client for real-time subscriptions |
| 18 | +- **storage_client**: File storage client with retry logic |
| 19 | +- **functions_client**: Edge functions invocation client |
| 20 | +- **yet_another_json_isolate**: JSON parsing in separate isolate for performance |
| 21 | + |
| 22 | +Key architectural patterns: |
| 23 | +- `SupabaseClient` is a facade that initializes and coordinates all sub-clients |
| 24 | +- `AuthHttpClient` wraps HTTP requests to inject JWT tokens automatically |
| 25 | +- Builder/fluent interface pattern for query construction (`from().select().eq()`) |
| 26 | +- Stream-based reactive pattern using RxDart `BehaviorSubject` |
| 27 | +- Platform-specific code via conditional imports (web vs native) |
| 28 | + |
| 29 | +## Development Setup |
| 30 | + |
| 31 | +```bash |
| 32 | +# Install Melos globally (if not already installed) |
| 33 | +dart pub global activate melos |
| 34 | + |
| 35 | +# Bootstrap dependencies for all packages |
| 36 | +melos bootstrap |
| 37 | +# or shorthand: |
| 38 | +melos bs |
| 39 | +``` |
| 40 | + |
| 41 | +## Common Commands |
| 42 | + |
| 43 | +### Linting and Formatting |
| 44 | + |
| 45 | +```bash |
| 46 | +# Run all static analysis checks (analyze + format) |
| 47 | +melos run lint:all |
| 48 | + |
| 49 | +# Run analyzer on all packages |
| 50 | +melos run analyze |
| 51 | + |
| 52 | +# Format code (80 char line length) |
| 53 | +melos run format |
| 54 | +``` |
| 55 | + |
| 56 | +### Testing |
| 57 | + |
| 58 | +Most packages have unit tests. The `postgrest`, `gotrue`, and `storage_client` packages require Docker services. |
| 59 | + |
| 60 | +**For packages requiring Docker (postgrest, gotrue, storage_client):** |
| 61 | + |
| 62 | +```bash |
| 63 | +# 1. Start Docker services |
| 64 | +cd infra/<package> |
| 65 | +docker compose up -d |
| 66 | + |
| 67 | +# 2. Run tests (from package directory) |
| 68 | +cd ../../packages/<package> |
| 69 | +dart test -j 1 |
| 70 | + |
| 71 | +# 3. Stop Docker services when done |
| 72 | +cd ../../infra/<package> |
| 73 | +docker compose down |
| 74 | +``` |
| 75 | + |
| 76 | +The `-j 1` flag runs tests sequentially (not concurrently), which is required since tests share the same Docker services. |
| 77 | + |
| 78 | +**For packages without Docker requirements:** |
| 79 | + |
| 80 | +```bash |
| 81 | +# Run tests from package directory |
| 82 | +cd packages/<package> |
| 83 | +dart test |
| 84 | +``` |
| 85 | + |
| 86 | +**Run tests with coverage:** |
| 87 | + |
| 88 | +```bash |
| 89 | +# From root or package directory |
| 90 | +melos run test:coverage |
| 91 | +``` |
| 92 | + |
| 93 | +### Running a Single Test File |
| 94 | + |
| 95 | +```bash |
| 96 | +# From package directory |
| 97 | +dart test test/specific_test.dart |
| 98 | + |
| 99 | +# For a specific test case |
| 100 | +dart test test/specific_test.dart -n "test name pattern" |
| 101 | +``` |
| 102 | + |
| 103 | +### Package Management |
| 104 | + |
| 105 | +```bash |
| 106 | +# Upgrade dependencies across all packages |
| 107 | +melos run upgrade |
| 108 | + |
| 109 | +# Check for outdated dependencies |
| 110 | +melos run outdated |
| 111 | +``` |
| 112 | + |
| 113 | +### Version Management |
| 114 | + |
| 115 | +```bash |
| 116 | +# Update version.dart files for all packages |
| 117 | +melos run update-version |
| 118 | + |
| 119 | +# Version packages and generate changelogs (handled by melos) |
| 120 | +melos version |
| 121 | +``` |
| 122 | + |
| 123 | +## Key Implementation Details |
| 124 | + |
| 125 | +### Authentication Flow |
| 126 | + |
| 127 | +- **GoTrueClient** manages sessions, tokens, and JWT validation |
| 128 | +- Emits auth state changes via `Stream<AuthState>` |
| 129 | +- **supabase_flutter** adds session persistence via `SharedPreferences` (mobile) or browser localStorage (web) |
| 130 | +- Deep link handling for OAuth callbacks (detects `?code=` for PKCE or `#access_token=` for implicit flow) |
| 131 | +- Auth tokens are automatically injected into all HTTP requests via `AuthHttpClient` |
| 132 | +- Realtime client receives token updates when auth state changes |
| 133 | + |
| 134 | +### Query Building |
| 135 | + |
| 136 | +PostgREST queries use a chain of builder classes: |
| 137 | +``` |
| 138 | +PostgrestQueryBuilder → PostgrestFilterBuilder → PostgrestTransformBuilder → ResponsePostgrestBuilder |
| 139 | +``` |
| 140 | + |
| 141 | +Example: `supabase.from('users').select('id, name').eq('id', 1).limit(10)` |
| 142 | + |
| 143 | +### Realtime Architecture |
| 144 | + |
| 145 | +- `SupabaseStreamBuilder` combines initial PostgREST data fetch with realtime updates |
| 146 | +- Uses RxDart `BehaviorSubject` for reactive streams |
| 147 | +- WebSocket maintains persistent connection with 30s heartbeat |
| 148 | +- Auto-reconnect with exponential backoff on disconnect |
| 149 | + |
| 150 | +### Error Handling |
| 151 | + |
| 152 | +Each package has its own exception hierarchy: |
| 153 | +- **gotrue**: `AuthException` (base), with specialized subclasses like `AuthApiException`, `AuthRetryableFetchException` |
| 154 | +- **postgrest**: HTTP-based error responses |
| 155 | +- **realtime**: `RealtimeSubscribeException` with status tracking |
| 156 | +- **storage**: Retry logic with exponential backoff (up to 8 attempts) |
| 157 | + |
| 158 | +### Platform Differences |
| 159 | + |
| 160 | +The codebase uses conditional imports for platform-specific implementations: |
| 161 | +```dart |
| 162 | +import './local_storage_stub.dart' |
| 163 | + if (dart.library.js_interop) './local_storage_web.dart' |
| 164 | +``` |
| 165 | + |
| 166 | +This enables: |
| 167 | +- Native mobile (iOS/Android): SharedPreferences for persistence |
| 168 | +- Web: Browser localStorage |
| 169 | +- Single codebase for all platforms |
| 170 | + |
| 171 | +### Client Configuration |
| 172 | + |
| 173 | +All clients accept options classes for customization: |
| 174 | +- `PostgrestClientOptions`: Custom schema access |
| 175 | +- `AuthClientOptions`: Auto-refresh tokens, PKCE vs implicit flow |
| 176 | +- `StorageClientOptions`: Retry attempts for uploads |
| 177 | +- `FunctionsClientOptions`: Edge function region selection |
| 178 | +- `RealtimeClientOptions`: WebSocket timeout configuration |
| 179 | + |
| 180 | +### URL Structure |
| 181 | + |
| 182 | +The `SupabaseClient` transforms a base URL into service-specific endpoints: |
| 183 | +``` |
| 184 | +supabaseUrl: "https://project.supabase.co" |
| 185 | +├─ REST: "https://project.supabase.co/rest/v1" |
| 186 | +├─ Realtime: "ws://project.supabase.co/realtime/v1" |
| 187 | +├─ Auth: "https://project.supabase.co/auth/v1" |
| 188 | +├─ Storage: "https://project.supabase.co/storage/v1" (or dedicated host) |
| 189 | +└─ Functions: "https://project.supabase.co/functions/v1" |
| 190 | +``` |
| 191 | + |
| 192 | +## Testing Against Local Supabase |
| 193 | + |
| 194 | +For integration testing, you may want to point to a local Supabase instance: |
| 195 | + |
| 196 | +```dart |
| 197 | +await Supabase.initialize( |
| 198 | + url: 'http://localhost:54321', |
| 199 | + anonKey: 'your-local-anon-key', |
| 200 | +); |
| 201 | +``` |
| 202 | + |
| 203 | +## Contributing Guidelines |
| 204 | + |
| 205 | +- Fork the repo and create feature branches |
| 206 | +- Run `melos run lint:all` before committing |
| 207 | +- Ensure tests pass for modified packages |
| 208 | +- Update package changelogs if making notable changes |
| 209 | +- Line length limit is 80 characters |
| 210 | +- Use `dart format` for consistent formatting |
0 commit comments