sanmai/hoa-protocol
PHP library from the Hoa project offering a unified abstraction for resources and paths. It implements a hoa:// protocol with mount points and routers, letting applications resolve virtual paths across filesystems and custom backends in a consistent, extensible way. Maintained fork for legacy projec...
app://, package://, tenant://) where each node holds an ordered list of candidate locations, tried first-to-last. That is exactly the data model for "ship a default theme, let the customer override it, let a plugin override that."resolve() bakes in is_file()-style local-disk checks; stripping it lets your code take the candidate list and check existence through Laravel's Storage/Flysystem instead — which is what makes S3-, GCS-, or CDN-backed assets a config change rather than a second abstraction.Reasonable fit when:
Hoa\Protocol's root API and need it to run under Laravel without Hoa's filesystem-bound resolver or wrapper side effects.Look elsewhere when:
Illuminate\Support\Facades\File, or symfony/finder, does it with no new concept.league/flysystem, not this.Executives: There is no license cost and no lock-in, so the decision is about risk, not money. The package is a maintenance orphan — archived, zero adopters, one maintainer — so we should not take it as a live dependency. Recommendation: copy the small amount of code we need into our own repository, keep the BSD attribution, and own it. Cost is hours, not weeks, and it removes a future audit and upgrade problem.
Engineering: It is the registry half of Hoa\Protocol without the half that assumes a local disk. You define roots, push ordered candidate paths onto them, and read the candidate list back; we implement resolution, so it works with any Flysystem disk and stays testable. The surface area is small, the semantics are the ones we already want for theme and plugin overrides, and vendoring means we can refactor it freely.
Risks and mitigations: Archived upstream, single maintainer, no dependents — so no CVE pipeline and no upgrade path. Mitigate by vendoring rather than requiring it, pinning it behind our own thin interface, and writing tests that lock the behaviour we depend on so a future replacement is a one-file change. If the team would rather not own even that, the fallback is a short in-house root registry — the concept is simple enough that this is a legitimate build-over-buy call.
How can I help you explore Laravel packages today?