Skip to content

Releases: fireflyframework/fireflyframework-pyfly

v26.06.113

17 Jun 16:08
332776e

Choose a tag to compare

v26.06.113 (2026-06-17)

Added

  • Server-layer observability. Observability is no longer only application-layer
    (the http_server_requests_seconds filter, tracing/correlation, process metrics):
    pyfly now emits metrics about the ASGI server itself across Uvicorn, Granian,
    and Hypercorn. A pure-ASGI ServerMetricsASGIMiddleware (the uniform primary
    source, running in every worker) emits server_active_connections,
    server_in_flight_requests, and server_requests_total; a ServerMetricsBinder
    bound from the in-worker ASGI lifespan emits server_workers,
    server_uptime_seconds, and server_started_total / server_stopped_total; and
    a best-effort ServerStatsPort surfaces Uvicorn's true socket count
    (server_native_connections) on the in-process serve_async path. Every meter is
    labeled server and worker_pid.
  • Correct multi-worker aggregation. With workers > 1, pyfly run enables
    prometheus_client multiprocess mode (sets PROMETHEUS_MULTIPROC_DIR before
    forking), so a single /actuator/prometheus scrape aggregates across all workers
    via MultiProcessCollector — this also fixes the previous per-worker gap for
    http_server_requests_*.
  • Live admin Observability dashboard. A new real-time Observability view
    (under Monitoring) shows server workers, uptime, active connections, in-flight
    requests, requests/sec, a per-worker breakdown, and worker lifecycle, with links
    to the Metrics and Traces views. Backed by GET /admin/api/observability and the
    observability SSE stream.
  • Configuration. New pyfly.server.observability.* keys — enabled
    (default true, activated by the web/core starters), sample-interval-seconds
    (5.0), and access-log (false, opt-in). Requires the observability extra
    (prometheus_client); degrades to a no-op without it.
  • Local observability stack. docker-compose.yml gained loopback-bound
    Prometheus + Grafana services (config in ops/prometheus/prometheus.yml) that
    scrape /actuator/prometheus.

Scope: gunicorn is intentionally not added (the stack stays async-only ASGI:
Granian > Uvicorn > Hypercorn), but the ServerStatsPort + multiprocess design is
gunicorn-ready for a future adapter.


Full Changelog: v26.06.112...v26.06.113

v26.06.112

16 Jun 20:13
872b5af

Choose a tag to compare

v26.06.112 (2026-06-16)

Changed

  • "PyFly by Example" — all diagrams redesigned. Every content figure in both
    the English and Spanish editions was rebuilt in a single, polished design
    language (consistent cards, gradient headers, numbered step flows, monospace
    code tokens, brand palette, vector iconography). This fixes real defects in the
    previous artwork — broken/tofu glyphs (font-dependent arrows, circled numbers
    and check marks) and clipped/overflowing content — by drawing all arrows,
    checkmarks and numbered badges as vector shapes and keeping figure text to
    ASCII/Latin-1 only.
  • Two new figures where they help most: Page / Pageable / Sort (Chapter 5)
    and Value Object vs Entity (Chapter 6). Both editions rebuilt and re-attached
    to the release.

Full Changelog: v26.06.111...v26.06.112

v26.06.111

16 Jun 19:42
ef200b3

Choose a tag to compare

v26.06.111 (2026-06-16)

Added

  • "PyFly by Example" — Spanish edition. The book is now published in Spanish
    (book/dist/pyfly-by-example-es.{epub,pdf}) alongside the English edition,
    built from a parallel book/manuscript-es/ manuscript via book.es.yaml. The
    book build (book/build/build.py) is now language-parameterized (--config,
    per-manifest manuscript_dir / output_basename / localized labels). Both
    editions are attached to the GitHub release.
  • Quick Start tutorial + step-by-step depth. A new "Build Lumen Step by Step"
    walkthrough takes the reader from an empty folder to a running, tested wallet
    feature; every chapter was deepened into a more granular, beginner-friendly
    tutorial. A dedication was added (EN + ES).

