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

Wireless Laravel Package

robert-stanciu/wireless

Wireless is a lightweight Laravel package that helps you wire up common application features with a simple, expressive API. It favors sensible defaults, minimal configuration, and clean, maintainable PHP code, making it easy to drop into new or existing Laravel projects.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require robert-stanciu/wireless:^3.0

That is the whole setup. Wireless is a pure-PHP driver — no service provider config, no migrations, no published assets, no front-end build. It targets PHP 8.2+, Laravel 12, Livewire ^3.6 specifically. If you are on Livewire 2 or on Livewire 4, stop here: v3 deliberately invokes mount/call with the Livewire 3 signature, and there is no compatibility shim.

Where to look first

There is effectively no narrative documentation beyond the pitch line and the release notes, so read in this order:

  1. src/ — find the facade/entry point (the thing you call ::mount() on) and the driver class. The driver's public methods are the API surface.
  2. tests/ — 124 tests in random order are the de facto manual. They are also the only place that documents teardown semantics, the redirector stack, and auth restoration.
  3. The v3.0.0 release notes — this is the migration guide if you are coming from v1.x/v2.x, and it names the exact behaviors that were fixed (all of which are things you can trip over).

Your first use case

The canonical one: exercising a Livewire component's behavior from a test or a console command without going through Livewire::test()/HTTP.

use RobertStanciu\Wireless\Facades\Wireless; // verify namespace in src/

$driver = Wireless::mount(Counter::class, ['start' => 5]);

$driver->set('start', 10);
$driver->call('increment');

$driver->returned();   // value returned by the last call()
$driver->dispatched(); // events the component dispatched
$driver->redirect();   // redirect the component requested

Sanity-check two things on day one before you build on it:

  • Does mount() run your mount() hook and call() run updated hooks? It should — validation failures raised inside an updated hook are explicitly carried to the next call — but confirm with a throwaway test.
  • What is returned() before any call()? In v3 it throws on a never-mounted driver, so guard rather than assume null.

If what you actually want to assert is rendered HTML, Wireless is the wrong tool: effects are only written during Livewire's dehydrate, and a Wireless cycle never dehydrates. Use Livewire::test() for markup, Wireless for state, calls, returns, redirects, and dispatches.

Implementation Patterns

Arrange / act / assert in tests. Treat the driver as a handle on a live component instance, not a client. Mount once, drive it through a sequence, assert on the returned values and side effects.

public function test_checkout_redirects_on_success(): void
{
    $driver = Wireless::mount(Checkout::class, ['cart' => $this->cart]);

    $driver->set('coupon', 'SAVE10');
    $driver->call('submit');

    $this->assertSame(route('orders.thanks'), $driver->redirect());
    $this->assertDatabaseHas('orders', ['coupon' => 'SAVE10']);
}

One mount, many calls. The cycle keeps component state between set() and call(), so model realistic user flows — set a property, call, assert, set another, call again — instead of remounting per assertion. Remounting is slower and hides order-dependent bugs.

Wrap it for commands and jobs. Calling a component from an artisan command, a queued job, or a scheduled task is the genuinely interesting non-test use: the component's logic becomes addressable from PHP.

$driver = Wireless::mount(SyncInvoices::class);

try {
    $driver->call('run', $account->id);
} finally {
    // explicit teardown in long-lived processes; don't rely on GC
}

Prefer explicit teardown in anything longer-lived than a request or a single test — queue workers and Octane especially. The component sits on Livewire's own stack; the package's test suite enforces a global guard that no component, redirector frame, or container redirector is left behind, and you want the same discipline in your code.

Isolate auth deliberately. The driver snapshots the previous user per guard and restores it at teardown, and v3 fixed the case where two drivers on one guard trampled each other. Authenticate before mounting, and do not assume a second driver mounted inside the first shares your expectation about who the current user is mid-cycle. Assert auth-dependent branches explicitly rather than relying on ambient state.

Assert dispatched events via the driver, DB via Laravel. Two different channels:

$driver->call('save');
$this->assertContains('invoice-saved', $driver->dispatched());

Event::fake([InvoiceSaved::class]);
$driver->call('save');
Event::assertDispatched(InvoiceSaved::class);

Testing validation is a first-class pattern here. Because an updated hook's ValidationException is carried to the next call, mount → set() (fails in updated) → call() will throw on the call rather than silently wiping the failure. Catch ValidationException around the call and assert the message bag. Do not assume set() throws at the exact point of failure.

Adapter, not a leak. Keep any production-ish wireless usage behind a small interface (InvoiceSyncer, OnboardingRunner) so domain code doesn't import the driver. It keeps you swappable if the package stalls, and it stops Wireless types from spreading through your codebase.

Gotchas and Tips

effects() no longer exists. It returned [] for every real cycle because effects are only populated during dehydrate. Use redirect(), dispatched(), returned(). Any tutorial or old code reaching for effects() is dead.

returned() throws on an unmounted driver. Guard it or you'll get a confusing exception when a component's mount() bails early.

Do not drive a component from inside a Livewire request. The driver mutates shared container state — the Redirector in particular. If a surrounding Livewire component already owns a redirector and you open a cycle inside its lifecycle, you are relying on the identity-based frame bookkeeping introduced in v3, not on something structurally safe. Keep Wireless out of Livewire actions, Livewire render paths, and middleware that runs during a Livewire update.

flush-state and overlapping cycles are the sharp edge. v3 fixed a flush-state while a cycle was open dropping the redirector snapshot (leaving the container pointing at a destroyed component for the process lifetime), and fixed teardown handing back a redirector while another component owned one. Those fixes make overlapping cycles survivable, not advisable. Serialize your drivers. In tests, one driver per test method.

Livewire::flushState() no longer runs from a destructor — the package asks "is Livewire busy?" again at teardown instead. Practically: teardown timing is nondeterministic if you rely on garbage collection, and a driver that outlives a Livewire::flushState() will re-check at finish. In queues and Octane, finish explicitly.

No Macroable/Tappable on the driver in v3. You cannot Wireless::macro(...). Extend by wrapping, not by monkey-patching. If you were doing this on v1/v2, it is a silent break.

Version pinning is genuinely important. Livewire ^3.6 only, and the package runs a canary against livewire:3.x-dev — meaning minor Livewire releases can move under it. Pin Livewire in composer.json if Wireless is load-bearing, and don't let a composer update slide Livewire to 4. v1.x/v2.x remain published for older stacks; the v3 renumber tracks Livewire's major, so old pins don't shift.

Debugging a leaking cycle. Assert cleanliness the way the package's own suite does: after the test, confirm nothing is left on Livewire's component stack and the container holds the application's original Redirector. If a later test starts behaving oddly, a leaked driver from an earlier test is a prime suspect.

Uploads and request-shaped inputs are the unproven area. There is no request and no dehydrate, so UploadedFile/TemporaryUploadedFile handling, wire:model deferred semantics, and anything reading the request are places to verify rather than assume. If a component's behavior depends on the request, this isn't the harness for it.

Adoption risk is the real headline. Zero stars, zero dependents, one maintainer, no narrative docs. That doesn't make it bad — the test suite and PHPStan level 6 suggest real engineering — but it does mean you are the documentation. Budget time to read src/ and tests/ before committing, keep it behind an adapter, and be prepared to fork. For a test-only dependency that's a cheap bet; for anything in a production path, weigh it accordingly.

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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment