Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
87ad01f
Restore Sanctum's stateful request tests
binaryfire Oct 2, 2026
4416561
Cover Sanctum session checks for users without passwords
binaryfire Oct 2, 2026
f4ad812
Use upstream's names for Sanctum's last_used_at tests
binaryfire Oct 2, 2026
9228d8c
Restore Sanctum's guard and exception constructor docs
binaryfire Oct 2, 2026
f11b388
Keep the application URL's port in Sanctum's stateful domains
binaryfire Oct 2, 2026
f3415f1
Use upstream's strict ability comparison test
binaryfire Oct 2, 2026
f76f822
Read the request user in Sanctum's ability middleware
binaryfire Oct 2, 2026
89576c2
Port Socialite's remaining Google ID-token tests
binaryfire Oct 2, 2026
b59f013
Reject non-string OAuth state values in Socialite
binaryfire Oct 2, 2026
dd3bec8
Port Socialite's fake user tests
binaryfire Oct 2, 2026
6a47739
Port Socialite's LinkedIn missing image key test
binaryfire Oct 2, 2026
9e12a68
Validate the nonce in Facebook Limited Login tokens
binaryfire Oct 2, 2026
644e5dd
Drop unused catch variables in Socialite providers
binaryfire Oct 2, 2026
b405233
Register the Socialite facade alias
binaryfire Oct 2, 2026
8035b6c
Document Socialite's differences from Laravel
binaryfire Oct 2, 2026
ddaf62b
Trim Horizon's package .gitignore
binaryfire Oct 2, 2026
d426d58
Skip non-array master supervisor records in Horizon
binaryfire Oct 2, 2026
e159198
Explain Horizon's batch search watcher
binaryfire Oct 2, 2026
a34297e
Port Horizon's released job delay tests
binaryfire Oct 2, 2026
671c15d
Disable npm install scripts for Horizon's assets
binaryfire Oct 2, 2026
b02eeef
Note Horizon's inapplicable Redis Cluster tests
binaryfire Oct 2, 2026
7f55762
Port Horizon's maximum runtime and throughput test
binaryfire Oct 2, 2026
1c22da5
Port Horizon's delayed job payload test
binaryfire Oct 2, 2026
fa2e0bc
Escape Horizon's CSP nonce attribute
binaryfire Oct 2, 2026
b2871d0
Add JSON worker output and logarithmic auto-scaling to Horizon
binaryfire Oct 2, 2026
ceabc54
Show interval delays in Horizon and update its frontend packages
binaryfire Oct 2, 2026
299e376
Document Horizon's differences from Laravel
binaryfire Oct 2, 2026
5effd32
Record the Sanctum and Socialite sync checkpoints
binaryfire Oct 2, 2026
fb87c71
Merge commit '029438149' into upstream-sync-framework-13
binaryfire Oct 2, 2026
149b1fb
Port Laravel Sentinel
binaryfire Oct 2, 2026
c73c44b
Protect Horizon's local dashboard with Sentinel
binaryfire Oct 2, 2026
f09d44e
Protect Telescope's local dashboard with Sentinel
binaryfire Oct 2, 2026
3596e9d
Record the Sentinel and Horizon sync checkpoints
binaryfire Oct 2, 2026
aec987b
Keep non-JSON event data in Reverb messages
binaryfire Oct 2, 2026
6b899a1
Port Reverb's metrics listener cleanup test
binaryfire Oct 2, 2026
a6d24d0
Restore Reverb's rate limiting environment variable names
binaryfire Oct 2, 2026
7260133
Preserve a custom Reverb pub/sub message handler binding
binaryfire Oct 2, 2026
b4c874b
Prefer identified connections when flattening Reverb channels
binaryfire Oct 2, 2026
6baa183
Port Reverb's socket ID publishing tests
binaryfire Oct 2, 2026
478bce5
Document Reverb's differences from Laravel
binaryfire Oct 2, 2026
cea845e
Exclude node_modules from formatting
binaryfire Oct 2, 2026
e553fd2
Balance Horizon's size and log strategies before runtimes are recorded
binaryfire Oct 2, 2026
8229cfd
Keep Horizon's runtimes across metrics snapshots
binaryfire Oct 2, 2026
2ae0511
Control the environment in default config tests
binaryfire Oct 2, 2026
fe8770d
Show Horizon's interval delays from the stored delay
binaryfire Oct 2, 2026
ac5eba3
Reject an empty expected nonce for Facebook Limited Login
binaryfire Oct 2, 2026
6c50e91
Check that Sanctum's ability middleware returns the next response
binaryfire Oct 2, 2026
7700e48
Describe Sentinel's local address handling accurately
binaryfire Oct 2, 2026
ae6fe7e
Drop the redundant dogfood vendor exclusion from formatting
binaryfire Oct 2, 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: 1 addition & 1 deletion .php-cs-fixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@
PhpCsFixer\Finder::create()
->exclude('_archive')
->exclude('_tmp')
->exclude('dogfood/testbench-package/vendor')
->exclude('node_modules')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Medium .php-cs-fixer.php:113

