Skip to content

Releases: CarlosGude/integrationEngine

v9.0.0

Choose a tag to compare

@CarlosGude CarlosGude released this 24 Sep 18:25

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

Choose a tag to compare

@CarlosGude CarlosGude released this 23 Sep 16:55

[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() and transform() 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

Choose a tag to compare

@CarlosGude CarlosGude released this 23 Sep 08:42

Fix documentation

v8.0.1

Choose a tag to compare

@CarlosGude CarlosGude released this 23 Sep 08:10

Patch release. No API changes.

Fixed

  • docs/DOCUMENTACION_v8.0.0.md referenced classes that don't exist: the removed ActionCompleted event, a RequestEncoding enum that was never implemented, and RequestMiddlewareInterface/Request under the wrong namespace. Corrected to match the actual v8.0.0 API (ResponseMapped/RequestFailed events, FormEncodedBodyInterface for form-encoded bodies, Core\Contract\Client namespace).
  • 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

Choose a tag to compare

@CarlosGude CarlosGude released this 22 Sep 16:03

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: form in 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:integration command for inspecting configurations
  • Batch token refresh with shared auth
  • Concurrent batch dispatch with encoding preservation
  • Request middleware for custom request signing

⚠️ Breaking Changes

  1. Lifecycle events — ActionStarted, ActionCompleted, ActionFailed → RequestSent, ResponseMapped, RequestFailed (scalar-only)
  2. Webhooks — Move to YAML configuration; mappers still extend AbstractWebhookMapper
  3. 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

Choose a tag to compare

@CarlosGude CarlosGude released this 21 Sep 18:02

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.

⚠️ Output changes for one input shape: a backslash-escaped quote inside a quoted field ("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

Choose a tag to compare

@CarlosGude CarlosGude released this 21 Sep 13:09

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 Throwable with backslash in type hints
    • Fix docblock alignment and spacing
    • Remove unused imports
    • Use backslash-qualified sprintf calls

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 static getName() method on action instead of non-existent getIntegrationName()
    • CsvParser: cast mb_convert_encoding result to (string) to resolve type inference
    • CsvParser: 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 properties
    • ExponentialBackoffPolicy: 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
    • LoggingMiddleware extends AbstractClientMiddleware
    • Add ?RequestHeadersInterface $headers parameter
    • Pass headers to next() callable
    • FormEncodedClientAdapter with correct namespace
    • All Resilience classes with correct namespace
    • Actions no longer break; v7.0 now compatible with v6.0 codebase

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

Choose a tag to compare

@CarlosGude CarlosGude released this 21 Sep 08:19

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 new Base64HmacSignatureVerifier (raw digest in base64 — the two removed verifiers were this class twice), TimestampedHmacSignatureVerifier.
  • make:webhook generates 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 to parse(), so the parser is autowired as it stands: no services.yaml entry per event type.
  • ConsumesWebhookEvents carries consume() and the check that skips events of another type reaching the same URL. Override handles() when the provider names the event somewhere else.

Fixed

  • IntegrationWebhookRequestParser no 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: 500 instead of 406, and the consumer's own type check never ran.
  • An event name with a slash (products/update) produced class names like Products/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

Choose a tag to compare

@CarlosGude CarlosGude released this 19 Sep 09:46

Fixed

  • Lifecycle events now reach Symfony listeners. SymfonyEventDispatcherAdapter couldn't be instantiated (Cannot call constructor: it called a parent constructor that doesn't exist), and the bundle never passed a LifecycleEventDispatcher to the integrations. The bundle now injects the IntegrationEngine\Core\Lifecycle\LifecycleEventDispatcher service into every integration; point that service at SymfonyEventDispatcherAdapter (as LIFECYCLE.md and the Flex recipe do) and #[AsEventListener] listeners receive ActionStarted, ActionCompleted, etc.
  • HttpResponseReceived::statusCode() reports the real HTTP status for the built-in REST and GraphQL clients; it was always 0. The client response shape gains an optional statusCode key; a custom client that doesn't set it keeps reporting 0.
  • Flex recipe: drops the unused INTEGRATION_ENGINE_CACHE env 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 xxh128 instead of sha1 (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 $platform argument. Callers passing it keep working: PHP accepts extra arguments, and Symfony resolves controller arguments by name.

Security

  • IntegrationWebhookRequestParser verified signatures with an empty key when framework.webhook.routing.<type>.secret was empty. It now falls back to getSignatureSecret(), and rejects the request (406) when both are empty.
  • MultiPlatformWebhookController always verified signatures with an empty key, so it accepted HMACs anyone can compute. It now verifies with WebhookPlatformConfig::$secret and answers 500 while none is configured.
  • Dead-letter queue failure ids are generated from random_bytes() instead of mt_rand().

Added

  • WebhookPlatformConfig optional secret argument (last position, default '').

Deprecated

  • MultiPlatformWebhookController: it verifies and acknowledges webhooks but never dispatches them. Use IntegrationWebhookRequestParser with 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). Intentional composer update steps 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

Choose a tag to compare

@CarlosGude CarlosGude released this 18 Sep 19:14

Fixed

  • The bundle no longer autodiscovers ShopifyWebhookController, MultiPlatformWebhookController and ProcessWebhookHandler. 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 longer readonly (fatal error when extending Symfony's AbstractRequestParser); 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 nonexistent webhooks: bundle key, /webhooks/{platform} endpoint and webhook: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 LifecycleEventDispatcher into the integrations.
  • HttpResponseReceived::$statusCode is always 0.