Skip to content

v0.6.0

Choose a tag to compare

@SanderMuller SanderMuller released this 10 May 14:55
· 15 commits to main since this release
Immutable release. Only release title and notes can be modified.
936f298

What's new

  • X402\Facilitator\DispatchingFacilitator — wraps any FacilitatorClient and surfaces a PaymentOutcome to a single onOutcome closure on every non-trivial outcome (VerifyRejected, VerifyError, SettleSucceeded, SettleFailed, SettleError):

    use X402\Facilitator\DispatchingFacilitator;
    use X402\Facilitator\PaymentOutcome;
    use X402\Facilitator\PaymentOutcomeKind;
    
    $facilitator = new DispatchingFacilitator(
        inner: CoinbaseFacilitator::default($psr18Client, $psr17),
        onOutcome: function (PaymentOutcome $outcome, array $context) use ($events): void {
            match ($outcome->kind) {
                PaymentOutcomeKind::SettleSucceeded => $events->dispatch(new PaymentSettled(...)),
                default                              => $events->dispatch(new PaymentRejected(...)),
            };
        },
        captureContext: fn (): array => ['user_id' => currentUser()?->id, 'ip' => clientIp()],
        resourceFormatter: fn (string $url): string => $registry->formatResource($url),
    );

    Three optional ctor closures: onOutcome (the listener), captureContext (no-arg, returns adopter-supplied context — request user id, IP, trace id — once per outcome), resourceFormatter (maps challenge->resource ?? '' to the canonical resource string surfaced on PaymentOutcome::$resource).

    Listener / context-capture / formatter exceptions on *-error paths are silently swallowed so the original facilitator throwable always propagates to the caller. Hook bugs on the slow path can't mask a transport / network failure that operations need to triage.

  • X402\Facilitator\PaymentOutcome — snapshot DTO surfaced to the onOutcome closure. Carries kind, signature, challenge, resource, reason, verify, settle, exception. Per-kind population documented on the class — adopters branch on $outcome->kind and consume the relevant result field.

  • X402\Facilitator\PaymentOutcomeKind — string-backed enum (verify-rejected / verify-error / settle-succeeded / settle-failed / settle-error). Constants REASON_PREFIX_VERIFY_ERROR / REASON_PREFIX_SETTLE_ERROR for the prefixed reason format. New cases may be added in any minor version (e.g. async-settlement support down the road), so adopters writing match ($outcome->kind) { ... } SHOULD include a default arm.

  • X402\PaymentHistory\PaymentRowBuilder::fromOutcome() — static helper that turns a PaymentOutcome into a flat array row matching the laravel-x402 x402_payments migration shape:

    use X402\PaymentHistory\PaymentRowBuilder;
    
    $row = PaymentRowBuilder::fromOutcome($outcome, $context);
    // ['status' => 'settled', 'resource' => '...', 'payer' => '0x...', 'amount' => '10000', ...]
    
    Payment::query()->updateOrCreate(['transaction' => $row['transaction']], $row);

    Constants: STATUS_SETTLED, STATUS_REJECTED, DEFAULT_REASON_MAX_LENGTH = 255. Reason truncation defaults to 255 chars (matches the migration column width) — without it, a long *-error reason exceeds the column and the audit-row write fails after the payment path already failed once. Pass replayKey: $extracted from the matched ReplayKeyExtractor for scheme-aware nonce / payer extraction; falls back to PaymentSignature::authorization() for the EIP-3009 path.

Full Changelog: 0.5.1...0.6.0