composer lint checks the installed dogfood/testbench-package/vendor files, and lint:fix can rewrite third-party code there. exclude('vendor') only excludes the root-relative directory, so keep the nested vendor exclusion alongside node_modules.

-            ->exclude('node_modules')
+            ->exclude('node_modules')
+            ->exclude('dogfood/testbench-package/vendor')
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file @.php-cs-fixer.php around line 113:

`composer lint` checks the installed `dogfood/testbench-package/vendor` files, and `lint:fix` can rewrite third-party code there. `exclude('vendor')` only excludes the root-relative directory, so keep the nested vendor exclusion alongside `node_modules`.

Evidence trail:
.php-cs-fixer.php:109-123 at ae6fe7e — Finder uses `in(__DIR__)`, excludes `vendor`, but not `dogfood/testbench-package/vendor`; composer.json:447-448,456-457 at ae6fe7e — lint commands and dogfood dependency installation; dogfood/testbench-package/composer.json:26-39 — installed package dependencies; PHP-CS-Fixer documentation: https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/master/doc/config.rst — `exclude()` paths are relative to the paths passed to `in()`. `git diff MERGE_BASE REVIEWED_COMMIT -- .php-cs-fixer.php` shows the nested exclusion was removed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finder already skips that directory. When it searches recursively, exclude() with a name that has no slash rejects every directory with that name at any depth, not just the one at the root (see Symfony's ExcludeDirectoryFilterIterator). With this config, php-cs-fixer list-files lists none of the files under dogfood/testbench-package/vendor, so the extra entry was redundant.

->exclude('overrides')
->exclude('src/testbench/workbench/bootstrap/cache')
->exclude('src/testbench/workbench/runtime')
Expand Down
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
"hypervel/saloon": "self.version",
"hypervel/sanctum": "self.version",
"hypervel/scout": "self.version",
"hypervel/sentinel": "self.version",
"hypervel/sentry": "self.version",
"hypervel/server": "self.version",
"hypervel/server-process": "self.version",
Expand Down Expand Up @@ -282,6 +283,7 @@
"Hypervel\\Saloon\\": "src/saloon/src/",
"Hypervel\\Sanctum\\": "src/sanctum/src/",
"Hypervel\\Scout\\": "src/scout/src/",
"Hypervel\\Sentinel\\": "src/sentinel/src/",
"Hypervel\\Sentry\\": "src/sentry/src/",
"Hypervel\\ServerProcess\\": "src/server-process/src/",
"Hypervel\\Server\\": "src/server/src/",
Expand Down Expand Up @@ -357,7 +359,8 @@
"aliases": {
"OpenTelemetry": "Hypervel\\OpenTelemetry\\Facades\\OpenTelemetry",
"Saloon": "Hypervel\\Saloon\\Facades\\Saloon",
"Sentry": "Hypervel\\Sentry\\Facade"
"Sentry": "Hypervel\\Sentry\\Facade",
"Socialite": "Hypervel\\Socialite\\Socialite"
},
"providers": [
"Hypervel\\Auth\\AuthServiceProvider",
Expand Down
4 changes: 0 additions & 4 deletions docs/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,3 @@
## Notifications

- Design a provider-agnostic first-party SMS notification API before adding an SMS provider. Keep Horizon's existing `Horizon::routeSmsNotificationsTo(...)`, but have Horizon target the generic channel and message contract rather than a vendor class; provider packages should adapt that contract to Vonage or other services. Decide routing, provider selection, message construction, per-message client overrides, and failure reporting, then implement the first adapter and update the notification and Horizon documentation, stubs, and Boost references. Keep mutable third-party SDK clients isolated per send—Vonage's client caches resources that mutate request and response state around yielding HTTP calls—while reusing only immutable configuration and the coroutine-safe transport. Add standalone package, provider, direct-construction, routing, failure, Horizon mail/Slack/SMS, and deterministic concurrent-send coverage. Do not add obsolete Nexmo names or compatibility aliases.

## Sentinel

- Port `laravel/sentinel` as `hypervel/sentinel`, add direct Horizon and Telescope dependencies, and prepend `SentinelMiddleware:horizon` and `SentinelMiddleware:telescope` while preserving configured middleware. Remove Horizon's temporary `REMOVED:` source comment and cover both dashboards' security integration.
27 changes: 18 additions & 9 deletions docs/upstream-sync/sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,21 +67,30 @@ laravel/passkeys-server:

laravel/sanctum:
branch: 4.x
checked_through: null
last_reviewed_pr: null
sync_date: null
checked_through: 1aa53e0b955415571837971ee6ca0a9427c58a4f
last_reviewed_pr: 620
sync_date: '2026-10-02'

laravel/socialite:
branch: 5.x
checked_through: null
last_reviewed_pr: null
sync_date: null
checked_through: fa0181ee6204ca28a55cd67145fadd631ac209cf
last_reviewed_pr: 793
sync_date: '2026-10-02'
notes: Google, Facebook and generic OpenID Connect ID-token verification share Two\Concerns\InteractsWithJwks, so upstream key-loading changes (phpseclib, getPublicKeyOfOIDCToken) map there, and upstream tests that stub key loading use the RSA fixtures in tests/Socialite/Fixtures/CreatesJwksFixtures.php.

laravel/sentinel:
branch: 1.x
checked_through: b8e15909d59bbcff3d63e74a7858c9350027b485
last_reviewed_pr: 17
sync_date: '2026-10-02'
notes: SentinelServiceProvider is not ported because its only job is a scoped SentinelManager binding. Hypervel auto-singletons the unbound manager, so drivers registered with extend() during boot reach every coroutine; a coroutine-scoped manager would lose them.

laravel/horizon:
branch: 5.x
checked_through: null
last_reviewed_pr: null
sync_date: null
checked_through: 5d9f80448a192d03ddb338cf91f73fbe5a50e250
last_reviewed_pr: 1823
sync_date: '2026-10-02'
notes: horizon:listen maps to Hypervel\Watcher and Console\HorizonRestartStrategy; assess behavior changes in upstream's bin/file-watcher.cjs against them instead of copying the Node script. Metric clearing uses the Redis flushByPattern/SafeScan operations instead of an inline SCAN loop. Rebuild dist with npm 11.10 or newer after resource or frontend dependency changes.

laravel/reverb:
branch: main
Expand Down
11 changes: 8 additions & 3 deletions src/docs/horizon.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,8 +174,6 @@ If the `defaults` option is omitted, Horizon applies no shared supervisor option

The Horizon dashboard may be accessed via the `/horizon` route. By default, you will only be able to access this dashboard in the `local` environment. However, within your `app/Providers/HorizonServiceProvider.php` file, there is an [authorization gate](/docs/{{version}}/authorization#gates) definition. This authorization gate controls access to Horizon in **non-local** environments. You are free to modify this gate as needed to restrict access to your Horizon installation:

The required `path` option controls the routes registered by the application. The required `proxy_path` option only prefixes URLs generated by the dashboard when a reverse proxy strips an external subdirectory before forwarding requests. Set `proxy_path` to an empty string when no external prefix is needed.

```php
/**
* Register the Horizon gate.
Expand All @@ -192,6 +190,10 @@ protected function gate(): void
}
```

Since the dashboard doesn't require a login in the `local` environment, Horizon rejects local dashboard requests that a [trusted proxy](/docs/{{version}}/requests#configuring-trusted-proxies) forwards on behalf of a public IP address, such as visitors arriving through an ngrok or Expose tunnel. Until you configure trusted proxies, requests to ngrok and Expose hostnames fail with an error, since Horizon can't see the visitor's address. To share the dashboard through a tunnel, run the application in a non-local environment so the gate protects it.

The required `path` option controls the routes registered by the application. The required `proxy_path` option only prefixes URLs generated by the dashboard when a reverse proxy strips an external subdirectory before forwarding requests. Set `proxy_path` to an empty string when no external prefix is needed.

<a name="alternative-authentication-strategies"></a>
#### Alternative Authentication Strategies

Expand Down Expand Up @@ -289,6 +291,7 @@ In addition to `tries`, `timeout`, and `backoff`, each supervisor accepts severa
'sleep' => 3,
'rest' => 0,
'nice' => 0,
'json' => false,
],
],
],
Expand All @@ -302,6 +305,7 @@ In addition to `tries`, `timeout`, and `backoff`, each supervisor accepts severa
- `sleep` defines the number of seconds a worker should wait when no job is available before polling the queue for new jobs again. By default, this value is `3`.
- `rest` defines the number of seconds to pause between processing each job. By default, this value is `0`.
- `nice` defines the "niceness" (scheduling priority) of the worker processes. A higher value gives the process a lower priority. By default, this value is `0`.
- `json` determines if worker processes output their job updates and stop information as JSON, like the `queue:work` command's [`--json` option](/docs/{{version}}/queues#the-queue-work-command). By default, this value is `false`.

