Revision history for WebDyne

3.026 2026-09-05

    * Required Carp 1.50 or newer so Devel::Confess preserves the original
      PAGI send failure on older Perls instead of reporting a stack-argument
      copy error. Installed Future::IO explicitly in CI to run the PAGI
      multipart tests instead of skipping them.

    * Retained the PAGI response Future before awaiting it to avoid a Perl
      5.38 segmentation fault when Devel::Confess builds a stack trace for a
      failed response send. Exception tracing remains enabled.

    * Added regression coverage for failed PAGI response body sends,
      checking that the original error propagates without sending
      additional events.

3.025 2026-09-05

    * Preserved repeated Set-Cookie headers in PAGI responses and flattened
      repeated PSGI response headers into separate scalar pairs. Apache
      header snapshots now retain repeated values; their documented snapshot
      semantics remain unchanged.

    * Bound PAGI and PSGI HTTP request bodies with WEBDYNE_CGI_POST_MAX (512
      KiB by default) before page dispatch. Added support for bodies without
      Content-Length and robust PSGI short-read handling, with oversized
      bodies rejected using HTTP 413 and invalid or incomplete PSGI bodies
      using HTTP 400.

    * Corrected PAGI mounted-path handling relative to root_path and
      normalized outgoing HTTP header names to lowercase.

    * Buffered bounded URL-encoded PAGI SSE form bodies before page setup,
      awaited SSE close sends, and returned explicit denial responses for
      SSE setup failures and WebSocket handshakes without valid page
      callbacks. Multipart SSE submissions remain unsupported.

    * Accepted URL-encoded form Content-Type parameters such as charset.
      Apache body readers now support missing Content-Length, reject
      incomplete reads, and enforce defensive size checks for buffered and
      streaming input. Multipart forms without a length are buffered for
      CGI::Simple parsing.

    * Documented Apache LimitRequestBody as the primary request-size
      protection. Adapter checks also enforce WEBDYNE_CGI_POST_MAX; uncaught
      defensive exceptions currently produce HTTP 500.

    * Added regression coverage for the request-adapter fixes to MANIFEST
      and made the new PSGI tests skip when optional Plack dependencies are
      unavailable. Refreshed the WebDyne 3.0 release overview and upgrade
      guidance.

    * Added GitHub build-provenance attestations for release distribution
      archives, alongside existing Cosign signatures. README.md now explains
      verification with gh attestation verify against aspeer/WebDyne,
      including archives downloaded from CPAN mirrors. Prefixed
      release-script shell globs with ./ to prevent filenames being
      interpreted as options.

    * Removed the Plack dependency from static-file subrequests used by
      standalone utilities. The historical PSGI::Static helper now inherits
      from Request::Fake; cpanfile no longer requires Plack::Request. Added
      regression coverage for utilities without Plack/PAGI, binary and empty
      static files, missing files, and PSGI/PAGI parent requests.

    * Reviewed and expanded the DocBook guide against the current code.
      Corrected examples and runtime defaults, and added guidance on PAGI
      async state and await boundaries, SSE and WebSocket completion,
      request and response handling, uploads, escaping, body limits, and
      production deployment.

3.024 2026-09-05

    * Fixed PAGI multipart form uploads by staging bounded request bodies
      before synchronous CGI::Simple parsing. Binary uploads and form fields
      now work with asynchronous request delivery, and multipart bodies
      above WEBDYNE_CGI_POST_MAX return HTTP 413.

    * Fixed source, template, and compiled-cache handling for files with an
      mtime of zero, as found on WebAssembly and other virtual filesystems.
      Distinguished undefined cache timestamps from valid epoch-dated caches
      when deciding whether to compile or load a page.

    * Added the missing Fcntl import in WebDyne::Util for file-open flags.

    * Added regression coverage for repeated asynchronous multipart uploads,
      upload size limits, and zero-timestamp source, template, and cache
      files. Optional PAGI tests now check dependencies before loading async
      modules, and the session-cookie test skips the SameSite assertion when
      the installed CGI::Simple cannot serialize that attribute.

3.023 2026-08-25

    * Moved PSGI and PAGI wrapper initialization fully into
      WebDyne::PSGI and WebDyne::PAGI. The webdyne.psgi and webdyne.pagi
      scripts now use the shared application builder, so configured
      middleware and document-root .webdyne.conf.pl loading behave the same
      for wrapper scripts and directly constructed applications.

    * Disabled PSGI and PAGI static-file middleware by default. Enable it
      explicitly with static => 1, --static in the helper scripts, or the
      WEBDYNE_PSGI_STATIC or WEBDYNE_PAGI_STATIC configuration constant.
      This avoids serving static assets unexpectedly from directly
      constructed applications.

    * Added regression coverage for wrapper static-option forwarding and
      ensured static middleware does not expose files with disallowed
      extensions.

