seamward / laravel-collector
Laravel adapter for the Seamward PHP collector.
Requires
- php: ^8.3
- illuminate/console: ^12.0 || ^13.0
- illuminate/contracts: ^12.0 || ^13.0
- illuminate/http: ^12.0 || ^13.0
- illuminate/queue: ^12.0 || ^13.0
- illuminate/support: ^12.0 || ^13.0
- seamward/php-collector: 0.1.0-alpha.3
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^10.0 || ^11.0
- pestphp/pest: ^4.0 || ^5.0
- pestphp/pest-plugin-laravel: ^4.0 || ^5.0
- phpstan/phpstan: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-07 12:02:10 UTC
README
Laravel 12 and 13 adapter for seamward/php-collector. It provides named connections, explicit request-side or response-side outbound HTTP observation, queue and scheduled-feed wrappers, terminable webhook middleware, lifecycle flushing, and credential-safe diagnostics.
Status: alpha. This package is available under the MIT license.
Install
composer require seamward/php-collector:^0.1@alpha seamward/laravel-collector:^0.1@alpha php artisan vendor:publish --tag=seamward-config
The Laravel package installs the PHP collector as a dependency. During the alpha, both constraints are explicit so Composer permits both prerelease packages without changing the project's global minimum stability.
Once the package is installed and present in composer.lock, the Seamward CLI
and setup MCP can use the same Set up Seamward in this project. prompt as a
Node.js service. The preview supports Laravel 12 and 13 on PHP 8.3 or later,
literal webhook routes, and Http facade calls whose stable route can be
recovered without guessing. It generates named connection config and verifies
PHP plus an approved Composer script. Dynamic targets and other source shapes
return manual_required before any write.
Add one named connection per Seamward Integration boundary in config/seamward.php, then observe an inbound route:
Route::post('/webhooks/candidates', CandidateWebhookController::class) ->middleware('seamward.webhook:candidate_webhook,/webhooks/candidates');
The template is optional. Without one, the middleware uses the matched route's own pattern, including group prefixes and with parameter names kept as a readable label:
Route::post('/webhooks/{provider}/events/{event?}', ProviderWebhookController::class) ->middleware('seamward.webhook:provider_webhook'); // Recorded as /webhooks/:provider/events/:event
Concrete parameter values and bound models are never read. A request that matched no route is not recorded, because its path would carry identifiers.
Or wrap an existing Laravel HTTP call:
$response = app(Seamward\LaravelCollector\SeamwardManager::class)->observeHttp( connection: 'candidate_api', method: 'POST', routeTemplate: '/v1/candidates', callback: fn () => Http::post($providerUrl, $data), );
Choose request-side structural evidence when the provider response is not the contract you need to monitor:
$response = $manager->observeHttp( connection: 'candidate_api', method: 'POST', routeTemplate: '/v1/candidates', callback: fn () => Http::post($providerUrl, $data), payloadLocation: 'request', requestPayload: $data, );
Calls made through a provider SDK or any other client use observeCall. The operation is the same reusable definition the core collector takes, so the method, template, and extractors live in one place in your own code:
use Seamward\Collector\Observation\CallOperation; // Your code: defined once, for example on a service class. $retrievePaymentIntent = CallOperation::http( method: 'GET', routeTemplate: '/v1/payment_intents/{paymentIntentId}', businessObjectType: 'payment_intent', ); // Each call site: a controller, service, job, or command. $intent = $manager->observeCall( 'payments', $retrievePaymentIntent, fn () => $stripe->paymentIntents->retrieve($id), reference: $id, );
observeCall returns the callback's own result and rethrows its own exception. A failed Laravel HTTP client connection is recorded as no response, and a thrown RequestException is recorded with its HTTP status. See the core collector README for extractors and how an unreadable status is recorded.
The manager also exposes observeQueuePublish(), observeQueueConsumer(), and observeScheduledFeed() for explicit broker and scheduler boundaries. These wrappers do not acknowledge jobs, retry messages, or change scheduler behavior.
Deployment context is configured per named connection under deployment. The published config reads the supported Seamward and deployment-platform variables while configuration is loaded, so Laravel configuration caching remains safe.
Collector failures are fail-open. The original application response or exception remains authoritative.
Diagnostics
php artisan seamward:doctor
The command reports whether each named connection is configured and never prints credential values. It also warns when a connection sets value_profile to full without a hash_key.
Value profiles
By default each connection describes field values without sending them: a format label, power-of-ten bands, and length bands. Configure it per connection in config/seamward.php:
'value_profile' => env('SEAMWARD_VALUE_PROFILE', 'structural'), // off, structural, full 'value_profile_exclude_fields' => ['tier'], 'drop_fields' => ['ssn'], 'hash_fields' => ['email'], 'hash_key' => env('SEAMWARD_HASH_KEY'),
Fields named in drop_fields or hash_fields are never described. full adds keyed hashes of short free-form values and needs your own hash_key; without one the connection keeps observing at structural, and no value is hashed with a key Seamward could work out.
Deprecation notices
observeCall reads a provider's Deprecation, Sunset and API version
headers from a Laravel HTTP client response, and from the response on a thrown
RequestException. Seamward turns them into a dated advisory. No header is
sent. Nothing needs configuring.
Rate limits and signature results
observeCall reads a provider's rate-limit headers from a Laravel HTTP client
response. The seamward.webhook middleware reports the result of your own
signature check when your route sets the ObserveWebhook::SIGNATURE_VALID
request attribute to a bool. No header, signature or secret is sent.
Account reference
observeCall accepts accountRef: and record() accepts 'accountRef' in an
outcome. The identifier is hashed in your process and only the hash is sent.
Development
composer install
composer test
composer analyse
composer format -- --test
One ingest token for every Integration
Your application does not need a Connection key and token for each Integration. A workspace has one ingest token per mode. In Seamward, switch to the mode you are setting up, open Settings, then Ingest token, and select Issue token:
SEAMWARD_INGEST_TOKEN=sw_svc_v1.replace_with_ingest_token
// config/seamward.php 'ingest_token' => env('SEAMWARD_INGEST_TOKEN'), 'connections' => [ 'paystack_webhook' => 'paystack-webhook', 'crawler_api' => ['service_connection' => 'crawler-api', 'max_batch_size' => 10], ],
A connection can be just the Integration's connection name, shown on its
Collector setup tab in Seamward, or an
array with service_connection and any other settings. The token decides the
mode, so the same names work in Test and Live. A connection that defines
connection_key and ingest_token keeps using its own credentials.
php artisan seamward:doctor reports such a connection as
configured (service token, <name>) and never prints the token.
Monthly observation allowances
Quota-aware monthly pausing is an unreleased candidate. The current published
versions listed below discard each rejected batch and continue sending later
evidence. After the announced grace period, only Sandbox admission is limited
to 10,000 accepted observations per account per UTC month.
Live usage is informational and is not rejected. In the candidate, 403 observation_monthly_quota_exhausted rejects the
entire batch without persistence. The collector discards that batch and pending
telemetry, counts them in rejected and its quotaRejected subset, then rejects
new telemetry locally until the validated UTC reset. Application requests keep
running. quotaResetAtSeconds is the reset as Unix seconds, or 0 when inactive.
New observations resume after reset; discarded telemetry is not recovered.
Minute throttling remains 429, with bounded retry and no monthly pause.
Malformed or unrelated 403 responses do not install a quota pause. Previously released Node 0.1.0-alpha.28 and PHP/Laravel v0.1.0-alpha.1
collectors discard each rejected batch and keep sending later evidence without
waiting for monthly reset. Upgrade to the quota-aware release before quota
enforcement begins. Account administrators can inspect the separate allowances
at https://seamward.com/api/workspace#read-account-mode-usage.