Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
952d311
Enhance contextual container construction
binaryfire Sep 1, 2026
768c215
Extract reusable unknown-field validation
binaryfire Sep 1, 2026
f3aff0e
Harden compiled validation rule execution
binaryfire Sep 1, 2026
23fb3aa
Add the Hypervel Data component foundation
binaryfire Sep 1, 2026
0991af6
Compile immutable Data declaration metadata
binaryfire Sep 1, 2026
d656315
Add the Data validation system
binaryfire Sep 1, 2026
b0224d8
Implement fixed Data construction
binaryfire Sep 1, 2026
441b021
Implement Data transformation and partials
binaryfire Sep 1, 2026
139cdb0
Add a reproducible Data benchmark harness
binaryfire Sep 1, 2026
a83abd2
Track the laravel-data upstream
binaryfire Sep 1, 2026
c7a5c7d
Record first-party TypeScript transformation work
binaryfire Sep 1, 2026
ee94c1f
Plan the first-party Hypervel Data package
binaryfire Sep 1, 2026
c0023af
Merge branch '0.4' into feature/data-package
binaryfire Sep 1, 2026
f694d14
Merge branch '0.4' into feature/data-package
binaryfire Sep 2, 2026
8d6783c
Refine Data declaration metadata
binaryfire Sep 2, 2026
c813e50
Preserve prepared validation graphs for Precognition
binaryfire Sep 2, 2026
9c1ad51
Complete Data validation compilation
binaryfire Sep 2, 2026
f190862
Complete fixed Data construction
binaryfire Sep 2, 2026
f057da5
Complete Data transformation and lazy values
binaryfire Sep 2, 2026
9b1023e
Add typed Data collections and adapters
binaryfire Sep 2, 2026
93e3c12
Move FormRequest Data casts into the package
binaryfire Sep 2, 2026
ad02deb
Add optional Inertia lazy values
binaryfire Sep 2, 2026
b543d6c
Add the WithData source concern
binaryfire Sep 2, 2026
d585bdb
Finish Data package tooling and boot integration
binaryfire Sep 2, 2026
73efd30
Verify Saloon Data interoperability
binaryfire Sep 2, 2026
2454bba
Remove the superseded Support DataObject
binaryfire Sep 2, 2026
b98eed4
Expand the Data performance harness
binaryfire Sep 2, 2026
c7a663f
Describe the Data component contract
binaryfire Sep 2, 2026
577f9eb
Document first-party Data objects
binaryfire Sep 2, 2026
91f7955
Finalize the Hypervel Data implementation plan
binaryfire Sep 2, 2026
ab11366
Merge branch '0.4' into feature/data-package
binaryfire Sep 2, 2026
454ecf8
Optimize Data construction and transformation hot paths
binaryfire Sep 3, 2026
75f6794
Reuse immutable contexts for Data persistence
binaryfire Sep 3, 2026
f6359b0
Modernize Data date cast exception assertions
binaryfire Sep 3, 2026
60d1526
Expand Data transformation benchmarks
binaryfire Sep 3, 2026
3a1b775
Document variadic Data factories and package credits
binaryfire Sep 3, 2026
b743805
Complete the Hypervel Data package plan
binaryfire Sep 3, 2026
42d85d8
Refine Data documentation prose
binaryfire Sep 3, 2026
8dd3275
Merge remote-tracking branch 'origin/0.4' into feature/data-package
binaryfire Sep 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
->exclude('src/testbench/workbench/storage')
->exclude('vendor')
->notPath('#^bin/#')
->notPath('tests/Data/Fixtures/PhpDocTypeContext.php')
->notPath('tests/Foundation/Fixtures/fake-compiled-view.php')
->name('hypervel-test-profile')
->in(__DIR__)
Expand Down
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"Hypervel\\Context\\": "src/context/src/",
"Hypervel\\Coordinator\\": "src/coordinator/src/",
"Hypervel\\Cookie\\": "src/cookie/src/",
"Hypervel\\Data\\": "src/data/src/",
"Hypervel\\Database\\": "src/database/src/",
"Hypervel\\Concurrency\\": "src/concurrency/src/",
"Hypervel\\Coroutine\\": "src/coroutine/src/",
Expand Down Expand Up @@ -242,6 +243,7 @@
"hypervel/coordinator": "self.version",
"hypervel/cookie": "self.version",
"hypervel/coroutine": "self.version",
"hypervel/data": "self.version",
"hypervel/database": "self.version",
"hypervel/di": "self.version",
"hypervel/docs": "self.version",
Expand Down Expand Up @@ -349,6 +351,7 @@
"Hypervel\\Concurrency\\ConcurrencyServiceProvider",
"Hypervel\\Console\\ConsoleServiceProvider",
"Hypervel\\Cookie\\CookieServiceProvider",
"Hypervel\\Data\\DataServiceProvider",
"Hypervel\\Database\\DatabaseServiceProvider",
"Hypervel\\Encryption\\EncryptionServiceProvider",
"Hypervel\\Engine\\EngineServiceProvider",
Expand Down
994 changes: 994 additions & 0 deletions docs/plans/2026-08-30-0349-hypervel-data-package.md

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions docs/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
- Publish reproducible Hypervel 0.4 benchmarks on a dedicated documentation page before linking them from the introduction. Record the framework, PHP, Swoole, and dependency versions; use the same hardware and load-generation conditions for every runtime; publish the benchmark applications and configuration; and include the raw results, collection date, and limitations. Do not reuse the Hypervel 0.3 results as current data. Once the page is published, add it to `src/docs/documentation.md` and link to it from the introduction.
- When the Hypervel 0.4 documentation is published, replace the versioned GitHub source links in both the `hypervel/components` and `hypervel/hypervel` READMEs with the corresponding hypervel.org documentation URLs. The documentation's `{{version}}` cross-links only resolve on the published site, so readers who follow the current links land on pages whose internal navigation is broken.