Fixed

  • pyfly new no longer scaffolds the removed pyfly.web.port key. The project
    template (pyfly.yaml.j2) now emits the port under server: as
    pyfly.server.port (Spring server.port parity); the legacy pyfly.web.port
    was removed in v26.06.102 and had been left as a dead key in freshly scaffolded
    applications.

Full Changelog: v26.06.110...v26.06.111

v26.06.110

16 Jun 16:12
f95cb1a

Choose a tag to compare

v26.06.110 (2026-06-16)

Fixed

  • The separate management port (actuator + admin) is now OPEN by default. When
    pyfly.management.server.port runs actuator/admin on a dedicated port, the
    app's user security filters (e.g. an HttpSecurity gate whose deny-all
    catch-all is scoped to the main app's URL space) were applied there too —
    rejecting /admin, /actuator/info, /actuator/metrics with 401/403
    while only /actuator/health (explicitly permitted) worked. The management
    port is a separate, typically-internal listener (Spring management.server.port
    parity) protected by network isolation, so it no longer applies the app's
    security filters by default. Opt back in with
    pyfly.management.security.enabled: true.

Full Changelog: v26.06.109...v26.06.110

v26.06.109

16 Jun 15:31
0357813

Choose a tag to compare

v26.06.109 (2026-06-16)

Fixed

  • CORS preflight is no longer rejected by the security gate. The
    CORSMiddleware is now the outermost middleware (ahead of the
    WebFilterChain that holds the HttpSecurity gate) on both the Starlette
    and FastAPI adapters. Previously the filter chain wrapped CORS, so a browser
    OPTIONS preflight (which carries no credentials) to a gated route was
    answered with 401 and without Access-Control-* headers — the browser
    then blocked the real request ("Load failed"/"Failed to fetch"). The preflight
    is now answered by CORS before the gate runs, and Access-Control-* headers
    are added to every response.

Full Changelog: v26.06.108...v26.06.109

v26.06.108

16 Jun 14:28
c566619

Choose a tag to compare

v26.06.108 (2026-06-16)

Added

  • The live actuator HealthAggregator is exposed on
    app.state.pyfly_health_aggregator.
    Consumers can now register extra
    health indicators after create_app (e.g. a readiness-only probe for an
    external dependency) without introspecting route closures. It is the same
    aggregator the live health routes use — whether actuator runs on the main app
    (shared management mode) or on the separate management port — so indicators
    added through it are reflected on /actuator/health in either mode.

Full Changelog: v26.06.107...v26.06.108

v26.06.107

16 Jun 14:01
52c2af3

Choose a tag to compare

v26.06.107 (2026-06-16)

Added

  • OAuth2 resource server: config-driven, multi-IdP, Spring-parity. The
    bearer-token resource server now works out of the box with Keycloak,
    Microsoft Entra ID (v1.0 + v2.0) and AWS Cognito via configuration
    alone (no subclassing), and reaches Spring-Security parity:
    • issuer-uri OIDC discovery — derive the JWKS endpoint + issuer from
      <issuer-uri>/.well-known/openid-configuration (alternative to jwks-uri).
    • Config-driven claim mapping (pyfly.security.oauth2.resource-server.*):
      principal-claim-names, authorities-claim-names, scope-claim-names,
      attribute-claims, authority-prefix. Claim names accept dotted paths
      with a * wildcard and are colon-safe, so authorities resolve from
      realm_access.roles, resource_access.*.roles (Keycloak), roles + groups
      (Entra), and cognito:groups (Cognito) with zero code.
    • audiences (a list; aud must match any) and validate-audience
      (disable for Cognito access tokens, which carry no aud).
    • Configurable algorithms, clock-skew-seconds, jwks-timeout-seconds,
      jwks-cache-seconds.
    • New typed ResourceServerProperties (@config_properties) and
      ClaimMappings.