</div>

Expand Down Expand Up @@ -398,12 +402,13 @@ For example, you may configure Horizon to maintain at least one process per queu
],
```

The `autoScalingStrategy` configuration option determines how Horizon will assign more worker processes to queues. You can choose between two strategies:
The `autoScalingStrategy` configuration option determines how Horizon will assign more worker processes to queues. You can choose between three strategies:

<div class="content-list" markdown="1">

- The `time` strategy will assign workers based on the total estimated amount of time it will take to clear the queue.
- The `size` strategy will assign workers based on the total number of jobs on the queue.
- The `log` strategy will assign workers based on the logarithm of the number of jobs on the queue. This prevents a significantly larger queue from receiving a disproportionately large share of workers.

</div>

Expand Down
8 changes: 8 additions & 0 deletions src/docs/porting-from-laravel.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
- [CSRF Protection](#csrf-protection)
- [Fortify](#fortify)
- [Scout](#scout)
- [Socialite](#socialite)
- [JSON Schema](#json-schema)
- [Validation](#validation)
- [Request and Input Data](#request-and-input-data)
Expand Down Expand Up @@ -540,6 +541,13 @@ Fortify ignores Laravel's `fortify.passwords` setting. Declare the password rese

Hypervel compiles integer and float values passed to Scout's Algolia `where`, `whereIn`, and `whereNotIn` methods as numeric comparisons. Numeric-looking strings remain facet values. When porting an Algolia index, ensure the indexed attribute type matches the PHP value type used by these filters.

<a name="socialite"></a>
### Socialite

Custom Socialite providers should read request-specific state through getters such as `getRequest()`, `getParameters()`, `getScopes()`, and `getClientId()`. Properties such as `$parameters`, `$scopes`, and `$clientId` only hold the defaults shared by every request, so reading them directly ignores `with()`, `scopes()`, and `setConfig()` calls. Build custom OAuth 2.0 drivers with `buildOAuth2Provider()` instead of `buildProvider()`. See [custom providers](/docs/{{version}}/socialite#custom-providers).

Google users' raw data does not include Laravel's deprecated `id`, `verified_email`, and `link` keys. Read `sub`, `email_verified`, and `profile` instead.

<a name="json-schema"></a>
### JSON Schema

Expand Down
4 changes: 2 additions & 2 deletions src/docs/reverb.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,10 +146,10 @@ return [
'max_message_size' => (int) env('REVERB_APP_MAX_MESSAGE_SIZE', 10_000),
'accept_client_events_from' => env('REVERB_APP_ACCEPT_CLIENT_EVENTS_FROM', 'members'),
'rate_limiting' => [
'enabled' => (bool) env('REVERB_APP_RATE_LIMIT_ENABLED', false),
'enabled' => (bool) env('REVERB_APP_RATE_LIMITING_ENABLED', false),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Preserve the previous rate-limit environment names or document the breaking migration; existing deployments using either old name silently disable rate limiting or limit termination.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At src/docs/reverb.md, line 149:

<comment>Preserve the previous rate-limit environment names or document the breaking migration; existing deployments using either old name silently disable rate limiting or limit termination.</comment>

<file context>
@@ -146,10 +146,10 @@ return [
                 'accept_client_events_from' => env('REVERB_APP_ACCEPT_CLIENT_EVENTS_FROM', 'members'),
                 'rate_limiting' => [
-                    'enabled' => (bool) env('REVERB_APP_RATE_LIMIT_ENABLED', false),
+                    'enabled' => (bool) env('REVERB_APP_RATE_LIMITING_ENABLED', false),
                     'max_attempts' => (int) env('REVERB_APP_RATE_LIMIT_MAX_ATTEMPTS', 60),
                     'decay_seconds' => (int) env('REVERB_APP_RATE_LIMIT_DECAY_SECONDS', 60),
</file context>

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the names laravel/reverb introduced in PR 371, and the docs now match them, so Reverb settings from a Laravel app work as written. The older names were a Hypervel rename that never shipped in a release, so there's no migration to document.

'max_attempts' => (int) env('REVERB_APP_RATE_LIMIT_MAX_ATTEMPTS', 60),
'decay_seconds' => (int) env('REVERB_APP_RATE_LIMIT_DECAY_SECONDS', 60),
'terminate_on_limit' => (bool) env('REVERB_APP_RATE_LIMIT_TERMINATE_ON_LIMIT', false),
'terminate_on_limit' => (bool) env('REVERB_APP_RATE_LIMIT_TERMINATE', false),
],
],
],
Expand Down
6 changes: 5 additions & 1 deletion src/docs/socialite.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,11 @@ use Hypervel\Socialite\Socialite;
$user = Socialite::driver('github')->userFromToken($token);
```

