Revision history for WebDyne 3.029 - 2026-09-11 * Read CGI cookies from the current request header, including absent headers, so PAGI sessions reuse their cookie and cannot inherit ambient process cookies. Preserve outgoing cookie construction and security flags. * Add an optional content_type override to redirect() for HTML, text and JSON responses, allowing applications to return SVG and other MIME types without a Worker-side header override. * Preserve binary and pre-encoded byte strings in PAGI responses. Continue UTF-8 encoding Perl character strings before sending them. * Encode Perl character responses at the PSGI and wdrender fake HTTP response boundaries. Recalculate Content-Length in bytes without changing existing byte bodies. The separate wdrender terminal wide- character print warning is unchanged. * Add the opt-in param_utf8(name) accessor for strict UTF-8 decoding of parameter value copies. Preserve scalar/list behaviour and original values, reject malformed UTF-8, and leave the existing param() API unchanged. * Update XML documentation and add regression coverage for request cookies, UTF-8 form values, explicit response MIME types, and Unicode and binary response bodies. 3.028 - 2026-09-08 * Add optional startup and shutdown coderefs to WebDyne::PAGI. Callbacks receive the application object and lifespan scope; returned Futures are awaited before acknowledgement. Exceptions and failed Futures produce the corresponding lifespan failure event. Missing callbacks preserve existing behaviour; shutdown callbacks run only when the server delivers shutdown. * Clear shared PAGI diagnostics before synchronous HTTP, SSE and WebSocket page setup, after request body buffering. Recovered errors no longer leak into later requests, while errors from the current request remain available to its error handler. * Add regression coverage for synchronous and asynchronous lifespan callbacks, callback and transport failures, and diagnostic isolation across sequential requests and interleaved HTTP/SSE body reads. 3.027 - 2026-09-07 * Use lazy load ("require") for modules only required at certain decision paths 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 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 , using the same dependency-loading and function-import behaviour as . 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 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 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 convention. * Documented the WebDyne 3.020 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 , allowing pages to add resources around configured WEBDYNE_START_HTML_PARAM defaults without replacing them. * Clarified 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 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 style/script extension attributes and PSGI/PAGI external-loader root configuration loading. 3.008 2026-08-04 * Added REST-style 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 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 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 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 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.