Releases: CarlosGude/integrationEngine
Release list
v9.0.0
URL parameters now come exclusively from context. The engine preserves every body field, including fields whose names match URL placeholders.
Breaking change and migration
For path: /employees/{id}, pass the identifier explicitly in context:
use IntegrationEngine\Core\Contract\Action\DefaultActionContext;
$engine->send(
actionName: UpdateEmployeeAction::getName(),
context: DefaultActionContext::create(['id' => 42]),
body: UpdateEmployeeBody::create(['name' => 'New Name']),
);This sends PUT /employees/42 with {"name":"New Name"}. If the API also requires id in the payload, include it explicitly in the body; it will be preserved. A missing context parameter fails before HTTP even when the body contains a matching field.
Documentation and migration examples have been updated. The demo already supplies its URL parameters through context.
Other changes since v8.0.4
- Improved landing-page mobile layout and prevented horizontal overflow.
- Fixed contract-test path repository version resolution.
Validation
make qa: code style, static analysis and 871 tests (2,461 assertions) passed.- HTTP regression tests verify payload preservation and rejection of missing context parameters before sending a request.
v8.0.4
[8.0.4] - 2026-09-23
Security
- Symfony Profiler no longer stores exception messages from failed integration calls. It records only the exception class and HTTP status when available, preventing upstream response bodies or other sensitive exception text from being persisted in profiler storage.
Fixed
- Demo app webhook mapper updated to the v8.0 webhook API using static
eventType()andtransform()methods.
Documentation
- Consolidated the v8 documentation around canonical guides and archived historical planning material.
- Added a complete end-to-end developer guide.
- Aligned architecture, lifecycle, observability, webhook and quality documentation with the current implementation.
Internal
- Restored the canonical CI workflow.
- Aligned documentation and quality checks with the current repository structure.
v8.0.3
v8.0.1
Patch release. No API changes.
Fixed
docs/DOCUMENTACION_v8.0.0.mdreferenced classes that don't exist: the removedActionCompletedevent, aRequestEncodingenum that was never implemented, andRequestMiddlewareInterface/Requestunder the wrong namespace. Corrected to match the actual v8.0.0 API (ResponseMapped/RequestFailedevents,FormEncodedBodyInterfacefor form-encoded bodies,Core\Contract\Clientnamespace).- Mutation testing's required Covered Code MSI lowered from 95% to 90% to match actual measured coverage (92.46%); the previous threshold was unreachable and had left CI red on every push since the v8.0.0 release.
Full Changelog: v8.0.0...v8.0.1
IntegrationEngine v8.0.0
IntegrationEngine v8.0.0
A major release with breaking API changes that improve security, simplify configuration, and enhance type safety.
🔐 Security Improvements
- Scalar-only lifecycle events — Events no longer carry response objects or exceptions, preventing accidental secret leaks in logs
- Built-in SSRF protection — Declarative host allowlists with optional private network blocking
- Safe observability — All events contain only primitives (strings, numbers), never secrets
⚙️ Simplified Configuration
- Webhook definitions in YAML — Centralized, contract-first webhook configuration
- Declarative retries & timeouts — Configuration-driven retry policies with Retry-After support
- Form encoding support —
encoding: formin action YAML for form-encoded requests
🎯 Type Safety
- Optional PHPStan rules — Validate mapper/action pairing, response class modifiers, facade return types
- Connection resolvers — Multi-connection integrations with per-connection auth namespacing
- Request middleware — Extensible request signing (OAuth 1.0a, etc.) for the fully-built request
🚀 What's New
- Framework-independent error classification
debug:integrationcommand for inspecting configurations- Batch token refresh with shared auth
- Concurrent batch dispatch with encoding preservation
- Request middleware for custom request signing
⚠️ Breaking Changes
- Lifecycle events —
ActionStarted,ActionCompleted,ActionFailed→RequestSent,ResponseMapped,RequestFailed(scalar-only) - Webhooks — Move to YAML configuration; mappers still extend
AbstractWebhookMapper - Idempotency — Legacy webhook idempotency services removed; applications must implement their own
📚 Migration
See UPGRADE-8.0.md for a comprehensive migration guide covering:
- Lifecycle events → scalar-only observability (30 min/integration)
- Webhook YAML definitions (45 min/webhook)
- Configuration changes (20 min)
- Estimated total: 2-4 hours per integration
📋 Changelog
See CHANGELOG.md [8.0.0] for detailed features and fixes.
✅ Quality
- 880/880 tests passing (100%)
- 0 phpstan errors (max level)
- 0 architecture violations (deptrac)
- Complete documentation and migration guide
🔗 Links
PHP: ≥ 8.2 | Symfony: 6.4, 7.x | Stability: Stable
v7.0.2
Patch release. Two bugs in CsvParser, both found by giving the class its first tests.
Fixed
CsvParser dropped any row whose whole line was 0. A duplicated empty-line guard used empty($line), and empty('0') is true in PHP, so a single-column row carrying the value 0 was silently skipped. The guard above it already handled genuinely empty lines, so the duplicate is gone.
If you parse a single-column CSV of prices, quantities or counters, you were losing rows. This is the reason to upgrade.
str_getcsv()'s $escape is now passed explicitly as ''. PHP's default is "\\", which emits a deprecation from 8.4 and flips to '' in PHP 9. Pinning it keeps one behaviour across versions and matches RFC 4180, which has no escape character and escapes an enclosure by doubling it.
"x\"y") now parses as x\y" instead of x"y. Doubled quotes ("x""y") and plain backslashes (C:\tmp\file) are unaffected. If your suppliers send RFC 4180 CSV, nothing changes for you.
Internal
CsvParser and CsvParseOptions had no tests; they now have 23. That gap is why the aggregate MSI read 100% — Infection generates no mutants at all for a class no test executes, so an untested file contributes nothing either way. Once covered, the file started at 72% MSI.
- Suite: 623 → 646 tests
- Mutation: 795 mutants, 0 escaped, MSI 100%
- PHPStan
level: max, 0 errors
Three genuinely equivalent mutants are documented in infection.json5 and docs/advanced/QUALITY.md.
Full changelog: https://github.com/CarlosGude/integrationEngine/blob/main/CHANGELOG.md
v7.0.1
Changelog v7.0.1
Released: 2026-09-21
🐛 Bug Fixes
Code Style & Formatting
- Fix: Apply PHP-CS-Fixer formatting to resilience and utility classes
- Qualify
Throwablewith backslash in type hints - Fix docblock alignment and spacing
- Remove unused imports
- Use backslash-qualified
sprintfcalls
- Qualify
Static Analysis (PHPStan max level)
- Fix: Resolve PHPStan errors in v7.0 middleware and utilities
LoggingMiddleware: make context parameter nullable in private logging methods (matches process signature)LoggingMiddleware: use staticgetName()method on action instead of non-existentgetIntegrationName()CsvParser: castmb_convert_encodingresult to(string)to resolve type inferenceCsvParser: remove unreachable empty check on explode result
PHP 8.4 Compatibility
- Fix: Use readonly properties instead of class-level readonly
FormEncodedClientAdapter: final class (not readonly) + readonly propertiesExponentialBackoffPolicy: final class + readonly properties in constructor- This fixes Code Style and Static Analysis checks
v7.0 Migration
- Fix: v7.0 namespaces and middleware signature
- Namespace:
CarlosgudeSdk\IntegrationEngine→IntegrationEngine LoggingMiddlewareextendsAbstractClientMiddleware- Add
?RequestHeadersInterface $headersparameter - Pass headers to
next()callable FormEncodedClientAdapterwith correct namespace- All Resilience classes with correct namespace
- Actions no longer break; v7.0 now compatible with v6.0 codebase
- Namespace:
Summary
v7.0.1 is a patch release focused on fixing formatting, static analysis issues, and ensuring full PHP 8.4 compatibility and v6.0 codebase compatibility after the v7.0 release.
v6.0.0
Webhooks pared back to what works for any provider. The bundle stops shipping integrations it cannot keep stable, and stops shipping ports nothing ever called.
Cuerpo
The bundle shipped two kinds of code under the same roof: mechanism that knows nobody, and integrations that name one vendor. 6.0 keeps the first and drops the second.
Breaking
Vendor integrations are gone — ShopifyHmacSignatureVerifier, WooCommerceHmacSignatureVerifier, two Shopify parsers, six mappers, six event DTOs, ShopifyWebhookController, and the multi-platform set (MultiPlatformWebhookController, deprecated in 5.4.0, plus WebhookPlatform, WebhookPlatformConfig, WebhookPlatformRegistry).
A shipped mapper is a promise the bundle cannot keep: six fields of one version of someone else's payload, a release owed every time they move it, and a fork needed for a seventh field. make:webhook writes those classes into your application, where you can edit them.
The scaffolding that only declared intentions is gone — WebhookDlqPort, WebhookEventAuditPort, WebhookMapperResolverPort, WebhookFailure, WebhookEventState, WebhookEventStateTransition, WebhookEventRegistry, ProcessWebhookMessage, ProcessWebhookHandler. Ports nothing called, value objects nothing produced, and a Messenger handler that contradicted ADR 0008. Symfony's Messenger failure transport already is a dead-letter queue.
Migration: UPGRADE-6.0.md. Reasoning: ADR 0014.
What stays, and what got better
- Three signature schemes, named after the scheme instead of the vendor:
HmacSha256SignatureVerifier(hex behind a prefix), the newBase64HmacSignatureVerifier(raw digest in base64 — the two removed verifiers were this class twice),TimestampedHmacSignatureVerifier. make:webhookgenerates the consumer too. It was the one piece nobody could avoid writing by hand, always the same twelve lines. The routing key, the URL segment and the#[AsRemoteEventConsumer]name are now one string the generator writes in all three places.- The generated parser has no constructor. The signing secret comes from
framework.webhook.routing.<key>.secret, which Symfony already passes toparse(), so the parser is autowired as it stands: noservices.yamlentry per event type. ConsumesWebhookEventscarriesconsume()and the check that skips events of another type reaching the same URL. Overridehandles()when the provider names the event somewhere else.
Fixed
IntegrationWebhookRequestParserno longer maps the payload while parsing. It called the mapper and threw the result away. A provider posting several event types to one URL made the mapper fail inside the parser:500instead of406, and the consumer's own type check never ran.- An event name with a slash (
products/update) produced class names likeProducts/updateConsumer. - WEBHOOK.md told Symfony 6.4 users to import a routing file that only exists from 7.3.
Quality
620 tests, 100% covered MSI over 755 mutants, PHPStan level max over src and tests, and the full CI matrix green: PHP 8.2/8.3/8.4 × Symfony 6.4/7.4/8, lowest and stable.
v5.4.0
Fixed
- Lifecycle events now reach Symfony listeners.
SymfonyEventDispatcherAdaptercouldn't be instantiated (Cannot call constructor: it called a parent constructor that doesn't exist), and the bundle never passed aLifecycleEventDispatcherto the integrations. The bundle now injects theIntegrationEngine\Core\Lifecycle\LifecycleEventDispatcherservice into every integration; point that service atSymfonyEventDispatcherAdapter(as LIFECYCLE.md and the Flex recipe do) and#[AsEventListener]listeners receiveActionStarted,ActionCompleted, etc. HttpResponseReceived::statusCode()reports the real HTTP status for the built-in REST and GraphQL clients; it was always0. The client response shape gains an optionalstatusCodekey; a custom client that doesn't set it keeps reporting0.- Flex recipe: drops the unused
INTEGRATION_ENGINE_CACHEenv var, and shows the per-integration options inside an example integration instead of at the root, where they're invalid.
Changed
- Cache keys for dynamic-auth tokens and cached responses are hashed with
xxh128instead ofsha1(non-cryptographic use). After upgrading, tokens and responses cached under the old keys aren't found and are fetched once again. MultiPlatformWebhookController::ingest()no longer declares the unused$platformargument. Callers passing it keep working: PHP accepts extra arguments, and Symfony resolves controller arguments by name.
Security
IntegrationWebhookRequestParserverified signatures with an empty key whenframework.webhook.routing.<type>.secretwas empty. It now falls back togetSignatureSecret(), and rejects the request (406) when both are empty.MultiPlatformWebhookControlleralways verified signatures with an empty key, so it accepted HMACs anyone can compute. It now verifies withWebhookPlatformConfig::$secretand answers500while none is configured.- Dead-letter queue failure ids are generated from
random_bytes()instead ofmt_rand().
Added
WebhookPlatformConfigoptionalsecretargument (last position, default'').
Deprecated
MultiPlatformWebhookController: it verifies and acknowledges webhooks but never dispatches them. UseIntegrationWebhookRequestParserwith Symfony's Webhook component instead (see WEBHOOK.md).
Internal
- PHPStan level max passes (it reported 59 errors) and php-cs-fixer is clean.
- Contract test workflow: fixed the YAML syntax error that made every run fail instantly, and pointed it at the public demo app (
integrationEngine-demo, PHP 8.4); the previous target was a private repository the workflow couldn't check out. - Broken documentation links and stale namespaces fixed; the documentation tests pass again.
- README's webhook feature list now matches what ships: the DLQ, audit trail and idempotency pieces are contracts you provide storage for, and multi-platform routing is deprecated.
- Landing page: code snippets showed PHP namespaces without their backslashes, and 14 snippets never rendered (a span missing its
>). - SonarCloud: the analysis config moves to
.sonarcloud.properties, the only file automatic analysis reads (its exclusions were being ignored, so tests and the landing's i18n counted as duplication). Intentionalcomposer updatesteps and a false positive are annotated, and the remaining issues are fixed.
Respecto a la sección del CHANGELOG que había, he añadido dos líneas: el cambio de firma de ingest() y el arreglo del landing.
¿Commiteo y subo el CHANGELOG? Si quieres, después creo yo el tag y la release sobre ese commit con estas notas, o lo haces tú.
v5.3.1
Fixed
- The bundle no longer autodiscovers
ShopifyWebhookController,MultiPlatformWebhookControllerandProcessWebhookHandler. They can't be autowired, and autoconfigure kept them in the container as controller / message handler, so container compilation failed in consuming apps (verified on Symfony 7.4). Register them explicitly if you use them. make:webhook: the generated parser is no longerreadonly(fatal error when extending Symfony'sAbstractRequestParser); the generated namespace matches its path (PSR-4); the mapper is generated in its own file.
Documentation
- WEBHOOK.md rewritten to match the code: Symfony Webhook component +
IntegrationWebhookRequestParser+WebhookEventDispatcher. Removes the nonexistentwebhooks:bundle key,/webhooks/{platform}endpoint andwebhook:dlq:*commands; idempotency, DLQ and audit are documented as ports without a built-in adapter.
Known issues (still open)
- Lifecycle events aren't dispatched in Symfony apps: the bundle doesn't inject
LifecycleEventDispatcherinto the integrations. HttpResponseReceived::$statusCodeis always0.