Skip to content

Releases: fireflyframework/fireflyframework-php

LaraFly 26.09.11

Choose a tag to compare

@ancongui ancongui released this 01 Oct 05:23
8bbad67

Fixed

  • Scheduling: every duration of a #[Scheduled] method — fixedRate, fixedDelay and lockTtl, as
    initialDelay already was — is parsed at boot, and one that does not parse refuses the boot naming its method.
    lockTtl used to be parsed only when its task ran, so an unparseable value failed that task on every tick and
    the task never ran while the application booted and looked healthy.
  • Durations: Firefly\Resilience\Duration also reads ISO-8601 durations (PT14M, PT1H30M, P1D,
    PT0.25S), the form Spring's @Scheduled and java.time.Duration use. Years, months and weeks are refused
    because their length is not fixed. Resilience settings and every scheduling duration accept it.

LaraFly 26.09.10

Choose a tag to compare

@github-actions github-actions released this 29 Sep 21:48
61ce8d1

Fixed

  • OpenAPI contracts: derive path-pattern 404 responses and restrict inferred validation 422 responses
    to typed request bodies. Included page controllers now preserve their actual JSON, HTML or redirect return
    contract. Browser coverage checks every generated operation, tag, response and component, including nested
    schemas and keyboard access on phones.

  • OpenAPI readability: improve local Swagger text contrast for method and version badges, links, actions,
    code examples, schema controls and constraints; verify expanded schemas with either system color preference.
    Normalize native schema buttons and wrap operation controls to prevent phone overflow in WebKit.

  • Error pages: shorten paths in symlinked deployments and test harnesses, bound the debug stack before
    rendering, and group dependency frames behind a native disclosure. Frame summaries stay on one line on desktop and give calls a second line on phones;
    text contrast meets 4.5:1 in both themes. The production facts grid has no empty colored cells and shows
    the reference once, with selectable text and an optional clipboard enhancement.

  • Error URL safety: validate configured home, sign-in, support and problem-type URLs at construction;
    reject unsafe schemes, authority-relative paths and interior URL control characters.

  • Problem documents: substitute invalid UTF-8 and return a degraded document if encoding or a serialization
    callback fails. Wildcard, absent and unsupported Accept types receive problem+json while error-page
    fallback is enabled. Laravel's own validation, authentication and carried-response exceptions retain
    their native handling.

  • Migration: problem instance values now begin with /, with unsafe path characters percent-encoded.
    Clients comparing the old relative path must account for the leading slash.

  • Admin listings: replace competing column rules with typed columns, fixed table layout and explicit
    colgroups. Route paths no longer collapse into stacks of characters beside unused space. Rigid column
    widths include cell padding and allow for Linux header-font metrics, and a bounded table scrollport makes
    sticky headers work.

  • Stable paging: append an ascending identity tiebreak so tied rows cannot move between pages. Clamp
    stale out-of-range pages to the last page; a SQL-backed data listing may need one additional query.

