rasuvaeff / yii3-webhooks-db
Database-backed delivery and nonce storage for rasuvaeff/yii3-webhooks
Requires
- php: 8.3 - 8.5
- psr/clock: ^1.0
- rasuvaeff/yii3-webhooks: ^1.0
- yiisoft/db: ^2.0
- yiisoft/db-migration: ^2.0
Requires (Dev)
- ergebnis/composer-normalize: ^2.51
- friendsofphp/php-cs-fixer: ^3.95
- infection/infection: ^0.33
- maglnet/composer-require-checker: ^4.17
- rector/rector: ^2.4
- roave/backward-compatibility-check: ^8.0
- testo/bridge-infection: ^0.1.6
- testo/testo: ^0.10.25
- vimeo/psalm: ^6.16
- yiisoft/cache: ^3.2
- yiisoft/db-sqlite: ^2.0
- yiisoft/injector: ^1.2
- yiisoft/test-support: ^3.1
This package is auto-updated.
Last update: 2026-07-25 13:28:02 UTC
README
Database storage for rasuvaeff/yii3-webhooks deliveries and nonces: a
production-grade record of delivery attempts and atomic replay protection.
Using an AI coding assistant? llms.txt contains a compact API reference you can share with the model.
Requirements
- PHP 8.3+
rasuvaeff/yii3-webhooks^1.0yiisoft/db^2.0yiisoft/db-migration^2.0psr/clock^1.0
Installation
composer require rasuvaeff/yii3-webhooks-db
Usage
use Psr\Clock\ClockInterface; use Rasuvaeff\Yii3Webhooks\WebhookDelivery; use Rasuvaeff\Yii3WebhooksDb\DbNonceStorage; use Rasuvaeff\Yii3WebhooksDb\DbWebhookDeliveryStorage; $deliveries = new DbWebhookDeliveryStorage(db: $db); $nonces = new DbNonceStorage(db: $db, clock: $clock); $delivery = WebhookDelivery::create(event: $event, endpoint: $endpoint); $deliveries->save(delivery: $delivery); $accepted = $nonces->add(nonce: $signature->getValue());
Under yiisoft/config this package binds only WebhookDeliveryStorage and
NonceStorage.
Migration
Register the bundled migration
(Rasuvaeff\Yii3WebhooksDb\Migration\M260612000000CreateWebhookTables)
by namespace — no vendor paths:
// config/common/di/migration.php use Yiisoft\Db\Migration\Service\MigrationService; return [ MigrationService::class => [ 'setSourceNamespaces()' => [['App\\Migration', 'Rasuvaeff\\Yii3WebhooksDb\\Migration']], ], ];
./yii migrate:up
Set the table names in params — the same values reach the migration and
both storages (as WebhookDeliveryTableName / WebhookNonceTableName):
// config/common/params.php 'rasuvaeff/yii3-webhooks-db' => [ 'deliveryTable' => 'my_webhook_deliveries', 'nonceTable' => 'my_webhook_nonces', 'table_prefix' => '', // prepended to both; e.g. 'rsv_' → rsv_my_webhook_deliveries ],
Index names follow the table names, so two installations can share one PostgreSQL schema — index names are unique per schema there, not per table.
Do not configure the migration through the DI container.
M...::class => ['__construct()' => [...]]does not work: the migration is built byInjector::make(), which resolves arguments by type and never reads a container definition keyed by the migration's own class. Worse, adding that definition makes the container fatal at build time in every request, because the class is not autoloadable until the migration runner requires it. That recipe was documented in 1.x; it never worked.
API reference
DbWebhookDeliveryStorage
| Method | Description |
|---|---|
save(delivery) |
Inserts or updates the delivery record |
findPending(limit) |
Returns pending deliveries, oldest first |
markDelivered(delivery) |
Stores the delivery as succeeded |
markFailed(delivery) |
Stores the delivery as failed |
getById(id) |
Loads a delivery by id |
DbNonceStorage
| Method | Description |
|---|---|
has(nonce) |
Whether the nonce is already known |
add(nonce) |
Atomic insert; returns false on a duplicate |
deleteOlderThan(threshold) |
Drops stale nonces for retention cleanup |
Security
DbNonceStorage::add()relies on the primary key and catches duplicate-key errors — that is what makes replay protection atomic instead of a check-then-write race.DbWebhookDeliveryStoragepersistsWebhookDeliveryfields only; endpoint secrets are never stored.- Keep nonce rows for at least the webhook timestamp tolerance window: prune them sooner and a replay becomes possible again.
Examples
See examples/ for a runnable SQLite example.
Development
make install
make build
make cs-fix
make test
make test-coverage
make mutation
make release-check
License
BSD-3-Clause. See LICENSE.md.