omnihub / github
Omnihub's GitHub provider: a static hub's packages read from GitHub - each repository's releases, their .tgz assets (npm pack's tarball), their package.json and hashes.
Requires
- php: >=8.2
- omnisense/contracts: ^1.0
- omnisense/omnihub: ^1.0
- symfony/http-client: ^6.4|^7.0|^8.0
- symfony/http-client-contracts: ^3.0
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-14 02:22:16 UTC
README
Omnihub's GitHub provider: a hub's packages read from GitHub repositories.
Each published release (not a draft) whose assets hold a .tgz - what
npm pack makes - is a version: the tarball downloaded once, its
package.json read, its sha1 and sha512 taken, the release's notes as its
changelog. Unity installs the asset itself: the tarball stays on GitHub.
Installation and a first call
composer require omnihub/github
It requires omnisense/omnihub and symfony/http-client. No account is needed
for public repositories: anonymous calls are allowed (60 requests an hour by
GitHub's rules); a token (GITHUB_TOKEN, a GitHub Action's own) raises the
limit. Only GitHub's REST API is read, never a page of github.com.
require __DIR__.'/vendor/autoload.php'; use Omnihub\GitHub\Repository; use Omnihub\Upm\Registry; use Symfony\Component\HttpClient\HttpClient; $packages = (new Repository('mystudio/tool', HttpClient::create(), getenv('GITHUB_TOKEN') ?: null))->packages(); foreach ($packages as $package) { echo Registry::json(Registry::document($package)), "\n"; // what Unity reads at GET /<name> }
In hub.yaml (vendor/bin/omnihub build): - github: mystudio/tool, and
optionally asset: '/\.tgz$/' to choose which assets count. GITHUB_TOKEN,
when set (a GitHub Action's own), lifts the API's limits. bin/omnihub reads
every repository and source of a build through one Api (the fifth argument
of Repository), so the rate limit, the usage policy and the kept ETags count
across them.
A GitHub owner, resolved at build time
A github source of hub.yaml - an owner and a pattern of repository names -
is written into hub.json as it is, for the hub clients to resolve. Asked to
(omnihub build hub.yaml _site --resolve-github), this package resolves it
at build time instead:
use Omnihub\GitHub\Api; use Omnihub\GitHub\Owner; use Omnihub\Source; $api = Api::fromEnvironment('.omnihub/github.json'); // GITHUB_TOKEN when set; the ETags kept in that file $sources = (new Owner($api))->resolve(Source::github('acme', 'unity-*')); $api->save();
- Only public repositories: the owner's list (
/users/{owner}/repos), then, for each name that matches,package.jsonat the root (raw) and the tags. A repository without apackage.jsonnaming a package is skipped. Each one found is agitsource at its newest version tag (a stable one first; none: the default branch), named by itsdisplayName, with the source'sinstall. - Every request carries the last
ETagof its answer (If-None-Match); a304reuses the kept answer. WhenX-RateLimit-Remainingreaches 0, or GitHub answers 403 withRetry-After(a secondary limit) or nothing remaining, or answers 429, nothing more is sent until the reset or the wait (RateLimited): bin/omnihub then leaves the source for the clients. - No page of github.com is read: the REST API only.
On omnisense/contracts' kit
Api and the downloads go through omnihub's HTTP client, on the kit of
omnisense/contracts:
-
sent once: the HTTP client given is kept from retrying (
Http\NoRetry): a 429 reaches theBackoff, a refusal is never replayed; -
a timeout (30 s without a byte for the API, 60 s for a tarball), the User-Agent
omnihub (+https://github.com/glitchr-omnisense/omnihub)andX-GitHub-Api-Version: 2022-11-28; -
GitHub's limits through the kit's
Backoff:X-RateLimit-Resetread as a Unix time,Retry-After, theRateLimitfields; the waits are kept in a limiter -Api's own, or one given (new Api($http, $token, limiter: $shared)) that several processes share; -
the usage policy of policy.json (declared in
composer.json'sextra.omnisense.policy): itsanonymousplan (60 requests an hour) or, with a token, itstokenplan (5,000), checked before each request and counted after it by the kit'sPolicyGuard. A site may tighten it and never loosen it:$policy = Api::policy(true)->tighten(['rateLimits' => [['max' => 1000, 'window' => 'hour', 'operations' => []]]]); $api = new Api(HttpClient::create(), getenv('GITHUB_TOKEN') ?: null, '.omnihub/github.json', policy: $policy);
-
errors without the token: a network failure is an
Omnihub\Exception\UnreachableException, a listing GitHub refuses anOmnihub\Exception\ProviderExceptionnaming the path only.RateLimitedis anOmnihub\Exception\UsageLimitReachedException, so the kit'sUsageLimitReachedtoo (retryAfter), and keeps itsuntil.
Any HTTP client of Symfony's contracts can be given; MockHttpClient in the
tests, which make no network call.
Tests
In omnisense/omnihub's harness, with this checkout beside the core
(OMNIHUB_PLUGINS=../.. in its docker/.env):
cd ../core/docker docker compose run --rm omnihub test # this package's tests among the family's docker compose run --rm omnihub phpstan # PHPStan at level max, an empty baseline docker compose run --rm omnihub bare # a hub built in plain PHP from recorded GitHub answers
MIT.