ske-io/laravel-bridge
ske-io/laravel-bridge is a Laravel integration package that connects an external service or SDK to your application, providing service provider registration, configuration publishing, and a thin adapter layer for calling it from Laravel code.
composer require ske-io/laravel-bridge — needs PHP 8.3+ and Laravel 11, 12 or 13. The service provider is auto-discovered; there is nothing to register in bootstrap/providers.php.composer.json to SKE without a conditional-provider dance.https://ske.io/docs/laravel, then config/ske.php (uploads wiring is the only thing the release notes explicitly place there), then the env vars the bridge reads: SKE_UPLOADS_URL, MAINTENANCE_MODE_SECRET, LARAVEL_ENV_ENCRYPTION_KEY.X-Request-Id. That single check proves the provider booted, the log formatter is installed, and the request pipeline is intact.$request->getScheme(), getHost() and ip() on a real request. If those are correct, the proxy trust is wired and your signed URLs and redirects will be too.Queues. Configure ske as a connection and dispatch to it per-queue rather than flipping your whole default if you have mixed workloads. The connection targets SQS on AWS and Cloud Tasks on GCP, but in both cases delivery is at-least-once and the platform runs Laravel's own worker — so do not add a supervisor, queue:work daemon, or Horizon-side process; you'd be competing with the platform's worker. Treat every job as idempotent, and set $timeout deliberately: the queue's timeout is enforced by the platform, and a killed long job becomes a retried long job.
Failed jobs. You get two different operating models and should pick one on purpose:
failed_jobs table: failures run through your exception handler and are recorded locally, so queue:failed / retry tooling works as usual.Logs. Everything goes to stderr as JSON lines. Use structured context (Log::info('paid', ['invoice' => $id])) rather than string interpolation so records stay queryable, and make sure your own middleware doesn't strip or regenerate X-Request-Id — that header is the join key across services. Propagate it into your own outbound calls if you want the same correlation downstream.
Proxies. Stop hand-maintaining TrustProxies with *. The bridge trusts the platform load balancer, which is why scheme/host/client IP are real. Any custom proxy middleware you keep can silently re-break signed URL generation and secure_url().
AWS credentials. Leave AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY unset on SKE so the SDK uses the function role's temporary credentials including the session token; an app-set key pair wins, which is what you want locally but not in production.
Mail. SES sends from the region of the mail provider linked to the environment. Keep the region in the SKE mail provider config, not in MAIL_* env vars, or you'll diverge per environment without noticing.
Maintenance mode. The dashboard is the switch; MAINTENANCE_MODE_SECRET behaves like php artisan down --secret, so ?secret=… bypasses. Pattern: put the secret in your secret manager, verify the bypass path in staging, and never assume artisan down is your lever.
Direct uploads. Define the uploadFiles gate first — that's the authorization surface. Return the signed PUT URL to the browser and let it upload straight to the bucket, which means server-side validation must happen at signing time and in bucket policy (size, content type, key prefix), not in a controller the bytes never touch. Verify CORS allows PUT from your app origin, and track URL expiry against client clock skew. Configure the endpoint through exactly one of config/ske.php or SKE_UPLOADS_URL.
Encrypted env. Commit .env.{environment}.encrypted per environment, keep LARAVEL_ENV_ENCRYPTION_KEY in the platform secret store, and treat the file as a migration target: it will not override platform or secret values, so remove duplicated dashboard vars when you move them into the file.
Inertia SSR. With SSR enabled, render calls hit the platform SSR server under a time limit and fall back to client-side rendering with a log entry. Keep SSR components cheap — no network calls or heavy data work inside render — because a timeout degrades silently rather than failing loudly. Exercise the fallback by killing the SSR server in staging and confirming you see the log.
php artisan config:cache in a CI/build step where LARAVEL_ENV_ENCRYPTION_KEY isn't present, you bake empty values into a cached config and ship it. Cache at container start, after decryption — or not at all.LARAVEL_ENV_ENCRYPTION_KEY missing, the encrypted file is simply ignored and the app boots on defaults. Add a boot-time assertion that the expected keys exist.bootstrap/cache/packages.php, the provider won't load and everything above quietly does nothing. php artisan package:discover after upgrading.var_dump, a library writing plain text to stderr, or a file-based log channel all corrupt parsing or vanish. Audit channels in production config, and keep context payloads small.queue:work --timeout and the platform's enforced queue timeout may not match; tune against observed behaviour and keep jobs idempotent so retries are safe.uploadFiles must actually exist; a missing or misnamed ability denies uploads (or throws) and looks like a credentials problem. Also enforce limits at signing time — the browser bypasses your app for the body.--secret, it travels in query strings, so it lands in access logs and Referer headers. Treat it as a credential and rotate it.inertiajs/inertia-laravel is optional — so an Inertia 1 app gets no SSR help; check your constraint. Same on the framework side: if composer resolution fails, composer why-not ske-io/laravel-bridge will point at the blocking patch version.uploadFiles gate, your exception handler, log channels/formatters, and config/ske.php. If you need a different queue backend or transport, use a separate connection per queue rather than fighting the bridge.How can I help you explore Laravel packages today?