3.022 2026-08-25

    * Hardened the helper script defaults for the built-in WebDyne indexer.
      webdyne.psgi, webdyne.pagi, and webdyne.apache now leave index handling
      disabled by default unless DOCUMENT_DEFAULT, a user option file, or an
      explicit --index option enables it.

    * Added WEBDYNE_INDEX_SOURCE_ENABLE and --view-source support for the
      helper scripts. The built-in index page source viewer is now disabled
      unless both index handling and source viewing are explicitly enabled,
      preserving the directory listing/debugging workflow without exposing
      page source by default.

    * Added PSGI and PAGI application builder support for wrapper-style
      initialization, including optional static handling and document-root
      .webdyne.conf.pl loading via the new constructor options. The helper
      scripts now opt in to this behaviour while direct
      WebDyne::PSGI->new(...)->to_app and WebDyne::PAGI->new(...)->to_app
      construction retains conservative defaults.

    * Fixed PSGI API fallback path traversal by rejecting dot path segments
      before route discovery and verifying discovered API files remain inside
      the document root using canonical relative-path checks. Added
      regression coverage for traversal attempts and normal API routing.

    * Restored end-of-string matching for WebDyne PSP filenames so files
      such as report.psp.pdf are not treated as executable PSP pages.
      This fixes a double-extension execution regression introduced when
      WEBDYNE_PSP_EXT became configurable.

    * Re-enabled CGI form value escaping by default and fixed the
      WebDyne::HTML::Tiny entity encoder override so
      WEBDYNE_CGI_AUTOESCAPE works as documented. Sticky text, password, and
      file form fields now escape request-derived values before rendering
      them into HTML attributes.

    * Applied automatic HTML escaping to request, environment, and method
      substitution operators (+{...}, *{...}, and ^{...}) when
      WEBDYNE_CGI_AUTOESCAPE is enabled. The raw ${...} substitution operator
      remains available for trusted, already-rendered values.

    * Added secure session cookie defaults and configuration constants for
      Secure, HttpOnly, and SameSite attributes. WebDyne sessions now emit
      Secure, HttpOnly, and SameSite=Lax cookies by default, with documented
      constants for deployments that need to adjust those attributes.

    * Preserved <start_html> shortcut version overrides and added regression
      coverage for local-configuration isolation so tests are not affected by
      a developer's document-root .webdyne.conf.pl.

    * Updated the XML documentation, markdown sidecars, MANIFEST, and test
      suite for the new helper defaults, index source controls, escaping
      behaviour, PSP extension matching, PSGI/PAGI initialization, API
      traversal checks, and session cookie flags.

3.021 2026-08-24

    * Extended wdlint to inspect inline Perl chunks, processing instructions,
      and substitution expressions in addition to __PERL__ sections. Each
      chunk is checked independently so later syntax errors are still reported
      after an earlier chunk fails. Added line-preserving regression coverage.

    * Added require and import attributes to <start_html>, using the same
      dependency-loading and function-import behaviour as <perl>. Declared
      dependencies are loaded before normal, SSE, and WebSocket handlers are
      dispatched.

    * Passed CGI parameter hashes to PAGI SSE and WebSocket subroutines as
      their second argument, allowing async handlers to use request
      parameters explicitly across await points.

    * Fixed URL-encoded form POST handling under PAGI by asynchronously
      buffering request bodies before synchronous CGI::Simple parsing. Kept
      the cached body available to the WebDyne PAGI request adapter and
      avoided crossing localized environment scopes during await. Added
      repeated-request regression coverage for the former Future panic.

    * Added documentation and WebDyne authoring guidance for start_html
      dependencies, PAGI parameters, SSE/WebSocket handlers, HTMX fragments,
      and the required hx-vals="js:{ ... }" syntax when supplying values from
      PSP pages.

    * Added release-board and pizza-order SSE/HTMX demonstration pages,
      including WebDyne-rendered fragments, status refreshes, and PAGI
      handler examples. Kept these developer demos and scratch material out
      of distribution manifests.