Added

  • Route detail: permalinked, server-rendered route contracts with ordered caller/injected bindings,
    resolver claims, binding-specific failures, bounded DTO trees, sibling comparison and duplicate warnings.
    Gated wiring/configuration/API/traffic links, default responses, exception handlers, registered route
    metadata and collapsed advice provenance make the compiled contract inspectable without running it.
    firefly.admin.routes.detail and firefly.admin.routes.advice control the new surface.

  • Bean explorer: server-rendered landing/search/focus/module states, native keyboard links, bounded hop
    columns, exact overflow links, complete paginated catalogue and relations, module coupling metrics,
    conditions and shortest entry-point chains. Iterative SCC analysis handles deep graphs and self-cycles.

  • Bean graph truthfulness: stable competing factory identities across configurations, explicit unresolved
    ambiguity instead of an arbitrary target, unknown factory scope and exclusion of unbound config DTOs.

  • Explorer settings: focus depth/row/node/path/page budgets, starter/module budgets and catalogue page size.
    The legacy firefly.admin.graph.max-nodes is still parsed but no longer controls drawing; 0 no longer
    forces a list
    . Use the catalogue or relation tables for tabular exploration.

  • Error navigation: configured sign-in on 401, retry on GET/HEAD 5xx, and home/support links where
    configured. Production ledes retain safe authored details and 405 pages name the allowed methods.

  • Error configuration: documented max-frames, home, sign-in, support, actions, copy-button,
    authored-detail, problem-fallback and problem.type-uri settings in the reference and module guide.

  • RFC 9457 type: about:blank by default, a code-derived URI when an HTTP(S) base is configured, or an
    omitted member when the setting is empty. Omitting type does not revert the corrected instance path.

  • Shared listing controls: server-side paging, sorting and searching with validated, bookmarkable URL
    state across routes, beans, conditions, scheduled tasks, configuration, runtime and data listings. Paired
    listings preserve each other's state, and row-count controls have submit buttons for use without JavaScript.

  • Table settings: firefly.admin.table.page-size, page-sizes, max-page-size, max-height, density
    and remember-scroll. The offered size set is closed; the data browser applies its own bounds in series.
    Auto-refresh keeps URL state; optional per-URL scroll restoration applies on reload and back/forward.

Changed

  • packages/admin — the data browser's rows-per-page control offers the dashboard's set, and a ?size=
    outside it is refused rather than lowered.
    /firefly/data used to draw its own <select> with 10
    among the literal options and cap whatever arrived; its listing query is now parsed against the shared
    firefly.admin.table.page-sizes narrowed by firefly.admin.data.max-page-size, and that set is closed
    — a size that is not a member falls back to firefly.admin.data.page-size instead of being clamped to the
    nearest permitted one. So ?size=300 renders 25 rows rather than 200, and a bookmark holding ?size=10
    renders 25 rather than 10
    , because ten is no longer offered unless a deployment says so
    (FIREFLY_ADMIN_TABLE_PAGE_SIZES=10,25,50,100,200, or FIREFLY_ADMIN_DATA_PAGE_SIZE=10, which forces its
    own default into the set). firefly.admin.data.max-page-size is a plain cap only for a direct
    Firefly\Admin\Data\DataBrowser::list() call, which is parsed against no query string.

LaraFly 26.09.9

Choose a tag to compare

@github-actions github-actions released this 27 Sep 04:56
cac7220

Changed

  • Publish the repository root as the fireflyframework/larafly library, replacing component names at the same
    version. Runtime dependencies, autoloading and Laravel discovery now belong to that package; no split
    mirrors or cross-repository release credential are needed. The public package uses the
    fireflyframework namespace because Packagist reserves firefly for another publisher.
  • Gate GitHub releases on PHP 8.3–8.5 validation and a clean installation of the exact tagged commit
    from Packagist, including the bundled application installer.
  • Exclude local development dependencies from both release archives and copied path installations.
  • Keep Lumen and component test support in development autoloading, and validate exported and copied
    consumer installations in CI. The installer uses the bundled skeleton and adds Testbench explicitly
    when the testing capability is requested. PostgreSQL outbox migrations are registered only for that
    configured transport.

Documentation downloads

English and Spanish editions of LaraFly by Example are attached as PDF and EPUB, updated for the single-package installation and bundled installer. The same downloads are available on the book page.

These documentation assets were rebuilt after the package release from documentation commit ac03345, after its complete CI and Pages deployment passed. build-info.json records that source and SHA256SUMS verifies all four books. The v26.09.9 tag and Composer package are unchanged.

v26.09.8 — the consumer close() that stranded its client, and a main that could not pass its own gate

Choose a tag to compare

@ancongui ancongui released this 25 Sep 18:23

The leak

RdKafkaConsumerClient::close() called KafkaConsumer::close() and then released the property. Releasing the property is exactly right and was always there; it did nothing, because by the time it ran the handle was already gone.

ext-rdkafka 6.0.5, kafka_consumer.c:531-542, is the whole of that method:

