Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ffb3f0d
Port Inertia redirect callbacks, previous locations and big integers
binaryfire Oct 3, 2026
b319093
Add the --graceful option to inertia:stop-ssr
binaryfire Oct 3, 2026
3986dc0
Assert preserved big integers as plain integers in Inertia tests
binaryfire Oct 3, 2026
2619a31
Title the Inertia middleware test endpoint helper
binaryfire Oct 3, 2026
f6a7655
Track sweeps for test method titles and return types
binaryfire Oct 4, 2026
91709e4
Merge current 0.4 into the remaining framework batch
binaryfire Oct 8, 2026
582a2ab
Replace deprecated exception message expectations
binaryfire Oct 8, 2026
46cad23
Reconcile Slack Block Kit with upstream
binaryfire Oct 8, 2026
7bde916
Reconcile the Slack notification channel with upstream
binaryfire Oct 8, 2026
5369de3
Track relevant Hyperf runtime changes
binaryfire Oct 8, 2026
2ed8387
Merge current 0.4 into the Inertia and Slack branch
binaryfire Oct 10, 2026
f40df6c
Keep a test's own failure when its children reach the time limit
binaryfire Oct 10, 2026
750d3f0
Compute Fortify and Horizon configuration again in each worker
binaryfire Oct 10, 2026
ea02aa4
Let Telescope record cache events without rewriting store configuration
binaryfire Oct 10, 2026
fdba812
Pool FTP and SFTP disks so concurrent requests never share a connection
binaryfire Oct 10, 2026
a165804
Release filesystem pool connections after buffered reads
binaryfire Oct 10, 2026
83aaa6a
Build Inertia back redirects before storing the current location
binaryfire Oct 10, 2026
03a4a53
Report blocked Inertia SSR health checks as unhealthy
binaryfire Oct 10, 2026
93f8934
Cache class metadata for Inertia big-integer encoding
binaryfire Oct 10, 2026
2913864
Accept dependency-specific causes for malformed JWT dates
binaryfire Oct 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

## Testing