3.020 2026-08-20

    * Changed <api> route pattern semantics so patterns are relative to the
      discovered API PSP file path. For example, api.psp owning
      /api/user/42 now uses pattern="/user/:id" rather than
      pattern="/api/user/:id". This is a breaking change for existing
      <api> pages.

    * Updated PSGI and PAGI API fallback dispatch to strip the full API PSP
      mount path from PATH_INFO before passing requests to Router::Simple,
      keeping API route declarations independent of document-root location.

    * Updated API examples, release examples, tests, and local authoring
      guidance to use the new suffix-only <api pattern> convention.

    * Documented the WebDyne 3.020 <api> pattern breaking change in the XML
      documentation and tag reference.

3.013 2026-08-16

    * Normalized generated no_* wrapper options to numeric booleans so
      --dump_opt output is stable across Perl and Data::Dumper versions.

    * Made the webdyne.apache wrapper tests less sensitive to whitespace in
      Apache::TestRunPerl argument dumps and avoided macOS APXS probing by
      using a fake test apxs helper.

    * Improved PAGI smoke-test diagnostics by allowing PAGI::Test::Client
      application exceptions to surface in t/14-pagi.t instead of comparing
      only against a generic Internal Server Error response.

    * Added PAGI::Tools to the webdyne.pagi wrapper test prerequisite gate,
      matching the wrapper's runtime check and avoiding noisy failures on
      partial PAGI installations.

3.012 2026-08-10

    * Disabled the redundant webdyne.apache ulimit probe, avoiding noisy
      stderr on restricted CPAN smoke hosts where raising the core-file
      ulimit is not permitted.

    * Guarded developer-only doc/example scans in the generated Makefile so
      CPAN install and smoke-test runs remain quiet when the documentation
      source tree is not shipped in the distribution tarball.

3.011 2026-08-07

    * Extended wdrender --quiet/--silent to suppress advisory warnings about
      missing optional HTML::Tidy5 or syntax-highlighting modules while
      leaving rendering behaviour unchanged.

    * Updated wdrender regression coverage so --header output remains clean
      on machines without libtidy-devel and HTML::Tidy5 installed.

    * Made wdrender head-insert tests tolerant of harmless HTML/CSS
      whitespace differences while still checking that the default head
      insert is present or absent as requested.

3.010 2026-08-07

    * Fixed duplicate response header emission when WebDyne handlers set
      headers through the request object, avoiding malformed HTTP response
      headers in PSGI and other runtimes.

    * Fixed wdrender --header output so response headers are included
      consistently regardless of colour, line-number, pretty-print, or tidy
      settings.

    * Added wdrender regression coverage for duplicate Content-Type headers
      and for --header behaviour with colour/tidy output enabled and
      disabled.

    * Added explicit filename override support for WebDyne::PSGI and
      WebDyne::PAGI helper applications, allowing tools such as wdrender to
      render a fixed source file while still exercising PSGI or PAGI request
      handling.

    * Documented that the WebDyne::PSGI and WebDyne::PAGI filename option
      is an application-level source-file override and always wins over
      normal request-path filename derivation.

    * Propagated wdrender --no-head-insert/--head-insert handling through
      PSGI, PAGI, and temporary Apache/mod_perl render paths.

    * Simplified wdrender test-file routing for PSGI and PAGI helper modes
      by passing an explicit filename override instead of depending on
      request path rewriting.

3.009 2026-08-06

    * Added style_prepend/style_append and script_prepend/script_append
      pseudo attributes for <start_html>, allowing pages to add resources
      around configured WEBDYNE_START_HTML_PARAM defaults without replacing
      them.

    * Clarified <start_html> default-attribute override behaviour: page
      attributes replace matching WEBDYNE_START_HTML_PARAM values, while the
      new prepend/append variants preserve and extend configured style/script
      resources.

    * Documented <start_html> resource ordering for linked styles versus
      include_style content, and external scripts versus include_script
      content.

    * Made PSGI and PAGI wrapper configuration loading consistent by loading
      DOCUMENT_ROOT/.webdyne.conf.pl when the app is built, including when
      webdyne.psgi or webdyne.pagi is loaded by an external server.

    * Clarified root .webdyne.conf.pl loading versus per-request directory
      .webdyne.conf.pl handling, where only WEBDYNE_DIR_CONFIG is read from
      PSP-directory config files.

    * Added regression coverage for <start_html> style/script extension
      attributes and PSGI/PAGI external-loader root configuration loading.