rd_kafka_consumer_close(intern->rk);
intern->rk = NULL;

No rd_kafka_destroy(), and the free handler at kafka_consumer.c:53-64 destroys the handle only if (intern->rk) — which close() has just nulled. The PHP object is freed and the rd_kafka_t is not.

Measured on PHP 8.5.8 / ext-rdkafka 6.0.5 / librdkafka 2.15.1, no broker: four OS threads stranded per closed consumer, still there after five seconds of polling; zero when the reference is dropped. Unconditional, not a race. It now calls unsubscribe(), which leaves the group and lets the drop destroy the client.

The regression test counts rd_kafka_thread_cnt() rather than asserting a WeakReference goes null, because the natural test is green on this bug: the PHP object really is freed and the leak is underneath it, in C.

main could not pass composer check

Three reasons, which is why CI had been red on every PHP version since 26.09.6:

  • The version is carried in four places and 26.09.6 moved one. Version::VERSION said 26.09.6, the CHANGELOG heading 26.09.7, the README badge 26.09.5, and the verbatim listing in docs/versioning.md 26.09.5 — so the code inside the tag v26.09.7 reported itself as 26.09.6. All four now say 26.09.8.
  • pint --test was red in three files from the 26.09.7 commit.
  • phpstan had three errors in InMemoryJwksProviderTest, from one missing @return.

composer check now passes: pint, phpstan clean, 3808 tests, deptrac 0/0.

Known: the split mirrors are still unpublished

The Release workflow refused again at its preflight, as it has since 26.09.5, and it is right to: the split action exits 0 even when its push fails, so the gate stops a matrix of green jobs that published nothing.

ACCESS_TOKEN is unset and the fireflyframework/firefly-* repositories do not exist. No split package has ever been published for any version. Fixing that needs an org PAT and the repositories — docs/publishing.md steps 6-7 — and is the one part of a release this project cannot do for itself.

v26.09.4 — the native gaps, closed in the framework

Choose a tag to compare

@ancongui ancongui released this 23 Sep 19:05

Everything here began as a place where an application running on 26.09.3 had to write framework-shaped code of its own — a metric wrapper around a method, a retry loop, a publisher per broker, a security rule that silently matched nothing. Each one is now an attribute the compiled manifest carries and a firefly.* key that configures it.

Highlights

Micrometer's method attributes. #[Timed], #[Counted] and #[Observed] ride the same interceptor chain #[Transactional] does. The scanner refuses the shapes that would compile into nothing rather than dropping them in silence — a metric on a class no post-processor reaches, on a final class or method, and the two shapes PHP does not inherit: a class-level attribute on a base whose stereotyped child returns [] for it, and a method an unannotated override hides. The drop decision is per method and an intersection over subclasses, so one child that merely inherits an annotated method cannot vouch for a sibling that overrides it.

The six resilience patterns as attributes, on that same chain, instead of wrappers — with an idle TTL for breaker and limiter records.

The EDA brokers reach the tracing seam. RabbitMqEventPublisher, KafkaEventPublisher and PostgresEventPublisher route publish() through EdaTracing::tracePublish(), so a broker record carries a traceparent of the framework's own making — gated by firefly.eda.tracing.brokers.enabled. The tracing figure and its Known-latent caveat moved with the code.

Spring Data continues. A #[Projection] and a trailing Pageable combine, paging in the database. initialDelay is applied rather than carried.

Breaking

