{"id":51367815,"url":"https://github.com/gustavorviana/filehub","last_synced_at":"2026-07-03T03:01:13.948Z","repository":{"id":351891800,"uuid":"1197249373","full_name":"gustavorviana/FileHub","owner":"gustavorviana","description":"One storage API for .NET. Write against IFileHub and run on disk, memory, S3, OCI, or FTP — swap the driver, keep the code.","archived":false,"fork":false,"pushed_at":"2026-06-30T18:27:28.000Z","size":904,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-30T20:17:19.382Z","etag":null,"topics":["abstraction","csharp","dependency-injection","dotnet","filesystem","ftp","nuget","oci","s3","storage"],"latest_commit_sha":null,"homepage":"","language":"C#","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/gustavorviana.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-31T12:45:03.000Z","updated_at":"2026-05-20T20:05:11.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gustavorviana/FileHub","commit_stats":null,"previous_names":["gustavorviana/filehub"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/gustavorviana/FileHub","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavorviana%2FFileHub","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavorviana%2FFileHub/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavorviana%2FFileHub/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavorviana%2FFileHub/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gustavorviana","download_url":"https://codeload.github.com/gustavorviana/FileHub/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gustavorviana%2FFileHub/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35070339,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-03T02:00:05.635Z","response_time":110,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["abstraction","csharp","dependency-injection","dotnet","filesystem","ftp","nuget","oci","s3","storage"],"created_at":"2026-07-03T03:00:58.453Z","updated_at":"2026-07-03T03:01:13.939Z","avatar_url":"https://github.com/gustavorviana.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# FileHub\n\n[![CI](https://github.com/gustavorviana/FileHub/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/gustavorviana/FileHub/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE.txt)\n\nA .NET storage abstraction. One API (`IFileHub` → `FileDirectory` → `FileEntry`) across local disk, in-memory, and cloud object storage — swap the driver, keep the code.\n\n```csharp\nusing FileHub.Local;\n\nvar hub = new LocalFileHub(@\"C:\\data\");        // or: new MemoryFileHub();\nvar file = hub.Root.CreateFile(\"hello.txt\");   // anywhere under the sandbox root\nfile.SetText(\"hi\");\n\nConsole.WriteLine(file.ReadAllText());\n```\n\n## Why\n\nMost .NET apps end up with `System.IO.File` scattered across services, or coupled to a cloud SDK whose types leak into every layer. When the storage backend has to change — \"move uploads to S3\", \"keep tests off the disk\", \"sandbox per-tenant data\" — the refactor hurts because the boundary was never drawn.\n\nFileHub draws it once. A service like `ReportService(IFileHub hub)` is written once, unit-tested against memory, run locally against disk, and deployed to the cloud against an object store — without a single line changing in the service.\n\n## What's in the box\n\n- **Drivers**: `FileHub.Local` (disk), `FileHub.Memory` (in-process), `FileHub.OracleObjectStorage` (OCI), `FileHub.Ftp` (FTP server). Custom drivers implement two abstract classes.\n- **Sync + async** on the same types. Async is the source of truth; sync delegates.\n- **Sandboxed by default** — every hub has a root. `..`, absolute paths, and symlink escapes are rejected.\n- **Read-only on demand** — `dir.AsReadOnly()` / `file.AsReadOnly()` wraps anything and blocks writes at runtime.\n- **DI integration** — `FileHub.DependencyInjection` ships `AddFileHub` / `AddNamedFileHubs` with lifetime + `IServiceProvider` support for tenant scoping.\n- **Nested paths** — `CreateDirectory(\"a/b/c\")` and `TryOpenDirectory(\"a/b/c\", out _)` work on every driver. `DirectoryPathMode.Direct` (default on cloud drivers) collapses it to a single API call.\n- **Zero external deps in core**. Multi-targets `netstandard2.0;net8.0`.\n\n## Install\n\n```bash\ndotnet add package FileHub\ndotnet add package FileHub.DependencyInjection    # optional\ndotnet add package FileHub.OracleObjectStorage    # optional\ndotnet add package FileHub.Ftp                    # optional\n```\n\n## Named hubs (tenant, multi-backend)\n\n```csharp\nservices.AddNamedFileHubs(b =\u003e b\n    .Register(\"reports\", new MemoryFileHub())\n    .Register(\n        \"tenant\",\n        sp =\u003e new LocalFileHub($@\"C:\\tenants\\{sp.GetRequiredService\u003cITenantContext\u003e().Id}\"),\n        ServiceLifetime.Scoped));\n```\n\nInject `INamedFileHubs` and call `GetByName(\"tenant\")`.\n\n## Documentation\n\nFull docs live in the [wiki](FileHub.wiki/Home.md):\n\n- [Quick Start](FileHub.wiki/Quick-Start.md) — install, hubs, files, directories\n- [API reference](FileHub.wiki/API.md) — `IFileHub`, `FileDirectory`, `FileEntry`, exceptions\n- [Drivers](FileHub.wiki/Driver-Local.md) — [Local](FileHub.wiki/Driver-Local.md), [Memory](FileHub.wiki/Driver-Memory.md), [OCI](FileHub.wiki/Driver-Oracle-Object-Storage.md), [FTP](FileHub.wiki/Driver-Ftp.md)\n- [Usage patterns](FileHub.wiki/Usage.md) — sync/async, streams, pagination\n- [Security](FileHub.wiki/Security.md) — sandbox and read-only mode\n- [Dependency injection](FileHub.wiki/Dependency-Injection.md) · [Custom drivers](FileHub.wiki/Custom-Drivers.md) · [Testing](FileHub.wiki/Testing.md)\n\n## License\n\nMIT — see [LICENSE.txt](LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgustavorviana%2Ffilehub","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgustavorviana%2Ffilehub","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgustavorviana%2Ffilehub/lists"}