Fixed

  • OAuth2 resource server — clock-skew leeway. JWT validation now allows 60s
    of clock skew by default (configurable). Previously a token whose iat/nbf
    was a few seconds ahead of the server clock — routine with real IdPs — was
    rejected as "not yet valid", causing intermittent 401s.
  • OAuth2 resource server — event-loop stall. The bearer filter now runs JWKS
    validation (which does blocking network I/O on a cache miss) in a worker thread
    (anyio.to_thread) instead of inline on the event loop.
  • OAuth2 resource server — multi-IdP claim coverage. Token-to-SecurityContext
    mapping previously read only realm_access.roles and scope/permissions,
    silently dropping Keycloak resource_access client roles, Entra groups /
    scp, Cognito cognito:groups, and any token attributes. All are now mapped
    (configurably).
  • OAuth2 resource server — case-insensitive Bearer scheme (RFC 7235): a
    bearer … / BEARER … Authorization header is now accepted.
  • OAuth2 resource server — opt-in strict rejection. New
    authenticate-error-mode: "401" rejects a present-but-invalid token at the
    filter with 401 + WWW-Authenticate: Bearer error="invalid_token" (RFC
    6750). Default remains "anonymous" (the gate decides) — no behavioural change
    unless opted in.

Full Changelog: v26.06.106...v26.06.107

v26.06.106

16 Jun 10:44
1ab27f0

Choose a tag to compare

v26.06.106 (2026-06-16)

Fixed

  • Admin dashboard: the Overview "Thread Count" gauge no longer renders the
    thread count as a percentage.
    The gauge widget (createGaugeChart) was a
    fixed 0–100 percentage meter — it clamped its value to 100 and appended a
    hard-coded % to the centre readout — but the Overview page feeds it the
    absolute active-thread count. A process with 8 threads therefore showed
    8%, and any count above 100 clamped to 100%. The gauge now accepts a
    max (the value that fills the arc) and a unit (the readout suffix); the
    thread gauge passes unit: '' and max: 100, so it shows the raw count
    (8, 150, …) while still acting as a thread-leak indicator (amber past 60,
    red past 80). The defaults (max: 100, unit: '%') keep every percentage
    gauge rendering exactly as before.

Full Changelog: v26.06.105...v26.06.106

v26.06.105

15 Jun 18:39
9e5ddd2

Choose a tag to compare

v26.06.105 (2026-06-15)

Fixed

  • Management-port observability now covers BOTH the application and the
    management ports.
    When actuator + admin run on a separate
    pyfly.management.server.port, the dashboard/actuator there is the single
    observability pane — but it previously reflected only the application port:
    • Access log: the management app was built without RequestLoggingFilter,
      so health probes, Prometheus scrapes and admin calls to the management port
      produced no http_request log line. It is now wired into the management
      chain (honoring pyfly.web.request-logging.enabled), so management-port
      traffic is logged through pyfly's structured logger like the main app.
    • Metrics / HTTP exchanges / traces: the data-capture filters
      (MetricsFilter, HttpExchangeRecorderFilter, the admin TraceCollector)
      ran only on the main app, so http.server.requests, /actuator/httpexchanges
      and the admin Traces view excluded management-port traffic. The same shared
      capture instances
      now also run on the management app, so the dashboard
      reflects both ports. A request traverses exactly one app's chain, so there is
      no double counting; the recorders keep their own path exclusions (Prometheus
      scrape, admin SSE self-polling).

Full Changelog: v26.06.104...v26.06.105

v26.06.104

15 Jun 17:07
a921a67

Choose a tag to compare

v26.06.104 (2026-06-15)

Changed

  • Clean error reporting — no raw tracebacks for expected (4xx) errors. A new
    pyfly.kernel.exceptions.is_expected_error() classifies BusinessException
    and SecurityException (validation, business-rule, not-found, auth — the HTTP
    4xx family) as expected. These are now logged at WARNING without a stack
    trace
    ; only unexpected infrastructure/5xx errors get a full traceback:
    • CQRS CommandHandler.on_error / QueryHandler.on_error no longer log
      exc_info=True for expected errors (previously every command/query failure,
      including validation, dumped a stack trace).
    • The web RequestLoggingFilter logs expected 4xx request failures at WARNING
      instead of ERROR (the RFC 7807 response is unchanged).
  • CLI shows clean one-line errors. pyfly now surfaces uncaught failures
    (e.g. a configuration/validation error during boot) as a single
    Error: <message> line and exit code 1, instead of a raw Python traceback.
    Pass --debug (or set PYFLY_DEBUG=1) to see the full traceback.

Full Changelog: v26.06.103...v26.06.104