If you are using Facebook Limited Login via an iOS application, Facebook will return an OIDC token instead of an access token. Like an access token, the OIDC token can be provided to the `userFromToken` method in order to retrieve user details.
If you are using Facebook Limited Login via an iOS application, Facebook will return an OIDC token instead of an access token. To retrieve user details from the OIDC token, provide the nonce used to initiate the login to the `userFromToken` method:

```php
$user = Socialite::driver('facebook')->userFromToken($token, $nonce);
```

Google ID tokens may also be provided to the `google` driver's `userFromToken` method. Hypervel will verify the JWT token before returning the user details:

Expand Down
2 changes: 2 additions & 0 deletions src/docs/telescope.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,8 @@ protected function gate(): void
}
```

Since the dashboard doesn't require a login in the `local` environment, Telescope rejects local dashboard requests that a [trusted proxy](/docs/{{version}}/requests#configuring-trusted-proxies) forwards on behalf of a public IP address, such as visitors arriving through an ngrok or Expose tunnel. Until you configure trusted proxies, requests to ngrok and Expose hostnames fail with an error, since Telescope can't see the visitor's address. To share the dashboard through a tunnel, run the application in a non-local environment so the gate protects it.

> [!WARNING]
> You should ensure you change your `APP_ENV` environment variable to `production` in your production environment. Otherwise, your Telescope installation will be publicly available.

Expand Down
6 changes: 0 additions & 6 deletions src/horizon/.gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1 @@
/vendor
/laravel
/node_modules
/phpunit.xml
composer.lock
.phpunit.result.cache
.phpunit.cache/
1 change: 1 addition & 0 deletions src/horizon/.npmrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
# dramatically reduces the chance of pulling a malicious release.
# npm measures this value in days.
min-release-age=7
ignore-scripts=true
3 changes: 3 additions & 0 deletions src/horizon/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,8 @@ Documentation: https://hypervel.org/docs/horizon
## Differences From Laravel

- The deprecated `horizon:publish` command is not included. Use `horizon:install` instead.
- `horizon:listen` uses Hypervel's file watcher instead of a Node.js `chokidar` process, so Node is not required. A nonempty `horizon.watch` list replaces the `watcher` configuration's watch list, and `--poll` selects its scanning driver. See [automatically restarting Horizon](https://hypervel.org/docs/horizon#automatically-restarting-horizon).
- Supervisors accept a `concurrency` option that lets each worker process run several jobs at once in coroutines. See [concurrency](https://hypervel.org/docs/horizon#concurrency).
- Redis Cluster is configured on the named Redis connection selected by `horizon.use`. Laravel's top-level `database.redis.clusters` entries are not read.

Ported from: https://github.com/laravel/horizon
1 change: 1 addition & 0 deletions src/horizon/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"hypervel/queue": "^0.4",
"hypervel/redis": "^0.4",
"hypervel/routing": "^0.4",
"hypervel/sentinel": "^0.4",
"hypervel/support": "^0.4",
"hypervel/watcher": "^0.4",
"symfony/console": "^8.1.2",
Expand Down
Loading
Loading