Search by

seamward / laravel-collector

a4anthony

Laravel adapter for the Seamward PHP collector.

Package info

github.com/seamward/laravel-collector

Homepage

pkg:composer/seamward/laravel-collector

Statistics

Installs: 110

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0-alpha.3 2026-10-07 11:06 UTC

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.