- Add the required title docblocks to the untitled non-test methods in `tests/`: about 8,400 methods in 1,600 files, mostly helpers, fixtures, and methods of anonymous classes in older tests. `AGENTS.md` requires a title on every method except `test*` methods, but most existing tests omit them, and agents follow the surrounding code over the written rule, so new tests keep reproducing the gap until review catches it. Make the change as one approved sweep (short imperative titles only), then add an automated check, such as a PHPStan rule, so the code and the rule cannot drift apart again. Decide whether the check also covers `src/`.
- Add native return types to the `test*` methods that lack them: about 5,600 methods in 490 files. `AGENTS.md` requires `: void` on test methods; a test that returns a value for `#[Depends]` takes its actual return type instead. As with method titles, untyped methods in existing files lead new tests to copy them, so make the change as one approved sweep and enforce it with the same automated check.
- Integrate the resolution of [PHPUnit #7039](https://github.com/sebastianbergmann/phpunit/issues/7039) into `RunTestsInCoroutine` once available; [PR #7040](https://github.com/sebastianbergmann/phpunit/pull/7040) proposes suspend/resume output buffering. Follow the accepted upstream design, including calling `parent::invokeTestMethod()` if capture is handled there. Add regression coverage for output expectations, flushed output and buffer cleanup; update the testing guidance and reassess output-related coroutine opt-outs.
- Lift the PHPUnit `13.3.*` pin in the root, Testbench and dogfood package manifests, and in the `hypervel/hypervel` application skeleton, once ParaTest supports PHPUnit 13.4. PHPUnit 13.4.0 made the internal `PhpHandler` constructor require an event emitter, and ParaTest 7.25.0 and Hypervel's `RunsInParallel` still construct it without one, so parallel runs fail before any test starts. When lifting the pin, pass the emitter to `PhpHandler` in `RunsInParallel`, as PHPUnit 13.4's own `Application` does.

Expand Down
49 changes: 47 additions & 2 deletions docs/upstream-sync/sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,10 @@ laravel/scout:

laravel/slack-notification-channel:
branch: 3.x
checked_through: null
checked_through: 7b7c3e220a4f7a45cd88d65069f28d4fb4b67281
last_reviewed_pr: null
sync_date: null
sync_date: '2026-10-08'
notes: Upstream src/ maps to src/slack-notification-channel/src and tests/ to tests/SlackNotificationChannel; the two tests/Slack notification fixtures live in Slack/Fixtures, and the feature tests' sendNotification and assertNotificationSent helpers live in Slack/TestCase. User documentation is the Slack Notifications section of src/docs/notifications.md, which also documents the webhook routes Laravel's docs omit. The Web API channel sends through the slack-notifications HTTP connection (SlackChannel::CONNECTION), so keep connection() when porting request changes. Feature tests fake Slack's API responses instead of calling Slack, and router tests register Mockery channel instances because determineChannel() returns typed channels. Horizon's LongWaitDetected builds both message types; run its test after message API changes.

laravel/telescope:
branch: 5.x
Expand Down Expand Up @@ -228,6 +229,50 @@ Sammyjo20/saloon-docs:
sync_date: '2026-10-07'
notes: Shared documentation for the unified src/saloon package and all four plugin entries above. Reconcile applicable core and plugin pages into the existing sections of the single src/docs/saloon.md rather than separate plugin guides, keeping Hypervel's additions and checking examples against current source, in Laravel-style prose matching the guide. The v3 branch includes v4 guidance. Installation commands, supported versions, upgrade guides, release notes, showcase, tutorials, the book and the third-party Lawman and SDK generator pages have no Hypervel equivalent; check them only for behavior the guide must still describe.

hyperf/engine:
branch: master
# Owner-selected history boundary before 2025-11-01, not a historical parity claim.
checked_through: 6595d2659ce7ebb940b8740a00ecd199128398f0
last_reviewed_pr: null
sync_date: null
notes: >-
Selective runtime tracking for Hypervel's independently maintained Engine;
review before hyperf/hyperf. Source maps to src/engine and interfaces to
src/contracts/src/Engine. Consult hyperf/engine-contract when an Engine change
depends on its contracts; it is not a separate tracking entry. Assess changes
for applicable correctness, security, coroutine isolation, blocking,
cancellation, resource cleanup, pooling, Swoole compatibility and performance
improvements. Verify applicability against current Hypervel source, adapt
useful changes and include relevant regression coverage. Preserve Hypervel's
architecture, Laravel-style APIs and enhancements; do not pursue Hyperf API
or full test-suite parity, restore removed Hyperf infrastructure or add Swow
support. HTTP server and response-emitter changes must be assessed against
src/http-server's Swoole bridges rather than restoring Engine's portability
layer. Follow affected consumers beyond these mappings when necessary.

hyperf/hyperf:
branch: master
# Owner-selected history boundary before 2025-11-01, not a historical parity claim.
checked_through: ded8b966ecf78590e8201a47a56c635f8df99e47
last_reviewed_pr: null
sync_date: null
notes: >-
Selective runtime tracking under the same applicability rules as hyperf/engine
above, not a framework merge target. Review the monorepo, not its subtree-split
mirrors. Upstream src/{context,coroutine,coordinator,server,signal,websocket-server,watcher}
map to the same Hypervel packages; pool maps to connection-pool, with shared
pooling issues also assessed against object-pool; framework bootstrap/events
and logging map to core; process maps to server-process; http-server and
http-message transport/lifecycle changes map to http-server's bridges; di AOP
and proxy generation map to di, not Hyperf's container; contract maps to the
corresponding runtime interfaces in contracts. Assess db-connection and
database driver changes against database's connection/pooling code, redis
against redis's connection/pooling code, grpc/grpc-client/grpc-server and
http2-client against grpc and Engine HTTP/2, and guzzle transport issues against
http and engine's different transports. These are applicability mappings,
not instructions to restore upstream implementations. Laravel remains the
primary API and implementation reference for Laravel-ported components.

getsentry/sentry-laravel:
branch: master
checked_through: null
Expand Down
8 changes: 5 additions & 3 deletions src/docs/filesystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ The `s3` and `gcs` drivers pool their SDK clients by default. The bucket-specifi

Pool identity is derived from the exact normalized configuration passed to the SDK client constructor. Equivalent client configurations converge automatically, including repeated `Storage::build()` calls. These configurations must use the same pool options; a mismatch throws immediately instead of silently reusing the first configuration's settings. Different credentials, regions, endpoints, or client options produce different pools.

The `ftp` and `sftp` drivers keep an open connection inside each disk, so Hypervel pools these disks whole. Each operation borrows a disk with its own connection, so concurrent requests never share one.

You may configure a pool using the disk's `pool` option:

```php
Expand All @@ -249,7 +251,7 @@ You may configure a pool using the disk's `pool` option:
],
```

`min_retained_objects` is an idle-trimming floor; it does not eagerly create clients. `max_lifetime` expires clients by absolute age, while `max_idle_time` trims individual idle clients. `pool_idle_timeout` removes an entirely unused pool after 300 seconds by default. Set any of these three optional durations to `null` to disable it. If all clients are in use and no capacity becomes available before `wait_timeout`, a `RuntimeException` is thrown.
`min_retained_objects` is an idle-trimming floor; it does not eagerly create clients. `max_lifetime` expires clients by absolute age, while `max_idle_time` trims individual idle clients. `pool_idle_timeout` removes an entirely unused pool after 300 seconds by default. Set any of these three optional durations to `null` to disable it. If all clients are in use and no capacity becomes available before `wait_timeout`, a `RuntimeException` is thrown. Each worker has its own pools, so an FTP or SFTP disk may open up to `max_objects` connections in every worker; keep that total within your server's connection limit.

An explicit pool name may be useful when multiple configurations intentionally identify the same operational resource:

Expand Down Expand Up @@ -285,7 +287,7 @@ $result = Storage::disk('s3')->withClient(function ($client) {
});
```

`Storage::forgetDisk()` only removes the manager's cached disk wrapper; an equivalent wrapper can continue using the shared pool. `Storage::purge()` removes the wrapper and closes its current pool, deriving the same pool identity even when the named disk has not been resolved yet or is composed from nested scoped disks. Other disks converging on that pool transparently create a fresh one on their next operation. Streams returned by `readStream()` or `readStreamRange()` retain their client lease until the stream is closed or destroyed.
`Storage::forgetDisk()` only removes the manager's cached disk wrapper; an equivalent wrapper can continue using the shared pool. `Storage::purge()` removes the wrapper and closes its current pool, deriving the same pool identity even when the named disk has not been resolved yet or is composed from nested scoped disks. Other disks converging on that pool transparently create a fresh one on their next operation. A stream returned by `readStream()` or `readStreamRange()` that still reads from its connection keeps that connection out of the pool until the stream is closed or destroyed. Fully buffered reads, including FTP and SFTP downloads, return the connection to the pool before you consume the stream.

S3 and Google Cloud Storage streams are read lazily by default, which keeps memory usage bounded and makes data available before the entire file has downloaded. This applies to `readStream()` and `readStreamRange()`; methods such as `get()` retain their normal behavior. Streaming requests close their HTTP connection after the read, so applications that open many small streams may prefer connection reuse and set the disk's `stream_reads` option to `false`.

Expand Down Expand Up @@ -783,7 +785,7 @@ Storage::disk('local')->moveToDisk(
);
```

Transfers from pooled disks, including S3 and Google Cloud Storage, buffer the source before writing to the destination so the source's pool slot is available during the write. Buffering keeps up to 2 MB in memory per transfer, then uses PHP's system temporary directory; allow enough temporary disk space for large files and concurrent transfers. Local sources stream directly.
Transfers from pooled disks, including S3 and Google Cloud Storage, buffer live source streams before writing to the destination so the source's pool slot is available during the write. Already buffered sources, including FTP and SFTP downloads, are reused without another copy. Buffering keeps up to 2 MB in memory per transfer, then uses PHP's system temporary directory; allow enough temporary disk space for large files and concurrent transfers. Local sources stream directly.

<a name="automatic-streaming"></a>
### Automatic Streaming
Expand Down
64 changes: 64 additions & 0 deletions src/docs/frontend.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,70 @@ Your local environment is always allowed, so a gate can never lock you out of De

The gate only controls who may view entries. Requests are recorded no matter who makes them, so only enable the recorder outside your local environment when untrusted visitors can't reach the application.

#### Previous URL

Hypervel's session middleware doesn't store the previous URL and route for Inertia visits, since they are sent as AJAX requests, so `session()->previousUrl()`, `session()->previousUri()`, and `session()->previousRoute()` return the last full page load. The `back()` helper is unaffected, as it resolves the previous location from the request's `Referer` header. You may enable the `store_previous_url` option in your application's `config/inertia.php` configuration file to store the previous location for Inertia visits as well:

```php
'store_previous_url' => true,
```

Prefetch requests and [partial reloads](https://inertiajs.com/docs/partial-reloads) are excluded, since deferred props, polling, and infinite scroll requests aren't navigations the user came from. You may customize which visits are stored by overriding the `shouldStoreCurrentUrl` method in your `HandleInertiaRequests` middleware:

```php
use Hypervel\Http\Request;
use Symfony\Component\HttpFoundation\Response;

/**
* Determine if the visit should be stored as the previous location.
*/
public function shouldStoreCurrentUrl(Request $request, Response $response): bool
{
return parent::shouldStoreCurrentUrl($request, $response)
&& ! $request->routeIs('admin.*');
}
```

#### Big Integers

JavaScript rounds integers outside its safe range while parsing JSON, so an ID such as `900719925474099988` from a 64-bit database column reaches your components as `900719925474100000`. Inertia can keep these values exact by delivering them as native `BigInt` values. This requires the Inertia client-side adapter at `^3.8`, with nothing to configure on the client.

Big integer support is disabled by default. You may enable it for every response using the `preserve_big_integers` option in your application's `config/inertia.php` configuration file, or the `INERTIA_PRESERVE_BIG_INTEGERS` environment variable:

```ini
INERTIA_PRESERVE_BIG_INTEGERS=true
```

You may also enable it for a single response using the `preserveBigIntegers` method:

```php
return Inertia::render('orders/show', [
'order' => $order,
])->preserveBigIntegers();
```

Passing `false` opts a single response out when the option is enabled:

```php
return Inertia::render('reports/index', $props)->preserveBigIntegers(false);
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
```

Only integers outside the safe range become a `BigInt`, so the same prop may arrive as a number or a `BigInt`, depending on its value. Flash data receives the same treatment as props. Arrays, models, collections, API resources, `JsonSerializable` values, and the public properties of your own classes are inspected for large integers, while built-in PHP classes such as `DateTime` are left untouched.

When enabled, Inertia reserves objects with a string `$bigint` property as integer markers. Avoid that shape in your own props and flash data, since the client converts the entire object to a `BigInt`.

A `BigInt` submitted through the router, a form, or Precognition is sent as its digits, so your controller receives a numeric string that the `integer` validation rule and the request's `integer` method handle as usual. The `useHttp` hook does not convert `BigInt` values, so convert them to strings before sending them.

Inertia's testing helpers turn big integers back into integers, so you may assert against the same values you passed to the response:

```php
use Hypervel\Inertia\Testing\AssertableInertia;

$response->assertInertia(fn (AssertableInertia $page) => $page
->where('order.id', 900719925474099988)
);
```

<a name="inertia-starter-kits"></a>
### Starter Kits

Expand Down
Loading
Loading