Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Package Doctor Laravel Package

satheez/laravel-package-doctor

Laravel Package Doctor provides diagnostic checks for Laravel packages, helping you spot common setup, structure, and configuration issues before they become problems. Use it to keep package integrations clean, consistent, and easier to maintain.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer, publish its config, and add a GitHub token to .env:

composer require <vendor>/<package>
php artisan vendor:publish --tag=github-config
GITHUB_TOKEN=ghp_...
GITHUB_BASE_URL=https://api.github.com

Look first at:

  • config/github.php — token, base URL, timeout, and any default options.
  • The package service provider and facade — confirms how the client is bound into the container.
  • The exception classes — these are what you will catch in application code.
  • The README’s authentication section — PAT vs GitHub App installation tokens behave differently.

The quickest first use case is an Artisan command or controller that fetches the authenticated user and lists issues for a repository:

use <Vendor>\<Package>\Facades\GitHub;

$user = GitHub::user()->me();
$issues = GitHub::issues()->all('laravel', 'framework', [
    'state' => 'open',
    'per_page' => 30,
]);

Resolve the client from the container rather than constructing it directly. That keeps configuration, token handling, and test fakes consistent across commands, jobs, and controllers.

Implementation Patterns

Wrap the client in domain services. Rather than scattering facade calls through controllers, create small services such as GitHubIssueService, GitHubReleaseService, or RepositorySyncService. Inject the package client into those services. This gives you one place to add caching, retries, logging, and DTO mapping.

Use the facade for scripts, injection for application code. A facade is convenient in one-off Artisan commands and tinker sessions. For anything tested or reused, constructor-inject the underlying client or a wrapper service so you can substitute a fake.

Queue rate-limit-sensitive work. Bulk operations — syncing all issues, backfilling releases, enumerating organisation repositories — should run in queued jobs. GitHub rate limits are per-token, and a long synchronous request loop in a web request will eventually hit them. Split work into pages and dispatch follow-up jobs.

Paginate deliberately. Use per_page and iterate pages explicitly, or follow the Link header. Do not assume a single response contains everything. For large repositories, combine pagination with since parameters where the endpoint supports them to avoid refetching unchanged data.

Handle errors by category, not by string matching. Catch the package’s GitHub exception types and branch on status:

  • 404 — resource missing or token lacks visibility.
  • 422 — validation failure; GitHub returns a structured errors array.
  • 403 — could be insufficient permissions or rate limiting; inspect X-RateLimit-Remaining and Retry-After.
  • 5xx — retry with exponential backoff.
try {
    $issue = GitHub::issues()->create($owner, $repo, $payload);
} catch (GitHubValidationException $e) {
    // Surface $e->errors() to the form
} catch (GitHubRateLimitException $e) {
    $this->release($e->retryAfter());
}

Cache GET responses and use conditional requests. Repository metadata, labels, and user profiles change infrequently. Cache them, and where possible store the ETag and send If-None-Match so GitHub returns 304 without consuming your rate limit.

Model authentication per tenant. If you support multiple GitHub accounts or GitHub App installations, resolve the correct token per request and bind a scoped client instance. Do not mutate a shared singleton token in a multi-tenant application.

Test with a fake client, not the network. Bind a fake implementation of the client interface in the container, or use Guzzle’s MockHandler if you are testing the HTTP layer directly. Avoid real API calls in the test suite; they are slow, flaky, and rate-limited.

Verify webhooks at the edge. If you receive GitHub webhooks, verify the X-Hub-Signature-256 header before parsing the payload, then dispatch a queued job for the actual work. Keep the webhook controller thin.

Gotchas and Tips

Guzzle version constraints matter more than they look. v0.2.0 supports guzzlehttp/guzzle ^7.8|^8.0. Laravel 11 and 12 continue to use Guzzle 7, so most applications will stay on Guzzle 7 and see no behavioural change. Guzzle 8 is exercised in CI only on PHP 8.4/8.5 with Laravel 13. If you are on Laravel 11 or 12, explicitly requiring Guzzle 8 can conflict with framework constraints — let the framework resolve Guzzle unless you have a specific reason to upgrade.

Upgrade to v0.2.0 if you use Guzzle 8. The release fixes GitHub API error handling across both Guzzle majors. On older versions, exception wrapping and status-code extraction could differ depending on which Guzzle major was installed. If you pinned 0.1.x and later moved to Guzzle 8, upgrade the package rather than debugging mismatched exception behaviour.

Watch the PHP/Laravel edge. The Guzzle 8 CI path targets PHP 8.4/8.5 and Laravel 13. That is a forward-looking combination; production applications on PHP 8.2/8.3 with Laravel 11/12 should stay on the Guzzle 7 path. Treat the Guzzle 8 support as available but not the default for current Laravel applications.

Rate limiting is the most common production failure. Authenticated requests get roughly 5,000 per hour; unauthenticated requests get 60. Secondary rate limits can trigger even below the primary limit during bursts. Read X-RateLimit-Remaining, honour Retry-After, and add jitter to retries. Do not retry 403 responses blindly — first determine whether the cause is rate limiting or permissions.

Do not log tokens or full request headers. GitHub tokens in logs are a credential leak. Redact Authorization headers in any Guzzle middleware or exception logger. Store tokens in .env and reference them from config/github.php so config:cache works correctly.

403 is ambiguous. It can mean “rate limited”, “token lacks scope”, or “resource not accessible”. Check response headers and the error body before deciding whether to retry, refresh credentials, or fail permanently. Fine-grained PATs in particular fail with 403 where classic PATs would succeed.

Pagination headers are easy to mishandle. The Link header contains rel="next", rel="last", and sometimes rel="prev". Parse it rather than incrementing page numbers until an empty response — the latter works but wastes requests and can break on endpoints with sparse pages.

Set timeouts and connection limits. The default HTTP timeout may be too generous for web requests. Configure a connect timeout and total timeout in config/github.php, and use shorter timeouts for interactive requests than for queued jobs.

GitHub Enterprise needs the base URL. If you point at GitHub Enterprise Server, set GITHUB_BASE_URL and confirm the package uses it consistently for both API calls and any generated links. Do not hardcode api.github.com in services.

Beware long-lived singleton clients under Octane. If you bind a client as a singleton and mutate its token or configuration per request, state can leak between requests. Prefer resolving a scoped client per request or per job.

Config caching catches env mistakes. Once php artisan config:cache runs, env() calls outside config files return null. Keep all GitHub environment reads inside config/github.php.

Use the extension points before forking. The package’s client binding and HTTP middleware are the right places to add retries, logging, and metrics. If you need custom behaviour, decorate the injected client rather than editing vendor code.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console