{"id":29562723,"url":"https://github.com/nikaera/aero_cache","last_synced_at":"2025-07-18T18:01:49.064Z","repository":{"id":304088483,"uuid":"1016583511","full_name":"nikaera/aero_cache","owner":"nikaera","description":"A high-performance HTTP caching library for Dart/Flutter with zstd compression, ETag/Last-Modified revalidation, and full Cache-Control directive support. ☁️","archived":false,"fork":false,"pushed_at":"2025-07-11T07:16:14.000Z","size":151,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-07-11T07:17:13.379Z","etag":null,"topics":["caching","compression","dart","flutter","http","image","media","video"],"latest_commit_sha":null,"homepage":"https://pub.dev/packages/aero_cache","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nikaera.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-09T08:19:05.000Z","updated_at":"2025-07-11T07:16:16.000Z","dependencies_parsed_at":"2025-07-11T07:18:03.747Z","dependency_job_id":"af77f055-9cc8-4a9f-9c48-bf7527802227","html_url":"https://github.com/nikaera/aero_cache","commit_stats":null,"previous_names":["nikaera/aero_cache"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/nikaera/aero_cache","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Faero_cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Faero_cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Faero_cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Faero_cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nikaera","download_url":"https://codeload.github.com/nikaera/aero_cache/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nikaera%2Faero_cache/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265806204,"owners_count":23831266,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["caching","compression","dart","flutter","http","image","media","video"],"created_at":"2025-07-18T18:01:13.666Z","updated_at":"2025-07-18T18:01:49.019Z","avatar_url":"https://github.com/nikaera.png","language":"Dart","readme":"# AeroCache ☁️\n\n\u003cimg src=\"https://github.com/user-attachments/assets/63710118-2c6e-4402-92ad-d7eb0ea27208\" width=\"80%\"/\u003e\n\n[![CI](https://github.com/nikaera/aero_cache/actions/workflows/project-ci.yaml/badge.svg)](https://github.com/nikaera/aero_cache/actions/workflows/project-ci.yaml)\n[![pub package](https://img.shields.io/pub/v/aero_cache.svg)](https://pub.dev/packages/aero_cache)\n[![style: very good analysis](https://img.shields.io/badge/style-very_good_analysis-B22C89.svg)](https://pub.dev/packages/very_good_analysis)\n\nA high-performance HTTP caching library for Dart/Flutter with zstd compression, ETag/Last-Modified revalidation, and full Cache-Control directive support.\n\n## Features ✨🚀\n\n- ⚡️ **High Performance**: Efficient caching with zstd compression for optimal storage\n- 🏷️ **ETag Support**: Automatic cache revalidation using ETag headers\n- 🕒 **Last-Modified Support**: Fallback cache validation using Last-Modified headers\n- 🧩 **Vary Header Support**: Intelligent cache key generation based on Vary header specifications\n- 🛡️ **Cache Control Directives**: Support for no-cache, no-store, must-revalidate, max-age, max-stale, min-fresh, only-if-cached, stale-while-revalidate, and stale-if-error\n- 🔄 **Background Revalidation**: Stale-while-revalidate support for serving stale content while updating cache\n- 🛠️ **Error Resilience**: Stale-if-error support for serving cached content during network failures\n- 📈 **Progress Tracking**: Real-time download progress callbacks\n- 🧹 **Automatic Cleanup**: Built-in expired cache cleanup\n- ⚙️ **Flexible Configuration**: Customizable cache directory and compression settings\n- 🚨 **Exception Handling**: Comprehensive error handling with custom exceptions\n\n## Installation 🛠️\n\nAdd this to your package's `pubspec.yaml` file:\n\n```yaml\ndependencies:\n  aero_cache: ^1.0.0\n```\n\nThen run:\n\n```bash\nflutter pub get\n```\n\n## Usage 📦\n\n### Basic Usage 🏁\n\n```dart\nimport 'package:aero_cache/aero_cache.dart';\n\nvoid main() async {\n  // Create AeroCache instance\n  final cache = AeroCache();\n  \n  // Initialize the cache\n  await cache.initialize();\n  \n  // Get data (downloads if not cached or stale)\n  final data = await cache.get('https://example.com/image.jpg');\n  \n  // Use the data\n  print('Downloaded ${data.length} bytes');\n  \n  // Clean up\n  cache.dispose();\n}\n```\n\n### Advanced Usage ⚙️\n\n```dart\nimport 'package:aero_cache/aero_cache.dart';\n\nvoid main() async {\n  // Create AeroCache with custom configuration\n  final cache = AeroCache(\n    disableCompression: false,  // Enable zstd compression\n    compressionLevel: 6,        // Custom compression level (1-22)\n    cacheDirPath: '/custom/cache/path',  // Custom cache directory\n    defaultCacheDuration: const Duration(hours: 24),  // Custom cache duration\n  );\n  \n  await cache.initialize();\n  \n  // Get data with progress tracking\n  final data = await cache.get(\n    'https://example.com/large-file.zip',\n    onProgress: (received, total) {\n      final progress = (received / total * 100).toStringAsFixed(1);\n      print('Download progress: $progress%');\n    },\n  );\n  \n  // Get metadata information\n  final metaInfo = await cache.metaInfo('https://example.com/large-file.zip');\n  if (metaInfo != null) {\n    print('ETag: ${metaInfo.etag}');\n    print('Last Modified: ${metaInfo.lastModified}');\n    print('Is Stale: ${metaInfo.isStale}');\n    print('Expires At: ${metaInfo.expiresAt}');\n    print('Content Type: ${metaInfo.contentType}');\n  }\n  \n  // Clear expired cache\n  await cache.clearExpiredCache();\n  \n  // Clear all cache\n  await cache.clearAllCache();\n  \n  cache.dispose();\n}\n```\n\n### Vary Header Handling 🧩\n\n```dart\nimport 'package:aero_cache/aero_cache.dart';\n\nvoid main() async {\n  final cache = AeroCache();\n  await cache.initialize();\n  \n  // First request with English accept-language\n  final data1 = await cache.get(\n    'https://api.example.com/content',\n    headers: {\n      'Accept-Language': 'en-US',\n      'User-Agent': 'MyApp/1.0',\n      'Accept-Encoding': 'gzip',\n    },\n  );\n  \n  // Second request with different accept-language\n  // This will create a separate cache entry if the server's response\n  // includes \"Vary: Accept-Language\"\n  final data2 = await cache.get(\n    'https://api.example.com/content',\n    headers: {\n      'Accept-Language': 'ja-JP',\n      'User-Agent': 'MyApp/1.0',\n      'Accept-Encoding': 'gzip',\n    },\n  );\n  \n  cache.dispose();\n}\n```\n\n### Cache Control Directives 🛡️\n\n```dart\nimport 'package:aero_cache/aero_cache.dart';\n\nvoid main() async {\n  final cache = AeroCache();\n  await cache.initialize();\n  \n  // Force bypass cache and download fresh data\n  final freshData = await cache.get(\n    'https://api.example.com/data',\n    noCache: true,\n  );\n  \n  // Only use cached data, fail if not available\n  try {\n    final cachedData = await cache.get(\n      'https://api.example.com/data',\n      onlyIfCached: true,\n    );\n  } catch (e) {\n    print('No cached data available');\n  }\n  \n  // Accept stale data up to 3600 seconds old\n  final staleData = await cache.get(\n    'https://api.example.com/data',\n    maxStale: 3600,\n  );\n  \n  // Require data to be fresh for at least 300 seconds\n  final freshRequiredData = await cache.get(\n    'https://api.example.com/data',\n    minFresh: 300,\n  );\n  \n  // Download without caching (no-store equivalent)\n  final temporaryData = await cache.get(\n    'https://api.example.com/data',\n    noStore: true,\n  );\n  \n  cache.dispose();\n}\n```\n\n### Flutter Integration 🐦\n\n```dart\nimport 'package:flutter/material.dart';\nimport 'package:aero_cache/aero_cache.dart';\n\nclass ImageWidget extends StatefulWidget {\n  final String imageUrl;\n  \n  const ImageWidget({Key? key, required this.imageUrl}) : super(key: key);\n  \n  @override\n  _ImageWidgetState createState() =\u003e _ImageWidgetState();\n}\n\nclass _ImageWidgetState extends State\u003cImageWidget\u003e {\n  final AeroCache _cache = AeroCache();\n  Uint8List? _imageData;\n  bool _isLoading = true;\n  double _progress = 0.0;\n  \n  @override\n  void initState() {\n    super.initState();\n    _loadImage();\n  }\n  \n  Future\u003cvoid\u003e _loadImage() async {\n    try {\n      await _cache.initialize();\n      final data = await _cache.get(\n        widget.imageUrl,\n        onProgress: (received, total) {\n          setState(() {\n            _progress = received / total;\n          });\n        },\n      );\n      setState(() {\n        _imageData = data;\n        _isLoading = false;\n      });\n    } catch (e) {\n      setState(() {\n        _isLoading = false;\n      });\n      // Handle error\n    }\n  }\n  \n  @override\n  Widget build(BuildContext context) {\n    if (_isLoading) {\n      return Column(\n        mainAxisAlignment: MainAxisAlignment.center,\n        children: [\n          const CircularProgressIndicator(),\n          const SizedBox(height: 8),\n          Text('${(_progress * 100).toInt()}%'),\n        ],\n      );\n    }\n    \n    if (_imageData != null) {\n      return Image.memory(_imageData!);\n    }\n    \n    return const Icon(Icons.error);\n  }\n  \n  @override\n  void dispose() {\n    _cache.dispose();\n    super.dispose();\n  }\n}\n```\n\n[API Reference 📚](https://nikaera.com/aero_cache/)\n\n## Performance ⚡️\n\nAeroCache uses zstd compression by default, which provides:\n- Fast compression/decompression speeds\n- Excellent compression ratios\n- Low memory usage\n\nBenchmarks show significant storage savings compared to uncompressed caching, especially for text-based content like JSON and HTML.\n\n## Vary Header Support 🧩\n\nAeroCache intelligently handles the `Vary` header to ensure correct cache behavior when responses depend on request headers. When a server includes a `Vary` header in its response, AeroCache automatically:\n\n- Parses the `Vary` header to identify which request headers affect the response\n- Incorporates relevant request header values into the cache key calculation\n- Ensures cache hits only occur when the specified request headers match exactly\n- Supports common headers like `Accept-Encoding`, `User-Agent`, `Accept-Language`, etc.\n\nThis ensures that cached responses are served only when appropriate, preventing issues like serving compressed content to clients that don't support compression.\n\n## Contributing 🤝\n\nWe welcome contributions to AeroCache! Please follow the GitHub Flow process:\n\n### How to Contribute\n\n1. **Fork the repository** on GitHub\n2. **Create a feature branch** from `main`:\n   ```bash\n   git checkout -b feature/your-feature-name\n   ```\n3. **Make your changes** and add tests if applicable\n4. **Ensure all tests pass**:\n   ```bash\n   flutter test\n   ```\n5. **Follow the code style** using `very_good_analysis`:\n   ```bash\n   dart analyze\n   ```\n6. **Commit your changes** with a clear message:\n   ```bash\n   git commit -m \"Add: your feature description\"\n   ```\n7. **Push to your fork**:\n   ```bash\n   git push origin feature/your-feature-name\n   ```\n8. **Create a Pull Request** on GitHub with:\n   - Clear description of changes\n   - Reference any related issues\n   - Screenshots if applicable\n\n### Development Setup 🧑‍💻\n\n1. Clone the repository:\n   ```bash\n   git clone https://github.com/your-username/aero_cache.git\n   cd aero_cache\n   ```\n\n2. Install dependencies:\n   ```bash\n   flutter pub get\n   ```\n\n3. Run tests:\n   ```bash\n   flutter test\n   ```\n\n4. Run the example:\n   ```bash\n   cd example\n   flutter run\n   ```\n\n### Code Style 🎨\n\n- Follow the official [Dart style guide](https://dart.dev/guides/language/effective-dart/style)\n- Use `very_good_analysis` linting rules\n- Write comprehensive tests for new features\n- Add documentation for public APIs\n\n## Support 💬\n\nFor questions and support:\n- Check the [example](example/) directory for usage examples\n- Open an issue on GitHub for bugs or feature requests\n- Review the API documentation\n\n### Reporting Issues 🐞\n\nWhen reporting issues, please include:\n- Flutter/Dart version\n- Operating system\n- Steps to reproduce\n- Expected vs actual behavior\n- Code samples if applicable\n\n## Changelog 📝\n\nSee [CHANGELOG.md](CHANGELOG.md) for version history and changes.\n\n## License 📄\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikaera%2Faero_cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnikaera%2Faero_cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnikaera%2Faero_cache/lists"}