3.008 2026-08-04

    * Added REST-style <api> route discovery and PATH_INFO mapping to
      WebDyne::PAGI, bringing PAGI API support in line with PSGI.

    * Added per-application API filename caches for PSGI and PAGI. API
      filename or route-structure changes may require a server restart.

    * Ensured PAGI emits a valid empty HTTP response when an API document
      produces no body, avoiding PAGI lint errors.

    * Clarified that Apache mod_perl does not provide automatic extensionless
      API route discovery without additional Apache rewrite or routing rules.

    * Added integration coverage for PSGI and PAGI API routing, caching,
      normal PSP requests, and 404 handling.

    * Fixed labelled <textfield> rendering so label-wrapped text inputs
      retain the correct HTML input type.

    * Added default/defaults handling for grouped form controls and popup
      menus, aligning generated form state with the documented attributes.

    * Added labelled textfield render fixtures and included them in the
      distribution manifest.

    * Updated the XML and generated Markdown documentation for the latest
      API, form-control, and demo example behaviour.

3.005 2026-08-02

    Major Version 3 release.

    * Added PAGI runtime support through WebDyne::PAGI and the
      webdyne.pagi wrapper, including HTTP, server-sent event, WebSocket,
      and lifespan request handling.

    * Added a common request abstraction for standalone, Apache/mod_perl,
      PSGI, and PAGI execution environments.

    * Refactored PSGI support into WebDyne::PSGI and expanded runtime
      handling for document roots, default documents, directory indexes,
      static files, and API routes.

    * Added webdyne.apache for temporary local Apache/mod_perl execution
      without requiring a permanent system Apache configuration.

    * Expanded wdapacheinit to support broader Apache installations,
      APXS discovery, installation and uninstall workflows, dry-run
      operation, and platform-specific configuration layouts.

    * Expanded wdrender to exercise multiple request backends, including
      fake, PSGI, PAGI, and mod_perl, with support for request methods,
      headers, parameters, response inspection, and comparison testing.

    * Added test-file modes to command-line compilation and rendering
      utilities.

    * Added a bundled default stylesheet for generated WebDyne pages and
      improved the appearance of default directory index output.

    * Added Docker runtime selection between PSGI and PAGI, with
      environment-variable tuning for server workers, timeouts, backlog,
      connection limits, and request body sizes.

    * Improved request and static-file safety, including path traversal,
      upload, multipart, error handling, and binary response coverage.

    * Reworked the documentation into a DocBook/MkDocs build with
      generated utility and module reference pages.

    * Added extensive examples and expanded automated test coverage for
      runtime backends, wrappers, static handling, APIs, SSE, WebSockets,
      and command-line utilities.

    * Removed the old WebDyne::CGI::PSGI adapter in favour of the new
      request and runtime abstraction.

2.021 2025-11-07

    * Added multi-line <start_html> attributes for scripts, styles, and
      related inclusions.

    * Prevented WebDyne substitution inside executable JavaScript blocks.

    * Added default viewport metadata and expanded head inclusion support,
      including array-valued includes.

    * Added Alpine/Vue attribute compatibility handling.

2.018 2025-10-29

    * Added the <htmx> tag for request-aware HTML fragment rendering.

    * Made directory indexes and static files available by default through
      the PSGI wrapper.

    * Improved HTML tree handling, constant importing, and error reporting.

2.017 2025-10-27

    * Added the <api> tag for lightweight JSON API responses using
      Router::Simple path matching.

2.015 2025-10-22

    * Added the wdlint utility for checking Perl syntax in __PERL__
      sections of PSP files.

    * Added the default PSGI directory index page and --index support.

2.014 2025-10-18

    * Replaced the CGI.pm-based HTML generation path with CGI::Simple and
      WebDyne::HTML::Tiny.

    * Refactored compilation and evaluation handling around the new HTML
      generation backend.

    * Added the JSON tag, alternate div-based WebDyne syntax,
      application/perl script blocks, and expanded HTML5 tag handling.

    * Added PSGI/Plack support to the main WebDyne distribution, including
      command-line document-root and default-document selection.

    * Added exported WebDyne::html() and WebDyne::html_sr() functions for
      standalone PSP rendering.

    * Added WebDyne::Template to the core distribution and added PSGI
      static-file serving through --static.

    * Added WEBDYNE_HEAD_INSERT for injecting common content into generated
      document heads.

    * Added Docker build files and container-oriented development support,
      including automatic dependency installation from a mounted cpanfile.