## TypeScript

- Port `spatie/typescript-transformer` as a general first-party Hypervel package, then add an optional Hypervel Data adapter that recognizes data classes and their existing mapping, Optional, lazy, and collection metadata. Keep TypeScript generation outside `hypervel/data`: the transformer must also support ordinary PHP classes and enums without making runtime data construction depend on filesystem discovery or code generation.

## Redis

- Revisit the rate limiter's portable fixed-window Lua script once native bounded increment-with-expiry support is mature across the supported Redis-compatible ecosystem. Redis 8.8's `INCREX` can atomically reject increments above an upper bound and set expiry only for a new window, but Redis 8.6 and Valkey 9 do not provide it, [Valkey #3253](https://github.com/valkey-io/valkey/pull/3253) is still an open related proposal rather than equivalent `INCREX` support, and phpredis 6.3 exposes no typed `INCREX` method (while `rawCommand()` bypasses key prefixing and has different Redis Cluster routing semantics). Re-benchmark and switch only when Redis and Valkey expose equivalent semantics and phpredis has prefix-aware, cluster-aware client support; keep the corresponding focused `@TODO` beside the Lua script until then.
Expand Down
6 changes: 3 additions & 3 deletions docs/upstream-sync/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This guide governs how Hypervel stays current with upstream packages (Laravel fr

When the user asks to run an upstream sync, sync session, upstream review, or similar. This guide **overrides** the `/hypervel-pr` skill's default first-time porting flow — follow the sync workflow below instead.

For the mechanics of porting code (namespace changes, container conversion, service provider migration, listener conversion, type modernization, test porting), `docs/ai/porting.md` is authoritative. Re-read it before writing any code. This guide only covers the *surrounding* workflow — discovery, classification, commit structure, PR structure, state tracking.
For the mechanics of porting code (namespace changes, container conversion, service provider migration, listener conversion, type modernization, test porting), the `Porting Packages` section of `AGENTS.md` is authoritative. Re-read it before writing any code. This guide only covers the *surrounding* workflow — discovery, classification, commit structure, PR structure, state tracking.

## Files in this directory

Expand All @@ -20,7 +20,7 @@ Deliberate, lasting differences from Laravel belong in the affected package READ
- **Releases are walked one at a time, oldest to newest.** Never merge multiple releases' PRs into one flat list. Finish release N before opening release N+1.
- **Never auto-decide a PR is skippable.** Propose classification, explain reasoning, wait for user approval. The user decides scope; you propose.
- **One commit per upstream PR.** Separation is cheap; bad reverts are expensive.
- **Stop-and-ask rules from `porting.md` apply in full** — source bugs, coroutine/container divergence, unusual dependencies, anything surprising.
- **Stop-and-ask rules from `AGENTS.md` apply in full** — source bugs, coroutine/container divergence, unusual dependencies, anything surprising.

## Session workflow

Expand Down Expand Up @@ -72,7 +72,7 @@ Propose a classification and reasoning:

Wait for user approval on every classification. Never silently skip.

If porting: follow `docs/ai/porting.md` for the mechanics. Commit with:
If porting: follow the `Porting Packages` section of `AGENTS.md` for the mechanics. Commit with:

```
Port <repo-slug>#<pr-number>: <original PR title>
Expand Down
6 changes: 6 additions & 0 deletions docs/upstream-sync/sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ orchestral/testbench:
sync_date: null
notes: Composer package is `orchestra/testbench` (different from gh slug).

spatie/laravel-data:
repo_url: https://github.com/spatie/laravel-data
release: 4.23.0
sync_date: 2026-08-30
notes: Initial port also reviewed main through ce296f22 and the v5 draft at ed630ee1.

spatie/laravel-permission:
repo_url: https://github.com/spatie/laravel-permission
release: null
Expand Down
4 changes: 4 additions & 0 deletions src/container/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Documentation: https://hypervel.org/docs/container

Hypervel supports Laravel's named container APIs, but not container ArrayAccess or dynamic service properties. Use `make()` / `get()`, `bound()` / `has()`, `bind()`, and `instance()`. For temporary instance overrides, use `forgetInstance()` to restore the original binding. Hypervel does not expose arbitrary binding removal because registrations are worker-wide boot-time state.

A contextual attribute's resolved value is authoritative, including `null`. Unlike Laravel, Hypervel does not fall through to class or primitive resolution, contextual bindings, or declared defaults after a contextual resolver returns `null`.

`#[BindWhen]` conditions must depend only on boot-stable state. The first matching condition becomes a normal worker-lifetime binding; unmatched conditions remain eligible for reevaluation on later resolutions.

Hypervel does not expose Laravel's protected per-parameter override helpers. Container subclasses that customize parameter override resolution should override `resolveRecipeParameters()`, which receives the current coroutine's resolution state and resolves the complete parameter list in one pass.

Ported from: https://github.com/laravel/framework/tree/13.x/src/Illuminate/Container
1 change: 1 addition & 0 deletions src/container/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"php": "^8.4",
"ext-swoole": "^6.2.2",
"psr/container": "^2.0.1",
"hypervel/collections": "^0.4",
"hypervel/context": "^0.4",
"hypervel/contracts": "^0.4",
"hypervel/reflection": "^0.4"
Expand Down
19 changes: 14 additions & 5 deletions src/container/src/Attributes/Authenticated.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@
namespace Hypervel\Container\Attributes;

use Attribute;
use Hypervel\Contracts\Auth\Authenticatable;
use Hypervel\Container\Attributes\Concerns\ExtractsPropertyValue;
use Hypervel\Contracts\Container\Container;
use Hypervel\Contracts\Container\ExecutionScopedAttribute;
use UnitEnum;

#[Attribute(Attribute::TARGET_PARAMETER)]
class Authenticated implements ExecutionScopedAttribute
{
use ExtractsPropertyValue;

/**
* Create a new class instance.
*
* Property paths use data_get() and may invoke object accessors or lazy-load
* Eloquent relationships.
*/
public function __construct(public UnitEnum|string|null $guard = null)
{
public function __construct(
public UnitEnum|string|null $guard = null,
public ?string $property = null,
) {
}

/**
Expand All @@ -31,8 +38,10 @@ public function isExecutionScoped(): bool
/**
* Resolve the currently authenticated user.
*/
public static function resolve(self $attribute, Container $container): ?Authenticatable
public static function resolve(self $attribute, Container $container): mixed
{
return call_user_func($container->make('auth')->userResolver(), $attribute->guard);
$value = call_user_func($container->make('auth')->userResolver(), $attribute->guard);

return $attribute->extractPropertyValue($value, $attribute->property);
}
}
43 changes: 43 additions & 0 deletions src/container/src/Attributes/BindWhen.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace Hypervel\Container\Attributes;

use Attribute;
use Closure;

/**
* Define a binding selected by a boot-stable condition.
*
* A matching condition becomes a normal worker-lifetime container binding.
*/
#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)]
class BindWhen
{
/**
* The concrete class to bind to.
*
* @var class-string
*/
public string $concrete;

/**
* The condition that determines if the binding should apply.
*
* @var Closure(\Hypervel\Contracts\Container\Container): bool
*/
public Closure $condition;

/**
* Create a new attribute instance.
*
* @param class-string $concrete
* @param Closure(\Hypervel\Contracts\Container\Container): bool $condition
*/
public function __construct(string $concrete, Closure $condition)
{
$this->concrete = $concrete;
$this->condition = $condition;
}
}
33 changes: 33 additions & 0 deletions src/container/src/Attributes/Concerns/ExtractsPropertyValue.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Hypervel\Container\Attributes\Concerns;

use Hypervel\Contracts\Container\BindingResolutionException;

trait ExtractsPropertyValue
{
/**
* Extract a property path from a contextual value.
*
* @throws BindingResolutionException
*/
protected function extractPropertyValue(mixed $value, ?string $property): mixed
{
if ($property === null) {
return $value;
}

if (is_scalar($value)) {
throw new BindingResolutionException(sprintf(
'Cannot extract property path [%s] from scalar [%s] resolved by [%s].',
$property,
get_debug_type($value),
static::class,
));
}

return data_get($value, $property);
}
}
37 changes: 37 additions & 0 deletions src/container/src/Attributes/RequestAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Hypervel\Container\Attributes;

use Attribute;
use Hypervel\Contracts\Container\Container;
use Hypervel\Contracts\Container\ExecutionScopedAttribute;
use ReflectionParameter;

#[Attribute(Attribute::TARGET_PARAMETER)]
class RequestAttribute implements ExecutionScopedAttribute
{
/**
* Create a new class instance.
*/
public function __construct(public string $parameter)
{
}

/**
* Determine whether the resolved value belongs to the current execution.
*/
public function isExecutionScoped(): bool
{
return true;
}

/**
* Resolve the request attribute.
*/
public static function resolve(self $attribute, Container $container, ReflectionParameter $parameter): mixed
{
return $container->make('request')->attributes->get($attribute->parameter);
}
}
16 changes: 13 additions & 3 deletions src/container/src/Attributes/RouteParameter.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,26 @@
namespace Hypervel\Container\Attributes;

use Attribute;
use Hypervel\Container\Attributes\Concerns\ExtractsPropertyValue;
use Hypervel\Contracts\Container\Container;
use Hypervel\Contracts\Container\ExecutionScopedAttribute;
use ReflectionParameter;

#[Attribute(Attribute::TARGET_PARAMETER)]
class RouteParameter implements ExecutionScopedAttribute
{
use ExtractsPropertyValue;

/**
* Create a new class instance.
*
* Property paths use data_get() and may invoke object accessors or lazy-load
* Eloquent relationships.
*/
public function __construct(public ?string $parameter = null)
{
public function __construct(
public ?string $parameter = null,
public ?string $property = null,
) {
}

/**
Expand All @@ -32,6 +40,8 @@ public function isExecutionScoped(): bool
*/
public static function resolve(self $attribute, Container $container, ReflectionParameter $parameter): mixed
{
return $container->make('request')->route($attribute->parameter ?? $parameter->getName());
$value = $container->make('request')->route($attribute->parameter ?? $parameter->getName());

return $attribute->extractPropertyValue($value, $attribute->property);
}
}
Loading
Loading