mobile bluesky app made with flutter lazurite.stormlightlabs.org/
mobile bluesky flutter
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add network inspector & interceptor

+2186 -23
+9 -8
doc/roadmap.txt
··· 22 22 - [x] Build DebugDrawer with tabs: System Info, ATProto Session 23 23 - [x] System Info Tab: Flutter version, platform, screen size, memory, FPS 24 24 - [x] ATProto Session Tab: DID, handle, PDS host, session status (no tokens) 25 - - [ ] Create DebugNetworkInterceptor for Dio to log XRPC calls 26 - - [ ] Network Inspector Tab: display last 20 XRPC calls, expandable bodies to 25 + - [x] Create DebugNetworkInterceptor for Dio to log XRPC calls 26 + - [x] Network Inspector Tab: display last 20 XRPC calls, expandable bodies to 27 27 view request/response details 28 - - [ ] Add dev_settings table (debugModeEnabled, allowOtherRepos, etc.) 29 - - [ ] Add dev_network_logs table with LRU eviction (1000 in-memory, 24h in DB) 28 + - [x] Add dev_settings table (debugModeEnabled, allowOtherRepos, etc.) 29 + - [x] Add dev_network_logs table with LRU eviction (1000 in-memory, 24h in DB) 30 30 31 - Phase 1: User-Facing DevTools Entry Points (Production builds) 32 - - [ ] Add Settings → "Developer Tools" toggle (works in release builds) 31 + Phase 1: User-Facing "DevTools" 32 + - [ ] Add dev_pins table for pinned collections/records 33 + - [ ] Add dev_recent_records table for LRU cache 33 34 - [ ] Create /devtools route group (always available, not kDebugMode gated) 34 35 - [ ] DevToolsHomePage: show DID, PDS host, quick actions 35 36 - [ ] "Copy my DID" action 37 + - [ ] Add Settings → "Developer Tools" toggle (works in release builds) 36 38 - [ ] Link debug overlay to full DevTools (/devtools routes) 37 - - [ ] Add dev_pins table for pinned collections/records 38 - - [ ] Add dev_recent_records table for LRU cache 39 39 40 40 Phase 2: Repository Browser (Read-Only) 41 41 - [ ] Implement DevtoolsRepository wrapping XrpcClient ··· 317 317 - [ ] Post published 318 318 - [ ] Media attached 319 319 - [ ] Publish failed 320 + 320 321 - [x] DM Accessibility 321 322 - [x] screen reader support (semantic labels) 322 323 - [ ] keyboard navigation (Cmd/Ctrl+Enter to send)
+1 -1
lib/src/features/debug/application/system_info_provider.g.dart
··· 53 53 } 54 54 } 55 55 56 - String _$systemInfoHash() => r'e15ed26cbe812794000a8602487f07c06b65210f'; 56 + String _$systemInfoHash() => r'3d8c64eeada1894c729201718b6e0e226c84455f';
+92
lib/src/features/debug/infrastructure/debug_network_interceptor.dart
··· 1 + import 'dart:convert'; 2 + import 'dart:developer' as developer; 3 + 4 + import 'package:dio/dio.dart'; 5 + import 'package:uuid/uuid.dart'; 6 + 7 + import '../../../infrastructure/db/daos/dev_tools_dao.dart'; 8 + 9 + /// Interceptor that logs network requests to the [DevToolsDao]. 10 + class DebugNetworkInterceptor extends Interceptor { 11 + DebugNetworkInterceptor(this._dao); 12 + 13 + final DevToolsDao _dao; 14 + final _uuid = const Uuid(); 15 + 16 + @override 17 + void onRequest(RequestOptions options, RequestInterceptorHandler handler) { 18 + final uuid = _uuid.v4(); 19 + options.extra['debug_uuid'] = uuid; 20 + options.extra['debug_start_time'] = DateTime.now().millisecondsSinceEpoch; 21 + 22 + // TODO: add pending status & log pending requests, updated on completion 23 + handler.next(options); 24 + } 25 + 26 + @override 27 + void onResponse(Response response, ResponseInterceptorHandler handler) { 28 + _logCompletion(response.requestOptions, response: response); 29 + handler.next(response); 30 + } 31 + 32 + @override 33 + void onError(DioException err, ErrorInterceptorHandler handler) { 34 + _logCompletion(err.requestOptions, error: err); 35 + handler.next(err); 36 + } 37 + 38 + Future<void> _logCompletion( 39 + RequestOptions options, { 40 + Response? response, 41 + DioException? error, 42 + }) async { 43 + try { 44 + final uuid = options.extra['debug_uuid'] as String? ?? _uuid.v4(); 45 + final startTime = 46 + options.extra['debug_start_time'] as int? ?? DateTime.now().millisecondsSinceEpoch; 47 + final endTime = DateTime.now().millisecondsSinceEpoch; 48 + final duration = endTime - startTime; 49 + 50 + final requestHeaders = jsonEncode(options.headers); 51 + final responseHeaders = response != null ? jsonEncode(response.headers.map) : '{}'; 52 + 53 + String? requestBody; 54 + try { 55 + if (options.data != null) { 56 + requestBody = options.data is String ? options.data : jsonEncode(options.data); 57 + } 58 + } catch (e) { 59 + requestBody = '<Unserializable Body: $e>'; 60 + } 61 + 62 + String? responseBody; 63 + try { 64 + if (response?.data != null) { 65 + responseBody = response!.data is String ? response.data : jsonEncode(response.data); 66 + } 67 + } catch (e) { 68 + responseBody = '<Unserializable Body: $e>'; 69 + } 70 + 71 + await _dao.logRequest( 72 + uuid: uuid, 73 + method: options.method, 74 + url: options.uri.toString(), 75 + statusCode: response?.statusCode ?? error?.response?.statusCode ?? 0, 76 + durationMs: duration, 77 + requestHeaders: requestHeaders, 78 + responseHeaders: responseHeaders, 79 + requestBody: requestBody, 80 + responseBody: responseBody, 81 + error: error?.message, 82 + ); 83 + } catch (e, stack) { 84 + developer.log( 85 + 'Failed to log network request', 86 + name: 'DebugNetworkInterceptor', 87 + error: e, 88 + stackTrace: stack, 89 + ); 90 + } 91 + } 92 + }
+8 -2
lib/src/features/debug/presentation/debug_drawer.dart
··· 3 3 4 4 import '../application/debug_overlay_controller.dart'; 5 5 import 'atproto_session_tab.dart'; 6 + import 'network_inspector_tab.dart'; 6 7 import 'system_info_tab.dart'; 7 8 8 9 /// A drawer displaying debug information in tabs. ··· 24 25 child: SafeArea( 25 26 left: false, 26 27 child: DefaultTabController( 27 - length: 2, 28 + length: 3, 28 29 initialIndex: overlayState.activeTabIndex, 29 30 child: Column( 30 31 children: [ 31 32 _buildHeader(context, ref, theme), 32 33 _buildTabBar(theme), 33 - const Expanded(child: TabBarView(children: [SystemInfoTab(), AtprotoSessionTab()])), 34 + const Expanded( 35 + child: TabBarView( 36 + children: [SystemInfoTab(), AtprotoSessionTab(), NetworkInspectorTab()], 37 + ), 38 + ), 34 39 ], 35 40 ), 36 41 ), ··· 73 78 tabs: const [ 74 79 Tab(icon: Icon(Icons.info_outline), text: 'System'), 75 80 Tab(icon: Icon(Icons.account_circle_outlined), text: 'Session'), 81 + Tab(icon: Icon(Icons.http), text: 'Network'), 76 82 ], 77 83 labelColor: theme.colorScheme.primary, 78 84 unselectedLabelColor: theme.colorScheme.onSurfaceVariant,
-1
lib/src/features/debug/presentation/debug_overlay_host.dart
··· 104 104 _longPressTimer = Timer(_longPressDuration, () { 105 105 if (mounted && _activePointers.length == 2) { 106 106 ref.read(debugOverlayControllerProvider.notifier).toggle(); 107 - // Reset to avoid repeated toggles without lifting fingers 108 107 _activePointers.clear(); 109 108 } 110 109 });
+280
lib/src/features/debug/presentation/network_inspector_tab.dart
··· 1 + import 'package:flutter/material.dart'; 2 + import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 + import 'package:intl/intl.dart'; 4 + import 'package:lazurite/src/app/providers.dart'; 5 + 6 + import '../../../infrastructure/db/app_database.dart'; 7 + 8 + /// Tab for inspecting network traffic in the debug drawer. 9 + class NetworkInspectorTab extends ConsumerWidget { 10 + const NetworkInspectorTab({super.key}); 11 + 12 + @override 13 + Widget build(BuildContext context, WidgetRef ref) { 14 + final db = ref.watch(appDatabaseProvider); 15 + final theme = Theme.of(context); 16 + 17 + return StreamBuilder<List<DevNetworkLog>>( 18 + stream: db.devToolsDao.watchLogs(), 19 + builder: (context, snapshot) { 20 + if (!snapshot.hasData) { 21 + return const Center(child: CircularProgressIndicator()); 22 + } 23 + 24 + final logs = snapshot.data!; 25 + if (logs.isEmpty) { 26 + return Center( 27 + child: Text( 28 + 'No network logs recorded.', 29 + style: theme.textTheme.bodyMedium?.copyWith( 30 + color: theme.colorScheme.onSurfaceVariant, 31 + ), 32 + ), 33 + ); 34 + } 35 + 36 + return Column( 37 + children: [ 38 + _buildToolbar(context, ref, logs.length), 39 + Expanded( 40 + child: ListView.separated( 41 + itemCount: logs.length, 42 + separatorBuilder: (context, index) => const Divider(height: 1), 43 + itemBuilder: (context, index) { 44 + final log = logs[index]; 45 + return _LogItem(log: log); 46 + }, 47 + ), 48 + ), 49 + ], 50 + ); 51 + }, 52 + ); 53 + } 54 + 55 + Widget _buildToolbar(BuildContext context, WidgetRef ref, int count) { 56 + final theme = Theme.of(context); 57 + return Container( 58 + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), 59 + color: theme.colorScheme.surfaceContainer, 60 + child: Row( 61 + children: [ 62 + Text( 63 + '$count Requests', 64 + style: theme.textTheme.labelMedium?.copyWith(fontWeight: FontWeight.bold), 65 + ), 66 + const Spacer(), 67 + TextButton.icon( 68 + onPressed: () { 69 + ref.read(appDatabaseProvider).devToolsDao.clearLogs(); 70 + }, 71 + icon: const Icon(Icons.delete_outline, size: 16), 72 + label: const Text('Clear'), 73 + style: TextButton.styleFrom( 74 + visualDensity: VisualDensity.compact, 75 + foregroundColor: theme.colorScheme.error, 76 + ), 77 + ), 78 + ], 79 + ), 80 + ); 81 + } 82 + } 83 + 84 + class _LogItem extends StatelessWidget { 85 + const _LogItem({required this.log}); 86 + 87 + final DevNetworkLog log; 88 + 89 + @override 90 + Widget build(BuildContext context) { 91 + final theme = Theme.of(context); 92 + final statusColor = _getStatusColor(log.statusCode, theme); 93 + final timeFormat = DateFormat('HH:mm:ss'); 94 + 95 + return InkWell( 96 + onTap: () => _showDetails(context), 97 + child: Padding( 98 + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), 99 + child: Column( 100 + crossAxisAlignment: CrossAxisAlignment.start, 101 + children: [ 102 + Row( 103 + children: [ 104 + Container( 105 + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), 106 + decoration: BoxDecoration( 107 + color: statusColor.withValues(alpha: 0.1), 108 + borderRadius: BorderRadius.circular(4), 109 + border: Border.all(color: statusColor.withValues(alpha: 0.5)), 110 + ), 111 + child: Text( 112 + log.statusCode.toString(), 113 + style: theme.textTheme.labelSmall?.copyWith( 114 + color: statusColor, 115 + fontWeight: FontWeight.bold, 116 + ), 117 + ), 118 + ), 119 + const SizedBox(width: 8), 120 + Text( 121 + log.method, 122 + style: theme.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.bold), 123 + ), 124 + const Spacer(), 125 + Text( 126 + '${log.durationMs}ms', 127 + style: theme.textTheme.bodySmall?.copyWith( 128 + color: theme.colorScheme.onSurfaceVariant, 129 + ), 130 + ), 131 + ], 132 + ), 133 + const SizedBox(height: 4), 134 + Text( 135 + log.url, 136 + style: theme.textTheme.bodyMedium, 137 + maxLines: 2, 138 + overflow: TextOverflow.ellipsis, 139 + ), 140 + const SizedBox(height: 4), 141 + Text( 142 + timeFormat.format(log.timestamp), 143 + style: theme.textTheme.bodySmall?.copyWith( 144 + color: theme.colorScheme.onSurfaceVariant, 145 + ), 146 + ), 147 + if (log.error != null) ...[ 148 + const SizedBox(height: 4), 149 + Text( 150 + log.error!, 151 + style: theme.textTheme.bodySmall?.copyWith( 152 + color: theme.colorScheme.error, 153 + fontWeight: FontWeight.w500, 154 + ), 155 + maxLines: 2, 156 + overflow: TextOverflow.ellipsis, 157 + ), 158 + ], 159 + ], 160 + ), 161 + ), 162 + ); 163 + } 164 + 165 + Color _getStatusColor(int statusCode, ThemeData theme) { 166 + if (statusCode >= 200 && statusCode < 300) return Colors.green; 167 + if (statusCode >= 300 && statusCode < 400) return Colors.blue; 168 + if (statusCode >= 400 && statusCode < 500) return Colors.orange; 169 + if (statusCode >= 500) return theme.colorScheme.error; 170 + return theme.colorScheme.onSurface; 171 + } 172 + 173 + void _showDetails(BuildContext context) { 174 + showModalBottomSheet( 175 + context: context, 176 + isScrollControlled: true, 177 + useSafeArea: true, 178 + showDragHandle: true, 179 + builder: (context) => _LogDetailsSheet(log: log), 180 + ); 181 + } 182 + } 183 + 184 + class _LogDetailsSheet extends StatelessWidget { 185 + const _LogDetailsSheet({required this.log}); 186 + 187 + final DevNetworkLog log; 188 + 189 + @override 190 + Widget build(BuildContext context) { 191 + final theme = Theme.of(context); 192 + 193 + return DraggableScrollableSheet( 194 + initialChildSize: 0.8, 195 + minChildSize: 0.5, 196 + maxChildSize: 0.95, 197 + expand: false, 198 + builder: (context, scrollController) { 199 + return ListView( 200 + controller: scrollController, 201 + padding: const EdgeInsets.fromLTRB(16, 0, 16, 24), 202 + children: [ 203 + SelectableText(log.url, style: theme.textTheme.titleMedium), 204 + const SizedBox(height: 16), 205 + _buildSection(context, 'General', [ 206 + _buildPair('Method', log.method), 207 + _buildPair('Status', '${log.statusCode}'), 208 + _buildPair('Duration', '${log.durationMs}ms'), 209 + _buildPair('Time', DateFormat('HH:mm:ss.SSS').format(log.timestamp)), 210 + ]), 211 + const Divider(height: 32), 212 + _buildSection(context, 'Request Headers', [_buildJsonOrText(log.requestHeaders)]), 213 + const SizedBox(height: 16), 214 + _buildSection(context, 'Request Body', [ 215 + _buildJsonOrText(log.requestBody ?? '(Empty)'), 216 + ]), 217 + const Divider(height: 32), 218 + _buildSection(context, 'Response Headers', [_buildJsonOrText(log.responseHeaders)]), 219 + const SizedBox(height: 16), 220 + _buildSection(context, 'Response Body', [ 221 + _buildJsonOrText(log.responseBody ?? '(Empty)'), 222 + ]), 223 + if (log.error != null) ...[ 224 + const Divider(height: 32), 225 + _buildSection(context, 'Error', [ 226 + Text(log.error!, style: TextStyle(color: theme.colorScheme.error)), 227 + ]), 228 + ], 229 + ], 230 + ); 231 + }, 232 + ); 233 + } 234 + 235 + Widget _buildSection(BuildContext context, String title, List<Widget> children) { 236 + final theme = Theme.of(context); 237 + return Column( 238 + crossAxisAlignment: CrossAxisAlignment.start, 239 + children: [ 240 + Text( 241 + title, 242 + style: theme.textTheme.labelLarge?.copyWith( 243 + color: theme.colorScheme.primary, 244 + fontWeight: FontWeight.bold, 245 + ), 246 + ), 247 + const SizedBox(height: 8), 248 + ...children, 249 + ], 250 + ); 251 + } 252 + 253 + Widget _buildPair(String label, String value) { 254 + return Padding( 255 + padding: const EdgeInsets.only(bottom: 4), 256 + child: Row( 257 + crossAxisAlignment: CrossAxisAlignment.start, 258 + children: [ 259 + SizedBox( 260 + width: 80, 261 + child: Text(label, style: const TextStyle(fontWeight: FontWeight.w500)), 262 + ), 263 + Expanded(child: SelectableText(value)), 264 + ], 265 + ), 266 + ); 267 + } 268 + 269 + Widget _buildJsonOrText(String text) { 270 + return Container( 271 + width: double.infinity, 272 + padding: const EdgeInsets.all(12), 273 + decoration: BoxDecoration( 274 + color: Colors.grey.withValues(alpha: 0.1), 275 + borderRadius: BorderRadius.circular(8), 276 + ), 277 + child: SelectableText(text, style: const TextStyle(fontFamily: 'monospace', fontSize: 13)), 278 + ); 279 + } 280 + }
+5 -1
lib/src/infrastructure/db/app_database.dart
··· 8 8 import 'daos/animation_preferences_dao.dart'; 9 9 import 'daos/bluesky_preferences_dao.dart'; 10 10 import 'daos/custom_theme_dao.dart'; 11 + import 'daos/dev_tools_dao.dart'; 11 12 import 'daos/dm_convos_dao.dart'; 12 13 import 'daos/dm_messages_dao.dart'; 13 14 import 'daos/dm_outbox_dao.dart'; ··· 55 56 DmConvos, 56 57 DmMessages, 57 58 DmOutbox, 59 + DevSettings, 60 + DevNetworkLogs, 58 61 ], 59 62 daos: [ 60 63 FeedContentDao, ··· 76 79 DmConvosDao, 77 80 DmMessagesDao, 78 81 DmOutboxDao, 82 + DevToolsDao, 79 83 ], 80 84 ) 81 85 class AppDatabase extends _$AppDatabase { 82 86 AppDatabase([QueryExecutor? e]) : super(e ?? _openConnection()); 83 87 84 88 @override 85 - int get schemaVersion => 3; 89 + int get schemaVersion => 1; 86 90 87 91 @override 88 92 MigrationStrategy get migration => MigrationStrategy(
+1345
lib/src/infrastructure/db/app_database.g.dart
··· 11651 11651 } 11652 11652 } 11653 11653 11654 + class $DevSettingsTable extends DevSettings with TableInfo<$DevSettingsTable, DevSetting> { 11655 + @override 11656 + final GeneratedDatabase attachedDatabase; 11657 + final String? _alias; 11658 + $DevSettingsTable(this.attachedDatabase, [this._alias]); 11659 + static const VerificationMeta _idMeta = const VerificationMeta('id'); 11660 + @override 11661 + late final GeneratedColumn<int> id = GeneratedColumn<int>( 11662 + 'id', 11663 + aliasedName, 11664 + false, 11665 + hasAutoIncrement: true, 11666 + type: DriftSqlType.int, 11667 + requiredDuringInsert: false, 11668 + defaultConstraints: GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'), 11669 + ); 11670 + static const VerificationMeta _keyMeta = const VerificationMeta('key'); 11671 + @override 11672 + late final GeneratedColumn<String> key = GeneratedColumn<String>( 11673 + 'key', 11674 + aliasedName, 11675 + false, 11676 + type: DriftSqlType.string, 11677 + requiredDuringInsert: true, 11678 + defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'), 11679 + ); 11680 + static const VerificationMeta _valueMeta = const VerificationMeta('value'); 11681 + @override 11682 + late final GeneratedColumn<String> value = GeneratedColumn<String>( 11683 + 'value', 11684 + aliasedName, 11685 + false, 11686 + type: DriftSqlType.string, 11687 + requiredDuringInsert: true, 11688 + ); 11689 + static const VerificationMeta _typeMeta = const VerificationMeta('type'); 11690 + @override 11691 + late final GeneratedColumn<String> type = GeneratedColumn<String>( 11692 + 'type', 11693 + aliasedName, 11694 + false, 11695 + type: DriftSqlType.string, 11696 + requiredDuringInsert: true, 11697 + ); 11698 + @override 11699 + List<GeneratedColumn> get $columns => [id, key, value, type]; 11700 + @override 11701 + String get aliasedName => _alias ?? actualTableName; 11702 + @override 11703 + String get actualTableName => $name; 11704 + static const String $name = 'dev_settings'; 11705 + @override 11706 + VerificationContext validateIntegrity( 11707 + Insertable<DevSetting> instance, { 11708 + bool isInserting = false, 11709 + }) { 11710 + final context = VerificationContext(); 11711 + final data = instance.toColumns(true); 11712 + if (data.containsKey('id')) { 11713 + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); 11714 + } 11715 + if (data.containsKey('key')) { 11716 + context.handle(_keyMeta, key.isAcceptableOrUnknown(data['key']!, _keyMeta)); 11717 + } else if (isInserting) { 11718 + context.missing(_keyMeta); 11719 + } 11720 + if (data.containsKey('value')) { 11721 + context.handle(_valueMeta, value.isAcceptableOrUnknown(data['value']!, _valueMeta)); 11722 + } else if (isInserting) { 11723 + context.missing(_valueMeta); 11724 + } 11725 + if (data.containsKey('type')) { 11726 + context.handle(_typeMeta, type.isAcceptableOrUnknown(data['type']!, _typeMeta)); 11727 + } else if (isInserting) { 11728 + context.missing(_typeMeta); 11729 + } 11730 + return context; 11731 + } 11732 + 11733 + @override 11734 + Set<GeneratedColumn> get $primaryKey => {id}; 11735 + @override 11736 + DevSetting map(Map<String, dynamic> data, {String? tablePrefix}) { 11737 + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; 11738 + return DevSetting( 11739 + id: attachedDatabase.typeMapping.read(DriftSqlType.int, data['${effectivePrefix}id'])!, 11740 + key: attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}key'])!, 11741 + value: attachedDatabase.typeMapping.read( 11742 + DriftSqlType.string, 11743 + data['${effectivePrefix}value'], 11744 + )!, 11745 + type: attachedDatabase.typeMapping.read( 11746 + DriftSqlType.string, 11747 + data['${effectivePrefix}type'], 11748 + )!, 11749 + ); 11750 + } 11751 + 11752 + @override 11753 + $DevSettingsTable createAlias(String alias) { 11754 + return $DevSettingsTable(attachedDatabase, alias); 11755 + } 11756 + } 11757 + 11758 + class DevSetting extends DataClass implements Insertable<DevSetting> { 11759 + final int id; 11760 + final String key; 11761 + final String value; 11762 + 11763 + /// Type of value: 'boolean', 'string', 'int' 11764 + final String type; 11765 + const DevSetting({required this.id, required this.key, required this.value, required this.type}); 11766 + @override 11767 + Map<String, Expression> toColumns(bool nullToAbsent) { 11768 + final map = <String, Expression>{}; 11769 + map['id'] = Variable<int>(id); 11770 + map['key'] = Variable<String>(key); 11771 + map['value'] = Variable<String>(value); 11772 + map['type'] = Variable<String>(type); 11773 + return map; 11774 + } 11775 + 11776 + DevSettingsCompanion toCompanion(bool nullToAbsent) { 11777 + return DevSettingsCompanion( 11778 + id: Value(id), 11779 + key: Value(key), 11780 + value: Value(value), 11781 + type: Value(type), 11782 + ); 11783 + } 11784 + 11785 + factory DevSetting.fromJson(Map<String, dynamic> json, {ValueSerializer? serializer}) { 11786 + serializer ??= driftRuntimeOptions.defaultSerializer; 11787 + return DevSetting( 11788 + id: serializer.fromJson<int>(json['id']), 11789 + key: serializer.fromJson<String>(json['key']), 11790 + value: serializer.fromJson<String>(json['value']), 11791 + type: serializer.fromJson<String>(json['type']), 11792 + ); 11793 + } 11794 + @override 11795 + Map<String, dynamic> toJson({ValueSerializer? serializer}) { 11796 + serializer ??= driftRuntimeOptions.defaultSerializer; 11797 + return <String, dynamic>{ 11798 + 'id': serializer.toJson<int>(id), 11799 + 'key': serializer.toJson<String>(key), 11800 + 'value': serializer.toJson<String>(value), 11801 + 'type': serializer.toJson<String>(type), 11802 + }; 11803 + } 11804 + 11805 + DevSetting copyWith({int? id, String? key, String? value, String? type}) => DevSetting( 11806 + id: id ?? this.id, 11807 + key: key ?? this.key, 11808 + value: value ?? this.value, 11809 + type: type ?? this.type, 11810 + ); 11811 + DevSetting copyWithCompanion(DevSettingsCompanion data) { 11812 + return DevSetting( 11813 + id: data.id.present ? data.id.value : this.id, 11814 + key: data.key.present ? data.key.value : this.key, 11815 + value: data.value.present ? data.value.value : this.value, 11816 + type: data.type.present ? data.type.value : this.type, 11817 + ); 11818 + } 11819 + 11820 + @override 11821 + String toString() { 11822 + return (StringBuffer('DevSetting(') 11823 + ..write('id: $id, ') 11824 + ..write('key: $key, ') 11825 + ..write('value: $value, ') 11826 + ..write('type: $type') 11827 + ..write(')')) 11828 + .toString(); 11829 + } 11830 + 11831 + @override 11832 + int get hashCode => Object.hash(id, key, value, type); 11833 + @override 11834 + bool operator ==(Object other) => 11835 + identical(this, other) || 11836 + (other is DevSetting && 11837 + other.id == this.id && 11838 + other.key == this.key && 11839 + other.value == this.value && 11840 + other.type == this.type); 11841 + } 11842 + 11843 + class DevSettingsCompanion extends UpdateCompanion<DevSetting> { 11844 + final Value<int> id; 11845 + final Value<String> key; 11846 + final Value<String> value; 11847 + final Value<String> type; 11848 + const DevSettingsCompanion({ 11849 + this.id = const Value.absent(), 11850 + this.key = const Value.absent(), 11851 + this.value = const Value.absent(), 11852 + this.type = const Value.absent(), 11853 + }); 11854 + DevSettingsCompanion.insert({ 11855 + this.id = const Value.absent(), 11856 + required String key, 11857 + required String value, 11858 + required String type, 11859 + }) : key = Value(key), 11860 + value = Value(value), 11861 + type = Value(type); 11862 + static Insertable<DevSetting> custom({ 11863 + Expression<int>? id, 11864 + Expression<String>? key, 11865 + Expression<String>? value, 11866 + Expression<String>? type, 11867 + }) { 11868 + return RawValuesInsertable({ 11869 + if (id != null) 'id': id, 11870 + if (key != null) 'key': key, 11871 + if (value != null) 'value': value, 11872 + if (type != null) 'type': type, 11873 + }); 11874 + } 11875 + 11876 + DevSettingsCompanion copyWith({ 11877 + Value<int>? id, 11878 + Value<String>? key, 11879 + Value<String>? value, 11880 + Value<String>? type, 11881 + }) { 11882 + return DevSettingsCompanion( 11883 + id: id ?? this.id, 11884 + key: key ?? this.key, 11885 + value: value ?? this.value, 11886 + type: type ?? this.type, 11887 + ); 11888 + } 11889 + 11890 + @override 11891 + Map<String, Expression> toColumns(bool nullToAbsent) { 11892 + final map = <String, Expression>{}; 11893 + if (id.present) { 11894 + map['id'] = Variable<int>(id.value); 11895 + } 11896 + if (key.present) { 11897 + map['key'] = Variable<String>(key.value); 11898 + } 11899 + if (value.present) { 11900 + map['value'] = Variable<String>(value.value); 11901 + } 11902 + if (type.present) { 11903 + map['type'] = Variable<String>(type.value); 11904 + } 11905 + return map; 11906 + } 11907 + 11908 + @override 11909 + String toString() { 11910 + return (StringBuffer('DevSettingsCompanion(') 11911 + ..write('id: $id, ') 11912 + ..write('key: $key, ') 11913 + ..write('value: $value, ') 11914 + ..write('type: $type') 11915 + ..write(')')) 11916 + .toString(); 11917 + } 11918 + } 11919 + 11920 + class $DevNetworkLogsTable extends DevNetworkLogs 11921 + with TableInfo<$DevNetworkLogsTable, DevNetworkLog> { 11922 + @override 11923 + final GeneratedDatabase attachedDatabase; 11924 + final String? _alias; 11925 + $DevNetworkLogsTable(this.attachedDatabase, [this._alias]); 11926 + static const VerificationMeta _idMeta = const VerificationMeta('id'); 11927 + @override 11928 + late final GeneratedColumn<int> id = GeneratedColumn<int>( 11929 + 'id', 11930 + aliasedName, 11931 + false, 11932 + hasAutoIncrement: true, 11933 + type: DriftSqlType.int, 11934 + requiredDuringInsert: false, 11935 + defaultConstraints: GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'), 11936 + ); 11937 + static const VerificationMeta _uuidMeta = const VerificationMeta('uuid'); 11938 + @override 11939 + late final GeneratedColumn<String> uuid = GeneratedColumn<String>( 11940 + 'uuid', 11941 + aliasedName, 11942 + false, 11943 + type: DriftSqlType.string, 11944 + requiredDuringInsert: true, 11945 + defaultConstraints: GeneratedColumn.constraintIsAlways('UNIQUE'), 11946 + ); 11947 + static const VerificationMeta _methodMeta = const VerificationMeta('method'); 11948 + @override 11949 + late final GeneratedColumn<String> method = GeneratedColumn<String>( 11950 + 'method', 11951 + aliasedName, 11952 + false, 11953 + type: DriftSqlType.string, 11954 + requiredDuringInsert: true, 11955 + ); 11956 + static const VerificationMeta _urlMeta = const VerificationMeta('url'); 11957 + @override 11958 + late final GeneratedColumn<String> url = GeneratedColumn<String>( 11959 + 'url', 11960 + aliasedName, 11961 + false, 11962 + type: DriftSqlType.string, 11963 + requiredDuringInsert: true, 11964 + ); 11965 + static const VerificationMeta _statusCodeMeta = const VerificationMeta('statusCode'); 11966 + @override 11967 + late final GeneratedColumn<int> statusCode = GeneratedColumn<int>( 11968 + 'status_code', 11969 + aliasedName, 11970 + false, 11971 + type: DriftSqlType.int, 11972 + requiredDuringInsert: true, 11973 + ); 11974 + static const VerificationMeta _requestHeadersMeta = const VerificationMeta('requestHeaders'); 11975 + @override 11976 + late final GeneratedColumn<String> requestHeaders = GeneratedColumn<String>( 11977 + 'request_headers', 11978 + aliasedName, 11979 + false, 11980 + type: DriftSqlType.string, 11981 + requiredDuringInsert: true, 11982 + ); 11983 + static const VerificationMeta _responseHeadersMeta = const VerificationMeta('responseHeaders'); 11984 + @override 11985 + late final GeneratedColumn<String> responseHeaders = GeneratedColumn<String>( 11986 + 'response_headers', 11987 + aliasedName, 11988 + false, 11989 + type: DriftSqlType.string, 11990 + requiredDuringInsert: true, 11991 + ); 11992 + static const VerificationMeta _requestBodyMeta = const VerificationMeta('requestBody'); 11993 + @override 11994 + late final GeneratedColumn<String> requestBody = GeneratedColumn<String>( 11995 + 'request_body', 11996 + aliasedName, 11997 + true, 11998 + type: DriftSqlType.string, 11999 + requiredDuringInsert: false, 12000 + ); 12001 + static const VerificationMeta _responseBodyMeta = const VerificationMeta('responseBody'); 12002 + @override 12003 + late final GeneratedColumn<String> responseBody = GeneratedColumn<String>( 12004 + 'response_body', 12005 + aliasedName, 12006 + true, 12007 + type: DriftSqlType.string, 12008 + requiredDuringInsert: false, 12009 + ); 12010 + static const VerificationMeta _timestampMeta = const VerificationMeta('timestamp'); 12011 + @override 12012 + late final GeneratedColumn<DateTime> timestamp = GeneratedColumn<DateTime>( 12013 + 'timestamp', 12014 + aliasedName, 12015 + false, 12016 + type: DriftSqlType.dateTime, 12017 + requiredDuringInsert: true, 12018 + ); 12019 + static const VerificationMeta _durationMsMeta = const VerificationMeta('durationMs'); 12020 + @override 12021 + late final GeneratedColumn<int> durationMs = GeneratedColumn<int>( 12022 + 'duration_ms', 12023 + aliasedName, 12024 + false, 12025 + type: DriftSqlType.int, 12026 + requiredDuringInsert: true, 12027 + ); 12028 + static const VerificationMeta _errorMeta = const VerificationMeta('error'); 12029 + @override 12030 + late final GeneratedColumn<String> error = GeneratedColumn<String>( 12031 + 'error', 12032 + aliasedName, 12033 + true, 12034 + type: DriftSqlType.string, 12035 + requiredDuringInsert: false, 12036 + ); 12037 + @override 12038 + List<GeneratedColumn> get $columns => [ 12039 + id, 12040 + uuid, 12041 + method, 12042 + url, 12043 + statusCode, 12044 + requestHeaders, 12045 + responseHeaders, 12046 + requestBody, 12047 + responseBody, 12048 + timestamp, 12049 + durationMs, 12050 + error, 12051 + ]; 12052 + @override 12053 + String get aliasedName => _alias ?? actualTableName; 12054 + @override 12055 + String get actualTableName => $name; 12056 + static const String $name = 'dev_network_logs'; 12057 + @override 12058 + VerificationContext validateIntegrity( 12059 + Insertable<DevNetworkLog> instance, { 12060 + bool isInserting = false, 12061 + }) { 12062 + final context = VerificationContext(); 12063 + final data = instance.toColumns(true); 12064 + if (data.containsKey('id')) { 12065 + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); 12066 + } 12067 + if (data.containsKey('uuid')) { 12068 + context.handle(_uuidMeta, uuid.isAcceptableOrUnknown(data['uuid']!, _uuidMeta)); 12069 + } else if (isInserting) { 12070 + context.missing(_uuidMeta); 12071 + } 12072 + if (data.containsKey('method')) { 12073 + context.handle(_methodMeta, method.isAcceptableOrUnknown(data['method']!, _methodMeta)); 12074 + } else if (isInserting) { 12075 + context.missing(_methodMeta); 12076 + } 12077 + if (data.containsKey('url')) { 12078 + context.handle(_urlMeta, url.isAcceptableOrUnknown(data['url']!, _urlMeta)); 12079 + } else if (isInserting) { 12080 + context.missing(_urlMeta); 12081 + } 12082 + if (data.containsKey('status_code')) { 12083 + context.handle( 12084 + _statusCodeMeta, 12085 + statusCode.isAcceptableOrUnknown(data['status_code']!, _statusCodeMeta), 12086 + ); 12087 + } else if (isInserting) { 12088 + context.missing(_statusCodeMeta); 12089 + } 12090 + if (data.containsKey('request_headers')) { 12091 + context.handle( 12092 + _requestHeadersMeta, 12093 + requestHeaders.isAcceptableOrUnknown(data['request_headers']!, _requestHeadersMeta), 12094 + ); 12095 + } else if (isInserting) { 12096 + context.missing(_requestHeadersMeta); 12097 + } 12098 + if (data.containsKey('response_headers')) { 12099 + context.handle( 12100 + _responseHeadersMeta, 12101 + responseHeaders.isAcceptableOrUnknown(data['response_headers']!, _responseHeadersMeta), 12102 + ); 12103 + } else if (isInserting) { 12104 + context.missing(_responseHeadersMeta); 12105 + } 12106 + if (data.containsKey('request_body')) { 12107 + context.handle( 12108 + _requestBodyMeta, 12109 + requestBody.isAcceptableOrUnknown(data['request_body']!, _requestBodyMeta), 12110 + ); 12111 + } 12112 + if (data.containsKey('response_body')) { 12113 + context.handle( 12114 + _responseBodyMeta, 12115 + responseBody.isAcceptableOrUnknown(data['response_body']!, _responseBodyMeta), 12116 + ); 12117 + } 12118 + if (data.containsKey('timestamp')) { 12119 + context.handle( 12120 + _timestampMeta, 12121 + timestamp.isAcceptableOrUnknown(data['timestamp']!, _timestampMeta), 12122 + ); 12123 + } else if (isInserting) { 12124 + context.missing(_timestampMeta); 12125 + } 12126 + if (data.containsKey('duration_ms')) { 12127 + context.handle( 12128 + _durationMsMeta, 12129 + durationMs.isAcceptableOrUnknown(data['duration_ms']!, _durationMsMeta), 12130 + ); 12131 + } else if (isInserting) { 12132 + context.missing(_durationMsMeta); 12133 + } 12134 + if (data.containsKey('error')) { 12135 + context.handle(_errorMeta, error.isAcceptableOrUnknown(data['error']!, _errorMeta)); 12136 + } 12137 + return context; 12138 + } 12139 + 12140 + @override 12141 + Set<GeneratedColumn> get $primaryKey => {id}; 12142 + @override 12143 + DevNetworkLog map(Map<String, dynamic> data, {String? tablePrefix}) { 12144 + final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : ''; 12145 + return DevNetworkLog( 12146 + id: attachedDatabase.typeMapping.read(DriftSqlType.int, data['${effectivePrefix}id'])!, 12147 + uuid: attachedDatabase.typeMapping.read( 12148 + DriftSqlType.string, 12149 + data['${effectivePrefix}uuid'], 12150 + )!, 12151 + method: attachedDatabase.typeMapping.read( 12152 + DriftSqlType.string, 12153 + data['${effectivePrefix}method'], 12154 + )!, 12155 + url: attachedDatabase.typeMapping.read(DriftSqlType.string, data['${effectivePrefix}url'])!, 12156 + statusCode: attachedDatabase.typeMapping.read( 12157 + DriftSqlType.int, 12158 + data['${effectivePrefix}status_code'], 12159 + )!, 12160 + requestHeaders: attachedDatabase.typeMapping.read( 12161 + DriftSqlType.string, 12162 + data['${effectivePrefix}request_headers'], 12163 + )!, 12164 + responseHeaders: attachedDatabase.typeMapping.read( 12165 + DriftSqlType.string, 12166 + data['${effectivePrefix}response_headers'], 12167 + )!, 12168 + requestBody: attachedDatabase.typeMapping.read( 12169 + DriftSqlType.string, 12170 + data['${effectivePrefix}request_body'], 12171 + ), 12172 + responseBody: attachedDatabase.typeMapping.read( 12173 + DriftSqlType.string, 12174 + data['${effectivePrefix}response_body'], 12175 + ), 12176 + timestamp: attachedDatabase.typeMapping.read( 12177 + DriftSqlType.dateTime, 12178 + data['${effectivePrefix}timestamp'], 12179 + )!, 12180 + durationMs: attachedDatabase.typeMapping.read( 12181 + DriftSqlType.int, 12182 + data['${effectivePrefix}duration_ms'], 12183 + )!, 12184 + error: attachedDatabase.typeMapping.read( 12185 + DriftSqlType.string, 12186 + data['${effectivePrefix}error'], 12187 + ), 12188 + ); 12189 + } 12190 + 12191 + @override 12192 + $DevNetworkLogsTable createAlias(String alias) { 12193 + return $DevNetworkLogsTable(attachedDatabase, alias); 12194 + } 12195 + } 12196 + 12197 + class DevNetworkLog extends DataClass implements Insertable<DevNetworkLog> { 12198 + final int id; 12199 + final String uuid; 12200 + final String method; 12201 + final String url; 12202 + final int statusCode; 12203 + final String requestHeaders; 12204 + final String responseHeaders; 12205 + final String? requestBody; 12206 + final String? responseBody; 12207 + final DateTime timestamp; 12208 + final int durationMs; 12209 + final String? error; 12210 + const DevNetworkLog({ 12211 + required this.id, 12212 + required this.uuid, 12213 + required this.method, 12214 + required this.url, 12215 + required this.statusCode, 12216 + required this.requestHeaders, 12217 + required this.responseHeaders, 12218 + this.requestBody, 12219 + this.responseBody, 12220 + required this.timestamp, 12221 + required this.durationMs, 12222 + this.error, 12223 + }); 12224 + @override 12225 + Map<String, Expression> toColumns(bool nullToAbsent) { 12226 + final map = <String, Expression>{}; 12227 + map['id'] = Variable<int>(id); 12228 + map['uuid'] = Variable<String>(uuid); 12229 + map['method'] = Variable<String>(method); 12230 + map['url'] = Variable<String>(url); 12231 + map['status_code'] = Variable<int>(statusCode); 12232 + map['request_headers'] = Variable<String>(requestHeaders); 12233 + map['response_headers'] = Variable<String>(responseHeaders); 12234 + if (!nullToAbsent || requestBody != null) { 12235 + map['request_body'] = Variable<String>(requestBody); 12236 + } 12237 + if (!nullToAbsent || responseBody != null) { 12238 + map['response_body'] = Variable<String>(responseBody); 12239 + } 12240 + map['timestamp'] = Variable<DateTime>(timestamp); 12241 + map['duration_ms'] = Variable<int>(durationMs); 12242 + if (!nullToAbsent || error != null) { 12243 + map['error'] = Variable<String>(error); 12244 + } 12245 + return map; 12246 + } 12247 + 12248 + DevNetworkLogsCompanion toCompanion(bool nullToAbsent) { 12249 + return DevNetworkLogsCompanion( 12250 + id: Value(id), 12251 + uuid: Value(uuid), 12252 + method: Value(method), 12253 + url: Value(url), 12254 + statusCode: Value(statusCode), 12255 + requestHeaders: Value(requestHeaders), 12256 + responseHeaders: Value(responseHeaders), 12257 + requestBody: requestBody == null && nullToAbsent ? const Value.absent() : Value(requestBody), 12258 + responseBody: responseBody == null && nullToAbsent 12259 + ? const Value.absent() 12260 + : Value(responseBody), 12261 + timestamp: Value(timestamp), 12262 + durationMs: Value(durationMs), 12263 + error: error == null && nullToAbsent ? const Value.absent() : Value(error), 12264 + ); 12265 + } 12266 + 12267 + factory DevNetworkLog.fromJson(Map<String, dynamic> json, {ValueSerializer? serializer}) { 12268 + serializer ??= driftRuntimeOptions.defaultSerializer; 12269 + return DevNetworkLog( 12270 + id: serializer.fromJson<int>(json['id']), 12271 + uuid: serializer.fromJson<String>(json['uuid']), 12272 + method: serializer.fromJson<String>(json['method']), 12273 + url: serializer.fromJson<String>(json['url']), 12274 + statusCode: serializer.fromJson<int>(json['statusCode']), 12275 + requestHeaders: serializer.fromJson<String>(json['requestHeaders']), 12276 + responseHeaders: serializer.fromJson<String>(json['responseHeaders']), 12277 + requestBody: serializer.fromJson<String?>(json['requestBody']), 12278 + responseBody: serializer.fromJson<String?>(json['responseBody']), 12279 + timestamp: serializer.fromJson<DateTime>(json['timestamp']), 12280 + durationMs: serializer.fromJson<int>(json['durationMs']), 12281 + error: serializer.fromJson<String?>(json['error']), 12282 + ); 12283 + } 12284 + @override 12285 + Map<String, dynamic> toJson({ValueSerializer? serializer}) { 12286 + serializer ??= driftRuntimeOptions.defaultSerializer; 12287 + return <String, dynamic>{ 12288 + 'id': serializer.toJson<int>(id), 12289 + 'uuid': serializer.toJson<String>(uuid), 12290 + 'method': serializer.toJson<String>(method), 12291 + 'url': serializer.toJson<String>(url), 12292 + 'statusCode': serializer.toJson<int>(statusCode), 12293 + 'requestHeaders': serializer.toJson<String>(requestHeaders), 12294 + 'responseHeaders': serializer.toJson<String>(responseHeaders), 12295 + 'requestBody': serializer.toJson<String?>(requestBody), 12296 + 'responseBody': serializer.toJson<String?>(responseBody), 12297 + 'timestamp': serializer.toJson<DateTime>(timestamp), 12298 + 'durationMs': serializer.toJson<int>(durationMs), 12299 + 'error': serializer.toJson<String?>(error), 12300 + }; 12301 + } 12302 + 12303 + DevNetworkLog copyWith({ 12304 + int? id, 12305 + String? uuid, 12306 + String? method, 12307 + String? url, 12308 + int? statusCode, 12309 + String? requestHeaders, 12310 + String? responseHeaders, 12311 + Value<String?> requestBody = const Value.absent(), 12312 + Value<String?> responseBody = const Value.absent(), 12313 + DateTime? timestamp, 12314 + int? durationMs, 12315 + Value<String?> error = const Value.absent(), 12316 + }) => DevNetworkLog( 12317 + id: id ?? this.id, 12318 + uuid: uuid ?? this.uuid, 12319 + method: method ?? this.method, 12320 + url: url ?? this.url, 12321 + statusCode: statusCode ?? this.statusCode, 12322 + requestHeaders: requestHeaders ?? this.requestHeaders, 12323 + responseHeaders: responseHeaders ?? this.responseHeaders, 12324 + requestBody: requestBody.present ? requestBody.value : this.requestBody, 12325 + responseBody: responseBody.present ? responseBody.value : this.responseBody, 12326 + timestamp: timestamp ?? this.timestamp, 12327 + durationMs: durationMs ?? this.durationMs, 12328 + error: error.present ? error.value : this.error, 12329 + ); 12330 + DevNetworkLog copyWithCompanion(DevNetworkLogsCompanion data) { 12331 + return DevNetworkLog( 12332 + id: data.id.present ? data.id.value : this.id, 12333 + uuid: data.uuid.present ? data.uuid.value : this.uuid, 12334 + method: data.method.present ? data.method.value : this.method, 12335 + url: data.url.present ? data.url.value : this.url, 12336 + statusCode: data.statusCode.present ? data.statusCode.value : this.statusCode, 12337 + requestHeaders: data.requestHeaders.present 12338 + ? data.requestHeaders.value 12339 + : this.requestHeaders, 12340 + responseHeaders: data.responseHeaders.present 12341 + ? data.responseHeaders.value 12342 + : this.responseHeaders, 12343 + requestBody: data.requestBody.present ? data.requestBody.value : this.requestBody, 12344 + responseBody: data.responseBody.present ? data.responseBody.value : this.responseBody, 12345 + timestamp: data.timestamp.present ? data.timestamp.value : this.timestamp, 12346 + durationMs: data.durationMs.present ? data.durationMs.value : this.durationMs, 12347 + error: data.error.present ? data.error.value : this.error, 12348 + ); 12349 + } 12350 + 12351 + @override 12352 + String toString() { 12353 + return (StringBuffer('DevNetworkLog(') 12354 + ..write('id: $id, ') 12355 + ..write('uuid: $uuid, ') 12356 + ..write('method: $method, ') 12357 + ..write('url: $url, ') 12358 + ..write('statusCode: $statusCode, ') 12359 + ..write('requestHeaders: $requestHeaders, ') 12360 + ..write('responseHeaders: $responseHeaders, ') 12361 + ..write('requestBody: $requestBody, ') 12362 + ..write('responseBody: $responseBody, ') 12363 + ..write('timestamp: $timestamp, ') 12364 + ..write('durationMs: $durationMs, ') 12365 + ..write('error: $error') 12366 + ..write(')')) 12367 + .toString(); 12368 + } 12369 + 12370 + @override 12371 + int get hashCode => Object.hash( 12372 + id, 12373 + uuid, 12374 + method, 12375 + url, 12376 + statusCode, 12377 + requestHeaders, 12378 + responseHeaders, 12379 + requestBody, 12380 + responseBody, 12381 + timestamp, 12382 + durationMs, 12383 + error, 12384 + ); 12385 + @override 12386 + bool operator ==(Object other) => 12387 + identical(this, other) || 12388 + (other is DevNetworkLog && 12389 + other.id == this.id && 12390 + other.uuid == this.uuid && 12391 + other.method == this.method && 12392 + other.url == this.url && 12393 + other.statusCode == this.statusCode && 12394 + other.requestHeaders == this.requestHeaders && 12395 + other.responseHeaders == this.responseHeaders && 12396 + other.requestBody == this.requestBody && 12397 + other.responseBody == this.responseBody && 12398 + other.timestamp == this.timestamp && 12399 + other.durationMs == this.durationMs && 12400 + other.error == this.error); 12401 + } 12402 + 12403 + class DevNetworkLogsCompanion extends UpdateCompanion<DevNetworkLog> { 12404 + final Value<int> id; 12405 + final Value<String> uuid; 12406 + final Value<String> method; 12407 + final Value<String> url; 12408 + final Value<int> statusCode; 12409 + final Value<String> requestHeaders; 12410 + final Value<String> responseHeaders; 12411 + final Value<String?> requestBody; 12412 + final Value<String?> responseBody; 12413 + final Value<DateTime> timestamp; 12414 + final Value<int> durationMs; 12415 + final Value<String?> error; 12416 + const DevNetworkLogsCompanion({ 12417 + this.id = const Value.absent(), 12418 + this.uuid = const Value.absent(), 12419 + this.method = const Value.absent(), 12420 + this.url = const Value.absent(), 12421 + this.statusCode = const Value.absent(), 12422 + this.requestHeaders = const Value.absent(), 12423 + this.responseHeaders = const Value.absent(), 12424 + this.requestBody = const Value.absent(), 12425 + this.responseBody = const Value.absent(), 12426 + this.timestamp = const Value.absent(), 12427 + this.durationMs = const Value.absent(), 12428 + this.error = const Value.absent(), 12429 + }); 12430 + DevNetworkLogsCompanion.insert({ 12431 + this.id = const Value.absent(), 12432 + required String uuid, 12433 + required String method, 12434 + required String url, 12435 + required int statusCode, 12436 + required String requestHeaders, 12437 + required String responseHeaders, 12438 + this.requestBody = const Value.absent(), 12439 + this.responseBody = const Value.absent(), 12440 + required DateTime timestamp, 12441 + required int durationMs, 12442 + this.error = const Value.absent(), 12443 + }) : uuid = Value(uuid), 12444 + method = Value(method), 12445 + url = Value(url), 12446 + statusCode = Value(statusCode), 12447 + requestHeaders = Value(requestHeaders), 12448 + responseHeaders = Value(responseHeaders), 12449 + timestamp = Value(timestamp), 12450 + durationMs = Value(durationMs); 12451 + static Insertable<DevNetworkLog> custom({ 12452 + Expression<int>? id, 12453 + Expression<String>? uuid, 12454 + Expression<String>? method, 12455 + Expression<String>? url, 12456 + Expression<int>? statusCode, 12457 + Expression<String>? requestHeaders, 12458 + Expression<String>? responseHeaders, 12459 + Expression<String>? requestBody, 12460 + Expression<String>? responseBody, 12461 + Expression<DateTime>? timestamp, 12462 + Expression<int>? durationMs, 12463 + Expression<String>? error, 12464 + }) { 12465 + return RawValuesInsertable({ 12466 + if (id != null) 'id': id, 12467 + if (uuid != null) 'uuid': uuid, 12468 + if (method != null) 'method': method, 12469 + if (url != null) 'url': url, 12470 + if (statusCode != null) 'status_code': statusCode, 12471 + if (requestHeaders != null) 'request_headers': requestHeaders, 12472 + if (responseHeaders != null) 'response_headers': responseHeaders, 12473 + if (requestBody != null) 'request_body': requestBody, 12474 + if (responseBody != null) 'response_body': responseBody, 12475 + if (timestamp != null) 'timestamp': timestamp, 12476 + if (durationMs != null) 'duration_ms': durationMs, 12477 + if (error != null) 'error': error, 12478 + }); 12479 + } 12480 + 12481 + DevNetworkLogsCompanion copyWith({ 12482 + Value<int>? id, 12483 + Value<String>? uuid, 12484 + Value<String>? method, 12485 + Value<String>? url, 12486 + Value<int>? statusCode, 12487 + Value<String>? requestHeaders, 12488 + Value<String>? responseHeaders, 12489 + Value<String?>? requestBody, 12490 + Value<String?>? responseBody, 12491 + Value<DateTime>? timestamp, 12492 + Value<int>? durationMs, 12493 + Value<String?>? error, 12494 + }) { 12495 + return DevNetworkLogsCompanion( 12496 + id: id ?? this.id, 12497 + uuid: uuid ?? this.uuid, 12498 + method: method ?? this.method, 12499 + url: url ?? this.url, 12500 + statusCode: statusCode ?? this.statusCode, 12501 + requestHeaders: requestHeaders ?? this.requestHeaders, 12502 + responseHeaders: responseHeaders ?? this.responseHeaders, 12503 + requestBody: requestBody ?? this.requestBody, 12504 + responseBody: responseBody ?? this.responseBody, 12505 + timestamp: timestamp ?? this.timestamp, 12506 + durationMs: durationMs ?? this.durationMs, 12507 + error: error ?? this.error, 12508 + ); 12509 + } 12510 + 12511 + @override 12512 + Map<String, Expression> toColumns(bool nullToAbsent) { 12513 + final map = <String, Expression>{}; 12514 + if (id.present) { 12515 + map['id'] = Variable<int>(id.value); 12516 + } 12517 + if (uuid.present) { 12518 + map['uuid'] = Variable<String>(uuid.value); 12519 + } 12520 + if (method.present) { 12521 + map['method'] = Variable<String>(method.value); 12522 + } 12523 + if (url.present) { 12524 + map['url'] = Variable<String>(url.value); 12525 + } 12526 + if (statusCode.present) { 12527 + map['status_code'] = Variable<int>(statusCode.value); 12528 + } 12529 + if (requestHeaders.present) { 12530 + map['request_headers'] = Variable<String>(requestHeaders.value); 12531 + } 12532 + if (responseHeaders.present) { 12533 + map['response_headers'] = Variable<String>(responseHeaders.value); 12534 + } 12535 + if (requestBody.present) { 12536 + map['request_body'] = Variable<String>(requestBody.value); 12537 + } 12538 + if (responseBody.present) { 12539 + map['response_body'] = Variable<String>(responseBody.value); 12540 + } 12541 + if (timestamp.present) { 12542 + map['timestamp'] = Variable<DateTime>(timestamp.value); 12543 + } 12544 + if (durationMs.present) { 12545 + map['duration_ms'] = Variable<int>(durationMs.value); 12546 + } 12547 + if (error.present) { 12548 + map['error'] = Variable<String>(error.value); 12549 + } 12550 + return map; 12551 + } 12552 + 12553 + @override 12554 + String toString() { 12555 + return (StringBuffer('DevNetworkLogsCompanion(') 12556 + ..write('id: $id, ') 12557 + ..write('uuid: $uuid, ') 12558 + ..write('method: $method, ') 12559 + ..write('url: $url, ') 12560 + ..write('statusCode: $statusCode, ') 12561 + ..write('requestHeaders: $requestHeaders, ') 12562 + ..write('responseHeaders: $responseHeaders, ') 12563 + ..write('requestBody: $requestBody, ') 12564 + ..write('responseBody: $responseBody, ') 12565 + ..write('timestamp: $timestamp, ') 12566 + ..write('durationMs: $durationMs, ') 12567 + ..write('error: $error') 12568 + ..write(')')) 12569 + .toString(); 12570 + } 12571 + } 12572 + 11654 12573 abstract class _$AppDatabase extends GeneratedDatabase { 11655 12574 _$AppDatabase(QueryExecutor e) : super(e); 11656 12575 $AppDatabaseManager get managers => $AppDatabaseManager(this); ··· 11682 12601 late final $DmConvosTable dmConvos = $DmConvosTable(this); 11683 12602 late final $DmMessagesTable dmMessages = $DmMessagesTable(this); 11684 12603 late final $DmOutboxTable dmOutbox = $DmOutboxTable(this); 12604 + late final $DevSettingsTable devSettings = $DevSettingsTable(this); 12605 + late final $DevNetworkLogsTable devNetworkLogs = $DevNetworkLogsTable(this); 11685 12606 late final Index feedContentSortIdx = Index( 11686 12607 'feed_content_sort_idx', 11687 12608 'CREATE INDEX feed_content_sort_idx ON feed_content_items (feed_key, sort_key)', ··· 11731 12652 late final DmConvosDao dmConvosDao = DmConvosDao(this as AppDatabase); 11732 12653 late final DmMessagesDao dmMessagesDao = DmMessagesDao(this as AppDatabase); 11733 12654 late final DmOutboxDao dmOutboxDao = DmOutboxDao(this as AppDatabase); 12655 + late final DevToolsDao devToolsDao = DevToolsDao(this as AppDatabase); 11734 12656 @override 11735 12657 Iterable<TableInfo<Table, Object?>> get allTables => 11736 12658 allSchemaEntities.whereType<TableInfo<Table, Object?>>(); ··· 11761 12683 dmConvos, 11762 12684 dmMessages, 11763 12685 dmOutbox, 12686 + devSettings, 12687 + devNetworkLogs, 11764 12688 feedContentSortIdx, 11765 12689 recentSearchesUniqueIdx, 11766 12690 searchCacheSortIdx, ··· 18549 19473 DmOutboxData, 18550 19474 PrefetchHooks Function() 18551 19475 >; 19476 + typedef $$DevSettingsTableCreateCompanionBuilder = 19477 + DevSettingsCompanion Function({ 19478 + Value<int> id, 19479 + required String key, 19480 + required String value, 19481 + required String type, 19482 + }); 19483 + typedef $$DevSettingsTableUpdateCompanionBuilder = 19484 + DevSettingsCompanion Function({ 19485 + Value<int> id, 19486 + Value<String> key, 19487 + Value<String> value, 19488 + Value<String> type, 19489 + }); 19490 + 19491 + class $$DevSettingsTableFilterComposer extends Composer<_$AppDatabase, $DevSettingsTable> { 19492 + $$DevSettingsTableFilterComposer({ 19493 + required super.$db, 19494 + required super.$table, 19495 + super.joinBuilder, 19496 + super.$addJoinBuilderToRootComposer, 19497 + super.$removeJoinBuilderFromRootComposer, 19498 + }); 19499 + ColumnFilters<int> get id => 19500 + $composableBuilder(column: $table.id, builder: (column) => ColumnFilters(column)); 19501 + 19502 + ColumnFilters<String> get key => 19503 + $composableBuilder(column: $table.key, builder: (column) => ColumnFilters(column)); 19504 + 19505 + ColumnFilters<String> get value => 19506 + $composableBuilder(column: $table.value, builder: (column) => ColumnFilters(column)); 19507 + 19508 + ColumnFilters<String> get type => 19509 + $composableBuilder(column: $table.type, builder: (column) => ColumnFilters(column)); 19510 + } 19511 + 19512 + class $$DevSettingsTableOrderingComposer extends Composer<_$AppDatabase, $DevSettingsTable> { 19513 + $$DevSettingsTableOrderingComposer({ 19514 + required super.$db, 19515 + required super.$table, 19516 + super.joinBuilder, 19517 + super.$addJoinBuilderToRootComposer, 19518 + super.$removeJoinBuilderFromRootComposer, 19519 + }); 19520 + ColumnOrderings<int> get id => 19521 + $composableBuilder(column: $table.id, builder: (column) => ColumnOrderings(column)); 19522 + 19523 + ColumnOrderings<String> get key => 19524 + $composableBuilder(column: $table.key, builder: (column) => ColumnOrderings(column)); 19525 + 19526 + ColumnOrderings<String> get value => 19527 + $composableBuilder(column: $table.value, builder: (column) => ColumnOrderings(column)); 19528 + 19529 + ColumnOrderings<String> get type => 19530 + $composableBuilder(column: $table.type, builder: (column) => ColumnOrderings(column)); 19531 + } 19532 + 19533 + class $$DevSettingsTableAnnotationComposer extends Composer<_$AppDatabase, $DevSettingsTable> { 19534 + $$DevSettingsTableAnnotationComposer({ 19535 + required super.$db, 19536 + required super.$table, 19537 + super.joinBuilder, 19538 + super.$addJoinBuilderToRootComposer, 19539 + super.$removeJoinBuilderFromRootComposer, 19540 + }); 19541 + GeneratedColumn<int> get id => 19542 + $composableBuilder(column: $table.id, builder: (column) => column); 19543 + 19544 + GeneratedColumn<String> get key => 19545 + $composableBuilder(column: $table.key, builder: (column) => column); 19546 + 19547 + GeneratedColumn<String> get value => 19548 + $composableBuilder(column: $table.value, builder: (column) => column); 19549 + 19550 + GeneratedColumn<String> get type => 19551 + $composableBuilder(column: $table.type, builder: (column) => column); 19552 + } 19553 + 19554 + class $$DevSettingsTableTableManager 19555 + extends 19556 + RootTableManager< 19557 + _$AppDatabase, 19558 + $DevSettingsTable, 19559 + DevSetting, 19560 + $$DevSettingsTableFilterComposer, 19561 + $$DevSettingsTableOrderingComposer, 19562 + $$DevSettingsTableAnnotationComposer, 19563 + $$DevSettingsTableCreateCompanionBuilder, 19564 + $$DevSettingsTableUpdateCompanionBuilder, 19565 + (DevSetting, BaseReferences<_$AppDatabase, $DevSettingsTable, DevSetting>), 19566 + DevSetting, 19567 + PrefetchHooks Function() 19568 + > { 19569 + $$DevSettingsTableTableManager(_$AppDatabase db, $DevSettingsTable table) 19570 + : super( 19571 + TableManagerState( 19572 + db: db, 19573 + table: table, 19574 + createFilteringComposer: () => $$DevSettingsTableFilterComposer($db: db, $table: table), 19575 + createOrderingComposer: () => $$DevSettingsTableOrderingComposer($db: db, $table: table), 19576 + createComputedFieldComposer: () => 19577 + $$DevSettingsTableAnnotationComposer($db: db, $table: table), 19578 + updateCompanionCallback: 19579 + ({ 19580 + Value<int> id = const Value.absent(), 19581 + Value<String> key = const Value.absent(), 19582 + Value<String> value = const Value.absent(), 19583 + Value<String> type = const Value.absent(), 19584 + }) => DevSettingsCompanion(id: id, key: key, value: value, type: type), 19585 + createCompanionCallback: 19586 + ({ 19587 + Value<int> id = const Value.absent(), 19588 + required String key, 19589 + required String value, 19590 + required String type, 19591 + }) => DevSettingsCompanion.insert(id: id, key: key, value: value, type: type), 19592 + withReferenceMapper: (p0) => 19593 + p0.map((e) => (e.readTable(table), BaseReferences(db, table, e))).toList(), 19594 + prefetchHooksCallback: null, 19595 + ), 19596 + ); 19597 + } 19598 + 19599 + typedef $$DevSettingsTableProcessedTableManager = 19600 + ProcessedTableManager< 19601 + _$AppDatabase, 19602 + $DevSettingsTable, 19603 + DevSetting, 19604 + $$DevSettingsTableFilterComposer, 19605 + $$DevSettingsTableOrderingComposer, 19606 + $$DevSettingsTableAnnotationComposer, 19607 + $$DevSettingsTableCreateCompanionBuilder, 19608 + $$DevSettingsTableUpdateCompanionBuilder, 19609 + (DevSetting, BaseReferences<_$AppDatabase, $DevSettingsTable, DevSetting>), 19610 + DevSetting, 19611 + PrefetchHooks Function() 19612 + >; 19613 + typedef $$DevNetworkLogsTableCreateCompanionBuilder = 19614 + DevNetworkLogsCompanion Function({ 19615 + Value<int> id, 19616 + required String uuid, 19617 + required String method, 19618 + required String url, 19619 + required int statusCode, 19620 + required String requestHeaders, 19621 + required String responseHeaders, 19622 + Value<String?> requestBody, 19623 + Value<String?> responseBody, 19624 + required DateTime timestamp, 19625 + required int durationMs, 19626 + Value<String?> error, 19627 + }); 19628 + typedef $$DevNetworkLogsTableUpdateCompanionBuilder = 19629 + DevNetworkLogsCompanion Function({ 19630 + Value<int> id, 19631 + Value<String> uuid, 19632 + Value<String> method, 19633 + Value<String> url, 19634 + Value<int> statusCode, 19635 + Value<String> requestHeaders, 19636 + Value<String> responseHeaders, 19637 + Value<String?> requestBody, 19638 + Value<String?> responseBody, 19639 + Value<DateTime> timestamp, 19640 + Value<int> durationMs, 19641 + Value<String?> error, 19642 + }); 19643 + 19644 + class $$DevNetworkLogsTableFilterComposer extends Composer<_$AppDatabase, $DevNetworkLogsTable> { 19645 + $$DevNetworkLogsTableFilterComposer({ 19646 + required super.$db, 19647 + required super.$table, 19648 + super.joinBuilder, 19649 + super.$addJoinBuilderToRootComposer, 19650 + super.$removeJoinBuilderFromRootComposer, 19651 + }); 19652 + ColumnFilters<int> get id => 19653 + $composableBuilder(column: $table.id, builder: (column) => ColumnFilters(column)); 19654 + 19655 + ColumnFilters<String> get uuid => 19656 + $composableBuilder(column: $table.uuid, builder: (column) => ColumnFilters(column)); 19657 + 19658 + ColumnFilters<String> get method => 19659 + $composableBuilder(column: $table.method, builder: (column) => ColumnFilters(column)); 19660 + 19661 + ColumnFilters<String> get url => 19662 + $composableBuilder(column: $table.url, builder: (column) => ColumnFilters(column)); 19663 + 19664 + ColumnFilters<int> get statusCode => 19665 + $composableBuilder(column: $table.statusCode, builder: (column) => ColumnFilters(column)); 19666 + 19667 + ColumnFilters<String> get requestHeaders => $composableBuilder( 19668 + column: $table.requestHeaders, 19669 + builder: (column) => ColumnFilters(column), 19670 + ); 19671 + 19672 + ColumnFilters<String> get responseHeaders => $composableBuilder( 19673 + column: $table.responseHeaders, 19674 + builder: (column) => ColumnFilters(column), 19675 + ); 19676 + 19677 + ColumnFilters<String> get requestBody => 19678 + $composableBuilder(column: $table.requestBody, builder: (column) => ColumnFilters(column)); 19679 + 19680 + ColumnFilters<String> get responseBody => 19681 + $composableBuilder(column: $table.responseBody, builder: (column) => ColumnFilters(column)); 19682 + 19683 + ColumnFilters<DateTime> get timestamp => 19684 + $composableBuilder(column: $table.timestamp, builder: (column) => ColumnFilters(column)); 19685 + 19686 + ColumnFilters<int> get durationMs => 19687 + $composableBuilder(column: $table.durationMs, builder: (column) => ColumnFilters(column)); 19688 + 19689 + ColumnFilters<String> get error => 19690 + $composableBuilder(column: $table.error, builder: (column) => ColumnFilters(column)); 19691 + } 19692 + 19693 + class $$DevNetworkLogsTableOrderingComposer extends Composer<_$AppDatabase, $DevNetworkLogsTable> { 19694 + $$DevNetworkLogsTableOrderingComposer({ 19695 + required super.$db, 19696 + required super.$table, 19697 + super.joinBuilder, 19698 + super.$addJoinBuilderToRootComposer, 19699 + super.$removeJoinBuilderFromRootComposer, 19700 + }); 19701 + ColumnOrderings<int> get id => 19702 + $composableBuilder(column: $table.id, builder: (column) => ColumnOrderings(column)); 19703 + 19704 + ColumnOrderings<String> get uuid => 19705 + $composableBuilder(column: $table.uuid, builder: (column) => ColumnOrderings(column)); 19706 + 19707 + ColumnOrderings<String> get method => 19708 + $composableBuilder(column: $table.method, builder: (column) => ColumnOrderings(column)); 19709 + 19710 + ColumnOrderings<String> get url => 19711 + $composableBuilder(column: $table.url, builder: (column) => ColumnOrderings(column)); 19712 + 19713 + ColumnOrderings<int> get statusCode => 19714 + $composableBuilder(column: $table.statusCode, builder: (column) => ColumnOrderings(column)); 19715 + 19716 + ColumnOrderings<String> get requestHeaders => $composableBuilder( 19717 + column: $table.requestHeaders, 19718 + builder: (column) => ColumnOrderings(column), 19719 + ); 19720 + 19721 + ColumnOrderings<String> get responseHeaders => $composableBuilder( 19722 + column: $table.responseHeaders, 19723 + builder: (column) => ColumnOrderings(column), 19724 + ); 19725 + 19726 + ColumnOrderings<String> get requestBody => 19727 + $composableBuilder(column: $table.requestBody, builder: (column) => ColumnOrderings(column)); 19728 + 19729 + ColumnOrderings<String> get responseBody => $composableBuilder( 19730 + column: $table.responseBody, 19731 + builder: (column) => ColumnOrderings(column), 19732 + ); 19733 + 19734 + ColumnOrderings<DateTime> get timestamp => 19735 + $composableBuilder(column: $table.timestamp, builder: (column) => ColumnOrderings(column)); 19736 + 19737 + ColumnOrderings<int> get durationMs => 19738 + $composableBuilder(column: $table.durationMs, builder: (column) => ColumnOrderings(column)); 19739 + 19740 + ColumnOrderings<String> get error => 19741 + $composableBuilder(column: $table.error, builder: (column) => ColumnOrderings(column)); 19742 + } 19743 + 19744 + class $$DevNetworkLogsTableAnnotationComposer 19745 + extends Composer<_$AppDatabase, $DevNetworkLogsTable> { 19746 + $$DevNetworkLogsTableAnnotationComposer({ 19747 + required super.$db, 19748 + required super.$table, 19749 + super.joinBuilder, 19750 + super.$addJoinBuilderToRootComposer, 19751 + super.$removeJoinBuilderFromRootComposer, 19752 + }); 19753 + GeneratedColumn<int> get id => 19754 + $composableBuilder(column: $table.id, builder: (column) => column); 19755 + 19756 + GeneratedColumn<String> get uuid => 19757 + $composableBuilder(column: $table.uuid, builder: (column) => column); 19758 + 19759 + GeneratedColumn<String> get method => 19760 + $composableBuilder(column: $table.method, builder: (column) => column); 19761 + 19762 + GeneratedColumn<String> get url => 19763 + $composableBuilder(column: $table.url, builder: (column) => column); 19764 + 19765 + GeneratedColumn<int> get statusCode => 19766 + $composableBuilder(column: $table.statusCode, builder: (column) => column); 19767 + 19768 + GeneratedColumn<String> get requestHeaders => 19769 + $composableBuilder(column: $table.requestHeaders, builder: (column) => column); 19770 + 19771 + GeneratedColumn<String> get responseHeaders => 19772 + $composableBuilder(column: $table.responseHeaders, builder: (column) => column); 19773 + 19774 + GeneratedColumn<String> get requestBody => 19775 + $composableBuilder(column: $table.requestBody, builder: (column) => column); 19776 + 19777 + GeneratedColumn<String> get responseBody => 19778 + $composableBuilder(column: $table.responseBody, builder: (column) => column); 19779 + 19780 + GeneratedColumn<DateTime> get timestamp => 19781 + $composableBuilder(column: $table.timestamp, builder: (column) => column); 19782 + 19783 + GeneratedColumn<int> get durationMs => 19784 + $composableBuilder(column: $table.durationMs, builder: (column) => column); 19785 + 19786 + GeneratedColumn<String> get error => 19787 + $composableBuilder(column: $table.error, builder: (column) => column); 19788 + } 19789 + 19790 + class $$DevNetworkLogsTableTableManager 19791 + extends 19792 + RootTableManager< 19793 + _$AppDatabase, 19794 + $DevNetworkLogsTable, 19795 + DevNetworkLog, 19796 + $$DevNetworkLogsTableFilterComposer, 19797 + $$DevNetworkLogsTableOrderingComposer, 19798 + $$DevNetworkLogsTableAnnotationComposer, 19799 + $$DevNetworkLogsTableCreateCompanionBuilder, 19800 + $$DevNetworkLogsTableUpdateCompanionBuilder, 19801 + (DevNetworkLog, BaseReferences<_$AppDatabase, $DevNetworkLogsTable, DevNetworkLog>), 19802 + DevNetworkLog, 19803 + PrefetchHooks Function() 19804 + > { 19805 + $$DevNetworkLogsTableTableManager(_$AppDatabase db, $DevNetworkLogsTable table) 19806 + : super( 19807 + TableManagerState( 19808 + db: db, 19809 + table: table, 19810 + createFilteringComposer: () => 19811 + $$DevNetworkLogsTableFilterComposer($db: db, $table: table), 19812 + createOrderingComposer: () => 19813 + $$DevNetworkLogsTableOrderingComposer($db: db, $table: table), 19814 + createComputedFieldComposer: () => 19815 + $$DevNetworkLogsTableAnnotationComposer($db: db, $table: table), 19816 + updateCompanionCallback: 19817 + ({ 19818 + Value<int> id = const Value.absent(), 19819 + Value<String> uuid = const Value.absent(), 19820 + Value<String> method = const Value.absent(), 19821 + Value<String> url = const Value.absent(), 19822 + Value<int> statusCode = const Value.absent(), 19823 + Value<String> requestHeaders = const Value.absent(), 19824 + Value<String> responseHeaders = const Value.absent(), 19825 + Value<String?> requestBody = const Value.absent(), 19826 + Value<String?> responseBody = const Value.absent(), 19827 + Value<DateTime> timestamp = const Value.absent(), 19828 + Value<int> durationMs = const Value.absent(), 19829 + Value<String?> error = const Value.absent(), 19830 + }) => DevNetworkLogsCompanion( 19831 + id: id, 19832 + uuid: uuid, 19833 + method: method, 19834 + url: url, 19835 + statusCode: statusCode, 19836 + requestHeaders: requestHeaders, 19837 + responseHeaders: responseHeaders, 19838 + requestBody: requestBody, 19839 + responseBody: responseBody, 19840 + timestamp: timestamp, 19841 + durationMs: durationMs, 19842 + error: error, 19843 + ), 19844 + createCompanionCallback: 19845 + ({ 19846 + Value<int> id = const Value.absent(), 19847 + required String uuid, 19848 + required String method, 19849 + required String url, 19850 + required int statusCode, 19851 + required String requestHeaders, 19852 + required String responseHeaders, 19853 + Value<String?> requestBody = const Value.absent(), 19854 + Value<String?> responseBody = const Value.absent(), 19855 + required DateTime timestamp, 19856 + required int durationMs, 19857 + Value<String?> error = const Value.absent(), 19858 + }) => DevNetworkLogsCompanion.insert( 19859 + id: id, 19860 + uuid: uuid, 19861 + method: method, 19862 + url: url, 19863 + statusCode: statusCode, 19864 + requestHeaders: requestHeaders, 19865 + responseHeaders: responseHeaders, 19866 + requestBody: requestBody, 19867 + responseBody: responseBody, 19868 + timestamp: timestamp, 19869 + durationMs: durationMs, 19870 + error: error, 19871 + ), 19872 + withReferenceMapper: (p0) => 19873 + p0.map((e) => (e.readTable(table), BaseReferences(db, table, e))).toList(), 19874 + prefetchHooksCallback: null, 19875 + ), 19876 + ); 19877 + } 19878 + 19879 + typedef $$DevNetworkLogsTableProcessedTableManager = 19880 + ProcessedTableManager< 19881 + _$AppDatabase, 19882 + $DevNetworkLogsTable, 19883 + DevNetworkLog, 19884 + $$DevNetworkLogsTableFilterComposer, 19885 + $$DevNetworkLogsTableOrderingComposer, 19886 + $$DevNetworkLogsTableAnnotationComposer, 19887 + $$DevNetworkLogsTableCreateCompanionBuilder, 19888 + $$DevNetworkLogsTableUpdateCompanionBuilder, 19889 + (DevNetworkLog, BaseReferences<_$AppDatabase, $DevNetworkLogsTable, DevNetworkLog>), 19890 + DevNetworkLog, 19891 + PrefetchHooks Function() 19892 + >; 18552 19893 18553 19894 class $AppDatabaseManager { 18554 19895 final _$AppDatabase _db; ··· 18596 19937 $$DmMessagesTableTableManager get dmMessages => 18597 19938 $$DmMessagesTableTableManager(_db, _db.dmMessages); 18598 19939 $$DmOutboxTableTableManager get dmOutbox => $$DmOutboxTableTableManager(_db, _db.dmOutbox); 19940 + $$DevSettingsTableTableManager get devSettings => 19941 + $$DevSettingsTableTableManager(_db, _db.devSettings); 19942 + $$DevNetworkLogsTableTableManager get devNetworkLogs => 19943 + $$DevNetworkLogsTableTableManager(_db, _db.devNetworkLogs); 18599 19944 }
+83
lib/src/infrastructure/db/daos/dev_tools_dao.dart
··· 1 + import 'package:drift/drift.dart'; 2 + 3 + import '../app_database.dart'; 4 + import '../tables.dart'; 5 + 6 + part 'dev_tools_dao.g.dart'; 7 + 8 + @DriftAccessor(tables: [DevSettings, DevNetworkLogs]) 9 + class DevToolsDao extends DatabaseAccessor<AppDatabase> with _$DevToolsDaoMixin { 10 + DevToolsDao(super.db); 11 + 12 + Future<String?> getSetting(String key) async { 13 + final query = select(devSettings)..where((t) => t.key.equals(key)); 14 + final result = await query.getSingleOrNull(); 15 + return result?.value; 16 + } 17 + 18 + Future<void> setSetting(String key, String value, String type) async { 19 + await into(devSettings).insertOnConflictUpdate( 20 + DevSettingsCompanion(key: Value(key), value: Value(value), type: Value(type)), 21 + ); 22 + } 23 + 24 + Future<void> logRequest({ 25 + required String uuid, 26 + required String method, 27 + required String url, 28 + required int statusCode, 29 + required int durationMs, 30 + required String requestHeaders, 31 + required String responseHeaders, 32 + String? requestBody, 33 + String? responseBody, 34 + String? error, 35 + }) async { 36 + await into(devNetworkLogs).insert( 37 + DevNetworkLogsCompanion( 38 + uuid: Value(uuid), 39 + method: Value(method), 40 + url: Value(url), 41 + statusCode: Value(statusCode), 42 + durationMs: Value(durationMs), 43 + requestHeaders: Value(requestHeaders), 44 + responseHeaders: Value(responseHeaders), 45 + requestBody: Value(requestBody), 46 + responseBody: Value(responseBody), 47 + error: Value(error), 48 + timestamp: Value(DateTime.now()), 49 + ), 50 + ); 51 + 52 + await pruneLogs(1000); 53 + } 54 + 55 + Stream<List<DevNetworkLog>> watchLogs() { 56 + return (select(devNetworkLogs)..orderBy([ 57 + (t) => OrderingTerm(expression: t.timestamp, mode: OrderingMode.desc), 58 + (t) => OrderingTerm(expression: t.id, mode: OrderingMode.desc), 59 + ])) 60 + .watch(); 61 + } 62 + 63 + Future<void> clearLogs() async { 64 + await delete(devNetworkLogs).go(); 65 + } 66 + 67 + Future<void> pruneLogs(int limit) async { 68 + final idsToKeepQuery = select(devNetworkLogs, distinct: false) 69 + ..orderBy([ 70 + (t) => OrderingTerm(expression: t.timestamp, mode: OrderingMode.desc), 71 + (t) => OrderingTerm(expression: t.id, mode: OrderingMode.desc), 72 + ]) 73 + ..limit(limit); 74 + 75 + final idsToKeep = await idsToKeepQuery.map((row) => row.id).get(); 76 + 77 + if (idsToKeep.isEmpty) return; 78 + 79 + final deleteQuery = delete(devNetworkLogs)..where((t) => t.id.isNotIn(idsToKeep)); 80 + 81 + await deleteQuery.go(); 82 + } 83 + }
+9
lib/src/infrastructure/db/daos/dev_tools_dao.g.dart
··· 1 + // GENERATED CODE - DO NOT MODIFY BY HAND 2 + 3 + part of 'dev_tools_dao.dart'; 4 + 5 + // ignore_for_file: type=lint 6 + mixin _$DevToolsDaoMixin on DatabaseAccessor<AppDatabase> { 7 + $DevSettingsTable get devSettings => attachedDatabase.devSettings; 8 + $DevNetworkLogsTable get devNetworkLogs => attachedDatabase.devNetworkLogs; 9 + }
+26
lib/src/infrastructure/db/tables.dart
··· 633 633 @override 634 634 Set<Column> get primaryKey => {outboxId}; 635 635 } 636 + 637 + /// Stores developer settings/flags (e.g., debug mode enabled). 638 + class DevSettings extends Table { 639 + IntColumn get id => integer().autoIncrement()(); 640 + TextColumn get key => text().unique()(); 641 + TextColumn get value => text()(); 642 + 643 + /// Type of value: 'boolean', 'string', 'int' 644 + TextColumn get type => text()(); 645 + } 646 + 647 + /// Stores network logs for the debug inspector. 648 + class DevNetworkLogs extends Table { 649 + IntColumn get id => integer().autoIncrement()(); 650 + TextColumn get uuid => text().unique()(); 651 + TextColumn get method => text()(); 652 + TextColumn get url => text()(); 653 + IntColumn get statusCode => integer()(); 654 + TextColumn get requestHeaders => text()(); // JSON 655 + TextColumn get responseHeaders => text()(); // JSON 656 + TextColumn get requestBody => text().nullable()(); 657 + TextColumn get responseBody => text().nullable()(); 658 + DateTimeColumn get timestamp => dateTime()(); 659 + IntColumn get durationMs => integer()(); 660 + TextColumn get error => text().nullable()(); 661 + }
+8 -2
lib/src/infrastructure/network/dio_clients.dart
··· 10 10 /// 11 11 /// This client is used for unauthenticated reads like fetching profiles, threads, and 12 12 /// search results. 13 - Dio createPublicDio({bool enableLogging = true}) { 13 + Dio createPublicDio({bool enableLogging = true, List<Interceptor> interceptors = const []}) { 14 14 final dio = Dio( 15 15 BaseOptions( 16 16 baseUrl: publicApiBaseUrl, ··· 21 21 ), 22 22 ); 23 23 24 - dio.interceptors.addAll([if (enableLogging) LoggingInterceptor(), RetryInterceptor()]); 24 + dio.interceptors.addAll([ 25 + if (enableLogging) LoggingInterceptor(), 26 + ...interceptors, 27 + RetryInterceptor(), 28 + ]); 25 29 26 30 return dio; 27 31 } ··· 37 41 DPoPNonceStore? nonceStore, 38 42 SessionInvalidatedCallback? onSessionInvalidated, 39 43 bool enableLogging = true, 44 + List<Interceptor> interceptors = const [], 40 45 }) { 41 46 final dio = Dio( 42 47 BaseOptions( ··· 57 62 onSessionInvalidated: onSessionInvalidated, 58 63 ), 59 64 ProxyInterceptor(), 65 + ...interceptors, 60 66 RetryInterceptor(), 61 67 ]); 62 68
+7 -2
lib/src/infrastructure/network/providers.dart
··· 1 1 import 'package:dio/dio.dart'; 2 + import 'package:flutter/foundation.dart'; 2 3 import 'package:lazurite/src/app/providers.dart'; 3 4 import 'package:lazurite/src/core/auth/session_model.dart'; 4 5 import 'package:lazurite/src/core/utils/logger_provider.dart'; ··· 6 7 import 'package:lazurite/src/features/auth/domain/auth_state.dart'; 7 8 import 'package:riverpod_annotation/riverpod_annotation.dart'; 8 9 10 + import '../../features/debug/infrastructure/debug_network_interceptor.dart'; 9 11 import 'dio_clients.dart'; 10 12 import 'xrpc_client.dart'; 11 13 ··· 16 18 /// This client is configured for the public AppView at public.api.bsky.app. 17 19 @Riverpod(keepAlive: true) 18 20 Dio dioPublic(Ref ref) { 19 - return createPublicDio(); 21 + final db = ref.watch(appDatabaseProvider); 22 + return createPublicDio(interceptors: [if (kDebugMode) DebugNetworkInterceptor(db.devToolsDao)]); 20 23 } 21 24 22 25 /// Provides the PDS Dio client for authenticated API access. ··· 31 34 return null; 32 35 } 33 36 37 + final db = ref.watch(appDatabaseProvider); 38 + 34 39 return createPdsDio( 35 40 pdsUrl: session.pdsUrl, 36 41 getSession: () => _readCurrentSession(ref), ··· 38 43 nonceStore: ref.read(dpopNonceStoreProvider), 39 44 onSessionInvalidated: () { 40 45 try { 41 - final db = ref.read(appDatabaseProvider); 42 46 db.feedContentDao.clearFeedContent('home', session.did); 43 47 } catch (e) { 44 48 /* Ignore if database not available */ ··· 46 50 47 51 ref.read(authProvider.notifier).logout(); 48 52 }, 53 + interceptors: [if (kDebugMode) DebugNetworkInterceptor(db.devToolsDao)], 49 54 ); 50 55 } 51 56
+117
test/src/features/debug/infrastructure/debug_network_interceptor_test.dart
··· 1 + import 'package:dio/dio.dart'; 2 + import 'package:dio/io.dart'; 3 + import 'package:flutter_test/flutter_test.dart'; 4 + import 'package:lazurite/src/features/debug/infrastructure/debug_network_interceptor.dart'; 5 + import 'package:lazurite/src/infrastructure/db/daos/dev_tools_dao.dart'; 6 + import 'package:mocktail/mocktail.dart'; 7 + 8 + class MockDevToolsDao extends Mock implements DevToolsDao {} 9 + 10 + void main() { 11 + late DebugNetworkInterceptor interceptor; 12 + late MockDevToolsDao mockDao; 13 + late Dio dio; 14 + 15 + setUp(() { 16 + mockDao = MockDevToolsDao(); 17 + interceptor = DebugNetworkInterceptor(mockDao); 18 + dio = Dio()..interceptors.add(interceptor); 19 + 20 + registerFallbackValue(''); 21 + when( 22 + () => mockDao.logRequest( 23 + uuid: any(named: 'uuid'), 24 + method: any(named: 'method'), 25 + url: any(named: 'url'), 26 + statusCode: any(named: 'statusCode'), 27 + durationMs: any(named: 'durationMs'), 28 + requestHeaders: any(named: 'requestHeaders'), 29 + responseHeaders: any(named: 'responseHeaders'), 30 + requestBody: any(named: 'requestBody'), 31 + responseBody: any(named: 'responseBody'), 32 + error: any(named: 'error'), 33 + ), 34 + ).thenAnswer((_) async {}); 35 + }); 36 + 37 + test('logs successful request', () async { 38 + dio.httpClientAdapter = IOHttpClientAdapter() 39 + ..createHttpClient = () { 40 + throw 'Should not be called with mocked adapter logic? No wait, use HttpClientAdapter'; 41 + }; 42 + 43 + dio.httpClientAdapter = _MockAdapter( 44 + (options) => ResponseBody.fromString( 45 + '{"key":"value"}', 46 + 200, 47 + headers: { 48 + Headers.contentTypeHeader: [Headers.jsonContentType], 49 + }, 50 + ), 51 + ); 52 + 53 + await dio.get('https://example.com/api'); 54 + 55 + verify( 56 + () => mockDao.logRequest( 57 + uuid: any(named: 'uuid'), 58 + method: 'GET', 59 + url: 'https://example.com/api', 60 + statusCode: 200, 61 + durationMs: any(named: 'durationMs'), // > 0 62 + requestHeaders: any(named: 'requestHeaders'), 63 + responseHeaders: any(named: 'responseHeaders'), 64 + requestBody: any(named: 'requestBody'), 65 + responseBody: any(named: 'responseBody'), 66 + ), 67 + ).called(1); 68 + }); 69 + 70 + test('logs error request', () async { 71 + dio.httpClientAdapter = _MockAdapter( 72 + (options) => throw DioException( 73 + requestOptions: options, 74 + response: Response(requestOptions: options, statusCode: 404, data: 'Not Found'), 75 + type: DioExceptionType.badResponse, 76 + ), 77 + ); 78 + 79 + try { 80 + await dio.get('https://example.com/404'); 81 + } catch (_) {} 82 + 83 + verify( 84 + () => mockDao.logRequest( 85 + uuid: any(named: 'uuid'), 86 + method: 'GET', 87 + url: 'https://example.com/404', 88 + statusCode: 404, 89 + durationMs: any(named: 'durationMs'), 90 + requestHeaders: any(named: 'requestHeaders'), 91 + responseHeaders: any(named: 'responseHeaders'), 92 + requestBody: any(named: 'requestBody'), 93 + responseBody: any(named: 'responseBody'), 94 + ), 95 + ).called(1); 96 + }); 97 + } 98 + 99 + class _MockAdapter implements HttpClientAdapter { 100 + _MockAdapter(this.handler); 101 + 102 + final dynamic Function(RequestOptions options) handler; 103 + 104 + @override 105 + Future<ResponseBody> fetch( 106 + RequestOptions options, 107 + Stream<List<int>>? requestStream, 108 + Future? cancelFuture, 109 + ) async { 110 + final result = handler(options); 111 + if (result is ResponseBody) return result; 112 + throw result; 113 + } 114 + 115 + @override 116 + void close({bool force = false}) {} 117 + }
-2
test/src/features/debug/presentation/debug_overlay_host_test.dart
··· 129 129 130 130 expect(find.text('Debug Overlay'), findsNothing); 131 131 132 - // Simulate 2-finger press 133 132 final gesture1 = await tester.createGesture(kind: PointerDeviceKind.touch, pointer: 1); 134 133 final gesture2 = await tester.createGesture(kind: PointerDeviceKind.touch, pointer: 2); 135 134 ··· 137 136 await gesture2.down(const Offset(200, 200)); 138 137 await tester.pump(); 139 138 140 - // Hold for required duration (2 seconds) 141 139 await tester.pump(const Duration(seconds: 2)); 142 140 143 141 expect(find.text('Debug Overlay'), findsOneWidget);
+94
test/src/features/debug/presentation/network_inspector_tab_test.dart
··· 1 + import 'package:flutter/material.dart'; 2 + import 'package:flutter_riverpod/flutter_riverpod.dart'; 3 + import 'package:flutter_test/flutter_test.dart'; 4 + import 'package:lazurite/src/app/providers.dart'; 5 + import 'package:lazurite/src/features/debug/presentation/network_inspector_tab.dart'; 6 + import 'package:lazurite/src/infrastructure/db/app_database.dart'; 7 + import 'package:lazurite/src/infrastructure/db/daos/dev_tools_dao.dart'; 8 + import 'package:mocktail/mocktail.dart'; 9 + 10 + class MockAppDatabase extends Mock implements AppDatabase {} 11 + 12 + class MockDevToolsDao extends Mock implements DevToolsDao {} 13 + 14 + void main() { 15 + late MockAppDatabase mockDb; 16 + late MockDevToolsDao mockDao; 17 + 18 + setUp(() { 19 + mockDb = MockAppDatabase(); 20 + mockDao = MockDevToolsDao(); 21 + when(() => mockDb.devToolsDao).thenReturn(mockDao); 22 + }); 23 + 24 + testWidgets('NetworkInspectorTab displays logs', (tester) async { 25 + final logs = [ 26 + DevNetworkLog( 27 + id: 1, 28 + uuid: 'uuid-1', 29 + method: 'GET', 30 + url: 'https://example.com/api', 31 + statusCode: 200, 32 + requestHeaders: '{}', 33 + responseHeaders: '{}', 34 + timestamp: DateTime.now(), 35 + durationMs: 150, 36 + requestBody: null, 37 + responseBody: null, 38 + error: null, 39 + ), 40 + DevNetworkLog( 41 + id: 2, 42 + uuid: 'uuid-2', 43 + method: 'POST', 44 + url: 'https://example.com/api/create', 45 + statusCode: 201, 46 + requestHeaders: '{}', 47 + responseHeaders: '{}', 48 + timestamp: DateTime.now().subtract(const Duration(seconds: 1)), 49 + durationMs: 300, 50 + requestBody: '{"data": "test"}', 51 + responseBody: '{"id": "1"}', 52 + error: null, 53 + ), 54 + ]; 55 + 56 + when(() => mockDao.watchLogs()).thenAnswer((_) => Stream.value(logs)); 57 + 58 + await tester.pumpWidget( 59 + ProviderScope( 60 + overrides: [appDatabaseProvider.overrideWithValue(mockDb)], 61 + child: const MaterialApp(home: Scaffold(body: NetworkInspectorTab())), 62 + ), 63 + ); 64 + await tester.pump(); 65 + 66 + expect(find.text('2 Requests'), findsOneWidget); 67 + expect(find.text('GET'), findsOneWidget); 68 + expect(find.text('https://example.com/api'), findsOneWidget); 69 + expect(find.text('200'), findsOneWidget); 70 + expect(find.text('POST'), findsOneWidget); 71 + expect(find.text('201'), findsOneWidget); 72 + 73 + await tester.tap(find.text('GET')); 74 + await tester.pumpAndSettle(); 75 + 76 + expect(find.text('General'), findsOneWidget); 77 + expect(find.text('Duration'), findsOneWidget); 78 + expect(find.widgetWithText(SelectableText, '150ms'), findsOneWidget); 79 + }); 80 + 81 + testWidgets('NetworkInspectorTab displays empty state', (tester) async { 82 + when(() => mockDao.watchLogs()).thenAnswer((_) => Stream.value([])); 83 + 84 + await tester.pumpWidget( 85 + ProviderScope( 86 + overrides: [appDatabaseProvider.overrideWithValue(mockDb)], 87 + child: const MaterialApp(home: Scaffold(body: NetworkInspectorTab())), 88 + ), 89 + ); 90 + await tester.pump(); 91 + 92 + expect(find.text('No network logs recorded.'), findsOneWidget); 93 + }); 94 + }
+2 -3
test/src/features/settings/presentation/screens/about_screen_test.dart
··· 205 205 ); 206 206 await tester.pumpAndSettle(); 207 207 208 - // Find logo. It's the first SvgPicture in the list (Header). 209 208 final logoFinder = find.byType(SvgPicture).first; 210 209 211 210 await tester.tap(logoFinder); ··· 215 214 await tester.tap(logoFinder); 216 215 await tester.pump(); 217 216 218 - // Verify toggle was called (mock controller manually tracks calls or we check state change if implementation updates state) 219 217 expect(mockController.toggleCalled, isTrue); 220 218 }); 221 219 }); ··· 233 231 state = state.copyWith(isVisible: !state.isVisible); 234 232 } 235 233 236 - // Stubs for other members to satisfy interface if needed, or stick to what's used. 237 234 @override 238 235 void show() {} 236 + 239 237 @override 240 238 void hide() {} 239 + 241 240 @override 242 241 void setTab(int index) {} 243 242 }
+86
test/src/infrastructure/db/daos/dev_tools_dao_test.dart
··· 1 + import 'package:drift/native.dart'; 2 + import 'package:flutter_test/flutter_test.dart'; 3 + import 'package:lazurite/src/infrastructure/db/app_database.dart'; 4 + import 'package:lazurite/src/infrastructure/db/daos/dev_tools_dao.dart'; 5 + 6 + void main() { 7 + late AppDatabase db; 8 + late DevToolsDao dao; 9 + 10 + setUp(() { 11 + db = AppDatabase(NativeDatabase.memory()); 12 + dao = DevToolsDao(db); 13 + }); 14 + 15 + tearDown(() async { 16 + await db.close(); 17 + }); 18 + 19 + group('DevToolsDao', () { 20 + test('getSetSetting stores and retrieves settings', () async { 21 + await dao.setSetting('debug_mode', 'true', 'boolean'); 22 + final value = await dao.getSetting('debug_mode'); 23 + expect(value, 'true'); 24 + 25 + final missing = await dao.getSetting('non_existent'); 26 + expect(missing, null); 27 + }); 28 + 29 + test('logRequest stores network log', () async { 30 + await dao.logRequest( 31 + uuid: 'uuid-1', 32 + method: 'GET', 33 + url: 'https://example.com', 34 + statusCode: 200, 35 + durationMs: 100, 36 + requestHeaders: '{}', 37 + responseHeaders: '{}', 38 + ); 39 + 40 + final logs = await dao.watchLogs().first; 41 + expect(logs.length, 1); 42 + expect(logs.first.url, 'https://example.com'); 43 + expect(logs.first.statusCode, 200); 44 + }); 45 + 46 + test('pruneLogs limits log count', () async { 47 + for (var i = 0; i < 10; i++) { 48 + await dao.logRequest( 49 + uuid: 'uuid-$i', 50 + method: 'GET', 51 + url: 'https://example.com/$i', 52 + statusCode: 200, 53 + durationMs: 100, 54 + requestHeaders: '{}', 55 + responseHeaders: '{}', 56 + ); 57 + } 58 + 59 + var logs = await dao.watchLogs().first; 60 + expect(logs.length, 10); 61 + 62 + await dao.pruneLogs(5); 63 + 64 + logs = await dao.watchLogs().first; 65 + expect(logs.length, 5); 66 + expect(logs.first.url, 'https://example.com/9'); 67 + expect(logs.last.url, 'https://example.com/5'); 68 + }); 69 + 70 + test('clearLogs removes all logs', () async { 71 + await dao.logRequest( 72 + uuid: 'uuid-1', 73 + method: 'GET', 74 + url: 'https://example.com', 75 + statusCode: 200, 76 + durationMs: 100, 77 + requestHeaders: '{}', 78 + responseHeaders: '{}', 79 + ); 80 + 81 + await dao.clearLogs(); 82 + final logs = await dao.watchLogs().first; 83 + expect(logs, isEmpty); 84 + }); 85 + }); 86 + }
+14 -1
test/src/infrastructure/network/providers_test.dart
··· 4 4 import 'package:lazurite/src/core/auth/session_model.dart'; 5 5 import 'package:lazurite/src/features/auth/application/auth_providers.dart'; 6 6 import 'package:lazurite/src/features/auth/domain/auth_state.dart'; 7 + import 'package:lazurite/src/infrastructure/db/daos/dev_tools_dao.dart'; 7 8 import 'package:lazurite/src/infrastructure/db/daos/feed_content_dao.dart'; 8 9 import 'package:lazurite/src/infrastructure/network/interceptors/auth_interceptor.dart'; 9 10 import 'package:lazurite/src/infrastructure/network/providers.dart'; ··· 12 13 import '../../../helpers/mocks.dart'; 13 14 14 15 class MockFeedContentDao extends Mock implements FeedContentDao {} 16 + 17 + class MockDevToolsDao extends Mock implements DevToolsDao {} 15 18 16 19 class TestAuthNotifier extends AuthNotifier { 17 20 TestAuthNotifier(this._initialState, {this.refreshedSession}); ··· 53 56 void main() { 54 57 group('dioPublicProvider', () { 55 58 test('creates Dio configured for public API', () { 56 - final container = ProviderContainer(); 59 + final database = MockAppDatabase(); 60 + final devToolsDao = MockDevToolsDao(); 61 + when(() => database.devToolsDao).thenReturn(devToolsDao); 62 + 63 + final container = ProviderContainer( 64 + overrides: [appDatabaseProvider.overrideWithValue(database)], 65 + ); 57 66 addTearDown(container.dispose); 58 67 59 68 final dio = container.read(dioPublicProvider); ··· 65 74 late MockSessionStorage mockSessionStorage; 66 75 late MockAppDatabase mockDatabase; 67 76 late MockFeedContentDao mockFeedContentDao; 77 + late MockDevToolsDao mockDevToolsDao; 68 78 69 79 setUp(() { 70 80 mockSessionStorage = MockSessionStorage(); 71 81 mockDatabase = MockAppDatabase(); 72 82 mockFeedContentDao = MockFeedContentDao(); 83 + mockDevToolsDao = MockDevToolsDao(); 73 84 74 85 when(() => mockSessionStorage.getSession()).thenAnswer((_) async => null); 75 86 when(() => mockSessionStorage.clearSession()).thenAnswer((_) async {}); 76 87 when(() => mockDatabase.feedContentDao).thenReturn(mockFeedContentDao); 88 + when(() => mockDatabase.devToolsDao).thenReturn(mockDevToolsDao); 77 89 when(() => mockFeedContentDao.clearFeedContent(any(), any())).thenAnswer((_) async {}); 78 90 }); 79 91 ··· 96 108 overrides: [ 97 109 sessionStorageProvider.overrideWithValue(mockSessionStorage), 98 110 authProvider.overrideWith(() => notifier), 111 + appDatabaseProvider.overrideWithValue(mockDatabase), 99 112 ], 100 113 ); 101 114 addTearDown(container.dispose);