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

Tabstack Laravel Package

juststeveking/tabstack

TabStack is a lightweight Laravel package from Steve King for defining and managing stacked tabs with a clean, fluent API. It keeps tab state and Blade markup organized so you can add tabbed interfaces without extra frontend complexity.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require juststeveking/tabstack
php artisan vendor:publish --tag="tabstack-config"

Add the credential to .env (TABSTACK_API_KEY=...) and confirm config/tabstack.php picks it up via env(). Run php artisan config:clear before your first call if you have cached config from a previous deploy.

Where to look first, in order:

  1. README.md — the happy-path example is the fastest way to see the intended entry point (facade vs. injected client).
  2. config/tabstack.php — this is the real API surface you'll be tuning: base URL, key, timeout, retry count, middleware.
  3. src/TabstackServiceProvider.php — shows what's bound into the container and whether the client is a singleton or a fresh instance per resolution. That determines how you handle multi-tenant credentials.
  4. src/ for the request/connector classes and src/Data/ (or equivalent) for response DTOs — the DTOs are what you'll actually be mapping into your domain.
  5. tests/ — the package's own tests are the best documentation of edge-case behaviour and the expected exception types.

First use case: one read call, end to end, in a tinker session or a throwaway artisan command. Resolve the client, make a single request, and dd() the returned object. Confirm you get a typed DTO rather than a raw array or Response — that single observation tells you most of what you need to know about how to integrate.

Implementation Patterns

Resolve through the container, not the facade, in anything you plan to test. app(Tabstack::class) or constructor injection keeps the class swappable and makes it trivial to bind a fake in a test. Reserve the facade for tinker, one-off commands, and Blade-adjacent glue.

Wrap the package in a thin application-level adapter. One class of your own (e.g. App\Services\TabstackGateway) that owns every call into the SDK. You get: a single place to add logging and metrics, a single place to convert package exceptions into your domain exceptions, and a seam for swapping the vendor later. This costs twenty minutes on day one and saves a refactor on every upgrade.

Hydrate DTOs into your own models at the boundary. Don't let package DTOs leak into controllers, resources, or — worst of all — Eloquent casts. Map to your own value objects or models as soon as the response lands. Package DTO constructors can change shape in minor releases; your domain objects shouldn't.

For per-tenant or per-user credentials, don't mutate the singleton. Either configure a fresh client instance with an explicit credential, or use a context/withToken()-style method if the package provides one. Check the service provider binding first — if it's registered as a singleton and you config()->set() a key at runtime, you may be sharing the wrong credential across a queue worker that processes multiple tenants. That bug is silent and ugly.

Push heavy or unreliable calls into queued jobs. $tries, backoff(), and retryUntil() on the job are more legible than the package's internal retry config, and they survive the process dying. Keep the package's retry count low (or zero) when you do this, so you're not multiplying retries: 3 package retries × 3 job tries = 9 requests.

Rate-limit at the job layer with RateLimited / Illuminate\Queue\Middleware\RateLimited or a Redis::throttle(). The SDK's own throttling, if any, is per-process and won't coordinate across workers.

Testing. Fake the transport, not your adapter. If the package wraps Laravel's HTTP client, Http::fake([...]) with Http::assertSent() covers you. If it's Saloon-based, use the package's mock client and assertSent. Then have a small number of tests for your adapter that assert the domain-level behaviour (retries, exception mapping), so an SDK internals change doesn't break forty tests.

Cache aggressively for read calls. Cache::remember() around your adapter method, keyed on the request parameters, is usually the single highest-value line of code in the integration — most SDK-backed features re-fetch the same resource.

Gotchas and Tips

v1.0.0 is the compatibility promise, and "hardening" is where the sharp edges live. A release billed as SDK hardening typically means: stricter type declarations, readonly/final on DTOs, tightened constructor signatures, narrowed return types, and changed or newly-thrown exception classes. None of that is a semver break after 1.0.0 — but it absolutely can break code written against a 0.x tag. If you're upgrading from pre-1.0, treat it as a breaking change: read the PR diff in full, then run your own test suite before composer update reaches production. Pin "juststeveking/tabstack": "^1.0".

Verify the timeout and retry defaults explicitly. SDK hardening often changes defaults from "whatever the HTTP client does" to something opinionated. A default timeout that's shorter than the upstream API's p95 latency produces intermittent failures that look like flakiness in your app. Set timeout and connect_timeout in config/tabstack.php from the vendor's published latency numbers, not from the package default. Same for retries — and confirm retries are disabled or idempotency-keyed for non-GET requests.

config:cache bites you twice. First, env() calls outside config/ return null once config is cached — make sure the key only ever comes from the config file. Second, if you're overriding the key at runtime for multi-tenancy, the cached config path can mask it. Test your deploy path, not just php artisan serve.

Exception granularity is the main thing to audit in this release. Enumerate the exception classes the package throws and map each to a behaviour: retry, surface to the user, or fail loudly. A common failure mode is catching a broad \Throwable around SDK calls, which swallows 401s (misconfigured key — should page someone) alongside 429s (retry — should not). Check whether the hardened release introduced a base exception interface you can catch narrowly.

Idempotency and pagination. If any calls create resources, check whether the SDK supports an idempotency key and use it — otherwise job retries create duplicates. For list endpoints, follow the package's paginator rather than hand-rolling page increments; hardened SDKs frequently add a ->lazy()/iterator that handles the cursor correctly and avoids the off-by-one on the final page.

Debugging a request you can't see: register a global middleware or HTTP client event listener (Http::globalRequestMiddleware, or Http::beforeSending) to log method, URL, and status — with the auth header redacted. Illuminate\Support\Facades\Http::globalMiddleware() is a one-liner in a service provider and beats adding dd() inside vendor/. Never edit files under vendor/ to debug; you'll forget, and the next composer install silently reverts your fix.

Extension points worth knowing before you fork anything: the container binding for the client (rebind it to add a custom transport or a Guzzle handler stack), the config file's middleware array if present, and the service provider's publish tags. Between those three you can usually solve auth refresh, request signing, custom headers, and proxy configuration without touching package code. If you genuinely need a change in src/, open the PR upstream — a single-maintainer SDK benefits from it, and you avoid a permanent merge-conflict tax.

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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
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
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core