Laravel collector
seamward/laravel-collector adds Laravel package discovery, named connections, webhook middleware, explicit HTTP, queue, and scheduled-feed observation, lifecycle flushing, and safe diagnostics on top of the framework-neutral PHP core.
Status
The Laravel collector is in alpha and is available from Packagist as 0.1.0-alpha.1. The one-prompt setup supports Laravel 12 and 13 on PHP 8.3 or later. During the reviewed local apply, Seamward installs the exact supported PHP and Laravel collector pair. Unsupported versions and unsafe source shapes stop before any project write.
Install
Install both alpha packages explicitly, then publish the Laravel configuration:
Code example
composer require seamward/php-collector:^0.1@alpha seamward/laravel-collector:^0.1@alphaphp artisan vendor:publish --tag=seamward-configBoth constraints are explicit so Composer accepts the prerelease dependency without changing the project's global minimum stability. Laravel discovers SeamwardServiceProvider automatically. The adapter supports Laravel 12 and 13 on PHP 8.3 or later.
Automatic setup preview
Run seamward setup, restart the coding agent, and ask:
Code example
Set up Seamward in this project.The CLI still runs on Node.js 22 or later. It detects Composer and Laravel internally, installs the exact supported collector versions from Packagist during the approved apply, generates credential-free named connection files under config/, wraps supported Http facade calls, adds seamward.webhook middleware to literal webhook routes, runs PHP syntax checks and an approved Composer verification script, and rolls back the complete change if verification fails. It never reads or edits .env.
Automatic rewriting is intentionally narrow. The request target must be a recoverable string route, and webhook routes must use a literal route template. Dynamic URL variables, custom request objects, queues, scheduled feeds, and other PHP frameworks return manual_required; use the explicit examples below for those boundaries.
Configure
Define one named connection per Seamward Integration boundary in config/seamward.php:
Code example
'connections' => [ 'candidate_webhook' => [ 'connection_key' => env('SEAMWARD_CANDIDATE_CONNECTION_KEY'), 'ingest_token' => env('SEAMWARD_CANDIDATE_INGEST_TOKEN'), 'endpoint' => env('SEAMWARD_INGEST_URL', 'https://api.seamward.com/ingest'), 'redaction_policy_version' => 'shape-only-v1', 'deployment' => [ 'service' => env('SEAMWARD_SERVICE'), 'release' => env('SEAMWARD_RELEASE'), 'commitSha' => env('SEAMWARD_COMMIT_SHA'), ], ],],Keep ingest tokens in protected runtime configuration. Never put them in source, browser code, logs, or support messages.
The default connection uses SEAMWARD_CONNECTION_KEY, SEAMWARD_INGEST_TOKEN,
and the optional SEAMWARD_INGEST_URL. Named connections can use names chosen
by the application, as shown above.
Observe an inbound webhook
Attach the terminable middleware to the route and pass the named connection plus a stable route template:
Code example
use Seamward\LaravelCollector\Middleware\ObserveWebhook;
Route::post('/webhooks/candidates', CandidateWebhookController::class) ->middleware(ObserveWebhook::class.':candidate_webhook,/webhooks/candidates');The middleware returns the original response and rethrows application exceptions unchanged. Its terminate phase flushes the observation outside the controller's business logic.
Observe outbound HTTP
Wrap only the provider call. The returned Laravel HTTP response and original exceptions remain authoritative:
Code example
use Illuminate\Support\Facades\Http;use Seamward\LaravelCollector\SeamwardManager;
$response = app(SeamwardManager::class)->observeHttp( connection: 'candidate_api', method: 'POST', routeTemplate: '/v1/candidates', callback: fn () => Http::post($providerUrl, $requestData),);Response values are inspected locally for their JSON structure. Request and response headers are never added to the observation envelope.
To observe the request contract instead, append payloadLocation and the local request value. Existing positional and named calls remain compatible:
Code example
$response = app(SeamwardManager::class)->observeHttp( connection: 'candidate_api', method: 'POST', routeTemplate: '/v1/candidates', callback: fn () => Http::post($providerUrl, $requestData), payloadLocation: 'request', requestPayload: $requestData,);requestPayload never enters the envelope. Only its structural shape and fingerprint are buffered. If the provider call throws, the envelope records status 0 and an unaccepted outcome, then the original exception is rethrown unchanged.
Observe a queue
Use explicit wrappers around the broker operation. The package does not infer an Integration from arbitrary Laravel jobs:
Code example
$published = $manager->observeQueuePublish( connection: 'candidate_events', queueName: 'candidate-events', message: $message, publisher: fn ($message) => $broker->publish('candidate-events', $message),);
$handled = $manager->observeQueueConsumer( connection: 'candidate_events', queueName: 'candidate-events', message: $message, consumer: fn ($message) => $handler->handle($message),);The wrappers record queue evidence but do not acknowledge, retry, release, or dead-letter the job. Laravel queue completion and failure events remain flush boundaries only.
Observe a scheduled feed
Wrap one scheduled import or export callback:
Code example
$result = $manager->observeScheduledFeed( connection: 'candidate_import', feedName: 'nightly-candidate-import', direction: 'inbound', payload: $rows, handler: fn ($rows) => $importer->import($rows),);Use a stable feed or job label, never a run id or timestamp. The wrapper does not schedule, retry, or otherwise control the job.
Lifecycle and diagnostics
The package flushes resolved collectors after terminable webhook middleware, completed console commands, processed or failed queue jobs, and application termination. Long-running workers and custom loops should call SeamwardManager::flush() at their own safe boundary. There is no background timer or destructor network call.
Check configuration presence without printing credentials:
Code example
php artisan seamward:doctor