Each of these is migratable without guessing; CHANGELOG.md carries the full migration note for every one.

  • when-authorized health details are real, instead of quietly degrading to never. An application already running that value with security on starts disclosing what it used to withhold. Decide, do not inherit: set never, list roles in firefly.management.endpoint.health.roles, or bind your own HealthDetailsAuthorizer. HealthEndpoint gained a required fourth constructor parameter.
  • problem+json's traceId is the W3C trace id, and correlationId is its own member beside it; both travel as response headers. With tracing off, every byte is what it was.
  • A URL rule written /api/* stops being a dead rule, so every /-prefixed rule now matches what its author meant.
  • The OpenAPI document publishes the security the server actually has, and what the dispatcher enforces rather than only what the URL rules say.

Documentation

The provenance guard that shipped in 26.09.3 audits every Markdown file this repository ships, and wave N branched before it existed. Eighteen listings quoting code the wave had changed were re-quoted verbatim from the files they name, five new listings gained a marker, and four claims that live outside any fenced block — where no guard reads them — were corrected, including the figure's alt text.

Verification

All 21 findings wave N's review loop left unconfirmed were verified against the tree before this tag: 21 already fixed, 0 still broken, each proven with git merge-base --is-ancestor.

Gate at 72db787: Pint, PHPStan max, 3779 tests (15,144 assertions), Deptrac 0 violations, 75 browser tests, and CI green on PHP 8.3, 8.4 and 8.5.

Installing

This release is not published to Packagist — the org's mirror repositories and release credentials are not configured, by design. Install from the monorepo or a git VCS repository entry; docs/publishing.md documents what a future Packagist release would need.

Full changelog: v26.09.3...v26.09.4

v26.09.3 — Spring Security parity, two OAuth2 packages, Spring Data, tracing, and documentation held to the code

Choose a tag to compare

@ancongui ancongui released this 23 Sep 14:32

Seven waves of framework work and the documentation set that describes them truthfully.

Spring-Security-grade authentication and authorization: session-persisted context, form login
with the framework's own page, HTTP Basic, logout, remember-me, an entry point that negotiates
a login redirect against a 401 problem document, method security on any stereotyped bean through
one compiled proxy chain that runs security before transaction, principal injection, an Eloquent
user store, the authentication event family, and test support.

Two new packages: firefly/security-oauth2-client (OpenID Connect login with provider presets and
discovery, PKCE, id-token validation, RP-initiated logout, client credentials, Http::oauth2Client())
and firefly/security-oauth2-server (a Spring-Authorization-Server-shaped OAuth 2.1 / OIDC provider:
registered clients, /oauth2/authorize with a consent page, three grants, introspection, revocation,
userinfo, JWKS, both .well-known documents, RS256/ES256 keys with rotation).

Spring-Data-grade data: a translated DataAccessException family, query by example, #[Modifying],

OpenTelemetry-shaped tracing with W3C propagation across the web filter, the Http client, both CQRS
buses and EDA envelopes; structured logging (json, ECS, logstash); histogram buckets on timers.

Spring-shaped validation messages and #[Valid] cascading into list elements.

A browser end-to-end suite: Pest 4 and Playwright driving real Chromium over the shipped skeleton,
with its own CI job.

And the documentation held to the code: every fenced listing in the README, the guides and both
book editions is now proved against the file it came from, or marked as the reader's own code.
Nine diagrams, a redesigned site, and a bilingual book caught up with all of it.


Gate: 3,340 tests · PHPStan level max · Pint · Deptrac 0 violations · 68 browser scenarios in real Chromium · 14 book tests · 294 verified code listings per manuscript · mkdocs build --strict. CI green on PHP 8.3, 8.4 and 8.5.

Documentation: https://fireflyframework.github.io/fireflyframework-php/

Note on installation: the per-package mirrors are not published for this tag — the release workflow's credential preflight refused, by design, because the org token is not configured. Install from this monorepo until the mirrors are set up; see docs/publishing.md.

v26.09.1 — response schemas, an error page, a data browser, and five security fixes

Choose a tag to compare

@ancongui ancongui released this 04 Sep 03:45
c29bdc9

A correctness release that also grew two browser surfaces — then had its own 606-file diff reviewed
adversarially and fixed everything that found.

Added

  • firefly/openapi documents what an endpoint RETURNS. Every success response used to be
    {"type": "object"} — a blank panel in a viewer, any in a generated client. DocType compiles a PHPDoc
    type expression into a JSON Schema fragment (array shapes, list<T>, array<K,V> told apart as
    array-vs-object, tuples, literal unions, PHPStan pseudo-types), and ResponseSchemaFactory builds a
    returned class from its wire shape rather than its constructor. Three input collections were fixed with
    it too: array<string, int> was published as an array, which is the wrong JSON type.
  • An HTML error page in the framework's own design, with the exception, its previous chain, the source
    around the throwing line, and a stack trace that separates your frames from your dependencies'. Overridable
    per status; json-paths (default api/*) forces problem+json on your API space whatever the caller asks.
  • Four new dashboard pages — a datasource page (connections, PDO persistence, the compiled
    #[Transactional] contract), a drawn entity map, a feature-switch console, and a data browser with
    filtering, real pagination, full CRUD and relations you can walk in both directions.
  • The skeleton ships what it advertises. firefly/admin and firefly/openapi were required by nothing,
    so create-project produced a project with neither. Its sample REST resource did not persist while its
    docblock claimed it did; it is now an EloquentRepository over two tables, which earns it its first
    #[Transactional].

Security

Five defects, each reproduced before it was fixed and each pinned by a test that fails when the fix is reverted.

CSRF Dashboard routes were mounted with no middleware at all — every @csrf in the views was decorative, and a tokenless curl -X POST changed the log level.
Extraction oracle A filter on a masked column recovered correct horse battery in 21 requests while the page displayed ******.
Production leak problem+json published an unhandled QueryException's SQL and its bindings in production, ungated, while the HTML page beside it withheld everything.
Write primitive The connection wizard, documented as "never writes anything", could create a file anywhere the worker could write via sqlite's database path.
Silent wrong answer contains/starts escaped LIKE wildcards with no ESCAPE clause, so a search for ada_love returned zero rows against a table containing ada_lovelace@example.test.

Laravel's CSRF middleware skips itself under tests, which is how that hole survived being written — so its
regression test asserts the middleware is attached, and the behaviour was verified over real HTTP.

The book

LaraFly by Example — fourteen chapters plus appendices, bilingual — is attached below as PDF and EPUB in
both languages, rebuilt from this tag. Chapter 4A gained "The success body: what an endpoint actually
returns" and Chapter 11 gained the new dashboard surfaces; both editions were edited in parallel.

Gates

2078 passed, 1 skipped · PHPStan max, 0 errors · deptrac 0 violations · Pint clean · book listings
223/223 · CI green on PHP 8.3, 8.4 and 8.5.

Not yet published to Packagist

release.yml splits 28 packages to fireflyframework/firefly-<pkg> mirrors, and those repositories do not
exist and no ACCESS_TOKEN secret is set
— so this tag published nothing to Packagist.

Worth knowing if you are watching the Actions tab: the split run for this tag reported success on all 28
jobs anyway
. symplify/monorepo-split-github-action exits 0 even when its push fails, so the run went
green while no mirror existed and nothing was published. That false green is fixed on main — the workflow
now refuses to start without ACCESS_TOKEN, and reads each tag back from its mirror before passing — but
this tag's run predates the fix.

Creating the mirrors and registering on Packagist need the org owner; see docs/publishing.md steps 6–7.

Full changelog: CHANGELOG.md

v26.07.18 — Docs-parity milestone

Choose a tag to compare

@ancongui ancongui released this 28 Jul 17:10

The documentation-parity milestone: a runnable Lumen wallet/ledger sample, a professional README, a docs table of contents, a bilingual step-by-step tutorial, and the complete bilingual book — all adversarially reviewed.

📘 LaraFly by Example — the book

Attached below as PDF + EPUB in both languages (a quick start, 13 chapters across four parts, plus a Laravel→LaraFly cheat-sheet and glossary — every listing verified against the real samples/lumen sample):

PDF EPUB
English larafly-by-example.pdf larafly-by-example.epub
Español larafly-by-example-es.pdf larafly-by-example-es.epub

The book sources live in book/ and rebuild via book/build/run.sh.

See CHANGELOG.md for the full milestone notes.