Repository navigation
Add Head for Blade and Inertia metadata management - #683
Conversation
Allow packages to inspect the prepared exception response without replacing the application response callback. Invoke boot-registered observers after request-local response callbacks and before respondUsing, ignoring observer return values. Expose beforeResponding through exception configuration and the facade, document its worker lifetime, and cover ordering, response identity, arguments, and ignored return values in the handler tests. This lets metadata integrations observe the actual error status before an Inertia error page renders. Validation: formatting and source/types analysis passed; FoundationExceptionsHandlerTest passed with 78 tests and 230 assertions. The complete framework run had no behavioral failures; its sole facade metadata failure was corrected and verified separately.
Read the optional response exception through null coalescing before rethrowing it. Plain Symfony responses have no exception property, so invalid JSON previously raised an undefined-property error instead of the intended assertion failure. Keep stored exception identity and the existing response proxy behavior unchanged. Add an exact-message regression alongside the stored-exception coverage. Validation: TestResponseTest passed with 259 tests and 1,030 assertions; formatting and source/types analysis passed.
Port Laravel Head metadata builders, routing macros, structured data, facades, and rendering into the optional hypervel/head split package. Keep request data scoped and replicable while reusing worker-safe services and bounded metadata caches. Add boot-registered runtime defaults, error, and canonical-origin resolvers for request-specific metadata. Preserve eager upstream configuration, isolate copied schemas, and retain lazy Inertia sharing and partial reload behavior. Decorate SSR responses without mutating their readonly contents or changing the JavaScript protocol, and forward gateway capabilities. Correct canonical query and fragment handling, independent Open Graph fallback media, literal zero metadata, manifest replacement, title ownership, and shared schema-factory lookup. Capture actual exception response status before final customization. Wire split and development metadata, optional test cleanup, editor signatures, generated facade metadata, and PHPStan macro support using public reflection APIs. Validation: formatting and complete source/types analysis passed, including routing and facade fixtures. Head passed 180 tests and 640 assertions; facade metadata checks passed 2 tests and 16,228 assertions. Package-mode and dogfood checks passed. The initial full framework run completed with one facade metadata failure, subsequently fixed and verified by focused checks.
Convert every applicable upstream Pest case to PHPUnit while preserving the upstream layout and fixture coverage. Record the intentional Livewire exclusion and use the shared Hypervel test lifecycle for static cleanup. Add focused coverage for concurrent requests, copied contexts, mutable builder lifetimes, lazy runtime resolvers, canonical origins, independent media fallback, manifest ownership, schema factories, and literal zero values. Exercise optional provider discovery, early handler and kernel resolution, actual exception status, SSR capability forwarding, custom props, partial reloads, and both Blade SSR ordering paths. Validation: all 180 Head cases passed with 640 assertions. Test files were checked during porting, and the complete framework run exposed no Head failures. No external services or new test framework are required for these tests.
Port the upstream Head guide with Hypervel installation, routing, Blade, structured data, and Inertia setup. Add request-specific defaults, error metadata, canonical origins, worker-lifetime guidance, context copying, and PHPStan integration using generic team examples. Explain serverHead setup for client and SSR entry points, static globals, partial reload behavior, and application-owned settings retrieval. Add Head in the package navigation, link from Inertia, and describe the worker configuration adaptation in the Laravel porting guide. Retain the completed implementation plan as the design reference. Documentation and comments were reviewed against the source, upstream coverage, and supported integration paths; diff whitespace checks passed.
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@coderabbitai review |
|
|
@cubic-dev-ai review |
@binaryfire cubic can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 123,074 of the 120,000 allowed lines of code this month. Reviews resume on 10 November 2026 (in 21 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews. To help optimise your usage, you can tune cubic to get the most out of your usage limits:
|
PR Summary by QodoAdd worker-safe Head metadata for Blade and Inertia
AI Description
Diagram
High-Level Assessment
Files changed (119)
|
Code Review by Qodo
1. Self-rendered error pages miss error metadata
|
Use the supplied magic setter value regardless of its argument name, preserving explicit null instead of replacing it with true. Infer schema types from the concrete class name without inserting spaces or inheriting a parent type. Restore numeric array keys to string labels in bulk breadcrumb and FAQ helpers. Descend into nested SchemaObject values during validation while preserving raw schema serialization and reference behavior. Extend schema regressions for named and null values, multiword class names, numeric labels, and invalid nested objects. Formatting, source and type analysis, and the Head suite pass.
Recognize HTTP and HTTPS schemes without regard to case and keep protocol-relative URLs on their explicit host. Resolve their scheme from forced HTTPS or the current request, retaining the protocol-relative form when neither applies. Keep origin callbacks limited to automatic and relative page URLs. Existing path, query, fragment, and trailing-slash normalization remains intact. Cover uppercase schemes and protocol-relative URLs with and without a request. Canonical tests, formatting, and static analysis pass.
Include the attribute in the ownership identity when a meta tag explicitly uses a different name or property attribute from the inferred default. This prevents Inertia deduplication from dropping distinct tags with the same key. Retain semantic ownership keys and aliases for normal tags so generic metadata continues to override dedicated builders. Media-specific tags keep their full identity. Add focused cases for description, Open Graph, and aliased theme metadata. Meta rendering tests, the Head suite, and static analysis pass.
Return an already registered custom builder before checking route-attribute conflicts. Repeated registration no longer conflicts with its own keys or invalidates the cached attribute map. Continue rejecting built-in builders, invalid extension classes, and keys owned by another builder. Extend the existing route integration regression to register the same builder twice and render its metadata. The focused extension tests, Head suite, formatting, and static analysis pass.
Replace pagination relations as one complete set so moving to a last or single page cannot retain stale links. Accept cursor paginator contracts alongside ordinary paginators, regenerate facade metadata, and stop advertising pagination as a route attribute. Accept bare feed URLs and lists as untitled RSS feeds while retaining titled maps and structured definitions. Treat omitted or null structured titles as untitled, omit empty title attributes, and continue rejecting other non-string titles. Reject ambiguous URL-to-string resource-hint maps through the existing route validation path instead of rendering the value as a URL. Preserve supported scalar and structured list inputs. Add focused rendering and route regressions for replacement, cursors, feed forms, and invalid inputs. Affected tests, the Head suite, facade checks, formatting, and source and type analysis pass.
Register lazy Head sharing before global middleware so Inertia error responses include metadata when maintenance handling rejects the request. Recognize registered Inertia provider subclasses while keeping discovery-disabled applications free of the integration. Register exception status callbacks only when the bound handler supports each hook. Use the exception handler contract and callable checks so contract-only handlers and forwarding fakes remain supported without adding runtime lookup machinery. Cover maintenance errors, a custom Inertia provider with a custom prop, and a handler without rendering hooks. Existing tests retain early kernel and handler resolution, SSR, and partial-reload coverage. Focused tests, the Head suite, formatting, and static analysis pass.
Explain complete pagination replacement, ordinary and cursor paginator support, accepted feed route forms, and omission of an empty fluent feed title. Clarify that automatic exception status capture uses the framework exception handler. Keep correctness fixes and additive support in the feature guide without adding compatibility warnings to the Laravel porting guide. Update the active port plan to reflect the completed correction design and the remaining release checkpoint.
Resolve an omitted og:url from the existing canonical builder when Open Graph metadata is present. Preserve explicit Open Graph URLs and leave output unchanged when no canonical or Open Graph builder exists. Port the implementation and regression cases from laravel/head#14 while retaining null and empty-string checks. Also port the split-defaults regression from laravel/head#16; the existing per-media provenance flags already provide the fix. The Head suite, source and type analysis, facade checks, and formatting pass. The change adds no cross-request state or cache.
Port the Event location, image, performer, status, and attendance-mode helpers from laravel/head#15, together with Place and the two schema.org enums. Preserve the proposed signatures and string-location conversion to a named Place, following existing typed schema conventions. Register Place in the schema factory and regenerate its facade metadata. All schema builders continue to support raw values through set(), and nested values use the existing coercion path. Copy and convert every upstream Event schema test to PHPUnit, covering rendering, location conversion, enums, related schemas, and factory resolution. Formatting, source and type analysis, the Head suite, and facade checks pass.
Extend the Open Graph fallback guidance to include the canonical URL and record the public output difference in the package README. Document Event and Place authoring with a structured address, status and attendance enums, string-location behavior, and raw schema values through set(). Add the Events navigation entry and Place factory to the feature guide. Record the agreed upstream additions and remaining PR workflow in the active port plan. Keep upstream source references there rather than in the package README.
This adds
hypervel/head, a port of Laravel Head for managing document titles, metadata, canonical URLs, social cards, links, and structured data from PHP. It supports Blade and optional Inertia integration, including SSR.The fluent builders, route macros, named arguments, schema APIs, and eager configuration methods follow upstream. The main adaptation is state ownership: Hypervel serves concurrent requests in long-lived workers, so metadata for one page must never become another request's defaults.
Request state and runtime configuration
Page data and error status are coroutine-scoped. Copying a coroutine context copies its Head data and schema objects, so child work can change its metadata without changing the parent. Mutable builders and schema objects resolve as fresh instances; managers, renderers, registries, and factories reuse worker-safe services.
Three optional hooks let applications configure request-dependent metadata during provider boot:
Head::resolveDefaultsUsing()builds defaults from the current request or application context.Head::resolveErrorsUsing()builds error metadata from the actual response status.Head::resolveCanonicalOriginUsing()supplies the preferred origin for automatic and relative canonical URLs, useful when a site has aliases or custom domains.These hooks preserve the existing eager
defaults(),errors(), andinertiaGlobals()APIs. Runtime values are resolved afresh, with precedence from defaults through route groups, route metadata, page data, and error metadata. Head does not fetch settings or add database queries. Applications can reuse settings they have already loaded.flush()clears the current coroutine's page data and status when generating independent pages sequentially. Boot configuration remains intact. Public configuration methods explain their worker lifetime, and the guide uses team settings to show safe runtime configuration.Blade and Inertia
Blade receives the
@headdirective. Inertia integration is enabled only when its provider is registered; having its classes available does not enable it. The package declares its own dependencies and discovery metadata for standalone installation.Head remains a lazy shared prop, preserving partial reload behavior. It is registered before global middleware so early error responses also receive metadata. Registered Inertia provider subclasses enable the integration too. Initial documents and subsequent Inertia visits use stable ownership keys. The SSR decorator removes duplicate page-managed tags while preserving other SSR tags and the rendered body. It creates a new immutable response instead of modifying Hypervel's readonly SSR result, and forwards request configuration, disabling, path exclusions, and health checks to the wrapped gateway.
There is no Inertia JavaScript protocol change. The guide covers
serverHeadconfiguration in both client and SSR entry points, custom prop names, static globals, and moving overlapping client metadata into Head. Livewire integration is intentionally omitted; Blade and Inertia are the supported rendering paths.Rendering fixes
"0"titles and descriptions survive rendering and array conversion, including Open Graph and Twitter fallbacks.titlehave separate Inertia ownership, so both survive deduplication.nameandpropertyattributes keep separate Inertia identities, while normal generic tags retain their ability to override dedicated builders.The port also includes the canonical-to-Open-Graph URL fallback and Event/Place helpers proposed upstream. An unset
og:urlfollows the resolved canonical when Open Graph metadata is present, with explicit URLs taking precedence. Event builders gain location, image, performer, status and attendance-mode helpers, plus a Place builder and schema.org enums. Their typed conventions follow the existing schema builders;set()remains available for raw schema values.The Open Graph fix replaces its single protected default-media flag with per-type flags. Public fluent methods are unchanged. An SSR gateway without health-check support now reports that unsupported capability instead of incorrectly reporting that the server is down.
Shared framework support
The exception handler gains
beforeResponding(), exposed through exception configuration and the facade. It observes the prepared response before the application's final response customization without replacing that callback. Head uses it to capture the actual status before an Inertia error page renders, including exceptions with embedded responses or custom renderers. The early status callback remains for ordinary Blade error views. Head registers these hooks only when the bound handler supports them, preserving custom exception handlers.TestResponsealso correctly reports invalid JSON from a plain Symfony response when no stored exception exists. Stored exceptions are still rethrown unchanged.Performance and tooling
Route-attribute lookup and inferred schema types are cached by registered builder or loaded class, keeping worker memory bounded. Request values and rendered output are not cached across requests. JSON-LD is encoded once per render, and non-cryptographic content identifiers use deterministic
xxh128hashes.Editor declarations and a package PHPStan extension cover every
withHeadrouting surface without loading runtime macros or replacing existing routing types. The extension follows the framework's existing layout and uses public PHPStan reflection APIs. Generated facade metadata retains rich callback and generic types through the existing mixin support. Optional static cleanup integrates with the framework test lifecycle.Validation
Applicable upstream tests are ported to PHPUnit, with additional coverage for coroutine isolation, context copying, runtime configuration, rendering fixes, exception responses, and SSR integration. Formatting, source and type analysis, Head tests, facade checks, package-mode tests, and dogfood checks pass.
The full framework suite was also exercised, with affected checks repeated after corrections. External-service tests without configured services were skipped.
The upstream Head guide is included and adapted for Hypervel, with package navigation, an Inertia link, and guidance for porting worker-shared configuration.
Note
Add Head package for Blade and Inertia head metadata management
hypervel/headpackage with aHeadfacade, service provider, and Blade@headdirectiveSchemaFactoryand built-in schema types like Article, Event, Product, and FAQwithHeadmacro on Router, Route, RouteRegistrar, and resource registrations, layered as defaults, route, page, and error definitionsdata-inertiakeys, and removes page-managed elements from SSR responses throughUniqueHeadGatewaybeforeRespondinghooks in the exception handler; includes PHPStan extension support and full feature test coveragebeforeRespondingcallbacks before final response customization (seeHandler::finalizeRenderedResponse), and Inertia SSR responses no longer include page-managed head elementsMacroscope summarized 54414c4.